From c45fecf107fcf6f1665647b33fc9bc9d7a710d95 Mon Sep 17 00:00:00 2001 From: Steven Massey Date: Sat, 29 Feb 2020 14:23:55 -0800 Subject: [PATCH] consolidated FuncType's in M3Environment; simplified op_CallIndirect --- source/extra/m3_test.c | 37 +++++++++++++++--------------- source/m3_bind.c | 38 ++++++++++++++++++++++--------- source/m3_bind.h | 2 +- source/m3_compile.c | 2 +- source/m3_core.h | 1 + source/m3_env.c | 50 ++++++++++++++++++++++++++++++++++------- source/m3_env.h | 31 ++++++++++++++----------- source/m3_exec.c | 51 ++++++++++++++---------------------------- source/m3_info.c | 16 ++++++++----- source/m3_info.h | 2 ++ source/m3_module.c | 13 +---------- source/m3_parse.c | 49 +++++++++++++++++++++------------------- source/wasm3.h | 1 + 13 files changed, 166 insertions(+), 127 deletions(-) diff --git a/source/extra/m3_test.c b/source/extra/m3_test.c index b2f8bef..4d0784e 100644 --- a/source/extra/m3_test.c +++ b/source/extra/m3_test.c @@ -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; diff --git a/source/m3_bind.c b/source/m3_bind.c index 4abe040..f114227 100644 --- a/source/m3_bind.c +++ b/source/m3_bind.c @@ -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; } diff --git a/source/m3_bind.h b/source/m3_bind.h index a2bfa72..90d995f 100644 --- a/source/m3_bind.h +++ b/source/m3_bind.h @@ -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 */ diff --git a/source/m3_compile.c b/source/m3_compile.c index 5b29629..9f01d65 100644 --- a/source/m3_compile.c +++ b/source/m3_compile.c @@ -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)); diff --git a/source/m3_core.h b/source/m3_core.h index 7f2302f..29cf51e 100644 --- a/source/m3_core.h +++ b/source/m3_core.h @@ -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 diff --git a/source/m3_env.c b/source/m3_env.c index 30d3406..ab8715b 100644 --- a/source/m3_env.c +++ b/source/m3_env.c @@ -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); diff --git a/source/m3_env.h b/source/m3_env.h index d3e9b9d..65453e4 100644 --- a/source/m3_env.h +++ b/source/m3_env.h @@ -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; //--------------------------------------------------------------------------------------------------------------------------------- diff --git a/source/m3_exec.c b/source/m3_exec.c index 4b89a88..34070c8 100644 --- a/source/m3_exec.c +++ b/source/m3_exec.c @@ -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; } diff --git a/source/m3_info.c b/source/m3_info.c index 38c1f14..ae3f645 100644 --- a/source/m3_info.c +++ b/source/m3_info.c @@ -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; } diff --git a/source/m3_info.h b/source/m3_info.h index b2fe8ce..48a133f 100644 --- a/source/m3_info.h +++ b/source/m3_info.h @@ -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(...) {} diff --git a/source/m3_module.c b/source/m3_module.c index c4c9bd6..4c6e452 100644 --- a/source/m3_module.c +++ b/source/m3_module.c @@ -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; diff --git a/source/m3_parse.c b/source/m3_parse.c index 5748d00..bf31d73 100644 --- a/source/m3_parse.c +++ b/source/m3_parse.c @@ -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; diff --git a/source/wasm3.h b/source/wasm3.h index ac9a196..eff6d1b 100644 --- a/source/wasm3.h +++ b/source/wasm3.h @@ -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")