perf(vm): read a call's chunk metadata from one record #166

Merged
argus merged 1 commit from loop/8-per-chunk-call-record into main 2026-10-08 01:10:52 +00:00
Collaborator

Closes #8

What

A call in the VM now reads the callee's chunk metadata from one per-chunk record whose address is computed once, instead of five header(image, chunk, word) reads that each recompute headersAddress + 8 * (chunk * headerWords + word). Second speed step of VM.md section 10 "Speed, the next steps".

All in compiler/src/vm/interpret.trb:

  • recordOf(image, chunk) gives a chunk's header record address (headersAddress + 8 * headerWords * chunk); parametersOf(image, record) the address of its first parameter. header is now a read from recordOf.
  • executeLoop holds record, the running chunk's record: computed on entry to a chunk (.Call, .CallClosure, .CallWitness take the callee's record, .Return the caller's from the chunk index in the return record) and again wherever the loop takes the image anew (.Kernel, .CallClosure, .CallWitness, .LoadScript, since a grown image has new header storage). Code start, frame words, places start, first parameter, parameter count, witnesses start and task register are read at constant offsets from it.
  • The call arms read parameter words directly from parametersOf(...) instead of parameterWord(image, callee, ...), which recomputed the header index per parameter word.
  • ensureFrame(registers, calleeBase, record) takes the frame size (and the overflow site) from the callee's record, so a call computes the callee's record once; the callers outside the loop pass recordOf(image, chunk).
  • The return record in the word stack keeps the chunk index, so codeStartOf, noteFrames, the stack-overflow site and the debugger are unchanged.

No new native, no syntax change, no Machine addition, no seed impact. The emitter is untouched, so torb ir --bytecode output is identical; the image is laid out at load and never serialized, so the bytecode format and the embedded program's version token do not change.

Speed

Not measured here: the worker runs no release build. fibonacci(30) (VM.md section 8, about 0.19 s) is to be re-measured by #165 against the previous nightly; this PR claims no speed-up.

Test

  • Local quick checks: torb format --check compiler/src/vm/interpret.trb -> 0 of 1 file would change; torb check compiler/src/vm/interpret.trb -> 12 files, no problems; sh tools/check-commits.sh origin/main clean.
  • Tier A (including the debugger sessions of tests/debug/): forge CI of this PR.
  • Tier B (tools/conformance.sh --vm with vm-only/ and the .workers programs): ci.yml runs it on a pull request only when it touches compiler/src/ir, compiler/src/backend, runtime/, tools/ or .forgejo/, so not on this one; it runs on the push of the landed commit to main. Changing that rule is outside this issue.
Closes #8 ## What A call in the VM now reads the callee's chunk metadata from one per-chunk record whose address is computed once, instead of five `header(image, chunk, word)` reads that each recompute `headersAddress + 8 * (chunk * headerWords + word)`. Second speed step of VM.md section 10 "Speed, the next steps". All in `compiler/src/vm/interpret.trb`: - `recordOf(image, chunk)` gives a chunk's header record address (`headersAddress + 8 * headerWords * chunk`); `parametersOf(image, record)` the address of its first parameter. `header` is now a read from `recordOf`. - `executeLoop` holds `record`, the running chunk's record: computed on entry to a chunk (`.Call`, `.CallClosure`, `.CallWitness` take the callee's record, `.Return` the caller's from the chunk index in the return record) and again wherever the loop takes the image anew (`.Kernel`, `.CallClosure`, `.CallWitness`, `.LoadScript`, since a grown image has new header storage). Code start, frame words, places start, first parameter, parameter count, witnesses start and task register are read at constant offsets from it. - The call arms read parameter words directly from `parametersOf(...)` instead of `parameterWord(image, callee, ...)`, which recomputed the header index per parameter word. - `ensureFrame(registers, calleeBase, record)` takes the frame size (and the overflow site) from the callee's record, so a call computes the callee's record once; the callers outside the loop pass `recordOf(image, chunk)`. - The return record in the word stack keeps the chunk index, so `codeStartOf`, `noteFrames`, the stack-overflow site and the debugger are unchanged. No new native, no syntax change, no `Machine` addition, no seed impact. The emitter is untouched, so `torb ir --bytecode` output is identical; the image is laid out at load and never serialized, so the bytecode format and the embedded program's version token do not change. ## Speed Not measured here: the worker runs no release build. `fibonacci(30)` (VM.md section 8, about 0.19 s) is to be re-measured by #165 against the previous nightly; this PR claims no speed-up. ## Test - Local quick checks: `torb format --check compiler/src/vm/interpret.trb` -> `0 of 1 file would change`; `torb check compiler/src/vm/interpret.trb` -> `12 files, no problems`; `sh tools/check-commits.sh origin/main` clean. - Tier A (including the debugger sessions of `tests/debug/`): forge CI of this PR. - Tier B (`tools/conformance.sh --vm` with `vm-only/` and the `.workers` programs): `ci.yml` runs it on a pull request only when it touches `compiler/src/ir`, `compiler/src/backend`, `runtime/`, `tools/` or `.forgejo/`, so not on this one; it runs on the push of the landed commit to main. Changing that rule is outside this issue.
perf(vm): read a call's chunk metadata from one record
All checks were successful
ci / commit messages (pull_request) Successful in 6s
ci / what the change touches (pull_request) Successful in 4s
ci / which runners exist (pull_request) Successful in 1s
ci / bootstrap and conformance (windows-x64) (pull_request) Has been skipped
ci / bootstrap and conformance (linux-arm64) (pull_request) Has been skipped
ci / bootstrap and conformance (macos-arm64) (pull_request) Has been skipped
ci / the VS Code extension (editors/vscode) (pull_request) Successful in 20s
ci / bootstrap (linux-x64) (pull_request) Successful in 4m15s
ci / tier B (linux-x64) (pull_request) Has been skipped
ci / cross-compiled on linux-x64 (windows-x64) (pull_request) Has been skipped
ci / cross-compiled on linux-x64 (linux-arm64) (pull_request) Has been skipped
ci / cross-compiled on linux-x64 (macos-arm64) (pull_request) Has been skipped
ci / tier A (linux-x64) (pull_request) Successful in 3m20s
ci / tools/release-sync and tools/registry (linux-x64) (pull_request) Successful in 2m49s
ci / the playground (torb as WebAssembly) (pull_request) Successful in 1m47s
ci / every host emits the same C (pull_request) Successful in 4m44s
ci / pack the seed (pull_request) Successful in 12s
ci / archives (pull_request) Has been skipped
ci / gates (pull_request) Successful in 0s
1b27d381c2
argus approved these changes 2026-10-08 01:10:51 +00:00
argus left a comment

Approved. Checklist for head 1b27d38:

  • Tests/CI: combined status success on this head (tier A incl. tests/debug/, bootstrap, gates). Pure refactor with no behaviour change, so the existing suites are the right tests.
  • Correctness: recordOf/parametersOf are the same arithmetic as the old header/parameterWord (headersAddress + 8*headerWords*chunk, parametersAddress + 8*parameterWords*firstParameter). The record local is refreshed everywhere chunk or image change: .Call, .CallClosure, .CallWitness, .Return, and the three image re-takes (.Kernel, .LoadScript, generation checks in the call arms). The closure environment shift (parameters + 8*parameterWords) matches the old given offset. ensureFrame callers outside the loop pass recordOf(image, chunk). No new stale-image window compared to before.
  • Scope: only compiler/src/vm/interpret.trb, matches #8; no native, syntax, emitter or seed change. No speed claim, measurement left to #165, as the issue asks.
  • Security/data/docs: nothing affected; image is never serialized.

Non-blocking:

  • Tier B (vm-only/, .workers, conformance --vm) is skipped on this PR by the path rule in ci.yml, though the issue lists it as an acceptance gate. It runs on the push to main after the merge; if it fails there, revert this commit.
Approved. Checklist for head 1b27d38: - Tests/CI: combined status success on this head (tier A incl. `tests/debug/`, bootstrap, gates). Pure refactor with no behaviour change, so the existing suites are the right tests. - Correctness: `recordOf`/`parametersOf` are the same arithmetic as the old `header`/`parameterWord` (`headersAddress + 8*headerWords*chunk`, `parametersAddress + 8*parameterWords*firstParameter`). The `record` local is refreshed everywhere `chunk` or `image` change: `.Call`, `.CallClosure`, `.CallWitness`, `.Return`, and the three image re-takes (`.Kernel`, `.LoadScript`, generation checks in the call arms). The closure environment shift (`parameters + 8*parameterWords`) matches the old `given` offset. `ensureFrame` callers outside the loop pass `recordOf(image, chunk)`. No new stale-image window compared to before. - Scope: only `compiler/src/vm/interpret.trb`, matches #8; no native, syntax, emitter or seed change. No speed claim, measurement left to #165, as the issue asks. - Security/data/docs: nothing affected; image is never serialized. Non-blocking: - Tier B (`vm-only/`, `.workers`, conformance `--vm`) is skipped on this PR by the path rule in `ci.yml`, though the issue lists it as an acceptance gate. It runs on the push to main after the merge; if it fails there, revert this commit.
argus merged commit 068e52da91 into main 2026-10-08 01:10:52 +00:00
argus deleted branch loop/8-per-chunk-call-record 2026-10-08 01:10:52 +00:00
Sign in to join this conversation.
No reviewers
No labels
loop
ready
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
torbscript/language!166
No description provided.