From 433e7d71a3d58cdb8f8450d5b4a34b6c6e81b35f Mon Sep 17 00:00:00 2001 From: Steven Massey Date: Sat, 15 May 2021 15:19:45 -0700 Subject: [PATCH] m3Ext_ReserveFunctions --- source/extensions/m3_extensions.c | 109 +++++++++++++++++++++--------- source/extensions/wasm3_ext.h | 29 +++++--- source/m3_config.h | 3 + source/m3_env.c | 12 ++-- source/m3_env.h | 6 ++ source/m3_function.h | 19 +++--- source/m3_module.c | 52 ++++++++++++-- source/m3_parse.c | 17 ++--- test/internal/m3_test.c | 6 +- 9 files changed, 180 insertions(+), 73 deletions(-) diff --git a/source/extensions/m3_extensions.c b/source/extensions/m3_extensions.c index c63109a..df632cb 100644 --- a/source/extensions/m3_extensions.c +++ b/source/extensions/m3_extensions.c @@ -12,30 +12,52 @@ #include "m3_exception.h" -IM3Module m3_NewModule (IM3Environment i_environment) -{ - IM3Module module = m3_AllocStruct (M3Module); - if (module) - { - module->name = ".unnamed"; - module->startFunction = -1; - module->environment = i_environment; +M3Result m3Ext_ReserveFunctions (IM3Module i_module, + uint32_t i_numFunctions) +{ + M3Result result = m3Err_none; + + if (i_module) + { d_m3Assert (i_module->table0Size == 0); + if (i_module->table0Size == 0) + { + i_module->numReservedFunctions = i_numFunctions; + + u32 totalFunctions = i_module->numFunctions + i_numFunctions; + + i_module->functions = m3_ReallocArray (M3Function, i_module->functions, totalFunctions, i_module->numFunctions); + _throwifnull (i_module->functions); + } + else _throw ("ReserveFunctions must come before LoadModule"); + } + else _throw (m3Err_nullArgument); + + _catch: + return result; +} - module->wasmStart = NULL; - module->wasmEnd = NULL; - } - return module; +i32 Module_HasFuncType (IM3Module i_module, IM3FuncType i_funcType) +{ + if (i_module->funcTypes) + { + for (u32 i = 0; i < i_module->numFuncTypes; ++i) + { + if (AreFuncTypesEqual (i_module->funcTypes [i], i_funcType)) + return i; + } + } + + return -1; } - -M3Result m3_InjectFunction (IM3Module i_module, - int32_t * io_functionIndex, - const char * const i_signature, - const uint8_t * const i_wasmBytes, - bool i_doCompilation) +M3Result m3Ext_InjectFunction (IM3Module i_module, + int32_t * io_functionIndex, + const char * const i_signature, + const uint8_t * const i_wasmBytes, + bool i_doCompilation) { M3Result result = m3Err_none; d_m3Assert (io_functionIndex); @@ -63,15 +85,19 @@ _ (ReadLEB_u32 (& size, & bytes, end)); } else { - // add slot to function type table in the module - u32 funcTypeIndex = i_module->numFuncTypes++; - i_module->funcTypes = m3_ReallocArray (IM3FuncType, i_module->funcTypes, i_module->numFuncTypes, funcTypeIndex); - _throwifnull (i_module->funcTypes); - - // add functype object to the environment - Environment_AddFuncType (i_module->environment, & ftype); - i_module->funcTypes [funcTypeIndex] = ftype; - ftype = NULL; // prevent freeing below + i32 funcTypeIndex = Module_HasFuncType (i_module, ftype); + if (funcTypeIndex < 0) + { + // add slot to function type table in the module + funcTypeIndex = i_module->numFuncTypes++; + i_module->funcTypes = m3_ReallocArray (IM3FuncType, i_module->funcTypes, i_module->numFuncTypes, funcTypeIndex); + _throwifnull (i_module->funcTypes); + + // add functype object to the environment + Environment_AddFuncType (i_module->environment, & ftype); + i_module->funcTypes [funcTypeIndex] = ftype; + ftype = NULL; // prevent freeing below + } index = (i32) i_module->numFunctions; _ (Module_AddFunction (i_module, funcTypeIndex, NULL)); @@ -106,7 +132,7 @@ _ (CompileFunction (function)); } -M3Result m3_AddFunctionToTable (IM3Function i_function, +M3Result m3Ext_AddFunctionToTable (IM3Function i_function, uint32_t * o_elementIndex, uint32_t i_tableIndex) { @@ -118,12 +144,13 @@ M3Result m3_AddFunctionToTable (IM3Function i_function, if (module) { - u32 newTableSize = module->table0Size + 1; - module->table0 = m3_ReallocArray (IM3Function, module->table0, newTableSize, module->table0Size); + u32 previousSize = module->table0Size; + u32 newTableSize = previousSize + 1; + module->table0 = m3_ReallocArray (IM3Function, module->table0, newTableSize, previousSize); _throwifnull (module->table0); - * o_elementIndex = module->table0Size; - module->table0 [* o_elementIndex] = i_function; + * o_elementIndex = previousSize; + module->table0 [previousSize] = i_function; module->table0Size = newTableSize; } else _throw ("null module"); @@ -140,6 +167,7 @@ IM3Function m3_GetFunctionByIndex (IM3Module i_module, uint32_t i_index) return Module_GetFunction (i_module, i_index); } + M3Result m3_GetFunctionIndex (IM3Function i_function, uint32_t * o_index) { @@ -167,3 +195,20 @@ M3Result m3_GetDataSegmentOffset (IM3Module i_module, _catch: return result; } + + +M3Result m3_RegisterCustomOpcode (IM3Module i_module, + uint16_t i_opcode, + uint8_t i_numImmediates, + IM3Operation i_operation) +{ + M3Result result = m3Err_none; d_m3Assert (i_module); + + if (i_module) + { + + } + else _throw (m3Err_nullArgument); + + _catch: return result; +} diff --git a/source/extensions/wasm3_ext.h b/source/extensions/wasm3_ext.h index 6bf4fc2..822f91b 100644 --- a/source/extensions/wasm3_ext.h +++ b/source/extensions/wasm3_ext.h @@ -10,36 +10,42 @@ #ifndef wasm3_ext_h #define wasm3_ext_h -#include "wasm3.h" -//#include "m3_exec_defs.h" +#include "m3_exec_defs.h" + #include #if defined(__cplusplus) extern "C" { #endif - //------------------------------------------------------------------------------------------------------------------------------- // API extensions +//------------------------------------------------------------------------------------------------------------------------------- +/* + These extensions allow for unconventional uses of Wasm3 -- mainly dynamic modification of modules to inject new Wasm + functions during runtime. +*/ //------------------------------------------------------------------------------------------------------------------------------- // Creates an empty module. - IM3Module m3_NewModule (IM3Environment i_environment); + IM3Module m3Ext_NewModule (IM3Environment i_environment); + // ReserveFunctions must be called prior to LoadModule. This reserves extra empty function slots that InjectFunction + // can rely upon. + M3Result m3Ext_ReserveFunctions (IM3Module i_module, + uint32_t i_numFunctions); // To append a new function, set io_functionIndex to negative. On return, the new function index will be set. // To overwrite an existing function, set io_functionIndex to the desired element. i_signature must match the existing - // function signature. - - // ** InjectFunction invalidates any outstanding IM3Function pointers - M3Result m3_InjectFunction (IM3Module i_module, + // function signature. TODO: failure result is? + M3Result m3Ext_InjectFunction (IM3Module i_module, int32_t * io_functionIndex, // const char * const i_name, const char * const i_signature, const uint8_t * const i_wasmBytes, // i_wasmBytes is copied bool i_doCompilation); - M3Result m3_AddFunctionToTable (IM3Function i_function, + M3Result m3Ext_AddFunctionToTable (IM3Function i_function, uint32_t * o_elementIndex, uint32_t i_tableIndex); // i_tableIndex must be zero @@ -55,12 +61,13 @@ extern "C" { //------------------------------------------------------------------------------------------------------------------------------- -#if 0 M3Result m3_RegisterCustomOpcode (IM3Module i_module, uint16_t i_opcode, uint8_t i_numImmediates, IM3Operation i_operation); -#endif + +//------------------------------------------------------------------------------------------------------------------------------- + #if 0 M3Result m3_SetStackGlobalIndex (IM3Module io_module, uint32_t i_index); diff --git a/source/m3_config.h b/source/m3_config.h index 6a204a3..6b77db8 100644 --- a/source/m3_config.h +++ b/source/m3_config.h @@ -73,6 +73,9 @@ # define d_m3EnableExceptionBreakpoint 0 // see m3_exception.h # endif +# ifndef d_m3EnableExtensions +# define d_m3EnableExtensions 1 // enables the specialized APIs in wasm3_ext.h +# endif // profiling and tracing ------------------------------------------------------ diff --git a/source/m3_env.c b/source/m3_env.c index 4dc66a6..20665bc 100644 --- a/source/m3_env.c +++ b/source/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; @@ -499,14 +500,17 @@ _ (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); + // i don't find any requirement that elements must be in increasing sequence. so 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; diff --git a/source/m3_env.h b/source/m3_env.h index a8b691b..e11c6e4 100644 --- a/source/m3_env.h +++ b/source/m3_env.h @@ -97,6 +97,10 @@ typedef struct M3Module u32 numFunctions; M3Function * functions; +# if d_m3EnableExtensions + u32 numReservedFunctions; +# endif + i32 startFunction; u32 numDataSegments; @@ -122,6 +126,8 @@ typedef struct M3Module } M3Module; +IM3Module m3_NewModule (IM3Environment i_environment); + M3Result Module_AddGlobal (IM3Module io_module, IM3Global * o_global, u8 i_type, bool i_mutable, bool i_isImported); M3Result Module_AddFunction (IM3Module io_module, u32 i_typeIndex, IM3ImportInfo i_importInfo /* can be null */); diff --git a/source/m3_function.h b/source/m3_function.h index 1936a64..a901faa 100644 --- a/source/m3_function.h +++ b/source/m3_function.h @@ -47,23 +47,26 @@ 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; -#endif +# endif + +# if defined (DEBUG) || d_m3EnableExtensions u32 index; - +# endif + u16 maxStackSlots; u16 numRetSlots; @@ -74,7 +77,7 @@ typedef struct M3Function bool ownsWasmCode; - u16 numConstantBytes; + u16 numConstantBytes; void * constants; } M3Function; diff --git a/source/m3_module.c b/source/m3_module.c index 26a31ba..ebe853e 100644 --- a/source/m3_module.c +++ b/source/m3_module.c @@ -9,6 +9,30 @@ #include "m3_exception.h" + +IM3Module m3_NewModule (IM3Environment i_environment) +{ + IM3Module module = m3_AllocStruct (M3Module); + + if (module) + { + module->name = ".unnamed"; + module->startFunction = -1; + module->environment = i_environment; + + module->hasWasmCodeCopy = false; + module->wasmStart = NULL; + module->wasmEnd = NULL; + +# if d_m3EnableExtensions + module->numReservedFunctions = 0; +# endif + } + + return module; +} + + void Module_FreeFunctions (IM3Module i_module) { for (u32 i = 0; i < i_module->numFunctions; ++i) @@ -77,18 +101,33 @@ 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); + + u32 index = io_module->numFunctions++; + +# if d_m3EnableExtensions + if (io_module->runtime) // module loaded, so this must be an InjectFunction call + { + if (io_module->numReservedFunctions) + { + io_module->numReservedFunctions--; + } + else _throw ("reserved function capacity exceeded"); + } + else +# endif + 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); IM3FuncType ft = io_module->funcTypes [i_typeIndex]; IM3Function func = Module_GetFunction (io_module, index); func->funcType = ft; -# ifdef DEBUG + +# if defined (DEBUG) || d_m3EnableExtensions func->index = index; -# endif +# endif if (i_importInfo and func->numNames == 0) { @@ -103,6 +142,7 @@ _try { return result; } + void Module_GenerateNames (IM3Module i_module) { for (u32 i = 0; i < i_module->numFunctions; ++i) diff --git a/source/m3_parse.c b/source/m3_parse.c index 2cc1d52..401e3de 100644 --- a/source/m3_parse.c +++ b/source/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; } @@ -576,17 +577,13 @@ 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, bool i_copyBytes) { - M3Result result; + M3Result result; m3log (parse, "load module: %d bytes", i_numBytes); - IM3Module module; -_try { - module = m3_AllocStruct (M3Module); - _throwifnull(module); - module->name = ".unnamed"; m3log (parse, "load module: %d bytes", i_numBytes); - module->startFunction = -1; - module->environment = i_environment; - module->hasWasmCodeCopy = i_copyBytes; + IM3Module module = m3_NewModule (i_environment); +_try { + _throwifnull (module); + const u8 * pos = i_bytes; if (i_copyBytes) diff --git a/test/internal/m3_test.c b/test/internal/m3_test.c index 0709d88..dce863f 100644 --- a/test/internal/m3_test.c +++ b/test/internal/m3_test.c @@ -30,6 +30,8 @@ bool RunTest (int i_argc, const char * i_argv [], cstr_t i_name) int main (int argc, const char * argv []) { +// m3_PrintM3Info (); + Test (signatures) { M3Result result; @@ -158,13 +160,13 @@ int main (int argc, const char * argv []) }; // will partially fail (compilation) because module isn't attached to a runtime yet. - result = m3_InjectFunction (module, & functionIndex, "i()", wasm, true); expect (result != m3Err_none) + result = m3Ext_InjectFunction (module, & functionIndex, "i()", wasm, true); expect (result != m3Err_none) expect (functionIndex >= 0) result = m3_LoadModule (runtime, module); expect (result == m3Err_none) // try again - result = m3_InjectFunction (module, & functionIndex, "i()", wasm, true); expect (result == m3Err_none) + result = m3Ext_InjectFunction (module, & functionIndex, "i()", wasm, true); expect (result == m3Err_none) IM3Function function = m3_GetFunctionByIndex (module, functionIndex); expect (function)