Skip to content

Commit d400a15

Browse files
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

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)