2 * Copyright (C) 1999-2002 Harri Porten (porten@kde.org)
3 * Copyright (C) 2001 Peter Kelly (pmk@post.com)
4 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
5 * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca)
6 * Copyright (C) 2007 Maks Orlovich
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
26 #include "JSFunction.h"
28 #include "CodeBlock.h"
29 #include "CommonIdentifiers.h"
30 #include "CallFrame.h"
31 #include "FunctionPrototype.h"
32 #include "JSGlobalObject.h"
33 #include "Interpreter.h"
34 #include "ObjectPrototype.h"
36 #include "PropertyNameArray.h"
37 #include "ScopeChainMark.h"
40 using namespace Unicode
;
44 ASSERT_CLASS_FITS_IN_CELL(JSFunction
);
46 const ClassInfo
JSFunction::info
= { "Function", &InternalFunction::info
, 0, 0 };
48 bool JSFunction::isHostFunctionNonInline() const
50 return isHostFunction();
53 JSFunction::JSFunction(NonNullPassRefPtr
<Structure
> structure
)
55 , m_executable(adoptRef(new VPtrHackExecutable()))
59 JSFunction::JSFunction(ExecState
* exec
, NonNullPassRefPtr
<Structure
> structure
, int length
, const Identifier
& name
, NativeExecutable
* thunk
, NativeFunction func
)
60 : Base(&exec
->globalData(), structure
, name
)
66 setNativeFunction(func
);
67 putDirect(exec
->propertyNames().length
, jsNumber(exec
, length
), DontDelete
| ReadOnly
| DontEnum
);
76 JSFunction::JSFunction(ExecState
* exec
, NonNullPassRefPtr
<Structure
> structure
, int length
, const Identifier
& name
, NativeFunction func
)
77 : Base(&exec
->globalData(), structure
, name
)
79 , m_executable(exec
->globalData().jitStubs
->ctiNativeCallThunk())
83 setNativeFunction(func
);
84 putDirect(exec
->propertyNames().length
, jsNumber(exec
, length
), DontDelete
| ReadOnly
| DontEnum
);
92 JSFunction::JSFunction(ExecState
* exec
, NonNullPassRefPtr
<FunctionExecutable
> executable
, ScopeChainNode
* scopeChainNode
)
93 : Base(&exec
->globalData(), exec
->lexicalGlobalObject()->functionStructure(), executable
->name())
94 , m_executable(executable
)
96 setScopeChain(scopeChainNode
);
99 JSFunction::~JSFunction()
101 ASSERT(vptr() == JSGlobalData::jsFunctionVPtr
);
103 // JIT code for other functions may have had calls linked directly to the code for this function; these links
104 // are based on a check for the this pointer value for this JSFunction - which will no longer be valid once
105 // this memory is freed and may be reused (potentially for another, different JSFunction).
106 if (!isHostFunction()) {
107 #if ENABLE(JIT_OPTIMIZE_CALL)
108 ASSERT(m_executable
);
109 if (jsExecutable()->isGenerated())
110 jsExecutable()->generatedBytecode().unlinkCallers();
112 scopeChain().~ScopeChain(); // FIXME: Don't we need to do this in the interpreter too?
116 void JSFunction::markChildren(MarkStack
& markStack
)
118 Base::markChildren(markStack
);
119 if (!isHostFunction()) {
120 jsExecutable()->markAggregate(markStack
);
121 scopeChain().markAggregate(markStack
);
125 CallType
JSFunction::getCallData(CallData
& callData
)
127 if (isHostFunction()) {
128 callData
.native
.function
= nativeFunction();
131 callData
.js
.functionExecutable
= jsExecutable();
132 callData
.js
.scopeChain
= scopeChain().node();
136 JSValue
JSFunction::call(ExecState
* exec
, JSValue thisValue
, const ArgList
& args
)
138 ASSERT(!isHostFunction());
139 return exec
->interpreter()->execute(jsExecutable(), exec
, this, thisValue
.toThisObject(exec
), args
, scopeChain().node(), exec
->exceptionSlot());
142 JSValue
JSFunction::argumentsGetter(ExecState
* exec
, JSValue slotBase
, const Identifier
&)
144 JSFunction
* thisObj
= asFunction(slotBase
);
145 ASSERT(!thisObj
->isHostFunction());
146 return exec
->interpreter()->retrieveArguments(exec
, thisObj
);
149 JSValue
JSFunction::callerGetter(ExecState
* exec
, JSValue slotBase
, const Identifier
&)
151 JSFunction
* thisObj
= asFunction(slotBase
);
152 ASSERT(!thisObj
->isHostFunction());
153 return exec
->interpreter()->retrieveCaller(exec
, thisObj
);
156 JSValue
JSFunction::lengthGetter(ExecState
* exec
, JSValue slotBase
, const Identifier
&)
158 JSFunction
* thisObj
= asFunction(slotBase
);
159 ASSERT(!thisObj
->isHostFunction());
160 return jsNumber(exec
, thisObj
->jsExecutable()->parameterCount());
163 bool JSFunction::getOwnPropertySlot(ExecState
* exec
, const Identifier
& propertyName
, PropertySlot
& slot
)
165 if (isHostFunction())
166 return Base::getOwnPropertySlot(exec
, propertyName
, slot
);
168 if (propertyName
== exec
->propertyNames().prototype
) {
169 JSValue
* location
= getDirectLocation(propertyName
);
172 JSObject
* prototype
= new (exec
) JSObject(scopeChain().globalObject()->emptyObjectStructure());
173 prototype
->putDirect(exec
->propertyNames().constructor
, this, DontEnum
);
174 putDirect(exec
->propertyNames().prototype
, prototype
, DontDelete
);
175 location
= getDirectLocation(propertyName
);
178 slot
.setValueSlot(this, location
, offsetForLocation(location
));
181 if (propertyName
== exec
->propertyNames().arguments
) {
182 slot
.setCacheableCustom(this, argumentsGetter
);
186 if (propertyName
== exec
->propertyNames().length
) {
187 slot
.setCacheableCustom(this, lengthGetter
);
191 if (propertyName
== exec
->propertyNames().caller
) {
192 slot
.setCacheableCustom(this, callerGetter
);
196 return Base::getOwnPropertySlot(exec
, propertyName
, slot
);
199 bool JSFunction::getOwnPropertyDescriptor(ExecState
* exec
, const Identifier
& propertyName
, PropertyDescriptor
& descriptor
)
201 if (isHostFunction())
202 return Base::getOwnPropertyDescriptor(exec
, propertyName
, descriptor
);
204 if (propertyName
== exec
->propertyNames().prototype
) {
206 getOwnPropertySlot(exec
, propertyName
, slot
);
207 return Base::getOwnPropertyDescriptor(exec
, propertyName
, descriptor
);
210 if (propertyName
== exec
->propertyNames().arguments
) {
211 descriptor
.setDescriptor(exec
->interpreter()->retrieveArguments(exec
, this), ReadOnly
| DontEnum
| DontDelete
);
215 if (propertyName
== exec
->propertyNames().length
) {
216 descriptor
.setDescriptor(jsNumber(exec
, jsExecutable()->parameterCount()), ReadOnly
| DontEnum
| DontDelete
);
220 if (propertyName
== exec
->propertyNames().caller
) {
221 descriptor
.setDescriptor(exec
->interpreter()->retrieveCaller(exec
, this), ReadOnly
| DontEnum
| DontDelete
);
225 return Base::getOwnPropertyDescriptor(exec
, propertyName
, descriptor
);
228 void JSFunction::getOwnPropertyNames(ExecState
* exec
, PropertyNameArray
& propertyNames
, EnumerationMode mode
)
230 if (!isHostFunction() && (mode
== IncludeDontEnumProperties
)) {
231 propertyNames
.add(exec
->propertyNames().arguments
);
232 propertyNames
.add(exec
->propertyNames().callee
);
233 propertyNames
.add(exec
->propertyNames().caller
);
234 propertyNames
.add(exec
->propertyNames().length
);
236 Base::getOwnPropertyNames(exec
, propertyNames
, mode
);
239 void JSFunction::put(ExecState
* exec
, const Identifier
& propertyName
, JSValue value
, PutPropertySlot
& slot
)
241 if (isHostFunction()) {
242 Base::put(exec
, propertyName
, value
, slot
);
245 if (propertyName
== exec
->propertyNames().arguments
|| propertyName
== exec
->propertyNames().length
)
247 Base::put(exec
, propertyName
, value
, slot
);
250 bool JSFunction::deleteProperty(ExecState
* exec
, const Identifier
& propertyName
)
252 if (isHostFunction())
253 return Base::deleteProperty(exec
, propertyName
);
254 if (propertyName
== exec
->propertyNames().arguments
|| propertyName
== exec
->propertyNames().length
)
256 return Base::deleteProperty(exec
, propertyName
);
259 // ECMA 13.2.2 [[Construct]]
260 ConstructType
JSFunction::getConstructData(ConstructData
& constructData
)
262 if (isHostFunction())
263 return ConstructTypeNone
;
264 constructData
.js
.functionExecutable
= jsExecutable();
265 constructData
.js
.scopeChain
= scopeChain().node();
266 return ConstructTypeJS
;
269 JSObject
* JSFunction::construct(ExecState
* exec
, const ArgList
& args
)
271 ASSERT(!isHostFunction());
272 Structure
* structure
;
273 JSValue prototype
= get(exec
, exec
->propertyNames().prototype
);
274 if (prototype
.isObject())
275 structure
= asObject(prototype
)->inheritorID();
277 structure
= exec
->lexicalGlobalObject()->emptyObjectStructure();
278 JSObject
* thisObj
= new (exec
) JSObject(structure
);
280 JSValue result
= exec
->interpreter()->execute(jsExecutable(), exec
, this, thisObj
, args
, scopeChain().node(), exec
->exceptionSlot());
281 if (exec
->hadException() || !result
.isObject())
283 return asObject(result
);