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
, NativeFunction func
)
60 : Base(&exec
->globalData(), structure
, name
)
62 , m_executable(adoptRef(new NativeExecutable(exec
)))
66 setNativeFunction(func
);
67 putDirect(exec
->propertyNames().length
, jsNumber(exec
, length
), DontDelete
| ReadOnly
| DontEnum
);
75 JSFunction::JSFunction(ExecState
* exec
, NonNullPassRefPtr
<FunctionExecutable
> executable
, ScopeChainNode
* scopeChainNode
)
76 : Base(&exec
->globalData(), exec
->lexicalGlobalObject()->functionStructure(), executable
->name())
77 , m_executable(executable
)
79 setScopeChain(scopeChainNode
);
82 JSFunction::~JSFunction()
84 ASSERT(vptr() == JSGlobalData::jsFunctionVPtr
);
86 // JIT code for other functions may have had calls linked directly to the code for this function; these links
87 // are based on a check for the this pointer value for this JSFunction - which will no longer be valid once
88 // this memory is freed and may be reused (potentially for another, different JSFunction).
89 if (!isHostFunction()) {
90 #if ENABLE(JIT_OPTIMIZE_CALL)
92 if (jsExecutable()->isGenerated())
93 jsExecutable()->generatedBytecode().unlinkCallers();
95 scopeChain().~ScopeChain(); // FIXME: Don't we need to do this in the interpreter too?
99 void JSFunction::markChildren(MarkStack
& markStack
)
101 Base::markChildren(markStack
);
102 if (!isHostFunction()) {
103 jsExecutable()->markAggregate(markStack
);
104 scopeChain().markAggregate(markStack
);
108 CallType
JSFunction::getCallData(CallData
& callData
)
110 if (isHostFunction()) {
111 callData
.native
.function
= nativeFunction();
114 callData
.js
.functionExecutable
= jsExecutable();
115 callData
.js
.scopeChain
= scopeChain().node();
119 JSValue
JSFunction::call(ExecState
* exec
, JSValue thisValue
, const ArgList
& args
)
121 ASSERT(!isHostFunction());
122 return exec
->interpreter()->execute(jsExecutable(), exec
, this, thisValue
.toThisObject(exec
), args
, scopeChain().node(), exec
->exceptionSlot());
125 JSValue
JSFunction::argumentsGetter(ExecState
* exec
, const Identifier
&, const PropertySlot
& slot
)
127 JSFunction
* thisObj
= asFunction(slot
.slotBase());
128 ASSERT(!thisObj
->isHostFunction());
129 return exec
->interpreter()->retrieveArguments(exec
, thisObj
);
132 JSValue
JSFunction::callerGetter(ExecState
* exec
, const Identifier
&, const PropertySlot
& slot
)
134 JSFunction
* thisObj
= asFunction(slot
.slotBase());
135 ASSERT(!thisObj
->isHostFunction());
136 return exec
->interpreter()->retrieveCaller(exec
, thisObj
);
139 JSValue
JSFunction::lengthGetter(ExecState
* exec
, const Identifier
&, const PropertySlot
& slot
)
141 JSFunction
* thisObj
= asFunction(slot
.slotBase());
142 ASSERT(!thisObj
->isHostFunction());
143 return jsNumber(exec
, thisObj
->jsExecutable()->parameterCount());
146 bool JSFunction::getOwnPropertySlot(ExecState
* exec
, const Identifier
& propertyName
, PropertySlot
& slot
)
148 if (isHostFunction())
149 return Base::getOwnPropertySlot(exec
, propertyName
, slot
);
151 if (propertyName
== exec
->propertyNames().prototype
) {
152 JSValue
* location
= getDirectLocation(propertyName
);
155 JSObject
* prototype
= new (exec
) JSObject(scopeChain().globalObject()->emptyObjectStructure());
156 prototype
->putDirect(exec
->propertyNames().constructor
, this, DontEnum
);
157 putDirect(exec
->propertyNames().prototype
, prototype
, DontDelete
);
158 location
= getDirectLocation(propertyName
);
161 slot
.setValueSlot(this, location
, offsetForLocation(location
));
164 if (propertyName
== exec
->propertyNames().arguments
) {
165 slot
.setCustom(this, argumentsGetter
);
169 if (propertyName
== exec
->propertyNames().length
) {
170 slot
.setCustom(this, lengthGetter
);
174 if (propertyName
== exec
->propertyNames().caller
) {
175 slot
.setCustom(this, callerGetter
);
179 return Base::getOwnPropertySlot(exec
, propertyName
, slot
);
182 bool JSFunction::getOwnPropertyDescriptor(ExecState
* exec
, const Identifier
& propertyName
, PropertyDescriptor
& descriptor
)
184 if (isHostFunction())
185 return Base::getOwnPropertyDescriptor(exec
, propertyName
, descriptor
);
187 if (propertyName
== exec
->propertyNames().prototype
) {
189 getOwnPropertySlot(exec
, propertyName
, slot
);
190 return Base::getOwnPropertyDescriptor(exec
, propertyName
, descriptor
);
193 if (propertyName
== exec
->propertyNames().arguments
) {
194 descriptor
.setDescriptor(exec
->interpreter()->retrieveArguments(exec
, this), ReadOnly
| DontEnum
| DontDelete
);
198 if (propertyName
== exec
->propertyNames().length
) {
199 descriptor
.setDescriptor(jsNumber(exec
, jsExecutable()->parameterCount()), ReadOnly
| DontEnum
| DontDelete
);
203 if (propertyName
== exec
->propertyNames().caller
) {
204 descriptor
.setDescriptor(exec
->interpreter()->retrieveCaller(exec
, this), ReadOnly
| DontEnum
| DontDelete
);
208 return Base::getOwnPropertyDescriptor(exec
, propertyName
, descriptor
);
211 void JSFunction::getOwnPropertyNames(ExecState
* exec
, PropertyNameArray
& propertyNames
, EnumerationMode mode
)
213 if (!isHostFunction() && (mode
== IncludeDontEnumProperties
)) {
214 propertyNames
.add(exec
->propertyNames().arguments
);
215 propertyNames
.add(exec
->propertyNames().callee
);
216 propertyNames
.add(exec
->propertyNames().caller
);
217 propertyNames
.add(exec
->propertyNames().length
);
219 Base::getOwnPropertyNames(exec
, propertyNames
, mode
);
222 void JSFunction::put(ExecState
* exec
, const Identifier
& propertyName
, JSValue value
, PutPropertySlot
& slot
)
224 if (isHostFunction()) {
225 Base::put(exec
, propertyName
, value
, slot
);
228 if (propertyName
== exec
->propertyNames().arguments
|| propertyName
== exec
->propertyNames().length
)
230 Base::put(exec
, propertyName
, value
, slot
);
233 bool JSFunction::deleteProperty(ExecState
* exec
, const Identifier
& propertyName
)
235 if (isHostFunction())
236 return Base::deleteProperty(exec
, propertyName
);
237 if (propertyName
== exec
->propertyNames().arguments
|| propertyName
== exec
->propertyNames().length
)
239 return Base::deleteProperty(exec
, propertyName
);
242 // ECMA 13.2.2 [[Construct]]
243 ConstructType
JSFunction::getConstructData(ConstructData
& constructData
)
245 if (isHostFunction())
246 return ConstructTypeNone
;
247 constructData
.js
.functionExecutable
= jsExecutable();
248 constructData
.js
.scopeChain
= scopeChain().node();
249 return ConstructTypeJS
;
252 JSObject
* JSFunction::construct(ExecState
* exec
, const ArgList
& args
)
254 ASSERT(!isHostFunction());
255 Structure
* structure
;
256 JSValue prototype
= get(exec
, exec
->propertyNames().prototype
);
257 if (prototype
.isObject())
258 structure
= asObject(prototype
)->inheritorID();
260 structure
= exec
->lexicalGlobalObject()->emptyObjectStructure();
261 JSObject
* thisObj
= new (exec
) JSObject(structure
);
263 JSValue result
= exec
->interpreter()->execute(jsExecutable(), exec
, this, thisObj
, args
, scopeChain().node(), exec
->exceptionSlot());
264 if (exec
->hadException() || !result
.isObject())
266 return asObject(result
);