diff --git a/Userland/Libraries/LibJS/AST.cpp b/Userland/Libraries/LibJS/AST.cpp index fec35d2b63..96302be146 100644 --- a/Userland/Libraries/LibJS/AST.cpp +++ b/Userland/Libraries/LibJS/AST.cpp @@ -886,7 +886,7 @@ Value ClassExpression::execute(Interpreter& interpreter, GlobalObject& global_ob interpreter.vm().throw_exception(global_object, ErrorType::ClassExtendsValueNotAConstructorOrNull, super_constructor.to_string_without_side_effects()); return {}; } - class_constructor->set_constructor_kind(FunctionObject::ConstructorKind::Derived); + class_constructor->set_constructor_kind(ECMAScriptFunctionObject::ConstructorKind::Derived); Object* super_constructor_prototype = nullptr; if (!super_constructor.is_null()) { diff --git a/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.h b/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.h index b863ed8de5..eb2abd32c3 100644 --- a/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.h +++ b/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.h @@ -17,6 +17,11 @@ class ECMAScriptFunctionObject final : public FunctionObject { JS_OBJECT(ECMAScriptFunctionObject, FunctionObject); public: + enum class ConstructorKind : u8 { + Base, + Derived, + }; + enum class ThisMode : u8 { Lexical, Strict, @@ -45,6 +50,9 @@ public: virtual Environment* environment() override { return m_environment; } virtual Realm* realm() const override { return m_realm; } + ConstructorKind constructor_kind() const { return m_constructor_kind; }; + void set_constructor_kind(ConstructorKind constructor_kind) { m_constructor_kind = constructor_kind; } + ThisMode this_mode() const { return m_this_mode; } protected: @@ -58,13 +66,14 @@ private: Value execute_function_body(); // Internal Slots of ECMAScript Function Objects, https://tc39.es/ecma262/#table-internal-slots-of-ecmascript-function-objects - Environment* m_environment { nullptr }; // [[Environment]] - Vector const m_formal_parameters; // [[FormalParameters]] - NonnullRefPtr m_ecmascript_code; // [[ECMAScriptCode]] - Realm* m_realm { nullptr }; // [[Realm]] - ThisMode m_this_mode { ThisMode::Global }; // [[ThisMode]] - bool m_strict { false }; // [[Strict]] - bool m_is_class_constructor { false }; // [[IsClassConstructor]] + Environment* m_environment { nullptr }; // [[Environment]] + Vector const m_formal_parameters; // [[FormalParameters]] + NonnullRefPtr m_ecmascript_code; // [[ECMAScriptCode]] + ConstructorKind m_constructor_kind { ConstructorKind::Base }; // [[ConstructorKind]] + Realm* m_realm { nullptr }; // [[Realm]] + ThisMode m_this_mode { ThisMode::Global }; // [[ThisMode]] + bool m_strict { false }; // [[Strict]] + bool m_is_class_constructor { false }; // [[IsClassConstructor]] FlyString m_name; Optional m_bytecode_executable; diff --git a/Userland/Libraries/LibJS/Runtime/FunctionObject.h b/Userland/Libraries/LibJS/Runtime/FunctionObject.h index a3bf54b316..5e2cb779e1 100644 --- a/Userland/Libraries/LibJS/Runtime/FunctionObject.h +++ b/Userland/Libraries/LibJS/Runtime/FunctionObject.h @@ -15,11 +15,6 @@ class FunctionObject : public Object { JS_OBJECT(Function, Object); public: - enum class ConstructorKind { - Base, - Derived, - }; - virtual ~FunctionObject(); virtual void initialize(GlobalObject&) override { } @@ -37,9 +32,6 @@ public: Object* home_object() const { return m_home_object; } void set_home_object(Object* home_object) { m_home_object = home_object; } - ConstructorKind constructor_kind() const { return m_constructor_kind; }; - void set_constructor_kind(ConstructorKind constructor_kind) { m_constructor_kind = constructor_kind; } - virtual bool is_strict_mode() const { return false; } // [[Environment]] @@ -77,7 +69,6 @@ private: Value m_bound_this; Vector m_bound_arguments; Object* m_home_object { nullptr }; - ConstructorKind m_constructor_kind = ConstructorKind::Base; bool m_has_simple_parameter_list { false }; Vector m_fields; }; diff --git a/Userland/Libraries/LibJS/Runtime/VM.cpp b/Userland/Libraries/LibJS/Runtime/VM.cpp index aaca0f127b..17fe692db6 100644 --- a/Userland/Libraries/LibJS/Runtime/VM.cpp +++ b/Userland/Libraries/LibJS/Runtime/VM.cpp @@ -470,12 +470,14 @@ void VM::initialize_instance_elements(Object& object, FunctionObject& constructo } } +// FIXME: This function should not exist as-is, most of it should be moved to the individual +// [[Construct]] implementations so that this becomes the Construct() AO (3 steps). Value VM::construct(FunctionObject& function, FunctionObject& new_target, Optional arguments) { auto& global_object = function.global_object(); Value this_argument; - if (function.constructor_kind() == FunctionObject::ConstructorKind::Base) + if (!is(function) || static_cast(function).constructor_kind() == ECMAScriptFunctionObject::ConstructorKind::Base) this_argument = TRY_OR_DISCARD(ordinary_create_from_constructor(global_object, new_target, &GlobalObject::object_prototype)); // FIXME: prepare_for_ordinary_call() is not supposed to receive a BoundFunction, ProxyObject, etc. - ever. @@ -507,7 +509,7 @@ Value VM::construct(FunctionObject& function, FunctionObject& new_target, Option // If we are a Derived constructor, |this| has not been constructed before super is called. callee_context.this_value = this_argument; - if (function.constructor_kind() == FunctionObject::ConstructorKind::Base) { + if (!is(function) || static_cast(function).constructor_kind() == ECMAScriptFunctionObject::ConstructorKind::Base) { VERIFY(this_argument.is_object()); initialize_instance_elements(this_argument.as_object(), function); if (exception()) @@ -521,7 +523,10 @@ Value VM::construct(FunctionObject& function, FunctionObject& new_target, Option // If we are constructing an instance of a derived class, // set the prototype on objects created by constructors that return an object (i.e. NativeFunction subclasses). - if (function.constructor_kind() == FunctionObject::ConstructorKind::Base && new_target.constructor_kind() == FunctionObject::ConstructorKind::Derived && result.is_object()) { + + if ((!is(function) || static_cast(function).constructor_kind() == ECMAScriptFunctionObject::ConstructorKind::Base) + && is(new_target) && static_cast(new_target).constructor_kind() == ECMAScriptFunctionObject::ConstructorKind::Derived + && result.is_object()) { if (auto* environment = callee_context.lexical_environment) verify_cast(environment)->replace_this_binding(result); auto prototype = new_target.get(names.prototype);