diff options
| author | Xavier Del Campo Romero <xavi.dcr@tutanota.com> | 2024-09-07 00:04:38 +0200 |
|---|---|---|
| committer | Xavier Del Campo Romero <xavi92@disroot.org> | 2025-11-06 14:38:40 +0100 |
| commit | 6d9d80362f9932bbc87e162b8ef7df06c73e27e1 (patch) | |
| tree | e3e228c63fe26f07503f226de7fb5086b3dc2286 /src/op | |
| download | nanowasm-6d9d80362f9932bbc87e162b8ef7df06c73e27e1.tar.gz | |
First commit
Diffstat (limited to 'src/op')
51 files changed, 2635 insertions, 0 deletions
diff --git a/src/op/CMakeLists.txt b/src/op/CMakeLists.txt new file mode 100644 index 0000000..53036f0 --- /dev/null +++ b/src/op/CMakeLists.txt @@ -0,0 +1,45 @@ +# nanowasm, a tiny WebAssembly/Wasm interpreter +# Copyright (C) 2023-2025 Xavier Del Campo Romero +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at https://mozilla.org/MPL/2.0/. + +target_sources(${PROJECT_NAME} PRIVATE + block.c + br.c + br_if.c + call.c + call_indirect.c + drop.c + end.c + get_local.c + get_global.c + i32_add.c + i32_and.c + i32_const.c + i32_eq.c + i32_eqz.c + i32_ge_s.c + i32_ge_u.c + i32_load.c + i32_load8_u.c + i32_lt_s.c + i32_mul.c + i32_ne.c + i32_or.c + i32_store.c + i32_sub.c + i64_const.c + i64_store.c + loop.c + nop.c + return.c + set_global.c + set_local.c + tee_local.c + tostr.c + unreachable.c +) + +add_subdirectory(check) diff --git a/src/op/block.c b/src/op/block.c new file mode 100644 index 0000000..e35a722 --- /dev/null +++ b/src/op/block.c @@ -0,0 +1,17 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2025 Xavier Del Campo Romero + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include <nanowasm/nw.h> +#include <nw/ops.h> +#include <nw/routines.h> + +void nwp_op_block(struct nw_interp *const i) +{ + nwp_start_block(i); +} diff --git a/src/op/br.c b/src/op/br.c new file mode 100644 index 0000000..83ceca7 --- /dev/null +++ b/src/op/br.c @@ -0,0 +1,36 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2025 Xavier Del Campo Romero + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include <nanowasm/nw.h> +#include <nw/interp.h> +#include <nw/io.h> +#include <nw/ops.h> +#include <nw/routines.h> + +static enum nw_state get_relative_depth(struct nw_interp *const i) +{ + struct nw_i_sm_br *const b = &i->sm.br; + const struct nw_io_cfg *const cfg = &i->cfg.io; + const enum nw_state n = nwp_varuint32(cfg, &b->leb128, + &b->relative_depth, cfg->user); + + if (n) + return n; + + nwp_break(i, b->relative_depth); + return NW_AGAIN; +} + +void nwp_op_br(struct nw_interp *const i) +{ + static const struct nw_i_sm_br b = {0}; + + i->next = get_relative_depth; + i->sm.br = b; +} diff --git a/src/op/br_if.c b/src/op/br_if.c new file mode 100644 index 0000000..661c959 --- /dev/null +++ b/src/op/br_if.c @@ -0,0 +1,95 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2025 Xavier Del Campo Romero + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include <nanowasm/nw.h> +#include <nw/interp.h> +#include <nw/io.h> +#include <nw/log.h> +#include <nw/ops.h> +#include <nw/routines.h> +#include <nw/stack.h> +#include <nw/types.h> + +static int condition(struct nw_interp *const i) +{ + const struct nw_i_sm_br_if *const b = &i->sm.br_if; + + switch (i->push_type) + { + case NW_TYPE_I32: + return b->condition.i32; + + case NW_TYPE_I64: + return b->condition.i64.low; + + case NW_TYPE_F32: + return b->condition.f32; + + case NW_TYPE_F64: + return b->condition.f64; + } + + return 0; +} + +static enum nw_state pop(struct nw_interp *const i) +{ + struct nw_i_sm_br_if *const b = &i->sm.br_if; + const enum nw_state n = nwp_stack_pop(i, &b->io); + + if (n) + return n; + else if (condition(i)) + nwp_break(i, b->relative_depth); + else + nwp_interp_resume(i); + + return NW_AGAIN; +} + +static enum nw_state get_relative_depth(struct nw_interp *const i) +{ + struct nw_i_sm_br_if *const b = &i->sm.br_if; + const struct nw_io_cfg *const cfg = &i->cfg.io; + const enum nw_state n = nwp_varuint32(cfg, &b->leb128, + &b->relative_depth, cfg->user); + size_t sz; + + if (n) + return n; + else if (nwp_type_sz(i->push_type, &sz)) + { + static const char *const exc = "invalid type"; + + i->exception = exc; +#ifdef NW_LOG + nwp_log("%s: %#x\n", exc, (unsigned)i->push_type); +#endif + return NW_FATAL; + } + else + { + struct nw_sm_io io = {0}; + + io.buf = &b->condition; + io.n = sz; + b->io = io; + i->next = pop; + } + + return NW_AGAIN; +} + +void nwp_op_br_if(struct nw_interp *const i) +{ + static const struct nw_i_sm_br_if b = {0}; + + i->next = get_relative_depth; + i->sm.br_if = b; +} diff --git a/src/op/call.c b/src/op/call.c new file mode 100644 index 0000000..11a9183 --- /dev/null +++ b/src/op/call.c @@ -0,0 +1,50 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2025 Xavier Del Campo Romero + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include <nanowasm/nw.h> +#include <nw/interp.h> +#include <nw/io.h> +#include <nw/ops.h> +#include <nw/routines.h> +#include <nw/types.h> + +static enum nw_state get_pc(struct nw_interp *const i) +{ + struct nw_i_sm_call *const c = &i->sm.call; + const struct nw_io_cfg *const cfg = &i->cfg.io; + const enum nw_state n = cfg->tell(&i->fr.pc, cfg->user); + + if (n) + return n; + + nwp_call(i, c->index); + return NW_AGAIN; +} + +static enum nw_state get_index(struct nw_interp *const i) +{ + struct nw_i_sm_call *const c = &i->sm.call; + struct nw_sm_leb128 *const l = &c->leb128; + const struct nw_io_cfg *const cfg = &i->cfg.io; + const enum nw_state n = nwp_varuint32(cfg, l, &c->index, cfg->user); + + if (n) + return n; + + i->next = get_pc; + return NW_AGAIN; +} + +void nwp_op_call(struct nw_interp *const i) +{ + static const struct nw_i_sm_call c = {0}; + + i->sm.call = c; + i->next = get_index; +} diff --git a/src/op/call_indirect.c b/src/op/call_indirect.c new file mode 100644 index 0000000..f41a14d --- /dev/null +++ b/src/op/call_indirect.c @@ -0,0 +1,64 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2025 Xavier Del Campo Romero + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include <nanowasm/nw.h> +#include <nw/interp.h> +#include <nw/io.h> +#include <nw/ops.h> +#include <nw/routines.h> +#include <nw/types.h> + +static enum nw_state get_pc(struct nw_interp *const i) +{ + struct nw_i_sm_call *const c = &i->sm.call; + const struct nw_io_cfg *const cfg = &i->cfg.io; + const enum nw_state n = cfg->tell(&i->fr.pc, cfg->user); + + if (n) + return n; + + nwp_call(i, c->index); + return NW_AGAIN; +} + +static enum nw_state get_value(struct nw_interp *const i) +{ + struct nw_i_sm_call_indirect *const ci = &i->sm.call_indirect; + struct nw_sm_leb128 *const l = &ci->leb128; + const struct nw_io_cfg *const cfg = &i->cfg.io; + const enum nw_state n = nwp_varuint32(cfg, l, &ci->value, cfg->user); + + if (n) + return n; + + i->next = get_pc; + return NW_AGAIN; +} + +static enum nw_state get_index(struct nw_interp *const i) +{ + struct nw_i_sm_call_indirect *const ci = &i->sm.call_indirect; + struct nw_sm_leb128 *const l = &ci->leb128; + const struct nw_io_cfg *const cfg = &i->cfg.io; + const enum nw_state n = nwp_varuint32(cfg, l, &ci->index, cfg->user); + + if (n) + return n; + + i->next = get_value; + return NW_AGAIN; +} + +void nwp_op_call_indirect(struct nw_interp *const i) +{ + static const struct nw_i_sm_call_indirect ci = {0}; + + i->sm.call_indirect = ci; + i->next = get_index; +} diff --git a/src/op/check/CMakeLists.txt b/src/op/check/CMakeLists.txt new file mode 100644 index 0000000..0745eb5 --- /dev/null +++ b/src/op/check/CMakeLists.txt @@ -0,0 +1,24 @@ +# nanowasm, a tiny WebAssembly/Wasm interpreter +# Copyright (C) 2023-2025 Xavier Del Campo Romero +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at https://mozilla.org/MPL/2.0/. + +target_sources(${PROJECT_NAME} PRIVATE + block.c + br_table.c + call.c + end.c + global_index.c + i64_const.c + local_index.c + memory_immediate.c + misc.c + no_immediate.c + relative_depth.c + varint32.c + varuint1.c + uint32.c + uint64.c +) diff --git a/src/op/check/block.c b/src/op/check/block.c new file mode 100644 index 0000000..7d5176e --- /dev/null +++ b/src/op/check/block.c @@ -0,0 +1,43 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2025 Xavier Del Campo Romero + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include <nanowasm/nw.h> +#include <nw/io.h> +#include <nw/log.h> +#include <nw/ops.h> +#include <nw/types.h> + +static enum nw_state get_type(struct nw_mod *const m) +{ + nw_varint7 type; + const struct nw_io_cfg *const cfg = &m->cfg.io; + struct nw_sm_c *const c = &m->sm.code; + struct nw_sm_leb128 *const l = &c->leb128; + const enum nw_state n = nwp_varint7(cfg, l, &type, cfg->user); + enum nw_type t; + + if (n) + return n; + else if (nwp_get_type(type, &t) && type != 0x40) + { +#ifdef NW_LOG + nwp_log("invalid block_type %#x\n", (unsigned)type); +#endif + return NW_FATAL; + } + + c->fn.blocks++; + m->next = m->sm.code.next; + return NW_AGAIN; +} + +void nwp_op_check_block(struct nw_mod *const m) +{ + m->next = get_type; +} diff --git a/src/op/check/br_table.c b/src/op/check/br_table.c new file mode 100644 index 0000000..d104669 --- /dev/null +++ b/src/op/check/br_table.c @@ -0,0 +1,78 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2025 Xavier Del Campo Romero + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include <nanowasm/nw.h> +#include <nw/io.h> +#include <nw/ops.h> + +static enum nw_state loop(struct nw_mod *m); + +static enum nw_state get_default_target(struct nw_mod *const m) +{ + const struct nw_io_cfg *const cfg = &m->cfg.io; + struct nw_sm_c *const c = &m->sm.code; + struct nw_sm_leb128 *const l = &c->leb128; + nw_varuint32 target; + const enum nw_state n = nwp_varuint32(cfg, l, &target, cfg->user); + + if (n) + return n; + + m->next = c->next; + return NW_AGAIN; +} + +static enum nw_state get_entry(struct nw_mod *const m) +{ + const struct nw_io_cfg *const cfg = &m->cfg.io; + struct nw_sm_c *const c = &m->sm.code; + struct nw_sm_c_t *const t = &c->u.target; + struct nw_sm_leb128 *const l = &c->leb128; + nw_varuint32 entry; + const enum nw_state n = nwp_varuint32(cfg, l, &entry, cfg->user); + + if (n) + return n; + + t->i++; + m->next = loop; + return NW_AGAIN; +} + +static enum nw_state loop(struct nw_mod *const m) +{ + const struct nw_sm_c *const c = &m->sm.code; + const struct nw_sm_c_t *const t = &c->u.target; + + m->next = t->i >= t->count ? get_default_target : get_entry; + return NW_AGAIN; +} + +static enum nw_state get_target_count(struct nw_mod *const m) +{ + const struct nw_io_cfg *const cfg = &m->cfg.io; + struct nw_sm_c *const c = &m->sm.code; + struct nw_sm_leb128 *const l = &c->leb128; + struct nw_sm_c_t *const t = &c->u.target; + const enum nw_state n = nwp_varuint32(cfg, l, &t->count, cfg->user); + + if (n) + return n; + + m->next = loop; + return NW_AGAIN; +} + +void nwp_op_check_br_table(struct nw_mod *const m) +{ + static const struct nw_sm_c_t t = {0}; + + m->sm.code.u.target = t; + m->next = get_target_count; +} diff --git a/src/op/check/call.c b/src/op/check/call.c new file mode 100644 index 0000000..7b02032 --- /dev/null +++ b/src/op/check/call.c @@ -0,0 +1,40 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2025 Xavier Del Campo Romero + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include <nanowasm/nw.h> +#include <nw/io.h> +#include <nw/log.h> +#include <nw/ops.h> + +static enum nw_state get_index(struct nw_mod *const m) +{ + nw_varuint32 index; + const struct nw_io_cfg *const cfg = &m->cfg.io; + struct nw_sm_c *const c = &m->sm.code; + struct nw_sm_leb128 *const l = &c->leb128; + const enum nw_state n = nwp_varuint32(cfg, l, &index, cfg->user); + + if (n) + return n; + else if (index >= c->count + m->cfg.n_imports) + { +#ifdef NW_LOG + nwp_log("invalid function index %lu\n", (unsigned long)index); +#endif + return NW_FATAL; + } + + m->next = m->sm.code.next; + return NW_AGAIN; +} + +void nwp_op_check_call(struct nw_mod *const m) +{ + m->next = get_index; +} diff --git a/src/op/check/end.c b/src/op/check/end.c new file mode 100644 index 0000000..8ec6bf7 --- /dev/null +++ b/src/op/check/end.c @@ -0,0 +1,36 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2025 Xavier Del Campo Romero + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include <nanowasm/nw.h> +#include <nw/io.h> +#include <nw/log.h> +#include <nw/ops.h> + +static enum nw_state run(struct nw_mod *const m) +{ + struct nw_sm_c *const c = &m->sm.code; + struct nw_sm_c_fn *const fn = &c->fn; + + if (!fn->blocks) + { +#ifdef NW_LOG + nwp_log("unexpected end in function %lu\n", (unsigned long)c->entry_i); +#endif + return NW_FATAL; + } + + fn->blocks--; + m->next = c->next; + return NW_AGAIN; +} + +void nwp_op_check_end(struct nw_mod *const m) +{ + m->next = run; +} diff --git a/src/op/check/global_index.c b/src/op/check/global_index.c new file mode 100644 index 0000000..b3a18bb --- /dev/null +++ b/src/op/check/global_index.c @@ -0,0 +1,40 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2025 Xavier Del Campo Romero + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include <nanowasm/nw.h> +#include <nw/io.h> +#include <nw/log.h> +#include <nw/ops.h> + +static enum nw_state get_index(struct nw_mod *const m) +{ + nw_varuint32 index; + const struct nw_io_cfg *const cfg = &m->cfg.io; + struct nw_sm_c *const c = &m->sm.code; + struct nw_sm_leb128 *const l = &c->leb128; + const enum nw_state n = nwp_varuint32(cfg, l, &index, cfg->user); + + if (n) + return n; + else if (index >= m->global_count) + { +#ifdef NW_LOG + nwp_log("invalid global index %lu\n", (unsigned long)index); +#endif + return NW_FATAL; + } + + m->next = c->next; + return NW_AGAIN; +} + +void nwp_op_check_global_index(struct nw_mod *const m) +{ + m->next = get_index; +} diff --git a/src/op/check/i64_const.c b/src/op/check/i64_const.c new file mode 100644 index 0000000..e283642 --- /dev/null +++ b/src/op/check/i64_const.c @@ -0,0 +1,32 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2025 Xavier Del Campo Romero + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include <nanowasm/nw.h> +#include <nw/io.h> +#include <nw/ops.h> + +static enum nw_state get_value(struct nw_mod *const m) +{ + nw_varint64 value; + const struct nw_io_cfg *const cfg = &m->cfg.io; + struct nw_sm_c *const c = &m->sm.code; + struct nw_sm_leb128 *const l = &c->leb128; + const enum nw_state n = nwp_varint64(cfg, l, &value, cfg->user); + + if (n) + return n; + + m->next = c->next; + return NW_AGAIN; +} + +void nwp_op_check_varint64(struct nw_mod *const m) +{ + m->next = get_value; +} diff --git a/src/op/check/local_index.c b/src/op/check/local_index.c new file mode 100644 index 0000000..a6df9ad --- /dev/null +++ b/src/op/check/local_index.c @@ -0,0 +1,43 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2025 Xavier Del Campo Romero + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include <nanowasm/nw.h> +#include <nw/io.h> +#include <nw/log.h> +#include <nw/ops.h> + +static enum nw_state get_index(struct nw_mod *const m) +{ + nw_varuint32 index; + const struct nw_io_cfg *const cfg = &m->cfg.io; + struct nw_sm_c *const c = &m->sm.code; + struct nw_sm_leb128 *const l = &c->leb128; + const enum nw_state n = nwp_varuint32(cfg, l, &index, cfg->user); + + if (n) + return n; +#if 0 + else if (index >= c->fn.local_total) + { + LOG("%s: invalid local index %lu in function %lu\n", __func__, + (unsigned long)index, (unsigned long)c->entry_i); + return NW_FATAL; + } +#else + /* TODO: take function parameters into account for local_total*/ +#endif + + m->next = c->next; + return NW_AGAIN; +} + +void nwp_op_check_local_index(struct nw_mod *const m) +{ + m->next = get_index; +} diff --git a/src/op/check/memory_immediate.c b/src/op/check/memory_immediate.c new file mode 100644 index 0000000..98aae52 --- /dev/null +++ b/src/op/check/memory_immediate.c @@ -0,0 +1,47 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2025 Xavier Del Campo Romero + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include <nanowasm/nw.h> +#include <nw/io.h> +#include <nw/ops.h> + +static enum nw_state get_offset(struct nw_mod *const m) +{ + nw_varuint32 offset; + const struct nw_io_cfg *const cfg = &m->cfg.io; + struct nw_sm_c *const c = &m->sm.code; + struct nw_sm_leb128 *const l = &c->leb128; + const enum nw_state n = nwp_varuint32(cfg, l, &offset, cfg->user); + + if (n) + return n; + + m->next = m->sm.code.next; + return NW_AGAIN; +} + +static enum nw_state get_flags(struct nw_mod *const m) +{ + nw_varuint32 flags; + const struct nw_io_cfg *const cfg = &m->cfg.io; + struct nw_sm_c *const c = &m->sm.code; + struct nw_sm_leb128 *const l = &c->leb128; + const enum nw_state n = nwp_varuint32(cfg, l, &flags, cfg->user); + + if (n) + return n; + + m->next = get_offset; + return NW_AGAIN; +} + +void nwp_op_check_memory_immediate(struct nw_mod *const m) +{ + m->next = get_flags; +} diff --git a/src/op/check/misc.c b/src/op/check/misc.c new file mode 100644 index 0000000..fc89d21 --- /dev/null +++ b/src/op/check/misc.c @@ -0,0 +1,34 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2025 Xavier Del Campo Romero + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include <nanowasm/nw.h> +#include <nw/io.h> +#include <nw/ops.h> + +static enum nw_state run(struct nw_mod *const m) +{ + unsigned char op; + const struct nw_io_cfg *const cfg = &m->cfg.io; + struct nw_sm_io io = {0}; + enum nw_state n; + + io.buf = &op; + io.n = sizeof op; + + if ((n = nwp_io_read(cfg, &io, cfg->user))) + return n; + + m->next = m->sm.code.next; + return NW_AGAIN; +} + +void nwp_op_check_misc(struct nw_mod *const m) +{ + m->next = run; +} diff --git a/src/op/check/no_immediate.c b/src/op/check/no_immediate.c new file mode 100644 index 0000000..86cd22c --- /dev/null +++ b/src/op/check/no_immediate.c @@ -0,0 +1,23 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2025 Xavier Del Campo Romero + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include <nanowasm/nw.h> +#include <nw/io.h> +#include <nw/ops.h> + +static enum nw_state run(struct nw_mod *const m) +{ + m->next = m->sm.code.next; + return NW_AGAIN; +} + +void nwp_op_check_no_immediate(struct nw_mod *const m) +{ + m->next = run; +} diff --git a/src/op/check/relative_depth.c b/src/op/check/relative_depth.c new file mode 100644 index 0000000..41011b8 --- /dev/null +++ b/src/op/check/relative_depth.c @@ -0,0 +1,40 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2025 Xavier Del Campo Romero + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include <nanowasm/nw.h> +#include <nw/io.h> +#include <nw/log.h> +#include <nw/ops.h> + +static enum nw_state get_relative_depth(struct nw_mod *const m) +{ + nw_varuint32 relative_depth; + const struct nw_io_cfg *const cfg = &m->cfg.io; + struct nw_sm_c *const c = &m->sm.code; + struct nw_sm_leb128 *const l = &c->leb128; + const enum nw_state n = nwp_varuint32(cfg, l, &relative_depth, cfg->user); + + if (n) + return n; + else if (relative_depth >= c->fn.blocks) + { +#ifdef NW_LOG + nwp_log("invalid relative depth %lu\n", (unsigned long)relative_depth); +#endif + return NW_FATAL; + } + + m->next = c->next; + return NW_AGAIN; +} + +void nwp_op_check_relative_depth(struct nw_mod *const m) +{ + m->next = get_relative_depth; +} diff --git a/src/op/check/uint32.c b/src/op/check/uint32.c new file mode 100644 index 0000000..28aa852 --- /dev/null +++ b/src/op/check/uint32.c @@ -0,0 +1,36 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2025 Xavier Del Campo Romero + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include <nanowasm/nw.h> +#include <nw/io.h> +#include <nw/ops.h> + +static enum nw_state get_value(struct nw_mod *const m) +{ + const struct nw_io_cfg *const cfg = &m->cfg.io; + struct nw_sm_c *const c = &m->sm.code; + const enum nw_state n = nwp_io_read(cfg, &c->io, cfg->user); + + if (n) + return n; + + m->next = c->next; + return NW_AGAIN; +} + +void nwp_op_check_uint32(struct nw_mod *const m) +{ + struct nw_sm_c *const c = &m->sm.code; + struct nw_sm_io io = {0}; + + io.buf = &c->u; + io.n = sizeof (struct nw_leuint32); + c->io = io; + m->next = get_value; +} diff --git a/src/op/check/uint64.c b/src/op/check/uint64.c new file mode 100644 index 0000000..a925999 --- /dev/null +++ b/src/op/check/uint64.c @@ -0,0 +1,36 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2025 Xavier Del Campo Romero + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include <nanowasm/nw.h> +#include <nw/io.h> +#include <nw/ops.h> + +static enum nw_state get_value(struct nw_mod *const m) +{ + const struct nw_io_cfg *const cfg = &m->cfg.io; + struct nw_sm_c *const c = &m->sm.code; + const enum nw_state n = nwp_io_read(cfg, &c->io, cfg->user); + + if (n) + return n; + + m->next = c->next; + return NW_AGAIN; +} + +void nwp_op_check_uint64(struct nw_mod *const m) +{ + struct nw_sm_c *const c = &m->sm.code; + struct nw_sm_io io = {0}; + + io.buf = &c->u; + io.n = sizeof (struct nw_leuint64); + c->io = io; + m->next = get_value; +} diff --git a/src/op/check/varint32.c b/src/op/check/varint32.c new file mode 100644 index 0000000..aff3904 --- /dev/null +++ b/src/op/check/varint32.c @@ -0,0 +1,32 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2025 Xavier Del Campo Romero + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include <nanowasm/nw.h> +#include <nw/io.h> +#include <nw/ops.h> + +static enum nw_state get_value(struct nw_mod *const m) +{ + nw_varint32 value; + const struct nw_io_cfg *const cfg = &m->cfg.io; + struct nw_sm_c *const c = &m->sm.code; + struct nw_sm_leb128 *const l = &c->leb128; + const enum nw_state n = nwp_varint32(cfg, l, &value, cfg->user); + + if (n) + return n; + + m->next = c->next; + return NW_AGAIN; +} + +void nwp_op_check_varint32(struct nw_mod *const m) +{ + m->next = get_value; +} diff --git a/src/op/check/varuint1.c b/src/op/check/varuint1.c new file mode 100644 index 0000000..87ef6c4 --- /dev/null +++ b/src/op/check/varuint1.c @@ -0,0 +1,32 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2025 Xavier Del Campo Romero + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include <nanowasm/nw.h> +#include <nw/io.h> +#include <nw/ops.h> + +static enum nw_state get_value(struct nw_mod *const m) +{ + nw_varuint1 value; + const struct nw_io_cfg *const cfg = &m->cfg.io; + struct nw_sm_c *const c = &m->sm.code; + struct nw_sm_leb128 *const l = &c->leb128; + const enum nw_state n = nwp_varuint1(cfg, l, &value, cfg->user); + + if (n) + return n; + + m->next = c->next; + return NW_AGAIN; +} + +void nwp_op_check_varuint1(struct nw_mod *const m) +{ + m->next = get_value; +} diff --git a/src/op/drop.c b/src/op/drop.c new file mode 100644 index 0000000..3b5dffd --- /dev/null +++ b/src/op/drop.c @@ -0,0 +1,101 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2025 Xavier Del Campo Romero + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include <nw/interp.h> +#include <nw/io.h> +#include <nw/log.h> +#include <nw/opcodes.h> +#include <nw/ops.h> +#include <nw/stack.h> +#include <nw/types.h> + +static enum nw_state pop(struct nw_interp *const i) +{ + struct nw_i_sm_drop *const d = &i->sm.drop; + const enum nw_state n = nwp_stack_pop(i, &d->io); + + if (n) + return n; + + nwp_interp_resume(i); + return NW_AGAIN; +} + +static enum nw_state check(struct nw_interp *const i) +{ + struct nw_i_sm_drop *const d = &i->sm.drop; + const struct nw_frame *const fr = &i->fr; + const struct nw_return *const r = &fr->prev_ret; + const unsigned char prev = fr->prev_op; + size_t sz; + + if (prev != OP_CALL && prev != OP_CALL_INDIRECT) + { + static const char *const exc = + "expected call or call_indirect before drop"; + + i->exception = exc; +#ifdef NW_LOG + nwp_log("%s, got: %#x\n", exc, (unsigned)prev); +#endif + return NW_FATAL; + } + else if (!r->count) + { + static const char *const exc = + "called drop from function without return value"; + + i->exception = exc; +#ifdef NW_LOG + nwp_log("%s\n", exc); +#endif + return NW_FATAL; + } + else if (r->type != i->push_type) + { + static const char *const exc = + "mismatch between return type and last push type"; + + i->exception = exc; +#ifdef NW_LOG + nwp_log("%s, expected: %#hhx, got: %#hhx\n", exc, + (unsigned char)i->push_type, (unsigned char)r->type); +#endif + return NW_FATAL; + } + else if (nwp_type_sz(r->type, &sz)) + { + static const char *const exc = "invalid return type"; + + i->exception = exc; +#ifdef NW_LOG + nwp_log("%s: %#x\n", exc, (unsigned)r->type); +#endif + return NW_FATAL; + } + else + { + struct nw_sm_io io = {0}; + + io.buf = &d->value; + io.n = sz; + d->io = io; + i->next = pop; + } + + return NW_AGAIN; +} + +void nwp_op_drop(struct nw_interp *const i) +{ + const struct nw_i_sm_drop d = {{0}}; + + i->sm.drop = d; + i->next = check; +} diff --git a/src/op/end.c b/src/op/end.c new file mode 100644 index 0000000..9eb575d --- /dev/null +++ b/src/op/end.c @@ -0,0 +1,67 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2025 Xavier Del Campo Romero + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include <nanowasm/nw.h> +#include <nw/interp.h> +#include <nw/log.h> +#include <nw/ops.h> +#include <nw/routines.h> + +static enum nw_state run(struct nw_interp *const i) +{ + const struct nw_i_sm_end *const e = &i->sm.end; + struct nw_frame *const f = &i->fr; + + if (i->set) + return NW_OK; + else if (f->block_i) + { + f->block_i--; + nwp_interp_resume(i); + } + else + { + const long expected = f->start + f->body_size; + + if (e->offset != expected) + { + static const char *const exc = "unexpected end"; + +#ifdef NW_LOG + nwp_log("%s\n", exc); +#endif + i->exception = exc; + return NW_FATAL; + } + else if (f->child) + nwp_unwind(i); + } + + return NW_AGAIN; +} + +static enum nw_state get_offset(struct nw_interp *const i) +{ + struct nw_i_sm_end *const e = &i->sm.end; + const struct nw_io_cfg *const cfg = &i->cfg.io; + const enum nw_state n = cfg->tell(&e->offset, cfg->user); + + if (n) + return n; + + return run(i); +} + +void nwp_op_end(struct nw_interp *const i) +{ + static const struct nw_i_sm_end e = {0}; + + i->sm.end = e; + i->next = get_offset; +} diff --git a/src/op/get_global.c b/src/op/get_global.c new file mode 100644 index 0000000..eb701b5 --- /dev/null +++ b/src/op/get_global.c @@ -0,0 +1,93 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2025 Xavier Del Campo Romero + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include <nanowasm/nw.h> +#include <nw/global.h> +#include <nw/io.h> +#include <nw/interp.h> +#include <nw/stack.h> +#include <nw/log.h> +#include <nw/ops.h> +#include <nw/routines.h> + +static enum nw_state push(struct nw_interp *const i) +{ + struct nw_i_sm_get_global *const g = &i->sm.get_global; + const enum nw_state n = nwp_stack_push(i, &g->io); + + if (n) + return n; + + nwp_interp_resume(i); + return NW_AGAIN; +} + +static enum nw_state read_global(struct nw_interp *const i) +{ + struct nw_i_sm_get_global *const g = &i->sm.get_global; + struct nw_sm_io *const io = &g->io; + struct nw_global *const gl = &g->gl; + const enum nw_state n = nwp_global_load(i, io, g->index); + size_t sz; + + if (n) + return n; + else if (nwp_type_sz(gl->type, &sz)) + { + static const char *const exc = "invalid global type"; + + i->exception = exc; +#ifdef NW_LOG + nwp_log("%s: %#x\n", exc, (unsigned)gl->type); +#endif + return NW_FATAL; + } + else + { + struct nw_sm_io io = {0}; + + io.buf = &gl->value; + io.n = sz; + g->io = io; + i->next = push; + i->push_type = gl->type; + } + + return NW_AGAIN; +} + +static enum nw_state get_index(struct nw_interp *const i) +{ + struct nw_i_sm_get_global *const g = &i->sm.get_global; + struct nw_sm_leb128 *const l = &g->leb128; + const struct nw_io_cfg *const cfg = &i->cfg.io; + const enum nw_state n = nwp_varuint32(cfg, l, &g->index, cfg->user); + + if (n) + return n; + else + { + struct nw_sm_io io = {0}; + + io.buf = &g->gl; + io.n = sizeof g->gl; + g->io = io; + i->next = read_global; + } + + return NW_AGAIN; +} + +void nwp_op_get_global(struct nw_interp *const i) +{ + static const struct nw_i_sm_get_global g = {0}; + + i->sm.get_global = g; + i->next = get_index; +} diff --git a/src/op/get_local.c b/src/op/get_local.c new file mode 100644 index 0000000..6a9a42a --- /dev/null +++ b/src/op/get_local.c @@ -0,0 +1,150 @@ + +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2025 Xavier Del Campo Romero + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include <nanowasm/nw.h> +#include <nw/interp.h> +#include <nw/io.h> +#include <nw/log.h> +#include <nw/ops.h> +#include <nw/routines.h> +#include <nw/stack.h> +#include <nw/types.h> + +static int init_io(struct nw_interp *const i, const enum nw_type t) +{ + struct nw_i_sm_get_local *const gl = &i->sm.get_local; + size_t sz; + + if (nwp_type_sz(t, &sz)) + { + static const char *const exc = "invalid type"; + + i->exception = exc; +#ifdef NW_LOG + nwp_log("%s: %#x\n", exc, (unsigned)t); +#endif + return -1; + } + else + { + struct nw_sm_io io = {0}; + + io.buf = &gl->value; + io.n = sz; + gl->io = io; + } + + return 0; +} + +static enum nw_state push(struct nw_interp *const i) +{ + struct nw_i_sm_get_local *const gl = &i->sm.get_local; + const enum nw_state n = nwp_stack_push(i, &gl->io); + + if (n) + return n; + + nwp_interp_resume(i); + return NW_AGAIN; +} + +static enum nw_state get_local(struct nw_interp *const i) +{ + struct nw_i_sm_get_local *const gl = &i->sm.get_local; + const struct nw_local_meta *const m = &gl->f.l.meta; + const enum nw_state n = nwp_stack_read(i, &gl->io, gl->f.l.addr); + + if (n) + return n; + else if (init_io(i, m->type)) + return NW_FATAL; + + i->next = push; + i->push_type = m->type; + return NW_AGAIN; +} + +static enum nw_state prepare_local(struct nw_interp *const i) +{ + const struct nw_local_meta *const m = &i->sm.get_local.f.l.meta; + + if (init_io(i, m->type)) + return NW_FATAL; + + i->next = get_local; + return NW_AGAIN; +} + +static enum nw_state get_param(struct nw_interp *const i) +{ + struct nw_i_sm_get_local *const gl = &i->sm.get_local; + const struct nw_find_param_out *const o = &gl->f.p.out; + const enum nw_state n = nwp_stack_read(i, &gl->io, o->addr); + + if (n) + return n; + else if (init_io(i, o->type)) + return NW_FATAL; + + i->next = push; + i->push_type = o->type; + return NW_AGAIN; +} + +static enum nw_state prepare_param(struct nw_interp *const i) +{ + struct nw_i_sm_get_local *const gl = &i->sm.get_local; + const struct nw_find_param_out *const o = &gl->f.p.out; + + if (init_io(i, o->type)) + return NW_FATAL; + + i->next = get_param; + return NW_AGAIN; +} + +static enum nw_state get_index(struct nw_interp *const i) +{ + struct nw_i_sm_get_local *const gl = &i->sm.get_local; + struct nw_sm_leb128 *const l = &gl->leb128; + const struct nw_io_cfg *const cfg = &i->cfg.io; + const struct nw_frame *const fr = &i->fr; + const struct nw_fn *const fn = &fr->fn; + const enum nw_state n = nwp_varuint32(cfg, l, &gl->index, cfg->user); + nw_varuint32 index; + + if (n) + return n; + else if (gl->index < fn->param_count) + nwp_find_param(i, &gl->f.p, gl->index, prepare_param, NULL); + else if ((index = gl->index - fn->param_count) >= fr->local_count) + { + static const char *const exc = "invalid local index"; + + i->exception = exc; +#ifdef NW_LOG + nwp_log("%s: %lu\n", exc, (unsigned long)gl->index); +#endif + return NW_FATAL; + } + else + nwp_find_local(i, &gl->f.l, index, prepare_local, NULL); + + return NW_AGAIN; +} + +void nwp_op_get_local(struct nw_interp *const i) +{ + static const struct nw_i_sm_get_local gl = {0}; + + i->sm.get_local = gl; + i->next = get_index; +} diff --git a/src/op/i32_add.c b/src/op/i32_add.c new file mode 100644 index 0000000..fe2ec69 --- /dev/null +++ b/src/op/i32_add.c @@ -0,0 +1,23 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2025 Xavier Del Campo Romero + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include <nanowasm/nw.h> +#include <nw/routines.h> + +static int add(const struct nw_i_sm_arithm_out *const o, + union nw_value *const res) +{ + res->i32 = (unsigned long)o->left.i32 + (unsigned long)o->right.i32; + return 0; +} + +void nwp_op_i32_add(struct nw_interp *const i) +{ + nwp_arithm(i, NW_TYPE_I32, add); +} diff --git a/src/op/i32_and.c b/src/op/i32_and.c new file mode 100644 index 0000000..d52bead --- /dev/null +++ b/src/op/i32_and.c @@ -0,0 +1,23 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2025 Xavier Del Campo Romero + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include <nanowasm/nw.h> +#include <nw/routines.h> + +static int and(const struct nw_i_sm_arithm_out *const o, + union nw_value *const res) +{ + res->i32 = o->left.i32 & o->right.i32; + return 0; +} + +void nwp_op_i32_and(struct nw_interp *const i) +{ + nwp_arithm(i, NW_TYPE_I32, and); +} diff --git a/src/op/i32_const.c b/src/op/i32_const.c new file mode 100644 index 0000000..80dc9dd --- /dev/null +++ b/src/op/i32_const.c @@ -0,0 +1,58 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2025 Xavier Del Campo Romero + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include <nanowasm/nw.h> +#include <nw/io.h> +#include <nw/interp.h> +#include <nw/log.h> +#include <nw/ops.h> +#include <nw/stack.h> + +static enum nw_state push(struct nw_interp *const i) +{ + struct nw_i_sm_i32_const *const c = &i->sm.i32_const; + const enum nw_state n = nwp_stack_push(i, &c->io); + + if (n) + return n; + + i->push_type = NW_TYPE_I32; + nwp_interp_resume(i); + return NW_AGAIN; +} + +static enum nw_state get_value(struct nw_interp *const i) +{ + const struct nw_io_cfg *const cfg = &i->cfg.io; + struct nw_i_sm_i32_const *const c = &i->sm.i32_const; + struct nw_sm_leb128 *const l = &c->leb128; + const enum nw_state n = nwp_varint32(cfg, l, &c->value, cfg->user); + + if (n) + return n; + else + { + struct nw_sm_io io = {0}; + + io.buf = &c->value; + io.n = sizeof c->value; + c->io = io; + i->next = push; + } + + return NW_AGAIN; +} + +void nwp_op_i32_const(struct nw_interp *const i) +{ + static const struct nw_i_sm_i32_const c = {0}; + + i->next = get_value; + i->sm.i32_const = c; +} diff --git a/src/op/i32_eq.c b/src/op/i32_eq.c new file mode 100644 index 0000000..3f2cc42 --- /dev/null +++ b/src/op/i32_eq.c @@ -0,0 +1,23 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2025 Xavier Del Campo Romero + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include <nanowasm/nw.h> +#include <nw/routines.h> + +static int eq(const struct nw_i_sm_arithm_out *const o, + union nw_value *const res) +{ + res->i32 = o->left.i32 == o->right.i32; + return 0; +} + +void nwp_op_i32_eq(struct nw_interp *const i) +{ + nwp_arithm(i, NW_TYPE_I32, eq); +} diff --git a/src/op/i32_eqz.c b/src/op/i32_eqz.c new file mode 100644 index 0000000..cd533fd --- /dev/null +++ b/src/op/i32_eqz.c @@ -0,0 +1,22 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2025 Xavier Del Campo Romero + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include <nanowasm/nw.h> +#include <nw/routines.h> + +static int eqz(const union nw_value *const in, union nw_value *const out) +{ + out->i32 = !in->i32; + return 0; +} + +void nwp_op_i32_eqz(struct nw_interp *const i) +{ + nwp_unary(i, NW_TYPE_I32, eqz); +} diff --git a/src/op/i32_ge_s.c b/src/op/i32_ge_s.c new file mode 100644 index 0000000..137b80d --- /dev/null +++ b/src/op/i32_ge_s.c @@ -0,0 +1,23 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2025 Xavier Del Campo Romero + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include <nanowasm/nw.h> +#include <nw/routines.h> + +static int ge_s(const struct nw_i_sm_arithm_out *const o, + union nw_value *const res) +{ + res->i32 = o->left.i32 >= o->right.i32; + return 0; +} + +void nwp_op_i32_ge_s(struct nw_interp *const i) +{ + nwp_arithm(i, NW_TYPE_I32, ge_s); +} diff --git a/src/op/i32_ge_u.c b/src/op/i32_ge_u.c new file mode 100644 index 0000000..c280dec --- /dev/null +++ b/src/op/i32_ge_u.c @@ -0,0 +1,23 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2025 Xavier Del Campo Romero + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include <nanowasm/nw.h> +#include <nw/routines.h> + +static int ge_u(const struct nw_i_sm_arithm_out *const o, + union nw_value *const res) +{ + res->i32 = (unsigned long)o->left.i32 >= (unsigned long)o->right.i32; + return 0; +} + +void nwp_op_i32_ge_u(struct nw_interp *const i) +{ + nwp_arithm(i, NW_TYPE_I32, ge_u); +} diff --git a/src/op/i32_load.c b/src/op/i32_load.c new file mode 100644 index 0000000..e2d883b --- /dev/null +++ b/src/op/i32_load.c @@ -0,0 +1,89 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2025 Xavier Del Campo Romero + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include <nanowasm/nw.h> +#include <nw/io.h> +#include <nw/interp.h> +#include <nw/linear.h> +#include <nw/stack.h> +#include <nw/log.h> +#include <nw/ops.h> +#include <nw/routines.h> + +static enum nw_state push(struct nw_interp *const i) +{ + struct nw_i_sm_load *const l = &i->sm.load; + const enum nw_state n = nwp_stack_push(i, &l->io); + + if (n) + return n; + + i->push_type = NW_TYPE_I32; + nwp_interp_resume(i); + return NW_AGAIN; +} + +static enum nw_state load(struct nw_interp *const i) +{ + struct nw_i_sm_load *const l = &i->sm.load; + const enum nw_state n = nwp_linear_load(i, &l->io, l->addr + l->imm.offset); + + if (n) + return n; + else + { + struct nw_sm_io io = {0}; + + l->value.i32 = nwp_leuint32(&l->value.v32); + io.buf = &l->value.i32; + io.n = sizeof l->value.i32; + l->io = io; + i->next = push; + } + + i->next = push; + return NW_AGAIN; +} + +static enum nw_state pop_addr(struct nw_interp *const i) +{ + struct nw_i_sm_load *const l = &i->sm.load; + const enum nw_state n = nwp_stack_pop(i, &l->io); + + if (n) + return n; + else + { + struct nw_sm_io io = {0}; + + io.buf = &l->value.i32; + io.n = sizeof l->value.i32; + l->io = io; + i->next = load; + } + + return NW_AGAIN; +} + +static void prepare(struct nw_interp *const i) +{ + struct nw_i_sm_imm_out imm = i->sm.imm.out; + struct nw_i_sm_load *const pl = &i->sm.load, l = {0}; + + l.imm = imm; + l.io.buf = &pl->addr; + l.io.n = sizeof pl->addr; + *pl = l; + i->next = pop_addr; +} + +void nwp_op_i32_load(struct nw_interp *const i) +{ + nwp_mem_imm(i, prepare); +} diff --git a/src/op/i32_load8_u.c b/src/op/i32_load8_u.c new file mode 100644 index 0000000..da4282b --- /dev/null +++ b/src/op/i32_load8_u.c @@ -0,0 +1,89 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2025 Xavier Del Campo Romero + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include <nanowasm/nw.h> +#include <nw/linear.h> +#include <nw/io.h> +#include <nw/interp.h> +#include <nw/stack.h> +#include <nw/log.h> +#include <nw/ops.h> +#include <nw/routines.h> + +static enum nw_state push(struct nw_interp *const i) +{ + struct nw_i_sm_load *const l = &i->sm.load; + const enum nw_state n = nwp_stack_push(i, &l->io); + + if (n) + return n; + + i->push_type = NW_TYPE_I32; + nwp_interp_resume(i); + return NW_AGAIN; +} + +static enum nw_state load(struct nw_interp *const i) +{ + struct nw_i_sm_load *const l = &i->sm.load; + const enum nw_state n = nwp_linear_load(i, &l->io, l->addr + l->imm.offset); + + if (n) + return n; + else + { + const unsigned char b = l->value.i8; + struct nw_sm_io io = {0}; + + io.buf = &l->value.i32; + io.n = sizeof l->value.i32; + l->value.i32 = b; + l->io = io; + i->next = push; + } + + return NW_AGAIN; +} + +static enum nw_state pop_addr(struct nw_interp *const i) +{ + struct nw_i_sm_load *const l = &i->sm.load; + const enum nw_state n = nwp_stack_pop(i, &l->io); + + if (n) + return n; + else + { + struct nw_sm_io io = {0}; + + io.buf = &l->value.i8; + io.n = sizeof l->value.i8; + l->io = io; + i->next = load; + } + + return NW_AGAIN; +} + +static void prepare(struct nw_interp *const i) +{ + struct nw_i_sm_imm_out imm = i->sm.imm.out; + struct nw_i_sm_load *const pl = &i->sm.load, l = {0}; + + l.imm = imm; + l.io.buf = &pl->addr; + l.io.n = sizeof pl->addr; + *pl = l; + i->next = pop_addr; +} + +void nwp_op_i32_load8_u(struct nw_interp *const i) +{ + nwp_mem_imm(i, prepare); +} diff --git a/src/op/i32_lt_s.c b/src/op/i32_lt_s.c new file mode 100644 index 0000000..3e583c3 --- /dev/null +++ b/src/op/i32_lt_s.c @@ -0,0 +1,23 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2025 Xavier Del Campo Romero + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include <nanowasm/nw.h> +#include <nw/routines.h> + +static int lt_s(const struct nw_i_sm_arithm_out *const o, + union nw_value *const res) +{ + res->i32 = o->left.i32 < o->right.i32; + return 0; +} + +void nwp_op_i32_lt_s(struct nw_interp *const i) +{ + nwp_arithm(i, NW_TYPE_I32, lt_s); +} diff --git a/src/op/i32_mul.c b/src/op/i32_mul.c new file mode 100644 index 0000000..8af64de --- /dev/null +++ b/src/op/i32_mul.c @@ -0,0 +1,23 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2025 Xavier Del Campo Romero + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include <nanowasm/nw.h> +#include <nw/routines.h> + +static int mul(const struct nw_i_sm_arithm_out *const o, + union nw_value *const res) +{ + res->i32 = (unsigned long)o->left.i32 * (unsigned long)o->right.i32; + return 0; +} + +void nwp_op_i32_mul(struct nw_interp *const i) +{ + nwp_arithm(i, NW_TYPE_I32, mul); +} diff --git a/src/op/i32_ne.c b/src/op/i32_ne.c new file mode 100644 index 0000000..c62a2a7 --- /dev/null +++ b/src/op/i32_ne.c @@ -0,0 +1,23 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2025 Xavier Del Campo Romero + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include <nanowasm/nw.h> +#include <nw/routines.h> + +static int ne(const struct nw_i_sm_arithm_out *const o, + union nw_value *const res) +{ + res->i32 = o->left.i32 != o->right.i32; + return 0; +} + +void nwp_op_i32_ne(struct nw_interp *const i) +{ + nwp_arithm(i, NW_TYPE_I32, ne); +} diff --git a/src/op/i32_or.c b/src/op/i32_or.c new file mode 100644 index 0000000..774dbed --- /dev/null +++ b/src/op/i32_or.c @@ -0,0 +1,23 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2025 Xavier Del Campo Romero + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include <nanowasm/nw.h> +#include <nw/routines.h> + +static int or(const struct nw_i_sm_arithm_out *const o, + union nw_value *const res) +{ + res->i32 = o->left.i32 | o->right.i32; + return 0; +} + +void nwp_op_i32_or(struct nw_interp *const i) +{ + nwp_arithm(i, NW_TYPE_I32, or); +} diff --git a/src/op/i32_store.c b/src/op/i32_store.c new file mode 100644 index 0000000..caff6b9 --- /dev/null +++ b/src/op/i32_store.c @@ -0,0 +1,90 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2025 Xavier Del Campo Romero + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include <nanowasm/nw.h> +#include <nw/linear.h> +#include <nw/io.h> +#include <nw/interp.h> +#include <nw/stack.h> +#include <nw/log.h> +#include <nw/ops.h> +#include <nw/routines.h> + +static enum nw_state store(struct nw_interp *const i) +{ + struct nw_i_sm_store *const s = &i->sm.store; + const enum nw_state n = nwp_linear_store(i, &s->io, s->addr + s->imm.offset); + + if (n) + return n; + + nwp_interp_resume(i); + return NW_AGAIN; +} + +static enum nw_state pop_addr(struct nw_interp *const i) +{ + struct nw_i_sm_store *const s = &i->sm.store; + const enum nw_state n = nwp_stack_pop(i, &s->io); + + if (n) + return n; + else + { + struct nw_sm_io io = {0}; + + io.buf = &s->value.i32; + io.n = sizeof s->value.i32; + s->io = io; + i->next = store; + } + + return NW_AGAIN; +} + +static enum nw_state pop_value(struct nw_interp *const i) +{ + struct nw_i_sm_store *const s = &i->sm.store; + const enum nw_state n = nwp_stack_pop(i, &s->io); + + if (n) + return n; + else + { + const struct nw_sm_io io = {0}; + + s->value.i32 = nwp_leuint32(&s->value.v32); + s->io = io; + s->io.buf = &s->addr; + s->io.n = sizeof s->addr; + i->next = pop_addr; + } + + return NW_AGAIN; +} + +static void prepare(struct nw_interp *const i) +{ + const struct nw_i_sm_store s = {0}; + struct nw_i_sm_store *const ps = &i->sm.store; + struct nw_sm_io *const io = &ps->io; + struct nw_i_sm_imm_out out; + + out = i->sm.imm.out; + *ps = s; + ps->imm = out; + io->buf = &ps->value.i32; + io->n = sizeof ps->value.i32; + i->next = pop_value; +} + +void nwp_op_i32_store(struct nw_interp *const i) +{ + nwp_mem_imm(i, prepare); +} diff --git a/src/op/i32_sub.c b/src/op/i32_sub.c new file mode 100644 index 0000000..46c4f66 --- /dev/null +++ b/src/op/i32_sub.c @@ -0,0 +1,23 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2025 Xavier Del Campo Romero + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include <nanowasm/nw.h> +#include <nw/routines.h> + +static int sub(const struct nw_i_sm_arithm_out *const o, + union nw_value *const res) +{ + res->i32 = (unsigned long)o->left.i32 - (unsigned long)o->right.i32; + return 0; +} + +void nwp_op_i32_sub(struct nw_interp *const i) +{ + nwp_arithm(i, NW_TYPE_I32, sub); +} diff --git a/src/op/i64_const.c b/src/op/i64_const.c new file mode 100644 index 0000000..20d539b --- /dev/null +++ b/src/op/i64_const.c @@ -0,0 +1,58 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2025 Xavier Del Campo Romero + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include <nanowasm/nw.h> +#include <nw/io.h> +#include <nw/interp.h> +#include <nw/log.h> +#include <nw/ops.h> +#include <nw/stack.h> + +static enum nw_state push(struct nw_interp *const i) +{ + struct nw_i_sm_i64_const *const c = &i->sm.i64_const; + const enum nw_state n = nwp_stack_push(i, &c->io); + + if (n) + return n; + + i->push_type = NW_TYPE_I64; + nwp_interp_resume(i); + return NW_AGAIN; +} + +static enum nw_state get_value(struct nw_interp *const i) +{ + const struct nw_io_cfg *const cfg = &i->cfg.io; + struct nw_i_sm_i64_const *const c = &i->sm.i64_const; + struct nw_sm_leb128 *const l = &c->leb128; + const enum nw_state n = nwp_varuint64(cfg, l, &c->value, cfg->user); + + if (n) + return n; + else + { + struct nw_sm_io io = {0}; + + io.buf = &c->value; + io.n = sizeof c->value; + c->io = io; + i->next = push; + } + + return NW_AGAIN; +} + +void nwp_op_i64_const(struct nw_interp *const i) +{ + const struct nw_i_sm_i64_const c = {{0}}; + + i->next = get_value; + i->sm.i64_const = c; +} diff --git a/src/op/i64_store.c b/src/op/i64_store.c new file mode 100644 index 0000000..fbae8b4 --- /dev/null +++ b/src/op/i64_store.c @@ -0,0 +1,87 @@ +/* +* nanowasm, a tiny WebAssembly/Wasm interpreter +* Copyright (C) 2023-2025 Xavier Del Campo Romero +* +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, You can obtain one at https://mozilla.org/MPL/2.0/. +*/ + +#include <nanowasm/nw.h> +#include <nw/linear.h> +#include <nw/io.h> +#include <nw/interp.h> +#include <nw/stack.h> +#include <nw/log.h> +#include <nw/ops.h> +#include <nw/routines.h> + +static enum nw_state store(struct nw_interp *const i) +{ + struct nw_i_sm_store *const s = &i->sm.store; + const enum nw_state n = nwp_linear_store(i, &s->io, + s->addr + s->imm.offset); + + if (n) + return n; + + nwp_interp_resume(i); + return NW_AGAIN; +} + +static enum nw_state pop_addr(struct nw_interp *const i) +{ + struct nw_i_sm_store *const s = &i->sm.store; + const enum nw_state n = nwp_stack_pop(i, &s->io); + + if (n) + return n; + else + { + struct nw_sm_io io = {0}; + + io.buf = &s->value.i64; + io.n = sizeof s->value.i64; + s->io = io; + i->next = store; + } + + return NW_AGAIN; +} + +static enum nw_state pop_value(struct nw_interp *const i) +{ + struct nw_i_sm_store *const s = &i->sm.store; + const enum nw_state n = nwp_stack_pop(i, &s->io); + + if (n) + return n; + else + { + struct nw_sm_io io = {0}; + + nwp_leuint64(&s->value.v64, &s->value.i64); + io.buf = &s->addr; + io.n = sizeof s->addr; + s->io = io; + i->next = pop_addr; + } + + return NW_AGAIN; +} + +static void prepare(struct nw_interp *const i) +{ + struct nw_i_sm_store *const ps = &i->sm.store, s = {0}; + + s.imm = i->sm.imm.out; + s.io.buf = &ps->value.v64; + s.io.n = sizeof ps->value.v64; + *ps =s; + i->next = pop_value; +} + +void nwp_op_i64_store(struct nw_interp *const i) +{ + nwp_mem_imm(i, prepare); +} diff --git a/src/op/loop.c b/src/op/loop.c new file mode 100644 index 0000000..e129610 --- /dev/null +++ b/src/op/loop.c @@ -0,0 +1,16 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2025 Xavier Del Campo Romero + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include <nanowasm/nw.h> +#include <nw/routines.h> + +void nwp_op_loop(struct nw_interp *const i) +{ + nwp_start_block(i); +} diff --git a/src/op/nop.c b/src/op/nop.c new file mode 100644 index 0000000..b6ef7c2 --- /dev/null +++ b/src/op/nop.c @@ -0,0 +1,17 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2025 Xavier Del Campo Romero + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include <nanowasm/nw.h> +#include <nw/interp.h> +#include <nw/ops.h> + +void nwp_op_nop(struct nw_interp *const i) +{ + nwp_interp_resume(i); +} diff --git a/src/op/return.c b/src/op/return.c new file mode 100644 index 0000000..0b2a129 --- /dev/null +++ b/src/op/return.c @@ -0,0 +1,19 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2025 Xavier Del Campo Romero + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include <nanowasm/nw.h> +#include <nw/interp.h> +#include <nw/log.h> +#include <nw/ops.h> +#include <nw/routines.h> + +void nwp_op_return(struct nw_interp *const i) +{ + nwp_unwind(i); +} diff --git a/src/op/set_global.c b/src/op/set_global.c new file mode 100644 index 0000000..9448c32 --- /dev/null +++ b/src/op/set_global.c @@ -0,0 +1,122 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2025 Xavier Del Campo Romero + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include <nanowasm/nw.h> +#include <nw/global.h> +#include <nw/io.h> +#include <nw/interp.h> +#include <nw/stack.h> +#include <nw/log.h> +#include <nw/ops.h> +#include <nw/routines.h> + +static enum nw_state set_global(struct nw_interp *const i) +{ + struct nw_i_sm_get_global *const g = &i->sm.get_global; + const enum nw_state n = nwp_global_store(i, &g->io, g->index); + + if (n) + return n; + + nwp_interp_resume(i); + return NW_AGAIN; +} + +static enum nw_state pop(struct nw_interp *const i) +{ + struct nw_i_sm_get_global *const g = &i->sm.get_global; + const enum nw_state n = nwp_stack_pop(i, &g->io); + + if (n) + return n; + else + { + struct nw_sm_io io = {0}; + + io.buf = &g->gl; + io.n = sizeof g->gl; + g->io = io; + i->next = set_global; + } + + return NW_AGAIN; +} + +static enum nw_state read_global(struct nw_interp *const i) +{ + struct nw_i_sm_get_global *const g = &i->sm.get_global; + struct nw_global *const gl = &g->gl; + const enum nw_state n = nwp_global_load(i, &g->io, g->index); + size_t sz; + + if (n) + return n; + else if (!gl->mutability) + { + static const char *const exc = "cannot set non-mutable global"; + + i->exception = exc; +#ifdef NW_LOG + nwp_log("%s, index: %lu\n", exc, (unsigned long)g->index); +#endif + return NW_FATAL; + } + else if (nwp_type_sz(gl->type, &sz)) + { + static const char *const exc = "invalid global type"; + + i->exception = exc; +#ifdef NW_LOG + nwp_log("%s: %#x\n", exc, (unsigned)gl->type); +#endif + return NW_FATAL; + } + else + { + struct nw_sm_io io = {0}; + + io.buf = &gl->value; + io.n = sz; + g->io = io; + i->next = pop; + i->push_type = gl->type; + } + + return NW_AGAIN; +} + +static enum nw_state get_index(struct nw_interp *const i) +{ + struct nw_i_sm_get_global *const g = &i->sm.get_global; + struct nw_sm_leb128 *const l = &g->leb128; + const struct nw_io_cfg *const cfg = &i->cfg.io; + const enum nw_state n = nwp_varuint32(cfg, l, &g->index, cfg->user); + + if (n) + return n; + else + { + struct nw_sm_io io = {0}; + + io.buf = &g->gl; + io.n = sizeof g->gl; + g->io = io; + i->next = read_global; + } + + return NW_AGAIN; +} + +void nwp_op_set_global(struct nw_interp *const i) +{ + static const struct nw_i_sm_set_global g = {0}; + + i->sm.set_global = g; + i->next = get_index; +} diff --git a/src/op/set_local.c b/src/op/set_local.c new file mode 100644 index 0000000..0488e16 --- /dev/null +++ b/src/op/set_local.c @@ -0,0 +1,24 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2025 Xavier Del Campo Romero + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include <nanowasm/nw.h> +#include <nw/interp.h> +#include <nw/ops.h> +#include <nw/routines.h> + +static enum nw_state resume(struct nw_interp *const i) +{ + nwp_interp_resume(i); + return NW_AGAIN; +} + +void nwp_op_set_local(struct nw_interp *const i) +{ + nwp_set_local(i, resume); +} diff --git a/src/op/tee_local.c b/src/op/tee_local.c new file mode 100644 index 0000000..b95603c --- /dev/null +++ b/src/op/tee_local.c @@ -0,0 +1,64 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2025 Xavier Del Campo Romero + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include <nanowasm/nw.h> +#include <nw/interp.h> +#include <nw/log.h> +#include <nw/ops.h> +#include <nw/routines.h> +#include <nw/stack.h> + +static enum nw_state push(struct nw_interp *const i) +{ + struct nw_i_sm_tee_local *const t = &i->sm.tee_local; + const enum nw_state n = nwp_stack_push(i, &t->io); + + if (n) + return n; + + nwp_interp_resume(i); + return NW_AGAIN; +} + +static enum nw_state prepare(struct nw_interp *const i) +{ + struct nw_i_sm_tee_local *const t = &i->sm.tee_local; + struct nw_i_sm_set_local_out o; + size_t sz; + + o = i->sm.set_local.out; + + if (nwp_type_sz(o.type, &sz)) + { + static const char *const exc = "invalid local type"; + + i->exception = exc; +#ifdef NW_LOG + nwp_log("%s: %#x\n", exc, (unsigned)o.type); +#endif + return NW_FATAL; + } + else + { + struct nw_i_sm_tee_local tl = {{0}}; + + tl.in = o; + tl.io.buf = &t->in.value; + tl.io.n = sz; + *t = tl; + i->next = push; + } + + return NW_AGAIN; +} + +void nwp_op_tee_local(struct nw_interp *const i) +{ + nwp_set_local(i, prepare); +} diff --git a/src/op/tostr.c b/src/op/tostr.c new file mode 100644 index 0000000..b2ac6dd --- /dev/null +++ b/src/op/tostr.c @@ -0,0 +1,278 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2025 Xavier Del Campo Romero + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include <nanowasm/nw.h> +#include <nw/opcodes.h> + +const char *nwp_op_tostr(const enum opcode op) +{ + static const char *const s[] = + { + "OP_UNREACHABLE", + "OP_NOP", + "OP_BLOCK", + "OP_LOOP", + "OP_IF", + "OP_ELSE", + NULL, + NULL, + NULL, + NULL, + NULL, + "OP_END", + "OP_BR", + "OP_BR_IF", + "OP_BR_TABLE", + "OP_RETURN", + "OP_CALL", + "OP_CALL_INDIRECT", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "OP_DROP", + "OP_SELECT", + NULL, + NULL, + NULL, + NULL, + "OP_GET_LOCAL", + "OP_SET_LOCAL", + "OP_TEE_LOCAL", + "OP_GET_GLOBAL", + "OP_SET_GLOBAL", + NULL, + NULL, + NULL, + "OP_I32_LOAD", + "OP_I64_LOAD", + "OP_F32_LOAD", + "OP_F64_LOAD", + "OP_I32_LOAD8_S", + "OP_I32_LOAD8_U", + "OP_I32_LOAD16_S", + "OP_I32_LOAD16_U", + "OP_I64_LOAD8_S", + "OP_I64_LOAD8_U", + "OP_I64_LOAD16_S", + "OP_I64_LOAD16_U", + "OP_I64_LOAD32_S", + "OP_I64_LOAD32_U", + "OP_I32_STORE", + "OP_I64_STORE", + "OP_F32_STORE", + "OP_F64_STORE", + "OP_I32_STORE8", + "OP_I32_STORE16", + "OP_I64_STORE8", + "OP_I64_STORE16", + "OP_I64_STORE32", + "OP_CURRENT_MEMORY", + "OP_GROW_MEMORY", + "OP_I32_CONST", + "OP_I64_CONST", + "OP_F32_CONST", + "OP_F64_CONST", + "OP_I32_EQZ", + "OP_I32_EQ", + "OP_I32_NE", + "OP_I32_LT_S", + "OP_I32_LT_U", + "OP_I32_GT_S", + "OP_I32_GT_U", + "OP_I32_LE_S", + "OP_I32_LE_U", + "OP_I32_GE_S", + "OP_I32_GE_U", + "OP_I64_EQZ", + "OP_I64_EQ", + "OP_I64_NE", + "OP_I64_LT_S", + "OP_I64_LT_U", + "OP_I64_GT_S", + "OP_I64_GT_U", + "OP_I64_LE_S", + "OP_I64_LE_U", + "OP_I64_GE_S", + "OP_I64_GE_U", + "OP_F32_EQ", + "OP_F32_NE", + "OP_F32_LT", + "OP_F32_GT", + "OP_F32_LE", + "OP_F32_GE", + "OP_F64_EQ", + "OP_F64_NE", + "OP_F64_LT", + "OP_F64_GT", + "OP_F64_LE", + "OP_F64_GE", + "OP_I32_CLZ", + "OP_I32_CTZ", + "OP_I32_POPCNT", + "OP_I32_ADD", + "OP_I32_SUB", + "OP_I32_MUL", + "OP_I32_DIV_S", + "OP_I32_DIV_U", + "OP_I32_REM_S", + "OP_I32_REM_U", + "OP_I32_AND", + "OP_I32_OR", + "OP_I32_XOR", + "OP_I32_SHL", + "OP_I32_SHR_S", + "OP_I32_SHR_U", + "OP_I32_ROTL", + "OP_I32_ROTR", + "OP_I64_CLZ", + "OP_I64_CTZ", + "OP_I64_POPCNT", + "OP_I64_ADD", + "OP_I64_SUB", + "OP_I64_MUL", + "OP_I64_DIV_S", + "OP_I64_DIV_U", + "OP_I64_REM_S", + "OP_I64_REM_U", + "OP_I64_AND", + "OP_I64_OR", + "OP_I64_XOR", + "OP_I64_SHL", + "OP_I64_SHR_S", + "OP_I64_SHR_U", + "OP_I64_ROTL", + "OP_I64_ROTR", + "OP_F32_ABS", + "OP_F32_NEG", + "OP_F32_CEIL", + "OP_F32_FLOOR", + "OP_F32_TRUNC", + "OP_F32_NEAREST", + "OP_F32_SQRT", + "OP_F32_ADD", + "OP_F32_SUB", + "OP_F32_MUL", + "OP_F32_DIV", + "OP_F32_MIN", + "OP_F32_MAX", + "OP_F32_COPYSIGN", + "OP_F64_ABS", + "OP_F64_NEG", + "OP_F64_CEIL", + "OP_F64_FLOOR", + "OP_F64_TRUNC", + "OP_F64_NEAREST", + "OP_F64_SQRT", + "OP_F64_ADD", + "OP_F64_SUB", + "OP_F64_MUL", + "OP_F64_DIV", + "OP_F64_MIN", + "OP_F64_MAX", + "OP_F64_COPYSIGN", + "OP_I32_WRAP_I64", + "OP_I32_TRUNC_S_F32", + "OP_I32_TRUNC_U_F32", + "OP_I32_TRUNC_S_F64", + "OP_I32_TRUNC_U_F64", + "OP_I64_EXTEND_S_I32", + "OP_I64_EXTEND_U_I32", + "OP_I64_TRUNC_S_F32", + "OP_I64_TRUNC_U_F32", + "OP_I64_TRUNC_S_F64", + "OP_I64_TRUNC_U_F64", + "OP_F32_CONVERT_S_I32", + "OP_F32_CONVERT_U_I32", + "OP_F32_CONVERT_S_I64", + "OP_F32_CONVERT_U_I64", + "OP_F32_DEMOTE_F64", + "OP_F64_CONVERT_S_I32", + "OP_F64_CONVERT_U_I32", + "OP_F64_CONVERT_S_I64", + "OP_F64_CONVERT_U_I64", + "OP_F64_PROMOTE_F32", + "OP_I32_REINTERPRET_F32", + "OP_I64_REINTERPRET_F64", + "OP_F32_REINTERPRET_I32", + "OP_F64_REINTERPRET_I64", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "OP_MISC", + }; + + if (op < 0 || op >= sizeof s / sizeof *s) + return "invalid opcode"; + + return s[op]; +} diff --git a/src/op/unreachable.c b/src/op/unreachable.c new file mode 100644 index 0000000..6ecd374 --- /dev/null +++ b/src/op/unreachable.c @@ -0,0 +1,38 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2025 Xavier Del Campo Romero + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include <nanowasm/nw.h> +#include <nw/interp.h> +#include <nw/log.h> +#include <nw/ops.h> + +static enum nw_state tell(struct nw_interp *const i) +{ + struct nw_i_sm_unreachable *const u = &i->sm.unreachable; + const struct nw_io_cfg *const cfg = &i->cfg.io; + static const char *const exc = "unreachable"; + const enum nw_state n = cfg->tell(&u->offset, cfg->user); + + if (n) + return n; + + i->exception = exc; +#ifdef NW_LOG + nwp_log("%s, offset: %ld\n", exc, u->offset); +#endif + return NW_FATAL; +} + +void nwp_op_unreachable(struct nw_interp *const i) +{ + static const struct nw_i_sm_unreachable u = {0}; + + i->sm.unreachable = u; + i->next = tell; +} |
