From 9e9184949d44669a52307e28641c8a6af3c7cbe5 Mon Sep 17 00:00:00 2001 From: Evan Reichard Date: Wed, 22 Jul 2026 21:43:06 -0400 Subject: [PATCH] tcg/wasm32: add opt-in ?yieldtrace store-yield counter Counts compiled-TB DONE_FLAG redispatch/resume re-entries. Three crashing nostoretci runs showed zero such re-entries, ruling out the store block-replay-via-redispatch path as the corruption trigger and pointing at a guest-RAM data race with concurrent device/timer callbacks. --- tcg/wasm32.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tcg/wasm32.c b/tcg/wasm32.c index 559dc8c2e6..20737312c6 100644 --- a/tcg/wasm32.c +++ b/tcg/wasm32.c @@ -1318,6 +1318,13 @@ int wasm_store_tci_disabled; int wasm_store_tci_hash; int wasm_store_bisect_on; int wasm_store_bisect_width; +int wasm_yield_trace; +uint32_t wasm_yield_reentries; + +EMSCRIPTEN_KEEPALIVE void wasm_enable_yield_trace(void) +{ + wasm_yield_trace = 1; +} uint32_t wasm_store_bisect_mask; uint32_t wasm_store_bisect_val; @@ -1704,12 +1711,15 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, while (true) { int tb_entry_ptr = (uint32_t)ctx.tb_ptr + export_vec_off; uint32_t res; + uint32_t prev_tb = (uint32_t)ctx.tb_ptr; + bool was_compiled = false; bool diff_store_tci = wasm_diff_mode == 1 && wasm_diff_lookup_store_tb(ctx.tb_ptr, NULL); if (diff_store_tci) { res = tcg_qemu_tb_exec_tci(env); } else if (*(int32_t*)tb_entry_ptr > 0) { res = ((wasm_func_ptr)(*(uint32_t*)tb_entry_ptr))(&ctx); + was_compiled = true; } else if (*(int32_t *)tb_entry_ptr == WASM_TCI_ONLY_ENTRY) { res = tcg_qemu_tb_exec_tci(env); } else if (*(int32_t*)tb_entry_ptr > (-1 * INSTANTIATE_NUM)) { @@ -1719,6 +1729,18 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, instantiate_wasm(); qatomic_inc(&instantiated_wasm_count); res = ((wasm_func_ptr)(*(uint32_t*)tb_entry_ptr))(&ctx); + was_compiled = true; + } + /* E17: a compiled TB that returns non-zero with the same tb_ptr and + * do_init still clear is a mid-TB yield/resume (rewind path), not a + * chain (chains set do_init=1) and not completion (tb_ptr==0). */ + if (wasm_yield_trace && was_compiled && (uint32_t)ctx.tb_ptr == prev_tb && + (uint32_t)ctx.tb_ptr != 0 && ctx.do_init == 0) { + wasm_yield_reentries++; + if (wasm_yield_reentries <= 20 || (wasm_yield_reentries % 5000) == 0) { + printf("YIELD reentry #%u tb=0x%x\n", wasm_yield_reentries, prev_tb); + fflush(stdout); + } } if ((uint32_t)ctx.tb_ptr == 0) { return res;