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