feat(adr7): static-PIC data/element-offset fold — inc 4 (#353)#365
feat(adr7): static-PIC data/element-offset fold — inc 4 (#353)#365avrabe wants to merge 3 commits into
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 |
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