Skip to content

merge train: land #10138 (Emscripten main + side modules) - #10140

Merged
proggeramlug merged 4 commits into
mainfrom
train168
Sep 12, 2026
Merged

merge train: land #10138 (Emscripten main + side modules)#10140
proggeramlug merged 4 commits into
mainfrom
train168

Conversation

@proggeramlug

@proggeramlug proggeramlug commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

Merge train landing #10138 (fix(wasm): support Emscripten main and side modules, Fixes #10102) on top of main 63910ad16.

Close keywords do not fire through a train branch, so #10138 is closed with a
pointer comment after this lands and #10102 swept by hand.

The finding: this PR's subject is never built by the ordinary arms

perry-runtime's WebAssembly support is behind #[cfg(feature = "wasm-host")],
which is not a default feature. So cargo check -p perry-runtime --tests
and cargo test -p perry-runtime — which pass on this branch, 3670 tests, zero
failures — never compile webassembly.rs, webassembly_calls.rs or
webassembly_host.rs at all. A PR that rewrites ~1,000 lines of that subsystem
can pass both with its own subject unbuilt.

Running the feature explicitly fails on this branch and passes on main:

cargo check -p perry-runtime --tests --features wasm-host
error[E0425]: cannot find function `wasm_memory_new_buffer` in this scope
  --> crates/perry-runtime/src/object/global_this_webassembly.rs:1629
  --> crates/perry-runtime/src/object/global_this_webassembly.rs:1677

#10138 gates wasm_memory_new_buffer to not(feature = "wasm-host") — with the
host present, memory comes from the real wasm host rather than a registered
ArrayBuffer — but leaves two tests calling it unconditionally. Both exercise the
fallback that function is, so they are gated the same way rather than given a
wasm-host variant: with the feature on there is nothing there to test.

That arm is now permanent in this worktree's validation protocol. It is the only
thing standing between a wasm-subsystem PR and a green run over code that was
never compiled.

Maintainer fix commits

  • fix(wasm): scope #10138's handle reads to their non-allocating calls
    the raw-handle ratchet went 944 -> 953 with two violations ceilings cannot
    absorb: webassembly_calls.rs is new (--no-raise-vs <merge-base> refuses a
    ceiling on a file absent at the base) and webassembly.rs cannot have its
    ceiling raised (20 -> 24). All nine sites are argument-position reads handed to
    a non-allocating store or a self-rooting entry point, so they become
    with_{mut,const}_ptr. That retires one pre-existing site too: recorded total
    944 -> 943, --no-raise-vs origin/main reports "none raised". These
    conversions live in the wasm-host-gated files, so they were themselves only
    type-checked once the feature arm was added.
  • fix(wasm): gate the ArrayBuffer-memory tests to not(wasm-host) — above.
  • chore: bump workspace version to 0.5.1541.

Validation

raw_handle_debt.py / gc_runtime_root_holders.py / addr_class_inventory.py
string_payload_access_inventory.py / check_file_size.sh / cargo fmt --check   rc=0
cargo check -p perry-stdlib                                    rc=0
cargo check -p perry-runtime --tests --features regex-engine   rc=0
cargo check -p perry-runtime --tests --features wasm-host      rc=0   <- the arm that caught it
cargo check -p perry-wasm-host --tests                         rc=0
RUSTFLAGS=-Dwarnings cargo check -p perry --bins                rc=0
RUST_TEST_THREADS=1 cargo test --release -p perry-runtime      3670 passed, 0 failed
RUST_TEST_THREADS=1 cargo test --release -p perry-wasm-host      15 passed, 0 failed
RUST_TEST_THREADS=1 cargo test --release -p perry-codegen      1982 passed, 0 failed

5667 tests, zero failures. Exit codes captured from each command itself.

Known red on main, not from this train

test_gap_gc_http2_pending_event_callback_rooting hangs on main, bisected to
#10077 and tracked in #10137.

Summary by CodeRabbit

  • New Features

    • Improved WebAssembly interoperability between main and side modules, including shared functions, tables, memories, and mutable globals.
    • Added support for WebAssembly table, global, and memory creation and manipulation.
    • Preserved exact 64-bit integer values and improved multi-argument WebAssembly export calls.
    • Added support for dynamic file and WebAssembly asset imports with import attributes.
    • Added optional diagnostics for standalone WebAssembly loading.
  • Bug Fixes

    • Improved import resolution, externref handling, and JavaScript Proxy-based module linking.
  • Chores

    • Updated the project version to 0.5.1541.

Ralph Küpper added 4 commits September 12, 2026 17:53
Train168 (#10138) lands on main at 0.5.1540; the PR did not bump the version,
which is the maintainer's job at merge time. Cargo.lock regenerated so every
workspace member's inherited version moves with it.
The raw-handle ratchet went 944 -> 953 on this PR, with two violations that
ceilings cannot absorb: `webassembly_calls.rs` is new, and
`--no-raise-vs <merge-base>` refuses a ceiling on a file absent at the base,
while `webassembly.rs` cannot have its existing ceiling raised (20 -> 24).

All nine sites are argument-position reads handed straight to a non-allocating
store or a self-rooting entry point, which is what `with_{mut,const}_ptr` is
for:

- `webassembly_calls.rs`: the settle path's `js_promise_resolve`/`_reject` and
  its boxed return, and the instance-result `then` closure's capture store and
  boxed pointer.
- `webassembly.rs`: `object_set`'s receiver and key, and the two import-resolution
  key reads feeding `js_object_get_field_by_name_f64`.

That also retires one pre-existing site, so the recorded total falls 944 -> 943
(`--no-raise-vs origin/main`: "none raised").
#10138 makes `wasm_memory_new_buffer` `#[cfg(not(feature = "wasm-host"))]` — with
the host present, memory comes from the real wasm host instead of a registered
ArrayBuffer — but leaves two tests calling it unconditionally:

    error[E0425]: cannot find function `wasm_memory_new_buffer` in this scope
      --> crates/perry-runtime/src/object/global_this_webassembly.rs:1629
      --> crates/perry-runtime/src/object/global_this_webassembly.rs:1677

`cargo check -p perry-runtime --tests --features wasm-host` therefore fails on
this branch while it passes on `main`. Both tests exercise the fallback the
function implements, so they are gated the same way rather than given a
wasm-host variant: with the feature on there is no such function to test.

Worth noting how this was nearly missed. `webassembly.rs` and friends sit behind
`#[cfg(feature = "wasm-host")]`, which is not a default feature, so the ordinary
`cargo check -p perry-runtime --tests` and `cargo test -p perry-runtime` arms
never compile them at all. A PR that rewrites 1,000 lines of WebAssembly support
can pass both while its own subject is never built — including, in this train,
the raw-handle conversions made to that same file.
@proggeramlug
proggeramlug merged commit ea3a091 into main Sep 12, 2026
21 of 22 checks passed
@proggeramlug
proggeramlug deleted the train168 branch September 12, 2026 16:17
@coderabbitai

coderabbitai Bot commented Sep 12, 2026

Copy link
Copy Markdown

Review Change StackReview Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: 0be43810-4b4a-48f3-893d-29112f22f54b

📥 Commits

Reviewing files that changed from the base of the PR and between 63910ad and 406a7ff.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (17)
  • CLAUDE.md
  • Cargo.toml
  • changelog.d/10102-wasm-main-side-modules.md
  • crates/perry-runtime/src/object/global_this.rs
  • crates/perry-runtime/src/object/global_this_webassembly.rs
  • crates/perry-runtime/src/webassembly.rs
  • crates/perry-runtime/src/webassembly_calls.rs
  • crates/perry-runtime/src/webassembly_host.rs
  • crates/perry-wasm-host/src/externals.rs
  • crates/perry-wasm-host/src/lib.rs
  • crates/perry-wasm-host/src/shared_import_tests.rs
  • crates/perry-wasm-host/src/tables.rs
  • crates/perry/src/commands/compile/collect_modules/tests.rs
  • crates/perry/src/commands/compile/collect_modules_helpers.rs
  • crates/perry/tests/issue_5234_wasm_esm_import.rs
  • scripts/raw_handle_debt_baseline.txt
  • scripts/raw_handle_debt_files.txt

📝 Walkthrough

Walkthrough

The pull request extends the WebAssembly host with shared main/side-module resources, host-backed Table, Global, and Memory objects, expanded function marshalling, compiled-module instantiation, dynamic asset embedding, and regression coverage.

Changes

WebAssembly runtime and asset loading

Layer / File(s) Summary
Host ABI and shared runtime
crates/perry-runtime/src/webassembly_host.rs, crates/perry-wasm-host/src/lib.rs, crates/perry-wasm-host/src/tables.rs
The host ABI now supports extern kinds, externref values, import resolution, shared thread-local stores, atomic instance state, and external function handles.
Shared externals and WebAssembly objects
crates/perry-runtime/src/object/*, crates/perry-runtime/src/webassembly.rs, crates/perry-wasm-host/src/externals.rs, crates/perry-wasm-host/src/shared_import_tests.rs
Memory, table, global, and function wrappers now map to host externals. WebAssembly constructors and accessors use host resources under wasm-host.
Instantiation and export calls
crates/perry-runtime/src/webassembly_calls.rs, crates/perry-runtime/src/webassembly.rs
The runtime adds compiled-module instantiation, export-call shims through arity 16, numeric result decoding, exact i64/BigInt conversion, promise-compatible results, and host error handling.
Dynamic assets and regression coverage
crates/perry/src/commands/compile/collect_modules_helpers.rs, crates/perry/src/commands/compile/collect_modules/tests.rs, crates/perry/tests/issue_5234_wasm_esm_import.rs, changelog.d/10102-wasm-main-side-modules.md, Cargo.toml, CLAUDE.md, scripts/*
Dynamic imports with type: "wasm" or type: "file" are collected and embedded. Tests cover shared resources, WebAssembly constructors, multi-argument exports, and asset paths. Version, changelog, and raw-handle baseline files are updated.

Estimated code review effort: 5 (Critical) | ~90 minutes

Change: Feature

Sequence Diagram(s)

sequenceDiagram
  participant JS
  participant Runtime
  participant Host
  participant MainModule
  participant SideModule
  JS->>Runtime: instantiate module with imports
  Runtime->>Host: compile and resolve imports
  Host->>MainModule: create shared resources
  Runtime->>Host: instantiate side module
  Host->>SideModule: attach shared externals
  SideModule->>MainModule: read and update shared memory, table, global, and function
  MainModule-->>JS: return shared state and export results
Loading

Possibly related PRs

  • PerryTS/perry#8299: Adds the earlier static .wasm ESM import and initial WebAssembly import callback flow extended by this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch train168

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

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.

runtime/AOT (refines #8508): Emscripten main+side-module loading (web-tree-sitter + grammars) and wasm-bindgen (photon) for OpenCode v1.18.30

1 participant