Skip to content

feat(core): update v8 to 146.8.0 with foreground task ownership#32771

Merged
bartlomieju merged 10 commits intomainfrom
feat/v8-task-ownership
Mar 18, 2026
Merged

feat(core): update v8 to 146.8.0 with foreground task ownership#32771
bartlomieju merged 10 commits intomainfrom
feat/v8-task-ownership

Conversation

@bartlomieju
Copy link
Copy Markdown
Member

Summary

  • Updates the v8 crate from 146.5.0 to 146.8.0 (includes rusty_v8#1934)
  • Updates DenoPlatformImpl to receive v8::Task / v8::IdleTask ownership from the C++ custom platform, instead of tasks being queued in DefaultPlatform
  • Tasks are queued per-isolate and drained/run directly on the event loop, removing the need for PumpMessageLoop
  • Follows up on fix: wake event loop when V8 posts foreground tasks from background threads #32450 by adapting deno_core to the new rusty_v8 task ownership API

Test plan

  • cargo check passes (full workspace)
  • tools/format.js clean
  • tools/lint.js clean
  • CI: existing test_pump_message_loop and atomics_wait_async_notify spec tests validate foreground task delivery

🤖 Generated with Claude Code

bartlomieju and others added 4 commits March 16, 2026 15:19
Updates the v8 crate to 146.8.0 which includes rusty_v8#1934. The
custom V8 platform now receives ownership of foreground tasks via
v8::Task and v8::IdleTask types, instead of tasks being queued in the
default platform. This eliminates the need for PumpMessageLoop and lets
deno_core run V8 foreground tasks directly on the event loop.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Instead of manually queuing tasks in a registry and draining them
in the event loop, spawn them directly onto the isolate's tokio
runtime handle. This removes the timer thread, task queues, and
the PumpMessageLoop call entirely.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Verifies that V8 foreground tasks are delivered to the correct
isolate when multiple workers use Atomics.waitAsync concurrently.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Some unit tests and snapshot creation run JsRuntime without a tokio
runtime. Use try_current() to gracefully skip waker registration
instead of panicking.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
if let Some(entry) = map.get(&key) {
let waker = entry.waker.clone();
entry.handle.spawn(async move {
task.run(0.0);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

v8 uses the value passed here like this for example:

while (deadline_in_seconds > platform_->MonotonicallyIncreasingTime()) {

so if you want the job to actually do anything you need to pass a value greater than the current monotonic timestamp.

in chromium all the idle tasks are queued together. and when there is idle time in the render process it will calculate a deadline and drain that queue until empty or it runs out of time.

this approach doesn't make much sense in server runtimes, so some other behavior needs to be selected i guess? but also worth noting is that in node the PostIdleTaskImpl just calls UNREACHABLE(), so maybe we don't need to care about it.

bartlomieju and others added 3 commits March 16, 2026 16:23
V8 idle tasks check `deadline > MonotonicallyIncreasingTime()`, so
passing 0.0 makes them no-ops. Node also ignores idle tasks entirely.
Just drop them without running.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Idle tasks are not used in server runtimes — Node also marks this
as UNREACHABLE(). Panic if V8 ever posts one unexpectedly.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Immediate foreground tasks must run synchronously during the event
loop poll to preserve microtask/timer ordering and ensure the event
loop sees their effects before checking pending state. Delayed tasks
use tokio::spawn with tokio::time::sleep.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@bartlomieju bartlomieju requested a review from devsnek March 16, 2026 18:10
bartlomieju and others added 3 commits March 17, 2026 18:43
- Remove `pump_v8_message_loop` from `PollEventLoopOptions` — foreground
  tasks are now always drained unconditionally on every event loop tick.
- Share the `ForegroundTaskQueue` (Arc<Mutex<Vec<v8::Task>>>) between
  `JsRuntimeState` and the global platform registry so the event loop
  drains tasks from its local Arc without touching the global map.
- Delayed tasks now queue into the shared Vec after sleeping instead of
  running directly on a tokio worker thread, ensuring they execute on
  the isolate's foreground thread.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove needless `..Default::default()` now that the struct has only
one field.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@bartlomieju bartlomieju merged commit 7d810ee into main Mar 18, 2026
112 checks passed
@bartlomieju bartlomieju deleted the feat/v8-task-ownership branch March 18, 2026 08:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants