Skip to content

feat: install host globals natively in the runtime (#38) - #43

Merged
schplitt merged 1 commit into
mainfrom
feat/native-global-install-38
Jul 25, 2026
Merged

feat: install host globals natively in the runtime (#38)#43
schplitt merged 1 commit into
mainfrom
feat/native-global-install-38

Conversation

@schplitt

Copy link
Copy Markdown
Owner

Closes #38.

What

Globals are no longer installed by prepending generated JavaScript to the user's code. The client sends each global as a structured GlobalDef and the Rust runtime installs it natively on the sandbox global object.

globals on the wire changes from List<String> (names) to List<GlobalDef>, a tagged union:

kind tail install
bridge bridge stub under name (unchanged)
string expr evaluate (expr) as its own script → object.set(name, …)
data (new) WireValue wire_to_v8_valueobject.set(name, …)
shim shim, handlerName stub under handlerName + wrapper built by a fixed factory → object.set(name, …)

Why this closes #38

  • Correct stack-trace line numbers — nothing is prepended, so user code starts at line 1. String/shim expressions compile as their own scripts with their own filenames.
  • No name interpolation — a global's name only ever travels as a string passed to object.set (or a WireValue field), never pasted into an identifier position. This removes the injection class flagged in the issue's "Additional findings".
  • New data-valued global ({ kind: 'data', value }) — constants cross as a WireValue and materialise natively (same supported set as host-module data leaves), killing the JSON.stringify-into-code pattern.

Hot path unchanged

For precompiled prefixes, string/data globals and shim wrappers are baked into the snapshot at precompile() (via install_value_globals in the snapshot isolate); prefix.run() only re-installs bridge stubs, exactly as before. No new per-run cost on the repeated-run path.

Tests

  • Rust: 214 passing (added coverage for parsing all four GlobalDef kinds).
  • TS: 460 passing — new integration tests for the data global (object, Uint8Array/bigint/null) and a line-number regression test asserting a user error reports line 1 with globals configured.
  • cargo fmt clean; clippy introduces zero new lints vs main; eslint/tsc clean.

Notes

Globals were installed by prepending generated JS to the user's code, which
shifted sandbox stack-trace line numbers and interpolated global names into
identifier positions. The client now sends each global as a structured
GlobalDef (bridge / string / data / shim) and the runtime installs it via the
V8 API: string/shim expressions evaluate as their own scripts, so user code
starts at line 1, and a global's name only ever travels as a string.

Adds a data-valued global kind ({ kind: 'data', value }) carried as a
WireValue and materialised natively — no more JSON.stringify-into-code.

Wire-protocol change: the `globals` field of Run/Precompile/PrefixRun is now a
List<GlobalDef>. @iso4/sandbox and the @iso4/v8-* binaries release together.
@schplitt
schplitt merged commit 2f0e296 into main Jul 25, 2026
1 check passed
@schplitt
schplitt deleted the feat/native-global-install-38 branch July 25, 2026 19:01
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.

Install globals natively in Rust instead of prepending generated preamble code

1 participant