Skip to content

Bridge Wasm exception transport into Control delimiter bookkeeping #156

Closed

Description

@biuld

The native exception transport and stack budget landed in #149–#155. The stage-1 Control bridge is completed in #157 (2026-10-20). CB-01..CB-15 are Verified in the committed design and execution checklist; the closing comment records the full validation and serial runtime remeasurement. The scope and downstream exclusions below remain unchanged.

References

Correction to the handoff accounting proposal

The machine captures persistent heap queues, not native stacks. Inspection of the native budget emission and actual Resume/cancel plans shows no native charge attached to a saved queue: return/tail epilogues already settle native activations. Do not subtract queue weights at cancel, and do not implement the proposed saved − ΣW_f(live remaining chain) restoration. The design derives the existing native depth = saved rule. Execution evidence is still required.

The actual lifecycle gaps are normal-only root closure and normal-only completion of acquired one-shot owners. A channel throw can bypass both.

Stage 1 — bridge scope

  • Add a target-neutral opaque exception-reference shape and generic CC protected regions with explicit Yield/Propagate exits. Verify binder scope and disjointness from erased source payloads.
  • Add MIR Exn, ordered catch clauses, CatchAllRef, and ThrowRef. CatchAllRef carries one exception reference; named payload-plus-reference catches remain unsupported until multi-result labels are designed.
  • Extend the single shared try-region/unwind relation. Inner handler bodies must remain protected by enclosing native regions. Unknown-tag ThrowRef must retain all possible enclosing catches/caller propagation without a private single-handler guess.
  • Protect the flat executor from the run helper. Exceptional exit closes that run's root and propagates the original exception. Existing ancestor checks expire abandoned child checkpoints; no extent registry or GC finalizer is needed.
  • Protect acquired-owner callback application locally. Pending → Running clears the callback slot before guest code. Normal and exceptional callback exit both end in Consumed. Illegal acquisition retains its existing rejection trap.
  • Restore the native watermark before cleanup. Cleanup uses direct private-cell writes, without allocation, callbacks, or instrumented helper calls that could exhaust again.
  • Keep native catch scope dynamic. A saved queue carries neither a native catch nor a budget charge. Ordinary Control handle is not an exception handler. The run guard covers all installs and interpreted resumes in its flat executor.

Abort produces no answer pair and guarantees lifecycle consistency; it does not roll back state, IO, or source mutations. Engine traps and foreign-resource recovery remain separate contracts.

Downstream consumers

  • Stage 2: a separately typed library exception-as-effect operation and recovery/transaction policy.
  • Stage 3: official Effect.Exception using direct native dynamic throw/catch plus bridge cleanup when a throw exits a runner.

Both consume stage 1; stage 3 does not strictly depend on stage 2. Neither public API is implemented by completing this bridge.

Validation

Follow the compiler iteration SOP before compiler changes. Implement and verify every CB-01..CB-15 row, including malformed CC/MIR, construction-plan mutations, original tag/payload identity through propagation, exceptional root expiry, acquired-owner completion, cancellation/abandonment accounting, nested runs/replay ancestry, dynamic lexical catches, budget exhaustion in cleanup paths, disabled profiles and optimized source execution. Runtime evidence must actually execute.

Run cargo fmt --all --check, cargo clippy --workspace --all-targets -- -D warnings, and PSRS_STDLIB_ROOT=/home/biu/Projects/psrs-stdlib PSRS_REQUIRE_WASMTIME=1 cargo test --workspace for Rust changes. Budget evidence pins -W max-wasm-stack=524288 and records the actual engine version. Follow the serial per-root runtime board protocol and remeasure before changing D-04; current boards do not establish Control × exception behavior.

Completion requires every checklist row Verified. Bridge completion does not close BE-21 or claim either downstream API complete.

Activity

  1. added
    gate:L6/M7Blocks runtime and the standard library (D-04 L6, M7)
    area:backendBackend: CC, MIR, Wasm encoding, WIT/ABI, WASI
    on Oct 19, 2026
  2. biuld commented on Oct 20, 2026

    @biuld
    OwnerAuthor

    Completed in #157, merged with a merge commit. The acceptance record verifies CB-01..CB-15 and maps each requirement to its owning code and evidence:
    https://github.com/biuld/purescript-rs/blob/master/docs/implementation/backend/control-exception-bridge.md

    Validation on the final candidate:

    • cargo fmt --all --check, required-Wasmtime cargo test --workspace, and cargo clippy --workspace --all-targets -- -D warnings passed. Backend: 602 unit tests; driver: 859; workspace integration tests and doctests passed.
    • All 14 source bridge tests passed with ordinary optimization and with MIR optimization bypassed (0 failed, 0 ignored). Emitted guests directly observe Consumed owner status and callback release, later resume/cancel rejection, and both nested-run checkpoint expiries. IR/model evidence covers original tag/reference-payload forwarding, malformed protection, unwind/capability rules and non-throwing cleanup.
    • The closing serial release runtime remeasurement is 287/340, all agreeing exits 0; 25 FFI roots excluded from 365 roots. Agreeing/failing name sets and stage decomposition are unchanged. BigFunction still has no compiler verdict: its outer harness timeout is counted as incomplete, never as a pass or compiler diagnostic. D-04 and README record this measurement.
    • PR CI passed using the workflow's pinned Wasmtime. Local budget evidence used Wasmtime 48.0.1 and -W max-wasm-stack=524288. Standard-library source and pin remain unchanged.

    This closes the stage-1 bridge only. BE-21, official Effect.Exception, exception-as-effect APIs, engine-trap recovery and foreign-resource cleanup retain their separate obligations. No corpus-blocker count moved, so the Corpus cases field is unchanged. Project Status is Done.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:backendBackend: CC, MIR, Wasm encoding, WIT/ABI, WASIgate:L6/M7Blocks runtime and the standard library (D-04 L6, M7)

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions