diff options
| author | Hanjie Wu <hanjiew@andrew.cmu.edu> | 2022-12-08 17:45:55 -0500 |
|---|---|---|
| committer | Hanjie Wu <hanjiew@andrew.cmu.edu> | 2022-12-08 17:45:55 -0500 |
| commit | a054755b62e660d3d8aba42fdb0a992e2d215599 (patch) | |
| tree | 5f2e793527f75240800b31025f4c4c1f58be23ab /weerun_inst.cpp | |
JIT implementation
Diffstat (limited to 'weerun_inst.cpp')
| -rw-r--r-- | weerun_inst.cpp | 978 |
1 files changed, 978 insertions, 0 deletions
diff --git a/weerun_inst.cpp b/weerun_inst.cpp new file mode 100644 index 0000000..f05997b --- /dev/null +++ b/weerun_inst.cpp @@ -0,0 +1,978 @@ +#include <cmath> +#include <iostream> + +#include "weerun.hpp" +#include "weerun_jit.hpp" + +#define INVALID_INST \ + { 0, 0, "illegal", nullptr, nullptr } + +static void run_unreachable(wasm_instance_t* ins, byte opcode); +static void run_nop(wasm_instance_t* ins, byte opcode); +static void run_drop(wasm_instance_t* ins, byte opcode); +static void run_select(wasm_instance_t* ins, byte opcode); +static void run_local_get(wasm_instance_t* ins, byte opcode); +static void run_local_set(wasm_instance_t* ins, byte opcode); +static void run_local_tee(wasm_instance_t* ins, byte opcode); +static void run_global_get(wasm_instance_t* ins, byte opcode); +static void run_global_set(wasm_instance_t* ins, byte opcode); + +#if 0 +static void run_tabel_get(wasm_instance_t* ins, byte opcode); +static void run_tabel_set(wasm_instance_t* ins, byte opcode); +#endif + +static void run_i32_load(wasm_instance_t* ins, byte opcode); +static void run_f64_load(wasm_instance_t* ins, byte opcode); +static void run_i32_load8_u(wasm_instance_t* ins, byte opcode); +static void run_i32_load8_s(wasm_instance_t* ins, byte opcode); +static void run_i32_load16_u(wasm_instance_t* ins, byte opcode); +static void run_i32_load16_s(wasm_instance_t* ins, byte opcode); +static void run_i32_store(wasm_instance_t* ins, byte opcode); +static void run_f64_store(wasm_instance_t* ins, byte opcode); +static void run_i32_store8(wasm_instance_t* ins, byte opcode); +static void run_i32_store16(wasm_instance_t* ins, byte opcode); +static void run_i32_const(wasm_instance_t* ins, byte opcode); +static void run_f64_const(wasm_instance_t* ins, byte opcode); +static void run_i32_numeric(wasm_instance_t* ins, byte opcode); +static void run_f64_compare(wasm_instance_t* ins, byte opcode); +static void run_f64_compute(wasm_instance_t* ins, byte opcode); +static void run_f64_convert(wasm_instance_t* ins, byte opcode); +static void run_call(wasm_instance_t* ins, byte opcode); +static void run_call_indirect(wasm_instance_t* ins, byte opcode); +static void run_return(wasm_instance_t* ins, byte opcode); +static void run_block(wasm_instance_t* ins, byte opcode); +static void run_end(wasm_instance_t* ins, byte opcode); +static void run_br(wasm_instance_t* ins, byte opcode); +static void run_br_table(wasm_instance_t* ins, byte opcode); + +const struct wasm_inst_desc_t g_inst_desc[] = { + {WASM_OP_UNREACHABLE, WASM_INST_TYPE_NOARG, "unreachable", run_unreachable, + &wasm_jit_t::emit_unreachable}, + {WASM_OP_NOP, WASM_INST_TYPE_NOARG, "nop", run_nop, &wasm_jit_t::emit_nop}, + {WASM_OP_BLOCK, WASM_INST_TYPE_BLOCK, "block", run_block, + &wasm_jit_t::emit_block}, + {WASM_OP_LOOP, WASM_INST_TYPE_BLOCK, "loop", run_block, + &wasm_jit_t::emit_block}, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + {WASM_OP_END, WASM_INST_TYPE_NOARG, "end", run_end, &wasm_jit_t::emit_end}, + {WASM_OP_BR, WASM_INST_TYPE_I32, "br", run_br, &wasm_jit_t::emit_br}, + {WASM_OP_BR_IF, WASM_INST_TYPE_I32, "br_if", run_br, + &wasm_jit_t::emit_br_if}, + {WASM_OP_BR_TABLE, WASM_INST_TYPE_BRTABLE, "br_tale", run_br_table, + &wasm_jit_t::emit_br_table}, + {WASM_OP_RETURN, WASM_INST_TYPE_NOARG, "return", run_return, + &wasm_jit_t::emit_return}, + {WASM_OP_CALL, WASM_INST_TYPE_I32, "call", run_call, + &wasm_jit_t::emit_call}, + {WASM_OP_CALL_INDIRECT, WASM_INST_TYPE_I32_I32, "call_indirect", + run_call_indirect, &wasm_jit_t::emit_call_indirect}, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + {WASM_OP_DROP, WASM_INST_TYPE_NOARG, "drop", run_drop, + &wasm_jit_t::emit_drop}, + {WASM_OP_SELECT, WASM_INST_TYPE_NOARG, "select", run_select, + &wasm_jit_t::emit_select}, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + {WASM_OP_LOCAL_GET, WASM_INST_TYPE_I32, "local.get", run_local_get, + &wasm_jit_t::emit_local_get}, + {WASM_OP_LOCAL_SET, WASM_INST_TYPE_I32, "local.set", run_local_set, + &wasm_jit_t::emit_local_set}, + {WASM_OP_LOCAL_TEE, WASM_INST_TYPE_I32, "local.tee", run_local_tee, + &wasm_jit_t::emit_local_tee}, + {WASM_OP_GLOBAL_GET, WASM_INST_TYPE_I32, "global.get", run_global_get, + &wasm_jit_t::emit_global_get}, + {WASM_OP_GLOBAL_SET, WASM_INST_TYPE_I32, "global.set", run_global_set, + &wasm_jit_t::emit_global_set}, + INVALID_INST, + INVALID_INST, + INVALID_INST, + {WASM_OP_I32_LOAD, WASM_INST_TYPE_MEMARG, "i32.load", run_i32_load, + &wasm_jit_t::emit_i32_load}, + INVALID_INST, + INVALID_INST, + {WASM_OP_F64_LOAD, WASM_INST_TYPE_MEMARG, "f64.load", run_f64_load, + &wasm_jit_t::emit_f64_load}, + {WASM_OP_I32_LOAD8_S, WASM_INST_TYPE_MEMARG, "i32.load8_s", run_i32_load8_s, + &wasm_jit_t::emit_i32_load}, + {WASM_OP_I32_LOAD8_U, WASM_INST_TYPE_MEMARG, "i32.load8_u", run_i32_load8_u, + &wasm_jit_t::emit_i32_load}, + {WASM_OP_I32_LOAD16_S, WASM_INST_TYPE_MEMARG, "i32.load16_s", + run_i32_load16_s, &wasm_jit_t::emit_i32_load}, + {WASM_OP_I32_LOAD16_U, WASM_INST_TYPE_MEMARG, "i32.load16_u", + run_i32_load16_u, &wasm_jit_t::emit_i32_load}, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + {WASM_OP_I32_STORE, WASM_INST_TYPE_MEMARG, "i32.store", run_i32_store, + &wasm_jit_t::emit_i32_store}, + INVALID_INST, + INVALID_INST, + {WASM_OP_F64_STORE, WASM_INST_TYPE_MEMARG, "f64.store", run_f64_store, + &wasm_jit_t::emit_f64_store}, + {WASM_OP_I32_STORE8, WASM_INST_TYPE_MEMARG, "i32.store8", run_i32_store8, + &wasm_jit_t::emit_i32_store}, + {WASM_OP_I32_STORE16, WASM_INST_TYPE_MEMARG, "i32.store16", run_i32_store16, + &wasm_jit_t::emit_i32_store}, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + {WASM_OP_I32_CONST, WASM_INST_TYPE_S32, "i32.const", run_i32_const, + &wasm_jit_t::emit_i32_const}, + INVALID_INST, + INVALID_INST, + {WASM_OP_F64_CONST, WASM_INST_TYPE_F64, "f64.const", run_f64_const, + &wasm_jit_t::emit_f64_const}, + {WASM_OP_I32_EQZ, WASM_INST_TYPE_NOARG, "i32.eqz", run_i32_numeric, + &wasm_jit_t::emit_i32_numeric}, + {WASM_OP_I32_EQ, WASM_INST_TYPE_NOARG, "i32.eq", run_i32_numeric, + &wasm_jit_t::emit_i32_numeric}, + {WASM_OP_I32_NE, WASM_INST_TYPE_NOARG, "i32.ne", run_i32_numeric, + &wasm_jit_t::emit_i32_numeric}, + {WASM_OP_I32_LT_S, WASM_INST_TYPE_NOARG, "i32.lt_s", run_i32_numeric, + &wasm_jit_t::emit_i32_numeric}, + {WASM_OP_I32_LT_U, WASM_INST_TYPE_NOARG, "i32.lt_u", run_i32_numeric, + &wasm_jit_t::emit_i32_numeric}, + {WASM_OP_I32_GT_S, WASM_INST_TYPE_NOARG, "i32.gt_s", run_i32_numeric, + &wasm_jit_t::emit_i32_numeric}, + {WASM_OP_I32_GT_U, WASM_INST_TYPE_NOARG, "i32.gt_u", run_i32_numeric, + &wasm_jit_t::emit_i32_numeric}, + {WASM_OP_I32_LE_S, WASM_INST_TYPE_NOARG, "i32.le_s", run_i32_numeric, + &wasm_jit_t::emit_i32_numeric}, + {WASM_OP_I32_LE_U, WASM_INST_TYPE_NOARG, "i32.le_u", run_i32_numeric, + &wasm_jit_t::emit_i32_numeric}, + {WASM_OP_I32_GE_S, WASM_INST_TYPE_NOARG, "i32.ge_s", run_i32_numeric, + &wasm_jit_t::emit_i32_numeric}, + {WASM_OP_I32_GE_U, WASM_INST_TYPE_NOARG, "i32.ge_u", run_i32_numeric, + &wasm_jit_t::emit_i32_numeric}, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + {WASM_OP_F64_EQ, WASM_INST_TYPE_NOARG, "f64.eq", run_f64_compare, + &wasm_jit_t::emit_f64_compute}, + {WASM_OP_F64_NE, WASM_INST_TYPE_NOARG, "f64.ne", run_f64_compare, + &wasm_jit_t::emit_f64_compute}, + {WASM_OP_F64_LT, WASM_INST_TYPE_NOARG, "f64.lt", run_f64_compare, + &wasm_jit_t::emit_f64_compute}, + {WASM_OP_F64_GT, WASM_INST_TYPE_NOARG, "f64.gt", run_f64_compare, + &wasm_jit_t::emit_f64_compute}, + {WASM_OP_F64_LE, WASM_INST_TYPE_NOARG, "f64.le", run_f64_compare, + &wasm_jit_t::emit_f64_compute}, + {WASM_OP_F64_GE, WASM_INST_TYPE_NOARG, "f64.ge", run_f64_compare, + &wasm_jit_t::emit_f64_compute}, + {WASM_OP_I32_CLZ, WASM_INST_TYPE_NOARG, "i32.clz", run_i32_numeric, + &wasm_jit_t::emit_i32_numeric}, + {WASM_OP_I32_CTZ, WASM_INST_TYPE_NOARG, "i32.ctz", run_i32_numeric, + &wasm_jit_t::emit_i32_numeric}, + {WASM_OP_I32_POPCNT, WASM_INST_TYPE_NOARG, "i32.popcnt", run_i32_numeric, + &wasm_jit_t::emit_i32_numeric}, + {WASM_OP_I32_ADD, WASM_INST_TYPE_NOARG, "i32.add", run_i32_numeric, + &wasm_jit_t::emit_i32_numeric}, + {WASM_OP_I32_SUB, WASM_INST_TYPE_NOARG, "i32.sub", run_i32_numeric, + &wasm_jit_t::emit_i32_numeric}, + {WASM_OP_I32_MUL, WASM_INST_TYPE_NOARG, "i32.mul", run_i32_numeric, + &wasm_jit_t::emit_i32_numeric}, + {WASM_OP_I32_DIV_S, WASM_INST_TYPE_NOARG, "i32.div_s", run_i32_numeric, + &wasm_jit_t::emit_i32_numeric}, + {WASM_OP_I32_DIV_U, WASM_INST_TYPE_NOARG, "i32.div_u", run_i32_numeric, + &wasm_jit_t::emit_i32_numeric}, + {WASM_OP_I32_REM_S, WASM_INST_TYPE_NOARG, "i32.rem_s", run_i32_numeric, + &wasm_jit_t::emit_i32_numeric}, + {WASM_OP_I32_REM_U, WASM_INST_TYPE_NOARG, "i32.rem_u", run_i32_numeric, + &wasm_jit_t::emit_i32_numeric}, + {WASM_OP_I32_AND, WASM_INST_TYPE_NOARG, "i32.and", run_i32_numeric, + &wasm_jit_t::emit_i32_numeric}, + {WASM_OP_I32_OR, WASM_INST_TYPE_NOARG, "i32.or", run_i32_numeric, + &wasm_jit_t::emit_i32_numeric}, + {WASM_OP_I32_XOR, WASM_INST_TYPE_NOARG, "i32.xor", run_i32_numeric, + &wasm_jit_t::emit_i32_numeric}, + {WASM_OP_I32_SHL, WASM_INST_TYPE_NOARG, "i32.shl", run_i32_numeric, + &wasm_jit_t::emit_i32_shift}, + {WASM_OP_I32_SHR_S, WASM_INST_TYPE_NOARG, "i32.shr_s", run_i32_numeric, + &wasm_jit_t::emit_i32_shift}, + {WASM_OP_I32_SHR_U, WASM_INST_TYPE_NOARG, "i32.shr_u", run_i32_numeric, + &wasm_jit_t::emit_i32_shift}, + {WASM_OP_I32_ROTL, WASM_INST_TYPE_NOARG, "i32.rotl", run_i32_numeric, + &wasm_jit_t::emit_i32_shift}, + {WASM_OP_I32_ROTR, WASM_INST_TYPE_NOARG, "i32.rotr", run_i32_numeric, + &wasm_jit_t::emit_i32_shift}, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + {WASM_OP_F64_ADD, WASM_INST_TYPE_NOARG, "f64.add", run_f64_compute, + &wasm_jit_t::emit_f64_compute}, + {WASM_OP_F64_SUB, WASM_INST_TYPE_NOARG, "f64.sub", run_f64_compute, + &wasm_jit_t::emit_f64_compute}, + {WASM_OP_F64_MUL, WASM_INST_TYPE_NOARG, "f64.mul", run_f64_compute, + &wasm_jit_t::emit_f64_compute}, + {WASM_OP_F64_DIV, WASM_INST_TYPE_NOARG, "f64.div", run_f64_compute, + &wasm_jit_t::emit_f64_compute}, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + {WASM_OP_I32_TRUNC_F64_S, WASM_INST_TYPE_NOARG, "i32.trunc_f64_s", + run_i32_numeric, &wasm_jit_t::emit_i32_convert}, + {WASM_OP_I32_TRUNC_F64_U, WASM_INST_TYPE_NOARG, "i32.trunc_f64_u", + run_i32_numeric, &wasm_jit_t::emit_i32_convert}, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + {WASM_OP_F64_CONVERT_I32_S, WASM_INST_TYPE_NOARG, "f64.convert_i32_s", + run_f64_convert, &wasm_jit_t::emit_f64_compute}, + {WASM_OP_F64_CONVERT_I32_U, WASM_INST_TYPE_NOARG, "f64.convert_i32_u", + run_f64_convert, &wasm_jit_t::emit_f64_compute}, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + INVALID_INST, + {WASM_OP_I32_EXTEND8_S, WASM_INST_TYPE_NOARG, "i32.extend8_s", + run_i32_numeric, &wasm_jit_t::emit_i32_numeric}, + {WASM_OP_I32_EXTEND16_S, WASM_INST_TYPE_NOARG, "i32.extend16_s", + run_i32_numeric, &wasm_jit_t::emit_i32_numeric}, +}; + +static bool is_zero(wasm_value_t v, uint8_t type) { + switch (type) { + case WASM_TYPE_I32: + return v.val.i32 == 0; + case WASM_TYPE_F64: + return v.val.f64 == 0; + default: + break; + } + return v.val.ref == nullptr; +} + +// fancy ops +static inline uint32_t i32_clz(uint32_t x) { + uint32_t zeros = 0; + for (int i = 31; i >= 0; i--) { + if ((x & (1 << i)) == 0) { + zeros++; + } else { + break; + } + } + return zeros; +} + +static inline uint32_t i32_ctz(uint32_t x) { + uint32_t zeros = 0; + for (int i = 0; i < 32; i++) { + if ((x & (1 << i)) == 0) { + zeros++; + } else { + break; + } + } + return zeros; +} + +static inline uint32_t i32_popcnt(uint32_t x) { + uint32_t ones = 0; + for (int i = 31; i >= 0; i--) { + if ((x & (1 << i)) != 0) { + ones++; + } + } + return ones; +} + +static inline uint32_t i32_rotl(uint32_t x, uint32_t n) { + return (x << n) | (x >> (32 - n)); +} + +static inline uint32_t i32_rotr(uint32_t x, uint32_t n) { + return (x >> n) | (x << (32 - n)); +} + +static inline std::pair<bool, int32_t> i32_div_s(int32_t a, int32_t b) { + if (b == 0) { + return {false, 0}; + } + if (a == (int32_t)0x80000000 && b == (int32_t)0xffffffff) { + return {false, 0}; + } + return {true, a / b}; +} + +static inline std::pair<bool, int32_t> i32_rem_s(int32_t a, int32_t b) { + if (b == 0) { + return {false, 0}; + } + if (a == (int32_t)0x80000000 && b == (int32_t)0xffffffff) { + return {true, 0}; + } + return {true, a % b}; +} + +static inline std::pair<bool, uint32_t> i32_div_u(uint32_t a, uint32_t b) { + if (b == 0) { + return {false, 0}; + } + return {true, a / b}; +} + +static inline std::pair<bool, uint32_t> i32_rem_u(uint32_t a, uint32_t b) { + if (b == 0) { + return {false, 0}; + } + return {true, a % b}; +} + +static inline std::pair<bool, int32_t> i32_trunc_f64_s(double x) { + int type = std::fpclassify(x); + if (type == FP_NAN || type == FP_INFINITE) { + return {false, 0}; + } + if (x <= -2147483649.0 || x >= 2147483648.0) { + return {false, 0}; + } + return {true, x}; +} + +static inline std::pair<bool, uint32_t> i32_trunc_f64_u(double x) { + int type = std::fpclassify(x); + if (type == FP_NAN || type == FP_INFINITE) { + return {false, 0}; + } + if (x <= -1.0 || x >= 4294967296.0) { + return {false, 0}; + } + return {true, x}; +} + +template <typename T> +static inline bool check_access(wasm_instance_t* ins, + uint32_t offset, + uint32_t addend) { + uint32_t size = ins->memory_.size(); + return offset <= size && addend <= size && + offset + addend + sizeof(T) <= size; +} + +static void run_unreachable(wasm_instance_t* ins, byte opcode) { + ins->trap(WASM_OP_UNREACHABLE); +} + +static void run_nop(wasm_instance_t* ins, byte opcode) {} + +static void run_drop(wasm_instance_t* ins, byte opcode) { + ins->pop_value(); +} + +static void run_select(wasm_instance_t* ins, byte opcode) { + wasm_value_t c = ins->pop_value(); + wasm_value_t b = ins->pop_value(); + wasm_value_t a = ins->pop_value(); + if (is_zero(c, WASM_TYPE_I32) == false) { + ins->push_value(a); + } else { + ins->push_value(b); + } +} + +static void run_local_get(wasm_instance_t* ins, byte opcode) { + uint32_t idx = ins->read_u32leb(); + ins->push_value(ins->cur_frame_->locals_[idx]); +} + +static void run_local_set(wasm_instance_t* ins, byte opcode) { + uint32_t idx = ins->read_u32leb(); + ins->cur_frame_->locals_[idx] = ins->pop_value(); +} + +static void run_local_tee(wasm_instance_t* ins, byte opcode) { + uint32_t idx = ins->read_u32leb(); + wasm_value_t v = ins->value_stack_.back(); + ins->cur_frame_->locals_[idx] = v; +} + +static void run_global_get(wasm_instance_t* ins, byte opcode) { + uint32_t idx = ins->read_u32leb(); + ins->push_value(ins->globals_[idx]); +} + +static void run_global_set(wasm_instance_t* ins, byte opcode) { + uint32_t idx = ins->read_u32leb(); + ins->globals_[idx] = ins->pop_value(); +} + +#if 0 +static void run_tabel_get(wasm_instance_t* ins, byte opcode) { + uint32_t idx = ins->read_u32leb(); + wasm_value_t v; + v.val.ref = (void*)ins->table_[idx]; + ins->push_value(v); +} + +static void run_tabel_set(wasm_instance_t* ins, byte opcode) { + uint32_t idx = ins->read_u32leb(); + ins->table_[idx] = (wasm_func_t*)ins->pop_value().val.ref; +} +#endif + +static void run_i32_load(wasm_instance_t* ins, byte opcode) { + uint32_t addend = ins->pop_value().val.i32; + ins->read_u32leb(); + uint32_t offset = ins->read_u32leb(); + if (check_access<uint32_t>(ins, offset, addend) == false) { + ins->trap(WASM_TRAP_REASON_OOB); + return; + } + byte* base = ins->memory_.data(); + wasm_value_t v; + v.val.i32 = *(uint32_t*)(base + (offset + addend)); + ins->push_value(v); +} + +static void run_f64_load(wasm_instance_t* ins, byte opcode) { + uint32_t addend = ins->pop_value().val.i32; + ins->read_u32leb(); + uint32_t offset = ins->read_u32leb(); + if (check_access<double>(ins, offset, addend) == false) { + ins->trap(WASM_TRAP_REASON_OOB); + return; + } + byte* base = ins->memory_.data(); + wasm_value_t v; + v.val.f64 = *(double*)(base + (offset + addend)); + ins->push_value(v); +} + +static void run_i32_load8_u(wasm_instance_t* ins, byte opcode) { + uint32_t addend = ins->pop_value().val.i32; + ins->read_u32leb(); + uint32_t offset = ins->read_u32leb(); + if (check_access<uint8_t>(ins, offset, addend) == false) { + ins->trap(WASM_TRAP_REASON_OOB); + return; + } + byte* base = ins->memory_.data(); + uint8_t u8 = *(uint8_t*)(base + (offset + addend)); + wasm_value_t v; + v.val.i32 = (uint32_t)u8; + ins->push_value(v); +} + +static void run_i32_load8_s(wasm_instance_t* ins, byte opcode) { + uint32_t addend = ins->pop_value().val.i32; + ins->read_u32leb(); + uint32_t offset = ins->read_u32leb(); + if (check_access<int8_t>(ins, offset, addend) == false) { + ins->trap(WASM_TRAP_REASON_OOB); + return; + } + byte* base = ins->memory_.data(); + int8_t i8 = *(int8_t*)(base + (offset + addend)); + wasm_value_t v; + v.val.i32 = (uint32_t)(int32_t)i8; + ins->push_value(v); +} + +static void run_i32_load16_u(wasm_instance_t* ins, byte opcode) { + uint32_t addend = ins->pop_value().val.i32; + ins->read_u32leb(); + uint32_t offset = ins->read_u32leb(); + if (check_access<uint16_t>(ins, offset, addend) == false) { + ins->trap(WASM_TRAP_REASON_OOB); + return; + } + byte* base = ins->memory_.data(); + uint16_t u16 = *(uint16_t*)(base + (offset + addend)); + wasm_value_t v; + v.val.i32 = (uint32_t)u16; + ins->push_value(v); +} + +static void run_i32_load16_s(wasm_instance_t* ins, byte opcode) { + uint32_t addend = ins->pop_value().val.i32; + ins->read_u32leb(); + uint32_t offset = ins->read_u32leb(); + if (check_access<int16_t>(ins, offset, addend) == false) { + ins->trap(WASM_TRAP_REASON_OOB); + return; + } + byte* base = ins->memory_.data(); + int16_t i16 = *(int16_t*)(base + (offset + addend)); + wasm_value_t v; + v.val.i32 = (uint32_t)(int32_t)i16; + ins->push_value(v); +} + +static void run_i32_store(wasm_instance_t* ins, byte opcode) { + wasm_value_t v = ins->pop_value(); + uint32_t addend = ins->pop_value().val.i32; + ins->read_u32leb(); + uint32_t offset = ins->read_u32leb(); + if (check_access<uint32_t>(ins, offset, addend) == false) { + ins->trap(WASM_TRAP_REASON_OOB); + return; + } + byte* base = ins->memory_.data(); + *(uint32_t*)(base + (offset + addend)) = v.val.i32; +} + +static void run_f64_store(wasm_instance_t* ins, byte opcode) { + wasm_value_t v = ins->pop_value(); + uint32_t addend = ins->pop_value().val.i32; + ins->read_u32leb(); + uint32_t offset = ins->read_u32leb(); + if (check_access<double>(ins, offset, addend) == false) { + ins->trap(WASM_TRAP_REASON_OOB); + return; + } + byte* base = ins->memory_.data(); + *(double*)(base + (offset + addend)) = v.val.f64; +} + +static void run_i32_store8(wasm_instance_t* ins, byte opcode) { + wasm_value_t v = ins->pop_value(); + uint32_t addend = ins->pop_value().val.i32; + ins->read_u32leb(); + uint32_t offset = ins->read_u32leb(); + if (check_access<uint8_t>(ins, offset, addend) == false) { + ins->trap(WASM_TRAP_REASON_OOB); + return; + } + byte* base = ins->memory_.data(); + *(uint8_t*)(base + (offset + addend)) = (uint8_t)v.val.i32; +} + +static void run_i32_store16(wasm_instance_t* ins, byte opcode) { + wasm_value_t v = ins->pop_value(); + uint32_t addend = ins->pop_value().val.i32; + ins->read_u32leb(); + uint32_t offset = ins->read_u32leb(); + if (check_access<uint16_t>(ins, offset, addend) == false) { + ins->trap(WASM_TRAP_REASON_OOB); + return; + } + byte* base = ins->memory_.data(); + *(uint16_t*)(base + (offset + addend)) = (uint16_t)v.val.i32; +} + +static void run_i32_const(wasm_instance_t* ins, byte opcode) { + uint32_t x = ins->read_i32leb(); + wasm_value_t v; + v.val.i32 = x; + ins->push_value(v); +} + +static void run_f64_const(wasm_instance_t* ins, byte opcode) { + double x = ins->read_double(); + wasm_value_t v; + v.val.f64 = x; + ins->push_value(v); +} + +static void run_i32_numeric(wasm_instance_t* ins, byte opcode) { + wasm_value_t a; + wasm_value_t b; + wasm_value_t result; + + b = ins->pop_value(); + switch (opcode) { + case WASM_OP_I32_EQZ: + result.val.i32 = (b.val.i32 == 0); + break; + case WASM_OP_I32_EQ: + a = ins->pop_value(); + result.val.i32 = (a.val.i32 == b.val.i32); + break; + case WASM_OP_I32_NE: + a = ins->pop_value(); + result.val.i32 = (a.val.i32 != b.val.i32); + break; + case WASM_OP_I32_LT_S: + a = ins->pop_value(); + result.val.i32 = ((int32_t)a.val.i32 < (int32_t)b.val.i32); + break; + case WASM_OP_I32_LT_U: + a = ins->pop_value(); + result.val.i32 = (a.val.i32 < b.val.i32); + break; + case WASM_OP_I32_GT_S: + a = ins->pop_value(); + result.val.i32 = ((int32_t)a.val.i32 > (int32_t)b.val.i32); + break; + case WASM_OP_I32_GT_U: + a = ins->pop_value(); + result.val.i32 = (a.val.i32 > b.val.i32); + break; + case WASM_OP_I32_LE_S: + a = ins->pop_value(); + result.val.i32 = ((int32_t)a.val.i32 <= (int32_t)b.val.i32); + break; + case WASM_OP_I32_LE_U: + a = ins->pop_value(); + result.val.i32 = (a.val.i32 <= b.val.i32); + break; + case WASM_OP_I32_GE_S: + a = ins->pop_value(); + result.val.i32 = ((int32_t)a.val.i32 >= (int32_t)b.val.i32); + break; + case WASM_OP_I32_GE_U: + a = ins->pop_value(); + result.val.i32 = (a.val.i32 >= b.val.i32); + break; + case WASM_OP_I32_CLZ: + result.val.i32 = i32_clz(b.val.i32); + break; + case WASM_OP_I32_CTZ: + result.val.i32 = i32_ctz(b.val.i32); + break; + case WASM_OP_I32_POPCNT: + result.val.i32 = i32_popcnt(b.val.i32); + break; + case WASM_OP_I32_ADD: + a = ins->pop_value(); + result.val.i32 = (a.val.i32 + b.val.i32); + break; + case WASM_OP_I32_SUB: + a = ins->pop_value(); + result.val.i32 = (a.val.i32 - b.val.i32); + break; + case WASM_OP_I32_MUL: + a = ins->pop_value(); + result.val.i32 = (a.val.i32 * b.val.i32); + break; + case WASM_OP_I32_DIV_S: { + a = ins->pop_value(); + auto r = i32_div_s((int32_t)a.val.i32, (int32_t)b.val.i32); + if (r.first == false) { + ins->trap(WASM_TRAP_REASON_SIGFPE); + return; + } + result.val.i32 = r.second; + break; + } + case WASM_OP_I32_DIV_U: { + a = ins->pop_value(); + auto r = i32_div_u((int32_t)a.val.i32, (int32_t)b.val.i32); + if (r.first == false) { + ins->trap(WASM_TRAP_REASON_SIGFPE); + return; + } + result.val.i32 = r.second; + break; + } + case WASM_OP_I32_REM_S: { + a = ins->pop_value(); + auto r = i32_rem_s((int32_t)a.val.i32, (int32_t)b.val.i32); + if (r.first == false) { + ins->trap(WASM_TRAP_REASON_SIGFPE); + return; + } + result.val.i32 = r.second; + break; + } + case WASM_OP_I32_REM_U: { + a = ins->pop_value(); + auto r = i32_rem_u((int32_t)a.val.i32, (int32_t)b.val.i32); + if (r.first == false) { + ins->trap(WASM_TRAP_REASON_SIGFPE); + return; + } + result.val.i32 = r.second; + break; + } + case WASM_OP_I32_AND: + a = ins->pop_value(); + result.val.i32 = (a.val.i32 & b.val.i32); + break; + case WASM_OP_I32_OR: + a = ins->pop_value(); + result.val.i32 = (a.val.i32 | b.val.i32); + break; + case WASM_OP_I32_XOR: + a = ins->pop_value(); + result.val.i32 = (a.val.i32 ^ b.val.i32); + break; + case WASM_OP_I32_SHL: + a = ins->pop_value(); + result.val.i32 = (a.val.i32 << b.val.i32); + break; + case WASM_OP_I32_SHR_S: + a = ins->pop_value(); + result.val.i32 = ((int32_t)a.val.i32 >> b.val.i32); + break; + case WASM_OP_I32_SHR_U: + a = ins->pop_value(); + result.val.i32 = (a.val.i32 >> b.val.i32); + break; + case WASM_OP_I32_ROTL: + a = ins->pop_value(); + result.val.i32 = i32_rotl(a.val.i32, b.val.i32); + break; + case WASM_OP_I32_ROTR: + a = ins->pop_value(); + result.val.i32 = i32_rotr(a.val.i32, b.val.i32); + break; + case WASM_OP_I32_TRUNC_F64_S: { + auto r = i32_trunc_f64_s(b.val.f64); + if (r.first == false) { + ins->trap(WASM_TRAP_REASON_SIGFPE); + return; + } + result.val.i32 = r.second; + break; + } + case WASM_OP_I32_TRUNC_F64_U: { + auto r = i32_trunc_f64_u(b.val.f64); + if (r.first == false) { + ins->trap(WASM_TRAP_REASON_SIGFPE); + return; + } + result.val.i32 = r.second; + break; + } + case WASM_OP_I32_EXTEND8_S: + result.val.i32 = (int32_t)(int8_t)b.val.i32; + break; + case WASM_OP_I32_EXTEND16_S: + result.val.i32 = (int32_t)(int16_t)b.val.i32; + break; + } + ins->push_value(result); +} + +static void run_f64_compare(wasm_instance_t* ins, byte opcode) { + wasm_value_t a; + wasm_value_t b; + wasm_value_t result; + + b = ins->pop_value(); + a = ins->pop_value(); + switch (opcode) { + case WASM_OP_F64_LT: + result.val.i32 = (a.val.f64 < b.val.f64); + break; + case WASM_OP_F64_GT: + result.val.i32 = (a.val.f64 > b.val.f64); + break; + case WASM_OP_F64_LE: + result.val.i32 = (a.val.f64 <= b.val.f64); + break; + case WASM_OP_F64_GE: + result.val.i32 = (a.val.f64 >= b.val.f64); + break; + case WASM_OP_F64_EQ: + result.val.i32 = (a.val.f64 == b.val.f64); + break; + case WASM_OP_F64_NE: + result.val.i32 = (a.val.f64 != b.val.f64); + break; + } + ins->push_value(result); +} + +static void run_f64_compute(wasm_instance_t* ins, byte opcode) { + wasm_value_t a; + wasm_value_t b; + wasm_value_t result; + + b = ins->pop_value(); + a = ins->pop_value(); + switch (opcode) { + case WASM_OP_F64_ADD: + result.val.f64 = (a.val.f64 + b.val.f64); + break; + case WASM_OP_F64_SUB: + result.val.f64 = (a.val.f64 - b.val.f64); + break; + case WASM_OP_F64_MUL: + result.val.f64 = (a.val.f64 * b.val.f64); + break; + case WASM_OP_F64_DIV: + result.val.f64 = (a.val.f64 / b.val.f64); + break; + } + ins->push_value(result); +} + +static void run_f64_convert(wasm_instance_t* ins, byte opcode) { + wasm_value_t b; + wasm_value_t result; + + b = ins->pop_value(); + switch (opcode) { + case WASM_OP_F64_CONVERT_I32_S: + result.val.f64 = (int32_t)b.val.i32; + break; + case WASM_OP_F64_CONVERT_I32_U: + result.val.f64 = b.val.i32; + break; + } + ins->push_value(result); +} + +static void run_call(wasm_instance_t* ins, byte opcode) { + uint32_t funcidx = ins->read_u32leb(); + ins->push_frame(&ins->module_->funcs_[funcidx]); +} + +bool is_same_type(wasm_func_decl_t* s, wasm_func_decl_t* t) { + if (s->args_.size() != t->args_.size()) { + return false; + } + if (memcmp(s->args_.data(), t->args_.data(), s->args_.size()) != 0) { + return false; + } + if (s->ret_.size() != t->ret_.size()) { + return false; + } + if (memcmp(s->ret_.data(), t->ret_.data(), s->ret_.size()) != 0) { + return false; + } + return true; +} + +static void run_call_indirect(wasm_instance_t* ins, byte opcode) { + ins->read_u32leb(); + uint32_t typeidx = ins->read_u32leb(); + wasm_value_t v = ins->pop_value(); + if (v.val.i32 >= ins->table_.size() || + typeidx >= ins->module_->sigs_.size()) { + ins->trap(WASM_TRAP_REASON_OOB); + return; + } + wasm_func_t* f = ins->table_[v.val.i32]; + if (f == nullptr) { + ins->trap(WASM_TRAP_REASON_NULLFUNCREF); + return; + } + if (is_same_type(&ins->module_->sigs_[typeidx], f->sig_) == false) { + ins->trap(WASM_TRAP_REASON_TYPEERR); + return; + } + ins->push_frame(ins->table_[v.val.i32]); +} + +static void run_return(wasm_instance_t* ins, byte opcode) { + ins->pop_frame(); + if (ins->frames_.empty()) { + ins->trap(WASM_TRAP_REASON_FUNCEND); + } +} + +static void run_block(wasm_instance_t* ins, byte opcode) { + // read the blocktype byte and go + ins->read_byte(); +} + +static void run_end(wasm_instance_t* ins, byte opcode) { + // only the OP_END for the outermost function matters + if (ins->cur_frame_->pc_.ptr == ins->cur_frame_->pc_.end) { + ins->pop_frame(); + if (ins->frames_.empty()) { + ins->trap(WASM_TRAP_REASON_FUNCEND); + } + } +} + +static void run_br(wasm_instance_t* ins, byte opcode) { + if (opcode == WASM_OP_BR_IF) { + wasm_value_t v = ins->pop_value(); + if (is_zero(v, WASM_TYPE_I32) == true) { + ins->cur_frame_->pc_.ptr += sizeof(uint32_t); + return; + } + } + uint32_t to_off = *(uint32_t*)(ins->cur_frame_->pc_.ptr); + ins->branch(to_off); +} + +static void run_br_table(wasm_instance_t* ins, byte opcode) { + uint32_t num_cases = ins->read_u32leb(); + uint32_t* cases = (uint32_t*)(ins->cur_frame_->pc_.ptr); + wasm_value_t v = ins->pop_value(); + uint32_t to_off; + uint32_t index = std::min(v.val.i32, num_cases); + to_off = cases[index]; + ins->branch(to_off); +} |
