vm: read a call's chunk metadata from one per-chunk record (fibonacci(30)) #8

Closed
opened 2026-10-05 21:07:09 +00:00 by orion · 6 comments
Collaborator

Goal

A call in the VM reads the callee's chunk metadata from one per-chunk record whose address is computed once per call, instead of five separate header(image, chunk, word) reads that each recompute headersAddress + 8 * (chunk * headerWords + word). This is the second of the four speed steps of VM.md "Speed, the next steps"; the issue is narrowed to it (see "Scope after refinement").

Source

  • VM.md section 10, "Speed, the next steps": "a call reads five header words where a per-chunk record in the image could be one".
  • VM.md section 4: the image, the header of nine words per chunk (ten in the code: headerWords), the return record of four words below a frame.
  • VM.md section 8: fibonacci(30) about 0.19 s, the number to beat; the method is there.
  • No entry of CONCEPT "Open Questions" is involved.

Scope after refinement

  • Step 4 (Place steps as words of the image) is already built: appendPlace, placeAt and resolvePlace of compiler/src/vm/interpret.trb read a place's steps as words by address, since the VM runs on every worker of the pool (commit 94c4a99e). VM.md section 10 is stale there; the correction is part of #165.
  • Step 1 (checked address arithmetic) is #163 and step 3 (retain/release as an instruction) is #164; both wait on an owner decision (mechanism, new natives, seed refresh). fibonacci(30) retains nothing, so #164 cannot be measured on it.
  • The measured numbers are #165: the loop's workers never run a bootstrap or release build in their own exec, so the numbers come from published nightly toolchains afterwards.
  • This issue is only the per-chunk call record.

What to change

All in compiler/src/vm/interpret.trb (headerWords, imageOf, header, the .Call, .CallClosure, .CallWitness, .Return arms of executeLoop, ensureFrame). The image is laid out in memory at load by imageOf; it is not serialized (vm/embed.trb writes chunks, not the image), so the bytecode format and the embedded program's version token do not change.

Acceptance criteria

  • The loop holds the running chunk's record address (headersAddress + 8 * headerWords * chunk, computed once on entry to a chunk) and reads the fields a call and a return need (code start, frame words, places start, first parameter, parameter count) at constant offsets from it; .Call, .CallClosure, .CallWitness and .Return no longer call header(...) with a chunk index for them. The return record in the word stack may keep the chunk index (the debugger, the stack-overflow site and noteFrames use it) or hold the record address, whichever keeps codeStartOf and the debugger unchanged.
  • ensureFrame takes the frame size from the same record (no second index computation for the same callee).
  • Behaviour is unchanged: torb ir --bytecode output (snapshots in compiler/tests/bytecode.test.trb) is identical, because the emitter is untouched; tools/conformance.sh --vm and the .workers programs, the debugger sessions (tests/debug/) and the sandbox programs (vm-only/) are green in tier A and tier B of the forge CI.
  • No new native, no syntax change, no Machine addition: only interpret.trb and, for the stale paragraph, nothing else (the VM.md text is #165).
  • The PR description states the intent for the number: fibonacci(30) is to be re-measured by #165 against the previous nightly; the worker does not claim a speed-up it did not measure.

Seed impact

None. No syntax change, no new native, no driver flag, no std name looked up by string. If the work turns out to need one, stop and file an owner decision instead of refreshing a seed.

Size and commits

One PR, one Conventional Commit: perf(vm): read a call's chunk metadata from one record. Touches compiler/src/vm/interpret.trb only.

Implementer

opus/high (compiler/src/vm, the interpreter hot path). CI only for the gates (tier A and tier B, because the interpreter runs the whole conformance suite); locally a torb format --check of the file and one quick test.

Collisions

  • #7 (sandbox network grant, VM tasks) touches runtime/sandbox.c, runtime/io.c, std/sandbox, conformance programs and docs - no shared file. If its tests expose an interpreter defect in the sandbox/budget code of interpret.trb, a trivial rebase is the worst case.
  • #5 (IO gates: runtime/stream.c, runtime/tests/, conformance programs) and #6 (pool benchmark: runtime/task.c, benchmarks/, CONCURRENCY.md) share no file with this issue.
  • #163 edits the same executeLoop arms later: land this first, #163 rebases on it.

Dependencies

None open for this step. Follow-ups: #163, #164 (owner decisions), #165 (measurement).

## Goal A call in the VM reads the callee's chunk metadata from one per-chunk record whose address is computed once per call, instead of five separate `header(image, chunk, word)` reads that each recompute `headersAddress + 8 * (chunk * headerWords + word)`. This is the second of the four speed steps of VM.md "Speed, the next steps"; the issue is narrowed to it (see "Scope after refinement"). ## Source - [VM.md section 10, "Speed, the next steps"](https://git.torb.dev/torbscript/language/src/commit/d55c8d9c10edbaf9f48665bd782480736efbea03/docs/design/VM.md#L469): "a call reads five header words where a per-chunk record in the image could be one". - [VM.md section 4](https://git.torb.dev/torbscript/language/src/commit/d55c8d9c10edbaf9f48665bd782480736efbea03/docs/design/VM.md#L169): the image, the header of nine words per chunk (ten in the code: `headerWords`), the return record of four words below a frame. - [VM.md section 8](https://git.torb.dev/torbscript/language/src/commit/d55c8d9c10edbaf9f48665bd782480736efbea03/docs/design/VM.md#L349): `fibonacci(30)` about 0.19 s, the number to beat; the method is there. - No entry of CONCEPT "Open Questions" is involved. ## Scope after refinement - **Step 4 (`Place` steps as words of the image) is already built**: `appendPlace`, `placeAt` and `resolvePlace` of `compiler/src/vm/interpret.trb` read a place's steps as words by address, since the VM runs on every worker of the pool (commit 94c4a99e). VM.md section 10 is stale there; the correction is part of #165. - **Step 1 (checked address arithmetic) is #163** and **step 3 (retain/release as an instruction) is #164**; both wait on an owner decision (mechanism, new natives, seed refresh). `fibonacci(30)` retains nothing, so #164 cannot be measured on it. - **The measured numbers are #165**: the loop's workers never run a bootstrap or release build in their own exec, so the numbers come from published nightly toolchains afterwards. - This issue is only the per-chunk call record. ## What to change All in `compiler/src/vm/interpret.trb` (`headerWords`, `imageOf`, `header`, the `.Call`, `.CallClosure`, `.CallWitness`, `.Return` arms of `executeLoop`, `ensureFrame`). The image is laid out in memory at load by `imageOf`; it is not serialized (`vm/embed.trb` writes chunks, not the image), so the bytecode format and the embedded program's version token do not change. ## Acceptance criteria - [ ] The loop holds the running chunk's record address (`headersAddress + 8 * headerWords * chunk`, computed once on entry to a chunk) and reads the fields a call and a return need (code start, frame words, places start, first parameter, parameter count) at constant offsets from it; `.Call`, `.CallClosure`, `.CallWitness` and `.Return` no longer call `header(...)` with a chunk index for them. The return record in the word stack may keep the chunk index (the debugger, the stack-overflow site and `noteFrames` use it) or hold the record address, whichever keeps `codeStartOf` and the debugger unchanged. - [ ] `ensureFrame` takes the frame size from the same record (no second index computation for the same callee). - [ ] Behaviour is unchanged: `torb ir --bytecode` output (snapshots in `compiler/tests/bytecode.test.trb`) is identical, because the emitter is untouched; `tools/conformance.sh --vm` and the `.workers` programs, the debugger sessions (`tests/debug/`) and the sandbox programs (`vm-only/`) are green in tier A and tier B of the forge CI. - [ ] No new native, no syntax change, no `Machine` addition: only `interpret.trb` and, for the stale paragraph, nothing else (the VM.md text is #165). - [ ] The PR description states the intent for the number: `fibonacci(30)` is to be re-measured by #165 against the previous nightly; the worker does not claim a speed-up it did not measure. ## Seed impact None. No syntax change, no new native, no driver flag, no std name looked up by string. If the work turns out to need one, stop and file an owner decision instead of refreshing a seed. ## Size and commits One PR, one Conventional Commit: `perf(vm): read a call's chunk metadata from one record`. Touches `compiler/src/vm/interpret.trb` only. ## Implementer opus/high (`compiler/src/vm`, the interpreter hot path). CI only for the gates (tier A and tier B, because the interpreter runs the whole conformance suite); locally a `torb format --check` of the file and one quick test. ## Collisions - #7 (sandbox network grant, VM tasks) touches `runtime/sandbox.c`, `runtime/io.c`, `std/sandbox`, conformance programs and docs - no shared file. If its tests expose an interpreter defect in the sandbox/budget code of `interpret.trb`, a trivial rebase is the worst case. - #5 (IO gates: `runtime/stream.c`, `runtime/tests/`, conformance programs) and #6 (pool benchmark: `runtime/task.c`, `benchmarks/`, `CONCURRENCY.md`) share no file with this issue. - #163 edits the same `executeLoop` arms later: land this first, #163 rebases on it. ## Dependencies None open for this step. Follow-ups: #163, #164 (owner decisions), #165 (measurement).
Author
Collaborator

[loop:torbscript] intake: in scope (author orion, label loop). Implements the four open speed steps of VM.md, each measured against fibonacci(30) (section 8); no collision with CONCEPT "Open Questions". Touches the VM and image format (opus/high worker); the image-format steps may touch the seed, to settle in refine. Likely to be split per step. Release freeze for 0.1.0 (2026-10-06) holds new PRs, next: refine (queued, buffer >= 2 ready)

[loop:torbscript] intake: in scope (author orion, label loop). Implements the four open speed steps of VM.md, each measured against fibonacci(30) (section 8); no collision with CONCEPT "Open Questions". Touches the VM and image format (opus/high worker); the image-format steps may touch the seed, to settle in refine. Likely to be split per step. Release freeze for 0.1.0 (2026-10-06) holds new PRs, next: refine (queued, buffer >= 2 ready)
Author
Collaborator

[loop:torbscript] claim refine by session:loop-torbscript-20261008 until 2026-10-08T00:30:21Z

[loop:torbscript] claim refine by session:loop-torbscript-20261008 until 2026-10-08T00:30:21Z
Author
Collaborator

[loop:torbscript] release refine: the earlier refine worker died with the gateway recreate (claim expired without a result). New claim follows.
[loop:torbscript] claim refine by session:loop-torbscript-20261008 until 2026-10-08T02:33:26Z

[loop:torbscript] release refine: the earlier refine worker died with the gateway recreate (claim expired without a result). New claim follows. [loop:torbscript] claim refine by session:loop-torbscript-20261008 until 2026-10-08T02:33:26Z
orion changed title from vm: the next speed steps measured against fibonacci(30) to vm: read a call's chunk metadata from one per-chunk record (fibonacci(30)) 2026-10-08 00:37:27 +00:00
Author
Collaborator

[loop:torbscript] refine: issue narrowed to the second speed step (one per-chunk record for a call) and set ready. Step 4 (place steps as image words) is already built, so only VM.md is stale; step 1 became #163 and step 3 #164, each with an owner decision comment (new Machine natives mean a seed refresh; fibonacci(30) cannot show step 3 at all); the measured numbers and the VM.md update became #165, because workers never run a release build. No seed impact, one commit perf(vm): ..., compiler/src/vm/interpret.trb only, no collision with #5, #6 or #7. Implementer: opus/high. The owner decisions are comments only; no question_ask tool was available to the refine worker, so the tick should file the blocks for #163 and #164. Worker usage ~120000 tokens, next: implement

[loop:torbscript] refine: issue narrowed to the second speed step (one per-chunk record for a call) and set `ready`. Step 4 (place steps as image words) is already built, so only VM.md is stale; step 1 became #163 and step 3 #164, each with an owner decision comment (new `Machine` natives mean a seed refresh; `fibonacci(30)` cannot show step 3 at all); the measured numbers and the VM.md update became #165, because workers never run a release build. No seed impact, one commit `perf(vm): ...`, `compiler/src/vm/interpret.trb` only, no collision with #5, #6 or #7. Implementer: opus/high. The owner decisions are comments only; no `question_ask` tool was available to the refine worker, so the tick should file the blocks for #163 and #164. Worker usage ~120000 tokens, next: implement
Author
Collaborator

[loop:torbscript] claim implement by session:loop-torbscript-20261008 until 2026-10-08T06:38:37Z

[loop:torbscript] claim implement by session:loop-torbscript-20261008 until 2026-10-08T06:38:37Z
argus closed this issue 2026-10-08 01:10:52 +00:00
Author
Collaborator

[loop:torbscript] implement: one commit perf(vm): read a call's chunk metadata from one record (only compiler/src/vm/interpret.trb): the loop holds the running chunk's header record address (recordOf), computed on entry to a chunk and wherever the image is taken anew; .Call, .CallClosure, .CallWitness and .Return read code start, frame words, places, first parameter and parameter count at constant offsets, the parameter words through one parametersOf address, and ensureFrame takes the callee's record. The return record keeps the chunk index, so codeStartOf, noteFrames and the debugger are unchanged. No seed impact, no new native. Forge CI of the PR green (bootstrap, tier A including the debugger sessions, playground, C agreement); tier B is skipped on pull requests that do not touch ir/, backend/, runtime/, tools/ or .forgejo/ (ci.yml rule), so conformance.sh --vm runs on the push of the landed commit to main. Speed not measured here, left to #165. PR #166, worker usage ~150000 tokens, next: review

[loop:torbscript] implement: one commit `perf(vm): read a call's chunk metadata from one record` (only `compiler/src/vm/interpret.trb`): the loop holds the running chunk's header record address (`recordOf`), computed on entry to a chunk and wherever the image is taken anew; `.Call`, `.CallClosure`, `.CallWitness` and `.Return` read code start, frame words, places, first parameter and parameter count at constant offsets, the parameter words through one `parametersOf` address, and `ensureFrame` takes the callee's record. The return record keeps the chunk index, so `codeStartOf`, `noteFrames` and the debugger are unchanged. No seed impact, no new native. Forge CI of the PR green (bootstrap, tier A including the debugger sessions, playground, C agreement); tier B is skipped on pull requests that do not touch `ir/`, `backend/`, `runtime/`, `tools/` or `.forgejo/` (ci.yml rule), so `conformance.sh --vm` runs on the push of the landed commit to main. Speed not measured here, left to #165. PR https://git.torb.dev/torbscript/language/pulls/166, worker usage ~150000 tokens, next: review
Sign in to join this conversation.
No labels
loop
ready
No project
No assignees
1 participant
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#8
No description provided.