diff --git a/build.zig b/build.zig index 45e5d663b5..0342efafab 100644 --- a/build.zig +++ b/build.zig @@ -361,6 +361,11 @@ fn buildBinary( .optimize = optimize, }); + const wasm3 = b.dependency("wasm3", .{ + .target = target, + .optimize = optimize, + }); + // // Build Artifact // @@ -416,6 +421,7 @@ fn buildBinary( urbit.linkLibrary(sigsegv.artifact("sigsegv")); urbit.linkLibrary(urcrypt.artifact("urcrypt")); urbit.linkLibrary(whereami.artifact("whereami")); + urbit.linkLibrary(wasm3.artifact("wasm3")); if (t.isDarwin()) { // Requires llvm@18 homebrew installation diff --git a/build.zig.zon b/build.zig.zon index b3e3900e00..a038ed9e12 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -56,6 +56,9 @@ .url = "https://github.com/allyourcodebase/zlib/archive/0918e87b7629b9c6a50a08edd0ce30d849758faf.tar.gz", .hash = "122034ab2a12adf8016ffa76e48b4be3245ffd305193edba4d83058adbcfa749c107", }, + .wasm3 = .{ + .path = "./ext/wasm3", + }, }, .paths = .{ "", diff --git a/ext/wasm3/build.zig b/ext/wasm3/build.zig new file mode 100644 index 0000000000..2c5c8337b1 --- /dev/null +++ b/ext/wasm3/build.zig @@ -0,0 +1,87 @@ +const std = @import("std"); + +pub fn build(b: *std.Build) void { + const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{}); + const t = target.result; + + const softfloat = b.dependency("softfloat", .{ + .target = target, + .optimize = optimize, + }); + + const wasm3_c = b.dependency("wasm3", .{ + .target = target, + .optimize = optimize, + }); + + const wasm3 = b.addStaticLibrary(.{ + .name = "wasm3", + .target = target, + .optimize = optimize, + }); + + wasm3.linkLibC(); + + wasm3.addIncludePath(wasm3_c.path("source/")); + + const common_flags = [_][]const u8{ + "-std=c99", + "-Wall", + "-Wextra", + "-Wparentheses", + "-Wundef", + "-Wpointer-arith", + "-Wstrict-aliasing=2", + "-Werror=implicit-function-declaration", + "-fno-sanitize=all", + // "-fsanitize=undefined", + // "-fno-sanitize-trap=undefined", + }; + + const mac_flags = common_flags ++ [_][]const u8{ + "-fPIC", + "-c", + }; + + wasm3.addCSourceFiles(.{ + .root = wasm3_c.path("source/"), + .files = &.{ + "m3_bind.c", + "m3_code.c", + "m3_compile.c", + "m3_core.c", + "m3_emit.c", + "m3_env.c", + "m3_exec.c", + "m3_function.c", + "m3_info.c", + "m3_module.c", + "m3_parse.c", + "m3_validate.c", + }, + .flags = if (t.os.tag == .macos) &mac_flags else &common_flags, + }); + + wasm3.installHeader(wasm3_c.path("source/m3_config_platforms.h"), "m3_config_platforms.h"); + wasm3.installHeader(wasm3_c.path("source/m3_bind.h"), "m3_bind.h"); + wasm3.installHeader(wasm3_c.path("source/m3_code.h"), "m3_code.h"); + wasm3.installHeader(wasm3_c.path("source/m3_compile.h"), "m3_compile.h"); + wasm3.installHeader(wasm3_c.path("source/m3_config.h"), "m3_config.h"); + wasm3.installHeader(wasm3_c.path("source/m3_core.h"), "m3_core.h"); + wasm3.installHeader(wasm3_c.path("source/m3_emit.h"), "m3_emit.h"); + wasm3.installHeader(wasm3_c.path("source/m3_env.h"), "m3_env.h"); + wasm3.installHeader(wasm3_c.path("source/m3_exception.h"), "m3_exception.h"); + wasm3.installHeader(wasm3_c.path("source/m3_exec.h"), "m3_exec.h"); + wasm3.installHeader(wasm3_c.path("source/m3_exec_defs.h"), "m3_exec_defs.h"); + wasm3.installHeader(wasm3_c.path("source/m3_function.h"), "m3_function.h"); + wasm3.installHeader(wasm3_c.path("source/m3_info.h"), "m3_info.h"); + wasm3.installHeader(wasm3_c.path("source/m3_math_utils.h"), "m3_math_utils.h"); + wasm3.installHeader(wasm3_c.path("source/wasm3.h"), "wasm3.h"); + wasm3.installHeader(wasm3_c.path("source/wasm3_defs.h"), "wasm3_defs.h"); + wasm3.installHeader(wasm3_c.path("source/m3_validate.h"), "m3_validate.h"); + + wasm3.linkLibrary(softfloat.artifact("softfloat")); + + b.installArtifact(wasm3); +} diff --git a/ext/wasm3/build.zig.zon b/ext/wasm3/build.zig.zon new file mode 100644 index 0000000000..b2f08fa4b0 --- /dev/null +++ b/ext/wasm3/build.zig.zon @@ -0,0 +1,17 @@ +.{ + .name = "wasm3", + .version = "0.0.1", + .dependencies = .{ + .softfloat = .{ + .path = "../softfloat", + }, + .wasm3 = .{ + // .path = "../../../../wasm3" + .url = "https://github.com/Quodss/wasm3/archive/5b74cbca01793cda71ebf707b0587616c32cc88c.tar.gz", + .hash = "12200fb06246d1956d73684cddbf84e819e4a0d7b1817bf5934b836466d194e3c60d", + }, + }, + .paths = .{ + "", + }, +} \ No newline at end of file diff --git a/pkg/c3/motes.h b/pkg/c3/motes.h index 7ae7ebcd75..86cdccbb20 100644 --- a/pkg/c3/motes.h +++ b/pkg/c3/motes.h @@ -402,6 +402,8 @@ # define c3__exit c3_s4('e','x','i','t') # define c3__eyre c3_s4('e','y','r','e') # define c3__f c3_s1('f') +# define c3__f32 c3_s3('f','3','2') +# define c3__f64 c3_s3('f','6','4') # define c3__fx c3_s2('f','x') # define c3__fab c3_s3('f','a','b') # define c3__face c3_s4('f','a','c','e') @@ -596,6 +598,8 @@ # define c3__hxtr c3_s4('h','x','t','r') # define c3__hxts c3_s4('h','x','t','s') # define c3__i c3_s1('i') +# define c3__i32 c3_s3('i','3','2') +# define c3__i64 c3_s3('i','6','4') # define c3__ic c3_s2('i','c') # define c3__ice c3_s3('i','c','e') # define c3__iced c3_s4('i','c','e','d') diff --git a/pkg/noun/build.zig b/pkg/noun/build.zig index 1c816ea7f8..99d9c89213 100644 --- a/pkg/noun/build.zig +++ b/pkg/noun/build.zig @@ -104,6 +104,11 @@ pub fn build(b: *std.Build) !void { .optimize = optimize, }); + const wasm3 = b.dependency("wasm3", .{ + .target = target, + .optimize = optimize, + }); + pkg_noun.linkLibC(); pkg_noun.linkLibrary(pkg_c3.artifact("c3")); @@ -123,6 +128,7 @@ pub fn build(b: *std.Build) !void { pkg_noun.linkLibrary(urcrypt.artifact("urcrypt")); pkg_noun.linkLibrary(whereami.artifact("whereami")); pkg_noun.linkLibrary(zlib.artifact("z")); + pkg_noun.linkLibrary(wasm3.artifact("wasm3")); pkg_noun.addIncludePath(b.path("")); if (t.os.tag.isDarwin()) @@ -310,6 +316,7 @@ const c_source_files = [_][]const u8{ "jets/e/slaw.c", "jets/e/tape.c", "jets/e/trip.c", + "jets/e/urwasm.c", "jets/f/cell.c", "jets/f/comb.c", "jets/f/cons.c", diff --git a/pkg/noun/build.zig.zon b/pkg/noun/build.zig.zon index 305efb9c97..3982a2a467 100644 --- a/pkg/noun/build.zig.zon +++ b/pkg/noun/build.zig.zon @@ -53,6 +53,9 @@ .url = "https://github.com/allyourcodebase/zlib/archive/0918e87b7629b9c6a50a08edd0ce30d849758faf.tar.gz", .hash = "122034ab2a12adf8016ffa76e48b4be3245ffd305193edba4d83058adbcfa749c107", }, + .wasm3 = .{ + .path = "../../ext/wasm3", + }, }, .paths = .{ "", diff --git a/pkg/noun/jets/137/tree.c b/pkg/noun/jets/137/tree.c index fec03edf1f..e8c7c35b7d 100644 --- a/pkg/noun/jets/137/tree.c +++ b/pkg/noun/jets/137/tree.c @@ -843,6 +843,56 @@ static u3j_core _137_non_d[] = }; +static u3j_harm _137_hex_lia_run_a[] = {{".2", u3we_lia_run, c3y}, {}}; + +static u3j_harm _137_hex_lia_run_once_inner_a[] = {{".2", u3we_lia_run_once, c3y}, {}}; + +static u3j_core _137_hex_lia_run_once_d[] = { + { "run-once-inner-v0", 15, _137_hex_lia_run_once_inner_a, 0, no_hashes }, + {} +}; + +static u3j_core _137_hex_lia_monad_d[] = { + { "run-v0", 7, _137_hex_lia_run_a, 0, no_hashes }, + { "run-once-v0", 7, 0, _137_hex_lia_run_once_d, no_hashes }, + {} +}; + +static u3j_core _137_hex_wasm_engine_d[] = { + { "monad-v0", 3, 0, _137_hex_lia_monad_d, no_hashes }, + {} +}; + +static u3j_core _137_hex_wasm_op_def_d[] = { + { "wasm-engine-v0", 3, 0, _137_hex_wasm_engine_d, no_hashes }, + {} +}; + +static u3j_core _137_hex_wasm_validator_d[] = { + { "wasm-op-def-v0", 3, 0, _137_hex_wasm_op_def_d, no_hashes }, + {} +}; + +static u3j_core _137_hex_wasm_parser_d[] = { + { "validator-v0", 3, 0, _137_hex_wasm_validator_d, no_hashes }, + {} +}; + +static u3j_core _137_hex_lia_sur_d[] = { + { "wasm-parser-v0", 3, 0, _137_hex_wasm_parser_d, no_hashes }, + {} +}; + +static u3j_core _137_hex_wasm_engine_sur_d[] = { + { "monad-sur-v0", 3, 0, _137_hex_lia_sur_d, no_hashes }, + {} +}; + +static u3j_core _137_hex_wasm_sur_d[] = { + { "engine-sur-v0", 3, 0, _137_hex_wasm_engine_sur_d, no_hashes }, + {} +}; + static u3j_core _137_hex_d[] = { { "non", 7, 0, _137_non_d, no_hashes }, @@ -869,6 +919,7 @@ static u3j_core _137_hex_d[] = { "secp", 6, 0, _137_hex_secp_d, no_hashes }, { "mimes", 31, 0, _137_hex_mimes_d, no_hashes }, { "json", 31, 0, _137_hex_json_d, no_hashes }, + { "wasm-sur-v0", 3, 0, _137_hex_wasm_sur_d, no_hashes }, {} }; diff --git a/pkg/noun/jets/e/urwasm.c b/pkg/noun/jets/e/urwasm.c new file mode 100644 index 0000000000..7ec9e47da2 --- /dev/null +++ b/pkg/noun/jets/e/urwasm.c @@ -0,0 +1,1440 @@ +/// @file + +#include "jets/k.h" +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +#include "wasm3.h" +#include "m3_env.h" +#include "m3_validate.h" + +// #define URWASM_SUBROAD +// #define URWASM_STATEFUL + +#define ONCE_CTX 63 +#define RUN_CTX 7 + +#define AX_RUNNABLE 374 +#define AX_ARROWS 1502 + +#define AX_CALL 20 +#define AX_MEMREAD 383 +#define AX_MEMWRITE 94 +#define AX_CALL_EXT 375 +#define AX_GLOBAL_SET 4 +#define AX_GLOBAL_GET 22 +#define AX_MEM_SIZE 186 +#define AX_MEM_GROW 381 +#define AX_GET_ACC 374 +#define AX_SET_ACC 92 +#define AX_GET_ALL_GLOB 43 +#define AX_SET_ALL_GLOB 380 + +#define AX_TRY 43 +#define AX_CATCH 4 +#define AX_RETURN 20 + +#define ARROW_CTX 511 +#define MONAD_CTX 127 + +#define arr_sam 62 +#define arr_sam_2 124 +#define arr_sam_3 125 +#define arr_sam_6 250 +#define arr_sam_7 251 + +#define ERR(string) ("\r\n\033[31m>>> " string "\033[0m\r\n") +#define WUT(string) ("\r\n\033[33m>> " string "\033[0m\r\n") + +static const M3Result m3Lia_Arrow = "non-zero yield from import arrow"; + +typedef struct { + u3_noun call_bat; + u3_noun memread_bat; + u3_noun memwrite_bat; + u3_noun call_ext_bat; + u3_noun try_bat; + u3_noun catch_bat; + u3_noun return_bat; + u3_noun global_set_bat; + u3_noun global_get_bat; + u3_noun mem_grow_bat; + u3_noun mem_size_bat; + u3_noun get_acc_bat; + u3_noun set_acc_bat; + u3_noun get_all_glob_bat; + u3_noun set_all_glob_bat; +// + u3_noun call_ctx; + u3_noun memread_ctx; + u3_noun memwrite_ctx; + u3_noun global_set_ctx; + u3_noun global_get_ctx; + u3_noun mem_grow_ctx; + u3_noun mem_size_ctx; + u3_noun get_all_glob_ctx; + u3_noun set_all_glob_ctx; +} match_data_struct; + +typedef struct { + IM3Module wasm_module; // p + u3_noun lia_shop; // q + u3_noun acc; // p.r, transferred + u3_noun map; // q.r, retained + match_data_struct* match; + u3_noun arrow_yil; +} lia_state; + +static u3_noun +_atoms_from_stack(void** valptrs, c3_w n, c3_y* types) +{ + u3_noun out = u3_nul; + while (n--) + { + switch (types[n]) + { // TODO 64 bit vere + case c_m3Type_i32: + case c_m3Type_f32: + { + out = u3nc(u3i_word(*(c3_w*)valptrs[n]), out); + break; + } + case c_m3Type_i64: + case c_m3Type_f64: + { + out = u3nc(u3i_chub(*(c3_d*)valptrs[n]), out); + break; + } + default: + { + return u3m_bail(c3__fail); + } + } + } + return out; +} + +// RETAIN argument +static c3_o +_atoms_to_stack(u3_noun atoms, void** valptrs, c3_w n, c3_y* types) +{ + for (c3_w i = 0; i < n; i++) + { + if (c3y == u3ud(atoms)) + { + return c3n; + } + u3_noun atom; + u3x_cell(atoms, &atom, &atoms); + if (c3n == u3ud(atom)) + { + return u3m_bail(c3__fail); + } + switch (types[i]) + { + case c_m3Type_i32: + case c_m3Type_f32: + { + *(c3_w*)valptrs[i] = u3r_word(0, atom); + break; + } + case c_m3Type_i64: + case c_m3Type_f64: + { + *(c3_d*)valptrs[i] = u3r_chub(0, atom); + break; + } + default: + { + return u3m_bail(c3__fail); + } + } + } + return __(u3_nul == atoms); +} + +static u3_noun +_coins_from_stack(void** valptrs, c3_w n, c3_y* types) +{ + u3_noun out = u3_nul; + while (n--) + { + switch (types[n]) + { // TODO 64 bit vere + case c_m3Type_i32: + { + out = u3nc(u3nc(c3__i32, u3i_word(*(c3_w*)valptrs[n])), out); + break; + } + case c_m3Type_i64: + { + out = u3nc(u3nc(c3__i64, u3i_chub(*(c3_d*)valptrs[n])), out); + break; + } + case c_m3Type_f32: + { + out = u3nc(u3nc(c3__f32, u3i_word(*(c3_w*)valptrs[n])), out); + break; + } + case c_m3Type_f64: + { + out = u3nc(u3nc(c3__f64, u3i_chub(*(c3_d*)valptrs[n])), out); + break; + } + default: + { + return u3m_bail(c3__fail); + } + } + } + return out; +} + +// RETAIN argument +static c3_o +_coins_to_stack(u3_noun coins, void** valptrs, c3_w n, c3_y* types) +{ + for (c3_w i = 0; i < n; i++) + { + if (c3y == u3ud(coins)) + { + return c3n; + } + u3_noun coin; + u3x_cell(coins, &coin, &coins); + if (c3y == u3ud(coin)) + { + return u3m_bail(c3__fail); + } + u3_noun tag, value; + u3x_cell(coin, &tag, &value); + if (c3n == u3ud(value)) + { + return u3m_bail(c3__fail); + } + switch (types[i]) + { + case c_m3Type_i32: + { + if (c3__i32 != tag) + { + return c3n; + } + *(c3_w*)valptrs[i] = u3r_word(0, value); + break; + } + case c_m3Type_i64: + { + if (c3__i64 != tag) + { + return c3n; + } + *(c3_d*)valptrs[i] = u3r_chub(0, value); + break; + } + case c_m3Type_f32: + { + if (c3__f32 != tag) + { + return c3n; + } + *(c3_w*)valptrs[i] = u3r_word(0, value); + break; + } + case c_m3Type_f64: + { + if (c3__f64 != tag) + { + return c3n; + } + *(c3_d*)valptrs[i] = u3r_chub(0, value); + break; + } + default: + { + return u3m_bail(c3__fail); + } + } + } + return __(u3_nul == coins); +} + +static c3_t +_deterministic_trap(M3Result result) +{ + if ( result == m3Err_trapOutOfBoundsMemoryAccess + || result == m3Err_trapDivisionByZero + || result == m3Err_trapIntegerOverflow + || result == m3Err_trapIntegerConversion + || result == m3Err_trapIndirectCallTypeMismatch + || result == m3Err_trapTableIndexOutOfRange + || result == m3Err_trapTableElementIsNull ) + { + return 1; + } + else + { + return 0; + } +} + +static u3_noun +_reduce_monad(u3_noun monad, lia_state* sat) +{ + u3_noun monad_bat = u3h(monad); + if (c3y == u3r_sing(monad_bat, sat->match->call_bat)) + { + if (c3n == u3r_sing(u3at(ARROW_CTX, monad), sat->match->call_ctx)) + { + return u3m_bail(c3__fail); + } + // call + u3_atom name = u3x_atom(u3at(arr_sam_2, monad)); + u3_noun args = u3at(arr_sam_3, monad); + + c3_w met_w = u3r_met(3, name); + c3_c* name_c = u3a_malloc(met_w + 1); + u3r_bytes(0, met_w, (c3_y*)name_c, name); + name_c[met_w] = 0; + + M3Result result; + + IM3Function f; + result = m3_FindFunction(&f, sat->wasm_module->runtime, name_c); + + if (result) + { + fprintf(stderr, ERR("function %s search error: %s"), name_c, result); + return u3m_bail(c3__fail); + } + + c3_w n_in = f->funcType->numArgs; + c3_w n_out = f->funcType->numRets; + c3_y* types = f->funcType->types; + + c3_d *vals_in = u3a_calloc(n_in, sizeof(c3_d)); + void **valptrs_in = u3a_calloc(n_in, sizeof(void*)); + for (c3_w i = 0; i < n_in; i++) + { + valptrs_in[i] = &vals_in[i]; + } + + c3_d *vals_out = u3a_calloc(n_out, sizeof(c3_d)); + void **valptrs_out = u3a_calloc(n_out, sizeof(void*)); + for (c3_w i = 0; i < n_out; i++) + { + valptrs_out[i] = &vals_out[i]; + } + + if (c3n == _atoms_to_stack(args, valptrs_in, n_in, (types+n_out))) + { + fprintf(stderr, ERR("function %s wrong number of args"), name_c); + return u3m_bail(c3__fail); + } + + result = m3_Call(f, n_in, (const void**)valptrs_in); + + u3_noun yil; + + if (result == m3Lia_Arrow) + { + yil = sat->arrow_yil; + sat->arrow_yil = 0; + if (yil == 0) + { + return u3m_bail(c3__fail); + } + } + else if (_deterministic_trap(result)) + { + fprintf(stderr, WUT("%s call trapped: %s"), name_c, result); + yil = u3nc(2, 0); + } + else if (result == m3Err_functionImportMissing) + { + return u3m_bail(c3__exit); + } + else if (result) + { + fprintf(stderr, ERR("%s call failed: %s"), name_c, result); + return u3m_bail(c3__fail); + } + else + { + result = m3_GetResults(f, n_out, (const void**)valptrs_out); + if (result) + { + fprintf(stderr, ERR("function %s failed to get results"), name_c); + return u3m_bail(c3__fail); + } + yil = u3nc(0, _atoms_from_stack(valptrs_out, n_out, types)); + } + + u3a_free(name_c); + u3a_free(vals_in); + u3a_free(valptrs_in); + u3a_free(vals_out); + u3a_free(valptrs_out); + u3z(monad); + + return yil; + } + else if (c3y == u3r_sing(monad_bat, sat->match->memread_bat)) + { + if (c3n == u3r_sing(u3at(ARROW_CTX, monad), sat->match->memread_ctx)) + { + return u3m_bail(c3__fail); + } + // memread + u3_atom ptr = u3x_atom(u3at(arr_sam_2, monad)); + u3_noun len = u3at(arr_sam_3, monad); + + c3_w ptr_w = u3r_word(0, ptr); + c3_l len_l = (c3y == u3a_is_cat(len)) ? len : u3m_bail(c3__fail); + c3_w len_buf_w; + c3_y* buf_y = m3_GetMemory(sat->wasm_module->runtime, &len_buf_w, 0); + + if (buf_y == NULL) + { + fprintf(stderr, ERR("memread failed to get memory")); + return u3m_bail(c3__fail); + } + + if (ptr_w + len_l > len_buf_w) + { + fprintf(stderr, ERR("memread out of bounds")); + return u3m_bail(c3__fail); + } + + u3z(monad); + return u3nt(0, len_l, u3i_bytes(len_l, (buf_y + ptr_w))); + } + else if (c3y == u3r_sing(monad_bat, sat->match->memwrite_bat)) + { + if (c3n == u3r_sing(u3at(ARROW_CTX, monad), sat->match->memwrite_ctx)) + { + return u3m_bail(c3__fail); + } + // memwrite + u3_atom ptr = u3x_atom(u3at(arr_sam_2, monad)); + u3_noun len = u3at(arr_sam_6, monad); + u3_noun src = u3at(arr_sam_7, monad); + + c3_w ptr_w = u3r_word(0, ptr); + c3_l len_l = (c3y == u3a_is_cat(len)) ? len : u3m_bail(c3__fail); + + c3_w len_buf_w; + c3_y* buf_y = m3_GetMemory(sat->wasm_module->runtime, &len_buf_w, 0); + + if (buf_y == NULL) + { + fprintf(stderr, ERR("memwrite failed to get memory")); + return u3m_bail(c3__fail); + } + + if (ptr_w + len_l > len_buf_w) + { + fprintf(stderr, ERR("memwrite out of bounds")); + return u3m_bail(c3__fail); + } + + u3r_bytes(0, len_l, (buf_y + ptr_w), u3x_atom(src)); + + u3z(monad); + return u3nc(0, 0); + } + else if (c3y == u3r_sing(monad_bat, sat->match->call_ext_bat)) + { + // call-ext + u3_noun name = u3at(arr_sam_2, monad); + u3_noun args = u3at(arr_sam_3, monad); + if (u3_nul == sat->lia_shop) + { + u3_noun yil = u3nt(1, u3k(name), u3k(args)); + u3z(monad); + return yil; + } + else + { + u3_noun lia_buy; + u3x_cell(sat->lia_shop, &lia_buy, &sat->lia_shop); + u3z(monad); + return u3nc(0, u3k(lia_buy)); + } + } + else if (c3y == u3r_sing(monad_bat, sat->match->try_bat)) + { + // try + u3_noun monad_b = u3at(60, monad); + u3_noun cont = u3at(61, monad); + u3_weak yil; + u3_noun monad_cont; + { + yil = _reduce_monad(u3k(monad_b), sat); + if (0 == u3h(yil)) + { + monad_cont = u3n_slam_on(u3k(cont), u3k(u3t(yil))); + u3z(yil); + yil = u3_none; + } + } + + u3z(monad); + if (u3_none == yil) + { + return _reduce_monad(monad_cont, sat); + } + else + { + return yil; + } + } + else if (c3y == u3r_sing(monad_bat, sat->match->catch_bat)) + { + // catch + u3_noun monad_try = u3at(120, monad); + u3_noun monad_catch = u3at(121, monad); + u3_noun cont = u3at(61, monad); + u3_weak yil; + u3_noun monad_cont; + + { + yil = _reduce_monad(u3k(monad_try), sat); + if (0 == u3h(yil)) + { + monad_cont = u3n_slam_on(u3k(cont), u3k(u3t(yil))); + u3z(yil); + yil = u3_none; + } + else if (2 == u3h(yil)) + { + u3z(yil); + yil = _reduce_monad(u3k(monad_catch), sat); + if (0 == u3h(yil)) + { + monad_cont = u3n_slam_on(u3k(cont), u3k(u3t(yil))); + u3z(yil); + yil = u3_none; + } + } + } + + u3z(monad); + if (u3_none == yil) + { + return _reduce_monad(monad_cont, sat); + } + else + { + return yil; + } + } + else if (c3y == u3r_sing(monad_bat, sat->match->return_bat)) + { + // return + u3_noun yil = u3nc(0, u3k(u3at(30, monad))); + u3z(monad); + return yil; + } + else if (c3y == u3r_sing(monad_bat, sat->match->global_set_bat)) + { + if (c3n == u3r_sing(u3at(ARROW_CTX, monad), sat->match->global_set_ctx)) + { + return u3m_bail(c3__fail); + } + // global-set + u3_atom name = u3x_atom(u3at(arr_sam_2, monad)); + u3_atom value = u3x_atom(u3at(arr_sam_3, monad)); + + c3_w met_w = u3r_met(3, name); + c3_c* name_c = u3a_malloc(met_w + 1); + u3r_bytes(0, met_w, (c3_y*)name_c, name); + name_c[met_w] = 0; + + IM3Global glob = m3_FindGlobal(sat->wasm_module, name_c); + + if (!glob) + { + fprintf(stderr, ERR("global %s not found"), name_c); + return u3m_bail(c3__fail); + } + + if (!glob->isMutable) + { + fprintf(stderr, ERR("global %s not mutable"), name_c); + return u3m_bail(c3__fail); + } + + M3TaggedValue glob_value; + M3Result result = m3_GetGlobal(glob, &glob_value); + if (result) + { + fprintf(stderr, ERR("couldn't get global %s: %s"), name_c, result); + return u3m_bail(c3__fail); + } + switch (glob_value.type) + { + default: + { + return u3m_bail(c3__fail); + } + case c_m3Type_i32: + { + glob_value.value.i32 = u3r_word(0, value); + break; + } + case c_m3Type_i64: + { + glob_value.value.i64 = u3r_chub(0, value); + break; + } + case c_m3Type_f32: + { + glob_value.value.f32 = u3r_word(0, value); + break; + } + case c_m3Type_f64: + { + glob_value.value.f64 = u3r_chub(0, value); + break; + } + } + result = m3_SetGlobal(glob, &glob_value); + if (result) + { + fprintf(stderr, ERR("couldn't set global %s: %s"), name_c, result); + return u3m_bail(c3__fail); + } + u3z(monad); + u3a_free(name_c); + return u3nc(0, 0); + } + else if (c3y == u3r_sing(monad_bat, sat->match->global_get_bat)) + { + if (c3n == u3r_sing(u3at(ARROW_CTX, monad), sat->match->global_get_ctx)) + { + return u3m_bail(c3__fail); + } + // global-get + u3_atom name = u3x_atom(u3at(arr_sam, monad)); + + c3_w met_w = u3r_met(3, name); + c3_c* name_c = u3a_malloc(met_w + 1); + u3r_bytes(0, met_w, (c3_y*)name_c, name); + name_c[met_w] = 0; + + IM3Global glob = m3_FindGlobal(sat->wasm_module, name_c); + if (!glob) + { + fprintf(stderr, ERR("global %s not found"), name_c); + return u3m_bail(c3__fail); + } + + M3TaggedValue glob_value; + M3Result result = m3_GetGlobal(glob, &glob_value); + if (result) + { + fprintf(stderr, ERR("couldn't get global %s: %s"), name_c, result); + return u3m_bail(c3__fail); + } + + u3_noun out; + switch (glob_value.type) + { + default: + { + return u3m_bail(c3__fail); + } + case c_m3Type_i32: + { + out = u3i_word(glob_value.value.i32); + break; + } + case c_m3Type_i64: + { + out = u3i_chub(glob_value.value.i64); + break; + } + case c_m3Type_f32: + { + out = u3i_word(glob_value.value.f32); + break; + } + case c_m3Type_f64: + { + out = u3i_chub(glob_value.value.f64); + break; + } + } + + u3z(monad); + u3a_free(name_c); + return u3nc(0, out); + + } + else if (c3y == u3r_sing(monad_bat, sat->match->mem_size_bat)) + { + if (c3n == u3r_sing(u3at(MONAD_CTX, monad), sat->match->mem_size_ctx)) + { + return u3m_bail(c3__fail); + } + // memory-size + if (!sat->wasm_module->memoryInfo.hasMemory) + { + fprintf(stderr, ERR("memsize no memory")); + return u3m_bail(c3__fail); + } + c3_w num_pages = sat->wasm_module->runtime->memory.numPages; + + u3z(monad); + return u3nc(0, u3i_word(num_pages)); + } + else if (c3y == u3r_sing(monad_bat, sat->match->mem_grow_bat)) + { + if (c3n == u3r_sing(u3at(ARROW_CTX, monad), sat->match->mem_grow_ctx)) + { + return u3m_bail(c3__fail); + } + // memory-grow + if (!sat->wasm_module->memoryInfo.hasMemory) + { + fprintf(stderr, ERR("memgrow no memory")); + return u3m_bail(c3__fail); + } + + u3_noun delta = u3at(arr_sam, monad); + + c3_l delta_l = (c3y == u3a_is_cat(delta)) ? delta : u3m_bail(c3__fail); + + c3_w n_pages = sat->wasm_module->runtime->memory.numPages; + c3_w required_pages = n_pages + delta_l; + + M3Result result = ResizeMemory(sat->wasm_module->runtime, required_pages); + + if (result) + { + fprintf(stderr, ERR("failed to resize memory: %s"), result); + return u3m_bail(c3__fail); + } + + u3z(monad); + return u3nc(0, u3i_word(n_pages)); + } + else if (c3y == u3r_sing(monad_bat, sat->match->get_acc_bat)) + { + u3z(monad); + return u3nc(0, u3k(sat->acc)); + } + else if (c3y == u3r_sing(monad_bat, sat->match->set_acc_bat)) + { + u3_noun new = u3k(u3at(arr_sam, monad)); + u3z(monad); + u3z(sat->acc); + sat->acc = new; + return u3nc(0, 0); + } + else if (c3y == u3r_sing(monad_bat, sat->match->get_all_glob_bat)) + { + if (c3n == u3r_sing(u3at(MONAD_CTX, monad), sat->match->get_all_glob_ctx)) + { + return u3m_bail(c3__fail); + } + u3z(monad); + u3_noun atoms = u3_nul; + c3_w n_globals = sat->wasm_module->numGlobals; + c3_w n_globals_import = sat->wasm_module->numGlobImports; + while (n_globals-- > n_globals_import) + { + M3Global glob = sat->wasm_module->globals[n_globals]; + switch (glob.type) + { + default: + { + return u3m_bail(c3__fail); + } + case c_m3Type_i32: + { + atoms = u3nc(u3i_word(glob.intValue), atoms); + break; + } + case c_m3Type_i64: + { + atoms = u3nc(u3i_chub(glob.intValue), atoms); + break; + } + case c_m3Type_f32: + { + atoms = u3nc(u3i_word(glob.f32Value), atoms); + break; + } + case c_m3Type_f64: + { + atoms = u3nc(u3i_chub(glob.f64Value), atoms); + break; + } + } + } + return u3nc(0, atoms); + } + else if (c3y == u3r_sing(monad_bat, sat->match->set_all_glob_bat)) + { + if (c3n == u3r_sing(u3at(ARROW_CTX, monad), sat->match->set_all_glob_ctx)) + { + return u3m_bail(c3__fail); + } + u3_noun atoms = u3at(arr_sam, monad); + c3_w n_globals = sat->wasm_module->numGlobals; + c3_w n_globals_import = sat->wasm_module->numGlobImports; + for (c3_w i = n_globals_import; i < n_globals; i++) + { + IM3Global glob = &sat->wasm_module->globals[i]; + u3_noun atom; + u3x_cell(atoms, &atom, &atoms); + u3x_atom(atom); + switch (glob->type) + { + default: + { + return u3m_bail(c3__fail); + } + case c_m3Type_i32: + { + glob->intValue = u3r_word(0, atom); + break; + } + case c_m3Type_i64: + { + glob->intValue = u3r_chub(0, atom); + break; + } + case c_m3Type_f32: + { + glob->f32Value = u3r_word(0, atom); + break; + } + case c_m3Type_f64: + { + glob->f64Value = u3r_chub(0, atom); + break; + } + } + } + if (u3_nul != atoms) + { + fprintf(stderr, WUT("glob list too long")); + return u3m_bail(c3__exit); + } + u3z(monad); + return u3nc(0, 0); + } + else + { + return u3m_bail(c3__fail); + } +} + +// TRANSFERS sat->arrow_yil if m3Lia_Arrow is thrown +static const void * +_link_wasm_with_arrow_map( + IM3Runtime runtime, + IM3ImportContext _ctx, + uint64_t * _sp, + void * _mem +) +{ + const char *mod = _ctx->function->import.moduleUtf8; + const char *name = _ctx->function->import.fieldUtf8; + lia_state* sat = _ctx->userdata; + + u3_noun key = u3nc(u3i_string(mod), u3i_string(name)); + u3_weak arrow = u3kdb_get(u3k(sat->map), key); + if (u3_none == arrow) + { + fprintf(stderr, ERR("import not found: %s/%s"), mod, name); + return m3Err_functionImportMissing; + } + c3_w n_in = _ctx->function->funcType->numArgs; + c3_w n_out = _ctx->function->funcType->numRets; + c3_y* types = _ctx->function->funcType->types; + void **valptrs_in = u3a_calloc(n_in, sizeof(void*)); + for (c3_w i = 0; i < n_in; i++) + { + valptrs_in[i] = &_sp[i+n_out]; + } + void **valptrs_out = u3a_calloc(n_out, sizeof(void*)); + for (c3_w i = 0; i < n_out; i++) + { + valptrs_out[i] = &_sp[i]; + } + + u3_noun coin_wasm_list = _coins_from_stack(valptrs_in, n_in, (types+n_out)); + + u3_noun yil = _reduce_monad(u3n_slam_on(arrow, coin_wasm_list), sat); + + M3Result result = m3Err_none; + + if (0 != u3h(yil)) + { + sat->arrow_yil = yil; + result = m3Lia_Arrow; + } + else + { + c3_o pushed = _coins_to_stack(u3t(yil), valptrs_out, n_out, types); + u3z(yil); + if (c3n == pushed) + { + fprintf(stderr, ERR("import result type mismatch: %s/%s"), mod, name); + result = "import result type mismatch"; + } + } + u3a_free(valptrs_in); + u3a_free(valptrs_out); + return result; +} + +u3_weak +u3we_lia_run(u3_noun cor) +{ +#ifndef URWASM_STATEFUL + return u3_none; +} +#else + if (c3__none == u3at(u3x_sam_7, cor)) + { + return u3_none; + } + + #ifdef URWASM_SUBROAD + + // enter subroad, 4MB safety buffer + u3m_hate(1 << 20); + + #endif + + u3r_mug(cor); + + u3_noun input = u3at(u3x_sam_2, cor); + u3_noun seed = u3at(u3x_sam_6, cor); + + u3_noun runnable = u3j_kink(u3k(u3at(RUN_CTX, cor)), AX_RUNNABLE); + u3_noun try_gate = u3j_kink(u3k(runnable), AX_TRY); + u3_noun try_gate_inner = u3j_kink(try_gate, 2); + + u3_noun seed_new; + u3_noun input_tag, p_input; + u3x_cell(input, &input_tag, &p_input); + + if (input_tag == c3y) + { + u3_noun p_input_gate = u3nt(u3nc(0, 7), 0, u3k(p_input)); // =>(p.input |=(* +>)) + u3_noun past_new = u3n_slam_on( + u3k(try_gate_inner), + u3nc( + u3k(u3at(6, seed)), + p_input_gate + ) + ); + seed_new = u3nq( + u3k(u3at(2, seed)), + past_new, + u3k(u3at(14, seed)), + u3k(u3at(15, seed)) + ); + } + else if (input_tag == c3n) + { + seed_new = u3nq( + u3k(u3at(2, seed)), + u3k(u3at(6, seed)), + u3kb_weld( + u3k(u3at(14, seed)), + u3nc(u3k(p_input), u3_nul) + ), + u3k(u3at(15, seed)) + ); + } + else + { + return u3m_bail(c3__fail); + } + + u3_noun call_script = u3j_kink(u3j_kink(u3k(u3at(RUN_CTX, cor)), AX_CALL), 2); + u3_noun memread_script = u3j_kink(u3j_kink(u3k(u3at(RUN_CTX, cor)), AX_MEMREAD), 2); + u3_noun memwrite_script = u3j_kink(u3j_kink(u3k(u3at(RUN_CTX, cor)), AX_MEMWRITE), 2); + u3_noun call_ext_script = u3j_kink(u3j_kink(u3k(u3at(RUN_CTX, cor)), AX_CALL_EXT), 2); + u3_noun global_set_script = u3j_kink(u3j_kink(u3k(u3at(RUN_CTX, cor)), AX_GLOBAL_SET), 2); + u3_noun global_get_script = u3j_kink(u3j_kink(u3k(u3at(RUN_CTX, cor)), AX_GLOBAL_GET), 2); + u3_noun mem_grow_script = u3j_kink(u3j_kink(u3k(u3at(RUN_CTX, cor)), AX_MEM_GROW), 2); + u3_noun mem_size_script = u3j_kink(u3k(u3at(RUN_CTX, cor)), AX_MEM_SIZE); + + u3_noun try_script = u3j_kink(try_gate_inner, 2); + u3_noun catch_script = u3j_kink(u3j_kink(u3j_kink(u3k(runnable), AX_CATCH), 2), 2); + u3_noun return_script = u3j_kink(u3j_kink(runnable, AX_RETURN), 2); + + u3_noun call_bat = u3k(u3h(call_script)); + u3_noun memread_bat = u3k(u3h(memread_script)); + u3_noun memwrite_bat = u3k(u3h(memwrite_script)); + u3_noun call_ext_bat = u3k(u3h(call_ext_script)); + u3_noun try_bat = u3k(u3h(try_script)); + u3_noun catch_bat = u3k(u3h(catch_script)); + u3_noun return_bat = u3k(u3h(return_script)); + u3_noun global_set_bat = u3k(u3h(global_set_script)); + u3_noun global_get_bat = u3k(u3h(global_get_script)); + u3_noun mem_grow_bat = u3k(u3h(mem_grow_script)); + u3_noun mem_size_bat = u3k(u3h(mem_size_script)); + + u3_noun call_ctx = u3k(u3at(ARROW_CTX, call_script)); + u3_noun memread_ctx = u3k(u3at(ARROW_CTX, memread_script)); + u3_noun memwrite_ctx = u3k(u3at(ARROW_CTX, memwrite_script)); + u3_noun global_set_ctx = u3k(u3at(ARROW_CTX, global_set_script)); + u3_noun global_get_ctx = u3k(u3at(ARROW_CTX, global_get_script)); + u3_noun mem_grow_ctx = u3k(u3at(ARROW_CTX, mem_grow_script)); + u3_noun mem_size_ctx = u3k(u3at(MONAD_CTX, mem_grow_script)); + + u3z(call_script); + u3z(memread_script); + u3z(memwrite_script); + u3z(call_ext_script); + u3z(try_script); + u3z(catch_script); + u3z(return_script); + u3z(global_set_script); + u3z(global_get_script); + u3z(mem_grow_script); + u3z(mem_size_script); + + match_data_struct match = { + call_bat, + memread_bat, + memwrite_bat, + call_ext_bat, + try_bat, + catch_bat, + return_bat, + global_set_bat, + global_get_bat, + mem_grow_bat, + mem_size_bat, + // + call_ctx, + memread_ctx, + memwrite_ctx, + global_set_ctx, + global_get_ctx, + mem_grow_ctx, + mem_size_ctx, + }; + + u3_noun octs = u3at(2, seed_new); + u3_noun p_octs, q_octs; + u3x_cell(octs, &p_octs, &q_octs); + + c3_w bin_len_w = (c3y == u3a_is_cat(p_octs)) ? p_octs : u3m_bail(c3__fail); + c3_y* bin_y = u3r_bytes_alloc(0, bin_len_w, u3x_atom(q_octs)); + + M3Result result; + + result = m3_SetAllocators(u3a_calloc, u3a_free, u3a_realloc); + + if (result) + { + fprintf(stderr, ERR("set allocators fail: %s"), result); + return u3m_bail(c3__fail); + } + + IM3Environment wasm3_env = m3_NewEnvironment(); + if (!wasm3_env) + { + fprintf(stderr, ERR("env is null")); + return u3m_bail(c3__fail); + } + + // 2MB stack + IM3Runtime wasm3_runtime = m3_NewRuntime(wasm3_env, 1 << 21, NULL); + if (!wasm3_runtime) + { + fprintf(stderr, ERR("runtime is null")); + return u3m_bail(c3__fail); + } + + IM3Module wasm3_module; + result = m3_ParseModule(wasm3_env, &wasm3_module, bin_y, bin_len_w); + if (result) + { + fprintf(stderr, ERR("parse binary error: %s"), result); + return u3m_bail(c3__fail); + } + + result = m3_LoadModule(wasm3_runtime, wasm3_module); + if (result) + { + fprintf(stderr, ERR("load module error: %s"), result); + return u3m_bail(c3__fail); + } + + result = m3_ValidateModule(wasm3_module); + if (result) + { + fprintf(stderr, ERR("validation error: %s"), result); + return u3m_bail(c3__fail); + } + + c3_w n_imports = wasm3_module->numFuncImports; + u3_noun monad = u3at(6, seed_new); + u3_noun lia_shop = u3at(14, seed_new); + u3_noun import = u3at(15, seed_new); + + lia_state sat = {wasm3_module, lia_shop, import, &match, 0}; + + for (c3_w i = 0; i < n_imports; i++) + { + M3Function f = wasm3_module->functions[i]; + const char * mod = f.import.moduleUtf8; + const char * name = f.import.fieldUtf8; + + result = m3_LinkRawFunctionEx( + wasm3_module, mod, name, + NULL, &_link_wasm_with_arrow_map, + (void *)&sat + ); + + if (result) + { + fprintf(stderr, ERR("link error: %s"), result); + return u3m_bail(c3__fail); + } + } + + u3_noun yil; + + result = m3_RunStart(wasm3_module); + + if (result == m3Lia_Arrow) + { + yil = sat.arrow_yil; + sat.arrow_yil = 0; + if (yil == 0) + { + return u3m_bail(c3__fail); + } + } + else if (_deterministic_trap(result)) + { + fprintf(stderr, WUT("start function call trapped: %s"), result); + yil = u3nc(2, 0); + } + else if (result) + { + fprintf(stderr, ERR("start function failed: %s"), result); + return u3m_bail(c3__fail); + } + else + { + yil = _reduce_monad(u3k(monad), &sat); + } + + m3_FreeRuntime(wasm3_runtime); + m3_FreeEnvironment(wasm3_env); + + u3a_free(bin_y); + + u3z(match.call_bat); + u3z(match.memread_bat); + u3z(match.memwrite_bat); + u3z(match.call_ext_bat); + u3z(match.try_bat); + u3z(match.catch_bat); + u3z(match.return_bat); + u3z(match.global_set_bat); + u3z(match.global_get_bat); + u3z(match.mem_grow_bat); + u3z(match.mem_size_bat); + + u3z(match.call_ctx); + u3z(match.memread_ctx); + u3z(match.memwrite_ctx); + u3z(global_set_ctx); + u3z(global_get_ctx); + u3z(mem_grow_ctx); + u3z(mem_size_ctx); + + #ifdef URWASM_SUBROAD + // exit subroad, copying the result + u3_noun pro = u3m_love(u3nc(yil, seed_new)); + #else + u3_noun pro = u3nc(yil, seed_new); + #endif + + return pro; +} + +#endif // URWASM_STATEFUL + +u3_weak +u3we_lia_run_once(u3_noun cor) +{ + if (c3__none == u3at(u3x_sam_6, cor)) + { + return u3_none; + } + + #ifdef URWASM_SUBROAD + // enter subroad, 4MB safety buffer + u3m_hate(1 << 20); + #endif + + u3_noun ctx = u3at(ONCE_CTX, cor); + u3r_mug(ctx); + + #define KICK1(TRAP) u3j_kink(TRAP, 2) + #define KICK2(TRAP) u3j_kink(KICK1(TRAP), 2) + + u3_noun runnable = u3j_kink(u3k(ctx), AX_RUNNABLE); + u3_noun arrows = KICK1(u3j_kink(u3k(ctx), AX_ARROWS)); + + u3_noun call_script = KICK1(u3j_kink(u3k(arrows), AX_CALL)); + u3_noun memread_script = KICK1(u3j_kink(u3k(arrows), AX_MEMREAD)); + u3_noun memwrite_script = KICK1(u3j_kink(u3k(arrows), AX_MEMWRITE)); + u3_noun call_ext_script = KICK1(u3j_kink(u3k(arrows), AX_CALL_EXT)); + u3_noun global_set_script = KICK1(u3j_kink(u3k(arrows), AX_GLOBAL_SET)); + u3_noun global_get_script = KICK1(u3j_kink(u3k(arrows), AX_GLOBAL_GET)); + u3_noun mem_grow_script = KICK1(u3j_kink(u3k(arrows), AX_MEM_GROW)); + u3_noun mem_size_script = u3j_kink(u3k(arrows), AX_MEM_SIZE); + u3_noun get_acc_script = u3j_kink(u3k(arrows), AX_GET_ACC); + u3_noun set_acc_script = KICK1(u3j_kink(u3k(arrows), AX_SET_ACC)); + u3_noun get_all_glob_script = u3j_kink(u3k(arrows), AX_GET_ALL_GLOB); + u3_noun set_all_glob_script = KICK1(u3j_kink( arrows, AX_SET_ALL_GLOB)); + + u3_noun try_script = KICK2(u3j_kink(u3k(runnable), AX_TRY)); + u3_noun catch_script = KICK2(u3j_kink(u3k(runnable), AX_CATCH)); + u3_noun return_script = KICK1(u3j_kink( runnable, AX_RETURN)); + + u3_noun call_bat = u3k(u3h(call_script)); + u3_noun memread_bat = u3k(u3h(memread_script)); + u3_noun memwrite_bat = u3k(u3h(memwrite_script)); + u3_noun call_ext_bat = u3k(u3h(call_ext_script)); + u3_noun try_bat = u3k(u3h(try_script)); + u3_noun catch_bat = u3k(u3h(catch_script)); + u3_noun return_bat = u3k(u3h(return_script)); + u3_noun global_set_bat = u3k(u3h(global_set_script)); + u3_noun global_get_bat = u3k(u3h(global_get_script)); + u3_noun mem_grow_bat = u3k(u3h(mem_grow_script)); + u3_noun mem_size_bat = u3k(u3h(mem_size_script)); + u3_noun get_acc_bat = u3k(u3h(get_acc_script)); + u3_noun set_acc_bat = u3k(u3h(set_acc_script)); + u3_noun get_all_glob_bat = u3k(u3h(get_all_glob_script)); + u3_noun set_all_glob_bat = u3k(u3h(set_all_glob_script)); + + u3_noun call_ctx = u3k(u3at(ARROW_CTX, call_script)); + u3_noun memread_ctx = u3k(u3at(ARROW_CTX, memread_script)); + u3_noun memwrite_ctx = u3k(u3at(ARROW_CTX, memwrite_script)); + u3_noun global_set_ctx = u3k(u3at(ARROW_CTX, global_set_script)); + u3_noun global_get_ctx = u3k(u3at(ARROW_CTX, global_get_script)); + u3_noun mem_grow_ctx = u3k(u3at(ARROW_CTX, mem_grow_script)); + u3_noun mem_size_ctx = u3k(u3at(MONAD_CTX, mem_size_script)); + u3_noun get_all_glob_ctx = u3k(u3at(MONAD_CTX, get_all_glob_script)); + u3_noun set_all_glob_ctx = u3k(u3at(ARROW_CTX, set_all_glob_script)); + + u3z(call_script); + u3z(memread_script); + u3z(memwrite_script); + u3z(call_ext_script); + u3z(try_script); + u3z(catch_script); + u3z(return_script); + u3z(global_set_script); + u3z(global_get_script); + u3z(mem_grow_script); + u3z(mem_size_script); + u3z(get_acc_script); + u3z(set_acc_script); + u3z(get_all_glob_script); + u3z(set_all_glob_script); + + + match_data_struct match = { + call_bat, + memread_bat, + memwrite_bat, + call_ext_bat, + try_bat, + catch_bat, + return_bat, + global_set_bat, + global_get_bat, + mem_grow_bat, + mem_size_bat, + get_acc_bat, + set_acc_bat, + get_all_glob_bat, + set_all_glob_bat, + // + call_ctx, + memread_ctx, + memwrite_ctx, + global_set_ctx, + global_get_ctx, + mem_grow_ctx, + mem_size_ctx, + get_all_glob_ctx, + set_all_glob_ctx, + }; + + u3_noun octs = u3at(u3x_sam_4, cor); + u3_noun p_octs, q_octs; + u3x_cell(octs, &p_octs, &q_octs); + + c3_w bin_len_w = (c3y == u3a_is_cat(p_octs)) ? p_octs : u3m_bail(c3__fail); + c3_y* bin_y = u3r_bytes_alloc(0, bin_len_w, u3x_atom(q_octs)); + + M3Result result; + + result = m3_SetAllocators(u3a_calloc, u3a_free, u3a_realloc); + + if (result) + { + fprintf(stderr, ERR("set allocators fail: %s"), result); + return u3m_bail(c3__fail); + } + + IM3Environment wasm3_env = m3_NewEnvironment(); + if (!wasm3_env) + { + fprintf(stderr, ERR("env is null")); + return u3m_bail(c3__fail); + } + + // 2MB stack + IM3Runtime wasm3_runtime = m3_NewRuntime(wasm3_env, 1 << 21, NULL); + if (!wasm3_runtime) + { + fprintf(stderr, ERR("runtime is null")); + return u3m_bail(c3__fail); + } + + IM3Module wasm3_module; + result = m3_ParseModule(wasm3_env, &wasm3_module, bin_y, bin_len_w); + if (result) + { + fprintf(stderr, ERR("parse binary error: %s"), result); + return u3m_bail(c3__fail); + } + + result = m3_LoadModule(wasm3_runtime, wasm3_module); + if (result) + { + fprintf(stderr, ERR("load module error: %s"), result); + return u3m_bail(c3__fail); + } + + result = m3_ValidateModule(wasm3_module); + if (result) + { + fprintf(stderr, ERR("validation error: %s"), result); + return u3m_bail(c3__fail); + } + + c3_w n_imports = wasm3_module->numFuncImports; + u3_noun monad = u3at(u3x_sam_7, cor); + u3_noun lia_shop = u3_nul; + u3_noun import = u3at(u3x_sam_5, cor); + + u3_noun acc, map; + u3x_cell(import, &acc, &map); + + lia_state sat = {wasm3_module, lia_shop, u3k(acc), map, &match, 0}; + + for (c3_w i = 0; i < n_imports; i++) + { + M3Function f = wasm3_module->functions[i]; + const char * mod = f.import.moduleUtf8; + const char * name = f.import.fieldUtf8; + + result = m3_LinkRawFunctionEx( + wasm3_module, mod, name, + NULL, &_link_wasm_with_arrow_map, + (void *)&sat + ); + + if (result) + { + fprintf(stderr, ERR("link error: %s"), result); + return u3m_bail(c3__fail); + } + } + + u3_noun yil; + + result = m3_RunStart(wasm3_module); + + if (result == m3Lia_Arrow) + { + yil = sat.arrow_yil; + sat.arrow_yil = 0; + if (yil == 0) + { + return u3m_bail(c3__fail); + } + } + else if (_deterministic_trap(result)) + { + fprintf(stderr, WUT("start function call trapped: %s"), result); + yil = u3nc(2, 0); + } + else if (result == m3Err_functionImportMissing) + { + return u3m_bail(c3__exit); + } + else if (result) + { + fprintf(stderr, ERR("start function failed: %s"), result); + return u3m_bail(c3__fail); + } + else + { + yil = _reduce_monad(u3k(monad), &sat); + } + + m3_FreeRuntime(wasm3_runtime); + m3_FreeEnvironment(wasm3_env); + + u3a_free(bin_y); + + u3z(match.call_bat); + u3z(match.memread_bat); + u3z(match.memwrite_bat); + u3z(match.call_ext_bat); + u3z(match.try_bat); + u3z(match.catch_bat); + u3z(match.return_bat); + u3z(match.global_set_bat); + u3z(match.global_get_bat); + u3z(match.mem_grow_bat); + u3z(match.mem_size_bat); + u3z(match.get_acc_bat); + u3z(match.set_acc_bat); + u3z(match.get_all_glob_bat); + u3z(match.set_all_glob_bat); + + u3z(match.call_ctx); + u3z(match.memread_ctx); + u3z(match.memwrite_ctx); + u3z(global_set_ctx); + u3z(global_get_ctx); + u3z(mem_grow_ctx); + u3z(mem_size_ctx); + u3z(get_all_glob_ctx); + u3z(set_all_glob_ctx); + + #ifdef URWASM_SUBROAD + // exit subroad, copying the result + u3_noun pro = u3m_love(u3nc(yil, sat.acc)); + #else + u3_noun pro = u3nc(yil, sat.acc); + #endif + + return pro; +} diff --git a/pkg/noun/jets/tree.c b/pkg/noun/jets/tree.c index 59a93204bb..d03cbd8ef4 100644 --- a/pkg/noun/jets/tree.c +++ b/pkg/noun/jets/tree.c @@ -2359,6 +2359,58 @@ static u3j_core _138_hex_chacha_d[] = {} }; +// urwasm jet registration +// +static u3j_harm _138_hex_lia_run_a[] = {{".2", u3we_lia_run, c3y}, {}}; + +static u3j_harm _138_hex_lia_run_once_inner_a[] = {{".2", u3we_lia_run_once, c3y}, {}}; + +static u3j_core _138_hex_lia_run_once_d[] = { + { "run-once-inner-v0", 15, _138_hex_lia_run_once_inner_a, 0, no_hashes }, + {} +}; + +static u3j_core _138_hex_lia_monad_d[] = { + { "run-v0", 7, _138_hex_lia_run_a, 0, no_hashes }, + { "run-once-v0", 7, 0, _138_hex_lia_run_once_d, no_hashes }, + {} +}; + +static u3j_core _138_hex_wasm_engine_d[] = { + { "monad-v0", 3, 0, _138_hex_lia_monad_d, no_hashes }, + {} +}; + +static u3j_core _138_hex_wasm_op_def_d[] = { + { "wasm-engine-v0", 3, 0, _138_hex_wasm_engine_d, no_hashes }, + {} +}; + +static u3j_core _138_hex_wasm_validator_d[] = { + { "wasm-op-def-v0", 3, 0, _138_hex_wasm_op_def_d, no_hashes }, + {} +}; + +static u3j_core _138_hex_wasm_parser_d[] = { + { "validator-v0", 3, 0, _138_hex_wasm_validator_d, no_hashes }, + {} +}; + +static u3j_core _138_hex_lia_sur_d[] = { + { "wasm-parser-v0", 3, 0, _138_hex_wasm_parser_d, no_hashes }, + {} +}; + +static u3j_core _138_hex_wasm_engine_sur_d[] = { + { "monad-sur-v0", 3, 0, _138_hex_lia_sur_d, no_hashes }, + {} +}; + +static u3j_core _138_hex_wasm_sur_d[] = { + { "engine-sur-v0", 3, 0, _138_hex_wasm_engine_sur_d, no_hashes }, + {} +}; + static u3j_core _138_hex_d[] = { { "lore", 63, _140_hex_lore_a, 0, no_hashes }, { "leer", 63, _140_hex_leer_a, 0, no_hashes }, @@ -2378,6 +2430,7 @@ static u3j_core _138_hex_d[] = { "secp", 6, 0, _140_hex_secp_d, no_hashes }, { "mimes", 31, 0, _140_hex_mimes_d, no_hashes }, { "json", 31, 0, _139_hex_json_d, no_hashes }, + { "wasm-sur-v0", 3, 0, _138_hex_wasm_sur_d, no_hashes }, {} }; diff --git a/pkg/noun/jets/w.h b/pkg/noun/jets/w.h index 78494314fe..befa2a7b30 100644 --- a/pkg/noun/jets/w.h +++ b/pkg/noun/jets/w.h @@ -304,6 +304,9 @@ u3_noun u3we_crc32(u3_noun); + u3_noun u3we_lia_run(u3_noun); + u3_noun u3we_lia_run_once(u3_noun); + /** Tier 6. **/ u3_noun u3wf_bull(u3_noun);