Commit d400a15
authored
perf(ext/web): port console/inspect to Rust (cppgc object wrap) (#35087)
Port `ext/web/01_console.js` — the largest remaining JS source in the
runtime snapshot after the WebCrypto port (#34966) — from JavaScript to
Rust, following the `ext/webgpu`/`ext/crypto` pattern: `Console` is a
cppgc object wrap registered on the extension's `objects = [...]` list,
and the inspect engine is implemented as Rust ops. `01_console.js` drops
from 4184 to 706 lines and becomes a thin shim.
## What moved to Rust (`ext/web/console/`)
- `inspect.rs` — the full `formatValue`/`formatRaw` engine: primitives,
arrays (sparse/grouped), Map/Set (+ iterators, weak collections via
`preview_entries`), typed arrays, ArrayBuffer hex preview, Promise
state, boxed primitives, Proxy handling, class/function bases,
circular-`<ref *n>` tracking, getter evaluation, prototype-chain
constructor naming, `showHidden` proto-property walk, custom-inspect
hooks (`Deno.customInspect`, `Deno.privateCustomInspect`,
`nodejs.util.inspect.custom`, incl. cross-`vm.Context` user options).
- `error_fmt.rs` — error/stack formatting: cause-stack dedup, recursive
frame collapsing (GCD range detection), cwd/`node_modules` highlighting,
`improveStack` name fixups.
- `css.rs` — `%c` handling (`parseCss`, `parseCssColor`, `cssToAnsi`).
- `table.rs` — `console.table` rendering.
- `width.rs`, `quote.rs` — display width / ANSI stripping / quoting.
- `mod.rs` — ops, options parsing, `inspectArgs` (`%s %d %i %f %j %o %O
%c %%`), and the `Console` cppgc class (`log`/`warn`/`error`/`dir`/
`assert`/`count*`/`time*`/`table`/`clear` as `#[op2]` methods; count
and timer maps and `indentLevel` live as Rust fields).
## JavaScript shim
`01_console.js` keeps the historical export surface (`inspect`,
`inspectArgs`, `formatValue`, `createFilteredInspectProxy`,
`getConsoleInspectOptions`, `styles`/`colors` tables, etc.), so all ~30
importers — including node's `util.inspect`, which builds directly on
`formatValue` with user-mutable `inspect.styles`/`inspect.colors` and
custom `stylize` callbacks — work unchanged. The shim passes a
snapshot-safe intrinsics object (primordial-captured `valueOf`s,
well-known prototypes, lazy URL prototype, cwd getter) into the ops;
the engine caches it per runtime as v8 Globals. The cppgc wrap is
created lazily on first use because no cppgc heap exists while
snapshotting.
## Measurements (release, strip -x -S, vs main)
| metric | Δ |
|---|---|
| `01_console.js` | −3478 lines (−83%) |
| snapshot (`CLI_SNAPSHOT.bin`) | −205 KB (−2.5%) |
| binary size | +33.6 KB (+0.04%) |
| startup (`deno run empty.js`, median of 40) | flat (within noise) |
| RSS, idle | flat (within noise) |
| `Deno.inspect` primitives/strings | parity |
| `Deno.inspect` plain objects/arrays (microbench) | ~2-3x slower
(descriptor materialization through the V8 C++ API; `console.log`
remains I/O-bound) |
## Behavior notes
- Output is byte-identical across the console/util test suites.
- Stack-frame cwd highlighting now reads the cwd directly (a JS-side
`Deno.cwd()` permission prompt can no longer be triggered by
formatting an error with colors).
- Frames in `node:*` modules are treated as builtin frames without
consulting `node:module`'s `isBuiltin` (in Deno, `node:` specifiers
only resolve to builtins).
## Test plan
- `cargo test unit::console_test` (87/87), `unit::error_test`,
`unit::error_stack_test`, full `unit::` suite
- `cargo test unit_node::` (incl. `util_test`, `console_test`)
- spec suites (`run`, `node`, `test`, `repl`, `eval`, `bench`, `lint`,
`fmt`, full sweep): failure set identical to main in the same
environment (remaining failures are environment-only: missing denort,
sockets, etc.)
- `tools/format.js`, `tools/lint.js --js`1 parent bf844be commit d400a15
12 files changed
Lines changed: 8307 additions & 3759 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
0 commit comments