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