diff options
| author | Xavier Del Campo Romero <xavi.dcr@tutanota.com> | 2023-11-26 22:43:30 +0100 |
|---|---|---|
| committer | Xavier Del Campo Romero <xavi.dcr@tutanota.com> | 2024-04-21 01:51:24 +0200 |
| commit | f25b015e5b668028c34974bbb22faa4105c26690 (patch) | |
| tree | 28f2b08c17b3585d06694ad74004d0617eadb785 /src/op | |
| download | nanowasm-sync-f25b015e5b668028c34974bbb22faa4105c26690.tar.gz | |
First commit
Diffstat (limited to 'src/op')
33 files changed, 1567 insertions, 0 deletions
diff --git a/src/op/CMakeLists.txt b/src/op/CMakeLists.txt new file mode 100644 index 0000000..7bf27de --- /dev/null +++ b/src/op/CMakeLists.txt @@ -0,0 +1,13 @@ +# nanowasm, a tiny WebAssembly/Wasm interpreter +# Copyright (C) 2023-2024 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/. + +add_subdirectory(call) +add_subdirectory(constants) +add_subdirectory(control_flow) +add_subdirectory(memory) +add_subdirectory(numeric) +add_subdirectory(variable_access) diff --git a/src/op/call/CMakeLists.txt b/src/op/call/CMakeLists.txt new file mode 100644 index 0000000..527f35d --- /dev/null +++ b/src/op/call/CMakeLists.txt @@ -0,0 +1,11 @@ +# nanowasm, a tiny WebAssembly/Wasm interpreter +# Copyright (C) 2023-2024 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 + call.c + call_indirect.c +) diff --git a/src/op/call/call.c b/src/op/call/call.c new file mode 100644 index 0000000..19355ca --- /dev/null +++ b/src/op/call/call.c @@ -0,0 +1,79 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2024 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/log.h> +#include <nw/ops.h> +#include <nanowasm/nw.h> +#include <nw/interp.h> +#include <nw/search.h> +#include <nw/sections.h> +#include <nw/types.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> + +static int call(struct nw_interp *const i, const varuint32 function_index) +{ + FILE *const f = i->f; + const struct nw_mod *const m = i->cfg.m; + struct nw_frame fr = {0}; + struct search_fn fn; + + /* TODO: treat import functions. */ + if (search_fn(function_index, m, f, &fn)) + { + LOG("%s: search_fn failed\n", __func__); + return -1; + } + else if (section_type_push(f, m, fn.index, &fr)) + { + LOG("%s: section_type_push failed\n", __func__); + return -1; + } + else if (section_code_push(f, fn.start, &fr)) + { + LOG("%s: section_code_push failed\n", __func__); + return -1; + } + else if (interp_push(i, &fr)) + { + LOG("%s: interp_push failed\n", __func__); + return -1; + } + + return 0; +} + +static int op(struct nw_interp *const i, FILE *const f) +{ + varuint32 function_index; + + if (varuint32_read(f, &function_index)) + { + LOG("%s: varuint32_read failed\n", __func__); + return -1; + } + else if (i && call(i, function_index)) + { + LOG("%s: call failed\n", __func__); + return -1; + } + + return 0; +} + +int op_call(struct nw_interp *const i) +{ + return op(i, i->f); +} + +int check_call(FILE *const f) +{ + return op(NULL, f); +} diff --git a/src/op/call/call_indirect.c b/src/op/call/call_indirect.c new file mode 100644 index 0000000..bae8a57 --- /dev/null +++ b/src/op/call/call_indirect.c @@ -0,0 +1,49 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2024 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/log.h> +#include <nw/ops.h> +#include <nanowasm/nw.h> +#include <nw/types.h> +#include <stdio.h> + +static int op(struct nw_interp *const i, FILE *const f) +{ + varuint32 type_index; + varuint1 reserved; + + if (varuint32_read(f, &type_index)) + { + LOG("%s: varuint32_read failed\n", __func__); + return 1; + } + else if (varuint1_read(f, &reserved)) + { + LOG("%s: varuint1_read failed\n", __func__); + return 1; + } + else if (reserved) + { + LOG("%s: unexpected non-zero reserved value %u\n", + __func__, (unsigned)reserved); + return 1; + } + + return 0; +} + +int op_call_indirect(struct nw_interp *const i) +{ + return op(i, i->f); +} + +int check_call_indirect(FILE *const f) +{ + return op(NULL, f); +} diff --git a/src/op/constants/CMakeLists.txt b/src/op/constants/CMakeLists.txt new file mode 100644 index 0000000..e5cc8c5 --- /dev/null +++ b/src/op/constants/CMakeLists.txt @@ -0,0 +1,13 @@ +# nanowasm, a tiny WebAssembly/Wasm interpreter +# Copyright (C) 2023-2024 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 + f32_const.c + f64_const.c + i32_const.c + i64_const.c +) diff --git a/src/op/constants/f32_const.c b/src/op/constants/f32_const.c new file mode 100644 index 0000000..c0c51b9 --- /dev/null +++ b/src/op/constants/f32_const.c @@ -0,0 +1,38 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2024 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/log.h> +#include <nw/ops.h> +#include <nanowasm/nw.h> +#include <nw/types.h> +#include <stddef.h> +#include <stdio.h> + +static int op(struct nw_interp *const i, FILE *const f) +{ + varuint32 value; + + if (varuint32_read(f, &value)) + { + LOG("%s: varuint32_read failed\n", __func__); + return -1; + } + + return 0; +} + +int op_f32_const(struct nw_interp *const i) +{ + return op(i, i->f); +} + +int check_f32_const(FILE *const f) +{ + return op(NULL, f); +} diff --git a/src/op/constants/f64_const.c b/src/op/constants/f64_const.c new file mode 100644 index 0000000..d88398c --- /dev/null +++ b/src/op/constants/f64_const.c @@ -0,0 +1,38 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2024 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/log.h> +#include <nw/ops.h> +#include <nanowasm/nw.h> +#include <nw/types.h> +#include <stddef.h> +#include <stdio.h> + +static int op(struct nw_interp *const i, FILE *const f) +{ + varuint64 value; + + if (varuint64_read(f, &value)) + { + LOG("%s: varuint64_read failed\n", __func__); + return -1; + } + + return 0; +} + +int op_f64_const(struct nw_interp *const i) +{ + return op(i, i->f); +} + +int check_f64_const(FILE *const f) +{ + return op(NULL, f); +} diff --git a/src/op/constants/i32_const.c b/src/op/constants/i32_const.c new file mode 100644 index 0000000..19161d3 --- /dev/null +++ b/src/op/constants/i32_const.c @@ -0,0 +1,51 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2024 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/log.h> +#include <nw/ops.h> +#include <nanowasm/nw.h> +#include <nw/types.h> +#include <nw/interp.h> +#include <stddef.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> + +static int set_value(struct nw_interp *const i, const int32_t src) +{ + return interp_stack_push(i, &src, sizeof src); +} + +static int op(struct nw_interp *const i, FILE *const f) +{ + varint32 value; + + if (varint32_read(f, &value)) + { + LOG("%s: varint32_read failed\n", __func__); + return -1; + } + else if (i && set_value(i, value)) + { + LOG("%s: set_value failed\n", __func__); + return -1; + } + + return 0; +} + +int op_i32_const(struct nw_interp *const i) +{ + return op(i, i->f); +} + +int check_i32_const(FILE *const f) +{ + return op(NULL, f); +} diff --git a/src/op/constants/i64_const.c b/src/op/constants/i64_const.c new file mode 100644 index 0000000..53f4237 --- /dev/null +++ b/src/op/constants/i64_const.c @@ -0,0 +1,38 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2024 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/log.h> +#include <nw/ops.h> +#include <nanowasm/nw.h> +#include <nw/types.h> +#include <stddef.h> +#include <stdio.h> + +static int op(struct nw_interp *const i, FILE *const f) +{ + varint64 value; + + if (varint64_read(f, &value)) + { + LOG("%s: varint32_read failed\n", __func__); + return -1; + } + + return 0; +} + +int op_i64_const(struct nw_interp *const i) +{ + return op(i, i->f); +} + +int check_i64_const(FILE *const f) +{ + return op(NULL, f); +} diff --git a/src/op/control_flow/CMakeLists.txt b/src/op/control_flow/CMakeLists.txt new file mode 100644 index 0000000..832f09e --- /dev/null +++ b/src/op/control_flow/CMakeLists.txt @@ -0,0 +1,20 @@ +# nanowasm, a tiny WebAssembly/Wasm interpreter +# Copyright (C) 2023-2024 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 + br_table.c + else.c + end.c + if.c + loop.c + nop.c + return.c + unreachable.c +) diff --git a/src/op/control_flow/block.c b/src/op/control_flow/block.c new file mode 100644 index 0000000..56f72f1 --- /dev/null +++ b/src/op/control_flow/block.c @@ -0,0 +1,75 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2024 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/log.h> +#include <nw/ops.h> +#include <nanowasm/nw.h> +#include <nw/interp.h> +#include <nw/types.h> +#include <errno.h> +#include <stddef.h> +#include <stdio.h> +#include <string.h> + +static int push(struct nw_interp *const i, FILE *const f) +{ + const long pc = ftell(f); + + if (pc < 0) + { + LOG("%s: ftell(3): %s\n", __func__, strerror(errno)); + i->exception = "I/O error"; + return -1; + } + + struct nw_frame *const fp = i->fp; + struct nw_block *const p = interp_stackptr(i); + const struct nw_block b = + { + .pc = pc, + .prev = fp->last_block + }; + + if (interp_stack_push(i, &b, sizeof b)) + { + LOG("%s: interp_stack_push failed\n", __func__); + return -1; + } + + fp->last_block = p; + return 0; +} + +static int op(struct nw_interp *const i, FILE *const f) +{ + varint7 sig; + + if (varint7_read(f, &sig)) + { + LOG("%s: varint7_read failed\n", __func__); + return -1; + } + else if (i && push(i, f)) + { + LOG("%s: push failed\n", __func__); + return -1; + } + + return 0; +} + +int op_block(struct nw_interp *const i) +{ + return op(i, i->f); +} + +int check_block(FILE *const f) +{ + return op(NULL, f); +} diff --git a/src/op/control_flow/br.c b/src/op/control_flow/br.c new file mode 100644 index 0000000..df3aacb --- /dev/null +++ b/src/op/control_flow/br.c @@ -0,0 +1,38 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2024 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/log.h> +#include <nw/ops.h> +#include <nanowasm/nw.h> +#include <nw/types.h> +#include <stddef.h> +#include <stdio.h> + +static int op(struct nw_interp *const i, FILE *const f) +{ + varuint32 relative_depth; + + if (varuint32_read(f, &relative_depth)) + { + LOG("%s: varuint32_read failed\n", __func__); + return -1; + } + + return 0; +} + +int op_br(struct nw_interp *const i) +{ + return op(i, i->f); +} + +int check_br(FILE *const f) +{ + return op(NULL, f); +} diff --git a/src/op/control_flow/br_if.c b/src/op/control_flow/br_if.c new file mode 100644 index 0000000..25bfdee --- /dev/null +++ b/src/op/control_flow/br_if.c @@ -0,0 +1,95 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2024 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/log.h> +#include <nw/ops.h> +#include <nanowasm/nw.h> +#include <nw/interp.h> +#include <nw/types.h> +#include <errno.h> +#include <stddef.h> +#include <stdio.h> +#include <string.h> + +static int branch(struct nw_interp *const i, const varuint32 relative_depth) +{ + const struct nw_block *b = i->fp->last_block; + static const char exc[] = "relative depth and block count mismatch"; + + for (varuint32 d = 0; b && d < relative_depth; d++) + b = b->prev; + + if (!b) + { + LOG("%s: %s\n", __func__, exc); + i->exception = exc; + return -1; + } + + if (fseek(i->f, b->pc, SEEK_SET)) + { + LOG("%s: fseek(3): %s\n", __func__, strerror(errno)); + i->exception = "I/O error"; + return -1; + } + + return 0; +} + +static bool cond(struct nw_interp *const i) +{ + int32_t value; + + if (interp_stack_pop(i, &value, sizeof value)) + { + LOG("%s: interp_stack_pop failed\n", __func__); + return -1; + } + + return value; +} + +static int br_if(struct nw_interp *const i, const varuint32 relative_depth) +{ + if (cond(i) && branch(i, relative_depth)) + { + LOG("%s: branch failed\n", __func__); + return -1; + } + + return 0; +} + +static int op(struct nw_interp *const i, FILE *const f) +{ + varuint32 relative_depth; + + if (varuint32_read(f, &relative_depth)) + { + LOG("%s: varuint32_read failed\n", __func__); + return 1; + } + else if (i && br_if(i, relative_depth)) + { + LOG("%s: br_if failed\n", __func__); + return -1; + } + + return 0; +} + +int op_br_if(struct nw_interp *const i) +{ + return op(i, i->f); +} + +int check_br_if(FILE *const f) +{ + return op(NULL, f); +} diff --git a/src/op/control_flow/br_table.c b/src/op/control_flow/br_table.c new file mode 100644 index 0000000..837cdcd --- /dev/null +++ b/src/op/control_flow/br_table.c @@ -0,0 +1,56 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2024 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/log.h> +#include <nw/ops.h> +#include <nanowasm/nw.h> +#include <nw/types.h> +#include <stddef.h> +#include <stdio.h> + +static int op(struct nw_interp *const i, FILE *const f) +{ + varuint32 target_count, default_target; + + if (varuint32_read(f, &target_count)) + { + LOG("%s: varuint32_read target_count failed\n", __func__); + return -1; + } + + for (varuint32 i = 0; i < target_count; i++) + { + varuint32 target_table; + + if (varuint32_read(f, &target_table)) + { + LOG("%s: varuint32_read target_table failed\n", + __func__); + return -1; + } + } + + if (varuint32_read(f, &default_target)) + { + LOG("%s: varuint32_read default_target failed\n", __func__); + return -1; + } + + return 0; +} + +int op_br_table(struct nw_interp *const i) +{ + return op(i, i->f); +} + +int check_br_table(FILE *const f) +{ + return op(NULL, f); +} diff --git a/src/op/control_flow/else.c b/src/op/control_flow/else.c new file mode 100644 index 0000000..fb839f0 --- /dev/null +++ b/src/op/control_flow/else.c @@ -0,0 +1,21 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2024 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/ops.h> +#include <nanowasm/nw.h> + +int op_else(struct nw_interp *const i) +{ + return -1; +} + +int check_else(FILE *const f) +{ + return 0; +} diff --git a/src/op/control_flow/end.c b/src/op/control_flow/end.c new file mode 100644 index 0000000..5f193d9 --- /dev/null +++ b/src/op/control_flow/end.c @@ -0,0 +1,24 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2024 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/ops.h> +#include <nanowasm/nw.h> +#include <stdbool.h> + +int op_end(struct nw_interp *const i) +{ + /* TODO: this is not correct. end can appear anywhere in a function. */ + i->exit = true; + return 0; +} + +int check_end(FILE *const f) +{ + return 0; +} diff --git a/src/op/control_flow/if.c b/src/op/control_flow/if.c new file mode 100644 index 0000000..1d5e838 --- /dev/null +++ b/src/op/control_flow/if.c @@ -0,0 +1,36 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2024 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/log.h> +#include <nw/ops.h> +#include <nanowasm/nw.h> +#include <nw/types.h> + +static int op(struct nw_interp *const i, FILE *const f) +{ + varint7 sig; + + if (varint7_read(f, &sig)) + { + LOG("%s: varint7_read failed\n", __func__); + return -1; + } + + return 0; +} + +int op_if(struct nw_interp *const i) +{ + return op(i, i->f); +} + +int check_if(FILE *const f) +{ + return op(NULL, f); +} diff --git a/src/op/control_flow/loop.c b/src/op/control_flow/loop.c new file mode 100644 index 0000000..5020f23 --- /dev/null +++ b/src/op/control_flow/loop.c @@ -0,0 +1,36 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2024 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/log.h> +#include <nw/ops.h> +#include <nanowasm/nw.h> +#include <nw/types.h> + +static int op(struct nw_interp *const i, FILE *const f) +{ + varint7 sig; + + if (varint7_read(f, &sig)) + { + LOG("%s: varint7_read failed\n", __func__); + return -1; + } + + return 0; +} + +int op_loop(struct nw_interp *const i) +{ + return op(i, i->f); +} + +int check_loop(FILE *const f) +{ + return op(NULL, f); +} diff --git a/src/op/control_flow/nop.c b/src/op/control_flow/nop.c new file mode 100644 index 0000000..356b7b0 --- /dev/null +++ b/src/op/control_flow/nop.c @@ -0,0 +1,22 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2024 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/ops.h> +#include <nanowasm/nw.h> +#include <nw/interp.h> + +int op_nop(struct nw_interp *const i) +{ + return 0; +} + +int check_nop(FILE *const f) +{ + return 0; +} diff --git a/src/op/control_flow/return.c b/src/op/control_flow/return.c new file mode 100644 index 0000000..abddea7 --- /dev/null +++ b/src/op/control_flow/return.c @@ -0,0 +1,30 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2024 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/log.h> +#include <nw/interp.h> +#include <nw/ops.h> +#include <nanowasm/nw.h> +#include <stdio.h> + +int op_return(struct nw_interp *const i) +{ + if (interp_pop(i)) + { + LOG("%s: interp_pop failed\n", __func__); + return -1; + } + + return 0; +} + +int check_return(FILE *const f) +{ + return 0; +} diff --git a/src/op/control_flow/unreachable.c b/src/op/control_flow/unreachable.c new file mode 100644 index 0000000..8f1982c --- /dev/null +++ b/src/op/control_flow/unreachable.c @@ -0,0 +1,25 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2024 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/ops.h> +#include <nanowasm/nw.h> +#include <stdbool.h> +#include <stdio.h> + +int op_unreachable(struct nw_interp *const i) +{ + i->exception = "Unreachable instruction"; + i->exit = true; + return 1; +} + +int check_unreachable(FILE *const f) +{ + return 0; +} diff --git a/src/op/memory/CMakeLists.txt b/src/op/memory/CMakeLists.txt new file mode 100644 index 0000000..ca4ba5a --- /dev/null +++ b/src/op/memory/CMakeLists.txt @@ -0,0 +1,12 @@ +# nanowasm, a tiny WebAssembly/Wasm interpreter +# Copyright (C) 2023-2024 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 + current_memory.c + i32_load.c + i32_store.c +) diff --git a/src/op/memory/current_memory.c b/src/op/memory/current_memory.c new file mode 100644 index 0000000..c67d425 --- /dev/null +++ b/src/op/memory/current_memory.c @@ -0,0 +1,44 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2024 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/log.h> +#include <nw/ops.h> +#include <nanowasm/nw.h> +#include <nw/types.h> +#include <stddef.h> +#include <stdio.h> + +static int op(struct nw_interp *const i, FILE *const f) +{ + varuint1 reserved; + + if (varuint1_read(f, &reserved)) + { + LOG("%s: varuint1_read failed\n", __func__); + return 1; + } + else if (reserved) + { + LOG("%s: unexpected non-zero reserved value %u\n", + __func__, (unsigned)reserved); + return 1; + } + + return 0; +} + +int op_current_memory(struct nw_interp *const i) +{ + return op(i, i->f); +} + +int check_current_memory(FILE *const f) +{ + return op(NULL, f); +} diff --git a/src/op/memory/i32_load.c b/src/op/memory/i32_load.c new file mode 100644 index 0000000..04dbec7 --- /dev/null +++ b/src/op/memory/i32_load.c @@ -0,0 +1,76 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2024 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/log.h> +#include <nw/ops.h> +#include <nanowasm/nw.h> +#include <nw/interp.h> +#include <nw/types.h> +#include <stddef.h> +#include <stdio.h> + +static int load(struct nw_interp *const i, const varuint32 flags, + const varuint32 offset) +{ + enum {ALIGN = 2}; + int32_t value; + + if (flags != ALIGN) + { + LOG("%s: expected 32-bit alignment (%d), got %lu\n", + __func__, ALIGN, (unsigned long)flags); + i->exception = "unaligned access"; + return -1; + } + else if (interp_heap_load(i, offset, &value, sizeof value)) + { + LOG("%s: interp_heap_load failed\n", __func__); + return -1; + } + else if (interp_stack_push(i, &value, sizeof value)) + { + LOG("%s: interp_stack_push failed\n", __func__); + return -1; + } + + return 0; +} + +static int op(struct nw_interp *const i, FILE *const f) +{ + varint32 flags, offset; + + if (varint32_read(f, &flags)) + { + LOG("%s: varint32_read flags failed\n", __func__); + return 1; + } + else if (varint32_read(f, &offset)) + { + LOG("%s: varint32_read offset failed\n", __func__); + return 1; + } + else if (i && load(i, flags, offset)) + { + LOG("%s: load failed\n", __func__); + return -1; + } + + return 0; +} + +int op_i32_load(struct nw_interp *const i) +{ + return op(i, i->f); +} + +int check_i32_load(FILE *const f) +{ + return op(NULL, f); +} diff --git a/src/op/memory/i32_store.c b/src/op/memory/i32_store.c new file mode 100644 index 0000000..212cd86 --- /dev/null +++ b/src/op/memory/i32_store.c @@ -0,0 +1,125 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2024 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/log.h> +#include <nw/ops.h> +#include <nanowasm/nw.h> +#include <nw/types.h> +#include <nw/interp.h> +#include <stdint.h> +#include <stddef.h> +#include <stdio.h> + +static int store(struct nw_interp *const i, const varuint32 flags, + const varuint32 offset) +{ + enum {ALIGN = 2}; + + if (flags != ALIGN) + { + LOG("%s: expected 32-bit alignment (%d), got %lu\n", + __func__, ALIGN, (unsigned long)flags); + i->exception = "unaligned access"; + return -1; + } + + int32_t value, addr; + + if (interp_stack_pop(i, &value, sizeof value)) + { + LOG("%s: inter_stack_pop value failed\n", __func__); + return -1; + } + else if (interp_stack_pop(i, &addr, sizeof addr)) + { + LOG("%s: inter_stack_pop addr failed\n", __func__); + return -1; + } + else if (offset > SIZE_MAX - addr) + { + static const char exc[] = "offset address overflow"; + + LOG("%s: %s\n", __func__, exc); + i->exception = exc; + return -1; + } + else if (interp_heap_store(i, offset + addr, &value, sizeof value)) + { + LOG("%s: interp_heap_store failed\n", __func__); + return -1; + } + + return 0; +#if 0 + stack_i -= sizeof addr; + + if (max < addr || offset >= max - addr) + { + LOG("%s: heap overflow\n", __func__); + i->exception = "heap overflow"; + return -1; + } + + const size_t raddr = offset + addr; + + if (raddr % sizeof addr) + { + LOG("%s: unaligned memory address\n", __func__); + i->exception = "unaligned access"; + return -1; + } + else if (stack_i < sizeof (uint32_t)) + { + LOG("%s: stack underflow (value)\n", __func__); + i->exception = "stack underflow"; + return -1; + } + + const int32_t value = htoni32(*stackptr); + void *dst = &((char *)i->cfg.heap.buf)[raddr]; + + *(int32_t *)dst = value; + stack_i -= sizeof addr; + i->stack_i = stack_i; + return 0; +#endif +} + +static int op(struct nw_interp *const i, FILE *const f) +{ + varuint32 flags, offset; + + if (varuint32_read(f, &flags)) + { + LOG("%s: varint32_read flags failed\n", __func__); + return -1; + } + else if (varuint32_read(f, &offset)) + { + LOG("%s: varint32_read offset failed\n", __func__); + return -1; + } + else if (i && store(i, flags, offset)) + { + LOG("%s: store failed\n", __func__); + return -1; + } + + return 0; +} + +int op_i32_store(struct nw_interp *const i) +{ + return op(i, i->f); +} + +int check_i32_store(FILE *const f) +{ + return op(NULL, f); +} diff --git a/src/op/numeric/CMakeLists.txt b/src/op/numeric/CMakeLists.txt new file mode 100644 index 0000000..a259506 --- /dev/null +++ b/src/op/numeric/CMakeLists.txt @@ -0,0 +1,10 @@ +# nanowasm, a tiny WebAssembly/Wasm interpreter +# Copyright (C) 2023-2024 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 + i32_sub.c +) diff --git a/src/op/numeric/i32_sub.c b/src/op/numeric/i32_sub.c new file mode 100644 index 0000000..c3d1352 --- /dev/null +++ b/src/op/numeric/i32_sub.c @@ -0,0 +1,66 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2024 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/log.h> +#include <nw/ops.h> +#include <nanowasm/nw.h> +#include <nw/interp.h> +#include <nw/types.h> +#include <inttypes.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> + +/* Inspired by "INT32-C. Ensure that operations on signed integers do + * not result in overflow". */ +static bool signed_overflow(const int32_t a, const int32_t b) +{ + return (b > 0 && a < INT32_MIN + b) + || (b < 0 && a > INT32_MAX + b); +} + +int op_i32_sub(struct nw_interp *const i) +{ + int32_t op1, op2; + + if (interp_stack_pop(i, &op2, sizeof op2)) + { + LOG("%s: interp_stack_pop %s failed\n", __func__, "op2"); + return -1; + } + else if (interp_stack_pop(i, &op1, sizeof op1)) + { + LOG("%s: interp_stack_pop %s failed\n", __func__, "op1"); + return -1; + } + else if (signed_overflow(op2, op1)) + { + LOG("%s: signed integer overflow (op1=%" PRIi32 ", op2=%" PRIi32 ")\n", + __func__, op1, op2); + i->exception = "signed integer overflow"; + return 1; + } + + const int32_t result = op2 - op1; + + if (interp_stack_push(i, &result, sizeof result)) + { + LOG("%s: interp_stack_push failed\n", __func__); + return -1; + } + + return 0; +} + +int check_i32_sub(FILE *const f) +{ + return 0; +} diff --git a/src/op/variable_access/CMakeLists.txt b/src/op/variable_access/CMakeLists.txt new file mode 100644 index 0000000..314b5bf --- /dev/null +++ b/src/op/variable_access/CMakeLists.txt @@ -0,0 +1,14 @@ +# nanowasm, a tiny WebAssembly/Wasm interpreter +# Copyright (C) 2023-2024 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 + get_global.c + get_local.c + set_global.c + set_local.c + tee_local.c +) diff --git a/src/op/variable_access/get_global.c b/src/op/variable_access/get_global.c new file mode 100644 index 0000000..d38f2d0 --- /dev/null +++ b/src/op/variable_access/get_global.c @@ -0,0 +1,100 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2024 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/log.h> +#include <nw/interp.h> +#include <nw/ops.h> +#include <nanowasm/nw.h> +#include <nw/types.h> +#include <stddef.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> + +static int get_i32(struct nw_interp *const i, const void *const src) +{ + return interp_stack_push(i, src, sizeof (int32_t)); +} + +static int get_i64(struct nw_interp *const i, const void *const src) +{ + return interp_stack_push(i, src, sizeof (int64_t)); +} + +static int get_f32(struct nw_interp *const i, const void *const src) +{ + return interp_stack_push(i, src, sizeof (float)); +} + +static int get_f64(struct nw_interp *const i, const void *const src) +{ + return interp_stack_push(i, src, sizeof (double)); +} + +static int get_global(struct nw_interp *const i, const varuint32 global_index) +{ + struct nw_gframe *gfr; + varuint32 idx; + + for (idx = global_index, gfr = i->gfp; gfr; gfr = gfr->next) + if (idx == global_index) + break; + + if (!gfr) + { + LOG("%s: cannot access global variable %lu\n", __func__, + (unsigned long)global_index); + i->exception = "global variable index out of bounds"; + return -1; + } + + static int (*const get[])(struct nw_interp *, const void *) = + { + [VALUE_TYPE_I32] = get_i32, + [VALUE_TYPE_I64] = get_i64, + [VALUE_TYPE_F32] = get_f32, + [VALUE_TYPE_F64] = get_f64, + }; + + if (get[gfr->type](i, gfr + 1)) + { + LOG("%s: get type %s failed\n", __func__, value_type_tostr(gfr->type)); + return -1; + } + + return 0; +} + +static int op(struct nw_interp *const i, FILE *const f) +{ + varuint32 global_index; + + if (varuint32_read(f, &global_index)) + { + LOG("%s: varuint32_read failed\n", __func__); + return 1; + } + else if (i && get_global(i, global_index)) + { + LOG("%s: get_global failed\n", __func__); + return -1; + } + + return 0; +} + +int op_get_global(struct nw_interp *const i) +{ + return op(i, i->f); +} + +int check_get_global(FILE *const f) +{ + return op(NULL, f); +} diff --git a/src/op/variable_access/get_local.c b/src/op/variable_access/get_local.c new file mode 100644 index 0000000..745a2e7 --- /dev/null +++ b/src/op/variable_access/get_local.c @@ -0,0 +1,112 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2024 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/log.h> +#include <nw/ops.h> +#include <nanowasm/nw.h> +#include <nw/types.h> +#include <nw/interp.h> +#include <stddef.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> + +static int get_i32(struct nw_interp *const i, const void *const data, + const varuint32 idx) +{ + const int32_t *const src = (const int32_t *)data + idx; + + return interp_stack_push(i, src, sizeof (*src)); +} + +static int get_i64(struct nw_interp *const i, const void *const data, + const varuint32 idx) +{ + const int64_t *const src = (const int64_t *)data + idx; + + return interp_stack_push(i, src, sizeof (*src)); +} + +static int get_f32(struct nw_interp *const i, const void *const data, + const varuint32 idx) +{ + const float *const src = (const float *)data + idx; + + return interp_stack_push(i, src, sizeof (*src)); +} + +static int get_f64(struct nw_interp *const i, const void *const data, + const varuint32 idx) +{ + const double *const src = (const double *)data + idx; + + return interp_stack_push(i, src, sizeof (*src)); +} + +static int get_local(const varuint32 local_index, struct nw_interp *const i) +{ + struct nw_frame *fr; + varuint32 idx; + + for (idx = local_index, fr = i->fp; fr; fr = fr->next) + if (idx < fr->n_locals) + break; + + if (!fr) + { + LOG("%s: cannot access local variable %lu\n", __func__, + (unsigned long)local_index); + i->exception = "local variable index out of bounds"; + return -1; + } + + static int (*const get[])(struct nw_interp *, const void *, varuint32) = + { + [VALUE_TYPE_I32] = get_i32, + [VALUE_TYPE_I64] = get_i64, + [VALUE_TYPE_F32] = get_f32, + [VALUE_TYPE_F64] = get_f64, + }; + + if (get[fr->local_type](i, fr + 1, idx)) + { + LOG("%s: get type %d failed\n", __func__, fr->local_type); + return -1; + } + + return 0; +} + +static int op(struct nw_interp *const i, FILE *const f) +{ + varuint32 local_index; + + if (varuint32_read(f, &local_index)) + { + LOG("%s: varuint32_read failed\n", __func__); + return 1; + } + else if (i && get_local(local_index, i)) + { + LOG("%s: get_local failed\n", __func__); + return -1; + } + + return 0; +} + +int op_get_local(struct nw_interp *const i) +{ + return op(i, i->f); +} + +int check_get_local(FILE *const f) +{ + return op(NULL, f); +} diff --git a/src/op/variable_access/set_global.c b/src/op/variable_access/set_global.c new file mode 100644 index 0000000..d1229c5 --- /dev/null +++ b/src/op/variable_access/set_global.c @@ -0,0 +1,38 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2024 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/log.h> +#include <nw/ops.h> +#include <nanowasm/nw.h> +#include <nw/types.h> +#include <stddef.h> +#include <stdio.h> + +static int op(struct nw_interp *const i, FILE *const f) +{ + varuint32 global_index; + + if (varuint32_read(f, &global_index)) + { + LOG("%s: varuint32_read failed\n", __func__); + return 1; + } + + return 0; +} + +int op_set_global(struct nw_interp *const i) +{ + return op(i, i->f); +} + +int check_set_global(FILE *const f) +{ + return op(NULL, f); +} diff --git a/src/op/variable_access/set_local.c b/src/op/variable_access/set_local.c new file mode 100644 index 0000000..8cf6440 --- /dev/null +++ b/src/op/variable_access/set_local.c @@ -0,0 +1,124 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2024 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/log.h> +#include <nw/ops.h> +#include <nanowasm/nw.h> +#include <nw/types.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdio.h> +#include <stdint.h> +#include <string.h> + +static int set_i32(struct nw_interp *const i, void *const data, + const varuint32 idx) +{ + const void *const stackptr = (const char *)i->cfg.stack.buf + i->stack_i; + const int32_t *const src = (const int32_t *)stackptr - 1; + int32_t *const dst = (int32_t *)data + idx; + + *dst = *src; + return 0; +} + +static int set_i64(struct nw_interp *const i, void *const data, + const varuint32 idx) +{ + const void *const stackptr = (const char *)i->cfg.stack.buf + i->stack_i; + const int64_t *const src = (const int64_t *)stackptr - 1; + int64_t *const dst = (int64_t *)data + idx; + + *dst = *src; + return 0; +} + +static int set_f32(struct nw_interp *const i, void *const data, + const varuint32 idx) +{ + const void *const stackptr = (const char *)i->cfg.stack.buf + i->stack_i; + const float *const src = (const float *)stackptr - 1; + float *const dst = (float *)data + idx; + + *dst = *src; + return 0; +} + +static int set_f64(struct nw_interp *const i, void *const data, + const varuint32 idx) +{ + const void *const stackptr = (const char *)i->cfg.stack.buf + i->stack_i; + const double *const src = (const double *)stackptr - 1; + double *const dst = (double *)data + idx; + + *dst = *src; + return 0; +} + +static int set_local(const varuint32 local_index, struct nw_interp *const i) +{ + struct nw_frame *fr; + varuint32 idx; + + for (idx = local_index, fr = i->fp; fr; fr = fr->next) + if (idx < fr->n_locals) + break; + + if (!fr) + { + LOG("%s: cannot access local variable %lu\n", __func__, + (unsigned long)local_index); + i->exception = "local variable index out of bounds"; + return -1; + } + + static int (*const set[])(struct nw_interp *, void *, varuint32) = + { + [VALUE_TYPE_I32] = set_i32, + [VALUE_TYPE_I64] = set_i64, + [VALUE_TYPE_F32] = set_f32, + [VALUE_TYPE_F64] = set_f64, + }; + + if (set[fr->local_type](i, fr + 1, idx)) + { + LOG("%s: set type %d failed\n", __func__, fr->local_type); + return -1; + } + + return 0; +} + +static int op(struct nw_interp *const i, FILE *const f) +{ + varuint32 local_index; + + if (varuint32_read(f, &local_index)) + { + LOG("%s: varuint32_read failed\n", __func__); + return 1; + } + else if (i && set_local(local_index, i)) + { + LOG("%s: set_local failed\n", __func__); + return -1; + } + + return 0; +} + +int op_set_local(struct nw_interp *const i) +{ + return op(i, i->f); +} + +int check_set_local(FILE *const f) +{ + return op(NULL, f); +} diff --git a/src/op/variable_access/tee_local.c b/src/op/variable_access/tee_local.c new file mode 100644 index 0000000..00d7832 --- /dev/null +++ b/src/op/variable_access/tee_local.c @@ -0,0 +1,38 @@ +/* + * nanowasm, a tiny WebAssembly/Wasm interpreter + * Copyright (C) 2023-2024 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/log.h> +#include <nw/ops.h> +#include <nanowasm/nw.h> +#include <nw/types.h> +#include <stddef.h> +#include <stdio.h> + +static int op(struct nw_interp *const i, FILE *const f) +{ + varuint32 local_index; + + if (varuint32_read(f, &local_index)) + { + LOG("%s: varuint32_read failed\n", __func__); + return 1; + } + + return 0; +} + +int op_tee_local(struct nw_interp *const i) +{ + return op(i, i->f); +} + +int check_tee_local(FILE *const f) +{ + return op(NULL, f); +} |
