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