diff --git a/build.zig b/build.zig index 7de5f9f83b..94ca6b7a2a 100644 --- a/build.zig +++ b/build.zig @@ -363,6 +363,11 @@ fn buildBinary( .optimize = optimize, }); + const wasm3 = b.dependency("wasm3", .{ + .target = target, + .optimize = optimize, + }); + // // Build Artifact // @@ -418,6 +423,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..55d9473907 --- /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/urbit/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 73d6d79e1e..c46f1029ab 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()) @@ -229,6 +235,7 @@ const c_source_files = [_][]const u8{ "jets/c/rig.c", "jets/c/rip.c", "jets/c/rsh.c", + "jets/c/sew.c", "jets/c/sqt.c", "jets/c/swp.c", "jets/c/xeb.c", @@ -315,6 +322,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 760f84e593..1ce21ebf99 100644 --- a/pkg/noun/jets/137/tree.c +++ b/pkg/noun/jets/137/tree.c @@ -874,6 +874,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 }, @@ -900,6 +950,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 }, {} }; @@ -1033,6 +1084,7 @@ static u3j_core _137_two__in_d[] = static u3j_harm _137_two_rig_a[] = {{".2", u3wc_rig, c3n}, {}}; static u3j_harm _137_two_mate_a[] = {{".2", u3wb_mate, c3y}, {}}; +static u3j_harm _137_two_sew_a[] = {{".2", u3wc_sew, c3y}, {}}; static u3j_core _137_two_d[] = { { "tri", 3, 0, _137_tri_d, no_hashes, _137_tri_ho }, @@ -1091,6 +1143,7 @@ static u3j_core _137_two_d[] = { "swp", 7, _137_two_swp_a, 0, no_hashes }, { "rub", 7, _137_two_rub_a, 0, no_hashes }, { "pow", 7, _137_two_pow_a, 0, no_hashes }, + { "sew", 7, _137_two_sew_a, 0, no_hashes }, { "sqt", 7, _137_two_sqt_a, 0, no_hashes }, { "xeb", 7, _137_two_xeb_a, 0, no_hashes }, diff --git a/pkg/noun/jets/c/bex.c b/pkg/noun/jets/c/bex.c index f064dc7a79..097df28b9a 100644 --- a/pkg/noun/jets/c/bex.c +++ b/pkg/noun/jets/c/bex.c @@ -34,7 +34,7 @@ u3qc_bex(u3_atom a) u3i_slab_init(&sab_u, 0, a_d + 1); - sab_u.buf_w[a_d >> 5] = 1 << (a_d & 31); + sab_u.buf_w[a_d >> 5] = (c3_d)1 << (a_d & 31); return u3i_slab_moot(&sab_u); } diff --git a/pkg/noun/jets/c/sew.c b/pkg/noun/jets/c/sew.c new file mode 100644 index 0000000000..fd85d0b9c7 --- /dev/null +++ b/pkg/noun/jets/c/sew.c @@ -0,0 +1,74 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" + +u3_weak +u3qc_sew(u3_atom a, + u3_atom b, + u3_atom c, + u3_atom d, + u3_atom e + ) +{ + if (0 == c) return u3k(e); + if ( !_(u3a_is_cat(b)) || + !_(u3a_is_cat(c)) ) { + return u3_none; + } + if ( !_(u3a_is_cat(a)) || (a >= 32) ) { + return u3m_bail(c3__fail); + } + + c3_g a_g = a; + c3_w b_w = b, c_w = c; + c3_w len_e_w = u3r_met(a_g, e); + u3i_slab sab_u; + c3_w* src_w; + c3_w len_src_w; + if ( _(u3a_is_cat(e)) ) { + len_src_w = e ? 1 : 0; + src_w = &e; + } + else { + u3a_atom* src_u = u3a_to_ptr(e); + len_src_w = src_u->len_w; + src_w = src_u->buf_w; + } + u3i_slab_init(&sab_u, a_g, c3_max(len_e_w, b_w + c_w)); + u3r_chop_words(a_g, 0, b_w, 0, sab_u.buf_w, len_src_w, src_w); + u3r_chop(a_g, 0, c_w, b_w, sab_u.buf_w, d); + if (len_e_w > b_w + c_w) { + u3r_chop_words(a_g, + b_w + c_w, + len_e_w - (b_w + c_w), + b_w + c_w, + sab_u.buf_w, + len_src_w, + src_w); + } + return u3i_slab_mint(&sab_u); +} + +u3_weak +u3wc_sew(u3_noun cor) +{ + u3_noun a, b, c, d, e; + if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, + u3x_sam_12, &b, + 106, &c, + 107, &d, + u3x_sam_7, &e, 0)) || + (c3n == u3ud(a)) || + (c3n == u3ud(b)) || + (c3n == u3ud(c)) || + (c3n == u3ud(d)) || + (c3n == u3ud(e)) ) + { + return u3m_bail(c3__fail); + } else { + return u3qc_sew(a, b, c, d, e); + } +} 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/q.h b/pkg/noun/jets/q.h index 5160058a9d..ee059c43f4 100644 --- a/pkg/noun/jets/q.h +++ b/pkg/noun/jets/q.h @@ -79,6 +79,7 @@ u3_noun u3qc_rig(u3_atom, u3_atom, u3_atom); u3_noun u3qc_rip(u3_atom, u3_atom, u3_atom); u3_noun u3qc_rsh(u3_atom, u3_atom, u3_atom); + u3_noun u3qc_sew(u3_atom, u3_atom, u3_atom, u3_atom, u3_atom); u3_noun u3qc_swp(u3_atom, u3_atom); u3_noun u3qc_sqt(u3_atom); diff --git a/pkg/noun/jets/w.h b/pkg/noun/jets/w.h index 340ecf2bad..2a2a2c9999 100644 --- a/pkg/noun/jets/w.h +++ b/pkg/noun/jets/w.h @@ -82,6 +82,7 @@ u3_noun u3wc_rig(u3_noun); u3_noun u3wc_rip(u3_noun); u3_noun u3wc_rsh(u3_noun); + u3_noun u3wc_sew(u3_noun); u3_noun u3wc_swp(u3_noun); u3_noun u3wc_sqt(u3_noun); @@ -315,6 +316,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); diff --git a/pkg/vere/disk.c b/pkg/vere/disk.c index 6cb3b62ca9..173a4a8089 100644 --- a/pkg/vere/disk.c +++ b/pkg/vere/disk.c @@ -839,7 +839,7 @@ static c3_i _disk_acquire(c3_c* pax_c) { c3_c* paf_c = _disk_lock(pax_c); - c3_y dat_y[12] = {0}; + c3_y dat_y[13] = {0}; c3_w pid_w = 0; c3_i fid_i, ret_i; @@ -872,7 +872,7 @@ _disk_acquire(c3_c* pax_c) len_y++; buf_y++; } - while ( len_y < sizeof(dat_y) ); + while ( len_y < (sizeof(dat_y) - 1) ); // null terminate if ( len_y ) { diff --git a/pkg/vere/io/mesa.c b/pkg/vere/io/mesa.c index 83e1a91909..8666f6763a 100644 --- a/pkg/vere/io/mesa.c +++ b/pkg/vere/io/mesa.c @@ -42,6 +42,9 @@ static c3_y are_y[524288]; #define DIRECT_ROUTE_TIMEOUT_MICROS 5000000 #define DIRECT_ROUTE_RETRY_MICROS 1000000 +#define PIT_EXPIRE_MICROS 20000000 + +#define JUMBO_CACHE_MAX_SIZE 200000000 // 200 mb // logging and debug symbols #define MESA_SYM_DESC(SYM) MESA_DESC_ ## SYM @@ -106,7 +109,6 @@ typedef struct _u3_gage { c3_w sst_w; // ssthresh c3_w con_w; // counter // - uv_timer_t tim_u; } u3_gage; struct _u3_mesa; @@ -138,6 +140,7 @@ typedef struct _u3_pit_addr { typedef struct _u3_pit_entry { u3_pit_addr* adr_u; + c3_d tim_d; arena are_u; } u3_pit_entry; @@ -158,6 +161,11 @@ static void u3_shap_to_ship( u3_ship ship, u3_shap shap ) ship[1] = shap.tel_d; } +static void u3_free_pit( u3_pit_entry* pit_u ) +{ + arena_free(&pit_u->are_u); +} + static void u3_free_str( u3_str key ) { c3_free(key.str_c); @@ -205,6 +213,7 @@ typedef struct _u3_pend_req u3_pend_req; #define HASH_FN u3_hash_str #define CMPR_FN u3_cmpr_str #define VAL_TY u3_pit_entry* +#define VAL_DTOR_FN u3_free_pit #include "verstable.h" #define NAME gag_map @@ -214,9 +223,6 @@ typedef struct _u3_pend_req u3_pend_req; #define VAL_TY u3_gage* #include "verstable.h" -typedef struct _u3_mesa_line u3_mesa_line; - - typedef enum _u3_mesa_ctag { CTAG_WAIT = 1, CTAG_BLOCK = 2, @@ -242,9 +248,19 @@ typedef struct _u3_mesa_line { arena are_u; } u3_mesa_line; + +static void u3_free_line( u3_mesa_line* lin_u ) +{ + // CTAG_WAIT, CTAG_BLOCK + if ( lin_u > (u3_mesa_line*)2 ) { + arena_free(&lin_u->are_u); + } +} + #define NAME jum_map #define KEY_TY u3_str #define KEY_DTOR_FN u3_free_str +#define VAL_DTOR_FN u3_free_line #define HASH_FN u3_hash_str #define CMPR_FN u3_cmpr_str #define VAL_TY u3_mesa_line* @@ -269,9 +285,8 @@ typedef struct _u3_mesa { u3_mesa_stat sat_u; // statistics c3_l sev_l; // XX: ?? c3_o for_o; // is forwarding - ur_cue_test_t* tes_u; // cue-test handle - u3_cue_xeno* sil_u; // cue handle per_map per_u; // (map ship u3_peer) + c3_d jum_d; // bytes in jumbo cache jum_map jum_u; // jumbo cache gag_map gag_u; // lane cache pit_map pit_u; // (map path [our=? las=(set lane)]) @@ -280,6 +295,7 @@ typedef struct _u3_mesa { c3_d tim_d; // XX: remove arena are_u; // per packet arena arena par_u; // permanent arena + uv_timer_t tim_u; // pit clear timer } u3_mesa; typedef struct _u3_peer { @@ -950,7 +966,7 @@ static c3_i _mesa_send_buf2(struct sockaddr** ads_u, uv_buf_t** bfs_u, c3_w* int // } // } } -static void _mesa_send_buf3(sockaddr_in add_u, uv_buf_t buf_u, u3_pend_req* req_u, c3_d fra_d) +static void _mesa_send_buf3(sockaddr_in add_u, uv_buf_t buf_u) { add_u.sin_addr.s_addr = ( u3_Host.ops_u.net == c3y ) ? add_u.sin_addr.s_addr : htonl(0x7f000001); @@ -1071,13 +1087,14 @@ _mesa_send_bufs(u3_mesa* sam_u, u3_pit_addr* las_u); static void -_mesa_send_modal(u3_peer* per_u, c3_y* buf_y, c3_w len_w) +_mesa_send_modal(u3_peer* per_u, uv_buf_t buf_u) { u3_mesa* sam_u = per_u->sam_u; c3_d now_d = _get_now_micros(); + c3_w len_w = buf_u.len; c3_y* sen_y = c3_calloc(len_w); - memcpy(sen_y, buf_y, len_w); + memcpy(sen_y, buf_u.base, len_w); u3_ship gal_u = {0}; gal_u[0] = per_u->imp_y; @@ -1102,11 +1119,9 @@ _mesa_send_modal(u3_peer* per_u, c3_y* buf_y, c3_w len_w) _mesa_send_buf(sam_u, imp_u, sen_y, len_w); per_u->ind_u.sen_d = now_d; - if ( (c3n == _mesa_is_lane_zero(per_u->dan_u)) - // && (per_u->dir_u.sen_d + DIRECT_ROUTE_RETRY_MICROS > now_d) // XX same check as _mesa_is_direct_mode - ) { + if ( c3n == _mesa_is_lane_zero(per_u->dan_u) ) { c3_y* san_y = c3_calloc(len_w); - memcpy(san_y, buf_y, len_w); + memcpy(san_y, buf_u.base, len_w); _mesa_send_buf(sam_u, per_u->dan_u, san_y, len_w); per_u->dir_u.sen_d = now_d; } @@ -1126,8 +1141,9 @@ _mesa_send_request(u3_mesa_request_data* dat_u) dat_u->las_u); } else { - u3l_log("mesa: send_modal()"); - _mesa_send_modal(per_u, dat_u->buf_y, dat_u->len_w); + /* u3l_log("mesa: send_modal()"); */ + uv_buf_t buf_u = uv_buf_init((c3_c*)dat_u->buf_y, dat_u->len_w); + _mesa_send_modal(per_u, buf_u); } } @@ -1168,7 +1184,7 @@ _try_resend(u3_pend_req* req_u, c3_d nex_d) c3_d now_d = _get_now_micros(); u3_mesa_pact *pac_u = &req_u->pic_u->pac_u; - c3_y buf_y[PACT_SIZE]; + /* c3_y buf_y[PACT_SIZE]; */ /* arena scr_u = req_u->are_u; */ /* uv_buf_t* bfs_u = new(&scr_u, uv_buf_t, 1); */ c3_w i_w = 0; @@ -1191,8 +1207,8 @@ _try_resend(u3_pend_req* req_u, c3_d nex_d) /* new(&scr_u, uv_buf_t, 1); */ /* bfs_u[i_w] = buf_u; */ /* c3_w len_w = mesa_etch_pact_to_buf(buf_y, PACT_SIZE, pac_u); */ - _mesa_send_buf3(req_u->per_u->dan_u, buf_u, req_u, i_d); - // _mesa_send_modal(req_u->per_u, (c3_y*)buf_u.base, buf_u.len); + /* _mesa_send_buf3(req_u->per_u->dan_u, buf_u, req_u, i_d); */ + _mesa_send_modal(req_u->per_u, buf_u); _mesa_req_pact_resent(req_u, &pac_u->pek_u.nam_u, now_d); i_w++; } @@ -1354,12 +1370,13 @@ _mesa_req_pact_done(u3_pend_req* req_u, else if ( c3y != lss_verifier_ingest(req_u->los_u, dat_u->fra_y, dat_u->len_w, par_u) ) { u3l_log("auth fail frag %"PRIu64, nam_u->fra_d); u3l_log("nit_o %u", nam_u->nit_o); - // TODO: do we drop the whole request on the floor? + _mesa_del_request(sam_u, nam_u); MESA_LOG(sam_u, AUTH); return; } else if ( c3y != _mesa_burn_misorder_queue(req_u, nam_u->boq_y, req_u->los_u->counter) ) { MESA_LOG(sam_u, AUTH) + _mesa_del_request(sam_u, nam_u); return; } else { @@ -1452,8 +1469,6 @@ _mesa_send_bufs(u3_mesa* sam_u, } } -static void _mesa_add_our_to_pit(u3_mesa*, u3_mesa_name*); - static u3_pit_entry* _mesa_get_pit(u3_mesa* sam_u, u3_mesa_name* nam_u) { @@ -1468,13 +1483,7 @@ static void _mesa_del_pit(u3_mesa* sam_u, u3_mesa_name* nam_u) { /* u3l_log("deleting %llu", nam_u->fra_d); */ - u3_pit_entry* pin_u = _mesa_get_pit(sam_u, nam_u); - if ( pin_u == NULL) { - u3l_log("deleting non existent key in PIT"); - return; - } vt_erase(&sam_u->pit_u, nam_u->str_u); - arena_free(&pin_u->are_u); } static void @@ -1482,10 +1491,13 @@ _mesa_add_lane_to_pit(u3_mesa* sam_u, u3_mesa_name* nam_u, sockaddr_in lan_u) { pit_map_itr itr_u = vt_get(&sam_u->pit_u, nam_u->str_u); + c3_d now_d = _get_now_micros(); + if ( vt_is_end(itr_u) ) { arena are_u = arena_create(16384); u3_pit_entry* ent_u = new(&are_u, u3_pit_entry, 1); ent_u->are_u = are_u; + ent_u->tim_d = now_d; u3_pit_addr* adr_u = new(&ent_u->are_u, u3_pit_addr, 1); adr_u->nex_p = 0; adr_u->sdr_u = lan_u; @@ -1505,6 +1517,7 @@ _mesa_add_lane_to_pit(u3_mesa* sam_u, u3_mesa_name* nam_u, sockaddr_in lan_u) } else { u3_pit_entry* ent_u = itr_u.data->val; + ent_u->tim_d = now_d; u3_pit_addr* old_u = ent_u->adr_u; while (old_u) { if ( c3y == _mesa_lanes_equal(lan_u, old_u->sdr_u) ) { @@ -1522,33 +1535,6 @@ _mesa_add_lane_to_pit(u3_mesa* sam_u, u3_mesa_name* nam_u, sockaddr_in lan_u) return; } -static void -_mesa_add_our_to_pit(u3_mesa* sam_u, u3_mesa_name* nam_u) -{ - c3_y buf_y[PACT_SIZE]; - sockaddr_in adr_u = {0}; - u3_mesa_name tmp_u = *nam_u; - /* u3l_log("putting %llu", tmp_u.fra_d); */ - /* log_name(&tmp_u); */ - u3_etcher ech_u; - - etcher_init(&ech_u, buf_y, PACT_SIZE); - _mesa_etch_name(&ech_u, &tmp_u); - - /* int i; */ - /* for (i = 0; i < ech_u.len_w; i++) */ - /* { */ - /* if (i > 0) fprintf(stderr, ":"); */ - /* fprintf(stderr, "%02X", buf_y[i]); */ - /* } */ - /* fprintf(stderr, "\n"); */ - - tmp_u.str_u.str_c = (c3_c*)buf_y; - tmp_u.str_u.len_w = ech_u.len_w; - _mesa_add_lane_to_pit(sam_u, &tmp_u, adr_u); - return; -} - static void _mesa_resend_timer_cb(uv_timer_t* tim_u) { @@ -1707,7 +1693,6 @@ _mesa_ef_send(u3_mesa* sam_u, u3_noun las, u3_noun pac) uv_timer_init(u3L, &res_u->tim_u); } _mesa_put_request(sam_u, nam_u, (u3_pend_req*)CTAG_WAIT); - /* _mesa_add_our_to_pit(sam_u, nam_u); */ res_u->tim_u.data = res_u; #ifdef PACKET_TEST packet_test(sam_u, "pages.packs"); @@ -1793,7 +1778,7 @@ static c3_o _mesa_kick(u3_mesa* sam_u, u3_noun tag, u3_noun dat) } break; } - // technically losing tag is unncessary as it always should + // technically losing tag is unnecessary as it always should // be a direct atom, but better to be strict u3z(dat); u3z(tag); return ret_o; @@ -1832,13 +1817,8 @@ _mesa_io_slog(u3_auto* car_u) { } static void -_mesa_exit_cb(uv_handle_t* had_u) -{ - u3_mesa* sam_u = had_u->data; - - u3s_cue_xeno_done(sam_u->sil_u); - ur_cue_test_done(sam_u->tes_u); - +_mesa_exit_cb(uv_handle_t* han_u) { + u3_mesa* sam_u = (u3_mesa*)han_u->data; arena_free(&sam_u->par_u); } @@ -1846,7 +1826,9 @@ static void _mesa_io_exit(u3_auto* car_u) { u3_mesa* sam_u = (u3_mesa*)car_u; - uv_close(&sam_u->had_u, _mesa_exit_cb); + uv_timer_stop(&sam_u->tim_u); + sam_u->tim_u.data = sam_u; + uv_close((uv_handle_t*)&sam_u->tim_u, _mesa_exit_cb); } static void @@ -1924,6 +1906,16 @@ _mesa_put_jumbo_cache(u3_mesa* sam_u, u3_mesa_name* nam_u, u3_mesa_line* lin_u) c3_w len_w = _name_to_jumbo_str(nam_u, buf_y); u3_str str_u = {(c3_c*)buf_y, len_w}; + // CTAG_BLOCK, CTAG_WAIT + if ( lin_u > (u3_mesa_line*)2 ) { + if (sam_u->jum_d > JUMBO_CACHE_MAX_SIZE) { + vt_cleanup(&sam_u->jum_u); + sam_u->jum_d = 0; + } + + sam_u->jum_d += lin_u->tob_d; + } + jum_map_itr itr_u = vt_insert(&sam_u->jum_u, str_u, lin_u); if ( vt_is_end(itr_u) ) { @@ -2286,7 +2278,6 @@ _mesa_request_next_fragments(u3_mesa* sam_u, u3l_log("peek overflow, dying, fragment %u", nex_d+i); abort(); } - /* _mesa_add_our_to_pit(sam_u, &nex_u->pac_u.pek_u.nam_u); */ mesa_etch_pact_to_buf((c3_y*)buf_u.base, buf_u.len, &nex_u->pac_u); /* bfs_u[i] = buf_u; */ /* bus_u[i] = &bfs_u[i]; */ @@ -2294,8 +2285,8 @@ _mesa_request_next_fragments(u3_mesa* sam_u, /* int_u[i] = 1; */ _mesa_req_pact_sent(req_u, fra_w, now_d); - _mesa_send_buf3(req_u->per_u->dan_u, buf_u, req_u, fra_w); - // _mesa_send_modal(req_u->per_u, (c3_y*)buf_u.base, buf_u.len); + /* _mesa_send_buf3(req_u->per_u->dan_u, buf_u, req_u, fra_w); */ + _mesa_send_modal(req_u->per_u, buf_u); /* _mesa_send(nex_u, lan_u); */ } /* if ( i > 0 ) { */ @@ -2940,9 +2931,7 @@ _mesa_io_talk(u3_auto* car_u) { // XX remove [sev_l] // - u3_noun wir = u3nt(c3__ames, - u3dc("scot", c3__uv, sam_u->sev_l), - u3_nul); + u3_noun wir = u3nc(c3__ames, u3_nul); u3_noun cad = u3nc(c3__born, u3_nul); u3_auto_plan(car_u, u3_ovum_init(0, c3__a, wir, cad)); @@ -3017,6 +3006,23 @@ _mesa_io_talk(u3_auto* car_u) //u3z(rac); u3z(who); } +static void _mesa_clear_pit(uv_timer_t *tim_u) +{ + u3_mesa* sam_u = (u3_mesa*)tim_u->data; + pit_map_itr itr_u = vt_first( &sam_u->pit_u ); + + c3_d now_d = _get_now_micros(); + + while (!vt_is_end(itr_u)) { + u3_pit_entry* pit_u = itr_u.data->val; + if ( (now_d - pit_u->tim_d) > PIT_EXPIRE_MICROS) { + itr_u = vt_erase_itr(&sam_u->pit_u, itr_u); + } else { + itr_u = vt_next(itr_u); + } + } +} + /* _mesa_io_init(): initialize ames I/O. */ u3_auto* @@ -3035,18 +3041,20 @@ u3_mesa_io_init(u3_pier* pir_u) are_u.end = (char*)(are_y + 524288); sam_u->are_u = are_u; + sam_u->jum_d = 0; + + uv_timer_init(u3L, &sam_u->tim_u); + + // clear pit every 30 seconds + sam_u->tim_u.data = sam_u; + uv_timer_start(&sam_u->tim_u, _mesa_clear_pit, 30000, 30000); + vt_init(&sam_u->pit_u); vt_init(&sam_u->per_u); vt_init(&sam_u->gag_u); vt_init(&sam_u->jum_u); vt_init(&sam_u->req_u); - u3_assert( !uv_udp_init_ex(u3L, &sam_u->wax_u, UV_UDP_RECVMMSG) ); - sam_u->wax_u.data = sam_u; - - sam_u->sil_u = u3s_cue_xeno_init(); - sam_u->tes_u = ur_cue_test_init(); - // Disable networking for fake ships // if ( c3y == sam_u->pir_u->fak_o ) { @@ -3065,6 +3073,7 @@ u3_mesa_io_init(u3_pier* pir_u) u3_auto* car_u = &sam_u->car_u; + memset(car_u, 0, sizeof(*car_u)); car_u->nam_m = c3__ames; car_u->liv_o = c3y; car_u->io.talk_f = _mesa_io_talk;