1/*
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
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"
31#include "ExceptionHelpers.h"
32#include "FunctionPrototype.h"
33#include "GetterSetter.h"
34#include "JSArray.h"
35#include "JSGlobalObject.h"
36#include "JSNotAnObject.h"
37#include "Interpreter.h"
38#include "ObjectConstructor.h"
39#include "ObjectPrototype.h"
40#include "Operations.h"
41#include "Parser.h"
42#include "PropertyNameArray.h"
43
44using namespace WTF;
45using namespace Unicode;
46
47namespace JSC {
48EncodedJSValue JSC_HOST_CALL callHostFunctionAsConstructor(ExecState* exec)
49{
50    return throwVMError(exec, createNotAConstructorError(exec, exec->callee()));
51}
52
53const ClassInfo JSFunction::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSFunction) };
54
55bool JSFunction::isHostFunctionNonInline() const
56{
57    return isHostFunction();
58}
59
60JSFunction* JSFunction::create(ExecState* exec, JSGlobalObject* globalObject, int length, const String& name, NativeFunction nativeFunction, Intrinsic intrinsic, NativeFunction nativeConstructor)
61{
62    NativeExecutable* executable;
63#if !ENABLE(JIT)
64    UNUSED_PARAM(intrinsic);
65#else
66    if (intrinsic != NoIntrinsic && exec->vm().canUseJIT()) {
67        ASSERT(nativeConstructor == callHostFunctionAsConstructor);
68        executable = exec->vm().getHostFunction(nativeFunction, intrinsic);
69    } else
70#endif
71        executable = exec->vm().getHostFunction(nativeFunction, nativeConstructor);
72
73    JSFunction* function = new (NotNull, allocateCell<JSFunction>(*exec->heap())) JSFunction(exec, globalObject, globalObject->functionStructure());
74    // Can't do this during initialization because getHostFunction might do a GC allocation.
75    function->finishCreation(exec, executable, length, name);
76    return function;
77}
78
79void JSFunction::destroy(JSCell* cell)
80{
81    static_cast<JSFunction*>(cell)->JSFunction::~JSFunction();
82}
83
84JSFunction::JSFunction(ExecState* exec, JSGlobalObject* globalObject, Structure* structure)
85    : Base(exec->vm(), structure)
86    , m_executable()
87    , m_scope(exec->vm(), this, globalObject)
88    // We initialize blind so that changes to the prototype after function creation but before
89    // the optimizer kicks in don't disable optimizations. Once the optimizer kicks in, the
90    // watchpoint will start watching and any changes will both force deoptimization and disable
91    // future attempts to optimize. This is necessary because we are guaranteed that the
92    // allocation profile is changed exactly once prior to optimizations kicking in. We could be
93    // smarter and count the number of times the prototype is clobbered and only optimize if it
94    // was clobbered exactly once, but that seems like overkill. In almost all cases it will be
95    // clobbered once, and if it's clobbered more than once, that will probably only occur
96    // before we started optimizing, anyway.
97    , m_allocationProfileWatchpoint(InitializedBlind)
98{
99}
100
101void JSFunction::finishCreation(ExecState* exec, NativeExecutable* executable, int length, const String& name)
102{
103    Base::finishCreation(exec->vm());
104    ASSERT(inherits(&s_info));
105    m_executable.set(exec->vm(), this, executable);
106    putDirect(exec->vm(), exec->vm().propertyNames->name, jsString(exec, name), DontDelete | ReadOnly | DontEnum);
107    putDirect(exec->vm(), exec->propertyNames().length, jsNumber(length), DontDelete | ReadOnly | DontEnum);
108}
109
110ObjectAllocationProfile* JSFunction::createAllocationProfile(ExecState* exec, size_t inlineCapacity)
111{
112    VM& vm = exec->vm();
113    JSObject* prototype = jsDynamicCast<JSObject*>(get(exec, vm.propertyNames->prototype));
114    if (!prototype)
115        prototype = globalObject()->objectPrototype();
116    m_allocationProfile.initialize(globalObject()->vm(), this, prototype, inlineCapacity);
117    return &m_allocationProfile;
118}
119
120String JSFunction::name(ExecState* exec)
121{
122    return get(exec, exec->vm().propertyNames->name).toWTFString(exec);
123}
124
125String JSFunction::displayName(ExecState* exec)
126{
127    JSValue displayName = getDirect(exec->vm(), exec->vm().propertyNames->displayName);
128
129    if (displayName && isJSString(displayName))
130        return asString(displayName)->tryGetValue();
131
132    return String();
133}
134
135const String JSFunction::calculatedDisplayName(ExecState* exec)
136{
137    const String explicitName = displayName(exec);
138
139    if (!explicitName.isEmpty())
140        return explicitName;
141
142    const String actualName = name(exec);
143    if (!actualName.isEmpty() || isHostFunction())
144        return actualName;
145
146    return jsExecutable()->inferredName().string();
147}
148
149const SourceCode* JSFunction::sourceCode() const
150{
151    if (isHostFunction())
152        return 0;
153    return &jsExecutable()->source();
154}
155
156void JSFunction::visitChildren(JSCell* cell, SlotVisitor& visitor)
157{
158    JSFunction* thisObject = jsCast<JSFunction*>(cell);
159    ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);
160    COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
161    ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
162    Base::visitChildren(thisObject, visitor);
163
164    visitor.append(&thisObject->m_scope);
165    visitor.append(&thisObject->m_executable);
166    thisObject->m_allocationProfile.visitAggregate(visitor);
167}
168
169CallType JSFunction::getCallData(JSCell* cell, CallData& callData)
170{
171    JSFunction* thisObject = jsCast<JSFunction*>(cell);
172    if (thisObject->isHostFunction()) {
173        callData.native.function = thisObject->nativeFunction();
174        return CallTypeHost;
175    }
176    callData.js.functionExecutable = thisObject->jsExecutable();
177    callData.js.scope = thisObject->scope();
178    return CallTypeJS;
179}
180
181JSValue JSFunction::argumentsGetter(ExecState* exec, JSValue slotBase, PropertyName)
182{
183    JSFunction* thisObj = jsCast<JSFunction*>(slotBase);
184    ASSERT(!thisObj->isHostFunction());
185    return exec->interpreter()->retrieveArgumentsFromVMCode(exec, thisObj);
186}
187
188JSValue JSFunction::callerGetter(ExecState* exec, JSValue slotBase, PropertyName)
189{
190    JSFunction* thisObj = jsCast<JSFunction*>(slotBase);
191    ASSERT(!thisObj->isHostFunction());
192    JSValue caller = exec->interpreter()->retrieveCallerFromVMCode(exec, thisObj);
193
194    // See ES5.1 15.3.5.4 - Function.caller may not be used to retrieve a strict caller.
195    if (!caller.isObject() || !asObject(caller)->inherits(&JSFunction::s_info))
196        return caller;
197    JSFunction* function = jsCast<JSFunction*>(caller);
198    if (function->isHostFunction() || !function->jsExecutable()->isStrictMode())
199        return caller;
200    return throwTypeError(exec, ASCIILiteral("Function.caller used to retrieve strict caller"));
201}
202
203JSValue JSFunction::lengthGetter(ExecState*, JSValue slotBase, PropertyName)
204{
205    JSFunction* thisObj = jsCast<JSFunction*>(slotBase);
206    ASSERT(!thisObj->isHostFunction());
207    return jsNumber(thisObj->jsExecutable()->parameterCount());
208}
209
210JSValue JSFunction::nameGetter(ExecState*, JSValue slotBase, PropertyName)
211{
212    JSFunction* thisObj = jsCast<JSFunction*>(slotBase);
213    ASSERT(!thisObj->isHostFunction());
214    return thisObj->jsExecutable()->nameValue();
215}
216
217bool JSFunction::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
218{
219    JSFunction* thisObject = jsCast<JSFunction*>(cell);
220    if (thisObject->isHostFunction())
221        return Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);
222
223    if (propertyName == exec->propertyNames().prototype) {
224        VM& vm = exec->vm();
225        PropertyOffset offset = thisObject->getDirectOffset(vm, propertyName);
226        if (!isValidOffset(offset)) {
227            JSObject* prototype = constructEmptyObject(exec);
228            prototype->putDirect(vm, exec->propertyNames().constructor, thisObject, DontEnum);
229            thisObject->putDirect(vm, exec->propertyNames().prototype, prototype, DontDelete | DontEnum);
230            offset = thisObject->getDirectOffset(vm, exec->propertyNames().prototype);
231            ASSERT(isValidOffset(offset));
232        }
233
234        slot.setValue(thisObject, thisObject->getDirect(offset), offset);
235    }
236
237    if (propertyName == exec->propertyNames().arguments) {
238        if (thisObject->jsExecutable()->isStrictMode()) {
239            bool result = Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);
240            if (!result) {
241                thisObject->putDirectAccessor(exec, propertyName, thisObject->globalObject()->throwTypeErrorGetterSetter(exec), DontDelete | DontEnum | Accessor);
242                result = Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);
243                ASSERT(result);
244            }
245            return result;
246        }
247        slot.setCacheableCustom(thisObject, argumentsGetter);
248        return true;
249    }
250
251    if (propertyName == exec->propertyNames().length) {
252        slot.setCacheableCustom(thisObject, lengthGetter);
253        return true;
254    }
255
256    if (propertyName == exec->propertyNames().name) {
257        slot.setCacheableCustom(thisObject, nameGetter);
258        return true;
259    }
260
261    if (propertyName == exec->propertyNames().caller) {
262        if (thisObject->jsExecutable()->isStrictMode()) {
263            bool result = Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);
264            if (!result) {
265                thisObject->putDirectAccessor(exec, propertyName, thisObject->globalObject()->throwTypeErrorGetterSetter(exec), DontDelete | DontEnum | Accessor);
266                result = Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);
267                ASSERT(result);
268            }
269            return result;
270        }
271        slot.setCacheableCustom(thisObject, callerGetter);
272        return true;
273    }
274
275    return Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);
276}
277
278bool JSFunction::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor)
279{
280    JSFunction* thisObject = jsCast<JSFunction*>(object);
281    if (thisObject->isHostFunction())
282        return Base::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor);
283
284    if (propertyName == exec->propertyNames().prototype) {
285        PropertySlot slot;
286        thisObject->methodTable()->getOwnPropertySlot(thisObject, exec, propertyName, slot);
287        return Base::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor);
288    }
289
290    if (propertyName == exec->propertyNames().arguments) {
291        if (thisObject->jsExecutable()->isStrictMode()) {
292            bool result = Base::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor);
293            if (!result) {
294                thisObject->putDirectAccessor(exec, propertyName, thisObject->globalObject()->throwTypeErrorGetterSetter(exec), DontDelete | DontEnum | Accessor);
295                result = Base::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor);
296                ASSERT(result);
297            }
298            return result;
299        }
300        descriptor.setDescriptor(exec->interpreter()->retrieveArgumentsFromVMCode(exec, thisObject), ReadOnly | DontEnum | DontDelete);
301        return true;
302    }
303
304    if (propertyName == exec->propertyNames().length) {
305        descriptor.setDescriptor(jsNumber(thisObject->jsExecutable()->parameterCount()), ReadOnly | DontEnum | DontDelete);
306        return true;
307    }
308
309    if (propertyName == exec->propertyNames().name) {
310        descriptor.setDescriptor(thisObject->jsExecutable()->nameValue(), ReadOnly | DontEnum | DontDelete);
311        return true;
312    }
313
314    if (propertyName == exec->propertyNames().caller) {
315        if (thisObject->jsExecutable()->isStrictMode()) {
316            bool result = Base::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor);
317            if (!result) {
318                thisObject->putDirectAccessor(exec, propertyName, thisObject->globalObject()->throwTypeErrorGetterSetter(exec), DontDelete | DontEnum | Accessor);
319                result = Base::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor);
320                ASSERT(result);
321            }
322            return result;
323        }
324        descriptor.setDescriptor(exec->interpreter()->retrieveCallerFromVMCode(exec, thisObject), ReadOnly | DontEnum | DontDelete);
325        return true;
326    }
327
328    return Base::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor);
329}
330
331void JSFunction::getOwnNonIndexPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
332{
333    JSFunction* thisObject = jsCast<JSFunction*>(object);
334    if (!thisObject->isHostFunction() && (mode == IncludeDontEnumProperties)) {
335        // Make sure prototype has been reified.
336        PropertySlot slot;
337        thisObject->methodTable()->getOwnPropertySlot(thisObject, exec, exec->propertyNames().prototype, slot);
338
339        propertyNames.add(exec->propertyNames().arguments);
340        propertyNames.add(exec->propertyNames().caller);
341        propertyNames.add(exec->propertyNames().length);
342        propertyNames.add(exec->propertyNames().name);
343    }
344    Base::getOwnNonIndexPropertyNames(thisObject, exec, propertyNames, mode);
345}
346
347void JSFunction::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
348{
349    JSFunction* thisObject = jsCast<JSFunction*>(cell);
350    if (thisObject->isHostFunction()) {
351        Base::put(thisObject, exec, propertyName, value, slot);
352        return;
353    }
354    if (propertyName == exec->propertyNames().prototype) {
355        // Make sure prototype has been reified, such that it can only be overwritten
356        // following the rules set out in ECMA-262 8.12.9.
357        PropertySlot slot;
358        thisObject->methodTable()->getOwnPropertySlot(thisObject, exec, propertyName, slot);
359        thisObject->m_allocationProfile.clear();
360        thisObject->m_allocationProfileWatchpoint.notifyWrite();
361        // Don't allow this to be cached, since a [[Put]] must clear m_allocationProfile.
362        PutPropertySlot dontCache;
363        Base::put(thisObject, exec, propertyName, value, dontCache);
364        return;
365    }
366    if (thisObject->jsExecutable()->isStrictMode() && (propertyName == exec->propertyNames().arguments || propertyName == exec->propertyNames().caller)) {
367        // This will trigger the property to be reified, if this is not already the case!
368        bool okay = thisObject->hasProperty(exec, propertyName);
369        ASSERT_UNUSED(okay, okay);
370        Base::put(thisObject, exec, propertyName, value, slot);
371        return;
372    }
373    if (propertyName == exec->propertyNames().arguments || propertyName == exec->propertyNames().length || propertyName == exec->propertyNames().name || propertyName == exec->propertyNames().caller) {
374        if (slot.isStrictMode())
375            throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
376        return;
377    }
378    Base::put(thisObject, exec, propertyName, value, slot);
379}
380
381bool JSFunction::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName)
382{
383    JSFunction* thisObject = jsCast<JSFunction*>(cell);
384    // For non-host functions, don't let these properties by deleted - except by DefineOwnProperty.
385    if (!thisObject->isHostFunction() && !exec->vm().isInDefineOwnProperty()
386        && (propertyName == exec->propertyNames().arguments
387            || propertyName == exec->propertyNames().length
388            || propertyName == exec->propertyNames().name
389            || propertyName == exec->propertyNames().prototype
390            || propertyName == exec->propertyNames().caller))
391        return false;
392    return Base::deleteProperty(thisObject, exec, propertyName);
393}
394
395bool JSFunction::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor, bool throwException)
396{
397    JSFunction* thisObject = jsCast<JSFunction*>(object);
398    if (thisObject->isHostFunction())
399        return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException);
400
401    if (propertyName == exec->propertyNames().prototype) {
402        // Make sure prototype has been reified, such that it can only be overwritten
403        // following the rules set out in ECMA-262 8.12.9.
404        PropertySlot slot;
405        thisObject->methodTable()->getOwnPropertySlot(thisObject, exec, propertyName, slot);
406        thisObject->m_allocationProfile.clear();
407        thisObject->m_allocationProfileWatchpoint.notifyWrite();
408        return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException);
409    }
410
411    bool valueCheck;
412    if (propertyName == exec->propertyNames().arguments) {
413        if (thisObject->jsExecutable()->isStrictMode()) {
414            if (!Base::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor))
415                thisObject->putDirectAccessor(exec, propertyName, thisObject->globalObject()->throwTypeErrorGetterSetter(exec), DontDelete | DontEnum | Accessor);
416            return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException);
417        }
418        valueCheck = !descriptor.value() || sameValue(exec, descriptor.value(), exec->interpreter()->retrieveArgumentsFromVMCode(exec, thisObject));
419    } else if (propertyName == exec->propertyNames().caller) {
420        if (thisObject->jsExecutable()->isStrictMode()) {
421            if (!Base::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor))
422                thisObject->putDirectAccessor(exec, propertyName, thisObject->globalObject()->throwTypeErrorGetterSetter(exec), DontDelete | DontEnum | Accessor);
423            return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException);
424        }
425        valueCheck = !descriptor.value() || sameValue(exec, descriptor.value(), exec->interpreter()->retrieveCallerFromVMCode(exec, thisObject));
426    } else if (propertyName == exec->propertyNames().length)
427        valueCheck = !descriptor.value() || sameValue(exec, descriptor.value(), jsNumber(thisObject->jsExecutable()->parameterCount()));
428    else if (propertyName == exec->propertyNames().name)
429        valueCheck = !descriptor.value() || sameValue(exec, descriptor.value(), thisObject->jsExecutable()->nameValue());
430    else
431        return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException);
432
433    if (descriptor.configurablePresent() && descriptor.configurable()) {
434        if (throwException)
435            throwError(exec, createTypeError(exec, ASCIILiteral("Attempting to configurable attribute of unconfigurable property.")));
436        return false;
437    }
438    if (descriptor.enumerablePresent() && descriptor.enumerable()) {
439        if (throwException)
440            throwError(exec, createTypeError(exec, ASCIILiteral("Attempting to change enumerable attribute of unconfigurable property.")));
441        return false;
442    }
443    if (descriptor.isAccessorDescriptor()) {
444        if (throwException)
445            throwError(exec, createTypeError(exec, ASCIILiteral("Attempting to change access mechanism for an unconfigurable property.")));
446        return false;
447    }
448    if (descriptor.writablePresent() && descriptor.writable()) {
449        if (throwException)
450            throwError(exec, createTypeError(exec, ASCIILiteral("Attempting to change writable attribute of unconfigurable property.")));
451        return false;
452    }
453    if (!valueCheck) {
454        if (throwException)
455            throwError(exec, createTypeError(exec, ASCIILiteral("Attempting to change value of a readonly property.")));
456        return false;
457    }
458    return true;
459}
460
461// ECMA 13.2.2 [[Construct]]
462ConstructType JSFunction::getConstructData(JSCell* cell, ConstructData& constructData)
463{
464    JSFunction* thisObject = jsCast<JSFunction*>(cell);
465    if (thisObject->isHostFunction()) {
466        constructData.native.function = thisObject->nativeConstructor();
467        return ConstructTypeHost;
468    }
469    constructData.js.functionExecutable = thisObject->jsExecutable();
470    constructData.js.scope = thisObject->scope();
471    return ConstructTypeJS;
472}
473
474String getCalculatedDisplayName(CallFrame* callFrame, JSObject* object)
475{
476    if (JSFunction* function = jsDynamicCast<JSFunction*>(object))
477        return function->calculatedDisplayName(callFrame);
478    if (InternalFunction* function = jsDynamicCast<InternalFunction*>(object))
479        return function->calculatedDisplayName(callFrame);
480    return "";
481}
482
483} // namespace JSC
484