From a9cf04de48ddfc30ef8e786bec414b90759e1c14 Mon Sep 17 00:00:00 2001 From: jedel1043 Date: Thu, 8 Jun 2023 19:41:21 -0600 Subject: [PATCH] Allow `JobQueue` to concurrently run jobs --- boa_engine/src/context/mod.rs | 18 +++++++++++++++++- boa_engine/src/job.rs | 20 ++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/boa_engine/src/context/mod.rs b/boa_engine/src/context/mod.rs index 3863cff98d3..f5d76ee5324 100644 --- a/boa_engine/src/context/mod.rs +++ b/boa_engine/src/context/mod.rs @@ -409,6 +409,22 @@ impl<'host> Context<'host> { self.clear_kept_objects(); } + /// Asynchronously runs all the jobs in the job queue. + /// + /// # Note + /// + /// Concurrent job execution cannot be guaranteed by the engine, since this depends on the + /// specific handling of each [`JobQueue`]. If you need to ensure that jobs are executed + /// concurrently, you can provide a custom implementor of `JobQueue` to the context. + #[allow(clippy::future_not_send)] + pub async fn run_jobs_async<'a>(self: &'a mut Context<'host>) + where + 'host: 'a, + { + self.job_queue().run_jobs_async(self).await; + self.clear_kept_objects(); + } + /// Abstract operation [`ClearKeptObjects`][clear]. /// /// Clears all objects maintained alive by calls to the [`AddToKeptObjects`][add] abstract @@ -424,7 +440,7 @@ impl<'host> Context<'host> { /// Retrieves the current stack trace of the context. #[inline] - pub fn stack_trace(&mut self) -> impl Iterator { + pub fn stack_trace(&self) -> impl Iterator { self.vm.frames.iter().rev() } diff --git a/boa_engine/src/job.rs b/boa_engine/src/job.rs index 0b828815acd..d9049897129 100644 --- a/boa_engine/src/job.rs +++ b/boa_engine/src/job.rs @@ -225,6 +225,26 @@ pub trait JobQueue { /// to do this will leave the inner `Promise` in the `pending` state, which won't call any `then` /// or `catch` handlers, even if `future` was already completed. fn enqueue_future_job(&self, future: FutureJob, context: &mut Context<'_>); + + /// Asynchronously runs all jobs in the queue. + /// + /// Running a job could enqueue more jobs in the queue. The implementor of the trait + /// determines if the method should loop until there are no more queued jobs or if + /// it should only run one iteration of the queue. + /// + /// By default forwards to [`JobQueue::run_jobs`]. Implementors using async should override this + /// with a proper algorithm to run jobs asynchronously. + fn run_jobs_async<'a, 'ctx, 'host, 'fut>( + &'a self, + context: &'ctx mut Context<'host>, + ) -> Pin + 'fut>> + where + 'a: 'fut, + 'ctx: 'fut, + 'host: 'fut, + { + Box::pin(async { self.run_jobs(context) }) + } } /// A job queue that does nothing.