Skip to content

bugc: define repeated pointer shapes once as templates - #399

Merged
gnidan merged 3 commits into
mainfrom
bugc-pointer-templates
Oct 16, 2026
Merged

gnidan merged 3 commits into
mainfrom
bugc-pointer-templates

Conversation

@gnidan

@gnidan gnidan commented Oct 15, 2026 •

Copy link
Copy Markdown
Member

Every instruction lists every variable in scope with its full pointer, so bugc's debug output repeats the same pointer shapes thousands of times. This defines each repeated shape once, as a pointer template in the compilation's info resources (resources.pointers), and makes each variable's pointer a reference to it: { "define": { ... }, "in": { "template": ..., "yields": { ... } } }. define binds what the template expects; yields keeps the region names users see today (name-offset, player-score, value-name-data, ...).

The bytecode output gets a new resources field, an ethdebug/format/info/resources object. A debugger dereferences a pointer with its templates: dereference(pointer, { state, templates: resources.pointers }). The conformance adapter and the docs' trace drawer now do this.

Templates:

  • frame-local: a local in the call frame (-frame plus the local's bytes at frame + offset).
  • frame-calldata-local, memory-calldata-local, stack-calldata-local: bytes or a string in calldata (the x-offset / x-length halves of the word, and x-data read from them), by where the local's word is.
  • memory-bytes, memory-<type>: the data a string, bytes, dynamic array or struct in memory refers to.
  • storage-bytes: a string or bytes in storage (length flag, then the data in the slot or from keccak256(slot)).
  • storage-<type>: an array, struct or mapping in storage. A type's name keeps its words in order without brackets (array<array<uint256>, 3> is array-3-array-uint256), so each type has its own template; defining one name for two types is an error. A mapping's template holds its entry templates, as the pointer held them before, so a debugger finds entry as before once it follows the reference.

What stays inline: a value-type storage variable (a packed field is one region, and a reference to it would be larger than the region), and a local in a stack slot or at a static memory offset (one region each).

Effect on the arcade example (the blog's arcade.bug), programs as JSON: 13,042,075 → 6,292,742 bytes at O0 and 10,629,058 → 5,206,449 at O2, plus 3.9 KB of resources.

Debug info only: the bytecode of every example and of arcade, at every level, is byte-for-byte the same as before (the activation-pairing snapshot only gains the new example, with the digests main gives it).

Tests: templates.test.ts reads each listed pointer at every step of runs of the examples, two ways:

  • every example, every level: through the templates, and with each reference written out in place; same regions and bytes required, and not all reads may fail.
  • some examples at O0 and O2: a digest of every read must match templates.golden.json, written by bugc from before this change (9c8d7cc; main at bb2d677 reads the same).

The new example intermediate/pointer-shapes.bug covers a dynamic storage array of structs, a mapping in a struct, struct fields named length and data next to string and bytes data, and string and bytes calldata locals in a function's frame. The existing pointer tests (locals soundness, storage strings and mappings, array layout, example annotations) now dereference with the resources' templates, and the examples test validates resources against the schema. A test with array<array<uint256>, 3> and array<array<uint256, 3>> checks each reads by its own template.

The docs' TraceViewer takes the templates too, and the trace viewer guide passes them to dereference.

@gnidan
gnidan force-pushed the bugc-pointer-templates branch from 34ad162 to 09b921d Compare October 15, 2026 23:39
@github-actions

github-actions Bot commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor
PR Preview Action v1.8.1
Preview removed because the pull request was closed.
2026-10-16 00:57 UTC

Every instruction lists every variable in scope with its full pointer,
so the same pointer shapes repeat thousands of times: a storage
string's length-flag group, a mapping's entry template, a struct in
memory, a local's frame-pointer group. Define each shape once as a
pointer template in the compilation's info resources, and make each
variable's pointer a reference to it, with `define` binding the
template's variables and `yields` keeping today's region names.

The bytecode output has a new `resources` field (an
ethdebug/format/info/resources object); its `pointers` hold the
templates. The conformance adapter and the docs' trace drawer pass
them to dereference.
Name a type's template by its words in order (`array-3-array-uint256`
for `array<array<uint256>, 3>`, `array-array-3-uint256` for
`array<array<uint256, 3>>`), so no two types share a name, and make
defining a name for a second type an error.

Check that pointers read what they read before templates: a digest of
every read, at every step, for some examples at O0 and O2, written by
bugc from before this change. Add an example with a dynamic storage
array of structs, a mapping in a struct, struct fields named `length`
and `data`, and string and bytes locals in a function's frame.

Let the docs' TraceViewer take the templates, and pass them in the
trace viewer guide's dereference example.
A long run of reads never turned the event loop, and vitest failed the run with 'Timeout calling "onTaskUpdate"'.
@gnidan
gnidan force-pushed the bugc-pointer-templates branch from 2c7c0b1 to 79e3ef5 Compare October 16, 2026 00:35
@gnidan
gnidan merged commit 16246cd into main Oct 16, 2026
9 checks passed
@gnidan
gnidan deleted the bugc-pointer-templates branch October 16, 2026 00:53
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