From 80fc64d0631244b4e165ecd1151b079bdfc2a2a4 Mon Sep 17 00:00:00 2001 From: Arya Nair Date: Wed, 26 Mar 2025 00:54:47 +0530 Subject: [PATCH] feat: add CanGc argument in get_dictionary_property (#36156) * feat: add CanGc argument in get_dictionary_property Signed-off-by: Arya Nair * feat: add CanGc argument in get_dictionary_property Signed-off-by: Arya Nair --------- Signed-off-by: Arya Nair --- components/script/body.rs | 8 +++---- components/script/dom/bindings/utils.rs | 1 + .../script/dom/bytelengthqueuingstrategy.rs | 3 ++- components/script/dom/readablestream.rs | 23 ++++++++++++++----- .../script/dom/readablestreamdefaultreader.rs | 4 ++-- .../script_bindings/codegen/CodegenRust.py | 5 ++-- 6 files changed, 29 insertions(+), 15 deletions(-) diff --git a/components/script/body.rs b/components/script/body.rs index 1a62556332f..c55e67d8add 100644 --- a/components/script/body.rs +++ b/components/script/body.rs @@ -282,7 +282,7 @@ struct TransmitBodyPromiseHandler { impl Callback for TransmitBodyPromiseHandler { /// Step 5 of fn callback(&self, cx: JSContext, v: HandleValue, _realm: InRealm, can_gc: CanGc) { - let is_done = match get_read_promise_done(cx, &v) { + let is_done = match get_read_promise_done(cx, &v, can_gc) { Ok(is_done) => is_done, Err(_) => { // Step 5.5, the "otherwise" steps. @@ -299,7 +299,7 @@ impl Callback for TransmitBodyPromiseHandler { return self.stream.stop_reading(can_gc); } - let chunk = match get_read_promise_bytes(cx, &v) { + let chunk = match get_read_promise_bytes(cx, &v, can_gc) { Ok(chunk) => chunk, Err(_) => { // Step 5.5, the "otherwise" steps. @@ -660,7 +660,7 @@ impl Callback for ConsumeBodyPromiseHandler { .as_ref() .expect("ConsumeBodyPromiseHandler has no stream in callback."); - let is_done = match get_read_promise_done(cx, &v) { + let is_done = match get_read_promise_done(cx, &v, can_gc) { Ok(is_done) => is_done, Err(err) => { stream.stop_reading(can_gc); @@ -673,7 +673,7 @@ impl Callback for ConsumeBodyPromiseHandler { // When read is fulfilled with an object whose done property is true. self.resolve_result_promise(cx, can_gc); } else { - let chunk = match get_read_promise_bytes(cx, &v) { + let chunk = match get_read_promise_bytes(cx, &v, can_gc) { Ok(chunk) => chunk, Err(err) => { stream.stop_reading(can_gc); diff --git a/components/script/dom/bindings/utils.rs b/components/script/dom/bindings/utils.rs index 9431c79d000..1fb26186d2e 100644 --- a/components/script/dom/bindings/utils.rs +++ b/components/script/dom/bindings/utils.rs @@ -303,6 +303,7 @@ pub(crate) fn get_dictionary_property( object: HandleObject, property: &str, rval: MutableHandleValue, + _can_gc: CanGc, ) -> Result { fn has_property( cx: *mut JSContext, diff --git a/components/script/dom/bytelengthqueuingstrategy.rs b/components/script/dom/bytelengthqueuingstrategy.rs index 3be16eb1599..adbe6667fd9 100644 --- a/components/script/dom/bytelengthqueuingstrategy.rs +++ b/components/script/dom/bytelengthqueuingstrategy.rs @@ -78,7 +78,7 @@ impl ByteLengthQueuingStrategyMethods for ByteLengthQueuin let fun = native_fn!(byte_length_queuing_strategy_size, c"size", 1, 0); // Step 3. Set globalObject’s byte length queuing strategy size function to // a Function that represents a reference to F, - // with callback context equal to globalObject’s relevant settings object. + // with callback context equal to globalObject's relevant settings object. global.set_byte_length_queuing_strategy_size(fun.clone()); Ok(fun) } @@ -109,6 +109,7 @@ pub(crate) unsafe fn byte_length_queuing_strategy_size( object.handle(), "byteLength", MutableHandleValue::from_raw(args.rval()), + CanGc::note(), ) .unwrap_or(false) } diff --git a/components/script/dom/readablestream.rs b/components/script/dom/readablestream.rs index 6f2fe166820..f8b23072e66 100644 --- a/components/script/dom/readablestream.rs +++ b/components/script/dom/readablestream.rs @@ -197,8 +197,14 @@ impl Callback for PipeTo { } else { rooted!(in(*cx) let object = result.to_object()); rooted!(in(*cx) let mut done = UndefinedValue()); - get_dictionary_property(*cx, object.handle(), "done", done.handle_mut()) - .unwrap() + get_dictionary_property( + *cx, + object.handle(), + "done", + done.handle_mut(), + can_gc, + ) + .unwrap() } }; // If any chunks have been read but not yet written, write them to dest. @@ -347,7 +353,7 @@ impl PipeTo { rooted!(in(*cx) let object = chunk.to_object()); rooted!(in(*cx) let mut bytes = UndefinedValue()); let has_value = - get_dictionary_property(*cx, object.handle(), "value", bytes.handle_mut()) + get_dictionary_property(*cx, object.handle(), "value", bytes.handle_mut(), can_gc) .expect("Chunk should have a value."); if !bytes.is_undefined() && has_value { // Write the chunk. @@ -1932,14 +1938,18 @@ impl ReadableStreamMethods for ReadableStream { #[allow(unsafe_code)] /// Get the `done` property of an object that a read promise resolved to. -pub(crate) fn get_read_promise_done(cx: SafeJSContext, v: &SafeHandleValue) -> Result { +pub(crate) fn get_read_promise_done( + cx: SafeJSContext, + v: &SafeHandleValue, + can_gc: CanGc, +) -> Result { if !v.is_object() { return Err(Error::Type("Unknown format for done property.".to_string())); } unsafe { rooted!(in(*cx) let object = v.to_object()); rooted!(in(*cx) let mut done = UndefinedValue()); - match get_dictionary_property(*cx, object.handle(), "done", done.handle_mut()) { + match get_dictionary_property(*cx, object.handle(), "done", done.handle_mut(), can_gc) { Ok(true) => match bool::from_jsval(*cx, done.handle(), ()) { Ok(ConversionResult::Success(val)) => Ok(val), Ok(ConversionResult::Failure(error)) => Err(Error::Type(error.to_string())), @@ -1956,6 +1966,7 @@ pub(crate) fn get_read_promise_done(cx: SafeJSContext, v: &SafeHandleValue) -> R pub(crate) fn get_read_promise_bytes( cx: SafeJSContext, v: &SafeHandleValue, + can_gc: CanGc, ) -> Result, Error> { if !v.is_object() { return Err(Error::Type( @@ -1965,7 +1976,7 @@ pub(crate) fn get_read_promise_bytes( unsafe { rooted!(in(*cx) let object = v.to_object()); rooted!(in(*cx) let mut bytes = UndefinedValue()); - match get_dictionary_property(*cx, object.handle(), "value", bytes.handle_mut()) { + match get_dictionary_property(*cx, object.handle(), "value", bytes.handle_mut(), can_gc) { Ok(true) => { match Vec::::from_jsval(*cx, bytes.handle(), ConversionBehavior::EnforceRange) { Ok(ConversionResult::Success(val)) => Ok(val), diff --git a/components/script/dom/readablestreamdefaultreader.rs b/components/script/dom/readablestreamdefaultreader.rs index 32eb9cfe621..65a63626287 100644 --- a/components/script/dom/readablestreamdefaultreader.rs +++ b/components/script/dom/readablestreamdefaultreader.rs @@ -60,7 +60,7 @@ impl Callback for ReadLoopFulFillmentHandler { #[cfg_attr(crown, allow(crown::unrooted_must_root))] fn callback(&self, cx: SafeJSContext, v: SafeHandleValue, realm: InRealm, can_gc: CanGc) { let global = self.reader.global(); - let is_done = match get_read_promise_done(cx, &v) { + let is_done = match get_read_promise_done(cx, &v, can_gc) { Ok(is_done) => is_done, Err(err) => { self.reader @@ -82,7 +82,7 @@ impl Callback for ReadLoopFulFillmentHandler { .expect("Releasing the reader should succeed"); } else { // - let chunk = match get_read_promise_bytes(cx, &v) { + let chunk = match get_read_promise_bytes(cx, &v, can_gc) { Ok(chunk) => chunk, Err(err) => { // If chunk is not a Uint8Array object, call failureSteps with a TypeError and abort these steps. diff --git a/components/script_bindings/codegen/CodegenRust.py b/components/script_bindings/codegen/CodegenRust.py index f7539d5b24d..adb9accf892 100644 --- a/components/script_bindings/codegen/CodegenRust.py +++ b/components/script_bindings/codegen/CodegenRust.py @@ -7394,8 +7394,9 @@ impl{self.generic} Clone for {self.makeClassName(self.dictionary)}{self.genericS conversion = ( "{\n" " rooted!(in(*cx) let mut rval = UndefinedValue());\n" - f' if get_dictionary_property(*cx, object.handle(), "{member.identifier.name}", rval.handle_mut())?' - " && !rval.is_undefined() {\n" + " if get_dictionary_property(*cx, object.handle(), " + f'"{member.identifier.name}", ' + "rval.handle_mut(), CanGc::note())? && !rval.is_undefined() {\n" f"{indent(conversion)}\n" " } else {\n" f"{indent(default)}\n"