From ad98bbd746276cafd2c689d9be610994027c40d7 Mon Sep 17 00:00:00 2001 From: Steven Massey Date: Fri, 28 Feb 2020 16:27:05 -0800 Subject: [PATCH] refactoring / cleanup --- source/extra/m3_test.c | 45 +++++++++++++++++ source/m3_bind.c | 110 +++++++++++++++++++++++------------------ source/m3_bind.h | 18 +++++++ source/m3_compile.c | 3 +- source/m3_core.c | 26 +++++++--- source/m3_core.h | 3 +- source/m3_env.c | 15 ++++++ source/m3_env.h | 11 +++-- source/m3_exception.h | 5 +- source/m3_parse.c | 97 +++++++++++++++--------------------- source/wasm3.h | 3 ++ 11 files changed, 214 insertions(+), 122 deletions(-) create mode 100644 source/extra/m3_test.c create mode 100644 source/m3_bind.h diff --git a/source/extra/m3_test.c b/source/extra/m3_test.c new file mode 100644 index 0000000..68a81f9 --- /dev/null +++ b/source/extra/m3_test.c @@ -0,0 +1,45 @@ +// +// m3_test.c +// m3 +// +// Created by Steven Massey on 2/27/20. +// Copyright © 2020 Steven Massey. All rights reserved. +// + +#include + +#include "m3_ext.h" +#include "m3_bind.h" + +#define Test(NAME) printf ("test: %s\n", #NAME); +#define expect(TEST) if (not (TEST)) { printf ("failed: (%s) on line: %d\n", #TEST, __LINE__); } + + +int main (int i_argc, const char * i_argv []) +{ + Test (signatures) + { + M3Result result; + + M3FuncType ftype = { 666, {}, 255 }; + + result = SignatureToFuncType (& ftype, ""); expect (result == m3Err_funcSignatureMissingReturnType) + + result = SignatureToFuncType (& ftype, "()"); expect (result == m3Err_funcSignatureMissingReturnType) + + result = SignatureToFuncType (& ftype, " v () "); expect (result == m3Err_none) + expect (ftype.returnType == c_m3Type_none) + expect (ftype.numArgs == 0) + + + result = SignatureToFuncType (& ftype, "f(IiF"); expect (result == m3Err_none) + expect (ftype.returnType == c_m3Type_f32) + expect (ftype.numArgs == 3) + + M3FuncType ftype2; + result = SignatureToFuncType (& ftype2, "f(I i F)"); expect (result == m3Err_none); + expect (AreFuncTypesEqual (& ftype, &ftype2)); + } + + return 0; +} diff --git a/source/m3_bind.c b/source/m3_bind.c index 78ef367..2567ac8 100644 --- a/source/m3_bind.c +++ b/source/m3_bind.c @@ -9,7 +9,7 @@ #include "m3_env.h" #include "m3_exception.h" -static + u8 ConvertTypeCharToTypeId (char i_code) { switch (i_code) { @@ -23,30 +23,35 @@ u8 ConvertTypeCharToTypeId (char i_code) return c_m3Type_none; } -static -M3Result ValidateSignature (IM3Function i_function, ccstr_t i_linkingSignature) + +M3Result SignatureToFuncType (M3FuncType * o_functionType, ccstr_t i_signature) { M3Result result = m3Err_none; - - cstr_t sig = i_linkingSignature; - IM3FuncType bindType = i_function->funcType; - + + if (not o_functionType) + _throw ("null function type"); + + if (not i_signature) + _throw ("null function signature"); + + cstr_t sig = i_signature; + bool hasReturn = false; - u32 numArgs = 0; - + o_functionType->numArgs = 0; + bool parsingArgs = false; while (* sig) { - if (numArgs >= d_m3MaxNumFunctionArgs) - _throw ("[link] arg count overflow"); - + if (o_functionType->numArgs >= d_m3MaxNumFunctionArgs) + _throw ("signature argument count overflow"); + char typeChar = * sig++; - + if (typeChar == '(') { if (not hasReturn) - _throw ("[link] malformed function signature; missing return type"); - + break; + parsingArgs = true; continue; } @@ -54,52 +59,59 @@ M3Result ValidateSignature (IM3Function i_function, ccstr_t i_linkingSignature continue; else if (typeChar == ')') break; - + u8 type = ConvertTypeCharToTypeId (typeChar); - - if (type) + + if (not type) + _throw ("unknown argument type char"); + + if (not parsingArgs) { - if (not parsingArgs) + if (hasReturn) + _throw ("malformed function signature; too many return types"); + + hasReturn = true; + + // M3FuncType doesn't speak 'void' + if (type == c_m3Type_void) + type = c_m3Type_none; + + o_functionType->returnType = type; + } + else + { + if (type != c_m3Type_runtime) { - if (hasReturn) - _throw ("[link] malformed function signature; too many return types"); - - hasReturn = true; + if (type == c_m3Type_ptr) + type = c_m3Type_i32; - // M3FuncType doesn't speak 'void' - if (type == c_m3Type_void) - type = c_m3Type_none; - - if (type != bindType->returnType) - _throw ("[link] mismatch return type in linking function"); - } - else - { - if (type != c_m3Type_runtime) - { - ++numArgs; - - if (numArgs <= bindType->numArgs) - { - if (type == c_m3Type_ptr) - type = c_m3Type_i32; - - if (type != bindType->argTypes [numArgs - 1]) - _throw ("[link] mismatched argument type"); - } - else break; - } + o_functionType->argTypes [o_functionType->numArgs++] = type; } } - else _throw ("[link] unknown argument type char"); } + + if (not hasReturn) + _throw (m3Err_funcSignatureMissingReturnType); + + _catch: return result; +} - if (bindType->numArgs != numArgs) - _throw ("[link] function arg count mismatch"); + +static +M3Result ValidateSignature (IM3Function i_function, ccstr_t i_linkingSignature) +{ + M3Result result = m3Err_none; + + M3FuncType ftype; +_ (SignatureToFuncType (& ftype, i_linkingSignature)); + + if (not AreFuncTypesEqual (& ftype, i_function->funcType)) + _throw ("function signature mismatch"); _catch: return result; } + typedef M3Result (* M3Linker) (IM3Module io_module, IM3Function io_function, const char * const i_signature, const void * i_function); M3Result FindAndLinkFunction (IM3Module io_module, diff --git a/source/m3_bind.h b/source/m3_bind.h new file mode 100644 index 0000000..bd4cb3e --- /dev/null +++ b/source/m3_bind.h @@ -0,0 +1,18 @@ +// +// m3_bind.h +// m3 +// +// Created by Steven Massey on 2/27/20. +// Copyright © 2020 Steven Massey. All rights reserved. +// + +#ifndef m3_bind_h +#define m3_bind_h + +#include "m3_core.h" + +u8 ConvertTypeCharToTypeId (char i_code); +M3Result SignatureToFuncType (M3FuncType * o_functionType, ccstr_t i_signature); + + +#endif /* m3_bind_h */ diff --git a/source/m3_compile.c b/source/m3_compile.c index 3c3420a..5b29629 100644 --- a/source/m3_compile.c +++ b/source/m3_compile.c @@ -1339,8 +1339,7 @@ _ (ReadLEB_u32 (& typeIndex, & o->wasm, o->wasmEnd)); i8 reserved; _ (ReadLEB_i7 (& reserved, & o->wasm, o->wasmEnd)); - if (typeIndex >= o->module->numFuncTypes) - _throw ("function type index out of range"); + _throwif ("function type index out of range", typeIndex >= o->module->numFuncTypes); if (IsStackTopInRegister (o)) _ (PreserveRegisterIfOccupied (o, c_m3Type_i32)); diff --git a/source/m3_core.c b/source/m3_core.c index edff408..3c1afa4 100644 --- a/source/m3_core.c +++ b/source/m3_core.c @@ -108,12 +108,10 @@ M3Result m3Malloc (void ** o_ptr, size_t i_size) { M3Result result = m3Err_none; - void * ptr = malloc (i_size); - if (ptr) - { - memset (ptr, 0x0, i_size); - } - else result = m3Err_mallocFailed; + void * ptr = calloc (i_size, 1); + + if (not ptr) + result = m3Err_mallocFailed; * o_ptr = ptr; // printf("== alloc %d => %p\n", (u32) i_size, ptr); @@ -151,6 +149,22 @@ void * m3Realloc (void * i_ptr, size_t i_newSize, size_t i_oldSize) return ptr; } + +M3Result m3MemCopy (void ** o_to, void * i_from, size_t i_size) +{ + void * to = malloc (i_size); + + if (to) + { + memcpy (to, i_from, i_size); + * o_to = to; + + return m3Err_none; + } + else return m3Err_mallocFailed; +} + + #endif //-------------------------------------------------------------------------------------------- diff --git a/source/m3_core.h b/source/m3_core.h index ef36cfc..0c0ace2 100644 --- a/source/m3_core.h +++ b/source/m3_core.h @@ -210,7 +210,8 @@ void m3NotImplemented (void); M3Result m3Malloc (void ** o_ptr, size_t i_size); void * m3Realloc (void * i_ptr, size_t i_newSize, size_t i_oldSize); -void m3Free_impl (void * o_ptr); +void m3Free_impl (void * i_ptr); +M3Result m3MemCopy (void ** o_to, void * i_from, size_t i_size); M3Result NormalizeType (u8 * o_type, i8 i_convolutedWasmType); diff --git a/source/m3_env.c b/source/m3_env.c index 0f9de83..a9dc4a3 100644 --- a/source/m3_env.c +++ b/source/m3_env.c @@ -12,6 +12,21 @@ #include "m3_exec.h" #include "m3_exception.h" + +bool AreFuncTypesEqual (const IM3FuncType i_typeA, const IM3FuncType i_typeB) +{ + if (i_typeA->returnType == i_typeB->returnType) + { + if (i_typeA->numArgs == i_typeB->numArgs) + { + return (memcmp (i_typeA->argTypes, i_typeB->argTypes, i_typeA->numArgs) == 0); + } + } + + return false; +} + + cstr_t GetFunctionName (IM3Function i_function) { if (i_function->import.fieldUtf8) diff --git a/source/m3_env.h b/source/m3_env.h index cc6be2b..a2a893a 100644 --- a/source/m3_env.h +++ b/source/m3_env.h @@ -26,6 +26,7 @@ M3FuncType; typedef M3FuncType * IM3FuncType; void PrintFuncTypeSignature (IM3FuncType i_funcType); +bool AreFuncTypesEqual (const IM3FuncType i_typeA, const IM3FuncType i_typeB); //--------------------------------------------------------------------------------------------------------------------------------- @@ -38,6 +39,8 @@ typedef struct M3Function bytes_t wasm; bytes_t wasmEnd; + bool ownsWasmCode; + cstr_t name; IM3FuncType funcType; @@ -56,8 +59,6 @@ typedef struct M3Function u16 numConstantBytes; void * constants; - -// bool callNeedsRuntime; } M3Function; @@ -137,7 +138,7 @@ typedef M3Global * IM3Global; //--------------------------------------------------------------------------------------------------------------------------------- -typedef struct M3Module // TODO add env owner? also discriminates stack/heap +typedef struct M3Module { struct M3Runtime * runtime; @@ -170,8 +171,8 @@ typedef struct M3Module // TODO add env owner? also discriminate M3MemoryInfo memoryInfo; bool memoryImported; - -// m3reg_t * globalMemory; + + bool hasWasmCodeCopy; struct M3Module * next; } diff --git a/source/m3_exception.h b/source/m3_exception.h index 0259da8..4a45741 100644 --- a/source/m3_exception.h +++ b/source/m3_exception.h @@ -14,7 +14,8 @@ #define EXCEPTION_PRINT //puts("Exc: " __FILE__ ":" M3_STR(__LINE__) "\n"); #define _try -#define _(TRY) { result = TRY; if (result) { EXCEPTION_PRINT; goto _catch; } } -#define _throw(ERROR) { result = ERROR; EXCEPTION_PRINT; goto _catch; } +#define _(TRY) { result = TRY; if (result) { EXCEPTION_PRINT; goto _catch; } } +#define _throw(ERROR) { result = ERROR; EXCEPTION_PRINT; goto _catch; } +#define _throwif(ERROR, COND) if (COND) { result = ERROR; EXCEPTION_PRINT; goto _catch; } #endif // m3_exception_h diff --git a/source/m3_parse.c b/source/m3_parse.c index 517b107..af97b92 100644 --- a/source/m3_parse.c +++ b/source/m3_parse.c @@ -58,8 +58,7 @@ _ (m3Alloc (& io_module->funcTypes, M3FuncType, numTypes)); i8 form; _ (ReadLEB_i7 (& form, & i_bytes, i_end)); - if (form != -32) - _throw (m3Err_wasmMalformed); // for WA MVP } + _throwif (m3Err_wasmMalformed, form != -32); // for WA MVP _ (ReadLEB_u32 (& ft->numArgs, & i_bytes, i_end)); @@ -245,6 +244,7 @@ _ (ReadLEB_u32 (& startFuncIndex, & i_bytes, i_end)); _catch: return result; } + M3Result Parse_InitExpr (M3Module * io_module, bytes_t * io_bytes, cbytes_t i_end) { M3Result result = m3Err_none; @@ -261,7 +261,6 @@ M3Result Parse_InitExpr (M3Module * io_module, bytes_t * io_bytes, cbytes_t i_ } - M3Result ParseSection_Element (IM3Module io_module, bytes_t i_bytes, cbytes_t i_end) { M3Result result = m3Err_none; @@ -269,19 +268,16 @@ M3Result ParseSection_Element (IM3Module io_module, bytes_t i_bytes, cbytes_t u32 numSegments; result = ReadLEB_u32 (& numSegments, & i_bytes, i_end); m3log (parse, "** Element [%d]", numSegments); - if (not result) - { - io_module->elementSection = i_bytes; - io_module->elementSectionEnd = i_end; - io_module->numElementSegments = numSegments; - } - else result = "error parsing Element section"; + _throwif ("error parsing Element section", result); + + io_module->elementSection = i_bytes; + io_module->elementSectionEnd = i_end; + io_module->numElementSegments = numSegments; - return result; + _catch: return result; } - M3Result ParseSection_Code (M3Module * io_module, bytes_t i_bytes, cbytes_t i_end) { M3Result result; @@ -291,8 +287,7 @@ _ (ReadLEB_u32 (& numFunctions, & i_bytes, i_end)); if (numFunctions != io_module->numFunctions - io_module->numImports) { - numFunctions = 0; - _throw (m3Err_wasmMalformed); // FIX: better error + _throw ("mismatched function count in code section"); } for (u32 f = 0; f < numFunctions; ++f) @@ -332,6 +327,7 @@ _ (NormalizeType (& normalType, wasmType)); func->module = io_module; func->wasm = start; func->wasmEnd = i_bytes; + func->ownsWasmCode = io_module->hasWasmCodeCopy; func->numLocals = numLocals; } else _throw (m3Err_wasmSectionOverrun); @@ -368,18 +364,15 @@ _ (ReadLEB_u32 (& segment->memoryRegion, & i_bytes, i_end)); _ (Parse_InitExpr (io_module, & i_bytes, i_end)); segment->initExprSize = (u32) (i_bytes - segment->initExpr); - if (segment->initExprSize <= 1) - _throw (m3Err_wasmMissingInitExpr); + _throwif (m3Err_wasmMissingInitExpr, segment->initExprSize <= 1); _ (ReadLEB_u32 (& segment->size, & i_bytes, i_end)); - segment->data = i_bytes; m3log (parse, " segment [%u] memory: %u; expr-size: %d; size: %d", i, segment->memoryRegion, segment->initExprSize, segment->size); i_bytes += segment->size; } _catch: - // TODO failure cleanup return result; } @@ -394,11 +387,9 @@ M3Result ParseSection_Memory (M3Module * io_module, bytes_t i_bytes, cbytes_t u32 numMemories; _ (ReadLEB_u32 (& numMemories, & i_bytes, i_end)); m3log (parse, "** Memory [%d]", numMemories); - if (numMemories == 1) - { - ParseType_Memory (& io_module->memoryInfo, & i_bytes, i_end); - } - else _throw (m3Err_tooManyMemorySections); + _throwif (m3Err_tooManyMemorySections, numMemories != 1); + + ParseType_Memory (& io_module->memoryInfo, & i_bytes, i_end); _catch: return result; } @@ -427,8 +418,7 @@ _ (Module_AddGlobal (io_module, & global, type, isMutable, false /* isImpo _ (Parse_InitExpr (io_module, & i_bytes, i_end)); global->initExprSize = (u32) (i_bytes - global->initExpr); - if (global->initExprSize <= 1) - _throw (m3Err_wasmMissingInitExpr); + _throwif (m3Err_wasmMissingInitExpr, global->initExprSize <= 1); } _catch: return result; @@ -537,51 +527,44 @@ M3Result m3_ParseModule (IM3Environment i_environment, IM3Module * o_module, c IM3Module module; _try { _ (m3Alloc (& module, M3Module, 1)); -// Module_Init (module); module->name = ".unnamed"; m3log (parse, "load module: %d bytes", i_numBytes); module->startFunction = -1; + module->hasWasmCodeCopy = false; const u8 * pos = i_bytes; const u8 * end = pos + i_numBytes; - u32 magic = 0; + u32 magic, version; _ (Read_u32 (& magic, & pos, end)); - - if (magic == 0x6d736100) +_ (Read_u32 (& version, & pos, end)); + + _throwif (m3Err_wasmMalformed, magic != 0x6d736100); + _throwif (m3Err_incompatibleWasmVersion, version != 1); + m3log (parse, "found magic + version"); + u8 previousSection = 0; + + while (pos < end) { - u32 version; -_ (Read_u32 (&version, & pos, end)); + u8 section; +_ (ReadLEB_u7 (& section, & pos, end)); + + if (section > previousSection or // from the spec: sections must appear in order + section == 0 or // custom section + (section == 12 and section == 9) or // if present, DataCount goes after Element + (section == 10 and section == 12)) // and before Code + { + u32 sectionLength; +_ (ReadLEB_u32 (& sectionLength, & pos, end)); +_ (ParseModuleSection (module, section, pos, sectionLength)); - if (version == 1) - { m3log (parse, "found magic + version"); - u8 previousSection = 0; + pos += sectionLength; - while (pos < end) - { - u8 sectionCode; -_ (ReadLEB_u7 (& sectionCode, & pos, end)); - - if (sectionCode > previousSection or // from the spec: sections must appear in order - sectionCode == 0 or - (sectionCode == 12 and previousSection == 9) or // if present, DataCount goes after Element - (sectionCode == 10 and previousSection == 12) // and before Code - ) { - u32 sectionLength; -_ (ReadLEB_u32 (& sectionLength, & pos, end)); -_ (ParseModuleSection (module, sectionCode, pos, sectionLength)); - - pos += sectionLength; - - if (sectionCode) - previousSection = sectionCode; - } - else _throw (m3Err_misorderedWasmSection); - } + if (section) + previousSection = section; } - else _throw (m3Err_incompatibleWasmVersion); + else _throw (m3Err_misorderedWasmSection); } - else _throw (m3Err_wasmMalformed); } _catch: diff --git a/source/wasm3.h b/source/wasm3.h index 5b5e6f2..ac9a196 100644 --- a/source/wasm3.h +++ b/source/wasm3.h @@ -118,6 +118,9 @@ d_m3ErrorConst (tooManyMemorySections, "Wasm MVP can only define one me d_m3ErrorConst (moduleAlreadyLinked, "attempting to bind module to multiple runtimes") d_m3ErrorConst (functionLookupFailed, "function lookup failed") d_m3ErrorConst (functionImportMissing, "missing imported function") + +d_m3ErrorConst (malformedFunctionSignature, "malformed function signature") +d_m3ErrorConst (funcSignatureMissingReturnType,"function signature missing return type") // compilation errors d_m3ErrorConst (noCompiler, "no compiler found for opcode")