diff --git a/source/extra/wasi_core.h b/source/extra/wasi_core.h index 381e038..0daaae3 100644 --- a/source/extra/wasi_core.h +++ b/source/extra/wasi_core.h @@ -749,7 +749,7 @@ _Static_assert(_Alignof(__wasi_whence_t) == 1, "witx calculated align"); /** * A reference to the offset of a directory entry. - * + * * The value 0 signifies the start of the directory. */ typedef uint64_t __wasi_dircookie_t; diff --git a/source/m3_api_meta_wasi.c b/source/m3_api_meta_wasi.c index 262b635..21e3ce7 100644 --- a/source/m3_api_meta_wasi.c +++ b/source/m3_api_meta_wasi.c @@ -54,7 +54,7 @@ m3ApiRawFunction(m3_wasi_unstable_args_get) m3ApiGetArgMem (uint32_t * , argv) m3ApiGetArgMem (char * , argv_buf) - m3_wasi_context_t* context = (m3_wasi_context_t*)userdata; + m3_wasi_context_t* context = (m3_wasi_context_t*)userdata; if (context == NULL) { m3ApiReturn(__WASI_ERRNO_INVAL); } @@ -77,7 +77,7 @@ m3ApiRawFunction(m3_wasi_unstable_args_sizes_get) m3ApiGetArgMem (__wasi_size_t * , argc) m3ApiGetArgMem (__wasi_size_t * , argv_buf_size) - m3_wasi_context_t* context = (m3_wasi_context_t*)userdata; + m3_wasi_context_t* context = (m3_wasi_context_t*)userdata; if (context == NULL) { m3ApiReturn(__WASI_ERRNO_INVAL); } @@ -342,11 +342,11 @@ m3ApiRawFunction(m3_wasi_unstable_proc_exit) { m3ApiGetArg (uint32_t, code) - m3_wasi_context_t* context = (m3_wasi_context_t*)userdata; + m3_wasi_context_t* context = (m3_wasi_context_t*)userdata; - if (context) { - context->exit_code = code; - } + if (context) { + context->exit_code = code; + } m3ApiTrap(m3Err_trapExit); } @@ -363,7 +363,7 @@ M3Result SuppressLookupFailure(M3Result i_result) m3_wasi_context_t* m3_GetWasiContext() { - return wasi_context; + return wasi_context; } diff --git a/source/m3_api_uvwasi.c b/source/m3_api_uvwasi.c index 7e953f5..c2efa6b 100644 --- a/source/m3_api_uvwasi.c +++ b/source/m3_api_uvwasi.c @@ -46,7 +46,7 @@ m3ApiRawFunction(m3_wasi_unstable_args_get) m3ApiGetArgMem (uint32_t * , argv) m3ApiGetArgMem (char * , argv_buf) - m3_wasi_context_t* context = (m3_wasi_context_t*)userdata; + m3_wasi_context_t* context = (m3_wasi_context_t*)userdata; if (context == NULL) { m3ApiReturn(UVWASI_EINVAL); } @@ -69,7 +69,7 @@ m3ApiRawFunction(m3_wasi_unstable_args_sizes_get) m3ApiGetArgMem (uvwasi_size_t * , argc) m3ApiGetArgMem (uvwasi_size_t * , argv_buf_size) - m3_wasi_context_t* context = (m3_wasi_context_t*)userdata; + m3_wasi_context_t* context = (m3_wasi_context_t*)userdata; if (context == NULL) { m3ApiReturn(UVWASI_EINVAL); } @@ -433,11 +433,11 @@ m3ApiRawFunction(m3_wasi_unstable_proc_exit) { m3ApiGetArg (uint32_t, code) - m3_wasi_context_t* context = (m3_wasi_context_t*)userdata; + m3_wasi_context_t* context = (m3_wasi_context_t*)userdata; - if (context) { - context->exit_code = code; - } + if (context) { + context->exit_code = code; + } m3ApiTrap(m3Err_trapExit); } @@ -454,7 +454,7 @@ M3Result SuppressLookupFailure(M3Result i_result) m3_wasi_context_t* m3_GetWasiContext() { - return wasi_context; + return wasi_context; } diff --git a/source/m3_api_wasi.c b/source/m3_api_wasi.c index 132f39e..bae646e 100644 --- a/source/m3_api_wasi.c +++ b/source/m3_api_wasi.c @@ -198,7 +198,7 @@ m3ApiRawFunction(m3_wasi_unstable_args_get) m3ApiGetArgMem (uint32_t * , argv) m3ApiGetArgMem (char * , argv_buf) - m3_wasi_context_t* context = (m3_wasi_context_t*)userdata; + m3_wasi_context_t* context = (m3_wasi_context_t*)userdata; if (context == NULL) { m3ApiReturn(__WASI_ERRNO_INVAL); } @@ -221,7 +221,7 @@ m3ApiRawFunction(m3_wasi_unstable_args_sizes_get) m3ApiGetArgMem (__wasi_size_t * , argc) m3ApiGetArgMem (__wasi_size_t * , argv_buf_size) - m3_wasi_context_t* context = (m3_wasi_context_t*)userdata; + m3_wasi_context_t* context = (m3_wasi_context_t*)userdata; if (context == NULL) { m3ApiReturn(__WASI_ERRNO_INVAL); } @@ -645,11 +645,11 @@ m3ApiRawFunction(m3_wasi_unstable_proc_exit) { m3ApiGetArg (uint32_t, code) - m3_wasi_context_t* context = (m3_wasi_context_t*)userdata; + m3_wasi_context_t* context = (m3_wasi_context_t*)userdata; - if (context) { - context->exit_code = code; - } + if (context) { + context->exit_code = code; + } m3ApiTrap(m3Err_trapExit); } @@ -666,7 +666,7 @@ M3Result SuppressLookupFailure(M3Result i_result) m3_wasi_context_t* m3_GetWasiContext() { - return wasi_context; + return wasi_context; } diff --git a/source/m3_bind.c b/source/m3_bind.c index 4df95d6..c54196f 100644 --- a/source/m3_bind.c +++ b/source/m3_bind.c @@ -65,7 +65,7 @@ _ (AllocFuncType (& funcType, maxNumArgs)); _throwif ("unknown argument type char", c_m3Type_unknown == type); if (type == c_m3Type_none) - continue; + continue; if (not parsingArgs) { @@ -148,7 +148,7 @@ M3Result FindAndLinkFunction (IM3Module io_module, ccstr_t i_functionName, ccstr_t i_signature, voidptr_t i_function, - voidptr_t i_userdata) + voidptr_t i_userdata) { M3Result result = m3Err_functionLookupFailed; diff --git a/source/m3_compile.c b/source/m3_compile.c index 5dfa627..80d44a9 100644 --- a/source/m3_compile.c +++ b/source/m3_compile.c @@ -2176,12 +2176,14 @@ M3Result Compile_BlockStatements (IM3Compilation o) } #endif - M3Compiler compiler = GetOpInfo(opcode)->compiler; + IM3OpInfo opinfo = GetOpInfo(opcode); + _throwif(m3Err_unknownOpcode, opinfo == NULL); - if (not compiler) - compiler = Compile_Operator; - - result = (* compiler) (o, opcode); + if (opinfo->compiler) { + result = (* opinfo->compiler) (o, opcode); + } else { + result = Compile_Operator(o, opcode); + } o->previousOpcode = opcode; // m3logif (stack, dump_type_stack (o)) @@ -2194,7 +2196,7 @@ M3Result Compile_BlockStatements (IM3Compilation o) if (opcode == c_waOp_end or opcode == c_waOp_else) break; } - +_catch: return result; } diff --git a/source/m3_env.h b/source/m3_env.h index 7095165..b21d3a2 100644 --- a/source/m3_env.h +++ b/source/m3_env.h @@ -10,7 +10,6 @@ #include "wasm3.h" #include "m3_code.h" -#include "m3_exec.h" #include "m3_compile.h" d_m3BeginExternC diff --git a/source/m3_exec.c b/source/m3_exec.c index 65c08ed..af9762b 100644 --- a/source/m3_exec.c +++ b/source/m3_exec.c @@ -15,445 +15,6 @@ void ReportError2 (IM3Function i_function, m3ret_t i_result) i_function->module->runtime->runtimeError = (M3Result)i_result; } -d_m3OpDef (GetGlobal_s32) -{ - u32 * global = immediate (u32 *); - slot (u32) = * global; // printf ("get global: %p %" PRIi64 "\n", global, *global); - - nextOp (); -} - - -d_m3OpDef (GetGlobal_s64) -{ - u64 * global = immediate (u64 *); - slot (u64) = * global; // printf ("get global: %p %" PRIi64 "\n", global, *global); - - nextOp (); -} - - -d_m3OpDef (SetGlobal_i32) -{ - u32 * global = immediate (u32 *); - * global = (u32) _r0; // printf ("set global: %p %" PRIi64 "\n", global, _r0); - - nextOp (); -} - - -d_m3OpDef (SetGlobal_i64) -{ - u64 * global = immediate (u64 *); - * global = (u64) _r0; // printf ("set global: %p %" PRIi64 "\n", global, _r0); - - nextOp (); -} - - -d_m3OpDef (Call) -{ - pc_t callPC = immediate (pc_t); - i32 stackOffset = immediate (i32); - IM3Memory memory = m3MemInfo (_mem); - - m3stack_t sp = _sp + stackOffset; - - m3ret_t r = Call (callPC, sp, _mem, d_m3OpDefaultArgs); - - if (r == 0) - { - _mem = memory->mallocated; - nextOp (); - } - else return r; -} - - -d_m3OpDef (CallIndirect) -{ - u32 tableIndex = slot (u32); - IM3Module module = immediate (IM3Module); - IM3FuncType type = immediate (IM3FuncType); - i32 stackOffset = immediate (i32); - IM3Memory memory = m3MemInfo (_mem); - - m3stack_t sp = _sp + stackOffset; - - m3ret_t r = m3Err_none; - - if (tableIndex < module->table0Size) - { - IM3Function function = module->table0 [tableIndex]; - - if (function) - { - if (type == function->funcType) - { - if (UNLIKELY(not function->compiled)) - r = Compile_Function (function); - - if (not r) - { - r = Call (function->compiled, sp, _mem, d_m3OpDefaultArgs); - - if (not r) - { - _mem = memory->mallocated; - r = nextOpDirect (); - } - } - } - else r = m3Err_trapIndirectCallTypeMismatch; - } - else r = m3Err_trapTableElementIsNull; - } - else r = m3Err_trapTableIndexOutOfRange; - - return r; -} - - -d_m3OpDef (CallRawFunction) -{ - M3RawCall call = (M3RawCall) (* _pc++); - IM3Function function = immediate (IM3Function); - void * userdata = immediate (void *); - u64* const sp = ((u64*)_sp); - -#if d_m3EnableStrace - IM3FuncType ftype = function->funcType; - - FILE* out = stderr; - char outbuff[1024]; - char* outp = outbuff; - char* oute = outbuff+1024; - - outp += snprintf(outp, oute-outp, "%s.%s(", function->import.moduleUtf8, function->import.fieldUtf8); - - const int nArgs = ftype->numArgs; - const int nRets = ftype->numRets; - for (int i=0; itypes[nRets + i]; - switch (type) { - case c_m3Type_i32: outp += snprintf(outp, oute-outp, "%i", *(i32*)(sp+i)); break; - case c_m3Type_i64: outp += snprintf(outp, oute-outp, "%lli", *(i64*)(sp+i)); break; - case c_m3Type_f32: outp += snprintf(outp, oute-outp, "%f", *(f32*)(sp+i)); break; - case c_m3Type_f64: outp += snprintf(outp, oute-outp, "%lf", *(f64*)(sp+i)); break; - default: outp += snprintf(outp, oute-outp, "", type); break; - } - outp += snprintf(outp, oute-outp, (i < nArgs-1) ? ", " : ")"); - } -#endif - - m3ret_t possible_trap = call (m3MemRuntime(_mem), sp, m3MemData(_mem), userdata); - -#if d_m3EnableStrace - if (possible_trap) { - fprintf(out, "%s -> %s\n", outbuff, possible_trap); - } else { - switch (GetSingleRetType(ftype)) { - case c_m3Type_none: fprintf(out, "%s\n", outbuff); break; - case c_m3Type_i32: fprintf(out, "%s = %i\n", outbuff, *(i32*)sp); break; - case c_m3Type_i64: fprintf(out, "%s = %lli\n", outbuff, *(i64*)sp); break; - case c_m3Type_f32: fprintf(out, "%s = %f\n", outbuff, *(f32*)sp); break; - case c_m3Type_f64: fprintf(out, "%s = %lf\n", outbuff, *(f64*)sp); break; - } - } -#endif - - return possible_trap; -} - - -d_m3OpDef (MemCurrent) -{ - IM3Memory memory = m3MemInfo (_mem); - - _r0 = memory->numPages; - - nextOp (); -} - - -d_m3OpDef (MemGrow) -{ - IM3Runtime runtime = m3MemRuntime(_mem); - IM3Memory memory = & runtime->memory; - - u32 numPagesToGrow = (u32) _r0; - _r0 = memory->numPages; - - if (numPagesToGrow) - { - u32 requiredPages = memory->numPages + numPagesToGrow; - - M3Result r = ResizeMemory (runtime, requiredPages); - if (r) - _r0 = -1; - - _mem = memory->mallocated; - } - - nextOp (); -} - - -// it's a debate: should the compilation be trigger be the caller or callee page. -// it's a much easier to put it in the caller pager. if it's in the callee, either the entire page -// has be left dangling or it's just a stub that jumps to a newly acquire page. In Gestalt, I opted -// for the stub approach. Stubbing makes it easier to dynamically free the compilation. You can also -// do both. -d_m3OpDef (Compile) -{ - rewrite_op (op_Call); - - IM3Function function = immediate (IM3Function); - - m3ret_t result = m3Err_none; - - if (UNLIKELY(not function->compiled)) // check to see if function was compiled since this operation was emitted. - result = Compile_Function (function); - - if (not result) - { - // patch up compiled pc and call rewriten op_Call - * ((void**) --_pc) = (void*) (function->compiled); - --_pc; - result = nextOpDirect (); - } - else ReportError2 (function, result); - - return result; -} - - - -d_m3OpDef (Entry) -{ - d_m3ClearRegisters - - IM3Function function = immediate (IM3Function); - -#if d_m3SkipStackCheck - if (true) -#else - if ((void *) ((m3slot_t *) _sp + function->maxStackSlots) < _mem->maxStack) -#endif - { - m3log (exec, " enter %p > %s %s", _pc - 2, function->name ? function->name : ".unnamed", SPrintFunctionArgList (function, _sp)); - -#if defined(DEBUG) - function->hits++; -#endif - u8 * stack = (u8 *) ((m3slot_t *) _sp + function->numArgSlots); - - memset (stack, 0x0, function->numLocalBytes); - stack += function->numLocalBytes; - - if (function->constants) - { - memcpy (stack, function->constants, function->numConstantBytes); - } - - m3ret_t r = nextOpDirect (); - -# if d_m3LogExec - char str [100] = { '!', 0 }; - - if (not r) - SPrintArg (str, 99, _sp, GetSingleRetType(function->funcType)); - - m3log (exec, " exit < %s %s %s %s", function->name, function->funcType->numRets ? "->" : "", str, r ? (cstr_t)r : ""); -# elif d_m3LogStackTrace - if (r) - printf (" ** %s %p\n", function->name, _sp); -# endif - - return r; - } - else return m3Err_trapStackOverflow; -} - - -d_m3OpDef (Loop) -{ - // regs are unused coming into a loop anyway - // this reduces code size & stack usage - d_m3ClearRegisters - - m3ret_t r; - - IM3Memory memory = m3MemInfo (_mem); - - do - { - r = nextOpDirect (); // printf ("loop: %p\n", r); - // linear memory pointer needs refreshed here because the block it's looping over - // can potentially invoke the grow operation. - _mem = memory->mallocated; - } - while (r == _pc); - - return r; -} - - -d_m3OpDef (Branch) -{ - return jumpOp (* _pc); -} - - -d_m3OpDef (If_r) -{ - i32 condition = (i32) _r0; - - pc_t elsePC = immediate (pc_t); - - if (condition) - nextOp (); - else - return jumpOp (elsePC); -} - - -d_m3OpDef (If_s) -{ - i32 condition = slot (i32); - - pc_t elsePC = immediate (pc_t); - - if (condition) - nextOp (); - else - return jumpOp (elsePC); -} - - -d_m3OpDef (BranchTable) -{ - i32 branchIndex = slot (i32); // branch index is always in a slot - i32 numTargets = immediate (i32); - - pc_t * branches = (pc_t *) _pc; - - if (branchIndex < 0 or branchIndex > numTargets) - branchIndex = numTargets; // the default index - - return jumpOp (branches [branchIndex]); -} - - -#define d_m3SetRegisterSetSlot(TYPE, REG) \ -d_m3OpDef (SetRegister_##TYPE) \ -{ \ - REG = slot (TYPE); \ - nextOp (); \ -} \ - \ -d_m3OpDef (SetSlot_##TYPE) \ -{ \ - slot (TYPE) = (TYPE) REG; \ - nextOp (); \ -} \ - \ -d_m3OpDef (PreserveSetSlot_##TYPE) \ -{ \ - TYPE * stack = slot_ptr (TYPE); \ - TYPE * preserve = slot_ptr (TYPE); \ - \ - * preserve = * stack; \ - * stack = (TYPE) REG; \ - \ - nextOp (); \ -} - -d_m3SetRegisterSetSlot (i32, _r0) -d_m3SetRegisterSetSlot (i64, _r0) -#if d_m3HasFloat -d_m3SetRegisterSetSlot (f32, _fp0) -d_m3SetRegisterSetSlot (f64, _fp0) -#endif - -d_m3OpDef (CopySlot_32) -{ - u32 * dst = slot_ptr (u32); - u32 * src = slot_ptr (u32); - - * dst = * src; - - nextOp (); -} - - -d_m3OpDef (PreserveCopySlot_32) -{ - u32 * dest = slot_ptr (u32); - u32 * src = slot_ptr (u32); - u32 * preserve = slot_ptr (u32); - - * preserve = * dest; - * dest = * src; - - nextOp (); -} - - -d_m3OpDef (CopySlot_64) -{ - u64 * dst = slot_ptr (u64); - u64 * src = slot_ptr (u64); - - * dst = * src; // printf ("copy: %p <- %" PRIi64 " <- %p\n", dst, * dst, src); - - nextOp (); -} - - -d_m3OpDef (PreserveCopySlot_64) -{ - u64 * dest = slot_ptr (u64); - u64 * src = slot_ptr (u64); - u64 * preserve = slot_ptr (u64); - - * preserve = * dest; - * dest = * src; - - nextOp (); -} - - -#if d_m3EnableOpTracing -//-------------------------------------------------------------------------------------------------------- -d_m3OpDef (DumpStack) -{ - u32 opcodeIndex = immediate (u32); - u32 stackHeight = immediate (u32); - IM3Function function = immediate (IM3Function); - - cstr_t funcName = (function) ? function->name : ""; - - printf (" %4d ", opcodeIndex); - printf (" %-25s r0: 0x%016" PRIx64 " i:%" PRIi64 " u:%" PRIu64 "\n", funcName, _r0, _r0, _r0); - printf (" fp0: %lf\n", _fp0); - - m3stack_t sp = _sp; - - for (u32 i = 0; i < stackHeight; ++i) - { - cstr_t kind = ""; - - printf ("%p %5s %2d: 0x%" PRIx64 " i:%" PRIi64 "\n", sp, kind, i, (u64) *(sp), (i64) *(sp)); - - ++sp; - } - printf ("---------------------------------------------------------------------------------------------------------\n"); - - return nextOpDirect(); -} -#endif - # if d_m3EnableOpProfiling //-------------------------------------------------------------------------------------------------------- diff --git a/source/m3_exec.h b/source/m3_exec.h index 0e3e2be..729be99 100644 --- a/source/m3_exec.h +++ b/source/m3_exec.h @@ -23,8 +23,10 @@ //------------------------------------------------------------------------------------------------------ -#include "m3_exec_defs.h" #include "m3_math_utils.h" +#include "m3_compile.h" +#include "m3_env.h" +#include "m3_exec_defs.h" #include @@ -32,20 +34,12 @@ d_m3BeginExternC # define rewrite_op(OP) * ((void **) (_pc-1)) = (void*)(OP) -# define d_m3RetSig static inline m3ret_t vectorcall -# define d_m3Op(NAME) op_section d_m3RetSig op_##NAME (d_m3OpSig) - -# define d_m3OpDef(NAME) op_section m3ret_t vectorcall op_##NAME (d_m3OpSig) -# define d_m3OpDecl(NAME) m3ret_t vectorcall op_##NAME (d_m3OpSig); - # define immediate(TYPE) * ((TYPE *) _pc++) # define skip_immediate(TYPE) (_pc++) # define slot(TYPE) * (TYPE *) (_sp + immediate (i32)) # define slot_ptr(TYPE) (TYPE *) (_sp + immediate (i32)) -#define nextOpDirect() ((IM3Operation)(* _pc))(_pc + 1, d_m3OpArgs) -#define jumpOpDirect(PC) ((IM3Operation)(* PC))( PC + 1, d_m3OpArgs) # if d_m3EnableOpProfiling d_m3RetSig profileOp (d_m3OpSig, cstr_t i_operationName); @@ -54,17 +48,17 @@ d_m3BeginExternC d_m3RetSig debugOp (d_m3OpSig, cstr_t i_operationName); # define nextOp() return debugOp (d_m3OpAllArgs, __FUNCTION__) # else -# define nextOp() return nextOpDirect() +# define nextOp() nextOpDirect() # endif -#define jumpOp(PC) jumpOpDirect((pc_t)PC) +#define jumpOp(PC) jumpOpDirect(PC) d_m3RetSig Call (d_m3OpSig) { m3ret_t possible_trap = m3_Yield (); if (UNLIKELY(possible_trap)) return possible_trap; - return nextOpDirect(); + nextOpDirect(); } // TODO: OK, this needs some explanation here ;0 @@ -442,9 +436,448 @@ d_m3ReinterpretOp (_fp0, f32, _r0, i32) d_m3ReinterpretOp (_fp0, f64, _r0, i64) #endif -d_m3OpDecl (Loop) -d_m3OpDecl (If_r) -d_m3OpDecl (If_s) + +d_m3Op (GetGlobal_s32) +{ + u32 * global = immediate (u32 *); + slot (u32) = * global; // printf ("get global: %p %" PRIi64 "\n", global, *global); + + nextOp (); +} + + +d_m3Op (GetGlobal_s64) +{ + u64 * global = immediate (u64 *); + slot (u64) = * global; // printf ("get global: %p %" PRIi64 "\n", global, *global); + + nextOp (); +} + + +d_m3Op (SetGlobal_i32) +{ + u32 * global = immediate (u32 *); + * global = (u32) _r0; // printf ("set global: %p %" PRIi64 "\n", global, _r0); + + nextOp (); +} + + +d_m3Op (SetGlobal_i64) +{ + u64 * global = immediate (u64 *); + * global = (u64) _r0; // printf ("set global: %p %" PRIi64 "\n", global, _r0); + + nextOp (); +} + + +d_m3Op (Call) +{ + pc_t callPC = immediate (pc_t); + i32 stackOffset = immediate (i32); + IM3Memory memory = m3MemInfo (_mem); + + m3stack_t sp = _sp + stackOffset; + + m3ret_t r = Call (callPC, sp, _mem, d_m3OpDefaultArgs); + + if (r == 0) + { + _mem = memory->mallocated; + nextOp (); + } + else trapOp (r); +} + + +d_m3Op (CallIndirect) +{ + u32 tableIndex = slot (u32); + IM3Module module = immediate (IM3Module); + IM3FuncType type = immediate (IM3FuncType); + i32 stackOffset = immediate (i32); + IM3Memory memory = m3MemInfo (_mem); + + m3stack_t sp = _sp + stackOffset; + + m3ret_t r = m3Err_none; + + if (tableIndex < module->table0Size) + { + IM3Function function = module->table0 [tableIndex]; + + if (function) + { + if (type == function->funcType) + { + if (UNLIKELY(not function->compiled)) + r = Compile_Function (function); + + if (not r) + { + r = Call (function->compiled, sp, _mem, d_m3OpDefaultArgs); + + if (not r) + { + _mem = memory->mallocated; + nextOpDirect (); + } + } + } + else r = m3Err_trapIndirectCallTypeMismatch; + } + else r = m3Err_trapTableElementIsNull; + } + else r = m3Err_trapTableIndexOutOfRange; + + trapOp (r); +} + + +d_m3Op (CallRawFunction) +{ + M3RawCall call = (M3RawCall) (* _pc++); + IM3Function function = immediate (IM3Function); + void * userdata = immediate (void *); + u64* const sp = ((u64*)_sp); + +#if d_m3EnableStrace + IM3FuncType ftype = function->funcType; + + FILE* out = stderr; + char outbuff[1024]; + char* outp = outbuff; + char* oute = outbuff+1024; + + outp += snprintf(outp, oute-outp, "%s.%s(", function->import.moduleUtf8, function->import.fieldUtf8); + + const int nArgs = ftype->numArgs; + const int nRets = ftype->numRets; + for (int i=0; itypes[nRets + i]; + switch (type) { + case c_m3Type_i32: outp += snprintf(outp, oute-outp, "%i", *(i32*)(sp+i)); break; + case c_m3Type_i64: outp += snprintf(outp, oute-outp, "%lli", *(i64*)(sp+i)); break; + case c_m3Type_f32: outp += snprintf(outp, oute-outp, "%f", *(f32*)(sp+i)); break; + case c_m3Type_f64: outp += snprintf(outp, oute-outp, "%lf", *(f64*)(sp+i)); break; + default: outp += snprintf(outp, oute-outp, "", type); break; + } + outp += snprintf(outp, oute-outp, (i < nArgs-1) ? ", " : ")"); + } +#endif + + m3ret_t possible_trap = call (m3MemRuntime(_mem), sp, m3MemData(_mem), userdata); + +#if d_m3EnableStrace + if (possible_trap) { + fprintf(out, "%s -> %s\n", outbuff, possible_trap); + } else { + switch (GetSingleRetType(ftype)) { + case c_m3Type_none: fprintf(out, "%s\n", outbuff); break; + case c_m3Type_i32: fprintf(out, "%s = %i\n", outbuff, *(i32*)sp); break; + case c_m3Type_i64: fprintf(out, "%s = %lli\n", outbuff, *(i64*)sp); break; + case c_m3Type_f32: fprintf(out, "%s = %f\n", outbuff, *(f32*)sp); break; + case c_m3Type_f64: fprintf(out, "%s = %lf\n", outbuff, *(f64*)sp); break; + } + } +#endif + + trapOp (possible_trap); +} + + +d_m3Op (MemCurrent) +{ + IM3Memory memory = m3MemInfo (_mem); + + _r0 = memory->numPages; + + nextOp (); +} + + +d_m3Op (MemGrow) +{ + IM3Runtime runtime = m3MemRuntime(_mem); + IM3Memory memory = & runtime->memory; + + u32 numPagesToGrow = (u32) _r0; + _r0 = memory->numPages; + + if (numPagesToGrow) + { + u32 requiredPages = memory->numPages + numPagesToGrow; + + M3Result r = ResizeMemory (runtime, requiredPages); + if (r) + _r0 = -1; + + _mem = memory->mallocated; + } + + nextOp (); +} + + +void ReportError2 (IM3Function i_function, m3ret_t i_result); + + +// it's a debate: should the compilation be trigger be the caller or callee page. +// it's a much easier to put it in the caller pager. if it's in the callee, either the entire page +// has be left dangling or it's just a stub that jumps to a newly acquire page. In Gestalt, I opted +// for the stub approach. Stubbing makes it easier to dynamically free the compilation. You can also +// do both. +d_m3Op (Compile) +{ + rewrite_op (op_Call); + + IM3Function function = immediate (IM3Function); + + m3ret_t result = m3Err_none; + + if (UNLIKELY(not function->compiled)) // check to see if function was compiled since this operation was emitted. + result = Compile_Function (function); + + if (not result) + { + // patch up compiled pc and call rewriten op_Call + * ((void**) --_pc) = (void*) (function->compiled); + --_pc; + nextOpDirect (); + } + else ReportError2 (function, result); + + trapOp (result); +} + + + +d_m3Op (Entry) +{ + d_m3ClearRegisters + + IM3Function function = immediate (IM3Function); + +#if d_m3SkipStackCheck + if (true) +#else + if ((void *) ((m3slot_t *) _sp + function->maxStackSlots) < _mem->maxStack) +#endif + { + m3log (exec, " enter %p > %s %s", _pc - 2, function->name ? function->name : ".unnamed", SPrintFunctionArgList (function, _sp)); + +#if defined(DEBUG) + function->hits++; +#endif + u8 * stack = (u8 *) ((m3slot_t *) _sp + function->numArgSlots); + + memset (stack, 0x0, function->numLocalBytes); + stack += function->numLocalBytes; + + if (function->constants) + { + memcpy (stack, function->constants, function->numConstantBytes); + } + + m3ret_t r = nextOpImpl (); + +# if d_m3LogExec + char str [100] = { '!', 0 }; + + if (not r) + SPrintArg (str, 99, _sp, GetSingleRetType(function->funcType)); + + m3log (exec, " exit < %s %s %s %s", function->name, function->funcType->numRets ? "->" : "", str, r ? (cstr_t)r : ""); +# elif d_m3LogStackTrace + if (r) + printf (" ** %s %p\n", function->name, _sp); +# endif + + return r; + } + else trapOp (m3Err_trapStackOverflow); +} + + +d_m3Op (Loop) +{ + // regs are unused coming into a loop anyway + // this reduces code size & stack usage + d_m3ClearRegisters + + m3ret_t r; + + IM3Memory memory = m3MemInfo (_mem); + + do + { + r = nextOpImpl (); // printf ("loop: %p\n", r); + // linear memory pointer needs refreshed here because the block it's looping over + // can potentially invoke the grow operation. + _mem = memory->mallocated; + } + while (r == _pc); + + trapOp (r); +} + + +d_m3Op (Branch) +{ + jumpOp (* _pc); +} + + +d_m3Op (If_r) +{ + i32 condition = (i32) _r0; + + pc_t elsePC = immediate (pc_t); + + if (condition) + nextOp (); + else + jumpOp (elsePC); +} + + +d_m3Op (If_s) +{ + i32 condition = slot (i32); + + pc_t elsePC = immediate (pc_t); + + if (condition) + nextOp (); + else + jumpOp (elsePC); +} + + +d_m3Op (BranchTable) +{ + i32 branchIndex = slot (i32); // branch index is always in a slot + i32 numTargets = immediate (i32); + + pc_t * branches = (pc_t *) _pc; + + if (branchIndex < 0 or branchIndex > numTargets) + branchIndex = numTargets; // the default index + + jumpOp (branches [branchIndex]); +} + + +#define d_m3SetRegisterSetSlot(TYPE, REG) \ +d_m3Op (SetRegister_##TYPE) \ +{ \ + REG = slot (TYPE); \ + nextOp (); \ +} \ + \ +d_m3Op (SetSlot_##TYPE) \ +{ \ + slot (TYPE) = (TYPE) REG; \ + nextOp (); \ +} \ + \ +d_m3Op (PreserveSetSlot_##TYPE) \ +{ \ + TYPE * stack = slot_ptr (TYPE); \ + TYPE * preserve = slot_ptr (TYPE); \ + \ + * preserve = * stack; \ + * stack = (TYPE) REG; \ + \ + nextOp (); \ +} + +d_m3SetRegisterSetSlot (i32, _r0) +d_m3SetRegisterSetSlot (i64, _r0) +#if d_m3HasFloat +d_m3SetRegisterSetSlot (f32, _fp0) +d_m3SetRegisterSetSlot (f64, _fp0) +#endif + +d_m3Op (CopySlot_32) +{ + u32 * dst = slot_ptr (u32); + u32 * src = slot_ptr (u32); + + * dst = * src; + + nextOp (); +} + + +d_m3Op (PreserveCopySlot_32) +{ + u32 * dest = slot_ptr (u32); + u32 * src = slot_ptr (u32); + u32 * preserve = slot_ptr (u32); + + * preserve = * dest; + * dest = * src; + + nextOp (); +} + + +d_m3Op (CopySlot_64) +{ + u64 * dst = slot_ptr (u64); + u64 * src = slot_ptr (u64); + + * dst = * src; // printf ("copy: %p <- %" PRIi64 " <- %p\n", dst, * dst, src); + + nextOp (); +} + + +d_m3Op (PreserveCopySlot_64) +{ + u64 * dest = slot_ptr (u64); + u64 * src = slot_ptr (u64); + u64 * preserve = slot_ptr (u64); + + * preserve = * dest; + * dest = * src; + + nextOp (); +} + + +#if d_m3EnableOpTracing +//-------------------------------------------------------------------------------------------------------- +d_m3Op (DumpStack) +{ + u32 opcodeIndex = immediate (u32); + u32 stackHeight = immediate (u32); + IM3Function function = immediate (IM3Function); + + cstr_t funcName = (function) ? function->name : ""; + + printf (" %4d ", opcodeIndex); + printf (" %-25s r0: 0x%016" PRIx64 " i:%" PRIi64 " u:%" PRIu64 "\n", funcName, _r0, _r0, _r0); + printf (" fp0: %lf\n", _fp0); + + m3stack_t sp = _sp; + + for (u32 i = 0; i < stackHeight; ++i) + { + cstr_t kind = ""; + + printf ("%p %5s %2d: 0x%" PRIx64 " i:%" PRIi64 "\n", sp, kind, i, (u64) *(sp), (i64) *(sp)); + + ++sp; + } + printf ("---------------------------------------------------------------------------------------------------------\n"); + + nextOpDirect(); +} +#endif #define d_m3Select_i(TYPE, REG) \ @@ -549,13 +982,10 @@ d_m3Select_f (f64, _fp0, s, slot (i32)) d_m3Op (Return) { m3StackCheck(); - return NULL; + trapOp (m3Err_none); } -d_m3OpDecl (Branch) - - d_m3Op (BranchIf_r) { i32 condition = (i32) _r0; @@ -563,7 +993,7 @@ d_m3Op (BranchIf_r) if (condition) { - return jumpOp (branch); + jumpOp (branch); } else nextOp (); } @@ -576,7 +1006,7 @@ d_m3Op (BranchIf_s) if (condition) { - return jumpOp (branch); + jumpOp (branch); } else nextOp (); } @@ -593,7 +1023,7 @@ d_m3Op (TYPE##_BranchIf_##LABEL##s) \ if (condition) \ { \ _r0 = value; \ - return jumpOp (branch); \ + jumpOp (branch); \ } \ else nextOp (); \ } @@ -605,8 +1035,6 @@ d_m3BranchIf (i32, s, slot (i32)) d_m3BranchIf (i64, s, slot (i32)) -d_m3OpDecl (BranchTable) - d_m3Op (ContinueLoop) { @@ -615,7 +1043,7 @@ d_m3Op (ContinueLoop) // has the potential to increase its native-stack usage. (don't forget ContinueLoopIf too.) void * loopId = immediate (void *); - return loopId; + trapOp (loopId); } @@ -626,24 +1054,12 @@ d_m3Op (ContinueLoopIf) if (condition) { - return loopId; + trapOp (loopId); } else nextOp (); } - -d_m3OpDecl (Compile) -d_m3OpDecl (Call) -d_m3OpDecl (CallIndirect) -d_m3OpDecl (CallRawFunction) -d_m3OpDecl (CallRawFunctionEx) -d_m3OpDecl (Entry) - -d_m3OpDecl (MemCurrent) -d_m3OpDecl (MemGrow) - - d_m3Op (Const32) { u32 value = * (u32 *)_pc++; @@ -662,29 +1078,23 @@ d_m3Op (Const64) d_m3Op (Unsupported) { m3log (exec, "*** unsupported ***"); - return "unsupported instruction executed"; + trapOp ("unsupported instruction executed"); } d_m3Op (Unreachable) { m3log (exec, "*** trapping ***"); m3StackCheck(); - return m3Err_trapUnreachable; + trapOp (m3Err_trapUnreachable); } d_m3Op (End) { m3StackCheck(); - return 0; + trapOp (m3Err_none); } -d_m3OpDecl (GetGlobal_s32) -d_m3OpDecl (GetGlobal_s64) -d_m3OpDecl (SetGlobal_i32) -d_m3OpDecl (SetGlobal_i64) - - d_m3Op (SetGlobal_s32) { u32 * global = immediate (u32 *); @@ -722,23 +1132,6 @@ d_m3Op (SetGlobal_f64) #endif -d_m3OpDecl (CopySlot_32) -d_m3OpDecl (PreserveCopySlot_32) - -d_m3OpDecl (CopySlot_64) -d_m3OpDecl (PreserveCopySlot_64) - -#define d_m3SetRegisterSetSlotDecl(TYPE) \ - d_m3OpDecl (SetRegister_##TYPE) \ - d_m3OpDecl (SetSlot_##TYPE) \ - d_m3OpDecl (PreserveSetSlot_##TYPE) - -d_m3SetRegisterSetSlotDecl (i32) -d_m3SetRegisterSetSlotDecl (i64) -d_m3SetRegisterSetSlotDecl (f32) -d_m3SetRegisterSetSlotDecl (f64) - - #if d_m3SkipMemoryBoundsCheck # define m3MemCheck(x) true #else @@ -746,11 +1139,11 @@ d_m3SetRegisterSetSlotDecl (f64) #endif #ifdef DEBUG - #define d_outOfBounds return ErrorRuntime (m3Err_trapOutOfBoundsMemoryAccess, \ + #define d_outOfBounds trapOp (ErrorRuntime (m3Err_trapOutOfBoundsMemoryAccess, \ _mem->runtime, "memory size: %zu; access offset: %zu", \ - _mem->length, operand) + _mem->length, operand)) #else - #define d_outOfBounds return m3Err_trapOutOfBoundsMemoryAccess + #define d_outOfBounds trapOp (m3Err_trapOutOfBoundsMemoryAccess) #endif // memcpy here is to support non-aligned access on some platforms. @@ -946,14 +1339,10 @@ d_m3RetSig debugOp (d_m3OpSig, cstr_t i_opcode) } puts (name); - return nextOpDirect(); + nextOpDirect(); } # endif -# if d_m3EnableOpTracing -d_m3OpDecl (DumpStack) -# endif - # if d_m3EnableOpProfiling typedef struct M3ProfilerSlot @@ -969,7 +1358,7 @@ d_m3RetSig profileOp (d_m3OpSig, cstr_t i_operationName) { ProfileHit (i_operationName); - return nextOpDirect(); + nextOpDirect(); } # endif diff --git a/source/m3_exec_defs.h b/source/m3_exec_defs.h index 13f96d8..589fd8b 100644 --- a/source/m3_exec_defs.h +++ b/source/m3_exec_defs.h @@ -12,6 +12,10 @@ d_m3BeginExternC +#define m3MemData(mem) (u8*)(((M3MemoryHeader*)(mem))+1) +#define m3MemRuntime(mem) (((M3MemoryHeader*)(mem))->runtime) +#define m3MemInfo(mem) (&(((M3MemoryHeader*)(mem))->runtime->memory)) + #if d_m3HasFloat # define d_m3OpSig pc_t _pc, m3stack_t _sp, M3MemoryHeader * _mem, m3reg_t _r0, f64 _fp0 @@ -30,12 +34,19 @@ d_m3BeginExternC #endif -# define m3MemData(mem) (u8*)(((M3MemoryHeader*)(mem))+1) -# define m3MemRuntime(mem) (((M3MemoryHeader*)(mem))->runtime) -# define m3MemInfo(mem) (&(((M3MemoryHeader*)(mem))->runtime->memory)) - typedef m3ret_t (vectorcall * IM3Operation) (d_m3OpSig); +#define d_m3RetSig static inline m3ret_t vectorcall +#define d_m3Op(NAME) op_section d_m3RetSig op_##NAME (d_m3OpSig) + +#define nextOpImpl() ((IM3Operation)(* _pc))(_pc + 1, d_m3OpArgs) +#define jumpOpImpl(PC) ((IM3Operation)(* PC))( PC + 1, d_m3OpArgs) + +#define nextOpDirect() return nextOpImpl() +#define jumpOpDirect(PC) return jumpOpImpl((pc_t)(PC)) + +#define trapOp(err) return (err) + d_m3EndExternC #endif // m3_exec_defs_h diff --git a/source/m3_info.c b/source/m3_info.c index a5f6a2c..cf65157 100644 --- a/source/m3_info.c +++ b/source/m3_info.c @@ -9,6 +9,7 @@ #include "m3_info.h" #include "m3_emit.h" #include "m3_compile.h" +#include "m3_exec.h" #if d_m3LogOutput diff --git a/source/m3_math_utils.h b/source/m3_math_utils.h index f9dab3e..1a493c1 100644 --- a/source/m3_math_utils.h +++ b/source/m3_math_utils.h @@ -153,26 +153,26 @@ u64 rotr64(u64 n, unsigned c) { * Integer Div, Rem */ -#define OP_DIV_U(RES, A, B) \ - if (UNLIKELY(B == 0)) return m3Err_trapDivisionByZero; \ +#define OP_DIV_U(RES, A, B) \ + if (UNLIKELY(B == 0)) trapOp (m3Err_trapDivisionByZero); \ RES = A / B; -#define OP_REM_U(RES, A, B) \ - if (UNLIKELY(B == 0)) return m3Err_trapDivisionByZero; \ +#define OP_REM_U(RES, A, B) \ + if (UNLIKELY(B == 0)) trapOp (m3Err_trapDivisionByZero); \ RES = A % B; // 2's complement detection #if (INT_MIN != -INT_MAX) #define OP_DIV_S(RES, A, B, TYPE_MIN) \ - if (UNLIKELY(B == 0)) return m3Err_trapDivisionByZero; \ + if (UNLIKELY(B == 0)) trapOp (m3Err_trapDivisionByZero); \ if (UNLIKELY(B == -1 and A == TYPE_MIN)) { \ - return m3Err_trapIntegerOverflow; \ + trapOp (m3Err_trapIntegerOverflow); \ } \ RES = A / B; #define OP_REM_S(RES, A, B, TYPE_MIN) \ - if (UNLIKELY(B == 0)) return m3Err_trapDivisionByZero; \ + if (UNLIKELY(B == 0)) trapOp (m3Err_trapDivisionByZero); \ if (UNLIKELY(B == -1 and A == TYPE_MIN)) RES = 0; \ else RES = A % B; @@ -189,10 +189,10 @@ u64 rotr64(u64 n, unsigned c) { #define OP_TRUNC(RES, A, TYPE, RMIN, RMAX) \ if (UNLIKELY(isnan(A))) { \ - return m3Err_trapIntegerConversion; \ + trapOp (m3Err_trapIntegerConversion); \ } \ if (UNLIKELY(A <= RMIN or A >= RMAX)) { \ - return m3Err_trapIntegerOverflow; \ + trapOp (m3Err_trapIntegerOverflow); \ } \ RES = (TYPE)A; diff --git a/source/m3_parse.c b/source/m3_parse.c index 3b994bb..79fb219 100644 --- a/source/m3_parse.c +++ b/source/m3_parse.c @@ -571,7 +571,7 @@ _ (ReadLEB_u7 (& section, & pos, end)); { u32 sectionLength; _ (ReadLEB_u32 (& sectionLength, & pos, end)); - _throwif(m3Err_wasmMalformed, pos + sectionLength > end); + _throwif(m3Err_wasmMalformed, pos + sectionLength > end); _ (ParseModuleSection (module, section, pos, sectionLength)); pos += sectionLength; diff --git a/source/wasm3.h b/source/wasm3.h index 2174c81..ae59d9a 100644 --- a/source/wasm3.h +++ b/source/wasm3.h @@ -61,8 +61,6 @@ typedef struct M3ImportInfo { const char * moduleUtf8; const char * fieldUtf8; - -// unsigned char type; } M3ImportInfo;