From 655fe6fcd788fa7afed1dddd181f67a45f923faa Mon Sep 17 00:00:00 2001 From: "g. nicholas d'andrea" Date: Thu, 2 Jul 2026 20:56:33 -0400 Subject: [PATCH 1/2] format: define context `name` as a referenceable identifier MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reframe the `name` context from a "disambiguation label" to its intended purpose: a machine-generated identifier for a context that other contexts reference by name, unique within a program. State the per-program uniqueness requirement. Apply it to activation reconstruction: an `invoke` context declares an activation's name; the matching `return` and the body's member instructions reference it. This pairs a call with its return order-independently — resolving the two cases push/pop + the inline marker alone cannot: adjacent same-function activations and reordered/interleaved bodies. When present, names are authoritative for activation structure; push/pop + marker-count are the name-less fallback. - name.schema.yaml: rewrite description (purpose + uniqueness); examples. - name.mdx: frame `name` as the referenceable-context-name primitive, then pick-selection and invoke/return correlation as applications; note gather carries distinct co-located names (tailcall). - invoke.mdx: add "Correlating with `name`" to Reconstructing activations (Layer 2 authoritative when present). No schema structure change. --- .../spec/program/context/function/invoke.mdx | 35 ++++++++++++ packages/web/spec/program/context/name.mdx | 55 +++++++++++++++++-- schemas/program/context/name.schema.yaml | 37 +++++++++---- 3 files changed, 113 insertions(+), 14 deletions(-) diff --git a/packages/web/spec/program/context/function/invoke.mdx b/packages/web/spec/program/context/function/invoke.mdx index 7a6b71701..c1e5fa247 100644 --- a/packages/web/spec/program/context/function/invoke.mdx +++ b/packages/web/spec/program/context/function/invoke.mdx @@ -188,6 +188,41 @@ non-member instruction (no `inline` marker for that depth) is attributed to the enclosing activation, not the inlined one, even while the virtual activation remains on the stack. +### Correlating with `name` + +The push/pop and membership rules above reconstruct activations +without any correlation identifier: they rely on `invoke`/`return` +appearing in a well-nested order and on the `inline` marker to +attribute instructions. That is sufficient for typical compiler +output. It has two blind spots, both from the marker alone being +unable to tell one activation from another of the same function: + +- **Adjacent activations of the same function.** Two inlined + copies of the same callee placed back-to-back, with no + intervening caller instruction, read as one activation under a + marker-run rule. +- **Reordered or interleaved bodies.** An optimizer that moves a + `return` marker ahead of its `invoke`, or interleaves two + activations non-nested, defeats strict push/pop pairing. + +A [`name`](/spec/program/context/name) closes both. When an +`invoke` context carries a `name`, it **declares** that activation; +the matching `return`, and the body instructions that belong to it, +carry the same `name` to **reference** it. Because names are unique +within the program, the pairing is explicit and order-independent: +adjacent same-function activations have distinct names, and a +reference resolves to its declaration regardless of trace order. + +When names are present they are **authoritative** for activation +structure — which `invoke` pairs with which `return`, and which +instructions belong to which activation. Push/pop, the `inline` +marker, and the marker-count depth remain the fallback a name-less +debugger uses; in well-nested output the two agree. Where they +cannot — the two blind spots above — the names are correct. A +compiler that emits names should therefore keep them consistent +with the push/pop structure wherever both are determinate, so the +two views never silently disagree. + ### Identity and values Every function-identity field (`identifier`, `declaration`, diff --git a/packages/web/spec/program/context/name.mdx b/packages/web/spec/program/context/name.mdx index 31fd7fb17..8d6a618f9 100644 --- a/packages/web/spec/program/context/name.mdx +++ b/packages/web/spec/program/context/name.mdx @@ -6,9 +6,56 @@ import SchemaViewer from "@site/src/components/SchemaViewer"; # Named contexts -Contexts may include a `name` property for distinguishing them from -other contexts. This is particularly useful inside `pick` alternatives, -where several possible contexts may apply at a given point in execution -and runtime information is needed to select which one is active. +A context may carry a `name`: a machine-generated identifier that gives +the context a stable identity other contexts can reference. A name is +what makes a **cross-context reference** possible — one context declares +a name, and another points back to it by the same name. + +Names are opaque strings; the format imposes no structure on their +contents. Within a single program — one +[`instructions`](/spec/program) sequence — a `name` **must** be unique, +so that a reference resolves to exactly one declaring context. Compilers +**should** also choose names that are meaningful to debugger users. + +## Uses + +### Selecting `pick` alternatives + +Inside a [`pick`](/spec/program/context/pick), several contexts may apply +at a given point in execution and runtime information is needed to select +which one is active. A `name` on each alternative gives the selection +something stable to identify the chosen alternative by. + +### Correlating an invocation with its return + +A `name` lets a function invocation and its return be paired directly. +An [`invoke`](/spec/program/context/function/invoke) context **declares** +an activation's name; the matching +[`return`](/spec/program/context/function/return) context — and the +instructions belonging to that activation's body — **reference** it by +the same name. + +This declaration/reference split follows the format's general +reference-by-name idiom (as a +[pointer template](/spec/pointer/collection/templates) is declared +once and referenced elsewhere). It pairs a call with its return +without relying on the trace +being strictly nested: even when optimization reorders or interleaves +code so that a naive "innermost open activation" rule would mispair +them, the shared name resolves the pairing unambiguously. When two +inlined copies of the same function appear back-to-back, their distinct +names keep them distinct activations. + +Because a single context object can hold at most one `name`, two +activation facts that must carry **different** names at the same +instruction — for example a tail call, where one instruction both +returns from the current activation and invokes the next — are expressed +with a [`gather`](/spec/program/context/gather) whose members each carry +their own name. The naming granularity therefore tracks the structure of +the contexts themselves. + +See the invoke context's +[Reconstructing activations](/spec/program/context/function/invoke#reconstructing-activations) +for how a debugger uses these names to rebuild the call stack. diff --git a/schemas/program/context/name.schema.yaml b/schemas/program/context/name.schema.yaml index 759161059..1a58bdf74 100644 --- a/schemas/program/context/name.schema.yaml +++ b/schemas/program/context/name.schema.yaml @@ -3,15 +3,29 @@ $id: "schema:ethdebug/format/program/context/name" title: ethdebug/format/program/context/name description: | - A label for distinguishing this context from other contexts. - This is particularly useful inside `pick` alternatives, - where several possible contexts may apply at a given point in - execution and runtime information is needed to select which one - is active. + A machine-generated identifier for this context that other + contexts may reference by name. - Context names are opaque strings with no format-imposed semantics. - Compilers **should** choose names that are meaningful to debugger - users. + A `name` gives a context a stable identity that the rest of a + program's debug information can point back to. This is what makes + cross-context references possible. Uses include: + + - **Selecting `pick` alternatives.** Several contexts may apply + at a point in execution; a `name` identifies which alternative + is active, so runtime information can select it. + - **Correlating an invocation with its return.** An `invoke` + context *declares* an activation's name; the matching `return` + context — and the instructions belonging to that activation — + *reference* it by the same name. This pairs a call with its + return directly, without relying on the trace being strictly + nested (see the invoke context's activation-reconstruction + guidance). + + Names are opaque strings; the format imposes no structure on + their contents. Within a single program — one **instructions** + sequence — a `name` **must** be unique, so that a reference + resolves to exactly one declaring context. Compilers **should** + also choose names that are meaningful to debugger users. type: object properties: @@ -21,7 +35,10 @@ required: - name examples: - # example: naming an inlined call site - - name: "inlined-call" + # example: declaring an inlined activation, referenced by its + # matching return and by the instructions of the inlined body + - name: "inline-0" # example: naming a generic instantiation - name: "Array" + # example: distinguishing a `pick` alternative + - name: "storage-layout-v2" From 36ca50371db3473209e98dc56c2149db03c151eb Mon Sep 17 00:00:00 2001 From: "g. nicholas d'andrea" Date: Thu, 2 Jul 2026 21:10:02 -0400 Subject: [PATCH 2/2] format: sharpen name uniqueness wording (declared once, referenced freely) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Per writer review of #236: 'a name must be unique' misread as 'appears once', but a name deliberately recurs — the invoke declares it, the return and every body instruction reference it. State the requirement on the declaration: each name is declared by exactly one context; other contexts reference it freely. Mirror the wording across name.schema.yaml, name.mdx, and invoke.mdx. Plus prose polish (marker-run phrasing, pick handle). --- .../spec/program/context/function/invoke.mdx | 18 ++++++++++-------- packages/web/spec/program/context/name.mdx | 12 +++++++----- schemas/program/context/name.schema.yaml | 10 ++++++---- 3 files changed, 23 insertions(+), 17 deletions(-) diff --git a/packages/web/spec/program/context/function/invoke.mdx b/packages/web/spec/program/context/function/invoke.mdx index c1e5fa247..76da58aff 100644 --- a/packages/web/spec/program/context/function/invoke.mdx +++ b/packages/web/spec/program/context/function/invoke.mdx @@ -194,13 +194,14 @@ The push/pop and membership rules above reconstruct activations without any correlation identifier: they rely on `invoke`/`return` appearing in a well-nested order and on the `inline` marker to attribute instructions. That is sufficient for typical compiler -output. It has two blind spots, both from the marker alone being -unable to tell one activation from another of the same function: +output. It has two blind spots, both arising because the marker +alone can't tell one activation from another of the same function: - **Adjacent activations of the same function.** Two inlined copies of the same callee placed back-to-back, with no - intervening caller instruction, read as one activation under a - marker-run rule. + intervening caller instruction, read as one activation to a + debugger that groups a consecutive run of `inline`-marked + instructions. - **Reordered or interleaved bodies.** An optimizer that moves a `return` marker ahead of its `invoke`, or interleaves two activations non-nested, defeats strict push/pop pairing. @@ -208,10 +209,11 @@ unable to tell one activation from another of the same function: A [`name`](/spec/program/context/name) closes both. When an `invoke` context carries a `name`, it **declares** that activation; the matching `return`, and the body instructions that belong to it, -carry the same `name` to **reference** it. Because names are unique -within the program, the pairing is explicit and order-independent: -adjacent same-function activations have distinct names, and a -reference resolves to its declaration regardless of trace order. +carry the same `name` to **reference** it. Because each name is +declared by exactly one `invoke`, the pairing is explicit and +order-independent: adjacent same-function activations have distinct +names, and a reference resolves to its declaration regardless of +trace order. When names are present they are **authoritative** for activation structure — which `invoke` pairs with which `return`, and which diff --git a/packages/web/spec/program/context/name.mdx b/packages/web/spec/program/context/name.mdx index 8d6a618f9..7a247d5d6 100644 --- a/packages/web/spec/program/context/name.mdx +++ b/packages/web/spec/program/context/name.mdx @@ -11,10 +11,12 @@ the context a stable identity other contexts can reference. A name is what makes a **cross-context reference** possible — one context declares a name, and another points back to it by the same name. -Names are opaque strings; the format imposes no structure on their -contents. Within a single program — one -[`instructions`](/spec/program) sequence — a `name` **must** be unique, -so that a reference resolves to exactly one declaring context. Compilers +Names are opaque strings; the format imposes no structure on them. +Within a single program — one [`instructions`](/spec/program) +sequence — each name **must** be declared by exactly one context; no +two contexts may declare the same name. Other contexts may reference +that name freely — that repetition is how they point back — and every +reference resolves to the single declaring context. Compilers **should** also choose names that are meaningful to debugger users. @@ -26,7 +28,7 @@ so that a reference resolves to exactly one declaring context. Compilers Inside a [`pick`](/spec/program/context/pick), several contexts may apply at a given point in execution and runtime information is needed to select which one is active. A `name` on each alternative gives the selection -something stable to identify the chosen alternative by. +a stable handle for the chosen alternative. ### Correlating an invocation with its return diff --git a/schemas/program/context/name.schema.yaml b/schemas/program/context/name.schema.yaml index 1a58bdf74..c9830fc1f 100644 --- a/schemas/program/context/name.schema.yaml +++ b/schemas/program/context/name.schema.yaml @@ -22,10 +22,12 @@ description: | guidance). Names are opaque strings; the format imposes no structure on - their contents. Within a single program — one **instructions** - sequence — a `name` **must** be unique, so that a reference - resolves to exactly one declaring context. Compilers **should** - also choose names that are meaningful to debugger users. + them. Within a single program — one **instructions** sequence — + each name **must** be declared by exactly one context; no two + contexts may declare the same name. Other contexts may reference + that name freely, and every reference resolves to the single + declaring context. Compilers **should** also choose names that + are meaningful to debugger users. type: object properties: