diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 5b88d05..ad9fbb8 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -528,7 +528,7 @@ jobs: run: | mkdir build cd build - g++ -xc++ -Dd_m3HasWASI \ + clang -xc++ -Dd_m3HasWASI \ -I../source ../source/*.c ../platforms/app/main.c \ -O3 -g0 -lm \ -o wasm3 @@ -546,7 +546,7 @@ jobs: run: | mkdir build cd build - g++ -xc++ -Dd_m3HasWASI -DDEBUG \ + clang -xc++ -Dd_m3HasWASI -DDEBUG \ -Dd_m3EnableOpTracing=1 \ -Dd_m3EnableStrace=1 \ -Dd_m3LogParse=1 \ diff --git a/README.md b/README.md index 4f97654..892fb60 100644 --- a/README.md +++ b/README.md @@ -98,6 +98,7 @@ Wasm3 started as a research project and remains so by many means. Evaluating the ## Further Resources [Demos](./docs/Demos.md) +[Cookbook](./docs/Cookbook.md) [Installation instructions](./docs/Installation.md) [Build and Development instructions](./docs/Development.md) [Supported Hardware](./docs/Hardware.md) diff --git a/docs/Cookbook.md b/docs/Cookbook.md new file mode 100644 index 0000000..f89a3c8 --- /dev/null +++ b/docs/Cookbook.md @@ -0,0 +1,394 @@ +# WASM module examples + +### Rust WASI app + +Create a new project: +```sh +$ cargo new --bin hello +$ cd hello +$ rustup target add wasm32-wasi +``` + +Build and run: +```sh +$ cargo build --release --target wasm32-wasi + +$ wasm3 ./target/wasm32-wasi/release/hello.wasm +Hello, world! +``` + +### AssemblyScript WASI app + +Create `hello.ts`: +```ts +import "wasi" +import {Console} from "as-wasi" + +Console.log('Hello World!'); +``` + +Create `package.json`: +```json +{ + "scripts": { + "asbuild:debug": "asc hello.ts -b hello.wasm --debug", + "asbuild:optimized": "asc hello.ts -b hello.wasm -O3s --noAssert", + "asbuild:tiny": "asc hello.ts -b hello.wasm -O3z --noAssert --runtime stub --use abort=", + "build": "npm run asbuild:optimized" + }, + "devDependencies": { + "assemblyscript": "*", + "as-wasi": "*" + } +} +``` + +Build and run: +```sh +$ npm install +$ npm run build + +$ wasm3 hello.wasm +Hello World! +``` + +### TinyGo WASI app + +Create `hello.go`: +```go +package main + +import "fmt" + +func main() { + fmt.Printf("Hello, %s!\n", "world") +} +``` + +Build and run: +```sh +$ tinygo build -o hello.wasm -target wasi -no-debug hello.go + +$ wasm3 hello.wasm +Hello, world! +``` + +### Zig WASI app + +Create `hello.zig`: +```zig +const std = @import("std"); + +pub fn main() !void { + const stdout = std.io.getStdOut().writer(); + try stdout.print("Hello, {s}!\n", .{"world"}); +} +``` + +Build and run: +```sh +$ zig build-exe -O ReleaseSmall -target wasm32-wasi hello.zig + +$ wasm3 hello.wasm +Hello, world! +``` + +## Zig library + +Create `add.zig`: +```zig +export fn add(a: i32, b: i32) i64 { + return a + b; +} +``` + +Build and run: +```sh +$ zig build-lib add.zig -O ReleaseSmall -target wasm32-freestanding + +$ wasm3 --repl add.wasm +wasm3> add 1 2 +Result: 3 +``` + +### C/C++ WASI app + +The easiest way to start is to use [Wasienv](https://github.com/wasienv/wasienv). + +Create `hello.cpp`: +```cpp +#include + +int main() { + std::cout << "Hello, world!" << std::endl; + return 0; +} +``` + +Or `hello.c`: +```c +#include + +int main() { + printf("Hello, %s!\n", "world"); + return 0; +} +``` + +Build and run: +```sh +$ wasic++ -O3 hello.cpp -o hello.wasm +$ wasicc -O3 hello.c -o hello.wasm + +$ wasm3 hello.wasm +Hello World! +``` + +Limitations: +- `setjmp/longjmp` and `C++ exceptions` are not available +- no support for `threads` and `atomics` +- no support for `dynamic libraries` + +### WAT WASI app + +Create `hello.wat`: +```wat +(module + ;; wasi_snapshot_preview1!fd_write(file_descriptor, *iovs, iovs_len, nwritten) -> status_code + (import "wasi_snapshot_preview1" "fd_write" (func $fd_write (param i32 i32 i32 i32) (result i32))) + + (memory 1) + (export "memory" (memory 0)) + + ;; Put a message to linear memory at offset 32 + (data (i32.const 32) "Hello, world!\n") + + (func $main (export "_start") + ;; Create a new io vector at address 0x4 + (i32.store (i32.const 4) (i32.const 32)) ;; iov.iov_base - pointer to the start of the message + (i32.store (i32.const 8) (i32.const 14)) ;; iov.iov_len - length of the message + + (call $fd_write + (i32.const 1) ;; file_descriptor - 1 for stdout + (i32.const 4) ;; *iovs - pointer to the io vector + (i32.const 1) ;; iovs_len - count of items in io vector + (i32.const 20) ;; nwritten - where to store the number of bytes written + ) + drop ;; discard the WASI status code + ) +) +``` + + +Build and run: +```sh +$ wat2wasm hello.wat -o hello.wasm + +$ wasm3 hello.wasm +Hello, world! +``` + +### WAT library + +Create `swap.wat`: +```wat +(module + (func (export "swap") (param i32 i32) (result i32 i32) + (get_local 1) + (get_local 0) + ) +) +``` + +Build and run: +```sh +$ wat2wasm swap.wat -o swap.wasm + +$ wasm3 --repl swap.wasm +wasm3> :invoke swap 123 456 +Result: 456:i32, 123:i32 +``` + +# Tracing + +Drag'n'drop any of the WASI apps to [`WebAssembly.sh`](https://webassembly.sh/) and run: +```sh +$ wasm3-strace /tmp/hello.wasm +``` + +The execution trace will be produced: +```js +_start () { + __wasilibc_init_preopen () { + malloc (i32: 16) { + dlmalloc (i32: 16) { + sbrk (i32: 0) { + } = 131072 + sbrk (i32: 65536) { +``` +
+ Click to expand! + +```js + } = 131072 + } = 131088 + } = 131088 + calloc (i32: 24, i32: 0) { + dlmalloc (i32: 96) { + } = 131120 + memset (i32: 131120, i32: 65504, i32: 0) { + } = 131120 + } = 131120 + po_map_assertvalid (i32: 131088) { + } + po_map_assertvalid (i32: 131088) { + } + } + wasi_unstable!fd_prestat_get(3, 65528) { } = 0 + malloc (i32: 2) { + dlmalloc (i32: 2) { + } = 131232 + } = 131232 + wasi_unstable!fd_prestat_dir_name(3, 131232, 1) { } = 0 + __wasilibc_register_preopened_fd (i32: 3, i32: 131120) { + po_map_assertvalid (i32: 131088) { + } + po_map_assertvalid (i32: 131088) { + } + strdup (i32: 131232) { + strlen (i32: 131232) { + } = 1 + malloc (i32: 2) { + dlmalloc (i32: 2) { + } = 131248 + } = 131248 + memcpy (i32: 131248, i32: 131233, i32: 131232) { + } = 131248 + } = 131248 + wasi_unstable!fd_fdstat_get(3, 65496) { } = 0 + po_map_assertvalid (i32: 131088) { + } + po_map_assertvalid (i32: 131088) { + } + } = 0 + free (i32: 131232) { + dlfree (i32: 131232) { + } + } + wasi_unstable!fd_prestat_get(4, 65528) { } = 0 + malloc (i32: 2) { + dlmalloc (i32: 2) { + } = 131232 + } = 131232 + wasi_unstable!fd_prestat_dir_name(4, 131232, 1) { } = 0 + __wasilibc_register_preopened_fd (i32: 4, i32: 131120) { + po_map_assertvalid (i32: 131088) { + } + po_map_assertvalid (i32: 131088) { + } + strdup (i32: 131232) { + strlen (i32: 131232) { + } = 1 + malloc (i32: 2) { + dlmalloc (i32: 2) { + } = 131264 + } = 131264 + memcpy (i32: 131264, i32: 131233, i32: 131232) { + } = 131264 + } = 131264 + wasi_unstable!fd_fdstat_get(4, 65496) { } = 0 + po_map_assertvalid (i32: 131088) { + } + po_map_assertvalid (i32: 131088) { + } + } = 0 + free (i32: 131232) { + dlfree (i32: 131232) { + } + } + wasi_unstable!fd_prestat_get(5, 65528) { } = 8 + __wasm_call_ctors () { + } + __original_main () { + printf (i32: 65536, i32: 0) { + vfprintf (i32: 69512, i32: 0, i32: 65536) { + printf_core (i32: 0, i32: -1, i32: 65536, i32: -16, i32: 65480) { + } = 0 + __towrite (i32: 69512) { + } = 0 + printf_core (i32: 69512, i32: 8, i32: 65536, i32: -1, i32: 65480) { + __fwritex (i32: 65536, i32: 0, i32: 7) { + memcpy (i32: 68472, i32: 0, i32: 65536) { + } = 68472 + } = 7 + __fwritex (i32: 65543, i32: 0, i32: 0) { + memcpy (i32: 68479, i32: 0, i32: 65543) { + } = 68479 + } = 0 + pop_arg (i32: 64456, i32: 0, i32: 9) { + } + strnlen (i32: 65548, i32: 0) { + memchr (i32: 65548, i32: 4, i32: 0) { + } = 65553 + } = 5 + __fwritex (i32: 67222, i32: 65553, i32: 0) { + memcpy (i32: 68479, i32: 0, i32: 67222) { + } = 68479 + } = 0 + __fwritex (i32: 65548, i32: 65553, i32: 5) { + memcpy (i32: 68479, i32: 0, i32: 65548) { + } = 68479 + } = 5 + __fwritex (i32: 65545, i32: 0, i32: 2) { + __stdout_write (i32: 69512, i32: 0, i32: 65545) { + __isatty (i32: 1) { + wasi_unstable!fd_fdstat_get(1, 64376) { } = 0 + } = 1 + __stdio_write (i32: 69512, i32: 64368, i32: 65545) { + writev (i32: 1, i32: -16, i32: 64384) { +Hello, world! + wasi_unstable!fd_write(1, 64384, 2, 64380) { } = 0 + } = 14 + } = 2 + } = 2 + memcpy (i32: 68472, i32: -1, i32: 65547) { + } = 68472 + } = 2 + } = 14 + } = 14 + } = 14 + } = 0 + __prepare_for_exit () { + dummy () { + } + __stdio_exit () { + __ofl_lock () { + } = 69504 + } + } +} +``` +
+ +# Gas Metering + +```sh +$ npm install -g wasm-metering + +$ wasm-meter hello.wasm hello-metered.wasm + +$ wasm3 hello-metered.wasm +Warning: Gas is limited to 500000000.0000 +Hello, world! +Gas used: 20.8950 + +$ wasm3 --gas-limit 10 hello-metered.wasm +Warning: Gas is limited to 10.0000 +Gas used: 10.0309 +Error: [trap] Out of gas +``` + +# Other resources + +- [WebAssembly by examples](https://wasmbyexample.dev/home.en-us.html) by Aaron Turner +- [Writing WebAssembly](https://docs.wasmtime.dev/wasm.html) in Wasmtime docs diff --git a/platforms/app/main.c b/platforms/app/main.c index 172ede8..49d6535 100644 --- a/platforms/app/main.c +++ b/platforms/app/main.c @@ -43,6 +43,7 @@ int wasm_bins_qty = 0; #if defined(GAS_LIMIT) +static int64_t initial_gas = GAS_FACTOR * GAS_LIMIT; static int64_t current_gas = GAS_FACTOR * GAS_LIMIT; static bool is_gas_metered = false; @@ -208,6 +209,15 @@ M3Result repl_load_hex (u32 fsize) return result; } +void print_gas_used() +{ +#if defined(GAS_LIMIT) + if (is_gas_metered) { + fprintf(stderr, "Gas used: %0.4f\n", (double)(initial_gas - current_gas) / GAS_FACTOR); + } +#endif +} + void print_backtrace() { IM3BacktraceInfo info = m3_GetBacktrace(runtime); @@ -253,6 +263,8 @@ M3Result repl_call (const char* name, int argc, const char* argv[]) result = m3_CallArgv(func, 0, NULL); + print_gas_used(); + if (result == m3Err_trapExit) { exit(wasi_ctx->exit_code); } @@ -273,11 +285,7 @@ M3Result repl_call (const char* name, int argc, const char* argv[]) result = m3_CallArgv (func, argc, argv); -#if defined(GAS_LIMIT) - if (is_gas_metered) { - fprintf(stderr, "Gas used: %0.4f\n", (double)((GAS_FACTOR * GAS_LIMIT) - current_gas) / GAS_FACTOR); - } -#endif + print_gas_used(); if (result) return result; @@ -297,8 +305,10 @@ M3Result repl_call (const char* name, int argc, const char* argv[]) switch (m3_GetRetType(func, i)) { case c_m3Type_i32: fprintf (stderr, "Result: %" PRIi32 "\n", *(i32*)valptrs[i]); break; case c_m3Type_i64: fprintf (stderr, "Result: %" PRIi64 "\n", *(i64*)valptrs[i]); break; +# if d_m3HasFloat case c_m3Type_f32: fprintf (stderr, "Result: %" PRIf32 "\n", *(f32*)valptrs[i]); break; case c_m3Type_f64: fprintf (stderr, "Result: %" PRIf64 "\n", *(f64*)valptrs[i]); break; +# endif default: return "unknown return type"; } } @@ -566,6 +576,10 @@ int main (int i_argc, const char* i_argv[]) const char* tmp = "65536"; ARGV_SET(tmp); argStackSize = atol(tmp); + } else if (!strcmp("--gas-limit", arg)) { + const char* tmp = "0"; + ARGV_SET(tmp); + initial_gas = current_gas = GAS_FACTOR * atol(tmp); } else if (!strcmp("--dir", arg)) { const char* argDir; ARGV_SET(argDir); diff --git a/platforms/app_fuzz/fuzzer.c b/platforms/app_fuzz/fuzzer.c index 76e236b..b97d649 100644 --- a/platforms/app_fuzz/fuzzer.c +++ b/platforms/app_fuzz/fuzzer.c @@ -31,9 +31,10 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) if (result == 0) { IM3Function f = NULL; result = m3_FindFunction (&f, runtime, "fib"); + /* TODO: if (f) { m3_CallV (f, 10); - } + }*/ } else { m3_FreeModule (module); } diff --git a/source/m3_compile.c b/source/m3_compile.c index 76e6ccd..835f1f6 100644 --- a/source/m3_compile.c +++ b/source/m3_compile.c @@ -1073,7 +1073,7 @@ _ (PushConst (o, value, c_m3Type_i64)); m3log (compile, } -#if d_m3HasFloat +#if d_m3ImplementFloat M3Result Compile_Const_f32 (IM3Compilation o, m3opcode_t i_opcode) { M3Result result; @@ -2370,7 +2370,12 @@ const M3OpInfo c_operations [] = # ifdef DEBUG // for codepage logging. the order doesn't matter: # define d_m3DebugOp(OP) M3OP (#OP, 0, none, { op_##OP }) + +# if d_m3HasFloat # define d_m3DebugTypedOp(OP) M3OP (#OP, 0, none, { op_##OP##_i32, op_##OP##_i64, op_##OP##_f32, op_##OP##_f64, }) +# else +# define d_m3DebugTypedOp(OP) M3OP (#OP, 0, none, { op_##OP##_i32, op_##OP##_i64 }) +# endif d_m3DebugOp (Compile), d_m3DebugOp (Entry), d_m3DebugOp (End), d_m3DebugOp (Unsupported), d_m3DebugOp (CallRawFunction), @@ -2383,11 +2388,13 @@ const M3OpInfo c_operations [] = d_m3DebugOp (Select_i32_rss), d_m3DebugOp (Select_i32_srs), d_m3DebugOp (Select_i32_ssr), d_m3DebugOp (Select_i32_sss), d_m3DebugOp (Select_i64_rss), d_m3DebugOp (Select_i64_srs), d_m3DebugOp (Select_i64_ssr), d_m3DebugOp (Select_i64_sss), +# if d_m3HasFloat d_m3DebugOp (Select_f32_sss), d_m3DebugOp (Select_f32_srs), d_m3DebugOp (Select_f32_ssr), d_m3DebugOp (Select_f32_rss), d_m3DebugOp (Select_f32_rrs), d_m3DebugOp (Select_f32_rsr), d_m3DebugOp (Select_f64_sss), d_m3DebugOp (Select_f64_srs), d_m3DebugOp (Select_f64_ssr), d_m3DebugOp (Select_f64_rss), d_m3DebugOp (Select_f64_rrs), d_m3DebugOp (Select_f64_rsr), +# endif d_m3DebugTypedOp (SetGlobal), d_m3DebugOp (SetGlobal_s32), d_m3DebugOp (SetGlobal_s64), diff --git a/source/m3_core.c b/source/m3_core.c index 2618b51..e21faf3 100644 --- a/source/m3_core.c +++ b/source/m3_core.c @@ -263,7 +263,7 @@ M3Result Read_u32 (u32 * o_value, bytes_t * io_bytes, cbytes_t i_end) else return m3Err_wasmUnderrun; } -#if d_m3HasFloat || d_m3NoFloatDynamic +#if d_m3ImplementFloat M3Result Read_f64 (f64 * o_value, bytes_t * io_bytes, cbytes_t i_end) { diff --git a/source/m3_core.h b/source/m3_core.h index 71d827d..745a24b 100644 --- a/source/m3_core.h +++ b/source/m3_core.h @@ -27,11 +27,9 @@ d_m3BeginExternC +#define d_m3ImplementFloat (d_m3HasFloat || d_m3NoFloatDynamic) + #if !defined(d_m3ShortTypesDefined) -#if d_m3HasFloat || d_m3NoFloatDynamic -typedef double f64; -typedef float f32; -#endif typedef uint64_t u64; typedef int64_t i64; @@ -41,6 +39,12 @@ typedef uint16_t u16; typedef int16_t i16; typedef uint8_t u8; typedef int8_t i8; + +#if d_m3ImplementFloat +typedef double f64; +typedef float f32; +#endif + #endif // d_m3ShortTypesDefined #define PRIf32 "f" @@ -224,7 +228,7 @@ u32 SizeOfType (u8 i_m3Type); 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 +#if d_m3ImplementFloat 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); #endif diff --git a/source/m3_env.c b/source/m3_env.c index dbaca05..997a406 100644 --- a/source/m3_env.c +++ b/source/m3_env.c @@ -616,8 +616,10 @@ M3Result m3_GetGlobal (IM3Global i_global, switch (i_global->type) { case c_m3Type_i32: o_value->value.i32 = i_global->intValue; break; case c_m3Type_i64: o_value->value.i64 = i_global->intValue; break; +# if d_m3HasFloat case c_m3Type_f32: o_value->value.f32 = i_global->f32Value; break; case c_m3Type_f64: o_value->value.f64 = i_global->f64Value; break; +# endif default: return m3Err_invalidTypeId; } @@ -636,8 +638,10 @@ M3Result m3_SetGlobal (IM3Global i_global, switch (i_value->type) { case c_m3Type_i32: i_global->intValue = i_value->value.i32; break; case c_m3Type_i64: i_global->intValue = i_value->value.i64; break; +# if d_m3HasFloat case c_m3Type_f32: i_global->f32Value = i_value->value.f32; break; case c_m3Type_f64: i_global->f64Value = i_value->value.f64; break; +# endif default: return m3Err_invalidTypeId; } @@ -795,8 +799,10 @@ M3Result m3_CallVL (IM3Function i_function, va_list i_args) switch (d_FuncArgType(ftype, i)) { case c_m3Type_i32: *(i32*)(s) = va_arg(i_args, i32); s += 8; break; case c_m3Type_i64: *(i64*)(s) = va_arg(i_args, i64); s += 8; break; +# if d_m3HasFloat case c_m3Type_f32: *(f32*)(s) = va_arg(i_args, f64); s += 8; break; // f32 is passed as f64 case c_m3Type_f64: *(f64*)(s) = va_arg(i_args, f64); s += 8; break; +# endif default: return "unknown argument type"; } } @@ -836,8 +842,10 @@ M3Result m3_Call (IM3Function i_function, uint32_t i_argc, const void * i_argp switch (d_FuncArgType(ftype, i)) { case c_m3Type_i32: *(i32*)(s) = *(i32*)i_argptrs[i]; s += 8; break; case c_m3Type_i64: *(i64*)(s) = *(i64*)i_argptrs[i]; s += 8; break; +# if d_m3HasFloat case c_m3Type_f32: *(f32*)(s) = *(f32*)i_argptrs[i]; s += 8; break; case c_m3Type_f64: *(f64*)(s) = *(f64*)i_argptrs[i]; s += 8; break; +# endif default: return "unknown argument type"; } } @@ -878,8 +886,10 @@ M3Result m3_CallArgv (IM3Function i_function, uint32_t i_argc, const char * i_ switch (d_FuncArgType(ftype, i)) { case c_m3Type_i32: *(i32*)(s) = strtoul(i_argv[i], NULL, 10); s += 8; break; case c_m3Type_i64: *(i64*)(s) = strtoull(i_argv[i], NULL, 10); s += 8; break; - case c_m3Type_f32: *(f32*)(s) = strtod(i_argv[i], NULL); s += 8; break; // strtof would be less portable +# if d_m3HasFloat + case c_m3Type_f32: *(f32*)(s) = strtod(i_argv[i], NULL); s += 8; break; // strtof would be less portable case c_m3Type_f64: *(f64*)(s) = strtod(i_argv[i], NULL); s += 8; break; +# endif default: return "unknown argument type"; } } @@ -924,8 +934,10 @@ M3Result m3_GetResults (IM3Function i_function, uint32_t i_retc, const void * switch (d_FuncRetType(ftype, i)) { case c_m3Type_i32: *(i32*)o_retptrs[i] = *(i32*)(s); s += 8; break; case c_m3Type_i64: *(i64*)o_retptrs[i] = *(i64*)(s); s += 8; break; +# if d_m3HasFloat case c_m3Type_f32: *(f32*)o_retptrs[i] = *(f32*)(s); s += 8; break; case c_m3Type_f64: *(f64*)o_retptrs[i] = *(f64*)(s); s += 8; break; +# endif default: return "unknown return type"; } } @@ -956,8 +968,10 @@ M3Result m3_GetResultsVL (IM3Function i_function, va_list o_rets) switch (d_FuncRetType(ftype, i)) { case c_m3Type_i32: *va_arg(o_rets, i32*) = *(i32*)(s); s += 8; break; case c_m3Type_i64: *va_arg(o_rets, i64*) = *(i64*)(s); s += 8; break; +# if d_m3HasFloat case c_m3Type_f32: *va_arg(o_rets, f32*) = *(f32*)(s); s += 8; break; case c_m3Type_f64: *va_arg(o_rets, f64*) = *(f64*)(s); s += 8; break; +# endif default: return "unknown argument type"; } } @@ -1040,7 +1054,8 @@ M3Result m3Error (M3Result i_result, IM3Runtime i_runtime, IM3Module i_module, { if (i_runtime) { - i_runtime->error = (M3ErrorInfo){ i_result, i_runtime, i_module, i_function, i_file, i_lineNum }; + i_runtime->error = (M3ErrorInfo){ .result = i_result, .runtime = i_runtime, .module = i_module, + .function = i_function, .file = i_file, .line = i_lineNum }; i_runtime->error.message = i_runtime->error_message; va_list args; diff --git a/source/m3_exec_defs.h b/source/m3_exec_defs.h index 7bb4e81..a7992a7 100644 --- a/source/m3_exec_defs.h +++ b/source/m3_exec_defs.h @@ -12,27 +12,35 @@ d_m3BeginExternC -#define m3MemData(mem) (u8*)(((M3MemoryHeader*)(mem))+1) -#define m3MemRuntime(mem) (((M3MemoryHeader*)(mem))->runtime) -#define m3MemInfo(mem) (&(((M3MemoryHeader*)(mem))->runtime->memory)) - -#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.0 -# define d_m3ClearRegisters _r0 = 0; _fp0 = 0.0; - -#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)) + +# define d_m3BaseOpSig pc_t _pc, m3stack_t _sp, M3MemoryHeader * _mem, m3reg_t _r0 +# define d_m3BaseOpArgs _sp, _mem, _r0 +# define d_m3BaseOpAllArgs _pc, _sp, _mem, _r0 +# define d_m3BaseOpDefaultArgs 0 +# define d_m3BaseClearRegisters _r0 = 0; + +# define d_m3ExpOpSig(...) d_m3BaseOpSig, __VA_ARGS__ +# define d_m3ExpOpArgs(...) d_m3BaseOpArgs, __VA_ARGS__ +# define d_m3ExpOpAllArgs(...) d_m3BaseOpAllArgs, __VA_ARGS__ +# define d_m3ExpOpDefaultArgs(...) d_m3BaseOpDefaultArgs, __VA_ARGS__ +# define d_m3ExpClearRegisters(...) d_m3BaseClearRegisters; __VA_ARGS__ + +# if d_m3HasFloat +# define d_m3OpSig d_m3ExpOpSig (f64 _fp0) +# define d_m3OpArgs d_m3ExpOpArgs (_fp0) +# define d_m3OpAllArgs d_m3ExpOpAllArgs (_fp0) +# define d_m3OpDefaultArgs d_m3ExpOpDefaultArgs (0.) +# define d_m3ClearRegisters d_m3ExpClearRegisters (_fp0 = 0.;) +# else +# define d_m3OpSig d_m3BaseOpSig +# define d_m3OpArgs d_m3BaseOpArgs +# define d_m3OpAllArgs d_m3BaseOpAllArgs +# define d_m3OpDefaultArgs d_m3BaseOpDefaultArgs +# define d_m3ClearRegisters d_m3BaseClearRegisters +# endif typedef m3ret_t (vectorcall * IM3Operation) (d_m3OpSig); diff --git a/source/m3_parse.c b/source/m3_parse.c index 4ea7bb1..ed681f5 100644 --- a/source/m3_parse.c +++ b/source/m3_parse.c @@ -291,7 +291,7 @@ M3Result Parse_InitExpr (M3Module * io_module, bytes_t * io_bytes, cbytes_t i_ #else M3Compilation compilation; #endif - compilation = (M3Compilation){ NULL, io_module, * io_bytes, i_end }; + compilation = (M3Compilation){ .runtime = NULL, .module = io_module, .wasm = * io_bytes, .wasmEnd = i_end }; result = CompileBlockStatements (& compilation);