kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

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:
Msrc/arch/arch.h | 1-
Msrc/arch/rv64/emu.c | 1-
Msrc/emu/cpu.c | 23-----------------------
Msrc/emu/emu.c | 8+++-----
Msrc/emu/emu.h | 11++---------
Msrc/emu/runtime.c | 89+++++++++++++++++++++++++++++--------------------------------------------------
Msrc/interp/engine.c | 108++++++++++++++++++++++++++++++++++++++++----------------------------------------
Msrc/interp/interp.h | 3++-
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;