diff --git a/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp b/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp index ba2bd28ceaf..b7f6bf79140 100644 --- a/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp +++ b/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp @@ -354,8 +354,8 @@ void ECMAScriptFunctionObject::initialize(Realm& realm) Object* prototype = nullptr; switch (m_kind) { case FunctionKind::Normal: - prototype = Object::create_prototype(realm, realm.intrinsics().object_prototype()); - MUST(prototype->define_property_or_throw(vm.names.constructor, { .value = this, .writable = true, .enumerable = false, .configurable = true })); + prototype = Object::create_with_premade_shape(realm.intrinsics().normal_function_prototype_shape()); + prototype->put_direct(realm.intrinsics().normal_function_prototype_constructor_offset(), this); break; case FunctionKind::Generator: // prototype is "g1.prototype" in figure-2 (https://tc39.es/ecma262/img/figure-2.png) diff --git a/Libraries/LibJS/Runtime/Intrinsics.cpp b/Libraries/LibJS/Runtime/Intrinsics.cpp index 244a527f7af..c4d6de09429 100644 --- a/Libraries/LibJS/Runtime/Intrinsics.cpp +++ b/Libraries/LibJS/Runtime/Intrinsics.cpp @@ -198,6 +198,11 @@ void Intrinsics::initialize_intrinsics(Realm& realm) m_iterator_result_object_value_offset = m_iterator_result_object_shape->lookup(vm.names.value.to_string_or_symbol()).value().offset; m_iterator_result_object_done_offset = m_iterator_result_object_shape->lookup(vm.names.done.to_string_or_symbol()).value().offset; + m_normal_function_prototype_shape = heap().allocate(realm); + m_normal_function_prototype_shape->set_prototype_without_transition(m_object_prototype); + m_normal_function_prototype_shape->add_property_without_transition(vm.names.constructor, Attribute::Writable | Attribute::Configurable); + m_normal_function_prototype_constructor_offset = m_normal_function_prototype_shape->lookup(vm.names.constructor.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); @@ -366,6 +371,7 @@ void Intrinsics::visit_edges(Visitor& visitor) visitor.visit(m_empty_object_shape); visitor.visit(m_new_object_shape); visitor.visit(m_iterator_result_object_shape); + visitor.visit(m_normal_function_prototype_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 724c0ed97ea..cc10f933493 100644 --- a/Libraries/LibJS/Runtime/Intrinsics.h +++ b/Libraries/LibJS/Runtime/Intrinsics.h @@ -28,6 +28,9 @@ public: [[nodiscard]] u32 iterator_result_object_value_offset() { return m_iterator_result_object_value_offset; } [[nodiscard]] u32 iterator_result_object_done_offset() { return m_iterator_result_object_done_offset; } + [[nodiscard]] GC::Ref normal_function_prototype_shape() { return *m_normal_function_prototype_shape; } + [[nodiscard]] u32 normal_function_prototype_constructor_offset() const { return m_normal_function_prototype_constructor_offset; } + // Not included in JS_ENUMERATE_NATIVE_OBJECTS due to missing distinct prototype GC::Ref proxy_constructor() { return *m_proxy_constructor; } @@ -133,6 +136,9 @@ private: u32 m_iterator_result_object_value_offset { 0 }; u32 m_iterator_result_object_done_offset { 0 }; + GC::Ptr m_normal_function_prototype_shape; + u32 m_normal_function_prototype_constructor_offset { 0 }; + // Not included in JS_ENUMERATE_NATIVE_OBJECTS due to missing distinct prototype GC::Ptr m_proxy_constructor;