Implement multi-module feature and bulk-memory feature (#271)
Refine wasm loader and aot loader Fix potential issue of os_mmap/os_munmap Update document
This commit is contained in:
@ -60,6 +60,10 @@ aot_create_mem_init_data_list(const WASMModule *module)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
#if WASM_ENABLE_BULK_MEMORY != 0
|
||||
data_list[i]->is_passive = module->data_segments[i]->is_passive;
|
||||
data_list[i]->memory_index = module->data_segments[i]->memory_index;
|
||||
#endif
|
||||
data_list[i]->offset = module->data_segments[i]->base_offset;
|
||||
data_list[i]->byte_count = module->data_segments[i]->data_length;
|
||||
memcpy(data_list[i]->bytes, module->data_segments[i]->data,
|
||||
|
||||
@ -24,6 +24,12 @@ typedef WASMType AOTFuncType;
|
||||
* A segment of memory init data
|
||||
*/
|
||||
typedef struct AOTMemInitData {
|
||||
#if WASM_ENABLE_BULK_MEMORY != 0
|
||||
/* Passive flag */
|
||||
bool is_passive;
|
||||
/* memory index */
|
||||
uint32 memory_index;
|
||||
#endif
|
||||
/* Start address of init data */
|
||||
AOTInitExpr offset;
|
||||
/* Byte count */
|
||||
|
||||
@ -741,6 +741,39 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
|
||||
if (!aot_compile_op_i64_trunc_f64(comp_ctx, func_ctx, sign, true))
|
||||
return false;
|
||||
break;
|
||||
#if WASM_ENABLE_BULK_MEMORY != 0
|
||||
case WASM_OP_MEMORY_INIT:
|
||||
{
|
||||
uint32 seg_index;
|
||||
read_leb_uint32(frame_ip, frame_ip_end, seg_index);
|
||||
frame_ip ++;
|
||||
if (!aot_compile_op_memory_init(comp_ctx, func_ctx, seg_index))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
case WASM_OP_DATA_DROP:
|
||||
{
|
||||
uint32 seg_index;
|
||||
read_leb_uint32(frame_ip, frame_ip_end, seg_index);
|
||||
if (!aot_compile_op_data_drop(comp_ctx, func_ctx, seg_index))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
case WASM_OP_MEMORY_COPY:
|
||||
{
|
||||
frame_ip += 2;
|
||||
if (!aot_compile_op_memory_copy(comp_ctx, func_ctx))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
case WASM_OP_MEMORY_FILL:
|
||||
{
|
||||
frame_ip ++;
|
||||
if (!aot_compile_op_memory_fill(comp_ctx, func_ctx))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
#endif /* WASM_ENABLE_BULK_MEMORY */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@ -124,8 +124,18 @@ get_mem_init_data_size(AOTMemInitData *mem_init_data)
|
||||
{
|
||||
/* init expr type (4 bytes) + init expr value (8 bytes)
|
||||
+ byte count (4 bytes) + bytes */
|
||||
return (uint32)(sizeof(uint32) + sizeof(uint64)
|
||||
+ sizeof(uint32) + mem_init_data->byte_count);
|
||||
uint32 total_size =
|
||||
(uint32)(sizeof(uint32) + sizeof(uint64)
|
||||
+ sizeof(uint32) + mem_init_data->byte_count);
|
||||
|
||||
/* bulk_memory enabled:
|
||||
is_passive (4 bytes) + memory_index (4 bytes)
|
||||
bulk memory disabled:
|
||||
placeholder (4 bytes) + placeholder (4 bytes)
|
||||
*/
|
||||
total_size += (sizeof(uint32) + sizeof(uint32));
|
||||
|
||||
return total_size;
|
||||
}
|
||||
|
||||
static uint32
|
||||
@ -682,7 +692,8 @@ get_relocation_section_size(AOTObjectData *obj_data)
|
||||
}
|
||||
|
||||
static uint32
|
||||
get_aot_file_size(AOTCompData *comp_data, AOTObjectData *obj_data)
|
||||
get_aot_file_size(AOTCompContext *comp_ctx, AOTCompData *comp_data,
|
||||
AOTObjectData *obj_data)
|
||||
{
|
||||
uint32 size = 0;
|
||||
|
||||
@ -868,7 +879,8 @@ aot_emit_target_info_section(uint8 *buf, uint8 *buf_end, uint32 *p_offset,
|
||||
|
||||
static bool
|
||||
aot_emit_mem_info(uint8 *buf, uint8 *buf_end, uint32 *p_offset,
|
||||
AOTCompData *comp_data, AOTObjectData *obj_data)
|
||||
AOTCompContext *comp_ctx, AOTCompData *comp_data,
|
||||
AOTObjectData *obj_data)
|
||||
{
|
||||
uint32 offset = *p_offset, i;
|
||||
AOTMemInitData **init_datas = comp_data->mem_init_data_list;
|
||||
@ -882,6 +894,18 @@ aot_emit_mem_info(uint8 *buf, uint8 *buf_end, uint32 *p_offset,
|
||||
|
||||
for (i = 0; i < comp_data->mem_init_data_count; i++) {
|
||||
offset = align_uint(offset, 4);
|
||||
#if WASM_ENABLE_BULK_MEMORY != 0
|
||||
if (comp_ctx->enable_bulk_memory) {
|
||||
EMIT_U32(init_datas[i]->is_passive);
|
||||
EMIT_U32(init_datas[i]->memory_index);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/* emit two placeholder to keep the same size */
|
||||
EMIT_U32(0);
|
||||
EMIT_U32(0);
|
||||
}
|
||||
EMIT_U32(init_datas[i]->offset.init_expr_type);
|
||||
EMIT_U64(init_datas[i]->offset.u.i64);
|
||||
EMIT_U32(init_datas[i]->byte_count);
|
||||
@ -1077,7 +1101,8 @@ aot_emit_object_data_section_info(uint8 *buf, uint8 *buf_end, uint32 *p_offset,
|
||||
|
||||
static bool
|
||||
aot_emit_init_data_section(uint8 *buf, uint8 *buf_end, uint32 *p_offset,
|
||||
AOTCompData *comp_data, AOTObjectData *obj_data)
|
||||
AOTCompContext *comp_ctx, AOTCompData *comp_data,
|
||||
AOTObjectData *obj_data)
|
||||
{
|
||||
uint32 section_size = get_init_data_section_size(comp_data, obj_data);
|
||||
uint32 offset = *p_offset;
|
||||
@ -1087,7 +1112,7 @@ aot_emit_init_data_section(uint8 *buf, uint8 *buf_end, uint32 *p_offset,
|
||||
EMIT_U32(AOT_SECTION_TYPE_INIT_DATA);
|
||||
EMIT_U32(section_size);
|
||||
|
||||
if (!aot_emit_mem_info(buf, buf_end, &offset, comp_data, obj_data)
|
||||
if (!aot_emit_mem_info(buf, buf_end, &offset, comp_ctx, comp_data, obj_data)
|
||||
|| !aot_emit_table_info(buf, buf_end, &offset, comp_data, obj_data)
|
||||
|| !aot_emit_func_type_info(buf, buf_end, &offset, comp_data, obj_data)
|
||||
|| !aot_emit_import_global_info(buf, buf_end, &offset, comp_data, obj_data)
|
||||
@ -1405,7 +1430,8 @@ aot_resolve_target_info(AOTCompContext *comp_ctx, AOTObjectData *obj_data)
|
||||
|
||||
obj_data->target_info.bin_type = bin_type - LLVMBinaryTypeELF32L;
|
||||
|
||||
if (bin_type == LLVMBinaryTypeELF32L || bin_type == LLVMBinaryTypeELF32B) {
|
||||
if (bin_type == LLVMBinaryTypeELF32L
|
||||
|| bin_type == LLVMBinaryTypeELF32B) {
|
||||
struct elf32_ehdr *elf_header;
|
||||
bool is_little_bin = bin_type == LLVMBinaryTypeELF32L;
|
||||
|
||||
@ -1420,7 +1446,8 @@ aot_resolve_target_info(AOTCompContext *comp_ctx, AOTObjectData *obj_data)
|
||||
SET_TARGET_INFO(e_version, e_version, uint32, is_little_bin);
|
||||
SET_TARGET_INFO(e_flags, e_flags, uint32, is_little_bin);
|
||||
}
|
||||
else {
|
||||
else if (bin_type == LLVMBinaryTypeELF64L
|
||||
|| bin_type == LLVMBinaryTypeELF64B) {
|
||||
struct elf64_ehdr *elf_header;
|
||||
bool is_little_bin = bin_type == LLVMBinaryTypeELF64L;
|
||||
|
||||
@ -1435,6 +1462,19 @@ aot_resolve_target_info(AOTCompContext *comp_ctx, AOTObjectData *obj_data)
|
||||
SET_TARGET_INFO(e_version, e_version, uint32, is_little_bin);
|
||||
SET_TARGET_INFO(e_flags, e_flags, uint32, is_little_bin);
|
||||
}
|
||||
else if (bin_type == LLVMBinaryTypeMachO32L
|
||||
|| bin_type == LLVMBinaryTypeMachO32B) {
|
||||
/* TODO: parse file type of Mach-O 32 */
|
||||
aot_set_last_error("invaid llvm binary bin_type.");
|
||||
return false;
|
||||
}
|
||||
else if (bin_type == LLVMBinaryTypeMachO64L
|
||||
|| bin_type == LLVMBinaryTypeMachO64B) {
|
||||
/* TODO: parse file type of Mach-O 64 */
|
||||
aot_set_last_error("invaid llvm binary bin_type.");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
strncpy(obj_data->target_info.arch, comp_ctx->target_arch,
|
||||
sizeof(obj_data->target_info.arch));
|
||||
@ -1941,7 +1981,7 @@ aot_emit_aot_file(AOTCompContext *comp_ctx, AOTCompData *comp_data,
|
||||
|
||||
bh_print_time("Begin to emit AOT file");
|
||||
|
||||
aot_file_size = get_aot_file_size(comp_data, obj_data);
|
||||
aot_file_size = get_aot_file_size(comp_ctx, comp_data, obj_data);
|
||||
|
||||
if (!(buf = aot_file_buf = wasm_runtime_malloc(aot_file_size))) {
|
||||
aot_set_last_error("allocate memory failed.");
|
||||
@ -1953,7 +1993,7 @@ aot_emit_aot_file(AOTCompContext *comp_ctx, AOTCompData *comp_data,
|
||||
|
||||
if (!aot_emit_file_header(buf, buf_end, &offset, comp_data, obj_data)
|
||||
|| !aot_emit_target_info_section(buf, buf_end, &offset, comp_data, obj_data)
|
||||
|| !aot_emit_init_data_section(buf, buf_end, &offset, comp_data, obj_data)
|
||||
|| !aot_emit_init_data_section(buf, buf_end, &offset, comp_ctx, comp_data, obj_data)
|
||||
|| !aot_emit_text_section(buf, buf_end, &offset, comp_data, obj_data)
|
||||
|| !aot_emit_func_section(buf, buf_end, &offset, comp_data, obj_data)
|
||||
|| !aot_emit_export_section(buf, buf_end, &offset, comp_data, obj_data)
|
||||
|
||||
@ -626,3 +626,290 @@ fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
#if WASM_ENABLE_BULK_MEMORY != 0
|
||||
|
||||
static LLVMValueRef
|
||||
check_bulk_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
LLVMValueRef offset, LLVMValueRef bytes)
|
||||
{
|
||||
LLVMValueRef maddr, max_addr, cmp;
|
||||
LLVMValueRef mem_base_addr;
|
||||
LLVMBasicBlockRef block_curr = LLVMGetInsertBlock(comp_ctx->builder);
|
||||
LLVMBasicBlockRef check_succ;
|
||||
uint32 off = offsetof(AOTModuleInstance, memory_data_size);
|
||||
LLVMValueRef mem_size_offset, mem_size_ptr, mem_size;
|
||||
|
||||
/* Get memory base address and memory data size */
|
||||
if (func_ctx->mem_space_unchanged) {
|
||||
mem_base_addr = func_ctx->mem_base_addr;
|
||||
}
|
||||
else {
|
||||
if (!(mem_base_addr = LLVMBuildLoad(comp_ctx->builder,
|
||||
func_ctx->mem_base_addr,
|
||||
"mem_base"))) {
|
||||
aot_set_last_error("llvm build load failed.");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* return addres directly if constant offset and inside memory space */
|
||||
if (LLVMIsConstant(offset) && LLVMIsConstant(bytes)) {
|
||||
uint64 mem_offset = (uint64)LLVMConstIntGetZExtValue(offset);
|
||||
uint64 mem_len = (uint64)LLVMConstIntGetZExtValue(bytes);
|
||||
uint32 num_bytes_per_page = comp_ctx->comp_data->num_bytes_per_page;
|
||||
uint32 init_page_count = comp_ctx->comp_data->mem_init_page_count;
|
||||
uint32 mem_data_size = num_bytes_per_page * init_page_count;
|
||||
if (mem_data_size > 0
|
||||
&& mem_offset + mem_len <= mem_data_size) {
|
||||
/* inside memory space */
|
||||
/* maddr = mem_base_addr + moffset */
|
||||
if (!(maddr = LLVMBuildInBoundsGEP(comp_ctx->builder,
|
||||
mem_base_addr,
|
||||
&offset, 1, "maddr"))) {
|
||||
aot_set_last_error("llvm build add failed.");
|
||||
goto fail;
|
||||
}
|
||||
return maddr;
|
||||
}
|
||||
}
|
||||
|
||||
/* mem_size_offset = aot_inst + off */
|
||||
mem_size_offset = I32_CONST(off);
|
||||
if (!(mem_size_ptr = LLVMBuildInBoundsGEP(comp_ctx->builder,
|
||||
func_ctx->aot_inst,
|
||||
&mem_size_offset, 1,
|
||||
"mem_size_ptr_tmp"))) {
|
||||
aot_set_last_error("llvm build inbounds gep failed.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* cast to int32* */
|
||||
if (!(mem_size_ptr = LLVMBuildBitCast(comp_ctx->builder, mem_size_ptr,
|
||||
INT32_PTR_TYPE, "mem_size_ptr"))) {
|
||||
aot_set_last_error("llvm build bitcast failed.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* load memory size */
|
||||
if (!(mem_size = LLVMBuildLoad(comp_ctx->builder,
|
||||
mem_size_ptr, "mem_size"))) {
|
||||
aot_set_last_error("llvm build load failed.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ADD_BASIC_BLOCK(check_succ, "check_succ");
|
||||
LLVMMoveBasicBlockAfter(check_succ, block_curr);
|
||||
|
||||
offset = LLVMBuildZExt(comp_ctx->builder, offset, I64_TYPE, "extend_offset");
|
||||
bytes = LLVMBuildZExt(comp_ctx->builder, bytes, I64_TYPE, "extend_len");
|
||||
mem_size = LLVMBuildZExt(comp_ctx->builder, mem_size, I64_TYPE, "extend_size");
|
||||
|
||||
BUILD_OP(Add, offset, bytes, max_addr, "max_addr");
|
||||
BUILD_ICMP(LLVMIntUGT, max_addr, mem_size, cmp,
|
||||
"cmp_max_mem_addr");
|
||||
if (!aot_emit_exception(comp_ctx, func_ctx,
|
||||
EXCE_OUT_OF_BOUNDS_MEMORY_ACCESS,
|
||||
true, cmp, check_succ)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* maddr = mem_base_addr + offset */
|
||||
if (!(maddr = LLVMBuildInBoundsGEP(comp_ctx->builder, mem_base_addr,
|
||||
&offset, 1, "maddr"))) {
|
||||
aot_set_last_error("llvm build add failed.");
|
||||
goto fail;
|
||||
}
|
||||
return maddr;
|
||||
fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define GET_AOT_FUNCTION(name, argc) do { \
|
||||
if (!(func_type = LLVMFunctionType(ret_type, param_types, \
|
||||
argc, false))) { \
|
||||
aot_set_last_error("llvm add function type failed."); \
|
||||
return false; \
|
||||
} \
|
||||
if (comp_ctx->is_jit_mode) { \
|
||||
/* JIT mode, call the function directly */ \
|
||||
if (!(func_ptr_type = LLVMPointerType(func_type, 0))) { \
|
||||
aot_set_last_error("llvm add pointer type failed."); \
|
||||
return false; \
|
||||
} \
|
||||
if (!(value = I64_CONST((uint64)(uintptr_t)name)) \
|
||||
|| !(func = LLVMConstIntToPtr(value, func_ptr_type))) { \
|
||||
aot_set_last_error("create LLVM value failed."); \
|
||||
return false; \
|
||||
} \
|
||||
} \
|
||||
else { \
|
||||
char *func_name = #name; \
|
||||
/* AOT mode, delcare the function */ \
|
||||
if (!(func = LLVMGetNamedFunction(comp_ctx->module, func_name)) \
|
||||
&& !(func = LLVMAddFunction(comp_ctx->module, \
|
||||
func_name, func_type))) { \
|
||||
aot_set_last_error("llvm add function failed."); \
|
||||
return false; \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
bool
|
||||
aot_compile_op_memory_init(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
uint32 seg_index)
|
||||
{
|
||||
LLVMValueRef seg, offset, dst, len, param_values[5], ret_value, func, value;
|
||||
LLVMTypeRef param_types[5], ret_type, func_type, func_ptr_type;
|
||||
AOTFuncType *aot_func_type = func_ctx->aot_func->func_type;
|
||||
LLVMBasicBlockRef block_curr = LLVMGetInsertBlock(comp_ctx->builder);
|
||||
LLVMBasicBlockRef mem_init_fail, init_success;
|
||||
|
||||
seg = I32_CONST(seg_index);
|
||||
|
||||
POP_I32(len);
|
||||
POP_I32(offset);
|
||||
POP_I32(dst);
|
||||
|
||||
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 = INT8_TYPE;
|
||||
|
||||
GET_AOT_FUNCTION(aot_memory_init, 5);
|
||||
|
||||
/* Call function aot_memory_init() */
|
||||
param_values[0] = func_ctx->aot_inst;
|
||||
param_values[1] = seg;
|
||||
param_values[2] = offset;
|
||||
param_values[3] = len;
|
||||
param_values[4] = dst;
|
||||
if (!(ret_value = LLVMBuildCall(comp_ctx->builder, func,
|
||||
param_values, 5, "call"))) {
|
||||
aot_set_last_error("llvm build call failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
BUILD_ICMP(LLVMIntUGT, ret_value, I8_ZERO, ret_value, "mem_init_ret");
|
||||
|
||||
ADD_BASIC_BLOCK(mem_init_fail, "mem_init_fail");
|
||||
ADD_BASIC_BLOCK(init_success, "init_success");
|
||||
|
||||
LLVMMoveBasicBlockAfter(mem_init_fail, block_curr);
|
||||
LLVMMoveBasicBlockAfter(init_success, block_curr);
|
||||
|
||||
if (!LLVMBuildCondBr(comp_ctx->builder, ret_value,
|
||||
init_success, mem_init_fail)) {
|
||||
aot_set_last_error("llvm build cond br failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* If memory.init failed, return this function
|
||||
so the runtime can catch the exception */
|
||||
LLVMPositionBuilderAtEnd(comp_ctx->builder, mem_init_fail);
|
||||
if (aot_func_type->result_count) {
|
||||
switch (aot_func_type->types[aot_func_type->param_count]) {
|
||||
case VALUE_TYPE_I32:
|
||||
LLVMBuildRet(comp_ctx->builder, I32_ZERO);
|
||||
break;
|
||||
case VALUE_TYPE_I64:
|
||||
LLVMBuildRet(comp_ctx->builder, I64_ZERO);
|
||||
break;
|
||||
case VALUE_TYPE_F32:
|
||||
LLVMBuildRet(comp_ctx->builder, F32_ZERO);
|
||||
break;
|
||||
case VALUE_TYPE_F64:
|
||||
LLVMBuildRet(comp_ctx->builder, F64_ZERO);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
LLVMBuildRetVoid(comp_ctx->builder);
|
||||
}
|
||||
|
||||
LLVMPositionBuilderAtEnd(comp_ctx->builder, init_success);
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_data_drop(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
uint32 seg_index)
|
||||
{
|
||||
LLVMValueRef seg, param_values[2], ret_value, func, value;
|
||||
LLVMTypeRef param_types[2], ret_type, func_type, func_ptr_type;
|
||||
|
||||
seg = I32_CONST(seg_index);
|
||||
|
||||
param_types[0] = INT8_PTR_TYPE;
|
||||
param_types[1] = I32_TYPE;
|
||||
ret_type = INT8_TYPE;
|
||||
|
||||
GET_AOT_FUNCTION(aot_data_drop, 2);
|
||||
|
||||
/* Call function aot_data_drop() */
|
||||
param_values[0] = func_ctx->aot_inst;
|
||||
param_values[1] = seg;
|
||||
if (!(ret_value = LLVMBuildCall(comp_ctx->builder, func,
|
||||
param_values, 2, "call"))) {
|
||||
aot_set_last_error("llvm build call failed.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_memory_copy(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
|
||||
{
|
||||
LLVMValueRef src, dst, src_addr, dst_addr, len, res;
|
||||
|
||||
POP_I32(len);
|
||||
POP_I32(src);
|
||||
POP_I32(dst);
|
||||
|
||||
if (!(src_addr =
|
||||
check_bulk_memory_overflow(comp_ctx, func_ctx, src, len)))
|
||||
return false;
|
||||
|
||||
if (!(dst_addr =
|
||||
check_bulk_memory_overflow(comp_ctx, func_ctx, dst, len)))
|
||||
return false;
|
||||
|
||||
if (!(res = LLVMBuildMemMove(comp_ctx->builder, dst_addr, 1,
|
||||
src_addr, 1, len))) {
|
||||
aot_set_last_error("llvm build memmove failed.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_memory_fill(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
|
||||
{
|
||||
LLVMValueRef val, dst, dst_addr, len, res;
|
||||
|
||||
POP_I32(len);
|
||||
POP_I32(val);
|
||||
POP_I32(dst);
|
||||
|
||||
if (!(dst_addr =
|
||||
check_bulk_memory_overflow(comp_ctx, func_ctx, dst, len)))
|
||||
return false;
|
||||
|
||||
val = LLVMBuildIntCast2(comp_ctx->builder, val, INT8_TYPE, true, "mem_set_value");
|
||||
|
||||
if (!(res = LLVMBuildMemSet(comp_ctx->builder, dst_addr,
|
||||
val, len, 1))) {
|
||||
aot_set_last_error("llvm build memset failed.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
#endif /* WASM_ENABLE_BULK_MEMORY */
|
||||
|
||||
@ -50,6 +50,22 @@ aot_compile_op_memory_size(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
|
||||
bool
|
||||
aot_compile_op_memory_grow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
|
||||
|
||||
#if WASM_ENABLE_BULK_MEMORY != 0
|
||||
bool
|
||||
aot_compile_op_memory_init(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
uint32 seg_index);
|
||||
|
||||
bool
|
||||
aot_compile_op_data_drop(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
uint32 seg_index);
|
||||
|
||||
bool
|
||||
aot_compile_op_memory_copy(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
|
||||
|
||||
bool
|
||||
aot_compile_op_memory_fill(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of extern "C" */
|
||||
#endif
|
||||
|
||||
@ -914,6 +914,9 @@ aot_create_comp_context(AOTCompData *comp_data,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (option->enable_bulk_memory)
|
||||
comp_ctx->enable_bulk_memory = true;
|
||||
|
||||
if (option->is_jit_mode) {
|
||||
/* Create LLVM execution engine */
|
||||
LLVMInitializeMCJITCompilerOptions(&jit_options, sizeof(jit_options));
|
||||
|
||||
@ -185,6 +185,9 @@ typedef struct AOTCompContext {
|
||||
LLVMExecutionEngineRef exec_engine;
|
||||
bool is_jit_mode;
|
||||
|
||||
/* Bulk memory feature */
|
||||
bool enable_bulk_memory;
|
||||
|
||||
/* Whether optimize the JITed code */
|
||||
bool optimize;
|
||||
|
||||
@ -223,6 +226,7 @@ typedef struct AOTCompOption{
|
||||
char *target_abi;
|
||||
char *target_cpu;
|
||||
char *cpu_features;
|
||||
bool enable_bulk_memory;
|
||||
uint32 opt_level;
|
||||
uint32 size_level;
|
||||
uint32 output_format;
|
||||
|
||||
Reference in New Issue
Block a user