From 0e1b32a232109fc0e192c1297a7274091af2ac61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Juli=C3=A1n=20Espina?= Date: Tue, 13 Jun 2023 22:29:59 +0000 Subject: [PATCH] Allow `JobQueue` to concurrently run jobs (#3036) * Allow `JobQueue` to concurrently run jobs * Remove bounds on `run_jobs_async` --- boa_engine/src/context/mod.rs | 15 ++++++++++++++- boa_engine/src/job.rs | 20 ++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/boa_engine/src/context/mod.rs b/boa_engine/src/context/mod.rs index 3863cff98d..5c4ea4fc76 100644 --- a/boa_engine/src/context/mod.rs +++ b/boa_engine/src/context/mod.rs @@ -409,6 +409,19 @@ 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(&mut self) { + 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 +437,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 0b828815ac..d904989712 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.