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/routines/break.c | |
| download | nanowasm-6d9d80362f9932bbc87e162b8ef7df06c73e27e1.tar.gz | |
First commit
Diffstat (limited to 'src/routines/break.c')
| -rw-r--r-- | src/routines/break.c | 243 |
1 files changed, 243 insertions, 0 deletions
diff --git a/src/routines/break.c b/src/routines/break.c new file mode 100644 index 0000000..3ee94a1 --- /dev/null +++ b/src/routines/break.c @@ -0,0 +1,243 @@ +/* + * 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/routines.h> + +static enum nw_state get_pc(struct nw_interp *); + +static enum nw_state seek_dst(struct nw_interp *const i) +{ + const struct nw_i_sm_break *const b = &i->sm.brk; + const struct nw_io_cfg *const cfg = &i->cfg.io; + const unsigned long dst = nwp_leuint32(&b->dst); + const enum nw_state n = cfg->seek(dst, cfg->user); + + if (n) + return n; + + nwp_interp_resume(i); + return NW_AGAIN; +} + +static enum nw_state skip(struct nw_interp *const i) +{ + struct nw_i_sm_break *const b = &i->sm.brk; + const unsigned long n_labels = nwp_leuint32(&b->n); + + if (++b->label_i >= n_labels) + { + static const char *const exc = "no label found"; + + i->exception = exc; +#ifdef NW_LOG + nwp_log("%s from offset: %ld\n", exc, b->pc); +#endif + return NW_FATAL; + } + else + { + struct nw_sm_io io = {0}; + + io.buf = &b->lpc; + io.n = sizeof b->lpc; + b->io = io; + i->next = get_pc; + } + + return NW_AGAIN; +} + +static enum nw_state get_dst(struct nw_interp *const i) +{ + struct nw_i_sm_break *const b = &i->sm.brk; + const struct nw_io_cfg *const cfg = &i->cfg.io; + const unsigned long pc = nwp_leuint32(&b->lpc); + const enum nw_state n = nwp_io_read(cfg, &b->io, cfg->user); + + if (n) + return n; + else if (pc == b->pc) + i->next = seek_dst; + else + return skip(i); + + return NW_AGAIN; +} + +static enum nw_state get_pc(struct nw_interp *const i) +{ + struct nw_i_sm_break *const b = &i->sm.brk; + const struct nw_io_cfg *const cfg = &i->cfg.io; + const enum nw_state n = nwp_io_read(cfg, &b->io, cfg->user); + + if (n) + return n; + else + { + struct nw_sm_io io = {0}; + + io.buf = &b->dst; + io.n = sizeof b->dst; + b->io = io; + i->next = get_dst; + } + + return NW_AGAIN; +} + +static enum nw_state get_n(struct nw_interp *const i) +{ + struct nw_i_sm_break *const b = &i->sm.brk; + const struct nw_io_cfg *const cfg = &i->cfg.io; + const enum nw_state n = nwp_io_read(cfg, &b->io, cfg->user); + + if (n) + return n; + else if (!nwp_leuint32(&b->n)) + { + static const char *const exc = "function has no labels"; + + i->exception = exc; +#ifdef NW_LOG + nwp_log("%s\n", exc); +#endif + return NW_FATAL; + } + else + { + struct nw_sm_io io = {0}; + + io.buf = &b->lpc; + io.n = sizeof b->lpc; + b->io = io; + } + + i->next = get_pc; + return NW_AGAIN; +} + +static enum nw_state seek_start(struct nw_interp *const i) +{ + struct nw_i_sm_break *const b = &i->sm.brk; + const struct nw_io_cfg *const cfg = &i->cfg.io; + const unsigned long offset = nwp_leuint32(&b->offset); + const enum nw_state n = cfg->seek(offset, cfg->user); + + if (n) + return n; + else + { + struct nw_sm_io io = {0}; + + io.buf = &b->n; + io.n = sizeof b->n; + b->io = io; + i->next = get_n; + } + + return NW_AGAIN; +} + +static enum nw_state get_start(struct nw_interp *const i) +{ + struct nw_i_sm_break *const b = &i->sm.brk; + const struct nw_io_cfg *const cfg = &i->cfg.io; + const enum nw_state n = nwp_io_read(cfg, &b->io, cfg->user); + + if (n) + return n; + + i->next = seek_start; + return NW_AGAIN; +} + +static enum nw_state seek_lo(struct nw_interp *const i) +{ + const struct nw_mod *const m = i->cfg.m; + struct nw_i_sm_break *const b = &i->sm.brk; + const struct nw_io_cfg *const cfg = &i->cfg.io; + long offset = m->c_sections[NW_CUSTOM_LO]; + enum nw_state n; + + if (!offset) + { + static const char *const exc = "nw_lo section not found"; + + i->exception = exc; +#ifdef NW_LOG + nwp_log("%s\n", exc); +#endif + return NW_FATAL; + } + else if (i->fr.fn.index < m->import_count) + { + static const char *const exc = "invalid function index"; + + i->exception = exc; +#ifdef NW_LOG + nwp_log("%s: %lu\n", exc, (unsigned long)i->fr.fn.index); +#endif + return NW_FATAL; + } + + offset += sizeof b->offset * (i->fr.fn.index - m->import_count); + + if ((n = cfg->seek(offset, cfg->user))) + return n; + else + { + struct nw_sm_io io = {0}; + + io.buf = &b->offset; + io.n = sizeof b->offset; + b->io = io; + i->next = get_start; + } + + return NW_AGAIN; +} + +static enum nw_state tell(struct nw_interp *const i) +{ + struct nw_i_sm_break *const b = &i->sm.brk; + const struct nw_io_cfg *const cfg = &i->cfg.io; + const enum nw_state n = cfg->tell(&b->pc, cfg->user); + + if (n) + return n; + else if (i->fr.block_i < b->relative_depth) + { + static const char *const exc = "relative depth exceeds block level"; + + i->exception = exc; +#ifdef NW_LOG + nwp_log("%s, rdepth: %lu, blvl: %lu\n", exc, + (unsigned long)i->fr.block_i, (unsigned long)b->relative_depth); +#endif + return NW_FATAL; + } + + i->fr.block_i -= b->relative_depth; + i->next = seek_lo; + return NW_AGAIN; +} + +void nwp_break(struct nw_interp *const i, const nw_varuint32 relative_depth) +{ + const struct nw_i_sm_break b = {0}; + struct nw_i_sm_break *const pb = &i->sm.brk; + + *pb = b; + pb->relative_depth = relative_depth; + i->next = tell; +} |
