Implement saveJobQueue() as required by SpiderMonkey

Signed-off-by: Delan Azabani <dazabani@igalia.com>
Co-authored-by: atbrakhi <atbrakhi@igalia.com>
This commit is contained in:
Delan Azabani 2025-07-22 19:37:08 +08:00
parent 86ea2641f8
commit 1f6c9fa028
3 changed files with 47 additions and 4 deletions

6
Cargo.lock generated
View file

@ -5202,7 +5202,7 @@ dependencies = [
[[package]]
name = "mozjs"
version = "0.14.1"
source = "git+https://github.com/servo/mozjs#128e1e230a0155ed9395c718184f34bddc045860"
source = "git+https://github.com/servo/mozjs?rev=94fb7eb92b7f027fa102c69c7eac55526f1ce124#94fb7eb92b7f027fa102c69c7eac55526f1ce124"
dependencies = [
"bindgen 0.71.1",
"cc",
@ -5213,8 +5213,8 @@ dependencies = [
[[package]]
name = "mozjs_sys"
version = "0.128.13-0"
source = "git+https://github.com/servo/mozjs#128e1e230a0155ed9395c718184f34bddc045860"
version = "0.128.13-1"
source = "git+https://github.com/servo/mozjs?rev=94fb7eb92b7f027fa102c69c7eac55526f1ce124#94fb7eb92b7f027fa102c69c7eac55526f1ce124"
dependencies = [
"bindgen 0.71.1",
"cc",

View file

@ -85,7 +85,7 @@ imsz = "0.2"
indexmap = { version = "2.10.0", features = ["std"] }
ipc-channel = "0.20"
itertools = "0.14"
js = { package = "mozjs", git = "https://github.com/servo/mozjs" }
js = { package = "mozjs", git = "https://github.com/servo/mozjs", rev = "94fb7eb92b7f027fa102c69c7eac55526f1ce124" } # branch = for_debugger
keyboard-types = "0.7"
kurbo = "0.11"
libc = "0.2"

View file

@ -88,6 +88,8 @@ static JOB_QUEUE_TRAPS: JobQueueTraps = JobQueueTraps {
getIncumbentGlobal: Some(get_incumbent_global),
enqueuePromiseJob: Some(enqueue_promise_job),
empty: Some(empty),
pushNewInterruptQueue: Some(push_new_interrupt_queue),
popInterruptQueue: Some(pop_interrupt_queue),
};
static SECURITY_CALLBACKS: JSSecurityCallbacks = JSSecurityCallbacks {
@ -248,6 +250,35 @@ unsafe extern "C" fn empty(extra: *const c_void) -> bool {
result
}
#[allow(unsafe_code)]
unsafe extern "C" fn push_new_interrupt_queue(interrupt_queues: *mut c_void) -> *mut c_void {
let mut result = std::ptr::null_mut();
wrap_panic(&mut || {
let interrupt_queues = &mut *(interrupt_queues as *mut Vec<Rc<MicrotaskQueue>>);
let mut new_queue = Rc::new(MicrotaskQueue::default());
// TODO: SAFETY: is this ok? It subverts the Rc::get_mut() check
result = Rc::get_mut(&mut new_queue).expect("Guaranteed by usage of `new_queue`") as *mut _
as *mut c_void;
interrupt_queues.push(new_queue.clone());
});
result
}
#[allow(unsafe_code)]
unsafe extern "C" fn pop_interrupt_queue(interrupt_queues: *mut c_void) -> *mut c_void {
let mut result = std::ptr::null_mut();
wrap_panic(&mut || {
let interrupt_queues = &mut *(interrupt_queues as *mut Vec<Rc<MicrotaskQueue>>);
let mut popped_queue: Rc<MicrotaskQueue> =
interrupt_queues.pop().expect("Guaranteed by SpiderMonkey?");
// Dangling, but jsglue.cpp will only use this for pointer comparison.
// TODO: SAFETY: is this ok? It subverts the Rc::get_mut() check
result = Rc::get_mut(&mut popped_queue).expect("Guaranteed by usage of `popped_queue`")
as *mut _ as *mut c_void;
});
result
}
/// SM callback for promise job resolution. Adds a promise callback to the current
/// global's microtask queue.
#[allow(unsafe_code)]
@ -474,7 +505,10 @@ pub(crate) fn notify_about_rejected_promises(global: &GlobalScope) {
#[derive(JSTraceable)]
pub(crate) struct Runtime {
rt: RustRuntime,
/// Our actual microtask queue, which is preserved and untouched by the debugger when running debugger scripts.
pub(crate) microtask_queue: Rc<MicrotaskQueue>,
/// Extra microtask queues created for debugger scripts via AutoDebuggerJobQueueInterruption and saveJobQueue().
interrupt_microtask_queues: Rc<Vec<Rc<MicrotaskQueue>>>,
job_queue: *mut JobQueue,
networking_task_src: Option<Box<SendableTaskSource>>,
}
@ -581,9 +615,15 @@ impl Runtime {
InitConsumeStreamCallback(cx, Some(consume_stream), Some(report_stream_error));
let microtask_queue = Rc::new(MicrotaskQueue::default());
let mut interrupt_microtask_queues: Rc<Vec<Rc<MicrotaskQueue>>> = Rc::new(vec![]);
// TODO: SAFETY: is this ok? It subverts the Rc::get_mut() check
let interrupt_queues_raw = Rc::get_mut(&mut interrupt_microtask_queues)
.expect("Guaranteed by usage of `new_queue`")
as *mut _ as *mut c_void;
let job_queue = CreateJobQueue(
&JOB_QUEUE_TRAPS,
&*microtask_queue as *const _ as *const c_void,
interrupt_queues_raw,
);
SetJobQueue(cx, job_queue);
SetPromiseRejectionTrackerCallback(cx, Some(promise_rejection_tracker), ptr::null_mut());
@ -728,6 +768,7 @@ impl Runtime {
Runtime {
rt: runtime,
microtask_queue,
interrupt_microtask_queues,
job_queue,
networking_task_src: (!networking_task_src_ptr.is_null())
.then(|| Box::from_raw(networking_task_src_ptr)),
@ -742,6 +783,8 @@ impl Runtime {
impl Drop for Runtime {
#[allow(unsafe_code)]
fn drop(&mut self) {
// Clear our microtask_queue, but do not touch any interrupt_microtask_queues.
// Those are under SpiderMonkeys control, even though we are responsible for their lifetimes.
self.microtask_queue.clear();
unsafe {