docs/test(wasm): E4-E7 store-bug isolation; deterministic byte+32 repro

This commit is contained in:
2026-07-22 06:53:41 -04:00
parent e3296dc533
commit cc6e6b0d88
3 changed files with 42 additions and 1 deletions
+39
View File
@@ -149,6 +149,45 @@ race** in the compiled restartable-block store path, not a codegen typo — and
is exactly why upstream forces every store-TB to TCI. Fixing it is architectural
(rewind/instance-safe compiled stores), not a one-op correction.
### E4-E7 — deterministic minimal repro, and what the bug is NOT
With a per-op gate in `tcg_out_qemu_st` (compile only store-TBs matching a
criterion, TCI the rest) plus targeted instrumentation, each run rebuilt +
browser-tested against the exact 1.4.1 firmware:
| experiment | change | result |
|-----------|--------|--------|
| E4 lifecycle | never `removeFunction` retired TB instances (pin all) | **crash** |
| E5 helper-only | force every store through the softmmu helper (no direct store codegen) | **crash** |
| E6 width: byte only | compile TBs whose store is 8-bit | **pass** |
| E6 width: 16 only | 16-bit | **pass** |
| E6 width: 32 only | 32-bit | **pass** |
| E6 width: byte+16 | | **pass** |
| E6 width: 16+32 | | **pass** |
| E6 width: **byte+32** | | **crash** |
| E7 bytewise-32 | emit 32-bit store as four 8-bit stores, compile all | **crash** |
| precheck | skip store helper on rewind when DONE_FLAG already set | **crash** |
| nochain | `-d nochain` (disable TB chaining), compile all stores | **crash** |
| determinism | rerun the crashing all-compiled build 3x | **crash x3, same gen 16, same MEPC** |
**Established:** the crash is *deterministic* (same point every run) but depends
on the exact compiled-TB set. The minimal reproducer is a byte-store TB **and**
a 32-bit-store TB compiled together; it is *counter-monotonic* — additionally
compiling 16-bit-store TBs hides it.
**Ruled out:** single miscompiled TB (E1-E3), a specific memory region
(inflate/ROM/IRAM/flash halves), TB chaining (nochain), instance/function
lifecycle & `removeFunction` reuse (E4 pin), the store *data* codegen itself
(E5 helper-only and E7 bytewise both crash), and store double-execution on
rewind (precheck to skip the replayed helper still crashes).
**Localized to:** the restartable-block rewind/register bookkeeping that wraps a
store op (shared in structure with loads, which survive because re-running a
load is harmless). The counter-monotonic width behavior points at an
interaction whose trigger shifts with which TBs are promoted, not at any single
store's emitted bytes. Next concrete step: dump the generated wasm for a
crashing store-TB and `wasm2wat` it to read the BLOCK_PTR/guard sequence
directly against a passing one.
### Next options
1. **Ship E1 as a guarded workaround** — reader works now; measure real
navigation/page-turn perf before judging it unacceptable.
+2
View File
@@ -37,6 +37,7 @@ def page_state():
generation: Number(document.querySelector('#frame-generation')?.value || -1),
runtimeErrors: window.__xteinkRuntimeErrors || [],
wasmHeap: window.__xteinkModule?.HEAPU8?.byteLength || 0,
instantiatedTbs: window.__xteinkModule?._wasm_instantiated_tb_count?.() || 0,
};
''')
except WebDriverException as error:
@@ -46,6 +47,7 @@ def page_state():
'generation': -1,
'runtimeErrors': [str(error)],
'wasmHeap': 0,
'instantiatedTbs': 0,
}