diff --git a/Cargo.lock b/Cargo.lock index fb7c23b0523..98383c378c5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5240,7 +5240,7 @@ dependencies = [ [[package]] name = "mozjs" version = "0.14.1" -source = "git+https://github.com/servo/mozjs#4035b0c4e9e2df5cacc68c4b71e7375a48605902" +source = "git+https://github.com/servo/mozjs#903a158b36c10902a40c7fda766406d698f98bf4" dependencies = [ "bindgen 0.71.1", "cc", @@ -5252,7 +5252,7 @@ dependencies = [ [[package]] name = "mozjs_sys" version = "0.128.13-3" -source = "git+https://github.com/servo/mozjs#4035b0c4e9e2df5cacc68c4b71e7375a48605902" +source = "git+https://github.com/servo/mozjs#903a158b36c10902a40c7fda766406d698f98bf4" dependencies = [ "bindgen 0.71.1", "cc", diff --git a/components/script/dom/bindings/buffer_source.rs b/components/script/dom/bindings/buffer_source.rs index 14a71532e9d..6af96e0281a 100644 --- a/components/script/dom/bindings/buffer_source.rs +++ b/components/script/dom/bindings/buffer_source.rs @@ -42,6 +42,7 @@ use js::typedarray::{ }; use crate::dom::bindings::error::{Error, Fallible}; +use crate::dom::bindings::trace::RootedTraceableBox; #[cfg(feature = "webgpu")] use crate::dom::globalscope::GlobalScope; use crate::script_runtime::{CanGc, JSContext}; @@ -52,15 +53,14 @@ use crate::script_runtime::{CanGc, JSContext}; /// provides a view onto an `ArrayBuffer`. /// /// See: -#[derive(PartialEq)] pub(crate) enum BufferSource { /// Represents an `ArrayBufferView` (e.g., `Uint8Array`, `DataView`). /// See: - ArrayBufferView(Box>), + ArrayBufferView(RootedTraceableBox>), /// Represents an `ArrayBuffer`, a fixed-length binary data buffer. /// See: - ArrayBuffer(Box>), + ArrayBuffer(RootedTraceableBox>), } pub(crate) fn create_heap_buffer_source_with_length( @@ -80,7 +80,7 @@ where } Ok(HeapBufferSource::::new(BufferSource::ArrayBufferView( - Heap::boxed(*array.handle()), + RootedTraceableBox::from_box(Heap::boxed(*array.handle())), ))) } @@ -100,8 +100,8 @@ where BufferSource::ArrayBufferView(heap) | BufferSource::ArrayBuffer(heap) => match &other .buffer_source { - BufferSource::ArrayBufferView(from_heap) | BufferSource::ArrayBuffer(from_heap) => unsafe { - heap.handle() == from_heap.handle() + BufferSource::ArrayBufferView(from_heap) | BufferSource::ArrayBuffer(from_heap) => { + std::ptr::eq(heap.get(), from_heap.get()) }, }, } @@ -122,14 +122,16 @@ where pub(crate) fn from_view( chunk: CustomAutoRooterGuard>, ) -> HeapBufferSource { - HeapBufferSource::::new(BufferSource::ArrayBufferView(Heap::boxed(unsafe { - *chunk.underlying_object() - }))) + HeapBufferSource::::new(BufferSource::ArrayBufferView(RootedTraceableBox::from_box( + Heap::boxed(unsafe { *chunk.underlying_object() }), + ))) } pub(crate) fn default() -> Self { HeapBufferSource { - buffer_source: BufferSource::ArrayBufferView(Heap::boxed(std::ptr::null_mut())), + buffer_source: BufferSource::ArrayBufferView(RootedTraceableBox::from_box( + Heap::boxed(std::ptr::null_mut()), + )), phantom: PhantomData, } } @@ -174,11 +176,11 @@ where BufferSource::ArrayBufferView(buffer) => unsafe { let mut is_shared = false; rooted!(in (*cx) let view_buffer = - JS_GetArrayBufferViewBuffer(*cx, buffer.handle(), &mut is_shared)); + JS_GetArrayBufferViewBuffer(*cx, buffer.handle().into(), &mut is_shared)); - HeapBufferSource::::new(BufferSource::ArrayBuffer(Heap::boxed( - *view_buffer.handle(), - ))) + HeapBufferSource::::new(BufferSource::ArrayBuffer( + RootedTraceableBox::from_box(Heap::boxed(*view_buffer.handle())), + )) }, BufferSource::ArrayBuffer(_) => { unreachable!("BufferSource::ArrayBuffer does not have a view buffer.") @@ -196,7 +198,7 @@ where // assert buffer is an ArrayBuffer view assert!(JS_IsArrayBufferViewObject(*buffer.handle())); rooted!(in (*cx) let view_buffer = - JS_GetArrayBufferViewBuffer(*cx, buffer.handle(), &mut is_shared)); + JS_GetArrayBufferViewBuffer(*cx, buffer.handle().into(), &mut is_shared)); // This buffer is always created unshared debug_assert!(!is_shared); // Detach the ArrayBuffer @@ -204,7 +206,7 @@ where } }, BufferSource::ArrayBuffer(buffer) => unsafe { - DetachArrayBuffer(*cx, Handle::from_raw(buffer.handle())) + DetachArrayBuffer(*cx, Handle::from_raw(buffer.handle().into())) }, } } @@ -226,7 +228,7 @@ where unsafe { assert!(JS_IsArrayBufferViewObject(*buffer.handle())); rooted!(in (*cx) let view_buffer = - JS_GetArrayBufferViewBuffer(*cx, buffer.handle(), &mut is_shared)); + JS_GetArrayBufferViewBuffer(*cx, buffer.handle().into(), &mut is_shared)); debug_assert!(!is_shared); IsDetachedArrayBufferObject(*view_buffer.handle()) } @@ -245,7 +247,7 @@ where unsafe { assert!(JS_IsArrayBufferViewObject(*buffer.handle())); rooted!(in (*cx) let view_buffer = - JS_GetArrayBufferViewBuffer(*cx, buffer.handle(), &mut is_shared)); + JS_GetArrayBufferViewBuffer(*cx, buffer.handle().into(), &mut is_shared)); debug_assert!(!is_shared); GetArrayBufferByteLength(*view_buffer.handle()) } @@ -429,13 +431,16 @@ where ) -> Option> { match &self.buffer_source { BufferSource::ArrayBufferView(heap) | BufferSource::ArrayBuffer(heap) => { - let result = - unsafe { ArrayBufferClone(*cx, heap.handle(), byte_offset, byte_length) }; + let result = unsafe { + ArrayBufferClone(*cx, heap.handle().into(), byte_offset, byte_length) + }; if result.is_null() { None } else { Some(HeapBufferSource::::new( - BufferSource::ArrayBuffer(Heap::boxed(result)), + BufferSource::ArrayBuffer(RootedTraceableBox::from_box(Heap::boxed( + result, + ))), )) } }, @@ -466,11 +471,9 @@ where match &from_buffer.buffer_source { BufferSource::ArrayBufferView(from_heap) | BufferSource::ArrayBuffer(from_heap) => { - unsafe { - if heap.handle() == from_heap.handle() { - return false; - } - }; + if std::ptr::eq(heap.get(), from_heap.get()) { + return false; + } }, } }, @@ -514,9 +517,9 @@ where BufferSource::ArrayBufferView(from_heap) | BufferSource::ArrayBuffer(from_heap) => ArrayBufferCopyData( *cx, - heap.handle(), + heap.handle().into(), dest_start, - from_heap.handle(), + from_heap.handle().into(), from_byte_offset, bytes_to_copy, ), @@ -541,7 +544,7 @@ where let mut is_defined = false; match &self.buffer_source { BufferSource::ArrayBufferView(heap) | BufferSource::ArrayBuffer(heap) => unsafe { - if !HasDefinedArrayBufferDetachKey(*cx, heap.handle(), &mut is_defined) { + if !HasDefinedArrayBufferDetachKey(*cx, heap.handle().into(), &mut is_defined) { return false; } }, @@ -568,7 +571,7 @@ where // Step 2 (Reordered) let buffer_data = match &self.buffer_source { BufferSource::ArrayBufferView(buffer) | BufferSource::ArrayBuffer(buffer) => unsafe { - StealArrayBufferContents(*cx, buffer.handle()) + StealArrayBufferContents(*cx, buffer.handle().into()) }, }; @@ -588,9 +591,9 @@ where // whose [[ArrayBufferData]] internal slot value is arrayBufferData and // whose [[ArrayBufferByteLength]] internal slot value is arrayBufferByteLength. Ok(HeapBufferSource::::new( - BufferSource::ArrayBuffer(Heap::boxed(unsafe { + BufferSource::ArrayBuffer(RootedTraceableBox::from_box(Heap::boxed(unsafe { NewArrayBufferWithContents(*cx, buffer_length, buffer_data) - })), + }))), )) } } @@ -679,9 +682,9 @@ pub(crate) fn create_buffer_source_with_constructor( match &buffer_source.buffer_source { BufferSource::ArrayBuffer(heap) => match constructor { Constructor::DataView => Ok(HeapBufferSource::new(BufferSource::ArrayBufferView( - Heap::boxed(unsafe { - JS_NewDataView(*cx, heap.handle(), byte_offset, byte_length) - }), + RootedTraceableBox::from_box(Heap::boxed(unsafe { + JS_NewDataView(*cx, heap.handle().into(), byte_offset, byte_length) + })), ))), Constructor::Name(name_type) => construct_typed_array( cx, @@ -709,45 +712,78 @@ fn construct_typed_array( BufferSource::ArrayBuffer(heap) => { let array_view = unsafe { match name_type { - Type::Int8 => { - JS_NewInt8ArrayWithBuffer(*cx, heap.handle(), byte_offset, byte_length) - }, - Type::Uint8 => { - JS_NewUint8ArrayWithBuffer(*cx, heap.handle(), byte_offset, byte_length) - }, - Type::Uint16 => { - JS_NewUint16ArrayWithBuffer(*cx, heap.handle(), byte_offset, byte_length) - }, - Type::Int16 => { - JS_NewInt16ArrayWithBuffer(*cx, heap.handle(), byte_offset, byte_length) - }, - Type::Int32 => { - JS_NewInt32ArrayWithBuffer(*cx, heap.handle(), byte_offset, byte_length) - }, - Type::Uint32 => { - JS_NewUint32ArrayWithBuffer(*cx, heap.handle(), byte_offset, byte_length) - }, - Type::Float32 => { - JS_NewFloat32ArrayWithBuffer(*cx, heap.handle(), byte_offset, byte_length) - }, - Type::Float64 => { - JS_NewFloat64ArrayWithBuffer(*cx, heap.handle(), byte_offset, byte_length) - }, - Type::Uint8Clamped => JS_NewUint8ClampedArrayWithBuffer( + Type::Int8 => JS_NewInt8ArrayWithBuffer( *cx, - heap.handle(), + heap.handle().into(), + byte_offset, + byte_length, + ), + Type::Uint8 => JS_NewUint8ArrayWithBuffer( + *cx, + heap.handle().into(), + byte_offset, + byte_length, + ), + Type::Uint16 => JS_NewUint16ArrayWithBuffer( + *cx, + heap.handle().into(), + byte_offset, + byte_length, + ), + Type::Int16 => JS_NewInt16ArrayWithBuffer( + *cx, + heap.handle().into(), + byte_offset, + byte_length, + ), + Type::Int32 => JS_NewInt32ArrayWithBuffer( + *cx, + heap.handle().into(), + byte_offset, + byte_length, + ), + Type::Uint32 => JS_NewUint32ArrayWithBuffer( + *cx, + heap.handle().into(), + byte_offset, + byte_length, + ), + Type::Float32 => JS_NewFloat32ArrayWithBuffer( + *cx, + heap.handle().into(), + byte_offset, + byte_length, + ), + Type::Float64 => JS_NewFloat64ArrayWithBuffer( + *cx, + heap.handle().into(), + byte_offset, + byte_length, + ), + Type::Uint8Clamped => JS_NewUint8ClampedArrayWithBuffer( + *cx, + heap.handle().into(), + byte_offset, + byte_length, + ), + Type::BigInt64 => JS_NewBigInt64ArrayWithBuffer( + *cx, + heap.handle().into(), + byte_offset, + byte_length, + ), + Type::BigUint64 => JS_NewBigUint64ArrayWithBuffer( + *cx, + heap.handle().into(), + byte_offset, + byte_length, + ), + Type::Float16 => JS_NewFloat16ArrayWithBuffer( + *cx, + heap.handle().into(), byte_offset, byte_length, ), - Type::BigInt64 => { - JS_NewBigInt64ArrayWithBuffer(*cx, heap.handle(), byte_offset, byte_length) - }, - Type::BigUint64 => { - JS_NewBigUint64ArrayWithBuffer(*cx, heap.handle(), byte_offset, byte_length) - }, - Type::Float16 => { - JS_NewFloat16ArrayWithBuffer(*cx, heap.handle(), byte_offset, byte_length) - }, Type::Int64 | Type::Simd128 | Type::MaxTypedArrayViewType => { unreachable!("Invalid TypedArray type") }, @@ -755,7 +791,7 @@ fn construct_typed_array( }; Ok(HeapBufferSource::new(BufferSource::ArrayBufferView( - Heap::boxed(array_view), + RootedTraceableBox::from_box(Heap::boxed(array_view)), ))) }, BufferSource::ArrayBufferView(_) => { @@ -779,7 +815,7 @@ pub(crate) fn create_array_buffer_with_size( Err(Error::Type("can't create array buffer".to_owned())) } else { Ok(HeapBufferSource::::new( - BufferSource::ArrayBuffer(Heap::boxed(result)), + BufferSource::ArrayBuffer(RootedTraceableBox::from_box(Heap::boxed(result))), )) } } @@ -866,6 +902,7 @@ impl DataBlock { #[cfg(feature = "webgpu")] #[derive(JSTraceable, MallocSizeOf)] +#[cfg_attr(crown, allow(crown::unrooted_must_root))] pub(crate) struct DataView { #[no_trace] range: Range, diff --git a/components/script/dom/bindings/frozenarray.rs b/components/script/dom/bindings/frozenarray.rs index 17470682912..e4e5f1af03d 100644 --- a/components/script/dom/bindings/frozenarray.rs +++ b/components/script/dom/bindings/frozenarray.rs @@ -12,6 +12,7 @@ use crate::dom::bindings::utils::to_frozen_array; use crate::script_runtime::{CanGc, JSContext}; #[derive(JSTraceable)] +#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)] pub(crate) struct CachedFrozenArray { frozen_value: DomRefCell>>, } diff --git a/components/script/dom/bindings/root.rs b/components/script/dom/bindings/root.rs index daa1de2f1fe..24d291f79bf 100644 --- a/components/script/dom/bindings/root.rs +++ b/components/script/dom/bindings/root.rs @@ -30,7 +30,8 @@ use std::hash::{Hash, Hasher}; use std::marker::PhantomData; use std::{mem, ptr}; -use js::jsapi::{JSObject, JSTracer}; +use js::jsapi::{Heap, JSObject, JSTracer, Value}; +use js::rust::HandleValue; use layout_api::TrustedNodeAddress; use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; pub(crate) use script_bindings::root::*; @@ -409,3 +410,21 @@ where &*(slice as *const [Dom] as *const [LayoutDom]) } } + +/// Converts a rooted `Heap` into a `HandleValue`. +/// +/// This is only safe if the `Heap` is rooted (e.g., held inside a `Dom`-managed struct), +/// and the `#[must_root]` crown lint is active to enforce rooting at compile time. +/// Avoids repeating unsafe `from_raw` calls at each usage site. +pub trait AsHandleValue<'a> { + fn as_handle_value(&'a self) -> HandleValue<'a>; +} + +impl<'a> AsHandleValue<'a> for Heap { + #[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)] + fn as_handle_value(&'a self) -> HandleValue<'a> { + // SAFETY: `self` is assumed to be rooted, and `handle()` ties + // the lifetime to `&self`, which the compiler can enforce. + unsafe { HandleValue::from_marked_location(self.ptr.get() as *const _) } + } +} diff --git a/components/script/dom/customelementregistry.rs b/components/script/dom/customelementregistry.rs index 7c2b76086bf..18d5a59f954 100644 --- a/components/script/dom/customelementregistry.rs +++ b/components/script/dom/customelementregistry.rs @@ -14,7 +14,7 @@ use js::glue::UnwrapObjectStatic; use js::jsapi::{HandleValueArray, Heap, IsCallable, IsConstructor, JSAutoRealm, JSObject}; use js::jsval::{BooleanValue, JSVal, NullValue, ObjectValue, UndefinedValue}; use js::rust::wrappers::{Construct1, JS_GetProperty, SameValue}; -use js::rust::{HandleObject, HandleValue, MutableHandleValue}; +use js::rust::{HandleObject, MutableHandleValue}; use script_bindings::conversions::{SafeFromJSValConvertible, SafeToJSValConvertible}; use super::bindings::trace::HashMapTracedValues; @@ -32,7 +32,7 @@ use crate::dom::bindings::error::{ }; use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::reflector::{DomGlobal, DomObject, Reflector, reflect_dom_object}; -use crate::dom::bindings::root::{Dom, DomRoot}; +use crate::dom::bindings::root::{AsHandleValue, Dom, DomRoot}; use crate::dom::bindings::settings_stack::is_execution_stack_empty; use crate::dom::bindings::str::DOMString; use crate::dom::document::Document; @@ -999,7 +999,6 @@ pub(crate) enum CustomElementReaction { impl CustomElementReaction { /// - #[allow(unsafe_code)] pub(crate) fn invoke(&self, element: &Element, can_gc: CanGc) { // Step 2.1 match *self { @@ -1008,10 +1007,7 @@ impl CustomElementReaction { }, CustomElementReaction::Callback(ref callback, ref arguments) => { // We're rooted, so it's safe to hand out a handle to objects in Heap - let arguments = arguments - .iter() - .map(|arg| unsafe { HandleValue::from_raw(arg.handle()) }) - .collect(); + let arguments = arguments.iter().map(|arg| arg.as_handle_value()).collect(); rooted!(in(*GlobalScope::get_cx()) let mut value: JSVal); let _ = callback.Call_( element, @@ -1112,6 +1108,7 @@ impl CustomElementReactionStack { } /// + #[cfg_attr(crown, allow(crown::unrooted_must_root))] pub(crate) fn enqueue_callback_reaction( &self, element: &Element, diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index cbfbf630eb4..47480657324 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -422,6 +422,7 @@ impl Element { self.ensure_rare_data().custom_element_definition = None; } + #[cfg_attr(crown, allow(crown::unrooted_must_root))] pub(crate) fn push_callback_reaction(&self, function: Rc, args: Box<[Heap]>) { self.ensure_rare_data() .custom_element_reaction_queue diff --git a/components/script/dom/filereader.rs b/components/script/dom/filereader.rs index fdbef3739c8..469b6e599ff 100644 --- a/components/script/dom/filereader.rs +++ b/components/script/dom/filereader.rs @@ -115,7 +115,7 @@ pub(crate) enum FileReaderReadyState { #[derive(JSTraceable, MallocSizeOf)] pub(crate) enum FileReaderResult { - ArrayBuffer(#[ignore_malloc_size_of = "mozjs"] Heap), + ArrayBuffer(#[ignore_malloc_size_of = "mozjs"] RootedTraceableBox>), String(DOMString), } @@ -354,7 +354,8 @@ impl FileReader { .is_ok() ); - *result.borrow_mut() = Some(FileReaderResult::ArrayBuffer(Heap::default())); + *result.borrow_mut() = + Some(FileReaderResult::ArrayBuffer(RootedTraceableBox::default())); if let Some(FileReaderResult::ArrayBuffer(ref mut heap)) = *result.borrow_mut() { heap.set(jsval::ObjectValue(array_buffer.get())); diff --git a/components/script/dom/history.rs b/components/script/dom/history.rs index 149c9f66834..dc773b842b7 100644 --- a/components/script/dom/history.rs +++ b/components/script/dom/history.rs @@ -24,7 +24,7 @@ use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods; use crate::dom::bindings::error::{Error, ErrorResult, Fallible}; use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object}; -use crate::dom::bindings::root::{Dom, DomRoot}; +use crate::dom::bindings::root::{AsHandleValue, Dom, DomRoot}; use crate::dom::bindings::str::{DOMString, USVString}; use crate::dom::bindings::structuredclone; use crate::dom::event::Event; @@ -53,18 +53,18 @@ pub(crate) struct History { impl History { pub(crate) fn new_inherited(window: &Window) -> History { - let state = Heap::default(); - state.set(NullValue()); History { reflector_: Reflector::new(), window: Dom::from_ref(window), - state, + state: Heap::default(), state_id: Cell::new(None), } } pub(crate) fn new(window: &Window, can_gc: CanGc) -> DomRoot { - reflect_dom_object(Box::new(History::new_inherited(window)), window, can_gc) + let dom_root = reflect_dom_object(Box::new(History::new_inherited(window)), window, can_gc); + dom_root.state.set(NullValue()); + dom_root } } @@ -84,7 +84,6 @@ impl History { /// /// Steps 5-16 - #[allow(unsafe_code)] pub(crate) fn activate_state( &self, state_id: Option, @@ -145,7 +144,7 @@ impl History { PopStateEvent::dispatch_jsval( self.window.upcast::(), &self.window, - unsafe { HandleValue::from_raw(self.state.handle()) }, + self.state.as_handle_value(), can_gc, ); } diff --git a/components/script/dom/notification.rs b/components/script/dom/notification.rs index 18722c72898..302d09d0c1c 100644 --- a/components/script/dom/notification.rs +++ b/components/script/dom/notification.rs @@ -166,7 +166,6 @@ impl Notification { ) -> Self { // TODO: missing call to https://html.spec.whatwg.org/multipage/#structuredserializeforstorage // may be find in `dom/bindings/structuredclone.rs` - let data = Heap::default(); let title = title.clone(); let dir = options.dir; @@ -234,7 +233,7 @@ impl Notification { serviceworker_registration: None, title, body, - data, + data: Heap::default(), dir, image, icon, diff --git a/components/script/dom/promise.rs b/components/script/dom/promise.rs index b21df0a66db..e4cf374e3a9 100644 --- a/components/script/dom/promise.rs +++ b/components/script/dom/promise.rs @@ -35,6 +35,7 @@ use script_bindings::conversions::SafeToJSValConvertible; use crate::dom::bindings::conversions::root_from_object; use crate::dom::bindings::error::{Error, ErrorToJsval}; use crate::dom::bindings::reflector::{DomGlobal, DomObject, MutDomObject, Reflector}; +use crate::dom::bindings::root::AsHandleValue; use crate::dom::bindings::settings_stack::AutoEntryScript; use crate::dom::globalscope::GlobalScope; use crate::dom::promisenativehandler::{Callback, PromiseNativeHandler}; @@ -435,7 +436,6 @@ struct WaitForAllFulfillmentHandler { } impl Callback for WaitForAllFulfillmentHandler { - #[allow(unsafe_code)] fn callback(&self, _cx: SafeJSContext, v: HandleValue, _realm: InRealm, _can_gc: CanGc) { // Let fulfillmentHandler be the following steps given arg: @@ -453,15 +453,10 @@ impl Callback for WaitForAllFulfillmentHandler { // If fulfilledCount equals total, then perform successSteps given result. if equals_total { - // Safety: the values are kept alive by the Heap - // while their handles are passed to the the success steps. - let result_handles: Vec = unsafe { - self.result - .borrow() - .iter() - .map(|val| HandleValue::from_raw(val.handle())) - .collect() - }; + let result_ref = self.result.borrow(); + let result_handles: Vec = + result_ref.iter().map(|v| v.as_handle_value()).collect(); + (self.success_steps)(result_handles); } } @@ -496,6 +491,7 @@ impl Callback for WaitForAllRejectionHandler { } /// +#[cfg_attr(crown, allow(crown::unrooted_must_root))] pub(crate) fn wait_for_all( cx: SafeJSContext, global: &GlobalScope, diff --git a/components/script/dom/readablestream.rs b/components/script/dom/readablestream.rs index 2f5bd2671a0..adc45449d1e 100644 --- a/components/script/dom/readablestream.rs +++ b/components/script/dom/readablestream.rs @@ -154,7 +154,7 @@ pub(crate) struct PipeTo { /// The error potentially passed to shutdown, /// stored here because we must keep it across a microtask. #[ignore_malloc_size_of = "mozjs"] - shutdown_error: Rc>>>, + shutdown_error: Rc>>>>, /// The promise returned by a shutdown action. /// We keep it to only continue when it is not pending anymore. @@ -376,7 +376,7 @@ impl PipeTo { /// Setting shutdown error in a way that ensures it isn't /// moved after it has been set. fn set_shutdown_error(&self, error: SafeHandleValue) { - *self.shutdown_error.borrow_mut() = Some(Heap::default()); + *self.shutdown_error.borrow_mut() = Some(RootedTraceableBox::new(Heap::default())); let Some(ref heap) = *self.shutdown_error.borrow() else { unreachable!("Option set to Some(heap) above."); }; diff --git a/components/script/dom/webgpu/gpu.rs b/components/script/dom/webgpu/gpu.rs index b2534cda9a8..9ed4a55897d 100644 --- a/components/script/dom/webgpu/gpu.rs +++ b/components/script/dom/webgpu/gpu.rs @@ -6,7 +6,7 @@ use std::rc::Rc; use constellation_traits::ScriptToConstellationMessage; use dom_struct::dom_struct; -use js::jsapi::Heap; +use js::jsapi::HandleObject; use webgpu_traits::WebGPUAdapterResponse; use wgpu_types::PowerPreference; @@ -117,7 +117,7 @@ impl RoutedPromiseListener for GPU { "{} ({:?})", adapter.adapter_info.name, adapter.adapter_id.0 )), - Heap::default(), + HandleObject::null(), adapter.features, adapter.limits, adapter.adapter_info, diff --git a/components/script/dom/webgpu/gpuadapter.rs b/components/script/dom/webgpu/gpuadapter.rs index e22eca173ca..4d956d22963 100644 --- a/components/script/dom/webgpu/gpuadapter.rs +++ b/components/script/dom/webgpu/gpuadapter.rs @@ -5,7 +5,7 @@ use std::rc::Rc; use dom_struct::dom_struct; -use js::jsapi::{Heap, JSObject}; +use js::jsapi::{HandleObject, Heap, JSObject}; use webgpu_traits::{ RequestDeviceError, WebGPU, WebGPUAdapter, WebGPUDeviceResponse, WebGPURequest, }; @@ -49,7 +49,6 @@ impl GPUAdapter { fn new_inherited( channel: WebGPU, name: DOMString, - extensions: Heap<*mut JSObject>, features: &GPUSupportedFeatures, limits: &GPUSupportedLimits, info: &GPUAdapterInfo, @@ -59,7 +58,7 @@ impl GPUAdapter { reflector_: Reflector::new(), channel, name, - extensions, + extensions: Heap::default(), features: Dom::from_ref(features), limits: Dom::from_ref(limits), info: Dom::from_ref(info), @@ -72,7 +71,7 @@ impl GPUAdapter { global: &GlobalScope, channel: WebGPU, name: DOMString, - extensions: Heap<*mut JSObject>, + extensions: HandleObject, features: wgpu_types::Features, limits: wgpu_types::Limits, info: wgpu_types::AdapterInfo, @@ -82,13 +81,15 @@ impl GPUAdapter { let features = GPUSupportedFeatures::Constructor(global, None, features, can_gc).unwrap(); let limits = GPUSupportedLimits::new(global, limits, can_gc); let info = GPUAdapterInfo::new(global, info, can_gc); - reflect_dom_object( + let dom_root = reflect_dom_object( Box::new(GPUAdapter::new_inherited( - channel, name, extensions, &features, &limits, &info, adapter, + channel, name, &features, &limits, &info, adapter, )), global, can_gc, - ) + ); + dom_root.extensions.set(*extensions); + dom_root } } @@ -226,7 +227,7 @@ impl RoutedPromiseListener for GPUAdapter { &self.global(), self.channel.clone(), self, - Heap::default(), + HandleObject::null(), descriptor.required_features, descriptor.required_limits, device_id, @@ -259,7 +260,7 @@ impl RoutedPromiseListener for GPUAdapter { &self.global(), self.channel.clone(), self, - Heap::default(), + HandleObject::null(), wgpu_types::Features::default(), wgpu_types::Limits::default(), device_id, diff --git a/components/script/dom/webgpu/gpudevice.rs b/components/script/dom/webgpu/gpudevice.rs index 9fa9f044daa..e4c0673b634 100644 --- a/components/script/dom/webgpu/gpudevice.rs +++ b/components/script/dom/webgpu/gpudevice.rs @@ -9,7 +9,7 @@ use std::cell::Cell; use std::rc::Rc; use dom_struct::dom_struct; -use js::jsapi::{Heap, JSObject}; +use js::jsapi::{HandleObject, Heap, JSObject}; use webgpu_traits::{ PopError, WebGPU, WebGPUComputePipeline, WebGPUComputePipelineResponse, WebGPUDevice, WebGPUPoppedErrorScopeResponse, WebGPUQueue, WebGPURenderPipeline, @@ -114,7 +114,6 @@ impl GPUDevice { fn new_inherited( channel: WebGPU, adapter: &GPUAdapter, - extensions: Heap<*mut JSObject>, features: &GPUSupportedFeatures, limits: &GPUSupportedLimits, device: WebGPUDevice, @@ -126,7 +125,7 @@ impl GPUDevice { eventtarget: EventTarget::new_inherited(), channel, adapter: Dom::from_ref(adapter), - extensions, + extensions: Heap::default(), features: Dom::from_ref(features), limits: Dom::from_ref(limits), label: DomRefCell::new(USVString::from(label)), @@ -142,7 +141,7 @@ impl GPUDevice { global: &GlobalScope, channel: WebGPU, adapter: &GPUAdapter, - extensions: Heap<*mut JSObject>, + extensions: HandleObject, features: wgpu_types::Features, limits: wgpu_types::Limits, device: WebGPUDevice, @@ -158,7 +157,6 @@ impl GPUDevice { Box::new(GPUDevice::new_inherited( channel, adapter, - extensions, &features, &limits, device, @@ -170,6 +168,7 @@ impl GPUDevice { can_gc, ); queue.set_device(&device); + device.extensions.set(*extensions); device } } diff --git a/components/script/script_module.rs b/components/script/script_module.rs index 0c83195a2f9..918138a6b68 100644 --- a/components/script/script_module.rs +++ b/components/script/script_module.rs @@ -88,16 +88,15 @@ fn gen_type_error(global: &GlobalScope, string: String, can_gc: CanGc) -> Rethro } #[derive(JSTraceable)] -pub(crate) struct ModuleObject(Box>); +pub(crate) struct ModuleObject(RootedTraceableBox>); impl ModuleObject { fn new(obj: RustHandleObject) -> ModuleObject { - ModuleObject(Heap::boxed(obj.get())) + ModuleObject(RootedTraceableBox::from_box(Heap::boxed(obj.get()))) } - #[allow(unsafe_code)] pub(crate) fn handle(&self) -> HandleObject { - unsafe { self.0.handle() } + self.0.handle().into() } } diff --git a/components/script/timers.rs b/components/script/timers.rs index 19e004afa7d..803ee63e5ae 100644 --- a/components/script/timers.rs +++ b/components/script/timers.rs @@ -24,7 +24,7 @@ use crate::dom::bindings::codegen::Bindings::FunctionBinding::Function; use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::refcounted::Trusted; use crate::dom::bindings::reflector::{DomGlobal, DomObject}; -use crate::dom::bindings::root::Dom; +use crate::dom::bindings::root::{AsHandleValue, Dom}; use crate::dom::bindings::str::DOMString; use crate::dom::csp::CspReporting; use crate::dom::document::{ImageAnimationUpdateCallback, RefreshRedirectDue}; @@ -395,6 +395,7 @@ pub(crate) enum TimerCallback { } #[derive(Clone, JSTraceable, MallocSizeOf)] +#[cfg_attr(crown, allow(crown::unrooted_must_root))] enum InternalTimerCallback { StringTimerCallback(DOMString), FunctionTimerCallback( @@ -416,6 +417,7 @@ impl Default for JsTimers { impl JsTimers { // see https://html.spec.whatwg.org/multipage/#timer-initialisation-steps + #[cfg_attr(crown, allow(crown::unrooted_must_root))] pub(crate) fn set_timeout_or_interval( &self, global: &GlobalScope, @@ -583,13 +585,8 @@ impl JsTimerTask { } } - // Returning Handles directly from Heap values is inherently unsafe, but here it's - // always done via rooted JsTimers, which is safe. - #[allow(unsafe_code)] fn collect_heap_args<'b>(&self, args: &'b [Heap]) -> Vec> { - args.iter() - .map(|arg| unsafe { HandleValue::from_raw(arg.handle()) }) - .collect() + args.iter().map(|arg| arg.as_handle_value()).collect() } } diff --git a/components/script_bindings/codegen/codegen.py b/components/script_bindings/codegen/codegen.py index c72cce0131a..0f278fbdddb 100644 --- a/components/script_bindings/codegen/codegen.py +++ b/components/script_bindings/codegen/codegen.py @@ -955,39 +955,51 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, if is_typed_array(type): if failureCode is None: - unwrapFailureCode = (f'throw_type_error(*cx, "{sourceDescription} is not a typed array.");\n' - f'{exceptionCode}') + unwrapFailureCode = ( + f'throw_type_error(*cx, "{sourceDescription} is not a typed array.");\n' + f'{exceptionCode}' + ) else: unwrapFailureCode = failureCode typeName = type.unroll().name # unroll because it may be nullable - if isMember == "Union": + is_union_member = (isMember == "Union") + + if is_union_member: typeName = f"Heap{typeName}" + map_call = ".map(RootedTraceableBox::new)" + else: + map_call = "" templateBody = fill( - """ - match typedarray::${ty}::from($${val}.get().to_object()) { + f""" + match typedarray::${{ty}}::from($${{val}}.get().to_object()){map_call} {{ Ok(val) => val, - Err(()) => { - $*{failureCode} - } - } + Err(()) => {{ + $*{{failureCode}} + }} + }} """, ty=typeName, failureCode=f"{unwrapFailureCode}\n", ) - if isMember == "Union": - templateBody = f"RootedTraceableBox::new({templateBody})" - declType = CGGeneric(f"typedarray::{typeName}") + if is_union_member: + declType = CGWrapper(declType, pre="RootedTraceableBox<", post=">") + if type.nullable(): templateBody = f"Some({templateBody})" declType = CGWrapper(declType, pre="Option<", post=">") - templateBody = wrapObjectTemplate(templateBody, "None", - isDefinitelyObject, type, failureCode) + templateBody = wrapObjectTemplate( + templateBody, + "None", + isDefinitelyObject, + type, + failureCode, + ) return handleOptional(templateBody, declType, handleDefault("None"))