consolidated FuncType's in M3Environment; simplified op_CallIndirect

extensions
Steven Massey 4 years ago
parent ac7badfdc5
commit c45fecf107

@ -19,32 +19,31 @@ int main (int i_argc, const char * i_argv [])
{
M3Result result;
M3FuncType ftype = { NULL, 666, 255 };
IM3FuncType ftype = NULL;
result = SignatureToFuncType (& ftype, ""); expect (result == m3Err_funcSignatureMissingReturnType)
FuncType_Free (& ftype);
result = SignatureToFuncType (& ftype, ""); expect (result == m3Err_malformedFunctionSignature)
m3Free (ftype);
result = SignatureToFuncType (& ftype, "()"); expect (result == m3Err_funcSignatureMissingReturnType)
FuncType_Free (& ftype);
result = SignatureToFuncType (& ftype, "()"); expect (result == m3Err_malformedFunctionSignature)
m3Free (ftype);
result = SignatureToFuncType (& ftype, " v () "); expect (result == m3Err_none)
expect (ftype.returnType == c_m3Type_none)
expect (ftype.numArgs == 0)
FuncType_Free (& ftype);
result = SignatureToFuncType (& ftype, "f(IiF"); expect (result == m3Err_none)
expect (ftype.returnType == c_m3Type_f32)
expect (ftype.numArgs == 3)
expect (ftype->returnType == c_m3Type_none)
expect (ftype->numArgs == 0)
m3Free (ftype);
result = SignatureToFuncType (& ftype, "f(IiF)"); expect (result == m3Err_none)
expect (ftype->returnType == c_m3Type_f32)
expect (ftype->numArgs == 3)
expect (ftype->argTypes [0] == c_m3Type_i64)
expect (ftype->argTypes [1] == c_m3Type_i32)
expect (ftype->argTypes [2] == c_m3Type_f64)
M3FuncType ftype2;
IM3FuncType ftype2 = NULL;
result = SignatureToFuncType (& ftype2, "f(I i F)"); expect (result == m3Err_none);
expect (AreFuncTypesEqual (& ftype, &ftype2));
FuncType_Free (& ftype);
FuncType_Free (& ftype2);
expect (AreFuncTypesEqual (ftype, ftype2));
m3Free (ftype);
m3Free (ftype2);
}
return 0;

@ -24,10 +24,12 @@ u8 ConvertTypeCharToTypeId (char i_code)
}
M3Result SignatureToFuncType (M3FuncType * o_functionType, ccstr_t i_signature)
M3Result SignatureToFuncType (IM3FuncType * o_functionType, ccstr_t i_signature)
{
M3Result result = m3Err_none; d_m3Assert (o_functionType->argTypes == NULL); // unfreed functype
M3Result result = m3Err_none;
IM3FuncType funcType = NULL;
if (not o_functionType)
_throw ("null function type");
@ -37,9 +39,14 @@ M3Result SignatureToFuncType (M3FuncType * o_functionType, ccstr_t i_signature
cstr_t sig = i_signature;
bool hasReturn = false;
o_functionType->numArgs = 0;
_ (m3Alloc (& o_functionType->argTypes, u8, strlen (i_signature)));
size_t maxNumArgs = strlen (i_signature);
_throwif (m3Err_malformedFunctionSignature, maxNumArgs < 3);
maxNumArgs -= 3; // "v()"
_throwif ("insane argument count", maxNumArgs > d_m3MaxSaneFunctionArgCount);
_ (AllocFuncType (& funcType, (u32) maxNumArgs));
bool parsingArgs = false;
while (* sig)
@ -75,16 +82,18 @@ _ (m3Alloc (& o_functionType->argTypes, u8, strlen (i_signature)));
if (type == c_m3Type_void)
type = c_m3Type_none;
o_functionType->returnType = type;
funcType->returnType = type;
}
else
{
_throwif (m3Err_malformedFunctionSignature, funcType->numArgs >= maxNumArgs); // forgot trailing ')' ?
if (type != c_m3Type_runtime)
{
if (type == c_m3Type_ptr)
type = c_m3Type_i32;
o_functionType->argTypes [o_functionType->numArgs++] = type;
funcType->argTypes [funcType->numArgs++] = type;
}
}
}
@ -92,7 +101,14 @@ _ (m3Alloc (& o_functionType->argTypes, u8, strlen (i_signature)));
if (not hasReturn)
_throw (m3Err_funcSignatureMissingReturnType);
_catch: return result;
_catch:
if (result)
m3Free (funcType); // nulls funcType
* o_functionType = funcType;
return result;
}
@ -101,15 +117,15 @@ M3Result ValidateSignature (IM3Function i_function, ccstr_t i_linkingSignature
{
M3Result result = m3Err_none;
M3FuncType ftype = {0};
IM3FuncType ftype = NULL;
_ (SignatureToFuncType (& ftype, i_linkingSignature));
if (not AreFuncTypesEqual (& ftype, i_function->funcType))
if (not AreFuncTypesEqual (ftype, i_function->funcType))
_throw ("function signature mismatch");
_catch:
FuncType_Free (& ftype);
m3Free (ftype);
return result;
}

@ -11,7 +11,7 @@
#include "m3_env.h"
u8 ConvertTypeCharToTypeId (char i_code);
M3Result SignatureToFuncType (M3FuncType * o_functionType, ccstr_t i_signature);
M3Result SignatureToFuncType (IM3FuncType * o_functionType, ccstr_t i_signature);
#endif /* m3_bind_h */

@ -1347,7 +1347,7 @@ _ (PreserveRegisterIfOccupied (o, c_m3Type_i32));
u16 tableIndexSlot = GetStackTopSlotIndex (o);
u16 execTop;
IM3FuncType type = & o->module->funcTypes [typeIndex];
IM3FuncType type = o->module->funcTypes [typeIndex];
_ (CompileCallArgsAndReturn (o, & execTop, type, true));
_ (EmitOp (o, op_CallIndirect));

@ -165,6 +165,7 @@ M3CodePageHeader;
#define d_m3Fp0SlotAlias 30001
#define d_m3MaxSaneUtf8Length 2000
#define d_m3MaxSaneFunctionArgCount 1000 // still insane, but whatever
#define d_externalKind_function 0
#define d_externalKind_table 1

@ -13,9 +13,11 @@
#include "m3_exception.h"
void FuncType_Free (IM3FuncType i_type)
M3Result AllocFuncType (IM3FuncType * o_functionType, u32 i_numArgs)
{
m3Free (i_type->argTypes);
size_t funcTypeSize = sizeof (M3FuncType) - 3 /* sizeof (argTypes [3]) */ + i_numArgs;
return m3Alloc (o_functionType, u8, funcTypeSize);
}
@ -25,10 +27,7 @@ bool AreFuncTypesEqual (const IM3FuncType i_typeA, const IM3FuncType i_typeB)
{
if (i_typeA->numArgs == i_typeB->numArgs)
{
if (i_typeA->argTypes and i_typeB->argTypes)
{
return (memcmp (i_typeA->argTypes, i_typeB->argTypes, i_typeA->numArgs) == 0);
}
return (memcmp (i_typeA->argTypes, i_typeB->argTypes, i_typeA->numArgs) == 0);
}
}
@ -116,12 +115,47 @@ void m3_FreeEnvironment (IM3Environment i_environment)
{
if (i_environment)
{
// ReleaseEnvironment (i_environment);
IM3FuncType ftype = i_environment->funcTypes;
while (ftype)
{
IM3FuncType next = ftype->next;
m3Free (ftype);
ftype = next;
}
m3Free (i_environment);
}
}
void Environment_AddFuncType (IM3Environment i_environment, IM3FuncType * io_funcType)
{
IM3FuncType addType = * io_funcType;
IM3FuncType newType = i_environment->funcTypes;
while (newType)
{
if (AreFuncTypesEqual (newType, addType))
{
m3Free (addType);
break;
}
newType = newType->next;
}
if (newType == NULL)
{
newType = addType;
newType->next = i_environment->funcTypes;
i_environment->funcTypes = newType;
}
* io_funcType = newType;
}
IM3Runtime m3_NewRuntime (IM3Environment i_environment, u32 i_stackSizeInBytes, M3StackInfo * i_nativeStackInfo)
{
IM3Runtime runtime = NULL;
@ -585,7 +619,7 @@ M3Result m3_CallWithArgs (IM3Function i_function, uint32_t i_argc, const char
if (i_function->name and strcmp (i_function->name, "_start") == 0) // WASI
i_argc = 0;
IM3FuncType ftype = i_function->funcType; m3logif (runtime, PrintFuncTypeSignature (ftype));
IM3FuncType ftype = i_function->funcType; m3log (runtime, "calling %s", SPrintFuncTypeSignature (ftype));
if (i_argc != ftype->numArgs)
_throw (m3Err_argumentCountMismatch);

@ -17,17 +17,18 @@ d_m3BeginExternC
typedef struct M3FuncType
{
u8 * argTypes;
u32 numArgs;
u8 returnType;
struct M3FuncType * next;
u32 numArgs;
u8 returnType;
u8 argTypes [3]; // M3FuncType is a dynamically sized object; these are padding
}
M3FuncType;
typedef M3FuncType * IM3FuncType;
void FuncType_Free (IM3FuncType i_type);
void PrintFuncTypeSignature (IM3FuncType i_funcType);
bool AreFuncTypesEqual (const IM3FuncType i_typeA, const IM3FuncType i_typeB);
M3Result AllocFuncType (IM3FuncType * o_functionType, u32 i_numArgs);
bool AreFuncTypesEqual (const IM3FuncType i_typeA, const IM3FuncType i_typeB);
//---------------------------------------------------------------------------------------------------------------------------------
@ -141,11 +142,12 @@ typedef M3Global * IM3Global;
typedef struct M3Module
{
struct M3Runtime * runtime;
struct M3Environment * environment;
cstr_t name;
u32 numFuncTypes;
M3FuncType * funcTypes;
IM3FuncType * funcTypes; // array of pointers to list of FuncTypes
u32 numImports;
IM3Function * imports; // notice: "I" prefix. imports are pointers to functions in another module.
@ -187,17 +189,20 @@ M3Result Module_AddFunction (IM3Module io_module, u3
IM3Function Module_GetFunction (IM3Module i_module, u32 i_functionIndex);
//---------------------------------------------------------------------------------------------------------------------------------
static const u32 c_m3NumTypesPerPage = 8;
//---------------------------------------------------------------------------------------------------------------------------------
typedef struct M3Environment
{
u32 dummy;
// u32 numCodePages;
// u32 numActiveCodePages;
// u32 numFuncTypes;
// M3FuncType * funcTypes;
IM3FuncType funcTypes; // linked list
}
M3Environment;
// takes ownership of io_funcType and returns a pointer to the persistent version (could be same or different)
void Environment_AddFuncType (IM3Environment i_environment, IM3FuncType * io_funcType);
typedef M3Environment * IM3Environment;
//---------------------------------------------------------------------------------------------------------------------------------

@ -94,54 +94,37 @@ d_m3OpDef (CallIndirect)
m3stack_t sp = _sp + stackOffset;
m3ret_t r = m3Err_none;
if (tableIndex < module->table0Size)
{
m3ret_t r = m3Err_none;
IM3Function function = module->table0 [tableIndex];
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 !defined(d_m3SkipCallCheck)
if (type->numArgs != function->funcType->numArgs)
{
return m3Err_trapIndirectCallTypeMismatch;
}
if (type->returnType != function->funcType->returnType)
{
return m3Err_trapIndirectCallTypeMismatch;
}
for (u32 argIndex = 0; argIndex < type->numArgs; ++argIndex)
{
if (type->argTypes[argIndex] != function->funcType->argTypes[argIndex])
{
return m3Err_trapIndirectCallTypeMismatch;
}
}
#endif
if (not function->compiled)
r = Compile_Function (function);
if (not r)
if (type == function->funcType)
{
r = Call (function->compiled, sp, _mem, d_m3OpDefaultArgs);
if (not function->compiled)
r = Compile_Function (function);
if (not r)
{
_mem = memory->mallocated;
r = nextOpDirect ();
r = Call (function->compiled, sp, _mem, d_m3OpDefaultArgs);
if (not r)
{
_mem = memory->mallocated;
r = nextOpDirect ();
}
}
}
else r = m3Err_trapIndirectCallTypeMismatch;
}
else r = "trap: table element is null";
return r;
else r = m3Err_trapTableElementIsNull;
}
else return m3Err_trapTableIndexOutOfRange;
else r = m3Err_trapTableIndexOutOfRange;
return r;
}

@ -59,9 +59,11 @@ cstr_t GetTypeName (u8 i_m3Type)
}
void PrintFuncTypeSignature (IM3FuncType i_funcType)
cstr_t SPrintFuncTypeSignature (IM3FuncType i_funcType)
{
printf ("(");
static char string [256];
sprintf (string, "(");
u32 numArgs = i_funcType->numArgs;
u8 * types = i_funcType->argTypes;
@ -69,11 +71,15 @@ void PrintFuncTypeSignature (IM3FuncType i_funcType)
for (u32 i = 0; i < numArgs; ++i)
{
if (i != 0)
printf (", ");
printf ("%s", GetTypeName (types [i]));
strcat (string, ", ");
strcat (string, GetTypeName (types [i]));
}
printf (") -> %s", GetTypeName (i_funcType->returnType));
strcat (string, ") -> ");
strcat (string, GetTypeName (i_funcType->returnType));
return string;
}

@ -20,6 +20,8 @@ const char * get_indention_string (IM3Compilation o);
void emit_stack_dump (IM3Compilation o);
void log_emit (IM3Compilation o, IM3Operation i_operation);
cstr_t SPrintFuncTypeSignature (IM3FuncType i_funcType);
#else // d_m3LogOutput
#define dump_type_stack(...) {}

@ -29,16 +29,6 @@ void Module_FreeFunctions (IM3Module i_module)
}
void Module_FreeFuncTypes (IM3Module i_module)
{
for (u32 i = 0; i < i_module->numFuncTypes; ++i)
{
IM3FuncType ftype = & i_module->funcTypes [i];
FuncType_Free (ftype);
}
}
void m3_FreeModule (IM3Module i_module)
{
if (i_module)
@ -47,7 +37,6 @@ void m3_FreeModule (IM3Module i_module)
i_module->name, i_module->numFunctions, i_module->numDataSegments);
Module_FreeFunctions (i_module);
Module_FreeFuncTypes (i_module);
m3Free (i_module->functions);
m3Free (i_module->imports);
@ -92,7 +81,7 @@ _ (m3ReallocArray (& io_module->functions, M3Function, io_module->numFunctions
if (i_typeIndex < io_module->numFuncTypes)
{
IM3FuncType ft = & io_module->funcTypes [i_typeIndex];
IM3FuncType ft = io_module->funcTypes [i_typeIndex];
IM3Function func = Module_GetFunction (io_module, index);
func->funcType = ft;

@ -9,6 +9,7 @@
#include "m3_compile.h"
#include "m3_exec.h"
#include "m3_exception.h"
#include "m3_info.h"
M3Result ParseType_Table (IM3Module io_module, bytes_t i_bytes, cbytes_t i_end)
@ -43,34 +44,34 @@ M3Result ParseSection_Type (IM3Module io_module, bytes_t i_bytes, cbytes_t i_e
u32 numTypes;
_ (ReadLEB_u32 (& numTypes, & i_bytes, i_end)); m3log (parse, "** Type [%d]", numTypes);
IM3FuncType ftype = NULL;
if (numTypes)
{
// FIX: these need to be instead added to a set in the runtime struct to facilitate IndirectCall
_ (m3Alloc (& io_module->funcTypes, M3FuncType, numTypes));
// table of IM3FuncType (that point to the actual M3FuncType struct in the Environment)
_ (m3Alloc (& io_module->funcTypes, IM3FuncType, numTypes));
io_module->numFuncTypes = numTypes;
IM3FuncType ft = io_module->funcTypes;
while (numTypes--)
for (u32 i = 0; i < numTypes; ++i)
{
i8 form;
_ (ReadLEB_i7 (& form, & i_bytes, i_end));
_throwif (m3Err_wasmMalformed, form != -32); // for WA MVP
_ (ReadLEB_u32 (& ft->numArgs, & i_bytes, i_end));
u32 numArgs;
_ (ReadLEB_u32 (& numArgs, & i_bytes, i_end));
_ (AllocFuncType (& ftype, numArgs));
ftype->numArgs = numArgs;
_ (m3Alloc (& ft->argTypes, u8, ft->numArgs));
for (u32 i = 0; i < ft->numArgs; ++i)
for (u32 a = 0; a < numArgs; ++a)
{
i8 wasmType;
u8 argType;
_ (ReadLEB_i7 (& wasmType, & i_bytes, i_end));
_ (NormalizeType (& argType, wasmType));
ft->argTypes [i] = argType;
ftype->argTypes [a] = argType;
}
u8 returnCount;
@ -80,10 +81,11 @@ _ (ReadLEB_u7 /* u1 in spec */ (& returnCount, & i_bytes, i_end));
{
i8 returnType;
_ (ReadLEB_i7 (& returnType, & i_bytes, i_end));
_ (NormalizeType (& ft->returnType, returnType));
} m3logif (parse, PrintFuncTypeSignature (ft))
_ (NormalizeType (& ftype->returnType, returnType));
} m3log (parse, " type %2d: %s", i, SPrintFuncTypeSignature (& ftype));
++ft;
Environment_AddFuncType (io_module->environment, & ftype);
io_module->funcTypes [i] = ftype;
}
}
@ -91,8 +93,8 @@ _ (NormalizeType (& ft->returnType, returnType));
if (result)
{
m3Free (ftype);
m3Free (io_module->funcTypes);
io_module->funcTypes = NULL;
io_module->numFuncTypes = 0;
}
@ -134,7 +136,7 @@ _ (ReadLEB_u32 (& numImports, & i_bytes, i_end));
_ (Read_utf8 (& import.moduleUtf8, & i_bytes, i_end));
_ (Read_utf8 (& import.fieldUtf8, & i_bytes, i_end));
_ (Read_u8 (& importKind, & i_bytes, i_end)); m3log (parse, " - kind: %d; '%s.%s' ",
_ (Read_u8 (& importKind, & i_bytes, i_end)); m3log (parse, " kind: %d '%s.%s' ",
(u32) importKind, import.moduleUtf8, import.fieldUtf8);
switch (importKind)
{
@ -208,7 +210,7 @@ _ (ReadLEB_u32 (& numExports, & i_bytes, i_end));
_ (Read_utf8 (& utf8, & i_bytes, i_end));
_ (Read_u8 (& exportKind, & i_bytes, i_end));
_ (ReadLEB_u32 (& index, & i_bytes, i_end)); m3log (parse, " - index: %4d; kind: %d; export: '%s'; ", index, (u32) exportKind, utf8);
_ (ReadLEB_u32 (& index, & i_bytes, i_end)); m3log (parse, " index: %3d; kind: %d; export: '%s'; ", index, (u32) exportKind, utf8);
if (exportKind == d_externalKind_function)
{
@ -303,7 +305,7 @@ _ (ReadLEB_u32 (& size, & i_bytes, i_end));
const u8 * start = ptr;
u32 numLocalBlocks;
_ (ReadLEB_u32 (& numLocalBlocks, & ptr, i_end)); m3log (parse, " - func size: %d; local blocks: %d", size, numLocalBlocks);
_ (ReadLEB_u32 (& numLocalBlocks, & ptr, i_end)); m3log (parse, " code size: %-4d", size);
u32 numLocals = 0;
@ -317,7 +319,7 @@ _ (ReadLEB_u32 (& varCount, & ptr, i_end));
_ (ReadLEB_i7 (& wasmType, & ptr, i_end));
_ (NormalizeType (& normalType, wasmType));
numLocals += varCount; m3log (parse, " - %d locals; type: '%s'", varCount, c_waTypes [normalType]);
numLocals += varCount; m3log (parse, " %2d locals; type: '%s'", varCount, c_waTypes [normalType]);
}
IM3Function func = Module_GetFunction (io_module, f + io_module->numImports);
@ -407,7 +409,7 @@ _ (ReadLEB_u32 (& numGlobals, & i_bytes, i_end));
_ (ReadLEB_i7 (& waType, & i_bytes, i_end));
_ (NormalizeType (& type, waType));
_ (ReadLEB_u7 (& isMutable, & i_bytes, i_end)); m3log (parse, " - add global: [%d] %s mutable: %d", i, c_waTypes [type], (u32) isMutable);
_ (ReadLEB_u7 (& isMutable, & i_bytes, i_end)); m3log (parse, " global: [%d] %s mutable: %d", i, c_waTypes [type], (u32) isMutable);
IM3Global global;
_ (Module_AddGlobal (io_module, & global, type, isMutable, false /* isImport */));
@ -459,7 +461,7 @@ _ (Read_utf8 (& name, & i_bytes, i_end));
{
if (not io_module->functions [index].name)
{
io_module->functions [index].name = name; m3log (parse, "naming function [%d]: %s", index, name);
io_module->functions [index].name = name; m3log (parse, " naming function%5d: %s", index, name);
name = NULL; // transfer ownership
}
// else m3log (parse, "prenamed: %s", io_module->functions [index].name);
@ -529,6 +531,7 @@ _ (m3Alloc (& module, M3Module, 1));
module->name = ".unnamed"; m3log (parse, "load module: %d bytes", i_numBytes);
module->startFunction = -1;
module->hasWasmCodeCopy = false;
module->environment = i_environment;
const u8 * pos = i_bytes;
const u8 * end = pos + i_numBytes;

@ -145,6 +145,7 @@ d_m3ErrorConst (trapIntegerOverflow, "[trap] integer overflow")
d_m3ErrorConst (trapIntegerConversion, "[trap] invalid conversion to integer")
d_m3ErrorConst (trapIndirectCallTypeMismatch, "[trap] indirect call type mismatch")
d_m3ErrorConst (trapTableIndexOutOfRange, "[trap] undefined element")
d_m3ErrorConst (trapTableElementIsNull, "[trap] null table element")
d_m3ErrorConst (trapExit, "[trap] program called exit")
d_m3ErrorConst (trapAbort, "[trap] program called abort")
d_m3ErrorConst (trapUnreachable, "[trap] unreachable executed")

Loading…
Cancel
Save