wasm-micro-runtime/core/iwasm/compilation/aot_emit_table.c
Wenyong Huang a182926a73
Refactor interpreter/AOT module instance layout (#1559)
Refactor the layout of interpreter and AOT module instance:
- Unify the interp/AOT module instance, use the same WASMModuleInstance/
  WASMMemoryInstance/WASMTableInstance data structures for both interpreter
  and AOT
- Make the offset of most fields the same in module instance for both interpreter
  and AOT, append memory instance structure, global data and table instances to
  the end of module instance for interpreter mode (like AOT mode)
- For extra fields in WASM module instance, use WASMModuleInstanceExtra to
  create a field `e` for interpreter
- Change the LLVM JIT module instance creating process, LLVM JIT uses the WASM
  module and module instance same as interpreter/Fast-JIT mode. So that Fast JIT
  and LLVM JIT can access the same data structures, and make it possible to
  implement the Multi-tier JIT (tier-up from Fast JIT to LLVM JIT) in the future
- Unify some APIs: merge some APIs for module instance and memory instance's
  related operations (only implement one copy)

Note that the AOT ABI is same, the AOT file format, AOT relocation types, how AOT
code accesses the AOT module instance and so on are kept unchanged.

Refer to:
https://github.com/bytecodealliance/wasm-micro-runtime/issues/1384
2022-10-18 10:59:28 +08:00

512 lines
14 KiB
C

/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "aot_emit_table.h"
#include "aot_emit_exception.h"
#include "../aot/aot_runtime.h"
uint64
get_tbl_inst_offset(const AOTCompContext *comp_ctx,
const AOTFuncContext *func_ctx, uint32 tbl_idx)
{
uint64 offset = 0, i = 0;
AOTImportTable *imp_tbls = comp_ctx->comp_data->import_tables;
AOTTable *tbls = comp_ctx->comp_data->tables;
if (comp_ctx->is_jit_mode) {
offset = offsetof(WASMModuleInstance, global_table_data.bytes)
+ (uint64)comp_ctx->comp_data->memory_count
* sizeof(AOTMemoryInstance)
+ comp_ctx->comp_data->global_data_size;
}
else {
offset = offsetof(AOTModuleInstance, global_table_data.bytes)
+ (uint64)comp_ctx->comp_data->memory_count
* sizeof(AOTMemoryInstance)
+ comp_ctx->comp_data->global_data_size;
}
while (i < tbl_idx && i < comp_ctx->comp_data->import_table_count) {
offset += offsetof(AOTTableInstance, elems);
/* avoid loading from current AOTTableInstance */
offset +=
sizeof(uint32)
* aot_get_imp_tbl_data_slots(imp_tbls + i, comp_ctx->is_jit_mode);
++i;
}
if (i == tbl_idx) {
return offset;
}
tbl_idx -= comp_ctx->comp_data->import_table_count;
i -= comp_ctx->comp_data->import_table_count;
while (i < tbl_idx && i < comp_ctx->comp_data->table_count) {
offset += offsetof(AOTTableInstance, elems);
/* avoid loading from current AOTTableInstance */
offset += sizeof(uint32)
* aot_get_tbl_data_slots(tbls + i, comp_ctx->is_jit_mode);
++i;
}
return offset;
}
#if WASM_ENABLE_REF_TYPES != 0
LLVMValueRef
aot_compile_get_tbl_inst(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
uint32 tbl_idx)
{
LLVMValueRef offset, tbl_inst;
if (!(offset =
I64_CONST(get_tbl_inst_offset(comp_ctx, func_ctx, tbl_idx)))) {
HANDLE_FAILURE("LLVMConstInt");
goto fail;
}
if (!(tbl_inst = LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE,
func_ctx->aot_inst, &offset, 1,
"tbl_inst"))) {
HANDLE_FAILURE("LLVMBuildInBoundsGEP");
goto fail;
}
return tbl_inst;
fail:
return NULL;
}
bool
aot_compile_op_elem_drop(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
uint32 tbl_seg_idx)
{
LLVMTypeRef param_types[2], ret_type, func_type, func_ptr_type;
LLVMValueRef param_values[2], ret_value, func, value;
/* void aot_drop_table_seg(AOTModuleInstance *, uint32 ) */
param_types[0] = INT8_PTR_TYPE;
param_types[1] = I32_TYPE;
ret_type = VOID_TYPE;
if (comp_ctx->is_jit_mode)
GET_AOT_FUNCTION(llvm_jit_drop_table_seg, 2);
else
GET_AOT_FUNCTION(aot_drop_table_seg, 2);
param_values[0] = func_ctx->aot_inst;
if (!(param_values[1] = I32_CONST(tbl_seg_idx))) {
HANDLE_FAILURE("LLVMConstInt");
goto fail;
}
/* "" means return void */
if (!(ret_value = LLVMBuildCall2(comp_ctx->builder, func_type, func,
param_values, 2, ""))) {
HANDLE_FAILURE("LLVMBuildCall");
goto fail;
}
return true;
fail:
return false;
}
static bool
aot_check_table_access(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
uint32 tbl_idx, LLVMValueRef elem_idx)
{
LLVMValueRef offset, tbl_sz, cmp_elem_idx;
LLVMBasicBlockRef check_elem_idx_succ;
/* get the cur size of the table instance */
if (!(offset = I32_CONST(get_tbl_inst_offset(comp_ctx, func_ctx, tbl_idx)
+ offsetof(AOTTableInstance, cur_size)))) {
HANDLE_FAILURE("LLVMConstInt");
goto fail;
}
if (!(tbl_sz = LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE,
func_ctx->aot_inst, &offset, 1,
"cur_size_i8p"))) {
HANDLE_FAILURE("LLVMBuildInBoundsGEP");
goto fail;
}
if (!(tbl_sz = LLVMBuildBitCast(comp_ctx->builder, tbl_sz, INT32_PTR_TYPE,
"cur_siuze_i32p"))) {
HANDLE_FAILURE("LLVMBuildBitCast");
goto fail;
}
if (!(tbl_sz = LLVMBuildLoad2(comp_ctx->builder, I32_TYPE, tbl_sz,
"cur_size"))) {
HANDLE_FAILURE("LLVMBuildLoad");
goto fail;
}
/* Check if (uint32)elem index >= table size */
if (!(cmp_elem_idx = LLVMBuildICmp(comp_ctx->builder, LLVMIntUGE, elem_idx,
tbl_sz, "cmp_elem_idx"))) {
aot_set_last_error("llvm build icmp failed.");
goto fail;
}
/* Throw exception if elem index >= table size */
if (!(check_elem_idx_succ = LLVMAppendBasicBlockInContext(
comp_ctx->context, func_ctx->func, "check_elem_idx_succ"))) {
aot_set_last_error("llvm add basic block failed.");
goto fail;
}
LLVMMoveBasicBlockAfter(check_elem_idx_succ,
LLVMGetInsertBlock(comp_ctx->builder));
if (!(aot_emit_exception(comp_ctx, func_ctx,
EXCE_OUT_OF_BOUNDS_TABLE_ACCESS, true,
cmp_elem_idx, check_elem_idx_succ)))
goto fail;
return true;
fail:
return false;
}
bool
aot_compile_op_table_get(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
uint32 tbl_idx)
{
LLVMValueRef elem_idx, offset, table_elem, func_idx;
POP_I32(elem_idx);
if (!aot_check_table_access(comp_ctx, func_ctx, tbl_idx, elem_idx)) {
goto fail;
}
/* load data as i32* */
if (!(offset = I32_CONST(get_tbl_inst_offset(comp_ctx, func_ctx, tbl_idx)
+ offsetof(AOTTableInstance, elems)))) {
HANDLE_FAILURE("LLVMConstInt");
goto fail;
}
if (!(table_elem = LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE,
func_ctx->aot_inst, &offset, 1,
"table_elem_i8p"))) {
aot_set_last_error("llvm build add failed.");
goto fail;
}
if (!(table_elem = LLVMBuildBitCast(comp_ctx->builder, table_elem,
INT32_PTR_TYPE, "table_elem_i32p"))) {
HANDLE_FAILURE("LLVMBuildBitCast");
goto fail;
}
/* Load function index */
if (!(table_elem =
LLVMBuildInBoundsGEP2(comp_ctx->builder, I32_TYPE, table_elem,
&elem_idx, 1, "table_elem"))) {
HANDLE_FAILURE("LLVMBuildNUWAdd");
goto fail;
}
if (!(func_idx = LLVMBuildLoad2(comp_ctx->builder, I32_TYPE, table_elem,
"func_idx"))) {
HANDLE_FAILURE("LLVMBuildLoad");
goto fail;
}
PUSH_I32(func_idx);
return true;
fail:
return false;
}
bool
aot_compile_op_table_set(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
uint32 tbl_idx)
{
LLVMValueRef val, elem_idx, offset, table_elem;
POP_I32(val);
POP_I32(elem_idx);
if (!aot_check_table_access(comp_ctx, func_ctx, tbl_idx, elem_idx)) {
goto fail;
}
/* load data as i32* */
if (!(offset = I32_CONST(get_tbl_inst_offset(comp_ctx, func_ctx, tbl_idx)
+ offsetof(AOTTableInstance, elems)))) {
HANDLE_FAILURE("LLVMConstInt");
goto fail;
}
if (!(table_elem = LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE,
func_ctx->aot_inst, &offset, 1,
"table_elem_i8p"))) {
HANDLE_FAILURE("LLVMBuildInBoundsGEP");
goto fail;
}
if (!(table_elem = LLVMBuildBitCast(comp_ctx->builder, table_elem,
INT32_PTR_TYPE, "table_elem_i32p"))) {
HANDLE_FAILURE("LLVMBuildBitCast");
goto fail;
}
/* Load function index */
if (!(table_elem =
LLVMBuildInBoundsGEP2(comp_ctx->builder, I32_TYPE, table_elem,
&elem_idx, 1, "table_elem"))) {
HANDLE_FAILURE("LLVMBuildInBoundsGEP");
goto fail;
}
if (!(LLVMBuildStore(comp_ctx->builder, val, table_elem))) {
HANDLE_FAILURE("LLVMBuildStore");
goto fail;
}
return true;
fail:
return false;
}
bool
aot_compile_op_table_init(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
uint32 tbl_idx, uint32 tbl_seg_idx)
{
LLVMValueRef func, param_values[6], value;
LLVMTypeRef param_types[6], ret_type, func_type, func_ptr_type;
param_types[0] = INT8_PTR_TYPE;
param_types[1] = I32_TYPE;
param_types[2] = I32_TYPE;
param_types[3] = I32_TYPE;
param_types[4] = I32_TYPE;
param_types[5] = I32_TYPE;
ret_type = VOID_TYPE;
if (comp_ctx->is_jit_mode)
GET_AOT_FUNCTION(llvm_jit_table_init, 6);
else
GET_AOT_FUNCTION(aot_table_init, 6);
param_values[0] = func_ctx->aot_inst;
if (!(param_values[1] = I32_CONST(tbl_idx))) {
HANDLE_FAILURE("LLVMConstInt");
goto fail;
}
if (!(param_values[2] = I32_CONST(tbl_seg_idx))) {
HANDLE_FAILURE("LLVMConstInt");
goto fail;
}
/* n */
POP_I32(param_values[3]);
/* s */
POP_I32(param_values[4]);
/* d */
POP_I32(param_values[5]);
/* "" means return void */
if (!(LLVMBuildCall2(comp_ctx->builder, func_type, func, param_values, 6,
""))) {
HANDLE_FAILURE("LLVMBuildCall");
goto fail;
}
return true;
fail:
return false;
}
bool
aot_compile_op_table_copy(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
uint32 src_tbl_idx, uint32 dst_tbl_idx)
{
LLVMTypeRef param_types[6], ret_type, func_type, func_ptr_type;
LLVMValueRef func, param_values[6], value;
param_types[0] = INT8_PTR_TYPE;
param_types[1] = I32_TYPE;
param_types[2] = I32_TYPE;
param_types[3] = I32_TYPE;
param_types[4] = I32_TYPE;
param_types[5] = I32_TYPE;
ret_type = VOID_TYPE;
if (comp_ctx->is_jit_mode)
GET_AOT_FUNCTION(llvm_jit_table_copy, 6);
else
GET_AOT_FUNCTION(aot_table_copy, 6);
param_values[0] = func_ctx->aot_inst;
if (!(param_values[1] = I32_CONST(src_tbl_idx))) {
HANDLE_FAILURE("LLVMConstInt");
goto fail;
}
if (!(param_values[2] = I32_CONST(dst_tbl_idx))) {
HANDLE_FAILURE("LLVMConstInt");
goto fail;
}
/* n */
POP_I32(param_values[3]);
/* s */
POP_I32(param_values[4]);
/* d */
POP_I32(param_values[5]);
/* "" means return void */
if (!(LLVMBuildCall2(comp_ctx->builder, func_type, func, param_values, 6,
""))) {
HANDLE_FAILURE("LLVMBuildCall");
goto fail;
}
return true;
fail:
return false;
}
bool
aot_compile_op_table_size(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
uint32 tbl_idx)
{
LLVMValueRef offset, tbl_sz;
if (!(offset = I32_CONST(get_tbl_inst_offset(comp_ctx, func_ctx, tbl_idx)
+ offsetof(AOTTableInstance, cur_size)))) {
HANDLE_FAILURE("LLVMConstInt");
goto fail;
}
if (!(tbl_sz = LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE,
func_ctx->aot_inst, &offset, 1,
"tbl_sz_ptr_i8"))) {
HANDLE_FAILURE("LLVMBuildInBoundsGEP");
goto fail;
}
if (!(tbl_sz = LLVMBuildBitCast(comp_ctx->builder, tbl_sz, INT32_PTR_TYPE,
"tbl_sz_ptr"))) {
HANDLE_FAILURE("LLVMBuildBitCast");
goto fail;
}
if (!(tbl_sz =
LLVMBuildLoad2(comp_ctx->builder, I32_TYPE, tbl_sz, "tbl_sz"))) {
HANDLE_FAILURE("LLVMBuildLoad");
goto fail;
}
PUSH_I32(tbl_sz);
return true;
fail:
return false;
}
bool
aot_compile_op_table_grow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
uint32 tbl_idx)
{
LLVMTypeRef param_types[4], ret_type, func_type, func_ptr_type;
LLVMValueRef func, param_values[4], ret, value;
param_types[0] = INT8_PTR_TYPE;
param_types[1] = I32_TYPE;
param_types[2] = I32_TYPE;
param_types[3] = I32_TYPE;
ret_type = I32_TYPE;
if (comp_ctx->is_jit_mode)
GET_AOT_FUNCTION(llvm_jit_table_grow, 4);
else
GET_AOT_FUNCTION(aot_table_grow, 4);
param_values[0] = func_ctx->aot_inst;
if (!(param_values[1] = I32_CONST(tbl_idx))) {
HANDLE_FAILURE("LLVMConstInt");
goto fail;
}
/* n */
POP_I32(param_values[2]);
/* v */
POP_I32(param_values[3]);
if (!(ret = LLVMBuildCall2(comp_ctx->builder, func_type, func, param_values,
4, "table_grow"))) {
HANDLE_FAILURE("LLVMBuildCall");
goto fail;
}
PUSH_I32(ret);
return true;
fail:
return false;
}
bool
aot_compile_op_table_fill(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
uint32 tbl_idx)
{
LLVMTypeRef param_types[5], ret_type, func_type, func_ptr_type;
LLVMValueRef func, param_values[5], value;
param_types[0] = INT8_PTR_TYPE;
param_types[1] = I32_TYPE;
param_types[2] = I32_TYPE;
param_types[3] = I32_TYPE;
param_types[4] = I32_TYPE;
ret_type = VOID_TYPE;
if (comp_ctx->is_jit_mode)
GET_AOT_FUNCTION(llvm_jit_table_fill, 5);
else
GET_AOT_FUNCTION(aot_table_fill, 5);
param_values[0] = func_ctx->aot_inst;
if (!(param_values[1] = I32_CONST(tbl_idx))) {
HANDLE_FAILURE("LLVMConstInt");
goto fail;
}
/* n */
POP_I32(param_values[2]);
/* v */
POP_I32(param_values[3]);
/* i */
POP_I32(param_values[4]);
/* "" means return void */
if (!(LLVMBuildCall2(comp_ctx->builder, func_type, func, param_values, 5,
""))) {
HANDLE_FAILURE("LLVMBuildCall");
goto fail;
}
return true;
fail:
return false;
}
#endif /* WASM_ENABLE_REF_TYPES != 0 */