[JSC] Unify how we throw TypeError from C++
[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-2009, 2015-2016 Apple Inc. All rights reserved.
5  *  Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca)
6  *  Copyright (C) 2007 Maks Orlovich
7  *  Copyright (C) 2015 Canon Inc. All rights reserved.
8  *
9  *  This library is free software; you can redistribute it and/or
10  *  modify it under the terms of the GNU Library General Public
11  *  License as published by the Free Software Foundation; either
12  *  version 2 of the License, or (at your option) any later version.
13  *
14  *  This library is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  *  Library General Public License for more details.
18  *
19  *  You should have received a copy of the GNU Library General Public License
20  *  along with this library; see the file COPYING.LIB.  If not, write to
21  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22  *  Boston, MA 02110-1301, USA.
23  *
24  */
25
26 #include "config.h"
27 #include "JSFunction.h"
28
29 #include "ClonedArguments.h"
30 #include "CodeBlock.h"
31 #include "CommonIdentifiers.h"
32 #include "CallFrame.h"
33 #include "ExceptionHelpers.h"
34 #include "FunctionPrototype.h"
35 #include "GeneratorPrototype.h"
36 #include "GetterSetter.h"
37 #include "JSArray.h"
38 #include "JSBoundFunction.h"
39 #include "JSCInlines.h"
40 #include "JSFunctionInlines.h"
41 #include "JSGlobalObject.h"
42 #include "Interpreter.h"
43 #include "ObjectConstructor.h"
44 #include "ObjectPrototype.h"
45 #include "Parser.h"
46 #include "PropertyNameArray.h"
47 #include "StackVisitor.h"
48
49 namespace JSC {
50
51 EncodedJSValue JSC_HOST_CALL callHostFunctionAsConstructor(ExecState* exec)
52 {
53     return throwVMError(exec, createNotAConstructorError(exec, exec->callee()));
54 }
55
56 const ClassInfo JSFunction::s_info = { "Function", &Base::s_info, 0, CREATE_METHOD_TABLE(JSFunction) };
57
58 bool JSFunction::isHostFunctionNonInline() const
59 {
60     return isHostFunction();
61 }
62
63 JSFunction* JSFunction::create(VM& vm, FunctionExecutable* executable, JSScope* scope)
64 {
65     return create(vm, executable, scope, scope->globalObject()->functionStructure());
66 }
67
68 JSFunction* JSFunction::create(VM& vm, FunctionExecutable* executable, JSScope* scope, Structure* structure)
69 {
70     JSFunction* result = createImpl(vm, executable, scope, structure);
71     executable->singletonFunction()->notifyWrite(vm, result, "Allocating a function");
72     return result;
73 }
74
75 #if ENABLE(WEBASSEMBLY)
76 JSFunction* JSFunction::create(VM& vm, WebAssemblyExecutable* executable, JSScope* scope)
77 {
78     JSFunction* function = new (NotNull, allocateCell<JSFunction>(vm.heap)) JSFunction(vm, executable, scope);
79     ASSERT(function->structure()->globalObject());
80     function->finishCreation(vm);
81     return function;
82 }
83 #endif
84
85 JSFunction* JSFunction::create(VM& vm, JSGlobalObject* globalObject, int length, const String& name, NativeFunction nativeFunction, Intrinsic intrinsic, NativeFunction nativeConstructor)
86 {
87     NativeExecutable* executable = vm.getHostFunction(nativeFunction, intrinsic, nativeConstructor, name);
88     JSFunction* function = new (NotNull, allocateCell<JSFunction>(vm.heap)) JSFunction(vm, globalObject, globalObject->functionStructure());
89     // Can't do this during initialization because getHostFunction might do a GC allocation.
90     function->finishCreation(vm, executable, length, name);
91     return function;
92 }
93
94 JSFunction::JSFunction(VM& vm, JSGlobalObject* globalObject, Structure* structure)
95     : Base(vm, globalObject, structure)
96     , m_executable()
97 {
98 }
99
100 void JSFunction::finishCreation(VM& vm, NativeExecutable* executable, int length, const String& name)
101 {
102     Base::finishCreation(vm);
103     ASSERT(inherits(info()));
104     m_executable.set(vm, this, executable);
105     putDirect(vm, vm.propertyNames->name, jsString(&vm, name), ReadOnly | DontEnum);
106     putDirect(vm, vm.propertyNames->length, jsNumber(length), ReadOnly | DontEnum);
107 }
108
109 JSFunction* JSFunction::createBuiltinFunction(VM& vm, FunctionExecutable* executable, JSGlobalObject* globalObject)
110 {
111     JSFunction* function = create(vm, executable, globalObject);
112     function->putDirect(vm, vm.propertyNames->name, jsString(&vm, executable->name().string()), ReadOnly | DontEnum);
113     function->putDirect(vm, vm.propertyNames->length, jsNumber(executable->parameterCount()), ReadOnly | DontEnum);
114     return function;
115 }
116
117 JSFunction* JSFunction::createBuiltinFunction(VM& vm, FunctionExecutable* executable, JSGlobalObject* globalObject, const String& name)
118 {
119     JSFunction* function = create(vm, executable, globalObject);
120     function->putDirect(vm, vm.propertyNames->name, jsString(&vm, name), ReadOnly | DontEnum);
121     function->putDirect(vm, vm.propertyNames->length, jsNumber(executable->parameterCount()), ReadOnly | DontEnum);
122     return function;
123 }
124
125 FunctionRareData* JSFunction::allocateRareData(VM& vm)
126 {
127     ASSERT(!m_rareData);
128     FunctionRareData* rareData = FunctionRareData::create(vm);
129
130     // A DFG compilation thread may be trying to read the rare data
131     // We want to ensure that it sees it properly allocated
132     WTF::storeStoreFence();
133
134     m_rareData.set(vm, this, rareData);
135     return m_rareData.get();
136 }
137
138 FunctionRareData* JSFunction::allocateAndInitializeRareData(ExecState* exec, size_t inlineCapacity)
139 {
140     ASSERT(!m_rareData);
141     VM& vm = exec->vm();
142     JSObject* prototype = jsDynamicCast<JSObject*>(get(exec, vm.propertyNames->prototype));
143     if (!prototype)
144         prototype = globalObject()->objectPrototype();
145     FunctionRareData* rareData = FunctionRareData::create(vm);
146     rareData->initializeObjectAllocationProfile(globalObject()->vm(), prototype, inlineCapacity);
147
148     // A DFG compilation thread may be trying to read the rare data
149     // We want to ensure that it sees it properly allocated
150     WTF::storeStoreFence();
151
152     m_rareData.set(vm, this, rareData);
153     return m_rareData.get();
154 }
155
156 FunctionRareData* JSFunction::initializeRareData(ExecState* exec, size_t inlineCapacity)
157 {
158     ASSERT(!!m_rareData);
159     VM& vm = exec->vm();
160     JSObject* prototype = jsDynamicCast<JSObject*>(get(exec, vm.propertyNames->prototype));
161     if (!prototype)
162         prototype = globalObject()->objectPrototype();
163     m_rareData->initializeObjectAllocationProfile(globalObject()->vm(), prototype, inlineCapacity);
164     return m_rareData.get();
165 }
166
167 String JSFunction::name()
168 {
169     if (isHostFunction()) {
170         NativeExecutable* executable = jsCast<NativeExecutable*>(this->executable());
171         return executable->name();
172     }
173     return jsExecutable()->name().string();
174 }
175
176 String JSFunction::displayName(VM& vm)
177 {
178     JSValue displayName = getDirect(vm, vm.propertyNames->displayName);
179     
180     if (displayName && isJSString(displayName))
181         return asString(displayName)->tryGetValue();
182     
183     return String();
184 }
185
186 const String JSFunction::calculatedDisplayName(VM& vm)
187 {
188     const String explicitName = displayName(vm);
189     
190     if (!explicitName.isEmpty())
191         return explicitName;
192     
193     const String actualName = name();
194     if (!actualName.isEmpty() || isHostOrBuiltinFunction())
195         return actualName;
196     
197     return jsExecutable()->inferredName().string();
198 }
199
200 const SourceCode* JSFunction::sourceCode() const
201 {
202     if (isHostOrBuiltinFunction())
203         return 0;
204     return &jsExecutable()->source();
205 }
206     
207 void JSFunction::visitChildren(JSCell* cell, SlotVisitor& visitor)
208 {
209     JSFunction* thisObject = jsCast<JSFunction*>(cell);
210     ASSERT_GC_OBJECT_INHERITS(thisObject, info());
211     Base::visitChildren(thisObject, visitor);
212
213     visitor.append(&thisObject->m_executable);
214     if (thisObject->m_rareData)
215         visitor.append(&thisObject->m_rareData);
216 }
217
218 CallType JSFunction::getCallData(JSCell* cell, CallData& callData)
219 {
220     JSFunction* thisObject = jsCast<JSFunction*>(cell);
221     if (thisObject->isHostFunction()) {
222         callData.native.function = thisObject->nativeFunction();
223         return CallType::Host;
224     }
225     callData.js.functionExecutable = thisObject->jsExecutable();
226     callData.js.scope = thisObject->scope();
227     return CallType::JS;
228 }
229
230 class RetrieveArgumentsFunctor {
231 public:
232     RetrieveArgumentsFunctor(JSFunction* functionObj)
233         : m_targetCallee(jsDynamicCast<JSObject*>(functionObj))
234         , m_result(jsNull())
235     {
236     }
237
238     JSValue result() const { return m_result; }
239
240     StackVisitor::Status operator()(StackVisitor& visitor) const
241     {
242         JSObject* callee = visitor->callee();
243         if (callee != m_targetCallee)
244             return StackVisitor::Continue;
245
246         m_result = JSValue(visitor->createArguments());
247         return StackVisitor::Done;
248     }
249
250 private:
251     JSObject* m_targetCallee;
252     mutable JSValue m_result;
253 };
254
255 static JSValue retrieveArguments(ExecState* exec, JSFunction* functionObj)
256 {
257     RetrieveArgumentsFunctor functor(functionObj);
258     exec->iterate(functor);
259     return functor.result();
260 }
261
262 EncodedJSValue JSFunction::argumentsGetter(ExecState* exec, EncodedJSValue thisValue, PropertyName)
263 {
264     JSFunction* thisObj = jsCast<JSFunction*>(JSValue::decode(thisValue));
265     ASSERT(!thisObj->isHostFunction());
266
267     return JSValue::encode(retrieveArguments(exec, thisObj));
268 }
269
270 class RetrieveCallerFunctionFunctor {
271 public:
272     RetrieveCallerFunctionFunctor(JSFunction* functionObj)
273         : m_targetCallee(jsDynamicCast<JSObject*>(functionObj))
274         , m_hasFoundFrame(false)
275         , m_hasSkippedToCallerFrame(false)
276         , m_result(jsNull())
277     {
278     }
279
280     JSValue result() const { return m_result; }
281
282     StackVisitor::Status operator()(StackVisitor& visitor) const
283     {
284         JSObject* callee = visitor->callee();
285
286         if (callee && callee->inherits(JSBoundFunction::info()))
287             return StackVisitor::Continue;
288
289         if (!m_hasFoundFrame && (callee != m_targetCallee))
290             return StackVisitor::Continue;
291
292         m_hasFoundFrame = true;
293         if (!m_hasSkippedToCallerFrame) {
294             m_hasSkippedToCallerFrame = true;
295             return StackVisitor::Continue;
296         }
297
298         if (callee)
299             m_result = callee;
300         return StackVisitor::Done;
301     }
302
303 private:
304     JSObject* m_targetCallee;
305     mutable bool m_hasFoundFrame;
306     mutable bool m_hasSkippedToCallerFrame;
307     mutable JSValue m_result;
308 };
309
310 static JSValue retrieveCallerFunction(ExecState* exec, JSFunction* functionObj)
311 {
312     RetrieveCallerFunctionFunctor functor(functionObj);
313     exec->iterate(functor);
314     return functor.result();
315 }
316
317 EncodedJSValue JSFunction::callerGetter(ExecState* exec, EncodedJSValue thisValue, PropertyName)
318 {
319     JSFunction* thisObj = jsCast<JSFunction*>(JSValue::decode(thisValue));
320     ASSERT(!thisObj->isHostFunction());
321     JSValue caller = retrieveCallerFunction(exec, thisObj);
322
323     // See ES5.1 15.3.5.4 - Function.caller may not be used to retrieve a strict caller.
324     if (!caller.isObject() || !asObject(caller)->inherits(JSFunction::info())) {
325         // It isn't a JSFunction, but if it is a JSCallee from a program or call eval, return null.
326         if (jsDynamicCast<JSCallee*>(caller))
327             return JSValue::encode(jsNull());
328         return JSValue::encode(caller);
329     }
330     JSFunction* function = jsCast<JSFunction*>(caller);
331     if (function->isHostOrBuiltinFunction() || !function->jsExecutable()->isStrictMode())
332         return JSValue::encode(caller);
333     return JSValue::encode(throwTypeError(exec, ASCIILiteral("Function.caller used to retrieve strict caller")));
334 }
335
336 bool JSFunction::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
337 {
338     JSFunction* thisObject = jsCast<JSFunction*>(object);
339     if (thisObject->isHostOrBuiltinFunction())
340         return Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);
341
342     if (propertyName == exec->propertyNames().prototype && !thisObject->jsExecutable()->isArrowFunction()) {
343         VM& vm = exec->vm();
344         unsigned attributes;
345         PropertyOffset offset = thisObject->getDirectOffset(vm, propertyName, attributes);
346         if (!isValidOffset(offset)) {
347             JSObject* prototype = nullptr;
348             if (thisObject->jsExecutable()->parseMode() == SourceParseMode::GeneratorWrapperFunctionMode)
349                 prototype = constructEmptyObject(exec, thisObject->globalObject()->generatorPrototype());
350             else
351                 prototype = constructEmptyObject(exec);
352
353             prototype->putDirect(vm, exec->propertyNames().constructor, thisObject, DontEnum);
354             thisObject->putDirect(vm, exec->propertyNames().prototype, prototype, DontDelete | DontEnum);
355             offset = thisObject->getDirectOffset(vm, exec->propertyNames().prototype, attributes);
356             ASSERT(isValidOffset(offset));
357         }
358
359         slot.setValue(thisObject, attributes, thisObject->getDirect(offset), offset);
360     }
361
362     if (propertyName == exec->propertyNames().arguments) {
363         if (thisObject->jsExecutable()->isStrictMode() || thisObject->jsExecutable()->isClassConstructorFunction()) {
364             bool result = Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);
365             if (!result) {
366                 GetterSetter* errorGetterSetter = thisObject->globalObject()->throwTypeErrorArgumentsCalleeAndCallerGetterSetter();
367                 thisObject->putDirectAccessor(exec, propertyName, errorGetterSetter, DontDelete | DontEnum | Accessor);
368                 result = Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);
369                 ASSERT(result);
370             }
371             return result;
372         }
373         slot.setCacheableCustom(thisObject, ReadOnly | DontEnum | DontDelete, argumentsGetter);
374         return true;
375     }
376
377     if (propertyName == exec->propertyNames().caller) {
378         if (thisObject->jsExecutable()->isStrictMode() || thisObject->jsExecutable()->isClassConstructorFunction()) {
379             bool result = Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);
380             if (!result) {
381                 GetterSetter* errorGetterSetter = thisObject->globalObject()->throwTypeErrorArgumentsCalleeAndCallerGetterSetter();
382                 thisObject->putDirectAccessor(exec, propertyName, errorGetterSetter, DontDelete | DontEnum | Accessor);
383                 result = Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);
384                 ASSERT(result);
385             }
386             return result;
387         }
388         slot.setCacheableCustom(thisObject, ReadOnly | DontEnum | DontDelete, callerGetter);
389         return true;
390     }
391
392     thisObject->reifyLazyPropertyIfNeeded(exec, propertyName);
393
394     return Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);
395 }
396
397 void JSFunction::getOwnNonIndexPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
398 {
399     JSFunction* thisObject = jsCast<JSFunction*>(object);
400     if (!thisObject->isHostOrBuiltinFunction() && mode.includeDontEnumProperties()) {
401         VM& vm = exec->vm();
402         // Make sure prototype has been reified.
403         PropertySlot slot(thisObject, PropertySlot::InternalMethodType::VMInquiry);
404         thisObject->methodTable(vm)->getOwnPropertySlot(thisObject, exec, vm.propertyNames->prototype, slot);
405
406         propertyNames.add(vm.propertyNames->arguments);
407         propertyNames.add(vm.propertyNames->caller);
408         if (!thisObject->hasReifiedLength())
409             propertyNames.add(vm.propertyNames->length);
410         if (!thisObject->hasReifiedName())
411             propertyNames.add(vm.propertyNames->name);
412     }
413     Base::getOwnNonIndexPropertyNames(thisObject, exec, propertyNames, mode);
414 }
415
416 bool JSFunction::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
417 {
418     JSFunction* thisObject = jsCast<JSFunction*>(cell);
419
420     if (UNLIKELY(isThisValueAltered(slot, thisObject)))
421         return ordinarySetSlow(exec, thisObject, propertyName, value, slot.thisValue(), slot.isStrictMode());
422
423     if (thisObject->isHostOrBuiltinFunction())
424         return Base::put(thisObject, exec, propertyName, value, slot);
425
426     if (propertyName == exec->propertyNames().prototype) {
427         // Make sure prototype has been reified, such that it can only be overwritten
428         // following the rules set out in ECMA-262 8.12.9.
429         PropertySlot slot(thisObject, PropertySlot::InternalMethodType::VMInquiry);
430         thisObject->methodTable(exec->vm())->getOwnPropertySlot(thisObject, exec, propertyName, slot);
431         if (thisObject->m_rareData)
432             thisObject->m_rareData->clear("Store to prototype property of a function");
433         // Don't allow this to be cached, since a [[Put]] must clear m_rareData.
434         PutPropertySlot dontCache(thisObject);
435         return Base::put(thisObject, exec, propertyName, value, dontCache);
436     }
437     if (thisObject->jsExecutable()->isStrictMode() && (propertyName == exec->propertyNames().arguments || propertyName == exec->propertyNames().caller)) {
438         // This will trigger the property to be reified, if this is not already the case!
439         bool okay = thisObject->hasProperty(exec, propertyName);
440         ASSERT_UNUSED(okay, okay);
441         return Base::put(thisObject, exec, propertyName, value, slot);
442     }
443     if (propertyName == exec->propertyNames().arguments || propertyName == exec->propertyNames().caller) {
444         if (slot.isStrictMode())
445             throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
446         return false;
447     }
448     thisObject->reifyLazyPropertyIfNeeded(exec, propertyName);
449     return Base::put(thisObject, exec, propertyName, value, slot);
450 }
451
452 bool JSFunction::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName)
453 {
454     JSFunction* thisObject = jsCast<JSFunction*>(cell);
455     // For non-host functions, don't let these properties by deleted - except by DefineOwnProperty.
456     if (!thisObject->isHostOrBuiltinFunction() && exec->vm().deletePropertyMode() != VM::DeletePropertyMode::IgnoreConfigurable) {
457         FunctionExecutable* executable = thisObject->jsExecutable();
458         if (propertyName == exec->propertyNames().arguments
459             || (propertyName == exec->propertyNames().prototype && !executable->isArrowFunction())
460             || propertyName == exec->propertyNames().caller)
461             return false;
462
463         thisObject->reifyLazyPropertyIfNeeded(exec, propertyName);
464     }
465     
466     return Base::deleteProperty(thisObject, exec, propertyName);
467 }
468
469 bool JSFunction::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName propertyName, const PropertyDescriptor& descriptor, bool throwException)
470 {
471     JSFunction* thisObject = jsCast<JSFunction*>(object);
472     if (thisObject->isHostOrBuiltinFunction())
473         return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException);
474
475     if (propertyName == exec->propertyNames().prototype) {
476         // Make sure prototype has been reified, such that it can only be overwritten
477         // following the rules set out in ECMA-262 8.12.9.
478         PropertySlot slot(thisObject, PropertySlot::InternalMethodType::VMInquiry);
479         thisObject->methodTable(exec->vm())->getOwnPropertySlot(thisObject, exec, propertyName, slot);
480         if (thisObject->m_rareData)
481             thisObject->m_rareData->clear("Store to prototype property of a function");
482         return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException);
483     }
484
485     bool valueCheck;
486     if (propertyName == exec->propertyNames().arguments) {
487         if (thisObject->jsExecutable()->isStrictMode()) {
488             PropertySlot slot(thisObject, PropertySlot::InternalMethodType::VMInquiry);
489             if (!Base::getOwnPropertySlot(thisObject, exec, propertyName, slot))
490                 thisObject->putDirectAccessor(exec, propertyName, thisObject->globalObject()->throwTypeErrorArgumentsCalleeAndCallerGetterSetter(), DontDelete | DontEnum | Accessor);
491             return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException);
492         }
493         valueCheck = !descriptor.value() || sameValue(exec, descriptor.value(), retrieveArguments(exec, thisObject));
494     } else if (propertyName == exec->propertyNames().caller) {
495         if (thisObject->jsExecutable()->isStrictMode()) {
496             PropertySlot slot(thisObject, PropertySlot::InternalMethodType::VMInquiry);
497             if (!Base::getOwnPropertySlot(thisObject, exec, propertyName, slot))
498                 thisObject->putDirectAccessor(exec, propertyName, thisObject->globalObject()->throwTypeErrorArgumentsCalleeAndCallerGetterSetter(), DontDelete | DontEnum | Accessor);
499             return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException);
500         }
501         valueCheck = !descriptor.value() || sameValue(exec, descriptor.value(), retrieveCallerFunction(exec, thisObject));
502     } else {
503         thisObject->reifyLazyPropertyIfNeeded(exec, propertyName);
504         return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException);
505     }
506      
507     if (descriptor.configurablePresent() && descriptor.configurable()) {
508         if (throwException)
509             throwTypeError(exec, ASCIILiteral("Attempting to change configurable attribute of unconfigurable property."));
510         return false;
511     }
512     if (descriptor.enumerablePresent() && descriptor.enumerable()) {
513         if (throwException)
514             throwTypeError(exec, ASCIILiteral("Attempting to change enumerable attribute of unconfigurable property."));
515         return false;
516     }
517     if (descriptor.isAccessorDescriptor()) {
518         if (throwException)
519             throwTypeError(exec, ASCIILiteral(UnconfigurablePropertyChangeAccessMechanismError));
520         return false;
521     }
522     if (descriptor.writablePresent() && descriptor.writable()) {
523         if (throwException)
524             throwTypeError(exec, ASCIILiteral("Attempting to change writable attribute of unconfigurable property."));
525         return false;
526     }
527     if (!valueCheck) {
528         if (throwException)
529             throwTypeError(exec, ASCIILiteral("Attempting to change value of a readonly property."));
530         return false;
531     }
532     return true;
533 }
534
535 // ECMA 13.2.2 [[Construct]]
536 ConstructType JSFunction::getConstructData(JSCell* cell, ConstructData& constructData)
537 {
538     JSFunction* thisObject = jsCast<JSFunction*>(cell);
539
540     if (thisObject->isHostFunction()) {
541         constructData.native.function = thisObject->nativeConstructor();
542         return ConstructType::Host;
543     }
544
545     FunctionExecutable* functionExecutable = thisObject->jsExecutable();
546     if (functionExecutable->constructAbility() == ConstructAbility::CannotConstruct)
547         return ConstructType::None;
548
549     constructData.js.functionExecutable = functionExecutable;
550     constructData.js.scope = thisObject->scope();
551     return ConstructType::JS;
552 }
553
554 String getCalculatedDisplayName(VM& vm, JSObject* object)
555 {
556     if (JSFunction* function = jsDynamicCast<JSFunction*>(object))
557         return function->calculatedDisplayName(vm);
558     if (InternalFunction* function = jsDynamicCast<InternalFunction*>(object))
559         return function->calculatedDisplayName(vm);
560     return emptyString();
561 }
562
563 void JSFunction::setFunctionName(ExecState* exec, JSValue value)
564 {
565     // The "name" property may have been already been defined as part of a property list in an
566     // object literal (and therefore reified).
567     if (hasReifiedName())
568         return;
569
570     ASSERT(!isHostFunction());
571     ASSERT(jsExecutable()->ecmaName().isNull());
572     String name;
573     if (value.isSymbol()) {
574         SymbolImpl* uid = asSymbol(value)->privateName().uid();
575         if (uid->isNullSymbol())
576             name = emptyString();
577         else
578             name = makeString("[", String(asSymbol(value)->privateName().uid()), ']');
579     } else {
580         VM& vm = exec->vm();
581         JSString* jsStr = value.toString(exec);
582         if (vm.exception())
583             return;
584         name = jsStr->value(exec);
585         if (vm.exception())
586             return;
587     }
588     reifyName(exec, name);
589 }
590
591 void JSFunction::reifyLength(ExecState* exec)
592 {
593     VM& vm = exec->vm();
594     FunctionRareData* rareData = this->rareData(vm);
595
596     ASSERT(!hasReifiedLength());
597     ASSERT(!isHostFunction());
598     JSValue initialValue = jsNumber(jsExecutable()->parameterCount());
599     unsigned initialAttributes = DontEnum | ReadOnly;
600     const Identifier& identifier = exec->propertyNames().length;
601     putDirect(vm, identifier, initialValue, initialAttributes);
602
603     rareData->setHasReifiedLength();
604 }
605
606 void JSFunction::reifyName(ExecState* exec)
607 {
608     String name = jsExecutable()->ecmaName().string();
609     reifyName(exec, name);
610 }
611
612 void JSFunction::reifyName(ExecState* exec, String name)
613 {
614     VM& vm = exec->vm();
615     FunctionRareData* rareData = this->rareData(vm);
616
617     ASSERT(!hasReifiedName());
618     ASSERT(!isHostFunction());
619     unsigned initialAttributes = DontEnum | ReadOnly;
620     const Identifier& propID = exec->propertyNames().name;
621
622     if (exec->lexicalGlobalObject()->needsSiteSpecificQuirks()) {
623         auto illegalCharMatcher = [] (UChar ch) -> bool {
624             return ch == ' ' || ch == '|';
625         };
626         if (name.find(illegalCharMatcher) != notFound)
627             name = String();
628     }
629     
630     if (jsExecutable()->isGetter())
631         name = makeString("get ", name);
632     else if (jsExecutable()->isSetter())
633         name = makeString("set ", name);
634
635     putDirect(vm, propID, jsString(exec, name), initialAttributes);
636     rareData->setHasReifiedName();
637 }
638
639 void JSFunction::reifyLazyPropertyIfNeeded(ExecState* exec, PropertyName propertyName)
640 {
641     if (propertyName == exec->propertyNames().length) {
642         if (!hasReifiedLength())
643             reifyLength(exec);
644     } else if (propertyName == exec->propertyNames().name) {
645         if (!hasReifiedName())
646             reifyName(exec);
647     }
648 }
649
650 } // namespace JSC