Skip to content

perf(vm): remove the runLoop hop; make leaveFrame parameter-free - #730

Open
mparrett wants to merge 2 commits into
mainfrom
perf/vm-dispatch-followups
Open

perf(vm): remove the runLoop hop; make leaveFrame parameter-free#730
mparrett wants to merge 2 commits into
mainfrom
perf/vm-dispatch-followups

Conversation

@mparrett

@mparrett mparrett commented Aug 12, 2026

Copy link
Copy Markdown
Collaborator

Draft until the stack ahead of it settles; I'll add perf-repeat for an EPYC adjudication once the queue is quiet.

Carries the three low-severity notes from #719's review as a stacked PR, so #719 merges as reviewed and its perf-repeat baseline stays put.

  • Fold the attribution gate into runChain. runLoop was a dispatcher too big to inline (cost 144 exceeds budget 80), so the entry path paid Run → runChain → runLoop → runLoopInner — one non-inlined call more than needed on every host→VM entry and every error-resume iteration. The gate is now hoisted out of runChain's loop and calls runLoopAttr/runLoopInner directly; runLoop is gone.
  • Drop leaveFrame's parameter. It took a *Frame it never read, and in OP_RETURN there is a window after ReleaseFrame(child) where state.current still points at the pooled frame — the first real use of the parameter would have been a use-after-release. With no parameter the invariant is structural, and runLoopAttr's defer sheds its closure.
  • Pin the default-config panic path. With LG_ALLOC_ATTR unset, Run is deliberately defer-free and a Go panic leaks the chain's pooled frames to GC (pre-vm: make direct bytecode calls non-recursive with an explicit frame chain #645 parity) — previously documented but untested. The new test panics a raw (unwrapped) callable inside a descended frame and asserts the panic value survives and the pool sees the intended behavior in both configurations: leak-to-GC with attribution off, exactly-once release via runChainProtected with it on.

Measured (interleaved go-bench medians, N=6, vs #719's head): FrameDispatch 0.94×, FuncInvoke/Closure 0.97×, Direct 1.00× — flat to slightly better, matching the review's own bench of the fold.

Verified: pkg/vm, pkg/rt, pkg/genmanifest, test/ suites; go test -race ./pkg/vm; both suites again with LG_ALLOC_ATTR=1; the new test passes in both configurations; linux, plan9, js/wasm builds.

mparrett and others added 2 commits August 12, 2026 12:50
…-free

Two structural notes from #719's review, together because they meet at
runLoopAttr:

runLoop was a dispatcher too big to inline (cost 144 vs budget 80), so
the entry path paid Run -> runChain -> runLoop -> runLoopInner — one
real call more than needed on every host->VM entry and error-resume
iteration. Hoist the allocAttrEnabled gate into runChain's loop and
call runLoopAttr/runLoopInner directly; runLoop goes away.

leaveFrame took a *Frame it never read, and the doc comment leaned on
that: in OP_RETURN there is a window after ReleaseFrame(child) where
state.current still points at the pooled frame, so the first real use
of the parameter would be a use-after-release. Drop the parameter —
the invariant is now structural, and runLoopAttr's defer no longer
needs a closure.

Interleaved go-bench medians (N=6, vs #719 head): FrameDispatch 0.94x,
FuncInvoke/Closure 0.97x, Direct 1.00x — flat to slightly better.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The default configuration's panic path had no test: with LG_ALLOC_ATTR
unset Run is deliberately defer-free and a Go panic leaks the chain's
pooled frames to GC (pre-#645 parity), but nothing pinned that intent —
a change reintroducing a must-release-on-panic invariant would pass the
suite silently. Panic a raw (unwrapped) callable inside a descended
frame and assert the panic value survives and the pool sees the
intended behavior: leak-to-GC with attribution off, exactly-once
release via runChainProtected with it on.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@mparrett
mparrett force-pushed the perf/vm-dispatch-followups branch from 37afd8f to b680b49 Compare August 12, 2026 19:50
@mparrett mparrett added the review-priority/low Minimal review effort left / already approved label Aug 14, 2026
@mparrett
mparrett marked this pull request as ready for review August 14, 2026 23:09
@mparrett mparrett added the perf-repeat Run the repeat A/B (variance-reduced) perf check label Aug 14, 2026
@mparrett
mparrett requested a review from nnunley August 16, 2026 02:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

perf-repeat Run the repeat A/B (variance-reduced) perf check review-priority/low Minimal review effort left / already approved

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant