feat(adr7): static-PIC data/element-offset fold — inc 4 (#353) - #365
Conversation
…ry premise does not reproduce (inc 4 / #353) Grounding for ADR-7 path-H inc 4 (static PIC / shared-everything flattening). Built a real PIC shared-everything fixture (clang --target=wasm32 -fPIC + wasm-ld --experimental-pic -shared + wasm-tools component link; a dylib with `(data (global.get $__memory_base) …)`) and probed current meld. FINDING: current meld (post inc 1–3) already - models the instance-level memory sharing → the fused core has ONE memory, NOT the two the #353 spike observed, and - folds `global.get $__memory_base` → `i32.const <base>` in globals/data (the #338 extended-const machinery), producing a VALID single core module. So the spike's "mints 2 memories / needs new topology modeling" premise does not reproduce on this fixture. What is NOT yet asserted is end-to-end address *correctness* — the linked component lifts no exports, so there is nothing to execute (the exact gap the spike flagged as "the one remaining verification"). Closing it needs a WIT-lifted executable PIC fixture. - tests/pic-fixtures/shared_everything_linked.wasm: the real fixture. - shared_everything_topology.rs: baseline guard (fuse → 1 memory + base-folded data at 0x100000 + validates), catching any regression to 2 memories/invalid. Refs #353 (ADR-7 path-H inc 4), #338 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
LS-N verification gate✅ 59/59 approved LS entries verified
Approved Failed LS entries(none) Missing regression tests(none) Updated automatically by |
… oracle The 'build wit' half of inc 4 found the real gap: a hand-written PIC-pattern component (base-relative (data (global.get $__memory_base) …) + a lifted read, no toolchain) fuses 'successfully' but the output FAILS wasmtime instantiation — 'constant expression required: global.get of locally defined global'. meld emits the fused data-segment offset as global.get of the (constant-valued) merged __memory_base global verbatim, instead of folding it to i32.const. wasm-tools validates it (lenient); wasmtime rejects it (strict) → silent invalid output. Root cause: segments.rs keeps global.get-first data offsets verbatim as 'runtime-dependent' (the #338 note), but a CONSTANT global must be folded in a data const-expr. Committed as an #[ignore]d reproducing oracle (CI-green, un-ignore on fix). This is the concrete inc-4 correctness gap — the spike's 'fold, not redefine' constraint, now reproduced minimally. Refs #353 (ADR-7 path-H inc 4), #338 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…atic PIC, #353) Implements the inc-4 fix for the bug reproduced in this branch's oracle. A data/element segment offset const-expr may `global.get` only an IMPORTED global; after fusion a `__memory_base`-style base (imported by a PIC dylib, defined by a `$main` module) becomes DEFINED, so meld emitted `(data (global.get $base) …)` verbatim — valid under wasm-tools but REJECTED by wasmtime ("constant expression required: global.get of locally defined global"). Silent invalid output from valid input. Fix: fold a `global.get` of a DEFINED constant-i32 global to `i32.const <value>` in offset emission. Imported globals stay verbatim, preserving #338. - segments.rs: `const_i32_init_value` extracts a global init's constant i32 (bare or extended-const, no embedded global.get); `ParsedConstExpr::reindex` folds a `GlobalGet` of a defined-const global to `I32Const` (covers BOTH data and element offsets, which both go through `reindex`). - merger.rs: `MergedModule.defined_global_i32_const` records defined constant-i32 globals at global-merge; copied into `IndexMaps` for the offset reindex. - rewriter.rs: `IndexMaps.defined_global_i32_consts` (empty default → no fold, so every other caller is unaffected). Verified: `shared_everything_topology::pic_base_relative_data_reads_correctly_ after_fold` — a hand-written PIC-pattern component (base-relative data + a lifted `read`) now fuses, VALIDATES, and executes on wasmtime with the data read back correctly (0xddccbbaa) at the folded base. The #338 imported-base oracle (`const_expr_globalget`, 4 tests) still passes (imported globals verbatim). Full meld-core suite green (0 failures); fmt + clippy clean. Tier-5 (merger/segments/adapter) → Mythos delta-pass to follow. Refs #353 (ADR-7 path-H inc 4), #338 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Mythos delta-pass requiredThis PR modifies one or more Tier-5 source files (per Before merge, run the Mythos discover protocol on the
Why this gate exists: LS-A-10 The gate check on this PR will pass once the label is |
Mythos delta-pass (auto)✅ NO FINDINGS across 4 Tier-5 file(s)
Auto-run via |
) Mythos self-review hardening of the static-PIC offset fold: restrict the defined-const global fold to IMMUTABLE globals. A `__memory_base` base is immutable, and folding a global's init value into a segment offset is unambiguously the segment-init-time value only for a non-mutable constant. (Active segments initialise before any start function, so even a mutable const-init would read its init value — but immutable removes all doubt and matches the PIC base shape.) Fold oracle + #338 imported-case + full suite green; fmt + clippy clean. Refs #353
Mythos discover pass (static-PIC offset fold) — NO FINDINGSA fresh-agent discover run hit the Anthropic session limit (infra, no result), so this is a self-conducted adversarial review — backed by the execution oracle Hypotheses examined against the diff (
Empty default ( |
…st bare global.get (#368) Completes the inc-4 static-PIC offset fold (#365). That fold handled the BARE `(data (global.get $base) …)` shape but left the extended-const `(data (i32.add (global.get $base) (i32.const N)) …)` shape as a verbatim `global.get`. But `wasm-tools component link` emits the extended-const form for EVERY N > 0 data segment (only N == 0 is bare) — so the common PIC case was still emitted as `global.get <defined base>; i32.const N; i32.add`, which wasm-tools accepts (lenient) but wasmtime REJECTS ("constant expression required: global.get of locally defined global"). Silent invalid output. Found by the inc-4 Mythos discover agent (which then died on a session-limit) and left the reproducing oracle behind. Fix: `ParsedConstExpr::reindex`'s `ExtendedGlobalGet` arm now folds the whole `base ± N` expression to a single `i32.const` when the leading global is a DEFINED constant-i32 (the `defined_global_i32_consts` map from #365), via a small stack evaluator `eval_ext_const_i32_with_base`. It declines (leaves verbatim) when the base is imported (#338), when a non-leading `global.get` appears, on any i64 op, or on an unbalanced sequence. - segments.rs: `eval_ext_const_i32_with_base` + the ExtendedGlobalGet fold; unit test covering base±N/*N, bare, and all three decline cases. - pic_extended_const_353.rs: execution oracle — a PIC-pattern component with an extended-const `base + N` data offset fuses, VALIDATES for wasmtime, and reads the data back correctly (was FAILING on main before this fix). Full meld-core suite green (0 failures); fmt + clippy clean. Refs #353 (ADR-7 path-H inc 4), #365, #338. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…s + static-PIC + same-memory transcoding (#369) Ships the full ADR-7 path-H arc (address-strategy seam #359, call-lowering seam #360, multiply-instantiated modules #362/#363, static-PIC fold #365, ADR record #354) plus the extended-const fold completion (#368), the #364 safety fix (#366), and same-memory string transcoding (#367). New capabilities: multiply-instantiated module support (RFC-46 Q1, MultiMemory, SR-55), static-PIC data/element offset folding (#353), same-memory string transcoding (#361). Safety: multiply-instantiated gated to the execution- verified MultiMemory case (#364); the sync same-memory cross-encoding miscompile closed (#360/#361). Falsification statements in CHANGELOG. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Implements ADR-7 path-H, increment 4 — static-PIC data/element-offset folding
(#353) — reproduced and fixed in one branch.
The bug (reproduced)
A data/element segment offset const-expr may
global.getonly an importedglobal. In a PIC dylib,
(data (global.get $__memory_base) …)is valid because__memory_baseis imported. But when meld fuses a shared-everything graph, a$mainmodule provides__memory_base, so after merge it becomes a definedglobal — and meld emitted
(data (global.get $base) …)verbatim. wasm-toolsvalidates it (lenient); wasmtime rejects it at instantiation ("constant
expression required: global.get of locally defined global") → silent invalid
output from valid input.
(The spike's original "2 memories / new topology modeling" premise did not
reproduce on current meld — see the earlier #353 comments; the real residual was
this offset fold.)
The fix
Fold a
global.getof a defined constant-i32 global toi32.const <value>in offset emission. Imported globals stay a verbatim
global.get, preserving#338.
segments.rs—const_i32_init_valueextracts a global init's constanti32;
ParsedConstExpr::reindexfoldsGlobalGet(defined-const)→I32Const.This sits in
reindex, so both data and element offsets are covered.merger.rs—MergedModule.defined_global_i32_constrecords definedconstant-i32 globals at global-merge; copied into
IndexMapsfor the reindex.rewriter.rs—IndexMaps.defined_global_i32_consts(empty default → nofold, so every other caller is unaffected).
Verification
pic_base_relative_data_reads_correctly_after_fold— ahand-written PIC-pattern component (base-relative data + a lifted
read) nowfuses, validates, and executes on wasmtime with the data read back
correctly (
0xddccbbaa) at the folded base. A wrong fold (value/index/address)fails this.
const_expr_globalget(4 tests, imported-base) stillgreen: imported globals stay verbatim.
shared_everything_fuses_to_valid_single_memory_core)against a real
wasm-tools component linkfixture still green.meld-coresuite green (0 failures); fmt + clippy clean.Tier-5 (merger/segments/adapter) → Mythos delta-pass below.
Refs #353 (ADR-7 path-H inc 4), #338