tcg/wasm32: remove compiled-store investigation probes

This commit is contained in:
2026-07-24 10:37:12 -04:00
parent c1fc905cf2
commit 598b5e66fd
8 changed files with 1 additions and 945 deletions
-24
View File
@@ -41,9 +41,6 @@
#include "tb-context.h"
#include "internal-common.h"
#include "internal-target.h"
#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER)
#include "../../tcg/wasm32.h"
#endif
/* -icount align implementation. */
@@ -176,14 +173,6 @@ uint32_t curr_cflags(CPUState *cpu)
cflags |= CF_NO_GOTO_TB;
}
#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER)
/* E10 needs one TB per dispatch so wasm_cur_tb_pc stays exact; E11 keeps
* chaining live to avoid watchdog-only slowdowns before the armed window. */
if (wasm_diff_needs_nochain()) {
cflags |= CF_NO_GOTO_TB | CF_NO_GOTO_PTR;
}
#endif
return cflags;
}
@@ -428,11 +417,6 @@ const void *HELPER(lookup_tb_ptr)(CPUArchState *env)
cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags);
cflags = curr_cflags(cpu);
#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER)
if (wasm_diff_needs_nochain_at(pc)) {
cflags |= CF_NO_GOTO_TB | CF_NO_GOTO_PTR;
}
#endif
if (check_for_breakpoints(cpu, pc, &cflags)) {
cpu_loop_exit(cpu);
}
@@ -471,9 +455,6 @@ cpu_tb_exec(CPUState *cpu, TranslationBlock *itb, int *tb_exit)
}
qemu_thread_jit_execute();
#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER)
wasm_cur_tb_pc = itb->pc;
#endif
ret = tcg_qemu_tb_exec(cpu_env(cpu), tb_ptr);
cpu->neg.can_do_io = true;
qemu_plugin_disable_mem_helpers(cpu);
@@ -995,11 +976,6 @@ cpu_exec_loop(CPUState *cpu, SyncClocks *sc)
cflags = cpu->cflags_next_tb;
if (cflags == -1) {
cflags = curr_cflags(cpu);
#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER)
if (wasm_diff_needs_nochain_at(pc)) {
cflags |= CF_NO_GOTO_TB | CF_NO_GOTO_PTR;
}
#endif
} else {
cpu->cflags_next_tb = -1;
}
-94
View File
@@ -73,28 +73,6 @@
} \
} while (0)
#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER)
extern int wasm_ramrace_trace;
static uint32_t wasm_ramrace_tlb_logs;
static void wasm_ramrace_log_tlb(const char *kind, CPUState *cpu, vaddr addr)
{
if (!wasm_ramrace_trace || current_cpu) {
return;
}
wasm_ramrace_tlb_logs++;
if (wasm_ramrace_tlb_logs <= 200 || (wasm_ramrace_tlb_logs % 10000) == 0) {
printf("RAMRACE tlb-%s off-vcpu #%u tid=%lu cpu=%p addr=0x%llx\n",
kind, wasm_ramrace_tlb_logs, (unsigned long)pthread_self(),
cpu, (unsigned long long)addr);
fflush(stdout);
}
}
#else
#define wasm_ramrace_log_tlb(kind, cpu, addr) ((void)0)
#endif
#define assert_cpu_is_self(cpu) do { \
if (DEBUG_TLB_GATE) { \
g_assert(!(cpu)->created || qemu_cpu_is_self(cpu)); \
@@ -439,7 +417,6 @@ static void tlb_flush_by_mmuidx_async_work(CPUState *cpu, run_on_cpu_data data)
void tlb_flush_by_mmuidx(CPUState *cpu, uint16_t idxmap)
{
tlb_debug("mmu_idx: 0x%" PRIx16 "\n", idxmap);
wasm_ramrace_log_tlb("full", cpu, 0);
assert_cpu_is_self(cpu);
@@ -456,7 +433,6 @@ void tlb_flush_by_mmuidx_all_cpus_synced(CPUState *src_cpu, uint16_t idxmap)
const run_on_cpu_func fn = tlb_flush_by_mmuidx_async_work;
tlb_debug("mmu_idx: 0x%"PRIx16"\n", idxmap);
wasm_ramrace_log_tlb("full-all", src_cpu, 0);
flush_all_helper(src_cpu, fn, RUN_ON_CPU_HOST_INT(idxmap));
async_safe_run_on_cpu(src_cpu, fn, RUN_ON_CPU_HOST_INT(idxmap));
@@ -632,7 +608,6 @@ static void tlb_flush_page_by_mmuidx_async_2(CPUState *cpu,
void tlb_flush_page_by_mmuidx(CPUState *cpu, vaddr addr, uint16_t idxmap)
{
tlb_debug("addr: %016" VADDR_PRIx " mmu_idx:%" PRIx16 "\n", addr, idxmap);
wasm_ramrace_log_tlb("page", cpu, addr);
assert_cpu_is_self(cpu);
@@ -652,7 +627,6 @@ void tlb_flush_page_by_mmuidx_all_cpus_synced(CPUState *src_cpu,
uint16_t idxmap)
{
tlb_debug("addr: %016" VADDR_PRIx " mmu_idx:%"PRIx16"\n", addr, idxmap);
wasm_ramrace_log_tlb("page-all", src_cpu, addr);
/* This should already be page aligned */
addr &= TARGET_PAGE_MASK;
@@ -803,7 +777,6 @@ void tlb_flush_range_by_mmuidx(CPUState *cpu, vaddr addr,
{
TLBFlushRangeData d;
wasm_ramrace_log_tlb("range", cpu, addr);
assert_cpu_is_self(cpu);
/*
@@ -844,8 +817,6 @@ void tlb_flush_range_by_mmuidx_all_cpus_synced(CPUState *src_cpu,
TLBFlushRangeData d, *p;
CPUState *dst_cpu;
wasm_ramrace_log_tlb("range-all", src_cpu, addr);
/*
* If all bits are significant, and len is small,
* this devolves to tlb_flush_page.
@@ -986,27 +957,9 @@ void tlb_reset_dirty(CPUState *cpu, ram_addr_t start1, ram_addr_t length)
static inline void tlb_set_dirty1_locked(CPUTLBEntry *tlb_entry,
vaddr addr)
{
#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER)
if (wasm_ramrace_trace && (addr & TARGET_PAGE_MASK) == 0x3fcb8000u) {
printf("FAULTTRACE tlb_set_dirty1 entry=%p before_read=0x%llx before_write=0x%llx before_addend=0x%llx addr=0x%llx\n",
tlb_entry, (unsigned long long)tlb_entry->addr_read,
(unsigned long long)tlb_entry->addr_write,
(unsigned long long)tlb_entry->addend, (unsigned long long)addr);
fflush(stdout);
}
#endif
if (tlb_entry->addr_write == (addr | TLB_NOTDIRTY)) {
tlb_entry->addr_write = addr;
}
#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER)
if (wasm_ramrace_trace && (addr & TARGET_PAGE_MASK) == 0x3fcb8000u) {
printf("FAULTTRACE tlb_set_dirty1 after entry=%p read=0x%llx write=0x%llx addend=0x%llx\n",
tlb_entry, (unsigned long long)tlb_entry->addr_read,
(unsigned long long)tlb_entry->addr_write,
(unsigned long long)tlb_entry->addend);
fflush(stdout);
}
#endif
}
/* update the TLB corresponding to virtual page vaddr
@@ -1125,16 +1078,6 @@ void tlb_set_page_full(CPUState *cpu, int mmu_idx,
is_ram = memory_region_is_ram(section->mr);
is_romd = memory_region_is_romd(section->mr);
#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER)
if (wasm_ramrace_trace && paddr_page == 0x3fcb8000u) {
printf("FAULTTRACE tlb_fill vaddr=0x%llx paddr=0x%llx asidx=%d prot=0x%x mr=%p name=%s ram=%d romd=%d readonly=%d xlat=0x%llx sz=0x%llx\n",
(unsigned long long)addr_page, (unsigned long long)paddr_page,
asidx, prot, section->mr, memory_region_name(section->mr) ?: "(null)",
is_ram, is_romd, section->readonly,
(unsigned long long)xlat, (unsigned long long)sz);
fflush(stdout);
}
#endif
if (is_ram || is_romd) {
/* RAM and ROMD both have associated host memory. */
@@ -1227,15 +1170,6 @@ void tlb_set_page_full(CPUState *cpu, int mmu_idx,
full = &desc->fulltlb[index];
full->xlat_section = iotlb - addr_page;
full->phys_addr = paddr_page;
#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER)
if (wasm_ramrace_trace && paddr_page == 0x3fcb8000u) {
printf("FAULTTRACE tlb_store index=%u iotlb=0x%llx addr_page=0x%llx stored_xlat=0x%llx phys=0x%llx\n",
index, (unsigned long long)iotlb, (unsigned long long)addr_page,
(unsigned long long)full->xlat_section,
(unsigned long long)full->phys_addr);
fflush(stdout);
}
#endif
/* Now calculate the new entry */
tn.addend = addend - addr_page;
@@ -1455,15 +1389,6 @@ static int probe_access_internal(CPUState *cpu, vaddr addr,
*pfull = full = &cpu->neg.tlb.d[mmu_idx].fulltlb[index];
flags |= full->slow_flags[access_type];
#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER)
if (wasm_ramrace_trace && ((addr & TARGET_PAGE_MASK) == 0x3fcb8000u)) {
printf("FAULTTRACE probe addr=0x%llx index=%lu access=%d tlb_addr=0x%llx flags=0x%x slow=0x%x addend=0x%llx full_xlat=0x%llx\n",
(unsigned long long)addr, (unsigned long)index, access_type,
(unsigned long long)tlb_addr, flags, full->slow_flags[access_type],
(unsigned long long)entry->addend, (unsigned long long)full->xlat_section);
fflush(stdout);
}
#endif
/* Fold all "mmio-like" bits into TLB_MMIO. This is not RAM. */
if (unlikely(flags & ~(TLB_WATCHPOINT | TLB_NOTDIRTY | TLB_CHECK_ALIGNED))
@@ -1754,16 +1679,6 @@ static bool mmu_lookup1(CPUState *cpu, MMULookupPageData *data, MemOp memop,
data->full = full;
data->flags = flags;
#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER)
if (wasm_ramrace_trace && ((addr & TARGET_PAGE_MASK) == 0x3fcb8000u)) {
printf("FAULTTRACE mmu_lookup1 addr=0x%llx mmu=%d index=%lu maybe_resized=%d tlb_addr=0x%llx flags=0x%x entry=%p full=%p full_xlat=0x%llx addend=0x%llx\n",
(unsigned long long)addr, mmu_idx, (unsigned long)index, maybe_resized,
(unsigned long long)tlb_addr, flags, entry, full,
(unsigned long long)full->xlat_section,
(unsigned long long)entry->addend);
fflush(stdout);
}
#endif
/* Compute haddr speculatively; depending on flags it might be invalid. */
data->haddr = (void *)((uintptr_t)addr + entry->addend);
@@ -2063,15 +1978,6 @@ static uint64_t do_ld_mmio_beN(CPUState *cpu, CPUTLBEntryFull *full,
attrs = full->attrs;
section = io_prepare(&mr_offset, cpu, full->xlat_section, attrs, addr, ra);
mr = section->mr;
#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER)
if (wasm_ramrace_trace && ((addr & TARGET_PAGE_MASK) == 0x3fcb8000u)) {
printf("FAULTTRACE mmio_read addr=0x%llx xlat_section=0x%llx mr_offset=0x%llx mr=%p name=%s ram=%d romd=%d readonly=%d\n",
(unsigned long long)addr, (unsigned long long)full->xlat_section,
(unsigned long long)mr_offset, mr, memory_region_name(mr) ?: "(null)",
memory_region_is_ram(mr), memory_region_is_romd(mr), section->readonly);
fflush(stdout);
}
#endif
BQL_LOCK_GUARD();
return int_ld_mmio_beN(cpu, full, ret_be, addr, size, mmu_idx,
-15
View File
@@ -32,7 +32,6 @@
#include "sysemu/tcg.h"
#include "qemu/accel.h"
#include "hw/boards.h"
#include "hw/core/cpu.h"
#include "migration/vmstate.h"
#include "exec/address-spaces.h"
@@ -1405,10 +1404,6 @@ static const MemoryRegionOps ram_device_mem_ops = {
},
};
#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER)
extern int wasm_ramrace_trace;
#endif
bool memory_region_access_valid(MemoryRegion *mr,
hwaddr addr,
unsigned size,
@@ -1421,16 +1416,6 @@ bool memory_region_access_valid(MemoryRegion *mr,
", size %u, region '%s', reason: rejected\n",
is_write ? "write" : "read",
addr, size, memory_region_name(mr));
#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER)
if (wasm_ramrace_trace) {
printf("FAULTTRACE rejected %s addr=0x%llx size=%u mr=%p name=%s ops=%p opaque=%p ram=%d rom=%d readonly=%d current_cpu=%p\n",
is_write ? "write" : "read", (unsigned long long)addr,
size, mr, memory_region_name(mr) ?: "(null)", mr->ops,
mr->opaque, memory_region_is_ram(mr), memory_region_is_rom(mr),
mr->readonly, current_cpu);
fflush(stdout);
}
#endif
return false;
}
-89
View File
@@ -78,10 +78,6 @@
#include "monitor/monitor.h"
#ifdef EMSCRIPTEN
#include <emscripten/emscripten.h>
#endif
#ifdef CONFIG_LIBDAXCTL
#include <daxctl/libdaxctl.h>
#endif
@@ -93,47 +89,6 @@
*/
RAMList ram_list = { .blocks = QLIST_HEAD_INITIALIZER(ram_list.blocks) };
#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER)
int wasm_ramrace_trace;
static uint32_t wasm_ramrace_read_logs;
static uint32_t wasm_ramrace_cached_read_logs;
static uint32_t wasm_ramrace_write_logs;
static uint32_t wasm_ramrace_cached_write_logs;
static uint32_t wasm_ramrace_map_logs;
static uint32_t wasm_ramrace_unmap_logs;
EMSCRIPTEN_KEEPALIVE void wasm_enable_ramrace_trace(void)
{
wasm_ramrace_trace = 1;
}
static bool wasm_ramrace_overlaps_dram(hwaddr addr, hwaddr len)
{
const hwaddr dram_lo = 0x3fc80000u;
const hwaddr dram_hi = 0x3fce0000u;
return len > 0 && addr < dram_hi && addr + len > dram_lo;
}
static void wasm_ramrace_log_access(const char *kind, hwaddr addr, hwaddr len,
uint32_t *counter)
{
if (!wasm_ramrace_trace || current_cpu || !wasm_ramrace_overlaps_dram(addr, len)) {
return;
}
(*counter)++;
if (*counter <= 200 || (*counter % 10000) == 0) {
printf("RAMRACE %s off-vcpu #%u tid=%lu addr=0x%llx len=0x%llx\n",
kind, *counter, (unsigned long)pthread_self(),
(unsigned long long)addr, (unsigned long long)len);
fflush(stdout);
}
}
#else
#define wasm_ramrace_log_access(kind, addr, len, counter) ((void)0)
#endif
static MemoryRegion *system_memory;
static MemoryRegion *system_io;
@@ -2979,15 +2934,6 @@ static MemTxResult flatview_read(FlatView *fv, hwaddr addr,
l = len;
mr = flatview_translate(fv, addr, &mr_addr, &l, false, attrs);
#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER)
if (wasm_ramrace_trace && current_cpu && mr->ops == &unassigned_mem_ops) {
printf("FAULTTRACE flatview_read addr=0x%llx len=0x%llx mr_addr=0x%llx translated_len=0x%llx fv=%p root=%p root_name=%s nr=%u\n",
(unsigned long long)addr, (unsigned long long)len,
(unsigned long long)mr_addr, (unsigned long long)l,
fv, fv->root, memory_region_name(fv->root) ?: "(null)", fv->nr);
fflush(stdout);
}
#endif
if (!flatview_access_allowed(mr, attrs, addr, len)) {
return MEMTX_ACCESS_ERROR;
}
@@ -3002,9 +2948,6 @@ MemTxResult address_space_read_full(AddressSpace *as, hwaddr addr,
FlatView *fv;
if (len > 0) {
#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER)
wasm_ramrace_log_access("address_space_read", addr, len, &wasm_ramrace_read_logs);
#endif
RCU_READ_LOCK_GUARD();
fv = address_space_to_flatview(as);
result = flatview_read(fv, addr, attrs, buf, len);
@@ -3021,9 +2964,6 @@ MemTxResult address_space_write(AddressSpace *as, hwaddr addr,
FlatView *fv;
if (len > 0) {
#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER)
wasm_ramrace_log_access("address_space_write", addr, len, &wasm_ramrace_write_logs);
#endif
RCU_READ_LOCK_GUARD();
fv = address_space_to_flatview(as);
result = flatview_write(fv, addr, attrs, buf, len);
@@ -3299,15 +3239,6 @@ void *address_space_map(AddressSpace *as,
FlatView *fv;
trace_address_space_map(as, addr, len, is_write, *(uint32_t *) &attrs);
#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER)
if (is_write) {
wasm_ramrace_log_access("address_space_map_write", addr, len,
&wasm_ramrace_map_logs);
} else {
wasm_ramrace_log_access("address_space_map_read", addr, len,
&wasm_ramrace_map_logs);
}
#endif
if (len == 0) {
return NULL;
@@ -3373,18 +3304,6 @@ void address_space_unmap(AddressSpace *as, void *buffer, hwaddr len,
mr = memory_region_from_host(buffer, &addr1);
if (mr != NULL) {
if (is_write) {
#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER)
if (wasm_ramrace_trace && !current_cpu && access_len > 0) {
wasm_ramrace_unmap_logs++;
if (wasm_ramrace_unmap_logs <= 200 ||
(wasm_ramrace_unmap_logs % 10000) == 0) {
printf("RAMRACE address_space_unmap_write off-vcpu #%u tid=%lu host-ram=0x%llx len=0x%llx\n",
wasm_ramrace_unmap_logs, (unsigned long)pthread_self(),
(unsigned long long)addr1, (unsigned long long)access_len);
fflush(stdout);
}
}
#endif
invalidate_and_set_dirty(mr, addr1, access_len);
}
if (xen_enabled()) {
@@ -3600,10 +3519,6 @@ address_space_read_cached_slow(MemoryRegionCache *cache, hwaddr addr,
hwaddr mr_addr, l;
MemoryRegion *mr;
#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER)
wasm_ramrace_log_access("address_space_read_cached", addr, len,
&wasm_ramrace_cached_read_logs);
#endif
l = len;
mr = address_space_translate_cached(cache, addr, &mr_addr, &l, false,
MEMTXATTRS_UNSPECIFIED);
@@ -3621,10 +3536,6 @@ address_space_write_cached_slow(MemoryRegionCache *cache, hwaddr addr,
hwaddr mr_addr, l;
MemoryRegion *mr;
#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER)
wasm_ramrace_log_access("address_space_write_cached", addr, len,
&wasm_ramrace_cached_write_logs);
#endif
l = len;
mr = address_space_translate_cached(cache, addr, &mr_addr, &l, true,
MEMTXATTRS_UNSPECIFIED);
-17
View File
@@ -6607,15 +6607,6 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb, uint64_t pc_start)
#endif
#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER)
wasm_diff_register_tb(tb->tc.ptr, tcg_splitwx_to_rx(tb->tc.ptr), pc_start,
wasm_tb_had_store,
wasm_tb_had_store && !wasm_tb_had_helper);
if (wasm_tb_had_store && wasm_store_pc_hi && pc_start >= wasm_store_pc_lo &&
pc_start < wasm_store_pc_hi) {
wasm_tci_only_tb = true;
printf("STPC TCI pc=0x%llx\n", (unsigned long long)pc_start);
fflush(stdout);
}
if (wasm_tci_only_tb) {
for (int i = 0; i < get_core_nums(); i++) {
export_vec_base[i] = WASM_TCI_ONLY_ENTRY;
@@ -6684,14 +6675,6 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb, uint64_t pc_start)
}
*(uint32_t *)wasm_blob_ptr_base = s->code_ptr - wasm_blob_ptr_base - 4;
if (wasm_dump_pc_hi && pc_start >= wasm_dump_pc_lo && pc_start < wasm_dump_pc_hi) {
uint32_t mod_len = *(uint32_t *)wasm_blob_ptr_base;
const uint8_t *mod = wasm_blob_ptr_base + 4;
char dump_name[32];
snprintf(dump_name, sizeof(dump_name), "pc-%08llx", (unsigned long long)pc_start);
wasm_dump_module(mod, mod_len, dump_name);
}
size_base = (uint32_t*)s->code_ptr;
s->code_ptr += 4;
memcpy(s->code_ptr, target_helper_funcs, num_helper_funcs * 4);
+1 -603
View File
@@ -32,10 +32,7 @@
#include <emscripten/threading.h>
#include "wasm32.h"
extern int wasm_ramrace_trace;
extern int wasm_tlb_guard_enabled;
__thread uintptr_t tci_tb_ptr;
static __thread int tlbtrace_guard_announced;
__thread bool wasm_tci_only_tb;
static int instantiated_wasm_count;
@@ -44,28 +41,6 @@ EMSCRIPTEN_KEEPALIVE int wasm_instantiated_tb_count(void)
return qatomic_read(&instantiated_wasm_count);
}
EM_JS(void, wasm_dump_module_js, (int ptr, int len, int name), {
const bytes = Uint8Array.from(HEAP8.subarray(ptr, ptr + len));
const dumpName = UTF8ToString(name);
try {
const fs = require('fs');
const fname = '/tmp/tbdump-' + dumpName + '.wasm';
fs.writeFileSync(fname, bytes);
out('WASM_DUMP wrote ' + fname + ' (' + len + ' bytes)');
} catch (e) {
let hex = '';
for (let i = 0; i < bytes.length; i++) hex += bytes[i].toString(16).padStart(2, '0');
out('WASM_DUMP_HEX_BEGIN ' + dumpName + ' ' + len);
for (let i = 0; i < hex.length; i += 2048) out('WASM_DUMP_HEX ' + dumpName + ' ' + hex.slice(i, i + 2048));
out('WASM_DUMP_HEX_END ' + dumpName);
}
});
void wasm_dump_module(const uint8_t *p, int len, const char *name)
{
wasm_dump_module_js((int)p, len, (int)name);
}
/* Disassemble TCI bytecode. */
int print_insn_tci(bfd_vma addr, disassemble_info *info)
{
@@ -207,39 +182,6 @@ EM_JS(void, init_wasm32_js, (int tb_ptr_ptr, int cur_core_num, int to_remove_ins
};
});
static void wasm_update_tlb_guard(CPUArchState *env)
{
uintptr_t lo = UINTPTR_MAX;
uintptr_t hi = 0;
CPUState *cpu = env_cpu(env);
ctx.tlb_guard_on = wasm_tlb_guard_enabled;
if (!ctx.tlb_guard_on) {
return;
}
for (int i = 0; i < NB_MMU_MODES; i++) {
CPUTLBDescFast *fast = &cpu->neg.tlb.f[i];
CPUTLBDesc *desc = &cpu->neg.tlb.d[i];
size_t n = fast->table ? ((fast->mask >> CPU_TLB_ENTRY_BITS) + 1) : 0;
if (n) {
lo = MIN(lo, (uintptr_t)fast->table);
hi = MAX(hi, (uintptr_t)(fast->table + n));
}
if (desc->fulltlb && n) {
lo = MIN(lo, (uintptr_t)desc->fulltlb);
hi = MAX(hi, (uintptr_t)(desc->fulltlb + n));
}
}
ctx.tlb_guard_lo = (uint32_t)lo;
ctx.tlb_guard_hi = (uint32_t)hi;
if (wasm_ramrace_trace && !tlbtrace_guard_announced) {
printf("TLBGUARD range lo=0x%x hi=0x%x\n", ctx.tlb_guard_lo, ctx.tlb_guard_hi);
fflush(stdout);
tlbtrace_guard_announced = 1;
}
}
void init_wasm32()
{
if (!initdone) {
@@ -1313,544 +1255,17 @@ static inline uintptr_t tcg_qemu_tb_exec_tci(CPUArchState *env)
}
}
/*
* Compiled-vs-TCI differential (debug).
*
* TCI stays the live/authoritative path (never crashes). For a TB whose guest PC
* is in the inflate window we additionally run the compiled blob as a shadow
* against a DRAM + register snapshot, then compare the resulting registers and
* DRAM against the authoritative TCI run. The first mismatch pinpoints the TB
* (and the first divergent guest register / DRAM word) whose compiled codegen is
* wrong the corruption only manifests through a store, so a divergent DRAM word
* is the miscompiled write. Opt-in via wasm_diff_enable(); no effect otherwise.
*/
#define DIFF_DRAM_BASE 0x3fc80000u
#define DIFF_DRAM_SIZE 0x60000u
#define DIFF_PC_LO 0x42000000ull
#define DIFF_PC_HI 0x42200000ull
__thread uint64_t wasm_cur_tb_pc;
static int wasm_diff_enabled;
static GHashTable *diff_store_tbs;
static GHashTable *diff_safe_tbs;
static __thread int diff_reported;
static __thread int diff_announced;
static __thread int diff_started;
static __thread int diff_skipped_slow;
static __thread uint32_t diff_compared;
static __thread uint8_t *diff_dram_pre, *diff_dram_c, *diff_dram_t;
static __thread uint8_t diff_env_pre[sizeof(CPUArchState)];
static __thread uint8_t diff_env_c[sizeof(CPUArchState)];
static __thread uint8_t diff_env_t[sizeof(CPUArchState)];
/*
* TB Entry Reads CPUNegativeOffsetState - The exit/interrupt check at TB start
* loads env-8 (icount_decr/exit flag), which lives before CPUArchState. The
* shadow must see the same pre-state here or it wrongly takes the early-exit
* path, so snapshot a window immediately below env too.
*/
#define DIFF_NEG sizeof(CPUNegativeOffsetState)
static __thread uint8_t diff_neg_pre[DIFF_NEG];
static __thread uint8_t diff_neg_t[DIFF_NEG];
static __thread uint8_t *diff_tlb_pre[NB_MMU_MODES];
static __thread uint8_t *diff_fulltlb_pre[NB_MMU_MODES];
static __thread size_t diff_tlb_size[NB_MMU_MODES];
static __thread size_t diff_fulltlb_size[NB_MMU_MODES];
static __thread uint32_t diff_compiled_ret;
static __thread int diff_tci_iters;
static __thread uint32_t diff2_eligible, diff2_incomplete, diff2_race;
static __thread uint64_t tlbtrace_last_read, tlbtrace_last_write, tlbtrace_last_addend, tlbtrace_last_xlat;
/* Mode 2 (E11): compiled runs LIVE, so its post-state must be re-applied after
* the TCI shadow. These hold the full compiled-post machine state. */
static __thread uint8_t diff_neg_c[DIFF_NEG];
static __thread uint8_t *diff_tlb_c[NB_MMU_MODES];
static __thread uint8_t *diff_fulltlb_c[NB_MMU_MODES];
int wasm_diff_mode;
int wasm_stateflush_enabled;
int wasm_tlb_guard_enabled;
uint64_t wasm_dump_pc_lo;
uint64_t wasm_dump_pc_hi;
int wasm_store_tci_disabled;
int wasm_store_tci_hash;
int wasm_store_helper_tci;
int wasm_store_bisect_on;
int wasm_store_bisect_width;
uint64_t wasm_store_pc_lo;
uint64_t wasm_store_pc_hi;
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;
EMSCRIPTEN_KEEPALIVE void wasm_disable_store_tci(void)
{
wasm_store_tci_disabled = 1;
}
/* E15 isolation: 1 = interpret even-hash store TBs, 2 = odd-hash. Both widths
* stay in the compiled half, so it separates a width-semantic bug from a
* compiled-store-population threshold. */
EMSCRIPTEN_KEEPALIVE void wasm_set_store_tci_hash(int mode)
{
wasm_store_tci_hash = mode;
}
EMSCRIPTEN_KEEPALIVE void wasm_set_store_helper_tci(void)
{
wasm_store_helper_tci = 1;
}
/* E15 bisection: compile a store TB only when (hash(pc) & mask) == val, else
* TCI. Runtime-settable so the culprit set can be binary-searched with no
* rebuild. */
EMSCRIPTEN_KEEPALIVE void wasm_set_store_bisect(int width, uint32_t mask, uint32_t val)
{
wasm_store_bisect_on = 1;
wasm_store_bisect_width = width;
wasm_store_bisect_mask = mask;
wasm_store_bisect_val = val;
}
EMSCRIPTEN_KEEPALIVE void wasm_set_store_pc_window(uint32_t lo, uint32_t hi)
{
wasm_store_pc_lo = lo;
wasm_store_pc_hi = hi;
}
EMSCRIPTEN_KEEPALIVE void wasm_diff_enable(void)
{
wasm_diff_enabled = 1;
wasm_diff_mode = 1;
}
EMSCRIPTEN_KEEPALIVE void wasm_diff_enable2(void)
{
wasm_diff_enabled = 1;
wasm_diff_mode = 2;
}
EMSCRIPTEN_KEEPALIVE void wasm_stateflush_enable(void)
{
wasm_stateflush_enabled = 1;
}
EMSCRIPTEN_KEEPALIVE void wasm_tlb_guard_enable(void)
{
wasm_tlb_guard_enabled = 1;
}
EMSCRIPTEN_KEEPALIVE void wasm_set_dump_pc_window(uint32_t lo, uint32_t hi)
{
wasm_dump_pc_lo = lo;
wasm_dump_pc_hi = hi;
}
int wasm_diff_on(void)
{
return wasm_diff_enabled;
}
int wasm_diff_needs_nochain(void)
{
return wasm_diff_mode == 1;
}
int wasm_diff_needs_nochain_at(uint64_t pc)
{
return (wasm_stateflush_enabled || wasm_diff_mode == 2) &&
pc >= DIFF_PC_LO && pc < DIFF_PC_HI;
}
static void wasm_trace_dram_tlb(CPUArchState *env, uint64_t pc)
{
CPUState *cpu;
const vaddr page = 0x3fcb8000u;
if (!wasm_ramrace_trace || pc < DIFF_PC_LO || pc >= DIFF_PC_HI) {
return;
}
cpu = env_cpu(env);
for (int mmu = 0; mmu < NB_MMU_MODES; mmu++) {
CPUTLBDescFast *fast = &cpu->neg.tlb.f[mmu];
CPUTLBDesc *desc = &cpu->neg.tlb.d[mmu];
if (!fast->table || !desc->fulltlb) {
continue;
}
size_t n = (fast->mask >> CPU_TLB_ENTRY_BITS) + 1;
for (size_t i = 0; i < n; i++) {
CPUTLBEntry *e = &fast->table[i];
if (((e->addr_read & TARGET_PAGE_MASK) == page) ||
((e->addr_write & TARGET_PAGE_MASK) == page)) {
CPUTLBEntryFull *f = &desc->fulltlb[i];
if (e->addr_read != tlbtrace_last_read ||
e->addr_write != tlbtrace_last_write ||
e->addend != tlbtrace_last_addend ||
f->xlat_section != tlbtrace_last_xlat) {
printf("TLBTRACE pc=0x%llx mmu=%d index=%zu entry=%p full=%p read=0x%llx write=0x%llx addend=0x%llx full_xlat=0x%llx\n",
(unsigned long long)pc, mmu, i, e, f,
(unsigned long long)e->addr_read,
(unsigned long long)e->addr_write,
(unsigned long long)e->addend,
(unsigned long long)f->xlat_section);
fflush(stdout);
tlbtrace_last_read = e->addr_read;
tlbtrace_last_write = e->addr_write;
tlbtrace_last_addend = e->addend;
tlbtrace_last_xlat = f->xlat_section;
}
return;
}
}
}
}
void wasm_diff_register_tb(const void *rw_ptr, const void *rx_ptr, uint64_t pc,
bool has_store, bool safe_shadow)
{
if (!diff_store_tbs) {
diff_store_tbs = g_hash_table_new(g_direct_hash, g_direct_equal);
diff_safe_tbs = g_hash_table_new(g_direct_hash, g_direct_equal);
}
g_hash_table_remove(diff_store_tbs, rw_ptr);
g_hash_table_remove(diff_store_tbs, rx_ptr);
g_hash_table_remove(diff_safe_tbs, rw_ptr);
g_hash_table_remove(diff_safe_tbs, rx_ptr);
if (!has_store) {
return;
}
gpointer value = GUINT_TO_POINTER((uint32_t)pc);
g_hash_table_insert(diff_store_tbs, (void *)rw_ptr, value);
g_hash_table_insert(diff_store_tbs, (void *)rx_ptr, value);
if (safe_shadow) {
g_hash_table_insert(diff_safe_tbs, (void *)rw_ptr, GINT_TO_POINTER(1));
g_hash_table_insert(diff_safe_tbs, (void *)rx_ptr, GINT_TO_POINTER(1));
}
}
bool wasm_diff_lookup_store_tb(const void *tb_ptr, uint64_t *pc)
{
gpointer value = diff_store_tbs ? g_hash_table_lookup(diff_store_tbs, tb_ptr) : NULL;
if (!value) {
return false;
}
if (pc) {
*pc = GPOINTER_TO_UINT(value);
}
return true;
}
bool wasm_diff_lookup_safe_tb(const void *tb_ptr)
{
return diff_safe_tbs && g_hash_table_contains(diff_safe_tbs, tb_ptr);
}
static void diff_report(uint64_t pc)
{
uint32_t pre_ra, pre_sp, stack_m4 = 0, stack_0 = 0, stack_4 = 0;
memcpy(&pre_ra, diff_env_pre + 4, 4);
memcpy(&pre_sp, diff_env_pre + 8, 4);
if (pre_sp >= DIFF_DRAM_BASE + 4 && pre_sp + 8 <= DIFF_DRAM_BASE + DIFF_DRAM_SIZE) {
uint32_t off = pre_sp - DIFF_DRAM_BASE;
memcpy(&stack_m4, diff_dram_pre + off - 4, 4);
memcpy(&stack_0, diff_dram_pre + off, 4);
memcpy(&stack_4, diff_dram_pre + off + 4, 4);
}
/* Compare guest integer registers (env offset 0..127 = gpr[0..31]). */
for (int i = 0; i < 32; i++) {
uint32_t c, t;
memcpy(&c, diff_env_c + i * 4, 4);
memcpy(&t, diff_env_t + i * 4, 4);
if (c != t) {
uint32_t neg8_pre, neg8_t;
memcpy(&neg8_pre, diff_neg_pre + DIFF_NEG - 8, 4);
memcpy(&neg8_t, diff_neg_t + DIFF_NEG - 8, 4);
printf("TCGDIFF pc=0x%llx gpr[%d] compiled=0x%08x tci=0x%08x "
"pre-ra=0x%08x pre-sp=0x%08x cret=0x%08x neg8_pre=0x%08x neg8_t=0x%08x tci_iters=%d\n",
(unsigned long long)pc, i, c, t, pre_ra, pre_sp,
diff_compiled_ret, neg8_pre, neg8_t, diff_tci_iters);
fflush(stdout);
diff_reported = 1;
return;
}
}
/* Compare DRAM word-by-word; first divergent word is the miscompiled store. */
for (uint32_t off = 0; off < DIFF_DRAM_SIZE; off += 4) {
uint32_t c, t;
memcpy(&c, diff_dram_c + off, 4);
memcpy(&t, diff_dram_t + off, 4);
if (c != t) {
printf("TCGDIFF pc=0x%llx dram[0x%08x] compiled=0x%08x tci=0x%08x\n",
(unsigned long long)pc, DIFF_DRAM_BASE + off, c, t);
fflush(stdout);
diff_reported = 1;
return;
}
}
}
static void diff_snapshot_pre(void)
{
if (!diff_dram_pre) {
diff_dram_pre = malloc(DIFF_DRAM_SIZE);
diff_dram_c = malloc(DIFF_DRAM_SIZE);
diff_dram_t = malloc(DIFF_DRAM_SIZE);
}
CPUNegativeOffsetState *neg = (void *)((uint8_t *)ctx.env - DIFF_NEG);
memcpy(diff_env_pre, ctx.env, sizeof(CPUArchState));
memcpy(diff_neg_pre, neg, DIFF_NEG);
for (int i = 0; i < NB_MMU_MODES; i++) {
size_t tlb_size = neg->tlb.f[i].mask + (1 << CPU_TLB_ENTRY_BITS);
size_t n = (neg->tlb.f[i].mask >> CPU_TLB_ENTRY_BITS) + 1;
size_t fulltlb_size = n * sizeof(CPUTLBEntryFull);
diff_tlb_pre[i] = g_realloc(diff_tlb_pre[i], tlb_size);
diff_fulltlb_pre[i] = g_realloc(diff_fulltlb_pre[i], fulltlb_size);
diff_tlb_size[i] = tlb_size;
diff_fulltlb_size[i] = fulltlb_size;
memcpy(diff_tlb_pre[i], neg->tlb.f[i].table, tlb_size);
memcpy(diff_fulltlb_pre[i], neg->tlb.d[i].fulltlb, fulltlb_size);
}
cpu_physical_memory_read(DIFF_DRAM_BASE, diff_dram_pre, DIFF_DRAM_SIZE);
}
static bool diff_restore_pre(CPUArchState *env)
{
CPUNegativeOffsetState *neg = (void *)((uint8_t *)env - DIFF_NEG);
CPUNegativeOffsetState *pre = (void *)diff_neg_pre;
for (int i = 0; i < NB_MMU_MODES; i++) {
if (neg->tlb.f[i].table != pre->tlb.f[i].table ||
neg->tlb.d[i].fulltlb != pre->tlb.d[i].fulltlb) {
return false;
}
}
cpu_physical_memory_write(DIFF_DRAM_BASE, diff_dram_pre, DIFF_DRAM_SIZE);
memcpy(env, diff_env_pre, sizeof(CPUArchState));
memcpy(neg, diff_neg_pre, DIFF_NEG);
for (int i = 0; i < NB_MMU_MODES; i++) {
memcpy(neg->tlb.f[i].table, diff_tlb_pre[i], diff_tlb_size[i]);
memcpy(neg->tlb.d[i].fulltlb, diff_fulltlb_pre[i], diff_fulltlb_size[i]);
}
return true;
}
static void diff_ensure_compiled(const void *tb_ptr)
{
ctx.tb_ptr = (uint32_t *)tb_ptr;
int slot_off = (uint32_t)ctx.tb_ptr + export_vec_off;
if (*(int32_t *)slot_off <= 0) {
instantiate_wasm();
}
}
/* Capture/restore full compiled-post machine state (mode 2 live trajectory). */
static void diff_capture_compiled_post(CPUArchState *env)
{
CPUNegativeOffsetState *neg = (void *)((uint8_t *)env - DIFF_NEG);
memcpy(diff_neg_c, neg, DIFF_NEG);
for (int i = 0; i < NB_MMU_MODES; i++) {
diff_tlb_c[i] = g_realloc(diff_tlb_c[i], diff_tlb_size[i]);
diff_fulltlb_c[i] = g_realloc(diff_fulltlb_c[i], diff_fulltlb_size[i]);
memcpy(diff_tlb_c[i], neg->tlb.f[i].table, diff_tlb_size[i]);
memcpy(diff_fulltlb_c[i], neg->tlb.d[i].fulltlb, diff_fulltlb_size[i]);
}
}
static void diff_restore_compiled_post(CPUArchState *env)
{
CPUNegativeOffsetState *neg = (void *)((uint8_t *)env - DIFF_NEG);
cpu_physical_memory_write(DIFF_DRAM_BASE, diff_dram_c, DIFF_DRAM_SIZE);
memcpy(env, diff_env_c, sizeof(CPUArchState));
memcpy(neg, diff_neg_c, DIFF_NEG);
for (int i = 0; i < NB_MMU_MODES; i++) {
memcpy(neg->tlb.f[i].table, diff_tlb_c[i], diff_tlb_size[i]);
memcpy(neg->tlb.d[i].fulltlb, diff_fulltlb_c[i], diff_fulltlb_size[i]);
}
}
static bool diff_run_compiled(const void *tb_ptr)
{
ctx.tb_ptr = (uint32_t *)tb_ptr;
ctx.do_init = 1;
ctx.done_flag = 2;
int slot_off = (uint32_t)ctx.tb_ptr + export_vec_off;
g_assert(*(int32_t *)slot_off > 0);
diff_compiled_ret = ((wasm_func_ptr)(*(uint32_t *)slot_off))(&ctx);
memcpy(diff_env_c, ctx.env, sizeof(CPUArchState));
cpu_physical_memory_read(DIFF_DRAM_BASE, diff_dram_c, DIFF_DRAM_SIZE);
/* done_flag 2 = pure inline (no slow path); 1 = completed store slow-path
* helper. Both finished this TB (tb_ptr==0); 0 = genuine unwind, skip. */
return ctx.done_flag != 0 && (uint32_t)ctx.tb_ptr == 0;
}
uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env,
const void *v_tb_ptr)
{
ctx.env = env;
ctx.tb_ptr = (uint32_t*)v_tb_ptr;
ctx.do_init = 1;
wasm_update_tlb_guard(env);
if (wasm_diff_mode == 2) {
if (!diff_started) {
printf("TCGDIFF2 enabled first-pc=0x%llx\n",
(unsigned long long)wasm_cur_tb_pc);
fflush(stdout);
diff_started = 1;
}
uint64_t pc = 0;
int slot = *(int32_t *)((uint32_t)ctx.tb_ptr + export_vec_off);
bool eligible = !diff_reported && slot > 0 &&
wasm_diff_lookup_store_tb(v_tb_ptr, &pc) &&
wasm_diff_lookup_safe_tb(v_tb_ptr) &&
pc >= DIFF_PC_LO && pc < DIFF_PC_HI;
if (eligible) {
if (!diff_announced) {
printf("TCGDIFF2 active first-store-pc=0x%llx\n",
(unsigned long long)pc);
fflush(stdout);
diff_announced = 1;
}
diff_snapshot_pre();
struct wasmContext pre_ctx = ctx;
/* Run compiled LIVE (authoritative buggy path); accumulate its state. */
bool compiled_complete = diff_run_compiled(v_tb_ptr);
uint32_t res = diff_compiled_ret;
diff_capture_compiled_post(env);
struct wasmContext c_ctx = ctx;
diff2_eligible++;
if (!compiled_complete) {
diff2_incomplete++;
}
if ((diff2_eligible % 20000) == 0) {
printf("TCGDIFF2 progress eligible=%u incomplete=%u race=%u compared=%u pc=0x%llx\n",
diff2_eligible, diff2_incomplete, diff2_race, diff_compared,
(unsigned long long)pc);
fflush(stdout);
}
/* Rewind, run the known-good TCI shadow, compare. */
if (compiled_complete && diff_restore_pre(env)) {
ctx = pre_ctx;
do {
tcg_qemu_tb_exec_tci(env);
} while ((uint32_t)ctx.tb_ptr != 0);
memcpy(diff_env_t, env, sizeof(CPUArchState));
memcpy(diff_neg_t, (uint8_t *)env - DIFF_NEG, DIFF_NEG);
cpu_physical_memory_read(DIFF_DRAM_BASE, diff_dram_t, DIFF_DRAM_SIZE);
uint32_t neg8_t_flag;
memcpy(&neg8_t_flag, diff_neg_t + DIFF_NEG - 8, 4);
if (neg8_t_flag & 0xffff0000) {
diff2_race++;
} else {
diff_compared++;
if (diff_compared == 1 || diff_compared % 10000 == 0) {
printf("TCGDIFF2 compared=%u pc=0x%llx\n", diff_compared,
(unsigned long long)pc);
fflush(stdout);
}
diff_report(pc);
}
}
/* Restore the live compiled trajectory and continue. */
diff_restore_compiled_post(env);
ctx = c_ctx;
return res;
}
/* Non-eligible: fall through to normal dispatch (compiled runs live). */
} else if (wasm_diff_mode == 1) {
if (!diff_started) {
printf("TCGDIFF enabled first-pc=0x%llx tb-meta=0x%08x\n",
(unsigned long long)wasm_cur_tb_pc, *(uint32_t *)ctx.tb_ptr);
fflush(stdout);
diff_started = 1;
}
uint64_t pc = 0;
bool is_store_tb = wasm_diff_lookup_store_tb(v_tb_ptr, &pc);
int eligible = !diff_reported && is_store_tb &&
wasm_diff_lookup_safe_tb(v_tb_ptr) &&
pc >= DIFF_PC_LO && pc < DIFF_PC_HI;
if (eligible) {
if (!diff_announced) {
printf("TCGDIFF active first-store-pc=0x%llx\n", (unsigned long long)pc);
fflush(stdout);
diff_announced = 1;
}
diff_ensure_compiled(v_tb_ptr);
struct wasmContext pre_ctx = ctx;
diff_snapshot_pre();
/* Run and retain the authoritative TCI result first. */
uint32_t res;
int tci_iters = 0;
do {
res = tcg_qemu_tb_exec_tci(env);
tci_iters++;
} while ((uint32_t)ctx.tb_ptr != 0);
diff_tci_iters = tci_iters;
struct wasmContext tci_ctx = ctx;
memcpy(diff_env_t, env, sizeof(CPUArchState));
memcpy(diff_neg_t, (uint8_t *)env - DIFF_NEG, DIFF_NEG);
cpu_physical_memory_read(DIFF_DRAM_BASE, diff_dram_t, DIFF_DRAM_SIZE);
/* Rewind guest state, run compiled as a shadow, then restore TCI. */
bool restored = diff_restore_pre(env);
ctx = pre_ctx;
bool compiled_complete = restored && diff_run_compiled(v_tb_ptr);
cpu_physical_memory_write(DIFF_DRAM_BASE, diff_dram_t, DIFF_DRAM_SIZE);
memcpy(env, diff_env_t, sizeof(CPUArchState));
memcpy((uint8_t *)env - DIFF_NEG, diff_neg_t, DIFF_NEG);
ctx = tci_ctx;
/* Skip Async-Exit Races - If the IO thread forced a CPU exit
* (icount_decr.high == -1) around the TCI run, TCI took the TB-entry
* interrupt exit while the restored compiled shadow saw a cleared
* flag and ran fully. That divergence is a harness race, not codegen. */
uint32_t neg8_t_flag;
memcpy(&neg8_t_flag, diff_neg_t + DIFF_NEG - 8, 4);
if (neg8_t_flag & 0xffff0000) {
compiled_complete = false;
}
if (compiled_complete && !diff_reported) {
diff_compared++;
if (diff_compared == 1 || diff_compared % 10000 == 0) {
printf("TCGDIFF compared=%u pc=0x%llx\n", diff_compared,
(unsigned long long)pc);
fflush(stdout);
}
diff_report(pc);
} else if (!diff_skipped_slow) {
printf("TCGDIFF skip-slow-path pc=0x%llx\n", (unsigned long long)pc);
fflush(stdout);
diff_skipped_slow = 1;
}
return res;
}
}
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) {
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)) {
@@ -1860,23 +1275,6 @@ 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;
}
if (was_compiled) {
uint64_t pc = 0;
wasm_diff_lookup_store_tb((void *)prev_tb, &pc);
wasm_trace_dram_tlb(env, pc);
}
/* 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;
-42
View File
@@ -18,12 +18,6 @@ struct wasmContext {
uint64_t *stack128;
// 28
uint32_t unwinding;
// 32
uint32_t tlb_guard_lo;
// 36
uint32_t tlb_guard_hi;
// 40
uint32_t tlb_guard_on;
};
#define ENV_OFF 0
@@ -34,9 +28,6 @@ struct wasmContext {
#define DONE_FLAG_OFF 20
#define STACK128_OFF 24
#define UNWINDING_OFF 28
#define TLB_GUARD_LO_OFF 32
#define TLB_GUARD_HI_OFF 36
#define TLB_GUARD_ON_OFF 40
void set_done_flag();
@@ -50,39 +41,6 @@ void flush_tb_instances(void);
void init_wasm32();
void wasm_dump_module(const uint8_t *p, int len, const char *name);
/* TCG compiled-vs-TCI differential (debug, opt-in via wasm_diff_enable()).
* wasm_cur_tb_pc is the guest PC of the TB about to run, set by cpu_tb_exec. */
extern __thread uint64_t wasm_cur_tb_pc;
extern int wasm_diff_mode;
extern int wasm_store_tci_disabled;
extern int wasm_store_tci_hash;
extern int wasm_store_helper_tci;
extern int wasm_store_bisect_on;
extern int wasm_store_bisect_width;
extern uint64_t wasm_store_pc_lo;
extern uint64_t wasm_store_pc_hi;
extern uint64_t wasm_dump_pc_lo;
extern uint64_t wasm_dump_pc_hi;
extern uint32_t wasm_store_bisect_mask;
extern uint32_t wasm_store_bisect_val;
void wasm_disable_store_tci(void);
void wasm_set_store_tci_hash(int mode);
void wasm_set_store_helper_tci(void);
void wasm_set_store_bisect(int width, uint32_t mask, uint32_t val);
void wasm_set_store_pc_window(uint32_t lo, uint32_t hi);
void wasm_set_dump_pc_window(uint32_t lo, uint32_t hi);
void wasm_diff_enable(void);
void wasm_diff_enable2(void);
int wasm_diff_on(void);
int wasm_diff_needs_nochain(void);
int wasm_diff_needs_nochain_at(uint64_t pc);
void wasm_diff_register_tb(const void *rw_ptr, const void *rx_ptr, uint64_t pc,
bool has_store, bool safe_shadow);
bool wasm_diff_lookup_store_tb(const void *tb_ptr, uint64_t *pc);
bool wasm_diff_lookup_safe_tb(const void *tb_ptr);
extern __thread bool wasm_tci_only_tb;
#define INSTANTIATE_NUM 1500
-61
View File
@@ -2235,25 +2235,6 @@ static uint8_t tcg_wasm_out_tlb_load(TCGContext *s, TCGReg addr, MemOpIdx oi, bo
tcg_wasm_out_op_i64_add(s);
tcg_wasm_out_op_local_set(s, TMP64_0_IDX);
if (!is_ld) {
tcg_wasm_out_ctx_i32_load(s, TLB_GUARD_ON_OFF);
tcg_wasm_out_op_if_noret(s);
tcg_wasm_out_op_local_get(s, TMP64_0_IDX);
tcg_wasm_out_op_i32_wrap_i64(s);
tcg_wasm_out_ctx_i32_load(s, TLB_GUARD_LO_OFF);
tcg_wasm_out_op_i32_ge_u(s);
tcg_wasm_out_op_local_get(s, TMP64_0_IDX);
tcg_wasm_out_op_i32_wrap_i64(s);
tcg_wasm_out_ctx_i32_load(s, TLB_GUARD_HI_OFF);
tcg_wasm_out_op_i32_lt_u(s);
tcg_wasm_out_op_i32_and(s);
tcg_wasm_out_op_if_noret(s);
tcg_wasm_out_op_i64_const(s, 0);
tcg_wasm_out_op_local_set(s, TMP64_0_IDX);
tcg_wasm_out_op_end(s);
tcg_wasm_out_op_end(s);
}
tcg_wasm_out_op_end(s);
@@ -3383,14 +3364,8 @@ static uint8_t tcg_tci_out_qemu_ldst(TCGContext *s, TCGOpcode opc, const TCGArg
insn = deposit32(insn, 0, 8, opc);
tcg_tci_out32(s, insn);
}
/* Dump tags: instrumentation-only, set during codegen so tcg.c can dump one store-TB / load-TB
* module for static analysis. No effect on emitted code. */
__thread bool wasm_tb_had_store;
__thread bool wasm_tb_had_load;
__thread bool wasm_tb_had_helper;
static void tcg_out_qemu_ld(TCGContext *s, TCGOpcode opc, const TCGArg *args, bool is_64)
{
wasm_tb_had_load = true;
tcg_tci_out_qemu_ldst(s, opc, args);
// Aliased qemu_ld - The wasm32 wrapper corrupts vCPU TLB state when the load destination also holds the address.
if (args[0] == args[1]) {
@@ -3400,40 +3375,8 @@ static void tcg_out_qemu_ld(TCGContext *s, TCGOpcode opc, const TCGArg *args, bo
}
static void tcg_out_qemu_st(TCGContext *s, TCGOpcode opc, const TCGArg *args, bool is_64)
{
wasm_tb_had_store = true;
tcg_tci_out_qemu_ldst(s, opc, args);
tcg_wasm_out_qemu_st(s, args, is_64);
bool store_tci = false;
if (s->gen_tb && (wasm_store_tci_hash || wasm_store_bisect_on)) {
uint64_t pc = s->gen_tb->pc;
uint32_t h = (uint32_t)((pc * 0x9e3779b97f4a7c15ull) >> 33);
if (wasm_store_bisect_on) {
/* Bisect one width: other widths stay compiled so their culprit is
* always present; the bisected width compiles only its hash bucket.
* This makes finding each culprit a single-target binary search. */
int w = 1 << (opc & MO_SIZE);
bool compiled;
if (wasm_store_bisect_width && w != wasm_store_bisect_width) {
compiled = true;
} else {
compiled = (h & wasm_store_bisect_mask) == wasm_store_bisect_val;
if (compiled) {
printf("STBISECT compile pc=0x%llx h=0x%x w=%d\n",
(unsigned long long)pc, h, w);
fflush(stdout);
}
}
store_tci = !compiled;
} else {
store_tci = ((h & 1) == (uint32_t)(wasm_store_tci_hash - 1));
}
}
if (wasm_store_helper_tci && (wasm_tb_had_helper || wasm_tb_had_load)) {
store_tci = true;
}
if (wasm_diff_mode != 2 && store_tci) {
wasm_tci_only_tb = true;
}
}
static void tcg_out_deposit_i32(TCGContext *s, TCGOpcode opc, TCGReg dest, TCGReg arg1, TCGReg arg2, int pos, int len)
{
@@ -3557,7 +3500,6 @@ static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val,
static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target,
const TCGHelperInfo *info)
{
wasm_tb_had_helper = true;
tcg_tci_out_call(s, target, info);
tcg_wasm_out_call(s, target, info);
}
@@ -3837,9 +3779,6 @@ void tcg_out_init() {
current_label_pos = 0;
env_cached = false;
wasm_tci_only_tb = false;
wasm_tb_had_store = false;
wasm_tb_had_load = false;
wasm_tb_had_helper = false;
}
/* Test if a constant matches the constraint. */