perf: nested writes through a boxed container lowered as List.update #207

Closed
opened 2026-10-08 14:25:25 +00:00 by orion · 6 comments
Collaborator

Goal

self.tables[module].types.set(at, id) through a trait-typed list is a round trip (Index.at, the change, MutableIndex.set) with the element owned twice, so the change copies it. Answer it with List.update(index, change): ArrayList answers it natively (unique storage, run the change through the element's address as PathStep.Element does), the VM gets the same member, and the lowering writes a nested write through a still-boxed container as a call of update whose closure is the rest of the path.

Design record

PERFORMANCE.md 9.6 ("A write through a trait-typed list"), BACKEND 2.3 (evaluation order: keys, then value, then access). Part of #144.

Acceptance criteria

  • Evaluation order is as before: the closure evaluates nothing the assignment has not evaluated before the access; a key out of range panics at the site of at.
  • Native ArrayList.update and the VM member, with tests for order, out-of-range key and uniqueness (no copy of the element).
  • No removeAt/insert take-out and put-back.
  • sh tools/gates.sh a and b green in forge CI; before/after numbers in PERFORMANCE.md 9.7.

Measurement

Measured in CI, no local bootstrap: the forge CI job for the PR runs sh tools/gates.sh a; the before/after processor times come from torb check tests/conformance/adts.trb, torb build --emit-c tests/conformance/adts.trb and torb build --emit-c ./compiler run with the main binary and the PR binary alternating (3 runs, mean, as in PERFORMANCE.md 9.5), printed in the CI log and copied into PERFORMANCE.md 9.7. CI machines are noisy, so the ratio of alternating runs counts, not absolute seconds.

Seed impact

Yes: a new native and a name the lowering looks up. Lands in two commits per CLAUDE.md "Seed and breaking changes" (teach both forms, refresh the seed, then migrate). Seed refresh is Torben's; this issue is blocked on the owner decision on #144 and is not ready. Likely two PRs rather than one.

## Goal `self.tables[module].types.set(at, id)` through a trait-typed list is a round trip (`Index.at`, the change, `MutableIndex.set`) with the element owned twice, so the change copies it. Answer it with `List.update(index, change)`: `ArrayList` answers it natively (unique storage, run the change through the element's address as `PathStep.Element` does), the VM gets the same member, and the lowering writes a nested write through a still-boxed container as a call of `update` whose closure is the rest of the path. ## Design record [PERFORMANCE.md 9.6](https://git.torb.dev/torbscript/language/src/branch/main/docs/PERFORMANCE.md) ("A write through a trait-typed list"), BACKEND 2.3 (evaluation order: keys, then value, then access). Part of #144. ## Acceptance criteria - [ ] Evaluation order is as before: the closure evaluates nothing the assignment has not evaluated before the access; a key out of range panics at the site of `at`. - [ ] Native `ArrayList.update` and the VM member, with tests for order, out-of-range key and uniqueness (no copy of the element). - [ ] No `removeAt`/`insert` take-out and put-back. - [ ] `sh tools/gates.sh a` and `b` green in forge CI; before/after numbers in PERFORMANCE.md 9.7. ## Measurement Measured in CI, no local bootstrap: the forge CI job for the PR runs `sh tools/gates.sh a`; the before/after processor times come from `torb check tests/conformance/adts.trb`, `torb build --emit-c tests/conformance/adts.trb` and `torb build --emit-c ./compiler` run with the `main` binary and the PR binary alternating (3 runs, mean, as in PERFORMANCE.md 9.5), printed in the CI log and copied into PERFORMANCE.md 9.7. CI machines are noisy, so the ratio of alternating runs counts, not absolute seconds. ## Seed impact **Yes**: a new native and a name the lowering looks up. Lands in two commits per `CLAUDE.md` "Seed and breaking changes" (teach both forms, refresh the seed, then migrate). Seed refresh is Torben's; this issue is blocked on the owner decision on #144 and is not `ready`. Likely two PRs rather than one.
Author
Collaborator

[loop:torbscript] owner decision recorded (torben via WhatsApp, 2026-10-08 16:35 Europe/Berlin): go for this round (see #144). Two-commit seed rule applies. Labelled ready.

[loop:torbscript] owner decision recorded (torben via WhatsApp, 2026-10-08 16:35 Europe/Berlin): go for this round (see #144). Two-commit seed rule applies. Labelled `ready`.
Author
Collaborator

[loop:torbscript] claim implement by session:loop-torbscript-20261008 until 2026-10-08T23:09Z

[loop:torbscript] claim implement by session:loop-torbscript-20261008 until 2026-10-08T23:09Z
Author
Collaborator

PR #215 merged by argus (fb36c465): ArrayList.update/TrieList.update as plain TorbScript members, no native, no seed refresh needed. No post-merge step. Remaining for this issue: the IR pass after devirtualization that lowers a nested write through a still-boxed container as update; stays open. Open PR #217 is the throwaway count probe (WIP, to be closed).

PR #215 merged by argus (fb36c465): `ArrayList.update`/`TrieList.update` as plain TorbScript members, no native, no seed refresh needed. No post-merge step. Remaining for this issue: the IR pass after devirtualization that lowers a nested write through a still-boxed container as `update`; stays open. Open PR #217 is the throwaway count probe (WIP, to be closed).
Author
Collaborator

[loop:torbscript] release implement: worker session ended after PR #215 merged; the remaining IR pass is not started. The throwaway probe PR #217 is closed. next: implement (ready)

[loop:torbscript] release implement: worker session ended after PR #215 merged; the remaining IR pass is not started. The throwaway probe PR #217 is closed. next: implement (ready)
Author
Collaborator

[loop:torbscript] claim implement by session:loop-torbscript-20261009 until 2026-10-09T05:04Z

[loop:torbscript] claim implement by session:loop-torbscript-20261009 until 2026-10-09T05:04Z
Author
Collaborator

[loop:torbscript] implement: PR #238, CI success (20872b48), next: review (waiting on the merge gate argus)

The IR pass ir/updates.trb lowers a nested write through a list that stayed boxed as one update(key, closure). It keeps the order of BACKEND 2.3, panics at the site with the message of at when the key is out of range, and does no take-out and put-back. New conformance programs list-update-nested and list-update-bounds give the same output as main, and compiler/tests/boxed-updates.test.trb snapshots the lowered function and its closure. The measurement is in PERFORMANCE 9.11 (forge CI, 3 alternating runs): neutral within the noise for adts check/emit-c and the compiler emit-c. No new native and no std/ change, so no seed refresh. This releases the implement claim.

Token usage: about 0.6M.

[loop:torbscript] implement: PR https://git.torb.dev/torbscript/language/pulls/238, CI success (20872b48), next: review (waiting on the merge gate argus) The IR pass `ir/updates.trb` lowers a nested write through a list that stayed boxed as one `update(key, closure)`. It keeps the order of BACKEND 2.3, panics at the site with the message of `at` when the key is out of range, and does no take-out and put-back. New conformance programs `list-update-nested` and `list-update-bounds` give the same output as `main`, and `compiler/tests/boxed-updates.test.trb` snapshots the lowered function and its closure. The measurement is in PERFORMANCE 9.11 (forge CI, 3 alternating runs): neutral within the noise for adts check/emit-c and the compiler emit-c. No new native and no `std/` change, so no seed refresh. This releases the implement claim. Token usage: about 0.6M.
argus closed this issue 2026-10-09 01:48:44 +00:00
Sign in to join this conversation.
No labels
loop
ready
No milestone
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#207
No description provided.