Refactor app heap and memory boundary check, and fix os_printf compilation error (#356)
Insert app heap before __heap_base, or before new page Fix os_printf compilation error in some platforms
This commit is contained in:
@ -375,6 +375,10 @@ aot_create_comp_data(WASMModule *module)
|
||||
}
|
||||
memset(comp_data->memories, 0, size);
|
||||
|
||||
if (!(module->import_memory_count + module->memory_count)) {
|
||||
comp_data->memories[0].num_bytes_per_page = DEFAULT_NUM_BYTES_PER_PAGE;
|
||||
}
|
||||
|
||||
/* Set memory page count */
|
||||
for (i = 0; i < module->import_memory_count + module->memory_count; i++) {
|
||||
if (i < module->import_memory_count) {
|
||||
@ -487,13 +491,19 @@ aot_create_comp_data(WASMModule *module)
|
||||
&& !(comp_data->funcs = aot_create_funcs(module)))
|
||||
goto fail;
|
||||
|
||||
/* Create llvm aux stack informations */
|
||||
comp_data->llvm_aux_stack_global_index = module->llvm_aux_stack_global_index;
|
||||
comp_data->llvm_aux_data_end = module->llvm_aux_data_end;
|
||||
comp_data->llvm_aux_stack_bottom = module->llvm_aux_stack_bottom;
|
||||
comp_data->llvm_aux_stack_size = module->llvm_aux_stack_size;
|
||||
/* Create aux data/heap/stack information */
|
||||
comp_data->aux_data_end_global_index = module->aux_data_end_global_index;
|
||||
comp_data->aux_data_end = module->aux_data_end;
|
||||
comp_data->aux_heap_base_global_index = module->aux_heap_base_global_index;
|
||||
comp_data->aux_heap_base = module->aux_heap_base;
|
||||
comp_data->aux_stack_top_global_index = module->aux_stack_top_global_index;
|
||||
comp_data->aux_stack_bottom = module->aux_stack_bottom;
|
||||
comp_data->aux_stack_size = module->aux_stack_size;
|
||||
|
||||
comp_data->start_func_index = module->start_function;
|
||||
comp_data->malloc_func_index = module->malloc_function;
|
||||
comp_data->free_func_index = module->free_function;
|
||||
|
||||
comp_data->wasm_module = module;
|
||||
|
||||
return comp_data;
|
||||
|
||||
@ -201,14 +201,19 @@ typedef struct AOTCompData {
|
||||
uint32 func_count;
|
||||
AOTFunc **funcs;
|
||||
|
||||
uint32 start_func_index;
|
||||
uint32 addr_data_size;
|
||||
uint32 global_data_size;
|
||||
|
||||
uint32 llvm_aux_data_end;
|
||||
uint32 llvm_aux_stack_bottom;
|
||||
uint32 llvm_aux_stack_size;
|
||||
uint32 llvm_aux_stack_global_index;
|
||||
uint32 start_func_index;
|
||||
uint32 malloc_func_index;
|
||||
uint32 free_func_index;
|
||||
|
||||
uint32 aux_data_end_global_index;
|
||||
uint32 aux_data_end;
|
||||
uint32 aux_heap_base_global_index;
|
||||
uint32 aux_heap_base;
|
||||
uint32 aux_stack_top_global_index;
|
||||
uint32 aux_stack_bottom;
|
||||
uint32 aux_stack_size;
|
||||
|
||||
WASMModule *wasm_module;
|
||||
} AOTCompData;
|
||||
|
||||
@ -779,9 +779,10 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
|
||||
|
||||
case WASM_OP_MISC_PREFIX:
|
||||
{
|
||||
if (frame_ip < frame_ip_end) {
|
||||
opcode = *frame_ip++;
|
||||
}
|
||||
uint32 opcode1;
|
||||
|
||||
read_leb_uint32(frame_ip, frame_ip_end, opcode1);
|
||||
opcode = (uint32)opcode1;
|
||||
|
||||
switch (opcode) {
|
||||
case WASM_OP_I32_TRUNC_SAT_S_F32:
|
||||
|
||||
@ -420,9 +420,8 @@ get_init_data_section_size(AOTCompData *comp_data, AOTObjectData *obj_data)
|
||||
size = align_uint(size, 4);
|
||||
size += (uint32)sizeof(uint32) * 2;
|
||||
|
||||
/* llvm aux data end + llvm aux stack bottom
|
||||
+ llvm aux stack size + llvm stack global index */
|
||||
size += sizeof(uint32) * 4;
|
||||
/* aux data/heap/stack data */
|
||||
size += sizeof(uint32) * 7;
|
||||
|
||||
size += get_object_data_section_info_size(obj_data);
|
||||
return size;
|
||||
@ -1190,10 +1189,13 @@ aot_emit_init_data_section(uint8 *buf, uint8 *buf_end, uint32 *p_offset,
|
||||
EMIT_U32(comp_data->func_count);
|
||||
EMIT_U32(comp_data->start_func_index);
|
||||
|
||||
EMIT_U32(comp_data->llvm_aux_data_end);
|
||||
EMIT_U32(comp_data->llvm_aux_stack_bottom);
|
||||
EMIT_U32(comp_data->llvm_aux_stack_size);
|
||||
EMIT_U32(comp_data->llvm_aux_stack_global_index);
|
||||
EMIT_U32(comp_data->aux_data_end_global_index);
|
||||
EMIT_U32(comp_data->aux_data_end);
|
||||
EMIT_U32(comp_data->aux_heap_base_global_index);
|
||||
EMIT_U32(comp_data->aux_heap_base);
|
||||
EMIT_U32(comp_data->aux_stack_top_global_index);
|
||||
EMIT_U32(comp_data->aux_stack_bottom);
|
||||
EMIT_U32(comp_data->aux_stack_size);
|
||||
|
||||
if (!aot_emit_object_data_section_info(buf, buf_end, &offset, obj_data))
|
||||
return false;
|
||||
|
||||
@ -70,29 +70,36 @@ get_memory_check_bound(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
return mem_check_bound;
|
||||
}
|
||||
|
||||
static LLVMValueRef
|
||||
get_memory_size(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
|
||||
|
||||
static LLVMValueRef
|
||||
check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
uint32 offset, uint32 bytes)
|
||||
{
|
||||
LLVMValueRef offset_const = I32_CONST(offset);
|
||||
LLVMValueRef addr, maddr, offset1, cmp, cmp1, cmp2;
|
||||
LLVMValueRef addr, maddr, offset1, cmp1, cmp2, cmp;
|
||||
LLVMValueRef mem_base_addr, mem_check_bound;
|
||||
LLVMBasicBlockRef block_curr = LLVMGetInsertBlock(comp_ctx->builder);
|
||||
LLVMBasicBlockRef check_succ;
|
||||
AOTValue *aot_value;
|
||||
bool is_target_64bit;
|
||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||
bool is_shared_memory =
|
||||
comp_ctx->comp_data->memories[0].memory_flags & 0x02;
|
||||
#endif
|
||||
|
||||
is_target_64bit = (comp_ctx->pointer_size == sizeof(uint64))
|
||||
? true : false;
|
||||
|
||||
CHECK_LLVM_CONST(offset_const);
|
||||
|
||||
/* Get memory base address and memory data size */
|
||||
if (func_ctx->mem_space_unchanged
|
||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||
if (func_ctx->mem_space_unchanged || is_shared_memory) {
|
||||
#else
|
||||
if (func_ctx->mem_space_unchanged) {
|
||||
|| is_shared_memory
|
||||
#endif
|
||||
) {
|
||||
mem_base_addr = func_ctx->mem_info[0].mem_base_addr;
|
||||
}
|
||||
else {
|
||||
@ -111,15 +118,15 @@ check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
|
||||
/* return addres directly if constant offset and inside memory space */
|
||||
if (LLVMIsConstant(addr)) {
|
||||
int64 mem_offset = (int64)LLVMConstIntGetSExtValue(addr) + (int64)offset;
|
||||
uint64 mem_offset = (uint64)LLVMConstIntGetZExtValue(addr)
|
||||
+ (uint64)offset;
|
||||
uint32 num_bytes_per_page =
|
||||
comp_ctx->comp_data->memories[0].num_bytes_per_page;
|
||||
uint32 init_page_count =
|
||||
comp_ctx->comp_data->memories[0].mem_init_page_count;
|
||||
int64 mem_data_size = num_bytes_per_page * init_page_count;
|
||||
if (mem_data_size > 0
|
||||
&& mem_offset >= 0
|
||||
&& mem_offset <= mem_data_size - bytes) {
|
||||
uint64 mem_data_size = num_bytes_per_page * init_page_count;
|
||||
|
||||
if (mem_offset + bytes <= mem_data_size) {
|
||||
/* inside memory space */
|
||||
offset1 = I32_CONST((uint32)mem_offset);
|
||||
CHECK_LLVM_CONST(offset1);
|
||||
@ -132,12 +139,14 @@ check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
}
|
||||
}
|
||||
|
||||
if (!(offset_const = LLVMBuildZExt(comp_ctx->builder, offset_const,
|
||||
I64_TYPE, "offset_i64"))
|
||||
|| !(addr = LLVMBuildSExt(comp_ctx->builder, addr,
|
||||
I64_TYPE, "addr_i64"))) {
|
||||
aot_set_last_error("llvm build extend i32 to i64 failed.");
|
||||
goto fail;
|
||||
if (is_target_64bit) {
|
||||
if (!(offset_const = LLVMBuildZExt(comp_ctx->builder, offset_const,
|
||||
I64_TYPE, "offset_i64"))
|
||||
|| !(addr = LLVMBuildZExt(comp_ctx->builder, addr,
|
||||
I64_TYPE, "addr_i64"))) {
|
||||
aot_set_last_error("llvm build zero extend failed.");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* offset1 = offset + addr; */
|
||||
@ -147,16 +156,41 @@ check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
&& !(aot_value->is_local
|
||||
&& aot_checked_addr_list_find(func_ctx, aot_value->local_idx,
|
||||
offset, bytes))) {
|
||||
uint32 init_page_count =
|
||||
comp_ctx->comp_data->memories[0].mem_init_page_count;
|
||||
if (init_page_count == 0) {
|
||||
LLVMValueRef mem_size;
|
||||
|
||||
if (!(mem_size = get_memory_size(comp_ctx, func_ctx))) {
|
||||
goto fail;
|
||||
}
|
||||
BUILD_ICMP(LLVMIntEQ, mem_size, I32_ZERO, cmp, "is_zero");
|
||||
ADD_BASIC_BLOCK(check_succ, "check_mem_size_succ");
|
||||
LLVMMoveBasicBlockAfter(check_succ, block_curr);
|
||||
if (!aot_emit_exception(comp_ctx, func_ctx,
|
||||
EXCE_OUT_OF_BOUNDS_MEMORY_ACCESS,
|
||||
true, cmp, check_succ)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
SET_BUILD_POS(check_succ);
|
||||
block_curr = check_succ;
|
||||
}
|
||||
|
||||
if (!(mem_check_bound =
|
||||
get_memory_check_bound(comp_ctx, func_ctx, bytes))) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
BUILD_ICMP(LLVMIntSGT,
|
||||
func_ctx->mem_info[0].mem_bound_check_heap_base,
|
||||
offset1, cmp1, "cmp1");
|
||||
BUILD_ICMP(LLVMIntSGT, offset1, mem_check_bound, cmp2, "cmp2");
|
||||
BUILD_OP(Or, cmp1, cmp2, cmp, "cmp");
|
||||
if (is_target_64bit) {
|
||||
BUILD_ICMP(LLVMIntUGT, offset1, mem_check_bound, cmp, "cmp");
|
||||
}
|
||||
else {
|
||||
/* Check integer overflow */
|
||||
BUILD_ICMP(LLVMIntULT, offset1, addr, cmp1, "cmp1");
|
||||
BUILD_ICMP(LLVMIntUGT, offset1, mem_check_bound, cmp2, "cmp2");
|
||||
BUILD_OP(Or, cmp1, cmp2, cmp, "cmp");
|
||||
}
|
||||
|
||||
/* Add basic blocks */
|
||||
ADD_BASIC_BLOCK(check_succ, "check_succ");
|
||||
|
||||
@ -190,6 +190,7 @@ create_memory_info(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
uint32 memory_count;
|
||||
WASMModule *module = comp_ctx->comp_data->wasm_module;
|
||||
WASMFunction *func = module->functions[func_index];
|
||||
LLVMTypeRef bound_check_type;
|
||||
bool mem_space_unchanged = (!func->has_op_memory_grow && !func->has_op_func_call)
|
||||
|| (!module->possible_memory_grow);
|
||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||
@ -264,7 +265,7 @@ create_memory_info(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
aot_set_last_error("llvm build in bounds gep failed");
|
||||
return false;
|
||||
}
|
||||
offset = I32_CONST(offsetof(AOTMemoryInstance, mem_cur_page_count));
|
||||
offset = I32_CONST(offsetof(AOTMemoryInstance, cur_page_count));
|
||||
if (!(func_ctx->mem_info[0].mem_cur_page_count_addr =
|
||||
LLVMBuildInBoundsGEP(comp_ctx->builder, shared_mem_addr,
|
||||
&offset, 1, "mem_cur_page_offset"))) {
|
||||
@ -284,7 +285,7 @@ create_memory_info(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
return false;
|
||||
}
|
||||
offset = I32_CONST(offsetof(AOTModuleInstance, global_table_data)
|
||||
+ offsetof(AOTMemoryInstance, mem_cur_page_count));
|
||||
+ offsetof(AOTMemoryInstance, cur_page_count));
|
||||
if (!(func_ctx->mem_info[0].mem_cur_page_count_addr =
|
||||
LLVMBuildInBoundsGEP(comp_ctx->builder, func_ctx->aot_inst,
|
||||
&offset, 1, "mem_cur_page_offset"))) {
|
||||
@ -339,6 +340,9 @@ create_memory_info(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
}
|
||||
#endif
|
||||
|
||||
bound_check_type = (comp_ctx->pointer_size == sizeof(uint64))
|
||||
? INT64_PTR_TYPE : INT32_PTR_TYPE;
|
||||
|
||||
/* Load memory bound check constants */
|
||||
offset = I32_CONST(offsetof(AOTMemoryInstance, mem_bound_check_1byte)
|
||||
- offsetof(AOTMemoryInstance, memory_data.ptr));
|
||||
@ -351,7 +355,7 @@ create_memory_info(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
if (!(func_ctx->mem_info[0].mem_bound_check_1byte =
|
||||
LLVMBuildBitCast(comp_ctx->builder,
|
||||
func_ctx->mem_info[0].mem_bound_check_1byte,
|
||||
INT64_PTR_TYPE, "bound_check_1byte_ptr"))) {
|
||||
bound_check_type, "bound_check_1byte_ptr"))) {
|
||||
aot_set_last_error("llvm build bit cast failed");
|
||||
return false;
|
||||
}
|
||||
@ -376,7 +380,7 @@ create_memory_info(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
if (!(func_ctx->mem_info[0].mem_bound_check_2bytes =
|
||||
LLVMBuildBitCast(comp_ctx->builder,
|
||||
func_ctx->mem_info[0].mem_bound_check_2bytes,
|
||||
INT64_PTR_TYPE, "bound_check_2bytes_ptr"))) {
|
||||
bound_check_type, "bound_check_2bytes_ptr"))) {
|
||||
aot_set_last_error("llvm build bit cast failed");
|
||||
return false;
|
||||
}
|
||||
@ -401,7 +405,7 @@ create_memory_info(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
if (!(func_ctx->mem_info[0].mem_bound_check_4bytes =
|
||||
LLVMBuildBitCast(comp_ctx->builder,
|
||||
func_ctx->mem_info[0].mem_bound_check_4bytes,
|
||||
INT64_PTR_TYPE, "bound_check_4bytes_ptr"))) {
|
||||
bound_check_type, "bound_check_4bytes_ptr"))) {
|
||||
aot_set_last_error("llvm build bit cast failed");
|
||||
return false;
|
||||
}
|
||||
@ -426,7 +430,7 @@ create_memory_info(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
if (!(func_ctx->mem_info[0].mem_bound_check_8bytes =
|
||||
LLVMBuildBitCast(comp_ctx->builder,
|
||||
func_ctx->mem_info[0].mem_bound_check_8bytes,
|
||||
INT64_PTR_TYPE, "bound_check_8bytes_ptr"))) {
|
||||
bound_check_type, "bound_check_8bytes_ptr"))) {
|
||||
aot_set_last_error("llvm build bit cast failed");
|
||||
return false;
|
||||
}
|
||||
@ -440,30 +444,6 @@ create_memory_info(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
}
|
||||
}
|
||||
|
||||
/* Load bound_check_heap_base */
|
||||
offset = I32_CONST(offsetof(AOTMemoryInstance, mem_bound_check_heap_base)
|
||||
- offsetof(AOTMemoryInstance, memory_data.ptr));
|
||||
if (!(func_ctx->mem_info[0].mem_bound_check_heap_base =
|
||||
LLVMBuildInBoundsGEP(comp_ctx->builder, mem_info_base,
|
||||
&offset, 1, "bound_check_heap_base_offset"))) {
|
||||
aot_set_last_error("llvm build in bounds gep failed");
|
||||
return false;
|
||||
}
|
||||
if (!(func_ctx->mem_info[0].mem_bound_check_heap_base =
|
||||
LLVMBuildBitCast(comp_ctx->builder,
|
||||
func_ctx->mem_info[0].mem_bound_check_heap_base,
|
||||
INT64_PTR_TYPE, "bound_check_heap_base_tmp"))) {
|
||||
aot_set_last_error("llvm build bit cast failed");
|
||||
return false;
|
||||
}
|
||||
if (!(func_ctx->mem_info[0].mem_bound_check_heap_base =
|
||||
LLVMBuildLoad(comp_ctx->builder,
|
||||
func_ctx->mem_info[0].mem_bound_check_heap_base,
|
||||
"bound_check_heap_base"))) {
|
||||
aot_set_last_error("llvm build load failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1033,6 +1013,7 @@ aot_create_comp_context(AOTCompData *comp_data,
|
||||
char triple_buf[32] = {0};
|
||||
uint32 opt_level, size_level;
|
||||
LLVMCodeModel code_model;
|
||||
LLVMTargetDataRef target_data_ref;
|
||||
|
||||
/* Initialize LLVM environment */
|
||||
LLVMInitializeAllTargetInfos();
|
||||
@ -1280,6 +1261,14 @@ aot_create_comp_context(AOTCompData *comp_data,
|
||||
}
|
||||
}
|
||||
|
||||
if (!(target_data_ref =
|
||||
LLVMCreateTargetDataLayout(comp_ctx->target_machine))) {
|
||||
aot_set_last_error("create LLVM target data layout failed.");
|
||||
goto fail;
|
||||
}
|
||||
comp_ctx->pointer_size = LLVMPointerSize(target_data_ref);
|
||||
LLVMDisposeTargetData(target_data_ref);
|
||||
|
||||
comp_ctx->optimize = true;
|
||||
if (option->output_format == AOT_LLVMIR_UNOPT_FILE)
|
||||
comp_ctx->optimize = false;
|
||||
|
||||
@ -102,7 +102,6 @@ typedef struct AOTCheckedAddr {
|
||||
typedef struct AOTMemInfo {
|
||||
LLVMValueRef mem_base_addr;
|
||||
LLVMValueRef mem_cur_page_count_addr;
|
||||
LLVMValueRef mem_bound_check_heap_base;
|
||||
LLVMValueRef mem_bound_check_1byte;
|
||||
LLVMValueRef mem_bound_check_2bytes;
|
||||
LLVMValueRef mem_bound_check_4bytes;
|
||||
@ -190,6 +189,7 @@ typedef struct AOTCompContext {
|
||||
LLVMTargetMachineRef target_machine;
|
||||
char *target_cpu;
|
||||
char target_arch[16];
|
||||
unsigned pointer_size;
|
||||
|
||||
/* LLVM execution engine required by JIT */
|
||||
LLVMExecutionEngineRef exec_engine;
|
||||
|
||||
Reference in New Issue
Block a user