diff --git a/Libraries/LibJS/Runtime/FunctionObject.cpp b/Libraries/LibJS/Runtime/FunctionObject.cpp index 73614f60e84..b563ded268f 100644 --- a/Libraries/LibJS/Runtime/FunctionObject.cpp +++ b/Libraries/LibJS/Runtime/FunctionObject.cpp @@ -24,14 +24,10 @@ FunctionObject::FunctionObject(Object& prototype, MayInterfereWithIndexedPropert } // 10.2.9 SetFunctionName ( F, name [ , prefix ] ), https://tc39.es/ecma262/#sec-setfunctionname -void FunctionObject::set_function_name(Variant const& name_arg, Optional const& prefix) +GC::Ref FunctionObject::make_function_name(Variant const& name_arg, Optional const& prefix) { auto& vm = this->vm(); - // 1. Assert: F is an extensible object that does not have a "name" own property. - VERIFY(m_is_extensible); - VERIFY(!storage_has(vm.names.name)); - String name; // 2. If Type(name) is Symbol, then @@ -74,8 +70,22 @@ void FunctionObject::set_function_name(Variant const& } } + return PrimitiveString::create(vm, move(name)); +} + +// 10.2.9 SetFunctionName ( F, name [ , prefix ] ), https://tc39.es/ecma262/#sec-setfunctionname +void FunctionObject::set_function_name(Variant const& name_arg, Optional const& prefix) +{ + auto& vm = this->vm(); + + // 1. Assert: F is an extensible object that does not have a "name" own property. + VERIFY(m_is_extensible); + VERIFY(!storage_has(vm.names.name)); + + auto name = make_function_name(name_arg, prefix); + // 6. Perform ! DefinePropertyOrThrow(F, "name", PropertyDescriptor { [[Value]]: name, [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }). - MUST(define_property_or_throw(vm.names.name, PropertyDescriptor { .value = PrimitiveString::create(vm, move(name)), .writable = false, .enumerable = false, .configurable = true })); + MUST(define_property_or_throw(vm.names.name, PropertyDescriptor { .value = name, .writable = false, .enumerable = false, .configurable = true })); // 7. Return unused. } diff --git a/Libraries/LibJS/Runtime/FunctionObject.h b/Libraries/LibJS/Runtime/FunctionObject.h index a482d85c7ac..6af855a0f30 100644 --- a/Libraries/LibJS/Runtime/FunctionObject.h +++ b/Libraries/LibJS/Runtime/FunctionObject.h @@ -46,6 +46,8 @@ protected: explicit FunctionObject(Realm&, Object* prototype, MayInterfereWithIndexedPropertyAccess = MayInterfereWithIndexedPropertyAccess::No); explicit FunctionObject(Object& prototype, MayInterfereWithIndexedPropertyAccess = MayInterfereWithIndexedPropertyAccess::No); + [[nodiscard]] GC::Ref make_function_name(Variant const&, Optional const& prefix); + private: virtual bool is_function() const override { return true; } }; diff --git a/Libraries/LibJS/Runtime/Intrinsics.cpp b/Libraries/LibJS/Runtime/Intrinsics.cpp index 50ea3cc782b..d0d4fd0e7e0 100644 --- a/Libraries/LibJS/Runtime/Intrinsics.cpp +++ b/Libraries/LibJS/Runtime/Intrinsics.cpp @@ -212,6 +212,13 @@ void Intrinsics::initialize_intrinsics(Realm& realm) m_normal_function_name_offset = m_normal_function_shape->lookup(vm.names.name.to_string_or_symbol()).value().offset; m_normal_function_prototype_offset = m_normal_function_shape->lookup(vm.names.prototype.to_string_or_symbol()).value().offset; + m_native_function_shape = heap().allocate(realm); + m_native_function_shape->set_prototype_without_transition(m_function_prototype); + m_native_function_shape->add_property_without_transition(vm.names.length, Attribute::Configurable); + m_native_function_shape->add_property_without_transition(vm.names.name, Attribute::Configurable); + m_native_function_length_offset = m_native_function_shape->lookup(vm.names.length.to_string_or_symbol()).value().offset; + m_native_function_name_offset = m_native_function_shape->lookup(vm.names.name.to_string_or_symbol()).value().offset; + // Normally Realm::create() takes care of this, but these are allocated via Heap::allocate(). m_function_prototype->initialize(realm); m_object_prototype->initialize(realm); @@ -382,6 +389,7 @@ void Intrinsics::visit_edges(Visitor& visitor) visitor.visit(m_iterator_result_object_shape); visitor.visit(m_normal_function_prototype_shape); visitor.visit(m_normal_function_shape); + visitor.visit(m_native_function_shape); visitor.visit(m_proxy_constructor); visitor.visit(m_async_from_sync_iterator_prototype); visitor.visit(m_async_generator_prototype); diff --git a/Libraries/LibJS/Runtime/Intrinsics.h b/Libraries/LibJS/Runtime/Intrinsics.h index a38f2894504..a6a945264d7 100644 --- a/Libraries/LibJS/Runtime/Intrinsics.h +++ b/Libraries/LibJS/Runtime/Intrinsics.h @@ -36,6 +36,10 @@ public: [[nodiscard]] u32 normal_function_name_offset() const { return m_normal_function_name_offset; } [[nodiscard]] u32 normal_function_prototype_offset() const { return m_normal_function_prototype_offset; } + [[nodiscard]] GC::Ref native_function_shape() { return *m_native_function_shape; } + [[nodiscard]] u32 native_function_length_offset() const { return m_native_function_length_offset; } + [[nodiscard]] u32 native_function_name_offset() const { return m_native_function_name_offset; } + // Not included in JS_ENUMERATE_NATIVE_OBJECTS due to missing distinct prototype GC::Ref proxy_constructor() { return *m_proxy_constructor; } @@ -149,6 +153,10 @@ private: u32 m_normal_function_name_offset { 0 }; u32 m_normal_function_prototype_offset { 0 }; + GC::Ptr m_native_function_shape; + u32 m_native_function_length_offset { 0 }; + u32 m_native_function_name_offset { 0 }; + // Not included in JS_ENUMERATE_NATIVE_OBJECTS due to missing distinct prototype GC::Ptr m_proxy_constructor; diff --git a/Libraries/LibJS/Runtime/NativeFunction.cpp b/Libraries/LibJS/Runtime/NativeFunction.cpp index b29d792b1e0..1f49345dd77 100644 --- a/Libraries/LibJS/Runtime/NativeFunction.cpp +++ b/Libraries/LibJS/Runtime/NativeFunction.cpp @@ -54,14 +54,16 @@ GC::Ref NativeFunction::create(Realm& allocating_realm, Function // 9. Set func.[[InitialName]] to null. auto function = allocating_realm.create(GC::create_function(vm.heap(), move(behaviour)), prototype, *realm.value()); + function->unsafe_set_shape(realm.value()->intrinsics().native_function_shape()); + // 10. Perform SetFunctionLength(func, length). - function->set_function_length(length); + function->put_direct(realm.value()->intrinsics().native_function_length_offset(), Value { length }); // 11. If prefix is not present, then // a. Perform SetFunctionName(func, name). // 12. Else, // a. Perform SetFunctionName(func, name, prefix). - function->set_function_name(name, prefix); + function->put_direct(realm.value()->intrinsics().native_function_name_offset(), function->make_function_name(name, prefix)); // 13. Return func. return function;