format, pointers: define segment offset carry semantics and resolve multi-slot regions - #284
Open
gnidan wants to merge 6 commits into
Open
format, pointers: define segment offset carry semantics and resolve multi-slot regions#284gnidan wants to merge 6 commits into
gnidan wants to merge 6 commits into
Conversation
…erence Two pointer-side fixes from the design rulings. Segment offset (ruling 5): the offset field prose required a value n with 0 <= n < $wordsize, contradicting the schema's own multi-slot note and the packed-struct pointer example, both of which use offsets at or beyond a word boundary. The offset is now defined as an unbounded non-negative value with full carry: for slot p and offset n, the segment begins at byte (n mod $wordsize) of slot (p + floor(n / $wordsize)). The multi-slot note and the example are unchanged; only the erroneous bound is removed. Region self-reference (ruling 6): the packed-array example computed a region's own offset from '.length: "struct-pointer"' — a reference to the region being declared, which the name-resolution rules (previously-declared names only) cannot satisfy on the first iteration. It now uses the built-in '.length: $this'. A guard is added to the $this reference: a property lookup via $this must not be circular.
Contributor
|
Adds a companion to the string-storage pointer example that expresses the long-string body as one region whose length runs across slots, instead of a per-slot list — the byte chaining the carry semantics enable. The existing per-slot list form is kept as the primary example: it stays resolvable by the reference implementation and yields a distinct region per slot, which a consumer may want. Also adds a minimal carry example to the segment scheme's own examples (offset at a word boundary addressing the next slot). Note: a single storage region spanning slots is not yet resolved by the pointers reference implementation (flagged to debugger as a tracked follow-up); the primary per-slot form remains the resolvable one.
The companion example shared the string example's 'string-storage-contract-variable-slot' identifier, which the pointers integration tests use with findExamplePointer (first substring match). First-match already selects the resolvable per-slot form, but renaming the companion's variable to 'string-storage-slot' removes the shared lookup substring so the companion can never be selected even if examples are reordered.
Segment regions (stack, storage, transient) now follow the addressing scheme's carry semantics: an offset at or beyond $wordsize addresses a later slot, a length may run across slots (concatenating sequentially addressed slots), and an omitted length ends at the end of the slot in which the segment begins. The Machine.State interface is unchanged; read() assembles the bytes from per-slot reads. Also: - express the segment `length` default with $remainder so that it is consistent with offset carry (it previously clamped to 0 for offsets at or beyond $wordsize) - add an integration test selecting the single-region `string storage` companion example against the same StringStorage contract - treat storage slots absent from ganache struct logs as zero (they previously decoded as garbage); this corrects the struct storage test's expected initial `salt` to 0x00000000 Claude-Session: https://claude.ai/code/session_01RJFyifZxcSXZchLFNTNPuT
…guide The slot-based locations paragraph in the pointers regions guide still described offset/length as sub-slot positioning only. Restate it against the segment scheme's semantics: offsets carry past $wordsize into later slots, lengths may span consecutive slots, and an omitted length ends at the end of the starting slot. Points at the multi-slot string storage example as the canonical use. Claude-Session: https://claude.ai/code/session_014otYPQPP9pvQabmY58Fyom
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two pointer-side fixes from the design rulings, with the reference implementation brought along so the schema does not outrun it.
Segment offset carry. The
offsetfield inpointer/scheme/segmentrequired its value n to satisfy0 ≤ n < $wordsize("must begin inside the slot"). That contradicts the schema's own multi-slot note — which already says byte{ "offset": "$wordsize" }of a slot is byte0of the next — and the flagship packed-struct pointer example, which places a sentinel region atoffset: $wordsize. The bound was the bug.offsetis now an unbounded non-negative value with full carry: for aslotvaluepand anoffsetvaluen, the segment begins at byten mod $wordsizeof slotp + floor(n / $wordsize). Emitters may chain byte sums across slot boundaries; resolvers recover slot and byte by division and remainder against$wordsize. The multi-slot note and the packed-struct example are unchanged.Length default under carry. The old default
$wordsize − .offsetclamps to zero onceoffsetcarries. The default is now$wordsize − (.offset mod $wordsize): the segment ends at the end of the slot in which it begins.Region self-reference. The packed-array example computed a region's own offset from
.length: "struct-pointer"— a reference to the very region being declared. The reference-resolution rules only resolve previously-declared names, so on the first list iteration there is no earlierstruct-pointerto resolve to. It now uses the built-in self-reference.length: $this, and the$thisreference gains a guard: a property lookup via$thismust not be circular. The pointers implementation already detects this and throws rather than looping; a test now pins that.Byte-chaining example. A companion to the
string storageexample expresses the long-string body as a single region whoselengthruns across slots —{ name: "string", slot: "start-slot", offset: 0, length: "string-length" }— instead of the per-slotlist+ last-slot-trim machinery. A minimal carry example is also added to the segment scheme's own examples. The per-slot list form stays primary: it exerciseslist/ conditional /defineand yields a distinct region per slot, which a consumer may want for display. The companion models only solc's long form.Reference implementation.
@ethdebug/pointersnow resolves all of the above. Reads against word-addressed locations (stack, storage, transient) go through a sharedreadSegmentthat applies the carry, reads as many consecutive words aslengthspans, and concatenates them. TheMachine.State.Wordsinterface is unchanged, so@ethdebug/evmneeds no changes. Unit tests cover carry at and past the word boundary, spans across two and three slots, the default length under a carried offset, and stack/transient carry. A new integration case observes the companion example against the sameStringStoragecontract as the existing test and decodes the multi-slot string end to end. Along the way the ganache test adapter now reads slots absent from the struct log as zero instead of garbage; that corrects the struct-storage case's initialsaltexpectation from0xto0x00000000.