Skip to content

Commit a633a8a

Browse files
committed
[JSC] NativeExecutable should have name and length in the same way to FunctionExecutable
https://bugs.webkit.org/show_bug.cgi?id=316443 rdar://178844469 Reviewed by Justin Michaud and Yijia Huang. This is slight optimization for case doing `bind` with native functions, but largely a preparation for introducing optimization for patterns converting JS builtins to C++ native functions. Previously NativeExecutable was not holding length / name appropriately while FunctionExecutable was doing so. As a result, JSBoundFunction related optimization was skipping NativeExecutable cases. This becomes a problem when we convert JS builtin functions to Native version as bind starts going to the slow path. This patch alignes NativeExecutable's name and length handling much more to FunctionExecutable. * JSTests/stress/promise-resolving-functions-name-and-length.js: Added. (shouldBe): (new.Promise): (checkAnonymousBuiltin): (i.new.Promise): * Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp: (JSC::DFG::ConstantFoldingPhase::foldConstants): * Source/JavaScriptCore/jit/JITThunks.cpp: (JSC::JITThunks::WeakNativeExecutableHash::hash): (JSC::JITThunks::WeakNativeExecutableHash::equal): (JSC::JITThunks::finalize): (JSC::JITThunks::hostFunctionStub): * Source/JavaScriptCore/jit/JITThunks.h: * Source/JavaScriptCore/runtime/BooleanConstructor.cpp: (JSC::BooleanConstructor::finishCreation): (JSC::BooleanConstructor::create): * Source/JavaScriptCore/runtime/JSBoundFunction.cpp: (JSC::JSBoundFunction::canSkipNameAndLengthMaterialization): * Source/JavaScriptCore/runtime/JSCustomGetterFunction.cpp: (JSC::JSCustomGetterFunction::create): * Source/JavaScriptCore/runtime/JSCustomSetterFunction.cpp: (JSC::JSCustomSetterFunction::create): * Source/JavaScriptCore/runtime/JSFunction.cpp: (JSC::JSFunction::create): (JSC::JSFunction::reifyLazyPropertyIfNeeded): (JSC::JSFunction::reifyLazyPropertyForHostOrBuiltinIfNeeded): (JSC::JSFunction::reifyLazyBoundNameIfNeeded): (JSC::JSFunction::finishCreation): Deleted. * Source/JavaScriptCore/runtime/JSFunction.h: * Source/JavaScriptCore/runtime/JSFunctionInlines.h: (JSC::JSFunction::originalLength): (JSC::JSFunction::originalName): (JSC::JSFunction::canAssumeNameAndLengthAreOriginal): * Source/JavaScriptCore/runtime/JSFunctionWithFields.cpp: (JSC::JSFunctionWithFields::create): * Source/JavaScriptCore/runtime/JSFunctionWithFields.h: * Source/JavaScriptCore/runtime/JSNativeStdFunction.cpp: (JSC::JSNativeStdFunction::getHostFunction): (JSC::JSNativeStdFunction::create): (JSC::JSNativeStdFunction::finishCreation): Deleted. * Source/JavaScriptCore/runtime/JSNativeStdFunction.h: * Source/JavaScriptCore/runtime/JSPromise.cpp: (JSC::JSPromise::createFirstResolveFunction): (JSC::JSPromise::createFirstRejectFunction): * Source/JavaScriptCore/runtime/JSPromiseConstructor.cpp: (JSC::promiseAllSlow): (JSC::JSC_DEFINE_HOST_FUNCTION): (JSC::promiseAllSettledSlow): (JSC::promiseAnySlow): * Source/JavaScriptCore/runtime/JSPromisePrototype.cpp: (JSC::JSC_DEFINE_HOST_FUNCTION): (JSC::promiseProtoFuncFinallySlow): * Source/JavaScriptCore/runtime/NativeExecutable.cpp: (JSC::NativeExecutable::create): (JSC::NativeExecutable::finishCreation): (JSC::NativeExecutable::nameJSString const): * Source/JavaScriptCore/runtime/NativeExecutable.h: * Source/JavaScriptCore/runtime/NumberConstructor.cpp: (JSC::NumberConstructor::create): (JSC::NumberConstructor::finishCreation): * Source/JavaScriptCore/runtime/PinballCompletion.cpp: (JSC::createHandler): * Source/JavaScriptCore/runtime/StringConstructor.cpp: (JSC::StringConstructor::finishCreation): (JSC::StringConstructor::create): * Source/JavaScriptCore/runtime/VM.cpp: (JSC::VM::getHostFunction): (JSC::VM::getBoundFunction): (JSC::VM::getRemoteFunction): (JSC::VM::promiseResolvingFunctionResolveExecutableSlow): (JSC::VM::promiseResolvingFunctionRejectExecutableSlow): (JSC::VM::promiseFirstResolvingFunctionResolveExecutableSlow): (JSC::VM::promiseFirstResolvingFunctionRejectExecutableSlow): (JSC::VM::promiseResolvingFunctionResolveWithInternalMicrotaskExecutableSlow): (JSC::VM::promiseResolvingFunctionRejectWithInternalMicrotaskExecutableSlow): (JSC::VM::promiseCapabilityExecutorExecutableSlow): (JSC::VM::promiseAllFulfillFunctionExecutableSlow): (JSC::VM::promiseAllSlowFulfillFunctionExecutableSlow): (JSC::VM::promiseAllSettledFulfillFunctionExecutableSlow): (JSC::VM::promiseAllSettledRejectFunctionExecutableSlow): (JSC::VM::promiseAllSettledSlowFulfillFunctionExecutableSlow): (JSC::VM::promiseAllSettledSlowRejectFunctionExecutableSlow): (JSC::VM::promiseAnyRejectFunctionExecutableSlow): (JSC::VM::promiseAnySlowRejectFunctionExecutableSlow): * Source/JavaScriptCore/runtime/VM.h: * Source/JavaScriptCore/wasm/js/WebAssemblyFunction.cpp: (JSC::WebAssemblyFunction::create): * Source/JavaScriptCore/wasm/js/WebAssemblyFunctionBase.cpp: (JSC::WebAssemblyFunctionBase::finishCreation): Deleted. * Source/JavaScriptCore/wasm/js/WebAssemblyFunctionBase.h: * Source/JavaScriptCore/wasm/js/WebAssemblyPromising.cpp: (JSC::createWebAssemblyPromisingFunction): * Source/JavaScriptCore/wasm/js/WebAssemblySuspending.cpp: (JSC::createWebAssemblySuspendingFunction): * Source/JavaScriptCore/wasm/js/WebAssemblyWrapperFunction.cpp: (JSC::WebAssemblyWrapperFunction::create): Canonical link: https://commits.webkit.org/314682@main
1 parent ff49066 commit a633a8a

31 files changed

Lines changed: 266 additions & 180 deletions
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
// Regression test for https://bugs.webkit.org/show_bug.cgi?id=316443
2+
// NativeExecutable now holds name/length the same way FunctionExecutable does, and the
3+
// internal promise resolving / combinator / finally functions reify their "name" and "length"
4+
// from the NativeExecutable instead of receiving them eagerly at creation time. These functions
5+
// are spec-anonymous built-ins (CreateBuiltinFunction with name ""), so they must expose an
6+
// *own* "name" property whose value is "" (not undefined, not inherited from Function.prototype),
7+
// and an *own* "length" property. This locks that observable shape down.
8+
9+
function shouldBe(actual, expected) {
10+
if (actual !== expected)
11+
throw new Error(`FAIL: expected '${expected}' actual '${actual}'`);
12+
}
13+
14+
function checkAnonymousBuiltin(label, f, expectedLength) {
15+
shouldBe(typeof f, "function");
16+
17+
// "name" must be an own property (not merely inherited from Function.prototype.name === "").
18+
shouldBe(Object.prototype.hasOwnProperty.call(f, "name"), true);
19+
shouldBe(f.name, "");
20+
21+
let nameDesc = Object.getOwnPropertyDescriptor(f, "name");
22+
shouldBe(nameDesc.value, "");
23+
shouldBe(nameDesc.writable, false);
24+
shouldBe(nameDesc.enumerable, false);
25+
shouldBe(nameDesc.configurable, true);
26+
27+
// "length" must be an own property with the expected value.
28+
shouldBe(Object.prototype.hasOwnProperty.call(f, "length"), true);
29+
shouldBe(f.length, expectedLength);
30+
31+
let lengthDesc = Object.getOwnPropertyDescriptor(f, "length");
32+
shouldBe(lengthDesc.value, expectedLength);
33+
shouldBe(lengthDesc.writable, false);
34+
shouldBe(lengthDesc.enumerable, false);
35+
shouldBe(lengthDesc.configurable, true);
36+
37+
if (label) { /* keep label referenced for debugging */ }
38+
}
39+
40+
// Resolve / reject functions handed to a Promise executor (CreateResolvingFunctions).
41+
{
42+
let resolve, reject;
43+
new Promise(function (res, rej) {
44+
resolve = res;
45+
reject = rej;
46+
});
47+
checkAnonymousBuiltin("resolve", resolve, 1);
48+
checkAnonymousBuiltin("reject", reject, 1);
49+
}
50+
51+
// Promise.withResolvers exposes the same pair of functions.
52+
{
53+
let { resolve, reject } = Promise.withResolvers();
54+
checkAnonymousBuiltin("withResolvers.resolve", resolve, 1);
55+
checkAnonymousBuiltin("withResolvers.reject", reject, 1);
56+
}
57+
58+
// Reading "name" first, then "length" (and vice versa) must both reify correctly and independently.
59+
{
60+
let resolve, reject;
61+
new Promise(function (res, rej) { resolve = res; reject = rej; });
62+
// Force name reification before touching length.
63+
shouldBe(resolve.name, "");
64+
shouldBe(Object.prototype.hasOwnProperty.call(resolve, "length"), true);
65+
shouldBe(resolve.length, 1);
66+
67+
// Force length reification before touching name on the other function.
68+
shouldBe(reject.length, 1);
69+
shouldBe(Object.prototype.hasOwnProperty.call(reject, "name"), true);
70+
shouldBe(reject.name, "");
71+
}
72+
73+
// The "name" property is configurable, so user code may redefine it; doing so must not
74+
// corrupt the originally-observed value on a freshly created pair.
75+
{
76+
let resolve;
77+
new Promise(function (res) { resolve = res; });
78+
Object.defineProperty(resolve, "name", { value: "mutated", configurable: true });
79+
shouldBe(resolve.name, "mutated");
80+
81+
let resolve2;
82+
new Promise(function (res) { resolve2 = res; });
83+
checkAnonymousBuiltin("resolve2", resolve2, 1);
84+
}
85+
86+
// Run many times so the test covers all JIT tiers / repeated allocation paths.
87+
for (let i = 0; i < testLoopCount; ++i) {
88+
let resolve, reject;
89+
new Promise(function (res, rej) { resolve = res; reject = rej; });
90+
shouldBe(resolve.name, "");
91+
shouldBe(reject.name, "");
92+
shouldBe(resolve.length, 1);
93+
shouldBe(reject.length, 1);
94+
shouldBe(Object.prototype.hasOwnProperty.call(resolve, "name"), true);
95+
shouldBe(Object.prototype.hasOwnProperty.call(reject, "name"), true);
96+
}

Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1235,9 +1235,13 @@ class ConstantFoldingPhase : public Phase {
12351235
Edge target = m_graph.child(node, 0);
12361236
AbstractValue& targetValue = m_state.forNode(target);
12371237
auto& structureSet = targetValue.m_structure;
1238-
if (!(targetValue.m_type & ~SpecFunction) && structureSet.isFinite() && structureSet.size() == 1) {
1239-
RegisteredStructure structure = structureSet.onlyStructure();
1240-
if (JSBoundFunction::canSkipNameAndLengthMaterialization(globalObject, structure.get())) {
1238+
if (!(targetValue.m_type & ~SpecFunction) && structureSet.isFinite() && structureSet.size() >= 1) {
1239+
bool allCanSkip = true;
1240+
structureSet.forEach([&](RegisteredStructure structure) {
1241+
if (!JSBoundFunction::canSkipNameAndLengthMaterialization(globalObject, structure.get()))
1242+
allCanSkip = false;
1243+
});
1244+
if (allCanSkip) {
12411245
node->convertToNewBoundFunction(m_graph.freeze(m_graph.m_vm.getBoundFunction(/* isJSFunction */ true, SourceTaintedOrigin::Untainted)));
12421246
changed = true;
12431247
break;

Source/JavaScriptCore/jit/JITThunks.cpp

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ static inline NativeExecutable& NODELETE getMayBeDyingNativeExecutable(const Wea
7474

7575
inline unsigned JITThunks::WeakNativeExecutableHash::hash(const NativeExecutable* executable)
7676
{
77-
return hash(executable->function(), executable->constructor(), executable->implementationVisibility(), executable->name());
77+
return hash(executable->function(), executable->constructor(), executable->implementationVisibility(), executable->length(), executable->name());
7878
}
7979

8080
inline unsigned JITThunks::WeakNativeExecutableHash::hash(const Weak<NativeExecutable>& key)
@@ -86,7 +86,7 @@ inline bool JITThunks::WeakNativeExecutableHash::equal(const NativeExecutable& a
8686
{
8787
if (&a == &b)
8888
return true;
89-
return a.function() == b.function() && a.constructor() == b.constructor() && a.implementationVisibility() == b.implementationVisibility() && a.name() == b.name();
89+
return a.function() == b.function() && a.constructor() == b.constructor() && a.implementationVisibility() == b.implementationVisibility() && a.length() == b.length() && a.name() == b.name();
9090
}
9191

9292
inline bool JITThunks::WeakNativeExecutableHash::equal(const Weak<NativeExecutable>& a, const Weak<NativeExecutable>& b)
@@ -102,7 +102,7 @@ inline bool JITThunks::WeakNativeExecutableHash::equal(const Weak<NativeExecutab
102102
inline bool JITThunks::WeakNativeExecutableHash::equal(const Weak<NativeExecutable>& a, const HostFunctionKey& b)
103103
{
104104
auto& aExecutable = getMayBeDyingNativeExecutable(a);
105-
return aExecutable.function() == std::get<0>(b) && aExecutable.constructor() == std::get<1>(b) && aExecutable.implementationVisibility() == std::get<2>(b) && aExecutable.name() == std::get<3>(b);
105+
return aExecutable.function() == std::get<0>(b) && aExecutable.constructor() == std::get<1>(b) && aExecutable.implementationVisibility() == std::get<2>(b) && aExecutable.length() == std::get<3>(b) && aExecutable.name() == std::get<4>(b);
106106
}
107107

108108
CodePtr<JITThunkPtrTag> JITThunks::ctiNativeCall(VM&)
@@ -227,7 +227,7 @@ struct JITThunks::NativeExecutableTranslator {
227227
void JITThunks::finalize(Handle<Unknown> handle, void*)
228228
{
229229
auto* nativeExecutable = static_cast<NativeExecutable*>(handle.get().asCell());
230-
auto hostFunctionKey = std::make_tuple(nativeExecutable->function(), nativeExecutable->constructor(), nativeExecutable->implementationVisibility(), nativeExecutable->name());
230+
auto hostFunctionKey = std::make_tuple(nativeExecutable->function(), nativeExecutable->constructor(), nativeExecutable->implementationVisibility(), nativeExecutable->length(), nativeExecutable->name());
231231
{
232232
AssertNoGC assertNoGC;
233233
auto iterator = m_nativeExecutableSet.find<HostKeySearcher>(hostFunctionKey);
@@ -238,17 +238,17 @@ void JITThunks::finalize(Handle<Unknown> handle, void*)
238238
}
239239
}
240240

241-
NativeExecutable* JITThunks::hostFunctionStub(VM& vm, TaggedNativeFunction function, TaggedNativeFunction constructor, ImplementationVisibility implementationVisibility, const String& name)
241+
NativeExecutable* JITThunks::hostFunctionStub(VM& vm, TaggedNativeFunction function, TaggedNativeFunction constructor, ImplementationVisibility implementationVisibility, unsigned length, const String& name)
242242
{
243-
return hostFunctionStub(vm, function, constructor, nullptr, implementationVisibility, NoIntrinsic, nullptr, name);
243+
return hostFunctionStub(vm, function, constructor, nullptr, implementationVisibility, NoIntrinsic, nullptr, length, name);
244244
}
245245

246-
NativeExecutable* JITThunks::hostFunctionStub(VM& vm, TaggedNativeFunction function, TaggedNativeFunction constructor, ThunkGenerator generator, ImplementationVisibility implementationVisibility, Intrinsic intrinsic, const DOMJIT::Signature* signature, const String& name)
246+
NativeExecutable* JITThunks::hostFunctionStub(VM& vm, TaggedNativeFunction function, TaggedNativeFunction constructor, ThunkGenerator generator, ImplementationVisibility implementationVisibility, Intrinsic intrinsic, const DOMJIT::Signature* signature, unsigned length, const String& name)
247247
{
248-
ASSERT(!isCompilationThread());
248+
ASSERT(!isCompilationThread());
249249
ASSERT(Options::useJIT());
250250

251-
auto hostFunctionKey = std::make_tuple(function, constructor, implementationVisibility, name);
251+
auto hostFunctionKey = std::make_tuple(function, constructor, implementationVisibility, length, name);
252252
{
253253
AssertNoGC assertNoGC;
254254
auto iterator = m_nativeExecutableSet.find<HostKeySearcher>(hostFunctionKey);
@@ -268,10 +268,10 @@ NativeExecutable* JITThunks::hostFunctionStub(VM& vm, TaggedNativeFunction funct
268268
forCall = adoptRef(new NativeDOMJITCode(MacroAssemblerCodeRef<JSEntryPtrTag>::createSelfManagedCodeRef(ctiNativeCall(vm).retagged<JSEntryPtrTag>()), JITType::HostCallThunk, intrinsic, signature));
269269
else
270270
forCall = adoptRef(new NativeJITCode(MacroAssemblerCodeRef<JSEntryPtrTag>::createSelfManagedCodeRef(ctiNativeCall(vm).retagged<JSEntryPtrTag>()), JITType::HostCallThunk, intrinsic));
271-
271+
272272
Ref<JSC::JITCode> forConstruct = adoptRef(*new NativeJITCode(MacroAssemblerCodeRef<JSEntryPtrTag>::createSelfManagedCodeRef(ctiNativeConstruct(vm).retagged<JSEntryPtrTag>()), JITType::HostCallThunk, NoIntrinsic));
273-
274-
NativeExecutable* nativeExecutable = NativeExecutable::create(vm, forCall.releaseNonNull(), function, WTF::move(forConstruct), constructor, implementationVisibility, name);
273+
274+
NativeExecutable* nativeExecutable = NativeExecutable::create(vm, forCall.releaseNonNull(), function, WTF::move(forConstruct), constructor, implementationVisibility, length, name);
275275
{
276276
AssertNoGC assertNoGC;
277277
auto addResult = m_nativeExecutableSet.add<NativeExecutableTranslator>(nativeExecutable);
@@ -291,9 +291,9 @@ NativeExecutable* JITThunks::hostFunctionStub(VM& vm, TaggedNativeFunction funct
291291
return nativeExecutable;
292292
}
293293

294-
NativeExecutable* JITThunks::hostFunctionStub(VM& vm, TaggedNativeFunction function, ThunkGenerator generator, ImplementationVisibility implementationVisibility, Intrinsic intrinsic, const String& name)
294+
NativeExecutable* JITThunks::hostFunctionStub(VM& vm, TaggedNativeFunction function, ThunkGenerator generator, ImplementationVisibility implementationVisibility, Intrinsic intrinsic, unsigned length, const String& name)
295295
{
296-
return hostFunctionStub(vm, function, callHostFunctionAsConstructor, generator, implementationVisibility, intrinsic, nullptr, name);
296+
return hostFunctionStub(vm, function, callHostFunctionAsConstructor, generator, implementationVisibility, intrinsic, nullptr, length, name);
297297
}
298298

299299
} // namespace JSC

Source/JavaScriptCore/jit/JITThunks.h

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -203,9 +203,9 @@ class JITThunks final : private WeakHandleOwner {
203203
MacroAssemblerCodeRef<JITThunkPtrTag> ctiStub(VM&, ThunkGenerator);
204204
MacroAssemblerCodeRef<JITThunkPtrTag> ctiSlowPathFunctionStub(VM&, SlowPathFunction);
205205

206-
NativeExecutable* hostFunctionStub(VM&, TaggedNativeFunction, TaggedNativeFunction constructor, ImplementationVisibility, const String& name);
207-
NativeExecutable* hostFunctionStub(VM&, TaggedNativeFunction, TaggedNativeFunction constructor, ThunkGenerator, ImplementationVisibility, Intrinsic, const DOMJIT::Signature*, const String& name);
208-
NativeExecutable* hostFunctionStub(VM&, TaggedNativeFunction, ThunkGenerator, ImplementationVisibility, Intrinsic, const String& name);
206+
NativeExecutable* hostFunctionStub(VM&, TaggedNativeFunction, TaggedNativeFunction constructor, ImplementationVisibility, unsigned length, const String& name);
207+
NativeExecutable* hostFunctionStub(VM&, TaggedNativeFunction, TaggedNativeFunction constructor, ThunkGenerator, ImplementationVisibility, Intrinsic, const DOMJIT::Signature*, unsigned length, const String& name);
208+
NativeExecutable* hostFunctionStub(VM&, TaggedNativeFunction, ThunkGenerator, ImplementationVisibility, Intrinsic, unsigned length, const String& name);
209209

210210
void initialize(VM&);
211211

@@ -221,14 +221,14 @@ class JITThunks final : private WeakHandleOwner {
221221
};
222222
using CTIStubMap = UncheckedKeyHashMap<ThunkGenerator, Entry>;
223223

224-
using HostFunctionKey = std::tuple<TaggedNativeFunction, TaggedNativeFunction, ImplementationVisibility, String>;
224+
using HostFunctionKey = std::tuple<TaggedNativeFunction, TaggedNativeFunction, ImplementationVisibility, unsigned, String>;
225225

226226
struct WeakNativeExecutableHash {
227227
static inline unsigned NODELETE hash(const Weak<NativeExecutable>&);
228228
static inline unsigned hash(const NativeExecutable*);
229229
static unsigned hash(const HostFunctionKey& key)
230230
{
231-
return hash(std::get<0>(key), std::get<1>(key), std::get<2>(key), std::get<3>(key));
231+
return hash(std::get<0>(key), std::get<1>(key), std::get<2>(key), std::get<3>(key), std::get<4>(key));
232232
}
233233

234234
static inline bool NODELETE equal(const Weak<NativeExecutable>&, const Weak<NativeExecutable>&);
@@ -238,12 +238,13 @@ class JITThunks final : private WeakHandleOwner {
238238
static constexpr bool safeToCompareToEmptyOrDeleted = false;
239239

240240
private:
241-
static unsigned hash(TaggedNativeFunction function, TaggedNativeFunction constructor, ImplementationVisibility implementationVisibility, const String& name)
241+
static unsigned hash(TaggedNativeFunction function, TaggedNativeFunction constructor, ImplementationVisibility implementationVisibility, unsigned length, const String& name)
242242
{
243243
Hasher hasher;
244244
WTF::add(hasher, function);
245245
WTF::add(hasher, constructor);
246246
WTF::add(hasher, implementationVisibility);
247+
WTF::add(hasher, length);
247248
if (!name.isNull())
248249
WTF::add(hasher, name);
249250
return hasher.hash();

Source/JavaScriptCore/runtime/BooleanConstructor.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,14 +64,12 @@ void BooleanConstructor::finishCreation(VM& vm, BooleanPrototype* booleanPrototy
6464
{
6565
Base::finishCreation(vm);
6666
putDirectWithoutTransition(vm, vm.propertyNames->prototype, booleanPrototype, PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum | PropertyAttribute::DontDelete);
67-
putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(1), PropertyAttribute::DontEnum | PropertyAttribute::ReadOnly);
68-
putDirectWithoutTransition(vm, vm.propertyNames->name, jsString(vm, vm.propertyNames->Boolean.string()), PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum);
6967
}
7068

7169
BooleanConstructor* BooleanConstructor::create(VM& vm, Structure* structure, BooleanPrototype* booleanPrototype)
7270
{
7371
JSGlobalObject* globalObject = structure->realm();
74-
NativeExecutable* executable = vm.getHostFunction(callBooleanConstructor, ImplementationVisibility::Public, BooleanConstructorIntrinsic, constructWithBooleanConstructor, nullptr, vm.propertyNames->Boolean.string());
72+
NativeExecutable* executable = vm.getHostFunction(callBooleanConstructor, ImplementationVisibility::Public, BooleanConstructorIntrinsic, constructWithBooleanConstructor, nullptr, 1, vm.propertyNames->Boolean.string());
7573
BooleanConstructor* constructor = new (NotNull, allocateCell<BooleanConstructor>(vm)) BooleanConstructor(vm, executable, globalObject, structure);
7674
constructor->finishCreation(vm, booleanPrototype);
7775
return constructor;

Source/JavaScriptCore/runtime/JSBoundFunction.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,11 @@ bool JSBoundFunction::canSkipNameAndLengthMaterialization(JSGlobalObject* global
406406
return true;
407407
if (structure == globalObject->sloppyFunctionStructure(true) || structure == globalObject->sloppyFunctionStructure(false))
408408
return true;
409+
// Plain host functions now use the lazy reify path for length/name (mirroring JS function and
410+
// builtin behavior), so an untransitioned hostFunctionStructure means length/name are still
411+
// recoverable from NativeExecutable via originalLength()/originalName().
412+
if (structure == globalObject->hostFunctionStructure())
413+
return true;
409414

410415
return false;
411416
}

Source/JavaScriptCore/runtime/JSCustomGetterFunction.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,16 @@ JSCustomGetterFunction::JSCustomGetterFunction(VM& vm, NativeExecutable* executa
6363
JSCustomGetterFunction* JSCustomGetterFunction::create(VM& vm, JSGlobalObject* globalObject, const PropertyName& propertyName, CustomFunctionPointer getter, std::optional<DOMAttributeAnnotation> domAttribute)
6464
{
6565
ASSERT(getter);
66-
NativeExecutable* executable = vm.getHostFunction(customGetterFunctionCall, ImplementationVisibility::Public, callHostFunctionAsConstructor, String(propertyName.publicName()));
66+
NativeExecutable* executable = vm.getHostFunction(customGetterFunctionCall, ImplementationVisibility::Public, callHostFunctionAsConstructor, 0, String(propertyName.publicName()));
6767
Structure* structure = globalObject->customGetterFunctionStructure();
6868
JSCustomGetterFunction* function = new (NotNull, allocateCell<JSCustomGetterFunction>(vm)) JSCustomGetterFunction(vm, executable, globalObject, structure, propertyName, getter, domAttribute);
69-
70-
// Can't do this during initialization because getHostFunction might do a GC allocation.
69+
function->finishCreation(vm);
70+
// ECMAScript-style "get foo" name is exposed via the JSFunction's `name` property; keep the
71+
// raw NativeExecutable name unprefixed so toString() renders as `function foo() { [native code] }`.
7172
auto name = makeString("get "_s, propertyName.publicName());
72-
function->finishCreation(vm, executable, 0, name);
73+
FunctionRareData* rareData = function->ensureRareData(vm);
74+
rareData->setHasReifiedName();
75+
function->putDirect(vm, vm.propertyNames->name, jsString(vm, WTF::move(name)), PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum);
7376
return function;
7477
}
7578

Source/JavaScriptCore/runtime/JSCustomSetterFunction.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,16 @@ JSCustomSetterFunction::JSCustomSetterFunction(VM& vm, NativeExecutable* executa
5353
JSCustomSetterFunction* JSCustomSetterFunction::create(VM& vm, JSGlobalObject* globalObject, const PropertyName& propertyName, CustomFunctionPointer setter)
5454
{
5555
ASSERT(setter);
56-
NativeExecutable* executable = vm.getHostFunction(customSetterFunctionCall, ImplementationVisibility::Public, callHostFunctionAsConstructor, String(propertyName.publicName()));
56+
NativeExecutable* executable = vm.getHostFunction(customSetterFunctionCall, ImplementationVisibility::Public, callHostFunctionAsConstructor, 1, String(propertyName.publicName()));
5757
Structure* structure = globalObject->customSetterFunctionStructure();
5858
JSCustomSetterFunction* function = new (NotNull, allocateCell<JSCustomSetterFunction>(vm)) JSCustomSetterFunction(vm, executable, globalObject, structure, propertyName, setter);
59-
60-
// Can't do this during initialization because getHostFunction might do a GC allocation.
59+
function->finishCreation(vm);
60+
// ECMAScript-style "set foo" name is exposed via the JSFunction's `name` property; keep the
61+
// raw NativeExecutable name unprefixed so toString() renders as `function foo() { [native code] }`.
6162
auto name = makeString("set "_s, propertyName.publicName());
62-
function->finishCreation(vm, executable, 1, name);
63+
FunctionRareData* rareData = function->ensureRareData(vm);
64+
rareData->setHasReifiedName();
65+
function->putDirect(vm, vm.propertyNames->name, jsString(vm, WTF::move(name)), PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum);
6366
return function;
6467
}
6568

0 commit comments

Comments
 (0)