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 "ExceptionHelpers.h"
32 #include "FunctionPrototype.h"
33 #include "JSGlobalObject.h"
34 #include "JSNotAnObject.h"
35 #include "Interpreter.h"
36 #include "ObjectPrototype.h"
38 #include "PropertyNameArray.h"
39 #include "ScopeChainMark.h"
42 using namespace Unicode;
45 EncodedJSValue JSC_HOST_CALL callHostFunctionAsConstructor(ExecState* exec)
47 return throwVMError(exec, createNotAConstructorError(exec, exec->callee()));
50 ASSERT_CLASS_FITS_IN_CELL(JSFunction);
52 const ClassInfo JSFunction::s_info = { "Function", &Base::s_info, 0, 0 };
54 bool JSFunction::isHostFunctionNonInline() const
56 return isHostFunction();
59 JSFunction::JSFunction(VPtrStealingHackType)
60 : Base(VPtrStealingHack)
64 JSFunction::JSFunction(ExecState* exec, JSGlobalObject* globalObject, Structure* structure)
65 : Base(exec->globalData(), structure)
67 , m_scopeChain(exec->globalData(), this, globalObject->globalScopeChain())
71 JSFunction::JSFunction(ExecState* exec, FunctionExecutable* executable, ScopeChainNode* scopeChainNode)
72 : Base(exec->globalData(), scopeChainNode->globalObject->functionStructure())
73 , m_executable(exec->globalData(), this, executable)
74 , m_scopeChain(exec->globalData(), this, scopeChainNode)
78 void JSFunction::finishCreation(ExecState* exec, int length, const Identifier& name, ExecutableBase* executable)
80 Base::finishCreation(exec->globalData());
81 ASSERT(inherits(&s_info));
82 m_executable.set(exec->globalData(), this, executable);
83 putDirect(exec->globalData(), exec->globalData().propertyNames->name, jsString(exec, name.isNull() ? "" : name.ustring()), DontDelete | ReadOnly | DontEnum);
84 putDirect(exec->globalData(), exec->propertyNames().length, jsNumber(length), DontDelete | ReadOnly | DontEnum);
87 void JSFunction::finishCreation(ExecState* exec, FunctionExecutable* executable, ScopeChainNode* scopeChainNode)
89 Base::finishCreation(exec->globalData());
90 ASSERT(inherits(&s_info));
91 setStructure(exec->globalData(), scopeChainNode->globalObject->namedFunctionStructure());
92 putDirectOffset(exec->globalData(), scopeChainNode->globalObject->functionNameOffset(), executable->nameValue());
95 JSFunction::~JSFunction()
97 ASSERT(vptr() == JSGlobalData::jsFunctionVPtr);
100 static const char* StrictModeCallerAccessError = "Cannot access caller property of a strict mode function";
101 static const char* StrictModeArgumentsAccessError = "Cannot access arguments property of a strict mode function";
103 static void createDescriptorForThrowingProperty(ExecState* exec, PropertyDescriptor& descriptor, const char* message)
105 JSValue thrower = createTypeErrorFunction(exec, message);
106 descriptor.setAccessorDescriptor(thrower, thrower, DontEnum | DontDelete | Getter | Setter);
109 const UString& JSFunction::name(ExecState* exec)
111 return asString(getDirect(exec->globalData(), exec->globalData().propertyNames->name))->tryGetValue();
114 const UString JSFunction::displayName(ExecState* exec)
116 JSValue displayName = getDirect(exec->globalData(), exec->globalData().propertyNames->displayName);
118 if (displayName && isJSString(&exec->globalData(), displayName))
119 return asString(displayName)->tryGetValue();
124 const UString JSFunction::calculatedDisplayName(ExecState* exec)
126 const UString explicitName = displayName(exec);
128 if (!explicitName.isEmpty())
134 void JSFunction::visitChildren(SlotVisitor& visitor)
136 ASSERT_GC_OBJECT_INHERITS(this, &s_info);
137 COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
138 ASSERT(structure()->typeInfo().overridesVisitChildren());
139 Base::visitChildren(visitor);
141 visitor.append(&m_scopeChain);
143 visitor.append(&m_executable);
146 CallType JSFunction::getCallData(CallData& callData)
148 if (isHostFunction()) {
149 callData.native.function = nativeFunction();
152 callData.js.functionExecutable = jsExecutable();
153 callData.js.scopeChain = scope();
157 JSValue JSFunction::argumentsGetter(ExecState* exec, JSValue slotBase, const Identifier&)
159 JSFunction* thisObj = asFunction(slotBase);
160 ASSERT(!thisObj->isHostFunction());
161 return exec->interpreter()->retrieveArguments(exec, thisObj);
164 JSValue JSFunction::callerGetter(ExecState* exec, JSValue slotBase, const Identifier&)
166 JSFunction* thisObj = asFunction(slotBase);
167 ASSERT(!thisObj->isHostFunction());
168 return exec->interpreter()->retrieveCaller(exec, thisObj);
171 JSValue JSFunction::lengthGetter(ExecState*, JSValue slotBase, const Identifier&)
173 JSFunction* thisObj = asFunction(slotBase);
174 ASSERT(!thisObj->isHostFunction());
175 return jsNumber(thisObj->jsExecutable()->parameterCount());
178 static inline WriteBarrierBase<Unknown>* createPrototypeProperty(JSGlobalData& globalData, JSGlobalObject* globalObject, JSFunction* function)
180 ASSERT(!function->isHostFunction());
182 ExecState* exec = globalObject->globalExec();
183 if (WriteBarrierBase<Unknown>* location = function->getDirectLocation(globalData, exec->propertyNames().prototype))
185 JSObject* prototype = constructEmptyObject(exec, globalObject->emptyObjectStructure());
186 prototype->putDirect(globalData, exec->propertyNames().constructor, function, DontEnum);
187 function->putDirect(globalData, exec->propertyNames().prototype, prototype, DontDelete | DontEnum);
188 return function->getDirectLocation(exec->globalData(), exec->propertyNames().prototype);
191 void JSFunction::preventExtensions(JSGlobalData& globalData)
193 if (!isHostFunction())
194 createPrototypeProperty(globalData, scope()->globalObject.get(), this);
195 JSObject::preventExtensions(globalData);
198 bool JSFunction::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
200 if (isHostFunction())
201 return Base::getOwnPropertySlot(exec, propertyName, slot);
203 if (propertyName == exec->propertyNames().prototype) {
204 WriteBarrierBase<Unknown>* location = getDirectLocation(exec->globalData(), propertyName);
207 location = createPrototypeProperty(exec->globalData(), scope()->globalObject.get(), this);
209 slot.setValue(this, location->get(), offsetForLocation(location));
212 if (propertyName == exec->propertyNames().arguments) {
213 if (jsExecutable()->isStrictMode()) {
214 throwTypeError(exec, "Can't access arguments object of a strict mode function");
215 slot.setValue(jsNull());
219 slot.setCacheableCustom(this, argumentsGetter);
223 if (propertyName == exec->propertyNames().length) {
224 slot.setCacheableCustom(this, lengthGetter);
228 if (propertyName == exec->propertyNames().caller) {
229 if (jsExecutable()->isStrictMode()) {
230 throwTypeError(exec, StrictModeCallerAccessError);
231 slot.setValue(jsNull());
234 slot.setCacheableCustom(this, callerGetter);
238 return Base::getOwnPropertySlot(exec, propertyName, slot);
241 bool JSFunction::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
243 if (isHostFunction())
244 return Base::getOwnPropertyDescriptor(exec, propertyName, descriptor);
246 if (propertyName == exec->propertyNames().prototype) {
248 getOwnPropertySlot(exec, propertyName, slot);
249 return Base::getOwnPropertyDescriptor(exec, propertyName, descriptor);
252 if (propertyName == exec->propertyNames().arguments) {
253 if (jsExecutable()->isStrictMode())
254 createDescriptorForThrowingProperty(exec, descriptor, StrictModeArgumentsAccessError);
256 descriptor.setDescriptor(exec->interpreter()->retrieveArguments(exec, this), ReadOnly | DontEnum | DontDelete);
260 if (propertyName == exec->propertyNames().length) {
261 descriptor.setDescriptor(jsNumber(jsExecutable()->parameterCount()), ReadOnly | DontEnum | DontDelete);
265 if (propertyName == exec->propertyNames().caller) {
266 if (jsExecutable()->isStrictMode())
267 createDescriptorForThrowingProperty(exec, descriptor, StrictModeCallerAccessError);
269 descriptor.setDescriptor(exec->interpreter()->retrieveCaller(exec, this), ReadOnly | DontEnum | DontDelete);
273 return Base::getOwnPropertyDescriptor(exec, propertyName, descriptor);
276 void JSFunction::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
278 if (!isHostFunction() && (mode == IncludeDontEnumProperties)) {
279 // Make sure prototype has been reified.
281 getOwnPropertySlot(exec, exec->propertyNames().prototype, slot);
283 propertyNames.add(exec->propertyNames().arguments);
284 propertyNames.add(exec->propertyNames().caller);
285 propertyNames.add(exec->propertyNames().length);
287 Base::getOwnPropertyNames(exec, propertyNames, mode);
290 void JSFunction::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
292 if (isHostFunction()) {
293 Base::put(exec, propertyName, value, slot);
296 if (propertyName == exec->propertyNames().prototype) {
297 // Make sure prototype has been reified, such that it can only be overwritten
298 // following the rules set out in ECMA-262 8.12.9.
300 getOwnPropertySlot(exec, propertyName, slot);
302 if (jsExecutable()->isStrictMode()) {
303 if (propertyName == exec->propertyNames().arguments) {
304 throwTypeError(exec, StrictModeArgumentsAccessError);
307 if (propertyName == exec->propertyNames().caller) {
308 throwTypeError(exec, StrictModeCallerAccessError);
312 if (propertyName == exec->propertyNames().arguments || propertyName == exec->propertyNames().length)
314 Base::put(exec, propertyName, value, slot);
317 bool JSFunction::deleteProperty(ExecState* exec, const Identifier& propertyName)
319 if (isHostFunction())
320 return Base::deleteProperty(exec, propertyName);
321 if (propertyName == exec->propertyNames().arguments || propertyName == exec->propertyNames().length)
323 return Base::deleteProperty(exec, propertyName);
326 // ECMA 13.2.2 [[Construct]]
327 ConstructType JSFunction::getConstructData(ConstructData& constructData)
329 if (isHostFunction())
330 return ConstructTypeNone;
331 constructData.js.functionExecutable = jsExecutable();
332 constructData.js.scopeChain = scope();
333 return ConstructTypeJS;