mirror of
https://github.com/bytecodealliance/wasm-micro-runtime.git
synced 2025-02-12 01:45:10 +00:00
![Wenyong Huang](/assets/img/avatar_default.png)
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
275 lines
8.9 KiB
C
275 lines
8.9 KiB
C
/*
|
|
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
|
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
*/
|
|
|
|
#include "aot_emit_variable.h"
|
|
#include "aot_emit_exception.h"
|
|
#include "../aot/aot_runtime.h"
|
|
|
|
#define CHECK_LOCAL(idx) \
|
|
do { \
|
|
if (idx >= func_ctx->aot_func->func_type->param_count \
|
|
+ func_ctx->aot_func->local_count) { \
|
|
aot_set_last_error("local index out of range"); \
|
|
return false; \
|
|
} \
|
|
} while (0)
|
|
|
|
static uint8
|
|
get_local_type(AOTFuncContext *func_ctx, uint32 local_idx)
|
|
{
|
|
AOTFunc *aot_func = func_ctx->aot_func;
|
|
uint32 param_count = aot_func->func_type->param_count;
|
|
return local_idx < param_count
|
|
? aot_func->func_type->types[local_idx]
|
|
: aot_func->local_types[local_idx - param_count];
|
|
}
|
|
|
|
bool
|
|
aot_compile_op_get_local(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
|
uint32 local_idx)
|
|
{
|
|
char name[32];
|
|
LLVMValueRef value;
|
|
AOTValue *aot_value_top;
|
|
uint8 local_type;
|
|
|
|
CHECK_LOCAL(local_idx);
|
|
|
|
local_type = get_local_type(func_ctx, local_idx);
|
|
|
|
snprintf(name, sizeof(name), "%s%d%s", "local", local_idx, "#");
|
|
if (!(value = LLVMBuildLoad2(comp_ctx->builder, TO_LLVM_TYPE(local_type),
|
|
func_ctx->locals[local_idx], name))) {
|
|
aot_set_last_error("llvm build load fail");
|
|
return false;
|
|
}
|
|
|
|
PUSH(value, local_type);
|
|
|
|
aot_value_top =
|
|
func_ctx->block_stack.block_list_end->value_stack.value_list_end;
|
|
aot_value_top->is_local = true;
|
|
aot_value_top->local_idx = local_idx;
|
|
return true;
|
|
|
|
fail:
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
aot_compile_op_set_local(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
|
uint32 local_idx)
|
|
{
|
|
LLVMValueRef value;
|
|
|
|
CHECK_LOCAL(local_idx);
|
|
|
|
POP(value, get_local_type(func_ctx, local_idx));
|
|
|
|
if (!LLVMBuildStore(comp_ctx->builder, value,
|
|
func_ctx->locals[local_idx])) {
|
|
aot_set_last_error("llvm build store fail");
|
|
return false;
|
|
}
|
|
|
|
aot_checked_addr_list_del(func_ctx, local_idx);
|
|
return true;
|
|
|
|
fail:
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
aot_compile_op_tee_local(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
|
uint32 local_idx)
|
|
{
|
|
LLVMValueRef value;
|
|
uint8 type;
|
|
|
|
CHECK_LOCAL(local_idx);
|
|
|
|
type = get_local_type(func_ctx, local_idx);
|
|
|
|
POP(value, type);
|
|
|
|
if (!LLVMBuildStore(comp_ctx->builder, value,
|
|
func_ctx->locals[local_idx])) {
|
|
aot_set_last_error("llvm build store fail");
|
|
return false;
|
|
}
|
|
|
|
PUSH(value, type);
|
|
aot_checked_addr_list_del(func_ctx, local_idx);
|
|
return true;
|
|
|
|
fail:
|
|
return false;
|
|
}
|
|
|
|
static bool
|
|
compile_global(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
|
uint32 global_idx, bool is_set, bool is_aux_stack)
|
|
{
|
|
AOTCompData *comp_data = comp_ctx->comp_data;
|
|
uint32 import_global_count = comp_data->import_global_count;
|
|
uint32 global_base_offset;
|
|
uint32 global_offset;
|
|
uint8 global_type;
|
|
LLVMValueRef offset, global_ptr, global, res;
|
|
LLVMTypeRef ptr_type = NULL;
|
|
|
|
if (comp_ctx->is_jit_mode) {
|
|
global_base_offset =
|
|
offsetof(WASMModuleInstance, global_table_data.bytes)
|
|
+ sizeof(WASMMemoryInstance) * comp_ctx->comp_data->memory_count;
|
|
}
|
|
else {
|
|
global_base_offset =
|
|
offsetof(AOTModuleInstance, global_table_data.bytes)
|
|
+ sizeof(AOTMemoryInstance) * comp_ctx->comp_data->memory_count;
|
|
}
|
|
|
|
bh_assert(global_idx < import_global_count + comp_data->global_count);
|
|
|
|
if (global_idx < import_global_count) {
|
|
global_offset = global_base_offset
|
|
+ comp_data->import_globals[global_idx].data_offset;
|
|
global_type = comp_data->import_globals[global_idx].type;
|
|
}
|
|
else {
|
|
global_offset =
|
|
global_base_offset
|
|
+ comp_data->globals[global_idx - import_global_count].data_offset;
|
|
global_type = comp_data->globals[global_idx - import_global_count].type;
|
|
}
|
|
|
|
offset = I32_CONST(global_offset);
|
|
if (!(global_ptr = LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE,
|
|
func_ctx->aot_inst, &offset, 1,
|
|
"global_ptr_tmp"))) {
|
|
aot_set_last_error("llvm build in bounds gep failed.");
|
|
return false;
|
|
}
|
|
|
|
switch (global_type) {
|
|
case VALUE_TYPE_I32:
|
|
case VALUE_TYPE_EXTERNREF:
|
|
case VALUE_TYPE_FUNCREF:
|
|
ptr_type = comp_ctx->basic_types.int32_ptr_type;
|
|
break;
|
|
case VALUE_TYPE_I64:
|
|
ptr_type = comp_ctx->basic_types.int64_ptr_type;
|
|
break;
|
|
case VALUE_TYPE_F32:
|
|
ptr_type = comp_ctx->basic_types.float32_ptr_type;
|
|
break;
|
|
case VALUE_TYPE_F64:
|
|
ptr_type = comp_ctx->basic_types.float64_ptr_type;
|
|
break;
|
|
case VALUE_TYPE_V128:
|
|
ptr_type = comp_ctx->basic_types.v128_ptr_type;
|
|
break;
|
|
default:
|
|
bh_assert("unknown type");
|
|
break;
|
|
}
|
|
|
|
if (!(global_ptr = LLVMBuildBitCast(comp_ctx->builder, global_ptr, ptr_type,
|
|
"global_ptr"))) {
|
|
aot_set_last_error("llvm build bit cast failed.");
|
|
return false;
|
|
}
|
|
|
|
if (!is_set) {
|
|
if (!(global =
|
|
LLVMBuildLoad2(comp_ctx->builder, TO_LLVM_TYPE(global_type),
|
|
global_ptr, "global"))) {
|
|
aot_set_last_error("llvm build load failed.");
|
|
return false;
|
|
}
|
|
/* All globals' data is 4-byte aligned */
|
|
LLVMSetAlignment(global, 4);
|
|
PUSH(global, global_type);
|
|
}
|
|
else {
|
|
POP(global, global_type);
|
|
|
|
if (is_aux_stack && comp_ctx->enable_aux_stack_check) {
|
|
LLVMBasicBlockRef block_curr =
|
|
LLVMGetInsertBlock(comp_ctx->builder);
|
|
LLVMBasicBlockRef check_overflow_succ, check_underflow_succ;
|
|
LLVMValueRef cmp;
|
|
|
|
/* Add basic blocks */
|
|
if (!(check_overflow_succ = LLVMAppendBasicBlockInContext(
|
|
comp_ctx->context, func_ctx->func,
|
|
"check_overflow_succ"))) {
|
|
aot_set_last_error("llvm add basic block failed.");
|
|
return false;
|
|
}
|
|
LLVMMoveBasicBlockAfter(check_overflow_succ, block_curr);
|
|
|
|
if (!(check_underflow_succ = LLVMAppendBasicBlockInContext(
|
|
comp_ctx->context, func_ctx->func,
|
|
"check_underflow_succ"))) {
|
|
aot_set_last_error("llvm add basic block failed.");
|
|
return false;
|
|
}
|
|
LLVMMoveBasicBlockAfter(check_underflow_succ, check_overflow_succ);
|
|
|
|
/* Check aux stack overflow */
|
|
if (!(cmp = LLVMBuildICmp(comp_ctx->builder, LLVMIntULE, global,
|
|
func_ctx->aux_stack_bound, "cmp"))) {
|
|
aot_set_last_error("llvm build icmp failed.");
|
|
return false;
|
|
}
|
|
if (!aot_emit_exception(comp_ctx, func_ctx, EXCE_AUX_STACK_OVERFLOW,
|
|
true, cmp, check_overflow_succ)) {
|
|
return false;
|
|
}
|
|
|
|
/* Check aux stack underflow */
|
|
LLVMPositionBuilderAtEnd(comp_ctx->builder, check_overflow_succ);
|
|
if (!(cmp = LLVMBuildICmp(comp_ctx->builder, LLVMIntUGT, global,
|
|
func_ctx->aux_stack_bottom, "cmp"))) {
|
|
aot_set_last_error("llvm build icmp failed.");
|
|
return false;
|
|
}
|
|
if (!aot_emit_exception(comp_ctx, func_ctx,
|
|
EXCE_AUX_STACK_UNDERFLOW, true, cmp,
|
|
check_underflow_succ)) {
|
|
return false;
|
|
}
|
|
|
|
LLVMPositionBuilderAtEnd(comp_ctx->builder, check_underflow_succ);
|
|
}
|
|
|
|
if (!(res = LLVMBuildStore(comp_ctx->builder, global, global_ptr))) {
|
|
aot_set_last_error("llvm build store failed.");
|
|
return false;
|
|
}
|
|
/* All globals' data is 4-byte aligned */
|
|
LLVMSetAlignment(res, 4);
|
|
}
|
|
|
|
return true;
|
|
fail:
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
aot_compile_op_get_global(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
|
uint32 global_idx)
|
|
{
|
|
return compile_global(comp_ctx, func_ctx, global_idx, false, false);
|
|
}
|
|
|
|
bool
|
|
aot_compile_op_set_global(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
|
uint32 global_idx, bool is_aux_stack)
|
|
{
|
|
return compile_global(comp_ctx, func_ctx, global_idx, true, is_aux_stack);
|
|
}
|