Skip to content

Commit 39ed894

Browse files
olwangclaude
andcommitted
docs(jit): correct J0.1 remaining-scope (live-out aggregates already OSR)
Accuracy fix after verifying current behavior: - Live-out / escaping loop-carried STRUCTS already OSR via the transactional heap-write path (native_osr_loop_carried_struct_live_after_loop_uses_heap_writes / ..._escaping_uses_heap_writes are green) — NOT a capability gap; scalar- replacing them is a pure perf refinement. - The one genuine remaining J0.1 coverage gap is perf-only: a live-after HEAP-payload variant/Result does not OSR (native_osr_j3_escaping_result_does_not_osr asserts osr_entries==0); it is correct (interpreter-run), just not accelerated. Needs the source-reg reconstruction recipe + liveness proof (a deliberate slice). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 7cec188 commit 39ed894

1 file changed

Lines changed: 22 additions & 17 deletions

File tree

docs/planning/vm-optimizing-jit-plan.md

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -133,23 +133,28 @@ machinery **engage real program shapes and prove it**, not new subsystems. In pr
133133
deopt state-map format / OSR-exit, NOT a one-liner — and none has a *correctness*
134134
driver today, so the differential cannot gate a reconstruction bug by output alone;
135135
they must be driven by dedicated repro tests):**
136-
- **(a) Live-out SCALAR aggregate reconstruction (most tractable; do first).**
137-
`native_loop_carried_struct_in_region` / the variant+struct SR passes bail when
138-
the aggregate is read after the loop (`passes.rs:7430`, the live-after / escape
139-
check). To lift that: when every field is scalar, record a *reconstruction recipe*
140-
`(orig_reg, layout/tag, [leaf_reg per field])` from the SR pass, thread it through
141-
`translate` into the OSR result, and at **OSR-exit** (reg_vm, before resuming the
142-
interpreter on the live-out window) rebuild `VmValue::Struct`/`Variant` from the
143-
leaf regs and write it into `orig_reg`. No `handle→VmValue` problem (all scalar);
144-
the differential validates correctness once a live-out-struct kernel is added.
145-
- **(b) Composite HEAP-payload reconstruction.** A variant/struct field that is a
146-
heap value (`Handle`) currently bails (`passes.rs:6205/6210`). The blocker: a heap
147-
field in a native reg is an opaque handle, and the interpreter frame no longer
148-
holds the dissolved value. Approach: extend the recipe so a heap field references
149-
its **interpreter-visible SOURCE register** (the reg the `MakeVariant`/`MakeStruct`
150-
read it from), provided that reg stays live + unclobbered to the reconstruction
151-
point (needs a liveness proof); reconstruction reads `frame.reg(source)`. Fields
152-
with no live source reg still bail.
136+
- **(a) Live-out / escaping aggregate OSR — ALREADY COVERED (correctness + OSR)
137+
via native heap writes; only a perf refinement remains.** A loop-carried struct
138+
read after the loop or returned already OSRs through the transactional heap-write
139+
path (`native_osr_loop_carried_struct_live_after_loop_uses_heap_writes`,
140+
`..._escaping_uses_heap_writes` — both green). The scalar loop-carried-struct SR
141+
pass declines (`passes.rs:7430`) but OSR proceeds with the un-dissolved body
142+
(host-helper `SetFieldSlot` writes, journaled). So this is **not a capability
143+
gap** — the only refinement is scalar-replacing such live-out structs for fewer
144+
host calls (record a recipe `(orig_reg, layout, [leaf_reg])`, rebuild at OSR-exit);
145+
pure perf, low priority.
146+
- **(b) Live-after HEAP-payload variant/Result OSR — the one genuine remaining
147+
coverage gap (perf, not correctness).** A `Result`/variant with a heap-payload arm
148+
that is **live after the loop** does NOT OSR today (`native_osr_j3_escaping_result_does_not_osr`
149+
asserts `osr_entries == 0`); it is correct (runs on the interpreter), just not
150+
accelerated. Unlike structs (which OSR via heap writes), a dissolved variant's heap
151+
payload has no live heap object to write back. Blocker: a heap field in a native
152+
reg is an opaque handle and the interpreter frame no longer holds the dissolved
153+
value. Approach: extend the reconstruction recipe so a heap field references its
154+
**interpreter-visible SOURCE register** (the reg `MakeVariant`/`MakeStruct` read it
155+
from), provided that reg stays live + unclobbered to the reconstruction point
156+
(needs a liveness proof); reconstruction reads `frame.reg(source)`. Subtle
157+
(which arm, in-loop-built payloads have no live source) — a deliberate slice.
153158
- **(c) Inlined logical-frame-chain format.** A deopt inside a `native_inline_leaf_calls`
154159
region resumes at the caller's `CallKnown` and re-runs the (side-effect-free)
155160
callee — *correct today*. Full J0.1 reconstructs the logical callee frame in place

0 commit comments

Comments
 (0)