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:
Wenyong Huang
2020-08-20 12:43:12 +08:00
committed by GitHub
parent 6b5f376e79
commit 89d2937cde
28 changed files with 1311 additions and 648 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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:

View File

@ -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;

View File

@ -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");

View File

@ -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;

View File

@ -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;