diff options
| author | Xavier Del Campo Romero <xavi92@disroot.org> | 2025-11-15 18:48:16 +0100 |
|---|---|---|
| committer | Xavier Del Campo Romero <xavi92@disroot.org> | 2025-11-15 18:48:16 +0100 |
| commit | 0b2a1fd9439d5ab1cdc076d7b9f1e763c4900b74 (patch) | |
| tree | a0a1724b1a8b2dbde94e938bb18b6ca4bb5ce800 /src | |
| parent | 4a356bf56051361f2c72037f4fb043f8fdaa576c (diff) | |
| download | nanowasm-0b2a1fd9439d5ab1cdc076d7b9f1e763c4900b74.tar.gz | |
Add br_table
br_table is in fact a generalization of other branch types like br or
br_if, since br_table contains several branches for the same pc inside
the nw_lo section.
Therefore, this kind of branch forced some changes to nwp_break and
those relying on it.
Diffstat (limited to 'src')
| -rw-r--r-- | src/interp/ops.c | 2 | ||||
| -rw-r--r-- | src/op/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | src/op/br.c | 2 | ||||
| -rw-r--r-- | src/op/br_if.c | 2 | ||||
| -rw-r--r-- | src/op/br_table.c | 98 | ||||
| -rw-r--r-- | src/op/else.c | 2 | ||||
| -rw-r--r-- | src/op/if.c | 2 | ||||
| -rw-r--r-- | src/routines/break.c | 8 |
8 files changed, 109 insertions, 8 deletions
diff --git a/src/interp/ops.c b/src/interp/ops.c index 9f80668..4366a49 100644 --- a/src/interp/ops.c +++ b/src/interp/ops.c @@ -28,7 +28,7 @@ static void (*const ops[])(struct nw_interp *) = nwp_op_end, /* OP_END */ nwp_op_br, /* OP_BR */ nwp_op_br_if, /* OP_BR_IF */ - NULL, /* OP_BR_TABLE */ + nwp_op_br_table, /* OP_BR_TABLE */ nwp_op_return, /* OP_RETURN */ nwp_op_call, /* OP_CALL */ nwp_op_call_indirect, /* OP_CALL_INDIRECT */ diff --git a/src/op/CMakeLists.txt b/src/op/CMakeLists.txt index 7468132..7cc6ff8 100644 --- a/src/op/CMakeLists.txt +++ b/src/op/CMakeLists.txt @@ -9,6 +9,7 @@ target_sources(${PROJECT_NAME} PRIVATE block.c br.c br_if.c + br_table.c call.c call_indirect.c current_memory.c diff --git a/src/op/br.c b/src/op/br.c index dd0066f..212d5dd 100644 --- a/src/op/br.c +++ b/src/op/br.c @@ -23,7 +23,7 @@ static enum nw_state get_relative_depth(struct nw_interp *const i) if (n) return n; - nwp_break(i, b->relative_depth); + nwp_break(i, b->relative_depth, 0); return NW_AGAIN; } diff --git a/src/op/br_if.c b/src/op/br_if.c index 6eca18a..a413f1e 100644 --- a/src/op/br_if.c +++ b/src/op/br_if.c @@ -46,7 +46,7 @@ static enum nw_state pop(struct nw_interp *const i) if (n) return n; else if (condition(i)) - nwp_break(i, b->relative_depth); + nwp_break(i, b->relative_depth, 0); else nwp_interp_resume(i); diff --git a/src/op/br_table.c b/src/op/br_table.c new file mode 100644 index 0000000..2737c0d --- /dev/null +++ b/src/op/br_table.c @@ -0,0 +1,98 @@ +/* + * 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 enum nw_state get_target(struct nw_interp *const i) +{ + nw_varuint32 target; + struct nw_i_sm_br_table *const b = &i->sm.br_table; + const struct nw_io_cfg *const cfg = &i->cfg.io; + const enum nw_state n = nwp_varuint32(cfg, &b->leb128, &target, cfg->user); + + if (n) + return n; + else if (b->target_i == b->offset + || (!b->set && b->target_i >= b->target_count)) + { + b->set = 1; + b->relative_depth = target; + } + + if (b->target_i >= b->target_count) + nwp_break(i, b->relative_depth, b->offset); + else + b->target_i++; + + return NW_AGAIN; +} + +static enum nw_state pop(struct nw_interp *const i) +{ + struct nw_i_sm_br_table *const b = &i->sm.br_table; + const enum nw_state n = nwp_stack_pop(i, &b->io); + + if (n) + return n; + + i->next = get_target; + return NW_AGAIN; +} + +static enum nw_state get_target_count(struct nw_interp *const i) +{ + struct nw_i_sm_br_table *const b = &i->sm.br_table; + const struct nw_io_cfg *const cfg = &i->cfg.io; + const enum nw_state n = nwp_varuint32(cfg, &b->leb128, + &b->target_count, cfg->user); + const enum nw_type pt = i->push_type; + + if (n) + return n; + else if (pt != NW_TYPE_I32) + { + static const char *const exc = "expected i32 expression for br_table"; + const char *const stype = nwp_type_str(pt); + + i->exception = exc; +#ifdef NW_LOG + if (stype) + nwp_log("%s, got: %s\n", exc, stype); + else + nwp_log("%s, got: unknown (%#x)\n", exc, (unsigned)pt); +#endif + return NW_FATAL; + } + else + { + struct nw_sm_io io = {0}; + + io.buf = &b->offset; + io.n = sizeof b->offset; + b->io = io; + i->next = pop; + } + + return NW_AGAIN; +} + +void nwp_op_br_table(struct nw_interp *const i) +{ + static const struct nw_i_sm_br_table b; + + i->next = get_target_count; + i->sm.br_table = b; +} diff --git a/src/op/else.c b/src/op/else.c index 2c1c6b1..13d9c6c 100644 --- a/src/op/else.c +++ b/src/op/else.c @@ -14,5 +14,5 @@ void nwp_op_else(struct nw_interp *const i) { - nwp_break(i, 0); + nwp_break(i, 0, 0); } diff --git a/src/op/if.c b/src/op/if.c index 2ef9565..2f5f4f5 100644 --- a/src/op/if.c +++ b/src/op/if.c @@ -25,7 +25,7 @@ static enum nw_state pop(struct nw_interp *const i) else if (pif->condition) nwp_interp_resume(i); else - nwp_break(i, 0); + nwp_break(i, 0, 0); return NW_AGAIN; } diff --git a/src/routines/break.c b/src/routines/break.c index 3ee94a1..bf13ca6 100644 --- a/src/routines/break.c +++ b/src/routines/break.c @@ -40,7 +40,7 @@ static enum nw_state skip(struct nw_interp *const i) i->exception = exc; #ifdef NW_LOG - nwp_log("%s from offset: %ld\n", exc, b->pc); + nwp_log("%s, offset: %#lx\n", exc, b->pc); #endif return NW_FATAL; } @@ -66,7 +66,7 @@ static enum nw_state get_dst(struct nw_interp *const i) if (n) return n; - else if (pc == b->pc) + else if (pc == b->pc && b->toffset_i++ >= b->table_offset) i->next = seek_dst; else return skip(i); @@ -232,12 +232,14 @@ static enum nw_state tell(struct nw_interp *const i) return NW_AGAIN; } -void nwp_break(struct nw_interp *const i, const nw_varuint32 relative_depth) +void nwp_break(struct nw_interp *const i, const nw_varuint32 relative_depth, + const nw_varuint32 table_offset) { 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; + pb->table_offset = table_offset; i->next = tell; } |
