m3Ext_ReserveFunctions

extensions
Steven Massey 3 years ago
parent 92c220407e
commit 433e7d71a3

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

@ -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 <stdbool.h>
#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);

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

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

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

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

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

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

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

Loading…
Cancel
Save