Browse Source

LibWeb: Generate exposed Window/Worker interfaces as lazy objects

We now lazily create these instances on-demand rather than all at once
when a Window/Worker object is created.
Timothy Flynn 2 năm trước cách đây
mục cha
commit
6e93d89ee3

+ 12 - 34
Meta/Lagom/Tools/CodeGenerators/LibWeb/GenerateWindowOrWorkerInterfaces.cpp

@@ -166,7 +166,7 @@ static ErrorOr<void> generate_intrinsic_definitions(StringView output_path, Vect
 namespace Web::Bindings {
 namespace Web::Bindings {
 )~~~");
 )~~~");
 
 
-    auto add_interface = [&](SourceGenerator& gen, StringView name, StringView prototype_class, StringView constructor_class, Optional<LegacyConstructor> const& legacy_constructor, bool attach_to_global) {
+    auto add_interface = [&](SourceGenerator& gen, StringView name, StringView prototype_class, StringView constructor_class, Optional<LegacyConstructor> const& legacy_constructor) {
         gen.set("interface_name", name);
         gen.set("interface_name", name);
         gen.set("prototype_class", prototype_class);
         gen.set("prototype_class", prototype_class);
         gen.set("constructor_class", constructor_class);
         gen.set("constructor_class", constructor_class);
@@ -182,15 +182,7 @@ void Intrinsics::create_web_prototype_and_constructor<@prototype_class@>(JS::Rea
 
 
     auto constructor = heap().allocate<@constructor_class@>(realm, realm);
     auto constructor = heap().allocate<@constructor_class@>(realm, realm);
     m_constructors.set("@interface_name@"sv, constructor);
     m_constructors.set("@interface_name@"sv, constructor);
-)~~~");
-
-        if (attach_to_global) {
-            gen.append(R"~~~(
-    auto& global = realm.global_object();
-    global.define_direct_property("@interface_name@", constructor.ptr(), JS::Attribute::Writable | JS::Attribute::Configurable);)~~~");
-        }
 
 
-        gen.append(R"~~~(
     prototype->define_direct_property(vm.names.constructor, constructor.ptr(), JS::Attribute::Writable | JS::Attribute::Configurable);
     prototype->define_direct_property(vm.names.constructor, constructor.ptr(), JS::Attribute::Writable | JS::Attribute::Configurable);
     constructor->define_direct_property(vm.names.name, JS::PrimitiveString::create(vm, "@interface_name@"sv), JS::Attribute::Configurable);
     constructor->define_direct_property(vm.names.name, JS::PrimitiveString::create(vm, "@interface_name@"sv), JS::Attribute::Configurable);
 )~~~");
 )~~~");
@@ -201,14 +193,7 @@ void Intrinsics::create_web_prototype_and_constructor<@prototype_class@>(JS::Rea
             gen.append(R"~~~(
             gen.append(R"~~~(
     auto legacy_constructor = heap().allocate<@legacy_constructor_class@>(realm, realm);
     auto legacy_constructor = heap().allocate<@legacy_constructor_class@>(realm, realm);
     m_constructors.set("@legacy_interface_name@"sv, legacy_constructor);
     m_constructors.set("@legacy_interface_name@"sv, legacy_constructor);
-)~~~");
 
 
-            if (attach_to_global) {
-                gen.append(R"~~~(
-    global.define_direct_property("@legacy_interface_name@", legacy_constructor.ptr(), JS::Attribute::Writable | JS::Attribute::Configurable);)~~~");
-            }
-
-            gen.append(R"~~~(
     legacy_constructor->define_direct_property(vm.names.name, JS::PrimitiveString::create(vm, "@legacy_interface_name@"sv), JS::Attribute::Configurable);)~~~");
     legacy_constructor->define_direct_property(vm.names.name, JS::PrimitiveString::create(vm, "@legacy_interface_name@"sv), JS::Attribute::Configurable);)~~~");
         }
         }
 
 
@@ -219,23 +204,23 @@ void Intrinsics::create_web_prototype_and_constructor<@prototype_class@>(JS::Rea
 
 
     for (auto& interface : exposed_interfaces) {
     for (auto& interface : exposed_interfaces) {
         auto gen = generator.fork();
         auto gen = generator.fork();
-        add_interface(gen, interface.name, interface.prototype_class, interface.constructor_class, lookup_legacy_constructor(interface), true);
+        add_interface(gen, interface.name, interface.prototype_class, interface.constructor_class, lookup_legacy_constructor(interface));
     }
     }
 
 
     // FIXME: Special case window. We should convert Window and Location to use IDL
     // FIXME: Special case window. We should convert Window and Location to use IDL
     {
     {
         auto gen = generator.fork();
         auto gen = generator.fork();
-        add_interface(gen, "Window"sv, "WindowPrototype"sv, "WindowConstructor"sv, {}, true);
-        add_interface(gen, "Location"sv, "LocationPrototype"sv, "LocationConstructor"sv, {}, true);
+        add_interface(gen, "Window"sv, "WindowPrototype"sv, "WindowConstructor"sv, {});
+        add_interface(gen, "Location"sv, "LocationPrototype"sv, "LocationConstructor"sv, {});
     }
     }
 
 
     // FIXME: Special case WebAssembly. We should convert WASM to use IDL.
     // FIXME: Special case WebAssembly. We should convert WASM to use IDL.
     {
     {
         auto gen = generator.fork();
         auto gen = generator.fork();
-        add_interface(gen, "WebAssembly.Memory"sv, "WebAssemblyMemoryPrototype"sv, "WebAssemblyMemoryConstructor"sv, {}, false);
-        add_interface(gen, "WebAssembly.Instance"sv, "WebAssemblyInstancePrototype"sv, "WebAssemblyInstanceConstructor"sv, {}, false);
-        add_interface(gen, "WebAssembly.Module"sv, "WebAssemblyModulePrototype"sv, "WebAssemblyModuleConstructor"sv, {}, false);
-        add_interface(gen, "WebAssembly.Table"sv, "WebAssemblyTablePrototype"sv, "WebAssemblyTableConstructor"sv, {}, false);
+        add_interface(gen, "WebAssembly.Memory"sv, "WebAssemblyMemoryPrototype"sv, "WebAssemblyMemoryConstructor"sv, {});
+        add_interface(gen, "WebAssembly.Instance"sv, "WebAssemblyInstancePrototype"sv, "WebAssemblyInstanceConstructor"sv, {});
+        add_interface(gen, "WebAssembly.Module"sv, "WebAssemblyModulePrototype"sv, "WebAssemblyModuleConstructor"sv, {});
+        add_interface(gen, "WebAssembly.Table"sv, "WebAssemblyTablePrototype"sv, "WebAssemblyTableConstructor"sv, {});
     }
     }
 
 
     generator.append(R"~~~(
     generator.append(R"~~~(
@@ -262,7 +247,7 @@ static ErrorOr<void> generate_exposed_interface_header(StringView class_name, St
 
 
 namespace Web::Bindings {
 namespace Web::Bindings {
 
 
-void add_@global_object_snake_name@_exposed_interfaces(JS::Object&, JS::Realm&);
+void add_@global_object_snake_name@_exposed_interfaces(JS::Object&);
 
 
 }
 }
 
 
@@ -284,7 +269,6 @@ static ErrorOr<void> generate_exposed_interface_implementation(StringView class_
     generator.set("global_object_snake_name", DeprecatedString(class_name).to_snakecase());
     generator.set("global_object_snake_name", DeprecatedString(class_name).to_snakecase());
 
 
     generator.append(R"~~~(
     generator.append(R"~~~(
-#include <LibJS/Heap/DeferGC.h>
 #include <LibJS/Runtime/Object.h>
 #include <LibJS/Runtime/Object.h>
 #include <LibWeb/Bindings/Intrinsics.h>
 #include <LibWeb/Bindings/Intrinsics.h>
 #include <LibWeb/Bindings/@global_object_name@ExposedInterfaces.h>
 #include <LibWeb/Bindings/@global_object_name@ExposedInterfaces.h>
@@ -317,15 +301,9 @@ static ErrorOr<void> generate_exposed_interface_implementation(StringView class_
     generator.append(R"~~~(
     generator.append(R"~~~(
 namespace Web::Bindings {
 namespace Web::Bindings {
 
 
-void add_@global_object_snake_name@_exposed_interfaces(JS::Object& global, JS::Realm& realm)
+void add_@global_object_snake_name@_exposed_interfaces(JS::Object& global)
 {
 {
-    auto& vm = global.vm();
-    // FIXME: Should we use vm.current_realm() here?
-
-    // NOTE: Temporarily disable garbage collection to prevent GC from triggering while a not-fully-constructed
-    //       prototype or constructor object has been allocated. This is a hack.
-    // FIXME: Find a nicer way to solve this.
-    JS::DeferGC defer_gc(vm.heap());
+    static constexpr u8 attr = JS::Attribute::Writable | JS::Attribute::Configurable;
 )~~~");
 )~~~");
 
 
     auto add_interface = [](SourceGenerator& gen, StringView name, StringView prototype_class) {
     auto add_interface = [](SourceGenerator& gen, StringView name, StringView prototype_class) {
@@ -333,7 +311,7 @@ void add_@global_object_snake_name@_exposed_interfaces(JS::Object& global, JS::R
         gen.set("prototype_class", prototype_class);
         gen.set("prototype_class", prototype_class);
 
 
         gen.append(R"~~~(
         gen.append(R"~~~(
-    (void)ensure_web_prototype<@prototype_class@>(realm, "@interface_name@"sv);)~~~"); };
+    global.define_intrinsic_accessor("@interface_name@", attr, [](auto& realm) -> JS::Value { return &ensure_web_constructor<@prototype_class@>(realm, "@interface_name@"sv); });)~~~"); };
 
 
     for (auto& interface : exposed_interfaces) {
     for (auto& interface : exposed_interfaces) {
         auto gen = generator.fork();
         auto gen = generator.fork();

+ 1 - 1
Userland/Libraries/LibWeb/Bindings/MainThreadVM.cpp

@@ -387,7 +387,7 @@ JS::VM& main_thread_vm()
         JS::DeferGC defer_gc(root_realm->heap());
         JS::DeferGC defer_gc(root_realm->heap());
         auto object = JS::Object::create(*root_realm, nullptr);
         auto object = JS::Object::create(*root_realm, nullptr);
         root_realm->set_global_object(object, object);
         root_realm->set_global_object(object, object);
-        add_window_exposed_interfaces(*object, *root_realm);
+        add_window_exposed_interfaces(*object);
 
 
         vm->push_execution_context(*custom_data.root_execution_context);
         vm->push_execution_context(*custom_data.root_execution_context);
     }
     }

+ 1 - 1
Userland/Libraries/LibWeb/HTML/Scripting/WorkerEnvironmentSettingsObject.h

@@ -35,7 +35,7 @@ public:
         realm->set_host_defined(move(host_defined));
         realm->set_host_defined(move(host_defined));
 
 
         // FIXME: Shared workers should use the shared worker method
         // FIXME: Shared workers should use the shared worker method
-        Bindings::add_dedicated_worker_exposed_interfaces(realm->global_object(), *realm);
+        Bindings::add_dedicated_worker_exposed_interfaces(realm->global_object());
 
 
         return settings_object;
         return settings_object;
     }
     }

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

@@ -1061,7 +1061,7 @@ HTML::BrowsingContext* Window::browsing_context()
 void Window::initialize_web_interfaces(Badge<WindowEnvironmentSettingsObject>)
 void Window::initialize_web_interfaces(Badge<WindowEnvironmentSettingsObject>)
 {
 {
     auto& realm = this->realm();
     auto& realm = this->realm();
-    add_window_exposed_interfaces(*this, realm);
+    add_window_exposed_interfaces(*this);
 
 
     Object::set_prototype(&Bindings::ensure_web_prototype<Bindings::WindowPrototype>(realm, "Window"));
     Object::set_prototype(&Bindings::ensure_web_prototype<Bindings::WindowPrototype>(realm, "Window"));