aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTaym Haddadi <haddadi.taym@gmail.com>2024-07-10 17:51:22 +0200
committerGitHub <noreply@github.com>2024-07-10 23:51:22 +0800
commitfa1578f2677aa90e0914c2f9642890f9e7275b74 (patch)
treedf4999fa2a45370b732435071eb70ba0ea5cff9c
parent2506d36e857b3f871c528d4f499482acbacafd45 (diff)
downloadservo-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.rs48
-rw-r--r--components/script/dom/bindings/mod.rs1
-rw-r--r--components/script/dom/bytelengthqueuingstrategy.rs41
-rw-r--r--components/script/dom/countqueuingstrategy.rs74
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()
}