567acc81f5dcd1d45c2ce56385c4c783a55ad6cb
[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     VM& vm = exec->vm();
54     auto scope = DECLARE_THROW_SCOPE(vm);
55     return throwVMError(exec, scope, createNotAConstructorError(exec, exec->jsCallee()));
56 }
57
58 const ClassInfo JSFunction::s_info = { "Function", &Base::s_info, 0, CREATE_METHOD_TABLE(JSFunction) };
59
60 bool JSFunction::isHostFunctionNonInline() const
61 {
62     return isHostFunction();
63 }
64
65 JSFunction* JSFunction::create(VM& vm, FunctionExecutable* executable, JSScope* scope)
66 {
67     return create(vm, executable, scope, scope->globalObject(vm)->functionStructure());
68 }
69
70 JSFunction* JSFunction::create(VM& vm, FunctionExecutable* executable, JSScope* scope, Structure* structure)
71 {
72     JSFunction* result = createImpl(vm, executable, scope, structure);
73     executable->singletonFunction()->notifyWrite(vm, result, "Allocating a function");
74     return result;
75 }
76
77 JSFunction* JSFunction::create(VM& vm, JSGlobalObject* globalObject, int length, const String& name, NativeFunction nativeFunction, Intrinsic intrinsic, NativeFunction nativeConstructor, const DOMJIT::Signature* signature)
78 {
79     NativeExecutable* executable = vm.getHostFunction(nativeFunction, intrinsic, nativeConstructor, signature, name);
80     JSFunction* function = new (NotNull, allocateCell<JSFunction>(vm.heap)) JSFunction(vm, globalObject, globalObject->functionStructure());
81     // Can't do this during initialization because getHostFunction might do a GC allocation.
82     function->finishCreation(vm, executable, length, name);
83     return function;
84 }
85
86 JSFunction::JSFunction(VM& vm, JSGlobalObject* globalObject, Structure* structure)
87     : Base(vm, globalObject, structure)
88     , m_executable()
89 {
90 }
91
92 void JSFunction::finishCreation(VM& vm, NativeExecutable* executable, int length, const String& name)
93 {
94     Base::finishCreation(vm);
95     ASSERT(inherits(info()));
96     m_executable.set(vm, this, executable);
97     // Some NativeExecutable functions, like JSBoundFunction, decide to lazily allocate their name string.
98     if (!name.isNull())
99         putDirect(vm, vm.propertyNames->name, jsString(&vm, name), ReadOnly | DontEnum);
100     putDirect(vm, vm.propertyNames->length, jsNumber(length), ReadOnly | DontEnum);
101 }
102
103 JSFunction* JSFunction::createBuiltinFunction(VM& vm, FunctionExecutable* executable, JSGlobalObject* globalObject)
104 {
105     JSFunction* function = create(vm, executable, globalObject);
106     function->putDirect(vm, vm.propertyNames->name, jsString(&vm, executable->name().string()), ReadOnly | DontEnum);
107     function->putDirect(vm, vm.propertyNames->length, jsNumber(executable->functionLength()), ReadOnly | DontEnum);
108     return function;
109 }
110
111 JSFunction* JSFunction::createBuiltinFunction(VM& vm, FunctionExecutable* executable, JSGlobalObject* globalObject, const String& name)
112 {
113     JSFunction* function = create(vm, executable, globalObject);
114     function->putDirect(vm, vm.propertyNames->name, jsString(&vm, name), ReadOnly | DontEnum);
115     function->putDirect(vm, vm.propertyNames->length, jsNumber(executable->functionLength()), ReadOnly | DontEnum);
116     return function;
117 }
118
119 FunctionRareData* JSFunction::allocateRareData(VM& vm)
120 {
121     ASSERT(!m_rareData);
122     FunctionRareData* rareData = FunctionRareData::create(vm);
123
124     // A DFG compilation thread may be trying to read the rare data
125     // We want to ensure that it sees it properly allocated
126     WTF::storeStoreFence();
127
128     m_rareData.set(vm, this, rareData);
129     return m_rareData.get();
130 }
131
132 FunctionRareData* JSFunction::allocateAndInitializeRareData(ExecState* exec, size_t inlineCapacity)
133 {
134     ASSERT(!m_rareData);
135     VM& vm = exec->vm();
136     JSObject* prototype = jsDynamicCast<JSObject*>(get(exec, vm.propertyNames->prototype));
137     if (!prototype)
138         prototype = globalObject(vm)->objectPrototype();
139     FunctionRareData* rareData = FunctionRareData::create(vm);
140     rareData->initializeObjectAllocationProfile(vm, prototype, inlineCapacity);
141
142     // A DFG compilation thread may be trying to read the rare data
143     // We want to ensure that it sees it properly allocated
144     WTF::storeStoreFence();
145
146     m_rareData.set(vm, this, rareData);
147     return m_rareData.get();
148 }
149
150 FunctionRareData* JSFunction::initializeRareData(ExecState* exec, size_t inlineCapacity)
151 {
152     ASSERT(!!m_rareData);
153     VM& vm = exec->vm();
154     JSObject* prototype = jsDynamicCast<JSObject*>(get(exec, vm.propertyNames->prototype));
155     if (!prototype)
156         prototype = globalObject(vm)->objectPrototype();
157     m_rareData->initializeObjectAllocationProfile(vm, prototype, inlineCapacity);
158     return m_rareData.get();
159 }
160
161 String JSFunction::name(VM& vm)
162 {
163     if (isHostFunction()) {
164         NativeExecutable* executable = jsCast<NativeExecutable*>(this->executable());
165         return executable->name();
166     }
167     const Identifier identifier = jsExecutable()->name();
168     if (identifier == vm.propertyNames->builtinNames().starDefaultPrivateName())
169         return emptyString();
170     return identifier.string();
171 }
172
173 String JSFunction::displayName(VM& vm)
174 {
175     JSValue displayName = getDirect(vm, vm.propertyNames->displayName);
176     
177     if (displayName && isJSString(displayName))
178         return asString(displayName)->tryGetValue();
179     
180     return String();
181 }
182
183 const String JSFunction::calculatedDisplayName(VM& vm)
184 {
185     const String explicitName = displayName(vm);
186     
187     if (!explicitName.isEmpty())
188         return explicitName;
189     
190     const String actualName = name(vm);
191     if (!actualName.isEmpty() || isHostOrBuiltinFunction())
192         return actualName;
193     
194     return jsExecutable()->inferredName().string();
195 }
196
197 const SourceCode* JSFunction::sourceCode() const
198 {
199     if (isHostOrBuiltinFunction())
200         return 0;
201     return &jsExecutable()->source();
202 }
203     
204 void JSFunction::visitChildren(JSCell* cell, SlotVisitor& visitor)
205 {
206     JSFunction* thisObject = jsCast<JSFunction*>(cell);
207     ASSERT_GC_OBJECT_INHERITS(thisObject, info());
208     Base::visitChildren(thisObject, visitor);
209
210     visitor.append(&thisObject->m_executable);
211     visitor.append(&thisObject->m_rareData);
212 }
213
214 CallType JSFunction::getCallData(JSCell* cell, CallData& callData)
215 {
216     JSFunction* thisObject = jsCast<JSFunction*>(cell);
217     if (thisObject->isHostFunction()) {
218         callData.native.function = thisObject->nativeFunction();
219         return CallType::Host;
220     }
221     callData.js.functionExecutable = thisObject->jsExecutable();
222     callData.js.scope = thisObject->scope();
223     return CallType::JS;
224 }
225
226 class RetrieveArgumentsFunctor {
227 public:
228     RetrieveArgumentsFunctor(JSFunction* functionObj)
229         : m_targetCallee(jsDynamicCast<JSObject*>(functionObj))
230         , m_result(jsNull())
231     {
232     }
233
234     JSValue result() const { return m_result; }
235
236     StackVisitor::Status operator()(StackVisitor& visitor) const
237     {
238         JSCell* callee = visitor->callee();
239         if (callee != m_targetCallee)
240             return StackVisitor::Continue;
241
242         m_result = JSValue(visitor->createArguments());
243         return StackVisitor::Done;
244     }
245
246 private:
247     JSObject* m_targetCallee;
248     mutable JSValue m_result;
249 };
250
251 static JSValue retrieveArguments(ExecState* exec, JSFunction* functionObj)
252 {
253     RetrieveArgumentsFunctor functor(functionObj);
254     exec->iterate(functor);
255     return functor.result();
256 }
257
258 EncodedJSValue JSFunction::argumentsGetter(ExecState* exec, EncodedJSValue thisValue, PropertyName)
259 {
260     JSFunction* thisObj = jsCast<JSFunction*>(JSValue::decode(thisValue));
261     ASSERT(!thisObj->isHostFunction());
262
263     return JSValue::encode(retrieveArguments(exec, thisObj));
264 }
265
266 class RetrieveCallerFunctionFunctor {
267 public:
268     RetrieveCallerFunctionFunctor(JSFunction* functionObj)
269         : m_targetCallee(jsDynamicCast<JSObject*>(functionObj))
270         , m_hasFoundFrame(false)
271         , m_hasSkippedToCallerFrame(false)
272         , m_result(jsNull())
273     {
274     }
275
276     JSValue result() const { return m_result; }
277
278     StackVisitor::Status operator()(StackVisitor& visitor) const
279     {
280         JSCell* callee = visitor->callee();
281
282         if (callee && callee->inherits(JSBoundFunction::info()))
283             return StackVisitor::Continue;
284
285         if (!m_hasFoundFrame && (callee != m_targetCallee))
286             return StackVisitor::Continue;
287
288         m_hasFoundFrame = true;
289         if (!m_hasSkippedToCallerFrame) {
290             m_hasSkippedToCallerFrame = true;
291             return StackVisitor::Continue;
292         }
293
294         if (callee)
295             m_result = callee;
296         return StackVisitor::Done;
297     }
298
299 private:
300     JSObject* m_targetCallee;
301     mutable bool m_hasFoundFrame;
302     mutable bool m_hasSkippedToCallerFrame;
303     mutable JSValue m_result;
304 };
305
306 static JSValue retrieveCallerFunction(ExecState* exec, JSFunction* functionObj)
307 {
308     RetrieveCallerFunctionFunctor functor(functionObj);
309     exec->iterate(functor);
310     return functor.result();
311 }
312
313 EncodedJSValue JSFunction::callerGetter(ExecState* exec, EncodedJSValue thisValue, PropertyName)
314 {
315     VM& vm = exec->vm();
316     auto scope = DECLARE_THROW_SCOPE(vm);
317
318     JSFunction* thisObj = jsCast<JSFunction*>(JSValue::decode(thisValue));
319     ASSERT(!thisObj->isHostFunction());
320     JSValue caller = retrieveCallerFunction(exec, thisObj);
321
322     // See ES5.1 15.3.5.4 - Function.caller may not be used to retrieve a strict caller.
323     if (!caller.isObject() || !asObject(caller)->inherits(JSFunction::info())) {
324         // It isn't a JSFunction, but if it is a JSCallee from a program or call eval, return null.
325         if (jsDynamicCast<JSCallee*>(caller))
326             return JSValue::encode(jsNull());
327         return JSValue::encode(caller);
328     }
329     JSFunction* function = jsCast<JSFunction*>(caller);
330     if (function->isHostOrBuiltinFunction() || !function->jsExecutable()->isStrictMode())
331         return JSValue::encode(caller);
332     return JSValue::encode(throwTypeError(exec, scope, ASCIILiteral("Function.caller used to retrieve strict caller")));
333 }
334
335 bool JSFunction::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
336 {
337     VM& vm = exec->vm();
338     JSFunction* thisObject = jsCast<JSFunction*>(object);
339     if (thisObject->isHostOrBuiltinFunction()) {
340         thisObject->reifyBoundNameIfNeeded(vm, exec, propertyName);
341         return Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);
342     }
343
344     if (propertyName == vm.propertyNames->prototype && thisObject->jsExecutable()->hasPrototypeProperty() && !thisObject->jsExecutable()->isClassConstructorFunction()) {
345         unsigned attributes;
346         PropertyOffset offset = thisObject->getDirectOffset(vm, propertyName, attributes);
347         if (!isValidOffset(offset)) {
348             JSObject* prototype = nullptr;
349             if (thisObject->jsExecutable()->parseMode() == SourceParseMode::GeneratorWrapperFunctionMode) {
350                 // Unlike function instances, the object that is the value of the a GeneratorFunction's prototype
351                 // property does not have a constructor property whose value is the GeneratorFunction instance.
352                 // https://tc39.github.io/ecma262/#sec-generatorfunction-instances-prototype
353                 prototype = constructEmptyObject(exec, thisObject->globalObject(vm)->generatorPrototype());
354             } else {
355                 prototype = constructEmptyObject(exec);
356                 prototype->putDirect(vm, vm.propertyNames->constructor, thisObject, DontEnum);
357             }
358
359             thisObject->putDirect(vm, vm.propertyNames->prototype, prototype, DontDelete | DontEnum);
360             offset = thisObject->getDirectOffset(vm, vm.propertyNames->prototype, attributes);
361             ASSERT(isValidOffset(offset));
362         }
363
364         slot.setValue(thisObject, attributes, thisObject->getDirect(offset), offset);
365     }
366
367     if (propertyName == exec->propertyNames().arguments) {
368         if (!thisObject->jsExecutable()->hasCallerAndArgumentsProperties())
369             return Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);
370         
371         slot.setCacheableCustom(thisObject, ReadOnly | DontEnum | DontDelete, argumentsGetter);
372         return true;
373     }
374
375     if (propertyName == exec->propertyNames().caller) {
376         if (!thisObject->jsExecutable()->hasCallerAndArgumentsProperties())
377             return Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);
378
379         slot.setCacheableCustom(thisObject, ReadOnly | DontEnum | DontDelete, callerGetter);
380         return true;
381     }
382
383     thisObject->reifyLazyPropertyIfNeeded(vm, exec, propertyName);
384
385     return Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);
386 }
387
388 void JSFunction::getOwnNonIndexPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
389 {
390     JSFunction* thisObject = jsCast<JSFunction*>(object);
391     if (!thisObject->isHostOrBuiltinFunction() && mode.includeDontEnumProperties()) {
392         VM& vm = exec->vm();
393         // Make sure prototype has been reified.
394         PropertySlot slot(thisObject, PropertySlot::InternalMethodType::VMInquiry);
395         thisObject->methodTable(vm)->getOwnPropertySlot(thisObject, exec, vm.propertyNames->prototype, slot);
396
397         if (thisObject->jsExecutable()->hasCallerAndArgumentsProperties()) {
398             propertyNames.add(vm.propertyNames->arguments);
399             propertyNames.add(vm.propertyNames->caller);
400         }
401         if (!thisObject->hasReifiedLength())
402             propertyNames.add(vm.propertyNames->length);
403         if (!thisObject->hasReifiedName())
404             propertyNames.add(vm.propertyNames->name);
405     } else if (thisObject->isHostOrBuiltinFunction() && mode.includeDontEnumProperties() && thisObject->inherits(JSBoundFunction::info()) && !thisObject->hasReifiedName())
406         propertyNames.add(exec->vm().propertyNames->name);
407     Base::getOwnNonIndexPropertyNames(thisObject, exec, propertyNames, mode);
408 }
409
410 bool JSFunction::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
411 {
412     VM& vm = exec->vm();
413     auto scope = DECLARE_THROW_SCOPE(vm);
414
415     JSFunction* thisObject = jsCast<JSFunction*>(cell);
416
417     if (UNLIKELY(isThisValueAltered(slot, thisObject))) {
418         scope.release();
419         return ordinarySetSlow(exec, thisObject, propertyName, value, slot.thisValue(), slot.isStrictMode());
420     }
421
422     if (thisObject->isHostOrBuiltinFunction()) {
423         LazyPropertyType propType = thisObject->reifyBoundNameIfNeeded(vm, exec, propertyName);
424         if (propType == LazyPropertyType::IsLazyProperty)
425             slot.disableCaching();
426         scope.release();
427         return Base::put(thisObject, exec, propertyName, value, slot);
428     }
429
430     if (propertyName == vm.propertyNames->prototype) {
431         slot.disableCaching();
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 getSlot(thisObject, PropertySlot::InternalMethodType::VMInquiry);
435         thisObject->methodTable(vm)->getOwnPropertySlot(thisObject, exec, propertyName, getSlot);
436         if (thisObject->m_rareData)
437             thisObject->m_rareData->clear("Store to prototype property of a function");
438         scope.release();
439         return Base::put(thisObject, exec, propertyName, value, slot);
440     }
441
442     if (propertyName == vm.propertyNames->arguments || propertyName == vm.propertyNames->caller) {
443         slot.disableCaching();
444         if (!thisObject->jsExecutable()->hasCallerAndArgumentsProperties()) {
445             // This will trigger the property to be reified, if this is not already the case!
446             // FIXME: Investigate if the `hasProperty()` call is even needed, as in the `!hasCallerAndArgumentsProperties()` case,
447             // these properties are not lazy and should not need to be reified. (https://bugs.webkit.org/show_bug.cgi?id=163579)
448             bool okay = thisObject->hasProperty(exec, propertyName);
449             RETURN_IF_EXCEPTION(scope, false);
450             ASSERT_UNUSED(okay, okay);
451             scope.release();
452             return Base::put(thisObject, exec, propertyName, value, slot);
453         }
454         return typeError(exec, scope, slot.isStrictMode(), ASCIILiteral(ReadonlyPropertyWriteError));
455     }
456     LazyPropertyType propType = thisObject->reifyLazyPropertyIfNeeded(vm, exec, propertyName);
457     if (propType == LazyPropertyType::IsLazyProperty)
458         slot.disableCaching();
459     scope.release();
460     return Base::put(thisObject, exec, propertyName, value, slot);
461 }
462
463 bool JSFunction::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName)
464 {
465     JSFunction* thisObject = jsCast<JSFunction*>(cell);
466     if (thisObject->isHostOrBuiltinFunction())
467         thisObject->reifyBoundNameIfNeeded(exec->vm(), exec, propertyName);
468     else if (exec->vm().deletePropertyMode() != VM::DeletePropertyMode::IgnoreConfigurable) {
469         // For non-host functions, don't let these properties by deleted - except by DefineOwnProperty.
470         VM& vm = exec->vm();
471         FunctionExecutable* executable = thisObject->jsExecutable();
472         
473         if (propertyName == exec->propertyNames().caller || propertyName == exec->propertyNames().arguments)
474             return !executable->hasCallerAndArgumentsProperties();
475
476         if (propertyName == exec->propertyNames().prototype && !executable->isArrowFunction())
477             return false;
478
479         thisObject->reifyLazyPropertyIfNeeded(vm, exec, propertyName);
480     }
481     
482     return Base::deleteProperty(thisObject, exec, propertyName);
483 }
484
485 bool JSFunction::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName propertyName, const PropertyDescriptor& descriptor, bool throwException)
486 {
487     VM& vm = exec->vm();
488     auto scope = DECLARE_THROW_SCOPE(vm);
489
490     JSFunction* thisObject = jsCast<JSFunction*>(object);
491     if (thisObject->isHostOrBuiltinFunction()) {
492         thisObject->reifyBoundNameIfNeeded(vm, exec, propertyName);
493         scope.release();
494         return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException);
495     }
496
497     if (propertyName == vm.propertyNames->prototype) {
498         // Make sure prototype has been reified, such that it can only be overwritten
499         // following the rules set out in ECMA-262 8.12.9.
500         PropertySlot slot(thisObject, PropertySlot::InternalMethodType::VMInquiry);
501         thisObject->methodTable(vm)->getOwnPropertySlot(thisObject, exec, propertyName, slot);
502         if (thisObject->m_rareData)
503             thisObject->m_rareData->clear("Store to prototype property of a function");
504         scope.release();
505         return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException);
506     }
507
508     bool valueCheck;
509     if (propertyName == vm.propertyNames->arguments) {
510         if (!thisObject->jsExecutable()->hasCallerAndArgumentsProperties()) {
511             if (thisObject->jsExecutable()->isClass()) {
512                 thisObject->reifyLazyPropertyIfNeeded(vm, exec, propertyName);
513                 scope.release();
514                 return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException);
515             }
516             PropertySlot slot(thisObject, PropertySlot::InternalMethodType::VMInquiry);
517             if (!Base::getOwnPropertySlot(thisObject, exec, propertyName, slot))
518                 thisObject->putDirectAccessor(exec, propertyName, thisObject->globalObject(vm)->throwTypeErrorArgumentsCalleeAndCallerGetterSetter(), DontDelete | DontEnum | Accessor);
519             scope.release();
520             return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException);
521         }
522         valueCheck = !descriptor.value() || sameValue(exec, descriptor.value(), retrieveArguments(exec, thisObject));
523     } else if (propertyName == vm.propertyNames->caller) {
524         if (!thisObject->jsExecutable()->hasCallerAndArgumentsProperties()) {
525             if (thisObject->jsExecutable()->isClass()) {
526                 thisObject->reifyLazyPropertyIfNeeded(vm, exec, propertyName);
527                 scope.release();
528                 return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException);
529             }
530             PropertySlot slot(thisObject, PropertySlot::InternalMethodType::VMInquiry);
531             if (!Base::getOwnPropertySlot(thisObject, exec, propertyName, slot))
532                 thisObject->putDirectAccessor(exec, propertyName, thisObject->globalObject(vm)->throwTypeErrorArgumentsCalleeAndCallerGetterSetter(), DontDelete | DontEnum | Accessor);
533             scope.release();
534             return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException);
535         }
536         valueCheck = !descriptor.value() || sameValue(exec, descriptor.value(), retrieveCallerFunction(exec, thisObject));
537     } else {
538         thisObject->reifyLazyPropertyIfNeeded(vm, exec, propertyName);
539         scope.release();
540         return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException);
541     }
542      
543     if (descriptor.configurablePresent() && descriptor.configurable())
544         return typeError(exec, scope, throwException, ASCIILiteral(UnconfigurablePropertyChangeConfigurabilityError));
545     if (descriptor.enumerablePresent() && descriptor.enumerable())
546         return typeError(exec, scope, throwException, ASCIILiteral(UnconfigurablePropertyChangeEnumerabilityError));
547     if (descriptor.isAccessorDescriptor())
548         return typeError(exec, scope, throwException, ASCIILiteral(UnconfigurablePropertyChangeAccessMechanismError));
549     if (descriptor.writablePresent() && descriptor.writable())
550         return typeError(exec, scope, throwException, ASCIILiteral(UnconfigurablePropertyChangeWritabilityError));
551     if (!valueCheck)
552         return typeError(exec, scope, throwException, ASCIILiteral(ReadonlyPropertyChangeError));
553     return true;
554 }
555
556 // ECMA 13.2.2 [[Construct]]
557 ConstructType JSFunction::getConstructData(JSCell* cell, ConstructData& constructData)
558 {
559     JSFunction* thisObject = jsCast<JSFunction*>(cell);
560
561     if (thisObject->isHostFunction()) {
562         if (thisObject->nativeConstructor() == callHostFunctionAsConstructor)
563             return ConstructType::None;
564         constructData.native.function = thisObject->nativeConstructor();
565         return ConstructType::Host;
566     }
567
568     FunctionExecutable* functionExecutable = thisObject->jsExecutable();
569     if (functionExecutable->constructAbility() == ConstructAbility::CannotConstruct)
570         return ConstructType::None;
571
572     constructData.js.functionExecutable = functionExecutable;
573     constructData.js.scope = thisObject->scope();
574     return ConstructType::JS;
575 }
576
577 String getCalculatedDisplayName(VM& vm, JSObject* object)
578 {
579     if (JSFunction* function = jsDynamicCast<JSFunction*>(object))
580         return function->calculatedDisplayName(vm);
581     if (InternalFunction* function = jsDynamicCast<InternalFunction*>(object))
582         return function->calculatedDisplayName(vm);
583     return emptyString();
584 }
585
586 void JSFunction::setFunctionName(ExecState* exec, JSValue value)
587 {
588     VM& vm = exec->vm();
589     auto scope = DECLARE_THROW_SCOPE(vm);
590
591     // The "name" property may have been already been defined as part of a property list in an
592     // object literal (and therefore reified).
593     if (hasReifiedName())
594         return;
595
596     ASSERT(!isHostFunction());
597     ASSERT(jsExecutable()->ecmaName().isNull());
598     String name;
599     if (value.isSymbol()) {
600         SymbolImpl& uid = asSymbol(value)->privateName().uid();
601         if (uid.isNullSymbol())
602             name = emptyString();
603         else
604             name = makeString('[', String(&uid), ']');
605     } else {
606         JSString* jsStr = value.toString(exec);
607         RETURN_IF_EXCEPTION(scope, void());
608         name = jsStr->value(exec);
609         RETURN_IF_EXCEPTION(scope, void());
610     }
611     reifyName(vm, exec, name);
612 }
613
614 void JSFunction::reifyLength(VM& vm)
615 {
616     FunctionRareData* rareData = this->rareData(vm);
617
618     ASSERT(!hasReifiedLength());
619     ASSERT(!isHostFunction());
620     JSValue initialValue = jsNumber(jsExecutable()->functionLength());
621     unsigned initialAttributes = DontEnum | ReadOnly;
622     const Identifier& identifier = vm.propertyNames->length;
623     putDirect(vm, identifier, initialValue, initialAttributes);
624
625     rareData->setHasReifiedLength();
626 }
627
628 void JSFunction::reifyName(VM& vm, ExecState* exec)
629 {
630     const Identifier& ecmaName = jsExecutable()->ecmaName();
631     String name;
632     // https://tc39.github.io/ecma262/#sec-exports-runtime-semantics-evaluation
633     // When the ident is "*default*", we need to set "default" for the ecma name.
634     // This "*default*" name is never shown to users.
635     if (ecmaName == exec->propertyNames().builtinNames().starDefaultPrivateName())
636         name = exec->propertyNames().defaultKeyword.string();
637     else
638         name = ecmaName.string();
639     reifyName(vm, exec, name);
640 }
641
642 void JSFunction::reifyName(VM& vm, ExecState* exec, String name)
643 {
644     FunctionRareData* rareData = this->rareData(vm);
645
646     ASSERT(!hasReifiedName());
647     ASSERT(!isHostFunction());
648     unsigned initialAttributes = DontEnum | ReadOnly;
649     const Identifier& propID = vm.propertyNames->name;
650
651     if (exec->lexicalGlobalObject()->needsSiteSpecificQuirks()) {
652         auto illegalCharMatcher = [] (UChar ch) -> bool {
653             return ch == ' ' || ch == '|';
654         };
655         if (name.find(illegalCharMatcher) != notFound)
656             name = String();
657     }
658     
659     if (jsExecutable()->isGetter())
660         name = makeString("get ", name);
661     else if (jsExecutable()->isSetter())
662         name = makeString("set ", name);
663
664     putDirect(vm, propID, jsString(exec, name), initialAttributes);
665     rareData->setHasReifiedName();
666 }
667
668 JSFunction::LazyPropertyType JSFunction::reifyLazyPropertyIfNeeded(VM& vm, ExecState* exec, PropertyName propertyName)
669 {
670     if (propertyName == vm.propertyNames->length) {
671         if (!hasReifiedLength())
672             reifyLength(vm);
673         return LazyPropertyType::IsLazyProperty;
674     } else if (propertyName == vm.propertyNames->name) {
675         if (!hasReifiedName())
676             reifyName(vm, exec);
677         return LazyPropertyType::IsLazyProperty;
678     }
679     return LazyPropertyType::NotLazyProperty;
680 }
681
682 JSFunction::LazyPropertyType JSFunction::reifyBoundNameIfNeeded(VM& vm, ExecState* exec, PropertyName propertyName)
683 {
684     const Identifier& nameIdent = vm.propertyNames->name;
685     if (propertyName != nameIdent)
686         return LazyPropertyType::NotLazyProperty;
687
688     if (hasReifiedName())
689         return LazyPropertyType::IsLazyProperty;
690
691     if (this->inherits(JSBoundFunction::info())) {
692         FunctionRareData* rareData = this->rareData(vm);
693         String name = makeString("bound ", static_cast<NativeExecutable*>(m_executable.get())->name());
694         unsigned initialAttributes = DontEnum | ReadOnly;
695         putDirect(vm, nameIdent, jsString(exec, name), initialAttributes);
696         rareData->setHasReifiedName();
697     }
698     return LazyPropertyType::IsLazyProperty;
699 }
700
701 } // namespace JSC