commit 79d6c9e94abf68d5d27abbd8dff18fcf582da12b
parent 6ed292ae28aba49938fbbd848517724be0fee3a8
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Wed, 3 Jun 2026 10:36:54 -0700
emu/interp: drop dead cpu_state cluster, size-param load/store, de-global interp fault latch
(1) Delete the vestigial emu cpu_state/cpu_type surface: the always-NULL
emu_cpu_guest_base/guest_va_base/guest_size, emu_cpu_arch_state_const,
emu_cpu_va_to_host_pub, the never-read EmuLiftCtx.cpu_state_type, and the
emu_cpu_type alias + its ArchEmuOps.cpu_type vtable slot (rv64 initializer
and the two NULL-checks shrink accordingly).
(2) Size-parameterize the eight emu_mem_load8/16/32/64 + store8/16/32/64
helpers over new static emu_mem_load_raw/emu_mem_store_raw byte loops; the
wrappers become one-liners. load64 stays a two-half compose to preserve its
per-map-boundary translation semantics.
(3) Move the interpreter memory-fault latch off the file-scope g_mem_fault
global onto KitInterpStack.mem_fault, threading the stack through
mem_read/mem_write/mem_copy and resetting it in kit_interp_stack_reset and at
run entry (CLAUDE.md bans global mutable state).
(cherry picked from commit 93e94d6c8aa832c07c58304aff046d28270351df)
Diffstat:
8 files changed, 94 insertions(+), 150 deletions(-)
diff --git a/src/arch/arch.h b/src/arch/arch.h
@@ -107,7 +107,6 @@ typedef struct ArchDecodeOps {
typedef struct ArchEmuOps {
EmuCPUState* (*cpu_new)(Compiler*, u64 initial_pc, u64 initial_sp);
- KitCgTypeId (*cpu_type)(Compiler*);
KitCgTypeId (*block_fn_type)(Compiler*);
KitStatus (*lift_block)(Compiler*, KitCg*, const KitDecodedInsn*, u32 n,
const EmuLiftCtx*);
diff --git a/src/arch/rv64/emu.c b/src/arch/rv64/emu.c
@@ -489,7 +489,6 @@ static void* rv64_resolve_runtime_helper(void* emu, KitSlice name) {
const ArchEmuOps rv64_emu_ops = {
.cpu_new = rv64_emu_cpu_new,
- .cpu_type = emu_cpu_type,
.block_fn_type = emu_block_fn_type,
.lift_block = rv64_emu_lift_block,
.get_gpr = emu_rv64_xreg,
diff --git a/src/emu/cpu.c b/src/emu/cpu.c
@@ -61,10 +61,6 @@ void emu_cpu_free(EmuCPUState* s) {
void* emu_cpu_arch_state(EmuCPUState* s) { return s ? s->arch_state : NULL; }
-const void* emu_cpu_arch_state_const(const EmuCPUState* s) {
- return s ? s->arch_state : NULL;
-}
-
void emu_cpu_set_thread(EmuCPUState* s, EmuThread* thread) {
if (s) s->thread = thread;
}
@@ -90,23 +86,6 @@ void emu_cpu_attach_addr_space(EmuCPUState* s, EmuAddrSpace* as) {
s->addr_space = as;
}
-u8* emu_cpu_guest_base(const EmuCPUState* s) {
- (void)s;
- return NULL;
-}
-u64 emu_cpu_guest_va_base(const EmuCPUState* s) {
- (void)s;
- return 0;
-}
-u64 emu_cpu_guest_size(const EmuCPUState* s) {
- (void)s;
- return 0;
-}
-
-u8* emu_cpu_va_to_host_pub(EmuCPUState* s, u64 va, u64 nbytes) {
- return emu_cpu_va_to_host_perm(s, va, nbytes, 0);
-}
-
u8* emu_cpu_va_to_host_perm(EmuCPUState* s, u64 va, u64 nbytes, u8 need_perms) {
if (!s || !s->addr_space) return NULL;
return emu_addr_space_ptr(s->addr_space, va, nbytes, need_perms);
@@ -145,8 +124,6 @@ KitCgTypeId emu_thread_type(Compiler* c) {
kit_cg_builtin_types((KitCompiler*)c).id[KIT_CG_BUILTIN_VOID], 0);
}
-KitCgTypeId emu_cpu_type(Compiler* c) { return emu_thread_type(c); }
-
KitCgTypeId emu_block_fn_type(Compiler* c) {
KitCgBuiltinTypes bi;
KitCgFuncParam param;
diff --git a/src/emu/emu.c b/src/emu/emu.c
@@ -218,8 +218,8 @@ static KitStatus emu_resolve_config(Compiler* c, const KitEmuOptions* opts,
arch = arch_lookup(target.arch);
os = os_lookup(target.os);
if (!arch || !arch->decode || !arch->decode->decode_block || !arch->emu ||
- !arch->emu->cpu_new || !arch->emu->cpu_type ||
- !arch->emu->block_fn_type || !arch->emu->lift_block || !os) {
+ !arch->emu->cpu_new || !arch->emu->block_fn_type ||
+ !arch->emu->lift_block || !os) {
return KIT_UNSUPPORTED;
}
@@ -447,8 +447,7 @@ static void* translate_block(KitEmu* e, u64 guest_pc) {
arch = e->process.arch;
if (!arch || !arch->decode || !arch->decode->decode_block || !arch->emu ||
- !arch->emu->cpu_type || !arch->emu->block_fn_type ||
- !arch->emu->lift_block)
+ !arch->emu->block_fn_type || !arch->emu->lift_block)
return NULL;
host_pc = emu_cpu_va_to_host_perm(emu_main_cpu(e), guest_pc,
@@ -501,7 +500,6 @@ static void* translate_block(KitEmu* e, u64 guest_pc) {
ctx.compiler = e->c;
ctx.arch = e->guest_target.arch;
ctx.thread_type = emu_thread_type(e->c);
- ctx.cpu_state_type = ctx.thread_type;
ctx.block_fn_type = arch->emu->block_fn_type(e->c);
ctx.block_sym = block_sym;
ctx.guest_pc = guest_pc;
diff --git a/src/emu/emu.h b/src/emu/emu.h
@@ -413,7 +413,6 @@ EmuCPUState* emu_cpu_new_with_arch_state(Compiler*, KitArchKind, u64 initial_pc,
size_t arch_state_align);
void emu_cpu_free(EmuCPUState*);
void* emu_cpu_arch_state(EmuCPUState*);
-const void* emu_cpu_arch_state_const(const EmuCPUState*);
void emu_cpu_set_thread(EmuCPUState*, EmuThread*);
EmuThread* emu_cpu_thread(const EmuCPUState*);
u64 emu_cpu_pc(const EmuCPUState*);
@@ -421,10 +420,6 @@ void emu_cpu_set_pc(EmuCPUState*, u64);
EmuTrapReason emu_cpu_trap_reason(const EmuCPUState*);
int emu_cpu_exit_code(const EmuCPUState*);
void emu_cpu_attach_addr_space(EmuCPUState*, EmuAddrSpace*);
-u8* emu_cpu_guest_base(const EmuCPUState*);
-u64 emu_cpu_guest_va_base(const EmuCPUState*);
-u64 emu_cpu_guest_size(const EmuCPUState*);
-u8* emu_cpu_va_to_host_pub(EmuCPUState*, u64 va, u64 nbytes);
u8* emu_cpu_va_to_host_perm(EmuCPUState*, u64 va, u64 nbytes, u8 need_perms);
u64 emu_cpu_brk_cur(const EmuCPUState*);
u64 emu_cpu_brk_max(const EmuCPUState*);
@@ -437,7 +432,6 @@ EmuCPUState* emu_thread_cpu(EmuThread*);
/* The interned codegen pointer type representing EmuThread for JIT helper
* calls. CPUState remains arch-owned state below the thread. */
KitCgTypeId emu_thread_type(Compiler*);
-KitCgTypeId emu_cpu_type(Compiler*);
/* The function type `u64 (EmuThread*)` used for every lifted block.
* Returned interned. */
@@ -448,9 +442,8 @@ KitCgTypeId emu_block_fn_type(Compiler*);
typedef struct EmuLiftCtx {
Compiler* compiler;
KitArchKind arch;
- KitCgTypeId thread_type; /* from emu_thread_type */
- KitCgTypeId cpu_state_type; /* legacy alias for pointer helper type */
- KitCgTypeId block_fn_type; /* from emu_block_fn_type */
+ KitCgTypeId thread_type; /* from emu_thread_type */
+ KitCgTypeId block_fn_type; /* from emu_block_fn_type */
KitCgSym block_sym; /* function symbol for this block */
u64 guest_pc; /* PC of first instruction in the block */
} EmuLiftCtx;
diff --git a/src/emu/runtime.c b/src/emu/runtime.c
@@ -220,34 +220,46 @@ static u64 emu_mem_load_checked(EmuThread* t, u64 addr, u64 nbytes, u8 access,
return 0;
}
-u8 emu_mem_load8(EmuThread* t, u64 addr) {
+/* Bounds-checked fast (unchecked-resume) load/store of `nbytes` (1..4)
+ * little-endian bytes through the CPUState guest-AS window. A load miss
+ * trap-faults the CPU and yields 0; a store miss routes through the OS fault
+ * delivery and returns its resume PC. These back the fixed-width shims. */
+static u64 emu_mem_load_raw(EmuThread* t, u64 addr, u32 nbytes) {
EmuCPUState* s = emu_thread_cpu(t);
- u8* p = emu_cpu_va_to_host_perm(s, addr, 1, EMU_MEM_READ);
+ u8* p = emu_cpu_va_to_host_perm(s, addr, nbytes, EMU_MEM_READ);
+ u64 v = 0;
+ u32 i;
if (!p) {
emu_cpu_trap_fault(s);
return 0;
}
- return p[0];
+ for (i = 0; i < nbytes; ++i) v |= ((u64)p[i]) << (8u * i);
+ return v;
}
-u16 emu_mem_load16(EmuThread* t, u64 addr) {
+
+static u64 emu_mem_store_raw(EmuThread* t, u64 addr, u64 v, u32 nbytes,
+ u64 fault_pc, u64 next_pc) {
EmuCPUState* s = emu_thread_cpu(t);
- u8* p = emu_cpu_va_to_host_perm(s, addr, 2, EMU_MEM_READ);
- if (!p) {
- emu_cpu_trap_fault(s);
- return 0;
- }
- return (u16)p[0] | ((u16)p[1] << 8);
+ u8* p = emu_cpu_va_to_host_perm(s, addr, nbytes, EMU_MEM_WRITE);
+ u32 i;
+ if (!p)
+ return emu_deliver_memory_fault(t, addr, EMU_MEM_WRITE, fault_pc, next_pc);
+ for (i = 0; i < nbytes; ++i) p[i] = (u8)(v >> (8u * i));
+ return next_pc;
+}
+
+u8 emu_mem_load8(EmuThread* t, u64 addr) {
+ return (u8)emu_mem_load_raw(t, addr, 1u);
+}
+u16 emu_mem_load16(EmuThread* t, u64 addr) {
+ return (u16)emu_mem_load_raw(t, addr, 2u);
}
u32 emu_mem_load32(EmuThread* t, u64 addr) {
- EmuCPUState* s = emu_thread_cpu(t);
- u8* p = emu_cpu_va_to_host_perm(s, addr, 4, EMU_MEM_READ);
- if (!p) {
- emu_cpu_trap_fault(s);
- return 0;
- }
- return (u32)p[0] | ((u32)p[1] << 8) | ((u32)p[2] << 16) | ((u32)p[3] << 24);
+ return (u32)emu_mem_load_raw(t, addr, 4u);
}
u64 emu_mem_load64(EmuThread* t, u64 addr) {
+ /* Two-half compose preserves the legacy per-map-boundary translation: each
+ * half is bounds-checked through its own va_to_host_perm window. */
u32 lo = emu_mem_load32(t, addr);
u32 hi = emu_mem_load32(t, addr + 4u);
return (u64)lo | ((u64)hi << 32);
@@ -278,51 +290,16 @@ u64 emu_mem_load64_checked(EmuThread* t, u64 addr, u64 fault_pc, u64 next_pc,
}
u64 emu_mem_store8(EmuThread* t, u64 addr, u8 v, u64 fault_pc, u64 next_pc) {
- EmuCPUState* s = emu_thread_cpu(t);
- u8* p = emu_cpu_va_to_host_perm(s, addr, 1, EMU_MEM_WRITE);
- if (!p) {
- return emu_deliver_memory_fault(t, addr, EMU_MEM_WRITE, fault_pc, next_pc);
- }
- p[0] = v;
- return next_pc;
+ return emu_mem_store_raw(t, addr, v, 1u, fault_pc, next_pc);
}
u64 emu_mem_store16(EmuThread* t, u64 addr, u16 v, u64 fault_pc, u64 next_pc) {
- EmuCPUState* s = emu_thread_cpu(t);
- u8* p = emu_cpu_va_to_host_perm(s, addr, 2, EMU_MEM_WRITE);
- if (!p) {
- return emu_deliver_memory_fault(t, addr, EMU_MEM_WRITE, fault_pc, next_pc);
- }
- p[0] = (u8)v;
- p[1] = (u8)(v >> 8);
- return next_pc;
+ return emu_mem_store_raw(t, addr, v, 2u, fault_pc, next_pc);
}
u64 emu_mem_store32(EmuThread* t, u64 addr, u32 v, u64 fault_pc, u64 next_pc) {
- EmuCPUState* s = emu_thread_cpu(t);
- u8* p = emu_cpu_va_to_host_perm(s, addr, 4, EMU_MEM_WRITE);
- if (!p) {
- return emu_deliver_memory_fault(t, addr, EMU_MEM_WRITE, fault_pc, next_pc);
- }
- p[0] = (u8)v;
- p[1] = (u8)(v >> 8);
- p[2] = (u8)(v >> 16);
- p[3] = (u8)(v >> 24);
- return next_pc;
+ return emu_mem_store_raw(t, addr, v, 4u, fault_pc, next_pc);
}
u64 emu_mem_store64(EmuThread* t, u64 addr, u64 v, u64 fault_pc, u64 next_pc) {
- EmuCPUState* s = emu_thread_cpu(t);
- u8* p = emu_cpu_va_to_host_perm(s, addr, 8, EMU_MEM_WRITE);
- if (!p) {
- return emu_deliver_memory_fault(t, addr, EMU_MEM_WRITE, fault_pc, next_pc);
- }
- p[0] = (u8)v;
- p[1] = (u8)(v >> 8);
- p[2] = (u8)(v >> 16);
- p[3] = (u8)(v >> 24);
- p[4] = (u8)(v >> 32);
- p[5] = (u8)(v >> 40);
- p[6] = (u8)(v >> 48);
- p[7] = (u8)(v >> 56);
- return next_pc;
+ return emu_mem_store_raw(t, addr, v, 8u, fault_pc, next_pc);
}
static void emu_syscall_decoded(EmuThread* thread,
diff --git a/src/interp/engine.c b/src/interp/engine.c
@@ -90,34 +90,34 @@ static u64 wr_f(double d, u32 w) {
}
/* ---- memory access (always vtable-translated) ---- */
+/* A translation miss latches st->mem_fault; the run loop converts the latch to
+ * a delivered fault at the next straight-line/branch re-check point. */
-static int g_mem_fault;
-
-static u64 mem_read(InterpProgram* p, u64 addr, u32 size) {
- u8* host = interp_translate(p, addr, size, PERM_R);
+static u64 mem_read(InterpStack* st, u64 addr, u32 size) {
+ u8* host = interp_translate(st->prog, addr, size, PERM_R);
u64 v = 0;
if (!host) {
- g_mem_fault = 1;
+ st->mem_fault = 1;
return 0;
}
memcpy(&v, host, size ? size : 8u);
return v;
}
-static void mem_write(InterpProgram* p, u64 addr, u32 size, u64 v) {
- u8* host = interp_translate(p, addr, size, PERM_W);
+static void mem_write(InterpStack* st, u64 addr, u32 size, u64 v) {
+ u8* host = interp_translate(st->prog, addr, size, PERM_W);
if (!host) {
- g_mem_fault = 1;
+ st->mem_fault = 1;
return;
}
memcpy(host, &v, size ? size : 8u);
}
-static void mem_copy(InterpProgram* p, u64 dst, u64 src, u32 n) {
- u8* d = interp_translate(p, dst, n, PERM_W);
- u8* s = interp_translate(p, src, n, PERM_R);
+static void mem_copy(InterpStack* st, u64 dst, u64 src, u32 n) {
+ u8* d = interp_translate(st->prog, dst, n, PERM_W);
+ u8* s = interp_translate(st->prog, src, n, PERM_R);
if (!d || !s) {
- g_mem_fault = 1;
+ st->mem_fault = 1;
return;
}
memmove(d, s, n);
@@ -166,7 +166,7 @@ static u64 op_value(InterpStack* st, InterpFunc* fn, u64* regs, u32 mem_off,
case OPT_OPK_INDIRECT: {
u64 a = op_addr(st, fn, regs, mem_off, op);
u32 sz = abi_cg_sizeof(fn->prog->c->abi, op->type);
- return mem_read(fn->prog, a, sz ? sz : 8u);
+ return mem_read(st, a, sz ? sz : 8u);
}
default:
return 0;
@@ -185,7 +185,7 @@ static void write_dst(InterpStack* st, InterpFunc* fn, u64* regs, u32 mem_off,
{
u64 a = op_addr(st, fn, regs, mem_off, op);
u32 sz = abi_cg_sizeof(fn->prog->c->abi, op->type);
- mem_write(fn->prog, a, sz ? sz : 8u, value);
+ mem_write(st, a, sz ? sz : 8u, value);
}
}
@@ -200,7 +200,7 @@ static u64 interp_ptr_addr(InterpStack* st, InterpFunc* fn, u64* regs,
if (op->kind == OPK_LOCAL) {
/* pointer-typed local: the slot holds the pointer value */
u64 slot = frame_base(st, mem_off) + fn->slot_off[op->v.frame_slot];
- return mem_read(fn->prog, slot, 8u);
+ return mem_read(st, slot, 8u);
}
return op_addr(st, fn, regs, mem_off, op);
}
@@ -556,9 +556,9 @@ static void bind_args(InterpStack* st, u32 caller_idx, u32 callee_idx,
efn->slot_off[pr->storage.v.frame_slot];
if (cg_type_is_aggregate(p->c, arg->type) || size > 8u) {
u64 src = op_addr(st, cfn, cregs, caller->mem_off, &arg->storage);
- mem_copy(p, dst, src, size);
+ mem_copy(st, dst, src, size);
} else {
- mem_write(p, dst, size ? size : 8u,
+ mem_write(st, dst, size ? size : 8u,
op_value(st, cfn, cregs, caller->mem_off, &arg->storage));
}
}
@@ -593,9 +593,9 @@ static int build_varargs(InterpStack* st, u32 caller_idx, u32 callee_idx,
dst = frame_base(st, callee->mem_off) + cur;
if (cg_type_is_aggregate(p->c, arg->type) || size > 8u) {
u64 src = op_addr(st, cfn, cregs, caller->mem_off, &arg->storage);
- mem_copy(p, dst, src, size);
+ mem_copy(st, dst, src, size);
} else {
- mem_write(p, dst, 8u,
+ mem_write(st, dst, 8u,
op_value(st, cfn, cregs, caller->mem_off, &arg->storage));
}
cur += va_stride_of(size);
@@ -707,7 +707,7 @@ static u64 ext_call(InterpStack* st, InterpFrame* fr, u64* regs, void* host_fp,
u32 k;
for (k = 0; k < ai->nparts; ++k) {
const ABIArgPart* pt = &ai->parts[k];
- u64 chunk = mem_read(p, base + pt->src_offset, pt->size);
+ u64 chunk = mem_read(st, base + pt->src_offset, pt->size);
int bad = (pt->cls == ABI_CLASS_FP)
? ffi_push_fp(&fa, chunk, pt->size, &reason)
: ffi_push_int(&fa, chunk, &reason);
@@ -789,7 +789,7 @@ static u64 ext_call(InterpStack* st, InterpFrame* fr, u64* regs, void* host_fp,
u64 dst = op_addr(st, fr->fn, regs, fr->mem_off, &desc->ret.storage);
u32 k;
for (k = 0; k < fi->ret.nparts && k < 2u; ++k)
- mem_write(p, dst + fi->ret.parts[k].src_offset, fa.ret_size[k], out[k]);
+ mem_write(st, dst + fi->ret.parts[k].src_offset, fa.ret_size[k], out[k]);
}
return out[0];
}
@@ -874,7 +874,7 @@ static u64 ext_call(InterpStack* st, InterpFrame* fr, u64* regs, void* host_fp,
*/
#define NEXT() \
do { \
- if (g_mem_fault) goto fault_mem; \
+ if (st->mem_fault) goto fault_mem; \
++ip; \
in = ip; \
I = in->inst; \
@@ -965,7 +965,7 @@ KitInterpStatus interp_run_stack(InterpStack* st, int64_t* out_ret) {
unsupported(st, fn->reject_reason ? fn->reject_reason : "function");
return (KitInterpStatus)st->status;
}
- g_mem_fault = 0;
+ st->mem_fault = 0;
#if INTERP_DISPATCH_THREADED
in = ip;
@@ -996,31 +996,31 @@ KitInterpStatus interp_run_stack(InterpStack* st, int64_t* out_ret) {
OP(IOP_COPY_AGG) : {
u64 d = op_addr(st, fn, regs, mem_off, &I->opnds[0]);
u64 s = op_addr(st, fn, regs, mem_off, &I->opnds[1]);
- mem_copy(p, d, s, abi_cg_sizeof(p->c->abi, I->opnds[0].type));
+ mem_copy(st, d, s, abi_cg_sizeof(p->c->abi, I->opnds[0].type));
NEXT();
}
OP(IOP_LOAD) : {
u64 a = op_addr(st, fn, regs, mem_off, &I->opnds[1]);
write_dst(st, fn, regs, mem_off, &I->opnds[0],
- mem_read(p, a, in->w0 ? in->w0 : 8u));
+ mem_read(st, a, in->w0 ? in->w0 : 8u));
NEXT();
}
OP(IOP_LOAD_AGG) : {
u64 d = op_addr(st, fn, regs, mem_off, &I->opnds[0]);
u64 s = op_addr(st, fn, regs, mem_off, &I->opnds[1]);
- mem_copy(p, d, s, abi_cg_sizeof(p->c->abi, I->opnds[0].type));
+ mem_copy(st, d, s, abi_cg_sizeof(p->c->abi, I->opnds[0].type));
NEXT();
}
OP(IOP_STORE) : {
u64 a = op_addr(st, fn, regs, mem_off, &I->opnds[0]);
u64 v = op_value(st, fn, regs, mem_off, &I->opnds[1]);
- mem_write(p, a, in->w0 ? in->w0 : 8u, v);
+ mem_write(st, a, in->w0 ? in->w0 : 8u, v);
NEXT();
}
OP(IOP_STORE_AGG) : {
u64 d = op_addr(st, fn, regs, mem_off, &I->opnds[0]);
u64 s = op_addr(st, fn, regs, mem_off, &I->opnds[1]);
- mem_copy(p, d, s, abi_cg_sizeof(p->c->abi, I->opnds[1].type));
+ mem_copy(st, d, s, abi_cg_sizeof(p->c->abi, I->opnds[1].type));
NEXT();
}
OP(IOP_ADDR_OF)
@@ -1079,7 +1079,7 @@ KitInterpStatus interp_run_stack(InterpStack* st, int64_t* out_ret) {
u64 c = op_value(st, fn, regs, mem_off, &I->opnds[0]);
/* A faulting selector would otherwise branch on garbage: branch ops
* skip the straight-line fault re-check, so test the latch here. */
- if (g_mem_fault) {
+ if (st->mem_fault) {
fault(st, "invalid memory access");
goto stop;
}
@@ -1091,7 +1091,7 @@ KitInterpStatus interp_run_stack(InterpStack* st, int64_t* out_ret) {
st, in->sub, op_value(st, fn, regs, mem_off, &I->opnds[0]),
op_value(st, fn, regs, mem_off, &I->opnds[1]), in->w0 ? in->w0 : 8u);
if (st->status) goto stop;
- if (g_mem_fault) {
+ if (st->mem_fault) {
fault(st, "invalid memory access");
goto stop;
}
@@ -1104,7 +1104,7 @@ KitInterpStatus interp_run_stack(InterpStack* st, int64_t* out_ret) {
u32 ci;
u32 target = sw->default_pc;
u32 selw = (u32)abi_cg_sizeof(p->c->abi, sw->sel_type);
- if (g_mem_fault) {
+ if (st->mem_fault) {
fault(st, "invalid memory access");
goto stop;
}
@@ -1127,7 +1127,7 @@ KitInterpStatus interp_run_stack(InterpStack* st, int64_t* out_ret) {
NEXT();
OP(IOP_INDIRECT_BR) : {
u64 target = op_value(st, fn, regs, mem_off, &I->opnds[0]);
- if (g_mem_fault) {
+ if (st->mem_fault) {
fault(st, "invalid memory access");
goto stop;
}
@@ -1181,7 +1181,7 @@ KitInterpStatus interp_run_stack(InterpStack* st, int64_t* out_ret) {
fault(st, "call: stack overflow");
goto stop;
}
- if (g_mem_fault) {
+ if (st->mem_fault) {
fault(st, "invalid memory access");
goto stop;
}
@@ -1331,7 +1331,7 @@ KitInterpStatus interp_run_stack(InterpStack* st, int64_t* out_ret) {
if (in->op == IOP_AGG_COPY) {
IRAggAux* aux = (IRAggAux*)I->extra.aux;
u64 s = interp_ptr_addr(st, fn, regs, mem_off, &I->opnds[1]);
- mem_copy(p, d, s, aux ? aux->access.size : 0u);
+ mem_copy(st, d, s, aux ? aux->access.size : 0u);
} else {
IRAggAux* aux = (IRAggAux*)I->extra.aux;
u64 byte = op_value(st, fn, regs, mem_off, &I->opnds[1]);
@@ -1340,7 +1340,7 @@ KitInterpStatus interp_run_stack(InterpStack* st, int64_t* out_ret) {
if (h)
memset(h, (int)(byte & 0xffu), n);
else
- g_mem_fault = 1;
+ st->mem_fault = 1;
}
NEXT();
}
@@ -1373,7 +1373,7 @@ KitInterpStatus interp_run_stack(InterpStack* st, int64_t* out_ret) {
ssz = aux->access.storage.size ? aux->access.storage.size : 4u;
width = aux->access.bit_width;
if (width) {
- raw = mem_read(p, rec + aux->access.storage_offset, ssz);
+ raw = mem_read(st, rec + aux->access.storage_offset, ssz);
v = (raw >> aux->access.bit_offset) & bits_mask(width);
if (aux->access.signed_ && width < 64u && (v & (1ull << (width - 1u))))
v |= ~bits_mask(width);
@@ -1400,9 +1400,9 @@ KitInterpStatus interp_run_stack(InterpStack* st, int64_t* out_ret) {
ones = bits_mask(width);
fmask = ones << aux->access.bit_offset;
src = op_value(st, fn, regs, mem_off, &I->opnds[1]);
- raw = mem_read(p, addr, ssz);
+ raw = mem_read(st, addr, ssz);
raw = (raw & ~fmask) | ((src & ones) << aux->access.bit_offset);
- mem_write(p, addr, ssz, raw);
+ mem_write(st, addr, ssz, raw);
NEXT();
}
OP(IOP_VA_START) : {
@@ -1410,7 +1410,7 @@ KitInterpStatus interp_run_stack(InterpStack* st, int64_t* out_ret) {
* with a cursor over this frame's anonymous-argument buffer. */
u64 ap = op_value(st, fn, regs, mem_off, &I->opnds[0]);
u64 cursor = fr->has_varargs ? frame_base(st, fr->vararg_off) : 0u;
- mem_write(p, ap, 8u, cursor);
+ mem_write(st, ap, 8u, cursor);
NEXT();
}
OP(IOP_VA_END) : NEXT(); /* nothing to release in the cursor model */
@@ -1418,7 +1418,7 @@ KitInterpStatus interp_run_stack(InterpStack* st, int64_t* out_ret) {
/* opnds = [dst va_list addr, src va_list addr]: duplicate the cursor. */
u64 d = op_value(st, fn, regs, mem_off, &I->opnds[0]);
u64 s = op_value(st, fn, regs, mem_off, &I->opnds[1]);
- mem_write(p, d, 8u, mem_read(p, s, 8u));
+ mem_write(st, d, 8u, mem_read(st, s, 8u));
NEXT();
}
OP(IOP_VA_ARG) : {
@@ -1426,18 +1426,18 @@ KitInterpStatus interp_run_stack(InterpStack* st, int64_t* out_ret) {
* Align the cursor, read the slot, advance, store the cursor back. */
KitCgTypeId ty = I->opnds[0].type;
u64 ap = op_value(st, fn, regs, mem_off, &I->opnds[1]);
- u64 cursor = mem_read(p, ap, 8u);
+ u64 cursor = mem_read(st, ap, 8u);
u32 size = abi_cg_sizeof(p->c->abi, ty);
u32 al = va_align_of(size);
cursor = (cursor + al - 1u) & ~((u64)al - 1u);
if (cg_type_is_aggregate(p->c, ty) || size > 8u) {
u64 dstaddr = op_addr(st, fn, regs, mem_off, &I->opnds[0]);
- mem_copy(p, dstaddr, cursor, size);
+ mem_copy(st, dstaddr, cursor, size);
} else {
write_dst(st, fn, regs, mem_off, &I->opnds[0],
- mem_read(p, cursor, size ? size : 8u));
+ mem_read(st, cursor, size ? size : 8u));
}
- mem_write(p, ap, 8u, cursor + va_stride_of(size));
+ mem_write(st, ap, 8u, cursor + va_stride_of(size));
NEXT();
}
/* Atomics: single-threaded interpreter, so the operation is serialized
@@ -1445,21 +1445,21 @@ KitInterpStatus interp_run_stack(InterpStack* st, int64_t* out_ret) {
OP(IOP_ATOMIC_LOAD) : {
u64 a = op_value(st, fn, regs, mem_off, &I->opnds[1]);
write_dst(st, fn, regs, mem_off, &I->opnds[0],
- mem_read(p, a, in->w0 ? in->w0 : 8u));
+ mem_read(st, a, in->w0 ? in->w0 : 8u));
NEXT();
}
OP(IOP_ATOMIC_STORE) : {
u64 a = op_value(st, fn, regs, mem_off, &I->opnds[0]);
- mem_write(p, a, in->w0 ? in->w0 : 8u,
+ mem_write(st, a, in->w0 ? in->w0 : 8u,
op_value(st, fn, regs, mem_off, &I->opnds[1]));
NEXT();
}
OP(IOP_ATOMIC_RMW) : {
u32 w = in->w0 ? in->w0 : 8u;
u64 a = op_value(st, fn, regs, mem_off, &I->opnds[1]);
- u64 old = mem_read(p, a, w);
+ u64 old = mem_read(st, a, w);
u64 v = op_value(st, fn, regs, mem_off, &I->opnds[2]);
- mem_write(p, a, w, do_rmw(in->sub, old, v, w));
+ mem_write(st, a, w, do_rmw(in->sub, old, v, w));
write_dst(st, fn, regs, mem_off, &I->opnds[0], old);
NEXT();
}
@@ -1468,9 +1468,9 @@ KitInterpStatus interp_run_stack(InterpStack* st, int64_t* out_ret) {
u64 a = op_value(st, fn, regs, mem_off, &I->opnds[2]);
u64 expected = op_value(st, fn, regs, mem_off, &I->opnds[3]);
u64 desired = op_value(st, fn, regs, mem_off, &I->opnds[4]);
- u64 old = mem_read(p, a, w);
+ u64 old = mem_read(st, a, w);
u64 ok = (mask_w(old, w) == mask_w(expected, w));
- if (ok) mem_write(p, a, w, desired);
+ if (ok) mem_write(st, a, w, desired);
write_dst(st, fn, regs, mem_off, &I->opnds[0], old); /* prior */
write_dst(st, fn, regs, mem_off, &I->opnds[1], ok); /* ok flag */
NEXT();
@@ -1485,7 +1485,7 @@ KitInterpStatus interp_run_stack(InterpStack* st, int64_t* out_ret) {
unsupported(st, "opcode");
goto stop;
}
-if (g_mem_fault) {
+if (st->mem_fault) {
fault(st, "invalid memory access");
goto stop;
}
@@ -1571,7 +1571,7 @@ static int interp_intrinsic(InterpStack* st, InterpFunc* fn, u64* regs,
case INTRIN_MEMCPY:
case INTRIN_MEMMOVE: {
u64 d = ARGV(0), s = ARGV(1), n = ARGV(2);
- mem_copy(p, d, s, (u32)n);
+ mem_copy(st, d, s, (u32)n);
if (aux->ndst > 0 && aux->dsts[0].kind == OPK_REG) regs[DST0] = d;
return 1;
}
@@ -1749,7 +1749,7 @@ static void bind_entry_param(InterpStack* st, InterpFunc* fn, u32 idx, u32 i,
} else {
u64 dst =
frame_base(st, fr->mem_off) + fn->slot_off[pr->storage.v.frame_slot];
- mem_write(st->prog, dst, 8u, value);
+ mem_write(st, dst, 8u, value);
}
}
@@ -1821,7 +1821,7 @@ KitStatus kit_interp_stack_reset(KitInterpStack* s) {
st->ret_is_fp = 0;
st->status = KIT_INTERP_DONE;
st->trap_reason = NULL;
- g_mem_fault = 0;
+ st->mem_fault = 0;
return KIT_OK;
}
diff --git a/src/interp/interp.h b/src/interp/interp.h
@@ -179,7 +179,8 @@ struct KitInterpStack {
u32 mem_cap;
u64 scalar_ret; /* return shuttle between frames */
u8 ret_is_fp;
- u8 status; /* KitInterpStatus */
+ u8 status; /* KitInterpStatus */
+ u8 mem_fault; /* set by mem_read/write/copy on a translation miss */
const char* trap_reason;
};
typedef struct KitInterpStack InterpStack;