diff options
author | Taym Haddadi <haddadi.taym@gmail.com> | 2024-07-10 17:51:22 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-07-10 23:51:22 +0800 |
commit | fa1578f2677aa90e0914c2f9642890f9e7275b74 (patch) | |
tree | df4999fa2a45370b732435071eb70ba0ea5cff9c | |
parent | 2506d36e857b3f871c528d4f499482acbacafd45 (diff) | |
download | servo-fa1578f2677aa90e0914c2f9642890f9e7275b74.tar.gz servo-fa1578f2677aa90e0914c2f9642890f9e7275b74.zip |
Create safe wrapper for JSFunctions (#32620)
* Create safe wrapper for JSFunctions
Signed-off-by: Bentaimia Haddadi <haddadi.taym@gmail.com>
* Add assert to check if the name ends in a null character
Signed-off-by: Bentaimia Haddadi <haddadi.taym@gmail.com>
* Create macro to wrap unsafe extern "C" function calls
Signed-off-by: Bentaimia Haddadi <haddadi.taym@gmail.com>
* Remove WRAPPER_FN
Signed-off-by: Bentaimia Haddadi <haddadi.taym@gmail.com>
* Add macro example documentation
Signed-off-by: Bentaimia Haddadi <haddadi.taym@gmail.com>
* Use C-string literals
Signed-off-by: Bentaimia Haddadi <haddadi.taym@gmail.com>
* Ensure name is Cstr type
Signed-off-by: Bentaimia Haddadi <haddadi.taym@gmail.com>
* Scope #[allow(unsafe_code)]
Signed-off-by: Bentaimia Haddadi <haddadi.taym@gmail.com>
---------
Signed-off-by: Bentaimia Haddadi <haddadi.taym@gmail.com>
-rw-r--r-- | components/script/dom/bindings/function.rs | 48 | ||||
-rw-r--r-- | components/script/dom/bindings/mod.rs | 1 | ||||
-rw-r--r-- | components/script/dom/bytelengthqueuingstrategy.rs | 41 | ||||
-rw-r--r-- | components/script/dom/countqueuingstrategy.rs | 74 |
4 files changed, 81 insertions, 83 deletions
diff --git a/components/script/dom/bindings/function.rs b/components/script/dom/bindings/function.rs new file mode 100644 index 00000000000..a60e0d9f4ba --- /dev/null +++ b/components/script/dom/bindings/function.rs @@ -0,0 +1,48 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/// Defines a macro `native_fn!` to create a JavaScript function from a Rust function pointer. +/// # Example +/// ``` +/// let js_function: Rc<Function> = native_fn!(my_rust_function, c"myFunction", 2, 0); +/// ``` +#[macro_export] +macro_rules! native_fn { + ($call:expr, $name:expr, $nargs:expr, $flags:expr) => {{ + let cx = crate::dom::types::GlobalScope::get_cx(); + let fun_obj = crate::native_raw_obj_fn!(cx, $call, $name, $nargs, $flags); + #[allow(unsafe_code)] + unsafe { + Function::new(cx, fun_obj) + } + }}; +} + +/// Defines a macro `native_raw_obj_fn!` to create a raw JavaScript function object. +/// # Example +/// ``` +/// let raw_function_obj: *mut JSObject = native_raw_obj_fn!(cx, my_rust_function, c"myFunction", 2, 0); +/// ``` +#[macro_export] +macro_rules! native_raw_obj_fn { + ($cx:expr, $call:expr, $name:expr, $nargs:expr, $flags:expr) => {{ + #[allow(unsafe_code)] + unsafe extern "C" fn wrapper(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool { + $call(cx, argc, vp) + } + #[allow(unsafe_code)] + unsafe { + let name: &std::ffi::CStr = $name; + let raw_fun = crate::dom::bindings::import::module::jsapi::JS_NewFunction( + *$cx, + Some(wrapper), + $nargs, + $flags, + name.as_ptr() as *const std::ffi::c_char, + ); + assert!(!raw_fun.is_null()); + crate::dom::bindings::import::module::jsapi::JS_GetFunctionObject(raw_fun) + } + }}; +} diff --git a/components/script/dom/bindings/mod.rs b/components/script/dom/bindings/mod.rs index e31d79cc494..81b3b403947 100644 --- a/components/script/dom/bindings/mod.rs +++ b/components/script/dom/bindings/mod.rs @@ -141,6 +141,7 @@ pub mod constant; pub mod conversions; pub mod error; pub mod finalize; +pub mod function; pub mod guard; pub mod htmlconstructor; pub mod import; diff --git a/components/script/dom/bytelengthqueuingstrategy.rs b/components/script/dom/bytelengthqueuingstrategy.rs index 07cdcbef710..88f65c363bf 100644 --- a/components/script/dom/bytelengthqueuingstrategy.rs +++ b/components/script/dom/bytelengthqueuingstrategy.rs @@ -2,12 +2,11 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use std::ffi::c_char; use std::rc::Rc; use dom_struct::dom_struct; use js::gc::{HandleValue, MutableHandleValue}; -use js::jsapi::{CallArgs, JSContext, JS_GetFunctionObject, JS_NewFunction}; +use js::jsapi::{CallArgs, JSContext}; use js::jsval::JSVal; use js::rust::HandleObject; @@ -15,11 +14,11 @@ use super::bindings::codegen::Bindings::FunctionBinding::Function; use super::bindings::codegen::Bindings::QueuingStrategyBinding::{ ByteLengthQueuingStrategyMethods, QueuingStrategyInit, }; -use super::bindings::import::module::{ - get_dictionary_property, DomObject, DomRoot, Fallible, Reflector, -}; +use super::bindings::import::module::{DomObject, DomRoot, Fallible, Reflector}; use super::bindings::reflector::reflect_dom_object_with_proto; use super::types::GlobalScope; +use crate::dom::bindings::import::module::get_dictionary_property; +use crate::native_fn; #[dom_struct] pub struct ByteLengthQueuingStrategy { @@ -56,11 +55,9 @@ impl ByteLengthQueuingStrategyMethods for ByteLengthQueuingStrategy { self.high_water_mark } - #[allow(unsafe_code)] /// <https://streams.spec.whatwg.org/#blqs-size> fn GetSize(&self) -> Fallible<Rc<Function>> { let global = self.reflector_.global(); - let cx = GlobalScope::get_cx(); // Return this's relevant global object's byte length queuing strategy // size function. if let Some(fun) = global.get_byte_length_queuing_strategy_size() { @@ -70,32 +67,20 @@ impl ByteLengthQueuingStrategyMethods for ByteLengthQueuingStrategy { // Step 1. Let steps be the following steps, given chunk // Note: See ByteLengthQueuingStrategySize instead. - unsafe { - // Step 2. Let F be !CreateBuiltinFunction(steps, 1, "size", « », - // globalObject’s relevant Realm). - let raw_fun = JS_NewFunction( - *cx, - Some(byte_length_queuing_strategy_size), - 1, - 0, - b"size\0".as_ptr() as *const c_char, - ); - assert!(!raw_fun.is_null()); - - // 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. - let fun_obj = JS_GetFunctionObject(raw_fun); - let fun = Function::new(cx, fun_obj); - global.set_byte_length_queuing_strategy_size(fun.clone()); - Ok(fun) - } + // Step 2. Let F be !CreateBuiltinFunction(steps, 1, "size", « », + // globalObject’s relevant Realm). + 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. + global.set_byte_length_queuing_strategy_size(fun.clone()); + Ok(fun) } } /// <https://streams.spec.whatwg.org/#byte-length-queuing-strategy-size-function> #[allow(unsafe_code)] -unsafe extern "C" fn byte_length_queuing_strategy_size( +pub unsafe fn byte_length_queuing_strategy_size( cx: *mut JSContext, argc: u32, vp: *mut JSVal, diff --git a/components/script/dom/countqueuingstrategy.rs b/components/script/dom/countqueuingstrategy.rs index 96b8bd699c1..01090b9a6c6 100644 --- a/components/script/dom/countqueuingstrategy.rs +++ b/components/script/dom/countqueuingstrategy.rs @@ -2,11 +2,10 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use std::ffi::c_char; use std::rc::Rc; use dom_struct::dom_struct; -use js::jsapi::{CallArgs, JSContext, JS_GetFunctionObject, JS_NewFunction}; +use js::jsapi::{CallArgs, JSContext}; use js::jsval::{Int32Value, JSVal}; use js::rust::HandleObject; @@ -16,7 +15,9 @@ use super::bindings::codegen::Bindings::QueuingStrategyBinding::{ }; use super::bindings::import::module::{DomObject, DomRoot, Error, Fallible, Reflector}; use super::bindings::reflector::reflect_dom_object_with_proto; +use super::bytelengthqueuingstrategy::byte_length_queuing_strategy_size; use super::types::GlobalScope; +use crate::{native_fn, native_raw_obj_fn}; #[dom_struct] pub struct CountQueuingStrategy { @@ -53,51 +54,32 @@ impl CountQueuingStrategyMethods for CountQueuingStrategy { self.high_water_mark } - #[allow(unsafe_code)] /// <https://streams.spec.whatwg.org/#cqs-size> fn GetSize(&self) -> Fallible<Rc<Function>> { let global = self.reflector_.global(); - let cx = GlobalScope::get_cx(); // Return this's relevant global object's count queuing strategy // size function. if let Some(fun) = global.get_count_queuing_strategy_size() { return Ok(fun); } - // Step 1. Let steps be the following steps: - // Note: See count_queuing_strategy_size instead. - - unsafe { - // Step 2. Let F be - // ! CreateBuiltinFunction(steps, 0, "size", « », - // globalObject’s relevant Realm). - let raw_fun = JS_NewFunction( - *cx, - Some(count_queuing_strategy_size), - 0, - 0, - b"size\0".as_ptr() as *const c_char, - ); - assert!(!raw_fun.is_null()); - - // Step 3. Set globalObject’s count queuing strategy size function to - // a Function that represents a reference to F, - // with callback context equal to globalObject’s relevant settings object. - let fun_obj = JS_GetFunctionObject(raw_fun); - let fun = Function::new(cx, fun_obj); - global.set_count_queuing_strategy_size(fun.clone()); - Ok(fun) - } + // Step 1. Let steps be the following steps, given chunk + // Note: See ByteLengthQueuingStrategySize instead. + + // Step 2. Let F be !CreateBuiltinFunction(steps, 1, "size", « », + // globalObject’s relevant Realm). + let fun = native_fn!(byte_length_queuing_strategy_size, c"size", 0, 0); + // Step 3. Set globalObject’s count queuing strategy size function to + // a Function that represents a reference to F, + // with callback context equal to globalObject’s relevant settings object. + global.set_count_queuing_strategy_size(fun.clone()); + Ok(fun) } } /// <https://streams.spec.whatwg.org/#count-queuing-strategy-size-function> #[allow(unsafe_code)] -unsafe extern "C" fn count_queuing_strategy_size( - _cx: *mut JSContext, - argc: u32, - vp: *mut JSVal, -) -> bool { +pub unsafe fn count_queuing_strategy_size(_cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool { let args = CallArgs::from_vp(vp, argc); // Step 1.1. Return 1. args.rval().set(Int32Value(1)); @@ -129,30 +111,12 @@ pub fn extract_high_water_mark(strategy: &QueuingStrategy, default_hwm: f64) -> /// <https://streams.spec.whatwg.org/#make-size-algorithm-from-size-function> pub fn extract_size_algorithm(strategy: &QueuingStrategy) -> Rc<QueuingStrategySize> { if strategy.size.is_none() { - #[allow(unsafe_code)] - unsafe extern "C" fn fallback_strategy_size( - _cx: *mut JSContext, - argc: u32, - vp: *mut JSVal, - ) -> bool { - let args = CallArgs::from_vp(vp, argc); - args.rval().set(Int32Value(1)); - true - } + let cx = GlobalScope::get_cx(); + let fun_obj = native_raw_obj_fn!(cx, count_queuing_strategy_size, c"size", 0, 0); #[allow(unsafe_code)] unsafe { - let cx = GlobalScope::get_cx(); - let raw_fun = JS_NewFunction( - *cx, - Some(fallback_strategy_size), - 0, - 0, - b"size\0".as_ptr() as *const c_char, - ); - assert!(!raw_fun.is_null()); - let fun_obj = JS_GetFunctionObject(raw_fun); - return QueuingStrategySize::new(cx, fun_obj).clone(); - } + QueuingStrategySize::new(cx, fun_obj).clone() + }; } strategy.size.as_ref().unwrap().clone() } |