Skip to content

feat: bump vendored rusty_v8 to v152.1.0 - #73

Open
bartlomieju wants to merge 3 commits into
mainfrom
bump-rusty-v8-152.1.0
Open

feat: bump vendored rusty_v8 to v152.1.0#73
bartlomieju wants to merge 3 commits into
mainfrom
bump-rusty-v8-152.1.0

Conversation

@bartlomieju

Copy link
Copy Markdown
Collaborator

Moves the vendor/rusty_v8 pin from v149.4.0 to v152.1.0 and brings the QuickJS
backend up to the C ABI that release declares. The surface moved by 15 added and
5 removed v8__* symbols, 4 added and 5 removed crdtp__* symbols, and 13
added v8_inspector__* symbols.

Both patches/rusty_v8-* apply unchanged, because scope.rs, scope/raw.rs
and value_serializer.rs are byte-identical between the two tags. gen/ now
carries the v152.1.0 release assets, and the identical-within-OS-family claim
still holds, including the ptrcomp variants that upstream added: 22 assets,
3 distinct contents.

What the QuickJS backend gained

v8::Locker and v8::Unlocker land in a new src/quickjs/locker.rs. A
JSRuntime can move between threads as long as one thread uses it at a time,
which is the contract v8::Locker states, so the lock is a per-isolate mutex
plus JS_UpdateStackTop whenever the entering thread changes. That call
matters because the runtime records its stack-overflow bounds at creation and
those bounds belong to the creating thread. IsLocked reads a published atomic
instead of taking the mutex, since it sits on the Global clone, drop, hash and
compare path. v8__Isolate__TryGetCurrent reports only an isolate that is
actually entered: current_iso deliberately falls back to the last isolate the
thread ran, and Locker asserts on this before taking the lock, so the fallback
would misfire on a thread that had merely used an isolate earlier.

Callable objects arrive with Object::{IsCallable, IsConstructor, CallAsFunction, CallAsConstructor} and ObjectTemplate::SetCallAsFunctionHandler.
QuickJS does not distinguish a callable object from a function object and cannot
add a [[Call]] slot to an ordinary object after the fact, so a template that
carries a call handler builds its instances as function objects from the start.
Interceptors need the exotic class instead, so the two cannot be combined.

MicrotaskQueueHandle replaces MicrotaskQueue::{New, DESTRUCT}. One
allocation backs both types in this backend, so the handle is the queue pointer
and Get is the identity.

crdtp gained Dispatchable associated data and the fallthrough callback, and
lost its probe phase: BASE__Dispatch now takes a live &Dispatchable and runs
the command, reporting whether it handled it. The old probe-then-execute split
would call it twice and send two responses.

The inspector gained session wrapObject, releaseObjectGroup and
addInspectedObject, built over the RemoteObject JSON the console path already
produces. This backend retains no remote references, so releaseObjectGroup has
nothing to release, and it serves no $0 to $4 history, so an added
inspectable is released rather than leaked.

v8::String::ValueView changed shape rather than gaining a symbol: rusty_v8
stopped calling the three accessors and now reads the fields straight out of the
buffer CONSTRUCT fills. Both backends therefore lay their state out the way
v8-primitive.h does. The JSC backend gets that change and the ICU 77 to 78
rename, but is otherwise untouched, and I could not build it here, so it needs
a CI pass.

The simdutf Cargo feature becomes a no-op, since upstream dropped the split
(denoland/rusty_v8#2048) and string.rs now calls crate::simdutf on every
path. The feature is kept so existing dependency declarations keep resolving.

Ratchet

quickjs/rusty_v8 goes from 268 to 303 baselined tests, and test_api links
for the first time. The baseline keeps
test_concurrent_isolate_creation_and_disposal, which is cfg-ed out on
aarch64 and so cannot be observed on the machine that regenerated the file.

Nine tests still fail, all new in this release:

  • crdtp_uber_dispatcher_fallthrough
  • inspector_wrap_object, inspector_value_subtype,
    inspector_release_object_group, inspector_inspected_object_round_trip,
    inspector_inspected_object_drops_rust_impl_when_evicted
  • global_off_thread_drop_is_drained_on_home_thread,
    shared_isolate_after_weak_into_raw,
    shared_isolate_rust_callback_across_threads

The last group shares one cause worth flagging: this backend keeps per-isolate
Rust state in thread-locals, including the function dispatch table
(src/quickjs/function.rs DISPATCH), the module caches and the template
registry. An isolate that migrates to another thread therefore loses its
Rust-registered callbacks, which is why rustCallJs returns 0 when it runs on a
second thread. The comment on dispatch_entry already calls that table
"process-global"; it is not. Making that state follow the isolate rather than
the thread is a change of its own, so it is not in this PR.

Moves the `vendor/rusty_v8` pin from v149.4.0 to v152.1.0 and brings the
QuickJS backend up to the C ABI that release declares. The surface moved by
15 added and 5 removed `v8__*` symbols, plus 4 added and 5 removed `crdtp__*`
symbols and 13 added `v8_inspector__*` symbols.

Both `patches/rusty_v8-*` apply unchanged: `scope.rs`, `scope/raw.rs` and
`value_serializer.rs` are byte-identical between the two tags. `gen/` carries
the v152.1.0 release assets; the identical-within-OS-family claim still holds,
now including the `ptrcomp` variants (22 assets, 3 distinct contents).

What the backend gained:

- `v8::Locker` and `v8::Unlocker`, in `src/quickjs/locker.rs`. A JSRuntime can
  move between threads as long as one thread uses it at a time, so the lock is
  a per-isolate mutex plus `JS_UpdateStackTop` whenever the entering thread
  changes, since the runtime's stack-overflow bounds belong to whichever thread
  created it. `IsLocked` reads an atomic rather than taking the mutex because
  it sits on the `Global` clone and drop path.
- `v8__Isolate__TryGetCurrent`, which reports only an entered isolate.
  `current_iso` falls back to the last isolate the thread ran, and `Locker`
  asserts on this before taking the lock, so the fallback would misfire.
- Callable objects (`Object::{IsCallable,IsConstructor,CallAsFunction,
  CallAsConstructor}` and `ObjectTemplate::SetCallAsFunctionHandler`). QuickJS
  does not distinguish a callable object from a function object, so a template
  with a call handler builds its instances as function objects.
- `MicrotaskQueueHandle`, which replaces `MicrotaskQueue::{New,DESTRUCT}`. One
  allocation backs both types here, so `Get` is the identity.
- `Dispatchable` associated data and the crdtp fallthrough callback. The probe
  phase is gone: `BASE__Dispatch` now takes a live `&Dispatchable` and runs the
  command, so calling it twice would send two responses.
- Session `wrapObject`, `releaseObjectGroup` and `addInspectedObject`, over the
  RemoteObject JSON the console path already builds.

`v8::String::ValueView` changed shape rather than gaining a symbol: rusty_v8
now reads the fields straight out of the buffer instead of calling the three
accessors, so both backends lay their state out the way `v8-primitive.h` does.
The JSC backend gets that change and the ICU 77 to 78 rename, but is otherwise
untouched and unverified here.

The `simdutf` Cargo feature becomes a no-op: upstream dropped the split and
`string.rs` now calls `crate::simdutf` unconditionally. The feature stays so
existing dependency declarations keep resolving.

quickjs/rusty_v8 goes from 268 to 303 baselined tests, and `test_api` links
for the first time. Nine tests still fail, all new in this release; the notable
group is the shared-isolate ones, which fail because this backend keeps
per-isolate Rust state (the function dispatch table, module caches, template
registry) in thread-locals, so an isolate that migrates loses its Rust
callbacks. That is its own change.
The bump commit only carried the QuickJS backend, so `check-jsc`,
`check-sys-jsc` and the Windows legs went red.

The JSC backends were missing all 21 new symbols. `src/jsc/locker.rs` is the
QuickJS locker without the `JS_UpdateStackTop` step: JSC serializes heap access
with its own JSLock, so what the shim adds is the ownership shape `v8::Locker`
promises and a home for the per-isolate bookkeeping. Callable objects,
`MicrotaskQueueHandle`, `TryGetCurrent` and the WebAssembly trap handler follow
the QuickJS versions. `ObjectTemplate::SetCallAsFunctionHandler` builds the
instance with `make_function_len` for the same reason QuickJS does: neither
engine can add a [[Call]] slot to an ordinary object afterwards. The inspector
symbols land at this backend's existing level, since it answers the protocol
without an injected script and so cannot wrap a live remote reference.

Windows failed on `v8_String_WriteFlags_kNullTerminate`, which the shim read
instead of the `v8__String__WriteFlags__kNullTerminate` upstream's own
`string.rs` uses. Both spellings appear in the Linux and Apple bindings, but
only the second appears in the MSVC one, so the first happened to work until
this release regenerated the assets. Both backends now read what upstream does.

sys-jsc/rusty_v8 goes from 46 to 47.
`check-jsc` links and runs after the C ABI port, and reports the same single
new pass the sys-jsc leg did. The vendored-WebKit backend cannot be built
outside CI, so this mirrors the sys-jsc baseline, which the two share
line-for-line.
@bartlomieju
bartlomieju force-pushed the bump-rusty-v8-152.1.0 branch from cdd4eaa to 1afa39c Compare August 12, 2026 08:42
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.

1 participant