Eagerly define interfaces on non-Window globals (#36604)

These changes make us match Gecko's setup for how Window and non-Window
globals are initialized. Since Window globals are much more common than
Worker globals, using lazy interface definitions can be a useful memory
optimization at the expense of increased complexity for property
lookups.

Also adds the MayResolve hook for all globals, which is an optimization
for the JIT to avoid calling resolve hooks unnecessarily.

Testing: Existing test coverage on global interfaces should suffice.

---------

Signed-off-by: Josh Matthews <josh@joshmatthews.net>
This commit is contained in:
Josh Matthews 2025-04-20 23:32:21 -04:00 committed by GitHub
parent 436dee8450
commit 76ee127af8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 138 additions and 35 deletions

View file

@ -118,6 +118,19 @@ pub(crate) const DOM_CALLBACKS: DOMCallbacks = DOMCallbacks {
instanceClassMatchesProto: Some(instance_class_has_proto_at_depth),
};
/// Eagerly define all relevant WebIDL interface constructors on the
/// provided global object.
pub(crate) fn define_all_exposed_interfaces(
global: &GlobalScope,
_in_realm: InRealm,
_can_gc: CanGc,
) {
let cx = GlobalScope::get_cx();
for (_, interface) in &InterfaceObjectMap::MAP {
(interface.define)(cx, global.reflector().get_jsobject());
}
}
impl DomHelpers<crate::DomTypeHolder> for crate::DomTypeHolder {
fn throw_dom_exception(
cx: SafeJSContext,

View file

@ -42,6 +42,7 @@ use crate::dom::bindings::root::{DomRoot, RootCollection, ThreadLocalStackRoots}
use crate::dom::bindings::str::DOMString;
use crate::dom::bindings::structuredclone;
use crate::dom::bindings::trace::{CustomTraceable, RootedTraceableBox};
use crate::dom::bindings::utils::define_all_exposed_interfaces;
use crate::dom::errorevent::ErrorEvent;
use crate::dom::event::{Event, EventBubbles, EventCancelable, EventStatus};
use crate::dom::eventtarget::EventTarget;
@ -493,7 +494,12 @@ impl DedicatedWorkerGlobalScope {
{
let _ar = AutoWorkerReset::new(&global, worker.clone());
let _ac = enter_realm(scope);
let realm = enter_realm(scope);
define_all_exposed_interfaces(
global.upcast(),
InRealm::entered(&realm),
CanGc::note(),
);
scope.execute_script(DOMString::from(source), CanGc::note());
}

View file

@ -38,6 +38,7 @@ use crate::dom::bindings::root::{DomRoot, RootCollection, ThreadLocalStackRoots}
use crate::dom::bindings::str::DOMString;
use crate::dom::bindings::structuredclone;
use crate::dom::bindings::trace::CustomTraceable;
use crate::dom::bindings::utils::define_all_exposed_interfaces;
use crate::dom::dedicatedworkerglobalscope::AutoWorkerReset;
use crate::dom::event::Event;
use crate::dom::eventtarget::EventTarget;
@ -379,6 +380,11 @@ impl ServiceWorkerGlobalScope {
{
// TODO: use AutoWorkerReset as in dedicated worker?
let realm = enter_realm(scope);
define_all_exposed_interfaces(
scope.upcast(),
InRealm::entered(&realm),
CanGc::note(),
);
scope.execute_script(DOMString::from(source), CanGc::note());
global.dispatch_activate(CanGc::note(), InRealm::entered(&realm));
}

View file

@ -15,6 +15,7 @@ use js::rust::Runtime;
use net_traits::ResourceThreads;
use net_traits::image_cache::ImageCache;
use profile_traits::{mem, time};
use script_bindings::realms::InRealm;
use script_traits::Painter;
use servo_url::{ImmutableOrigin, MutableOrigin, ServoUrl};
use stylo_atoms::Atom;
@ -22,6 +23,7 @@ use stylo_atoms::Atom;
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::root::DomRoot;
use crate::dom::bindings::trace::CustomTraceable;
use crate::dom::bindings::utils::define_all_exposed_interfaces;
use crate::dom::globalscope::GlobalScope;
use crate::dom::paintworkletglobalscope::{PaintWorkletGlobalScope, PaintWorkletTask};
use crate::dom::testworkletglobalscope::{TestWorkletGlobalScope, TestWorkletTask};
@ -29,6 +31,7 @@ use crate::dom::testworkletglobalscope::{TestWorkletGlobalScope, TestWorkletTask
use crate::dom::webgpu::identityhub::IdentityHub;
use crate::dom::worklet::WorkletExecutor;
use crate::messaging::MainThreadScriptMsg;
use crate::realms::enter_realm;
use crate::script_module::ScriptFetchOptions;
use crate::script_runtime::{CanGc, JSContext};
@ -56,7 +59,7 @@ impl WorkletGlobalScope {
executor: WorkletExecutor,
init: &WorkletGlobalScopeInit,
) -> DomRoot<WorkletGlobalScope> {
match scope_type {
let scope: DomRoot<WorkletGlobalScope> = match scope_type {
WorkletGlobalScopeType::Test => DomRoot::upcast(TestWorkletGlobalScope::new(
runtime,
pipeline_id,
@ -71,7 +74,12 @@ impl WorkletGlobalScope {
executor,
init,
)),
}
};
let realm = enter_realm(&*scope);
define_all_exposed_interfaces(scope.upcast(), InRealm::entered(&realm), CanGc::note());
scope
}
/// Create a new stack-allocated `WorkletGlobalScope`.