diff --git a/src/m3_compile.c b/src/m3_compile.c index c14e0e0..06446ef 100644 --- a/src/m3_compile.c +++ b/src/m3_compile.c @@ -292,7 +292,8 @@ M3Result AllocateSlots (IM3Compilation o, u16 * o_slot, u8 i_type) M3Result AllocateConstantSlots (IM3Compilation o, u16 * o_slot, u8 i_type) { - return AllocateSlotsWithinRange (o, o_slot, i_type, o->slotFirstConstIndex, o->slotFirstDynamicIndex); + u16 maxTableIndex = o->slotFirstConstIndex + d_m3MaxConstantTableSize; + return AllocateSlotsWithinRange (o, o_slot, i_type, o->slotFirstConstIndex, M3_MIN(o->slotFirstDynamicIndex, maxTableIndex)); } @@ -1116,10 +1117,10 @@ _ (Read_u8 (& opcode, & o->wasm, o->wasmEnd)); m3log (compile, d_i //printf("Extended opcode: 0x%x\n", i_opcode); - const M3OpInfo* opinfo = GetOpInfo (i_opcode); - _throwif (m3Err_unknownOpcode, not opinfo); + IM3OpInfo opInfo = GetOpInfo (i_opcode); + _throwif (m3Err_unknownOpcode, not opInfo); - M3Compiler compiler = opinfo->compiler; + M3Compiler compiler = opInfo->compiler; _throwif (m3Err_noCompiler, not compiler); _ ((* compiler) (o, i_opcode)); @@ -2011,9 +2012,10 @@ M3Result Compile_Operator (IM3Compilation o, m3opcode_t i_opcode) { M3Result result; - const M3OpInfo * op = GetOpInfo(i_opcode); + IM3OpInfo opInfo = GetOpInfo (i_opcode); + _throwif (m3Err_unknownOpcode, not opInfo); - IM3Operation operation; + IM3Operation op; // This preserve is for for FP compare operations. // either need additional slot destination operations or the @@ -2021,64 +2023,64 @@ M3Result Compile_Operator (IM3Compilation o, m3opcode_t i_opcode) // moving out the way might be the optimal solution most often? // otherwise, the _r0 reg can get buried down in the stack // and be idle & wasted for a moment. - if (IsFpType (GetStackTopType (o)) and IsIntType (op->type)) + if (IsFpType (GetStackTopType (o)) and IsIntType (opInfo->type)) { -_ (PreserveRegisterIfOccupied (o, op->type)); +_ (PreserveRegisterIfOccupied (o, opInfo->type)); } - if (op->stackOffset == 0) + if (opInfo->stackOffset == 0) { if (IsStackTopInRegister (o)) { - operation = op->operations [0]; // _s + op = opInfo->operations [0]; // _s } else { -_ (PreserveRegisterIfOccupied (o, op->type)); - operation = op->operations [1]; // _r +_ (PreserveRegisterIfOccupied (o, opInfo->type)); + op = opInfo->operations [1]; // _r } } else { if (IsStackTopInRegister (o)) { - operation = op->operations [0]; // _rs + op = opInfo->operations [0]; // _rs if (IsStackTopMinus1InRegister (o)) { d_m3Assert (i_opcode == 0x38 or i_opcode == 0x39); - operation = op->operations [3]; // _rr for fp.store + op = opInfo->operations [3]; // _rr for fp.store } } else if (IsStackTopMinus1InRegister (o)) { - operation = op->operations [1]; // _sr + op = opInfo->operations [1]; // _sr - if (not operation) // must be commutative, then - operation = op->operations [0]; + if (not op) // must be commutative, then + op = opInfo->operations [0]; } else { -_ (PreserveRegisterIfOccupied (o, op->type)); // _ss - operation = op->operations [2]; +_ (PreserveRegisterIfOccupied (o, opInfo->type)); // _ss + op = opInfo->operations [2]; } } - if (operation) + if (op) { -_ (EmitOp (o, operation)); +_ (EmitOp (o, op)); _ (EmitSlotNumOfStackTopAndPop (o)); - if (op->stackOffset < 0) + if (opInfo->stackOffset < 0) _ (EmitSlotNumOfStackTopAndPop (o)); - if (op->type != c_m3Type_none) -_ (PushRegister (o, op->type)); + if (opInfo->type != c_m3Type_none) +_ (PushRegister (o, opInfo->type)); } else { # ifdef DEBUG - result = ErrorCompile ("no operation found for opcode", o, "'%s'", op->name); + result = ErrorCompile ("no operation found for opcode", o, "'%s'", opInfo->name); # else result = ErrorCompile ("no operation found for opcode", o, "%x", i_opcode); # endif @@ -2093,7 +2095,9 @@ M3Result Compile_Convert (IM3Compilation o, m3opcode_t i_opcode) { M3Result result = m3Err_none; - const M3OpInfo * opInfo = GetOpInfo(i_opcode); +_try { + IM3OpInfo opInfo = GetOpInfo (i_opcode); + _throwif (m3Err_unknownOpcode, not opInfo); bool destInSlot = IsRegisterTypeAllocated (o, opInfo->type); bool sourceInSlot = IsStackTopInSlot (o); @@ -2108,6 +2112,7 @@ _ (PushAllocatedSlotAndEmit (o, opInfo->type)) else _ (PushRegister (o, opInfo->type)) +} _catch: return result; } @@ -2122,9 +2127,10 @@ _try { _ (ReadLEB_u32 (& alignHint, & o->wasm, o->wasmEnd)); _ (ReadLEB_u32 (& memoryOffset, & o->wasm, o->wasmEnd)); m3log (compile, d_indent " (offset = %d)", get_indention_string (o), memoryOffset); - const M3OpInfo * op = GetOpInfo(i_opcode); + IM3OpInfo opInfo = GetOpInfo (i_opcode); + _throwif (m3Err_unknownOpcode, not opInfo); - if (IsFpType (op->type)) + if (IsFpType (opInfo->type)) _ (PreserveRegisterIfOccupied (o, c_m3Type_f64)); _ (Compile_Operator (o, i_opcode)); @@ -2439,7 +2445,8 @@ const M3OpInfo c_operationsFC [] = # endif }; -const M3OpInfo* GetOpInfo (m3opcode_t opcode) + +IM3OpInfo GetOpInfo (m3opcode_t opcode) { switch (opcode >> 8) { case 0x00: @@ -2480,7 +2487,7 @@ _ (Read_opcode (& opcode, & o->wasm, o->wasmEnd)); log_opco } } - IM3OpInfo opinfo = GetOpInfo(opcode); + IM3OpInfo opinfo = GetOpInfo (opcode); if (opinfo == NULL) _throw (ErrorCompile (m3Err_unknownOpcode, o, "opcode '%x' not available", opcode)); @@ -2648,6 +2655,7 @@ M3Result CompileLocals (IM3Compilation o) { M3Result result; + u32 numLocals = 0; u32 numLocalBlocks; _ (ReadLEB_u32 (& numLocalBlocks, & o->wasm, o->wasmEnd)); @@ -2660,11 +2668,14 @@ _ (ReadLEB_u32 (& numLocalBlocks, & o->wasm, o->wasmEnd)); _ (ReadLEB_u32 (& varCount, & o->wasm, o->wasmEnd)); _ (ReadLEB_i7 (& waType, & o->wasm, o->wasmEnd)); _ (NormalizeType (& localType, waType)); - m3log (compile, "pushing locals. count: %d; type: %s", varCount, c_waTypes [localType]); + numLocals += varCount; m3log (compile, "pushing locals. count: %d; type: %s", varCount, c_waTypes [localType]); while (varCount--) _ (PushAllocatedSlot (o, localType)); } + if (o->function) + o->function->numLocals = numLocals; + _catch: return result; } diff --git a/src/m3_compile.h b/src/m3_compile.h index fa5f7a6..89fa201 100644 --- a/src/m3_compile.h +++ b/src/m3_compile.h @@ -140,7 +140,7 @@ M3OpInfo; typedef const M3OpInfo * IM3OpInfo; -extern const M3OpInfo* GetOpInfo(m3opcode_t opcode); +IM3OpInfo GetOpInfo (m3opcode_t opcode); // TODO: This helper should be removed, when MultiValue is implemented static inline diff --git a/src/m3_config.h b/src/m3_config.h index 8194572..6a204a3 100644 --- a/src/m3_config.h +++ b/src/m3_config.h @@ -33,7 +33,7 @@ # endif # ifndef d_m3MaxConstantTableSize -# define d_m3MaxConstantTableSize 1024 +# define d_m3MaxConstantTableSize 120 # endif # ifndef d_m3MaxDuplicateFunctionImpl diff --git a/src/m3_config_platforms.h b/src/m3_config_platforms.h index 57b24d2..b3b8e8b 100644 --- a/src/m3_config_platforms.h +++ b/src/m3_config_platforms.h @@ -71,7 +71,7 @@ # define M3_NO_UBSAN # else # define M3_WEAK __attribute__((weak)) -# define M3_NO_UBSAN __attribute__((no_sanitize("undefined"))) +# define M3_NO_UBSAN //__attribute__((no_sanitize("undefined"))) # endif # ifndef M3_MIN diff --git a/src/m3_core.h b/src/m3_core.h index 745a24b..86c5853 100644 --- a/src/m3_core.h +++ b/src/m3_core.h @@ -245,7 +245,7 @@ M3Result ReadLEB_i64 (i64 * o_value, bytes_t * io_bytes, cbytes_t M3Result Read_utf8 (cstr_t * o_utf8, bytes_t * io_bytes, cbytes_t i_end); cstr_t SPrintValue (void * i_value, u8 i_type); -size_t SPrintArg (char * o_string, size_t i_stringBufferSize, m3stack_t i_sp, u8 i_type); +size_t SPrintArg (char * o_string, size_t i_stringBufferSize, voidptr_t i_sp, u8 i_type); void ReportError (IM3Runtime io_runtime, IM3Module i_module, IM3Function i_function, ccstr_t i_errorMessage, ccstr_t i_file, u32 i_lineNum); diff --git a/src/m3_env.c b/src/m3_env.c index 6389810..3a159fd 100644 --- a/src/m3_env.c +++ b/src/m3_env.c @@ -107,6 +107,7 @@ void Environment_AddFuncType (IM3Environment i_environment, IM3FuncType * io_f * io_funcType = newType; } + IM3CodePage RemoveCodePageOfCapacity (M3CodePage ** io_list, u32 i_minimumLineCount) { IM3CodePage prev = NULL; @@ -194,6 +195,7 @@ void * m3_GetUserData (IM3Runtime i_runtime) return i_runtime ? i_runtime->userdata : NULL; } + void * ForEachModule (IM3Runtime i_runtime, ModuleVisitor i_visitor, void * i_info) { void * r = NULL; @@ -444,6 +446,8 @@ M3Result InitDataSegments (M3Memory * io_memory, IM3Module io_module) { M3Result result = m3Err_none; + _throwif ("unallocated linear memory", !(io_memory->mallocated)); + for (u32 i = 0; i < io_module->numDataSegments; ++i) { M3DataSegment * segment = & io_module->dataSegments [i]; @@ -454,8 +458,6 @@ _ (EvaluateExpression (io_module, & segmentOffset, c_m3Type_i32, & start, m3log (runtime, "loading data segment: %d; size: %d; offset: %d", i, segment->size, segmentOffset); - _throwif ("unallocated linear memory", !(io_memory->mallocated)); - if (segmentOffset >= 0 && (size_t)(segmentOffset) + segment->size <= io_memory->mallocated->length) { u8 * dest = m3MemData (io_memory->mallocated) + segmentOffset; @@ -490,14 +492,18 @@ _ (EvaluateExpression (io_module, & offset, c_m3Type_i32, & bytes, end u32 numElements; _ (ReadLEB_u32 (& numElements, & bytes, end)); - size_t endElement = (size_t)(numElements) + offset; + size_t endElement = (size_t) numElements + offset; _throwif ("table overflow", endElement > d_m3MaxSaneTableSize); - io_module->table0 = m3_ReallocArray (IM3Function, io_module->table0, endElement, io_module->table0Size); + // is there any requirement that elements must be in increasing sequence? + // make sure the table isn't shrunk. + if (endElement > io_module->table0Size) + { + io_module->table0 = m3_ReallocArray (IM3Function, io_module->table0, endElement, io_module->table0Size); + io_module->table0Size = (u32) endElement; + } _throwifnull(io_module->table0); - io_module->table0Size = (u32) endElement; - for (u32 e = 0; e < numElements; ++e) { u32 functionIndex; @@ -513,6 +519,22 @@ _ (ReadLEB_u32 (& functionIndex, & bytes, end)); _catch: return result; } +M3Result m3_CompileModule (IM3Module io_module) +{ + M3Result result = m3Err_none; + + for (u32 i = 0; i < io_module->numFunctions; ++i) + { + IM3Function f = & io_module->functions [i]; + if (f->wasm and not f->compiled) + { +_ (CompileFunction (f)); + } + } + + _catch: return result; +} + M3Result m3_RunStart (IM3Module io_module) { #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION @@ -779,6 +801,16 @@ M3Result m3_CallV (IM3Function i_function, ...) return r; } +static +void ReportNativeStackUsage () +{ +# if d_m3LogNativeStack + int stackUsed = m3StackGetMax(); + fprintf (stderr, "Native stack used: %d\n", stackUsed); +# endif +} + + M3Result m3_CallVL (IM3Function i_function, va_list i_args) { IM3Runtime runtime = i_function->module->runtime; @@ -808,14 +840,10 @@ M3Result m3_CallVL (IM3Function i_function, va_list i_args) } m3StackCheckInit(); M3Result r = (M3Result) Call (i_function->compiled, (m3stack_t)(runtime->stack), runtime->memory.mallocated, d_m3OpDefaultArgs); + ReportNativeStackUsage (); runtime->lastCalled = r ? NULL : i_function; -#if d_m3LogNativeStack - int stackUsed = m3StackGetMax(); - fprintf (stderr, "Native stack used: %d\n", stackUsed); -#endif - return r; } @@ -852,13 +880,10 @@ M3Result m3_Call (IM3Function i_function, uint32_t i_argc, const void * i_argp m3StackCheckInit(); M3Result r = (M3Result) Call (i_function->compiled, (m3stack_t)(runtime->stack), runtime->memory.mallocated, d_m3OpDefaultArgs); + ReportNativeStackUsage (); runtime->lastCalled = r ? NULL : i_function; -#if d_m3LogNativeStack - int stackUsed = m3StackGetMax(); - fprintf (stderr, "Native stack used: %d\n", stackUsed); -#endif return r; } @@ -896,14 +921,10 @@ M3Result m3_CallArgv (IM3Function i_function, uint32_t i_argc, const char * i_ m3StackCheckInit(); M3Result r = (M3Result) Call (i_function->compiled, (m3stack_t)(runtime->stack), runtime->memory.mallocated, d_m3OpDefaultArgs); + ReportNativeStackUsage (); runtime->lastCalled = r ? NULL : i_function; -#if d_m3LogNativeStack - int stackUsed = m3StackGetMax(); - fprintf (stderr, "Native stack used: %d\n", stackUsed); -#endif - return r; } @@ -1090,8 +1111,7 @@ void m3_ResetErrorInfo (IM3Runtime i_runtime) uint8_t * m3_GetMemory (IM3Runtime i_runtime, uint32_t * o_memorySizeInBytes, uint32_t i_memoryIndex) { - uint8_t * memory = NULL; - d_m3Assert (i_memoryIndex == 0); + uint8_t * memory = NULL; d_m3Assert (i_memoryIndex == 0); if (i_runtime) { @@ -1107,11 +1127,13 @@ uint8_t * m3_GetMemory (IM3Runtime i_runtime, uint32_t * o_memorySizeInBytes, return memory; } + uint32_t m3_GetMemorySize (IM3Runtime i_runtime) { return i_runtime->memory.mallocated->length; } + M3BacktraceInfo * m3_GetBacktrace (IM3Runtime i_runtime) { # if d_m3RecordBacktraces diff --git a/src/m3_env.h b/src/m3_env.h index 3b98951..15e8bde 100644 --- a/src/m3_env.h +++ b/src/m3_env.h @@ -41,7 +41,7 @@ typedef M3Memory * IM3Memory; typedef struct M3DataSegment { - const u8 * initExpr; // wasm code + const u8 * initExpr; // wasm code const u8 * data; u32 initExprSize; diff --git a/src/m3_exec.h b/src/m3_exec.h index a2b1d4e..1ebeead 100644 --- a/src/m3_exec.h +++ b/src/m3_exec.h @@ -781,7 +781,7 @@ d_m3Op (Entry) #if d_m3SkipStackCheck if (true) #else - if (LIKELY((void *)((m3slot_t *) _sp + function->maxStackSlots) < _mem->maxStack)) + if (LIKELY ((void *) (_sp + function->maxStackSlots) < _mem->maxStack)) #endif { #if defined(DEBUG) @@ -798,7 +798,7 @@ d_m3Op (Entry) } #if d_m3EnableStrace >= 2 - d_m3TracePrint("%s %s {", m3_GetFunctionName(function), SPrintFunctionArgList (function, _sp)); + d_m3TracePrint("%s %s {", m3_GetFunctionName(function), SPrintFunctionArgList (function, _sp + function->numRetSlots)); trace_rt->callDepth++; #endif diff --git a/src/m3_function.h b/src/m3_function.h index c4b2504..e25b3f8 100644 --- a/src/m3_function.h +++ b/src/m3_function.h @@ -47,22 +47,22 @@ typedef struct M3Function bytes_t wasm; bytes_t wasmEnd; - u16 numNames; // maximum of d_m3MaxDuplicateFunctionImpl cstr_t names[d_m3MaxDuplicateFunctionImpl]; + u16 numNames; // maximum of d_m3MaxDuplicateFunctionImpl IM3FuncType funcType; pc_t compiled; -#if (d_m3EnableCodePageRefCounting) +# if (d_m3EnableCodePageRefCounting) IM3CodePage * codePageRefs; // array of all pages used u32 numCodePageRefs; -#endif +# endif -#if defined (DEBUG) +# if defined (DEBUG) u32 hits; u32 index; -#endif +# endif u16 maxStackSlots; diff --git a/src/m3_info.c b/src/m3_info.c index 53710db..2364296 100644 --- a/src/m3_info.c +++ b/src/m3_info.c @@ -100,7 +100,7 @@ cstr_t SPrintFuncTypeSignature (IM3FuncType i_funcType) } -size_t SPrintArg (char * o_string, size_t i_stringBufferSize, m3stack_t i_sp, u8 i_type) +size_t SPrintArg (char * o_string, size_t i_stringBufferSize, voidptr_t i_sp, u8 i_type) { int len = 0; @@ -142,7 +142,7 @@ cstr_t SPrintFunctionArgList (IM3Function i_function, m3stack_t i_sp) ret = snprintf (s, e-s, "("); s += M3_MAX (0, ret); - m3stack_t argSp = i_sp; + u64 * argSp = (u64 *) i_sp; IM3FuncType funcType = i_function->funcType; if (funcType) diff --git a/src/m3_module.c b/src/m3_module.c index f96834a..d6ba8d8 100644 --- a/src/m3_module.c +++ b/src/m3_module.c @@ -72,15 +72,18 @@ M3Result Module_AddFunction (IM3Module io_module, u32 i_typeIndex, IM3ImportIn M3Result result = m3Err_none; _try { + u32 index = io_module->numFunctions++; io_module->functions = m3_ReallocArray (M3Function, io_module->functions, io_module->numFunctions, index); - _throwifnull(io_module->functions); - _throwif("type sig index out of bounds", i_typeIndex >= io_module->numFuncTypes); + + _throwifnull (io_module->functions); + _throwif ("type sig index out of bounds", i_typeIndex >= io_module->numFuncTypes); IM3FuncType ft = io_module->funcTypes [i_typeIndex]; IM3Function func = Module_GetFunction (io_module, index); func->funcType = ft; + # ifdef DEBUG func->index = index; # endif diff --git a/src/m3_parse.c b/src/m3_parse.c index ed681f5..00e01b0 100644 --- a/src/m3_parse.c +++ b/src/m3_parse.c @@ -52,7 +52,7 @@ _ (ReadLEB_u32 (& numTypes, & i_bytes, i_end)); { // table of IM3FuncType (that point to the actual M3FuncType struct in the Environment) io_module->funcTypes = m3_AllocArray (IM3FuncType, numTypes); - _throwifnull(io_module->funcTypes); + _throwifnull (io_module->funcTypes); io_module->numFuncTypes = numTypes; for (u32 i = 0; i < numTypes; ++i) @@ -110,6 +110,7 @@ _ (NormalizeType (& retType, wasmType)); if (result) { m3_Free (ftype); + // FIX: M3FuncTypes in the table are leaked m3_Free (io_module->funcTypes); io_module->numFuncTypes = 0; } @@ -346,6 +347,7 @@ _ (ReadLEB_u32 (& size, & i_bytes, i_end)); if (i_bytes <= i_end) { + /* u32 numLocalBlocks; _ (ReadLEB_u32 (& numLocalBlocks, & ptr, i_end)); m3log (parse, " code size: %-4d", size); @@ -363,6 +365,7 @@ _ (NormalizeType (& normalType, wasmType)); numLocals += varCount; m3log (parse, " %2d locals; type: '%s'", varCount, c_waTypes [normalType]); } + */ IM3Function func = Module_GetFunction (io_module, f + io_module->numFuncImports); @@ -370,7 +373,7 @@ _ (NormalizeType (& normalType, wasmType)); func->wasm = start; func->wasmEnd = i_bytes; //func->ownsWasmCode = io_module->hasWasmCodeCopy; - func->numLocals = numLocals; +// func->numLocals = numLocals; } else _throw (m3Err_wasmSectionOverrun); } @@ -574,12 +577,12 @@ M3Result ParseModuleSection (M3Module * o_module, u8 i_sectionType, bytes_t i_ M3Result m3_ParseModule (IM3Environment i_environment, IM3Module * o_module, cbytes_t i_bytes, u32 i_numBytes) { - M3Result result; + M3Result result; m3log (parse, "load module: %d bytes", i_numBytes); IM3Module module; _try { module = m3_AllocStruct (M3Module); - _throwifnull(module); + _throwifnull (module); module->name = ".unnamed"; m3log (parse, "load module: %d bytes", i_numBytes); module->startFunction = -1; //module->hasWasmCodeCopy = false; diff --git a/src/wasm3.h b/src/wasm3.h index 29c18ac..30f00df 100644 --- a/src/wasm3.h +++ b/src/wasm3.h @@ -18,7 +18,7 @@ #include #include -#include +#include "wasm3_defs.h" #if defined(__cplusplus) extern "C" { @@ -229,6 +229,9 @@ d_m3ErrorConst (trapStackOverflow, "[trap] stack overflow") // LoadModule transfers ownership of a module to the runtime. Do not free modules once successfully loaded into the runtime M3Result m3_LoadModule (IM3Runtime io_runtime, IM3Module io_module); + // Optional, compiles all functions in the module + M3Result m3_CompileModule (IM3Module io_module); + // Calling m3_RunStart is optional M3Result m3_RunStart (IM3Module i_module);