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