From 66ca1a3b55eae5da2b0fa4c2fbce0231446a8398 Mon Sep 17 00:00:00 2001 From: Volodymyr Shymanskyy Date: Mon, 28 Dec 2020 22:02:36 +0200 Subject: [PATCH] Update to v0.4.8 --- examples/Wasm_Blink/Wasm_Blink.ino | 8 +- examples/Wasm_Fibonacci/Wasm_Fibonacci.ino | 119 +++++ examples_pio/Wasm_Advanced/platformio.ini | 14 + .../Wasm_Advanced/wasm_vm/wasm_vm.ino | 8 +- library.json | 2 +- library.properties | 2 +- src/m3_api_defs.h | 2 +- src/m3_api_libc.c | 1 - src/m3_bind.c | 158 ++---- src/m3_bind.h | 20 + src/m3_compile.c | 500 ++++++++++-------- src/m3_compile.h | 31 +- src/m3_config.h | 97 +++- src/m3_config_platforms.h | 88 ++- src/m3_core.c | 7 +- src/m3_core.h | 35 +- src/m3_emit.c | 2 +- src/m3_env.c | 92 ++-- src/m3_env.h | 43 +- src/m3_exec.c | 93 ++-- src/m3_exec.h | 42 +- src/m3_exec_defs.h | 16 +- src/m3_info.c | 33 +- src/m3_math_utils.h | 7 +- src/m3_parse.c | 42 +- src/wasm3.h | 30 +- 26 files changed, 903 insertions(+), 589 deletions(-) create mode 100644 examples/Wasm_Fibonacci/Wasm_Fibonacci.ino create mode 100644 src/m3_bind.h diff --git a/examples/Wasm_Blink/Wasm_Blink.ino b/examples/Wasm_Blink/Wasm_Blink.ino index e11d6bc..a358bce 100644 --- a/examples/Wasm_Blink/Wasm_Blink.ino +++ b/examples/Wasm_Blink/Wasm_Blink.ino @@ -212,6 +212,12 @@ void wasm_task(void*) Serial.print(" ("); Serial.print(info.message); Serial.println(")"); + if (info.file && strlen(info.file) && info.line) { + Serial.print("At "); + Serial.print(info.file); + Serial.print(":"); + Serial.println(info.line); + } } } @@ -224,7 +230,7 @@ void setup() // Needed for native USB port only while(!Serial) {} - Serial.println("\nWasm3 v" M3_VERSION ", build " __DATE__ " " __TIME__); + Serial.println("\nWasm3 v" M3_VERSION " (" M3_ARCH "), build " __DATE__ " " __TIME__); #ifdef ESP32 // On ESP32, we can launch in a separate thread diff --git a/examples/Wasm_Fibonacci/Wasm_Fibonacci.ino b/examples/Wasm_Fibonacci/Wasm_Fibonacci.ino new file mode 100644 index 0000000..46204da --- /dev/null +++ b/examples/Wasm_Fibonacci/Wasm_Fibonacci.ino @@ -0,0 +1,119 @@ +/* + * Wasm3 - high performance WebAssembly interpreter written in C. + * Copyright © 2020 Volodymyr Shymanskyy, Steven Massey. + * All rights reserved. + */ + +#include +#include + +/* + * Configuration + */ +#define FIB_ARG "24" +#define WASM_STACK_SLOTS 1024 + +/* + * WebAssembly app (recursive Fibonacci) + */ + +unsigned char fib_wasm[] = { + 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x06, 0x01, 0x60, + 0x01, 0x7f, 0x01, 0x7f, 0x03, 0x02, 0x01, 0x00, 0x07, 0x07, 0x01, 0x03, + 0x66, 0x69, 0x62, 0x00, 0x00, 0x0a, 0x1f, 0x01, 0x1d, 0x00, 0x20, 0x00, + 0x41, 0x02, 0x49, 0x04, 0x40, 0x20, 0x00, 0x0f, 0x0b, 0x20, 0x00, 0x41, + 0x02, 0x6b, 0x10, 0x00, 0x20, 0x00, 0x41, 0x01, 0x6b, 0x10, 0x00, 0x6a, + 0x0f, 0x0b +}; + +/* + * Engine start, liftoff! + */ + +#define FATAL(func, msg) { Serial.print("Fatal: " func " "); Serial.println(msg); return; } +#define TSTART() { tstart = micros(); } +#define TFINISH(s) { tend = micros(); Serial.print(s " in "); Serial.print(tend-tstart); Serial.println(" us"); } + +void wasm_task(void*) +{ + uint32_t tend, tstart; + TSTART(); + + M3Result result = m3Err_none; + + IM3Environment env = m3_NewEnvironment (); + if (!env) FATAL("NewEnvironment", "failed"); + + IM3Runtime runtime = m3_NewRuntime (env, WASM_STACK_SLOTS, NULL); + if (!runtime) FATAL("NewRuntime", "failed"); + + IM3Module module; + result = m3_ParseModule (env, &module, fib_wasm, sizeof(fib_wasm)-1); + if (result) FATAL("ParseModule", result); + + result = m3_LoadModule (runtime, module); + if (result) FATAL("LoadModule", result); + + IM3Function f; + result = m3_FindFunction (&f, runtime, "fib"); + if (result) FATAL("FindFunction", result); + + TFINISH("Init"); + + Serial.println("Running fib(" FIB_ARG ")..."); + + TSTART(); + + const char* i_argv[2] = { FIB_ARG , NULL }; + result = m3_CallWithArgs (f, 1, i_argv); + + TFINISH("Done"); + + if (result == m3Err_none) { + uint32_t value = *(uint32_t*)(runtime->stack); + Serial.print("Result: "); + Serial.println(value); + } else { + M3ErrorInfo info; + m3_GetErrorInfo (runtime, &info); + Serial.print("Error: "); + Serial.print(result); + Serial.print(" ("); + Serial.print(info.message); + Serial.println(")"); + if (info.file && strlen(info.file) && info.line) { + Serial.print("At "); + Serial.print(info.file); + Serial.print(":"); + Serial.println(info.line); + } + } +#ifdef ESP32 + vTaskDelete(NULL); +#endif +} + +void setup() +{ + Serial.begin(115200); + delay(100); + + // Wait for serial port to connect + // Needed for native USB port only + while(!Serial) {} + + Serial.println("\nWasm3 v" M3_VERSION " (" M3_ARCH "), build " __DATE__ " " __TIME__); + +#ifdef ESP32 + // On ESP32, we can launch in a separate thread (with 16Kb stack) + Serial.println("Running a separate task"); + xTaskCreate(&wasm_task, "wasm3", 16*1024, NULL, 5, NULL); +#else + wasm_task(NULL); +#endif +} + +void loop() +{ + delay(100); +} diff --git a/examples_pio/Wasm_Advanced/platformio.ini b/examples_pio/Wasm_Advanced/platformio.ini index 0f242de..811ad85 100644 --- a/examples_pio/Wasm_Advanced/platformio.ini +++ b/examples_pio/Wasm_Advanced/platformio.ini @@ -49,6 +49,20 @@ src_build_flags = -DESP8266 -Dd_m3FixedHeap=0x6000 -O3 -flto +[env:AdafruitPyBadge] +platform = atmelsam +board = adafruit_pybadge_m4 + +src_build_flags = + ${env.src_build_flags} + -DLED_PIN=13 + -O3 -flto + +#build_flags = +# -Dd_m3LogNativeStack=1 +# -Dd_m3LogOutput=1 +# -Dd_m3VerboseLogs=1 + [env:Arduino101] platform = intel_arc32 board = genuino101 diff --git a/examples_pio/Wasm_Advanced/wasm_vm/wasm_vm.ino b/examples_pio/Wasm_Advanced/wasm_vm/wasm_vm.ino index 393151d..9bd1c43 100644 --- a/examples_pio/Wasm_Advanced/wasm_vm/wasm_vm.ino +++ b/examples_pio/Wasm_Advanced/wasm_vm/wasm_vm.ino @@ -206,6 +206,12 @@ void wasm_task(void*) Serial.print(" ("); Serial.print(info.message); Serial.println(")"); + if (info.file && strlen(info.file) && info.line) { + Serial.print("At "); + Serial.print(info.file); + Serial.print(":"); + Serial.println(info.line); + } } } @@ -218,7 +224,7 @@ void setup() // Needed for native USB port only while(!Serial) {} - Serial.println("\nWasm3 v" M3_VERSION ", build " __DATE__ " " __TIME__); + Serial.println("\nWasm3 v" M3_VERSION " (" M3_ARCH "), build " __DATE__ " " __TIME__); #ifdef ESP32 // On ESP32, we can launch in a separate thread diff --git a/library.json b/library.json index dfb590a..274baa0 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "Wasm3", - "version": "0.4.5", + "version": "0.4.8", "description": "The fastest WebAssembly interpreter. It allows you to run WASM files directly on a wide range of devices, including microcontrollers, routers, smartphones and of course within browsers.", "keywords": "esp32, esp8266, wasm, webassembly, interpreter, iot, edge computing", "authors": [ diff --git a/library.properties b/library.properties index 8f2dff6..518dec0 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Wasm3 -version=0.4.5 +version=0.4.8 author=Volodymyr Shymanskyy , Steven Massey license=MIT maintainer=Volodymyr Shymanskyy diff --git a/src/m3_api_defs.h b/src/m3_api_defs.h index a0fc478..33d028e 100644 --- a/src/m3_api_defs.h +++ b/src/m3_api_defs.h @@ -18,7 +18,7 @@ #define m3ApiGetArg(TYPE, NAME) TYPE NAME = * ((TYPE *) (_sp++)); #define m3ApiGetArgMem(TYPE, NAME) TYPE NAME = (TYPE)m3ApiOffsetToPtr(* ((u32 *) (_sp++))); -#define m3ApiRawFunction(NAME) const void * NAME (IM3Runtime runtime, uint64_t * _sp, void * _mem) +#define m3ApiRawFunction(NAME) const void * NAME (IM3Runtime runtime, uint64_t * _sp, void * _mem, void * userdata) #define m3ApiReturn(VALUE) { *raw_return = (VALUE); return m3Err_none; } #define m3ApiTrap(VALUE) { return VALUE; } #define m3ApiSuccess() { return m3Err_none; } diff --git a/src/m3_api_libc.c b/src/m3_api_libc.c index 3b8333f..d34e967 100644 --- a/src/m3_api_libc.c +++ b/src/m3_api_libc.c @@ -43,7 +43,6 @@ m3ApiRawFunction(m3_libc_memset) m3ApiReturn(result); } - m3ApiRawFunction(m3_libc_memmove) { m3ApiReturnType (int32_t) diff --git a/src/m3_bind.c b/src/m3_bind.c index fcd14e1..4df95d6 100644 --- a/src/m3_bind.c +++ b/src/m3_bind.c @@ -14,14 +14,14 @@ u8 ConvertTypeCharToTypeId (char i_code) { switch (i_code) { - case 'v': return c_m3Type_void; + case 'v': return c_m3Type_none; case 'i': return c_m3Type_i32; case 'I': return c_m3Type_i64; case 'f': return c_m3Type_f32; case 'F': return c_m3Type_f64; - case '*': return c_m3Type_ptr; + case '*': return c_m3Type_i32; } - return c_m3Type_none; + return c_m3Type_unknown; } @@ -39,15 +39,11 @@ _try { cstr_t sig = i_signature; - bool hasReturn = false; - - size_t maxNumArgs = strlen (i_signature); - _throwif (m3Err_malformedFunctionSignature, maxNumArgs < 3); - - maxNumArgs -= 3; // "v()" + int maxNumArgs = strlen (i_signature) - 2; // "()" + _throwif (m3Err_malformedFunctionSignature, maxNumArgs < 0); _throwif ("insane argument count", maxNumArgs > d_m3MaxSaneFunctionArgCount); -_ (AllocFuncType (& funcType, (u32) maxNumArgs)); +_ (AllocFuncType (& funcType, maxNumArgs)); bool parsingArgs = false; while (* sig) @@ -56,9 +52,6 @@ _ (AllocFuncType (& funcType, (u32) maxNumArgs)); if (typeChar == '(') { - if (not hasReturn) - break; - parsingArgs = true; continue; } @@ -69,41 +62,25 @@ _ (AllocFuncType (& funcType, (u32) maxNumArgs)); u8 type = ConvertTypeCharToTypeId (typeChar); - if (not type) - _throw ("unknown argument type char"); + _throwif ("unknown argument type char", c_m3Type_unknown == type); + + if (type == c_m3Type_none) + continue; 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; - if (type == c_m3Type_ptr) - type = c_m3Type_i32; + _throwif ("malformed function signature; too many return types", funcType->numRets >= 1); - funcType->returnType = type; + funcType->types [funcType->numRets++] = type; } else { _throwif (m3Err_malformedFunctionSignature, funcType->numArgs >= maxNumArgs); // forgot trailing ')' ? - if (type != c_m3Type_runtime) - { - if (type == c_m3Type_ptr) - type = c_m3Type_i32; - - funcType->argTypes [funcType->numArgs++] = type; - } + funcType->types [funcType->numRets + funcType->numArgs++] = type; } } - if (not hasReturn) - _throw (m3Err_funcSignatureMissingReturnType); - } _catch: if (result) @@ -139,47 +116,14 @@ _ (SignatureToFuncType (& ftype, i_linkingSignature)); } -typedef M3Result (* M3Linker) (IM3Module io_module, IM3Function io_function, const char * const i_signature, const void * i_function); - -M3Result FindAndLinkFunction (IM3Module io_module, - ccstr_t i_moduleName, - ccstr_t i_functionName, - ccstr_t i_signature, - voidptr_t i_function, - const M3Linker i_linker) -{ - M3Result result = m3Err_functionLookupFailed; - - bool wildcardModule = (strcmp (i_moduleName, "*") == 0); - - for (u32 i = 0; i < io_module->numFunctions; ++i) - { - IM3Function f = & io_module->functions [i]; - - if (f->import.moduleUtf8 and f->import.fieldUtf8) - { - if (strcmp (f->import.fieldUtf8, i_functionName) == 0 and - (wildcardModule or strcmp (f->import.moduleUtf8, i_moduleName) == 0)) - { - result = i_linker (io_module, f, i_signature, i_function); - if (result) return result; - } - } - } - - return result; -} - -// -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - -M3Result LinkRawFunction (IM3Module io_module, IM3Function io_function, ccstr_t signature, const void * i_function) +M3Result LinkRawFunction (IM3Module io_module, IM3Function io_function, ccstr_t signature, const void * i_function, const void * i_userdata) { M3Result result = m3Err_none; d_m3Assert (io_module->runtime); _try { _ (ValidateSignature (io_function, signature)); - IM3CodePage page = AcquireCodePageWithCapacity (io_module->runtime, 2); + IM3CodePage page = AcquireCodePageWithCapacity (io_module->runtime, 4); if (page) { @@ -188,6 +132,8 @@ _ (ValidateSignature (io_function, signature)); EmitWord (page, op_CallRawFunction); EmitWord (page, i_function); + EmitWord (page, io_function); + EmitWord (page, i_userdata); ReleaseCodePage (io_module->runtime, page); } @@ -197,23 +143,15 @@ _ (ValidateSignature (io_function, signature)); return result; } - -M3Result m3_LinkRawFunction (IM3Module io_module, - const char * const i_moduleName, - const char * const i_functionName, - const char * const i_signature, - M3RawCall i_function) +M3Result FindAndLinkFunction (IM3Module io_module, + ccstr_t i_moduleName, + ccstr_t i_functionName, + ccstr_t i_signature, + voidptr_t i_function, + voidptr_t i_userdata) { - return FindAndLinkFunction (io_module, i_moduleName, i_functionName, i_signature, (voidptr_t)i_function, LinkRawFunction); -} - -// -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + M3Result result = m3Err_functionLookupFailed; -IM3Function FindFunction (IM3Module io_module, - ccstr_t i_moduleName, - ccstr_t i_functionName, - ccstr_t i_signature) -{ bool wildcardModule = (strcmp (i_moduleName, "*") == 0); for (u32 i = 0; i < io_module->numFunctions; ++i) @@ -225,37 +163,12 @@ IM3Function FindFunction (IM3Module io_module, if (strcmp (f->import.fieldUtf8, i_functionName) == 0 and (wildcardModule or strcmp (f->import.moduleUtf8, i_moduleName) == 0)) { - return f; + result = LinkRawFunction (io_module, f, i_signature, i_function, i_userdata); + if (result) return result; } } } - return NULL; -} - -M3Result LinkRawFunctionEx (IM3Module io_module, IM3Function io_function, ccstr_t signature, const void * i_function, void * cookie) -{ - M3Result result = m3Err_none; d_m3Assert (io_module->runtime); - -_try { -_ (ValidateSignature (io_function, signature)); - - IM3CodePage page = AcquireCodePageWithCapacity (io_module->runtime, 3); - - if (page) - { - io_function->compiled = GetPagePC (page); - io_function->module = io_module; - - EmitWord (page, op_CallRawFunctionEx); - EmitWord (page, i_function); - EmitWord (page, cookie); - - ReleaseCodePage (io_module->runtime, page); - } - else _throw(m3Err_mallocFailedCodePage); - -} _catch: return result; } @@ -263,13 +176,18 @@ M3Result m3_LinkRawFunctionEx (IM3Module io_module, const char * const i_moduleName, const char * const i_functionName, const char * const i_signature, - M3RawCallEx i_function, - void * i_cookie) + M3RawCall i_function, + const void * i_userdata) { - IM3Function f = FindFunction(io_module, i_moduleName, i_functionName, i_signature); - if (f == NULL) - return m3Err_functionLookupFailed; + return FindAndLinkFunction (io_module, i_moduleName, i_functionName, i_signature, (voidptr_t)i_function, i_userdata); +} - M3Result result = LinkRawFunctionEx(io_module, f, i_signature, (voidptr_t)i_function, i_cookie); - return result; +M3Result m3_LinkRawFunction (IM3Module io_module, + const char * const i_moduleName, + const char * const i_functionName, + const char * const i_signature, + M3RawCall i_function) +{ + return FindAndLinkFunction (io_module, i_moduleName, i_functionName, i_signature, (voidptr_t)i_function, NULL); } + diff --git a/src/m3_bind.h b/src/m3_bind.h new file mode 100644 index 0000000..a80317a --- /dev/null +++ b/src/m3_bind.h @@ -0,0 +1,20 @@ +// +// m3_bind.h +// +// 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_env.h" + +d_m3BeginExternC + +u8 ConvertTypeCharToTypeId (char i_code); +M3Result SignatureToFuncType (IM3FuncType * o_functionType, ccstr_t i_signature); + +d_m3EndExternC + +#endif /* m3_bind_h */ diff --git a/src/m3_compile.c b/src/m3_compile.c index 3a34b18..0066d94 100644 --- a/src/m3_compile.c +++ b/src/m3_compile.c @@ -14,7 +14,7 @@ //------------------------------------------------------------------------------------------------------------------------- -#define d_indent " | " +#define d_indent " | %s" // just want less letter and numbers to stare at down the way in the compiler table #define i_32 c_m3Type_i32 @@ -24,7 +24,33 @@ #define none c_m3Type_none #define any (u8)-1 -static const IM3Operation c_setSetOps [] = { NULL, op_SetSlot_i32, op_SetSlot_i64, op_SetSlot_f32, op_SetSlot_f64 }; +#if d_m3HasFloat +#define FPOP(x) x +#else +#define FPOP(x) NULL +#endif + +static const IM3Operation c_preserveSetSlot [] = { NULL, op_PreserveSetSlot_i32, op_PreserveSetSlot_i64, + FPOP(op_PreserveSetSlot_f32), FPOP(op_PreserveSetSlot_f64) }; +static const IM3Operation c_setSetOps [] = { NULL, op_SetSlot_i32, op_SetSlot_i64, + FPOP(op_SetSlot_f32), FPOP(op_SetSlot_f64) }; +static const IM3Operation c_setGlobalOps [] = { NULL, op_SetGlobal_i32, op_SetGlobal_i64, + FPOP(op_SetGlobal_f32), FPOP(op_SetGlobal_f64) }; +static const IM3Operation c_setRegisterOps [] = { NULL, op_SetRegister_i32, op_SetRegister_i64, + FPOP(op_SetRegister_f32), FPOP(op_SetRegister_f64) }; + +static const IM3Operation c_ifOps [2] [2] = { { op_i32_BranchIf_ss, op_i32_BranchIf_rs }, + { op_i64_BranchIf_ss, op_i64_BranchIf_rs } }; + +static const IM3Operation c_intSelectOps [2] [4] = { { op_Select_i32_rss, op_Select_i32_srs, op_Select_i32_ssr, op_Select_i32_sss }, + { op_Select_i64_rss, op_Select_i64_srs, op_Select_i64_ssr, op_Select_i64_sss } }; + +#if d_m3HasFloat +static const IM3Operation c_fpSelectOps [2] [2] [3] = { { { op_Select_f32_sss, op_Select_f32_srs, op_Select_f32_ssr }, // selector in slot + { op_Select_f32_rss, op_Select_f32_rrs, op_Select_f32_rsr } }, // selector in reg + { { op_Select_f64_sss, op_Select_f64_srs, op_Select_f64_ssr }, // selector in slot + { op_Select_f64_rss, op_Select_f64_rrs, op_Select_f64_rsr } } }; // selector in reg +#endif static const u16 c_m3RegisterUnallocated = 0; static const u16 c_slotUnused = 0xffff; @@ -75,8 +101,6 @@ bool IsRegisterLocation (i16 i_location) { return (i_location >= d_m3 bool IsFpRegisterLocation (i16 i_location) { return (i_location == d_m3Fp0SlotAlias); } bool IsIntRegisterLocation (i16 i_location) { return (i_location == d_m3Reg0SlotAlias); } -u8 GetBlockType (IM3Compilation o) { return o->block.type; } -bool BlockHasType (IM3Compilation o) { return GetBlockType (o) != c_m3Type_none; } i16 GetNumBlockValues (IM3Compilation o) { return o->stackIndex - o->block.initStackIndex; } u16 GetTypeNumSlots (u8 i_type) @@ -217,8 +241,9 @@ M3Result AllocateSlotsWithinRange (IM3Compilation o, u16 * o_slot, u8 i_type, u16 numSlots = GetTypeNumSlots (i_type); u16 searchOffset = numSlots - 1; - if (d_m3Use32BitSlots) + if (d_m3Use32BitSlots) { AlignSlotIndexToType (& i_startSlot, i_type); + } // search for 1 or 2 consecutive slots in the execution stack u16 i = i_startSlot; @@ -402,6 +427,12 @@ M3Result Push (IM3Compilation o, u8 i_type, u16 i_location) { M3Result result = m3Err_none; +#if !d_m3HasFloat + if (i_type == c_m3Type_f32 || i_type == c_m3Type_f64) { + return m3Err_unknownOpcode; + } +#endif + u16 stackIndex = o->stackIndex++; // printf ("push: %d\n", (i32) i); if (stackIndex < d_m3MaxFunctionStackHeight) @@ -423,7 +454,7 @@ M3Result Push (IM3Compilation o, u8 i_type, u16 i_location) } } - m3logif (stack, dump_type_stack (o)) + if (d_m3LogWasmStack) dump_type_stack (o); } else result = m3Err_functionStackOverflow; @@ -458,8 +489,6 @@ M3Result Pop (IM3Compilation o) { DeallocateSlot (o, slot, type); } - -// m3logif (stack, dump_type_stack (o)) } else if (not IsStackPolymorphic (o)) result = m3Err_functionStackUnderrun; @@ -759,8 +788,6 @@ M3Result PreservedCopyTopSlot (IM3Compilation o, u16 i_destSlot, u16 i_preserv if (IsStackTopInRegister (o)) { - const IM3Operation c_preserveSetSlot [] = { NULL, op_PreserveSetSlot_i32, op_PreserveSetSlot_i64, op_PreserveSetSlot_f32, op_PreserveSetSlot_f64 }; - op = c_preserveSetSlot [type]; } else op = Is64BitType (type) ? op_PreserveCopySlot_64 : op_PreserveCopySlot_32; @@ -780,8 +807,6 @@ _ (EmitOp (o, op)); M3Result MoveStackTopToRegister (IM3Compilation o) { - static const IM3Operation setRegisterOps [] = { NULL, op_SetRegister_i32, op_SetRegister_i64, op_SetRegister_f32, op_SetRegister_f64 }; - M3Result result = m3Err_none; if (IsStackTopInSlot (o)) @@ -790,7 +815,7 @@ M3Result MoveStackTopToRegister (IM3Compilation o) _ (PreserveRegisterIfOccupied (o, type)); - IM3Operation op = setRegisterOps [type]; + IM3Operation op = c_setRegisterOps [type]; _ (EmitOp (o, op)); _ (EmitTopSlotAndPop (o)); @@ -890,7 +915,7 @@ M3Result Compile_Const_i32 (IM3Compilation o, m3opcode_t i_opcode) i32 value; _ (ReadLEB_i32 (& value, & o->wasm, o->wasmEnd)); -_ (PushConst (o, value, c_m3Type_i32)); m3log (compile, d_indent "%s (const i32 = %" PRIi32 ")", get_indention_string (o), value); +_ (PushConst (o, value, c_m3Type_i32)); m3log (compile, d_indent " (const i32 = %" PRIi32 ")", get_indention_string (o), value); _catch: return result; } @@ -901,18 +926,19 @@ M3Result Compile_Const_i64 (IM3Compilation o, m3opcode_t i_opcode) i64 value; _ (ReadLEB_i64 (& value, & o->wasm, o->wasmEnd)); -_ (PushConst (o, value, c_m3Type_i64)); m3log (compile, d_indent "%s (const i64 = %" PRIi64 ")", get_indention_string (o), value); +_ (PushConst (o, value, c_m3Type_i64)); m3log (compile, d_indent " (const i64 = %" PRIi64 ")", get_indention_string (o), value); _catch: return result; } +#if d_m3HasFloat M3Result Compile_Const_f32 (IM3Compilation o, m3opcode_t i_opcode) { M3Result result; union { u32 u; f32 f; } value = { 0 }; -_ (Read_f32 (& value.f, & o->wasm, o->wasmEnd)); m3log (compile, d_indent "%s (const f32 = %f)", get_indention_string (o), value.f); +_ (Read_f32 (& value.f, & o->wasm, o->wasmEnd)); m3log (compile, d_indent " (const f32 = %f)", get_indention_string (o), value.f); _ (PushConst (o, value.u, c_m3Type_f32)); _catch: return result; @@ -925,11 +951,12 @@ M3Result Compile_Const_f64 (IM3Compilation o, m3opcode_t i_opcode) union { u64 u; f64 f; } value = { 0 }; -_ (Read_f64 (& value.f, & o->wasm, o->wasmEnd)); m3log (compile, d_indent "%s (const f64 = %lf)", get_indention_string (o), value.f); +_ (Read_f64 (& value.f, & o->wasm, o->wasmEnd)); m3log (compile, d_indent " (const f64 = %lf)", get_indention_string (o), value.f); _ (PushConst (o, value.u, c_m3Type_f64)); _catch: return result; } +#endif #ifdef d_m3CompileExtendedOpcode @@ -940,7 +967,7 @@ M3Result Compile_ExtendedOpcode (IM3Compilation o, m3opcode_t i_opcode) i32 value; u8 opcode; -_ (Read_u8 (& opcode, & o->wasm, o->wasmEnd)); m3log (compile, d_indent "%s (FC: %" PRIi32 ")", get_indention_string (o), opcode); +_ (Read_u8 (& opcode, & o->wasm, o->wasmEnd)); m3log (compile, d_indent " (FC: %" PRIi32 ")", get_indention_string (o), opcode); i_opcode = (i_opcode << 8) | opcode; @@ -964,9 +991,7 @@ M3Result Compile_Return (IM3Compilation o, m3opcode_t i_opcode) { M3Result result; - bool hasReturn = GetFunctionNumReturns (o->function); - - if (hasReturn) + if (GetFunctionNumReturns (o->function)) { _ (ReturnStackTop (o)); _ (Pop (o)); @@ -987,7 +1012,7 @@ M3Result Compile_End (IM3Compilation o, m3opcode_t i_opcode) // function end: if (o->block.depth == 0) { - u8 valueType = o->block.type; + u8 valueType = GetSingleRetType(o->block.type); if (valueType) { @@ -998,7 +1023,7 @@ M3Result Compile_End (IM3Compilation o, m3opcode_t i_opcode) if (IsStackTopInRegister (o)) PatchBranches (o); -_ (ReturnStackTop (o)); +_ (ReturnStackTop (o)); } else PatchBranches (o); // for no return type, branch to op_End @@ -1096,8 +1121,6 @@ M3Result Compile_SetGlobal (IM3Compilation o, M3Global * i_global) if (IsStackTopInRegister (o)) { - const IM3Operation c_setGlobalOps [] = { NULL, op_SetGlobal_i32, op_SetGlobal_i64, op_SetGlobal_f32, op_SetGlobal_f64 }; - op = c_setGlobalOps [type]; } else op = Is64BitType (type) ? op_SetGlobal_s64 : op_SetGlobal_s32; @@ -1173,7 +1196,7 @@ _ (EmitOp (o, op)); { u16 conditionSlot = c_slotUnused; u16 valueSlot = c_slotUnused; - u8 valueType = scope->type; + u8 valueType = GetSingleRetType(scope->type); if (i_opcode == c_waOp_branchIf) { @@ -1196,9 +1219,7 @@ _ (MoveStackTopToRegister (o)); { valueSlot = GetStackTopSlotIndex (o); - const IM3Operation ifOps [2][2] = { { op_i32_BranchIf_ss, op_i32_BranchIf_rs }, { op_i64_BranchIf_ss, op_i64_BranchIf_rs } }; - - op = ifOps [valueType - c_m3Type_i32] [conditionInRegister]; + op = c_ifOps [valueType - c_m3Type_i32] [conditionInRegister]; } } } @@ -1351,12 +1372,10 @@ _ (CopyTopSlot (o, argTop -= slotsPerArg)); _ (Pop (o)); } - i32 numReturns = i_type->returnType ? 1 : 0; - - if (numReturns) + if (i_type->numRets) { MarkSlotAllocated (o, topSlot); -_ (Push (o, i_type->returnType, topSlot)); +_ (Push (o, GetSingleRetType(i_type), topSlot)); } } _catch: return result; @@ -1374,7 +1393,7 @@ _ (ReadLEB_u32 (& functionIndex, & o->wasm, o->wasmEnd)); IM3Function function = Module_GetFunction (o->module, functionIndex); if (function) - { m3log (compile, d_indent "%s (func= '%s'; args= %d)", + { m3log (compile, d_indent " (func= '%s'; args= %d)", get_indention_string (o), GetFunctionName (function), function->funcType->numArgs); if (function->module) { @@ -1477,16 +1496,27 @@ _ (PushRegister (o, c_m3Type_i32)); _catch: return result; } - -M3Result ReadBlockType (IM3Compilation o, u8 * o_blockType) +static +M3Result ReadBlockType (IM3Compilation o, IM3FuncType * o_blockType) { - M3Result result; d_m3Assert (o_blockType); - - i8 type; + M3Result result; + i64 type; +_ (ReadLebSigned (& type, 33, & o->wasm, o->wasmEnd)); -_ (ReadLEB_i7 (& type, & o->wasm, o->wasmEnd)); -_ (NormalizeType (o_blockType, type)); if (* o_blockType) m3log (compile, d_indent "%s (type: %s)", - get_indention_string (o), c_waTypes [(u32) * o_blockType]); + if (type < 0) + { + u8 valueType; +_ (NormalizeType (&valueType, type)); m3log (compile, d_indent " (type: %s)", get_indention_string (o), c_waTypes [valueType]); + *o_blockType = o->module->environment->retFuncTypes[valueType]; + } + else if (type < o->module->numFuncTypes) + { + *o_blockType = o->module->funcTypes[type]; m3log (compile, d_indent " (type: %s)", get_indention_string (o), SPrintFuncTypeSignature (*o_blockType)); + } + else + { + return "func type out of bounds"; + } _catch: return result; } @@ -1505,17 +1535,18 @@ M3Result PreserveArgsAndLocals (IM3Compilation o) for (u32 i = 0; i < numArgsAndLocals; ++i) { + u16 localSlot = GetSlotForStackIndex (o, i); u16 preservedSlotIndex; -_ (FindReferencedLocalWithinCurrentBlock (o, & preservedSlotIndex, i)); +_ (FindReferencedLocalWithinCurrentBlock (o, & preservedSlotIndex, localSlot)); - if (preservedSlotIndex != i) + if (preservedSlotIndex != localSlot) { u8 type = GetStackBottomType (o, i); IM3Operation op = Is64BitType (type) ? op_CopySlot_64 : op_CopySlot_32; EmitOp (o, op); EmitSlotOffset (o, preservedSlotIndex); - EmitSlotOffset (o, i); + EmitSlotOffset (o, localSlot); } } } @@ -1532,7 +1563,7 @@ M3Result Compile_LoopOrBlock (IM3Compilation o, m3opcode_t i_opcode) _ (PreserveRegisters (o)); _ (PreserveArgsAndLocals (o)); - u8 blockType; + IM3FuncType blockType; _ (ReadBlockType (o, & blockType)); if (i_opcode == c_waOp_loop) @@ -1544,7 +1575,7 @@ _ (CompileBlock (o, blockType, i_opcode)); } -M3Result CompileElseBlock (IM3Compilation o, pc_t * o_startPC, u8 i_blockType) +M3Result CompileElseBlock (IM3Compilation o, pc_t * o_startPC, IM3FuncType i_blockType) { M3Result result; @@ -1588,7 +1619,7 @@ _ (EmitTopSlotAndPop (o)); pc_t * pc = (pc_t *) ReservePointer (o); - u8 blockType; + IM3FuncType blockType; _ (ReadBlockType (o, & blockType)); _ (CompileBlock (o, blockType, i_opcode)); @@ -1610,13 +1641,6 @@ _ (CompileElseBlock (o, pc, blockType)); M3Result Compile_Select (IM3Compilation o, m3opcode_t i_opcode) { - static const IM3Operation intSelectOps [2] [4] = { { op_Select_i32_rss, op_Select_i32_srs, op_Select_i32_ssr, op_Select_i32_sss }, - { op_Select_i64_rss, op_Select_i64_srs, op_Select_i64_ssr, op_Select_i64_sss } }; - - static const IM3Operation fpSelectOps [2] [2] [3] = { { { op_Select_f32_sss, op_Select_f32_srs, op_Select_f32_ssr }, // selector in slot - { op_Select_f32_rss, op_Select_f32_rrs, op_Select_f32_rsr } }, // selector in reg - { { op_Select_f64_sss, op_Select_f64_srs, op_Select_f64_ssr }, // selector in slot - { op_Select_f64_rss, op_Select_f64_rrs, op_Select_f64_rsr } } }; // selector in reg M3Result result = m3Err_none; u16 slots [3] = { c_slotUnused, c_slotUnused, c_slotUnused }; @@ -1627,6 +1651,7 @@ M3Result Compile_Select (IM3Compilation o, m3opcode_t i_opcode) if (IsFpType (type)) { +#if d_m3HasFloat // not consuming a fp reg, so preserve if (not IsStackTopMinus1InRegister (o) and not IsStackTopMinus2InRegister (o)) @@ -1650,7 +1675,10 @@ _ (Pop (o)); _ (Pop (o)); } - op = fpSelectOps [type - c_m3Type_f32] [selectorInReg] [opIndex]; + op = c_fpSelectOps [type - c_m3Type_f32] [selectorInReg] [opIndex]; +#else + _throw (m3Err_unknownOpcode); +#endif } else if (IsIntType (type)) { @@ -1674,7 +1702,7 @@ _ (PreserveRegisterIfOccupied (o, type)); _ (Pop (o)); } - op = intSelectOps [type - c_m3Type_i32] [opIndex]; + op = c_intSelectOps [type - c_m3Type_i32] [opIndex]; } else if (not IsStackPolymorphic (o)) _throw (m3Err_functionStackUnderrun); @@ -1693,7 +1721,7 @@ _ (PushRegister (o, type)); M3Result Compile_Drop (IM3Compilation o, m3opcode_t i_opcode) { - M3Result result = Pop (o); m3logif (stack, dump_type_stack (o)) + M3Result result = Pop (o); if (d_m3LogWasmStack) dump_type_stack (o); return result; } @@ -1833,7 +1861,7 @@ _try { _ (ReadLEB_u32 (& alignHint, & o->wasm, o->wasmEnd)); _ (ReadLEB_u32 (& memoryOffset, & o->wasm, o->wasmEnd)); - m3log (compile, d_indent "%s (offset = %d)", get_indention_string (o), memoryOffset); + m3log (compile, d_indent " (offset = %d)", get_indention_string (o), memoryOffset); const M3OpInfo * op = GetOpInfo(i_opcode); if (IsFpType (op->type)) @@ -1898,8 +1926,8 @@ const M3OpInfo c_operations [] = M3OP( "i32.load", 0, i_32, d_unaryOpList (i32, Load_i32), Compile_Load_Store ), // 0x28 M3OP( "i64.load", 0, i_64, d_unaryOpList (i64, Load_i64), Compile_Load_Store ), // 0x29 - M3OP( "f32.load", 0, f_32, d_unaryOpList (f32, Load_f32), Compile_Load_Store ), // 0x2a - M3OP( "f64.load", 0, f_64, d_unaryOpList (f64, Load_f64), Compile_Load_Store ), // 0x2b + M3OP_F( "f32.load", 0, f_32, d_unaryOpList (f32, Load_f32), Compile_Load_Store ), // 0x2a + M3OP_F( "f64.load", 0, f_64, d_unaryOpList (f64, Load_f64), Compile_Load_Store ), // 0x2b M3OP( "i32.load8_s", 0, i_32, d_unaryOpList (i32, Load_i8), Compile_Load_Store ), // 0x2c M3OP( "i32.load8_u", 0, i_32, d_unaryOpList (i32, Load_u8), Compile_Load_Store ), // 0x2d @@ -1915,8 +1943,8 @@ const M3OpInfo c_operations [] = M3OP( "i32.store", -2, none, d_binOpList (i32, Store_i32), Compile_Load_Store ), // 0x36 M3OP( "i64.store", -2, none, d_binOpList (i64, Store_i64), Compile_Load_Store ), // 0x37 - M3OP( "f32.store", -2, none, d_storeFpOpList (f32, Store_f32), Compile_Load_Store ), // 0x38 - M3OP( "f64.store", -2, none, d_storeFpOpList (f64, Store_f64), Compile_Load_Store ), // 0x39 + M3OP_F( "f32.store", -2, none, d_storeFpOpList (f32, Store_f32), Compile_Load_Store ), // 0x38 + M3OP_F( "f64.store", -2, none, d_storeFpOpList (f64, Store_f64), Compile_Load_Store ), // 0x39 M3OP( "i32.store8", -2, none, d_binOpList (i32, Store_u8), Compile_Load_Store ), // 0x3a M3OP( "i32.store16", -2, none, d_binOpList (i32, Store_i16), Compile_Load_Store ), // 0x3b @@ -1930,157 +1958,157 @@ const M3OpInfo c_operations [] = M3OP( "i32.const", 1, i_32, d_logOp (Const32), Compile_Const_i32 ), // 0x41 M3OP( "i64.const", 1, i_64, d_logOp (Const64), Compile_Const_i64 ), // 0x42 - M3OP( "f32.const", 1, f_32, d_emptyOpList, Compile_Const_f32 ), // 0x43 - M3OP( "f64.const", 1, f_64, d_emptyOpList, Compile_Const_f64 ), // 0x44 - - M3OP( "i32.eqz", 0, i_32, d_unaryOpList (i32, EqualToZero) ), // 0x45 - M3OP( "i32.eq", -1, i_32, d_commutativeBinOpList (i32, Equal) ), // 0x46 - M3OP( "i32.ne", -1, i_32, d_commutativeBinOpList (i32, NotEqual) ), // 0x47 - M3OP( "i32.lt_s", -1, i_32, d_binOpList (i32, LessThan) ), // 0x48 - M3OP( "i32.lt_u", -1, i_32, d_binOpList (u32, LessThan) ), // 0x49 - M3OP( "i32.gt_s", -1, i_32, d_binOpList (i32, GreaterThan) ), // 0x4a - M3OP( "i32.gt_u", -1, i_32, d_binOpList (u32, GreaterThan) ), // 0x4b - M3OP( "i32.le_s", -1, i_32, d_binOpList (i32, LessThanOrEqual) ), // 0x4c - M3OP( "i32.le_u", -1, i_32, d_binOpList (u32, LessThanOrEqual) ), // 0x4d - M3OP( "i32.ge_s", -1, i_32, d_binOpList (i32, GreaterThanOrEqual) ), // 0x4e - M3OP( "i32.ge_u", -1, i_32, d_binOpList (u32, GreaterThanOrEqual) ), // 0x4f - - M3OP( "i64.eqz", 0, i_32, d_unaryOpList (i64, EqualToZero) ), // 0x50 - M3OP( "i64.eq", -1, i_32, d_commutativeBinOpList (i64, Equal) ), // 0x51 - M3OP( "i64.ne", -1, i_32, d_commutativeBinOpList (i64, NotEqual) ), // 0x52 - M3OP( "i64.lt_s", -1, i_32, d_binOpList (i64, LessThan) ), // 0x53 - M3OP( "i64.lt_u", -1, i_32, d_binOpList (u64, LessThan) ), // 0x54 - M3OP( "i64.gt_s", -1, i_32, d_binOpList (i64, GreaterThan) ), // 0x55 - M3OP( "i64.gt_u", -1, i_32, d_binOpList (u64, GreaterThan) ), // 0x56 - M3OP( "i64.le_s", -1, i_32, d_binOpList (i64, LessThanOrEqual) ), // 0x57 - M3OP( "i64.le_u", -1, i_32, d_binOpList (u64, LessThanOrEqual) ), // 0x58 - M3OP( "i64.ge_s", -1, i_32, d_binOpList (i64, GreaterThanOrEqual) ), // 0x59 - M3OP( "i64.ge_u", -1, i_32, d_binOpList (u64, GreaterThanOrEqual) ), // 0x5a - - M3OP( "f32.eq", -1, i_32, d_commutativeBinOpList (f32, Equal) ), // 0x5b - M3OP( "f32.ne", -1, i_32, d_commutativeBinOpList (f32, NotEqual) ), // 0x5c - M3OP( "f32.lt", -1, i_32, d_binOpList (f32, LessThan) ), // 0x5d - M3OP( "f32.gt", -1, i_32, d_binOpList (f32, GreaterThan) ), // 0x5e - M3OP( "f32.le", -1, i_32, d_binOpList (f32, LessThanOrEqual) ), // 0x5f - M3OP( "f32.ge", -1, i_32, d_binOpList (f32, GreaterThanOrEqual) ), // 0x60 - - M3OP( "f64.eq", -1, i_32, d_commutativeBinOpList (f64, Equal) ), // 0x61 - M3OP( "f64.ne", -1, i_32, d_commutativeBinOpList (f64, NotEqual) ), // 0x62 - M3OP( "f64.lt", -1, i_32, d_binOpList (f64, LessThan) ), // 0x63 - M3OP( "f64.gt", -1, i_32, d_binOpList (f64, GreaterThan) ), // 0x64 - M3OP( "f64.le", -1, i_32, d_binOpList (f64, LessThanOrEqual) ), // 0x65 - M3OP( "f64.ge", -1, i_32, d_binOpList (f64, GreaterThanOrEqual) ), // 0x66 - - M3OP( "i32.clz", 0, i_32, d_unaryOpList (u32, Clz) ), // 0x67 - M3OP( "i32.ctz", 0, i_32, d_unaryOpList (u32, Ctz) ), // 0x68 - M3OP( "i32.popcnt", 0, i_32, d_unaryOpList (u32, Popcnt) ), // 0x69 - - M3OP( "i32.add", -1, i_32, d_commutativeBinOpList (i32, Add) ), // 0x6a - M3OP( "i32.sub", -1, i_32, d_binOpList (i32, Subtract) ), // 0x6b - M3OP( "i32.mul", -1, i_32, d_commutativeBinOpList (i32, Multiply) ), // 0x6c - M3OP( "i32.div_s", -1, i_32, d_binOpList (i32, Divide) ), // 0x6d - M3OP( "i32.div_u", -1, i_32, d_binOpList (u32, Divide) ), // 0x6e - M3OP( "i32.rem_s", -1, i_32, d_binOpList (i32, Remainder) ), // 0x6f - M3OP( "i32.rem_u", -1, i_32, d_binOpList (u32, Remainder) ), // 0x70 - M3OP( "i32.and", -1, i_32, d_commutativeBinOpList (u32, And) ), // 0x71 - M3OP( "i32.or", -1, i_32, d_commutativeBinOpList (u32, Or) ), // 0x72 - M3OP( "i32.xor", -1, i_32, d_commutativeBinOpList (u32, Xor) ), // 0x73 - M3OP( "i32.shl", -1, i_32, d_binOpList (u32, ShiftLeft) ), // 0x74 - M3OP( "i32.shr_s", -1, i_32, d_binOpList (i32, ShiftRight) ), // 0x75 - M3OP( "i32.shr_u", -1, i_32, d_binOpList (u32, ShiftRight) ), // 0x76 - M3OP( "i32.rotl", -1, i_32, d_binOpList (u32, Rotl) ), // 0x77 - M3OP( "i32.rotr", -1, i_32, d_binOpList (u32, Rotr) ), // 0x78 - - M3OP( "i64.clz", 0, i_64, d_unaryOpList (u64, Clz) ), // 0x79 - M3OP( "i64.ctz", 0, i_64, d_unaryOpList (u64, Ctz) ), // 0x7a - M3OP( "i64.popcnt", 0, i_64, d_unaryOpList (u64, Popcnt) ), // 0x7b - - M3OP( "i64.add", -1, i_64, d_commutativeBinOpList (i64, Add) ), // 0x7c - M3OP( "i64.sub", -1, i_64, d_binOpList (i64, Subtract) ), // 0x7d - M3OP( "i64.mul", -1, i_64, d_commutativeBinOpList (i64, Multiply) ), // 0x7e - M3OP( "i64.div_s", -1, i_64, d_binOpList (i64, Divide) ), // 0x7f - M3OP( "i64.div_u", -1, i_64, d_binOpList (u64, Divide) ), // 0x80 - M3OP( "i64.rem_s", -1, i_64, d_binOpList (i64, Remainder) ), // 0x81 - M3OP( "i64.rem_u", -1, i_64, d_binOpList (u64, Remainder) ), // 0x82 - M3OP( "i64.and", -1, i_64, d_commutativeBinOpList (u64, And) ), // 0x83 - M3OP( "i64.or", -1, i_64, d_commutativeBinOpList (u64, Or) ), // 0x84 - M3OP( "i64.xor", -1, i_64, d_commutativeBinOpList (u64, Xor) ), // 0x85 - M3OP( "i64.shl", -1, i_64, d_binOpList (u64, ShiftLeft) ), // 0x86 - M3OP( "i64.shr_s", -1, i_64, d_binOpList (i64, ShiftRight) ), // 0x87 - M3OP( "i64.shr_u", -1, i_64, d_binOpList (u64, ShiftRight) ), // 0x88 - M3OP( "i64.rotl", -1, i_64, d_binOpList (u64, Rotl) ), // 0x89 - M3OP( "i64.rotr", -1, i_64, d_binOpList (u64, Rotr) ), // 0x8a - - M3OP( "f32.abs", 0, f_32, d_unaryOpList(f32, Abs) ), // 0x8b - M3OP( "f32.neg", 0, f_32, d_unaryOpList(f32, Negate) ), // 0x8c - M3OP( "f32.ceil", 0, f_32, d_unaryOpList(f32, Ceil) ), // 0x8d - M3OP( "f32.floor", 0, f_32, d_unaryOpList(f32, Floor) ), // 0x8e - M3OP( "f32.trunc", 0, f_32, d_unaryOpList(f32, Trunc) ), // 0x8f - M3OP( "f32.nearest", 0, f_32, d_unaryOpList(f32, Nearest) ), // 0x90 - M3OP( "f32.sqrt", 0, f_32, d_unaryOpList(f32, Sqrt) ), // 0x91 - - M3OP( "f32.add", -1, f_32, d_commutativeBinOpList (f32, Add) ), // 0x92 - M3OP( "f32.sub", -1, f_32, d_binOpList (f32, Subtract) ), // 0x93 - M3OP( "f32.mul", -1, f_32, d_commutativeBinOpList (f32, Multiply) ), // 0x94 - M3OP( "f32.div", -1, f_32, d_binOpList (f32, Divide) ), // 0x95 - M3OP( "f32.min", -1, f_32, d_commutativeBinOpList (f32, Min) ), // 0x96 - M3OP( "f32.max", -1, f_32, d_commutativeBinOpList (f32, Max) ), // 0x97 - M3OP( "f32.copysign", -1, f_32, d_binOpList (f32, CopySign) ), // 0x98 - - M3OP( "f64.abs", 0, f_64, d_unaryOpList(f64, Abs) ), // 0x99 - M3OP( "f64.neg", 0, f_64, d_unaryOpList(f64, Negate) ), // 0x9a - M3OP( "f64.ceil", 0, f_64, d_unaryOpList(f64, Ceil) ), // 0x9b - M3OP( "f64.floor", 0, f_64, d_unaryOpList(f64, Floor) ), // 0x9c - M3OP( "f64.trunc", 0, f_64, d_unaryOpList(f64, Trunc) ), // 0x9d - M3OP( "f64.nearest", 0, f_64, d_unaryOpList(f64, Nearest) ), // 0x9e - M3OP( "f64.sqrt", 0, f_64, d_unaryOpList(f64, Sqrt) ), // 0x9f - - M3OP( "f64.add", -1, f_64, d_commutativeBinOpList (f64, Add) ), // 0xa0 - M3OP( "f64.sub", -1, f_64, d_binOpList (f64, Subtract) ), // 0xa1 - M3OP( "f64.mul", -1, f_64, d_commutativeBinOpList (f64, Multiply) ), // 0xa2 - M3OP( "f64.div", -1, f_64, d_binOpList (f64, Divide) ), // 0xa3 - M3OP( "f64.min", -1, f_64, d_commutativeBinOpList (f64, Min) ), // 0xa4 - M3OP( "f64.max", -1, f_64, d_commutativeBinOpList (f64, Max) ), // 0xa5 - M3OP( "f64.copysign", -1, f_64, d_binOpList (f64, CopySign) ), // 0xa6 - - M3OP( "i32.wrap/i64", 0, i_32, d_unaryOpList (i32, Wrap_i64) ), // 0xa7 - M3OP( "i32.trunc_s/f32", 0, i_32, d_convertOpList (i32_Trunc_f32), Compile_Convert ), // 0xa8 - M3OP( "i32.trunc_u/f32", 0, i_32, d_convertOpList (u32_Trunc_f32), Compile_Convert ), // 0xa9 - M3OP( "i32.trunc_s/f64", 0, i_32, d_convertOpList (i32_Trunc_f64), Compile_Convert ), // 0xaa - M3OP( "i32.trunc_u/f64", 0, i_32, d_convertOpList (u32_Trunc_f64), Compile_Convert ), // 0xab - - M3OP( "i64.extend_s/i32", 0, i_64, d_unaryOpList (i64, Extend_i32) ), // 0xac - M3OP( "i64.extend_u/i32", 0, i_64, d_unaryOpList (i64, Extend_u32) ), // 0xad - - M3OP( "i64.trunc_s/f32", 0, i_64, d_convertOpList (i64_Trunc_f32), Compile_Convert ), // 0xae - M3OP( "i64.trunc_u/f32", 0, i_64, d_convertOpList (u64_Trunc_f32), Compile_Convert ), // 0xaf - M3OP( "i64.trunc_s/f64", 0, i_64, d_convertOpList (i64_Trunc_f64), Compile_Convert ), // 0xb0 - M3OP( "i64.trunc_u/f64", 0, i_64, d_convertOpList (u64_Trunc_f64), Compile_Convert ), // 0xb1 - - M3OP( "f32.convert_s/i32", 0, f_32, d_convertOpList (f32_Convert_i32), Compile_Convert ), // 0xb2 - M3OP( "f32.convert_u/i32", 0, f_32, d_convertOpList (f32_Convert_u32), Compile_Convert ), // 0xb3 - M3OP( "f32.convert_s/i64", 0, f_32, d_convertOpList (f32_Convert_i64), Compile_Convert ), // 0xb4 - M3OP( "f32.convert_u/i64", 0, f_32, d_convertOpList (f32_Convert_u64), Compile_Convert ), // 0xb5 - - M3OP( "f32.demote/f64", 0, f_32, d_unaryOpList (f32, Demote_f64) ), // 0xb6 - - M3OP( "f64.convert_s/i32", 0, f_64, d_convertOpList (f64_Convert_i32), Compile_Convert ), // 0xb7 - M3OP( "f64.convert_u/i32", 0, f_64, d_convertOpList (f64_Convert_u32), Compile_Convert ), // 0xb8 - M3OP( "f64.convert_s/i64", 0, f_64, d_convertOpList (f64_Convert_i64), Compile_Convert ), // 0xb9 - M3OP( "f64.convert_u/i64", 0, f_64, d_convertOpList (f64_Convert_u64), Compile_Convert ), // 0xba - - M3OP( "f64.promote/f32", 0, f_64, d_unaryOpList (f64, Promote_f32) ), // 0xbb - - M3OP( "i32.reinterpret/f32", 0, i_32, d_convertOpList (i32_Reinterpret_f32), Compile_Convert ), // 0xbc - M3OP( "i64.reinterpret/f64", 0, i_64, d_convertOpList (i64_Reinterpret_f64), Compile_Convert ), // 0xbd - M3OP( "f32.reinterpret/i32", 0, f_32, d_convertOpList (f32_Reinterpret_i32), Compile_Convert ), // 0xbe - M3OP( "f64.reinterpret/i64", 0, f_64, d_convertOpList (f64_Reinterpret_i64), Compile_Convert ), // 0xbf - - M3OP( "i32.extend8_s", 0, i_32, d_unaryOpList (i32, Extend8_s) ), // 0xc0 - M3OP( "i32.extend16_s", 0, i_32, d_unaryOpList (i32, Extend16_s) ), // 0xc1 - M3OP( "i64.extend8_s", 0, i_64, d_unaryOpList (i64, Extend8_s) ), // 0xc2 - M3OP( "i64.extend16_s", 0, i_64, d_unaryOpList (i64, Extend16_s) ), // 0xc3 - M3OP( "i64.extend32_s", 0, i_64, d_unaryOpList (i64, Extend32_s) ), // 0xc4 + M3OP_F( "f32.const", 1, f_32, d_emptyOpList, Compile_Const_f32 ), // 0x43 + M3OP_F( "f64.const", 1, f_64, d_emptyOpList, Compile_Const_f64 ), // 0x44 + + M3OP( "i32.eqz", 0, i_32, d_unaryOpList (i32, EqualToZero) , NULL ), // 0x45 + M3OP( "i32.eq", -1, i_32, d_commutativeBinOpList (i32, Equal) , NULL ), // 0x46 + M3OP( "i32.ne", -1, i_32, d_commutativeBinOpList (i32, NotEqual) , NULL ), // 0x47 + M3OP( "i32.lt_s", -1, i_32, d_binOpList (i32, LessThan) , NULL ), // 0x48 + M3OP( "i32.lt_u", -1, i_32, d_binOpList (u32, LessThan) , NULL ), // 0x49 + M3OP( "i32.gt_s", -1, i_32, d_binOpList (i32, GreaterThan) , NULL ), // 0x4a + M3OP( "i32.gt_u", -1, i_32, d_binOpList (u32, GreaterThan) , NULL ), // 0x4b + M3OP( "i32.le_s", -1, i_32, d_binOpList (i32, LessThanOrEqual) , NULL ), // 0x4c + M3OP( "i32.le_u", -1, i_32, d_binOpList (u32, LessThanOrEqual) , NULL ), // 0x4d + M3OP( "i32.ge_s", -1, i_32, d_binOpList (i32, GreaterThanOrEqual) , NULL ), // 0x4e + M3OP( "i32.ge_u", -1, i_32, d_binOpList (u32, GreaterThanOrEqual) , NULL ), // 0x4f + + M3OP( "i64.eqz", 0, i_32, d_unaryOpList (i64, EqualToZero) , NULL ), // 0x50 + M3OP( "i64.eq", -1, i_32, d_commutativeBinOpList (i64, Equal) , NULL ), // 0x51 + M3OP( "i64.ne", -1, i_32, d_commutativeBinOpList (i64, NotEqual) , NULL ), // 0x52 + M3OP( "i64.lt_s", -1, i_32, d_binOpList (i64, LessThan) , NULL ), // 0x53 + M3OP( "i64.lt_u", -1, i_32, d_binOpList (u64, LessThan) , NULL ), // 0x54 + M3OP( "i64.gt_s", -1, i_32, d_binOpList (i64, GreaterThan) , NULL ), // 0x55 + M3OP( "i64.gt_u", -1, i_32, d_binOpList (u64, GreaterThan) , NULL ), // 0x56 + M3OP( "i64.le_s", -1, i_32, d_binOpList (i64, LessThanOrEqual) , NULL ), // 0x57 + M3OP( "i64.le_u", -1, i_32, d_binOpList (u64, LessThanOrEqual) , NULL ), // 0x58 + M3OP( "i64.ge_s", -1, i_32, d_binOpList (i64, GreaterThanOrEqual) , NULL ), // 0x59 + M3OP( "i64.ge_u", -1, i_32, d_binOpList (u64, GreaterThanOrEqual) , NULL ), // 0x5a + + M3OP_F( "f32.eq", -1, i_32, d_commutativeBinOpList (f32, Equal) , NULL ), // 0x5b + M3OP_F( "f32.ne", -1, i_32, d_commutativeBinOpList (f32, NotEqual) , NULL ), // 0x5c + M3OP_F( "f32.lt", -1, i_32, d_binOpList (f32, LessThan) , NULL ), // 0x5d + M3OP_F( "f32.gt", -1, i_32, d_binOpList (f32, GreaterThan) , NULL ), // 0x5e + M3OP_F( "f32.le", -1, i_32, d_binOpList (f32, LessThanOrEqual) , NULL ), // 0x5f + M3OP_F( "f32.ge", -1, i_32, d_binOpList (f32, GreaterThanOrEqual) , NULL ), // 0x60 + + M3OP_F( "f64.eq", -1, i_32, d_commutativeBinOpList (f64, Equal) , NULL ), // 0x61 + M3OP_F( "f64.ne", -1, i_32, d_commutativeBinOpList (f64, NotEqual) , NULL ), // 0x62 + M3OP_F( "f64.lt", -1, i_32, d_binOpList (f64, LessThan) , NULL ), // 0x63 + M3OP_F( "f64.gt", -1, i_32, d_binOpList (f64, GreaterThan) , NULL ), // 0x64 + M3OP_F( "f64.le", -1, i_32, d_binOpList (f64, LessThanOrEqual) , NULL ), // 0x65 + M3OP_F( "f64.ge", -1, i_32, d_binOpList (f64, GreaterThanOrEqual) , NULL ), // 0x66 + + M3OP( "i32.clz", 0, i_32, d_unaryOpList (u32, Clz) , NULL ), // 0x67 + M3OP( "i32.ctz", 0, i_32, d_unaryOpList (u32, Ctz) , NULL ), // 0x68 + M3OP( "i32.popcnt", 0, i_32, d_unaryOpList (u32, Popcnt) , NULL ), // 0x69 + + M3OP( "i32.add", -1, i_32, d_commutativeBinOpList (i32, Add) , NULL ), // 0x6a + M3OP( "i32.sub", -1, i_32, d_binOpList (i32, Subtract) , NULL ), // 0x6b + M3OP( "i32.mul", -1, i_32, d_commutativeBinOpList (i32, Multiply) , NULL ), // 0x6c + M3OP( "i32.div_s", -1, i_32, d_binOpList (i32, Divide) , NULL ), // 0x6d + M3OP( "i32.div_u", -1, i_32, d_binOpList (u32, Divide) , NULL ), // 0x6e + M3OP( "i32.rem_s", -1, i_32, d_binOpList (i32, Remainder) , NULL ), // 0x6f + M3OP( "i32.rem_u", -1, i_32, d_binOpList (u32, Remainder) , NULL ), // 0x70 + M3OP( "i32.and", -1, i_32, d_commutativeBinOpList (u32, And) , NULL ), // 0x71 + M3OP( "i32.or", -1, i_32, d_commutativeBinOpList (u32, Or) , NULL ), // 0x72 + M3OP( "i32.xor", -1, i_32, d_commutativeBinOpList (u32, Xor) , NULL ), // 0x73 + M3OP( "i32.shl", -1, i_32, d_binOpList (u32, ShiftLeft) , NULL ), // 0x74 + M3OP( "i32.shr_s", -1, i_32, d_binOpList (i32, ShiftRight) , NULL ), // 0x75 + M3OP( "i32.shr_u", -1, i_32, d_binOpList (u32, ShiftRight) , NULL ), // 0x76 + M3OP( "i32.rotl", -1, i_32, d_binOpList (u32, Rotl) , NULL ), // 0x77 + M3OP( "i32.rotr", -1, i_32, d_binOpList (u32, Rotr) , NULL ), // 0x78 + + M3OP( "i64.clz", 0, i_64, d_unaryOpList (u64, Clz) , NULL ), // 0x79 + M3OP( "i64.ctz", 0, i_64, d_unaryOpList (u64, Ctz) , NULL ), // 0x7a + M3OP( "i64.popcnt", 0, i_64, d_unaryOpList (u64, Popcnt) , NULL ), // 0x7b + + M3OP( "i64.add", -1, i_64, d_commutativeBinOpList (i64, Add) , NULL ), // 0x7c + M3OP( "i64.sub", -1, i_64, d_binOpList (i64, Subtract) , NULL ), // 0x7d + M3OP( "i64.mul", -1, i_64, d_commutativeBinOpList (i64, Multiply) , NULL ), // 0x7e + M3OP( "i64.div_s", -1, i_64, d_binOpList (i64, Divide) , NULL ), // 0x7f + M3OP( "i64.div_u", -1, i_64, d_binOpList (u64, Divide) , NULL ), // 0x80 + M3OP( "i64.rem_s", -1, i_64, d_binOpList (i64, Remainder) , NULL ), // 0x81 + M3OP( "i64.rem_u", -1, i_64, d_binOpList (u64, Remainder) , NULL ), // 0x82 + M3OP( "i64.and", -1, i_64, d_commutativeBinOpList (u64, And) , NULL ), // 0x83 + M3OP( "i64.or", -1, i_64, d_commutativeBinOpList (u64, Or) , NULL ), // 0x84 + M3OP( "i64.xor", -1, i_64, d_commutativeBinOpList (u64, Xor) , NULL ), // 0x85 + M3OP( "i64.shl", -1, i_64, d_binOpList (u64, ShiftLeft) , NULL ), // 0x86 + M3OP( "i64.shr_s", -1, i_64, d_binOpList (i64, ShiftRight) , NULL ), // 0x87 + M3OP( "i64.shr_u", -1, i_64, d_binOpList (u64, ShiftRight) , NULL ), // 0x88 + M3OP( "i64.rotl", -1, i_64, d_binOpList (u64, Rotl) , NULL ), // 0x89 + M3OP( "i64.rotr", -1, i_64, d_binOpList (u64, Rotr) , NULL ), // 0x8a + + M3OP_F( "f32.abs", 0, f_32, d_unaryOpList(f32, Abs) , NULL ), // 0x8b + M3OP_F( "f32.neg", 0, f_32, d_unaryOpList(f32, Negate) , NULL ), // 0x8c + M3OP_F( "f32.ceil", 0, f_32, d_unaryOpList(f32, Ceil) , NULL ), // 0x8d + M3OP_F( "f32.floor", 0, f_32, d_unaryOpList(f32, Floor) , NULL ), // 0x8e + M3OP_F( "f32.trunc", 0, f_32, d_unaryOpList(f32, Trunc) , NULL ), // 0x8f + M3OP_F( "f32.nearest", 0, f_32, d_unaryOpList(f32, Nearest) , NULL ), // 0x90 + M3OP_F( "f32.sqrt", 0, f_32, d_unaryOpList(f32, Sqrt) , NULL ), // 0x91 + + M3OP_F( "f32.add", -1, f_32, d_commutativeBinOpList (f32, Add) , NULL ), // 0x92 + M3OP_F( "f32.sub", -1, f_32, d_binOpList (f32, Subtract) , NULL ), // 0x93 + M3OP_F( "f32.mul", -1, f_32, d_commutativeBinOpList (f32, Multiply) , NULL ), // 0x94 + M3OP_F( "f32.div", -1, f_32, d_binOpList (f32, Divide) , NULL ), // 0x95 + M3OP_F( "f32.min", -1, f_32, d_commutativeBinOpList (f32, Min) , NULL ), // 0x96 + M3OP_F( "f32.max", -1, f_32, d_commutativeBinOpList (f32, Max) , NULL ), // 0x97 + M3OP_F( "f32.copysign", -1, f_32, d_binOpList (f32, CopySign) , NULL ), // 0x98 + + M3OP_F( "f64.abs", 0, f_64, d_unaryOpList(f64, Abs) , NULL ), // 0x99 + M3OP_F( "f64.neg", 0, f_64, d_unaryOpList(f64, Negate) , NULL ), // 0x9a + M3OP_F( "f64.ceil", 0, f_64, d_unaryOpList(f64, Ceil) , NULL ), // 0x9b + M3OP_F( "f64.floor", 0, f_64, d_unaryOpList(f64, Floor) , NULL ), // 0x9c + M3OP_F( "f64.trunc", 0, f_64, d_unaryOpList(f64, Trunc) , NULL ), // 0x9d + M3OP_F( "f64.nearest", 0, f_64, d_unaryOpList(f64, Nearest) , NULL ), // 0x9e + M3OP_F( "f64.sqrt", 0, f_64, d_unaryOpList(f64, Sqrt) , NULL ), // 0x9f + + M3OP_F( "f64.add", -1, f_64, d_commutativeBinOpList (f64, Add) , NULL ), // 0xa0 + M3OP_F( "f64.sub", -1, f_64, d_binOpList (f64, Subtract) , NULL ), // 0xa1 + M3OP_F( "f64.mul", -1, f_64, d_commutativeBinOpList (f64, Multiply) , NULL ), // 0xa2 + M3OP_F( "f64.div", -1, f_64, d_binOpList (f64, Divide) , NULL ), // 0xa3 + M3OP_F( "f64.min", -1, f_64, d_commutativeBinOpList (f64, Min) , NULL ), // 0xa4 + M3OP_F( "f64.max", -1, f_64, d_commutativeBinOpList (f64, Max) , NULL ), // 0xa5 + M3OP_F( "f64.copysign", -1, f_64, d_binOpList (f64, CopySign) , NULL ), // 0xa6 + + M3OP( "i32.wrap/i64", 0, i_32, d_unaryOpList (i32, Wrap_i64), NULL ), // 0xa7 + M3OP_F( "i32.trunc_s/f32", 0, i_32, d_convertOpList (i32_Trunc_f32), Compile_Convert ), // 0xa8 + M3OP_F( "i32.trunc_u/f32", 0, i_32, d_convertOpList (u32_Trunc_f32), Compile_Convert ), // 0xa9 + M3OP_F( "i32.trunc_s/f64", 0, i_32, d_convertOpList (i32_Trunc_f64), Compile_Convert ), // 0xaa + M3OP_F( "i32.trunc_u/f64", 0, i_32, d_convertOpList (u32_Trunc_f64), Compile_Convert ), // 0xab + + M3OP( "i64.extend_s/i32", 0, i_64, d_unaryOpList (i64, Extend_i32), NULL ), // 0xac + M3OP( "i64.extend_u/i32", 0, i_64, d_unaryOpList (i64, Extend_u32), NULL ), // 0xad + + M3OP_F( "i64.trunc_s/f32", 0, i_64, d_convertOpList (i64_Trunc_f32), Compile_Convert ), // 0xae + M3OP_F( "i64.trunc_u/f32", 0, i_64, d_convertOpList (u64_Trunc_f32), Compile_Convert ), // 0xaf + M3OP_F( "i64.trunc_s/f64", 0, i_64, d_convertOpList (i64_Trunc_f64), Compile_Convert ), // 0xb0 + M3OP_F( "i64.trunc_u/f64", 0, i_64, d_convertOpList (u64_Trunc_f64), Compile_Convert ), // 0xb1 + + M3OP_F( "f32.convert_s/i32",0, f_32, d_convertOpList (f32_Convert_i32), Compile_Convert ), // 0xb2 + M3OP_F( "f32.convert_u/i32",0, f_32, d_convertOpList (f32_Convert_u32), Compile_Convert ), // 0xb3 + M3OP_F( "f32.convert_s/i64",0, f_32, d_convertOpList (f32_Convert_i64), Compile_Convert ), // 0xb4 + M3OP_F( "f32.convert_u/i64",0, f_32, d_convertOpList (f32_Convert_u64), Compile_Convert ), // 0xb5 + + M3OP_F( "f32.demote/f64", 0, f_32, d_unaryOpList (f32, Demote_f64), NULL ), // 0xb6 + + M3OP_F( "f64.convert_s/i32",0, f_64, d_convertOpList (f64_Convert_i32), Compile_Convert ), // 0xb7 + M3OP_F( "f64.convert_u/i32",0, f_64, d_convertOpList (f64_Convert_u32), Compile_Convert ), // 0xb8 + M3OP_F( "f64.convert_s/i64",0, f_64, d_convertOpList (f64_Convert_i64), Compile_Convert ), // 0xb9 + M3OP_F( "f64.convert_u/i64",0, f_64, d_convertOpList (f64_Convert_u64), Compile_Convert ), // 0xba + + M3OP_F( "f64.promote/f32", 0, f_64, d_unaryOpList (f64, Promote_f32), NULL ), // 0xbb + + M3OP_F( "i32.reinterpret/f32",0,i_32, d_convertOpList (i32_Reinterpret_f32), Compile_Convert ), // 0xbc + M3OP_F( "i64.reinterpret/f64",0,i_64, d_convertOpList (i64_Reinterpret_f64), Compile_Convert ), // 0xbd + M3OP_F( "f32.reinterpret/i32",0,f_32, d_convertOpList (f32_Reinterpret_i32), Compile_Convert ), // 0xbe + M3OP_F( "f64.reinterpret/i64",0,f_64, d_convertOpList (f64_Reinterpret_i64), Compile_Convert ), // 0xbf + + M3OP( "i32.extend8_s", 0, i_32, d_unaryOpList (i32, Extend8_s), NULL ), // 0xc0 + M3OP( "i32.extend16_s", 0, i_32, d_unaryOpList (i32, Extend16_s), NULL ), // 0xc1 + M3OP( "i64.extend8_s", 0, i_64, d_unaryOpList (i64, Extend8_s), NULL ), // 0xc2 + M3OP( "i64.extend16_s", 0, i_64, d_unaryOpList (i64, Extend16_s), NULL ), // 0xc3 + M3OP( "i64.extend32_s", 0, i_64, d_unaryOpList (i64, Extend32_s), NULL ), // 0xc4 # ifdef DEBUG // for codepage logging: # define d_m3DebugOp(OP) M3OP (#OP, 0, none, { op_##OP }) @@ -2088,7 +2116,8 @@ const M3OpInfo c_operations [] = d_m3DebugOp (Entry), d_m3DebugOp (Compile), d_m3DebugOp (End), - d_m3DebugOp (CallRawFunction), d_m3DebugOp (CallRawFunctionEx), + d_m3DebugOp (Unsupported), + d_m3DebugOp (CallRawFunction), d_m3DebugOp (GetGlobal_s32), d_m3DebugOp (GetGlobal_s64), d_m3DebugOp (ContinueLoop), d_m3DebugOp (ContinueLoopIf), @@ -2112,27 +2141,27 @@ const M3OpInfo c_operations [] = # endif # ifdef d_m3CompileExtendedOpcode - [0xFC] = M3OP( "0xFC", 0, c_m3Type_void, d_emptyOpList, Compile_ExtendedOpcode ), + [0xFC] = M3OP( "0xFC", 0, c_m3Type_unknown, d_emptyOpList, Compile_ExtendedOpcode ), # endif # ifdef DEBUG - M3OP( "termination", 0, c_m3Type_void ) // for find_operation_info + M3OP( "termination", 0, c_m3Type_unknown ) // for find_operation_info # endif }; const M3OpInfo c_operationsFC [] = { - M3OP( "i32.trunc_s:sat/f32",0, i_32, d_convertOpList (i32_TruncSat_f32), Compile_Convert ), // 0x00 - M3OP( "i32.trunc_u:sat/f32",0, i_32, d_convertOpList (u32_TruncSat_f32), Compile_Convert ), // 0x01 - M3OP( "i32.trunc_s:sat/f64",0, i_32, d_convertOpList (i32_TruncSat_f64), Compile_Convert ), // 0x02 - M3OP( "i32.trunc_u:sat/f64",0, i_32, d_convertOpList (u32_TruncSat_f64), Compile_Convert ), // 0x03 - M3OP( "i64.trunc_s:sat/f32",0, i_64, d_convertOpList (i64_TruncSat_f32), Compile_Convert ), // 0x04 - M3OP( "i64.trunc_u:sat/f32",0, i_64, d_convertOpList (u64_TruncSat_f32), Compile_Convert ), // 0x05 - M3OP( "i64.trunc_s:sat/f64",0, i_64, d_convertOpList (i64_TruncSat_f64), Compile_Convert ), // 0x06 - M3OP( "i64.trunc_u:sat/f64",0, i_64, d_convertOpList (u64_TruncSat_f64), Compile_Convert ), // 0x07 + M3OP_F( "i32.trunc_s:sat/f32",0, i_32, d_convertOpList (i32_TruncSat_f32), Compile_Convert ), // 0x00 + M3OP_F( "i32.trunc_u:sat/f32",0, i_32, d_convertOpList (u32_TruncSat_f32), Compile_Convert ), // 0x01 + M3OP_F( "i32.trunc_s:sat/f64",0, i_32, d_convertOpList (i32_TruncSat_f64), Compile_Convert ), // 0x02 + M3OP_F( "i32.trunc_u:sat/f64",0, i_32, d_convertOpList (u32_TruncSat_f64), Compile_Convert ), // 0x03 + M3OP_F( "i64.trunc_s:sat/f32",0, i_64, d_convertOpList (i64_TruncSat_f32), Compile_Convert ), // 0x04 + M3OP_F( "i64.trunc_u:sat/f32",0, i_64, d_convertOpList (u64_TruncSat_f32), Compile_Convert ), // 0x05 + M3OP_F( "i64.trunc_s:sat/f64",0, i_64, d_convertOpList (i64_TruncSat_f64), Compile_Convert ), // 0x06 + M3OP_F( "i64.trunc_u:sat/f64",0, i_64, d_convertOpList (u64_TruncSat_f64), Compile_Convert ), // 0x07 # ifdef DEBUG - M3OP( "termination", 0, c_m3Type_void ) // for find_operation_info + M3OP( "termination", 0, c_m3Type_unknown ) // for find_operation_info # endif }; @@ -2179,12 +2208,14 @@ M3Result ValidateBlockEnd (IM3Compilation o, bool * o_copyStackTopToRegister) * o_copyStackTopToRegister = false; - if (o->block.type != c_m3Type_none) + u8 valueType = GetSingleRetType(o->block.type); + + if (valueType != c_m3Type_none) { if (IsStackPolymorphic (o)) { _ (UnwindBlockStack (o)); -_ (PushRegister (o, o->block.type)); +_ (PushRegister (o, valueType)); } else { @@ -2207,7 +2238,7 @@ _ (UnwindBlockStack (o)); } -M3Result CompileBlock (IM3Compilation o, /*pc_t * o_startPC,*/ u8 i_blockType, u8 i_blockOpcode) +M3Result CompileBlock (IM3Compilation o, /*pc_t * o_startPC,*/ IM3FuncType i_blockType, u8 i_blockOpcode) { M3Result result; d_m3Assert (not IsRegisterAllocated (o, 0)); d_m3Assert (not IsRegisterAllocated (o, 1)); @@ -2307,8 +2338,10 @@ void SetupCompilation (IM3Compilation o) M3Result Compile_Function (IM3Function io_function) { + IM3FuncType ft = io_function->funcType; + M3Result result = m3Err_none; m3log (compile, "compiling: '%s'; wasm-size: %d; numArgs: %d; return: %s", - io_function->name, (u32) (io_function->wasmEnd - io_function->wasm), GetFunctionNumArgs (io_function), c_waTypes [GetFunctionReturnType (io_function)]); + io_function->name, (u32) (io_function->wasmEnd - io_function->wasm), GetFunctionNumArgs (io_function), c_waTypes [GetSingleRetType(ft)]); IM3Runtime runtime = io_function->module->runtime; IM3Compilation o = & runtime->compilation; @@ -2325,18 +2358,17 @@ _ (AcquireCompilationCodePage (o, & o->page)); pc_t pc = GetPagePC (o->page); - o->block.type = GetFunctionReturnType (io_function); - // push the arg types to the type stack - M3FuncType * ft = io_function->funcType; + o->block.type = ft; // all args are 64-bit aligned const u32 argSlotCount = sizeof (u64) / sizeof (m3slot_t); u32 numArgs = GetFunctionNumArgs (o->function); + u32 numRets = GetFunctionNumReturns(o->function); for (u32 i = 0; i < numArgs; ++i) { - u8 type = ft->argTypes [i]; + u8 type = ft->types [numRets + i]; _ (PushAllocatedSlot (o, type)); if (i < numArgs - 1) diff --git a/src/m3_compile.h b/src/m3_compile.h index 2ccdde8..40ed07f 100644 --- a/src/m3_compile.h +++ b/src/m3_compile.h @@ -29,6 +29,18 @@ enum c_waOp_teeLocal = 0x22, }; +typedef struct M3FuncType +{ + struct M3FuncType * next; + + u32 numRets; + u32 numArgs; + u8 types[]; // returns, then args +} +M3FuncType; + +typedef M3FuncType * IM3FuncType; + //----------------------------------------------------------------------------------------------------------------------------------- // since the end location of a block is unknown when a branch is compiled, writing @@ -53,7 +65,7 @@ typedef struct M3CompilationScope i32 depth; // i32 loopDepth; i16 initStackIndex; - u8 type; + IM3FuncType type; m3opcode_t opcode; bool isPolymorphic; } @@ -148,14 +160,29 @@ const M3OpInfo* GetOpInfo(m3opcode_t opcode) { } } +// TODO: This helper should be removed, when MultiValue is implemented +static inline +u8 GetSingleRetType(IM3FuncType ftype) { + return (ftype && ftype->numRets) ? ftype->types[0] : c_m3Type_none; +} + #ifdef DEBUG #define M3OP(...) { __VA_ARGS__ } #define M3OP_RESERVED { "reserved" } #else + // Strip-off name #define M3OP(name, ...) { __VA_ARGS__ } #define M3OP_RESERVED { 0 } #endif +#if d_m3HasFloat + #define M3OP_F M3OP +#elif d_m3NoFloatDynamic + #define M3OP_F(n,o,t,op,...) M3OP(n, o, t, { op_Unsupported, op_Unsupported, op_Unsupported, op_Unsupported }, __VA_ARGS__) +#else + #define M3OP_F(...) { 0 } +#endif + //----------------------------------------------------------------------------------------------------------------------------------- u16 GetTypeNumSlots (u8 i_type); @@ -168,7 +195,7 @@ bool IsIntRegisterLocation (i16 i_location); bool IsStackPolymorphic (IM3Compilation o); -M3Result CompileBlock (IM3Compilation io, u8 i_blockType, u8 i_blockOpcode); +M3Result CompileBlock (IM3Compilation io, IM3FuncType i_blockType, u8 i_blockOpcode); M3Result Compile_BlockStatements (IM3Compilation io); M3Result Compile_Function (IM3Function io_function); diff --git a/src/m3_config.h b/src/m3_config.h index c22ca17..20aa48d 100644 --- a/src/m3_config.h +++ b/src/m3_config.h @@ -21,11 +21,16 @@ # endif # ifndef d_m3MaxFunctionStackHeight -# define d_m3MaxFunctionStackHeight 2000 +# define d_m3MaxFunctionStackHeight 2000 // TODO: comment on upper limit # endif -#define d_m3MaxFunctionSlots 4000 // twice d_m3MaxFunctionStackHeight -#define d_m3MaxConstantTableSize 120 +# ifndef d_m3MaxFunctionSlots +# define d_m3MaxFunctionSlots ((d_m3MaxFunctionStackHeight)*2) +# endif + +# ifndef d_m3MaxConstantTableSize +# define d_m3MaxConstantTableSize 120 +# endif # ifndef d_m3LogOutput # define d_m3LogOutput 1 @@ -52,31 +57,81 @@ # define d_m3ProfilerSlotMask 0xFFFF # endif + +// profiling and tracing ------------------------------------------------------ + +# ifndef d_m3EnableOpProfiling +# define d_m3EnableOpProfiling 0 // opcode usage counters +# endif + +# ifndef d_m3EnableOpTracing +# define d_m3EnableOpTracing 0 // only works with DEBUG +# endif + +# ifndef d_m3EnableStrace +# define d_m3EnableStrace 0 // trace exported function calls +# endif + + // logging -------------------------------------------------------------------- -// d_m3LogsDefined allows setting logging options through the compiler flags, -// i.e. -DDEBUG -Dd_m3LogsDefined -Dd_m3EnableOpTracing=1 -#ifndef d_m3LogsDefined +# ifndef d_m3LogParse +# define d_m3LogParse 0 // .wasm binary decoding info +# endif -# define d_m3EnableOpProfiling 0 // profiling or tracing can be used -# define d_m3EnableOpTracing 0 // only works with DEBUG +# ifndef d_m3LogModule +# define d_m3LogModule 0 // wasm module info +# endif -# define d_m3LogParse 0 // .wasm binary decoding info -# define d_m3LogModule 0 // wasm module info -# define d_m3LogCompile 0 // wasm -> metacode generation phase -# define d_m3LogWasmStack 0 // dump the wasm stack when pushed or popped -# define d_m3LogEmit 0 // metacode generation info -# define d_m3LogCodePages 0 // dump metacode pages when released -# define d_m3LogExec 0 // low-level interpreter specific logs -# define d_m3LogRuntime 0 // higher-level runtime information -# define d_m3LogStackTrace 0 // dump the call stack when traps occur -# define d_m3LogNativeStack 0 // track the memory usage of the C-stack +# ifndef d_m3LogCompile +# define d_m3LogCompile 0 // wasm -> metacode generation phase +# endif + +# ifndef d_m3LogWasmStack +# define d_m3LogWasmStack 0 // dump the wasm stack when pushed or popped +# endif + +# ifndef d_m3LogEmit +# define d_m3LogEmit 0 // metacode generation info +# endif + +# ifndef d_m3LogCodePages +# define d_m3LogCodePages 0 // dump metacode pages when released +# endif + +# ifndef d_m3LogExec +# define d_m3LogExec 0 // low-level interpreter specific logs +# endif + +# ifndef d_m3LogRuntime +# define d_m3LogRuntime 0 // higher-level runtime information +# endif + +# ifndef d_m3LogStackTrace +# define d_m3LogStackTrace 0 // dump the call stack when traps occur +# endif + +# ifndef d_m3LogNativeStack +# define d_m3LogNativeStack 0 // track the memory usage of the C-stack +# endif -#endif // other ---------------------------------------------------------------------- -//#define d_m3SkipStackCheck -//#define d_m3SkipMemoryBoundsCheck +# ifndef d_m3HasFloat +# define d_m3HasFloat 1 // implement floating point ops +# endif + +#if !d_m3HasFloat && !defined(d_m3NoFloatDynamic) +# define d_m3NoFloatDynamic 1 // if no floats, do not fail until flops are actually executed +#endif + +# ifndef d_m3SkipStackCheck +# define d_m3SkipStackCheck 0 // skip stack overrun checks +# endif + +# ifndef d_m3SkipMemoryBoundsCheck +# define d_m3SkipMemoryBoundsCheck 0 // skip memory bounds checks +# endif #endif // m3_config_h diff --git a/src/m3_config_platforms.h b/src/m3_config_platforms.h index 13f026a..d212ce2 100644 --- a/src/m3_config_platforms.h +++ b/src/m3_config_platforms.h @@ -18,7 +18,7 @@ #define M3_CONCAT__(a,b) a##b #define M3_CONCAT(a,b) M3_CONCAT__(a,b) -# if !defined(__cplusplus) +# if !defined(__cplusplus) || defined(_MSC_VER) # define not ! # define and && # define or || @@ -48,7 +48,7 @@ # define M3_ARCH "x86_64" # elif defined(__i386__) -# define M3_ARCH "x86" +# define M3_ARCH "i386" # elif defined(__aarch64__) # define M3_ARCH "arm64-v8a" @@ -158,9 +158,9 @@ # if defined(M3_COMPILER_MSVC) # if defined(_M_X64) -# define M3_ARCH "x64" +# define M3_ARCH "x86_64" # elif defined(_M_IX86) -# define M3_ARCH "x86" +# define M3_ARCH "i386" # elif defined(_M_ARM64) # define M3_ARCH "arm64" # elif defined(_M_ARM) @@ -191,6 +191,18 @@ * Detect/define features */ +# ifdef __has_feature +# define M3_COMPILER_HAS_FEATURE(x) __has_feature(x) +# else +# define M3_COMPILER_HAS_FEATURE(x) 0 +# endif + +# ifdef __has_builtin +# define M3_COMPILER_HAS_BUILTIN(x) __has_builtin(x) +# else +# define M3_COMPILER_HAS_BUILTIN(x) 0 +# endif + # if defined(M3_COMPILER_MSVC) # include # if UINTPTR_MAX == 0xFFFFFFFF @@ -218,11 +230,57 @@ // Byte swapping (for Big-Endian systems only) +# if defined(M3_COMPILER_MSVC) +# define m3_bswap16(x) _byteswap_ushort((x)) +# define m3_bswap32(x) _byteswap_ulong((x)) +# define m3_bswap64(x) _byteswap_uint64((x)) +# elif defined(M3_COMPILER_GCC) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)) +// __builtin_bswap32/64 added in gcc 4.3, __builtin_bswap16 added in gcc 4.8 +# define m3_bswap16(x) __builtin_bswap16((x)) +# define m3_bswap32(x) __builtin_bswap32((x)) +# define m3_bswap64(x) __builtin_bswap64((x)) +# elif defined(M3_COMPILER_CLANG) && M3_COMPILER_HAS_BUILTIN(__builtin_bswap16) +# define m3_bswap16(x) __builtin_bswap16((x)) +# define m3_bswap32(x) __builtin_bswap32((x)) +# define m3_bswap64(x) __builtin_bswap64((x)) +# else +# include +# if defined(__bswap_16) +# define m3_bswap16(x) __bswap_16((x)) +# define m3_bswap32(x) __bswap_32((x)) +# define m3_bswap64(x) __bswap_64((x)) +# else +# warning "Using naive (probably slow) bswap operations" + static inline + uint16_t m3_bswap16(uint16_t x) { + return ((( x >> 8 ) & 0xffu ) | (( x & 0xffu ) << 8 )); + } + static inline + uint32_t m3_bswap32(uint32_t x) { + return ((( x & 0xff000000u ) >> 24 ) | + (( x & 0x00ff0000u ) >> 8 ) | + (( x & 0x0000ff00u ) << 8 ) | + (( x & 0x000000ffu ) << 24 )); + } + static inline + uint64_t m3_bswap64(uint64_t x) { + return ((( x & 0xff00000000000000ull ) >> 56 ) | + (( x & 0x00ff000000000000ull ) >> 40 ) | + (( x & 0x0000ff0000000000ull ) >> 24 ) | + (( x & 0x000000ff00000000ull ) >> 8 ) | + (( x & 0x00000000ff000000ull ) << 8 ) | + (( x & 0x0000000000ff0000ull ) << 24 ) | + (( x & 0x000000000000ff00ull ) << 40 ) | + (( x & 0x00000000000000ffull ) << 56 )); + } +# endif +# endif + # if defined(M3_BIG_ENDIAN) # define M3_BSWAP_u8(X) {} -# define M3_BSWAP_u16(X) { (X)=__builtin_bswap16((X)); } -# define M3_BSWAP_u32(X) { (X)=__builtin_bswap32((X)); } -# define M3_BSWAP_u64(X) { (X)=__builtin_bswap64((X)); } +# define M3_BSWAP_u16(X) { (X)=m3_bswap16((X)); } +# define M3_BSWAP_u32(X) { (X)=m3_bswap32((X)); } +# define M3_BSWAP_u64(X) { (X)=m3_bswap64((X)); } # define M3_BSWAP_i8(X) {} # define M3_BSWAP_i16(X) M3_BSWAP_u16(X) # define M3_BSWAP_i32(X) M3_BSWAP_u32(X) @@ -242,17 +300,19 @@ # define M3_BSWAP_f64(X) {} # endif -# if defined(M3_COMPILER_MSVC) -# define UNLIKELY(x) (x) -# define LIKELY(x) (x) -# else +# if defined(M3_COMPILER_GCC) || defined(M3_COMPILER_CLANG) || defined(M3_COMPILER_ICC) # define UNLIKELY(x) __builtin_expect(!!(x), 0) # define LIKELY(x) __builtin_expect(!!(x), 1) +# else +# define UNLIKELY(x) (x) +# define LIKELY(x) (x) # endif # if defined(M3_COMPILER_MSVC) -# define M3_WEAK +# define M3_WEAK //__declspec(selectany) +# elif defined(__MINGW32__) +# define M3_WEAK //__attribute__((selectany)) # else # define M3_WEAK __attribute__((weak)) # endif @@ -345,10 +405,10 @@ typedef int8_t i8; # if defined(ARDUINO) || defined(PARTICLE) || defined(PLATFORMIO) || defined(__MBED__) || \ defined(ESP8266) || defined(ESP32) || defined(BLUE_PILL) || defined(WM_W600) || defined(FOMU) # ifndef d_m3LogOutput -# define d_m3LogOutput false +# define d_m3LogOutput 0 # endif # ifndef d_m3VerboseLogs -# define d_m3VerboseLogs false +# define d_m3VerboseLogs 0 # endif # ifndef d_m3MaxFunctionStackHeight # define d_m3MaxFunctionStackHeight 64 diff --git a/src/m3_core.c b/src/m3_core.c index f87afa3..32ad972 100644 --- a/src/m3_core.c +++ b/src/m3_core.c @@ -10,7 +10,7 @@ #include "m3_core.h" -void m3Abort(const char* message) { +void m3_Abort(const char* message) { #if d_m3LogOutput fprintf(stderr, "Error: %s\n", message); #endif @@ -183,7 +183,7 @@ void m3StackCheck () // printf ("maxStack: %ld\n", m3StackGetMax ()); } -size_t m3StackGetMax () +int m3StackGetMax () { return stack_start - stack_end; } @@ -274,6 +274,8 @@ M3Result Read_u32 (u32 * o_value, bytes_t * io_bytes, cbytes_t i_end) else return m3Err_wasmUnderrun; } +#if d_m3HasFloat || d_m3NoFloatDynamic + M3Result Read_f64 (f64 * o_value, bytes_t * io_bytes, cbytes_t i_end) { const u8 * ptr = * io_bytes; @@ -305,6 +307,7 @@ M3Result Read_f32 (f32 * o_value, bytes_t * io_bytes, cbytes_t i_end) else return m3Err_wasmUnderrun; } +#endif M3Result Read_u8 (u8 * o_value, bytes_t * io_bytes, cbytes_t i_end) { diff --git a/src/m3_core.h b/src/m3_core.h index 7bb9d54..56439ec 100644 --- a/src/m3_core.h +++ b/src/m3_core.h @@ -28,8 +28,11 @@ d_m3BeginExternC #if !defined(d_m3ShortTypesDefined) +#if d_m3HasFloat || d_m3NoFloatDynamic typedef double f64; typedef float f32; +#endif + typedef uint64_t u64; typedef int64_t i64; typedef uint32_t u32; @@ -62,12 +65,6 @@ typedef m3slot_t * m3stack_t; typedef const void * const cvptr_t; -# define d_m3Log_parse d_m3LogParse // required for m3logif -# define d_m3Log_stack d_m3LogWasmStack -# define d_m3Log_runtime d_m3LogRuntime -# define d_m3Log_exec d_m3LogExec -# define d_m3Log_emit d_m3LogEmit - # if d_m3LogOutput && defined (DEBUG) # define d_m3Log(CATEGORY, FMT, ...) printf (" %8s | " FMT, #CATEGORY, ##__VA_ARGS__); @@ -121,10 +118,9 @@ const void * const cvptr_t; # endif # define m3log(CATEGORY, FMT, ...) m3log_##CATEGORY (CATEGORY, FMT "\n", ##__VA_ARGS__) -# define m3logif(CATEGORY, STATEMENT) m3log_##CATEGORY (CATEGORY, ""); if (d_m3Log_##CATEGORY) { STATEMENT; printf ("\n"); } # else +# define d_m3Log(CATEGORY, FMT, ...) {} # define m3log(CATEGORY, FMT, ...) {} -# define m3logif(CATEGORY, STATEMENT) {} # endif @@ -174,8 +170,8 @@ M3CodePageHeader; #define d_externalKind_memory 2 #define d_externalKind_global 3 -static const char * const c_waTypes [] = { "nil", "i32", "i64", "f32", "f64", "void", "void *" }; -static const char * const c_waCompactTypes [] = { "0", "i", "I", "f", "F", "v", "*" }; +static const char * const c_waTypes [] = { "nil", "i32", "i64", "f32", "f64", "unknown" }; +static const char * const c_waCompactTypes [] = { "_", "i", "I", "f", "F", "?" }; # if d_m3VerboseLogs @@ -197,15 +193,14 @@ M3Result m3Error (M3Result i_result, IM3Runtime i_runtime, IM3Module i_module, I #if d_m3LogNativeStack void m3StackCheckInit (); void m3StackCheck (); -size_t m3StackGetMax (); +int m3StackGetMax (); #else #define m3StackCheckInit() #define m3StackCheck() #define m3StackGetMax() 0 #endif -void m3Abort (const char* message); - +void m3_Abort (const char* message); M3Result m3_Malloc (void ** o_ptr, size_t i_size); M3Result m3_Realloc (void ** io_ptr, size_t i_newSize, size_t i_oldSize); void m3_Free (void ** io_ptr); @@ -224,17 +219,19 @@ bool IsFpType (u8 i_wasmType); bool Is64BitType (u8 i_m3Type); u32 SizeOfType (u8 i_m3Type); -M3Result Read_u64 (u64 * o_value, const u8 ** io_bytes, cbytes_t i_end); -M3Result Read_u32 (u32 * o_value, const u8 ** io_bytes, cbytes_t i_end); +M3Result Read_u64 (u64 * o_value, bytes_t * io_bytes, cbytes_t i_end); +M3Result Read_u32 (u32 * o_value, bytes_t * io_bytes, cbytes_t i_end); +#if d_m3HasFloat || d_m3NoFloatDynamic M3Result Read_f64 (f64 * o_value, bytes_t * io_bytes, cbytes_t i_end); M3Result Read_f32 (f32 * o_value, bytes_t * io_bytes, cbytes_t i_end); -M3Result Read_u8 (u8 * o_value, const u8 ** io_bytes, cbytes_t i_end); +#endif +M3Result Read_u8 (u8 * o_value, bytes_t * io_bytes, cbytes_t i_end); M3Result ReadLebUnsigned (u64 * o_value, u32 i_maxNumBits, bytes_t * io_bytes, cbytes_t i_end); M3Result ReadLebSigned (i64 * o_value, u32 i_maxNumBits, bytes_t * io_bytes, cbytes_t i_end); -M3Result ReadLEB_u32 (u32 * o_value, bytes_t* io_bytes, cbytes_t i_end); -M3Result ReadLEB_u7 (u8 * o_value, bytes_t * io_bytes, cbytes_t i_end); -M3Result ReadLEB_i7 (i8 * o_value, bytes_t * io_bytes, cbytes_t i_end); +M3Result ReadLEB_u32 (u32 * o_value, bytes_t * io_bytes, cbytes_t i_end); +M3Result ReadLEB_u7 (u8 * o_value, bytes_t * io_bytes, cbytes_t i_end); +M3Result ReadLEB_i7 (i8 * o_value, bytes_t * io_bytes, cbytes_t i_end); M3Result ReadLEB_i32 (i32 * o_value, bytes_t * io_bytes, cbytes_t i_end); M3Result ReadLEB_i64 (i64 * o_value, bytes_t * io_bytes, cbytes_t i_end); M3Result Read_utf8 (cstr_t * o_utf8, bytes_t * io_bytes, cbytes_t i_end); diff --git a/src/m3_emit.c b/src/m3_emit.c index 9dcdc4c..4b7a52c 100644 --- a/src/m3_emit.c +++ b/src/m3_emit.c @@ -61,7 +61,7 @@ M3Result EmitOp (IM3Compilation o, IM3Operation i_operation) result = BridgeToNewPageIfNecessary (o); if (not result) - { m3logif (emit, log_emit (o, i_operation)) + { if (d_m3LogEmit) log_emit (o, i_operation); EmitWord (o->page, i_operation); } } diff --git a/src/m3_env.c b/src/m3_env.c index 54ae9e8..2755566 100644 --- a/src/m3_env.c +++ b/src/m3_env.c @@ -14,22 +14,17 @@ #include "m3_info.h" -M3Result AllocFuncType (IM3FuncType * o_functionType, u32 i_numArgs) +M3Result AllocFuncType (IM3FuncType * o_functionType, u32 i_numTypes) { - size_t funcTypeSize = sizeof (M3FuncType) - 3 /* sizeof (argTypes [3]) */ + i_numArgs; - - return m3Alloc (o_functionType, u8, funcTypeSize); + return m3Alloc (o_functionType, u8, sizeof (M3FuncType) + i_numTypes); } bool AreFuncTypesEqual (const IM3FuncType i_typeA, const IM3FuncType i_typeB) { - if (i_typeA->returnType == i_typeB->returnType) + if (i_typeA->numRets == i_typeB->numRets && i_typeA->numArgs == i_typeB->numArgs) { - if (i_typeA->numArgs == i_typeB->numArgs) - { - return (memcmp (i_typeA->argTypes, i_typeB->argTypes, i_typeA->numArgs) == 0); - } + return (memcmp (i_typeA->types, i_typeB->types, i_typeA->numRets + i_typeA->numArgs) == 0); } return false; @@ -126,24 +121,15 @@ u32 GetFunctionNumReturns (IM3Function i_function) { u32 numReturns = 0; - if (i_function->funcType) - numReturns = i_function->funcType->returnType ? 1 : 0; + if (i_function) + { + if (i_function->funcType) + numReturns = i_function->funcType->numRets; + } return numReturns; } - -u8 GetFunctionReturnType (IM3Function i_function) -{ - u8 returnType = c_m3Type_none; - - if (i_function->funcType) - returnType = i_function->funcType->returnType; - - return returnType; -} - - u32 GetFunctionNumArgsAndLocals (IM3Function i_function) { if (i_function) @@ -165,6 +151,18 @@ IM3Environment m3_NewEnvironment () IM3Environment env = NULL; m3Alloc (& env, M3Environment, 1); + // create FuncTypes for all simple block return ValueTypes + for (int t = c_m3Type_none; t <= c_m3Type_f64; t++) + { + IM3FuncType ftype; + AllocFuncType (& ftype, 1); + ftype->numArgs = 0; + ftype->numRets = (t == c_m3Type_none) ? 0 : 1; + ftype->types[0] = t; + + env->retFuncTypes[t] = ftype; + } + return env; } @@ -219,7 +217,6 @@ void Environment_AddFuncType (IM3Environment i_environment, IM3FuncType * io_f * io_funcType = newType; } - IM3CodePage RemoveCodePageOfCapacity (M3CodePage ** io_list, u32 i_minimumLineCount) { IM3CodePage prev = NULL; @@ -276,7 +273,7 @@ void Environment_ReleaseCodePages (IM3Environment i_environment, IM3CodePage i } -IM3Runtime m3_NewRuntime (IM3Environment i_environment, u32 i_stackSizeInBytes, void * unused) +IM3Runtime m3_NewRuntime (IM3Environment i_environment, u32 i_stackSizeInBytes, void * i_userdata) { IM3Runtime runtime = NULL; m3Alloc (& runtime, M3Runtime, 1); @@ -286,6 +283,7 @@ IM3Runtime m3_NewRuntime (IM3Environment i_environment, u32 i_stackSizeInBytes m3_ResetErrorInfo(runtime); runtime->environment = i_environment; + runtime->userdata = i_userdata; m3Alloc (& runtime->stack, u8, i_stackSizeInBytes); @@ -299,6 +297,10 @@ IM3Runtime m3_NewRuntime (IM3Environment i_environment, u32 i_stackSizeInBytes return runtime; } +void * m3_GetUserData (IM3Runtime i_runtime) +{ + return i_runtime ? i_runtime->userdata : NULL; +} typedef void * (* ModuleVisitor) (IM3Module i_module, void * i_info); @@ -373,15 +375,15 @@ M3Result EvaluateExpression (IM3Module i_module, void * o_expressed, u8 i_type { M3Result result = m3Err_none; - m3slot_t stack [d_m3MaxFunctionSlots]; // stack on the stack - // create a temporary runtime context M3Runtime runtime; M3_INIT (runtime); runtime.environment = i_module->runtime->environment; - runtime.numStackSlots = d_m3MaxFunctionSlots; - runtime.stack = & stack; + runtime.numStackSlots = i_module->runtime->numStackSlots; + runtime.stack = i_module->runtime->stack; + + m3stack_t stack = (m3stack_t)runtime.stack; IM3Runtime savedRuntime = i_module->runtime; i_module->runtime = & runtime; @@ -399,8 +401,10 @@ M3Result EvaluateExpression (IM3Module i_module, void * o_expressed, u8 i_type if (o->page) { + IM3FuncType ftype = runtime.environment->retFuncTypes[i_type]; + pc_t m3code = GetPagePC (o->page); - result = CompileBlock (o, i_type, c_waOp_block); + result = CompileBlock (o, ftype, c_waOp_block); if (not result) { @@ -638,7 +642,14 @@ M3Result InitStartFunc (IM3Module io_module) _ (Compile_Function (function)); } -_ (m3_Call(function)); + IM3FuncType ftype = function->funcType; + if (ftype->numArgs != 0 || ftype->numRets != 0) + _throw (m3Err_argumentCountMismatch); + + IM3Module module = function->module; + IM3Runtime runtime = module->runtime; + +_ ((M3Result) Call (function->compiled, (m3stack_t) runtime->stack, runtime->memory.mallocated, d_m3OpDefaultArgs)); io_module->startFunction = -1; } @@ -664,7 +675,8 @@ _ (InitElements (io_module)); io_module->next = io_runtime->modules; io_runtime->modules = io_module; - // Start func will be called when first function call is attempted + // Start func might use imported functions, which are not liked here yet, + // so it will be called before a function call is attempted (in m3_FindFuSnction) } else result = m3Err_moduleAlreadyLinked; @@ -761,7 +773,7 @@ M3Result m3_CallWithArgs (IM3Function i_function, uint32_t i_argc, const char u64 * s = & stack [i]; ccstr_t str = i_argv[i]; - switch (ftype->argTypes[i]) { + switch (ftype->types[ftype->numRets + i]) { #ifdef USE_HUMAN_FRIENDLY_ARGS case c_m3Type_i32: *(i32*)(s) = atol(str); break; case c_m3Type_i64: *(i64*)(s) = atoll(str); break; @@ -781,7 +793,7 @@ M3Result m3_CallWithArgs (IM3Function i_function, uint32_t i_argc, const char _ ((M3Result) Call (i_function->compiled, (m3stack_t) stack, runtime->memory.mallocated, d_m3OpDefaultArgs)); #if d_m3LogOutput - switch (ftype->returnType) { + switch (GetSingleRetType(ftype)) { case c_m3Type_none: fprintf (stderr, "Result: \n"); break; #ifdef USE_HUMAN_FRIENDLY_ARGS case c_m3Type_i32: fprintf (stderr, "Result: %" PRIi32 "\n", *(i32*)(stack)); break; @@ -789,13 +801,9 @@ _ ((M3Result) Call (i_function->compiled, (m3stack_t) stack, runtime->memo case c_m3Type_f32: fprintf (stderr, "Result: %f\n", *(f32*)(stack)); break; case c_m3Type_f64: fprintf (stderr, "Result: %lf\n", *(f64*)(stack)); break; #else - case c_m3Type_i32: fprintf (stderr, "Result: %u\n", *(u32*)(stack)); break; - case c_m3Type_f32: { - union { u32 u; f32 f; } union32; - union32.f = * (f32 *)(stack); - fprintf (stderr, "Result: %u\n", union32.u ); - break; - } + case c_m3Type_i32: + case c_m3Type_f32: + fprintf (stderr, "Result: %u\n", *(u32*)(stack)); break; case c_m3Type_i64: case c_m3Type_f64: fprintf (stderr, "Result: %" PRIu64 "\n", *(u64*)(stack)); break; @@ -804,7 +812,7 @@ _ ((M3Result) Call (i_function->compiled, (m3stack_t) stack, runtime->memo } #if d_m3LogNativeStack - size_t stackUsed = m3StackGetMax(); + int stackUsed = m3StackGetMax(); fprintf (stderr, "Native stack used: %d\n", stackUsed); #endif // d_m3LogNativeStack diff --git a/src/m3_env.h b/src/m3_env.h index 7ca92a1..4f3b21e 100644 --- a/src/m3_env.h +++ b/src/m3_env.h @@ -15,19 +15,7 @@ d_m3BeginExternC -typedef struct M3FuncType -{ - struct M3FuncType * next; - - u32 numArgs; - u8 returnType; - u8 argTypes [3]; // M3FuncType is a dynamically sized object; these are padding -} -M3FuncType; - -typedef M3FuncType * IM3FuncType; - -M3Result AllocFuncType (IM3FuncType * o_functionType, u32 i_numArgs); +M3Result AllocFuncType (IM3FuncType * o_functionType, u32 i_numTypes); bool AreFuncTypesEqual (const IM3FuncType i_typeA, const IM3FuncType i_typeB); @@ -70,8 +58,6 @@ typedef struct M3Function } M3Function; -typedef M3Function * IM3Function; - void Function_Release (IM3Function i_function); void Function_FreeCompiledCode (IM3Function i_function); @@ -79,7 +65,6 @@ cstr_t GetFunctionImportModuleName (IM3Function i_function); cstr_t GetFunctionName (IM3Function i_function); u32 GetFunctionNumArgs (IM3Function i_function); u32 GetFunctionNumReturns (IM3Function i_function); -u8 GetFunctionReturnType (IM3Function i_function); u32 GetFunctionNumArgsAndLocals (IM3Function i_function); @@ -133,8 +118,10 @@ typedef struct M3Global union { i64 intValue; +#if d_m3HasFloat f64 f64Value; f32 f32Value; +#endif }; bytes_t initExpr; // wasm code @@ -189,9 +176,6 @@ typedef struct M3Module } M3Module; -typedef M3Module * IM3Module; - - 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 */); @@ -199,16 +183,14 @@ IM3Function Module_GetFunction (IM3Module i_module, u32 //--------------------------------------------------------------------------------------------------------------------------------- -static const u32 c_m3NumTypesPerPage = 8; - -//--------------------------------------------------------------------------------------------------------------------------------- - typedef struct M3Environment { // struct M3Runtime * runtimes; IM3FuncType funcTypes; // linked list + IM3FuncType retFuncTypes[5]; + M3CodePage * pagesReleased; } M3Environment; @@ -218,12 +200,8 @@ void Environment_Release (IM3Environment i_enviro // 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; - //--------------------------------------------------------------------------------------------------------------------------------- -// OPTZ: function types need to move to the runtime structure so that all modules can share types -// then type equality can be a simple pointer compare for indirect call checks typedef struct M3Runtime { M3Compilation compilation; @@ -242,25 +220,24 @@ typedef struct M3Runtime u32 stackSize; u32 numStackSlots; + i32 exit_code; u32 argc; ccstr_t * argv; - M3Result runtimeError; + void * userdata; M3Memory memory; u32 memoryLimit; + M3Result runtimeError; + M3ErrorInfo error; #if d_m3VerboseLogs - char error_message[256]; + char error_message[256]; // the actual buffer. M3ErrorInfo can point to this #endif - i32 exit_code; } M3Runtime; -typedef M3Runtime * IM3Runtime; - - void InitRuntime (IM3Runtime io_runtime, u32 i_stackSizeInBytes); void Runtime_Release (IM3Runtime io_runtime); diff --git a/src/m3_exec.c b/src/m3_exec.c index cf659ec..65c08ed 100644 --- a/src/m3_exec.c +++ b/src/m3_exec.c @@ -10,20 +10,6 @@ #include "m3_compile.h" -static inline -IM3Memory GetMemoryInfo (M3MemoryHeader * header) -{ - IM3Memory memory = & header->runtime->memory; - - return memory; -} - -static inline -IM3Runtime GetRuntime (M3MemoryHeader * header) -{ - return header->runtime; -} - void ReportError2 (IM3Function i_function, m3ret_t i_result) { i_function->module->runtime->runtimeError = (M3Result)i_result; @@ -32,7 +18,7 @@ void ReportError2 (IM3Function i_function, m3ret_t i_result) d_m3OpDef (GetGlobal_s32) { u32 * global = immediate (u32 *); - slot (u32) = * global; // printf ("get global: %p %" PRIi64 "\n", global, *global); + slot (u32) = * global; // printf ("get global: %p %" PRIi64 "\n", global, *global); nextOp (); } @@ -69,7 +55,7 @@ d_m3OpDef (Call) { pc_t callPC = immediate (pc_t); i32 stackOffset = immediate (i32); - IM3Memory memory = GetMemoryInfo (_mem); + IM3Memory memory = m3MemInfo (_mem); m3stack_t sp = _sp + stackOffset; @@ -90,7 +76,7 @@ d_m3OpDef (CallIndirect) IM3Module module = immediate (IM3Module); IM3FuncType type = immediate (IM3FuncType); i32 stackOffset = immediate (i32); - IM3Memory memory = GetMemoryInfo (_mem); + IM3Memory memory = m3MemInfo (_mem); m3stack_t sp = _sp + stackOffset; @@ -131,26 +117,58 @@ d_m3OpDef (CallIndirect) d_m3OpDef (CallRawFunction) { M3RawCall call = (M3RawCall) (* _pc++); - IM3Runtime runtime = GetRuntime (_mem); - - m3ret_t possible_trap = call (runtime, (u64 *) _sp, m3MemData(_mem)); - return possible_trap; -} + IM3Function function = immediate (IM3Function); + void * userdata = immediate (void *); + u64* const sp = ((u64*)_sp); + +#if d_m3EnableStrace + IM3FuncType ftype = function->funcType; + + FILE* out = stderr; + char outbuff[1024]; + char* outp = outbuff; + char* oute = outbuff+1024; + + outp += snprintf(outp, oute-outp, "%s.%s(", function->import.moduleUtf8, function->import.fieldUtf8); + + const int nArgs = ftype->numArgs; + const int nRets = ftype->numRets; + for (int i=0; itypes[nRets + i]; + switch (type) { + case c_m3Type_i32: outp += snprintf(outp, oute-outp, "%i", *(i32*)(sp+i)); break; + case c_m3Type_i64: outp += snprintf(outp, oute-outp, "%lli", *(i64*)(sp+i)); break; + case c_m3Type_f32: outp += snprintf(outp, oute-outp, "%f", *(f32*)(sp+i)); break; + case c_m3Type_f64: outp += snprintf(outp, oute-outp, "%lf", *(f64*)(sp+i)); break; + default: outp += snprintf(outp, oute-outp, "", type); break; + } + outp += snprintf(outp, oute-outp, (i < nArgs-1) ? ", " : ")"); + } +#endif -d_m3OpDef (CallRawFunctionEx) -{ - M3RawCallEx call = (M3RawCallEx) (* _pc++); - void * cookie = immediate (void *); - IM3Runtime runtime = GetRuntime (_mem); + m3ret_t possible_trap = call (m3MemRuntime(_mem), sp, m3MemData(_mem), userdata); + +#if d_m3EnableStrace + if (possible_trap) { + fprintf(out, "%s -> %s\n", outbuff, possible_trap); + } else { + switch (GetSingleRetType(ftype)) { + case c_m3Type_none: fprintf(out, "%s\n", outbuff); break; + case c_m3Type_i32: fprintf(out, "%s = %i\n", outbuff, *(i32*)sp); break; + case c_m3Type_i64: fprintf(out, "%s = %lli\n", outbuff, *(i64*)sp); break; + case c_m3Type_f32: fprintf(out, "%s = %f\n", outbuff, *(f32*)sp); break; + case c_m3Type_f64: fprintf(out, "%s = %lf\n", outbuff, *(f64*)sp); break; + } + } +#endif - m3ret_t possible_trap = call (runtime, (u64 *)_sp, m3MemData(_mem), cookie); return possible_trap; } d_m3OpDef (MemCurrent) { - IM3Memory memory = GetMemoryInfo (_mem); + IM3Memory memory = m3MemInfo (_mem); _r0 = memory->numPages; @@ -160,7 +178,7 @@ d_m3OpDef (MemCurrent) d_m3OpDef (MemGrow) { - IM3Runtime runtime = GetRuntime (_mem); + IM3Runtime runtime = m3MemRuntime(_mem); IM3Memory memory = & runtime->memory; u32 numPagesToGrow = (u32) _r0; @@ -217,7 +235,7 @@ d_m3OpDef (Entry) IM3Function function = immediate (IM3Function); -#if defined (d_m3SkipStackCheck) +#if d_m3SkipStackCheck if (true) #else if ((void *) ((m3slot_t *) _sp + function->maxStackSlots) < _mem->maxStack) @@ -241,14 +259,12 @@ d_m3OpDef (Entry) m3ret_t r = nextOpDirect (); # if d_m3LogExec - u8 returnType = function->funcType->returnType; - char str [100] = { '!', 0 }; if (not r) - SPrintArg (str, 99, _sp, function->funcType->returnType); + SPrintArg (str, 99, _sp, GetSingleRetType(function->funcType)); - m3log (exec, " exit < %s %s %s %s", function->name, returnType ? "->" : "", str, r ? (cstr_t)r : ""); + m3log (exec, " exit < %s %s %s %s", function->name, function->funcType->numRets ? "->" : "", str, r ? (cstr_t)r : ""); # elif d_m3LogStackTrace if (r) printf (" ** %s %p\n", function->name, _sp); @@ -268,7 +284,7 @@ d_m3OpDef (Loop) m3ret_t r; - IM3Memory memory = GetMemoryInfo (_mem); + IM3Memory memory = m3MemInfo (_mem); do { @@ -355,9 +371,10 @@ d_m3OpDef (PreserveSetSlot_##TYPE) \ d_m3SetRegisterSetSlot (i32, _r0) d_m3SetRegisterSetSlot (i64, _r0) +#if d_m3HasFloat d_m3SetRegisterSetSlot (f32, _fp0) d_m3SetRegisterSetSlot (f64, _fp0) - +#endif d_m3OpDef (CopySlot_32) { @@ -452,7 +469,7 @@ void ProfileHit (cstr_t i_operationName) { if (slot->opName != i_operationName) { - m3Abort ("profiler slot collision; increase d_m3ProfilerSlotMask"); + m3_Abort ("profiler slot collision; increase d_m3ProfilerSlotMask"); } } diff --git a/src/m3_exec.h b/src/m3_exec.h index 2374466..0e3e2be 100644 --- a/src/m3_exec.h +++ b/src/m3_exec.h @@ -26,7 +26,6 @@ #include "m3_exec_defs.h" #include "m3_math_utils.h" -#include #include d_m3BeginExternC @@ -135,14 +134,14 @@ d_m3Op_i (u32, GreaterThan, > ) d_m3Op_i (u64, GreaterThan, d_m3Op_i (u32, LessThanOrEqual, <=) d_m3Op_i (u64, LessThanOrEqual, <=) d_m3Op_i (u32, GreaterThanOrEqual, >=) d_m3Op_i (u64, GreaterThanOrEqual, >=) -// float +#if d_m3HasFloat d_m3CommutativeCmpOp_f (f32, Equal, ==) d_m3CommutativeCmpOp_f (f64, Equal, ==) d_m3CommutativeCmpOp_f (f32, NotEqual, !=) d_m3CommutativeCmpOp_f (f64, NotEqual, !=) d_m3CompareOp_f (f32, LessThan, < ) d_m3CompareOp_f (f64, LessThan, < ) d_m3CompareOp_f (f32, GreaterThan, > ) d_m3CompareOp_f (f64, GreaterThan, > ) d_m3CompareOp_f (f32, LessThanOrEqual, <=) d_m3CompareOp_f (f64, LessThanOrEqual, <=) d_m3CompareOp_f (f32, GreaterThanOrEqual, >=) d_m3CompareOp_f (f64, GreaterThanOrEqual, >=) - +#endif d_m3CommutativeOp_i (i32, Add, +) d_m3CommutativeOp_i (i64, Add, +) d_m3CommutativeOp_i (i32, Multiply, *) d_m3CommutativeOp_i (i64, Multiply, *) @@ -166,11 +165,12 @@ d_m3CommutativeOp_i (u64, And, &) d_m3CommutativeOp_i (u64, Or, |) d_m3CommutativeOp_i (u64, Xor, ^) +#if d_m3HasFloat d_m3CommutativeOp_f (f32, Add, +) d_m3CommutativeOp_f (f64, Add, +) d_m3CommutativeOp_f (f32, Multiply, *) d_m3CommutativeOp_f (f64, Multiply, *) d_m3Op_f (f32, Subtract, -) d_m3Op_f (f64, Subtract, -) d_m3Op_f (f32, Divide, /) d_m3Op_f (f64, Divide, /) - +#endif d_m3OpFunc_i(u32, Rotl, rotl32) d_m3OpFunc_i(u32, Rotr, rotr32) @@ -187,6 +187,7 @@ d_m3OpMacro_i(i32, Remainder, OP_REM_S, INT32_MIN); d_m3OpMacro_i(u64, Remainder, OP_REM_U); d_m3OpMacro_i(i64, Remainder, OP_REM_S, INT64_MIN); +#if d_m3HasFloat d_m3OpFunc_f(f32, Min, min_f32); d_m3OpFunc_f(f32, Max, max_f32); d_m3OpFunc_f(f64, Min, min_f64); @@ -194,6 +195,7 @@ d_m3OpFunc_f(f64, Max, max_f64); d_m3OpFunc_f(f32, CopySign, copysignf); d_m3OpFunc_f(f64, CopySign, copysign); +#endif // Unary operations // Note: This macro follows the principle of d_m3OpMacro @@ -215,6 +217,7 @@ d_m3Op(TYPE##_##NAME##_s) \ #define d_m3UnaryOp_i(TYPE, NAME, OPERATION) d_m3UnaryMacro( _r0, _r0, TYPE, NAME, M3_UNARY, OPERATION) #define d_m3UnaryOp_f(TYPE, NAME, OPERATION) d_m3UnaryMacro(_fp0, _fp0, TYPE, NAME, M3_UNARY, OPERATION) +#if d_m3HasFloat d_m3UnaryOp_f (f32, Abs, fabsf); d_m3UnaryOp_f (f64, Abs, fabs); d_m3UnaryOp_f (f32, Ceil, ceilf); d_m3UnaryOp_f (f64, Ceil, ceil); d_m3UnaryOp_f (f32, Floor, floorf); d_m3UnaryOp_f (f64, Floor, floor); @@ -222,7 +225,7 @@ d_m3UnaryOp_f (f32, Trunc, truncf); d_m3UnaryOp_f (f64, Trunc, d_m3UnaryOp_f (f32, Sqrt, sqrtf); d_m3UnaryOp_f (f64, Sqrt, sqrt); d_m3UnaryOp_f (f32, Nearest, rintf); d_m3UnaryOp_f (f64, Nearest, rint); d_m3UnaryOp_f (f32, Negate, -); d_m3UnaryOp_f (f64, Negate, -); - +#endif #define OP_EQZ(x) ((x) == 0) @@ -313,6 +316,7 @@ d_m3Op(TYPE##_##NAME##_##FROM##_s_s) \ nextOp (); \ } +#if d_m3HasFloat d_m3TruncMacro(_r0, _fp0, i32, Trunc, f32, OP_I32_TRUNC_F32) d_m3TruncMacro(_r0, _fp0, u32, Trunc, f32, OP_U32_TRUNC_F32) d_m3TruncMacro(_r0, _fp0, i32, Trunc, f64, OP_I32_TRUNC_F64) @@ -332,7 +336,7 @@ d_m3TruncMacro(_r0, _fp0, i64, TruncSat, f32, OP_I64_TRUNC_SAT_F32) d_m3TruncMacro(_r0, _fp0, u64, TruncSat, f32, OP_U64_TRUNC_SAT_F32) d_m3TruncMacro(_r0, _fp0, i64, TruncSat, f64, OP_I64_TRUNC_SAT_F64) d_m3TruncMacro(_r0, _fp0, u64, TruncSat, f64, OP_U64_TRUNC_SAT_F64) - +#endif #define d_m3TypeModifyOp(REG_TO, REG_FROM, TO, NAME, FROM) \ d_m3Op(TO##_##NAME##_##FROM##_r) \ @@ -353,9 +357,10 @@ d_m3TypeModifyOp (_r0, _r0, i64, Extend, i32); d_m3TypeModifyOp (_r0, _r0, i64, Extend, u32); // Float to float +#if d_m3HasFloat d_m3TypeModifyOp (_fp0, _fp0, f32, Demote, f64); d_m3TypeModifyOp (_fp0, _fp0, f64, Promote, f32); - +#endif #define d_m3TypeConvertOp(REG_TO, REG_FROM, TO, NAME, FROM) \ d_m3Op(TO##_##NAME##_##FROM##_r_r) \ @@ -385,6 +390,7 @@ d_m3Op(TO##_##NAME##_##FROM##_s_s) \ } // Int to float +#if d_m3HasFloat d_m3TypeConvertOp (_fp0, _r0, f64, Convert, i32); d_m3TypeConvertOp (_fp0, _r0, f64, Convert, u32); d_m3TypeConvertOp (_fp0, _r0, f64, Convert, i64); @@ -394,7 +400,7 @@ d_m3TypeConvertOp (_fp0, _r0, f32, Convert, i32); d_m3TypeConvertOp (_fp0, _r0, f32, Convert, u32); d_m3TypeConvertOp (_fp0, _r0, f32, Convert, i64); d_m3TypeConvertOp (_fp0, _r0, f32, Convert, u64); - +#endif #define d_m3ReinterpretOp(REG, TO, SRC, FROM) \ d_m3Op(TO##_Reinterpret_##FROM##_r_r) \ @@ -429,11 +435,12 @@ d_m3Op(TO##_Reinterpret_##FROM##_s_s) \ nextOp (); \ } +#if d_m3HasFloat d_m3ReinterpretOp (_r0, i32, _fp0, f32) d_m3ReinterpretOp (_r0, i64, _fp0, f64) d_m3ReinterpretOp (_fp0, f32, _r0, i32) d_m3ReinterpretOp (_fp0, f64, _r0, i64) - +#endif d_m3OpDecl (Loop) d_m3OpDecl (If_r) @@ -531,13 +538,13 @@ d_m3Op (Select_##TYPE##_##LABEL##sr) \ nextOp (); \ } - +#if d_m3HasFloat d_m3Select_f (f32, _fp0, r, _r0) d_m3Select_f (f32, _fp0, s, slot (i32)) d_m3Select_f (f64, _fp0, r, _r0) d_m3Select_f (f64, _fp0, s, slot (i32)) - +#endif d_m3Op (Return) { @@ -653,6 +660,10 @@ d_m3Op (Const64) nextOp (); } +d_m3Op (Unsupported) +{ m3log (exec, "*** unsupported ***"); + return "unsupported instruction executed"; +} d_m3Op (Unreachable) { m3log (exec, "*** trapping ***"); @@ -691,7 +702,7 @@ d_m3Op (SetGlobal_s64) nextOp (); } - +#if d_m3HasFloat d_m3Op (SetGlobal_f32) { f32 * global = immediate (f32 *); @@ -708,6 +719,7 @@ d_m3Op (SetGlobal_f64) nextOp (); } +#endif d_m3OpDecl (CopySlot_32) @@ -727,7 +739,7 @@ d_m3SetRegisterSetSlotDecl (f32) d_m3SetRegisterSetSlotDecl (f64) -#if defined(d_m3SkipMemoryBoundsCheck) +#if d_m3SkipMemoryBoundsCheck # define m3MemCheck(x) true #else # define m3MemCheck(x) LIKELY(x) @@ -786,8 +798,10 @@ d_m3Op(DEST_TYPE##_Load_##SRC_TYPE##_s) \ #define d_m3Load_i(DEST_TYPE, SRC_TYPE) d_m3Load(_r0, DEST_TYPE, SRC_TYPE) #define d_m3Load_f(DEST_TYPE, SRC_TYPE) d_m3Load(_fp0, DEST_TYPE, SRC_TYPE) +#if d_m3HasFloat d_m3Load_f (f32, f32); d_m3Load_f (f64, f64); +#endif d_m3Load_i (i32, i8); d_m3Load_i (i32, u8); @@ -878,8 +892,10 @@ d_m3Op (TYPE##_Store_##TYPE##_rr) \ #define d_m3Store_i(SRC_TYPE, DEST_TYPE) d_m3Store(_r0, SRC_TYPE, DEST_TYPE) #define d_m3Store_f(SRC_TYPE, DEST_TYPE) d_m3Store(_fp0, SRC_TYPE, DEST_TYPE) d_m3StoreFp (_fp0, SRC_TYPE); +#if d_m3HasFloat d_m3Store_f (f32, f32) d_m3Store_f (f64, f64) +#endif d_m3Store_i (i32, u8) d_m3Store_i (i32, i16) diff --git a/src/m3_exec_defs.h b/src/m3_exec_defs.h index 6049eaa..13f96d8 100644 --- a/src/m3_exec_defs.h +++ b/src/m3_exec_defs.h @@ -12,13 +12,27 @@ d_m3BeginExternC +#if d_m3HasFloat + # define d_m3OpSig pc_t _pc, m3stack_t _sp, M3MemoryHeader * _mem, m3reg_t _r0, f64 _fp0 # define d_m3OpArgs _sp, _mem, _r0, _fp0 # define d_m3OpAllArgs _pc, _sp, _mem, _r0, _fp0 # define d_m3OpDefaultArgs 0, 0. # define d_m3ClearRegisters _r0 = 0; _fp0 = 0.; -# define m3MemData(mem) (u8*)((M3MemoryHeader*)(mem)+1) +#else + +# define d_m3OpSig pc_t _pc, m3stack_t _sp, M3MemoryHeader * _mem, m3reg_t _r0 +# define d_m3OpArgs _sp, _mem, _r0 +# define d_m3OpAllArgs _pc, _sp, _mem, _r0 +# define d_m3OpDefaultArgs 0 +# define d_m3ClearRegisters _r0 = 0; + +#endif + +# define m3MemData(mem) (u8*)(((M3MemoryHeader*)(mem))+1) +# define m3MemRuntime(mem) (((M3MemoryHeader*)(mem))->runtime) +# define m3MemInfo(mem) (&(((M3MemoryHeader*)(mem))->runtime->memory)) typedef m3ret_t (vectorcall * IM3Operation) (d_m3OpSig); diff --git a/src/m3_info.c b/src/m3_info.c index 22a4207..a5f6a2c 100644 --- a/src/m3_info.c +++ b/src/m3_info.c @@ -52,7 +52,7 @@ void m3_PrintRuntimeInfo (IM3Runtime i_runtime) cstr_t GetTypeName (u8 i_m3Type) { - if (i_m3Type < 7) + if (i_m3Type < 5) return c_waTypes [i_m3Type]; else return "?"; @@ -66,18 +66,26 @@ cstr_t SPrintFuncTypeSignature (IM3FuncType i_funcType) sprintf (string, "("); u32 numArgs = i_funcType->numArgs; - u8 * types = i_funcType->argTypes; + u32 numRets = i_funcType->numRets; + u8 * types = i_funcType->types; for (u32 i = 0; i < numArgs; ++i) { if (i != 0) strcat (string, ", "); - strcat (string, GetTypeName (types [i])); + strcat (string, GetTypeName (types [numRets + i])); } strcat (string, ") -> "); - strcat (string, GetTypeName (i_funcType->returnType)); + + for (u32 i = 0; i < numRets; ++i) + { + if (i != 0) + strcat (string, ", "); + + strcat (string, GetTypeName (types [i])); + } return string; } @@ -93,10 +101,12 @@ size_t SPrintArg (char * o_string, size_t i_n, m3stack_t i_sp, u8 i_type) len = snprintf (o_string, i_n, "%" PRIi32, * (i32 *) i_sp); else if (i_type == c_m3Type_i64) len = snprintf (o_string, i_n, "%" PRIi64, * (i64 *) i_sp); +#if d_m3HasFloat else if (i_type == c_m3Type_f32) len = snprintf (o_string, i_n, "%f", * (f32 *) i_sp); else if (i_type == c_m3Type_f64) len = snprintf (o_string, i_n, "%lf", * (f64 *) i_sp); +#endif len = M3_MAX (0, len); @@ -121,11 +131,11 @@ cstr_t SPrintFunctionArgList (IM3Function i_function, m3stack_t i_sp) if (funcType) { u32 numArgs = funcType->numArgs; - u8 * types = funcType->argTypes; + u8 * argTypes = funcType->types + funcType->numRets; for (u32 i = 0; i < numArgs; ++i) { - u8 type = types [i]; + u8 type = argTypes [i]; ret = snprintf (s, e-s, "%s: ", c_waTypes [type]); s += M3_MAX (0, ret); @@ -158,7 +168,7 @@ OpInfo find_operation_info (IM3Operation i_operation) { IM3OpInfo oi = GetOpInfo(i); - if (oi->type != c_m3Type_void) + if (oi->type != c_m3Type_unknown) { for (u32 o = 0; o < 4; ++o) { @@ -317,7 +327,7 @@ void dump_type_stack (IM3Compilation o) { /* Reminders about how the stack works! :) -- args & locals remain on the type stack for duration of the function. Denoted with a constant 'A' and 'L' in this dump. - -- the intial stack dumps originate from the CompileLocals () function, so these identifiers won't/can't be + -- the initial stack dumps originate from the CompileLocals () function, so these identifiers won't/can't be applied until this compilation stage is finished -- constants are not statically represented in the type stack (like args & constants) since they don't have/need write counts @@ -334,6 +344,7 @@ void dump_type_stack (IM3Compilation o) i32 regAllocated [2] = { (i32) IsRegisterAllocated (o, 0), (i32) IsRegisterAllocated (o, 1) }; // display whether r0 or fp0 is allocated. these should then also be reflected somewhere in the stack too. + d_m3Log(stack, ""); printf (" "); printf ("%s %s ", regAllocated [0] ? "(r0)" : " ", regAllocated [1] ? "(fp0)" : " "); @@ -367,6 +378,7 @@ void dump_type_stack (IM3Compilation o) printf (" "); } + printf ("\n"); for (u32 r = 0; r < 2; ++r) d_m3Assert (regAllocated [r] == 0); // reg allocation & stack out of sync @@ -431,11 +443,12 @@ void log_emit (IM3Compilation o, IM3Operation i_operation) # ifdef DEBUG OpInfo i = find_operation_info (i_operation); + d_m3Log(emit, ""); if (i.info) { - printf ("%p: %s", GetPC (o), i.info->name); + printf ("%p: %s\n", GetPC (o), i.info->name); } - else printf ("not found: %p", i_operation); + else printf ("not found: %p\n", i_operation); # endif } diff --git a/src/m3_math_utils.h b/src/m3_math_utils.h index e53c652..f9dab3e 100644 --- a/src/m3_math_utils.h +++ b/src/m3_math_utils.h @@ -10,7 +10,6 @@ #include "m3_core.h" -#include #include #if defined(M3_COMPILER_MSVC) @@ -232,6 +231,11 @@ u64 rotr64(u64 n, unsigned c) { /* * Min, Max */ + +#if d_m3HasFloat + +#include + static inline f32 min_f32(f32 a, f32 b) { if (UNLIKELY(isnan(a) or isnan(b))) return NAN; @@ -259,5 +263,6 @@ f64 max_f64(f64 a, f64 b) { if (UNLIKELY(a == 0 and a == b)) return signbit(a) ? b : a; return a > b ? a : b; } +#endif #endif // m3_math_utils_h diff --git a/src/m3_parse.c b/src/m3_parse.c index 8443ebf..9005517 100644 --- a/src/m3_parse.c +++ b/src/m3_parse.c @@ -61,9 +61,13 @@ _ (ReadLEB_i7 (& form, & i_bytes, i_end)); u32 numArgs; _ (ReadLEB_u32 (& numArgs, & i_bytes, i_end)); -_ (AllocFuncType (& ftype, numArgs)); - ftype->numArgs = numArgs; + _throwif ("insane argument count", numArgs > d_m3MaxSaneFunctionArgCount); +#if defined(M3_COMPILER_MSVC) + u8 argTypes[d_m3MaxSaneFunctionArgCount]; +#else + u8 argTypes[numArgs]; +#endif for (u32 a = 0; a < numArgs; ++a) { i8 wasmType; @@ -71,18 +75,28 @@ _ (AllocFuncType (& ftype, numArgs)); _ (ReadLEB_i7 (& wasmType, & i_bytes, i_end)); _ (NormalizeType (& argType, wasmType)); - ftype->argTypes [a] = argType; + argTypes[a] = argType; } - u8 returnCount; -_ (ReadLEB_u7 /* u1 in spec */ (& returnCount, & i_bytes, i_end)); + u32 numRets; +_ (ReadLEB_u32 (& numRets, & i_bytes, i_end)); + + _throwif ("insane returns count", numRets > d_m3MaxSaneFunctionArgCount); + +_ (AllocFuncType (& ftype, numRets + numArgs)); + ftype->numArgs = numArgs; + ftype->numRets = numRets; - if (returnCount) + for (u32 r = 0; r < numRets; ++r) { - i8 returnType; -_ (ReadLEB_i7 (& returnType, & i_bytes, i_end)); -_ (NormalizeType (& ftype->returnType, returnType)); - } m3log (parse, " type %2d: %s", i, SPrintFuncTypeSignature (ftype)); + i8 wasmType; + u8 retType; +_ (ReadLEB_i7 (& wasmType, & i_bytes, i_end)); +_ (NormalizeType (& retType, wasmType)); + + ftype->types[r] = retType; + } + memcpy(ftype->types + numRets, argTypes, numArgs); m3log (parse, " type %2d: %s", i, SPrintFuncTypeSignature (ftype)); Environment_AddFuncType (io_module->environment, & ftype); io_module->funcTypes [i] = ftype; @@ -549,10 +563,10 @@ _ (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 + if (section > previousSection or // from the spec: sections must appear in order + section == 0 or // custom section + (section == 12 and previousSection == 9) or // if present, DataCount goes after Element + (section == 10 and previousSection == 12)) // and before Code { u32 sectionLength; _ (ReadLEB_u32 (& sectionLength, & pos, end)); diff --git a/src/wasm3.h b/src/wasm3.h index 67bca55..fa4428c 100644 --- a/src/wasm3.h +++ b/src/wasm3.h @@ -10,8 +10,8 @@ #define M3_VERSION_MAJOR 0 #define M3_VERSION_MINOR 4 -#define M3_VERSION_REV 7 -#define M3_VERSION "0.4.7" +#define M3_VERSION_REV 8 +#define M3_VERSION "0.4.8" #include #include @@ -53,11 +53,7 @@ enum // EWaTypes c_m3Type_f32 = 3, c_m3Type_f64 = 4, - c_m3Type_void, - c_m3Type_ptr, - c_m3Type_trap, - - c_m3Type_runtime + c_m3Type_unknown }; @@ -112,7 +108,6 @@ 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") @@ -161,13 +156,16 @@ d_m3ErrorConst (trapStackOverflow, "[trap] stack overflow") IM3Runtime m3_NewRuntime (IM3Environment io_environment, uint32_t i_stackSizeInBytes, - void * unused); + void * i_userdata); void m3_FreeRuntime (IM3Runtime i_runtime); - + uint8_t * m3_GetMemory (IM3Runtime i_runtime, uint32_t * o_memorySizeInBytes, uint32_t i_memoryIndex); + + void * m3_GetUserData (IM3Runtime i_runtime); + // Wasm currently only supports one memory region. i_memoryIndex should be zero. //------------------------------------------------------------------------------------------------------------------------------- @@ -186,24 +184,20 @@ d_m3ErrorConst (trapStackOverflow, "[trap] stack overflow") M3Result m3_LoadModule (IM3Runtime io_runtime, IM3Module io_module); // LoadModule transfers ownership of a module to the runtime. Do not free modules once successfully imported into the runtime - typedef const void * (* M3RawCall) (IM3Runtime runtime, uint64_t * _sp, void * _mem); + typedef const void * (* M3RawCall) (IM3Runtime runtime, uint64_t * _sp, void * _mem, void * userdata); M3Result m3_LinkRawFunction (IM3Module io_module, const char * const i_moduleName, const char * const i_functionName, const char * const i_signature, - M3RawCall i_function); - - typedef const void * (* M3RawCallEx) (IM3Runtime runtime, uint64_t * _sp, void * _mem, void * cookie); + M3RawCall i_function); - // m3_LinkRawFunctionEx links a native callback function that has a cookie parameter, allowing one native - // callback to receive multiple m3 function calls. This ease for dynamic routing in the callback. M3Result m3_LinkRawFunctionEx (IM3Module io_module, const char * const i_moduleName, const char * const i_functionName, const char * const i_signature, - M3RawCallEx i_function, - void * i_cookie); + M3RawCall i_function, + const void * i_userdata); //------------------------------------------------------------------------------------------------------------------------------- // functions