/* * Copyright (C) 2019 Intel Corporation. All rights reserved. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception */ #include "jit_emit_table.h" #include "jit_emit_exception.h" #include "jit_emit_function.h" #include "../../interpreter/wasm_runtime.h" #include "../jit_frontend.h" #if WASM_ENABLE_REF_TYPES != 0 static void wasm_elem_drop(WASMModuleInstance *inst, uint32 tbl_seg_idx) { bh_bitmap_set_bit(inst->e->common.elem_dropped, tbl_seg_idx); } bool jit_compile_op_elem_drop(JitCompContext *cc, uint32 tbl_seg_idx) { JitReg args[2] = { 0 }; args[0] = get_module_inst_reg(cc->jit_frame); args[1] = NEW_CONST(I32, tbl_seg_idx); return jit_emit_callnative(cc, wasm_elem_drop, 0, args, sizeof(args) / sizeof(args[0])); } bool jit_compile_op_table_get(JitCompContext *cc, uint32 tbl_idx) { JitReg elem_idx, tbl_sz, tbl_elems, elem_idx_long, offset, res; POP_I32(elem_idx); /* if (elem_idx >= tbl_sz) goto exception; */ tbl_sz = get_table_cur_size_reg(cc->jit_frame, tbl_idx); GEN_INSN(CMP, cc->cmp_reg, elem_idx, tbl_sz); if (!jit_emit_exception(cc, EXCE_OUT_OF_BOUNDS_TABLE_ACCESS, JIT_OP_BGEU, cc->cmp_reg, NULL)) goto fail; elem_idx_long = jit_cc_new_reg_I64(cc); GEN_INSN(I32TOI64, elem_idx_long, elem_idx); offset = jit_cc_new_reg_I64(cc); GEN_INSN(MUL, offset, elem_idx_long, NEW_CONST(I64, sizeof(table_elem_type_t))); res = jit_cc_new_reg_I32(cc); tbl_elems = get_table_elems_reg(cc->jit_frame, tbl_idx); GEN_INSN(LDI32, res, tbl_elems, offset); PUSH_I32(res); return true; fail: return false; } bool jit_compile_op_table_set(JitCompContext *cc, uint32 tbl_idx) { JitReg elem_idx, elem_val, tbl_sz, tbl_elems, elem_idx_long, offset; POP_I32(elem_val); POP_I32(elem_idx); /* if (elem_idx >= tbl_sz) goto exception; */ tbl_sz = get_table_cur_size_reg(cc->jit_frame, tbl_idx); GEN_INSN(CMP, cc->cmp_reg, elem_idx, tbl_sz); if (!jit_emit_exception(cc, EXCE_OUT_OF_BOUNDS_TABLE_ACCESS, JIT_OP_BGEU, cc->cmp_reg, NULL)) goto fail; elem_idx_long = jit_cc_new_reg_I64(cc); GEN_INSN(I32TOI64, elem_idx_long, elem_idx); offset = jit_cc_new_reg_I64(cc); GEN_INSN(MUL, offset, elem_idx_long, NEW_CONST(I64, sizeof(table_elem_type_t))); tbl_elems = get_table_elems_reg(cc->jit_frame, tbl_idx); GEN_INSN(STI32, elem_val, tbl_elems, offset); return true; fail: return false; } static int wasm_init_table(WASMModuleInstance *inst, uint32 tbl_idx, uint32 seg_idx, uint32 dst_offset, uint32 len, uint32 src_offset) { WASMTableInstance *tbl; WASMTableSeg *tbl_seg = inst->module->table_segments + seg_idx; InitializerExpression *tbl_seg_init_values = NULL, *init_values; uint32 tbl_sz, tbl_seg_len = 0, i; table_elem_type_t *addr; if (!bh_bitmap_get_bit(inst->e->common.elem_dropped, seg_idx)) { /* table segment isn't dropped */ tbl_seg_init_values = tbl_seg->init_values; tbl_seg_len = tbl_seg->value_count; } if (offset_len_out_of_bounds(src_offset, len, tbl_seg_len)) goto out_of_bounds; tbl = inst->tables[tbl_idx]; tbl_sz = tbl->cur_size; if (offset_len_out_of_bounds(dst_offset, len, tbl_sz)) goto out_of_bounds; if (!len) return 0; addr = (table_elem_type_t *)((uint8 *)tbl + offsetof(WASMTableInstance, elems) + dst_offset * sizeof(table_elem_type_t)); init_values = tbl_seg_init_values + src_offset; for (i = 0; i < len; i++) { addr[i] = (table_elem_type_t)(uintptr_t)init_values[+i].u.ref_index; } return 0; out_of_bounds: wasm_set_exception(inst, "out of bounds table access"); return -1; } bool jit_compile_op_table_init(JitCompContext *cc, uint32 tbl_idx, uint32 tbl_seg_idx) { JitReg len, src, dst, res; JitReg args[6] = { 0 }; POP_I32(len); POP_I32(src); POP_I32(dst); res = jit_cc_new_reg_I32(cc); args[0] = get_module_inst_reg(cc->jit_frame); args[1] = NEW_CONST(I32, tbl_idx); args[2] = NEW_CONST(I32, tbl_seg_idx); args[3] = dst; args[4] = len; args[5] = src; if (!jit_emit_callnative(cc, wasm_init_table, res, args, sizeof(args) / sizeof(args[0]))) goto fail; GEN_INSN(CMP, cc->cmp_reg, res, NEW_CONST(I32, 0)); if (!jit_emit_exception(cc, EXCE_ALREADY_THROWN, JIT_OP_BLTS, cc->cmp_reg, NULL)) goto fail; return true; fail: return false; } static int wasm_copy_table(WASMModuleInstance *inst, uint32 src_tbl_idx, uint32 dst_tbl_idx, uint32 dst_offset, uint32 len, uint32 src_offset) { WASMTableInstance *src_tbl, *dst_tbl; uint32 src_tbl_sz, dst_tbl_sz; dst_tbl = inst->tables[dst_tbl_idx]; dst_tbl_sz = dst_tbl->cur_size; if (offset_len_out_of_bounds(dst_offset, len, dst_tbl_sz)) goto out_of_bounds; src_tbl = inst->tables[src_tbl_idx]; src_tbl_sz = src_tbl->cur_size; if (offset_len_out_of_bounds(src_offset, len, src_tbl_sz)) goto out_of_bounds; bh_memmove_s( (uint8 *)dst_tbl + offsetof(WASMTableInstance, elems) + dst_offset * sizeof(table_elem_type_t), (uint32)((dst_tbl_sz - dst_offset) * sizeof(table_elem_type_t)), (uint8 *)src_tbl + offsetof(WASMTableInstance, elems) + src_offset * sizeof(table_elem_type_t), (uint32)(len * sizeof(table_elem_type_t))); return 0; out_of_bounds: wasm_set_exception(inst, "out of bounds table access"); return -1; } bool jit_compile_op_table_copy(JitCompContext *cc, uint32 src_tbl_idx, uint32 dst_tbl_idx) { JitReg len, src, dst, res; JitReg args[6] = { 0 }; POP_I32(len); POP_I32(src); POP_I32(dst); res = jit_cc_new_reg_I32(cc); args[0] = get_module_inst_reg(cc->jit_frame); args[1] = NEW_CONST(I32, src_tbl_idx); args[2] = NEW_CONST(I32, dst_tbl_idx); args[3] = dst; args[4] = len; args[5] = src; if (!jit_emit_callnative(cc, wasm_copy_table, res, args, sizeof(args) / sizeof(args[0]))) goto fail; GEN_INSN(CMP, cc->cmp_reg, res, NEW_CONST(I32, 0)); if (!jit_emit_exception(cc, EXCE_ALREADY_THROWN, JIT_OP_BLTS, cc->cmp_reg, NULL)) goto fail; return true; fail: return false; } bool jit_compile_op_table_size(JitCompContext *cc, uint32 tbl_idx) { JitReg res; res = get_table_cur_size_reg(cc->jit_frame, tbl_idx); PUSH_I32(res); return true; fail: return false; } bool jit_compile_op_table_grow(JitCompContext *cc, uint32 tbl_idx) { JitReg tbl_sz, n, val, enlarge_ret, res; JitReg args[4] = { 0 }; POP_I32(n); POP_I32(val); tbl_sz = get_table_cur_size_reg(cc->jit_frame, tbl_idx); enlarge_ret = jit_cc_new_reg_I32(cc); args[0] = get_module_inst_reg(cc->jit_frame); args[1] = NEW_CONST(I32, tbl_idx); args[2] = n; args[3] = val; if (!jit_emit_callnative(cc, wasm_enlarge_table, enlarge_ret, args, sizeof(args) / sizeof(args[0]))) goto fail; /* Convert bool to uint32 */ GEN_INSN(AND, enlarge_ret, enlarge_ret, NEW_CONST(I32, 0xFF)); res = jit_cc_new_reg_I32(cc); GEN_INSN(CMP, cc->cmp_reg, enlarge_ret, NEW_CONST(I32, 1)); GEN_INSN(SELECTEQ, res, cc->cmp_reg, tbl_sz, NEW_CONST(I32, -1)); PUSH_I32(res); /* Ensure a refresh in next get memory related registers */ clear_table_regs(cc->jit_frame); return true; fail: return false; } static int wasm_fill_table(WASMModuleInstance *inst, uint32 tbl_idx, uint32 dst_offset, uintptr_t val, uint32 len) { WASMTableInstance *tbl; uint32 tbl_sz; tbl = inst->tables[tbl_idx]; tbl_sz = tbl->cur_size; if (offset_len_out_of_bounds(dst_offset, len, tbl_sz)) goto out_of_bounds; for (; len != 0; dst_offset++, len--) { tbl->elems[dst_offset] = val; } return 0; out_of_bounds: wasm_set_exception(inst, "out of bounds table access"); return -1; } bool jit_compile_op_table_fill(JitCompContext *cc, uint32 tbl_idx) { JitReg len, val, dst, res; JitReg args[5] = { 0 }; POP_I32(len); POP_I32(val); POP_I32(dst); res = jit_cc_new_reg_I32(cc); args[0] = get_module_inst_reg(cc->jit_frame); args[1] = NEW_CONST(I32, tbl_idx); args[2] = dst; args[3] = val; args[4] = len; if (!jit_emit_callnative(cc, wasm_fill_table, res, args, sizeof(args) / sizeof(args[0]))) goto fail; GEN_INSN(CMP, cc->cmp_reg, res, NEW_CONST(I32, 0)); if (!jit_emit_exception(cc, EXCE_ALREADY_THROWN, JIT_OP_BLTS, cc->cmp_reg, NULL)) goto fail; return true; fail: return false; } #endif