From 9584b9e57d8d1bdcd69eacbdfd9ba93ac149f90b Mon Sep 17 00:00:00 2001 From: lumiscosity Date: Mon, 8 Sep 2025 11:21:42 +0200 Subject: [PATCH] script: Add can_gc to WebIDL dictionary constructors (#39195) More progress on can_gc! Testing: Internal change only, shouldn't change behavior. Fixes: #38708 --------- Signed-off-by: lumiscosity --- components/script/dom/bluetooth/bluetooth.rs | 3 ++- components/script/dom/html/htmlcanvaselement.rs | 12 ++++++++---- components/script/dom/permissions.rs | 9 ++++++--- components/script/dom/readablestream.rs | 2 +- components/script/dom/subtlecrypto.rs | 5 +++-- components/script/dom/transformstream.rs | 2 +- components/script/dom/writablestream.rs | 2 +- components/script_bindings/codegen/codegen.py | 8 ++++---- 8 files changed, 26 insertions(+), 17 deletions(-) diff --git a/components/script/dom/bluetooth/bluetooth.rs b/components/script/dom/bluetooth/bluetooth.rs index 02bcadaee92..90b53d5bf52 100644 --- a/components/script/dom/bluetooth/bluetooth.rs +++ b/components/script/dom/bluetooth/bluetooth.rs @@ -635,12 +635,13 @@ impl PermissionAlgorithm for Bluetooth { fn create_descriptor( cx: JSContext, permission_descriptor_obj: *mut JSObject, + can_gc: CanGc, ) -> Result { rooted!(in(*cx) let mut property = UndefinedValue()); property .handle_mut() .set(ObjectValue(permission_descriptor_obj)); - match BluetoothPermissionDescriptor::new(cx, property.handle()) { + match BluetoothPermissionDescriptor::new(cx, property.handle(), can_gc) { Ok(ConversionResult::Success(descriptor)) => Ok(descriptor), Ok(ConversionResult::Failure(error)) => Err(Error::Type(error.into_owned())), Err(_) => Err(Error::Type(String::from(BT_DESC_CONVERSION_ERROR))), diff --git a/components/script/dom/html/htmlcanvaselement.rs b/components/script/dom/html/htmlcanvaselement.rs index a0e5456aa67..1f932078eb4 100644 --- a/components/script/dom/html/htmlcanvaselement.rs +++ b/components/script/dom/html/htmlcanvaselement.rs @@ -260,7 +260,7 @@ impl HTMLCanvasElement { let canvas = RootedHTMLCanvasElementOrOffscreenCanvas::HTMLCanvasElement(DomRoot::from_ref(self)); let size = self.get_size(); - let attrs = Self::get_gl_attributes(cx, options)?; + let attrs = Self::get_gl_attributes(cx, options, can_gc)?; let context = WebGLRenderingContext::new( &window, &canvas, @@ -293,7 +293,7 @@ impl HTMLCanvasElement { let canvas = RootedHTMLCanvasElementOrOffscreenCanvas::HTMLCanvasElement(DomRoot::from_ref(self)); let size = self.get_size(); - let attrs = Self::get_gl_attributes(cx, options)?; + let attrs = Self::get_gl_attributes(cx, options, can_gc)?; let context = WebGL2RenderingContext::new(&window, &canvas, size, attrs, can_gc)?; *self.context_mode.borrow_mut() = Some(RenderingContext::WebGL2(Dom::from_ref(&*context))); Some(context) @@ -338,9 +338,13 @@ impl HTMLCanvasElement { } #[allow(unsafe_code)] - fn get_gl_attributes(cx: JSContext, options: HandleValue) -> Option { + fn get_gl_attributes( + cx: JSContext, + options: HandleValue, + can_gc: CanGc, + ) -> Option { unsafe { - match WebGLContextAttributes::new(cx, options) { + match WebGLContextAttributes::new(cx, options, can_gc) { Ok(ConversionResult::Success(attrs)) => Some(attrs.convert()), Ok(ConversionResult::Failure(error)) => { throw_type_error(*cx, &error); diff --git a/components/script/dom/permissions.rs b/components/script/dom/permissions.rs index 852c8d4ab82..27dbba9ae41 100644 --- a/components/script/dom/permissions.rs +++ b/components/script/dom/permissions.rs @@ -40,6 +40,7 @@ pub(crate) trait PermissionAlgorithm { fn create_descriptor( cx: JSContext, permission_descriptor_obj: *mut JSObject, + can_gc: CanGc, ) -> Result; fn permission_query( cx: JSContext, @@ -101,7 +102,7 @@ impl Permissions { }; // (Query, Request, Revoke) Step 1. - let root_desc = match Permissions::create_descriptor(cx, permissionDesc) { + let root_desc = match Permissions::create_descriptor(cx, permissionDesc, can_gc) { Ok(descriptor) => descriptor, Err(error) => { p.reject_error(error, can_gc); @@ -116,7 +117,8 @@ impl Permissions { match root_desc.name { #[cfg(feature = "bluetooth")] PermissionName::Bluetooth => { - let bluetooth_desc = match Bluetooth::create_descriptor(cx, permissionDesc) { + let bluetooth_desc = match Bluetooth::create_descriptor(cx, permissionDesc, can_gc) + { Ok(descriptor) => descriptor, Err(error) => { p.reject_error(error, can_gc); @@ -221,12 +223,13 @@ impl PermissionAlgorithm for Permissions { fn create_descriptor( cx: JSContext, permission_descriptor_obj: *mut JSObject, + can_gc: CanGc, ) -> Result { rooted!(in(*cx) let mut property = UndefinedValue()); property .handle_mut() .set(ObjectValue(permission_descriptor_obj)); - match PermissionDescriptor::new(cx, property.handle()) { + match PermissionDescriptor::new(cx, property.handle(), can_gc) { Ok(ConversionResult::Success(descriptor)) => Ok(descriptor), Ok(ConversionResult::Failure(error)) => Err(Error::Type(error.into_owned())), Err(_) => Err(Error::JSFailed), diff --git a/components/script/dom/readablestream.rs b/components/script/dom/readablestream.rs index 833ed565f77..b68e3de63c5 100644 --- a/components/script/dom/readablestream.rs +++ b/components/script/dom/readablestream.rs @@ -1973,7 +1973,7 @@ impl ReadableStreamMethods for ReadableStream { // converted to an IDL value of type UnderlyingSource. let underlying_source_dict = if !underlying_source_obj.is_null() { rooted!(in(*cx) let obj_val = ObjectValue(underlying_source_obj.get())); - match JsUnderlyingSource::new(cx, obj_val.handle()) { + match JsUnderlyingSource::new(cx, obj_val.handle(), can_gc) { Ok(ConversionResult::Success(val)) => val, Ok(ConversionResult::Failure(error)) => return Err(Error::Type(error.to_string())), _ => { diff --git a/components/script/dom/subtlecrypto.rs b/components/script/dom/subtlecrypto.rs index d8adb77d820..3b8a5686c0b 100644 --- a/components/script/dom/subtlecrypto.rs +++ b/components/script/dom/subtlecrypto.rs @@ -1405,7 +1405,8 @@ enum KeyWrapAlgorithm { macro_rules! value_from_js_object { ($t: ty, $cx: ident, $value: ident) => {{ - let params_result = <$t>::new($cx, $value.handle()).map_err(|_| Error::JSFailed)?; + let params_result = + <$t>::new($cx, $value.handle(), CanGc::note()).map_err(|_| Error::JSFailed)?; let ConversionResult::Success(params) = params_result else { return Err(Error::Syntax(None)); }; @@ -3218,7 +3219,7 @@ impl JsonWebKeyExt for JsonWebKey { } // Step 5. Let key be the result of converting result to the IDL dictionary type of JsonWebKey. - let key = match JsonWebKey::new(cx, result.handle()) { + let key = match JsonWebKey::new(cx, result.handle(), CanGc::note()) { Ok(ConversionResult::Success(key)) => key, Ok(ConversionResult::Failure(error)) => { return Err(Error::Type(error.to_string())); diff --git a/components/script/dom/transformstream.rs b/components/script/dom/transformstream.rs index 5865c3d88fb..6fc79bf5d75 100644 --- a/components/script/dom/transformstream.rs +++ b/components/script/dom/transformstream.rs @@ -968,7 +968,7 @@ impl TransformStreamMethods for TransformStream { // converted to an IDL value of type UnderlyingSink. let transformer_dict = if !transformer_obj.is_null() { rooted!(in(*cx) let obj_val = ObjectValue(transformer_obj.get())); - match Transformer::new(cx, obj_val.handle()) { + match Transformer::new(cx, obj_val.handle(), can_gc) { Ok(ConversionResult::Success(val)) => val, Ok(ConversionResult::Failure(error)) => return Err(Error::Type(error.to_string())), _ => { diff --git a/components/script/dom/writablestream.rs b/components/script/dom/writablestream.rs index 8c953463c14..5592cc500d7 100644 --- a/components/script/dom/writablestream.rs +++ b/components/script/dom/writablestream.rs @@ -1025,7 +1025,7 @@ impl WritableStreamMethods for WritableStream { // converted to an IDL value of type UnderlyingSink. let underlying_sink_dict = if !underlying_sink_obj.is_null() { rooted!(in(*cx) let obj_val = ObjectValue(underlying_sink_obj.get())); - match UnderlyingSink::new(cx, obj_val.handle()) { + match UnderlyingSink::new(cx, obj_val.handle(), can_gc) { Ok(ConversionResult::Success(val)) => val, Ok(ConversionResult::Failure(error)) => return Err(Error::Type(error.to_string())), _ => { diff --git a/components/script_bindings/codegen/codegen.py b/components/script_bindings/codegen/codegen.py index c4cc51e124c..7f5548120c1 100644 --- a/components/script_bindings/codegen/codegen.py +++ b/components/script_bindings/codegen/codegen.py @@ -7523,7 +7523,7 @@ impl{self.generic} Clone for {self.makeClassName(self.dictionary)}{self.genericS assert isinstance(d.parent, IDLDictionary) initParent = ( "{\n" - f" match {self.makeModuleName(d.parent)}::{self.makeClassName(d.parent)}::new(cx, val)? {{\n" + f" match {self.makeModuleName(d.parent)}::{self.makeClassName(d.parent)}::new(cx, val, can_gc)? {{\n" " ConversionResult::Success(v) => v,\n" " ConversionResult::Failure(error) => {\n" " throw_type_error(*cx, &error);\n" @@ -7582,7 +7582,7 @@ impl{self.generic} Clone for {self.makeClassName(self.dictionary)}{self.genericS return ( f"impl{self.generic} {selfName}{self.genericSuffix} {{\n" f"{CGIndenter(CGGeneric(self.makeEmpty()), indentLevel=4).define()}\n" - " pub fn new(cx: SafeJSContext, val: HandleValue) \n" + " pub fn new(cx: SafeJSContext, val: HandleValue, can_gc: CanGc) \n" f" -> Result, ()> {{\n" f" {unsafe_if_necessary} {{\n" " let object = if val.get().is_null_or_undefined() {\n" @@ -7606,7 +7606,7 @@ impl{self.generic} Clone for {self.makeClassName(self.dictionary)}{self.genericS " type Config = ();\n" " unsafe fn from_jsval(cx: *mut JSContext, value: HandleValue, _option: ())\n" f" -> Result, ()> {{\n" - f" {selfName}::new(SafeJSContext::from_ptr(cx), value)\n" + f" {selfName}::new(SafeJSContext::from_ptr(cx), value, CanGc::note())\n" " }\n" "}\n" "\n" @@ -7675,7 +7675,7 @@ impl{self.generic} Clone for {self.makeClassName(self.dictionary)}{self.genericS " rooted!(in(*cx) let mut rval = UndefinedValue());\n" " if get_dictionary_property(*cx, object.handle(), " f'"{member.identifier.name}", ' - "rval.handle_mut(), CanGc::note())? && !rval.is_undefined() {\n" + "rval.handle_mut(), can_gc)? && !rval.is_undefined() {\n" f"{indent(conversion)}\n" " } else {\n" f"{indent(default)}\n"