script: Return a Result from GlobalScope::evaluate_script_on_global_with_result (#38549)

Make GlobalScope::evaluate_script_on_global_with_result return a Result
instead of a boolean. This is the first step to resolve issue #37810.

Testing: Should not break or fix any existing tests

---------

Signed-off-by: Rodion Borovyk <rodion.borovyk@gmail.com>
This commit is contained in:
Rodion Borovyk 2025-08-10 18:51:46 +02:00 committed by GitHub
parent 86c37a380b
commit 4f8731d562
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 45 additions and 28 deletions

View file

@ -60,7 +60,7 @@ pub(crate) fn handle_evaluate_js(
let source_code = SourceCode::Text(Rc::new(DOMString::from_string(eval))); let source_code = SourceCode::Text(Rc::new(DOMString::from_string(eval)));
// TODO: run code with SpiderMonkey Debugger API, like Firefox does // TODO: run code with SpiderMonkey Debugger API, like Firefox does
// <https://searchfox.org/mozilla-central/rev/f6a806c38c459e0e0d797d264ca0e8ad46005105/devtools/server/actors/webconsole/eval-with-debugger.js#270> // <https://searchfox.org/mozilla-central/rev/f6a806c38c459e0e0d797d264ca0e8ad46005105/devtools/server/actors/webconsole/eval-with-debugger.js#270>
global.evaluate_script_on_global_with_result( _ = global.evaluate_script_on_global_with_result(
&source_code, &source_code,
"<eval>", "<eval>",
rval.handle_mut(), rval.handle_mut(),

View file

@ -6,6 +6,7 @@ use base::id::PipelineId;
use constellation_traits::ScriptToConstellationChan; use constellation_traits::ScriptToConstellationChan;
use devtools_traits::{ScriptToDevtoolsControlMsg, WorkerId}; use devtools_traits::{ScriptToDevtoolsControlMsg, WorkerId};
use dom_struct::dom_struct; use dom_struct::dom_struct;
use embedder_traits::JavaScriptEvaluationError;
use embedder_traits::resources::{self, Resource}; use embedder_traits::resources::{self, Resource};
use ipc_channel::ipc::IpcSender; use ipc_channel::ipc::IpcSender;
use js::jsval::UndefinedValue; use js::jsval::UndefinedValue;
@ -104,7 +105,7 @@ impl DebuggerGlobalScope {
GlobalScope::get_cx() GlobalScope::get_cx()
} }
fn evaluate_js(&self, script: &str, can_gc: CanGc) -> bool { fn evaluate_js(&self, script: &str, can_gc: CanGc) -> Result<(), JavaScriptEvaluationError> {
rooted!(in (*Self::get_cx()) let mut rval = UndefinedValue()); rooted!(in (*Self::get_cx()) let mut rval = UndefinedValue());
self.global_scope.evaluate_js_on_global_with_result( self.global_scope.evaluate_js_on_global_with_result(
script, script,
@ -117,7 +118,10 @@ impl DebuggerGlobalScope {
} }
pub(crate) fn execute(&self, can_gc: CanGc) { pub(crate) fn execute(&self, can_gc: CanGc) {
if !self.evaluate_js(&resources::read_string(Resource::DebuggerJS), can_gc) { if self
.evaluate_js(&resources::read_string(Resource::DebuggerJS), can_gc)
.is_err()
{
let ar = enter_realm(self); let ar = enter_realm(self);
report_pending_exception(Self::get_cx(), true, InRealm::Entered(&ar), can_gc); report_pending_exception(Self::get_cx(), true, InRealm::Entered(&ar), can_gc);
} }

View file

@ -26,7 +26,7 @@ use content_security_policy::CspList;
use crossbeam_channel::Sender; use crossbeam_channel::Sender;
use devtools_traits::{PageError, ScriptToDevtoolsControlMsg}; use devtools_traits::{PageError, ScriptToDevtoolsControlMsg};
use dom_struct::dom_struct; use dom_struct::dom_struct;
use embedder_traits::EmbedderMsg; use embedder_traits::{EmbedderMsg, JavaScriptEvaluationError};
use ipc_channel::ipc::{self, IpcSender}; use ipc_channel::ipc::{self, IpcSender};
use ipc_channel::router::ROUTER; use ipc_channel::router::ROUTER;
use js::glue::{IsWrapper, UnwrapObjectDynamic}; use js::glue::{IsWrapper, UnwrapObjectDynamic};
@ -2762,7 +2762,7 @@ impl GlobalScope {
script_base_url: ServoUrl, script_base_url: ServoUrl,
can_gc: CanGc, can_gc: CanGc,
introduction_type: Option<&'static CStr>, introduction_type: Option<&'static CStr>,
) -> bool { ) -> Result<(), JavaScriptEvaluationError> {
let source_code = SourceCode::Text(Rc::new(DOMString::from_string((*code).to_string()))); let source_code = SourceCode::Text(Rc::new(DOMString::from_string((*code).to_string())));
self.evaluate_script_on_global_with_result( self.evaluate_script_on_global_with_result(
&source_code, &source_code,
@ -2789,7 +2789,7 @@ impl GlobalScope {
script_base_url: ServoUrl, script_base_url: ServoUrl,
can_gc: CanGc, can_gc: CanGc,
introduction_type: Option<&'static CStr>, introduction_type: Option<&'static CStr>,
) -> bool { ) -> Result<(), JavaScriptEvaluationError> {
let cx = GlobalScope::get_cx(); let cx = GlobalScope::get_cx();
let ar = enter_realm(self); let ar = enter_realm(self);
@ -2815,7 +2815,7 @@ impl GlobalScope {
if compiled_script.is_null() { if compiled_script.is_null() {
debug!("error compiling Dom string"); debug!("error compiling Dom string");
report_pending_exception(cx, true, InRealm::Entered(&ar), can_gc); report_pending_exception(cx, true, InRealm::Entered(&ar), can_gc);
return false; return Err(JavaScriptEvaluationError::CompilationFailure);
} }
}, },
SourceCode::Compiled(pre_compiled_script) => { SourceCode::Compiled(pre_compiled_script) => {
@ -2865,10 +2865,11 @@ impl GlobalScope {
if !result { if !result {
debug!("error evaluating Dom string"); debug!("error evaluating Dom string");
report_pending_exception(cx, true, InRealm::Entered(&ar), can_gc); report_pending_exception(cx, true, InRealm::Entered(&ar), can_gc);
return Err(JavaScriptEvaluationError::EvaluationFailure);
} }
maybe_resume_unwind(); maybe_resume_unwind();
result Ok(())
} }
} }

View file

@ -1160,7 +1160,7 @@ impl HTMLScriptElement {
self.line_number as u32 self.line_number as u32
}; };
rooted!(in(*GlobalScope::get_cx()) let mut rval = UndefinedValue()); rooted!(in(*GlobalScope::get_cx()) let mut rval = UndefinedValue());
window _ = window
.as_global_scope() .as_global_scope()
.evaluate_script_on_global_with_result( .evaluate_script_on_global_with_result(
&script.code, &script.code,

View file

@ -31,7 +31,7 @@ pub(crate) fn load_script(head: &HTMLHeadElement) {
Rc::new(DOMString::from_string(user_script.script)) Rc::new(DOMString::from_string(user_script.script))
); );
let global_scope = win.as_global_scope(); let global_scope = win.as_global_scope();
global_scope.evaluate_script_on_global_with_result( _ = global_scope.evaluate_script_on_global_with_result(
&script_text, &script_text,
&user_script.source_file.map(|path| path.to_string_lossy().to_string()).unwrap_or_default(), &user_script.source_file.map(|path| path.to_string_lossy().to_string()).unwrap_or_default(),
rval.handle_mut(), rval.handle_mut(),

View file

@ -691,7 +691,7 @@ impl WorkletThread {
// to the main script thread. // to the main script thread.
// https://github.com/w3c/css-houdini-drafts/issues/407 // https://github.com/w3c/css-houdini-drafts/issues/407
let ok = script let ok = script
.map(|script| global_scope.evaluate_js(&script, can_gc)) .map(|s| global_scope.evaluate_js(&s, can_gc).is_ok())
.unwrap_or(false); .unwrap_or(false);
if !ok { if !ok {

View file

@ -9,6 +9,7 @@ use constellation_traits::{ScriptToConstellationChan, ScriptToConstellationMessa
use crossbeam_channel::Sender; use crossbeam_channel::Sender;
use devtools_traits::ScriptToDevtoolsControlMsg; use devtools_traits::ScriptToDevtoolsControlMsg;
use dom_struct::dom_struct; use dom_struct::dom_struct;
use embedder_traits::JavaScriptEvaluationError;
use ipc_channel::ipc::IpcSender; use ipc_channel::ipc::IpcSender;
use js::jsval::UndefinedValue; use js::jsval::UndefinedValue;
use js::rust::Runtime; use js::rust::Runtime;
@ -124,7 +125,11 @@ impl WorkletGlobalScope {
} }
/// Evaluate a JS script in this global. /// Evaluate a JS script in this global.
pub(crate) fn evaluate_js(&self, script: &str, can_gc: CanGc) -> bool { pub(crate) fn evaluate_js(
&self,
script: &str,
can_gc: CanGc,
) -> Result<(), JavaScriptEvaluationError> {
debug!("Evaluating Dom in a worklet."); debug!("Evaluating Dom in a worklet.");
rooted!(in (*GlobalScope::get_cx()) let mut rval = UndefinedValue()); rooted!(in (*GlobalScope::get_cx()) let mut rval = UndefinedValue());
self.globalscope.evaluate_js_on_global_with_result( self.globalscope.evaluate_js_on_global_with_result(

View file

@ -3738,7 +3738,7 @@ impl ScriptThread {
// Script source is ready to be evaluated (11.) // Script source is ready to be evaluated (11.)
let _ac = enter_realm(global_scope); let _ac = enter_realm(global_scope);
rooted!(in(*GlobalScope::get_cx()) let mut jsval = UndefinedValue()); rooted!(in(*GlobalScope::get_cx()) let mut jsval = UndefinedValue());
global_scope.evaluate_js_on_global_with_result( _ = global_scope.evaluate_js_on_global_with_result(
&script_source, &script_source,
jsval.handle_mut(), jsval.handle_mut(),
ScriptFetchOptions::default_classic_script(global_scope), ScriptFetchOptions::default_classic_script(global_scope),
@ -4093,7 +4093,7 @@ impl ScriptThread {
let context = window.get_cx(); let context = window.get_cx();
rooted!(in(*context) let mut return_value = UndefinedValue()); rooted!(in(*context) let mut return_value = UndefinedValue());
global_scope.evaluate_js_on_global_with_result( _ = global_scope.evaluate_js_on_global_with_result(
&script, &script,
return_value.handle_mut(), return_value.handle_mut(),
ScriptFetchOptions::default_classic_script(global_scope), ScriptFetchOptions::default_classic_script(global_scope),

View file

@ -556,7 +556,7 @@ impl JsTimerTask {
let cx = GlobalScope::get_cx(); let cx = GlobalScope::get_cx();
rooted!(in(*cx) let mut rval = UndefinedValue()); rooted!(in(*cx) let mut rval = UndefinedValue());
// FIXME(cybai): Use base url properly by saving private reference for timers (#27260) // FIXME(cybai): Use base url properly by saving private reference for timers (#27260)
global.evaluate_js_on_global_with_result( _ = global.evaluate_js_on_global_with_result(
code_str, code_str,
rval.handle_mut(), rval.handle_mut(),
ScriptFetchOptions::default_classic_script(&global), ScriptFetchOptions::default_classic_script(&global),

View file

@ -524,17 +524,17 @@ pub(crate) fn handle_execute_script(
rooted!(in(*cx) let mut rval = UndefinedValue()); rooted!(in(*cx) let mut rval = UndefinedValue());
let global = window.as_global_scope(); let global = window.as_global_scope();
let result = if global.evaluate_js_on_global_with_result( let evaluation_result = global.evaluate_js_on_global_with_result(
&eval, &eval,
rval.handle_mut(), rval.handle_mut(),
ScriptFetchOptions::default_classic_script(global), ScriptFetchOptions::default_classic_script(global),
global.api_base_url(), global.api_base_url(),
can_gc, can_gc,
None, // No known `introductionType` for JS code from WebDriver None, // No known `introductionType` for JS code from WebDriver
) { );
jsval_to_webdriver(cx, global, rval.handle(), realm, can_gc) let result = match evaluation_result {
} else { Ok(_) => jsval_to_webdriver(cx, global, rval.handle(), realm, can_gc),
Err(WebDriverJSError::JSError) Err(_) => Err(WebDriverJSError::JSError),
}; };
if reply.send(result).is_err() { if reply.send(result).is_err() {
@ -566,14 +566,17 @@ pub(crate) fn handle_execute_async_script(
rooted!(in(*cx) let mut rval = UndefinedValue()); rooted!(in(*cx) let mut rval = UndefinedValue());
let global_scope = window.as_global_scope(); let global_scope = window.as_global_scope();
if !global_scope.evaluate_js_on_global_with_result( if global_scope
&eval, .evaluate_js_on_global_with_result(
rval.handle_mut(), &eval,
ScriptFetchOptions::default_classic_script(global_scope), rval.handle_mut(),
global_scope.api_base_url(), ScriptFetchOptions::default_classic_script(global_scope),
can_gc, global_scope.api_base_url(),
None, // No known `introductionType` for JS code from WebDriver can_gc,
) { None, // No known `introductionType` for JS code from WebDriver
)
.is_err()
{
reply_sender.send(Err(WebDriverJSError::JSError)).unwrap(); reply_sender.send(Err(WebDriverJSError::JSError)).unwrap();
} }
}, },

View file

@ -1033,6 +1033,10 @@ impl From<&WebDriverJSValue> for JSValue {
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] #[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub enum JavaScriptEvaluationError { pub enum JavaScriptEvaluationError {
/// The script could not be compiled
CompilationFailure,
/// The script could not be evaluated
EvaluationFailure,
/// An internal Servo error prevented the JavaSript evaluation from completing properly. /// An internal Servo error prevented the JavaSript evaluation from completing properly.
/// This indicates a bug in Servo. /// This indicates a bug in Servo.
InternalError, InternalError,