diff --git a/platforms/app/main.c b/platforms/app/main.c index a190428..624f9ad 100644 --- a/platforms/app/main.c +++ b/platforms/app/main.c @@ -33,7 +33,7 @@ M3Result repl_load (IM3Runtime env, const char* fn) fclose (f); IM3Module module; - result = m3_ParseModule (&module, wasm, fsize); + result = m3_ParseModule (env->environment, &module, wasm, fsize); if (result) return result; result = m3_LoadModule (env, module); @@ -71,10 +71,10 @@ void repl_free(IM3Runtime* env) { } } -M3Result repl_init(IM3Runtime* env) { - repl_free(env); - *env = m3_NewRuntime (8*1024); - if (*env == NULL) { +M3Result repl_init(IM3Environment env, IM3Runtime* runtime) { + repl_free(runtime); + *runtime = m3_NewRuntime (env, 8*1024); + if (*runtime == NULL) { return "m3_NewRuntime failed"; } return c_m3Err_none; @@ -120,7 +120,9 @@ void print_usage() { int main (int i_argc, const char* i_argv[]) { M3Result result = c_m3Err_none; - IM3Runtime env = NULL; + + IM3Environment env = m3_NewEnvironment (); + IM3Runtime runtime = NULL; bool argRepl = false; const char* argFile = NULL; const char* argFunc = "_start"; @@ -157,21 +159,21 @@ int main (int i_argc, const char* i_argv[]) ARGV_SET(argFile); - result = repl_init(&env); + result = repl_init(env, &runtime); if (result) FATAL("repl_init: %s", result); if (argFile) { - result = repl_load(env, argFile); + result = repl_load(runtime, argFile); if (result) FATAL("repl_load: %s", result); - result = m3_LinkWASI (env->modules); + result = m3_LinkWASI (runtime->modules); if (result) FATAL("m3_LinkWASI: %s", result); - result = m3_LinkLibC (env->modules); + result = m3_LinkLibC (runtime->modules); if (result) FATAL("m3_LinkLibC: %s", result); if (argFunc and not argRepl) { - result = repl_call(env, argFunc, i_argc, i_argv); + result = repl_call(runtime, argFunc, i_argc, i_argv); if (result) FATAL("repl_call: %s", result); } } @@ -191,21 +193,21 @@ int main (int i_argc, const char* i_argv[]) } M3Result result = c_m3Err_none; if (!strcmp(":init", argv[0])) { - result = repl_init(&env); + result = repl_init(env, &runtime); } else if (!strcmp(":exit", argv[0])) { - repl_free(&env); + repl_free(&runtime); return 0; } else if (!strcmp(":load", argv[0])) { - result = repl_load(env, argv[1]); + result = repl_load(runtime, argv[1]); } else if (argv[0][0] == ':') { result = "no such command"; } else { - result = repl_call(env, argv[0], argc-1, argv+1); + result = repl_call(runtime, argv[0], argc-1, argv+1); } if (result) { printf ("Error: %s", result); - M3ErrorInfo info = m3_GetErrorInfo (env); + M3ErrorInfo info = m3_GetErrorInfo (runtime); printf (" (%s)\n", info.message); } } @@ -213,14 +215,16 @@ int main (int i_argc, const char* i_argv[]) _onfatal: if (result) { printf ("Error: %s", result); - if (env) + if (runtime) { - M3ErrorInfo info = m3_GetErrorInfo (env); + M3ErrorInfo info = m3_GetErrorInfo (runtime); printf (" (%s)", info.message); } } printf ("\n"); + m3_FreeEnvironment (env); + return 0; } diff --git a/source/m3.h b/source/m3.h index 7e072c5..42f9906 100644 --- a/source/m3.h +++ b/source/m3.h @@ -42,6 +42,7 @@ extern "C" { typedef const char * M3Result; +struct M3Environment; typedef struct M3Environment * IM3Environment; struct M3Runtime; typedef struct M3Runtime * IM3Runtime; struct M3Module; typedef struct M3Module * IM3Module; struct M3Function; typedef struct M3Function * IM3Function; @@ -175,15 +176,18 @@ typedef int64_t (* M3Callback) (IM3Function i_currentFunction, void * i_ref); //-------------------------------------------------------------------------------------------------------------------------------------------- -// "global" environment +// global environment than can host multiple runtimes //-------------------------------------------------------------------------------------------------------------------------------------------- -// IM3Environment m3_NewEnvironment + IM3Environment m3_NewEnvironment (void); + + void m3_FreeEnvironment (IM3Environment i_environment); //-------------------------------------------------------------------------------------------------------------------------------------------- // execution context //-------------------------------------------------------------------------------------------------------------------------------------------- - IM3Runtime m3_NewRuntime (uint32_t i_stackSizeInBytes); + IM3Runtime m3_NewRuntime (IM3Environment io_environment, + uint32_t i_stackSizeInBytes); M3Result m3_RegisterFunction (IM3Runtime io_runtime, @@ -201,7 +205,8 @@ typedef int64_t (* M3Callback) (IM3Function i_currentFunction, void * i_ref); // modules //-------------------------------------------------------------------------------------------------------------------------------------------- - M3Result m3_ParseModule (IM3Module * o_module, + M3Result m3_ParseModule (IM3Environment i_environment, + IM3Module * o_module, const uint8_t * const i_wasmBytes, uint32_t i_numWasmBytes // M3Free i_releaseHandler // i_ref argument type provided to M3Free() handler is diff --git a/source/m3_compile.c b/source/m3_compile.c index 4d65d44..855cbe4 100644 --- a/source/m3_compile.c +++ b/source/m3_compile.c @@ -16,33 +16,8 @@ #define d_indent " | " -u16 GetMaxExecSlot (IM3Compilation o); - -const char * GetOpcodeIndentionString (IM3Compilation o) -{ - i32 blockDepth = o->block.depth + 1; - if (blockDepth < 0) - blockDepth = 0; - - static const char * s_spaces = "......................................................................................."; - const char * indent = s_spaces + strlen (s_spaces); - indent -= (blockDepth * 2); - if (indent < s_spaces) - indent = s_spaces; - - return indent; -} - - -const char * GetIndentionString (IM3Compilation o) -{ - o->block.depth += 4; - const char *indent = GetOpcodeIndentionString (o); - o->block.depth -= 4; - - return indent; -} +u16 GetMaxExecSlot (IM3Compilation o); void emit_stack_dump (IM3Compilation o) @@ -61,19 +36,6 @@ void emit_stack_dump (IM3Compilation o) } -void log_opcode (IM3Compilation o, u8 i_opcode) -{ - if (i_opcode == c_waOp_end or i_opcode == c_waOp_else) - o->block.depth--; -#ifdef DEBUG - m3log (compile, "%4d | 0x%02x %s %s", o->numOpcodes++, i_opcode, GetOpcodeIndentionString (o), c_operations [i_opcode].name); -#else - m3log (compile, "%4d | 0x%02x %s", o->numOpcodes++, i_opcode, GetOpcodeIndentionString (o)); -#endif - if (i_opcode == c_waOp_end or i_opcode == c_waOp_else) - o->block.depth++; -} - //------------------------------------------------------------------------------------------------------------------------- static const IM3Operation c_setSetOps [] = { NULL, op_SetSlot_i32, op_SetSlot_i64, op_SetSlot_f32, op_SetSlot_f64 }; @@ -523,6 +485,13 @@ M3Result EmitTopSlotAndPop (IM3Compilation o) } +void EmitMemory (IM3Compilation o) +{ + // this is factored out for potential future functionality. see comment on op_Loop in m3_exec.c + EmitPointer (o, & o->runtime->memory); +} + + M3Result AddTrapRecord (IM3Compilation o) { M3Result result = c_m3Err_none; @@ -566,7 +535,7 @@ M3Result CopyTopSlot (IM3Compilation o, u16 i_destSlot) u8 type = GetStackTopType (o); op = c_setSetOps [type]; } - else op = op_CopySlot; + else op = op_CopySlot_64; // TODO: need 32-bit version for compacted stack _ (EmitOp (o, op)); EmitConstant (o, i_destSlot); @@ -593,7 +562,7 @@ M3Result PreservedCopyTopSlot (IM3Compilation o, u16 i_destSlot, u16 i_preserv bool isFp = IsStackTopTypeFp (o); op = isFp ? op_PreserveSetSlot_f64 : op_PreserveSetSlot_i64; } - else op = op_PreserveCopySlot; + else op = op_PreserveCopySlot_64; _ (EmitOp (o, op)); EmitConstant (o, i_destSlot); @@ -713,7 +682,7 @@ M3Result Compile_Const_i32 (IM3Compilation o, u8 i_opcode) M3Result result; i32 value; -_ (ReadLEB_i32 (& value, & o->wasm, o->wasmEnd)); m3log (compile, d_indent "%s (const i32 = %" PRIi32 ")", GetIndentionString (o), value); +_ (ReadLEB_i32 (& value, & o->wasm, o->wasmEnd)); m3log (compile, d_indent "%s (const i32 = %" PRIi32 ")", get_indention_string (o), value); _ (PushConst (o, value, c_m3Type_i32)); @@ -726,7 +695,7 @@ M3Result Compile_Const_i64 (IM3Compilation o, u8 i_opcode) M3Result result; i64 value; -_ (ReadLEB_i64 (& value, & o->wasm, o->wasmEnd)); m3log (compile, d_indent "%s (const i64 = %" PRIi64 ")", GetIndentionString (o), value); +_ (ReadLEB_i64 (& value, & o->wasm, o->wasmEnd)); m3log (compile, d_indent "%s (const i64 = %" PRIi64 ")", get_indention_string (o), value); _ (PushConst (o, value, c_m3Type_i64)); @@ -741,7 +710,7 @@ M3Result Compile_Const_f32 (IM3Compilation o, u8 i_opcode) f32 value; union { u64 u; f32 f; } union64; -_ (Read_f32 (& value, & o->wasm, o->wasmEnd)); m3log (compile, d_indent "%s (const f32 = %f)", GetIndentionString (o), value); +_ (Read_f32 (& value, & o->wasm, o->wasmEnd)); m3log (compile, d_indent "%s (const f32 = %f)", get_indention_string (o), value); union64.f = value; @@ -758,7 +727,7 @@ M3Result Compile_Const_f64 (IM3Compilation o, u8 i_opcode) f64 value; union { u64 u; f64 f; } union64; -_ (Read_f64 (& value, & o->wasm, o->wasmEnd)); m3log (compile, d_indent "%s (const f64 = %lf)", GetIndentionString (o), value); +_ (Read_f64 (& value, & o->wasm, o->wasmEnd)); m3log (compile, d_indent "%s (const f64 = %lf)", get_indention_string (o), value); union64.f = value; @@ -1107,12 +1076,12 @@ _ (ReadLEB_u32 (& functionIndex, & o->wasm, o->wasmEnd)); if (function) { m3log (compile, d_indent "%s (func= '%s'; args= %d)", - GetIndentionString (o), GetFunctionName (function), function->funcType->numArgs); + get_indention_string (o), GetFunctionName (function), function->funcType->numArgs); if (function->module) { // TODO OPTZ: could avoid arg copy when args are already sequential and at top - u16 execTop = GetMaxExecSlot (o); + u16 slotTop = GetMaxExecSlot (o); _ (CompileCallArgsReturn (o, function->funcType, false)); @@ -1132,7 +1101,8 @@ _ (CompileCallArgsReturn (o, function->funcType, false)); _ (EmitOp (o, op)); EmitPointer (o, operand); - EmitOffset (o, execTop); + EmitOffset (o, slotTop); + EmitMemory (o); } else result = ErrorCompile (c_m3Err_functionImportMissing, o, "'%s'", GetFunctionName (function)); } @@ -1163,6 +1133,7 @@ _ (EmitOp (o, op_CallIndirect)); EmitPointer (o, o->module); EmitPointer (o, type); // TODO: unify all types in M3Runtime EmitOffset (o, execTop); + EmitMemory (o); } else _throw ("function type index out of range"); @@ -1213,7 +1184,7 @@ M3Result ReadBlockType (IM3Compilation o, u8 * o_blockType) _ (ReadLEB_i7 (& type, & o->wasm, o->wasmEnd)); _ (NormalizeType (o_blockType, type)); if (* o_blockType) m3log (compile, d_indent "%s (block_type: 0x%02x normalized: %d)", - GetIndentionString (o), (u32) (u8) type, (u32) * o_blockType); + get_indention_string (o), (u32) (u8) type, (u32) * o_blockType); _catch: return result; } @@ -1230,7 +1201,7 @@ _ (ReadBlockType (o, & blockType)); if (i_opcode == c_waOp_loop) { _ (EmitOp (o, op_Loop)); - EmitPointer (o, & o->runtime->memory); + EmitMemory (o); } _ (CompileBlock (o, blockType, i_opcode)); @@ -1456,7 +1427,7 @@ M3Result Compile_Load_Store (IM3Compilation o, u8 i_opcode) _ (ReadLEB_u32 (& alignHint, & o->wasm, o->wasmEnd)); _ (ReadLEB_u32 (& offset, & o->wasm, o->wasmEnd)); - m3log (compile, d_indent "%s (offset = %d)", GetIndentionString (o), offset); + m3log (compile, d_indent "%s (offset = %d)", get_indention_string (o), offset); _ (Compile_Operator (o, i_opcode)); EmitConstant (o, offset); @@ -1693,8 +1664,8 @@ const M3OpInfo c_operations [] = M3OP( "SetGlobal_s", 0, none, op_SetGlobal_s), - M3OP( "PreserveCopySlot", 0, none, op_PreserveCopySlot), - M3OP( "CopySlot", 0, none, op_CopySlot), + M3OP( "PreserveCopySlot", 0, none, op_PreserveCopySlot_64), + M3OP( "CopySlot", 0, none, op_CopySlot_64), M3OP( "SetSlot_i32", 0, none, op_SetSlot_i32), M3OP( "SetSlot_i64", 0, none, op_SetSlot_i64), M3OP( "SetSlot_f32", 0, none, op_SetSlot_f32), @@ -1713,7 +1684,7 @@ const M3OpInfo c_operations [] = M3OP( "End", 0, none, op_End ), # endif - M3OP( "termination", 0, c_m3Type_void ) // termination for FindOperationInfo () + M3OP( "termination", 0, c_m3Type_void ) // termination for find_operation_info () }; diff --git a/source/m3_compile.h b/source/m3_compile.h index 4d6a6fd..d77ba68 100644 --- a/source/m3_compile.h +++ b/source/m3_compile.h @@ -12,18 +12,6 @@ #include "m3_env.h" #include "m3_exec_defs.h" -/* - - WebAssembly spec info - --------------------- - 2.3.2 Result Types - Note: In the current version of WebAssembly, at most one value is allowed as a result. However, this may be - generalized to sequences of values in future versions. - - M3 - -- - -*/ enum { diff --git a/source/m3_emit.c b/source/m3_emit.c index f49f92b..8076072 100644 --- a/source/m3_emit.c +++ b/source/m3_emit.c @@ -47,7 +47,7 @@ M3Result BridgeToNewPageIfNecessary (IM3Compilation o) void log_emit (IM3Operation i_operation) { # if DEBUG - OpInfo i = FindOperationInfo (i_operation); + OpInfo i = find_operation_info (i_operation); if (i.info) { diff --git a/source/m3_env.c b/source/m3_env.c index de028b9..37496c6 100644 --- a/source/m3_env.c +++ b/source/m3_env.c @@ -71,20 +71,42 @@ void FreeImportInfo (M3ImportInfo * i_info) m3Free (i_info->fieldUtf8); } -IM3Runtime m3_NewRuntime (u32 i_stackSizeInBytes) + +IM3Environment m3_NewEnvironment () { - IM3Runtime env; - m3Alloc (& env, M3Runtime, 1); + IM3Environment env = NULL; + m3Alloc (& env, M3Environment, 1); + + return env; +} - if (!env) return NULL; - m3Malloc (& env->stack, i_stackSizeInBytes); +void m3_FreeEnvironment (IM3Environment i_environment) +{ + if (i_environment) + { +// ReleaseEnvironment (i_environment); + m3Free (i_environment); + } +} - if (!env->stack) { - m3Free(env); - return NULL; + +IM3Runtime m3_NewRuntime (IM3Environment i_environment, u32 i_stackSizeInBytes) +{ + IM3Runtime env = NULL; + m3Alloc (& env, M3Runtime, 1); + + if (env) + { + m3Malloc (& env->stack, i_stackSizeInBytes); + + if (env->stack) + { + env->numStackSlots = i_stackSizeInBytes / sizeof (m3reg_t); + env->environment = i_environment; + } + else m3Free (env); } - env->numStackSlots = i_stackSizeInBytes / sizeof (m3reg_t); return env; } diff --git a/source/m3_env.h b/source/m3_env.h index 4b9322e..a4cb218 100644 --- a/source/m3_env.h +++ b/source/m3_env.h @@ -183,10 +183,21 @@ M3Result Module_AddGlobal (IM3Module io_module, IM M3Result Module_AddFunction (IM3Module io_module, u32 i_typeIndex, IM3ImportInfo i_importInfo /* can be null */); IM3Function Module_GetFunction (IM3Module i_module, u32 i_functionIndex); +//--------------------------------------------------------------------------------------------------------------------------------- +typedef struct M3Environment +{ + // u32 numFuncTypes; + // M3FuncType * funcTypes; +} +M3Environment; + +typedef M3Environment * IM3Environment; //--------------------------------------------------------------------------------------------------------------------------------- typedef struct M3Runtime { + IM3Environment environment; + M3CodePage * pagesOpen; // linked list of code pages with writable space on them M3CodePage * pagesFull; // linked list of finalized pages @@ -200,9 +211,6 @@ typedef struct M3Runtime M3Memory memory; -// u32 numFuncTypes; -// M3FuncType * funcTypes; - M3ErrorInfo error; } M3Runtime; diff --git a/source/m3_exec.c b/source/m3_exec.c index 0474b39..d712f96 100644 --- a/source/m3_exec.c +++ b/source/m3_exec.c @@ -33,15 +33,18 @@ d_m3OpDef (Call) { pc_t callPC = immediate (pc_t); i32 stackOffset = immediate (i32); + M3Memory * memory = immediate (M3Memory *); m3stack_t sp = _sp + stackOffset; m3ret_t r = Call (callPC, sp, _mem, d_m3OpDefaultArgs); if (r == 0) + { + _mem = memory->wasmPages; return nextOp (); - else - return r; + } + else return r; } @@ -50,6 +53,7 @@ d_m3OpDef (CallIndirect) IM3Module module = immediate (IM3Module); IM3FuncType type = immediate (IM3FuncType); i32 stackOffset = immediate (i32); + M3Memory * memory = immediate (M3Memory *); m3stack_t sp = _sp + stackOffset; @@ -63,6 +67,9 @@ d_m3OpDef (CallIndirect) if (function) { + // TODO: this can eventually be simplified. by using a shared set of unique M3FuncType objects in + // M3Environment, the compare can be reduced to a single pointer-compare operation + if (type->numArgs != function->funcType->numArgs) { return c_m3Err_trapIndirectCallTypeMismatch; @@ -89,7 +96,10 @@ d_m3OpDef (CallIndirect) r = Call (function->compiled, sp, _mem, d_m3OpDefaultArgs); if (not r) + { + _mem = memory->wasmPages; r = nextOp (); + } } } else r = "trap: table element is null"; @@ -275,6 +285,7 @@ d_m3OpDef (Loop) // compiled m3 code. with non-Windows calling conventions, a new // "IM3Runtime _runtime" argument could be added to operations to detach // the execution context from the codepage. + // alternatively: // the compiler could track whether blocks/functions contain mem.grows. // functions that are grow-clean could be shared and those that aren't diff --git a/source/m3_exec.h b/source/m3_exec.h index 7310467..f0f480c 100644 --- a/source/m3_exec.h +++ b/source/m3_exec.h @@ -301,8 +301,8 @@ d_m3Op(TO##_##NAME##_##FROM##_r) \ \ d_m3Op(TO##_##NAME##_##FROM##_s) \ { \ - FROM * stack = (FROM *) (_sp + immediate (i32)); \ - REG_TO = (TO) (* stack); \ + FROM from = slot (FROM); \ + REG_TO = (TO) (from); \ return nextOp (); \ } @@ -625,7 +625,7 @@ d_m3Op (SetGlobal_f64) } -d_m3Op (CopySlot) +d_m3Op (CopySlot_64) { u64 * dst = slot_ptr (u64); u64 * src = slot_ptr (u64); @@ -636,7 +636,7 @@ d_m3Op (CopySlot) } -d_m3Op (PreserveCopySlot) +d_m3Op (PreserveCopySlot_64) { u64 * dest = slot_ptr (u64); u64 * src = slot_ptr (u64); diff --git a/source/m3_info.c b/source/m3_info.c index 533f63c..ca126d4 100644 --- a/source/m3_info.c +++ b/source/m3_info.c @@ -123,7 +123,7 @@ cstr_t SPrintFunctionArgList (IM3Function i_function, m3stack_t i_sp) } -OpInfo FindOperationInfo (IM3Operation i_operation) +OpInfo find_operation_info (IM3Operation i_operation) { OpInfo opInfo; M3_INIT(opInfo); @@ -245,7 +245,7 @@ void dump_code_page (IM3CodePage i_codePage, pc_t i_startPC) if (op) { - OpInfo i = FindOperationInfo (op); + OpInfo i = find_operation_info (op); if (i.info) { @@ -342,4 +342,46 @@ void dump_type_stack (IM3Compilation o) } +const char * GetOpcodeIndentionString (IM3Compilation o) +{ + i32 blockDepth = o->block.depth + 1; + + if (blockDepth < 0) + blockDepth = 0; + + static const char * s_spaces = "......................................................................................."; + const char * indent = s_spaces + strlen (s_spaces); + indent -= (blockDepth * 2); + if (indent < s_spaces) + indent = s_spaces; + + return indent; +} + + +const char * get_indention_string (IM3Compilation o) +{ + o->block.depth += 4; + const char *indent = GetOpcodeIndentionString (o); + o->block.depth -= 4; + + return indent; +} + + +void log_opcode (IM3Compilation o, u8 i_opcode) +{ + if (i_opcode == c_waOp_end or i_opcode == c_waOp_else) + o->block.depth--; + +# ifdef DEBUG + m3log (compile, "%4d | 0x%02x %s %s", o->numOpcodes++, i_opcode, GetOpcodeIndentionString (o), c_operations [i_opcode].name); +# else + m3log (compile, "%4d | 0x%02x %s", o->numOpcodes++, i_opcode, GetOpcodeIndentionString (o)); +# endif + + if (i_opcode == c_waOp_end or i_opcode == c_waOp_else) + o->block.depth++; +} + diff --git a/source/m3_info.h b/source/m3_info.h index 115aa1d..6412ff2 100644 --- a/source/m3_info.h +++ b/source/m3_info.h @@ -20,10 +20,11 @@ typedef struct OpInfo OpInfo; -OpInfo FindOperationInfo (IM3Operation i_operation); +OpInfo find_operation_info (IM3Operation i_operation); - -void dump_type_stack (IM3Compilation o); +void dump_type_stack (IM3Compilation o); +void log_opcode (IM3Compilation o, u8 i_opcode); +const char * get_indention_string (IM3Compilation o); #endif /* m3_info_h */ diff --git a/source/m3_parse.c b/source/m3_parse.c index e620cb9..05e1bc3 100644 --- a/source/m3_parse.c +++ b/source/m3_parse.c @@ -528,7 +528,7 @@ M3Result ParseModuleSection (M3Module * o_module, u8 i_sectionType, bytes_t i_ } -M3Result m3_ParseModule (IM3Module * o_module, cbytes_t i_bytes, u32 i_numBytes) +M3Result m3_ParseModule (IM3Environment i_environment, IM3Module * o_module, cbytes_t i_bytes, u32 i_numBytes) { M3Result result;