]> git.saurik.com Git - apple/javascriptcore.git/blame - runtime/JSFunction.cpp
JavaScriptCore-903.5.tar.gz
[apple/javascriptcore.git] / runtime / JSFunction.cpp
CommitLineData
9dae56ea
A
1/*
2 * Copyright (C) 1999-2002 Harri Porten (porten@kde.org)
3 * Copyright (C) 2001 Peter Kelly (pmk@post.com)
f9bf01c6 4 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
9dae56ea
A
5 * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca)
6 * Copyright (C) 2007 Maks Orlovich
7 *
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.
12 *
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.
17 *
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.
22 *
23 */
24
25#include "config.h"
26#include "JSFunction.h"
27
28#include "CodeBlock.h"
29#include "CommonIdentifiers.h"
30#include "CallFrame.h"
14957cd0 31#include "ExceptionHelpers.h"
9dae56ea
A
32#include "FunctionPrototype.h"
33#include "JSGlobalObject.h"
14957cd0 34#include "JSNotAnObject.h"
9dae56ea
A
35#include "Interpreter.h"
36#include "ObjectPrototype.h"
37#include "Parser.h"
38#include "PropertyNameArray.h"
39#include "ScopeChainMark.h"
40
41using namespace WTF;
42using namespace Unicode;
43
44namespace JSC {
14957cd0
A
45EncodedJSValue JSC_HOST_CALL callHostFunctionAsConstructor(ExecState* exec)
46{
47 return throwVMError(exec, createNotAConstructorError(exec, exec->callee()));
48}
9dae56ea
A
49
50ASSERT_CLASS_FITS_IN_CELL(JSFunction);
51
14957cd0 52const ClassInfo JSFunction::s_info = { "Function", &Base::s_info, 0, 0 };
9dae56ea 53
f9bf01c6
A
54bool JSFunction::isHostFunctionNonInline() const
55{
56 return isHostFunction();
57}
58
14957cd0
A
59JSFunction::JSFunction(VPtrStealingHackType)
60 : Base(VPtrStealingHack)
f9bf01c6
A
61{
62}
63
14957cd0
A
64JSFunction::JSFunction(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, int length, const Identifier& name, NativeExecutable* thunk)
65 : Base(globalObject, structure)
66 , m_executable(exec->globalData(), this, thunk)
67 , m_scopeChain(exec->globalData(), this, globalObject->globalScopeChain())
4e4e5a6f 68{
14957cd0
A
69 ASSERT(inherits(&s_info));
70 putDirect(exec->globalData(), exec->globalData().propertyNames->name, jsString(exec, name.isNull() ? "" : name.ustring()), DontDelete | ReadOnly | DontEnum);
71 putDirect(exec->globalData(), exec->propertyNames().length, jsNumber(length), DontDelete | ReadOnly | DontEnum);
4e4e5a6f
A
72}
73
14957cd0
A
74JSFunction::JSFunction(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, int length, const Identifier& name, NativeFunction func)
75 : Base(globalObject, structure)
76 , m_scopeChain(exec->globalData(), this, globalObject->globalScopeChain())
ba379fdc 77{
14957cd0
A
78 ASSERT(inherits(&s_info));
79
80 // Can't do this during initialization because getHostFunction might do a GC allocation.
81 m_executable.set(exec->globalData(), this, exec->globalData().getHostFunction(func));
82
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);
ba379fdc
A
85}
86
14957cd0
A
87JSFunction::JSFunction(ExecState* exec, FunctionExecutable* executable, ScopeChainNode* scopeChainNode)
88 : Base(scopeChainNode->globalObject.get(), scopeChainNode->globalObject->functionStructure())
89 , m_executable(exec->globalData(), this, executable)
90 , m_scopeChain(exec->globalData(), this, scopeChainNode)
9dae56ea 91{
14957cd0
A
92 ASSERT(inherits(&s_info));
93 const Identifier& name = static_cast<FunctionExecutable*>(m_executable.get())->name();
94 putDirect(exec->globalData(), exec->globalData().propertyNames->name, jsString(exec, name.isNull() ? "" : name.ustring()), DontDelete | ReadOnly | DontEnum);
9dae56ea
A
95}
96
97JSFunction::~JSFunction()
98{
f9bf01c6 99 ASSERT(vptr() == JSGlobalData::jsFunctionVPtr);
14957cd0 100}
f9bf01c6 101
14957cd0
A
102static const char* StrictModeCallerAccessError = "Cannot access caller property of a strict mode function";
103static const char* StrictModeArgumentsAccessError = "Cannot access arguments property of a strict mode function";
104
105static void createDescriptorForThrowingProperty(ExecState* exec, PropertyDescriptor& descriptor, const char* message)
106{
107 JSValue thrower = createTypeErrorFunction(exec, message);
108 descriptor.setAccessorDescriptor(thrower, thrower, DontEnum | DontDelete | Getter | Setter);
9dae56ea
A
109}
110
14957cd0 111const UString& JSFunction::name(ExecState* exec)
9dae56ea 112{
14957cd0
A
113 return asString(getDirect(exec->globalData(), exec->globalData().propertyNames->name))->tryGetValue();
114}
115
116const UString JSFunction::displayName(ExecState* exec)
117{
118 JSValue displayName = getDirect(exec->globalData(), exec->globalData().propertyNames->displayName);
119
120 if (displayName && isJSString(&exec->globalData(), displayName))
121 return asString(displayName)->tryGetValue();
122
123 return UString();
124}
125
126const UString JSFunction::calculatedDisplayName(ExecState* exec)
127{
128 const UString explicitName = displayName(exec);
129
130 if (!explicitName.isEmpty())
131 return explicitName;
132
133 return name(exec);
134}
135
136void JSFunction::visitChildren(SlotVisitor& visitor)
137{
138 ASSERT_GC_OBJECT_INHERITS(this, &s_info);
139 COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
140 ASSERT(structure()->typeInfo().overridesVisitChildren());
141 Base::visitChildren(visitor);
142
143 visitor.append(&m_scopeChain);
144 if (m_executable)
145 visitor.append(&m_executable);
9dae56ea
A
146}
147
148CallType JSFunction::getCallData(CallData& callData)
149{
ba379fdc
A
150 if (isHostFunction()) {
151 callData.native.function = nativeFunction();
152 return CallTypeHost;
153 }
f9bf01c6 154 callData.js.functionExecutable = jsExecutable();
14957cd0 155 callData.js.scopeChain = scope();
9dae56ea
A
156 return CallTypeJS;
157}
158
4e4e5a6f 159JSValue JSFunction::argumentsGetter(ExecState* exec, JSValue slotBase, const Identifier&)
9dae56ea 160{
4e4e5a6f 161 JSFunction* thisObj = asFunction(slotBase);
ba379fdc 162 ASSERT(!thisObj->isHostFunction());
9dae56ea
A
163 return exec->interpreter()->retrieveArguments(exec, thisObj);
164}
165
4e4e5a6f 166JSValue JSFunction::callerGetter(ExecState* exec, JSValue slotBase, const Identifier&)
9dae56ea 167{
4e4e5a6f 168 JSFunction* thisObj = asFunction(slotBase);
ba379fdc 169 ASSERT(!thisObj->isHostFunction());
9dae56ea
A
170 return exec->interpreter()->retrieveCaller(exec, thisObj);
171}
172
14957cd0 173JSValue JSFunction::lengthGetter(ExecState*, JSValue slotBase, const Identifier&)
9dae56ea 174{
4e4e5a6f 175 JSFunction* thisObj = asFunction(slotBase);
ba379fdc 176 ASSERT(!thisObj->isHostFunction());
14957cd0
A
177 return jsNumber(thisObj->jsExecutable()->parameterCount());
178}
179
180static inline WriteBarrierBase<Unknown>* createPrototypeProperty(JSGlobalData& globalData, JSGlobalObject* globalObject, JSFunction* function)
181{
182 ASSERT(!function->isHostFunction());
183
184 ExecState* exec = globalObject->globalExec();
185 if (WriteBarrierBase<Unknown>* location = function->getDirectLocation(globalData, exec->propertyNames().prototype))
186 return location;
187 JSObject* prototype = constructEmptyObject(exec, globalObject->emptyObjectStructure());
188 prototype->putDirect(globalData, exec->propertyNames().constructor, function, DontEnum);
189 function->putDirect(globalData, exec->propertyNames().prototype, prototype, DontDelete | DontEnum);
190 return function->getDirectLocation(exec->globalData(), exec->propertyNames().prototype);
191}
192
193void JSFunction::preventExtensions(JSGlobalData& globalData)
194{
195 if (!isHostFunction())
196 createPrototypeProperty(globalData, scope()->globalObject.get(), this);
197 JSObject::preventExtensions(globalData);
9dae56ea
A
198}
199
200bool JSFunction::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
201{
ba379fdc
A
202 if (isHostFunction())
203 return Base::getOwnPropertySlot(exec, propertyName, slot);
204
9dae56ea 205 if (propertyName == exec->propertyNames().prototype) {
14957cd0 206 WriteBarrierBase<Unknown>* location = getDirectLocation(exec->globalData(), propertyName);
9dae56ea 207
14957cd0
A
208 if (!location)
209 location = createPrototypeProperty(exec->globalData(), scope()->globalObject.get(), this);
9dae56ea 210
14957cd0 211 slot.setValue(this, location->get(), offsetForLocation(location));
9dae56ea
A
212 }
213
214 if (propertyName == exec->propertyNames().arguments) {
14957cd0
A
215 if (jsExecutable()->isStrictMode()) {
216 throwTypeError(exec, "Can't access arguments object of a strict mode function");
217 slot.setValue(jsNull());
218 return true;
219 }
220
4e4e5a6f 221 slot.setCacheableCustom(this, argumentsGetter);
9dae56ea
A
222 return true;
223 }
224
225 if (propertyName == exec->propertyNames().length) {
4e4e5a6f 226 slot.setCacheableCustom(this, lengthGetter);
9dae56ea
A
227 return true;
228 }
229
230 if (propertyName == exec->propertyNames().caller) {
14957cd0
A
231 if (jsExecutable()->isStrictMode()) {
232 throwTypeError(exec, StrictModeCallerAccessError);
233 slot.setValue(jsNull());
234 return true;
235 }
4e4e5a6f 236 slot.setCacheableCustom(this, callerGetter);
9dae56ea
A
237 return true;
238 }
239
240 return Base::getOwnPropertySlot(exec, propertyName, slot);
241}
242
14957cd0
A
243bool JSFunction::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
244{
245 if (isHostFunction())
246 return Base::getOwnPropertyDescriptor(exec, propertyName, descriptor);
247
248 if (propertyName == exec->propertyNames().prototype) {
249 PropertySlot slot;
250 getOwnPropertySlot(exec, propertyName, slot);
251 return Base::getOwnPropertyDescriptor(exec, propertyName, descriptor);
252 }
253
254 if (propertyName == exec->propertyNames().arguments) {
255 if (jsExecutable()->isStrictMode())
256 createDescriptorForThrowingProperty(exec, descriptor, StrictModeArgumentsAccessError);
257 else
f9bf01c6 258 descriptor.setDescriptor(exec->interpreter()->retrieveArguments(exec, this), ReadOnly | DontEnum | DontDelete);
14957cd0
A
259 return true;
260 }
261
262 if (propertyName == exec->propertyNames().length) {
263 descriptor.setDescriptor(jsNumber(jsExecutable()->parameterCount()), ReadOnly | DontEnum | DontDelete);
264 return true;
265 }
266
267 if (propertyName == exec->propertyNames().caller) {
268 if (jsExecutable()->isStrictMode())
269 createDescriptorForThrowingProperty(exec, descriptor, StrictModeCallerAccessError);
270 else
f9bf01c6 271 descriptor.setDescriptor(exec->interpreter()->retrieveCaller(exec, this), ReadOnly | DontEnum | DontDelete);
14957cd0 272 return true;
f9bf01c6
A
273 }
274
14957cd0
A
275 return Base::getOwnPropertyDescriptor(exec, propertyName, descriptor);
276}
277
f9bf01c6
A
278void JSFunction::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
279{
280 if (!isHostFunction() && (mode == IncludeDontEnumProperties)) {
14957cd0
A
281 // Make sure prototype has been reified.
282 PropertySlot slot;
283 getOwnPropertySlot(exec, exec->propertyNames().prototype, slot);
284
f9bf01c6
A
285 propertyNames.add(exec->propertyNames().arguments);
286 propertyNames.add(exec->propertyNames().callee);
287 propertyNames.add(exec->propertyNames().caller);
288 propertyNames.add(exec->propertyNames().length);
289 }
290 Base::getOwnPropertyNames(exec, propertyNames, mode);
291}
292
ba379fdc 293void JSFunction::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
9dae56ea 294{
ba379fdc
A
295 if (isHostFunction()) {
296 Base::put(exec, propertyName, value, slot);
297 return;
298 }
14957cd0
A
299 if (propertyName == exec->propertyNames().prototype) {
300 // Make sure prototype has been reified, such that it can only be overwritten
301 // following the rules set out in ECMA-262 8.12.9.
302 PropertySlot slot;
303 getOwnPropertySlot(exec, propertyName, slot);
304 }
305 if (jsExecutable()->isStrictMode()) {
306 if (propertyName == exec->propertyNames().arguments) {
307 throwTypeError(exec, StrictModeArgumentsAccessError);
308 return;
309 }
310 if (propertyName == exec->propertyNames().caller) {
311 throwTypeError(exec, StrictModeCallerAccessError);
312 return;
313 }
314 }
9dae56ea
A
315 if (propertyName == exec->propertyNames().arguments || propertyName == exec->propertyNames().length)
316 return;
317 Base::put(exec, propertyName, value, slot);
318}
319
320bool JSFunction::deleteProperty(ExecState* exec, const Identifier& propertyName)
321{
ba379fdc
A
322 if (isHostFunction())
323 return Base::deleteProperty(exec, propertyName);
9dae56ea
A
324 if (propertyName == exec->propertyNames().arguments || propertyName == exec->propertyNames().length)
325 return false;
326 return Base::deleteProperty(exec, propertyName);
327}
328
329// ECMA 13.2.2 [[Construct]]
330ConstructType JSFunction::getConstructData(ConstructData& constructData)
331{
ba379fdc
A
332 if (isHostFunction())
333 return ConstructTypeNone;
f9bf01c6 334 constructData.js.functionExecutable = jsExecutable();
14957cd0 335 constructData.js.scopeChain = scope();
9dae56ea
A
336 return ConstructTypeJS;
337}
338
9dae56ea 339} // namespace JSC