script: introduce safe wrappers for js val conversions (#38004)

Introduce a safe wrapper trait for the unsafe `ToJSValConvertible`, and
use it in `script/dom` where the default `T` implementation works.

Part of https://github.com/servo/servo/issues/37951

---------

Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com>
This commit is contained in:
Gregory Terzian 2025-07-15 08:57:15 +07:00 committed by GitHub
parent 9e2ee0029a
commit 027954dbad
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 149 additions and 187 deletions

View file

@ -16,7 +16,7 @@ use std::ptr;
use std::rc::Rc;
use dom_struct::dom_struct;
use js::conversions::{ConversionResult, FromJSValConvertibleRc, ToJSValConvertible};
use js::conversions::{ConversionResult, FromJSValConvertibleRc};
use js::jsapi::{
AddRawValueRoot, CallArgs, GetFunctionNativeReserved, Heap, JS_ClearPendingException,
JS_GetFunctionObject, JS_NewFunction, JSAutoRealm, JSContext, JSObject,
@ -30,6 +30,7 @@ use js::rust::wrappers::{
ResolvePromise, SetAnyPromiseIsHandled, SetPromiseUserInputEventHandlingState,
};
use js::rust::{HandleObject, HandleValue, MutableHandleObject, Runtime};
use script_bindings::conversions::SafeToJSValConvertible;
use crate::dom::bindings::conversions::root_from_object;
use crate::dom::bindings::error::{Error, ErrorToJsval};
@ -156,13 +157,13 @@ impl Promise {
pub(crate) fn new_resolved(
global: &GlobalScope,
cx: SafeJSContext,
value: impl ToJSValConvertible,
value: impl SafeToJSValConvertible,
_can_gc: CanGc,
) -> Rc<Promise> {
let _ac = JSAutoRealm::new(*cx, global.reflector().get_jsobject().get());
rooted!(in(*cx) let mut rval = UndefinedValue());
value.safe_to_jsval(cx, rval.handle_mut());
unsafe {
rooted!(in(*cx) let mut rval = UndefinedValue());
value.to_jsval(*cx, rval.handle_mut());
rooted!(in(*cx) let p = CallOriginalPromiseResolve(*cx, rval.handle()));
assert!(!p.handle().is_null());
Promise::new_with_js_promise(p.handle(), cx)
@ -174,30 +175,27 @@ impl Promise {
pub(crate) fn new_rejected(
global: &GlobalScope,
cx: SafeJSContext,
value: impl ToJSValConvertible,
value: impl SafeToJSValConvertible,
_can_gc: CanGc,
) -> Rc<Promise> {
let _ac = JSAutoRealm::new(*cx, global.reflector().get_jsobject().get());
rooted!(in(*cx) let mut rval = UndefinedValue());
value.safe_to_jsval(cx, rval.handle_mut());
unsafe {
rooted!(in(*cx) let mut rval = UndefinedValue());
value.to_jsval(*cx, rval.handle_mut());
rooted!(in(*cx) let p = CallOriginalPromiseReject(*cx, rval.handle()));
assert!(!p.handle().is_null());
Promise::new_with_js_promise(p.handle(), cx)
}
}
#[allow(unsafe_code)]
pub(crate) fn resolve_native<T>(&self, val: &T, can_gc: CanGc)
where
T: ToJSValConvertible,
T: SafeToJSValConvertible,
{
let cx = GlobalScope::get_cx();
let _ac = enter_realm(self);
rooted!(in(*cx) let mut v = UndefinedValue());
unsafe {
val.to_jsval(*cx, v.handle_mut());
}
val.safe_to_jsval(cx, v.handle_mut());
self.resolve(cx, v.handle(), can_gc);
}
@ -211,17 +209,14 @@ impl Promise {
}
}
#[allow(unsafe_code)]
pub(crate) fn reject_native<T>(&self, val: &T, can_gc: CanGc)
where
T: ToJSValConvertible,
T: SafeToJSValConvertible,
{
let cx = GlobalScope::get_cx();
let _ac = enter_realm(self);
rooted!(in(*cx) let mut v = UndefinedValue());
unsafe {
val.to_jsval(*cx, v.handle_mut());
}
val.safe_to_jsval(cx, v.handle_mut());
self.reject(cx, v.handle(), can_gc);
}