diff options
Diffstat (limited to 'src/routines/call_function.c')
| -rw-r--r-- | src/routines/call_function.c | 242 |
1 files changed, 242 insertions, 0 deletions
diff --git a/src/routines/call_function.c b/src/routines/call_function.c new file mode 100644 index 0000000..eeee2fc --- /dev/null +++ b/src/routines/call_function.c @@ -0,0 +1,242 @@ +/* + * 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 <nanowasm/types.h> +#include <nw/io.h> +#include <nw/interp.h> +#include <nw/log.h> +#include <nw/routines.h> +#include <nw/stack.h> +#include <nw/types.h> + +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); +} |
