diff options
author | bors-servo <servo-ops@mozilla.com> | 2021-07-09 10:01:38 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-07-09 10:01:38 -0400 |
commit | 94b613fbdaa2b98f2179fc0bbda13c64e6fa0d38 (patch) | |
tree | 307c398278ee7d72b39224e7d48b97d100f83a52 /components/script/dom | |
parent | 42d7892d88d8e97ca20aa3557b2f03f739f17b89 (diff) | |
parent | 7cda260fcb0b7e1de7457f1b03a2e3b613fc1052 (diff) | |
download | servo-94b613fbdaa2b98f2179fc0bbda13c64e6fa0d38.tar.gz servo-94b613fbdaa2b98f2179fc0bbda13c64e6fa0d38.zip |
Auto merge of #28536 - yvt:fix-one-compartment, r=jdm
Create only one compartment for each script thread (agent)
Documents in the same [agent][1] can share and exchange JS and DOM objects freely, so putting them in separate compartments would require almost every instance of `Dom` to be capable of handling cross-compartment references.
[1]: https://html.spec.whatwg.org/multipage/webappapis.html#integration-with-the-javascript-agent-formalism
---
- [x] `./mach build -d` does not report any errors
- [ ] `./mach test-tidy` does not report any errors
- [ ] These changes fix #___ (GitHub issue number if applicable)
---
- [ ] There are tests for these changes OR
- [x] These changes do not require tests because I think there's already a wide test coverage for same-origin-domain JS object passing, albeit this requires Servo to be built with `--debug-mozjs` for the errors to be (reliably) observable
Diffstat (limited to 'components/script/dom')
-rw-r--r-- | components/script/dom/bindings/interface.rs | 42 | ||||
-rw-r--r-- | components/script/dom/windowproxy.rs | 12 |
2 files changed, 47 insertions, 7 deletions
diff --git a/components/script/dom/bindings/interface.rs b/components/script/dom/bindings/interface.rs index 1085a137428..82303f800ba 100644 --- a/components/script/dom/bindings/interface.rs +++ b/components/script/dom/bindings/interface.rs @@ -16,6 +16,10 @@ use js::glue::UncheckedUnwrapObject; use js::jsapi::GetWellKnownSymbol; use js::jsapi::HandleObject as RawHandleObject; use js::jsapi::{jsid, JSClass, JSClassOps}; +use js::jsapi::{ + Compartment, CompartmentSpecifier, IsSharableCompartment, IsSystemCompartment, + JS_IterateCompartments, JS::CompartmentIterResult, +}; use js::jsapi::{JSAutoRealm, JSContext, JSFunctionSpec, JSObject, JSFUN_CONSTRUCTOR}; use js::jsapi::{JSPropertySpec, JSString, JSTracer, JS_AtomizeAndPinString}; use js::jsapi::{JS_GetFunctionObject, JS_NewFunction, JS_NewGlobalObject}; @@ -139,6 +143,7 @@ pub unsafe fn create_global_object( options.creationOptions_.traceGlobal_ = Some(trace); options.creationOptions_.sharedMemoryAndAtomics_ = false; options.creationOptions_.streams_ = true; + select_compartment(cx, &mut options); rval.set(JS_NewGlobalObject( *cx, @@ -162,6 +167,43 @@ pub unsafe fn create_global_object( JS_FireOnNewGlobalObject(*cx, rval.handle()); } +/// Choose the compartment to create a new global object in. +fn select_compartment(cx: SafeJSContext, options: &mut RealmOptions) { + type Data = *mut Compartment; + unsafe extern "C" fn callback( + _cx: *mut JSContext, + data: *mut libc::c_void, + compartment: *mut Compartment, + ) -> CompartmentIterResult { + let data = data as *mut Data; + + if !IsSharableCompartment(compartment) || IsSystemCompartment(compartment) { + return CompartmentIterResult::KeepGoing; + } + + // Choose any sharable, non-system compartment in this context to allow + // same-agent documents to share JS and DOM objects. + *data = compartment; + CompartmentIterResult::Stop + } + + let mut compartment: Data = ptr::null_mut(); + unsafe { + JS_IterateCompartments( + *cx, + (&mut compartment) as *mut Data as *mut libc::c_void, + Some(callback), + ); + } + + if compartment.is_null() { + options.creationOptions_.compSpec_ = CompartmentSpecifier::NewCompartmentAndZone; + } else { + options.creationOptions_.compSpec_ = CompartmentSpecifier::ExistingCompartment; + options.creationOptions_.__bindgen_anon_1.comp_ = compartment; + } +} + /// Create and define the interface object of a callback interface. pub fn create_callback_interface_object( cx: SafeJSContext, diff --git a/components/script/dom/windowproxy.rs b/components/script/dom/windowproxy.rs index e37e561af06..0f92e4b3367 100644 --- a/components/script/dom/windowproxy.rs +++ b/components/script/dom/windowproxy.rs @@ -637,13 +637,11 @@ impl WindowProxy { // The old window proxy no longer owns this browsing context. SetProxyReservedSlot(old_js_proxy.get(), 0, &PrivateValue(ptr::null_mut())); - // Brain transpant the window proxy. - // We need to do this, because the Window and WindowProxy - // objects need to be in the same realm. - // JS_TransplantObject does this by copying the contents - // of the old window proxy to the new window proxy, then - // making the old window proxy a cross-realm wrapper - // pointing to the new window proxy. + // Brain transpant the window proxy. Brain transplantation is + // usually done to move a window proxy between compartments, but + // that's not what we are doing here. We need to do this just + // because we want to replace the wrapper's `ProxyTraps`, but we + // don't want to update its identity. rooted!(in(*cx) let new_js_proxy = NewWindowProxy(*cx, window_jsobject, handler)); debug!( "Transplanting proxy from {:p} to {:p}.", |