diff --git a/Cargo.lock b/Cargo.lock index 2c6c718a122..58d5c0b5afd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5240,7 +5240,7 @@ dependencies = [ [[package]] name = "mozjs" version = "0.14.1" -source = "git+https://github.com/servo/mozjs#9c017973a4bf9186df2335d8c96ed3554b84434e" +source = "git+https://github.com/servo/mozjs#b23161580b082e1ccfa3273d94f43f6168aedc3d" dependencies = [ "bindgen 0.71.1", "cc", @@ -5251,8 +5251,8 @@ dependencies = [ [[package]] name = "mozjs_sys" -version = "0.128.13-1" -source = "git+https://github.com/servo/mozjs#9c017973a4bf9186df2335d8c96ed3554b84434e" +version = "0.128.13-2" +source = "git+https://github.com/servo/mozjs#b23161580b082e1ccfa3273d94f43f6168aedc3d" dependencies = [ "bindgen 0.71.1", "cc", diff --git a/components/script/script_runtime.rs b/components/script/script_runtime.rs index d82a6c126b7..c054ae6afef 100644 --- a/components/script/script_runtime.rs +++ b/components/script/script_runtime.rs @@ -88,6 +88,9 @@ 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), + dropInterruptQueues: Some(drop_interrupt_queues), }; static SECURITY_CALLBACKS: JSSecurityCallbacks = JSSecurityCallbacks { @@ -248,6 +251,41 @@ 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) -> *const c_void { + let mut result = std::ptr::null(); + wrap_panic(&mut || { + let mut interrupt_queues = Box::from_raw(interrupt_queues as *mut Vec>); + let new_queue = Rc::new(MicrotaskQueue::default()); + result = Rc::as_ptr(&new_queue) as *const c_void; + interrupt_queues.push(new_queue.clone()); + std::mem::forget(interrupt_queues); + }); + result +} + +#[allow(unsafe_code)] +unsafe extern "C" fn pop_interrupt_queue(interrupt_queues: *mut c_void) -> *const c_void { + let mut result = std::ptr::null(); + wrap_panic(&mut || { + let mut interrupt_queues = Box::from_raw(interrupt_queues as *mut Vec>); + let popped_queue: Rc = + interrupt_queues.pop().expect("Guaranteed by SpiderMonkey?"); + // Dangling, but jsglue.cpp will only use this for pointer comparison. + result = Rc::as_ptr(&popped_queue) as *const c_void; + std::mem::forget(interrupt_queues); + }); + result +} + +#[allow(unsafe_code)] +unsafe extern "C" fn drop_interrupt_queues(interrupt_queues: *mut c_void) { + wrap_panic(&mut || { + let interrupt_queues = Box::from_raw(interrupt_queues as *mut Vec>); + drop(interrupt_queues); + }); +} + /// SM callback for promise job resolution. Adds a promise callback to the current /// global's microtask queue. #[allow(unsafe_code)] @@ -474,6 +512,7 @@ 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, job_queue: *mut JobQueue, networking_task_src: Option>, @@ -581,9 +620,16 @@ impl Runtime { InitConsumeStreamCallback(cx, Some(consume_stream), Some(report_stream_error)); let microtask_queue = Rc::new(MicrotaskQueue::default()); + + // Extra queues for debugger scripts (“interrupts”) via AutoDebuggerJobQueueInterruption and saveJobQueue(). + // Moved indefinitely to mozjs via CreateJobQueue(), borrowed from mozjs via JobQueueTraps, and moved back from + // mozjs for dropping via DeleteJobQueue(). + let interrupt_queues: Box>> = Box::default(); + let job_queue = CreateJobQueue( &JOB_QUEUE_TRAPS, &*microtask_queue as *const _ as *const c_void, + Box::into_raw(interrupt_queues) as *mut c_void, ); SetJobQueue(cx, job_queue); SetPromiseRejectionTrackerCallback(cx, Some(promise_rejection_tracker), ptr::null_mut()); @@ -742,8 +788,10 @@ impl Runtime { impl Drop for Runtime { #[allow(unsafe_code)] fn drop(&mut self) { + // Clear our main microtask_queue. self.microtask_queue.clear(); + // Delete the RustJobQueue in mozjs, which will destroy our interrupt queues. unsafe { DeleteJobQueue(self.job_queue); }