MemGrow fixes for op_Call & op_CallIndirect; placeholder IM3Environment API addition

extensions
Steven Massey 5 years ago
parent 16e62cd360
commit e11b25a202

@ -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;
}

@ -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 <IM3Module>

@ -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 ()
};

@ -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
{

@ -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)
{

@ -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;
}

@ -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;

@ -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

@ -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);

@ -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++;
}

@ -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 */

@ -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;

Loading…
Cancel
Save