/* * 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 #include #include #include #include #include #include #include static enum nw_state get_entry_count(struct nw_interp *); static enum nw_state push_frame(struct nw_interp *const i) { struct nw_i_sm_pl *const pl = &i->sm.pl; const enum nw_state n = nwp_stack_push(i, &pl->io); if (n) return n; i->fr = pl->fr; #ifdef NW_LOG nwp_log("entering function %lu\n", (unsigned long)i->fr.fn.index); #endif nwp_interp_resume(i); return NW_AGAIN; } static void init(struct nw_i_sm_pl *const pl) { union nw_value *const v = &pl->value; struct nw_sm_io io = {0}; io.buf = v; switch (pl->meta.type) { case NW_TYPE_I32: v->i32 = 0; io.n = sizeof v->i32; break; case NW_TYPE_I64: v->i64.low = 0; v->i64.hi = 0; io.n = sizeof v->i64; break; case NW_TYPE_F32: v->f32 = 0; io.n = sizeof v->f32; break; case NW_TYPE_F64: v->f64 = 0; io.n = sizeof v->f64; break; } pl->io = io; } static enum nw_state get_code_start(struct nw_interp *const i) { struct nw_i_sm_pl *const pl = &i->sm.pl; struct nw_frame *const fr = &pl->fr; const struct nw_io_cfg *const cfg = &i->cfg.io; const enum nw_state n = cfg->tell(&fr->start, cfg->user); if (n) return n; else { struct nw_sm_io io = {0}; io.buf = &i->fr; io.n = sizeof i->fr; pl->io = io; fr->local_end = nwp_stack_ptr(i); fr->body_size -= fr->start - pl->body_start; i->next = push_frame; } return NW_AGAIN; } static enum nw_state push_local(struct nw_interp *const i) { struct nw_i_sm_pl *const pl = &i->sm.pl; const enum nw_state n = nwp_stack_push(i, &pl->io); if (n) return n; else if (++pl->entry_i >= pl->meta.entry_count) i->next = ++pl->local_i >= pl->local_count ? get_code_start : get_entry_count; else init(pl); return NW_AGAIN; } static enum nw_state push_meta(struct nw_interp *const i) { struct nw_i_sm_pl *const pl = &i->sm.pl; const enum nw_state n = nwp_stack_push(i, &pl->io); if (n) return n; init(pl); i->next = push_local; return NW_AGAIN; } static enum nw_state get_type(struct nw_interp *const i) { nw_varint7 type; struct nw_i_sm_pl *const pl = &i->sm.pl; struct nw_sm_leb128 *const l = &pl->leb128; const struct nw_io_cfg *const cfg = &i->cfg.io; const enum nw_state n = nwp_varint7(cfg, l, &type, cfg->user); if (n) return n; else if (nwp_get_type(type, &pl->meta.type)) { static const char *const exc = "invalid type"; i->exception = exc; #ifdef NW_LOG nwp_log("%s: %x\n", exc, (unsigned)type); #endif return NW_FATAL; } else { struct nw_sm_io io = {0}; io.buf = &pl->meta; io.n = sizeof pl->meta; pl->io = io; i->next = push_meta; } return NW_AGAIN; } static enum nw_state get_entry_count(struct nw_interp *const i) { struct nw_i_sm_pl *const pl = &i->sm.pl; struct nw_sm_leb128 *const l = &pl->leb128; nw_varuint32 *const count = &pl->meta.entry_count; struct nw_frame *const fr = &pl->fr; const struct nw_io_cfg *const cfg = &i->cfg.io; const enum nw_state n = nwp_varuint32(cfg, l, count, cfg->user); if (n) return n; pl->entry_i = 0; fr->local_count += *count; i->next = get_type; return NW_AGAIN; } static enum nw_state get_count(struct nw_interp *const i) { struct nw_i_sm_pl *const pl = &i->sm.pl; struct nw_sm_leb128 *const l = &pl->leb128; struct nw_frame *const fr = &pl->fr; const struct nw_io_cfg *const cfg = &i->cfg.io; const enum nw_state n = nwp_varuint32(cfg, l, &pl->local_count, cfg->user); if (n) return n; fr->local_start = nwp_stack_ptr(i); i->next = pl->local_count ? get_entry_count : get_code_start; return NW_AGAIN; } static enum nw_state get_body_start(struct nw_interp *const i) { struct nw_i_sm_pl *const pl = &i->sm.pl; const struct nw_io_cfg *const cfg = &i->cfg.io; const enum nw_state n = cfg->tell(&pl->body_start, cfg->user); if (n) return n; i->next = get_count; return NW_AGAIN; } static enum nw_state get_body_len(struct nw_interp *const i) { struct nw_i_sm_pl *const pl = &i->sm.pl; struct nw_sm_leb128 *const l = &pl->leb128; struct nw_frame *const fr = &pl->fr; const struct nw_io_cfg *const cfg = &i->cfg.io; const enum nw_state n = nwp_varuint32(cfg, l, &fr->body_size, cfg->user); if (n) return n; i->next = get_body_start; return NW_AGAIN; } static void begin(struct nw_interp *const i) { const struct nw_i_sm_pl l = {0}; const struct nw_fn fn = i->sm.ffn.fn; struct nw_i_sm_pl *const pl = &i->sm.pl; struct nw_frame *const fr = &pl->fr; *pl = l; fr->child = 1; fr->fn = fn; fr->fr_start = nwp_stack_ptr(i); i->next = get_body_len; } static enum nw_state find(struct nw_interp *const i) { nwp_find_function(i, &i->sm.type.out, begin); return NW_AGAIN; } void nwp_call_function(struct nw_interp *const i, const nw_varuint32 index) { nwp_get_function_type(i, index, find); }