Skip to content

format: fix the program example's pre-execution stack pointers#278

Open
gnidan wants to merge 1 commit into
mainfrom
architect-program-stack-example
Open

format: fix the program example's pre-execution stack pointers#278
gnidan wants to merge 1 commit into
mainfrom
architect-program-stack-example

Conversation

@gnidan

@gnidan gnidan commented Jul 24, 2026

Copy link
Copy Markdown
Member

The Incrementer example in program.schema.yaml sizes its stack-resident local against post-execution machine state, contradicting the pointer convention the instruction schema declares.

Convention (program/instruction.schema.yaml, and the invoke schema's InternalCall note): a context's pointers describe the machine state a debugger observes when it is stopped at the instruction — that is, before the instruction executes. Stack slot counts from the top of that pre-execution stack.

Applying that convention to let localValue = storedValue; storedValue += 1; (call bytecode), the pre-execution stack at each instruction is:

offset op pre-exec stack (top → bottom) localValue
0 PUSH0 (empty)
1 SLOAD [0x00] — (SLOAD produces it)
2 PUSH1 0x01 [localValue] slot 0
4 ADD [localValue, 0x01] slot 1 (ADD consumes it)
5 PUSH0 [storedValue+1] out of scope
6 SSTORE [storedValue+1, 0x00] out of scope

So localValue is observable only at offsets 2 and 4. It first appears at offset 2 — one step after the SLOAD that computes it, because its value is not on the stack at the SLOAD trace step itself — and is gone once ADD consumes it. The previous example placed it at slot 0 as early as offset 1 and kept it live through offset 5, which would make a debugger display it off by one. storedValue stays at storage slot 0 throughout.

Per-offset stack notes are inlined so the slot math is checkable against the ops, and a stale value = tmp; line (a leftover from an earlier naming of the pseudo-code) is removed.

Schema example and validity tests pass.

The Incrementer example annotated its stack-resident local against
post-execution machine state, contradicting the pointer convention the
instruction schema declares: a context's pointers describe the state a
debugger observes when stopped at the instruction, before it executes.

Reworked the example to that convention. localValue (produced by the
SLOAD at offset 1) is first observable at offset 2, where the
pre-execution stack holds it at the top (slot 0); at offset 4 it sits
one below the PUSH1 result (slot 1) and is then consumed by ADD, so it
is no longer in scope at offsets 5-6. Previously it was shown live on
the stack after ADD, which would have made a debugger display it off by
one. Also drops a stale 'value = tmp;' line left over from an earlier
naming of the pseudo-code.
@github-actions

Copy link
Copy Markdown
Contributor
PR Preview Action v1.8.1

QR code for preview link

🚀 View preview at
https://ethdebug.github.io/format/pr-preview/pr-278/

Built to branch gh-pages at 2026-07-24 02:16 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant