script_bindings: Remove jsstring_to_str (#38527)

This PR removes `jsstring_to_str`, which is replaced with
`jsstr_to_string`, and updates `mozjs` to
6f3dcb99a7.

Given that servo now always replaces unpaired surrogate since
https://github.com/servo/servo/pull/35381, the internal conversion
function `jsstring_to_str` is functionally the same as `jsstr_to_string`
from `mozjs`. This PR removes `jsstring_to_str` and replaces with
`jsstr_to_string` with conversions to `DOMString` where necessary.

Testing: Passes all unit test. No regression was found in WPT test (see
try run: https://github.com/minghuaw/servo/actions/runs/16821156583)

---------

Signed-off-by: minghuaw <wuminghua7@huawei.com>
Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com>
Co-authored-by: sagudev <16504129+sagudev@users.noreply.github.com>
This commit is contained in:
minghuaw 2025-08-09 19:50:14 +08:00 committed by GitHub
parent a3e0a34802
commit ad18638534
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 49 additions and 81 deletions

View file

@ -12,6 +12,7 @@ use devtools_traits::{
NodeInfo, NodeStyle, RuleModification, TimelineMarker, TimelineMarkerType,
};
use ipc_channel::ipc::IpcSender;
use js::conversions::jsstr_to_string;
use js::jsval::UndefinedValue;
use js::rust::ToString;
use servo_config::pref;
@ -28,7 +29,7 @@ use crate::dom::bindings::codegen::Bindings::ElementBinding::ElementMethods;
use crate::dom::bindings::codegen::Bindings::HTMLElementBinding::HTMLElementMethods;
use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeConstants;
use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
use crate::dom::bindings::conversions::{ConversionResult, FromJSValConvertible, jsstring_to_str};
use crate::dom::bindings::conversions::{ConversionResult, FromJSValConvertible};
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::root::DomRoot;
use crate::dom::bindings::str::DOMString;
@ -83,17 +84,17 @@ pub(crate) fn handle_evaluate_js(
)
} else if rval.is_string() {
let jsstr = std::ptr::NonNull::new(rval.to_string()).unwrap();
EvaluateJSReply::StringValue(String::from(jsstring_to_str(*cx, jsstr)))
EvaluateJSReply::StringValue(jsstr_to_string(*cx, jsstr))
} else if rval.is_null() {
EvaluateJSReply::NullValue
} else {
assert!(rval.is_object());
let jsstr = std::ptr::NonNull::new(ToString(*cx, rval.handle())).unwrap();
let class_name = jsstring_to_str(*cx, jsstr);
let class_name = jsstr_to_string(*cx, jsstr);
EvaluateJSReply::ActorValue {
class: class_name.to_string(),
class: class_name,
uuid: Uuid::new_v4().to_string(),
}
}

View file

@ -10,6 +10,7 @@ use devtools_traits::{
ConsoleMessage, ConsoleMessageArgument, ConsoleMessageBuilder, LogLevel,
ScriptToDevtoolsControlMsg, StackFrame,
};
use js::conversions::jsstr_to_string;
use js::jsapi::{self, ESClass, PropertyDescriptor};
use js::jsval::{Int32Value, UndefinedValue};
use js::rust::wrappers::{
@ -22,7 +23,6 @@ use js::rust::{
use script_bindings::conversions::get_dom_class;
use crate::dom::bindings::codegen::Bindings::ConsoleBinding::consoleMethods;
use crate::dom::bindings::conversions::jsstring_to_str;
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::str::DOMString;
use crate::dom::globalscope::GlobalScope;
@ -127,7 +127,7 @@ unsafe fn handle_value_to_string(cx: *mut jsapi::JSContext, value: HandleValue)
match std::ptr::NonNull::new(JS_ValueToSource(cx, value)) {
Some(js_str) => {
js_string.set(js_str.as_ptr());
jsstring_to_str(cx, js_str)
DOMString::from_string(jsstr_to_string(cx, js_str))
},
None => "<error converting value to string>".into(),
}
@ -140,8 +140,8 @@ fn console_argument_from_handle_value(
) -> ConsoleMessageArgument {
if handle_value.is_string() {
let js_string = ptr::NonNull::new(handle_value.to_string()).unwrap();
let dom_string = unsafe { jsstring_to_str(*cx, js_string) };
return ConsoleMessageArgument::String(dom_string.into());
let dom_string = unsafe { jsstr_to_string(*cx, js_string) };
return ConsoleMessageArgument::String(dom_string);
}
if handle_value.is_int32() {
@ -164,7 +164,8 @@ fn stringify_handle_value(message: HandleValue) -> DOMString {
let cx = GlobalScope::get_cx();
unsafe {
if message.is_string() {
return jsstring_to_str(*cx, std::ptr::NonNull::new(message.to_string()).unwrap());
let jsstr = std::ptr::NonNull::new(message.to_string()).unwrap();
return DOMString::from_string(jsstr_to_string(*cx, jsstr));
}
unsafe fn stringify_object_from_handle_value(
cx: *mut jsapi::JSContext,
@ -297,7 +298,7 @@ fn maybe_stringify_dom_object(cx: JSContext, value: HandleValue) -> Option<DOMSt
return Some("<error converting DOM object to string>".into());
};
let class_name = unsafe {
jsstring_to_str(*cx, class_name)
jsstr_to_string(*cx, class_name)
.replace("[object ", "")
.replace("]", "")
};
@ -493,7 +494,7 @@ fn get_js_stack(cx: *mut jsapi::JSContext) -> Vec<StackFrame> {
);
}
let function_name = if let Some(nonnull_result) = ptr::NonNull::new(*result) {
unsafe { jsstring_to_str(cx, nonnull_result) }.into()
unsafe { jsstr_to_string(cx, nonnull_result) }
} else {
"<anonymous>".into()
};
@ -510,7 +511,7 @@ fn get_js_stack(cx: *mut jsapi::JSContext) -> Vec<StackFrame> {
);
}
let filename = if let Some(nonnull_result) = ptr::NonNull::new(*result) {
unsafe { jsstring_to_str(cx, nonnull_result) }.into()
unsafe { jsstr_to_string(cx, nonnull_result) }
} else {
"<anonymous>".into()
};

View file

@ -9,6 +9,7 @@ use cssparser::{Parser, ParserInput};
use dom_struct::dom_struct;
use euclid::Angle;
use euclid::default::{Transform2D, Transform3D};
use js::conversions::jsstr_to_string;
use js::jsapi::JSObject;
use js::jsval;
use js::rust::{CustomAutoRooterGuard, HandleObject, ToString};
@ -24,7 +25,6 @@ use crate::dom::bindings::codegen::Bindings::DOMMatrixBinding::{
use crate::dom::bindings::codegen::Bindings::DOMMatrixReadOnlyBinding::DOMMatrixReadOnlyMethods;
use crate::dom::bindings::codegen::Bindings::DOMPointBinding::DOMPointInit;
use crate::dom::bindings::codegen::UnionTypes::StringOrUnrestrictedDoubleSequence;
use crate::dom::bindings::conversions::jsstring_to_str;
use crate::dom::bindings::error;
use crate::dom::bindings::error::Fallible;
use crate::dom::bindings::inheritance::Castable;
@ -835,11 +835,9 @@ impl DOMMatrixReadOnlyMethods<crate::DomTypeHolder> for DOMMatrixReadOnly {
unsafe {
rooted!(in(*cx) let mut rooted_value = value);
let serialization = ToString(*cx, rooted_value.handle());
jsstring_to_str(
*cx,
ptr::NonNull::new(serialization).expect("Pointer cannot be null"),
)
let serialization = std::ptr::NonNull::new(ToString(*cx, rooted_value.handle()))
.expect("Pointer cannot be null");
jsstr_to_string(*cx, serialization)
}
};

View file

@ -5,6 +5,7 @@
use std::iter::repeat;
use std::ptr;
use js::conversions::jsstr_to_string;
use js::gc::MutableHandle;
use js::jsapi::{
ESClass, GetBuiltinClass, IsArrayBufferObject, JS_DeleteUCProperty,
@ -18,7 +19,6 @@ use script_bindings::conversions::{SafeToJSValConvertible, root_from_object};
use script_bindings::str::DOMString;
use crate::dom::bindings::codegen::UnionTypes::StringOrStringSequence as StrOrStringSequence;
use crate::dom::bindings::conversions::jsstring_to_str;
use crate::dom::bindings::error::Error;
use crate::dom::bindings::import::module::SafeJSContext;
use crate::dom::bindings::structuredclone;
@ -104,7 +104,7 @@ pub fn convert_value_to_key(
if input.is_string() {
let string_ptr = std::ptr::NonNull::new(input.to_string()).unwrap();
let key = unsafe { jsstring_to_str(*cx, string_ptr).str().to_string() };
let key = unsafe { jsstr_to_string(*cx, string_ptr) };
return Ok(IndexedDBKeyType::String(key));
}

View file

@ -17,6 +17,7 @@ use headers::{HeaderMapExt, ReferrerPolicy as ReferrerPolicyHeader};
use html5ever::local_name;
use hyper_serde::Serde;
use indexmap::{IndexMap, IndexSet};
use js::conversions::jsstr_to_string;
use js::jsapi::{
CompileModule1, ExceptionStackBehavior, FinishDynamicModuleImport, GetModuleRequestSpecifier,
GetModuleResolveHook, GetRequestedModuleSpecifier, GetRequestedModulesCount,
@ -50,7 +51,6 @@ use uuid::Uuid;
use crate::document_loader::LoadType;
use crate::dom::bindings::cell::DomRefCell;
use crate::dom::bindings::codegen::Bindings::WindowBinding::Window_Binding::WindowMethods;
use crate::dom::bindings::conversions::jsstring_to_str;
use crate::dom::bindings::error::{
Error, ErrorToJsval, report_pending_exception, throw_dom_exception,
};
@ -630,11 +630,10 @@ impl ModuleTree {
let length = GetRequestedModulesCount(*cx, module_object);
for index in 0..length {
let specifier = jsstring_to_str(
*cx,
ptr::NonNull::new(GetRequestedModuleSpecifier(*cx, module_object, index))
.unwrap(),
);
let jsstr =
std::ptr::NonNull::new(GetRequestedModuleSpecifier(*cx, module_object, index))
.unwrap();
let specifier = DOMString::from_string(jsstr_to_string(*cx, jsstr));
rooted!(in(*cx) let mut private = UndefinedValue());
JS_GetModulePrivate(module_object.get(), private.handle_mut());
@ -1519,10 +1518,8 @@ fn fetch_an_import_module_script_graph(
// Step 1.
let cx = GlobalScope::get_cx();
let specifier = unsafe {
jsstring_to_str(
*cx,
ptr::NonNull::new(GetModuleRequestSpecifier(*cx, module_request)).unwrap(),
)
let jsstr = std::ptr::NonNull::new(GetModuleRequestSpecifier(*cx, module_request)).unwrap();
DOMString::from_string(jsstr_to_string(*cx, jsstr))
};
let mut options = ScriptFetchOptions::default_classic_script(global);
let module_data = unsafe { module_script_from_reference_private(&reference_private) };
@ -1594,10 +1591,8 @@ unsafe extern "C" fn HostResolveImportedModule(
// Step 5.
let module_data = module_script_from_reference_private(&reference_private);
let specifier = jsstring_to_str(
cx,
ptr::NonNull::new(GetModuleRequestSpecifier(cx, specifier)).unwrap(),
);
let jsstr = std::ptr::NonNull::new(GetModuleRequestSpecifier(cx, specifier)).unwrap();
let specifier = DOMString::from_string(jsstr_to_string(cx, jsstr));
let url =
ModuleTree::resolve_module_specifier(&global_scope, module_data, specifier, CanGc::note());

View file

@ -13,7 +13,6 @@ use std::ffi::{CStr, CString};
use std::io::{Write, stdout};
use std::ops::Deref;
use std::os::raw::c_void;
use std::ptr::NonNull;
use std::rc::Rc;
use std::sync::Mutex;
use std::time::{Duration, Instant};
@ -490,9 +489,8 @@ unsafe extern "C" fn content_security_policy_allows(
allowed = match runtime_code {
RuntimeCode::JS => {
let source = NonNull::new(*sample)
.map(|sample| jsstr_to_string(*cx, sample))
.unwrap_or("".to_string());
let source = std::ptr::NonNull::new(*sample)
.map_or_else(String::new, |jsstr| jsstr_to_string(*cx, jsstr));
global
.get_csp_list()
.is_js_evaluation_allowed(global, &source)

View file

@ -14,6 +14,7 @@ use embedder_traits::{
use euclid::default::{Point2D, Rect, Size2D};
use hyper_serde::Serde;
use ipc_channel::ipc::{self, IpcSender};
use js::conversions::jsstr_to_string;
use js::jsapi::{
self, GetPropertyKeys, HandleValueArray, JS_GetOwnPropertyDescriptorById, JS_GetPropertyById,
JS_IsExceptionPending, JSAutoRealm, JSContext, JSType, PropertyDescriptor,
@ -52,7 +53,7 @@ use crate::dom::bindings::codegen::Bindings::XPathResultBinding::{
};
use crate::dom::bindings::conversions::{
ConversionBehavior, ConversionResult, FromJSValConvertible, StringificationBehavior,
get_property, get_property_jsval, jsid_to_string, jsstring_to_str, root_from_object,
get_property, get_property_jsval, jsid_to_string, root_from_object,
};
use crate::dom::bindings::error::{Error, report_pending_exception, throw_dom_exception};
use crate::dom::bindings::inheritance::Castable;
@ -269,7 +270,7 @@ unsafe fn is_arguments_object(cx: *mut JSContext, value: HandleValue) -> bool {
let Some(class_name) = NonNull::new(class_name.get()) else {
return false;
};
jsstring_to_str(cx, class_name) == "[object Arguments]"
jsstr_to_string(cx, class_name) == "[object Arguments]"
}
#[derive(Clone, Eq, Hash, PartialEq)]
@ -327,7 +328,7 @@ unsafe fn jsval_to_webdriver_inner(
},
))
} else if val.get().is_string() {
//FIXME: use jsstring_to_str when jsval grows to_jsstring
//FIXME: use jsstr_to_string when jsval grows to_jsstring
let string: DOMString =
match FromJSValConvertible::from_jsval(cx, val, StringificationBehavior::Default)
.unwrap()

View file

@ -5,7 +5,7 @@
use std::{ptr, slice};
use js::conversions::{
ConversionResult, FromJSValConvertible, ToJSValConvertible, latin1_to_string,
ConversionResult, FromJSValConvertible, ToJSValConvertible, jsstr_to_string,
};
use js::error::throw_type_error;
use js::glue::{
@ -14,7 +14,7 @@ use js::glue::{
};
use js::jsapi::{
Heap, IsWindowProxy, JS_DeprecatedStringHasLatin1Chars, JS_GetLatin1StringCharsAndLength,
JS_GetTwoByteStringCharsAndLength, JS_NewStringCopyN, JSContext, JSObject, JSString,
JS_GetTwoByteStringCharsAndLength, JS_NewStringCopyN, JSContext, JSObject,
};
use js::jsval::{ObjectValue, StringValue, UndefinedValue};
use js::rust::wrappers::IsArrayObject;
@ -115,7 +115,9 @@ impl FromJSValConvertible for DOMString {
Ok(ConversionResult::Success(DOMString::new()))
} else {
match ptr::NonNull::new(ToString(cx, value)) {
Some(jsstr) => Ok(ConversionResult::Success(jsstring_to_str(cx, jsstr))),
Some(jsstr) => Ok(ConversionResult::Success(DOMString::from_string(
jsstr_to_string(cx, jsstr),
))),
None => {
debug!("ToString failed");
Err(())
@ -125,34 +127,6 @@ impl FromJSValConvertible for DOMString {
}
}
/// Convert the given `JSString` to a `DOMString`. Fails if the string does not
/// contain valid UTF-16.
///
/// # Safety
/// cx and s must point to valid values.
pub unsafe fn jsstring_to_str(cx: *mut JSContext, s: ptr::NonNull<JSString>) -> DOMString {
let latin1 = JS_DeprecatedStringHasLatin1Chars(s.as_ptr());
DOMString::from_string(if latin1 {
latin1_to_string(cx, s)
} else {
let mut length = 0;
let chars = JS_GetTwoByteStringCharsAndLength(cx, ptr::null(), s.as_ptr(), &mut length);
assert!(!chars.is_null());
let potentially_ill_formed_utf16 = slice::from_raw_parts(chars, length);
let mut s = String::with_capacity(length);
for item in char::decode_utf16(potentially_ill_formed_utf16.iter().cloned()) {
match item {
Ok(c) => s.push(c),
Err(_) => {
error!("Found an unpaired surrogate in a DOM string.");
s.push('\u{FFFD}');
},
}
}
s
})
}
// http://heycam.github.io/webidl/#es-USVString
impl FromJSValConvertible for USVString {
type Config = ();
@ -168,8 +142,8 @@ impl FromJSValConvertible for USVString {
let latin1 = JS_DeprecatedStringHasLatin1Chars(jsstr.as_ptr());
if latin1 {
// FIXME(ajeffrey): Convert directly from DOMString to USVString
return Ok(ConversionResult::Success(USVString(String::from(
jsstring_to_str(cx, jsstr),
return Ok(ConversionResult::Success(USVString(jsstr_to_string(
cx, jsstr,
))));
}
let mut length = 0;
@ -445,7 +419,7 @@ pub unsafe fn jsid_to_string(cx: *mut JSContext, id: HandleId) -> Option<DOMStri
let id_raw = *id;
if id_raw.is_string() {
let jsstr = std::ptr::NonNull::new(id_raw.to_string()).unwrap();
return Some(jsstring_to_str(cx, jsstr));
return Some(DOMString::from_string(jsstr_to_string(cx, jsstr)));
}
if id_raw.is_int() {

View file

@ -8,7 +8,7 @@ use std::ffi::CStr;
use std::os::raw::c_char;
use std::ptr;
use js::conversions::ToJSValConvertible;
use js::conversions::{ToJSValConvertible, jsstr_to_string};
use js::glue::{
GetProxyHandler, GetProxyHandlerFamily, GetProxyPrivate, InvokeGetOwnPropertyDescriptor,
SetProxyPrivate,
@ -33,7 +33,7 @@ use js::rust::{Handle, HandleObject, HandleValue, MutableHandle, MutableHandleOb
use js::{jsapi, rooted};
use crate::DomTypes;
use crate::conversions::{is_dom_proxy, jsid_to_string, jsstring_to_str};
use crate::conversions::{is_dom_proxy, jsid_to_string};
use crate::error::Error;
use crate::interfaces::{DomHelpers, GlobalScopeHelpers};
use crate::realms::{AlreadyInRealm, InRealm};
@ -232,7 +232,7 @@ pub(crate) fn id_to_source(cx: SafeJSContext, id: RawHandleId) -> Option<DOMStri
jsstr.get()
})
.and_then(ptr::NonNull::new)
.map(|jsstr| jsstring_to_str(*cx, jsstr))
.map(|jsstr| DOMString::from_string(jsstr_to_string(*cx, jsstr)))
}
}

View file

@ -7,7 +7,7 @@ use std::os::raw::{c_char, c_void};
use std::ptr::{self, NonNull};
use std::slice;
use js::conversions::ToJSValConvertible;
use js::conversions::{ToJSValConvertible, jsstr_to_string};
use js::gc::Handle;
use js::glue::{
AppendToIdVector, CallJitGetterOp, CallJitMethodOp, CallJitSetterOp, JS_GetReservedSlot,
@ -40,7 +40,7 @@ use crate::DomTypes;
use crate::codegen::Globals::Globals;
use crate::codegen::InheritTypes::TopTypeId;
use crate::codegen::PrototypeList::{self, MAX_PROTO_CHAIN_LENGTH, PROTO_OR_IFACE_LENGTH};
use crate::conversions::{PrototypeCheck, jsstring_to_str, private_from_proto_check};
use crate::conversions::{PrototypeCheck, private_from_proto_check};
use crate::error::throw_invalid_this;
use crate::interfaces::DomHelpers;
use crate::script_runtime::{CanGc, JSContext as SafeJSContext};
@ -222,7 +222,7 @@ pub(crate) unsafe fn find_enum_value<'a, T>(
) -> Result<(Option<&'a T>, DOMString), ()> {
match ptr::NonNull::new(ToString(cx, v)) {
Some(jsstr) => {
let search = jsstring_to_str(cx, jsstr);
let search = DOMString::from_string(jsstr_to_string(cx, jsstr));
Ok((
pairs
.iter()