Parcourir la source

LibJS: Let Shape store a Realm instead of a GlobalObject

This is a cautious first step towards being able to create JS objects
before a global object has been instantiated.
Andreas Kling il y a 3 ans
Parent
commit
50d951aea2

+ 3 - 2
Meta/Lagom/Fuzzers/FuzzilliJs.cpp

@@ -119,7 +119,7 @@ class TestRunnerGlobalObject final : public JS::GlobalObject {
     JS_OBJECT(TestRunnerGlobalObject, JS::GlobalObject);
 
 public:
-    TestRunnerGlobalObject();
+    TestRunnerGlobalObject(JS::Realm&);
     virtual ~TestRunnerGlobalObject() override;
 
     virtual void initialize_global_object() override;
@@ -128,7 +128,8 @@ private:
     JS_DECLARE_NATIVE_FUNCTION(fuzzilli);
 };
 
-TestRunnerGlobalObject::TestRunnerGlobalObject()
+TestRunnerGlobalObject::TestRunnerGlobalObject(JS::Realm& realm)
+    : GlobalObject(realm)
 {
 }
 

+ 3 - 2
Userland/Applications/Spreadsheet/JSIntegration.cpp

@@ -92,8 +92,9 @@ Optional<FunctionAndArgumentIndex> get_function_and_argument_index(StringView so
     return {};
 }
 
-SheetGlobalObject::SheetGlobalObject(Sheet& sheet)
-    : m_sheet(sheet)
+SheetGlobalObject::SheetGlobalObject(JS::Realm& realm, Sheet& sheet)
+    : JS::GlobalObject(realm)
+    , m_sheet(sheet)
 {
 }
 

+ 1 - 1
Userland/Applications/Spreadsheet/JSIntegration.h

@@ -23,7 +23,7 @@ class SheetGlobalObject final : public JS::GlobalObject {
     JS_OBJECT(SheetGlobalObject, JS::GlobalObject);
 
 public:
-    SheetGlobalObject(Sheet&);
+    SheetGlobalObject(JS::Realm&, Sheet&);
 
     virtual ~SheetGlobalObject() override = default;
 

+ 2 - 1
Userland/Libraries/LibJS/Contrib/Test262/$262Object.cpp

@@ -57,7 +57,8 @@ JS_DEFINE_NATIVE_FUNCTION($262Object::clear_kept_objects)
 
 JS_DEFINE_NATIVE_FUNCTION($262Object::create_realm)
 {
-    auto realm = vm.heap().allocate_without_global_object<GlobalObject>();
+    // FIXME: This doesn't look right.
+    auto realm = vm.heap().allocate_without_global_object<GlobalObject>(*global_object.associated_realm());
     realm->initialize_global_object();
     return Value(realm->$262());
 }

+ 4 - 1
Userland/Libraries/LibJS/Contrib/Test262/GlobalObject.h

@@ -15,7 +15,10 @@ class GlobalObject final : public JS::GlobalObject {
     JS_OBJECT(GlobalObject, JS::GlobalObject);
 
 public:
-    GlobalObject() = default;
+    GlobalObject(JS::Realm& realm)
+        : JS::GlobalObject(realm)
+    {
+    }
     virtual void initialize_global_object() override;
     virtual ~GlobalObject() override = default;
 

+ 2 - 2
Userland/Libraries/LibJS/Interpreter.h

@@ -64,7 +64,7 @@ public:
 
         // 7. If the host requires use of an exotic object to serve as realm's global object, let global be such an object created in a host-defined manner.
         //    Otherwise, let global be undefined, indicating that an ordinary object should be created as the global object.
-        auto* global_object = static_cast<GlobalObject*>(interpreter->heap().allocate_without_global_object<GlobalObjectType>(forward<Args>(args)...));
+        auto* global_object = static_cast<GlobalObject*>(interpreter->heap().allocate_without_global_object<GlobalObjectType>(*realm, forward<Args>(args)...));
 
         // 8. If the host requires that the this binding in realm's global scope return an object other than the global object, let thisValue be such an object created
         //    in a host-defined manner. Otherwise, let thisValue be undefined, indicating that realm's global this binding should be the global object.
@@ -73,7 +73,7 @@ public:
             this_value = global_object;
         } else {
             // FIXME: Should we pass args in here? Let's er on the side of caution and say yes.
-            this_value = static_cast<Object*>(interpreter->heap().allocate_without_global_object<GlobalThisObjectType>(forward<Args>(args)...));
+            this_value = static_cast<Object*>(interpreter->heap().allocate_without_global_object<GlobalThisObjectType>(*realm, forward<Args>(args)...));
         }
 
         // 9. Perform SetRealmGlobalObject(realm, global, thisValue).

+ 9 - 6
Userland/Libraries/LibJS/Runtime/GlobalObject.cpp

@@ -139,8 +139,8 @@
 
 namespace JS {
 
-GlobalObject::GlobalObject()
-    : Object(GlobalObjectTag::Tag)
+GlobalObject::GlobalObject(Realm& realm)
+    : Object(GlobalObjectTag::Tag, realm)
     , m_console(make<Console>(*this))
 {
 }
@@ -152,14 +152,16 @@ void GlobalObject::initialize_global_object()
     ensure_shape_is_unique();
 
     // These are done first since other prototypes depend on their presence.
-    m_empty_object_shape = heap().allocate_without_global_object<Shape>(*this);
+    VERIFY(associated_realm());
+    auto& realm = *associated_realm();
+    m_empty_object_shape = heap().allocate_without_global_object<Shape>(realm);
     m_object_prototype = heap().allocate_without_global_object<ObjectPrototype>(*this);
     m_function_prototype = heap().allocate_without_global_object<FunctionPrototype>(*this);
 
-    m_new_object_shape = vm.heap().allocate_without_global_object<Shape>(*this);
+    m_new_object_shape = vm.heap().allocate_without_global_object<Shape>(realm);
     m_new_object_shape->set_prototype_without_transition(m_object_prototype);
 
-    m_new_ordinary_function_prototype_object_shape = vm.heap().allocate_without_global_object<Shape>(*this);
+    m_new_ordinary_function_prototype_object_shape = vm.heap().allocate_without_global_object<Shape>(realm);
     m_new_ordinary_function_prototype_object_shape->set_prototype_without_transition(m_object_prototype);
     m_new_ordinary_function_prototype_object_shape->add_property_without_transition(vm.names.constructor, Attribute::Writable | Attribute::Configurable);
 
@@ -359,8 +361,9 @@ Realm* GlobalObject::associated_realm()
     return m_associated_realm;
 }
 
-void GlobalObject::set_associated_realm(Badge<Realm>, Realm& realm)
+void GlobalObject::set_associated_realm(Realm& realm)
 {
+    VERIFY(&realm == &shape().realm());
     m_associated_realm = &realm;
 }
 

+ 33 - 12
Userland/Libraries/LibJS/Runtime/GlobalObject.h

@@ -17,7 +17,7 @@ class GlobalObject : public Object {
     JS_OBJECT(GlobalObject, Object);
 
 public:
-    explicit GlobalObject();
+    explicit GlobalObject(Realm&);
     virtual void initialize_global_object();
 
     virtual ~GlobalObject() override;
@@ -25,7 +25,7 @@ public:
     Console& console() { return *m_console; }
 
     Realm* associated_realm();
-    void set_associated_realm(Badge<Realm>, Realm&);
+    void set_associated_realm(Realm&);
 
     Shape* empty_object_shape() { return m_empty_object_shape; }
 
@@ -56,25 +56,46 @@ public:
     FunctionObject* throw_type_error_function() const { return m_throw_type_error_function; }
 
 #define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName, ArrayType) \
-    ConstructorName* snake_name##_constructor() { return m_##snake_name##_constructor; } \
-    Object* snake_name##_prototype() { return m_##snake_name##_prototype; }
+    ConstructorName* snake_name##_constructor()                                          \
+    {                                                                                    \
+        return m_##snake_name##_constructor;                                             \
+    }                                                                                    \
+    Object* snake_name##_prototype()                                                     \
+    {                                                                                    \
+        return m_##snake_name##_prototype;                                               \
+    }
     JS_ENUMERATE_BUILTIN_TYPES
 #undef __JS_ENUMERATE
 
-#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName)                              \
-    Intl::ConstructorName* intl_##snake_name##_constructor() { return m_intl_##snake_name##_constructor; } \
-    Object* intl_##snake_name##_prototype() { return m_intl_##snake_name##_prototype; }
+#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName) \
+    Intl::ConstructorName* intl_##snake_name##_constructor()                  \
+    {                                                                         \
+        return m_intl_##snake_name##_constructor;                             \
+    }                                                                         \
+    Object* intl_##snake_name##_prototype()                                   \
+    {                                                                         \
+        return m_intl_##snake_name##_prototype;                               \
+    }
     JS_ENUMERATE_INTL_OBJECTS
 #undef __JS_ENUMERATE
 
-#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName)                                          \
-    Temporal::ConstructorName* temporal_##snake_name##_constructor() { return m_temporal_##snake_name##_constructor; } \
-    Object* temporal_##snake_name##_prototype() { return m_temporal_##snake_name##_prototype; }
+#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName) \
+    Temporal::ConstructorName* temporal_##snake_name##_constructor()          \
+    {                                                                         \
+        return m_temporal_##snake_name##_constructor;                         \
+    }                                                                         \
+    Object* temporal_##snake_name##_prototype()                               \
+    {                                                                         \
+        return m_temporal_##snake_name##_prototype;                           \
+    }
     JS_ENUMERATE_TEMPORAL_OBJECTS
 #undef __JS_ENUMERATE
 
 #define __JS_ENUMERATE(ClassName, snake_name) \
-    Object* snake_name##_prototype() { return m_##snake_name##_prototype; }
+    Object* snake_name##_prototype()          \
+    {                                         \
+        return m_##snake_name##_prototype;    \
+    }
     JS_ENUMERATE_ITERATOR_PROTOTYPES
 #undef __JS_ENUMERATE
 
@@ -173,7 +194,7 @@ inline void GlobalObject::add_constructor(PropertyKey const& property_key, Const
 
 inline GlobalObject* Shape::global_object() const
 {
-    return static_cast<GlobalObject*>(m_global_object);
+    return &static_cast<GlobalObject&>(m_realm.global_object());
 }
 
 template<>

+ 9 - 3
Userland/Libraries/LibJS/Runtime/Object.cpp

@@ -34,15 +34,21 @@ Object* Object::create(GlobalObject& global_object, Object* prototype)
         return global_object.heap().allocate<Object>(global_object, *prototype);
 }
 
-Object::Object(GlobalObjectTag)
+GlobalObject& Object::global_object() const
+{
+    return *shape().global_object();
+}
+
+Object::Object(GlobalObjectTag, Realm& realm)
 {
     // This is the global object
-    m_shape = heap().allocate_without_global_object<Shape>(*this);
+    m_shape = heap().allocate_without_global_object<Shape>(realm);
 }
 
 Object::Object(ConstructWithoutPrototypeTag, GlobalObject& global_object)
 {
-    m_shape = heap().allocate_without_global_object<Shape>(global_object);
+    VERIFY(global_object.associated_realm());
+    m_shape = heap().allocate_without_global_object<Shape>(*global_object.associated_realm());
 }
 
 Object::Object(GlobalObject& global_object, Object* prototype)

+ 2 - 2
Userland/Libraries/LibJS/Runtime/Object.h

@@ -186,7 +186,7 @@ public:
     Shape& shape() { return *m_shape; }
     Shape const& shape() const { return *m_shape; }
 
-    GlobalObject& global_object() const { return *shape().global_object(); }
+    GlobalObject& global_object() const;
 
     void ensure_shape_is_unique();
 
@@ -196,7 +196,7 @@ public:
 protected:
     enum class GlobalObjectTag { Tag };
     enum class ConstructWithoutPrototypeTag { Tag };
-    explicit Object(GlobalObjectTag);
+    explicit Object(GlobalObjectTag, Realm&);
     Object(ConstructWithoutPrototypeTag, GlobalObject&);
 
     void set_prototype(Object*);

+ 1 - 1
Userland/Libraries/LibJS/Runtime/Realm.cpp

@@ -24,7 +24,7 @@ void Realm::set_global_object(GlobalObject& global_object, Object* this_value)
     // 2. Assert: Type(globalObj) is Object.
 
     // Non-standard
-    global_object.set_associated_realm({}, *this);
+    global_object.set_associated_realm(*this);
 
     // 3. If thisValue is undefined, set thisValue to globalObj.
     if (!this_value)

+ 2 - 2
Userland/Libraries/LibJS/Runtime/ShadowRealmConstructor.cpp

@@ -63,9 +63,9 @@ ThrowCompletionOr<Object*> ShadowRealmConstructor::construct(FunctionObject& new
     auto* object = TRY(ordinary_create_from_constructor<ShadowRealm>(global_object, new_target, &GlobalObject::shadow_realm_prototype, *realm, move(context)));
 
     // 10. Perform ? SetRealmGlobalObject(realmRec, undefined, undefined).
-    auto* new_global_object = vm.heap().allocate_without_global_object<GlobalObject>();
-    new_global_object->initialize_global_object();
+    auto* new_global_object = vm.heap().allocate_without_global_object<GlobalObject>(*realm);
     realm->set_global_object(*new_global_object, nullptr);
+    new_global_object->initialize_global_object();
 
     // TODO: I don't think we should have these exactly like this, that doesn't work well with how
     //       we create global objects. Still, it should be possible to make a ShadowRealm with a

+ 6 - 7
Userland/Libraries/LibJS/Runtime/Shape.cpp

@@ -12,8 +12,7 @@ namespace JS {
 
 Shape* Shape::create_unique_clone() const
 {
-    VERIFY(m_global_object);
-    auto* new_shape = heap().allocate_without_global_object<Shape>(*m_global_object);
+    auto* new_shape = heap().allocate_without_global_object<Shape>(m_realm);
     new_shape->m_unique = true;
     new_shape->m_prototype = m_prototype;
     ensure_property_table();
@@ -88,13 +87,13 @@ Shape* Shape::create_prototype_transition(Object* new_prototype)
     return new_shape;
 }
 
-Shape::Shape(Object& global_object)
-    : m_global_object(&global_object)
+Shape::Shape(Realm& realm)
+    : m_realm(realm)
 {
 }
 
 Shape::Shape(Shape& previous_shape, StringOrSymbol const& property_key, PropertyAttributes attributes, TransitionType transition_type)
-    : m_global_object(previous_shape.m_global_object)
+    : m_realm(previous_shape.m_realm)
     , m_previous(&previous_shape)
     , m_property_key(property_key)
     , m_prototype(previous_shape.m_prototype)
@@ -105,7 +104,7 @@ Shape::Shape(Shape& previous_shape, StringOrSymbol const& property_key, Property
 }
 
 Shape::Shape(Shape& previous_shape, Object* new_prototype)
-    : m_global_object(previous_shape.m_global_object)
+    : m_realm(previous_shape.m_realm)
     , m_previous(&previous_shape)
     , m_prototype(new_prototype)
     , m_property_count(previous_shape.m_property_count)
@@ -116,7 +115,7 @@ Shape::Shape(Shape& previous_shape, Object* new_prototype)
 void Shape::visit_edges(Cell::Visitor& visitor)
 {
     Cell::visit_edges(visitor);
-    visitor.visit(m_global_object);
+    visitor.visit(&m_realm);
     visitor.visit(m_prototype);
     visitor.visit(m_previous);
     m_property_key.visit_edges(visitor);

+ 3 - 2
Userland/Libraries/LibJS/Runtime/Shape.h

@@ -47,7 +47,7 @@ public:
         Prototype,
     };
 
-    explicit Shape(Object& global_object);
+    explicit Shape(Realm&);
     Shape(Shape& previous_shape, StringOrSymbol const& property_key, PropertyAttributes attributes, TransitionType);
     Shape(Shape& previous_shape, Object* new_prototype);
 
@@ -61,6 +61,7 @@ public:
     bool is_unique() const { return m_unique; }
     Shape* create_unique_clone() const;
 
+    Realm& realm() const { return m_realm; }
     GlobalObject* global_object() const;
 
     Object* prototype() { return m_prototype; }
@@ -92,7 +93,7 @@ private:
 
     void ensure_property_table() const;
 
-    Object* m_global_object { nullptr };
+    Realm& m_realm;
 
     mutable OwnPtr<HashMap<StringOrSymbol, PropertyMetadata>> m_property_table;
 

+ 5 - 1
Userland/Libraries/LibTest/JavaScriptTestRunner.h

@@ -190,7 +190,11 @@ class TestRunnerGlobalObject final : public JS::GlobalObject {
     JS_OBJECT(TestRunnerGlobalObject, JS::GlobalObject);
 
 public:
-    TestRunnerGlobalObject() = default;
+    TestRunnerGlobalObject(JS::Realm& realm)
+        : JS::GlobalObject(realm)
+    {
+    }
+
     virtual ~TestRunnerGlobalObject() override = default;
 
     virtual void initialize_global_object() override;

+ 3 - 2
Userland/Libraries/LibWeb/Bindings/WindowObject.cpp

@@ -50,8 +50,9 @@
 
 namespace Web::Bindings {
 
-WindowObject::WindowObject(HTML::Window& impl)
-    : m_impl(impl)
+WindowObject::WindowObject(JS::Realm& realm, HTML::Window& impl)
+    : GlobalObject(realm)
+    , m_impl(impl)
 {
     impl.set_wrapper({}, *this);
 }

+ 1 - 1
Userland/Libraries/LibWeb/Bindings/WindowObject.h

@@ -32,7 +32,7 @@ class WindowObject
     JS_OBJECT(WindowObject, JS::GlobalObject);
 
 public:
-    explicit WindowObject(HTML::Window&);
+    explicit WindowObject(JS::Realm&, HTML::Window&);
     virtual void initialize_global_object() override;
     virtual ~WindowObject() override = default;
 

+ 1 - 1
Userland/Libraries/LibWeb/HTML/Worker.cpp

@@ -113,7 +113,7 @@ void Worker::run_a_worker(AK::URL& url, EnvironmentSettingsObject& outside_setti
 
     // FIXME: Make and use subclasses of WorkerGlobalScope, however this requires JS::GlobalObject to
     //        play nicely with the IDL interpreter, to make spec-compliant extensions, which it currently does not.
-    m_worker_scope = m_worker_vm->heap().allocate_without_global_object<JS::GlobalObject>();
+    m_worker_scope = m_worker_vm->heap().allocate_without_global_object<JS::GlobalObject>(*m_worker_realm);
     m_worker_scope->initialize_global_object();
 
     m_console = adopt_ref(*new WorkerDebugConsoleClient(m_worker_scope->console()));

+ 3 - 2
Userland/Services/WebContent/ConsoleGlobalObject.cpp

@@ -14,8 +14,9 @@
 
 namespace WebContent {
 
-ConsoleGlobalObject::ConsoleGlobalObject(Web::Bindings::WindowObject& parent_object)
-    : m_window_object(&parent_object)
+ConsoleGlobalObject::ConsoleGlobalObject(JS::Realm& realm, Web::Bindings::WindowObject& parent_object)
+    : GlobalObject(realm)
+    , m_window_object(&parent_object)
 {
 }
 

+ 1 - 1
Userland/Services/WebContent/ConsoleGlobalObject.h

@@ -20,7 +20,7 @@ class ConsoleGlobalObject final : public JS::GlobalObject {
     JS_OBJECT(ConsoleGlobalObject, JS::GlobalObject);
 
 public:
-    ConsoleGlobalObject(Web::Bindings::WindowObject&);
+    ConsoleGlobalObject(JS::Realm&, Web::Bindings::WindowObject&);
     virtual ~ConsoleGlobalObject() override = default;
 
     virtual JS::ThrowCompletionOr<Object*> internal_get_prototype_of() const override;

+ 2 - 1
Userland/Services/WebContent/WebContentConsoleClient.cpp

@@ -26,12 +26,13 @@ WebContentConsoleClient::WebContentConsoleClient(JS::Console& console, WeakPtr<J
     auto& vm = m_interpreter->vm();
     auto& global_object = m_interpreter->global_object();
 
-    auto console_global_object = m_interpreter->heap().allocate_without_global_object<ConsoleGlobalObject>(static_cast<Web::Bindings::WindowObject&>(global_object));
+    auto console_global_object = m_interpreter->heap().allocate_without_global_object<ConsoleGlobalObject>(m_interpreter->realm(), static_cast<Web::Bindings::WindowObject&>(global_object));
 
     // NOTE: We need to push an execution context here for NativeFunction::create() to succeed during global object initialization.
     // It gets removed immediately after creating the interpreter in Document::interpreter().
     auto& eso = verify_cast<Web::HTML::EnvironmentSettingsObject>(*m_interpreter->realm().host_defined());
     vm.push_execution_context(eso.realm_execution_context());
+    console_global_object->set_associated_realm(m_interpreter->realm());
     console_global_object->initialize_global_object();
     vm.pop_execution_context();
 

+ 8 - 2
Userland/Utilities/js.cpp

@@ -92,7 +92,10 @@ class ReplObject final : public JS::GlobalObject {
     JS_OBJECT(ReplObject, JS::GlobalObject);
 
 public:
-    ReplObject() = default;
+    ReplObject(JS::Realm& realm)
+        : GlobalObject(realm)
+    {
+    }
     virtual void initialize_global_object() override;
     virtual ~ReplObject() override = default;
 
@@ -110,7 +113,10 @@ class ScriptObject final : public JS::GlobalObject {
     JS_OBJECT(ScriptObject, JS::GlobalObject);
 
 public:
-    ScriptObject() = default;
+    ScriptObject(JS::Realm& realm)
+        : JS::GlobalObject(realm)
+    {
+    }
     virtual void initialize_global_object() override;
     virtual ~ScriptObject() override = default;