From f72e84811474991db5dcb48c7069de583e281fe9 Mon Sep 17 00:00:00 2001 From: wenyongh Date: Wed, 22 Apr 2020 18:43:50 +0800 Subject: [PATCH 001/207] Refine aot memory boundary check, add more llvm passes (#236) Fix issue of some error info mismatch with spec cases --- core/iwasm/compilation/aot_emit_control.c | 5 ++ core/iwasm/compilation/aot_emit_memory.c | 51 ++++++++----- core/iwasm/compilation/aot_emit_variable.c | 7 ++ core/iwasm/compilation/aot_llvm.c | 84 ++++++++++++++++++++- core/iwasm/compilation/aot_llvm.h | 24 ++++++ core/iwasm/interpreter/wasm_loader.c | 86 +++++++++++++++++----- core/iwasm/interpreter/wasm_runtime.c | 2 +- 7 files changed, 218 insertions(+), 41 deletions(-) diff --git a/core/iwasm/compilation/aot_emit_control.c b/core/iwasm/compilation/aot_emit_control.c index d2a321fa1..4dbaabb06 100644 --- a/core/iwasm/compilation/aot_emit_control.c +++ b/core/iwasm/compilation/aot_emit_control.c @@ -127,6 +127,8 @@ handle_next_reachable_block(AOTCompContext *comp_ctx, AOTBlock *block_prev; uint8 *frame_ip; + aot_checked_addr_list_destroy(func_ctx); + if (block->block_type == BLOCK_TYPE_IF && block->llvm_else_block && !block->skip_wasm_code_else @@ -233,6 +235,8 @@ aot_compile_op_block(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, /* Start to translate the block */ SET_BUILDER_POS(block->llvm_entry_block); aot_block_stack_push(&func_ctx->block_stack, block); + if (block_type == BLOCK_TYPE_LOOP) + aot_checked_addr_list_destroy(func_ctx); } else if (block_type == BLOCK_TYPE_IF) { POP_COND(value); @@ -373,6 +377,7 @@ aot_compile_op_else(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, /* Clear value stack and start to translate else branch */ aot_value_stack_destroy(&block->value_stack); SET_BUILDER_POS(block->llvm_else_block); + aot_checked_addr_list_destroy(func_ctx); return true; } diff --git a/core/iwasm/compilation/aot_emit_memory.c b/core/iwasm/compilation/aot_emit_memory.c index cdabe6b92..674d2eb1a 100644 --- a/core/iwasm/compilation/aot_emit_memory.c +++ b/core/iwasm/compilation/aot_emit_memory.c @@ -82,6 +82,7 @@ check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, LLVMValueRef mem_base_addr, mem_check_bound, total_mem_size; LLVMBasicBlockRef block_curr = LLVMGetInsertBlock(comp_ctx->builder); LLVMBasicBlockRef check_succ, check_mem_space; + AOTValue *aot_value; CHECK_LLVM_CONST(offset_const); CHECK_LLVM_CONST(bytes_const); @@ -100,6 +101,8 @@ check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } } + aot_value = func_ctx->block_stack.block_list_end->value_stack.value_list_end; + POP_I32(addr); /* offset1 = offset + addr; */ BUILD_OP(Add, offset_const, addr, offset1, "offset1"); @@ -152,28 +155,38 @@ check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, SET_BUILD_POS(check_mem_space); } - /* offset2 = offset1 - heap_base_offset; */ - BUILD_OP(Sub, offset1, heap_base_offset, offset2, "offset2"); + if (!(aot_value->is_local + && aot_checked_addr_list_find(func_ctx, aot_value->local_idx, + offset, bytes))) { + /* offset2 = offset1 - heap_base_offset; */ + BUILD_OP(Sub, offset1, heap_base_offset, offset2, "offset2"); - if (!(mem_check_bound = - get_memory_check_bound(comp_ctx, func_ctx, bytes))) { - goto fail; + if (!(mem_check_bound = + get_memory_check_bound(comp_ctx, func_ctx, bytes))) { + goto fail; + } + + /* Add basic blocks */ + ADD_BASIC_BLOCK(check_succ, "check_succ"); + LLVMMoveBasicBlockAfter(check_succ, block_curr); + + /* offset2 > bound ? */ + BUILD_ICMP(LLVMIntUGT, offset2, mem_check_bound, cmp, "cmp"); + 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); + + if (aot_value->is_local) { + if (!aot_checked_addr_list_add(func_ctx, aot_value->local_idx, + offset, bytes)) + goto fail; + } } - /* Add basic blocks */ - ADD_BASIC_BLOCK(check_succ, "check_succ"); - LLVMMoveBasicBlockAfter(check_succ, block_curr); - - /* offset2 > bound ? */ - BUILD_ICMP(LLVMIntUGT, offset2, mem_check_bound, cmp, "cmp"); - 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); - /* maddr = mem_base_addr + offset1 */ if (!(maddr = LLVMBuildInBoundsGEP(comp_ctx->builder, mem_base_addr, &offset1, 1, "maddr"))) { diff --git a/core/iwasm/compilation/aot_emit_variable.c b/core/iwasm/compilation/aot_emit_variable.c index 97ca8da00..4f5e63f18 100644 --- a/core/iwasm/compilation/aot_emit_variable.c +++ b/core/iwasm/compilation/aot_emit_variable.c @@ -30,6 +30,7 @@ aot_compile_op_get_local(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, { char name[32]; LLVMValueRef value; + AOTValue *aot_value; CHECK_LOCAL(local_idx); @@ -42,6 +43,10 @@ aot_compile_op_get_local(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } PUSH(value, get_local_type(func_ctx, local_idx)); + + aot_value = func_ctx->block_stack.block_list_end->value_stack.value_list_end; + aot_value->is_local = true; + aot_value->local_idx = local_idx; return true; fail: @@ -65,6 +70,7 @@ aot_compile_op_set_local(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, return false; } + aot_checked_addr_list_del(func_ctx, local_idx); return true; fail: @@ -92,6 +98,7 @@ aot_compile_op_tee_local(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } PUSH(value, type); + aot_checked_addr_list_del(func_ctx, local_idx); return true; fail: diff --git a/core/iwasm/compilation/aot_llvm.c b/core/iwasm/compilation/aot_llvm.c index 5e3da9c43..f1776d124 100644 --- a/core/iwasm/compilation/aot_llvm.c +++ b/core/iwasm/compilation/aot_llvm.c @@ -629,6 +629,7 @@ aot_destroy_func_contexts(AOTFuncContext **func_ctxes, uint32 count) if (func_ctxes[i]->exception_blocks) wasm_runtime_free(func_ctxes[i]->exception_blocks); aot_block_stack_destroy(&func_ctxes[i]->block_stack); + aot_checked_addr_list_destroy(func_ctxes[i]); wasm_runtime_free(func_ctxes[i]); } wasm_runtime_free(func_ctxes); @@ -1119,11 +1120,15 @@ aot_create_comp_context(AOTCompData *comp_data, aot_set_last_error("create LLVM pass manager failed."); goto fail; } + + LLVMAddBasicAliasAnalysisPass(comp_ctx->pass_mgr); LLVMAddPromoteMemoryToRegisterPass(comp_ctx->pass_mgr); LLVMAddInstructionCombiningPass(comp_ctx->pass_mgr); - LLVMAddCFGSimplificationPass(comp_ctx->pass_mgr); LLVMAddJumpThreadingPass(comp_ctx->pass_mgr); LLVMAddConstantPropagationPass(comp_ctx->pass_mgr); + LLVMAddReassociatePass(comp_ctx->pass_mgr); + LLVMAddGVNPass(comp_ctx->pass_mgr); + LLVMAddCFGSimplificationPass(comp_ctx->pass_mgr); /* Create metadata for llvm float experimental constrained intrinsics */ if (!(comp_ctx->fp_rounding_mode = @@ -1298,3 +1303,80 @@ aot_block_destroy(AOTBlock *block) aot_value_stack_destroy(&block->value_stack); wasm_runtime_free(block); } + +bool +aot_checked_addr_list_add(AOTFuncContext *func_ctx, + uint32 local_idx, uint32 offset, uint32 bytes) +{ + AOTCheckedAddr *node = func_ctx->checked_addr_list; + + if (!(node = wasm_runtime_malloc(sizeof(AOTCheckedAddr)))) { + aot_set_last_error("allocate memory failed."); + return false; + } + + node->local_idx = local_idx; + node->offset = offset; + node->bytes = bytes; + + node->next = func_ctx->checked_addr_list; + func_ctx->checked_addr_list = node; + return true; +} + +void +aot_checked_addr_list_del(AOTFuncContext *func_ctx, uint32 local_idx) +{ + AOTCheckedAddr *node = func_ctx->checked_addr_list; + AOTCheckedAddr *node_prev = NULL, *node_next; + + while (node) { + node_next = node->next; + + if (node->local_idx == local_idx) { + if (!node_prev) + func_ctx->checked_addr_list = node_next; + else + node_prev->next = node_next; + wasm_runtime_free(node); + } + else { + node_prev = node; + } + + node = node_next; + } +} + +bool +aot_checked_addr_list_find(AOTFuncContext *func_ctx, + uint32 local_idx, uint32 offset, uint32 bytes) +{ + AOTCheckedAddr *node = func_ctx->checked_addr_list; + + while (node) { + if (node->local_idx == local_idx + && node->offset == offset + && node->bytes >= bytes) { + return true; + } + node = node->next; + } + + return false; +} + +void +aot_checked_addr_list_destroy(AOTFuncContext *func_ctx) +{ + AOTCheckedAddr *node = func_ctx->checked_addr_list, *node_next; + + while (node) { + node_next = node->next; + wasm_runtime_free(node); + node = node_next; + } + + func_ctx->checked_addr_list = NULL; +} + diff --git a/core/iwasm/compilation/aot_llvm.h b/core/iwasm/compilation/aot_llvm.h index 6cbf11995..c97cd4855 100644 --- a/core/iwasm/compilation/aot_llvm.h +++ b/core/iwasm/compilation/aot_llvm.h @@ -30,6 +30,8 @@ typedef struct AOTValue { LLVMValueRef value; /* VALUE_TYPE_I32/I64/F32/F64/VOID */ uint8 type; + bool is_local; + uint32 local_idx; } AOTValue; /** @@ -84,6 +86,13 @@ typedef struct AOTBlockStack { uint32 block_index[3]; } AOTBlockStack; +typedef struct AOTCheckedAddr { + struct AOTCheckedAddr *next; + uint32 local_idx; + uint32 offset; + uint32 bytes; +} AOTCheckedAddr, *AOTCheckedAddrList; + typedef struct AOTFuncContext { AOTFunc *aot_func; LLVMValueRef func; @@ -105,6 +114,7 @@ typedef struct AOTFuncContext { LLVMValueRef cur_exception; bool mem_space_unchanged; + AOTCheckedAddrList checked_addr_list; LLVMBasicBlockRef *exception_blocks; LLVMBasicBlockRef got_exception_block; @@ -258,6 +268,20 @@ aot_block_destroy(AOTBlock *block); LLVMTypeRef wasm_type_to_llvm_type(AOTLLVMTypes *llvm_types, uint8 wasm_type); +bool +aot_checked_addr_list_add(AOTFuncContext *func_ctx, + uint32 local_idx, uint32 offset, uint32 bytes); + +void +aot_checked_addr_list_del(AOTFuncContext *func_ctx, uint32 local_idx); + +bool +aot_checked_addr_list_find(AOTFuncContext *func_ctx, + uint32 local_idx, uint32 offset, uint32 bytes); + +void +aot_checked_addr_list_destroy(AOTFuncContext *func_ctx); + #ifdef __cplusplus } /* end of extern "C" */ #endif diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index 12f7c79bd..d24babbf9 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -419,7 +419,7 @@ load_type_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, read_leb_uint32(p, p_end, result_count); if (result_count > 1) { set_error_buf(error_buf, error_buf_size, - "Load type section failed: invalid result count."); + "Load type section failed: invalid result arity."); return false; } CHECK_BUF(p, p_end, result_count); @@ -485,6 +485,36 @@ load_table_import(const uint8 **p_buf, const uint8 *buf_end, unsigned wasm_runtime_memory_pool_size(); +static bool +check_memory_init_size(uint32 init_size, + char *error_buf, uint32 error_buf_size) +{ + if (init_size > 65536) { + set_error_buf(error_buf, error_buf_size, + "memory size must be at most 65536 pages (4GiB)"); + return false; + } + return true; +} + +static bool +check_memory_max_size(uint32 init_size, uint32 max_size, + char *error_buf, uint32 error_buf_size) +{ + if (max_size < init_size) { + set_error_buf(error_buf, error_buf_size, + "size minimum must not be greater than maximum"); + return false; + } + + if (max_size > 65536) { + set_error_buf(error_buf, error_buf_size, + "memory size must be at most 65536 pages (4GiB)"); + return false; + } + return true; +} + static bool load_memory_import(const uint8 **p_buf, const uint8 *buf_end, WASMMemoryImport *memory, @@ -501,8 +531,16 @@ load_memory_import(const uint8 **p_buf, const uint8 *buf_end, read_leb_uint32(p, p_end, memory->flags); read_leb_uint32(p, p_end, memory->init_page_count); + if (!check_memory_init_size(memory->init_page_count, + error_buf, error_buf_size)) + return false; + if (memory->flags & 1) { read_leb_uint32(p, p_end, memory->max_page_count); + if (!check_memory_max_size(memory->init_page_count, + memory->max_page_count, + error_buf, error_buf_size)) + return false; if (memory->max_page_count > max_page_count) memory->max_page_count = max_page_count; } @@ -552,8 +590,16 @@ load_memory(const uint8 **p_buf, const uint8 *buf_end, WASMMemory *memory, read_leb_uint32(p, p_end, memory->flags); read_leb_uint32(p, p_end, memory->init_page_count); + if (!check_memory_init_size(memory->init_page_count, + error_buf, error_buf_size)) + return false; + if (memory->flags & 1) { read_leb_uint32(p, p_end, memory->max_page_count); + if (!check_memory_max_size(memory->init_page_count, + memory->max_page_count, + error_buf, error_buf_size)) + return false; if (memory->max_page_count > max_page_count) memory->max_page_count = max_page_count; } @@ -715,7 +761,7 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, if (type_index >= module->type_count) { set_error_buf(error_buf, error_buf_size, "Load import section failed: " - "function type index out of range."); + "unknown type."); return false; } import->u.function.func_type = module->types[type_index]; @@ -898,7 +944,7 @@ load_function_section(const uint8 *buf, const uint8 *buf_end, if (type_index >= module->type_count) { set_error_buf(error_buf, error_buf_size, "Load function section failed: " - "function type index out of range."); + "unknown type."); return false; } @@ -1017,7 +1063,7 @@ load_table_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, if (table_count) { if (table_count > 1) { set_error_buf(error_buf, error_buf_size, - "Load table section failed: multiple memories"); + "Load table section failed: multiple tables"); return false; } module->table_count = table_count; @@ -1194,7 +1240,7 @@ load_export_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, if (index >= module->function_count + module->import_function_count) { set_error_buf(error_buf, error_buf_size, "Load export section failed: " - "function index out of range."); + "unknown function."); return false; } break; @@ -1203,7 +1249,7 @@ load_export_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, if (index >= module->table_count + module->import_table_count) { set_error_buf(error_buf, error_buf_size, "Load export section failed: " - "table index out of range."); + "unknown table."); return false; } break; @@ -1212,7 +1258,7 @@ load_export_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, if (index >= module->memory_count + module->import_memory_count) { set_error_buf(error_buf, error_buf_size, "Load export section failed: " - "memory index out of range."); + "unknown memory."); return false; } break; @@ -1221,7 +1267,7 @@ load_export_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, if (index >= module->global_count + module->import_global_count) { set_error_buf(error_buf, error_buf_size, "Load export section failed: " - "global index out of range."); + "unknown global."); return false; } break; @@ -1273,7 +1319,7 @@ load_table_segment_section(const uint8 *buf, const uint8 *buf_end, WASMModule *m if (p >= p_end) { set_error_buf(error_buf, error_buf_size, "Load table segment section failed: " - "invalid value type"); + "unexpected end"); return false; } read_leb_uint32(p, p_end, table_index); @@ -1417,7 +1463,7 @@ load_start_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, if (start_function >= module->function_count + module->import_function_count) { set_error_buf(error_buf, error_buf_size, "Load start section failed: " - "function index out of range."); + "unknown function."); return false; } module->start_function = start_function; @@ -2703,7 +2749,7 @@ wasm_loader_check_br(WASMLoaderContext *ctx, uint32 depth, { if (ctx->csp_num < depth + 1) { set_error_buf(error_buf, error_buf_size, - "WASM module load failed: type mismatch: " + "WASM module load failed: unknown label, " "unexpected end of section or function"); return false; } @@ -3405,7 +3451,7 @@ fail: if (local_idx >= param_count + local_count) { \ set_error_buf(error_buf, error_buf_size, \ "WASM module load failed: " \ - "local index out of range"); \ + "unknown local."); \ goto fail; \ } \ local_type = local_idx < param_count \ @@ -3427,8 +3473,7 @@ check_memory(WASMModule *module, if (module->memory_count == 0 && module->import_memory_count == 0) { set_error_buf(error_buf, error_buf_size, - "WASM module load failed: " - "load or store in module without default memory"); + "WASM module load failed: unknown memory"); return false; } return true; @@ -3848,7 +3893,7 @@ handle_next_reachable_block: if (func_idx >= module->import_function_count + module->function_count) { set_error_buf(error_buf, error_buf_size, "WASM loader prepare bytecode failed: " - "function index out of range"); + "unknown function."); goto fail; } @@ -3888,7 +3933,7 @@ handle_next_reachable_block: && module->import_table_count == 0) { set_error_buf(error_buf, error_buf_size, "WASM loader prepare bytecode failed: " - "call indirect without default table"); + "call indirect with unknown table"); goto fail; } @@ -3911,7 +3956,7 @@ handle_next_reachable_block: if (type_idx >= module->type_count) { set_error_buf(error_buf, error_buf_size, "WASM loader prepare bytecode failed: " - "function index out of range"); + "unknown type"); goto fail; } @@ -3992,7 +4037,8 @@ handle_next_reachable_block: if (loader_ctx->stack_cell_num <= 0) { set_error_buf(error_buf, error_buf_size, "WASM loader prepare bytecode failed: " - "opcode select was found but stack was empty"); + "type mismatch, opcode select was found " + "but stack was empty"); goto fail; } @@ -4175,7 +4221,7 @@ handle_next_reachable_block: if (global_idx >= global_count) { set_error_buf(error_buf, error_buf_size, "WASM loader prepare bytecode failed: " - "global index out of range"); + "unknown global."); goto fail; } @@ -4197,7 +4243,7 @@ handle_next_reachable_block: if (global_idx >= global_count) { set_error_buf(error_buf, error_buf_size, "WASM loader prepare bytecode failed: " - "global index out of range"); + "unknown global."); goto fail; } diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index 06f4f8966..789340871 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -753,7 +753,7 @@ wasm_instantiate(WASMModule *module, for (j = 0; j < length; j++) { if (table_seg->func_indexes[j] >= module_inst->function_count) { set_error_buf(error_buf, error_buf_size, - "function index is overflow"); + "WASM instantiate failed: unknown function"); wasm_deinstantiate(module_inst); return NULL; } From eab5e4085398a6c187bcd0a20b4fff9e26a4117d Mon Sep 17 00:00:00 2001 From: Wang Xin Date: Wed, 22 Apr 2020 19:07:44 +0800 Subject: [PATCH 002/207] sample gui update (#237) --- wamr-sdk/build_sdk.sh | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/wamr-sdk/build_sdk.sh b/wamr-sdk/build_sdk.sh index 02f43e183..0b819c5db 100755 --- a/wamr-sdk/build_sdk.sh +++ b/wamr-sdk/build_sdk.sh @@ -159,9 +159,6 @@ fi echo -e "\n\n" echo "############## Start to build wasm app sdk ###############" -cd ${sdk_root}/app -rm -fr build && mkdir build -cd build # If wgl module is selected, check if the extra SDK include dir is passed by the args, prompt user to input if not. app_all_selected=`cat ${wamr_config_cmake_file} | grep WAMR_APP_BUILD_ALL` @@ -178,8 +175,15 @@ if [[ -n "${app_wgl_selected}" ]] || [[ -n "${app_all_selected}" ]]; then CM_DEXTRA_SDK_INCLUDE_PATH="-DEXTRA_SDK_INCLUDE_PATH=${extra_file_path}" fi fi + + cd ${wamr_root_dir}/core/app-framework/wgl/app + ./prepare_headers.sh fi +cd ${sdk_root}/app +rm -fr build && mkdir build +cd build + out=`grep WAMR_BUILD_LIBC_WASI ${wamr_config_cmake_file} |grep 1` if [ -n "$out" ]; then LIBC_SUPPORT="WASI" From ab4f0c541988e038b6af6a200838758a386b02a0 Mon Sep 17 00:00:00 2001 From: Lei Zhang Date: Sat, 25 Apr 2020 11:48:24 +0800 Subject: [PATCH 003/207] bugfix: check type for opcode block, loop and if (#238) (#239) Otherwise a block opcode with invalid type signature could crash the wasm loader. --- core/iwasm/interpreter/wasm_loader.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index d24babbf9..cc44e1744 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -3489,6 +3489,24 @@ check_memory(WASMModule *module, #endif /* WASM_ENABLE_FAST_INTERP */ +static bool +is_block_type_valid(uint8 type) +{ + return type == VALUE_TYPE_I32 || + type == VALUE_TYPE_I64 || + type == VALUE_TYPE_F32 || + type == VALUE_TYPE_F64 || + type == VALUE_TYPE_VOID; +} + +#define CHECK_BLOCK_TYPE(type) do { \ + if (!is_block_type_valid(type)) { \ + set_error_buf(error_buf, error_buf_size, \ + "WASM module load failed: invalid block type"); \ + goto fail; \ + } \ + } while (0) + static bool wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, BlockAddr *block_addr_cache, @@ -3576,6 +3594,7 @@ re_scan: case WASM_OP_BLOCK: /* 0x40/0x7F/0x7E/0x7D/0x7C */ block_return_type = read_uint8(p); + CHECK_BLOCK_TYPE(block_return_type); PUSH_CSP(BLOCK_TYPE_BLOCK, block_return_type, p); #if WASM_ENABLE_FAST_INTERP != 0 skip_label(); @@ -3585,6 +3604,7 @@ re_scan: case WASM_OP_LOOP: /* 0x40/0x7F/0x7E/0x7D/0x7C */ block_return_type = read_uint8(p); + CHECK_BLOCK_TYPE(block_return_type); PUSH_CSP(BLOCK_TYPE_LOOP, block_return_type, p); #if WASM_ENABLE_FAST_INTERP != 0 skip_label(); @@ -3597,6 +3617,7 @@ re_scan: POP_I32(); /* 0x40/0x7F/0x7E/0x7D/0x7C */ block_return_type = read_uint8(p); + CHECK_BLOCK_TYPE(block_return_type); PUSH_CSP(BLOCK_TYPE_IF, block_return_type, p); #if WASM_ENABLE_FAST_INTERP != 0 emit_empty_label_addr_and_frame_ip(PATCH_ELSE); From d381b0fdec04f5ca8b891c070a00fd99a785c322 Mon Sep 17 00:00:00 2001 From: wenyongh Date: Thu, 30 Apr 2020 17:52:11 +0800 Subject: [PATCH 004/207] Implement post-MVP features and native stack overflow check (#243) Implement native thread stack overflow check Implement post-MVP: Non-trapping float-to-int conversions Implement post-MVP: Sign-extension operators Enhance WASM loader checks --- build-scripts/config_common.cmake | 4 + core/config.h | 4 + core/iwasm/aot/aot_loader.c | 13 +- core/iwasm/aot/aot_runtime.c | 29 +- core/iwasm/aot/aot_runtime.h | 1 + core/iwasm/common/wasm_exec_env.c | 9 + core/iwasm/common/wasm_exec_env.h | 26 +- core/iwasm/common/wasm_native.c | 6 +- core/iwasm/common/wasm_runtime_common.c | 65 ++-- core/iwasm/compilation/aot_compiler.c | 69 ++++- core/iwasm/compilation/aot_emit_conversion.c | 281 +++++++++++++++++- core/iwasm/compilation/aot_emit_conversion.h | 16 +- core/iwasm/compilation/aot_emit_exception.c | 3 +- core/iwasm/compilation/aot_emit_function.c | 36 +++ core/iwasm/compilation/aot_emit_numberic.c | 2 +- core/iwasm/compilation/aot_llvm.c | 35 +++ core/iwasm/compilation/aot_llvm.h | 2 + core/iwasm/interpreter/wasm_interp_classic.c | 243 +++++++++++++-- core/iwasm/interpreter/wasm_interp_fast.c | 238 +++++++++++++-- core/iwasm/interpreter/wasm_loader.c | 127 ++++++-- core/iwasm/interpreter/wasm_opcode.h | 72 +++-- core/iwasm/interpreter/wasm_runtime.c | 65 ++-- core/iwasm/interpreter/wasm_runtime.h | 1 - .../libc-builtin/libc_builtin_wrapper.c | 50 +++- .../include/wasmtime_ssp.h | 21 +- core/shared/platform/alios/alios_thread.c | 6 + .../platform/android/platform_internal.h | 2 +- .../platform/common/posix/posix_thread.c | 20 ++ .../platform/darwin/platform_internal.h | 2 +- .../platform/include/platform_api_vmcore.h | 7 + core/shared/platform/linux-sgx/sgx_thread.c | 6 + .../shared/platform/linux/platform_internal.h | 2 +- .../platform/vxworks/platform_internal.h | 2 +- core/shared/platform/zephyr/zephyr_thread.c | 10 + .../vgl-native-ui-app/CMakeLists.txt | 1 + wamr-compiler/CMakeLists.txt | 2 +- 36 files changed, 1246 insertions(+), 232 deletions(-) diff --git a/build-scripts/config_common.cmake b/build-scripts/config_common.cmake index 2ec4d64fa..dc8f59d3f 100644 --- a/build-scripts/config_common.cmake +++ b/build-scripts/config_common.cmake @@ -124,3 +124,7 @@ else () message (" Fast interpreter disabled") endif () +if (WAMR_BUILD_SPEC_TEST EQUAL 1) + add_definitions (-DWASM_ENABLE_SPEC_TEST=1) + message (" spec test compatible mode is on") +endif() diff --git a/core/config.h b/core/config.h index 29ebe27eb..25d546c33 100644 --- a/core/config.h +++ b/core/config.h @@ -179,6 +179,10 @@ enum { #define APP_THREAD_STACK_SIZE_MAX (256 * 1024) #endif +/* Reserved bytes to the native thread stack boundary, throw native + stack overflow exception if the guard boudary is reached */ +#define RESERVED_BYTES_TO_NATIVE_STACK_BOUNDARY (512) + /* Default wasm block address cache size and conflict list size */ #define BLOCK_ADDR_CACHE_SIZE 64 #define BLOCK_ADDR_CONFLICT_SIZE 2 diff --git a/core/iwasm/aot/aot_loader.c b/core/iwasm/aot/aot_loader.c index f4115bbd0..a68f8e96c 100644 --- a/core/iwasm/aot/aot_loader.c +++ b/core/iwasm/aot/aot_loader.c @@ -942,8 +942,7 @@ load_init_data_section(const uint8 *buf, const uint8 *buf_end, /* check start function index */ if (module->start_func_index != (uint32)-1 - && (module->start_func_index < module->import_func_count - || module->start_func_index >= module->import_func_count + && (module->start_func_index >= module->import_func_count + module->func_count)) { set_error_buf(error_buf, error_buf_size, "AOT module load failed: " @@ -1044,9 +1043,13 @@ load_function_section(const uint8 *buf, const uint8 *buf_end, /* Set start function when function pointers are resolved */ if (module->start_func_index != (uint32)-1) { - module->start_function = - module->func_ptrs[module->start_func_index - - module->import_func_count]; + if (module->start_func_index >= module->import_func_count) + module->start_function = + module->func_ptrs[module->start_func_index + - module->import_func_count]; + else + /* TODO: fix start function can be import function issue */ + module->start_function = NULL; } else { module->start_function = NULL; diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index 09b1a38d3..308e545c8 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -39,7 +39,11 @@ global_instantiate(AOTModuleInstance *module_inst, AOTModule *module, init_expr = &global->init_expr; switch (init_expr->init_expr_type) { case INIT_EXPR_TYPE_GET_GLOBAL: - bh_assert(init_expr->u.global_index < module->import_global_count); + if (init_expr->u.global_index >= module->import_global_count + i) { + set_error_buf(error_buf, error_buf_size, + "Instantiate global failed: unknown global."); + return false; + } memcpy(p, &module->import_globals[init_expr->u.global_index].global_data_linked, global->size); @@ -501,6 +505,9 @@ aot_create_exec_env_and_call_function(AOTModuleInstance *module_inst, return false; } + /* set thread handle and stack boundary */ + wasm_exec_env_set_thread_info(exec_env); + ret = aot_call_function(exec_env, func, argc, argv); wasm_exec_env_destroy(exec_env); return ret; @@ -556,6 +563,9 @@ aot_set_exception_with_id(AOTModuleInstance *module_inst, case EXCE_CALL_UNLINKED_IMPORT_FUNC: aot_set_exception(module_inst, "fail to call unlinked import function"); break; + case EXCE_NATIVE_STACK_OVERFLOW: + aot_set_exception(module_inst, "native stack overflow"); + break; default: break; } @@ -662,10 +672,12 @@ void * aot_addr_app_to_native(AOTModuleInstance *module_inst, int32 app_offset) { int32 memory_data_size = (int32)module_inst->memory_data_size; + uint8 *addr = (uint8 *)module_inst->memory_data.ptr + app_offset; - if (module_inst->heap_base_offset < app_offset - && app_offset < memory_data_size) - return (uint8*)module_inst->memory_data.ptr + app_offset; + if ((uint8*)module_inst->heap_data.ptr < addr + && addr < (uint8*)module_inst->memory_data.ptr + + memory_data_size) + return addr; return NULL; } @@ -929,6 +941,15 @@ aot_call_indirect(WASMExecEnv *exec_env, } } + /* this function is called from native code, so exec_env->handle and + exec_env->native_stack_boundary must have been set, we don't set + it again */ + + if ((uint8*)&module_inst < exec_env->native_stack_boundary) { + aot_set_exception_with_id(module_inst, EXCE_NATIVE_STACK_OVERFLOW); + return false; + } + return wasm_runtime_invoke_native(exec_env, func_ptr, func_type, signature, attachment, argv, argc, argv); diff --git a/core/iwasm/aot/aot_runtime.h b/core/iwasm/aot/aot_runtime.h index 0239fe35f..41f9b7a85 100644 --- a/core/iwasm/aot/aot_runtime.h +++ b/core/iwasm/aot/aot_runtime.h @@ -30,6 +30,7 @@ typedef enum AOTExceptionID { EXCE_UNDEFINED_ELEMENT, EXCE_UNINITIALIZED_ELEMENT, EXCE_CALL_UNLINKED_IMPORT_FUNC, + EXCE_NATIVE_STACK_OVERFLOW, EXCE_NUM, } AOTExceptionID; diff --git a/core/iwasm/common/wasm_exec_env.c b/core/iwasm/common/wasm_exec_env.c index 895cdaea1..814301a00 100644 --- a/core/iwasm/common/wasm_exec_env.c +++ b/core/iwasm/common/wasm_exec_env.c @@ -50,3 +50,12 @@ wasm_exec_env_get_module_inst(WASMExecEnv *exec_env) return exec_env->module_inst; } +void +wasm_exec_env_set_thread_info(WASMExecEnv *exec_env) +{ + exec_env->handle = os_self_thread(); + exec_env->native_stack_boundary = os_thread_get_stack_boundary() + + RESERVED_BYTES_TO_NATIVE_STACK_BOUNDARY; + +} + diff --git a/core/iwasm/common/wasm_exec_env.h b/core/iwasm/common/wasm_exec_env.h index 6d3c19d8f..c6d14df51 100644 --- a/core/iwasm/common/wasm_exec_env.h +++ b/core/iwasm/common/wasm_exec_env.h @@ -20,12 +20,15 @@ struct WASMInterpFrame; /* Execution environment */ typedef struct WASMExecEnv { - /* Next thread's exec env of a WASM module instance. */ + /* Next thread's exec env of a WASM module instance. */ struct WASMExecEnv *next; - /* Previous thread's exec env of a WASM module instance. */ + /* Previous thread's exec env of a WASM module instance. */ struct WASMExecEnv *prev; + /* Note: field module_inst, argv_buf and native_stack_boundary + are used by AOTed code, don't change the places of them */ + /* The WASM module instance of current thread */ struct WASMModuleInstanceCommon *module_inst; @@ -33,6 +36,11 @@ typedef struct WASMExecEnv { uint32 *argv_buf; #endif + /* The boundary of native stack. When runtime detects that native + frame may overrun this boundary, it throws stack overflow + exception. */ + uint8 *native_stack_boundary; + /* attachment for native function */ void *attachment; @@ -48,11 +56,6 @@ typedef struct WASMExecEnv { BlockAddr block_addr_cache[BLOCK_ADDR_CACHE_SIZE][BLOCK_ADDR_CONFLICT_SIZE]; #endif - /* The boundary of native stack. When interpreter detects that native - frame may overrun this boundary, it throws a stack overflow - exception. */ - void *native_stack_boundary; - /* The WASM stack size */ uint32 wasm_stack_size; @@ -61,13 +64,13 @@ typedef struct WASMExecEnv { uint64 __make_it_8_byte_aligned_; struct { - /* The top boundary of the stack. */ + /* The top boundary of the stack. */ uint8 *top_boundary; - /* Top cell index which is free. */ + /* Top cell index which is free. */ uint8 *top; - /* The Java stack. */ + /* The WASM stack. */ uint8 bottom[1]; } s; } wasm_stack; @@ -159,6 +162,9 @@ wasm_exec_env_get_cur_frame(WASMExecEnv *exec_env) struct WASMModuleInstanceCommon * wasm_exec_env_get_module_inst(WASMExecEnv *exec_env); +void +wasm_exec_env_set_thread_info(WASMExecEnv *exec_env); + #ifdef __cplusplus } #endif diff --git a/core/iwasm/common/wasm_native.c b/core/iwasm/common/wasm_native.c index d92271a9a..2a2c41c1c 100644 --- a/core/iwasm/common/wasm_native.c +++ b/core/iwasm/common/wasm_native.c @@ -14,8 +14,10 @@ static NativeSymbolsList g_native_symbols_list_end = NULL; uint32 get_libc_builtin_export_apis(NativeSymbol **p_libc_builtin_apis); +#if WASM_ENABLE_SPEC_TEST != 0 uint32 get_spectest_export_apis(NativeSymbol **p_libc_builtin_apis); +#endif uint32 get_libc_wasi_export_apis(NativeSymbol **p_libc_wasi_apis); @@ -242,11 +244,13 @@ wasm_native_init() native_symbols, n_native_symbols)) return false; +#if WASM_ENABLE_SPEC_TEST n_native_symbols = get_spectest_export_apis(&native_symbols); if (!wasm_native_register_natives("spectest", native_symbols, n_native_symbols)) return false; -#endif +#endif /* WASM_ENABLE_SPEC_TEST */ +#endif /* WASM_ENABLE_LIBC_BUILTIN */ #if WASM_ENABLE_LIBC_WASI != 0 n_native_symbols = get_libc_wasi_export_apis(&native_symbols); diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index 276e21b0a..1db69b462 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -292,7 +292,8 @@ wasm_runtime_call_wasm(WASMExecEnv *exec_env, return false; } - exec_env->handle = os_self_thread(); + /* set thread handle and stack boundary */ + wasm_exec_env_set_thread_info(exec_env); #if WASM_ENABLE_INTERP != 0 if (exec_env->module_inst->module_type == Wasm_Module_Bytecode) @@ -1410,37 +1411,39 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, } /* print return value */ - switch (type->types[type->param_count]) { - case VALUE_TYPE_I32: - os_printf("0x%x:i32", argv1[0]); - break; - case VALUE_TYPE_I64: - { - union { uint64 val; uint32 parts[2]; } u; - u.parts[0] = argv1[0]; - u.parts[1] = argv1[1]; + if (type->result_count > 0) { + switch (type->types[type->param_count]) { + case VALUE_TYPE_I32: + os_printf("0x%x:i32", argv1[0]); + break; + case VALUE_TYPE_I64: + { + union { uint64 val; uint32 parts[2]; } u; + u.parts[0] = argv1[0]; + u.parts[1] = argv1[1]; #ifdef PRIx64 - os_printf("0x%"PRIx64":i64", u.val); + os_printf("0x%"PRIx64":i64", u.val); #else - char buf[16]; - if (sizeof(long) == 4) - snprintf(buf, sizeof(buf), "%s", "0x%llx:i64"); - else - snprintf(buf, sizeof(buf), "%s", "0x%lx:i64"); - os_printf(buf, u.val); + char buf[16]; + if (sizeof(long) == 4) + snprintf(buf, sizeof(buf), "%s", "0x%llx:i64"); + else + snprintf(buf, sizeof(buf), "%s", "0x%lx:i64"); + os_printf(buf, u.val); #endif - break; - } - case VALUE_TYPE_F32: - os_printf("%.7g:f32", *(float32*)argv1); - break; - case VALUE_TYPE_F64: - { - union { float64 val; uint32 parts[2]; } u; - u.parts[0] = argv1[0]; - u.parts[1] = argv1[1]; - os_printf("%.7g:f64", u.val); - break; + break; + } + case VALUE_TYPE_F32: + os_printf("%.7g:f32", *(float32*)argv1); + break; + case VALUE_TYPE_F64: + { + union { float64 val; uint32 parts[2]; } u; + u.parts[0] = argv1[0]; + u.parts[1] = argv1[1]; + os_printf("%.7g:f64", u.val); + break; + } } } os_printf("\n"); @@ -2148,7 +2151,9 @@ wasm_runtime_call_indirect(WASMExecEnv *exec_env, return false; } - exec_env->handle = os_self_thread(); + /* this function is called from native code, so exec_env->handle and + exec_env->native_stack_boundary must have been set, we don't set + it again */ #if WASM_ENABLE_INTERP != 0 if (exec_env->module_inst->module_type == Wasm_Module_Bytecode) diff --git a/core/iwasm/compilation/aot_compiler.c b/core/iwasm/compilation/aot_compiler.c index 21f85f37d..15fc1dd2c 100644 --- a/core/iwasm/compilation/aot_compiler.c +++ b/core/iwasm/compilation/aot_compiler.c @@ -595,14 +595,14 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index) case WASM_OP_I32_TRUNC_S_F32: case WASM_OP_I32_TRUNC_U_F32: sign = (opcode == WASM_OP_I32_TRUNC_S_F32) ? true : false; - if (!aot_compile_op_i32_trunc_f32(comp_ctx, func_ctx, sign)) + if (!aot_compile_op_i32_trunc_f32(comp_ctx, func_ctx, sign, false)) return false; break; case WASM_OP_I32_TRUNC_S_F64: case WASM_OP_I32_TRUNC_U_F64: sign = (opcode == WASM_OP_I32_TRUNC_S_F64) ? true : false; - if (!aot_compile_op_i32_trunc_f64(comp_ctx, func_ctx, sign)) + if (!aot_compile_op_i32_trunc_f64(comp_ctx, func_ctx, sign, false)) return false; break; @@ -616,14 +616,14 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index) case WASM_OP_I64_TRUNC_S_F32: case WASM_OP_I64_TRUNC_U_F32: sign = (opcode == WASM_OP_I64_TRUNC_S_F32) ? true : false; - if (!aot_compile_op_i64_trunc_f32(comp_ctx, func_ctx, sign)) + if (!aot_compile_op_i64_trunc_f32(comp_ctx, func_ctx, sign, false)) return false; break; case WASM_OP_I64_TRUNC_S_F64: case WASM_OP_I64_TRUNC_U_F64: sign = (opcode == WASM_OP_I64_TRUNC_S_F64) ? true : false; - if (!aot_compile_op_i64_trunc_f64(comp_ctx, func_ctx, sign)) + if (!aot_compile_op_i64_trunc_f64(comp_ctx, func_ctx, sign, false)) return false; break; @@ -685,6 +685,67 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index) return false; break; + case WASM_OP_I32_EXTEND8_S: + if (!aot_compile_op_i32_extend_i32(comp_ctx, func_ctx, 8)) + return false; + break; + + case WASM_OP_I32_EXTEND16_S: + if (!aot_compile_op_i32_extend_i32(comp_ctx, func_ctx, 16)) + return false; + break; + + case WASM_OP_I64_EXTEND8_S: + if (!aot_compile_op_i64_extend_i64(comp_ctx, func_ctx, 8)) + return false; + break; + + case WASM_OP_I64_EXTEND16_S: + if (!aot_compile_op_i64_extend_i64(comp_ctx, func_ctx, 16)) + return false; + break; + + case WASM_OP_I64_EXTEND32_S: + if (!aot_compile_op_i64_extend_i64(comp_ctx, func_ctx, 32)) + return false; + break; + + case WASM_OP_MISC_PREFIX: + { + if (frame_ip < frame_ip_end) { + opcode = *frame_ip++; + } + + switch (opcode) { + case WASM_OP_I32_TRUNC_SAT_S_F32: + case WASM_OP_I32_TRUNC_SAT_U_F32: + sign = (opcode == WASM_OP_I32_TRUNC_SAT_S_F32) ? true : false; + if (!aot_compile_op_i32_trunc_f32(comp_ctx, func_ctx, sign, true)) + return false; + break; + case WASM_OP_I32_TRUNC_SAT_S_F64: + case WASM_OP_I32_TRUNC_SAT_U_F64: + sign = (opcode == WASM_OP_I32_TRUNC_SAT_S_F64) ? true : false; + if (!aot_compile_op_i32_trunc_f64(comp_ctx, func_ctx, sign, true)) + return false; + break; + case WASM_OP_I64_TRUNC_SAT_S_F32: + case WASM_OP_I64_TRUNC_SAT_U_F32: + sign = (opcode == WASM_OP_I64_TRUNC_SAT_S_F32) ? true : false; + if (!aot_compile_op_i64_trunc_f32(comp_ctx, func_ctx, sign, true)) + return false; + break; + case WASM_OP_I64_TRUNC_SAT_S_F64: + case WASM_OP_I64_TRUNC_SAT_U_F64: + sign = (opcode == WASM_OP_I64_TRUNC_SAT_S_F64) ? true : false; + if (!aot_compile_op_i64_trunc_f64(comp_ctx, func_ctx, sign, true)) + return false; + break; + default: + break; + } + } + default: break; } diff --git a/core/iwasm/compilation/aot_emit_conversion.c b/core/iwasm/compilation/aot_emit_conversion.c index 706c267b1..7dcb928b2 100644 --- a/core/iwasm/compilation/aot_emit_conversion.c +++ b/core/iwasm/compilation/aot_emit_conversion.c @@ -89,6 +89,156 @@ fail: return false; } +#define ADD_BASIC_BLOCK(block, name) do { \ + if (!(block = LLVMAppendBasicBlockInContext(comp_ctx->context, \ + func_ctx->func, \ + name))) { \ + aot_set_last_error("llvm add basic block failed."); \ + goto fail; \ + } \ + \ + LLVMMoveBasicBlockAfter(block, LLVMGetInsertBlock(comp_ctx->builder)); \ +} while (0) + +static bool +trunc_sat_float_to_int(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, + LLVMValueRef operand, LLVMTypeRef dest_type, + LLVMValueRef min_value, LLVMValueRef max_value, + char *name, bool sign) +{ + LLVMBasicBlockRef check_nan_succ, check_less_succ, check_greater_succ; + LLVMBasicBlockRef is_nan_block, is_less_block, is_greater_block, res_block; + LLVMValueRef is_less, is_greater, res, phi; + LLVMValueRef zero = (dest_type == I32_TYPE) ? I32_ZERO : I64_ZERO; + LLVMValueRef vmin, vmax; + + if (!(res = LLVMBuildFCmp(comp_ctx->builder, LLVMRealUNO, + operand, operand, "fcmp_is_nan"))) { + aot_set_last_error("llvm build fcmp failed."); + goto fail; + } + + ADD_BASIC_BLOCK(check_nan_succ, "check_nan_succ"); + ADD_BASIC_BLOCK(is_nan_block, "is_nan_block"); + ADD_BASIC_BLOCK(check_less_succ, "check_less_succ"); + ADD_BASIC_BLOCK(is_less_block, "is_less_block"); + ADD_BASIC_BLOCK(check_greater_succ, "check_greater_succ"); + ADD_BASIC_BLOCK(is_greater_block, "is_greater_block"); + ADD_BASIC_BLOCK(res_block, "res_block"); + + if (!LLVMBuildCondBr(comp_ctx->builder, res, + is_nan_block, check_nan_succ)) { + aot_set_last_error("llvm build cond br failed."); + goto fail; + } + + /* Start to translate is_nan block */ + LLVMPositionBuilderAtEnd(comp_ctx->builder, is_nan_block); + if (!LLVMBuildBr(comp_ctx->builder, res_block)) { + aot_set_last_error("llvm build br failed."); + goto fail; + } + + /* Start to translate check_nan_succ block */ + LLVMPositionBuilderAtEnd(comp_ctx->builder, check_nan_succ); + if (!(is_less = LLVMBuildFCmp(comp_ctx->builder, LLVMRealOLE, operand, + min_value, "fcmp_min_value"))) { + aot_set_last_error("llvm build fcmp failed."); + goto fail; + } + if (!LLVMBuildCondBr(comp_ctx->builder, is_less, + is_less_block, check_less_succ)) { + aot_set_last_error("llvm build cond br failed."); + goto fail; + } + + /* Start to translate is_less block */ + LLVMPositionBuilderAtEnd(comp_ctx->builder, is_less_block); + if (!LLVMBuildBr(comp_ctx->builder, res_block)) { + aot_set_last_error("llvm build br failed."); + goto fail; + } + + /* Start to translate check_less_succ block */ + LLVMPositionBuilderAtEnd(comp_ctx->builder, check_less_succ); + if (!(is_greater = LLVMBuildFCmp(comp_ctx->builder, LLVMRealOGE, operand, + max_value, "fcmp_max_value"))) { + aot_set_last_error("llvm build fcmp failed."); + goto fail; + } + if (!LLVMBuildCondBr(comp_ctx->builder, is_greater, + is_greater_block, check_greater_succ)) { + aot_set_last_error("llvm build cond br failed."); + goto fail; + } + + /* Start to translate is_greater block */ + LLVMPositionBuilderAtEnd(comp_ctx->builder, is_greater_block); + if (!LLVMBuildBr(comp_ctx->builder, res_block)) { + aot_set_last_error("llvm build br failed."); + goto fail; + } + + /* Start to translate check_greater_succ block */ + LLVMPositionBuilderAtEnd(comp_ctx->builder, check_greater_succ); + if (sign) + res = LLVMBuildFPToSI(comp_ctx->builder, operand, dest_type, name); + else + res = LLVMBuildFPToUI(comp_ctx->builder, operand, dest_type, name); + if (!res) { + aot_set_last_error("llvm build conversion failed."); + return false; + } + if (!LLVMBuildBr(comp_ctx->builder, res_block)) { + aot_set_last_error("llvm build br failed."); + goto fail; + } + + /* Start to translate res_block */ + LLVMPositionBuilderAtEnd(comp_ctx->builder, res_block); + /* Create result phi */ + if (!(phi = LLVMBuildPhi(comp_ctx->builder, + dest_type, + "trunc_sat_result_phi"))) { + aot_set_last_error("llvm build phi failed."); + return false; + } + + /* Add phi incoming values */ + if (dest_type == I32_TYPE) { + if (sign) { + vmin = I32_CONST(INT32_MIN); + vmax = I32_CONST(INT32_MAX); + } + else { + vmin = I32_CONST(0); + vmax = I32_CONST(UINT32_MAX); + } + } + else if (dest_type == I64_TYPE) { + if (sign) { + vmin = I64_CONST(INT64_MIN); + vmax = I64_CONST(INT64_MAX); + } + else { + vmin = I64_CONST(0); + vmax = I64_CONST(UINT64_MAX); + } + } + LLVMAddIncoming(phi, &zero, &is_nan_block, 1); + LLVMAddIncoming(phi, &vmin, &is_less_block, 1); + LLVMAddIncoming(phi, &vmax, &is_greater_block, 1); + LLVMAddIncoming(phi, &res, &check_greater_succ, 1); + + if (dest_type == I32_TYPE) + PUSH_I32(phi); + else if (dest_type == I64_TYPE) + PUSH_I64(phi); + return true; +fail: + return false; +} + bool aot_compile_op_i32_wrap_i64(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) { @@ -109,7 +259,7 @@ fail: bool aot_compile_op_i32_trunc_f32(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, - bool sign) + bool sign, bool saturating) { LLVMValueRef value; LLVMValueRef min_value, max_value; @@ -125,16 +275,22 @@ aot_compile_op_i32_trunc_f32(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, max_value = F32_CONST(4294967296.0f); } - return trunc_float_to_int(comp_ctx, func_ctx, value, - I32_TYPE, min_value, max_value, - sign ? "i32_trunc_f32_s" : "i32_trunc_f32_u", sign); + if (!saturating) + return trunc_float_to_int(comp_ctx, func_ctx, value, + I32_TYPE, min_value, max_value, + sign ? "i32_trunc_f32_s" : "i32_trunc_f32_u", sign); + else + return trunc_sat_float_to_int(comp_ctx, func_ctx, value, + I32_TYPE, min_value, max_value, + sign ? "i32_trunc_sat_f32_s" : + "i32_trunc_sat_f32_u", sign); fail: return false; } bool aot_compile_op_i32_trunc_f64(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, - bool sign) + bool sign, bool saturating) { LLVMValueRef value; LLVMValueRef min_value, max_value; @@ -150,9 +306,15 @@ aot_compile_op_i32_trunc_f64(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, max_value = F64_CONST(4294967296.0); } - return trunc_float_to_int(comp_ctx, func_ctx, value, - I32_TYPE, min_value, max_value, - sign ? "i32_trunc_f64_s" : "i32_trunc_f64_u", sign); + if (!saturating) + return trunc_float_to_int(comp_ctx, func_ctx, value, + I32_TYPE, min_value, max_value, + sign ? "i32_trunc_f64_s" : "i32_trunc_f64_u", sign); + else + return trunc_sat_float_to_int(comp_ctx, func_ctx, value, + I32_TYPE, min_value, max_value, + sign ? "i32_trunc_sat_f64_s" : + "i32_trunc_sat_f64_u", sign); fail: return false; } @@ -180,9 +342,83 @@ fail: return false; } +bool +aot_compile_op_i64_extend_i64(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, + int8 bitwidth) +{ + LLVMValueRef value, res, cast_value = NULL; + + POP_I64(value); + + if (bitwidth == 8) { + cast_value = LLVMBuildIntCast2(comp_ctx->builder, value, + INT8_TYPE, true, "i8_intcast_i64"); + } + else if (bitwidth == 16) { + cast_value = LLVMBuildIntCast2(comp_ctx->builder, value, + INT16_TYPE, true, "i16_intcast_i64"); + } + else if (bitwidth == 32) { + cast_value = LLVMBuildIntCast2(comp_ctx->builder, value, + I32_TYPE, true, "i32_intcast_i64"); + } + + if (!cast_value) { + aot_set_last_error("llvm build conversion failed."); + return false; + } + + res = LLVMBuildSExt(comp_ctx->builder, cast_value, I64_TYPE, "i64_extend_i64_s"); + + if (!res) { + aot_set_last_error("llvm build conversion failed."); + return false; + } + + PUSH_I64(res); + return true; +fail: + return false; +} + +bool +aot_compile_op_i32_extend_i32(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, + int8 bitwidth) +{ + LLVMValueRef value, res, cast_value = NULL; + + POP_I32(value); + + if (bitwidth == 8) { + cast_value = LLVMBuildIntCast2(comp_ctx->builder, value, + INT8_TYPE, true, "i8_intcast_i32"); + } + else if (bitwidth == 16) { + cast_value = LLVMBuildIntCast2(comp_ctx->builder, value, + INT16_TYPE, true, "i16_intcast_i32"); + } + + if (!cast_value) { + aot_set_last_error("llvm build conversion failed."); + return false; + } + + res = LLVMBuildSExt(comp_ctx->builder, cast_value, I32_TYPE, "i32_extend_i32_s"); + + if (!res) { + aot_set_last_error("llvm build conversion failed."); + return false; + } + + PUSH_I32(res); + return true; +fail: + return false; +} + bool aot_compile_op_i64_trunc_f32(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, - bool sign) + bool sign, bool saturating) { LLVMValueRef value; LLVMValueRef min_value, max_value; @@ -198,16 +434,22 @@ aot_compile_op_i64_trunc_f32(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, max_value = F32_CONST(18446744073709551616.0f); } - return trunc_float_to_int(comp_ctx, func_ctx, value, - I64_TYPE, min_value, max_value, - sign ? "i64_trunc_f32_s" : "i64_trunc_f32_u", sign); + if (!saturating) + return trunc_float_to_int(comp_ctx, func_ctx, value, + I64_TYPE, min_value, max_value, + sign ? "i64_trunc_f32_s" : "i64_trunc_f32_u", sign); + else + return trunc_sat_float_to_int(comp_ctx, func_ctx, value, + I64_TYPE, min_value, max_value, + sign ? "i64_trunc_sat_f32_s" : + "i64_trunc_sat_f32_u", sign); fail: return false; } bool aot_compile_op_i64_trunc_f64(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, - bool sign) + bool sign, bool saturating) { LLVMValueRef value; LLVMValueRef min_value, max_value; @@ -223,9 +465,16 @@ aot_compile_op_i64_trunc_f64(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, max_value = F64_CONST(18446744073709551616.0); } - return trunc_float_to_int(comp_ctx, func_ctx, value, - I64_TYPE, min_value, max_value, - sign ? "i64_trunc_f64_s" : "i64_trunc_f64_u", sign); + if (!saturating) + return trunc_float_to_int(comp_ctx, func_ctx, value, + I64_TYPE, min_value, max_value, + sign ? "i64_trunc_f64_s" : "i64_trunc_f64_u", sign); + else + return trunc_sat_float_to_int(comp_ctx, func_ctx, value, + I64_TYPE, min_value, max_value, + sign ? "i64_trunc_sat_f64_s" : + "i64_trunc_sat_f64_u", sign); + fail: return false; } diff --git a/core/iwasm/compilation/aot_emit_conversion.h b/core/iwasm/compilation/aot_emit_conversion.h index d12ffe615..da8023178 100644 --- a/core/iwasm/compilation/aot_emit_conversion.h +++ b/core/iwasm/compilation/aot_emit_conversion.h @@ -17,23 +17,31 @@ aot_compile_op_i32_wrap_i64(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx); bool aot_compile_op_i32_trunc_f32(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, - bool sign); + bool sign, bool saturating); bool aot_compile_op_i32_trunc_f64(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, - bool sign); + bool sign, bool saturating); bool aot_compile_op_i64_extend_i32(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, bool sign); +bool +aot_compile_op_i64_extend_i64(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, + int8 bitwidth); + +bool +aot_compile_op_i32_extend_i32(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, + int8 bitwidth); + bool aot_compile_op_i64_trunc_f32(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, - bool sign); + bool sign, bool saturating); bool aot_compile_op_i64_trunc_f64(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, - bool sign); + bool sign, bool saturating); bool aot_compile_op_f32_convert_i32(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, diff --git a/core/iwasm/compilation/aot_emit_exception.c b/core/iwasm/compilation/aot_emit_exception.c index 408990485..8c9e24b6c 100644 --- a/core/iwasm/compilation/aot_emit_exception.c +++ b/core/iwasm/compilation/aot_emit_exception.c @@ -17,7 +17,8 @@ static char *exce_block_names[] = { "exce_invalid_func_idx", /* EXCE_INVALID_FUNCTION_INDEX */ "exce_undefined_element", /* EXCE_UNDEFINED_ELEMENT */ "exce_uninit_element", /* EXCE_UNINITIALIZED_ELEMENT */ - "exce_call_unlinked" /* EXCE_CALL_UNLINKED_IMPORT_FUNC */ + "exce_call_unlinked", /* EXCE_CALL_UNLINKED_IMPORT_FUNC */ + "exce_native_stack_overflow" /* EXCE_NATIVE_STACK_OVERFLOW */ }; bool diff --git a/core/iwasm/compilation/aot_emit_function.c b/core/iwasm/compilation/aot_emit_function.c index dfcff55b6..2228177a1 100644 --- a/core/iwasm/compilation/aot_emit_function.c +++ b/core/iwasm/compilation/aot_emit_function.c @@ -255,6 +255,39 @@ call_aot_invoke_native_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, return true; } +static bool +check_stack_boundary(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) +{ + LLVMBasicBlockRef block_curr = LLVMGetInsertBlock(comp_ctx->builder); + LLVMBasicBlockRef check_stack; + LLVMValueRef cmp; + + if (!(check_stack = LLVMAppendBasicBlockInContext(comp_ctx->context, + func_ctx->func, + "check_stack"))) { + aot_set_last_error("llvm add basic block failed."); + return false; + } + + LLVMMoveBasicBlockAfter(check_stack, block_curr); + + if (!(cmp = LLVMBuildICmp(comp_ctx->builder, LLVMIntULT, + func_ctx->last_alloca, func_ctx->native_stack_bound, + "cmp"))) { + aot_set_last_error("llvm build icmp failed."); + return false; + } + + if (!aot_emit_exception(comp_ctx, func_ctx, + EXCE_NATIVE_STACK_OVERFLOW, + true, cmp, check_stack)) { + return false; + } + + LLVMPositionBuilderAtEnd(comp_ctx->builder, check_stack); + return true; +} + bool aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, uint32 func_idx, uint8 **p_frame_ip) @@ -347,6 +380,9 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, else { func = func_ctxes[func_idx - import_func_count]->func; + if (!check_stack_boundary(comp_ctx, func_ctx)) + goto fail; + /* Call the function */ if (!(value_ret = LLVMBuildCall(comp_ctx->builder, func, param_values, (uint32)param_count + 1, diff --git a/core/iwasm/compilation/aot_emit_numberic.c b/core/iwasm/compilation/aot_emit_numberic.c index de50db3d0..fc6a51382 100644 --- a/core/iwasm/compilation/aot_emit_numberic.c +++ b/core/iwasm/compilation/aot_emit_numberic.c @@ -27,7 +27,7 @@ #define ADD_BASIC_BLOCK(block, name) do { \ if (!(block = LLVMAppendBasicBlockInContext(comp_ctx->context, \ func_ctx->func, \ - name))) { \ + name))) { \ aot_set_last_error("llvm add basic block failed."); \ goto fail; \ } \ diff --git a/core/iwasm/compilation/aot_llvm.c b/core/iwasm/compilation/aot_llvm.c index f1776d124..c67758a7c 100644 --- a/core/iwasm/compilation/aot_llvm.c +++ b/core/iwasm/compilation/aot_llvm.c @@ -5,6 +5,7 @@ #include "aot_llvm.h" #include "aot_compiler.h" +#include "aot_emit_exception.h" #include "../aot/aot_runtime.h" @@ -451,6 +452,7 @@ aot_create_func_context(AOTCompData *comp_data, AOTCompContext *comp_ctx, LLVMTypeRef int8_ptr_type, int32_ptr_type; LLVMValueRef aot_inst_offset = I32_TWO, aot_inst_addr; LLVMValueRef argv_buf_offset = I32_THREE, argv_buf_addr; + LLVMValueRef stack_bound_offset = I32_FOUR, stack_bound_addr; char local_name[32]; uint64 size; uint32 i, j = 0; @@ -526,6 +528,21 @@ aot_create_func_context(AOTCompData *comp_data, AOTCompContext *comp_ctx, goto fail; } + /* Get native stack boundary address */ + if (!(stack_bound_addr = + LLVMBuildInBoundsGEP(comp_ctx->builder, func_ctx->exec_env, + &stack_bound_offset, 1, "stack_bound_addr"))) { + aot_set_last_error("llvm build in bounds gep failed"); + goto fail; + } + + if (!(func_ctx->native_stack_bound = + LLVMBuildLoad(comp_ctx->builder, + stack_bound_addr, "native_stack_bound"))) { + aot_set_last_error("llvm build load failed"); + goto fail; + } + for (i = 0; i < aot_func_type->param_count; i++, j++) { snprintf(local_name, sizeof(local_name), "l%d", i); func_ctx->locals[i] = @@ -580,6 +597,24 @@ aot_create_func_context(AOTCompData *comp_data, AOTCompContext *comp_ctx, } } + if (aot_func_type->param_count + func->local_count > 0) { + func_ctx->last_alloca = func_ctx->locals[aot_func_type->param_count + + func->local_count - 1]; + if (!(func_ctx->last_alloca = + LLVMBuildBitCast(comp_ctx->builder, func_ctx->last_alloca, + INT8_PTR_TYPE, "stack_ptr"))) { + aot_set_last_error("llvm build bit cast failed."); + goto fail; + } + } + else { + if (!(func_ctx->last_alloca = LLVMBuildAlloca(comp_ctx->builder, INT8_TYPE, + "stack_ptr"))) { + aot_set_last_error("llvm build alloca failed."); + goto fail; + } + } + if (!(int8_ptr_type = LLVMPointerType(INT8_PTR_TYPE, 0))) { aot_set_last_error("llvm add pointer type failed."); goto fail; diff --git a/core/iwasm/compilation/aot_llvm.h b/core/iwasm/compilation/aot_llvm.h index c97cd4855..e671b1c6a 100644 --- a/core/iwasm/compilation/aot_llvm.h +++ b/core/iwasm/compilation/aot_llvm.h @@ -102,6 +102,8 @@ typedef struct AOTFuncContext { LLVMValueRef aot_inst; LLVMValueRef table_base; LLVMValueRef argv_buf; + LLVMValueRef native_stack_bound; + LLVMValueRef last_alloca; LLVMValueRef heap_base_offset; LLVMValueRef mem_base_addr; diff --git a/core/iwasm/interpreter/wasm_interp_classic.c b/core/iwasm/interpreter/wasm_interp_classic.c index 3e7b302b7..dea86c1bc 100644 --- a/core/iwasm/interpreter/wasm_interp_classic.c +++ b/core/iwasm/interpreter/wasm_interp_classic.c @@ -606,18 +606,128 @@ read_leb(const uint8 *buf, uint32 *p_offset, uint32 maxbits, bool sign) PUSH_##src_op_type(method(val)); \ } while (0) -#define DEF_OP_TRUNC(dst_type, dst_op_type, src_type, src_op_type, \ - min_cond, max_cond) do { \ - src_type value = POP_##src_op_type(); \ - if (isnan(value)) { \ - wasm_set_exception(module, "invalid conversion to integer"); \ - goto got_exception; \ - } \ - else if (value min_cond || value max_cond) { \ - wasm_set_exception(module, "integer overflow"); \ - goto got_exception; \ - } \ - PUSH_##dst_op_type(((dst_type)value)); \ +#define TRUNC_FUNCTION(func_name, src_type, dst_type, signed_type) \ +static dst_type \ +func_name(src_type src_value, src_type src_min, src_type src_max, \ + dst_type dst_min, dst_type dst_max, bool is_sign) \ +{ \ + dst_type dst_value = 0; \ + if (!isnan(src_value)) { \ + if (src_value <= src_min) \ + dst_value = dst_min; \ + else if (src_value >= src_max) \ + dst_value = dst_max; \ + else { \ + if (is_sign) \ + dst_value = (dst_type)(signed_type)src_value; \ + else \ + dst_value = (dst_type)src_value; \ + } \ + } \ + return dst_value; \ +} + +TRUNC_FUNCTION(trunc_f32_to_i32, float32, uint32, int32) +TRUNC_FUNCTION(trunc_f32_to_i64, float32, uint64, int64) +TRUNC_FUNCTION(trunc_f64_to_i32, float64, uint32, int32) +TRUNC_FUNCTION(trunc_f64_to_i64, float64, uint64, int64) + +static bool +trunc_f32_to_int(WASMModuleInstance *module, + uint32 *frame_sp, + float32 src_min, float32 src_max, + bool saturating, bool is_i32, bool is_sign) +{ + float32 src_value = POP_F32(); + uint64 dst_value_i64; + uint32 dst_value_i32; + + if (!saturating) { + if (isnan(src_value)) { + wasm_set_exception(module, "invalid conversion to integer"); + return true; + } + else if (src_value <= src_min || src_value >= src_max) { + wasm_set_exception(module, "integer overflow"); + return true; + } + } + + if (is_i32) { + uint32 dst_min = is_sign ? INT32_MIN : 0; + uint32 dst_max = is_sign ? INT32_MAX : UINT32_MAX; + dst_value_i32 = trunc_f32_to_i32(src_value, src_min, src_max, + dst_min, dst_max, is_sign); + PUSH_I32(dst_value_i32); + } + else { + uint64 dst_min = is_sign ? INT64_MIN : 0; + uint64 dst_max = is_sign ? INT64_MAX : UINT64_MAX; + dst_value_i64 = trunc_f32_to_i64(src_value, src_min, src_max, + dst_min, dst_max, is_sign); + PUSH_I64(dst_value_i64); + } + return false; +} + +static bool +trunc_f64_to_int(WASMModuleInstance *module, + uint32 *frame_sp, + float64 src_min, float64 src_max, + bool saturating, bool is_i32, bool is_sign) +{ + float64 src_value = POP_F64(); + uint64 dst_value_i64; + uint32 dst_value_i32; + + if (!saturating) { + if (isnan(src_value)) { + wasm_set_exception(module, "invalid conversion to integer"); + return true; + } + else if (src_value <= src_min || src_value >= src_max) { + wasm_set_exception(module, "integer overflow"); + return true; + } + } + + if (is_i32) { + uint32 dst_min = is_sign ? INT32_MIN : 0; + uint32 dst_max = is_sign ? INT32_MAX : UINT32_MAX; + dst_value_i32 = trunc_f64_to_i32(src_value, src_min, src_max, + dst_min, dst_max, is_sign); + PUSH_I32(dst_value_i32); + } + else { + uint64 dst_min = is_sign ? INT64_MIN : 0; + uint64 dst_max = is_sign ? INT64_MAX : UINT64_MAX; + dst_value_i64 = trunc_f64_to_i64(src_value, src_min, src_max, + dst_min, dst_max, is_sign); + PUSH_I64(dst_value_i64); + } + return false; +} + +#define DEF_OP_TRUNC_F32(min, max, is_i32, is_sign) do { \ + if (trunc_f32_to_int(module, frame_sp, min, max, \ + false, is_i32, is_sign)) \ + goto got_exception; \ + } while (0) + +#define DEF_OP_TRUNC_F64(min, max, is_i32, is_sign) do { \ + if (trunc_f64_to_int(module, frame_sp, min, max, \ + false, is_i32, is_sign)) \ + goto got_exception; \ + } while (0) + +#define DEF_OP_TRUNC_SAT_F32(min, max, is_i32, is_sign) do { \ + (void)trunc_f32_to_int(module, frame_sp, min, max, \ + true, is_i32, is_sign); \ + } while (0) + +#define DEF_OP_TRUNC_SAT_F64(min, max, is_i32, is_sign) do { \ + (void)trunc_f64_to_int(module, frame_sp, min, max, \ + true, is_i32, is_sign); \ } while (0) #define DEF_OP_CONVERT(dst_type, dst_op_type, \ @@ -2088,23 +2198,23 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, all int32/uint32/int64/uint64 values, e.g.: UINT32_MAX is 4294967295, but (float32)4294967295 is 4294967296.0f, but not 4294967295.0f. */ - DEF_OP_TRUNC(int32, I32, float32, F32, <= -2147483904.0f, - >= 2147483648.0f); + DEF_OP_TRUNC_F32(-2147483904.0f, 2147483648.0f, true, true); HANDLE_OP_END (); HANDLE_OP (WASM_OP_I32_TRUNC_U_F32): - DEF_OP_TRUNC(uint32, I32, float32, F32, <= -1.0f, - >= 4294967296.0f); + DEF_OP_TRUNC_F32(-1.0f, 4294967296.0f, true, false); HANDLE_OP_END (); HANDLE_OP (WASM_OP_I32_TRUNC_S_F64): - DEF_OP_TRUNC(int32, I32, float64, F64, <= -2147483649.0, - >= 2147483648.0); + DEF_OP_TRUNC_F64(-2147483649.0, 2147483648.0, true, true); + /* frame_sp can't be moved in trunc function, we need to manually adjust + it if src and dst op's cell num is different */ + frame_sp--; HANDLE_OP_END (); HANDLE_OP (WASM_OP_I32_TRUNC_U_F64): - DEF_OP_TRUNC(uint32, I32, float64, F64, <= -1.0 , - >= 4294967296.0); + DEF_OP_TRUNC_F64(-1.0, 4294967296.0, true, false); + frame_sp--; HANDLE_OP_END (); /* conversions of i64 */ @@ -2117,23 +2227,25 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP_END (); HANDLE_OP (WASM_OP_I64_TRUNC_S_F32): - DEF_OP_TRUNC(int64, I64, float32, F32, <= -9223373136366403584.0f, - >= 9223372036854775808.0f); + DEF_OP_TRUNC_F32(-9223373136366403584.0f, 9223372036854775808.0f, + false, true); + frame_sp++; HANDLE_OP_END (); HANDLE_OP (WASM_OP_I64_TRUNC_U_F32): - DEF_OP_TRUNC(uint64, I64, float32, F32, <= -1.0f, - >= 18446744073709551616.0f); + DEF_OP_TRUNC_F32(-1.0f, 18446744073709551616.0f, + false, false); + frame_sp++; HANDLE_OP_END (); HANDLE_OP (WASM_OP_I64_TRUNC_S_F64): - DEF_OP_TRUNC(int64, I64, float64, F64, <= -9223372036854777856.0, - >= 9223372036854775808.0); + DEF_OP_TRUNC_F64(-9223372036854777856.0, 9223372036854775808.0, + false, true); HANDLE_OP_END (); HANDLE_OP (WASM_OP_I64_TRUNC_U_F64): - DEF_OP_TRUNC(uint64, I64, float64, F64, <= -1.0, - >= 18446744073709551616.0); + DEF_OP_TRUNC_F64(-1.0, 18446744073709551616.0, + false, false); HANDLE_OP_END (); /* conversions of f32 */ @@ -2185,6 +2297,75 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP (WASM_OP_F64_REINTERPRET_I64): HANDLE_OP_END (); + HANDLE_OP (WASM_OP_I32_EXTEND8_S): + DEF_OP_CONVERT(int32, I32, int8, I32); + HANDLE_OP_END (); + + HANDLE_OP (WASM_OP_I32_EXTEND16_S): + DEF_OP_CONVERT(int32, I32, int16, I32); + HANDLE_OP_END (); + + HANDLE_OP (WASM_OP_I64_EXTEND8_S): + DEF_OP_CONVERT(int64, I64, int8, I64); + HANDLE_OP_END (); + + HANDLE_OP (WASM_OP_I64_EXTEND16_S): + DEF_OP_CONVERT(int64, I64, int16, I64); + HANDLE_OP_END (); + + HANDLE_OP (WASM_OP_I64_EXTEND32_S): + DEF_OP_CONVERT(int64, I64, int32, I64); + HANDLE_OP_END (); + + HANDLE_OP (WASM_OP_MISC_PREFIX): + { + opcode = *frame_ip++; + switch (opcode) + { + case WASM_OP_I32_TRUNC_SAT_S_F32: + DEF_OP_TRUNC_SAT_F32(-2147483904.0f, 2147483648.0f, + true, true); + break; + case WASM_OP_I32_TRUNC_SAT_U_F32: + DEF_OP_TRUNC_SAT_F32(-1.0f, 4294967296.0f, + true, false); + break; + case WASM_OP_I32_TRUNC_SAT_S_F64: + DEF_OP_TRUNC_SAT_F64(-2147483649.0, 2147483648.0, + true, true); + frame_sp--; + break; + case WASM_OP_I32_TRUNC_SAT_U_F64: + DEF_OP_TRUNC_SAT_F64(-1.0, 4294967296.0, + true, false); + frame_sp--; + break; + case WASM_OP_I64_TRUNC_SAT_S_F32: + DEF_OP_TRUNC_SAT_F32(-9223373136366403584.0f, 9223372036854775808.0f, + false, true); + frame_sp++; + break; + case WASM_OP_I64_TRUNC_SAT_U_F32: + DEF_OP_TRUNC_SAT_F32(-1.0f, 18446744073709551616.0f, + false, false); + frame_sp++; + break; + case WASM_OP_I64_TRUNC_SAT_S_F64: + DEF_OP_TRUNC_SAT_F64(-9223372036854777856.0, 9223372036854775808.0, + false, true); + break; + case WASM_OP_I64_TRUNC_SAT_U_F64: + DEF_OP_TRUNC_SAT_F64(-1.0f, 18446744073709551616.0, + false, false); + break; + default: + wasm_set_exception(module, "WASM interp failed: unsupported opcode."); + goto got_exception; + break; + } + HANDLE_OP_END (); + } + HANDLE_OP (WASM_OP_IMPDEP): frame = prev_frame; frame_ip = frame->ip; @@ -2359,7 +2540,11 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, return; } - /* TODO: check stack overflow. */ + if ((uint8*)&prev_frame < exec_env->native_stack_boundary) { + wasm_set_exception((WASMModuleInstance*)exec_env->module_inst, + "WASM interp failed: native stack overflow."); + return; + } if (!(frame = ALLOC_FRAME(exec_env, frame_size, (WASMInterpFrame*)prev_frame))) return; diff --git a/core/iwasm/interpreter/wasm_interp_fast.c b/core/iwasm/interpreter/wasm_interp_fast.c index 6eb28c4a8..ae4cbb3eb 100644 --- a/core/iwasm/interpreter/wasm_interp_fast.c +++ b/core/iwasm/interpreter/wasm_interp_fast.c @@ -536,18 +536,131 @@ read_leb(const uint8 *buf, uint32 *p_offset, uint32 maxbits, bool sign) frame_ip += 4; \ } while (0) -#define DEF_OP_TRUNC(dst_type, dst_op_type, src_type, src_op_type, \ - min_cond, max_cond) do { \ - src_type value = GET_OPERAND(src_type, 0); \ - if (isnan(value)) { \ - wasm_set_exception(module, "invalid conversion to integer"); \ - goto got_exception; \ - } \ - else if (value min_cond || value max_cond) { \ - wasm_set_exception(module, "integer overflow"); \ - goto got_exception; \ - } \ - SET_OPERAND(dst_type, 2, value); \ +#define TRUNC_FUNCTION(func_name, src_type, dst_type, signed_type) \ +static dst_type \ +func_name(src_type src_value, src_type src_min, src_type src_max, \ + dst_type dst_min, dst_type dst_max, bool is_sign) \ +{ \ + dst_type dst_value = 0; \ + if (!isnan(src_value)) { \ + if (src_value <= src_min) \ + dst_value = dst_min; \ + else if (src_value >= src_max) \ + dst_value = dst_max; \ + else { \ + if (is_sign) \ + dst_value = (dst_type)(signed_type)src_value; \ + else \ + dst_value = (dst_type)src_value; \ + } \ + } \ + return dst_value; \ +} + +TRUNC_FUNCTION(trunc_f32_to_i32, float32, uint32, int32) +TRUNC_FUNCTION(trunc_f32_to_i64, float32, uint64, int64) +TRUNC_FUNCTION(trunc_f64_to_i32, float64, uint32, int32) +TRUNC_FUNCTION(trunc_f64_to_i64, float64, uint64, int64) + +static bool +trunc_f32_to_int(WASMModuleInstance *module, + uint8 *frame_ip, uint32 *frame_lp, + float32 src_min, float32 src_max, + bool saturating, bool is_i32, bool is_sign) +{ + float32 src_value = GET_OPERAND(float32, 0); + uint64 dst_value_i64; + uint32 dst_value_i32; + + if (!saturating) { + if (isnan(src_value)) { + wasm_set_exception(module, "invalid conversion to integer"); + return true; + } + else if (src_value <= src_min || src_value >= src_max) { + wasm_set_exception(module, "integer overflow"); + return true; + } + } + + if (is_i32) { + uint32 dst_min = is_sign ? INT32_MIN : 0; + uint32 dst_max = is_sign ? INT32_MAX : UINT32_MAX; + dst_value_i32 = trunc_f32_to_i32(src_value, src_min, src_max, + dst_min, dst_max, is_sign); + SET_OPERAND(uint32, 2, dst_value_i32); + } + else { + uint64 dst_min = is_sign ? INT64_MIN : 0; + uint64 dst_max = is_sign ? INT64_MAX : UINT64_MAX; + dst_value_i64 = trunc_f32_to_i64(src_value, src_min, src_max, + dst_min, dst_max, is_sign); + SET_OPERAND(uint64, 2, dst_value_i64); + } + return false; +} + +static bool +trunc_f64_to_int(WASMModuleInstance *module, + uint8 *frame_ip, uint32 *frame_lp, + float64 src_min, float64 src_max, + bool saturating, bool is_i32, bool is_sign) +{ + float64 src_value = GET_OPERAND(float64, 0); + uint64 dst_value_i64; + uint32 dst_value_i32; + + if (!saturating) { + if (isnan(src_value)) { + wasm_set_exception(module, "invalid conversion to integer"); + return true; + } + else if (src_value <= src_min || src_value >= src_max) { + wasm_set_exception(module, "integer overflow"); + return true; + } + } + + if (is_i32) { + uint32 dst_min = is_sign ? INT32_MIN : 0; + uint32 dst_max = is_sign ? INT32_MAX : UINT32_MAX; + dst_value_i32 = trunc_f64_to_i32(src_value, src_min, src_max, + dst_min, dst_max, is_sign); + SET_OPERAND(uint32, 2, dst_value_i32); + } + else { + uint64 dst_min = is_sign ? INT64_MIN : 0; + uint64 dst_max = is_sign ? INT64_MAX : UINT64_MAX; + dst_value_i64 = trunc_f64_to_i64(src_value, src_min, src_max, + dst_min, dst_max, is_sign); + SET_OPERAND(uint64, 2, dst_value_i64); + } + return false; +} + +#define DEF_OP_TRUNC_F32(min, max, is_i32, is_sign) do { \ + if (trunc_f32_to_int(module, frame_ip, frame_lp, min, max, \ + false, is_i32, is_sign)) \ + goto got_exception; \ + frame_ip += 4; \ + } while (0) + +#define DEF_OP_TRUNC_F64(min, max, is_i32, is_sign) do { \ + if (trunc_f64_to_int(module, frame_ip, frame_lp, min, max, \ + false, is_i32, is_sign)) \ + goto got_exception; \ + frame_ip += 4; \ + } while (0) + +#define DEF_OP_TRUNC_SAT_F32(min, max, is_i32, is_sign) do { \ + (void)trunc_f32_to_int(module, frame_ip, frame_lp, min, max, \ + true, is_i32, is_sign); \ + frame_ip += 4; \ + } while (0) + +#define DEF_OP_TRUNC_SAT_F64(min, max, is_i32, is_sign) do { \ + (void)trunc_f64_to_int(module, frame_ip, frame_lp, min, max, \ + true, is_i32, is_sign); \ frame_ip += 4; \ } while (0) @@ -799,7 +912,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, int32 didx, val; uint8 *maddr = NULL; uint32 local_idx, local_offset, global_idx; - uint8 local_type, *global_addr; + uint8 opcode, local_type, *global_addr; #if WASM_ENABLE_LABELS_AS_VALUES != 0 #define HANDLE_OPCODE(op) &&HANDLE_##op @@ -1981,23 +2094,19 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, all int32/uint32/int64/uint64 values, e.g.: UINT32_MAX is 4294967295, but (float32)4294967295 is 4294967296.0f, but not 4294967295.0f. */ - DEF_OP_TRUNC(int32, I32, float32, F32, <= -2147483904.0f, - >= 2147483648.0f); + DEF_OP_TRUNC_F32(-2147483904.0f, 2147483648.0f, true, true); HANDLE_OP_END (); HANDLE_OP (WASM_OP_I32_TRUNC_U_F32): - DEF_OP_TRUNC(uint32, I32, float32, F32, <= -1.0f, - >= 4294967296.0f); + DEF_OP_TRUNC_F32(-1.0f, 4294967296.0f, true, false); HANDLE_OP_END (); HANDLE_OP (WASM_OP_I32_TRUNC_S_F64): - DEF_OP_TRUNC(int32, I32, float64, F64, <= -2147483649.0, - >= 2147483648.0); + DEF_OP_TRUNC_F64(-2147483649.0, 2147483648.0, true, true); HANDLE_OP_END (); HANDLE_OP (WASM_OP_I32_TRUNC_U_F64): - DEF_OP_TRUNC(uint32, I32, float64, F64, <= -1.0 , - >= 4294967296.0); + DEF_OP_TRUNC_F64(-1.0, 4294967296.0, true, false); HANDLE_OP_END (); /* conversions of i64 */ @@ -2010,23 +2119,23 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP_END (); HANDLE_OP (WASM_OP_I64_TRUNC_S_F32): - DEF_OP_TRUNC(int64, I64, float32, F32, <= -9223373136366403584.0f, - >= 9223372036854775808.0f); + DEF_OP_TRUNC_F32(-9223373136366403584.0f, + 9223372036854775808.0f, false, true); HANDLE_OP_END (); HANDLE_OP (WASM_OP_I64_TRUNC_U_F32): - DEF_OP_TRUNC(uint64, I64, float32, F32, <= -1.0f, - >= 18446744073709551616.0f); + DEF_OP_TRUNC_F32(-1.0f, 18446744073709551616.0f, + false, false); HANDLE_OP_END (); HANDLE_OP (WASM_OP_I64_TRUNC_S_F64): - DEF_OP_TRUNC(int64, I64, float64, F64, <= -9223372036854777856.0, - >= 9223372036854775808.0); + DEF_OP_TRUNC_F64(-9223372036854777856.0, + 9223372036854775808.0, false, true); HANDLE_OP_END (); HANDLE_OP (WASM_OP_I64_TRUNC_U_F64): - DEF_OP_TRUNC(uint64, I64, float64, F64, <= -1.0, - >= 18446744073709551616.0); + DEF_OP_TRUNC_F64(-1.0, 18446744073709551616.0, + false, false); HANDLE_OP_END (); /* conversions of f32 */ @@ -2130,6 +2239,71 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP_END (); } + HANDLE_OP (WASM_OP_I32_EXTEND8_S): + DEF_OP_CONVERT(int32, I32, int8, I32); + HANDLE_OP_END (); + + HANDLE_OP (WASM_OP_I32_EXTEND16_S): + DEF_OP_CONVERT(int32, I32, int16, I32); + HANDLE_OP_END (); + + HANDLE_OP (WASM_OP_I64_EXTEND8_S): + DEF_OP_CONVERT(int64, I64, int8, I64); + HANDLE_OP_END (); + + HANDLE_OP (WASM_OP_I64_EXTEND16_S): + DEF_OP_CONVERT(int64, I64, int16, I64); + HANDLE_OP_END (); + + HANDLE_OP (WASM_OP_I64_EXTEND32_S): + DEF_OP_CONVERT(int64, I64, int32, I64); + HANDLE_OP_END (); + + HANDLE_OP (WASM_OP_MISC_PREFIX): + { + GET_OPCODE(); + switch (opcode) + { + case WASM_OP_I32_TRUNC_SAT_S_F32: + DEF_OP_TRUNC_SAT_F32(-2147483904.0f, 2147483648.0f, + true, true); + break; + case WASM_OP_I32_TRUNC_SAT_U_F32: + DEF_OP_TRUNC_SAT_F32(-1.0f, 4294967296.0f, + true, false); + break; + case WASM_OP_I32_TRUNC_SAT_S_F64: + DEF_OP_TRUNC_SAT_F64(-2147483649.0, 2147483648.0, + true, true); + break; + case WASM_OP_I32_TRUNC_SAT_U_F64: + DEF_OP_TRUNC_SAT_F64(-1.0, 4294967296.0, + true, false); + break; + case WASM_OP_I64_TRUNC_SAT_S_F32: + DEF_OP_TRUNC_SAT_F32(-9223373136366403584.0f, 9223372036854775808.0f, + false, true); + break; + case WASM_OP_I64_TRUNC_SAT_U_F32: + DEF_OP_TRUNC_SAT_F32(-1.0f, 18446744073709551616.0f, + false, false); + break; + case WASM_OP_I64_TRUNC_SAT_S_F64: + DEF_OP_TRUNC_SAT_F64(-9223372036854777856.0, 9223372036854775808.0, + false, true); + break; + case WASM_OP_I64_TRUNC_SAT_U_F64: + DEF_OP_TRUNC_SAT_F64(-1.0, 18446744073709551616.0, + false, false); + break; + default: + wasm_set_exception(module, "WASM interp failed: unsupported opcode."); + goto got_exception; + break; + } + HANDLE_OP_END (); + } + HANDLE_OP (WASM_OP_IMPDEP): frame = prev_frame; frame_ip = frame->ip; @@ -2334,7 +2508,11 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, return; } - /* TODO: check stack overflow. */ + if ((uint8*)&prev_frame < exec_env->native_stack_boundary) { + wasm_set_exception((WASMModuleInstance*)exec_env->module_inst, + "WASM interp failed: native stack overflow."); + return; + } if (!(frame = ALLOC_FRAME(exec_env, frame_size, (WASMInterpFrame*)prev_frame))) return; diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index cc44e1744..24d02d0b8 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -321,7 +321,7 @@ const_str_list_insert(const uint8 *str, uint32 len, WASMModule *module, static bool load_init_expr(const uint8 **p_buf, const uint8 *buf_end, - InitializerExpression *init_expr, + InitializerExpression *init_expr, uint8 type, char *error_buf, uint32 error_buf_size) { const uint8 *p = *p_buf, *p_end = buf_end; @@ -335,14 +335,20 @@ load_init_expr(const uint8 **p_buf, const uint8 *buf_end, switch (flag) { /* i32.const */ case INIT_EXPR_TYPE_I32_CONST: + if (type != VALUE_TYPE_I32) + goto fail; read_leb_int32(p, p_end, init_expr->u.i32); break; /* i64.const */ case INIT_EXPR_TYPE_I64_CONST: + if (type != VALUE_TYPE_I64) + goto fail; read_leb_int64(p, p_end, init_expr->u.i64); break; /* f32.const */ case INIT_EXPR_TYPE_F32_CONST: + if (type != VALUE_TYPE_F32) + goto fail; CHECK_BUF(p, p_end, 4); p_float = (uint8*)&init_expr->u.f32; for (i = 0; i < sizeof(float32); i++) @@ -350,6 +356,8 @@ load_init_expr(const uint8 **p_buf, const uint8 *buf_end, break; /* f64.const */ case INIT_EXPR_TYPE_F64_CONST: + if (type != VALUE_TYPE_F64) + goto fail; CHECK_BUF(p, p_end, 8); p_float = (uint8*)&init_expr->u.f64; for (i = 0; i < sizeof(float64); i++) @@ -360,21 +368,20 @@ load_init_expr(const uint8 **p_buf, const uint8 *buf_end, read_leb_uint32(p, p_end, init_expr->u.global_index); break; default: - set_error_buf(error_buf, error_buf_size, - "WASM module load failed: type mismatch"); - return false; + goto fail; } CHECK_BUF(p, p_end, 1); end_byte = read_uint8(p); - if (end_byte != 0x0b) { - set_error_buf(error_buf, error_buf_size, - "WASM module load failed: " - "unexpected end of section or function"); - return false; - } + if (end_byte != 0x0b) + goto fail; *p_buf = p; return true; +fail: + set_error_buf(error_buf, error_buf_size, + "WASM module load failed: type mismatch or " + "constant expression required."); + return false; } static bool @@ -1104,7 +1111,6 @@ load_memory_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, WASMMemory *memory; read_leb_uint32(p, p_end, memory_count); - bh_assert(memory_count == 1); if (memory_count) { if (memory_count > 1) { @@ -1180,7 +1186,8 @@ load_global_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, global->is_mutable = mutable ? true : false; /* initialize expression */ - if (!load_init_expr(&p, p_end, &(global->init_expr), error_buf, error_buf_size)) + if (!load_init_expr(&p, p_end, &(global->init_expr), + global->type, error_buf, error_buf_size)) return false; } } @@ -1327,7 +1334,7 @@ load_table_segment_section(const uint8 *buf, const uint8 *buf_end, WASMModule *m /* initialize expression */ if (!load_init_expr(&p, p_end, &(table_segment->base_offset), - error_buf, error_buf_size)) + VALUE_TYPE_I32, error_buf, error_buf_size)) return false; read_leb_uint32(p, p_end, function_count); @@ -1387,7 +1394,8 @@ load_data_segment_section(const uint8 *buf, const uint8 *buf_end, for (i = 0; i < data_seg_count; i++) { read_leb_uint32(p, p_end, mem_index); - if (!load_init_expr(&p, p_end, &init_expr, error_buf, error_buf_size)) + if (!load_init_expr(&p, p_end, &init_expr, VALUE_TYPE_I32, + error_buf, error_buf_size)) return false; read_leb_uint32(p, p_end, data_seg_len); @@ -1455,20 +1463,33 @@ load_start_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, char *error_buf, uint32 error_buf_size) { const uint8 *p = buf, *p_end = buf_end; + WASMType *type; uint32 start_function; read_leb_uint32(p, p_end, start_function); - if (start_function) { - if (start_function >= module->function_count + module->import_function_count) { - set_error_buf(error_buf, error_buf_size, - "Load start section failed: " - "unknown function."); - return false; - } - module->start_function = start_function; + if (start_function >= module->function_count + + module->import_function_count) { + set_error_buf(error_buf, error_buf_size, + "Load start section failed: " + "unknown function."); + return false; } + if (start_function < module->import_function_count) + type = module->import_functions[start_function].u.function.func_type; + else + type = module->functions + [start_function - module->import_function_count]->func_type; + if (type->param_count != 0 || type->result_count != 0) { + set_error_buf(error_buf, error_buf_size, + "Load start section failed: " + "invalid start function."); + return false; + } + + module->start_function = start_function; + if (p != p_end) { set_error_buf(error_buf, error_buf_size, "Load start section failed: section size mismatch"); @@ -2345,6 +2366,16 @@ wasm_loader_find_block_addr(BlockAddr *block_addr_cache, case WASM_OP_I64_REINTERPRET_F64: case WASM_OP_F32_REINTERPRET_I32: case WASM_OP_F64_REINTERPRET_I64: + case WASM_OP_I32_EXTEND8_S: + case WASM_OP_I32_EXTEND16_S: + case WASM_OP_I64_EXTEND8_S: + case WASM_OP_I64_EXTEND16_S: + case WASM_OP_I64_EXTEND32_S: + break; + case WASM_OP_MISC_PREFIX: + /* skip extend op */ + if (p < code_end_addr) + p++; break; default: @@ -4714,6 +4745,58 @@ handle_next_reachable_block: PUSH_F64(); break; + case WASM_OP_I32_EXTEND8_S: + case WASM_OP_I32_EXTEND16_S: + POP_I32(); + PUSH_I32(); + break; + + case WASM_OP_I64_EXTEND8_S: + case WASM_OP_I64_EXTEND16_S: + case WASM_OP_I64_EXTEND32_S: + POP_I64(); + PUSH_I64(); + break; + + case WASM_OP_MISC_PREFIX: + { + opcode = read_uint8(p); +#if WASM_ENABLE_FAST_INTERP != 0 + emit_byte(loader_ctx, opcode); +#endif + switch (opcode) + { + case WASM_OP_I32_TRUNC_SAT_S_F32: + case WASM_OP_I32_TRUNC_SAT_U_F32: + POP_F32(); + PUSH_I32(); + break; + case WASM_OP_I32_TRUNC_SAT_S_F64: + case WASM_OP_I32_TRUNC_SAT_U_F64: + POP_F64(); + PUSH_I32(); + break; + case WASM_OP_I64_TRUNC_SAT_S_F32: + case WASM_OP_I64_TRUNC_SAT_U_F32: + POP_F32(); + PUSH_I64(); + break; + case WASM_OP_I64_TRUNC_SAT_S_F64: + case WASM_OP_I64_TRUNC_SAT_U_F64: + POP_F64(); + PUSH_I64(); + break; + default: + if (error_buf != NULL) + snprintf(error_buf, error_buf_size, + "WASM module load failed: " + "invalid opcode 0xfc %02x.", opcode); + goto fail; + break; + } + break; + } + default: if (error_buf != NULL) snprintf(error_buf, error_buf_size, diff --git a/core/iwasm/interpreter/wasm_opcode.h b/core/iwasm/interpreter/wasm_opcode.h index 51c3e2245..d8a4b274f 100644 --- a/core/iwasm/interpreter/wasm_opcode.h +++ b/core/iwasm/interpreter/wasm_opcode.h @@ -237,22 +237,42 @@ typedef enum WASMOpcode { WASM_OP_F32_REINTERPRET_I32 = 0xbe, /* f32.reinterpret/i32 */ WASM_OP_F64_REINTERPRET_I64 = 0xbf, /* f64.reinterpret/i64 */ + WASM_OP_I32_EXTEND8_S = 0xc0, /* i32.extend8_s */ + WASM_OP_I32_EXTEND16_S = 0xc1, /* i32.extend16_s */ + WASM_OP_I64_EXTEND8_S = 0xc2, /* i64.extend8_s */ + WASM_OP_I64_EXTEND16_S = 0xc3, /* i64.extend16_s */ + WASM_OP_I64_EXTEND32_S = 0xc4, /* i64.extend32_s */ + /* drop/select specified types*/ - WASM_OP_DROP_64 = 0xc0, - WASM_OP_SELECT_64 = 0xc1, + WASM_OP_DROP_64 = 0xc5, + WASM_OP_SELECT_64 = 0xc6, /* extend op code */ - EXT_OP_GET_LOCAL_FAST = 0xc2, - EXT_OP_SET_LOCAL_FAST_I64 = 0xc3, - EXT_OP_SET_LOCAL_FAST = 0xc4, - EXT_OP_TEE_LOCAL_FAST = 0xc5, - EXT_OP_TEE_LOCAL_FAST_I64 = 0xc6, - EXT_OP_COPY_STACK_TOP = 0xc7, - EXT_OP_COPY_STACK_TOP_I64 = 0xc8, + EXT_OP_GET_LOCAL_FAST = 0xc7, + EXT_OP_SET_LOCAL_FAST_I64 = 0xc8, + EXT_OP_SET_LOCAL_FAST = 0xc9, + EXT_OP_TEE_LOCAL_FAST = 0xca, + EXT_OP_TEE_LOCAL_FAST_I64 = 0xcb, + EXT_OP_COPY_STACK_TOP = 0xcc, + EXT_OP_COPY_STACK_TOP_I64 = 0xcd, - WASM_OP_IMPDEP = 0xc9 + WASM_OP_IMPDEP = 0xce, + + /* Post-MVP extend op prefix */ + WASM_OP_MISC_PREFIX = 0xfc, } WASMOpcode; +typedef enum WASMEXTOpcode { + WASM_OP_I32_TRUNC_SAT_S_F32 = 0x00, + WASM_OP_I32_TRUNC_SAT_U_F32 = 0x01, + WASM_OP_I32_TRUNC_SAT_S_F64 = 0x02, + WASM_OP_I32_TRUNC_SAT_U_F64 = 0x03, + WASM_OP_I64_TRUNC_SAT_S_F32 = 0x04, + WASM_OP_I64_TRUNC_SAT_U_F32 = 0x05, + WASM_OP_I64_TRUNC_SAT_S_F64 = 0x06, + WASM_OP_I64_TRUNC_SAT_U_F64 = 0x07, +} WASMEXTOpcode; + #ifdef __cplusplus } #endif @@ -456,16 +476,24 @@ static type _name[WASM_INSTRUCTION_NUM] = { \ HANDLE_OPCODE (WASM_OP_I64_REINTERPRET_F64), /* 0xbd */ \ HANDLE_OPCODE (WASM_OP_F32_REINTERPRET_I32), /* 0xbe */ \ HANDLE_OPCODE (WASM_OP_F64_REINTERPRET_I64), /* 0xbf */ \ - HANDLE_OPCODE (WASM_OP_DROP_64), /* 0xc0 */ \ - HANDLE_OPCODE (WASM_OP_SELECT_64), /* 0xc1 */ \ - HANDLE_OPCODE (EXT_OP_GET_LOCAL_FAST), /* 0xc2 */ \ - HANDLE_OPCODE (EXT_OP_SET_LOCAL_FAST_I64), /* 0xc3 */ \ - HANDLE_OPCODE (EXT_OP_SET_LOCAL_FAST), /* 0xc4 */ \ - HANDLE_OPCODE (EXT_OP_TEE_LOCAL_FAST), /* 0xc5 */ \ - HANDLE_OPCODE (EXT_OP_TEE_LOCAL_FAST_I64), /* 0xc6 */ \ - HANDLE_OPCODE (EXT_OP_COPY_STACK_TOP), /* 0xc7 */ \ - HANDLE_OPCODE (EXT_OP_COPY_STACK_TOP_I64), /* 0xc8 */ \ - HANDLE_OPCODE (WASM_OP_IMPDEP), /* 0xc9 */ \ -} - + HANDLE_OPCODE (WASM_OP_I32_EXTEND8_S), /* 0xc0 */ \ + HANDLE_OPCODE (WASM_OP_I32_EXTEND16_S), /* 0xc1 */ \ + HANDLE_OPCODE (WASM_OP_I64_EXTEND8_S), /* 0xc2 */ \ + HANDLE_OPCODE (WASM_OP_I64_EXTEND16_S), /* 0xc3 */ \ + HANDLE_OPCODE (WASM_OP_I64_EXTEND32_S), /* 0xc4 */ \ + HANDLE_OPCODE (WASM_OP_DROP_64), /* 0xc5 */ \ + HANDLE_OPCODE (WASM_OP_SELECT_64), /* 0xc6 */ \ + HANDLE_OPCODE (EXT_OP_GET_LOCAL_FAST), /* 0xc7 */ \ + HANDLE_OPCODE (EXT_OP_SET_LOCAL_FAST_I64), /* 0xc8 */ \ + HANDLE_OPCODE (EXT_OP_SET_LOCAL_FAST), /* 0xc9 */ \ + HANDLE_OPCODE (EXT_OP_TEE_LOCAL_FAST), /* 0xca */ \ + HANDLE_OPCODE (EXT_OP_TEE_LOCAL_FAST_I64), /* 0xcb */ \ + HANDLE_OPCODE (EXT_OP_COPY_STACK_TOP), /* 0xcc */ \ + HANDLE_OPCODE (EXT_OP_COPY_STACK_TOP_I64), /* 0xcd */ \ + HANDLE_OPCODE (WASM_OP_IMPDEP), /* 0xce */ \ +}; \ +do { \ + _name[WASM_OP_MISC_PREFIX] = \ + HANDLE_OPCODE (WASM_OP_MISC_PREFIX); /* 0xfc */ \ +} while (0) #endif /* end of _WASM_OPCODE_H */ diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index 789340871..84785804d 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -419,47 +419,24 @@ globals_instantiate(const WASMModule *module, return globals; } -static void +static bool globals_instantiate_fix(WASMGlobalInstance *globals, const WASMModule *module, - WASMModuleInstance *module_inst) + WASMModuleInstance *module_inst, + char *error_buf, uint32 error_buf_size) { WASMGlobalInstance *global = globals; - WASMImport *import = module->import_globals; uint32 i; - /* Fix globals from import section */ - for (i = 0; i < module->import_global_count; i++, import++, global++) { - if (!strcmp(import->u.names.module_name, "env")) { - if (!strcmp(import->u.names.field_name, "memoryBase") - || !strcmp(import->u.names.field_name, "__memory_base")) { - global->initial_value.addr = 0; - } - else if (!strcmp(import->u.names.field_name, "tableBase") - || !strcmp(import->u.names.field_name, "__table_base")) { - global->initial_value.addr = 0; - } - else if (!strcmp(import->u.names.field_name, "DYNAMICTOP_PTR")) { - global->initial_value.i32 = (int32) - (module_inst->default_memory->num_bytes_per_page - * module_inst->default_memory->cur_page_count); - module_inst->DYNAMICTOP_PTR_offset = global->data_offset; - } - else if (!strcmp(import->u.names.field_name, "STACKTOP")) { - global->initial_value.i32 = 0; - } - else if (!strcmp(import->u.names.field_name, "STACK_MAX")) { - /* Unused in emcc wasm bin actually. */ - global->initial_value.i32 = 0; - } - } - } - for (i = 0; i < module->global_count; i++) { InitializerExpression *init_expr = &module->globals[i].init_expr; if (init_expr->init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL) { - bh_assert(init_expr->u.global_index < module->import_global_count); + if (init_expr->u.global_index >= module->import_global_count + i) { + set_error_buf(error_buf, error_buf_size, + "Instantiate global failed: unknown global."); + return false; + } global->initial_value = globals[init_expr->u.global_index].initial_value; } else { @@ -468,6 +445,7 @@ globals_instantiate_fix(WASMGlobalInstance *globals, } global++; } + return true; } /** @@ -658,7 +636,11 @@ wasm_instantiate(WASMModule *module, memory_data = module_inst->default_memory->memory_data; /* fix import memoryBase */ - globals_instantiate_fix(globals, module, module_inst); + if (!globals_instantiate_fix(globals, module, module_inst, + error_buf, error_buf_size)) { + wasm_deinstantiate(module_inst); + return NULL; + } /* Initialize the global data */ global_data = memory->global_data; @@ -710,7 +692,7 @@ wasm_instantiate(WASMModule *module, && (base_offset >= memory_size || base_offset + length > memory_size)) { set_error_buf(error_buf, error_buf_size, - "Instantiate module failed: data segment out of range."); + "Instantiate module failed: data segment does not fit."); wasm_deinstantiate(module_inst); return NULL; } @@ -784,9 +766,10 @@ wasm_instantiate(WASMModule *module, #endif if (module->start_function != (uint32)-1) { - bh_assert(module->start_function >= module->import_function_count); - module_inst->start_function = - &module_inst->functions[module->start_function]; + /* TODO: fix start function can be import function issue */ + if (module->start_function >= module->import_function_count) + module_inst->start_function = + &module_inst->functions[module->start_function]; } module_inst->module = module; @@ -881,6 +864,9 @@ wasm_create_exec_env_and_call_function(WASMModuleInstance *module_inst, return false; } + /* set thread handle and stack boundary */ + wasm_exec_env_set_thread_info(exec_env); + ret = wasm_call_function(exec_env, func, argc, argv); wasm_exec_env_destroy(exec_env); return ret; @@ -998,12 +984,13 @@ wasm_addr_app_to_native(WASMModuleInstance *module_inst, int32 app_offset) { WASMMemoryInstance *memory = module_inst->default_memory; + uint8 *addr = memory->memory_data + app_offset; int32 memory_data_size = (int32)(memory->num_bytes_per_page * memory->cur_page_count); - if (memory->heap_base_offset < app_offset - && app_offset < memory_data_size) - return memory->memory_data + app_offset; + if (memory->heap_data < addr + && addr < memory->memory_data + memory_data_size) + return addr; return NULL; } diff --git a/core/iwasm/interpreter/wasm_runtime.h b/core/iwasm/interpreter/wasm_runtime.h index dd512494d..102db8795 100644 --- a/core/iwasm/interpreter/wasm_runtime.h +++ b/core/iwasm/interpreter/wasm_runtime.h @@ -136,7 +136,6 @@ typedef struct WASMModuleInstance { WASIContext *wasi_ctx; #endif - uint32 DYNAMICTOP_PTR_offset; uint32 temp_ret; uint32 llvm_stack; diff --git a/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c b/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c index b83d606f9..76f821ad8 100644 --- a/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c +++ b/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c @@ -993,12 +993,45 @@ __cxa_throw_wrapper(wasm_exec_env_t exec_env, wasm_runtime_set_exception(module_inst, buf); } +#if WASM_ENABLE_SPEC_TEST != 0 +static void +print_wrapper(wasm_exec_env_t exec_env) +{ + os_printf("in specttest.print()\n"); + +} + static void print_i32_wrapper(wasm_exec_env_t exec_env, int32 i32) { - os_printf("%d\n", i32); + os_printf("in specttest.print_i32(%d)\n", i32); } +static void +print_i32_f32_wrapper(wasm_exec_env_t exec_env, int32 i32, float f32) +{ + os_printf("in specttest.print_i32_f32(%d, %f)\n", i32, f32); +} + +static void +print_f64_f64_wrapper(wasm_exec_env_t exec_env, double f64_1, double f64_2) +{ + os_printf("in specttest.print_f64_f64(%f, %f)\n", f64_1, f64_2); +} + +static void +print_f32_wrapper(wasm_exec_env_t exec_env, float f32) +{ + os_printf("in specttest.print_f32(%f)\n", f32); +} + +static void +print_f64_wrapper(wasm_exec_env_t exec_env, double f64) +{ + os_printf("in specttest.print_f64(%f)\n", f64); +} +#endif /* WASM_ENABLE_SPEC_TEST */ + #define REG_NATIVE_FUNC(func_name, signature) \ { #func_name, func_name##_wrapper, signature, NULL } @@ -1060,9 +1093,16 @@ static NativeSymbol native_symbols_libc_builtin[] = { REG_NATIVE_FUNC(__cxa_throw, "(**i)") }; +#if WASM_ENABLE_SPEC_TEST != 0 static NativeSymbol native_symbols_spectest[] = { - REG_NATIVE_FUNC(print_i32, "(i)") + REG_NATIVE_FUNC(print, "()"), + REG_NATIVE_FUNC(print_i32, "(i)"), + REG_NATIVE_FUNC(print_i32_f32, "(if)"), + REG_NATIVE_FUNC(print_f64_f64, "(fF)"), + REG_NATIVE_FUNC(print_f32, "(f)"), + REG_NATIVE_FUNC(print_f64, "(F)") }; +#endif uint32 get_libc_builtin_export_apis(NativeSymbol **p_libc_builtin_apis) @@ -1071,12 +1111,14 @@ get_libc_builtin_export_apis(NativeSymbol **p_libc_builtin_apis) return sizeof(native_symbols_libc_builtin) / sizeof(NativeSymbol); } +#if WASM_ENABLE_SPEC_TEST != 0 uint32 get_spectest_export_apis(NativeSymbol **p_libc_builtin_apis) { *p_libc_builtin_apis = native_symbols_spectest; return sizeof(native_symbols_spectest) / sizeof(NativeSymbol); } +#endif /************************************* * Global Variables * @@ -1090,8 +1132,8 @@ typedef struct WASMNativeGlobalDef { static WASMNativeGlobalDef native_global_defs[] = { { "spectest", "global_i32", .global_data.i32 = 666 }, - { "spectest", "global_f32", .global_data.f32 = 0 }, - { "spectest", "global_f64", .global_data.f64 = 0 }, + { "spectest", "global_f32", .global_data.f32 = 666.6 }, + { "spectest", "global_f64", .global_data.f64 = 666.6 }, { "test", "global-i32", .global_data.i32 = 0 }, { "test", "global-f32", .global_data.f32 = 0 }, { "env", "STACKTOP", .global_data.u32 = 0 }, diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h index 75aac3892..c24530917 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h @@ -13,6 +13,22 @@ #include #include +#ifdef __cplusplus +#ifndef _Static_assert +#define _Static_assert static_assert +#endif /* _Static_assert */ + +#ifndef _Alignof +#define _Alignof alignof +#endif /* _Alignof */ + +#ifndef _Noreturn +#define _Noreturn [[ noreturn ]] +#endif /* _Noreturn */ +extern "C" { +#endif + + _Static_assert(_Alignof(int8_t) == 1, "non-wasi data layout"); _Static_assert(_Alignof(uint8_t) == 1, "non-wasi data layout"); _Static_assert(_Alignof(int16_t) == 2, "non-wasi data layout"); @@ -24,10 +40,6 @@ _Static_assert(_Alignof(int64_t) == 8, "non-wasi data layout"); _Static_assert(_Alignof(uint64_t) == 8, "non-wasi data layout"); #endif -#ifdef __cplusplus -extern "C" { -#endif - typedef uint8_t __wasi_advice_t; #define __WASI_ADVICE_NORMAL (0) #define __WASI_ADVICE_SEQUENTIAL (1) @@ -874,3 +886,4 @@ __wasi_errno_t wasmtime_ssp_sched_yield(void) #undef WASMTIME_SSP_SYSCALL_NAME #endif + diff --git a/core/shared/platform/alios/alios_thread.c b/core/shared/platform/alios/alios_thread.c index 236f19efa..8dd9cb10d 100644 --- a/core/shared/platform/alios/alios_thread.c +++ b/core/shared/platform/alios/alios_thread.c @@ -339,3 +339,9 @@ os_cond_signal(korp_cond *cond) return BHT_OK; } +uint8 *os_thread_get_stack_boundary() +{ + /* TODO: get alios stack boundary */ + return NULL; +} + diff --git a/core/shared/platform/android/platform_internal.h b/core/shared/platform/android/platform_internal.h index b52348d0c..5754daf7d 100644 --- a/core/shared/platform/android/platform_internal.h +++ b/core/shared/platform/android/platform_internal.h @@ -40,7 +40,7 @@ extern "C" { #define _STACK_SIZE_ADJUSTMENT (32 * 1024) /* Stack size of applet threads's native part. */ -#define BH_APPLET_PRESERVED_STACK_SIZE (8 * 1024 + _STACK_SIZE_ADJUSTMENT) +#define BH_APPLET_PRESERVED_STACK_SIZE (32 * 1024 + _STACK_SIZE_ADJUSTMENT) /* Default thread priority */ #define BH_THREAD_DEFAULT_PRIORITY 0 diff --git a/core/shared/platform/common/posix/posix_thread.c b/core/shared/platform/common/posix/posix_thread.c index 161a16174..cb01a912d 100644 --- a/core/shared/platform/common/posix/posix_thread.c +++ b/core/shared/platform/common/posix/posix_thread.c @@ -3,6 +3,9 @@ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception */ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif #include "platform_api_vmcore.h" #include "platform_api_extension.h" @@ -218,3 +221,20 @@ int os_thread_join(korp_tid thread, void **value_ptr) return pthread_join(thread, value_ptr); } +uint8 *os_thread_get_stack_boundary() +{ + pthread_attr_t attr; + void *addr = NULL; + size_t size; + + if (pthread_getattr_np(pthread_self(), &attr) == 0) { + pthread_attr_getstack(&attr, &addr, &size); + pthread_attr_destroy (&attr); + } + + if (addr) + return (uint8*)addr + _STACK_SIZE_ADJUSTMENT; + else + return NULL; +} + diff --git a/core/shared/platform/darwin/platform_internal.h b/core/shared/platform/darwin/platform_internal.h index 7d1e18a79..de2eb2051 100644 --- a/core/shared/platform/darwin/platform_internal.h +++ b/core/shared/platform/darwin/platform_internal.h @@ -40,7 +40,7 @@ extern "C" { #define _STACK_SIZE_ADJUSTMENT (32 * 1024) /* Stack size of applet threads's native part. */ -#define BH_APPLET_PRESERVED_STACK_SIZE (8 * 1024 + _STACK_SIZE_ADJUSTMENT) +#define BH_APPLET_PRESERVED_STACK_SIZE (32 * 1024 + _STACK_SIZE_ADJUSTMENT) /* Default thread priority */ #define BH_THREAD_DEFAULT_PRIORITY 0 diff --git a/core/shared/platform/include/platform_api_vmcore.h b/core/shared/platform/include/platform_api_vmcore.h index 2099a7507..df7899520 100644 --- a/core/shared/platform/include/platform_api_vmcore.h +++ b/core/shared/platform/include/platform_api_vmcore.h @@ -65,6 +65,13 @@ uint64 os_time_get_boot_microsecond(void); */ korp_tid os_self_thread(void); +/** + * Get current thread's stack boundary address, used for runtime + * to check the native stack overflow. Return NULL if it is not + * easy to implement, but may have potential issue. + */ +uint8 *os_thread_get_stack_boundary(void); + /** ************** mutext APIs *********** * vmcore: Not required until pthread is supported by runtime diff --git a/core/shared/platform/linux-sgx/sgx_thread.c b/core/shared/platform/linux-sgx/sgx_thread.c index c7fa01ff8..3f398949a 100644 --- a/core/shared/platform/linux-sgx/sgx_thread.c +++ b/core/shared/platform/linux-sgx/sgx_thread.c @@ -47,3 +47,9 @@ int os_cond_destroy(korp_cond *cond) return BHT_OK; } +uint8 *os_thread_get_stack_boundary() +{ + /* TODO: get sgx stack boundary */ + return NULL; +} + diff --git a/core/shared/platform/linux/platform_internal.h b/core/shared/platform/linux/platform_internal.h index 1a03b5077..343172bef 100644 --- a/core/shared/platform/linux/platform_internal.h +++ b/core/shared/platform/linux/platform_internal.h @@ -40,7 +40,7 @@ extern "C" { #define _STACK_SIZE_ADJUSTMENT (32 * 1024) /* Stack size of applet threads's native part. */ -#define BH_APPLET_PRESERVED_STACK_SIZE (8 * 1024 + _STACK_SIZE_ADJUSTMENT) +#define BH_APPLET_PRESERVED_STACK_SIZE (32 * 1024 + _STACK_SIZE_ADJUSTMENT) /* Default thread priority */ #define BH_THREAD_DEFAULT_PRIORITY 0 diff --git a/core/shared/platform/vxworks/platform_internal.h b/core/shared/platform/vxworks/platform_internal.h index 74ed01dbc..266c804c5 100644 --- a/core/shared/platform/vxworks/platform_internal.h +++ b/core/shared/platform/vxworks/platform_internal.h @@ -39,7 +39,7 @@ extern "C" { #define _STACK_SIZE_ADJUSTMENT (32 * 1024) /* Stack size of applet threads's native part. */ -#define BH_APPLET_PRESERVED_STACK_SIZE (8 * 1024 + _STACK_SIZE_ADJUSTMENT) +#define BH_APPLET_PRESERVED_STACK_SIZE (32 * 1024 + _STACK_SIZE_ADJUSTMENT) /* Default thread priority */ #define BH_THREAD_DEFAULT_PRIORITY 0 diff --git a/core/shared/platform/zephyr/zephyr_thread.c b/core/shared/platform/zephyr/zephyr_thread.c index cbed2596c..de54251bd 100644 --- a/core/shared/platform/zephyr/zephyr_thread.c +++ b/core/shared/platform/zephyr/zephyr_thread.c @@ -444,3 +444,13 @@ int os_cond_signal(korp_cond *cond) return BHT_OK; } +uint8 *os_thread_get_stack_boundary() +{ +#if defined(CONFIG_THREAD_STACK_INFO) + korp_tid thread = k_current_get(); + return (uint8*)thread->stack_info.start; +#else + return NULL; +#endif +} + diff --git a/samples/littlevgl/vgl-native-ui-app/CMakeLists.txt b/samples/littlevgl/vgl-native-ui-app/CMakeLists.txt index 45ff9bc85..f43b9c1e1 100644 --- a/samples/littlevgl/vgl-native-ui-app/CMakeLists.txt +++ b/samples/littlevgl/vgl-native-ui-app/CMakeLists.txt @@ -128,6 +128,7 @@ include_directories( ${LVGL_DRIVER_DIR}/display ${LVGL_DRIVER_DIR}/indev ${LVGL_SOURCE_DIR} + ${LVGL_SOURCE_DIR}/.. ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_LIST_DIR} ${CMAKE_CURRENT_LIST_DIR}/../lv_config diff --git a/wamr-compiler/CMakeLists.txt b/wamr-compiler/CMakeLists.txt index ea65406b7..336e317d1 100644 --- a/wamr-compiler/CMakeLists.txt +++ b/wamr-compiler/CMakeLists.txt @@ -59,7 +59,7 @@ if (CMAKE_SIZEOF_VOID_P EQUAL 8) endif () if (NOT CMAKE_BUILD_TYPE) - set(CMAKE_BUILD_TYPE Release) + set(CMAKE_BUILD_TYPE Release) endif (NOT CMAKE_BUILD_TYPE) message ("-- CMAKE_BUILD_TYPE = " ${CMAKE_BUILD_TYPE}) From e8e45aeecd1b3e35205767dc85825299a910d458 Mon Sep 17 00:00:00 2001 From: wenyongh Date: Fri, 8 May 2020 12:38:59 +0800 Subject: [PATCH 005/207] Refine aot stack overflow check and enhance wasm loader malformed checks (#248) And separate global data from wasm memory instance --- core/iwasm/aot/aot_loader.c | 14 +- core/iwasm/aot/aot_runtime.c | 18 +- core/iwasm/compilation/aot.c | 2 + core/iwasm/compilation/aot.h | 2 + core/iwasm/compilation/aot_emit_function.c | 26 +- core/iwasm/interpreter/wasm_interp_classic.c | 3 +- core/iwasm/interpreter/wasm_interp_fast.c | 3 +- core/iwasm/interpreter/wasm_loader.c | 225 ++++++++++++------ core/iwasm/interpreter/wasm_runtime.c | 80 +++---- core/iwasm/interpreter/wasm_runtime.h | 9 +- .../platform/android/platform_internal.h | 4 +- .../platform/common/posix/posix_thread.c | 3 +- .../platform/darwin/platform_internal.h | 4 +- .../shared/platform/linux/platform_internal.h | 4 +- .../platform/vxworks/platform_internal.h | 4 +- .../src/platform/zephyr/iwasm_main.c | 2 +- 16 files changed, 241 insertions(+), 162 deletions(-) diff --git a/core/iwasm/aot/aot_loader.c b/core/iwasm/aot/aot_loader.c index a68f8e96c..560030d56 100644 --- a/core/iwasm/aot/aot_loader.c +++ b/core/iwasm/aot/aot_loader.c @@ -1959,12 +1959,14 @@ aot_load_from_comp_data(AOTCompData *comp_data, AOTCompContext *comp_ctx, module->start_func_index = comp_data->start_func_index; if (comp_data->start_func_index != (uint32)-1) { - bh_assert(comp_data->start_func_index >= module->import_func_count - && comp_data->start_func_index < module->import_func_count - + module->func_count); - module->start_function = - module->func_ptrs[comp_data->start_func_index - - module->import_func_count]; + bh_assert(comp_data->start_func_index < module->import_func_count + + module->func_count); + /* TODO: fix issue that start func cannot be import func */ + if (comp_data->start_func_index >= module->import_func_count) { + module->start_function = + module->func_ptrs[comp_data->start_func_index + - module->import_func_count]; + } } else { module->start_function = NULL; diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index 308e545c8..a57f8e8d4 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -897,6 +897,15 @@ aot_call_indirect(WASMExecEnv *exec_env, void *attachment = NULL; char buf[128]; + /* this function is called from native code, so exec_env->handle and + exec_env->native_stack_boundary must have been set, we don't set + it again */ + + if ((uint8*)&module_inst < exec_env->native_stack_boundary) { + aot_set_exception_with_id(module_inst, EXCE_NATIVE_STACK_OVERFLOW); + return false; + } + if (table_elem_idx >= table_size) { aot_set_exception_with_id(module_inst, EXCE_UNDEFINED_ELEMENT); return false; @@ -941,15 +950,6 @@ aot_call_indirect(WASMExecEnv *exec_env, } } - /* this function is called from native code, so exec_env->handle and - exec_env->native_stack_boundary must have been set, we don't set - it again */ - - if ((uint8*)&module_inst < exec_env->native_stack_boundary) { - aot_set_exception_with_id(module_inst, EXCE_NATIVE_STACK_OVERFLOW); - return false; - } - return wasm_runtime_invoke_native(exec_env, func_ptr, func_type, signature, attachment, argv, argc, argv); diff --git a/core/iwasm/compilation/aot.c b/core/iwasm/compilation/aot.c index ee431fd4f..a130ba7a6 100644 --- a/core/iwasm/compilation/aot.c +++ b/core/iwasm/compilation/aot.c @@ -327,6 +327,8 @@ aot_create_funcs(const WASMModule *module) /* Resolve local variable info and code info */ funcs[i]->local_count = func->local_count; funcs[i]->local_types = func->local_types; + funcs[i]->param_cell_num = func->param_cell_num; + funcs[i]->local_cell_num = func->local_cell_num; funcs[i]->code = func->code; funcs[i]->code_size = func->code_size; } diff --git a/core/iwasm/compilation/aot.h b/core/iwasm/compilation/aot.h index 22ccff60e..ede02b434 100644 --- a/core/iwasm/compilation/aot.h +++ b/core/iwasm/compilation/aot.h @@ -98,6 +98,8 @@ typedef struct AOTFunc { uint32 func_type_index; uint32 local_count; uint8 *local_types; + uint16 param_cell_num; + uint16 local_cell_num; uint32 code_size; uint8 *code; } AOTFunc; diff --git a/core/iwasm/compilation/aot_emit_function.c b/core/iwasm/compilation/aot_emit_function.c index 2228177a1..3c1708928 100644 --- a/core/iwasm/compilation/aot_emit_function.c +++ b/core/iwasm/compilation/aot_emit_function.c @@ -256,11 +256,25 @@ call_aot_invoke_native_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } static bool -check_stack_boundary(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) +check_stack_boundary(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, + uint32 callee_cell_num) { LLVMBasicBlockRef block_curr = LLVMGetInsertBlock(comp_ctx->builder); LLVMBasicBlockRef check_stack; - LLVMValueRef cmp; + LLVMValueRef callee_local_size, stack_bound, cmp; + + if (!(callee_local_size = I32_CONST(callee_cell_num * 4))) { + aot_set_last_error("llvm build const failed."); + return false; + } + + if (!(stack_bound = LLVMBuildInBoundsGEP(comp_ctx->builder, + func_ctx->native_stack_bound, + &callee_local_size, 1, + "stack_bound"))) { + aot_set_last_error("llvm build inbound gep failed."); + return false; + } if (!(check_stack = LLVMAppendBasicBlockInContext(comp_ctx->context, func_ctx->func, @@ -272,7 +286,7 @@ check_stack_boundary(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) LLVMMoveBasicBlockAfter(check_stack, block_curr); if (!(cmp = LLVMBuildICmp(comp_ctx->builder, LLVMIntULT, - func_ctx->last_alloca, func_ctx->native_stack_bound, + func_ctx->last_alloca, stack_bound, "cmp"))) { aot_set_last_error("llvm build icmp failed."); return false; @@ -297,11 +311,13 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, uint32 func_count = comp_ctx->func_ctx_count, param_cell_num = 0; AOTFuncContext **func_ctxes = comp_ctx->func_ctxes; AOTFuncType *func_type; + AOTFunc *aot_func; LLVMTypeRef *param_types = NULL, ret_type; LLVMValueRef *param_values = NULL, value_ret = NULL, func; LLVMValueRef import_func_idx, res; int32 i, j = 0, param_count; uint64 total_size; + uint32 callee_cell_num; uint8 wasm_ret_type; bool ret = false; @@ -379,8 +395,10 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } else { func = func_ctxes[func_idx - import_func_count]->func; + aot_func = func_ctxes[func_idx - import_func_count]->aot_func; + callee_cell_num = aot_func->param_cell_num + aot_func->local_cell_num + 1; - if (!check_stack_boundary(comp_ctx, func_ctx)) + if (!check_stack_boundary(comp_ctx, func_ctx, callee_cell_num)) goto fail; /* Call the function */ diff --git a/core/iwasm/interpreter/wasm_interp_classic.c b/core/iwasm/interpreter/wasm_interp_classic.c index dea86c1bc..54fb7ccb2 100644 --- a/core/iwasm/interpreter/wasm_interp_classic.c +++ b/core/iwasm/interpreter/wasm_interp_classic.c @@ -901,7 +901,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, uint32 num_bytes_per_page = memory ? memory->num_bytes_per_page : 0; uint32 total_mem_size = memory ? num_bytes_per_page * memory->cur_page_count - heap_base_offset : 0; - uint8 *global_data = memory ? memory->global_data : NULL; + uint8 *global_data = module->global_data; WASMTableInstance *table = module->default_table; WASMGlobalInstance *globals = module->globals; uint8 opcode_IMPDEP = WASM_OP_IMPDEP; @@ -1521,7 +1521,6 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, memory = module->default_memory; total_mem_size = num_bytes_per_page * memory->cur_page_count - heap_base_offset; - global_data = memory->global_data; } (void)reserved; diff --git a/core/iwasm/interpreter/wasm_interp_fast.c b/core/iwasm/interpreter/wasm_interp_fast.c index ae4cbb3eb..60a04dc50 100644 --- a/core/iwasm/interpreter/wasm_interp_fast.c +++ b/core/iwasm/interpreter/wasm_interp_fast.c @@ -893,7 +893,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, uint32 num_bytes_per_page = memory ? memory->num_bytes_per_page : 0; uint32 total_mem_size = memory ? num_bytes_per_page * memory->cur_page_count - heap_base_offset : 0; - uint8 *global_data = memory ? memory->global_data : NULL; + uint8 *global_data = module->global_data; WASMTableInstance *table = module->default_table; WASMGlobalInstance *globals = module->globals; uint8 opcode_IMPDEP = WASM_OP_IMPDEP; @@ -1429,7 +1429,6 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, memory = module->default_memory; total_mem_size = num_bytes_per_page * memory->cur_page_count - heap_base_offset; - global_data = memory->global_data; } (void)reserved; diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index 24d02d0b8..5c882e9df 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -467,6 +467,18 @@ load_type_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, return true; } +static bool +check_table_max_size(uint32 init_size, uint32 max_size, + char *error_buf, uint32 error_buf_size) +{ + if (max_size < init_size) { + set_error_buf(error_buf, error_buf_size, + "size minimum must not be greater than maximum"); + return false; + } + return true; +} + static bool load_table_import(const uint8 **p_buf, const uint8 *buf_end, WASMTableImport *table, @@ -480,8 +492,12 @@ load_table_import(const uint8 **p_buf, const uint8 *buf_end, bh_assert(table->elem_type == TABLE_ELEM_TYPE_ANY_FUNC); read_leb_uint32(p, p_end, table->flags); read_leb_uint32(p, p_end, table->init_size); - if (table->flags & 1) + if (table->flags & 1) { read_leb_uint32(p, p_end, table->max_size); + if (!check_table_max_size(table->init_size, table->max_size, + error_buf, error_buf_size)) + return false; + } else table->max_size = 0x10000; @@ -573,8 +589,12 @@ load_table(const uint8 **p_buf, const uint8 *buf_end, WASMTable *table, bh_assert(table->elem_type == TABLE_ELEM_TYPE_ANY_FUNC); read_leb_uint32(p, p_end, table->flags); read_leb_uint32(p, p_end, table->init_size); - if (table->flags & 1) + if (table->flags & 1) { read_leb_uint32(p, p_end, table->max_size); + if (!check_table_max_size(table->init_size, table->max_size, + error_buf, error_buf_size)) + return false; + } else table->max_size = 0x10000; @@ -1065,7 +1085,6 @@ load_table_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, WASMTable *table; read_leb_uint32(p, p_end, table_count); - bh_assert(table_count == 1); if (table_count) { if (table_count > 1) { @@ -2419,6 +2438,7 @@ typedef struct BranchBlock { uint8 block_type; uint8 return_type; bool is_block_reachable; + bool skip_else_branch; uint8 *start_addr; uint8 *else_addr; uint8 *end_addr; @@ -2590,10 +2610,13 @@ check_stack_pop(WASMLoaderContext *ctx, uint8 type, char *error_buf, uint32 error_buf_size, const char *type_str) { + uint32 block_stack_cell_num = ctx->stack_cell_num + - (ctx->frame_csp - 1)->stack_cell_num; + if (((type == VALUE_TYPE_I32 || type == VALUE_TYPE_F32) - && ctx->stack_cell_num < 1) + && block_stack_cell_num < 1) || ((type == VALUE_TYPE_I64 || type == VALUE_TYPE_F64) - && ctx->stack_cell_num < 2)) { + && block_stack_cell_num < 2)) { set_error_buf(error_buf, error_buf_size, "WASM module load failed: " "type mismatch: expect data but stack was empty"); @@ -2766,7 +2789,17 @@ static bool wasm_loader_pop_frame_csp(WASMLoaderContext *ctx, char *error_buf, uint32 error_buf_size) { + uint8 block_return_type; + CHECK_CSP_POP(); + + block_return_type = (ctx->frame_csp - 1)->return_type; + if (!wasm_loader_pop_frame_ref(ctx, block_return_type, + error_buf, error_buf_size) + || !wasm_loader_push_frame_ref(ctx, block_return_type, + error_buf, error_buf_size)) + goto fail; + ctx->frame_csp--; ctx->csp_num--; return true; @@ -3476,7 +3509,6 @@ fail: goto fail; \ } while (0) - #define GET_LOCAL_INDEX_TYPE_AND_OFFSET() do { \ read_leb_uint32(p, p_end, local_idx); \ if (local_idx >= param_count + local_count) { \ @@ -3515,11 +3547,6 @@ check_memory(WASMModule *module, goto fail; \ } while (0) -#if WASM_ENABLE_FAST_INTERP != 0 - - -#endif /* WASM_ENABLE_FAST_INTERP */ - static bool is_block_type_valid(uint8 type) { @@ -3538,6 +3565,44 @@ is_block_type_valid(uint8 type) } \ } while (0) +static BranchBlock * +check_branch_block(WASMLoaderContext *loader_ctx, + uint8 **p_buf, uint8 *buf_end, + char *error_buf, uint32 error_buf_size) +{ + uint8 *p = *p_buf, *p_end = buf_end; + BranchBlock *frame_csp_tmp; + uint32 depth; + + read_leb_uint32(p, p_end, depth); + CHECK_BR(depth); + frame_csp_tmp = loader_ctx->frame_csp - depth - 1; +#if WASM_ENABLE_FAST_INTERP != 0 + emit_br_info(frame_csp_tmp); +#endif + + *p_buf = p; + return frame_csp_tmp; +fail: + return NULL; +} + +static bool +check_branch_block_ret(WASMLoaderContext *loader_ctx, + BranchBlock *frame_csp_tmp, + char *error_buf, uint32 error_buf_size) +{ + frame_csp_tmp->is_block_reachable = true; + if (frame_csp_tmp->block_type != BLOCK_TYPE_LOOP) { + uint8 block_return_type = frame_csp_tmp->return_type; + POP_TYPE(block_return_type); + PUSH_TYPE(block_return_type); + } + return true; +fail: + return false; +} + static bool wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, BlockAddr *block_addr_cache, @@ -3547,7 +3612,7 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, uint32 param_count, local_count, global_count; uint8 *param_types, ret_type, *local_types, local_type, global_type; uint16 *local_offsets, local_offset; - uint32 count, i, local_idx, global_idx, depth, u32, align, mem_offset; + uint32 count, i, local_idx, global_idx, u32, align, mem_offset; uint32 cache_index, item_index; int32 i32, i32_const = 0; int64 i64; @@ -3555,6 +3620,7 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, bool return_value = false, is_i32_const = false; BlockAddr *cache_items; WASMLoaderContext *loader_ctx; + BranchBlock *frame_csp_tmp; #if WASM_ENABLE_FAST_INTERP != 0 uint8 *func_const_end, *func_const; int16 operand_offset; @@ -3657,32 +3723,32 @@ re_scan: if (!is_i32_const) (loader_ctx->frame_csp - 1)->is_block_reachable = true; else { - if (!i32_const) { - cache_index = ((uintptr_t)(loader_ctx->frame_csp - 1)->start_addr) - & (uintptr_t)(BLOCK_ADDR_CACHE_SIZE - 1); - cache_items = block_addr_cache + - BLOCK_ADDR_CONFLICT_SIZE * cache_index; - for (item_index = 0; item_index < BLOCK_ADDR_CONFLICT_SIZE; - item_index++) { - if (cache_items[item_index].start_addr == - (loader_ctx->frame_csp - 1)->start_addr) { - (loader_ctx->frame_csp - 1)->else_addr = - cache_items[item_index].else_addr; - (loader_ctx->frame_csp - 1)->end_addr = - cache_items[item_index].end_addr; - break; - } + cache_index = ((uintptr_t)(loader_ctx->frame_csp - 1)->start_addr) + & (uintptr_t)(BLOCK_ADDR_CACHE_SIZE - 1); + cache_items = block_addr_cache + + BLOCK_ADDR_CONFLICT_SIZE * cache_index; + for (item_index = 0; item_index < BLOCK_ADDR_CONFLICT_SIZE; + item_index++) { + if (cache_items[item_index].start_addr == + (loader_ctx->frame_csp - 1)->start_addr) { + (loader_ctx->frame_csp - 1)->else_addr = + cache_items[item_index].else_addr; + (loader_ctx->frame_csp - 1)->end_addr = + cache_items[item_index].end_addr; + break; } - if (item_index == BLOCK_ADDR_CONFLICT_SIZE - && !wasm_loader_find_block_addr(block_addr_cache, - (loader_ctx->frame_csp - 1)->start_addr, - p_end, - (loader_ctx->frame_csp - 1)->block_type, - &(loader_ctx->frame_csp - 1)->else_addr, - &(loader_ctx->frame_csp - 1)->end_addr, - error_buf, error_buf_size)) - goto fail; + } + if (item_index == BLOCK_ADDR_CONFLICT_SIZE + && !wasm_loader_find_block_addr(block_addr_cache, + (loader_ctx->frame_csp - 1)->start_addr, + p_end, + (loader_ctx->frame_csp - 1)->block_type, + &(loader_ctx->frame_csp - 1)->else_addr, + &(loader_ctx->frame_csp - 1)->end_addr, + error_buf, error_buf_size)) + goto fail; + if (!i32_const) { if ((loader_ctx->frame_csp - 1)->else_addr) { #if WASM_ENABLE_FAST_INTERP != 0 loader_ctx->frame_offset = loader_ctx->frame_offset_bottom + @@ -3698,6 +3764,10 @@ re_scan: is_i32_const = false; continue; } + else { + /* The else branch cannot be reached, ignored it. */ + (loader_ctx->frame_csp - 1)->skip_else_branch = true; + } } break; @@ -3710,6 +3780,16 @@ re_scan: goto fail; } + if ((loader_ctx->frame_csp - 1)->skip_else_branch) { + /* The else branch is ignored. */ + is_i32_const = false; + p = (loader_ctx->frame_csp - 1)->end_addr; +#if WASM_ENABLE_FAST_INTERP != 0 + skip_label(); +#endif + continue; + } + (loader_ctx->frame_csp - 1)->else_addr = p - 1; loader_ctx->stack_cell_num = (loader_ctx->frame_csp - 1)->stack_cell_num; loader_ctx->frame_ref = loader_ctx->frame_ref_bottom + @@ -3748,9 +3828,6 @@ re_scan: { POP_CSP(); - POP_TYPE(loader_ctx->frame_csp->return_type); - PUSH_TYPE(loader_ctx->frame_csp->return_type); - #if WASM_ENABLE_FAST_INTERP != 0 skip_label(); // copy the result to the block return address @@ -3800,16 +3877,13 @@ re_scan: case WASM_OP_BR: { -#if WASM_ENABLE_FAST_INTERP != 0 - BranchBlock *frame_csp_tmp; -#endif - read_leb_uint32(p, p_end, depth); - CHECK_BR(depth); + if (!(frame_csp_tmp = check_branch_block(loader_ctx, &p, p_end, + error_buf, error_buf_size))) + goto fail; -#if WASM_ENABLE_FAST_INTERP != 0 - frame_csp_tmp = loader_ctx->frame_csp - depth - 1; - emit_br_info(frame_csp_tmp); -#endif + if (!check_branch_block_ret(loader_ctx, frame_csp_tmp, + error_buf, error_buf_size)) + goto fail; handle_next_reachable_block: for (i = 1; i <= loader_ctx->csp_num; i++) @@ -3870,31 +3944,25 @@ handle_next_reachable_block: case WASM_OP_BR_IF: { -#if WASM_ENABLE_FAST_INTERP != 0 - BranchBlock *frame_csp_tmp; -#endif - read_leb_uint32(p, p_end, depth); POP_I32(); - CHECK_BR(depth); -#if WASM_ENABLE_FAST_INTERP != 0 - frame_csp_tmp = loader_ctx->frame_csp - depth - 1; - emit_br_info(frame_csp_tmp); -#endif - if (!is_i32_const) - (loader_ctx->frame_csp - (depth + 1))->is_block_reachable = true; - else { - if (i32_const) - goto handle_next_reachable_block; + + if (!(frame_csp_tmp = check_branch_block(loader_ctx, &p, p_end, + error_buf, error_buf_size))) + goto fail; + + if (!is_i32_const || i32_const) { + /* The branch can be reached */ + if (!check_branch_block_ret(loader_ctx, frame_csp_tmp, + error_buf, error_buf_size)) + goto fail; } + if (is_i32_const && i32_const) + goto handle_next_reachable_block; break; } case WASM_OP_BR_TABLE: { -#if WASM_ENABLE_FAST_INTERP != 0 - BranchBlock *frame_csp_tmp; -#endif - read_leb_uint32(p, p_end, count); #if WASM_ENABLE_FAST_INTERP != 0 emit_const(count); @@ -3903,12 +3971,13 @@ handle_next_reachable_block: /* TODO: check the const */ for (i = 0; i <= count; i++) { - read_leb_uint32(p, p_end, depth); - CHECK_BR(depth); -#if WASM_ENABLE_FAST_INTERP != 0 - frame_csp_tmp = loader_ctx->frame_csp - depth - 1; - emit_br_info(frame_csp_tmp); -#endif + if (!(frame_csp_tmp = check_branch_block(loader_ctx, &p, p_end, + error_buf, error_buf_size))) + goto fail; + + if (!check_branch_block_ret(loader_ctx, frame_csp_tmp, + error_buf, error_buf_size)) + goto fail; } goto handle_next_reachable_block; @@ -4037,10 +4106,12 @@ handle_next_reachable_block: case WASM_OP_DROP: case WASM_OP_DROP_64: { - if (loader_ctx->stack_cell_num <= 0) { + if (loader_ctx->stack_cell_num + - (loader_ctx->frame_csp - 1)->stack_cell_num <= 0) { set_error_buf(error_buf, error_buf_size, "WASM loader prepare bytecode failed: " - "opcode drop was found but stack was empty"); + "type mismatch, opcode drop was found " + "but stack was empty"); goto fail; } @@ -4057,10 +4128,12 @@ handle_next_reachable_block: #endif } else { - if (loader_ctx->stack_cell_num <= 1) { + if (loader_ctx->stack_cell_num + - (loader_ctx->frame_csp - 1)->stack_cell_num <= 0) { set_error_buf(error_buf, error_buf_size, "WASM loader prepare bytecode failed: " - "opcode drop was found but stack was empty"); + "type mismatch, opcode drop was found " + "but stack was empty"); goto fail; } loader_ctx->frame_ref -= 2; diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index 84785804d..9bf28c239 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -60,15 +60,13 @@ memories_deinstantiate(WASMMemoryInstance **memories, uint32 count) static WASMMemoryInstance* memory_instantiate(uint32 num_bytes_per_page, uint32 init_page_count, uint32 max_page_count, - uint32 global_data_size, uint32 heap_size, char *error_buf, uint32 error_buf_size) { WASMMemoryInstance *memory; uint64 total_size = offsetof(WASMMemoryInstance, base_addr) + (uint64)heap_size + - num_bytes_per_page * (uint64)init_page_count + - global_data_size; + num_bytes_per_page * (uint64)init_page_count; /* Allocate memory space, addr data and global data */ if (total_size >= UINT32_MAX @@ -85,10 +83,8 @@ memory_instantiate(uint32 num_bytes_per_page, memory->heap_data = memory->base_addr; memory->memory_data = memory->heap_data + heap_size; - memory->global_data = memory->memory_data + + memory->end_addr = memory->memory_data + num_bytes_per_page * memory->cur_page_count; - memory->global_data_size = global_data_size; - memory->end_addr = memory->global_data + global_data_size; bh_assert(memory->end_addr - (uint8*)memory == (uint32)total_size); @@ -112,7 +108,7 @@ memory_instantiate(uint32 num_bytes_per_page, */ static WASMMemoryInstance** memories_instantiate(const WASMModule *module, - uint32 global_data_size, uint32 heap_size, + uint32 heap_size, char *error_buf, uint32 error_buf_size) { WASMImport *import; @@ -121,9 +117,6 @@ memories_instantiate(const WASMModule *module, uint64 total_size; WASMMemoryInstance **memories, *memory; - if (memory_count == 0 && global_data_size > 0) - memory_count = 1; - total_size = sizeof(WASMMemoryInstance*) * (uint64)memory_count; if (total_size >= UINT32_MAX @@ -143,7 +136,6 @@ memories_instantiate(const WASMModule *module, memory_instantiate(import->u.memory.num_bytes_per_page, import->u.memory.init_page_count, import->u.memory. max_page_count, - global_data_size, heap_size, error_buf, error_buf_size))) { set_error_buf(error_buf, error_buf_size, "Instantiate memory failed: " @@ -159,7 +151,6 @@ memories_instantiate(const WASMModule *module, memory_instantiate(module->memories[i].num_bytes_per_page, module->memories[i].init_page_count, module->memories[i].max_page_count, - global_data_size, heap_size, error_buf, error_buf_size))) { set_error_buf(error_buf, error_buf_size, "Instantiate memory failed: " @@ -172,8 +163,8 @@ memories_instantiate(const WASMModule *module, if (mem_index == 0) { /* no import memory and define memory, but has global variables */ if (!(memory = memories[mem_index++] = - memory_instantiate(0, 0, 0, global_data_size, - heap_size, error_buf, error_buf_size))) { + memory_instantiate(0, 0, 0, heap_size, + error_buf, error_buf_size))) { set_error_buf(error_buf, error_buf_size, "Instantiate memory failed: " "allocate memory failed.\n"); @@ -608,11 +599,20 @@ wasm_instantiate(WASMModule *module, module->import_function_count + module->function_count; module_inst->export_func_count = get_export_function_count(module); + if (global_count > 0) { + if (!(module_inst->global_data = + wasm_runtime_malloc(global_data_size))) { + wasm_deinstantiate(module_inst); + return NULL; + } + memset(module_inst->global_data, 0, global_data_size); + } + /* Instantiate memories/tables/functions */ - if (((module_inst->memory_count > 0 || global_count > 0) + if ((module_inst->memory_count > 0 && !(module_inst->memories = - memories_instantiate(module, global_data_size, - heap_size, error_buf, error_buf_size))) + memories_instantiate(module, heap_size, + error_buf, error_buf_size))) || (module_inst->table_count > 0 && !(module_inst->tables = tables_instantiate(module, error_buf, @@ -629,13 +629,8 @@ wasm_instantiate(WASMModule *module, return NULL; } - if (module_inst->memory_count || global_count > 0) { - WASMMemoryInstance *memory; - - memory = module_inst->default_memory = module_inst->memories[0]; - memory_data = module_inst->default_memory->memory_data; - - /* fix import memoryBase */ + if (global_count > 0) { + /* fix globals */ if (!globals_instantiate_fix(globals, module, module_inst, error_buf, error_buf_size)) { wasm_deinstantiate(module_inst); @@ -643,7 +638,7 @@ wasm_instantiate(WASMModule *module, } /* Initialize the global data */ - global_data = memory->global_data; + global_data = module_inst->global_data; global_data_end = global_data + global_data_size; global = globals; for (i = 0; i < global_count; i++, global++) { @@ -665,8 +660,16 @@ wasm_instantiate(WASMModule *module, } bh_assert(global_data == global_data_end); + } + + if (module_inst->memory_count) { + WASMMemoryInstance *memory; + + memory = module_inst->default_memory = module_inst->memories[0]; + memory_data = module_inst->default_memory->memory_data; + /* Initialize the memory data with data segment section */ - if (module_inst->default_memory->cur_page_count > 0) { + if (memory->cur_page_count > 0) { for (i = 0; i < module->data_seg_count; i++) { data_seg = module->data_segments[i]; bh_assert(data_seg->memory_index == 0); @@ -685,8 +688,8 @@ wasm_instantiate(WASMModule *module, base_offset = (uint32)data_seg->base_offset.u.i32; length = data_seg->data_length; - memory_size = module_inst->default_memory->num_bytes_per_page - * module_inst->default_memory->cur_page_count; + memory_size = memory->num_bytes_per_page + * memory->cur_page_count; if (length > 0 && (base_offset >= memory_size @@ -825,6 +828,9 @@ wasm_deinstantiate(WASMModuleInstance *module_inst) globals_deinstantiate(module_inst->globals); export_functions_deinstantiate(module_inst->export_functions); + if (module_inst->global_data) + wasm_runtime_free(module_inst->global_data); + wasm_runtime_free(module_inst); } @@ -1057,14 +1063,11 @@ wasm_enlarge_memory(WASMModuleInstance *module, uint32 inc_page_count) { WASMMemoryInstance *memory = module->default_memory, *new_memory; uint32 heap_size = memory->memory_data - memory->heap_data; - uint32 old_page_count = memory->cur_page_count; uint32 total_size_old = memory->end_addr - (uint8*)memory; uint32 total_page_count = inc_page_count + memory->cur_page_count; uint64 total_size = offsetof(WASMMemoryInstance, base_addr) + (uint64)heap_size - + memory->num_bytes_per_page * (uint64)total_page_count - + memory->global_data_size; - uint8 *global_data_old; + + memory->num_bytes_per_page * (uint64)total_page_count; void *heap_handle_old = memory->heap_handle; if (inc_page_count <= 0) @@ -1111,17 +1114,8 @@ wasm_enlarge_memory(WASMModuleInstance *module, uint32 inc_page_count) new_memory->cur_page_count = total_page_count; new_memory->heap_data = new_memory->base_addr; new_memory->memory_data = new_memory->base_addr + heap_size; - new_memory->global_data = new_memory->memory_data + - new_memory->num_bytes_per_page * total_page_count; - new_memory->end_addr = new_memory->global_data + new_memory->global_data_size; - - global_data_old = new_memory->memory_data + - new_memory->num_bytes_per_page * old_page_count; - - /* Copy global data */ - bh_memcpy_s(new_memory->global_data, new_memory->global_data_size, - global_data_old, new_memory->global_data_size); - memset(global_data_old, 0, new_memory->global_data_size); + new_memory->end_addr = new_memory->memory_data + + new_memory->num_bytes_per_page * total_page_count; module->memories[0] = module->default_memory = new_memory; return true; diff --git a/core/iwasm/interpreter/wasm_runtime.h b/core/iwasm/interpreter/wasm_runtime.h index 102db8795..03268e63d 100644 --- a/core/iwasm/interpreter/wasm_runtime.h +++ b/core/iwasm/interpreter/wasm_runtime.h @@ -33,17 +33,12 @@ typedef struct WASMMemoryInstance { /* Memory data */ uint8 *memory_data; - /* Global data of global instances */ - uint8 *global_data; - uint32 global_data_size; - /* End address of memory */ uint8 *end_addr; /* Base address, the layout is: - heap_data + memory data + global data + heap_data + memory data memory data init size is: num_bytes_per_page * cur_page_count - global data size is calculated in module instantiating Note: when memory is re-allocated, the heap data and memory data must be copied to new memory also. */ @@ -127,6 +122,8 @@ typedef struct WASMModuleInstance { WASMMemoryInstance *default_memory; WASMTableInstance *default_table; + /* Global data of global instances */ + uint8 *global_data; WASMFunctionInstance *start_function; diff --git a/core/shared/platform/android/platform_internal.h b/core/shared/platform/android/platform_internal.h index 5754daf7d..bf1248a25 100644 --- a/core/shared/platform/android/platform_internal.h +++ b/core/shared/platform/android/platform_internal.h @@ -37,10 +37,8 @@ extern "C" { #define BH_PLATFORM_ANDROID #endif -#define _STACK_SIZE_ADJUSTMENT (32 * 1024) - /* Stack size of applet threads's native part. */ -#define BH_APPLET_PRESERVED_STACK_SIZE (32 * 1024 + _STACK_SIZE_ADJUSTMENT) +#define BH_APPLET_PRESERVED_STACK_SIZE (32 * 1024) /* Default thread priority */ #define BH_THREAD_DEFAULT_PRIORITY 0 diff --git a/core/shared/platform/common/posix/posix_thread.c b/core/shared/platform/common/posix/posix_thread.c index cb01a912d..1a32b1502 100644 --- a/core/shared/platform/common/posix/posix_thread.c +++ b/core/shared/platform/common/posix/posix_thread.c @@ -233,7 +233,8 @@ uint8 *os_thread_get_stack_boundary() } if (addr) - return (uint8*)addr + _STACK_SIZE_ADJUSTMENT; + /* Reserved 4 KB for safety */ + return (uint8*)addr + 4 * 1024; else return NULL; } diff --git a/core/shared/platform/darwin/platform_internal.h b/core/shared/platform/darwin/platform_internal.h index de2eb2051..55622028b 100644 --- a/core/shared/platform/darwin/platform_internal.h +++ b/core/shared/platform/darwin/platform_internal.h @@ -37,10 +37,8 @@ extern "C" { #define BH_PLATFORM_DARWIN #endif -#define _STACK_SIZE_ADJUSTMENT (32 * 1024) - /* Stack size of applet threads's native part. */ -#define BH_APPLET_PRESERVED_STACK_SIZE (32 * 1024 + _STACK_SIZE_ADJUSTMENT) +#define BH_APPLET_PRESERVED_STACK_SIZE (32 * 1024) /* Default thread priority */ #define BH_THREAD_DEFAULT_PRIORITY 0 diff --git a/core/shared/platform/linux/platform_internal.h b/core/shared/platform/linux/platform_internal.h index 343172bef..445d881fd 100644 --- a/core/shared/platform/linux/platform_internal.h +++ b/core/shared/platform/linux/platform_internal.h @@ -37,10 +37,8 @@ extern "C" { #define BH_PLATFORM_LINUX #endif -#define _STACK_SIZE_ADJUSTMENT (32 * 1024) - /* Stack size of applet threads's native part. */ -#define BH_APPLET_PRESERVED_STACK_SIZE (32 * 1024 + _STACK_SIZE_ADJUSTMENT) +#define BH_APPLET_PRESERVED_STACK_SIZE (32 * 1024) /* Default thread priority */ #define BH_THREAD_DEFAULT_PRIORITY 0 diff --git a/core/shared/platform/vxworks/platform_internal.h b/core/shared/platform/vxworks/platform_internal.h index 266c804c5..06b4d3ae4 100644 --- a/core/shared/platform/vxworks/platform_internal.h +++ b/core/shared/platform/vxworks/platform_internal.h @@ -36,10 +36,8 @@ extern "C" { #define BH_PLATFORM_VXWORKS #endif -#define _STACK_SIZE_ADJUSTMENT (32 * 1024) - /* Stack size of applet threads's native part. */ -#define BH_APPLET_PRESERVED_STACK_SIZE (32 * 1024 + _STACK_SIZE_ADJUSTMENT) +#define BH_APPLET_PRESERVED_STACK_SIZE (32 * 1024) /* Default thread priority */ #define BH_THREAD_DEFAULT_PRIORITY 0 diff --git a/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/iwasm_main.c b/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/iwasm_main.c index 217639752..cc0111eb3 100644 --- a/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/iwasm_main.c +++ b/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/iwasm_main.c @@ -74,7 +74,7 @@ host_interface interface = { timer_ctx_t timer_ctx; -static char global_heap_buf[370 * 1024] = { 0 }; +static char global_heap_buf[368 * 1024] = { 0 }; static NativeSymbol native_symbols[] = { EXPORT_WASM_API_WITH_SIG(display_input_read, "(*)i"), From 44ccfd20ad906b83a9c09a5e7f70b2e2aac38c8d Mon Sep 17 00:00:00 2001 From: wenyongh Date: Fri, 8 May 2020 13:34:07 +0800 Subject: [PATCH 006/207] Fix issue of condition settings of app boundary check (#249) --- core/iwasm/aot/aot_runtime.c | 24 +++++++++++------------- core/iwasm/interpreter/wasm_runtime.c | 22 ++++++++++------------ 2 files changed, 21 insertions(+), 25 deletions(-) diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index a57f8e8d4..d64c1f1ba 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -635,11 +635,10 @@ aot_validate_app_addr(AOTModuleInstance *module_inst, goto fail; } - if (app_offset <= module_inst->heap_base_offset - || app_offset + (int32)size > (int32)module_inst->memory_data_size) { - goto fail; + if (module_inst->heap_base_offset <= app_offset + && app_offset + (int32)size <= (int32)module_inst->memory_data_size) { + return true; } - return true; fail: aot_set_exception(module_inst, "out of bounds memory access"); return false; @@ -657,12 +656,11 @@ aot_validate_native_addr(AOTModuleInstance *module_inst, goto fail; } - if (addr <= (uint8*)module_inst->heap_data.ptr - || addr + size > (uint8*)module_inst->memory_data.ptr - + memory_data_size) { - goto fail; + if ((uint8*)module_inst->heap_data.ptr <= addr + && addr + size <= (uint8*)module_inst->memory_data.ptr + + memory_data_size) { + return true; } - return true; fail: aot_set_exception(module_inst, "out of bounds memory access"); return false; @@ -674,7 +672,7 @@ aot_addr_app_to_native(AOTModuleInstance *module_inst, int32 app_offset) int32 memory_data_size = (int32)module_inst->memory_data_size; uint8 *addr = (uint8 *)module_inst->memory_data.ptr + app_offset; - if ((uint8*)module_inst->heap_data.ptr < addr + if ((uint8*)module_inst->heap_data.ptr <= addr && addr < (uint8*)module_inst->memory_data.ptr + memory_data_size) return addr; @@ -687,7 +685,7 @@ aot_addr_native_to_app(AOTModuleInstance *module_inst, void *native_ptr) uint8 *addr = (uint8*)native_ptr; int32 memory_data_size = (int32)module_inst->memory_data_size; - if ((uint8*)module_inst->heap_data.ptr < addr + if ((uint8*)module_inst->heap_data.ptr <= addr && addr < (uint8*)module_inst->memory_data.ptr + memory_data_size) return (int32)(addr - (uint8*)module_inst->memory_data.ptr); @@ -702,7 +700,7 @@ aot_get_app_addr_range(AOTModuleInstance *module_inst, { int32 memory_data_size = (int32)module_inst->memory_data_size; - if (module_inst->heap_base_offset < app_offset + if (module_inst->heap_base_offset <= app_offset && app_offset < memory_data_size) { if (p_app_start_offset) *p_app_start_offset = module_inst->heap_base_offset; @@ -722,7 +720,7 @@ aot_get_native_addr_range(AOTModuleInstance *module_inst, uint8 *addr = (uint8*)native_ptr; int32 memory_data_size = (int32)module_inst->memory_data_size; - if ((uint8*)module_inst->heap_data.ptr < addr + if ((uint8*)module_inst->heap_data.ptr <= addr && addr < (uint8*)module_inst->memory_data.ptr + memory_data_size) { if (p_native_start_addr) diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index 9bf28c239..98f1bcc84 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -952,11 +952,10 @@ wasm_validate_app_addr(WASMModuleInstance *module_inst, goto fail; } - if (app_offset <= memory->heap_base_offset - || app_offset + (int32)size > memory_data_size) { - goto fail; + if (memory->heap_base_offset <= app_offset + && app_offset + (int32)size <= memory_data_size) { + return true; } - return true; fail: wasm_set_exception(module_inst, "out of bounds memory access"); return false; @@ -975,11 +974,10 @@ wasm_validate_native_addr(WASMModuleInstance *module_inst, goto fail; } - if (addr <= memory->heap_data - || addr + size > memory->memory_data + memory_data_size) { - goto fail; + if (memory->heap_data <= addr + && addr + size <= memory->memory_data + memory_data_size) { + return true; } - return true; fail: wasm_set_exception(module_inst, "out of bounds memory access"); return false; @@ -994,7 +992,7 @@ wasm_addr_app_to_native(WASMModuleInstance *module_inst, int32 memory_data_size = (int32)(memory->num_bytes_per_page * memory->cur_page_count); - if (memory->heap_data < addr + if (memory->heap_data <= addr && addr < memory->memory_data + memory_data_size) return addr; return NULL; @@ -1009,7 +1007,7 @@ wasm_addr_native_to_app(WASMModuleInstance *module_inst, int32 memory_data_size = (int32)(memory->num_bytes_per_page * memory->cur_page_count); - if (memory->heap_data < addr + if (memory->heap_data <= addr && addr < memory->memory_data + memory_data_size) return (int32)(addr - memory->memory_data); return 0; @@ -1025,7 +1023,7 @@ wasm_get_app_addr_range(WASMModuleInstance *module_inst, int32 memory_data_size = (int32)(memory->num_bytes_per_page * memory->cur_page_count); - if (memory->heap_base_offset < app_offset + if (memory->heap_base_offset <= app_offset && app_offset < memory_data_size) { if (p_app_start_offset) *p_app_start_offset = memory->heap_base_offset; @@ -1047,7 +1045,7 @@ wasm_get_native_addr_range(WASMModuleInstance *module_inst, int32 memory_data_size = (int32)(memory->num_bytes_per_page * memory->cur_page_count); - if (memory->heap_data < addr + if (memory->heap_data <= addr && addr < memory->memory_data + memory_data_size) { if (p_native_start_addr) *p_native_start_addr = memory->heap_data; From 7abd1ca813794db267aeb9fb18d465f461a0d4da Mon Sep 17 00:00:00 2001 From: wenyongh Date: Fri, 8 May 2020 13:40:04 +0800 Subject: [PATCH 007/207] Change llvm void pointer to i8 pointer to avoid assert failed (#250) --- core/iwasm/compilation/aot_compiler.h | 1 - core/iwasm/compilation/aot_emit_memory.c | 4 +-- core/iwasm/compilation/aot_llvm.c | 45 ------------------------ core/iwasm/compilation/aot_llvm.h | 2 -- 4 files changed, 2 insertions(+), 50 deletions(-) diff --git a/core/iwasm/compilation/aot_compiler.h b/core/iwasm/compilation/aot_compiler.h index d13b43862..b44ab4ddf 100644 --- a/core/iwasm/compilation/aot_compiler.h +++ b/core/iwasm/compilation/aot_compiler.h @@ -192,7 +192,6 @@ typedef enum FloatArithmetic { #define INT64_PTR_TYPE comp_ctx->basic_types.int64_ptr_type #define F32_PTR_TYPE comp_ctx->basic_types.float32_ptr_type #define F64_PTR_TYPE comp_ctx->basic_types.float64_ptr_type -#define VOID_PTR_TYPE comp_ctx->basic_types.void_ptr_type #define I32_CONST(v) LLVMConstInt(I32_TYPE, v, true) #define I64_CONST(v) LLVMConstInt(I64_TYPE, v, true) diff --git a/core/iwasm/compilation/aot_emit_memory.c b/core/iwasm/compilation/aot_emit_memory.c index 674d2eb1a..680d24c7e 100644 --- a/core/iwasm/compilation/aot_emit_memory.c +++ b/core/iwasm/compilation/aot_emit_memory.c @@ -583,7 +583,7 @@ aot_compile_op_memory_grow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) /* To be simple, call wasm_runtime_set_exception() no matter enlarge success or not */ - param_types[1] = VOID_PTR_TYPE; + param_types[1] = INT8_PTR_TYPE; ret_type = VOID_TYPE; if (!(func_type = LLVMFunctionType(ret_type, param_types, 2, false))) { aot_set_last_error("llvm add function type failed."); @@ -614,7 +614,7 @@ aot_compile_op_memory_grow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) } /* Call function wasm_runtime_set_exception(aot_inst, NULL) */ - param_values[1] = LLVMConstNull(VOID_PTR_TYPE); + param_values[1] = LLVMConstNull(INT8_PTR_TYPE); CHECK_LLVM_CONST(param_values[1]); if (!(LLVMBuildCall(comp_ctx->builder, func, param_values, 2, ""))) { aot_set_last_error("llvm build call failed."); diff --git a/core/iwasm/compilation/aot_llvm.c b/core/iwasm/compilation/aot_llvm.c index c67758a7c..28572be3e 100644 --- a/core/iwasm/compilation/aot_llvm.c +++ b/core/iwasm/compilation/aot_llvm.c @@ -359,45 +359,6 @@ create_cur_exception(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) return true; } -static bool -create_func_ptrs(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) -{ - LLVMValueRef offset, func_ptrs_ptr; - LLVMTypeRef void_ptr_type; - - offset = I32_CONST(offsetof(AOTModuleInstance, func_ptrs.ptr)); - func_ptrs_ptr = LLVMBuildInBoundsGEP(comp_ctx->builder, - func_ctx->aot_inst, - &offset, 1, - "func_ptrs_ptr"); - if (!func_ptrs_ptr) { - aot_set_last_error("llvm build in bounds gep failed."); - return false; - } - - if (!(void_ptr_type = LLVMPointerType(VOID_PTR_TYPE, 0)) - || !(void_ptr_type = LLVMPointerType(void_ptr_type, 0))) { - aot_set_last_error("llvm get pointer type failed."); - return false; - } - - func_ctx->func_ptrs = LLVMBuildBitCast(comp_ctx->builder, func_ptrs_ptr, - void_ptr_type, "func_ptrs_tmp"); - if (!func_ctx->func_ptrs) { - aot_set_last_error("llvm build bit cast failed."); - return false; - } - - func_ctx->func_ptrs = LLVMBuildLoad(comp_ctx->builder, func_ctx->func_ptrs, - "func_ptrs"); - if (!func_ctx->func_ptrs) { - aot_set_last_error("llvm build load failed."); - return false; - } - - return true; -} - static bool create_func_type_indexes(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) @@ -636,10 +597,6 @@ aot_create_func_context(AOTCompData *comp_data, AOTCompContext *comp_ctx, if (!create_cur_exception(comp_ctx, func_ctx)) goto fail; - /* Load function pointers */ - if (!create_func_ptrs(comp_ctx, func_ctx)) - goto fail; - /* Load function type indexes */ if (!create_func_type_indexes(comp_ctx, func_ctx)) goto fail; @@ -723,7 +680,6 @@ aot_set_llvm_basic_types(AOTLLVMTypes *basic_types, LLVMContextRef context) basic_types->int64_ptr_type = LLVMPointerType(basic_types->int64_type, 0); basic_types->float32_ptr_type = LLVMPointerType(basic_types->float32_type, 0); basic_types->float64_ptr_type = LLVMPointerType(basic_types->float64_type, 0); - basic_types->void_ptr_type = LLVMPointerType(basic_types->void_type, 0); return (basic_types->int8_ptr_type && basic_types->int16_ptr_type @@ -731,7 +687,6 @@ aot_set_llvm_basic_types(AOTLLVMTypes *basic_types, LLVMContextRef context) && basic_types->int64_ptr_type && basic_types->float32_ptr_type && basic_types->float64_ptr_type - && basic_types->void_ptr_type && basic_types->meta_data_type) ? true : false; } diff --git a/core/iwasm/compilation/aot_llvm.h b/core/iwasm/compilation/aot_llvm.h index e671b1c6a..8883681c0 100644 --- a/core/iwasm/compilation/aot_llvm.h +++ b/core/iwasm/compilation/aot_llvm.h @@ -122,7 +122,6 @@ typedef struct AOTFuncContext { LLVMBasicBlockRef got_exception_block; LLVMBasicBlockRef func_return_block; LLVMValueRef exception_id_phi; - LLVMValueRef func_ptrs; LLVMValueRef func_type_indexes; LLVMValueRef locals[1]; } AOTFuncContext; @@ -143,7 +142,6 @@ typedef struct AOTLLVMTypes { LLVMTypeRef int64_ptr_type; LLVMTypeRef float32_ptr_type; LLVMTypeRef float64_ptr_type; - LLVMTypeRef void_ptr_type; LLVMTypeRef meta_data_type; } AOTLLVMTypes; From 1362b6d81f9045be0325287ad99cc0ed064ee9c6 Mon Sep 17 00:00:00 2001 From: Wenbo Hu Date: Tue, 12 May 2020 13:06:37 +0800 Subject: [PATCH 008/207] Rename log_level enums (#252) * rename loglevel enums * Update bh_log.c --- core/shared/utils/bh_log.c | 2 +- core/shared/utils/bh_log.h | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/core/shared/utils/bh_log.c b/core/shared/utils/bh_log.c index 808e234ac..a661591dc 100644 --- a/core/shared/utils/bh_log.c +++ b/core/shared/utils/bh_log.c @@ -9,7 +9,7 @@ * The verbose level of the log system. Only those verbose logs whose * levels are less than or equal to this value are outputed. */ -static uint32 log_verbose_level = LOG_LEVEL_WARNING; +static uint32 log_verbose_level = BH_LOG_LEVEL_WARNING; void bh_log_set_verbose_level(uint32 level) diff --git a/core/shared/utils/bh_log.h b/core/shared/utils/bh_log.h index 279b9c11b..5dd13a8ec 100644 --- a/core/shared/utils/bh_log.h +++ b/core/shared/utils/bh_log.h @@ -28,11 +28,11 @@ extern "C" { #endif typedef enum { - LOG_LEVEL_FATAL = 0, - LOG_LEVEL_ERROR = 1, - LOG_LEVEL_WARNING = 2, - LOG_LEVEL_DEBUG = 3, - LOG_LEVEL_VERBOSE = 4 + BH_LOG_LEVEL_FATAL = 0, + BH_LOG_LEVEL_ERROR = 1, + BH_LOG_LEVEL_WARNING = 2, + BH_LOG_LEVEL_DEBUG = 3, + BH_LOG_LEVEL_VERBOSE = 4 } LogLevel; void @@ -41,11 +41,11 @@ bh_log_set_verbose_level(uint32 level); void bh_log(LogLevel log_level, const char *file, int line, const char *fmt, ...); -#define LOG_FATAL(...) bh_log(LOG_LEVEL_FATAL, __FILE__, __LINE__, __VA_ARGS__) -#define LOG_ERROR(...) bh_log(LOG_LEVEL_ERROR, NULL, 0, __VA_ARGS__) -#define LOG_DEBUG(...) bh_log(LOG_LEVEL_DEBUG, __FILE__, __LINE__, 0, __VA_ARGS__) -#define LOG_WARNING(...) bh_log(LOG_LEVEL_WARNING, NULL, 0, __VA_ARGS__) -#define LOG_VERBOSE(...) bh_log(LOG_LEVEL_VERBOSE, NULL, 0, __VA_ARGS__) +#define LOG_FATAL(...) bh_log(BH_LOG_LEVEL_FATAL, __FILE__, __LINE__, __VA_ARGS__) +#define LOG_ERROR(...) bh_log(BH_LOG_LEVEL_ERROR, NULL, 0, __VA_ARGS__) +#define LOG_DEBUG(...) bh_log(BH_LOG_LEVEL_DEBUG, __FILE__, __LINE__, 0, __VA_ARGS__) +#define LOG_WARNING(...) bh_log(BH_LOG_LEVEL_WARNING, NULL, 0, __VA_ARGS__) +#define LOG_VERBOSE(...) bh_log(BH_LOG_LEVEL_VERBOSE, NULL, 0, __VA_ARGS__) void bh_print_time(const char *prompt); From a0bb761beb665646fefea53aca5766e93d9dd89a Mon Sep 17 00:00:00 2001 From: wenyongh Date: Fri, 15 May 2020 17:44:36 +0800 Subject: [PATCH 009/207] Update API comments, refine footprint of wasm loader (#256) and fix issues of get native stack boundary --- core/iwasm/include/wasm_export.h | 37 +- core/iwasm/interpreter/wasm_loader.c | 460 +++++++++--------- core/iwasm/interpreter/wasm_runtime.c | 4 - .../platform/common/posix/posix_thread.c | 32 +- 4 files changed, 269 insertions(+), 264 deletions(-) diff --git a/core/iwasm/include/wasm_export.h b/core/iwasm/include/wasm_export.h index c2e142f6f..0a915f83a 100644 --- a/core/iwasm/include/wasm_export.h +++ b/core/iwasm/include/wasm_export.h @@ -179,7 +179,9 @@ package_type_t get_package_type(const uint8_t *buf, uint32_t size); /** - * Load a WASM module from a specified byte buffer. + * Load a WASM module from a specified byte buffer. The byte buffer can be + * WASM binary data when interpreter or JIT is enabled, or AOT binary data + * when AOT is enabled. If it is AOT binary data, it must be 4-byte aligned. * * @param buf the byte buffer which contains the WASM binary data * @param size the size of the buffer @@ -225,11 +227,13 @@ wasm_runtime_set_wasi_args(wasm_module_t module, * Instantiate a WASM module. * * @param module the WASM module to instantiate - * @param stack_size the default stack size of the module instance, a stack - * will be created when function wasm_runtime_call_wasm() is called - * to run WASM function and the exec_env argument passed to - * wasm_runtime_call_wasm() is NULL. That means this parameter is - * ignored if exec_env is not NULL. + * @param stack_size the default stack size of the module instance when the + * exec env's operation stack isn't created by user, e.g. API + * wasm_application_execute_main() and wasm_application_execute_func() + * create the operation stack internally with the stack size specified + * here. And API wasm_runtime_create_exec_env() creates the operation + * stack with stack size specified by its parameter, the stack size + * specified here is ignored. * @param heap_size the default heap size of the module instance, a heap will * be created besides the app memory space. Both wasm app and native * function can allocate memory from the heap. If heap_size is 0, the @@ -286,7 +290,7 @@ wasm_runtime_create_exec_env(wasm_module_inst_t module_inst, /** * Destroy the execution environment. * - * @param env the execution environment to destroy + * @param exec_env the execution environment to destroy */ void wasm_runtime_destroy_exec_env(wasm_exec_env_t exec_env); @@ -305,17 +309,18 @@ wasm_runtime_get_module_inst(wasm_exec_env_t exec_env); * Call the given WASM function of a WASM module instance with * arguments (bytecode and AoT). * - * @param exec_env the execution environment to call the function + * @param exec_env the execution environment to call the function, * which must be created from wasm_create_exec_env() - * @param function the function to be called + * @param function the function to call * @param argc the number of arguments - * @param argv the arguments. If the function method has return value, + * @param argv the arguments. If the function has return value, * the first (or first two in case 64-bit return value) element of * argv stores the return value of the called WASM function after this * function returns. * * @return true if success, false otherwise and exception will be thrown, - * the caller can call wasm_runtime_get_exception to get exception info. + * the caller can call wasm_runtime_get_exception to get the exception + * info. */ bool wasm_runtime_call_wasm(wasm_exec_env_t exec_env, @@ -330,8 +335,9 @@ wasm_runtime_call_wasm(wasm_exec_env_t exec_env, * @param argc the number of arguments * @param argv the arguments array * - * @return true if the main function is called, false otherwise and exception will be thrown, - * the caller can call wasm_runtime_get_exception to get exception info. + * @return true if the main function is called, false otherwise and exception + * will be thrown, the caller can call wasm_runtime_get_exception to get + * the exception info. */ bool wasm_application_execute_main(wasm_module_inst_t module_inst, @@ -346,8 +352,9 @@ wasm_application_execute_main(wasm_module_inst_t module_inst, * @param argc the number of arguments * @param argv the arguments array * - * @return true if the specified function is called, false otherwise and exception will be thrown, - * the caller can call wasm_runtime_get_exception to get exception info. + * @return true if the specified function is called, false otherwise and + * exception will be thrown, the caller can call wasm_runtime_get_exception + * to get the exception info. */ bool wasm_application_execute_func(wasm_module_inst_t module_inst, diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index 5c882e9df..16a5c7674 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -42,11 +42,11 @@ set_error_buf(char *error_buf, uint32 error_buf_size, const char *string) } while (0) static bool -skip_leb(const uint8 *buf, const uint8 *buf_end, - uint32 *p_offset, uint32 maxbits, +skip_leb(const uint8 **p_buf, const uint8 *buf_end, uint32 maxbits, char* error_buf, uint32 error_buf_size) { - uint32 bcnt = 0; + const uint8 *buf = *p_buf; + uint32 offset = 0, bcnt = 0; uint64 byte; while (true) { @@ -57,51 +57,46 @@ skip_leb(const uint8 *buf, const uint8 *buf_end, return false; } - CHECK_BUF(buf, buf_end, *p_offset + 1); - byte = buf[*p_offset]; - *p_offset += 1; + CHECK_BUF(buf, buf_end, offset + 1); + byte = buf[offset]; + offset += 1; bcnt += 1; if ((byte & 0x80) == 0) { break; } } + *p_buf += offset; return true; } #define skip_leb_int64(p, p_end) do { \ - uint32 off = 0; \ - if (!skip_leb(p, p_end, &off, 64, \ + if (!skip_leb(&p, p_end, 64, \ error_buf, error_buf_size)) \ return false; \ - p += off; \ } while (0) #define skip_leb_uint32(p, p_end) do { \ - uint32 off = 0; \ - if (!skip_leb(p, p_end, &off, 32, \ + if (!skip_leb(&p, p_end, 32, \ error_buf, error_buf_size)) \ return false; \ - p += off; \ } while (0) #define skip_leb_int32(p, p_end) do { \ - uint32 off = 0; \ - if (!skip_leb(p, p_end, &off, 32, \ + if (!skip_leb(&p, p_end, 32, \ error_buf, error_buf_size)) \ return false; \ - p += off; \ } while (0) static bool -read_leb(const uint8 *buf, const uint8 *buf_end, - uint32 *p_offset, uint32 maxbits, - bool sign, uint64 *p_result, +read_leb(uint8 **p_buf, const uint8 *buf_end, + uint32 maxbits, bool sign, uint64 *p_result, char* error_buf, uint32 error_buf_size) { + const uint8 *buf = *p_buf; uint64 result = 0; uint32 shift = 0; - uint32 bcnt = 0; + uint32 offset = 0, bcnt = 0; uint64 byte; while (true) { @@ -112,9 +107,9 @@ read_leb(const uint8 *buf, const uint8 *buf_end, return false; } - CHECK_BUF(buf, buf_end, *p_offset + 1); - byte = buf[*p_offset]; - *p_offset += 1; + CHECK_BUF(buf, buf_end, offset + 1); + byte = buf[offset]; + offset += 1; result |= ((byte & 0x7f) << shift); shift += 7; bcnt += 1; @@ -160,6 +155,7 @@ read_leb(const uint8 *buf, const uint8 *buf_end, } } + *p_buf += offset; *p_result = result; return true; @@ -174,62 +170,26 @@ fail_integer_too_large: #define read_bool(p) TEMPLATE_READ_VALUE(bool, p) #define read_leb_int64(p, p_end, res) do { \ - if (p < p_end) { \ - uint8 _val = *p; \ - if (!(_val & 0x80)) { \ - res = (int64)_val; \ - if (_val & 0x40) \ - /* sign extend */ \ - res |= 0xFFFFFFFFFFFFFF80LL; \ - p++; \ - break; \ - } \ - } \ - uint32 off = 0; \ uint64 res64; \ - if (!read_leb(p, p_end, &off, 64, true, &res64, \ + if (!read_leb((uint8**)&p, p_end, 64, true, &res64,\ error_buf, error_buf_size)) \ return false; \ - p += off; \ res = (int64)res64; \ } while (0) #define read_leb_uint32(p, p_end, res) do { \ - if (p < p_end) { \ - uint8 _val = *p; \ - if (!(_val & 0x80)) { \ - res = _val; \ - p++; \ - break; \ - } \ - } \ - uint32 off = 0; \ uint64 res64; \ - if (!read_leb(p, p_end, &off, 32, false, &res64, \ + if (!read_leb((uint8**)&p, p_end, 32, false, &res64,\ error_buf, error_buf_size)) \ return false; \ - p += off; \ res = (uint32)res64; \ } while (0) #define read_leb_int32(p, p_end, res) do { \ - if (p < p_end) { \ - uint8 _val = *p; \ - if (!(_val & 0x80)) { \ - res = (int32)_val; \ - if (_val & 0x40) \ - /* sign extend */ \ - res |= 0xFFFFFF80; \ - p++; \ - break; \ - } \ - } \ - uint32 off = 0; \ uint64 res64; \ - if (!read_leb(p, p_end, &off, 32, true, &res64, \ + if (!read_leb((uint8**)&p, p_end, 32, true, &res64,\ error_buf, error_buf_size)) \ return false; \ - p += off; \ res = (int32)res64; \ } while (0) @@ -2094,15 +2054,22 @@ wasm_loader_find_block_addr(BlockAddr *block_addr_cache, { const uint8 *p = start_addr, *p_end = code_end_addr; uint8 *else_addr = NULL; - uint32 block_nested_depth = 1, count, i; + uint32 block_nested_depth = 1, count, i, j, t; uint8 opcode, u8; - BlockAddr block_stack[16] = { 0 }, *block; - uint32 j, t; i = ((uintptr_t)start_addr) % BLOCK_ADDR_CACHE_SIZE; block = block_addr_cache + BLOCK_ADDR_CONFLICT_SIZE * i; + for (j = 0; j < BLOCK_ADDR_CONFLICT_SIZE; j++) { + if (block[j].start_addr == start_addr) { + /* Cache hit */ + *p_else_addr = block[j].else_addr; + *p_end_addr = block[j].end_addr; + return true; + } + } + /* Cache unhit */ block_stack[0].start_addr = start_addr; @@ -2761,6 +2728,20 @@ wasm_loader_pop_frame_ref(WASMLoaderContext *ctx, uint8 type, return true; } +static bool +wasm_loader_push_pop_frame_ref(WASMLoaderContext *ctx, uint8 pop_cnt, + uint8 type_push, uint8 type_pop, + char *error_buf, uint32 error_buf_size) +{ + for (int i = 0; i < pop_cnt; i++) { + if (!wasm_loader_pop_frame_ref(ctx, type_pop, error_buf, error_buf_size)) + return false; + } + if (!wasm_loader_push_frame_ref(ctx, type_push, error_buf, error_buf_size)) + return false; + return true; +} + static bool wasm_loader_push_frame_csp(WASMLoaderContext *ctx, uint8 type, uint8 ret_type, uint8* start_addr, @@ -3253,6 +3234,24 @@ wasm_loader_pop_frame_offset(WASMLoaderContext *ctx, uint8 type, return true; } +static bool +wasm_loader_push_pop_frame_offset(WASMLoaderContext *ctx, uint8 pop_cnt, + uint8 type_push, uint8 type_pop, + bool disable_emit, int16 operand_offset, + char *error_buf, uint32 error_buf_size) +{ + for (int i = 0; i < pop_cnt; i++) { + if (!wasm_loader_pop_frame_offset(ctx, type_pop, error_buf, error_buf_size)) + return false; + } + if (!wasm_loader_push_frame_offset(ctx, type_push, + disable_emit, operand_offset, + error_buf, error_buf_size)) + return false; + + return true; +} + static bool wasm_loader_push_frame_ref_offset(WASMLoaderContext *ctx, uint8 type, bool disable_emit, int16 operand_offset, @@ -3279,6 +3278,22 @@ wasm_loader_pop_frame_ref_offset(WASMLoaderContext *ctx, uint8 type, return true; } +static bool +wasm_loader_push_pop_frame_ref_offset(WASMLoaderContext *ctx, uint8 pop_cnt, + uint8 type_push, uint8 type_pop, + bool disable_emit, int16 operand_offset, + char *error_buf, uint32 error_buf_size) +{ + if (!wasm_loader_push_pop_frame_ref(ctx, pop_cnt, type_push, type_pop, + error_buf, error_buf_size)) + return false; + if (!wasm_loader_push_pop_frame_offset(ctx, pop_cnt, type_push, type_pop, + disable_emit, operand_offset, + error_buf, error_buf_size)) + return false; + + return true; +} static bool wasm_loader_get_const_offset(WASMLoaderContext *ctx, uint8 type, @@ -3432,6 +3447,23 @@ fail: goto fail; \ } while (0) +#define POP_AND_PUSH(type_pop, type_push) do { \ + if (!(wasm_loader_push_pop_frame_ref_offset(loader_ctx, 1, \ + type_push, type_pop, \ + disable_emit, operand_offset, \ + error_buf, error_buf_size))) \ + goto fail; \ + } while (0) + +/* type of POPs should be the same */ +#define POP2_AND_PUSH(type_pop, type_push) do { \ + if (!(wasm_loader_push_pop_frame_ref_offset(loader_ctx, 2, \ + type_push, type_pop, \ + disable_emit, operand_offset, \ + error_buf, error_buf_size))) \ + goto fail; \ + } while (0) + #else /* WASM_ENABLE_FAST_INTERP */ #define PUSH_I32() do { \ @@ -3482,8 +3514,85 @@ fail: goto fail; \ } while (0) +#define POP_AND_PUSH(type_pop, type_push) do { \ + if (!(wasm_loader_push_pop_frame_ref(loader_ctx, 1, \ + type_push, type_pop, \ + error_buf, error_buf_size))) \ + goto fail; \ + } while (0) + +/* type of POPs should be the same */ +#define POP2_AND_PUSH(type_pop, type_push) do { \ + if (!(wasm_loader_push_pop_frame_ref(loader_ctx, 2, \ + type_push, type_pop, \ + error_buf, error_buf_size))) \ + goto fail; \ + } while (0) #endif /* WASM_ENABLE_FAST_INTERP */ +#if WASM_ENABLE_FAST_INTERP != 0 + +static bool +reserve_block_ret(WASMLoaderContext *loader_ctx, uint8 opcode, bool disable_emit, + char *error_buf, uint32 error_buf_size) +{ + int16 operand_offset = 0; + uint8 block_depth = 0; + if (opcode == WASM_OP_ELSE) + block_depth = 1; + else + block_depth = 0; + + if ((loader_ctx->frame_csp - block_depth)->return_type != VALUE_TYPE_VOID) { + uint8 return_cells; + if ((loader_ctx->frame_csp - block_depth)->return_type == VALUE_TYPE_I32 + || (loader_ctx->frame_csp - block_depth)->return_type == VALUE_TYPE_F32) + return_cells = 1; + else + return_cells = 2; + if ((loader_ctx->frame_csp - block_depth)->dynamic_offset != + *(loader_ctx->frame_offset - return_cells)) { + + /* insert op_copy before else opcode */ + if (opcode == WASM_OP_ELSE) + skip_label(); + + if (return_cells == 1) + emit_label(EXT_OP_COPY_STACK_TOP); + else + emit_label(EXT_OP_COPY_STACK_TOP_I64); + emit_operand(loader_ctx, *(loader_ctx->frame_offset - return_cells)); + emit_operand(loader_ctx, (loader_ctx->frame_csp - block_depth)->dynamic_offset); + + if (opcode == WASM_OP_ELSE) { + *(loader_ctx->frame_offset - return_cells) = + (loader_ctx->frame_csp - block_depth)->dynamic_offset; + } + else { + loader_ctx->frame_offset -= return_cells; + loader_ctx->dynamic_offset = loader_ctx->frame_csp->dynamic_offset; + PUSH_OFFSET_TYPE((loader_ctx->frame_csp - block_depth)->return_type); + wasm_loader_emit_backspace(loader_ctx, sizeof(int16)); + } + if (opcode == WASM_OP_ELSE) + emit_label(opcode); + } + } + + return true; + +fail: + return false; +} + +#endif /* WASM_ENABLE_FAST_INTERP */ + +#define RESERVE_BLOCK_RET() do { \ + if (!reserve_block_ret(loader_ctx, opcode, disable_emit, \ + error_buf, error_buf_size)) \ + goto fail; \ + } while (0) + #define PUSH_TYPE(type) do { \ if (!(wasm_loader_push_frame_ref(loader_ctx, type, \ error_buf, error_buf_size))) \ @@ -3613,12 +3722,10 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, uint8 *param_types, ret_type, *local_types, local_type, global_type; uint16 *local_offsets, local_offset; uint32 count, i, local_idx, global_idx, u32, align, mem_offset; - uint32 cache_index, item_index; int32 i32, i32_const = 0; int64 i64; uint8 opcode, u8, block_return_type; bool return_value = false, is_i32_const = false; - BlockAddr *cache_items; WASMLoaderContext *loader_ctx; BranchBlock *frame_csp_tmp; #if WASM_ENABLE_FAST_INTERP != 0 @@ -3723,23 +3830,7 @@ re_scan: if (!is_i32_const) (loader_ctx->frame_csp - 1)->is_block_reachable = true; else { - cache_index = ((uintptr_t)(loader_ctx->frame_csp - 1)->start_addr) - & (uintptr_t)(BLOCK_ADDR_CACHE_SIZE - 1); - cache_items = block_addr_cache - + BLOCK_ADDR_CONFLICT_SIZE * cache_index; - for (item_index = 0; item_index < BLOCK_ADDR_CONFLICT_SIZE; - item_index++) { - if (cache_items[item_index].start_addr == - (loader_ctx->frame_csp - 1)->start_addr) { - (loader_ctx->frame_csp - 1)->else_addr = - cache_items[item_index].else_addr; - (loader_ctx->frame_csp - 1)->end_addr = - cache_items[item_index].end_addr; - break; - } - } - if (item_index == BLOCK_ADDR_CONFLICT_SIZE - && !wasm_loader_find_block_addr(block_addr_cache, + if (!wasm_loader_find_block_addr(block_addr_cache, (loader_ctx->frame_csp - 1)->start_addr, p_end, (loader_ctx->frame_csp - 1)->block_type, @@ -3796,27 +3887,7 @@ re_scan: loader_ctx->stack_cell_num; #if WASM_ENABLE_FAST_INTERP != 0 /* if the result of if branch is in local or const area, add a copy op */ - if ((loader_ctx->frame_csp - 1)->return_type != VALUE_TYPE_VOID) { - uint8 return_cells; - if ((loader_ctx->frame_csp - 1)->return_type == VALUE_TYPE_I32 - || (loader_ctx->frame_csp - 1)->return_type == VALUE_TYPE_F32) - return_cells = 1; - else - return_cells = 2; - if ((loader_ctx->frame_csp - 1)->dynamic_offset != - *(loader_ctx->frame_offset - return_cells)) { - skip_label(); - if (return_cells == 1) - emit_label(EXT_OP_COPY_STACK_TOP); - else - emit_label(EXT_OP_COPY_STACK_TOP_I64); - emit_operand(loader_ctx, *(loader_ctx->frame_offset - return_cells)); - emit_operand(loader_ctx, (loader_ctx->frame_csp - 1)->dynamic_offset); - *(loader_ctx->frame_offset - return_cells) = - (loader_ctx->frame_csp - 1)->dynamic_offset; - emit_label(opcode); - } - } + RESERVE_BLOCK_RET(); loader_ctx->frame_offset = loader_ctx->frame_offset_bottom + loader_ctx->stack_cell_num; emit_empty_label_addr_and_frame_ip(PATCH_END); @@ -3830,29 +3901,8 @@ re_scan: #if WASM_ENABLE_FAST_INTERP != 0 skip_label(); - // copy the result to the block return address - if (loader_ctx->frame_csp->return_type != VALUE_TYPE_VOID) { - uint8 return_cells; - if (loader_ctx->frame_csp->return_type == VALUE_TYPE_I32 - || loader_ctx->frame_csp->return_type == VALUE_TYPE_F32) - return_cells = 1; - else - return_cells = 2; - if (loader_ctx->frame_csp->dynamic_offset != - *(loader_ctx->frame_offset - return_cells)) { - if (return_cells == 1) - emit_label(EXT_OP_COPY_STACK_TOP); - else - emit_label(EXT_OP_COPY_STACK_TOP_I64); - emit_operand(loader_ctx, *(loader_ctx->frame_offset - return_cells)); - emit_operand(loader_ctx, loader_ctx->frame_csp->dynamic_offset); - } - // the frame_offset stack top should be the return address of the block - loader_ctx->frame_offset -= return_cells; - loader_ctx->dynamic_offset = loader_ctx->frame_csp->dynamic_offset; - PUSH_OFFSET_TYPE(loader_ctx->frame_csp->return_type); - wasm_loader_emit_backspace(loader_ctx, sizeof(int16)); - } + /* copy the result to the block return address */ + RESERVE_BLOCK_RET(); apply_label_patch(loader_ctx, 0, PATCH_END); free_label_patch_list(loader_ctx->frame_csp); @@ -3892,24 +3942,13 @@ handle_next_reachable_block: block_return_type = (loader_ctx->frame_csp - i)->return_type; - cache_index = ((uintptr_t)(loader_ctx->frame_csp - i)->start_addr) - & (uintptr_t)(BLOCK_ADDR_CACHE_SIZE - 1); - cache_items = block_addr_cache + BLOCK_ADDR_CONFLICT_SIZE * cache_index; - for (item_index = 0; item_index < BLOCK_ADDR_CONFLICT_SIZE; item_index++) { - if (cache_items[item_index].start_addr == (loader_ctx->frame_csp - i)->start_addr) { - (loader_ctx->frame_csp - i)->else_addr = cache_items[item_index].else_addr; - (loader_ctx->frame_csp - i)->end_addr = cache_items[item_index].end_addr; - break; - } - } - if(item_index == BLOCK_ADDR_CONFLICT_SIZE - && !wasm_loader_find_block_addr(block_addr_cache, - (loader_ctx->frame_csp - i)->start_addr, - p_end, - (loader_ctx->frame_csp - i)->block_type, - &(loader_ctx->frame_csp - i)->else_addr, - &(loader_ctx->frame_csp - i)->end_addr, - error_buf, error_buf_size)) + if(!wasm_loader_find_block_addr(block_addr_cache, + (loader_ctx->frame_csp - i)->start_addr, + p_end, + (loader_ctx->frame_csp - i)->block_type, + &(loader_ctx->frame_csp - i)->else_addr, + &(loader_ctx->frame_csp - i)->end_addr, + error_buf, error_buf_size)) goto fail; loader_ctx->stack_cell_num = (loader_ctx->frame_csp - i)->stack_cell_num; @@ -4443,8 +4482,7 @@ handle_next_reachable_block: case WASM_OP_I32_LOAD8_U: case WASM_OP_I32_LOAD16_S: case WASM_OP_I32_LOAD16_U: - POP_I32(); - PUSH_I32(); + POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32); break; case WASM_OP_I64_LOAD: case WASM_OP_I64_LOAD8_S: @@ -4453,16 +4491,13 @@ handle_next_reachable_block: case WASM_OP_I64_LOAD16_U: case WASM_OP_I64_LOAD32_S: case WASM_OP_I64_LOAD32_U: - POP_I32(); - PUSH_I64(); + POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I64); break; case WASM_OP_F32_LOAD: - POP_I32(); - PUSH_F32(); + POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_F32); break; case WASM_OP_F64_LOAD: - POP_I32(); - PUSH_F64(); + POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_F64); break; /* store */ case WASM_OP_I32_STORE: @@ -4513,8 +4548,7 @@ handle_next_reachable_block: "zero flag expected"); goto fail; } - POP_I32(); - PUSH_I32(); + POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32); func->has_op_memory_grow = true; module->possible_memory_grow = true; @@ -4566,8 +4600,7 @@ handle_next_reachable_block: break; case WASM_OP_I32_EQZ: - POP_I32(); - PUSH_I32(); + POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32); break; case WASM_OP_I32_EQ: @@ -4580,14 +4613,11 @@ handle_next_reachable_block: case WASM_OP_I32_LE_U: case WASM_OP_I32_GE_S: case WASM_OP_I32_GE_U: - POP_I32(); - POP_I32(); - PUSH_I32(); + POP2_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32); break; case WASM_OP_I64_EQZ: - POP_I64(); - PUSH_I32(); + POP_AND_PUSH(VALUE_TYPE_I64, VALUE_TYPE_I32); break; case WASM_OP_I64_EQ: @@ -4600,9 +4630,7 @@ handle_next_reachable_block: case WASM_OP_I64_LE_U: case WASM_OP_I64_GE_S: case WASM_OP_I64_GE_U: - POP_I64(); - POP_I64(); - PUSH_I32(); + POP2_AND_PUSH(VALUE_TYPE_I64, VALUE_TYPE_I32); break; case WASM_OP_F32_EQ: @@ -4611,9 +4639,7 @@ handle_next_reachable_block: case WASM_OP_F32_GT: case WASM_OP_F32_LE: case WASM_OP_F32_GE: - POP_F32(); - POP_F32(); - PUSH_I32(); + POP2_AND_PUSH(VALUE_TYPE_F32, VALUE_TYPE_I32); break; case WASM_OP_F64_EQ: @@ -4622,9 +4648,7 @@ handle_next_reachable_block: case WASM_OP_F64_GT: case WASM_OP_F64_LE: case WASM_OP_F64_GE: - POP_F64(); - POP_F64(); - PUSH_I32(); + POP2_AND_PUSH(VALUE_TYPE_F64, VALUE_TYPE_I32); break; break; @@ -4632,8 +4656,7 @@ handle_next_reachable_block: case WASM_OP_I32_CLZ: case WASM_OP_I32_CTZ: case WASM_OP_I32_POPCNT: - POP_I32(); - PUSH_I32(); + POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32); break; case WASM_OP_I32_ADD: @@ -4651,16 +4674,13 @@ handle_next_reachable_block: case WASM_OP_I32_SHR_U: case WASM_OP_I32_ROTL: case WASM_OP_I32_ROTR: - POP_I32(); - POP_I32(); - PUSH_I32(); + POP2_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32); break; case WASM_OP_I64_CLZ: case WASM_OP_I64_CTZ: case WASM_OP_I64_POPCNT: - POP_I64(); - PUSH_I64(); + POP_AND_PUSH(VALUE_TYPE_I64, VALUE_TYPE_I64); break; case WASM_OP_I64_ADD: @@ -4678,9 +4698,7 @@ handle_next_reachable_block: case WASM_OP_I64_SHR_U: case WASM_OP_I64_ROTL: case WASM_OP_I64_ROTR: - POP_I64(); - POP_I64(); - PUSH_I64(); + POP2_AND_PUSH(VALUE_TYPE_I64, VALUE_TYPE_I64); break; case WASM_OP_F32_ABS: @@ -4690,8 +4708,7 @@ handle_next_reachable_block: case WASM_OP_F32_TRUNC: case WASM_OP_F32_NEAREST: case WASM_OP_F32_SQRT: - POP_F32(); - PUSH_F32(); + POP_AND_PUSH(VALUE_TYPE_F32, VALUE_TYPE_F32); break; case WASM_OP_F32_ADD: @@ -4701,9 +4718,7 @@ handle_next_reachable_block: case WASM_OP_F32_MIN: case WASM_OP_F32_MAX: case WASM_OP_F32_COPYSIGN: - POP_F32(); - POP_F32(); - PUSH_F32(); + POP2_AND_PUSH(VALUE_TYPE_F32, VALUE_TYPE_F32); break; case WASM_OP_F64_ABS: @@ -4713,8 +4728,7 @@ handle_next_reachable_block: case WASM_OP_F64_TRUNC: case WASM_OP_F64_NEAREST: case WASM_OP_F64_SQRT: - POP_F64(); - PUSH_F64(); + POP_AND_PUSH(VALUE_TYPE_F64, VALUE_TYPE_F64); break; case WASM_OP_F64_ADD: @@ -4724,111 +4738,91 @@ handle_next_reachable_block: case WASM_OP_F64_MIN: case WASM_OP_F64_MAX: case WASM_OP_F64_COPYSIGN: - POP_F64(); - POP_F64(); - PUSH_F64(); + POP2_AND_PUSH(VALUE_TYPE_F64, VALUE_TYPE_F64); break; case WASM_OP_I32_WRAP_I64: - POP_I64(); - PUSH_I32(); + POP_AND_PUSH(VALUE_TYPE_I64, VALUE_TYPE_I32); break; case WASM_OP_I32_TRUNC_S_F32: case WASM_OP_I32_TRUNC_U_F32: - POP_F32(); - PUSH_I32(); + POP_AND_PUSH(VALUE_TYPE_F32, VALUE_TYPE_I32); break; case WASM_OP_I32_TRUNC_S_F64: case WASM_OP_I32_TRUNC_U_F64: - POP_F64(); - PUSH_I32(); + POP_AND_PUSH(VALUE_TYPE_F64, VALUE_TYPE_I32); break; case WASM_OP_I64_EXTEND_S_I32: case WASM_OP_I64_EXTEND_U_I32: - POP_I32(); - PUSH_I64(); + POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I64); break; case WASM_OP_I64_TRUNC_S_F32: case WASM_OP_I64_TRUNC_U_F32: - POP_F32(); - PUSH_I64(); + POP_AND_PUSH(VALUE_TYPE_F32, VALUE_TYPE_I64); break; case WASM_OP_I64_TRUNC_S_F64: case WASM_OP_I64_TRUNC_U_F64: - POP_F64(); - PUSH_I64(); + POP_AND_PUSH(VALUE_TYPE_F64, VALUE_TYPE_I64); break; case WASM_OP_F32_CONVERT_S_I32: case WASM_OP_F32_CONVERT_U_I32: - POP_I32(); - PUSH_F32(); + POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_F32); break; case WASM_OP_F32_CONVERT_S_I64: case WASM_OP_F32_CONVERT_U_I64: - POP_I64(); - PUSH_F32(); + POP_AND_PUSH(VALUE_TYPE_I64, VALUE_TYPE_F32); break; case WASM_OP_F32_DEMOTE_F64: - POP_F64(); - PUSH_F32(); + POP_AND_PUSH(VALUE_TYPE_F64, VALUE_TYPE_F32); break; case WASM_OP_F64_CONVERT_S_I32: case WASM_OP_F64_CONVERT_U_I32: - POP_I32(); - PUSH_F64(); + POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_F64); break; case WASM_OP_F64_CONVERT_S_I64: case WASM_OP_F64_CONVERT_U_I64: - POP_I64(); - PUSH_F64(); + POP_AND_PUSH(VALUE_TYPE_I64, VALUE_TYPE_F64); break; case WASM_OP_F64_PROMOTE_F32: - POP_F32(); - PUSH_F64(); + POP_AND_PUSH(VALUE_TYPE_F32, VALUE_TYPE_F64); break; case WASM_OP_I32_REINTERPRET_F32: - POP_F32(); - PUSH_I32(); + POP_AND_PUSH(VALUE_TYPE_F32, VALUE_TYPE_I32); break; case WASM_OP_I64_REINTERPRET_F64: - POP_F64(); - PUSH_I64(); + POP_AND_PUSH(VALUE_TYPE_F64, VALUE_TYPE_I64); break; case WASM_OP_F32_REINTERPRET_I32: - POP_I32(); - PUSH_F32(); + POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_F32); break; case WASM_OP_F64_REINTERPRET_I64: - POP_I64(); - PUSH_F64(); + POP_AND_PUSH(VALUE_TYPE_I64, VALUE_TYPE_F64); break; case WASM_OP_I32_EXTEND8_S: case WASM_OP_I32_EXTEND16_S: - POP_I32(); - PUSH_I32(); + POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32); break; case WASM_OP_I64_EXTEND8_S: case WASM_OP_I64_EXTEND16_S: case WASM_OP_I64_EXTEND32_S: - POP_I64(); - PUSH_I64(); + POP_AND_PUSH(VALUE_TYPE_I64, VALUE_TYPE_I64); break; case WASM_OP_MISC_PREFIX: @@ -4841,23 +4835,19 @@ handle_next_reachable_block: { case WASM_OP_I32_TRUNC_SAT_S_F32: case WASM_OP_I32_TRUNC_SAT_U_F32: - POP_F32(); - PUSH_I32(); + POP_AND_PUSH(VALUE_TYPE_F32, VALUE_TYPE_I32); break; case WASM_OP_I32_TRUNC_SAT_S_F64: case WASM_OP_I32_TRUNC_SAT_U_F64: - POP_F64(); - PUSH_I32(); + POP_AND_PUSH(VALUE_TYPE_F64, VALUE_TYPE_I32); break; case WASM_OP_I64_TRUNC_SAT_S_F32: case WASM_OP_I64_TRUNC_SAT_U_F32: - POP_F32(); - PUSH_I64(); + POP_AND_PUSH(VALUE_TYPE_F32, VALUE_TYPE_I64); break; case WASM_OP_I64_TRUNC_SAT_S_F64: case WASM_OP_I64_TRUNC_SAT_U_F64: - POP_F64(); - PUSH_I64(); + POP_AND_PUSH(VALUE_TYPE_F64, VALUE_TYPE_I64); break; default: if (error_buf != NULL) diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index 98f1bcc84..bca20e6dc 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -818,10 +818,6 @@ wasm_deinstantiate(WASMModuleInstance *module_inst) if (module_inst->memory_count > 0) memories_deinstantiate(module_inst->memories, module_inst->memory_count); - else if (module_inst->memories != NULL && module_inst->global_count > 0) - /* No imported memory and defined memory, the memory is created when - global count > 0. */ - memories_deinstantiate(module_inst->memories, 1); tables_deinstantiate(module_inst->tables, module_inst->table_count); functions_deinstantiate(module_inst->functions, module_inst->function_count); diff --git a/core/shared/platform/common/posix/posix_thread.c b/core/shared/platform/common/posix/posix_thread.c index 1a32b1502..9c0cf3835 100644 --- a/core/shared/platform/common/posix/posix_thread.c +++ b/core/shared/platform/common/posix/posix_thread.c @@ -223,19 +223,31 @@ int os_thread_join(korp_tid thread, void **value_ptr) uint8 *os_thread_get_stack_boundary() { + pthread_t self = pthread_self(); pthread_attr_t attr; - void *addr = NULL; - size_t size; + uint8 *addr = NULL; + size_t stack_size, guard_size; - if (pthread_getattr_np(pthread_self(), &attr) == 0) { - pthread_attr_getstack(&attr, &addr, &size); - pthread_attr_destroy (&attr); +#ifdef __linux__ + if (pthread_getattr_np(self, &attr) == 0) { + pthread_attr_getstack(&attr, (void**)&addr, &stack_size); + pthread_attr_getguardsize(&attr, &guard_size); + pthread_attr_destroy(&attr); + if (guard_size < 4 * 1024) + /* Reserved 4 KB guard size at least for safety */ + guard_size = 4 * 1024; + addr += guard_size; } + (void)stack_size; +#elif defined(__APPLE__) + if ((addr = (uint8*)pthread_get_stackaddr_np(self))) { + stack_size = pthread_get_stacksize_np(self); + addr -= stack_size; + /* Reserved 4 KB guard size at least for safety */ + addr += 4 * 1024; + } +#endif - if (addr) - /* Reserved 4 KB for safety */ - return (uint8*)addr + 4 * 1024; - else - return NULL; + return addr; } From 0529815f34c3a39b8d9bc11856649f2a76b6689a Mon Sep 17 00:00:00 2001 From: liurenju Date: Thu, 21 May 2020 01:05:02 -0700 Subject: [PATCH 010/207] change the alignment, which might potentially casue problem. (#258) --- product-mini/platforms/zephyr/simple/src/test_wasm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/product-mini/platforms/zephyr/simple/src/test_wasm.h b/product-mini/platforms/zephyr/simple/src/test_wasm.h index 65b834798..23e87b5be 100644 --- a/product-mini/platforms/zephyr/simple/src/test_wasm.h +++ b/product-mini/platforms/zephyr/simple/src/test_wasm.h @@ -8,7 +8,7 @@ * which is compiled by emcc or clang toolchain from C source file of: * core/iwasm/app-samples/hello-world/main.c. */ -unsigned char wasm_test_file[] = { 0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, +unsigned char __aligned(4) wasm_test_file[] = { 0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x06, 0x64, 0x79, 0x6C, 0x69, 0x6E, 0x6B, 0xC0, 0x80, 0x04, 0x04, 0x00, 0x00, 0x01, 0x13, 0x04, 0x60, 0x01, 0x7F, 0x00, 0x60, 0x01, 0x7F, 0x01, 0x7F, 0x60, 0x02, 0x7F, 0x7F, 0x01, 0x7F, 0x60, 0x00, From c182eebc6b66fd74bbae113556b6100068d0c8d0 Mon Sep 17 00:00:00 2001 From: dpinthinker Date: Thu, 28 May 2020 13:27:52 +0800 Subject: [PATCH 011/207] add darwin compiling support for wamr-compiler (#265) * add darwin support for wamr-compiler compiling * add darwin support for wamr-compiler * Update CMakeLists.txt Co-authored-by: wenyongh --- README.md | 1 + wamr-compiler/CMakeLists.txt | 12 +++++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 6d89814d9..be93b8e50 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,7 @@ cmake .. make ln -s {current path}/wamrc /usr/bin/wamrc ``` +For MacOS, you should replace `cmake ..` with `cmake -DWAMR_BUILD_PLATFORM=darwin ..`. ### Build the mini product diff --git a/wamr-compiler/CMakeLists.txt b/wamr-compiler/CMakeLists.txt index 336e317d1..a8c70677f 100644 --- a/wamr-compiler/CMakeLists.txt +++ b/wamr-compiler/CMakeLists.txt @@ -4,7 +4,9 @@ cmake_minimum_required (VERSION 2.8) project (aot-compiler) -set (WAMR_BUILD_PLATFORM "linux") +if (NOT DEFINED WAMR_BUILD_PLATFORM) + set (WAMR_BUILD_PLATFORM "linux") +endif() # Reset default linker flags set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") @@ -76,7 +78,9 @@ add_definitions(${LLVM_DEFINITIONS}) message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") -set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") +if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang")) + set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") +endif() set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ffunction-sections -fdata-sections \ -Wall -Wno-unused-parameter -Wno-pedantic") @@ -102,7 +106,9 @@ include (${IWASM_DIR}/compilation/iwasm_compl.cmake) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat -Wformat-security") # set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wconversion -Wsign-conversion") if (WAMR_BUILD_TARGET MATCHES "X86_.*" OR WAMR_BUILD_TARGET STREQUAL "AMD_64") -set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mindirect-branch-register") + if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang")) + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mindirect-branch-register") + endif() endif () set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fstack-protector-strong --param ssp-buffer-size=4") set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wl,-z,noexecstack,-z,relro,-z,now") From e81f72d41fa7b3b36783ad298041d1d0e28d10e1 Mon Sep 17 00:00:00 2001 From: dpinthinker Date: Sun, 31 May 2020 12:40:12 +0800 Subject: [PATCH 012/207] MacOs: fix wamrc Error invaid llvm binary bin_type (#269) * add darwin support for wamr-compiler compiling * add darwin support for wamr-compiler * Update CMakeLists.txt * MacOs: fix wamrc Error invaid llvm binary bin_type Co-authored-by: wenyongh --- core/iwasm/compilation/aot_emit_aot_file.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/core/iwasm/compilation/aot_emit_aot_file.c b/core/iwasm/compilation/aot_emit_aot_file.c index 557528b0c..2cffb44f6 100644 --- a/core/iwasm/compilation/aot_emit_aot_file.c +++ b/core/iwasm/compilation/aot_emit_aot_file.c @@ -1394,7 +1394,11 @@ aot_resolve_target_info(AOTCompContext *comp_ctx, AOTObjectData *obj_data) if (bin_type != LLVMBinaryTypeELF32L && bin_type != LLVMBinaryTypeELF32B && bin_type != LLVMBinaryTypeELF64L - && bin_type != LLVMBinaryTypeELF64B) { + && bin_type != LLVMBinaryTypeELF64B + && bin_type != LLVMBinaryTypeMachO32L + && bin_type != LLVMBinaryTypeMachO32B + && bin_type != LLVMBinaryTypeMachO64L + && bin_type != LLVMBinaryTypeMachO64B) { aot_set_last_error("invaid llvm binary bin_type."); return false; } From 752826a667b359002a25ec8b7ebe1942fbfe2710 Mon Sep 17 00:00:00 2001 From: wenyongh Date: Tue, 2 Jun 2020 14:53:06 +0800 Subject: [PATCH 013/207] 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 --- _clang-format => .clang-format | 63 +- .gitignore | 3 + README.md | 8 +- assembly-script/.gitignore | 1 + build-scripts/config_common.cmake | 14 +- .../app-native-shared/bi-inc/attr_container.h | 2 +- .../app-native-shared/restful_utils.c | 5 - core/app-mgr/app-manager/app_manager_host.c | 6 +- core/app-mgr/app-manager/module_wasm_app.c | 12 +- .../app-mgr-shared/app_manager_export.h | 2 +- core/config.h | 10 + core/iwasm/aot/aot_loader.c | 16 +- core/iwasm/aot/aot_reloc.h | 25 + core/iwasm/aot/aot_runtime.c | 234 +- core/iwasm/aot/aot_runtime.h | 9 + core/iwasm/common/wasm_native.c | 2 +- core/iwasm/common/wasm_runtime_common.c | 564 ++++- core/iwasm/common/wasm_runtime_common.h | 80 +- core/iwasm/compilation/aot.c | 4 + core/iwasm/compilation/aot.h | 6 + core/iwasm/compilation/aot_compiler.c | 33 + core/iwasm/compilation/aot_emit_aot_file.c | 60 +- core/iwasm/compilation/aot_emit_memory.c | 287 +++ core/iwasm/compilation/aot_emit_memory.h | 16 + core/iwasm/compilation/aot_llvm.c | 3 + core/iwasm/compilation/aot_llvm.h | 4 + core/iwasm/include/aot_export.h | 1 + core/iwasm/include/lib_export.h | 2 +- core/iwasm/include/wasm_export.h | 56 +- core/iwasm/interpreter/wasm.h | 46 +- core/iwasm/interpreter/wasm_interp_classic.c | 265 ++- core/iwasm/interpreter/wasm_interp_fast.c | 243 ++- core/iwasm/interpreter/wasm_loader.c | 1929 +++++++++++++---- core/iwasm/interpreter/wasm_opcode.h | 13 +- core/iwasm/interpreter/wasm_runtime.c | 799 +++++-- core/iwasm/interpreter/wasm_runtime.h | 83 +- .../libc-builtin/libc_builtin_wrapper.c | 2 +- .../platform/common/posix/posix_memmap.c | 46 +- .../platform/common/posix/posix_thread.c | 3 +- core/shared/platform/linux-sgx/sgx_platform.c | 35 +- core/shared/utils/bh_common.c | 20 + core/shared/utils/bh_common.h | 7 + core/shared/utils/bh_log.h | 12 +- core/shared/utils/runtime_timer.h | 2 +- doc/build_wamr.md | 30 +- doc/multi_module.md | 228 ++ doc/pics/multi_module_pic1.png | Bin 0 -> 8585 bytes product-mini/platforms/linux/CMakeLists.txt | 8 + product-mini/platforms/linux/main.c | 134 +- samples/multi-module/CMakeLists.txt | 51 + samples/multi-module/src/main.c | 144 ++ samples/multi-module/wasm-apps/CMakeLists.txt | 41 + samples/multi-module/wasm-apps/mA.c | 5 + samples/multi-module/wasm-apps/mB.c | 16 + samples/multi-module/wasm-apps/mC.c | 25 + wamr-compiler/CMakeLists.txt | 1 + wamr-compiler/main.c | 4 + 57 files changed, 4902 insertions(+), 818 deletions(-) rename _clang-format => .clang-format (78%) create mode 100644 assembly-script/.gitignore create mode 100644 doc/multi_module.md create mode 100644 doc/pics/multi_module_pic1.png create mode 100644 samples/multi-module/CMakeLists.txt create mode 100644 samples/multi-module/src/main.c create mode 100644 samples/multi-module/wasm-apps/CMakeLists.txt create mode 100644 samples/multi-module/wasm-apps/mA.c create mode 100644 samples/multi-module/wasm-apps/mB.c create mode 100644 samples/multi-module/wasm-apps/mC.c diff --git a/_clang-format b/.clang-format similarity index 78% rename from _clang-format rename to .clang-format index c99997022..f1f14f519 100644 --- a/_clang-format +++ b/.clang-format @@ -1,13 +1,47 @@ ---- +RawStringFormats: + - Language: Cpp + Delimiters: + - c + - C + - cc + - CC + - cpp + - Cpp + - CPP + - 'c++' + - 'C++' + - h + - hpp + CanonicalDelimiter: '' + BasedOnStyle: google + - Language: TextProto + Delimiters: + - pb + - PB + - proto + - PROTO + EnclosingFunctions: + - EqualsProto + - EquivToProto + - PARSE_PARTIAL_TEXT_PROTO + - PARSE_TEST_PROTO + - PARSE_TEXT_PROTO + - ParseTextOrDie + - ParseTextProtoOrDie + CanonicalDelimiter: '' + BasedOnStyle: google + +Language: Cpp BasedOnStyle: Mozilla IndentWidth: 4 - ---- -Language: Cpp +AlignAfterOpenBracket: Align +AllowAllArgumentsOnNextLine: false AlignConsecutiveMacros: true AllowShortBlocksOnASingleLine: true +AlwaysBreakAfterReturnType: All BinPackArguments: true -BinPackParameters: true +BinPackParameters: false +BreakBeforeBinaryOperators: NonAssignment BreakBeforeBraces: Custom BraceWrapping: AfterCaseLabel: false @@ -17,16 +51,17 @@ BraceWrapping: AfterFunction: true AfterNamespace: false AfterObjCDeclaration: false - AfterStruct: true + AfterStruct: false AfterUnion: false - AfterExternBlock: true + AfterExternBlock: false BeforeCatch: false - BeforeElse: false + BeforeElse: true IndentBraces: false SplitEmptyFunction: true SplitEmptyRecord: false SplitEmptyNamespace: true ColumnLimit: 79 +ContinuationIndentWidth: 2 DerivePointerAlignment: false IncludeBlocks: Regroup IncludeCategories: @@ -36,20 +71,22 @@ IncludeCategories: Priority: 1 - Regex: ".*" Priority: 3 +IndentPPDirectives: None +KeepEmptyLinesAtTheStartOfBlocks: false +NamespaceIndentation: None PointerAlignment: Right ReflowComments: false -Standard: Cpp03 +Standard: Auto StatementMacros: - Q_UNUSED - QT_REQUIRE_VERSION + # AccessModifierOffset: -2 -# AlignAfterOpenBracket: Align # AlignConsecutiveAssignments: false # AlignConsecutiveDeclarations: false # AlignEscapedNewlines: Right # AlignOperands: true # AlignTrailingComments: true -# AllowAllArgumentsOnNextLine: true # AllowAllConstructorInitializersOnNextLine: true # AllowAllParametersOfDeclarationOnNextLine: false # AllowShortCaseLabelsOnASingleLine: false @@ -61,7 +98,6 @@ StatementMacros: # AlwaysBreakAfterReturnType: TopLevel # AlwaysBreakBeforeMultilineStrings: false # AlwaysBreakTemplateDeclarations: Yes -# BreakBeforeBinaryOperators: None # BreakBeforeInheritanceComma: false # BreakInheritanceList: BeforeComma # BreakBeforeTernaryOperators: true @@ -73,7 +109,6 @@ StatementMacros: # CompactNamespaces: false # ConstructorInitializerAllOnOneLineOrOnePerLine: false # ConstructorInitializerIndentWidth: 2 -# ContinuationIndentWidth: 2 # Cpp11BracedListStyle: false # DisableFormat: false # ExperimentalAutoDetectBinPacking: false @@ -84,7 +119,6 @@ StatementMacros: # - BOOST_FOREACH # IncludeIsMainRegex: '(Test)?$' # IndentCaseLabels: true -# IndentPPDirectives: None # IndentWrappedFunctionNames: false # JavaScriptQuotes: Leave # JavaScriptWrapImports: true @@ -92,7 +126,6 @@ StatementMacros: # MacroBlockBegin: '' # MacroBlockEnd: '' # MaxEmptyLinesToKeep: 1 -# NamespaceIndentation: None # ObjCBinPackProtocolList: Auto # ObjCBlockIndentWidth: 2 # ObjCSpaceAfterProperty: true diff --git a/.gitignore b/.gitignore index 0b2d07118..ef08be476 100644 --- a/.gitignore +++ b/.gitignore @@ -3,8 +3,11 @@ core/deps/lv_drivers core/deps/llvm core/deps/lvgl +core/deps/tlsf core/shared/mem-alloc/tlsf +core/app-framework/wgl wamr-sdk/out/ wamr-sdk/runtime/build_runtime_sdk/ test-tools/host-tool/bin/ +product-mini/app-samples/hello-world/test.wasm \ No newline at end of file diff --git a/README.md b/README.md index be93b8e50..bdb707c86 100644 --- a/README.md +++ b/README.md @@ -22,11 +22,17 @@ iwasm VM core - 100% compliant to the W3C WASM MVP - Small runtime binary size (85K for interpreter and 50K for AoT) and low memory usage -- Near to native speed by AoT +- Near to native speed by AoT - Self-implemented module loader enables AoT working cross Linux, SGX and MCU systems - Choices of WASM application libc support: the built-in libc subset for the embedded environment or [WASI](https://github.com/WebAssembly/WASI) for standard libc - [Embeddable with the supporting C API's](./doc/embed_wamr.md) - [The mechanism for exporting native API's to WASM applications](./doc/export_native_api.md) +- [Multiple modules as dependencies](./doc/multi_module.md) + +### post-MVP features +- [Non-trapping float-to-int conversions](https://github.com/WebAssembly/nontrapping-float-to-int-conversions) +- [Sign-extension operators](https://github.com/WebAssembly/sign-extension-ops) +- [Bulk memory operations](https://github.com/WebAssembly/bulk-memory-operations) ### Performance and memory usage The WAMR performance, footprint and memory usage data are available at the [performance](../../wiki/Performance) wiki page. diff --git a/assembly-script/.gitignore b/assembly-script/.gitignore new file mode 100644 index 000000000..07e6e472c --- /dev/null +++ b/assembly-script/.gitignore @@ -0,0 +1 @@ +/node_modules diff --git a/build-scripts/config_common.cmake b/build-scripts/config_common.cmake index dc8f59d3f..6187910d8 100644 --- a/build-scripts/config_common.cmake +++ b/build-scripts/config_common.cmake @@ -123,8 +123,20 @@ else () add_definitions (-DWASM_ENABLE_FAST_INTERP=0) message (" Fast interpreter disabled") endif () - +if (WAMR_BUILD_MULTI_MODULE EQUAL 1) + add_definitions (-DWASM_ENABLE_MULTI_MODULE=1) + message (" Multiple modules enabled") +else () + add_definitions (-DWASM_ENABLE_MULTI_MODULE=0) + message (" Multiple modules disabled") +endif () if (WAMR_BUILD_SPEC_TEST EQUAL 1) add_definitions (-DWASM_ENABLE_SPEC_TEST=1) message (" spec test compatible mode is on") endif() +if (WAMR_BUILD_BULK_MEMORY EQUAL 1) + add_definitions (-DWASM_ENABLE_BULK_MEMORY=1) + message (" Bulk memory feature enabled") +else () + add_definitions (-DWASM_ENABLE_BULK_MEMORY=0) +endif() diff --git a/core/app-framework/app-native-shared/bi-inc/attr_container.h b/core/app-framework/app-native-shared/bi-inc/attr_container.h index d8fc08e4b..e70d0e4c4 100644 --- a/core/app-framework/app-native-shared/bi-inc/attr_container.h +++ b/core/app-framework/app-native-shared/bi-inc/attr_container.h @@ -6,7 +6,7 @@ #ifndef _ATTR_CONTAINER_H_ #define _ATTR_CONTAINER_H_ -#include +#include #include #include #include diff --git a/core/app-framework/app-native-shared/restful_utils.c b/core/app-framework/app-native-shared/restful_utils.c index 4907df017..5268b22a7 100644 --- a/core/app-framework/app-native-shared/restful_utils.c +++ b/core/app-framework/app-native-shared/restful_utils.c @@ -71,23 +71,18 @@ void free_req_resp_packet(char * packet) request_t * unpack_request(char * packet, int size, request_t * request) { if (*packet != REQUES_PACKET_VER) { - printf("version fail\n"); return NULL; } if (size < REQUEST_PACKET_FIX_PART_LEN) { - printf("size error: %d\n", size); return NULL; } uint16 url_len = ntohs(*((uint16*) (packet + 12))); uint32 payload_len = ntohl(*((uint32*) (packet + 14))); if (size != ( REQUEST_PACKET_FIX_PART_LEN + url_len + payload_len)) { - printf("size error: %d, expect: %d\n", size, - REQUEST_PACKET_FIX_PART_LEN + url_len + payload_len); return NULL; } if (*(packet + REQUEST_PACKET_FIX_PART_LEN + url_len - 1) != 0) { - printf("url not end with 0\n"); return NULL; } diff --git a/core/app-mgr/app-manager/app_manager_host.c b/core/app-mgr/app-manager/app_manager_host.c index c98a2c8ad..d9024a346 100644 --- a/core/app-mgr/app-manager/app_manager_host.c +++ b/core/app-mgr/app-manager/app_manager_host.c @@ -246,7 +246,7 @@ bool app_manager_host_init(host_interface *interface) return true; } -int app_manager_host_send_msg(int msg_type, const unsigned char *buf, int size) +int app_manager_host_send_msg(int msg_type, const char *buf, int size) { /* send an IMRT LINK message contains the buf as payload */ if (host_commu.send != NULL) { @@ -276,10 +276,10 @@ int app_manager_host_send_msg(int msg_type, const unsigned char *buf, int size) n = host_commu.send(NULL, buf, size); os_mutex_unlock(&host_lock); - printf("sent %d bytes to host\n", n); + app_manager_printf("sent %d bytes to host\n", n); return n; } else { - printf("no send api provided\n"); + app_manager_printf("no send api provided\n"); } return 0; } diff --git a/core/app-mgr/app-manager/module_wasm_app.c b/core/app-mgr/app-manager/module_wasm_app.c index 18f877e9c..f58580b6e 100644 --- a/core/app-mgr/app-manager/module_wasm_app.c +++ b/core/app-mgr/app-manager/module_wasm_app.c @@ -445,7 +445,7 @@ wasm_app_routine(void *arg) 0, NULL)) { const char *exception = wasm_runtime_get_exception(inst); bh_assert(exception); - printf("Got exception running wasi start function: %s\n", + app_manager_printf("Got exception running wasi start function: %s\n", exception); wasm_runtime_clear_exception(inst); goto fail1; @@ -467,7 +467,7 @@ wasm_app_routine(void *arg) 0, NULL)) { const char *exception = wasm_runtime_get_exception(inst); bh_assert(exception); - printf("Got exception running WASM code: %s\n", + app_manager_printf("Got exception running WASM code: %s\n", exception); wasm_runtime_clear_exception(inst); /* call on_destroy() in case some resources are opened in on_init() @@ -644,7 +644,7 @@ wasm_app_module_install(request_t * msg) if (!module) { SEND_ERR_RESPONSE(msg->mid, "Install WASM app failed: load WASM file failed."); - printf("error: %s\n", err); + app_manager_printf("error: %s\n", err); destroy_all_aot_sections(aot_file->sections); return false; } @@ -674,7 +674,7 @@ wasm_app_module_install(request_t * msg) if (!inst) { SEND_ERR_RESPONSE(msg->mid, "Install WASM app failed: instantiate wasm runtime failed."); - printf("error: %s\n", err); + app_manager_printf("error: %s\n", err); wasm_runtime_unload(module); destroy_all_aot_sections(aot_file->sections); return false; @@ -713,7 +713,7 @@ wasm_app_module_install(request_t * msg) if (!module) { SEND_ERR_RESPONSE(msg->mid, "Install WASM app failed: load WASM file failed."); - printf("error: %s\n", err); + app_manager_printf("error: %s\n", err); destroy_all_wasm_sections(bytecode_file->sections); return false; } @@ -744,7 +744,7 @@ wasm_app_module_install(request_t * msg) if (!inst) { SEND_ERR_RESPONSE(msg->mid, "Install WASM app failed: instantiate wasm runtime failed."); - printf("error: %s\n", err); + app_manager_printf("error: %s\n", err); wasm_runtime_unload(module); destroy_all_wasm_sections(bytecode_file->sections); return false; diff --git a/core/app-mgr/app-mgr-shared/app_manager_export.h b/core/app-mgr/app-mgr-shared/app_manager_export.h index 877a2df55..4e29b1f92 100644 --- a/core/app-mgr/app-mgr-shared/app_manager_export.h +++ b/core/app-mgr/app-mgr-shared/app_manager_export.h @@ -285,7 +285,7 @@ bool bh_applet_check_permission(const char *perm); int -app_manager_host_send_msg(int msg_type, const unsigned char *buf, int size); +app_manager_host_send_msg(int msg_type, const char *buf, int size); #ifdef __cplusplus } /* end of extern "C" */ diff --git a/core/config.h b/core/config.h index 25d546c33..e54a4be0c 100644 --- a/core/config.h +++ b/core/config.h @@ -94,6 +94,11 @@ enum { #define WASM_ENABLE_APP_FRAMEWORK 0 #endif +/* Bulk memory operation */ +#ifndef WASM_ENABLE_BULK_MEMORY +#define WASM_ENABLE_BULK_MEMORY 0 +#endif + /* WASM log system */ #ifndef WASM_ENABLE_LOG #define WASM_ENABLE_LOG 1 @@ -120,6 +125,11 @@ enum { #define WASM_ENABLE_OPCODE_COUNTER 0 #endif +/* Support a module with dependency, other modules */ +#ifndef WASM_ENABLE_MULTI_MODULE +#define WASM_ENABLE_MULTI_MODULE 0 +#endif + /* Heap and stack profiling */ #define BH_ENABLE_MEMORY_PROFILING 0 diff --git a/core/iwasm/aot/aot_loader.c b/core/iwasm/aot/aot_loader.c index 560030d56..ab043afe1 100644 --- a/core/iwasm/aot/aot_loader.c +++ b/core/iwasm/aot/aot_loader.c @@ -363,6 +363,11 @@ load_mem_init_data_list(const uint8 **p_buf, const uint8 *buf_end, for (i = 0; i < module->mem_init_data_count; i++) { uint32 init_expr_type, byte_count; uint64 init_expr_value; + uint32 is_passive; + uint32 memory_index; + + read_uint32(buf, buf_end, is_passive); + read_uint32(buf, buf_end, memory_index); read_uint32(buf, buf_end, init_expr_type); read_uint64(buf, buf_end, init_expr_value); read_uint32(buf, buf_end, byte_count); @@ -375,6 +380,11 @@ load_mem_init_data_list(const uint8 **p_buf, const uint8 *buf_end, return false; } +#if WASM_ENABLE_BULK_MEMORY != 0 + /* is_passive and memory_index is only used in bulk memory mode */ + data_list[i]->is_passive = (bool)is_passive; + data_list[i]->memory_index = memory_index; +#endif data_list[i]->offset.init_expr_type = (uint8)init_expr_type; data_list[i]->offset.u.i64 = (int64)init_expr_value; data_list[i]->byte_count = byte_count; @@ -773,8 +783,7 @@ load_import_funcs(const uint8 **p_buf, const uint8 *buf_end, read_uint16(buf, buf_end, import_funcs[i].func_type_index); if (import_funcs[i].func_type_index >= module->func_type_count) { set_error_buf(error_buf, error_buf_size, - "AOT module load failed: " - "invalid function type index."); + "AOT module load failed: unknown type."); return false; } import_funcs[i].func_type = module->func_types[import_funcs[i].func_type_index]; @@ -1067,8 +1076,7 @@ load_function_section(const uint8 *buf, const uint8 *buf_end, read_uint32(p, p_end, module->func_type_indexes[i]); if (module->func_type_indexes[i] >= module->func_type_count) { set_error_buf(error_buf, error_buf_size, - "AOT module load failed: " - "invalid function type index."); + "AOT module load failed: unknown type."); return false; } } diff --git a/core/iwasm/aot/aot_reloc.h b/core/iwasm/aot/aot_reloc.h index c98a58e26..198880850 100644 --- a/core/iwasm/aot/aot_reloc.h +++ b/core/iwasm/aot/aot_reloc.h @@ -12,6 +12,30 @@ typedef struct { #define REG_SYM(symbol) { #symbol, (void*)symbol } +#if WASM_ENABLE_BULK_MEMORY != 0 +#define REG_COMMON_SYMBOLS \ + REG_SYM(aot_set_exception_with_id), \ + REG_SYM(aot_invoke_native), \ + REG_SYM(aot_call_indirect), \ + REG_SYM(wasm_runtime_enlarge_memory), \ + REG_SYM(wasm_runtime_set_exception), \ + REG_SYM(fmin), \ + REG_SYM(fminf), \ + REG_SYM(fmax), \ + REG_SYM(fmaxf), \ + REG_SYM(ceil), \ + REG_SYM(ceilf), \ + REG_SYM(floor), \ + REG_SYM(floorf), \ + REG_SYM(trunc), \ + REG_SYM(truncf), \ + REG_SYM(rint), \ + REG_SYM(rintf), \ + REG_SYM(memset), \ + REG_SYM(memmove), \ + REG_SYM(aot_memory_init), \ + REG_SYM(aot_data_drop) +#else #define REG_COMMON_SYMBOLS \ REG_SYM(aot_set_exception_with_id), \ REG_SYM(aot_invoke_native), \ @@ -30,6 +54,7 @@ typedef struct { REG_SYM(truncf), \ REG_SYM(rint), \ REG_SYM(rintf) +#endif #define CHECK_RELOC_OFFSET(data_size) do { \ if (!check_reloc_offset(target_section_size, reloc_offset, data_size, \ diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index d64c1f1ba..d42989d21 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -68,42 +68,62 @@ table_instantiate(AOTModuleInstance *module_inst, AOTModule *module, uint32 i, global_index, global_data_offset, base_offset, length; AOTTableInitData *table_seg; - if (module->table_init_data_count > 0) { - for (i = 0; i < module->table_init_data_count; i++) { - table_seg = module->table_init_data_list[i]; - bh_assert(table_seg->offset.init_expr_type == - INIT_EXPR_TYPE_I32_CONST - || table_seg->offset.init_expr_type == - INIT_EXPR_TYPE_GET_GLOBAL); + for (i = 0; i < module->table_init_data_count; i++) { + table_seg = module->table_init_data_list[i]; + bh_assert(table_seg->offset.init_expr_type == + INIT_EXPR_TYPE_I32_CONST + || table_seg->offset.init_expr_type == + INIT_EXPR_TYPE_GET_GLOBAL); - /* Resolve table data base offset */ - if (table_seg->offset.init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL) { - global_index = table_seg->offset.u.global_index; - bh_assert(global_index < - module->import_global_count + module->global_count); - /* TODO: && globals[table_seg->offset.u.global_index].type == - VALUE_TYPE_I32*/ - if (global_index < module->import_global_count) - global_data_offset = - module->import_globals[global_index].data_offset; - else - global_data_offset = - module->globals[global_index - module->import_global_count] - .data_offset; - - base_offset = *(uint32*) - ((uint8*)module_inst->global_data.ptr + global_data_offset); - } + /* Resolve table data base offset */ + if (table_seg->offset.init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL) { + global_index = table_seg->offset.u.global_index; + bh_assert(global_index < + module->import_global_count + module->global_count); + /* TODO: && globals[table_seg->offset.u.global_index].type == + VALUE_TYPE_I32*/ + if (global_index < module->import_global_count) + global_data_offset = + module->import_globals[global_index].data_offset; else - base_offset = (uint32)table_seg->offset.u.i32; + global_data_offset = + module->globals[global_index - module->import_global_count] + .data_offset; - /* Copy table data */ - length = table_seg->func_index_count; - if (base_offset < module_inst->table_size) { - memcpy((uint32*)module_inst->table_data.ptr + base_offset, - table_seg->func_indexes, length * sizeof(uint32)); - } + base_offset = *(uint32*) + ((uint8*)module_inst->global_data.ptr + global_data_offset); } + else + base_offset = (uint32)table_seg->offset.u.i32; + + /* Copy table data */ + bh_assert(module_inst->table_data.ptr); + /* base_offset only since length might negative */ + if (base_offset > module_inst->table_size) { + LOG_DEBUG("base_offset(%d) > table_size(%d)", base_offset, + module_inst->table_size); + set_error_buf(error_buf, error_buf_size, + "elements segment does not fit"); + return false; + } + + /* base_offset + length(could be zero) */ + length = table_seg->func_index_count; + if (base_offset + length > module_inst->table_size) { + LOG_DEBUG("base_offset(%d) + length(%d) > table_size(%d)", + base_offset, length, module_inst->table_size); + set_error_buf(error_buf, error_buf_size, + "elements segment does not fit"); + return false; + } + + /** + * Check function index in the current module inst for now. + * will check the linked table inst owner in future + */ + memcpy((uint32 *)module_inst->table_data.ptr + base_offset, + table_seg->func_indexes, + length * sizeof(uint32)); } return true; @@ -169,50 +189,64 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModule *module, module_inst->mem_bound_check_8bytes = module_inst->total_mem_size - 8; } - if (module->mem_init_page_count > 0) { - for (i = 0; i < module->mem_init_data_count; i++) { - data_seg = module->mem_init_data_list[i]; - bh_assert(data_seg->offset.init_expr_type == - INIT_EXPR_TYPE_I32_CONST - || data_seg->offset.init_expr_type == - INIT_EXPR_TYPE_GET_GLOBAL); + for (i = 0; i < module->mem_init_data_count; i++) { + data_seg = module->mem_init_data_list[i]; +#if WASM_ENABLE_BULK_MEMORY != 0 + if (data_seg->is_passive) + continue; +#endif - /* Resolve memory data base offset */ - if (data_seg->offset.init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL) { - global_index = data_seg->offset.u.global_index; - bh_assert(global_index < - module->import_global_count + module->global_count); - /* TODO: && globals[data_seg->offset.u.global_index].type == - VALUE_TYPE_I32*/ - if (global_index < module->import_global_count) - global_data_offset = - module->import_globals[global_index].data_offset; - else - global_data_offset = - module->globals[global_index - module->import_global_count] - .data_offset; + bh_assert(data_seg->offset.init_expr_type == + INIT_EXPR_TYPE_I32_CONST + || data_seg->offset.init_expr_type == + INIT_EXPR_TYPE_GET_GLOBAL); - base_offset = *(uint32*) - ((uint8*)module_inst->global_data.ptr + global_data_offset); - } + /* Resolve memory data base offset */ + if (data_seg->offset.init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL) { + global_index = data_seg->offset.u.global_index; + bh_assert(global_index < + module->import_global_count + module->global_count); + /* TODO: && globals[data_seg->offset.u.global_index].type == + VALUE_TYPE_I32*/ + if (global_index < module->import_global_count) + global_data_offset = + module->import_globals[global_index].data_offset; else - base_offset = (uint32)data_seg->offset.u.i32; + global_data_offset = + module->globals[global_index - module->import_global_count] + .data_offset; - length = data_seg->byte_count; - - /* Check memory data */ - if (length > 0 - && (base_offset >= module_inst->memory_data_size - || base_offset + length > module_inst->memory_data_size)) { - set_error_buf(error_buf, error_buf_size, - "AOT module instantiate failed: data segment out of range."); - goto fail2; - } - - /* Copy memory data */ - memcpy((uint8*)module_inst->memory_data.ptr + base_offset, - data_seg->bytes, length); + base_offset = *(uint32*) + ((uint8*)module_inst->global_data.ptr + global_data_offset); + } else { + base_offset = (uint32)data_seg->offset.u.i32; } + + /* Copy memory data */ + bh_assert(module_inst->memory_data.ptr); + + /* Check memory data */ + /* check offset since length might negative */ + if (base_offset > module_inst->memory_data_size) { + LOG_DEBUG("base_offset(%d) > memory_data_size(%d)", base_offset, + module_inst->memory_data_size); + set_error_buf(error_buf, error_buf_size, + "data segment does not fit"); + goto fail2; + } + + /* check offset + length(could be zero) */ + length = data_seg->byte_count; + if (base_offset + length > module_inst->memory_data_size) { + LOG_DEBUG("base_offset(%d) + length(%d) > memory_data_size(%d)", + base_offset, length, module_inst->memory_data_size); + set_error_buf(error_buf, error_buf_size, + "data segment does not fit"); + goto fail2; + } + + memcpy((uint8*)module_inst->memory_data.ptr + base_offset, + data_seg->bytes, length); } return true; @@ -952,3 +986,61 @@ aot_call_indirect(WASMExecEnv *exec_env, func_type, signature, attachment, argv, argc, argv); } + +#if WASM_ENABLE_BULK_MEMORY != 0 +bool +aot_memory_init(AOTModuleInstance *module_inst, uint32 seg_index, + uint32 offset, uint32 len, uint32 dst) +{ + AOTModule *aot_module; + uint8 *data = NULL; + uint8 *maddr; + uint64 seg_len = 0; + + aot_module = (AOTModule *)module_inst->aot_module.ptr; + if (aot_module->is_jit_mode) { +#if WASM_ENABLE_JIT != 0 + seg_len = aot_module->wasm_module->data_segments[seg_index]->data_length; + data = aot_module->wasm_module->data_segments[seg_index]->data; +#endif + } + else { + seg_len = aot_module->mem_init_data_list[seg_index]->byte_count; + data = aot_module->mem_init_data_list[seg_index]->bytes; + } + + if (!aot_validate_app_addr(module_inst, dst, len)) + return false; + + if ((uint64)offset + (uint64)len > seg_len) { + aot_set_exception(module_inst, "out of bounds memory access"); + return false; + } + + maddr = aot_addr_app_to_native(module_inst, dst); + + bh_memcpy_s(maddr, module_inst->memory_data_size - dst, + data + offset, len); + return true; +} + +bool +aot_data_drop(AOTModuleInstance *module_inst, uint32 seg_index) +{ + AOTModule *aot_module = (AOTModule *)(module_inst->aot_module.ptr); + + if (aot_module->is_jit_mode) { +#if WASM_ENABLE_JIT != 0 + aot_module->wasm_module->data_segments[seg_index]->data_length = 0; + /* Currently we can't free the dropped data segment + as they are stored in wasm bytecode */ +#endif + } + else { + aot_module->mem_init_data_list[seg_index]->byte_count = 0; + /* Currently we can't free the dropped data segment + as the mem_init_data_count is a continuous array */ + } + return true; +} +#endif /* WASM_ENABLE_BULK_MEMORY */ diff --git a/core/iwasm/aot/aot_runtime.h b/core/iwasm/aot/aot_runtime.h index 41f9b7a85..74d9667e2 100644 --- a/core/iwasm/aot/aot_runtime.h +++ b/core/iwasm/aot/aot_runtime.h @@ -458,6 +458,15 @@ aot_call_indirect(WASMExecEnv *exec_env, uint32 aot_get_plt_table_size(); +#if WASM_ENABLE_BULK_MEMORY != 0 +bool +aot_memory_init(AOTModuleInstance *module_inst, uint32 seg_index, + uint32 offset, uint32 len, uint32 dst); + +bool +aot_data_drop(AOTModuleInstance *module_inst, uint32 seg_index); +#endif + #ifdef __cplusplus } /* end of extern "C" */ #endif diff --git a/core/iwasm/common/wasm_native.c b/core/iwasm/common/wasm_native.c index 2a2c41c1c..115296eed 100644 --- a/core/iwasm/common/wasm_native.c +++ b/core/iwasm/common/wasm_native.c @@ -243,6 +243,7 @@ wasm_native_init() if (!wasm_native_register_natives("env", native_symbols, n_native_symbols)) return false; +#endif /* WASM_ENABLE_LIBC_BUILTIN */ #if WASM_ENABLE_SPEC_TEST n_native_symbols = get_spectest_export_apis(&native_symbols); @@ -250,7 +251,6 @@ wasm_native_init() native_symbols, n_native_symbols)) return false; #endif /* WASM_ENABLE_SPEC_TEST */ -#endif /* WASM_ENABLE_LIBC_BUILTIN */ #if WASM_ENABLE_LIBC_WASI != 0 n_native_symbols = get_libc_wasi_export_apis(&native_symbols); diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index 1db69b462..c3b6da951 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -16,6 +16,43 @@ #include "../aot/aot_runtime.h" #endif +#if WASM_ENABLE_MULTI_MODULE != 0 +/* + * a safety insurance to prevent + * circular depencies leading a stack overflow + * try break early + */ +typedef struct LoadingModule { + bh_list_link l; + /* point to a string pool */ + const char *module_name; +} LoadingModule; + +static bh_list loading_module_list_head; +static bh_list *const loading_module_list = &loading_module_list_head; +static korp_mutex loading_module_list_lock; + +/* + * a list about all exported functions, globals, memories, tables of every + * fully loaded module + */ +static bh_list registered_module_list_head; +static bh_list *const registered_module_list = ®istered_module_list_head; +static korp_mutex registered_module_list_lock; +static void +wasm_runtime_destroy_registered_module_list(); +#endif /* WASM_ENABLE_MULTI_MODULE */ + +void +set_error_buf_v(char *error_buf, uint32 error_buf_size, const char *format, + ...) +{ + va_list args; + va_start(args, format); + vsnprintf(error_buf, error_buf_size, format, args); + va_end(args); +} + static void set_error_buf(char *error_buf, uint32 error_buf_size, const char *string) { @@ -34,11 +71,25 @@ wasm_runtime_env_init() return false; } +#if WASM_ENABLE_MULTI_MODULE + if (BHT_OK != os_mutex_init(®istered_module_list_lock)) { + wasm_native_destroy(); + bh_platform_destroy(); + return false; + } + + if (BHT_OK != os_mutex_init(&loading_module_list_lock)) { + os_mutex_destroy(®istered_module_list_lock); + wasm_native_destroy(); + bh_platform_destroy(); + return false; + } +#endif return true; } static bool -wasm_runtime_env_check(WASMExecEnv *exec_env) +wasm_runtime_exec_env_check(WASMExecEnv *exec_env) { return !(!exec_env || !exec_env->module_inst @@ -65,8 +116,17 @@ wasm_runtime_init() void wasm_runtime_destroy() { + /* runtime env destroy */ +#if WASM_ENABLE_MULTI_MODULE + wasm_runtime_destroy_loading_module_list(); + os_mutex_destroy(&loading_module_list_lock); + + wasm_runtime_destroy_registered_module_list(); + os_mutex_destroy(®istered_module_list_lock); +#endif wasm_native_destroy(); bh_platform_destroy(); + wasm_runtime_memory_destroy(); } @@ -105,10 +165,342 @@ get_package_type(const uint8 *buf, uint32 size) return Package_Type_Unknown; } +#if WASM_ENABLE_MULTI_MODULE != 0 +static module_reader reader; +static module_destroyer destroyer; + +void +wasm_runtime_set_module_reader(const module_reader reader_cb, + const module_destroyer destroyer_cb) +{ + reader = reader_cb; + destroyer = destroyer_cb; +} + +module_reader +wasm_runtime_get_module_reader() +{ + return reader; +} + +module_destroyer +wasm_runtime_get_module_destroyer() +{ + return destroyer; +} + +static WASMRegisteredModule * +wasm_runtime_find_module_registered_by_reference(WASMModuleCommon *module) +{ + WASMRegisteredModule *reg_module = NULL; + + os_mutex_lock(®istered_module_list_lock); + reg_module = bh_list_first_elem(registered_module_list); + while (reg_module && module != reg_module->module) { + reg_module = bh_list_elem_next(reg_module); + } + os_mutex_unlock(®istered_module_list_lock); + + return reg_module; +} + +bool +wasm_runtime_register_module_internal(const char *module_name, + WASMModuleCommon *module, + uint8 *orig_file_buf, + uint32 orig_file_buf_size, + char *error_buf, + uint32_t error_buf_size) +{ + WASMRegisteredModule *node = NULL; + + node = wasm_runtime_find_module_registered_by_reference(module); + if (node) { /* module has been registered */ + if (node->module_name) { /* module has name */ + if (strcmp(node->module_name, module_name)) { + /* module has different name */ + LOG_DEBUG("module(%p) has been registered with name %s", + module, node->module_name); + set_error_buf_v(error_buf, error_buf_size, + "can not rename the module"); + return false; + } + else { + /* module has the same name */ + LOG_DEBUG("module(%p) has been registered with the same name %s", + module, node->module_name); + return true; + } + } + else { + /* module has empyt name, reset it */ + node->module_name = module_name; + return true; + } + } + + /* module hasn't been registered */ + node = wasm_runtime_malloc(sizeof(WASMRegisteredModule)); + if (!node) { + LOG_DEBUG("malloc WASMRegisteredModule failed. SZ=%d", + sizeof(WASMRegisteredModule)); + set_error_buf_v(error_buf, error_buf_size, + "malloc WASMRegisteredModule failed. SZ=%d", + sizeof(WASMRegisteredModule)); + return false; + } + + /* share the string and the module */ + node->module_name = module_name; + node->module = module; + node->orig_file_buf = orig_file_buf; + node->orig_file_buf_size = orig_file_buf_size; + + os_mutex_lock(®istered_module_list_lock); + bh_list_status ret = bh_list_insert(registered_module_list, node); + bh_assert(BH_LIST_SUCCESS == ret); + (void)ret; + os_mutex_unlock(®istered_module_list_lock); + return true; +} + +bool +wasm_runtime_register_module(const char *module_name, WASMModuleCommon *module, + char *error_buf, uint32_t error_buf_size) +{ + if (!error_buf || !error_buf_size) { + LOG_ERROR("error buffer is required"); + return false; + } + + if (!module_name || !module) { + LOG_DEBUG("module_name and module are required"); + set_error_buf_v(error_buf, error_buf_size, + "module_name and module are required"); + return false; + } + + if (wasm_runtime_is_built_in_module(module_name)) { + LOG_DEBUG("%s is a built-in module name", module_name); + set_error_buf(error_buf, error_buf_size, + "can not register as a built-in module"); + return false; + } + + return wasm_runtime_register_module_internal( + module_name, module, NULL, 0, + error_buf, error_buf_size); +} + +void +wasm_runtime_unregister_module(const WASMModuleCommon *module) +{ + WASMRegisteredModule *registered_module = NULL; + + os_mutex_lock(®istered_module_list_lock); + registered_module = bh_list_first_elem(registered_module_list); + while (registered_module && module != registered_module->module) { + registered_module = bh_list_elem_next(registered_module); + } + + /* it does not matter if it is not exist. after all, it is gone */ + if (registered_module) { + bh_list_remove(registered_module_list, registered_module); + wasm_runtime_free(registered_module); + } + os_mutex_unlock(®istered_module_list_lock); +} + +WASMModuleCommon * +wasm_runtime_find_module_registered(const char *module_name) +{ + WASMRegisteredModule *module = NULL, *module_next; + + os_mutex_lock(®istered_module_list_lock); + module = bh_list_first_elem(registered_module_list); + while (module) { + module_next = bh_list_elem_next(module); + if (module->module_name + && !strcmp(module_name, module->module_name)) { + break; + } + module = module_next; + } + os_mutex_unlock(®istered_module_list_lock); + + return module ? module->module : NULL; +} + +bool +wasm_runtime_is_module_registered(const char *module_name) +{ + return NULL != wasm_runtime_find_module_registered(module_name); +} + +/* + * simply destroy all + */ +static void +wasm_runtime_destroy_registered_module_list() +{ + WASMRegisteredModule *reg_module = NULL; + + os_mutex_lock(®istered_module_list_lock); + reg_module = bh_list_first_elem(registered_module_list); + while (reg_module) { + WASMRegisteredModule *next_reg_module = bh_list_elem_next(reg_module); + + bh_list_remove(registered_module_list, reg_module); + + /* now, it is time to release every module in the runtime */ +#if WASM_ENABLE_INTERP != 0 + if (reg_module->module->module_type == Wasm_Module_Bytecode) + wasm_unload((WASMModule *)reg_module->module); +#endif +#if WASM_ENABLE_AOT != 0 + if (reg_module->module->module_type == Wasm_Module_AoT) + aot_unload((AOTModule *)reg_module->module); +#endif + + /* destroy the file buffer */ + if (destroyer && reg_module->orig_file_buf) { + destroyer(reg_module->orig_file_buf, + reg_module->orig_file_buf_size); + reg_module->orig_file_buf = NULL; + reg_module->orig_file_buf_size = 0; + } + + wasm_runtime_free(reg_module); + reg_module = next_reg_module; + } + os_mutex_unlock(®istered_module_list_lock); +} + +bool +wasm_runtime_add_loading_module(const char *module_name, char *error_buf, + uint32 error_buf_size) +{ + LOG_DEBUG("add %s into a loading list", module_name); + LoadingModule *loadingModule = wasm_runtime_malloc(sizeof(LoadingModule)); + + if (!loadingModule) { + set_error_buf_v(error_buf, error_buf_size, + "malloc LoadingModule failed. SZ=%d", + sizeof(LoadingModule)); + return false; + } + + /* share the incoming string */ + loadingModule->module_name = module_name; + + os_mutex_lock(&loading_module_list_lock); + bh_list_status ret = bh_list_insert(loading_module_list, loadingModule); + bh_assert(BH_LIST_SUCCESS == ret); + (void)ret; + os_mutex_unlock(&loading_module_list_lock); + return true; +} + +void +wasm_runtime_delete_loading_module(const char *module_name) +{ + LOG_DEBUG("delete %s from a loading list", module_name); + + LoadingModule *module = NULL; + + os_mutex_lock(&loading_module_list_lock); + module = bh_list_first_elem(loading_module_list); + while (module && strcmp(module->module_name, module_name)) { + module = bh_list_elem_next(module); + } + + /* it does not matter if it is not exist. after all, it is gone */ + if (module) { + bh_list_remove(loading_module_list, module); + wasm_runtime_free(module); + } + os_mutex_unlock(&loading_module_list_lock); +} + +bool +wasm_runtime_is_loading_module(const char *module_name) +{ + LOG_DEBUG("find %s in a loading list", module_name); + + LoadingModule *module = NULL; + + os_mutex_lock(&loading_module_list_lock); + module = bh_list_first_elem(loading_module_list); + while (module && strcmp(module_name, module->module_name)) { + module = bh_list_elem_next(module); + } + os_mutex_unlock(&loading_module_list_lock); + + return module != NULL; +} + +void +wasm_runtime_destroy_loading_module_list() +{ + LoadingModule *module = NULL; + + os_mutex_lock(&loading_module_list_lock); + module = bh_list_first_elem(loading_module_list); + while (module) { + LoadingModule *next_module = bh_list_elem_next(module); + + bh_list_remove(loading_module_list, module); + /* + * will not free the module_name since it is + * shared one of the const string pool + */ + wasm_runtime_free(module); + + module = next_module; + } + + os_mutex_unlock(&loading_module_list_lock); +} +#endif /* WASM_ENABLE_MULTI_MODULE */ + +bool +wasm_runtime_is_built_in_module(const char *module_name) +{ + return (!strcmp("env", module_name) + || !strcmp("wasi_unstable", module_name) + || !strcmp("wasi_snapshot_preview1", module_name) + || !strcmp("spectest", module_name) + ); +} + +static WASMModuleCommon * +register_module_with_null_name(WASMModuleCommon *module_common, + char *error_buf, uint32 error_buf_size) +{ +#if WASM_ENABLE_MULTI_MODULE != 0 + if (module_common) { + if (!wasm_runtime_register_module_internal(NULL, module_common, + NULL, 0, + error_buf, + error_buf_size)) { + wasm_runtime_unload(module_common); + return NULL; + } + return module_common; + } + else + return NULL; +#else + return module_common; +#endif +} + WASMModuleCommon * wasm_runtime_load(const uint8 *buf, uint32 size, char *error_buf, uint32 error_buf_size) { + WASMModuleCommon *module_common = NULL; + if (get_package_type(buf, size) == Wasm_Module_Bytecode) { #if WASM_ENABLE_AOT != 0 && WASM_ENABLE_JIT != 0 AOTModule *aot_module; @@ -121,18 +513,24 @@ wasm_runtime_load(const uint8 *buf, uint32 size, wasm_unload(module); return NULL; } - return (WASMModuleCommon*)aot_module; + + module_common = (WASMModuleCommon*)aot_module; + return register_module_with_null_name(module_common, + error_buf, error_buf_size); #elif WASM_ENABLE_INTERP != 0 - return (WASMModuleCommon*) + module_common = (WASMModuleCommon*) wasm_load(buf, size, error_buf, error_buf_size); + return register_module_with_null_name(module_common, + error_buf, error_buf_size); #endif } else if (get_package_type(buf, size) == Wasm_Module_AoT) { #if WASM_ENABLE_AOT != 0 - return (WASMModuleCommon*) + module_common = (WASMModuleCommon*) aot_load_from_aot_file(buf, size, error_buf, error_buf_size); - -#endif /* end of WASM_ENABLE_AOT */ + return register_module_with_null_name(module_common, + error_buf, error_buf_size); +#endif } if (size < 4) @@ -148,17 +546,25 @@ WASMModuleCommon * wasm_runtime_load_from_sections(WASMSection *section_list, bool is_aot, char *error_buf, uint32_t error_buf_size) { + WASMModuleCommon *module_common; + #if WASM_ENABLE_INTERP != 0 - if (!is_aot) - return (WASMModuleCommon*) + if (!is_aot) { + module_common = (WASMModuleCommon*) wasm_load_from_sections(section_list, error_buf, error_buf_size); + return register_module_with_null_name(module_common, + error_buf, error_buf_size); + } #endif #if WASM_ENABLE_AOT != 0 - if (is_aot) - return (WASMModuleCommon*) + if (is_aot) { + module_common = (WASMModuleCommon*) aot_load_from_sections(section_list, error_buf, error_buf_size); + return register_module_with_null_name(module_common, + error_buf, error_buf_size); + } #endif set_error_buf(error_buf, error_buf_size, @@ -169,12 +575,21 @@ wasm_runtime_load_from_sections(WASMSection *section_list, bool is_aot, void wasm_runtime_unload(WASMModuleCommon *module) { +#if WASM_ENABLE_MULTI_MODULE != 0 + /** + * since we will unload and free all module when runtime_destroy() + * we don't want users to unwillingly disrupt it + */ + return; +#endif + #if WASM_ENABLE_INTERP != 0 if (module->module_type == Wasm_Module_Bytecode) { wasm_unload((WASMModule*)module); return; } #endif + #if WASM_ENABLE_AOT != 0 if (module->module_type == Wasm_Module_AoT) { aot_unload((AOTModule*)module); @@ -285,9 +700,9 @@ wasm_runtime_lookup_function(WASMModuleInstanceCommon * const module_inst, bool wasm_runtime_call_wasm(WASMExecEnv *exec_env, WASMFunctionInstanceCommon *function, - unsigned argc, uint32 argv[]) + uint32 argc, uint32 argv[]) { - if (!wasm_runtime_env_check(exec_env)) { + if (!wasm_runtime_exec_env_check(exec_env)) { LOG_ERROR("Invalid exec env stack info."); return false; } @@ -313,7 +728,7 @@ wasm_runtime_call_wasm(WASMExecEnv *exec_env, bool wasm_runtime_create_exec_env_and_call_wasm(WASMModuleInstanceCommon *module_inst, WASMFunctionInstanceCommon *function, - unsigned argc, uint32 argv[]) + uint32 argc, uint32 argv[]) { #if WASM_ENABLE_INTERP != 0 if (module_inst->module_type == Wasm_Module_Bytecode) @@ -1077,7 +1492,7 @@ check_main_func_type(const WASMType *type) bool wasm_application_execute_main(WASMModuleInstanceCommon *module_inst, - int argc, char *argv[]) + int32 argc, char *argv[]) { WASMFunctionInstanceCommon *func; WASMType *func_type = NULL; @@ -1165,6 +1580,54 @@ wasm_application_execute_main(WASMModuleInstanceCommon *module_inst, argc1, argv1); } + + +#if WASM_ENABLE_MULTI_MODULE != 0 +static WASMModuleInstance * +get_sub_module_inst(const WASMModuleInstance *parent_module_inst, + const char *sub_module_name) +{ + WASMSubModInstNode *node = + bh_list_first_elem(parent_module_inst->sub_module_inst_list); + + while (node && strcmp(node->module_name, sub_module_name)) { + node = bh_list_elem_next(node); + } + return node ? node->module_inst : NULL; +} + +static bool +parse_function_name(char *orig_function_name, char **p_module_name, + char **p_function_name) +{ + if (orig_function_name[0] != '$') { + *p_module_name = NULL; + *p_function_name = orig_function_name; + return true; + } + + /** + * $module_name$function_name\0 + * ===> + * module_name\0function_name\0 + * ===> + * module_name + * function_name + */ + char *p1 = orig_function_name; + char *p2 = strchr(p1 + 1, '$'); + if (!p2) { + LOG_DEBUG("can not parse the incoming function name"); + return false; + } + + *p_module_name = p1 + 1; + *p2 = '\0'; + *p_function_name = p2 + 1; + return strlen(*p_module_name) && strlen(*p_function_name); +} +#endif + /** * Implementation of wasm_application_execute_func() */ @@ -1173,32 +1636,76 @@ static WASMFunctionInstanceCommon* resolve_function(const WASMModuleInstanceCommon *module_inst, const char *name) { - uint32 i; + uint32 i = 0; + WASMFunctionInstanceCommon *ret = NULL; +#if WASM_ENABLE_MULTI_MODULE != 0 + WASMModuleInstance *sub_module_inst = NULL; + char *orig_name = NULL; + char *sub_module_name = NULL; + char *function_name = NULL; + uint32 length = strlen(name) + 1; + + orig_name = wasm_runtime_malloc(sizeof(char) * length); + if (!orig_name) { + return NULL; + } + + memset(orig_name, 0, sizeof(char) * length); + strncpy(orig_name, name, length); + + if (!parse_function_name(orig_name, &sub_module_name, &function_name)) { + goto LEAVE; + } + + LOG_DEBUG("%s -> %s and %s", name, sub_module_name, function_name); + + if (sub_module_name) { + sub_module_inst = get_sub_module_inst( + (WASMModuleInstance *)module_inst, sub_module_name); + if (!sub_module_inst) { + LOG_DEBUG("can not find a sub module named %s", sub_module_name); + goto LEAVE; + } + } +#else + const char *function_name = name; +#endif #if WASM_ENABLE_INTERP != 0 if (module_inst->module_type == Wasm_Module_Bytecode) { WASMModuleInstance *wasm_inst = (WASMModuleInstance*)module_inst; + +#if WASM_ENABLE_MULTI_MODULE != 0 + wasm_inst = sub_module_inst ? sub_module_inst : wasm_inst; +#endif /* WASM_ENABLE_MULTI_MODULE */ + for (i = 0; i < wasm_inst->export_func_count; i++) { - if (!strcmp(wasm_inst->export_functions[i].name, name)) - return wasm_inst->export_functions[i].function; + if (!strcmp(wasm_inst->export_functions[i].name, function_name)) { + ret = wasm_inst->export_functions[i].function; + break; + } } - return NULL; } -#endif +#endif /* WASM_ENABLE_INTERP */ #if WASM_ENABLE_AOT != 0 if (module_inst->module_type == Wasm_Module_AoT) { AOTModuleInstance *aot_inst = (AOTModuleInstance*)module_inst; AOTModule *module = (AOTModule*)aot_inst->aot_module.ptr; for (i = 0; i < module->export_func_count; i++) { - if (!strcmp(module->export_funcs[i].func_name, name)) - return (WASMFunctionInstance*)&module->export_funcs[i]; + if (!strcmp(module->export_funcs[i].func_name, function_name)) { + ret = (WASMFunctionInstance*)&module->export_funcs[i]; + break; + } } - return NULL; } #endif - return NULL; +#if WASM_ENABLE_MULTI_MODULE != 0 +LEAVE: + wasm_runtime_free(orig_name); +#endif + return ret; } union ieee754_float { @@ -1251,7 +1758,7 @@ static union { bool wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, - const char *name, int argc, char *argv[]) + const char *name, int32 argc, char *argv[]) { WASMFunctionInstanceCommon *func; WASMType *type = NULL; @@ -1262,6 +1769,7 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, char buf[128]; bh_assert(argc >= 0); + LOG_DEBUG("call a function \"%s\" with %d arguments", name, argc); func = resolve_function(module_inst, name); if (!func) { @@ -1273,7 +1781,11 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, #if WASM_ENABLE_INTERP != 0 if (module_inst->module_type == Wasm_Module_Bytecode) { WASMFunctionInstance *wasm_func = (WASMFunctionInstance*)func; - if (wasm_func->is_import_func) { + if (wasm_func->is_import_func +#if WASM_ENABLE_MULTI_MODULE != 0 + && !wasm_func->import_func_inst +#endif + ) { snprintf(buf, sizeof(buf), "lookup function %s failed.", name); wasm_runtime_set_exception(module_inst, buf); goto fail; @@ -2146,7 +2658,7 @@ wasm_runtime_call_indirect(WASMExecEnv *exec_env, uint32_t element_indices, uint32_t argc, uint32_t argv[]) { - if (!wasm_runtime_env_check(exec_env)) { + if (!wasm_runtime_exec_env_check(exec_env)) { LOG_ERROR("Invalid exec env stack info."); return false; } diff --git a/core/iwasm/common/wasm_runtime_common.h b/core/iwasm/common/wasm_runtime_common.h index 432db5988..97db71f8e 100644 --- a/core/iwasm/common/wasm_runtime_common.h +++ b/core/iwasm/common/wasm_runtime_common.h @@ -21,7 +21,6 @@ extern "C" { #endif - typedef struct WASMModuleCommon { /* Module type, for module loaded from WASM bytecode binary, this field is Wasm_Module_Bytecode, and this structure should @@ -56,9 +55,25 @@ typedef struct WASIContext { } WASIContext; #endif +#if WASM_ENABLE_MULTI_MODULE != 0 +typedef struct WASMRegisteredModule { + bh_list_link l; + /* point to a string pool */ + const char *module_name; + WASMModuleCommon *module; + /* to store the original module file buffer address */ + uint8 *orig_file_buf; + uint32 orig_file_buf_size; +} WASMRegisteredModule; +#endif + typedef package_type_t PackageType; typedef wasm_section_t WASMSection, AOTSection; +void +set_error_buf_v(char *error_buf, uint32 error_buf_size, const char *format, + ...); + /* See wasm_export.h for description */ bool wasm_runtime_init(); @@ -75,6 +90,7 @@ wasm_runtime_destroy(); PackageType get_package_type(const uint8 *buf, uint32 size); + /* See wasm_export.h for description */ WASMModuleCommon * wasm_runtime_load(const uint8 *buf, uint32 size, @@ -83,7 +99,7 @@ wasm_runtime_load(const uint8 *buf, uint32 size, /* See wasm_export.h for description */ WASMModuleCommon * wasm_runtime_load_from_sections(WASMSection *section_list, bool is_aot, - char *error_buf, uint32_t error_buf_size); + char *error_buf, uint32 error_buf_size); /* See wasm_export.h for description */ void @@ -119,21 +135,21 @@ wasm_runtime_get_module_inst(WASMExecEnv *exec_env); /* See wasm_export.h for description */ void * -wasm_runtime_get_function_attachment(wasm_exec_env_t exec_env); +wasm_runtime_get_function_attachment(WASMExecEnv *exec_env); /* See wasm_export.h for description */ void -wasm_runtime_set_user_data(wasm_exec_env_t exec_env, void *user_data); +wasm_runtime_set_user_data(WASMExecEnv *exec_env, void *user_data); /* See wasm_export.h for description */ void * -wasm_runtime_get_user_data(wasm_exec_env_t exec_env); +wasm_runtime_get_user_data(WASMExecEnv *exec_env); /* See wasm_export.h for description */ bool wasm_runtime_call_wasm(WASMExecEnv *exec_env, WASMFunctionInstanceCommon *function, - unsigned argc, uint32 argv[]); + uint32 argc, uint32 argv[]); /** * Call a function reference of a given WASM runtime instance with @@ -154,23 +170,23 @@ wasm_runtime_call_wasm(WASMExecEnv *exec_env, */ bool wasm_runtime_call_indirect(WASMExecEnv *exec_env, - uint32_t element_indices, - uint32_t argc, uint32_t argv[]); + uint32 element_indices, + uint32 argc, uint32 argv[]); bool wasm_runtime_create_exec_env_and_call_wasm(WASMModuleInstanceCommon *module_inst, WASMFunctionInstanceCommon *function, - unsigned argc, uint32 argv[]); + uint32 argc, uint32 argv[]); /* See wasm_export.h for description */ bool wasm_application_execute_main(WASMModuleInstanceCommon *module_inst, - int argc, char *argv[]); + int32 argc, char *argv[]); /* See wasm_export.h for description */ bool wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, - const char *name, int argc, char *argv[]); + const char *name, int32 argc, char *argv[]); /* See wasm_export.h for description */ void @@ -261,6 +277,48 @@ void wasm_runtime_set_llvm_stack(WASMModuleInstanceCommon *module_inst, uint32 llvm_stack); +#if WASM_ENABLE_MULTI_MODULE != 0 +void +wasm_runtime_set_module_reader(const module_reader reader, + const module_destroyer destroyer); + +module_reader +wasm_runtime_get_module_reader(); + +module_destroyer +wasm_runtime_get_module_destroyer(); + +bool +wasm_runtime_register_module_internal(const char *module_name, + WASMModuleCommon *module, + uint8 *orig_file_buf, + uint32 orig_file_buf_size, + char *error_buf, + uint32 error_buf_size); + +void +wasm_runtime_unregister_module(const WASMModuleCommon *module); + +bool +wasm_runtime_is_module_registered(const char *module_name); + +bool +wasm_runtime_add_loading_module(const char *module_name, + char *error_buf, uint32 error_buf_size); + +void +wasm_runtime_delete_loading_module(const char *module_name); + +bool +wasm_runtime_is_loading_module(const char *module_name); + +void +wasm_runtime_destroy_loading_module_list(); +#endif /* WASM_ENALBE_MULTI_MODULE */ + +bool +wasm_runtime_is_built_in_module(const char *module_name); + #if WASM_ENABLE_LIBC_WASI != 0 /* See wasm_export.h for description */ void diff --git a/core/iwasm/compilation/aot.c b/core/iwasm/compilation/aot.c index a130ba7a6..025294b6f 100644 --- a/core/iwasm/compilation/aot.c +++ b/core/iwasm/compilation/aot.c @@ -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, diff --git a/core/iwasm/compilation/aot.h b/core/iwasm/compilation/aot.h index ede02b434..7a533fa75 100644 --- a/core/iwasm/compilation/aot.h +++ b/core/iwasm/compilation/aot.h @@ -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 */ diff --git a/core/iwasm/compilation/aot_compiler.c b/core/iwasm/compilation/aot_compiler.c index 15fc1dd2c..617bf6e65 100644 --- a/core/iwasm/compilation/aot_compiler.c +++ b/core/iwasm/compilation/aot_compiler.c @@ -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; } diff --git a/core/iwasm/compilation/aot_emit_aot_file.c b/core/iwasm/compilation/aot_emit_aot_file.c index 2cffb44f6..2095388e0 100644 --- a/core/iwasm/compilation/aot_emit_aot_file.c +++ b/core/iwasm/compilation/aot_emit_aot_file.c @@ -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) diff --git a/core/iwasm/compilation/aot_emit_memory.c b/core/iwasm/compilation/aot_emit_memory.c index 680d24c7e..70e6a0faa 100644 --- a/core/iwasm/compilation/aot_emit_memory.c +++ b/core/iwasm/compilation/aot_emit_memory.c @@ -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 */ diff --git a/core/iwasm/compilation/aot_emit_memory.h b/core/iwasm/compilation/aot_emit_memory.h index d34264c36..c2415ff92 100644 --- a/core/iwasm/compilation/aot_emit_memory.h +++ b/core/iwasm/compilation/aot_emit_memory.h @@ -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 diff --git a/core/iwasm/compilation/aot_llvm.c b/core/iwasm/compilation/aot_llvm.c index 28572be3e..09155918c 100644 --- a/core/iwasm/compilation/aot_llvm.c +++ b/core/iwasm/compilation/aot_llvm.c @@ -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)); diff --git a/core/iwasm/compilation/aot_llvm.h b/core/iwasm/compilation/aot_llvm.h index 8883681c0..fc4821e22 100644 --- a/core/iwasm/compilation/aot_llvm.h +++ b/core/iwasm/compilation/aot_llvm.h @@ -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; diff --git a/core/iwasm/include/aot_export.h b/core/iwasm/include/aot_export.h index 4338465cf..531d2df79 100644 --- a/core/iwasm/include/aot_export.h +++ b/core/iwasm/include/aot_export.h @@ -39,6 +39,7 @@ typedef struct AOTCompOption{ char *target_abi; char *target_cpu; char *cpu_features; + bool enable_bulk_memory; uint32_t opt_level; uint32_t size_level; uint32_t output_format; diff --git a/core/iwasm/include/lib_export.h b/core/iwasm/include/lib_export.h index 0bc4317b8..3a4c02d43 100644 --- a/core/iwasm/include/lib_export.h +++ b/core/iwasm/include/lib_export.h @@ -6,7 +6,7 @@ #ifndef _LIB_EXPORT_H_ #define _LIB_EXPORT_H_ -#include +#include #ifdef __cplusplus extern "C" { diff --git a/core/iwasm/include/wasm_export.h b/core/iwasm/include/wasm_export.h index 0a915f83a..0ef3bb982 100644 --- a/core/iwasm/include/wasm_export.h +++ b/core/iwasm/include/wasm_export.h @@ -6,7 +6,7 @@ #ifndef _WASM_EXPORT_H #define _WASM_EXPORT_H -#include +#include #include #include "lib_export.h" @@ -178,6 +178,56 @@ void wasm_runtime_free(void *ptr); package_type_t get_package_type(const uint8_t *buf, uint32_t size); +#if WASM_ENABLE_MULTI_MODULE != 0 +/** + * It is a callback for WAMR providing by embedding to load a module file + * into a buffer + */ +typedef bool (*module_reader)(const char *module_name, + uint8_t **p_buffer, uint32_t *p_size); + +/** + * It is a callback for WAMR providing by embedding to release the buffer which + * is used by loading a module file + */ +typedef void (*module_destroyer)(uint8_t *buffer, uint32_t size); + +/** + * To setup callbacks for reading and releasing a buffer about a module file + * + * @param reader a callback to read a module file into a buffer + * @param destroyer a callback to release above buffer + */ +void +wasm_runtime_set_module_reader(const module_reader reader, + const module_destroyer destroyer); +/** + * Give the "module" a name "module_name". + * can not assign a new name to a module if it already has a name + * + * @param module_name indicate a name + * @param module the target module + * @param error_buf output of the exception info + * @param error_buf_size the size of the exception string + * + * @return true means success, false means failed + */ +bool +wasm_runtime_register_module(const char *module_name, wasm_module_t module, + char *error_buf, uint32_t error_buf_size); + +/** + * To check if there is already a loaded module named module_name in the + * runtime. you will not want to load repeately + * + * @param module_name indicate a name + * + * @return return WASM module loaded, NULL if failed + */ +wasm_module_t +wasm_runtime_find_module_registered(const char *module_name); +#endif /* WASM_ENABLE_MULTI_MODULE */ + /** * Load a WASM module from a specified byte buffer. The byte buffer can be * WASM binary data when interpreter or JIT is enabled, or AOT binary data @@ -348,7 +398,9 @@ wasm_application_execute_main(wasm_module_inst_t module_inst, * and execute that function. * * @param module_inst the WASM module instance - * @param name the name of the function to execute + * @param name the name of the function to execute. + * to indicate the module name via: $module_name$function_name + * or just a function name: function_name * @param argc the number of arguments * @param argv the arguments array * diff --git a/core/iwasm/interpreter/wasm.h b/core/iwasm/interpreter/wasm.h index 96ed3954a..b54d09aa3 100644 --- a/core/iwasm/interpreter/wasm.h +++ b/core/iwasm/interpreter/wasm.h @@ -22,6 +22,8 @@ extern "C" { #define VALUE_TYPE_VOID 0x40 /* Used by AOT */ #define VALUE_TYPE_I1 0x41 +/* Used by loader to represent any type of i32/i64/f32/f64 */ +#define VALUE_TYPE_ANY 0x42 /* Table Element Type */ #define TABLE_ELEM_TYPE_ANY_FUNC 0x70 @@ -50,6 +52,9 @@ extern "C" { #define SECTION_TYPE_ELEM 9 #define SECTION_TYPE_CODE 10 #define SECTION_TYPE_DATA 11 +#if WASM_ENABLE_BULK_MEMORY != 0 +#define SECTION_TYPE_DATACOUNT 12 +#endif #define IMPORT_KIND_FUNC 0 #define IMPORT_KIND_TABLE 1 @@ -66,6 +71,10 @@ extern "C" { #define BLOCK_TYPE_IF 2 #define BLOCK_TYPE_FUNCTION 3 +typedef struct WASMModule WASMModule; +typedef struct WASMFunction WASMFunction; +typedef struct WASMGlobal WASMGlobal; + typedef union WASMValue { int32 i32; uint32 u32; @@ -119,6 +128,10 @@ typedef struct WASMTableImport { uint32 init_size; /* specified if (flags & 1), else it is 0x10000 */ uint32 max_size; +#if WASM_ENABLE_MULTI_MODULE != 0 + WASMModule *import_module; + WASMTable *import_table_linked; +#endif } WASMTableImport; typedef struct WASMMemoryImport { @@ -128,6 +141,10 @@ typedef struct WASMMemoryImport { uint32 num_bytes_per_page; uint32 init_page_count; uint32 max_page_count; +#if WASM_ENABLE_MULTI_MODULE != 0 + WASMModule *import_module; + WASMMemory *import_memory_linked; +#endif } WASMMemoryImport; typedef struct WASMFunctionImport { @@ -135,13 +152,17 @@ typedef struct WASMFunctionImport { char *field_name; /* function type */ WASMType *func_type; - /* function pointer after linked */ + /* native function pointer after linked */ void *func_ptr_linked; /* signature from registered native symbols */ const char *signature; /* attachment */ void *attachment; bool call_conv_raw; +#if WASM_ENABLE_MULTI_MODULE != 0 + WASMModule *import_module; + WASMFunction *import_func_linked; +#endif } WASMFunctionImport; typedef struct WASMGlobalImport { @@ -151,6 +172,12 @@ typedef struct WASMGlobalImport { bool is_mutable; /* global data after linked */ WASMValue global_data_linked; +#if WASM_ENABLE_MULTI_MODULE != 0 + /* imported function pointer after linked */ + // TODO: remove if not necessary + WASMModule *import_module; + WASMGlobal *import_global_linked; +#endif } WASMGlobalImport; typedef struct WASMImport { @@ -223,6 +250,9 @@ typedef struct WASMDataSeg { uint32 memory_index; InitializerExpression base_offset; uint32 data_length; +#if WASM_ENABLE_BULK_MEMORY != 0 + bool is_passive; +#endif uint8 *data; } WASMDataSeg; @@ -266,7 +296,12 @@ typedef struct WASMModule { uint32 global_count; uint32 export_count; uint32 table_seg_count; + /* data seg count read from data segment section */ uint32 data_seg_count; +#if WASM_ENABLE_BULK_MEMORY != 0 + /* data count read from datacount section */ + uint32 data_seg_count1; +#endif uint32 import_function_count; uint32 import_table_count; @@ -308,6 +343,12 @@ typedef struct WASMModule { WASIArguments wasi_args; bool is_wasi_module; #endif + +#if WASM_ENABLE_MULTI_MODULE != 0 + // TODO: mutex ? mutli-threads ? + bh_list import_module_list_head; + bh_list *import_module_list; +#endif } WASMModule; typedef struct WASMBranchBlock { @@ -430,5 +471,4 @@ wasm_type_equal(const WASMType *type1, const WASMType *type2) } /* end of extern "C" */ #endif -#endif /* end of _WASM_H_ */ - +#endif /* end of _WASM_H_ */ \ No newline at end of file diff --git a/core/iwasm/interpreter/wasm_interp_classic.c b/core/iwasm/interpreter/wasm_interp_classic.c index 54fb7ccb2..56e95fce5 100644 --- a/core/iwasm/interpreter/wasm_interp_classic.c +++ b/core/iwasm/interpreter/wasm_interp_classic.c @@ -236,6 +236,15 @@ LOAD_I16(void *addr) goto out_of_bounds; \ } while (0) +#define CHECK_BULK_MEMORY_OVERFLOW(start, bytes, maddr) do { \ + uint64 offset1 = (int32)(start); \ + if (offset1 + bytes <= linear_mem_size) \ + /* App heap space is not valid space for bulk memory operation */ \ + maddr = memory->memory_data + offset1; \ + else \ + goto out_of_bounds; \ + } while (0) + static inline uint32 rotl32(uint32 n, uint32 c) { @@ -877,6 +886,59 @@ wasm_interp_call_func_native(WASMModuleInstance *module_inst, wasm_exec_env_set_cur_frame(exec_env, prev_frame); } +#if WASM_ENABLE_MULTI_MODULE != 0 +static void +wasm_interp_call_func_bytecode(WASMModuleInstance *module, + WASMExecEnv *exec_env, + WASMFunctionInstance *cur_func, + WASMInterpFrame *prev_frame); + +static void +wasm_interp_call_func_import(WASMModuleInstance *module_inst, + WASMExecEnv *exec_env, + WASMFunctionInstance *cur_func, + WASMInterpFrame *prev_frame) +{ + WASMModuleInstance *sub_module_inst = cur_func->import_module_inst; + WASMFunctionInstance *sub_func_inst = cur_func->import_func_inst; + WASMFunctionImport *func_import = cur_func->u.func_import; + uint8 *ip = prev_frame->ip; + char buf[128]; + + if (!sub_func_inst) { + snprintf(buf, sizeof(buf), + "fail to call unlinked import function (%s, %s)", + func_import->module_name, func_import->field_name); + wasm_set_exception(module_inst, buf); + return; + } + + /* set ip NULL to make call_func_bytecode return after executing + this function */ + prev_frame->ip = NULL; + + /* replace exec_env's module_inst with sub_module_inst so we can + call it */ + exec_env->module_inst = (WASMModuleInstanceCommon *)sub_module_inst; + + /* call function of sub-module*/ + wasm_interp_call_func_bytecode(sub_module_inst, exec_env, + sub_func_inst, prev_frame); + + /* restore ip and module_inst */ + prev_frame->ip = ip; + exec_env->module_inst = (WASMModuleInstanceCommon *)module_inst; + + /* transfer exception if it is thrown */ + if (wasm_get_exception(sub_module_inst)) { + bh_memcpy_s(module_inst->cur_exception, + sizeof(module_inst->cur_exception), + sub_module_inst->cur_exception, + sizeof(sub_module_inst->cur_exception)); + } +} +#endif + #if WASM_ENABLE_LABELS_AS_VALUES != 0 #define HANDLE_OP(opcode) HANDLE_##opcode @@ -902,6 +964,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, uint32 total_mem_size = memory ? num_bytes_per_page * memory->cur_page_count - heap_base_offset : 0; uint8 *global_data = module->global_data; +#if WASM_ENABLE_BULK_MEMORY != 0 + uint32 linear_mem_size = memory ? num_bytes_per_page * memory->cur_page_count : 0; +#endif WASMTableInstance *table = module->default_table; WASMGlobalInstance *globals = module->globals; uint8 opcode_IMPDEP = WASM_OP_IMPDEP; @@ -1086,14 +1151,27 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP (WASM_OP_CALL): read_leb_uint32(frame_ip, frame_ip_end, fidx); - bh_assert(fidx < module->function_count); +#if WASM_ENABLE_MULTI_MODULE != 0 + if (fidx >= module->function_count) { + wasm_set_exception(module, "unknown function"); + goto got_exception; + } +#endif + cur_func = module->functions + fidx; goto call_func_from_interp; HANDLE_OP (WASM_OP_CALL_INDIRECT): { WASMType *cur_type, *cur_func_type; + WASMTableInstance *cur_table_inst; + /** + * type check. compiler will make sure all like + * (call_indirect (type $x) (i32.const 1)) + * the function type has to be defined in the module also + * no matter it is used or not + */ read_leb_uint32(frame_ip, frame_ip_end, tidx); if (tidx >= module->module->type_count) { wasm_set_exception(module, "type index is overflow"); @@ -1105,27 +1183,48 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, frame_ip++; val = POP_I32(); - if (val < 0 || val >= (int32)table->cur_size) { + /* careful, it might be a table in another module */ + cur_table_inst = table; +#if WASM_ENABLE_MULTI_MODULE != 0 + if (table->table_inst_linked) { + cur_table_inst = table->table_inst_linked; + } +#endif + + if (val < 0 || val >= (int32)cur_table_inst->cur_size) { wasm_set_exception(module, "undefined element"); goto got_exception; } - fidx = ((uint32*)table->base_addr)[val]; + fidx = ((uint32*)cur_table_inst->base_addr)[val]; if (fidx == (uint32)-1) { wasm_set_exception(module, "uninitialized element"); goto got_exception; } +#if WASM_ENABLE_MULTI_MODULE != 0 + if (fidx >= module->function_count) { + wasm_set_exception(module, "unknown function"); + goto got_exception; + } +#endif + + /* always call module own functions */ cur_func = module->functions + fidx; - if (cur_func->is_import_func) - cur_func_type = cur_func->u.func_import->func_type; + if (cur_func->is_import_func +#if WASM_ENABLE_MULTI_MODULE != 0 + && !cur_func->import_func_inst +#endif + ) + cur_func_type = cur_func->u.func_import->func_type; else cur_func_type = cur_func->u.func->func_type; if (!wasm_type_equal(cur_type, cur_func_type)) { wasm_set_exception(module, "indirect call type mismatch"); goto got_exception; } + goto call_func_from_interp; } @@ -1264,7 +1363,14 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, bh_assert(global_idx < module->global_count); global = globals + global_idx; - global_addr = global_data + global->data_offset; + global_addr = +#if WASM_ENABLE_MULTI_MODULE != 0 + global->import_global_inst + ? global->import_module_inst->global_data + + global->import_global_inst->data_offset + : +#endif + global_data + global->data_offset; switch (global->type) { case VALUE_TYPE_I32: @@ -1289,7 +1395,14 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, bh_assert(global_idx < module->global_count); global = globals + global_idx; - global_addr = global_data + global->data_offset; + global_addr = +#if WASM_ENABLE_MULTI_MODULE != 0 + global->import_global_inst + ? global->import_module_inst->global_data + + global->import_global_inst->data_offset + : +#endif + global_data + global->data_offset; switch (global->type) { case VALUE_TYPE_I32: @@ -1521,6 +1634,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, memory = module->default_memory; total_mem_size = num_bytes_per_page * memory->cur_page_count - heap_base_offset; +#if WASM_ENABLE_BULK_MEMORY != 0 + linear_mem_size = num_bytes_per_page * memory->cur_page_count; +#endif } (void)reserved; @@ -2357,6 +2473,78 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, DEF_OP_TRUNC_SAT_F64(-1.0f, 18446744073709551616.0, false, false); break; +#if WASM_ENABLE_BULK_MEMORY != 0 + case WASM_OP_MEMORY_INIT: + { + uint32 addr, segment; + uint64 bytes, offset, seg_len; + uint8* data; + + read_leb_uint32(frame_ip, frame_ip_end, segment); + /* skip memory index */ + frame_ip++; + + bytes = (uint64)(uint32)POP_I32(); + offset = (uint64)(uint32)POP_I32(); + addr = (uint32)POP_I32(); + + CHECK_BULK_MEMORY_OVERFLOW(addr, bytes, maddr); + + seg_len = (uint64)module->module->data_segments[segment]->data_length; + data = module->module->data_segments[segment]->data; + if (offset + bytes > seg_len) + goto out_of_bounds; + + bh_memcpy_s(maddr, linear_mem_size - addr, + data + offset, bytes); + break; + } + case WASM_OP_DATA_DROP: + { + uint32 segment; + + read_leb_uint32(frame_ip, frame_ip_end, segment); + module->module->data_segments[segment]->data_length = 0; + + break; + } + case WASM_OP_MEMORY_COPY: + { + uint32 dst, src, len; + uint8 *mdst, *msrc; + + frame_ip += 2; + + len = POP_I32(); + src = POP_I32(); + dst = POP_I32(); + + CHECK_BULK_MEMORY_OVERFLOW(src, len, msrc); + CHECK_BULK_MEMORY_OVERFLOW(dst, len, mdst); + + /* allowing the destination and source to overlap */ + bh_memmove_s(mdst, linear_mem_size - dst, + msrc, len); + + break; + } + case WASM_OP_MEMORY_FILL: + { + uint32 dst, len; + uint8 val, *mdst; + frame_ip++; + + len = POP_I32(); + val = POP_I32(); + dst = POP_I32(); + + CHECK_BULK_MEMORY_OVERFLOW(dst, len, mdst); + + memset(mdst, val, len); + + break; + } +#endif /* WASM_ENABLE_BULK_MEMORY */ default: wasm_set_exception(module, "WASM interp failed: unsupported opcode."); goto got_exception; @@ -2430,14 +2618,25 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, call_func_from_entry: { if (cur_func->is_import_func) { - wasm_interp_call_func_native(module, exec_env, cur_func, prev_frame); - prev_frame = frame->prev_frame; - cur_func = frame->function; - UPDATE_ALL_FROM_FRAME(); +#if WASM_ENABLE_MULTI_MODULE != 0 + if (cur_func->import_func_inst) { + wasm_interp_call_func_import(module, exec_env, cur_func, + prev_frame); + } + else +#endif + { + wasm_interp_call_func_native(module, exec_env, cur_func, + prev_frame); + } - memory = module->default_memory; - if (wasm_get_exception(module)) - goto got_exception; + prev_frame = frame->prev_frame; + cur_func = frame->function; + UPDATE_ALL_FROM_FRAME(); + + memory = module->default_memory; + if (wasm_get_exception(module)) + goto got_exception; } else { WASMFunction *cur_wasm_func = cur_func->u.func; @@ -2521,6 +2720,7 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMFunctionInstance *function, uint32 argc, uint32 argv[]) { + // TODO: since module_inst = exec_env->module_inst, shall we remove the 1st arg? WASMRuntimeFrame *prev_frame = wasm_exec_env_get_cur_frame(exec_env); WASMInterpFrame *frame, *outs_area; @@ -2559,15 +2759,44 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, wasm_exec_env_set_cur_frame(exec_env, frame); - if (function->is_import_func) - wasm_interp_call_func_native(module_inst, exec_env, function, frame); - else + if (function->is_import_func) { +#if WASM_ENABLE_MULTI_MODULE != 0 + if (function->import_module_inst) { + LOG_DEBUG("it is a function of a sub module"); + wasm_interp_call_func_import(module_inst, + exec_env, + function, + frame); + } + else +#endif + { + LOG_DEBUG("it is an native function"); + /* it is a native function */ + wasm_interp_call_func_native(module_inst, + exec_env, + function, + frame); + } + } + else { + LOG_DEBUG("it is a function of the module itself"); wasm_interp_call_func_bytecode(module_inst, exec_env, function, frame); + } /* Output the return value to the caller */ if (!wasm_get_exception(module_inst)) { - for (i = 0; i < function->ret_cell_num; i++) + for (i = 0; i < function->ret_cell_num; i++) { argv[i] = *(frame->sp + i - function->ret_cell_num); + } + + if (function->ret_cell_num) { + LOG_DEBUG("first return value argv[0]=%d", argv[0]); + } else { + LOG_DEBUG("no return value"); + } + } else { + LOG_DEBUG("meet an exception %s", wasm_get_exception(module_inst)); } wasm_exec_env_set_cur_frame(exec_env, prev_frame); diff --git a/core/iwasm/interpreter/wasm_interp_fast.c b/core/iwasm/interpreter/wasm_interp_fast.c index 60a04dc50..02d0ee573 100644 --- a/core/iwasm/interpreter/wasm_interp_fast.c +++ b/core/iwasm/interpreter/wasm_interp_fast.c @@ -238,6 +238,15 @@ LOAD_I16(void *addr) goto out_of_bounds; \ } while (0) +#define CHECK_BULK_MEMORY_OVERFLOW(start, bytes, maddr) do { \ + uint64 offset1 = (int32)(start); \ + if (offset1 + bytes <= linear_mem_size) \ + /* App heap space is not valid space for bulk memory operation */ \ + maddr = memory->memory_data + offset1; \ + else \ + goto out_of_bounds; \ + } while (0) + static inline uint32 rotl32(uint32 n, uint32 c) { @@ -815,6 +824,59 @@ wasm_interp_call_func_native(WASMModuleInstance *module_inst, wasm_exec_env_set_cur_frame(exec_env, prev_frame); } +#if WASM_ENABLE_MULTI_MODULE != 0 +static void +wasm_interp_call_func_bytecode(WASMModuleInstance *module, + WASMExecEnv *exec_env, + WASMFunctionInstance *cur_func, + WASMInterpFrame *prev_frame); + +static void +wasm_interp_call_func_import(WASMModuleInstance *module_inst, + WASMExecEnv *exec_env, + WASMFunctionInstance *cur_func, + WASMInterpFrame *prev_frame) +{ + WASMModuleInstance *sub_module_inst = cur_func->import_module_inst; + WASMFunctionInstance *sub_func_inst = cur_func->import_func_inst; + WASMFunctionImport *func_import = cur_func->u.func_import; + uint8 *ip = prev_frame->ip; + char buf[128]; + + if (!sub_func_inst) { + snprintf(buf, sizeof(buf), + "fail to call unlinked import function (%s, %s)", + func_import->module_name, func_import->field_name); + wasm_set_exception(module_inst, buf); + return; + } + + /* set ip NULL to make call_func_bytecode return after executing + this function */ + prev_frame->ip = NULL; + + /* replace exec_env's module_inst with sub_module_inst so we can + call it */ + exec_env->module_inst = (WASMModuleInstanceCommon *)sub_module_inst; + + /* call function of sub-module*/ + wasm_interp_call_func_bytecode(sub_module_inst, exec_env, + sub_func_inst, prev_frame); + + /* restore ip and module_inst */ + prev_frame->ip = ip; + exec_env->module_inst = (WASMModuleInstanceCommon *)module_inst; + + /* transfer exception if it is thrown */ + if (wasm_get_exception(sub_module_inst)) { + bh_memcpy_s(module_inst->cur_exception, + sizeof(module_inst->cur_exception), + sub_module_inst->cur_exception, + sizeof(sub_module_inst->cur_exception)); + } +} +#endif + #if WASM_ENABLE_OPCODE_COUNTER != 0 typedef struct OpcodeInfo { char *name; @@ -894,6 +956,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, uint32 total_mem_size = memory ? num_bytes_per_page * memory->cur_page_count - heap_base_offset : 0; uint8 *global_data = module->global_data; +#if WASM_ENABLE_BULK_MEMORY != 0 + uint32 linear_mem_size = memory ? num_bytes_per_page * memory->cur_page_count : 0; +#endif WASMTableInstance *table = module->default_table; WASMGlobalInstance *globals = module->globals; uint8 opcode_IMPDEP = WASM_OP_IMPDEP; @@ -997,6 +1062,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP (WASM_OP_CALL_INDIRECT): { WASMType *cur_type, *cur_func_type; + WASMTableInstance *cur_table_inst; tidx = GET_OPERAND(int32, 0); val = GET_OPERAND(int32, 2); @@ -1008,21 +1074,41 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, } cur_type = module->module->types[tidx]; - if (val < 0 || val >= (int32)table->cur_size) { + /* careful, it might be a table in another module */ + cur_table_inst = table; +#if WASM_ENABLE_MULTI_MODULE != 0 + if (table->table_inst_linked) { + cur_table_inst = table->table_inst_linked; + } +#endif + + if (val < 0 || val >= (int32)cur_table_inst->cur_size) { wasm_set_exception(module, "undefined element"); goto got_exception; } - fidx = ((uint32*)table->base_addr)[val]; + fidx = ((uint32*)cur_table_inst->base_addr)[val]; if (fidx == (uint32)-1) { wasm_set_exception(module, "uninitialized element"); goto got_exception; } +#if WASM_ENABLE_MULTI_MODULE != 0 + if (fidx >= module->function_count) { + wasm_set_exception(module, "unknown function"); + goto got_exception; + } +#endif + + /* always call module own functions */ cur_func = module->functions + fidx; - if (cur_func->is_import_func) - cur_func_type = cur_func->u.func_import->func_type; + if (cur_func->is_import_func +#if WASM_ENABLE_MULTI_MODULE != 0 + && !cur_func->import_func_inst +#endif + ) + cur_func_type = cur_func->u.func_import->func_type; else cur_func_type = cur_func->u.func->func_type; if (!wasm_type_equal(cur_type, cur_func_type)) { @@ -1115,7 +1201,14 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, bh_assert(global_idx < module->global_count); global = globals + global_idx; - global_addr = global_data + global->data_offset; + global_addr = +#if WASM_ENABLE_MULTI_MODULE != 0 + global->import_global_inst + ? global->import_module_inst->global_data + + global->import_global_inst->data_offset + : +#endif + global_data + global->data_offset; switch (global->type) { case VALUE_TYPE_I32: @@ -1141,7 +1234,14 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, bh_assert(global_idx < module->global_count); global = globals + global_idx; - global_addr = global_data + global->data_offset; + global_addr = +#if WASM_ENABLE_MULTI_MODULE != 0 + global->import_global_inst + ? global->import_module_inst->global_data + + global->import_global_inst->data_offset + : +#endif + global_data + global->data_offset; switch (global->type) { case VALUE_TYPE_I32: @@ -1429,6 +1529,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, memory = module->default_memory; total_mem_size = num_bytes_per_page * memory->cur_page_count - heap_base_offset; +#if WASM_ENABLE_BULK_MEMORY != 0 + linear_mem_size = num_bytes_per_page * memory->cur_page_count; +#endif } (void)reserved; @@ -2295,6 +2398,76 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, DEF_OP_TRUNC_SAT_F64(-1.0, 18446744073709551616.0, false, false); break; +#if WASM_ENABLE_BULK_MEMORY != 0 + case WASM_OP_MEMORY_INIT: + { + uint32 addr, segment; + uint64 bytes, offset, seg_len; + uint8* data; + + segment = GET_OPERAND(uint32, 0); + frame_ip += 2; + + bytes = (uint64)POP_I32(); + offset = (uint64)POP_I32(); + addr = POP_I32(); + + CHECK_BULK_MEMORY_OVERFLOW(addr, bytes, maddr); + + seg_len = (uint64)module->module->data_segments[segment]->data_length; + data = module->module->data_segments[segment]->data; + if (offset + bytes > seg_len) + goto out_of_bounds; + + bh_memcpy_s(maddr, linear_mem_size - addr, + data + offset, bytes); + break; + } + case WASM_OP_DATA_DROP: + { + uint32 segment; + + segment = GET_OPERAND(uint32, 0); + frame_ip += 2; + + module->module->data_segments[segment]->data_length = 0; + + break; + } + case WASM_OP_MEMORY_COPY: + { + uint32 dst, src, len; + uint8 *mdst, *msrc; + + len = POP_I32(); + src = POP_I32(); + dst = POP_I32(); + + CHECK_BULK_MEMORY_OVERFLOW(src, len, msrc); + CHECK_BULK_MEMORY_OVERFLOW(dst, len, mdst); + + /* allowing the destination and source to overlap */ + bh_memmove_s(mdst, linear_mem_size - dst, + msrc, len); + + break; + } + case WASM_OP_MEMORY_FILL: + { + uint32 dst, len; + uint8 val, *mdst; + + len = POP_I32(); + val = POP_I32(); + dst = POP_I32(); + + CHECK_BULK_MEMORY_OVERFLOW(dst, len, mdst); + + memset(mdst, val, len); + + break; + } +#endif /* WASM_ENABLE_BULK_MEMORY */ default: wasm_set_exception(module, "WASM interp failed: unsupported opcode."); goto got_exception; @@ -2310,7 +2483,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP (WASM_OP_CALL): fidx = frame_lp[GET_OFFSET()]; - bh_assert(fidx < module->function_count); +#if WASM_ENABLE_MULTI_MODULE != 0 + if (fidx >= module->function_count) { + wasm_set_exception(module, "unknown function"); + goto got_exception; + } +#endif cur_func = module->functions + fidx; goto call_func_from_interp; @@ -2383,7 +2561,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, GET_OPERAND(int64, (2 * (cur_func->param_count - i - 1))); outs_area->lp += 2; } else { - *(outs_area->lp) = GET_OPERAND(int32, (2 * (cur_func->param_count - i - 1)));; + *(outs_area->lp) = GET_OPERAND(int32, (2 * (cur_func->param_count - i - 1))); outs_area->lp ++; } } @@ -2397,14 +2575,25 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, call_func_from_entry: { if (cur_func->is_import_func) { - wasm_interp_call_func_native(module, exec_env, cur_func, prev_frame); - prev_frame = frame->prev_frame; - cur_func = frame->function; - UPDATE_ALL_FROM_FRAME(); +#if WASM_ENABLE_MULTI_MODULE != 0 + if (cur_func->import_func_inst) { + wasm_interp_call_func_import(module, exec_env, cur_func, + prev_frame); + } + else +#endif + { + wasm_interp_call_func_native(module, exec_env, cur_func, + prev_frame); + } - memory = module->default_memory; - if (wasm_get_exception(module)) - goto got_exception; + prev_frame = frame->prev_frame; + cur_func = frame->function; + UPDATE_ALL_FROM_FRAME(); + + memory = module->default_memory; + if (wasm_get_exception(module)) + goto got_exception; } else { WASMFunction *cur_wasm_func = cur_func->u.func; @@ -2528,10 +2717,28 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, wasm_exec_env_set_cur_frame(exec_env, frame); - if (function->is_import_func) - wasm_interp_call_func_native(module_inst, exec_env, function, frame); - else + if (function->is_import_func) { +#if WASM_ENABLE_MULTI_MODULE != 0 + if (function->import_module_inst) { + LOG_DEBUG("it is a function of a sub module"); + wasm_interp_call_func_import(module_inst, + exec_env, + function, + frame); + } + else +#endif + { + LOG_DEBUG("it is an native function"); + wasm_interp_call_func_native(module_inst, + exec_env, + function, + frame); + } + } + else { wasm_interp_call_func_bytecode(module_inst, exec_env, function, frame); + } /* Output the return value to the caller */ if (!wasm_get_exception(module_inst)) { diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index 16a5c7674..b8f4f6933 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -251,8 +251,10 @@ const_str_list_insert(const uint8 *str, uint32 len, WASMModule *module, node = node_next; } - if (node) + if (node) { + LOG_DEBUG("reuse %s", node->str); return node->str; + } if (!(node = wasm_runtime_malloc(sizeof(StringNode) + len + 1))) { set_error_buf(error_buf, error_buf_size, @@ -427,6 +429,338 @@ load_type_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, return true; } +#if WASM_ENABLE_MULTI_MODULE != 0 +/** + * Find export item of a module with export info: + * module name, field name and export kind + */ +static WASMExport * +wasm_loader_find_export(const WASMModule *module, + const char *module_name, + const char *field_name, + uint8 export_kind, + uint32 export_index_boundary, + char *error_buf, uint32 error_buf_size) +{ + WASMExport *export; + uint32 i; + + for (i = 0, export = module->exports; i < module->export_count; + ++i, ++export) { + /** + * need to consider a scenario that different kinds of exports + * may have the same name, like + * (table (export "m1" "exported") 10 funcref) + * (memory (export "m1" "exported") 10) + **/ + if (export->kind == export_kind && !strcmp(field_name, export->name)) { + break; + } + } + + if (i == module->export_count) { + LOG_DEBUG("can not find an export %d named %s in the module %s", + export_kind, field_name, module_name); + set_error_buf_v(error_buf, error_buf_size, + "unknown import or incompatible import type"); + return NULL; + } + + if (export->index >= export_index_boundary) { + LOG_DEBUG("%s in the module %s is out of index (%d >= %d )", + field_name, module_name, + export->index, export_index_boundary); + set_error_buf_v(error_buf, error_buf_size, "incompatible import type"); + return NULL; + } + + return export; +} + +static WASMFunction * +wasm_loader_resolve_function(const char *module_name, + const char *function_name, + const WASMType *expected_function_type, + char *error_buf, uint32 error_buf_size) +{ + WASMModuleCommon *module_reg; + WASMFunction *function = NULL; + WASMExport *export = NULL; + WASMModule *module = NULL; + WASMType *target_function_type = NULL; + + module_reg = wasm_runtime_find_module_registered(module_name); + if (!module_reg + || module_reg->module_type != Wasm_Module_Bytecode) { + LOG_DEBUG("can not find a module named %s for function", module_name); + set_error_buf_v(error_buf, error_buf_size, "unknown import"); + return NULL; + } + + module = (WASMModule *)module_reg; + export = wasm_loader_find_export(module, module_name, function_name, + EXPORT_KIND_FUNC, + module->import_function_count + + module->function_count, + error_buf, error_buf_size); + if (!export) { + return NULL; + } + + /* run a function type check */ + if (export->index < module->import_function_count) { + target_function_type = + module->import_functions[export->index].u.function.func_type; + function = module->import_functions[export->index] + .u.function.import_func_linked; + } + else { + target_function_type = + module->functions[export->index - module->import_function_count] + ->func_type; + function = + module->functions[export->index - module->import_function_count]; + } + + if (!wasm_type_equal(expected_function_type, target_function_type)) { + LOG_DEBUG("%s.%s failed the type check", module_name, function_name); + set_error_buf_v(error_buf, error_buf_size, "incompatible import type"); + return NULL; + } + + return function; +} + +static WASMTable * +wasm_loader_resolve_table(const char *module_name, const char *table_name, + uint32 init_size, uint32 max_size, + char *error_buf, uint32 error_buf_size) +{ + WASMModuleCommon *module_reg; + WASMTable *table = NULL; + WASMExport *export = NULL; + WASMModule *module = NULL; + + module_reg = wasm_runtime_find_module_registered(module_name); + if (!module_reg + || module_reg->module_type != Wasm_Module_Bytecode) { + LOG_DEBUG("can not find a module named %s for table", module_name); + set_error_buf_v(error_buf, error_buf_size, "unknown import"); + return NULL; + } + + module = (WASMModule *)module_reg; + export = wasm_loader_find_export(module, module_name, table_name, + EXPORT_KIND_TABLE, + module->table_count + + module->import_table_count, + error_buf, error_buf_size); + if (!export) { + return NULL; + } + + /* run a table type check */ + if (export->index < module->import_table_count) { + table = + module->import_tables[export->index].u.table.import_table_linked; + } + else { + table = &(module->tables[export->index - module->import_table_count]); + } + if (table->init_size < init_size || table->max_size > max_size) { + LOG_DEBUG("%s,%s failed type check(%d-%d), expected(%d-%d)", + module_name, table_name, table->init_size, table->max_size, + init_size, max_size); + set_error_buf_v(error_buf, error_buf_size, "incompatible import type"); + return NULL; + } + + return table; +} + +static WASMMemory * +wasm_loader_resolve_memory(const char *module_name, const char *memory_name, + uint32 init_page_count, uint32 max_page_count, + char *error_buf, uint32 error_buf_size) +{ + WASMModuleCommon *module_reg; + WASMMemory *memory = NULL; + WASMExport *export = NULL; + WASMModule *module = NULL; + + module_reg = wasm_runtime_find_module_registered(module_name); + if (!module_reg + || module_reg->module_type != Wasm_Module_Bytecode) { + LOG_DEBUG("can not find a module named %s for memory", module_name); + set_error_buf_v(error_buf, error_buf_size, "unknown import"); + return NULL; + } + + module = (WASMModule *)module_reg; + export = wasm_loader_find_export(module, module_name, memory_name, + EXPORT_KIND_MEMORY, + module->import_memory_count + + module->memory_count, + error_buf, error_buf_size); + if (!export) { + return NULL; + } + + + /* run a memory check */ + if (export->index < module->import_memory_count) { + memory = + module->import_memories[export->index].u.memory.import_memory_linked; + } + else { + memory = + &(module->memories[export->index - module->import_memory_count]); + } + if (memory->init_page_count < init_page_count || + memory->max_page_count > max_page_count) { + LOG_DEBUG("%s,%s failed type check(%d-%d), expected(%d-%d)", + module_name, memory_name, memory->init_page_count, + memory->max_page_count, init_page_count, max_page_count); + set_error_buf_v(error_buf, error_buf_size, "incompatible import type"); + return NULL; + } + return memory; +} + +static WASMGlobal * +wasm_loader_resolve_global(const char *module_name, + const char *global_name, + uint8 type, bool is_mutable, + char *error_buf, uint32 error_buf_size) +{ + WASMModuleCommon *module_reg; + WASMGlobal *global = NULL; + WASMExport *export = NULL; + WASMModule *module = NULL; + + module_reg = wasm_runtime_find_module_registered(module_name); + if (!module_reg + || module_reg->module_type != Wasm_Module_Bytecode) { + LOG_DEBUG("can not find a module named %s for global", module_name); + set_error_buf_v(error_buf, error_buf_size, "unknown import"); + return NULL; + } + + module = (WASMModule *)module_reg; + export = wasm_loader_find_export(module, module_name, global_name, + EXPORT_KIND_GLOBAL, + module->import_global_count + + module->global_count, + error_buf, error_buf_size); + if (!export) { + return NULL; + } + + /* run a global check */ + if (export->index < module->import_global_count) { + global = + module->import_globals[export->index].u.global.import_global_linked; + } else { + global = + &(module->globals[export->index - module->import_global_count]); + } + if (global->type != type || global->is_mutable != is_mutable) { + LOG_DEBUG("%s,%s failed type check(%d, %d), expected(%d, %d)", + module_name, global_name, global->type, global->is_mutable, + type, is_mutable); + set_error_buf_v(error_buf, error_buf_size, "incompatible import type"); + return NULL; + } + return global; +} +#endif /* end of WASM_ENABLE_MULTI_MODULE */ + +static bool +load_function_import(const WASMModule *parent_module, WASMModule *sub_module, + char *sub_module_name, char *function_name, + const uint8 **p_buf, const uint8 *buf_end, + WASMFunctionImport *function, + char *error_buf, uint32 error_buf_size) +{ + const uint8 *p = *p_buf, *p_end = buf_end; + uint32 declare_type_index = 0; + WASMType *declare_func_type = NULL; + WASMFunction *linked_func = NULL; + const char *linked_signature = NULL; + void *linked_attachment = NULL; + bool linked_call_conv_raw = false; + bool is_built_in_module = false; + + CHECK_BUF(p, p_end, 1); + read_leb_uint32(p, p_end, declare_type_index); + *p_buf = p; + + if (declare_type_index >= parent_module->type_count) { + set_error_buf(error_buf, error_buf_size, + "Load import section failed: unknown type."); + LOG_DEBUG("the type index is out of range"); + return false; + } + + declare_func_type = parent_module->types[declare_type_index]; + + is_built_in_module = wasm_runtime_is_built_in_module(sub_module_name); + if (is_built_in_module) { + LOG_DEBUG("%s is a function of a built-in module %s", + function_name, + sub_module_name); + /* check built-in modules */ + linked_func = wasm_native_resolve_symbol(sub_module_name, + function_name, + declare_func_type, + &linked_signature, + &linked_attachment, + &linked_call_conv_raw); + } +#if WASM_ENABLE_MULTI_MODULE != 0 + else { + LOG_DEBUG("%s is a function of a sub-module %s", + function_name, + sub_module_name); + linked_func = wasm_loader_resolve_function(sub_module_name, + function_name, + declare_func_type, + error_buf, + error_buf_size); + } +#endif + + if (!linked_func) { +#if WASM_ENABLE_SPEC_TEST != 0 + set_error_buf(error_buf, + error_buf_size, + "unknown import or incompatible import type"); + return false; +#else +#if WASM_ENABLE_WAMR_COMPILER == 0 + LOG_WARNING( + "warning: fail to link import function (%s, %s)", + sub_module_name, function_name); +#endif +#endif + } + + function->module_name = sub_module_name; + function->field_name = function_name; + function->func_type = declare_func_type; + /* func_ptr_linked is for built-in functions */ + function->func_ptr_linked = is_built_in_module ? linked_func : NULL; + function->signature = linked_signature; + function->attachment = linked_attachment; + function->call_conv_raw = linked_call_conv_raw; +#if WASM_ENABLE_MULTI_MODULE != 0 + function->import_module = is_built_in_module ? NULL : sub_module; + /* can not set both func_ptr_linked and import_func_linked not NULL */ + function->import_func_linked = is_built_in_module ? NULL : linked_func; +#endif + return true; +} + static bool check_table_max_size(uint32 init_size, uint32 max_size, char *error_buf, uint32 error_buf_size) @@ -440,28 +774,97 @@ check_table_max_size(uint32 init_size, uint32 max_size, } static bool -load_table_import(const uint8 **p_buf, const uint8 *buf_end, - WASMTableImport *table, +load_table_import(WASMModule *sub_module, const char *sub_module_name, + const char *table_name, const uint8 **p_buf, + const uint8 *buf_end, WASMTableImport *table, char *error_buf, uint32 error_buf_size) { const uint8 *p = *p_buf, *p_end = buf_end; + uint32 declare_elem_type = 0; + uint32 declare_max_size_flag = 0; + uint32 declare_init_size = 0; + uint32 declare_max_size = 0; +#if WASM_ENABLE_MULTI_MODULE != 0 + WASMTable *linked_table = NULL; +#endif CHECK_BUF(p, p_end, 1); /* 0x70 */ - table->elem_type = read_uint8(p); - bh_assert(table->elem_type == TABLE_ELEM_TYPE_ANY_FUNC); - read_leb_uint32(p, p_end, table->flags); - read_leb_uint32(p, p_end, table->init_size); - if (table->flags & 1) { - read_leb_uint32(p, p_end, table->max_size); + declare_elem_type = read_uint8(p); + if (TABLE_ELEM_TYPE_ANY_FUNC != declare_elem_type) { + set_error_buf(error_buf, error_buf_size, "incompatible import type"); + return false; + } + + read_leb_uint32(p, p_end, declare_max_size_flag); + read_leb_uint32(p, p_end, declare_init_size); + if (declare_max_size_flag & 1) { + read_leb_uint32(p, p_end, declare_max_size); if (!check_table_max_size(table->init_size, table->max_size, error_buf, error_buf_size)) return false; + } else { + declare_max_size = 0x10000; } - else - table->max_size = 0x10000; - *p_buf = p; + + if ((declare_max_size_flag & 1) && declare_init_size > declare_max_size) { + set_error_buf(error_buf, error_buf_size, + "size minimum must not be greater than maximum"); + return false; + } + +#if WASM_ENABLE_MULTI_MODULE != 0 + if (!wasm_runtime_is_built_in_module(sub_module_name)) { + linked_table = wasm_loader_resolve_table( + sub_module_name, table_name, + declare_init_size, declare_max_size, + error_buf, error_buf_size); + if (!linked_table) { + LOG_DEBUG("(%s, %s) is not an exported from one of modules", + table_name, sub_module_name); + return false; + } + + /** + * reset with linked table limit + */ + declare_elem_type = linked_table->elem_type; + declare_init_size = linked_table->init_size; + declare_max_size = linked_table->max_size; + declare_max_size_flag = linked_table->flags; + table->import_table_linked = linked_table; + table->import_module = sub_module; + } +#endif + + /* (table (export "table") 10 20 funcref) */ + if (!strcmp("spectest", sub_module_name)) { + uint32 spectest_table_init_size = 10; + uint32 spectest_table_max_size = 20; + + if (strcmp("table", table_name)) { + set_error_buf(error_buf, error_buf_size, + "incompatible import type or unknown import"); + return false; + } + + if (declare_init_size > spectest_table_init_size + || declare_max_size < spectest_table_max_size) { + set_error_buf(error_buf, error_buf_size, + "incompatible import type"); + return false; + } + + declare_init_size = spectest_table_init_size; + declare_max_size = spectest_table_max_size; + } + + /* now we believe all declaration are ok */ + table->elem_type = declare_elem_type; + table->init_size = declare_init_size; + table->flags = declare_max_size_flag; + table->max_size = declare_max_size; return true; } @@ -499,8 +902,9 @@ check_memory_max_size(uint32 init_size, uint32 max_size, } static bool -load_memory_import(const uint8 **p_buf, const uint8 *buf_end, - WASMMemoryImport *memory, +load_memory_import(WASMModule *sub_module, const char *sub_module_name, + const char *memory_name, const uint8 **p_buf, + const uint8 *buf_end, WASMMemoryImport *memory, char *error_buf, uint32 error_buf_size) { const uint8 *p = *p_buf, *p_end = buf_end; @@ -510,33 +914,160 @@ load_memory_import(const uint8 **p_buf, const uint8 *buf_end, / DEFAULT_NUM_BYTES_PER_PAGE; #else uint32 max_page_count = pool_size / DEFAULT_NUM_BYTES_PER_PAGE; +#endif /* WASM_ENABLE_APP_FRAMEWORK */ + uint32 declare_max_page_count_flag = 0; + uint32 declare_init_page_count = 0; + uint32 declare_max_page_count = 0; +#if WASM_ENABLE_MULTI_MODULE != 0 + WASMMemory *linked_memory = NULL; #endif - read_leb_uint32(p, p_end, memory->flags); - read_leb_uint32(p, p_end, memory->init_page_count); - if (!check_memory_init_size(memory->init_page_count, - error_buf, error_buf_size)) + read_leb_uint32(p, p_end, declare_max_page_count_flag); + read_leb_uint32(p, p_end, declare_init_page_count); + if (!check_memory_init_size(declare_init_page_count, error_buf, + error_buf_size)) { return false; - - if (memory->flags & 1) { - read_leb_uint32(p, p_end, memory->max_page_count); - if (!check_memory_max_size(memory->init_page_count, - memory->max_page_count, - error_buf, error_buf_size)) - return false; - if (memory->max_page_count > max_page_count) - memory->max_page_count = max_page_count; } - else - /* Limit the maximum memory size to max_page_count */ - memory->max_page_count = max_page_count; + if (declare_max_page_count_flag & 1) { + read_leb_uint32(p, p_end, declare_max_page_count); + if (!check_memory_max_size(declare_init_page_count, + declare_max_page_count, error_buf, + error_buf_size)) { + return false; + } + if (declare_max_page_count > max_page_count) { + declare_max_page_count = max_page_count; + } + } + else { + /* Limit the maximum memory size to max_page_count */ + declare_max_page_count = max_page_count; + } + +#if WASM_ENABLE_MULTI_MODULE != 0 + if (!wasm_runtime_is_built_in_module(sub_module_name)) { + linked_memory = wasm_loader_resolve_memory( + sub_module_name, memory_name, + declare_init_page_count, declare_max_page_count, + error_buf, error_buf_size); + if (!linked_memory) { + return false; + } + + /** + * reset with linked memory limit + */ + memory->import_module = sub_module; + memory->import_memory_linked = linked_memory; + declare_init_page_count = linked_memory->init_page_count; + declare_max_page_count = linked_memory->max_page_count; + } +#endif + + /* (memory (export "memory") 1 2) */ + if (!strcmp("spectest", sub_module_name)) { + uint32 spectest_memory_init_page = 1; + uint32 spectest_memory_max_page = 2; + + if (strcmp("memory", memory_name)) { + set_error_buf(error_buf, error_buf_size, + "incompatible import type or unknown import"); + return false; + } + + if (declare_init_page_count > spectest_memory_init_page + || declare_max_page_count < spectest_memory_max_page) { + set_error_buf(error_buf, error_buf_size, + "incompatible import type"); + return false; + } + + declare_init_page_count = spectest_memory_init_page; + declare_max_page_count = spectest_memory_max_page; + } + + /* now we believe all declaration are ok */ + memory->flags = declare_max_page_count_flag; + memory->init_page_count = declare_init_page_count; + memory->max_page_count = declare_max_page_count; memory->num_bytes_per_page = DEFAULT_NUM_BYTES_PER_PAGE; *p_buf = p; return true; } +static bool +load_global_import(const WASMModule *parent_module, + WASMModule *sub_module, + char *sub_module_name, char *global_name, + const uint8 **p_buf, const uint8 *buf_end, + WASMGlobalImport *global, + char *error_buf, uint32 error_buf_size) +{ + const uint8 *p = *p_buf, *p_end = buf_end; + uint8 declare_type = 0; + uint8 declare_mutable = 0; + bool is_mutable = false; + bool ret = false; + + CHECK_BUF(p, p_end, 2); + declare_type = read_uint8(p); + declare_mutable = read_uint8(p); + *p_buf = p; + + if (declare_mutable >= 2) { + set_error_buf(error_buf, error_buf_size, + "Load import section failed: " + "invalid mutability"); + return false; + } + + is_mutable = declare_mutable & 1 ? true : false; + +#if WASM_ENABLE_LIBC_BUILTIN != 0 + ret = wasm_runtime_is_built_in_module(sub_module_name); + if (ret) { + /* check built-in modules */ + ret = wasm_native_lookup_libc_builtin_global(sub_module_name, + global_name, global); + if (ret) { + LOG_DEBUG("(%s, %s) is a global of a built-in module", + sub_module_name, global_name); + } + } +#endif /* WASM_ENABLE_LIBC_BUILTIN */ + +#if WASM_ENABLE_MULTI_MODULE != 0 + if (!ret) { + /* check sub modules */ + WASMGlobal *linked_global = + wasm_loader_resolve_global(sub_module_name, global_name, + declare_type, declare_mutable, + error_buf, error_buf_size); + if (linked_global) { + LOG_DEBUG("(%s, %s) is a global of external module", + sub_module_name, global_name); + global->import_module = sub_module; + global->import_global_linked = linked_global; + ret = true; + } + } +#endif + + if (!ret) { + set_error_buf_v(error_buf, error_buf_size, + "unknown import or incompatible import type"); + return false; + } + + global->module_name = sub_module_name; + global->field_name = global_name; + global->type = declare_type; + global->is_mutable = is_mutable; + return true; +} + static bool load_table(const uint8 **p_buf, const uint8 *buf_end, WASMTable *table, char *error_buf, uint32 error_buf_size) @@ -546,7 +1077,11 @@ load_table(const uint8 **p_buf, const uint8 *buf_end, WASMTable *table, CHECK_BUF(p, p_end, 1); /* 0x70 */ table->elem_type = read_uint8(p); - bh_assert(table->elem_type == TABLE_ELEM_TYPE_ANY_FUNC); + if (TABLE_ELEM_TYPE_ANY_FUNC != table->elem_type) { + set_error_buf(error_buf, error_buf_size, "incompatible import type"); + return false; + } + read_leb_uint32(p, p_end, table->flags); read_leb_uint32(p, p_end, table->init_size); if (table->flags & 1) { @@ -558,6 +1093,12 @@ load_table(const uint8 **p_buf, const uint8 *buf_end, WASMTable *table, else table->max_size = 0x10000; + if ((table->flags & 1) && table->init_size > table->max_size) { + set_error_buf(error_buf, error_buf_size, + "size minimum must not be greater than maximum"); + return false; + } + *p_buf = p; return true; } @@ -600,6 +1141,174 @@ load_memory(const uint8 **p_buf, const uint8 *buf_end, WASMMemory *memory, return true; } +#if WASM_ENABLE_MULTI_MODULE != 0 +static WASMModule * +search_sub_module(const WASMModule *parent_module, const char *sub_module_name) +{ + WASMRegisteredModule *node = + bh_list_first_elem(parent_module->import_module_list); + while (node && strcmp(sub_module_name, node->module_name)) { + node = bh_list_elem_next(node); + } + return node ? (WASMModule*)node->module : NULL; +} + +static bool +register_sub_module(const WASMModule *parent_module, + const char *sub_module_name, WASMModule *sub_module) +{ + /* register a sub_module on its parent sub module list */ + WASMRegisteredModule *node = NULL; + bh_list_status ret; + + if (search_sub_module(parent_module, sub_module_name)) { + LOG_DEBUG("%s has been registered in its parent", sub_module_name); + return true; + } + + node = wasm_runtime_malloc(sizeof(WASMRegisteredModule)); + if (!node) { + LOG_DEBUG("malloc WASMRegisteredModule failed. SZ %d\n", + sizeof(WASMRegisteredModule)); + return false; + } + + node->module_name = sub_module_name; + node->module = (WASMModuleCommon*)sub_module; + ret = bh_list_insert(parent_module->import_module_list, node); + bh_assert(BH_LIST_SUCCESS == ret); + (void)ret; + return true; +} + +static WASMModule * +load_depended_module(const WASMModule *parent_module, + const char *sub_module_name, char *error_buf, + uint32 error_buf_size) +{ + WASMModule *sub_module = NULL; + bool ret = false; + uint8 *buffer = NULL; + uint32 buffer_size = 0; + const module_reader reader = wasm_runtime_get_module_reader(); + const module_destroyer destroyer = wasm_runtime_get_module_destroyer(); + + /* check the registered module list of the parent */ + sub_module = search_sub_module(parent_module, sub_module_name); + if (sub_module) { + LOG_DEBUG("%s has been loaded before", sub_module_name); + return sub_module; + } + + /* check the global registered module list */ + sub_module = + (WASMModule *)wasm_runtime_find_module_registered(sub_module_name); + if (sub_module) { + LOG_DEBUG("%s has been loaded", sub_module_name); + goto REGISTER_SUB_MODULE; + } + + LOG_VERBOSE("to load %s", sub_module_name); + + if (!reader) { + LOG_DEBUG("error: there is no sub_module reader to load %s", + sub_module_name); + set_error_buf_v(error_buf, error_buf_size, + "error: there is no sub_module reader to load %s", + sub_module_name); + return NULL; + } + + /* start to maintain a loading module list */ + ret = wasm_runtime_is_loading_module(sub_module_name); + if (ret) { + LOG_DEBUG("find a circular dependency on %s", sub_module_name); + set_error_buf_v(error_buf, error_buf_size, + "error: find a circular dependency on %s", + sub_module_name); + return NULL; + } + + ret = wasm_runtime_add_loading_module(sub_module_name, error_buf, + error_buf_size); + if (!ret) { + LOG_DEBUG("can not add %s into loading module list\n", + sub_module_name); + return NULL; + } + + ret = reader(sub_module_name, &buffer, &buffer_size); + if (!ret) { + LOG_DEBUG("read the file of %s failed", sub_module_name); + set_error_buf_v(error_buf, error_buf_size, + "error: can not read the module file of %s", + sub_module_name); + goto DELETE_FROM_LOADING_LIST; + } + + sub_module = + wasm_loader_load(buffer, buffer_size, error_buf, error_buf_size); + if (!sub_module) { + LOG_DEBUG("error: can not load the sub_module %s", sub_module_name); + /* + * others will be destroyed in runtime_destroy() + */ + goto DESTROY_FILE_BUFFER; + } + + wasm_runtime_delete_loading_module(sub_module_name); + + /* register on a global list */ + ret = wasm_runtime_register_module_internal(sub_module_name, + (WASMModuleCommon*)sub_module, + buffer, buffer_size, error_buf, + error_buf_size); + if (!ret) { + LOG_DEBUG("error: can not register module %s globally\n", + sub_module_name); + /* + * others will be unload in runtime_destroy() + */ + goto UNLOAD_MODULE; + } + + /* register on its parent list */ +REGISTER_SUB_MODULE: + ret = register_sub_module(parent_module, sub_module_name, sub_module); + if (!ret) { + LOG_DEBUG("error: can not register a sub module %s with its parent", + sizeof(WASMRegisteredModule)); + set_error_buf_v( + error_buf, error_buf_size, + "error: can not register a sub module %s with its parent", + sizeof(WASMRegisteredModule)); + /* + * since it is in the global module list, there is no need to + * unload the module. the runtime_destroy() will do it + */ + return NULL; + } + + return sub_module; + +UNLOAD_MODULE: + wasm_loader_unload(sub_module); + +DESTROY_FILE_BUFFER: + if (destroyer) { + destroyer(buffer, buffer_size); + } + else { + LOG_WARNING("need to release the reading buffer of %s manually", + sub_module_name); + } + +DELETE_FROM_LOADING_LIST: + wasm_runtime_delete_loading_module(sub_module_name); + return NULL; +} +#endif /* WASM_ENABLE_MULTI_MODULE */ + static bool load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, char *error_buf, uint32 error_buf_size) @@ -610,8 +1319,8 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, WASMImport *import; WASMImport *import_functions = NULL, *import_tables = NULL; WASMImport *import_memories = NULL, *import_globals = NULL; - char *module_name, *field_name; - uint8 mutable, u8, kind; + char *sub_module_name, *field_name; + uint8 u8, kind; read_leb_uint32(p, p_end, import_count); @@ -708,6 +1417,7 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, p = p_old; + // TODO: move it out of the loop /* insert "env", "wasi_unstable" and "wasi_snapshot_preview1" to const str list */ if (!const_str_list_insert((uint8*)"env", 3, module, error_buf, error_buf_size) || !const_str_list_insert((uint8*)"wasi_unstable", 13, module, @@ -719,11 +1429,13 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, /* Scan again to read the data */ for (i = 0; i < import_count; i++) { + WASMModule *sub_module = NULL; + /* load module name */ read_leb_uint32(p, p_end, name_len); CHECK_BUF(p, p_end, name_len); - if (!(module_name = const_str_list_insert - (p, name_len, module, error_buf, error_buf_size))) { + if (!(sub_module_name = const_str_list_insert( + p, name_len, module, error_buf, error_buf_size))) { return false; } p += name_len; @@ -731,12 +1443,31 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, /* load field name */ read_leb_uint32(p, p_end, name_len); CHECK_BUF(p, p_end, name_len); - if (!(field_name = const_str_list_insert - (p, name_len, module, error_buf, error_buf_size))) { + if (!(field_name = const_str_list_insert( + p, name_len, module, error_buf, error_buf_size))) { return false; } p += name_len; + LOG_DEBUG("import #%d: (%s, %s)", i, sub_module_name, field_name); +#if WASM_ENABLE_MULTI_MODULE != 0 + /* assume built-in modules have been loaded */ + if (!wasm_runtime_is_built_in_module(sub_module_name)) { + LOG_DEBUG("%s is an exported field of a %s", field_name, + sub_module_name); + /* + * if it returns well, guarantee that + * the sub_module_name and its dependencies + * have been loaded well + */ + sub_module = load_depended_module(module, sub_module_name, + error_buf, error_buf_size); + if (!sub_module) { + return false; + } + } +#endif + CHECK_BUF(p, p_end, 1); /* 0x00/0x01/0x02/0x03 */ kind = read_uint8(p); @@ -744,36 +1475,27 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, case IMPORT_KIND_FUNC: /* import function */ bh_assert(import_functions); import = import_functions++; - read_leb_uint32(p, p_end, type_index); - if (type_index >= module->type_count) { - set_error_buf(error_buf, error_buf_size, - "Load import section failed: " - "unknown type."); + if (!load_function_import(module, sub_module, + sub_module_name, field_name, &p, + p_end, &import->u.function, + error_buf, error_buf_size)) { return false; } - import->u.function.func_type = module->types[type_index]; - - if (!(import->u.function.func_ptr_linked = - wasm_native_resolve_symbol(module_name, field_name, - import->u.function.func_type, - &import->u.function.signature, - &import->u.function.attachment, - &import->u.function.call_conv_raw))) { -#if WASM_ENABLE_WAMR_COMPILER == 0 /* Output warning except running aot compiler */ - LOG_WARNING("warning: fail to link import function (%s, %s)\n", - module_name, field_name); -#endif - } break; case IMPORT_KIND_TABLE: /* import table */ bh_assert(import_tables); import = import_tables++; - if (!load_table_import(&p, p_end, &import->u.table, - error_buf, error_buf_size)) - return false; - if (module->import_table_count > 1) { - set_error_buf(error_buf, error_buf_size, "multiple tables"); + if (!load_table_import(sub_module, + sub_module_name, + field_name, + &p, + p_end, + &import->u.table, + error_buf, + error_buf_size)) { + LOG_DEBUG("can not import such a table (%s,%s)", + sub_module_name, field_name); return false; } break; @@ -781,12 +1503,14 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, case IMPORT_KIND_MEMORY: /* import memory */ bh_assert(import_memories); import = import_memories++; - if (!load_memory_import(&p, p_end, &import->u.memory, - error_buf, error_buf_size)) - return false; - if (module->import_memory_count > 1) { - set_error_buf(error_buf, error_buf_size, - "Load import section failed: multiple memories"); + if (!load_memory_import(sub_module, + sub_module_name, + field_name, + &p, + p_end, + &import->u.memory, + error_buf, + error_buf_size)) { return false; } break; @@ -794,28 +1518,13 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, case IMPORT_KIND_GLOBAL: /* import global */ bh_assert(import_globals); import = import_globals++; - CHECK_BUF(p, p_end, 2); - import->u.global.type = read_uint8(p); - mutable = read_uint8(p); - if (mutable >= 2) { - set_error_buf(error_buf, error_buf_size, - "Load import section failed: " - "invalid mutability"); + if (!load_global_import(module, + sub_module, + sub_module_name, field_name, &p, + p_end, &import->u.global, + error_buf, error_buf_size)) { return false; } - import->u.global.is_mutable = mutable & 1 ? true : false; -#if WASM_ENABLE_LIBC_BUILTIN != 0 - if (!(wasm_native_lookup_libc_builtin_global( - module_name, field_name, - &import->u.global))) { - if (error_buf != NULL) - snprintf(error_buf, error_buf_size, - "Load import section failed: " - "resolve import global (%s, %s) failed.", - module_name, field_name); - return false; - } -#endif break; default: @@ -825,8 +1534,9 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, return false; } import->kind = kind; - import->u.names.module_name = module_name; + import->u.names.module_name = sub_module_name; import->u.names.field_name = field_name; + (void)sub_module; } #if WASM_ENABLE_LIBC_WASI != 0 @@ -850,6 +1560,7 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, LOG_VERBOSE("Load import section success.\n"); (void)u8; (void)u32; + (void)type_index; return true; } @@ -985,6 +1696,16 @@ load_function_section(const uint8 *buf, const uint8 *buf_end, if (local_count > 0) func->local_types = (uint8*)func + sizeof(WASMFunction); func->code_size = code_size; + /* + * we shall make a copy of code body [p_code, p_code + code_size] + * when we are worrying about inappropriate releasing behaviour. + * all code bodies are actually in a buffer which user allocates in + * his embedding environment and we don't have power on them. + * it will be like: + * code_body_cp = malloc(code_size); + * memcpy(code_body_cp, p_code, code_size); + * func->code = code_body_cp; + */ func->code = (uint8*)p_code; /* Load each local type */ @@ -1045,13 +1766,13 @@ load_table_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, WASMTable *table; read_leb_uint32(p, p_end, table_count); + /* a total of one table is allowed */ + if (module->import_table_count + table_count > 1) { + set_error_buf(error_buf, error_buf_size, "multiple tables"); + return false; + } if (table_count) { - if (table_count > 1) { - set_error_buf(error_buf, error_buf_size, - "Load table section failed: multiple tables"); - return false; - } module->table_count = table_count; total_size = sizeof(WASMTable) * (uint64)table_count; if (total_size >= UINT32_MAX @@ -1090,13 +1811,13 @@ load_memory_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, WASMMemory *memory; read_leb_uint32(p, p_end, memory_count); + /* a total of one memory is allowed */ + if (module->import_memory_count + memory_count > 1) { + set_error_buf(error_buf, error_buf_size, "multiple memories"); + return false; + } if (memory_count) { - if (memory_count > 1) { - set_error_buf(error_buf, error_buf_size, - "Load memory section failed: multiple memories"); - return false; - } module->memory_count = memory_count; total_size = sizeof(WASMMemory) * (uint64)memory_count; if (total_size >= UINT32_MAX @@ -1168,6 +1889,20 @@ load_global_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, if (!load_init_expr(&p, p_end, &(global->init_expr), global->type, error_buf, error_buf_size)) return false; + + if (INIT_EXPR_TYPE_GET_GLOBAL == global->init_expr.init_expr_type) { + /** + * Currently, constant expressions occurring as initializers + * of globals are further constrained in that contained + * global.get instructions are + * only allowed to refer to imported globals. + */ + uint32 target_global_index = global->init_expr.u.global_index; + if (target_global_index >= module->import_global_count) { + set_error_buf(error_buf, error_buf_size, "unknown global"); + return false; + } + } } } @@ -1186,10 +1921,11 @@ load_export_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, char *error_buf, uint32 error_buf_size) { const uint8 *p = buf, *p_end = buf_end; - uint32 export_count, i, index; + uint32 export_count, i, j, index; uint64 total_size; uint32 str_len; WASMExport *export; + const char *name; read_leb_uint32(p, p_end, export_count); @@ -1210,10 +1946,22 @@ load_export_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, for (i = 0; i < export_count; i++, export++) { read_leb_uint32(p, p_end, str_len); CHECK_BUF(p, p_end, str_len); + + for (j = 0; j < i; j++) { + name = module->exports[j].name; + if (strlen(name) == str_len + && memcmp(name, p, str_len) == 0) { + set_error_buf(error_buf, error_buf_size, + "duplicate export name"); + return false; + } + } + if (!(export->name = const_str_list_insert(p, str_len, module, error_buf, error_buf_size))) { return false; } + p += str_len; CHECK_BUF(p, p_end, 1); export->kind = read_uint8(p); @@ -1309,6 +2057,13 @@ load_table_segment_section(const uint8 *buf, const uint8 *buf_end, WASMModule *m return false; } read_leb_uint32(p, p_end, table_index); + if (table_index + >= module->import_table_count + module->table_count) { + LOG_DEBUG("table#%d does not exist", table_index); + set_error_buf(error_buf, error_buf_size, "unknown table"); + return false; + } + table_segment->table_index = table_index; /* initialize expression */ @@ -1329,6 +2084,12 @@ load_table_segment_section(const uint8 *buf, const uint8 *buf_end, WASMModule *m } for (j = 0; j < function_count; j++) { read_leb_uint32(p, p_end, function_index); + if (function_index >= module->function_count + module->function_count) { + set_error_buf(error_buf, error_buf_size, + "Load table segment section failed: " + "unknown function"); + return false; + } table_segment->func_indexes[j] = function_index; } } @@ -1354,9 +2115,22 @@ load_data_segment_section(const uint8 *buf, const uint8 *buf_end, uint64 total_size; WASMDataSeg *dataseg; InitializerExpression init_expr; +#if WASM_ENABLE_BULK_MEMORY != 0 + bool is_passive = false; + uint32 mem_flag; +#endif read_leb_uint32(p, p_end, data_seg_count); +#if WASM_ENABLE_BULK_MEMORY != 0 + if ((module->data_seg_count1 != 0) + && (data_seg_count != module->data_seg_count1)) { + set_error_buf(error_buf, error_buf_size, + "data count and data section have inconsistent lengths"); + return false; + } +#endif + if (data_seg_count) { module->data_seg_count = data_seg_count; total_size = sizeof(WASMDataSeg*) * (uint64)data_seg_count; @@ -1372,10 +2146,50 @@ load_data_segment_section(const uint8 *buf, const uint8 *buf_end, for (i = 0; i < data_seg_count; i++) { read_leb_uint32(p, p_end, mem_index); - - if (!load_init_expr(&p, p_end, &init_expr, VALUE_TYPE_I32, - error_buf, error_buf_size)) +#if WASM_ENABLE_BULK_MEMORY != 0 + is_passive = false; + mem_flag = mem_index & 0x03; + switch (mem_flag) { + case 0x01: + is_passive = true; + break; + case 0x00: + /* no memory index, treat index as 0 */ + mem_index = 0; + goto check_mem_index; + break; + case 0x02: + /* read following memory index */ + read_leb_uint32(p, p_end, mem_index); +check_mem_index: + if (mem_index + >= module->import_memory_count + module->memory_count) { + LOG_DEBUG("memory#%d does not exist", mem_index); + set_error_buf(error_buf, error_buf_size, "unknown memory"); + return false; + } + break; + case 0x03: + default: + set_error_buf(error_buf, error_buf_size, "unknown memory"); + return false; + break; + } +#else + if (mem_index + >= module->import_memory_count + module->memory_count) { + LOG_DEBUG("memory#%d does not exist", mem_index); + set_error_buf(error_buf, error_buf_size, "unknown memory"); return false; + } +#endif /* WASM_ENABLE_BULK_MEMORY */ + +#if WASM_ENABLE_BULK_MEMORY != 0 + if (!is_passive) +#endif + if (!load_init_expr(&p, p_end, &init_expr, VALUE_TYPE_I32, + error_buf, error_buf_size)) + return false; read_leb_uint32(p, p_end, data_seg_len); @@ -1387,10 +2201,17 @@ load_data_segment_section(const uint8 *buf, const uint8 *buf_end, return false; } - bh_memcpy_s(&dataseg->base_offset, sizeof(InitializerExpression), - &init_expr, sizeof(InitializerExpression)); +#if WASM_ENABLE_BULK_MEMORY != 0 + dataseg->is_passive = is_passive; + if (!is_passive) +#endif + { + bh_memcpy_s(&dataseg->base_offset, sizeof(InitializerExpression), + &init_expr, sizeof(InitializerExpression)); + + dataseg->memory_index = mem_index; + } - dataseg->memory_index = mem_index; dataseg->data_length = data_seg_len; CHECK_BUF(p, p_end, data_seg_len); dataseg->data = (uint8*)p; @@ -1408,6 +2229,28 @@ load_data_segment_section(const uint8 *buf, const uint8 *buf_end, return true; } +#if WASM_ENABLE_BULK_MEMORY != 0 +static bool +load_datacount_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, + char *error_buf, uint32 error_buf_size) +{ + const uint8 *p = buf, *p_end = buf_end; + uint32 data_seg_count1 = 0; + + read_leb_uint32(p, p_end, data_seg_count1); + module->data_seg_count1 = data_seg_count1; + + if (p != p_end) { + set_error_buf(error_buf, error_buf_size, + "Load datacount section failed: section size mismatch"); + return false; + } + + LOG_VERBOSE("Load datacount section success.\n"); + return true; +} +#endif + static bool load_code_section(const uint8 *buf, const uint8 *buf_end, const uint8 *buf_func, @@ -1447,23 +2290,24 @@ load_start_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, read_leb_uint32(p, p_end, start_function); - if (start_function >= module->function_count - + module->import_function_count) { + if (start_function + >= module->function_count + module->import_function_count) { set_error_buf(error_buf, error_buf_size, - "Load start section failed: " - "unknown function."); + "Load start section failed: " + "unknown function."); return false; } if (start_function < module->import_function_count) type = module->import_functions[start_function].u.function.func_type; else - type = module->functions - [start_function - module->import_function_count]->func_type; + type = + module->functions[start_function - module->import_function_count] + ->func_type; if (type->param_count != 0 || type->result_count != 0) { set_error_buf(error_buf, error_buf_size, - "Load start section failed: " - "invalid start function."); + "Load start section failed: " + "invalid start function."); return false; } @@ -1560,6 +2404,7 @@ load_from_sections(WASMModule *module, WASMSection *sections, while (section) { buf = section->section_body; buf_end = buf + section->section_body_size; + LOG_DEBUG("to section %d", section->section_type); switch (section->section_type) { case SECTION_TYPE_USER: /* unsupported user section, ignore it. */ @@ -1612,6 +2457,12 @@ load_from_sections(WASMModule *module, WASMSection *sections, if (!load_data_segment_section(buf, buf_end, module, error_buf, error_buf_size)) return false; break; +#if WASM_ENABLE_BULK_MEMORY != 0 + case SECTION_TYPE_DATACOUNT: + if (!load_datacount_section(buf, buf_end, module, error_buf, error_buf_size)) + return false; + break; +#endif default: set_error_buf(error_buf, error_buf_size, "WASM module load failed: invalid section id"); @@ -1781,6 +2632,9 @@ create_module(char *error_buf, uint32 error_buf_size) /* Set start_function to -1, means no start function */ module->start_function = (uint32)-1; +#if WASM_ENABLE_MULTI_MODULE != 0 + module->import_module_list = &module->import_module_list_head; +#endif return module; } @@ -1812,6 +2666,37 @@ destroy_sections(WASMSection *section_list) } } +static uint8 section_ids[] = { + SECTION_TYPE_USER, + SECTION_TYPE_TYPE, + SECTION_TYPE_IMPORT, + SECTION_TYPE_FUNC, + SECTION_TYPE_TABLE, + SECTION_TYPE_MEMORY, + SECTION_TYPE_GLOBAL, + SECTION_TYPE_EXPORT, + SECTION_TYPE_START, + SECTION_TYPE_ELEM, +#if WASM_ENABLE_BULK_MEMORY != 0 + SECTION_TYPE_DATACOUNT, +#endif + SECTION_TYPE_CODE, + SECTION_TYPE_DATA +}; + +static uint8 +get_section_index(uint8 section_type) +{ + uint8 max_id = sizeof(section_ids) / sizeof(uint8); + + for (uint8 i = 0; i < max_id; i++) { + if (section_type == section_ids[i]) + return i; + } + + return (uint8)-1; +} + static bool create_sections(const uint8 *buf, uint32 size, WASMSection **p_section_list, @@ -1819,7 +2704,7 @@ create_sections(const uint8 *buf, uint32 size, { WASMSection *section_list_end = NULL, *section; const uint8 *p = buf, *p_end = buf + size/*, *section_body*/; - uint8 section_type, last_section_type = (uint8)-1; + uint8 section_type, section_index, last_section_index = (uint8)-1; uint32 section_size; bh_assert(!*p_section_list); @@ -1828,19 +2713,20 @@ create_sections(const uint8 *buf, uint32 size, while (p < p_end) { CHECK_BUF(p, p_end, 1); section_type = read_uint8(p); - if (section_type <= SECTION_TYPE_DATA) { + section_index = get_section_index(section_type); + if (section_index != (uint8)-1) { if (section_type != SECTION_TYPE_USER) { /* Custom sections may be inserted at any place, while other sections must occur at most once and in prescribed order. */ - if (last_section_type != (uint8)-1 - && section_type <= last_section_type) { + if (last_section_index != (uint8)-1 + && (section_index <= last_section_index)) { set_error_buf(error_buf, error_buf_size, "WASM module load failed: " "junk after last section"); return false; } - last_section_type = section_type; + last_section_index = section_index; } CHECK_BUF1(p, p_end, 1); read_leb_uint32(p, p_end, section_size); @@ -1940,25 +2826,17 @@ load(const uint8 *buf, uint32 size, WASMModule *module, WASMModule* wasm_loader_load(const uint8 *buf, uint32 size, char *error_buf, uint32 error_buf_size) { - WASMModule *module = wasm_runtime_malloc(sizeof(WASMModule)); - + WASMModule *module = create_module(error_buf, error_buf_size); if (!module) { - set_error_buf(error_buf, error_buf_size, - "WASM module load failed: allocate memory failed."); return NULL; } - memset(module, 0, sizeof(WASMModule)); - - module->module_type = Wasm_Module_Bytecode; - - /* Set start_function to -1, means no start function */ - module->start_function = (uint32)-1; - - if (!load(buf, size, module, error_buf, error_buf_size)) + if (!load(buf, size, module, error_buf, error_buf_size)) { + LOG_VERBOSE("Load module failed, %s", error_buf); goto fail; + } - LOG_VERBOSE("Load module success.\n"); + LOG_VERBOSE("Load module success"); return module; fail: @@ -2039,6 +2917,30 @@ wasm_loader_unload(WASMModule *module) } } +#if WASM_ENABLE_MULTI_MODULE != 0 + /* just release the sub module list */ + if (module->import_module_list) { + WASMRegisteredModule *node = + bh_list_first_elem(module->import_module_list); + while (node) { + WASMRegisteredModule *next = bh_list_elem_next(node); + bh_list_remove(module->import_module_list, node); + /* + * unload(sub_module) will be trigged during runtime_destroy(). + * every module in the global module list will be unloaded one by + * one. so don't worry. + */ + wasm_runtime_free(node); + /* + * + * the module file reading buffer will be released + * in runtime_destroy() + */ + node = next; + } + } +#endif + wasm_runtime_free(module); } @@ -2359,10 +3261,45 @@ wasm_loader_find_block_addr(BlockAddr *block_addr_cache, case WASM_OP_I64_EXTEND32_S: break; case WASM_OP_MISC_PREFIX: - /* skip extend op */ - if (p < code_end_addr) - p++; + { + opcode = read_uint8(p); + switch (opcode) { + case WASM_OP_I32_TRUNC_SAT_S_F32: + case WASM_OP_I32_TRUNC_SAT_U_F32: + case WASM_OP_I32_TRUNC_SAT_S_F64: + case WASM_OP_I32_TRUNC_SAT_U_F64: + case WASM_OP_I64_TRUNC_SAT_S_F32: + case WASM_OP_I64_TRUNC_SAT_U_F32: + case WASM_OP_I64_TRUNC_SAT_S_F64: + case WASM_OP_I64_TRUNC_SAT_U_F64: + break; +#if WASM_ENABLE_BULK_MEMORY != 0 + case WASM_OP_MEMORY_INIT: + skip_leb_uint32(p, p_end); + /* skip memory idx */ + p++; + break; + case WASM_OP_DATA_DROP: + skip_leb_uint32(p, p_end); + break; + case WASM_OP_MEMORY_COPY: + /* skip two memory idx */ + p += 2; + break; + case WASM_OP_MEMORY_FILL: + /* skip memory idx */ + p++; + break; +#endif + default: + if (error_buf) + snprintf(error_buf, error_buf_size, + "WASM loader find block addr failed: " + "invalid opcode fc %02x.", opcode); + return false; + } break; + } default: if (error_buf) @@ -2383,6 +3320,7 @@ wasm_loader_find_block_addr(BlockAddr *block_addr_cache, #define REF_I64_2 VALUE_TYPE_I64 #define REF_F64_1 VALUE_TYPE_F64 #define REF_F64_2 VALUE_TYPE_F64 +#define REF_ANY VALUE_TYPE_ANY #if WASM_ENABLE_FAST_INTERP != 0 @@ -2404,8 +3342,6 @@ typedef struct BranchBlockPatch { typedef struct BranchBlock { uint8 block_type; uint8 return_type; - bool is_block_reachable; - bool skip_else_branch; uint8 *start_addr; uint8 *else_addr; uint8 *end_addr; @@ -2415,6 +3351,14 @@ typedef struct BranchBlock { uint8 *code_compiled; BranchBlockPatch *patch_list; #endif + + /* Indicate the operand stack is in polymorphic state. + * If the opcode is one of unreachable/br/br_table/return, stack is marked + * to polymorphic state until the block's 'end' opcode is processed. + * If stack is in polymorphic state and stack is empty, instruction can + * pop any type of value directly without decreasing stack top pointer + * and stack cell num. */ + bool is_stack_polymorphic; } BranchBlock; typedef struct WASMLoaderContext { @@ -2519,19 +3463,28 @@ static bool check_offset_push(WASMLoaderContext *ctx, char *error_buf, uint32 error_buf_size) { + uint32 cell_num = (ctx->frame_offset - ctx->frame_offset_bottom); if (ctx->frame_offset >= ctx->frame_offset_boundary) { MEM_REALLOC(ctx->frame_offset_bottom, ctx->frame_offset_size, ctx->frame_offset_size + 16); ctx->frame_offset_size += 16; ctx->frame_offset_boundary = ctx->frame_offset_bottom + ctx->frame_offset_size / sizeof(int16); - ctx->frame_offset = ctx->frame_offset_bottom + ctx->stack_cell_num; + ctx->frame_offset = ctx->frame_offset_bottom + cell_num; } return true; fail: return false; } +static bool +check_offset_pop(WASMLoaderContext *ctx, uint32 cells) +{ + if (ctx->frame_offset - cells < ctx->frame_offset_bottom) + return false; + return true; +} + static void free_label_patch_list(BranchBlock *frame_csp) { BranchBlockPatch *label_patch = frame_csp->patch_list; @@ -2572,38 +3525,58 @@ fail: return false; } + static bool -check_stack_pop(WASMLoaderContext *ctx, uint8 type, - char *error_buf, uint32 error_buf_size, - const char *type_str) +check_stack_top_values(uint8 *frame_ref, int32 stack_cell_num, uint8 type, + char *error_buf, uint32 error_buf_size) { - uint32 block_stack_cell_num = ctx->stack_cell_num - - (ctx->frame_csp - 1)->stack_cell_num; + char *type_str[] = { "f64", "f32", "i64", "i32" }; if (((type == VALUE_TYPE_I32 || type == VALUE_TYPE_F32) - && block_stack_cell_num < 1) + && stack_cell_num < 1) || ((type == VALUE_TYPE_I64 || type == VALUE_TYPE_F64) - && block_stack_cell_num < 2)) { + && stack_cell_num < 2)) { set_error_buf(error_buf, error_buf_size, "WASM module load failed: " "type mismatch: expect data but stack was empty"); return false; } - if ((type == VALUE_TYPE_I32 && *(ctx->frame_ref - 1) != REF_I32) - || (type == VALUE_TYPE_F32 && *(ctx->frame_ref - 1) != REF_F32) + if ((type == VALUE_TYPE_I32 && *(frame_ref - 1) != REF_I32) + || (type == VALUE_TYPE_F32 && *(frame_ref - 1) != REF_F32) || (type == VALUE_TYPE_I64 - && (*(ctx->frame_ref - 2) != REF_I64_1 - || *(ctx->frame_ref - 1) != REF_I64_2)) + && (*(frame_ref - 2) != REF_I64_1 + || *(frame_ref - 1) != REF_I64_2)) || (type == VALUE_TYPE_F64 - && (*(ctx->frame_ref - 2) != REF_F64_1 - || *(ctx->frame_ref - 1) != REF_F64_2))) { + && (*(frame_ref - 2) != REF_F64_1 + || *(frame_ref - 1) != REF_F64_2))) { if (error_buf != NULL) snprintf(error_buf, error_buf_size, "%s%s%s", "WASM module load failed: type mismatch: expect ", - type_str, " but got other"); + type_str[type - VALUE_TYPE_F64], " but got other"); return false; } + + return true; +} + +static bool +check_stack_pop(WASMLoaderContext *ctx, uint8 type, + char *error_buf, uint32 error_buf_size) +{ + int32 block_stack_cell_num = (int32) + (ctx->stack_cell_num - (ctx->frame_csp - 1)->stack_cell_num); + + if (block_stack_cell_num > 0 + && *(ctx->frame_ref - 1) == VALUE_TYPE_ANY) { + /* the stack top is a value of any type, return success */ + return true; + } + + if (!check_stack_top_values(ctx->frame_ref, block_stack_cell_num, + type, error_buf, error_buf_size)) + return false; + return true; } @@ -2693,7 +3666,9 @@ wasm_loader_push_frame_ref(WASMLoaderContext *ctx, uint8 type, if (ctx->stack_cell_num > ctx->max_stack_cell_num) ctx->max_stack_cell_num = ctx->stack_cell_num; - if (type == VALUE_TYPE_I32 || type == VALUE_TYPE_F32) + if (type == VALUE_TYPE_I32 + || type == VALUE_TYPE_F32 + || type == VALUE_TYPE_ANY) return true; if (!check_stack_push(ctx, error_buf, error_buf_size)) @@ -2709,18 +3684,27 @@ static bool wasm_loader_pop_frame_ref(WASMLoaderContext *ctx, uint8 type, char *error_buf, uint32 error_buf_size) { - char *type_str[] = { "f64", "f32", "i64", "i32" }; + BranchBlock *cur_block = ctx->frame_csp - 1; + int32 available_stack_cell = (int32) + (ctx->stack_cell_num - cur_block->stack_cell_num); + + /* Directly return success if current block is in stack + * polymorphic state while stack is empty. */ + if (available_stack_cell <= 0 && cur_block->is_stack_polymorphic) + return true; + if (type == VALUE_TYPE_VOID) return true; - if (!check_stack_pop(ctx, type, error_buf, error_buf_size, - type_str[type - VALUE_TYPE_F64])) + if (!check_stack_pop(ctx, type, error_buf, error_buf_size)) return false; ctx->frame_ref--; ctx->stack_cell_num--; - if (type == VALUE_TYPE_I32 || type == VALUE_TYPE_F32) + if (type == VALUE_TYPE_I32 + || type == VALUE_TYPE_F32 + || *ctx->frame_ref == VALUE_TYPE_ANY) return true; ctx->frame_ref--; @@ -2770,17 +3754,7 @@ static bool wasm_loader_pop_frame_csp(WASMLoaderContext *ctx, char *error_buf, uint32 error_buf_size) { - uint8 block_return_type; - CHECK_CSP_POP(); - - block_return_type = (ctx->frame_csp - 1)->return_type; - if (!wasm_loader_pop_frame_ref(ctx, block_return_type, - error_buf, error_buf_size) - || !wasm_loader_push_frame_ref(ctx, block_return_type, - error_buf, error_buf_size)) - goto fail; - ctx->frame_csp--; ctx->csp_num--; return true; @@ -2792,32 +3766,30 @@ static bool wasm_loader_check_br(WASMLoaderContext *ctx, uint32 depth, char *error_buf, uint32 error_buf_size) { + BranchBlock *target_block, *cur_block; + int32 available_stack_cell; + if (ctx->csp_num < depth + 1) { set_error_buf(error_buf, error_buf_size, "WASM module load failed: unknown label, " "unexpected end of section or function"); return false; } - if ((ctx->frame_csp - (depth + 1))->block_type != BLOCK_TYPE_LOOP) { - uint8 tmp_ret_type = (ctx->frame_csp - (depth + 1))->return_type; - if ((tmp_ret_type == VALUE_TYPE_I32 - && (ctx->stack_cell_num < 1 || *(ctx->frame_ref - 1) != REF_I32)) - || (tmp_ret_type == VALUE_TYPE_F32 - && (ctx->stack_cell_num < 1 || *(ctx->frame_ref - 1) != REF_F32)) - || (tmp_ret_type == VALUE_TYPE_I64 - && (ctx->stack_cell_num < 2 - || *(ctx->frame_ref - 2) != REF_I64_1 - || *(ctx->frame_ref - 1) != REF_I64_2)) - || (tmp_ret_type == VALUE_TYPE_F64 - && (ctx->stack_cell_num < 2 - || *(ctx->frame_ref - 2) != REF_F64_1 - || *(ctx->frame_ref - 1) != REF_F64_2))) { - set_error_buf(error_buf, error_buf_size, - "WASM module load failed: type mismatch: " - "expect data but stack was empty or other type"); + + target_block = ctx->frame_csp - (depth + 1); + cur_block = ctx->frame_csp - 1; + + available_stack_cell = (int32) + (ctx->stack_cell_num - cur_block->stack_cell_num); + + if (available_stack_cell <= 0 && target_block->is_stack_polymorphic) + return true; + + if (target_block->block_type != BLOCK_TYPE_LOOP) { + uint8 type = target_block->return_type; + if (!check_stack_top_values(ctx->frame_ref, available_stack_cell, + type, error_buf, error_buf_size)) return false; - } - (ctx->frame_csp - (depth + 1))->is_block_reachable = true; } return true; } @@ -3209,22 +4181,45 @@ wasm_loader_push_frame_offset(WASMLoaderContext *ctx, uint8 type, return true; } -/* The frame_offset stack should always keep the same depth with - frame_ref, so we don't check pop of frame_offset */ +/* This function should be in front of wasm_loader_pop_frame_ref + as they both use ctx->stack_cell_num, and ctx->stack_cell_num + will be modified by wasm_loader_pop_frame_ref */ static bool wasm_loader_pop_frame_offset(WASMLoaderContext *ctx, uint8 type, char *error_buf, uint32 error_buf_size) { + /* if ctx->frame_csp equals ctx->frame_csp_bottom, + then current block is the function block */ + uint32 depth = ctx->frame_csp > ctx->frame_csp_bottom ? 1 : 0; + BranchBlock *cur_block = ctx->frame_csp - depth; + int32 available_stack_cell = (int32) + (ctx->stack_cell_num - cur_block->stack_cell_num); + + /* Directly return success if current block is in stack + * polymorphic state while stack is empty. */ + if (available_stack_cell <= 0 && cur_block->is_stack_polymorphic) + return true; + if (type == VALUE_TYPE_VOID) return true; if (type == VALUE_TYPE_I32 || type == VALUE_TYPE_F32) { + /* Check the offset stack bottom to ensure the frame offset + stack will not go underflow. But we don't thrown error + and return true here, because the error msg should be + given in wasm_loader_pop_frame_ref */ + if (!check_offset_pop(ctx, 1)) + return true; + ctx->frame_offset -= 1; if ((*(ctx->frame_offset) > ctx->start_dynamic_offset) && (*(ctx->frame_offset) < ctx->max_dynamic_offset)) ctx->dynamic_offset -= 1; } else { + if (!check_offset_pop(ctx, 2)) + return true; + ctx->frame_offset -= 2; if ((*(ctx->frame_offset) > ctx->start_dynamic_offset) && (*(ctx->frame_offset) < ctx->max_dynamic_offset)) @@ -3257,11 +4252,11 @@ wasm_loader_push_frame_ref_offset(WASMLoaderContext *ctx, uint8 type, bool disable_emit, int16 operand_offset, char *error_buf, uint32 error_buf_size) { - if (!(wasm_loader_push_frame_ref(ctx, type, error_buf, error_buf_size))) - return false; if (!(wasm_loader_push_frame_offset(ctx, type, disable_emit, operand_offset, error_buf, error_buf_size))) return false; + if (!(wasm_loader_push_frame_ref(ctx, type, error_buf, error_buf_size))) + return false; return true; } @@ -3270,10 +4265,11 @@ static bool wasm_loader_pop_frame_ref_offset(WASMLoaderContext *ctx, uint8 type, char *error_buf, uint32 error_buf_size) { - if (!wasm_loader_pop_frame_ref(ctx, type, error_buf, error_buf_size)) - return false; + /* put wasm_loader_pop_frame_offset in front of wasm_loader_pop_frame_ref */ if (!wasm_loader_pop_frame_offset(ctx, type, error_buf, error_buf_size)) return false; + if (!wasm_loader_pop_frame_ref(ctx, type, error_buf, error_buf_size)) + return false; return true; } @@ -3284,13 +4280,13 @@ wasm_loader_push_pop_frame_ref_offset(WASMLoaderContext *ctx, uint8 pop_cnt, bool disable_emit, int16 operand_offset, char *error_buf, uint32 error_buf_size) { - if (!wasm_loader_push_pop_frame_ref(ctx, pop_cnt, type_push, type_pop, - error_buf, error_buf_size)) - return false; if (!wasm_loader_push_pop_frame_offset(ctx, pop_cnt, type_push, type_pop, disable_emit, operand_offset, error_buf, error_buf_size)) return false; + if (!wasm_loader_push_pop_frame_ref(ctx, pop_cnt, type_push, type_pop, + error_buf, error_buf_size)) + return false; return true; } @@ -3656,6 +4652,24 @@ check_memory(WASMModule *module, goto fail; \ } while (0) +static bool +check_memory_access_align(uint8 opcode, uint32 align, + char *error_buf, uint32 error_buf_size) +{ + uint8 mem_access_aligns[] = { + 2, 3, 2, 3, 0, 0, 1, 1, 0, 0, 1, 1, 2, 2, /* loads */ + 2, 3, 2, 3, 0, 1, 0, 1, 2 /* stores */ + }; + bh_assert(opcode >= WASM_OP_I32_LOAD + && opcode <= WASM_OP_I64_STORE32); + if (align > mem_access_aligns[opcode - WASM_OP_I32_LOAD]) { + set_error_buf(error_buf, error_buf_size, + "alignment must not be larger than natural"); + return false; + } + return true; +} + static bool is_block_type_valid(uint8 type) { @@ -3701,9 +4715,22 @@ check_branch_block_ret(WASMLoaderContext *loader_ctx, BranchBlock *frame_csp_tmp, char *error_buf, uint32 error_buf_size) { - frame_csp_tmp->is_block_reachable = true; +#if WASM_ENABLE_FAST_INTERP != 0 + BranchBlock *cur_block = loader_ctx->frame_csp - 1; + bool disable_emit = true; + int16 operand_offset = 0; +#endif if (frame_csp_tmp->block_type != BLOCK_TYPE_LOOP) { uint8 block_return_type = frame_csp_tmp->return_type; +#if WASM_ENABLE_FAST_INTERP != 0 + /* If the stack is in polymorphic state, do fake pop and push on + offset stack to keep the depth of offset stack to be the same + with ref stack */ + if (cur_block->is_stack_polymorphic) { + POP_OFFSET_TYPE(block_return_type); + PUSH_OFFSET_TYPE(block_return_type); + } +#endif POP_TYPE(block_return_type); PUSH_TYPE(block_return_type); } @@ -3712,6 +4739,92 @@ fail: return false; } +static bool +check_block_stack(WASMLoaderContext *ctx, BranchBlock *block, + char *error_buf, uint32 error_buf_size) +{ + uint8 type = block->return_type; + int32 available_stack_cell = (int32) + (ctx->stack_cell_num - block->stack_cell_num); + + if (type != VALUE_TYPE_VOID + && available_stack_cell <= 0 + && block->is_stack_polymorphic) { + if (!(wasm_loader_push_frame_ref(ctx, type, error_buf, error_buf_size)) +#if WASM_ENABLE_FAST_INTERP != 0 + || !(wasm_loader_push_frame_offset(ctx, type, true, 0, error_buf, error_buf_size)) +#endif + ) + return false; + return true; + } + + if (type != VALUE_TYPE_VOID + && available_stack_cell == 1 + && *(ctx->frame_ref - 1) == VALUE_TYPE_ANY) { + if (type == VALUE_TYPE_I32 || type == VALUE_TYPE_F32) { + /* If the stack top is a value of any type, change its type to the + * same as block return type and return success */ + *(ctx->frame_ref - 1) = type; + } + else { + if (!(wasm_loader_push_frame_ref(ctx, VALUE_TYPE_I32, + error_buf, error_buf_size)) +#if WASM_ENABLE_FAST_INTERP != 0 + || !(wasm_loader_push_frame_offset(ctx, VALUE_TYPE_I32, + true, 0, + error_buf, error_buf_size)) +#endif + ) + return false; + *(ctx->frame_ref - 1) = *(ctx->frame_ref - 2) = type; + } + return true; + } + + if (((type == VALUE_TYPE_I32 || type == VALUE_TYPE_F32) + && available_stack_cell != 1) + || ((type == VALUE_TYPE_I64 || type == VALUE_TYPE_F64) + && available_stack_cell != 2) + || (type == VALUE_TYPE_VOID && available_stack_cell > 0)) { + set_error_buf(error_buf, error_buf_size, + "WASM module load failed: " + "type mismatch: stack size does not match block type"); + return false; + } + + if (!check_stack_top_values(ctx->frame_ref, available_stack_cell, + type, error_buf, error_buf_size)) + return false; + + return true; +} + +/* reset the stack to the state of before entering the last block */ +#if WASM_ENABLE_FAST_INTERP != 0 +#define RESET_STACK() do { \ + loader_ctx->stack_cell_num = \ + (loader_ctx->frame_csp - 1)->stack_cell_num; \ + loader_ctx->frame_ref = \ + loader_ctx->frame_ref_bottom + loader_ctx->stack_cell_num; \ + loader_ctx->frame_offset = \ + loader_ctx->frame_offset_bottom + loader_ctx->stack_cell_num; \ +} while (0) +#else +#define RESET_STACK() do { \ + loader_ctx->stack_cell_num = \ + (loader_ctx->frame_csp - 1)->stack_cell_num; \ + loader_ctx->frame_ref = \ + loader_ctx->frame_ref_bottom + loader_ctx->stack_cell_num; \ +} while (0) +#endif + +/* set current block's stack polymorphic state */ +#define SET_CUR_BLOCK_STACK_POLYMORPHIC_STATE(flag) do { \ + BranchBlock *cur_block = loader_ctx->frame_csp - 1; \ + cur_block->is_stack_polymorphic = flag; \ +} while (0) + static bool wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, BlockAddr *block_addr_cache, @@ -3725,9 +4838,12 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, int32 i32, i32_const = 0; int64 i64; uint8 opcode, u8, block_return_type; - bool return_value = false, is_i32_const = false; + bool return_value = false; WASMLoaderContext *loader_ctx; BranchBlock *frame_csp_tmp; +#if WASM_ENABLE_BULK_MEMORY != 0 + uint32 segment_index; +#endif #if WASM_ENABLE_FAST_INTERP != 0 uint8 *func_const_end, *func_const; int16 operand_offset; @@ -3775,7 +4891,6 @@ re_scan: #endif PUSH_CSP(BLOCK_TYPE_FUNCTION, ret_type, p); - (loader_ctx->frame_csp - 1)->is_block_reachable = true; while (p < p_end) { opcode = *p++; @@ -3787,7 +4902,9 @@ re_scan: switch (opcode) { case WASM_OP_UNREACHABLE: - goto handle_next_reachable_block; + RESET_STACK(); + SET_CUR_BLOCK_STACK_POLYMORPHIC_STATE(true); + break; case WASM_OP_NOP: #if WASM_ENABLE_FAST_INTERP != 0 @@ -3827,39 +4944,6 @@ re_scan: emit_empty_label_addr_and_frame_ip(PATCH_ELSE); emit_empty_label_addr_and_frame_ip(PATCH_END); #endif - if (!is_i32_const) - (loader_ctx->frame_csp - 1)->is_block_reachable = true; - else { - if (!wasm_loader_find_block_addr(block_addr_cache, - (loader_ctx->frame_csp - 1)->start_addr, - p_end, - (loader_ctx->frame_csp - 1)->block_type, - &(loader_ctx->frame_csp - 1)->else_addr, - &(loader_ctx->frame_csp - 1)->end_addr, - error_buf, error_buf_size)) - goto fail; - - if (!i32_const) { - if ((loader_ctx->frame_csp - 1)->else_addr) { -#if WASM_ENABLE_FAST_INTERP != 0 - loader_ctx->frame_offset = loader_ctx->frame_offset_bottom + - (loader_ctx->frame_csp - 1)->stack_cell_num; - apply_label_patch(loader_ctx, 1, PATCH_ELSE); -#endif - p = (loader_ctx->frame_csp - 1)->else_addr + 1; - } - else { - p = (loader_ctx->frame_csp - 1)->end_addr; - } - - is_i32_const = false; - continue; - } - else { - /* The else branch cannot be reached, ignored it. */ - (loader_ctx->frame_csp - 1)->skip_else_branch = true; - } - } break; case WASM_OP_ELSE: @@ -3871,32 +4955,43 @@ re_scan: goto fail; } - if ((loader_ctx->frame_csp - 1)->skip_else_branch) { - /* The else branch is ignored. */ - is_i32_const = false; - p = (loader_ctx->frame_csp - 1)->end_addr; -#if WASM_ENABLE_FAST_INTERP != 0 - skip_label(); -#endif - continue; - } + /* check whether if branch's stack matches its result type */ + if (!check_block_stack(loader_ctx, loader_ctx->frame_csp - 1, + error_buf, error_buf_size)) + goto fail; (loader_ctx->frame_csp - 1)->else_addr = p - 1; - loader_ctx->stack_cell_num = (loader_ctx->frame_csp - 1)->stack_cell_num; - loader_ctx->frame_ref = loader_ctx->frame_ref_bottom + - loader_ctx->stack_cell_num; + #if WASM_ENABLE_FAST_INTERP != 0 /* if the result of if branch is in local or const area, add a copy op */ RESERVE_BLOCK_RET(); - loader_ctx->frame_offset = loader_ctx->frame_offset_bottom + - loader_ctx->stack_cell_num; + emit_empty_label_addr_and_frame_ip(PATCH_END); apply_label_patch(loader_ctx, 1, PATCH_ELSE); #endif + RESET_STACK(); + SET_CUR_BLOCK_STACK_POLYMORPHIC_STATE(false); break; case WASM_OP_END: { + + /* check whether block stack matches its result type */ + if (!check_block_stack(loader_ctx, loader_ctx->frame_csp - 1, + error_buf, error_buf_size)) + goto fail; + + /* if has return value, but no else branch, fail */ + if ((loader_ctx->frame_csp - 1)->block_type == BLOCK_TYPE_IF + && (loader_ctx->frame_csp - 1)->return_type != VALUE_TYPE_VOID + && !(loader_ctx->frame_csp - 1)->else_addr) { + set_error_buf(error_buf, error_buf_size, + "WASM module load failed: " + "type mismatch: if has return value and else is missing"); + + goto fail; + } + POP_CSP(); #if WASM_ENABLE_FAST_INTERP != 0 @@ -3919,9 +5014,10 @@ re_scan: ignore the following bytecodes */ p = p_end; - is_i32_const = false; continue; } + + SET_CUR_BLOCK_STACK_POLYMORPHIC_STATE(false); break; } @@ -3935,50 +5031,9 @@ re_scan: error_buf, error_buf_size)) goto fail; -handle_next_reachable_block: - for (i = 1; i <= loader_ctx->csp_num; i++) - if ((loader_ctx->frame_csp - i)->is_block_reachable) - break; - - block_return_type = (loader_ctx->frame_csp - i)->return_type; - - if(!wasm_loader_find_block_addr(block_addr_cache, - (loader_ctx->frame_csp - i)->start_addr, - p_end, - (loader_ctx->frame_csp - i)->block_type, - &(loader_ctx->frame_csp - i)->else_addr, - &(loader_ctx->frame_csp - i)->end_addr, - error_buf, error_buf_size)) - goto fail; - - loader_ctx->stack_cell_num = (loader_ctx->frame_csp - i)->stack_cell_num; - loader_ctx->frame_ref = loader_ctx->frame_ref_bottom + - loader_ctx->stack_cell_num; - loader_ctx->csp_num -= i - 1; - loader_ctx->frame_csp -= i - 1; - - if ((loader_ctx->frame_csp - 1)->block_type == BLOCK_TYPE_IF - && (loader_ctx->frame_csp - 1)->else_addr != NULL - && p <= (loader_ctx->frame_csp - 1)->else_addr) { -#if WASM_ENABLE_FAST_INTERP != 0 - loader_ctx->frame_offset = loader_ctx->frame_offset_bottom + - (loader_ctx->frame_csp - 1)->stack_cell_num; - apply_label_patch(loader_ctx, 1, PATCH_ELSE); -#endif - p = (loader_ctx->frame_csp - 1)->else_addr + 1; - - } - else { - p = (loader_ctx->frame_csp - 1)->end_addr; - PUSH_TYPE(block_return_type); -#if WASM_ENABLE_FAST_INTERP != 0 - loader_ctx->frame_offset = loader_ctx->frame_offset_bottom + - loader_ctx->stack_cell_num; -#endif - } - - is_i32_const = false; - continue; + RESET_STACK(); + SET_CUR_BLOCK_STACK_POLYMORPHIC_STATE(true); + break; } case WASM_OP_BR_IF: @@ -3989,19 +5044,17 @@ handle_next_reachable_block: error_buf, error_buf_size))) goto fail; - if (!is_i32_const || i32_const) { - /* The branch can be reached */ - if (!check_branch_block_ret(loader_ctx, frame_csp_tmp, - error_buf, error_buf_size)) - goto fail; - } - if (is_i32_const && i32_const) - goto handle_next_reachable_block; + if (!check_branch_block_ret(loader_ctx, frame_csp_tmp, + error_buf, error_buf_size)) + goto fail; + break; } case WASM_OP_BR_TABLE: { + uint8 ret_type; + read_leb_uint32(p, p_end, count); #if WASM_ENABLE_FAST_INTERP != 0 emit_const(count); @@ -4011,15 +5064,34 @@ handle_next_reachable_block: /* TODO: check the const */ for (i = 0; i <= count; i++) { if (!(frame_csp_tmp = check_branch_block(loader_ctx, &p, p_end, - error_buf, error_buf_size))) + error_buf, error_buf_size))) goto fail; if (!check_branch_block_ret(loader_ctx, frame_csp_tmp, error_buf, error_buf_size)) goto fail; + + if (i == 0) { + ret_type = frame_csp_tmp->block_type == BLOCK_TYPE_LOOP ? + VALUE_TYPE_VOID : frame_csp_tmp->return_type; + } + else { + /* Check whether all table items have the same return type */ + uint8 tmp_ret_type = frame_csp_tmp->block_type == BLOCK_TYPE_LOOP ? + VALUE_TYPE_VOID : frame_csp_tmp->return_type; + if (ret_type != tmp_ret_type) { + set_error_buf(error_buf, error_buf_size, + "WASM loader prepare bytecode failed: " + "type mismatch: br_table targets must " + "all use same result type"); + goto fail; + } + } } - goto handle_next_reachable_block; + RESET_STACK(); + SET_CUR_BLOCK_STACK_POLYMORPHIC_STATE(true); + break; } case WASM_OP_RETURN: @@ -4030,12 +5102,11 @@ handle_next_reachable_block: #if WASM_ENABLE_FAST_INTERP != 0 // emit the offset after return opcode POP_OFFSET_TYPE(ret_type); - loader_ctx->frame_offset = loader_ctx->frame_offset_bottom + - loader_ctx->stack_cell_num; #endif - is_i32_const = false; - goto handle_next_reachable_block; + RESET_STACK(); + SET_CUR_BLOCK_STACK_POLYMORPHIC_STATE(true); + break; } case WASM_OP_CALL: @@ -4145,8 +5216,12 @@ handle_next_reachable_block: case WASM_OP_DROP: case WASM_OP_DROP_64: { - if (loader_ctx->stack_cell_num - - (loader_ctx->frame_csp - 1)->stack_cell_num <= 0) { + BranchBlock *cur_block = loader_ctx->frame_csp - 1; + int32 available_stack_cell = (int32) + (loader_ctx->stack_cell_num - cur_block->stack_cell_num); + + if (available_stack_cell <= 0 + && !cur_block->is_stack_polymorphic) { set_error_buf(error_buf, error_buf_size, "WASM loader prepare bytecode failed: " "type mismatch, opcode drop was found " @@ -4154,38 +5229,37 @@ handle_next_reachable_block: goto fail; } - if (*(loader_ctx->frame_ref - 1) == REF_I32 - || *(loader_ctx->frame_ref - 1) == REF_F32) { - loader_ctx->frame_ref--; - loader_ctx->stack_cell_num--; + if (available_stack_cell > 0) { + if (*(loader_ctx->frame_ref - 1) == REF_I32 + || *(loader_ctx->frame_ref - 1) == REF_F32) { + loader_ctx->frame_ref--; + loader_ctx->stack_cell_num--; #if WASM_ENABLE_FAST_INTERP != 0 - skip_label(); - loader_ctx->frame_offset--; - if (*(loader_ctx->frame_offset) > - loader_ctx->start_dynamic_offset) - loader_ctx->dynamic_offset --; + skip_label(); + loader_ctx->frame_offset--; + if (*(loader_ctx->frame_offset) > + loader_ctx->start_dynamic_offset) + loader_ctx->dynamic_offset --; #endif + } + else { + loader_ctx->frame_ref -= 2; + loader_ctx->stack_cell_num -= 2; +#if (WASM_ENABLE_FAST_INTERP == 0) || (WASM_ENABLE_JIT != 0) + *(p - 1) = WASM_OP_DROP_64; +#endif +#if WASM_ENABLE_FAST_INTERP != 0 + skip_label(); + loader_ctx->frame_offset -= 2; + if (*(loader_ctx->frame_offset) > + loader_ctx->start_dynamic_offset) + loader_ctx->dynamic_offset -= 2; +#endif + } } else { - if (loader_ctx->stack_cell_num - - (loader_ctx->frame_csp - 1)->stack_cell_num <= 0) { - set_error_buf(error_buf, error_buf_size, - "WASM loader prepare bytecode failed: " - "type mismatch, opcode drop was found " - "but stack was empty"); - goto fail; - } - loader_ctx->frame_ref -= 2; - loader_ctx->stack_cell_num -= 2; -#if (WASM_ENABLE_FAST_INTERP == 0) || (WASM_ENABLE_JIT != 0) - *(p - 1) = WASM_OP_DROP_64; -#endif #if WASM_ENABLE_FAST_INTERP != 0 skip_label(); - loader_ctx->frame_offset -= 2; - if (*(loader_ctx->frame_offset) > - loader_ctx->start_dynamic_offset) - loader_ctx->dynamic_offset -= 2; #endif } break; @@ -4195,10 +5269,16 @@ handle_next_reachable_block: case WASM_OP_SELECT_64: { uint8 ref_type; + BranchBlock *cur_block = loader_ctx->frame_csp - 1; + int32 available_stack_cell; POP_I32(); - if (loader_ctx->stack_cell_num <= 0) { + available_stack_cell = (int32) + (loader_ctx->stack_cell_num - cur_block->stack_cell_num); + + if (available_stack_cell <= 0 + && !cur_block->is_stack_polymorphic) { set_error_buf(error_buf, error_buf_size, "WASM loader prepare bytecode failed: " "type mismatch, opcode select was found " @@ -4206,38 +5286,50 @@ handle_next_reachable_block: goto fail; } - switch (*(loader_ctx->frame_ref - 1)) { - case REF_I32: - case REF_F32: - break; - case REF_I64_2: - case REF_F64_2: + if (available_stack_cell > 0) { + switch (*(loader_ctx->frame_ref - 1)) { + case REF_I32: + case REF_F32: + break; + case REF_I64_2: + case REF_F64_2: #if (WASM_ENABLE_FAST_INTERP == 0) || (WASM_ENABLE_JIT != 0) - *(p - 1) = WASM_OP_SELECT_64; + *(p - 1) = WASM_OP_SELECT_64; #endif #if WASM_ENABLE_FAST_INTERP != 0 - if (loader_ctx->p_code_compiled) { + if (loader_ctx->p_code_compiled) { #if WASM_ENABLE_ABS_LABEL_ADDR != 0 - *(void**)(loader_ctx->p_code_compiled - 2 - sizeof(void*)) = - handle_table[WASM_OP_SELECT_64]; + *(void**)(loader_ctx->p_code_compiled - 2 - sizeof(void*)) = + handle_table[WASM_OP_SELECT_64]; #else - *((int16*)loader_ctx->p_code_compiled - 2) = (int16) - (handle_table[WASM_OP_SELECT_64] - handle_table[0]); + *((int16*)loader_ctx->p_code_compiled - 2) = (int16) + (handle_table[WASM_OP_SELECT_64] - handle_table[0]); #endif - } + } #endif - break; - } + break; + } - ref_type = *(loader_ctx->frame_ref - 1); - POP_TYPE(ref_type); - POP_TYPE(ref_type); - PUSH_TYPE(ref_type); + ref_type = *(loader_ctx->frame_ref - 1); #if WASM_ENABLE_FAST_INTERP != 0 - POP_OFFSET_TYPE(ref_type); - POP_OFFSET_TYPE(ref_type); - PUSH_OFFSET_TYPE(ref_type); + POP_OFFSET_TYPE(ref_type); #endif + POP_TYPE(ref_type); +#if WASM_ENABLE_FAST_INTERP != 0 + POP_OFFSET_TYPE(ref_type); +#endif + POP_TYPE(ref_type); +#if WASM_ENABLE_FAST_INTERP != 0 + PUSH_OFFSET_TYPE(ref_type); +#endif + PUSH_TYPE(ref_type); + } + else { +#if WASM_ENABLE_FAST_INTERP != 0 + PUSH_OFFSET_TYPE(VALUE_TYPE_ANY); +#endif + PUSH_TYPE(VALUE_TYPE_ANY); + } break; } @@ -4335,6 +5427,16 @@ handle_next_reachable_block: { p_org = p - 1; GET_LOCAL_INDEX_TYPE_AND_OFFSET(); +#if WASM_ENABLE_FAST_INTERP != 0 + /* If the stack is in polymorphic state, do fake pop and push on + offset stack to keep the depth of offset stack to be the same + with ref stack */ + BranchBlock *cur_block = loader_ctx->frame_csp - 1; + if (cur_block->is_stack_polymorphic) { + POP_OFFSET_TYPE(local_type); + PUSH_OFFSET_TYPE(local_type); + } +#endif POP_TYPE(local_type); PUSH_TYPE(local_type); @@ -4403,6 +5505,7 @@ handle_next_reachable_block: case WASM_OP_SET_GLOBAL: { + bool is_multable = false; read_leb_uint32(p, p_end, global_idx); if (global_idx >= global_count) { set_error_buf(error_buf, error_buf_size, @@ -4411,9 +5514,23 @@ handle_next_reachable_block: goto fail; } - global_type = global_idx < module->import_global_count - ? module->import_globals[global_idx].u.global.type - : module->globals[global_idx - module->import_global_count].type; + is_multable = + global_idx < module->import_global_count + ? module->import_globals[global_idx].u.global.is_mutable + : module->globals[global_idx - module->import_global_count] + .is_mutable; + if (!is_multable) { + set_error_buf(error_buf, + error_buf_size, + "global is immutable"); + goto fail; + } + + global_type = + global_idx < module->import_global_count + ? module->import_globals[global_idx].u.global.type + : module->globals[global_idx - module->import_global_count] + .type; POP_TYPE(global_type); #if WASM_ENABLE_FAST_INTERP != 0 @@ -4471,6 +5588,10 @@ handle_next_reachable_block: CHECK_MEMORY(); read_leb_uint32(p, p_end, align); /* align */ read_leb_uint32(p, p_end, mem_offset); /* offset */ + if (!check_memory_access_align(opcode, align, + error_buf, error_buf_size)) { + goto fail; + } #if WASM_ENABLE_FAST_INTERP != 0 emit_const(mem_offset); #endif @@ -4556,12 +5677,12 @@ handle_next_reachable_block: case WASM_OP_I32_CONST: read_leb_int32(p, p_end, i32_const); - /* Currently we only track simple I32_CONST opcode. */ - is_i32_const = true; #if WASM_ENABLE_FAST_INTERP != 0 skip_label(); disable_emit = true; GET_CONST_OFFSET(VALUE_TYPE_I32, i32_const); +#else + (void)i32_const; #endif PUSH_I32(); break; @@ -4849,6 +5970,92 @@ handle_next_reachable_block: case WASM_OP_I64_TRUNC_SAT_U_F64: POP_AND_PUSH(VALUE_TYPE_F64, VALUE_TYPE_I64); break; +#if WASM_ENABLE_BULK_MEMORY != 0 + case WASM_OP_MEMORY_INIT: + read_leb_uint32(p, p_end, segment_index); +#if WASM_ENABLE_FAST_INTERP != 0 + emit_const(segment_index); +#endif + if (module->import_memory_count == 0 && module->memory_count == 0) + goto fail_unknown_memory; + + if (*p++ != 0x00) + goto fail_zero_flag_expected; + + if (segment_index >= module->data_seg_count) { + char msg[128]; + snprintf(msg, 128, "WASM loader prepare bytecode failed: " + "unknown data segment %d", segment_index); + set_error_buf(error_buf, error_buf_size, msg); + goto fail; + } + + if (module->data_seg_count1 == 0) + goto fail_data_cnt_sec_require; + + POP_I32(); + POP_I32(); + POP_I32(); + break; + case WASM_OP_DATA_DROP: + read_leb_uint32(p, p_end, segment_index); +#if WASM_ENABLE_FAST_INTERP != 0 + emit_const(segment_index); +#endif + if (segment_index >= module->data_seg_count) { + set_error_buf(error_buf, error_buf_size, + "WASM loader prepare bytecode failed: " + "unknown data segment"); + goto fail; + } + + if (module->data_seg_count1 == 0) + goto fail_data_cnt_sec_require; + + break; + case WASM_OP_MEMORY_COPY: + /* both src and dst memory index should be 0 */ + if (*(int16*)p != 0x0000) + goto fail_zero_flag_expected; + p += 2; + + if (module->import_memory_count == 0 && module->memory_count == 0) + goto fail_unknown_memory; + + POP_I32(); + POP_I32(); + POP_I32(); + break; + case WASM_OP_MEMORY_FILL: + if (*p++ != 0x00) { + goto fail_zero_flag_expected; + } + if (module->import_memory_count == 0 && module->memory_count == 0) { + goto fail_unknown_memory; + } + + POP_I32(); + POP_I32(); + POP_I32(); + break; +fail_zero_flag_expected: + set_error_buf(error_buf, error_buf_size, + "WASM loader prepare bytecode failed: " + "zero flag expected"); + goto fail; + +fail_unknown_memory: + set_error_buf(error_buf, error_buf_size, + "WASM loader prepare bytecode failed: " + "unknown memory 0"); + goto fail; +fail_data_cnt_sec_require: + set_error_buf(error_buf, error_buf_size, + "WASM loader prepare bytecode failed: " + "data count section required"); + goto fail; + /* TODO: to support bulk table operation */ +#endif /* WASM_ENABLE_BULK_MEMORY */ default: if (error_buf != NULL) snprintf(error_buf, error_buf_size, @@ -4859,7 +6066,6 @@ handle_next_reachable_block: } break; } - default: if (error_buf != NULL) snprintf(error_buf, error_buf_size, @@ -4868,9 +6074,6 @@ handle_next_reachable_block: goto fail; } - if (opcode != WASM_OP_I32_CONST) - is_i32_const = false; - #if WASM_ENABLE_FAST_INTERP != 0 last_op = opcode; #endif diff --git a/core/iwasm/interpreter/wasm_opcode.h b/core/iwasm/interpreter/wasm_opcode.h index d8a4b274f..c2cd39948 100644 --- a/core/iwasm/interpreter/wasm_opcode.h +++ b/core/iwasm/interpreter/wasm_opcode.h @@ -262,7 +262,7 @@ typedef enum WASMOpcode { WASM_OP_MISC_PREFIX = 0xfc, } WASMOpcode; -typedef enum WASMEXTOpcode { +typedef enum WASMMiscEXTOpcode { WASM_OP_I32_TRUNC_SAT_S_F32 = 0x00, WASM_OP_I32_TRUNC_SAT_U_F32 = 0x01, WASM_OP_I32_TRUNC_SAT_S_F64 = 0x02, @@ -271,7 +271,16 @@ typedef enum WASMEXTOpcode { WASM_OP_I64_TRUNC_SAT_U_F32 = 0x05, WASM_OP_I64_TRUNC_SAT_S_F64 = 0x06, WASM_OP_I64_TRUNC_SAT_U_F64 = 0x07, -} WASMEXTOpcode; +#if WASM_ENABLE_BULK_MEMORY != 0 + WASM_OP_MEMORY_INIT = 0x08, + WASM_OP_DATA_DROP = 0x09, + WASM_OP_MEMORY_COPY = 0x0a, + WASM_OP_MEMORY_FILL = 0x0b, + WASM_OP_TABLE_INIT = 0x0c, + WASM_OP_ELEM_DROP = 0x0d, + WASM_OP_TABLE_COPY = 0x0e +#endif +} WASMMiscEXTOpcode; #ifdef __cplusplus } diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index bca20e6dc..923005a4d 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -39,22 +39,46 @@ wasm_unload(WASMModule *module) wasm_loader_unload(module); } +#if WASM_ENABLE_MULTI_MODULE != 0 +static WASMModuleInstance * +get_sub_module_inst(const WASMModuleInstance *parent_module_inst, + const WASMModule *sub_module) +{ + bh_list *sub_module_inst_list = parent_module_inst->sub_module_inst_list; + WASMSubModInstNode *node = bh_list_first_elem(sub_module_inst_list); + + while (node && sub_module != node->module_inst->module) { + node = bh_list_elem_next(node); + } + return node ? node->module_inst : NULL; +} +#endif + /** * Destroy memory instances. */ static void -memories_deinstantiate(WASMMemoryInstance **memories, uint32 count) +memories_deinstantiate(WASMModuleInstance *module_inst, + WASMMemoryInstance **memories, + uint32 count) { uint32 i; if (memories) { for (i = 0; i < count; i++) if (memories[i]) { - if (memories[i]->heap_handle) +#if WASM_ENABLE_MULTI_MODULE != 0 + if (memories[i]->owner != module_inst) + continue; +#endif + if (memories[i]->heap_handle) { mem_allocator_destroy(memories[i]->heap_handle); + memories[i]->heap_handle = NULL; + } wasm_runtime_free(memories[i]); } wasm_runtime_free(memories); } + (void)module_inst; } static WASMMemoryInstance* @@ -89,8 +113,9 @@ memory_instantiate(uint32 num_bytes_per_page, bh_assert(memory->end_addr - (uint8*)memory == (uint32)total_size); /* Initialize heap */ - if (!(memory->heap_handle = mem_allocator_create - (memory->heap_data, heap_size))) { + if (heap_size > 0 + && !(memory->heap_handle = + mem_allocator_create(memory->heap_data, heap_size))) { wasm_runtime_free(memory); return NULL; } @@ -106,10 +131,10 @@ memory_instantiate(uint32 num_bytes_per_page, /** * Instantiate memories in a module. */ -static WASMMemoryInstance** +static WASMMemoryInstance ** memories_instantiate(const WASMModule *module, - uint32 heap_size, - char *error_buf, uint32 error_buf_size) + WASMModuleInstance *module_inst, + uint32 heap_size, char *error_buf, uint32 error_buf_size) { WASMImport *import; uint32 mem_index = 0, i, memory_count = @@ -132,16 +157,47 @@ memories_instantiate(const WASMModule *module, /* instantiate memories from import section */ import = module->import_memories; for (i = 0; i < module->import_memory_count; i++, import++) { - if (!(memory = memories[mem_index++] = - memory_instantiate(import->u.memory.num_bytes_per_page, - import->u.memory.init_page_count, - import->u.memory. max_page_count, - heap_size, error_buf, error_buf_size))) { - set_error_buf(error_buf, error_buf_size, - "Instantiate memory failed: " - "allocate memory failed."); - memories_deinstantiate(memories, memory_count); - return NULL; + uint32 num_bytes_per_page = import->u.memory.num_bytes_per_page; + uint32 init_page_count = import->u.memory.init_page_count; + uint32 max_page_count = import->u.memory.max_page_count; + uint32 actual_heap_size = heap_size; + +#if WASM_ENABLE_MULTI_MODULE != 0 + WASMMemoryInstance *memory_inst_linked = NULL; + if (import->u.memory.import_module != NULL) { + LOG_DEBUG("(%s, %s) is a memory of a sub-module", + import->u.memory.module_name, + import->u.memory.field_name); + + // TODO: how about native memory ? + WASMModuleInstance *module_inst_linked = + get_sub_module_inst( + module_inst, + import->u.memory.import_module); + bh_assert(module_inst_linked); + + memory_inst_linked = + wasm_lookup_memory(module_inst_linked, + import->u.memory.field_name); + bh_assert(memory_inst_linked); + + memories[mem_index++] = memory_inst_linked; + memory = memory_inst_linked; + } + else +#endif + { + if (!(memory = memories[mem_index++] = memory_instantiate( + num_bytes_per_page, init_page_count, max_page_count, + actual_heap_size, error_buf, error_buf_size))) { + set_error_buf(error_buf, error_buf_size, + "Instantiate memory failed: " + "allocate memory failed."); + memories_deinstantiate( + module_inst, + memories, memory_count); + return NULL; + } } } @@ -155,25 +211,34 @@ memories_instantiate(const WASMModule *module, set_error_buf(error_buf, error_buf_size, "Instantiate memory failed: " "allocate memory failed."); - memories_deinstantiate(memories, memory_count); + memories_deinstantiate( + module_inst, + memories, memory_count); return NULL; } +#if WASM_ENABLE_MULTI_MODULE != 0 + memory->owner = module_inst; +#endif } if (mem_index == 0) { - /* no import memory and define memory, but has global variables */ + /** + * no import memory and define memory, but still need heap + * for wasm code + */ if (!(memory = memories[mem_index++] = memory_instantiate(0, 0, 0, heap_size, error_buf, error_buf_size))) { set_error_buf(error_buf, error_buf_size, "Instantiate memory failed: " "allocate memory failed.\n"); - memories_deinstantiate(memories, memory_count); + memories_deinstantiate(module_inst, memories, memory_count); return NULL; } } bh_assert(mem_index == memory_count); + (void)module_inst; return memories; } @@ -195,8 +260,9 @@ tables_deinstantiate(WASMTableInstance **tables, uint32 count) /** * Instantiate tables in a module. */ -static WASMTableInstance** +static WASMTableInstance ** tables_instantiate(const WASMModule *module, + WASMModuleInstance *module_inst, char *error_buf, uint32 error_buf_size) { WASMImport *import; @@ -218,11 +284,35 @@ tables_instantiate(const WASMModule *module, /* instantiate tables from import section */ import = module->import_tables; for (i = 0; i < module->import_table_count; i++, import++) { - total_size = offsetof(WASMTableInstance, base_addr) + - sizeof(uint32) * (uint64)import->u.table.init_size; +#if WASM_ENABLE_MULTI_MODULE != 0 + WASMTableInstance *table_inst_linked = NULL; + WASMModuleInstance *module_inst_linked = NULL; + if (import->u.table.import_module) { + LOG_DEBUG("(%s, %s) is a table of a sub-module", + import->u.table.module_name, + import->u.memory.field_name); + + module_inst_linked = + get_sub_module_inst(module_inst, import->u.table.import_module); + bh_assert(module_inst_linked); + + table_inst_linked = wasm_lookup_table(module_inst_linked, + import->u.table.field_name); + bh_assert(table_inst_linked); + + total_size = offsetof(WASMTableInstance, base_addr); + } + else +#endif + { + /* it is a built-in table */ + total_size = offsetof(WASMTableInstance, base_addr) + + sizeof(uint32) * (uint64)import->u.table.init_size; + } + if (total_size >= UINT32_MAX || !(table = tables[table_index++] = - wasm_runtime_malloc((uint32)total_size))) { + wasm_runtime_malloc((uint32)total_size))) { set_error_buf(error_buf, error_buf_size, "Instantiate table failed: " "allocate memory failed."); @@ -232,9 +322,20 @@ tables_instantiate(const WASMModule *module, /* Set all elements to -1 to mark them as uninitialized elements */ memset(table, -1, (uint32)total_size); - table->elem_type = import->u.table.elem_type; - table->cur_size = import->u.table.init_size; - table->max_size = import->u.table.max_size; +#if WASM_ENABLE_MULTI_MODULE != 0 + table->table_inst_linked = table_inst_linked; + if (table_inst_linked != NULL) { + table->elem_type = table_inst_linked->elem_type; + table->cur_size = table_inst_linked->cur_size; + table->max_size = table_inst_linked->max_size; + } + else +#endif + { + table->elem_type = import->u.table.elem_type; + table->cur_size = import->u.table.init_size; + table->max_size = import->u.table.max_size; + } } /* instantiate tables from table section */ @@ -256,9 +357,13 @@ tables_instantiate(const WASMModule *module, table->elem_type = module->tables[i].elem_type; table->cur_size = module->tables[i].init_size; table->max_size = module->tables[i].max_size; +#if WASM_ENABLE_MULTI_MODULE != 0 + table->table_inst_linked = NULL; +#endif } bh_assert(table_index == table_count); + (void)module_inst; return tables; } @@ -276,8 +381,9 @@ functions_deinstantiate(WASMFunctionInstance *functions, uint32 count) /** * Instantiate functions in a module. */ -static WASMFunctionInstance* +static WASMFunctionInstance * functions_instantiate(const WASMModule *module, + WASMModuleInstance *module_inst, char *error_buf, uint32 error_buf_size) { WASMImport *import; @@ -301,19 +407,59 @@ functions_instantiate(const WASMModule *module, import = module->import_functions; for (i = 0; i < module->import_function_count; i++, import++) { function->is_import_func = true; - function->u.func_import = &import->u.function; - function->param_cell_num = - wasm_type_param_cell_num(import->u.function.func_type); - function->ret_cell_num = - wasm_type_return_cell_num(import->u.function.func_type); - function->local_cell_num = 0; +#if WASM_ENABLE_MULTI_MODULE != 0 + if (import->u.function.import_module) { + LOG_DEBUG("(%s, %s) is a function of a sub-module", + import->u.function.module_name, + import->u.function.field_name); - function->param_count = - (uint16)function->u.func_import->func_type->param_count; - function->local_count = 0; - function->param_types = function->u.func_import->func_type->types; - function->local_types = NULL; + function->import_module_inst = + get_sub_module_inst(module_inst, + import->u.function.import_module); + bh_assert(function->import_module_inst); + + WASMFunction *function_linked = + import->u.function.import_func_linked; + + function->u.func = function_linked; + function->import_func_inst = + wasm_lookup_function(function->import_module_inst, + import->u.function.field_name, + NULL); + bh_assert(function->import_func_inst); + + function->param_cell_num = function->u.func->param_cell_num; + function->ret_cell_num = function->u.func->ret_cell_num; + function->local_cell_num = function->u.func->local_cell_num; + function->param_count = + (uint16)function->u.func->func_type->param_count; + function->local_count = (uint16)function->u.func->local_count; + function->param_types = function->u.func->func_type->types; + function->local_types = function->u.func->local_types; + function->local_offsets = function->u.func->local_offsets; +#if WASM_ENABLE_FAST_INTERP != 0 + function->const_cell_num = function->u.func->const_cell_num; +#endif + } + else +#endif /* WASM_ENABLE_MULTI_MODULE */ + { + LOG_DEBUG("(%s, %s) is a function of native", + import->u.function.module_name, + import->u.function.field_name); + function->u.func_import = &import->u.function; + function->param_cell_num = + wasm_type_param_cell_num(import->u.function.func_type); + function->ret_cell_num = + wasm_type_return_cell_num(import->u.function.func_type); + function->param_count = + (uint16)function->u.func_import->func_type->param_count; + function->param_types = function->u.func_import->func_type->types; + function->local_cell_num = 0; + function->local_count = 0; + function->local_types = NULL; + } function++; } @@ -342,6 +488,7 @@ functions_instantiate(const WASMModule *module, } bh_assert((uint32)(function - functions) == function_count); + (void)module_inst; return functions; } @@ -355,13 +502,51 @@ globals_deinstantiate(WASMGlobalInstance *globals) wasm_runtime_free(globals); } +/** + * init_expr->u ==> init_val + */ +static bool +parse_init_expr(const InitializerExpression *init_expr, + const WASMGlobalInstance *global_inst_array, + uint32 boundary, WASMValue *init_val) +{ + if (init_expr->init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL) { + uint32 target_global_index = init_expr->u.global_index; + /** + * a global gets the init value of another global + */ + if (target_global_index >= boundary) { + LOG_DEBUG("unknown target global, %d", target_global_index); + return false; + } + + /** + * it will work if using WASMGlobalImport and WASMGlobal in + * WASMModule, but will have to face complicated cases + * + * but we still have no sure the target global has been + * initialized before + */ + WASMValue target_value = + global_inst_array[target_global_index].initial_value; + bh_memcpy_s(init_val, sizeof(WASMValue), &target_value, + sizeof(target_value)); + } + else { + bh_memcpy_s(init_val, sizeof(WASMValue), &init_expr->u, + sizeof(init_expr->u)); + } + return true; +} + /** * Instantiate globals in a module. */ -static WASMGlobalInstance* +static WASMGlobalInstance * globals_instantiate(const WASMModule *module, - uint32 *p_global_data_size, - char *error_buf, uint32 error_buf_size) + WASMModuleInstance *module_inst, + uint32 *p_global_data_size, char *error_buf, + uint32 error_buf_size) { WASMImport *import; uint32 global_data_offset = 0; @@ -387,7 +572,45 @@ globals_instantiate(const WASMModule *module, WASMGlobalImport *global_import = &import->u.global; global->type = global_import->type; global->is_mutable = global_import->is_mutable; - global->initial_value = global_import->global_data_linked; +#if WASM_ENABLE_MULTI_MODULE != 0 + if (global_import->import_module) { + WASMModuleInstance *sub_module_inst = get_sub_module_inst( + module_inst, global_import->import_module); + bh_assert(sub_module_inst); + + WASMGlobalInstance *global_inst_linked = + wasm_lookup_global(sub_module_inst, global_import->field_name); + bh_assert(global_inst_linked); + + global->import_global_inst = global_inst_linked; + global->import_module_inst = sub_module_inst; + + /** + * although, actually don't need initial_value for an imported + * global, we keep it here like a place holder because of + * global-data and + * (global $g2 i32 (global.get $g1)) + */ + WASMGlobal *linked_global = global_import->import_global_linked; + InitializerExpression *linked_init_expr = + &(linked_global->init_expr); + + bool ret = parse_init_expr( + linked_init_expr, + sub_module_inst->globals, + sub_module_inst->global_count, &(global->initial_value)); + if (!ret) { + set_error_buf(error_buf, error_buf_size, + "Instantiate global failed: unknown global."); + return NULL; + } + } + else +#endif + { + /* native globals share their initial_values in one module */ + global->initial_value = global_import->global_data_linked; + } global->data_offset = global_data_offset; global_data_offset += wasm_value_type_size(global->type); @@ -396,44 +619,69 @@ globals_instantiate(const WASMModule *module, /* instantiate globals from global section */ for (i = 0; i < module->global_count; i++) { + bool ret = false; + uint32 global_count = + module->import_global_count + module->global_count; + InitializerExpression *init_expr = &(module->globals[i].init_expr); + global->type = module->globals[i].type; global->is_mutable = module->globals[i].is_mutable; - global->data_offset = global_data_offset; + global_data_offset += wasm_value_type_size(global->type); + /** + * first init, it might happen that the target global instance + * has not been initialize yet + */ + if (init_expr->init_expr_type != INIT_EXPR_TYPE_GET_GLOBAL) { + ret = + parse_init_expr(init_expr, globals, global_count, + &(global->initial_value)); + if (!ret) { + set_error_buf(error_buf, error_buf_size, + "Instantiate global failed: unknown global."); + return NULL; + } + } global++; } bh_assert((uint32)(global - globals) == global_count); *p_global_data_size = global_data_offset; + (void)module_inst; return globals; } static bool globals_instantiate_fix(WASMGlobalInstance *globals, const WASMModule *module, - WASMModuleInstance *module_inst, char *error_buf, uint32 error_buf_size) { WASMGlobalInstance *global = globals; uint32 i; + uint32 global_count = module->import_global_count + module->global_count; + /** + * second init, only target global instances from global + * (ignore import_global) + * to fix skipped init_value in the previous round + * hope two rounds are enough but how about a chain ? + */ for (i = 0; i < module->global_count; i++) { + bool ret = false; InitializerExpression *init_expr = &module->globals[i].init_expr; if (init_expr->init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL) { - if (init_expr->u.global_index >= module->import_global_count + i) { + ret = parse_init_expr(init_expr, globals, global_count, + &global->initial_value); + if (!ret) { set_error_buf(error_buf, error_buf_size, "Instantiate global failed: unknown global."); return false; } - global->initial_value = globals[init_expr->u.global_index].initial_value; - } - else { - bh_memcpy_s(&global->initial_value, sizeof(WASMValue), - &init_expr->u, sizeof(init_expr->u)); } + global++; } return true; @@ -443,13 +691,13 @@ globals_instantiate_fix(WASMGlobalInstance *globals, * Return export function count in module export section. */ static uint32 -get_export_function_count(const WASMModule *module) +get_export_count(const WASMModule *module, uint8 kind) { WASMExport *export = module->exports; uint32 count = 0, i; for (i = 0; i < module->export_count; i++, export++) - if (export->kind == EXPORT_KIND_FUNC) + if (export->kind == kind) count++; return count; @@ -500,6 +748,48 @@ export_functions_instantiate(const WASMModule *module, return export_funcs; } +#if WASM_ENABLE_MULTI_MODULE != 0 +static void +export_globals_deinstantiate(WASMExportGlobInstance *globals) +{ + if (globals) + wasm_runtime_free(globals); +} + +static WASMExportGlobInstance * +export_globals_instantiate(const WASMModule *module, + WASMModuleInstance *module_inst, + uint32 export_glob_count, char *error_buf, + uint32 error_buf_size) +{ + WASMExportGlobInstance *export_globals, *export_global; + WASMExport *export = module->exports; + uint32 i; + uint64 total_size = sizeof(WASMExportGlobInstance) * (uint64)export_glob_count; + + if (total_size >= UINT32_MAX + || !(export_global = export_globals = + wasm_runtime_malloc((uint32)total_size))) { + set_error_buf(error_buf, error_buf_size, + "Instantiate export global failed: " + "allocate memory failed."); + return NULL; + } + + memset(export_globals, 0, (uint32)total_size); + + for (i = 0; i < module->export_count; i++, export++) + if (export->kind == EXPORT_KIND_GLOBAL) { + export_global->name = export->name; + export_global->global = &module_inst->globals[export->index]; + export_global++; + } + + bh_assert((uint32)(export_global - export_globals) == export_glob_count); + return export_globals; +} +#endif + static bool execute_post_inst_function(WASMModuleInstance *module_inst) { @@ -541,6 +831,66 @@ execute_start_function(WASMModuleInstance *module_inst) return wasm_create_exec_env_and_call_function(module_inst, func, 0, NULL); } +#if WASM_ENABLE_MULTI_MODULE != 0 +static bool +sub_module_instantiate(WASMModule *module, WASMModuleInstance *module_inst, + uint32 stack_size, uint32 heap_size, char *error_buf, + uint32 error_buf_size) +{ + bh_list *sub_module_inst_list = module_inst->sub_module_inst_list; + WASMRegisteredModule *sub_module_list_node = + bh_list_first_elem(module->import_module_list); + + while (sub_module_list_node) { + WASMModule *sub_module = (WASMModule*)sub_module_list_node->module; + WASMModuleInstance *sub_module_inst = wasm_instantiate( + sub_module, stack_size, heap_size, error_buf, error_buf_size); + if (!sub_module_inst) { + LOG_DEBUG("instantiate %s failed", + sub_module_list_node->module_name); + set_error_buf_v(error_buf, error_buf_size, "instantiate %s failed", + sub_module_list_node->module_name); + return false; + } + + WASMSubModInstNode *sub_module_inst_list_node = + wasm_runtime_malloc(sizeof(WASMSubModInstNode)); + if (!sub_module_inst_list_node) { + LOG_DEBUG("Malloc WASMSubModInstNode failed, SZ:%d", + sizeof(WASMSubModInstNode)); + set_error_buf_v(error_buf, error_buf_size, "malloc failed"); + wasm_deinstantiate(sub_module_inst); + return false; + } + + sub_module_inst_list_node->module_inst = sub_module_inst; + sub_module_inst_list_node->module_name = + sub_module_list_node->module_name; + bh_list_status ret = + bh_list_insert(sub_module_inst_list, sub_module_inst_list_node); + bh_assert(BH_LIST_SUCCESS == ret); + (void)ret; + + sub_module_list_node = bh_list_elem_next(sub_module_list_node); + } + + return true; +} + +static void +sub_module_deinstantiate(WASMModuleInstance *module_inst) +{ + bh_list *list = module_inst->sub_module_inst_list; + WASMSubModInstNode *node = bh_list_first_elem(list); + while (node) { + WASMSubModInstNode *next_node = bh_list_elem_next(node); + bh_list_remove(list, node); + wasm_deinstantiate(node->module_inst); + node = next_node; + } +} +#endif + /** * Instantiate module */ @@ -550,14 +900,13 @@ wasm_instantiate(WASMModule *module, char *error_buf, uint32 error_buf_size) { WASMModuleInstance *module_inst; - WASMTableSeg *table_seg; - WASMDataSeg *data_seg; WASMGlobalInstance *globals = NULL, *global; - uint32 global_count, global_data_size = 0, i, j; - uint32 base_offset, length, memory_size; + uint32 global_count, global_data_size = 0, i; + uint32 base_offset, length; uint8 *global_data, *global_data_end; - uint8 *memory_data; - uint32 *table_data; +#if WASM_ENABLE_MULTI_MODULE != 0 + bool ret = false; +#endif if (!module) return NULL; @@ -571,23 +920,38 @@ wasm_instantiate(WASMModule *module, if (heap_size > APP_HEAP_SIZE_MAX) heap_size = APP_HEAP_SIZE_MAX; - /* Instantiate global firstly to get the mutable data size */ - global_count = module->import_global_count + module->global_count; - if (global_count && - !(globals = globals_instantiate(module, - &global_data_size, - error_buf, error_buf_size))) - return NULL; - /* Allocate the memory */ if (!(module_inst = wasm_runtime_malloc((uint32)sizeof(WASMModuleInstance)))) { set_error_buf(error_buf, error_buf_size, "Instantiate module failed: allocate memory failed."); - globals_deinstantiate(globals); return NULL; } + LOG_DEBUG("Instantiate a module %p -> %p", module, module_inst); + memset(module_inst, 0, (uint32)sizeof(WASMModuleInstance)); + +#if WASM_ENABLE_MULTI_MODULE != 0 + module_inst->sub_module_inst_list = + &module_inst->sub_module_inst_list_head; + ret = sub_module_instantiate(module, module_inst, stack_size, heap_size, + error_buf, error_buf_size); + if (!ret) { + LOG_DEBUG("build a sub module list failed"); + wasm_deinstantiate(module_inst); + return NULL; + } +#endif + + /* Instantiate global firstly to get the mutable data size */ + global_count = module->import_global_count + module->global_count; + if (global_count && !(globals = globals_instantiate( + module, + module_inst, + &global_data_size, error_buf, error_buf_size))) { + wasm_deinstantiate(module_inst); + return NULL; + } module_inst->global_count = global_count; module_inst->globals = globals; @@ -597,7 +961,14 @@ wasm_instantiate(WASMModule *module, module->import_table_count + module->table_count; module_inst->function_count = module->import_function_count + module->function_count; - module_inst->export_func_count = get_export_function_count(module); + + /* export */ + module_inst->export_func_count = get_export_count(module, EXPORT_KIND_FUNC); +#if WASM_ENABLE_MULTI_MODULE != 0 + module_inst->export_tab_count = get_export_count(module, EXPORT_KIND_TABLE); + module_inst->export_mem_count = get_export_count(module, EXPORT_KIND_MEMORY); + module_inst->export_glob_count = get_export_count(module, EXPORT_KIND_GLOBAL); +#endif if (global_count > 0) { if (!(module_inst->global_data = @@ -611,27 +982,40 @@ wasm_instantiate(WASMModule *module, /* Instantiate memories/tables/functions */ if ((module_inst->memory_count > 0 && !(module_inst->memories = - memories_instantiate(module, heap_size, - error_buf, error_buf_size))) + memories_instantiate(module, + module_inst, + heap_size, error_buf, error_buf_size))) || (module_inst->table_count > 0 - && !(module_inst->tables = tables_instantiate(module, - error_buf, - error_buf_size))) + && !(module_inst->tables = + tables_instantiate(module, + module_inst, + error_buf, error_buf_size))) || (module_inst->function_count > 0 - && !(module_inst->functions = functions_instantiate(module, - error_buf, - error_buf_size))) + && !(module_inst->functions = + functions_instantiate(module, + module_inst, + error_buf, error_buf_size))) || (module_inst->export_func_count > 0 && !(module_inst->export_functions = export_functions_instantiate( - module, module_inst, module_inst->export_func_count, - error_buf, error_buf_size)))) { + module, module_inst, module_inst->export_func_count, + error_buf, error_buf_size))) +#if WASM_ENABLE_MULTI_MODULE != 0 + || (module_inst->export_glob_count > 0 + && !(module_inst->export_globals = export_globals_instantiate( + module, module_inst, module_inst->export_glob_count, + error_buf, error_buf_size))) +#endif + ) { wasm_deinstantiate(module_inst); return NULL; } if (global_count > 0) { - /* fix globals */ - if (!globals_instantiate_fix(globals, module, module_inst, + /** + * since there might be some globals are not instantiate the first + * instantiate round + */ + if (!globals_instantiate_fix(globals, module, error_buf, error_buf_size)) { wasm_deinstantiate(module_inst); return NULL; @@ -659,97 +1043,137 @@ wasm_instantiate(WASMModule *module, } } bh_assert(global_data == global_data_end); - } - if (module_inst->memory_count) { - WASMMemoryInstance *memory; + /* Initialize the memory data with data segment section */ + module_inst->default_memory = + module_inst->memory_count ? module_inst->memories[0] : NULL; - memory = module_inst->default_memory = module_inst->memories[0]; - memory_data = module_inst->default_memory->memory_data; + for (i = 0; i < module->data_seg_count; i++) { + WASMMemoryInstance *memory = NULL; + uint8 *memory_data = NULL; + uint32 memory_size = 0; + WASMDataSeg *data_seg = module->data_segments[i]; - /* Initialize the memory data with data segment section */ - if (memory->cur_page_count > 0) { - for (i = 0; i < module->data_seg_count; i++) { - data_seg = module->data_segments[i]; - bh_assert(data_seg->memory_index == 0); - bh_assert(data_seg->base_offset.init_expr_type == - INIT_EXPR_TYPE_I32_CONST - || data_seg->base_offset.init_expr_type == - INIT_EXPR_TYPE_GET_GLOBAL); +#if WASM_ENABLE_BULK_MEMORY != 0 + if (data_seg->is_passive) + continue; +#endif - if (data_seg->base_offset.init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL) { - bh_assert(data_seg->base_offset.u.global_index < global_count - && globals[data_seg->base_offset.u.global_index].type == - VALUE_TYPE_I32); - data_seg->base_offset.u.i32 = - globals[data_seg->base_offset.u.global_index].initial_value.i32; - } + /* has check it in loader */ + memory = module_inst->memories[data_seg->memory_index]; + bh_assert(memory); - base_offset = (uint32)data_seg->base_offset.u.i32; - length = data_seg->data_length; - memory_size = memory->num_bytes_per_page - * memory->cur_page_count; + memory_data = memory->memory_data; + bh_assert(memory_data); - if (length > 0 - && (base_offset >= memory_size - || base_offset + length > memory_size)) { - set_error_buf(error_buf, error_buf_size, - "Instantiate module failed: data segment does not fit."); - wasm_deinstantiate(module_inst); - return NULL; - } + memory_size = memory->num_bytes_per_page * memory->cur_page_count; - bh_memcpy_s(memory_data + base_offset, memory_size - base_offset, - data_seg->data, length); - } + bh_assert(data_seg->base_offset.init_expr_type + == INIT_EXPR_TYPE_I32_CONST + || data_seg->base_offset.init_expr_type + == INIT_EXPR_TYPE_GET_GLOBAL); + + if (data_seg->base_offset.init_expr_type + == INIT_EXPR_TYPE_GET_GLOBAL) { + bh_assert(data_seg->base_offset.u.global_index < global_count + && globals[data_seg->base_offset.u.global_index].type + == VALUE_TYPE_I32); + data_seg->base_offset.u.i32 = + globals[data_seg->base_offset.u.global_index] + .initial_value.i32; } + + /* check offset since length might negative */ + base_offset = (uint32)data_seg->base_offset.u.i32; + if (base_offset > memory_size) { + LOG_DEBUG("base_offset(%d) > memory_size(%d)", base_offset, + memory_size); + set_error_buf(error_buf, error_buf_size, + "data segment does not fit."); + wasm_deinstantiate(module_inst); + return NULL; + } + + /* check offset + length(could be zero) */ + length = data_seg->data_length; + if (base_offset + length > memory_size) { + LOG_DEBUG("base_offset(%d) + length(%d) > memory_size(%d)", + base_offset, length, memory_size); + set_error_buf( + error_buf, error_buf_size, + "Instantiate module failed: data segment does not fit."); + wasm_deinstantiate(module_inst); + return NULL; + } + + bh_memcpy_s(memory_data + base_offset, memory_size - base_offset, + data_seg->data, length); } - if (module_inst->table_count) { - module_inst->default_table = module_inst->tables[0]; + /* Initialize the table data with table segment section */ + module_inst->default_table = + module_inst->table_count ? module_inst->tables[0] : NULL; + for (i = 0; i < module->table_seg_count; i++) { + WASMTableSeg *table_seg = module->table_segments + i; + /* has check it in loader */ + WASMTableInstance *table = module_inst->tables[table_seg->table_index]; + bh_assert(table); - /* Initialize the table data with table segment section */ - table_data = (uint32*)module_inst->default_table->base_addr; - table_seg = module->table_segments; - for (i = 0; i < module->table_seg_count; i++, table_seg++) { - bh_assert(table_seg->table_index == 0); - bh_assert(table_seg->base_offset.init_expr_type == - INIT_EXPR_TYPE_I32_CONST - || table_seg->base_offset.init_expr_type == - INIT_EXPR_TYPE_GET_GLOBAL); + uint32 *table_data = (uint32 *)table->base_addr; +#if WASM_ENABLE_MULTI_MODULE != 0 + table_data = table->table_inst_linked + ? (uint32 *)table->table_inst_linked->base_addr + : table_data; +#endif + bh_assert(table_data); - if (table_seg->base_offset.init_expr_type == - INIT_EXPR_TYPE_GET_GLOBAL) { - bh_assert(table_seg->base_offset.u.global_index < global_count - && globals[table_seg->base_offset.u.global_index].type == - VALUE_TYPE_I32); - table_seg->base_offset.u.i32 = - globals[table_seg->base_offset.u.global_index].initial_value.i32; - } - if ((uint32)table_seg->base_offset.u.i32 < - module_inst->default_table->cur_size) { - length = table_seg->function_count; - if ((uint32)table_seg->base_offset.u.i32 + length > - module_inst->default_table->cur_size) - length = module_inst->default_table->cur_size - - (uint32)table_seg->base_offset.u.i32; - /* Check function index */ - for (j = 0; j < length; j++) { - if (table_seg->func_indexes[j] >= module_inst->function_count) { - set_error_buf(error_buf, error_buf_size, - "WASM instantiate failed: unknown function"); - wasm_deinstantiate(module_inst); - return NULL; - } - } - bh_memcpy_s(table_data + table_seg->base_offset.u.i32, - (uint32)((module_inst->default_table->cur_size - - (uint32)table_seg->base_offset.u.i32) - * sizeof(uint32)), - table_seg->func_indexes, (uint32)(length * sizeof(uint32))); - } + /* init vec(funcidx) */ + bh_assert(table_seg->base_offset.init_expr_type + == INIT_EXPR_TYPE_I32_CONST + || table_seg->base_offset.init_expr_type + == INIT_EXPR_TYPE_GET_GLOBAL); + + if (table_seg->base_offset.init_expr_type + == INIT_EXPR_TYPE_GET_GLOBAL) { + bh_assert(table_seg->base_offset.u.global_index < global_count + && globals[table_seg->base_offset.u.global_index].type + == VALUE_TYPE_I32); + table_seg->base_offset.u.i32 = + globals[table_seg->base_offset.u.global_index].initial_value.i32; } + + /* check offset since length might negative */ + if ((uint32)table_seg->base_offset.u.i32 > table->cur_size) { + LOG_DEBUG("base_offset(%d) > table->cur_size(%d)", + table_seg->base_offset.u.i32, table->cur_size); + set_error_buf(error_buf, error_buf_size, + "elements segment does not fit"); + wasm_deinstantiate(module_inst); + return NULL; + } + + /* check offset + length(could be zero) */ + length = table_seg->function_count; + if ((uint32)table_seg->base_offset.u.i32 + length > table->cur_size) { + LOG_DEBUG("base_offset(%d) + length(%d)> table->cur_size(%d)", + table_seg->base_offset.u.i32, length, table->cur_size); + set_error_buf(error_buf, error_buf_size, + "elements segment does not fit"); + wasm_deinstantiate(module_inst); + return NULL; + } + + /** + * Check function index in the current module inst for now. + * will check the linked table inst owner in future. + * so loader check is enough + */ + bh_memcpy_s( + table_data + table_seg->base_offset.u.i32, + (uint32)((table->cur_size - (uint32)table_seg->base_offset.u.i32) + * sizeof(uint32)), + table_seg->func_indexes, (uint32)(length * sizeof(uint32))); } #if WASM_ENABLE_LIBC_WASI != 0 @@ -808,6 +1232,10 @@ wasm_deinstantiate(WASMModuleInstance *module_inst) if (!module_inst) return; +#if WASM_ENABLE_MULTI_MODULE != 0 + sub_module_deinstantiate(module_inst); +#endif + #if WASM_ENABLE_LIBC_WASI != 0 /* Destroy wasi resource before freeing app heap, since some fields of wasi contex are allocated from app heap, and if app heap is freed, @@ -817,12 +1245,17 @@ wasm_deinstantiate(WASMModuleInstance *module_inst) #endif if (module_inst->memory_count > 0) - memories_deinstantiate(module_inst->memories, module_inst->memory_count); + memories_deinstantiate( + module_inst, + module_inst->memories, module_inst->memory_count); tables_deinstantiate(module_inst->tables, module_inst->table_count); functions_deinstantiate(module_inst->functions, module_inst->function_count); globals_deinstantiate(module_inst->globals); export_functions_deinstantiate(module_inst->export_functions); +#if WASM_ENABLE_MULTI_MODULE != 0 + export_globals_deinstantiate(module_inst->export_globals); +#endif if (module_inst->global_data) wasm_runtime_free(module_inst->global_data); @@ -842,6 +1275,40 @@ wasm_lookup_function(const WASMModuleInstance *module_inst, return NULL; } +#if WASM_ENABLE_MULTI_MODULE != 0 +WASMGlobalInstance * +wasm_lookup_global(const WASMModuleInstance *module_inst, const char *name) +{ + uint32 i; + for (i = 0; i < module_inst->export_glob_count; i++) + if (!strcmp(module_inst->export_globals[i].name, name)) + return module_inst->export_globals[i].global; + return NULL; +} + +WASMMemoryInstance * +wasm_lookup_memory(const WASMModuleInstance *module_inst, const char *name) +{ + /** + * using a strong assumption that one module instance only has + * one memory instance + */ + (void)module_inst->export_memories; + return module_inst->memories[0]; +} + +WASMTableInstance * +wasm_lookup_table(const WASMModuleInstance *module_inst, const char *name) +{ + /** + * using a strong assumption that one module instance only has + * one table instance + */ + (void)module_inst->export_tables; + return module_inst->tables[0]; +} +#endif + bool wasm_call_function(WASMExecEnv *exec_env, WASMFunctionInstance *function, @@ -1141,14 +1608,28 @@ wasm_call_indirect(WASMExecEnv *exec_env, goto got_exception; } + /** + * please be aware that table_inst->base_addr may point + * to another module's table + **/ function_indices = ((uint32_t*)table_inst->base_addr)[element_indices]; if (function_indices == 0xFFFFFFFF) { wasm_set_exception(module_inst, "uninitialized element"); goto got_exception; } + /** + * we insist to call functions owned by the module itself + **/ + if (function_indices >= module_inst->function_count) { + wasm_set_exception(module_inst, "unknown function"); + goto got_exception; + } + function_inst = module_inst->functions + function_indices; + wasm_interp_call_wasm(module_inst, exec_env, function_inst, argc, argv); + return !wasm_get_exception(module_inst) ? true : false; got_exception: diff --git a/core/iwasm/interpreter/wasm_runtime.h b/core/iwasm/interpreter/wasm_runtime.h index 03268e63d..6b3882b3e 100644 --- a/core/iwasm/interpreter/wasm_runtime.h +++ b/core/iwasm/interpreter/wasm_runtime.h @@ -15,6 +15,12 @@ extern "C" { #endif +typedef struct WASMModuleInstance WASMModuleInstance; +typedef struct WASMFunctionInstance WASMFunctionInstance; +typedef struct WASMMemoryInstance WASMMemoryInstance; +typedef struct WASMTableInstance WASMTableInstance; +typedef struct WASMGlobalInstance WASMGlobalInstance; + typedef struct WASMMemoryInstance { /* Number bytes per page */ uint32 num_bytes_per_page; @@ -36,6 +42,10 @@ typedef struct WASMMemoryInstance { /* End address of memory */ uint8 *end_addr; +#if WASM_ENABLE_MULTI_MODULE != 0 + /* to indicate which module instance create it */ + WASMModuleInstance *owner; +#endif /* Base address, the layout is: heap_data + memory data memory data init size is: num_bytes_per_page * cur_page_count @@ -52,6 +62,10 @@ typedef struct WASMTableInstance { uint32 cur_size; /* Maximum size */ uint32 max_size; +#if WASM_ENABLE_MULTI_MODULE != 0 + /* just for import, keep the reference here */ + WASMTableInstance *table_inst_linked; +#endif /* Base address */ uint8 base_addr[1]; } WASMTableInstance; @@ -65,6 +79,11 @@ typedef struct WASMGlobalInstance { uint32 data_offset; /* initial value */ WASMValue initial_value; +#if WASM_ENABLE_MULTI_MODULE != 0 + /* just for import, keep the reference here */ + WASMModuleInstance *import_module_inst; + WASMGlobalInstance *import_global_inst; +#endif } WASMGlobalInstance; typedef struct WASMFunctionInstance { @@ -93,6 +112,10 @@ typedef struct WASMFunctionInstance { WASMFunctionImport *func_import; WASMFunction *func; } u; +#if WASM_ENABLE_MULTI_MODULE != 0 + WASMModuleInstance *import_module_inst; + WASMFunctionInstance *import_func_inst; +#endif } WASMFunctionInstance; typedef struct WASMExportFuncInstance { @@ -100,6 +123,23 @@ typedef struct WASMExportFuncInstance { WASMFunctionInstance *function; } WASMExportFuncInstance; +#if WASM_ENABLE_MULTI_MODULE != 0 +typedef struct WASMExportGlobInstance { + char *name; + WASMGlobalInstance *global; +} WASMExportGlobInstance; + +typedef struct WASMExportTabInstance { + char *name; + WASMTableInstance *table; +} WASMExportTabInstance; + +typedef struct WASMExportMemInstance { + char *name; + WASMMemoryInstance *memory; +} WASMExportMemInstance; +#endif + typedef struct WASMModuleInstance { /* Module instance type, for module instance loaded from WASM bytecode binary, this field is Wasm_Module_Bytecode; @@ -112,13 +152,25 @@ typedef struct WASMModuleInstance { uint32 table_count; uint32 global_count; uint32 function_count; + uint32 export_func_count; +#if WASM_ENABLE_MULTI_MODULE != 0 + uint32 export_glob_count; + uint32 export_mem_count; + uint32 export_tab_count; +#endif WASMMemoryInstance **memories; WASMTableInstance **tables; WASMGlobalInstance *globals; WASMFunctionInstance *functions; + WASMExportFuncInstance *export_functions; +#if WASM_ENABLE_MULTI_MODULE != 0 + WASMExportGlobInstance *export_globals; + WASMExportMemInstance *export_memories; + WASMExportTabInstance *export_tables; +#endif WASMMemoryInstance *default_memory; WASMTableInstance *default_table; @@ -148,11 +200,26 @@ typedef struct WASMModuleInstance { /* Main exec env */ WASMExecEnv *main_exec_env; + +#if WASM_ENABLE_MULTI_MODULE != 0 + // TODO: mutex ? mutli-threads ? + bh_list sub_module_inst_list_head; + bh_list *sub_module_inst_list; +#endif } WASMModuleInstance; struct WASMInterpFrame; typedef struct WASMInterpFrame WASMRuntimeFrame; +#if WASM_ENABLE_MULTI_MODULE != 0 +typedef struct WASMSubModInstNode { + bh_list_link l; + /* point to a string pool */ + const char *module_name; + WASMModuleInstance *module_inst; +} WASMSubModInstNode; +#endif + /** * Return the code block of a function. * @@ -182,10 +249,11 @@ wasm_get_func_code_end(WASMFunctionInstance *func) { #if WASM_ENABLE_FAST_INTERP == 0 return func->is_import_func - ? NULL : func->u.func->code + func->u.func->code_size; + ? NULL : func->u.func->code + func->u.func->code_size; #else return func->is_import_func - ? NULL : func->u.func->code_compiled + func->u.func->code_compiled_size; + ? NULL + : func->u.func->code_compiled + func->u.func->code_compiled_size; #endif } @@ -212,6 +280,17 @@ WASMFunctionInstance * wasm_lookup_function(const WASMModuleInstance *module_inst, const char *name, const char *signature); +#if WASM_ENABLE_MULTI_MODULE != 0 +WASMGlobalInstance * +wasm_lookup_global(const WASMModuleInstance *module_inst, const char *name); + +WASMMemoryInstance * +wasm_lookup_memory(const WASMModuleInstance *module_inst, const char *name); + +WASMTableInstance * +wasm_lookup_table(const WASMModuleInstance *module_inst, const char *name); +#endif + bool wasm_call_function(WASMExecEnv *exec_env, WASMFunctionInstance *function, diff --git a/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c b/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c index 76f821ad8..88ebc0131 100644 --- a/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c +++ b/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c @@ -1098,7 +1098,7 @@ static NativeSymbol native_symbols_spectest[] = { REG_NATIVE_FUNC(print, "()"), REG_NATIVE_FUNC(print_i32, "(i)"), REG_NATIVE_FUNC(print_i32_f32, "(if)"), - REG_NATIVE_FUNC(print_f64_f64, "(fF)"), + REG_NATIVE_FUNC(print_f64_f64, "(FF)"), REG_NATIVE_FUNC(print_f32, "(f)"), REG_NATIVE_FUNC(print_f64, "(F)") }; diff --git a/core/shared/platform/common/posix/posix_memmap.c b/core/shared/platform/common/posix/posix_memmap.c index 7cf83f44d..7625cf66a 100644 --- a/core/shared/platform/common/posix/posix_memmap.c +++ b/core/shared/platform/common/posix/posix_memmap.c @@ -11,13 +11,11 @@ os_mmap(void *hint, uint32 size, int prot, int flags) int map_prot = PROT_NONE; int map_flags = MAP_ANONYMOUS | MAP_PRIVATE; uint64 request_size, page_size; - uint8 *addr, *addr_aligned; + uint8 *addr; uint32 i; - /* align to 2M if no less than 2M, else align to 4K */ - page_size = size < 2 * 1024 * 1024 ? 4096 : 2 * 1024 * 1024; + page_size = getpagesize(); request_size = (size + page_size - 1) & ~(page_size - 1); - request_size += page_size; if (request_size >= UINT32_MAX) return NULL; @@ -47,43 +45,25 @@ os_mmap(void *hint, uint32 size, int prot, int flags) if (addr != MAP_FAILED) break; } + if (addr == MAP_FAILED) return NULL; - addr_aligned = (uint8*)(uintptr_t) - (((uint64)(uintptr_t)addr + page_size - 1) & ~(page_size - 1)); - - /* Unmap memory allocated before the aligned base address */ - if (addr != addr_aligned) { - uint32 prefix_size = (uint32)(addr_aligned - addr); - munmap(addr, prefix_size); - request_size -= prefix_size; - } - - /* Unmap memory allocated after the potentially unaligned end */ - if (size != request_size) { - uint32 suffix_size = (uint32)(request_size - size); - munmap(addr_aligned + size, suffix_size); - request_size -= size; - } - -#ifndef __APPLE__ - if (size >= 2 * 1024 * 1024) { - /* Try to use huge page to improve performance */ - if (!madvise(addr, size, MADV_HUGEPAGE)) - /* make huge page become effective */ - memset(addr, 0, size); - } -#endif - - return addr_aligned; + return addr; } void os_munmap(void *addr, uint32 size) { - if (addr) - munmap(addr, size); + uint64 page_size = getpagesize(); + uint64 request_size = (size + page_size - 1) & ~(page_size - 1); + + if (addr) { + if (munmap(addr, request_size)) { + os_printf("os_munmap error addr:%p, size:0x%lx, errno:%d\n", + addr, request_size, errno); + } + } } int diff --git a/core/shared/platform/common/posix/posix_thread.c b/core/shared/platform/common/posix/posix_thread.c index 9c0cf3835..e2d45b450 100644 --- a/core/shared/platform/common/posix/posix_thread.c +++ b/core/shared/platform/common/posix/posix_thread.c @@ -249,5 +249,4 @@ uint8 *os_thread_get_stack_boundary() #endif return addr; -} - +} \ No newline at end of file diff --git a/core/shared/platform/linux-sgx/sgx_platform.c b/core/shared/platform/linux-sgx/sgx_platform.c index 08aa37c36..e52df1da5 100644 --- a/core/shared/platform/linux-sgx/sgx_platform.c +++ b/core/shared/platform/linux-sgx/sgx_platform.c @@ -82,29 +82,39 @@ int os_vprintf(const char * format, va_list arg) return 0; } -void* os_mmap(void *hint, unsigned int size, int prot, int flags) +void* os_mmap(void *hint, uint32 size, int prot, int flags) { #if WASM_ENABLE_AOT != 0 int mprot = 0; - unsigned alignedSize = (size+4095) & (unsigned)~4095; //Page aligned + uint64 aligned_size, page_size; void* ret = NULL; sgx_status_t st = 0; - ret = sgx_alloc_rsrv_mem(alignedSize); + page_size = getpagesize(); + aligned_size = (size + page_size - 1) & ~(page_size - 1); + + if (aligned_size >= UINT32_MAX) + return NULL; + + ret = sgx_alloc_rsrv_mem(aligned_size); if (ret == NULL) { - os_printf("os_mmap(size=%d, alignedSize=%d, prot=0x%x) failed.",size, alignedSize, prot); + os_printf("os_mmap(size=%u, aligned size=%lu, prot=0x%x) failed.", + size, aligned_size, prot); return NULL; } + if (prot & MMAP_PROT_READ) mprot |= SGX_PROT_READ; if (prot & MMAP_PROT_WRITE) mprot |= SGX_PROT_WRITE; if (prot & MMAP_PROT_EXEC) mprot |= SGX_PROT_EXEC; - st = sgx_tprotect_rsrv_mem(ret, alignedSize, mprot); - if (st != SGX_SUCCESS){ - os_printf("os_mmap(size=%d,prot=0x%x) failed to set protect.",size, prot); - sgx_free_rsrv_mem(ret, alignedSize); + + st = sgx_tprotect_rsrv_mem(ret, aligned_size, mprot); + if (st != SGX_SUCCESS) { + os_printf("os_mmap(size=%u, prot=0x%x) failed to set protect.", + size, prot); + sgx_free_rsrv_mem(ret, aligned_size); return NULL; } @@ -117,7 +127,11 @@ void* os_mmap(void *hint, unsigned int size, int prot, int flags) void os_munmap(void *addr, uint32 size) { #if WASM_ENABLE_AOT != 0 - sgx_free_rsrv_mem(addr, size); + uint64 aligned_size, page_size; + + page_size = getpagesize(); + aligned_size = (size + page_size - 1) & ~(page_size - 1); + sgx_free_rsrv_mem(addr, aligned_size); #endif } @@ -135,7 +149,8 @@ int os_mprotect(void *addr, uint32 size, int prot) mprot |= SGX_PROT_EXEC; st = sgx_tprotect_rsrv_mem(addr, size, mprot); if (st != SGX_SUCCESS) - os_printf("os_mprotect(addr=0x%lx,size=%d,prot=0x%x) failed.", addr, size, prot); + os_printf("os_mprotect(addr=0x%lx, size=%u, prot=0x%x) failed.", + addr, size, prot); return (st == SGX_SUCCESS? 0:-1); #else diff --git a/core/shared/utils/bh_common.c b/core/shared/utils/bh_common.c index a3f47a52d..44bdbed1b 100644 --- a/core/shared/utils/bh_common.c +++ b/core/shared/utils/bh_common.c @@ -32,6 +32,26 @@ b_memcpy_s(void * s1, unsigned int s1max, return 0; } +int b_memmove_s(void * s1, unsigned int s1max, + const void * s2, unsigned int n) +{ + char *dest = (char*)s1; + char *src = (char*)s2; + if (n == 0) { + return 0; + } + + if (s1 == NULL || s1max > RSIZE_MAX) { + return -1; + } + if (s2 == NULL || n > s1max) { + memset(dest, 0, s1max); + return -1; + } + memmove(dest, src, n); + return 0; +} + int b_strcat_s(char * s1, unsigned int s1max, const char * s2) { diff --git a/core/shared/utils/bh_common.h b/core/shared/utils/bh_common.h index 682e3d2e3..cd3bcdacf 100644 --- a/core/shared/utils/bh_common.h +++ b/core/shared/utils/bh_common.h @@ -18,6 +18,12 @@ extern "C" { bh_assert (_ret == 0); \ } while (0) +#define bh_memmove_s(dest, dlen, src, slen) do { \ + int _ret = slen == 0 ? 0 : b_memmove_s (dest, dlen, src, slen); \ + (void)_ret; \ + bh_assert (_ret == 0); \ + } while (0) + #define bh_strcat_s(dest, dlen, src) do { \ int _ret = b_strcat_s (dest, dlen, src); \ (void)_ret; \ @@ -31,6 +37,7 @@ extern "C" { } while (0) int b_memcpy_s(void * s1, unsigned int s1max, const void * s2, unsigned int n); +int b_memmove_s(void * s1, unsigned int s1max, const void * s2, unsigned int n); int b_strcat_s(char * s1, unsigned int s1max, const char * s2); int b_strcpy_s(char * s1, unsigned int s1max, const char * s2); diff --git a/core/shared/utils/bh_log.h b/core/shared/utils/bh_log.h index 5dd13a8ec..8f7a179d1 100644 --- a/core/shared/utils/bh_log.h +++ b/core/shared/utils/bh_log.h @@ -41,12 +41,22 @@ bh_log_set_verbose_level(uint32 level); void bh_log(LogLevel log_level, const char *file, int line, const char *fmt, ...); +#if BH_DEBUG == 1 #define LOG_FATAL(...) bh_log(BH_LOG_LEVEL_FATAL, __FILE__, __LINE__, __VA_ARGS__) +#else +#define LOG_FATAL(...) bh_log(BH_LOG_LEVEL_FATAL, __FUNCTION__, __LINE__, __VA_ARGS__) +#endif + #define LOG_ERROR(...) bh_log(BH_LOG_LEVEL_ERROR, NULL, 0, __VA_ARGS__) -#define LOG_DEBUG(...) bh_log(BH_LOG_LEVEL_DEBUG, __FILE__, __LINE__, 0, __VA_ARGS__) #define LOG_WARNING(...) bh_log(BH_LOG_LEVEL_WARNING, NULL, 0, __VA_ARGS__) #define LOG_VERBOSE(...) bh_log(BH_LOG_LEVEL_VERBOSE, NULL, 0, __VA_ARGS__) +#if BH_DEBUG == 1 +#define LOG_DEBUG(...) bh_log(BH_LOG_LEVEL_DEBUG, __FILE__, __LINE__, __VA_ARGS__) +#else +#define LOG_DEBUG(...) /* do nothing */ +#endif + void bh_print_time(const char *prompt); diff --git a/core/shared/utils/runtime_timer.h b/core/shared/utils/runtime_timer.h index f173de546..8e8cc59ef 100644 --- a/core/shared/utils/runtime_timer.h +++ b/core/shared/utils/runtime_timer.h @@ -17,7 +17,7 @@ uint32 bh_get_elpased_ms(uint32 *last_system_clock); struct _timer_ctx; typedef struct _timer_ctx * timer_ctx_t; -typedef void (*timer_callback_f)(uint32 id, unsigned int owner); +typedef void (*timer_callback_f)(unsigned int id, unsigned int owner); typedef void (*check_timer_expiry_f)(timer_ctx_t ctx); timer_ctx_t create_timer_ctx(timer_callback_f timer_handler, diff --git a/doc/build_wamr.md b/doc/build_wamr.md index 4485a4345..eb4f7e6fa 100644 --- a/doc/build_wamr.md +++ b/doc/build_wamr.md @@ -7,7 +7,7 @@ It is recommended to use the [WAMR SDK](../wamr-sdk) tools to build a project th ## iwasm VM core CMake building configurations -By including the script `runtime_lib.cmake` under folder [build-scripts](../build-scripts) in CMakeList.txt, it is easy to build minimal product with CMake. +By including the script `runtime_lib.cmake` under folder [build-scripts](../build-scripts) in CMakeList.txt, it is easy to build minimal product with CMake. ```cmake # add this in your CMakeList.text @@ -21,19 +21,19 @@ The script `runtime_lib.cmake` defined a number of variables for configuring the #### **Configure platform and architecture** -- **WAMR_BUILD_PLATFORM**: set the target platform. It can be set to any platform name (folder name) under folder [core/shared/platform](../core/shared/platform). +- **WAMR_BUILD_PLATFORM**: set the target platform. It can be set to any platform name (folder name) under folder [core/shared/platform](../core/shared/platform). - **WAMR_BUILD_TARGET**: set the target CPU architecture. Current supported targets: X86_64, X86_32, AArch64, ARM, THUMB, XTENSA and MIPS. For AArch64, ARM and THUMB, the format is [][_VFP] where is the ARM sub-architecture and the "_VFP" suffix means VFP coprocessor registers s0-s15 (d0-d7) are used for passing arguments or returning results in standard procedure-call. Both and "_VFP" are optional. e.g. AARCH64, AARCH64V8, AARCHV8.1, ARMV7, ARMV7_VFP, THUMBV7, THUMBV7_VFP and so on. ```bash - cmake -DWAMR_BUILD_PLATFORM=linux -DWAMR_BUILD_TARGET=ARM + cmake -DWAMR_BUILD_PLATFORM=linux -DWAMR_BUILD_TARGET=ARM ``` -#### **Configure interpreter** +#### **Configure interpreter** - **WAMR_BUILD_INTERP**=1/0: enable or disable WASM interpreter -- **WAMR_BUILD_FAST_INTERP**=1/0:build fast (default) or classic WASM interpreter. +- **WAMR_BUILD_FAST_INTERP**=1/0:build fast (default) or classic WASM interpreter. NOTE: the fast interpreter will run ~2X faster than classic interpreter, but it consumes about 2X memory to hold the WASM bytecode code. @@ -48,14 +48,16 @@ The script `runtime_lib.cmake` defined a number of variables for configuring the - **WAMR_BUILD_LIBC_WASI**=1/0, default to disable if no set - +#### **Enable Multi-Module feature** + +- **WAMR_BUILD_MULTI_MODULE**=1/0, default to disable if not set **Combination of configurations:** We can combine the configurations. For example, if we want to disable interpreter, enable AOT and WASI, we can run command: ``` Bash -cmake .. -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_AOT=1 -DWAMR_BUILD_LIBC_WASI=0 -DWAMR_BUILD_PLATFORM=linux +cmake .. -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_AOT=1 -DWAMR_BUILD_LIBC_WASI=0 -DWAMR_BUILD_PLATFORM=linux ``` Or if we want to enable interpreter, disable AOT and WASI, and build as X86_32, we can run command: @@ -73,7 +75,7 @@ If you are building for ARM architecture on a X86 development machine, you can u ``` cmake .. -DCMAKE_TOOLCHAIN_FILE=$TOOL_CHAIN_FILE \ -DWAMR_BUILD_PLATFORM=linux \ - -DWAMR_BUILD_TARGET=ARM + -DWAMR_BUILD_TARGET=ARM ``` Refer to toochain sample file [`samples/simple/profiles/arm-interp/toolchain.cmake`](../samples/simple/profiles/arm-interp/toolchain.cmake) for how to build mini product for ARM target architecture. @@ -260,7 +262,7 @@ AliOS-Things ``` 7. build source code and run For linux host: - + ``` Bash aos make helloworld@linuxhost -c config aos make @@ -269,7 +271,7 @@ AliOS-Things For developerkit: Modify file middleware/iwasm/aos.mk, patch as: - + ``` C WAMR_BUILD_TARGET := THUMBV7M ``` @@ -285,11 +287,11 @@ Android able to generate a shared library support Android platform. - need an [android SDK](https://developer.android.com/studio). Go and get the "Command line tools only" - look for a command named *sdkmanager* and download below components. version numbers might need to check and pick others - - "build-tools;29.0.3" - - "cmake;3.10.2.4988404" - - "ndk;21.0.6113669" + - "build-tools;29.0.3" + - "cmake;3.10.2.4988404" + - "ndk;21.0.6113669" - "patcher;v4" - - "platform-tools" + - "platform-tools" - "platforms;android-29" - add bin/ of the downloaded cmake to $PATH - export ANDROID_SDK_HOME=/the/path/of/downloaded/sdk/ diff --git a/doc/multi_module.md b/doc/multi_module.md new file mode 100644 index 000000000..08e827eea --- /dev/null +++ b/doc/multi_module.md @@ -0,0 +1,228 @@ +Multiple Modules as Dependencies +========================= + +It is allowed that one WASM module can *import* *functions*, *globals*, *memories* and *tables* from other modules as its dependencies, and also one module can *export* those entities for other modules to *access* and may *write*. + +WAMR loads all dependencies recursively according to the *import section* of a module. + +> Currently WAMR only implements the load-time dynamic linking. Please refer to [dynamic linking](https://webassembly.org/docs/dynamic-linking/) for more details. + +## Multi-Module Related APIs + +### Register a module + +``` c +bool +wasm_runtime_register_module(const char *module_name, + wasm_module_t module, + char *error_buf, + uint32_t error_buf_size); +``` + +It is used to register a *module* with a *module_name* to WASM runtime, especially for the root module, which is loaded by `wasm_runtime_load()` and doesn't have a chance to tell runtime its *module name*. + +Fot all the sub modules, WAMR will get their names and load the .wasm files from the filesystem or stream, so no need to register the sub modules again. + +### Find a registered module + +``` c +wasm_module_t +wasm_runtime_find_module_registered( + const char *module_name); +``` + +It is used to check if a module with a given *module_name* has been registered, if yes return the module. + +### Module reader and destroyer + +``` c +typedef bool (*module_reader)(const char *module_name, + uint8_t **p_buffer, + uint32_t *p_size); + +typedef void (*module_destroyer)(uint8_t *buffer, + uint32_t size); + +void +wasm_runtime_set_module_reader(const module_reader reader, + const module_destroyer destroyer); +``` + +WAMR hopes that the native host or embedding environment loads/unloads the module WASM files by themselves and only passes runtime the binary content without worrying filesystem or storage issues. `module_reader` and `module_destroyer` are two callbacks called when dynamic-loading/unloading the sub modules. Developers must implement the two callbacks by themselves. + +### Call function of sub module + +```c +wasm_function_inst_t +wasm_runtime_lookup_function(wasm_module_inst_t const module_inst, + const char *name, + const char *signature); +``` + +Multi-module allows to lookup the function of sub module and call it. There are two ways to indicate the function *name*: + +- parent function name only by default, used to lookup the function of parent module +- sub module name, function name of sub module and two $ symbols, e.g. `$sub_module_name$function_name`, used to lookup function of sub module + +## Example + +### WASM modules +Suppose we have three C files, *mA.c*, *mB.c* and *mC.c*. Each of them has some exported functions and import some from others except mA. + +Undefined symbols can be marked in the source code with the *import_name* clang attribute which means that they are expected to be undefined at static link time. Without the *import_module* clang attribute, undefined symbols will be marked from the *env* module. + +``` C +// mA.c +int A() { return 10; } +``` + +``` C +// mB.c +__attribute__((import_module("mA"))) __attribute__((import_name("A"))) extern int A(); +int B() { return 11; } +int call_A() { return A(); } +``` + +``` C +// mC.c +__attribute__((import_module("mA"))) __attribute__((import_name("A"))) extern int A(); +__attribute__((import_module("mB"))) __attribute__((import_name("B"))) extern int B(); +int C() { return 12; } +int call_A() { return A(); } +int call_B() { return B(); } +``` + +By default no undefined symbols are allowed in the final binary. The flag *--allow-undefined* results in a WebAssembly import being defined for each undefined symbol. It is then up to the runtime to provide such symbols. + +When building an executable, only the entry point (_start) and symbols with the *export_name* attribute exported by default. in addition, symbols can be exported via the linker command line using *--export*. + +In the example, another linked command option *--export-all* is used. + +> with more detail, please refer to [WebAssembly lld port][https://lld.llvm.org/WebAssembly.html] + +Here is an example how to compile a *.c* to a *.wasm* with clang. Since there is no *start* function, we use *--no-entry* option. + +``` shell +$ clang --target=wasm32 -nostdlib \ + -Wl,--no-entry,--allow-undefined,--export-all \ + -o mA.wasm mA.c +$ clang --target=wasm32 -nostdlib \ + -Wl,--no-entry,--allow-undefined,--export-all \ + -o mB.wasm mB.c +$ clang --target=wasm32 -nostdlib \ + -Wl,--no-entry,--allow-undefined,--export-all \ + -o mC.wasm mC.c +``` + +put *mA.wasm*, *mB.wasm* and *mC.wasm* in the directory *wasm-apps* + +``` shell +$ # copy mA.wasm, mB.wasm and mC.wasm into wasm-apps +$ tree wasm-apps/ +wasm-apps/ +├── mA.wasm +├── mB.wasm +└── mC.wasm +``` + +eventually, their *import relationships* will be like: + +![import relationships](./pics/multi_module_pic1.png) + +### libvmlib + +We need to enable *WAMR_BUILD_MULTI_MODULE* option when building WAMR vmlib. Please ref to [Build WAMR core](./build_wamr.md) for a thoughtful guide. + +### code + +After all above preparation, we can call some functions from native code with APIs + +first, create two callbacks to load WASM module files into memory and unload them later + +``` c +static bool +module_reader_cb(const char *module_name, uint8 **p_buffer, uint32 *p_size) +{ + // ... + *p_buffer = (uint8_t *)bh_read_file_to_buffer(wasm_file_path, p_size); + // ... +} + +static void +module_destroyer_cb(uint8 *buffer, uint32 size) +{ + BH_FREE(buffer); +} +``` + +second, create a large buffer and tell WAMR malloc any resource only from this buffer later + +``` c +static char sandbox_memory_space[10 * 1024 * 1024] = { 0 }; +``` + +third, put all together + +``` c +int main() +{ + /* all malloc() only from the given buffer */ + init_args.mem_alloc_type = Alloc_With_Pool; + init_args.mem_alloc_option.pool.heap_buf = sandbox_memory_space; + init_args.mem_alloc_option.pool.heap_size = sizeof(sandbox_memory_space); + + /* initialize runtime environment */ + wasm_runtime_full_init(&init_args); + + /* set module reader and destroyer */ + wasm_runtime_set_module_reader(module_reader_cb, module_destroyer_cb); + + /* load WASM byte buffer from WASM bin file */ + module_reader_cb("mC", &file_buf, &file_buf_size)); + + /* load mC and let WAMR load mA and mB */ + module = wasm_runtime_load(file_buf, file_buf_size, + error_buf, sizeof(error_buf)); + + /* instantiate the module */ + module_inst = + wasm_runtime_instantiate(module, stack_size, + heap_size, error_buf, sizeof(error_buf))); + + + printf("call \"C\", it will return 0xc:i32, ===> "); + wasm_application_execute_func(module_inst, "C", 0, &args[0]); + printf("call \"call_B\", it will return 0xb:i32, ===> "); + wasm_application_execute_func(module_inst, "call_B", 0, &args[0]); + printf("call \"call_A\", it will return 0xa:i32, ===>"); + wasm_application_execute_func(module_inst, "call_A", 0, &args[0]); + + /* call some functions of mB */ + printf("call \"mB.B\", it will return 0xb:i32, ===>"); + wasm_application_execute_func(module_inst, "$mB$B", 0, &args[0]); + printf("call \"mB.call_A\", it will return 0xa:i32, ===>"); + wasm_application_execute_func(module_inst, "$mB$call_A", 0, &args[0]); + + /* call some functions of mA */ + printf("call \"mA.A\", it will return 0xa:i32, ===>"); + wasm_application_execute_func(module_inst, "$mA$A", 0, &args[0]); + + // ... +} +``` + +> please refer to [main.c](../samples/multi_modules/src/main.c) + +The output of the main.c will like: + +``` shell +$ ./a.out + +call "C", it will return 0xc:i32, ===> 0xc:i32 +call "call_B", it will return 0xb:i32, ===> 0xb:i32 +call "call_A", it will return 0xa:i32, ===>0xa:i32 +call "mB.B", it will return 0xb:i32, ===>0xb:i32 +call "mB.call_A", it will return 0xa:i32, ===>0xa:i32 +call "mA.A", it will return 0xa:i32, ===>0xa:i32 + +``` diff --git a/doc/pics/multi_module_pic1.png b/doc/pics/multi_module_pic1.png new file mode 100644 index 0000000000000000000000000000000000000000..f0c8e33a3725fd92a08fff84bc39218c95e9db8a GIT binary patch literal 8585 zcmd6NXFQwl+jnBbCb36F@U!=<8m$qu_NLT|YEh$9QF}{`Dz#_DicPK79-(Tds8OS+ z8ntVc;<@^J?*IMbdGWluU)(RwGs$^fT+X5%7os zfxzUX5a3zT;45Je2m!i>R59_h*~umI)}6lk7*agREc0>3zoad#|A?~Y$3G@&>N+r0 zVwf7`nBtfk#sw>2sYaE+tYvf_ukM_RDOpQ;On!wez%sl1so5KqKVA6e=I(;8+-c6U zkj_Toe=c(B$9zLZJ;p9h`zy?AY+!6c-yRV!+Cdi{5d85g07VQSoK(ROL%P1MOgm^M zSeL&G;euh7qod@KdP_#E2*I(X=Z&w`CrWd+RAus8OEA6Y%6hI3< zQTqmCK{61h2hs;1?{!aVjlvB@icN#51CXh};f?>v!&h@~2~N&DM&S&V;9!o4@dCQy zr8Je4G#w5mEEOvMcJ9X75R>=L97Al}SG^BjpG2DMpvT>*-l9`P2cL_7P1ZjS$dY*? zkid-3K0jgC1A|A34~G$2pNjKw?+{HM9Lk)W%PBd5VJF+O8u#lT6*G#=85tOmWZim3 zkSphzark3Ib9p(a%yadTbEHL^pDg<=uTYf3s`Fffq4()7d+f{m|L`zI@bjbx(+-6* zv(D*sO&5LymEW%y<@u+wpjdkyzjSSr+2XUK%^=jFZyO{N9^boHDj--cHIm<%HJDn#AMCULEtvJDJEF?wQi(y>BEzO5P@pUF=FT|h z{3ARwGQ0S*xoUtiGO^jJng0MYmVc+Tt7~quW{H%X(p4n*B;?vRs;Ae=P)A4j_qiF< zooq=*IVHb+KHWUU>3_x#*C;l+!rB`ieu8AHJ3!siv~0tgWeELx|6*LZ2qv1D>!-@kVcbadS0ALh$9t zbDeK4Pzjwk8O-_z2MPk3)I$MD+}vsdUt5V1IPOf8qbV__FOM>n8Iiu7JP{kav`_KB zSddI)Ka0K|N{aK5ZEk<9)%0${uzuhOKqk;5d1vhsvG_xKU<>z@w%UfVn~pb5*K2xL zb@(jhDq$8rJ71`tpyxz6PSC6(|8C5h^?h)>A+dFUQUG##>&fZDEccv9Zj;!pBFqH%PW5W zUT&`KMg68>aBwg^JNwR-rd8W@t$nZ4bhUNKl8nb_nJOnE9r>E@Ww&^GDS!yAwXBmV871pJpHWf?>OMPIU9b%H>v)mPkm)>C z&XB+=Gg$T8=+`owaAl%Yzf3a`9yvfL0;9t0Wfev5jn|r3D2woq}Ev)IhvTQ3g92Q3`wg;rEs;VMCRNk+TK3pI3NRia~1s@Dp z;kIgYNwr^`fFcC*xC8|5Q4%;Ll_gQ-ak%x7GYB&G|6(IR7Vk(u-!gIeT=X)DMY{d# z$<9}x`jZ}}G}Z2^JZSY1>BHd+(nYQL1qEg3qe^GyKRk2pi)Dy3U3B}}GhI{VRBUheWgA=c^fRGFIMoI19ssoyJoab;Smg0c^aNB(IchEd$B3#7=U zRnl9!ML|-DP<0E{qwHs`8#hlZ(T3(LzTm=<#B1b7G!hFsvO=LK3%>f^?`|K`TR(5m zB8M~noUJCp>jeAE#8aHRfPDDrl^D0HjO#J1d;k}>13llG{Pe}^5bf=Ru`6R^yhO>g zi#H)xN#nREt|1L};w6rD{_uquy?jCnf&E=dL zv9itXn&UFpP-bQ^_?kuzw0$aI*?^r=L_HxKq__wZ&q|VdtT!RkLgIOTwAm1R=`T5V zl$%!ZNLUzRFoOx5x~-iq+DMM_@{&B>U9b{1>KxFwrk=o@eIE@{|k zs?wFc%A}0ee(P|#HzsldUi*e7VrtM{7kh4?-PLhNwvL@+`7m>ImvP_y@~KM@vgYU#y+Z z2y!3{0n&Lh|N0N#!iQ%uwXq9BLqiR995Q3TWgMjH?OR0MDccC=pBrkbGe5{fMOfPS zUL8M~eaF-2JfQ))<+E*pPZ2aKLcd3*BT)TBHsZd!^QtDUiZ`zTmN{nBPhUSp`~%A58a0#Ca1q!k7EC7vP>+YY1V$J4fb?fBmWPcsNfGS2*7(=3FOdV~r>h{MI^&}l4a zto%qKhe~Q(Iirv(Jz?a=H;^PT(q!yME}@^MQw+B$NVwdEn0%hZ26n1KLa4nC;!+g% zZ;zcN=ekWW{36?9q^taG1PM*-8zFBpE^@5ZLa3Fh^ka0;o2*wvzQ0A};!*ll&f#t(8%HA;{13}o9 zWrm4-Ojy%ez+O9FTDb(8m1lMqfe|Uap&cIJa7~>h7fQqNyd&_p(+ch-uME&b_!PzD z!}mHasuvIh-tiI`o92>2L!M;;Pd_;k649u60ccA@WuGsWK$Tt&;JkoP(; zXAV#zDTlh^@)TbfQ8E`++7Pynm#UX}jZIso!Ye#Z#H!Hd%G47;zrhZg(-OV{ zoPr%9;nw|>4X^uF5+E|HIr)!!Mkrh@a0t2iEq~kYyX_5xzWNW@3Wr$DRJ{i zKSUh;>JzrTf(1#HLe>m>$&7>;5|WFfv-pWl(3D&eSTbT}q%J*S01}d2TwIFzneH;H66Q1Cz(X&oclh|dTQ7gn5qvzbO32UYwTyP ze}v`;qE7+8KUgKf1NzKq^K*i1YPky{%X|c2?gdj7=5gp0(mMauekxcaZCLr6=oFou`NhV@a^VP0PESjv9*>T1PL%3~3)tI=2w;gmz!m*!NvYxnGVypk00uls z4{8v4naQk}CZpo=hDRfk{%8AO(;Ax?2n}4n!c3%uT|qW(>EeRK=;3$78)r75DS{-2>Da@o(43OB~$TU3{!IrAY6mbj%Aj(J;4;#Fk&Bu zxGNKG$jvO<)5c{X+f%!;^j=gyPjLmFMyXN_Q(z8xZ5zmchJMYb6d@OM?qpbe{yRvg zpkQJ1&+mHahj)omMXjSP8=SPkV3CdW{8Iz(BPT$nB0D-{a2F-vGs!)@g}7^==^|rj zu5|zk@D@y{LGjd0qS+4_ini$7zY8L7vg;-|zq;6qx`_;RVOA|CKub9EXDCxrQ8CyF z%DPPQtMZ#Q%u?TwQ+~sz&p0KFq7nMi>|rZtf_?oy|IqapV)ib{TYzIZHo9muoE)wV z#U&C%D{@Z?bw$Q}sn8@s10v$>`}b}o)EY>nLP6&Ta{xX?pKpH74v$dNMP&J!?W;}d zadKLhJzKv!n9LI=awFMF1-ZS{yy&m}(EBgn^Xr+e=Ef#c;Vt-5G~2E6IR39=sVu?oVC7b9JY|7>FR$Th|4603`a&4Gd`7Wcel81}3_kp+xZ=@y$%|-aLYiFf z2R{G#rC1|@wHU_8&PTL(b^f!a%n6Ta$+@pGwXFk{D2FmzWY0D2=m6$M0txErQ*q!8 zBS$E;7;1)GNCOoOT#>)c=vdQLv9fSHsZvDJcD#x+Jf z0iVaR**(fhOw_U=`f#nj0fpMQJYDiV@)2#dsmWzX zCqu0!uprr@-pQ~;I8_)qPe`CoHq$muDKSCe6GHa@A%*7kivHDqTY`JFw32VyA;glcCm1{?Z!lMmzI0!Hv!$ zu#(3C+GxTmI!y7(vHR*N^GWdP^$cA#18{0YD>|zA>&Hl6*^Sua4ZK>8cfo%h5667C zX#y{lsTn}DKtWaW^6fV#G3F1UjjC~RhxVV?T<}7YXi)-Xq2`fcHkT3Lg(as(RN&LL zM`TGal&$`kQiT5|G5TQG0TwnrXIyF59qzosR}$i3Q?SEJ%ZzL2kwUu@!NT}q1JH3fM5ORlLD!dLMX{b!=t0V+ARbEMWZX-D%~f z6&i#j)b!vf-<>(0V8Bpuh(+H`P))Sk2n7+p+9?0)O~6UR#KEB`t)l6l(>2D`4?d7~ ze{S{N)AQ)eWeuV)h=s8Dh6!D?8O9$a2tZUTkLSwz^t5x5WL z;pL6RmZJw^={la)e%_j@5a8rgi6qttbOFV0ROKr8GKPKKoByB&WFWVgn3%DNc_f#{ z{$J<^Oj;;s(E)(->gbhQ&wdyjtn?9gZR&zy9IuRIR^!9H6<#tEUko=t5NpmRKj zhLr)6iNET>htJZJ_zH8eK>&b3ni52IBqksT-z{Owh5;hp&x!#jIz%c!pKc_TikF)~ zt5xMdqNUO4RAO=gC$56F9c`fj*H@Q46oRFZ?6(6m`V-h58&Bof&;=@qt2*K|5axV>Q$@ciRkr$-iSnGI^58ZVu}i) zbs)1kB$IrL4tZoCWLC*P+TULZA;0>_5kkMCbQFBLJ*x&7k(p;ob4yM!n41)0QCoD6 z$o?O3_Q`-~lcXUD!NU_Z-hq1!YjX!W@DUZ4jUX?tMtqrWuDq#qc>-#b2xja$&L=CI zCTiQE6Gg#PvcLaS!lZBpP><>iW%1l7R~ngDwANj;Xy(aibA=a&Ma+WX#&KcYlLWyHtqa|D26xA2Qy<JBzT9_MdRQHddY`50!0v$FC}O zzCn#7jk`}ssc%QA!=f+|_pN$xy+ADntDk?{q%$}O7!TRARr>Z^Du2M6zq(S7ml*-G6RpKS=%LvbJF;u)D&> zUYZD<;o05hY-E&NPy&{U*c#51nrwVxUT#o8AaeiR_r{@$BZ3l6<;WSQN{3ClVg8BG zG=$M2-IEJ(cc;iry|z+&W!zAgahDW|b(}x1=Y~e#FNYR7H?_YGrU3$Dkm9Ud*pNG{ zVm#MlVdd0eI!P+dN{yr^_i0<^ry153nrd965E2#D8_sy^hGwBJ%;Z$T-6OVudqf_{ zfJ$|i>?JA;KWb9}e#uy1zdgWMTXG>LC405SlLJzBqlsbSTkX))L^6fl_}iuKPSE2A zRRSXvIRoFwD&i?=xa>^6Y}z}KD11J$3#AG0u8pIPQ;2tmgSp5(acEeB!$<16Dx;rj z92)TO!R?4cW@w!-hZ=|6f!0t&w+2VbsUMUR#CmC=9J?t|xzM{wVkxPgS<+DS;iDgN zZ7r3UaIgI|Z|3z?%P)(`$jJ#t_oC@9tICle%Ll4!FSTcf?T_vP0jT*u&fK7W<2q52 zkTojSTfefp+BYj@ahS-$sV|*K3>(^(cpUJ30M;y8Z{DQvP3H-Bp8untnrr`ewx|?z zD48I-ac>pMd4nomO=!WMP1Y3=NH15*f4Rvp`|M#sd4ds*)y6ro865O#sH)ygZIwyHq5%BX2JJyqEoZ?T*qrAOw&+|5=P_SjiMj# zTBqr4qB3nW2FEv^&jtCOpnbGUcPM7LU0MVGM*4RH!lhZlVXb>Wb*fr5yJIMruC#$% ze%lk(US^|ohn#x%?u%dkvqyrI7+uLtu_Q}`hGt^HLTj@TK-95jRsJa=RQemtJ_k}EFfTLo9FEtG8?B*ODnZ)u6uP$2+l$9xB zV_Dt*Gr&R+uKXDJ>AW^*!73w|)p3SmweAc~T?}d#rec?W3C!7ef=>a>H!$4{p@J)h zwY3@Dv{%Xos)@@FPKn(M9?vFH5qOY$`d9&`^$=aH9R&MvF zDp()O$G_%;0bknZ@SqHtloYWsnrkI(r)>UrQdwJ@my&!K3ea#QyMj;YXfAivkB^oF z5PX)Z{AIf^y8f|#$%|iRhQANX@CNH6alC$mXJ_mwVzyi5n}88v004sXpR-KwwLzY( z#da#H8*`?Q5Fy-*KtfU#+{$@^~0s z{A9Y?Xu4WO+Is_e`0HZE9>$D};hFqFwGH z6Hl#{&yKFFgWV{43KG!e_aVsnl8|ft&4X19ji~!ej)K3m==x4#JP;m6nu9pH}=l}Zy^7+TGe15!ZKAtB|HweF#!4ZUVyv# zWRoD+VAq?TLX>!Ga8Sr#5_c){p^9dy>nypn^XD6bsY1=B0HOc)f42n2Af7{MRDTE1 zdABd)VwuF$gM-74KJo2HZd?B-zhw$`=XN=2Mg7-=Q4)^FKfbl<55cnty6nR#F%XJA zVeJPpPyRbm|A+JbKjGkOFzw&piz{c3JTorh)&ZIE1n)bskhn9#yx60AzwUP(I@F*T z9MfETUtDj1T&_IyqshoC^1kU-GcW`wt-}R3lTeigLw>y+6zz=y{( literal 0 HcmV?d00001 diff --git a/product-mini/platforms/linux/CMakeLists.txt b/product-mini/platforms/linux/CMakeLists.txt index fd8657a91..fc2cb2a0b 100644 --- a/product-mini/platforms/linux/CMakeLists.txt +++ b/product-mini/platforms/linux/CMakeLists.txt @@ -4,6 +4,7 @@ cmake_minimum_required (VERSION 2.8) project (iwasm) +# set (CMAKE_VERBOSE_MAKEFILE 1) set (WAMR_BUILD_PLATFORM "linux") @@ -11,6 +12,8 @@ set (WAMR_BUILD_PLATFORM "linux") set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") set (CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") +set (CMAKE_C_STANDARD 99) + # Set WAMR_BUILD_TARGET, currently values supported: # "X86_64", "AMD_64", "X86_32", "AARCH64[sub]", "ARM[sub]", "THUMB[sub]", "MIPS", "XTENSA" if (NOT DEFINED WAMR_BUILD_TARGET) @@ -57,6 +60,11 @@ if (NOT DEFINED WAMR_BUILD_FAST_INTERP) set (WAMR_BUILD_FAST_INTERP 1) endif () +if (NOT DEFINED WAMR_BUILD_MULTI_MODULE) + # Enable multiple modules + set (WAMR_BUILD_MULTI_MODULE 0) +endif () + set (WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../..) include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) diff --git a/product-mini/platforms/linux/main.c b/product-mini/platforms/linux/main.c index defc0d949..4926f8ac8 100644 --- a/product-mini/platforms/linux/main.c +++ b/product-mini/platforms/linux/main.c @@ -8,24 +8,26 @@ #endif #include #include + #include "bh_platform.h" -#include "bh_assert.h" -#include "bh_log.h" #include "bh_read_file.h" #include "wasm_export.h" static int app_argc; static char **app_argv; -static int print_help() +#define MODULE_PATH ("--module-path=") + +static int +print_help() { printf("Usage: iwasm [-options] wasm_file [args...]\n"); printf("options:\n"); - printf(" -f|--function name Specify function name to run in module\n" - " rather than main\n"); + printf(" -f|--function name Specify a function name of the module to run rather\n" + " than main\n"); #if WASM_ENABLE_LOG != 0 - printf(" -v=n Set log verbose level (0 to 5, default is 2),\n" - " larger level with more log\n"); + printf(" -v=n Set log verbose level (0 to 5, default is 2) larger\n" + " level with more log\n"); #endif printf(" --stack-size=n Set maximum stack size in bytes, default is 16 KB\n"); printf(" --heap-size=n Set maximum heap size in bytes, default is 16 KB\n"); @@ -39,11 +41,14 @@ static int print_help() printf(" to the program, for example:\n"); printf(" --dir= --dir=\n"); #endif - +#if WASM_ENABLE_MULTI_MODULE != 0 + printf(" --module-path= Indicate a module search path. default is current\n" + " directory('./')\n"); +#endif return 1; } -static void* +static void * app_instance_main(wasm_module_inst_t module_inst) { const char *exception; @@ -54,7 +59,7 @@ app_instance_main(wasm_module_inst_t module_inst) return NULL; } -static void* +static void * app_instance_func(wasm_module_inst_t module_inst, const char *func_name) { wasm_application_execute_func(module_inst, func_name, app_argc - 1, @@ -81,20 +86,31 @@ split_string(char *str, int *count) do { p = strtok(str, " "); str = NULL; - res = (char**) realloc(res, sizeof(char*) * (uint32)(idx + 1)); + res = (char **)realloc(res, sizeof(char *) * (uint32)(idx + 1)); if (res == NULL) { return NULL; } res[idx++] = p; } while (p); + /** + * since the function name, + * res[0] might be contains a '\' to indicate a space + * func\name -> func name + */ + p = strchr(res[0], '\\'); + while (p) { + *p = ' '; + p = strchr(p, '\\'); + } + if (count) { *count = idx - 1; } return res; } -static void* +static void * app_instance_repl(wasm_module_inst_t module_inst) { char *cmd = NULL; @@ -149,7 +165,49 @@ validate_env_str(char *env) static char global_heap_buf[10 * 1024 * 1024] = { 0 }; #endif -int main(int argc, char *argv[]) +#if WASM_ENABLE_MULTI_MODULE != 0 +static char * +handle_module_path(const char *module_path) +{ + // next character after = + return (strchr(module_path, '=')) + 1; +} + +static char *module_search_path = "."; +static bool +module_reader_callback(const char *module_name, uint8 **p_buffer, + uint32 *p_size) +{ + const char *format = "%s/%s.wasm"; + int sz = strlen(module_search_path) + strlen("/") + strlen(module_name) + + strlen(".wasm") + 1; + char *wasm_file_name = BH_MALLOC(sz); + if (!wasm_file_name) { + return false; + } + + snprintf(wasm_file_name, sz, format, module_search_path, module_name); + + *p_buffer = (uint8_t *)bh_read_file_to_buffer(wasm_file_name, p_size); + + wasm_runtime_free(wasm_file_name); + return *p_buffer != NULL; +} + +static void +moudle_destroyer(uint8 *buffer, uint32 size) +{ + if (!buffer) { + return; + } + + wasm_runtime_free(buffer); + buffer = NULL; +} +#endif /* WASM_ENABLE_MULTI_MODULE */ + +int +main(int argc, char *argv[]) { char *wasm_file = NULL; const char *func_name = NULL; @@ -172,6 +230,8 @@ int main(int argc, char *argv[]) #endif /* Process options. */ + // TODO: use a option name and option handler pair table to + // optimize for (argc--, argv++; argc > 0 && argv[0][0] == '-'; argc--, argv++) { if (!strcmp(argv[0], "-f") || !strcmp(argv[0], "--function")) { argc--, argv++; @@ -188,8 +248,9 @@ int main(int argc, char *argv[]) return print_help(); } #endif - else if (!strcmp(argv[0], "--repl")) + else if (!strcmp(argv[0], "--repl")) { is_repl_mode = true; + } else if (!strncmp(argv[0], "--stack-size=", 13)) { if (argv[0][13] == '\0') return print_help(); @@ -204,9 +265,9 @@ int main(int argc, char *argv[]) else if (!strncmp(argv[0], "--dir=", 6)) { if (argv[0][6] == '\0') return print_help(); - if (dir_list_size >= sizeof(dir_list) / sizeof(char*)) { + if (dir_list_size >= sizeof(dir_list) / sizeof(char *)) { printf("Only allow max dir number %d\n", - (int)(sizeof(dir_list) / sizeof(char*))); + (int)(sizeof(dir_list) / sizeof(char *))); return -1; } dir_list[dir_list_size++] = argv[0] + 6; @@ -216,20 +277,29 @@ int main(int argc, char *argv[]) if (argv[0][6] == '\0') return print_help(); - if (env_list_size >= sizeof(env_list) / sizeof(char*)) { + if (env_list_size >= sizeof(env_list) / sizeof(char *)) { printf("Only allow max env number %d\n", - (int)(sizeof(env_list) / sizeof(char*))); + (int)(sizeof(env_list) / sizeof(char *))); return -1; } tmp_env = argv[0] + 6; if (validate_env_str(tmp_env)) env_list[env_list_size++] = tmp_env; else { - printf("Wasm parse env string failed: expect \"key=value\", got \"%s\"\n", + printf("Wasm parse env string failed: expect \"key=value\", " + "got \"%s\"\n", tmp_env); return print_help(); } } +#endif /* WASM_ENABLE_LIBC_WASI */ +#if WASM_ENABLE_MULTI_MODULE != 0 + else if (!strncmp(argv[0], MODULE_PATH, strlen(MODULE_PATH))) { + module_search_path = handle_module_path(argv[0]); + if (!strlen(module_search_path)) { + return print_help(); + } + } #endif else return print_help(); @@ -261,13 +331,19 @@ int main(int argc, char *argv[]) return -1; } +#if WASM_ENABLE_LOG != 0 bh_log_set_verbose_level(log_verbose_level); +#endif /* load WASM byte buffer from WASM bin file */ - if (!(wasm_file_buf = (uint8*) bh_read_file_to_buffer(wasm_file, - &wasm_file_size))) + if (!(wasm_file_buf = + (uint8 *)bh_read_file_to_buffer(wasm_file, &wasm_file_size))) goto fail1; +#if WASM_ENABLE_MULTI_MODULE != 0 + wasm_runtime_set_module_reader(module_reader_callback, moudle_destroyer); +#endif + /* load WASM module */ if (!(wasm_module = wasm_runtime_load(wasm_file_buf, wasm_file_size, error_buf, sizeof(error_buf)))) { @@ -276,19 +352,14 @@ int main(int argc, char *argv[]) } #if WASM_ENABLE_LIBC_WASI != 0 - wasm_runtime_set_wasi_args(wasm_module, - dir_list, dir_list_size, - NULL, 0, - env_list, env_list_size, - argv, argc); + wasm_runtime_set_wasi_args(wasm_module, dir_list, dir_list_size, NULL, 0, + env_list, env_list_size, argv, argc); #endif /* instantiate the module */ - if (!(wasm_module_inst = wasm_runtime_instantiate(wasm_module, - stack_size, - heap_size, - error_buf, - sizeof(error_buf)))) { + if (!(wasm_module_inst = + wasm_runtime_instantiate(wasm_module, stack_size, heap_size, + error_buf, sizeof(error_buf)))) { printf("%s\n", error_buf); goto fail3; } @@ -316,4 +387,3 @@ fail1: wasm_runtime_destroy(); return 0; } - diff --git a/samples/multi-module/CMakeLists.txt b/samples/multi-module/CMakeLists.txt new file mode 100644 index 000000000..774524c6f --- /dev/null +++ b/samples/multi-module/CMakeLists.txt @@ -0,0 +1,51 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required(VERSION 2.8) +project(multi_module) +set(CMAKE_VERBOSE_MAKEFILE on) + +################ runtime settings ################ +set(WAMR_BUILD_PLATFORM "linux") + +# Resetdefault linker flags +set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") +set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") + +# WAMR features switch +set(WAMR_BUILD_TARGET "X86_64") +set(WAMR_BUILD_INTERP 1) +set(WAMR_BUILD_AOT 0) +set(WAMR_BUILD_JIT 0) +set(WAMR_BUILD_LIBC_BUILTIN 1) +set(WAMR_BUILD_LIBC_WASI 1) +set(WAMR_BUILD_FAST_INTERP 0) +set(WAMR_BUILD_MULTI_MODULE 1) + +# compiling and linking flags +set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections -pie -fPIE") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat -Wformat-security -mindirect-branch-register") + +# build out vmlib +set(WAMR_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../..) +include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) + +add_library(vmlib STATIC ${WAMR_RUNTIME_LIB_SOURCE}) +################################################ + +################ application related ################ + +################ WASM MODULES +# .c -> .wasm +add_subdirectory(wasm-apps) + +################ NATIVE +include_directories(${CMAKE_CURRENT_LIST_DIR}/src) +include (${SHARED_DIR}/utils/uncommon/shared_uncommon.cmake) + +add_executable(multi_module src/main.c ${UNCOMMON_SHARED_SOURCE}) + +add_dependencies(multi_module vmlib wasm-modules) + +# libraries +target_link_libraries(multi_module PRIVATE vmlib -lpthread -lm) diff --git a/samples/multi-module/src/main.c b/samples/multi-module/src/main.c new file mode 100644 index 000000000..77a443797 --- /dev/null +++ b/samples/multi-module/src/main.c @@ -0,0 +1,144 @@ +#include +#include +#include + +#include "bh_read_file.h" +#include "platform_common.h" +#include "wasm_export.h" + +static char * +build_module_path(const char *module_name) +{ + const char *module_search_path = "./wasm-apps"; + const char *format = "%s/%s.wasm"; + int sz = strlen(module_search_path) + strlen("/") + strlen(module_name) + + strlen(".wasm") + 1; + char *wasm_file_name = BH_MALLOC(sz); + if (!wasm_file_name) { + return NULL; + } + + snprintf(wasm_file_name, sz, format, module_search_path, module_name); + return wasm_file_name; +} + +static bool +module_reader_cb(const char *module_name, uint8 **p_buffer, uint32 *p_size) +{ + char *wasm_file_path = build_module_path(module_name); + if (!wasm_file_path) { + return false; + } + + printf("- bh_read_file_to_buffer %s\n", wasm_file_path); + *p_buffer = (uint8_t *)bh_read_file_to_buffer(wasm_file_path, p_size); + BH_FREE(wasm_file_path); + return *p_buffer != NULL; +} + +static void +module_destroyer_cb(uint8 *buffer, uint32 size) +{ + printf("- release the read file buffer\n"); + if (!buffer) { + return; + } + + BH_FREE(buffer); + buffer = NULL; +} + +/* 10M */ +static char sandbox_memory_space[10 * 1024 * 1024] = { 0 }; +int +main() +{ + bool ret = false; + /* 16K */ + const uint32 stack_size = 16 * 1024; + const uint32 heap_size = 16 * 1024; + + RuntimeInitArgs init_args = { 0 }; + char error_buf[128] = { 0 }; + /* parameters and return values */ + char* args[1] = { 0 }; + + uint8 *file_buf = NULL; + uint32 file_buf_size = 0; + wasm_module_t module = NULL; + wasm_module_inst_t module_inst = NULL; + + /* all malloc() only from the given buffer */ + init_args.mem_alloc_type = Alloc_With_Pool; + init_args.mem_alloc_option.pool.heap_buf = sandbox_memory_space; + init_args.mem_alloc_option.pool.heap_size = sizeof(sandbox_memory_space); + + printf("- wasm_runtime_full_init\n"); + /* initialize runtime environment */ + if (!wasm_runtime_full_init(&init_args)) { + printf("Init runtime environment failed.\n"); + goto EXIT; + } + +#if WASM_ENABLE_MULTI_MODULE != 0 + printf("- wasm_runtime_set_module_reader\n"); + /* set module reader and destroyer */ + wasm_runtime_set_module_reader(module_reader_cb, module_destroyer_cb); +#endif + + /* load WASM byte buffer from WASM bin file */ + if (!module_reader_cb("mC", &file_buf, &file_buf_size)) { + goto RELEASE_RUNTIME; + } + + /* load mC and let WAMR load mA and mB */ + printf("- wasm_runtime_load\n"); + if (!(module = wasm_runtime_load(file_buf, file_buf_size, + error_buf, sizeof(error_buf)))) { + printf("%s\n", error_buf); + goto RELEASE_BINARY; + } + + /* instantiate the module */ + printf("- wasm_runtime_instantiate\n"); + if (!(module_inst = + wasm_runtime_instantiate(module, stack_size, heap_size, + error_buf, sizeof(error_buf)))) { + printf("%s\n", error_buf); + goto UNLOAD_MODULE; + } + + /* call some functions of mC */ + printf("\n----------------------------------------\n"); + printf("call \"C\", it will return 0xc:i32, ===> "); + wasm_application_execute_func(module_inst, "C", 0, &args[0]); + printf("call \"call_B\", it will return 0xb:i32, ===> "); + wasm_application_execute_func(module_inst, "call_B", 0, &args[0]); + printf("call \"call_A\", it will return 0xa:i32, ===>"); + wasm_application_execute_func(module_inst, "call_A", 0, &args[0]); + + /* call some functions of mB */ + printf("call \"mB.B\", it will return 0xb:i32, ===>"); + wasm_application_execute_func(module_inst, "$mB$B", 0, &args[0]); + printf("call \"mB.call_A\", it will return 0xa:i32, ===>"); + wasm_application_execute_func(module_inst, "$mB$call_A", 0, &args[0]); + + /* call some functions of mA */ + printf("call \"mA.A\", it will return 0xa:i32, ===>"); + wasm_application_execute_func(module_inst, "$mA$A", 0, &args[0]); + printf("----------------------------------------\n\n"); + ret = true; + + printf("- wasm_runtime_deinstantiate\n"); + wasm_runtime_deinstantiate(module_inst); +UNLOAD_MODULE: + printf("- wasm_runtime_unload\n"); + wasm_runtime_unload(module); +RELEASE_BINARY: + module_destroyer_cb(file_buf, file_buf_size); +RELEASE_RUNTIME: + printf("- wasm_runtime_destroy\n"); + wasm_runtime_destroy(); +EXIT: + return ret ? 0 : 1; +} diff --git a/samples/multi-module/wasm-apps/CMakeLists.txt b/samples/multi-module/wasm-apps/CMakeLists.txt new file mode 100644 index 000000000..2691c50b9 --- /dev/null +++ b/samples/multi-module/wasm-apps/CMakeLists.txt @@ -0,0 +1,41 @@ +cmake_minimum_required(VERSION 2.8) +project(wasm-apps) + +set(CMAKE_VERBOSE_MAKEFILE on) + +set(WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../..) +set(CLANG_COMMAND "/opt/wasi-sdk/bin/clang") + +set(CLANG_FLAGS --target=wasm32 -nostdlib) +set(CLANG_FLAGS ${CLANG_FLAGS} -Wl,--no-entry,--allow-undefined,--export-all) + +set(SOURCE_A ${CMAKE_CURRENT_SOURCE_DIR}/mA.c) +add_custom_command( + OUTPUT mA.wasm + COMMENT "Transform mA.C to mA.WASM" + COMMAND ${CLANG_COMMAND} ${CLANG_FLAGS} -o mA.wasm ${SOURCE_A} + DEPENDS ${SOURCE_A} + VERBATIM +) + +set(SOURCE_B ${CMAKE_CURRENT_SOURCE_DIR}/mB.c) +add_custom_command( + OUTPUT mB.wasm + COMMENT "Transform mB.C to mB.WASM" + COMMAND ${CLANG_COMMAND} ${CLANG_FLAGS} -o mB.wasm ${SOURCE_B} + DEPENDS ${SOURCE_B} + VERBATIM +) + +set(SOURCE_C ${CMAKE_CURRENT_SOURCE_DIR}/mC.c) +add_custom_command( + OUTPUT mC.wasm + COMMENT "Transform mC.C to mC.WASM" + COMMAND ${CLANG_COMMAND} ${CLANG_FLAGS} -o mC.wasm ${SOURCE_C} + DEPENDS ${SOURCE_C} + VERBATIM +) + +add_custom_target(wasm-modules ALL + DEPENDS mA.wasm mB.wasm mC.wasm +) \ No newline at end of file diff --git a/samples/multi-module/wasm-apps/mA.c b/samples/multi-module/wasm-apps/mA.c new file mode 100644 index 000000000..d5e8d833e --- /dev/null +++ b/samples/multi-module/wasm-apps/mA.c @@ -0,0 +1,5 @@ +int +A() +{ + return 10; +} \ No newline at end of file diff --git a/samples/multi-module/wasm-apps/mB.c b/samples/multi-module/wasm-apps/mB.c new file mode 100644 index 000000000..76aa1e7dc --- /dev/null +++ b/samples/multi-module/wasm-apps/mB.c @@ -0,0 +1,16 @@ +__attribute__((import_module("mA"))) +__attribute__((import_name("A"))) extern int +A(); + +int +B() +{ + return 11; +} + +int +call_A() +{ + return A(); +} + diff --git a/samples/multi-module/wasm-apps/mC.c b/samples/multi-module/wasm-apps/mC.c new file mode 100644 index 000000000..5a378dd15 --- /dev/null +++ b/samples/multi-module/wasm-apps/mC.c @@ -0,0 +1,25 @@ +__attribute__((import_module("mA"))) +__attribute__((import_name("A"))) extern int +A(); + +__attribute__((import_module("mB"))) +__attribute__((import_name("B"))) extern int +B(); + +int +C() +{ + return 12; +} + +int +call_A() +{ + return A(); +} + +int +call_B() +{ + return B(); +} \ No newline at end of file diff --git a/wamr-compiler/CMakeLists.txt b/wamr-compiler/CMakeLists.txt index a8c70677f..a00884782 100644 --- a/wamr-compiler/CMakeLists.txt +++ b/wamr-compiler/CMakeLists.txt @@ -14,6 +14,7 @@ set (CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") add_definitions(-DWASM_ENABLE_INTERP=1) add_definitions(-DWASM_ENABLE_WAMR_COMPILER=1) +add_definitions(-DWASM_ENABLE_BULK_MEMORY=1) # Set WAMR_BUILD_TARGET, currently values supported: # "X86_64", "AMD_64", "X86_32", "ARM_32", "MIPS_32", "XTENSA_32" diff --git a/wamr-compiler/main.c b/wamr-compiler/main.c index 9a9d212fa..72f717075 100644 --- a/wamr-compiler/main.c +++ b/wamr-compiler/main.c @@ -35,6 +35,7 @@ print_help() printf(" object Native object file\n"); printf(" llvmir-unopt Unoptimized LLVM IR\n"); printf(" llvmir-opt Optimized LLVM IR\n"); + printf(" --enable-bulk-memory Enable the post-MVP bulk memory feature\n"); printf(" -v=n Set log verbose level (0 to 5, default is 2), larger with more log\n"); printf("Examples: wamrc -o test.aot test.wasm\n"); printf(" wamrc --target=i386 -o test.aot test.wasm\n"); @@ -127,6 +128,9 @@ main(int argc, char *argv[]) if (log_verbose_level < 0 || log_verbose_level > 5) return print_help(); } + else if (!strcmp(argv[0], "--enable-bulk-memory")) { + option.enable_bulk_memory = true; + } else return print_help(); } From 5d86060d35f1cf73e0022081898d9f38c1ae55a5 Mon Sep 17 00:00:00 2001 From: dpinthinker Date: Wed, 3 Jun 2020 15:17:22 +0800 Subject: [PATCH 014/207] fix one typo in samples/basic.README.md (#274) --- samples/basic/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/basic/README.md b/samples/basic/README.md index d12f501fd..32e7ed650 100644 --- a/samples/basic/README.md +++ b/samples/basic/README.md @@ -25,7 +25,7 @@ Enter the out directory. ``` $ cd ./out/ $ -$ ./basic wasm-apps/testapp.wasm +$ ./basic -f wasm-apps/testapp.wasm calling into WASM function: generate_float Native finished calling wasm function generate_float(), returned a float value: 102009.921875f calling into WASM function: float_to_string From 002f3b7ac4cf574aa490e5eacc43d960fb05943e Mon Sep 17 00:00:00 2001 From: J-Heinemann <66268543+J-Heinemann@users.noreply.github.com> Date: Mon, 8 Jun 2020 05:00:22 +0200 Subject: [PATCH 015/207] Missing SGX SDK Include fixed (#275) * Missing SGX SDK Include fixed * Update shared_platform.cmake Co-authored-by: Joshua Heinemann Co-authored-by: wenyongh --- core/shared/platform/linux-sgx/shared_platform.cmake | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/core/shared/platform/linux-sgx/shared_platform.cmake b/core/shared/platform/linux-sgx/shared_platform.cmake index dd1303ed4..810a7cf2e 100644 --- a/core/shared/platform/linux-sgx/shared_platform.cmake +++ b/core/shared/platform/linux-sgx/shared_platform.cmake @@ -8,6 +8,15 @@ add_definitions(-DBH_PLATFORM_LINUX_SGX) include_directories(${PLATFORM_SHARED_DIR}) include_directories(${PLATFORM_SHARED_DIR}/../include) +if ("$ENV{SGX_SDK}" STREQUAL "") + set (SGX_SDK_DIR "/opt/intel/sgxsdk") +else() + set (SGX_SDK_DIR $ENV{SGX_SDK}) +endif() + +include_directories (${SGX_SDK_DIR}/include + ${SGX_SDK_DIR}/include/tlibc + ${SGX_SDK_DIR}/include/libcxx) file (GLOB_RECURSE source_all ${PLATFORM_SHARED_DIR}/*.c) From 7a287fd1a90836bb3de86eba9889cd689bd493ab Mon Sep 17 00:00:00 2001 From: wenyongh Date: Mon, 8 Jun 2020 11:19:09 +0800 Subject: [PATCH 016/207] Implement wasm mini loader and refine footprint of loader and runtime (#276) --- build-scripts/config_common.cmake | 10 +- core/config.h | 5 + core/iwasm/aot/aot_loader.c | 184 +- core/iwasm/aot/aot_runtime.c | 50 +- core/iwasm/common/wasm_runtime_common.c | 88 +- core/iwasm/interpreter/iwasm_interp.cmake | 8 +- core/iwasm/interpreter/wasm_loader.c | 262 +- core/iwasm/interpreter/wasm_mini_loader.c | 4947 +++++++++++++++++ core/iwasm/interpreter/wasm_runtime.c | 141 +- doc/build_wamr.md | 5 + .../platforms/linux-sgx/CMakeLists.txt | 11 +- product-mini/platforms/linux/CMakeLists.txt | 5 + 12 files changed, 5285 insertions(+), 431 deletions(-) create mode 100644 core/iwasm/interpreter/wasm_mini_loader.c diff --git a/build-scripts/config_common.cmake b/build-scripts/config_common.cmake index 6187910d8..106427566 100644 --- a/build-scripts/config_common.cmake +++ b/build-scripts/config_common.cmake @@ -133,10 +133,16 @@ endif () if (WAMR_BUILD_SPEC_TEST EQUAL 1) add_definitions (-DWASM_ENABLE_SPEC_TEST=1) message (" spec test compatible mode is on") -endif() +endif () if (WAMR_BUILD_BULK_MEMORY EQUAL 1) add_definitions (-DWASM_ENABLE_BULK_MEMORY=1) message (" Bulk memory feature enabled") else () add_definitions (-DWASM_ENABLE_BULK_MEMORY=0) -endif() +endif () +if (WAMR_BUILD_MINI_LOADER EQUAL 1) + add_definitions (-DWASM_ENABLE_MINI_LOADER=1) + message (" WASM mini loader enabled") +else () + add_definitions (-DWASM_ENABLE_MINI_LOADER=0) +endif () diff --git a/core/config.h b/core/config.h index e54a4be0c..2bbcb7bf7 100644 --- a/core/config.h +++ b/core/config.h @@ -130,6 +130,11 @@ enum { #define WASM_ENABLE_MULTI_MODULE 0 #endif +/* Enable wasm mini loader or not */ +#ifndef WASM_ENABLE_MINI_LOADER +#define WASM_ENABLE_MINI_LOADER 0 +#endif + /* Heap and stack profiling */ #define BH_ENABLE_MEMORY_PROFILING 0 diff --git a/core/iwasm/aot/aot_loader.c b/core/iwasm/aot/aot_loader.c index ab043afe1..8803213e7 100644 --- a/core/iwasm/aot/aot_loader.c +++ b/core/iwasm/aot/aot_loader.c @@ -59,13 +59,24 @@ static union { #define is_little_endian() (__ue.b == 1) -#define CHECK_BUF(buf, buf_end, length) do { \ - if (buf + length > buf_end) { \ - set_error_buf(error_buf, error_buf_size, \ - "Read data failed: unexpected end."); \ - goto fail; \ - } \ - } while (0) +static bool +check_buf(const uint8 *buf, const uint8 *buf_end, uint32 length, + char *error_buf, uint32 error_buf_size) +{ + if (buf + length > buf_end) { + set_error_buf(error_buf, error_buf_size, + "AOT module load failed: unexpect end."); + return false; + } + return true; +} + +#define CHECK_BUF(buf, buf_end, length) do { \ + if (!check_buf(buf, buf_end, length, \ + error_buf, error_buf_size)) { \ + goto fail; \ + } \ +} while (0) static uint8* align_ptr(const uint8 *p, uint32 b) @@ -150,17 +161,32 @@ GET_U64_FROM_ADDR(uint32 *addr) /* Legal values for e_version */ #define E_VERSION_CURRENT 1 /* Current version */ +static void * +loader_malloc(uint64 size, char *error_buf, uint32 error_buf_size) +{ + void *mem; + + if (size >= UINT32_MAX + || !(mem = wasm_runtime_malloc((uint32)size))) { + set_error_buf(error_buf, error_buf_size, + "AOT module load failed: " + "allocate memory failed."); + return NULL; + } + + memset(mem, 0, (uint32)size); + return mem; +} + static char* const_str_set_insert(const uint8 *str, int32 len, AOTModule *module, char* error_buf, uint32 error_buf_size) { HashMap *set = module->const_str_set; - char *c_str = wasm_runtime_malloc((uint32)len + 1), *value; + char *c_str, *value; - if (!c_str) { - set_error_buf(error_buf, error_buf_size, - "AOT module load failed: " - "allocate memory failed."); + if (!(c_str = loader_malloc((uint32)len + 1, + error_buf, error_buf_size))) { return NULL; } @@ -348,17 +374,11 @@ load_mem_init_data_list(const uint8 **p_buf, const uint8 *buf_end, /* Allocate memory */ size = sizeof(AOTMemInitData *) * (uint64)module->mem_init_data_count; - if (size >= UINT32_MAX - || !(module->mem_init_data_list = - data_list = wasm_runtime_malloc((uint32)size))) { - set_error_buf(error_buf, error_buf_size, - "AOT module load failed: " - "allocate memory failed."); + if (!(module->mem_init_data_list = data_list = + loader_malloc(size, error_buf, error_buf_size))) { return false; } - memset(data_list, 0, size); - /* Create each memory data segment */ for (i = 0; i < module->mem_init_data_count; i++) { uint32 init_expr_type, byte_count; @@ -372,11 +392,8 @@ load_mem_init_data_list(const uint8 **p_buf, const uint8 *buf_end, read_uint64(buf, buf_end, init_expr_value); read_uint32(buf, buf_end, byte_count); size = offsetof(AOTMemInitData, bytes) + (uint64)byte_count; - if (size >= UINT32_MAX - || !(data_list[i] = wasm_runtime_malloc((uint32)size))) { - set_error_buf(error_buf, error_buf_size, - "AOT module load failed: " - "allocate memory failed."); + if (!(data_list[i] = loader_malloc + (size, error_buf, error_buf_size))) { return false; } @@ -447,17 +464,11 @@ load_table_init_data_list(const uint8 **p_buf, const uint8 *buf_end, /* Allocate memory */ size = sizeof(AOTTableInitData *) * (uint64)module->table_init_data_count; - if (size >= UINT32_MAX - || !(module->table_init_data_list = - data_list = wasm_runtime_malloc((uint32)size))) { - set_error_buf(error_buf, error_buf_size, - "AOT module load failed: " - "allocate memory failed."); + if (!(module->table_init_data_list = data_list = + loader_malloc(size, error_buf, error_buf_size))) { return false; } - memset(data_list, 0, size); - /* Create each table data segment */ for (i = 0; i < module->table_init_data_count; i++) { uint32 init_expr_type, func_index_count; @@ -469,11 +480,8 @@ load_table_init_data_list(const uint8 **p_buf, const uint8 *buf_end, size1 = sizeof(uint32) * (uint64)func_index_count; size = offsetof(AOTTableInitData, func_indexes) + size1; - if (size >= UINT32_MAX - || !(data_list[i] = wasm_runtime_malloc((uint32)size))) { - set_error_buf(error_buf, error_buf_size, - "AOT module load failed: " - "allocate memory failed."); + if (!(data_list[i] = loader_malloc + (size, error_buf, error_buf_size))) { return false; } @@ -535,16 +543,11 @@ load_func_types(const uint8 **p_buf, const uint8 *buf_end, /* Allocate memory */ size = sizeof(AOTFuncType *) * (uint64)module->func_type_count; - if (size >= UINT32_MAX - || !(module->func_types = func_types = wasm_runtime_malloc((uint32)size))) { - set_error_buf(error_buf, error_buf_size, - "AOT module load failed: " - "allocate memory failed."); + if (!(module->func_types = func_types = loader_malloc + (size, error_buf, error_buf_size))) { return false; } - memset(func_types, 0, size); - /* Create each function type */ for (i = 0; i < module->func_type_count; i++) { uint32 param_count, result_count; @@ -555,11 +558,8 @@ load_func_types(const uint8 **p_buf, const uint8 *buf_end, size1 = (uint64)param_count + (uint64)result_count; size = offsetof(AOTFuncType, types) + size1; - if (size >= UINT32_MAX - || !(func_types[i] = wasm_runtime_malloc((uint32)size))) { - set_error_buf(error_buf, error_buf_size, - "AOT module load failed: " - "allocate memory failed."); + if (!(func_types[i] = loader_malloc + (size, error_buf, error_buf_size))) { return false; } @@ -613,17 +613,11 @@ load_import_globals(const uint8 **p_buf, const uint8 *buf_end, /* Allocate memory */ size = sizeof(AOTImportGlobal) * (uint64)module->import_global_count; - if (size >= UINT32_MAX - || !(module->import_globals = - import_globals = wasm_runtime_malloc((uint32)size))) { - set_error_buf(error_buf, error_buf_size, - "AOT module load failed: " - "allocate memory failed."); + if (!(module->import_globals = import_globals = + loader_malloc(size, error_buf, error_buf_size))) { return false; } - memset(import_globals, 0, size); - /* Create each import global */ for (i = 0; i < module->import_global_count; i++) { buf = (uint8*)align_ptr(buf, 2); @@ -685,16 +679,11 @@ load_globals(const uint8 **p_buf, const uint8 *buf_end, /* Allocate memory */ size = sizeof(AOTGlobal) * (uint64)module->global_count; - if (size >= UINT32_MAX - || !(module->globals = globals = wasm_runtime_malloc((uint32)size))) { - set_error_buf(error_buf, error_buf_size, - "AOT module load failed: " - "allocate memory failed."); + if (!(module->globals = globals = loader_malloc + (size, error_buf, error_buf_size))) { return false; } - memset(globals, 0, size); - if (module->import_global_count > 0) { last_import_global = &module->import_globals[module->import_global_count - 1]; @@ -767,17 +756,11 @@ load_import_funcs(const uint8 **p_buf, const uint8 *buf_end, /* Allocate memory */ size = sizeof(AOTImportFunc) * (uint64)module->import_func_count; - if (size >= UINT32_MAX - || !(module->import_funcs = - import_funcs = wasm_runtime_malloc((uint32)size))) { - set_error_buf(error_buf, error_buf_size, - "AOT module load failed: " - "allocate memory failed."); + if (!(module->import_funcs = import_funcs = + loader_malloc(size, error_buf, error_buf_size))) { return false; } - memset(import_funcs, 0, size); - /* Create each import func */ for (i = 0; i < module->import_func_count; i++) { read_uint16(buf, buf_end, import_funcs[i].func_type_index); @@ -860,17 +843,11 @@ load_object_data_sections(const uint8 **p_buf, const uint8 *buf_end, /* Allocate memory */ size = sizeof(AOTObjectDataSection) * (uint64)module->data_section_count; - if (size >= UINT32_MAX - || !(module->data_sections = - data_sections = wasm_runtime_malloc((uint32)size))) { - set_error_buf(error_buf, error_buf_size, - "AOT module load failed: " - "allocate memory failed."); + if (!(module->data_sections = data_sections = + loader_malloc(size, error_buf, error_buf_size))) { return false; } - memset(data_sections, 0, size); - /* Create each data section */ for (i = 0; i < module->data_section_count; i++) { int map_prot = MMAP_PROT_READ | MMAP_PROT_WRITE; @@ -1021,10 +998,8 @@ load_function_section(const uint8 *buf, const uint8 *buf_end, uint64 size, text_offset; size = sizeof(void*) * (uint64)module->func_count; - if (size >= UINT32_MAX - || !(module->func_ptrs = wasm_runtime_malloc((uint32)size))) { - set_error_buf(error_buf, error_buf_size, - "AOT module load failed: allocate memory failed."); + if (!(module->func_ptrs = loader_malloc + (size, error_buf, error_buf_size))) { return false; } @@ -1065,10 +1040,8 @@ load_function_section(const uint8 *buf, const uint8 *buf_end, } size = sizeof(uint32) * (uint64)module->func_count; - if (size >= UINT32_MAX - || !(module->func_type_indexes = wasm_runtime_malloc((uint32)size))) { - set_error_buf(error_buf, error_buf_size, - "AOT module load failed: allocate memory failed."); + if (!(module->func_type_indexes = loader_malloc + (size, error_buf, error_buf_size))) { return false; } @@ -1112,17 +1085,11 @@ load_export_funcs(const uint8 **p_buf, const uint8 *buf_end, /* Allocate memory */ size = sizeof(AOTExportFunc) * (uint64)module->export_func_count; - if (size >= UINT32_MAX - || !(module->export_funcs = - export_funcs = wasm_runtime_malloc((uint32)size))) { - set_error_buf(error_buf, error_buf_size, - "AOT module load failed: " - "allocate memory failed."); + if (!(module->export_funcs = export_funcs = + loader_malloc(size, error_buf, error_buf_size))) { return false; } - memset(export_funcs, 0, size); - /* Create each export func */ for (i = 0; i < module->export_func_count; i++) { read_uint32(buf, buf_end, export_funcs[i].func_index); @@ -1234,10 +1201,8 @@ do_text_relocation(AOTModule *module, if (symbol_len + 1 <= sizeof(symbol_buf)) symbol = symbol_buf; else { - if (!(symbol = wasm_runtime_malloc(symbol_len + 1))) { - set_error_buf(error_buf, error_buf_size, - "AOT module load failed: " - "allocate memory failed."); + if (!(symbol = loader_malloc(symbol_len + 1, + error_buf, error_buf_size))) { return false; } } @@ -1432,15 +1397,10 @@ load_relocation_section(const uint8 *buf, const uint8 *buf_end, /* Allocate memory for relocation groups */ size = sizeof(AOTRelocationGroup) * (uint64)group_count; - if (size >= UINT32_MAX || !(groups = wasm_runtime_malloc((uint32)size))) { - set_error_buf(error_buf, error_buf_size, - "AOT module load failed: " - "allocate memory failed."); + if (!(groups = loader_malloc(size, error_buf, error_buf_size))) { goto fail; } - memset(groups, 0, size); - /* Load each relocation group */ for (i = 0, group = groups; i < group_count; i++, group++) { AOTRelocation *relocation; @@ -1473,18 +1433,12 @@ load_relocation_section(const uint8 *buf, const uint8 *buf_end, /* Allocate memory for relocations */ size = sizeof(AOTRelocation) * (uint64)group->relocation_count; - if (size >= UINT32_MAX - || !(group->relocations = relocation = - wasm_runtime_malloc((uint32)size))) { - set_error_buf(error_buf, error_buf_size, - "AOT module load failed: " - "allocate memory failed."); + if (!(group->relocations = relocation = + loader_malloc(size, error_buf, error_buf_size))) { ret = false; goto fail; } - memset(group->relocations, 0, size); - /* Load each relocation */ for (j = 0; j < group->relocation_count; j++, relocation++) { uint32 symbol_index; diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index d42989d21..65975a10c 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -14,6 +14,23 @@ set_error_buf(char *error_buf, uint32 error_buf_size, const char *string) snprintf(error_buf, error_buf_size, "%s", string); } +static void * +runtime_malloc(uint64 size, char *error_buf, uint32 error_buf_size) +{ + void *mem; + + if (size >= UINT32_MAX + || !(mem = wasm_runtime_malloc((uint32)size))) { + set_error_buf(error_buf, error_buf_size, + "AOT module instantiate failed: " + "allocate memory failed."); + return NULL; + } + + memset(mem, 0, (uint32)size); + return mem; +} + static bool global_instantiate(AOTModuleInstance *module_inst, AOTModule *module, char *error_buf, uint32 error_buf_size) @@ -142,15 +159,10 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModule *module, uint8 *p; /* Allocate memory */ - if (total_size >= UINT32_MAX - || !(p = wasm_runtime_malloc((uint32)total_size))) { - set_error_buf(error_buf, error_buf_size, - "AOT module instantiate failed: allocate memory failed."); + if (!(p = runtime_malloc(total_size, error_buf, error_buf_size))) { return false; } - memset(p, 0, (uint32)total_size); - /* Initialize heap info */ module_inst->heap_data.ptr = p; p += heap_size; @@ -270,15 +282,11 @@ init_func_ptrs(AOTModuleInstance *module_inst, AOTModule *module, ((uint64)module->import_func_count + module->func_count) * sizeof(void*); /* Allocate memory */ - if (total_size >= UINT32_MAX - || !(module_inst->func_ptrs.ptr = wasm_runtime_malloc((uint32)total_size))) { - set_error_buf(error_buf, error_buf_size, - "AOT module instantiate failed: allocate memory failed."); + if (!(module_inst->func_ptrs.ptr = runtime_malloc + (total_size, error_buf, error_buf_size))) { return false; } - memset(module_inst->func_ptrs.ptr, 0, (uint32)total_size); - /* Set import function pointers */ func_ptrs = (void**)module_inst->func_ptrs.ptr; for (i = 0; i < module->import_func_count; i++, func_ptrs++) @@ -299,16 +307,11 @@ init_func_type_indexes(AOTModuleInstance *module_inst, AOTModule *module, ((uint64)module->import_func_count + module->func_count) * sizeof(uint32); /* Allocate memory */ - if (total_size >= UINT32_MAX - || !(module_inst->func_type_indexes.ptr = - wasm_runtime_malloc((uint32)total_size))) { - set_error_buf(error_buf, error_buf_size, - "AOT module instantiate failed: allocate memory failed."); + if (!(module_inst->func_type_indexes.ptr = + runtime_malloc(total_size, error_buf, error_buf_size))) { return false; } - memset(module_inst->func_type_indexes.ptr, 0, (uint32)total_size); - /* Set import function type indexes */ func_type_index = (uint32*)module_inst->func_type_indexes.ptr; for (i = 0; i < module->import_func_count; i++, func_type_index++) @@ -381,14 +384,11 @@ aot_instantiate(AOTModule *module, heap_size = APP_HEAP_SIZE_MAX; /* Allocate module instance, global data, table data and heap data */ - if (total_size >= UINT32_MAX - || !(module_inst = wasm_runtime_malloc((uint32)total_size))) { - set_error_buf(error_buf, error_buf_size, - "AOT module instantiate failed: allocate memory failed."); + if (!(module_inst = runtime_malloc(total_size, + error_buf, error_buf_size))) { return NULL; } - memset(module_inst, 0, total_size); module_inst->module_type = Wasm_Module_AoT; module_inst->aot_module.ptr = module; @@ -801,7 +801,7 @@ aot_enlarge_memory(AOTModuleInstance *module_inst, uint32 inc_page_count) /* Destroy heap's lock firstly, if its memory is re-allocated, we cannot access its lock again. */ mem_allocator_destroy_lock(module_inst->heap_handle.ptr); - if (!(heap_data = wasm_runtime_realloc(heap_handle_old, (uint32)total_size))) { + if (!(heap_data = wasm_runtime_realloc(heap_data_old, (uint32)total_size))) { if (!(heap_data = wasm_runtime_malloc((uint32)total_size))) { /* Restore heap's lock if memory re-alloc failed */ mem_allocator_reinit_lock(module_inst->heap_handle.ptr); diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index c3b6da951..02cd58634 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -60,6 +60,29 @@ set_error_buf(char *error_buf, uint32 error_buf_size, const char *string) snprintf(error_buf, error_buf_size, "%s", string); } +static void * +runtime_malloc(uint64 size, WASMModuleInstanceCommon *module_inst, + char *error_buf, uint32 error_buf_size) +{ + void *mem; + + if (size >= UINT32_MAX + || !(mem = wasm_runtime_malloc((uint32)size))) { + if (module_inst != NULL) { + wasm_runtime_set_exception(module_inst, + "allocate memory failed."); + } + else if (error_buf != NULL) { + set_error_buf(error_buf, error_buf_size, + "allocate memory failed."); + } + return NULL; + } + + memset(mem, 0, (uint32)size); + return mem; +} + static bool wasm_runtime_env_init() { @@ -91,12 +114,12 @@ wasm_runtime_env_init() static bool wasm_runtime_exec_env_check(WASMExecEnv *exec_env) { - return !(!exec_env - || !exec_env->module_inst - || exec_env->wasm_stack_size == 0 - || exec_env->wasm_stack.s.top_boundary != + return exec_env + && exec_env->module_inst + && exec_env->wasm_stack_size > 0 + && exec_env->wasm_stack.s.top_boundary == exec_env->wasm_stack.s.bottom + exec_env->wasm_stack_size - || exec_env->wasm_stack.s.top > exec_env->wasm_stack.s.top_boundary); + && exec_env->wasm_stack.s.top <= exec_env->wasm_stack.s.top_boundary; } bool @@ -240,13 +263,10 @@ wasm_runtime_register_module_internal(const char *module_name, } /* module hasn't been registered */ - node = wasm_runtime_malloc(sizeof(WASMRegisteredModule)); + node = runtime_malloc(sizeof(WASMRegisteredModule), NULL, NULL, 0); if (!node) { LOG_DEBUG("malloc WASMRegisteredModule failed. SZ=%d", sizeof(WASMRegisteredModule)); - set_error_buf_v(error_buf, error_buf_size, - "malloc WASMRegisteredModule failed. SZ=%d", - sizeof(WASMRegisteredModule)); return false; } @@ -377,16 +397,15 @@ wasm_runtime_destroy_registered_module_list() } bool -wasm_runtime_add_loading_module(const char *module_name, char *error_buf, - uint32 error_buf_size) +wasm_runtime_add_loading_module(const char *module_name, + char *error_buf, uint32 error_buf_size) { LOG_DEBUG("add %s into a loading list", module_name); - LoadingModule *loadingModule = wasm_runtime_malloc(sizeof(LoadingModule)); + LoadingModule *loadingModule = + runtime_malloc(sizeof(LoadingModule), NULL, + error_buf, error_buf_size); if (!loadingModule) { - set_error_buf_v(error_buf, error_buf_size, - "malloc LoadingModule failed. SZ=%d", - sizeof(LoadingModule)); return false; } @@ -1145,13 +1164,11 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, uint64 total_size; uint32 i; - if (!(wasi_ctx = wasm_runtime_malloc(sizeof(WASIContext)))) { - set_error_buf(error_buf, error_buf_size, - "Init wasi environment failed: allocate memory failed."); + if (!(wasi_ctx = runtime_malloc(sizeof(WASIContext), NULL, + error_buf, error_buf_size))) { return false; } - memset(wasi_ctx, 0, sizeof(WASIContext)); wasm_runtime_set_wasi_ctx(module_inst, wasi_ctx); #if WASM_ENABLE_INTERP != 0 @@ -1645,12 +1662,11 @@ resolve_function(const WASMModuleInstanceCommon *module_inst, char *function_name = NULL; uint32 length = strlen(name) + 1; - orig_name = wasm_runtime_malloc(sizeof(char) * length); + orig_name = runtime_malloc(sizeof(char) * length, NULL, NULL, 0); if (!orig_name) { return NULL; } - memset(orig_name, 0, sizeof(char) * length); strncpy(orig_name, name, length); if (!parse_function_name(orig_name, &sub_module_name, &function_name)) { @@ -1808,9 +1824,8 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, } total_size = sizeof(uint32) * (uint64)(argc1 > 2 ? argc1 : 2); - if (total_size >= UINT32_MAX - || (!(argv1 = wasm_runtime_malloc((uint32)total_size)))) { - wasm_runtime_set_exception(module_inst, "allocate memory failed."); + if ((!(argv1 = runtime_malloc((uint32)total_size, module_inst, + NULL, 0)))) { goto fail; } @@ -2008,13 +2023,10 @@ wasm_runtime_invoke_native_raw(WASMExecEnv *exec_env, void *func_ptr, argc1 = func_type->param_count; if (argc1 > sizeof(argv_buf) / sizeof(uint64)) { size = sizeof(uint64) * (uint64)argc1; - if (size >= UINT32_MAX - || !(argv1 = wasm_runtime_malloc((uint32)size))) { - wasm_runtime_set_exception(exec_env->module_inst, - "allocate memory failed."); + if (!(argv1 = runtime_malloc((uint32)size, exec_env->module_inst, + NULL, 0))) { return false; } - memset(argv1, 0, (uint32)size); } argv_dst = argv1; @@ -2208,10 +2220,8 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, argc1 = MAX_REG_INTS + MAX_REG_FLOATS + n_stacks; if (argc1 > sizeof(argv_buf) / sizeof(uint32)) { size = sizeof(uint32) * (uint32)argc1; - if (size >= UINT32_MAX - || !(argv1 = wasm_runtime_malloc((uint32)size))) { - wasm_runtime_set_exception(exec_env->module_inst, - "allocate memory failed."); + if (!(argv1 = runtime_malloc((uint32)size, exec_env->module_inst, + NULL, 0))) { return false; } } @@ -2386,10 +2396,8 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, if (argc1 > sizeof(argv_buf) / sizeof(uint32)) { size = sizeof(uint32) * (uint64)argc1; - if (size >= UINT_MAX - || !(argv1 = wasm_runtime_malloc((uint32)size))) { - wasm_runtime_set_exception(exec_env->module_inst, - "allocate memory failed."); + if (!(argv1 = runtime_malloc((uint32)size, exec_env->module_inst, + NULL, 0))) { return false; } } @@ -2543,10 +2551,8 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, argc1 = 1 + MAX_REG_FLOATS + func_type->param_count + 2; if (argc1 > sizeof(argv_buf) / sizeof(uint64)) { size = sizeof(uint64) * (uint64)argc1; - if (size >= UINT32_MAX - || !(argv1 = wasm_runtime_malloc((uint32)size))) { - wasm_runtime_set_exception(exec_env->module_inst, - "allocate memory failed."); + if (!(argv1 = runtime_malloc((uint32)size, exec_env->module_inst, + NULL, 0))) { return false; } } diff --git a/core/iwasm/interpreter/iwasm_interp.cmake b/core/iwasm/interpreter/iwasm_interp.cmake index bb4f23219..e6e52e42c 100644 --- a/core/iwasm/interpreter/iwasm_interp.cmake +++ b/core/iwasm/interpreter/iwasm_interp.cmake @@ -13,8 +13,14 @@ else () set (INTERPRETER "wasm_interp_classic.c") endif () +if (WAMR_BUILD_MINI_LOADER EQUAL 1) + set (LOADER "wasm_mini_loader.c") +else () + set (LOADER "wasm_loader.c") +endif () + file (GLOB_RECURSE source_all - ${IWASM_INTERP_DIR}/wasm_loader.c + ${IWASM_INTERP_DIR}/${LOADER} ${IWASM_INTERP_DIR}/wasm_runtime.c ${IWASM_INTERP_DIR}/${INTERPRETER} ) diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index b8f4f6933..042a503ed 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -24,21 +24,43 @@ set_error_buf(char *error_buf, uint32 error_buf_size, const char *string) snprintf(error_buf, error_buf_size, "%s", string); } -#define CHECK_BUF(buf, buf_end, length) do { \ - if (buf + length > buf_end) { \ - set_error_buf(error_buf, error_buf_size, \ - "WASM module load failed: " \ - "unexpected end of section or function"); \ - return false; \ - } \ +static bool +check_buf(const uint8 *buf, const uint8 *buf_end, uint32 length, + char *error_buf, uint32 error_buf_size) +{ + if (buf + length > buf_end) { + set_error_buf(error_buf, error_buf_size, + "WASM module load failed: " + "unexpected end of section or function"); + return false; + } + return true; +} + +static bool +check_buf1(const uint8 *buf, const uint8 *buf_end, uint32 length, + char *error_buf, uint32 error_buf_size) +{ + if (buf + length > buf_end) { + set_error_buf(error_buf, error_buf_size, + "WASM module load failed: unexpected end"); + return false; + } + return true; +} + +#define CHECK_BUF(buf, buf_end, length) do { \ + if (!check_buf(buf, buf_end, length, \ + error_buf, error_buf_size)) { \ + return false; \ + } \ } while (0) -#define CHECK_BUF1(buf, buf_end, length) do { \ - if (buf + length > buf_end) { \ - set_error_buf(error_buf, error_buf_size, \ - "WASM module load failed: unexpected end");\ - return false; \ - } \ +#define CHECK_BUF1(buf, buf_end, length) do { \ + if (!check_buf1(buf, buf_end, length, \ + error_buf, error_buf_size)) { \ + return false; \ + } \ } while (0) static bool @@ -193,6 +215,23 @@ fail_integer_too_large: res = (int32)res64; \ } while (0) +static void * +loader_malloc(uint64 size, char *error_buf, uint32 error_buf_size) +{ + void *mem; + + if (size >= UINT32_MAX + || !(mem = wasm_runtime_malloc((uint32)size))) { + set_error_buf(error_buf, error_buf_size, + "WASM module load failed: " + "allocate memory failed."); + return NULL; + } + + memset(mem, 0, (uint32)size); + return mem; +} + static bool check_utf8_str(const uint8* str, uint32 len) { @@ -256,10 +295,8 @@ const_str_list_insert(const uint8 *str, uint32 len, WASMModule *module, return node->str; } - if (!(node = wasm_runtime_malloc(sizeof(StringNode) + len + 1))) { - set_error_buf(error_buf, error_buf_size, - "WASM module load failed: " - "allocate memory failed."); + if (!(node = loader_malloc(sizeof(StringNode) + len + 1, + error_buf, error_buf_size))) { return NULL; } @@ -361,15 +398,11 @@ load_type_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, if (type_count) { module->type_count = type_count; total_size = sizeof(WASMType*) * (uint64)type_count; - if (total_size >= UINT32_MAX - || !(module->types = wasm_runtime_malloc((uint32)total_size))) { - set_error_buf(error_buf, error_buf_size, - "Load type section failed: allocate memory failed."); + if (!(module->types = loader_malloc + (total_size, error_buf, error_buf_size))) { return false; } - memset(module->types, 0, (uint32)total_size); - for (i = 0; i < type_count; i++) { CHECK_BUF(p, p_end, 1); flag = read_uint8(p); @@ -396,11 +429,8 @@ load_type_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, total_size = offsetof(WASMType, types) + sizeof(uint8) * (uint64)(param_count + result_count); - if (total_size >= UINT32_MAX - || !(type = module->types[i] = - wasm_runtime_malloc((uint32)total_size))) { - set_error_buf(error_buf, error_buf_size, - "Load type section failed: allocate memory failed."); + if (!(type = module->types[i] = + loader_malloc(total_size, error_buf, error_buf_size))) { return false; } @@ -808,12 +838,6 @@ load_table_import(WASMModule *sub_module, const char *sub_module_name, } *p_buf = p; - if ((declare_max_size_flag & 1) && declare_init_size > declare_max_size) { - set_error_buf(error_buf, error_buf_size, - "size minimum must not be greater than maximum"); - return false; - } - #if WASM_ENABLE_MULTI_MODULE != 0 if (!wasm_runtime_is_built_in_module(sub_module_name)) { linked_table = wasm_loader_resolve_table( @@ -1093,12 +1117,6 @@ load_table(const uint8 **p_buf, const uint8 *buf_end, WASMTable *table, else table->max_size = 0x10000; - if ((table->flags & 1) && table->init_size > table->max_size) { - set_error_buf(error_buf, error_buf_size, - "size minimum must not be greater than maximum"); - return false; - } - *p_buf = p; return true; } @@ -1327,15 +1345,11 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, if (import_count) { module->import_count = import_count; total_size = sizeof(WASMImport) * (uint64)import_count; - if (total_size >= UINT32_MAX - || !(module->imports = wasm_runtime_malloc((uint32)total_size))) { - set_error_buf(error_buf, error_buf_size, - "Load import section failed: allocate memory failed."); + if (!(module->imports = loader_malloc + (total_size, error_buf, error_buf_size))) { return false; } - memset(module->imports, 0, (uint32)total_size); - p_old = p; /* Scan firstly to get import count of each type */ @@ -1576,10 +1590,8 @@ init_function_local_offsets(WASMFunction *func, uint32 i, local_offset = 0; uint64 total_size = sizeof(uint16) * ((uint64)param_count + local_count); - if (total_size >= UINT32_MAX - || !(func->local_offsets = wasm_runtime_malloc((uint32)total_size))) { - set_error_buf(error_buf, error_buf_size, - "Load function section failed: allocate memory failed."); + if (!(func->local_offsets = + loader_malloc(total_size, error_buf, error_buf_size))) { return false; } @@ -1627,15 +1639,11 @@ load_function_section(const uint8 *buf, const uint8 *buf_end, if (func_count) { module->function_count = func_count; total_size = sizeof(WASMFunction*) * (uint64)func_count; - if (total_size >= UINT32_MAX - || !(module->functions = wasm_runtime_malloc((uint32)total_size))) { - set_error_buf(error_buf, error_buf_size, - "Load function section failed: allocate memory failed."); + if (!(module->functions = + loader_malloc(total_size, error_buf, error_buf_size))) { return false; } - memset(module->functions, 0, (uint32)total_size); - for (i = 0; i < func_count; i++) { /* Resolve function type */ read_leb_uint32(p, p_end, type_index); @@ -1680,17 +1688,12 @@ load_function_section(const uint8 *buf, const uint8 *buf_end, code_size = (uint32)(p_code_end - p_code); total_size = sizeof(WASMFunction) + (uint64)local_count; - if (total_size >= UINT32_MAX - || !(func = module->functions[i] = - wasm_runtime_malloc((uint32)total_size))) { - set_error_buf(error_buf, error_buf_size, - "Load function section failed: " - "allocate memory failed."); + if (!(func = module->functions[i] = + loader_malloc(total_size, error_buf, error_buf_size))) { return false; } /* Set function type, local count, code size and code body */ - memset(func, 0, (uint32)total_size); func->func_type = module->types[type_index]; func->local_count = local_count; if (local_count > 0) @@ -1775,15 +1778,11 @@ load_table_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, if (table_count) { module->table_count = table_count; total_size = sizeof(WASMTable) * (uint64)table_count; - if (total_size >= UINT32_MAX - || !(module->tables = wasm_runtime_malloc((uint32)total_size))) { - set_error_buf(error_buf, error_buf_size, - "Load table section failed: allocate memory failed."); + if (!(module->tables = loader_malloc + (total_size, error_buf, error_buf_size))) { return false; } - memset(module->tables, 0, (uint32)total_size); - /* load each table */ table = module->tables; for (i = 0; i < table_count; i++, table++) @@ -1820,15 +1819,11 @@ load_memory_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, if (memory_count) { module->memory_count = memory_count; total_size = sizeof(WASMMemory) * (uint64)memory_count; - if (total_size >= UINT32_MAX - || !(module->memories = wasm_runtime_malloc((uint32)total_size))) { - set_error_buf(error_buf, error_buf_size, - "Load memory section failed: allocate memory failed."); + if (!(module->memories = loader_malloc + (total_size, error_buf, error_buf_size))) { return false; } - memset(module->memories, 0, (uint32)total_size); - /* load each memory */ memory = module->memories; for (i = 0; i < memory_count; i++, memory++) @@ -1861,16 +1856,11 @@ load_global_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, if (global_count) { module->global_count = global_count; total_size = sizeof(WASMGlobal) * (uint64)global_count; - if (total_size >= UINT32_MAX - || !(module->globals = wasm_runtime_malloc((uint32)total_size))) { - set_error_buf(error_buf, error_buf_size, - "Load global section failed: " - "allocate memory failed."); + if (!(module->globals = loader_malloc + (total_size, error_buf, error_buf_size))) { return false; } - memset(module->globals, 0, (uint32)total_size); - global = module->globals; for(i = 0; i < global_count; i++, global++) { @@ -1932,16 +1922,11 @@ load_export_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, if (export_count) { module->export_count = export_count; total_size = sizeof(WASMExport) * (uint64)export_count; - if (total_size >= UINT32_MAX - || !(module->exports = wasm_runtime_malloc((uint32)total_size))) { - set_error_buf(error_buf, error_buf_size, - "Load export section failed: " - "allocate memory failed."); + if (!(module->exports = loader_malloc + (total_size, error_buf, error_buf_size))) { return false; } - memset(module->exports, 0, (uint32)total_size); - export = module->exports; for (i = 0; i < export_count; i++, export++) { read_leb_uint32(p, p_end, str_len); @@ -2038,16 +2023,11 @@ load_table_segment_section(const uint8 *buf, const uint8 *buf_end, WASMModule *m if (table_segment_count) { module->table_seg_count = table_segment_count; total_size = sizeof(WASMTableSeg) * (uint64)table_segment_count; - if (total_size >= UINT32_MAX - || !(module->table_segments = wasm_runtime_malloc((uint32)total_size))) { - set_error_buf(error_buf, error_buf_size, - "Load table segment section failed: " - "allocate memory failed."); + if (!(module->table_segments = loader_malloc + (total_size, error_buf, error_buf_size))) { return false; } - memset(module->table_segments, 0, (uint32)total_size); - table_segment = module->table_segments; for (i = 0; i < table_segment_count; i++, table_segment++) { if (p >= p_end) { @@ -2074,12 +2054,8 @@ load_table_segment_section(const uint8 *buf, const uint8 *buf_end, WASMModule *m read_leb_uint32(p, p_end, function_count); table_segment->function_count = function_count; total_size = sizeof(uint32) * (uint64)function_count; - if (total_size >= UINT32_MAX - || !(table_segment->func_indexes = (uint32 *) - wasm_runtime_malloc((uint32)total_size))) { - set_error_buf(error_buf, error_buf_size, - "Load table segment section failed: " - "allocate memory failed."); + if (!(table_segment->func_indexes = (uint32 *) + loader_malloc(total_size, error_buf, error_buf_size))) { return false; } for (j = 0; j < function_count; j++) { @@ -2134,16 +2110,11 @@ load_data_segment_section(const uint8 *buf, const uint8 *buf_end, if (data_seg_count) { module->data_seg_count = data_seg_count; total_size = sizeof(WASMDataSeg*) * (uint64)data_seg_count; - if (total_size >= UINT32_MAX - || !(module->data_segments = wasm_runtime_malloc((uint32)total_size))) { - set_error_buf(error_buf, error_buf_size, - "Load data segment section failed: " - "allocate memory failed."); + if (!(module->data_segments = loader_malloc + (total_size, error_buf, error_buf_size))) { return false; } - memset(module->data_segments, 0, (uint32)total_size); - for (i = 0; i < data_seg_count; i++) { read_leb_uint32(p, p_end, mem_index); #if WASM_ENABLE_BULK_MEMORY != 0 @@ -2157,7 +2128,6 @@ load_data_segment_section(const uint8 *buf, const uint8 *buf_end, /* no memory index, treat index as 0 */ mem_index = 0; goto check_mem_index; - break; case 0x02: /* read following memory index */ read_leb_uint32(p, p_end, mem_index); @@ -2193,11 +2163,8 @@ check_mem_index: read_leb_uint32(p, p_end, data_seg_len); - if (!(dataseg = module->data_segments[i] = - wasm_runtime_malloc((uint32)sizeof(WASMDataSeg)))) { - set_error_buf(error_buf, error_buf_size, - "Load data segment section failed: " - "allocate memory failed."); + if (!(dataseg = module->data_segments[i] = loader_malloc + (sizeof(WASMDataSeg), error_buf, error_buf_size))) { return false; } @@ -2477,18 +2444,19 @@ load_from_sections(WASMModule *module, WASMSection *sections, #endif total_size = sizeof(BlockAddr) * (uint64)BLOCK_ADDR_CACHE_SIZE * BLOCK_ADDR_CONFLICT_SIZE; - if (total_size >= UINT32_MAX - || !(block_addr_cache = wasm_runtime_malloc((uint32)total_size))) { - set_error_buf(error_buf, error_buf_size, - "WASM module load failed: allocate memory failed"); + if (!(block_addr_cache = loader_malloc + (total_size, error_buf, error_buf_size))) { return false; } for (i = 0; i < module->function_count; i++) { WASMFunction *func = module->functions[i]; memset(block_addr_cache, 0, (uint32)total_size); - if (!wasm_loader_prepare_bytecode(module, func, block_addr_cache, error_buf, error_buf_size)) + if (!wasm_loader_prepare_bytecode(module, func, block_addr_cache, + error_buf, error_buf_size)) { + wasm_runtime_free(block_addr_cache); return false; + } } wasm_runtime_free(block_addr_cache); @@ -2616,17 +2584,13 @@ static void wasm_loader_free(void *ptr) static WASMModule* create_module(char *error_buf, uint32 error_buf_size) { - WASMModule *module = wasm_runtime_malloc(sizeof(WASMModule)); + WASMModule *module = loader_malloc(sizeof(WASMModule), + error_buf, error_buf_size); if (!module) { - set_error_buf(error_buf, error_buf_size, - "WASM module load failed: " - "allocate memory failed."); return NULL; } - memset(module, 0, sizeof(WASMModule)); - module->module_type = Wasm_Module_Bytecode; /* Set start_function to -1, means no start function */ @@ -2732,14 +2696,11 @@ create_sections(const uint8 *buf, uint32 size, read_leb_uint32(p, p_end, section_size); CHECK_BUF1(p, p_end, section_size); - if (!(section = wasm_runtime_malloc(sizeof(WASMSection)))) { - set_error_buf(error_buf, error_buf_size, - "WASM module load failed: " - "allocate memory failed."); + if (!(section = loader_malloc(sizeof(WASMSection), + error_buf, error_buf_size))) { return false; } - memset(section, 0, sizeof(WASMSection)); section->section_type = section_type; section->section_body = (uint8*)p; section->section_body_size = section_size; @@ -3416,16 +3377,12 @@ memory_realloc(void *mem_old, uint32 size_old, uint32 size_new, { uint8 *mem_new; bh_assert(size_new > size_old); - if ((mem_new = wasm_runtime_malloc(size_new))) { + if ((mem_new = loader_malloc + (size_new, error_buf, error_buf_size))) { bh_memcpy_s(mem_new, size_new, mem_old, size_old); memset(mem_new + size_old, 0, size_new - size_old); wasm_runtime_free(mem_old); } - else { - set_error_buf(error_buf, error_buf_size, - "WASM loader prepare bytecode failed: " - "allocate memory failed."); - } return mem_new; } @@ -3485,7 +3442,8 @@ check_offset_pop(WASMLoaderContext *ctx, uint32 cells) return true; } -static void free_label_patch_list(BranchBlock *frame_csp) +static void +free_label_patch_list(BranchBlock *frame_csp) { BranchBlockPatch *label_patch = frame_csp->patch_list; BranchBlockPatch *next; @@ -3497,7 +3455,8 @@ static void free_label_patch_list(BranchBlock *frame_csp) frame_csp->patch_list = NULL; } -static void free_all_label_patch_lists(BranchBlock *frame_csp, uint32 csp_num) +static void +free_all_label_patch_lists(BranchBlock *frame_csp, uint32 csp_num) { BranchBlock *tmp_csp = frame_csp; @@ -3525,7 +3484,6 @@ fail: return false; } - static bool check_stack_top_values(uint8 *frame_ref, int32 stack_cell_num, uint8 type, char *error_buf, uint32 error_buf_size) @@ -3580,7 +3538,8 @@ check_stack_pop(WASMLoaderContext *ctx, uint8 type, return true; } -static void wasm_loader_ctx_destroy(WASMLoaderContext *ctx) +static void +wasm_loader_ctx_destroy(WASMLoaderContext *ctx) { if (ctx) { if (ctx->frame_ref_bottom) @@ -4055,11 +4014,9 @@ add_label_patch_to_list(BranchBlock *frame_csp, uint8 patch_type, uint8 *p_code_compiled, char *error_buf, uint32 error_buf_size) { - BranchBlockPatch *patch = wasm_runtime_malloc(sizeof(BranchBlockPatch)); + BranchBlockPatch *patch = loader_malloc + (sizeof(BranchBlockPatch), error_buf, error_buf_size); if (!patch) { - set_error_buf(error_buf, error_buf_size, - "WASM loader prepare bytecode failed: " - "allocate memory failed"); return false; } patch->patch_type = patch_type; @@ -5505,7 +5462,7 @@ re_scan: case WASM_OP_SET_GLOBAL: { - bool is_multable = false; + bool is_mutable = false; read_leb_uint32(p, p_end, global_idx); if (global_idx >= global_count) { set_error_buf(error_buf, error_buf_size, @@ -5514,12 +5471,12 @@ re_scan: goto fail; } - is_multable = + is_mutable = global_idx < module->import_global_count ? module->import_globals[global_idx].u.global.is_mutable : module->globals[global_idx - module->import_global_count] .is_mutable; - if (!is_multable) { + if (!is_mutable) { set_error_buf(error_buf, error_buf_size, "global is immutable"); @@ -5772,8 +5729,6 @@ re_scan: POP2_AND_PUSH(VALUE_TYPE_F64, VALUE_TYPE_I32); break; - break; - case WASM_OP_I32_CLZ: case WASM_OP_I32_CTZ: case WASM_OP_I32_POPCNT: @@ -6092,13 +6047,10 @@ fail_data_cnt_sec_require: func->const_cell_num = loader_ctx->const_cell_num; if (!(func->consts = func_const = - wasm_runtime_malloc(func->const_cell_num * 4))) { - set_error_buf(error_buf, error_buf_size, - "WASM loader prepare bytecode failed: " - "allocate memory failed"); + loader_malloc(func->const_cell_num * 4, + error_buf, error_buf_size))) { goto fail; } - memset(func->consts, 0, func->const_cell_num * 4); func_const_end = func->consts + func->const_cell_num * 4; // reverse the const buf for (int i = loader_ctx->num_const - 1; i >= 0; i--) { diff --git a/core/iwasm/interpreter/wasm_mini_loader.c b/core/iwasm/interpreter/wasm_mini_loader.c new file mode 100644 index 000000000..3ca23f818 --- /dev/null +++ b/core/iwasm/interpreter/wasm_mini_loader.c @@ -0,0 +1,4947 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "wasm_loader.h" +#include "bh_common.h" +#include "bh_log.h" +#include "wasm.h" +#include "wasm_opcode.h" +#include "wasm_runtime.h" +#include "../common/wasm_native.h" + +/* Read a value of given type from the address pointed to by the given + pointer and increase the pointer to the position just after the + value being read. */ +#define TEMPLATE_READ_VALUE(Type, p) \ + (p += sizeof(Type), *(Type *)(p - sizeof(Type))) + +static void +set_error_buf(char *error_buf, uint32 error_buf_size, const char *string) +{ + if (error_buf != NULL) + snprintf(error_buf, error_buf_size, "%s", string); +} + +#define CHECK_BUF(buf, buf_end, length) do { \ + bh_assert(buf + length <= buf_end); \ + } while (0) + +#define CHECK_BUF1(buf, buf_end, length) do { \ + bh_assert(buf + length <= buf_end); \ + } while (0) + +static void +skip_leb(const uint8 **p_buf, const uint8 *buf_end, uint32 maxbits, + char* error_buf, uint32 error_buf_size) +{ + const uint8 *buf = *p_buf; + uint32 offset = 0, bcnt = 0; + uint64 byte; + + while (true) { + bh_assert(bcnt + 1 <= (maxbits + 6) / 7); + CHECK_BUF(buf, buf_end, offset + 1); + byte = buf[offset]; + offset += 1; + bcnt += 1; + if ((byte & 0x80) == 0) { + break; + } + } + + *p_buf += offset; +} + +#define skip_leb_int64(p, p_end) do { \ + skip_leb(&p, p_end, 64, \ + error_buf, error_buf_size); \ + } while (0) + +#define skip_leb_uint32(p, p_end) do { \ + skip_leb(&p, p_end, 32, \ + error_buf, error_buf_size); \ + } while (0) + +#define skip_leb_int32(p, p_end) do { \ + skip_leb(&p, p_end, 32, \ + error_buf, error_buf_size); \ + } while (0) + +static void +read_leb(uint8 **p_buf, const uint8 *buf_end, + uint32 maxbits, bool sign, uint64 *p_result, + char* error_buf, uint32 error_buf_size) +{ + const uint8 *buf = *p_buf; + uint64 result = 0; + uint32 shift = 0; + uint32 offset = 0, bcnt = 0; + uint64 byte; + + while (true) { + bh_assert(bcnt + 1 <= (maxbits + 6) / 7); + CHECK_BUF(buf, buf_end, offset + 1); + byte = buf[offset]; + offset += 1; + result |= ((byte & 0x7f) << shift); + shift += 7; + bcnt += 1; + if ((byte & 0x80) == 0) { + break; + } + } + + if (!sign && maxbits == 32 && shift >= maxbits) { + /* The top bits set represent values > 32 bits */ + bh_assert(!(((uint8)byte) & 0xf0)); + } + else if (sign && maxbits == 32) { + if (shift < maxbits) { + /* Sign extend */ + result = (((int32)result) << (maxbits - shift)) + >> (maxbits - shift); + } + else { + /* The top bits should be a sign-extension of the sign bit */ + bool sign_bit_set = ((uint8)byte) & 0x8; + int top_bits = ((uint8)byte) & 0xf0; + bh_assert(!((sign_bit_set && top_bits != 0x70) + || (!sign_bit_set && top_bits != 0))); + (void)top_bits; + (void)sign_bit_set; + } + } + else if (sign && maxbits == 64) { + if (shift < maxbits) { + /* Sign extend */ + result = (((int64)result) << (maxbits - shift)) + >> (maxbits - shift); + } + else { + /* The top bits should be a sign-extension of the sign bit */ + bool sign_bit_set = ((uint8)byte) & 0x1; + int top_bits = ((uint8)byte) & 0xfe; + + bh_assert(!((sign_bit_set && top_bits != 0x7e) + || (!sign_bit_set && top_bits != 0))); + (void)top_bits; + (void)sign_bit_set; + } + } + + *p_buf += offset; + *p_result = result; +} + +#define read_uint8(p) TEMPLATE_READ_VALUE(uint8, p) +#define read_uint32(p) TEMPLATE_READ_VALUE(uint32, p) +#define read_bool(p) TEMPLATE_READ_VALUE(bool, p) + +#define read_leb_int64(p, p_end, res) do { \ + uint64 res64; \ + read_leb((uint8**)&p, p_end, 64, true, &res64, \ + error_buf, error_buf_size); \ + res = (int64)res64; \ +} while (0) + +#define read_leb_uint32(p, p_end, res) do { \ + uint64 res64; \ + read_leb((uint8**)&p, p_end, 32, false, &res64, \ + error_buf, error_buf_size); \ + res = (uint32)res64; \ +} while (0) + +#define read_leb_int32(p, p_end, res) do { \ + uint64 res64; \ + read_leb((uint8**)&p, p_end, 32, true, &res64, \ + error_buf, error_buf_size); \ + res = (int32)res64; \ +} while (0) + +static void * +loader_malloc(uint64 size, char *error_buf, uint32 error_buf_size) +{ + void *mem; + + if (size >= UINT32_MAX + || !(mem = wasm_runtime_malloc((uint32)size))) { + set_error_buf(error_buf, error_buf_size, + "WASM module load failed: " + "allocate memory failed."); + return NULL; + } + + memset(mem, 0, (uint32)size); + return mem; +} + +static char * +const_str_list_insert(const uint8 *str, uint32 len, WASMModule *module, + char *error_buf, uint32 error_buf_size) +{ + StringNode *node, *node_next; + + /* Search const str list */ + node = module->const_str_list; + while (node) { + node_next = node->next; + if (strlen(node->str) == len + && !memcmp(node->str, str, len)) + break; + node = node_next; + } + + if (node) { + LOG_DEBUG("reuse %s", node->str); + return node->str; + } + + if (!(node = loader_malloc(sizeof(StringNode) + len + 1, + error_buf, error_buf_size))) { + return NULL; + } + + node->str = ((char*)node) + sizeof(StringNode); + bh_memcpy_s(node->str, len + 1, str, len); + node->str[len] = '\0'; + + if (!module->const_str_list) { + /* set as head */ + module->const_str_list = node; + node->next = NULL; + } + else { + /* insert it */ + node->next = module->const_str_list; + module->const_str_list = node; + } + + return node->str; +} + +static bool +load_init_expr(const uint8 **p_buf, const uint8 *buf_end, + InitializerExpression *init_expr, uint8 type, + char *error_buf, uint32 error_buf_size) +{ + const uint8 *p = *p_buf, *p_end = buf_end; + uint8 flag, end_byte, *p_float; + uint32 i; + + CHECK_BUF(p, p_end, 1); + init_expr->init_expr_type = read_uint8(p); + flag = init_expr->init_expr_type; + + switch (flag) { + /* i32.const */ + case INIT_EXPR_TYPE_I32_CONST: + bh_assert(type == VALUE_TYPE_I32); + read_leb_int32(p, p_end, init_expr->u.i32); + break; + /* i64.const */ + case INIT_EXPR_TYPE_I64_CONST: + bh_assert(type == VALUE_TYPE_I64); + read_leb_int64(p, p_end, init_expr->u.i64); + break; + /* f32.const */ + case INIT_EXPR_TYPE_F32_CONST: + bh_assert(type == VALUE_TYPE_F32); + CHECK_BUF(p, p_end, 4); + p_float = (uint8*)&init_expr->u.f32; + for (i = 0; i < sizeof(float32); i++) + *p_float++ = *p++; + break; + /* f64.const */ + case INIT_EXPR_TYPE_F64_CONST: + bh_assert(type == VALUE_TYPE_F64); + CHECK_BUF(p, p_end, 8); + p_float = (uint8*)&init_expr->u.f64; + for (i = 0; i < sizeof(float64); i++) + *p_float++ = *p++; + break; + /* get_global */ + case INIT_EXPR_TYPE_GET_GLOBAL: + read_leb_uint32(p, p_end, init_expr->u.global_index); + break; + default: + bh_assert(0); + break; + } + CHECK_BUF(p, p_end, 1); + end_byte = read_uint8(p); + bh_assert(end_byte == 0x0b); + *p_buf = p; + + (void)end_byte; + return true; +} + +static bool +load_type_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, + char *error_buf, uint32 error_buf_size) +{ + const uint8 *p = buf, *p_end = buf_end, *p_org; + uint32 type_count, param_count, result_count, i, j; + uint64 total_size; + uint8 flag; + WASMType *type; + + read_leb_uint32(p, p_end, type_count); + + if (type_count) { + module->type_count = type_count; + total_size = sizeof(WASMType*) * (uint64)type_count; + if (!(module->types = loader_malloc + (total_size, error_buf, error_buf_size))) { + return false; + } + + for (i = 0; i < type_count; i++) { + CHECK_BUF(p, p_end, 1); + flag = read_uint8(p); + bh_assert(flag == 0x60); + + read_leb_uint32(p, p_end, param_count); + + /* Resolve param count and result count firstly */ + p_org = p; + CHECK_BUF(p, p_end, param_count); + p += param_count; + read_leb_uint32(p, p_end, result_count); + bh_assert(result_count <= 1); + CHECK_BUF(p, p_end, result_count); + p = p_org; + + total_size = offsetof(WASMType, types) + + sizeof(uint8) * (uint64)(param_count + result_count); + if (!(type = module->types[i] = + loader_malloc(total_size, error_buf, error_buf_size))) { + return false; + } + + /* Resolve param types and result types */ + type->param_count = param_count; + type->result_count = result_count; + for (j = 0; j < param_count; j++) { + CHECK_BUF(p, p_end, 1); + type->types[j] = read_uint8(p); + } + read_leb_uint32(p, p_end, result_count); + for (j = 0; j < result_count; j++) { + CHECK_BUF(p, p_end, 1); + type->types[param_count + j] = read_uint8(p); + } + } + } + + bh_assert(p == p_end); + LOG_VERBOSE("Load type section success.\n"); + (void)flag; + return true; +} + +static bool +load_function_import(const WASMModule *parent_module, WASMModule *sub_module, + char *sub_module_name, char *function_name, + const uint8 **p_buf, const uint8 *buf_end, + WASMFunctionImport *function, + char *error_buf, uint32 error_buf_size) +{ + const uint8 *p = *p_buf, *p_end = buf_end; + uint32 declare_type_index = 0; + WASMType *declare_func_type = NULL; + WASMFunction *linked_func = NULL; + const char *linked_signature = NULL; + void *linked_attachment = NULL; + bool linked_call_conv_raw = false; + bool is_built_in_module = false; + + CHECK_BUF(p, p_end, 1); + read_leb_uint32(p, p_end, declare_type_index); + *p_buf = p; + + bh_assert(declare_type_index < parent_module->type_count); + + declare_func_type = parent_module->types[declare_type_index]; + + is_built_in_module = wasm_runtime_is_built_in_module(sub_module_name); + if (is_built_in_module) { + LOG_DEBUG("%s is a function of a built-in module %s", + function_name, + sub_module_name); + /* check built-in modules */ + linked_func = wasm_native_resolve_symbol(sub_module_name, + function_name, + declare_func_type, + &linked_signature, + &linked_attachment, + &linked_call_conv_raw); + } + + if (!linked_func) { +#if WASM_ENABLE_SPEC_TEST != 0 + set_error_buf(error_buf, + error_buf_size, + "unknown import or incompatible import type"); + return false; +#else +#if WASM_ENABLE_WAMR_COMPILER == 0 + LOG_WARNING( + "warning: fail to link import function (%s, %s)", + sub_module_name, function_name); +#endif +#endif + } + + function->module_name = sub_module_name; + function->field_name = function_name; + function->func_type = declare_func_type; + /* func_ptr_linked is for built-in functions */ + function->func_ptr_linked = is_built_in_module ? linked_func : NULL; + function->signature = linked_signature; + function->attachment = linked_attachment; + function->call_conv_raw = linked_call_conv_raw; + return true; +} + +static bool +load_table_import(WASMModule *sub_module, const char *sub_module_name, + const char *table_name, const uint8 **p_buf, + const uint8 *buf_end, WASMTableImport *table, + char *error_buf, uint32 error_buf_size) +{ + const uint8 *p = *p_buf, *p_end = buf_end; + uint32 declare_elem_type = 0; + uint32 declare_max_size_flag = 0; + uint32 declare_init_size = 0; + uint32 declare_max_size = 0; + + CHECK_BUF(p, p_end, 1); + /* 0x70 */ + declare_elem_type = read_uint8(p); + bh_assert(TABLE_ELEM_TYPE_ANY_FUNC == declare_elem_type); + + read_leb_uint32(p, p_end, declare_max_size_flag); + read_leb_uint32(p, p_end, declare_init_size); + if (declare_max_size_flag & 1) { + read_leb_uint32(p, p_end, declare_max_size); + bh_assert(table->init_size <= table->max_size); + } else { + declare_max_size = 0x10000; + } + *p_buf = p; + + bh_assert(!((declare_max_size_flag & 1) + && declare_init_size > declare_max_size)); + + /* now we believe all declaration are ok */ + table->elem_type = declare_elem_type; + table->init_size = declare_init_size; + table->flags = declare_max_size_flag; + table->max_size = declare_max_size; + return true; +} + +unsigned +wasm_runtime_memory_pool_size(); + +static bool +load_memory_import(WASMModule *sub_module, const char *sub_module_name, + const char *memory_name, const uint8 **p_buf, + const uint8 *buf_end, WASMMemoryImport *memory, + char *error_buf, uint32 error_buf_size) +{ + const uint8 *p = *p_buf, *p_end = buf_end; + uint32 pool_size = wasm_runtime_memory_pool_size(); +#if WASM_ENABLE_APP_FRAMEWORK != 0 + uint32 max_page_count = pool_size * APP_MEMORY_MAX_GLOBAL_HEAP_PERCENT + / DEFAULT_NUM_BYTES_PER_PAGE; +#else + uint32 max_page_count = pool_size / DEFAULT_NUM_BYTES_PER_PAGE; +#endif /* WASM_ENABLE_APP_FRAMEWORK */ + uint32 declare_max_page_count_flag = 0; + uint32 declare_init_page_count = 0; + uint32 declare_max_page_count = 0; + + read_leb_uint32(p, p_end, declare_max_page_count_flag); + read_leb_uint32(p, p_end, declare_init_page_count); + bh_assert(declare_init_page_count <= 65536); + + if (declare_max_page_count_flag & 1) { + read_leb_uint32(p, p_end, declare_max_page_count); + bh_assert(declare_init_page_count <= declare_max_page_count); + bh_assert(declare_max_page_count <= 65536); + if (declare_max_page_count > max_page_count) { + declare_max_page_count = max_page_count; + } + } + else { + /* Limit the maximum memory size to max_page_count */ + declare_max_page_count = max_page_count; + } + + /* now we believe all declaration are ok */ + memory->flags = declare_max_page_count_flag; + memory->init_page_count = declare_init_page_count; + memory->max_page_count = declare_max_page_count; + memory->num_bytes_per_page = DEFAULT_NUM_BYTES_PER_PAGE; + + *p_buf = p; + return true; +} + +static bool +load_global_import(const WASMModule *parent_module, + WASMModule *sub_module, + char *sub_module_name, char *global_name, + const uint8 **p_buf, const uint8 *buf_end, + WASMGlobalImport *global, + char *error_buf, uint32 error_buf_size) +{ + const uint8 *p = *p_buf, *p_end = buf_end; + uint8 declare_type = 0; + uint8 declare_mutable = 0; + bool is_mutable = false; + bool ret = false; + + CHECK_BUF(p, p_end, 2); + declare_type = read_uint8(p); + declare_mutable = read_uint8(p); + *p_buf = p; + + bh_assert(declare_mutable < 2); + + is_mutable = declare_mutable & 1 ? true : false; + +#if WASM_ENABLE_LIBC_BUILTIN != 0 + ret = wasm_runtime_is_built_in_module(sub_module_name); + if (ret) { + /* check built-in modules */ + ret = wasm_native_lookup_libc_builtin_global(sub_module_name, + global_name, global); + if (ret) { + LOG_DEBUG("(%s, %s) is a global of a built-in module", + sub_module_name, global_name); + } + } +#endif /* WASM_ENABLE_LIBC_BUILTIN */ + + if (!ret) { + set_error_buf_v(error_buf, error_buf_size, + "unknown import or incompatible import type"); + return false; + } + + global->module_name = sub_module_name; + global->field_name = global_name; + global->type = declare_type; + global->is_mutable = is_mutable; + (void)p_end; + return true; +} + +static bool +load_table(const uint8 **p_buf, const uint8 *buf_end, WASMTable *table, + char *error_buf, uint32 error_buf_size) +{ + const uint8 *p = *p_buf, *p_end = buf_end; + + CHECK_BUF(p, p_end, 1); + /* 0x70 */ + table->elem_type = read_uint8(p); + bh_assert(TABLE_ELEM_TYPE_ANY_FUNC == table->elem_type); + + read_leb_uint32(p, p_end, table->flags); + read_leb_uint32(p, p_end, table->init_size); + if (table->flags & 1) { + read_leb_uint32(p, p_end, table->max_size); + bh_assert(table->init_size <= table->max_size); + } + else + table->max_size = 0x10000; + + bh_assert(!((table->flags & 1) + && table->init_size > table->max_size)); + + *p_buf = p; + return true; +} + +static bool +load_memory(const uint8 **p_buf, const uint8 *buf_end, WASMMemory *memory, + char *error_buf, uint32 error_buf_size) +{ + const uint8 *p = *p_buf, *p_end = buf_end; + uint32 pool_size = wasm_runtime_memory_pool_size(); +#if WASM_ENABLE_APP_FRAMEWORK != 0 + uint32 max_page_count = pool_size * APP_MEMORY_MAX_GLOBAL_HEAP_PERCENT + / DEFAULT_NUM_BYTES_PER_PAGE; +#else + uint32 max_page_count = pool_size / DEFAULT_NUM_BYTES_PER_PAGE; +#endif + + read_leb_uint32(p, p_end, memory->flags); + read_leb_uint32(p, p_end, memory->init_page_count); + bh_assert(memory->init_page_count <= 65536); + + if (memory->flags & 1) { + read_leb_uint32(p, p_end, memory->max_page_count); + bh_assert(memory->init_page_count <= memory->max_page_count); + bh_assert(memory->max_page_count <= 65536); + if (memory->max_page_count > max_page_count) + memory->max_page_count = max_page_count; + } + else + /* Limit the maximum memory size to max_page_count */ + memory->max_page_count = max_page_count; + + memory->num_bytes_per_page = DEFAULT_NUM_BYTES_PER_PAGE; + + *p_buf = p; + return true; +} + +static bool +load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, + char *error_buf, uint32 error_buf_size) +{ + const uint8 *p = buf, *p_end = buf_end, *p_old; + uint32 import_count, name_len, type_index, i, u32, flags; + uint64 total_size; + WASMImport *import; + WASMImport *import_functions = NULL, *import_tables = NULL; + WASMImport *import_memories = NULL, *import_globals = NULL; + char *sub_module_name, *field_name; + uint8 u8, kind; + + read_leb_uint32(p, p_end, import_count); + + if (import_count) { + module->import_count = import_count; + total_size = sizeof(WASMImport) * (uint64)import_count; + if (!(module->imports = loader_malloc + (total_size, error_buf, error_buf_size))) { + return false; + } + + p_old = p; + + /* Scan firstly to get import count of each type */ + for (i = 0; i < import_count; i++) { + /* module name */ + read_leb_uint32(p, p_end, name_len); + CHECK_BUF(p, p_end, name_len); + p += name_len; + + /* field name */ + read_leb_uint32(p, p_end, name_len); + CHECK_BUF(p, p_end, name_len); + p += name_len; + + CHECK_BUF(p, p_end, 1); + /* 0x00/0x01/0x02/0x03 */ + kind = read_uint8(p); + + switch (kind) { + case IMPORT_KIND_FUNC: /* import function */ + read_leb_uint32(p, p_end, type_index); + module->import_function_count++; + break; + + case IMPORT_KIND_TABLE: /* import table */ + CHECK_BUF(p, p_end, 1); + /* 0x70 */ + u8 = read_uint8(p); + read_leb_uint32(p, p_end, flags); + read_leb_uint32(p, p_end, u32); + if (flags & 1) + read_leb_uint32(p, p_end, u32); + module->import_table_count++; + bh_assert(module->import_table_count <= 1); + break; + + case IMPORT_KIND_MEMORY: /* import memory */ + read_leb_uint32(p, p_end, flags); + read_leb_uint32(p, p_end, u32); + if (flags & 1) + read_leb_uint32(p, p_end, u32); + module->import_memory_count++; + bh_assert(module->import_memory_count <= 1); + break; + + case IMPORT_KIND_GLOBAL: /* import global */ + CHECK_BUF(p, p_end, 2); + p += 2; + module->import_global_count++; + break; + + default: + bh_assert(0); + break; + } + } + + if (module->import_function_count) + import_functions = module->import_functions = module->imports; + if (module->import_table_count) + import_tables = module->import_tables = + module->imports + module->import_function_count; + if (module->import_memory_count) + import_memories = module->import_memories = + module->imports + module->import_function_count + module->import_table_count; + if (module->import_global_count) + import_globals = module->import_globals = + module->imports + module->import_function_count + module->import_table_count + + module->import_memory_count; + + p = p_old; + + // TODO: move it out of the loop + /* insert "env", "wasi_unstable" and "wasi_snapshot_preview1" to const str list */ + if (!const_str_list_insert((uint8*)"env", 3, module, error_buf, error_buf_size) + || !const_str_list_insert((uint8*)"wasi_unstable", 13, module, + error_buf, error_buf_size) + || !const_str_list_insert((uint8*)"wasi_snapshot_preview1", 22, module, + error_buf, error_buf_size)) { + return false; + } + + /* Scan again to read the data */ + for (i = 0; i < import_count; i++) { + WASMModule *sub_module = NULL; + + /* load module name */ + read_leb_uint32(p, p_end, name_len); + CHECK_BUF(p, p_end, name_len); + if (!(sub_module_name = const_str_list_insert( + p, name_len, module, error_buf, error_buf_size))) { + return false; + } + p += name_len; + + /* load field name */ + read_leb_uint32(p, p_end, name_len); + CHECK_BUF(p, p_end, name_len); + if (!(field_name = const_str_list_insert( + p, name_len, module, error_buf, error_buf_size))) { + return false; + } + p += name_len; + + LOG_DEBUG("import #%d: (%s, %s)", i, sub_module_name, field_name); + + CHECK_BUF(p, p_end, 1); + /* 0x00/0x01/0x02/0x03 */ + kind = read_uint8(p); + switch (kind) { + case IMPORT_KIND_FUNC: /* import function */ + bh_assert(import_functions); + import = import_functions++; + if (!load_function_import(module, sub_module, + sub_module_name, field_name, &p, + p_end, &import->u.function, + error_buf, error_buf_size)) { + return false; + } + break; + + case IMPORT_KIND_TABLE: /* import table */ + bh_assert(import_tables); + import = import_tables++; + if (!load_table_import(sub_module, + sub_module_name, + field_name, + &p, + p_end, + &import->u.table, + error_buf, + error_buf_size)) { + LOG_DEBUG("can not import such a table (%s,%s)", + sub_module_name, field_name); + return false; + } + break; + + case IMPORT_KIND_MEMORY: /* import memory */ + bh_assert(import_memories); + import = import_memories++; + if (!load_memory_import(sub_module, + sub_module_name, + field_name, + &p, + p_end, + &import->u.memory, + error_buf, + error_buf_size)) { + return false; + } + break; + + case IMPORT_KIND_GLOBAL: /* import global */ + bh_assert(import_globals); + import = import_globals++; + if (!load_global_import(module, + sub_module, + sub_module_name, field_name, &p, + p_end, &import->u.global, + error_buf, error_buf_size)) { + return false; + } + break; + + default: + bh_assert(0); + import = NULL; + break; + } + import->kind = kind; + import->u.names.module_name = sub_module_name; + import->u.names.field_name = field_name; + (void)sub_module; + } + +#if WASM_ENABLE_LIBC_WASI != 0 + import = module->import_functions; + for (i = 0; i < module->import_function_count; i++, import++) { + if (!strcmp(import->u.names.module_name, "wasi_unstable") + || !strcmp(import->u.names.module_name, "wasi_snapshot_preview1")) { + module->is_wasi_module = true; + break; + } + } +#endif + } + + bh_assert(p == p_end); + + LOG_VERBOSE("Load import section success.\n"); + (void)u8; + (void)u32; + (void)type_index; + return true; +} + +static bool +init_function_local_offsets(WASMFunction *func, + char *error_buf, uint32 error_buf_size) +{ + WASMType *param_type = func->func_type; + uint32 param_count = param_type->param_count; + uint8 *param_types = param_type->types; + uint32 local_count = func->local_count; + uint8 *local_types = func->local_types; + uint32 i, local_offset = 0; + uint64 total_size = sizeof(uint16) * ((uint64)param_count + local_count); + + if (!(func->local_offsets = + loader_malloc(total_size, error_buf, error_buf_size))) { + return false; + } + + for (i = 0; i < param_count; i++) { + func->local_offsets[i] = (uint16)local_offset; + local_offset += wasm_value_type_cell_num(param_types[i]); + } + + for (i = 0; i < local_count; i++) { + func->local_offsets[param_count + i] = (uint16)local_offset; + local_offset += wasm_value_type_cell_num(local_types[i]); + } + + bh_assert(local_offset == func->param_cell_num + func->local_cell_num); + return true; +} + +static bool +load_function_section(const uint8 *buf, const uint8 *buf_end, + const uint8 *buf_code, const uint8 *buf_code_end, + WASMModule *module, + char *error_buf, uint32 error_buf_size) +{ + const uint8 *p = buf, *p_end = buf_end; + const uint8 *p_code = buf_code, *p_code_end, *p_code_save; + uint32 func_count; + uint64 total_size; + uint32 code_count = 0, code_size, type_index, i, j, k, local_type_index; + uint32 local_count, local_set_count, sub_local_count; + uint8 type; + WASMFunction *func; + + read_leb_uint32(p, p_end, func_count); + + if (buf_code) + read_leb_uint32(p_code, buf_code_end, code_count); + + bh_assert(func_count == code_count); + + if (func_count) { + module->function_count = func_count; + total_size = sizeof(WASMFunction*) * (uint64)func_count; + if (!(module->functions = + loader_malloc(total_size, error_buf, error_buf_size))) { + return false; + } + + for (i = 0; i < func_count; i++) { + /* Resolve function type */ + read_leb_uint32(p, p_end, type_index); + bh_assert(type_index < module->type_count); + + read_leb_uint32(p_code, buf_code_end, code_size); + bh_assert(code_size > 0 + && p_code + code_size <= buf_code_end); + + /* Resolve local set count */ + p_code_end = p_code + code_size; + local_count = 0; + read_leb_uint32(p_code, buf_code_end, local_set_count); + p_code_save = p_code; + + /* Calculate total local count */ + for (j = 0; j < local_set_count; j++) { + read_leb_uint32(p_code, buf_code_end, sub_local_count); + bh_assert(sub_local_count <= UINT32_MAX - local_count); + + CHECK_BUF(p_code, buf_code_end, 1); + /* 0x7F/0x7E/0x7D/0x7C */ + type = read_uint8(p_code); + local_count += sub_local_count; + } + + /* Alloc memory, layout: function structure + local types */ + code_size = (uint32)(p_code_end - p_code); + + total_size = sizeof(WASMFunction) + (uint64)local_count; + if (!(func = module->functions[i] = + loader_malloc(total_size, error_buf, error_buf_size))) { + return false; + } + + /* Set function type, local count, code size and code body */ + func->func_type = module->types[type_index]; + func->local_count = local_count; + if (local_count > 0) + func->local_types = (uint8*)func + sizeof(WASMFunction); + func->code_size = code_size; + /* + * we shall make a copy of code body [p_code, p_code + code_size] + * when we are worrying about inappropriate releasing behaviour. + * all code bodies are actually in a buffer which user allocates in + * his embedding environment and we don't have power on them. + * it will be like: + * code_body_cp = malloc(code_size); + * memcpy(code_body_cp, p_code, code_size); + * func->code = code_body_cp; + */ + func->code = (uint8*)p_code; + + /* Load each local type */ + p_code = p_code_save; + local_type_index = 0; + for (j = 0; j < local_set_count; j++) { + read_leb_uint32(p_code, buf_code_end, sub_local_count); + bh_assert(!(local_type_index + sub_local_count <= local_type_index + || local_type_index + sub_local_count > local_count)); + + CHECK_BUF(p_code, buf_code_end, 1); + /* 0x7F/0x7E/0x7D/0x7C */ + type = read_uint8(p_code); + bh_assert(type >= VALUE_TYPE_F64 && type <= VALUE_TYPE_I32); + for (k = 0; k < sub_local_count; k++) { + func->local_types[local_type_index++] = type; + } + } + + func->param_cell_num = wasm_type_param_cell_num(func->func_type); + func->ret_cell_num = wasm_type_return_cell_num(func->func_type); + func->local_cell_num = + wasm_get_cell_num(func->local_types, func->local_count); + + if (!init_function_local_offsets(func, error_buf, error_buf_size)) + return false; + + p_code = p_code_end; + } + } + + bh_assert(p == p_end); + LOG_VERBOSE("Load function section success.\n"); + (void)code_count; + return true; +} + +static bool +load_table_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, + char *error_buf, uint32 error_buf_size) +{ + const uint8 *p = buf, *p_end = buf_end; + uint32 table_count, i; + uint64 total_size; + WASMTable *table; + + read_leb_uint32(p, p_end, table_count); + bh_assert(module->import_table_count + table_count <= 1); + + if (table_count) { + module->table_count = table_count; + total_size = sizeof(WASMTable) * (uint64)table_count; + if (!(module->tables = loader_malloc + (total_size, error_buf, error_buf_size))) { + return false; + } + + /* load each table */ + table = module->tables; + for (i = 0; i < table_count; i++, table++) + if (!load_table(&p, p_end, table, error_buf, error_buf_size)) + return false; + } + + bh_assert(p == p_end); + LOG_VERBOSE("Load table section success.\n"); + return true; +} + +static bool +load_memory_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, + char *error_buf, uint32 error_buf_size) +{ + const uint8 *p = buf, *p_end = buf_end; + uint32 memory_count, i; + uint64 total_size; + WASMMemory *memory; + + read_leb_uint32(p, p_end, memory_count); + bh_assert(module->import_memory_count + memory_count <= 1); + + if (memory_count) { + module->memory_count = memory_count; + total_size = sizeof(WASMMemory) * (uint64)memory_count; + if (!(module->memories = loader_malloc + (total_size, error_buf, error_buf_size))) { + return false; + } + + /* load each memory */ + memory = module->memories; + for (i = 0; i < memory_count; i++, memory++) + if (!load_memory(&p, p_end, memory, error_buf, error_buf_size)) + return false; + } + + bh_assert(p == p_end); + LOG_VERBOSE("Load memory section success.\n"); + return true; +} + +static bool +load_global_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, + char *error_buf, uint32 error_buf_size) +{ + const uint8 *p = buf, *p_end = buf_end; + uint32 global_count, i; + uint64 total_size; + WASMGlobal *global; + uint8 mutable; + + read_leb_uint32(p, p_end, global_count); + + if (global_count) { + module->global_count = global_count; + total_size = sizeof(WASMGlobal) * (uint64)global_count; + if (!(module->globals = loader_malloc + (total_size, error_buf, error_buf_size))) { + return false; + } + + global = module->globals; + + for(i = 0; i < global_count; i++, global++) { + CHECK_BUF(p, p_end, 2); + global->type = read_uint8(p); + mutable = read_uint8(p); + bh_assert(mutable < 2); + global->is_mutable = mutable ? true : false; + + /* initialize expression */ + if (!load_init_expr(&p, p_end, &(global->init_expr), + global->type, error_buf, error_buf_size)) + return false; + + if (INIT_EXPR_TYPE_GET_GLOBAL == global->init_expr.init_expr_type) { + /** + * Currently, constant expressions occurring as initializers + * of globals are further constrained in that contained + * global.get instructions are + * only allowed to refer to imported globals. + */ + uint32 target_global_index = global->init_expr.u.global_index; + bh_assert(target_global_index < module->import_global_count); + (void)target_global_index; + } + } + } + + bh_assert(p == p_end); + LOG_VERBOSE("Load global section success.\n"); + return true; +} + +static bool +load_export_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, + char *error_buf, uint32 error_buf_size) +{ + const uint8 *p = buf, *p_end = buf_end; + uint32 export_count, i, j, index; + uint64 total_size; + uint32 str_len; + WASMExport *export; + const char *name; + + read_leb_uint32(p, p_end, export_count); + + if (export_count) { + module->export_count = export_count; + total_size = sizeof(WASMExport) * (uint64)export_count; + if (!(module->exports = loader_malloc + (total_size, error_buf, error_buf_size))) { + return false; + } + + export = module->exports; + for (i = 0; i < export_count; i++, export++) { + read_leb_uint32(p, p_end, str_len); + CHECK_BUF(p, p_end, str_len); + + for (j = 0; j < i; j++) { + name = module->exports[j].name; + bh_assert(!(strlen(name) == str_len + && memcmp(name, p, str_len) == 0)); + } + + if (!(export->name = const_str_list_insert(p, str_len, module, + error_buf, error_buf_size))) { + return false; + } + + p += str_len; + CHECK_BUF(p, p_end, 1); + export->kind = read_uint8(p); + read_leb_uint32(p, p_end, index); + export->index = index; + + switch(export->kind) { + /*function index*/ + case EXPORT_KIND_FUNC: + bh_assert(index < module->function_count + + module->import_function_count); + break; + /*table index*/ + case EXPORT_KIND_TABLE: + bh_assert(index < module->table_count + + module->import_table_count); + break; + /*memory index*/ + case EXPORT_KIND_MEMORY: + bh_assert(index < module->memory_count + + module->import_memory_count); + break; + /*global index*/ + case EXPORT_KIND_GLOBAL: + bh_assert(index < module->global_count + + module->import_global_count); + break; + default: + bh_assert(0); + break; + } + } + } + + bh_assert(p == p_end); + LOG_VERBOSE("Load export section success.\n"); + (void)name; + return true; +} + +static bool +load_table_segment_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, + char *error_buf, uint32 error_buf_size) +{ + const uint8 *p = buf, *p_end = buf_end; + uint32 table_segment_count, i, j, table_index, function_count, function_index; + uint64 total_size; + WASMTableSeg *table_segment; + + read_leb_uint32(p, p_end, table_segment_count); + + if (table_segment_count) { + module->table_seg_count = table_segment_count; + total_size = sizeof(WASMTableSeg) * (uint64)table_segment_count; + if (!(module->table_segments = loader_malloc + (total_size, error_buf, error_buf_size))) { + return false; + } + + table_segment = module->table_segments; + for (i = 0; i < table_segment_count; i++, table_segment++) { + bh_assert(p < p_end); + read_leb_uint32(p, p_end, table_index); + bh_assert(table_index < module->import_table_count + + module->table_count); + + table_segment->table_index = table_index; + + /* initialize expression */ + if (!load_init_expr(&p, p_end, &(table_segment->base_offset), + VALUE_TYPE_I32, error_buf, error_buf_size)) + return false; + + read_leb_uint32(p, p_end, function_count); + table_segment->function_count = function_count; + total_size = sizeof(uint32) * (uint64)function_count; + if (!(table_segment->func_indexes = (uint32 *) + loader_malloc(total_size, error_buf, error_buf_size))) { + return false; + } + + for (j = 0; j < function_count; j++) { + read_leb_uint32(p, p_end, function_index); + bh_assert(function_index < module->function_count + + module->function_count); + table_segment->func_indexes[j] = function_index; + } + } + } + + bh_assert(p == p_end); + LOG_VERBOSE("Load table segment section success.\n"); + return true; +} + +static bool +load_data_segment_section(const uint8 *buf, const uint8 *buf_end, + WASMModule *module, + char *error_buf, uint32 error_buf_size) +{ + const uint8 *p = buf, *p_end = buf_end; + uint32 data_seg_count, i, mem_index, data_seg_len; + uint64 total_size; + WASMDataSeg *dataseg; + InitializerExpression init_expr; +#if WASM_ENABLE_BULK_MEMORY != 0 + bool is_passive = false; + uint32 mem_flag; +#endif + + read_leb_uint32(p, p_end, data_seg_count); + +#if WASM_ENABLE_BULK_MEMORY != 0 + bh_assert(module->data_seg_count1 == 0 + || data_seg_count == module->data_seg_count1); +#endif + + if (data_seg_count) { + module->data_seg_count = data_seg_count; + total_size = sizeof(WASMDataSeg*) * (uint64)data_seg_count; + if (!(module->data_segments = loader_malloc + (total_size, error_buf, error_buf_size))) { + return false; + } + + for (i = 0; i < data_seg_count; i++) { + read_leb_uint32(p, p_end, mem_index); +#if WASM_ENABLE_BULK_MEMORY != 0 + is_passive = false; + mem_flag = mem_index & 0x03; + switch (mem_flag) { + case 0x01: + is_passive = true; + break; + case 0x00: + /* no memory index, treat index as 0 */ + mem_index = 0; + goto check_mem_index; + case 0x02: + /* read following memory index */ + read_leb_uint32(p, p_end, mem_index); +check_mem_index: + bh_assert(mem_index < module->import_memory_count + + module->memory_count); + break; + case 0x03: + default: + bh_assert(0); + break; + } +#else + bh_assert(mem_index < module->import_memory_count + + module->memory_count); +#endif /* WASM_ENABLE_BULK_MEMORY */ + +#if WASM_ENABLE_BULK_MEMORY != 0 + if (!is_passive) +#endif + if (!load_init_expr(&p, p_end, &init_expr, VALUE_TYPE_I32, + error_buf, error_buf_size)) + return false; + + read_leb_uint32(p, p_end, data_seg_len); + + if (!(dataseg = module->data_segments[i] = loader_malloc + (sizeof(WASMDataSeg), error_buf, error_buf_size))) { + return false; + } + +#if WASM_ENABLE_BULK_MEMORY != 0 + dataseg->is_passive = is_passive; + if (!is_passive) +#endif + { + bh_memcpy_s(&dataseg->base_offset, sizeof(InitializerExpression), + &init_expr, sizeof(InitializerExpression)); + + dataseg->memory_index = mem_index; + } + + dataseg->data_length = data_seg_len; + CHECK_BUF(p, p_end, data_seg_len); + dataseg->data = (uint8*)p; + p += data_seg_len; + } + } + + bh_assert(p == p_end); + LOG_VERBOSE("Load data segment section success.\n"); + return true; +} + +#if WASM_ENABLE_BULK_MEMORY != 0 +static bool +load_datacount_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, + char *error_buf, uint32 error_buf_size) +{ + const uint8 *p = buf, *p_end = buf_end; + uint32 data_seg_count1 = 0; + + read_leb_uint32(p, p_end, data_seg_count1); + module->data_seg_count1 = data_seg_count1; + + bh_assert(p == p_end); + LOG_VERBOSE("Load datacount section success.\n"); + return true; +} +#endif + +static bool +load_code_section(const uint8 *buf, const uint8 *buf_end, + const uint8 *buf_func, + const uint8 *buf_func_end, + WASMModule *module, + char *error_buf, uint32 error_buf_size) +{ + const uint8 *p = buf, *p_end = buf_end; + const uint8 *p_func = buf_func; + uint32 func_count = 0, code_count; + + /* code has been loaded in function section, so pass it here, just check + * whether function and code section have inconsistent lengths */ + read_leb_uint32(p, p_end, code_count); + + if (buf_func) + read_leb_uint32(p_func, buf_func_end, func_count); + + bh_assert(func_count == code_count); + LOG_VERBOSE("Load code segment section success.\n"); + (void)code_count; + (void)func_count; + return true; +} + +static bool +load_start_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, + char *error_buf, uint32 error_buf_size) +{ + const uint8 *p = buf, *p_end = buf_end; + WASMType *type; + uint32 start_function; + + read_leb_uint32(p, p_end, start_function); + + bh_assert(start_function < module->function_count + + module->import_function_count); + + if (start_function < module->import_function_count) + type = module->import_functions[start_function].u.function.func_type; + else + type = module->functions[start_function - module->import_function_count] + ->func_type; + + bh_assert(type->param_count == 0 && type->result_count == 0); + + module->start_function = start_function; + + bh_assert(p == p_end); + LOG_VERBOSE("Load start section success.\n"); + (void)type; + return true; +} + +static bool +load_user_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, + char *error_buf, uint32 error_buf_size) +{ + const uint8 *p = buf, *p_end = buf_end; + uint32 name_len; + + bh_assert(p < p_end); + + read_leb_uint32(p, p_end, name_len); + + bh_assert(name_len > 0 + && p + name_len <= p_end); + LOG_VERBOSE("Load custom section success.\n"); + (void)name_len; + return true; +} + + +static bool +wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, + BlockAddr *block_addr_cache, + char *error_buf, uint32 error_buf_size); + +#if WASM_ENABLE_FAST_INTERP != 0 +void ** +wasm_interp_get_handle_table(); + +static void **handle_table; +#endif + +static bool +load_from_sections(WASMModule *module, WASMSection *sections, + char *error_buf, uint32 error_buf_size) +{ + WASMExport *export; + WASMSection *section = sections; + const uint8 *buf, *buf_end, *buf_code = NULL, *buf_code_end = NULL, + *buf_func = NULL, *buf_func_end = NULL; + WASMGlobal *llvm_data_end_global = NULL, *llvm_heap_base_global = NULL; + WASMGlobal *llvm_stack_top_global = NULL, *global; + uint32 llvm_data_end = UINT32_MAX, llvm_heap_base = UINT32_MAX; + uint32 llvm_stack_top = UINT32_MAX, global_index, i; + uint32 data_end_global_index = UINT32_MAX; + uint32 heap_base_global_index = UINT32_MAX; + uint32 stack_top_global_index = UINT32_MAX; + BlockAddr *block_addr_cache; + uint64 total_size; + + /* Find code and function sections if have */ + while (section) { + if (section->section_type == SECTION_TYPE_CODE) { + buf_code = section->section_body; + buf_code_end = buf_code + section->section_body_size; + } + else if (section->section_type == SECTION_TYPE_FUNC) { + buf_func = section->section_body; + buf_func_end = buf_func + section->section_body_size; + } + section = section->next; + } + + section = sections; + while (section) { + buf = section->section_body; + buf_end = buf + section->section_body_size; + LOG_DEBUG("to section %d", section->section_type); + switch (section->section_type) { + case SECTION_TYPE_USER: + /* unsupported user section, ignore it. */ + if (!load_user_section(buf, buf_end, module, error_buf, error_buf_size)) + return false; + break; + case SECTION_TYPE_TYPE: + if (!load_type_section(buf, buf_end, module, error_buf, error_buf_size)) + return false; + break; + case SECTION_TYPE_IMPORT: + if (!load_import_section(buf, buf_end, module, error_buf, error_buf_size)) + return false; + break; + case SECTION_TYPE_FUNC: + if (!load_function_section(buf, buf_end, buf_code, buf_code_end, + module, error_buf, error_buf_size)) + return false; + break; + case SECTION_TYPE_TABLE: + if (!load_table_section(buf, buf_end, module, error_buf, error_buf_size)) + return false; + break; + case SECTION_TYPE_MEMORY: + if (!load_memory_section(buf, buf_end, module, error_buf, error_buf_size)) + return false; + break; + case SECTION_TYPE_GLOBAL: + if (!load_global_section(buf, buf_end, module, error_buf, error_buf_size)) + return false; + break; + case SECTION_TYPE_EXPORT: + if (!load_export_section(buf, buf_end, module, error_buf, error_buf_size)) + return false; + break; + case SECTION_TYPE_START: + if (!load_start_section(buf, buf_end, module, error_buf, error_buf_size)) + return false; + break; + case SECTION_TYPE_ELEM: + if (!load_table_segment_section(buf, buf_end, module, error_buf, error_buf_size)) + return false; + break; + case SECTION_TYPE_CODE: + if (!load_code_section(buf, buf_end, buf_func, buf_func_end, + module, error_buf, error_buf_size)) + return false; + break; + case SECTION_TYPE_DATA: + if (!load_data_segment_section(buf, buf_end, module, error_buf, error_buf_size)) + return false; + break; +#if WASM_ENABLE_BULK_MEMORY != 0 + case SECTION_TYPE_DATACOUNT: + if (!load_datacount_section(buf, buf_end, module, error_buf, error_buf_size)) + return false; + break; +#endif + default: + set_error_buf(error_buf, error_buf_size, + "WASM module load failed: invalid section id"); + return false; + } + + section = section->next; + } + +#if WASM_ENABLE_FAST_INTERP != 0 + handle_table = wasm_interp_get_handle_table(); +#endif + + total_size = sizeof(BlockAddr) * (uint64)BLOCK_ADDR_CACHE_SIZE * BLOCK_ADDR_CONFLICT_SIZE; + if (!(block_addr_cache = loader_malloc + (total_size, error_buf, error_buf_size))) { + return false; + } + + for (i = 0; i < module->function_count; i++) { + WASMFunction *func = module->functions[i]; + memset(block_addr_cache, 0, (uint32)total_size); + if (!wasm_loader_prepare_bytecode(module, func, block_addr_cache, + error_buf, error_buf_size)) { + wasm_runtime_free(block_addr_cache); + return false; + } + } + wasm_runtime_free(block_addr_cache); + + /* Resolve llvm auxiliary data/stack/heap info and reset memory info */ + if (!module->possible_memory_grow) { + export = module->exports; + for (i = 0; i < module->export_count; i++, export++) { + if (export->kind == EXPORT_KIND_GLOBAL) { + if (!strcmp(export->name, "__heap_base")) { + global_index = export->index - module->import_global_count; + global = module->globals + global_index; + if (global->type == VALUE_TYPE_I32 + && !global->is_mutable + && global->init_expr.init_expr_type == + INIT_EXPR_TYPE_I32_CONST) { + heap_base_global_index = global_index; + llvm_heap_base_global = global; + llvm_heap_base = global->init_expr.u.i32; + LOG_VERBOSE("found llvm __heap_base global, value: %d\n", + llvm_heap_base); + } + } + else if (!strcmp(export->name, "__data_end")) { + global_index = export->index - module->import_global_count; + global = module->globals + global_index; + if (global->type == VALUE_TYPE_I32 + && !global->is_mutable + && global->init_expr.init_expr_type == + INIT_EXPR_TYPE_I32_CONST) { + data_end_global_index = global_index; + llvm_data_end_global = global; + llvm_data_end = global->init_expr.u.i32; + LOG_VERBOSE("found llvm __data_end global, value: %d\n", + llvm_data_end); + + llvm_data_end = align_uint(llvm_data_end, 16); + } + } + + if (llvm_data_end_global && llvm_heap_base_global) { + if ((data_end_global_index == heap_base_global_index + 1 + && (int32)data_end_global_index > 1) + || (heap_base_global_index == data_end_global_index + 1 + && (int32)heap_base_global_index > 1)) { + global_index = + data_end_global_index < heap_base_global_index + ? data_end_global_index - 1 : heap_base_global_index - 1; + global = module->globals + global_index; + if (global->type == VALUE_TYPE_I32 + && global->is_mutable + && global->init_expr.init_expr_type == + INIT_EXPR_TYPE_I32_CONST) { + llvm_stack_top_global = global; + llvm_stack_top = global->init_expr.u.i32; + stack_top_global_index = global_index; + LOG_VERBOSE("found llvm stack top global, " + "value: %d, global index: %d\n", + llvm_stack_top, global_index); + } + } + break; + } + } + } + + if (llvm_data_end_global + && llvm_heap_base_global + && llvm_stack_top_global + && llvm_stack_top <= llvm_heap_base) { + WASMMemoryImport *memory_import; + WASMMemory *memory; + uint64 init_memory_size; + uint32 shrunk_memory_size = llvm_heap_base > llvm_data_end + ? llvm_heap_base : llvm_data_end; + if (module->import_memory_count) { + memory_import = &module->import_memories[0].u.memory; + init_memory_size = (uint64)memory_import->num_bytes_per_page * + memory_import->init_page_count; + if (llvm_heap_base <= init_memory_size + && llvm_data_end <= init_memory_size) { + /* Reset memory info to decrease memory usage */ + memory_import->num_bytes_per_page = shrunk_memory_size; + memory_import->init_page_count = 1; + LOG_VERBOSE("reset import memory size to %d\n", + shrunk_memory_size); + } + } + if (module->memory_count) { + memory = &module->memories[0]; + init_memory_size = (uint64)memory->num_bytes_per_page * + memory->init_page_count; + if (llvm_heap_base <= init_memory_size + && llvm_data_end <= init_memory_size) { + /* Reset memory info to decrease memory usage */ + memory->num_bytes_per_page = shrunk_memory_size; + memory->init_page_count = 1; + LOG_VERBOSE("reset memory size to %d\n", shrunk_memory_size); + } + } + + module->llvm_aux_data_end = llvm_data_end; + module->llvm_aux_stack_bottom = llvm_stack_top; + module->llvm_aux_stack_size = llvm_stack_top > llvm_data_end + ? llvm_stack_top - llvm_data_end + : llvm_stack_top; + module->llvm_aux_stack_global_index = stack_top_global_index; + LOG_VERBOSE("aux stack bottom: %d, size: %d\n", + module->llvm_aux_stack_bottom, + module->llvm_aux_stack_size); + } + } + + return true; +} + +#if BH_ENABLE_MEMORY_PROFILING != 0 +static void wasm_loader_free(void *ptr) +{ + wasm_runtime_free(ptr); +} +#else +#define wasm_loader_free wasm_free +#endif + +static WASMModule* +create_module(char *error_buf, uint32 error_buf_size) +{ + WASMModule *module = loader_malloc(sizeof(WASMModule), + error_buf, error_buf_size); + + if (!module) { + return NULL; + } + + module->module_type = Wasm_Module_Bytecode; + + /* Set start_function to -1, means no start function */ + module->start_function = (uint32)-1; + +#if WASM_ENABLE_MULTI_MODULE != 0 + module->import_module_list = &module->import_module_list_head; +#endif + return module; +} + +WASMModule * +wasm_loader_load_from_sections(WASMSection *section_list, + char *error_buf, uint32 error_buf_size) +{ + WASMModule *module = create_module(error_buf, error_buf_size); + if (!module) + return NULL; + + if (!load_from_sections(module, section_list, error_buf, error_buf_size)) { + wasm_loader_unload(module); + return NULL; + } + + LOG_VERBOSE("Load module from sections success.\n"); + return module; +} + +static void +destroy_sections(WASMSection *section_list) +{ + WASMSection *section = section_list, *next; + while (section) { + next = section->next; + wasm_runtime_free(section); + section = next; + } +} + +static uint8 section_ids[] = { + SECTION_TYPE_USER, + SECTION_TYPE_TYPE, + SECTION_TYPE_IMPORT, + SECTION_TYPE_FUNC, + SECTION_TYPE_TABLE, + SECTION_TYPE_MEMORY, + SECTION_TYPE_GLOBAL, + SECTION_TYPE_EXPORT, + SECTION_TYPE_START, + SECTION_TYPE_ELEM, +#if WASM_ENABLE_BULK_MEMORY != 0 + SECTION_TYPE_DATACOUNT, +#endif + SECTION_TYPE_CODE, + SECTION_TYPE_DATA +}; + +static uint8 +get_section_index(uint8 section_type) +{ + uint8 max_id = sizeof(section_ids) / sizeof(uint8); + + for (uint8 i = 0; i < max_id; i++) { + if (section_type == section_ids[i]) + return i; + } + + return (uint8)-1; +} + +static bool +create_sections(const uint8 *buf, uint32 size, + WASMSection **p_section_list, + char *error_buf, uint32 error_buf_size) +{ + WASMSection *section_list_end = NULL, *section; + const uint8 *p = buf, *p_end = buf + size/*, *section_body*/; + uint8 section_type, section_index, last_section_index = (uint8)-1; + uint32 section_size; + + bh_assert(!*p_section_list); + + p += 8; + while (p < p_end) { + CHECK_BUF(p, p_end, 1); + section_type = read_uint8(p); + section_index = get_section_index(section_type); + if (section_index != (uint8)-1) { + if (section_type != SECTION_TYPE_USER) { + /* Custom sections may be inserted at any place, + while other sections must occur at most once + and in prescribed order. */ + bh_assert(last_section_index == (uint8)-1 + || last_section_index < section_index); + last_section_index = section_index; + } + CHECK_BUF1(p, p_end, 1); + read_leb_uint32(p, p_end, section_size); + CHECK_BUF1(p, p_end, section_size); + + if (!(section = loader_malloc(sizeof(WASMSection), + error_buf, error_buf_size))) { + return false; + } + + section->section_type = section_type; + section->section_body = (uint8*)p; + section->section_body_size = section_size; + + if (!*p_section_list) + *p_section_list = section_list_end = section; + else { + section_list_end->next = section; + section_list_end = section; + } + + p += section_size; + } + else { + bh_assert(0); + } + } + + (void)last_section_index; + return true; +} + +static void +exchange32(uint8* p_data) +{ + uint8 value = *p_data; + *p_data = *(p_data + 3); + *(p_data + 3) = value; + + value = *(p_data + 1); + *(p_data + 1) = *(p_data + 2); + *(p_data + 2) = value; +} + +static union { + int a; + char b; +} __ue = { .a = 1 }; + +#define is_little_endian() (__ue.b == 1) + +static bool +load(const uint8 *buf, uint32 size, WASMModule *module, + char *error_buf, uint32 error_buf_size) +{ + const uint8 *buf_end = buf + size; + const uint8 *p = buf, *p_end = buf_end; + uint32 magic_number, version; + WASMSection *section_list = NULL; + + CHECK_BUF1(p, p_end, sizeof(uint32)); + magic_number = read_uint32(p); + if (!is_little_endian()) + exchange32((uint8*)&magic_number); + + bh_assert(magic_number == WASM_MAGIC_NUMBER); + + CHECK_BUF1(p, p_end, sizeof(uint32)); + version = read_uint32(p); + if (!is_little_endian()) + exchange32((uint8*)&version); + + if (version != WASM_CURRENT_VERSION) { + set_error_buf(error_buf, error_buf_size, + "WASM module load failed: unknown binary version"); + return false; + } + + if (!create_sections(buf, size, §ion_list, error_buf, error_buf_size) + || !load_from_sections(module, section_list, error_buf, error_buf_size)) { + destroy_sections(section_list); + return false; + } + + destroy_sections(section_list); + (void)p_end; + return true; +} + +WASMModule* +wasm_loader_load(const uint8 *buf, uint32 size, char *error_buf, uint32 error_buf_size) +{ + WASMModule *module = create_module(error_buf, error_buf_size); + if (!module) { + return NULL; + } + + if (!load(buf, size, module, error_buf, error_buf_size)) { + LOG_VERBOSE("Load module failed, %s", error_buf); + goto fail; + } + + LOG_VERBOSE("Load module success"); + return module; + +fail: + wasm_loader_unload(module); + return NULL; +} + +void +wasm_loader_unload(WASMModule *module) +{ + uint32 i; + + if (!module) + return; + + if (module->types) { + for (i = 0; i < module->type_count; i++) { + if (module->types[i]) + wasm_runtime_free(module->types[i]); + } + wasm_runtime_free(module->types); + } + + if (module->imports) + wasm_runtime_free(module->imports); + + if (module->functions) { + for (i = 0; i < module->function_count; i++) { + if (module->functions[i]) { + if (module->functions[i]->local_offsets) + wasm_runtime_free(module->functions[i]->local_offsets); +#if WASM_ENABLE_FAST_INTERP != 0 + if (module->functions[i]->code_compiled) + wasm_runtime_free(module->functions[i]->code_compiled); + if (module->functions[i]->consts) + wasm_runtime_free(module->functions[i]->consts); +#endif + wasm_runtime_free(module->functions[i]); + } + } + wasm_runtime_free(module->functions); + } + + if (module->tables) + wasm_runtime_free(module->tables); + + if (module->memories) + wasm_runtime_free(module->memories); + + if (module->globals) + wasm_runtime_free(module->globals); + + if (module->exports) + wasm_runtime_free(module->exports); + + if (module->table_segments) { + for (i = 0; i < module->table_seg_count; i++) { + if (module->table_segments[i].func_indexes) + wasm_runtime_free(module->table_segments[i].func_indexes); + } + wasm_runtime_free(module->table_segments); + } + + if (module->data_segments) { + for (i = 0; i < module->data_seg_count; i++) { + if (module->data_segments[i]) + wasm_runtime_free(module->data_segments[i]); + } + wasm_runtime_free(module->data_segments); + } + + if (module->const_str_list) { + StringNode *node = module->const_str_list, *node_next; + while (node) { + node_next = node->next; + wasm_runtime_free(node); + node = node_next; + } + } + + wasm_runtime_free(module); +} + +bool +wasm_loader_find_block_addr(BlockAddr *block_addr_cache, + const uint8 *start_addr, + const uint8 *code_end_addr, + uint8 block_type, + uint8 **p_else_addr, + uint8 **p_end_addr, + char *error_buf, + uint32 error_buf_size) +{ + const uint8 *p = start_addr, *p_end = code_end_addr; + uint8 *else_addr = NULL; + uint32 block_nested_depth = 1, count, i, j, t; + uint8 opcode, u8; + BlockAddr block_stack[16] = { 0 }, *block; + + i = ((uintptr_t)start_addr) % BLOCK_ADDR_CACHE_SIZE; + block = block_addr_cache + BLOCK_ADDR_CONFLICT_SIZE * i; + + for (j = 0; j < BLOCK_ADDR_CONFLICT_SIZE; j++) { + if (block[j].start_addr == start_addr) { + /* Cache hit */ + *p_else_addr = block[j].else_addr; + *p_end_addr = block[j].end_addr; + return true; + } + } + + /* Cache unhit */ + block_stack[0].start_addr = start_addr; + + while (p < code_end_addr) { + opcode = *p++; + + switch (opcode) { + case WASM_OP_UNREACHABLE: + case WASM_OP_NOP: + break; + + case WASM_OP_BLOCK: + case WASM_OP_LOOP: + case WASM_OP_IF: + CHECK_BUF(p, p_end, 1); + /* block result type: 0x40/0x7F/0x7E/0x7D/0x7C */ + u8 = read_uint8(p); + if (block_nested_depth < sizeof(block_stack)/sizeof(BlockAddr)) { + block_stack[block_nested_depth].start_addr = p; + block_stack[block_nested_depth].else_addr = NULL; + } + block_nested_depth++; + break; + + case WASM_OP_ELSE: + if (block_type == BLOCK_TYPE_IF && block_nested_depth == 1) + else_addr = (uint8*)(p - 1); + if (block_nested_depth - 1 < sizeof(block_stack)/sizeof(BlockAddr)) + block_stack[block_nested_depth - 1].else_addr = (uint8*)(p - 1); + break; + + case WASM_OP_END: + if (block_nested_depth == 1) { + if (block_type == BLOCK_TYPE_IF) + *p_else_addr = else_addr; + *p_end_addr = (uint8*)(p - 1); + + block_stack[0].end_addr = (uint8*)(p - 1); + for (t = 0; t < sizeof(block_stack)/sizeof(BlockAddr); t++) { + start_addr = block_stack[t].start_addr; + if (start_addr) { + i = ((uintptr_t)start_addr) % BLOCK_ADDR_CACHE_SIZE; + block = block_addr_cache + BLOCK_ADDR_CONFLICT_SIZE * i; + for (j = 0; j < BLOCK_ADDR_CONFLICT_SIZE; j++) + if (!block[j].start_addr) + break; + + if (j == BLOCK_ADDR_CONFLICT_SIZE) { + memmove(block + 1, block, (BLOCK_ADDR_CONFLICT_SIZE - 1) * + sizeof(BlockAddr)); + j = 0; + + } + block[j].start_addr = block_stack[t].start_addr; + block[j].else_addr = block_stack[t].else_addr; + block[j].end_addr = block_stack[t].end_addr; + } + else + break; + } + return true; + } + else { + block_nested_depth--; + if (block_nested_depth < sizeof(block_stack)/sizeof(BlockAddr)) + block_stack[block_nested_depth].end_addr = (uint8*)(p - 1); + } + break; + + case WASM_OP_BR: + case WASM_OP_BR_IF: + skip_leb_uint32(p, p_end); /* labelidx */ + break; + + case WASM_OP_BR_TABLE: + read_leb_uint32(p, p_end, count); /* lable num */ + for (i = 0; i <= count; i++) /* lableidxs */ + skip_leb_uint32(p, p_end); + break; + + case WASM_OP_RETURN: + break; + + case WASM_OP_CALL: + skip_leb_uint32(p, p_end); /* funcidx */ + break; + + case WASM_OP_CALL_INDIRECT: + skip_leb_uint32(p, p_end); /* typeidx */ + CHECK_BUF(p, p_end, 1); + u8 = read_uint8(p); /* 0x00 */ + break; + + case WASM_OP_DROP: + case WASM_OP_SELECT: + case WASM_OP_DROP_64: + case WASM_OP_SELECT_64: + break; + + case WASM_OP_GET_LOCAL: + case WASM_OP_SET_LOCAL: + case WASM_OP_TEE_LOCAL: + case WASM_OP_GET_GLOBAL: + case WASM_OP_SET_GLOBAL: + skip_leb_uint32(p, p_end); /* localidx */ + break; + + case EXT_OP_GET_LOCAL_FAST: + case EXT_OP_SET_LOCAL_FAST: + case EXT_OP_TEE_LOCAL_FAST: + CHECK_BUF(p, p_end, 1); + p++; + break; + + case WASM_OP_I32_LOAD: + case WASM_OP_I64_LOAD: + case WASM_OP_F32_LOAD: + case WASM_OP_F64_LOAD: + case WASM_OP_I32_LOAD8_S: + case WASM_OP_I32_LOAD8_U: + case WASM_OP_I32_LOAD16_S: + case WASM_OP_I32_LOAD16_U: + case WASM_OP_I64_LOAD8_S: + case WASM_OP_I64_LOAD8_U: + case WASM_OP_I64_LOAD16_S: + case WASM_OP_I64_LOAD16_U: + case WASM_OP_I64_LOAD32_S: + case WASM_OP_I64_LOAD32_U: + case WASM_OP_I32_STORE: + case WASM_OP_I64_STORE: + case WASM_OP_F32_STORE: + case WASM_OP_F64_STORE: + case WASM_OP_I32_STORE8: + case WASM_OP_I32_STORE16: + case WASM_OP_I64_STORE8: + case WASM_OP_I64_STORE16: + case WASM_OP_I64_STORE32: + skip_leb_uint32(p, p_end); /* align */ + skip_leb_uint32(p, p_end); /* offset */ + break; + + case WASM_OP_MEMORY_SIZE: + case WASM_OP_MEMORY_GROW: + skip_leb_uint32(p, p_end); /* 0x00 */ + break; + + case WASM_OP_I32_CONST: + skip_leb_int32(p, p_end); + break; + case WASM_OP_I64_CONST: + skip_leb_int64(p, p_end); + break; + case WASM_OP_F32_CONST: + p += sizeof(float32); + break; + case WASM_OP_F64_CONST: + p += sizeof(float64); + break; + + case WASM_OP_I32_EQZ: + case WASM_OP_I32_EQ: + case WASM_OP_I32_NE: + case WASM_OP_I32_LT_S: + case WASM_OP_I32_LT_U: + case WASM_OP_I32_GT_S: + case WASM_OP_I32_GT_U: + case WASM_OP_I32_LE_S: + case WASM_OP_I32_LE_U: + case WASM_OP_I32_GE_S: + case WASM_OP_I32_GE_U: + case WASM_OP_I64_EQZ: + case WASM_OP_I64_EQ: + case WASM_OP_I64_NE: + case WASM_OP_I64_LT_S: + case WASM_OP_I64_LT_U: + case WASM_OP_I64_GT_S: + case WASM_OP_I64_GT_U: + case WASM_OP_I64_LE_S: + case WASM_OP_I64_LE_U: + case WASM_OP_I64_GE_S: + case WASM_OP_I64_GE_U: + case WASM_OP_F32_EQ: + case WASM_OP_F32_NE: + case WASM_OP_F32_LT: + case WASM_OP_F32_GT: + case WASM_OP_F32_LE: + case WASM_OP_F32_GE: + case WASM_OP_F64_EQ: + case WASM_OP_F64_NE: + case WASM_OP_F64_LT: + case WASM_OP_F64_GT: + case WASM_OP_F64_LE: + case WASM_OP_F64_GE: + case WASM_OP_I32_CLZ: + case WASM_OP_I32_CTZ: + case WASM_OP_I32_POPCNT: + case WASM_OP_I32_ADD: + case WASM_OP_I32_SUB: + case WASM_OP_I32_MUL: + case WASM_OP_I32_DIV_S: + case WASM_OP_I32_DIV_U: + case WASM_OP_I32_REM_S: + case WASM_OP_I32_REM_U: + case WASM_OP_I32_AND: + case WASM_OP_I32_OR: + case WASM_OP_I32_XOR: + case WASM_OP_I32_SHL: + case WASM_OP_I32_SHR_S: + case WASM_OP_I32_SHR_U: + case WASM_OP_I32_ROTL: + case WASM_OP_I32_ROTR: + case WASM_OP_I64_CLZ: + case WASM_OP_I64_CTZ: + case WASM_OP_I64_POPCNT: + case WASM_OP_I64_ADD: + case WASM_OP_I64_SUB: + case WASM_OP_I64_MUL: + case WASM_OP_I64_DIV_S: + case WASM_OP_I64_DIV_U: + case WASM_OP_I64_REM_S: + case WASM_OP_I64_REM_U: + case WASM_OP_I64_AND: + case WASM_OP_I64_OR: + case WASM_OP_I64_XOR: + case WASM_OP_I64_SHL: + case WASM_OP_I64_SHR_S: + case WASM_OP_I64_SHR_U: + case WASM_OP_I64_ROTL: + case WASM_OP_I64_ROTR: + case WASM_OP_F32_ABS: + case WASM_OP_F32_NEG: + case WASM_OP_F32_CEIL: + case WASM_OP_F32_FLOOR: + case WASM_OP_F32_TRUNC: + case WASM_OP_F32_NEAREST: + case WASM_OP_F32_SQRT: + case WASM_OP_F32_ADD: + case WASM_OP_F32_SUB: + case WASM_OP_F32_MUL: + case WASM_OP_F32_DIV: + case WASM_OP_F32_MIN: + case WASM_OP_F32_MAX: + case WASM_OP_F32_COPYSIGN: + case WASM_OP_F64_ABS: + case WASM_OP_F64_NEG: + case WASM_OP_F64_CEIL: + case WASM_OP_F64_FLOOR: + case WASM_OP_F64_TRUNC: + case WASM_OP_F64_NEAREST: + case WASM_OP_F64_SQRT: + case WASM_OP_F64_ADD: + case WASM_OP_F64_SUB: + case WASM_OP_F64_MUL: + case WASM_OP_F64_DIV: + case WASM_OP_F64_MIN: + case WASM_OP_F64_MAX: + case WASM_OP_F64_COPYSIGN: + case WASM_OP_I32_WRAP_I64: + case WASM_OP_I32_TRUNC_S_F32: + case WASM_OP_I32_TRUNC_U_F32: + case WASM_OP_I32_TRUNC_S_F64: + case WASM_OP_I32_TRUNC_U_F64: + case WASM_OP_I64_EXTEND_S_I32: + case WASM_OP_I64_EXTEND_U_I32: + case WASM_OP_I64_TRUNC_S_F32: + case WASM_OP_I64_TRUNC_U_F32: + case WASM_OP_I64_TRUNC_S_F64: + case WASM_OP_I64_TRUNC_U_F64: + case WASM_OP_F32_CONVERT_S_I32: + case WASM_OP_F32_CONVERT_U_I32: + case WASM_OP_F32_CONVERT_S_I64: + case WASM_OP_F32_CONVERT_U_I64: + case WASM_OP_F32_DEMOTE_F64: + case WASM_OP_F64_CONVERT_S_I32: + case WASM_OP_F64_CONVERT_U_I32: + case WASM_OP_F64_CONVERT_S_I64: + case WASM_OP_F64_CONVERT_U_I64: + case WASM_OP_F64_PROMOTE_F32: + case WASM_OP_I32_REINTERPRET_F32: + case WASM_OP_I64_REINTERPRET_F64: + case WASM_OP_F32_REINTERPRET_I32: + case WASM_OP_F64_REINTERPRET_I64: + case WASM_OP_I32_EXTEND8_S: + case WASM_OP_I32_EXTEND16_S: + case WASM_OP_I64_EXTEND8_S: + case WASM_OP_I64_EXTEND16_S: + case WASM_OP_I64_EXTEND32_S: + break; + case WASM_OP_MISC_PREFIX: + { + opcode = read_uint8(p); + switch (opcode) { + case WASM_OP_I32_TRUNC_SAT_S_F32: + case WASM_OP_I32_TRUNC_SAT_U_F32: + case WASM_OP_I32_TRUNC_SAT_S_F64: + case WASM_OP_I32_TRUNC_SAT_U_F64: + case WASM_OP_I64_TRUNC_SAT_S_F32: + case WASM_OP_I64_TRUNC_SAT_U_F32: + case WASM_OP_I64_TRUNC_SAT_S_F64: + case WASM_OP_I64_TRUNC_SAT_U_F64: + break; +#if WASM_ENABLE_BULK_MEMORY != 0 + case WASM_OP_MEMORY_INIT: + skip_leb_uint32(p, p_end); + /* skip memory idx */ + p++; + break; + case WASM_OP_DATA_DROP: + skip_leb_uint32(p, p_end); + break; + case WASM_OP_MEMORY_COPY: + /* skip two memory idx */ + p += 2; + break; + case WASM_OP_MEMORY_FILL: + /* skip memory idx */ + p++; + break; +#endif + default: + bh_assert(0); + break; + } + break; + } + + default: + bh_assert(0); + break; + } + } + + (void)u8; + return false; +} + +#define REF_I32 VALUE_TYPE_I32 +#define REF_F32 VALUE_TYPE_F32 +#define REF_I64_1 VALUE_TYPE_I64 +#define REF_I64_2 VALUE_TYPE_I64 +#define REF_F64_1 VALUE_TYPE_F64 +#define REF_F64_2 VALUE_TYPE_F64 +#define REF_ANY VALUE_TYPE_ANY + +#if WASM_ENABLE_FAST_INTERP != 0 + +#if WASM_DEBUG_PREPROCESSOR != 0 +#define LOG_OP(...) os_printf(__VA_ARGS__) +#else +#define LOG_OP(...) +#endif + +#define PATCH_ELSE 0 +#define PATCH_END 1 +typedef struct BranchBlockPatch { + struct BranchBlockPatch *next; + uint8 patch_type; + uint8 *code_compiled; +} BranchBlockPatch; +#endif + +typedef struct BranchBlock { + uint8 block_type; + uint8 return_type; + uint8 *start_addr; + uint8 *else_addr; + uint8 *end_addr; + uint32 stack_cell_num; +#if WASM_ENABLE_FAST_INTERP != 0 + uint16 dynamic_offset; + uint8 *code_compiled; + BranchBlockPatch *patch_list; +#endif + + /* Indicate the operand stack is in polymorphic state. + * If the opcode is one of unreachable/br/br_table/return, stack is marked + * to polymorphic state until the block's 'end' opcode is processed. + * If stack is in polymorphic state and stack is empty, instruction can + * pop any type of value directly without decreasing stack top pointer + * and stack cell num. */ + bool is_stack_polymorphic; +} BranchBlock; + +typedef struct WASMLoaderContext { + /* frame ref stack */ + uint8 *frame_ref; + uint8 *frame_ref_bottom; + uint8 *frame_ref_boundary; + uint32 frame_ref_size; + uint32 stack_cell_num; + uint32 max_stack_cell_num; + + /* frame csp stack */ + BranchBlock *frame_csp; + BranchBlock *frame_csp_bottom; + BranchBlock *frame_csp_boundary; + uint32 frame_csp_size; + uint32 csp_num; + uint32 max_csp_num; + +#if WASM_ENABLE_FAST_INTERP != 0 + /* frame offset stack */ + int16 *frame_offset; + int16 *frame_offset_bottom; + int16 *frame_offset_boundary; + uint32 frame_offset_size; + int16 dynamic_offset; + int16 start_dynamic_offset; + int16 max_dynamic_offset; + + /* preserved local offset */ + int16 preserved_local_offset; + + /* const buffer */ + uint8 *const_buf; + uint16 num_const; + uint16 const_buf_size; + uint16 const_cell_num; + + /* processed code */ + uint8 *p_code_compiled; + uint8 *p_code_compiled_end; + uint32 code_compiled_size; +#endif +} WASMLoaderContext; + +typedef struct Const { + WASMValue value; + uint16 slot_index; + uint8 value_type; +} Const; + +static void* +memory_realloc(void *mem_old, uint32 size_old, uint32 size_new, + char *error_buf, uint32 error_buf_size) +{ + uint8 *mem_new; + bh_assert(size_new > size_old); + if ((mem_new = loader_malloc + (size_new, error_buf, error_buf_size))) { + bh_memcpy_s(mem_new, size_new, mem_old, size_old); + memset(mem_new + size_old, 0, size_new - size_old); + wasm_runtime_free(mem_old); + } + return mem_new; +} + +#define MEM_REALLOC(mem, size_old, size_new) do { \ + void *mem_new = memory_realloc(mem, size_old, size_new, \ + error_buf, error_buf_size); \ + if (!mem_new) \ + goto fail; \ + mem = mem_new; \ + } while (0) + +#define CHECK_CSP_PUSH() do { \ + if (ctx->frame_csp >= ctx->frame_csp_boundary) { \ + MEM_REALLOC(ctx->frame_csp_bottom, ctx->frame_csp_size, \ + (uint32)(ctx->frame_csp_size \ + + 8 * sizeof(BranchBlock))); \ + ctx->frame_csp_size += (uint32)(8 * sizeof(BranchBlock)); \ + ctx->frame_csp_boundary = ctx->frame_csp_bottom + \ + ctx->frame_csp_size / sizeof(BranchBlock); \ + ctx->frame_csp = ctx->frame_csp_bottom + ctx->csp_num; \ + } \ + } while (0) + +#define CHECK_CSP_POP() do { \ + bh_assert(ctx->csp_num >= 1); \ + } while (0) + +#if WASM_ENABLE_FAST_INTERP != 0 +static bool +check_offset_push(WASMLoaderContext *ctx, + char *error_buf, uint32 error_buf_size) +{ + uint32 cell_num = (ctx->frame_offset - ctx->frame_offset_bottom); + if (ctx->frame_offset >= ctx->frame_offset_boundary) { + MEM_REALLOC(ctx->frame_offset_bottom, ctx->frame_offset_size, + ctx->frame_offset_size + 16); + ctx->frame_offset_size += 16; + ctx->frame_offset_boundary = ctx->frame_offset_bottom + + ctx->frame_offset_size / sizeof(int16); + ctx->frame_offset = ctx->frame_offset_bottom + cell_num; + } + return true; +fail: + return false; +} + +static bool +check_offset_pop(WASMLoaderContext *ctx, uint32 cells) +{ + if (ctx->frame_offset - cells < ctx->frame_offset_bottom) + return false; + return true; +} + +static void +free_label_patch_list(BranchBlock *frame_csp) +{ + BranchBlockPatch *label_patch = frame_csp->patch_list; + BranchBlockPatch *next; + while (label_patch != NULL) { + next = label_patch->next; + wasm_runtime_free(label_patch); + label_patch = next; + } + frame_csp->patch_list = NULL; +} + +static void +free_all_label_patch_lists(BranchBlock *frame_csp, uint32 csp_num) +{ + BranchBlock *tmp_csp = frame_csp; + + for (uint32 i = 0; i < csp_num; i++) { + free_label_patch_list(tmp_csp); + tmp_csp ++; + } +} + +#endif + +static bool +check_stack_push(WASMLoaderContext *ctx, + char *error_buf, uint32 error_buf_size) +{ + if (ctx->frame_ref >= ctx->frame_ref_boundary) { + MEM_REALLOC(ctx->frame_ref_bottom, ctx->frame_ref_size, + ctx->frame_ref_size + 16); + ctx->frame_ref_size += 16; + ctx->frame_ref_boundary = ctx->frame_ref_bottom + ctx->frame_ref_size; + ctx->frame_ref = ctx->frame_ref_bottom + ctx->stack_cell_num; + } + return true; +fail: + return false; +} + + +static bool +check_stack_top_values(uint8 *frame_ref, int32 stack_cell_num, uint8 type, + char *error_buf, uint32 error_buf_size) +{ + bh_assert(!(((type == VALUE_TYPE_I32 || type == VALUE_TYPE_F32) + && stack_cell_num < 1) + || ((type == VALUE_TYPE_I64 || type == VALUE_TYPE_F64) + && stack_cell_num < 2))); + + bh_assert(!((type == VALUE_TYPE_I32 && *(frame_ref - 1) != REF_I32) + || (type == VALUE_TYPE_F32 && *(frame_ref - 1) != REF_F32) + || (type == VALUE_TYPE_I64 + && (*(frame_ref - 2) != REF_I64_1 + || *(frame_ref - 1) != REF_I64_2)) + || (type == VALUE_TYPE_F64 + && (*(frame_ref - 2) != REF_F64_1 + || *(frame_ref - 1) != REF_F64_2)))); + return true; +} + +static bool +check_stack_pop(WASMLoaderContext *ctx, uint8 type, + char *error_buf, uint32 error_buf_size) +{ + int32 block_stack_cell_num = (int32) + (ctx->stack_cell_num - (ctx->frame_csp - 1)->stack_cell_num); + + if (block_stack_cell_num > 0 + && *(ctx->frame_ref - 1) == VALUE_TYPE_ANY) { + /* the stack top is a value of any type, return success */ + return true; + } + + if (!check_stack_top_values(ctx->frame_ref, block_stack_cell_num, + type, error_buf, error_buf_size)) + return false; + + return true; +} + +static void +wasm_loader_ctx_destroy(WASMLoaderContext *ctx) +{ + if (ctx) { + if (ctx->frame_ref_bottom) + wasm_runtime_free(ctx->frame_ref_bottom); + if (ctx->frame_csp_bottom) { +#if WASM_ENABLE_FAST_INTERP != 0 + free_all_label_patch_lists(ctx->frame_csp_bottom, ctx->csp_num); +#endif + wasm_runtime_free(ctx->frame_csp_bottom); + } +#if WASM_ENABLE_FAST_INTERP != 0 + if (ctx->frame_offset_bottom) + wasm_runtime_free(ctx->frame_offset_bottom); + if (ctx->const_buf) + wasm_runtime_free(ctx->const_buf); +#endif + wasm_runtime_free(ctx); + } +} + +static WASMLoaderContext* +wasm_loader_ctx_init(WASMFunction *func) +{ + WASMLoaderContext *loader_ctx = + wasm_runtime_malloc(sizeof(WASMLoaderContext)); + if (!loader_ctx) + return false; + memset(loader_ctx, 0, sizeof(WASMLoaderContext)); + + loader_ctx->frame_ref_size = 32; + if (!(loader_ctx->frame_ref_bottom = loader_ctx->frame_ref = + wasm_runtime_malloc(loader_ctx->frame_ref_size))) + goto fail; + memset(loader_ctx->frame_ref_bottom, 0, loader_ctx->frame_ref_size); + loader_ctx->frame_ref_boundary = loader_ctx->frame_ref_bottom + + loader_ctx->frame_ref_size; + + loader_ctx->frame_csp_size = sizeof(BranchBlock) * 8; + if (!(loader_ctx->frame_csp_bottom = loader_ctx->frame_csp = + wasm_runtime_malloc(loader_ctx->frame_csp_size))) + goto fail; + memset(loader_ctx->frame_csp_bottom, 0, loader_ctx->frame_csp_size); + loader_ctx->frame_csp_boundary = loader_ctx->frame_csp_bottom + 8; + +#if WASM_ENABLE_FAST_INTERP != 0 + loader_ctx->frame_offset_size = sizeof(int16) * 32; + if (!(loader_ctx->frame_offset_bottom = loader_ctx->frame_offset = + wasm_runtime_malloc(loader_ctx->frame_offset_size))) + goto fail; + memset(loader_ctx->frame_offset_bottom, 0, + loader_ctx->frame_offset_size); + loader_ctx->frame_offset_boundary = loader_ctx->frame_offset_bottom + 32; + + loader_ctx->num_const = 0; + loader_ctx->const_buf_size = sizeof(Const) * 8; + if (!(loader_ctx->const_buf = wasm_runtime_malloc(loader_ctx->const_buf_size))) + goto fail; + memset(loader_ctx->const_buf, 0, loader_ctx->const_buf_size); + + loader_ctx->start_dynamic_offset = loader_ctx->dynamic_offset = + loader_ctx->max_dynamic_offset = func->param_cell_num + + func->local_cell_num; +#endif + return loader_ctx; + +fail: + wasm_loader_ctx_destroy(loader_ctx); + return NULL; +} + +static bool +wasm_loader_push_frame_ref(WASMLoaderContext *ctx, uint8 type, + char *error_buf, uint32 error_buf_size) +{ + if (type == VALUE_TYPE_VOID) + return true; + + if (!check_stack_push(ctx, error_buf, error_buf_size)) + return false; + + *ctx->frame_ref++ = type; + ctx->stack_cell_num++; + if (ctx->stack_cell_num > ctx->max_stack_cell_num) + ctx->max_stack_cell_num = ctx->stack_cell_num; + + if (type == VALUE_TYPE_I32 + || type == VALUE_TYPE_F32 + || type == VALUE_TYPE_ANY) + return true; + + if (!check_stack_push(ctx, error_buf, error_buf_size)) + return false; + *ctx->frame_ref++ = type; + ctx->stack_cell_num++; + if (ctx->stack_cell_num > ctx->max_stack_cell_num) + ctx->max_stack_cell_num = ctx->stack_cell_num; + return true; +} + +static bool +wasm_loader_pop_frame_ref(WASMLoaderContext *ctx, uint8 type, + char *error_buf, uint32 error_buf_size) +{ + BranchBlock *cur_block = ctx->frame_csp - 1; + int32 available_stack_cell = (int32) + (ctx->stack_cell_num - cur_block->stack_cell_num); + + /* Directly return success if current block is in stack + * polymorphic state while stack is empty. */ + if (available_stack_cell <= 0 && cur_block->is_stack_polymorphic) + return true; + + if (type == VALUE_TYPE_VOID) + return true; + + if (!check_stack_pop(ctx, type, error_buf, error_buf_size)) + return false; + + ctx->frame_ref--; + ctx->stack_cell_num--; + + if (type == VALUE_TYPE_I32 + || type == VALUE_TYPE_F32 + || *ctx->frame_ref == VALUE_TYPE_ANY) + return true; + + ctx->frame_ref--; + ctx->stack_cell_num--; + return true; +} + +static bool +wasm_loader_push_pop_frame_ref(WASMLoaderContext *ctx, uint8 pop_cnt, + uint8 type_push, uint8 type_pop, + char *error_buf, uint32 error_buf_size) +{ + for (int i = 0; i < pop_cnt; i++) { + if (!wasm_loader_pop_frame_ref(ctx, type_pop, error_buf, error_buf_size)) + return false; + } + if (!wasm_loader_push_frame_ref(ctx, type_push, error_buf, error_buf_size)) + return false; + return true; +} + +static bool +wasm_loader_push_frame_csp(WASMLoaderContext *ctx, uint8 type, + uint8 ret_type, uint8* start_addr, + char *error_buf, uint32 error_buf_size) +{ + CHECK_CSP_PUSH(); + memset(ctx->frame_csp, 0, sizeof(BranchBlock)); + ctx->frame_csp->block_type = type; + ctx->frame_csp->return_type = ret_type; + ctx->frame_csp->start_addr = start_addr; + ctx->frame_csp->stack_cell_num = ctx->stack_cell_num; +#if WASM_ENABLE_FAST_INTERP != 0 + ctx->frame_csp->dynamic_offset = ctx->dynamic_offset; + ctx->frame_csp->patch_list = NULL; +#endif + ctx->frame_csp++; + ctx->csp_num++; + if (ctx->csp_num > ctx->max_csp_num) + ctx->max_csp_num = ctx->csp_num; + return true; +fail: + return false; +} + +static bool +wasm_loader_pop_frame_csp(WASMLoaderContext *ctx, + char *error_buf, uint32 error_buf_size) +{ + CHECK_CSP_POP(); + ctx->frame_csp--; + ctx->csp_num--; + return true; +} + +static bool +wasm_loader_check_br(WASMLoaderContext *ctx, uint32 depth, + char *error_buf, uint32 error_buf_size) +{ + BranchBlock *target_block, *cur_block; + int32 available_stack_cell; + + bh_assert(ctx->csp_num >= depth + 1); + + target_block = ctx->frame_csp - (depth + 1); + cur_block = ctx->frame_csp - 1; + + available_stack_cell = (int32) + (ctx->stack_cell_num - cur_block->stack_cell_num); + + if (available_stack_cell <= 0 && target_block->is_stack_polymorphic) + return true; + + if (target_block->block_type != BLOCK_TYPE_LOOP) { + uint8 type = target_block->return_type; + if (!check_stack_top_values(ctx->frame_ref, available_stack_cell, + type, error_buf, error_buf_size)) + return false; + } + return true; +} + +#if WASM_ENABLE_FAST_INTERP != 0 + +#if WASM_ENABLE_ABS_LABEL_ADDR != 0 + +#define emit_label(opcode) do { \ + wasm_loader_emit_ptr(loader_ctx, handle_table[opcode]); \ + LOG_OP("\nemit_op [%02x]\t", opcode); \ + } while (0) + +#define skip_label() do { \ + wasm_loader_emit_backspace(loader_ctx, sizeof(void *)); \ + LOG_OP("\ndelete last op\n"); \ + } while (0) + +#else + +#define emit_label(opcode) do { \ + int32 offset = (int32)(handle_table[opcode] - handle_table[0]); \ + bh_assert(offset >= INT16_MIN && offset < INT16_MAX); \ + wasm_loader_emit_int16(loader_ctx, offset); \ + LOG_OP("\nemit_op [%02x]\t", opcode); \ + } while (0) + +// drop local.get / const / block / loop / end +#define skip_label() do { \ + wasm_loader_emit_backspace(loader_ctx, sizeof(int16)); \ + LOG_OP("\ndelete last op\n"); \ + } while (0) + +#endif /* WASM_ENABLE_ABS_LABEL_ADDR */ + +#define emit_empty_label_addr_and_frame_ip(type) do { \ + if (!add_label_patch_to_list(loader_ctx->frame_csp - 1, type, \ + loader_ctx->p_code_compiled, \ + error_buf, error_buf_size)) \ + goto fail; \ + /* label address, to be patched */ \ + wasm_loader_emit_ptr(loader_ctx, NULL); \ + } while (0) + +#define emit_br_info(frame_csp) do { \ + if (!wasm_loader_emit_br_info(loader_ctx, frame_csp, \ + error_buf, error_buf_size)) \ + goto fail; \ + } while (0) + +#define LAST_OP_OUTPUT_I32() (last_op >= WASM_OP_I32_EQZ \ + && last_op <= WASM_OP_I32_ROTR) \ + || (last_op == WASM_OP_I32_LOAD \ + || last_op == WASM_OP_F32_LOAD) \ + || (last_op >= WASM_OP_I32_LOAD8_S \ + && last_op <= WASM_OP_I32_LOAD16_U) \ + || (last_op >= WASM_OP_F32_ABS \ + && last_op <= WASM_OP_F32_COPYSIGN) \ + || (last_op >= WASM_OP_I32_WRAP_I64 \ + && last_op <= WASM_OP_I32_TRUNC_U_F64) \ + || (last_op >= WASM_OP_F32_CONVERT_S_I32 \ + && last_op <= WASM_OP_F32_DEMOTE_F64) \ + || (last_op == WASM_OP_I32_REINTERPRET_F32) \ + || (last_op == WASM_OP_F32_REINTERPRET_I32) \ + || (last_op == EXT_OP_COPY_STACK_TOP) + +#define LAST_OP_OUTPUT_I64() (last_op >= WASM_OP_I64_CLZ \ + && last_op <= WASM_OP_I64_ROTR) \ + || (last_op >= WASM_OP_F64_ABS \ + && last_op <= WASM_OP_F64_COPYSIGN) \ + || (last_op == WASM_OP_I64_LOAD \ + || last_op == WASM_OP_F64_LOAD) \ + || (last_op >= WASM_OP_I64_LOAD8_S \ + && last_op <= WASM_OP_I64_LOAD32_U) \ + || (last_op >= WASM_OP_I64_EXTEND_S_I32 \ + && last_op <= WASM_OP_I64_TRUNC_U_F64) \ + || (last_op >= WASM_OP_F64_CONVERT_S_I32 \ + && last_op <= WASM_OP_F64_PROMOTE_F32) \ + || (last_op == WASM_OP_I64_REINTERPRET_F64) \ + || (last_op == WASM_OP_F64_REINTERPRET_I64) \ + || (last_op == EXT_OP_COPY_STACK_TOP_I64) + +#define GET_CONST_OFFSET(type, val) do { \ + if (!(wasm_loader_get_const_offset(loader_ctx, type, \ + &val, &operand_offset, \ + error_buf, error_buf_size))) \ + goto fail; \ + } while (0) + +#define GET_CONST_F32_OFFSET(type, fval) do { \ + if (!(wasm_loader_get_const_offset(loader_ctx, type, \ + &fval, &operand_offset, \ + error_buf, error_buf_size))) \ + goto fail; \ + } while (0) + +#define GET_CONST_F64_OFFSET(type, fval) do { \ + if (!(wasm_loader_get_const_offset(loader_ctx, type, \ + &fval, &operand_offset, \ + error_buf, error_buf_size))) \ + goto fail; \ + } while (0) + +#define emit_operand(ctx, offset) do { \ + wasm_loader_emit_int16(ctx, offset); \ + LOG_OP("%d\t", offset); \ + } while (0) + +#define emit_byte(ctx, byte) do { \ + wasm_loader_emit_uint8(ctx, byte); \ + LOG_OP("%d\t", byte); \ + } while (0) + +#define emit_leb() do { \ + wasm_loader_emit_leb(loader_ctx, p_org, p); \ + } while (0) + +#define emit_const(value) do { \ + GET_CONST_OFFSET(VALUE_TYPE_I32, value); \ + emit_operand(loader_ctx, operand_offset); \ + } while (0) + +static bool +wasm_loader_ctx_reinit(WASMLoaderContext *ctx) +{ + if (!(ctx->p_code_compiled = wasm_runtime_malloc(ctx->code_compiled_size))) + return false; + memset(ctx->p_code_compiled, 0, ctx->code_compiled_size); + ctx->p_code_compiled_end = ctx->p_code_compiled + + ctx->code_compiled_size; + + /* clean up frame ref */ + memset(ctx->frame_ref_bottom, 0, ctx->frame_ref_size); + ctx->frame_ref = ctx->frame_ref_bottom; + ctx->stack_cell_num = 0; + + /* clean up frame csp */ + memset(ctx->frame_csp_bottom, 0, ctx->frame_csp_size); + ctx->frame_csp = ctx->frame_csp_bottom; + ctx->csp_num = 0; + ctx->max_csp_num = 0; + + /* clean up frame offset */ + memset(ctx->frame_offset_bottom, 0, ctx->frame_offset_size); + ctx->frame_offset = ctx->frame_offset_bottom; + ctx->dynamic_offset = ctx->start_dynamic_offset; + + /* init preserved local offsets */ + ctx->preserved_local_offset = ctx->max_dynamic_offset; + + /* const buf is reserved */ + return true; +} + +static void +wasm_loader_emit_int16(WASMLoaderContext *ctx, int16 value) +{ + if (ctx->p_code_compiled) { + *(int16*)(ctx->p_code_compiled) = value; + ctx->p_code_compiled += sizeof(int16); + } + else + ctx->code_compiled_size += sizeof(int16); +} + +static void +wasm_loader_emit_uint8(WASMLoaderContext *ctx, uint8 value) +{ + if (ctx->p_code_compiled) { + *(ctx->p_code_compiled) = value; + ctx->p_code_compiled += sizeof(uint8); + } + else + ctx->code_compiled_size += sizeof(uint8); +} + +static void +wasm_loader_emit_ptr(WASMLoaderContext *ctx, void *value) +{ + if (ctx->p_code_compiled) { + *(uint8**)(ctx->p_code_compiled) = value; + ctx->p_code_compiled += sizeof(void *); + } + else + ctx->code_compiled_size += sizeof(void *); +} + +static void +wasm_loader_emit_backspace(WASMLoaderContext *ctx, uint32 size) +{ + if (ctx->p_code_compiled) { + ctx->p_code_compiled -= size; + } + else + ctx->code_compiled_size -= size; +} + +static void +wasm_loader_emit_leb(WASMLoaderContext *ctx, uint8* start, uint8* end) +{ + if (ctx->p_code_compiled) { + bh_memcpy_s(ctx->p_code_compiled, + ctx->p_code_compiled_end - ctx->p_code_compiled, + start, end - start); + ctx->p_code_compiled += (end - start); + } + else { + ctx->code_compiled_size += (end - start); + } + +} + +static bool +preserve_referenced_local(WASMLoaderContext *loader_ctx, uint8 opcode, + uint32 local_index, uint32 local_type, bool *preserved, + char *error_buf, uint32 error_buf_size) +{ + int16 preserved_offset = (int16)local_index; + *preserved = false; + for (uint32 i = 0; i < loader_ctx->stack_cell_num; i++) { + /* move previous local into dynamic space before a set/tee_local opcode */ + if (loader_ctx->frame_offset_bottom[i] == (int16)local_index) { + if (preserved_offset == (int16)local_index) { + *preserved = true; + skip_label(); + if (local_type == VALUE_TYPE_I32 + || local_type == VALUE_TYPE_F32) { + preserved_offset = loader_ctx->preserved_local_offset; + /* Only increase preserve offset in the second traversal */ + if (loader_ctx->p_code_compiled) + loader_ctx->preserved_local_offset++; + emit_label(EXT_OP_COPY_STACK_TOP); + } + else { + preserved_offset = loader_ctx->preserved_local_offset; + if (loader_ctx->p_code_compiled) + loader_ctx->preserved_local_offset += 2; + emit_label(EXT_OP_COPY_STACK_TOP_I64); + } + emit_operand(loader_ctx, local_index); + emit_operand(loader_ctx, preserved_offset); + emit_label(opcode); + } + loader_ctx->frame_offset_bottom[i] = preserved_offset; + } + } + + return true; + +#if WASM_ENABLE_ABS_LABEL_ADDR == 0 +fail: + return false; +#endif +} + +static bool +add_label_patch_to_list(BranchBlock *frame_csp, + uint8 patch_type, uint8 *p_code_compiled, + char *error_buf, uint32 error_buf_size) +{ + BranchBlockPatch *patch = loader_malloc + (sizeof(BranchBlockPatch), error_buf, error_buf_size); + if (!patch) { + return false; + } + patch->patch_type = patch_type; + patch->code_compiled = p_code_compiled; + if (!frame_csp->patch_list) { + frame_csp->patch_list = patch; + patch->next = NULL; + } + else { + patch->next = frame_csp->patch_list; + frame_csp->patch_list = patch; + } + return true; +} + +static void +apply_label_patch(WASMLoaderContext *ctx, uint8 depth, + uint8 patch_type) +{ + BranchBlock *frame_csp = ctx->frame_csp - depth; + BranchBlockPatch *node = frame_csp->patch_list; + BranchBlockPatch *node_prev = NULL, *node_next; + + if (!ctx->p_code_compiled) + return; + + while (node) { + node_next = node->next; + if (node->patch_type == patch_type) { + *((uint8**)node->code_compiled) = ctx->p_code_compiled; + if (node_prev == NULL) { + frame_csp->patch_list = node_next; + } + else { + node_prev->next = node_next; + } + wasm_runtime_free(node); + } + else { + node_prev = node; + } + node = node_next; + } +} + +static bool +wasm_loader_emit_br_info(WASMLoaderContext *ctx, BranchBlock *frame_csp, + char *error_buf, uint32 error_buf_size) +{ + emit_operand(ctx, frame_csp->dynamic_offset); + if (frame_csp->block_type == BLOCK_TYPE_LOOP || + frame_csp->return_type == VALUE_TYPE_VOID) { + emit_byte(ctx, 0); + emit_operand(ctx, 0); + } + else if (frame_csp->return_type == VALUE_TYPE_I32 + || frame_csp->return_type == VALUE_TYPE_F32) { + emit_byte(ctx, 1); + emit_operand(ctx, *(int16*)(ctx->frame_offset - 1)); + } + else if (frame_csp->return_type == VALUE_TYPE_I64 + || frame_csp->return_type == VALUE_TYPE_F64) { + emit_byte(ctx, 2); + emit_operand(ctx, *(int16*)(ctx->frame_offset - 2)); + } + + if (frame_csp->block_type == BLOCK_TYPE_LOOP) { + wasm_loader_emit_ptr(ctx, frame_csp->code_compiled); + } + else { + if (!add_label_patch_to_list(frame_csp, PATCH_END, + ctx->p_code_compiled, + error_buf, error_buf_size)) + return false; + /* label address, to be patched */ + wasm_loader_emit_ptr(ctx, NULL); + } + return true; +} + +static bool +wasm_loader_push_frame_offset(WASMLoaderContext *ctx, uint8 type, + bool disable_emit, int16 operand_offset, + char *error_buf, uint32 error_buf_size) +{ + if (type == VALUE_TYPE_VOID) + return true; + + // only check memory overflow in first traverse + if (ctx->p_code_compiled == NULL) { + if (!check_offset_push(ctx, error_buf, error_buf_size)) + return false; + } + + if (disable_emit) + *(ctx->frame_offset)++ = operand_offset; + else { + emit_operand(ctx, ctx->dynamic_offset); + *(ctx->frame_offset)++ = ctx->dynamic_offset; + ctx->dynamic_offset++; + if (ctx->dynamic_offset > ctx->max_dynamic_offset) + ctx->max_dynamic_offset = ctx->dynamic_offset; + } + + if (type == VALUE_TYPE_I32 || type == VALUE_TYPE_F32) + return true; + + if (ctx->p_code_compiled == NULL) { + if (!check_offset_push(ctx, error_buf, error_buf_size)) + return false; + } + + ctx->frame_offset++; + if (!disable_emit) { + ctx->dynamic_offset++; + if (ctx->dynamic_offset > ctx->max_dynamic_offset) + ctx->max_dynamic_offset = ctx->dynamic_offset; + } + return true; +} + +/* This function should be in front of wasm_loader_pop_frame_ref + as they both use ctx->stack_cell_num, and ctx->stack_cell_num + will be modified by wasm_loader_pop_frame_ref */ +static bool +wasm_loader_pop_frame_offset(WASMLoaderContext *ctx, uint8 type, + char *error_buf, uint32 error_buf_size) +{ + /* if ctx->frame_csp equals ctx->frame_csp_bottom, + then current block is the function block */ + uint32 depth = ctx->frame_csp > ctx->frame_csp_bottom ? 1 : 0; + BranchBlock *cur_block = ctx->frame_csp - depth; + int32 available_stack_cell = (int32) + (ctx->stack_cell_num - cur_block->stack_cell_num); + + /* Directly return success if current block is in stack + * polymorphic state while stack is empty. */ + if (available_stack_cell <= 0 && cur_block->is_stack_polymorphic) + return true; + + if (type == VALUE_TYPE_VOID) + return true; + + if (type == VALUE_TYPE_I32 || type == VALUE_TYPE_F32) { + /* Check the offset stack bottom to ensure the frame offset + stack will not go underflow. But we don't thrown error + and return true here, because the error msg should be + given in wasm_loader_pop_frame_ref */ + if (!check_offset_pop(ctx, 1)) + return true; + + ctx->frame_offset -= 1; + if ((*(ctx->frame_offset) > ctx->start_dynamic_offset) + && (*(ctx->frame_offset) < ctx->max_dynamic_offset)) + ctx->dynamic_offset -= 1; + } + else { + if (!check_offset_pop(ctx, 2)) + return true; + + ctx->frame_offset -= 2; + if ((*(ctx->frame_offset) > ctx->start_dynamic_offset) + && (*(ctx->frame_offset) < ctx->max_dynamic_offset)) + ctx->dynamic_offset -= 2; + } + emit_operand(ctx, *(ctx->frame_offset)); + return true; +} + +static bool +wasm_loader_push_pop_frame_offset(WASMLoaderContext *ctx, uint8 pop_cnt, + uint8 type_push, uint8 type_pop, + bool disable_emit, int16 operand_offset, + char *error_buf, uint32 error_buf_size) +{ + for (int i = 0; i < pop_cnt; i++) { + if (!wasm_loader_pop_frame_offset(ctx, type_pop, error_buf, error_buf_size)) + return false; + } + if (!wasm_loader_push_frame_offset(ctx, type_push, + disable_emit, operand_offset, + error_buf, error_buf_size)) + return false; + + return true; +} + +static bool +wasm_loader_push_frame_ref_offset(WASMLoaderContext *ctx, uint8 type, + bool disable_emit, int16 operand_offset, + char *error_buf, uint32 error_buf_size) +{ + if (!(wasm_loader_push_frame_offset(ctx, type, disable_emit, operand_offset, + error_buf, error_buf_size))) + return false; + if (!(wasm_loader_push_frame_ref(ctx, type, error_buf, error_buf_size))) + return false; + + return true; +} + +static bool +wasm_loader_pop_frame_ref_offset(WASMLoaderContext *ctx, uint8 type, + char *error_buf, uint32 error_buf_size) +{ + /* put wasm_loader_pop_frame_offset in front of wasm_loader_pop_frame_ref */ + if (!wasm_loader_pop_frame_offset(ctx, type, error_buf, error_buf_size)) + return false; + if (!wasm_loader_pop_frame_ref(ctx, type, error_buf, error_buf_size)) + return false; + + return true; +} + +static bool +wasm_loader_push_pop_frame_ref_offset(WASMLoaderContext *ctx, uint8 pop_cnt, + uint8 type_push, uint8 type_pop, + bool disable_emit, int16 operand_offset, + char *error_buf, uint32 error_buf_size) +{ + if (!wasm_loader_push_pop_frame_offset(ctx, pop_cnt, type_push, type_pop, + disable_emit, operand_offset, + error_buf, error_buf_size)) + return false; + if (!wasm_loader_push_pop_frame_ref(ctx, pop_cnt, type_push, type_pop, + error_buf, error_buf_size)) + return false; + + return true; +} + +static bool +wasm_loader_get_const_offset(WASMLoaderContext *ctx, uint8 type, + void *value, int16 *offset, + char *error_buf, uint32 error_buf_size) +{ + int16 operand_offset = 0; + Const *c; + for (c = (Const *)ctx->const_buf; + (uint8*)c < ctx->const_buf + ctx->num_const * sizeof(Const); c ++) { + if ((type == c->value_type) + && ((type == VALUE_TYPE_I64 && *(int64*)value == c->value.i64) + || (type == VALUE_TYPE_I32 && *(int32*)value == c->value.i32) + || (type == VALUE_TYPE_F64 + && (0 == memcmp(value, &(c->value.f64), sizeof(float64)))) + || (type == VALUE_TYPE_F32 + && (0 == memcmp(value, &(c->value.f32), sizeof(float32)))))) { + operand_offset = c->slot_index; + break; + } + if (c->value_type == VALUE_TYPE_I64 + || c->value_type == VALUE_TYPE_F64) + operand_offset += 2; + else + operand_offset += 1; + } + if ((uint8 *)c == ctx->const_buf + ctx->num_const * sizeof(Const)) { + if ((uint8 *)c == ctx->const_buf + ctx->const_buf_size) { + MEM_REALLOC(ctx->const_buf, + ctx->const_buf_size, + ctx->const_buf_size + 4 * sizeof(Const)); + ctx->const_buf_size += 4 * sizeof(Const); + c = (Const *)(ctx->const_buf + ctx->num_const * sizeof(Const)); + } + c->value_type = type; + switch (type) { + case VALUE_TYPE_F64: + bh_memcpy_s(&(c->value.f64), sizeof(WASMValue), value, sizeof(float64)); + ctx->const_cell_num += 2; + /* The const buf will be reversed, we use the second cell */ + /* of the i64/f64 const so the finnal offset is corrent */ + operand_offset ++; + break; + case VALUE_TYPE_I64: + c->value.i64 = *(int64*)value; + ctx->const_cell_num += 2; + operand_offset ++; + break; + case VALUE_TYPE_F32: + bh_memcpy_s(&(c->value.f32), sizeof(WASMValue), value, sizeof(float32)); + ctx->const_cell_num ++; + break; + case VALUE_TYPE_I32: + c->value.i32 = *(int32*)value; + ctx->const_cell_num ++; + break; + default: + break; + } + c->slot_index = operand_offset; + ctx->num_const ++; + LOG_OP("#### new const [%d]: %ld\n", + ctx->num_const, (int64)c->value.i64); + } + /* use negetive index for const */ + operand_offset = -(operand_offset + 1); + *offset = operand_offset; + return true; +fail: + return false; +} + +/* + PUSH(POP)_XXX = push(pop) frame_ref + push(pop) frame_offset + -- Mostly used for the binary / compare operation + PUSH(POP)_OFFSET_TYPE only push(pop) the frame_offset stack + -- Mostly used in block / control instructions + + The POP will always emit the offset on the top of the frame_offset stack + PUSH can be used in two ways: + 1. directly PUSH: + PUSH_XXX(); + will allocate a dynamic space and emit + 2. silent PUSH: + operand_offset = xxx; disable_emit = true; + PUSH_XXX(); + only push the frame_offset stack, no emit +*/ +#define PUSH_I32() do { \ + if (!wasm_loader_push_frame_ref_offset(loader_ctx, VALUE_TYPE_I32, \ + disable_emit, operand_offset,\ + error_buf, error_buf_size)) \ + goto fail; \ + } while (0) + +#define PUSH_F32() do { \ + if (!wasm_loader_push_frame_ref_offset(loader_ctx, VALUE_TYPE_F32, \ + disable_emit, operand_offset,\ + error_buf, error_buf_size)) \ + goto fail; \ + } while (0) + +#define PUSH_I64() do { \ + if (!wasm_loader_push_frame_ref_offset(loader_ctx, VALUE_TYPE_I64, \ + disable_emit, operand_offset,\ + error_buf, error_buf_size)) \ + goto fail; \ + } while (0) + +#define PUSH_F64() do { \ + if (!wasm_loader_push_frame_ref_offset(loader_ctx, VALUE_TYPE_F64, \ + disable_emit, operand_offset,\ + error_buf, error_buf_size)) \ + goto fail; \ + } while (0) + +#define POP_I32() do { \ + if (!wasm_loader_pop_frame_ref_offset(loader_ctx, VALUE_TYPE_I32, \ + error_buf, error_buf_size)) \ + goto fail; \ + } while (0) + +#define POP_F32() do { \ + if (!wasm_loader_pop_frame_ref_offset(loader_ctx, VALUE_TYPE_F32, \ + error_buf, error_buf_size)) \ + goto fail; \ + } while (0) + +#define POP_I64() do { \ + if (!wasm_loader_pop_frame_ref_offset(loader_ctx, VALUE_TYPE_I64, \ + error_buf, error_buf_size)) \ + goto fail; \ + } while (0) + +#define POP_F64() do { \ + if (!wasm_loader_pop_frame_ref_offset(loader_ctx, VALUE_TYPE_F64, \ + error_buf, error_buf_size)) \ + goto fail; \ + } while (0) + +#define PUSH_OFFSET_TYPE(type) do { \ + if (!(wasm_loader_push_frame_offset(loader_ctx, type, \ + disable_emit, operand_offset, \ + error_buf, error_buf_size))) \ + goto fail; \ + } while (0) + +#define POP_OFFSET_TYPE(type) do { \ + if (!(wasm_loader_pop_frame_offset(loader_ctx, type, \ + error_buf, error_buf_size))) \ + goto fail; \ + } while (0) + +#define POP_AND_PUSH(type_pop, type_push) do { \ + if (!(wasm_loader_push_pop_frame_ref_offset(loader_ctx, 1, \ + type_push, type_pop, \ + disable_emit, operand_offset, \ + error_buf, error_buf_size))) \ + goto fail; \ + } while (0) + +/* type of POPs should be the same */ +#define POP2_AND_PUSH(type_pop, type_push) do { \ + if (!(wasm_loader_push_pop_frame_ref_offset(loader_ctx, 2, \ + type_push, type_pop, \ + disable_emit, operand_offset, \ + error_buf, error_buf_size))) \ + goto fail; \ + } while (0) + +#else /* WASM_ENABLE_FAST_INTERP */ + +#define PUSH_I32() do { \ + if (!(wasm_loader_push_frame_ref(loader_ctx, VALUE_TYPE_I32, \ + error_buf, error_buf_size))) \ + goto fail; \ + } while (0) + +#define PUSH_F32() do { \ + if (!(wasm_loader_push_frame_ref(loader_ctx, VALUE_TYPE_F32, \ + error_buf, error_buf_size))) \ + goto fail; \ + } while (0) + +#define PUSH_I64() do { \ + if (!(wasm_loader_push_frame_ref(loader_ctx, VALUE_TYPE_I64, \ + error_buf, error_buf_size))) \ + goto fail; \ + } while (0) + +#define PUSH_F64() do { \ + if (!(wasm_loader_push_frame_ref(loader_ctx, VALUE_TYPE_F64, \ + error_buf, error_buf_size))) \ + goto fail; \ + } while (0) + +#define POP_I32() do { \ + if (!(wasm_loader_pop_frame_ref(loader_ctx, VALUE_TYPE_I32, \ + error_buf, error_buf_size))) \ + goto fail; \ + } while (0) + +#define POP_F32() do { \ + if (!(wasm_loader_pop_frame_ref(loader_ctx, VALUE_TYPE_F32, \ + error_buf, error_buf_size))) \ + goto fail; \ + } while (0) + +#define POP_I64() do { \ + if (!(wasm_loader_pop_frame_ref(loader_ctx, VALUE_TYPE_I64, \ + error_buf, error_buf_size))) \ + goto fail; \ + } while (0) + +#define POP_F64() do { \ + if (!(wasm_loader_pop_frame_ref(loader_ctx, VALUE_TYPE_F64, \ + error_buf, error_buf_size))) \ + goto fail; \ + } while (0) + +#define POP_AND_PUSH(type_pop, type_push) do { \ + if (!(wasm_loader_push_pop_frame_ref(loader_ctx, 1, \ + type_push, type_pop, \ + error_buf, error_buf_size))) \ + goto fail; \ + } while (0) + +/* type of POPs should be the same */ +#define POP2_AND_PUSH(type_pop, type_push) do { \ + if (!(wasm_loader_push_pop_frame_ref(loader_ctx, 2, \ + type_push, type_pop, \ + error_buf, error_buf_size))) \ + goto fail; \ + } while (0) +#endif /* WASM_ENABLE_FAST_INTERP */ + +#if WASM_ENABLE_FAST_INTERP != 0 + +static bool +reserve_block_ret(WASMLoaderContext *loader_ctx, uint8 opcode, bool disable_emit, + char *error_buf, uint32 error_buf_size) +{ + int16 operand_offset = 0; + uint8 block_depth = 0; + if (opcode == WASM_OP_ELSE) + block_depth = 1; + else + block_depth = 0; + + if ((loader_ctx->frame_csp - block_depth)->return_type != VALUE_TYPE_VOID) { + uint8 return_cells; + if ((loader_ctx->frame_csp - block_depth)->return_type == VALUE_TYPE_I32 + || (loader_ctx->frame_csp - block_depth)->return_type == VALUE_TYPE_F32) + return_cells = 1; + else + return_cells = 2; + if ((loader_ctx->frame_csp - block_depth)->dynamic_offset != + *(loader_ctx->frame_offset - return_cells)) { + + /* insert op_copy before else opcode */ + if (opcode == WASM_OP_ELSE) + skip_label(); + + if (return_cells == 1) + emit_label(EXT_OP_COPY_STACK_TOP); + else + emit_label(EXT_OP_COPY_STACK_TOP_I64); + emit_operand(loader_ctx, *(loader_ctx->frame_offset - return_cells)); + emit_operand(loader_ctx, (loader_ctx->frame_csp - block_depth)->dynamic_offset); + + if (opcode == WASM_OP_ELSE) { + *(loader_ctx->frame_offset - return_cells) = + (loader_ctx->frame_csp - block_depth)->dynamic_offset; + } + else { + loader_ctx->frame_offset -= return_cells; + loader_ctx->dynamic_offset = loader_ctx->frame_csp->dynamic_offset; + PUSH_OFFSET_TYPE((loader_ctx->frame_csp - block_depth)->return_type); + wasm_loader_emit_backspace(loader_ctx, sizeof(int16)); + } + if (opcode == WASM_OP_ELSE) + emit_label(opcode); + } + } + + return true; + +fail: + return false; +} + +#endif /* WASM_ENABLE_FAST_INTERP */ + +#define RESERVE_BLOCK_RET() do { \ + if (!reserve_block_ret(loader_ctx, opcode, disable_emit, \ + error_buf, error_buf_size)) \ + goto fail; \ + } while (0) + +#define PUSH_TYPE(type) do { \ + if (!(wasm_loader_push_frame_ref(loader_ctx, type, \ + error_buf, error_buf_size))) \ + goto fail; \ + } while (0) + +#define POP_TYPE(type) do { \ + if (!(wasm_loader_pop_frame_ref(loader_ctx, type, \ + error_buf, error_buf_size))) \ + goto fail; \ + } while (0) + +#define PUSH_CSP(type, ret_type, _start_addr) do { \ + if (!wasm_loader_push_frame_csp(loader_ctx, type, ret_type, \ + _start_addr, error_buf, \ + error_buf_size)) \ + goto fail; \ + } while (0) + +#define POP_CSP() do { \ + if (!wasm_loader_pop_frame_csp(loader_ctx, \ + error_buf, error_buf_size)) \ + goto fail; \ + } while (0) + +#define GET_LOCAL_INDEX_TYPE_AND_OFFSET() do { \ + read_leb_uint32(p, p_end, local_idx); \ + bh_assert(local_idx < param_count + local_count);\ + local_type = local_idx < param_count \ + ? param_types[local_idx] \ + : local_types[local_idx - param_count]; \ + local_offset = local_offsets[local_idx]; \ + } while (0) + +#define CHECK_BR(depth) do { \ + if (!wasm_loader_check_br(loader_ctx, depth, \ + error_buf, error_buf_size)) \ + goto fail; \ + } while (0) + +#define CHECK_MEMORY() do { \ + bh_assert(module->import_memory_count \ + + module->memory_count > 0); \ + } while (0) + +#define CHECK_BLOCK_TYPE(type) do { \ + bh_assert(type == VALUE_TYPE_I32 \ + || type == VALUE_TYPE_I64 \ + || type == VALUE_TYPE_F32 \ + || type == VALUE_TYPE_F64 \ + || type == VALUE_TYPE_VOID); \ + } while (0) + +static BranchBlock * +check_branch_block(WASMLoaderContext *loader_ctx, + uint8 **p_buf, uint8 *buf_end, + char *error_buf, uint32 error_buf_size) +{ + uint8 *p = *p_buf, *p_end = buf_end; + BranchBlock *frame_csp_tmp; + uint32 depth; + + read_leb_uint32(p, p_end, depth); + CHECK_BR(depth); + frame_csp_tmp = loader_ctx->frame_csp - depth - 1; +#if WASM_ENABLE_FAST_INTERP != 0 + emit_br_info(frame_csp_tmp); +#endif + + *p_buf = p; + return frame_csp_tmp; +fail: + return NULL; +} + +static bool +check_branch_block_ret(WASMLoaderContext *loader_ctx, + BranchBlock *frame_csp_tmp, + char *error_buf, uint32 error_buf_size) +{ +#if WASM_ENABLE_FAST_INTERP != 0 + BranchBlock *cur_block = loader_ctx->frame_csp - 1; + bool disable_emit = true; + int16 operand_offset = 0; +#endif + if (frame_csp_tmp->block_type != BLOCK_TYPE_LOOP) { + uint8 block_return_type = frame_csp_tmp->return_type; +#if WASM_ENABLE_FAST_INTERP != 0 + /* If the stack is in polymorphic state, do fake pop and push on + offset stack to keep the depth of offset stack to be the same + with ref stack */ + if (cur_block->is_stack_polymorphic) { + POP_OFFSET_TYPE(block_return_type); + PUSH_OFFSET_TYPE(block_return_type); + } +#endif + POP_TYPE(block_return_type); + PUSH_TYPE(block_return_type); + } + return true; +fail: + return false; +} + +static bool +check_block_stack(WASMLoaderContext *ctx, BranchBlock *block, + char *error_buf, uint32 error_buf_size) +{ + uint8 type = block->return_type; + int32 available_stack_cell = (int32) + (ctx->stack_cell_num - block->stack_cell_num); + + if (type != VALUE_TYPE_VOID + && available_stack_cell <= 0 + && block->is_stack_polymorphic) { + if (!(wasm_loader_push_frame_ref(ctx, type, error_buf, error_buf_size)) +#if WASM_ENABLE_FAST_INTERP != 0 + || !(wasm_loader_push_frame_offset(ctx, type, true, 0, error_buf, error_buf_size)) +#endif + ) + return false; + return true; + } + + if (type != VALUE_TYPE_VOID + && available_stack_cell == 1 + && *(ctx->frame_ref - 1) == VALUE_TYPE_ANY) { + if (type == VALUE_TYPE_I32 || type == VALUE_TYPE_F32) { + /* If the stack top is a value of any type, change its type to the + * same as block return type and return success */ + *(ctx->frame_ref - 1) = type; + } + else { + if (!(wasm_loader_push_frame_ref(ctx, VALUE_TYPE_I32, + error_buf, error_buf_size)) +#if WASM_ENABLE_FAST_INTERP != 0 + || !(wasm_loader_push_frame_offset(ctx, VALUE_TYPE_I32, + true, 0, + error_buf, error_buf_size)) +#endif + ) + return false; + *(ctx->frame_ref - 1) = *(ctx->frame_ref - 2) = type; + } + return true; + } + + bh_assert(!(((type == VALUE_TYPE_I32 || type == VALUE_TYPE_F32) + && available_stack_cell != 1) + || ((type == VALUE_TYPE_I64 || type == VALUE_TYPE_F64) + && available_stack_cell != 2) + || (type == VALUE_TYPE_VOID + && available_stack_cell > 0))); + + if (!check_stack_top_values(ctx->frame_ref, available_stack_cell, + type, error_buf, error_buf_size)) + return false; + + return true; +} + +/* reset the stack to the state of before entering the last block */ +#if WASM_ENABLE_FAST_INTERP != 0 +#define RESET_STACK() do { \ + loader_ctx->stack_cell_num = \ + (loader_ctx->frame_csp - 1)->stack_cell_num; \ + loader_ctx->frame_ref = \ + loader_ctx->frame_ref_bottom + loader_ctx->stack_cell_num; \ + loader_ctx->frame_offset = \ + loader_ctx->frame_offset_bottom + loader_ctx->stack_cell_num; \ +} while (0) +#else +#define RESET_STACK() do { \ + loader_ctx->stack_cell_num = \ + (loader_ctx->frame_csp - 1)->stack_cell_num; \ + loader_ctx->frame_ref = \ + loader_ctx->frame_ref_bottom + loader_ctx->stack_cell_num; \ +} while (0) +#endif + +/* set current block's stack polymorphic state */ +#define SET_CUR_BLOCK_STACK_POLYMORPHIC_STATE(flag) do { \ + BranchBlock *cur_block = loader_ctx->frame_csp - 1; \ + cur_block->is_stack_polymorphic = flag; \ +} while (0) + +static bool +wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, + BlockAddr *block_addr_cache, + char *error_buf, uint32 error_buf_size) +{ + uint8 *p = func->code, *p_end = func->code + func->code_size, *p_org; + uint32 param_count, local_count, global_count; + uint8 *param_types, ret_type, *local_types, local_type, global_type; + uint16 *local_offsets, local_offset; + uint32 count, i, local_idx, global_idx, u32, align, mem_offset; + int32 i32, i32_const = 0; + int64 i64; + uint8 opcode, u8, block_return_type; + bool return_value = false; + WASMLoaderContext *loader_ctx; + BranchBlock *frame_csp_tmp; +#if WASM_ENABLE_BULK_MEMORY != 0 + uint32 segment_index; +#endif +#if WASM_ENABLE_FAST_INTERP != 0 + uint8 *func_const_end, *func_const; + int16 operand_offset; + uint8 last_op = 0; + bool disable_emit, preserve_local = false; + float32 f32; + float64 f64; + + LOG_OP("\nProcessing func | [%d] params | [%d] locals | [%d] return\n", + func->param_cell_num, + func->local_cell_num, + func->ret_cell_num); +#endif + + global_count = module->import_global_count + module->global_count; + + param_count = func->func_type->param_count; + param_types = func->func_type->types; + ret_type = func->func_type->result_count + ? param_types[param_count] : VALUE_TYPE_VOID; + + local_count = func->local_count; + local_types = func->local_types; + local_offsets = func->local_offsets; + + if (!(loader_ctx = wasm_loader_ctx_init(func))) { + set_error_buf(error_buf, error_buf_size, + "WASM loader prepare bytecode failed: " + "allocate memory failed"); + goto fail; + } + +#if WASM_ENABLE_FAST_INTERP != 0 +re_scan: + if (loader_ctx->code_compiled_size > 0) { + if (!wasm_loader_ctx_reinit(loader_ctx)) { + set_error_buf(error_buf, error_buf_size, + "WASM loader prepare bytecode failed: " + "allocate memory failed"); + goto fail; + } + p = func->code; + func->code_compiled = loader_ctx->p_code_compiled; + } +#endif + + PUSH_CSP(BLOCK_TYPE_FUNCTION, ret_type, p); + + while (p < p_end) { + opcode = *p++; +#if WASM_ENABLE_FAST_INTERP != 0 + p_org = p; + disable_emit = false; + emit_label(opcode); +#endif + + switch (opcode) { + case WASM_OP_UNREACHABLE: + RESET_STACK(); + SET_CUR_BLOCK_STACK_POLYMORPHIC_STATE(true); + break; + + case WASM_OP_NOP: +#if WASM_ENABLE_FAST_INTERP != 0 + skip_label(); +#endif + break; + + case WASM_OP_BLOCK: + /* 0x40/0x7F/0x7E/0x7D/0x7C */ + block_return_type = read_uint8(p); + CHECK_BLOCK_TYPE(block_return_type); + PUSH_CSP(BLOCK_TYPE_BLOCK, block_return_type, p); +#if WASM_ENABLE_FAST_INTERP != 0 + skip_label(); +#endif + break; + + case WASM_OP_LOOP: + /* 0x40/0x7F/0x7E/0x7D/0x7C */ + block_return_type = read_uint8(p); + CHECK_BLOCK_TYPE(block_return_type); + PUSH_CSP(BLOCK_TYPE_LOOP, block_return_type, p); +#if WASM_ENABLE_FAST_INTERP != 0 + skip_label(); + (loader_ctx->frame_csp - 1)->code_compiled = + loader_ctx->p_code_compiled; +#endif + break; + + case WASM_OP_IF: + POP_I32(); + /* 0x40/0x7F/0x7E/0x7D/0x7C */ + block_return_type = read_uint8(p); + CHECK_BLOCK_TYPE(block_return_type); + PUSH_CSP(BLOCK_TYPE_IF, block_return_type, p); +#if WASM_ENABLE_FAST_INTERP != 0 + emit_empty_label_addr_and_frame_ip(PATCH_ELSE); + emit_empty_label_addr_and_frame_ip(PATCH_END); +#endif + break; + + case WASM_OP_ELSE: + bh_assert(loader_ctx->csp_num >= 2 + && (loader_ctx->frame_csp - 1)->block_type + == BLOCK_TYPE_IF); + + /* check whether if branch's stack matches its result type */ + if (!check_block_stack(loader_ctx, loader_ctx->frame_csp - 1, + error_buf, error_buf_size)) + goto fail; + + (loader_ctx->frame_csp - 1)->else_addr = p - 1; + +#if WASM_ENABLE_FAST_INTERP != 0 + /* if the result of if branch is in local or const area, add a copy op */ + RESERVE_BLOCK_RET(); + + emit_empty_label_addr_and_frame_ip(PATCH_END); + apply_label_patch(loader_ctx, 1, PATCH_ELSE); +#endif + RESET_STACK(); + SET_CUR_BLOCK_STACK_POLYMORPHIC_STATE(false); + break; + + case WASM_OP_END: + { + + /* check whether block stack matches its result type */ + if (!check_block_stack(loader_ctx, loader_ctx->frame_csp - 1, + error_buf, error_buf_size)) + goto fail; + + /* if has return value, but no else branch, fail */ + bh_assert(!((loader_ctx->frame_csp - 1)->block_type == BLOCK_TYPE_IF + && (loader_ctx->frame_csp - 1)->return_type != VALUE_TYPE_VOID + && !(loader_ctx->frame_csp - 1)->else_addr)); + + POP_CSP(); + +#if WASM_ENABLE_FAST_INTERP != 0 + skip_label(); + /* copy the result to the block return address */ + RESERVE_BLOCK_RET(); + + apply_label_patch(loader_ctx, 0, PATCH_END); + free_label_patch_list(loader_ctx->frame_csp); + if (loader_ctx->frame_csp->block_type == BLOCK_TYPE_FUNCTION) { + emit_label(WASM_OP_RETURN); + POP_OFFSET_TYPE(loader_ctx->frame_csp->return_type); + } +#endif + if (loader_ctx->csp_num > 0) { + loader_ctx->frame_csp->end_addr = p - 1; + } + else { + /* end of function block, function will return, + ignore the following bytecodes */ + p = p_end; + + continue; + } + + SET_CUR_BLOCK_STACK_POLYMORPHIC_STATE(false); + break; + } + + case WASM_OP_BR: + { + if (!(frame_csp_tmp = check_branch_block(loader_ctx, &p, p_end, + error_buf, error_buf_size))) + goto fail; + + if (!check_branch_block_ret(loader_ctx, frame_csp_tmp, + error_buf, error_buf_size)) + goto fail; + + RESET_STACK(); + SET_CUR_BLOCK_STACK_POLYMORPHIC_STATE(true); + break; + } + + case WASM_OP_BR_IF: + { + POP_I32(); + + if (!(frame_csp_tmp = check_branch_block(loader_ctx, &p, p_end, + error_buf, error_buf_size))) + goto fail; + + if (!check_branch_block_ret(loader_ctx, frame_csp_tmp, + error_buf, error_buf_size)) + goto fail; + + break; + } + + case WASM_OP_BR_TABLE: + { + uint8 ret_type; + + read_leb_uint32(p, p_end, count); +#if WASM_ENABLE_FAST_INTERP != 0 + emit_const(count); +#endif + POP_I32(); + + /* TODO: check the const */ + for (i = 0; i <= count; i++) { + if (!(frame_csp_tmp = check_branch_block(loader_ctx, &p, p_end, + error_buf, error_buf_size))) + goto fail; + + if (!check_branch_block_ret(loader_ctx, frame_csp_tmp, + error_buf, error_buf_size)) + goto fail; + + if (i == 0) { + ret_type = frame_csp_tmp->block_type == BLOCK_TYPE_LOOP ? + VALUE_TYPE_VOID : frame_csp_tmp->return_type; + } + else { + /* Check whether all table items have the same return type */ + uint8 tmp_ret_type = frame_csp_tmp->block_type == BLOCK_TYPE_LOOP ? + VALUE_TYPE_VOID : frame_csp_tmp->return_type; + bh_assert(ret_type == tmp_ret_type); + (void)tmp_ret_type; + } + } + + RESET_STACK(); + SET_CUR_BLOCK_STACK_POLYMORPHIC_STATE(true); + (void)ret_type; + break; + } + + case WASM_OP_RETURN: + { + POP_TYPE(ret_type); + PUSH_TYPE(ret_type); + +#if WASM_ENABLE_FAST_INTERP != 0 + // emit the offset after return opcode + POP_OFFSET_TYPE(ret_type); +#endif + + RESET_STACK(); + SET_CUR_BLOCK_STACK_POLYMORPHIC_STATE(true); + break; + } + + case WASM_OP_CALL: + { + WASMType *func_type; + uint32 func_idx; + int32 idx; + + read_leb_uint32(p, p_end, func_idx); +#if WASM_ENABLE_FAST_INTERP != 0 + // we need to emit func_idx before arguments + emit_const(func_idx); +#endif + + bh_assert(func_idx < module->import_function_count + + module->function_count); + + if (func_idx < module->import_function_count) + func_type = module->import_functions[func_idx].u.function.func_type; + else + func_type = + module->functions[func_idx - module->import_function_count]->func_type; + + if (func_type->param_count > 0) { + for (idx = (int32)(func_type->param_count - 1); idx >= 0; idx--) { + POP_TYPE(func_type->types[idx]); +#if WASM_ENABLE_FAST_INTERP != 0 + POP_OFFSET_TYPE(func_type->types[idx]); +#endif + } + } + + if (func_type->result_count) { + PUSH_TYPE(func_type->types[func_type->param_count]); +#if WASM_ENABLE_FAST_INTERP != 0 + PUSH_OFFSET_TYPE(func_type->types[func_type->param_count]); +#endif + } + + func->has_op_func_call = true; + break; + } + + case WASM_OP_CALL_INDIRECT: + { + int32 idx; + WASMType *func_type; + uint32 type_idx; + + bh_assert(module->import_table_count + + module->table_count > 0); + + read_leb_uint32(p, p_end, type_idx); +#if WASM_ENABLE_FAST_INTERP != 0 + // we need to emit func_idx before arguments + emit_const(type_idx); +#endif + + /* reserved byte 0x00 */ + bh_assert(*p == 0x00); + p++; + + POP_I32(); + + bh_assert(type_idx < module->type_count); + + func_type = module->types[type_idx]; + + if (func_type->param_count > 0) { + for (idx = (int32)(func_type->param_count - 1); idx >= 0; idx--) { + POP_TYPE(func_type->types[idx]); +#if WASM_ENABLE_FAST_INTERP != 0 + POP_OFFSET_TYPE(func_type->types[idx]); +#endif + } + } + + if (func_type->result_count > 0) { + PUSH_TYPE(func_type->types[func_type->param_count]); +#if WASM_ENABLE_FAST_INTERP != 0 + PUSH_OFFSET_TYPE(func_type->types[func_type->param_count]); +#endif + } + + func->has_op_func_call = true; + break; + } + + case WASM_OP_DROP: + case WASM_OP_DROP_64: + { + BranchBlock *cur_block = loader_ctx->frame_csp - 1; + int32 available_stack_cell = (int32) + (loader_ctx->stack_cell_num - cur_block->stack_cell_num); + + bh_assert(!(available_stack_cell <= 0 + && !cur_block->is_stack_polymorphic)); + + if (available_stack_cell > 0) { + if (*(loader_ctx->frame_ref - 1) == REF_I32 + || *(loader_ctx->frame_ref - 1) == REF_F32) { + loader_ctx->frame_ref--; + loader_ctx->stack_cell_num--; +#if WASM_ENABLE_FAST_INTERP != 0 + skip_label(); + loader_ctx->frame_offset--; + if (*(loader_ctx->frame_offset) > + loader_ctx->start_dynamic_offset) + loader_ctx->dynamic_offset --; +#endif + } + else { + loader_ctx->frame_ref -= 2; + loader_ctx->stack_cell_num -= 2; +#if (WASM_ENABLE_FAST_INTERP == 0) || (WASM_ENABLE_JIT != 0) + *(p - 1) = WASM_OP_DROP_64; +#endif +#if WASM_ENABLE_FAST_INTERP != 0 + skip_label(); + loader_ctx->frame_offset -= 2; + if (*(loader_ctx->frame_offset) > + loader_ctx->start_dynamic_offset) + loader_ctx->dynamic_offset -= 2; +#endif + } + } + else { +#if WASM_ENABLE_FAST_INTERP != 0 + skip_label(); +#endif + } + break; + } + + case WASM_OP_SELECT: + case WASM_OP_SELECT_64: + { + uint8 ref_type; + BranchBlock *cur_block = loader_ctx->frame_csp - 1; + int32 available_stack_cell; + + POP_I32(); + + available_stack_cell = (int32) + (loader_ctx->stack_cell_num - cur_block->stack_cell_num); + + bh_assert(!(available_stack_cell <= 0 + && !cur_block->is_stack_polymorphic)); + + if (available_stack_cell > 0) { + switch (*(loader_ctx->frame_ref - 1)) { + case REF_I32: + case REF_F32: + break; + case REF_I64_2: + case REF_F64_2: +#if (WASM_ENABLE_FAST_INTERP == 0) || (WASM_ENABLE_JIT != 0) + *(p - 1) = WASM_OP_SELECT_64; +#endif +#if WASM_ENABLE_FAST_INTERP != 0 + if (loader_ctx->p_code_compiled) { +#if WASM_ENABLE_ABS_LABEL_ADDR != 0 + *(void**)(loader_ctx->p_code_compiled - 2 - sizeof(void*)) = + handle_table[WASM_OP_SELECT_64]; +#else + *((int16*)loader_ctx->p_code_compiled - 2) = (int16) + (handle_table[WASM_OP_SELECT_64] - handle_table[0]); +#endif + } +#endif + break; + } + + ref_type = *(loader_ctx->frame_ref - 1); +#if WASM_ENABLE_FAST_INTERP != 0 + POP_OFFSET_TYPE(ref_type); +#endif + POP_TYPE(ref_type); +#if WASM_ENABLE_FAST_INTERP != 0 + POP_OFFSET_TYPE(ref_type); +#endif + POP_TYPE(ref_type); +#if WASM_ENABLE_FAST_INTERP != 0 + PUSH_OFFSET_TYPE(ref_type); +#endif + PUSH_TYPE(ref_type); + } + else { +#if WASM_ENABLE_FAST_INTERP != 0 + PUSH_OFFSET_TYPE(VALUE_TYPE_ANY); +#endif + PUSH_TYPE(VALUE_TYPE_ANY); + } + break; + } + + case WASM_OP_GET_LOCAL: + { + p_org = p - 1; + GET_LOCAL_INDEX_TYPE_AND_OFFSET(); + PUSH_TYPE(local_type); + +#if WASM_ENABLE_FAST_INTERP != 0 + /* Get Local is optimized out */ + skip_label(); + disable_emit = true; + operand_offset = local_offset; + PUSH_OFFSET_TYPE(local_type); +#else +#if (WASM_ENABLE_WAMR_COMPILER == 0) && (WASM_ENABLE_JIT == 0) + if (local_offset < 0x80) { + *p_org++ = EXT_OP_GET_LOCAL_FAST; + if (local_type == VALUE_TYPE_I32 + || local_type == VALUE_TYPE_F32) + *p_org++ = (uint8)local_offset; + else + *p_org++ = (uint8)(local_offset | 0x80); + while (p_org < p) + *p_org++ = WASM_OP_NOP; + } +#endif +#endif + break; + } + + case WASM_OP_SET_LOCAL: + { + p_org = p - 1; + GET_LOCAL_INDEX_TYPE_AND_OFFSET(); + POP_TYPE(local_type); + +#if WASM_ENABLE_FAST_INTERP != 0 + if (!(preserve_referenced_local(loader_ctx, opcode, local_offset, + local_type, &preserve_local, + error_buf, error_buf_size))) + goto fail; + + if (local_offset < 256) { + skip_label(); + if ((!preserve_local) && (LAST_OP_OUTPUT_I32())) { + if (loader_ctx->p_code_compiled) + *(int16*)(loader_ctx->p_code_compiled - 2) = local_offset; + loader_ctx->frame_offset --; + loader_ctx->dynamic_offset --; + } + else if ((!preserve_local) && (LAST_OP_OUTPUT_I64())) { + if (loader_ctx->p_code_compiled) + *(int16*)(loader_ctx->p_code_compiled - 2) = local_offset; + loader_ctx->frame_offset -= 2; + loader_ctx->dynamic_offset -= 2; + } + else { + if (local_type == VALUE_TYPE_I32 + || local_type == VALUE_TYPE_F32) { + emit_label(EXT_OP_SET_LOCAL_FAST); + emit_byte(loader_ctx, local_offset); + } + else { + emit_label(EXT_OP_SET_LOCAL_FAST_I64); + emit_byte(loader_ctx, local_offset); + } + POP_OFFSET_TYPE(local_type); + } + } + else { /* local index larger than 255, reserve leb */ + p_org ++; + emit_leb(); + POP_OFFSET_TYPE(local_type); + } +#else +#if (WASM_ENABLE_WAMR_COMPILER == 0) && (WASM_ENABLE_JIT == 0) + if (local_offset < 0x80) { + *p_org++ = EXT_OP_SET_LOCAL_FAST; + if (local_type == VALUE_TYPE_I32 + || local_type == VALUE_TYPE_F32) + *p_org++ = (uint8)local_offset; + else + *p_org++ = (uint8)(local_offset | 0x80); + while (p_org < p) + *p_org++ = WASM_OP_NOP; + } +#endif +#endif + break; + } + + case WASM_OP_TEE_LOCAL: + { + p_org = p - 1; + GET_LOCAL_INDEX_TYPE_AND_OFFSET(); +#if WASM_ENABLE_FAST_INTERP != 0 + /* If the stack is in polymorphic state, do fake pop and push on + offset stack to keep the depth of offset stack to be the same + with ref stack */ + BranchBlock *cur_block = loader_ctx->frame_csp - 1; + if (cur_block->is_stack_polymorphic) { + POP_OFFSET_TYPE(local_type); + PUSH_OFFSET_TYPE(local_type); + } +#endif + POP_TYPE(local_type); + PUSH_TYPE(local_type); + +#if WASM_ENABLE_FAST_INTERP != 0 + if (!(preserve_referenced_local(loader_ctx, opcode, local_offset, + local_type, &preserve_local, + error_buf, error_buf_size))) + goto fail; + + if (local_offset < 256) { + skip_label(); + if (local_type == VALUE_TYPE_I32 + || local_type == VALUE_TYPE_F32) { + emit_label(EXT_OP_TEE_LOCAL_FAST); + emit_byte(loader_ctx, local_offset); + } + else { + emit_label(EXT_OP_TEE_LOCAL_FAST_I64); + emit_byte(loader_ctx, local_offset); + } + } + else { /* local index larger than 255, reserve leb */ + p_org ++; + emit_leb(); + } + emit_operand(loader_ctx, *(loader_ctx->frame_offset - + wasm_value_type_cell_num(local_type))); +#else +#if (WASM_ENABLE_WAMR_COMPILER == 0) && (WASM_ENABLE_JIT == 0) + if (local_offset < 0x80) { + *p_org++ = EXT_OP_TEE_LOCAL_FAST; + if (local_type == VALUE_TYPE_I32 + || local_type == VALUE_TYPE_F32) + *p_org++ = (uint8)local_offset; + else + *p_org++ = (uint8)(local_offset | 0x80); + while (p_org < p) + *p_org++ = WASM_OP_NOP; + } +#endif +#endif + break; + } + + case WASM_OP_GET_GLOBAL: + { + read_leb_uint32(p, p_end, global_idx); + bh_assert(global_idx < global_count); + + global_type = global_idx < module->import_global_count + ? module->import_globals[global_idx].u.global.type + :module->globals[global_idx - module->import_global_count].type; + + PUSH_TYPE(global_type); +#if WASM_ENABLE_FAST_INTERP != 0 + emit_const(global_idx); + PUSH_OFFSET_TYPE(global_type); +#endif + break; + } + + case WASM_OP_SET_GLOBAL: + { + bool is_mutable = false; + read_leb_uint32(p, p_end, global_idx); + bh_assert(global_idx < global_count); + + is_mutable = + global_idx < module->import_global_count + ? module->import_globals[global_idx].u.global.is_mutable + : module->globals[global_idx - module->import_global_count] + .is_mutable; + bh_assert(is_mutable); + + global_type = + global_idx < module->import_global_count + ? module->import_globals[global_idx].u.global.type + : module->globals[global_idx - module->import_global_count] + .type; + + POP_TYPE(global_type); +#if WASM_ENABLE_FAST_INTERP != 0 + emit_const(global_idx); + POP_OFFSET_TYPE(global_type); +#endif + (void)is_mutable; + break; + } + + /* load */ + case WASM_OP_I32_LOAD: + case WASM_OP_I32_LOAD8_S: + case WASM_OP_I32_LOAD8_U: + case WASM_OP_I32_LOAD16_S: + case WASM_OP_I32_LOAD16_U: + case WASM_OP_I64_LOAD: + case WASM_OP_I64_LOAD8_S: + case WASM_OP_I64_LOAD8_U: + case WASM_OP_I64_LOAD16_S: + case WASM_OP_I64_LOAD16_U: + case WASM_OP_I64_LOAD32_S: + case WASM_OP_I64_LOAD32_U: + case WASM_OP_F32_LOAD: + case WASM_OP_F64_LOAD: + /* store */ + case WASM_OP_I32_STORE: + case WASM_OP_I32_STORE8: + case WASM_OP_I32_STORE16: + case WASM_OP_I64_STORE: + case WASM_OP_I64_STORE8: + case WASM_OP_I64_STORE16: + case WASM_OP_I64_STORE32: + case WASM_OP_F32_STORE: + case WASM_OP_F64_STORE: + { +#if WASM_ENABLE_FAST_INTERP != 0 + /* change F32/F64 into I32/I64 */ + if (opcode == WASM_OP_F32_LOAD) { + skip_label(); + emit_label(WASM_OP_I32_LOAD); + } + else if (opcode == WASM_OP_F64_LOAD) { + skip_label(); + emit_label(WASM_OP_I64_LOAD); + } + else if (opcode == WASM_OP_F32_STORE) { + skip_label(); + emit_label(WASM_OP_I32_STORE); + } + else if (opcode == WASM_OP_F64_STORE) { + skip_label(); + emit_label(WASM_OP_I64_STORE); + } +#endif + CHECK_MEMORY(); + read_leb_uint32(p, p_end, align); /* align */ + read_leb_uint32(p, p_end, mem_offset); /* offset */ +#if WASM_ENABLE_FAST_INTERP != 0 + emit_const(mem_offset); +#endif + switch (opcode) + { + /* load */ + case WASM_OP_I32_LOAD: + case WASM_OP_I32_LOAD8_S: + case WASM_OP_I32_LOAD8_U: + case WASM_OP_I32_LOAD16_S: + case WASM_OP_I32_LOAD16_U: + POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32); + break; + case WASM_OP_I64_LOAD: + case WASM_OP_I64_LOAD8_S: + case WASM_OP_I64_LOAD8_U: + case WASM_OP_I64_LOAD16_S: + case WASM_OP_I64_LOAD16_U: + case WASM_OP_I64_LOAD32_S: + case WASM_OP_I64_LOAD32_U: + POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I64); + break; + case WASM_OP_F32_LOAD: + POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_F32); + break; + case WASM_OP_F64_LOAD: + POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_F64); + break; + /* store */ + case WASM_OP_I32_STORE: + case WASM_OP_I32_STORE8: + case WASM_OP_I32_STORE16: + POP_I32(); + POP_I32(); + break; + case WASM_OP_I64_STORE: + case WASM_OP_I64_STORE8: + case WASM_OP_I64_STORE16: + case WASM_OP_I64_STORE32: + POP_I64(); + POP_I32(); + break; + case WASM_OP_F32_STORE: + POP_F32(); + POP_I32(); + break; + case WASM_OP_F64_STORE: + POP_F64(); + POP_I32(); + break; + default: + break; + } + break; + } + + case WASM_OP_MEMORY_SIZE: + CHECK_MEMORY(); + /* reserved byte 0x00 */ + bh_assert(*p == 0x00); + p++; + PUSH_I32(); + break; + + case WASM_OP_MEMORY_GROW: + CHECK_MEMORY(); + /* reserved byte 0x00 */ + bh_assert(*p == 0x00); + p++; + POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32); + + func->has_op_memory_grow = true; + module->possible_memory_grow = true; + break; + + case WASM_OP_I32_CONST: + read_leb_int32(p, p_end, i32_const); +#if WASM_ENABLE_FAST_INTERP != 0 + skip_label(); + disable_emit = true; + GET_CONST_OFFSET(VALUE_TYPE_I32, i32_const); +#else + (void)i32_const; +#endif + PUSH_I32(); + break; + + case WASM_OP_I64_CONST: + read_leb_int64(p, p_end, i64); +#if WASM_ENABLE_FAST_INTERP != 0 + skip_label(); + disable_emit = true; + GET_CONST_OFFSET(VALUE_TYPE_I64, i64); +#endif + PUSH_I64(); + break; + + case WASM_OP_F32_CONST: + p += sizeof(float32); +#if WASM_ENABLE_FAST_INTERP != 0 + skip_label(); + disable_emit = true; + bh_memcpy_s((uint8*)&f32, sizeof(float32), p_org, sizeof(float32)); + GET_CONST_F32_OFFSET(VALUE_TYPE_F32, f32); +#endif + PUSH_F32(); + break; + + case WASM_OP_F64_CONST: + p += sizeof(float64); +#if WASM_ENABLE_FAST_INTERP != 0 + skip_label(); + disable_emit = true; + /* Some MCU may require 8-byte align */ + bh_memcpy_s((uint8*)&f64, sizeof(float64), p_org, sizeof(float64)); + GET_CONST_F64_OFFSET(VALUE_TYPE_F64, f64); +#endif + PUSH_F64(); + break; + + case WASM_OP_I32_EQZ: + POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32); + break; + + case WASM_OP_I32_EQ: + case WASM_OP_I32_NE: + case WASM_OP_I32_LT_S: + case WASM_OP_I32_LT_U: + case WASM_OP_I32_GT_S: + case WASM_OP_I32_GT_U: + case WASM_OP_I32_LE_S: + case WASM_OP_I32_LE_U: + case WASM_OP_I32_GE_S: + case WASM_OP_I32_GE_U: + POP2_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32); + break; + + case WASM_OP_I64_EQZ: + POP_AND_PUSH(VALUE_TYPE_I64, VALUE_TYPE_I32); + break; + + case WASM_OP_I64_EQ: + case WASM_OP_I64_NE: + case WASM_OP_I64_LT_S: + case WASM_OP_I64_LT_U: + case WASM_OP_I64_GT_S: + case WASM_OP_I64_GT_U: + case WASM_OP_I64_LE_S: + case WASM_OP_I64_LE_U: + case WASM_OP_I64_GE_S: + case WASM_OP_I64_GE_U: + POP2_AND_PUSH(VALUE_TYPE_I64, VALUE_TYPE_I32); + break; + + case WASM_OP_F32_EQ: + case WASM_OP_F32_NE: + case WASM_OP_F32_LT: + case WASM_OP_F32_GT: + case WASM_OP_F32_LE: + case WASM_OP_F32_GE: + POP2_AND_PUSH(VALUE_TYPE_F32, VALUE_TYPE_I32); + break; + + case WASM_OP_F64_EQ: + case WASM_OP_F64_NE: + case WASM_OP_F64_LT: + case WASM_OP_F64_GT: + case WASM_OP_F64_LE: + case WASM_OP_F64_GE: + POP2_AND_PUSH(VALUE_TYPE_F64, VALUE_TYPE_I32); + break; + + case WASM_OP_I32_CLZ: + case WASM_OP_I32_CTZ: + case WASM_OP_I32_POPCNT: + POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32); + break; + + case WASM_OP_I32_ADD: + case WASM_OP_I32_SUB: + case WASM_OP_I32_MUL: + case WASM_OP_I32_DIV_S: + case WASM_OP_I32_DIV_U: + case WASM_OP_I32_REM_S: + case WASM_OP_I32_REM_U: + case WASM_OP_I32_AND: + case WASM_OP_I32_OR: + case WASM_OP_I32_XOR: + case WASM_OP_I32_SHL: + case WASM_OP_I32_SHR_S: + case WASM_OP_I32_SHR_U: + case WASM_OP_I32_ROTL: + case WASM_OP_I32_ROTR: + POP2_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32); + break; + + case WASM_OP_I64_CLZ: + case WASM_OP_I64_CTZ: + case WASM_OP_I64_POPCNT: + POP_AND_PUSH(VALUE_TYPE_I64, VALUE_TYPE_I64); + break; + + case WASM_OP_I64_ADD: + case WASM_OP_I64_SUB: + case WASM_OP_I64_MUL: + case WASM_OP_I64_DIV_S: + case WASM_OP_I64_DIV_U: + case WASM_OP_I64_REM_S: + case WASM_OP_I64_REM_U: + case WASM_OP_I64_AND: + case WASM_OP_I64_OR: + case WASM_OP_I64_XOR: + case WASM_OP_I64_SHL: + case WASM_OP_I64_SHR_S: + case WASM_OP_I64_SHR_U: + case WASM_OP_I64_ROTL: + case WASM_OP_I64_ROTR: + POP2_AND_PUSH(VALUE_TYPE_I64, VALUE_TYPE_I64); + break; + + case WASM_OP_F32_ABS: + case WASM_OP_F32_NEG: + case WASM_OP_F32_CEIL: + case WASM_OP_F32_FLOOR: + case WASM_OP_F32_TRUNC: + case WASM_OP_F32_NEAREST: + case WASM_OP_F32_SQRT: + POP_AND_PUSH(VALUE_TYPE_F32, VALUE_TYPE_F32); + break; + + case WASM_OP_F32_ADD: + case WASM_OP_F32_SUB: + case WASM_OP_F32_MUL: + case WASM_OP_F32_DIV: + case WASM_OP_F32_MIN: + case WASM_OP_F32_MAX: + case WASM_OP_F32_COPYSIGN: + POP2_AND_PUSH(VALUE_TYPE_F32, VALUE_TYPE_F32); + break; + + case WASM_OP_F64_ABS: + case WASM_OP_F64_NEG: + case WASM_OP_F64_CEIL: + case WASM_OP_F64_FLOOR: + case WASM_OP_F64_TRUNC: + case WASM_OP_F64_NEAREST: + case WASM_OP_F64_SQRT: + POP_AND_PUSH(VALUE_TYPE_F64, VALUE_TYPE_F64); + break; + + case WASM_OP_F64_ADD: + case WASM_OP_F64_SUB: + case WASM_OP_F64_MUL: + case WASM_OP_F64_DIV: + case WASM_OP_F64_MIN: + case WASM_OP_F64_MAX: + case WASM_OP_F64_COPYSIGN: + POP2_AND_PUSH(VALUE_TYPE_F64, VALUE_TYPE_F64); + break; + + case WASM_OP_I32_WRAP_I64: + POP_AND_PUSH(VALUE_TYPE_I64, VALUE_TYPE_I32); + break; + + case WASM_OP_I32_TRUNC_S_F32: + case WASM_OP_I32_TRUNC_U_F32: + POP_AND_PUSH(VALUE_TYPE_F32, VALUE_TYPE_I32); + break; + + case WASM_OP_I32_TRUNC_S_F64: + case WASM_OP_I32_TRUNC_U_F64: + POP_AND_PUSH(VALUE_TYPE_F64, VALUE_TYPE_I32); + break; + + case WASM_OP_I64_EXTEND_S_I32: + case WASM_OP_I64_EXTEND_U_I32: + POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I64); + break; + + case WASM_OP_I64_TRUNC_S_F32: + case WASM_OP_I64_TRUNC_U_F32: + POP_AND_PUSH(VALUE_TYPE_F32, VALUE_TYPE_I64); + break; + + case WASM_OP_I64_TRUNC_S_F64: + case WASM_OP_I64_TRUNC_U_F64: + POP_AND_PUSH(VALUE_TYPE_F64, VALUE_TYPE_I64); + break; + + case WASM_OP_F32_CONVERT_S_I32: + case WASM_OP_F32_CONVERT_U_I32: + POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_F32); + break; + + case WASM_OP_F32_CONVERT_S_I64: + case WASM_OP_F32_CONVERT_U_I64: + POP_AND_PUSH(VALUE_TYPE_I64, VALUE_TYPE_F32); + break; + + case WASM_OP_F32_DEMOTE_F64: + POP_AND_PUSH(VALUE_TYPE_F64, VALUE_TYPE_F32); + break; + + case WASM_OP_F64_CONVERT_S_I32: + case WASM_OP_F64_CONVERT_U_I32: + POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_F64); + break; + + case WASM_OP_F64_CONVERT_S_I64: + case WASM_OP_F64_CONVERT_U_I64: + POP_AND_PUSH(VALUE_TYPE_I64, VALUE_TYPE_F64); + break; + + case WASM_OP_F64_PROMOTE_F32: + POP_AND_PUSH(VALUE_TYPE_F32, VALUE_TYPE_F64); + break; + + case WASM_OP_I32_REINTERPRET_F32: + POP_AND_PUSH(VALUE_TYPE_F32, VALUE_TYPE_I32); + break; + + case WASM_OP_I64_REINTERPRET_F64: + POP_AND_PUSH(VALUE_TYPE_F64, VALUE_TYPE_I64); + break; + + case WASM_OP_F32_REINTERPRET_I32: + POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_F32); + break; + + case WASM_OP_F64_REINTERPRET_I64: + POP_AND_PUSH(VALUE_TYPE_I64, VALUE_TYPE_F64); + break; + + case WASM_OP_I32_EXTEND8_S: + case WASM_OP_I32_EXTEND16_S: + POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32); + break; + + case WASM_OP_I64_EXTEND8_S: + case WASM_OP_I64_EXTEND16_S: + case WASM_OP_I64_EXTEND32_S: + POP_AND_PUSH(VALUE_TYPE_I64, VALUE_TYPE_I64); + break; + + case WASM_OP_MISC_PREFIX: + { + opcode = read_uint8(p); +#if WASM_ENABLE_FAST_INTERP != 0 + emit_byte(loader_ctx, opcode); +#endif + switch (opcode) + { + case WASM_OP_I32_TRUNC_SAT_S_F32: + case WASM_OP_I32_TRUNC_SAT_U_F32: + POP_AND_PUSH(VALUE_TYPE_F32, VALUE_TYPE_I32); + break; + case WASM_OP_I32_TRUNC_SAT_S_F64: + case WASM_OP_I32_TRUNC_SAT_U_F64: + POP_AND_PUSH(VALUE_TYPE_F64, VALUE_TYPE_I32); + break; + case WASM_OP_I64_TRUNC_SAT_S_F32: + case WASM_OP_I64_TRUNC_SAT_U_F32: + POP_AND_PUSH(VALUE_TYPE_F32, VALUE_TYPE_I64); + break; + case WASM_OP_I64_TRUNC_SAT_S_F64: + case WASM_OP_I64_TRUNC_SAT_U_F64: + POP_AND_PUSH(VALUE_TYPE_F64, VALUE_TYPE_I64); + break; +#if WASM_ENABLE_BULK_MEMORY != 0 + case WASM_OP_MEMORY_INIT: + read_leb_uint32(p, p_end, segment_index); +#if WASM_ENABLE_FAST_INTERP != 0 + emit_const(segment_index); +#endif + bh_assert(module->import_memory_count + + module->memory_count > 0); + + bh_assert(*p == 0x00); + p++; + + bh_assert(segment_index < module->data_seg_count); + bh_assert(module->data_seg_count1 > 0); + + POP_I32(); + POP_I32(); + POP_I32(); + break; + case WASM_OP_DATA_DROP: + read_leb_uint32(p, p_end, segment_index); +#if WASM_ENABLE_FAST_INTERP != 0 + emit_const(segment_index); +#endif + bh_assert(segment_index < module->data_seg_count); + bh_assert(module->data_seg_count1 > 0); + break; + case WASM_OP_MEMORY_COPY: + /* both src and dst memory index should be 0 */ + bh_assert(*(int16*)p != 0x0000); + p += 2; + + bh_assert(module->import_memory_count + + module->memory_count > 0); + + POP_I32(); + POP_I32(); + POP_I32(); + break; + case WASM_OP_MEMORY_FILL: + bh_assert(*p == 0); + p++; + + bh_assert(module->import_memory_count + + module->memory_count > 0); + + POP_I32(); + POP_I32(); + POP_I32(); + break; + /* TODO: to support bulk table operation */ +#endif /* WASM_ENABLE_BULK_MEMORY */ + default: + bh_assert(0); + break; + } + break; + } + + default: + bh_assert(0); + break; + } + +#if WASM_ENABLE_FAST_INTERP != 0 + last_op = opcode; +#endif + } + + if (loader_ctx->csp_num > 0) { + set_error_buf(error_buf, error_buf_size, + "WASM module load failed: " + "function body must end with END opcode."); + goto fail; + } + +#if WASM_ENABLE_FAST_INTERP != 0 + if (loader_ctx->p_code_compiled == NULL) + goto re_scan; + + func->const_cell_num = loader_ctx->const_cell_num; + if (!(func->consts = func_const = + loader_malloc(func->const_cell_num * 4, + error_buf, error_buf_size))) { + goto fail; + } + func_const_end = func->consts + func->const_cell_num * 4; + // reverse the const buf + for (int i = loader_ctx->num_const - 1; i >= 0; i--) { + Const *c = (Const*)(loader_ctx->const_buf + i * sizeof(Const)); + if (c->value_type == VALUE_TYPE_F64 + || c->value_type == VALUE_TYPE_I64) { + bh_memcpy_s(func_const, func_const_end - func_const, + &(c->value.f64), sizeof(int64)); + func_const += sizeof(int64); + } else { + bh_memcpy_s(func_const, func_const_end - func_const, + &(c->value.f32), sizeof(int32)); + func_const += sizeof(int32); + } + } + + func->max_stack_cell_num = loader_ctx->preserved_local_offset - + loader_ctx->start_dynamic_offset + 1; +#else + func->max_stack_cell_num = loader_ctx->max_stack_cell_num; +#endif + func->max_block_num = loader_ctx->max_csp_num; + return_value = true; + +fail: + wasm_loader_ctx_destroy(loader_ctx); + + (void)u8; + (void)u32; + (void)i32; + (void)i64; + (void)global_count; + (void)local_count; + (void)local_offset; + (void)p_org; + (void)mem_offset; + (void)align; + return return_value; +} diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index 923005a4d..827691d2e 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -39,6 +39,23 @@ wasm_unload(WASMModule *module) wasm_loader_unload(module); } +static void * +runtime_malloc(uint64 size, char *error_buf, uint32 error_buf_size) +{ + void *mem; + + if (size >= UINT32_MAX + || !(mem = wasm_runtime_malloc((uint32)size))) { + set_error_buf(error_buf, error_buf_size, + "WASM module instantiate failed: " + "allocate memory failed."); + return NULL; + } + + memset(mem, 0, (uint32)size); + return mem; +} + #if WASM_ENABLE_MULTI_MODULE != 0 static WASMModuleInstance * get_sub_module_inst(const WASMModuleInstance *parent_module_inst, @@ -93,14 +110,11 @@ memory_instantiate(uint32 num_bytes_per_page, num_bytes_per_page * (uint64)init_page_count; /* Allocate memory space, addr data and global data */ - if (total_size >= UINT32_MAX - || !(memory = wasm_runtime_malloc((uint32)total_size))) { - set_error_buf(error_buf, error_buf_size, - "Instantiate memory failed: allocate memory failed."); + if (!(memory = runtime_malloc(total_size, + error_buf, error_buf_size))) { return NULL; } - memset(memory, 0, (uint32)total_size); memory->num_bytes_per_page = num_bytes_per_page; memory->cur_page_count = init_page_count; memory->max_page_count = max_page_count; @@ -144,16 +158,11 @@ memories_instantiate(const WASMModule *module, total_size = sizeof(WASMMemoryInstance*) * (uint64)memory_count; - if (total_size >= UINT32_MAX - || !(memories = wasm_runtime_malloc((uint32)total_size))) { - set_error_buf(error_buf, error_buf_size, - "Instantiate memory failed: " - "allocate memory failed."); + if (!(memories = runtime_malloc(total_size, + error_buf, error_buf_size))) { return NULL; } - memset(memories, 0, (uint32)total_size); - /* instantiate memories from import section */ import = module->import_memories; for (i = 0; i < module->import_memory_count; i++, import++) { @@ -271,16 +280,11 @@ tables_instantiate(const WASMModule *module, uint64 total_size = sizeof(WASMTableInstance*) * (uint64)table_count; WASMTableInstance **tables, *table; - if (total_size >= UINT32_MAX - || !(tables = wasm_runtime_malloc((uint32)total_size))) { - set_error_buf(error_buf, error_buf_size, - "Instantiate table failed: " - "allocate memory failed."); + if (!(tables = runtime_malloc(total_size, + error_buf, error_buf_size))) { return NULL; } - memset(tables, 0, (uint32)total_size); - /* instantiate tables from import section */ import = module->import_tables; for (i = 0; i < module->import_table_count; i++, import++) { @@ -310,12 +314,8 @@ tables_instantiate(const WASMModule *module, + sizeof(uint32) * (uint64)import->u.table.init_size; } - if (total_size >= UINT32_MAX - || !(table = tables[table_index++] = - wasm_runtime_malloc((uint32)total_size))) { - set_error_buf(error_buf, error_buf_size, - "Instantiate table failed: " - "allocate memory failed."); + if (!(table = tables[table_index++] = runtime_malloc + (total_size, error_buf, error_buf_size))) { tables_deinstantiate(tables, table_count); return NULL; } @@ -342,12 +342,8 @@ tables_instantiate(const WASMModule *module, for (i = 0; i < module->table_count; i++) { total_size = offsetof(WASMTableInstance, base_addr) + sizeof(uint32) * (uint64)module->tables[i].init_size; - if (total_size >= UINT32_MAX - || !(table = tables[table_index++] = - wasm_runtime_malloc((uint32)total_size))) { - set_error_buf(error_buf, error_buf_size, - "Instantiate table failed: " - "allocate memory failed."); + if (!(table = tables[table_index++] = runtime_malloc + (total_size, error_buf, error_buf_size))) { tables_deinstantiate(tables, table_count); return NULL; } @@ -392,16 +388,11 @@ functions_instantiate(const WASMModule *module, uint64 total_size = sizeof(WASMFunctionInstance) * (uint64)function_count; WASMFunctionInstance *functions, *function; - if (total_size >= UINT32_MAX - || !(functions = wasm_runtime_malloc((uint32)total_size))) { - set_error_buf(error_buf, error_buf_size, - "Instantiate function failed: " - "allocate memory failed."); + if (!(functions = runtime_malloc(total_size, + error_buf, error_buf_size))) { return NULL; } - memset(functions, 0, (uint32)total_size); - /* instantiate functions from import section */ function = functions; import = module->import_functions; @@ -555,16 +546,11 @@ globals_instantiate(const WASMModule *module, uint64 total_size = sizeof(WASMGlobalInstance) * (uint64)global_count; WASMGlobalInstance *globals, *global; - if (total_size >= UINT32_MAX - || !(globals = wasm_runtime_malloc((uint32)total_size))) { - set_error_buf(error_buf, error_buf_size, - "Instantiate global failed: " - "allocate memory failed."); + if (!(globals = runtime_malloc(total_size, + error_buf, error_buf_size))) { return NULL; } - memset(globals, 0, (uint32)total_size); - /* instantiate globals from import section */ global = globals; import = module->import_globals; @@ -727,16 +713,11 @@ export_functions_instantiate(const WASMModule *module, uint32 i; uint64 total_size = sizeof(WASMExportFuncInstance) * (uint64)export_func_count; - if (total_size >= UINT32_MAX - || !(export_func = export_funcs = wasm_runtime_malloc((uint32)total_size))) { - set_error_buf(error_buf, error_buf_size, - "Instantiate export function failed: " - "allocate memory failed."); + if (!(export_func = export_funcs = runtime_malloc + (total_size, error_buf, error_buf_size))) { return NULL; } - memset(export_funcs, 0, (uint32)total_size); - for (i = 0; i < module->export_count; i++, export++) if (export->kind == EXPORT_KIND_FUNC) { export_func->name = export->name; @@ -767,17 +748,11 @@ export_globals_instantiate(const WASMModule *module, uint32 i; uint64 total_size = sizeof(WASMExportGlobInstance) * (uint64)export_glob_count; - if (total_size >= UINT32_MAX - || !(export_global = export_globals = - wasm_runtime_malloc((uint32)total_size))) { - set_error_buf(error_buf, error_buf_size, - "Instantiate export global failed: " - "allocate memory failed."); + if (!(export_global = export_globals = runtime_malloc + (total_size, error_buf, error_buf_size))) { return NULL; } - memset(export_globals, 0, (uint32)total_size); - for (i = 0; i < module->export_count; i++, export++) if (export->kind == EXPORT_KIND_GLOBAL) { export_global->name = export->name; @@ -853,12 +828,11 @@ sub_module_instantiate(WASMModule *module, WASMModuleInstance *module_inst, return false; } - WASMSubModInstNode *sub_module_inst_list_node = - wasm_runtime_malloc(sizeof(WASMSubModInstNode)); + WASMSubModInstNode *sub_module_inst_list_node = runtime_malloc + (sizeof(WASMSubModInstNode), error_buf, error_buf_size); if (!sub_module_inst_list_node) { LOG_DEBUG("Malloc WASMSubModInstNode failed, SZ:%d", sizeof(WASMSubModInstNode)); - set_error_buf_v(error_buf, error_buf_size, "malloc failed"); wasm_deinstantiate(sub_module_inst); return false; } @@ -921,9 +895,8 @@ wasm_instantiate(WASMModule *module, heap_size = APP_HEAP_SIZE_MAX; /* Allocate the memory */ - if (!(module_inst = wasm_runtime_malloc((uint32)sizeof(WASMModuleInstance)))) { - set_error_buf(error_buf, error_buf_size, - "Instantiate module failed: allocate memory failed."); + if (!(module_inst = runtime_malloc(sizeof(WASMModuleInstance), + error_buf, error_buf_size))) { return NULL; } @@ -971,12 +944,11 @@ wasm_instantiate(WASMModule *module, #endif if (global_count > 0) { - if (!(module_inst->global_data = - wasm_runtime_malloc(global_data_size))) { + if (!(module_inst->global_data = runtime_malloc + (global_data_size, error_buf, error_buf_size))) { wasm_deinstantiate(module_inst); return NULL; } - memset(module_inst->global_data, 0, global_data_size); } /* Instantiate memories/tables/functions */ @@ -1546,13 +1518,17 @@ wasm_enlarge_memory(WASMModuleInstance *module, uint32 inc_page_count) return false; } - /* Destroy heap's lock firstly, if its memory is re-allocated, - we cannot access its lock again. */ - mem_allocator_destroy_lock(memory->heap_handle); + if (heap_size > 0) { + /* Destroy heap's lock firstly, if its memory is re-allocated, + we cannot access its lock again. */ + mem_allocator_destroy_lock(memory->heap_handle); + } if (!(new_memory = wasm_runtime_realloc(memory, (uint32)total_size))) { if (!(new_memory = wasm_runtime_malloc((uint32)total_size))) { - /* Restore heap's lock if memory re-alloc failed */ - mem_allocator_reinit_lock(memory->heap_handle); + if (heap_size > 0) { + /* Restore heap's lock if memory re-alloc failed */ + mem_allocator_reinit_lock(memory->heap_handle); + } wasm_set_exception(module, "fail to enlarge memory."); return false; } @@ -1564,12 +1540,14 @@ wasm_enlarge_memory(WASMModuleInstance *module, uint32 inc_page_count) memset((uint8*)new_memory + total_size_old, 0, (uint32)total_size - total_size_old); - new_memory->heap_handle = (uint8*)heap_handle_old + - ((uint8*)new_memory - (uint8*)memory); - if (mem_allocator_migrate(new_memory->heap_handle, - heap_handle_old) != 0) { - wasm_set_exception(module, "fail to enlarge memory."); - return false; + if (heap_size > 0) { + new_memory->heap_handle = (uint8*)heap_handle_old + + ((uint8*)new_memory - (uint8*)memory); + if (mem_allocator_migrate(new_memory->heap_handle, + heap_handle_old) != 0) { + wasm_set_exception(module, "fail to enlarge memory."); + return false; + } } new_memory->cur_page_count = total_page_count; @@ -1582,7 +1560,6 @@ wasm_enlarge_memory(WASMModuleInstance *module, uint32 inc_page_count) return true; } - bool wasm_call_indirect(WASMExecEnv *exec_env, uint32_t element_indices, @@ -1599,7 +1576,7 @@ wasm_call_indirect(WASMExecEnv *exec_env, table_inst = module_inst->default_table; if (!table_inst) { - wasm_set_exception(module_inst, "there is no table"); + wasm_set_exception(module_inst, "unknown table"); goto got_exception; } diff --git a/doc/build_wamr.md b/doc/build_wamr.md index eb4f7e6fa..8d33ee6b1 100644 --- a/doc/build_wamr.md +++ b/doc/build_wamr.md @@ -52,6 +52,11 @@ The script `runtime_lib.cmake` defined a number of variables for configuring the - **WAMR_BUILD_MULTI_MODULE**=1/0, default to disable if not set +#### **Enable WASM mini loader** + +- **WAMR_BUILD_MINI_LOADER**=1/0, default to disable if not set +Note: the mini loader doesn't check the integrity of the WASM binary file, user must ensure that the WASM file is not mal-formed. + **Combination of configurations:** We can combine the configurations. For example, if we want to disable interpreter, enable AOT and WASI, we can run command: diff --git a/product-mini/platforms/linux-sgx/CMakeLists.txt b/product-mini/platforms/linux-sgx/CMakeLists.txt index d30636866..a8da1f752 100644 --- a/product-mini/platforms/linux-sgx/CMakeLists.txt +++ b/product-mini/platforms/linux-sgx/CMakeLists.txt @@ -65,17 +65,8 @@ set (APP_FRAMEWORK_DIR ${WAMR_ROOT_DIR}/core/app-framework) # include the build config template file include (${WAMR_ROOT_DIR}/build-scripts/config_common.cmake) -if ("$ENV{SGX_SDK}" STREQUAL "") - set (SGX_SDK_DIR "/opt/intel/sgxsdk") -else() - set (SGX_SDK_DIR $ENV{SGX_SDK}) -endif() - include_directories (${SHARED_DIR}/include - ${IWASM_DIR}/include - ${SGX_SDK_DIR}/include - ${SGX_SDK_DIR}/include/tlibc - ${SGX_SDK_DIR}/include/libcxx) + ${IWASM_DIR}/include) enable_language (ASM) diff --git a/product-mini/platforms/linux/CMakeLists.txt b/product-mini/platforms/linux/CMakeLists.txt index fc2cb2a0b..642155f40 100644 --- a/product-mini/platforms/linux/CMakeLists.txt +++ b/product-mini/platforms/linux/CMakeLists.txt @@ -65,6 +65,11 @@ if (NOT DEFINED WAMR_BUILD_MULTI_MODULE) set (WAMR_BUILD_MULTI_MODULE 0) endif () +if (NOT DEFINED WAMR_BUILD_MINI_LOADER) + # Disable wasm mini loader by default + set (WAMR_BUILD_MINI_LOADER 0) +endif () + set (WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../..) include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) From 10980a1dd7ee1dcdc1a0d356f0b9be0866696f90 Mon Sep 17 00:00:00 2001 From: wenyongh Date: Thu, 11 Jun 2020 14:19:55 +0800 Subject: [PATCH 017/207] Fix app manager parse applet name issue (#280) --- core/app-mgr/app-manager/app_manager_host.c | 2 +- core/app-mgr/app-manager/resource_reg.c | 2 +- core/iwasm/interpreter/wasm_loader.c | 3 ++- core/iwasm/interpreter/wasm_mini_loader.c | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/core/app-mgr/app-manager/app_manager_host.c b/core/app-mgr/app-manager/app_manager_host.c index d9024a346..a6b13baac 100644 --- a/core/app-mgr/app-manager/app_manager_host.c +++ b/core/app-mgr/app-manager/app_manager_host.c @@ -216,7 +216,7 @@ int aee_host_msg_callback(void *msg, uint16_t msg_len) am_dispatch_request(&request); } else { - printf("unexpected host msg type: %d\n", msg_type); + app_manager_printf("unexpected host msg type: %d\n", msg_type); } APP_MGR_FREE(recv_ctx.message.payload); diff --git a/core/app-mgr/app-manager/resource_reg.c b/core/app-mgr/app-manager/resource_reg.c index c6655ff65..83bc37d98 100644 --- a/core/app-mgr/app-manager/resource_reg.c +++ b/core/app-mgr/app-manager/resource_reg.c @@ -71,7 +71,7 @@ void targeted_app_request_handler(request_t *request, void *unused) } strncpy(applet_name, request->url + offset, sizeof(applet_name) - 1); - char *p = strrchr(applet_name, '/'); + char *p = strchr(applet_name, '/'); if (p) { *p = 0; } else diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index 042a503ed..34400822b 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -2060,7 +2060,8 @@ load_table_segment_section(const uint8 *buf, const uint8 *buf_end, WASMModule *m } for (j = 0; j < function_count; j++) { read_leb_uint32(p, p_end, function_index); - if (function_index >= module->function_count + module->function_count) { + if (function_index >= module->import_function_count + + module->function_count) { set_error_buf(error_buf, error_buf_size, "Load table segment section failed: " "unknown function"); diff --git a/core/iwasm/interpreter/wasm_mini_loader.c b/core/iwasm/interpreter/wasm_mini_loader.c index 3ca23f818..00299f7c7 100644 --- a/core/iwasm/interpreter/wasm_mini_loader.c +++ b/core/iwasm/interpreter/wasm_mini_loader.c @@ -1209,7 +1209,7 @@ load_table_segment_section(const uint8 *buf, const uint8 *buf_end, WASMModule *m for (j = 0; j < function_count; j++) { read_leb_uint32(p, p_end, function_index); - bh_assert(function_index < module->function_count + bh_assert(function_index < module->import_function_count + module->function_count); table_segment->func_indexes[j] = function_index; } From f4d4d6973696cdd6cb5142ade5cc7b521bd7c144 Mon Sep 17 00:00:00 2001 From: J-Heinemann <66268543+J-Heinemann@users.noreply.github.com> Date: Fri, 12 Jun 2020 12:47:06 +0200 Subject: [PATCH 018/207] wasm_export.h Function Description & SGX SDK Include path (#279) * Missing SGX SDK Include fixed * Update shared_platform.cmake * CMakeFile remove stdlib from untrusted part * Added two times in function description zero as possible return value * Update shared_platform.cmake Co-authored-by: Joshua Heinemann Co-authored-by: wenyongh --- core/iwasm/include/wasm_export.h | 4 ++-- core/shared/platform/linux-sgx/shared_platform.cmake | 8 +++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/core/iwasm/include/wasm_export.h b/core/iwasm/include/wasm_export.h index 0ef3bb982..f9659a2e8 100644 --- a/core/iwasm/include/wasm_export.h +++ b/core/iwasm/include/wasm_export.h @@ -319,7 +319,7 @@ wasm_runtime_lookup_wasi_start_function(wasm_module_inst_t module_inst); * @param name the name of the function * @param signature the signature of the function, ignored currently * - * @return the function instance found + * @return the function instance found. Otherwise NULL will be returned. */ wasm_function_inst_t wasm_runtime_lookup_function(wasm_module_inst_t const module_inst, @@ -331,7 +331,7 @@ wasm_runtime_lookup_function(wasm_module_inst_t const module_inst, * @param module_inst the module instance * @param stack_size the stack size to execute a WASM function * - * @return the execution environment + * @return the execution environment. In case of invalid stack size, NULL will be returned. */ wasm_exec_env_t wasm_runtime_create_exec_env(wasm_module_inst_t module_inst, diff --git a/core/shared/platform/linux-sgx/shared_platform.cmake b/core/shared/platform/linux-sgx/shared_platform.cmake index 810a7cf2e..a92caafee 100644 --- a/core/shared/platform/linux-sgx/shared_platform.cmake +++ b/core/shared/platform/linux-sgx/shared_platform.cmake @@ -14,9 +14,11 @@ else() set (SGX_SDK_DIR $ENV{SGX_SDK}) endif() -include_directories (${SGX_SDK_DIR}/include - ${SGX_SDK_DIR}/include/tlibc - ${SGX_SDK_DIR}/include/libcxx) +include_directories (${SGX_SDK_DIR}/include) +if (NOT BUILD_UNTRUST_PART EQUAL 1) + include_directories (${SGX_SDK_DIR}/include/tlibc + ${SGX_SDK_DIR}/include/libcxx) +endif () file (GLOB_RECURSE source_all ${PLATFORM_SHARED_DIR}/*.c) From d98ab63e5c6c0cd3a3f3901827d48a17300d7d43 Mon Sep 17 00:00:00 2001 From: Xu Jun <693788454@qq.com> Date: Mon, 15 Jun 2020 19:04:04 +0800 Subject: [PATCH 019/207] Enable shared memory && add pthread support (#282) --- README.md | 1 + build-scripts/config_common.cmake | 12 + build-scripts/runtime_lib.cmake | 14 + core/config.h | 18 + core/iwasm/aot/aot_runtime.c | 99 ++- core/iwasm/aot/aot_runtime.h | 6 +- core/iwasm/common/wasm_exec_env.c | 92 ++- core/iwasm/common/wasm_exec_env.h | 42 + core/iwasm/common/wasm_native.c | 26 + core/iwasm/common/wasm_runtime_common.c | 147 +++- core/iwasm/common/wasm_runtime_common.h | 25 + core/iwasm/common/wasm_shared_memory.c | 124 +++ core/iwasm/common/wasm_shared_memory.h | 82 ++ core/iwasm/include/wasm_export.h | 17 +- core/iwasm/interpreter/wasm_interp_classic.c | 39 + core/iwasm/interpreter/wasm_interp_fast.c | 39 + core/iwasm/interpreter/wasm_loader.c | 161 ++-- core/iwasm/interpreter/wasm_mini_loader.c | 135 ++-- core/iwasm/interpreter/wasm_runtime.c | 293 +++++-- core/iwasm/interpreter/wasm_runtime.h | 18 +- .../libraries/lib-pthread/lib_pthread.cmake | 13 + .../lib-pthread/lib_pthread_wrapper.c | 731 ++++++++++++++++++ .../libc-builtin/libc_builtin_wrapper.c | 2 + .../libraries/libc-wasi/libc_wasi_wrapper.c | 123 +++ .../libraries/thread-mgr/thread_manager.c | 523 +++++++++++++ .../libraries/thread-mgr/thread_manager.h | 116 +++ .../libraries/thread-mgr/thread_mgr.cmake | 13 + core/shared/platform/alios/alios_thread.c | 8 +- .../platform/common/posix/posix_thread.c | 20 +- .../platform/include/platform_api_extension.h | 16 + .../platform/include/platform_api_vmcore.h | 4 +- core/shared/platform/linux-sgx/sgx_thread.c | 8 +- core/shared/platform/zephyr/zephyr_thread.c | 8 +- doc/build_wamr.md | 10 + doc/pthread_library.md | 157 ++++ product-mini/platforms/linux/main.c | 14 + samples/multi-thread/CMakeLists.txt | 47 ++ samples/multi-thread/wasm-apps/CMakeLists.txt | 34 + samples/multi-thread/wasm-apps/main.c | 69 ++ .../libc-builtin-sysroot/include/pthread.h | 49 ++ .../share/defined-symbols.txt | 15 + 41 files changed, 3081 insertions(+), 289 deletions(-) create mode 100644 core/iwasm/common/wasm_shared_memory.c create mode 100644 core/iwasm/common/wasm_shared_memory.h create mode 100644 core/iwasm/libraries/lib-pthread/lib_pthread.cmake create mode 100644 core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c create mode 100644 core/iwasm/libraries/thread-mgr/thread_manager.c create mode 100644 core/iwasm/libraries/thread-mgr/thread_manager.h create mode 100644 core/iwasm/libraries/thread-mgr/thread_mgr.cmake create mode 100644 doc/pthread_library.md create mode 100644 samples/multi-thread/CMakeLists.txt create mode 100644 samples/multi-thread/wasm-apps/CMakeLists.txt create mode 100644 samples/multi-thread/wasm-apps/main.c create mode 100644 wamr-sdk/app/libc-builtin-sysroot/include/pthread.h diff --git a/README.md b/README.md index bdb707c86..e2276b95f 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,7 @@ iwasm VM core - [Non-trapping float-to-int conversions](https://github.com/WebAssembly/nontrapping-float-to-int-conversions) - [Sign-extension operators](https://github.com/WebAssembly/sign-extension-ops) - [Bulk memory operations](https://github.com/WebAssembly/bulk-memory-operations) +- [Shared memmory](https://github.com/WebAssembly/threads/blob/master/proposals/threads/Overview.md#shared-linear-memory) ### Performance and memory usage The WAMR performance, footprint and memory usage data are available at the [performance](../../wiki/Performance) wiki page. diff --git a/build-scripts/config_common.cmake b/build-scripts/config_common.cmake index 106427566..3908ea1e2 100644 --- a/build-scripts/config_common.cmake +++ b/build-scripts/config_common.cmake @@ -140,6 +140,18 @@ if (WAMR_BUILD_BULK_MEMORY EQUAL 1) else () add_definitions (-DWASM_ENABLE_BULK_MEMORY=0) endif () +if (WAMR_BUILD_SHARED_MEMORY EQUAL 1) + add_definitions (-DWASM_ENABLE_SHARED_MEMORY=1) + message (" Shared memory enabled") +else () + add_definitions (-DWASM_ENABLE_SHARED_MEMORY=0) +endif () +if (WAMR_BUILD_THREAD_MGR EQUAL 1) + message (" Thread manager enabled") +endif () +if (WAMR_BUILD_LIB_PTHREAD EQUAL 1) + message (" Lib pthread enabled") +endif () if (WAMR_BUILD_MINI_LOADER EQUAL 1) add_definitions (-DWASM_ENABLE_MINI_LOADER=1) message (" WASM mini loader enabled") diff --git a/build-scripts/runtime_lib.cmake b/build-scripts/runtime_lib.cmake index 128f44ea6..febdec225 100644 --- a/build-scripts/runtime_lib.cmake +++ b/build-scripts/runtime_lib.cmake @@ -69,6 +69,18 @@ if (WAMR_BUILD_LIBC_WASI EQUAL 1) include (${IWASM_DIR}/libraries/libc-wasi/libc_wasi.cmake) endif () +if (WAMR_BUILD_LIB_PTHREAD EQUAL 1) + include (${IWASM_DIR}/libraries/lib-pthread/lib_pthread.cmake) + # Enable the dependent feature if lib pthread is enabled + set (WAMR_BUILD_THREAD_MGR 1) + set (WAMR_BUILD_BULK_MEMORY 1) + set (WAMR_BUILD_SHARED_MEMORY 1) +endif () + +if (WAMR_BUILD_THREAD_MGR EQUAL 1) + include (${IWASM_DIR}/libraries/thread-mgr/thread_mgr.cmake) +endif () + ####################### Common sources ####################### set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99 -ffunction-sections -fdata-sections \ -Wall -Wno-unused-parameter -Wno-pedantic") @@ -106,6 +118,8 @@ set (source_all ${WASM_APP_LIB_SOURCE_ALL} ${NATIVE_INTERFACE_SOURCE} ${APP_MGR_SOURCE} + ${LIB_PTHREAD_SOURCE} + ${THREAD_MGR_SOURCE} ) set (WAMR_RUNTIME_LIB_SOURCE ${source_all}) diff --git a/core/config.h b/core/config.h index 2bbcb7bf7..870d02c7b 100644 --- a/core/config.h +++ b/core/config.h @@ -86,6 +86,10 @@ enum { #define WASM_ENABLE_LIBC_WASI 0 #endif +#ifndef WASM_ENABLE_LIB_PTHREAD +#define WASM_ENABLE_LIB_PTHREAD 0 +#endif + #ifndef WASM_ENABLE_BASE_LIB #define WASM_ENABLE_BASE_LIB 0 #endif @@ -99,6 +103,16 @@ enum { #define WASM_ENABLE_BULK_MEMORY 0 #endif +/* Shared memory */ +#ifndef WASM_ENABLE_SHARED_MEMORY +#define WASM_ENABLE_SHARED_MEMORY 0 +#endif + +/* Thread manager */ +#ifndef WASM_ENABLE_THREAD_MGR +#define WASM_ENABLE_THREAD_MGR 0 +#endif + /* WASM log system */ #ifndef WASM_ENABLE_LOG #define WASM_ENABLE_LOG 1 @@ -206,5 +220,9 @@ enum { #define WASM_ENABLE_SPEC_TEST 0 #endif +/* Default max thread num per cluster. Can be overwrite by + wasm_runtime_set_max_thread_num */ +#define CLUSTER_MAX_THREAD_NUM 4 + #endif /* end of _CONFIG_H_ */ diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index 65975a10c..c2e491af9 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -167,30 +167,24 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModule *module, module_inst->heap_data.ptr = p; p += heap_size; module_inst->heap_data_end.ptr = p; - if (!(heap_handle = mem_allocator_create(module_inst->heap_data.ptr, - heap_size))) { - set_error_buf(error_buf, error_buf_size, - "AOT module instantiate failed: init app heap failed."); - goto fail1; - } - module_inst->heap_handle.ptr = heap_handle; module_inst->heap_data_size = heap_size; -#if WASM_ENABLE_SPEC_TEST == 0 module_inst->heap_base_offset = -(int32)heap_size; -#else - module_inst->heap_base_offset = 0; -#endif + if (heap_size > 0) { + if (!(heap_handle = mem_allocator_create(module_inst->heap_data.ptr, + heap_size))) { + set_error_buf(error_buf, error_buf_size, + "AOT module instantiate failed: init app heap failed."); + goto fail1; + } + module_inst->heap_handle.ptr = heap_handle; + } /* Init memory info */ module_inst->memory_data.ptr = p; p += (uint32)memory_data_size; module_inst->memory_data_end.ptr = p; module_inst->memory_data_size = (uint32)memory_data_size; -#if WASM_ENABLE_SPEC_TEST == 0 module_inst->total_mem_size = (uint32)(heap_size + memory_data_size); -#else - module_inst->total_mem_size = (uint32)memory_data_size; -#endif module_inst->mem_cur_page_count = module->mem_init_page_count; module_inst->mem_max_page_count = module->mem_max_page_count; @@ -210,7 +204,7 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModule *module, bh_assert(data_seg->offset.init_expr_type == INIT_EXPR_TYPE_I32_CONST - || data_seg->offset.init_expr_type == + || data_seg->offset.init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL); /* Resolve memory data base offset */ @@ -264,8 +258,10 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModule *module, return true; fail2: - mem_allocator_destroy(module_inst->heap_handle.ptr); - module_inst->heap_handle.ptr = NULL; + if (heap_size > 0) { + mem_allocator_destroy(module_inst->heap_handle.ptr); + module_inst->heap_handle.ptr = NULL; + } fail1: wasm_runtime_free(module_inst->heap_data.ptr); module_inst->heap_data.ptr = NULL; @@ -361,7 +357,7 @@ execute_start_function(AOTModuleInstance *module_inst) } AOTModuleInstance* -aot_instantiate(AOTModule *module, +aot_instantiate(AOTModule *module, bool is_sub_inst, uint32 stack_size, uint32 heap_size, char *error_buf, uint32 error_buf_size) { @@ -376,10 +372,6 @@ aot_instantiate(AOTModule *module, /* Check heap size */ heap_size = align_uint(heap_size, 8); - if (heap_size == 0) - heap_size = APP_HEAP_SIZE_DEFAULT; - if (heap_size < APP_HEAP_SIZE_MIN) - heap_size = APP_HEAP_SIZE_MIN; if (heap_size > APP_HEAP_SIZE_MAX) heap_size = APP_HEAP_SIZE_MAX; @@ -422,16 +414,17 @@ aot_instantiate(AOTModule *module, goto fail; #if WASM_ENABLE_LIBC_WASI != 0 - if (!wasm_runtime_init_wasi((WASMModuleInstanceCommon*)module_inst, - module->wasi_args.dir_list, - module->wasi_args.dir_count, - module->wasi_args.map_dir_list, - module->wasi_args.map_dir_count, - module->wasi_args.env, - module->wasi_args.env_count, - module->wasi_args.argv, - module->wasi_args.argc, - error_buf, error_buf_size)) + if (heap_size > 0 + && !wasm_runtime_init_wasi((WASMModuleInstanceCommon*)module_inst, + module->wasi_args.dir_list, + module->wasi_args.dir_count, + module->wasi_args.map_dir_list, + module->wasi_args.map_dir_count, + module->wasi_args.env, + module->wasi_args.env_count, + module->wasi_args.argv, + module->wasi_args.argc, + error_buf, error_buf_size)) goto fail; #endif @@ -455,19 +448,21 @@ aot_instantiate(AOTModule *module, return module_inst; fail: - aot_deinstantiate(module_inst); + aot_deinstantiate(module_inst, is_sub_inst); return NULL; } void -aot_deinstantiate(AOTModuleInstance *module_inst) +aot_deinstantiate(AOTModuleInstance *module_inst, bool is_sub_inst) { #if WASM_ENABLE_LIBC_WASI != 0 /* Destroy wasi resource before freeing app heap, since some fields of wasi contex are allocated from app heap, and if app heap is freed, these fields will be set to NULL, we cannot free their internal data which may allocated from global heap. */ - wasm_runtime_destroy_wasi((WASMModuleInstanceCommon*)module_inst); + /* Only destroy wasi ctx in the main module instance */ + if (!is_sub_inst) + wasm_runtime_destroy_wasi((WASMModuleInstanceCommon*)module_inst); #endif if (module_inst->heap_handle.ptr) @@ -798,13 +793,17 @@ aot_enlarge_memory(AOTModuleInstance *module_inst, uint32 inc_page_count) return false; } - /* Destroy heap's lock firstly, if its memory is re-allocated, - we cannot access its lock again. */ - mem_allocator_destroy_lock(module_inst->heap_handle.ptr); + if (heap_size > 0) { + /* Destroy heap's lock firstly, if its memory is re-allocated, + we cannot access its lock again. */ + mem_allocator_destroy_lock(module_inst->heap_handle.ptr); + } if (!(heap_data = wasm_runtime_realloc(heap_data_old, (uint32)total_size))) { if (!(heap_data = wasm_runtime_malloc((uint32)total_size))) { - /* Restore heap's lock if memory re-alloc failed */ - mem_allocator_reinit_lock(module_inst->heap_handle.ptr); + if (heap_size > 0) { + /* Restore heap's lock if memory re-alloc failed */ + mem_allocator_reinit_lock(module_inst->heap_handle.ptr); + } aot_set_exception(module_inst, "fail to enlarge memory."); return false; } @@ -817,23 +816,21 @@ aot_enlarge_memory(AOTModuleInstance *module_inst, uint32 inc_page_count) 0, (uint32)total_size - total_size_old); module_inst->heap_data.ptr = heap_data; - module_inst->heap_handle.ptr = (uint8*)heap_handle_old - + (heap_data - heap_data_old); module_inst->heap_data_end.ptr = heap_data + heap_size; - if (mem_allocator_migrate(module_inst->heap_handle.ptr, - heap_handle_old) != 0) { - aot_set_exception(module_inst, "fail to enlarge memory."); - return false; + if (heap_size > 0) { + module_inst->heap_handle.ptr = (uint8*)heap_handle_old + + (heap_data - heap_data_old); + if (mem_allocator_migrate(module_inst->heap_handle.ptr, + heap_handle_old) != 0) { + aot_set_exception(module_inst, "fail to enlarge memory."); + return false; + } } module_inst->mem_cur_page_count = total_page_count; module_inst->memory_data_size = (uint32)memory_data_size; -#if WASM_ENABLE_SPEC_TEST == 0 module_inst->total_mem_size = (uint32)(heap_size + memory_data_size); -#else - module_inst->total_mem_size = (uint32)memory_data_size; -#endif module_inst->memory_data.ptr = (uint8*)heap_data + heap_size; module_inst->memory_data_end.ptr = (uint8*)module_inst->memory_data.ptr + (uint32)memory_data_size; diff --git a/core/iwasm/aot/aot_runtime.h b/core/iwasm/aot/aot_runtime.h index 74d9667e2..d06bc0b80 100644 --- a/core/iwasm/aot/aot_runtime.h +++ b/core/iwasm/aot/aot_runtime.h @@ -296,6 +296,7 @@ aot_unload(AOTModule *module); * Instantiate a AOT module. * * @param module the AOT module to instantiate + * @param is_sub_inst the flag of sub instance * @param heap_size the default heap size of the module instance, a heap will * be created besides the app memory space. Both wasm app and native * function can allocate memory from the heap. If heap_size is 0, the @@ -306,7 +307,7 @@ aot_unload(AOTModule *module); * @return return the instantiated AOT module instance, NULL if failed */ AOTModuleInstance* -aot_instantiate(AOTModule *module, +aot_instantiate(AOTModule *module, bool is_sub_inst, uint32 stack_size, uint32 heap_size, char *error_buf, uint32 error_buf_size); @@ -314,9 +315,10 @@ aot_instantiate(AOTModule *module, * Deinstantiate a AOT module instance, destroy the resources. * * @param module_inst the AOT module instance to destroy + * @param is_sub_inst the flag of sub instance */ void -aot_deinstantiate(AOTModuleInstance *module_inst); +aot_deinstantiate(AOTModuleInstance *module_inst, bool is_sub_inst); /** * Lookup an exported function in the AOT module instance. diff --git a/core/iwasm/common/wasm_exec_env.c b/core/iwasm/common/wasm_exec_env.c index 814301a00..14a173c11 100644 --- a/core/iwasm/common/wasm_exec_env.c +++ b/core/iwasm/common/wasm_exec_env.c @@ -6,9 +6,13 @@ #include "wasm_exec_env.h" #include "wasm_runtime_common.h" +#if WASM_ENABLE_THREAD_MGR != 0 +#include "../libraries/thread-mgr/thread_manager.h" +#endif + WASMExecEnv * -wasm_exec_env_create(struct WASMModuleInstanceCommon *module_inst, - uint32 stack_size) +wasm_exec_env_create_internal(struct WASMModuleInstanceCommon *module_inst, + uint32 stack_size) { uint64 total_size = offsetof(WASMExecEnv, wasm_stack.s.bottom) + (uint64)stack_size; @@ -22,26 +26,87 @@ wasm_exec_env_create(struct WASMModuleInstanceCommon *module_inst, #if WASM_ENABLE_AOT != 0 if (!(exec_env->argv_buf = wasm_runtime_malloc(sizeof(uint32) * 64))) { - wasm_runtime_free(exec_env); - return NULL; + goto fail1; } #endif +#if WASM_ENABLE_THREAD_MGR != 0 + if (os_mutex_init(&exec_env->wait_lock) != 0) + goto fail2; + + if (os_cond_init(&exec_env->wait_cond) != 0) + goto fail3; +#endif + exec_env->module_inst = module_inst; exec_env->wasm_stack_size = stack_size; exec_env->wasm_stack.s.top_boundary = exec_env->wasm_stack.s.bottom + stack_size; exec_env->wasm_stack.s.top = exec_env->wasm_stack.s.bottom; return exec_env; + +#if WASM_ENABLE_THREAD_MGR != 0 +fail3: + os_mutex_destroy(&exec_env->wait_lock); +fail2: +#endif +#if WASM_ENABLE_AOT != 0 + wasm_runtime_free(exec_env->argv_buf); +fail1: +#endif + wasm_runtime_free(exec_env); + return NULL; +} + +void +wasm_exec_env_destroy_internal(WASMExecEnv *exec_env) +{ +#if WASM_ENABLE_THREAD_MGR != 0 + os_mutex_destroy(&exec_env->wait_lock); + os_cond_destroy(&exec_env->wait_cond); +#endif +#if WASM_ENABLE_AOT != 0 + wasm_runtime_free(exec_env->argv_buf); +#endif + wasm_runtime_free(exec_env); +} + +WASMExecEnv * +wasm_exec_env_create(struct WASMModuleInstanceCommon *module_inst, + uint32 stack_size) +{ + WASMExecEnv *exec_env = wasm_exec_env_create_internal(module_inst, + stack_size); + /* Set the aux_stack_boundary to 0 */ + exec_env->aux_stack_boundary = 0; +#if WASM_ENABLE_THREAD_MGR != 0 + WASMCluster *cluster; + + if (!exec_env) + return NULL; + + /* Create a new cluster for this exec_env */ + cluster = wasm_cluster_create(exec_env); + if (!cluster) { + wasm_exec_env_destroy_internal(exec_env); + return NULL; + } +#endif + return exec_env; } void wasm_exec_env_destroy(WASMExecEnv *exec_env) { -#if WASM_ENABLE_AOT != 0 - wasm_runtime_free(exec_env->argv_buf); +#if WASM_ENABLE_THREAD_MGR != 0 + /* Terminate all sub-threads */ + WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env); + if (cluster) { + wasm_cluster_terminate_all_except_self(cluster, exec_env); + wasm_cluster_del_exec_env(cluster, exec_env); + } #endif - wasm_runtime_free(exec_env); + wasm_exec_env_destroy_internal(exec_env); } WASMModuleInstanceCommon * @@ -59,3 +124,16 @@ wasm_exec_env_set_thread_info(WASMExecEnv *exec_env) } +#if WASM_ENABLE_THREAD_MGR != 0 +void * +wasm_exec_env_get_thread_arg(WASMExecEnv *exec_env) +{ + return exec_env->thread_arg; +} + +void +wasm_exec_env_set_thread_arg(WASMExecEnv *exec_env, void *thread_arg) +{ + exec_env->thread_arg = thread_arg; +} +#endif \ No newline at end of file diff --git a/core/iwasm/common/wasm_exec_env.h b/core/iwasm/common/wasm_exec_env.h index c6d14df51..d29f33cb7 100644 --- a/core/iwasm/common/wasm_exec_env.h +++ b/core/iwasm/common/wasm_exec_env.h @@ -18,6 +18,10 @@ extern "C" { struct WASMModuleInstanceCommon; struct WASMInterpFrame; +#if WASM_ENABLE_THREAD_MGR != 0 +typedef struct WASMCluster WASMCluster; +#endif + /* Execution environment */ typedef struct WASMExecEnv { /* Next thread's exec env of a WASM module instance. */ @@ -41,6 +45,28 @@ typedef struct WASMExecEnv { exception. */ uint8 *native_stack_boundary; +#if WASM_ENABLE_THREAD_MGR != 0 + /* Used to terminate or suspend the interpreter + bit 0: need terminate + bit 1: need suspend + bit 2: need to go into breakpoint */ + uintptr_t suspend_flags; + + /* Must be provided by thread library */ + void* (*thread_start_routine)(void *); + void *thread_arg; + + /* pointer to the cluster */ + WASMCluster *cluster; + + /* used to support debugger */ + korp_mutex wait_lock; + korp_cond wait_cond; +#endif + + /* Aux stack boundary */ + uint32 aux_stack_boundary; + /* attachment for native function */ void *attachment; @@ -76,6 +102,13 @@ typedef struct WASMExecEnv { } wasm_stack; } WASMExecEnv; +WASMExecEnv * +wasm_exec_env_create_internal(struct WASMModuleInstanceCommon *module_inst, + uint32 stack_size); + +void +wasm_exec_env_destroy_internal(WASMExecEnv *exec_env); + WASMExecEnv * wasm_exec_env_create(struct WASMModuleInstanceCommon *module_inst, uint32 stack_size); @@ -165,6 +198,15 @@ wasm_exec_env_get_module_inst(WASMExecEnv *exec_env); void wasm_exec_env_set_thread_info(WASMExecEnv *exec_env); + +#if WASM_ENABLE_THREAD_MGR != 0 +void * +wasm_exec_env_get_thread_arg(WASMExecEnv *exec_env); + +void +wasm_exec_env_set_thread_arg(WASMExecEnv *exec_env, void *thread_arg); +#endif + #ifdef __cplusplus } #endif diff --git a/core/iwasm/common/wasm_native.c b/core/iwasm/common/wasm_native.c index 115296eed..3dd38c389 100644 --- a/core/iwasm/common/wasm_native.c +++ b/core/iwasm/common/wasm_native.c @@ -28,6 +28,17 @@ get_base_lib_export_apis(NativeSymbol **p_base_lib_apis); uint32 get_ext_lib_export_apis(NativeSymbol **p_ext_lib_apis); +#if WASM_ENABLE_LIB_PTHREAD != 0 +bool +lib_pthread_init(); + +void +lib_pthread_destroy(); + +uint32 +get_lib_pthread_export_apis(NativeSymbol **p_lib_pthread_apis); +#endif + static bool check_symbol_signature(const WASMType *type, const char *signature) { @@ -278,6 +289,17 @@ wasm_native_init() return false; #endif +#if WASM_ENABLE_LIB_PTHREAD != 0 + if (!lib_pthread_init()) + return false; + + n_native_symbols = get_lib_pthread_export_apis(&native_symbols); + if (n_native_symbols > 0 + && !wasm_native_register_natives("env", + native_symbols, n_native_symbols)) + return false; +#endif + return true; } @@ -286,6 +308,10 @@ wasm_native_destroy() { NativeSymbolsNode *node, *node_next; +#if WASM_ENABLE_LIB_PTHREAD != 0 + lib_pthread_destroy(); +#endif + node = g_native_symbols_list; while (node) { node_next = node->next; diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index 02cd58634..50b459bf8 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -15,6 +15,12 @@ #if WASM_ENABLE_AOT != 0 #include "../aot/aot_runtime.h" #endif +#if WASM_ENABLE_THREAD_MGR != 0 +#include "../libraries/thread-mgr/thread_manager.h" +#endif +#if WASM_ENABLE_SHARED_MEMORY != 0 +#include "wasm_shared_memory.h" +#endif #if WASM_ENABLE_MULTI_MODULE != 0 /* @@ -90,25 +96,50 @@ wasm_runtime_env_init() return false; if (wasm_native_init() == false) { - bh_platform_destroy(); - return false; + goto fail1; } #if WASM_ENABLE_MULTI_MODULE if (BHT_OK != os_mutex_init(®istered_module_list_lock)) { - wasm_native_destroy(); - bh_platform_destroy(); - return false; + goto fail2; } if (BHT_OK != os_mutex_init(&loading_module_list_lock)) { - os_mutex_destroy(®istered_module_list_lock); - wasm_native_destroy(); - bh_platform_destroy(); - return false; + goto fail3; + } +#endif + +#if WASM_ENABLE_SHARED_MEMORY + if (!wasm_shared_memory_init()) { + goto fail4; + } +#endif + +#if WASM_ENABLE_THREAD_MGR != 0 + if (!thread_manager_init()) { + goto fail5; } #endif return true; + +#if WASM_ENABLE_THREAD_MGR != 0 +fail5: +#endif +#if WASM_ENABLE_SHARED_MEMORY + wasm_shared_memory_destroy(); +fail4: +#endif +#if WASM_ENABLE_MULTI_MODULE + os_mutex_destroy(&loading_module_list_lock); +fail3: + os_mutex_destroy(®istered_module_list_lock); +fail2: +#endif + wasm_native_destroy(); +fail1: + bh_platform_destroy(); + + return false; } static bool @@ -147,6 +178,15 @@ wasm_runtime_destroy() wasm_runtime_destroy_registered_module_list(); os_mutex_destroy(®istered_module_list_lock); #endif + +#if WASM_ENABLE_SHARED_MEMORY + wasm_shared_memory_destroy(); +#endif + +#if WASM_ENABLE_THREAD_MGR != 0 + thread_manager_destroy(); +#endif + wasm_native_destroy(); bh_platform_destroy(); @@ -191,7 +231,6 @@ get_package_type(const uint8 *buf, uint32 size) #if WASM_ENABLE_MULTI_MODULE != 0 static module_reader reader; static module_destroyer destroyer; - void wasm_runtime_set_module_reader(const module_reader reader_cb, const module_destroyer destroyer_cb) @@ -492,6 +531,42 @@ wasm_runtime_is_built_in_module(const char *module_name) ); } +#if WASM_ENABLE_THREAD_MGR != 0 +bool +wasm_exec_env_set_aux_stack(WASMExecEnv *exec_env, + uint32 start_offset, uint32 size) +{ + WASMModuleInstanceCommon *module_inst + = wasm_exec_env_get_module_inst(exec_env); +#if WASM_ENABLE_INTERP != 0 + if (module_inst->module_type == Wasm_Module_Bytecode) { + return wasm_set_aux_stack(exec_env, start_offset, size); + } +#endif + return false; +} + +bool +wasm_exec_env_get_aux_stack(WASMExecEnv *exec_env, + uint32 *start_offset, uint32 *size) +{ + WASMModuleInstanceCommon *module_inst + = wasm_exec_env_get_module_inst(exec_env); +#if WASM_ENABLE_INTERP != 0 + if (module_inst->module_type == Wasm_Module_Bytecode) { + return wasm_get_aux_stack(exec_env, start_offset, size); + } +#endif + return false; +} + +void +wasm_runtime_set_max_thread_num(uint32 num) +{ + wasm_cluster_set_max_thread_num(num); +} +#endif /* end of WASM_ENABLE_THREAD_MGR */ + static WASMModuleCommon * register_module_with_null_name(WASMModuleCommon *module_common, char *error_buf, uint32 error_buf_size) @@ -618,47 +693,63 @@ wasm_runtime_unload(WASMModuleCommon *module) } WASMModuleInstanceCommon * -wasm_runtime_instantiate(WASMModuleCommon *module, - uint32 stack_size, uint32 heap_size, - char *error_buf, uint32 error_buf_size) +wasm_runtime_instantiate_internal(WASMModuleCommon *module, bool is_sub_inst, + uint32 stack_size, uint32 heap_size, + char *error_buf, uint32 error_buf_size) { #if WASM_ENABLE_INTERP != 0 if (module->module_type == Wasm_Module_Bytecode) return (WASMModuleInstanceCommon*) - wasm_instantiate((WASMModule*)module, + wasm_instantiate((WASMModule*)module, is_sub_inst, stack_size, heap_size, error_buf, error_buf_size); #endif #if WASM_ENABLE_AOT != 0 if (module->module_type == Wasm_Module_AoT) return (WASMModuleInstanceCommon*) - aot_instantiate((AOTModule*)module, + aot_instantiate((AOTModule*)module, is_sub_inst, stack_size, heap_size, error_buf, error_buf_size); #endif - set_error_buf(error_buf, error_buf_size, "Instantiate module failed, invalid module type"); return NULL; } +WASMModuleInstanceCommon * +wasm_runtime_instantiate(WASMModuleCommon *module, + uint32 stack_size, uint32 heap_size, + char *error_buf, uint32 error_buf_size) +{ + return wasm_runtime_instantiate_internal(module, false, + stack_size, heap_size, + error_buf, error_buf_size); +} + void -wasm_runtime_deinstantiate(WASMModuleInstanceCommon *module_inst) +wasm_runtime_deinstantiate_internal(WASMModuleInstanceCommon *module_inst, + bool is_sub_inst) { #if WASM_ENABLE_INTERP != 0 if (module_inst->module_type == Wasm_Module_Bytecode) { - wasm_deinstantiate((WASMModuleInstance*)module_inst); + wasm_deinstantiate((WASMModuleInstance*)module_inst, is_sub_inst); return; } #endif #if WASM_ENABLE_AOT != 0 if (module_inst->module_type == Wasm_Module_AoT) { - aot_deinstantiate((AOTModuleInstance*)module_inst); + aot_deinstantiate((AOTModuleInstance*)module_inst, is_sub_inst); return; } #endif } +void +wasm_runtime_deinstantiate(WASMModuleInstanceCommon *module_inst) +{ + return wasm_runtime_deinstantiate_internal(module_inst, false); +} + WASMExecEnv * wasm_runtime_create_exec_env(WASMModuleInstanceCommon *module_inst, uint32 stack_size) @@ -1442,6 +1533,24 @@ wasm_runtime_set_wasi_ctx(WASMModuleInstanceCommon *module_inst, } #endif /* end of WASM_ENABLE_LIBC_WASI */ +WASMModuleCommon* +wasm_exec_env_get_module(WASMExecEnv *exec_env) +{ + WASMModuleInstanceCommon *module_inst = + wasm_runtime_get_module_inst(exec_env); +#if WASM_ENABLE_INTERP != 0 + if (module_inst->module_type == Wasm_Module_Bytecode) + return (WASMModuleCommon*) + ((WASMModuleInstance*)module_inst)->module; +#endif +#if WASM_ENABLE_AOT != 0 + if (module_inst->module_type == Wasm_Module_AoT) + return (WASMModuleCommon*) + ((AOTModuleInstance*)module_inst)->aot_module.ptr; +#endif + return NULL; +} + /** * Implementation of wasm_application_execute_main() */ diff --git a/core/iwasm/common/wasm_runtime_common.h b/core/iwasm/common/wasm_runtime_common.h index 97db71f8e..91532bfd6 100644 --- a/core/iwasm/common/wasm_runtime_common.h +++ b/core/iwasm/common/wasm_runtime_common.h @@ -105,6 +105,17 @@ wasm_runtime_load_from_sections(WASMSection *section_list, bool is_aot, void wasm_runtime_unload(WASMModuleCommon *module); +/* Internal API */ +WASMModuleInstanceCommon * +wasm_runtime_instantiate_internal(WASMModuleCommon *module, bool is_sub_inst, + uint32 stack_size, uint32 heap_size, + char *error_buf, uint32 error_buf_size); + +/* Internal API */ +void +wasm_runtime_deinstantiate_internal(WASMModuleInstanceCommon *module_inst, + bool is_sub_inst); + /* See wasm_export.h for description */ WASMModuleInstanceCommon * wasm_runtime_instantiate(WASMModuleCommon *module, @@ -319,6 +330,16 @@ wasm_runtime_destroy_loading_module_list(); bool wasm_runtime_is_built_in_module(const char *module_name); +#if WASM_ENABLE_THREAD_MGR != 0 +bool +wasm_exec_env_get_aux_stack(WASMExecEnv *exec_env, + uint32 *start_offset, uint32 *size); + +bool +wasm_exec_env_set_aux_stack(WASMExecEnv *exec_env, + uint32 start_offset, uint32 size); +#endif + #if WASM_ENABLE_LIBC_WASI != 0 /* See wasm_export.h for description */ void @@ -356,6 +377,10 @@ wasm_runtime_get_wasi_ctx(WASMModuleInstanceCommon *module_inst); #endif /* end of WASM_ENABLE_LIBC_WASI */ +/* Get module of the current exec_env */ +WASMModuleCommon* +wasm_exec_env_get_module(WASMExecEnv *exec_env); + /** * Enlarge wasm memory data space. * diff --git a/core/iwasm/common/wasm_shared_memory.c b/core/iwasm/common/wasm_shared_memory.c new file mode 100644 index 000000000..5fbfe50fe --- /dev/null +++ b/core/iwasm/common/wasm_shared_memory.c @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#if WASM_ENABLE_SHARED_MEMORY != 0 + +#include "bh_log.h" +#include "wasm_shared_memory.h" + +static bh_list shared_memory_list_head; +static bh_list *const shared_memory_list = &shared_memory_list_head; +static korp_mutex shared_memory_list_lock; + +bool +wasm_shared_memory_init() +{ + if (os_mutex_init(&shared_memory_list_lock) != 0) + return false; + return true; +} + +void +wasm_shared_memory_destroy() +{ + os_mutex_destroy(&shared_memory_list_lock); +} + +static WASMSharedMemNode* +search_module(WASMModuleCommon *module) +{ + WASMSharedMemNode *node; + + os_mutex_lock(&shared_memory_list_lock); + node = bh_list_first_elem(shared_memory_list); + + while (node) { + if (module == node->module) { + os_mutex_unlock(&shared_memory_list_lock); + return node; + } + node = bh_list_elem_next(node); + } + + os_mutex_unlock(&shared_memory_list_lock); + return NULL; +} + +WASMSharedMemNode* +wasm_module_get_shared_memory(WASMModuleCommon *module) +{ + return search_module(module); +} + +int32 +shared_memory_inc_reference(WASMModuleCommon *module) +{ + WASMSharedMemNode *node = search_module(module); + if (node) { + os_mutex_lock(&node->lock); + node->ref_count++; + os_mutex_unlock(&node->lock); + return node->ref_count; + } + return -1; +} + +int32 +shared_memory_dec_reference(WASMModuleCommon *module) +{ + WASMSharedMemNode *node = search_module(module); + uint32 ref_count = 0; + if (node) { + os_mutex_lock(&node->lock); + ref_count = --node->ref_count; + os_mutex_unlock(&node->lock); + if (ref_count == 0) { + os_mutex_lock(&shared_memory_list_lock); + bh_list_remove(shared_memory_list, node); + os_mutex_unlock(&shared_memory_list_lock); + + os_mutex_destroy(&node->lock); + wasm_runtime_free(node); + } + return ref_count; + } + + return -1; +} + +WASMMemoryInstance* +shared_memory_get_memory_inst(WASMSharedMemNode *node) +{ + return node->u.wasm_memory; +} + +WASMSharedMemNode* +shared_memory_set_memory_inst(WASMModuleCommon *module, + WASMMemoryInstance *memory) +{ + WASMSharedMemNode *node; + bh_list_status ret; + + if (!(node = wasm_runtime_malloc(sizeof(WASMSharedMemNode)))) + return NULL; + + node->module = module; + node->u.wasm_memory = memory; + node->ref_count = 1; + if (os_mutex_init(&node->lock) != 0) { + wasm_runtime_free(node); + return NULL; + } + + os_mutex_lock(&shared_memory_list_lock); + ret = bh_list_insert(shared_memory_list, node); + bh_assert(ret == BH_LIST_SUCCESS); + os_mutex_unlock(&shared_memory_list_lock); + + (void)ret; + return node; +} + +#endif /* end of WASM_ENABLE_SHARED_MEMORY */ diff --git a/core/iwasm/common/wasm_shared_memory.h b/core/iwasm/common/wasm_shared_memory.h new file mode 100644 index 000000000..aed6d10e1 --- /dev/null +++ b/core/iwasm/common/wasm_shared_memory.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _WASM_SHARED_MEMORY_H +#define _WASM_SHARED_MEMORY_H + +#include "bh_common.h" +#if WASM_ENABLE_INTERP != 0 +#include "wasm_runtime.h" +#endif +#if WASM_ENABLE_AOT != 0 +#include "aot_runtime.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct WASMSharedMemNode { + bh_list_link l; + /* Lock */ + korp_mutex lock; + /* The module reference */ + WASMModuleCommon *module; + /* The memory information */ + union { +#if WASM_ENABLE_INTERP + WASMMemoryInstance *wasm_memory; +#endif +#if WASM_ENABLE_AOT + struct { + /* memory space info */ + uint32 mem_cur_page_count; + uint32 mem_max_page_count; + uint32 memory_data_size; + AOTPointer memory_data; + AOTPointer memory_data_end; + + /* heap space info */ + int32 heap_base_offset; + uint32 heap_data_size; + AOTPointer heap_data; + AOTPointer heap_data_end; + AOTPointer heap_handle; + } aot_memory; +#endif + } u; + + /* reference count */ + uint32 ref_count; +} WASMSharedMemNode; + +bool +wasm_shared_memory_init(); + +void +wasm_shared_memory_destroy(); + +WASMSharedMemNode* +wasm_module_get_shared_memory(WASMModuleCommon *module); + +int32 +shared_memory_inc_reference(WASMModuleCommon *module); + +int32 +shared_memory_dec_reference(WASMModuleCommon *module); + +WASMMemoryInstance* +shared_memory_get_memory_inst(WASMSharedMemNode *node); + +WASMSharedMemNode* +shared_memory_set_memory_inst(WASMModuleCommon *module, + WASMMemoryInstance *memory); + + +#ifdef __cplusplus +} +#endif + +#endif /* end of _WASM_SHARED_MEMORY_H */ diff --git a/core/iwasm/include/wasm_export.h b/core/iwasm/include/wasm_export.h index f9659a2e8..8c4ff9271 100644 --- a/core/iwasm/include/wasm_export.h +++ b/core/iwasm/include/wasm_export.h @@ -319,7 +319,7 @@ wasm_runtime_lookup_wasi_start_function(wasm_module_inst_t module_inst); * @param name the name of the function * @param signature the signature of the function, ignored currently * - * @return the function instance found. Otherwise NULL will be returned. + * @return the function instance found, NULL if not found */ wasm_function_inst_t wasm_runtime_lookup_function(wasm_module_inst_t const module_inst, @@ -331,7 +331,8 @@ wasm_runtime_lookup_function(wasm_module_inst_t const module_inst, * @param module_inst the module instance * @param stack_size the stack size to execute a WASM function * - * @return the execution environment. In case of invalid stack size, NULL will be returned. + * @return the execution environment, NULL if failed, e.g. invalid + * stack size is passed */ wasm_exec_env_t wasm_runtime_create_exec_env(wasm_module_inst_t module_inst, @@ -386,7 +387,7 @@ wasm_runtime_call_wasm(wasm_exec_env_t exec_env, * @param argv the arguments array * * @return true if the main function is called, false otherwise and exception - * will be thrown, the caller can call wasm_runtime_get_exception to get + * will be thrown, the caller can call wasm_runtime_get_exception to get * the exception info. */ bool @@ -679,6 +680,16 @@ wasm_runtime_set_user_data(wasm_exec_env_t exec_env, void * wasm_runtime_get_user_data(wasm_exec_env_t exec_env); +#if WASM_ENABLE_THREAD_MGR != 0 +/** + * Set the max thread num per cluster. + * + * @param num maximum thread num + */ +void +wasm_runtime_set_max_thread_num(uint32_t num); +#endif + #ifdef __cplusplus } #endif diff --git a/core/iwasm/interpreter/wasm_interp_classic.c b/core/iwasm/interpreter/wasm_interp_classic.c index 56e95fce5..02914f7f0 100644 --- a/core/iwasm/interpreter/wasm_interp_classic.c +++ b/core/iwasm/interpreter/wasm_interp_classic.c @@ -939,6 +939,18 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst, } #endif +#if WASM_ENABLE_THREAD_MGR != 0 +#define CHECK_SUSPEND_FLAGS() do { \ + if (exec_env->suspend_flags != 0) { \ + if (exec_env->suspend_flags & 0x01) { \ + /* terminate current thread */ \ + return; \ + } \ + /* TODO: support suspend and breakpoint */ \ + } \ + } while (0) +#endif + #if WASM_ENABLE_LABELS_AS_VALUES != 0 #define HANDLE_OP(opcode) HANDLE_##opcode @@ -989,6 +1001,13 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, uint32 local_idx, local_offset, global_idx; uint8 local_type, *global_addr; uint32 cache_index; + int32 aux_stack_top_global_idx = -1; + + /* If the aux stack information is resolved, + we will check the aux stack boundary */ + if (module->module->llvm_aux_stack_size) { + aux_stack_top_global_idx = module->module->llvm_aux_stack_global_index; + } #if WASM_ENABLE_LABELS_AS_VALUES != 0 #define HANDLE_OPCODE(op) &&HANDLE_##op @@ -1103,11 +1122,17 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP_END (); HANDLE_OP (WASM_OP_BR): +#if WASM_ENABLE_THREAD_MGR != 0 + CHECK_SUSPEND_FLAGS(); +#endif read_leb_uint32(frame_ip, frame_ip_end, depth); POP_CSP_N(depth); HANDLE_OP_END (); HANDLE_OP (WASM_OP_BR_IF): +#if WASM_ENABLE_THREAD_MGR != 0 + CHECK_SUSPEND_FLAGS(); +#endif read_leb_uint32(frame_ip, frame_ip_end, depth); cond = (uint32)POP_I32(); if (cond) @@ -1115,6 +1140,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP_END (); HANDLE_OP (WASM_OP_BR_TABLE): +#if WASM_ENABLE_THREAD_MGR != 0 + CHECK_SUSPEND_FLAGS(); +#endif read_leb_uint32(frame_ip, frame_ip_end, count); if (count <= BR_TABLE_TMP_BUF_LEN) depths = depth_buf; @@ -1150,6 +1178,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, goto return_func; HANDLE_OP (WASM_OP_CALL): +#if WASM_ENABLE_THREAD_MGR != 0 + CHECK_SUSPEND_FLAGS(); +#endif read_leb_uint32(frame_ip, frame_ip_end, fidx); #if WASM_ENABLE_MULTI_MODULE != 0 if (fidx >= module->function_count) { @@ -1166,6 +1197,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, WASMType *cur_type, *cur_func_type; WASMTableInstance *cur_table_inst; +#if WASM_ENABLE_THREAD_MGR != 0 + CHECK_SUSPEND_FLAGS(); +#endif + /** * type check. compiler will make sure all like * (call_indirect (type $x) (i32.const 1)) @@ -1406,6 +1441,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, switch (global->type) { case VALUE_TYPE_I32: + /* Check aux stack boundary */ + if ((global_idx == (uint32)aux_stack_top_global_idx) + && (*(uint32*)(frame_sp - 1) < exec_env->aux_stack_boundary)) + goto out_of_bounds; case VALUE_TYPE_F32: *(int32*)global_addr = POP_I32(); break; diff --git a/core/iwasm/interpreter/wasm_interp_fast.c b/core/iwasm/interpreter/wasm_interp_fast.c index 02d0ee573..7f8ee8457 100644 --- a/core/iwasm/interpreter/wasm_interp_fast.c +++ b/core/iwasm/interpreter/wasm_interp_fast.c @@ -877,6 +877,18 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst, } #endif +#if WASM_ENABLE_THREAD_MGR != 0 +#define CHECK_SUSPEND_FLAGS() do { \ + if (exec_env->suspend_flags != 0) { \ + if (exec_env->suspend_flags & 0x01) { \ + /* terminate current thread */ \ + return; \ + } \ + /* TODO: support suspend and breakpoint */ \ + } \ + } while (0) +#endif + #if WASM_ENABLE_OPCODE_COUNTER != 0 typedef struct OpcodeInfo { char *name; @@ -978,6 +990,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, uint8 *maddr = NULL; uint32 local_idx, local_offset, global_idx; uint8 opcode, local_type, *global_addr; + int32 aux_stack_top_global_idx = -1; #if WASM_ENABLE_LABELS_AS_VALUES != 0 #define HANDLE_OPCODE(op) &&HANDLE_##op @@ -991,6 +1004,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, #endif #endif + /* If the aux stack information is resolved, + we will check the aux stack boundary */ + if (module->module->llvm_aux_stack_size) { + aux_stack_top_global_idx = module->module->llvm_aux_stack_global_index; + } + #if WASM_ENABLE_LABELS_AS_VALUES == 0 while (frame_ip < frame_ip_end) { opcode = *frame_ip++; @@ -1024,10 +1043,16 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP_END (); HANDLE_OP (WASM_OP_BR): +#if WASM_ENABLE_THREAD_MGR != 0 + CHECK_SUSPEND_FLAGS(); +#endif RECOVER_BR_INFO(); HANDLE_OP_END (); HANDLE_OP (WASM_OP_BR_IF): +#if WASM_ENABLE_THREAD_MGR != 0 + CHECK_SUSPEND_FLAGS(); +#endif cond = frame_lp[GET_OFFSET()]; if (cond) @@ -1039,6 +1064,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP_END (); HANDLE_OP (WASM_OP_BR_TABLE): +#if WASM_ENABLE_THREAD_MGR != 0 + CHECK_SUSPEND_FLAGS(); +#endif count = GET_OPERAND(uint32, 0); didx = GET_OPERAND(uint32, 2); frame_ip += 4; @@ -1064,6 +1092,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, WASMType *cur_type, *cur_func_type; WASMTableInstance *cur_table_inst; +#if WASM_ENABLE_THREAD_MGR != 0 + CHECK_SUSPEND_FLAGS(); +#endif + tidx = GET_OPERAND(int32, 0); val = GET_OPERAND(int32, 2); frame_ip += 4; @@ -1245,6 +1277,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, switch (global->type) { case VALUE_TYPE_I32: + /* Check aux stack boundary */ + if ((global_idx == (uint32)aux_stack_top_global_idx) + && (frame_lp[addr1] < exec_env->aux_stack_boundary)) + goto out_of_bounds; case VALUE_TYPE_F32: *(int32*)global_addr = frame_lp[addr1]; break; @@ -2482,6 +2518,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, goto call_func_from_entry; HANDLE_OP (WASM_OP_CALL): +#if WASM_ENABLE_THREAD_MGR != 0 + CHECK_SUSPEND_FLAGS(); +#endif fidx = frame_lp[GET_OFFSET()]; #if WASM_ENABLE_MULTI_MODULE != 0 if (fidx >= module->function_count) { diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index 34400822b..26491578b 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -1117,6 +1117,12 @@ load_table(const uint8 **p_buf, const uint8 *buf_end, WASMTable *table, else table->max_size = 0x10000; + if ((table->flags & 1) && table->init_size > table->max_size) { + set_error_buf(error_buf, error_buf_size, + "size minimum must not be greater than maximum"); + return false; + } + *p_buf = p; return true; } @@ -2349,8 +2355,6 @@ load_from_sections(WASMModule *module, WASMSection *sections, WASMGlobal *llvm_stack_top_global = NULL, *global; uint32 llvm_data_end = UINT32_MAX, llvm_heap_base = UINT32_MAX; uint32 llvm_stack_top = UINT32_MAX, global_index, i; - uint32 data_end_global_index = UINT32_MAX; - uint32 heap_base_global_index = UINT32_MAX; uint32 stack_top_global_index = UINT32_MAX; BlockAddr *block_addr_cache; uint64 total_size; @@ -2462,67 +2466,93 @@ load_from_sections(WASMModule *module, WASMSection *sections, wasm_runtime_free(block_addr_cache); /* Resolve llvm auxiliary data/stack/heap info and reset memory info */ - if (!module->possible_memory_grow) { - export = module->exports; - for (i = 0; i < module->export_count; i++, export++) { - if (export->kind == EXPORT_KIND_GLOBAL) { - if (!strcmp(export->name, "__heap_base")) { - global_index = export->index - module->import_global_count; - global = module->globals + global_index; - if (global->type == VALUE_TYPE_I32 - && !global->is_mutable - && global->init_expr.init_expr_type == - INIT_EXPR_TYPE_I32_CONST) { - heap_base_global_index = global_index; - llvm_heap_base_global = global; - llvm_heap_base = global->init_expr.u.i32; - LOG_VERBOSE("found llvm __heap_base global, value: %d\n", - llvm_heap_base); - } - } - else if (!strcmp(export->name, "__data_end")) { - global_index = export->index - module->import_global_count; - global = module->globals + global_index; - if (global->type == VALUE_TYPE_I32 - && !global->is_mutable - && global->init_expr.init_expr_type == - INIT_EXPR_TYPE_I32_CONST) { - data_end_global_index = global_index; - llvm_data_end_global = global; - llvm_data_end = global->init_expr.u.i32; - LOG_VERBOSE("found llvm __data_end global, value: %d\n", - llvm_data_end); - - llvm_data_end = align_uint(llvm_data_end, 16); - } - } - - if (llvm_data_end_global && llvm_heap_base_global) { - if ((data_end_global_index == heap_base_global_index + 1 - && (int32)data_end_global_index > 1) - || (heap_base_global_index == data_end_global_index + 1 - && (int32)heap_base_global_index > 1)) { - global_index = - data_end_global_index < heap_base_global_index - ? data_end_global_index - 1 : heap_base_global_index - 1; - global = module->globals + global_index; - if (global->type == VALUE_TYPE_I32 - && global->is_mutable - && global->init_expr.init_expr_type == - INIT_EXPR_TYPE_I32_CONST) { - llvm_stack_top_global = global; - llvm_stack_top = global->init_expr.u.i32; - stack_top_global_index = global_index; - LOG_VERBOSE("found llvm stack top global, " - "value: %d, global index: %d\n", - llvm_stack_top, global_index); - } - } - break; + export = module->exports; + for (i = 0; i < module->export_count; i++, export++) { + if (export->kind == EXPORT_KIND_GLOBAL) { + if (!strcmp(export->name, "__heap_base")) { + global_index = export->index - module->import_global_count; + global = module->globals + global_index; + if (global->type == VALUE_TYPE_I32 + && !global->is_mutable + && global->init_expr.init_expr_type == + INIT_EXPR_TYPE_I32_CONST) { + llvm_heap_base_global = global; + llvm_heap_base = global->init_expr.u.i32; + LOG_VERBOSE("found llvm __heap_base global, value: %d\n", + llvm_heap_base); } } - } + else if (!strcmp(export->name, "__data_end")) { + global_index = export->index - module->import_global_count; + global = module->globals + global_index; + if (global->type == VALUE_TYPE_I32 + && !global->is_mutable + && global->init_expr.init_expr_type == + INIT_EXPR_TYPE_I32_CONST) { + llvm_data_end_global = global; + llvm_data_end = global->init_expr.u.i32; + LOG_VERBOSE("found llvm __data_end global, value: %d\n", + llvm_data_end); + llvm_data_end = align_uint(llvm_data_end, 16); + } + } + + /* For module compiled with -pthread option, the global is: + [0] stack_top <-- 0 + [1] tls_pointer + [2] tls_size + [3] data_end <-- 3 + [4] global_base + [5] heap_base <-- 5 + [6] dso_handle + + For module compiled without -pthread option: + [0] stack_top <-- 0 + [1] data_end <-- 1 + [2] global_base + [3] heap_base <-- 3 + [4] dso_handle + */ + if (llvm_data_end_global && llvm_heap_base_global) { + /* Resolve aux stack top global */ + for (global_index = 0; global_index < module->global_count; global_index++) { + global = module->globals + global_index; + if (global != llvm_data_end_global + && global != llvm_heap_base_global + && global->type == VALUE_TYPE_I32 + && global->is_mutable + && global->init_expr.init_expr_type == + INIT_EXPR_TYPE_I32_CONST + && (global->init_expr.u.i32 == + llvm_heap_base_global->init_expr.u.i32 + || global->init_expr.u.i32 == + llvm_data_end_global->init_expr.u.i32)) { + llvm_stack_top_global = global; + llvm_stack_top = global->init_expr.u.i32; + stack_top_global_index = global_index; + LOG_VERBOSE("found llvm stack top global, " + "value: %d, global index: %d\n", + llvm_stack_top, global_index); + break; + } + } + + module->llvm_aux_data_end = llvm_data_end; + module->llvm_aux_stack_bottom = llvm_stack_top; + module->llvm_aux_stack_size = llvm_stack_top > llvm_data_end + ? llvm_stack_top - llvm_data_end + : llvm_stack_top; + module->llvm_aux_stack_global_index = stack_top_global_index; + LOG_VERBOSE("aux stack bottom: %d, size: %d\n", + module->llvm_aux_stack_bottom, + module->llvm_aux_stack_size); + break; + } + } + } + + if (!module->possible_memory_grow) { if (llvm_data_end_global && llvm_heap_base_global && llvm_stack_top_global @@ -2557,16 +2587,6 @@ load_from_sections(WASMModule *module, WASMSection *sections, LOG_VERBOSE("reset memory size to %d\n", shrunk_memory_size); } } - - module->llvm_aux_data_end = llvm_data_end; - module->llvm_aux_stack_bottom = llvm_stack_top; - module->llvm_aux_stack_size = llvm_stack_top > llvm_data_end - ? llvm_stack_top - llvm_data_end - : llvm_stack_top; - module->llvm_aux_stack_global_index = stack_top_global_index; - LOG_VERBOSE("aux stack bottom: %d, size: %d\n", - module->llvm_aux_stack_bottom, - module->llvm_aux_stack_size); } } @@ -3485,6 +3505,7 @@ fail: return false; } + static bool check_stack_top_values(uint8 *frame_ref, int32 stack_cell_num, uint8 type, char *error_buf, uint32 error_buf_size) diff --git a/core/iwasm/interpreter/wasm_mini_loader.c b/core/iwasm/interpreter/wasm_mini_loader.c index 00299f7c7..dd7f2285c 100644 --- a/core/iwasm/interpreter/wasm_mini_loader.c +++ b/core/iwasm/interpreter/wasm_mini_loader.c @@ -1545,67 +1545,76 @@ load_from_sections(WASMModule *module, WASMSection *sections, wasm_runtime_free(block_addr_cache); /* Resolve llvm auxiliary data/stack/heap info and reset memory info */ - if (!module->possible_memory_grow) { - export = module->exports; - for (i = 0; i < module->export_count; i++, export++) { - if (export->kind == EXPORT_KIND_GLOBAL) { - if (!strcmp(export->name, "__heap_base")) { - global_index = export->index - module->import_global_count; - global = module->globals + global_index; - if (global->type == VALUE_TYPE_I32 - && !global->is_mutable - && global->init_expr.init_expr_type == - INIT_EXPR_TYPE_I32_CONST) { - heap_base_global_index = global_index; - llvm_heap_base_global = global; - llvm_heap_base = global->init_expr.u.i32; - LOG_VERBOSE("found llvm __heap_base global, value: %d\n", - llvm_heap_base); - } - } - else if (!strcmp(export->name, "__data_end")) { - global_index = export->index - module->import_global_count; - global = module->globals + global_index; - if (global->type == VALUE_TYPE_I32 - && !global->is_mutable - && global->init_expr.init_expr_type == - INIT_EXPR_TYPE_I32_CONST) { - data_end_global_index = global_index; - llvm_data_end_global = global; - llvm_data_end = global->init_expr.u.i32; - LOG_VERBOSE("found llvm __data_end global, value: %d\n", - llvm_data_end); - - llvm_data_end = align_uint(llvm_data_end, 16); - } - } - - if (llvm_data_end_global && llvm_heap_base_global) { - if ((data_end_global_index == heap_base_global_index + 1 - && (int32)data_end_global_index > 1) - || (heap_base_global_index == data_end_global_index + 1 - && (int32)heap_base_global_index > 1)) { - global_index = - data_end_global_index < heap_base_global_index - ? data_end_global_index - 1 : heap_base_global_index - 1; - global = module->globals + global_index; - if (global->type == VALUE_TYPE_I32 - && global->is_mutable - && global->init_expr.init_expr_type == - INIT_EXPR_TYPE_I32_CONST) { - llvm_stack_top_global = global; - llvm_stack_top = global->init_expr.u.i32; - stack_top_global_index = global_index; - LOG_VERBOSE("found llvm stack top global, " - "value: %d, global index: %d\n", - llvm_stack_top, global_index); - } - } - break; + export = module->exports; + for (i = 0; i < module->export_count; i++, export++) { + if (export->kind == EXPORT_KIND_GLOBAL) { + if (!strcmp(export->name, "__heap_base")) { + global_index = export->index - module->import_global_count; + global = module->globals + global_index; + if (global->type == VALUE_TYPE_I32 + && !global->is_mutable + && global->init_expr.init_expr_type == + INIT_EXPR_TYPE_I32_CONST) { + heap_base_global_index = global_index; + llvm_heap_base_global = global; + llvm_heap_base = global->init_expr.u.i32; + LOG_VERBOSE("found llvm __heap_base global, value: %d\n", + llvm_heap_base); } } - } + else if (!strcmp(export->name, "__data_end")) { + global_index = export->index - module->import_global_count; + global = module->globals + global_index; + if (global->type == VALUE_TYPE_I32 + && !global->is_mutable + && global->init_expr.init_expr_type == + INIT_EXPR_TYPE_I32_CONST) { + data_end_global_index = global_index; + llvm_data_end_global = global; + llvm_data_end = global->init_expr.u.i32; + LOG_VERBOSE("found llvm __data_end global, value: %d\n", + llvm_data_end); + llvm_data_end = align_uint(llvm_data_end, 16); + } + } + + if (llvm_data_end_global && llvm_heap_base_global) { + if ((data_end_global_index == heap_base_global_index + 1 + && (int32)data_end_global_index > 1) + || (heap_base_global_index == data_end_global_index + 1 + && (int32)heap_base_global_index > 1)) { + global_index = + data_end_global_index < heap_base_global_index + ? data_end_global_index - 1 : heap_base_global_index - 1; + global = module->globals + global_index; + if (global->type == VALUE_TYPE_I32 + && global->is_mutable + && global->init_expr.init_expr_type == + INIT_EXPR_TYPE_I32_CONST) { + llvm_stack_top_global = global; + llvm_stack_top = global->init_expr.u.i32; + stack_top_global_index = global_index; + LOG_VERBOSE("found llvm stack top global, " + "value: %d, global index: %d\n", + llvm_stack_top, global_index); + } + } + module->llvm_aux_data_end = llvm_data_end; + module->llvm_aux_stack_bottom = llvm_stack_top; + module->llvm_aux_stack_size = llvm_stack_top > llvm_data_end + ? llvm_stack_top - llvm_data_end + : llvm_stack_top; + module->llvm_aux_stack_global_index = stack_top_global_index; + LOG_VERBOSE("aux stack bottom: %d, size: %d\n", + module->llvm_aux_stack_bottom, + module->llvm_aux_stack_size); + break; + } + } + } + + if (!module->possible_memory_grow) { if (llvm_data_end_global && llvm_heap_base_global && llvm_stack_top_global @@ -1640,16 +1649,6 @@ load_from_sections(WASMModule *module, WASMSection *sections, LOG_VERBOSE("reset memory size to %d\n", shrunk_memory_size); } } - - module->llvm_aux_data_end = llvm_data_end; - module->llvm_aux_stack_bottom = llvm_stack_top; - module->llvm_aux_stack_size = llvm_stack_top > llvm_data_end - ? llvm_stack_top - llvm_data_end - : llvm_stack_top; - module->llvm_aux_stack_global_index = stack_top_global_index; - LOG_VERBOSE("aux stack bottom: %d, size: %d\n", - module->llvm_aux_stack_bottom, - module->llvm_aux_stack_size); } } diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index 827691d2e..4ea874e4e 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -10,6 +10,9 @@ #include "bh_log.h" #include "mem_alloc.h" #include "../common/wasm_runtime_common.h" +#if WASM_ENABLE_SHARED_MEMORY != 0 +#include "../common/wasm_shared_memory.h" +#endif static void set_error_buf(char *error_buf, uint32 error_buf_size, const char *string) @@ -86,6 +89,19 @@ memories_deinstantiate(WASMModuleInstance *module_inst, #if WASM_ENABLE_MULTI_MODULE != 0 if (memories[i]->owner != module_inst) continue; +#endif +#if WASM_ENABLE_SHARED_MEMORY != 0 + if (memories[i]->is_shared) { + int32 ref_count = + shared_memory_dec_reference( + (WASMModuleCommon *)module_inst->module); + bh_assert(ref_count >= 0); + + /* if the reference count is not zero, + don't free the memory */ + if (ref_count > 0) + continue; + } #endif if (memories[i]->heap_handle) { mem_allocator_destroy(memories[i]->heap_handle); @@ -99,16 +115,45 @@ memories_deinstantiate(WASMModuleInstance *module_inst, } static WASMMemoryInstance* -memory_instantiate(uint32 num_bytes_per_page, +memory_instantiate(WASMModuleInstance *module_inst, + uint32 num_bytes_per_page, uint32 init_page_count, uint32 max_page_count, - uint32 heap_size, + uint32 heap_size, uint32 flags, char *error_buf, uint32 error_buf_size) { WASMMemoryInstance *memory; - uint64 total_size = offsetof(WASMMemoryInstance, base_addr) + - (uint64)heap_size + + uint64 heap_and_inst_size = offsetof(WASMMemoryInstance, base_addr) + + (uint64)heap_size; + uint64 total_size = heap_and_inst_size + num_bytes_per_page * (uint64)init_page_count; +#if WASM_ENABLE_SHARED_MEMORY != 0 + bool is_shared_memory = flags & 0x02 ? true : false; + + /* shared memory */ + if (is_shared_memory) { + WASMSharedMemNode *node = + wasm_module_get_shared_memory( + (WASMModuleCommon *)module_inst->module); + /* If the memory of this module has been instantiated, + return the memory instance directly */ + if (node) { + uint32 ref_count; + ref_count = shared_memory_inc_reference( + (WASMModuleCommon *)module_inst->module); + bh_assert(ref_count > 0); + memory = shared_memory_get_memory_inst(node); + bh_assert(memory); + + (void)ref_count; + return memory; + } + /* Allocate max page for shared memory */ + total_size = heap_and_inst_size + + num_bytes_per_page * (uint64)max_page_count; + } +#endif + /* Allocate memory space, addr data and global data */ if (!(memory = runtime_malloc(total_size, error_buf, error_buf_size))) { @@ -121,8 +166,17 @@ memory_instantiate(uint32 num_bytes_per_page, memory->heap_data = memory->base_addr; memory->memory_data = memory->heap_data + heap_size; - memory->end_addr = memory->memory_data + - num_bytes_per_page * memory->cur_page_count; +#if WASM_ENABLE_SHARED_MEMORY != 0 + if (is_shared_memory) { + memory->end_addr = memory->memory_data + + num_bytes_per_page * memory->max_page_count; + } + else +#endif + { + memory->end_addr = memory->memory_data + + num_bytes_per_page * memory->cur_page_count; + } bh_assert(memory->end_addr - (uint8*)memory == (uint32)total_size); @@ -134,10 +188,20 @@ memory_instantiate(uint32 num_bytes_per_page, return NULL; } -#if WASM_ENABLE_SPEC_TEST == 0 memory->heap_base_offset = -(int32)heap_size; -#else - memory->heap_base_offset = 0; + +#if WASM_ENABLE_SHARED_MEMORY != 0 + if (is_shared_memory) { + memory->is_shared = true; + if (!shared_memory_set_memory_inst( + (WASMModuleCommon *)module_inst->module, memory)) { + set_error_buf(error_buf, error_buf_size, + "Instantiate memory failed:" + "allocate memory failed."); + wasm_runtime_free(memory); + return NULL; + } + } #endif return memory; } @@ -169,6 +233,7 @@ memories_instantiate(const WASMModule *module, uint32 num_bytes_per_page = import->u.memory.num_bytes_per_page; uint32 init_page_count = import->u.memory.init_page_count; uint32 max_page_count = import->u.memory.max_page_count; + uint32 flags = import->u.memory.flags; uint32 actual_heap_size = heap_size; #if WASM_ENABLE_MULTI_MODULE != 0 @@ -197,8 +262,9 @@ memories_instantiate(const WASMModule *module, #endif { if (!(memory = memories[mem_index++] = memory_instantiate( - num_bytes_per_page, init_page_count, max_page_count, - actual_heap_size, error_buf, error_buf_size))) { + module_inst, num_bytes_per_page, init_page_count, + max_page_count, actual_heap_size, flags, + error_buf, error_buf_size))) { set_error_buf(error_buf, error_buf_size, "Instantiate memory failed: " "allocate memory failed."); @@ -213,10 +279,12 @@ memories_instantiate(const WASMModule *module, /* instantiate memories from memory section */ for (i = 0; i < module->memory_count; i++) { if (!(memory = memories[mem_index++] = - memory_instantiate(module->memories[i].num_bytes_per_page, + memory_instantiate(module_inst, + module->memories[i].num_bytes_per_page, module->memories[i].init_page_count, module->memories[i].max_page_count, - heap_size, error_buf, error_buf_size))) { + heap_size, module->memories[i].flags, + error_buf, error_buf_size))) { set_error_buf(error_buf, error_buf_size, "Instantiate memory failed: " "allocate memory failed."); @@ -236,7 +304,7 @@ memories_instantiate(const WASMModule *module, * for wasm code */ if (!(memory = memories[mem_index++] = - memory_instantiate(0, 0, 0, heap_size, + memory_instantiate(module_inst, 0, 0, 0, heap_size, 0, error_buf, error_buf_size))) { set_error_buf(error_buf, error_buf_size, "Instantiate memory failed: " @@ -792,6 +860,36 @@ execute_post_inst_function(WASMModuleInstance *module_inst) 0, NULL); } +#if WASM_ENABLE_BULK_MEMORY != 0 +static bool +execute_memory_init_function(WASMModuleInstance *module_inst) +{ + WASMFunctionInstance *memory_init_func = NULL; + WASMType *memory_init_func_type; + uint32 i; + + for (i = 0; i < module_inst->export_func_count; i++) + if (!strcmp(module_inst->export_functions[i].name, "__wasm_call_ctors")) { + memory_init_func = module_inst->export_functions[i].function; + break; + } + + if (!memory_init_func) + /* Not found */ + return true; + + memory_init_func_type = memory_init_func->u.func->func_type; + if (memory_init_func_type->param_count != 0 + || memory_init_func_type->result_count != 0) + /* Not a valid function type, ignore it */ + return true; + + return wasm_create_exec_env_and_call_function(module_inst, + memory_init_func, + 0, NULL); +} +#endif + static bool execute_start_function(WASMModuleInstance *module_inst) { @@ -819,7 +917,7 @@ sub_module_instantiate(WASMModule *module, WASMModuleInstance *module_inst, while (sub_module_list_node) { WASMModule *sub_module = (WASMModule*)sub_module_list_node->module; WASMModuleInstance *sub_module_inst = wasm_instantiate( - sub_module, stack_size, heap_size, error_buf, error_buf_size); + sub_module, false, stack_size, heap_size, error_buf, error_buf_size); if (!sub_module_inst) { LOG_DEBUG("instantiate %s failed", sub_module_list_node->module_name); @@ -833,7 +931,7 @@ sub_module_instantiate(WASMModule *module, WASMModuleInstance *module_inst, if (!sub_module_inst_list_node) { LOG_DEBUG("Malloc WASMSubModInstNode failed, SZ:%d", sizeof(WASMSubModInstNode)); - wasm_deinstantiate(sub_module_inst); + wasm_deinstantiate(sub_module_inst, false); return false; } @@ -859,7 +957,7 @@ sub_module_deinstantiate(WASMModuleInstance *module_inst) while (node) { WASMSubModInstNode *next_node = bh_list_elem_next(node); bh_list_remove(list, node); - wasm_deinstantiate(node->module_inst); + wasm_deinstantiate(node->module_inst, false); node = next_node; } } @@ -869,7 +967,7 @@ sub_module_deinstantiate(WASMModuleInstance *module_inst) * Instantiate module */ WASMModuleInstance* -wasm_instantiate(WASMModule *module, +wasm_instantiate(WASMModule *module, bool is_sub_inst, uint32 stack_size, uint32 heap_size, char *error_buf, uint32 error_buf_size) { @@ -887,10 +985,6 @@ wasm_instantiate(WASMModule *module, /* Check heap size */ heap_size = align_uint(heap_size, 8); - if (heap_size == 0) - heap_size = APP_HEAP_SIZE_DEFAULT; - if (heap_size < APP_HEAP_SIZE_MIN) - heap_size = APP_HEAP_SIZE_MIN; if (heap_size > APP_HEAP_SIZE_MAX) heap_size = APP_HEAP_SIZE_MAX; @@ -904,6 +998,8 @@ wasm_instantiate(WASMModule *module, memset(module_inst, 0, (uint32)sizeof(WASMModuleInstance)); + module_inst->module = module; + #if WASM_ENABLE_MULTI_MODULE != 0 module_inst->sub_module_inst_list = &module_inst->sub_module_inst_list_head; @@ -911,7 +1007,7 @@ wasm_instantiate(WASMModule *module, error_buf, error_buf_size); if (!ret) { LOG_DEBUG("build a sub module list failed"); - wasm_deinstantiate(module_inst); + wasm_deinstantiate(module_inst, false); return NULL; } #endif @@ -922,7 +1018,7 @@ wasm_instantiate(WASMModule *module, module, module_inst, &global_data_size, error_buf, error_buf_size))) { - wasm_deinstantiate(module_inst); + wasm_deinstantiate(module_inst, false); return NULL; } module_inst->global_count = global_count; @@ -946,7 +1042,7 @@ wasm_instantiate(WASMModule *module, if (global_count > 0) { if (!(module_inst->global_data = runtime_malloc (global_data_size, error_buf, error_buf_size))) { - wasm_deinstantiate(module_inst); + wasm_deinstantiate(module_inst, false); return NULL; } } @@ -978,7 +1074,7 @@ wasm_instantiate(WASMModule *module, error_buf, error_buf_size))) #endif ) { - wasm_deinstantiate(module_inst); + wasm_deinstantiate(module_inst, false); return NULL; } @@ -989,7 +1085,7 @@ wasm_instantiate(WASMModule *module, */ if (!globals_instantiate_fix(globals, module, error_buf, error_buf_size)) { - wasm_deinstantiate(module_inst); + wasm_deinstantiate(module_inst, false); return NULL; } @@ -1063,7 +1159,7 @@ wasm_instantiate(WASMModule *module, memory_size); set_error_buf(error_buf, error_buf_size, "data segment does not fit."); - wasm_deinstantiate(module_inst); + wasm_deinstantiate(module_inst, false); return NULL; } @@ -1075,7 +1171,7 @@ wasm_instantiate(WASMModule *module, set_error_buf( error_buf, error_buf_size, "Instantiate module failed: data segment does not fit."); - wasm_deinstantiate(module_inst); + wasm_deinstantiate(module_inst, false); return NULL; } @@ -1121,7 +1217,7 @@ wasm_instantiate(WASMModule *module, table_seg->base_offset.u.i32, table->cur_size); set_error_buf(error_buf, error_buf_size, "elements segment does not fit"); - wasm_deinstantiate(module_inst); + wasm_deinstantiate(module_inst, false); return NULL; } @@ -1132,7 +1228,7 @@ wasm_instantiate(WASMModule *module, table_seg->base_offset.u.i32, length, table->cur_size); set_error_buf(error_buf, error_buf_size, "elements segment does not fit"); - wasm_deinstantiate(module_inst); + wasm_deinstantiate(module_inst, false); return NULL; } @@ -1149,18 +1245,22 @@ wasm_instantiate(WASMModule *module, } #if WASM_ENABLE_LIBC_WASI != 0 - if (!wasm_runtime_init_wasi((WASMModuleInstanceCommon*)module_inst, - module->wasi_args.dir_list, - module->wasi_args.dir_count, - module->wasi_args.map_dir_list, - module->wasi_args.map_dir_count, - module->wasi_args.env, - module->wasi_args.env_count, - module->wasi_args.argv, - module->wasi_args.argc, - error_buf, error_buf_size)) { - wasm_deinstantiate(module_inst); - return NULL; + /* The sub-instance will get the wasi_ctx from main-instance */ + if (!is_sub_inst) { + if (heap_size > 0 + && !wasm_runtime_init_wasi((WASMModuleInstanceCommon*)module_inst, + module->wasi_args.dir_list, + module->wasi_args.dir_count, + module->wasi_args.map_dir_list, + module->wasi_args.map_dir_count, + module->wasi_args.env, + module->wasi_args.env_count, + module->wasi_args.argv, + module->wasi_args.argc, + error_buf, error_buf_size)) { + wasm_deinstantiate(module_inst, false); + return NULL; + } } #endif @@ -1171,8 +1271,6 @@ wasm_instantiate(WASMModule *module, &module_inst->functions[module->start_function]; } - module_inst->module = module; - /* module instance type */ module_inst->module_type = Wasm_Module_Bytecode; @@ -1190,16 +1288,36 @@ wasm_instantiate(WASMModule *module, || !execute_start_function(module_inst)) { set_error_buf(error_buf, error_buf_size, module_inst->cur_exception); - wasm_deinstantiate(module_inst); + wasm_deinstantiate(module_inst, false); return NULL; } +#if WASM_ENABLE_BULK_MEMORY != 0 +#if WASM_ENABLE_LIBC_WASI != 0 + if (!module->is_wasi_module) { +#endif + /* Only execute the memory init function for main instance because + the data segments will be dropped once initialized. + */ + if (!is_sub_inst) { + if (!execute_memory_init_function(module_inst)) { + set_error_buf(error_buf, error_buf_size, + module_inst->cur_exception); + wasm_deinstantiate(module_inst, false); + return NULL; + } + } +#if WASM_ENABLE_LIBC_WASI != 0 + } +#endif +#endif + (void)global_data_end; return module_inst; } void -wasm_deinstantiate(WASMModuleInstance *module_inst) +wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst) { if (!module_inst) return; @@ -1213,7 +1331,9 @@ wasm_deinstantiate(WASMModuleInstance *module_inst) wasi contex are allocated from app heap, and if app heap is freed, these fields will be set to NULL, we cannot free their internal data which may allocated from global heap. */ - wasm_runtime_destroy_wasi((WASMModuleInstanceCommon*)module_inst); + /* Only destroy wasi ctx in the main module instance */ + if (!is_sub_inst) + wasm_runtime_destroy_wasi((WASMModuleInstanceCommon*)module_inst); #endif if (module_inst->memory_count > 0) @@ -1299,8 +1419,9 @@ wasm_create_exec_env_and_call_function(WASMModuleInstance *module_inst, WASMExecEnv *exec_env; bool ret; - if (!(exec_env = wasm_exec_env_create((WASMModuleInstanceCommon*)module_inst, - module_inst->default_wasm_stack_size))) { + if (!(exec_env = wasm_exec_env_create( + (WASMModuleInstanceCommon*)module_inst, + module_inst->default_wasm_stack_size))) { wasm_set_exception(module_inst, "allocate memory failed."); return false; } @@ -1518,6 +1639,15 @@ wasm_enlarge_memory(WASMModuleInstance *module, uint32 inc_page_count) return false; } +#if WASM_ENABLE_SHARED_MEMORY != 0 + if (memory->is_shared) { + /* For shared memory, we have reserved the maximum spaces during + instantiate, only change the cur_page_count here */ + memory->cur_page_count = total_page_count; + return true; + } +#endif + if (heap_size > 0) { /* Destroy heap's lock firstly, if its memory is re-allocated, we cannot access its lock again. */ @@ -1612,3 +1742,66 @@ wasm_call_indirect(WASMExecEnv *exec_env, got_exception: return false; } + +#if WASM_ENABLE_THREAD_MGR != 0 +bool +wasm_set_aux_stack(WASMExecEnv *exec_env, + uint32 start_offset, uint32 size) +{ + WASMModuleInstance *module_inst = + (WASMModuleInstance*)exec_env->module_inst; + + uint32 stack_top_idx = + module_inst->module->llvm_aux_stack_global_index; + uint32 data_end = + module_inst->module->llvm_aux_data_end; + uint32 stack_bottom = + module_inst->module->llvm_aux_stack_bottom; + bool is_stack_before_data = + stack_bottom < data_end ? true : false; + + /* Check the aux stack space, currently we don't allocate space in heap */ + if ((is_stack_before_data && (size > start_offset)) + || ((!is_stack_before_data) && (start_offset - data_end < size))) + return false; + + if (stack_bottom) { + /* The aux stack top is a wasm global, + set the initial value for the global */ + uint8 *global_addr = + module_inst->global_data + + module_inst->globals[stack_top_idx].data_offset; + *(int32*)global_addr = start_offset; + /* The aux stack boundary is a constant value, + set the value to exec_env */ + exec_env->aux_stack_boundary = start_offset - size; + return true; + } + + return false; +} + +bool +wasm_get_aux_stack(WASMExecEnv *exec_env, + uint32 *start_offset, uint32 *size) +{ + WASMModuleInstance *module_inst = + (WASMModuleInstance*)exec_env->module_inst; + + /* The aux stack information is resolved in loader + and store in module */ + uint32 stack_bottom = + module_inst->module->llvm_aux_stack_bottom; + uint32 total_aux_stack_size = + module_inst->module->llvm_aux_stack_size; + + if (stack_bottom != 0 && total_aux_stack_size != 0) { + if (start_offset) + *start_offset = stack_bottom; + if (size) + *size = total_aux_stack_size; + return true; + } + return false; +} +#endif \ No newline at end of file diff --git a/core/iwasm/interpreter/wasm_runtime.h b/core/iwasm/interpreter/wasm_runtime.h index 6b3882b3e..f8b12c629 100644 --- a/core/iwasm/interpreter/wasm_runtime.h +++ b/core/iwasm/interpreter/wasm_runtime.h @@ -22,6 +22,10 @@ typedef struct WASMTableInstance WASMTableInstance; typedef struct WASMGlobalInstance WASMGlobalInstance; typedef struct WASMMemoryInstance { +#if WASM_ENABLE_SHARED_MEMORY != 0 + /* shared memory flag */ + bool is_shared; +#endif /* Number bytes per page */ uint32 num_bytes_per_page; /* Current page count */ @@ -269,12 +273,12 @@ void wasm_unload(WASMModule *module); WASMModuleInstance * -wasm_instantiate(WASMModule *module, +wasm_instantiate(WASMModule *module, bool is_sub_inst, uint32 stack_size, uint32 heap_size, char *error_buf, uint32 error_buf_size); void -wasm_deinstantiate(WASMModuleInstance *module_inst); +wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst); WASMFunctionInstance * wasm_lookup_function(const WASMModuleInstance *module_inst, @@ -358,6 +362,16 @@ wasm_call_indirect(WASMExecEnv *exec_env, uint32_t element_indices, uint32_t argc, uint32_t argv[]); +#if WASM_ENABLE_THREAD_MGR != 0 +bool +wasm_set_aux_stack(WASMExecEnv *exec_env, + uint32 start_offset, uint32 size); + +bool +wasm_get_aux_stack(WASMExecEnv *exec_env, + uint32 *start_offset, uint32 *size); +#endif + #ifdef __cplusplus } #endif diff --git a/core/iwasm/libraries/lib-pthread/lib_pthread.cmake b/core/iwasm/libraries/lib-pthread/lib_pthread.cmake new file mode 100644 index 000000000..76112785e --- /dev/null +++ b/core/iwasm/libraries/lib-pthread/lib_pthread.cmake @@ -0,0 +1,13 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +set (LIB_PTHREAD_DIR ${CMAKE_CURRENT_LIST_DIR}) + +add_definitions (-DWASM_ENABLE_LIB_PTHREAD=1) + +include_directories(${LIB_PTHREAD_DIR}) + +file (GLOB source_all ${LIB_PTHREAD_DIR}/*.c) + +set (LIB_PTHREAD_SOURCE ${source_all}) + diff --git a/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c b/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c new file mode 100644 index 000000000..9f19f8fcc --- /dev/null +++ b/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c @@ -0,0 +1,731 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "bh_common.h" +#include "bh_log.h" +#include "wasm_export.h" +#include "../interpreter/wasm.h" +#include "../common/wasm_runtime_common.h" +#include "thread_manager.h" + +#define get_module(exec_env) \ + wasm_exec_env_get_module(exec_env) + +#define get_module_inst(exec_env) \ + wasm_runtime_get_module_inst(exec_env) + +#define get_thread_arg(exec_env) \ + wasm_exec_env_get_thread_arg(exec_env) + +#define get_wasi_ctx(module_inst) \ + wasm_runtime_get_wasi_ctx(module_inst) + +#define validate_app_addr(offset, size) \ + wasm_runtime_validate_app_addr(module_inst, offset, size) + +#define validate_native_addr(addr, size) \ + wasm_runtime_validate_native_addr(module_inst, addr, size) + +#define addr_app_to_native(offset) \ + wasm_runtime_addr_app_to_native(module_inst, offset) + +#define addr_native_to_app(ptr) \ + wasm_runtime_addr_native_to_app(module_inst, ptr) + +extern bool +wasm_runtime_call_indirect(wasm_exec_env_t exec_env, + uint32 element_indices, + uint32 argc, uint32 argv[]); + +enum { + T_THREAD, + T_MUTEX, + T_COND, +}; + +enum thread_status_t { + THREAD_INIT, + THREAD_RUNNING, + THREAD_CANCELLED, + THREAD_EXIT, +}; + +enum mutex_status_t { + MUTEX_CREATED, + MUTEX_DESTROYED, +}; + +enum cond_status_t { + COND_CREATED, + COND_DESTROYED, +}; + +typedef struct ClusterInfoNode { + bh_list_link l; + WASMCluster *cluster; + HashMap *thread_info_map; +} ClusterInfoNode; + +typedef struct ThreadInfoNode { + wasm_exec_env_t parent_exec_env; + wasm_exec_env_t exec_env; + /* the id returned to app */ + uint32 handle; + /* type can be [THREAD | MUTEX | CONDITION] */ + uint32 type; + /* Thread status, this variable should be volatile + as its value may be changed in different threads */ + volatile uint32 status; + union { + korp_tid thread; + korp_mutex *mutex; + korp_cond *cond; + } u; +} ThreadInfoNode; + +typedef struct { + ThreadInfoNode *info_node; + /* table elem index of the app's entry function */ + uint32 elem_index; + /* arg of the app's entry function */ + void *arg; + wasm_module_inst_t module_inst; +} ThreadRoutineArgs; + +static bh_list cluster_info_list; +static korp_mutex pthread_global_lock; +static uint32 handle_id = 1; + +static void +lib_pthread_destroy_callback(WASMCluster *cluster); + +static uint32 +thread_handle_hash(void *handle) +{ + return (uint32)(uintptr_t)handle; +} + +static bool +thread_handle_equal(void *h1, void *h2) +{ + return (uint32)(uintptr_t)h1 == (uint32)(uintptr_t)h2 ? true : false; +} + +static void +thread_info_destroy(void *node) +{ + ThreadInfoNode *info_node = (ThreadInfoNode *)node; + ThreadRoutineArgs *args; + + pthread_mutex_lock(&pthread_global_lock); + if (info_node->type == T_THREAD) { + args = get_thread_arg(info_node->exec_env); + if (args) { + wasm_runtime_free(args); + } + } + else if (info_node->type == T_MUTEX) { + if (info_node->status != MUTEX_DESTROYED) + os_mutex_destroy(info_node->u.mutex); + wasm_runtime_free(info_node->u.mutex); + } + else if (info_node->type == T_COND) { + if (info_node->status != COND_DESTROYED) + os_cond_destroy(info_node->u.cond); + wasm_runtime_free(info_node->u.cond); + } + wasm_runtime_free(info_node); + pthread_mutex_unlock(&pthread_global_lock); +} + +bool +lib_pthread_init() +{ + if (0 != os_mutex_init(&pthread_global_lock)) + return false; + bh_list_init(&cluster_info_list); + if (!wasm_cluster_register_destroy_callback( + lib_pthread_destroy_callback)) { + os_mutex_destroy(&pthread_global_lock); + return false; + } + return true; +} + +void +lib_pthread_destroy() +{ + os_mutex_destroy(&pthread_global_lock); +} + +static ClusterInfoNode* +get_cluster_info(WASMCluster *cluster) +{ + ClusterInfoNode *node; + + os_mutex_lock(&pthread_global_lock); + node = bh_list_first_elem(&cluster_info_list); + + while (node) { + if (cluster == node->cluster) { + os_mutex_unlock(&pthread_global_lock); + return node; + } + node = bh_list_elem_next(node); + } + os_mutex_unlock(&pthread_global_lock); + + return NULL; +} + +static ClusterInfoNode* +create_cluster_info(WASMCluster *cluster) +{ + ClusterInfoNode *node; + bh_list_status ret; + + if (!(node = wasm_runtime_malloc(sizeof(ClusterInfoNode)))) { + return NULL; + } + + node->cluster = cluster; + if (!(node->thread_info_map = + bh_hash_map_create(32, true, + (HashFunc)thread_handle_hash, + (KeyEqualFunc)thread_handle_equal, + NULL, + thread_info_destroy))) { + wasm_runtime_free(node); + return NULL; + } + os_mutex_lock(&pthread_global_lock); + ret = bh_list_insert(&cluster_info_list, node); + bh_assert(ret == 0); + os_mutex_unlock(&pthread_global_lock); + + (void)ret; + return node; +} + +static bool +destroy_cluster_info(WASMCluster *cluster) +{ + ClusterInfoNode *node = get_cluster_info(cluster); + if (node) { + bh_hash_map_destroy(node->thread_info_map); + os_mutex_lock(&pthread_global_lock); + bh_list_remove(&cluster_info_list, node); + wasm_runtime_free(node); + os_mutex_unlock(&pthread_global_lock); + return true; + } + return false; +} + +static void +lib_pthread_destroy_callback(WASMCluster *cluster) +{ + destroy_cluster_info(cluster); +} + +static void +delete_thread_info_node(ThreadInfoNode *thread_info) +{ + ClusterInfoNode *node; + bool ret; + WASMCluster *cluster = + wasm_exec_env_get_cluster(thread_info->exec_env); + + if ((node = get_cluster_info(cluster))) { + ret = bh_hash_map_remove(node->thread_info_map, + (void *)(uintptr_t)thread_info->handle, + NULL, NULL); + (void)ret; + } + + thread_info_destroy(thread_info); +} + +static bool +append_thread_info_node(ThreadInfoNode *thread_info) +{ + ClusterInfoNode *node; + WASMCluster *cluster = + wasm_exec_env_get_cluster(thread_info->exec_env); + + if (!(node = get_cluster_info(cluster))) { + if (!(node = create_cluster_info(cluster))) { + return false; + } + } + + if (!bh_hash_map_insert(node->thread_info_map, + (void *)(uintptr_t)thread_info->handle, + thread_info)) { + return false; + } + + return true; +} + +static ThreadInfoNode* +get_thread_info(wasm_exec_env_t exec_env, uint32 handle) +{ + WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env); + ClusterInfoNode *info = get_cluster_info(cluster); + return bh_hash_map_find(info->thread_info_map, (void *)(uintptr_t)handle); +} + +static uint32 +allocate_handle() +{ + uint32 id; + os_mutex_lock(&pthread_global_lock); + id = handle_id++; + os_mutex_unlock(&pthread_global_lock); + return id; +} + +static void* +pthread_start_routine(void *arg) +{ + wasm_exec_env_t exec_env = (wasm_exec_env_t)arg; + wasm_exec_env_t parent_exec_env; + wasm_module_inst_t module_inst = get_module_inst(exec_env); + ThreadRoutineArgs *routine_args = exec_env->thread_arg; + ThreadInfoNode *info_node = routine_args->info_node; + uint32 argv[1]; + + parent_exec_env = info_node->parent_exec_env; + os_mutex_lock(&parent_exec_env->wait_lock); + info_node->exec_env = exec_env; + info_node->u.thread = exec_env->handle; + if (!append_thread_info_node(info_node)) { + wasm_runtime_deinstantiate_internal(module_inst, true); + delete_thread_info_node(info_node); + os_cond_signal(&parent_exec_env->wait_cond); + os_mutex_unlock(&parent_exec_env->wait_lock); + return NULL; + } + + info_node->status = THREAD_RUNNING; + os_cond_signal(&parent_exec_env->wait_cond); + os_mutex_unlock(&parent_exec_env->wait_lock); + + if (!validate_native_addr(routine_args->arg, sizeof(uint32))) { + /* If there are exceptions, copy the exception to + all other instance in this cluster */ + wasm_cluster_spread_exception(exec_env); + wasm_runtime_deinstantiate_internal(module_inst, true); + delete_thread_info_node(info_node); + return NULL; + } + + argv[0] = addr_native_to_app(routine_args->arg); + + if(!wasm_runtime_call_indirect(exec_env, + routine_args->elem_index, + 1, argv)) { + wasm_cluster_spread_exception(exec_env); + } + + /* routine exit, destroy instance */ + wasm_runtime_deinstantiate_internal(module_inst, true); + + info_node->status = THREAD_EXIT; + + delete_thread_info_node(info_node); + + return (void *)(uintptr_t)argv[0]; +} + +static int +pthread_create_wrapper(wasm_exec_env_t exec_env, + uint32 *thread, /* thread_handle */ + const void *attr, /* not supported */ + uint32 elem_index, /* entry function */ + void *arg) /* arguments buffer */ +{ + wasm_module_t module = get_module(exec_env); + wasm_module_inst_t new_module_inst = NULL; + ThreadInfoNode *info_node = NULL; + ThreadRoutineArgs *routine_args = NULL; + uint32 thread_handle; + int32 ret = -1; +#if WASM_ENABLE_LIBC_WASI != 0 + wasm_module_inst_t module_inst = get_module_inst(exec_env); + WASIContext *wasi_ctx = get_wasi_ctx(module_inst); +#endif + + if (!(new_module_inst = + wasm_runtime_instantiate_internal(module, true, 8192, 0, + NULL, 0))) + return -1; + +#if WASM_ENABLE_LIBC_WASI != 0 + if (wasi_ctx) + wasm_runtime_set_wasi_ctx(new_module_inst, wasi_ctx); +#endif + + if (!(info_node = wasm_runtime_malloc(sizeof(ThreadInfoNode)))) + goto fail; + + memset(info_node, 0, sizeof(ThreadInfoNode)); + thread_handle = allocate_handle(); + info_node->parent_exec_env = exec_env; + info_node->handle = thread_handle; + info_node->type = T_THREAD; + info_node->status = THREAD_INIT; + + if (!(routine_args = wasm_runtime_malloc(sizeof(ThreadRoutineArgs)))) + goto fail; + + routine_args->arg = arg; + routine_args->elem_index = elem_index; + routine_args->info_node = info_node; + routine_args->module_inst = new_module_inst; + + os_mutex_lock(&exec_env->wait_lock); + ret = wasm_cluster_create_thread(exec_env, new_module_inst, + pthread_start_routine, + (void *)routine_args); + if (ret != 0) { + os_mutex_unlock(&exec_env->wait_lock); + goto fail; + } + + /* Wait for the thread routine to assign the exec_env to + thread_info_node, otherwise the exec_env in the thread + info node may be NULL in the next pthread API call */ + os_cond_wait(&exec_env->wait_cond, &exec_env->wait_lock); + os_mutex_unlock(&exec_env->wait_lock); + + if (thread) + *thread = thread_handle; + + return 0; + +fail: + if (new_module_inst) + wasm_runtime_deinstantiate_internal(new_module_inst, true); + if (info_node) + wasm_runtime_free(info_node); + if (routine_args) + wasm_runtime_free(routine_args); + return ret; +} + +static int32 +pthread_join_wrapper(wasm_exec_env_t exec_env, uint32 thread, + int32 retval_offset) /* void **retval */ +{ + uint32 *ret; + int32 join_ret; + void **retval; + ThreadInfoNode *node; + wasm_module_inst_t module_inst; + wasm_exec_env_t target_exec_env; + + node = get_thread_info(exec_env, thread); + if (!node) { + /* The thread has exited, return 0 to app */ + return 0; + } + + target_exec_env = node->exec_env; + bh_assert(target_exec_env != NULL); + module_inst = get_module_inst(target_exec_env); + + /* validate addr before join thread, otherwise + the module_inst may be freed */ + if (!validate_app_addr(retval_offset, sizeof(uint32))) { + /* Join failed, but we don't want to terminate all threads, + do not spread exception here */ + wasm_runtime_set_exception(module_inst, NULL); + return -1; + } + retval = (void **)addr_app_to_native(retval_offset); + + join_ret = wasm_cluster_join_thread(target_exec_env, (void **)&ret); + + if (retval_offset != 0) + *retval = (void*)ret; + + return join_ret; +} + +static int32 +pthread_detach_wrapper(wasm_exec_env_t exec_env, uint32 thread) +{ + ThreadInfoNode *node; + wasm_exec_env_t target_exec_env; + + node = get_thread_info(exec_env, thread); + if (!node) + return 0; + + target_exec_env = node->exec_env; + bh_assert(target_exec_env != NULL); + + return wasm_cluster_detach_thread(target_exec_env); +} + +static int32 +pthread_cancel_wrapper(wasm_exec_env_t exec_env, uint32 thread) +{ + ThreadInfoNode *node; + wasm_exec_env_t target_exec_env; + + node = get_thread_info(exec_env, thread); + if (!node) + return 0; + + target_exec_env = node->exec_env; + bh_assert(target_exec_env != NULL); + + return wasm_cluster_cancel_thread(target_exec_env); +} + +static int32 +pthread_self_wrapper(wasm_exec_env_t exec_env) +{ + ThreadRoutineArgs *args = get_thread_arg(exec_env); + /* If thread_arg is NULL, it's the exec_env of the main thread, + return id 0 to app */ + if (!args) + return 0; + + return args->info_node->handle; +} + +static void +pthread_exit_wrapper(wasm_exec_env_t exec_env, int32 retval_offset) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + ThreadRoutineArgs *args = get_thread_arg(exec_env); + /* Currently exit main thread is not allowed */ + if (!args) + return; + + /* routine exit, destroy instance */ + wasm_runtime_deinstantiate_internal(module_inst, true); + + delete_thread_info_node(args->info_node); + + wasm_cluster_exit_thread(exec_env, (void *)(uintptr_t)retval_offset); +} + +static int32 +pthread_mutex_init_wrapper(wasm_exec_env_t exec_env, uint32 *mutex, void *attr) +{ + korp_mutex *pmutex; + ThreadInfoNode *info_node; + + if (!(pmutex = wasm_runtime_malloc(sizeof(korp_mutex)))) { + return -1; + } + + if (os_mutex_init(pmutex) != 0) { + goto fail1; + } + + if (!(info_node = wasm_runtime_malloc(sizeof(ThreadInfoNode)))) + goto fail2; + + memset(info_node, 0, sizeof(ThreadInfoNode)); + info_node->exec_env = exec_env; + info_node->handle = allocate_handle(); + info_node->type = T_MUTEX; + info_node->u.mutex = pmutex; + info_node->status = MUTEX_CREATED; + + if (!append_thread_info_node(info_node)) + goto fail3; + + /* Return the mutex handle to app */ + if (mutex) + *(uint32*)mutex = info_node->handle; + + return 0; + +fail3: + delete_thread_info_node(info_node); +fail2: + os_mutex_destroy(pmutex); +fail1: + wasm_runtime_free(pmutex); + + return -1; +} + +static int32 +pthread_mutex_lock_wrapper(wasm_exec_env_t exec_env, uint32 *mutex) +{ + ThreadInfoNode* info_node = get_thread_info(exec_env, *mutex); + if (!info_node || info_node->type != T_MUTEX) + return -1; + + return os_mutex_lock(info_node->u.mutex); +} + +static int32 +pthread_mutex_unlock_wrapper(wasm_exec_env_t exec_env, uint32 *mutex) +{ + ThreadInfoNode* info_node = get_thread_info(exec_env, *mutex); + if (!info_node || info_node->type != T_MUTEX) + return -1; + + return os_mutex_unlock(info_node->u.mutex); +} + +static int32 +pthread_mutex_destroy_wrapper(wasm_exec_env_t exec_env, uint32 *mutex) +{ + int32 ret_val; + ThreadInfoNode* info_node = get_thread_info(exec_env, *mutex); + if (!info_node || info_node->type != T_MUTEX) + return -1; + + ret_val = os_mutex_destroy(info_node->u.mutex); + + info_node->status = MUTEX_DESTROYED; + delete_thread_info_node(info_node); + + return ret_val; +} + +static int32 +pthread_cond_init_wrapper(wasm_exec_env_t exec_env, uint32 *cond, void *attr) +{ + korp_cond *pcond; + ThreadInfoNode *info_node; + + if (!(pcond = wasm_runtime_malloc(sizeof(korp_cond)))) { + return -1; + } + + if (os_cond_init(pcond) != 0) { + goto fail1; + } + + if (!(info_node = wasm_runtime_malloc(sizeof(ThreadInfoNode)))) + goto fail2; + + memset(info_node, 0, sizeof(ThreadInfoNode)); + info_node->exec_env = exec_env; + info_node->handle = allocate_handle(); + info_node->type = T_COND; + info_node->u.cond = pcond; + info_node->status = COND_CREATED; + + if (!append_thread_info_node(info_node)) + goto fail3; + + /* Return the cond handle to app */ + if (cond) + *(uint32*)cond = info_node->handle; + + return 0; + +fail3: + delete_thread_info_node(info_node); +fail2: + os_cond_destroy(pcond); +fail1: + wasm_runtime_free(pcond); + + return -1; +} + +static int32 +pthread_cond_wait_wrapper(wasm_exec_env_t exec_env, uint32 *cond, uint32 *mutex) +{ + ThreadInfoNode *cond_info_node, *mutex_info_node; + + cond_info_node = get_thread_info(exec_env, *cond); + if (!cond_info_node || cond_info_node->type != T_COND) + return -1; + + mutex_info_node = get_thread_info(exec_env, *mutex); + if (!mutex_info_node || mutex_info_node->type != T_MUTEX) + return -1; + + return os_cond_wait(cond_info_node->u.cond, mutex_info_node->u.mutex); +} + +/* Currently we don't support struct timespec in built-in libc, + so the pthread_cond_timedwait use useconds instead +*/ +static int32 +pthread_cond_timedwait_wrapper(wasm_exec_env_t exec_env, uint32 *cond, + uint32 *mutex, uint32 useconds) +{ + ThreadInfoNode *cond_info_node, *mutex_info_node; + + cond_info_node = get_thread_info(exec_env, *cond); + if (!cond_info_node || cond_info_node->type != T_COND) + return -1; + + mutex_info_node = get_thread_info(exec_env, *mutex); + if (!mutex_info_node || mutex_info_node->type != T_MUTEX) + return -1; + + return os_cond_reltimedwait(cond_info_node->u.cond, + mutex_info_node->u.mutex, useconds); +} + +static int32 +pthread_cond_signal_wrapper(wasm_exec_env_t exec_env, uint32 *cond) +{ + ThreadInfoNode* info_node = get_thread_info(exec_env, *cond); + if (!info_node || info_node->type != T_COND) + return -1; + + return os_cond_signal(info_node->u.cond); +} + +static int32 +pthread_cond_destroy_wrapper(wasm_exec_env_t exec_env, uint32 *cond) +{ + int32 ret_val; + ThreadInfoNode* info_node = get_thread_info(exec_env, *cond); + if (!info_node || info_node->type != T_COND) + return -1; + + ret_val = os_cond_destroy(info_node->u.cond); + + info_node->status = COND_DESTROYED; + delete_thread_info_node(info_node); + + return ret_val; +} + +#define REG_NATIVE_FUNC(func_name, signature) \ + { #func_name, func_name##_wrapper, signature, NULL } + +static NativeSymbol native_symbols_lib_pthread[] = { + REG_NATIVE_FUNC(pthread_create, "(**i*)i"), + REG_NATIVE_FUNC(pthread_join, "(ii)i"), + REG_NATIVE_FUNC(pthread_detach, "(i)i"), + REG_NATIVE_FUNC(pthread_cancel, "(i)i"), + REG_NATIVE_FUNC(pthread_self, "()i"), + REG_NATIVE_FUNC(pthread_exit, "(i)"), + REG_NATIVE_FUNC(pthread_mutex_init, "(**)i"), + REG_NATIVE_FUNC(pthread_mutex_lock, "(*)i"), + REG_NATIVE_FUNC(pthread_mutex_unlock, "(*)i"), + REG_NATIVE_FUNC(pthread_mutex_destroy, "(*)i"), + REG_NATIVE_FUNC(pthread_cond_init, "(**)i"), + REG_NATIVE_FUNC(pthread_cond_wait, "(**)i"), + REG_NATIVE_FUNC(pthread_cond_timedwait, "(**i)i"), + REG_NATIVE_FUNC(pthread_cond_signal, "(*)i"), + REG_NATIVE_FUNC(pthread_cond_destroy, "(*)i"), +}; + +uint32 +get_lib_pthread_export_apis(NativeSymbol **p_lib_pthread_apis) +{ + *p_lib_pthread_apis = native_symbols_lib_pthread; + return sizeof(native_symbols_lib_pthread) / sizeof(NativeSymbol); +} \ No newline at end of file diff --git a/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c b/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c index 88ebc0131..006e5519e 100644 --- a/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c +++ b/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c @@ -1131,9 +1131,11 @@ typedef struct WASMNativeGlobalDef { } WASMNativeGlobalDef; static WASMNativeGlobalDef native_global_defs[] = { +#if WASM_ENABLE_SPEC_TEST != 0 { "spectest", "global_i32", .global_data.i32 = 666 }, { "spectest", "global_f32", .global_data.f32 = 666.6 }, { "spectest", "global_f64", .global_data.f64 = 666.6 }, +#endif { "test", "global-i32", .global_data.i32 = 0 }, { "test", "global-f32", .global_data.f32 = 0 }, { "env", "STACKTOP", .global_data.u32 = 0 }, diff --git a/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c b/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c index c5780dbdd..c3fa207bc 100644 --- a/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c +++ b/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c @@ -58,6 +58,8 @@ static struct fd_table * wasi_ctx_get_curfds(wasm_module_inst_t module_inst, wasi_ctx_t wasi_ctx) { + if (!wasi_ctx) + return NULL; return (struct fd_table *) wasm_runtime_addr_app_to_native(module_inst, wasi_ctx->curfds_offset); @@ -67,6 +69,8 @@ static struct argv_environ_values * wasi_ctx_get_argv_environ(wasm_module_inst_t module_inst, wasi_ctx_t wasi_ctx) { + if (!wasi_ctx) + return NULL; return (struct argv_environ_values *) wasm_runtime_addr_app_to_native(module_inst, wasi_ctx->argv_environ_offset); @@ -76,6 +80,8 @@ static struct fd_prestats * wasi_ctx_get_prestats(wasm_module_inst_t module_inst, wasi_ctx_t wasi_ctx) { + if (!wasi_ctx) + return NULL; return (struct fd_prestats *) wasm_runtime_addr_app_to_native(module_inst, wasi_ctx->prestats_offset); @@ -93,6 +99,9 @@ wasi_args_get(wasm_exec_env_t exec_env, int32 *argv_offsets, char *argv_buf) uint64 total_size; wasi_errno_t err; + if (!wasi_ctx) + return (wasi_errno_t)-1; + err = wasmtime_ssp_args_sizes_get(argv_environ, &argc, &argv_buf_size); if (err) return err; @@ -133,6 +142,9 @@ wasi_args_sizes_get(wasm_exec_env_t exec_env, size_t argc, argv_buf_size; wasi_errno_t err; + if (!wasi_ctx) + return (wasi_errno_t)-1; + if (!validate_native_addr(argc_app, sizeof(uint32)) || !validate_native_addr(argv_buf_size_app, sizeof(uint32))) return (wasi_errno_t)-1; @@ -191,6 +203,9 @@ wasi_environ_get(wasm_exec_env_t exec_env, char **environs; wasi_errno_t err; + if (!wasi_ctx) + return (wasi_errno_t)-1; + err = wasmtime_ssp_environ_sizes_get(argv_environ, &environ_count, &environ_buf_size); if (err) @@ -234,6 +249,9 @@ wasi_environ_sizes_get(wasm_exec_env_t exec_env, size_t environ_count, environ_buf_size; wasi_errno_t err; + if (!wasi_ctx) + return (wasi_errno_t)-1; + if (!validate_native_addr(environ_count_app, sizeof(uint32)) || !validate_native_addr(environ_buf_size_app, sizeof(uint32))) return (wasi_errno_t)-1; @@ -259,6 +277,9 @@ wasi_fd_prestat_get(wasm_exec_env_t exec_env, wasi_prestat_t prestat; wasi_errno_t err; + if (!wasi_ctx) + return (wasi_errno_t)-1; + if (!validate_native_addr(prestat_app, sizeof(wasi_prestat_app_t))) return (wasi_errno_t)-1; @@ -279,6 +300,9 @@ wasi_fd_prestat_dir_name(wasm_exec_env_t exec_env, wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); struct fd_prestats *prestats = wasi_ctx_get_prestats(module_inst, wasi_ctx); + if (!wasi_ctx) + return (wasi_errno_t)-1; + return wasmtime_ssp_fd_prestat_dir_name(prestats, fd, path, path_len); } @@ -291,6 +315,9 @@ wasi_fd_close(wasm_exec_env_t exec_env, wasi_fd_t fd) struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); struct fd_prestats *prestats = wasi_ctx_get_prestats(module_inst, wasi_ctx); + if (!wasi_ctx) + return (wasi_errno_t)-1; + return wasmtime_ssp_fd_close(curfds, prestats, fd); } @@ -301,6 +328,9 @@ wasi_fd_datasync(wasm_exec_env_t exec_env, wasi_fd_t fd) wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + if (!wasi_ctx) + return (wasi_errno_t)-1; + return wasmtime_ssp_fd_datasync(curfds, fd); } @@ -319,6 +349,9 @@ wasi_fd_pread(wasm_exec_env_t exec_env, uint32 i; wasi_errno_t err; + if (!wasi_ctx) + return (wasi_errno_t)-1; + total_size = sizeof(iovec_app_t) * (uint64)iovs_len; if (!validate_native_addr(nread_app, (uint32)sizeof(uint32)) || total_size >= UINT32_MAX @@ -371,6 +404,9 @@ wasi_fd_pwrite(wasm_exec_env_t exec_env, uint32 i; wasi_errno_t err; + if (!wasi_ctx) + return (wasi_errno_t)-1; + total_size = sizeof(iovec_app_t) * (uint64)iovs_len; if (!validate_native_addr(nwritten_app, (uint32)sizeof(uint32)) || total_size >= UINT32_MAX @@ -423,6 +459,9 @@ wasi_fd_read(wasm_exec_env_t exec_env, int32 mem; wasi_errno_t err; + if (!wasi_ctx) + return (wasi_errno_t)-1; + total_size = sizeof(iovec_app_t) * (uint64)iovs_len; if (!validate_native_addr(nread_app, (uint32)sizeof(uint32)) || total_size >= UINT32_MAX @@ -468,6 +507,9 @@ wasi_fd_renumber(wasm_exec_env_t exec_env, wasi_fd_t from, wasi_fd_t to) struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); struct fd_prestats *prestats = wasi_ctx_get_prestats(module_inst, wasi_ctx); + if (!wasi_ctx) + return (wasi_errno_t)-1; + return wasmtime_ssp_fd_renumber(curfds, prestats, from, to); } @@ -480,6 +522,9 @@ wasi_fd_seek(wasm_exec_env_t exec_env, wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + if (!wasi_ctx) + return (wasi_errno_t)-1; + if (!validate_native_addr(newoffset, sizeof(wasi_filesize_t))) return (wasi_errno_t)-1; @@ -494,6 +539,9 @@ wasi_fd_tell(wasm_exec_env_t exec_env, wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + if (!wasi_ctx) + return (wasi_errno_t)-1; + if (!validate_native_addr(newoffset, sizeof(wasi_filesize_t))) return (wasi_errno_t)-1; @@ -510,6 +558,9 @@ wasi_fd_fdstat_get(wasm_exec_env_t exec_env, wasi_fdstat_t fdstat; wasi_errno_t err; + if (!wasi_ctx) + return (wasi_errno_t)-1; + if (!validate_native_addr(fdstat_app, sizeof(wasi_fdstat_t))) return (wasi_errno_t)-1; @@ -529,6 +580,9 @@ wasi_fd_fdstat_set_flags(wasm_exec_env_t exec_env, wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + if (!wasi_ctx) + return (wasi_errno_t)-1; + return wasmtime_ssp_fd_fdstat_set_flags(curfds, fd, flags); } @@ -542,6 +596,9 @@ wasi_fd_fdstat_set_rights(wasm_exec_env_t exec_env, wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + if (!wasi_ctx) + return (wasi_errno_t)-1; + return wasmtime_ssp_fd_fdstat_set_rights(curfds, fd, fs_rights_base, fs_rights_inheriting); } @@ -553,6 +610,9 @@ wasi_fd_sync(wasm_exec_env_t exec_env, wasi_fd_t fd) wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + if (!wasi_ctx) + return (wasi_errno_t)-1; + return wasmtime_ssp_fd_sync(curfds, fd); } @@ -571,6 +631,9 @@ wasi_fd_write(wasm_exec_env_t exec_env, wasi_fd_t fd, uint32 i; wasi_errno_t err; + if (!wasi_ctx) + return (wasi_errno_t)-1; + total_size = sizeof(iovec_app_t) * (uint64)iovs_len; if (!validate_native_addr(nwritten_app, (uint32)sizeof(uint32)) || total_size >= UINT32_MAX @@ -619,6 +682,9 @@ wasi_fd_advise(wasm_exec_env_t exec_env, wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + if (!wasi_ctx) + return (wasi_errno_t)-1; + return wasmtime_ssp_fd_advise(curfds, fd, offset, len, advice); } @@ -632,6 +698,9 @@ wasi_fd_allocate(wasm_exec_env_t exec_env, wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + if (!wasi_ctx) + return (wasi_errno_t)-1; + return wasmtime_ssp_fd_allocate(curfds, fd, offset, len); } @@ -643,6 +712,9 @@ wasi_path_create_directory(wasm_exec_env_t exec_env, wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + if (!wasi_ctx) + return (wasi_errno_t)-1; + return wasmtime_ssp_path_create_directory(curfds, fd, path, path_len); } @@ -660,6 +732,9 @@ wasi_path_link(wasm_exec_env_t exec_env, struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); struct fd_prestats *prestats = wasi_ctx_get_prestats(module_inst, wasi_ctx); + if (!wasi_ctx) + return (wasi_errno_t)-1; + return wasmtime_ssp_path_link(curfds, prestats, old_fd, old_flags, old_path, old_path_len, new_fd, new_path, new_path_len); @@ -682,6 +757,9 @@ wasi_path_open(wasm_exec_env_t exec_env, wasi_fd_t fd = -1; /* set fd_app -1 if path open failed */ wasi_errno_t err; + if (!wasi_ctx) + return (wasi_errno_t)-1; + if (!validate_native_addr(fd_app, sizeof(wasi_fd_t))) return (wasi_errno_t)-1; @@ -711,6 +789,9 @@ wasi_fd_readdir(wasm_exec_env_t exec_env, size_t bufused; wasi_errno_t err; + if (!wasi_ctx) + return (wasi_errno_t)-1; + if (!validate_native_addr(bufused_app, sizeof(uint32))) return (wasi_errno_t)-1; @@ -736,6 +817,9 @@ wasi_path_readlink(wasm_exec_env_t exec_env, size_t bufused; wasi_errno_t err; + if (!wasi_ctx) + return (wasi_errno_t)-1; + if (!validate_native_addr(bufused_app, sizeof(uint32))) return (wasi_errno_t)-1; @@ -758,6 +842,9 @@ wasi_path_rename(wasm_exec_env_t exec_env, wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + if (!wasi_ctx) + return (wasi_errno_t)-1; + return wasmtime_ssp_path_rename(curfds, old_fd, old_path, old_path_len, new_fd, new_path, new_path_len); @@ -771,6 +858,9 @@ wasi_fd_filestat_get(wasm_exec_env_t exec_env, wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + if (!wasi_ctx) + return (wasi_errno_t)-1; + if (!validate_native_addr(filestat, sizeof(wasi_filestat_t))) return (wasi_errno_t)-1; @@ -788,6 +878,9 @@ wasi_fd_filestat_set_times(wasm_exec_env_t exec_env, wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + if (!wasi_ctx) + return (wasi_errno_t)-1; + return wasmtime_ssp_fd_filestat_set_times(curfds, fd, st_atim, st_mtim, fstflags); } @@ -801,6 +894,9 @@ wasi_fd_filestat_set_size(wasm_exec_env_t exec_env, wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + if (!wasi_ctx) + return (wasi_errno_t)-1; + return wasmtime_ssp_fd_filestat_set_size(curfds, fd, st_size); } @@ -815,6 +911,9 @@ wasi_path_filestat_get(wasm_exec_env_t exec_env, wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + if (!wasi_ctx) + return (wasi_errno_t)-1; + if (!validate_native_addr(filestat, sizeof(wasi_filestat_t))) return (wasi_errno_t)-1; @@ -835,6 +934,9 @@ wasi_path_filestat_set_times(wasm_exec_env_t exec_env, wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + if (!wasi_ctx) + return (wasi_errno_t)-1; + return wasmtime_ssp_path_filestat_set_times(curfds, fd, flags, path, path_len, st_atim, st_mtim, fstflags); @@ -850,6 +952,9 @@ wasi_path_symlink(wasm_exec_env_t exec_env, struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); struct fd_prestats *prestats = wasi_ctx_get_prestats(module_inst, wasi_ctx); + if (!wasi_ctx) + return (wasi_errno_t)-1; + return wasmtime_ssp_path_symlink(curfds, prestats, old_path, old_path_len, fd, new_path, new_path_len); @@ -863,6 +968,9 @@ wasi_path_unlink_file(wasm_exec_env_t exec_env, wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + if (!wasi_ctx) + return (wasi_errno_t)-1; + return wasmtime_ssp_path_unlink_file(curfds, fd, path, path_len); } @@ -874,6 +982,9 @@ wasi_path_remove_directory(wasm_exec_env_t exec_env, wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + if (!wasi_ctx) + return (wasi_errno_t)-1; + return wasmtime_ssp_path_remove_directory(curfds, fd, path, path_len); } @@ -888,6 +999,9 @@ wasi_poll_oneoff(wasm_exec_env_t exec_env, size_t nevents; wasi_errno_t err; + if (!wasi_ctx) + return (wasi_errno_t)-1; + if (!validate_native_addr((void*)in, sizeof(wasi_subscription_t)) || !validate_native_addr(out, sizeof(wasi_event_t)) || !validate_native_addr(nevents_app, sizeof(uint32))) @@ -943,6 +1057,9 @@ wasi_sock_recv(wasm_exec_env_t exec_env, uint32 i; wasi_errno_t err; + if (!wasi_ctx) + return (wasi_errno_t)-1; + total_size = sizeof(iovec_app_t) * (uint64)ri_data_len; if (!validate_native_addr(ro_datalen_app, (uint32)sizeof(uint32)) || !validate_native_addr(ro_flags, (uint32)sizeof(wasi_roflags_t)) @@ -1000,6 +1117,9 @@ wasi_sock_send(wasm_exec_env_t exec_env, uint32 i; wasi_errno_t err; + if (!wasi_ctx) + return (wasi_errno_t)-1; + total_size = sizeof(iovec_app_t) * (uint64)si_data_len; if (!validate_native_addr(so_datalen_app, sizeof(uint32)) || total_size >= UINT32_MAX @@ -1046,6 +1166,9 @@ wasi_sock_shutdown(wasm_exec_env_t exec_env, wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + if (!wasi_ctx) + return (wasi_errno_t)-1; + return wasmtime_ssp_sock_shutdown(curfds, sock, how); } diff --git a/core/iwasm/libraries/thread-mgr/thread_manager.c b/core/iwasm/libraries/thread-mgr/thread_manager.c new file mode 100644 index 000000000..d1d8a531b --- /dev/null +++ b/core/iwasm/libraries/thread-mgr/thread_manager.c @@ -0,0 +1,523 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "thread_manager.h" + +typedef struct { + bh_list_link l; + + void (*destroy_cb)(WASMCluster *); +} DestroyCallBackNode; + +static bh_list destroy_callback_list_head; +static bh_list *const destroy_callback_list = &destroy_callback_list_head; + +static bh_list cluster_list_head; +static bh_list *const cluster_list = &cluster_list_head; +static korp_mutex cluster_list_lock; + +typedef void (*list_visitor)(void *, void *); + +static uint32 cluster_max_thread_num = CLUSTER_MAX_THREAD_NUM; + +/* Set the maximum thread number, if this function is not called, + the max thread num is defined by CLUSTER_MAX_THREAD_NUM */ +void +wasm_cluster_set_max_thread_num(uint32 num) +{ + cluster_max_thread_num = num; +} + +bool +thread_manager_init() +{ + if (bh_list_init(cluster_list) != 0) + return false; + if (os_mutex_init(&cluster_list_lock) != 0) + return false; + return true; +} + +void +thread_manager_destroy() +{ + WASMCluster *cluster = bh_list_first_elem(cluster_list); + WASMCluster *next; + while (cluster) { + next = bh_list_elem_next(cluster); + wasm_cluster_destroy(cluster); + cluster = next; + } + wasm_cluster_cancel_all_callbacks(); + os_mutex_destroy(&cluster_list_lock); +} + +static void +traverse_list(bh_list *l, list_visitor visitor, void *user_data) +{ + void *next, *node = bh_list_first_elem(l); + while (node) { + next = bh_list_elem_next(node); + visitor(node, user_data); + node = next; + } +} + +static bool +allocate_aux_stack(WASMCluster *cluster, uint32 *start, uint32 *size) +{ + uint32 i; + + /* If the module doesn't have aux stack info, + it can't create any threads */ + if (!cluster->stack_segment_occupied) + return false; + + os_mutex_lock(&cluster->lock); + for (i = 0; i < cluster_max_thread_num; i++) { + if (!cluster->stack_segment_occupied[i]) { + if (start) + *start = cluster->stack_tops[i]; + if (size) + *size = cluster->stack_size; + cluster->stack_segment_occupied[i] = true; + os_mutex_unlock(&cluster->lock); + return true; + } + } + os_mutex_unlock(&cluster->lock); + return false; +} + +static bool +free_aux_stack(WASMCluster *cluster, uint32 start) +{ + uint32 i; + + for (i = 0; i < cluster_max_thread_num; i++) { + if (start == cluster->stack_tops[i]) { + os_mutex_lock(&cluster->lock); + cluster->stack_segment_occupied[i] = false; + os_mutex_unlock(&cluster->lock); + return true; + } + } + return false; +} + +WASMCluster * +wasm_cluster_create(WASMExecEnv *exec_env) +{ + WASMCluster *cluster; + uint64 total_size; + uint32 aux_stack_start, aux_stack_size, i; + + bh_assert(exec_env->cluster == NULL); + if (!(cluster = wasm_runtime_malloc(sizeof(WASMCluster)))) { + LOG_ERROR("thread manager error: failed to allocate memory"); + return NULL; + } + memset(cluster, 0, sizeof(WASMCluster)); + + exec_env->cluster = cluster; + + bh_list_init(&cluster->exec_env_list); + bh_list_insert(&cluster->exec_env_list, exec_env); + if (os_mutex_init(&cluster->lock) != 0) { + wasm_runtime_free(cluster); + LOG_ERROR("thread manager error: failed to init mutex"); + return NULL; + } + + /* Prepare the aux stack top and size for every thread */ + if (!wasm_exec_env_get_aux_stack(exec_env, + &aux_stack_start, + &aux_stack_size)) { + LOG_VERBOSE("No aux stack info for this module, can't create thread"); + + /* If the module don't have aux stack info, don't throw error here, + but remain stack_tops and stack_segment_occupied as NULL */ + os_mutex_lock(&cluster_list_lock); + if (bh_list_insert(cluster_list, cluster) != 0) { + os_mutex_unlock(&cluster_list_lock); + goto fail; + } + os_mutex_unlock(&cluster_list_lock); + + return cluster; + } + + cluster->stack_size = aux_stack_size / (cluster_max_thread_num + 1); + if (cluster->stack_size == 0) { + goto fail; + } + + /* Set initial aux stack top to the instance and + aux stack boundary to the main exec_env */ + if (!wasm_exec_env_set_aux_stack(exec_env, aux_stack_start, + cluster->stack_size)) + goto fail; + + if (cluster_max_thread_num != 0) { + total_size = cluster_max_thread_num * sizeof(uint32); + if (total_size >= UINT32_MAX + || !(cluster->stack_tops = + wasm_runtime_malloc((uint32)total_size))) { + goto fail; + } + memset(cluster->stack_tops, 0, (uint32)total_size); + + if (!(cluster->stack_segment_occupied = + wasm_runtime_malloc(cluster_max_thread_num * sizeof(bool)))) { + goto fail; + } + memset(cluster->stack_segment_occupied, 0, + cluster_max_thread_num * sizeof(bool)); + + /* Reserve space for main instance */ + aux_stack_start -= cluster->stack_size; + + for (i = 0; i < cluster_max_thread_num; i++) { + cluster->stack_tops[i] = aux_stack_start - cluster->stack_size * i; + } + } + + os_mutex_lock(&cluster_list_lock); + if (bh_list_insert(cluster_list, cluster) != 0) { + os_mutex_unlock(&cluster_list_lock); + goto fail; + } + os_mutex_unlock(&cluster_list_lock); + + return cluster; + +fail: + if (cluster) + wasm_cluster_destroy(cluster); + + return NULL; +} + +static void +destroy_cluster_visitor(void *node, void *user_data) +{ + DestroyCallBackNode *destroy_node = (DestroyCallBackNode *)node; + WASMCluster *cluster = (WASMCluster *)user_data; + + destroy_node->destroy_cb(cluster); +} + +void +wasm_cluster_destroy(WASMCluster *cluster) +{ + traverse_list(destroy_callback_list, + destroy_cluster_visitor, (void *)cluster); + + /* Remove the cluster from the cluster list */ + os_mutex_lock(&cluster_list_lock); + bh_list_remove(cluster_list, cluster); + os_mutex_unlock(&cluster_list_lock); + + os_mutex_destroy(&cluster->lock); + + if (cluster->stack_tops) + wasm_runtime_free(cluster->stack_tops); + if (cluster->stack_segment_occupied) + wasm_runtime_free(cluster->stack_segment_occupied); + wasm_runtime_free(cluster); +} + +static void +free_node_visitor(void *node, void *user_data) +{ + wasm_runtime_free(node); +} + +void +wasm_cluster_cancel_all_callbacks() +{ + traverse_list(destroy_callback_list, free_node_visitor, NULL); +} + +WASMCluster * +wasm_exec_env_get_cluster(WASMExecEnv *exec_env) +{ + return exec_env->cluster; +} + +bool +wasm_cluster_add_exec_env(WASMCluster *cluster, WASMExecEnv *exec_env) +{ + bool ret = true; + + exec_env->cluster = cluster; + + os_mutex_lock(&cluster->lock); + if (bh_list_insert(&cluster->exec_env_list, exec_env) != 0) + ret = false; + os_mutex_unlock(&cluster->lock); + return ret; +} + +bool +wasm_cluster_del_exec_env(WASMCluster *cluster, WASMExecEnv *exec_env) +{ + bool ret = true; + bh_assert(exec_env->cluster == cluster); + os_mutex_lock(&cluster->lock); + if (bh_list_remove(&cluster->exec_env_list, exec_env) != 0) + ret = false; + os_mutex_unlock(&cluster->lock); + + if (cluster->exec_env_list.len == 0) { + /* exec_env_list empty, destroy the cluster */ + wasm_cluster_destroy(cluster); + } + return ret; +} + +/* start routine of thread manager */ +static void* +thread_manager_start_routine(void *arg) +{ + void *ret; + WASMExecEnv *exec_env = (WASMExecEnv *)arg; + WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env); + bh_assert(cluster != NULL); + + exec_env->handle = os_self_thread(); + ret = exec_env->thread_start_routine(exec_env); + + /* Routine exit */ + /* Free aux stack space */ + free_aux_stack(cluster, + exec_env->aux_stack_boundary + cluster->stack_size); + /* Detach the native thread here to ensure the resources are freed */ + wasm_cluster_detach_thread(exec_env); + /* Remove and destroy exec_env */ + wasm_cluster_del_exec_env(cluster, exec_env); + wasm_exec_env_destroy_internal(exec_env); + + os_thread_exit(ret); + return ret; +} + +int32 +wasm_cluster_create_thread(WASMExecEnv *exec_env, + wasm_module_inst_t module_inst, + void* (*thread_routine)(void *), + void *arg) +{ + WASMCluster *cluster; + WASMExecEnv *new_exec_env; + uint32 aux_stack_start, aux_stack_size; + korp_tid tid; + + cluster = wasm_exec_env_get_cluster(exec_env); + bh_assert(cluster); + + new_exec_env = wasm_exec_env_create_internal( + module_inst, exec_env->wasm_stack_size); + if (!new_exec_env) + return -1; + + if (!allocate_aux_stack(cluster, &aux_stack_start, &aux_stack_size)) { + LOG_ERROR("thread manager error: " + "failed to allocate aux stack space for new thread"); + goto fail1; + } + + /* Set aux stack for current thread */ + if (!wasm_exec_env_set_aux_stack(new_exec_env, aux_stack_start, + aux_stack_size)) { + goto fail2; + } + + if (!wasm_cluster_add_exec_env(cluster, new_exec_env)) + goto fail2; + + new_exec_env->thread_start_routine = thread_routine; + new_exec_env->thread_arg = arg; + + if (0 != os_thread_create(&tid, thread_manager_start_routine, + (void *)new_exec_env, + APP_THREAD_STACK_SIZE_DEFAULT)) { + goto fail3; + } + + return 0; + +fail3: + wasm_cluster_del_exec_env(cluster, new_exec_env); +fail2: + /* free the allocated aux stack space */ + free_aux_stack(cluster, aux_stack_start); +fail1: + wasm_exec_env_destroy(new_exec_env); + return -1; +} + +int32 +wasm_cluster_join_thread(WASMExecEnv *exec_env, void **ret_val) +{ + return os_thread_join(exec_env->handle, ret_val); +} + +int32 +wasm_cluster_detach_thread(WASMExecEnv *exec_env) +{ + return os_thread_detach(exec_env->handle); +} + +void +wasm_cluster_exit_thread(WASMExecEnv *exec_env, void *retval) +{ + WASMCluster *cluster; + + cluster = wasm_exec_env_get_cluster(exec_env); + bh_assert(cluster); + + /* App exit the thread, free the resources before exit native thread */ + /* Free aux stack space */ + free_aux_stack(cluster, + exec_env->aux_stack_boundary + cluster->stack_size); + /* Detach the native thread here to ensure the resources are freed */ + wasm_cluster_detach_thread(exec_env); + /* Remove and destroy exec_env */ + wasm_cluster_del_exec_env(cluster, exec_env); + wasm_exec_env_destroy_internal(exec_env); + + os_thread_exit(retval); +} + +int32 +wasm_cluster_cancel_thread(WASMExecEnv *exec_env) +{ + /* Set the termination flag */ + exec_env->suspend_flags |= 0x01; + return 0; +} + +static void +terminate_thread_visitor(void *node, void *user_data) +{ + WASMExecEnv *curr_exec_env = (WASMExecEnv *)node; + WASMExecEnv *exec_env = (WASMExecEnv *)user_data; + + if (curr_exec_env == exec_env) + return; + + wasm_cluster_cancel_thread(curr_exec_env); + wasm_cluster_join_thread(curr_exec_env, NULL); +} + +void +wasm_cluster_terminate_all(WASMCluster *cluster) +{ + traverse_list(&cluster->exec_env_list, + terminate_thread_visitor, NULL); +} + +void +wasm_cluster_terminate_all_except_self(WASMCluster *cluster, + WASMExecEnv *exec_env) +{ + traverse_list(&cluster->exec_env_list, + terminate_thread_visitor, (void *)exec_env); +} + +bool +wasm_cluster_register_destroy_callback(void (*callback)(WASMCluster *)) +{ + DestroyCallBackNode *node; + + if (!(node = wasm_runtime_malloc(sizeof(DestroyCallBackNode)))) { + LOG_ERROR("thread manager error: failed to allocate memory"); + return false; + } + node->destroy_cb = callback; + bh_list_insert(destroy_callback_list, node); + return true; +} + +void +wasm_cluster_suspend_thread(WASMExecEnv *exec_env) +{ + /* Set the suspend flag */ + exec_env->suspend_flags |= 0x02; +} + +static void +suspend_thread_visitor(void *node, void *user_data) +{ + WASMExecEnv *curr_exec_env = (WASMExecEnv *)node; + WASMExecEnv *exec_env = (WASMExecEnv *)user_data; + + if (curr_exec_env == exec_env) + return; + + wasm_cluster_suspend_thread(curr_exec_env); +} + +void +wasm_cluster_suspend_all(WASMCluster *cluster) +{ + traverse_list(&cluster->exec_env_list, + suspend_thread_visitor, NULL); +} + +void +wasm_cluster_suspend_all_except_self(WASMCluster *cluster, + WASMExecEnv *exec_env) +{ + traverse_list(&cluster->exec_env_list, + suspend_thread_visitor, (void *)exec_env); +} + +void +wasm_cluster_resume_thread(WASMExecEnv *exec_env) +{ + exec_env->suspend_flags &= ~0x02; +} + +static void +resume_thread_visitor(void *node, void *user_data) +{ + WASMExecEnv *curr_exec_env = (WASMExecEnv *)node; + + wasm_cluster_resume_thread(curr_exec_env); +} + +void +wasm_cluster_resume_all(WASMCluster *cluster) +{ + traverse_list(&cluster->exec_env_list, resume_thread_visitor, NULL); +} + +static void +set_exception_visitor(void *node, void *user_data) +{ + WASMExecEnv *curr_exec_env = (WASMExecEnv *)node; + WASMExecEnv *exec_env = (WASMExecEnv *)user_data; + WASMModuleInstanceCommon *module_inst = get_module_inst(exec_env); + WASMModuleInstanceCommon *curr_module_inst = + get_module_inst(curr_exec_env); + const char *exception = wasm_runtime_get_exception(module_inst); + /* skip "Exception: " */ + exception += 11; + + if (curr_exec_env != exec_env) { + curr_module_inst = get_module_inst(curr_exec_env); + wasm_runtime_set_exception(curr_module_inst, exception); + } +} + +void +wasm_cluster_spread_exception(WASMExecEnv *exec_env) +{ + WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env); + + traverse_list(&cluster->exec_env_list, set_exception_visitor, exec_env); +} diff --git a/core/iwasm/libraries/thread-mgr/thread_manager.h b/core/iwasm/libraries/thread-mgr/thread_manager.h new file mode 100644 index 000000000..139763769 --- /dev/null +++ b/core/iwasm/libraries/thread-mgr/thread_manager.h @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _THREAD_MANAGER_H +#define _THREAD_MANAGER_H + +#include "bh_common.h" +#include "bh_log.h" +#include "wasm_export.h" +#include "../interpreter/wasm.h" +#include "../common/wasm_runtime_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct WASMCluster +{ + struct WASMCluster *next; + + korp_mutex lock; + bh_list exec_env_list; + + /* The aux stack of a module with shared memory will be + divided into several segments. This array store the + stack top of different segments */ + uint32 *stack_tops; + /* Size of every stack segment */ + uint32 stack_size; + /* Record which segments are occupied */ + bool *stack_segment_occupied; +} WASMCluster; + +void wasm_cluster_set_max_thread_num(uint32 num); + +bool +thread_manager_init(); + +void +thread_manager_destroy(); + +/* Create cluster */ +WASMCluster * +wasm_cluster_create(WASMExecEnv *exec_env); + +/* Destroy cluster */ +void +wasm_cluster_destroy(WASMCluster *cluster); + +/* Get the cluster of the current exec_env */ +WASMCluster* +wasm_exec_env_get_cluster(WASMExecEnv *exec_env); + +int32 +wasm_cluster_create_thread(WASMExecEnv *exec_env, + wasm_module_inst_t module_inst, + void* (*thread_routine)(void *), + void *arg); + +int32 +wasm_cluster_join_thread(WASMExecEnv *exec_env, void **ret_val); + +int32 +wasm_cluster_detach_thread(WASMExecEnv *exec_env); + +int32 +wasm_cluster_cancel_thread(WASMExecEnv *exec_env); + +void +wasm_cluster_exit_thread(WASMExecEnv *exec_env, void *retval); + +bool +wasm_cluster_register_destroy_callback(void (*callback)(WASMCluster *)); + +void +wasm_cluster_cancel_all_callbacks(); + +void +wasm_cluster_suspend_all(WASMCluster *cluster); + +void +wasm_cluster_suspend_all_except_self(WASMCluster *cluster, + WASMExecEnv *exec_env); + +void +wasm_cluster_suspend_thread(WASMExecEnv *exec_env); + +void +wasm_cluster_resume_thread(WASMExecEnv *exec_env); + +void +wasm_cluster_resume_all(WASMCluster *cluster); + +void +wasm_cluster_terminate_all(WASMCluster *cluster); + +void +wasm_cluster_terminate_all_except_self(WASMCluster *cluster, + WASMExecEnv *exec_env); + +bool +wasm_cluster_add_exec_env(WASMCluster *cluster, WASMExecEnv *exec_env); + +bool +wasm_cluster_del_exec_env(WASMCluster *cluster, WASMExecEnv *exec_env); + +void +wasm_cluster_spread_exception(WASMExecEnv *exec_env); + +#ifdef __cplusplus +} +#endif + +#endif /* end of _THREAD_MANAGER_H */ diff --git a/core/iwasm/libraries/thread-mgr/thread_mgr.cmake b/core/iwasm/libraries/thread-mgr/thread_mgr.cmake new file mode 100644 index 000000000..c37a336b4 --- /dev/null +++ b/core/iwasm/libraries/thread-mgr/thread_mgr.cmake @@ -0,0 +1,13 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +set (THREAD_MGR_DIR ${CMAKE_CURRENT_LIST_DIR}) + +add_definitions (-DWASM_ENABLE_THREAD_MGR=1) + +include_directories(${THREAD_MGR_DIR}) + +file (GLOB source_all ${THREAD_MGR_DIR}/*.c) + +set (THREAD_MGR_SOURCE ${source_all}) + diff --git a/core/shared/platform/alios/alios_thread.c b/core/shared/platform/alios/alios_thread.c index 8dd9cb10d..f4028fbf3 100644 --- a/core/shared/platform/alios/alios_thread.c +++ b/core/shared/platform/alios/alios_thread.c @@ -242,16 +242,16 @@ os_mutex_destroy(korp_mutex *mutex) return BHT_OK; } -void +int os_mutex_lock(korp_mutex *mutex) { - aos_mutex_lock(mutex, AOS_WAIT_FOREVER); + return aos_mutex_lock(mutex, AOS_WAIT_FOREVER); } -void +int os_mutex_unlock(korp_mutex *mutex) { - aos_mutex_unlock(mutex); + return aos_mutex_unlock(mutex); } int diff --git a/core/shared/platform/common/posix/posix_thread.c b/core/shared/platform/common/posix/posix_thread.c index e2d45b450..54ff0e8cd 100644 --- a/core/shared/platform/common/posix/posix_thread.c +++ b/core/shared/platform/common/posix/posix_thread.c @@ -19,10 +19,12 @@ typedef struct { static void *os_thread_wrapper(void *arg) { thread_wrapper_arg * targ = arg; + thread_start_routine_t start_func = targ->start; + void *thread_arg = targ->arg; printf("THREAD CREATE %p\n", &targ); targ->stack = (void *)((uintptr_t)(&arg) & (uintptr_t)~0xfff); - targ->start(targ->arg); BH_FREE(targ); + start_func(thread_arg); return NULL; } @@ -114,7 +116,7 @@ int os_mutex_destroy(korp_mutex *mutex) locking the mutex indicates some logic error present in the program somewhere. Don't try to recover error for an existing unknown error.*/ -void os_mutex_lock(korp_mutex *mutex) +int os_mutex_lock(korp_mutex *mutex) { int ret; @@ -124,13 +126,14 @@ void os_mutex_lock(korp_mutex *mutex) printf("vm mutex lock failed (ret=%d)!\n", ret); exit(-1); } + return ret; } /* Returned error (EINVAL, EAGAIN and EPERM) from unlocking the mutex indicates some logic error present in the program somewhere. Don't try to recover error for an existing unknown error.*/ -void os_mutex_unlock(korp_mutex *mutex) +int os_mutex_unlock(korp_mutex *mutex) { int ret; @@ -140,6 +143,7 @@ void os_mutex_unlock(korp_mutex *mutex) printf("vm mutex unlock failed (ret=%d)!\n", ret); exit(-1); } + return ret; } int os_cond_init(korp_cond *cond) @@ -221,6 +225,16 @@ int os_thread_join(korp_tid thread, void **value_ptr) return pthread_join(thread, value_ptr); } +int os_thread_detach(korp_tid thread) +{ + return pthread_detach(thread); +} + +void os_thread_exit(void *retval) +{ + return pthread_exit(retval); +} + uint8 *os_thread_get_stack_boundary() { pthread_t self = pthread_self(); diff --git a/core/shared/platform/include/platform_api_extension.h b/core/shared/platform/include/platform_api_extension.h index d4553ae96..55cd9c99c 100644 --- a/core/shared/platform/include/platform_api_extension.h +++ b/core/shared/platform/include/platform_api_extension.h @@ -68,6 +68,22 @@ int os_thread_create_with_prio(korp_tid *p_tid, thread_start_routine_t start, */ int os_thread_join(korp_tid thread, void **retval); +/** + * Detach the thread specified by thread + * + * @param thread the thread to detach + * + * @return return 0 if success + */ +int os_thread_detach(korp_tid); + +/** + * Exit current thread + * + * @param retval the return value of the current thread + */ +void os_thread_exit(void *retval); + /** * Suspend execution of the calling thread for (at least) * usec microseconds diff --git a/core/shared/platform/include/platform_api_vmcore.h b/core/shared/platform/include/platform_api_vmcore.h index df7899520..acf6522ab 100644 --- a/core/shared/platform/include/platform_api_vmcore.h +++ b/core/shared/platform/include/platform_api_vmcore.h @@ -82,9 +82,9 @@ int os_mutex_init(korp_mutex *mutex); int os_mutex_destroy(korp_mutex *mutex); -void os_mutex_lock(korp_mutex *mutex); +int os_mutex_lock(korp_mutex *mutex); -void os_mutex_unlock(korp_mutex *mutex); +int os_mutex_unlock(korp_mutex *mutex); /************************************************** diff --git a/core/shared/platform/linux-sgx/sgx_thread.c b/core/shared/platform/linux-sgx/sgx_thread.c index 3f398949a..568b515af 100644 --- a/core/shared/platform/linux-sgx/sgx_thread.c +++ b/core/shared/platform/linux-sgx/sgx_thread.c @@ -24,14 +24,14 @@ int os_mutex_destroy(korp_mutex *mutex) return BHT_OK; } -void os_mutex_lock(korp_mutex *mutex) +int os_mutex_lock(korp_mutex *mutex) { - sgx_thread_mutex_lock(mutex); + return sgx_thread_mutex_lock(mutex); } -void os_mutex_unlock(korp_mutex *mutex) +int os_mutex_unlock(korp_mutex *mutex) { - sgx_thread_mutex_unlock(mutex); + return sgx_thread_mutex_unlock(mutex); } int os_cond_init(korp_cond *cond) diff --git a/core/shared/platform/zephyr/zephyr_thread.c b/core/shared/platform/zephyr/zephyr_thread.c index de54251bd..ebcb37b42 100644 --- a/core/shared/platform/zephyr/zephyr_thread.c +++ b/core/shared/platform/zephyr/zephyr_thread.c @@ -350,14 +350,14 @@ int os_mutex_destroy(korp_mutex *mutex) return BHT_OK; } -void os_mutex_lock(korp_mutex *mutex) +int os_mutex_lock(korp_mutex *mutex) { - k_mutex_lock(mutex, K_FOREVER); + return k_mutex_lock(mutex, K_FOREVER); } -void os_mutex_unlock(korp_mutex *mutex) +int os_mutex_unlock(korp_mutex *mutex) { - k_mutex_unlock(mutex); + return k_mutex_unlock(mutex); } int os_cond_init(korp_cond *cond) diff --git a/doc/build_wamr.md b/doc/build_wamr.md index 8d33ee6b1..b6d56307d 100644 --- a/doc/build_wamr.md +++ b/doc/build_wamr.md @@ -57,6 +57,16 @@ The script `runtime_lib.cmake` defined a number of variables for configuring the - **WAMR_BUILD_MINI_LOADER**=1/0, default to disable if not set Note: the mini loader doesn't check the integrity of the WASM binary file, user must ensure that the WASM file is not mal-formed. +#### **Enable shared memory feature** +- **WAMR_BUILD_SHARED_MEMORY**=1/0, default to disable if not set + +#### **Enable thread manager** +- **WAMR_BUILD_THREAD_MGR**=1/0, default to disable if not set + +#### **Enable Lib-pthread** +- **WAMR_BUILD_LIB_PTHREAD**=1/0, default to disable if not set +> Note: The dependent feature of lib pthread such as the `shared memory` and `thread manager` will be enabled automatically. + **Combination of configurations:** We can combine the configurations. For example, if we want to disable interpreter, enable AOT and WASI, we can run command: diff --git a/doc/pthread_library.md b/doc/pthread_library.md new file mode 100644 index 000000000..4e9409f38 --- /dev/null +++ b/doc/pthread_library.md @@ -0,0 +1,157 @@ +# WAMR pthread library + +WAMR provides a built-in library to support pthread APIs. You can call pthread APIs in your application source code. + +## Build and run +Suppose you have written a C program calling pthread_create() to create a thread, and the file name is main.c +``` C +#include +#include + +void *thread_routine(void *arg) +{ + printf("Enter thread\n"); + pthread_exit(NULL); + return NULL; +} + +int main(int argc, char** argv) +{ + pthread_t tid; + + if (0 != pthread_create(&tid, NULL, thread_routine, NULL)) { + printf("Failed to create thread\n"); + } + + if (0 != pthread_join(tid, NULL)) { + printf("Failed to join thread %d.\n", tid); + } + + printf("Exit\n"); + + return 0; +} +``` +**Build with libc-builtin** + +To build this C program into WebAssembly app with libc-builtin, you can use this command: +``` bash +/opt/wasi-sdk/bin/clang --target=wasm32 \ + --sysroot=${WAMR_ROOT}/wamr-sdk/app/libc-builtin-sysroot \ + -O3 -pthread -nostdlib -z stack-size=32768 \ + -Wl,--shared-memory \ + -Wl,--initial-memory=131072,--max-memory=131072 \ + -Wl,--allow-undefined-file=${WAMR_ROOT}/wamr-sdk/app/libc-builtin-sysroot/share/defined-symbols.txt \ + -Wl,--no-entry -Wl,--export=main \ + -Wl,--export=__heap_base,--export=__data_end \ + -Wl,--export=__wasm_call_ctors \ + main.c -o test.wasm +# -pthread: it will enable some dependent WebAssembly features for thread +# -nostdlib: disable the WASI standard library as we only support libc-builtin currently +# -z stack-size=: specify the total aux stack size +# -Wl,--export=__heap_base,--export=__data_end: export these globals so the runtime can resolve the total aux stack size and the start offset of the stack top +# -Wl,--export=__wasm_call_ctors: export the init function to initialize the passive data segments +``` + +**Build with libc-WASI** + +You can also build this program with WASI, but we need to make some changes to wasi-sysroot: + +1. disable malloc / free of wasi as they don't support shared memory + ``` bash + /opt/wasi-sdk/bin/llvm-ar -d /opt/wasi-sdk/share/wasi-sysroot/lib/wasm32-wasi/libc.a dlmalloc.o + ``` +2. copy the pthread.h to wasi-sysroot so the compiler can find it: + ``` bash + cp ${WAMR_ROOT}/wamr-sdk/app/libc-builtin-sysroot/include/pthread.h /opt/wasi-sdk/share/wasi-sysroot/include + ``` +> Note:
+>1. Remember to back up the original sysroot files +>2. wasi-sdk 9.0 or above are not supported, please use 7.0 or 8.0 + +Then build the program with this command: +``` bash +/opt/wasi-sdk/bin/clang -pthread -O3 \ + -Wl,--shared-memory,--max-memory=196608 \ + -Wl,--allow-undefined,--no-check-features \ + -Wl,--export=__heap_base,--export=__data_end \ + main.c -o test.wasm +# -Wl,--no-check-features: the errno.o in wasi-sysroot is not compatible with pthread feature, pass this option to avoid errors +``` + +Currently WAMR disables pthread library by default. To run the module with pthread support, please build the runtime with `-DWAMR_BUILD_LIB_PTHREAD=1` +``` bash +cd ${WAMR_ROOT}/product-mini/platforms/linux +mkdir build && cd build +cmake .. -DWAMR_BUILD_LIB_PTHREAD=1 +make +# Then you can run the wasm module above: +./iwasm test.wasm +``` + +> Note: Currently pthread library is not supported in AoT mode. + +[Here](../samples/multi-thread) is also a sample to show how wasm-apps use pthread APIs to create threads, and how to build it with cmake. You can build this sample and have a try: +``` bash +cd ${WAMR_ROOT}/samples/multi-thread +mkdir build && cd build +cmake .. +make +# Run wasm application +./iwasm wasm-apps/test.wasm +``` + + +## Aux stack seperation +The compiler may use some spaces in the linear memory as an auxiliary stack. When pthread is enabled, every thread should have its own aux stack space, so the total aux stack space reserved by the compiler will be divided into N + 1 parts, where N is the maximum number of threads that can be created by the user code. + +The default value of N is 4, which means you can create 4 threads at most. This value can be changed by an option if you are using product-mini: +``` bash +./iwasm --max-threads=n test.wasm +``` +If you are going to develop your own runtime product, you can use the API `wasm_runtime_set_max_thread_num` to set the value, or you can change the macro `CLUSTER_MAX_THREAD_NUM` in [config.h](../core/config.h), + +> Note: the total size of aux stack reserved by compiler can be set with `-z stack-size` option during compilation. If you need to create more threads, please set a larger value, otherwise it is easy to cause aux stack overflow. + +## Supported APIs +``` C +/* Thread APIs */ +int pthread_create(pthread_t *thread, const void *attr, + void *(*start_routine) (void *), void *arg); + +int pthread_join(pthread_t thread, void **retval); + +int pthread_detach(pthread_t thread); + +int pthread_cancel(pthread_t thread); + +pthread_t pthread_self(void); + +void pthread_exit(void *retval); + +/* Mutex APIs */ +int pthread_mutex_init(pthread_mutex_t *mutex, const void *attr); + +int pthread_mutex_lock(pthread_mutex_t *mutex); + +int pthread_mutex_unlock(pthread_mutex_t *mutex); + +int pthread_mutex_destroy(pthread_mutex_t *mutex); + +/* Cond APIs */ +int pthread_cond_init(pthread_cond_t *cond, const void *attr); + +int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); + +int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, + unsigned int useconds); + +int pthread_cond_signal(pthread_cond_t *cond); + +int pthread_cond_destroy(pthread_cond_t *cond); +``` + +## Known limits +- `pthread_attr_t`, `pthread_mutexattr_t` and `pthread_condattr_t` are not supported yet, so please pass `NULL` as the second argument of `pthread_create`, `pthread_mutex_init` and `pthread_cond_init`. +- The `errno.o` in wasi-sysroot is not compatible with this feature, so using errno in multi-thread may cause unexpected behavior. +- Currently `struct timespec` is not supported, so the prototype of `pthread_cond_timedwait` is different from the native one, it takes an unsigned int argument `useconds` to indicate the waiting time. \ No newline at end of file diff --git a/product-mini/platforms/linux/main.c b/product-mini/platforms/linux/main.c index 4926f8ac8..1d1a828a7 100644 --- a/product-mini/platforms/linux/main.c +++ b/product-mini/platforms/linux/main.c @@ -44,6 +44,9 @@ print_help() #if WASM_ENABLE_MULTI_MODULE != 0 printf(" --module-path= Indicate a module search path. default is current\n" " directory('./')\n"); +#endif +#if WASM_ENABLE_LIB_PTHREAD != 0 + printf(" --max-threads=n Set maximum thread number per cluster, default is 4\n"); #endif return 1; } @@ -125,6 +128,10 @@ app_instance_repl(wasm_module_inst_t module_inst) else cmd[n - 1] = '\0'; } + if (!strcmp(cmd, "__exit__")) { + printf("exit repl mode\n"); + break; + } app_argv = split_string(cmd, &app_argc); if (app_argv == NULL) { LOG_ERROR("Wasm prepare param failed: split string failed.\n"); @@ -300,6 +307,13 @@ main(int argc, char *argv[]) return print_help(); } } +#endif +#if WASM_ENABLE_LIB_PTHREAD != 0 + else if (!strncmp(argv[0], "--max-threads=", 14)) { + if (argv[0][14] == '\0') + return print_help(); + wasm_runtime_set_max_thread_num(atoi(argv[0] + 14)); + } #endif else return print_help(); diff --git a/samples/multi-thread/CMakeLists.txt b/samples/multi-thread/CMakeLists.txt new file mode 100644 index 000000000..52164bfeb --- /dev/null +++ b/samples/multi-thread/CMakeLists.txt @@ -0,0 +1,47 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required(VERSION 2.8) +project(pthread) + +################ runtime settings ################ +set(WAMR_BUILD_PLATFORM "linux") + +# Resetdefault linker flags +set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") +set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") + +# WAMR features switch +set(WAMR_BUILD_TARGET "X86_64") +set(WAMR_BUILD_INTERP 1) +set(WAMR_BUILD_AOT 0) +set(WAMR_BUILD_JIT 0) +set(WAMR_BUILD_LIBC_BUILTIN 1) +set(WAMR_BUILD_FAST_INTERP 1) +set(WAMR_BUILD_LIB_PTHREAD 1) + +# compiling and linking flags +set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections -pie -fPIE") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat -Wformat-security") + +# build out vmlib +set(WAMR_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../..) +include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) + +add_library(vmlib ${WAMR_RUNTIME_LIB_SOURCE}) +################################################ + + +################ wasm application ################ +add_subdirectory(wasm-apps) + +################ wamr runtime ################ +include (${SHARED_DIR}/utils/uncommon/shared_uncommon.cmake) + +set (RUNTIME_SOURCE_ALL + ${CMAKE_CURRENT_LIST_DIR}/../../product-mini/platforms/linux/main.c + ${UNCOMMON_SHARED_SOURCE} +) +add_executable (iwasm ${RUNTIME_SOURCE_ALL}) +target_link_libraries(iwasm vmlib -lpthread -lm) + diff --git a/samples/multi-thread/wasm-apps/CMakeLists.txt b/samples/multi-thread/wasm-apps/CMakeLists.txt new file mode 100644 index 000000000..8ef729fde --- /dev/null +++ b/samples/multi-thread/wasm-apps/CMakeLists.txt @@ -0,0 +1,34 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required(VERSION 2.8) +project(wasm-apps) + +set(WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../..) + +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_PROCESSOR wasm32) +set (CMAKE_SYSROOT ${WAMR_ROOT_DIR}/wamr-sdk/app/libc-builtin-sysroot) + +if (NOT DEFINED WASI_SDK_DIR) + set (WASI_SDK_DIR "/opt/wasi-sdk") +endif () + +set (CMAKE_C_FLAGS "-nostdlib -pthread -Qunused-arguments") +set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -z stack-size=32768") +set (CMAKE_C_COMPILER_TARGET "wasm32") +set (CMAKE_C_COMPILER "${WASI_SDK_DIR}/bin/clang") + +set (DEFINED_SYMBOLS +"${WAMR_ROOT_DIR}/wamr-sdk/app/libc-builtin-sysroot/share/defined-symbols.txt") + +set (CMAKE_EXE_LINKER_FLAGS + "-Wl,--shared-memory,--max-memory=131072, \ + -Wl,--no-entry,--strip-all,--export=main, \ + -Wl,--export=__heap_base,--export=__data_end \ + -Wl,--export=__wasm_call_ctors \ + -Wl,--allow-undefined-file=${DEFINED_SYMBOLS}" +) + +add_executable(test.wasm main.c) +target_link_libraries(test.wasm) \ No newline at end of file diff --git a/samples/multi-thread/wasm-apps/main.c b/samples/multi-thread/wasm-apps/main.c new file mode 100644 index 000000000..e871e555b --- /dev/null +++ b/samples/multi-thread/wasm-apps/main.c @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include +#include + +static pthread_mutex_t mutex; +static pthread_cond_t cond; + +static void *thread(void *arg) +{ + int *num = (int *)arg; + + pthread_mutex_lock(&mutex); + printf("thread start \n"); + + for (int i = 0; i < 10; i++) { + *num = *num + 1; + printf("num: %d\n", *num); + } + + pthread_cond_signal(&cond); + pthread_mutex_unlock(&mutex); + + printf("thread exit \n"); + + return NULL; +} + +int main(int argc, char *argv[]) +{ + pthread_t tid; + int num = 0, ret = -1; + + if (pthread_mutex_init(&mutex, NULL) != 0) { + printf("Failed to init mutex.\n"); + return -1; + } + if (pthread_cond_init(&cond, NULL) != 0) { + printf("Failed to init cond.\n"); + goto fail1; + } + + pthread_mutex_lock(&mutex); + if (pthread_create(&tid, NULL, thread, &num) != 0) { + printf("Failed to create thread.\n"); + goto fail2; + } + + printf("cond wait start\n"); + pthread_cond_wait(&cond, &mutex); + pthread_mutex_unlock(&mutex); + printf("cond wait success.\n"); + + if (pthread_join(tid, NULL) != 0) { + printf("Failed to join thread.\n"); + } + + ret = 0; + +fail2: + pthread_cond_destroy(&cond); +fail1: + pthread_mutex_destroy(&mutex); + + return ret; +} \ No newline at end of file diff --git a/wamr-sdk/app/libc-builtin-sysroot/include/pthread.h b/wamr-sdk/app/libc-builtin-sysroot/include/pthread.h new file mode 100644 index 000000000..b10f4b59c --- /dev/null +++ b/wamr-sdk/app/libc-builtin-sysroot/include/pthread.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _WAMR_LIB_PTHREAD_H +#define _WAMR_LIB_PTHREAD_H + +/* Data type define of pthread, mutex and cond */ +typedef unsigned int pthread_t; +typedef unsigned int pthread_mutex_t; +typedef unsigned int pthread_cond_t; + +/* Thread APIs */ +int pthread_create(pthread_t *thread, const void *attr, + void *(*start_routine) (void *), void *arg); + +int pthread_join(pthread_t thread, void **retval); + +int pthread_detach(pthread_t thread); + +int pthread_cancel(pthread_t thread); + +pthread_t pthread_self(void); + +void pthread_exit(void *retval); + +/* Mutex APIs */ +int pthread_mutex_init(pthread_mutex_t *mutex, const void *attr); + +int pthread_mutex_lock(pthread_mutex_t *mutex); + +int pthread_mutex_unlock(pthread_mutex_t *mutex); + +int pthread_mutex_destroy(pthread_mutex_t *mutex); + +/* Cond APIs */ +int pthread_cond_init(pthread_cond_t *cond, const void *attr); + +int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); + +int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, + unsigned int useconds); + +int pthread_cond_signal(pthread_cond_t *cond); + +int pthread_cond_destroy(pthread_cond_t *cond); + +#endif /* end of _WAMR_LIB_PTHREAD_H */ \ No newline at end of file diff --git a/wamr-sdk/app/libc-builtin-sysroot/share/defined-symbols.txt b/wamr-sdk/app/libc-builtin-sysroot/share/defined-symbols.txt index 6d9c46f2a..2b878b84f 100644 --- a/wamr-sdk/app/libc-builtin-sysroot/share/defined-symbols.txt +++ b/wamr-sdk/app/libc-builtin-sysroot/share/defined-symbols.txt @@ -62,3 +62,18 @@ isxdigit tolower toupper isalnum +pthread_create +pthread_join +pthread_detach +pthread_cancel +pthread_self +pthread_exit +pthread_mutex_init +pthread_mutex_lock +pthread_mutex_unlock +pthread_mutex_destroy +pthread_cond_init +pthread_cond_wait +pthread_cond_timedwait +pthread_cond_signal +pthread_cond_destroy From acb68c64c2603515926baeb90cd7c9daa9cfec61 Mon Sep 17 00:00:00 2001 From: Xu Jun <693788454@qq.com> Date: Tue, 16 Jun 2020 15:01:35 +0800 Subject: [PATCH 020/207] update doc for multi-thread (#284) --- README.md | 1 + core/iwasm/common/wasm_runtime_common.c | 8 ++++++++ core/iwasm/common/wasm_shared_memory.c | 3 +++ core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c | 2 -- 4 files changed, 12 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e2276b95f..41e028b1a 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,7 @@ iwasm VM core - [Embeddable with the supporting C API's](./doc/embed_wamr.md) - [The mechanism for exporting native API's to WASM applications](./doc/export_native_api.md) - [Multiple modules as dependencies](./doc/multi_module.md) +- [Thread management and pthread library](./doc/pthread_library.md) ### post-MVP features - [Non-trapping float-to-int conversions](https://github.com/WebAssembly/nontrapping-float-to-int-conversions) diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index 50b459bf8..986348aaf 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -542,6 +542,10 @@ wasm_exec_env_set_aux_stack(WASMExecEnv *exec_env, if (module_inst->module_type == Wasm_Module_Bytecode) { return wasm_set_aux_stack(exec_env, start_offset, size); } +#endif +#if WASM_ENABLE_AOT != 0 + /* TODO: implement set aux stack in AoT mode */ + (void)module_inst; #endif return false; } @@ -556,6 +560,10 @@ wasm_exec_env_get_aux_stack(WASMExecEnv *exec_env, if (module_inst->module_type == Wasm_Module_Bytecode) { return wasm_get_aux_stack(exec_env, start_offset, size); } +#endif +#if WASM_ENABLE_AOT != 0 + /* TODO: implement get aux stack in AoT mode */ + (void)module_inst; #endif return false; } diff --git a/core/iwasm/common/wasm_shared_memory.c b/core/iwasm/common/wasm_shared_memory.c index 5fbfe50fe..38baee9c9 100644 --- a/core/iwasm/common/wasm_shared_memory.c +++ b/core/iwasm/common/wasm_shared_memory.c @@ -88,6 +88,7 @@ shared_memory_dec_reference(WASMModuleCommon *module) return -1; } +#if WASM_ENABLE_INTERP != 0 WASMMemoryInstance* shared_memory_get_memory_inst(WASMSharedMemNode *node) { @@ -121,4 +122,6 @@ shared_memory_set_memory_inst(WASMModuleCommon *module, return node; } +#endif /* end of WASM_ENABLE_INTERP */ + #endif /* end of WASM_ENABLE_SHARED_MEMORY */ diff --git a/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c b/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c index 006e5519e..88ebc0131 100644 --- a/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c +++ b/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c @@ -1131,11 +1131,9 @@ typedef struct WASMNativeGlobalDef { } WASMNativeGlobalDef; static WASMNativeGlobalDef native_global_defs[] = { -#if WASM_ENABLE_SPEC_TEST != 0 { "spectest", "global_i32", .global_data.i32 = 666 }, { "spectest", "global_f32", .global_data.f32 = 666.6 }, { "spectest", "global_f64", .global_data.f64 = 666.6 }, -#endif { "test", "global-i32", .global_data.i32 = 0 }, { "test", "global-f32", .global_data.f32 = 0 }, { "env", "STACKTOP", .global_data.u32 = 0 }, From e3c04e66841df6025a465c19233fc7fd4cec7ab7 Mon Sep 17 00:00:00 2001 From: Xu Jun <693788454@qq.com> Date: Thu, 18 Jun 2020 11:37:31 +0800 Subject: [PATCH 021/207] support pthread_key related APIs (#288) --- .../lib-pthread/lib_pthread_wrapper.c | 280 +++++++++++++++++- doc/pthread_library.md | 11 +- .../libc-builtin-sysroot/include/pthread.h | 12 +- .../share/defined-symbols.txt | 4 + 4 files changed, 304 insertions(+), 3 deletions(-) diff --git a/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c b/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c index 9f19f8fcc..f7aa9083f 100644 --- a/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c +++ b/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c @@ -10,6 +10,8 @@ #include "../common/wasm_runtime_common.h" #include "thread_manager.h" +#define WAMR_PTHREAD_KEYS_MAX 32 + #define get_module(exec_env) \ wasm_exec_env_get_module(exec_env) @@ -62,10 +64,27 @@ enum cond_status_t { COND_DESTROYED, }; +typedef struct ThreadKeyValueNode { + bh_list_link l; + wasm_exec_env_t exec_env; + int32 thread_key_values[WAMR_PTHREAD_KEYS_MAX]; +} ThreadKeyValueNode; + +typedef struct KeyData { + int32 destructor_func; + bool is_created; +} KeyData; + typedef struct ClusterInfoNode { bh_list_link l; WASMCluster *cluster; HashMap *thread_info_map; + /* Key data list */ + KeyData key_data_list[WAMR_PTHREAD_KEYS_MAX]; + korp_mutex key_data_list_lock; + /* Every node contains the key value list for a thread */ + bh_list thread_list_head; + bh_list *thread_list; } ClusterInfoNode; typedef struct ThreadInfoNode { @@ -180,6 +199,132 @@ get_cluster_info(WASMCluster *cluster) return NULL; } +static KeyData* +key_data_list_lookup(wasm_exec_env_t exec_env, int32 key) +{ + ClusterInfoNode *node; + WASMCluster *cluster = + wasm_exec_env_get_cluster(exec_env); + + if ((node = get_cluster_info(cluster))) { + return (key >= 0 && key < WAMR_PTHREAD_KEYS_MAX + && node->key_data_list[key].is_created) + ? &(node->key_data_list[key]) : NULL; + } + + return NULL; +} + +/* Lookup the thread key value node for a thread, + create a new one if failed + This design will reduce the memory usage. If the thread doesn't use + the local storage, it will not occupy memory space +*/ +static int32* +key_value_list_lookup_or_create(wasm_exec_env_t exec_env, + ClusterInfoNode *info, int32 key) +{ + KeyData *key_node; + ThreadKeyValueNode *data; + + /* Check if the key is valid */ + key_node = key_data_list_lookup(exec_env, key); + if (!key_node) { + return NULL; + } + + /* Find key values node */ + data = bh_list_first_elem(info->thread_list); + while (data) { + if (data->exec_env == exec_env) + return data->thread_key_values; + data = bh_list_elem_next(data); + } + + /* If not found, create a new node for this thread */ + if (!(data = wasm_runtime_malloc(sizeof(ThreadKeyValueNode)))) + return NULL; + memset(data, 0, sizeof(ThreadKeyValueNode)); + data->exec_env = exec_env; + + if (bh_list_insert(info->thread_list, data) != 0) { + wasm_runtime_free(data); + return NULL; + } + + return data->thread_key_values; +} + +static void +call_key_destructor(wasm_exec_env_t exec_env) +{ + int32 i; + uint32 destructor_index; + KeyData *key_node; + ThreadKeyValueNode *value_node; + WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env); + ClusterInfoNode *info = get_cluster_info(cluster); + + value_node = bh_list_first_elem(info->thread_list); + while (value_node) { + if (value_node->exec_env == exec_env) + break; + value_node = bh_list_elem_next(value_node); + } + + /* This thread hasn't created key value node */ + if (!value_node) + return; + + /* Destroy key values */ + for (i = 0; i < WAMR_PTHREAD_KEYS_MAX; i++) { + if (value_node->thread_key_values[i] != 0) { + int32 value = value_node->thread_key_values[i]; + os_mutex_lock(&info->key_data_list_lock); + + if ((key_node = key_data_list_lookup(exec_env, i))) + destructor_index = key_node->destructor_func; + else + destructor_index = 0; + os_mutex_unlock(&info->key_data_list_lock); + + /* reset key value */ + value_node->thread_key_values[i] = 0; + + /* Call the destructor func provided by app */ + if (destructor_index) { + uint32 argv[1]; + + argv[0] = value; + wasm_runtime_call_indirect(exec_env, + destructor_index, + 1, argv); + } + } + } + + bh_list_remove(info->thread_list, value_node); + wasm_runtime_free(value_node); +} + +static void +destroy_thread_key_value_list(bh_list *list) +{ + ThreadKeyValueNode *node, *next; + + /* There should be only one node for main thread */ + bh_assert(list->len <= 1); + + if (list->len) { + node = bh_list_first_elem(list); + while (node) { + next = bh_list_elem_next(node); + call_key_destructor(node->exec_env); + node = next; + } + } +} + static ClusterInfoNode* create_cluster_info(WASMCluster *cluster) { @@ -189,6 +334,16 @@ create_cluster_info(WASMCluster *cluster) if (!(node = wasm_runtime_malloc(sizeof(ClusterInfoNode)))) { return NULL; } + memset(node, 0, sizeof(WASMCluster)); + + node->thread_list = &node->thread_list_head; + ret = bh_list_init(node->thread_list); + bh_assert(ret == BH_LIST_SUCCESS); + + if (os_mutex_init(&node->key_data_list_lock) != 0) { + wasm_runtime_free(node); + return NULL; + } node->cluster = cluster; if (!(node->thread_info_map = @@ -197,12 +352,13 @@ create_cluster_info(WASMCluster *cluster) (KeyEqualFunc)thread_handle_equal, NULL, thread_info_destroy))) { + os_mutex_destroy(&node->key_data_list_lock); wasm_runtime_free(node); return NULL; } os_mutex_lock(&pthread_global_lock); ret = bh_list_insert(&cluster_info_list, node); - bh_assert(ret == 0); + bh_assert(ret == BH_LIST_SUCCESS); os_mutex_unlock(&pthread_global_lock); (void)ret; @@ -215,6 +371,10 @@ destroy_cluster_info(WASMCluster *cluster) ClusterInfoNode *node = get_cluster_info(cluster); if (node) { bh_hash_map_destroy(node->thread_info_map); + destroy_thread_key_value_list(node->thread_list); + os_mutex_destroy(&node->key_data_list_lock); + + /* Remove from the cluster info list */ os_mutex_lock(&pthread_global_lock); bh_list_remove(&cluster_info_list, node); wasm_runtime_free(node); @@ -331,6 +491,9 @@ pthread_start_routine(void *arg) wasm_cluster_spread_exception(exec_env); } + /* destroy pthread key values */ + call_key_destructor(exec_env); + /* routine exit, destroy instance */ wasm_runtime_deinstantiate_internal(module_inst, true); @@ -509,6 +672,9 @@ pthread_exit_wrapper(wasm_exec_env_t exec_env, int32 retval_offset) if (!args) return; + /* destroy pthread key values */ + call_key_destructor(exec_env); + /* routine exit, destroy instance */ wasm_runtime_deinstantiate_internal(module_inst, true); @@ -702,6 +868,114 @@ pthread_cond_destroy_wrapper(wasm_exec_env_t exec_env, uint32 *cond) return ret_val; } +static int32 +pthread_key_create_wrapper(wasm_exec_env_t exec_env, int32 *key, + int32 destructor_elem_index) +{ + uint32 i; + WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env); + ClusterInfoNode *info = get_cluster_info(cluster); + + if (!info) { + /* The user may call pthread_key_create in main thread, + in this case the cluster info hasn't been created */ + if (!(info = create_cluster_info(cluster))) { + return -1; + } + } + + os_mutex_lock(&info->key_data_list_lock); + for (i = 0; i < WAMR_PTHREAD_KEYS_MAX; i++) { + if (!info->key_data_list[i].is_created) { + break; + } + } + + if (i == WAMR_PTHREAD_KEYS_MAX) { + os_mutex_unlock(&info->key_data_list_lock); + return -1; + } + + info->key_data_list[i].destructor_func = destructor_elem_index; + info->key_data_list[i].is_created = true; + *key = i; + os_mutex_unlock(&info->key_data_list_lock); + + return 0; +} + +static int32 +pthread_setspecific_wrapper(wasm_exec_env_t exec_env, int32 key, + int32 value_offset) +{ + WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env); + ClusterInfoNode *info = get_cluster_info(cluster); + int32 *key_values; + + if (!info) + return -1; + + os_mutex_lock(&info->key_data_list_lock); + + key_values = key_value_list_lookup_or_create(exec_env, info, key); + if (!key_values) { + os_mutex_unlock(&info->key_data_list_lock); + return 0; + } + + key_values[key] = value_offset; + os_mutex_unlock(&info->key_data_list_lock); + + return 0; +} + +static int32 +pthread_getspecific_wrapper(wasm_exec_env_t exec_env, int32 key) +{ + WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env); + ClusterInfoNode *info = get_cluster_info(cluster); + int32 ret, *key_values; + + if (!info) + return -1; + + os_mutex_lock(&info->key_data_list_lock); + + key_values = key_value_list_lookup_or_create(exec_env, info, key); + if (!key_values) { + os_mutex_unlock(&info->key_data_list_lock); + return 0; + } + + ret = key_values[key]; + os_mutex_unlock(&info->key_data_list_lock); + + return ret; +} + +static int32 +pthread_key_delete_wrapper(wasm_exec_env_t exec_env, int32 key) +{ + KeyData *data; + WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env); + ClusterInfoNode *info = get_cluster_info(cluster); + + if (!info) + return -1; + + os_mutex_lock(&info->key_data_list_lock); + data = key_data_list_lookup(exec_env, key); + if (!data) { + os_mutex_unlock(&info->key_data_list_lock); + return -1; + } + + memset(data, 0, sizeof(KeyData)); + os_mutex_unlock(&info->key_data_list_lock); + + return 0; +} + #define REG_NATIVE_FUNC(func_name, signature) \ { #func_name, func_name##_wrapper, signature, NULL } @@ -721,6 +995,10 @@ static NativeSymbol native_symbols_lib_pthread[] = { REG_NATIVE_FUNC(pthread_cond_timedwait, "(**i)i"), REG_NATIVE_FUNC(pthread_cond_signal, "(*)i"), REG_NATIVE_FUNC(pthread_cond_destroy, "(*)i"), + REG_NATIVE_FUNC(pthread_key_create, "(*i)i"), + REG_NATIVE_FUNC(pthread_setspecific, "(ii)i"), + REG_NATIVE_FUNC(pthread_getspecific, "(i)i"), + REG_NATIVE_FUNC(pthread_key_delete, "(i)i"), }; uint32 diff --git a/doc/pthread_library.md b/doc/pthread_library.md index 4e9409f38..622bdfa27 100644 --- a/doc/pthread_library.md +++ b/doc/pthread_library.md @@ -47,7 +47,7 @@ To build this C program into WebAssembly app with libc-builtin, you can use this -Wl,--export=__wasm_call_ctors \ main.c -o test.wasm # -pthread: it will enable some dependent WebAssembly features for thread -# -nostdlib: disable the WASI standard library as we only support libc-builtin currently +# -nostdlib: disable the WASI standard library as we are using WAMR builtin-libc # -z stack-size=: specify the total aux stack size # -Wl,--export=__heap_base,--export=__data_end: export these globals so the runtime can resolve the total aux stack size and the start offset of the stack top # -Wl,--export=__wasm_call_ctors: export the init function to initialize the passive data segments @@ -149,6 +149,15 @@ int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, int pthread_cond_signal(pthread_cond_t *cond); int pthread_cond_destroy(pthread_cond_t *cond); + +/* Pthread key APIs */ +int pthread_key_create(pthread_key_t *key, void (*destructor)(void *)); + +int pthread_setspecific(pthread_key_t key, const void *value); + +void *pthread_getspecific(pthread_key_t key); + +int pthread_key_delete(pthread_key_t key); ``` ## Known limits diff --git a/wamr-sdk/app/libc-builtin-sysroot/include/pthread.h b/wamr-sdk/app/libc-builtin-sysroot/include/pthread.h index b10f4b59c..38be34e13 100644 --- a/wamr-sdk/app/libc-builtin-sysroot/include/pthread.h +++ b/wamr-sdk/app/libc-builtin-sysroot/include/pthread.h @@ -6,10 +6,11 @@ #ifndef _WAMR_LIB_PTHREAD_H #define _WAMR_LIB_PTHREAD_H -/* Data type define of pthread, mutex and cond */ +/* Data type define of pthread, mutex, cond and key */ typedef unsigned int pthread_t; typedef unsigned int pthread_mutex_t; typedef unsigned int pthread_cond_t; +typedef unsigned int pthread_key_t; /* Thread APIs */ int pthread_create(pthread_t *thread, const void *attr, @@ -46,4 +47,13 @@ int pthread_cond_signal(pthread_cond_t *cond); int pthread_cond_destroy(pthread_cond_t *cond); +/* Pthread key APIs */ +int pthread_key_create(pthread_key_t *key, void (*destructor)(void *)); + +int pthread_setspecific(pthread_key_t key, const void *value); + +void *pthread_getspecific(pthread_key_t key); + +int pthread_key_delete(pthread_key_t key); + #endif /* end of _WAMR_LIB_PTHREAD_H */ \ No newline at end of file diff --git a/wamr-sdk/app/libc-builtin-sysroot/share/defined-symbols.txt b/wamr-sdk/app/libc-builtin-sysroot/share/defined-symbols.txt index 2b878b84f..08a378462 100644 --- a/wamr-sdk/app/libc-builtin-sysroot/share/defined-symbols.txt +++ b/wamr-sdk/app/libc-builtin-sysroot/share/defined-symbols.txt @@ -77,3 +77,7 @@ pthread_cond_wait pthread_cond_timedwait pthread_cond_signal pthread_cond_destroy +pthread_key_create +pthread_setspecific +pthread_getspecific +pthread_key_delete From 548926ab1a483b397ceee3cc6e5c027b8c1d8a49 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sat, 27 Jun 2020 02:36:59 -0700 Subject: [PATCH 022/207] Rename "master" branch to "main" Update all links accordingly. Also update links to other repositories whose branches have renamed. The references to repositories whose branches have not renamed should be referencing specific commits anyway, so reference those specific commits by hash. --- README.md | 2 +- .../sandboxed-system-primitives/include/wasmtime_ssp.h | 2 +- .../libc-wasi/sandboxed-system-primitives/src/README.md | 4 ++-- .../libc-wasi/sandboxed-system-primitives/src/locking.h | 4 ++-- .../sandboxed-system-primitives/src/numeric_limits.h | 4 ++-- .../libc-wasi/sandboxed-system-primitives/src/posix.c | 4 ++-- .../libc-wasi/sandboxed-system-primitives/src/posix.h | 4 ++-- .../libc-wasi/sandboxed-system-primitives/src/queue.h | 4 ++-- .../libc-wasi/sandboxed-system-primitives/src/random.c | 4 ++-- .../libc-wasi/sandboxed-system-primitives/src/random.h | 4 ++-- .../libc-wasi/sandboxed-system-primitives/src/refcount.h | 4 ++-- .../libc-wasi/sandboxed-system-primitives/src/rights.h | 4 ++-- .../libc-wasi/sandboxed-system-primitives/src/signals.h | 4 ++-- .../libc-wasi/sandboxed-system-primitives/src/ssp_config.h | 4 ++-- .../libraries/libc-wasi/sandboxed-system-primitives/src/str.c | 4 ++-- .../libraries/libc-wasi/sandboxed-system-primitives/src/str.h | 4 ++-- core/shared/platform/linux-sgx/sgx_rsrv_mem_mngr.h | 2 +- samples/basic/src/main.c | 2 +- .../wasm_django/devices/templates/help.html | 2 +- 19 files changed, 33 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 41e028b1a..8cbd41d0f 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ iwasm VM core - [Non-trapping float-to-int conversions](https://github.com/WebAssembly/nontrapping-float-to-int-conversions) - [Sign-extension operators](https://github.com/WebAssembly/sign-extension-ops) - [Bulk memory operations](https://github.com/WebAssembly/bulk-memory-operations) -- [Shared memmory](https://github.com/WebAssembly/threads/blob/master/proposals/threads/Overview.md#shared-linear-memory) +- [Shared memmory](https://github.com/WebAssembly/threads/blob/main/proposals/threads/Overview.md#shared-linear-memory) ### Performance and memory usage The WAMR performance, footprint and memory usage data are available at the [performance](../../wiki/Performance) wiki page. diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h index c24530917..1c2988cbd 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h @@ -1,6 +1,6 @@ /* * Part of the Wasmtime Project, under the Apache License v2.0 with LLVM Exceptions. - * See https://github.com/CraneStation/wasmtime/blob/master/LICENSE for license information. + * See https://github.com/bytecodealliance/wasmtime/blob/main/LICENSE for license information. * * This file declares an interface similar to WASI, but augmented to expose * some implementation details such as the curfds arguments that we pass diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/README.md b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/README.md index fe73057f5..b4d55d803 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/README.md +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/README.md @@ -1,4 +1,4 @@ -This directory consists of selected files copied from the [libemulator] +This directory consists of selected files copied from the [src/libemulator] directory in the [cloudabi-utils] repository, with minor modifications, along with the accompanying LICENSE file from that repository. @@ -10,5 +10,5 @@ which is dated Tue Jun 25 17:22:07 2019 -0700 . -[libemulator]: https://github.com/NuxiNL/cloudabi-utils/tree/master/src/libemulator +[libemulator]: https://github.com/NuxiNL/cloudabi-utils/tree/223dadc53248552db43e012c67ed08cf416a2b12/src/libemulator [cloudabi-utils]: https://github.com/NuxiNL/cloudabi-utils diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/locking.h b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/locking.h index 97d11bef1..1ae69667b 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/locking.h +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/locking.h @@ -1,8 +1,8 @@ // Part of the Wasmtime Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://github.com/CraneStation/wasmtime/blob/master/LICENSE for license information. +// See https://github.com/bytecodealliance/wasmtime/blob/main/LICENSE for license information. // // Significant parts of this file are derived from cloudabi-utils. See -// https://github.com/CraneStation/wasmtime/blob/master/lib/wasi/sandboxed-system-primitives/src/LICENSE +// https://github.com/bytecodealliance/wasmtime/blob/main/lib/wasi/sandboxed-system-primitives/src/LICENSE // for license information. // // The upstream file contains the following copyright notice: diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/numeric_limits.h b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/numeric_limits.h index 30dddd19a..b6e3787db 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/numeric_limits.h +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/numeric_limits.h @@ -1,8 +1,8 @@ // Part of the Wasmtime Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://github.com/CraneStation/wasmtime/blob/master/LICENSE for license information. +// See https://github.com/bytecodealliance/wasmtime/blob/main/LICENSE for license information. // // Significant parts of this file are derived from cloudabi-utils. See -// https://github.com/CraneStation/wasmtime/blob/master/lib/wasi/sandboxed-system-primitives/src/LICENSE +// https://github.com/bytecodealliance/wasmtime/blob/main/lib/wasi/sandboxed-system-primitives/src/LICENSE // for license information. // // The upstream file contains the following copyright notice: diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c index bcad83617..ef597252d 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c @@ -1,8 +1,8 @@ // Part of the Wasmtime Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://github.com/CraneStation/wasmtime/blob/master/LICENSE for license information. +// See https://github.com/bytecodealliance/wasmtime/blob/main/LICENSE for license information. // // Significant parts of this file are derived from cloudabi-utils. See -// https://github.com/CraneStation/wasmtime/blob/master/lib/wasi/sandboxed-system-primitives/src/LICENSE +// https://github.com/bytecodealliance/wasmtime/blob/main/lib/wasi/sandboxed-system-primitives/src/LICENSE // for license information. // // The upstream file contains the following copyright notice: diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.h b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.h index f4def4bc4..01de1cb27 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.h +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.h @@ -1,8 +1,8 @@ // Part of the Wasmtime Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://github.com/CraneStation/wasmtime/blob/master/LICENSE for license information. +// See https://github.com/bytecodealliance/wasmtime/blob/main/LICENSE for license information. // // Significant parts of this file are derived from cloudabi-utils. See -// https://github.com/CraneStation/wasmtime/blob/master/lib/wasi/sandboxed-system-primitives/src/LICENSE +// https://github.com/bytecodealliance/wasmtime/blob/main/lib/wasi/sandboxed-system-primitives/src/LICENSE // for license information. // // The upstream file contains the following copyright notice: diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/queue.h b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/queue.h index c46190a85..62cbd4e93 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/queue.h +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/queue.h @@ -1,8 +1,8 @@ // Part of the Wasmtime Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://github.com/CraneStation/wasmtime/blob/master/LICENSE for license information. +// See https://github.com/bytecodealliance/wasmtime/blob/main/LICENSE for license information. // // Significant parts of this file are derived from cloudabi-utils. See -// https://github.com/CraneStation/wasmtime/blob/master/lib/wasi/sandboxed-system-primitives/src/LICENSE +// https://github.com/bytecodealliance/wasmtime/blob/main/lib/wasi/sandboxed-system-primitives/src/LICENSE // for license information. // // The upstream file contains the following copyright notice: diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/random.c b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/random.c index 41618bd58..914b1158d 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/random.c +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/random.c @@ -1,8 +1,8 @@ // Part of the Wasmtime Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://github.com/CraneStation/wasmtime/blob/master/LICENSE for license information. +// See https://github.com/bytecodealliance/wasmtime/blob/main/LICENSE for license information. // // Significant parts of this file are derived from cloudabi-utils. See -// https://github.com/CraneStation/wasmtime/blob/master/lib/wasi/sandboxed-system-primitives/src/LICENSE +// https://github.com/bytecodealliance/wasmtime/blob/main/lib/wasi/sandboxed-system-primitives/src/LICENSE // for license information. // // The upstream file contains the following copyright notice: diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/random.h b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/random.h index d87a292cf..b79ce92fe 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/random.h +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/random.h @@ -1,8 +1,8 @@ // Part of the Wasmtime Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://github.com/CraneStation/wasmtime/blob/master/LICENSE for license information. +// See https://github.com/bytecodealliance/wasmtime/blob/main/LICENSE for license information. // // Significant parts of this file are derived from cloudabi-utils. See -// https://github.com/CraneStation/wasmtime/blob/master/lib/wasi/sandboxed-system-primitives/src/LICENSE +// https://github.com/bytecodealliance/wasmtime/blob/main/lib/wasi/sandboxed-system-primitives/src/LICENSE // for license information. // // The upstream file contains the following copyright notice: diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/refcount.h b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/refcount.h index 0d516e2d1..6faa51a29 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/refcount.h +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/refcount.h @@ -1,8 +1,8 @@ // Part of the Wasmtime Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://github.com/CraneStation/wasmtime/blob/master/LICENSE for license information. +// See https://github.com/bytecodealliance/wasmtime/blob/main/LICENSE for license information. // // Significant parts of this file are derived from cloudabi-utils. See -// https://github.com/CraneStation/wasmtime/blob/master/lib/wasi/sandboxed-system-primitives/src/LICENSE +// https://github.com/bytecodealliance/wasmtime/blob/main/lib/wasi/sandboxed-system-primitives/src/LICENSE // for license information. // // The upstream file contains the following copyright notice: diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/rights.h b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/rights.h index 69349e45c..565635e7b 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/rights.h +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/rights.h @@ -1,8 +1,8 @@ // Part of the Wasmtime Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://github.com/CraneStation/wasmtime/blob/master/LICENSE for license information. +// See https://github.com/bytecodealliance/wasmtime/blob/main/LICENSE for license information. // // Significant parts of this file are derived from cloudabi-utils. See -// https://github.com/CraneStation/wasmtime/blob/master/lib/wasi/sandboxed-system-primitives/src/LICENSE +// https://github.com/bytecodealliance/wasmtime/blob/main/lib/wasi/sandboxed-system-primitives/src/LICENSE // for license information. // // The upstream file contains the following copyright notice: diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/signals.h b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/signals.h index 16f5d575c..ead95e79a 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/signals.h +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/signals.h @@ -1,8 +1,8 @@ // Part of the Wasmtime Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://github.com/CraneStation/wasmtime/blob/master/LICENSE for license information. +// See https://github.com/bytecodealliance/wasmtime/blob/main/LICENSE for license information. // // Significant parts of this file are derived from cloudabi-utils. See -// https://github.com/CraneStation/wasmtime/blob/master/lib/wasi/sandboxed-system-primitives/src/LICENSE +// https://github.com/bytecodealliance/wasmtime/blob/main/lib/wasi/sandboxed-system-primitives/src/LICENSE // for license information. // // The upstream file contains the following copyright notice: diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/ssp_config.h b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/ssp_config.h index d4af40774..de5898b84 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/ssp_config.h +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/ssp_config.h @@ -1,8 +1,8 @@ // Part of the Wasmtime Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://github.com/CraneStation/wasmtime/blob/master/LICENSE for license information. +// See https://github.com/bytecodealliance/wasmtime/blob/main/LICENSE for license information. // // Significant parts of this file are derived from cloudabi-utils. See -// https://github.com/CraneStation/wasmtime/blob/master/lib/wasi/sandboxed-system-primitives/src/LICENSE +// https://github.com/bytecodealliance/wasmtime/blob/main/lib/wasi/sandboxed-system-primitives/src/LICENSE // for license information. // // The upstream file contains the following copyright notice: diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/str.c b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/str.c index 87b9ba75f..040d5845c 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/str.c +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/str.c @@ -1,8 +1,8 @@ // Part of the Wasmtime Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://github.com/CraneStation/wasmtime/blob/master/LICENSE for license information. +// See https://github.com/bytecodealliance/wasmtime/blob/main/LICENSE for license information. // // Significant parts of this file are derived from cloudabi-utils. See -// https://github.com/CraneStation/wasmtime/blob/master/lib/wasi/sandboxed-system-primitives/src/LICENSE +// https://github.com/bytecodealliance/wasmtime/blob/main/lib/wasi/sandboxed-system-primitives/src/LICENSE // for license information. // // The upstream file contains the following copyright notice: diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/str.h b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/str.h index 8399415e7..bf46dda34 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/str.h +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/str.h @@ -1,8 +1,8 @@ // Part of the Wasmtime Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://github.com/CraneStation/wasmtime/blob/master/LICENSE for license information. +// See https://github.com/bytecodealliance/wasmtime/blob/main/LICENSE for license information. // // Significant parts of this file are derived from cloudabi-utils. See -// https://github.com/CraneStation/wasmtime/blob/master/lib/wasi/sandboxed-system-primitives/src/LICENSE +// https://github.com/bytecodealliance/wasmtime/blob/main/lib/wasi/sandboxed-system-primitives/src/LICENSE // for license information. // // The upstream file contains the following copyright notice: diff --git a/core/shared/platform/linux-sgx/sgx_rsrv_mem_mngr.h b/core/shared/platform/linux-sgx/sgx_rsrv_mem_mngr.h index 18f813dd0..b32a68ba5 100644 --- a/core/shared/platform/linux-sgx/sgx_rsrv_mem_mngr.h +++ b/core/shared/platform/linux-sgx/sgx_rsrv_mem_mngr.h @@ -30,7 +30,7 @@ */ /* - * This file is copied from https://github.com/intel/linux-sgx/blob/master/common/inc/internal/sgx_rsrv_mem_mngr.h + * This file is copied from https://github.com/intel/linux-sgx/blob/4589daddd58bec7367a6a9de3fe301e6de17671a/common/inc/internal/sgx_rsrv_mem_mngr.h * The reason we copied here is that the official SGX SDK release has * not included this header file yet. */ diff --git a/samples/basic/src/main.c b/samples/basic/src/main.c index bbcd83359..7411434f6 100644 --- a/samples/basic/src/main.c +++ b/samples/basic/src/main.c @@ -61,7 +61,7 @@ int main(int argc, char *argv_main[]) // Note: the array must be static defined since runtime // will keep it after registration // For the function signature specifications, goto the link: - // https://github.com/bytecodealliance/wasm-micro-runtime/blob/master/doc/export_native_api.md + // https://github.com/bytecodealliance/wasm-micro-runtime/blob/main/doc/export_native_api.md static NativeSymbol native_symbols[] = { diff --git a/test-tools/IoT-APP-Store-Demo/wasm_django/devices/templates/help.html b/test-tools/IoT-APP-Store-Demo/wasm_django/devices/templates/help.html index bc834634c..b36279d44 100755 --- a/test-tools/IoT-APP-Store-Demo/wasm_django/devices/templates/help.html +++ b/test-tools/IoT-APP-Store-Demo/wasm_django/devices/templates/help.html @@ -49,7 +49,7 @@

Before running the UI-enabled runtime, please install some required softwares:

sudo apt-get install libsdl2-2.0-0:i386

For more details please refer to this guide + href="https://github.com/bytecodealliance/wasm-micro-runtime/tree/main/samples/littlevgl">guide

cd ~/Download && ./wasm_runtime_wgl -a 39.106.110.7

From ee315e404971f8d242603995c5837a23542472a9 Mon Sep 17 00:00:00 2001 From: wenyongh Date: Sun, 28 Jun 2020 15:41:25 +0800 Subject: [PATCH 023/207] Implement memory access bound check with hardware trap for 64-bit platforms (#293) Also implement native stack overflow check with hardware trap for 64-bit platforms Refine classic interpreter and fast interpreter to improve performance Update document --- README.md | 10 +- build-scripts/config_common.cmake | 5 + core/config.h | 10 +- core/iwasm/aot/aot_runtime.c | 268 +++++++++++++- core/iwasm/aot/aot_runtime.h | 20 +- core/iwasm/common/wasm_exec_env.c | 35 +- core/iwasm/common/wasm_exec_env.h | 19 + core/iwasm/common/wasm_runtime_common.c | 21 ++ core/iwasm/compilation/aot_emit_function.c | 3 +- core/iwasm/compilation/aot_emit_memory.c | 74 ++-- core/iwasm/compilation/aot_llvm.c | 76 ++-- core/iwasm/compilation/aot_llvm.h | 8 +- core/iwasm/include/aot_export.h | 2 + core/iwasm/interpreter/wasm_interp_classic.c | 347 +++++++++++------- core/iwasm/interpreter/wasm_interp_fast.c | 184 +++++----- core/iwasm/interpreter/wasm_loader.c | 37 +- core/iwasm/interpreter/wasm_mini_loader.c | 37 +- .../lib-pthread/lib_pthread_wrapper.c | 1 + core/shared/platform/alios/alios_platform.c | 10 +- .../platform/android/platform_internal.h | 32 ++ .../platform/common/posix/posix_memmap.c | 17 +- .../platform/common/posix/posix_thread.c | 163 +++++++- .../platform/darwin/platform_internal.h | 32 ++ .../platform/include/platform_api_vmcore.h | 6 +- core/shared/platform/linux-sgx/sgx_platform.c | 12 +- .../shared/platform/linux/platform_internal.h | 32 ++ .../platform/vxworks/platform_internal.h | 32 ++ core/shared/platform/zephyr/zephyr_platform.c | 10 +- doc/build_wamr.md | 10 +- doc/build_wasm_app.md | 43 ++- product-mini/platforms/linux/CMakeLists.txt | 7 +- wamr-compiler/CMakeLists.txt | 1 + wamr-compiler/main.c | 17 +- 33 files changed, 1143 insertions(+), 438 deletions(-) diff --git a/README.md b/README.md index 8cbd41d0f..df10d7179 100644 --- a/README.md +++ b/README.md @@ -53,11 +53,13 @@ Following platforms are supported. Refer to [WAMR porting guide](./doc/port_wamr - [Linux](./doc/build_wamr.md#linux), [Zephyr](./doc/build_wamr.md#zephyr), [MacOS](./doc/build_wamr.md#macos), [VxWorks](./doc/build_wamr.md#vxworks), [AliOS-Things](./doc/build_wamr.md#alios-things), [Intel Software Guard Extention (Linux)](./doc/build_wamr.md#linux-sgx-intel-software-guard-extention), [Android](./doc/build_wamr.md#android) +### Build iwasm VM core (mini product) +WAMR supports building the iwasm VM core only (no app framework) to the mini product. The WAMR mini product takes the WASM application file name or AoT file name as input and then executes it. For the detailed procedure, please see **[build WAMR VM core](./doc/build_wamr.md)** and **[build and run WASM application](./doc/build_wasm_app.md)**. Also we can click the link of each platform above to see how to build iwasm on it. ### Build wamrc AoT compiler -Execute following commands to build **wamrc** compiler: +Both wasm binary file and AoT file are supported by iwasm. The wamrc AoT compiler is to compile wasm binary file to AoT file which can also be run by iwasm. Execute following commands to build **wamrc** compiler: ```shell cd wamr-compiler @@ -69,12 +71,6 @@ ln -s {current path}/wamrc /usr/bin/wamrc ``` For MacOS, you should replace `cmake ..` with `cmake -DWAMR_BUILD_PLATFORM=darwin ..`. -### Build the mini product - -WAMR supports building the iwasm VM core only (no app framework) to the mini product. The WAMR mini product takes the WASM application file name as input and then executes it. For the detailed procedure, see **[build WAMR VM core](./doc/build_wamr.md)** and **[build and run WASM application](./doc/build_wasm_app.md)**. - - - Application framework =================================== diff --git a/build-scripts/config_common.cmake b/build-scripts/config_common.cmake index 3908ea1e2..3b7728f56 100644 --- a/build-scripts/config_common.cmake +++ b/build-scripts/config_common.cmake @@ -158,3 +158,8 @@ if (WAMR_BUILD_MINI_LOADER EQUAL 1) else () add_definitions (-DWASM_ENABLE_MINI_LOADER=0) endif () +if (WAMR_DISABLE_HW_BOUND_CHECK EQUAL 1) + add_definitions (-DWASM_DISABLE_HW_BOUND_CHECK=1) + message (" Hardware boundary check disabled") +endif () + diff --git a/core/config.h b/core/config.h index 870d02c7b..104dfdf3d 100644 --- a/core/config.h +++ b/core/config.h @@ -149,6 +149,12 @@ enum { #define WASM_ENABLE_MINI_LOADER 0 #endif +/* Disable boundary check with hardware trap or not, + * enable it by default if it is supported */ +#ifndef WASM_DISABLE_HW_BOUND_CHECK +#define WASM_DISABLE_HW_BOUND_CHECK 0 +#endif + /* Heap and stack profiling */ #define BH_ENABLE_MEMORY_PROFILING 0 @@ -199,8 +205,8 @@ enum { /* Default/min/max stack size of each app thread */ #if !defined(BH_PLATFORM_ZEPHYR) && !defined(BH_PLATFORM_ALIOS_THINGS) -#define APP_THREAD_STACK_SIZE_DEFAULT (20 * 1024) -#define APP_THREAD_STACK_SIZE_MIN (16 * 1024) +#define APP_THREAD_STACK_SIZE_DEFAULT (32 * 1024) +#define APP_THREAD_STACK_SIZE_MIN (24 * 1024) #define APP_THREAD_STACK_SIZE_MAX (256 * 1024) #else #define APP_THREAD_STACK_SIZE_DEFAULT (6 * 1024) diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index c2e491af9..29e11db17 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -158,10 +158,38 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModule *module, uint64 total_size = heap_size + memory_data_size; uint8 *p; +#ifndef OS_ENABLE_HW_BOUND_CHECK /* Allocate memory */ if (!(p = runtime_malloc(total_size, error_buf, error_buf_size))) { return false; } +#else + uint8 *mapped_mem; + uint64 map_size = 8 * (uint64)BH_GB; + + /* Totally 8G is mapped, the opcode load/store address range is -2G to 6G: + * ea = i + memarg.offset + * i is i32, the range is -2G to 2G + * memarg.offset is u32, the range is 0 to 4G + * so the range of ea is -2G to 6G + */ + if (total_size >= UINT32_MAX + || !(mapped_mem = os_mmap(NULL, map_size, + MMAP_PROT_NONE, MMAP_MAP_NONE))) { + set_error_buf(error_buf, error_buf_size, + "AOT module instantiate failed: mmap memory failed."); + return false; + } + + p = mapped_mem + 2 * (uint64)BH_GB - heap_size; + if (os_mprotect(p, total_size, MMAP_PROT_READ | MMAP_PROT_WRITE) != 0) { + set_error_buf(error_buf, error_buf_size, + "AOT module instantiate failed: mprotec memory failed."); + os_munmap(mapped_mem, map_size); + return false; + } + memset(p, 0, (uint32)total_size); +#endif /* Initialize heap info */ module_inst->heap_data.ptr = p; @@ -184,15 +212,15 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModule *module, p += (uint32)memory_data_size; module_inst->memory_data_end.ptr = p; module_inst->memory_data_size = (uint32)memory_data_size; - module_inst->total_mem_size = (uint32)(heap_size + memory_data_size); module_inst->mem_cur_page_count = module->mem_init_page_count; module_inst->mem_max_page_count = module->mem_max_page_count; - if (module_inst->total_mem_size > 0) { - module_inst->mem_bound_check_1byte = module_inst->total_mem_size - 1; - module_inst->mem_bound_check_2bytes = module_inst->total_mem_size - 2; - module_inst->mem_bound_check_4bytes = module_inst->total_mem_size - 4; - module_inst->mem_bound_check_8bytes = module_inst->total_mem_size - 8; + module_inst->mem_bound_check_heap_base = module_inst->heap_base_offset; + if (module_inst->memory_data_size > 0) { + module_inst->mem_bound_check_1byte = module_inst->memory_data_size - 1; + module_inst->mem_bound_check_2bytes = module_inst->memory_data_size - 2; + module_inst->mem_bound_check_4bytes = module_inst->memory_data_size - 4; + module_inst->mem_bound_check_8bytes = module_inst->memory_data_size - 8; } for (i = 0; i < module->mem_init_data_count; i++) { @@ -263,7 +291,11 @@ fail2: module_inst->heap_handle.ptr = NULL; } fail1: +#ifndef OS_ENABLE_HW_BOUND_CHECK wasm_runtime_free(module_inst->heap_data.ptr); +#else + os_munmap(mapped_mem, map_size); +#endif module_inst->heap_data.ptr = NULL; return false; } @@ -374,6 +406,9 @@ aot_instantiate(AOTModule *module, bool is_sub_inst, heap_size = align_uint(heap_size, 8); if (heap_size > APP_HEAP_SIZE_MAX) heap_size = APP_HEAP_SIZE_MAX; +#ifdef OS_ENABLE_HW_BOUND_CHECK + heap_size = align_uint(heap_size, os_getpagesize()); +#endif /* Allocate module instance, global data, table data and heap data */ if (!(module_inst = runtime_malloc(total_size, @@ -468,8 +503,14 @@ aot_deinstantiate(AOTModuleInstance *module_inst, bool is_sub_inst) if (module_inst->heap_handle.ptr) mem_allocator_destroy(module_inst->heap_handle.ptr); - if (module_inst->heap_data.ptr) + if (module_inst->heap_data.ptr) { +#ifndef OS_ENABLE_HW_BOUND_CHECK wasm_runtime_free(module_inst->heap_data.ptr); +#else + os_munmap((uint8*)module_inst->memory_data.ptr - 2 * (uint64)BH_GB, + 8 * (uint64)BH_GB); +#endif + } if (module_inst->func_ptrs.ptr) wasm_runtime_free(module_inst->func_ptrs.ptr); @@ -508,6 +549,157 @@ aot_lookup_function(const AOTModuleInstance *module_inst, (addr)[1] = u.parts[1]; \ } while (0) + +#ifdef OS_ENABLE_HW_BOUND_CHECK + +static os_thread_local_attribute WASMExecEnv *aot_exec_env = NULL; + +static inline uint8 * +get_stack_min_addr(WASMExecEnv *exec_env, uint32 page_size) +{ + uintptr_t stack_bound = (uintptr_t)exec_env->native_stack_boundary; + return (uint8*)(stack_bound & ~(uintptr_t)(page_size -1 )); +} + +static void +aot_signal_handler(void *sig_addr) +{ + AOTModuleInstance *module_inst; + WASMJmpBuf *jmpbuf_node; + uint8 *mapped_mem_start_addr, *mapped_mem_end_addr; + uint8 *stack_min_addr; + uint32 page_size; + + /* Check whether current thread is running aot function */ + if (aot_exec_env + && aot_exec_env->handle == os_self_thread() + && (jmpbuf_node = aot_exec_env->jmpbuf_stack_top)) { + /* Get mapped mem info of current instance */ + module_inst = (AOTModuleInstance *)aot_exec_env->module_inst; + mapped_mem_start_addr = (uint8*)module_inst->memory_data.ptr + - 2 * (uint64)BH_GB; + mapped_mem_end_addr = (uint8*)module_inst->memory_data.ptr + + 6 * (uint64)BH_GB; + + /* Get stack info of current thread */ + page_size = os_getpagesize(); + stack_min_addr = get_stack_min_addr(aot_exec_env, page_size); + + if (mapped_mem_start_addr <= (uint8*)sig_addr + && (uint8*)sig_addr < mapped_mem_end_addr) { + /* The address which causes segmentation fault is inside + aot instance's guard regions */ + aot_set_exception_with_id(module_inst, EXCE_OUT_OF_BOUNDS_MEMORY_ACCESS); + os_longjmp(jmpbuf_node->jmpbuf, 1); + } + else if (stack_min_addr - page_size <= (uint8*)sig_addr + && (uint8*)sig_addr < stack_min_addr + page_size * 3) { + /* The address which causes segmentation fault is inside + native thread's guard page */ + aot_set_exception_with_id(module_inst, EXCE_NATIVE_STACK_OVERFLOW); + os_longjmp(jmpbuf_node->jmpbuf, 1); + } + } +} + +bool +aot_signal_init() +{ + return os_signal_init(aot_signal_handler) == 0 ? true : false; +} + +void +aot_signal_destroy() +{ + os_signal_destroy(); +} + +#if defined(__GNUC__) +__attribute__((no_sanitize_address)) static uint32 +#else +static uint32 +#endif +touch_pages(uint8 *stack_min_addr, uint32 page_size) +{ + uint8 sum = 0; + while (1) { + uint8 *touch_addr = os_alloca(page_size / 2); + sum += *touch_addr; + if (touch_addr < stack_min_addr + page_size) { + break; + } + } + return sum; +} + +static bool +invoke_native_with_hw_bound_check(WASMExecEnv *exec_env, void *func_ptr, + const WASMType *func_type, const char *signature, + void *attachment, + uint32 *argv, uint32 argc, uint32 *argv_ret) +{ + AOTModuleInstance *module_inst = (AOTModuleInstance*)exec_env->module_inst; + WASMExecEnv **p_aot_exec_env = &aot_exec_env; + WASMJmpBuf *jmpbuf_node, *jmpbuf_node_pop; + uint32 page_size = os_getpagesize(); + uint8 *stack_min_addr = get_stack_min_addr(exec_env, page_size); + bool ret; + + if (aot_exec_env + && (aot_exec_env != exec_env)) { + aot_set_exception(module_inst, "Invalid exec env."); + return false; + } + + if (!exec_env->jmpbuf_stack_top) { + /* Touch each stack page to ensure that it has been mapped: the OS may + lazily grow the stack mapping as a guard page is hit. */ + touch_pages(stack_min_addr, page_size); + /* First time to call aot function, protect one page */ + if (os_mprotect(stack_min_addr, page_size * 3, MMAP_PROT_NONE) != 0) { + aot_set_exception(module_inst, "Set protected page failed."); + return false; + } + } + + if (!(jmpbuf_node = wasm_runtime_malloc(sizeof(WASMJmpBuf)))) { + aot_set_exception_with_id(module_inst, EXCE_OUT_OF_MEMORY); + return false; + } + + wasm_exec_env_push_jmpbuf(exec_env, jmpbuf_node); + + aot_exec_env = exec_env; + if (os_setjmp(jmpbuf_node->jmpbuf) == 0) { + ret = wasm_runtime_invoke_native(exec_env, func_ptr, func_type, + signature, attachment, + argv, argc, argv); + } + else { + /* Exception has been set in signal handler before calling longjmp */ + ret = false; + } + + jmpbuf_node_pop = wasm_exec_env_pop_jmpbuf(exec_env); + bh_assert(jmpbuf_node == jmpbuf_node_pop); + wasm_runtime_free(jmpbuf_node); + if (!exec_env->jmpbuf_stack_top) { + /* Unprotect the guard page when the nested call depth is zero */ + os_mprotect(stack_min_addr, page_size * 3, + MMAP_PROT_READ | MMAP_PROT_WRITE); + *p_aot_exec_env = NULL; + } + os_sigreturn(); + os_signal_unmask(); + (void)jmpbuf_node_pop; + return ret; +} + +#define invoke_native_internal invoke_native_with_hw_bound_check +#else /* else of OS_ENABLE_HW_BOUND_CHECK */ +#define invoke_native_internal wasm_runtime_invoke_native +#endif /* end of OS_ENABLE_HW_BOUND_CHECK */ + bool aot_call_function(WASMExecEnv *exec_env, AOTFunctionInstance *function, @@ -515,8 +707,8 @@ aot_call_function(WASMExecEnv *exec_env, { AOTModuleInstance *module_inst = (AOTModuleInstance*)exec_env->module_inst; AOTFuncType *func_type = function->func_type; - bool ret = wasm_runtime_invoke_native(exec_env, function->func_ptr, - func_type, NULL, NULL, argv, argc, argv); + bool ret = invoke_native_internal(exec_env, function->func_ptr, + func_type, NULL, NULL, argv, argc, argv); return ret && !aot_get_exception(module_inst) ? true : false; } @@ -762,6 +954,7 @@ aot_get_native_addr_range(AOTModuleInstance *module_inst, return false; } +#ifndef OS_ENABLE_HW_BOUND_CHECK bool aot_enlarge_memory(AOTModuleInstance *module_inst, uint32 inc_page_count) { @@ -830,17 +1023,58 @@ aot_enlarge_memory(AOTModuleInstance *module_inst, uint32 inc_page_count) module_inst->mem_cur_page_count = total_page_count; module_inst->memory_data_size = (uint32)memory_data_size; - module_inst->total_mem_size = (uint32)(heap_size + memory_data_size); module_inst->memory_data.ptr = (uint8*)heap_data + heap_size; module_inst->memory_data_end.ptr = (uint8*)module_inst->memory_data.ptr + (uint32)memory_data_size; - module_inst->mem_bound_check_1byte = module_inst->total_mem_size - 1; - module_inst->mem_bound_check_2bytes = module_inst->total_mem_size - 2; - module_inst->mem_bound_check_4bytes = module_inst->total_mem_size - 4; - module_inst->mem_bound_check_8bytes = module_inst->total_mem_size - 8; + module_inst->mem_bound_check_1byte = module_inst->memory_data_size - 1; + module_inst->mem_bound_check_2bytes = module_inst->memory_data_size - 2; + module_inst->mem_bound_check_4bytes = module_inst->memory_data_size - 4; + module_inst->mem_bound_check_8bytes = module_inst->memory_data_size - 8; return true; } +#else +bool +aot_enlarge_memory(AOTModuleInstance *module_inst, uint32 inc_page_count) +{ + uint32 num_bytes_per_page = + ((AOTModule*)module_inst->aot_module.ptr)->num_bytes_per_page; + uint32 cur_page_count = module_inst->mem_cur_page_count; + uint32 max_page_count = module_inst->mem_max_page_count; + uint32 total_page_count = cur_page_count + inc_page_count; + uint64 memory_data_size = (uint64)num_bytes_per_page * total_page_count; + + if (inc_page_count <= 0) + /* No need to enlarge memory */ + return true; + + if (total_page_count < cur_page_count /* integer overflow */ + || total_page_count > max_page_count) { + aot_set_exception(module_inst, "fail to enlarge memory."); + return false; + } + + if (os_mprotect(module_inst->memory_data.ptr, memory_data_size, + MMAP_PROT_READ | MMAP_PROT_WRITE) != 0) { + aot_set_exception(module_inst, "fail to enlarge memory."); + return false; + } + + memset(module_inst->memory_data_end.ptr, 0, + num_bytes_per_page * inc_page_count); + + module_inst->mem_cur_page_count = total_page_count; + module_inst->memory_data_size = (uint32)memory_data_size; + module_inst->memory_data_end.ptr = (uint8*)module_inst->memory_data.ptr + + (uint32)memory_data_size; + + module_inst->mem_bound_check_1byte = module_inst->memory_data_size - 1; + module_inst->mem_bound_check_2bytes = module_inst->memory_data_size - 2; + module_inst->mem_bound_check_4bytes = module_inst->memory_data_size - 4; + module_inst->mem_bound_check_8bytes = module_inst->memory_data_size - 8; + return true; +} +#endif bool aot_is_wasm_type_equal(AOTModuleInstance *module_inst, @@ -979,9 +1213,9 @@ aot_call_indirect(WASMExecEnv *exec_env, } } - return wasm_runtime_invoke_native(exec_env, func_ptr, - func_type, signature, attachment, - argv, argc, argv); + return invoke_native_internal(exec_env, func_ptr, + func_type, signature, attachment, + argv, argc, argv); } #if WASM_ENABLE_BULK_MEMORY != 0 diff --git a/core/iwasm/aot/aot_runtime.h b/core/iwasm/aot/aot_runtime.h index d06bc0b80..b42f12a23 100644 --- a/core/iwasm/aot/aot_runtime.h +++ b/core/iwasm/aot/aot_runtime.h @@ -198,14 +198,12 @@ typedef struct AOTModuleInstance { /* WASI context */ AOTPointer wasi_ctx; - /* total memory size: heap and linear memory */ - uint32 total_mem_size; - /* boundary check constants for aot code */ - uint32 mem_bound_check_1byte; - uint32 mem_bound_check_2bytes; - uint32 mem_bound_check_4bytes; - uint32 mem_bound_check_8bytes; + int64 mem_bound_check_heap_base; + int64 mem_bound_check_1byte; + int64 mem_bound_check_2bytes; + int64 mem_bound_check_4bytes; + int64 mem_bound_check_8bytes; /* others */ int32 temp_ret; @@ -469,6 +467,14 @@ bool aot_data_drop(AOTModuleInstance *module_inst, uint32 seg_index); #endif +#ifdef OS_ENABLE_HW_BOUND_CHECK +bool +aot_signal_init(); + +void +aot_signal_destroy(); +#endif + #ifdef __cplusplus } /* end of extern "C" */ #endif diff --git a/core/iwasm/common/wasm_exec_env.c b/core/iwasm/common/wasm_exec_env.c index 14a173c11..4975b4d2c 100644 --- a/core/iwasm/common/wasm_exec_env.c +++ b/core/iwasm/common/wasm_exec_env.c @@ -61,6 +61,15 @@ fail1: void wasm_exec_env_destroy_internal(WASMExecEnv *exec_env) { +#ifdef OS_ENABLE_HW_BOUND_CHECK + WASMJmpBuf *jmpbuf = exec_env->jmpbuf_stack_top; + WASMJmpBuf *jmpbuf_prev; + while (jmpbuf) { + jmpbuf_prev = jmpbuf->prev; + wasm_runtime_free(jmpbuf); + jmpbuf = jmpbuf_prev; + } +#endif #if WASM_ENABLE_THREAD_MGR != 0 os_mutex_destroy(&exec_env->wait_lock); os_cond_destroy(&exec_env->wait_cond); @@ -121,7 +130,6 @@ wasm_exec_env_set_thread_info(WASMExecEnv *exec_env) exec_env->handle = os_self_thread(); exec_env->native_stack_boundary = os_thread_get_stack_boundary() + RESERVED_BYTES_TO_NATIVE_STACK_BOUNDARY; - } #if WASM_ENABLE_THREAD_MGR != 0 @@ -136,4 +144,27 @@ wasm_exec_env_set_thread_arg(WASMExecEnv *exec_env, void *thread_arg) { exec_env->thread_arg = thread_arg; } -#endif \ No newline at end of file +#endif + +#ifdef OS_ENABLE_HW_BOUND_CHECK +void +wasm_exec_env_push_jmpbuf(WASMExecEnv *exec_env, WASMJmpBuf *jmpbuf) +{ + jmpbuf->prev = exec_env->jmpbuf_stack_top; + exec_env->jmpbuf_stack_top = jmpbuf; +} + +WASMJmpBuf * +wasm_exec_env_pop_jmpbuf(WASMExecEnv *exec_env) +{ + WASMJmpBuf *stack_top = exec_env->jmpbuf_stack_top; + + if (stack_top) { + exec_env->jmpbuf_stack_top = stack_top->prev; + return stack_top; + } + + return NULL; +} +#endif + diff --git a/core/iwasm/common/wasm_exec_env.h b/core/iwasm/common/wasm_exec_env.h index d29f33cb7..fa5310e5d 100644 --- a/core/iwasm/common/wasm_exec_env.h +++ b/core/iwasm/common/wasm_exec_env.h @@ -22,6 +22,13 @@ struct WASMInterpFrame; typedef struct WASMCluster WASMCluster; #endif +#ifdef OS_ENABLE_HW_BOUND_CHECK +typedef struct WASMJmpBuf { + struct WASMJmpBuf *prev; + korp_jmpbuf jmpbuf; +} WASMJmpBuf; +#endif + /* Execution environment */ typedef struct WASMExecEnv { /* Next thread's exec env of a WASM module instance. */ @@ -82,6 +89,10 @@ typedef struct WASMExecEnv { BlockAddr block_addr_cache[BLOCK_ADDR_CACHE_SIZE][BLOCK_ADDR_CONFLICT_SIZE]; #endif +#ifdef OS_ENABLE_HW_BOUND_CHECK + WASMJmpBuf *jmpbuf_stack_top; +#endif + /* The WASM stack size */ uint32 wasm_stack_size; @@ -207,6 +218,14 @@ void wasm_exec_env_set_thread_arg(WASMExecEnv *exec_env, void *thread_arg); #endif +#ifdef OS_ENABLE_HW_BOUND_CHECK +void +wasm_exec_env_push_jmpbuf(WASMExecEnv *exec_env, WASMJmpBuf *jmpbuf); + +WASMJmpBuf * +wasm_exec_env_pop_jmpbuf(WASMExecEnv *exec_env); +#endif + #ifdef __cplusplus } #endif diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index 986348aaf..ef3b5c468 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -120,9 +120,24 @@ wasm_runtime_env_init() goto fail5; } #endif + +#if WASM_ENABLE_AOT != 0 +#ifdef OS_ENABLE_HW_BOUND_CHECK + if (!aot_signal_init()) { + goto fail6; + } +#endif +#endif + return true; +#if WASM_ENABLE_AOT != 0 +#ifdef OS_ENABLE_HW_BOUND_CHECK +fail6: +#endif +#endif #if WASM_ENABLE_THREAD_MGR != 0 + thread_manager_destroy(); fail5: #endif #if WASM_ENABLE_SHARED_MEMORY @@ -170,6 +185,12 @@ wasm_runtime_init() void wasm_runtime_destroy() { +#if WASM_ENABLE_AOT != 0 +#ifdef OS_ENABLE_HW_BOUND_CHECK + aot_signal_destroy(); +#endif +#endif + /* runtime env destroy */ #if WASM_ENABLE_MULTI_MODULE wasm_runtime_destroy_loading_module_list(); diff --git a/core/iwasm/compilation/aot_emit_function.c b/core/iwasm/compilation/aot_emit_function.c index 3c1708928..ed45edda9 100644 --- a/core/iwasm/compilation/aot_emit_function.c +++ b/core/iwasm/compilation/aot_emit_function.c @@ -398,7 +398,8 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, aot_func = func_ctxes[func_idx - import_func_count]->aot_func; callee_cell_num = aot_func->param_cell_num + aot_func->local_cell_num + 1; - if (!check_stack_boundary(comp_ctx, func_ctx, callee_cell_num)) + if (comp_ctx->enable_bound_check + && !check_stack_boundary(comp_ctx, func_ctx, callee_cell_num)) goto fail; /* Call the function */ diff --git a/core/iwasm/compilation/aot_emit_memory.c b/core/iwasm/compilation/aot_emit_memory.c index 70e6a0faa..462926608 100644 --- a/core/iwasm/compilation/aot_emit_memory.c +++ b/core/iwasm/compilation/aot_emit_memory.c @@ -75,18 +75,13 @@ check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, uint32 offset, uint32 bytes) { LLVMValueRef offset_const = I32_CONST(offset); - LLVMValueRef bytes_const = I32_CONST(bytes); - LLVMValueRef bytes64_const = I64_CONST(bytes); - LLVMValueRef heap_base_offset = func_ctx->heap_base_offset; - LLVMValueRef addr, maddr, offset1, offset2, cmp; - LLVMValueRef mem_base_addr, mem_check_bound, total_mem_size; + LLVMValueRef addr, maddr, offset1, cmp, cmp1, cmp2; + LLVMValueRef mem_base_addr, mem_check_bound; LLVMBasicBlockRef block_curr = LLVMGetInsertBlock(comp_ctx->builder); - LLVMBasicBlockRef check_succ, check_mem_space; + LLVMBasicBlockRef check_succ; AOTValue *aot_value; CHECK_LLVM_CONST(offset_const); - CHECK_LLVM_CONST(bytes_const); - CHECK_LLVM_CONST(bytes64_const); /* Get memory base address and memory data size */ if (func_ctx->mem_space_unchanged) { @@ -104,21 +99,20 @@ check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, aot_value = func_ctx->block_stack.block_list_end->value_stack.value_list_end; POP_I32(addr); - /* offset1 = offset + addr; */ - BUILD_OP(Add, offset_const, addr, offset1, "offset1"); /* return addres directly if constant offset and inside memory space */ - if (LLVMIsConstant(offset1)) { - uint32 mem_offset = (uint32)LLVMConstIntGetZExtValue(offset1); + if (LLVMIsConstant(addr)) { + int64 mem_offset = (int64)LLVMConstIntGetSExtValue(addr) + (int64)offset; 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; + 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) { /* inside memory space */ - /* maddr = mem_base_addr + moffset */ - if (!(maddr = LLVMBuildInBoundsGEP(comp_ctx->builder, - mem_base_addr, + offset1 = I32_CONST((uint32)mem_offset); + CHECK_LLVM_CONST(offset_const); + if (!(maddr = LLVMBuildInBoundsGEP(comp_ctx->builder, mem_base_addr, &offset1, 1, "maddr"))) { aot_set_last_error("llvm build add failed."); goto fail; @@ -127,51 +121,35 @@ check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } } - if (comp_ctx->comp_data->mem_init_page_count == 0) { - /* Get total memory size */ - if (func_ctx->mem_space_unchanged) { - total_mem_size = func_ctx->total_mem_size; - } - else { - if (!(total_mem_size = LLVMBuildLoad(comp_ctx->builder, - func_ctx->total_mem_size, - "total_mem_size"))) { - aot_set_last_error("llvm build load failed."); + 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; - } - } - - ADD_BASIC_BLOCK(check_mem_space, "check_mem_space"); - LLVMMoveBasicBlockAfter(check_mem_space, block_curr); - - /* if total_mem_size is zero, boundary check fail */ - BUILD_ICMP(LLVMIntEQ, total_mem_size, I32_ZERO, cmp, - "cmp_total_mem_size"); - if (!aot_emit_exception(comp_ctx, func_ctx, - EXCE_OUT_OF_BOUNDS_MEMORY_ACCESS, - true, cmp, check_mem_space)) { - goto fail; - } - SET_BUILD_POS(check_mem_space); } - if (!(aot_value->is_local - && aot_checked_addr_list_find(func_ctx, aot_value->local_idx, - offset, bytes))) { - /* offset2 = offset1 - heap_base_offset; */ - BUILD_OP(Sub, offset1, heap_base_offset, offset2, "offset2"); + /* offset1 = offset + addr; */ + BUILD_OP(Add, offset_const, addr, offset1, "offset1"); + if (comp_ctx->enable_bound_check + && !(aot_value->is_local + && aot_checked_addr_list_find(func_ctx, aot_value->local_idx, + offset, bytes))) { if (!(mem_check_bound = get_memory_check_bound(comp_ctx, func_ctx, bytes))) { goto fail; } + BUILD_ICMP(LLVMIntSGT, func_ctx->mem_bound_check_heap_base, offset1, + cmp1, "cmp1"); + BUILD_ICMP(LLVMIntSGT, offset1, mem_check_bound, cmp2, "cmp2"); + BUILD_OP(Or, cmp1, cmp2, cmp, "cmp"); + /* Add basic blocks */ ADD_BASIC_BLOCK(check_succ, "check_succ"); LLVMMoveBasicBlockAfter(check_succ, block_curr); - /* offset2 > bound ? */ - BUILD_ICMP(LLVMIntUGT, offset2, mem_check_bound, cmp, "cmp"); if (!aot_emit_exception(comp_ctx, func_ctx, EXCE_OUT_OF_BOUNDS_MEMORY_ACCESS, true, cmp, check_succ)) { diff --git a/core/iwasm/compilation/aot_llvm.c b/core/iwasm/compilation/aot_llvm.c index 09155918c..7ae2e025d 100644 --- a/core/iwasm/compilation/aot_llvm.c +++ b/core/iwasm/compilation/aot_llvm.c @@ -182,29 +182,6 @@ create_memory_info(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } } - /* Load total memory size */ - offset = I32_CONST(offsetof(AOTModuleInstance, total_mem_size)); - if (!(func_ctx->total_mem_size = - LLVMBuildInBoundsGEP(comp_ctx->builder, func_ctx->aot_inst, - &offset, 1, "bound_check_1byte_offset"))) { - aot_set_last_error("llvm build in bounds gep failed"); - return false; - } - if (!(func_ctx->total_mem_size = - LLVMBuildBitCast(comp_ctx->builder, func_ctx->total_mem_size, - INT32_PTR_TYPE, "bound_check_1byte_ptr"))) { - aot_set_last_error("llvm build bit cast failed"); - return false; - } - if (mem_space_unchanged) { - if (!(func_ctx->total_mem_size = - LLVMBuildLoad(comp_ctx->builder, func_ctx->total_mem_size, - "bound_check_1byte"))) { - aot_set_last_error("llvm build load failed"); - return false; - } - } - /* Load memory bound check constants */ offset = I32_CONST(offsetof(AOTModuleInstance, mem_bound_check_1byte)); if (!(func_ctx->mem_bound_check_1byte = @@ -215,7 +192,7 @@ create_memory_info(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } if (!(func_ctx->mem_bound_check_1byte = LLVMBuildBitCast(comp_ctx->builder, func_ctx->mem_bound_check_1byte, - INT32_PTR_TYPE, "bound_check_1byte_ptr"))) { + INT64_PTR_TYPE, "bound_check_1byte_ptr"))) { aot_set_last_error("llvm build bit cast failed"); return false; } @@ -237,7 +214,7 @@ create_memory_info(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } if (!(func_ctx->mem_bound_check_2bytes = LLVMBuildBitCast(comp_ctx->builder, func_ctx->mem_bound_check_2bytes, - INT32_PTR_TYPE, "bound_check_2bytes_ptr"))) { + INT64_PTR_TYPE, "bound_check_2bytes_ptr"))) { aot_set_last_error("llvm build bit cast failed"); return false; } @@ -259,7 +236,7 @@ create_memory_info(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } if (!(func_ctx->mem_bound_check_4bytes = LLVMBuildBitCast(comp_ctx->builder, func_ctx->mem_bound_check_4bytes, - INT32_PTR_TYPE, "bound_check_4bytes_ptr"))) { + INT64_PTR_TYPE, "bound_check_4bytes_ptr"))) { aot_set_last_error("llvm build bit cast failed"); return false; } @@ -281,7 +258,7 @@ create_memory_info(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } if (!(func_ctx->mem_bound_check_8bytes = LLVMBuildBitCast(comp_ctx->builder, func_ctx->mem_bound_check_8bytes, - INT32_PTR_TYPE, "bound_check_8bytes_ptr"))) { + INT64_PTR_TYPE, "bound_check_8bytes_ptr"))) { aot_set_last_error("llvm build bit cast failed"); return false; } @@ -294,23 +271,23 @@ create_memory_info(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } } - /* Load heap base offset */ - offset = I32_CONST(offsetof(AOTModuleInstance, heap_base_offset)); - if (!(func_ctx->heap_base_offset = + /* Load bound_check_heap_base */ + offset = I32_CONST(offsetof(AOTModuleInstance, mem_bound_check_heap_base)); + if (!(func_ctx->mem_bound_check_heap_base = LLVMBuildInBoundsGEP(comp_ctx->builder, func_ctx->aot_inst, - &offset, 1, "heap_base_offset_offset"))) { + &offset, 1, "bound_check_heap_base_offset"))) { aot_set_last_error("llvm build in bounds gep failed"); return false; } - if (!(func_ctx->heap_base_offset = - LLVMBuildBitCast(comp_ctx->builder, func_ctx->heap_base_offset, - INT32_PTR_TYPE, "heap_base_offset_tmp"))) { + if (!(func_ctx->mem_bound_check_heap_base = + LLVMBuildBitCast(comp_ctx->builder, func_ctx->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->heap_base_offset = - LLVMBuildLoad(comp_ctx->builder, func_ctx->heap_base_offset, - "heap_base_offset"))) { + if (!(func_ctx->mem_bound_check_heap_base = + LLVMBuildLoad(comp_ctx->builder, func_ctx->mem_bound_check_heap_base, + "bound_check_heap_base"))) { aot_set_last_error("llvm build load failed"); return false; } @@ -936,6 +913,11 @@ aot_create_comp_context(AOTCompData *comp_data, comp_ctx->is_jit_mode = true; comp_ctx->target_machine = LLVMGetExecutionEngineTargetMachine(comp_ctx->exec_engine); +#ifndef OS_ENABLE_HW_BOUND_CHECK + comp_ctx->enable_bound_check = true; +#else + comp_ctx->enable_bound_check = false; +#endif } else { /* Create LLVM target machine */ @@ -1049,6 +1031,21 @@ aot_create_comp_context(AOTCompData *comp_data, get_target_arch_from_triple(triple_norm, comp_ctx->target_arch, sizeof(comp_ctx->target_arch)); + if (option->bounds_checks == 1 || option->bounds_checks == 0) { + /* Set by user */ + comp_ctx->enable_bound_check = + (option->bounds_checks == 1) ? true : false; + } + else { + /* Unset by user, use default value */ + if (strstr(comp_ctx->target_arch, "64") && !option->is_sgx_platform) { + comp_ctx->enable_bound_check = false; + } + else { + comp_ctx->enable_bound_check = true; + } + } + os_printf("Create AoT compiler with:\n"); os_printf(" target: %s\n", comp_ctx->target_arch); os_printf(" target cpu: %s\n", cpu); @@ -1114,14 +1111,11 @@ aot_create_comp_context(AOTCompData *comp_data, goto fail; } - LLVMAddBasicAliasAnalysisPass(comp_ctx->pass_mgr); LLVMAddPromoteMemoryToRegisterPass(comp_ctx->pass_mgr); LLVMAddInstructionCombiningPass(comp_ctx->pass_mgr); + LLVMAddCFGSimplificationPass(comp_ctx->pass_mgr); LLVMAddJumpThreadingPass(comp_ctx->pass_mgr); LLVMAddConstantPropagationPass(comp_ctx->pass_mgr); - LLVMAddReassociatePass(comp_ctx->pass_mgr); - LLVMAddGVNPass(comp_ctx->pass_mgr); - LLVMAddCFGSimplificationPass(comp_ctx->pass_mgr); /* Create metadata for llvm float experimental constrained intrinsics */ if (!(comp_ctx->fp_rounding_mode = diff --git a/core/iwasm/compilation/aot_llvm.h b/core/iwasm/compilation/aot_llvm.h index fc4821e22..f94f7c754 100644 --- a/core/iwasm/compilation/aot_llvm.h +++ b/core/iwasm/compilation/aot_llvm.h @@ -105,9 +105,8 @@ typedef struct AOTFuncContext { LLVMValueRef native_stack_bound; LLVMValueRef last_alloca; - LLVMValueRef heap_base_offset; LLVMValueRef mem_base_addr; - LLVMValueRef total_mem_size; + LLVMValueRef mem_bound_check_heap_base; LLVMValueRef mem_bound_check_1byte; LLVMValueRef mem_bound_check_2bytes; LLVMValueRef mem_bound_check_4bytes; @@ -188,6 +187,9 @@ typedef struct AOTCompContext { /* Bulk memory feature */ bool enable_bulk_memory; + /* Bounday Check */ + bool enable_bound_check; + /* Whether optimize the JITed code */ bool optimize; @@ -227,9 +229,11 @@ typedef struct AOTCompOption{ char *target_cpu; char *cpu_features; bool enable_bulk_memory; + bool is_sgx_platform; uint32 opt_level; uint32 size_level; uint32 output_format; + uint32 bounds_checks; } AOTCompOption, *aot_comp_option_t; AOTCompContext * diff --git a/core/iwasm/include/aot_export.h b/core/iwasm/include/aot_export.h index 531d2df79..981c9edca 100644 --- a/core/iwasm/include/aot_export.h +++ b/core/iwasm/include/aot_export.h @@ -40,9 +40,11 @@ typedef struct AOTCompOption{ char *target_cpu; char *cpu_features; bool enable_bulk_memory; + bool is_sgx_platform; uint32_t opt_level; uint32_t size_level; uint32_t output_format; + uint32_t bounds_checks; } AOTCompOption, *aot_comp_option_t; aot_comp_context_t diff --git a/core/iwasm/interpreter/wasm_interp_classic.c b/core/iwasm/interpreter/wasm_interp_classic.c index 02914f7f0..2b164e715 100644 --- a/core/iwasm/interpreter/wasm_interp_classic.c +++ b/core/iwasm/interpreter/wasm_interp_classic.c @@ -224,11 +224,9 @@ LOAD_I16(void *addr) #endif /* WASM_CPU_SUPPORTS_UNALIGNED_64BIT_ACCESS != 0 */ #define CHECK_MEMORY_OVERFLOW(bytes) do { \ - int32 offset1 = (int32)(offset + addr); \ - uint64 offset2 = (uint64)(uint32)(offset1 - heap_base_offset); \ - /* if (flags != 2) \ - LOG_VERBOSE("unaligned load/store, flag: %d.\n", flags); */ \ - if (offset2 + LOAD_SIZE[opcode - WASM_OP_I32_LOAD] <= total_mem_size) \ + int64 offset1 = (int64)(uint32)offset + (int64)(int32)addr; \ + if (heap_base_offset <= offset1 \ + && offset1 <= (int64)linear_mem_size - bytes) \ /* If offset1 is in valid range, maddr must also be in valid range, \ no need to check it again. */ \ maddr = memory->memory_data + offset1; \ @@ -973,12 +971,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, WASMMemoryInstance *memory = module->default_memory; int32 heap_base_offset = memory ? memory->heap_base_offset : 0; uint32 num_bytes_per_page = memory ? memory->num_bytes_per_page : 0; - uint32 total_mem_size = memory ? num_bytes_per_page * memory->cur_page_count - - heap_base_offset : 0; uint8 *global_data = module->global_data; -#if WASM_ENABLE_BULK_MEMORY != 0 uint32 linear_mem_size = memory ? num_bytes_per_page * memory->cur_page_count : 0; -#endif WASMTableInstance *table = module->default_table; WASMGlobalInstance *globals = module->globals; uint8 opcode_IMPDEP = WASM_OP_IMPDEP; @@ -1015,12 +1009,6 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, #undef HANDLE_OPCODE #endif - /* Size of memory load. - This starts with the first memory load operator at opcode 0x28 */ - uint32 LOAD_SIZE[] = { - 4, 8, 4, 8, 1, 1, 2, 2, 1, 1, 2, 2, 4, 4, /* loads */ - 4, 8, 4, 8, 1, 2, 1, 2, 4 }; /* stores */ - #if WASM_ENABLE_LABELS_AS_VALUES == 0 while (frame_ip < frame_ip_end) { opcode = *frame_ip++; @@ -1445,6 +1433,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, if ((global_idx == (uint32)aux_stack_top_global_idx) && (*(uint32*)(frame_sp - 1) < exec_env->aux_stack_boundary)) goto out_of_bounds; + *(int32*)global_addr = POP_I32(); + break; case VALUE_TYPE_F32: *(int32*)global_addr = POP_I32(); break; @@ -1462,180 +1452,261 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, /* memory load instructions */ HANDLE_OP (WASM_OP_I32_LOAD): - HANDLE_OP (WASM_OP_I64_LOAD): HANDLE_OP (WASM_OP_F32_LOAD): - HANDLE_OP (WASM_OP_F64_LOAD): - HANDLE_OP (WASM_OP_I32_LOAD8_S): - HANDLE_OP (WASM_OP_I32_LOAD8_U): - HANDLE_OP (WASM_OP_I32_LOAD16_S): - HANDLE_OP (WASM_OP_I32_LOAD16_U): - HANDLE_OP (WASM_OP_I64_LOAD8_S): - HANDLE_OP (WASM_OP_I64_LOAD8_U): - HANDLE_OP (WASM_OP_I64_LOAD16_S): - HANDLE_OP (WASM_OP_I64_LOAD16_U): - HANDLE_OP (WASM_OP_I64_LOAD32_S): - HANDLE_OP (WASM_OP_I64_LOAD32_U): { - uint32 offset, flags, addr; - GET_OPCODE(); + uint32 offset, flags; + int32 addr; + read_leb_uint32(frame_ip, frame_ip_end, flags); read_leb_uint32(frame_ip, frame_ip_end, offset); - addr = (uint32)POP_I32(); - CHECK_MEMORY_OVERFLOW(); -#if WASM_ENABLE_LABELS_AS_VALUES != 0 - static const void *handle_load_table[] = { - &&HANDLE_LOAD_WASM_OP_I32_LOAD, - &&HANDLE_LOAD_WASM_OP_I64_LOAD, - &&HANDLE_LOAD_WASM_OP_F32_LOAD, - &&HANDLE_LOAD_WASM_OP_F64_LOAD, - &&HANDLE_LOAD_WASM_OP_I32_LOAD8_S, - &&HANDLE_LOAD_WASM_OP_I32_LOAD8_U, - &&HANDLE_LOAD_WASM_OP_I32_LOAD16_S, - &&HANDLE_LOAD_WASM_OP_I32_LOAD16_U, - &&HANDLE_LOAD_WASM_OP_I64_LOAD8_S, - &&HANDLE_LOAD_WASM_OP_I64_LOAD8_U, - &&HANDLE_LOAD_WASM_OP_I64_LOAD16_S, - &&HANDLE_LOAD_WASM_OP_I64_LOAD16_U, - &&HANDLE_LOAD_WASM_OP_I64_LOAD32_S, - &&HANDLE_LOAD_WASM_OP_I64_LOAD32_U - }; - #define HANDLE_OP_LOAD(opcode) HANDLE_LOAD_##opcode - goto *handle_load_table[opcode - WASM_OP_I32_LOAD]; -#else - #define HANDLE_OP_LOAD(opcode) case opcode - switch (opcode) -#endif - { - HANDLE_OP_LOAD(WASM_OP_I32_LOAD): - PUSH_I32(LOAD_I32(maddr)); - HANDLE_OP_END(); - HANDLE_OP_LOAD(WASM_OP_I64_LOAD): - PUSH_I64(LOAD_I64(maddr)); - HANDLE_OP_END(); - HANDLE_OP_LOAD(WASM_OP_F32_LOAD): - PUSH_I32(LOAD_I32(maddr)); - HANDLE_OP_END(); - HANDLE_OP_LOAD(WASM_OP_F64_LOAD): - PUSH_F64(LOAD_F64(maddr)); - HANDLE_OP_END(); - HANDLE_OP_LOAD(WASM_OP_I32_LOAD8_S): - PUSH_I32(sign_ext_8_32(*(int8*)maddr)); - HANDLE_OP_END(); - HANDLE_OP_LOAD(WASM_OP_I32_LOAD8_U): - PUSH_I32((uint32)(*(uint8*)maddr)); - HANDLE_OP_END(); - HANDLE_OP_LOAD(WASM_OP_I32_LOAD16_S): - PUSH_I32(sign_ext_16_32(LOAD_I16(maddr))); - HANDLE_OP_END(); - HANDLE_OP_LOAD(WASM_OP_I32_LOAD16_U): - PUSH_I32((uint32)(LOAD_U16(maddr))); - HANDLE_OP_END(); - HANDLE_OP_LOAD(WASM_OP_I64_LOAD8_S): - PUSH_I64(sign_ext_8_64(*(int8*)maddr)); - HANDLE_OP_END(); - HANDLE_OP_LOAD(WASM_OP_I64_LOAD8_U): - PUSH_I64((uint64)(*(uint8*)maddr)); - HANDLE_OP_END(); - HANDLE_OP_LOAD(WASM_OP_I64_LOAD16_S): - PUSH_I64(sign_ext_16_64(LOAD_I16(maddr))); - HANDLE_OP_END(); - HANDLE_OP_LOAD(WASM_OP_I64_LOAD16_U): - PUSH_I64((uint64)(LOAD_U16(maddr))); - HANDLE_OP_END(); - HANDLE_OP_LOAD(WASM_OP_I64_LOAD32_S): - PUSH_I64(sign_ext_32_64(LOAD_I32(maddr))); - HANDLE_OP_END(); - HANDLE_OP_LOAD(WASM_OP_I64_LOAD32_U): - PUSH_I64((uint64)(LOAD_U32(maddr))); - HANDLE_OP_END(); - } + addr = POP_I32(); + CHECK_MEMORY_OVERFLOW(4); + PUSH_I32(LOAD_I32(maddr)); (void)flags; - HANDLE_OP_END (); + HANDLE_OP_END(); + } + + HANDLE_OP (WASM_OP_I64_LOAD): + HANDLE_OP (WASM_OP_F64_LOAD): + { + uint32 offset, flags; + int32 addr; + + read_leb_uint32(frame_ip, frame_ip_end, flags); + read_leb_uint32(frame_ip, frame_ip_end, offset); + addr = POP_I32(); + CHECK_MEMORY_OVERFLOW(8); + PUSH_I64(LOAD_I64(maddr)); + (void)flags; + HANDLE_OP_END(); + } + + HANDLE_OP (WASM_OP_I32_LOAD8_S): + { + uint32 offset, flags; + int32 addr; + + read_leb_uint32(frame_ip, frame_ip_end, flags); + read_leb_uint32(frame_ip, frame_ip_end, offset); + addr = POP_I32(); + CHECK_MEMORY_OVERFLOW(1); + PUSH_I32(sign_ext_8_32(*(int8*)maddr)); + (void)flags; + HANDLE_OP_END(); + } + + HANDLE_OP (WASM_OP_I32_LOAD8_U): + { + uint32 offset, flags; + int32 addr; + + read_leb_uint32(frame_ip, frame_ip_end, flags); + read_leb_uint32(frame_ip, frame_ip_end, offset); + addr = POP_I32(); + CHECK_MEMORY_OVERFLOW(1); + PUSH_I32((uint32)(*(uint8*)maddr)); + (void)flags; + HANDLE_OP_END(); + } + + HANDLE_OP (WASM_OP_I32_LOAD16_S): + { + uint32 offset, flags; + int32 addr; + + read_leb_uint32(frame_ip, frame_ip_end, flags); + read_leb_uint32(frame_ip, frame_ip_end, offset); + addr = POP_I32(); + CHECK_MEMORY_OVERFLOW(2); + PUSH_I32(sign_ext_16_32(LOAD_I16(maddr))); + (void)flags; + HANDLE_OP_END(); + } + + HANDLE_OP (WASM_OP_I32_LOAD16_U): + { + uint32 offset, flags; + int32 addr; + + read_leb_uint32(frame_ip, frame_ip_end, flags); + read_leb_uint32(frame_ip, frame_ip_end, offset); + addr = POP_I32(); + CHECK_MEMORY_OVERFLOW(2); + PUSH_I32((uint32)(LOAD_U16(maddr))); + (void)flags; + HANDLE_OP_END(); + } + + HANDLE_OP (WASM_OP_I64_LOAD8_S): + { + uint32 offset, flags; + int32 addr; + + read_leb_uint32(frame_ip, frame_ip_end, flags); + read_leb_uint32(frame_ip, frame_ip_end, offset); + addr = POP_I32(); + CHECK_MEMORY_OVERFLOW(1); + PUSH_I64(sign_ext_8_64(*(int8*)maddr)); + (void)flags; + HANDLE_OP_END(); + } + + HANDLE_OP (WASM_OP_I64_LOAD8_U): + { + uint32 offset, flags; + int32 addr; + + read_leb_uint32(frame_ip, frame_ip_end, flags); + read_leb_uint32(frame_ip, frame_ip_end, offset); + addr = POP_I32(); + CHECK_MEMORY_OVERFLOW(1); + PUSH_I64((uint64)(*(uint8*)maddr)); + (void)flags; + HANDLE_OP_END(); + } + + HANDLE_OP (WASM_OP_I64_LOAD16_S): + { + uint32 offset, flags; + int32 addr; + + read_leb_uint32(frame_ip, frame_ip_end, flags); + read_leb_uint32(frame_ip, frame_ip_end, offset); + addr = POP_I32(); + CHECK_MEMORY_OVERFLOW(2); + PUSH_I64(sign_ext_16_64(LOAD_I16(maddr))); + (void)flags; + HANDLE_OP_END(); + } + + HANDLE_OP (WASM_OP_I64_LOAD16_U): + { + uint32 offset, flags; + int32 addr; + + read_leb_uint32(frame_ip, frame_ip_end, flags); + read_leb_uint32(frame_ip, frame_ip_end, offset); + addr = POP_I32(); + CHECK_MEMORY_OVERFLOW(2); + PUSH_I64((uint64)(LOAD_U16(maddr))); + (void)flags; + HANDLE_OP_END(); + } + + HANDLE_OP (WASM_OP_I64_LOAD32_S): + { + uint32 offset, flags; + int32 addr; + + opcode = *(frame_ip - 1); + read_leb_uint32(frame_ip, frame_ip_end, flags); + read_leb_uint32(frame_ip, frame_ip_end, offset); + addr = POP_I32(); + CHECK_MEMORY_OVERFLOW(4); + PUSH_I64(sign_ext_32_64(LOAD_I32(maddr))); + (void)flags; + HANDLE_OP_END(); + } + + HANDLE_OP (WASM_OP_I64_LOAD32_U): + { + uint32 offset, flags; + int32 addr; + + read_leb_uint32(frame_ip, frame_ip_end, flags); + read_leb_uint32(frame_ip, frame_ip_end, offset); + addr = POP_I32(); + CHECK_MEMORY_OVERFLOW(4); + PUSH_I64((uint64)(LOAD_U32(maddr))); + (void)flags; + HANDLE_OP_END(); } /* memory store instructions */ + HANDLE_OP (WASM_OP_I32_STORE): HANDLE_OP (WASM_OP_F32_STORE): { - uint32 offset, flags, addr; - GET_OPCODE(); + uint32 offset, flags; + int32 addr; + read_leb_uint32(frame_ip, frame_ip_end, flags); read_leb_uint32(frame_ip, frame_ip_end, offset); frame_sp--; - addr = (uint32)POP_I32(); - CHECK_MEMORY_OVERFLOW(); + addr = POP_I32(); + CHECK_MEMORY_OVERFLOW(4); STORE_U32(maddr, frame_sp[1]); (void)flags; HANDLE_OP_END (); } + HANDLE_OP (WASM_OP_I64_STORE): HANDLE_OP (WASM_OP_F64_STORE): { - uint32 offset, flags, addr; - GET_OPCODE(); + uint32 offset, flags; + int32 addr; + read_leb_uint32(frame_ip, frame_ip_end, flags); read_leb_uint32(frame_ip, frame_ip_end, offset); frame_sp -= 2; - addr = (uint32)POP_I32(); - CHECK_MEMORY_OVERFLOW(); + addr = POP_I32(); + CHECK_MEMORY_OVERFLOW(8); STORE_U32(maddr, frame_sp[1]); STORE_U32(maddr + 4, frame_sp[2]); (void)flags; HANDLE_OP_END (); } - HANDLE_OP (WASM_OP_I32_STORE): HANDLE_OP (WASM_OP_I32_STORE8): HANDLE_OP (WASM_OP_I32_STORE16): { - uint32 offset, flags, addr; + uint32 offset, flags; + int32 addr; uint32 sval; - GET_OPCODE(); + + opcode = *(frame_ip - 1); read_leb_uint32(frame_ip, frame_ip_end, flags); read_leb_uint32(frame_ip, frame_ip_end, offset); sval = (uint32)POP_I32(); - addr = (uint32)POP_I32(); - CHECK_MEMORY_OVERFLOW(); - switch (opcode) { - case WASM_OP_I32_STORE: - STORE_U32(maddr, sval); - break; - case WASM_OP_I32_STORE8: + addr = POP_I32(); + + if (opcode == WASM_OP_I32_STORE8) { + CHECK_MEMORY_OVERFLOW(1); *(uint8*)maddr = (uint8)sval; - break; - case WASM_OP_I32_STORE16: - STORE_U16(maddr, (uint16)sval); - break; } + else { + CHECK_MEMORY_OVERFLOW(2); + STORE_U16(maddr, (uint16)sval); + } + (void)flags; HANDLE_OP_END (); } - HANDLE_OP (WASM_OP_I64_STORE): HANDLE_OP (WASM_OP_I64_STORE8): HANDLE_OP (WASM_OP_I64_STORE16): HANDLE_OP (WASM_OP_I64_STORE32): { - uint32 offset, flags, addr; + uint32 offset, flags; + int32 addr; uint64 sval; - GET_OPCODE(); + + opcode = *(frame_ip - 1); read_leb_uint32(frame_ip, frame_ip_end, flags); read_leb_uint32(frame_ip, frame_ip_end, offset); sval = (uint64)POP_I64(); - addr = (uint32)POP_I32(); - CHECK_MEMORY_OVERFLOW(); - switch (opcode) { - case WASM_OP_I64_STORE: - STORE_I64(maddr, sval); - break; - case WASM_OP_I64_STORE8: + addr = POP_I32(); + + if (opcode == WASM_OP_I64_STORE8) { + CHECK_MEMORY_OVERFLOW(1); *(uint8*)maddr = (uint8)sval; - break; - case WASM_OP_I64_STORE16: + } + else if(opcode == WASM_OP_I64_STORE16) { + CHECK_MEMORY_OVERFLOW(2); STORE_U16(maddr, (uint16)sval); - break; - case WASM_OP_I64_STORE32: + } + else { + CHECK_MEMORY_OVERFLOW(4); STORE_U32(maddr, (uint32)sval); - break; } (void)flags; HANDLE_OP_END (); @@ -1671,11 +1742,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, PUSH_I32(prev_page_count); /* update the memory instance ptr */ memory = module->default_memory; - total_mem_size = num_bytes_per_page * memory->cur_page_count - - heap_base_offset; -#if WASM_ENABLE_BULK_MEMORY != 0 linear_mem_size = num_bytes_per_page * memory->cur_page_count; -#endif } (void)reserved; diff --git a/core/iwasm/interpreter/wasm_interp_fast.c b/core/iwasm/interpreter/wasm_interp_fast.c index 7f8ee8457..afb9ac3ef 100644 --- a/core/iwasm/interpreter/wasm_interp_fast.c +++ b/core/iwasm/interpreter/wasm_interp_fast.c @@ -226,11 +226,9 @@ LOAD_I16(void *addr) #endif /* WASM_CPU_SUPPORTS_UNALIGNED_64BIT_ACCESS != 0 */ #define CHECK_MEMORY_OVERFLOW(bytes) do { \ - int32 offset1 = (int32)(offset + addr); \ - uint64 offset2 = (uint64)(uint32)(offset1 - heap_base_offset); \ - /* if (flags != 2) \ - LOG_VERBOSE("unaligned load/store, flag: %d.\n", flags); */ \ - if (offset2 + bytes <= total_mem_size) \ + int64 offset1 = (int64)(uint32)offset + (int64)(int32)addr; \ + if (heap_base_offset <= offset1 \ + && offset1 <= (int64)linear_mem_size - bytes) \ /* If offset1 is in valid range, maddr must also be in valid range,\ no need to check it again. */ \ maddr = memory->memory_data + offset1; \ @@ -412,6 +410,8 @@ read_leb(const uint8 *buf, uint32 *p_offset, uint32 maxbits, bool sign) p += _off; \ } while (0) +#define read_uint32(p) (p += sizeof(uint32), *(uint32 *)(p - sizeof(uint32))) + #define GET_LOCAL_INDEX_TYPE_AND_OFFSET() do { \ uint32 param_count = cur_func->param_count; \ read_leb_uint32(frame_ip, frame_ip_end, local_idx); \ @@ -965,12 +965,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, WASMMemoryInstance *memory = module->default_memory; int32 heap_base_offset = memory ? memory->heap_base_offset : 0; uint32 num_bytes_per_page = memory ? memory->num_bytes_per_page : 0; - uint32 total_mem_size = memory ? num_bytes_per_page * memory->cur_page_count - - heap_base_offset : 0; uint8 *global_data = module->global_data; -#if WASM_ENABLE_BULK_MEMORY != 0 uint32 linear_mem_size = memory ? num_bytes_per_page * memory->cur_page_count : 0; -#endif WASMTableInstance *table = module->default_table; WASMGlobalInstance *globals = module->globals; uint8 opcode_IMPDEP = WASM_OP_IMPDEP; @@ -1067,9 +1063,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, #if WASM_ENABLE_THREAD_MGR != 0 CHECK_SUSPEND_FLAGS(); #endif - count = GET_OPERAND(uint32, 0); - didx = GET_OPERAND(uint32, 2); - frame_ip += 4; + count = read_uint32(frame_ip); + didx = GET_OPERAND(uint32, 0); + frame_ip += 2; if (!(didx >= 0 && (uint32)didx < count)) didx = count; @@ -1096,9 +1092,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, CHECK_SUSPEND_FLAGS(); #endif - tidx = GET_OPERAND(int32, 0); - val = GET_OPERAND(int32, 2); - frame_ip += 4; + tidx = read_uint32(frame_ip); + val = GET_OPERAND(int32, 0); + frame_ip += 2; if (tidx >= module->module->type_count) { wasm_set_exception(module, "type index is overflow"); @@ -1228,7 +1224,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP (WASM_OP_GET_GLOBAL): { - global_idx = frame_lp[GET_OFFSET()]; + global_idx = read_uint32(frame_ip); addr_ret = GET_OFFSET(); bh_assert(global_idx < module->global_count); @@ -1261,7 +1257,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP (WASM_OP_SET_GLOBAL): { - global_idx = frame_lp[GET_OFFSET()]; + global_idx = read_uint32(frame_ip); addr1 = GET_OFFSET(); bh_assert(global_idx < module->global_count); @@ -1281,6 +1277,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, if ((global_idx == (uint32)aux_stack_top_global_idx) && (frame_lp[addr1] < exec_env->aux_stack_boundary)) goto out_of_bounds; + *(int32*)global_addr = frame_lp[addr1]; + break; case VALUE_TYPE_F32: *(int32*)global_addr = frame_lp[addr1]; break; @@ -1300,9 +1298,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP (WASM_OP_I32_LOAD): { uint32 offset, addr; - offset = GET_OPERAND(uint32, 0); - addr = GET_OPERAND(uint32, 2); - frame_ip += 4; + offset = read_uint32(frame_ip); + addr = GET_OPERAND(uint32, 0); + frame_ip += 2; addr_ret = GET_OFFSET(); CHECK_MEMORY_OVERFLOW(4); frame_lp[addr_ret] = LOAD_I32(maddr); @@ -1312,9 +1310,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP (WASM_OP_I64_LOAD): { uint32 offset, addr; - offset = GET_OPERAND(uint32, 0); - addr = GET_OPERAND(uint32, 2); - frame_ip += 4; + offset = read_uint32(frame_ip); + addr = GET_OPERAND(uint32, 0); + frame_ip += 2; addr_ret = GET_OFFSET(); CHECK_MEMORY_OVERFLOW(8); PUT_I64_TO_ADDR(frame_lp + addr_ret, LOAD_I64(maddr)); @@ -1324,9 +1322,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP (WASM_OP_I32_LOAD8_S): { uint32 offset, addr; - offset = GET_OPERAND(uint32, 0); - addr = GET_OPERAND(uint32, 2); - frame_ip += 4; + offset = read_uint32(frame_ip); + addr = GET_OPERAND(uint32, 0); + frame_ip += 2; addr_ret = GET_OFFSET(); CHECK_MEMORY_OVERFLOW(1); frame_lp[addr_ret] = sign_ext_8_32(*(int8*)maddr); @@ -1336,9 +1334,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP (WASM_OP_I32_LOAD8_U): { uint32 offset, addr; - offset = GET_OPERAND(uint32, 0); - addr = GET_OPERAND(uint32, 2); - frame_ip += 4; + offset = read_uint32(frame_ip); + addr = GET_OPERAND(uint32, 0); + frame_ip += 2; addr_ret = GET_OFFSET(); CHECK_MEMORY_OVERFLOW(1); frame_lp[addr_ret] = (uint32)(*(uint8*)maddr); @@ -1348,9 +1346,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP (WASM_OP_I32_LOAD16_S): { uint32 offset, addr; - offset = GET_OPERAND(uint32, 0); - addr = GET_OPERAND(uint32, 2); - frame_ip += 4; + offset = read_uint32(frame_ip); + addr = GET_OPERAND(uint32, 0); + frame_ip += 2; addr_ret = GET_OFFSET(); CHECK_MEMORY_OVERFLOW(2); frame_lp[addr_ret] = sign_ext_16_32(LOAD_I16(maddr)); @@ -1360,9 +1358,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP (WASM_OP_I32_LOAD16_U): { uint32 offset, addr; - offset = GET_OPERAND(uint32, 0); - addr = GET_OPERAND(uint32, 2); - frame_ip += 4; + offset = read_uint32(frame_ip); + addr = GET_OPERAND(uint32, 0); + frame_ip += 2; addr_ret = GET_OFFSET(); CHECK_MEMORY_OVERFLOW(2); frame_lp[addr_ret] = (uint32)(LOAD_U16(maddr)); @@ -1372,9 +1370,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP (WASM_OP_I64_LOAD8_S): { uint32 offset, addr; - offset = GET_OPERAND(uint32, 0); - addr = GET_OPERAND(uint32, 2); - frame_ip += 4; + offset = read_uint32(frame_ip); + addr = GET_OPERAND(uint32, 0); + frame_ip += 2; addr_ret = GET_OFFSET(); CHECK_MEMORY_OVERFLOW(1); *(int64 *)(frame_lp + addr_ret) = sign_ext_8_64(*(int8*)maddr); @@ -1384,9 +1382,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP (WASM_OP_I64_LOAD8_U): { uint32 offset, addr; - offset = GET_OPERAND(uint32, 0); - addr = GET_OPERAND(uint32, 2); - frame_ip += 4; + offset = read_uint32(frame_ip); + addr = GET_OPERAND(uint32, 0); + frame_ip += 2; addr_ret = GET_OFFSET(); CHECK_MEMORY_OVERFLOW(1); *(int64 *)(frame_lp + addr_ret) = (uint64)(*(uint8*)maddr); @@ -1396,9 +1394,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP (WASM_OP_I64_LOAD16_S): { uint32 offset, addr; - offset = GET_OPERAND(uint32, 0); - addr = GET_OPERAND(uint32, 2); - frame_ip += 4; + offset = read_uint32(frame_ip); + addr = GET_OPERAND(uint32, 0); + frame_ip += 2; addr_ret = GET_OFFSET(); CHECK_MEMORY_OVERFLOW(2); *(int64 *)(frame_lp + addr_ret) = sign_ext_16_64(LOAD_I16(maddr)); @@ -1408,9 +1406,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP (WASM_OP_I64_LOAD16_U): { uint32 offset, addr; - offset = GET_OPERAND(uint32, 0); - addr = GET_OPERAND(uint32, 2); - frame_ip += 4; + offset = read_uint32(frame_ip); + addr = GET_OPERAND(uint32, 0); + frame_ip += 2; addr_ret = GET_OFFSET(); CHECK_MEMORY_OVERFLOW(2); *(int64 *)(frame_lp + addr_ret) = (uint64)(LOAD_U16(maddr)); @@ -1420,9 +1418,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP (WASM_OP_I64_LOAD32_S): { uint32 offset, addr; - offset = GET_OPERAND(uint32, 0); - addr = GET_OPERAND(uint32, 2); - frame_ip += 4; + offset = read_uint32(frame_ip); + addr = GET_OPERAND(uint32, 0); + frame_ip += 2; addr_ret = GET_OFFSET(); CHECK_MEMORY_OVERFLOW(4); *(int64 *)(frame_lp + addr_ret) = sign_ext_32_64(LOAD_I32(maddr)); @@ -1432,9 +1430,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP (WASM_OP_I64_LOAD32_U): { uint32 offset, addr; - offset = GET_OPERAND(uint32, 0); - addr = GET_OPERAND(uint32, 2); - frame_ip += 4; + offset = read_uint32(frame_ip); + addr = GET_OPERAND(uint32, 0); + frame_ip += 2; addr_ret = GET_OFFSET(); CHECK_MEMORY_OVERFLOW(4); *(int64 *)(frame_lp + addr_ret) = (uint64)(LOAD_U32(maddr)); @@ -1445,10 +1443,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, { uint32 offset, addr; uint32 sval; - offset = GET_OPERAND(uint32, 0); - sval = GET_OPERAND(uint32, 2); - addr = GET_OPERAND(uint32, 4); - frame_ip += 6; + offset = read_uint32(frame_ip); + sval = GET_OPERAND(uint32, 0); + addr = GET_OPERAND(uint32, 2); + frame_ip += 4; CHECK_MEMORY_OVERFLOW(4); STORE_U32(maddr, sval); HANDLE_OP_END (); @@ -1458,10 +1456,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, { uint32 offset, addr; uint32 sval; - offset = GET_OPERAND(uint32, 0); - sval = GET_OPERAND(uint32, 2); - addr = GET_OPERAND(uint32, 4); - frame_ip += 6; + offset = read_uint32(frame_ip); + sval = GET_OPERAND(uint32, 0); + addr = GET_OPERAND(uint32, 2); + frame_ip += 4; CHECK_MEMORY_OVERFLOW(1); *(uint8*)maddr = (uint8)sval; HANDLE_OP_END (); @@ -1471,10 +1469,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, { uint32 offset, addr; uint32 sval; - offset = GET_OPERAND(uint32, 0); - sval = GET_OPERAND(uint32, 2); - addr = GET_OPERAND(uint32, 4); - frame_ip += 6; + offset = read_uint32(frame_ip); + sval = GET_OPERAND(uint32, 0); + addr = GET_OPERAND(uint32, 2); + frame_ip += 4; CHECK_MEMORY_OVERFLOW(2); STORE_U16(maddr, (uint16)sval); HANDLE_OP_END (); @@ -1484,10 +1482,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, { uint32 offset, addr; uint64 sval; - offset = GET_OPERAND(uint32, 0); - sval = GET_OPERAND(uint64, 2); - addr = GET_OPERAND(uint32, 4); - frame_ip += 6; + offset = read_uint32(frame_ip); + sval = GET_OPERAND(uint64, 0); + addr = GET_OPERAND(uint32, 2); + frame_ip += 4; CHECK_MEMORY_OVERFLOW(8); STORE_I64(maddr, sval); HANDLE_OP_END (); @@ -1497,10 +1495,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, { uint32 offset, addr; uint64 sval; - offset = GET_OPERAND(uint32, 0); - sval = GET_OPERAND(uint64, 2); - addr = GET_OPERAND(uint32, 4); - frame_ip += 6; + offset = read_uint32(frame_ip); + sval = GET_OPERAND(uint64, 0); + addr = GET_OPERAND(uint32, 2); + frame_ip += 4; CHECK_MEMORY_OVERFLOW(1); *(uint8*)maddr = (uint8)sval; HANDLE_OP_END (); @@ -1510,10 +1508,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, { uint32 offset, addr; uint64 sval; - offset = GET_OPERAND(uint32, 0); - sval = GET_OPERAND(uint64, 2); - addr = GET_OPERAND(uint32, 4); - frame_ip += 6; + offset = read_uint32(frame_ip); + sval = GET_OPERAND(uint64, 0); + addr = GET_OPERAND(uint32, 2); + frame_ip += 4; CHECK_MEMORY_OVERFLOW(2); STORE_U16(maddr, (uint16)sval); HANDLE_OP_END (); @@ -1523,10 +1521,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, { uint32 offset, addr; uint64 sval; - offset = GET_OPERAND(uint32, 0); - sval = GET_OPERAND(uint64, 2); - addr = GET_OPERAND(uint32, 4); - frame_ip += 6; + offset = read_uint32(frame_ip); + sval = GET_OPERAND(uint64, 0); + addr = GET_OPERAND(uint32, 2); + frame_ip += 4; CHECK_MEMORY_OVERFLOW(4); STORE_U32(maddr, (uint32)sval); HANDLE_OP_END (); @@ -1563,11 +1561,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, frame_lp[addr_ret] = prev_page_count; /* update the memory instance ptr */ memory = module->default_memory; - total_mem_size = num_bytes_per_page * memory->cur_page_count - - heap_base_offset; -#if WASM_ENABLE_BULK_MEMORY != 0 linear_mem_size = num_bytes_per_page * memory->cur_page_count; -#endif } (void)reserved; @@ -2335,23 +2329,13 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP (EXT_OP_COPY_STACK_TOP): addr1 = GET_OFFSET(); addr2 = GET_OFFSET(); -#if defined(BUILD_TARGET_X86_32) - bh_memcpy_s(frame_lp + addr2, sizeof(int32), - frame_lp + addr1, sizeof(int32)); -#else frame_lp[addr2] = frame_lp[addr1]; -#endif HANDLE_OP_END (); HANDLE_OP (EXT_OP_COPY_STACK_TOP_I64): addr1 = GET_OFFSET(); addr2 = GET_OFFSET(); -#if defined(BUILD_TARGET_X86_32) - bh_memcpy_s(frame_lp + addr2, sizeof(int64), - frame_lp + addr1, sizeof(int64)); -#else - *(float64*)(frame_lp + addr2) = *(float64*)(frame_lp + addr1); -#endif + *(uint64*)(frame_lp + addr2) = *(uint64*)(frame_lp + addr1); HANDLE_OP_END (); HANDLE_OP (WASM_OP_SET_LOCAL): @@ -2441,8 +2425,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, uint64 bytes, offset, seg_len; uint8* data; - segment = GET_OPERAND(uint32, 0); - frame_ip += 2; + segment = read_uint32(frame_ip); bytes = (uint64)POP_I32(); offset = (uint64)POP_I32(); @@ -2463,8 +2446,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, { uint32 segment; - segment = GET_OPERAND(uint32, 0); - frame_ip += 2; + segment = read_uint32(frame_ip); module->module->data_segments[segment]->data_length = 0; @@ -2521,7 +2503,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, #if WASM_ENABLE_THREAD_MGR != 0 CHECK_SUSPEND_FLAGS(); #endif - fidx = frame_lp[GET_OFFSET()]; + fidx = read_uint32(frame_ip); #if WASM_ENABLE_MULTI_MODULE != 0 if (fidx >= module->function_count) { wasm_set_exception(module, "unknown function"); diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index 26491578b..9786762f9 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -3889,13 +3889,13 @@ wasm_loader_check_br(WASMLoaderContext *ctx, uint32 depth, LOG_OP("%d\t", byte); \ } while (0) -#define emit_leb() do { \ - wasm_loader_emit_leb(loader_ctx, p_org, p); \ +#define emit_uint32(ctx, value) do { \ + wasm_loader_emit_uint32(ctx, value); \ + LOG_OP("%d\t", value); \ } while (0) -#define emit_const(value) do { \ - GET_CONST_OFFSET(VALUE_TYPE_I32, value); \ - emit_operand(loader_ctx, operand_offset); \ +#define emit_leb() do { \ + wasm_loader_emit_leb(loader_ctx, p_org, p); \ } while (0) static bool @@ -3930,6 +3930,17 @@ wasm_loader_ctx_reinit(WASMLoaderContext *ctx) return true; } +static void +wasm_loader_emit_uint32(WASMLoaderContext *ctx, uint32 value) +{ + if (ctx->p_code_compiled) { + *(uint32*)(ctx->p_code_compiled) = value; + ctx->p_code_compiled += sizeof(uint32); + } + else + ctx->code_compiled_size += sizeof(uint32); +} + static void wasm_loader_emit_int16(WASMLoaderContext *ctx, int16 value) { @@ -5036,7 +5047,7 @@ re_scan: read_leb_uint32(p, p_end, count); #if WASM_ENABLE_FAST_INTERP != 0 - emit_const(count); + emit_uint32(loader_ctx, count); #endif POP_I32(); @@ -5097,7 +5108,7 @@ re_scan: read_leb_uint32(p, p_end, func_idx); #if WASM_ENABLE_FAST_INTERP != 0 // we need to emit func_idx before arguments - emit_const(func_idx); + emit_uint32(loader_ctx, func_idx); #endif if (func_idx >= module->import_function_count + module->function_count) { @@ -5150,7 +5161,7 @@ re_scan: read_leb_uint32(p, p_end, type_idx); #if WASM_ENABLE_FAST_INTERP != 0 // we need to emit func_idx before arguments - emit_const(type_idx); + emit_uint32(loader_ctx, type_idx); #endif /* reserved byte 0x00 */ @@ -5476,7 +5487,7 @@ re_scan: PUSH_TYPE(global_type); #if WASM_ENABLE_FAST_INTERP != 0 - emit_const(global_idx); + emit_uint32(loader_ctx, global_idx); PUSH_OFFSET_TYPE(global_type); #endif break; @@ -5513,7 +5524,7 @@ re_scan: POP_TYPE(global_type); #if WASM_ENABLE_FAST_INTERP != 0 - emit_const(global_idx); + emit_uint32(loader_ctx, global_idx); POP_OFFSET_TYPE(global_type); #endif break; @@ -5572,7 +5583,7 @@ re_scan: goto fail; } #if WASM_ENABLE_FAST_INTERP != 0 - emit_const(mem_offset); + emit_uint32(loader_ctx, mem_offset); #endif switch (opcode) { @@ -5951,7 +5962,7 @@ re_scan: case WASM_OP_MEMORY_INIT: read_leb_uint32(p, p_end, segment_index); #if WASM_ENABLE_FAST_INTERP != 0 - emit_const(segment_index); + emit_uint32(loader_ctx, segment_index); #endif if (module->import_memory_count == 0 && module->memory_count == 0) goto fail_unknown_memory; @@ -5977,7 +5988,7 @@ re_scan: case WASM_OP_DATA_DROP: read_leb_uint32(p, p_end, segment_index); #if WASM_ENABLE_FAST_INTERP != 0 - emit_const(segment_index); + emit_uint32(loader_ctx, segment_index); #endif if (segment_index >= module->data_seg_count) { set_error_buf(error_buf, error_buf_size, diff --git a/core/iwasm/interpreter/wasm_mini_loader.c b/core/iwasm/interpreter/wasm_mini_loader.c index dd7f2285c..02c68b894 100644 --- a/core/iwasm/interpreter/wasm_mini_loader.c +++ b/core/iwasm/interpreter/wasm_mini_loader.c @@ -2881,13 +2881,13 @@ wasm_loader_check_br(WASMLoaderContext *ctx, uint32 depth, LOG_OP("%d\t", byte); \ } while (0) -#define emit_leb() do { \ - wasm_loader_emit_leb(loader_ctx, p_org, p); \ +#define emit_uint32(ctx, value) do { \ + wasm_loader_emit_uint32(ctx, value); \ + LOG_OP("%d\t", value); \ } while (0) -#define emit_const(value) do { \ - GET_CONST_OFFSET(VALUE_TYPE_I32, value); \ - emit_operand(loader_ctx, operand_offset); \ +#define emit_leb() do { \ + wasm_loader_emit_leb(loader_ctx, p_org, p); \ } while (0) static bool @@ -2922,6 +2922,17 @@ wasm_loader_ctx_reinit(WASMLoaderContext *ctx) return true; } +static void +wasm_loader_emit_uint32(WASMLoaderContext *ctx, uint32 value) +{ + if (ctx->p_code_compiled) { + *(uint32*)(ctx->p_code_compiled) = value; + ctx->p_code_compiled += sizeof(uint32); + } + else + ctx->code_compiled_size += sizeof(uint32); +} + static void wasm_loader_emit_int16(WASMLoaderContext *ctx, int16 value) { @@ -3968,7 +3979,7 @@ re_scan: read_leb_uint32(p, p_end, count); #if WASM_ENABLE_FAST_INTERP != 0 - emit_const(count); + emit_uint32(loader_ctx, count); #endif POP_I32(); @@ -4025,7 +4036,7 @@ re_scan: read_leb_uint32(p, p_end, func_idx); #if WASM_ENABLE_FAST_INTERP != 0 // we need to emit func_idx before arguments - emit_const(func_idx); + emit_uint32(loader_ctx, func_idx); #endif bh_assert(func_idx < module->import_function_count @@ -4069,7 +4080,7 @@ re_scan: read_leb_uint32(p, p_end, type_idx); #if WASM_ENABLE_FAST_INTERP != 0 // we need to emit func_idx before arguments - emit_const(type_idx); + emit_uint32(loader_ctx, type_idx); #endif /* reserved byte 0x00 */ @@ -4369,7 +4380,7 @@ re_scan: PUSH_TYPE(global_type); #if WASM_ENABLE_FAST_INTERP != 0 - emit_const(global_idx); + emit_uint32(loader_ctx, global_idx); PUSH_OFFSET_TYPE(global_type); #endif break; @@ -4396,7 +4407,7 @@ re_scan: POP_TYPE(global_type); #if WASM_ENABLE_FAST_INTERP != 0 - emit_const(global_idx); + emit_uint32(loader_ctx, global_idx); POP_OFFSET_TYPE(global_type); #endif (void)is_mutable; @@ -4452,7 +4463,7 @@ re_scan: read_leb_uint32(p, p_end, align); /* align */ read_leb_uint32(p, p_end, mem_offset); /* offset */ #if WASM_ENABLE_FAST_INTERP != 0 - emit_const(mem_offset); + emit_uint32(loader_ctx, mem_offset); #endif switch (opcode) { @@ -4823,7 +4834,7 @@ re_scan: case WASM_OP_MEMORY_INIT: read_leb_uint32(p, p_end, segment_index); #if WASM_ENABLE_FAST_INTERP != 0 - emit_const(segment_index); + emit_uint32(loader_ctx, segment_index); #endif bh_assert(module->import_memory_count + module->memory_count > 0); @@ -4841,7 +4852,7 @@ re_scan: case WASM_OP_DATA_DROP: read_leb_uint32(p, p_end, segment_index); #if WASM_ENABLE_FAST_INTERP != 0 - emit_const(segment_index); + emit_uint32(loader_ctx, segment_index); #endif bh_assert(segment_index < module->data_seg_count); bh_assert(module->data_seg_count1 > 0); diff --git a/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c b/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c index f7aa9083f..a19ac6f5b 100644 --- a/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c +++ b/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c @@ -483,6 +483,7 @@ pthread_start_routine(void *arg) return NULL; } + wasm_exec_env_set_thread_info(exec_env); argv[0] = addr_native_to_app(routine_args->arg); if(!wasm_runtime_call_indirect(exec_env, diff --git a/core/shared/platform/alios/alios_platform.c b/core/shared/platform/alios/alios_platform.c index 0af45aeb4..815054820 100644 --- a/core/shared/platform/alios/alios_platform.c +++ b/core/shared/platform/alios/alios_platform.c @@ -42,19 +42,21 @@ os_free(void *ptr) } void * -os_mmap(void *hint, unsigned int size, int prot, int flags) +os_mmap(void *hint, size_t size, int prot, int flags) { - return BH_MALLOC(size); + if ((uint64)size >= UINT32_MAX) + return NULL; + return BH_MALLOC((uint32)size); } void -os_munmap(void *addr, uint32 size) +os_munmap(void *addr, size_t size) { return BH_FREE(addr); } int -os_mprotect(void *addr, uint32 size, int prot) +os_mprotect(void *addr, size_t size, int prot) { return 0; } diff --git a/core/shared/platform/android/platform_internal.h b/core/shared/platform/android/platform_internal.h index bf1248a25..74c3f2365 100644 --- a/core/shared/platform/android/platform_internal.h +++ b/core/shared/platform/android/platform_internal.h @@ -48,6 +48,38 @@ typedef pthread_mutex_t korp_mutex; typedef pthread_cond_t korp_cond; typedef pthread_t korp_thread; +#if WASM_DISABLE_HW_BOUND_CHECK == 0 +#if defined(BUILD_TARGET_X86_64) \ + || defined(BUILD_TARGET_AMD_64) \ + || defined(BUILD_TARGET_AARCH64) + +#include +#include + +#define OS_ENABLE_HW_BOUND_CHECK + +#define os_thread_local_attribute __thread + +typedef jmp_buf korp_jmpbuf; + +#define os_setjmp setjmp +#define os_longjmp longjmp +#define os_alloca alloca + +#define os_getpagesize getpagesize + +typedef void (*os_signal_handler)(void *sig_addr); + +int os_signal_init(os_signal_handler handler); + +void os_signal_destroy(); + +void os_signal_unmask(); + +void os_sigreturn(); +#endif /* end of BUILD_TARGET_X86_64/AMD_64/AARCH64 */ +#endif /* end of WASM_DISABLE_HW_BOUND_CHECK */ + #ifdef __cplusplus } #endif diff --git a/core/shared/platform/common/posix/posix_memmap.c b/core/shared/platform/common/posix/posix_memmap.c index 7625cf66a..26b8d8427 100644 --- a/core/shared/platform/common/posix/posix_memmap.c +++ b/core/shared/platform/common/posix/posix_memmap.c @@ -6,7 +6,7 @@ #include "platform_api_vmcore.h" void * -os_mmap(void *hint, uint32 size, int prot, int flags) +os_mmap(void *hint, size_t size, int prot, int flags) { int map_prot = PROT_NONE; int map_flags = MAP_ANONYMOUS | MAP_PRIVATE; @@ -17,7 +17,12 @@ os_mmap(void *hint, uint32 size, int prot, int flags) page_size = getpagesize(); request_size = (size + page_size - 1) & ~(page_size - 1); - if (request_size >= UINT32_MAX) + if ((size_t)request_size < size) + /* integer overflow */ + return NULL; + + if (request_size > 16 * (uint64)UINT32_MAX) + /* At most 16 G is allowed */ return NULL; if (prot & MMAP_PROT_READ) @@ -53,7 +58,7 @@ os_mmap(void *hint, uint32 size, int prot, int flags) } void -os_munmap(void *addr, uint32 size) +os_munmap(void *addr, size_t size) { uint64 page_size = getpagesize(); uint64 request_size = (size + page_size - 1) & ~(page_size - 1); @@ -67,9 +72,11 @@ os_munmap(void *addr, uint32 size) } int -os_mprotect(void *addr, uint32 size, int prot) +os_mprotect(void *addr, size_t size, int prot) { int map_prot = PROT_NONE; + uint64 page_size = getpagesize(); + uint64 request_size = (size + page_size - 1) & ~(page_size - 1); if (!addr) return 0; @@ -83,7 +90,7 @@ os_mprotect(void *addr, uint32 size, int prot) if (prot & MMAP_PROT_EXEC) map_prot |= PROT_EXEC; - return mprotect(addr, size, map_prot); + return mprotect(addr, request_size, map_prot); } void diff --git a/core/shared/platform/common/posix/posix_thread.c b/core/shared/platform/common/posix/posix_thread.c index 54ff0e8cd..58d8fee7e 100644 --- a/core/shared/platform/common/posix/posix_thread.c +++ b/core/shared/platform/common/posix/posix_thread.c @@ -21,7 +21,7 @@ static void *os_thread_wrapper(void *arg) thread_wrapper_arg * targ = arg; thread_start_routine_t start_func = targ->start; void *thread_arg = targ->arg; - printf("THREAD CREATE %p\n", &targ); + os_printf("THREAD CREATED %p\n", &targ); targ->stack = (void *)((uintptr_t)(&arg) & (uintptr_t)~0xfff); BH_FREE(targ); start_func(thread_arg); @@ -41,8 +41,8 @@ int os_thread_create_with_prio(korp_tid *tid, thread_start_routine_t start, pthread_attr_init(&tattr); pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_JOINABLE); if (pthread_attr_setstacksize(&tattr, stack_size) != 0) { - printf("Invalid thread stack size %u. Min stack size on Linux = %u", - stack_size, PTHREAD_STACK_MIN); + os_printf("Invalid thread stack size %u. Min stack size on Linux = %u", + stack_size, PTHREAD_STACK_MIN); pthread_attr_destroy(&tattr); return BHT_ERROR; } @@ -123,7 +123,7 @@ int os_mutex_lock(korp_mutex *mutex) assert(mutex); ret = pthread_mutex_lock(mutex); if (0 != ret) { - printf("vm mutex lock failed (ret=%d)!\n", ret); + os_printf("vm mutex lock failed (ret=%d)!\n", ret); exit(-1); } return ret; @@ -140,7 +140,7 @@ int os_mutex_unlock(korp_mutex *mutex) assert(mutex); ret = pthread_mutex_unlock(mutex); if (0 != ret) { - printf("vm mutex unlock failed (ret=%d)!\n", ret); + os_printf("vm mutex unlock failed (ret=%d)!\n", ret); exit(-1); } return ret; @@ -241,15 +241,16 @@ uint8 *os_thread_get_stack_boundary() pthread_attr_t attr; uint8 *addr = NULL; size_t stack_size, guard_size; + int page_size = getpagesize(); #ifdef __linux__ if (pthread_getattr_np(self, &attr) == 0) { pthread_attr_getstack(&attr, (void**)&addr, &stack_size); pthread_attr_getguardsize(&attr, &guard_size); pthread_attr_destroy(&attr); - if (guard_size < 4 * 1024) - /* Reserved 4 KB guard size at least for safety */ - guard_size = 4 * 1024; + if (guard_size < (size_t)page_size) + /* Reserved 1 guard page at least for safety */ + guard_size = (size_t)page_size; addr += guard_size; } (void)stack_size; @@ -257,10 +258,150 @@ uint8 *os_thread_get_stack_boundary() if ((addr = (uint8*)pthread_get_stackaddr_np(self))) { stack_size = pthread_get_stacksize_np(self); addr -= stack_size; - /* Reserved 4 KB guard size at least for safety */ - addr += 4 * 1024; + /* Reserved 1 guard page at least for safety */ + addr += page_size; } #endif return addr; -} \ No newline at end of file +} + +#ifdef OS_ENABLE_HW_BOUND_CHECK + +#define SIG_ALT_STACK_SIZE (32 * 1024) + +/* The signal alternate stack base addr */ +static uint8 *sigalt_stack_base_addr; + +/* The signal handler passed to os_signal_init() */ +static os_signal_handler signal_handler; + +static void +mask_signals(int how) +{ + sigset_t set; + + sigemptyset(&set); + sigaddset(&set, SIGSEGV); + sigaddset(&set, SIGBUS); + pthread_sigmask(how, &set, NULL); +} + +__attribute__((noreturn)) static void +signal_callback(int sig_num, siginfo_t *sig_info, void *sig_ucontext) +{ + int i; + void *sig_addr = sig_info->si_addr; + + mask_signals(SIG_BLOCK); + + if (signal_handler + && (sig_num == SIGSEGV || sig_num == SIGBUS)) { + signal_handler(sig_addr); + } + + /* signal unhandled */ + switch (sig_num) { + case SIGSEGV: + os_printf("unhandled SIGSEGV, si_addr: %p\n", sig_addr); + break; + case SIGBUS: + os_printf("unhandled SIGBUS, si_addr: %p\n", sig_addr); + break; + default: + os_printf("unhandle signal %d, si_addr: %p\n", + sig_num, sig_addr); + break; + } + + /* divived by 0 to make it abort */ + i = os_printf(" "); + os_printf("%d\n", i / (i - 1)); + /* access NULL ptr to make it abort */ + os_printf("%d\n", *(uint32*)(uintptr_t)(i - 1)); + exit(1); +} + +int +os_signal_init(os_signal_handler handler) +{ + int ret = -1; + struct sigaction sig_act; + stack_t sigalt_stack_info; + uint32 map_size = SIG_ALT_STACK_SIZE; + uint8 *map_addr; + + /* Initialize memory for signal alternate stack */ + if (!(map_addr = os_mmap(NULL, map_size, + MMAP_PROT_READ | MMAP_PROT_WRITE, + MMAP_MAP_NONE))) { + os_printf("Failed to mmap memory for alternate stack\n"); + return -1; + } + + /* Initialize signal alternate stack */ + memset(map_addr, 0, map_size); + sigalt_stack_info.ss_sp = map_addr; + sigalt_stack_info.ss_size = map_size; + sigalt_stack_info.ss_flags = 0; + if ((ret = sigaltstack(&sigalt_stack_info, NULL)) != 0) { + goto fail1; + } + + /* Install signal hanlder */ + sig_act.sa_sigaction = signal_callback; + sig_act.sa_flags = SA_SIGINFO | SA_ONSTACK | SA_NODEFER; + sigemptyset(&sig_act.sa_mask); + if ((ret = sigaction(SIGSEGV, &sig_act, NULL)) != 0 + || (ret = sigaction(SIGBUS, &sig_act, NULL)) != 0) { + goto fail2; + } + + sigalt_stack_base_addr = map_addr; + signal_handler = handler; + return 0; + +fail2: + memset(&sigalt_stack_info, 0, sizeof(stack_t)); + sigalt_stack_info.ss_flags = SS_DISABLE; + sigalt_stack_info.ss_size = map_size; + sigaltstack(&sigalt_stack_info, NULL); +fail1: + os_munmap(map_addr, map_size); + return ret; +} + +void +os_signal_destroy() +{ + stack_t sigalt_stack_info; + + /* Disable signal alternate stack */ + memset(&sigalt_stack_info, 0, sizeof(stack_t)); + sigalt_stack_info.ss_flags = SS_DISABLE; + sigalt_stack_info.ss_size = SIG_ALT_STACK_SIZE; + sigaltstack(&sigalt_stack_info, NULL); + + os_munmap(sigalt_stack_base_addr, SIG_ALT_STACK_SIZE); +} + +void +os_signal_unmask() +{ + mask_signals(SIG_UNBLOCK); +} + +void +os_sigreturn() +{ +#if defined(__APPLE__) + #define UC_RESET_ALT_STACK 0x80000000 + extern int __sigreturn(void *, int); + + /* It's necessary to call __sigreturn to restore the sigaltstack state + after exiting the signal handler. */ + __sigreturn(NULL, UC_RESET_ALT_STACK); +#endif +} +#endif /* end of OS_ENABLE_HW_BOUND_CHECK */ + diff --git a/core/shared/platform/darwin/platform_internal.h b/core/shared/platform/darwin/platform_internal.h index 55622028b..e0820b32d 100644 --- a/core/shared/platform/darwin/platform_internal.h +++ b/core/shared/platform/darwin/platform_internal.h @@ -51,6 +51,38 @@ typedef pthread_t korp_thread; #define os_printf printf #define os_vprintf vprintf +#if WASM_DISABLE_HW_BOUND_CHECK == 0 +#if defined(BUILD_TARGET_X86_64) \ + || defined(BUILD_TARGET_AMD_64) \ + || defined(BUILD_TARGET_AARCH64) + +#include +#include + +#define OS_ENABLE_HW_BOUND_CHECK + +#define os_thread_local_attribute __thread + +typedef jmp_buf korp_jmpbuf; + +#define os_setjmp setjmp +#define os_longjmp longjmp +#define os_alloca alloca + +#define os_getpagesize getpagesize + +typedef void (*os_signal_handler)(void *sig_addr); + +int os_signal_init(os_signal_handler handler); + +void os_signal_destroy(); + +void os_signal_unmask(); + +void os_sigreturn(); +#endif /* end of BUILD_TARGET_X86_64/AMD_64/AARCH64 */ +#endif /* end of WASM_DISABLE_HW_BOUND_CHECK */ + #ifdef __cplusplus } #endif diff --git a/core/shared/platform/include/platform_api_vmcore.h b/core/shared/platform/include/platform_api_vmcore.h index acf6522ab..f7f2cad00 100644 --- a/core/shared/platform/include/platform_api_vmcore.h +++ b/core/shared/platform/include/platform_api_vmcore.h @@ -110,9 +110,9 @@ enum { MMAP_MAP_FIXED = 2 }; -void *os_mmap(void *hint, unsigned int size, int prot, int flags); -void os_munmap(void *addr, uint32 size); -int os_mprotect(void *addr, uint32 size, int prot); +void *os_mmap(void *hint, size_t size, int prot, int flags); +void os_munmap(void *addr, size_t size); +int os_mprotect(void *addr, size_t size, int prot); /** * Flush cpu data cache, in some CPUs, after applying relocation to the diff --git a/core/shared/platform/linux-sgx/sgx_platform.c b/core/shared/platform/linux-sgx/sgx_platform.c index e52df1da5..f018db4de 100644 --- a/core/shared/platform/linux-sgx/sgx_platform.c +++ b/core/shared/platform/linux-sgx/sgx_platform.c @@ -82,7 +82,7 @@ int os_vprintf(const char * format, va_list arg) return 0; } -void* os_mmap(void *hint, uint32 size, int prot, int flags) +void* os_mmap(void *hint, size_t size, int prot, int flags) { #if WASM_ENABLE_AOT != 0 int mprot = 0; @@ -124,7 +124,7 @@ void* os_mmap(void *hint, uint32 size, int prot, int flags) #endif } -void os_munmap(void *addr, uint32 size) +void os_munmap(void *addr, size_t size) { #if WASM_ENABLE_AOT != 0 uint64 aligned_size, page_size; @@ -135,11 +135,15 @@ void os_munmap(void *addr, uint32 size) #endif } -int os_mprotect(void *addr, uint32 size, int prot) +int os_mprotect(void *addr, size_t size, int prot) { #if WASM_ENABLE_AOT != 0 int mprot = 0; sgx_status_t st = 0; + uint64 aligned_size, page_size; + + page_size = getpagesize(); + aligned_size = (size + page_size - 1) & ~(page_size - 1); if (prot & MMAP_PROT_READ) mprot |= SGX_PROT_READ; @@ -147,7 +151,7 @@ int os_mprotect(void *addr, uint32 size, int prot) mprot |= SGX_PROT_WRITE; if (prot & MMAP_PROT_EXEC) mprot |= SGX_PROT_EXEC; - st = sgx_tprotect_rsrv_mem(addr, size, mprot); + st = sgx_tprotect_rsrv_mem(addr, aligned_size, mprot); if (st != SGX_SUCCESS) os_printf("os_mprotect(addr=0x%lx, size=%u, prot=0x%x) failed.", addr, size, prot); diff --git a/core/shared/platform/linux/platform_internal.h b/core/shared/platform/linux/platform_internal.h index 445d881fd..d3bc9d2b2 100644 --- a/core/shared/platform/linux/platform_internal.h +++ b/core/shared/platform/linux/platform_internal.h @@ -51,6 +51,38 @@ typedef pthread_t korp_thread; #define os_printf printf #define os_vprintf vprintf +#if WASM_DISABLE_HW_BOUND_CHECK == 0 +#if defined(BUILD_TARGET_X86_64) \ + || defined(BUILD_TARGET_AMD_64) \ + || defined(BUILD_TARGET_AARCH64) + +#include +#include + +#define OS_ENABLE_HW_BOUND_CHECK + +#define os_thread_local_attribute __thread + +typedef jmp_buf korp_jmpbuf; + +#define os_setjmp setjmp +#define os_longjmp longjmp +#define os_alloca alloca + +#define os_getpagesize getpagesize + +typedef void (*os_signal_handler)(void *sig_addr); + +int os_signal_init(os_signal_handler handler); + +void os_signal_destroy(); + +void os_signal_unmask(); + +void os_sigreturn(); +#endif /* end of BUILD_TARGET_X86_64/AMD_64/AARCH64 */ +#endif /* end of WASM_DISABLE_HW_BOUND_CHECK */ + #ifdef __cplusplus } #endif diff --git a/core/shared/platform/vxworks/platform_internal.h b/core/shared/platform/vxworks/platform_internal.h index 06b4d3ae4..a78366924 100644 --- a/core/shared/platform/vxworks/platform_internal.h +++ b/core/shared/platform/vxworks/platform_internal.h @@ -50,6 +50,38 @@ typedef pthread_t korp_thread; #define os_printf printf #define os_vprintf vprintf +#if WASM_DISABLE_HW_BOUND_CHECK == 0 +#if defined(BUILD_TARGET_X86_64) \ + || defined(BUILD_TARGET_AMD_64) \ + || defined(BUILD_TARGET_AARCH64) + +#include +#include + +#define OS_ENABLE_HW_BOUND_CHECK + +#define os_thread_local_attribute __thread + +typedef jmp_buf korp_jmpbuf; + +#define os_setjmp setjmp +#define os_longjmp longjmp +#define os_alloca alloca + +#define os_getpagesize getpagesize + +typedef void (*os_signal_handler)(void *sig_addr); + +int os_signal_init(os_signal_handler handler); + +void os_signal_destroy(); + +void os_signal_unmask(); + +void os_sigreturn(); +#endif /* end of BUILD_TARGET_X86_64/AMD_64/AARCH64 */ +#endif /* end of WASM_DISABLE_HW_BOUND_CHECK */ + #ifdef __cplusplus } #endif diff --git a/core/shared/platform/zephyr/zephyr_platform.c b/core/shared/platform/zephyr/zephyr_platform.c index 0f52d1105..d2408948d 100644 --- a/core/shared/platform/zephyr/zephyr_platform.c +++ b/core/shared/platform/zephyr/zephyr_platform.c @@ -110,16 +110,18 @@ os_vprintf(const char *fmt, va_list ap) } void * -os_mmap(void *hint, unsigned int size, int prot, int flags) +os_mmap(void *hint, size_t size, int prot, int flags) { + if ((uint64)size >= UINT32_MAX) + return NULL; if (exec_mem_alloc_func) - return exec_mem_alloc_func(size); + return exec_mem_alloc_func((uint32)size); else return BH_MALLOC(size); } void -os_munmap(void *addr, uint32 size) +os_munmap(void *addr, size_t size) { if (exec_mem_free_func) exec_mem_free_func(addr); @@ -128,7 +130,7 @@ os_munmap(void *addr, uint32 size) } int -os_mprotect(void *addr, uint32 size, int prot) +os_mprotect(void *addr, size_t size, int prot) { return 0; } diff --git a/doc/build_wamr.md b/doc/build_wamr.md index b6d56307d..b9405633d 100644 --- a/doc/build_wamr.md +++ b/doc/build_wamr.md @@ -46,7 +46,7 @@ The script `runtime_lib.cmake` defined a number of variables for configuring the - **WAMR_BUILD_LIBC_BUILTIN**=1/0, default to enable if no set -- **WAMR_BUILD_LIBC_WASI**=1/0, default to disable if no set +- **WAMR_BUILD_LIBC_WASI**=1/0, default to enable if no set #### **Enable Multi-Module feature** @@ -55,7 +55,7 @@ The script `runtime_lib.cmake` defined a number of variables for configuring the #### **Enable WASM mini loader** - **WAMR_BUILD_MINI_LOADER**=1/0, default to disable if not set -Note: the mini loader doesn't check the integrity of the WASM binary file, user must ensure that the WASM file is not mal-formed. +Note: the mini loader doesn't check the integrity of the WASM binary file, developer must ensure that the WASM file is not mal-formed. #### **Enable shared memory feature** - **WAMR_BUILD_SHARED_MEMORY**=1/0, default to disable if not set @@ -63,10 +63,14 @@ Note: the mini loader doesn't check the integrity of the WASM binary file, user #### **Enable thread manager** - **WAMR_BUILD_THREAD_MGR**=1/0, default to disable if not set -#### **Enable Lib-pthread** +#### **Enable lib-pthread** - **WAMR_BUILD_LIB_PTHREAD**=1/0, default to disable if not set > Note: The dependent feature of lib pthread such as the `shared memory` and `thread manager` will be enabled automatically. +#### **Disable boundary check with hardware trap in AOT or JIT mode** +- **WAMR_DISABLE_HW_BOUND_CHECK=1, default to enable if not set and supported by platform +> Note: by default only platform linux/darwin/android/vxworks 64-bit will enable boundary check with hardware trap in AOT or JIT mode, and the wamrc tool will generate AOT code without boundary check instructions in all 64-bit targets except SGX to improve performance. + **Combination of configurations:** We can combine the configurations. For example, if we want to disable interpreter, enable AOT and WASI, we can run command: diff --git a/doc/build_wasm_app.md b/doc/build_wasm_app.md index 8401da195..b110de3b8 100644 --- a/doc/build_wasm_app.md +++ b/doc/build_wasm_app.md @@ -2,7 +2,7 @@ # Prepare WASM building environments -WASI-SDK version 7.0+ is the major tool supported by WAMR for building WASM applications. There are some other WASM compilers such as the standard clang compiler and Emscripten might also work [here](./other_wasm_compilers.md). +WASI-SDK version 8.0+ is the major tool supported by WAMR to build WASM applications. There are some other WASM compilers such as the standard clang compiler and Emscripten might also work [here](./other_wasm_compilers.md). Install WASI SDK: Download the [wasi-sdk](https://github.com/CraneStation/wasi-sdk/releases) and extract the archive to default path `/opt/wasi-sdk` @@ -38,14 +38,47 @@ int main(int argc, char **argv) } ``` - - -To build the source file to WASM bytecode, input following command: +To build the source file to WASM bytecode, we can input the following command: ``` Bash -/opt/wasi-sdk/bin/clang test.c -o test.wasm +/opt/wasi-sdk/bin/clang -O3 -o test.wasm test.c ``` +There are some useful options which can be specified to build the source code: + +- **-nostdlib** Do not use the standard system startup files or libraries when linking. In this mode, the libc-builtin library of WAMR must be built to run the wasm app, otherwise, the libc-wasi library must be built. You can specify **-DWAMR_BUILD_LIBC_BUILTIN** or **-DWAMR_BUILD_LIBC_WASI** for cmake to build WAMR with libc-builtin support or libc-wasi support. + +- **-Wl,--no-entry** Do not output any entry point + +- **-Wl,--export=** Force a symbol to be exported, e.g. **-Wl,--export=main** to export main function + +- **-Wl,--export-all** Export all symbols (normally combined with --no-gc-sections) + +- **-Wl,--initial-memory=** Initial size of the linear memory, which must be a multiple of 65536 + +- **-Wl,--max-memory=** Maximum size of the linear memory, which must be a multiple of 65536 + +- **-z stack-size=** The auxiliary stack size, which is an area of linear memory, and must be smaller than initial memory size. + +- **-Wl,--strip-all** Strip all symbols + +- **-Wl,--shared-memory** Use shared linear memory + +- **-Wl,--threads** or **-Wl,--no-threads** Run or do not run the linker multi-threaded + +- **-Wl,--allow-undefined** Allow undefined symbols in linked binary + +- **-Wl,--allow-undefined-file=** Allow symbols listed in to be undefined in linked binary + +For example, we can build the wasm app with command: +``` Bash +/opt/wasi-sdk/bin/clang -O3 -nostdlib \ + -z stack-size=8192 -Wl,--initial-memory=65536 \ + -Wl,--export=main -o test.wasm test.c \ + -Wl,--export=__heap_base,--export=__data_end \ + -Wl,--no-entry -Wl,--strip-all -Wl,--allow-undefined +``` +to generate a wasm binary with small footprint. # Build a project with cmake diff --git a/product-mini/platforms/linux/CMakeLists.txt b/product-mini/platforms/linux/CMakeLists.txt index 642155f40..053e76eac 100644 --- a/product-mini/platforms/linux/CMakeLists.txt +++ b/product-mini/platforms/linux/CMakeLists.txt @@ -70,6 +70,10 @@ if (NOT DEFINED WAMR_BUILD_MINI_LOADER) set (WAMR_BUILD_MINI_LOADER 0) endif () +if (COLLECT_CODE_COVERAGE EQUAL 1) + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage") +endif () + set (WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../..) include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) @@ -108,5 +112,4 @@ install (TARGETS libiwasm DESTINATION lib) set_target_properties (libiwasm PROPERTIES OUTPUT_NAME iwasm) -target_link_libraries (libiwasm ${LLVM_AVAILABLE_LIBS} -lm -ldl -lpthread) - +target_link_libraries (libiwasm ${LLVM_AVAILABLE_LIBS} -lm -ldl -lpthread) \ No newline at end of file diff --git a/wamr-compiler/CMakeLists.txt b/wamr-compiler/CMakeLists.txt index a00884782..02fadd359 100644 --- a/wamr-compiler/CMakeLists.txt +++ b/wamr-compiler/CMakeLists.txt @@ -15,6 +15,7 @@ set (CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") add_definitions(-DWASM_ENABLE_INTERP=1) add_definitions(-DWASM_ENABLE_WAMR_COMPILER=1) add_definitions(-DWASM_ENABLE_BULK_MEMORY=1) +add_definitions(-DWASM_DISABLE_HW_BOUND_CHECK=1) # Set WAMR_BUILD_TARGET, currently values supported: # "X86_64", "AMD_64", "X86_32", "ARM_32", "MIPS_32", "XTENSA_32" diff --git a/wamr-compiler/main.c b/wamr-compiler/main.c index 72f717075..7b54cd879 100644 --- a/wamr-compiler/main.c +++ b/wamr-compiler/main.c @@ -26,9 +26,13 @@ print_help() printf(" Use +feature to enable a feature, or -feature to disable it\n"); printf(" For example, --cpu-features=+feature1,-feature2\n"); printf(" Use --cpu-features=+help to list all the features supported\n"); - printf(" --opt-level=n Set the optimization level (0 to 3, default: 3, which is fastest)\n"); - printf(" --size-level=n Set the code size level (0 to 3, default: 3, which is smallest)\n"); + printf(" --opt-level=n Set the optimization level (0 to 3, default is 3)\n"); + printf(" --size-level=n Set the code size level (0 to 3, default is 3)\n"); printf(" -sgx Generate code for SGX platform (Intel Software Guard Extention)\n"); + printf(" --bounds-checks=1/0 Enable or disable the bounds checks for memory access:\n"); + printf(" by default it is disabled in all 64-bit platforms except SGX and\n"); + printf(" in these platforms runtime does bounds checks with hardware trap,\n"); + printf(" and by default it is enabled in all 32-bit platforms\n"); printf(" --format= Specifies the format of the output file\n"); printf(" The format supported:\n"); printf(" aot (default) AoT file\n"); @@ -61,6 +65,8 @@ main(int argc, char *argv[]) option.opt_level = 3; option.size_level = 3; option.output_format = AOT_FORMAT_FILE; + /* default value, enable or disable depends on the platform */ + option.bounds_checks = 2; /* Process options. */ for (argc--, argv++; argc > 0 && argv[0][0] == '-'; argc--, argv++) { @@ -107,6 +113,9 @@ main(int argc, char *argv[]) else if (!strcmp(argv[0], "-sgx")) { sgx_mode = true; } + else if (!strncmp(argv[0], "--bounds-checks=", 16)) { + option.bounds_checks = (atoi(argv[0] + 16) == 1) ? 1 : 0; + } else if (!strncmp(argv[0], "--format=", 9)) { if (argv[0][9] == '\0') return print_help(); @@ -138,8 +147,10 @@ main(int argc, char *argv[]) if (argc == 0) return print_help(); - if (sgx_mode) + if (sgx_mode) { option.size_level = 1; + option.is_sgx_platform = true; + } wasm_file_name = argv[0]; From 847dccaa34fa791677535c4a14931fd25ad448d3 Mon Sep 17 00:00:00 2001 From: wenyongh Date: Mon, 29 Jun 2020 14:17:27 +0800 Subject: [PATCH 024/207] Refine get/set global opcodes for interpreter (#294) --- core/iwasm/interpreter/wasm_interp_classic.c | 128 +++++++++--------- core/iwasm/interpreter/wasm_interp_fast.c | 135 ++++++++++--------- core/iwasm/interpreter/wasm_loader.c | 64 +++++++-- core/iwasm/interpreter/wasm_mini_loader.c | 65 +++++++-- core/iwasm/interpreter/wasm_opcode.h | 12 +- 5 files changed, 252 insertions(+), 152 deletions(-) diff --git a/core/iwasm/interpreter/wasm_interp_classic.c b/core/iwasm/interpreter/wasm_interp_classic.c index 2b164e715..5316bd92d 100644 --- a/core/iwasm/interpreter/wasm_interp_classic.c +++ b/core/iwasm/interpreter/wasm_interp_classic.c @@ -974,7 +974,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, uint8 *global_data = module->global_data; uint32 linear_mem_size = memory ? num_bytes_per_page * memory->cur_page_count : 0; WASMTableInstance *table = module->default_table; - WASMGlobalInstance *globals = module->globals; + WASMGlobalInstance *globals = module->globals, *global; uint8 opcode_IMPDEP = WASM_OP_IMPDEP; WASMInterpFrame *frame = NULL; /* Points to this special opcode so as to jump to the call_method_from_entry. */ @@ -982,7 +982,6 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, register uint32 *frame_lp = NULL; /* cache of frame->lp */ register uint32 *frame_sp = NULL; /* cache of frame->sp */ WASMBranchBlock *frame_csp = NULL; - WASMGlobalInstance *global; BlockAddr *cache_items; uint8 *frame_ip_end = frame_ip + 1; uint8 opcode, block_ret_type; @@ -995,13 +994,6 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, uint32 local_idx, local_offset, global_idx; uint8 local_type, *global_addr; uint32 cache_index; - int32 aux_stack_top_global_idx = -1; - - /* If the aux stack information is resolved, - we will check the aux stack boundary */ - if (module->module->llvm_aux_stack_size) { - aux_stack_top_global_idx = module->module->llvm_aux_stack_global_index; - } #if WASM_ENABLE_LABELS_AS_VALUES != 0 #define HANDLE_OPCODE(op) &&HANDLE_##op @@ -1383,70 +1375,87 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP (WASM_OP_GET_GLOBAL): { read_leb_uint32(frame_ip, frame_ip_end, global_idx); - bh_assert(global_idx < module->global_count); global = globals + global_idx; - global_addr = -#if WASM_ENABLE_MULTI_MODULE != 0 - global->import_global_inst - ? global->import_module_inst->global_data - + global->import_global_inst->data_offset - : +#if WASM_ENABLE_MULTI_MODULE == 0 + global_addr = global_data + global->data_offset; +#else + global_addr = global->import_global_inst + ? global->import_module_inst->global_data + + global->import_global_inst->data_offset + : global_data + global->data_offset; #endif - global_data + global->data_offset; - - switch (global->type) { - case VALUE_TYPE_I32: - case VALUE_TYPE_F32: - PUSH_I32(*(uint32*)global_addr); - break; - case VALUE_TYPE_I64: - case VALUE_TYPE_F64: - PUSH_I64(GET_I64_FROM_ADDR((uint32*)global_addr)); - break; - default: - wasm_set_exception(module, "invalid global type"); - goto got_exception; - } + PUSH_I32(*(uint32*)global_addr); + HANDLE_OP_END (); + } + HANDLE_OP (WASM_OP_GET_GLOBAL_64): + { + read_leb_uint32(frame_ip, frame_ip_end, global_idx); + bh_assert(global_idx < module->global_count); + global = globals + global_idx; +#if WASM_ENABLE_MULTI_MODULE == 0 + global_addr = global_data + global->data_offset; +#else + global_addr = global->import_global_inst + ? global->import_module_inst->global_data + + global->import_global_inst->data_offset + : global_data + global->data_offset; +#endif + PUSH_I64(GET_I64_FROM_ADDR((uint32*)global_addr)); HANDLE_OP_END (); } HANDLE_OP (WASM_OP_SET_GLOBAL): { read_leb_uint32(frame_ip, frame_ip_end, global_idx); - bh_assert(global_idx < module->global_count); global = globals + global_idx; - global_addr = -#if WASM_ENABLE_MULTI_MODULE != 0 - global->import_global_inst - ? global->import_module_inst->global_data - + global->import_global_inst->data_offset - : +#if WASM_ENABLE_MULTI_MODULE == 0 + global_addr = global_data + global->data_offset; +#else + global_addr = global->import_global_inst + ? global->import_module_inst->global_data + + global->import_global_inst->data_offset + : global_data + global->data_offset; #endif - global_data + global->data_offset; + *(int32*)global_addr = POP_I32(); + HANDLE_OP_END (); + } - switch (global->type) { - case VALUE_TYPE_I32: - /* Check aux stack boundary */ - if ((global_idx == (uint32)aux_stack_top_global_idx) - && (*(uint32*)(frame_sp - 1) < exec_env->aux_stack_boundary)) - goto out_of_bounds; - *(int32*)global_addr = POP_I32(); - break; - case VALUE_TYPE_F32: - *(int32*)global_addr = POP_I32(); - break; - case VALUE_TYPE_I64: - case VALUE_TYPE_F64: - PUT_I64_TO_ADDR((uint32*)global_addr, POP_I64()); - break; - default: - wasm_set_exception(module, "invalid global type"); - goto got_exception; - } + HANDLE_OP (WASM_OP_SET_GLOBAL_AUX_STACK): + { + read_leb_uint32(frame_ip, frame_ip_end, global_idx); + bh_assert(global_idx < module->global_count); + global = globals + global_idx; +#if WASM_ENABLE_MULTI_MODULE == 0 + global_addr = global_data + global->data_offset; +#else + global_addr = global->import_global_inst + ? global->import_module_inst->global_data + + global->import_global_inst->data_offset + : global_data + global->data_offset; +#endif + if (*(uint32*)(frame_sp - 1) < exec_env->aux_stack_boundary) + goto out_of_bounds; + *(int32*)global_addr = POP_I32(); + HANDLE_OP_END (); + } + HANDLE_OP (WASM_OP_SET_GLOBAL_64): + { + read_leb_uint32(frame_ip, frame_ip_end, global_idx); + bh_assert(global_idx < module->global_count); + global = globals + global_idx; +#if WASM_ENABLE_MULTI_MODULE == 0 + global_addr = global_data + global->data_offset; +#else + global_addr = global->import_global_inst + ? global->import_module_inst->global_data + + global->import_global_inst->data_offset + : global_data + global->data_offset; +#endif + PUT_I64_TO_ADDR((uint32*)global_addr, POP_I64()); HANDLE_OP_END (); } @@ -2691,9 +2700,6 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP (WASM_OP_UNUSED_0x1d): HANDLE_OP (WASM_OP_UNUSED_0x1e): HANDLE_OP (WASM_OP_UNUSED_0x1f): - HANDLE_OP (WASM_OP_UNUSED_0x25): - HANDLE_OP (WASM_OP_UNUSED_0x26): - HANDLE_OP (WASM_OP_UNUSED_0x27): /* Used by fast interpreter */ HANDLE_OP (EXT_OP_SET_LOCAL_FAST_I64): HANDLE_OP (EXT_OP_TEE_LOCAL_FAST_I64): diff --git a/core/iwasm/interpreter/wasm_interp_fast.c b/core/iwasm/interpreter/wasm_interp_fast.c index afb9ac3ef..b6509a7cf 100644 --- a/core/iwasm/interpreter/wasm_interp_fast.c +++ b/core/iwasm/interpreter/wasm_interp_fast.c @@ -968,7 +968,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, uint8 *global_data = module->global_data; uint32 linear_mem_size = memory ? num_bytes_per_page * memory->cur_page_count : 0; WASMTableInstance *table = module->default_table; - WASMGlobalInstance *globals = module->globals; + WASMGlobalInstance *globals = module->globals, *global; uint8 opcode_IMPDEP = WASM_OP_IMPDEP; WASMInterpFrame *frame = NULL; /* Points to this special opcode so as to jump to the call_method_from_entry. */ @@ -977,7 +977,6 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, #if WASM_ENABLE_ABS_LABEL_ADDR == 0 register uint8 *label_base = &&HANDLE_WASM_OP_UNREACHABLE; /* cache of label base addr */ #endif - WASMGlobalInstance *global; uint8 *frame_ip_end; uint32 cond, count, fidx, tidx, frame_size = 0; uint64 all_cell_num = 0; @@ -986,7 +985,6 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, uint8 *maddr = NULL; uint32 local_idx, local_offset, global_idx; uint8 opcode, local_type, *global_addr; - int32 aux_stack_top_global_idx = -1; #if WASM_ENABLE_LABELS_AS_VALUES != 0 #define HANDLE_OPCODE(op) &&HANDLE_##op @@ -1000,12 +998,6 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, #endif #endif - /* If the aux stack information is resolved, - we will check the aux stack boundary */ - if (module->module->llvm_aux_stack_size) { - aux_stack_top_global_idx = module->module->llvm_aux_stack_global_index; - } - #if WASM_ENABLE_LABELS_AS_VALUES == 0 while (frame_ip < frame_ip_end) { opcode = *frame_ip++; @@ -1225,72 +1217,92 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP (WASM_OP_GET_GLOBAL): { global_idx = read_uint32(frame_ip); - addr_ret = GET_OFFSET(); - bh_assert(global_idx < module->global_count); global = globals + global_idx; - global_addr = -#if WASM_ENABLE_MULTI_MODULE != 0 - global->import_global_inst - ? global->import_module_inst->global_data - + global->import_global_inst->data_offset - : +#if WASM_ENABLE_MULTI_MODULE == 0 + global_addr = global_data + global->data_offset; +#else + global_addr = global->import_global_inst + ? global->import_module_inst->global_data + + global->import_global_inst->data_offset + : global_data + global->data_offset; #endif - global_data + global->data_offset; - - switch (global->type) { - case VALUE_TYPE_I32: - case VALUE_TYPE_F32: - frame_lp[addr_ret] = *(uint32*)global_addr; - break; - case VALUE_TYPE_I64: - case VALUE_TYPE_F64: - *(uint64 *)(frame_lp + addr_ret) = GET_I64_FROM_ADDR((uint32*)global_addr); - break; - default: - wasm_set_exception(module, "invalid global type"); - goto got_exception; - } + addr_ret = GET_OFFSET(); + frame_lp[addr_ret] = *(uint32*)global_addr; + HANDLE_OP_END (); + } + HANDLE_OP (WASM_OP_GET_GLOBAL_64): + { + global_idx = read_uint32(frame_ip); + bh_assert(global_idx < module->global_count); + global = globals + global_idx; +#if WASM_ENABLE_MULTI_MODULE == 0 + global_addr = global_data + global->data_offset; +#else + global_addr = global->import_global_inst + ? global->import_module_inst->global_data + + global->import_global_inst->data_offset + : global_data + global->data_offset; +#endif + addr_ret = GET_OFFSET(); + *(uint64 *)(frame_lp + addr_ret) = GET_I64_FROM_ADDR((uint32*)global_addr); HANDLE_OP_END (); } HANDLE_OP (WASM_OP_SET_GLOBAL): { global_idx = read_uint32(frame_ip); - addr1 = GET_OFFSET(); - bh_assert(global_idx < module->global_count); global = globals + global_idx; - global_addr = -#if WASM_ENABLE_MULTI_MODULE != 0 - global->import_global_inst - ? global->import_module_inst->global_data - + global->import_global_inst->data_offset - : +#if WASM_ENABLE_MULTI_MODULE == 0 + global_addr = global_data + global->data_offset; +#else + global_addr = global->import_global_inst + ? global->import_module_inst->global_data + + global->import_global_inst->data_offset + : global_data + global->data_offset; #endif - global_data + global->data_offset; + addr1 = GET_OFFSET(); + *(int32*)global_addr = frame_lp[addr1]; + HANDLE_OP_END (); + } - switch (global->type) { - case VALUE_TYPE_I32: - /* Check aux stack boundary */ - if ((global_idx == (uint32)aux_stack_top_global_idx) - && (frame_lp[addr1] < exec_env->aux_stack_boundary)) - goto out_of_bounds; - *(int32*)global_addr = frame_lp[addr1]; - break; - case VALUE_TYPE_F32: - *(int32*)global_addr = frame_lp[addr1]; - break; - case VALUE_TYPE_I64: - case VALUE_TYPE_F64: - PUT_I64_TO_ADDR((uint32*)global_addr, *(int64 *)(frame_lp + addr1)); - break; - default: - wasm_set_exception(module, "invalid global type"); - goto got_exception; - } + HANDLE_OP (WASM_OP_SET_GLOBAL_AUX_STACK): + { + global_idx = read_uint32(frame_ip); + bh_assert(global_idx < module->global_count); + global = globals + global_idx; +#if WASM_ENABLE_MULTI_MODULE == 0 + global_addr = global_data + global->data_offset; +#else + global_addr = global->import_global_inst + ? global->import_module_inst->global_data + + global->import_global_inst->data_offset + : global_data + global->data_offset; +#endif + addr1 = GET_OFFSET(); + if (frame_lp[addr1] < exec_env->aux_stack_boundary) + goto out_of_bounds; + *(int32*)global_addr = frame_lp[addr1]; + HANDLE_OP_END (); + } + HANDLE_OP (WASM_OP_SET_GLOBAL_64): + { + global_idx = read_uint32(frame_ip); + bh_assert(global_idx < module->global_count); + global = globals + global_idx; +#if WASM_ENABLE_MULTI_MODULE == 0 + global_addr = global_data + global->data_offset; +#else + global_addr = global->import_global_inst + ? global->import_module_inst->global_data + + global->import_global_inst->data_offset + : global_data + global->data_offset; +#endif + addr1 = GET_OFFSET(); + PUT_I64_TO_ADDR((uint32*)global_addr, *(int64 *)(frame_lp + addr1)); HANDLE_OP_END (); } @@ -2538,9 +2550,6 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP (WASM_OP_UNUSED_0x1d): HANDLE_OP (WASM_OP_UNUSED_0x1e): HANDLE_OP (WASM_OP_UNUSED_0x1f): - HANDLE_OP (WASM_OP_UNUSED_0x25): - HANDLE_OP (WASM_OP_UNUSED_0x26): - HANDLE_OP (WASM_OP_UNUSED_0x27): /* optimized op code */ HANDLE_OP (WASM_OP_F32_STORE): HANDLE_OP (WASM_OP_F64_STORE): diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index 9786762f9..b22cc8488 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -1538,10 +1538,9 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, case IMPORT_KIND_GLOBAL: /* import global */ bh_assert(import_globals); import = import_globals++; - if (!load_global_import(module, - sub_module, - sub_module_name, field_name, &p, - p_end, &import->u.global, + if (!load_global_import(module, sub_module, + sub_module_name, field_name, + &p, p_end, &import->u.global, error_buf, error_buf_size)) { return false; } @@ -3058,6 +3057,9 @@ wasm_loader_find_block_addr(BlockAddr *block_addr_cache, case WASM_OP_TEE_LOCAL: case WASM_OP_GET_GLOBAL: case WASM_OP_SET_GLOBAL: + case WASM_OP_GET_GLOBAL_64: + case WASM_OP_SET_GLOBAL_64: + case WASM_OP_SET_GLOBAL_AUX_STACK: skip_leb_uint32(p, p_end); /* localidx */ break; @@ -5473,6 +5475,7 @@ re_scan: case WASM_OP_GET_GLOBAL: { + p_org = p - 1; read_leb_uint32(p, p_end, global_idx); if (global_idx >= global_count) { set_error_buf(error_buf, error_buf_size, @@ -5481,21 +5484,38 @@ re_scan: goto fail; } - global_type = global_idx < module->import_global_count - ? module->import_globals[global_idx].u.global.type - :module->globals[global_idx - module->import_global_count].type; + global_type = + global_idx < module->import_global_count + ? module->import_globals[global_idx].u.global.type + : module->globals[global_idx - module->import_global_count] + .type; PUSH_TYPE(global_type); -#if WASM_ENABLE_FAST_INTERP != 0 + +#if WASM_ENABLE_FAST_INTERP == 0 +#if (WASM_ENABLE_WAMR_COMPILER == 0) && (WASM_ENABLE_JIT == 0) + if (global_type == VALUE_TYPE_I64 + || global_type == VALUE_TYPE_F64) { + *p_org = WASM_OP_GET_GLOBAL_64; + } +#endif +#else /* else of WASM_ENABLE_FAST_INTERP */ + if (global_type == VALUE_TYPE_I64 + || global_type == VALUE_TYPE_F64) { + skip_label(); + emit_label(WASM_OP_GET_GLOBAL_64); + } emit_uint32(loader_ctx, global_idx); PUSH_OFFSET_TYPE(global_type); -#endif +#endif /* end of WASM_ENABLE_FAST_INTERP */ break; } case WASM_OP_SET_GLOBAL: { bool is_mutable = false; + + p_org = p - 1; read_leb_uint32(p, p_end, global_idx); if (global_idx >= global_count) { set_error_buf(error_buf, error_buf_size, @@ -5523,10 +5543,32 @@ re_scan: .type; POP_TYPE(global_type); -#if WASM_ENABLE_FAST_INTERP != 0 + +#if WASM_ENABLE_FAST_INTERP == 0 +#if (WASM_ENABLE_WAMR_COMPILER == 0) && (WASM_ENABLE_JIT == 0) + if (global_type == VALUE_TYPE_I64 + || global_type == VALUE_TYPE_F64) { + *p_org = WASM_OP_SET_GLOBAL_64; + } + else if (module->llvm_aux_stack_size > 0 + && global_idx == module->llvm_aux_stack_global_index) { + *p_org = WASM_OP_SET_GLOBAL_AUX_STACK; + } +#endif +#else /* else of WASM_ENABLE_FAST_INTERP */ + if (global_type == VALUE_TYPE_I64 + || global_type == VALUE_TYPE_F64) { + skip_label(); + emit_label(WASM_OP_SET_GLOBAL_64); + } + else if (module->llvm_aux_stack_size > 0 + && global_idx == module->llvm_aux_stack_global_index) { + skip_label(); + emit_label(WASM_OP_SET_GLOBAL_AUX_STACK); + } emit_uint32(loader_ctx, global_idx); POP_OFFSET_TYPE(global_type); -#endif +#endif /* end of WASM_ENABLE_FAST_INTERP */ break; } diff --git a/core/iwasm/interpreter/wasm_mini_loader.c b/core/iwasm/interpreter/wasm_mini_loader.c index 02c68b894..d969c2203 100644 --- a/core/iwasm/interpreter/wasm_mini_loader.c +++ b/core/iwasm/interpreter/wasm_mini_loader.c @@ -782,10 +782,9 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, case IMPORT_KIND_GLOBAL: /* import global */ bh_assert(import_globals); import = import_globals++; - if (!load_global_import(module, - sub_module, - sub_module_name, field_name, &p, - p_end, &import->u.global, + if (!load_global_import(module, sub_module, + sub_module_name, field_name, + &p, p_end, &import->u.global, error_buf, error_buf_size)) { return false; } @@ -2087,6 +2086,9 @@ wasm_loader_find_block_addr(BlockAddr *block_addr_cache, case WASM_OP_TEE_LOCAL: case WASM_OP_GET_GLOBAL: case WASM_OP_SET_GLOBAL: + case WASM_OP_GET_GLOBAL_64: + case WASM_OP_SET_GLOBAL_64: + case WASM_OP_SET_GLOBAL_AUX_STACK: skip_leb_uint32(p, p_end); /* localidx */ break; @@ -4371,24 +4373,42 @@ re_scan: case WASM_OP_GET_GLOBAL: { + p_org = p - 1; read_leb_uint32(p, p_end, global_idx); bh_assert(global_idx < global_count); - global_type = global_idx < module->import_global_count - ? module->import_globals[global_idx].u.global.type - :module->globals[global_idx - module->import_global_count].type; + global_type = + global_idx < module->import_global_count + ? module->import_globals[global_idx].u.global.type + : module->globals[global_idx - module->import_global_count] + .type; PUSH_TYPE(global_type); -#if WASM_ENABLE_FAST_INTERP != 0 + +#if WASM_ENABLE_FAST_INTERP == 0 +#if (WASM_ENABLE_WAMR_COMPILER == 0) && (WASM_ENABLE_JIT == 0) + if (global_type == VALUE_TYPE_I64 + || global_type == VALUE_TYPE_F64) { + *p_org = WASM_OP_GET_GLOBAL_64; + } +#endif +#else /* else of WASM_ENABLE_FAST_INTERP */ + if (global_type == VALUE_TYPE_I64 + || global_type == VALUE_TYPE_F64) { + skip_label(); + emit_label(WASM_OP_GET_GLOBAL_64); + } emit_uint32(loader_ctx, global_idx); PUSH_OFFSET_TYPE(global_type); -#endif +#endif /* end of WASM_ENABLE_FAST_INTERP */ break; } case WASM_OP_SET_GLOBAL: { bool is_mutable = false; + + p_org = p - 1; read_leb_uint32(p, p_end, global_idx); bh_assert(global_idx < global_count); @@ -4406,10 +4426,33 @@ re_scan: .type; POP_TYPE(global_type); -#if WASM_ENABLE_FAST_INTERP != 0 + +#if WASM_ENABLE_FAST_INTERP == 0 +#if (WASM_ENABLE_WAMR_COMPILER == 0) && (WASM_ENABLE_JIT == 0) + if (global_type == VALUE_TYPE_I64 + || global_type == VALUE_TYPE_F64) { + *p_org = WASM_OP_SET_GLOBAL_64; + } + else if (module->llvm_aux_stack_size > 0 + && global_idx == module->llvm_aux_stack_global_index) { + *p_org = WASM_OP_SET_GLOBAL_AUX_STACK; + } +#endif +#else /* else of WASM_ENABLE_FAST_INTERP */ + if (global_type == VALUE_TYPE_I64 + || global_type == VALUE_TYPE_F64) { + skip_label(); + emit_label(WASM_OP_SET_GLOBAL_64); + } + else if (module->llvm_aux_stack_size > 0 + && global_idx == module->llvm_aux_stack_global_index) { + skip_label(); + emit_label(WASM_OP_SET_GLOBAL_AUX_STACK); + } emit_uint32(loader_ctx, global_idx); POP_OFFSET_TYPE(global_type); -#endif +#endif /* end of WASM_ENABLE_FAST_INTERP */ + (void)is_mutable; break; } diff --git a/core/iwasm/interpreter/wasm_opcode.h b/core/iwasm/interpreter/wasm_opcode.h index c2cd39948..99b4f0b0a 100644 --- a/core/iwasm/interpreter/wasm_opcode.h +++ b/core/iwasm/interpreter/wasm_opcode.h @@ -60,9 +60,9 @@ typedef enum WASMOpcode { WASM_OP_GET_GLOBAL = 0x23, /* get_global */ WASM_OP_SET_GLOBAL = 0x24, /* set_global */ - WASM_OP_UNUSED_0x25 = 0x25, - WASM_OP_UNUSED_0x26 = 0x26, - WASM_OP_UNUSED_0x27 = 0x27, + WASM_OP_GET_GLOBAL_64 = 0x25, + WASM_OP_SET_GLOBAL_64 = 0x26, + WASM_OP_SET_GLOBAL_AUX_STACK = 0x27, /* memory instructions */ WASM_OP_I32_LOAD = 0x28, /* i32.load */ @@ -330,9 +330,9 @@ static type _name[WASM_INSTRUCTION_NUM] = { \ HANDLE_OPCODE (WASM_OP_TEE_LOCAL), /* 0x22 */ \ HANDLE_OPCODE (WASM_OP_GET_GLOBAL), /* 0x23 */ \ HANDLE_OPCODE (WASM_OP_SET_GLOBAL), /* 0x24 */ \ - HANDLE_OPCODE (WASM_OP_UNUSED_0x25), /* 0x25 */ \ - HANDLE_OPCODE (WASM_OP_UNUSED_0x26), /* 0x26 */ \ - HANDLE_OPCODE (WASM_OP_UNUSED_0x27), /* 0x27 */ \ + HANDLE_OPCODE (WASM_OP_GET_GLOBAL_64), /* 0x25 */ \ + HANDLE_OPCODE (WASM_OP_SET_GLOBAL_64), /* 0x26 */ \ + HANDLE_OPCODE (WASM_OP_SET_GLOBAL_AUX_STACK), /* 0x27 */ \ HANDLE_OPCODE (WASM_OP_I32_LOAD), /* 0x28 */ \ HANDLE_OPCODE (WASM_OP_I64_LOAD), /* 0x29 */ \ HANDLE_OPCODE (WASM_OP_F32_LOAD), /* 0x2a */ \ From ee3d448eb6609ae915ec02f12ce640c8ab72f411 Mon Sep 17 00:00:00 2001 From: wenyongh Date: Wed, 1 Jul 2020 12:22:13 +0800 Subject: [PATCH 025/207] Fix aot issue in 32-bit platform (#297) fix aot 32-bit boundary check issue --- core/iwasm/aot/aot_runtime.c | 12 +++++------- core/iwasm/aot/aot_runtime.h | 2 +- core/iwasm/compilation/aot_emit_control.c | 21 +++++++++++++++++---- core/iwasm/compilation/aot_emit_memory.c | 2 +- 4 files changed, 24 insertions(+), 13 deletions(-) diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index 29e11db17..ca8e3cea5 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -215,13 +215,11 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModule *module, module_inst->mem_cur_page_count = module->mem_init_page_count; module_inst->mem_max_page_count = module->mem_max_page_count; - module_inst->mem_bound_check_heap_base = module_inst->heap_base_offset; - if (module_inst->memory_data_size > 0) { - module_inst->mem_bound_check_1byte = module_inst->memory_data_size - 1; - module_inst->mem_bound_check_2bytes = module_inst->memory_data_size - 2; - module_inst->mem_bound_check_4bytes = module_inst->memory_data_size - 4; - module_inst->mem_bound_check_8bytes = module_inst->memory_data_size - 8; - } + module_inst->mem_bound_check_heap_base = (int64)module_inst->heap_base_offset; + module_inst->mem_bound_check_1byte = (int64)module_inst->memory_data_size - 1; + module_inst->mem_bound_check_2bytes = (int64)module_inst->memory_data_size - 2; + module_inst->mem_bound_check_4bytes = (int64)module_inst->memory_data_size - 4; + module_inst->mem_bound_check_8bytes = (int64)module_inst->memory_data_size - 8; for (i = 0; i < module->mem_init_data_count; i++) { data_seg = module->mem_init_data_list[i]; diff --git a/core/iwasm/aot/aot_runtime.h b/core/iwasm/aot/aot_runtime.h index b42f12a23..a2f4908a7 100644 --- a/core/iwasm/aot/aot_runtime.h +++ b/core/iwasm/aot/aot_runtime.h @@ -211,7 +211,7 @@ typedef struct AOTModuleInstance { uint32 default_wasm_stack_size; /* reserved */ - uint32 reserved[12]; + uint32 reserved[11]; union { uint64 _make_it_8_byte_aligned_; diff --git a/core/iwasm/compilation/aot_emit_control.c b/core/iwasm/compilation/aot_emit_control.c index 4dbaabb06..bbb470a2c 100644 --- a/core/iwasm/compilation/aot_emit_control.c +++ b/core/iwasm/compilation/aot_emit_control.c @@ -144,10 +144,23 @@ handle_next_reachable_block(AOTCompContext *comp_ctx, block_prev = block->prev; block = aot_block_stack_pop(&func_ctx->block_stack); - if (block->block_type == BLOCK_TYPE_IF - && block->llvm_end_block) { - LLVMDeleteBasicBlock(block->llvm_end_block); - block->llvm_end_block = NULL; + if (block->block_type == BLOCK_TYPE_IF) { + if (block->llvm_else_block + && !block->skip_wasm_code_else + && *p_frame_ip <= block->wasm_code_else) { + /* Clear value stack and start to translate else branch */ + aot_value_stack_destroy(&block->value_stack); + SET_BUILDER_POS(block->llvm_else_block); + *p_frame_ip = block->wasm_code_else + 1; + /* Push back the block */ + aot_block_stack_push(&func_ctx->block_stack, block); + return true; + } + else if (block->llvm_end_block) { + /* Remove unreachable basic block */ + LLVMDeleteBasicBlock(block->llvm_end_block); + block->llvm_end_block = NULL; + } } frame_ip = block->wasm_code_end; diff --git a/core/iwasm/compilation/aot_emit_memory.c b/core/iwasm/compilation/aot_emit_memory.c index 462926608..b6d497582 100644 --- a/core/iwasm/compilation/aot_emit_memory.c +++ b/core/iwasm/compilation/aot_emit_memory.c @@ -111,7 +111,7 @@ check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, && mem_offset <= mem_data_size - bytes) { /* inside memory space */ offset1 = I32_CONST((uint32)mem_offset); - CHECK_LLVM_CONST(offset_const); + CHECK_LLVM_CONST(offset1); if (!(maddr = LLVMBuildInBoundsGEP(comp_ctx->builder, mem_base_addr, &offset1, 1, "maddr"))) { aot_set_last_error("llvm build add failed."); From 1f6b589c12083df1f9337cc26d41e14f6224839a Mon Sep 17 00:00:00 2001 From: dpinthinker Date: Wed, 1 Jul 2020 12:24:36 +0800 Subject: [PATCH 026/207] fix comments wrong position (#296) --- .../app-mgr/app-mgr-shared/app_manager_export.h | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/core/app-mgr/app-mgr-shared/app_manager_export.h b/core/app-mgr/app-mgr-shared/app_manager_export.h index 4e29b1f92..aa676d2a4 100644 --- a/core/app-mgr/app-mgr-shared/app_manager_export.h +++ b/core/app-mgr/app-mgr-shared/app_manager_export.h @@ -175,15 +175,6 @@ typedef struct host_interface { bool app_manager_host_init(host_interface *interface); -/** - * Send message to Host - * - * @param buf buffer to send - * @param size size of buffer - * - * @return size of buffer sent - */ - /* Startup app manager */ void app_manager_startup(host_interface *interface); @@ -284,6 +275,14 @@ send_error_response_to_host(int mid, int code, const char *msg); bool bh_applet_check_permission(const char *perm); +/** + * Send message to Host + * + * @param buf buffer to send + * @param size size of buffer + * + * @return size of buffer sent + */ int app_manager_host_send_msg(int msg_type, const char *buf, int size); From 9b8fc6ae9577802725e6f259afda2f6e9fc124f8 Mon Sep 17 00:00:00 2001 From: dpinthinker Date: Wed, 1 Jul 2020 16:57:22 +0800 Subject: [PATCH 027/207] fix one typo in module_wasm_app.c's log (#299) * fix comments wrong position * fix one typo in module_wasm_app.c's log --- core/app-mgr/app-manager/module_wasm_app.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/app-mgr/app-manager/module_wasm_app.c b/core/app-mgr/app-manager/module_wasm_app.c index f58580b6e..95ac95a78 100644 --- a/core/app-mgr/app-manager/module_wasm_app.c +++ b/core/app-mgr/app-manager/module_wasm_app.c @@ -847,7 +847,7 @@ wasm_app_module_install(request_t * msg) (void*) m_data, APP_THREAD_STACK_SIZE_DEFAULT) != 0) { module_data_list_remove(m_data); SEND_ERR_RESPONSE(msg->mid, - "Install WASM app failed: create app threadf failed."); + "Install WASM app failed: create app thread failed."); goto fail; } From 2fc7230009cecdff9b309adcaf214a1d88427d51 Mon Sep 17 00:00:00 2001 From: wenyongh Date: Tue, 7 Jul 2020 09:56:46 +0800 Subject: [PATCH 028/207] Enhance the native stack overflow check (#302) --- core/iwasm/aot/aot_runtime.c | 42 +++++++++++++++++++++---- core/iwasm/common/wasm_runtime_common.c | 7 +++-- 2 files changed, 40 insertions(+), 9 deletions(-) diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index ca8e3cea5..0e0b574d0 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -550,6 +550,8 @@ aot_lookup_function(const AOTModuleInstance *module_inst, #ifdef OS_ENABLE_HW_BOUND_CHECK +#define STACK_OVERFLOW_CHECK_GUARD_PAGE_COUNT 3 + static os_thread_local_attribute WASMExecEnv *aot_exec_env = NULL; static inline uint8 * @@ -567,6 +569,7 @@ aot_signal_handler(void *sig_addr) uint8 *mapped_mem_start_addr, *mapped_mem_end_addr; uint8 *stack_min_addr; uint32 page_size; + uint32 guard_page_count = STACK_OVERFLOW_CHECK_GUARD_PAGE_COUNT; /* Check whether current thread is running aot function */ if (aot_exec_env @@ -591,7 +594,8 @@ aot_signal_handler(void *sig_addr) os_longjmp(jmpbuf_node->jmpbuf, 1); } else if (stack_min_addr - page_size <= (uint8*)sig_addr - && (uint8*)sig_addr < stack_min_addr + page_size * 3) { + && (uint8*)sig_addr < stack_min_addr + + page_size * guard_page_count) { /* The address which causes segmentation fault is inside native thread's guard page */ aot_set_exception_with_id(module_inst, EXCE_NATIVE_STACK_OVERFLOW); @@ -621,11 +625,13 @@ touch_pages(uint8 *stack_min_addr, uint32 page_size) { uint8 sum = 0; while (1) { - uint8 *touch_addr = os_alloca(page_size / 2); - sum += *touch_addr; + volatile uint8 *touch_addr = + (volatile uint8*)os_alloca(page_size / 2); if (touch_addr < stack_min_addr + page_size) { + sum += *(stack_min_addr + page_size - 1); break; } + sum += *touch_addr; } return sum; } @@ -640,9 +646,19 @@ invoke_native_with_hw_bound_check(WASMExecEnv *exec_env, void *func_ptr, WASMExecEnv **p_aot_exec_env = &aot_exec_env; WASMJmpBuf *jmpbuf_node, *jmpbuf_node_pop; uint32 page_size = os_getpagesize(); + uint32 guard_page_count = STACK_OVERFLOW_CHECK_GUARD_PAGE_COUNT; uint8 *stack_min_addr = get_stack_min_addr(exec_env, page_size); bool ret; + /* Check native stack overflow firstly to ensure we have enough + native stack to run the following codes before actually calling + the aot function in invokeNative function. */ + if ((uint8*)&module_inst < exec_env->native_stack_boundary + + page_size * (guard_page_count + 1)) { + aot_set_exception_with_id(module_inst, EXCE_NATIVE_STACK_OVERFLOW); + return false; + } + if (aot_exec_env && (aot_exec_env != exec_env)) { aot_set_exception(module_inst, "Invalid exec env."); @@ -654,7 +670,8 @@ invoke_native_with_hw_bound_check(WASMExecEnv *exec_env, void *func_ptr, lazily grow the stack mapping as a guard page is hit. */ touch_pages(stack_min_addr, page_size); /* First time to call aot function, protect one page */ - if (os_mprotect(stack_min_addr, page_size * 3, MMAP_PROT_NONE) != 0) { + if (os_mprotect(stack_min_addr, page_size * guard_page_count, + MMAP_PROT_NONE) != 0) { aot_set_exception(module_inst, "Set protected page failed."); return false; } @@ -671,7 +688,7 @@ invoke_native_with_hw_bound_check(WASMExecEnv *exec_env, void *func_ptr, if (os_setjmp(jmpbuf_node->jmpbuf) == 0) { ret = wasm_runtime_invoke_native(exec_env, func_ptr, func_type, signature, attachment, - argv, argc, argv); + argv, argc, argv_ret); } else { /* Exception has been set in signal handler before calling longjmp */ @@ -683,7 +700,7 @@ invoke_native_with_hw_bound_check(WASMExecEnv *exec_env, void *func_ptr, wasm_runtime_free(jmpbuf_node); if (!exec_env->jmpbuf_stack_top) { /* Unprotect the guard page when the nested call depth is zero */ - os_mprotect(stack_min_addr, page_size * 3, + os_mprotect(stack_min_addr, page_size * guard_page_count, MMAP_PROT_READ | MMAP_PROT_WRITE); *p_aot_exec_env = NULL; } @@ -1113,6 +1130,19 @@ aot_invoke_native(WASMExecEnv *exec_env, uint32 func_idx, void *attachment; char buf[128]; +#ifdef OS_ENABLE_HW_BOUND_CHECK + uint32 page_size = os_getpagesize(); + uint32 guard_page_count = STACK_OVERFLOW_CHECK_GUARD_PAGE_COUNT; + /* Check native stack overflow firstly to ensure we have enough + native stack to run the following codes before actually calling + the aot function in invokeNative function. */ + if ((uint8*)&module_inst < exec_env->native_stack_boundary + + page_size * (guard_page_count + 1)) { + aot_set_exception_with_id(module_inst, EXCE_NATIVE_STACK_OVERFLOW); + return false; + } +#endif + bh_assert(func_idx < aot_module->import_func_count); import_func = aot_module->import_funcs + func_idx; diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index ef3b5c468..fa1700df2 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -2797,6 +2797,10 @@ fail: return ret; } +#endif /* end of defined(BUILD_TARGET_X86_64) \ + || defined(BUILD_TARGET_AMD_64) \ + || defined(BUILD_TARGET_AARCH64) */ + bool wasm_runtime_call_indirect(WASMExecEnv *exec_env, uint32_t element_indices, @@ -2825,6 +2829,3 @@ wasm_runtime_call_indirect(WASMExecEnv *exec_env, return false; } -#endif /* end of defined(BUILD_TARGET_X86_64) \ - || defined(BUILD_TARGET_AMD_64) \ - || defined(BUILD_TARGET_AARCH64) */ From 16a284a67c1a9d531586fe2c393e26c3aacccb7f Mon Sep 17 00:00:00 2001 From: wenyongh Date: Thu, 9 Jul 2020 16:07:41 +0800 Subject: [PATCH 029/207] Fix compile issue of zephyr (#306) --- core/shared/platform/zephyr/zephyr_platform.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/shared/platform/zephyr/zephyr_platform.c b/core/shared/platform/zephyr/zephyr_platform.c index d2408948d..8c701a203 100644 --- a/core/shared/platform/zephyr/zephyr_platform.c +++ b/core/shared/platform/zephyr/zephyr_platform.c @@ -20,7 +20,7 @@ static exec_mem_free_func_t exec_mem_free_func = NULL; static void disable_mpu_rasr_xn(void) { - u32_t index; + uint32 index; /* Kept the max index as 8 (irrespective of soc) because the sram would most likely be set at index 2. */ for (index = 0U; index < 8; index++) { From 1a85051415b0830c12ff48c3515bcf1ceac3341e Mon Sep 17 00:00:00 2001 From: Weining <50284696+Weining2019@users.noreply.github.com> Date: Fri, 10 Jul 2020 16:29:15 +0800 Subject: [PATCH 030/207] Implement multi-value feature and import binarydump tool (#308) --- README.md | 1 + core/app-mgr/app-manager/module_wasm_app.c | 8 +- core/iwasm/aot/aot_loader.c | 25 +- core/iwasm/aot/aot_runtime.c | 150 ++- core/iwasm/common/arch/invokeNative_aarch64.s | 2 +- core/iwasm/common/arch/invokeNative_arm_vfp.s | 2 +- core/iwasm/common/wasm_native.c | 2 +- core/iwasm/common/wasm_runtime_common.c | 77 +- core/iwasm/compilation/aot_compiler.c | 41 +- core/iwasm/compilation/aot_emit_control.c | 503 +++++++--- core/iwasm/compilation/aot_emit_control.h | 3 +- core/iwasm/compilation/aot_emit_function.c | 167 +++- core/iwasm/compilation/aot_llvm.c | 65 +- core/iwasm/compilation/aot_llvm.h | 18 +- core/iwasm/interpreter/wasm.h | 108 +- core/iwasm/interpreter/wasm_interp.h | 4 +- core/iwasm/interpreter/wasm_interp_classic.c | 93 +- core/iwasm/interpreter/wasm_interp_fast.c | 237 ++++- core/iwasm/interpreter/wasm_loader.c | 935 +++++++++++++----- core/iwasm/interpreter/wasm_mini_loader.c | 873 +++++++++++----- core/iwasm/interpreter/wasm_opcode.h | 13 +- core/iwasm/interpreter/wasm_runtime.c | 6 +- product-mini/platforms/linux/CMakeLists.txt | 2 +- test-tools/binarydump-tool/CMakeLists.txt | 11 + test-tools/binarydump-tool/binarydump.c | 126 +++ 25 files changed, 2660 insertions(+), 812 deletions(-) create mode 100644 test-tools/binarydump-tool/CMakeLists.txt create mode 100644 test-tools/binarydump-tool/binarydump.c diff --git a/README.md b/README.md index df10d7179..1163f49ad 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,7 @@ iwasm VM core - [Sign-extension operators](https://github.com/WebAssembly/sign-extension-ops) - [Bulk memory operations](https://github.com/WebAssembly/bulk-memory-operations) - [Shared memmory](https://github.com/WebAssembly/threads/blob/main/proposals/threads/Overview.md#shared-linear-memory) +- [Multi-value](https://github.com/WebAssembly/multi-value) ### Performance and memory usage The WAMR performance, footprint and memory usage data are available at the [performance](../../wiki/Performance) wiki page. diff --git a/core/app-mgr/app-manager/module_wasm_app.c b/core/app-mgr/app-manager/module_wasm_app.c index 95ac95a78..4d30c4a08 100644 --- a/core/app-mgr/app-manager/module_wasm_app.c +++ b/core/app-mgr/app-manager/module_wasm_app.c @@ -556,7 +556,7 @@ wasm_app_module_init(void) static bool wasm_app_module_install(request_t * msg) { - unsigned int m_data_size, heap_size; + unsigned int m_data_size, heap_size, stack_size; unsigned int timeout, timers, err_size; char *properties; int properties_offset; @@ -842,9 +842,13 @@ wasm_app_module_install(request_t * msg) goto fail; } + stack_size = APP_THREAD_STACK_SIZE_DEFAULT; +#ifdef OS_ENABLE_HW_BOUND_CHECK + stack_size += 4 * BH_KB; +#endif /* Create WASM app thread. */ if (os_thread_create(&wasm_app_data->thread_id, wasm_app_routine, - (void*) m_data, APP_THREAD_STACK_SIZE_DEFAULT) != 0) { + (void*) m_data, stack_size) != 0) { module_data_list_remove(m_data); SEND_ERR_RESPONSE(msg->mid, "Install WASM app failed: create app thread failed."); diff --git a/core/iwasm/aot/aot_loader.c b/core/iwasm/aot/aot_loader.c index 8803213e7..af0d8fdb5 100644 --- a/core/iwasm/aot/aot_loader.c +++ b/core/iwasm/aot/aot_loader.c @@ -551,11 +551,19 @@ load_func_types(const uint8 **p_buf, const uint8 *buf_end, /* Create each function type */ for (i = 0; i < module->func_type_count; i++) { uint32 param_count, result_count; + uint32 param_cell_num, ret_cell_num; uint64 size1; read_uint32(buf, buf_end, param_count); read_uint32(buf, buf_end, result_count); + if (param_count > UINT16_MAX || result_count > UINT16_MAX) { + set_error_buf(error_buf, error_buf_size, + "AOT module load failed: " + "param count or result count too large"); + return false; + } + size1 = (uint64)param_count + (uint64)result_count; size = offsetof(AOTFuncType, types) + size1; if (!(func_types[i] = loader_malloc @@ -563,9 +571,22 @@ load_func_types(const uint8 **p_buf, const uint8 *buf_end, return false; } - func_types[i]->param_count = param_count; - func_types[i]->result_count = result_count; + func_types[i]->param_count = (uint16)param_count; + func_types[i]->result_count = (uint16)result_count; read_byte_array(buf, buf_end, func_types[i]->types, (uint32)size1); + + param_cell_num = wasm_get_cell_num(func_types[i]->types, param_count); + ret_cell_num = wasm_get_cell_num(func_types[i]->types + param_count, + result_count); + if (param_cell_num > UINT16_MAX || ret_cell_num > UINT16_MAX) { + set_error_buf(error_buf, error_buf_size, + "AOT module load failed: " + "param count or result count too large"); + return false; + } + + func_types[i]->param_cell_num = (uint16)param_cell_num; + func_types[i]->ret_cell_num = (uint16)ret_cell_num; } *p_buf = buf; diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index 0e0b574d0..7805b1f9e 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -722,9 +722,77 @@ aot_call_function(WASMExecEnv *exec_env, { AOTModuleInstance *module_inst = (AOTModuleInstance*)exec_env->module_inst; AOTFuncType *func_type = function->func_type; - bool ret = invoke_native_internal(exec_env, function->func_ptr, - func_type, NULL, NULL, argv, argc, argv); - return ret && !aot_get_exception(module_inst) ? true : false; + uint32 result_count = func_type->result_count; + uint32 ext_ret_count = result_count > 1 ? result_count - 1 : 0; + bool ret; + + if (ext_ret_count > 0) { + uint32 cell_num = 0, i; + uint8 *ext_ret_types = func_type->types + func_type->param_count + 1; + uint32 argv1_buf[32], *argv1 = argv1_buf, *ext_rets = NULL; + uint32 *argv_ret = argv; + uint32 ext_ret_cell = wasm_get_cell_num(ext_ret_types, ext_ret_count); + uint64 size; + + /* Allocate memory all arguments */ + size = sizeof(uint32) * (uint64)argc /* original arguments */ + + sizeof(void*) * (uint64)ext_ret_count /* extra result values' addr */ + + sizeof(uint32) * (uint64)ext_ret_cell; /* extra result values */ + if (size > sizeof(argv1_buf) + && !(argv1 = runtime_malloc(size, module_inst->cur_exception, + sizeof(module_inst->cur_exception)))) { + aot_set_exception_with_id(module_inst, EXCE_OUT_OF_MEMORY); + return false; + } + + /* Copy original arguments */ + bh_memcpy_s(argv1, (uint32)size, argv, sizeof(uint32) * argc); + + /* Get the extra result value's address */ + ext_rets = argv1 + argc + sizeof(void*)/sizeof(uint32) * ext_ret_count; + + /* Append each extra result value's address to original arguments */ + for (i = 0; i < ext_ret_count; i++) { + *(uintptr_t*)(argv1 + argc + sizeof(void*) / sizeof(uint32) * i) = + (uintptr_t)(ext_rets + cell_num); + cell_num += wasm_value_type_cell_num(ext_ret_types[i]); + } + + ret = invoke_native_internal(exec_env, function->func_ptr, + func_type, NULL, NULL, argv1, argc, argv); + if (!ret || aot_get_exception(module_inst)) { + if (argv1 != argv1_buf) + wasm_runtime_free(argv1); + return false; + } + + /* Get extra result values */ + switch (func_type->types[func_type->param_count]) { + case VALUE_TYPE_I32: + case VALUE_TYPE_F32: + argv_ret++; + break; + case VALUE_TYPE_I64: + case VALUE_TYPE_F64: + argv_ret += 2; + break; + default: + bh_assert(0); + break; + } + ext_rets = argv1 + argc + sizeof(void*)/sizeof(uint32) * ext_ret_count; + bh_memcpy_s(argv_ret, sizeof(uint32) * cell_num, + ext_rets, sizeof(uint32) * cell_num); + if (argv1 != argv1_buf) + wasm_runtime_free(argv1); + + return true; + } + else { + ret = invoke_native_internal(exec_env, function->func_ptr, + func_type, NULL, NULL, argv, argc, argv); + return ret && !aot_get_exception(module_inst) ? true : false; + } } bool @@ -1183,10 +1251,12 @@ aot_call_indirect(WASMExecEnv *exec_env, void **func_ptrs = (void**)module_inst->func_ptrs.ptr, *func_ptr; uint32 table_size = module_inst->table_size; uint32 func_idx, func_type_idx1; + uint32 ext_ret_count; AOTImportFunc *import_func; const char *signature = NULL; void *attachment = NULL; char buf[128]; + bool ret; /* this function is called from native code, so exec_env->handle and exec_env->native_stack_boundary must have been set, we don't set @@ -1241,9 +1311,77 @@ aot_call_indirect(WASMExecEnv *exec_env, } } - return invoke_native_internal(exec_env, func_ptr, - func_type, signature, attachment, - argv, argc, argv); + ext_ret_count = func_type->result_count > 1 + ? func_type->result_count - 1 : 0; + if (ext_ret_count > 0) { + uint32 argv1_buf[32], *argv1 = argv1_buf; + uint32 *ext_rets = NULL, *argv_ret = argv; + uint32 cell_num = 0, i; + uint8 *ext_ret_types = func_type->types + func_type->param_count + 1; + uint32 ext_ret_cell = wasm_get_cell_num(ext_ret_types, ext_ret_count); + uint64 size; + + /* Allocate memory all arguments */ + size = sizeof(uint32) * (uint64)argc /* original arguments */ + + sizeof(void*) * (uint64)ext_ret_count /* extra result values' addr */ + + sizeof(uint32) * (uint64)ext_ret_cell; /* extra result values */ + if (size > sizeof(argv1_buf) + && !(argv1 = runtime_malloc(size, module_inst->cur_exception, + sizeof(module_inst->cur_exception)))) { + aot_set_exception_with_id(module_inst, EXCE_OUT_OF_MEMORY); + return false; + } + + /* Copy original arguments */ + bh_memcpy_s(argv1, (uint32)size, argv, sizeof(uint32) * argc); + + /* Get the extra result value's address */ + ext_rets = argv1 + argc + sizeof(void*)/sizeof(uint32) * ext_ret_count; + + /* Append each extra result value's address to original arguments */ + for (i = 0; i < ext_ret_count; i++) { + *(uintptr_t*)(argv1 + argc + sizeof(void*) / sizeof(uint32) * i) = + (uintptr_t)(ext_rets + cell_num); + cell_num += wasm_value_type_cell_num(ext_ret_types[i]); + } + + ret = invoke_native_internal(exec_env, func_ptr, + func_type, signature, attachment, + argv1, argc, argv); + if (!ret || aot_get_exception(module_inst)) { + if (argv1 != argv1_buf) + wasm_runtime_free(argv1); + return false; + } + + /* Get extra result values */ + switch (func_type->types[func_type->param_count]) { + case VALUE_TYPE_I32: + case VALUE_TYPE_F32: + argv_ret++; + break; + case VALUE_TYPE_I64: + case VALUE_TYPE_F64: + argv_ret += 2; + break; + default: + bh_assert(0); + break; + } + ext_rets = argv1 + argc + sizeof(void*)/sizeof(uint32) * ext_ret_count; + bh_memcpy_s(argv_ret, sizeof(uint32) * cell_num, + ext_rets, sizeof(uint32) * cell_num); + + if (argv1 != argv1_buf) + wasm_runtime_free(argv1); + + return true; + } + else { + return invoke_native_internal(exec_env, func_ptr, + func_type, signature, attachment, + argv, argc, argv); + } } #if WASM_ENABLE_BULK_MEMORY != 0 diff --git a/core/iwasm/common/arch/invokeNative_aarch64.s b/core/iwasm/common/arch/invokeNative_aarch64.s index 7204a958e..68390cb54 100644 --- a/core/iwasm/common/arch/invokeNative_aarch64.s +++ b/core/iwasm/common/arch/invokeNative_aarch64.s @@ -44,7 +44,7 @@ invokeNative: cmp x21, #0 beq call_func - /* Fill all stack args: reserve stack space and fill ony by one */ + /* Fill all stack args: reserve stack space and fill one by one */ mov x23, sp bic sp, x23, #15 /* Ensure stack is 16 bytes aligned */ lsl x23, x21, #3 /* x23 = nstacks * 8 */ diff --git a/core/iwasm/common/arch/invokeNative_arm_vfp.s b/core/iwasm/common/arch/invokeNative_arm_vfp.s index 0020f28a5..679fdedf1 100644 --- a/core/iwasm/common/arch/invokeNative_arm_vfp.s +++ b/core/iwasm/common/arch/invokeNative_arm_vfp.s @@ -52,7 +52,7 @@ invokeNative: beq call_func - /* Fill all stack args: reserve stack space and fill ony by one */ + /* Fill all stack args: reserve stack space and fill one by one */ add r4, r4, #64 /* r4 points to stack args */ bic sp, sp, #7 /* Ensure stack is 8 byte aligned */ mov r7, r5, lsl#2 /* r7 = nstacks * 4 */ diff --git a/core/iwasm/common/wasm_native.c b/core/iwasm/common/wasm_native.c index 3dd38c389..fcf52de08 100644 --- a/core/iwasm/common/wasm_native.c +++ b/core/iwasm/common/wasm_native.c @@ -54,7 +54,7 @@ check_symbol_signature(const WASMType *type, const char *signature) if (*p++ != '(') return false; - if ((uint32)(p_end - p) < type->param_count + 1) + if ((uint32)(p_end - p) < (uint32)(type->param_count + 1)) /* signatures of parameters, and ')' */ return false; diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index fa1700df2..66d79b888 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -1916,7 +1916,7 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, { WASMFunctionInstanceCommon *func; WASMType *type = NULL; - uint32 argc1, *argv1 = NULL; + uint32 argc1, *argv1 = NULL, cell_num, j, k = 0; int32 i, p; uint64 total_size; const char *exception; @@ -1946,12 +1946,16 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, } type = wasm_func->u.func->func_type; argc1 = wasm_func->param_cell_num; + cell_num = argc1 > wasm_func->ret_cell_num ? + argc1 : wasm_func->ret_cell_num; } #endif #if WASM_ENABLE_AOT != 0 if (module_inst->module_type == Wasm_Module_AoT) { type = ((AOTFunctionInstance*)func)->func_type; - argc1 = wasm_type_param_cell_num(type); + argc1 = type->param_cell_num; + cell_num = argc1 > type->ret_cell_num ? + argc1 : type->ret_cell_num; } #endif @@ -1961,7 +1965,7 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, goto fail; } - total_size = sizeof(uint32) * (uint64)(argc1 > 2 ? argc1 : 2); + total_size = sizeof(uint32) * (uint64)(cell_num > 2 ? cell_num : 2); if ((!(argv1 = runtime_malloc((uint32)total_size, module_inst, NULL, 0)))) { goto fail; @@ -2076,16 +2080,18 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, } /* print return value */ - if (type->result_count > 0) { - switch (type->types[type->param_count]) { + for (j = 0; j < type->result_count; j++) { + switch (type->types[type->param_count + j]) { case VALUE_TYPE_I32: - os_printf("0x%x:i32", argv1[0]); + os_printf("0x%x:i32", argv1[k]); + k++; break; case VALUE_TYPE_I64: { union { uint64 val; uint32 parts[2]; } u; - u.parts[0] = argv1[0]; - u.parts[1] = argv1[1]; + u.parts[0] = argv1[k]; + u.parts[1] = argv1[k + 1]; + k += 2; #ifdef PRIx64 os_printf("0x%"PRIx64":i64", u.val); #else @@ -2099,17 +2105,21 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, break; } case VALUE_TYPE_F32: - os_printf("%.7g:f32", *(float32*)argv1); + os_printf("%.7g:f32", *(float32*)(argv1 + k)); + k++; break; case VALUE_TYPE_F64: { union { float64 val; uint32 parts[2]; } u; - u.parts[0] = argv1[0]; - u.parts[1] = argv1[1]; + u.parts[0] = argv1[k]; + u.parts[1] = argv1[k + 1]; + k += 2; os_printf("%.7g:f64", u.val); break; } } + if (j < (uint32)(type->result_count - 1)) + os_printf(","); } os_printf("\n"); @@ -2302,6 +2312,8 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, uint32 argv_buf[32], *argv1 = argv_buf, *fps, *ints, *stacks, size; uint32 *argv_src = argv, i, argc1, n_ints = 0, n_fps = 0, n_stacks = 0; uint32 arg_i32, ptr_len; + uint32 result_count = func_type->result_count; + uint32 ext_ret_count = result_count > 1 ? result_count - 1 : 0; bool ret = false; n_ints++; /* exec env */ @@ -2355,6 +2367,13 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, } } + for (i = 0; i < ext_ret_count; i++) { + if (n_ints < MAX_REG_INTS) + n_ints++; + else + n_stacks++; + } + argc1 = MAX_REG_INTS + MAX_REG_FLOATS + n_stacks; if (argc1 > sizeof(argv_buf) / sizeof(uint32)) { size = sizeof(uint32) * (uint32)argc1; @@ -2458,6 +2477,14 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, } } + /* Save extra result values' address to argv1 */ + for (i = 0; i < ext_ret_count; i++) { + if (n_ints < MAX_REG_INTS) + ints[n_ints++] = *(uint32*)argv_src++; + else + stacks[n_stacks++] = *(uint32*)argv_src++; + } + exec_env->attachment = attachment; if (func_type->result_count == 0) { invokeNative_Void(func_ptr, argv1, n_stacks); @@ -2521,15 +2548,17 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, WASMModuleInstanceCommon *module = wasm_runtime_get_module_inst(exec_env); uint32 argv_buf[32], *argv1 = argv_buf, argc1, i, j = 0; uint32 arg_i32, ptr_len; + uint32 result_count = func_type->result_count; + uint32 ext_ret_count = result_count > 1 ? result_count - 1 : 0; uint64 size; bool ret = false; #if defined(BUILD_TARGET_X86_32) - argc1 = argc + 2; + argc1 = argc + ext_ret_count + 2; #else /* arm/thumb/mips/xtensa, 64-bit data must be 8 bytes aligned, so we need to allocate more memory. */ - argc1 = func_type->param_count * 2 + 2; + argc1 = func_type->param_count * 2 + ext_ret_count + 2; #endif if (argc1 > sizeof(argv_buf) / sizeof(uint32)) { @@ -2598,7 +2627,10 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, } } - argc1 = j; + /* Save extra result values' address to argv1 */ + word_copy(argv1 + j, argv, ext_ret_count); + + argc1 = j + ext_ret_count; exec_env->attachment = attachment; if (func_type->result_count == 0) { invokeNative_Void(func_ptr, argv1, argc1); @@ -2678,7 +2710,10 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, uint64 argv_buf[32], *argv1 = argv_buf, *fps, *ints, *stacks, size, arg_i64; uint32 *argv_src = argv, i, argc1, n_ints = 0, n_stacks = 0; uint32 arg_i32, ptr_len; + uint32 result_count = func_type->result_count; + uint32 ext_ret_count = result_count > 1 ? result_count - 1 : 0; bool ret = false; + #if defined(_WIN32) || defined(_WIN32_) /* important difference in calling conventions */ #define n_fps n_ints @@ -2686,7 +2721,7 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, int n_fps = 0; #endif - argc1 = 1 + MAX_REG_FLOATS + func_type->param_count + 2; + argc1 = 1 + MAX_REG_FLOATS + func_type->param_count + ext_ret_count; if (argc1 > sizeof(argv_buf) / sizeof(uint64)) { size = sizeof(uint64) * (uint64)argc1; if (!(argv1 = runtime_malloc((uint32)size, exec_env->module_inst, @@ -2764,11 +2799,21 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, } } + /* Save extra result values' address to argv1 */ + for (i = 0; i < ext_ret_count; i++) { + if (n_ints < MAX_REG_INTS) + ints[n_ints++] = *(uint64*)argv_src; + else + stacks[n_stacks++] = *(uint64*)argv_src; + argv_src += 2; + } + exec_env->attachment = attachment; - if (func_type->result_count == 0) { + if (result_count == 0) { invokeNative_Void(func_ptr, argv1, n_stacks); } else { + /* Invoke the native function and get the first result value */ switch (func_type->types[func_type->param_count]) { case VALUE_TYPE_I32: argv_ret[0] = (uint32)invokeNative_Int32(func_ptr, argv1, n_stacks); diff --git a/core/iwasm/compilation/aot_compiler.c b/core/iwasm/compilation/aot_compiler.c index 617bf6e65..f0f2539c6 100644 --- a/core/iwasm/compilation/aot_compiler.c +++ b/core/iwasm/compilation/aot_compiler.c @@ -92,14 +92,21 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index) AOTFuncContext *func_ctx = comp_ctx->func_ctxes[func_index]; uint8 *frame_ip = func_ctx->aot_func->code, opcode, *p_f32, *p_f64; uint8 *frame_ip_end = frame_ip + func_ctx->aot_func->code_size; - uint32 block_ret_type, br_depth, *br_depths, br_count; + uint8 *param_types = NULL; + uint8 *result_types = NULL; + uint8 value_type; + uint16 param_count; + uint16 result_count; + uint32 br_depth, *br_depths, br_count; uint32 func_idx, type_idx, mem_idx, local_idx, global_idx, i; uint32 bytes = 4, align, offset; + uint32 type_index; bool sign = true; int32 i32_const; int64 i64_const; float32 f32_const; float64 f64_const; + AOTFuncType *func_type = NULL; /* Start to translate the opcodes */ LLVMPositionBuilderAtEnd(comp_ctx->builder, @@ -119,11 +126,37 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index) case WASM_OP_BLOCK: case WASM_OP_LOOP: case WASM_OP_IF: - read_leb_uint32(frame_ip, frame_ip_end, block_ret_type); + value_type = *frame_ip++; + if (value_type == VALUE_TYPE_I32 + || value_type == VALUE_TYPE_I64 + || value_type == VALUE_TYPE_F32 + || value_type == VALUE_TYPE_F64 + || value_type == VALUE_TYPE_VOID) { + param_count = 0; + param_types = NULL; + if (value_type == VALUE_TYPE_VOID) { + result_count = 0; + result_types = NULL; + } + else { + result_count = 1; + result_types = &value_type; + } + } + else { + frame_ip--; + read_leb_uint32(frame_ip, frame_ip_end, type_index); + func_type = comp_ctx->comp_data->func_types[type_index]; + param_count = func_type->param_count; + param_types = func_type->types; + result_count = func_type->result_count; + result_types = func_type->types + param_count; + } if (!aot_compile_op_block(comp_ctx, func_ctx, &frame_ip, frame_ip_end, - (uint32)(BLOCK_TYPE_BLOCK + opcode - WASM_OP_BLOCK), - block_ret_type)) + (uint32)(LABEL_TYPE_BLOCK + opcode - WASM_OP_BLOCK), + param_count, param_types, + result_count, result_types)) return false; break; diff --git a/core/iwasm/compilation/aot_emit_control.c b/core/iwasm/compilation/aot_emit_control.c index bbb470a2c..b6d38bf20 100644 --- a/core/iwasm/compilation/aot_emit_control.c +++ b/core/iwasm/compilation/aot_emit_control.c @@ -19,13 +19,13 @@ enum { static void format_block_name(char *name, uint32 name_size, - uint32 block_index, uint32 block_type, - uint32 label_type) + uint32 block_index, uint32 label_type, + uint32 label_id) { - if (block_type != BLOCK_TYPE_FUNCTION) + if (label_type != LABEL_TYPE_FUNCTION) snprintf(name, name_size, "%s%d%s%s", - block_name_prefix[block_type], block_index, - "_", block_name_suffix[label_type]); + block_name_prefix[label_type], block_index, + "_", block_name_suffix[label_id]); else snprintf(name, name_size, "%s", "func_end"); } @@ -69,28 +69,44 @@ format_block_name(char *name, uint32 name_size, #define SET_BUILDER_POS(llvm_block) \ LLVMPositionBuilderAtEnd(comp_ctx->builder, llvm_block) -#define CREATE_RETURN_VALUE_PHI(block) do { \ - if (block->return_type != VALUE_TYPE_VOID \ - && !block->return_value_phi) { \ - LLVMBasicBlockRef block_curr = CURR_BLOCK(); \ - SET_BUILDER_POS(block->llvm_end_block); \ - if (!(block->return_value_phi = \ - LLVMBuildPhi(comp_ctx->builder, \ - TO_LLVM_TYPE(block->return_type),\ - "phi"))) { \ - aot_set_last_error("llvm build phi failed."); \ - goto fail; \ - } \ - SET_BUILDER_POS(block_curr); \ - } \ +#define CREATE_RESULT_VALUE_PHIS(block) do { \ + if (block->result_count && !block->result_phis) { \ + uint32 i; \ + uint64 size; \ + LLVMBasicBlockRef block_curr = CURR_BLOCK(); \ + /* Allocate memory */ \ + size = sizeof(LLVMValueRef) * (uint64)block->result_count; \ + if (size >= UINT32_MAX \ + || !(block->result_phis = \ + wasm_runtime_malloc((uint32)size))) { \ + aot_set_last_error("allocate memory failed."); \ + goto fail; \ + } \ + SET_BUILDER_POS(block->llvm_end_block); \ + for (i = 0; i < block->result_count; i++) { \ + if (!(block->result_phis[i] = \ + LLVMBuildPhi(comp_ctx->builder, \ + TO_LLVM_TYPE(block->result_types[i]), \ + "phi"))) { \ + aot_set_last_error("llvm build phi failed."); \ + goto fail; \ + } \ + } \ + SET_BUILDER_POS(block_curr); \ + } \ } while (0) -#define ADD_TO_RETURN_PHI(block, value) do { \ - LLVMBasicBlockRef block_curr = CURR_BLOCK(); \ - LLVMAddIncoming(block->return_value_phi, \ - &value, &block_curr, 1); \ +#define ADD_TO_RESULT_PHIS(block, value, idx) do { \ + LLVMBasicBlockRef block_curr = CURR_BLOCK(); \ + LLVMAddIncoming(block->result_phis[idx], \ + &value, &block_curr, 1); \ } while (0) +#define ADD_TO_PARAM_PHIS(block, value, idx) do { \ + LLVMBasicBlockRef block_curr = CURR_BLOCK(); \ + LLVMAddIncoming(block->param_phis[idx], \ + &value, &block_curr, 1); \ + } while (0) static LLVMBasicBlockRef find_next_llvm_end_block(AOTBlock *block) @@ -126,15 +142,20 @@ handle_next_reachable_block(AOTCompContext *comp_ctx, AOTBlock *block = func_ctx->block_stack.block_list_end; AOTBlock *block_prev; uint8 *frame_ip; + uint32 i; + AOTFuncType *func_type; aot_checked_addr_list_destroy(func_ctx); - if (block->block_type == BLOCK_TYPE_IF + if (block->label_type == LABEL_TYPE_IF && block->llvm_else_block && !block->skip_wasm_code_else && *p_frame_ip <= block->wasm_code_else) { /* Clear value stack and start to translate else branch */ aot_value_stack_destroy(&block->value_stack); + /* Recover parameters of else branch */ + for (i = 0; i < block->param_count; i++) + PUSH(block->else_param_phis[i], block->param_types[i]); SET_BUILDER_POS(block->llvm_else_block); *p_frame_ip = block->wasm_code_else + 1; return true; @@ -144,7 +165,7 @@ handle_next_reachable_block(AOTCompContext *comp_ctx, block_prev = block->prev; block = aot_block_stack_pop(&func_ctx->block_stack); - if (block->block_type == BLOCK_TYPE_IF) { + if (block->label_type == LABEL_TYPE_IF) { if (block->llvm_else_block && !block->skip_wasm_code_else && *p_frame_ip <= block->wasm_code_else) { @@ -178,15 +199,39 @@ handle_next_reachable_block(AOTCompContext *comp_ctx, /* Pop block, push its return value, and destroy the block */ block = aot_block_stack_pop(&func_ctx->block_stack); - if (block->return_type != VALUE_TYPE_VOID) { - bh_assert(block->return_value_phi); - if (block->block_type != BLOCK_TYPE_FUNCTION) - PUSH(block->return_value_phi, block->return_type); - else - LLVMBuildRet(comp_ctx->builder, block->return_value_phi); + func_type = func_ctx->aot_func->func_type; + for (i = 0; i < block->result_count; i++) { + bh_assert(block->result_phis[i]); + if (block->label_type != LABEL_TYPE_FUNCTION) { + PUSH(block->result_phis[i], block->result_types[i]); + } + else { + /* Store extra return values to function parameters */ + if (i != 0) { + uint32 param_index = func_type->param_count + i; + if (!LLVMBuildStore(comp_ctx->builder, + block->result_phis[i], + LLVMGetParam(func_ctx->func, param_index))) { + aot_set_last_error("llvm build store failed."); + goto fail; + } + } + } } - else if (block->block_type == BLOCK_TYPE_FUNCTION) { - LLVMBuildRetVoid(comp_ctx->builder); + if (block->label_type == LABEL_TYPE_FUNCTION) { + if (block->result_count) { + /* Return the first return value */ + if (!LLVMBuildRet(comp_ctx->builder, block->result_phis[0])) { + aot_set_last_error("llvm build return failed."); + goto fail; + } + } + else { + if (!LLVMBuildRetVoid(comp_ctx->builder)) { + aot_set_last_error("llvm build return void failed."); + goto fail; + } + } } aot_block_destroy(block); return true; @@ -194,10 +239,116 @@ fail: return false; } +static bool +push_aot_block_to_stack_and_pass_params(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + AOTBlock *block) +{ + uint32 i, param_index; + LLVMValueRef value; + uint64 size; + char name[32]; + LLVMBasicBlockRef block_curr = CURR_BLOCK(); + + if (block->param_count) { + size = sizeof(LLVMValueRef) * (uint64)block->param_count; + if (size >= UINT32_MAX + || !(block->param_phis = wasm_runtime_malloc((uint32)size))) { + aot_set_last_error("allocate memory failed."); + return false; + } + + if (block->label_type == LABEL_TYPE_IF + && !block->skip_wasm_code_else + && !(block->else_param_phis = wasm_runtime_malloc((uint32)size))) { + wasm_runtime_free(block->param_phis); + block->param_phis = NULL; + aot_set_last_error("allocate memory failed."); + return false; + } + + /* Create param phis */ + for (i = 0; i < block->param_count; i++) { + SET_BUILDER_POS(block->llvm_entry_block); + snprintf(name, sizeof(name), "%s%d_phi%d", + block_name_prefix[block->label_type], + block->block_index, i); + if (!(block->param_phis[i] = + LLVMBuildPhi(comp_ctx->builder, + TO_LLVM_TYPE(block->param_types[i]), + name))) { + aot_set_last_error("llvm build phi failed."); + goto fail; + } + + if (block->label_type == LABEL_TYPE_IF + && !block->skip_wasm_code_else + && block->llvm_else_block) { + /* Build else param phis */ + SET_BUILDER_POS(block->llvm_else_block); + snprintf(name, sizeof(name), "else%d_phi%d", + block->block_index, i); + if (!(block->else_param_phis[i] = + LLVMBuildPhi(comp_ctx->builder, + TO_LLVM_TYPE(block->param_types[i]), + name))) { + aot_set_last_error("llvm build phi failed."); + goto fail; + } + } + } + SET_BUILDER_POS(block_curr); + + /* Pop param values from current block's + * value stack and add to param phis. + */ + for (i = 0; i < block->param_count; i++) { + param_index = block->param_count - 1 - i; + POP(value, block->param_types[param_index]); + ADD_TO_PARAM_PHIS(block, value, param_index); + if (block->label_type == LABEL_TYPE_IF + && !block->skip_wasm_code_else) { + if (block->llvm_else_block) { + /* has else branch, add to else param phis */ + LLVMAddIncoming(block->else_param_phis[param_index], + &value, &block_curr, 1); + } + else { + /* no else branch, add to result phis */ + CREATE_RESULT_VALUE_PHIS(block); + ADD_TO_RESULT_PHIS(block, value, param_index); + } + } + } + } + + /* Push the new block to block stack */ + aot_block_stack_push(&func_ctx->block_stack, block); + + /* Push param phis to the new block */ + for (i = 0; i < block->param_count; i++) { + PUSH(block->param_phis[i], block->param_types[i]); + } + + return true; + +fail: + if (block->param_phis) { + wasm_runtime_free(block->param_phis); + block->param_phis = NULL; + } + if (block->else_param_phis) { + wasm_runtime_free(block->else_param_phis); + block->else_param_phis = NULL; + } + return false; +} + bool aot_compile_op_block(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, uint8 **p_frame_ip, uint8 *frame_ip_end, - uint32 block_type, uint32 block_ret_type) + uint32 label_type, uint32 param_count, uint8 *param_types, + uint32 result_count, uint8 *result_types) { BlockAddr block_addr_cache[BLOCK_ADDR_CACHE_SIZE][BLOCK_ADDR_CONFLICT_SIZE]; AOTBlock *block; @@ -215,7 +366,7 @@ aot_compile_op_block(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, /* Get block info */ if (!(wasm_loader_find_block_addr((BlockAddr*)block_addr_cache, - *p_frame_ip, frame_ip_end, (uint8)block_type, + *p_frame_ip, frame_ip_end, (uint8)label_type, &else_addr, &end_addr, NULL, 0))) { aot_set_last_error("find block end addr failed."); return false; @@ -226,51 +377,66 @@ aot_compile_op_block(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, aot_set_last_error("allocate memory failed."); return false; } + memset(block, 0, sizeof(AOTBlock)); + if (param_count + && !(block->param_types = wasm_runtime_malloc(param_count))) { + aot_set_last_error("allocate memory failed."); + goto fail; + } + if (result_count) { + if (!(block->result_types = wasm_runtime_malloc(result_count))) { + aot_set_last_error("allocate memory failed."); + goto fail; + } + } /* Init aot block data */ - memset(block, 0, sizeof(AOTBlock)); - block->block_type = block_type; - block->return_type = (uint8)block_ret_type; + block->label_type = label_type; + block->param_count = param_count; + memcpy(block->param_types, param_types, param_count); + block->result_count = result_count; + memcpy(block->result_types, result_types, result_count); block->wasm_code_else = else_addr; block->wasm_code_end = end_addr; - block->block_index = func_ctx->block_stack.block_index[block_type]; - func_ctx->block_stack.block_index[block_type]++; + block->block_index = func_ctx->block_stack.block_index[label_type]; + func_ctx->block_stack.block_index[label_type]++; - if (block_type == BLOCK_TYPE_BLOCK - || block_type == BLOCK_TYPE_LOOP) { + if (label_type == LABEL_TYPE_BLOCK + || label_type == LABEL_TYPE_LOOP) { /* Create block */ format_block_name(name, sizeof(name), - block->block_index, block_type, LABEL_BEGIN); + block->block_index, label_type, LABEL_BEGIN); CREATE_BLOCK(block->llvm_entry_block, name); MOVE_BLOCK_AFTER_CURR(block->llvm_entry_block); /* Jump to the entry block */ BUILD_BR(block->llvm_entry_block); + if (!push_aot_block_to_stack_and_pass_params(comp_ctx, func_ctx, block)) + goto fail; /* Start to translate the block */ SET_BUILDER_POS(block->llvm_entry_block); - aot_block_stack_push(&func_ctx->block_stack, block); - if (block_type == BLOCK_TYPE_LOOP) + if (label_type == LABEL_TYPE_LOOP) aot_checked_addr_list_destroy(func_ctx); } - else if (block_type == BLOCK_TYPE_IF) { + else if (label_type == LABEL_TYPE_IF) { POP_COND(value); if (!LLVMIsConstant(value)) { /* Compare value is not constant, create condition br IR */ /* Create entry block */ format_block_name(name, sizeof(name), - block->block_index, block_type, LABEL_BEGIN); + block->block_index, label_type, LABEL_BEGIN); CREATE_BLOCK(block->llvm_entry_block, name); MOVE_BLOCK_AFTER_CURR(block->llvm_entry_block); /* Create end block */ format_block_name(name, sizeof(name), - block->block_index, block_type, LABEL_END); + block->block_index, label_type, LABEL_END); CREATE_BLOCK(block->llvm_end_block, name); MOVE_BLOCK_AFTER(block->llvm_end_block, block->llvm_entry_block); if (else_addr) { /* Create else block */ format_block_name(name, sizeof(name), - block->block_index, block_type, LABEL_ELSE); + block->block_index, label_type, LABEL_ELSE); CREATE_BLOCK(block->llvm_else_block, name); MOVE_BLOCK_AFTER(block->llvm_else_block, block->llvm_entry_block); /* Create condition br IR */ @@ -283,49 +449,48 @@ aot_compile_op_block(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, block->llvm_end_block); block->is_reachable = true; } + if (!push_aot_block_to_stack_and_pass_params(comp_ctx, func_ctx, block)) + goto fail; /* Start to translate if branch of BLOCK if */ SET_BUILDER_POS(block->llvm_entry_block); - aot_block_stack_push(&func_ctx->block_stack, block); } else { if ((int32)LLVMConstIntGetZExtValue(value) != 0) { - /* Compare value is not 0, condtion is true, else branch of + /* Compare value is not 0, condition is true, else branch of BLOCK if cannot be reached */ block->skip_wasm_code_else = true; /* Create entry block */ format_block_name(name, sizeof(name), - block->block_index, block_type, LABEL_BEGIN); + block->block_index, label_type, LABEL_BEGIN); CREATE_BLOCK(block->llvm_entry_block, name); MOVE_BLOCK_AFTER_CURR(block->llvm_entry_block); /* Jump to the entry block */ BUILD_BR(block->llvm_entry_block); + if (!push_aot_block_to_stack_and_pass_params(comp_ctx, func_ctx, block)) + goto fail; /* Start to translate the if branch */ SET_BUILDER_POS(block->llvm_entry_block); - aot_block_stack_push(&func_ctx->block_stack, block); } else { - /* Compare value is not 0, condtion is false, if branch of + /* Compare value is not 0, condition is false, if branch of BLOCK if cannot be reached */ if (else_addr) { /* Create else block */ format_block_name(name, sizeof(name), - block->block_index, block_type, LABEL_ELSE); + block->block_index, label_type, LABEL_ELSE); CREATE_BLOCK(block->llvm_else_block, name); MOVE_BLOCK_AFTER_CURR(block->llvm_else_block); /* Jump to the else block */ BUILD_BR(block->llvm_else_block); + if (!push_aot_block_to_stack_and_pass_params(comp_ctx, func_ctx, block)) + goto fail; /* Start to translate the else branch */ SET_BUILDER_POS(block->llvm_else_block); *p_frame_ip = else_addr + 1; - aot_block_stack_push(&func_ctx->block_stack, block); } else { - if (block->return_type != VALUE_TYPE_VOID) { - aot_set_last_error("WASM value stack underflow."); - goto fail; - } /* skip the block */ - wasm_runtime_free(block); + aot_block_destroy(block); *p_frame_ip = end_addr + 1; } } @@ -338,7 +503,7 @@ aot_compile_op_block(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, return true; fail: - wasm_runtime_free(block); + aot_block_destroy(block); return false; } @@ -349,13 +514,14 @@ aot_compile_op_else(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, AOTBlock *block = func_ctx->block_stack.block_list_end; LLVMValueRef value; char name[32]; + uint32 i, result_index; /* Check block */ if (!block) { aot_set_last_error("WASM block stack underflow."); return false; } - if (block->block_type != BLOCK_TYPE_IF + if (block->label_type != LABEL_TYPE_IF || (!block->skip_wasm_code_else && !block->llvm_else_block)) { aot_set_last_error("Invalid WASM block type."); @@ -365,7 +531,7 @@ aot_compile_op_else(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, /* Create end block if needed */ if (!block->llvm_end_block) { format_block_name(name, sizeof(name), - block->block_index, block->block_type, LABEL_END); + block->block_index, block->label_type, LABEL_END); CREATE_BLOCK(block->llvm_end_block, name); if (block->llvm_else_block) MOVE_BLOCK_AFTER(block->llvm_end_block, block->llvm_else_block); @@ -376,10 +542,11 @@ aot_compile_op_else(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, block->is_reachable = true; /* Comes from the if branch of BLOCK if */ - if (block->return_type != VALUE_TYPE_VOID) { - POP(value, block->return_type); - CREATE_RETURN_VALUE_PHI(block); - ADD_TO_RETURN_PHI(block, value); + CREATE_RESULT_VALUE_PHIS(block); + for (i = 0; i < block->result_count; i++) { + result_index = block->result_count - 1 - i; + POP(value, block->result_types[result_index]); + ADD_TO_RESULT_PHIS(block, value, result_index); } /* Jump to end block */ @@ -387,8 +554,12 @@ aot_compile_op_else(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, if (!block->skip_wasm_code_else && block->llvm_else_block) { - /* Clear value stack and start to translate else branch */ + /* Clear value stack, recover param values + * and start to translate else branch. + */ aot_value_stack_destroy(&block->value_stack); + for (i = 0; i < block->param_count; i++) + PUSH(block->else_param_phis[i], block->param_types[i]); SET_BUILDER_POS(block->llvm_else_block); aot_checked_addr_list_destroy(func_ctx); return true; @@ -409,6 +580,7 @@ aot_compile_op_end(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, LLVMValueRef value; LLVMBasicBlockRef next_llvm_end_block; char name[32]; + uint32 i, result_index; /* Check block stack */ if (!(block = func_ctx->block_stack.block_list_end)) { @@ -419,17 +591,18 @@ aot_compile_op_end(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, /* Create the end block */ if (!block->llvm_end_block) { format_block_name(name, sizeof(name), - block->block_index, block->block_type, LABEL_END); + block->block_index, block->label_type, LABEL_END); CREATE_BLOCK(block->llvm_end_block, name); if ((next_llvm_end_block = find_next_llvm_end_block(block))) MOVE_BLOCK_BEFORE(block->llvm_end_block, next_llvm_end_block); } - /* Handle block return value */ - if (block->return_type != VALUE_TYPE_VOID) { - POP(value, block->return_type); - CREATE_RETURN_VALUE_PHI(block); - ADD_TO_RETURN_PHI(block, value); + /* Handle block result values */ + CREATE_RESULT_VALUE_PHIS(block); + for (i = 0; i < block->result_count; i++) { + result_index = block->result_count - 1 - i; + POP(value, block->result_types[result_index]); + ADD_TO_RESULT_PHIS(block, value, result_index); } /* Jump to the end block */ @@ -446,16 +619,23 @@ aot_compile_op_br(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, uint32 br_depth, uint8 **p_frame_ip) { AOTBlock *block_dst; - LLVMValueRef value_ret; + LLVMValueRef value_ret, value_param; LLVMBasicBlockRef next_llvm_end_block; char name[32]; + uint32 i, param_index, result_index; if (!(block_dst = get_target_block(func_ctx, br_depth))) { return false; } - if (block_dst->block_type == BLOCK_TYPE_LOOP) { + if (block_dst->label_type == LABEL_TYPE_LOOP) { /* Dest block is Loop block */ + /* Handle Loop parameters */ + for (i = 0; i < block_dst->param_count; i++) { + param_index = block_dst->param_count - 1 - i; + POP(value_param, block_dst->param_types[param_index]); + ADD_TO_PARAM_PHIS(block_dst, value_param, param_index); + } BUILD_BR(block_dst->llvm_entry_block); } else { @@ -463,7 +643,7 @@ aot_compile_op_br(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, /* Create the end block */ if (!block_dst->llvm_end_block) { format_block_name(name, sizeof(name), - block_dst->block_index, block_dst->block_type, + block_dst->block_index, block_dst->label_type, LABEL_END); CREATE_BLOCK(block_dst->llvm_end_block, name); if ((next_llvm_end_block = find_next_llvm_end_block(block_dst))) @@ -473,13 +653,13 @@ aot_compile_op_br(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, block_dst->is_reachable = true; - /* Handle return value */ - if (block_dst->return_type != VALUE_TYPE_VOID) { - POP(value_ret, block_dst->return_type); - CREATE_RETURN_VALUE_PHI(block_dst); - ADD_TO_RETURN_PHI(block_dst, value_ret); + /* Handle result values */ + CREATE_RESULT_VALUE_PHIS(block_dst); + for (i = 0; i < block_dst->result_count; i++) { + result_index = block_dst->result_count - 1 - i; + POP(value_ret, block_dst->result_types[result_index]); + ADD_TO_RESULT_PHIS(block_dst, value_ret, result_index); } - /* Jump to the end block */ BUILD_BR(block_dst->llvm_end_block); } @@ -494,9 +674,11 @@ aot_compile_op_br_if(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, uint32 br_depth, uint8 **p_frame_ip) { AOTBlock *block_dst; - LLVMValueRef value_cmp, value_ret; + LLVMValueRef value_cmp, value, *values = NULL; LLVMBasicBlockRef llvm_else_block, next_llvm_end_block; char name[32]; + uint32 i, param_index, result_index; + uint64 size; POP_COND(value_cmp); if (!LLVMIsConstant(value_cmp)) { @@ -509,8 +691,29 @@ aot_compile_op_br_if(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, CREATE_BLOCK(llvm_else_block, "br_if_else"); MOVE_BLOCK_AFTER_CURR(llvm_else_block); - if (block_dst->block_type == BLOCK_TYPE_LOOP) { + if (block_dst->label_type == LABEL_TYPE_LOOP) { /* Dest block is Loop block */ + /* Handle Loop parameters */ + if (block_dst->param_count) { + size = sizeof(LLVMValueRef) * (uint64)block_dst->param_count; + if (size >= UINT32_MAX + || !(values = wasm_runtime_malloc((uint32)size))) { + aot_set_last_error("allocate memory failed."); + goto fail; + } + for (i = 0; i < block_dst->param_count; i++) { + param_index = block_dst->param_count - 1 - i; + POP(value, block_dst->param_types[param_index]); + ADD_TO_PARAM_PHIS(block_dst, value, param_index); + values[param_index] = value; + } + for (i = 0; i < block_dst->param_count; i++) { + PUSH(values[i], block_dst->param_types[i]); + } + wasm_runtime_free(values); + values = NULL; + } + BUILD_COND_BR(value_cmp, block_dst->llvm_entry_block, llvm_else_block); @@ -522,7 +725,7 @@ aot_compile_op_br_if(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, /* Create the end block */ if (!block_dst->llvm_end_block) { format_block_name(name, sizeof(name), - block_dst->block_index, block_dst->block_type, + block_dst->block_index, block_dst->label_type, LABEL_END); CREATE_BLOCK(block_dst->llvm_end_block, name); if ((next_llvm_end_block = find_next_llvm_end_block(block_dst))) @@ -530,15 +733,29 @@ aot_compile_op_br_if(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, next_llvm_end_block); } - /* Set reachable flag and create condtion br IR */ + /* Set reachable flag and create condition br IR */ block_dst->is_reachable = true; - /* Handle return value */ - if (block_dst->return_type != VALUE_TYPE_VOID) { - POP(value_ret, block_dst->return_type); - CREATE_RETURN_VALUE_PHI(block_dst); - ADD_TO_RETURN_PHI(block_dst, value_ret); - PUSH(value_ret, block_dst->return_type); + /* Handle result values */ + if (block_dst->result_count) { + size = sizeof(LLVMValueRef) * (uint64)block_dst->result_count; + if (size >= UINT32_MAX + || !(values = wasm_runtime_malloc((uint32)size))) { + aot_set_last_error("allocate memory failed."); + goto fail; + } + CREATE_RESULT_VALUE_PHIS(block_dst); + for (i = 0; i < block_dst->result_count; i++) { + result_index = block_dst->result_count - 1 - i; + POP(value, block_dst->result_types[result_index]); + values[result_index] = value; + ADD_TO_RESULT_PHIS(block_dst, value, result_index); + } + for (i = 0; i < block_dst->result_count; i++) { + PUSH(values[i], block_dst->result_types[i]); + } + wasm_runtime_free(values); + values = NULL; } /* Condition jump to end block */ @@ -551,16 +768,18 @@ aot_compile_op_br_if(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } else { if ((int32)LLVMConstIntGetZExtValue(value_cmp) != 0) { - /* Compare value is not 0, condtion is true, same as op_br */ + /* Compare value is not 0, condition is true, same as op_br */ return aot_compile_op_br(comp_ctx, func_ctx, br_depth, p_frame_ip); } else { - /* Compare value is not 0, condtion is false, skip br_if */ + /* Compare value is not 0, condition is false, skip br_if */ return true; } } return true; fail: + if (values) + wasm_runtime_free(values); return false; } @@ -569,12 +788,14 @@ aot_compile_op_br_table(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, uint32 *br_depths, uint32 br_count, uint8 **p_frame_ip) { - uint32 i; - LLVMValueRef value_switch, value_cmp, value_case, value_ret = NULL; + uint32 i, j; + LLVMValueRef value_switch, value_cmp, value_case, value, *values = NULL; LLVMBasicBlockRef default_llvm_block = NULL, target_llvm_block; LLVMBasicBlockRef next_llvm_end_block; AOTBlock *target_block; uint32 br_depth, depth_idx; + uint32 param_index, result_index; + uint64 size; char name[32]; POP_I32(value_cmp); @@ -585,13 +806,13 @@ aot_compile_op_br_table(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, if (!target_block) return false; - if (target_block->block_type != BLOCK_TYPE_LOOP) { + if (target_block->label_type != LABEL_TYPE_LOOP) { /* Dest block is Block/If/Function block */ /* Create the end block */ if (!target_block->llvm_end_block) { format_block_name(name, sizeof(name), target_block->block_index, - target_block->block_type, + target_block->label_type, LABEL_END); CREATE_BLOCK(target_block->llvm_end_block, name); if ((next_llvm_end_block = @@ -599,18 +820,50 @@ aot_compile_op_br_table(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, MOVE_BLOCK_BEFORE(target_block->llvm_end_block, next_llvm_end_block); } - /* Handle return value */ - if (target_block->return_type != VALUE_TYPE_VOID) { - POP(value_ret, target_block->return_type); - CREATE_RETURN_VALUE_PHI(target_block); - ADD_TO_RETURN_PHI(target_block, value_ret); - PUSH(value_ret, target_block->return_type); + /* Handle result values */ + if (target_block->result_count) { + size = sizeof(LLVMValueRef) * (uint64)target_block->result_count; + if (size >= UINT32_MAX + || !(values = wasm_runtime_malloc((uint32)size))) { + aot_set_last_error("allocate memory failed."); + goto fail; + } + CREATE_RESULT_VALUE_PHIS(target_block); + for (j = 0; j < target_block->result_count; j++) { + result_index = target_block->result_count - 1 - j; + POP(value, target_block->result_types[result_index]); + values[result_index] = value; + ADD_TO_RESULT_PHIS(target_block, value, result_index); + } + for (j = 0; j < target_block->result_count; j++) { + PUSH(values[j], target_block->result_types[j]); + } + wasm_runtime_free(values); } target_block->is_reachable = true; if (i == br_count) default_llvm_block = target_block->llvm_end_block; } else { + /* Handle Loop parameters */ + if (target_block->param_count) { + size = sizeof(LLVMValueRef) * (uint64)target_block->param_count; + if (size >= UINT32_MAX + || !(values = wasm_runtime_malloc((uint32)size))) { + aot_set_last_error("allocate memory failed."); + goto fail; + } + for (j = 0; j < target_block->param_count; j++) { + param_index = target_block->param_count - 1 - j; + POP(value, target_block->param_types[param_index]); + values[param_index] = value; + ADD_TO_PARAM_PHIS(target_block, value, param_index); + } + for (j = 0; j < target_block->param_count; j++) { + PUSH(values[j], target_block->param_types[j]); + } + wasm_runtime_free(values); + } if (i == br_count) default_llvm_block = target_block->llvm_entry_block; } @@ -630,7 +883,7 @@ aot_compile_op_br_table(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, target_block = get_target_block(func_ctx, br_depths[i]); if (!target_block) return false; - target_llvm_block = target_block->block_type != BLOCK_TYPE_LOOP + target_llvm_block = target_block->label_type != LABEL_TYPE_LOOP ? target_block->llvm_end_block : target_block->llvm_entry_block; LLVMAddCase(value_switch, value_case, target_llvm_block); @@ -648,6 +901,8 @@ aot_compile_op_br_table(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, return aot_compile_op_br(comp_ctx, func_ctx, br_depth, p_frame_ip); } fail: + if (values) + wasm_runtime_free(values); return false; } @@ -657,14 +912,38 @@ aot_compile_op_return(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, { AOTBlock *block_func = func_ctx->block_stack.block_list_head; LLVMValueRef value; + AOTFuncType *func_type; + uint32 i, param_index, result_index; bh_assert(block_func); - if (block_func->return_type != VALUE_TYPE_VOID) { - POP(value, block_func->return_type); - LLVMBuildRet(comp_ctx->builder, value); + func_type = func_ctx->aot_func->func_type; + + if (block_func->result_count) { + /* Store extra result values to function parameters */ + for (i = 0; i < block_func->result_count - 1; i++) { + result_index = block_func->result_count - 1 - i; + POP(value, block_func->result_types[result_index]); + param_index = func_type->param_count + result_index; + if (!LLVMBuildStore(comp_ctx->builder, + value, + LLVMGetParam(func_ctx->func, param_index))) { + aot_set_last_error("llvm build store failed."); + goto fail; + } + } + /* Return the first result value */ + POP(value, block_func->result_types[0]); + if (!LLVMBuildRet(comp_ctx->builder, value)) { + aot_set_last_error("llvm build return failed."); + goto fail; + } + } + else { + if (!LLVMBuildRetVoid(comp_ctx->builder)) { + aot_set_last_error("llvm build return void failed."); + goto fail; + } } - else - LLVMBuildRetVoid(comp_ctx->builder); return handle_next_reachable_block(comp_ctx, func_ctx, p_frame_ip); fail: diff --git a/core/iwasm/compilation/aot_emit_control.h b/core/iwasm/compilation/aot_emit_control.h index d222ea607..fa73d29fb 100644 --- a/core/iwasm/compilation/aot_emit_control.h +++ b/core/iwasm/compilation/aot_emit_control.h @@ -15,7 +15,8 @@ extern "C" { bool aot_compile_op_block(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, uint8 **p_frame_ip, uint8 *frame_ip_end, - uint32 block_type, uint32 block_ret_type); + uint32 label_type, uint32 param_count, uint8 *param_types, + uint32 result_count, uint8 *result_types); bool aot_compile_op_else(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, diff --git a/core/iwasm/compilation/aot_emit_function.c b/core/iwasm/compilation/aot_emit_function.c index ed45edda9..1897cfd80 100644 --- a/core/iwasm/compilation/aot_emit_function.c +++ b/core/iwasm/compilation/aot_emit_function.c @@ -64,9 +64,9 @@ check_exception_thrown(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) /* Load the first byte of aot_module_inst->cur_exception, and check whether it is '\0'. If yes, no exception was thrown. */ if (!(value = LLVMBuildLoad(comp_ctx->builder, func_ctx->cur_exception, - "exce_value")) + "exce_value")) || !(cmp = LLVMBuildICmp(comp_ctx->builder, LLVMIntEQ, - value, I8_ZERO, "cmp"))) { + value, I8_ZERO, "cmp"))) { aot_set_last_error("llvm build icmp failed."); return false; } @@ -183,7 +183,7 @@ call_aot_invoke_native_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } } - if (param_count > 64) { + if (param_cell_num > 64) { aot_set_last_error("prepare native arguments failed: " "maximum 64 parameter cell number supported."); return false; @@ -309,17 +309,22 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, uint32 import_func_count = comp_ctx->comp_data->import_func_count; AOTImportFunc *import_funcs = comp_ctx->comp_data->import_funcs; uint32 func_count = comp_ctx->func_ctx_count, param_cell_num = 0; + uint32 ext_ret_cell_num = 0, cell_num = 0; AOTFuncContext **func_ctxes = comp_ctx->func_ctxes; AOTFuncType *func_type; AOTFunc *aot_func; LLVMTypeRef *param_types = NULL, ret_type; + LLVMTypeRef ext_ret_ptr_type; LLVMValueRef *param_values = NULL, value_ret = NULL, func; LLVMValueRef import_func_idx, res; - int32 i, j = 0, param_count; + LLVMValueRef ext_ret, ext_ret_ptr, ext_ret_idx; + int32 i, j = 0, param_count, result_count, ext_ret_count; uint64 total_size; uint32 callee_cell_num; uint8 wasm_ret_type; + uint8 *ext_ret_types = NULL; bool ret = false; + char buf[32]; /* Check function index */ if (func_idx >= import_func_count + func_count) { @@ -335,11 +340,19 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, aot_func->func_type; /* Get param cell number */ - param_cell_num = wasm_type_param_cell_num(func_type); + param_cell_num = func_type->param_cell_num; - /* Allocate memory for parameters */ + /* Allocate memory for parameters. + * Parameters layout: + * - exec env + * - wasm function's parameters + * - extra results'(except the first one) addresses + */ param_count = (int32)func_type->param_count; - total_size = sizeof(LLVMValueRef) * (uint64)(param_count + 1); + result_count = (int32)func_type->result_count; + ext_ret_count = result_count > 1 ? result_count - 1 : 0; + total_size = sizeof(LLVMValueRef) * (uint64)(param_count + 1 + + ext_ret_count); if (total_size >= UINT32_MAX || !(param_values = wasm_runtime_malloc((uint32)total_size))) { aot_set_last_error("Allocate memory failed."); @@ -402,9 +415,50 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, && !check_stack_boundary(comp_ctx, func_ctx, callee_cell_num)) goto fail; + /* Prepare parameters for extra results */ + if (ext_ret_count > 0) { + ext_ret_types = func_type->types + param_count + 1; + ext_ret_cell_num = + wasm_get_cell_num(ext_ret_types, ext_ret_count); + if (ext_ret_cell_num > 64) { + aot_set_last_error("prepare extra results's return " + "address arguments failed: " + "maximum 64 parameter cell number supported."); + goto fail; + } + + for (i = 0; i < ext_ret_count; i++) { + if (!(ext_ret_idx = I32_CONST(cell_num)) + || !(ext_ret_ptr_type = + LLVMPointerType(TO_LLVM_TYPE(ext_ret_types[i]), 0))) { + aot_set_last_error("llvm add const or pointer type failed."); + goto fail; + } + + snprintf(buf, sizeof(buf), "func%d_ext_ret%d_ptr", func_idx, i); + if (!(ext_ret_ptr = LLVMBuildInBoundsGEP(comp_ctx->builder, + func_ctx->argv_buf, + &ext_ret_idx, 1, buf))) { + aot_set_last_error("llvm build GEP failed."); + goto fail; + } + snprintf(buf, sizeof(buf), "func%d_ext_ret%d_ptr_cast", func_idx, i); + if (!(ext_ret_ptr = LLVMBuildBitCast(comp_ctx->builder, + ext_ret_ptr, + ext_ret_ptr_type, + buf))) { + aot_set_last_error("llvm build bit cast failed."); + goto fail; + } + param_values[1 + param_count + i] = ext_ret_ptr; + cell_num += wasm_value_type_cell_num(ext_ret_types[i]); + } + } + /* Call the function */ if (!(value_ret = LLVMBuildCall(comp_ctx->builder, func, - param_values, (uint32)param_count + 1, + param_values, + (uint32)param_count + 1 + ext_ret_count, (func_type->result_count > 0 ? "call" : "")))) { aot_set_last_error("LLVM build call failed."); @@ -419,8 +473,21 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, goto fail; } - if (func_type->result_count > 0) + if (func_type->result_count > 0) { + /* Push the first result to stack */ PUSH(value_ret, func_type->types[func_type->param_count]); + /* Load extra result from its address and push to stack */ + for (i = 0; i < ext_ret_count; i++) { + snprintf(buf, sizeof(buf), "func%d_ext_ret%d", func_idx, i); + if (!(ext_ret = LLVMBuildLoad(comp_ctx->builder, + param_values[1 + param_count + i], + buf))) { + aot_set_last_error("llvm build load failed."); + goto fail; + } + PUSH(ext_ret, ext_ret_types[i]); + } + } ret = true; fail: @@ -437,15 +504,15 @@ call_aot_call_indirect_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, LLVMValueRef func_type_idx, LLVMValueRef table_elem_idx, LLVMTypeRef *param_types, LLVMValueRef *param_values, uint32 param_count, uint32 param_cell_num, - LLVMTypeRef ret_type, uint8 wasm_ret_type, - LLVMValueRef *p_value_ret, LLVMValueRef *p_res) + uint32 result_count, uint8 *wasm_ret_types, + LLVMValueRef *value_rets, LLVMValueRef *p_res) { LLVMTypeRef func_type, func_ptr_type, func_param_types[6]; - LLVMTypeRef ret_ptr_type, elem_ptr_type; - LLVMValueRef func, elem_idx, elem_ptr; - LLVMValueRef func_param_values[6], value_ret = NULL, res = NULL; + LLVMTypeRef ret_type, ret_ptr_type, elem_ptr_type; + LLVMValueRef func, ret_idx, ret_ptr, elem_idx, elem_ptr; + LLVMValueRef func_param_values[6], res = NULL; char buf[32], *func_name = "aot_call_indirect"; - uint32 i, cell_num = 0; + uint32 i, cell_num = 0, ret_cell_num, argv_cell_num; /* prepare function type of aot_call_indirect */ func_param_types[0] = comp_ctx->exec_env_type; /* exec_env */ @@ -482,7 +549,9 @@ call_aot_call_indirect_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } } - if (param_count > 64) { + ret_cell_num = wasm_get_cell_num(wasm_ret_types, result_count); + argv_cell_num = param_cell_num > ret_cell_num ? param_cell_num : ret_cell_num; + if (argv_cell_num > 64) { aot_set_last_error("prepare native arguments failed: " "maximum 64 parameter cell number supported."); return false; @@ -533,24 +602,31 @@ call_aot_call_indirect_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, return false; } - /* get function return value */ - if (wasm_ret_type != VALUE_TYPE_VOID) { - if (!(ret_ptr_type = LLVMPointerType(ret_type, 0))) { - aot_set_last_error("llvm add pointer type failed."); + /* get function result values */ + cell_num = 0; + for (i = 0; i < result_count; i++) { + ret_type = TO_LLVM_TYPE(wasm_ret_types[i]); + if (!(ret_idx = I32_CONST(cell_num)) + || !(ret_ptr_type = LLVMPointerType(ret_type, 0))) { + aot_set_last_error("llvm add const or pointer type failed."); return false; } - if (!(value_ret = LLVMBuildBitCast(comp_ctx->builder, func_ctx->argv_buf, - ret_ptr_type, "argv_ret"))) { - aot_set_last_error("llvm build bit cast failed."); + snprintf(buf, sizeof(buf), "argv_ret%d", i); + if (!(ret_ptr = LLVMBuildInBoundsGEP(comp_ctx->builder, + func_ctx->argv_buf, &ret_idx, 1, buf)) + || !(ret_ptr = LLVMBuildBitCast(comp_ctx->builder, ret_ptr, + ret_ptr_type, buf))) { + aot_set_last_error("llvm build GEP or bit cast failed."); return false; } - if (!(*p_value_ret = LLVMBuildLoad(comp_ctx->builder, value_ret, - "value_ret"))) { + snprintf(buf, sizeof(buf), "ret%d", i); + if (!(value_rets[i] = LLVMBuildLoad(comp_ctx->builder, ret_ptr, buf))) { aot_set_last_error("llvm build load failed."); return false; } + cell_num += wasm_value_type_cell_num(wasm_ret_types[i]); } *p_res = res; @@ -563,12 +639,12 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, { AOTFuncType *func_type; LLVMValueRef elem_idx, ftype_idx; - LLVMValueRef *param_values = NULL, value_ret = NULL, res = NULL; - LLVMTypeRef *param_types = NULL, ret_type; - int32 i, param_count; + LLVMValueRef *param_values = NULL, *value_rets = NULL, res = NULL; + LLVMTypeRef *param_types = NULL; + int32 i, param_count, result_count; uint32 param_cell_num; uint64 total_size; - uint8 wasm_ret_type; + uint8 *wasm_ret_types = NULL; bool ret; /* Check function type index */ @@ -582,7 +658,9 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, func_type = comp_ctx->comp_data->func_types[type_idx]; - param_cell_num = wasm_type_param_cell_num(func_type); + param_cell_num = func_type->param_cell_num; + result_count = func_type->result_count; + wasm_ret_types = func_type->types + func_type->param_count; POP_I32(elem_idx); @@ -598,16 +676,6 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, for (i = 0; i < param_count; i++) param_types[i] = TO_LLVM_TYPE(func_type->types[i]); - /* Resolve return type of the LLVM function */ - if (func_type->result_count) { - wasm_ret_type = func_type->types[func_type->param_count]; - ret_type = TO_LLVM_TYPE(wasm_ret_type); - } - else { - wasm_ret_type = VALUE_TYPE_VOID; - ret_type = VOID_TYPE; - } - /* Allocate memory for parameters */ total_size = sizeof(LLVMValueRef) * (uint64)param_count; if (total_size >= UINT32_MAX @@ -620,16 +688,25 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, for (i = param_count - 1; i >= 0; i--) POP(param_values[i], func_type->types[i]); + /* Allocate memory for result values */ + total_size = sizeof(LLVMValueRef) * (uint64)result_count; + if (total_size >= UINT32_MAX + || !(value_rets = wasm_runtime_malloc((uint32)total_size))) { + aot_set_last_error("Allocate memory failed."); + goto fail; + } + memset(value_rets, 0, total_size); + if (!call_aot_call_indirect_func(comp_ctx, func_ctx, func_type, ftype_idx, elem_idx, param_types, param_values, param_count, param_cell_num, - ret_type, wasm_ret_type, - &value_ret, &res)) + result_count, wasm_ret_types, + value_rets, &res)) goto fail; - if (func_type->result_count > 0) - PUSH(value_ret, func_type->types[func_type->param_count]); + for (i = 0; i < func_type->result_count; i++) + PUSH(value_rets[i], func_type->types[func_type->param_count + i]); /* Check whether there was exception thrown when executing the function */ if (!check_call_return(comp_ctx, func_ctx, res)) @@ -638,6 +715,8 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, ret = true; fail: + if (value_rets) + wasm_runtime_free(value_rets); if (param_values) wasm_runtime_free(param_values); if (param_types) diff --git a/core/iwasm/compilation/aot_llvm.c b/core/iwasm/compilation/aot_llvm.c index 7ae2e025d..813513eb7 100644 --- a/core/iwasm/compilation/aot_llvm.c +++ b/core/iwasm/compilation/aot_llvm.c @@ -41,9 +41,14 @@ aot_add_llvm_func(AOTCompContext *comp_ctx, AOTFuncType *aot_func_type, uint64 size; uint32 i, j = 0, param_count = (uint64)aot_func_type->param_count; - /* aot context as first parameter */ + /* exec env as first parameter */ param_count++; + /* Extra wasm function results(except the first one)'s address are + * appended to aot function parameters. */ + if (aot_func_type->result_count > 1) + param_count += aot_func_type->result_count - 1; + /* Initialize parameter types of the LLVM function */ size = sizeof(LLVMTypeRef) * ((uint64)param_count); if (size >= UINT32_MAX @@ -56,6 +61,15 @@ aot_add_llvm_func(AOTCompContext *comp_ctx, AOTFuncType *aot_func_type, param_types[j++] = comp_ctx->exec_env_type; for (i = 0; i < aot_func_type->param_count; i++) param_types[j++] = TO_LLVM_TYPE(aot_func_type->types[i]); + /* Extra results' address */ + for (i = 1; i < aot_func_type->result_count; i++, j++) { + param_types[j] = + TO_LLVM_TYPE(aot_func_type->types[aot_func_type->param_count + i]); + if (!(param_types[j] = LLVMPointerType(param_types[j], 0))) { + aot_set_last_error("llvm get pointer type failed."); + goto fail; + } + } /* Resolve return type of the LLVM function */ if (aot_func_type->result_count) @@ -92,6 +106,16 @@ fail: return func; } +static void +free_block_memory(AOTBlock *block) +{ + if (block->param_types) + wasm_runtime_free(block->param_types); + if (block->result_types) + wasm_runtime_free(block->result_types); + wasm_runtime_free(block); +} + /** * Create first AOTBlock, or function block for the function */ @@ -100,22 +124,33 @@ aot_create_func_block(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, AOTFunc *func, AOTFuncType *aot_func_type) { AOTBlock *aot_block; + uint32 param_count = aot_func_type->param_count, + result_count = aot_func_type->result_count; /* Allocate memory */ if (!(aot_block = wasm_runtime_malloc(sizeof(AOTBlock)))) { aot_set_last_error("allocate memory failed."); return NULL; } - memset(aot_block, 0, sizeof(AOTBlock)); + if (param_count + && !(aot_block->param_types = wasm_runtime_malloc(param_count))) { + aot_set_last_error("allocate memory failed."); + goto fail; + } + if (result_count) { + if (!(aot_block->result_types = wasm_runtime_malloc(result_count))) { + aot_set_last_error("allocate memory failed."); + goto fail; + } + } - /* Set block type and return type */ - aot_block->block_type = BLOCK_TYPE_FUNCTION; - if (aot_func_type->result_count) - aot_block->return_type = aot_func_type->types[aot_func_type->param_count]; - else - aot_block->return_type = VALUE_TYPE_VOID; - + /* Set block data */ + aot_block->label_type = LABEL_TYPE_FUNCTION; + aot_block->param_count = param_count; + memcpy(aot_block->param_types, aot_func_type->types, param_count); + aot_block->result_count = result_count; + memcpy(aot_block->result_types, aot_func_type->types + param_count, result_count); aot_block->wasm_code_end = func->code + func->code_size; /* Add function entry block */ @@ -129,7 +164,7 @@ aot_create_func_block(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, return aot_block; fail: - wasm_runtime_free(aot_block); + free_block_memory(aot_block); return NULL; } @@ -1288,6 +1323,16 @@ void aot_block_destroy(AOTBlock *block) { aot_value_stack_destroy(&block->value_stack); + if (block->param_types) + wasm_runtime_free(block->param_types); + if (block->param_phis) + wasm_runtime_free(block->param_phis); + if (block->else_param_phis) + wasm_runtime_free(block->else_param_phis); + if (block->result_types) + wasm_runtime_free(block->result_types); + if (block->result_phis) + wasm_runtime_free(block->result_phis); wasm_runtime_free(block); } diff --git a/core/iwasm/compilation/aot_llvm.h b/core/iwasm/compilation/aot_llvm.h index f94f7c754..9fd28a622 100644 --- a/core/iwasm/compilation/aot_llvm.h +++ b/core/iwasm/compilation/aot_llvm.h @@ -48,10 +48,8 @@ typedef struct AOTBlock { /* Block index */ uint32 block_index; - /* BLOCK_TYPE_BLOCK/LOOP/IF/FUNCTION */ - uint32 block_type; - /* VALUE_TYPE_I32/I64/F32/F64/VOID */ - uint8 return_type; + /* LABEL_TYPE_BLOCK/LOOP/IF/FUNCTION */ + uint32 label_type; /* Whether it is reachable */ bool is_reachable; /* Whether skip translation of wasm else branch */ @@ -72,8 +70,16 @@ typedef struct AOTBlock { /* WASM operation stack */ AOTValueStack value_stack; - /* Return value of this block, a PHI node */ - LLVMValueRef return_value_phi; + /* Param count/types/PHIs of this block */ + uint32 param_count; + uint8 *param_types; + LLVMValueRef *param_phis; + LLVMValueRef *else_param_phis; + + /* Result count/types/PHIs of this block */ + uint32 result_count; + uint8 *result_types; + LLVMValueRef *result_phis; } AOTBlock; /** diff --git a/core/iwasm/interpreter/wasm.h b/core/iwasm/interpreter/wasm.h index b54d09aa3..fd7f03a82 100644 --- a/core/iwasm/interpreter/wasm.h +++ b/core/iwasm/interpreter/wasm.h @@ -66,10 +66,10 @@ extern "C" { #define EXPORT_KIND_MEMORY 2 #define EXPORT_KIND_GLOBAL 3 -#define BLOCK_TYPE_BLOCK 0 -#define BLOCK_TYPE_LOOP 1 -#define BLOCK_TYPE_IF 2 -#define BLOCK_TYPE_FUNCTION 3 +#define LABEL_TYPE_BLOCK 0 +#define LABEL_TYPE_LOOP 1 +#define LABEL_TYPE_IF 2 +#define LABEL_TYPE_FUNCTION 3 typedef struct WASMModule WASMModule; typedef struct WASMFunction WASMFunction; @@ -98,9 +98,10 @@ typedef struct InitializerExpression { } InitializerExpression; typedef struct WASMType { - uint32 param_count; - /* only one result is supported currently */ - uint32 result_count; + uint16 param_count; + uint16 result_count; + uint16 param_cell_num; + uint16 ret_cell_num; /* types of params and results */ uint8 types[1]; } WASMType; @@ -206,7 +207,7 @@ typedef struct WASMFunction { uint16 ret_cell_num; /* cell num of local variables */ uint16 local_cell_num; - /* offset of each local, including function paramameters + /* offset of each local, including function parameters and local variables */ uint16 *local_offsets; @@ -351,9 +352,21 @@ typedef struct WASMModule { #endif } WASMModule; +typedef struct BlockType { + /* Block type may be expressed in one of two forms: + * either by the type of the single return value or + * by a type index of module. + */ + union { + uint8 value_type; + WASMType *type; + } u; + bool is_value_type; +} BlockType; + typedef struct WASMBranchBlock { - uint8 block_type; - uint8 return_type; + uint8 label_type; + uint32 cell_num; uint8 *target_addr; uint32 *frame_sp; } WASMBranchBlock; @@ -421,40 +434,28 @@ wasm_value_type_size(uint8 value_type) inline static uint16 wasm_value_type_cell_num(uint8 value_type) { - switch (value_type) { - case VALUE_TYPE_I32: - case VALUE_TYPE_F32: - return 1; - case VALUE_TYPE_I64: - case VALUE_TYPE_F64: - return 2; - default: - bh_assert(0); + if (value_type == VALUE_TYPE_VOID) + return 0; + else if (value_type == VALUE_TYPE_I32 + || value_type == VALUE_TYPE_F32) + return 1; + else if (value_type == VALUE_TYPE_I64 + || value_type == VALUE_TYPE_F64) + return 2; + else { + bh_assert(0); } return 0; } -inline static uint16 +inline static uint32 wasm_get_cell_num(const uint8 *types, uint32 type_count) { uint32 cell_num = 0; uint32 i; for (i = 0; i < type_count; i++) cell_num += wasm_value_type_cell_num(types[i]); - return (uint16)cell_num; -} - -inline static uint16 -wasm_type_param_cell_num(const WASMType *type) -{ - return wasm_get_cell_num(type->types, type->param_count); -} - -inline static uint16 -wasm_type_return_cell_num(const WASMType *type) -{ - return wasm_get_cell_num(type->types + type->param_count, - type->result_count); + return cell_num; } inline static bool @@ -467,8 +468,45 @@ wasm_type_equal(const WASMType *type1, const WASMType *type2) ? true : false; } +static inline uint32 +block_type_get_param_types(BlockType *block_type, + uint8 **p_param_types) +{ + uint32 param_count = 0; + if (!block_type->is_value_type) { + WASMType *wasm_type = block_type->u.type; + *p_param_types = wasm_type->types; + param_count = wasm_type->param_count; + } + else { + *p_param_types = NULL; + param_count = 0; + } + + return param_count; +} + +static inline uint32 +block_type_get_result_types(BlockType *block_type, + uint8 **p_result_types) +{ + uint32 result_count = 0; + if (block_type->is_value_type) { + if (block_type->u.value_type != VALUE_TYPE_VOID) { + *p_result_types = &block_type->u.value_type; + result_count = 1; + } + } + else { + WASMType *wasm_type = block_type->u.type; + *p_result_types = wasm_type->types + wasm_type->param_count; + result_count = wasm_type->result_count; + } + return result_count; +} + #ifdef __cplusplus } /* end of extern "C" */ #endif -#endif /* end of _WASM_H_ */ \ No newline at end of file +#endif /* end of _WASM_H_ */ diff --git a/core/iwasm/interpreter/wasm_interp.h b/core/iwasm/interpreter/wasm_interp.h index 9883d2654..c3c2c1b34 100644 --- a/core/iwasm/interpreter/wasm_interp.h +++ b/core/iwasm/interpreter/wasm_interp.h @@ -27,8 +27,8 @@ typedef struct WASMInterpFrame { uint8 *ip; #if WASM_ENABLE_FAST_INTERP != 0 - /* return offset of current frame. - the callee will put return value here */ + /* return offset of the first return value of current frame. + the callee will put return values here continuously */ uint32 ret_offset; uint32 *lp; uint32 operand[1]; diff --git a/core/iwasm/interpreter/wasm_interp_classic.c b/core/iwasm/interpreter/wasm_interp_classic.c index 5316bd92d..211ba5bf7 100644 --- a/core/iwasm/interpreter/wasm_interp_classic.c +++ b/core/iwasm/interpreter/wasm_interp_classic.c @@ -414,13 +414,13 @@ read_leb(const uint8 *buf, uint32 *p_offset, uint32 maxbits, bool sign) frame_sp += 2; \ } while (0) -#define PUSH_CSP(type, ret_type, _target_addr) do { \ - bh_assert(frame_csp < frame->csp_boundary); \ - frame_csp->block_type = type; \ - frame_csp->return_type = ret_type; \ - frame_csp->target_addr = _target_addr; \ - frame_csp->frame_sp = frame_sp; \ - frame_csp++; \ +#define PUSH_CSP(_label_type, cell_num, _target_addr) do { \ + bh_assert(frame_csp < frame->csp_boundary); \ + frame_csp->label_type = _label_type; \ + frame_csp->cell_num = cell_num; \ + frame_csp->target_addr = _target_addr; \ + frame_csp->frame_sp = frame_sp; \ + frame_csp++; \ } while (0) #define POP_I32() (--frame_sp, *(int32*)frame_sp) @@ -442,21 +442,15 @@ read_leb(const uint8 *buf, uint32 *p_offset, uint32 maxbits, bool sign) #define POP_CSP_N(n) do { \ uint32 *frame_sp_old = frame_sp; \ + uint32 cell_num = 0; \ POP_CSP_CHECK_OVERFLOW(n + 1); \ frame_csp -= n; \ frame_ip = (frame_csp - 1)->target_addr; \ - /* copy return value of block */ \ + /* copy arity values of block */ \ frame_sp = (frame_csp - 1)->frame_sp; \ - switch ((frame_csp - 1)->return_type) { \ - case VALUE_TYPE_I32: \ - case VALUE_TYPE_F32: \ - PUSH_I32(*(frame_sp_old - 1)); \ - break; \ - case VALUE_TYPE_I64: \ - case VALUE_TYPE_F64: \ - PUSH_I64(GET_I64_FROM_ADDR(frame_sp_old - 2)); \ - break; \ - } \ + cell_num = (frame_csp - 1)->cell_num; \ + word_copy(frame_sp, frame_sp_old - cell_num, cell_num); \ + frame_sp += cell_num; \ } while (0) /* Pop the given number of elements from the given frame's stack. */ @@ -974,6 +968,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, uint8 *global_data = module->global_data; uint32 linear_mem_size = memory ? num_bytes_per_page * memory->cur_page_count : 0; WASMTableInstance *table = module->default_table; + WASMType **wasm_types = module->module->types; WASMGlobalInstance *globals = module->globals, *global; uint8 opcode_IMPDEP = WASM_OP_IMPDEP; WASMInterpFrame *frame = NULL; @@ -984,7 +979,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, WASMBranchBlock *frame_csp = NULL; BlockAddr *cache_items; uint8 *frame_ip_end = frame_ip + 1; - uint8 opcode, block_ret_type; + uint8 opcode; uint32 *depths = NULL; uint32 depth_buf[BR_TABLE_TMP_BUF_LEN]; uint32 i, depth, cond, count, fidx, tidx, frame_size = 0; @@ -993,7 +988,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, uint8 *else_addr, *end_addr, *maddr = NULL; uint32 local_idx, local_offset, global_idx; uint8 local_type, *global_addr; - uint32 cache_index; + uint32 cache_index, type_index, cell_num; + uint8 value_type; #if WASM_ENABLE_LABELS_AS_VALUES != 0 #define HANDLE_OPCODE(op) &&HANDLE_##op @@ -1016,9 +1012,15 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP (WASM_OP_NOP): HANDLE_OP_END (); - HANDLE_OP (WASM_OP_BLOCK): - block_ret_type = *frame_ip++; + HANDLE_OP (EXT_OP_BLOCK): + read_leb_uint32(frame_ip, frame_ip_end, type_index); + cell_num = wasm_types[type_index]->ret_cell_num; + goto handle_op_block; + HANDLE_OP (WASM_OP_BLOCK): + value_type = *frame_ip++; + cell_num = wasm_value_type_cell_num(value_type); +handle_op_block: cache_index = ((uintptr_t)frame_ip) & (uintptr_t)(BLOCK_ADDR_CACHE_SIZE - 1); cache_items = exec_env->block_addr_cache[cache_index]; if (cache_items[0].start_addr == frame_ip) { @@ -1029,24 +1031,37 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, } else if (!wasm_loader_find_block_addr((BlockAddr*)exec_env->block_addr_cache, frame_ip, (uint8*)-1, - BLOCK_TYPE_BLOCK, + LABEL_TYPE_BLOCK, &else_addr, &end_addr, NULL, 0)) { wasm_set_exception(module, "find block address failed"); goto got_exception; } - PUSH_CSP(BLOCK_TYPE_BLOCK, block_ret_type, end_addr); + PUSH_CSP(LABEL_TYPE_BLOCK, cell_num, end_addr); HANDLE_OP_END (); + HANDLE_OP (EXT_OP_LOOP): + read_leb_uint32(frame_ip, frame_ip_end, type_index); + cell_num = wasm_types[type_index]->param_cell_num; + goto handle_op_loop; + HANDLE_OP (WASM_OP_LOOP): - block_ret_type = *frame_ip++; - PUSH_CSP(BLOCK_TYPE_LOOP, block_ret_type, frame_ip); + value_type = *frame_ip++; + cell_num = wasm_value_type_cell_num(value_type); +handle_op_loop: + PUSH_CSP(LABEL_TYPE_LOOP, cell_num, frame_ip); HANDLE_OP_END (); - HANDLE_OP (WASM_OP_IF): - block_ret_type = *frame_ip++; + HANDLE_OP (EXT_OP_IF): + read_leb_uint32(frame_ip, frame_ip_end, type_index); + cell_num = wasm_types[type_index]->ret_cell_num; + goto handle_op_if; + HANDLE_OP (WASM_OP_IF): + value_type = *frame_ip++; + cell_num = wasm_value_type_cell_num(value_type); +handle_op_if: cache_index = ((uintptr_t)frame_ip) & (uintptr_t)(BLOCK_ADDR_CACHE_SIZE - 1); cache_items = exec_env->block_addr_cache[cache_index]; if (cache_items[0].start_addr == frame_ip) { @@ -1059,7 +1074,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, } else if (!wasm_loader_find_block_addr((BlockAddr*)exec_env->block_addr_cache, frame_ip, (uint8*)-1, - BLOCK_TYPE_IF, + LABEL_TYPE_IF, &else_addr, &end_addr, NULL, 0)) { wasm_set_exception(module, "find block address failed"); @@ -1068,7 +1083,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, cond = (uint32)POP_I32(); - PUSH_CSP(BLOCK_TYPE_IF, block_ret_type, end_addr); + PUSH_CSP(LABEL_TYPE_IF, cell_num, end_addr); /* condition of the if branch is false, else condition is met */ if (cond == 0) { @@ -1106,6 +1121,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, CHECK_SUSPEND_FLAGS(); #endif read_leb_uint32(frame_ip, frame_ip_end, depth); +label_pop_csp_n: POP_CSP_N(depth); HANDLE_OP_END (); @@ -1116,7 +1132,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, read_leb_uint32(frame_ip, frame_ip_end, depth); cond = (uint32)POP_I32(); if (cond) - POP_CSP_N(depth); + goto label_pop_csp_n; HANDLE_OP_END (); HANDLE_OP (WASM_OP_BR_TABLE): @@ -1147,7 +1163,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, wasm_runtime_free(depths); depths = NULL; } - POP_CSP_N(depth); + goto label_pop_csp_n; HANDLE_OP_END (); HANDLE_OP (WASM_OP_RETURN): @@ -1192,7 +1208,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, wasm_set_exception(module, "type index is overflow"); goto got_exception; } - cur_type = module->module->types[tidx]; + cur_type = wasm_types[tidx]; /* to skip 0x00 here */ frame_ip++; @@ -2705,6 +2721,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP (EXT_OP_TEE_LOCAL_FAST_I64): HANDLE_OP (EXT_OP_COPY_STACK_TOP): HANDLE_OP (EXT_OP_COPY_STACK_TOP_I64): + HANDLE_OP (EXT_OP_COPY_STACK_VALUES): { wasm_set_exception(module, "WASM interp failed: unsupported opcode."); goto got_exception; @@ -2753,7 +2770,6 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, else { WASMFunction *cur_wasm_func = cur_func->u.func; WASMType *func_type; - uint8 ret_type; func_type = cur_wasm_func->func_type; @@ -2790,10 +2806,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, (uint32)(cur_func->local_cell_num * 4)); /* Push function block as first block */ - ret_type = func_type->result_count - ? cur_func->param_types[func_type->param_count] - : VALUE_TYPE_VOID; - PUSH_CSP(BLOCK_TYPE_FUNCTION, ret_type, frame_ip_end - 1); + cell_num = func_type->ret_cell_num; + PUSH_CSP(LABEL_TYPE_FUNCTION, cell_num, frame_ip_end - 1); wasm_exec_env_set_cur_frame(exec_env, (WASMRuntimeFrame*)frame); } @@ -2837,7 +2851,8 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMInterpFrame *frame, *outs_area; /* Allocate sufficient cells for all kinds of return values. */ - unsigned all_cell_num = 2, i; + unsigned all_cell_num = function->ret_cell_num > 2 ? + function->ret_cell_num : 2, i; /* This frame won't be used by JITed code, so only allocate interp frame here. */ unsigned frame_size = wasm_interp_interp_frame_size(all_cell_num); diff --git a/core/iwasm/interpreter/wasm_interp_fast.c b/core/iwasm/interpreter/wasm_interp_fast.c index b6509a7cf..fe34f91e8 100644 --- a/core/iwasm/interpreter/wasm_interp_fast.c +++ b/core/iwasm/interpreter/wasm_interp_fast.c @@ -679,21 +679,121 @@ trunc_f64_to_int(WASMModuleInstance *module, PUSH_##dst_op_type(value); \ } while (0) -#define RECOVER_BR_INFO() do { \ - uint16 stack_index, ret_cell_num; \ - stack_index = *(uint16*)frame_ip; \ - frame_ip += sizeof(uint16); \ - ret_cell_num = *(uint8*)frame_ip; \ - frame_ip += sizeof(uint8); \ - if (ret_cell_num == 1) \ - frame_lp[stack_index] = \ - frame_lp[*(int16*)frame_ip]; \ - else if (ret_cell_num == 2) { \ - *(int64*)(frame_lp + stack_index) = \ - *(int64*)(frame_lp + *(int16*)frame_ip);\ - } \ - frame_ip += sizeof(int16); \ - frame_ip = *(uint8**)frame_ip; \ +static bool +copy_stack_values(WASMModuleInstance *module, + uint32 *frame_lp, + uint32 arity, + uint32 total_cell_num, + const uint8 *cells, + const int16 *src_offsets, + const uint16 *dst_offsets) +{ + /* To avoid the overlap issue between src offsets and dst offset, + * we use 2 steps to do the copy. First step, copy the src values + * to a tmp buf. Second step, copy the values from tmp buf to dst. + */ + uint32 buf[16] = {0}, i; + uint32 *tmp_buf = buf; + uint8 cell; + int16 src, buf_index = 0; + uint16 dst; + + /* Allocate memory if the buf is not large enough */ + if (total_cell_num > sizeof(buf)/sizeof(uint32)) { + uint64 total_size = sizeof(uint32) * (uint64)total_cell_num; + if (total_size >= UINT32_MAX + || !(tmp_buf = wasm_runtime_malloc((uint32)total_size))) { + wasm_set_exception(module, + "WASM interp failed: allocate memory failed."); + return false; + } + } + + /* 1) Copy values from src to tmp buf */ + for (i = 0; i < arity; i++) { + cell = cells[i]; + src = src_offsets[i]; + if (cell == 1) + tmp_buf[buf_index] = frame_lp[src]; + else + *(uint64*)(tmp_buf + buf_index) = *(uint64*)(frame_lp + src); + buf_index += cell; + } + + /* 2) Copy values from tmp buf to dest */ + buf_index = 0; + for (i = 0; i < arity; i++) { + cell = cells[i]; + dst = dst_offsets[i]; + if (cell == 1) + frame_lp[dst] = tmp_buf[buf_index]; + else + *(uint64*)(frame_lp + dst) = *(uint64*)(tmp_buf + buf_index); + buf_index += cell; + } + + if (tmp_buf != buf) { + wasm_runtime_free(tmp_buf); + } + + return true; +} + +#define RECOVER_BR_INFO() do { \ + uint32 arity; \ + /* read arity */ \ + arity = *(uint32*)frame_ip; \ + frame_ip += sizeof(arity); \ + if (arity) { \ + uint32 total_cell; \ + uint16 *dst_offsets = NULL; \ + uint8 *cells; \ + int16 *src_offsets = NULL; \ + /* read total cell num */ \ + total_cell = *(uint32*)frame_ip; \ + frame_ip += sizeof(total_cell); \ + /* cells */ \ + cells = (uint8 *)frame_ip; \ + frame_ip += arity * sizeof(uint8); \ + /* src offsets */ \ + src_offsets = (int16 *)frame_ip; \ + frame_ip += arity * sizeof(int16); \ + /* dst offsets */ \ + dst_offsets = (uint16*)frame_ip; \ + frame_ip += arity * sizeof(uint16); \ + if (arity == 1) { \ + if (cells[0] == 1) \ + frame_lp[dst_offsets[0]] = \ + frame_lp[src_offsets[0]]; \ + else if (cells[0] == 2) { \ + *(int64*)(frame_lp + dst_offsets[0]) = \ + *(int64*)(frame_lp + src_offsets[0]); \ + } \ + } \ + else { \ + if (!copy_stack_values(module, frame_lp, \ + arity, total_cell, \ + cells, src_offsets, \ + dst_offsets)) \ + goto got_exception; \ + } \ + } \ + frame_ip = *(uint8**)frame_ip; \ + } while (0) + +#define SKIP_BR_INFO() do { \ + uint32 arity; \ + /* read and skip arity */ \ + arity = *(uint32*)frame_ip; \ + frame_ip += sizeof(arity); \ + if (arity) { \ + /* skip total cell num */ \ + frame_ip += sizeof(uint32); \ + /* skip cells, src offsets and dst offsets */ \ + frame_ip += (sizeof(uint8) + sizeof(int16) + sizeof(uint16)) * arity; \ + } \ + /* skip target address */ \ + frame_ip += sizeof(uint8*); \ } while (0) static inline int32 @@ -1034,6 +1134,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, #if WASM_ENABLE_THREAD_MGR != 0 CHECK_SUSPEND_FLAGS(); #endif +recover_br_info: RECOVER_BR_INFO(); HANDLE_OP_END (); @@ -1044,10 +1145,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, cond = frame_lp[GET_OFFSET()]; if (cond) - RECOVER_BR_INFO(); - else { - frame_ip += (2 + 1 + 2 + sizeof(uint8*)); - } + goto recover_br_info; + else + SKIP_BR_INFO(); HANDLE_OP_END (); @@ -1062,16 +1162,44 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, if (!(didx >= 0 && (uint32)didx < count)) didx = count; - frame_ip += (didx * ((2 + 1 + 2 + sizeof(uint8*)))); - RECOVER_BR_INFO(); - HANDLE_OP_END (); + while (didx--) + SKIP_BR_INFO(); + + goto recover_br_info; HANDLE_OP (WASM_OP_RETURN): - if (cur_func->ret_cell_num == 2) { - *((uint64 *)(prev_frame->lp + prev_frame->ret_offset)) = - GET_OPERAND(uint64, 0); - } else if (cur_func->ret_cell_num == 1) { - prev_frame->lp[prev_frame->ret_offset] = GET_OPERAND(int32, 0);; + { + uint32 ret_idx; + WASMType *func_type; + uint32 off, ret_offset; + uint8 *ret_types; + if (cur_func->is_import_func +#if WASM_ENABLE_MULTI_MODULE != 0 + && !cur_func->import_func_inst +#endif + ) + func_type = cur_func->u.func_import->func_type; + else + func_type = cur_func->u.func->func_type; + + /* types of each return value */ + ret_types = func_type->types + func_type->param_count; + ret_offset = prev_frame->ret_offset; + + for (ret_idx = 0, off = sizeof(int16) * (func_type->result_count - 1); + ret_idx < func_type->result_count; + ret_idx++, off -= sizeof(int16)) { + if (ret_types[ret_idx] == VALUE_TYPE_I64 + || ret_types[ret_idx] == VALUE_TYPE_F64) { + *((uint64 *)(prev_frame->lp + ret_offset)) = + GET_OPERAND(uint64, off); + ret_offset += 2; + } + else { + prev_frame->lp[ret_offset] = GET_OPERAND(int32, off); + ret_offset++; + } + } } goto return_func; @@ -1128,7 +1256,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, && !cur_func->import_func_inst #endif ) - cur_func_type = cur_func->u.func_import->func_type; + cur_func_type = cur_func->u.func_import->func_type; else cur_func_type = cur_func->u.func->func_type; if (!wasm_type_equal(cur_type, cur_func_type)) { @@ -2350,6 +2478,37 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, *(uint64*)(frame_lp + addr2) = *(uint64*)(frame_lp + addr1); HANDLE_OP_END (); + HANDLE_OP (EXT_OP_COPY_STACK_VALUES): + { + uint32 values_count, total_cell; + uint8 *cells; + int16 *src_offsets = NULL; + uint16 *dst_offsets = NULL; + + /* read values_count */ + values_count = *(uint32*)frame_ip; + frame_ip += sizeof(values_count); + /* read total cell num */ + total_cell = *(uint32*)frame_ip; + frame_ip += sizeof(total_cell); + /* cells */ + cells = (uint8 *)frame_ip; + frame_ip += values_count * sizeof(uint8); + /* src offsets */ + src_offsets = (int16 *)frame_ip; + frame_ip += values_count * sizeof(int16); + /* dst offsets */ + dst_offsets = (uint16*)frame_ip; + frame_ip += values_count * sizeof(uint16); + + if (!copy_stack_values(module, frame_lp, + values_count, total_cell, + cells, src_offsets, + dst_offsets)) + goto got_exception; + + HANDLE_OP_END (); + } HANDLE_OP (WASM_OP_SET_LOCAL): HANDLE_OP (WASM_OP_TEE_LOCAL): { @@ -2567,6 +2726,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP (WASM_OP_LOOP): HANDLE_OP (WASM_OP_END): HANDLE_OP (WASM_OP_NOP): + HANDLE_OP (EXT_OP_BLOCK): + HANDLE_OP (EXT_OP_LOOP): + HANDLE_OP (EXT_OP_IF): { wasm_set_exception(module, "WASM interp failed: unsupported opcode."); goto got_exception; @@ -2596,8 +2758,22 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, } } frame_ip += cur_func->param_count * sizeof(int16); - if (cur_func->ret_cell_num != 0) + if (cur_func->ret_cell_num != 0) { + /* Get the first return value's offset. Since loader emit all return + * values' offset so we must skip remain return values' offsets. + */ + WASMType *func_type; + if (cur_func->is_import_func +#if WASM_ENABLE_MULTI_MODULE != 0 + && !cur_func->import_func_inst +#endif + ) + func_type = cur_func->u.func_import->func_type; + else + func_type = cur_func->u.func->func_type; frame->ret_offset = GET_OFFSET(); + frame_ip += 2 * (func_type->result_count - 1); + } SYNC_ALL_TO_FRAME(); prev_frame = frame; } @@ -2712,7 +2888,8 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMInterpFrame *frame, *outs_area; /* Allocate sufficient cells for all kinds of return values. */ - unsigned all_cell_num = 2, i; + unsigned all_cell_num = function->ret_cell_num > 2 ? + function->ret_cell_num : 2, i; /* This frame won't be used by JITed code, so only allocate interp frame here. */ unsigned frame_size = wasm_interp_interp_frame_size(all_cell_num); diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index b22cc8488..f846f8d2c 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -389,6 +389,7 @@ load_type_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, { const uint8 *p = buf, *p_end = buf_end, *p_org; uint32 type_count, param_count, result_count, i, j; + uint32 param_cell_num, ret_cell_num; uint64 total_size; uint8 flag; WASMType *type; @@ -419,14 +420,16 @@ load_type_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, CHECK_BUF(p, p_end, param_count); p += param_count; read_leb_uint32(p, p_end, result_count); - if (result_count > 1) { - set_error_buf(error_buf, error_buf_size, - "Load type section failed: invalid result arity."); - return false; - } CHECK_BUF(p, p_end, result_count); p = p_org; + if (param_count > UINT16_MAX || result_count > UINT16_MAX) { + set_error_buf(error_buf, error_buf_size, + "Load type section failed: " + "param count or result count too large"); + return false; + } + total_size = offsetof(WASMType, types) + sizeof(uint8) * (uint64)(param_count + result_count); if (!(type = module->types[i] = @@ -435,8 +438,8 @@ load_type_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, } /* Resolve param types and result types */ - type->param_count = param_count; - type->result_count = result_count; + type->param_count = (uint16)param_count; + type->result_count = (uint16)result_count; for (j = 0; j < param_count; j++) { CHECK_BUF(p, p_end, 1); type->types[j] = read_uint8(p); @@ -446,6 +449,18 @@ load_type_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, CHECK_BUF(p, p_end, 1); type->types[param_count + j] = read_uint8(p); } + + param_cell_num = wasm_get_cell_num(type->types, param_count); + ret_cell_num = wasm_get_cell_num(type->types + param_count, + result_count); + if (param_cell_num > UINT16_MAX || ret_cell_num > UINT16_MAX) { + set_error_buf(error_buf, error_buf_size, + "Load type section failed: " + "param count or result count too large"); + return false; + } + type->param_cell_num = (uint16)param_cell_num; + type->ret_cell_num = (uint16)ret_cell_num; } } @@ -1742,8 +1757,8 @@ load_function_section(const uint8 *buf, const uint8 *buf_end, } } - func->param_cell_num = wasm_type_param_cell_num(func->func_type); - func->ret_cell_num = wasm_type_return_cell_num(func->func_type); + func->param_cell_num = func->func_type->param_cell_num; + func->ret_cell_num = func->func_type->ret_cell_num; func->local_cell_num = wasm_get_cell_num(func->local_types, func->local_count); @@ -2929,7 +2944,7 @@ bool wasm_loader_find_block_addr(BlockAddr *block_addr_cache, const uint8 *start_addr, const uint8 *code_end_addr, - uint8 block_type, + uint8 label_type, uint8 **p_else_addr, uint8 **p_end_addr, char *error_buf, @@ -2977,8 +2992,20 @@ wasm_loader_find_block_addr(BlockAddr *block_addr_cache, block_nested_depth++; break; + case EXT_OP_BLOCK: + case EXT_OP_LOOP: + case EXT_OP_IF: + /* block type */ + skip_leb_uint32(p, p_end); + if (block_nested_depth < sizeof(block_stack)/sizeof(BlockAddr)) { + block_stack[block_nested_depth].start_addr = p; + block_stack[block_nested_depth].else_addr = NULL; + } + block_nested_depth++; + break; + case WASM_OP_ELSE: - if (block_type == BLOCK_TYPE_IF && block_nested_depth == 1) + if (label_type == LABEL_TYPE_IF && block_nested_depth == 1) else_addr = (uint8*)(p - 1); if (block_nested_depth - 1 < sizeof(block_stack)/sizeof(BlockAddr)) block_stack[block_nested_depth - 1].else_addr = (uint8*)(p - 1); @@ -2986,7 +3013,7 @@ wasm_loader_find_block_addr(BlockAddr *block_addr_cache, case WASM_OP_END: if (block_nested_depth == 1) { - if (block_type == BLOCK_TYPE_IF) + if (label_type == LABEL_TYPE_IF) *p_else_addr = else_addr; *p_end_addr = (uint8*)(p - 1); @@ -3324,8 +3351,8 @@ typedef struct BranchBlockPatch { #endif typedef struct BranchBlock { - uint8 block_type; - uint8 return_type; + uint8 label_type; + BlockType block_type; uint8 *start_addr; uint8 *else_addr; uint8 *end_addr; @@ -3334,6 +3361,8 @@ typedef struct BranchBlock { uint16 dynamic_offset; uint8 *code_compiled; BranchBlockPatch *patch_list; + /* This is used to save params frame_offset of of if block */ + int16 *param_frame_offsets; #endif /* Indicate the operand stack is in polymorphic state. @@ -3710,14 +3739,14 @@ wasm_loader_push_pop_frame_ref(WASMLoaderContext *ctx, uint8 pop_cnt, } static bool -wasm_loader_push_frame_csp(WASMLoaderContext *ctx, uint8 type, - uint8 ret_type, uint8* start_addr, +wasm_loader_push_frame_csp(WASMLoaderContext *ctx, uint8 label_type, + BlockType block_type, uint8* start_addr, char *error_buf, uint32 error_buf_size) { CHECK_CSP_PUSH(); memset(ctx->frame_csp, 0, sizeof(BranchBlock)); - ctx->frame_csp->block_type = type; - ctx->frame_csp->return_type = ret_type; + ctx->frame_csp->label_type = label_type; + ctx->frame_csp->block_type = block_type; ctx->frame_csp->start_addr = start_addr; ctx->frame_csp->stack_cell_num = ctx->stack_cell_num; #if WASM_ENABLE_FAST_INTERP != 0 @@ -3738,45 +3767,18 @@ wasm_loader_pop_frame_csp(WASMLoaderContext *ctx, char *error_buf, uint32 error_buf_size) { CHECK_CSP_POP(); +#if WASM_ENABLE_FAST_INTERP != 0 + if ((ctx->frame_csp - 1)->param_frame_offsets) + wasm_runtime_free((ctx->frame_csp - 1)->param_frame_offsets); +#endif ctx->frame_csp--; ctx->csp_num--; + return true; fail: return false; } -static bool -wasm_loader_check_br(WASMLoaderContext *ctx, uint32 depth, - char *error_buf, uint32 error_buf_size) -{ - BranchBlock *target_block, *cur_block; - int32 available_stack_cell; - - if (ctx->csp_num < depth + 1) { - set_error_buf(error_buf, error_buf_size, - "WASM module load failed: unknown label, " - "unexpected end of section or function"); - return false; - } - - target_block = ctx->frame_csp - (depth + 1); - cur_block = ctx->frame_csp - 1; - - available_stack_cell = (int32) - (ctx->stack_cell_num - cur_block->stack_cell_num); - - if (available_stack_cell <= 0 && target_block->is_stack_polymorphic) - return true; - - if (target_block->block_type != BLOCK_TYPE_LOOP) { - uint8 type = target_block->return_type; - if (!check_stack_top_values(ctx->frame_ref, available_stack_cell, - type, error_buf, error_buf_size)) - return false; - } - return true; -} - #if WASM_ENABLE_FAST_INTERP != 0 #if WASM_ENABLE_ABS_LABEL_ADDR != 0 @@ -4101,24 +4103,61 @@ static bool wasm_loader_emit_br_info(WASMLoaderContext *ctx, BranchBlock *frame_csp, char *error_buf, uint32 error_buf_size) { - emit_operand(ctx, frame_csp->dynamic_offset); - if (frame_csp->block_type == BLOCK_TYPE_LOOP || - frame_csp->return_type == VALUE_TYPE_VOID) { - emit_byte(ctx, 0); - emit_operand(ctx, 0); - } - else if (frame_csp->return_type == VALUE_TYPE_I32 - || frame_csp->return_type == VALUE_TYPE_F32) { - emit_byte(ctx, 1); - emit_operand(ctx, *(int16*)(ctx->frame_offset - 1)); - } - else if (frame_csp->return_type == VALUE_TYPE_I64 - || frame_csp->return_type == VALUE_TYPE_F64) { - emit_byte(ctx, 2); - emit_operand(ctx, *(int16*)(ctx->frame_offset - 2)); + /* br info layout: + * a) arity of target block + * b) total cell num of arity values + * c) each arity value's cell num + * d) each arity value's src frame offset + * e) each arity values's dst dynamic offset + * f) branch target address + * + * Note: b-e are omitted when arity is 0 so that + * interpreter can recover the br info quickly. + */ + BlockType *block_type = &frame_csp->block_type; + uint8 *types = NULL, cell; + uint32 arity = 0; + int32 i; + int16 *frame_offset = ctx->frame_offset; + uint16 dynamic_offset; + + /* Note: loop's arity is different from if and block. loop's arity is + * its parameter count while if and block arity is result count. + */ + if (frame_csp->label_type == LABEL_TYPE_LOOP) + arity = block_type_get_param_types(block_type, &types); + else + arity = block_type_get_result_types(block_type, &types); + + /* Part a */ + emit_uint32(ctx, arity); + + if (arity) { + /* Part b */ + emit_uint32(ctx, wasm_get_cell_num(types, arity)); + /* Part c */ + for (i = (int32)arity - 1; i >= 0; i--) { + cell = wasm_value_type_cell_num(types[i]); + emit_byte(ctx, cell); + } + /* Part d */ + for (i = (int32)arity - 1; i >= 0; i--) { + cell = wasm_value_type_cell_num(types[i]); + frame_offset -= cell; + emit_operand(ctx, *(int16*)(frame_offset)); + } + /* Part e */ + dynamic_offset = frame_csp->dynamic_offset + + wasm_get_cell_num(types, arity); + for (i = (int32)arity - 1; i >= 0; i--) { + cell = wasm_value_type_cell_num(types[i]); + dynamic_offset -= cell; + emit_operand(ctx, dynamic_offset); + } } - if (frame_csp->block_type == BLOCK_TYPE_LOOP) { + /* Part f */ + if (frame_csp->label_type == LABEL_TYPE_LOOP) { wasm_loader_emit_ptr(ctx, frame_csp->code_compiled); } else { @@ -4129,6 +4168,7 @@ wasm_loader_emit_br_info(WASMLoaderContext *ctx, BranchBlock *frame_csp, /* label address, to be patched */ wasm_loader_emit_ptr(ctx, NULL); } + return true; } @@ -4521,50 +4561,143 @@ fail: #if WASM_ENABLE_FAST_INTERP != 0 static bool -reserve_block_ret(WASMLoaderContext *loader_ctx, uint8 opcode, bool disable_emit, +reserve_block_ret(WASMLoaderContext *loader_ctx, + uint8 opcode, bool disable_emit, char *error_buf, uint32 error_buf_size) { int16 operand_offset = 0; - uint8 block_depth = 0; - if (opcode == WASM_OP_ELSE) - block_depth = 1; - else - block_depth = 0; + BranchBlock *block = (opcode == WASM_OP_ELSE) ? + loader_ctx->frame_csp - 1 : loader_ctx->frame_csp; + BlockType *block_type = &block->block_type; + uint8 *return_types = NULL; + uint32 return_count = 0, value_count = 0, total_cel_num = 0; + int32 i = 0; + int16 dynamic_offset, dynamic_offset_org, + *frame_offset = NULL, *frame_offset_org = NULL; - if ((loader_ctx->frame_csp - block_depth)->return_type != VALUE_TYPE_VOID) { - uint8 return_cells; - if ((loader_ctx->frame_csp - block_depth)->return_type == VALUE_TYPE_I32 - || (loader_ctx->frame_csp - block_depth)->return_type == VALUE_TYPE_F32) - return_cells = 1; - else - return_cells = 2; - if ((loader_ctx->frame_csp - block_depth)->dynamic_offset != - *(loader_ctx->frame_offset - return_cells)) { + return_count = block_type_get_result_types(block_type, &return_types); + /* If there is only one return value, use EXT_OP_COPY_STACK_TOP/_I64 instead + * of EXT_OP_COPY_STACK_VALUES for interpreter performance. */ + if (return_count == 1) { + uint8 cell = wasm_value_type_cell_num(return_types[0]); + if (block->dynamic_offset != *(loader_ctx->frame_offset - cell)) { /* insert op_copy before else opcode */ if (opcode == WASM_OP_ELSE) skip_label(); - - if (return_cells == 1) - emit_label(EXT_OP_COPY_STACK_TOP); - else - emit_label(EXT_OP_COPY_STACK_TOP_I64); - emit_operand(loader_ctx, *(loader_ctx->frame_offset - return_cells)); - emit_operand(loader_ctx, (loader_ctx->frame_csp - block_depth)->dynamic_offset); + emit_label(cell == 1 ? EXT_OP_COPY_STACK_TOP : EXT_OP_COPY_STACK_TOP_I64); + emit_operand(loader_ctx, *(loader_ctx->frame_offset - cell)); + emit_operand(loader_ctx, block->dynamic_offset); if (opcode == WASM_OP_ELSE) { - *(loader_ctx->frame_offset - return_cells) = - (loader_ctx->frame_csp - block_depth)->dynamic_offset; + *(loader_ctx->frame_offset - cell) = block->dynamic_offset; } else { - loader_ctx->frame_offset -= return_cells; - loader_ctx->dynamic_offset = loader_ctx->frame_csp->dynamic_offset; - PUSH_OFFSET_TYPE((loader_ctx->frame_csp - block_depth)->return_type); + loader_ctx->frame_offset -= cell; + loader_ctx->dynamic_offset = block->dynamic_offset; + PUSH_OFFSET_TYPE(return_types[0]); wasm_loader_emit_backspace(loader_ctx, sizeof(int16)); } if (opcode == WASM_OP_ELSE) emit_label(opcode); } + return true; + } + + /* Copy stack top values to block's results which are in dynamic space. + * The instruction format: + * Part a: values count + * Part b: all values total cell num + * Part c: each value's cell_num, src offset and dst offset + * Part d: each value's src offset and dst offset + * Part e: each value's dst offset + */ + frame_offset = frame_offset_org = loader_ctx->frame_offset; + dynamic_offset = dynamic_offset_org = + block->dynamic_offset + + wasm_get_cell_num(return_types, return_count); + + /* First traversal to get the count of values needed to be copied. */ + for (i = (int32)return_count - 1; i >= 0; i--) { + uint8 cells = wasm_value_type_cell_num(return_types[i]); + + frame_offset -= cells; + dynamic_offset -= cells; + if (dynamic_offset != *frame_offset) { + value_count++; + total_cel_num += cells; + } + } + + if (value_count) { + uint32 j = 0; + uint8 *emit_data = NULL, *cells = NULL; + int16 *src_offsets = NULL; + uint16 *dst_offsets = NULL; + uint64 size = (uint64)value_count * (sizeof(*cells) + + sizeof(*src_offsets) + + sizeof(*dst_offsets)); + + /* Allocate memory for the emit data */ + if (!(emit_data = loader_malloc(size, error_buf, error_buf_size))) + return false; + + cells = emit_data; + src_offsets = (int16 *)(cells + value_count); + dst_offsets = (uint16 *)(src_offsets + value_count); + + /* insert op_copy before else opcode */ + if (opcode == WASM_OP_ELSE) + skip_label(); + emit_label(EXT_OP_COPY_STACK_VALUES); + /* Part a) */ + emit_uint32(loader_ctx, value_count); + /* Part b) */ + emit_uint32(loader_ctx, total_cel_num); + + /* Second traversal to get each value's cell num, src offset and dst offset. */ + frame_offset = frame_offset_org; + dynamic_offset = dynamic_offset_org; + for (i = (int32)return_count - 1, j = 0; i >= 0; i--) { + uint8 cell = wasm_value_type_cell_num(return_types[i]); + frame_offset -= cell; + dynamic_offset -= cell; + if (dynamic_offset != *frame_offset) { + /* cell num */ + cells[j] = cell; + /* src offset */ + src_offsets[j] = *frame_offset; + /* dst offset */ + dst_offsets[j] = dynamic_offset; + j++; + } + if (opcode == WASM_OP_ELSE) { + *frame_offset = dynamic_offset; + } + else { + loader_ctx->frame_offset = frame_offset; + loader_ctx->dynamic_offset = dynamic_offset; + PUSH_OFFSET_TYPE(return_types[i]); + wasm_loader_emit_backspace(loader_ctx, sizeof(int16)); + loader_ctx->frame_offset = frame_offset_org; + loader_ctx->dynamic_offset = dynamic_offset_org; + } + } + + bh_assert(j == value_count); + + /* Emit the cells, src_offsets and dst_offsets */ + for (j = 0; j < value_count; j++) + emit_byte(loader_ctx, cells[j]); + for (j = 0; j < value_count; j++) + emit_operand(loader_ctx, src_offsets[j]); + for (j = 0; j < value_count; j++) + emit_operand(loader_ctx, dst_offsets[j]); + + if (opcode == WASM_OP_ELSE) + emit_label(opcode); + + wasm_runtime_free(emit_data); } return true; @@ -4572,7 +4705,6 @@ reserve_block_ret(WASMLoaderContext *loader_ctx, uint8 opcode, bool disable_emit fail: return false; } - #endif /* WASM_ENABLE_FAST_INTERP */ #define RESERVE_BLOCK_RET() do { \ @@ -4593,11 +4725,11 @@ fail: goto fail; \ } while (0) -#define PUSH_CSP(type, ret_type, _start_addr) do { \ - if (!wasm_loader_push_frame_csp(loader_ctx, type, ret_type, \ - _start_addr, error_buf, \ - error_buf_size)) \ - goto fail; \ +#define PUSH_CSP(label_type, block_type, _start_addr) do { \ + if (!wasm_loader_push_frame_csp(loader_ctx, label_type, block_type, \ + _start_addr, error_buf, \ + error_buf_size)) \ + goto fail; \ } while (0) #define POP_CSP() do { \ @@ -4663,7 +4795,7 @@ check_memory_access_align(uint8 opcode, uint32 align, } static bool -is_block_type_valid(uint8 type) +is_value_type(uint8 type) { return type == VALUE_TYPE_I32 || type == VALUE_TYPE_I64 || @@ -4672,13 +4804,77 @@ is_block_type_valid(uint8 type) type == VALUE_TYPE_VOID; } -#define CHECK_BLOCK_TYPE(type) do { \ - if (!is_block_type_valid(type)) { \ - set_error_buf(error_buf, error_buf_size, \ - "WASM module load failed: invalid block type"); \ - goto fail; \ - } \ - } while (0) +static bool +wasm_loader_check_br(WASMLoaderContext *loader_ctx, uint32 depth, + char *error_buf, uint32 error_buf_size) +{ + BranchBlock *target_block, *cur_block; + BlockType *target_block_type; + uint8 *types = NULL, *frame_ref; + uint32 arity = 0; + int32 i, available_stack_cell; + uint16 cell_num; + + if (loader_ctx->csp_num < depth + 1) { + set_error_buf(error_buf, error_buf_size, + "WASM module load failed: unknown label, " + "unexpected end of section or function"); + return false; + } + + cur_block = loader_ctx->frame_csp - 1; + target_block = loader_ctx->frame_csp - (depth + 1); + target_block_type = &target_block->block_type; + frame_ref = loader_ctx->frame_ref; + + /* Note: loop's arity is different from if and block. loop's arity is + * its parameter count while if and block arity is result count. + */ + if (target_block->label_type == LABEL_TYPE_LOOP) + arity = block_type_get_param_types(target_block_type, &types); + else + arity = block_type_get_result_types(target_block_type, &types); + + /* If the stack is in polymorphic state, just clear the stack + * and then re-push the values to make the stack top values + * match block type. */ + if (cur_block->is_stack_polymorphic) { + for (i = (int32)arity -1; i >= 0; i--) { +#if WASM_ENABLE_FAST_INTERP != 0 + POP_OFFSET_TYPE(types[i]); +#endif + POP_TYPE(types[i]); + } + for (i = 0; i < (int32)arity; i++) { +#if WASM_ENABLE_FAST_INTERP != 0 + bool disable_emit = true; + int16 operand_offset = 0; + PUSH_OFFSET_TYPE(types[i]); +#endif + PUSH_TYPE(types[i]); + } + return true; + } + + available_stack_cell = (int32) + (loader_ctx->stack_cell_num - cur_block->stack_cell_num); + + /* Check stack top values match target block type */ + for (i = (int32)arity -1; i >= 0; i--) { + if (!check_stack_top_values(frame_ref, available_stack_cell, + types[i], + error_buf, error_buf_size)) + return false; + cell_num = wasm_value_type_cell_num(types[i]); + frame_ref -= cell_num; + available_stack_cell -= cell_num; + } + + return true; + +fail: + return false; +} static BranchBlock * check_branch_block(WASMLoaderContext *loader_ctx, @@ -4703,94 +4899,174 @@ fail: } static bool -check_branch_block_ret(WASMLoaderContext *loader_ctx, - BranchBlock *frame_csp_tmp, - char *error_buf, uint32 error_buf_size) +check_block_stack(WASMLoaderContext *loader_ctx, BranchBlock *block, + char *error_buf, uint32 error_buf_size) { + BlockType *block_type = &block->block_type; + uint8 *return_types = NULL; + uint32 return_count = 0; + int32 available_stack_cell, return_cell_num, i; + uint8 *frame_ref = NULL; + + available_stack_cell = (int32) + (loader_ctx->stack_cell_num + - block->stack_cell_num); + + return_count = block_type_get_result_types(block_type, &return_types); + return_cell_num = return_count > 0 ? + wasm_get_cell_num(return_types, return_count) : 0; + + /* If the stack is in polymorphic state, just clear the stack + * and then re-push the values to make the stack top values + * match block type. */ + if (block->is_stack_polymorphic) { + for (i = (int32)return_count -1; i >= 0; i--) { #if WASM_ENABLE_FAST_INTERP != 0 - BranchBlock *cur_block = loader_ctx->frame_csp - 1; - bool disable_emit = true; - int16 operand_offset = 0; + POP_OFFSET_TYPE(return_types[i]); #endif - if (frame_csp_tmp->block_type != BLOCK_TYPE_LOOP) { - uint8 block_return_type = frame_csp_tmp->return_type; -#if WASM_ENABLE_FAST_INTERP != 0 - /* If the stack is in polymorphic state, do fake pop and push on - offset stack to keep the depth of offset stack to be the same - with ref stack */ - if (cur_block->is_stack_polymorphic) { - POP_OFFSET_TYPE(block_return_type); - PUSH_OFFSET_TYPE(block_return_type); + POP_TYPE(return_types[i]); } + + /* Check stack is empty */ + if (loader_ctx->stack_cell_num != block->stack_cell_num) { + set_error_buf(error_buf, error_buf_size, + "WASM module load failed: " + "type mismatch: stack size does not match block type"); + goto fail; + } + + for (i = 0; i < (int32)return_count; i++) { +#if WASM_ENABLE_FAST_INTERP != 0 + bool disable_emit = true; + int16 operand_offset = 0; + PUSH_OFFSET_TYPE(return_types[i]); #endif - POP_TYPE(block_return_type); - PUSH_TYPE(block_return_type); + PUSH_TYPE(return_types[i]); + } + return true; } + + /* Check stack cell num equals return cell num */ + if (available_stack_cell != return_cell_num) { + set_error_buf(error_buf, error_buf_size, + "WASM module load failed: " + "type mismatch: stack size does not match block type"); + goto fail; + } + + /* Check stack values match return types */ + frame_ref = loader_ctx->frame_ref; + for (i = (int32)return_count -1; i >= 0; i--) { + if (!check_stack_top_values(frame_ref, available_stack_cell, + return_types[i], + error_buf, error_buf_size)) + return false; + frame_ref -= wasm_value_type_cell_num(return_types[i]); + available_stack_cell -= wasm_value_type_cell_num(return_types[i]); + } + return true; + fail: return false; } +#if WASM_ENABLE_FAST_INTERP != 0 +/* Copy parameters to dynamic space. + * 1) POP original parameter out; + * 2) Push and copy original values to dynamic space. + * The copy instruction format: + * Part a: param count + * Part b: all param total cell num + * Part c: each param's cell_num, src offset and dst offset + * Part d: each param's src offset + * Part e: each param's dst offset + */ static bool -check_block_stack(WASMLoaderContext *ctx, BranchBlock *block, - char *error_buf, uint32 error_buf_size) +copy_params_to_dynamic_space(WASMLoaderContext *loader_ctx, bool is_if_block, + char* error_buf, uint32 error_buf_size) { - uint8 type = block->return_type; - int32 available_stack_cell = (int32) - (ctx->stack_cell_num - block->stack_cell_num); + int16 *frame_offset = NULL; + uint8 *cells = NULL, cell; + int16 *src_offsets = NULL; + uint8 *emit_data = NULL; + uint32 i; + BranchBlock *block = loader_ctx->frame_csp - 1; + BlockType *block_type = &block->block_type; + WASMType *wasm_type = block_type->u.type; + uint32 param_count = block_type->u.type->param_count; + int16 condition_offset = 0; + bool disable_emit = false; + int16 operand_offset = 0; - if (type != VALUE_TYPE_VOID - && available_stack_cell <= 0 - && block->is_stack_polymorphic) { - if (!(wasm_loader_push_frame_ref(ctx, type, error_buf, error_buf_size)) -#if WASM_ENABLE_FAST_INTERP != 0 - || !(wasm_loader_push_frame_offset(ctx, type, true, 0, error_buf, error_buf_size)) -#endif - ) - return false; - return true; - } + uint64 size = (uint64)param_count * (sizeof(*cells) + + sizeof(*src_offsets)); - if (type != VALUE_TYPE_VOID - && available_stack_cell == 1 - && *(ctx->frame_ref - 1) == VALUE_TYPE_ANY) { - if (type == VALUE_TYPE_I32 || type == VALUE_TYPE_F32) { - /* If the stack top is a value of any type, change its type to the - * same as block return type and return success */ - *(ctx->frame_ref - 1) = type; - } - else { - if (!(wasm_loader_push_frame_ref(ctx, VALUE_TYPE_I32, - error_buf, error_buf_size)) -#if WASM_ENABLE_FAST_INTERP != 0 - || !(wasm_loader_push_frame_offset(ctx, VALUE_TYPE_I32, - true, 0, - error_buf, error_buf_size)) -#endif - ) - return false; - *(ctx->frame_ref - 1) = *(ctx->frame_ref - 2) = type; - } - return true; - } + /* For if block, we also need copy the condition operand offset. */ + if (is_if_block) + size += sizeof(*cells) + sizeof(*src_offsets); - if (((type == VALUE_TYPE_I32 || type == VALUE_TYPE_F32) - && available_stack_cell != 1) - || ((type == VALUE_TYPE_I64 || type == VALUE_TYPE_F64) - && available_stack_cell != 2) - || (type == VALUE_TYPE_VOID && available_stack_cell > 0)) { - set_error_buf(error_buf, error_buf_size, - "WASM module load failed: " - "type mismatch: stack size does not match block type"); + /* Allocate memory for the emit data */ + if (!(emit_data = loader_malloc(size, error_buf, error_buf_size))) return false; + + cells = emit_data; + src_offsets = (int16 *)(cells + param_count); + + if (is_if_block) + condition_offset = *loader_ctx->frame_offset; + + /* POP original parameter out */ + for (i = 0; i < param_count; i++) { + POP_OFFSET_TYPE(wasm_type->types[param_count - i - 1]); + wasm_loader_emit_backspace(loader_ctx, sizeof(int16)); + } + frame_offset = loader_ctx->frame_offset; + + /* Get each param's cell num and src offset */ + for (i = 0; i < param_count; i++) { + cell = wasm_value_type_cell_num(wasm_type->types[i]); + cells[i] = cell; + src_offsets[i] = *frame_offset; + frame_offset += cell; } - if (!check_stack_top_values(ctx->frame_ref, available_stack_cell, - type, error_buf, error_buf_size)) - return false; + /* emit copy instruction */ + emit_label(EXT_OP_COPY_STACK_VALUES); + /* Part a) */ + emit_uint32(loader_ctx, is_if_block ? param_count + 1 : param_count); + /* Part b) */ + emit_uint32(loader_ctx, is_if_block ? + wasm_type->param_cell_num + 1 : + wasm_type->param_cell_num); + /* Part c) */ + for (i = 0; i < param_count; i++) + emit_byte(loader_ctx, cells[i]); + if (is_if_block) + emit_byte(loader_ctx, 1); + + /* Part d) */ + for (i = 0; i < param_count; i++) + emit_operand(loader_ctx, src_offsets[i]); + if (is_if_block) + emit_operand(loader_ctx, condition_offset); + + /* Part e) */ + /* Push to dynamic space. The push will emit the dst offset. */ + for (i = 0; i < param_count; i++) + PUSH_OFFSET_TYPE(wasm_type->types[i]); + if (is_if_block) + PUSH_OFFSET_TYPE(VALUE_TYPE_I32); + + /* Free the emit data */ + wasm_runtime_free(emit_data); return true; + +fail: + return false; } +#endif /* reset the stack to the state of before entering the last block */ #if WASM_ENABLE_FAST_INTERP != 0 @@ -4817,6 +5093,9 @@ check_block_stack(WASMLoaderContext *ctx, BranchBlock *block, cur_block->is_stack_polymorphic = flag; \ } while (0) +#define BLOCK_HAS_PARAM(block_type) \ + (!block_type.is_value_type && block_type.u.type->param_count > 0) + static bool wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, BlockAddr *block_addr_cache, @@ -4824,12 +5103,13 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, { uint8 *p = func->code, *p_end = func->code + func->code_size, *p_org; uint32 param_count, local_count, global_count; - uint8 *param_types, ret_type, *local_types, local_type, global_type; + uint8 *param_types, *local_types, local_type, global_type; + BlockType func_type; uint16 *local_offsets, local_offset; uint32 count, i, local_idx, global_idx, u32, align, mem_offset; int32 i32, i32_const = 0; int64 i64; - uint8 opcode, u8, block_return_type; + uint8 opcode, u8; bool return_value = false; WASMLoaderContext *loader_ctx; BranchBlock *frame_csp_tmp; @@ -4854,8 +5134,9 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, param_count = func->func_type->param_count; param_types = func->func_type->types; - ret_type = func->func_type->result_count - ? param_types[param_count] : VALUE_TYPE_VOID; + + func_type.is_value_type = false; + func_type.u.type = func->func_type; local_count = func->local_count; local_types = func->local_types; @@ -4882,7 +5163,7 @@ re_scan: } #endif - PUSH_CSP(BLOCK_TYPE_FUNCTION, ret_type, p); + PUSH_CSP(LABEL_TYPE_FUNCTION, func_type, p); while (p < p_end) { opcode = *p++; @@ -4904,43 +5185,142 @@ re_scan: #endif break; - case WASM_OP_BLOCK: - /* 0x40/0x7F/0x7E/0x7D/0x7C */ - block_return_type = read_uint8(p); - CHECK_BLOCK_TYPE(block_return_type); - PUSH_CSP(BLOCK_TYPE_BLOCK, block_return_type, p); -#if WASM_ENABLE_FAST_INTERP != 0 - skip_label(); -#endif - break; - - case WASM_OP_LOOP: - /* 0x40/0x7F/0x7E/0x7D/0x7C */ - block_return_type = read_uint8(p); - CHECK_BLOCK_TYPE(block_return_type); - PUSH_CSP(BLOCK_TYPE_LOOP, block_return_type, p); -#if WASM_ENABLE_FAST_INTERP != 0 - skip_label(); - (loader_ctx->frame_csp - 1)->code_compiled = - loader_ctx->p_code_compiled; -#endif - break; - case WASM_OP_IF: POP_I32(); - /* 0x40/0x7F/0x7E/0x7D/0x7C */ - block_return_type = read_uint8(p); - CHECK_BLOCK_TYPE(block_return_type); - PUSH_CSP(BLOCK_TYPE_IF, block_return_type, p); + goto handle_op_block_and_loop; + case WASM_OP_BLOCK: + case WASM_OP_LOOP: +handle_op_block_and_loop: + { + uint8 value_type; + BlockType block_type; + + value_type = read_uint8(p); + if (is_value_type(value_type)) { + /* If the first byte is one of these special values: + * 0x40/0x7F/0x7E/0x7D/0x7C, take it as the type of + * the single return value. */ + block_type.is_value_type = true; + block_type.u.value_type = value_type; + } + else { + uint32 type_index; + /* Resolve the leb128 encoded type index as block type */ + p--; + read_leb_uint32(p, p_end, type_index); + if (type_index >= module->type_count) { + set_error_buf(error_buf, error_buf_size, + "WASM loader prepare bytecode failed: " + "unknown type"); + goto fail; + } + block_type.is_value_type = false; + block_type.u.type = module->types[type_index]; +#if WASM_ENABLE_FAST_INTERP == 0 \ + && WASM_ENABLE_WAMR_COMPILER == 0 \ + && WASM_ENABLE_JIT == 0 + /* If block use type index as block type, change the opcode + * to new extended opcode so that interpreter can resolve the + * block quickly. + */ + *(p - 2) = EXT_OP_BLOCK + (opcode - WASM_OP_BLOCK); +#endif + } + + /* Pop block parameters from stack */ + if (BLOCK_HAS_PARAM(block_type)) { + WASMType *wasm_type = block_type.u.type; + for (i = 0; i < block_type.u.type->param_count; i++) + POP_TYPE(wasm_type->types[wasm_type->param_count - i - 1]); + } + + PUSH_CSP(LABEL_TYPE_BLOCK + (opcode - WASM_OP_BLOCK), block_type, p); + + /* Pass parameters to block */ + if (BLOCK_HAS_PARAM(block_type)) { + for (i = 0; i < block_type.u.type->param_count; i++) + PUSH_TYPE(block_type.u.type->types[i]); + } + #if WASM_ENABLE_FAST_INTERP != 0 - emit_empty_label_addr_and_frame_ip(PATCH_ELSE); - emit_empty_label_addr_and_frame_ip(PATCH_END); + if (opcode == WASM_OP_BLOCK) { + skip_label(); + } else if (opcode == WASM_OP_LOOP) { + skip_label(); + if (BLOCK_HAS_PARAM(block_type)) { + /* Make sure params are in dynamic space */ + if (!copy_params_to_dynamic_space(loader_ctx, + false, + error_buf, + error_buf_size)) + goto fail; + } + (loader_ctx->frame_csp - 1)->code_compiled = + loader_ctx->p_code_compiled; + } else if (opcode == WASM_OP_IF) { + /* If block has parameters, we should make sure they are in + * dynamic space. Otherwise, when else branch is missing, + * the later opcode may consume incorrect operand offset. + * Spec case: + * (func (export "params-id") (param i32) (result i32) + * (i32.const 1) + * (i32.const 2) + * (if (param i32 i32) (result i32 i32) (local.get 0) (then)) + * (i32.add) + * ) + * + * So we should emit a copy instruction before the if. + * + * And we also need to save the parameter offsets and + * recover them before entering else branch. + * + */ + if (BLOCK_HAS_PARAM(block_type)) { + BranchBlock *block = loader_ctx->frame_csp - 1; + uint64 size; + + /* skip the if condition operand offset */ + wasm_loader_emit_backspace(loader_ctx, sizeof(int16)); + /* skip the if label */ + skip_label(); + /* Emit a copy instruction */ + if (!copy_params_to_dynamic_space(loader_ctx, + true, + error_buf, + error_buf_size)) + goto fail; + + /* Emit the if instruction */ + emit_label(opcode); + /* Emit the new condition operand offset */ + POP_OFFSET_TYPE(VALUE_TYPE_I32); + + /* Save top param_count values of frame_offset stack, so that + * we can recover it before executing else branch */ + size = sizeof(int16) * + (uint64)block_type.u.type->param_cell_num; + if (!(block->param_frame_offsets = + loader_malloc(size, error_buf, error_buf_size))) + goto fail; + bh_memcpy_s(block->param_frame_offsets, + size, + loader_ctx->frame_offset - size/sizeof(int16), + size); + } + + emit_empty_label_addr_and_frame_ip(PATCH_ELSE); + emit_empty_label_addr_and_frame_ip(PATCH_END); + } #endif break; + } case WASM_OP_ELSE: + { + BlockType block_type = (loader_ctx->frame_csp - 1)->block_type; + if (loader_ctx->csp_num < 2 - || (loader_ctx->frame_csp - 1)->block_type != BLOCK_TYPE_IF) { + || (loader_ctx->frame_csp - 1)->label_type != LABEL_TYPE_IF) { set_error_buf(error_buf, error_buf_size, "WASM loader prepare bytecode failed: " "opcode else found without matched opcode if"); @@ -4963,25 +5343,63 @@ re_scan: #endif RESET_STACK(); SET_CUR_BLOCK_STACK_POLYMORPHIC_STATE(false); + + /* Pass parameters to if-false branch */ + if (BLOCK_HAS_PARAM(block_type)) { + for (i = 0; i < block_type.u.type->param_count; i++) + PUSH_TYPE(block_type.u.type->types[i]); + } + +#if WASM_ENABLE_FAST_INTERP != 0 + /* Recover top param_count values of frame_offset stack */ + if (BLOCK_HAS_PARAM((block_type))) { + uint32 size; + BranchBlock *block = loader_ctx->frame_csp - 1; + size = sizeof(int16) * + block_type.u.type->param_cell_num; + bh_memcpy_s(loader_ctx->frame_offset, size, + block->param_frame_offsets, size); + loader_ctx->frame_offset += (size/sizeof(int16)); + } +#endif + break; + } case WASM_OP_END: { + BranchBlock *cur_block = loader_ctx->frame_csp - 1; /* check whether block stack matches its result type */ - if (!check_block_stack(loader_ctx, loader_ctx->frame_csp - 1, + if (!check_block_stack(loader_ctx, cur_block, error_buf, error_buf_size)) goto fail; - /* if has return value, but no else branch, fail */ - if ((loader_ctx->frame_csp - 1)->block_type == BLOCK_TYPE_IF - && (loader_ctx->frame_csp - 1)->return_type != VALUE_TYPE_VOID - && !(loader_ctx->frame_csp - 1)->else_addr) { - set_error_buf(error_buf, error_buf_size, - "WASM module load failed: " - "type mismatch: if has return value and else is missing"); - - goto fail; + /* if no else branch, and return types do not match param types, fail */ + if (cur_block->label_type == LABEL_TYPE_IF + && !cur_block->else_addr) { + uint32 param_count = 0, ret_count = 0; + uint8 *param_types = NULL, *ret_types = NULL; + BlockType *block_type = &cur_block->block_type; + if (block_type->is_value_type) { + if (block_type->u.value_type != VALUE_TYPE_VOID) { + ret_count = 1; + ret_types = &block_type->u.value_type; + } + } + else { + param_count = block_type->u.type->param_count; + ret_count = block_type->u.type->result_count; + param_types = block_type->u.type->types; + ret_types = block_type->u.type->types + param_count; + } + if (param_count != ret_count + || (param_count && memcmp(param_types, ret_types, param_count))) { + set_error_buf(error_buf, error_buf_size, + "WASM module load failed: " + "type mismatch: else branch missing"); + goto fail; + } } POP_CSP(); @@ -4993,9 +5411,17 @@ re_scan: apply_label_patch(loader_ctx, 0, PATCH_END); free_label_patch_list(loader_ctx->frame_csp); - if (loader_ctx->frame_csp->block_type == BLOCK_TYPE_FUNCTION) { + if (loader_ctx->frame_csp->label_type == LABEL_TYPE_FUNCTION) { + int32 idx; + uint8 ret_type; + emit_label(WASM_OP_RETURN); - POP_OFFSET_TYPE(loader_ctx->frame_csp->return_type); + for (idx = (int32)func->func_type->result_count - 1; + idx >= 0; idx--) { + ret_type = *(func->func_type->types + + func->func_type->param_count + idx); + POP_OFFSET_TYPE(ret_type); + } } #endif if (loader_ctx->csp_num > 0) { @@ -5019,10 +5445,6 @@ re_scan: error_buf, error_buf_size))) goto fail; - if (!check_branch_block_ret(loader_ctx, frame_csp_tmp, - error_buf, error_buf_size)) - goto fail; - RESET_STACK(); SET_CUR_BLOCK_STACK_POLYMORPHIC_STATE(true); break; @@ -5036,16 +5458,13 @@ re_scan: error_buf, error_buf_size))) goto fail; - if (!check_branch_block_ret(loader_ctx, frame_csp_tmp, - error_buf, error_buf_size)) - goto fail; - break; } case WASM_OP_BR_TABLE: { - uint8 ret_type; + uint8 *ret_types = NULL; + uint32 ret_count = 0; read_leb_uint32(p, p_end, count); #if WASM_ENABLE_FAST_INTERP != 0 @@ -5055,23 +5474,30 @@ re_scan: /* TODO: check the const */ for (i = 0; i <= count; i++) { - if (!(frame_csp_tmp = check_branch_block(loader_ctx, &p, p_end, - error_buf, error_buf_size))) - goto fail; - - if (!check_branch_block_ret(loader_ctx, frame_csp_tmp, - error_buf, error_buf_size)) + if (!(frame_csp_tmp = + check_branch_block(loader_ctx, &p, p_end, + error_buf, error_buf_size))) goto fail; if (i == 0) { - ret_type = frame_csp_tmp->block_type == BLOCK_TYPE_LOOP ? - VALUE_TYPE_VOID : frame_csp_tmp->return_type; + if (frame_csp_tmp->label_type != LABEL_TYPE_LOOP) + ret_count = + block_type_get_result_types(&frame_csp_tmp->block_type, + &ret_types); } else { + uint8 *tmp_ret_types = NULL; + uint32 tmp_ret_count = 0; + /* Check whether all table items have the same return type */ - uint8 tmp_ret_type = frame_csp_tmp->block_type == BLOCK_TYPE_LOOP ? - VALUE_TYPE_VOID : frame_csp_tmp->return_type; - if (ret_type != tmp_ret_type) { + if (frame_csp_tmp->label_type != LABEL_TYPE_LOOP) + tmp_ret_count = + block_type_get_result_types(&frame_csp_tmp->block_type, + &tmp_ret_types); + + if (ret_count != tmp_ret_count + || (ret_count + && 0 != memcmp(ret_types, tmp_ret_types, ret_count))) { set_error_buf(error_buf, error_buf_size, "WASM loader prepare bytecode failed: " "type mismatch: br_table targets must " @@ -5088,16 +5514,21 @@ re_scan: case WASM_OP_RETURN: { - POP_TYPE(ret_type); - PUSH_TYPE(ret_type); - + int32 idx; + uint8 ret_type; + for (idx = (int32)func->func_type->result_count - 1; idx >= 0; idx--) { + ret_type = *(func->func_type->types + + func->func_type->param_count + idx); + POP_TYPE(ret_type); #if WASM_ENABLE_FAST_INTERP != 0 - // emit the offset after return opcode - POP_OFFSET_TYPE(ret_type); + // emit the offset after return opcode + POP_OFFSET_TYPE(ret_type); #endif + } RESET_STACK(); SET_CUR_BLOCK_STACK_POLYMORPHIC_STATE(true); + break; } @@ -5135,10 +5566,14 @@ re_scan: } } - if (func_type->result_count) { - PUSH_TYPE(func_type->types[func_type->param_count]); + for (i = 0; i < func_type->result_count; i++) { + PUSH_TYPE(func_type->types[func_type->param_count + i]); #if WASM_ENABLE_FAST_INTERP != 0 - PUSH_OFFSET_TYPE(func_type->types[func_type->param_count]); + /* Here we emit each return value's dynamic_offset. But in fact + * these offsets are continuous, so interpreter only need to get + * the first return value's offset. + */ + PUSH_OFFSET_TYPE(func_type->types[func_type->param_count + i]); #endif } @@ -5194,10 +5629,10 @@ re_scan: } } - if (func_type->result_count > 0) { - PUSH_TYPE(func_type->types[func_type->param_count]); + for (i = 0; i < func_type->result_count; i++) { + PUSH_TYPE(func_type->types[func_type->param_count + i]); #if WASM_ENABLE_FAST_INTERP != 0 - PUSH_OFFSET_TYPE(func_type->types[func_type->param_count]); + PUSH_OFFSET_TYPE(func_type->types[func_type->param_count + i]); #endif } diff --git a/core/iwasm/interpreter/wasm_mini_loader.c b/core/iwasm/interpreter/wasm_mini_loader.c index d969c2203..b56aa720d 100644 --- a/core/iwasm/interpreter/wasm_mini_loader.c +++ b/core/iwasm/interpreter/wasm_mini_loader.c @@ -284,6 +284,7 @@ load_type_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, { const uint8 *p = buf, *p_end = buf_end, *p_org; uint32 type_count, param_count, result_count, i, j; + uint32 param_cell_num, ret_cell_num; uint64 total_size; uint8 flag; WASMType *type; @@ -310,10 +311,11 @@ load_type_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, CHECK_BUF(p, p_end, param_count); p += param_count; read_leb_uint32(p, p_end, result_count); - bh_assert(result_count <= 1); CHECK_BUF(p, p_end, result_count); p = p_org; + bh_assert(param_count <= UINT16_MAX && result_count <= UINT16_MAX); + total_size = offsetof(WASMType, types) + sizeof(uint8) * (uint64)(param_count + result_count); if (!(type = module->types[i] = @@ -322,8 +324,8 @@ load_type_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, } /* Resolve param types and result types */ - type->param_count = param_count; - type->result_count = result_count; + type->param_count = (uint16)param_count; + type->result_count = (uint16)result_count; for (j = 0; j < param_count; j++) { CHECK_BUF(p, p_end, 1); type->types[j] = read_uint8(p); @@ -333,6 +335,13 @@ load_type_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, CHECK_BUF(p, p_end, 1); type->types[param_count + j] = read_uint8(p); } + + param_cell_num = wasm_get_cell_num(type->types, param_count); + ret_cell_num = wasm_get_cell_num(type->types + param_count, + result_count); + bh_assert(param_cell_num <= UINT16_MAX && ret_cell_num <= UINT16_MAX); + type->param_cell_num = (uint16)param_cell_num; + type->ret_cell_num = (uint16)ret_cell_num; } } @@ -953,8 +962,8 @@ load_function_section(const uint8 *buf, const uint8 *buf_end, } } - func->param_cell_num = wasm_type_param_cell_num(func->func_type); - func->ret_cell_num = wasm_type_return_cell_num(func->func_type); + func->param_cell_num = func->func_type->param_cell_num; + func->ret_cell_num = func->func_type->ret_cell_num; func->local_cell_num = wasm_get_cell_num(func->local_types, func->local_count); @@ -1958,7 +1967,7 @@ bool wasm_loader_find_block_addr(BlockAddr *block_addr_cache, const uint8 *start_addr, const uint8 *code_end_addr, - uint8 block_type, + uint8 label_type, uint8 **p_else_addr, uint8 **p_end_addr, char *error_buf, @@ -2006,8 +2015,20 @@ wasm_loader_find_block_addr(BlockAddr *block_addr_cache, block_nested_depth++; break; + case EXT_OP_BLOCK: + case EXT_OP_LOOP: + case EXT_OP_IF: + /* block type */ + skip_leb_uint32(p, p_end); + if (block_nested_depth < sizeof(block_stack)/sizeof(BlockAddr)) { + block_stack[block_nested_depth].start_addr = p; + block_stack[block_nested_depth].else_addr = NULL; + } + block_nested_depth++; + break; + case WASM_OP_ELSE: - if (block_type == BLOCK_TYPE_IF && block_nested_depth == 1) + if (label_type == LABEL_TYPE_IF && block_nested_depth == 1) else_addr = (uint8*)(p - 1); if (block_nested_depth - 1 < sizeof(block_stack)/sizeof(BlockAddr)) block_stack[block_nested_depth - 1].else_addr = (uint8*)(p - 1); @@ -2015,7 +2036,7 @@ wasm_loader_find_block_addr(BlockAddr *block_addr_cache, case WASM_OP_END: if (block_nested_depth == 1) { - if (block_type == BLOCK_TYPE_IF) + if (label_type == LABEL_TYPE_IF) *p_else_addr = else_addr; *p_end_addr = (uint8*)(p - 1); @@ -2347,8 +2368,8 @@ typedef struct BranchBlockPatch { #endif typedef struct BranchBlock { - uint8 block_type; - uint8 return_type; + uint8 label_type; + BlockType block_type; uint8 *start_addr; uint8 *else_addr; uint8 *end_addr; @@ -2357,6 +2378,8 @@ typedef struct BranchBlock { uint16 dynamic_offset; uint8 *code_compiled; BranchBlockPatch *patch_list; + /* This is used to save params frame_offset of of if block */ + int16 *param_frame_offsets; #endif /* Indicate the operand stack is in polymorphic state. @@ -2714,14 +2737,14 @@ wasm_loader_push_pop_frame_ref(WASMLoaderContext *ctx, uint8 pop_cnt, } static bool -wasm_loader_push_frame_csp(WASMLoaderContext *ctx, uint8 type, - uint8 ret_type, uint8* start_addr, +wasm_loader_push_frame_csp(WASMLoaderContext *ctx, uint8 label_type, + BlockType block_type, uint8* start_addr, char *error_buf, uint32 error_buf_size) { CHECK_CSP_PUSH(); memset(ctx->frame_csp, 0, sizeof(BranchBlock)); - ctx->frame_csp->block_type = type; - ctx->frame_csp->return_type = ret_type; + ctx->frame_csp->label_type = label_type; + ctx->frame_csp->block_type = block_type; ctx->frame_csp->start_addr = start_addr; ctx->frame_csp->stack_cell_num = ctx->stack_cell_num; #if WASM_ENABLE_FAST_INTERP != 0 @@ -2742,38 +2765,15 @@ wasm_loader_pop_frame_csp(WASMLoaderContext *ctx, char *error_buf, uint32 error_buf_size) { CHECK_CSP_POP(); +#if WASM_ENABLE_FAST_INTERP != 0 + if ((ctx->frame_csp - 1)->param_frame_offsets) + wasm_runtime_free((ctx->frame_csp - 1)->param_frame_offsets); +#endif ctx->frame_csp--; ctx->csp_num--; return true; } -static bool -wasm_loader_check_br(WASMLoaderContext *ctx, uint32 depth, - char *error_buf, uint32 error_buf_size) -{ - BranchBlock *target_block, *cur_block; - int32 available_stack_cell; - - bh_assert(ctx->csp_num >= depth + 1); - - target_block = ctx->frame_csp - (depth + 1); - cur_block = ctx->frame_csp - 1; - - available_stack_cell = (int32) - (ctx->stack_cell_num - cur_block->stack_cell_num); - - if (available_stack_cell <= 0 && target_block->is_stack_polymorphic) - return true; - - if (target_block->block_type != BLOCK_TYPE_LOOP) { - uint8 type = target_block->return_type; - if (!check_stack_top_values(ctx->frame_ref, available_stack_cell, - type, error_buf, error_buf_size)) - return false; - } - return true; -} - #if WASM_ENABLE_FAST_INTERP != 0 #if WASM_ENABLE_ABS_LABEL_ADDR != 0 @@ -3093,24 +3093,56 @@ static bool wasm_loader_emit_br_info(WASMLoaderContext *ctx, BranchBlock *frame_csp, char *error_buf, uint32 error_buf_size) { - emit_operand(ctx, frame_csp->dynamic_offset); - if (frame_csp->block_type == BLOCK_TYPE_LOOP || - frame_csp->return_type == VALUE_TYPE_VOID) { - emit_byte(ctx, 0); - emit_operand(ctx, 0); + /* br info layout: + * a) arity of target block + * b) total cell num of arity values + * c) each arity value's cell num + * d) each arity value's src frame offset + * e) each arity values's dst dynamic offset + * f) branch target address + */ + BlockType *block_type = &frame_csp->block_type; + uint8 *types = NULL, cell; + uint32 arity = 0; + int32 i; + int16 *frame_offset = ctx->frame_offset; + uint16 dynamic_offset; + + /* Note: loop's arity is different from if and block. loop's arity is + * its parameter count while if and block arity is result count. + */ + if (frame_csp->label_type == LABEL_TYPE_LOOP) + arity = block_type_get_param_types(block_type, &types); + else + arity = block_type_get_result_types(block_type, &types); + + /* Part a */ + emit_uint32(ctx, arity); + /* Part b */ + emit_uint32(ctx, wasm_get_cell_num(types, arity)); + + /* Part c */ + for (i = (int32)arity - 1; i >= 0; i--) { + cell = wasm_value_type_cell_num(types[i]); + emit_byte(ctx, cell); } - else if (frame_csp->return_type == VALUE_TYPE_I32 - || frame_csp->return_type == VALUE_TYPE_F32) { - emit_byte(ctx, 1); - emit_operand(ctx, *(int16*)(ctx->frame_offset - 1)); + /* Part d */ + for (i = (int32)arity - 1; i >= 0; i--) { + cell = wasm_value_type_cell_num(types[i]); + frame_offset -= cell; + emit_operand(ctx, *(int16*)(frame_offset)); } - else if (frame_csp->return_type == VALUE_TYPE_I64 - || frame_csp->return_type == VALUE_TYPE_F64) { - emit_byte(ctx, 2); - emit_operand(ctx, *(int16*)(ctx->frame_offset - 2)); + /* Part e */ + dynamic_offset = frame_csp->dynamic_offset + + wasm_get_cell_num(types, arity); + for (i = (int32)arity - 1; i >= 0; i--) { + cell = wasm_value_type_cell_num(types[i]); + dynamic_offset -= cell; + emit_operand(ctx, dynamic_offset); } - if (frame_csp->block_type == BLOCK_TYPE_LOOP) { + /* Part f */ + if (frame_csp->label_type == LABEL_TYPE_LOOP) { wasm_loader_emit_ptr(ctx, frame_csp->code_compiled); } else { @@ -3121,6 +3153,7 @@ wasm_loader_emit_br_info(WASMLoaderContext *ctx, BranchBlock *frame_csp, /* label address, to be patched */ wasm_loader_emit_ptr(ctx, NULL); } + return true; } @@ -3513,50 +3546,116 @@ fail: #if WASM_ENABLE_FAST_INTERP != 0 static bool -reserve_block_ret(WASMLoaderContext *loader_ctx, uint8 opcode, bool disable_emit, +reserve_block_ret(WASMLoaderContext *loader_ctx, + uint8 opcode, bool disable_emit, char *error_buf, uint32 error_buf_size) { int16 operand_offset = 0; - uint8 block_depth = 0; - if (opcode == WASM_OP_ELSE) - block_depth = 1; - else - block_depth = 0; + BranchBlock *block = (opcode == WASM_OP_ELSE) ? + loader_ctx->frame_csp - 1 : loader_ctx->frame_csp; + BlockType *block_type = &block->block_type; + uint8 *return_types = NULL; + uint32 return_count = 0, value_count = 0, total_cel_num = 0; + int32 i = 0; + int16 dynamic_offset, dynamic_offset_org, + *frame_offset = NULL, *frame_offset_org = NULL; - if ((loader_ctx->frame_csp - block_depth)->return_type != VALUE_TYPE_VOID) { - uint8 return_cells; - if ((loader_ctx->frame_csp - block_depth)->return_type == VALUE_TYPE_I32 - || (loader_ctx->frame_csp - block_depth)->return_type == VALUE_TYPE_F32) - return_cells = 1; - else - return_cells = 2; - if ((loader_ctx->frame_csp - block_depth)->dynamic_offset != - *(loader_ctx->frame_offset - return_cells)) { + return_count = block_type_get_result_types(block_type, &return_types); - /* insert op_copy before else opcode */ - if (opcode == WASM_OP_ELSE) - skip_label(); + /* Copy stack top values to block's results which are in dynamic space. + * The instruction format: + * Part a: values count + * Part b: all values total cell num + * Part c: each value's cell_num, src offset and dst offset + * Part d: each value's src offset and dst offset + * Part e: each value's dst offset + */ + frame_offset = frame_offset_org = loader_ctx->frame_offset; + dynamic_offset = dynamic_offset_org = + block->dynamic_offset + + wasm_get_cell_num(return_types, return_count); - if (return_cells == 1) - emit_label(EXT_OP_COPY_STACK_TOP); - else - emit_label(EXT_OP_COPY_STACK_TOP_I64); - emit_operand(loader_ctx, *(loader_ctx->frame_offset - return_cells)); - emit_operand(loader_ctx, (loader_ctx->frame_csp - block_depth)->dynamic_offset); + /* First traversal to get the count of values needed to be copied. */ + for (i = (int32)return_count - 1; i >= 0; i--) { + uint8 cells = wasm_value_type_cell_num(return_types[i]); + frame_offset -= cells; + dynamic_offset -= cells; + if (dynamic_offset != *frame_offset) { + value_count++; + total_cel_num += cells; + } + } + + if (value_count) { + uint32 j = 0; + uint8 *emit_data = NULL, *cells = NULL; + int16 *src_offsets = NULL; + uint16 *dst_offsets = NULL; + uint64 size = (uint64)value_count * (sizeof(*cells) + + sizeof(*src_offsets) + + sizeof(*dst_offsets)); + + /* Allocate memory for the emit data */ + if (!(emit_data = loader_malloc(size, error_buf, error_buf_size))) + return false; + + cells = emit_data; + src_offsets = (int16 *)(cells + value_count); + dst_offsets = (uint16 *)(src_offsets + value_count); + + /* insert op_copy before else opcode */ + if (opcode == WASM_OP_ELSE) + skip_label(); + emit_label(EXT_OP_COPY_STACK_VALUES); + /* Part a) */ + emit_uint32(loader_ctx, value_count); + /* Part b) */ + emit_uint32(loader_ctx, total_cel_num); + + /* Second traversal to get each value's cell num, src offset and dst offset. */ + frame_offset = frame_offset_org; + dynamic_offset = dynamic_offset_org; + for (i = (int32)return_count - 1, j = 0; i >= 0; i--) { + uint8 cell = wasm_value_type_cell_num(return_types[i]); + frame_offset -= cell; + dynamic_offset -= cell; + if (dynamic_offset != *frame_offset) { + /* cell num */ + cells[j] = cell; + /* src offset */ + src_offsets[j] = *frame_offset; + /* dst offset */ + dst_offsets[j] = dynamic_offset; + j++; + } if (opcode == WASM_OP_ELSE) { - *(loader_ctx->frame_offset - return_cells) = - (loader_ctx->frame_csp - block_depth)->dynamic_offset; + *frame_offset = dynamic_offset; } else { - loader_ctx->frame_offset -= return_cells; - loader_ctx->dynamic_offset = loader_ctx->frame_csp->dynamic_offset; - PUSH_OFFSET_TYPE((loader_ctx->frame_csp - block_depth)->return_type); + loader_ctx->frame_offset = frame_offset; + loader_ctx->dynamic_offset = dynamic_offset; + PUSH_OFFSET_TYPE(return_types[i]); wasm_loader_emit_backspace(loader_ctx, sizeof(int16)); + loader_ctx->frame_offset = frame_offset_org; + loader_ctx->dynamic_offset = dynamic_offset_org; } - if (opcode == WASM_OP_ELSE) - emit_label(opcode); } + + bh_assert(j == value_count); + + /* Emit the cells, src_offsets and dst_offsets */ + for (j = 0; j < value_count; j++) + emit_byte(loader_ctx, cells[j]); + for (j = 0; j < value_count; j++) + emit_operand(loader_ctx, src_offsets[j]); + for (j = 0; j < value_count; j++) + emit_operand(loader_ctx, dst_offsets[j]); + + if (opcode == WASM_OP_ELSE) + emit_label(opcode); + + wasm_runtime_free(emit_data); } return true; @@ -3585,11 +3684,11 @@ fail: goto fail; \ } while (0) -#define PUSH_CSP(type, ret_type, _start_addr) do { \ - if (!wasm_loader_push_frame_csp(loader_ctx, type, ret_type, \ - _start_addr, error_buf, \ - error_buf_size)) \ - goto fail; \ +#define PUSH_CSP(label_type, block_type, _start_addr) do { \ + if (!wasm_loader_push_frame_csp(loader_ctx, label_type, block_type, \ + _start_addr, error_buf, \ + error_buf_size)) \ + goto fail; \ } while (0) #define POP_CSP() do { \ @@ -3618,13 +3717,88 @@ fail: + module->memory_count > 0); \ } while (0) -#define CHECK_BLOCK_TYPE(type) do { \ - bh_assert(type == VALUE_TYPE_I32 \ - || type == VALUE_TYPE_I64 \ - || type == VALUE_TYPE_F32 \ - || type == VALUE_TYPE_F64 \ - || type == VALUE_TYPE_VOID); \ - } while (0) + +static bool +is_value_type(uint8 type) +{ + return type == VALUE_TYPE_I32 || + type == VALUE_TYPE_I64 || + type == VALUE_TYPE_F32 || + type == VALUE_TYPE_F64 || + type == VALUE_TYPE_VOID; +} + +static bool +wasm_loader_check_br(WASMLoaderContext *loader_ctx, uint32 depth, + char *error_buf, uint32 error_buf_size) +{ + BranchBlock *target_block, *cur_block; + BlockType *target_block_type; + uint8 *types = NULL, *frame_ref; + uint32 arity = 0; + int32 i, available_stack_cell; + uint16 cell_num; + + if (loader_ctx->csp_num < depth + 1) { + set_error_buf(error_buf, error_buf_size, + "WASM module load failed: unknown label, " + "unexpected end of section or function"); + return false; + } + + cur_block = loader_ctx->frame_csp - 1; + target_block = loader_ctx->frame_csp - (depth + 1); + target_block_type = &target_block->block_type; + frame_ref = loader_ctx->frame_ref; + + /* Note: loop's arity is different from if and block. loop's arity is + * its parameter count while if and block arity is result count. + */ + if (target_block->label_type == LABEL_TYPE_LOOP) + arity = block_type_get_param_types(target_block_type, &types); + else + arity = block_type_get_result_types(target_block_type, &types); + + /* If the stack is in polymorphic state, just clear the stack + * and then re-push the values to make the stack top values + * match block type. */ + if (cur_block->is_stack_polymorphic) { + for (i = (int32)arity -1; i >= 0; i--) { +#if WASM_ENABLE_FAST_INTERP != 0 + POP_OFFSET_TYPE(types[i]); +#endif + POP_TYPE(types[i]); + } + for (i = 0; i < (int32)arity; i++) { +#if WASM_ENABLE_FAST_INTERP != 0 + bool disable_emit = true; + int16 operand_offset = 0; + PUSH_OFFSET_TYPE(types[i]); +#endif + PUSH_TYPE(types[i]); + } + return true; + } + + available_stack_cell = (int32) + (loader_ctx->stack_cell_num - cur_block->stack_cell_num); + + /* Check stack top values match target block type */ + for (i = (int32)arity -1; i >= 0; i--) { + if (!check_stack_top_values(frame_ref, available_stack_cell, + types[i], + error_buf, error_buf_size)) + return false; + cell_num = wasm_value_type_cell_num(types[i]); + frame_ref -= cell_num; + available_stack_cell -= cell_num; + } + + return true; + +fail: + return false; +} static BranchBlock * check_branch_block(WASMLoaderContext *loader_ctx, @@ -3649,90 +3823,165 @@ fail: } static bool -check_branch_block_ret(WASMLoaderContext *loader_ctx, - BranchBlock *frame_csp_tmp, - char *error_buf, uint32 error_buf_size) +check_block_stack(WASMLoaderContext *loader_ctx, BranchBlock *block, + char *error_buf, uint32 error_buf_size) { + BlockType *block_type = &block->block_type; + uint8 *return_types = NULL; + uint32 return_count = 0; + int32 available_stack_cell, return_cell_num, i; + uint8 *frame_ref = NULL; + + available_stack_cell = (int32) + (loader_ctx->stack_cell_num + - block->stack_cell_num); + + return_count = block_type_get_result_types(block_type, &return_types); + return_cell_num = return_count > 0 ? + wasm_get_cell_num(return_types, return_count) : 0; + + /* If the stack is in polymorphic state, just clear the stack + * and then re-push the values to make the stack top values + * match block type. */ + if (block->is_stack_polymorphic) { + for (i = (int32)return_count -1; i >= 0; i--) { #if WASM_ENABLE_FAST_INTERP != 0 - BranchBlock *cur_block = loader_ctx->frame_csp - 1; - bool disable_emit = true; - int16 operand_offset = 0; + POP_OFFSET_TYPE(return_types[i]); #endif - if (frame_csp_tmp->block_type != BLOCK_TYPE_LOOP) { - uint8 block_return_type = frame_csp_tmp->return_type; -#if WASM_ENABLE_FAST_INTERP != 0 - /* If the stack is in polymorphic state, do fake pop and push on - offset stack to keep the depth of offset stack to be the same - with ref stack */ - if (cur_block->is_stack_polymorphic) { - POP_OFFSET_TYPE(block_return_type); - PUSH_OFFSET_TYPE(block_return_type); + POP_TYPE(return_types[i]); } + + /* Check stack is empty */ + bh_assert(loader_ctx->stack_cell_num == block->stack_cell_num); + + for (i = 0; i < (int32)return_count; i++) { +#if WASM_ENABLE_FAST_INTERP != 0 + bool disable_emit = true; + int16 operand_offset = 0; + PUSH_OFFSET_TYPE(return_types[i]); #endif - POP_TYPE(block_return_type); - PUSH_TYPE(block_return_type); + PUSH_TYPE(return_types[i]); + } + return true; } + + /* Check stack cell num equals return cell num */ + bh_assert(available_stack_cell == return_cell_num); + + /* Check stack values match return types */ + frame_ref = loader_ctx->frame_ref; + for (i = (int32)return_count -1; i >= 0; i--) { + if (!check_stack_top_values(frame_ref, available_stack_cell, + return_types[i], + error_buf, error_buf_size)) + return false; + frame_ref -= wasm_value_type_cell_num(return_types[i]); + available_stack_cell -= wasm_value_type_cell_num(return_types[i]); + } + + (void)return_cell_num; return true; + fail: return false; } +#if WASM_ENABLE_FAST_INTERP != 0 +/* Copy parameters to dynamic space. + * 1) POP original parameter out; + * 2) Push and copy original values to dynamic space. + * The copy instruction format: + * Part a: param count + * Part b: all param total cell num + * Part c: each param's cell_num, src offset and dst offset + * Part d: each param's src offset + * Part e: each param's dst offset + */ static bool -check_block_stack(WASMLoaderContext *ctx, BranchBlock *block, - char *error_buf, uint32 error_buf_size) +copy_params_to_dynamic_space(WASMLoaderContext *loader_ctx, bool is_if_block, + char* error_buf, uint32 error_buf_size) { - uint8 type = block->return_type; - int32 available_stack_cell = (int32) - (ctx->stack_cell_num - block->stack_cell_num); + int16 *frame_offset = NULL; + uint8 *cells = NULL, cell; + int16 *src_offsets = NULL; + uint8 *emit_data = NULL; + uint32 i; + BranchBlock *block = loader_ctx->frame_csp - 1; + BlockType *block_type = &block->block_type; + WASMType *wasm_type = block_type->u.type; + uint32 param_count = block_type->u.type->param_count; + int16 condition_offset = 0; + bool disable_emit = false; + int16 operand_offset = 0; - if (type != VALUE_TYPE_VOID - && available_stack_cell <= 0 - && block->is_stack_polymorphic) { - if (!(wasm_loader_push_frame_ref(ctx, type, error_buf, error_buf_size)) -#if WASM_ENABLE_FAST_INTERP != 0 - || !(wasm_loader_push_frame_offset(ctx, type, true, 0, error_buf, error_buf_size)) -#endif - ) - return false; - return true; - } + uint64 size = (uint64)param_count * (sizeof(*cells) + + sizeof(*src_offsets)); - if (type != VALUE_TYPE_VOID - && available_stack_cell == 1 - && *(ctx->frame_ref - 1) == VALUE_TYPE_ANY) { - if (type == VALUE_TYPE_I32 || type == VALUE_TYPE_F32) { - /* If the stack top is a value of any type, change its type to the - * same as block return type and return success */ - *(ctx->frame_ref - 1) = type; - } - else { - if (!(wasm_loader_push_frame_ref(ctx, VALUE_TYPE_I32, - error_buf, error_buf_size)) -#if WASM_ENABLE_FAST_INTERP != 0 - || !(wasm_loader_push_frame_offset(ctx, VALUE_TYPE_I32, - true, 0, - error_buf, error_buf_size)) -#endif - ) - return false; - *(ctx->frame_ref - 1) = *(ctx->frame_ref - 2) = type; - } - return true; - } + /* For if block, we also need copy the condition operand offset. */ + if (is_if_block) + size += sizeof(*cells) + sizeof(*src_offsets); - bh_assert(!(((type == VALUE_TYPE_I32 || type == VALUE_TYPE_F32) - && available_stack_cell != 1) - || ((type == VALUE_TYPE_I64 || type == VALUE_TYPE_F64) - && available_stack_cell != 2) - || (type == VALUE_TYPE_VOID - && available_stack_cell > 0))); - - if (!check_stack_top_values(ctx->frame_ref, available_stack_cell, - type, error_buf, error_buf_size)) + /* Allocate memory for the emit data */ + if (!(emit_data = loader_malloc(size, error_buf, error_buf_size))) return false; + cells = emit_data; + src_offsets = (int16 *)(cells + param_count); + + if (is_if_block) + condition_offset = *loader_ctx->frame_offset; + + /* POP original parameter out */ + for (i = 0; i < param_count; i++) { + POP_OFFSET_TYPE(wasm_type->types[param_count - i - 1]); + wasm_loader_emit_backspace(loader_ctx, sizeof(int16)); + } + frame_offset = loader_ctx->frame_offset; + + /* Get each param's cell num and src offset */ + for (i = 0; i < param_count; i++) { + cell = wasm_value_type_cell_num(wasm_type->types[i]); + cells[i] = cell; + src_offsets[i] = *frame_offset; + frame_offset += cell; + } + + /* emit copy instruction */ + emit_label(EXT_OP_COPY_STACK_VALUES); + /* Part a) */ + emit_uint32(loader_ctx, is_if_block ? param_count + 1 : param_count); + /* Part b) */ + emit_uint32(loader_ctx, is_if_block ? + wasm_type->param_cell_num + 1 : + wasm_type->param_cell_num); + /* Part c) */ + for (i = 0; i < param_count; i++) + emit_byte(loader_ctx, cells[i]); + if (is_if_block) + emit_byte(loader_ctx, 1); + + /* Part d) */ + for (i = 0; i < param_count; i++) + emit_operand(loader_ctx, src_offsets[i]); + if (is_if_block) + emit_operand(loader_ctx, condition_offset); + + /* Part e) */ + /* Push to dynamic space. The push will emit the dst offset. */ + for (i = 0; i < param_count; i++) + PUSH_OFFSET_TYPE(wasm_type->types[i]); + if (is_if_block) + PUSH_OFFSET_TYPE(VALUE_TYPE_I32); + + /* Free the emit data */ + wasm_runtime_free(emit_data); + return true; + +fail: + return false; } +#endif /* reset the stack to the state of before entering the last block */ #if WASM_ENABLE_FAST_INTERP != 0 @@ -3759,6 +4008,9 @@ check_block_stack(WASMLoaderContext *ctx, BranchBlock *block, cur_block->is_stack_polymorphic = flag; \ } while (0) +#define BLOCK_HAS_PARAM(block_type) \ + (!block_type.is_value_type && block_type.u.type->param_count > 0) + static bool wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, BlockAddr *block_addr_cache, @@ -3766,12 +4018,13 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, { uint8 *p = func->code, *p_end = func->code + func->code_size, *p_org; uint32 param_count, local_count, global_count; - uint8 *param_types, ret_type, *local_types, local_type, global_type; + uint8 *param_types, *local_types, local_type, global_type; + BlockType func_type; uint16 *local_offsets, local_offset; uint32 count, i, local_idx, global_idx, u32, align, mem_offset; int32 i32, i32_const = 0; int64 i64; - uint8 opcode, u8, block_return_type; + uint8 opcode, u8; bool return_value = false; WASMLoaderContext *loader_ctx; BranchBlock *frame_csp_tmp; @@ -3796,8 +4049,9 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, param_count = func->func_type->param_count; param_types = func->func_type->types; - ret_type = func->func_type->result_count - ? param_types[param_count] : VALUE_TYPE_VOID; + + func_type.is_value_type = false; + func_type.u.type = func->func_type; local_count = func->local_count; local_types = func->local_types; @@ -3824,7 +4078,7 @@ re_scan: } #endif - PUSH_CSP(BLOCK_TYPE_FUNCTION, ret_type, p); + PUSH_CSP(LABEL_TYPE_FUNCTION, func_type, p); while (p < p_end) { opcode = *p++; @@ -3846,44 +4100,137 @@ re_scan: #endif break; - case WASM_OP_BLOCK: - /* 0x40/0x7F/0x7E/0x7D/0x7C */ - block_return_type = read_uint8(p); - CHECK_BLOCK_TYPE(block_return_type); - PUSH_CSP(BLOCK_TYPE_BLOCK, block_return_type, p); -#if WASM_ENABLE_FAST_INTERP != 0 - skip_label(); -#endif - break; - - case WASM_OP_LOOP: - /* 0x40/0x7F/0x7E/0x7D/0x7C */ - block_return_type = read_uint8(p); - CHECK_BLOCK_TYPE(block_return_type); - PUSH_CSP(BLOCK_TYPE_LOOP, block_return_type, p); -#if WASM_ENABLE_FAST_INTERP != 0 - skip_label(); - (loader_ctx->frame_csp - 1)->code_compiled = - loader_ctx->p_code_compiled; -#endif - break; - case WASM_OP_IF: POP_I32(); - /* 0x40/0x7F/0x7E/0x7D/0x7C */ - block_return_type = read_uint8(p); - CHECK_BLOCK_TYPE(block_return_type); - PUSH_CSP(BLOCK_TYPE_IF, block_return_type, p); + goto handle_op_block_and_loop; + case WASM_OP_BLOCK: + case WASM_OP_LOOP: +handle_op_block_and_loop: + { + uint8 value_type; + BlockType block_type; + + value_type = read_uint8(p); + if (is_value_type(value_type)) { + /* If the first byte is one of these special values: + * 0x40/0x7F/0x7E/0x7D/0x7C, take it as the type of + * the single return value. */ + block_type.is_value_type = true; + block_type.u.value_type = value_type; + } + else { + uint32 type_index; + /* Resolve the leb128 encoded type index as block type */ + p--; + read_leb_uint32(p, p_end, type_index); + bh_assert(type_index < module->type_count); + block_type.is_value_type = false; + block_type.u.type = module->types[type_index]; +#if WASM_ENABLE_FAST_INTERP == 0 \ + && WASM_ENABLE_WAMR_COMPILER == 0 \ + && WASM_ENABLE_JIT == 0 + /* If block use type index as block type, change the opcode + * to new extended opcode so that interpreter can resolve the + * block quickly. + */ + *(p - 2) = EXT_OP_BLOCK + (opcode - WASM_OP_BLOCK); +#endif + } + + /* Pop block parameters from stack */ + if (BLOCK_HAS_PARAM(block_type)) { + WASMType *wasm_type = block_type.u.type; + for (i = 0; i < block_type.u.type->param_count; i++) + POP_TYPE(wasm_type->types[wasm_type->param_count - i - 1]); + } + + PUSH_CSP(LABEL_TYPE_BLOCK + (opcode - WASM_OP_BLOCK), block_type, p); + + /* Pass parameters to block */ + if (BLOCK_HAS_PARAM(block_type)) { + for (i = 0; i < block_type.u.type->param_count; i++) + PUSH_TYPE(block_type.u.type->types[i]); + } + #if WASM_ENABLE_FAST_INTERP != 0 - emit_empty_label_addr_and_frame_ip(PATCH_ELSE); - emit_empty_label_addr_and_frame_ip(PATCH_END); + if (opcode == WASM_OP_BLOCK) { + skip_label(); + } else if (opcode == WASM_OP_LOOP) { + skip_label(); + if (BLOCK_HAS_PARAM(block_type)) { + /* Make sure params are in dynamic space */ + if (!copy_params_to_dynamic_space(loader_ctx, + false, + error_buf, + error_buf_size)) + goto fail; + } + (loader_ctx->frame_csp - 1)->code_compiled = + loader_ctx->p_code_compiled; + } else if (opcode == WASM_OP_IF) { + /* If block has parameters, we should make sure they are in + * dynamic space. Otherwise, when else branch is missing, + * the later opcode may consume incorrect operand offset. + * Spec case: + * (func (export "params-id") (param i32) (result i32) + * (i32.const 1) + * (i32.const 2) + * (if (param i32 i32) (result i32 i32) (local.get 0) (then)) + * (i32.add) + * ) + * + * So we should emit a copy instruction before the if. + * + * And we also need to save the parameter offsets and + * recover them before entering else branch. + * + */ + if (BLOCK_HAS_PARAM(block_type)) { + BranchBlock *block = loader_ctx->frame_csp - 1; + uint64 size; + + /* skip the if condition operand offset */ + wasm_loader_emit_backspace(loader_ctx, sizeof(int16)); + /* skip the if label */ + skip_label(); + /* Emit a copy instruction */ + if (!copy_params_to_dynamic_space(loader_ctx, + true, + error_buf, + error_buf_size)) + goto fail; + + /* Emit the if instruction */ + emit_label(opcode); + /* Emit the new condition operand offset */ + POP_OFFSET_TYPE(VALUE_TYPE_I32); + + /* Save top param_count values of frame_offset stack, so that + * we can recover it before executing else branch */ + size = sizeof(int16) * + (uint64)block_type.u.type->param_cell_num; + if (!(block->param_frame_offsets = + loader_malloc(size, error_buf, error_buf_size))) + goto fail; + bh_memcpy_s(block->param_frame_offsets, + size, + loader_ctx->frame_offset - size/sizeof(int16), + size); + } + + emit_empty_label_addr_and_frame_ip(PATCH_ELSE); + emit_empty_label_addr_and_frame_ip(PATCH_END); + } #endif break; + } case WASM_OP_ELSE: + { + BlockType block_type = (loader_ctx->frame_csp - 1)->block_type; bh_assert(loader_ctx->csp_num >= 2 - && (loader_ctx->frame_csp - 1)->block_type - == BLOCK_TYPE_IF); + && (loader_ctx->frame_csp - 1)->label_type + == LABEL_TYPE_IF); /* check whether if branch's stack matches its result type */ if (!check_block_stack(loader_ctx, loader_ctx->frame_csp - 1, @@ -3901,20 +4248,63 @@ re_scan: #endif RESET_STACK(); SET_CUR_BLOCK_STACK_POLYMORPHIC_STATE(false); + + /* Pass parameters to if-false branch */ + if (BLOCK_HAS_PARAM(block_type)) { + for (i = 0; i < block_type.u.type->param_count; i++) + PUSH_TYPE(block_type.u.type->types[i]); + } + +#if WASM_ENABLE_FAST_INTERP != 0 + /* Recover top param_count values of frame_offset stack */ + if (BLOCK_HAS_PARAM((block_type))) { + uint32 size; + BranchBlock *block = loader_ctx->frame_csp - 1; + size = sizeof(int16) * + block_type.u.type->param_cell_num; + bh_memcpy_s(loader_ctx->frame_offset, size, + block->param_frame_offsets, size); + loader_ctx->frame_offset += (size/sizeof(int16)); + } +#endif + break; + } case WASM_OP_END: { + BranchBlock *cur_block = loader_ctx->frame_csp - 1; /* check whether block stack matches its result type */ - if (!check_block_stack(loader_ctx, loader_ctx->frame_csp - 1, + if (!check_block_stack(loader_ctx, cur_block, error_buf, error_buf_size)) goto fail; - /* if has return value, but no else branch, fail */ - bh_assert(!((loader_ctx->frame_csp - 1)->block_type == BLOCK_TYPE_IF - && (loader_ctx->frame_csp - 1)->return_type != VALUE_TYPE_VOID - && !(loader_ctx->frame_csp - 1)->else_addr)); + /* if no else branch, and return types do not match param types, fail */ + if (cur_block->label_type == LABEL_TYPE_IF + && !cur_block->else_addr) { + uint32 param_count = 0, ret_count = 0; + uint8 *param_types = NULL, *ret_types = NULL; + BlockType *block_type = &cur_block->block_type; + if (block_type->is_value_type) { + if (block_type->u.value_type != VALUE_TYPE_VOID) { + ret_count = 1; + ret_types = &block_type->u.value_type; + } + } + else { + param_count = block_type->u.type->param_count; + ret_count = block_type->u.type->result_count; + param_types = block_type->u.type->types; + ret_types = block_type->u.type->types + param_count; + } + bh_assert(param_count == ret_count + && (!param_count + || !memcmp(param_types, ret_types, param_count))); + (void)ret_types; + (void)ret_count; + (void)param_types; + } POP_CSP(); @@ -3925,9 +4315,17 @@ re_scan: apply_label_patch(loader_ctx, 0, PATCH_END); free_label_patch_list(loader_ctx->frame_csp); - if (loader_ctx->frame_csp->block_type == BLOCK_TYPE_FUNCTION) { + if (loader_ctx->frame_csp->label_type == LABEL_TYPE_FUNCTION) { + int32 idx; + uint8 ret_type; + emit_label(WASM_OP_RETURN); - POP_OFFSET_TYPE(loader_ctx->frame_csp->return_type); + for (idx = (int32)func->func_type->result_count - 1; + idx >= 0; idx--) { + ret_type = *(func->func_type->types + + func->func_type->param_count + idx); + POP_OFFSET_TYPE(ret_type); + } } #endif if (loader_ctx->csp_num > 0) { @@ -3951,10 +4349,6 @@ re_scan: error_buf, error_buf_size))) goto fail; - if (!check_branch_block_ret(loader_ctx, frame_csp_tmp, - error_buf, error_buf_size)) - goto fail; - RESET_STACK(); SET_CUR_BLOCK_STACK_POLYMORPHIC_STATE(true); break; @@ -3968,16 +4362,13 @@ re_scan: error_buf, error_buf_size))) goto fail; - if (!check_branch_block_ret(loader_ctx, frame_csp_tmp, - error_buf, error_buf_size)) - goto fail; - break; } case WASM_OP_BR_TABLE: { - uint8 ret_type; + uint8 *ret_types = NULL; + uint32 ret_count = 0; read_leb_uint32(p, p_end, count); #if WASM_ENABLE_FAST_INTERP != 0 @@ -3987,45 +4378,37 @@ re_scan: /* TODO: check the const */ for (i = 0; i <= count; i++) { - if (!(frame_csp_tmp = check_branch_block(loader_ctx, &p, p_end, - error_buf, error_buf_size))) + if (!(frame_csp_tmp = + check_branch_block(loader_ctx, &p, p_end, + error_buf, error_buf_size))) goto fail; - - if (!check_branch_block_ret(loader_ctx, frame_csp_tmp, - error_buf, error_buf_size)) - goto fail; - - if (i == 0) { - ret_type = frame_csp_tmp->block_type == BLOCK_TYPE_LOOP ? - VALUE_TYPE_VOID : frame_csp_tmp->return_type; - } - else { - /* Check whether all table items have the same return type */ - uint8 tmp_ret_type = frame_csp_tmp->block_type == BLOCK_TYPE_LOOP ? - VALUE_TYPE_VOID : frame_csp_tmp->return_type; - bh_assert(ret_type == tmp_ret_type); - (void)tmp_ret_type; - } } RESET_STACK(); SET_CUR_BLOCK_STACK_POLYMORPHIC_STATE(true); - (void)ret_type; + + (void)ret_count; + (void)ret_types; break; } case WASM_OP_RETURN: { - POP_TYPE(ret_type); - PUSH_TYPE(ret_type); - + int32 idx; + uint8 ret_type; + for (idx = (int32)func->func_type->result_count - 1; idx >= 0; idx--) { + ret_type = *(func->func_type->types + + func->func_type->param_count + idx); + POP_TYPE(ret_type); #if WASM_ENABLE_FAST_INTERP != 0 - // emit the offset after return opcode - POP_OFFSET_TYPE(ret_type); + // emit the offset after return opcode + POP_OFFSET_TYPE(ret_type); #endif + } RESET_STACK(); SET_CUR_BLOCK_STACK_POLYMORPHIC_STATE(true); + break; } @@ -4059,10 +4442,14 @@ re_scan: } } - if (func_type->result_count) { - PUSH_TYPE(func_type->types[func_type->param_count]); + for (i = 0; i < func_type->result_count; i++) { + PUSH_TYPE(func_type->types[func_type->param_count + i]); #if WASM_ENABLE_FAST_INTERP != 0 - PUSH_OFFSET_TYPE(func_type->types[func_type->param_count]); + /* Here we emit each return value's dynamic_offset. But in fact + * these offsets are continuous, so interpreter only need to get + * the first return value's offset. + */ + PUSH_OFFSET_TYPE(func_type->types[func_type->param_count + i]); #endif } @@ -4104,10 +4491,10 @@ re_scan: } } - if (func_type->result_count > 0) { - PUSH_TYPE(func_type->types[func_type->param_count]); + for (i = 0; i < func_type->result_count; i++) { + PUSH_TYPE(func_type->types[func_type->param_count + i]); #if WASM_ENABLE_FAST_INTERP != 0 - PUSH_OFFSET_TYPE(func_type->types[func_type->param_count]); + PUSH_OFFSET_TYPE(func_type->types[func_type->param_count + i]); #endif } diff --git a/core/iwasm/interpreter/wasm_opcode.h b/core/iwasm/interpreter/wasm_opcode.h index 99b4f0b0a..abb60b8ed 100644 --- a/core/iwasm/interpreter/wasm_opcode.h +++ b/core/iwasm/interpreter/wasm_opcode.h @@ -255,8 +255,11 @@ typedef enum WASMOpcode { EXT_OP_TEE_LOCAL_FAST_I64 = 0xcb, EXT_OP_COPY_STACK_TOP = 0xcc, EXT_OP_COPY_STACK_TOP_I64 = 0xcd, - - WASM_OP_IMPDEP = 0xce, + EXT_OP_COPY_STACK_VALUES = 0xce, + EXT_OP_BLOCK = 0xcf, /* block with blocktype */ + EXT_OP_LOOP = 0xd0, /* loop with blocktype */ + EXT_OP_IF = 0xd1, /* if with blocktype */ + WASM_OP_IMPDEP = 0xd2, /* Post-MVP extend op prefix */ WASM_OP_MISC_PREFIX = 0xfc, @@ -499,7 +502,11 @@ static type _name[WASM_INSTRUCTION_NUM] = { \ HANDLE_OPCODE (EXT_OP_TEE_LOCAL_FAST_I64), /* 0xcb */ \ HANDLE_OPCODE (EXT_OP_COPY_STACK_TOP), /* 0xcc */ \ HANDLE_OPCODE (EXT_OP_COPY_STACK_TOP_I64), /* 0xcd */ \ - HANDLE_OPCODE (WASM_OP_IMPDEP), /* 0xce */ \ + HANDLE_OPCODE (EXT_OP_COPY_STACK_VALUES), /* 0xce */ \ + HANDLE_OPCODE (EXT_OP_BLOCK), /* 0xcf */ \ + HANDLE_OPCODE (EXT_OP_LOOP), /* 0xd0 */ \ + HANDLE_OPCODE (EXT_OP_IF), /* 0xd1 */ \ + HANDLE_OPCODE (WASM_OP_IMPDEP), /* 0xd2 */ \ }; \ do { \ _name[WASM_OP_MISC_PREFIX] = \ diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index 4ea874e4e..5212ca1cf 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -509,9 +509,9 @@ functions_instantiate(const WASMModule *module, import->u.function.field_name); function->u.func_import = &import->u.function; function->param_cell_num = - wasm_type_param_cell_num(import->u.function.func_type); + import->u.function.func_type->param_cell_num; function->ret_cell_num = - wasm_type_return_cell_num(import->u.function.func_type); + import->u.function.func_type->ret_cell_num; function->param_count = (uint16)function->u.func_import->func_type->param_count; function->param_types = function->u.func_import->func_type->types; @@ -1804,4 +1804,4 @@ wasm_get_aux_stack(WASMExecEnv *exec_env, } return false; } -#endif \ No newline at end of file +#endif diff --git a/product-mini/platforms/linux/CMakeLists.txt b/product-mini/platforms/linux/CMakeLists.txt index 053e76eac..e7a5a0786 100644 --- a/product-mini/platforms/linux/CMakeLists.txt +++ b/product-mini/platforms/linux/CMakeLists.txt @@ -112,4 +112,4 @@ install (TARGETS libiwasm DESTINATION lib) set_target_properties (libiwasm PROPERTIES OUTPUT_NAME iwasm) -target_link_libraries (libiwasm ${LLVM_AVAILABLE_LIBS} -lm -ldl -lpthread) \ No newline at end of file +target_link_libraries (libiwasm ${LLVM_AVAILABLE_LIBS} -lm -ldl -lpthread) diff --git a/test-tools/binarydump-tool/CMakeLists.txt b/test-tools/binarydump-tool/CMakeLists.txt new file mode 100644 index 000000000..d821c8062 --- /dev/null +++ b/test-tools/binarydump-tool/CMakeLists.txt @@ -0,0 +1,11 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required (VERSION 2.8) + +project(binarydump) + +add_definitions (-Wextra -pedantic -Wno-unused-parameter) + +add_executable (binarydump binarydump.c) + diff --git a/test-tools/binarydump-tool/binarydump.c b/test-tools/binarydump-tool/binarydump.c new file mode 100644 index 000000000..cd19eecad --- /dev/null +++ b/test-tools/binarydump-tool/binarydump.c @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include +#include +#include +#include + +static unsigned char* +read_file_to_buffer (const char *filename, int *ret_size) +{ + unsigned char *buffer; + FILE *file; + int file_size, read_size; + + if (!(file = fopen (filename, "r"))) + return NULL; + + fseek (file, 0, SEEK_END); + file_size = ftell (file); + fseek (file, 0, SEEK_SET); + + if (!(buffer = malloc (file_size))) { + fclose (file); + return NULL; + } + + read_size = fread (buffer, 1, file_size, file); + fclose (file); + + if (read_size < file_size) { + free (buffer); + return NULL; + } + + *ret_size = file_size; + + return buffer; +} + +static int +print_help () +{ + printf ("Usage: binarydump -o -n input_file\n"); + printf ("Options:\n"); + printf (" -o Place the output into \n"); + printf (" -n The name of array \n"); + + return -1; +} + +static bool +bin_file_dump (const unsigned char *file, int size, + const char *bin_file_output, + const char *array_name) +{ + unsigned i = 0; + const unsigned char *p = file, *p_end = file + size; + FILE *file_output = fopen(bin_file_output, "wb+"); + + if (!file_output) + return false; + + fprintf(file_output, "\nunsigned char __aligned(4) %s[] = {\n ", array_name); + + while (p < p_end) { + fprintf(file_output, "0x%02X", *p++); + + if (p == p_end) + break; + + fprintf(file_output, ","); + + if ((++i % 12) != 0) + fprintf(file_output, " "); + else + fprintf(file_output, "\n "); + } + + fprintf(file_output, "\n};\n"); + + fclose(file_output); + return true; +} + +int +main (int argc, char *argv[]) +{ + unsigned char *file; + int size; + bool ret; + const char *bin_file_input, *array_file_output = NULL, *array_name = NULL; + + for (argc--, argv++; argc > 0 && argv[0][0] == '-'; argc--, argv++) { + if (!strcmp (argv[0], "-o")) { + ++argv; + if (--argc == 0) + return print_help (); + array_file_output = *argv; + } + else if (!strcmp (argv[0], "-n")) { + ++argv; + if (--argc == 0) + return print_help (); + array_name = *argv; + } + else + return print_help (); + } + + if (!array_file_output || !array_name) + return print_help (); + + bin_file_input = *argv; + + if (!(file = read_file_to_buffer (bin_file_input, &size))) + return -1; + + ret = bin_file_dump (file, size, array_file_output, array_name); + + free (file); + + return ret ? 0 : -1; +} From 0472ddc0d0f41615d9c6273a3c59151189024707 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A4mes=20M=C3=A9n=C3=A9trey?= Date: Fri, 10 Jul 2020 10:41:08 +0200 Subject: [PATCH 031/207] Change whence_t constant values to match pre-existing agreed-upon values. (#307) --- .../sandboxed-system-primitives/include/wasmtime_ssp.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h index 1c2988cbd..e386eebf2 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h @@ -275,9 +275,9 @@ typedef uint64_t __wasi_timestamp_t; typedef uint64_t __wasi_userdata_t; typedef uint8_t __wasi_whence_t; -#define __WASI_WHENCE_CUR (0) -#define __WASI_WHENCE_END (1) -#define __WASI_WHENCE_SET (2) +#define __WASI_WHENCE_SET (0) +#define __WASI_WHENCE_CUR (1) +#define __WASI_WHENCE_END (2) typedef uint8_t __wasi_preopentype_t; #define __WASI_PREOPENTYPE_DIR (0) From 49555f48b3e212df0d4aca9c9e81c75f934c9b41 Mon Sep 17 00:00:00 2001 From: dpinthinker Date: Fri, 10 Jul 2020 16:47:22 +0800 Subject: [PATCH 032/207] remove duplicated method resolve_main_func (#305) --- core/iwasm/common/wasm_runtime_common.c | 44 +++++-------------------- 1 file changed, 8 insertions(+), 36 deletions(-) diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index 66d79b888..e8c1d4586 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -1584,41 +1584,9 @@ wasm_exec_env_get_module(WASMExecEnv *exec_env) * Implementation of wasm_application_execute_main() */ -static WASMFunctionInstanceCommon * -resolve_main_function(const WASMModuleInstanceCommon *module_inst) -{ - uint32 i; - -#if WASM_ENABLE_INTERP != 0 - if (module_inst->module_type == Wasm_Module_Bytecode) { - WASMModuleInstance *wasm_inst = (WASMModuleInstance*)module_inst; - for (i = 0; i < wasm_inst->export_func_count; i++) { - if (!strcmp(wasm_inst->export_functions[i].name, "_main") - || !strcmp(wasm_inst->export_functions[i].name, "main")) - return (WASMFunctionInstanceCommon*) - wasm_inst->export_functions[i].function; - } - LOG_ERROR("WASM execute application failed: main function not found.\n"); - return NULL; - } -#endif - -#if WASM_ENABLE_AOT != 0 - if (module_inst->module_type == Wasm_Module_AoT) { - AOTModuleInstance *aot_inst = (AOTModuleInstance*)module_inst; - AOTModule *module = (AOTModule*)aot_inst->aot_module.ptr; - for (i = 0; i < module->export_func_count; i++) { - if (!strcmp(module->export_funcs[i].func_name, "_main") - || !strcmp(module->export_funcs[i].func_name, "main")) - return (WASMFunctionInstanceCommon*)&module->export_funcs[i]; - } - LOG_ERROR("WASM execute application failed: main function not found.\n"); - return NULL; - } -#endif - - return NULL; -} +static WASMFunctionInstanceCommon* +resolve_function(const WASMModuleInstanceCommon *module_inst, + const char *name); static bool check_main_func_type(const WASMType *type) @@ -1672,7 +1640,11 @@ wasm_application_execute_main(WASMModuleInstanceCommon *module_inst, } #endif /* end of WASM_ENABLE_LIBC_WASI */ - func = resolve_main_function(module_inst); + func = resolve_function(module_inst, "_main"); + if (!func) { + func = resolve_function(module_inst, "main"); + } + if (!func) { wasm_runtime_set_exception(module_inst, "lookup main function failed."); From ca938f3634f90d40b6eee877ba07057ca2e20b3a Mon Sep 17 00:00:00 2001 From: yjsungo <68210713+yjsungo@users.noreply.github.com> Date: Mon, 13 Jul 2020 11:10:46 +0800 Subject: [PATCH 033/207] Fix one typo in README.md (#309) Signed-off-by: yijin.syj Co-authored-by: yijin.syj --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1163f49ad..28045e26b 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ iwasm VM core - [Non-trapping float-to-int conversions](https://github.com/WebAssembly/nontrapping-float-to-int-conversions) - [Sign-extension operators](https://github.com/WebAssembly/sign-extension-ops) - [Bulk memory operations](https://github.com/WebAssembly/bulk-memory-operations) -- [Shared memmory](https://github.com/WebAssembly/threads/blob/main/proposals/threads/Overview.md#shared-linear-memory) +- [Shared memory](https://github.com/WebAssembly/threads/blob/main/proposals/threads/Overview.md#shared-linear-memory) - [Multi-value](https://github.com/WebAssembly/multi-value) ### Performance and memory usage From 32b2943369bccce52fbbc86bc9239757d37cbf52 Mon Sep 17 00:00:00 2001 From: Xu Jun <693788454@qq.com> Date: Thu, 16 Jul 2020 20:35:04 +0800 Subject: [PATCH 034/207] enable pthread for AoT && update AOT current version to 2 (#311) --- core/config.h | 2 +- core/iwasm/aot/aot_loader.c | 245 ++++--- core/iwasm/aot/aot_runtime.c | 643 +++++++++++++----- core/iwasm/aot/aot_runtime.h | 94 ++- core/iwasm/common/wasm_exec_env.h | 11 +- core/iwasm/common/wasm_runtime_common.c | 44 +- core/iwasm/common/wasm_runtime_common.h | 8 + core/iwasm/common/wasm_shared_memory.c | 11 +- core/iwasm/common/wasm_shared_memory.h | 27 +- core/iwasm/compilation/aot.c | 159 +++-- core/iwasm/compilation/aot.h | 101 ++- core/iwasm/compilation/aot_emit_aot_file.c | 131 +++- core/iwasm/compilation/aot_emit_control.c | 125 ++++ core/iwasm/compilation/aot_emit_control.h | 5 + core/iwasm/compilation/aot_emit_function.c | 16 + core/iwasm/compilation/aot_emit_memory.c | 119 ++-- core/iwasm/compilation/aot_emit_variable.c | 5 +- core/iwasm/compilation/aot_llvm.c | 244 +++++-- core/iwasm/compilation/aot_llvm.h | 21 +- core/iwasm/include/aot_export.h | 1 + core/iwasm/interpreter/wasm_interp_classic.c | 4 +- core/iwasm/interpreter/wasm_interp_fast.c | 4 +- core/iwasm/interpreter/wasm_loader.c | 8 +- core/iwasm/interpreter/wasm_mini_loader.c | 25 +- core/iwasm/interpreter/wasm_runtime.c | 8 +- core/iwasm/interpreter/wasm_runtime.h | 6 +- .../lib-pthread/lib_pthread_wrapper.c | 12 +- .../libraries/thread-mgr/thread_manager.c | 30 +- doc/pthread_library.md | 11 +- product-mini/platforms/linux/CMakeLists.txt | 5 + wamr-compiler/CMakeLists.txt | 2 + wamr-compiler/main.c | 6 + 32 files changed, 1549 insertions(+), 584 deletions(-) diff --git a/core/config.h b/core/config.h index 104dfdf3d..9dd042a5c 100644 --- a/core/config.h +++ b/core/config.h @@ -62,7 +62,7 @@ enum { #endif #define AOT_MAGIC_NUMBER 0x746f6100 -#define AOT_CURRENT_VERSION 1 +#define AOT_CURRENT_VERSION 2 #ifndef WASM_ENABLE_JIT #define WASM_ENABLE_JIT 0 diff --git a/core/iwasm/aot/aot_loader.c b/core/iwasm/aot/aot_loader.c index af0d8fdb5..e6c48cadf 100644 --- a/core/iwasm/aot/aot_loader.c +++ b/core/iwasm/aot/aot_loader.c @@ -349,6 +349,14 @@ fail: return false; } +static void +destroy_import_memories(AOTImportMemory *import_memories, + bool is_jit_mode) +{ + if (!is_jit_mode) + wasm_runtime_free(import_memories); +} + static void destroy_mem_init_data_list(AOTMemInitData **data_list, uint32 count, bool is_jit_mode) @@ -420,11 +428,28 @@ load_memory_info(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module, char *error_buf, uint32 error_buf_size) { + uint32 i; + uint64 total_size; const uint8 *buf = *p_buf; - read_uint32(buf, buf_end, module->num_bytes_per_page); - read_uint32(buf, buf_end, module->mem_init_page_count); - read_uint32(buf, buf_end, module->mem_max_page_count); + read_uint32(buf, buf_end, module->import_memory_count); + /* We don't support import_memory_count > 0 currently */ + bh_assert(module->import_memory_count == 0); + + read_uint32(buf, buf_end, module->memory_count); + total_size = sizeof(AOTMemory) * (uint64)module->memory_count; + if (!(module->memories = + loader_malloc(total_size, error_buf, error_buf_size))) { + return false; + } + + for (i = 0; i < module->memory_count; i++) { + read_uint32(buf, buf_end, module->memories[i].memory_flags); + read_uint32(buf, buf_end, module->memories[i].num_bytes_per_page); + read_uint32(buf, buf_end, module->memories[i].mem_init_page_count); + read_uint32(buf, buf_end, module->memories[i].mem_max_page_count); + } + read_uint32(buf, buf_end, module->mem_init_data_count); /* load memory init data list */ @@ -439,6 +464,20 @@ fail: return false; } +static void +destroy_import_tables(AOTImportTable *import_tables, bool is_jit_mode) +{ + if (!is_jit_mode) + wasm_runtime_free(import_tables); +} + +static void +destroy_tables(AOTTable *tables, bool is_jit_mode) +{ + if (!is_jit_mode) + wasm_runtime_free(tables); +} + static void destroy_table_init_data_list(AOTTableInitData **data_list, uint32 count, bool is_jit_mode) @@ -452,6 +491,36 @@ destroy_table_init_data_list(AOTTableInitData **data_list, uint32 count, } } +static bool +load_table_list(const uint8 **p_buf, const uint8 *buf_end, + AOTModule *module, char *error_buf, uint32 error_buf_size) +{ + const uint8 *buf = *p_buf; + AOTTable *table; + uint64 size; + uint32 i; + + /* Allocate memory */ + size = sizeof(AOTTable) * (uint64)module->table_count; + if (!(module->tables = table = + loader_malloc(size, error_buf, error_buf_size))) { + return false; + } + + /* Create each table data segment */ + for (i = 0; i < module->table_count; i++, table++) { + read_uint32(buf, buf_end, table->elem_type); + read_uint32(buf, buf_end, table->table_flags); + read_uint32(buf, buf_end, table->table_init_size); + read_uint32(buf, buf_end, table->table_max_size); + } + + *p_buf = buf; + return true; +fail: + return false; +} + static bool load_table_init_data_list(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module, @@ -471,9 +540,10 @@ load_table_init_data_list(const uint8 **p_buf, const uint8 *buf_end, /* Create each table data segment */ for (i = 0; i < module->table_init_data_count; i++) { - uint32 init_expr_type, func_index_count; + uint32 table_index, init_expr_type, func_index_count; uint64 init_expr_value, size1; + read_uint32(buf, buf_end, table_index); read_uint32(buf, buf_end, init_expr_type); read_uint64(buf, buf_end, init_expr_value); read_uint32(buf, buf_end, func_index_count); @@ -485,6 +555,7 @@ load_table_init_data_list(const uint8 **p_buf, const uint8 *buf_end, return false; } + data_list[i]->table_index = table_index; data_list[i]->offset.init_expr_type = (uint8)init_expr_type; data_list[i]->offset.u.i64 = (int64)init_expr_value; data_list[i]->func_index_count = func_index_count; @@ -504,7 +575,16 @@ load_table_info(const uint8 **p_buf, const uint8 *buf_end, { const uint8 *buf = *p_buf; - read_uint32(buf, buf_end, module->table_size); + read_uint32(buf, buf_end, module->import_table_count); + /* We don't support import_table_count > 0 currently */ + bh_assert(module->import_table_count == 0); + + read_uint32(buf, buf_end, module->table_count); + if (module->table_count > 0 + && !load_table_list(&buf, buf_end, module, + error_buf, error_buf_size)) + return false; + read_uint32(buf, buf_end, module->table_init_data_count); /* load table init data list */ @@ -1088,40 +1168,42 @@ fail: } static void -destroy_export_funcs(AOTExportFunc *export_funcs, bool is_jit_mode) +destroy_exports(AOTExport *exports, bool is_jit_mode) { if (!is_jit_mode) - wasm_runtime_free(export_funcs); + wasm_runtime_free(exports); } static bool -load_export_funcs(const uint8 **p_buf, const uint8 *buf_end, - AOTModule *module, - char *error_buf, uint32 error_buf_size) +load_exports(const uint8 **p_buf, const uint8 *buf_end, + AOTModule *module, char *error_buf, uint32 error_buf_size) { const uint8 *buf = *p_buf; - AOTExportFunc *export_funcs; + AOTExport *exports; uint64 size; uint32 i; /* Allocate memory */ - size = sizeof(AOTExportFunc) * (uint64)module->export_func_count; - if (!(module->export_funcs = export_funcs = + size = sizeof(AOTExport) * (uint64)module->export_count; + if (!(module->exports = exports = loader_malloc(size, error_buf, error_buf_size))) { return false; } - /* Create each export func */ - for (i = 0; i < module->export_func_count; i++) { - read_uint32(buf, buf_end, export_funcs[i].func_index); - if (export_funcs[i].func_index >= + /* Create each export */ + for (i = 0; i < module->export_count; i++) { + read_uint32(buf, buf_end, exports[i].index); + read_uint8(buf, buf_end, exports[i].kind); + read_string(buf, buf_end, exports[i].name); +#if 0 /* TODO: check kind and index */ + if (export_funcs[i].index >= module->func_count + module->import_func_count) { set_error_buf(error_buf, error_buf_size, "AOT module load failed: " "function index is out of range."); return false; } - read_string(buf, buf_end, export_funcs[i].func_name); +#endif } *p_buf = buf; @@ -1138,9 +1220,9 @@ load_export_section(const uint8 *buf, const uint8 *buf_end, const uint8 *p = buf, *p_end = buf_end; /* load export functions */ - read_uint32(p, p_end, module->export_func_count); - if (module->export_func_count > 0 - && !load_export_funcs(&p, p_end, module, error_buf, error_buf_size)) + read_uint32(p, p_end, module->export_count); + if (module->export_count > 0 + && !load_exports(&p, p_end, module, error_buf, error_buf_size)) return false; if (p != p_end) { @@ -1385,12 +1467,11 @@ load_relocation_section(const uint8 *buf, const uint8 *buf_end, { AOTRelocationGroup *groups = NULL, *group; uint32 symbol_count = 0; - uint32 group_count = 0, i, j, func_index, func_type_index; + uint32 group_count = 0, i, j; uint64 size; uint32 *symbol_offsets, total_string_len; uint8 *symbol_buf, *symbol_buf_end; bool ret = false; - AOTExportFunc *export_func; read_uint32(buf, buf_end, symbol_count); @@ -1510,21 +1591,6 @@ load_relocation_section(const uint8 *buf, const uint8 *buf_end, } } - export_func = module->export_funcs; - for (i = 0; i < module->export_func_count; i++, export_func++) { - func_index = export_func->func_index - module->import_func_count; - if (func_index >= module->func_count) { - set_error_buf(error_buf, error_buf_size, - "AOT module load failed: " - "invalid export function index."); - ret = false; - goto fail; - } - func_type_index = module->func_type_indexes[func_index]; - export_func->func_type = module->func_types[func_type_index]; - export_func->func_ptr = module->func_ptrs[func_index]; - } - ret = true; fail: @@ -1621,17 +1687,13 @@ static void aot_free(void *ptr) static AOTModule* create_module(char *error_buf, uint32 error_buf_size) { - AOTModule *module = wasm_runtime_malloc(sizeof(AOTModule)); + AOTModule *module = + loader_malloc(sizeof(AOTModule), error_buf, error_buf_size); if (!module) { - set_error_buf(error_buf, error_buf_size, - "AOT module load failed: " - "allocate memory failed."); return NULL; } - memset(module, 0, sizeof(AOTModule)); - module->module_type = Wasm_Module_AoT; if (!(module->const_str_set = @@ -1703,10 +1765,9 @@ create_sections(const uint8 *buf, uint32 size, read_uint32(p, p_end, section_size); CHECK_BUF(p, p_end, section_size); - if (!(section = wasm_runtime_malloc(sizeof(AOTSection)))) { - set_error_buf(error_buf, error_buf_size, - "AOT module load failed: " - "allocate memory failed."); + if (!(section = + loader_malloc(sizeof(AOTSection), + error_buf, error_buf_size))) { goto fail; } @@ -1858,25 +1919,38 @@ aot_load_from_comp_data(AOTCompData *comp_data, AOTCompContext *comp_ctx, AOTModule *module; /* Allocate memory for module */ - if (!(module = wasm_runtime_malloc(sizeof(AOTModule)))) { - set_error_buf(error_buf, error_buf_size, - "Allocate memory for AOT module failed."); + if (!(module = + loader_malloc(sizeof(AOTModule), error_buf, error_buf_size))) { return NULL; } - memset(module, 0, sizeof(AOTModule)); - module->module_type = Wasm_Module_AoT; - module->num_bytes_per_page = comp_data->num_bytes_per_page; - module->mem_init_page_count = comp_data->mem_init_page_count; - module->mem_max_page_count = comp_data->mem_max_page_count; + + module->import_memory_count = comp_data->import_memory_count; + module->import_memories = comp_data->import_memories; + + module->memory_count = comp_data->memory_count; + if (module->memory_count) { + size = sizeof(AOTMemory) * (uint64)module->memory_count; + if (!(module->memories = + loader_malloc(size, error_buf, error_buf_size))) { + goto fail1; + } + + bh_memcpy_s(module->memories, size, comp_data->memories, size); + } module->mem_init_data_list = comp_data->mem_init_data_list; module->mem_init_data_count = comp_data->mem_init_data_count; + module->import_table_count = comp_data->import_table_count; + module->import_tables = comp_data->import_tables; + + module->table_count = comp_data->table_count; + module->tables = comp_data->tables; + module->table_init_data_list = comp_data->table_init_data_list; module->table_init_data_count = comp_data->table_init_data_count; - module->table_size = comp_data->table_size; module->func_type_count = comp_data->func_type_count; module->func_types = comp_data->func_types; @@ -1899,15 +1973,13 @@ aot_load_from_comp_data(AOTCompData *comp_data, AOTCompContext *comp_ctx, /* Allocate memory for function pointers */ size = (uint64)module->func_count * sizeof(void *); - if (size >= UINT32_MAX - || !(module->func_ptrs = wasm_runtime_malloc((uint32)size))) { - set_error_buf(error_buf, error_buf_size, "Create func ptrs fail."); - goto fail1; + if (!(module->func_ptrs = + loader_malloc(size, error_buf, error_buf_size))) { + goto fail2; } /* Resolve function addresses */ bh_assert(comp_ctx->exec_engine); - memset(module->func_ptrs, 0, (uint32)size); for (i = 0; i < comp_data->func_count; i++) { snprintf(func_name, sizeof(func_name), "%s%d", AOT_FUNC_PREFIX, i); if (!(module->func_ptrs[i] = @@ -1915,30 +1987,21 @@ aot_load_from_comp_data(AOTCompData *comp_data, AOTCompContext *comp_ctx, func_name))) { set_error_buf(error_buf, error_buf_size, "Get function address fail."); - goto fail2; + goto fail3; } } /* Allocation memory for function type indexes */ size = (uint64)module->func_count * sizeof(uint32); - if (size >= UINT32_MAX - || !(module->func_type_indexes = wasm_runtime_malloc((uint32)size))) { - set_error_buf(error_buf, error_buf_size, "Create func type indexes fail."); - goto fail2; + if (!(module->func_type_indexes = + loader_malloc(size, error_buf, error_buf_size))) { + goto fail3; } - memset(module->func_type_indexes, 0, (uint32)size); for (i = 0; i < comp_data->func_count; i++) module->func_type_indexes[i] = comp_data->funcs[i]->func_type_index; - module->export_func_count = comp_data->export_func_count; - module->export_funcs = comp_data->export_funcs; - - /* Set export function pointers */ - for (i = 0; i < module->export_func_count; i++) { - module->export_funcs[i].func_ptr = - module->func_ptrs[module->export_funcs[i].func_index - - module->import_func_count]; - } + module->export_count = comp_data->wasm_module->export_count; + module->exports = comp_data->wasm_module->exports; module->start_func_index = comp_data->start_func_index; if (comp_data->start_func_index != (uint32)-1) { @@ -1975,8 +2038,11 @@ aot_load_from_comp_data(AOTCompData *comp_data, AOTCompContext *comp_ctx, return module; -fail2: +fail3: wasm_runtime_free(module->func_ptrs); +fail2: + if (module->memory_count > 0) + wasm_runtime_free(module->memories); fail1: wasm_runtime_free(module); return NULL; @@ -2001,6 +2067,9 @@ aot_convert_wasm_module(WASMModule *wasm_module, } option.is_jit_mode = true; +#if WASM_ENABLE_THREAD_MGR != 0 + option.enable_thread_mgr = true; +#endif comp_ctx = aot_create_comp_context(comp_data, &option); if (!comp_ctx) { aot_last_error = aot_get_last_error(); @@ -2046,11 +2115,25 @@ aot_unload(AOTModule *module) wasm_loader_unload(module->wasm_module); #endif + if (module->import_memories) + destroy_import_memories(module->import_memories, + module->is_jit_mode); + + if (module->memories) + wasm_runtime_free(module->memories); + if (module->mem_init_data_list) destroy_mem_init_data_list(module->mem_init_data_list, module->mem_init_data_count, module->is_jit_mode); + if (module->import_tables) + destroy_import_tables(module->import_tables, + module->is_jit_mode); + + if (module->tables) + destroy_tables(module->tables, module->is_jit_mode); + if (module->table_init_data_list) destroy_table_init_data_list(module->table_init_data_list, module->table_init_data_count, @@ -2073,9 +2156,9 @@ aot_unload(AOTModule *module) destroy_import_funcs(module->import_funcs, module->is_jit_mode); - if (module->export_funcs) - destroy_export_funcs(module->export_funcs, - module->is_jit_mode); + if (module->exports) + destroy_exports(module->exports, + module->is_jit_mode); if (module->func_type_indexes) wasm_runtime_free(module->func_type_indexes); diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index 7805b1f9e..d3fe3f690 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -6,6 +6,9 @@ #include "aot_runtime.h" #include "bh_log.h" #include "mem_alloc.h" +#if WASM_ENABLE_SHARED_MEMORY != 0 +#include "../common/wasm_shared_memory.h" +#endif static void set_error_buf(char *error_buf, uint32 error_buf_size, const char *string) @@ -38,7 +41,7 @@ global_instantiate(AOTModuleInstance *module_inst, AOTModule *module, uint32 i; InitializerExpression *init_expr; uint8 *p = (uint8*)module_inst->global_data.ptr; - AOTImportGlobal *import_global = module->import_globals;; + AOTImportGlobal *import_global = module->import_globals; AOTGlobal *global = module->globals; /* Initialize import global data */ @@ -146,22 +149,93 @@ table_instantiate(AOTModuleInstance *module_inst, AOTModule *module, return true; } -static bool +static void +memories_deinstantiate(AOTModuleInstance *module_inst) +{ + uint32 i; + AOTMemoryInstance *memory_inst; + + for (i = 0; i < module_inst->memory_count; i++) { + memory_inst = ((AOTMemoryInstance **)module_inst->memories.ptr)[i]; + if (memory_inst) { +#if WASM_ENABLE_SHARED_MEMORY != 0 + if (memory_inst->is_shared) { + int32 ref_count = + shared_memory_dec_reference( + (WASMModuleCommon *)module_inst->aot_module.ptr); + bh_assert(ref_count >= 0); + + /* if the reference count is not zero, + don't free the memory */ + if (ref_count > 0) + continue; + } +#endif + if (memory_inst->heap_handle.ptr) + mem_allocator_destroy(memory_inst->heap_handle.ptr); + + if (memory_inst->heap_data.ptr) { +#ifndef OS_ENABLE_HW_BOUND_CHECK + wasm_runtime_free(memory_inst->heap_data.ptr); +#else + os_munmap((uint8*)memory_inst->memory_data.ptr - 2 * (uint64)BH_GB, + 8 * (uint64)BH_GB); +#endif + } + } + } + wasm_runtime_free(module_inst->memories.ptr); +} + +static AOTMemoryInstance* memory_instantiate(AOTModuleInstance *module_inst, AOTModule *module, + AOTMemoryInstance *memory_inst, AOTMemory *memory, uint32 heap_size, char *error_buf, uint32 error_buf_size) { - uint32 i, global_index, global_data_offset, base_offset, length; - AOTMemInitData *data_seg; void *heap_handle; - uint64 memory_data_size = (uint64)module->num_bytes_per_page - * module->mem_init_page_count; + uint64 memory_data_size = (uint64)memory->num_bytes_per_page + * memory->mem_init_page_count; uint64 total_size = heap_size + memory_data_size; uint8 *p; +#if WASM_ENABLE_SHARED_MEMORY != 0 + AOTMemoryInstance *shared_memory_instance; + bool is_shared_memory = memory->memory_flags & 0x02 ? true : false; + uint64 max_memory_data_size = (uint64)memory->num_bytes_per_page + * memory->mem_max_page_count; + + /* Shared memory */ + if (is_shared_memory) { + WASMSharedMemNode *node = + wasm_module_get_shared_memory((WASMModuleCommon *)module); + /* If the memory of this module has been instantiated, + return the memory instance directly */ + if (node) { + uint32 ref_count; + ref_count = shared_memory_inc_reference( + (WASMModuleCommon *)module); + bh_assert(ref_count > 0); + shared_memory_instance = + (AOTMemoryInstance *)shared_memory_get_memory_inst(node); + bh_assert(shared_memory_instance); + + /* Set the shared memory flag, so the runtime will get the + actual memory inst through module_inst->memories array */ + memory_inst->is_shared = true; + (void)ref_count; + return shared_memory_instance; + } +#ifndef OS_ENABLE_HW_BOUND_CHECK + /* Allocate max page for shared memory */ + total_size = heap_size + max_memory_data_size; +#endif + } +#endif + #ifndef OS_ENABLE_HW_BOUND_CHECK /* Allocate memory */ if (!(p = runtime_malloc(total_size, error_buf, error_buf_size))) { - return false; + return NULL; } #else uint8 *mapped_mem; @@ -178,7 +252,7 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModule *module, MMAP_PROT_NONE, MMAP_MAP_NONE))) { set_error_buf(error_buf, error_buf_size, "AOT module instantiate failed: mmap memory failed."); - return false; + return NULL; } p = mapped_mem + 2 * (uint64)BH_GB - heap_size; @@ -186,40 +260,128 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModule *module, set_error_buf(error_buf, error_buf_size, "AOT module instantiate failed: mprotec memory failed."); os_munmap(mapped_mem, map_size); - return false; + return NULL; } memset(p, 0, (uint32)total_size); #endif + memory_inst->module_type = Wasm_Module_AoT; /* Initialize heap info */ - module_inst->heap_data.ptr = p; + memory_inst->heap_data.ptr = p; p += heap_size; - module_inst->heap_data_end.ptr = p; - module_inst->heap_data_size = heap_size; - module_inst->heap_base_offset = -(int32)heap_size; + memory_inst->heap_data_end.ptr = p; + memory_inst->heap_data_size = heap_size; + memory_inst->heap_base_offset = -(int32)heap_size; if (heap_size > 0) { - if (!(heap_handle = mem_allocator_create(module_inst->heap_data.ptr, + if (!(heap_handle = mem_allocator_create(memory_inst->heap_data.ptr, heap_size))) { set_error_buf(error_buf, error_buf_size, - "AOT module instantiate failed: init app heap failed."); + "AOT module instantiate failed:" + "init app heap failed."); goto fail1; } - module_inst->heap_handle.ptr = heap_handle; + memory_inst->heap_handle.ptr = heap_handle; } /* Init memory info */ - module_inst->memory_data.ptr = p; - p += (uint32)memory_data_size; - module_inst->memory_data_end.ptr = p; - module_inst->memory_data_size = (uint32)memory_data_size; - module_inst->mem_cur_page_count = module->mem_init_page_count; - module_inst->mem_max_page_count = module->mem_max_page_count; + memory_inst->memory_data.ptr = p; +#if WASM_ENABLE_SHARED_MEMORY != 0 + if (is_shared_memory) { + p += (uint32)max_memory_data_size; + } + else +#endif + { + p += (uint32)memory_data_size; + } + memory_inst->memory_data_end.ptr = p; + memory_inst->memory_data_size = (uint32)memory_data_size; + memory_inst->mem_cur_page_count = memory->mem_init_page_count; + memory_inst->mem_max_page_count = memory->mem_max_page_count; - module_inst->mem_bound_check_heap_base = (int64)module_inst->heap_base_offset; - module_inst->mem_bound_check_1byte = (int64)module_inst->memory_data_size - 1; - module_inst->mem_bound_check_2bytes = (int64)module_inst->memory_data_size - 2; - module_inst->mem_bound_check_4bytes = (int64)module_inst->memory_data_size - 4; - module_inst->mem_bound_check_8bytes = (int64)module_inst->memory_data_size - 8; + memory_inst->mem_bound_check_heap_base = memory_inst->heap_base_offset; + memory_inst->mem_bound_check_1byte = + (int64)memory_inst->memory_data_size - 1; + memory_inst->mem_bound_check_2bytes = + (int64)memory_inst->memory_data_size - 2; + memory_inst->mem_bound_check_4bytes = + (int64)memory_inst->memory_data_size - 4; + memory_inst->mem_bound_check_8bytes = + (int64)memory_inst->memory_data_size - 8; + +#if WASM_ENABLE_SHARED_MEMORY != 0 + if (is_shared_memory) { + memory_inst->is_shared = true; + if (!shared_memory_set_memory_inst((WASMModuleCommon *)module, + (WASMMemoryInstanceCommon *)memory_inst)) { + set_error_buf(error_buf, error_buf_size, + "Instantiate memory failed:" + "allocate memory failed."); + goto fail2; + } + } +#endif + + return memory_inst; + +#if WASM_ENABLE_SHARED_MEMORY != 0 +fail2: + if (heap_size > 0) { + mem_allocator_destroy(memory_inst->heap_handle.ptr); + memory_inst->heap_handle.ptr = NULL; + } +#endif +fail1: +#ifndef OS_ENABLE_HW_BOUND_CHECK + wasm_runtime_free(memory_inst->heap_data.ptr); +#else + os_munmap(mapped_mem, map_size); +#endif + memory_inst->heap_data.ptr = NULL; + return NULL; +} + +static AOTMemoryInstance* +aot_get_default_memory(AOTModuleInstance *module_inst) +{ + if (module_inst->memories.ptr) + return ((AOTMemoryInstance **)module_inst->memories.ptr)[0]; + else + return NULL; +} + +static bool +memories_instantiate(AOTModuleInstance *module_inst, AOTModule *module, + uint32 heap_size, char *error_buf, uint32 error_buf_size) +{ + uint32 global_index, global_data_offset, base_offset, length; + uint32 i, memory_count = module->memory_count; + AOTMemoryInstance *memories, *memory_inst; + AOTMemInitData *data_seg; + uint64 total_size; + + module_inst->memory_count = memory_count; + total_size = sizeof(AOTPointer) * (uint64)memory_count; + if (!(module_inst->memories.ptr = + runtime_malloc(total_size, error_buf, error_buf_size))) { + return false; + } + + memories = module_inst->global_table_data.memory_instances; + for (i = 0; i < memory_count; i++, memories++) { + memory_inst = + memory_instantiate(module_inst, module, + memories, &module->memories[i], + heap_size, error_buf, error_buf_size); + if (!memory_inst) { + return false; + } + + ((AOTMemoryInstance **)module_inst->memories.ptr)[i] = memory_inst; + } + + /* Get default memory instance */ + memory_inst = aot_get_default_memory(module_inst); for (i = 0; i < module->mem_init_data_count; i++) { data_seg = module->mem_init_data_list[i]; @@ -255,47 +417,34 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModule *module, } /* Copy memory data */ - bh_assert(module_inst->memory_data.ptr); + bh_assert(memory_inst->memory_data.ptr); /* Check memory data */ /* check offset since length might negative */ - if (base_offset > module_inst->memory_data_size) { + if (base_offset > memory_inst->memory_data_size) { LOG_DEBUG("base_offset(%d) > memory_data_size(%d)", base_offset, - module_inst->memory_data_size); + memory_inst->memory_data_size); set_error_buf(error_buf, error_buf_size, "data segment does not fit"); - goto fail2; + return false; } /* check offset + length(could be zero) */ length = data_seg->byte_count; - if (base_offset + length > module_inst->memory_data_size) { + if (base_offset + length > memory_inst->memory_data_size) { LOG_DEBUG("base_offset(%d) + length(%d) > memory_data_size(%d)", - base_offset, length, module_inst->memory_data_size); + base_offset, length, memory_inst->memory_data_size); set_error_buf(error_buf, error_buf_size, "data segment does not fit"); - goto fail2; + return false; } - memcpy((uint8*)module_inst->memory_data.ptr + base_offset, - data_seg->bytes, length); + bh_memcpy_s((uint8*)memory_inst->memory_data.ptr + base_offset, + memory_inst->memory_data_size - base_offset, + data_seg->bytes, length); } return true; - -fail2: - if (heap_size > 0) { - mem_allocator_destroy(module_inst->heap_handle.ptr); - module_inst->heap_handle.ptr = NULL; - } -fail1: -#ifndef OS_ENABLE_HW_BOUND_CHECK - wasm_runtime_free(module_inst->heap_data.ptr); -#else - os_munmap(mapped_mem, map_size); -#endif - module_inst->heap_data.ptr = NULL; - return false; } static bool @@ -349,6 +498,64 @@ init_func_type_indexes(AOTModuleInstance *module_inst, AOTModule *module, return true; } +static bool +create_export_funcs(AOTModuleInstance *module_inst, AOTModule *module, + char *error_buf, uint32 error_buf_size) +{ + AOTExport *exports = module->exports; + AOTFunctionInstance *export_func; + uint64 size; + uint32 i, func_index, ftype_index; + + for (i = 0; i < module->export_count; i++) { + if (exports[i].kind == EXPORT_KIND_FUNC) + module_inst->export_func_count++; + } + + if (module_inst->export_func_count > 0) { + /* Allocate memory */ + size = sizeof(AOTFunctionInstance) + * (uint64)module_inst->export_func_count; + if (!(module_inst->export_funcs.ptr = export_func = + runtime_malloc(size, error_buf, error_buf_size))) { + return false; + } + + for (i = 0; i < module->export_count; i++) { + if (exports[i].kind == EXPORT_KIND_FUNC) { + export_func->func_name = exports[i].name; + export_func->func_index = exports[i].index; + if (export_func->func_index < module->import_func_count) { + export_func->is_import_func = true; + export_func->u.func_import = + &module->import_funcs[export_func->func_index]; + } + else { + export_func->is_import_func = false; + func_index = export_func->func_index + - module->import_func_count; + ftype_index = module->func_type_indexes[func_index]; + export_func->u.func.func_type = + module->func_types[ftype_index]; + export_func->u.func.func_ptr = + module->func_ptrs[func_index]; + } + export_func++; + } + } + } + + return true; +} + +static bool +create_exports(AOTModuleInstance *module_inst, AOTModule *module, + char *error_buf, uint32 error_buf_size) +{ + return create_export_funcs(module_inst, module, + error_buf, error_buf_size); +} + static bool execute_post_inst_function(AOTModuleInstance *module_inst) { @@ -386,6 +593,22 @@ execute_start_function(AOTModuleInstance *module_inst) return !aot_get_exception(module_inst); } +#if WASM_ENABLE_BULK_MEMORY != 0 +static bool +execute_memory_init_function(AOTModuleInstance *module_inst) +{ + AOTFunctionInstance *memory_init_func = + aot_lookup_function(module_inst, "__wasm_call_ctors", "()"); + + if (!memory_init_func) + /* Not found */ + return true; + + return aot_create_exec_env_and_call_function(module_inst, memory_init_func, + 0, NULL); +} +#endif + AOTModuleInstance* aot_instantiate(AOTModule *module, bool is_sub_inst, uint32 stack_size, uint32 heap_size, @@ -394,8 +617,13 @@ aot_instantiate(AOTModule *module, bool is_sub_inst, AOTModuleInstance *module_inst; uint32 module_inst_struct_size = offsetof(AOTModuleInstance, global_table_data.bytes); - uint64 table_data_size = (uint64)module->table_size * sizeof(uint32); + uint64 module_inst_mem_inst_size = + (uint64)module->memory_count * sizeof(AOTMemoryInstance); + uint32 table_size = module->table_count > 0 ? + module->tables[0].table_init_size : 0; + uint64 table_data_size = (uint64)table_size * sizeof(uint32); uint64 total_size = (uint64)module_inst_struct_size + + module_inst_mem_inst_size + module->global_data_size + table_data_size; uint8 *p; @@ -418,7 +646,8 @@ aot_instantiate(AOTModule *module, bool is_sub_inst, module_inst->aot_module.ptr = module; /* Initialize global info */ - p = (uint8*)module_inst + module_inst_struct_size; + p = (uint8*)module_inst + module_inst_struct_size + + module_inst_mem_inst_size; module_inst->global_data.ptr = p; module_inst->global_data_size = module->global_data_size; if (!global_instantiate(module_inst, module, error_buf, error_buf_size)) @@ -427,15 +656,15 @@ aot_instantiate(AOTModule *module, bool is_sub_inst, /* Initialize table info */ p += module->global_data_size; module_inst->table_data.ptr = p; - module_inst->table_size = module->table_size; + module_inst->table_size = table_size; /* Set all elements to -1 to mark them as uninitialized elements */ memset(module_inst->table_data.ptr, -1, (uint32)table_data_size); if (!table_instantiate(module_inst, module, error_buf, error_buf_size)) goto fail; /* Initialize memory space */ - if (!memory_instantiate(module_inst, module, heap_size, - error_buf, error_buf_size)) + if (!memories_instantiate(module_inst, module, heap_size, + error_buf, error_buf_size)) goto fail; /* Initialize function pointers */ @@ -446,19 +675,24 @@ aot_instantiate(AOTModule *module, bool is_sub_inst, if (!init_func_type_indexes(module_inst, module, error_buf, error_buf_size)) goto fail; -#if WASM_ENABLE_LIBC_WASI != 0 - if (heap_size > 0 - && !wasm_runtime_init_wasi((WASMModuleInstanceCommon*)module_inst, - module->wasi_args.dir_list, - module->wasi_args.dir_count, - module->wasi_args.map_dir_list, - module->wasi_args.map_dir_count, - module->wasi_args.env, - module->wasi_args.env_count, - module->wasi_args.argv, - module->wasi_args.argc, - error_buf, error_buf_size)) + if (!create_exports(module_inst, module, error_buf, error_buf_size)) goto fail; + +#if WASM_ENABLE_LIBC_WASI != 0 + if (!is_sub_inst) { + if (heap_size > 0 + && !wasm_runtime_init_wasi((WASMModuleInstanceCommon*)module_inst, + module->wasi_args.dir_list, + module->wasi_args.dir_count, + module->wasi_args.map_dir_list, + module->wasi_args.map_dir_count, + module->wasi_args.env, + module->wasi_args.env_count, + module->wasi_args.argv, + module->wasi_args.argc, + error_buf, error_buf_size)) + goto fail; + } #endif /* Initialize the thread related data */ @@ -478,6 +712,25 @@ aot_instantiate(AOTModule *module, bool is_sub_inst, goto fail; } +#if WASM_ENABLE_BULK_MEMORY != 0 +#if WASM_ENABLE_LIBC_WASI != 0 + if (!module->is_wasi_module) { +#endif + /* Only execute the memory init function for main instance because + the data segments will be dropped once initialized. + */ + if (!is_sub_inst) { + if (!execute_memory_init_function(module_inst)) { + set_error_buf(error_buf, error_buf_size, + module_inst->cur_exception); + goto fail; + } + } +#if WASM_ENABLE_LIBC_WASI != 0 + } +#endif +#endif + return module_inst; fail: @@ -498,17 +751,11 @@ aot_deinstantiate(AOTModuleInstance *module_inst, bool is_sub_inst) wasm_runtime_destroy_wasi((WASMModuleInstanceCommon*)module_inst); #endif - if (module_inst->heap_handle.ptr) - mem_allocator_destroy(module_inst->heap_handle.ptr); + if (module_inst->memories.ptr) + memories_deinstantiate(module_inst); - if (module_inst->heap_data.ptr) { -#ifndef OS_ENABLE_HW_BOUND_CHECK - wasm_runtime_free(module_inst->heap_data.ptr); -#else - os_munmap((uint8*)module_inst->memory_data.ptr - 2 * (uint64)BH_GB, - 8 * (uint64)BH_GB); -#endif - } + if (module_inst->export_funcs.ptr) + wasm_runtime_free(module_inst->export_funcs.ptr); if (module_inst->func_ptrs.ptr) wasm_runtime_free(module_inst->func_ptrs.ptr); @@ -524,11 +771,12 @@ aot_lookup_function(const AOTModuleInstance *module_inst, const char *name, const char *signature) { uint32 i; - AOTModule *module = (AOTModule*)module_inst->aot_module.ptr; + AOTFunctionInstance *export_funcs = (AOTFunctionInstance *) + module_inst->export_funcs.ptr; - for (i = 0; i < module->export_func_count; i++) - if (!strcmp(module->export_funcs[i].func_name, name)) - return &module->export_funcs[i]; + for (i = 0; i < module_inst->export_func_count; i++) + if (!strcmp(export_funcs[i].func_name, name)) + return &export_funcs[i]; (void)signature; return NULL; } @@ -565,6 +813,7 @@ static void aot_signal_handler(void *sig_addr) { AOTModuleInstance *module_inst; + AOTMemoryInstance *memory_inst; WASMJmpBuf *jmpbuf_node; uint8 *mapped_mem_start_addr, *mapped_mem_end_addr; uint8 *stack_min_addr; @@ -577,17 +826,22 @@ aot_signal_handler(void *sig_addr) && (jmpbuf_node = aot_exec_env->jmpbuf_stack_top)) { /* Get mapped mem info of current instance */ module_inst = (AOTModuleInstance *)aot_exec_env->module_inst; - mapped_mem_start_addr = (uint8*)module_inst->memory_data.ptr - - 2 * (uint64)BH_GB; - mapped_mem_end_addr = (uint8*)module_inst->memory_data.ptr - + 6 * (uint64)BH_GB; + /* Get the default memory instance */ + memory_inst = aot_get_default_memory(module_inst); + if (memory_inst) { + mapped_mem_start_addr = (uint8*)memory_inst->memory_data.ptr + - 2 * (uint64)BH_GB; + mapped_mem_end_addr = (uint8*)memory_inst->memory_data.ptr + + 6 * (uint64)BH_GB; + } /* Get stack info of current thread */ page_size = os_getpagesize(); stack_min_addr = get_stack_min_addr(aot_exec_env, page_size); - if (mapped_mem_start_addr <= (uint8*)sig_addr - && (uint8*)sig_addr < mapped_mem_end_addr) { + if (memory_inst + && (mapped_mem_start_addr <= (uint8*)sig_addr + && (uint8*)sig_addr < mapped_mem_end_addr)) { /* The address which causes segmentation fault is inside aot instance's guard regions */ aot_set_exception_with_id(module_inst, EXCE_OUT_OF_BOUNDS_MEMORY_ACCESS); @@ -721,7 +975,7 @@ aot_call_function(WASMExecEnv *exec_env, unsigned argc, uint32 argv[]) { AOTModuleInstance *module_inst = (AOTModuleInstance*)exec_env->module_inst; - AOTFuncType *func_type = function->func_type; + AOTFuncType *func_type = function->u.func.func_type; uint32 result_count = func_type->result_count; uint32 ext_ret_count = result_count > 1 ? result_count - 1 : 0; bool ret; @@ -758,7 +1012,7 @@ aot_call_function(WASMExecEnv *exec_env, cell_num += wasm_value_type_cell_num(ext_ret_types[i]); } - ret = invoke_native_internal(exec_env, function->func_ptr, + ret = invoke_native_internal(exec_env, function->u.func.func_ptr, func_type, NULL, NULL, argv1, argc, argv); if (!ret || aot_get_exception(module_inst)) { if (argv1 != argv1_buf) @@ -789,7 +1043,7 @@ aot_call_function(WASMExecEnv *exec_env, return true; } else { - ret = invoke_native_internal(exec_env, function->func_ptr, + ret = invoke_native_internal(exec_env, function->u.func.func_ptr, func_type, NULL, NULL, argv, argc, argv); return ret && !aot_get_exception(module_inst) ? true : false; } @@ -894,24 +1148,26 @@ int32 aot_module_malloc(AOTModuleInstance *module_inst, uint32 size, void **p_native_addr) { - uint8 *addr = mem_allocator_malloc(module_inst->heap_handle.ptr, size); + AOTMemoryInstance *memory_inst = aot_get_default_memory(module_inst); + uint8 *addr = mem_allocator_malloc(memory_inst->heap_handle.ptr, size); if (!addr) { aot_set_exception(module_inst, "out of memory"); return 0; } if (p_native_addr) *p_native_addr = addr; - return (int32)(addr - (uint8*)module_inst->memory_data.ptr); + return (int32)(addr - (uint8*)memory_inst->memory_data.ptr); } void aot_module_free(AOTModuleInstance *module_inst, int32 ptr) { + AOTMemoryInstance *memory_inst = aot_get_default_memory(module_inst); if (ptr) { - uint8 *addr = (uint8*)module_inst->memory_data.ptr + ptr; - if ((uint8*)module_inst->heap_data.ptr < addr - && addr < (uint8*)module_inst->memory_data.ptr) - mem_allocator_free(module_inst->heap_handle.ptr, addr); + uint8 *addr = (uint8*)memory_inst->memory_data.ptr + ptr; + if ((uint8*)memory_inst->heap_data.ptr < addr + && addr < (uint8*)memory_inst->memory_data.ptr) + mem_allocator_free(memory_inst->heap_handle.ptr, addr); } } @@ -934,13 +1190,14 @@ bool aot_validate_app_addr(AOTModuleInstance *module_inst, int32 app_offset, uint32 size) { + AOTMemoryInstance *memory_inst = aot_get_default_memory(module_inst); /* integer overflow check */ if(app_offset + (int32)size < app_offset) { goto fail; } - if (module_inst->heap_base_offset <= app_offset - && app_offset + (int32)size <= (int32)module_inst->memory_data_size) { + if (memory_inst->heap_base_offset <= app_offset + && app_offset + (int32)size <= (int32)memory_inst->memory_data_size) { return true; } fail: @@ -953,15 +1210,16 @@ aot_validate_native_addr(AOTModuleInstance *module_inst, void *native_ptr, uint32 size) { uint8 *addr = (uint8*)native_ptr; - int32 memory_data_size = (int32)module_inst->memory_data_size; + AOTMemoryInstance *memory_inst = aot_get_default_memory(module_inst); + int32 memory_data_size = (int32)memory_inst->memory_data_size; /* integer overflow check */ if (addr + size < addr) { goto fail; } - if ((uint8*)module_inst->heap_data.ptr <= addr - && addr + size <= (uint8*)module_inst->memory_data.ptr + if ((uint8*)memory_inst->heap_data.ptr <= addr + && addr + size <= (uint8*)memory_inst->memory_data.ptr + memory_data_size) { return true; } @@ -973,11 +1231,12 @@ fail: void * aot_addr_app_to_native(AOTModuleInstance *module_inst, int32 app_offset) { - int32 memory_data_size = (int32)module_inst->memory_data_size; - uint8 *addr = (uint8 *)module_inst->memory_data.ptr + app_offset; + AOTMemoryInstance *memory_inst = aot_get_default_memory(module_inst); + int32 memory_data_size = (int32)memory_inst->memory_data_size; + uint8 *addr = (uint8 *)memory_inst->memory_data.ptr + app_offset; - if ((uint8*)module_inst->heap_data.ptr <= addr - && addr < (uint8*)module_inst->memory_data.ptr + if ((uint8*)memory_inst->heap_data.ptr <= addr + && addr < (uint8*)memory_inst->memory_data.ptr + memory_data_size) return addr; return NULL; @@ -987,12 +1246,13 @@ int32 aot_addr_native_to_app(AOTModuleInstance *module_inst, void *native_ptr) { uint8 *addr = (uint8*)native_ptr; - int32 memory_data_size = (int32)module_inst->memory_data_size; + AOTMemoryInstance *memory_inst = aot_get_default_memory(module_inst); + int32 memory_data_size = (int32)memory_inst->memory_data_size; - if ((uint8*)module_inst->heap_data.ptr <= addr - && addr < (uint8*)module_inst->memory_data.ptr + if ((uint8*)memory_inst->heap_data.ptr <= addr + && addr < (uint8*)memory_inst->memory_data.ptr + memory_data_size) - return (int32)(addr - (uint8*)module_inst->memory_data.ptr); + return (int32)(addr - (uint8*)memory_inst->memory_data.ptr); return 0; } @@ -1002,12 +1262,13 @@ aot_get_app_addr_range(AOTModuleInstance *module_inst, int32 *p_app_start_offset, int32 *p_app_end_offset) { - int32 memory_data_size = (int32)module_inst->memory_data_size; + AOTMemoryInstance *memory_inst = aot_get_default_memory(module_inst); + int32 memory_data_size = (int32)memory_inst->memory_data_size; - if (module_inst->heap_base_offset <= app_offset + if (memory_inst->heap_base_offset <= app_offset && app_offset < memory_data_size) { if (p_app_start_offset) - *p_app_start_offset = module_inst->heap_base_offset; + *p_app_start_offset = memory_inst->heap_base_offset; if (p_app_end_offset) *p_app_end_offset = memory_data_size; return true; @@ -1022,15 +1283,16 @@ aot_get_native_addr_range(AOTModuleInstance *module_inst, uint8 **p_native_end_addr) { uint8 *addr = (uint8*)native_ptr; - int32 memory_data_size = (int32)module_inst->memory_data_size; + AOTMemoryInstance *memory_inst = aot_get_default_memory(module_inst); + int32 memory_data_size = (int32)memory_inst->memory_data_size; - if ((uint8*)module_inst->heap_data.ptr <= addr - && addr < (uint8*)module_inst->memory_data.ptr + if ((uint8*)memory_inst->heap_data.ptr <= addr + && addr < (uint8*)memory_inst->memory_data.ptr + memory_data_size) { if (p_native_start_addr) - *p_native_start_addr = (uint8*)module_inst->heap_data.ptr; + *p_native_start_addr = (uint8*)memory_inst->heap_data.ptr; if (p_native_end_addr) - *p_native_end_addr = (uint8*)module_inst->memory_data.ptr + *p_native_end_addr = (uint8*)memory_inst->memory_data.ptr + memory_data_size; return true; } @@ -1041,18 +1303,19 @@ aot_get_native_addr_range(AOTModuleInstance *module_inst, bool aot_enlarge_memory(AOTModuleInstance *module_inst, uint32 inc_page_count) { - uint8 *heap_data_old = module_inst->heap_data.ptr, *heap_data; + AOTMemoryInstance *memory_inst = aot_get_default_memory(module_inst); + uint8 *heap_data_old = memory_inst->heap_data.ptr, *heap_data; uint32 num_bytes_per_page = - ((AOTModule*)module_inst->aot_module.ptr)->num_bytes_per_page; - uint32 cur_page_count = module_inst->mem_cur_page_count; - uint32 max_page_count = module_inst->mem_max_page_count; + ((AOTModule*)module_inst->aot_module.ptr)->memories[0].num_bytes_per_page; + uint32 cur_page_count = memory_inst->mem_cur_page_count; + uint32 max_page_count = memory_inst->mem_max_page_count; uint32 total_page_count = cur_page_count + inc_page_count; uint64 memory_data_size = (uint64)num_bytes_per_page * total_page_count; - uint32 heap_size = (uint32)((uint8*)module_inst->memory_data.ptr - - (uint8*)module_inst->heap_data.ptr); - uint32 total_size_old = heap_size + module_inst->memory_data_size; + uint32 heap_size = (uint32)((uint8*)memory_inst->memory_data.ptr + - (uint8*)memory_inst->heap_data.ptr); + uint32 total_size_old = heap_size + memory_inst->memory_data_size; uint64 total_size = heap_size + memory_data_size; - void *heap_handle_old = module_inst->heap_handle.ptr; + void *heap_handle_old = memory_inst->heap_handle.ptr; if (inc_page_count <= 0) /* No need to enlarge memory */ @@ -1069,16 +1332,25 @@ aot_enlarge_memory(AOTModuleInstance *module_inst, uint32 inc_page_count) return false; } +#if WASM_ENABLE_SHARED_MEMORY != 0 + if (memory_inst->is_shared) { + /* For shared memory, we have reserved the maximum spaces during + instantiate, only change the cur_page_count here */ + memory_inst->mem_cur_page_count = total_page_count; + return true; + } +#endif + if (heap_size > 0) { /* Destroy heap's lock firstly, if its memory is re-allocated, we cannot access its lock again. */ - mem_allocator_destroy_lock(module_inst->heap_handle.ptr); + mem_allocator_destroy_lock(memory_inst->heap_handle.ptr); } if (!(heap_data = wasm_runtime_realloc(heap_data_old, (uint32)total_size))) { if (!(heap_data = wasm_runtime_malloc((uint32)total_size))) { if (heap_size > 0) { /* Restore heap's lock if memory re-alloc failed */ - mem_allocator_reinit_lock(module_inst->heap_handle.ptr); + mem_allocator_reinit_lock(memory_inst->heap_handle.ptr); } aot_set_exception(module_inst, "fail to enlarge memory."); return false; @@ -1091,39 +1363,40 @@ aot_enlarge_memory(AOTModuleInstance *module_inst, uint32 inc_page_count) memset(heap_data + total_size_old, 0, (uint32)total_size - total_size_old); - module_inst->heap_data.ptr = heap_data; - module_inst->heap_data_end.ptr = heap_data + heap_size; + memory_inst->heap_data.ptr = heap_data; + memory_inst->heap_data_end.ptr = heap_data + heap_size; if (heap_size > 0) { - module_inst->heap_handle.ptr = (uint8*)heap_handle_old + memory_inst->heap_handle.ptr = (uint8*)heap_handle_old + (heap_data - heap_data_old); - if (mem_allocator_migrate(module_inst->heap_handle.ptr, + if (mem_allocator_migrate(memory_inst->heap_handle.ptr, heap_handle_old) != 0) { aot_set_exception(module_inst, "fail to enlarge memory."); return false; } } - module_inst->mem_cur_page_count = total_page_count; - module_inst->memory_data_size = (uint32)memory_data_size; - module_inst->memory_data.ptr = (uint8*)heap_data + heap_size; - module_inst->memory_data_end.ptr = (uint8*)module_inst->memory_data.ptr + memory_inst->mem_cur_page_count = total_page_count; + memory_inst->memory_data_size = (uint32)memory_data_size; + memory_inst->memory_data.ptr = (uint8*)heap_data + heap_size; + memory_inst->memory_data_end.ptr = (uint8*)memory_inst->memory_data.ptr + (uint32)memory_data_size; - module_inst->mem_bound_check_1byte = module_inst->memory_data_size - 1; - module_inst->mem_bound_check_2bytes = module_inst->memory_data_size - 2; - module_inst->mem_bound_check_4bytes = module_inst->memory_data_size - 4; - module_inst->mem_bound_check_8bytes = module_inst->memory_data_size - 8; + memory_inst->mem_bound_check_1byte = memory_inst->memory_data_size - 1; + memory_inst->mem_bound_check_2bytes = memory_inst->memory_data_size - 2; + memory_inst->mem_bound_check_4bytes = memory_inst->memory_data_size - 4; + memory_inst->mem_bound_check_8bytes = memory_inst->memory_data_size - 8; return true; } #else bool aot_enlarge_memory(AOTModuleInstance *module_inst, uint32 inc_page_count) { + AOTMemoryInstance *memory_inst = aot_get_default_memory(module_inst); uint32 num_bytes_per_page = - ((AOTModule*)module_inst->aot_module.ptr)->num_bytes_per_page; - uint32 cur_page_count = module_inst->mem_cur_page_count; - uint32 max_page_count = module_inst->mem_max_page_count; + ((AOTModule*)module_inst->aot_module.ptr)->memories[0].num_bytes_per_page; + uint32 cur_page_count = memory_inst->mem_cur_page_count; + uint32 max_page_count = memory_inst->mem_max_page_count; uint32 total_page_count = cur_page_count + inc_page_count; uint64 memory_data_size = (uint64)num_bytes_per_page * total_page_count; @@ -1137,24 +1410,24 @@ aot_enlarge_memory(AOTModuleInstance *module_inst, uint32 inc_page_count) return false; } - if (os_mprotect(module_inst->memory_data.ptr, memory_data_size, + if (os_mprotect(memory_inst->memory_data.ptr, memory_data_size, MMAP_PROT_READ | MMAP_PROT_WRITE) != 0) { aot_set_exception(module_inst, "fail to enlarge memory."); return false; } - memset(module_inst->memory_data_end.ptr, 0, + memset(memory_inst->memory_data_end.ptr, 0, num_bytes_per_page * inc_page_count); - module_inst->mem_cur_page_count = total_page_count; - module_inst->memory_data_size = (uint32)memory_data_size; - module_inst->memory_data_end.ptr = (uint8*)module_inst->memory_data.ptr + memory_inst->mem_cur_page_count = total_page_count; + memory_inst->memory_data_size = (uint32)memory_data_size; + memory_inst->memory_data_end.ptr = (uint8*)memory_inst->memory_data.ptr + (uint32)memory_data_size; - module_inst->mem_bound_check_1byte = module_inst->memory_data_size - 1; - module_inst->mem_bound_check_2bytes = module_inst->memory_data_size - 2; - module_inst->mem_bound_check_4bytes = module_inst->memory_data_size - 4; - module_inst->mem_bound_check_8bytes = module_inst->memory_data_size - 8; + memory_inst->mem_bound_check_1byte = memory_inst->memory_data_size - 1; + memory_inst->mem_bound_check_2bytes = memory_inst->memory_data_size - 2; + memory_inst->mem_bound_check_4bytes = memory_inst->memory_data_size - 4; + memory_inst->mem_bound_check_8bytes = memory_inst->memory_data_size - 8; return true; } #endif @@ -1389,6 +1662,7 @@ bool aot_memory_init(AOTModuleInstance *module_inst, uint32 seg_index, uint32 offset, uint32 len, uint32 dst) { + AOTMemoryInstance *memory_inst = aot_get_default_memory(module_inst); AOTModule *aot_module; uint8 *data = NULL; uint8 *maddr; @@ -1416,7 +1690,7 @@ aot_memory_init(AOTModuleInstance *module_inst, uint32 seg_index, maddr = aot_addr_app_to_native(module_inst, dst); - bh_memcpy_s(maddr, module_inst->memory_data_size - dst, + bh_memcpy_s(maddr, memory_inst->memory_data_size - dst, data + offset, len); return true; } @@ -1441,3 +1715,68 @@ aot_data_drop(AOTModuleInstance *module_inst, uint32 seg_index) return true; } #endif /* WASM_ENABLE_BULK_MEMORY */ + +#if WASM_ENABLE_THREAD_MGR != 0 +bool +aot_set_aux_stack(WASMExecEnv *exec_env, + uint32 start_offset, uint32 size) +{ + AOTModuleInstance *module_inst = + (AOTModuleInstance*)exec_env->module_inst; + AOTModule *module = (AOTModule *)module_inst->aot_module.ptr; + + uint32 stack_top_idx = + module->llvm_aux_stack_global_index; + uint32 data_end = + module->llvm_aux_data_end; + uint32 stack_bottom = + module->llvm_aux_stack_bottom; + bool is_stack_before_data = + stack_bottom < data_end ? true : false; + + /* Check the aux stack space, currently we don't allocate space in heap */ + if ((is_stack_before_data && (size > start_offset)) + || ((!is_stack_before_data) && (start_offset - data_end < size))) + return false; + + if ((stack_bottom != (uint32)-1) && (stack_top_idx != (uint32)-1)) { + /* The aux stack top is a wasm global, + set the initial value for the global */ + uint32 global_offset = + module->globals[stack_top_idx].data_offset; + uint8 *global_addr = module_inst->global_data.ptr + global_offset; + *(int32*)global_addr = start_offset; + + /* The aux stack boundary is a constant value, + set the value to exec_env */ + exec_env->aux_stack_boundary = start_offset - size; + return true; + } + + return false; +} + +bool +aot_get_aux_stack(WASMExecEnv *exec_env, + uint32 *start_offset, uint32 *size) +{ + AOTModuleInstance *module_inst = + (AOTModuleInstance*)exec_env->module_inst; + AOTModule *module = (AOTModule *)module_inst->aot_module.ptr; + + /* The aux stack information is resolved in loader + and store in module */ + uint32 stack_bottom = module->llvm_aux_stack_bottom; + uint32 total_aux_stack_size = module->llvm_aux_stack_size; + + if (stack_bottom != 0 && total_aux_stack_size != 0) { + if (start_offset) + *start_offset = stack_bottom; + if (size) + *size = total_aux_stack_size; + return true; + } + return false; +} + +#endif diff --git a/core/iwasm/aot/aot_runtime.h b/core/iwasm/aot/aot_runtime.h index a2f4908a7..0678a701c 100644 --- a/core/iwasm/aot/aot_runtime.h +++ b/core/iwasm/aot/aot_runtime.h @@ -69,18 +69,45 @@ typedef struct AOTRelocationGroup { AOTRelocation *relocations; } AOTRelocationGroup; +/* AOT function instance */ +typedef struct AOTFunctionInstance { + char *func_name; + uint32 func_index; + bool is_import_func; + union { + struct { + AOTFuncType *func_type; + /* function pointer linked */ + void *func_ptr; + } func; + AOTImportFunc *func_import; + } u; +} AOTFunctionInstance; + typedef struct AOTModule { uint32 module_type; + /* import memories */ + uint32 import_memory_count; + AOTImportMemory *import_memories; + /* memory info */ - uint32 num_bytes_per_page; - uint32 mem_init_page_count; - uint32 mem_max_page_count; + uint32 memory_count; + AOTMemory *memories; + + /* init data */ uint32 mem_init_data_count; AOTMemInitData **mem_init_data_list; - /* table info */ - uint32 table_size; + /* import tables */ + uint32 import_table_count; + AOTImportTable *import_tables; + + /* tables */ + uint32 table_count; + AOTTable *tables; + + /* table init data info */ uint32 table_init_data_count; AOTTableInitData **table_init_data_list; @@ -110,9 +137,9 @@ typedef struct AOTModule { /* function type indexes */ uint32 *func_type_indexes; - /* export function info */ - uint32 export_func_count; - AOTExportFunc *export_funcs; + /* export info */ + uint32 export_count; + AOTExport *exports; /* start function index, -1 denotes no start function */ uint32 start_func_index; @@ -160,13 +187,15 @@ typedef union { void *ptr; } AOTPointer; -typedef struct AOTModuleInstance { +typedef struct AOTMemoryInstance { uint32 module_type; - + /* shared memory flag */ + bool is_shared; /* memory space info */ uint32 mem_cur_page_count; uint32 mem_max_page_count; uint32 memory_data_size; + uint32 __padding__; AOTPointer memory_data; AOTPointer memory_data_end; @@ -177,6 +206,21 @@ typedef struct AOTModuleInstance { AOTPointer heap_data_end; AOTPointer heap_handle; + /* boundary check constants for aot code */ + int64 mem_bound_check_heap_base; + int64 mem_bound_check_1byte; + int64 mem_bound_check_2bytes; + int64 mem_bound_check_4bytes; + int64 mem_bound_check_8bytes; +} AOTMemoryInstance; + +typedef struct AOTModuleInstance { + uint32 module_type; + + /* memories */ + uint32 memory_count; + AOTPointer memories; + /* global and table info */ uint32 global_data_size; uint32 table_size; @@ -188,6 +232,16 @@ typedef struct AOTModuleInstance { /* function type indexes */ AOTPointer func_type_indexes; + /* export info */ + uint32 export_func_count; + uint32 export_global_count; + uint32 export_mem_count; + uint32 export_tab_count; + AOTPointer export_funcs; + AOTPointer export_globals; + AOTPointer export_memories; + AOTPointer export_tables; + /* The exception buffer for current thread. */ char cur_exception[128]; /* The custom data that can be set/get by @@ -198,13 +252,6 @@ typedef struct AOTModuleInstance { /* WASI context */ AOTPointer wasi_ctx; - /* boundary check constants for aot code */ - int64 mem_bound_check_heap_base; - int64 mem_bound_check_1byte; - int64 mem_bound_check_2bytes; - int64 mem_bound_check_4bytes; - int64 mem_bound_check_8bytes; - /* others */ int32 temp_ret; uint32 llvm_stack; @@ -215,12 +262,11 @@ typedef struct AOTModuleInstance { union { uint64 _make_it_8_byte_aligned_; + AOTMemoryInstance memory_instances[1]; uint8 bytes[1]; } global_table_data; } AOTModuleInstance; -typedef AOTExportFunc AOTFunctionInstance; - /* Target info, read from ELF header of object file */ typedef struct AOTTargetInfo { /* Binary type, elf32l/elf32b/elf64l/elf64b */ @@ -467,6 +513,16 @@ bool aot_data_drop(AOTModuleInstance *module_inst, uint32 seg_index); #endif +#if WASM_ENABLE_THREAD_MGR != 0 +bool +aot_set_aux_stack(WASMExecEnv *exec_env, + uint32 start_offset, uint32 size); + +bool +aot_get_aux_stack(WASMExecEnv *exec_env, + uint32 *start_offset, uint32 *size); +#endif + #ifdef OS_ENABLE_HW_BOUND_CHECK bool aot_signal_init(); diff --git a/core/iwasm/common/wasm_exec_env.h b/core/iwasm/common/wasm_exec_env.h index fa5310e5d..625676353 100644 --- a/core/iwasm/common/wasm_exec_env.h +++ b/core/iwasm/common/wasm_exec_env.h @@ -56,8 +56,15 @@ typedef struct WASMExecEnv { /* Used to terminate or suspend the interpreter bit 0: need terminate bit 1: need suspend - bit 2: need to go into breakpoint */ - uintptr_t suspend_flags; + bit 2: need to go into breakpoint + bit 3: return from pthread_exit */ + union { + uint32 flags; + uintptr_t __padding__; + } suspend_flags; + + /* thread return value */ + void *thread_ret_value; /* Must be provided by thread library */ void* (*thread_start_routine)(void *); diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index e8c1d4586..97bb0c024 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -115,7 +115,7 @@ wasm_runtime_env_init() } #endif -#if WASM_ENABLE_THREAD_MGR != 0 +#if (WASM_ENABLE_WAMR_COMPILER == 0) && (WASM_ENABLE_THREAD_MGR != 0) if (!thread_manager_init()) { goto fail5; } @@ -136,7 +136,7 @@ wasm_runtime_env_init() fail6: #endif #endif -#if WASM_ENABLE_THREAD_MGR != 0 +#if (WASM_ENABLE_WAMR_COMPILER == 0) && (WASM_ENABLE_THREAD_MGR != 0) thread_manager_destroy(); fail5: #endif @@ -204,7 +204,7 @@ wasm_runtime_destroy() wasm_shared_memory_destroy(); #endif -#if WASM_ENABLE_THREAD_MGR != 0 +#if (WASM_ENABLE_WAMR_COMPILER == 0) && (WASM_ENABLE_THREAD_MGR != 0) thread_manager_destroy(); #endif @@ -565,8 +565,9 @@ wasm_exec_env_set_aux_stack(WASMExecEnv *exec_env, } #endif #if WASM_ENABLE_AOT != 0 - /* TODO: implement set aux stack in AoT mode */ - (void)module_inst; + if (module_inst->module_type == Wasm_Module_AoT) { + return aot_set_aux_stack(exec_env, start_offset, size); + } #endif return false; } @@ -583,8 +584,9 @@ wasm_exec_env_get_aux_stack(WASMExecEnv *exec_env, } #endif #if WASM_ENABLE_AOT != 0 - /* TODO: implement get aux stack in AoT mode */ - (void)module_inst; + if (module_inst->module_type == Wasm_Module_AoT) { + return aot_get_aux_stack(exec_env, start_offset, size); + } #endif return false; } @@ -1298,7 +1300,8 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, #endif #if WASM_ENABLE_AOT != 0 if (module_inst->module_type == Wasm_Module_AoT - && !((AOTModuleInstance*)module_inst)->memory_data.ptr) + && !((AOTModuleInstance*)module_inst)-> + global_table_data.memory_instances[0].memory_data.ptr) return true; #endif @@ -1479,17 +1482,18 @@ wasm_runtime_lookup_wasi_start_function(WASMModuleInstanceCommon *module_inst) #if WASM_ENABLE_AOT != 0 if (module_inst->module_type == Wasm_Module_AoT) { AOTModuleInstance *aot_inst = (AOTModuleInstance*)module_inst; - AOTModule *module = (AOTModule*)aot_inst->aot_module.ptr; - for (i = 0; i < module->export_func_count; i++) { - if (!strcmp(module->export_funcs[i].func_name, "_start")) { - AOTFuncType *func_type = module->export_funcs[i].func_type; + AOTFunctionInstance *export_funcs = (AOTFunctionInstance *) + aot_inst->export_funcs.ptr; + for (i = 0; i < aot_inst->export_func_count; i++) { + if (!strcmp(export_funcs[i].func_name, "_start")) { + AOTFuncType *func_type = export_funcs[i].u.func.func_type; if (func_type->param_count != 0 || func_type->result_count != 0) { LOG_ERROR("Lookup wasi _start function failed: " "invalid function type.\n"); return NULL; } - return (WASMFunctionInstanceCommon*)&module->export_funcs[i]; + return (WASMFunctionInstanceCommon*)&export_funcs[i]; } } return NULL; @@ -1663,7 +1667,7 @@ wasm_application_execute_main(WASMModuleInstanceCommon *module_inst, #endif #if WASM_ENABLE_AOT != 0 if (module_inst->module_type == Wasm_Module_AoT) - func_type = ((AOTFunctionInstance*)func)->func_type; + func_type = ((AOTFunctionInstance*)func)->u.func.func_type; #endif if (!check_main_func_type(func_type)) { @@ -1817,10 +1821,11 @@ resolve_function(const WASMModuleInstanceCommon *module_inst, #if WASM_ENABLE_AOT != 0 if (module_inst->module_type == Wasm_Module_AoT) { AOTModuleInstance *aot_inst = (AOTModuleInstance*)module_inst; - AOTModule *module = (AOTModule*)aot_inst->aot_module.ptr; - for (i = 0; i < module->export_func_count; i++) { - if (!strcmp(module->export_funcs[i].func_name, function_name)) { - ret = (WASMFunctionInstance*)&module->export_funcs[i]; + AOTFunctionInstance *export_funcs = (AOTFunctionInstance *) + aot_inst->export_funcs.ptr; + for (i = 0; i < aot_inst->export_func_count; i++) { + if (!strcmp(export_funcs[i].func_name, function_name)) { + ret = &export_funcs[i]; break; } } @@ -1924,7 +1929,7 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, #endif #if WASM_ENABLE_AOT != 0 if (module_inst->module_type == Wasm_Module_AoT) { - type = ((AOTFunctionInstance*)func)->func_type; + type = ((AOTFunctionInstance*)func)->u.func.func_type; argc1 = type->param_cell_num; cell_num = argc1 > type->ret_cell_num ? argc1 : type->ret_cell_num; @@ -2845,4 +2850,3 @@ wasm_runtime_call_indirect(WASMExecEnv *exec_env, #endif return false; } - diff --git a/core/iwasm/common/wasm_runtime_common.h b/core/iwasm/common/wasm_runtime_common.h index 91532bfd6..57bb591fc 100644 --- a/core/iwasm/common/wasm_runtime_common.h +++ b/core/iwasm/common/wasm_runtime_common.h @@ -67,6 +67,14 @@ typedef struct WASMRegisteredModule { } WASMRegisteredModule; #endif +#if WASM_ENABLE_SHARED_MEMORY != 0 +typedef struct WASMMemoryInstanceCommon { + uint32 module_type; + uint8 memory_inst_data[1]; +} WASMMemoryInstanceCommon; + +#endif + typedef package_type_t PackageType; typedef wasm_section_t WASMSection, AOTSection; diff --git a/core/iwasm/common/wasm_shared_memory.c b/core/iwasm/common/wasm_shared_memory.c index 38baee9c9..be99e6fe3 100644 --- a/core/iwasm/common/wasm_shared_memory.c +++ b/core/iwasm/common/wasm_shared_memory.c @@ -88,16 +88,15 @@ shared_memory_dec_reference(WASMModuleCommon *module) return -1; } -#if WASM_ENABLE_INTERP != 0 -WASMMemoryInstance* +WASMMemoryInstanceCommon* shared_memory_get_memory_inst(WASMSharedMemNode *node) { - return node->u.wasm_memory; + return node->memory_inst; } WASMSharedMemNode* shared_memory_set_memory_inst(WASMModuleCommon *module, - WASMMemoryInstance *memory) + WASMMemoryInstanceCommon *memory) { WASMSharedMemNode *node; bh_list_status ret; @@ -106,7 +105,7 @@ shared_memory_set_memory_inst(WASMModuleCommon *module, return NULL; node->module = module; - node->u.wasm_memory = memory; + node->memory_inst = memory; node->ref_count = 1; if (os_mutex_init(&node->lock) != 0) { wasm_runtime_free(node); @@ -122,6 +121,4 @@ shared_memory_set_memory_inst(WASMModuleCommon *module, return node; } -#endif /* end of WASM_ENABLE_INTERP */ - #endif /* end of WASM_ENABLE_SHARED_MEMORY */ diff --git a/core/iwasm/common/wasm_shared_memory.h b/core/iwasm/common/wasm_shared_memory.h index aed6d10e1..5a78b5fee 100644 --- a/core/iwasm/common/wasm_shared_memory.h +++ b/core/iwasm/common/wasm_shared_memory.h @@ -25,28 +25,7 @@ typedef struct WASMSharedMemNode { /* The module reference */ WASMModuleCommon *module; /* The memory information */ - union { -#if WASM_ENABLE_INTERP - WASMMemoryInstance *wasm_memory; -#endif -#if WASM_ENABLE_AOT - struct { - /* memory space info */ - uint32 mem_cur_page_count; - uint32 mem_max_page_count; - uint32 memory_data_size; - AOTPointer memory_data; - AOTPointer memory_data_end; - - /* heap space info */ - int32 heap_base_offset; - uint32 heap_data_size; - AOTPointer heap_data; - AOTPointer heap_data_end; - AOTPointer heap_handle; - } aot_memory; -#endif - } u; + WASMMemoryInstanceCommon *memory_inst; /* reference count */ uint32 ref_count; @@ -67,12 +46,12 @@ shared_memory_inc_reference(WASMModuleCommon *module); int32 shared_memory_dec_reference(WASMModuleCommon *module); -WASMMemoryInstance* +WASMMemoryInstanceCommon* shared_memory_get_memory_inst(WASMSharedMemNode *node); WASMSharedMemNode* shared_memory_set_memory_inst(WASMModuleCommon *module, - WASMMemoryInstance *memory); + WASMMemoryInstanceCommon *memory); #ifdef __cplusplus diff --git a/core/iwasm/compilation/aot.c b/core/iwasm/compilation/aot.c index 025294b6f..35cf56c55 100644 --- a/core/iwasm/compilation/aot.c +++ b/core/iwasm/compilation/aot.c @@ -344,43 +344,12 @@ fail: return NULL; } -static AOTExportFunc * -aot_create_export_funcs(const WASMModule *module, - uint32 export_func_count) -{ - AOTExportFunc *export_funcs; - uint64 size; - uint32 i, j = 0; - - /* Allocate memory */ - size = sizeof(AOTExportFunc) * (uint64)export_func_count; - if (size >= UINT32_MAX - || !(export_funcs = wasm_runtime_malloc((uint32)size))) { - aot_set_last_error("allocate memory failed."); - return NULL; - } - - /* Create each export function */ - for (i = 0; i < module->export_count; i++) { - if (module->exports[i].kind == EXPORT_KIND_FUNC) { - export_funcs[j].func_name = module->exports[i].name; - export_funcs[j].func_index = module->exports[i].index; - export_funcs[j].func_type = - module->functions[module->exports[i].index - - module->import_function_count]->func_type; - /* Function pointer to be linked in JIT mode */ - export_funcs[j].func_ptr = NULL; - j++; - } - } - return export_funcs; -} - AOTCompData* aot_create_comp_data(WASMModule *module) { AOTCompData *comp_data; - uint32 import_global_data_size = 0, global_data_size = 0, i; + uint32 import_global_data_size = 0, global_data_size = 0, i, j; + uint64 size; /* Allocate memory */ if (!(comp_data = wasm_runtime_malloc(sizeof(AOTCompData)))) { @@ -390,22 +359,49 @@ aot_create_comp_data(WASMModule *module) memset(comp_data, 0, sizeof(AOTCompData)); - /* Set memory page count */ - if (module->import_memory_count) { - comp_data->num_bytes_per_page = - module->import_memories[0].u.memory.num_bytes_per_page; - comp_data->mem_init_page_count = - module->import_memories[0].u.memory.init_page_count; - comp_data->mem_max_page_count = - module->import_memories[0].u.memory.max_page_count; + comp_data->memory_count = module->import_memory_count + module->memory_count; + + /* TODO: create import memories */ + + /* Allocate memory for memory array, reserve one AOTMemory space at least */ + if (!comp_data->memory_count) + comp_data->memory_count = 1; + + size = (uint64)comp_data->memory_count * sizeof(AOTMemory); + if (size >= UINT32_MAX + || !(comp_data->memories = wasm_runtime_malloc((uint32)size))) { + aot_set_last_error("create memories array failed.\n"); + goto fail; } - else if (module->memory_count) { - comp_data->num_bytes_per_page = - module->memories[0].num_bytes_per_page; - comp_data->mem_init_page_count = - module->memories[0].init_page_count; - comp_data->mem_max_page_count = - module->memories[0].max_page_count; + memset(comp_data->memories, 0, size); + + /* Set memory page count */ + for (i = 0; i < module->import_memory_count + module->memory_count; i++) { + if (i < module->import_memory_count) { + comp_data->memories[i].memory_flags = + module->import_memories[i].u.memory.flags; + comp_data->memories[i].num_bytes_per_page = + module->import_memories[i].u.memory.num_bytes_per_page; + comp_data->memories[i].mem_init_page_count = + module->import_memories[i].u.memory.init_page_count; + comp_data->memories[i].mem_max_page_count = + module->import_memories[i].u.memory.max_page_count; + comp_data->memories[i].num_bytes_per_page = + module->import_memories[i].u.memory.num_bytes_per_page; + } + else { + j = i - module->import_memory_count; + comp_data->memories[i].memory_flags = + module->memories[j].flags; + comp_data->memories[i].num_bytes_per_page = + module->memories[j].num_bytes_per_page; + comp_data->memories[i].mem_init_page_count = + module->memories[j].init_page_count; + comp_data->memories[i].mem_max_page_count = + module->memories[j].max_page_count; + comp_data->memories[i].num_bytes_per_page = + module->memories[j].num_bytes_per_page; + } } /* Create memory data segments */ @@ -415,11 +411,39 @@ aot_create_comp_data(WASMModule *module) aot_create_mem_init_data_list(module))) goto fail; - /* Set table size */ - if (module->import_table_count) - comp_data->table_size = module->import_tables[0].u.table.init_size; - else if (module->table_count) - comp_data->table_size = module->tables[0].init_size; + /* TODO: create import tables */ + + /* Create tables */ + comp_data->table_count = module->import_table_count + module->table_count; + + if (comp_data->table_count > 0) { + size = sizeof(AOTTable) * (uint64)comp_data->table_count; + if (size >= UINT32_MAX + || !(comp_data->tables = wasm_runtime_malloc((uint32)size))) { + aot_set_last_error("create memories array failed.\n"); + goto fail; + } + memset(comp_data->tables, 0, size); + for (i = 0; i < comp_data->table_count; i++) { + if (i < module->import_table_count) { + comp_data->tables[i].elem_type = + module->import_tables[i].u.table.elem_type; + comp_data->tables[i].table_flags = + module->import_tables[i].u.table.flags; + comp_data->tables[i].table_init_size = + module->import_tables[i].u.table.init_size; + comp_data->tables[i].table_max_size = + module->import_tables[i].u.table.max_size; + } + else { + j = i - module->import_table_count; + comp_data->tables[i].elem_type = module->tables[i].elem_type; + comp_data->tables[i].table_flags = module->tables[i].flags; + comp_data->tables[i].table_init_size = module->tables[i].init_size; + comp_data->tables[i].table_max_size = module->tables[i].max_size; + } + } + } /* Create table data segments */ comp_data->table_init_data_count = module->table_seg_count; @@ -463,15 +487,11 @@ aot_create_comp_data(WASMModule *module) && !(comp_data->funcs = aot_create_funcs(module))) goto fail; - /* Create export functions */ - for (i = 0; i < module->export_count; i++) - if (module->exports[i].kind == EXPORT_KIND_FUNC) - comp_data->export_func_count++; - - if (comp_data->export_func_count - && !(comp_data->export_funcs = aot_create_export_funcs - (module, comp_data->export_func_count))) - 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; comp_data->start_func_index = module->start_function; comp_data->wasm_module = module; @@ -490,10 +510,22 @@ aot_destroy_comp_data(AOTCompData *comp_data) if (!comp_data) return; + if (comp_data->import_memories) + wasm_runtime_free(comp_data->import_memories); + + if (comp_data->memories) + wasm_runtime_free(comp_data->memories); + if (comp_data->mem_init_data_list) aot_destroy_mem_init_data_list(comp_data->mem_init_data_list, comp_data->mem_init_data_count); + if (comp_data->import_tables) + wasm_runtime_free(comp_data->import_tables); + + if (comp_data->tables) + wasm_runtime_free(comp_data->tables); + if (comp_data->table_init_data_list) aot_destroy_table_init_data_list(comp_data->table_init_data_list, comp_data->table_init_data_count); @@ -514,9 +546,6 @@ aot_destroy_comp_data(AOTCompData *comp_data) if (comp_data->funcs) aot_destroy_funcs(comp_data->funcs, comp_data->func_count); - if (comp_data->export_funcs) - wasm_runtime_free(comp_data->export_funcs); - wasm_runtime_free(comp_data); } diff --git a/core/iwasm/compilation/aot.h b/core/iwasm/compilation/aot.h index 7a533fa75..abf86d854 100644 --- a/core/iwasm/compilation/aot.h +++ b/core/iwasm/compilation/aot.h @@ -19,6 +19,30 @@ extern "C" { typedef InitializerExpression AOTInitExpr; typedef WASMType AOTFuncType; +typedef WASMExport AOTExport; + +/** + * Import memory + */ +typedef struct AOTImportMemory { + char *module_name; + char *memory_name; + uint32 memory_flags; + uint32 num_bytes_per_page; + uint32 mem_init_page_count; + uint32 mem_max_page_count; +} AOTImportMemory; + +/** + * Memory information + */ +typedef struct AOTMemory { + /* memory info */ + uint32 memory_flags; + uint32 num_bytes_per_page; + uint32 mem_init_page_count; + uint32 mem_max_page_count; +} AOTMemory; /** * A segment of memory init data @@ -38,10 +62,32 @@ typedef struct AOTMemInitData { uint8 bytes[1]; } AOTMemInitData; +/** + * Import table + */ +typedef struct AOTImportTable { + char *module_name; + char *table_name; + uint32 table_flags; + uint32 table_init_size; + uint32 table_max_size; +} AOTImportTable; + +/** + * Table + */ +typedef struct AOTTable { + uint32 elem_type; + uint32 table_flags; + uint32 table_init_size; + uint32 table_max_size; +} AOTTable; + /** * A segment of table init data */ typedef struct AOTTableInitData { + uint32 table_index; /* Start address of init data */ AOTInitExpr offset; /* Function index count */ @@ -110,47 +156,50 @@ typedef struct AOTFunc { uint8 *code; } AOTFunc; -/** - * Export function - */ -typedef struct AOTExportFunc { - char *func_name; - AOTFuncType *func_type; - /* function pointer linked */ - void *func_ptr; - uint32 func_index; -} AOTExportFunc; - typedef struct AOTCompData { - /* Memory and memory init data info */ - uint32 num_bytes_per_page; - uint32 mem_init_page_count; - uint32 mem_max_page_count; + /* Import memories */ + uint32 import_memory_count; + AOTImportMemory *import_memories; + + /* Memories */ + uint32 memory_count; + AOTMemory *memories; + + /* Memory init data info */ uint32 mem_init_data_count; AOTMemInitData **mem_init_data_list; - /* Table and table init data info */ - uint32 table_size; - AOTTableInitData **table_init_data_list; + /* Import tables */ + uint32 import_table_count; + AOTImportTable *import_tables; + + /* Tables */ + uint32 table_count; + AOTTable *tables; + + /* Table init data info */ uint32 table_init_data_count; + AOTTableInitData **table_init_data_list; - AOTImportGlobal *import_globals; + /* Import globals */ uint32 import_global_count; + AOTImportGlobal *import_globals; - AOTGlobal *globals; + /* Globals */ uint32 global_count; + AOTGlobal *globals; - AOTFuncType **func_types; + /* Function types */ uint32 func_type_count; + AOTFuncType **func_types; - AOTImportFunc *import_funcs; + /* Import functions */ uint32 import_func_count; + AOTImportFunc *import_funcs; - AOTFunc **funcs; + /* Functions */ uint32 func_count; - - AOTExportFunc *export_funcs; - uint32 export_func_count; + AOTFunc **funcs; uint32 start_func_index; uint32 addr_data_size; diff --git a/core/iwasm/compilation/aot_emit_aot_file.c b/core/iwasm/compilation/aot_emit_aot_file.c index 2095388e0..8b9c39bf1 100644 --- a/core/iwasm/compilation/aot_emit_aot_file.c +++ b/core/iwasm/compilation/aot_emit_aot_file.c @@ -152,12 +152,30 @@ get_mem_init_data_list_size(AOTMemInitData **mem_init_data_list, return size; } +static uint32 +get_import_memory_size(AOTCompData *comp_data) +{ + /* currently we only emit import_memory_count = 0 */ + return sizeof(uint32); +} + +static uint32 +get_memory_size(AOTCompData *comp_data) +{ + /* memory_count + count * (memory_flags + num_bytes_per_page + + init_page_count + max_page_count) */ + return (uint32)(sizeof(uint32) + + comp_data->memory_count * sizeof(uint32) * 4); +} + static uint32 get_mem_info_size(AOTCompData *comp_data) { - /* num bytes per page + init page count + max page count - + init data count + init data list */ - return (uint32)sizeof(uint32) * 4 + /* import_memory_size + memory_size + + init_data_count + init_data_list */ + return get_import_memory_size(comp_data) + + get_memory_size(comp_data) + + (uint32)sizeof(uint32) + get_mem_init_data_list_size(comp_data->mem_init_data_list, comp_data->mem_init_data_count); } @@ -165,9 +183,10 @@ get_mem_info_size(AOTCompData *comp_data) static uint32 get_table_init_data_size(AOTTableInitData *table_init_data) { - /* init expr type (4 bytes) + init expr value (8 bytes) + /* table_index + init expr type (4 bytes) + init expr value (8 bytes) + func index count (4 bytes) + func indexes */ - return (uint32)(sizeof(uint32) + sizeof(uint64) + sizeof(uint32) + return (uint32)(sizeof(uint32) + sizeof(uint32) + + sizeof(uint64) + sizeof(uint32) + sizeof(uint32) * table_init_data->func_index_count); } @@ -185,11 +204,30 @@ get_table_init_data_list_size(AOTTableInitData **table_init_data_list, return size; } +static uint32 +get_import_table_size(AOTCompData *comp_data) +{ + /* currently we only emit import_table_count = 0 */ + return sizeof(uint32); +} + +static uint32 +get_table_size(AOTCompData *comp_data) +{ + /* table_count + table_count * (elem_type + table_flags + * + init_size + max_size) */ + return (uint32)(sizeof(uint32) + + comp_data->table_count * sizeof(uint32) * 4); +} + static uint32 get_table_info_size(AOTCompData *comp_data) { - /* table size + init data count + init data list */ - return (uint32)sizeof(uint32) * 2 + /* import_table size + table_size + + init data count + init data list */ + return get_import_table_size(comp_data) + + get_table_size(comp_data) + + (uint32)sizeof(uint32) + get_table_init_data_list_size(comp_data->table_init_data_list, comp_data->table_init_data_count); } @@ -412,23 +450,22 @@ get_func_section_size(AOTCompData *comp_data, AOTObjectData *obj_data) } static uint32 -get_export_func_size(AOTExportFunc *export_func) +get_export_size(AOTExport *export) { - /* export func index + export func name */ - return (uint32)sizeof(uint32) - + get_string_size(export_func->func_name); + /* export index + export kind + 1 byte padding + export name */ + return (uint32)sizeof(uint32) + sizeof(uint8) + 1 + + get_string_size(export->name); } static uint32 -get_export_funcs_size(AOTExportFunc *export_funcs, - uint32 export_func_count) +get_exports_size(AOTExport *exports, uint32 export_count) { - AOTExportFunc *export_func = export_funcs; + AOTExport *export = exports; uint32 size = 0, i; - for (i = 0; i < export_func_count; i++, export_func++) { + for (i = 0; i < export_count; i++, export++) { size = align_uint(size, 4); - size += get_export_func_size(export_func); + size += get_export_size(export); } return size; } @@ -436,10 +473,10 @@ get_export_funcs_size(AOTExportFunc *export_funcs, static uint32 get_export_section_size(AOTCompData *comp_data) { - /* export func count + export funcs */ + /* export count + exports */ return (uint32)sizeof(uint32) - + get_export_funcs_size(comp_data->export_funcs, - comp_data->export_func_count); + + get_exports_size(comp_data->wasm_module->exports, + comp_data->wasm_module->export_count); } static uint32 @@ -887,11 +924,24 @@ aot_emit_mem_info(uint8 *buf, uint8 *buf_end, uint32 *p_offset, *p_offset = offset = align_uint(offset, 4); - EMIT_U32(comp_data->num_bytes_per_page); - EMIT_U32(comp_data->mem_init_page_count); - EMIT_U32(comp_data->mem_max_page_count); - EMIT_U32(comp_data->mem_init_data_count); + /* Emit import memory count, only emit 0 currently. + TODO: emit the actual import memory count and + the full import memory info. */ + EMIT_U32(0); + /* Emit memory count */ + EMIT_U32(comp_data->memory_count); + /* Emit memory items */ + for (i = 0; i < comp_data->memory_count; i++) { + EMIT_U32(comp_data->memories[i].memory_flags); + EMIT_U32(comp_data->memories[i].num_bytes_per_page); + EMIT_U32(comp_data->memories[i].mem_init_page_count); + EMIT_U32(comp_data->memories[i].mem_max_page_count); + } + + /* Emit mem init data count */ + EMIT_U32(comp_data->mem_init_data_count); + /* Emit mem init data items */ for (i = 0; i < comp_data->mem_init_data_count; i++) { offset = align_uint(offset, 4); #if WASM_ENABLE_BULK_MEMORY != 0 @@ -931,11 +981,27 @@ aot_emit_table_info(uint8 *buf, uint8 *buf_end, uint32 *p_offset, *p_offset = offset = align_uint(offset, 4); - EMIT_U32(comp_data->table_size); - EMIT_U32(comp_data->table_init_data_count); + /* Emit import table count, only emit 0 currently. + TODO: emit the actual import table count and + the full import table info. */ + EMIT_U32(0); + /* Emit table count */ + EMIT_U32(comp_data->table_count); + /* Emit table items */ + for (i = 0; i < comp_data->table_count; i++) { + EMIT_U32(comp_data->tables[i].elem_type); + EMIT_U32(comp_data->tables[i].table_flags); + EMIT_U32(comp_data->tables[i].table_init_size); + EMIT_U32(comp_data->tables[i].table_max_size); + } + + /* Emit table init data count */ + EMIT_U32(comp_data->table_init_data_count); + /* Emit table init data items */ for (i = 0; i < comp_data->table_init_data_count; i++) { offset = align_uint(offset, 4); + EMIT_U32(init_datas[i]->table_index); EMIT_U32(init_datas[i]->offset.init_expr_type); EMIT_U64(init_datas[i]->offset.u.i64); EMIT_U32(init_datas[i]->func_index_count); @@ -1211,19 +1277,22 @@ aot_emit_export_section(uint8 *buf, uint8 *buf_end, uint32 *p_offset, AOTCompData *comp_data, AOTObjectData *obj_data) { uint32 section_size = get_export_section_size(comp_data); - AOTExportFunc *func = comp_data->export_funcs;; - uint32 i, offset = *p_offset, export_func_count = comp_data->export_func_count; + AOTExport *export = comp_data->wasm_module->exports; + uint32 export_count = comp_data->wasm_module->export_count; + uint32 i, offset = *p_offset; *p_offset = offset = align_uint(offset, 4); EMIT_U32(AOT_SECTION_TYPE_EXPORT); EMIT_U32(section_size); - EMIT_U32(export_func_count); + EMIT_U32(export_count); - for (i = 0; i < export_func_count; i++, func++) { + for (i = 0; i < export_count; i++, export++) { offset = align_uint(offset, 4); - EMIT_U32(func->func_index); - EMIT_STR(func->func_name); + EMIT_U32(export->index); + EMIT_U8(export->kind); + EMIT_U8(0); + EMIT_STR(export->name); } if (offset - *p_offset != section_size + sizeof(uint32) * 2) { diff --git a/core/iwasm/compilation/aot_emit_control.c b/core/iwasm/compilation/aot_emit_control.c index b6d38bf20..a2799a7e5 100644 --- a/core/iwasm/compilation/aot_emit_control.c +++ b/core/iwasm/compilation/aot_emit_control.c @@ -102,6 +102,14 @@ format_block_name(char *name, uint32 name_size, &value, &block_curr, 1); \ } while (0) +#define BUILD_ICMP(op, left, right, res, name) do { \ + if (!(res = LLVMBuildICmp(comp_ctx->builder, op, \ + left, right, name))) { \ + aot_set_last_error("llvm build icmp failed."); \ + goto fail; \ + } \ + } while (0) + #define ADD_TO_PARAM_PHIS(block, value, idx) do { \ LLVMBasicBlockRef block_curr = CURR_BLOCK(); \ LLVMAddIncoming(block->param_phis[idx], \ @@ -614,6 +622,99 @@ fail: return false; } +#if WASM_ENABLE_THREAD_MGR != 0 +bool +check_suspend_flags(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) +{ + LLVMValueRef terminate_addr, terminate_flags, flag, offset, res; + LLVMBasicBlockRef terminate_check_block, non_terminate_block; + AOTFuncType *aot_func_type = func_ctx->aot_func->func_type; + LLVMBasicBlockRef terminate_block; + + /* Offset of suspend_flags */ + offset = I32_CONST(5); + CHECK_LLVM_CONST(offset); + + if (!(terminate_addr = + LLVMBuildInBoundsGEP(comp_ctx->builder, func_ctx->exec_env, + &offset, 1, "terminate_addr"))) { + aot_set_last_error("llvm build in bounds gep failed"); + return false; + } + if (!(terminate_addr = + LLVMBuildBitCast(comp_ctx->builder, + terminate_addr, + INT32_PTR_TYPE, "terminate_addr_ptr"))) { + aot_set_last_error("llvm build bit cast failed"); + return false; + } + + if (!(terminate_flags = + LLVMBuildLoad(comp_ctx->builder, + terminate_addr, "terminate_flags"))) { + aot_set_last_error("llvm build bit cast failed"); + return false; + } + /* Set terminate_flags memory accecc to volatile, so that the value + will always be loaded from memory rather than register */ + LLVMSetVolatile(terminate_flags, true); + + CREATE_BLOCK(terminate_check_block, "terminate_check"); + MOVE_BLOCK_AFTER_CURR(terminate_check_block); + + CREATE_BLOCK(non_terminate_block, "non_terminate"); + MOVE_BLOCK_AFTER_CURR(non_terminate_block); + + BUILD_ICMP(LLVMIntSGT, terminate_flags, I32_ZERO, res, "need_terminate"); + BUILD_COND_BR(res, terminate_check_block, non_terminate_block); + + /* Move builder to terminate check block */ + SET_BUILDER_POS(terminate_check_block); + + CREATE_BLOCK(terminate_block, "terminate"); + MOVE_BLOCK_AFTER_CURR(terminate_block); + + if (!(flag = + LLVMBuildAnd(comp_ctx->builder, terminate_flags, + I32_ONE, "termination_flag"))) { + aot_set_last_error("llvm build AND failed"); + return false; + } + + BUILD_ICMP(LLVMIntSGT, flag, I32_ZERO, res, "need_terminate"); + BUILD_COND_BR(res, terminate_block, non_terminate_block); + + /* Move builder to terminate block */ + SET_BUILDER_POS(terminate_block); + 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); + } + + /* Move builder to terminate block */ + SET_BUILDER_POS(non_terminate_block); + return true; + +fail: + return false; +} +#endif /* End of WASM_ENABLE_THREAD_MGR */ + bool aot_compile_op_br(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, uint32 br_depth, uint8 **p_frame_ip) @@ -624,6 +725,14 @@ aot_compile_op_br(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, char name[32]; uint32 i, param_index, result_index; +#if WASM_ENABLE_THREAD_MGR != 0 + /* Insert suspend check point */ + if (comp_ctx->enable_thread_mgr) { + if (!check_suspend_flags(comp_ctx, func_ctx)) + return false; + } +#endif + if (!(block_dst = get_target_block(func_ctx, br_depth))) { return false; } @@ -680,6 +789,14 @@ aot_compile_op_br_if(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, uint32 i, param_index, result_index; uint64 size; +#if WASM_ENABLE_THREAD_MGR != 0 + /* Insert suspend check point */ + if (comp_ctx->enable_thread_mgr) { + if (!check_suspend_flags(comp_ctx, func_ctx)) + return false; + } +#endif + POP_COND(value_cmp); if (!LLVMIsConstant(value_cmp)) { /* Compare value is not constant, create condition br IR */ @@ -798,6 +915,14 @@ aot_compile_op_br_table(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, uint64 size; char name[32]; +#if WASM_ENABLE_THREAD_MGR != 0 + /* Insert suspend check point */ + if (comp_ctx->enable_thread_mgr) { + if (!check_suspend_flags(comp_ctx, func_ctx)) + return false; + } +#endif + POP_I32(value_cmp); if (!LLVMIsConstant(value_cmp)) { /* Compare value is not constant, create switch IR */ diff --git a/core/iwasm/compilation/aot_emit_control.h b/core/iwasm/compilation/aot_emit_control.h index fa73d29fb..c0c029056 100644 --- a/core/iwasm/compilation/aot_emit_control.h +++ b/core/iwasm/compilation/aot_emit_control.h @@ -53,6 +53,11 @@ aot_handle_next_reachable_block(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, uint8 **p_frame_ip); +#if WASM_ENABLE_THREAD_MGR != 0 +bool +check_suspend_flags(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx); +#endif + #ifdef __cplusplus } /* end of extern "C" */ #endif diff --git a/core/iwasm/compilation/aot_emit_function.c b/core/iwasm/compilation/aot_emit_function.c index 1897cfd80..af7362f50 100644 --- a/core/iwasm/compilation/aot_emit_function.c +++ b/core/iwasm/compilation/aot_emit_function.c @@ -326,6 +326,14 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, bool ret = false; char buf[32]; +#if WASM_ENABLE_THREAD_MGR != 0 + /* Insert suspend check point */ + if (comp_ctx->enable_thread_mgr) { + if (!check_suspend_flags(comp_ctx, func_ctx)) + return false; + } +#endif + /* Check function index */ if (func_idx >= import_func_count + func_count) { aot_set_last_error("Function index out of range."); @@ -514,6 +522,14 @@ call_aot_call_indirect_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, char buf[32], *func_name = "aot_call_indirect"; uint32 i, cell_num = 0, ret_cell_num, argv_cell_num; +#if WASM_ENABLE_THREAD_MGR != 0 + /* Insert suspend check point */ + if (comp_ctx->enable_thread_mgr) { + if (!check_suspend_flags(comp_ctx, func_ctx)) + return false; + } +#endif + /* prepare function type of aot_call_indirect */ func_param_types[0] = comp_ctx->exec_env_type; /* exec_env */ func_param_types[1] = INT8_TYPE; /* check_func_type */ diff --git a/core/iwasm/compilation/aot_emit_memory.c b/core/iwasm/compilation/aot_emit_memory.c index b6d497582..ff3922c8b 100644 --- a/core/iwasm/compilation/aot_emit_memory.c +++ b/core/iwasm/compilation/aot_emit_memory.c @@ -42,16 +42,16 @@ get_memory_check_bound(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, LLVMValueRef mem_check_bound = NULL; switch (bytes) { case 1: - mem_check_bound = func_ctx->mem_bound_check_1byte; + mem_check_bound = func_ctx->mem_info[0].mem_bound_check_1byte; break; case 2: - mem_check_bound = func_ctx->mem_bound_check_2bytes; + mem_check_bound = func_ctx->mem_info[0].mem_bound_check_2bytes; break; case 4: - mem_check_bound = func_ctx->mem_bound_check_4bytes; + mem_check_bound = func_ctx->mem_info[0].mem_bound_check_4bytes; break; case 8: - mem_check_bound = func_ctx->mem_bound_check_8bytes; + mem_check_bound = func_ctx->mem_info[0].mem_bound_check_8bytes; break; default: bh_assert(0); @@ -80,17 +80,26 @@ check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, LLVMBasicBlockRef block_curr = LLVMGetInsertBlock(comp_ctx->builder); LLVMBasicBlockRef check_succ; AOTValue *aot_value; +#if WASM_ENABLE_SHARED_MEMORY != 0 + bool is_shared_memory = + comp_ctx->comp_data->memories[0].memory_flags & 0x02; +#endif CHECK_LLVM_CONST(offset_const); /* Get memory base address and memory data size */ +#if WASM_ENABLE_SHARED_MEMORY != 0 + if (func_ctx->mem_space_unchanged || is_shared_memory) { +#else if (func_ctx->mem_space_unchanged) { - mem_base_addr = func_ctx->mem_base_addr; +#endif + mem_base_addr = func_ctx->mem_info[0].mem_base_addr; } else { - if (!(mem_base_addr = LLVMBuildLoad(comp_ctx->builder, - func_ctx->mem_base_addr, - "mem_base"))) { + if (!(mem_base_addr = + LLVMBuildLoad(comp_ctx->builder, + func_ctx->mem_info[0].mem_base_addr, + "mem_base"))) { aot_set_last_error("llvm build load failed."); goto fail; } @@ -103,8 +112,10 @@ 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; - 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 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 @@ -141,8 +152,9 @@ check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, goto fail; } - BUILD_ICMP(LLVMIntSGT, func_ctx->mem_bound_check_heap_base, offset1, - cmp1, "cmp1"); + 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"); @@ -448,32 +460,19 @@ fail: static LLVMValueRef get_memory_size(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) { - uint32 offset = offsetof(AOTModuleInstance, mem_cur_page_count); - LLVMValueRef mem_size_offset, mem_size_ptr, mem_size; + LLVMValueRef mem_size; - /* mem_size_offset = aot_inst + offset */ - mem_size_offset = I32_CONST(offset); - CHECK_LLVM_CONST(mem_size_offset); - 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; + if (func_ctx->mem_space_unchanged) { + mem_size = func_ctx->mem_info[0].mem_cur_page_count_addr; } - - /* 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, or current page count */ - if (!(mem_size = LLVMBuildLoad(comp_ctx->builder, - mem_size_ptr, "mem_size"))) { - aot_set_last_error("llvm build load failed."); - return NULL; + else { + if (!(mem_size = + LLVMBuildLoad(comp_ctx->builder, + func_ctx->mem_info[0].mem_cur_page_count_addr, + "mem_size"))) { + aot_set_last_error("llvm build load failed."); + goto fail; + } } return mem_size; @@ -614,17 +613,24 @@ check_bulk_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, 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; + LLVMValueRef mem_size; /* Get memory base address and memory data size */ +#if WASM_ENABLE_SHARED_MEMORY != 0 + bool is_shared_memory = + comp_ctx->comp_data->memories[0].memory_flags & 0x02; + + if (func_ctx->mem_space_unchanged || is_shared_memory) { +#else if (func_ctx->mem_space_unchanged) { - mem_base_addr = func_ctx->mem_base_addr; +#endif + mem_base_addr = func_ctx->mem_info[0].mem_base_addr; } else { - if (!(mem_base_addr = LLVMBuildLoad(comp_ctx->builder, - func_ctx->mem_base_addr, - "mem_base"))) { + if (!(mem_base_addr = + LLVMBuildLoad(comp_ctx->builder, + func_ctx->mem_info[0].mem_base_addr, + "mem_base"))) { aot_set_last_error("llvm build load failed."); goto fail; } @@ -634,8 +640,10 @@ check_bulk_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, 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 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; uint32 mem_data_size = num_bytes_per_page * init_page_count; if (mem_data_size > 0 && mem_offset + mem_len <= mem_data_size) { @@ -652,27 +660,8 @@ check_bulk_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } /* 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; + if (!(mem_size = get_memory_size(comp_ctx, func_ctx))) { + goto fail; } ADD_BASIC_BLOCK(check_succ, "check_succ"); diff --git a/core/iwasm/compilation/aot_emit_variable.c b/core/iwasm/compilation/aot_emit_variable.c index 4f5e63f18..f9e18a5fd 100644 --- a/core/iwasm/compilation/aot_emit_variable.c +++ b/core/iwasm/compilation/aot_emit_variable.c @@ -111,8 +111,9 @@ compile_global(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, { AOTCompData *comp_data = comp_ctx->comp_data; uint32 import_global_count = comp_data->import_global_count; - uint32 global_base_offset = offsetof(AOTModuleInstance, - global_table_data.bytes); + uint32 global_base_offset = + offsetof(AOTModuleInstance, global_table_data.bytes) + + sizeof(AOTMemoryInstance) * comp_ctx->comp_data->memory_count; uint32 global_offset; uint8 global_type; LLVMValueRef offset, global_ptr, global; diff --git a/core/iwasm/compilation/aot_llvm.c b/core/iwasm/compilation/aot_llvm.c index 813513eb7..753f67e27 100644 --- a/core/iwasm/compilation/aot_llvm.c +++ b/core/iwasm/compilation/aot_llvm.c @@ -186,142 +186,279 @@ static bool create_memory_info(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, LLVMTypeRef int8_ptr_type, uint32 func_index) { - LLVMValueRef offset; + LLVMValueRef offset, mem_info_base; + uint32 memory_count; WASMModule *module = comp_ctx->comp_data->wasm_module; WASMFunction *func = module->functions[func_index]; bool mem_space_unchanged = (!func->has_op_memory_grow && !func->has_op_func_call) || (!module->possible_memory_grow); +#if WASM_ENABLE_SHARED_MEMORY != 0 + bool is_shared_memory; +#endif func_ctx->mem_space_unchanged = mem_space_unchanged; - /* Load memory base address */ - offset = I32_CONST(offsetof(AOTModuleInstance, memory_data.ptr)); - if (!(func_ctx->mem_base_addr = - LLVMBuildInBoundsGEP(comp_ctx->builder, func_ctx->aot_inst, - &offset, 1, "mem_base_addr_offset"))) { - aot_set_last_error("llvm build in bounds gep failed"); + memory_count = module->memory_count + module->import_memory_count; + /* If the module dosen't have memory, reserve + one mem_info space with empty content */ + if (memory_count == 0) + memory_count = 1; + + if (!(func_ctx->mem_info = + wasm_runtime_malloc(sizeof(AOTMemInfo) * memory_count))) { return false; } - if (!(func_ctx->mem_base_addr = - LLVMBuildBitCast(comp_ctx->builder, func_ctx->mem_base_addr, + memset(func_ctx->mem_info, 0, sizeof(AOTMemInfo)); + + /* Currently we only create memory info for memory 0 */ + /* Load memory base address */ +#if WASM_ENABLE_SHARED_MEMORY != 0 + is_shared_memory = comp_ctx->comp_data->memories[0].memory_flags & 0x02 + ? true : false; + if (is_shared_memory) { + LLVMValueRef shared_mem_addr; + offset = I32_CONST(offsetof(AOTModuleInstance, memories)); + if (!offset) { + aot_set_last_error("create llvm const failed."); + return false; + } + + /* aot_inst->memories */ + if (!(shared_mem_addr = + LLVMBuildInBoundsGEP(comp_ctx->builder, func_ctx->aot_inst, + &offset, 1, "shared_mem_addr_offset"))) { + aot_set_last_error("llvm build in bounds gep failed"); + return false; + } + if (!(shared_mem_addr = + LLVMBuildBitCast(comp_ctx->builder, + shared_mem_addr, int8_ptr_type, + "shared_mem_addr_ptr"))) { + aot_set_last_error("llvm build bit cast failed"); + return false; + } + /* aot_inst->memories[0] */ + if (!(shared_mem_addr = + LLVMBuildLoad(comp_ctx->builder, + shared_mem_addr, "shared_mem_addr"))) { + aot_set_last_error("llvm build load failed"); + return false; + } + if (!(shared_mem_addr = + LLVMBuildBitCast(comp_ctx->builder, + shared_mem_addr, int8_ptr_type, + "shared_mem_addr_ptr"))) { + aot_set_last_error("llvm build bit cast failed"); + return false; + } + if (!(shared_mem_addr = + LLVMBuildLoad(comp_ctx->builder, + shared_mem_addr, "shared_mem_addr"))) { + aot_set_last_error("llvm build load failed"); + return false; + } + offset = I32_CONST(offsetof(AOTMemoryInstance, memory_data.ptr)); + if (!(func_ctx->mem_info[0].mem_base_addr = + LLVMBuildInBoundsGEP(comp_ctx->builder, shared_mem_addr, + &offset, 1, "mem_base_addr_offset"))) { + aot_set_last_error("llvm build in bounds gep failed"); + return false; + } + offset = I32_CONST(offsetof(AOTMemoryInstance, mem_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"))) { + aot_set_last_error("llvm build in bounds gep failed"); + return false; + } + } + else +#endif + { + offset = I32_CONST(offsetof(AOTModuleInstance, global_table_data) + + offsetof(AOTMemoryInstance, memory_data.ptr)); + if (!(func_ctx->mem_info[0].mem_base_addr = + LLVMBuildInBoundsGEP(comp_ctx->builder, func_ctx->aot_inst, + &offset, 1, "mem_base_addr_offset"))) { + aot_set_last_error("llvm build in bounds gep failed"); + return false; + } + offset = I32_CONST(offsetof(AOTModuleInstance, global_table_data) + + offsetof(AOTMemoryInstance, mem_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"))) { + aot_set_last_error("llvm build in bounds gep failed"); + return false; + } + } + /* Store mem info base address before cast */ + mem_info_base = func_ctx->mem_info[0].mem_base_addr; + + if (!(func_ctx->mem_info[0].mem_base_addr = + LLVMBuildBitCast(comp_ctx->builder, + func_ctx->mem_info[0].mem_base_addr, int8_ptr_type, "mem_base_addr_ptr"))) { aot_set_last_error("llvm build bit cast failed"); return false; } + if (!(func_ctx->mem_info[0].mem_cur_page_count_addr = + LLVMBuildBitCast(comp_ctx->builder, + func_ctx->mem_info[0].mem_cur_page_count_addr, + INT32_PTR_TYPE, "mem_cur_page_ptr"))) { + aot_set_last_error("llvm build bit cast failed"); + return false; + } if (mem_space_unchanged) { - if (!(func_ctx->mem_base_addr = - LLVMBuildLoad(comp_ctx->builder, func_ctx->mem_base_addr, + if (!(func_ctx->mem_info[0].mem_base_addr = + LLVMBuildLoad(comp_ctx->builder, + func_ctx->mem_info[0].mem_base_addr, + "mem_base_addr"))) { + aot_set_last_error("llvm build load failed"); + return false; + } + if (!(func_ctx->mem_info[0].mem_cur_page_count_addr = + LLVMBuildLoad(comp_ctx->builder, + func_ctx->mem_info[0].mem_cur_page_count_addr, + "mem_cur_page_count_addr"))) { + aot_set_last_error("llvm build load failed"); + return false; + } + } +#if WASM_ENABLE_SHARED_MEMORY != 0 + else if (is_shared_memory) { + /* The base address for shared memory will never changed, + we can load the value here */ + if (!(func_ctx->mem_info[0].mem_base_addr = + LLVMBuildLoad(comp_ctx->builder, + func_ctx->mem_info[0].mem_base_addr, "mem_base_addr"))) { aot_set_last_error("llvm build load failed"); return false; } } +#endif /* Load memory bound check constants */ - offset = I32_CONST(offsetof(AOTModuleInstance, mem_bound_check_1byte)); - if (!(func_ctx->mem_bound_check_1byte = - LLVMBuildInBoundsGEP(comp_ctx->builder, func_ctx->aot_inst, + offset = I32_CONST(offsetof(AOTMemoryInstance, mem_bound_check_1byte) + - offsetof(AOTMemoryInstance, memory_data.ptr)); + if (!(func_ctx->mem_info[0].mem_bound_check_1byte = + LLVMBuildInBoundsGEP(comp_ctx->builder, mem_info_base, &offset, 1, "bound_check_1byte_offset"))) { aot_set_last_error("llvm build in bounds gep failed"); return false; } - if (!(func_ctx->mem_bound_check_1byte = - LLVMBuildBitCast(comp_ctx->builder, func_ctx->mem_bound_check_1byte, + 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"))) { aot_set_last_error("llvm build bit cast failed"); return false; } if (mem_space_unchanged) { - if (!(func_ctx->mem_bound_check_1byte = - LLVMBuildLoad(comp_ctx->builder, func_ctx->mem_bound_check_1byte, - "bound_check_1byte"))) { + if (!(func_ctx->mem_info[0].mem_bound_check_1byte = + LLVMBuildLoad(comp_ctx->builder, + func_ctx->mem_info[0].mem_bound_check_1byte, + "bound_check_1byte"))) { aot_set_last_error("llvm build load failed"); return false; } } - offset = I32_CONST(offsetof(AOTModuleInstance, mem_bound_check_2bytes)); - if (!(func_ctx->mem_bound_check_2bytes = - LLVMBuildInBoundsGEP(comp_ctx->builder, func_ctx->aot_inst, + offset = I32_CONST(offsetof(AOTMemoryInstance, mem_bound_check_2bytes) + - offsetof(AOTMemoryInstance, memory_data.ptr)); + if (!(func_ctx->mem_info[0].mem_bound_check_2bytes = + LLVMBuildInBoundsGEP(comp_ctx->builder, mem_info_base, &offset, 1, "bound_check_2bytes_offset"))) { aot_set_last_error("llvm build in bounds gep failed"); return false; } - if (!(func_ctx->mem_bound_check_2bytes = - LLVMBuildBitCast(comp_ctx->builder, func_ctx->mem_bound_check_2bytes, + 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"))) { aot_set_last_error("llvm build bit cast failed"); return false; } if (mem_space_unchanged) { - if (!(func_ctx->mem_bound_check_2bytes = - LLVMBuildLoad(comp_ctx->builder, func_ctx->mem_bound_check_2bytes, - "bound_check_2bytes"))) { + if (!(func_ctx->mem_info[0].mem_bound_check_2bytes = + LLVMBuildLoad(comp_ctx->builder, + func_ctx->mem_info[0].mem_bound_check_2bytes, + "bound_check_2bytes"))) { aot_set_last_error("llvm build load failed"); return false; } } - offset = I32_CONST(offsetof(AOTModuleInstance, mem_bound_check_4bytes)); - if (!(func_ctx->mem_bound_check_4bytes = - LLVMBuildInBoundsGEP(comp_ctx->builder, func_ctx->aot_inst, + offset = I32_CONST(offsetof(AOTMemoryInstance, mem_bound_check_4bytes) + - offsetof(AOTMemoryInstance, memory_data.ptr)); + if (!(func_ctx->mem_info[0].mem_bound_check_4bytes = + LLVMBuildInBoundsGEP(comp_ctx->builder, mem_info_base, &offset, 1, "bound_check_4bytes_offset"))) { aot_set_last_error("llvm build in bounds gep failed"); return false; } - if (!(func_ctx->mem_bound_check_4bytes = - LLVMBuildBitCast(comp_ctx->builder, func_ctx->mem_bound_check_4bytes, + 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"))) { aot_set_last_error("llvm build bit cast failed"); return false; } if (mem_space_unchanged) { - if (!(func_ctx->mem_bound_check_4bytes = - LLVMBuildLoad(comp_ctx->builder, func_ctx->mem_bound_check_4bytes, - "bound_check_4bytes"))) { + if (!(func_ctx->mem_info[0].mem_bound_check_4bytes = + LLVMBuildLoad(comp_ctx->builder, + func_ctx->mem_info[0].mem_bound_check_4bytes, + "bound_check_4bytes"))) { aot_set_last_error("llvm build load failed"); return false; } } - offset = I32_CONST(offsetof(AOTModuleInstance, mem_bound_check_8bytes)); - if (!(func_ctx->mem_bound_check_8bytes = - LLVMBuildInBoundsGEP(comp_ctx->builder, func_ctx->aot_inst, + offset = I32_CONST(offsetof(AOTMemoryInstance, mem_bound_check_8bytes) + - offsetof(AOTMemoryInstance, memory_data.ptr)); + if (!(func_ctx->mem_info[0].mem_bound_check_8bytes = + LLVMBuildInBoundsGEP(comp_ctx->builder, mem_info_base, &offset, 1, "bound_check_8bytes_offset"))) { aot_set_last_error("llvm build in bounds gep failed"); return false; } - if (!(func_ctx->mem_bound_check_8bytes = - LLVMBuildBitCast(comp_ctx->builder, func_ctx->mem_bound_check_8bytes, + 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"))) { aot_set_last_error("llvm build bit cast failed"); return false; } if (mem_space_unchanged) { - if (!(func_ctx->mem_bound_check_8bytes = - LLVMBuildLoad(comp_ctx->builder, func_ctx->mem_bound_check_8bytes, - "bound_check_8bytes"))) { + if (!(func_ctx->mem_info[0].mem_bound_check_8bytes = + LLVMBuildLoad(comp_ctx->builder, + func_ctx->mem_info[0].mem_bound_check_8bytes, + "bound_check_8bytes"))) { aot_set_last_error("llvm build load failed"); return false; } } /* Load bound_check_heap_base */ - offset = I32_CONST(offsetof(AOTModuleInstance, mem_bound_check_heap_base)); - if (!(func_ctx->mem_bound_check_heap_base = - LLVMBuildInBoundsGEP(comp_ctx->builder, func_ctx->aot_inst, + 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_bound_check_heap_base = - LLVMBuildBitCast(comp_ctx->builder, func_ctx->mem_bound_check_heap_base, + 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_bound_check_heap_base = - LLVMBuildLoad(comp_ctx->builder, func_ctx->mem_bound_check_heap_base, + 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; @@ -616,6 +753,8 @@ aot_create_func_context(AOTCompData *comp_data, AOTCompContext *comp_ctx, return func_ctx; fail: + if (func_ctx->mem_info) + wasm_runtime_free(func_ctx->mem_info); if (func_ctx->exception_blocks) wasm_runtime_free(func_ctx->exception_blocks); aot_block_stack_destroy(&func_ctx->block_stack); @@ -630,6 +769,8 @@ aot_destroy_func_contexts(AOTFuncContext **func_ctxes, uint32 count) for (i = 0; i < count; i++) if (func_ctxes[i]) { + if (func_ctxes[i]->mem_info) + wasm_runtime_free(func_ctxes[i]->mem_info); if (func_ctxes[i]->exception_blocks) wasm_runtime_free(func_ctxes[i]->exception_blocks); aot_block_stack_destroy(&func_ctxes[i]->block_stack); @@ -929,6 +1070,9 @@ aot_create_comp_context(AOTCompData *comp_data, if (option->enable_bulk_memory) comp_ctx->enable_bulk_memory = true; + if (option->enable_thread_mgr) + comp_ctx->enable_thread_mgr = true; + if (option->is_jit_mode) { /* Create LLVM execution engine */ LLVMInitializeMCJITCompilerOptions(&jit_options, sizeof(jit_options)); diff --git a/core/iwasm/compilation/aot_llvm.h b/core/iwasm/compilation/aot_llvm.h index 9fd28a622..82df590e3 100644 --- a/core/iwasm/compilation/aot_llvm.h +++ b/core/iwasm/compilation/aot_llvm.h @@ -99,6 +99,16 @@ typedef struct AOTCheckedAddr { uint32 bytes; } AOTCheckedAddr, *AOTCheckedAddrList; +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; + LLVMValueRef mem_bound_check_8bytes; +} AOTMemInfo; + typedef struct AOTFuncContext { AOTFunc *aot_func; LLVMValueRef func; @@ -111,12 +121,7 @@ typedef struct AOTFuncContext { LLVMValueRef native_stack_bound; LLVMValueRef last_alloca; - LLVMValueRef mem_base_addr; - LLVMValueRef mem_bound_check_heap_base; - LLVMValueRef mem_bound_check_1byte; - LLVMValueRef mem_bound_check_2bytes; - LLVMValueRef mem_bound_check_4bytes; - LLVMValueRef mem_bound_check_8bytes; + AOTMemInfo *mem_info; LLVMValueRef cur_exception; @@ -196,6 +201,9 @@ typedef struct AOTCompContext { /* Bounday Check */ bool enable_bound_check; + /* Thread Manager */ + bool enable_thread_mgr; + /* Whether optimize the JITed code */ bool optimize; @@ -235,6 +243,7 @@ typedef struct AOTCompOption{ char *target_cpu; char *cpu_features; bool enable_bulk_memory; + bool enable_thread_mgr; bool is_sgx_platform; uint32 opt_level; uint32 size_level; diff --git a/core/iwasm/include/aot_export.h b/core/iwasm/include/aot_export.h index 981c9edca..778400d2f 100644 --- a/core/iwasm/include/aot_export.h +++ b/core/iwasm/include/aot_export.h @@ -40,6 +40,7 @@ typedef struct AOTCompOption{ char *target_cpu; char *cpu_features; bool enable_bulk_memory; + bool enable_thread_mgr; bool is_sgx_platform; uint32_t opt_level; uint32_t size_level; diff --git a/core/iwasm/interpreter/wasm_interp_classic.c b/core/iwasm/interpreter/wasm_interp_classic.c index 211ba5bf7..66c257c8d 100644 --- a/core/iwasm/interpreter/wasm_interp_classic.c +++ b/core/iwasm/interpreter/wasm_interp_classic.c @@ -933,8 +933,8 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst, #if WASM_ENABLE_THREAD_MGR != 0 #define CHECK_SUSPEND_FLAGS() do { \ - if (exec_env->suspend_flags != 0) { \ - if (exec_env->suspend_flags & 0x01) { \ + if (exec_env->suspend_flags.flags != 0) { \ + if (exec_env->suspend_flags.flags & 0x01) { \ /* terminate current thread */ \ return; \ } \ diff --git a/core/iwasm/interpreter/wasm_interp_fast.c b/core/iwasm/interpreter/wasm_interp_fast.c index fe34f91e8..2307ead86 100644 --- a/core/iwasm/interpreter/wasm_interp_fast.c +++ b/core/iwasm/interpreter/wasm_interp_fast.c @@ -979,8 +979,8 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst, #if WASM_ENABLE_THREAD_MGR != 0 #define CHECK_SUSPEND_FLAGS() do { \ - if (exec_env->suspend_flags != 0) { \ - if (exec_env->suspend_flags & 0x01) { \ + if (exec_env->suspend_flags.flags != 0) { \ + if (exec_env->suspend_flags.flags & 0x01) { \ /* terminate current thread */ \ return; \ } \ diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index f846f8d2c..7d75a31b4 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -2538,10 +2538,10 @@ load_from_sections(WASMModule *module, WASMSection *sections, && global->is_mutable && global->init_expr.init_expr_type == INIT_EXPR_TYPE_I32_CONST - && (global->init_expr.u.i32 == + && (global->init_expr.u.i32 <= llvm_heap_base_global->init_expr.u.i32 - || global->init_expr.u.i32 == - llvm_data_end_global->init_expr.u.i32)) { + && llvm_data_end_global->init_expr.u.i32 <= + llvm_heap_base_global->init_expr.u.i32)) { llvm_stack_top_global = global; llvm_stack_top = global->init_expr.u.i32; stack_top_global_index = global_index; @@ -2592,7 +2592,7 @@ load_from_sections(WASMModule *module, WASMSection *sections, if (module->memory_count) { memory = &module->memories[0]; init_memory_size = (uint64)memory->num_bytes_per_page * - memory->init_page_count; + memory->init_page_count; if (llvm_heap_base <= init_memory_size && llvm_data_end <= init_memory_size) { /* Reset memory info to decrease memory usage */ diff --git a/core/iwasm/interpreter/wasm_mini_loader.c b/core/iwasm/interpreter/wasm_mini_loader.c index b56aa720d..2e1152428 100644 --- a/core/iwasm/interpreter/wasm_mini_loader.c +++ b/core/iwasm/interpreter/wasm_mini_loader.c @@ -1440,8 +1440,6 @@ load_from_sections(WASMModule *module, WASMSection *sections, WASMGlobal *llvm_stack_top_global = NULL, *global; uint32 llvm_data_end = UINT32_MAX, llvm_heap_base = UINT32_MAX; uint32 llvm_stack_top = UINT32_MAX, global_index, i; - uint32 data_end_global_index = UINT32_MAX; - uint32 heap_base_global_index = UINT32_MAX; uint32 stack_top_global_index = UINT32_MAX; BlockAddr *block_addr_cache; uint64 total_size; @@ -1563,7 +1561,6 @@ load_from_sections(WASMModule *module, WASMSection *sections, && !global->is_mutable && global->init_expr.init_expr_type == INIT_EXPR_TYPE_I32_CONST) { - heap_base_global_index = global_index; llvm_heap_base_global = global; llvm_heap_base = global->init_expr.u.i32; LOG_VERBOSE("found llvm __heap_base global, value: %d\n", @@ -1577,7 +1574,6 @@ load_from_sections(WASMModule *module, WASMSection *sections, && !global->is_mutable && global->init_expr.init_expr_type == INIT_EXPR_TYPE_I32_CONST) { - data_end_global_index = global_index; llvm_data_end_global = global; llvm_data_end = global->init_expr.u.i32; LOG_VERBOSE("found llvm __data_end global, value: %d\n", @@ -1588,26 +1584,29 @@ load_from_sections(WASMModule *module, WASMSection *sections, } if (llvm_data_end_global && llvm_heap_base_global) { - if ((data_end_global_index == heap_base_global_index + 1 - && (int32)data_end_global_index > 1) - || (heap_base_global_index == data_end_global_index + 1 - && (int32)heap_base_global_index > 1)) { - global_index = - data_end_global_index < heap_base_global_index - ? data_end_global_index - 1 : heap_base_global_index - 1; + /* Resolve aux stack top global */ + for (global_index = 0; global_index < module->global_count; global_index++) { global = module->globals + global_index; - if (global->type == VALUE_TYPE_I32 + if (global != llvm_data_end_global + && global != llvm_heap_base_global + && global->type == VALUE_TYPE_I32 && global->is_mutable && global->init_expr.init_expr_type == - INIT_EXPR_TYPE_I32_CONST) { + INIT_EXPR_TYPE_I32_CONST + && (global->init_expr.u.i32 <= + llvm_heap_base_global->init_expr.u.i32 + && llvm_data_end_global->init_expr.u.i32 <= + llvm_heap_base_global->init_expr.u.i32)) { llvm_stack_top_global = global; llvm_stack_top = global->init_expr.u.i32; stack_top_global_index = global_index; LOG_VERBOSE("found llvm stack top global, " "value: %d, global index: %d\n", llvm_stack_top, global_index); + break; } } + module->llvm_aux_data_end = llvm_data_end; module->llvm_aux_stack_bottom = llvm_stack_top; module->llvm_aux_stack_size = llvm_stack_top > llvm_data_end diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index 5212ca1cf..4f8007a1b 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -142,7 +142,7 @@ memory_instantiate(WASMModuleInstance *module_inst, ref_count = shared_memory_inc_reference( (WASMModuleCommon *)module_inst->module); bh_assert(ref_count > 0); - memory = shared_memory_get_memory_inst(node); + memory = (WASMMemoryInstance *)shared_memory_get_memory_inst(node); bh_assert(memory); (void)ref_count; @@ -160,6 +160,7 @@ memory_instantiate(WASMModuleInstance *module_inst, return NULL; } + memory->module_type = Wasm_Module_Bytecode; memory->num_bytes_per_page = num_bytes_per_page; memory->cur_page_count = init_page_count; memory->max_page_count = max_page_count; @@ -194,7 +195,8 @@ memory_instantiate(WASMModuleInstance *module_inst, if (is_shared_memory) { memory->is_shared = true; if (!shared_memory_set_memory_inst( - (WASMModuleCommon *)module_inst->module, memory)) { + (WASMModuleCommon *)module_inst->module, + (WASMMemoryInstanceCommon *)memory)) { set_error_buf(error_buf, error_buf_size, "Instantiate memory failed:" "allocate memory failed."); @@ -1765,7 +1767,7 @@ wasm_set_aux_stack(WASMExecEnv *exec_env, || ((!is_stack_before_data) && (start_offset - data_end < size))) return false; - if (stack_bottom) { + if ((stack_bottom != (uint32)-1) && (stack_top_idx != (uint32)-1)) { /* The aux stack top is a wasm global, set the initial value for the global */ uint8 *global_addr = diff --git a/core/iwasm/interpreter/wasm_runtime.h b/core/iwasm/interpreter/wasm_runtime.h index f8b12c629..361a76111 100644 --- a/core/iwasm/interpreter/wasm_runtime.h +++ b/core/iwasm/interpreter/wasm_runtime.h @@ -22,10 +22,10 @@ typedef struct WASMTableInstance WASMTableInstance; typedef struct WASMGlobalInstance WASMGlobalInstance; typedef struct WASMMemoryInstance { -#if WASM_ENABLE_SHARED_MEMORY != 0 - /* shared memory flag */ + /* Module type */ + uint32 module_type; + /* Shared memory flag */ bool is_shared; -#endif /* Number bytes per page */ uint32 num_bytes_per_page; /* Current page count */ diff --git a/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c b/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c index a19ac6f5b..c13e8c57a 100644 --- a/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c +++ b/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c @@ -489,7 +489,8 @@ pthread_start_routine(void *arg) if(!wasm_runtime_call_indirect(exec_env, routine_args->elem_index, 1, argv)) { - wasm_cluster_spread_exception(exec_env); + if (wasm_runtime_get_exception(module_inst)) + wasm_cluster_spread_exception(exec_env); } /* destroy pthread key values */ @@ -673,6 +674,15 @@ pthread_exit_wrapper(wasm_exec_env_t exec_env, int32 retval_offset) if (!args) return; +#ifdef OS_ENABLE_HW_BOUND_CHECK + /* If hardware bound check enabled, don't deinstantiate module inst + and thread info node here for AoT module, as they will be freed + in pthread_start_routine */ + if (exec_env->jmpbuf_stack_top) { + wasm_cluster_exit_thread(exec_env, (void *)(uintptr_t)retval_offset); + } +#endif + /* destroy pthread key values */ call_key_destructor(exec_env); diff --git a/core/iwasm/libraries/thread-mgr/thread_manager.c b/core/iwasm/libraries/thread-mgr/thread_manager.c index d1d8a531b..8a55265da 100644 --- a/core/iwasm/libraries/thread-mgr/thread_manager.c +++ b/core/iwasm/libraries/thread-mgr/thread_manager.c @@ -290,6 +290,11 @@ thread_manager_start_routine(void *arg) exec_env->handle = os_self_thread(); ret = exec_env->thread_start_routine(exec_env); +#ifdef OS_ENABLE_HW_BOUND_CHECK + if (exec_env->suspend_flags.flags & 0x08) + ret = exec_env->thread_ret_value; +#endif + /* Routine exit */ /* Free aux stack space */ free_aux_stack(cluster, @@ -376,6 +381,25 @@ wasm_cluster_exit_thread(WASMExecEnv *exec_env, void *retval) { WASMCluster *cluster; +#ifdef OS_ENABLE_HW_BOUND_CHECK + if (exec_env->jmpbuf_stack_top) { + WASMJmpBuf *jmpbuf_node; + + /* Store the return value in exec_env */ + exec_env->thread_ret_value = retval; + exec_env->suspend_flags.flags |= 0x08; + + /* Free all jmpbuf_node except the last one */ + while (exec_env->jmpbuf_stack_top->prev) { + jmpbuf_node = wasm_exec_env_pop_jmpbuf(exec_env); + wasm_runtime_free(jmpbuf_node); + } + jmpbuf_node = exec_env->jmpbuf_stack_top; + os_longjmp(jmpbuf_node->jmpbuf, 1); + return; + } +#endif + cluster = wasm_exec_env_get_cluster(exec_env); bh_assert(cluster); @@ -396,7 +420,7 @@ int32 wasm_cluster_cancel_thread(WASMExecEnv *exec_env) { /* Set the termination flag */ - exec_env->suspend_flags |= 0x01; + exec_env->suspend_flags.flags |= 0x01; return 0; } @@ -446,7 +470,7 @@ void wasm_cluster_suspend_thread(WASMExecEnv *exec_env) { /* Set the suspend flag */ - exec_env->suspend_flags |= 0x02; + exec_env->suspend_flags.flags |= 0x02; } static void @@ -479,7 +503,7 @@ wasm_cluster_suspend_all_except_self(WASMCluster *cluster, void wasm_cluster_resume_thread(WASMExecEnv *exec_env) { - exec_env->suspend_flags &= ~0x02; + exec_env->suspend_flags.flags &= ~0x02; } static void diff --git a/doc/pthread_library.md b/doc/pthread_library.md index 622bdfa27..953f76a80 100644 --- a/doc/pthread_library.md +++ b/doc/pthread_library.md @@ -79,6 +79,13 @@ Then build the program with this command: # -Wl,--no-check-features: the errno.o in wasi-sysroot is not compatible with pthread feature, pass this option to avoid errors ``` +**Build AoT module** + +You can build the wasm module into AoT module with pthread support, please pass option `--enable-multi-thread` to wamrc: +``` bash +wamrc --enable-multi-thread -o test.aot test.wasm +``` + Currently WAMR disables pthread library by default. To run the module with pthread support, please build the runtime with `-DWAMR_BUILD_LIB_PTHREAD=1` ``` bash cd ${WAMR_ROOT}/product-mini/platforms/linux @@ -87,10 +94,10 @@ cmake .. -DWAMR_BUILD_LIB_PTHREAD=1 make # Then you can run the wasm module above: ./iwasm test.wasm +# Or the AoT module: +# ./iwasm test.aot ``` -> Note: Currently pthread library is not supported in AoT mode. - [Here](../samples/multi-thread) is also a sample to show how wasm-apps use pthread APIs to create threads, and how to build it with cmake. You can build this sample and have a try: ``` bash cd ${WAMR_ROOT}/samples/multi-thread diff --git a/product-mini/platforms/linux/CMakeLists.txt b/product-mini/platforms/linux/CMakeLists.txt index e7a5a0786..6b1b6e753 100644 --- a/product-mini/platforms/linux/CMakeLists.txt +++ b/product-mini/platforms/linux/CMakeLists.txt @@ -65,6 +65,11 @@ if (NOT DEFINED WAMR_BUILD_MULTI_MODULE) set (WAMR_BUILD_MULTI_MODULE 0) endif () +if (NOT DEFINED WAMR_BUILD_LIB_PTHREAD) + # Disable pthread library by default + set (WAMR_BUILD_LIB_PTHREAD 0) +endif () + if (NOT DEFINED WAMR_BUILD_MINI_LOADER) # Disable wasm mini loader by default set (WAMR_BUILD_MINI_LOADER 0) diff --git a/wamr-compiler/CMakeLists.txt b/wamr-compiler/CMakeLists.txt index 02fadd359..7cdf2fb2a 100644 --- a/wamr-compiler/CMakeLists.txt +++ b/wamr-compiler/CMakeLists.txt @@ -16,6 +16,8 @@ add_definitions(-DWASM_ENABLE_INTERP=1) add_definitions(-DWASM_ENABLE_WAMR_COMPILER=1) add_definitions(-DWASM_ENABLE_BULK_MEMORY=1) add_definitions(-DWASM_DISABLE_HW_BOUND_CHECK=1) +add_definitions(-DWASM_ENABLE_SHARED_MEMORY=1) +add_definitions(-DWASM_ENABLE_THREAD_MGR=1) # Set WAMR_BUILD_TARGET, currently values supported: # "X86_64", "AMD_64", "X86_32", "ARM_32", "MIPS_32", "XTENSA_32" diff --git a/wamr-compiler/main.c b/wamr-compiler/main.c index 7b54cd879..3c72dc381 100644 --- a/wamr-compiler/main.c +++ b/wamr-compiler/main.c @@ -40,6 +40,8 @@ print_help() printf(" llvmir-unopt Unoptimized LLVM IR\n"); printf(" llvmir-opt Optimized LLVM IR\n"); printf(" --enable-bulk-memory Enable the post-MVP bulk memory feature\n"); + printf(" --enable-multi-thread Enable multi-thread feature, the dependent features bulk-memory and\n"); + printf(" thread-mgr will be enabled automatically\n"); printf(" -v=n Set log verbose level (0 to 5, default is 2), larger with more log\n"); printf("Examples: wamrc -o test.aot test.wasm\n"); printf(" wamrc --target=i386 -o test.aot test.wasm\n"); @@ -140,6 +142,10 @@ main(int argc, char *argv[]) else if (!strcmp(argv[0], "--enable-bulk-memory")) { option.enable_bulk_memory = true; } + else if (!strcmp(argv[0], "--enable-multi-thread")) { + option.enable_bulk_memory = true; + option.enable_thread_mgr = true; + } else return print_help(); } From 08d01b65c54a2db24f521855a34561f1b0899d1a Mon Sep 17 00:00:00 2001 From: lum1n0us <62137521+lum1n0us@users.noreply.github.com> Date: Thu, 23 Jul 2020 16:54:13 +0800 Subject: [PATCH 035/207] Eable post-MVP feature wasm-c-api (#315) --- README.md | 6 +- core/config.h | 5 + core/iwasm/common/wasm_c_api.c | 2745 +++++++++++++++++++++++ core/iwasm/common/wasm_c_api_internal.h | 180 ++ core/iwasm/common/wasm_runtime_common.h | 3 - core/iwasm/common/wasm_shared_memory.c | 4 - core/iwasm/include/wasm_c_api.h | 679 ++++++ core/iwasm/include/wasm_export.h | 3 + core/iwasm/interpreter/wasm_loader.c | 2 + core/iwasm/interpreter/wasm_runtime.c | 3 - core/shared/utils/bh_platform.h | 1 + core/shared/utils/bh_vector.c | 38 +- core/shared/utils/bh_vector.h | 10 +- doc/wasm_c_api.md | 77 + samples/multi-module/CMakeLists.txt | 3 +- samples/wasm-c-api/CMakeLists.txt | 89 + samples/wasm-c-api/README.md | 39 + samples/wasm-c-api/src/callback.c | 168 ++ samples/wasm-c-api/src/callback.wasm | Bin 0 -> 102 bytes samples/wasm-c-api/src/callback.wat | 10 + samples/wasm-c-api/src/global.c | 236 ++ samples/wasm-c-api/src/global.wasm | Bin 0 -> 576 bytes samples/wasm-c-api/src/global.wat | 27 + samples/wasm-c-api/src/hello.c | 112 + samples/wasm-c-api/src/hello.wasm | Bin 0 -> 71 bytes samples/wasm-c-api/src/hello.wat | 4 + 26 files changed, 4405 insertions(+), 39 deletions(-) create mode 100644 core/iwasm/common/wasm_c_api.c create mode 100644 core/iwasm/common/wasm_c_api_internal.h create mode 100644 core/iwasm/include/wasm_c_api.h create mode 100644 doc/wasm_c_api.md create mode 100644 samples/wasm-c-api/CMakeLists.txt create mode 100644 samples/wasm-c-api/README.md create mode 100644 samples/wasm-c-api/src/callback.c create mode 100644 samples/wasm-c-api/src/callback.wasm create mode 100644 samples/wasm-c-api/src/callback.wat create mode 100644 samples/wasm-c-api/src/global.c create mode 100644 samples/wasm-c-api/src/global.wasm create mode 100644 samples/wasm-c-api/src/global.wat create mode 100644 samples/wasm-c-api/src/hello.c create mode 100644 samples/wasm-c-api/src/hello.wasm create mode 100644 samples/wasm-c-api/src/hello.wat diff --git a/README.md b/README.md index 28045e26b..a5a667a76 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ WebAssembly Micro Runtime ========================= -[Build WAMR VM core](./doc/build_wamr.md) | [Embed WAMR](./doc/embed_wamr.md) | [Export native function](./doc/export_native_api.md) | [Build WASM applications](./doc/build_wasm_app.md) | [Samples](https://github.com/bytecodealliance/wasm-micro-runtime#samples-and-demos) +[Build WAMR VM core](./doc/build_wamr.md) | [Embed WAMR](./doc/embed_wamr.md) | [Export native function](./doc/export_native_api.md) | [Build WASM applications](./doc/build_wasm_app.md) | [Samples](https://github.com/bytecodealliance/wasm-micro-runtime#samples) **A [Bytecode Alliance][BA] project** @@ -36,6 +36,7 @@ iwasm VM core - [Bulk memory operations](https://github.com/WebAssembly/bulk-memory-operations) - [Shared memory](https://github.com/WebAssembly/threads/blob/main/proposals/threads/Overview.md#shared-linear-memory) - [Multi-value](https://github.com/WebAssembly/multi-value) +- [wasm-c-api](https://github.com/WebAssembly/wasm-c-api) ### Performance and memory usage The WAMR performance, footprint and memory usage data are available at the [performance](../../wiki/Performance) wiki page. @@ -112,8 +113,7 @@ The WAMR [samples](./samples) integrate the iwasm VM core, application manager a - **[Simple](./samples/simple/README.md)**: The runtime is integrated with most of the WAMR APP libraries, and a few WASM applications are provided for testing the WAMR APP API set. It uses **built-in libc** and executes apps in **interpreter** mode by default. - **[littlevgl](./samples/littlevgl/README.md)**: Demonstrating the graphic user interface application usage on WAMR. The whole [LittlevGL](https://github.com/littlevgl/) 2D user graphic library and the UI application is built into WASM application. It uses **WASI libc** and executes apps in **AoT mode** by default. - **[gui](./samples/gui/README.md)**: Moved the [LittlevGL](https://github.com/littlevgl/) library into the runtime and defined a WASM application interface by wrapping the littlevgl API. It uses **WASI libc** and executes apps in **interpreter** mode by default. - - +- **[wasm-c-api](./samples/wasm-c-api/README.md)**: they are samples from [wasm-c-api proposal](https://github.com/WebAssembly/wasm-c-api) and show supported APIs. Releases and acknowledgments diff --git a/core/config.h b/core/config.h index 9dd042a5c..c14eac4e3 100644 --- a/core/config.h +++ b/core/config.h @@ -127,6 +127,11 @@ enum { /* WASM Interpreter labels-as-values feature */ #define WASM_ENABLE_LABELS_AS_VALUES 1 +/* Enable fast interpreter or not */ +#ifndef WASM_ENABLE_FAST_INTERP +#define WASM_ENABLE_FAST_INTERP 0 +#endif + #if WASM_ENABLE_FAST_INTERP != 0 #define WASM_ENABLE_ABS_LABEL_ADDR 1 #define WASM_DEBUG_PREPROCESSOR 0 diff --git a/core/iwasm/common/wasm_c_api.c b/core/iwasm/common/wasm_c_api.c new file mode 100644 index 000000000..dc6e38a29 --- /dev/null +++ b/core/iwasm/common/wasm_c_api.c @@ -0,0 +1,2745 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "wasm_c_api_internal.h" +#include "wasm_memory.h" +#if WASM_ENABLE_INTERP != 0 +#include "wasm_runtime.h" +#endif +#if WASM_ENABLE_AOT != 0 +#include "aot_runtime.h" +#endif + +#define NOT_REACHED() bh_assert(!"should not be reached") + +typedef struct wasm_module_ex_t wasm_module_ex_t; + +void +wasm_module_delete_internal(wasm_module_t *); + +void +wasm_instance_delete_internal(wasm_instance_t *); + +static void * +malloc_internal(size_t size) +{ + void *mem = NULL; + + if (size >= UINT32_MAX) { + return NULL; + } + + mem = wasm_runtime_malloc((uint32)size); + if (mem) { + memset(mem, 0, size); + } + + return mem; +} + +#define FREEIF(p) \ + if (p) { \ + wasm_runtime_free(p); \ + } + +/* Vectors */ +#define INIT_VEC(vector_p, func_prefix, size) \ + do { \ + vector_p = malloc_internal(sizeof(*(vector_p))); \ + if (!vector_p) { \ + goto failed; \ + } \ + func_prefix##_new_uninitialized(vector_p, size); \ + if (!(vector_p)->data) { \ + goto failed; \ + } \ + } while (false) + +#define DEINIT_VEC(vector_p, delete_func) \ + if ((vector_p)) { \ + if ((vector_p)->data) { \ + delete_func(vector_p); \ + } \ + wasm_runtime_free(vector_p); \ + vector_p = NULL; \ + } + +#define FREE_VEC_ELEMS(vec, del_func) \ + for (i = 0; i < (vec)->num_elems; ++i) { \ + del_func(*((vec)->data + i)); \ + *((vec)->data + i) = NULL; \ + } + +static inline void +generic_vec_init_data(Vector *out, size_t num_of_elems, size_t size_of_elem) +{ + if (!bh_vector_init(out, num_of_elems, size_of_elem)) { + memset(out, 0, sizeof(Vector)); + } + else { + memset(out->data, 0, num_of_elems * size_of_elem); + } +} + +void +wasm_byte_vec_new_uninitialized(wasm_byte_vec_t *out, size_t size) +{ + bh_assert(out); + generic_vec_init_data((Vector *)out, size, sizeof(wasm_byte_t)); +} + +void +wasm_byte_vec_copy(wasm_byte_vec_t *out, const wasm_byte_vec_t *src) +{ + uint32 len = 0; + + bh_assert(out && src); + + generic_vec_init_data((Vector *)out, src->size, src->size_of_elem); + if (!out->data) { + goto failed; + } + + len = src->size * src->size_of_elem; + bh_memcpy_s(out->data, len, src->data, len); + out->num_elems = src->num_elems; + return; + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + wasm_byte_vec_delete(out); +} + +void +wasm_byte_vec_new(wasm_byte_vec_t *out, size_t size, const wasm_byte_t *data) +{ + size_t size_in_bytes = 0; + + bh_assert(out && data); + + generic_vec_init_data((Vector *)out, size, sizeof(wasm_byte_t)); + if (!out->data) { + goto failed; + } + + size_in_bytes = size * sizeof(wasm_byte_t); + bh_memcpy_s(out->data, size_in_bytes, data, size_in_bytes); + out->num_elems = size; + return; + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + wasm_byte_vec_delete(out); +} + +void +wasm_byte_vec_delete(wasm_byte_vec_t *byte_vec) +{ + if (byte_vec && byte_vec->data) { + bh_vector_destroy((Vector *)byte_vec); + } +} + +/* Runtime Environment */ +static void +wasm_engine_delete_internal(wasm_engine_t *engine) +{ + if (engine) { + DEINIT_VEC(engine->stores, wasm_store_vec_delete); + wasm_runtime_free(engine); + } + + wasm_runtime_destroy(); +} + +static wasm_engine_t * +wasm_engine_new_internal(mem_alloc_type_t type, + const MemAllocOption *opts, + runtime_mode_e mode) +{ + wasm_engine_t *engine = NULL; + /* init runtime */ + RuntimeInitArgs init_args = { 0 }; + init_args.mem_alloc_type = type; + + if (type == Alloc_With_Pool) { + init_args.mem_alloc_option.pool.heap_buf = opts->pool.heap_buf; + init_args.mem_alloc_option.pool.heap_size = opts->pool.heap_size; + } + else if (type == Alloc_With_Allocator) { + init_args.mem_alloc_option.allocator.malloc_func = + opts->allocator.malloc_func; + init_args.mem_alloc_option.allocator.free_func = + opts->allocator.free_func; + init_args.mem_alloc_option.allocator.realloc_func = + opts->allocator.realloc_func; + } + else { + init_args.mem_alloc_option.pool.heap_buf = NULL; + init_args.mem_alloc_option.pool.heap_size = 0; + } + + if (!wasm_runtime_full_init(&init_args)) { + goto failed; + } + +#if BH_DEBUG == 1 + bh_log_set_verbose_level(5); +#else + bh_log_set_verbose_level(3); +#endif + + /* create wasm_engine_t */ + engine = malloc_internal(sizeof(wasm_engine_t)); + if (!engine) { + goto failed; + } + + /* set running mode */ + LOG_WARNING("running under mode %d", mode); + engine->mode = mode; + + /* create wasm_store_vec_t */ + INIT_VEC(engine->stores, wasm_store_vec, 1); + + return engine; + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + wasm_engine_delete_internal(engine); + return NULL; +} + +/* global engine instance */ +static wasm_engine_t *singleton_engine = NULL; + +static inline runtime_mode_e +current_runtime_mode() +{ + bh_assert(singleton_engine); + return singleton_engine->mode; +} + +wasm_engine_t * +wasm_engine_new() +{ + runtime_mode_e mode = INTERP_MODE; +#if WASM_ENABLE_INTERP == 0 && WASM_ENABLE_AOT != 0 + mode = AOT_MODE; +#endif + + if (INTERP_MODE == mode) { +#if WASM_ENABLE_INTERP == 0 + bh_assert(!"does not support INTERP_MODE. Please recompile"); +#endif + } + else { +#if WASM_ENABLE_AOT == 0 + bh_assert(!"does not support AOT_MODE. Please recompile"); +#endif + } + + if (!singleton_engine) { + singleton_engine = + wasm_engine_new_internal(Alloc_With_System_Allocator, NULL, mode); + } + return singleton_engine; +} + +wasm_engine_t * +wasm_engine_new_with_args(mem_alloc_type_t type, + const MemAllocOption *opts, + runtime_mode_e mode) +{ + if (!singleton_engine) { + singleton_engine = wasm_engine_new_internal(type, opts, mode); + } + return singleton_engine; +} + +void +wasm_engine_delete(wasm_engine_t *engine) +{ + if (engine) { + wasm_engine_delete_internal(engine); + singleton_engine = NULL; + } +} + +wasm_store_t * +wasm_store_new(wasm_engine_t *engine) +{ + wasm_store_t *store = NULL; + + bh_assert(engine && singleton_engine == engine); + + /* always return the first store */ + if (bh_vector_size((Vector *)singleton_engine->stores) > 0) { + /* + * although it is a copy of the first store, but still point to + * the wasm_store_t + */ + if (!bh_vector_get((Vector *)singleton_engine->stores, 0, &store)) { + goto failed; + } + return store; + } + + store = malloc_internal(sizeof(wasm_store_t)); + if (!store) { + goto failed; + } + + /* new a vector, and new its data */ + INIT_VEC(store->modules, wasm_module_vec, DEFAULT_VECTOR_INIT_LENGTH); + INIT_VEC(store->instances, wasm_instance_vec, DEFAULT_VECTOR_INIT_LENGTH); + + /* append to a store list of engine */ + if (!bh_vector_append((Vector *)singleton_engine->stores, &store)) { + goto failed; + } + + return store; + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + wasm_store_delete(store); + return NULL; +} + +void +wasm_store_delete(wasm_store_t *store) +{ + if (!store || singleton_engine->stores->num_elems == 0) { + return; + } + + DEINIT_VEC(store->modules, wasm_module_vec_delete); + DEINIT_VEC(store->instances, wasm_instance_vec_delete); + + wasm_runtime_free(store); + bh_vector_remove((Vector *)singleton_engine->stores, 0, NULL); +} + +void +wasm_store_vec_new_uninitialized(wasm_store_vec_t *out, size_t size) +{ + bh_assert(out); + generic_vec_init_data((Vector *)out, size, sizeof(wasm_store_t *)); +} + +void +wasm_store_vec_delete(wasm_store_vec_t *store_vec) +{ + size_t i = 0; + if (!store_vec || !store_vec->data) { + return; + } + + FREE_VEC_ELEMS(store_vec, wasm_store_delete); + bh_vector_destroy((Vector *)store_vec); +} + +static inline void +check_engine_and_store(wasm_engine_t *engine, wasm_store_t *store) +{ + /* remove it if we are supporting more than one store */ + bh_assert(engine && store && engine->stores->data[0] == store); +} + +/* Type Representations */ +static wasm_valtype_t * +wasm_valtype_new_internal(uint8 val_type_rt) +{ + switch (val_type_rt) { + case VALUE_TYPE_I32: + return wasm_valtype_new_i32(); + case VALUE_TYPE_I64: + return wasm_valtype_new_i64(); + case VALUE_TYPE_F32: + return wasm_valtype_new_f32(); + case VALUE_TYPE_F64: + return wasm_valtype_new_f64(); + case VALUE_TYPE_ANY: + return wasm_valtype_new_anyref(); + default: + return NULL; + } +} + +wasm_valtype_t * +wasm_valtype_new(wasm_valkind_t kind) +{ + wasm_valtype_t *val_type = malloc_internal(sizeof(wasm_valtype_t)); + if (val_type) { + val_type->kind = kind; + } + return val_type; +} + +void +wasm_valtype_delete(wasm_valtype_t *val_type) +{ + bh_assert(val_type); + wasm_runtime_free(val_type); +} + +wasm_valtype_t * +wasm_valtype_copy(wasm_valtype_t *src) +{ + bh_assert(src); + return wasm_valtype_new(src->kind); +} + +wasm_valkind_t +wasm_valtype_kind(const wasm_valtype_t *val_type) +{ + bh_assert(val_type); + return val_type->kind; +} + +bool +wasm_valtype_same(const wasm_valtype_t *vt1, const wasm_valtype_t *vt2) +{ + if (!vt1 && !vt2) { + return true; + } + + if (!vt1 || !vt2) { + return false; + } + + return vt1->kind == vt2->kind; +} + +void +wasm_valtype_vec_new_uninitialized(wasm_valtype_vec_t *out, size_t size) +{ + bh_assert(out); + generic_vec_init_data((Vector *)out, size, sizeof(wasm_valtype_t *)); +} + +void +wasm_valtype_vec_new_empty(wasm_valtype_vec_t *out) +{ + bh_assert(out); + memset(out, 0, sizeof(wasm_valtype_vec_t)); +} + +void +wasm_valtype_vec_new(wasm_valtype_vec_t *out, + size_t size, + wasm_valtype_t *const data[]) +{ + size_t size_in_bytes = 0; + bh_assert(out && data); + generic_vec_init_data((Vector *)out, size, sizeof(wasm_valtype_t *)); + if (!out->data) { + goto failed; + } + + size_in_bytes = size * sizeof(wasm_valtype_t *); + bh_memcpy_s(out->data, size_in_bytes, data, size_in_bytes); + out->num_elems = size; + return; + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + wasm_valtype_vec_delete(out); +} + +void +wasm_valtype_vec_copy(wasm_valtype_vec_t *out, const wasm_valtype_vec_t *src) +{ + size_t i = 0; + + bh_assert(out && src); + + generic_vec_init_data((Vector *)out, src->size, src->size_of_elem); + if (!out->data) { + goto failed; + } + + /* clone every wasm_valtype_t */ + for (i = 0; i < src->num_elems; i++) { + wasm_valtype_t *cloned = wasm_valtype_copy(*(src->data + i)); + if (!cloned) { + goto failed; + } + if (!bh_vector_append((Vector *)out, &cloned)) { + goto failed; + } + } + + return; + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + wasm_valtype_vec_delete(out); +} + +void +wasm_valtype_vec_delete(wasm_valtype_vec_t *val_type_vec) +{ + size_t i = 0; + if (!val_type_vec || !val_type_vec->data) { + return; + } + + FREE_VEC_ELEMS(val_type_vec, wasm_valtype_delete); + bh_vector_destroy((Vector *)val_type_vec); +} + +static wasm_functype_t * +wasm_functype_new_internal(WASMType *type_rt) +{ + wasm_functype_t *func_type = NULL; + uint32 i = 0; + + bh_assert(type_rt); + + func_type = malloc_internal(sizeof(wasm_functype_t)); + if (!func_type) { + goto failed; + } + + /* WASMType->types[0 : type_rt->param_count) -> func_type->params */ + INIT_VEC(func_type->params, wasm_valtype_vec, type_rt->param_count); + for (i = 0; i < type_rt->param_count; ++i) { + wasm_valtype_t *param_type = + wasm_valtype_new_internal(*(type_rt->types + i)); + if (!param_type) { + goto failed; + } + + if (!bh_vector_append((Vector *)func_type->params, ¶m_type)) { + goto failed; + } + } + + /* WASMType->types[type_rt->param_count : type_rt->result_count) -> func_type->results */ + INIT_VEC(func_type->results, wasm_valtype_vec, type_rt->result_count); + for (i = type_rt->param_count; i < type_rt->result_count; ++i) { + wasm_valtype_t *result_type = + wasm_valtype_new_internal(*(type_rt->types + i)); + if (!result_type) { + goto failed; + } + + if (!bh_vector_append((Vector *)func_type->results, &result_type)) { + goto failed; + } + } + + return func_type; + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + wasm_functype_delete(func_type); + return NULL; +} + +wasm_functype_t * +wasm_functype_new(wasm_valtype_vec_t *params, wasm_valtype_vec_t *results) +{ + wasm_functype_t *func_type = NULL; + + bh_assert(params); + bh_assert(results); + + func_type = malloc_internal(sizeof(wasm_functype_t)); + if (!func_type) { + goto failed; + } + + func_type->extern_kind = WASM_EXTERN_FUNC; + + func_type->params = malloc_internal(sizeof(wasm_valtype_vec_t)); + if (!func_type->params) { + goto failed; + } + + /* transfer ownership of contents of params and results */ + bh_memcpy_s(func_type->params, sizeof(wasm_valtype_vec_t), params, + sizeof(wasm_valtype_vec_t)); + + func_type->results = malloc_internal(sizeof(wasm_valtype_vec_t)); + if (!func_type->results) { + goto failed; + } + + bh_memcpy_s(func_type->results, sizeof(wasm_valtype_vec_t), results, + sizeof(wasm_valtype_vec_t)); + + return func_type; + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + FREEIF(func_type->params); + FREEIF(func_type->results); + FREEIF(func_type); + return NULL; +} + +wasm_functype_t * +wasm_functype_copy(wasm_functype_t *src) +{ + wasm_functype_t *dst = NULL; + + bh_assert(src); + + dst = malloc_internal(sizeof(wasm_functype_t)); + if (!dst) { + goto failed; + } + + dst->extern_kind = src->extern_kind; + + dst->params = malloc_internal(sizeof(wasm_valtype_vec_t)); + if (!dst->params) { + goto failed; + } + + wasm_valtype_vec_copy(dst->params, src->params); + if (!dst->params) { + goto failed; + } + + dst->results = malloc_internal(sizeof(wasm_valtype_vec_t)); + if (!dst->results) { + goto failed; + } + + wasm_valtype_vec_copy(dst->results, src->results); + if (!dst->results) { + goto failed; + } + + return dst; + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + wasm_functype_delete(dst); + return NULL; +} + +void +wasm_functype_delete(wasm_functype_t *func_type) +{ + if (!func_type) { + return; + } + + if (func_type->params) { + wasm_valtype_vec_delete(func_type->params); + wasm_runtime_free(func_type->params); + func_type->params = NULL; + } + + if (func_type->results) { + wasm_valtype_vec_delete(func_type->results); + wasm_runtime_free(func_type->results); + func_type->results = NULL; + } + + wasm_runtime_free(func_type); +} + +const wasm_valtype_vec_t * +wasm_functype_params(const wasm_functype_t *func_type) +{ + bh_assert(func_type); + return func_type->params; +} + +const wasm_valtype_vec_t * +wasm_functype_results(const wasm_functype_t *func_type) +{ + bh_assert(func_type); + return func_type->results; +} + +wasm_globaltype_t * +wasm_globaltype_new(wasm_valtype_t *val_type, wasm_mutability_t mut) +{ + wasm_globaltype_t *global_type = NULL; + + bh_assert(val_type); + + global_type = malloc_internal(sizeof(wasm_globaltype_t)); + if (!global_type) { + goto failed; + } + + global_type->val_type = val_type; + global_type->mutability = mut; + + return global_type; + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + wasm_globaltype_delete(global_type); + return NULL; +} + +wasm_globaltype_t * +wasm_globaltype_new_internal(uint8 val_type_rt, bool is_mutable) +{ + wasm_globaltype_t *global_type = NULL; + + global_type = malloc_internal(sizeof(wasm_globaltype_t)); + if (!global_type) { + goto failed; + } + + global_type->val_type = wasm_valtype_new_internal(val_type_rt); + if (!global_type->val_type) { + goto failed; + } + + global_type->mutability = is_mutable ? WASM_VAR : WASM_CONST; + + return global_type; + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + wasm_globaltype_delete(global_type); + return NULL; +} + +void +wasm_globaltype_delete(wasm_globaltype_t *global_type) +{ + if (!global_type) { + return; + } + + if (global_type->val_type) { + wasm_valtype_delete(global_type->val_type); + global_type->val_type = NULL; + } + + wasm_runtime_free(global_type); +} + +wasm_globaltype_t * +wasm_globaltype_copy(wasm_globaltype_t *src) +{ + wasm_globaltype_t *dst = NULL; + + bh_assert(src); + + dst = malloc_internal(sizeof(wasm_globaltype_t)); + if (!dst) { + goto failed; + } + + dst->val_type = wasm_valtype_copy(src->val_type); + if (!dst->val_type) { + goto failed; + } + + dst->mutability = src->mutability; + + return dst; + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + wasm_globaltype_delete(dst); + return NULL; +} + +const wasm_valtype_t * +wasm_globaltype_content(const wasm_globaltype_t *global_type) +{ + bh_assert(global_type); + return global_type->val_type; +} + +wasm_mutability_t +wasm_globaltype_mutability(const wasm_globaltype_t *global_type) +{ + bh_assert(global_type); + return global_type->mutability; +} + +bool +wasm_globaltype_same(const wasm_globaltype_t *gt1, + const wasm_globaltype_t *gt2) +{ + if (!gt1 && !gt2) { + return true; + } + + if (!gt1 || !gt2) { + return false; + } + + return wasm_valtype_same(gt1->val_type, gt2->val_type) + || gt1->mutability == gt2->mutability; +} + +wasm_tabletype_t * +wasm_tabletype_new(wasm_valtype_t *val_type, const wasm_limits_t *limits) +{ + return NULL; +} + +void +wasm_tabletype_delete(wasm_tabletype_t *table_type) +{} + +wasm_memorytype_t * +wasm_memorytype_new(const wasm_limits_t *limits) +{ + return NULL; +} + +void +wasm_memorytype_delete(wasm_memorytype_t *memory_type) +{} + +/* Runtime Objects */ + +void +wasm_val_delete(wasm_val_t *v) +{ + /* do nothing */ +} + +void +wasm_val_copy(wasm_val_t *out, const wasm_val_t *src) +{ + bh_assert(out && src); + bh_memcpy_s(out, sizeof(wasm_val_t), src, sizeof(wasm_val_t)); +} + +bool +wasm_val_same(const wasm_val_t *v1, const wasm_val_t *v2) +{ + if (!v1 && !v2) { + return true; + } + + if (!v1 || !v2) { + return false; + } + + if (v1->kind != v2->kind) { + return false; + } + + switch (v1->kind) { + case WASM_I32: + return v1->of.i32 == v2->of.i32; + case WASM_I64: + return v1->of.i64 == v2->of.i64; + case WASM_F32: + return v1->of.f32 == v2->of.f32; + case WASM_F64: + return v1->of.f64 == v2->of.f64; + case WASM_FUNCREF: + return v1->of.ref == v2->of.ref; + default: + break; + } + return false; +} + +wasm_trap_t * +wasm_trap_new(wasm_store_t *store, const wasm_message_t *message) +{ + wasm_trap_t *trap; + + bh_assert(store && message); + + trap = malloc_internal(sizeof(wasm_trap_t)); + if (!trap) { + goto failed; + } + + wasm_byte_vec_new(trap->message, message->num_elems, message->data); + if (!trap->message->data) { + goto failed; + } + + return trap; + +failed: + wasm_trap_delete(trap); + return NULL; +} + +void +wasm_trap_delete(wasm_trap_t *trap) +{ + if (!trap) { + return; + } + + if (trap->message) { + wasm_byte_vec_delete(trap->message); + } + + wasm_runtime_free(trap); +} + +void +wasm_trap_message(const wasm_trap_t *trap, wasm_message_t *out) +{ + bh_assert(trap && out); + wasm_byte_vec_copy(out, trap->message); +} + +struct wasm_module_ex_t { + struct WASMModuleCommon *module_comm_rt; + wasm_byte_vec_t *binary; +}; + +static inline wasm_module_t * +module_ext_to_module(wasm_module_ex_t *module_ex) +{ + return (wasm_module_t *)module_ex; +} + +static inline wasm_module_ex_t * +module_to_module_ext(wasm_module_t *module) +{ + return (wasm_module_ex_t *)module; +} + +wasm_module_t * +wasm_module_new(wasm_store_t *store, const wasm_byte_vec_t *binary) +{ + char error[128] = { 0 }; + wasm_module_ex_t *module_ex = NULL; + PackageType pkg_type = Package_Type_Unknown; + + check_engine_and_store(singleton_engine, store); + bh_assert(binary && binary->data && binary->size); + + pkg_type = get_package_type((uint8 *)binary->data, binary->size); + if (Package_Type_Unknown == pkg_type + || (Wasm_Module_Bytecode == pkg_type + && INTERP_MODE != current_runtime_mode()) + || (Wasm_Module_AoT == pkg_type + && INTERP_MODE == current_runtime_mode())) { + LOG_WARNING( + "current runtime mode %d doesn\'t support the package type " + "%d", + current_runtime_mode(), pkg_type); + goto failed; + } + + module_ex = malloc_internal(sizeof(wasm_module_ex_t)); + if (!module_ex) { + goto failed; + } + + module_ex->binary = malloc_internal(sizeof(wasm_byte_vec_t)); + if (!module_ex->binary) { + goto failed; + } + + wasm_byte_vec_copy(module_ex->binary, binary); + if (!module_ex->binary->data) { + goto failed; + } + + module_ex->module_comm_rt = + wasm_runtime_load((uint8 *)module_ex->binary->data, + module_ex->binary->size, error, (uint32)sizeof(error)); + if (!(module_ex->module_comm_rt)) { + LOG_ERROR(error); + goto failed; + } + + /* add it to a watching list in store */ + if (!bh_vector_append((Vector *)store->modules, &module_ex)) { + goto failed; + } + + return module_ext_to_module(module_ex); + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + wasm_module_delete_internal(module_ext_to_module(module_ex)); + return NULL; +} + +void +wasm_module_delete_internal(wasm_module_t *module) +{ + wasm_module_ex_t *module_ex; + if (!module) { + return; + } + + module_ex = module_to_module_ext(module); + if (module_ex->binary) { + wasm_byte_vec_delete(module_ex->binary); + wasm_runtime_free(module_ex->binary); + module_ex->binary = NULL; + } + + if (module_ex->module_comm_rt) { + wasm_runtime_unload(module_ex->module_comm_rt); + module_ex->module_comm_rt = NULL; + } + + wasm_runtime_free(module_ex); +} + +/* will release module when releasing the store */ +void +wasm_module_delete(wasm_module_t *module) +{ + /* pass */ +} + +void +wasm_module_vec_new_uninitialized(wasm_module_vec_t *out, size_t size) +{ + generic_vec_init_data((Vector *)out, size, sizeof(wasm_module_t *)); +} + +void +wasm_module_vec_delete(wasm_module_vec_t *module_vec) +{ + size_t i = 0; + if (!module_vec || !module_vec->data) { + return; + } + + FREE_VEC_ELEMS(module_vec, wasm_module_delete_internal); + bh_vector_destroy((Vector *)module_vec); +} + +static uint32 +argv_to_params(const uint64 *argv, + const wasm_valtype_vec_t *param_defs, + wasm_val_t *out) +{ + size_t i = 0; + uint32 argc = 0; + void *argv_p = (void *)argv; + + for (i = 0; i < param_defs->num_elems; i++) { + wasm_valtype_t *param_def = param_defs->data[i]; + wasm_val_t *param = out + i; + switch (param_def->kind) { + case WASM_I32: + param->kind = WASM_I32; + param->of.i32 = *(uint32 *)argv_p; + argv_p = (uint32 *)argv_p + 1; + argc++; + break; + case WASM_I64: + param->kind = WASM_I64; + param->of.i64 = *(uint64 *)argv_p; + argv_p = (uint64 *)argv_p + 1; + argc++; + break; + case WASM_F32: + param->kind = WASM_F32; + param->of.f32 = *(float32 *)argv_p; + argv_p = (float32 *)argv_p + 1; + argc++; + break; + case WASM_F64: + param->kind = WASM_F64; + param->of.f64 = *(float64 *)argv_p; + argv_p = (float64 *)argv_p + 1; + argc++; + break; + default: + NOT_REACHED(); + goto failed; + } + } + + return argc; +failed: + return 0; +} + +static uint32 +results_to_argv(const wasm_val_t *results, + const wasm_valtype_vec_t *result_defs, + uint64 *out) +{ + size_t i = 0; + uint32 argc = 0; + void *argv_p = out; + + for (i = 0; i < result_defs->num_elems; ++i) { + wasm_valtype_t *result_def = result_defs->data[i]; + const wasm_val_t *result = results + i; + switch (result_def->kind) { + case WASM_I32: + *(uint32 *)argv_p = result->of.i32; + argv_p = (uint32 *)argv_p + 1; + argc++; + break; + case WASM_I64: + *(uint64 *)argv_p = result->of.i64; + argv_p = (uint64 *)argv_p + 1; + argc++; + break; + case WASM_F32: + *(float32 *)argv_p = result->of.f32; + argv_p = (float32 *)argv_p + 1; + argc++; + break; + case WASM_F64: + *(float64 *)argv_p = result->of.f64; + argv_p = (float64 *)argv_p + 1; + argc++; + break; + default: + NOT_REACHED(); + goto failed; + } + } + + return argc; +failed: + return 0; +} + +static void +native_func_trampoline(wasm_exec_env_t exec_env, uint64 *argv) +{ + wasm_val_t *params = NULL; + wasm_val_t *results = NULL; + uint32 argc = 0; + const wasm_func_t *func = NULL; + wasm_trap_t *trap = NULL; + + bh_assert(argv); + + func = wasm_runtime_get_function_attachment(exec_env); + bh_assert(func); + + params = malloc_internal(wasm_func_param_arity(func) * sizeof(wasm_val_t)); + if (!params) { + goto failed; + } + + results = + malloc_internal(wasm_func_result_arity(func) * sizeof(wasm_val_t)); + if (!results) { + goto failed; + } + + /* argv -> const wasm_val_t params[] */ + argc = + argv_to_params(argv, wasm_functype_params(wasm_func_type(func)), params); + if (wasm_func_param_arity(func) && !argc) { + goto failed; + } + + if (func->with_env) { + trap = func->u.cb_env.cb(func->u.cb_env.env, params, results); + } + else { + trap = func->u.cb(params, results); + } + + if (trap) { + wasm_name_t *message = NULL; + wasm_trap_message(trap, message); + LOG_WARNING("got a trap %s", message->data); + wasm_name_delete(message); + } + + /* there is no result or there is an exception */ + if (trap || !wasm_func_result_arity(func)) { + memset(argv, 0, wasm_func_param_arity(func) * sizeof(uint64)); + } + + /* wasm_val_t results[] -> argv */ + argc = results_to_argv(results, + wasm_functype_results(wasm_func_type(func)), argv); + if (wasm_func_result_arity(func) && !argc) { + goto failed; + } + +failed: + FREEIF(params); + FREEIF(results); + return; +} + +wasm_func_t * +wasm_func_new(wasm_store_t *store, + const wasm_functype_t *func_type, + wasm_func_callback_t callback) +{ + wasm_func_t *func = NULL; + + check_engine_and_store(singleton_engine, store); + bh_assert(func_type); + + func = malloc_internal(sizeof(wasm_func_t)); + if (!func) { + goto failed; + } + + func->kind = WASM_EXTERN_FUNC; + func->with_env = false; + func->u.cb = callback; + + func->func_type = wasm_functype_copy((wasm_functype_t *)func_type); + if (!func->func_type) { + goto failed; + } + + return func; + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + wasm_func_delete(func); + return NULL; +} + +wasm_func_t * +wasm_func_new_with_env(wasm_store_t *store, + const wasm_functype_t *func_type, + wasm_func_callback_with_env_t callback, + void *env, + void (*finalizer)(void *)) +{ + wasm_func_t *func = NULL; + + check_engine_and_store(singleton_engine, store); + bh_assert(func_type); + + func = malloc_internal(sizeof(wasm_func_t)); + if (!func) { + goto failed; + } + + func->kind = WASM_EXTERN_FUNC; + func->with_env = true; + func->u.cb_env.cb = callback; + func->u.cb_env.env = env; + func->u.cb_env.finalizer = finalizer; + + func->func_type = wasm_functype_copy((wasm_functype_t *)func_type); + if (!func->func_type) { + goto failed; + } + + return func; + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + wasm_func_delete(func); + return NULL; +} + +static wasm_func_t * +wasm_func_new_internal(wasm_store_t *store, + uint16 func_idx_rt, + WASMModuleInstanceCommon *inst_comm_rt) +{ + wasm_func_t *func = NULL; + WASMType *type_rt = NULL; + + check_engine_and_store(singleton_engine, store); + bh_assert(inst_comm_rt); + + func = malloc_internal(sizeof(wasm_func_t)); + if (!func) { + goto failed; + } + + func->kind = WASM_EXTERN_FUNC; + + if (INTERP_MODE == current_runtime_mode()) { +#if WASM_ENABLE_INTERP != 0 + bh_assert(func_idx_rt + < ((WASMModuleInstance *)inst_comm_rt)->function_count); + WASMFunctionInstance *func_interp = + ((WASMModuleInstance *)inst_comm_rt)->functions + func_idx_rt; + type_rt = func_interp->is_import_func + ? func_interp->u.func_import->func_type + : func_interp->u.func->func_type; +#endif + } + else { +#if WASM_ENABLE_AOT != 0 + /* use same index to trace the function type in AOTFuncType **func_types */ + AOTModuleInstance *inst_aot = (AOTModuleInstance *)inst_comm_rt; + AOTFunctionInstance *func_aot = + (AOTFunctionInstance *)inst_aot->export_funcs.ptr + func_idx_rt; + type_rt = func_aot->is_import_func ? func_aot->u.func_import->func_type + : func_aot->u.func.func_type; +#endif + } + + if (!type_rt) { + goto failed; + } + + func->func_type = wasm_functype_new_internal(type_rt); + if (!func->func_type) { + goto failed; + } + + /* will add name information when processing "exports" */ + func->module_name = NULL; + func->name = NULL; + func->func_idx_rt = func_idx_rt; + func->inst_comm_rt = inst_comm_rt; + return func; + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + wasm_func_delete(func); + return NULL; +} + +void +wasm_func_delete(wasm_func_t *func) +{ + if (!func) { + return; + } + + if (func->func_type) { + wasm_functype_delete(func->func_type); + func->func_type = NULL; + } + + if (func->with_env) { + if (func->u.cb_env.finalizer) { + func->u.cb_env.finalizer(func->u.cb_env.env); + func->u.cb_env.finalizer = NULL; + func->u.cb_env.env = NULL; + } + } + + wasm_runtime_free(func); +} + +wasm_func_t * +wasm_func_copy(const wasm_func_t *func) +{ + wasm_func_t *cloned = NULL; + + bh_assert(func); + + cloned = malloc_internal(sizeof(wasm_func_t)); + if (!cloned) { + goto failed; + } + + cloned->kind = func->kind; + cloned->with_env = func->with_env; + if (cloned->with_env) { + cloned->u.cb_env.cb = func->u.cb_env.cb; + cloned->u.cb_env.env = func->u.cb_env.env; + cloned->u.cb_env.finalizer = func->u.cb_env.finalizer; + } + else { + cloned->u.cb = func->u.cb; + } + + cloned->func_idx_rt = func->func_idx_rt; + cloned->inst_comm_rt = func->inst_comm_rt; + cloned->func_type = wasm_functype_copy(func->func_type); + if (!cloned->func_type) { + goto failed; + } + + return cloned; + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + wasm_func_delete(cloned); + return NULL; +} + +wasm_functype_t * +wasm_func_type(const wasm_func_t *func) +{ + bh_assert(func); + return func->func_type; +} + +static uint32 +params_to_argv(const wasm_val_t *params, + const wasm_valtype_vec_t *param_defs, + size_t param_arity, + uint32 *out) +{ + size_t i = 0; + uint32 argc = 0; + const wasm_val_t *param = NULL; + + if (!param_arity) { + return 0; + } + + bh_assert(params && param_defs && out); + bh_assert(param_defs->num_elems == param_arity); + + for (i = 0; out && i < param_arity; ++i) { + param = params + i; + bh_assert((*(param_defs->data + i))->kind == param->kind); + + switch (param->kind) { + case WASM_I32: + *(int32 *)out = param->of.i32; + out += 1; + argc += 1; + break; + case WASM_I64: + *(int64 *)out = param->of.i64; + out += 2; + argc += 2; + break; + case WASM_F32: + *(float32 *)out = param->of.f32; + out += 1; + argc += 1; + break; + case WASM_F64: + *(float64 *)out = param->of.f64; + out += 2; + argc += 2; + break; + default: + LOG_DEBUG("unexpected parameter val type %d", param->kind); + goto failed; + } + } + + return argc; + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + return 0; +} + +static uint32 +argv_to_results(const uint32 *results, + const wasm_valtype_vec_t *result_defs, + size_t result_arity, + wasm_val_t *out) +{ + size_t i = 0; + uint32 argc = 0; + const uint32 *result = results; + const wasm_valtype_t *def = NULL; + + if (!result_arity) { + return 0; + } + + bh_assert(results && result_defs && out); + bh_assert(result_arity == result_defs->num_elems); + + for (i = 0; out && i < result_arity; i++) { + def = *(result_defs->data + i); + + switch (def->kind) { + case WASM_I32: + out->kind = WASM_I32; + out->of.i32 = *(int32 *)result; + result += 1; + break; + case WASM_I64: + out->kind = WASM_I64; + out->of.i64 = *(int64 *)result; + result += 2; + break; + case WASM_F32: + out->kind = WASM_F32; + out->of.f32 = *(float32 *)result; + result += 1; + break; + case WASM_F64: + out->kind = WASM_F64; + out->of.f64 = *(float64 *)result; + result += 2; + break; + default: + LOG_DEBUG("unexpected parameter val type %d", def->kind); + goto failed; + } + out++; + argc++; + } + + return argc; + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + return 0; +} + +wasm_trap_t * +wasm_func_call(const wasm_func_t *func, + const wasm_val_t params[], + wasm_val_t results[]) +{ + /* parameters count as if all are uint32 */ + /* a int64 or float64 parameter means 2 */ + uint32 argc = 0; + /* a parameter list and a return value list */ + uint32 *argv = NULL; + WASMFunctionInstanceCommon *func_comm_rt = NULL; + size_t param_count = 0; + size_t result_count = 0; + + bh_assert(func && func->func_type && func->inst_comm_rt); + + if (INTERP_MODE == current_runtime_mode()) { +#if WASM_ENABLE_INTERP != 0 + func_comm_rt = ((WASMModuleInstance *)func->inst_comm_rt)->functions + + func->func_idx_rt; +#endif + } + else { +#if WASM_ENABLE_AOT != 0 + AOTModuleInstance *inst_aot = (AOTModuleInstance *)func->inst_comm_rt; + func_comm_rt = (AOTFunctionInstance *)inst_aot->export_funcs.ptr + + func->func_idx_rt; +#endif + } + if (!func_comm_rt) { + goto failed; + } + + param_count = wasm_func_param_arity(func); + result_count = wasm_func_result_arity(func); + argv = malloc_internal( + sizeof(uint64) + * (param_count > result_count ? param_count : result_count)); + if (!argv) { + goto failed; + } + + /* copy parametes */ + argc = params_to_argv(params, wasm_functype_params(wasm_func_type(func)), + wasm_func_param_arity(func), argv); + if (wasm_func_param_arity(func) && !argc) { + goto failed; + } + + if (!wasm_runtime_create_exec_env_and_call_wasm( + func->inst_comm_rt, func_comm_rt, argc, argv)) { + LOG_DEBUG("wasm_runtime_create_exec_env_and_call_wasm failed"); + goto failed; + } + + /* copy results */ + argc = argv_to_results(argv, wasm_functype_results(wasm_func_type(func)), + wasm_func_result_arity(func), results); + if (wasm_func_result_arity(func) && !argc) { + goto failed; + } + + FREEIF(argv); + /* should return trap */ + return NULL; + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + FREEIF(argv); + return NULL; +} + +size_t +wasm_func_param_arity(const wasm_func_t *func) +{ + bh_assert(func && func->func_type && func->func_type->params); + return func->func_type->params->num_elems; +} + +size_t +wasm_func_result_arity(const wasm_func_t *func) +{ + bh_assert(func && func->func_type && func->func_type->results); + return func->func_type->results->num_elems; +} + +wasm_extern_t * +wasm_func_as_extern(wasm_func_t *func) +{ + return (wasm_extern_t *)func; +} + +wasm_global_t * +wasm_global_new(wasm_store_t *store, + const wasm_globaltype_t *global_type, + const wasm_val_t *init) +{ + wasm_global_t *global = NULL; + + check_engine_and_store(singleton_engine, store); + bh_assert(store && global_type && init); + + global = malloc_internal(sizeof(wasm_global_t)); + if (!global) { + goto failed; + } + + global->kind = WASM_EXTERN_GLOBAL; + global->type = wasm_globaltype_copy((wasm_globaltype_t *)global_type); + if (!global->type) { + goto failed; + } + + global->init = malloc_internal(sizeof(wasm_val_t)); + if (!global->init) { + goto failed; + } + + wasm_val_copy(global->init, init); + /* TODO: how to check if above is failed */ + + return global; + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + wasm_global_delete(global); + return NULL; +} + +/* almost same with wasm_global_new */ +wasm_global_t * +wasm_global_copy(const wasm_global_t *src) +{ + wasm_global_t *global = NULL; + + bh_assert(src); + + global = malloc_internal(sizeof(wasm_global_t)); + if (!global) { + goto failed; + } + + global->kind = WASM_EXTERN_GLOBAL; + global->type = wasm_globaltype_copy((wasm_globaltype_t *)src->type); + if (!global->type) { + goto failed; + } + + global->init = malloc_internal(sizeof(wasm_val_t)); + if (!global->init) { + goto failed; + } + + wasm_val_copy(global->init, src->init); + + global->global_idx_rt = src->global_idx_rt; + global->inst_comm_rt = src->inst_comm_rt; + + return global; + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + wasm_global_delete(global); + return NULL; +} + +void +wasm_global_delete(wasm_global_t *global) +{ + if (!global) { + return; + } + + if (global->init) { + wasm_val_delete(global->init); + wasm_runtime_free(global->init); + global->init = NULL; + } + + if (global->type) { + wasm_globaltype_delete(global->type); + global->type = NULL; + } + + wasm_runtime_free(global); +} + +bool +wasm_global_same(const wasm_global_t *g1, const wasm_global_t *g2) +{ + if (!g1 && !g2) { + return true; + } + + if (!g1 || !g2) { + return false; + } + + return g1->kind == g2->kind && wasm_globaltype_same(g1->type, g2->type) + && wasm_val_same(g1->init, g2->init); +} + +#if WASM_ENABLE_INTERP != 0 +static bool +interp_global_set(const WASMModuleInstance *inst_interp, + uint16 global_idx_rt, + const wasm_val_t *v) +{ + const WASMGlobalInstance *global_interp = + inst_interp->globals + global_idx_rt; + uint8 val_type_rt = global_interp->type; + uint8 *data = inst_interp->global_data + global_interp->data_offset; + bool ret = true; + + switch (val_type_rt) { + case VALUE_TYPE_I32: + bh_assert(WASM_I32 == v->kind); + *((int32 *)data) = v->of.i32; + break; + case VALUE_TYPE_F32: + bh_assert(WASM_F32 == v->kind); + *((float32 *)data) = v->of.f32; + break; + case VALUE_TYPE_I64: + bh_assert(WASM_I64 == v->kind); + *((int64 *)data) = v->of.i64; + break; + case VALUE_TYPE_F64: + bh_assert(WASM_F64 == v->kind); + *((float64 *)data) = v->of.f64; + break; + default: + LOG_DEBUG("unexpected value type %d", val_type_rt); + ret = false; + break; + } + + return ret; +} + +static bool +interp_global_get(const WASMModuleInstance *inst_interp, + uint16 global_idx_rt, + wasm_val_t *out) +{ + WASMGlobalInstance *global_interp = inst_interp->globals + global_idx_rt; + uint8 val_type_rt = global_interp->type; + uint8 *data = inst_interp->global_data + global_interp->data_offset; + bool ret = true; + + switch (val_type_rt) { + case VALUE_TYPE_I32: + out->kind = WASM_I32; + out->of.i32 = *((int32 *)data); + break; + case VALUE_TYPE_F32: + out->kind = WASM_F32; + out->of.f32 = *((float32 *)data); + break; + case VALUE_TYPE_I64: + out->kind = WASM_I64; + out->of.i64 = *((int64 *)data); + break; + case VALUE_TYPE_F64: + out->kind = WASM_F64; + out->of.f64 = *((float64 *)data); + break; + default: + LOG_DEBUG("unexpected value type %d", val_type_rt); + ret = false; + } + return ret; +} +#endif + +#if WASM_ENABLE_AOT != 0 +static bool +aot_global_set(const AOTModuleInstance *inst_aot, + uint16 global_idx_rt, + const wasm_val_t *v) +{ + AOTModule *module_aot = inst_aot->aot_module.ptr; + uint8 val_type_rt = 0; + uint32 data_offset = 0; + void *data = NULL; + bool ret = true; + + if (global_idx_rt < module_aot->import_global_count) { + data_offset = module_aot->import_globals[global_idx_rt].data_offset; + val_type_rt = module_aot->import_globals[global_idx_rt].type; + } + else { + data_offset = + module_aot->globals[global_idx_rt - module_aot->import_global_count] + .data_offset; + val_type_rt = + module_aot->globals[global_idx_rt - module_aot->import_global_count] + .type; + } + + data = inst_aot->global_data.ptr + data_offset; + switch (val_type_rt) { + case VALUE_TYPE_I32: + bh_assert(WASM_I32 == v->kind); + *((int32 *)data) = v->of.i32; + break; + case VALUE_TYPE_F32: + bh_assert(WASM_F32 == v->kind); + *((float32 *)data) = v->of.f32; + break; + case VALUE_TYPE_I64: + bh_assert(WASM_I64 == v->kind); + *((int64 *)data) = v->of.i64; + break; + case VALUE_TYPE_F64: + bh_assert(WASM_F64 == v->kind); + *((float64 *)data) = v->of.f64; + break; + default: + LOG_DEBUG("unexpected value type %d", val_type_rt); + ret = false; + } + return ret; +} + +static bool +aot_global_get(const AOTModuleInstance *inst_aot, + uint16 global_idx_rt, + wasm_val_t *out) +{ + AOTModule *module_aot = inst_aot->aot_module.ptr; + uint8 val_type_rt = 0; + uint32 data_offset = 0; + void *data = NULL; + bool ret = true; + + if (global_idx_rt < module_aot->import_global_count) { + data_offset = module_aot->import_globals[global_idx_rt].data_offset; + val_type_rt = module_aot->import_globals[global_idx_rt].type; + } + else { + data_offset = + module_aot->globals[global_idx_rt - module_aot->import_global_count] + .data_offset; + val_type_rt = + module_aot->globals[global_idx_rt - module_aot->import_global_count] + .type; + } + + data = inst_aot->global_data.ptr + data_offset; + switch (val_type_rt) { + case VALUE_TYPE_I32: + out->kind = WASM_I32; + out->of.i32 = *((int32 *)data); + break; + case VALUE_TYPE_F32: + out->kind = WASM_F32; + out->of.f32 = *((float32 *)data); + break; + case VALUE_TYPE_I64: + out->kind = WASM_I64; + out->of.i64 = *((int64 *)data); + break; + case VALUE_TYPE_F64: + out->kind = WASM_F64; + out->of.f64 = *((float64 *)data); + break; + default: + LOG_DEBUG("unexpected value type %d", val_type_rt); + ret = false; + } + return ret; +} +#endif + +void +wasm_global_set(wasm_global_t *global, const wasm_val_t *v) +{ + bh_assert(global && v); + + if (INTERP_MODE == current_runtime_mode()) { +#if WASM_ENABLE_INTERP != 0 + (void)interp_global_set((WASMModuleInstance *)global->inst_comm_rt, + global->global_idx_rt, v); +#endif + } + else { +#if WASM_ENABLE_AOT != 0 + (void)aot_global_set((AOTModuleInstance *)global->inst_comm_rt, + global->global_idx_rt, v); +#endif + } +} + +void +wasm_global_get(const wasm_global_t *global, wasm_val_t *out) +{ + bh_assert(global && out); + + memset(out, 0, sizeof(wasm_val_t)); + + if (INTERP_MODE == current_runtime_mode()) { +#if WASM_ENABLE_INTERP != 0 + (void)interp_global_get((WASMModuleInstance *)global->inst_comm_rt, + global->global_idx_rt, out); +#endif + } + else { +#if WASM_ENABLE_AOT != 0 + (void)aot_global_get((AOTModuleInstance *)global->inst_comm_rt, + global->global_idx_rt, out); +#endif + } + + bh_assert(global->init->kind == out->kind); +} + +static wasm_global_t * +wasm_global_new_internal(wasm_store_t *store, + uint16 global_idx_rt, + WASMModuleInstanceCommon *inst_comm_rt) +{ + wasm_global_t *global = NULL; + uint8 val_type_rt = 0; + bool is_mutable = 0; + + check_engine_and_store(singleton_engine, store); + bh_assert(inst_comm_rt); + + global = malloc_internal(sizeof(wasm_global_t)); + if (!global) { + goto failed; + } + + /* + * global->module_name = NULL; + * global->name = NULL; + */ + global->kind = WASM_EXTERN_GLOBAL; + + if (INTERP_MODE == current_runtime_mode()) { +#if WASM_ENABLE_INTERP != 0 + WASMGlobalInstance *global_interp = + ((WASMModuleInstance *)inst_comm_rt)->globals + global_idx_rt; + val_type_rt = global_interp->type; + is_mutable = global_interp->is_mutable; +#endif + } + else { +#if WASM_ENABLE_AOT != 0 + AOTModuleInstance *inst_aot = (AOTModuleInstance *)inst_comm_rt; + AOTModule *module_aot = inst_aot->aot_module.ptr; + if (global_idx_rt < module_aot->import_global_count) { + AOTImportGlobal *global_import_aot = + module_aot->import_globals + global_idx_rt; + val_type_rt = global_import_aot->type; + is_mutable = global_import_aot->is_mutable; + } + else { + AOTGlobal *global_aot = + module_aot->globals + + (global_idx_rt - module_aot->import_global_count); + val_type_rt = global_aot->type; + is_mutable = global_aot->is_mutable; + } +#endif + } + + global->type = wasm_globaltype_new_internal(val_type_rt, is_mutable); + if (!global->type) { + goto failed; + } + + global->init = malloc_internal(sizeof(wasm_val_t)); + if (!global->init) { + goto failed; + } + + if (INTERP_MODE == current_runtime_mode()) { +#if WASM_ENABLE_INTERP != 0 + interp_global_get((WASMModuleInstance *)inst_comm_rt, global_idx_rt, + global->init); +#endif + } + else { +#if WASM_ENABLE_AOT != 0 + aot_global_get((AOTModuleInstance *)inst_comm_rt, global_idx_rt, + global->init); +#endif + } + + global->inst_comm_rt = inst_comm_rt; + global->global_idx_rt = global_idx_rt; + + return global; + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + wasm_global_delete(global); + return NULL; +} + +wasm_globaltype_t * +wasm_global_type(const wasm_global_t *global) +{ + bh_assert(global); + return global->type; +} + +wasm_extern_t * +wasm_global_as_extern(wasm_global_t *global) +{ + return (wasm_extern_t *)global; +} + +void +wasm_table_delete(wasm_table_t *table) +{} + +void +wasm_memory_delete(wasm_memory_t *memory) +{} + +#if WASM_ENABLE_INTERP != 0 +static bool +interp_link_func(const wasm_instance_t *inst, + const WASMModule *module_interp, + uint16 func_idx_rt, + wasm_func_t *import) +{ + WASMImport *imported_func_interp = NULL; + wasm_func_t *cloned = NULL; + + bh_assert(inst && module_interp && import); + bh_assert(func_idx_rt < module_interp->import_function_count); + bh_assert(WASM_EXTERN_FUNC == import->kind); + + imported_func_interp = module_interp->import_functions + func_idx_rt; + bh_assert(imported_func_interp); + + cloned = wasm_func_copy(import); + if (!cloned || !bh_vector_append((Vector *)inst->imports, &cloned)) { + return false; + } + + /* add native_func_trampoline as a NativeSymbol */ + imported_func_interp->u.function.call_conv_raw = true; + imported_func_interp->u.function.attachment = cloned; + imported_func_interp->u.function.func_ptr_linked = native_func_trampoline; + import->func_idx_rt = func_idx_rt; + + return true; +} + +static bool +interp_link_global(const WASMModule *module_interp, + uint16 global_idx_rt, + wasm_global_t *import) +{ + WASMImport *imported_global_interp = NULL; + + bh_assert(module_interp && import); + bh_assert(global_idx_rt < module_interp->import_global_count); + bh_assert(WASM_EXTERN_GLOBAL == import->kind); + + imported_global_interp = module_interp->import_globals + global_idx_rt; + bh_assert(imported_global_interp); + + /* set init value */ + switch (wasm_valtype_kind(import->type->val_type)) { + case WASM_I32: + bh_assert(VALUE_TYPE_I32 == imported_global_interp->u.global.type); + imported_global_interp->u.global.global_data_linked.i32 = + import->init->of.i32; + break; + case WASM_I64: + bh_assert(VALUE_TYPE_I64 == imported_global_interp->u.global.type); + imported_global_interp->u.global.global_data_linked.i64 = + import->init->of.i64; + break; + case WASM_F32: + bh_assert(VALUE_TYPE_F32 == imported_global_interp->u.global.type); + imported_global_interp->u.global.global_data_linked.f32 = + import->init->of.f32; + break; + case WASM_F64: + bh_assert(VALUE_TYPE_F64 == imported_global_interp->u.global.type); + imported_global_interp->u.global.global_data_linked.f64 = + import->init->of.f64; + break; + default: + return false; + } + + import->global_idx_rt = global_idx_rt; + return true; +} + +static bool +interp_link_memory(const WASMModule *module_interp, + uint16 memory_inst_index, + wasm_memory_t *import) +{ + return false; +} + +static bool +interp_link_table(const WASMModule *module_interp, + uint16 table_inst_index, + wasm_table_t *import) +{ + return false; +} + +static int32 +interp_link(const wasm_instance_t *inst, + const WASMModule *module_interp, + wasm_extern_t *imports[]) +{ + uint32 i = 0; + uint32 import_func_i = 0; + uint32 import_global_i = 0; + uint32 import_table_i = 0; + uint32 import_memory_i = 0; + wasm_func_t *func = NULL; + wasm_global_t *global = NULL; + + bh_assert(inst && module_interp && imports); + + for (i = 0; i < module_interp->import_count; ++i) { + wasm_extern_t *import = imports[i]; + WASMImport *import_rt = module_interp->imports + i; + + switch (import_rt->kind) { + case IMPORT_KIND_FUNC: + func = wasm_extern_as_func(import); + if (!interp_link_func(inst, module_interp, import_func_i++, + func)) { + goto failed; + } + + break; + case IMPORT_KIND_GLOBAL: + global = wasm_extern_as_global(import); + if (!interp_link_global(module_interp, import_global_i++, + global)) { + goto failed; + } + + break; + case IMPORT_KIND_MEMORY: + if (!interp_link_memory(module_interp, import_memory_i++, + wasm_extern_as_memory(import))) { + goto failed; + }; + break; + case IMPORT_KIND_TABLE: + if (!interp_link_table(module_interp, import_table_i++, + wasm_extern_as_table(import))) { + goto failed; + } + break; + default: + NOT_REACHED(); + break; + } + } + + return module_interp->import_count; + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + return -1; +} + +static bool +interp_process_export(wasm_store_t *store, + const WASMModuleInstance *inst_interp, + wasm_extern_vec_t *externals) +{ + WASMExport *exports = NULL; + WASMExport *export = NULL; + wasm_func_t *func = NULL; + wasm_global_t *global = NULL; + wasm_extern_t *external = NULL; + uint32 export_cnt = 0; + uint32 i = 0; + + bh_assert(store && inst_interp && externals); + + exports = inst_interp->module->exports; + export_cnt = inst_interp->module->export_count; + + for (i = 0; i < export_cnt; ++i) { + export = exports + i; + + switch (export->kind) { + case EXPORT_KIND_FUNC: + func = wasm_func_new_internal( + store, export->index, + (WASMModuleInstanceCommon *)inst_interp); + if (!func) { + goto failed; + } + + external = wasm_func_as_extern(func); + break; + case EXPORT_KIND_GLOBAL: + global = wasm_global_new_internal( + store, export->index, + (WASMModuleInstanceCommon *)inst_interp); + if (!global) { + goto failed; + } + + external = wasm_global_as_extern(global); + break; + // TODO: + case EXPORT_KIND_MEMORY: + case EXPORT_KIND_TABLE: + break; + default: + goto failed; + } + + if (!bh_vector_append((Vector *)externals, &external)) { + goto failed; + } + } + + return true; + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + return false; +} +#endif /* WASM_ENABLE_INTERP */ + +#if WASM_ENABLE_AOT != 0 +static bool +aot_link_func(const wasm_instance_t *inst, + const AOTModule *module_aot, + uint32 import_func_idx_rt, + wasm_func_t *import) +{ + AOTImportFunc *import_aot_func = NULL; + wasm_func_t *cloned = NULL; + + bh_assert(inst && module_aot && import); + + import_aot_func = module_aot->import_funcs + import_func_idx_rt; + bh_assert(import_aot_func); + + cloned = wasm_func_copy(import); + if (!cloned || !bh_vector_append((Vector *)inst->imports, &cloned)) { + return false; + } + + import_aot_func->call_conv_raw = true; + import_aot_func->attachment = wasm_func_copy(import); + import_aot_func->func_ptr_linked = native_func_trampoline; + import->func_idx_rt = import_func_idx_rt; + + return true; +} + +static bool +aot_link_global(const AOTModule *module_aot, + uint16 global_idx_rt, + wasm_global_t *import) +{ + AOTImportGlobal *import_aot_global = NULL; + const wasm_valtype_t *val_type = NULL; + + bh_assert(module_aot && import); + + import_aot_global = module_aot->import_globals + global_idx_rt; + bh_assert(import_aot_global); + + val_type = wasm_globaltype_content(wasm_global_type(import)); + bh_assert(val_type); + + switch (wasm_valtype_kind(val_type)) { + case WASM_I32: + bh_assert(VALUE_TYPE_I32 == import_aot_global->type); + import_aot_global->global_data_linked.i32 = import->init->of.i32; + break; + case WASM_I64: + bh_assert(VALUE_TYPE_I64 == import_aot_global->type); + import_aot_global->global_data_linked.i64 = import->init->of.i64; + break; + case WASM_F32: + bh_assert(VALUE_TYPE_F32 == import_aot_global->type); + import_aot_global->global_data_linked.f32 = import->init->of.f32; + break; + case WASM_F64: + bh_assert(VALUE_TYPE_F64 == import_aot_global->type); + import_aot_global->global_data_linked.f64 = import->init->of.f64; + break; + default: + goto failed; + } + + import->global_idx_rt = global_idx_rt; + return true; + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + return false; +} + +static int32 +aot_link(const wasm_instance_t *inst, + const AOTModule *module_aot, + wasm_extern_t *imports[]) +{ + uint32 i = 0; + uint32 import_func_i = 0; + uint32 import_global_i = 0; + wasm_extern_t *import = NULL; + wasm_func_t *func = NULL; + wasm_global_t *global = NULL; + + bh_assert(inst && module_aot && imports); + + while (import_func_i < module_aot->import_func_count + || import_global_i < module_aot->import_global_count) { + import = imports[i++]; + + bh_assert(import); + + switch (wasm_extern_kind(import)) { + case WASM_EXTERN_FUNC: + bh_assert(import_func_i < module_aot->import_func_count); + func = wasm_extern_as_func((wasm_extern_t *)import); + if (!aot_link_func(inst, module_aot, import_func_i++, func)) { + goto failed; + } + + break; + case WASM_EXTERN_GLOBAL: + bh_assert(import_global_i < module_aot->import_global_count); + global = wasm_extern_as_global((wasm_extern_t *)import); + if (!aot_link_global(module_aot, import_global_i++, global)) { + goto failed; + } + + break; + case WASM_EXTERN_MEMORY: + break; + case WASM_EXTERN_TABLE: + break; + default: + goto failed; + } + } + + return i; + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + return -1; +} + +static bool +aot_process_export(wasm_store_t *store, + const AOTModuleInstance *inst_aot, + wasm_extern_vec_t *externals) +{ + uint32 i = 0; + uint32 export_func_i = 0; + wasm_extern_t *external = NULL; + AOTModule *module_aot = NULL; + + bh_assert(store && inst_aot && externals); + + module_aot = (AOTModule *)inst_aot->aot_module.ptr; + bh_assert(module_aot); + + for (i = 0; i < module_aot->export_count; ++i) { + AOTExport *export = module_aot->exports + i; + wasm_func_t *func = NULL; + wasm_global_t *global = NULL; + + switch (export->kind) { + case EXPORT_KIND_FUNC: + func = + wasm_func_new_internal(store, export_func_i++, + (WASMModuleInstanceCommon *)inst_aot); + if (!func) { + goto failed; + } + + external = wasm_func_as_extern(func); + break; + case EXPORT_KIND_GLOBAL: + global = wasm_global_new_internal( + store, export->index, (WASMModuleInstanceCommon *)inst_aot); + if (!global) { + goto failed; + } + + external = wasm_global_as_extern(global); + break; + case EXPORT_KIND_MEMORY: + case EXPORT_KIND_TABLE: + break; + default: + NOT_REACHED(); + goto failed; + } + + if (!bh_vector_append((Vector *)externals, &external)) { + goto failed; + } + } + + return true; + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + return false; +} +#endif /* WASM_ENABLE_AOT */ + +wasm_instance_t * +wasm_instance_new(wasm_store_t *store, + const wasm_module_t *module, + const wasm_extern_t *const imports[], + wasm_trap_t **traps) +{ + char error[128] = { 0 }; + const uint32 stack_size = 16 * 1024; + const uint32 heap_size = 16 * 1024; + int32 import_count = 0; + wasm_instance_t *instance = NULL; + uint32 i = 0; + (void)traps; + + check_engine_and_store(singleton_engine, store); + + instance = malloc_internal(sizeof(wasm_instance_t)); + if (!instance) { + goto failed; + } + + /* link module and imports */ + if (INTERP_MODE == current_runtime_mode()) { +#if WASM_ENABLE_INTERP != 0 + import_count = ((WASMModule *)*module)->import_count; + INIT_VEC(instance->imports, wasm_extern_vec, import_count); + if (!instance->imports) { + goto failed; + } + + import_count = interp_link(instance, (WASMModule *)*module, + (wasm_extern_t **)imports); +#endif + } + else { +#if WASM_ENABLE_AOT != 0 + import_count = ((AOTModule *)*module)->import_func_count + + ((AOTModule *)*module)->import_global_count + + ((AOTModule *)*module)->import_memory_count + + ((AOTModule *)*module)->import_table_count; + INIT_VEC(instance->imports, wasm_extern_vec, import_count); + if (!instance->imports) { + goto failed; + } + + import_count = + aot_link(instance, (AOTModule *)*module, (wasm_extern_t **)imports); +#endif + } + if (import_count < 0) { + goto failed; + } + + instance->inst_comm_rt = wasm_runtime_instantiate( + *module, stack_size, heap_size, error, sizeof(error)); + if (!instance->inst_comm_rt) { + LOG_ERROR(error); + goto failed; + } + + /* fill in inst */ + for (i = 0; i < (uint32)import_count; ++i) { + wasm_extern_t *import = (wasm_extern_t *)imports[i]; + switch (import->kind) { + case WASM_EXTERN_FUNC: + wasm_extern_as_func(import)->inst_comm_rt = + instance->inst_comm_rt; + break; + case WASM_EXTERN_GLOBAL: + wasm_extern_as_global(import)->inst_comm_rt = + instance->inst_comm_rt; + break; + case WASM_EXTERN_MEMORY: + wasm_extern_as_memory(import)->inst_comm_rt = + instance->inst_comm_rt; + break; + case WASM_EXTERN_TABLE: + wasm_extern_as_table(import)->inst_comm_rt = + instance->inst_comm_rt; + break; + default: + goto failed; + } + } + + /* build the exports list */ + if (INTERP_MODE == current_runtime_mode()) { +#if WASM_ENABLE_INTERP != 0 + uint32 export_cnt = + ((WASMModuleInstance *)instance->inst_comm_rt)->module->export_count; + + INIT_VEC(instance->exports, wasm_extern_vec, export_cnt); + + if (!interp_process_export( + store, (WASMModuleInstance *)instance->inst_comm_rt, + instance->exports)) { + goto failed; + } +#endif + } + else { +#if WASM_ENABLE_AOT != 0 + uint32 export_cnt = + ((AOTModuleInstance *)instance->inst_comm_rt)->export_func_count; + + INIT_VEC(instance->exports, wasm_extern_vec, export_cnt); + + if (!aot_process_export(store, + (AOTModuleInstance *)instance->inst_comm_rt, + instance->exports)) { + goto failed; + } +#endif + } + + /* add it to a watching list in store */ + if (!bh_vector_append((Vector *)store->instances, &instance)) { + goto failed; + } + + return instance; + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + wasm_instance_delete_internal(instance); + return NULL; +} + +void +wasm_instance_delete_internal(wasm_instance_t *instance) +{ + if (!instance) { + return; + } + + DEINIT_VEC(instance->imports, wasm_extern_vec_delete); + DEINIT_VEC(instance->exports, wasm_extern_vec_delete); + + if (instance->inst_comm_rt) { + wasm_runtime_deinstantiate(instance->inst_comm_rt); + instance->inst_comm_rt = NULL; + } + wasm_runtime_free(instance); +} + +/* will release instance when releasing the store */ +void +wasm_instance_delete(wasm_instance_t *module) +{ + /* pass */ +} + +void +wasm_instance_exports(const wasm_instance_t *instance, wasm_extern_vec_t *out) +{ + bh_assert(instance && out); + wasm_extern_vec_copy(out, instance->exports); +} + +void +wasm_instance_vec_new_uninitialized(wasm_instance_vec_t *out, size_t size) +{ + generic_vec_init_data((Vector *)out, size, sizeof(wasm_instance_t)); +} + +void +wasm_instance_vec_delete(wasm_instance_vec_t *instance_vec) +{ + size_t i = 0; + if (!instance_vec || !instance_vec->data) { + return; + } + + FREE_VEC_ELEMS(instance_vec, wasm_instance_delete_internal); + bh_vector_destroy((Vector *)instance_vec); +} + +wasm_extern_t * +wasm_extern_copy(const wasm_extern_t *src) +{ + wasm_extern_t *dst = NULL; + wasm_func_t *func = NULL; + wasm_global_t *global = NULL; + bh_assert(src); + + switch (wasm_extern_kind(src)) { + case WASM_EXTERN_FUNC: + func = wasm_func_copy(wasm_extern_as_func_const(src)); + dst = wasm_func_as_extern(func); + break; + case WASM_EXTERN_GLOBAL: + global = wasm_global_copy(wasm_extern_as_global_const(src)); + dst = wasm_global_as_extern(global); + break; + case WASM_EXTERN_MEMORY: + case WASM_EXTERN_TABLE: + default: + break; + } + + if (!dst) { + goto failed; + } + + return dst; + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + wasm_extern_delete(dst); + return NULL; +} + +void +wasm_extern_delete(wasm_extern_t *external) +{ + if (!external) { + return; + } + + switch (wasm_extern_kind(external)) { + case WASM_EXTERN_FUNC: + wasm_func_delete(wasm_extern_as_func(external)); + break; + case WASM_EXTERN_GLOBAL: + wasm_global_delete(wasm_extern_as_global(external)); + break; + case WASM_EXTERN_MEMORY: + case WASM_EXTERN_TABLE: + default: + break; + } +} + +wasm_externkind_t +wasm_extern_kind(const wasm_extern_t *extrenal) +{ + return extrenal->kind; +} + +wasm_func_t * +wasm_extern_as_func(wasm_extern_t *external) +{ + return (wasm_func_t *)external; +} + +const wasm_func_t * +wasm_extern_as_func_const(const wasm_extern_t *external) +{ + return (const wasm_func_t *)external; +} + +wasm_global_t * +wasm_extern_as_global(wasm_extern_t *external) +{ + return (wasm_global_t *)external; +} + +const wasm_global_t * +wasm_extern_as_global_const(const wasm_extern_t *external) +{ + return (const wasm_global_t *)external; +} + +wasm_memory_t * +wasm_extern_as_memory(wasm_extern_t *external) +{ + return (wasm_memory_t *)external; +} + +const wasm_memory_t * +wasm_extern_as_memory_const(const wasm_extern_t *external) +{ + return (const wasm_memory_t *)external; +} + +wasm_table_t * +wasm_extern_as_table(wasm_extern_t *external) +{ + return (wasm_table_t *)external; +} + +const wasm_table_t * +wasm_extern_as_table_const(const wasm_extern_t *external) +{ + return (const wasm_table_t *)external; +} + +void +wasm_extern_vec_copy(wasm_extern_vec_t *out, const wasm_extern_vec_t *src) +{ + size_t i = 0; + bh_assert(out && src); + + generic_vec_init_data((Vector *)out, src->size, src->size_of_elem); + if (!out->data) { + goto failed; + } + + for (i = 0; i < src->num_elems; ++i) { + wasm_extern_t *orig = *(src->data + i); + wasm_extern_t *cloned = wasm_extern_copy(orig); + if (!cloned) { + goto failed; + } + + if (!bh_vector_append((Vector *)out, &cloned)) { + goto failed; + } + } + + return; + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + wasm_extern_vec_delete(out); + return; +} + +void +wasm_extern_vec_new_uninitialized(wasm_extern_vec_t *out, size_t size) +{ + generic_vec_init_data((Vector *)out, size, sizeof(wasm_extern_t *)); +} + +void +wasm_extern_vec_delete(wasm_extern_vec_t *extern_vec) +{ + size_t i = 0; + if (!extern_vec || !extern_vec->data) { + return; + } + + FREE_VEC_ELEMS(extern_vec, wasm_extern_delete); + bh_vector_destroy((Vector *)extern_vec); +} diff --git a/core/iwasm/common/wasm_c_api_internal.h b/core/iwasm/common/wasm_c_api_internal.h new file mode 100644 index 000000000..b321ff873 --- /dev/null +++ b/core/iwasm/common/wasm_c_api_internal.h @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _WASM_C_API_INTERNAL_H +#define _WASM_C_API_INTERNAL_H + +#include "wasm_c_api.h" +#include "wasm_runtime_common.h" + +#ifndef own +#define own +#endif + +/* Vectors */ +/* we will malloc resource for the vector's data field */ +/* we will release resource of data */ +/* caller needs to take care resource for the vector itself */ +#define DEFAULT_VECTOR_INIT_LENGTH (64) + +WASM_DECLARE_VEC(store, *) +WASM_DECLARE_VEC(module, *) +WASM_DECLARE_VEC(instance, *) + +/* Runtime Environment */ +typedef enum runtime_mode_e { + INTERP_MODE = 0, + JIT_MODE, + AOT_MODE +} runtime_mode_e; + +struct wasm_engine_t { + // support one store for now + wasm_store_vec_t *stores; + // Interpreter by deault + runtime_mode_e mode; +}; + +struct wasm_store_t { + wasm_module_vec_t *modules; + wasm_instance_vec_t *instances; +}; + +/* Type Representations */ +struct wasm_valtype_t { + wasm_valkind_t kind; +}; + +struct wasm_functype_t { + uint32 extern_kind; + // gona to new and delete own + wasm_valtype_vec_t *params; + wasm_valtype_vec_t *results; +}; + +struct wasm_globaltype_t { + uint32 extern_kind; + // gona to new and delete own + wasm_valtype_t *val_type; + wasm_mutability_t mutability; +}; + +struct wasm_tabletype_t { + uint32 extern_kind; + // always be WASM_FUNCREF + wasm_valtype_t *type; + wasm_limits_t *limits; +}; + +struct wasm_memorytype_t { + uint32 extern_kind; + wasm_limits_t *limits; +}; + +struct wasm_externtype_t { + uint32 extern_kind; + uint8 data[1]; +}; + +struct wasm_import_type_t { + uint32 extern_kind; + wasm_name_t *module_name; + wasm_name_t *name; +}; + +struct wasm_export_type_t { + uint32 extern_kind; + wasm_name_t *module_name; + wasm_name_t *name; +}; + +/* Runtime Objects */ +struct wasm_ref_t {}; + +struct wasm_trap_t { + wasm_byte_vec_t *message; +}; + +struct wasm_func_t { + wasm_name_t *module_name; + wasm_name_t *name; + uint16 kind; + + wasm_functype_t *func_type; + + bool with_env; + union { + wasm_func_callback_t cb; + struct callback_ext { + void *env; + wasm_func_callback_with_env_t cb; + void (*finalizer)(void *); + } cb_env; + } u; + /* + * an index in both functions runtime instance lists + * of interpreter mode and aot mode + */ + uint16 func_idx_rt; + WASMModuleInstanceCommon *inst_comm_rt; +}; + +struct wasm_global_t { + wasm_name_t *module_name; + wasm_name_t *name; + uint16 kind; + + wasm_globaltype_t *type; + wasm_val_t *init; + /* + * an index in both global runtime instance lists + * of interpreter mode and aot mode + */ + uint16 global_idx_rt; + WASMModuleInstanceCommon *inst_comm_rt; +}; + +struct wasm_memory_t { + wasm_name_t *module_name; + wasm_name_t *name; + uint16 kind; + + wasm_memorytype_t *type; + /* + * an index in both memory runtime instance lists + * of interpreter mode and aot mode + */ + uint16 memory_idx_rt; + WASMModuleInstanceCommon *inst_comm_rt; +}; + +struct wasm_table_t { + wasm_name_t *module_name; + wasm_name_t *name; + uint16 kind; + + wasm_tabletype_t *type; + /* + * an index in both table runtime instance lists + * of interpreter mode and aot mode + */ + uint16 table_idx_rt; + WASMModuleInstanceCommon *inst_comm_rt; +}; + +struct wasm_extern_t { + wasm_name_t *module_name; + wasm_name_t *name; + uint16 kind; + uint8 data[1]; +}; + +struct wasm_instance_t { + wasm_extern_vec_t *imports; + wasm_extern_vec_t *exports; + WASMModuleInstanceCommon *inst_comm_rt; +}; + +#endif /* _WASM_C_API_INTERNAL_H */ diff --git a/core/iwasm/common/wasm_runtime_common.h b/core/iwasm/common/wasm_runtime_common.h index 57bb591fc..95f4fb7f2 100644 --- a/core/iwasm/common/wasm_runtime_common.h +++ b/core/iwasm/common/wasm_runtime_common.h @@ -67,14 +67,11 @@ typedef struct WASMRegisteredModule { } WASMRegisteredModule; #endif -#if WASM_ENABLE_SHARED_MEMORY != 0 typedef struct WASMMemoryInstanceCommon { uint32 module_type; uint8 memory_inst_data[1]; } WASMMemoryInstanceCommon; -#endif - typedef package_type_t PackageType; typedef wasm_section_t WASMSection, AOTSection; diff --git a/core/iwasm/common/wasm_shared_memory.c b/core/iwasm/common/wasm_shared_memory.c index be99e6fe3..8d2f88db6 100644 --- a/core/iwasm/common/wasm_shared_memory.c +++ b/core/iwasm/common/wasm_shared_memory.c @@ -3,8 +3,6 @@ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception */ -#if WASM_ENABLE_SHARED_MEMORY != 0 - #include "bh_log.h" #include "wasm_shared_memory.h" @@ -120,5 +118,3 @@ shared_memory_set_memory_inst(WASMModuleCommon *module, (void)ret; return node; } - -#endif /* end of WASM_ENABLE_SHARED_MEMORY */ diff --git a/core/iwasm/include/wasm_c_api.h b/core/iwasm/include/wasm_c_api.h new file mode 100644 index 000000000..5b5bd79e4 --- /dev/null +++ b/core/iwasm/include/wasm_c_api.h @@ -0,0 +1,679 @@ +// WebAssembly C API + +#ifndef WASM_H +#define WASM_H + +#include +#include +#include +#include +#include + +#ifndef WASM_API_EXTERN +#ifdef _WIN32 +#define WASM_API_EXTERN __declspec(dllimport) +#else +#define WASM_API_EXTERN +#endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Auxiliaries + +// Machine types +#if (__STDC_VERSION__ > 199901L) +inline void assertions() { + static_assert(sizeof(float) == sizeof(uint32_t), "incompatible float type"); + static_assert(sizeof(double) == sizeof(uint64_t), "incompatible double type"); + static_assert(sizeof(intptr_t) == sizeof(uint32_t) || + sizeof(intptr_t) == sizeof(uint64_t), + "incompatible pointer type"); +} +#endif /* __STDC_VERSION__ > 199901L */ + +typedef char byte_t; +typedef float float32_t; +typedef double float64_t; + + +// Ownership + +#define own + +// The qualifier `own` is used to indicate ownership of data in this API. +// It is intended to be interpreted similar to a `const` qualifier: +// +// - `own wasm_xxx_t*` owns the pointed-to data +// - `own wasm_xxx_t` distributes to all fields of a struct or union `xxx` +// - `own wasm_xxx_vec_t` owns the vector as well as its elements(!) +// - an `own` function parameter passes ownership from caller to callee +// - an `own` function result passes ownership from callee to caller +// - an exception are `own` pointer parameters named `out`, which are copy-back +// output parameters passing back ownership from callee to caller +// +// Own data is created by `wasm_xxx_new` functions and some others. +// It must be released with the corresponding `wasm_xxx_delete` function. +// +// Deleting a reference does not necessarily delete the underlying object, +// it merely indicates that this owner no longer uses it. +// +// For vectors, `const wasm_xxx_vec_t` is used informally to indicate that +// neither the vector nor its elements should be modified. +// TODO: introduce proper `wasm_xxx_const_vec_t`? + + +#define WASM_DECLARE_OWN(name) \ + typedef struct wasm_##name##_t wasm_##name##_t; \ + \ + WASM_API_EXTERN void wasm_##name##_delete(own wasm_##name##_t*); + + +// Vectors +// size: capacity +// num_elems: current number of elements +// size_of_elem: size of one element +#define WASM_DECLARE_VEC(name, ptr_or_none) \ + typedef struct wasm_##name##_vec_t { \ + size_t size; \ + wasm_##name##_t ptr_or_none* data; \ + size_t num_elems; \ + size_t size_of_elem; \ + } wasm_##name##_vec_t; \ + \ + WASM_API_EXTERN void wasm_##name##_vec_new_empty(own wasm_##name##_vec_t* out); \ + WASM_API_EXTERN void wasm_##name##_vec_new_uninitialized( \ + own wasm_##name##_vec_t* out, size_t); \ + WASM_API_EXTERN void wasm_##name##_vec_new( \ + own wasm_##name##_vec_t* out, \ + size_t, own wasm_##name##_t ptr_or_none const[]); \ + WASM_API_EXTERN void wasm_##name##_vec_copy( \ + own wasm_##name##_vec_t* out, const wasm_##name##_vec_t*); \ + WASM_API_EXTERN void wasm_##name##_vec_delete(own wasm_##name##_vec_t*); + + +// Byte vectors + +typedef byte_t wasm_byte_t; +WASM_DECLARE_VEC(byte, ) + +typedef wasm_byte_vec_t wasm_name_t; + +#define wasm_name wasm_byte_vec +#define wasm_name_new wasm_byte_vec_new +#define wasm_name_new_empty wasm_byte_vec_new_empty +#define wasm_name_new_new_uninitialized wasm_byte_vec_new_uninitialized +#define wasm_name_copy wasm_byte_vec_copy +#define wasm_name_delete wasm_byte_vec_delete + +static inline void wasm_name_new_from_string( + own wasm_name_t* out, const char* s +) { + wasm_name_new(out, strlen(s) + 1, s); +} + + +/////////////////////////////////////////////////////////////////////////////// +// Runtime Environment + +// Engine + +WASM_DECLARE_OWN(engine) + +WASM_API_EXTERN own wasm_engine_t* wasm_engine_new(); + + +// Store + +WASM_DECLARE_OWN(store) + +WASM_API_EXTERN own wasm_store_t* wasm_store_new(wasm_engine_t*); + + +/////////////////////////////////////////////////////////////////////////////// +// Type Representations + +// Type attributes + +typedef uint8_t wasm_mutability_t; +enum wasm_mutability_enum { + WASM_CONST, + WASM_VAR, +}; + +typedef struct wasm_limits_t { + uint32_t min; + uint32_t max; +} wasm_limits_t; + +static const uint32_t wasm_limits_max_default = 0xffffffff; + + +// Generic + +#define WASM_DECLARE_TYPE(name) \ + WASM_DECLARE_OWN(name) \ + WASM_DECLARE_VEC(name, *) \ + \ + WASM_API_EXTERN own wasm_##name##_t* wasm_##name##_copy(wasm_##name##_t*); + + +// Value Types + +WASM_DECLARE_TYPE(valtype) + +typedef uint8_t wasm_valkind_t; +enum wasm_valkind_enum { + WASM_I32, + WASM_I64, + WASM_F32, + WASM_F64, + WASM_ANYREF = 128, + WASM_FUNCREF, +}; + +WASM_API_EXTERN own wasm_valtype_t* wasm_valtype_new(wasm_valkind_t); + +WASM_API_EXTERN wasm_valkind_t wasm_valtype_kind(const wasm_valtype_t*); + +static inline bool wasm_valkind_is_num(wasm_valkind_t k) { + return k < WASM_ANYREF; +} +static inline bool wasm_valkind_is_ref(wasm_valkind_t k) { + return k >= WASM_ANYREF; +} + +static inline bool wasm_valtype_is_num(const wasm_valtype_t* t) { + return wasm_valkind_is_num(wasm_valtype_kind(t)); +} +static inline bool wasm_valtype_is_ref(const wasm_valtype_t* t) { + return wasm_valkind_is_ref(wasm_valtype_kind(t)); +} + + +// Function Types + +WASM_DECLARE_TYPE(functype) + +WASM_API_EXTERN own wasm_functype_t* wasm_functype_new( + own wasm_valtype_vec_t* params, own wasm_valtype_vec_t* results); + +WASM_API_EXTERN const wasm_valtype_vec_t* wasm_functype_params(const wasm_functype_t*); +WASM_API_EXTERN const wasm_valtype_vec_t* wasm_functype_results(const wasm_functype_t*); + + +// Global Types + +WASM_DECLARE_TYPE(globaltype) + +WASM_API_EXTERN own wasm_globaltype_t* wasm_globaltype_new( + own wasm_valtype_t*, wasm_mutability_t); + +WASM_API_EXTERN const wasm_valtype_t* wasm_globaltype_content(const wasm_globaltype_t*); +WASM_API_EXTERN wasm_mutability_t wasm_globaltype_mutability(const wasm_globaltype_t*); + + +// Table Types + +WASM_DECLARE_TYPE(tabletype) + +WASM_API_EXTERN own wasm_tabletype_t* wasm_tabletype_new( + own wasm_valtype_t*, const wasm_limits_t*); + +WASM_API_EXTERN const wasm_valtype_t* wasm_tabletype_element(const wasm_tabletype_t*); +WASM_API_EXTERN const wasm_limits_t* wasm_tabletype_limits(const wasm_tabletype_t*); + + +// Memory Types + +WASM_DECLARE_TYPE(memorytype) + +WASM_API_EXTERN own wasm_memorytype_t* wasm_memorytype_new(const wasm_limits_t*); + +WASM_API_EXTERN const wasm_limits_t* wasm_memorytype_limits(const wasm_memorytype_t*); + + +// Extern Types + +WASM_DECLARE_TYPE(externtype) + +typedef uint8_t wasm_externkind_t; +enum wasm_externkind_enum { + WASM_EXTERN_FUNC, + WASM_EXTERN_GLOBAL, + WASM_EXTERN_TABLE, + WASM_EXTERN_MEMORY, +}; + +WASM_API_EXTERN wasm_externkind_t wasm_externtype_kind(const wasm_externtype_t*); + +WASM_API_EXTERN wasm_externtype_t* wasm_functype_as_externtype(wasm_functype_t*); +WASM_API_EXTERN wasm_externtype_t* wasm_globaltype_as_externtype(wasm_globaltype_t*); +WASM_API_EXTERN wasm_externtype_t* wasm_tabletype_as_externtype(wasm_tabletype_t*); +WASM_API_EXTERN wasm_externtype_t* wasm_memorytype_as_externtype(wasm_memorytype_t*); + +WASM_API_EXTERN wasm_functype_t* wasm_externtype_as_functype(wasm_externtype_t*); +WASM_API_EXTERN wasm_globaltype_t* wasm_externtype_as_globaltype(wasm_externtype_t*); +WASM_API_EXTERN wasm_tabletype_t* wasm_externtype_as_tabletype(wasm_externtype_t*); +WASM_API_EXTERN wasm_memorytype_t* wasm_externtype_as_memorytype(wasm_externtype_t*); + +WASM_API_EXTERN const wasm_externtype_t* wasm_functype_as_externtype_const(const wasm_functype_t*); +WASM_API_EXTERN const wasm_externtype_t* wasm_globaltype_as_externtype_const(const wasm_globaltype_t*); +WASM_API_EXTERN const wasm_externtype_t* wasm_tabletype_as_externtype_const(const wasm_tabletype_t*); +WASM_API_EXTERN const wasm_externtype_t* wasm_memorytype_as_externtype_const(const wasm_memorytype_t*); + +WASM_API_EXTERN const wasm_functype_t* wasm_externtype_as_functype_const(const wasm_externtype_t*); +WASM_API_EXTERN const wasm_globaltype_t* wasm_externtype_as_globaltype_const(const wasm_externtype_t*); +WASM_API_EXTERN const wasm_tabletype_t* wasm_externtype_as_tabletype_const(const wasm_externtype_t*); +WASM_API_EXTERN const wasm_memorytype_t* wasm_externtype_as_memorytype_const(const wasm_externtype_t*); + + +// Import Types + +WASM_DECLARE_TYPE(importtype) + +WASM_API_EXTERN own wasm_importtype_t* wasm_importtype_new( + own wasm_name_t* module, own wasm_name_t* name, own wasm_externtype_t*); + +WASM_API_EXTERN const wasm_name_t* wasm_importtype_module(const wasm_importtype_t*); +WASM_API_EXTERN const wasm_name_t* wasm_importtype_name(const wasm_importtype_t*); +WASM_API_EXTERN const wasm_externtype_t* wasm_importtype_type(const wasm_importtype_t*); + + +// Export Types + +WASM_DECLARE_TYPE(exporttype) + +WASM_API_EXTERN own wasm_exporttype_t* wasm_exporttype_new( + own wasm_name_t*, own wasm_externtype_t*); + +WASM_API_EXTERN const wasm_name_t* wasm_exporttype_name(const wasm_exporttype_t*); +WASM_API_EXTERN const wasm_externtype_t* wasm_exporttype_type(const wasm_exporttype_t*); + + +/////////////////////////////////////////////////////////////////////////////// +// Runtime Objects + +// Values + +struct wasm_ref_t; + +typedef struct wasm_val_t { + wasm_valkind_t kind; + union { + int32_t i32; + int64_t i64; + float32_t f32; + float64_t f64; + struct wasm_ref_t* ref; + } of; +} wasm_val_t; + +WASM_API_EXTERN void wasm_val_delete(own wasm_val_t* v); +WASM_API_EXTERN void wasm_val_copy(own wasm_val_t* out, const wasm_val_t*); + +WASM_DECLARE_VEC(val, ) + + +// References + +#define WASM_DECLARE_REF_BASE(name) \ + WASM_DECLARE_OWN(name) \ + \ + WASM_API_EXTERN own wasm_##name##_t* wasm_##name##_copy(const wasm_##name##_t*); \ + WASM_API_EXTERN bool wasm_##name##_same(const wasm_##name##_t*, const wasm_##name##_t*); + +#define WASM_DECLARE_REF(name) \ + WASM_DECLARE_REF_BASE(name) \ + \ + WASM_API_EXTERN wasm_ref_t* wasm_##name##_as_ref(wasm_##name##_t*); \ + WASM_API_EXTERN wasm_##name##_t* wasm_ref_as_##name(wasm_ref_t*); \ + WASM_API_EXTERN const wasm_ref_t* wasm_##name##_as_ref_const(const wasm_##name##_t*); \ + WASM_API_EXTERN const wasm_##name##_t* wasm_ref_as_##name##_const(const wasm_ref_t*); + +#define WASM_DECLARE_SHARABLE_REF(name) \ + WASM_DECLARE_REF(name) \ + WASM_DECLARE_OWN(shared_##name) \ + \ + WASM_API_EXTERN own wasm_shared_##name##_t* wasm_##name##_share(const wasm_##name##_t*); \ + WASM_API_EXTERN own wasm_##name##_t* wasm_##name##_obtain(wasm_store_t*, const wasm_shared_##name##_t*); + + +WASM_DECLARE_REF_BASE(ref) + +// Traps + +typedef wasm_name_t wasm_message_t; // null terminated + +WASM_DECLARE_REF_BASE(trap) + +WASM_API_EXTERN own wasm_trap_t* wasm_trap_new(wasm_store_t* store, const wasm_message_t*); + +WASM_API_EXTERN void wasm_trap_message(const wasm_trap_t*, own wasm_message_t* out); + +// Modules +#ifndef WASM_MODULE_T_DEFINED +#define WASM_MODULE_T_DEFINED +struct WASMModuleCommon; +typedef struct WASMModuleCommon *wasm_module_t; +#endif + +WASM_API_EXTERN own wasm_module_t* wasm_module_new( + wasm_store_t*, const wasm_byte_vec_t* binary); + +WASM_API_EXTERN bool wasm_module_validate(wasm_store_t*, const wasm_byte_vec_t* binary); + +WASM_API_EXTERN void wasm_module_delete(own wasm_module_t*); + +WASM_API_EXTERN own wasm_module_t* wasm_module_copy(const wasm_module_t*); +WASM_API_EXTERN bool wasm_module_same(const wasm_module_t*, const wasm_module_t*); + +WASM_API_EXTERN void wasm_module_imports(const wasm_module_t*, own wasm_importtype_vec_t* out); +WASM_API_EXTERN void wasm_module_exports(const wasm_module_t*, own wasm_exporttype_vec_t* out); + +WASM_API_EXTERN void wasm_module_serialize(const wasm_module_t*, own wasm_byte_vec_t* out); +WASM_API_EXTERN own wasm_module_t* wasm_module_deserialize(wasm_store_t*, const wasm_byte_vec_t*); + + +// Function Instances + +WASM_DECLARE_REF(func) + +typedef own wasm_trap_t* (*wasm_func_callback_t)( + const wasm_val_t args[], wasm_val_t results[]); +typedef own wasm_trap_t* (*wasm_func_callback_with_env_t)( + void* env, const wasm_val_t args[], wasm_val_t results[]); + +WASM_API_EXTERN own wasm_func_t* wasm_func_new( + wasm_store_t*, const wasm_functype_t*, wasm_func_callback_t); +WASM_API_EXTERN own wasm_func_t* wasm_func_new_with_env( + wasm_store_t*, const wasm_functype_t* type, wasm_func_callback_with_env_t, + void* env, void (*finalizer)(void*)); + +WASM_API_EXTERN own wasm_functype_t* wasm_func_type(const wasm_func_t*); +WASM_API_EXTERN size_t wasm_func_param_arity(const wasm_func_t*); +WASM_API_EXTERN size_t wasm_func_result_arity(const wasm_func_t*); + +WASM_API_EXTERN own wasm_trap_t* wasm_func_call( + const wasm_func_t*, const wasm_val_t args[], wasm_val_t results[]); + + +// Global Instances + +WASM_DECLARE_REF_BASE(global) + +WASM_API_EXTERN own wasm_global_t* wasm_global_new( + wasm_store_t*, const wasm_globaltype_t*, const wasm_val_t*); + +WASM_API_EXTERN own wasm_globaltype_t* wasm_global_type(const wasm_global_t*); + +WASM_API_EXTERN void wasm_global_get(const wasm_global_t*, own wasm_val_t* out); +WASM_API_EXTERN void wasm_global_set(wasm_global_t*, const wasm_val_t*); + + +// Table Instances + +WASM_DECLARE_REF_BASE(table) + +typedef uint32_t wasm_table_size_t; + +WASM_API_EXTERN own wasm_table_t* wasm_table_new( + wasm_store_t*, const wasm_tabletype_t*, wasm_ref_t* init); + +WASM_API_EXTERN own wasm_tabletype_t* wasm_table_type(const wasm_table_t*); + +WASM_API_EXTERN own wasm_ref_t* wasm_table_get(const wasm_table_t*, wasm_table_size_t index); +WASM_API_EXTERN bool wasm_table_set(wasm_table_t*, wasm_table_size_t index, wasm_ref_t*); + +WASM_API_EXTERN wasm_table_size_t wasm_table_size(const wasm_table_t*); +WASM_API_EXTERN bool wasm_table_grow(wasm_table_t*, wasm_table_size_t delta, wasm_ref_t* init); + + +// Memory Instances + +WASM_DECLARE_REF_BASE(memory) + +typedef uint32_t wasm_memory_pages_t; + +static const size_t MEMORY_PAGE_SIZE = 0x10000; + +WASM_API_EXTERN own wasm_memory_t* wasm_memory_new(wasm_store_t*, const wasm_memorytype_t*); + +WASM_API_EXTERN own wasm_memorytype_t* wasm_memory_type(const wasm_memory_t*); + +WASM_API_EXTERN byte_t* wasm_memory_data(wasm_memory_t*); +WASM_API_EXTERN size_t wasm_memory_data_size(const wasm_memory_t*); + +WASM_API_EXTERN wasm_memory_pages_t wasm_memory_size(const wasm_memory_t*); +WASM_API_EXTERN bool wasm_memory_grow(wasm_memory_t*, wasm_memory_pages_t delta); + + +// Externals + +WASM_DECLARE_REF_BASE(extern) +WASM_DECLARE_VEC(extern, *) + +WASM_API_EXTERN wasm_externkind_t wasm_extern_kind(const wasm_extern_t*); +WASM_API_EXTERN own wasm_externtype_t* wasm_extern_type(const wasm_extern_t*); + +WASM_API_EXTERN wasm_extern_t* wasm_func_as_extern(wasm_func_t*); +WASM_API_EXTERN wasm_extern_t* wasm_global_as_extern(wasm_global_t*); +WASM_API_EXTERN wasm_extern_t* wasm_table_as_extern(wasm_table_t*); +WASM_API_EXTERN wasm_extern_t* wasm_memory_as_extern(wasm_memory_t*); + +WASM_API_EXTERN wasm_func_t* wasm_extern_as_func(wasm_extern_t*); +WASM_API_EXTERN wasm_global_t* wasm_extern_as_global(wasm_extern_t*); +WASM_API_EXTERN wasm_table_t* wasm_extern_as_table(wasm_extern_t*); +WASM_API_EXTERN wasm_memory_t* wasm_extern_as_memory(wasm_extern_t*); + +WASM_API_EXTERN const wasm_extern_t* wasm_func_as_extern_const(const wasm_func_t*); +WASM_API_EXTERN const wasm_extern_t* wasm_global_as_extern_const(const wasm_global_t*); +WASM_API_EXTERN const wasm_extern_t* wasm_table_as_extern_const(const wasm_table_t*); +WASM_API_EXTERN const wasm_extern_t* wasm_memory_as_extern_const(const wasm_memory_t*); + +WASM_API_EXTERN const wasm_func_t* wasm_extern_as_func_const(const wasm_extern_t*); +WASM_API_EXTERN const wasm_global_t* wasm_extern_as_global_const(const wasm_extern_t*); +WASM_API_EXTERN const wasm_table_t* wasm_extern_as_table_const(const wasm_extern_t*); +WASM_API_EXTERN const wasm_memory_t* wasm_extern_as_memory_const(const wasm_extern_t*); + + +// Module Instances + +WASM_DECLARE_REF_BASE(instance) + +WASM_API_EXTERN own wasm_instance_t* wasm_instance_new( + wasm_store_t*, const wasm_module_t*, const wasm_extern_t* const imports[], + own wasm_trap_t** +); + +WASM_API_EXTERN void wasm_instance_exports(const wasm_instance_t*, own wasm_extern_vec_t* out); + + +/////////////////////////////////////////////////////////////////////////////// +// Convenience + +// Value Type construction short-hands + +static inline own wasm_valtype_t* wasm_valtype_new_i32() { + return wasm_valtype_new(WASM_I32); +} +static inline own wasm_valtype_t* wasm_valtype_new_i64() { + return wasm_valtype_new(WASM_I64); +} +static inline own wasm_valtype_t* wasm_valtype_new_f32() { + return wasm_valtype_new(WASM_F32); +} +static inline own wasm_valtype_t* wasm_valtype_new_f64() { + return wasm_valtype_new(WASM_F64); +} + +static inline own wasm_valtype_t* wasm_valtype_new_anyref() { + return wasm_valtype_new(WASM_ANYREF); +} +static inline own wasm_valtype_t* wasm_valtype_new_funcref() { + return wasm_valtype_new(WASM_FUNCREF); +} + + +// Function Types construction short-hands + +static inline own wasm_functype_t* wasm_functype_new_0_0() { + wasm_valtype_vec_t params, results; + wasm_valtype_vec_new_empty(¶ms); + wasm_valtype_vec_new_empty(&results); + return wasm_functype_new(¶ms, &results); +} + +static inline own wasm_functype_t* wasm_functype_new_1_0( + own wasm_valtype_t* p +) { + wasm_valtype_t* ps[1] = {p}; + wasm_valtype_vec_t params, results; + wasm_valtype_vec_new(¶ms, 1, ps); + wasm_valtype_vec_new_empty(&results); + return wasm_functype_new(¶ms, &results); +} + +static inline own wasm_functype_t* wasm_functype_new_2_0( + own wasm_valtype_t* p1, own wasm_valtype_t* p2 +) { + wasm_valtype_t* ps[2] = {p1, p2}; + wasm_valtype_vec_t params, results; + wasm_valtype_vec_new(¶ms, 2, ps); + wasm_valtype_vec_new_empty(&results); + return wasm_functype_new(¶ms, &results); +} + +static inline own wasm_functype_t* wasm_functype_new_3_0( + own wasm_valtype_t* p1, own wasm_valtype_t* p2, own wasm_valtype_t* p3 +) { + wasm_valtype_t* ps[3] = {p1, p2, p3}; + wasm_valtype_vec_t params, results; + wasm_valtype_vec_new(¶ms, 3, ps); + wasm_valtype_vec_new_empty(&results); + return wasm_functype_new(¶ms, &results); +} + +static inline own wasm_functype_t* wasm_functype_new_0_1( + own wasm_valtype_t* r +) { + wasm_valtype_t* rs[1] = {r}; + wasm_valtype_vec_t params, results; + wasm_valtype_vec_new_empty(¶ms); + wasm_valtype_vec_new(&results, 1, rs); + return wasm_functype_new(¶ms, &results); +} + +static inline own wasm_functype_t* wasm_functype_new_1_1( + own wasm_valtype_t* p, own wasm_valtype_t* r +) { + wasm_valtype_t* ps[1] = {p}; + wasm_valtype_t* rs[1] = {r}; + wasm_valtype_vec_t params, results; + wasm_valtype_vec_new(¶ms, 1, ps); + wasm_valtype_vec_new(&results, 1, rs); + return wasm_functype_new(¶ms, &results); +} + +static inline own wasm_functype_t* wasm_functype_new_2_1( + own wasm_valtype_t* p1, own wasm_valtype_t* p2, own wasm_valtype_t* r +) { + wasm_valtype_t* ps[2] = {p1, p2}; + wasm_valtype_t* rs[1] = {r}; + wasm_valtype_vec_t params, results; + wasm_valtype_vec_new(¶ms, 2, ps); + wasm_valtype_vec_new(&results, 1, rs); + return wasm_functype_new(¶ms, &results); +} + +static inline own wasm_functype_t* wasm_functype_new_3_1( + own wasm_valtype_t* p1, own wasm_valtype_t* p2, own wasm_valtype_t* p3, + own wasm_valtype_t* r +) { + wasm_valtype_t* ps[3] = {p1, p2, p3}; + wasm_valtype_t* rs[1] = {r}; + wasm_valtype_vec_t params, results; + wasm_valtype_vec_new(¶ms, 3, ps); + wasm_valtype_vec_new(&results, 1, rs); + return wasm_functype_new(¶ms, &results); +} + +static inline own wasm_functype_t* wasm_functype_new_0_2( + own wasm_valtype_t* r1, own wasm_valtype_t* r2 +) { + wasm_valtype_t* rs[2] = {r1, r2}; + wasm_valtype_vec_t params, results; + wasm_valtype_vec_new_empty(¶ms); + wasm_valtype_vec_new(&results, 2, rs); + return wasm_functype_new(¶ms, &results); +} + +static inline own wasm_functype_t* wasm_functype_new_1_2( + own wasm_valtype_t* p, own wasm_valtype_t* r1, own wasm_valtype_t* r2 +) { + wasm_valtype_t* ps[1] = {p}; + wasm_valtype_t* rs[2] = {r1, r2}; + wasm_valtype_vec_t params, results; + wasm_valtype_vec_new(¶ms, 1, ps); + wasm_valtype_vec_new(&results, 2, rs); + return wasm_functype_new(¶ms, &results); +} + +static inline own wasm_functype_t* wasm_functype_new_2_2( + own wasm_valtype_t* p1, own wasm_valtype_t* p2, + own wasm_valtype_t* r1, own wasm_valtype_t* r2 +) { + wasm_valtype_t* ps[2] = {p1, p2}; + wasm_valtype_t* rs[2] = {r1, r2}; + wasm_valtype_vec_t params, results; + wasm_valtype_vec_new(¶ms, 2, ps); + wasm_valtype_vec_new(&results, 2, rs); + return wasm_functype_new(¶ms, &results); +} + +static inline own wasm_functype_t* wasm_functype_new_3_2( + own wasm_valtype_t* p1, own wasm_valtype_t* p2, own wasm_valtype_t* p3, + own wasm_valtype_t* r1, own wasm_valtype_t* r2 +) { + wasm_valtype_t* ps[3] = {p1, p2, p3}; + wasm_valtype_t* rs[2] = {r1, r2}; + wasm_valtype_vec_t params, results; + wasm_valtype_vec_new(¶ms, 3, ps); + wasm_valtype_vec_new(&results, 2, rs); + return wasm_functype_new(¶ms, &results); +} + + +// Value construction short-hands + +static inline void wasm_val_init_ptr(own wasm_val_t* out, void* p) { +#if UINTPTR_MAX == UINT32_MAX + out->kind = WASM_I32; + out->of.i32 = (intptr_t)p; +#elif UINTPTR_MAX == UINT64_MAX + out->kind = WASM_I64; + out->of.i64 = (intptr_t)p; +#endif +} + +static inline void* wasm_val_ptr(const wasm_val_t* val) { +#if UINTPTR_MAX == UINT32_MAX + return (void*)(intptr_t)val->of.i32; +#elif UINTPTR_MAX == UINT64_MAX + return (void*)(intptr_t)val->of.i64; +#endif +} + + +/////////////////////////////////////////////////////////////////////////////// + +#undef own + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // #ifdef WASM_H diff --git a/core/iwasm/include/wasm_export.h b/core/iwasm/include/wasm_export.h index 8c4ff9271..eb48a0e3e 100644 --- a/core/iwasm/include/wasm_export.h +++ b/core/iwasm/include/wasm_export.h @@ -43,10 +43,13 @@ extern "C" { #define native_raw_set_return(val) *raw_ret = (val) +#ifndef WASM_MODULE_T_DEFINED +#define WASM_MODULE_T_DEFINED /* Uninstantiated WASM module loaded from WASM binary file or AoT binary file*/ struct WASMModuleCommon; typedef struct WASMModuleCommon *wasm_module_t; +#endif /* Instantiated WASM module */ struct WASMModuleInstanceCommon; diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index 7d75a31b4..b1bbd1e4d 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -1095,9 +1095,11 @@ load_global_import(const WASMModule *parent_module, #endif if (!ret) { +#if WASM_ENABLE_SPEC_TEST != 0 set_error_buf_v(error_buf, error_buf_size, "unknown import or incompatible import type"); return false; +#endif } global->module_name = sub_module_name; diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index 4f8007a1b..c2d9ab9cb 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -995,9 +995,6 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, error_buf, error_buf_size))) { return NULL; } - - LOG_DEBUG("Instantiate a module %p -> %p", module, module_inst); - memset(module_inst, 0, (uint32)sizeof(WASMModuleInstance)); module_inst->module = module; diff --git a/core/shared/utils/bh_platform.h b/core/shared/utils/bh_platform.h index 6d7bd1141..94b156f47 100644 --- a/core/shared/utils/bh_platform.h +++ b/core/shared/utils/bh_platform.h @@ -15,6 +15,7 @@ #include "bh_list.h" #include "bh_log.h" #include "bh_queue.h" +#include "bh_vector.h" #include "runtime_timer.h" diff --git a/core/shared/utils/bh_vector.c b/core/shared/utils/bh_vector.c index 15fc9fc29..dfb8339bc 100644 --- a/core/shared/utils/bh_vector.c +++ b/core/shared/utils/bh_vector.c @@ -27,7 +27,7 @@ extend_vector(Vector *vector, uint32 length) { uint8 *data; - if (length <= vector->max_elements) + if (length <= vector->max_elems) return true; if (length < vector->size_elem * 3 / 2) @@ -37,10 +37,10 @@ extend_vector(Vector *vector, uint32 length) return false; } - memcpy(data, vector->data, vector->size_elem * vector->max_elements); + memcpy(data, vector->data, vector->size_elem * vector->max_elems); BH_FREE(vector->data); vector->data = data; - vector->max_elements = length; + vector->max_elems = length; return true; } @@ -62,8 +62,8 @@ bh_vector_init(Vector *vector, uint32 init_length, uint32 size_elem) } vector->size_elem = size_elem; - vector->max_elements = init_length; - vector->num_elements = 0; + vector->max_elems = init_length; + vector->num_elems = 0; return true; } @@ -75,7 +75,7 @@ bh_vector_set(Vector *vector, uint32 index, const void *elem_buf) return false; } - if (index >= vector->num_elements) { + if (index >= vector->num_elems) { LOG_ERROR("Set vector elem failed: invalid elem index.\n"); return false; } @@ -92,7 +92,7 @@ bool bh_vector_get(const Vector *vector, uint32 index, void *elem_buf) return false; } - if (index >= vector->num_elements) { + if (index >= vector->num_elems) { LOG_ERROR("Get vector elem failed: invalid elem index.\n"); return false; } @@ -112,24 +112,24 @@ bool bh_vector_insert(Vector *vector, uint32 index, const void *elem_buf) return false; } - if (index >= vector->num_elements) { + if (index >= vector->num_elems) { LOG_ERROR("Insert vector elem failed: invalid elem index.\n"); return false; } - if (!extend_vector(vector, vector->num_elements + 1)) { + if (!extend_vector(vector, vector->num_elems + 1)) { LOG_ERROR("Insert vector elem failed: extend vector failed.\n"); return false; } - p = vector->data + vector->size_elem * vector->num_elements; - for (i = vector->num_elements - 1; i > index; i--) { + p = vector->data + vector->size_elem * vector->num_elems; + for (i = vector->num_elems - 1; i > index; i--) { memcpy(p, p - vector->size_elem, vector->size_elem); p -= vector->size_elem; } memcpy(p, elem_buf, vector->size_elem); - vector->num_elements++; + vector->num_elems++; return true; } @@ -140,14 +140,14 @@ bool bh_vector_append(Vector *vector, const void *elem_buf) return false; } - if (!extend_vector(vector, vector->num_elements + 1)) { + if (!extend_vector(vector, vector->num_elems + 1)) { LOG_ERROR("Append ector elem failed: extend vector failed.\n"); return false; } - memcpy(vector->data + vector->size_elem * vector->num_elements, + memcpy(vector->data + vector->size_elem * vector->num_elems, elem_buf, vector->size_elem); - vector->num_elements++; + vector->num_elems++; return true; } @@ -162,7 +162,7 @@ bh_vector_remove(Vector *vector, uint32 index, void *old_elem_buf) return false; } - if (index >= vector->num_elements) { + if (index >= vector->num_elems) { LOG_ERROR("Remove vector elem failed: invalid elem index.\n"); return false; } @@ -173,19 +173,19 @@ bh_vector_remove(Vector *vector, uint32 index, void *old_elem_buf) memcpy(old_elem_buf, p, vector->size_elem); } - for (i = index; i < vector->num_elements - 1; i++) { + for (i = index; i < vector->num_elems - 1; i++) { memcpy(p, p + vector->size_elem, vector->size_elem); p += vector->size_elem; } - vector->num_elements--; + vector->num_elems--; return true; } uint32 bh_vector_size(const Vector *vector) { - return vector ? vector->num_elements : 0; + return vector ? vector->num_elems : 0; } bool diff --git a/core/shared/utils/bh_vector.h b/core/shared/utils/bh_vector.h index 548c84970..1ae7c279b 100644 --- a/core/shared/utils/bh_vector.h +++ b/core/shared/utils/bh_vector.h @@ -15,14 +15,14 @@ extern "C" { #define DEFAULT_VECTOR_INIT_SIZE 8 typedef struct Vector { - /* size of each element */ - uint32 size_elem; /* max element number */ - uint32 max_elements; - /* current element num */ - uint32 num_elements; + size_t max_elems; /* vector data allocated */ uint8 *data; + /* current element num */ + size_t num_elems; + /* size of each element */ + size_t size_elem; } Vector; /** diff --git a/doc/wasm_c_api.md b/doc/wasm_c_api.md new file mode 100644 index 000000000..6d2278743 --- /dev/null +++ b/doc/wasm_c_api.md @@ -0,0 +1,77 @@ +All samples come from the commit 340fd9528cc3b26d22fe30ee1628c8c3f2b8c53b +of [wasm-c-api][https://github.com/WebAssembly/wasm-c-api]. + +Every user should be familiar with *APIs* listed in +[wasm.h][https://github.com/WebAssembly/wasm-c-api/blob/master/include/wasm.h]. + +all [examples][https://github.com/WebAssembly/wasm-c-api/tree/master/example] are +very helpful for learning. + +Currently, we support partial of *APIs* and are going to support the rest of +them in next releases. + +Supported APIs: + +``` c +/* wasm_bytevec_t APIs ... */ + +wasm_engine_t *wasm_engine_new(); +wasm_engine_t *wasm_engine_new_with_args(mem_alloc_type_t, const MemAllocOption*, runtime_mode_e); +void wasm_engine_delete(wasm_engine_t *); + +wasm_store_t *wasm_store_new(wasm_engine_t *); +void wasm_store_delete(wasm_store_t *); + +/* wasm_valtype_t APIs ... */ +/* wasm_valtype_vec_t APIs ... */ +/* wasm_functype_vec_t APIs ... */ +/* wasm_globaltype_vec_t APIs ... */ +/* wasm_val_t APIs ... */ +/* wasm_trap_t partial APIs ... */ + +wasm_module_t *wasm_module_new(wasm_store_t *, const wasm_byte_vec_t *); +void wasm_module_delete(wasm_module_t *); + +wasm_func_t *wasm_func_new(wasm_store_t *, const wasm_functype_t *, wasm_func_callback_t); +wasm_func_t *wasm_func_new_with_env(wasm_store_t *store, const wasm_functype_t *, wasm_func_callback_with_env_t, void *env, void (*finalizer)(void *)); +void wasm_func_delete(wasm_func_t *); +wasm_fucn_t *wasm_func_copy(const wasm_func_t *); +wasm_functype_t *wasm_func_type(const wasm_func_t *); +wasm_trap_t * wasm_func_call(const wasm_func_t *, const wasm_val_t params[], wasm_val_t results[]); +size_t wasm_func_param_arity(const wasm_func_t *); +size_t wasm_func_result_arity(const wasm_func_t *); + +wasm_global_t *wasm_global_new(wasm_store_t *, const wasm_globaltype_t *, const wasm_val_t *); +wasm_global_t * wasm_global_copy(const wasm_global_t *); +void wasm_global_delete(wasm_global_t *); +bool wasm_global_same(const wasm_global_t *, const wasm_global_t *); +void wasm_global_set(wasm_global_t *, const wasm_val_t *); +void wasm_global_get(const wasm_global_t *, wasm_val_t *out); +wasm_globaltype_t * wasm_global_type(const wasm_global_t *); + +wasm_instance_t *wasm_instance_new(wasm_store_t *, const wasm_module_t *, const wasm_extern_t *const imports[], wasm_trap_t **traps); +void wasm_instance_delete(wasm_instance_t *); +void wasm_instance_exports(const wasm_instance_t *, wasm_extern_vec_t *out); + +/* wasm_extern_t APIs */ +``` + +Unsupported APIs: + +``` c +/* wasm_tabletype_t APIs */ +/* wasm_memorytype_t APIs */ +/* wasm_externtype_t APIs */ +/* wasm_importtype_t APIs */ +/* wasm_exporttype_t APIs */ +/* wasm_ref_t APIs */ +/* wasm_shared_##name##_t APIs */ + +WASM_API_EXTERN bool wasm_module_validate(wasm_store_t*, const wasm_byte_vec_t* binary); +WASM_API_EXTERN void wasm_module_imports(const wasm_module_t*, own wasm_importtype_vec_t* out); +WASM_API_EXTERN void wasm_module_serialize(const wasm_module_t*, own wasm_byte_vec_t* out); +WASM_API_EXTERN own wasm_module_t* wasm_module_deserialize(wasm_store_t*, const wasm_byte_vec_t*); + +/* wasm_table_t APIs */ +/* wasm_memory_t APIs */ +``` diff --git a/samples/multi-module/CMakeLists.txt b/samples/multi-module/CMakeLists.txt index 774524c6f..ac06fcb38 100644 --- a/samples/multi-module/CMakeLists.txt +++ b/samples/multi-module/CMakeLists.txt @@ -3,7 +3,6 @@ cmake_minimum_required(VERSION 2.8) project(multi_module) -set(CMAKE_VERBOSE_MAKEFILE on) ################ runtime settings ################ set(WAMR_BUILD_PLATFORM "linux") @@ -18,7 +17,7 @@ set(WAMR_BUILD_INTERP 1) set(WAMR_BUILD_AOT 0) set(WAMR_BUILD_JIT 0) set(WAMR_BUILD_LIBC_BUILTIN 1) -set(WAMR_BUILD_LIBC_WASI 1) +set(WAMR_BUILD_LIBC_WASI 0) set(WAMR_BUILD_FAST_INTERP 0) set(WAMR_BUILD_MULTI_MODULE 1) diff --git a/samples/wasm-c-api/CMakeLists.txt b/samples/wasm-c-api/CMakeLists.txt new file mode 100644 index 000000000..6e0a47222 --- /dev/null +++ b/samples/wasm-c-api/CMakeLists.txt @@ -0,0 +1,89 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required (VERSION 2.8) +project(c-api) + +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Release) +endif() +################ runtime settings ################ +set(WAMR_BUILD_PLATFORM "linux") + +# Resetdefault linker flags +set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") +set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") + +# WAMR features switch +set(WAMR_BUILD_TARGET "X86_64") + +if(NOT DEFINED WAMR_BUILD_INTERP) + set(WAMR_BUILD_INTERP 1) +endif() + +if(NOT DEFINED WAMR_BUILD_AOT) + set(WAMR_BUILD_AOT 0) +endif() + +if(NOT DEFINED WAMR_BUILD_JOT) + set(WAMR_BUILD_JIT 0) +endif() + +set(WAMR_BUILD_LIBC_BUILTIN 1) +set(WAMR_BUILD_LIBC_WASI 0) + +if(NOT DEFINED WAMR_BUILD_FAST_INTERP) + set(WAMR_BUILD_FAST_INTERP 0) +endif() + +# compiling and linking flags +set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections -pie -fPIE") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat -Wformat-security -mindirect-branch-register") + +# build out vmlib +set(WAMR_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../..) +set(WAMRC ${WAMR_ROOT_DIR}/wamr-compiler/build/wamrc) +include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) + +add_library(vmlib STATIC ${WAMR_RUNTIME_LIB_SOURCE}) +################################################ + +################ application related ################ +file(GLOB SOURCES src/*.c) +add_library(c-api ${SOURCES}) +target_include_directories(c-api + PRIVATE ${C_API_PATH}/include +) +target_link_libraries(c-api PRIVATE vmlib -lpthread -lm) + +foreach(SRC ${SOURCES}) + get_filename_component(APPNAME ${SRC} NAME_WE) + + # build executable for each .c + add_executable(${APPNAME} ${SRC}) + message("create executable about ${APPNAME}") + target_link_libraries(${APPNAME} c-api) + + # copy .wasm + add_custom_command(TARGET ${APPNAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_CURRENT_SOURCE_DIR}/src/${APPNAME}.wasm + ${PROJECT_BINARY_DIR}/ + BYPRODUCTS ${APPNAME}.wasm + COMMENT "Copy ${SRC} to the output directory" + ) + + # generate .aot file + if(${WAMR_BUILD_AOT} EQUAL 1) + if(EXISTS ${WAMRC}) + add_custom_command(TARGET ${APPNAME} POST_BUILD + COMMAND ${WAMRC} -o ${APPNAME}.aot + ${CMAKE_CURRENT_SOURCE_DIR}/src/${APPNAME}.wasm + BYPRODUCTS ${APPNAME}.aot + COMMENT "generate a aot file ${APPNAME}.aot" + ) + endif() + endif() + +endforeach(SRC ${SOURCES}) +################################################ diff --git a/samples/wasm-c-api/README.md b/samples/wasm-c-api/README.md new file mode 100644 index 000000000..31d2aea09 --- /dev/null +++ b/samples/wasm-c-api/README.md @@ -0,0 +1,39 @@ +WAMR supports *wasm-c-api* in both *interpreter* mode and *aot* mode. By default, +all samples are compiled and run in "interpreter" mode. + +``` shell +$ mkdir build +$ cd build +$ cmake .. +$ make +$ # it will build a library with c-api supporting. +$ # Also copy *.wasm from ../src/ +$ # and generate executable files +$ # now, it is ok to run samples +$ ./hello +$ ... +$ ./global +$ ... +$ ./callback +$ ... +``` + +They can be compiled and run in *aot* mode when some compiling flags are given. + +``` shell +$ mkdir build +$ cd build +$ cmake -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_AOT=1 .. +$ make +$ # it will build a library with c-api supporting. +$ # Also copy *.wasm from ../src/ +$ # and transform *.wasm to *.aot +$ # and generate executable files +$ # now, it is ok to run samples +$ ./hello +$ ... +$ ./global +$ ... +$ ./callback +$ ... +``` \ No newline at end of file diff --git a/samples/wasm-c-api/src/callback.c b/samples/wasm-c-api/src/callback.c new file mode 100644 index 000000000..df2e65592 --- /dev/null +++ b/samples/wasm-c-api/src/callback.c @@ -0,0 +1,168 @@ +#include +#include +#include +#include + +#include "wasm_c_api.h" + +#define own + +// Print a Wasm value +void wasm_val_print(wasm_val_t val) { + switch (val.kind) { + case WASM_I32: { + printf("%" PRIu32, val.of.i32); + } break; + case WASM_I64: { + printf("%" PRIu64, val.of.i64); + } break; + case WASM_F32: { + printf("%f", val.of.f32); + } break; + case WASM_F64: { + printf("%g", val.of.f64); + } break; + case WASM_ANYREF: + case WASM_FUNCREF: { + if (val.of.ref == NULL) { + printf("null"); + } else { + printf("ref(%p)", val.of.ref); + } + } break; + } +} + +// A function to be called from Wasm code. +own wasm_trap_t* print_callback( + const wasm_val_t args[], wasm_val_t results[] +) { + printf("Calling back...\n> "); + wasm_val_print(args[0]); + printf("\n"); + + wasm_val_copy(&results[0], &args[0]); + return NULL; +} + + +// A function closure. +own wasm_trap_t* closure_callback( + void* env, const wasm_val_t args[], wasm_val_t results[] +) { + int i = *(int*)env; + printf("Calling back closure...\n"); + printf("> %d\n", i); + + results[0].kind = WASM_I32; + results[0].of.i32 = (int32_t)i; + return NULL; +} + + +int main(int argc, const char* argv[]) { + // Initialize. + printf("Initializing...\n"); + wasm_engine_t* engine = wasm_engine_new(); + wasm_store_t* store = wasm_store_new(engine); + + // Load binary. + printf("Loading binary...\n"); + FILE* file = fopen("callback.wasm", "rb"); + if (!file) { + printf("> Error loading module!\n"); + return 1; + } + fseek(file, 0L, SEEK_END); + size_t file_size = ftell(file); + fseek(file, 0L, SEEK_SET); + wasm_byte_vec_t binary; + wasm_byte_vec_new_uninitialized(&binary, file_size); + if (fread(binary.data, file_size, 1, file) != 1) { + printf("> Error loading module!\n"); + return 1; + } + fclose(file); + + // Compile. + printf("Compiling module...\n"); + own wasm_module_t* module = wasm_module_new(store, &binary); + if (!module) { + printf("> Error compiling module!\n"); + return 1; + } + + wasm_byte_vec_delete(&binary); + + // Create external print functions. + printf("Creating callback...\n"); + own wasm_functype_t* print_type = wasm_functype_new_1_1(wasm_valtype_new_i32(), wasm_valtype_new_i32()); + own wasm_func_t* print_func = wasm_func_new(store, print_type, print_callback); + + int i = 42; + own wasm_functype_t* closure_type = wasm_functype_new_0_1(wasm_valtype_new_i32()); + own wasm_func_t* closure_func = wasm_func_new_with_env(store, closure_type, closure_callback, &i, NULL); + + wasm_functype_delete(print_type); + wasm_functype_delete(closure_type); + + // Instantiate. + printf("Instantiating module...\n"); + const wasm_extern_t* imports[] = { + wasm_func_as_extern(print_func), wasm_func_as_extern(closure_func) + }; + own wasm_instance_t* instance = + wasm_instance_new(store, module, imports, NULL); + if (!instance) { + printf("> Error instantiating module!\n"); + return 1; + } + + wasm_func_delete(print_func); + wasm_func_delete(closure_func); + + // Extract export. + printf("Extracting export...\n"); + own wasm_extern_vec_t exports; + wasm_instance_exports(instance, &exports); + if (exports.size == 0) { + printf("> Error accessing exports!\n"); + return 1; + } + const wasm_func_t* run_func = wasm_extern_as_func(exports.data[0]); + if (run_func == NULL) { + printf("> Error accessing export!\n"); + return 1; + } + + wasm_module_delete(module); + wasm_instance_delete(instance); + + // Call. + printf("Calling export...\n"); + wasm_val_t args[2]; + args[0].kind = WASM_I32; + args[0].of.i32 = 3; + args[1].kind = WASM_I32; + args[1].of.i32 = 4; + wasm_val_t results[1]; + if (wasm_func_call(run_func, args, results)) { + printf("> Error calling function!\n"); + return 1; + } + + wasm_extern_vec_delete(&exports); + + // Print result. + printf("Printing result...\n"); + printf("> %u\n", results[0].of.i32); + + // Shut down. + printf("Shutting down...\n"); + wasm_store_delete(store); + wasm_engine_delete(engine); + + // All done. + printf("Done.\n"); + return 0; +} diff --git a/samples/wasm-c-api/src/callback.wasm b/samples/wasm-c-api/src/callback.wasm new file mode 100644 index 0000000000000000000000000000000000000000..7e00b580142c1e8171c18577fca06d1a39f2b48c GIT binary patch literal 102 zcmW+sy9$6H6g~G!2(|bLewq;tNm*#lN=r*a1pRN?aNY-fSO@^!IcEq%iIPD9r{egn nEu-1|Lqn5QP-MFgPD&Y~ literal 0 HcmV?d00001 diff --git a/samples/wasm-c-api/src/callback.wat b/samples/wasm-c-api/src/callback.wat new file mode 100644 index 000000000..d86195f51 --- /dev/null +++ b/samples/wasm-c-api/src/callback.wat @@ -0,0 +1,10 @@ +(module + (func $print (import "" "print") (param i32) (result i32)) + (func $closure (import "" "closure") (result i32)) + (func (export "run") (param $x i32) (param $y i32) (result i32) + (i32.add + (call $print (i32.add (local.get $x) (local.get $y))) + (call $closure) + ) + ) +) diff --git a/samples/wasm-c-api/src/global.c b/samples/wasm-c-api/src/global.c new file mode 100644 index 000000000..ba73d95ed --- /dev/null +++ b/samples/wasm-c-api/src/global.c @@ -0,0 +1,236 @@ +#include +#include +#include +#include + +#include "wasm_c_api.h" + +#define own + +wasm_global_t* get_export_global(const wasm_extern_vec_t* exports, size_t i) { + if (exports->size <= i || !wasm_extern_as_global(exports->data[i])) { + printf("> Error accessing global export %zu!\n", i); + exit(1); + } + return wasm_extern_as_global(exports->data[i]); +} + +wasm_func_t* get_export_func(const wasm_extern_vec_t* exports, size_t i) { + if (exports->size <= i || !wasm_extern_as_func(exports->data[i])) { + printf("> Error accessing function export %zu!\n", i); + exit(1); + } + return wasm_extern_as_func(exports->data[i]); +} + + +#define check(val, type, expected) \ + if (val.of.type != expected) { \ + printf("> Error reading value\n"); \ + exit(1); \ + } + +#define check_global(global, type, expected) \ + { \ + wasm_val_t val; \ + wasm_global_get(global, &val); \ + check(val, type, expected); \ + } + +#define check_call(func, type, expected) \ + { \ + wasm_val_t results[1]; \ + wasm_func_call(func, NULL, results); \ + check(results[0], type, expected); \ + } + + +int main(int argc, const char* argv[]) { + // Initialize. + printf("Initializing...\n"); + wasm_engine_t* engine = wasm_engine_new(); + wasm_store_t* store = wasm_store_new(engine); + + // Load binary. + printf("Loading binary...\n"); +#if WASM_ENABLE_AOT != 0 && WASM_ENABLE_INTERP == 0 + FILE* file = fopen("global.aot", "rb"); +#else + FILE* file = fopen("global.wasm", "rb"); +#endif + if (!file) { + printf("> Error loading module!\n"); + return 1; + } + fseek(file, 0L, SEEK_END); + size_t file_size = ftell(file); + fseek(file, 0L, SEEK_SET); + wasm_byte_vec_t binary; + wasm_byte_vec_new_uninitialized(&binary, file_size); + if (fread(binary.data, file_size, 1, file) != 1) { + printf("> Error loading module!\n"); + return 1; + } + fclose(file); + + // Compile. + printf("Compiling module...\n"); + own wasm_module_t* module = wasm_module_new(store, &binary); + if (!module) { + printf("> Error compiling module!\n"); + return 1; + } + + wasm_byte_vec_delete(&binary); + + // Create external globals. + printf("Creating globals...\n"); + own wasm_globaltype_t* const_f32_type = wasm_globaltype_new( + wasm_valtype_new(WASM_F32), WASM_CONST); + own wasm_globaltype_t* const_i64_type = wasm_globaltype_new( + wasm_valtype_new(WASM_I64), WASM_CONST); + own wasm_globaltype_t* var_f32_type = wasm_globaltype_new( + wasm_valtype_new(WASM_F32), WASM_VAR); + own wasm_globaltype_t* var_i64_type = wasm_globaltype_new( + wasm_valtype_new(WASM_I64), WASM_VAR); + + wasm_val_t val_f32_1 = {.kind = WASM_F32, .of = {.f32 = 1}}; + own wasm_global_t* const_f32_import = + wasm_global_new(store, const_f32_type, &val_f32_1); + wasm_val_t val_i64_2 = {.kind = WASM_I64, .of = {.i64 = 2}}; + own wasm_global_t* const_i64_import = + wasm_global_new(store, const_i64_type, &val_i64_2); + wasm_val_t val_f32_3 = {.kind = WASM_F32, .of = {.f32 = 3}}; + own wasm_global_t* var_f32_import = + wasm_global_new(store, var_f32_type, &val_f32_3); + wasm_val_t val_i64_4 = {.kind = WASM_I64, .of = {.i64 = 4}}; + own wasm_global_t* var_i64_import = + wasm_global_new(store, var_i64_type, &val_i64_4); + + wasm_globaltype_delete(const_f32_type); + wasm_globaltype_delete(const_i64_type); + wasm_globaltype_delete(var_f32_type); + wasm_globaltype_delete(var_i64_type); + + // Instantiate. + printf("Instantiating module...\n"); + const wasm_extern_t* imports[] = { + wasm_global_as_extern(const_f32_import), + wasm_global_as_extern(const_i64_import), + wasm_global_as_extern(var_f32_import), + wasm_global_as_extern(var_i64_import) + }; + own wasm_instance_t* instance = + wasm_instance_new(store, module, imports, NULL); + if (!instance) { + printf("> Error instantiating module!\n"); + return 1; + } + + wasm_module_delete(module); + + // Extract export. + printf("Extracting exports...\n"); + own wasm_extern_vec_t exports; + wasm_instance_exports(instance, &exports); + size_t i = 0; + wasm_global_t* const_f32_export = get_export_global(&exports, i++); + wasm_global_t* const_i64_export = get_export_global(&exports, i++); + wasm_global_t* var_f32_export = get_export_global(&exports, i++); + wasm_global_t* var_i64_export = get_export_global(&exports, i++); + wasm_func_t* get_const_f32_import = get_export_func(&exports, i++); + wasm_func_t* get_const_i64_import = get_export_func(&exports, i++); + wasm_func_t* get_var_f32_import = get_export_func(&exports, i++); + wasm_func_t* get_var_i64_import = get_export_func(&exports, i++); + wasm_func_t* get_const_f32_export = get_export_func(&exports, i++); + wasm_func_t* get_const_i64_export = get_export_func(&exports, i++); + wasm_func_t* get_var_f32_export = get_export_func(&exports, i++); + wasm_func_t* get_var_i64_export = get_export_func(&exports, i++); + wasm_func_t* set_var_f32_import = get_export_func(&exports, i++); + wasm_func_t* set_var_i64_import = get_export_func(&exports, i++); + wasm_func_t* set_var_f32_export = get_export_func(&exports, i++); + wasm_func_t* set_var_i64_export = get_export_func(&exports, i++); + + // Try cloning. + own wasm_global_t* copy = wasm_global_copy(var_f32_import); + assert(wasm_global_same(var_f32_import, copy)); + wasm_global_delete(copy); + + // Interact. + printf("Accessing globals...\n"); + + // Check initial values. + check_global(const_f32_import, f32, 1); + check_global(const_i64_import, i64, 2); + check_global(var_f32_import, f32, 3); + check_global(var_i64_import, i64, 4); + check_global(const_f32_export, f32, 5); + check_global(const_i64_export, i64, 6); + check_global(var_f32_export, f32, 7); + check_global(var_i64_export, i64, 8); + + check_call(get_const_f32_import, f32, 1); + check_call(get_const_i64_import, i64, 2); + check_call(get_var_f32_import, f32, 3); + check_call(get_var_i64_import, i64, 4); + check_call(get_const_f32_export, f32, 5); + check_call(get_const_i64_export, i64, 6); + check_call(get_var_f32_export, f32, 7); + check_call(get_var_i64_export, i64, 8); + + // Modify variables through API and check again. + wasm_val_t val33 = {.kind = WASM_F32, .of = {.f32 = 33}}; + wasm_global_set(var_f32_import, &val33); + wasm_val_t val34 = {.kind = WASM_I64, .of = {.i64 = 34}}; + wasm_global_set(var_i64_import, &val34); + wasm_val_t val37 = {.kind = WASM_F32, .of = {.f32 = 37}}; + wasm_global_set(var_f32_export, &val37); + wasm_val_t val38 = {.kind = WASM_I64, .of = {.i64 = 38}}; + wasm_global_set(var_i64_export, &val38); + + check_global(var_f32_import, f32, 33); + check_global(var_i64_import, i64, 34); + check_global(var_f32_export, f32, 37); + check_global(var_i64_export, i64, 38); + + check_call(get_var_f32_import, f32, 33); + check_call(get_var_i64_import, i64, 34); + check_call(get_var_f32_export, f32, 37); + check_call(get_var_i64_export, i64, 38); + + // Modify variables through calls and check again. + wasm_val_t args73[] = { {.kind = WASM_F32, .of = {.f32 = 73}} }; + wasm_func_call(set_var_f32_import, args73, NULL); + wasm_val_t args74[] = { {.kind = WASM_I64, .of = {.i64 = 74}} }; + wasm_func_call(set_var_i64_import, args74, NULL); + wasm_val_t args77[] = { {.kind = WASM_F32, .of = {.f32 = 77}} }; + wasm_func_call(set_var_f32_export, args77, NULL); + wasm_val_t args78[] = { {.kind = WASM_I64, .of = {.i64 = 78}} }; + wasm_func_call(set_var_i64_export, args78, NULL); + + check_global(var_f32_import, f32, 73); + check_global(var_i64_import, i64, 74); + check_global(var_f32_export, f32, 77); + check_global(var_i64_export, i64, 78); + + check_call(get_var_f32_import, f32, 73); + check_call(get_var_i64_import, i64, 74); + check_call(get_var_f32_export, f32, 77); + check_call(get_var_i64_export, i64, 78); + + wasm_global_delete(const_f32_import); + wasm_global_delete(const_i64_import); + wasm_global_delete(var_f32_import); + wasm_global_delete(var_i64_import); + wasm_extern_vec_delete(&exports); + wasm_instance_delete(instance); + + // Shut down. + printf("Shutting down...\n"); + wasm_store_delete(store); + wasm_engine_delete(engine); + + // All done. + printf("Done.\n"); + return 0; +} diff --git a/samples/wasm-c-api/src/global.wasm b/samples/wasm-c-api/src/global.wasm new file mode 100644 index 0000000000000000000000000000000000000000..0e76863278e62f064730544392e92c0194097134 GIT binary patch literal 576 zcmZXQO-{ow5JtbT6T7Whpo#-nYEMuq)~H-06)II1rKpK2HjbhSv17rS4Od{neYgaB zY$yJaP?YG+%lMl~u&(z6fZn^VLs5Z@z1xZmDr&*Ly~ga0h(esunAu4B6tx7PJ~E`E|BuF0*OHz%H|llY}Sd z7SvjF?mdh_gai%h%jL6lIOEopM_L z-(VDFw!t{cEOU}%nyx0l{#U=aCuUFsPyiNy2PguR0Ym_)UVV +#include +#include +#include + +#include "wasm_c_api.h" + +#define own + +// A function to be called from Wasm code. +own wasm_trap_t* hello_callback( + const wasm_val_t args[], wasm_val_t results[] +) { + printf("Calling back...\n"); + printf("> Hello World!\n"); + return NULL; +} + + +int main(int argc, const char* argv[]) { + // Initialize. + printf("Initializing...\n"); + wasm_engine_t* engine = wasm_engine_new(); + wasm_store_t* store = wasm_store_new(engine); + + // Load binary. + printf("Loading binary...\n"); +#if WASM_ENABLE_AOT != 0 && WASM_ENABLE_INTERP == 0 + FILE* file = fopen("hello.aot", "rb"); +#else + FILE* file = fopen("hello.wasm", "rb"); +#endif + if (!file) { + printf("> Error loading module!\n"); + return 1; + } + fseek(file, 0L, SEEK_END); + size_t file_size = ftell(file); + fseek(file, 0L, SEEK_SET); + wasm_byte_vec_t binary; + wasm_byte_vec_new_uninitialized(&binary, file_size); + if (fread(binary.data, file_size, 1, file) != 1) { + printf("> Error loading module!\n"); + return 1; + } + fclose(file); + + // Compile. + printf("Compiling module...\n"); + own wasm_module_t* module = wasm_module_new(store, &binary); + if (!module) { + printf("> Error compiling module!\n"); + return 1; + } + + wasm_byte_vec_delete(&binary); + + // Create external print functions. + printf("Creating callback...\n"); + own wasm_functype_t* hello_type = wasm_functype_new_0_0(); + own wasm_func_t* hello_func = + wasm_func_new(store, hello_type, hello_callback); + + wasm_functype_delete(hello_type); + + // Instantiate. + printf("Instantiating module...\n"); + const wasm_extern_t* imports[] = { wasm_func_as_extern(hello_func) }; + own wasm_instance_t* instance = + wasm_instance_new(store, module, imports, NULL); + if (!instance) { + printf("> Error instantiating module!\n"); + return 1; + } + + wasm_func_delete(hello_func); + + // Extract export. + printf("Extracting export...\n"); + own wasm_extern_vec_t exports; + wasm_instance_exports(instance, &exports); + if (exports.size == 0) { + printf("> Error accessing exports!\n"); + return 1; + } + const wasm_func_t* run_func = wasm_extern_as_func(exports.data[0]); + if (run_func == NULL) { + printf("> Error accessing export!\n"); + return 1; + } + + wasm_module_delete(module); + wasm_instance_delete(instance); + + // Call. + printf("Calling export...\n"); + if (wasm_func_call(run_func, NULL, NULL)) { + printf("> Error calling function!\n"); + return 1; + } + + wasm_extern_vec_delete(&exports); + + // Shut down. + printf("Shutting down...\n"); + wasm_store_delete(store); + wasm_engine_delete(engine); + + // All done. + printf("Done.\n"); + return 0; +} diff --git a/samples/wasm-c-api/src/hello.wasm b/samples/wasm-c-api/src/hello.wasm new file mode 100644 index 0000000000000000000000000000000000000000..2207c03eead3f45f13dfa58b73c6bce27716bffa GIT binary patch literal 71 zcmZQbEY4+QU|?WuX=rF*U`$|OVCn+17+5n>b8_+-7?_(NeD-!Q&0JKP$H2%1Q3Te+ IAi%&40BKwiaR2}S literal 0 HcmV?d00001 diff --git a/samples/wasm-c-api/src/hello.wat b/samples/wasm-c-api/src/hello.wat new file mode 100644 index 000000000..1c56c5582 --- /dev/null +++ b/samples/wasm-c-api/src/hello.wat @@ -0,0 +1,4 @@ +(module + (func $hello (import "" "hello")) + (func (export "run") (call $hello)) +) From 056b824ac46bf4c70e2b1a7abb624389f28d2244 Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Tue, 28 Jul 2020 13:46:37 +0800 Subject: [PATCH 036/207] Fix fast interpreter i64 shift issue for non-x86 arch (#319) --- core/iwasm/interpreter/wasm_interp_fast.c | 6 +++--- .../libraries/template/lib_export_template.c | 17 ----------------- 2 files changed, 3 insertions(+), 20 deletions(-) delete mode 100644 core/iwasm/libraries/template/lib_export_template.c diff --git a/core/iwasm/interpreter/wasm_interp_fast.c b/core/iwasm/interpreter/wasm_interp_fast.c index 2307ead86..2e31552ae 100644 --- a/core/iwasm/interpreter/wasm_interp_fast.c +++ b/core/iwasm/interpreter/wasm_interp_fast.c @@ -495,7 +495,7 @@ read_leb(const uint8 *buf, uint32 *p_offset, uint32 maxbits, bool sign) #define DEF_OP_NUMERIC(src_type1, src_type2, src_op_type, operation) do { \ SET_OPERAND(src_type1, 4, (GET_OPERAND(src_type1, 2) \ - operation GET_OPERAND(src_type1, 0))); \ + operation GET_OPERAND(src_type2, 0))); \ frame_ip += 6; \ } while (0) @@ -530,13 +530,13 @@ read_leb(const uint8 *buf, uint32 *p_offset, uint32 maxbits, bool sign) #define DEF_OP_NUMERIC2(src_type1, src_type2, src_op_type, operation) do { \ SET_OPERAND(src_type1, 4, (GET_OPERAND(src_type1, 2) \ - operation (GET_OPERAND(src_type1, 0) % 32))); \ + operation (GET_OPERAND(src_type2, 0) % 32))); \ frame_ip += 6; \ } while (0) #define DEF_OP_NUMERIC2_64(src_type1, src_type2, src_op_type, operation) do { \ SET_OPERAND(src_type1, 4, (GET_OPERAND(src_type1, 2) \ - operation (GET_OPERAND(src_type1, 0) % 64))); \ + operation (GET_OPERAND(src_type2, 0) % 64))); \ frame_ip += 6; \ } while (0) diff --git a/core/iwasm/libraries/template/lib_export_template.c b/core/iwasm/libraries/template/lib_export_template.c deleted file mode 100644 index 35159728b..000000000 --- a/core/iwasm/libraries/template/lib_export_template.c +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright (C) 2019 Intel Corporation. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - */ - -#include -#include -#include -#include "lib-export.h" - -/* TODO: use macro EXPORT_WASM_API() or EXPORT_WASM_API2() to add functions to register. */ - -NativeSymbol extended_native_symbol_defs[] = { - -/*EXPORT_WASM_API(publish_event)*/ - -}; From 88af12501d60ce15474196b482ecdc7f48df9576 Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Tue, 28 Jul 2020 16:18:54 +0800 Subject: [PATCH 037/207] Implement ecall to handle commands from host to call enclave runtime APIs (#320) --- .../platforms/linux-sgx/CMakeLists.txt | 10 +- .../linux-sgx/enclave-sample/App/App.cpp | 573 +++++++++++++++++- .../enclave-sample/Enclave/Enclave.config.xml | 2 +- .../enclave-sample/Enclave/Enclave.cpp | 478 +++++++++++++-- .../enclave-sample/Enclave/Enclave.edl | 6 +- .../linux-sgx/enclave-sample/Makefile | 18 +- 6 files changed, 1035 insertions(+), 52 deletions(-) diff --git a/product-mini/platforms/linux-sgx/CMakeLists.txt b/product-mini/platforms/linux-sgx/CMakeLists.txt index a8da1f752..fa6fedac8 100644 --- a/product-mini/platforms/linux-sgx/CMakeLists.txt +++ b/product-mini/platforms/linux-sgx/CMakeLists.txt @@ -32,9 +32,9 @@ if (NOT DEFINED WAMR_BUILD_INTERP) endif () if (NOT DEFINED WAMR_BUILD_AOT) - # Disable AOT by default. - # If enabling AOT, please install Intel SGX SDKv2.8 or later. - set (WAMR_BUILD_AOT 0) + # Enable AOT by default + # Please install Intel SGX SDKv2.8 or later. + set (WAMR_BUILD_AOT 1) endif () if (NOT DEFINED WAMR_BUILD_JIT) @@ -52,6 +52,10 @@ if (NOT DEFINED WAMR_BUILD_LIBC_WASI) set (WAMR_BUILD_LIBC_WASI 0) endif () +if (COLLECT_CODE_COVERAGE EQUAL 1) + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage") +endif () + set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99 -ffunction-sections -fdata-sections \ -Wall -Wno-unused-parameter -Wno-pedantic \ diff --git a/product-mini/platforms/linux-sgx/enclave-sample/App/App.cpp b/product-mini/platforms/linux-sgx/enclave-sample/App/App.cpp index 9c4dcc5c9..a6d502928 100644 --- a/product-mini/platforms/linux-sgx/enclave-sample/App/App.cpp +++ b/product-mini/platforms/linux-sgx/enclave-sample/App/App.cpp @@ -4,11 +4,15 @@ */ #include +#include +#include +#include +#include +#include +#include #include #include #include -#include -#include #include "Enclave_u.h" #include "sgx_urts.h" @@ -25,7 +29,9 @@ #define ENCLAVE_FILENAME "enclave.signed.so" #define MAX_PATH FILENAME_MAX -sgx_enclave_id_t g_eid = 0; +#define TEST_OCALL_API 0 + +static sgx_enclave_id_t g_eid = 0; void ocall_print(const char* str) @@ -53,7 +59,7 @@ enclave_init(sgx_enclave_id_t *p_eid) sgx_status_t ret = SGX_ERROR_UNEXPECTED; int updated = 0; - /* Step 1: try to retrieve the launch token saved by last transaction + /* Step 1: try to retrieve the launch token saved by last transaction * if there is no token, then create a new one. */ /* try to get the token saved in $HOME */ @@ -116,15 +122,568 @@ enclave_init(sgx_enclave_id_t *p_eid) return 0; } -int -main(int argc, char const *argv[]) +static unsigned char * +read_file_to_buffer(const char *filename, uint32_t *ret_size) { + unsigned char *buffer; + FILE *file; + int file_size, read_size; + + if (!(file = fopen(filename, "r"))) + return NULL; + + fseek(file, 0, SEEK_END); + file_size = ftell(file); + fseek(file, 0, SEEK_SET); + + if (!(buffer = (unsigned char*)malloc(file_size))) { + fclose(file); + return NULL; + } + + read_size = fread(buffer, 1, file_size, file); + fclose(file); + + if (read_size < file_size) { + free(buffer); + return NULL; + } + + *ret_size = file_size; + + return buffer; +} + +static int +print_help() +{ + printf("Usage: iwasm [-options] wasm_file [args...]\n"); + printf("options:\n"); + printf(" -f|--function name Specify a function name of the module to run rather\n" + " than main\n"); + printf(" -v=n Set log verbose level (0 to 5, default is 2) larger\n" + " level with more log\n"); + printf(" --stack-size=n Set maximum stack size in bytes, default is 16 KB\n"); + printf(" --heap-size=n Set maximum heap size in bytes, default is 16 KB\n"); + printf(" --repl Start a very simple REPL (read-eval-print-loop) mode\n" + " that runs commands in the form of `FUNC ARG...`\n"); + printf(" --env= Pass wasi environment variables with \"key=value\"\n"); + printf(" to the program, for example:\n"); + printf(" --env=\"key1=value1\" --env=\"key2=value2\"\n"); + printf(" --dir= Grant wasi access to the given host directories\n"); + printf(" to the program, for example:\n"); + printf(" --dir= --dir=\n"); + printf(" --max-threads=n Set maximum thread number per cluster, default is 4\n"); + return 1; +} + +/** + * Split a space separated strings into an array of strings + * Returns NULL on failure + * Memory must be freed by caller + * Based on: http://stackoverflow.com/a/11198630/471795 + */ +static char ** +split_string(char *str, int *count) +{ + char **res = NULL; + char *p; + int idx = 0; + + /* split string and append tokens to 'res' */ + do { + p = strtok(str, " "); + str = NULL; + res = (char **)realloc(res, sizeof(char *) * (unsigned)(idx + 1)); + if (res == NULL) { + return NULL; + } + res[idx++] = p; + } while (p); + + /** + * since the function name, + * res[0] might be contains a '\' to indicate a space + * func\name -> func name + */ + p = strchr(res[0], '\\'); + while (p) { + *p = ' '; + p = strchr(p, '\\'); + } + + if (count) { + *count = idx - 1; + } + return res; +} + +typedef enum EcallCmd { + CMD_INIT_RUNTIME = 0, /* wasm_runtime_init/full_init() */ + CMD_LOAD_MODULE, /* wasm_runtime_load() */ + CMD_INSTANTIATE_MODULE, /* wasm_runtime_instantiate() */ + CMD_LOOKUP_FUNCTION, /* wasm_runtime_lookup_function() */ + CMD_CREATE_EXEC_ENV, /* wasm_runtime_create_exec_env() */ + CMD_CALL_WASM, /* wasm_runtime_call_wasm */ + CMD_EXEC_APP_FUNC, /* wasm_application_execute_func() */ + CMD_EXEC_APP_MAIN, /* wasm_application_execute_main() */ + CMD_GET_EXCEPTION, /* wasm_runtime_get_exception() */ + CMD_DEINSTANTIATE_MODULE, /* wasm_runtime_deinstantiate() */ + CMD_UNLOAD_MODULE, /* wasm_runtime_unload() */ + CMD_DESTROY_RUNTIME, /* wasm_runtime_destroy() */ + CMD_SET_WASI_ARGS, /* wasm_runtime_set_wasi_args() */ + CMD_SET_LOG_LEVEL, /* bh_log_set_verbose_level() */ + CMD_SET_MAX_THREAD_NUM, /* wasm_runtime_set_max_thread_num() */ +} EcallCmd; + +static void +app_instance_func(void *wasm_module_inst, const char *func_name, + int app_argc, char **app_argv); + +static void * +app_instance_repl(void *module_inst, int app_argc, char **app_argv) +{ + char *cmd = NULL; + size_t len = 0; + ssize_t n; + + while ((printf("webassembly> "), n = getline(&cmd, &len, stdin)) != -1) { + assert(n > 0); + if (cmd[n - 1] == '\n') { + if (n == 1) + continue; + else + cmd[n - 1] = '\0'; + } + if (!strcmp(cmd, "__exit__")) { + printf("exit repl mode\n"); + break; + } + app_argv = split_string(cmd, &app_argc); + if (app_argv == NULL) { + printf("Wasm prepare param failed: split string failed.\n"); + break; + } + if (app_argc != 0) { + app_instance_func(module_inst, app_argv[0], + app_argc - 1, app_argv + 1); + } + free(app_argv); + } + free(cmd); + return NULL; +} + +static bool +validate_env_str(char *env) +{ + char *p = env; + int key_len = 0; + + while (*p != '\0' && *p != '=') { + key_len++; + p++; + } + + if (*p != '=' || key_len == 0) + return false; + + return true; +} + +static bool +set_log_verbose_level(int log_verbose_level) +{ + uint64_t ecall_args[1]; + + /* Set log verbose level */ + if (log_verbose_level != 2) { + ecall_args[0] = log_verbose_level; + if (SGX_SUCCESS != ecall_handle_command(g_eid, CMD_SET_LOG_LEVEL, + (uint8_t *)ecall_args, + sizeof(uint64_t))) { + printf("Call ecall_handle_command() failed.\n"); + return false; + } + } + return true; +} + +static bool +init_runtime(bool alloc_with_pool) +{ + uint64_t ecall_args[1]; + + ecall_args[0] = alloc_with_pool; + if (SGX_SUCCESS != ecall_handle_command(g_eid, CMD_INIT_RUNTIME, + (uint8_t *)ecall_args, + sizeof(uint64_t))) { + printf("Call ecall_handle_command() failed.\n"); + return false; + } + if (!(bool)ecall_args[0]) { + printf("Init runtime environment failed.\n"); + return false; + } + return true; +} + +static void +destroy_runtime() +{ + if (SGX_SUCCESS != ecall_handle_command(g_eid, CMD_DESTROY_RUNTIME, + NULL, 0)) { + printf("Call ecall_handle_command() failed.\n"); + } +} + +static void * +load_module(uint8_t *wasm_file_buf, uint32_t wasm_file_size, + char *error_buf, uint32_t error_buf_size) +{ + uint64_t ecall_args[4]; + + ecall_args[0] = (uint64_t)(uintptr_t)wasm_file_buf; + ecall_args[1] = wasm_file_size; + ecall_args[2] = (uint64_t)(uintptr_t)error_buf; + ecall_args[3] = error_buf_size; + if (SGX_SUCCESS != ecall_handle_command(g_eid, CMD_LOAD_MODULE, + (uint8_t *)ecall_args, + sizeof(uint64_t) * 4)) { + printf("Call ecall_handle_command() failed.\n"); + return NULL; + } + + return (void *)(uintptr_t)ecall_args[0]; +} + +static void +unload_module(void *wasm_module) +{ + uint64_t ecall_args[1]; + + ecall_args[0] = (uint64_t)(uintptr_t)wasm_module; + if (SGX_SUCCESS != ecall_handle_command(g_eid, CMD_UNLOAD_MODULE, + (uint8_t *)ecall_args, + sizeof(uint64_t))) { + printf("Call ecall_handle_command() failed.\n"); + } +} + +static void * +instantiate_module(void *wasm_module, + uint32_t stack_size, uint32_t heap_size, + char *error_buf, uint32_t error_buf_size) +{ + uint64_t ecall_args[5]; + + ecall_args[0] = (uint64_t)(uintptr_t)wasm_module; + ecall_args[1] = stack_size; + ecall_args[2] = heap_size; + ecall_args[3] = (uint64_t)(uintptr_t)error_buf; + ecall_args[4] = error_buf_size; + if (SGX_SUCCESS != ecall_handle_command(g_eid, CMD_INSTANTIATE_MODULE, + (uint8_t *)ecall_args, + sizeof(uint64_t) * 5)) { + printf("Call ecall_handle_command() failed.\n"); + return NULL; + } + + return (void *)(uintptr_t)ecall_args[0]; +} + +static void +deinstantiate_module(void *wasm_module_inst) +{ + uint64_t ecall_args[1]; + + ecall_args[0] = (uint64_t)(uintptr_t)wasm_module_inst; + if (SGX_SUCCESS != ecall_handle_command(g_eid, CMD_DEINSTANTIATE_MODULE, + (uint8_t *)ecall_args, + sizeof(uint64_t))) { + printf("Call ecall_handle_command() failed.\n"); + } +} + +static bool +get_exception(void *wasm_module_inst, + char *exception, uint32_t exception_size) +{ + uint64_t ecall_args[3]; + + ecall_args[0] = (uint64_t)(uintptr_t)wasm_module_inst; + ecall_args[1] = (uint64_t)(uintptr_t)exception; + ecall_args[2] = exception_size; + if (SGX_SUCCESS != ecall_handle_command(g_eid, CMD_GET_EXCEPTION, + (uint8_t *)ecall_args, + sizeof(uint64_t) * 3)) { + printf("Call ecall_handle_command() failed.\n"); + } + + return (bool)ecall_args[0]; +} + +static void +app_instance_main(void *wasm_module_inst, + int app_argc, char **app_argv) +{ + char exception[128]; + uint64_t ecall_args_buf[16], *ecall_args = ecall_args_buf; + int i, size; + + if (app_argc + 2 > sizeof(ecall_args_buf) / sizeof(uint64_t)) { + if (!(ecall_args = (uint64_t *) + malloc(sizeof(uint64_t) * (app_argc + 2)))) { + printf("Allocate memory failed.\n"); + return; + } + } + + ecall_args[0] = (uintptr_t)wasm_module_inst; + ecall_args[1] = app_argc; + for (i = 0; i < app_argc; i++) { + ecall_args[i + 2] = (uintptr_t)app_argv[i]; + } + + size = (uint32_t)sizeof(uint64_t) * (app_argc + 2); + if (SGX_SUCCESS != ecall_handle_command(g_eid, CMD_EXEC_APP_MAIN, + (uint8_t *)ecall_args, + size)) { + printf("Call ecall_handle_command() failed.\n"); + } + + if (get_exception(wasm_module_inst, exception, sizeof(exception))) { + printf("%s\n", exception); + } + + if (ecall_args != ecall_args_buf) { + free(ecall_args); + } +} + +static void +app_instance_func(void *wasm_module_inst, const char *func_name, + int app_argc, char **app_argv) +{ + uint64_t ecall_args_buf[16], *ecall_args = ecall_args_buf; + int i, size; + + if (app_argc + 3 > sizeof(ecall_args_buf) / sizeof(uint64_t)) { + if (!(ecall_args = (uint64_t *) + malloc(sizeof(uint64_t) * (app_argc + 3)))) { + printf("Allocate memory failed.\n"); + return; + } + } + + ecall_args[0] = (uintptr_t)wasm_module_inst; + ecall_args[1] = (uintptr_t)func_name; + ecall_args[2] = (uintptr_t)app_argc; + for (i = 0; i < app_argc; i++) { + ecall_args[i + 3] = (uintptr_t)app_argv[i]; + } + + size = (uint32_t)sizeof(uint64_t) * (app_argc + 3); + if (SGX_SUCCESS != ecall_handle_command(g_eid, CMD_EXEC_APP_FUNC, + (uint8_t *)ecall_args, + size)) { + printf("Call ecall_handle_command() failed.\n"); + } + + if (ecall_args != ecall_args_buf) { + free(ecall_args); + } +} + +static bool +set_wasi_args(void *wasm_module, + const char **dir_list, uint32_t dir_list_size, + const char **env_list, uint32_t env_list_size, + char **argv, uint32_t argc) +{ + uint64_t ecall_args[7]; + + ecall_args[0] = (uint64_t)(uintptr_t)wasm_module; + ecall_args[1] = (uint64_t)(uintptr_t)dir_list; + ecall_args[2] = dir_list_size; + ecall_args[3] = (uint64_t)(uintptr_t)env_list; + ecall_args[4] = env_list_size; + ecall_args[5] = (uint64_t)(uintptr_t)argv; + ecall_args[6] = argc; + if (SGX_SUCCESS != ecall_handle_command(g_eid, CMD_SET_WASI_ARGS, + (uint8_t *)ecall_args, + sizeof(uint64_t) * 7)) { + printf("Call ecall_handle_command() failed.\n"); + } + + return (bool)ecall_args[0]; +} + +int +main(int argc, char *argv[]) +{ + char *wasm_file = NULL; + const char *func_name = NULL; + uint8_t *wasm_file_buf = NULL; + uint32_t wasm_file_size; + uint32_t stack_size = 16 * 1024, heap_size = 16 * 1024; + void *wasm_module = NULL; + void *wasm_module_inst = NULL; + char error_buf[128] = { 0 }; + int log_verbose_level = 2; + bool is_repl_mode = false, alloc_with_pool = false; + const char *dir_list[8] = { NULL }; + uint32_t dir_list_size = 0; + const char *env_list[8] = { NULL }; + uint32_t env_list_size = 0; + if (enclave_init(&g_eid) < 0) { std::cout << "Fail to initialize enclave." << std::endl; return 1; } - ecall_iwasm_main(g_eid); +#if TEST_OCALL_API != 0 + { + ecall_iwasm_test(g_eid); + return 0; + } +#endif + + /* Process options. */ + for (argc--, argv++; argc > 0 && argv[0][0] == '-'; argc--, argv++) { + if (!strcmp(argv[0], "-f") || !strcmp(argv[0], "--function")) { + argc--, argv++; + if (argc < 2) { + print_help(); + return 0; + } + func_name = argv[0]; + } + else if (!strncmp(argv[0], "-v=", 3)) { + log_verbose_level = atoi(argv[0] + 3); + if (log_verbose_level < 0 || log_verbose_level > 5) + return print_help(); + } + else if (!strcmp(argv[0], "--repl")) { + is_repl_mode = true; + } + else if (!strncmp(argv[0], "--stack-size=", 13)) { + if (argv[0][13] == '\0') + return print_help(); + stack_size = atoi(argv[0] + 13); + } + else if (!strncmp(argv[0], "--heap-size=", 12)) { + if (argv[0][12] == '\0') + return print_help(); + heap_size = atoi(argv[0] + 12); + } + else if (!strncmp(argv[0], "--dir=", 6)) { + if (argv[0][6] == '\0') + return print_help(); + if (dir_list_size >= sizeof(dir_list) / sizeof(char *)) { + printf("Only allow max dir number %d\n", + (int)(sizeof(dir_list) / sizeof(char *))); + return -1; + } + dir_list[dir_list_size++] = argv[0] + 6; + } + else if (!strncmp(argv[0], "--env=", 6)) { + char *tmp_env; + + if (argv[0][6] == '\0') + return print_help(); + if (env_list_size >= sizeof(env_list) / sizeof(char *)) { + printf("Only allow max env number %d\n", + (int)(sizeof(env_list) / sizeof(char *))); + return -1; + } + tmp_env = argv[0] + 6; + if (validate_env_str(tmp_env)) + env_list[env_list_size++] = tmp_env; + else { + printf("Wasm parse env string failed: expect \"key=value\", " + "got \"%s\"\n", + tmp_env); + return print_help(); + } + } + else if (!strncmp(argv[0], "--max-threads=", 14)) { + if (argv[0][14] == '\0') + return print_help(); + /*wasm_runtime_set_max_thread_num(atoi(argv[0] + 14));*/ + /* TODO */ + } + else + return print_help(); + } + + if (argc == 0) + return print_help(); + + wasm_file = argv[0]; + + /* Init runtime */ + if (!init_runtime(alloc_with_pool)) { + return -1; + } + + /* Set log verbose level */ + if (!set_log_verbose_level(log_verbose_level)) { + goto fail1; + } + + /* Load WASM byte buffer from WASM bin file */ + if (!(wasm_file_buf = + (uint8_t *)read_file_to_buffer(wasm_file, &wasm_file_size))) { + goto fail1; + } + + /* Load module */ + if (!(wasm_module = load_module(wasm_file_buf, wasm_file_size, + error_buf, sizeof(error_buf)))) { + printf("%s\n", error_buf); + goto fail2; + } + + /* Set wasi arguments */ + if (!set_wasi_args(wasm_module, dir_list, dir_list_size, + env_list, env_list_size, argv, argc)) { + printf("%s\n", "set wasi arguments failed.\n"); + goto fail3; + } + + /* Instantiate module */ + if (!(wasm_module_inst = instantiate_module(wasm_module, + stack_size, heap_size, + error_buf, + sizeof(error_buf)))) { + printf("%s\n", error_buf); + goto fail3; + } + + if (is_repl_mode) + app_instance_repl(wasm_module_inst, argc, argv); + else if (func_name) + app_instance_func(wasm_module_inst, func_name, + argc - 1, argv + 1); + else + app_instance_main(wasm_module_inst, argc, argv); + + /* Deinstantiate module */ + deinstantiate_module(wasm_module_inst); + +fail3: + /* Unload module */ + unload_module(wasm_module); + +fail2: + /* Free the file buffer */ + free(wasm_file_buf); + +fail1: + /* Destroy runtime environment */ + destroy_runtime(); + return 0; } diff --git a/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.config.xml b/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.config.xml index dfdb26c12..94d7e1043 100644 --- a/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.config.xml +++ b/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.config.xml @@ -3,7 +3,7 @@ 0 0 0x40000 - 0x200000 + 0x400000 0x100000 1 10 diff --git a/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.cpp b/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.cpp index 428f72e1c..7d4472851 100644 --- a/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.cpp +++ b/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.cpp @@ -5,50 +5,461 @@ #include #include +#include +#include + #include "Enclave_t.h" -#include "test_wasm.h" #include "wasm_export.h" - -static char global_heap_buf[2* 1024 * 1024] = { 0 }; - -static int app_argc; -static char **app_argv; - -static void* -app_instance_main(wasm_module_inst_t module_inst) -{ - const char *exception; - - wasm_application_execute_main(module_inst, app_argc, app_argv); - if ((exception = wasm_runtime_get_exception(module_inst))) { - ocall_print(exception); - ocall_print("\n"); - } - return NULL; -} +#include "bh_platform.h" extern "C" { + typedef void (*os_print_function_t)(const char* message); + extern void os_set_print_function(os_print_function_t pf); -typedef void (*os_print_function_t)(const char* message); -extern void os_set_print_function(os_print_function_t pf); - -void enclave_print(const char *message) -{ - ocall_print(message); + void + enclave_print(const char *message) + { + ocall_print(message); + } } +typedef enum EcallCmd { + CMD_INIT_RUNTIME = 0, /* wasm_runtime_init/full_init() */ + CMD_LOAD_MODULE, /* wasm_runtime_load() */ + CMD_INSTANTIATE_MODULE, /* wasm_runtime_instantiate() */ + CMD_LOOKUP_FUNCTION, /* wasm_runtime_lookup_function() */ + CMD_CREATE_EXEC_ENV, /* wasm_runtime_create_exec_env() */ + CMD_CALL_WASM, /* wasm_runtime_call_wasm */ + CMD_EXEC_APP_FUNC, /* wasm_application_execute_func() */ + CMD_EXEC_APP_MAIN, /* wasm_application_execute_main() */ + CMD_GET_EXCEPTION, /* wasm_runtime_get_exception() */ + CMD_DEINSTANTIATE_MODULE, /* wasm_runtime_deinstantiate() */ + CMD_UNLOAD_MODULE, /* wasm_runtime_unload() */ + CMD_DESTROY_RUNTIME, /* wasm_runtime_destroy() */ + CMD_SET_WASI_ARGS, /* wasm_runtime_set_wasi_args() */ + CMD_SET_LOG_LEVEL, /* bh_log_set_verbose_level() */ + CMD_SET_MAX_THREAD_NUM, /* wasm_runtime_set_max_thread_num() */ +} EcallCmd; + +typedef struct EnclaveModule { + wasm_module_t module; + uint8 *wasm_file; + uint32 wasm_file_size; + char *wasi_arg_buf; + char **wasi_dir_list; + uint32 wasi_dir_list_size; + char **wasi_env_list; + uint32 wasi_env_list_size; + char **wasi_argv; + uint32 wasi_argc; +} EnclaveModule; + +static char global_heap_buf[2 * 1024 * 1024] = { 0 }; + +static void +set_error_buf(char *error_buf, uint32 error_buf_size, const char *string) +{ + if (error_buf != NULL) + snprintf(error_buf, error_buf_size, "%s", string); } -void ecall_iwasm_main() +static void +handle_cmd_init_runtime(uint64 *args, uint32 argc) { + bool alloc_with_pool = true; + RuntimeInitArgs init_args; + os_set_print_function(enclave_print); - uint8_t *wasm_file_buf = NULL; - int wasm_file_size; + if (argc > 0) { + alloc_with_pool = (bool)args[0]; + } + + memset(&init_args, 0, sizeof(RuntimeInitArgs)); + + if (alloc_with_pool) { + init_args.mem_alloc_type = Alloc_With_Pool; + init_args.mem_alloc_option.pool.heap_buf = global_heap_buf; + init_args.mem_alloc_option.pool.heap_size = sizeof(global_heap_buf); + } + else { + init_args.mem_alloc_type = Alloc_With_System_Allocator; + } + + /* initialize runtime environment */ + if (!wasm_runtime_full_init(&init_args)) { + LOG_ERROR("Init runtime environment failed.\n"); + args[0] = false; + return; + } + + args[0] = true; + + LOG_VERBOSE("Init runtime environment success.\n"); +} + +static void +handle_cmd_destroy_runtime() +{ + wasm_runtime_destroy(); + + LOG_VERBOSE("Destroy runtime success.\n"); +} + +static void +handle_cmd_load_module(uint64 *args, uint32 argc) +{ + uint64 *args_org = args; + char *wasm_file = *(char **)args++; + uint32 wasm_file_size = *(uint32 *)args++; + char *error_buf = *(char **)args++; + uint32 error_buf_size = *(uint32 *)args++; + uint64 total_size = sizeof(EnclaveModule) + (uint64)wasm_file_size; + EnclaveModule *enclave_module; + + bh_assert(argc == 4); + + if (total_size >= UINT32_MAX + || !(enclave_module = (EnclaveModule *) + wasm_runtime_malloc((uint32)total_size))) { + set_error_buf(error_buf, error_buf_size, + "WASM module load failed: " + "allocate memory failed."); + *(void **)args_org = NULL; + return; + } + + memset(enclave_module, 0, (uint32)total_size); + enclave_module->wasm_file = (uint8 *)enclave_module + + sizeof(EnclaveModule); + bh_memcpy_s(enclave_module->wasm_file, wasm_file_size, + wasm_file, wasm_file_size); + + if (!(enclave_module->module = + wasm_runtime_load(enclave_module->wasm_file, wasm_file_size, + error_buf, error_buf_size))) { + *(void **)args_org = NULL; + return; + } + + *(EnclaveModule **)args_org = enclave_module; + + LOG_VERBOSE("Load module success.\n"); +} + +static void +handle_cmd_unload_module(uint64 *args, uint32 argc) +{ + EnclaveModule *enclave_module = *(EnclaveModule **)args++; + uint32 i; + + bh_assert(argc == 1); + + if (enclave_module->wasi_arg_buf) + wasm_runtime_free(enclave_module->wasi_arg_buf); + + wasm_runtime_unload(enclave_module->module); + wasm_runtime_free(enclave_module); + + LOG_VERBOSE("Unload module success.\n"); +} + +static void +handle_cmd_instantiate_module(uint64 *args, uint32 argc) +{ + uint64 *args_org = args; + EnclaveModule *enclave_module = *(EnclaveModule **)args++; + uint32 stack_size = *(uint32 *)args++; + uint32 heap_size = *(uint32 *)args++; + char *error_buf = *(char **)args++; + uint32 error_buf_size = *(uint32 *)args++; + wasm_module_inst_t module_inst; + + bh_assert(argc == 5); + + if (!(module_inst = + wasm_runtime_instantiate(enclave_module->module, + stack_size, heap_size, + error_buf, error_buf_size))) { + *(void **)args_org = NULL; + return; + } + + *(wasm_module_inst_t *)args_org = module_inst; + + LOG_VERBOSE("Instantiate module success.\n"); +} + +static void +handle_cmd_deinstantiate_module(uint64 *args, uint32 argc) +{ + wasm_module_inst_t module_inst = *(wasm_module_inst_t *)args++; + + bh_assert(argc == 1); + + wasm_runtime_deinstantiate(module_inst); + + LOG_VERBOSE("Deinstantiate module success.\n"); +} + +static void +handle_cmd_get_exception(uint64 *args, uint32 argc) +{ + uint64 *args_org = args; + wasm_module_inst_t module_inst = *(wasm_module_inst_t *)args++; + char *exception = *(char **)args++; + uint32 exception_size = *(uint32 *)args++; + const char *exception1; + + bh_assert(argc == 3); + + if ((exception1 = wasm_runtime_get_exception(module_inst))) { + snprintf(exception, exception_size, + "%s", exception1); + args_org[0] = true; + } + else { + args_org[0] = false; + } +} + +static void +handle_cmd_exec_app_main(uint64 *args, int32 argc) +{ + wasm_module_inst_t module_inst = *(wasm_module_inst_t *)args++; + uint32 app_argc = *(uint32 *)args++; + char **app_argv = NULL; + uint64 total_size; + int32 i; + + bh_assert(argc >= 3); + bh_assert(app_argc >= 1); + + total_size = sizeof(char *) * (app_argc > 2 ? (uint64)app_argc : 2); + + if (total_size >= UINT32_MAX + || !(app_argv = (char **)wasm_runtime_malloc(total_size))) { + wasm_runtime_set_exception(module_inst, "allocate memory failed."); + return; + } + + for (i = 0; i < app_argc; i++) { + app_argv[i] = (char *)(uintptr_t)args[i]; + } + + wasm_application_execute_main(module_inst, app_argc - 1, app_argv + 1); + + wasm_runtime_free(app_argv); +} + +static void +handle_cmd_exec_app_func(uint64 *args, int32 argc) +{ + wasm_module_inst_t module_inst = *(wasm_module_inst_t *)args++; + char *func_name = *(char **)args++; + uint32 app_argc = *(uint32 *)args++; + char **app_argv = NULL; + uint64 total_size; + int32 i, func_name_len = strlen(func_name); + + bh_assert(argc == app_argc + 3); + + total_size = sizeof(char *) * (app_argc > 2 ? (uint64)app_argc : 2); + + if (total_size >= UINT32_MAX + || !(app_argv = (char **)wasm_runtime_malloc(total_size))) { + wasm_runtime_set_exception(module_inst, "allocate memory failed."); + return; + } + + for (i = 0; i < app_argc; i++) { + app_argv[i] = (char *)(uintptr_t)args[i]; + } + + wasm_application_execute_func(module_inst, func_name, app_argc, app_argv); + + wasm_runtime_free(app_argv); +} + +static void +handle_cmd_set_log_level(uint64 *args, uint32 argc) +{ +#if WASM_ENABLE_LOG != 0 + LOG_VERBOSE("Set log verbose level to %d.\n", (int)args[0]); + bh_log_set_verbose_level((int)args[0]); +#endif +} + +static void +handle_cmd_set_max_thread_num(uint64 *args, uint32 argc) +{ +#if WASM_ENABLE_LIB_PTHREAD != 0 + LOG_VERBOSE("Set max thread num to %d.\n", (uint32)args[0]); + wasm_runtime_set_max_thread_num((uint32)args[0]); +#endif +} + +static void +handle_cmd_set_wasi_args(uint64 *args, int32 argc) +{ + uint64 *args_org = args; + EnclaveModule *enclave_module = *(EnclaveModule **)args++; + char **dir_list = *(char ***)args++; + uint32 dir_list_size = *(uint32 *)args++; + char **env_list = *(char ***)args++; + uint32 env_list_size = *(uint32 *)args++; + char **wasi_argv = *(char ***)args++; + char *p, *p1; + uint32 wasi_argc = *(uint32 *)args++; + uint64 total_size = 0; + int32 i, str_len; + + bh_assert(argc == 7); + + total_size += sizeof(char *) * (uint64)dir_list_size + + sizeof(char *) * (uint64)env_list_size + + sizeof(char *) * (uint64)wasi_argc; + + for (i = 0; i < dir_list_size; i++) { + total_size += strlen(dir_list[i]) + 1; + } + + for (i = 0; i < env_list_size; i++) { + total_size += strlen(env_list[i]) + 1; + } + + for (i = 0; i < wasi_argc; i++) { + total_size += strlen(wasi_argv[i]) + 1; + } + + if (total_size >= UINT32_MAX + || !(enclave_module->wasi_arg_buf = p = (char *) + wasm_runtime_malloc((uint32)total_size))) { + *args_org = false; + return; + } + + p1 = p + sizeof(char *) * dir_list_size + + sizeof(char *) * env_list_size + + sizeof(char *) * wasi_argc; + + if (dir_list_size > 0) { + enclave_module->wasi_dir_list = (char **)p; + enclave_module->wasi_dir_list_size = dir_list_size; + for (i = 0; i < dir_list_size; i++) { + enclave_module->wasi_dir_list[i] = p1; + str_len = strlen(dir_list[i]); + bh_memcpy_s(p1, str_len + 1, dir_list[i], str_len + 1); + p1 += str_len + 1; + } + p += sizeof(char *) * dir_list_size; + } + + if (env_list_size > 0) { + enclave_module->wasi_env_list = (char **)p; + enclave_module->wasi_env_list_size = env_list_size; + for (i = 0; i < env_list_size; i++) { + enclave_module->wasi_env_list[i] = p1; + str_len = strlen(env_list[i]); + bh_memcpy_s(p1, str_len + 1, env_list[i], str_len + 1); + p1 += str_len + 1; + } + p += sizeof(char *) * env_list_size; + } + + if (wasi_argc > 0) { + enclave_module->wasi_argv = (char **)p; + enclave_module->wasi_argc = wasi_argc; + for (i = 0; i < wasi_argc; i++) { + enclave_module->wasi_argv[i] = p1; + str_len = strlen(wasi_argv[i]); + bh_memcpy_s(p1, str_len + 1, wasi_argv[i], str_len + 1); + p1 += str_len + 1; + } + p += sizeof(char *) * wasi_argc; + } + +#if WASM_ENABLE_LIBC_WASI != 0 + wasm_runtime_set_wasi_args(enclave_module->module, + (const char **)enclave_module->wasi_dir_list, + dir_list_size, + NULL, 0, + (const char **)enclave_module->wasi_env_list, + env_list_size, + envclave_module->wasi_argv, + envclave_module->wasi_argc); +#endif + + *args_org = true; +} + +void +ecall_handle_command(unsigned cmd, + unsigned char *cmd_buf, + unsigned cmd_buf_size) +{ + uint64 *args = (uint64 *)cmd_buf; + uint32 argc = cmd_buf_size / sizeof(uint64); + + switch (cmd) { + case CMD_INIT_RUNTIME: + handle_cmd_init_runtime(args, argc); + break; + case CMD_LOAD_MODULE: + handle_cmd_load_module(args, argc); + break; + case CMD_SET_WASI_ARGS: + handle_cmd_set_wasi_args(args, argc); + break; + case CMD_INSTANTIATE_MODULE: + handle_cmd_instantiate_module(args, argc); + break; + case CMD_LOOKUP_FUNCTION: + break; + case CMD_CREATE_EXEC_ENV: + break; + case CMD_CALL_WASM: + break; + case CMD_EXEC_APP_FUNC: + handle_cmd_exec_app_func(args, argc); + break; + case CMD_EXEC_APP_MAIN: + handle_cmd_exec_app_main(args, argc); + break; + case CMD_GET_EXCEPTION: + handle_cmd_get_exception(args, argc); + break; + case CMD_DEINSTANTIATE_MODULE: + handle_cmd_deinstantiate_module(args, argc); + break; + case CMD_UNLOAD_MODULE: + handle_cmd_unload_module(args, argc); + break; + case CMD_DESTROY_RUNTIME: + handle_cmd_destroy_runtime(); + break; + case CMD_SET_LOG_LEVEL: + handle_cmd_set_log_level(args, argc); + break; + case CMD_SET_MAX_THREAD_NUM: + handle_cmd_set_max_thread_num(args, argc); + break; + default: + LOG_ERROR("Unknown command %d\n", cmd); + break; + } +} + +void +ecall_iwasm_main(uint8_t *wasm_file_buf, uint32_t wasm_file_size) +{ wasm_module_t wasm_module = NULL; wasm_module_inst_t wasm_module_inst = NULL; RuntimeInitArgs init_args; char error_buf[128]; + const char *exception; + + os_set_print_function(enclave_print); memset(&init_args, 0, sizeof(RuntimeInitArgs)); @@ -63,10 +474,6 @@ void ecall_iwasm_main() return; } - /* load WASM byte buffer from byte buffer of include file */ - wasm_file_buf = (uint8_t*) wasm_test_file; - wasm_file_size = sizeof(wasm_test_file); - /* load WASM module */ if (!(wasm_module = wasm_runtime_load(wasm_file_buf, wasm_file_size, error_buf, sizeof(error_buf)))) { @@ -87,7 +494,11 @@ void ecall_iwasm_main() } /* execute the main function of wasm app */ - app_instance_main(wasm_module_inst); + wasm_application_execute_main(wasm_module_inst, 0, NULL); + if ((exception = wasm_runtime_get_exception(wasm_module_inst))) { + ocall_print(exception); + ocall_print("\n"); + } /* destroy the module instance */ wasm_runtime_deinstantiate(wasm_module_inst); @@ -100,4 +511,3 @@ fail1: /* destroy runtime environment */ wasm_runtime_destroy(); } - diff --git a/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.edl b/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.edl index fc7ef56ea..5b3bde341 100644 --- a/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.edl +++ b/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.edl @@ -8,7 +8,11 @@ enclave { trusted { /* define ECALLs here. */ - public void ecall_iwasm_main(void); + public void ecall_handle_command(unsigned cmd, + [in, out, size=cmd_buf_size]uint8_t *cmd_buf, + unsigned cmd_buf_size); + public void ecall_iwasm_main([user_check]uint8_t *wasm_file_buf, + uint32_t wasm_file_size); }; untrusted { diff --git a/product-mini/platforms/linux-sgx/enclave-sample/Makefile b/product-mini/platforms/linux-sgx/enclave-sample/Makefile index 56016bd98..57074f141 100644 --- a/product-mini/platforms/linux-sgx/enclave-sample/Makefile +++ b/product-mini/platforms/linux-sgx/enclave-sample/Makefile @@ -6,6 +6,7 @@ SGX_SDK ?= /opt/intel/sgxsdk SGX_MODE ?= SIM SGX_ARCH ?= x64 +SGX_DEBUG ?= 0 ifeq ($(shell getconf LONG_BIT), 32) SGX_ARCH := x86 @@ -73,7 +74,7 @@ endif App_Cpp_Objects := $(App_Cpp_Files:.cpp=.o) -App_Name := app +App_Name := iwasm ######## Enclave Settings ######## @@ -89,15 +90,20 @@ Crypto_Library_Name := sgx_tcrypto WAMR_ROOT := $(CURDIR)/../../../../ Enclave_Cpp_Files := Enclave/Enclave.cpp + Enclave_Include_Paths := -IEnclave -I$(WAMR_ROOT)/core/iwasm/include \ - -I$(SGX_SDK)/include -I$(SGX_SDK)/include/tlibc -I$(SGX_SDK)/include/stlport + -I$(WAMR_ROOT)/core/shared/utils \ + -I$(WAMR_ROOT)/core/shared/platform/linux-sgx \ + -I$(SGX_SDK)/include \ + -I$(SGX_SDK)/include/tlibc \ + -I$(SGX_SDK)/include/stlport Enclave_C_Flags := $(SGX_COMMON_CFLAGS) -nostdinc -fvisibility=hidden -fpie -fstack-protector $(Enclave_Include_Paths) Enclave_Cpp_Flags := $(Enclave_C_Flags) -std=c++03 -nostdinc++ Enclave_Link_Flags := $(SGX_COMMON_CFLAGS) -Wl,--no-undefined -nostdlib -nodefaultlibs -nostartfiles -L$(SGX_LIBRARY_PATH) \ -Wl,--whole-archive -l$(Trts_Library_Name) -Wl,--no-whole-archive \ libvmlib.a \ - -Wl,--start-group -lsgx_tstdc -lsgx_tcxx -l$(Crypto_Library_Name) -l$(Service_Library_Name) -Wl,--end-group \ + -Wl,--start-group -lsgx_tstdc -lsgx_tcxx -lsgx_pthread -l$(Crypto_Library_Name) -l$(Service_Library_Name) -Wl,--end-group \ -Wl,-Bstatic -Wl,-Bsymbolic -Wl,--no-undefined \ -Wl,-pie,-eenclave_entry -Wl,--export-dynamic \ -Wl,--defsym,__ImageBase=0 @@ -140,7 +146,7 @@ endif ######## App Objects ######## App/Enclave_u.c: $(SGX_EDGER8R) Enclave/Enclave.edl - @cd App && $(SGX_EDGER8R) --untrusted ../Enclave/Enclave.edl --search-path ../Enclave --search-path $(SGX_SDK)/include + @cd App && $(SGX_EDGER8R) --untrusted ../Enclave/Enclave.edl --search-path ../Enclave --search-path $(SGX_SDK)/include --search-path $(WAMR_ROOT)/core/shared/platform/linux-sgx @echo "GEN => $@" App/Enclave_u.o: App/Enclave_u.c @@ -159,7 +165,7 @@ $(App_Name): App/Enclave_u.o $(App_Cpp_Objects) ######## Enclave Objects ######## Enclave/Enclave_t.c: $(SGX_EDGER8R) Enclave/Enclave.edl - @cd Enclave && $(SGX_EDGER8R) --trusted ../Enclave/Enclave.edl --search-path ../Enclave --search-path $(SGX_SDK)/include + @cd Enclave && $(SGX_EDGER8R) --trusted ../Enclave/Enclave.edl --search-path ../Enclave --search-path $(SGX_SDK)/include --search-path $(WAMR_ROOT)/core/shared/platform/linux-sgx @echo "GEN => $@" Enclave/Enclave_t.o: Enclave/Enclave_t.c @@ -185,4 +191,4 @@ $(Signed_Enclave_Name): $(Enclave_Name) .PHONY: clean clean: - @rm -f $(App_Name) $(Enclave_Name) $(Signed_Enclave_Name) $(App_Cpp_Objects) App/Enclave_u.* $(Enclave_Cpp_Objects) Enclave/Enclave_t.* + @rm -f $(App_Name) $(Enclave_Name) $(Signed_Enclave_Name) $(App_Cpp_Objects) App/Enclave_u.* $(Enclave_Cpp_Objects) Enclave/Enclave_t.* libvmlib.a From 93ca9d8c62af3f85e1da9c3f2101be6826747917 Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Thu, 30 Jul 2020 10:18:55 +0800 Subject: [PATCH 038/207] Disable memory shrink opt when memory.size opcode is found (#323) --- core/iwasm/interpreter/wasm_loader.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index b1bbd1e4d..67ad75bc0 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -6127,6 +6127,8 @@ handle_op_block_and_loop: goto fail; } PUSH_I32(); + + module->possible_memory_grow = true; break; case WASM_OP_MEMORY_GROW: From cc05f8fb1ca83da9d643cbe4d374c1ef3eb4e345 Mon Sep 17 00:00:00 2001 From: dpinthinker Date: Fri, 31 Jul 2020 20:54:03 +0800 Subject: [PATCH 039/207] Use quicksort to sort native_symbols (#324) --- core/iwasm/common/wasm_native.c | 79 ++++++++++++++++++++++++++++++++- 1 file changed, 78 insertions(+), 1 deletion(-) diff --git a/core/iwasm/common/wasm_native.c b/core/iwasm/common/wasm_native.c index fcf52de08..bbec48648 100644 --- a/core/iwasm/common/wasm_native.c +++ b/core/iwasm/common/wasm_native.c @@ -7,6 +7,12 @@ #include "wasm_runtime_common.h" #include "bh_log.h" +#define ENABLE_QUICKSORT 1 +#define ENABLE_SORT_DEBUG 0 + +#if ENABLE_SORT_DEBUG != 0 +#include +#endif static NativeSymbolsList g_native_symbols_list = NULL; static NativeSymbolsList g_native_symbols_list_end = NULL; @@ -103,6 +109,7 @@ check_symbol_signature(const WASMType *type, const char *signature) return true; } +#if ENABLE_QUICKSORT == 0 static void sort_symbol_ptr(NativeSymbol *native_symbols, uint32 n_native_symbols) { @@ -120,6 +127,56 @@ sort_symbol_ptr(NativeSymbol *native_symbols, uint32 n_native_symbols) } } } +#else +static void +swap_symbol(NativeSymbol* left, NativeSymbol* right) +{ + NativeSymbol temp = *left; + *left = *right; + *right = temp; +} + +static void +quick_sort_symbols(NativeSymbol* native_symbols, int left, int right) +{ + NativeSymbol base_symbol; + int pin_left = left; + int pin_right = right; + + if (left >= right) { + return; + } + + base_symbol = native_symbols[left]; + while (left < right) { + while (left < right + && strcmp(native_symbols[right].symbol, + base_symbol.symbol) > 0) { + right--; + } + + if (left < right) { + swap_symbol(&native_symbols[left], &native_symbols[right]); + left++; + } + + while (left < right + && strcmp(native_symbols[left].symbol, + base_symbol.symbol) < 0) { + left++; + } + + if (left < right) { + swap_symbol(&native_symbols[left], &native_symbols[right]); + right--; + } + } + native_symbols[left] = base_symbol; + + quick_sort_symbols(native_symbols, pin_left, left - 1); + quick_sort_symbols(native_symbols, left + 1, pin_right); +} +#endif /* end of ENABLE_QUICKSORT */ static void * lookup_symbol(NativeSymbol *native_symbols, uint32 n_native_symbols, @@ -205,6 +262,11 @@ register_natives(const char *module_name, bool call_conv_raw) { NativeSymbolsNode *node; +#if ENABLE_SORT_DEBUG != 0 + struct timeval start; + struct timeval end; + unsigned long timer; +#endif if (!(node = wasm_runtime_malloc(sizeof(NativeSymbolsNode)))) return false; @@ -223,7 +285,23 @@ register_natives(const char *module_name, g_native_symbols_list = g_native_symbols_list_end = node; } +#if ENABLE_SORT_DEBUG != 0 + gettimeofday(&start, NULL); +#endif + +#if ENABLE_QUICKSORT == 0 sort_symbol_ptr(native_symbols, n_native_symbols); +#else + quick_sort_symbols(native_symbols, 0, (int)(n_native_symbols - 1)); +#endif + +#if ENABLE_SORT_DEBUG != 0 + gettimeofday(&end, NULL); + timer = 1000000 * (end.tv_sec - start.tv_sec) + + (end.tv_usec - start.tv_usec); + LOG_ERROR("module_name: %s, nums: %d, sorted used: %ld us", + module_name, n_native_symbols, timer); +#endif return true; } @@ -321,4 +399,3 @@ wasm_native_destroy() g_native_symbols_list = g_native_symbols_list_end = NULL; } - From 29e45e15274ac6640b3383f01260c285123814bd Mon Sep 17 00:00:00 2001 From: Xu Jun <693788454@qq.com> Date: Mon, 3 Aug 2020 11:30:26 +0800 Subject: [PATCH 040/207] implement atomic opcode in AOT/JIT (#329) --- .clang-format | 2 +- .gitignore | 5 +- core/iwasm/aot/aot_reloc.h | 42 +- core/iwasm/aot/aot_runtime.c | 3 + core/iwasm/aot/aot_runtime.h | 1 + core/iwasm/aot/arch/aot_reloc_arm.c | 2 +- core/iwasm/aot/arch/aot_reloc_thumb.c | 2 +- core/iwasm/aot/arch/aot_reloc_x86_32.c | 2 +- core/iwasm/aot/arch/aot_reloc_xtensa.c | 2 +- core/iwasm/common/wasm_native.c | 5 + core/iwasm/common/wasm_shared_memory.c | 299 ++++++++++ core/iwasm/common/wasm_shared_memory.h | 7 + core/iwasm/compilation/aot_compiler.c | 187 ++++++- core/iwasm/compilation/aot_emit_exception.c | 3 +- core/iwasm/compilation/aot_emit_memory.c | 523 ++++++++++++++++-- core/iwasm/compilation/aot_emit_memory.h | 38 +- core/iwasm/interpreter/wasm_loader.c | 194 ++++++- core/iwasm/interpreter/wasm_mini_loader.c | 149 +++++ core/iwasm/interpreter/wasm_opcode.h | 80 +++ .../enclave-sample/Enclave/test_wasm.h | 59 -- 20 files changed, 1447 insertions(+), 158 deletions(-) delete mode 100644 product-mini/platforms/linux-sgx/enclave-sample/Enclave/test_wasm.h diff --git a/.clang-format b/.clang-format index f1f14f519..aa4cde60a 100644 --- a/.clang-format +++ b/.clang-format @@ -47,7 +47,7 @@ BraceWrapping: AfterCaseLabel: false AfterClass: true AfterControlStatement: false - AfterEnum: true + AfterEnum: false AfterFunction: true AfterNamespace: false AfterObjCDeclaration: false diff --git a/.gitignore b/.gitignore index ef08be476..cf9f70360 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,6 @@ .vscode **/*build/ -core/deps/lv_drivers -core/deps/llvm -core/deps/lvgl -core/deps/tlsf +core/deps/** core/shared/mem-alloc/tlsf core/app-framework/wgl diff --git a/core/iwasm/aot/aot_reloc.h b/core/iwasm/aot/aot_reloc.h index 198880850..bd6391c07 100644 --- a/core/iwasm/aot/aot_reloc.h +++ b/core/iwasm/aot/aot_reloc.h @@ -13,6 +13,22 @@ typedef struct { #define REG_SYM(symbol) { #symbol, (void*)symbol } #if WASM_ENABLE_BULK_MEMORY != 0 +#define REG_BULK_MEMORY_SYM() \ + REG_SYM(aot_memory_init), \ + REG_SYM(aot_data_drop), +#else +#define REG_BULK_MEMORY_SYM() +#endif + +#if WASM_ENABLE_SHARED_MEMORY != 0 +#include "wasm_shared_memory.h" +#define REG_ATOMIC_WAIT_SYM() \ + REG_SYM(wasm_runtime_atomic_wait), \ + REG_SYM(wasm_runtime_atomic_notify), +#else +#define REG_ATOMIC_WAIT_SYM() +#endif + #define REG_COMMON_SYMBOLS \ REG_SYM(aot_set_exception_with_id), \ REG_SYM(aot_invoke_native), \ @@ -31,30 +47,8 @@ typedef struct { REG_SYM(truncf), \ REG_SYM(rint), \ REG_SYM(rintf), \ - REG_SYM(memset), \ - REG_SYM(memmove), \ - REG_SYM(aot_memory_init), \ - REG_SYM(aot_data_drop) -#else -#define REG_COMMON_SYMBOLS \ - REG_SYM(aot_set_exception_with_id), \ - REG_SYM(aot_invoke_native), \ - REG_SYM(aot_call_indirect), \ - REG_SYM(wasm_runtime_enlarge_memory), \ - REG_SYM(wasm_runtime_set_exception), \ - REG_SYM(fmin), \ - REG_SYM(fminf), \ - REG_SYM(fmax), \ - REG_SYM(fmaxf), \ - REG_SYM(ceil), \ - REG_SYM(ceilf), \ - REG_SYM(floor), \ - REG_SYM(floorf), \ - REG_SYM(trunc), \ - REG_SYM(truncf), \ - REG_SYM(rint), \ - REG_SYM(rintf) -#endif + REG_BULK_MEMORY_SYM() \ + REG_ATOMIC_WAIT_SYM() #define CHECK_RELOC_OFFSET(data_size) do { \ if (!check_reloc_offset(target_section_size, reloc_offset, data_size, \ diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index d3fe3f690..7be1a234e 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -1124,6 +1124,9 @@ aot_set_exception_with_id(AOTModuleInstance *module_inst, case EXCE_NATIVE_STACK_OVERFLOW: aot_set_exception(module_inst, "native stack overflow"); break; + case EXCE_UNALIGNED_ATOMIC: + aot_set_exception(module_inst, "unaligned atomic"); + break; default: break; } diff --git a/core/iwasm/aot/aot_runtime.h b/core/iwasm/aot/aot_runtime.h index 0678a701c..95b54a46e 100644 --- a/core/iwasm/aot/aot_runtime.h +++ b/core/iwasm/aot/aot_runtime.h @@ -31,6 +31,7 @@ typedef enum AOTExceptionID { EXCE_UNINITIALIZED_ELEMENT, EXCE_CALL_UNLINKED_IMPORT_FUNC, EXCE_NATIVE_STACK_OVERFLOW, + EXCE_UNALIGNED_ATOMIC, EXCE_NUM, } AOTExceptionID; diff --git a/core/iwasm/aot/arch/aot_reloc_arm.c b/core/iwasm/aot/arch/aot_reloc_arm.c index c73f9324a..a61613c2b 100644 --- a/core/iwasm/aot/arch/aot_reloc_arm.c +++ b/core/iwasm/aot/arch/aot_reloc_arm.c @@ -56,7 +56,7 @@ void __aeabi_f2iz(); void __aeabi_f2d(); static SymbolMap target_sym_map[] = { - REG_COMMON_SYMBOLS, + REG_COMMON_SYMBOLS /* compiler-rt symbols that come from compiler(e.g. gcc) */ REG_SYM(__divdi3), REG_SYM(__udivdi3), diff --git a/core/iwasm/aot/arch/aot_reloc_thumb.c b/core/iwasm/aot/arch/aot_reloc_thumb.c index 134f7abe3..316927b5e 100644 --- a/core/iwasm/aot/arch/aot_reloc_thumb.c +++ b/core/iwasm/aot/arch/aot_reloc_thumb.c @@ -55,7 +55,7 @@ void __aeabi_f2iz(); void __aeabi_f2d(); static SymbolMap target_sym_map[] = { - REG_COMMON_SYMBOLS, + REG_COMMON_SYMBOLS /* compiler-rt symbols that come from compiler(e.g. gcc) */ REG_SYM(__divdi3), REG_SYM(__udivdi3), diff --git a/core/iwasm/aot/arch/aot_reloc_x86_32.c b/core/iwasm/aot/arch/aot_reloc_x86_32.c index 20e82b3e2..a1424dae9 100644 --- a/core/iwasm/aot/arch/aot_reloc_x86_32.c +++ b/core/iwasm/aot/arch/aot_reloc_x86_32.c @@ -14,7 +14,7 @@ void __moddi3(); void __umoddi3(); static SymbolMap target_sym_map[] = { - REG_COMMON_SYMBOLS, + REG_COMMON_SYMBOLS /* compiler-rt symbols that come from compiler(e.g. gcc) */ REG_SYM(__divdi3), REG_SYM(__udivdi3), diff --git a/core/iwasm/aot/arch/aot_reloc_xtensa.c b/core/iwasm/aot/arch/aot_reloc_xtensa.c index ea04070f6..91499a173 100644 --- a/core/iwasm/aot/arch/aot_reloc_xtensa.c +++ b/core/iwasm/aot/arch/aot_reloc_xtensa.c @@ -22,7 +22,7 @@ void __modsi3(); void __divdi3(); static SymbolMap target_sym_map[] = { - REG_COMMON_SYMBOLS, + REG_COMMON_SYMBOLS /* API's for soft-float */ /* TODO: only register these symbols when Floating-Point Coprocessor diff --git a/core/iwasm/common/wasm_native.c b/core/iwasm/common/wasm_native.c index bbec48648..ed95b59b4 100644 --- a/core/iwasm/common/wasm_native.c +++ b/core/iwasm/common/wasm_native.c @@ -7,7 +7,12 @@ #include "wasm_runtime_common.h" #include "bh_log.h" +#if !defined(BH_PLATFORM_ZEPHYR) && !defined(BH_PLATFORM_ALIOS_THINGS) #define ENABLE_QUICKSORT 1 +#else +#define ENABLE_QUICKSORT 0 +#endif + #define ENABLE_SORT_DEBUG 0 #if ENABLE_SORT_DEBUG != 0 diff --git a/core/iwasm/common/wasm_shared_memory.c b/core/iwasm/common/wasm_shared_memory.c index 8d2f88db6..220406156 100644 --- a/core/iwasm/common/wasm_shared_memory.c +++ b/core/iwasm/common/wasm_shared_memory.c @@ -10,11 +10,50 @@ static bh_list shared_memory_list_head; static bh_list *const shared_memory_list = &shared_memory_list_head; static korp_mutex shared_memory_list_lock; +enum { + S_WAITING, S_NOTIFIED +}; + +typedef struct AtomicWaitInfo { + korp_mutex wait_list_lock; + bh_list wait_list_head; + bh_list *wait_list; +} AtomicWaitInfo; + +typedef struct AtomicWaitNode { + bh_list_link l; + uint8 status; + korp_mutex wait_lock; + korp_cond wait_cond; +} AtomicWaitNode; + +/* Atomic wait map */ +static HashMap *wait_map; + +static uint32 +wait_address_hash(void *address); + +static bool +wait_address_equal(void *h1, void *h2); + +static void +destroy_wait_info(void *wait_info); + bool wasm_shared_memory_init() { if (os_mutex_init(&shared_memory_list_lock) != 0) return false; + /* wait map not exists, create new map */ + if (!(wait_map = + bh_hash_map_create(32, true, + (HashFunc)wait_address_hash, + (KeyEqualFunc)wait_address_equal, + NULL, destroy_wait_info))) { + os_mutex_destroy(&shared_memory_list_lock); + return false; + } + return true; } @@ -22,6 +61,9 @@ void wasm_shared_memory_destroy() { os_mutex_destroy(&shared_memory_list_lock); + if (wait_map) { + bh_hash_map_destroy(wait_map); + } } static WASMSharedMemNode* @@ -118,3 +160,260 @@ shared_memory_set_memory_inst(WASMModuleCommon *module, (void)ret; return node; } + +/* Atomics wait && notify APIs */ +static uint32 +wait_address_hash(void *address) +{ + return (uint32)(uintptr_t)address; +} + +static bool +wait_address_equal(void *h1, void *h2) +{ + return h1 == h2 ? true : false; +} + +static bool +is_wait_node_exists(bh_list *wait_list, AtomicWaitNode *node) +{ + AtomicWaitNode *curr; + curr = bh_list_first_elem(wait_list); + + while (curr) { + if (curr == node) { + return true; + } + curr = bh_list_elem_next(curr); + } + + return false; +} + +static uint32 +notify_wait_list(bh_list *wait_list, uint32 count) +{ + AtomicWaitNode *node, *next; + uint32 i, notify_count = count; + + if ((count == UINT32_MAX) || (count > wait_list->len)) + notify_count = wait_list->len; + + node = bh_list_first_elem(wait_list); + + for (i = 0; i < count; i++) { + bh_assert(node); + next = bh_list_elem_next(node); + + node->status = S_NOTIFIED; + /* wakeup */ + os_cond_signal(&node->wait_cond); + + node = next; + } + + return notify_count; +} + +static AtomicWaitInfo * +acquire_wait_info(void *address, bool create) +{ + AtomicWaitInfo *wait_info = NULL; + bh_list_status ret; + + wait_info = (AtomicWaitInfo *) + bh_hash_map_find(wait_map, address); + + if (!create) + return wait_info; + + /* No wait info on this address, create new info */ + if (!wait_info) { + if (!(wait_info = + (AtomicWaitInfo *)wasm_runtime_malloc(sizeof(AtomicWaitInfo)))) + return NULL; + memset(wait_info, 0, sizeof(AtomicWaitInfo)); + + /* init wait list */ + wait_info->wait_list = &wait_info->wait_list_head; + ret = bh_list_init(wait_info->wait_list); + bh_assert(ret == BH_LIST_SUCCESS); + + /* init wait list lock */ + if (0 != os_mutex_init(&wait_info->wait_list_lock)) { + wasm_runtime_free(wait_info); + return NULL; + } + + if (!bh_hash_map_insert(wait_map, address, + (void *)wait_info)) { + os_mutex_destroy(&wait_info->wait_list_lock); + wasm_runtime_free(wait_info); + return NULL; + } + } + + bh_assert(wait_info); + (void)ret; + return wait_info; +} + +static void +destroy_wait_info(void *wait_info) +{ + AtomicWaitNode *node, *next; + + if (wait_info) { + + node = bh_list_first_elem(((AtomicWaitInfo *)wait_info)->wait_list); + + while (node) { + next = bh_list_elem_next(node); + os_mutex_destroy(&node->wait_lock); + os_cond_destroy(&node->wait_cond); + wasm_runtime_free(node); + node = next; + } + + os_mutex_destroy(&((AtomicWaitInfo *)wait_info)->wait_list_lock); + wasm_runtime_free(wait_info); + } +} + +static void +release_wait_info(HashMap *wait_map, + AtomicWaitInfo *wait_info, void *address) +{ + if (wait_info->wait_list->len == 0) { + bh_hash_map_remove(wait_map, address, NULL, NULL); + destroy_wait_info(wait_info); + } +} + +uint32 +wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address, + uint64 expect, int64 timeout, bool wait64) +{ + AtomicWaitInfo *wait_info; + AtomicWaitNode *wait_node; + bool check_ret, is_timeout; + +#if WASM_ENABLE_INTERP != 0 + if (module->module_type == Wasm_Module_Bytecode) { + WASMModuleInstance *module_inst = (WASMModuleInstance *)module; + /* Currently we have only one memory instance */ + if (!module_inst->memories[0]->is_shared) { + wasm_runtime_set_exception(module, "wait on unshared memory"); + return -1; + } + } +#endif +#if WASM_ENABLE_AOT != 0 + if (module->module_type == Wasm_Module_AoT) { + AOTModuleInstance *aot_inst = (AOTModuleInstance *)module; + AOTMemoryInstance *aot_memory = + ((AOTMemoryInstance **)aot_inst->memories.ptr)[0]; + /* Currently we have only one memory instance */ + if (!aot_memory->is_shared) { + wasm_runtime_set_exception(module, "wait on unshared memory"); + return -1; + } + } +#endif + + /* acquire the wait info, create new one if not exists */ + wait_info = acquire_wait_info(address, true); + + if (!wait_info) { + wasm_runtime_set_exception(module, "failed to acquire wait_info"); + return -1; + } + + os_mutex_lock(&wait_info->wait_list_lock); + + if ((!wait64 && *(uint32*)address != (uint32)expect) + || (wait64 && *(uint64*)address != expect)) { + os_mutex_unlock(&wait_info->wait_list_lock); + return 1; + } + else { + bh_list_status ret; + + if (!(wait_node = wasm_runtime_malloc(sizeof(AtomicWaitNode)))) { + wasm_runtime_set_exception(module, "failed to create wait node"); + os_mutex_unlock(&wait_info->wait_list_lock); + return -1; + } + memset(wait_node, 0, sizeof(AtomicWaitNode)); + + if (0 != os_mutex_init(&wait_node->wait_lock)) { + wasm_runtime_free(wait_node); + os_mutex_unlock(&wait_info->wait_list_lock); + return -1; + } + + if (0 != os_cond_init(&wait_node->wait_cond)) { + os_mutex_destroy(&wait_node->wait_lock); + wasm_runtime_free(wait_node); + os_mutex_unlock(&wait_info->wait_list_lock); + return -1; + } + + wait_node->status = S_WAITING; + + ret = bh_list_insert(wait_info->wait_list, wait_node); + bh_assert(ret == BH_LIST_SUCCESS); + (void)ret; + } + + os_mutex_unlock(&wait_info->wait_list_lock); + + /* condition wait start */ + os_mutex_lock(&wait_node->wait_lock); + + if (timeout < 0) + timeout = BHT_WAIT_FOREVER; + os_cond_reltimedwait(&wait_node->wait_cond, + &wait_node->wait_lock, timeout); + + os_mutex_unlock(&wait_node->wait_lock); + + /* Check the wait node status */ + os_mutex_lock(&wait_info->wait_list_lock); + check_ret = is_wait_node_exists(wait_info->wait_list, wait_node); + bh_assert(check_ret); + + is_timeout = wait_node->status == S_WAITING ? true : false; + + bh_list_remove(wait_info->wait_list, wait_node); + os_mutex_destroy(&wait_node->wait_lock); + os_cond_destroy(&wait_node->wait_cond); + wasm_runtime_free(wait_node); + os_mutex_unlock(&wait_info->wait_list_lock); + + release_wait_info(wait_map, wait_info, address); + + (void)check_ret; + return is_timeout ? 2 : 0; +} + +uint8 +wasm_runtime_atomic_notify(WASMModuleInstanceCommon *module, + void *address, uint32 count) +{ + uint32 notify_result; + AtomicWaitInfo *wait_info; + + /* Nobody wait on this address */ + wait_info = acquire_wait_info(address, false); + if (!wait_info) + return 0; + + os_mutex_lock(&wait_info->wait_list_lock); + notify_result = notify_wait_list(wait_info->wait_list, count); + os_mutex_unlock(&wait_info->wait_list_lock); + + release_wait_info(wait_map, wait_info, address); + + return notify_result; +} diff --git a/core/iwasm/common/wasm_shared_memory.h b/core/iwasm/common/wasm_shared_memory.h index 5a78b5fee..5e863c194 100644 --- a/core/iwasm/common/wasm_shared_memory.h +++ b/core/iwasm/common/wasm_shared_memory.h @@ -53,6 +53,13 @@ WASMSharedMemNode* shared_memory_set_memory_inst(WASMModuleCommon *module, WASMMemoryInstanceCommon *memory); +uint32 +wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address, + uint64 expect, int64 timeout, bool wait64); + +uint8 +wasm_runtime_atomic_notify(WASMModuleInstanceCommon *module, + void *address, uint32 count); #ifdef __cplusplus } diff --git a/core/iwasm/compilation/aot_compiler.c b/core/iwasm/compilation/aot_compiler.c index f0f2539c6..c631259ce 100644 --- a/core/iwasm/compilation/aot_compiler.c +++ b/core/iwasm/compilation/aot_compiler.c @@ -86,6 +86,38 @@ read_leb(const uint8 *buf, const uint8 *buf_end, res = (int64)res64; \ } while (0) +#define COMPILE_ATOMIC_RMW(OP, NAME) \ + case WASM_OP_ATOMIC_RMW_I32_##NAME: \ + bytes = 4; \ + op_type = VALUE_TYPE_I32; \ + goto OP_ATOMIC_##OP; \ + case WASM_OP_ATOMIC_RMW_I64_##NAME: \ + bytes = 8; \ + op_type = VALUE_TYPE_I64; \ + goto OP_ATOMIC_##OP; \ + case WASM_OP_ATOMIC_RMW_I32_##NAME##8_U: \ + bytes = 1; \ + op_type = VALUE_TYPE_I32; \ + goto OP_ATOMIC_##OP; \ + case WASM_OP_ATOMIC_RMW_I32_##NAME##16_U: \ + bytes = 2; \ + op_type = VALUE_TYPE_I32; \ + goto OP_ATOMIC_##OP; \ + case WASM_OP_ATOMIC_RMW_I64_##NAME##8_U: \ + bytes = 1; \ + op_type = VALUE_TYPE_I64; \ + goto OP_ATOMIC_##OP; \ + case WASM_OP_ATOMIC_RMW_I64_##NAME##16_U: \ + bytes = 2; \ + op_type = VALUE_TYPE_I64; \ + goto OP_ATOMIC_##OP; \ + case WASM_OP_ATOMIC_RMW_I64_##NAME##32_U: \ + bytes = 4; \ + op_type = VALUE_TYPE_I64; \ +OP_ATOMIC_##OP: \ + bin_op = LLVMAtomicRMWBinOp##OP; \ + goto build_atomic_rmw; + static bool aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index) { @@ -286,7 +318,7 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index) read_leb_uint32(frame_ip, frame_ip_end, align); read_leb_uint32(frame_ip, frame_ip_end, offset); if (!aot_compile_op_i32_load(comp_ctx, func_ctx, align, offset, - bytes, sign)) + bytes, sign, false)) return false; break; @@ -312,7 +344,7 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index) read_leb_uint32(frame_ip, frame_ip_end, align); read_leb_uint32(frame_ip, frame_ip_end, offset); if (!aot_compile_op_i64_load(comp_ctx, func_ctx, align, offset, - bytes, sign)) + bytes, sign, false)) return false; break; @@ -341,7 +373,8 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index) op_i32_store: read_leb_uint32(frame_ip, frame_ip_end, align); read_leb_uint32(frame_ip, frame_ip_end, offset); - if (!aot_compile_op_i32_store(comp_ctx, func_ctx, align, offset, bytes)) + if (!aot_compile_op_i32_store(comp_ctx, func_ctx, align, + offset, bytes, false)) return false; break; @@ -359,7 +392,8 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index) op_i64_store: read_leb_uint32(frame_ip, frame_ip_end, align); read_leb_uint32(frame_ip, frame_ip_end, offset); - if (!aot_compile_op_i64_store(comp_ctx, func_ctx, align, offset, bytes)) + if (!aot_compile_op_i64_store(comp_ctx, func_ctx, align, + offset, bytes, false)) return false; break; @@ -810,7 +844,152 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index) default: break; } + break; } +#if WASM_ENABLE_SHARED_MEMORY != 0 + case WASM_OP_ATOMIC_PREFIX: + { + uint8 bin_op, op_type; + + if (frame_ip < frame_ip_end) { + opcode = *frame_ip++; + } + if (opcode != WASM_OP_ATOMIC_FENCE) { + read_leb_uint32(frame_ip, frame_ip_end, align); + read_leb_uint32(frame_ip, frame_ip_end, offset); + } + switch (opcode) { + case WASM_OP_ATOMIC_WAIT32: + if (!aot_compile_op_atomic_wait(comp_ctx, func_ctx, VALUE_TYPE_I32, + align, offset, 4)) + return false; + break; + case WASM_OP_ATOMIC_WAIT64: + if (!aot_compile_op_atomic_wait(comp_ctx, func_ctx, VALUE_TYPE_I64, + align, offset, 8)) + return false; + break; + case WASM_OP_ATOMIC_NOTIFY: + if (!aot_compiler_op_atomic_notify(comp_ctx, func_ctx, align, + offset, bytes)) + return false; + break; + case WASM_OP_ATOMIC_I32_LOAD: + bytes = 4; + goto op_atomic_i32_load; + case WASM_OP_ATOMIC_I32_LOAD8_U: + bytes = 1; + goto op_atomic_i32_load; + case WASM_OP_ATOMIC_I32_LOAD16_U: + bytes = 2; + op_atomic_i32_load: + if (!aot_compile_op_i32_load(comp_ctx, func_ctx, align, + offset, bytes, sign, true)) + return false; + break; + + case WASM_OP_ATOMIC_I64_LOAD: + bytes = 8; + goto op_atomic_i64_load; + case WASM_OP_ATOMIC_I64_LOAD8_U: + bytes = 1; + goto op_atomic_i64_load; + case WASM_OP_ATOMIC_I64_LOAD16_U: + bytes = 2; + goto op_atomic_i64_load; + case WASM_OP_ATOMIC_I64_LOAD32_U: + bytes = 4; + op_atomic_i64_load: + if (!aot_compile_op_i64_load(comp_ctx, func_ctx, align, + offset, bytes, sign, true)) + return false; + break; + + case WASM_OP_ATOMIC_I32_STORE: + bytes = 4; + goto op_atomic_i32_store; + case WASM_OP_ATOMIC_I32_STORE8: + bytes = 1; + goto op_atomic_i32_store; + case WASM_OP_ATOMIC_I32_STORE16: + bytes = 2; + op_atomic_i32_store: + if (!aot_compile_op_i32_store(comp_ctx, func_ctx, align, + offset, bytes, true)) + return false; + break; + + case WASM_OP_ATOMIC_I64_STORE: + bytes = 8; + goto op_atomic_i64_store; + case WASM_OP_ATOMIC_I64_STORE8: + bytes = 1; + goto op_atomic_i64_store; + case WASM_OP_ATOMIC_I64_STORE16: + bytes = 2; + goto op_atomic_i64_store; + case WASM_OP_ATOMIC_I64_STORE32: + bytes = 4; + op_atomic_i64_store: + if (!aot_compile_op_i64_store(comp_ctx, func_ctx, align, + offset, bytes, true)) + return false; + break; + + case WASM_OP_ATOMIC_RMW_I32_CMPXCHG: + bytes = 4; + op_type = VALUE_TYPE_I32; + goto op_atomic_cmpxchg; + case WASM_OP_ATOMIC_RMW_I64_CMPXCHG: + bytes = 8; + op_type = VALUE_TYPE_I64; + goto op_atomic_cmpxchg; + case WASM_OP_ATOMIC_RMW_I32_CMPXCHG8_U: + bytes = 1; + op_type = VALUE_TYPE_I32; + goto op_atomic_cmpxchg; + case WASM_OP_ATOMIC_RMW_I32_CMPXCHG16_U: + bytes = 2; + op_type = VALUE_TYPE_I32; + goto op_atomic_cmpxchg; + case WASM_OP_ATOMIC_RMW_I64_CMPXCHG8_U: + bytes = 1; + op_type = VALUE_TYPE_I64; + goto op_atomic_cmpxchg; + case WASM_OP_ATOMIC_RMW_I64_CMPXCHG16_U: + bytes = 2; + op_type = VALUE_TYPE_I64; + goto op_atomic_cmpxchg; + case WASM_OP_ATOMIC_RMW_I64_CMPXCHG32_U: + bytes = 4; + op_type = VALUE_TYPE_I64; + op_atomic_cmpxchg: + if (!aot_compile_op_atomic_cmpxchg(comp_ctx, func_ctx, + op_type, align, + offset, bytes)) + return false; + break; + + COMPILE_ATOMIC_RMW(Add, ADD); + COMPILE_ATOMIC_RMW(Sub, SUB); + COMPILE_ATOMIC_RMW(And, AND); + COMPILE_ATOMIC_RMW(Or, OR); + COMPILE_ATOMIC_RMW(Xor, XOR); + COMPILE_ATOMIC_RMW(Xchg, XCHG); + +build_atomic_rmw: + if (!aot_compile_op_atomic_rmw(comp_ctx, func_ctx, + bin_op, op_type, + align, offset, bytes)) + return false; + break; + + default: + break; + } + break; + } +#endif /* end of WASM_ENABLE_SHARED_MEMORY */ default: break; diff --git a/core/iwasm/compilation/aot_emit_exception.c b/core/iwasm/compilation/aot_emit_exception.c index 8c9e24b6c..62911189b 100644 --- a/core/iwasm/compilation/aot_emit_exception.c +++ b/core/iwasm/compilation/aot_emit_exception.c @@ -18,7 +18,8 @@ static char *exce_block_names[] = { "exce_undefined_element", /* EXCE_UNDEFINED_ELEMENT */ "exce_uninit_element", /* EXCE_UNINITIALIZED_ELEMENT */ "exce_call_unlinked", /* EXCE_CALL_UNLINKED_IMPORT_FUNC */ - "exce_native_stack_overflow" /* EXCE_NATIVE_STACK_OVERFLOW */ + "exce_native_stack_overflow", /* EXCE_NATIVE_STACK_OVERFLOW */ + "exce_unaligned_atomic" /* EXCE_UNALIGNED_ATOMIC */ }; bool diff --git a/core/iwasm/compilation/aot_emit_memory.c b/core/iwasm/compilation/aot_emit_memory.c index ff3922c8b..cf80e6300 100644 --- a/core/iwasm/compilation/aot_emit_memory.c +++ b/core/iwasm/compilation/aot_emit_memory.c @@ -205,7 +205,7 @@ fail: LLVMSetAlignment(value, 1); \ } while (0) -#define BUILD_TRUNC(data_type) do { \ +#define BUILD_TRUNC(value, data_type) do { \ if (!(value = LLVMBuildTrunc(comp_ctx->builder, value, \ data_type, "val_trunc"))){ \ aot_set_last_error("llvm build trunc failed."); \ @@ -238,9 +238,79 @@ fail: } \ } while (0) +#if WASM_ENABLE_SHARED_MEMORY != 0 +bool +check_memory_alignment(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, + LLVMValueRef addr, uint32 align) +{ + LLVMBasicBlockRef block_curr = LLVMGetInsertBlock(comp_ctx->builder); + LLVMBasicBlockRef check_align_succ; + LLVMValueRef align_mask = I32_CONST(((uint32)1 << align) - 1); + LLVMValueRef res; + + CHECK_LLVM_CONST(align_mask); + + /* Convert pointer to int */ + if (!(addr = LLVMBuildPtrToInt(comp_ctx->builder, addr, + I32_TYPE, "address"))) { + aot_set_last_error("llvm build ptr to int failed."); + goto fail; + } + + /* The memory address should be aligned */ + BUILD_OP(And, addr, align_mask, res, "and"); + BUILD_ICMP(LLVMIntNE, res, I32_ZERO, res, "cmp"); + + /* Add basic blocks */ + ADD_BASIC_BLOCK(check_align_succ, "check_align_succ"); + LLVMMoveBasicBlockAfter(check_align_succ, block_curr); + + if (!aot_emit_exception(comp_ctx, func_ctx, + EXCE_UNALIGNED_ATOMIC, + true, res, check_align_succ)) { + goto fail; + } + + SET_BUILD_POS(check_align_succ); + + return true; +fail: + return false; +} + +#define BUILD_ATOMIC_LOAD(align) do { \ + if (!(check_memory_alignment(comp_ctx, func_ctx, maddr, align))) { \ + goto fail; \ + } \ + if (!(value = LLVMBuildLoad(comp_ctx->builder, maddr, \ + "data"))) { \ + aot_set_last_error("llvm build load failed."); \ + goto fail; \ + } \ + LLVMSetAlignment(value, 1 << align); \ + LLVMSetVolatile(value, true); \ + LLVMSetOrdering(value, LLVMAtomicOrderingSequentiallyConsistent); \ + } while (0) + +#define BUILD_ATOMIC_STORE(align) do { \ + LLVMValueRef res; \ + if (!(check_memory_alignment(comp_ctx, func_ctx, maddr, align))) { \ + goto fail; \ + } \ + if (!(res = LLVMBuildStore(comp_ctx->builder, value, maddr))) { \ + aot_set_last_error("llvm build store failed."); \ + goto fail; \ + } \ + LLVMSetAlignment(res, 1 << align); \ + LLVMSetVolatile(res, true); \ + LLVMSetOrdering(res, LLVMAtomicOrderingSequentiallyConsistent); \ + } while (0) +#endif + bool aot_compile_op_i32_load(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, - uint32 align, uint32 offset, uint32 bytes, bool sign) + uint32 align, uint32 offset, uint32 bytes, + bool sign, bool atomic) { LLVMValueRef maddr, value = NULL; @@ -250,7 +320,12 @@ aot_compile_op_i32_load(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, switch (bytes) { case 4: BUILD_PTR_CAST(INT32_PTR_TYPE); - BUILD_LOAD(); +#if WASM_ENABLE_SHARED_MEMORY != 0 + if (atomic) + BUILD_ATOMIC_LOAD(align); + else +#endif + BUILD_LOAD(); break; case 2: case 1: @@ -258,11 +333,20 @@ aot_compile_op_i32_load(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, BUILD_PTR_CAST(INT16_PTR_TYPE); else BUILD_PTR_CAST(INT8_PTR_TYPE); - BUILD_LOAD(); - if (sign) - BUILD_SIGN_EXT(I32_TYPE); - else +#if WASM_ENABLE_SHARED_MEMORY != 0 + if (atomic) { + BUILD_ATOMIC_LOAD(align); BUILD_ZERO_EXT(I32_TYPE); + } + else +#endif + { + BUILD_LOAD(); + if (sign) + BUILD_SIGN_EXT(I32_TYPE); + else + BUILD_ZERO_EXT(I32_TYPE); + } break; default: bh_assert(0); @@ -277,7 +361,8 @@ fail: bool aot_compile_op_i64_load(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, - uint32 align, uint32 offset, uint32 bytes, bool sign) + uint32 align, uint32 offset, uint32 bytes, + bool sign, bool atomic) { LLVMValueRef maddr, value = NULL; @@ -287,7 +372,12 @@ aot_compile_op_i64_load(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, switch (bytes) { case 8: BUILD_PTR_CAST(INT64_PTR_TYPE); - BUILD_LOAD(); +#if WASM_ENABLE_SHARED_MEMORY != 0 + if (atomic) + BUILD_ATOMIC_LOAD(align); + else +#endif + BUILD_LOAD(); break; case 4: case 2: @@ -298,11 +388,20 @@ aot_compile_op_i64_load(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, BUILD_PTR_CAST(INT16_PTR_TYPE); else BUILD_PTR_CAST(INT8_PTR_TYPE); - BUILD_LOAD(); - if (sign) - BUILD_SIGN_EXT(I64_TYPE); - else +#if WASM_ENABLE_SHARED_MEMORY != 0 + if (atomic) { + BUILD_ATOMIC_LOAD(align); BUILD_ZERO_EXT(I64_TYPE); + } + else +#endif + { + BUILD_LOAD(); + if (sign) + BUILD_SIGN_EXT(I64_TYPE); + else + BUILD_ZERO_EXT(I64_TYPE); + } break; default: bh_assert(0); @@ -351,7 +450,7 @@ fail: bool aot_compile_op_i32_store(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, - uint32 align, uint32 offset, uint32 bytes) + uint32 align, uint32 offset, uint32 bytes, bool atomic) { LLVMValueRef maddr, value; @@ -366,18 +465,23 @@ aot_compile_op_i32_store(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, break; case 2: BUILD_PTR_CAST(INT16_PTR_TYPE); - BUILD_TRUNC(INT16_TYPE); + BUILD_TRUNC(value, INT16_TYPE); break; case 1: BUILD_PTR_CAST(INT8_PTR_TYPE); - BUILD_TRUNC(INT8_TYPE); + BUILD_TRUNC(value, INT8_TYPE); break; default: bh_assert(0); break; } - BUILD_STORE(); +#if WASM_ENABLE_SHARED_MEMORY != 0 + if (atomic) + BUILD_ATOMIC_STORE(align); + else +#endif + BUILD_STORE(); return true; fail: return false; @@ -385,7 +489,7 @@ fail: bool aot_compile_op_i64_store(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, - uint32 align, uint32 offset, uint32 bytes) + uint32 align, uint32 offset, uint32 bytes, bool atomic) { LLVMValueRef maddr, value; @@ -400,22 +504,27 @@ aot_compile_op_i64_store(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, break; case 4: BUILD_PTR_CAST(INT32_PTR_TYPE); - BUILD_TRUNC(I32_TYPE); + BUILD_TRUNC(value, I32_TYPE); break; case 2: BUILD_PTR_CAST(INT16_PTR_TYPE); - BUILD_TRUNC(INT16_TYPE); + BUILD_TRUNC(value, INT16_TYPE); break; case 1: BUILD_PTR_CAST(INT8_PTR_TYPE); - BUILD_TRUNC(INT8_TYPE); + BUILD_TRUNC(value, INT8_TYPE); break; default: bh_assert(0); break; } - BUILD_STORE(); +#if WASM_ENABLE_SHARED_MEMORY != 0 + if (atomic) + BUILD_ATOMIC_STORE(align); + else +#endif + BUILD_STORE(); return true; fail: return false; @@ -603,6 +712,36 @@ fail: return false; } +#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) + #if WASM_ENABLE_BULK_MEMORY != 0 static LLVMValueRef @@ -691,36 +830,6 @@ 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) @@ -810,6 +919,7 @@ aot_compile_op_data_drop(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, LLVMTypeRef param_types[2], ret_type, func_type, func_ptr_type; seg = I32_CONST(seg_index); + CHECK_LLVM_CONST(seg); param_types[0] = INT8_PTR_TYPE; param_types[1] = I32_TYPE; @@ -825,7 +935,10 @@ aot_compile_op_data_drop(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, aot_set_last_error("llvm build call failed."); return false; } + return true; +fail: + return false; } bool @@ -879,4 +992,308 @@ aot_compile_op_memory_fill(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) fail: return false; } -#endif /* WASM_ENABLE_BULK_MEMORY */ +#endif /* end of WASM_ENABLE_BULK_MEMORY */ + +#if WASM_ENABLE_SHARED_MEMORY != 0 +bool +aot_compile_op_atomic_rmw(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + uint8 atomic_op, uint8 op_type, + uint32 align, uint32 offset, + uint32 bytes) +{ + LLVMValueRef maddr, value, result; + + if (op_type == VALUE_TYPE_I32) + POP_I32(value); + else + POP_I64(value); + + if (!(maddr = check_memory_overflow(comp_ctx, func_ctx, offset, bytes))) + return false; + + if (!check_memory_alignment(comp_ctx, func_ctx, maddr, align)) + return false; + + switch (bytes) { + case 8: + BUILD_PTR_CAST(INT64_PTR_TYPE); + break; + case 4: + BUILD_PTR_CAST(INT32_PTR_TYPE); + if (op_type == VALUE_TYPE_I64) + BUILD_TRUNC(value, I32_TYPE); + break; + case 2: + BUILD_PTR_CAST(INT16_PTR_TYPE); + BUILD_TRUNC(value, INT16_TYPE); + break; + case 1: + BUILD_PTR_CAST(INT8_PTR_TYPE); + BUILD_TRUNC(value, INT8_TYPE); + break; + default: + bh_assert(0); + break; + } + + if (!(result = + LLVMBuildAtomicRMW(comp_ctx->builder, + atomic_op, maddr, value, + LLVMAtomicOrderingSequentiallyConsistent, false))) { + goto fail; + } + + LLVMSetVolatile(result, true); + + if (op_type == VALUE_TYPE_I32) { + if (!(result = LLVMBuildZExt(comp_ctx->builder, result, + I32_TYPE, "result_i32"))) { + goto fail; + } + PUSH_I32(result); + } + else { + if (!(result = LLVMBuildZExt(comp_ctx->builder, result, + I64_TYPE, "result_i64"))) { + goto fail; + } + PUSH_I64(result); + } + + return true; +fail: + return false; +} + +bool +aot_compile_op_atomic_cmpxchg(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + uint8 op_type, uint32 align, + uint32 offset, uint32 bytes) +{ + LLVMValueRef maddr, value, expect, result; + + if (op_type == VALUE_TYPE_I32) { + POP_I32(value); + POP_I32(expect); + } + else { + POP_I64(value); + POP_I64(expect); + } + + if (!(maddr = check_memory_overflow(comp_ctx, func_ctx, offset, bytes))) + return false; + + if (!check_memory_alignment(comp_ctx, func_ctx, maddr, align)) + return false; + + switch (bytes) { + case 8: + BUILD_PTR_CAST(INT64_PTR_TYPE); + break; + case 4: + BUILD_PTR_CAST(INT32_PTR_TYPE); + if (op_type == VALUE_TYPE_I64) { + BUILD_TRUNC(value, I32_TYPE); + BUILD_TRUNC(expect, I32_TYPE); + } + break; + case 2: + BUILD_PTR_CAST(INT16_PTR_TYPE); + BUILD_TRUNC(value, INT16_TYPE); + BUILD_TRUNC(expect, INT16_TYPE); + break; + case 1: + BUILD_PTR_CAST(INT8_PTR_TYPE); + BUILD_TRUNC(value, INT8_TYPE); + BUILD_TRUNC(expect, INT8_TYPE); + break; + default: + bh_assert(0); + break; + } + + if (!(result = + LLVMBuildAtomicCmpXchg(comp_ctx->builder, maddr, expect, value, + LLVMAtomicOrderingSequentiallyConsistent, + LLVMAtomicOrderingSequentiallyConsistent, + false))) { + goto fail; + } + + LLVMSetVolatile(result, true); + + /* CmpXchg return {i32, i1} structure, + we need to extrack the previous_value from the structure */ + if (!(result = + LLVMBuildExtractValue(comp_ctx->builder, + result, 0, "previous_value"))) { + goto fail; + } + + if (op_type == VALUE_TYPE_I32) { + if (!(result = LLVMBuildZExt(comp_ctx->builder, result, + I32_TYPE, "result_i32"))) { + goto fail; + } + PUSH_I32(result); + } + else { + if (!(result = LLVMBuildZExt(comp_ctx->builder, result, + I64_TYPE, "result_i64"))) { + goto fail; + } + PUSH_I64(result); + } + + return true; +fail: + return false; +} + +bool +aot_compile_op_atomic_wait(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, + uint8 op_type, uint32 align, + uint32 offset, uint32 bytes) +{ + LLVMValueRef maddr, value, timeout, expect, cmp; + LLVMValueRef param_values[5], ret_value, func, is_wait64; + LLVMTypeRef param_types[5], ret_type, func_type, func_ptr_type; + LLVMBasicBlockRef wait_fail, wait_success; + LLVMBasicBlockRef block_curr = LLVMGetInsertBlock(comp_ctx->builder); + AOTFuncType *aot_func_type = func_ctx->aot_func->func_type; + + POP_I64(timeout); + if (op_type == VALUE_TYPE_I32) { + POP_I32(expect); + is_wait64 = I8_CONST(false); + if (!(expect = + LLVMBuildZExt(comp_ctx->builder, expect, + I64_TYPE, "expect_i64"))) { + goto fail; + } + } + else { + POP_I64(expect); + is_wait64 = I8_CONST(true); + } + + CHECK_LLVM_CONST(is_wait64); + + if (!(maddr = check_memory_overflow(comp_ctx, func_ctx, offset, bytes))) + return false; + + if (!check_memory_alignment(comp_ctx, func_ctx, maddr, align)) + return false; + + param_types[0] = INT8_PTR_TYPE; + param_types[1] = INT8_PTR_TYPE; + param_types[2] = I64_TYPE; + param_types[3] = I64_TYPE; + param_types[4] = INT8_TYPE; + ret_type = I32_TYPE; + + GET_AOT_FUNCTION(wasm_runtime_atomic_wait, 5); + + /* Call function wasm_runtime_atomic_wait() */ + param_values[0] = func_ctx->aot_inst; + param_values[1] = maddr; + param_values[2] = expect; + param_values[3] = timeout; + param_values[4] = is_wait64; + if (!(ret_value = LLVMBuildCall(comp_ctx->builder, func, + param_values, 5, "call"))) { + aot_set_last_error("llvm build call failed."); + return false; + } + + BUILD_ICMP(LLVMIntSGT, ret_value, I32_ZERO, cmp, "atomic_wait_ret"); + + ADD_BASIC_BLOCK(wait_fail, "atomic_wait_fail"); + ADD_BASIC_BLOCK(wait_success, "wait_success"); + + LLVMMoveBasicBlockAfter(wait_fail, block_curr); + LLVMMoveBasicBlockAfter(wait_success, block_curr); + + if (!LLVMBuildCondBr(comp_ctx->builder, cmp, + wait_success, wait_fail)) { + aot_set_last_error("llvm build cond br failed."); + goto fail; + } + + /* If atomic wait failed, return this function + so the runtime can catch the exception */ + LLVMPositionBuilderAtEnd(comp_ctx->builder, wait_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, wait_success); + + PUSH_I32(ret_value); + + return true; +fail: + return false; +} + +bool +aot_compiler_op_atomic_notify(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + uint32 align, uint32 offset, uint32 bytes) +{ + LLVMValueRef maddr, value, count; + LLVMValueRef param_values[3], ret_value, func; + LLVMTypeRef param_types[3], ret_type, func_type, func_ptr_type; + + POP_I32(count); + + if (!(maddr = check_memory_overflow(comp_ctx, func_ctx, offset, bytes))) + return false; + + if (!check_memory_alignment(comp_ctx, func_ctx, maddr, align)) + return false; + + param_types[0] = INT8_PTR_TYPE; + param_types[1] = INT8_PTR_TYPE; + param_types[2] = I32_TYPE; + ret_type = I32_TYPE; + + GET_AOT_FUNCTION(wasm_runtime_atomic_notify, 3); + + /* Call function wasm_runtime_atomic_notify() */ + param_values[0] = func_ctx->aot_inst; + param_values[1] = maddr; + param_values[2] = count; + if (!(ret_value = LLVMBuildCall(comp_ctx->builder, func, + param_values, 3, "call"))) { + aot_set_last_error("llvm build call failed."); + return false; + } + + PUSH_I32(ret_value); + + return true; +fail: + return false; +} + +#endif /* end of WASM_ENABLE_SHARED_MEMORY */ diff --git a/core/iwasm/compilation/aot_emit_memory.h b/core/iwasm/compilation/aot_emit_memory.h index c2415ff92..82465ae37 100644 --- a/core/iwasm/compilation/aot_emit_memory.h +++ b/core/iwasm/compilation/aot_emit_memory.h @@ -7,6 +7,9 @@ #define _AOT_EMIT_MEMORY_H_ #include "aot_compiler.h" +#if WASM_ENABLE_SHARED_MEMORY != 0 +#include "wasm_shared_memory.h" +#endif #ifdef __cplusplus extern "C" { @@ -14,11 +17,13 @@ extern "C" { bool aot_compile_op_i32_load(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, - uint32 align, uint32 offset, uint32 bytes, bool sign); + uint32 align, uint32 offset, uint32 bytes, + bool sign, bool atomic); bool aot_compile_op_i64_load(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, - uint32 align, uint32 offset, uint32 bytes, bool sign); + uint32 align, uint32 offset, uint32 bytes, + bool sign, bool atomic); bool aot_compile_op_f32_load(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, @@ -30,11 +35,11 @@ aot_compile_op_f64_load(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, bool aot_compile_op_i32_store(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, - uint32 align, uint32 offset, uint32 bytes); + uint32 align, uint32 offset, uint32 bytes, bool atomic); bool aot_compile_op_i64_store(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, - uint32 align, uint32 offset, uint32 bytes); + uint32 align, uint32 offset, uint32 bytes, bool atomic); bool aot_compile_op_f32_store(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, @@ -66,6 +71,31 @@ bool aot_compile_op_memory_fill(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx); #endif +#if WASM_ENABLE_SHARED_MEMORY != 0 +bool +aot_compile_op_atomic_rmw(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + uint8 atomic_op, uint8 op_type, + uint32 align, uint32 offset, + uint32 bytes); + +bool +aot_compile_op_atomic_cmpxchg(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + uint8 op_type, uint32 align, + uint32 offset, uint32 bytes); + +bool +aot_compile_op_atomic_wait(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, + uint8 op_type, uint32 align, + uint32 offset, uint32 bytes); + +bool +aot_compiler_op_atomic_notify(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + uint32 align, uint32 offset, uint32 bytes); +#endif + #ifdef __cplusplus } /* end of extern "C" */ #endif diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index 67ad75bc0..fb12b4ae8 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -3307,13 +3307,28 @@ wasm_loader_find_block_addr(BlockAddr *block_addr_cache, default: if (error_buf) snprintf(error_buf, error_buf_size, - "WASM loader find block addr failed: " - "invalid opcode fc %02x.", opcode); + "WASM loader find block addr failed: " + "invalid opcode fc %02x.", opcode); return false; } break; } - +#if WASM_ENABLE_SHARED_MEMORY != 0 + case WASM_OP_ATOMIC_PREFIX: + { + /* atomic_op (1 u8) + memarg (2 u32_leb) */ + opcode = read_uint8(p); + if (opcode != WASM_OP_ATOMIC_FENCE) { + skip_leb_uint32(p, p_end); /* align */ + skip_leb_uint32(p, p_end); /* offset */ + } + else { + /* atomic.fence doesn't have memarg */ + p++; + } + break; + } +#endif default: if (error_buf) snprintf(error_buf, error_buf_size, @@ -4796,6 +4811,36 @@ check_memory_access_align(uint8 opcode, uint32 align, return true; } +#if WASM_ENABLE_SHARED_MEMORY != 0 +static bool +check_memory_align_equal(uint8 opcode, uint32 align, + char *error_buf, uint32 error_buf_size) +{ + uint8 wait_notify_aligns[] = {2, 2, 3}; + uint8 mem_access_aligns[] = { + 2, 3, 0, 1, 0, 1, 2, + }; + uint8 expect; + + bh_assert((opcode <= WASM_OP_ATOMIC_WAIT64) + || (opcode >= WASM_OP_ATOMIC_I32_LOAD + && opcode <= WASM_OP_ATOMIC_RMW_I64_CMPXCHG32_U)); + if (opcode <= WASM_OP_ATOMIC_WAIT64) { + expect = wait_notify_aligns[opcode - WASM_OP_ATOMIC_NOTIFY]; + } + else { + /* 7 opcodes in every group */ + expect = mem_access_aligns[(opcode - WASM_OP_ATOMIC_I32_LOAD) % 7]; + } + if (align != expect) { + set_error_buf(error_buf, error_buf_size, + "alignment isn't equal to natural"); + return false; + } + return true; +} +#endif /* end of WASM_ENABLE_SHARED_MEMORY */ + static bool is_value_type(uint8 type) { @@ -6535,6 +6580,147 @@ fail_data_cnt_sec_require: } break; } +#if WASM_ENABLE_SHARED_MEMORY != 0 + case WASM_OP_ATOMIC_PREFIX: + { + opcode = read_uint8(p); +#if WASM_ENABLE_FAST_INTERP != 0 + emit_byte(loader_ctx, opcode); +#endif + if (opcode != WASM_OP_ATOMIC_FENCE) { + CHECK_MEMORY(); + read_leb_uint32(p, p_end, align); /* align */ + read_leb_uint32(p, p_end, mem_offset); /* offset */ + if (!check_memory_align_equal(opcode, align, + error_buf, + error_buf_size)) { + goto fail; + } + } + switch (opcode) { + case WASM_OP_ATOMIC_NOTIFY: + POP2_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32); + break; + case WASM_OP_ATOMIC_WAIT32: + POP_I64(); + POP_I32(); + POP_I32(); + PUSH_I32(); + break; + case WASM_OP_ATOMIC_WAIT64: + POP_I64(); + POP_I64(); + POP_I32(); + PUSH_I32(); + break; + case WASM_OP_ATOMIC_FENCE: + /* reserved byte 0x00 */ + if (*p++ != 0x00) { + set_error_buf(error_buf, error_buf_size, + "WASM loader prepare bytecode failed: " + "zero flag expected"); + goto fail; + } + break; + case WASM_OP_ATOMIC_I32_LOAD: + case WASM_OP_ATOMIC_I32_LOAD8_U: + case WASM_OP_ATOMIC_I32_LOAD16_U: + POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32); + break; + case WASM_OP_ATOMIC_I32_STORE: + case WASM_OP_ATOMIC_I32_STORE8: + case WASM_OP_ATOMIC_I32_STORE16: + POP_I32(); + POP_I32(); + break; + case WASM_OP_ATOMIC_I64_LOAD: + case WASM_OP_ATOMIC_I64_LOAD8_U: + case WASM_OP_ATOMIC_I64_LOAD16_U: + case WASM_OP_ATOMIC_I64_LOAD32_U: + POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I64); + break; + case WASM_OP_ATOMIC_I64_STORE: + case WASM_OP_ATOMIC_I64_STORE8: + case WASM_OP_ATOMIC_I64_STORE16: + case WASM_OP_ATOMIC_I64_STORE32: + POP_I64(); + POP_I32(); + break; + case WASM_OP_ATOMIC_RMW_I32_ADD: + case WASM_OP_ATOMIC_RMW_I32_ADD8_U: + case WASM_OP_ATOMIC_RMW_I32_ADD16_U: + case WASM_OP_ATOMIC_RMW_I32_SUB: + case WASM_OP_ATOMIC_RMW_I32_SUB8_U: + case WASM_OP_ATOMIC_RMW_I32_SUB16_U: + case WASM_OP_ATOMIC_RMW_I32_AND: + case WASM_OP_ATOMIC_RMW_I32_AND8_U: + case WASM_OP_ATOMIC_RMW_I32_AND16_U: + case WASM_OP_ATOMIC_RMW_I32_OR: + case WASM_OP_ATOMIC_RMW_I32_OR8_U: + case WASM_OP_ATOMIC_RMW_I32_OR16_U: + case WASM_OP_ATOMIC_RMW_I32_XOR: + case WASM_OP_ATOMIC_RMW_I32_XOR8_U: + case WASM_OP_ATOMIC_RMW_I32_XOR16_U: + case WASM_OP_ATOMIC_RMW_I32_XCHG: + case WASM_OP_ATOMIC_RMW_I32_XCHG8_U: + case WASM_OP_ATOMIC_RMW_I32_XCHG16_U: + POP2_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32); + break; + case WASM_OP_ATOMIC_RMW_I64_ADD: + case WASM_OP_ATOMIC_RMW_I64_ADD8_U: + case WASM_OP_ATOMIC_RMW_I64_ADD16_U: + case WASM_OP_ATOMIC_RMW_I64_ADD32_U: + case WASM_OP_ATOMIC_RMW_I64_SUB: + case WASM_OP_ATOMIC_RMW_I64_SUB8_U: + case WASM_OP_ATOMIC_RMW_I64_SUB16_U: + case WASM_OP_ATOMIC_RMW_I64_SUB32_U: + case WASM_OP_ATOMIC_RMW_I64_AND: + case WASM_OP_ATOMIC_RMW_I64_AND8_U: + case WASM_OP_ATOMIC_RMW_I64_AND16_U: + case WASM_OP_ATOMIC_RMW_I64_AND32_U: + case WASM_OP_ATOMIC_RMW_I64_OR: + case WASM_OP_ATOMIC_RMW_I64_OR8_U: + case WASM_OP_ATOMIC_RMW_I64_OR16_U: + case WASM_OP_ATOMIC_RMW_I64_OR32_U: + case WASM_OP_ATOMIC_RMW_I64_XOR: + case WASM_OP_ATOMIC_RMW_I64_XOR8_U: + case WASM_OP_ATOMIC_RMW_I64_XOR16_U: + case WASM_OP_ATOMIC_RMW_I64_XOR32_U: + case WASM_OP_ATOMIC_RMW_I64_XCHG: + case WASM_OP_ATOMIC_RMW_I64_XCHG8_U: + case WASM_OP_ATOMIC_RMW_I64_XCHG16_U: + case WASM_OP_ATOMIC_RMW_I64_XCHG32_U: + POP_I64(); + POP_I32(); + PUSH_I64(); + break; + case WASM_OP_ATOMIC_RMW_I32_CMPXCHG: + case WASM_OP_ATOMIC_RMW_I32_CMPXCHG8_U: + case WASM_OP_ATOMIC_RMW_I32_CMPXCHG16_U: + POP_I32(); + POP_I32(); + POP_I32(); + PUSH_I32(); + break; + case WASM_OP_ATOMIC_RMW_I64_CMPXCHG: + case WASM_OP_ATOMIC_RMW_I64_CMPXCHG8_U: + case WASM_OP_ATOMIC_RMW_I64_CMPXCHG16_U: + case WASM_OP_ATOMIC_RMW_I64_CMPXCHG32_U: + POP_I64(); + POP_I64(); + POP_I32(); + PUSH_I64(); + break; + default: + if (error_buf != NULL) + snprintf(error_buf, error_buf_size, + "WASM module load failed: " + "invalid opcode 0xfe %02x.", opcode); + goto fail; + } + break; + } +#endif /* end of WASM_ENABLE_SHARED_MEMORY */ default: if (error_buf != NULL) snprintf(error_buf, error_buf_size, @@ -6566,7 +6752,7 @@ fail_data_cnt_sec_require: goto fail; } func_const_end = func->consts + func->const_cell_num * 4; - // reverse the const buf + /* reverse the const buf */ for (int i = loader_ctx->num_const - 1; i >= 0; i--) { Const *c = (Const*)(loader_ctx->const_buf + i * sizeof(Const)); if (c->value_type == VALUE_TYPE_F64 diff --git a/core/iwasm/interpreter/wasm_mini_loader.c b/core/iwasm/interpreter/wasm_mini_loader.c index 2e1152428..bfa835afc 100644 --- a/core/iwasm/interpreter/wasm_mini_loader.c +++ b/core/iwasm/interpreter/wasm_mini_loader.c @@ -2331,6 +2331,23 @@ wasm_loader_find_block_addr(BlockAddr *block_addr_cache, break; } +#if WASM_ENABLE_SHARED_MEMORY != 0 + case WASM_OP_ATOMIC_PREFIX: + { + /* atomic_op (1 u8) + memarg (2 u32_leb) */ + opcode = read_uint8(p); + if (opcode != WASM_OP_ATOMIC_FENCE) { + skip_leb_uint32(p, p_end); /* align */ + skip_leb_uint32(p, p_end); /* offset */ + } + else { + /* atomic.fence doesn't have memarg */ + p++; + } + break; + } +#endif + default: bh_assert(0); break; @@ -4953,6 +4970,8 @@ handle_op_block_and_loop: bh_assert(*p == 0x00); p++; PUSH_I32(); + + module->possible_memory_grow = true; break; case WASM_OP_MEMORY_GROW: @@ -5318,6 +5337,136 @@ handle_op_block_and_loop: break; } +#if WASM_ENABLE_SHARED_MEMORY != 0 + case WASM_OP_ATOMIC_PREFIX: + { + opcode = read_uint8(p); +#if WASM_ENABLE_FAST_INTERP != 0 + emit_byte(loader_ctx, opcode); +#endif + if (opcode != WASM_OP_ATOMIC_FENCE) { + CHECK_MEMORY(); + read_leb_uint32(p, p_end, align); /* align */ + read_leb_uint32(p, p_end, mem_offset); /* offset */ + } + switch (opcode) { + case WASM_OP_ATOMIC_NOTIFY: + POP2_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32); + break; + case WASM_OP_ATOMIC_WAIT32: + POP_I64(); + POP_I32(); + POP_I32(); + PUSH_I32(); + break; + case WASM_OP_ATOMIC_WAIT64: + POP_I64(); + POP_I64(); + POP_I32(); + PUSH_I32(); + break; + case WASM_OP_ATOMIC_FENCE: + /* reserved byte 0x00 */ + bh_assert(*p == 0x00); + p++; + break; + case WASM_OP_ATOMIC_I32_LOAD: + case WASM_OP_ATOMIC_I32_LOAD8_U: + case WASM_OP_ATOMIC_I32_LOAD16_U: + POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32); + break; + case WASM_OP_ATOMIC_I32_STORE: + case WASM_OP_ATOMIC_I32_STORE8: + case WASM_OP_ATOMIC_I32_STORE16: + POP_I32(); + POP_I32(); + break; + case WASM_OP_ATOMIC_I64_LOAD: + case WASM_OP_ATOMIC_I64_LOAD8_U: + case WASM_OP_ATOMIC_I64_LOAD16_U: + case WASM_OP_ATOMIC_I64_LOAD32_U: + POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I64); + break; + case WASM_OP_ATOMIC_I64_STORE: + case WASM_OP_ATOMIC_I64_STORE8: + case WASM_OP_ATOMIC_I64_STORE16: + case WASM_OP_ATOMIC_I64_STORE32: + POP_I64(); + POP_I32(); + break; + case WASM_OP_ATOMIC_RMW_I32_ADD: + case WASM_OP_ATOMIC_RMW_I32_ADD8_U: + case WASM_OP_ATOMIC_RMW_I32_ADD16_U: + case WASM_OP_ATOMIC_RMW_I32_SUB: + case WASM_OP_ATOMIC_RMW_I32_SUB8_U: + case WASM_OP_ATOMIC_RMW_I32_SUB16_U: + case WASM_OP_ATOMIC_RMW_I32_AND: + case WASM_OP_ATOMIC_RMW_I32_AND8_U: + case WASM_OP_ATOMIC_RMW_I32_AND16_U: + case WASM_OP_ATOMIC_RMW_I32_OR: + case WASM_OP_ATOMIC_RMW_I32_OR8_U: + case WASM_OP_ATOMIC_RMW_I32_OR16_U: + case WASM_OP_ATOMIC_RMW_I32_XOR: + case WASM_OP_ATOMIC_RMW_I32_XOR8_U: + case WASM_OP_ATOMIC_RMW_I32_XOR16_U: + case WASM_OP_ATOMIC_RMW_I32_XCHG: + case WASM_OP_ATOMIC_RMW_I32_XCHG8_U: + case WASM_OP_ATOMIC_RMW_I32_XCHG16_U: + POP2_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32); + break; + case WASM_OP_ATOMIC_RMW_I64_ADD: + case WASM_OP_ATOMIC_RMW_I64_ADD8_U: + case WASM_OP_ATOMIC_RMW_I64_ADD16_U: + case WASM_OP_ATOMIC_RMW_I64_ADD32_U: + case WASM_OP_ATOMIC_RMW_I64_SUB: + case WASM_OP_ATOMIC_RMW_I64_SUB8_U: + case WASM_OP_ATOMIC_RMW_I64_SUB16_U: + case WASM_OP_ATOMIC_RMW_I64_SUB32_U: + case WASM_OP_ATOMIC_RMW_I64_AND: + case WASM_OP_ATOMIC_RMW_I64_AND8_U: + case WASM_OP_ATOMIC_RMW_I64_AND16_U: + case WASM_OP_ATOMIC_RMW_I64_AND32_U: + case WASM_OP_ATOMIC_RMW_I64_OR: + case WASM_OP_ATOMIC_RMW_I64_OR8_U: + case WASM_OP_ATOMIC_RMW_I64_OR16_U: + case WASM_OP_ATOMIC_RMW_I64_OR32_U: + case WASM_OP_ATOMIC_RMW_I64_XOR: + case WASM_OP_ATOMIC_RMW_I64_XOR8_U: + case WASM_OP_ATOMIC_RMW_I64_XOR16_U: + case WASM_OP_ATOMIC_RMW_I64_XOR32_U: + case WASM_OP_ATOMIC_RMW_I64_XCHG: + case WASM_OP_ATOMIC_RMW_I64_XCHG8_U: + case WASM_OP_ATOMIC_RMW_I64_XCHG16_U: + case WASM_OP_ATOMIC_RMW_I64_XCHG32_U: + POP_I64(); + POP_I32(); + PUSH_I64(); + break; + case WASM_OP_ATOMIC_RMW_I32_CMPXCHG: + case WASM_OP_ATOMIC_RMW_I32_CMPXCHG8_U: + case WASM_OP_ATOMIC_RMW_I32_CMPXCHG16_U: + POP_I32(); + POP_I32(); + POP_I32(); + PUSH_I32(); + break; + case WASM_OP_ATOMIC_RMW_I64_CMPXCHG: + case WASM_OP_ATOMIC_RMW_I64_CMPXCHG8_U: + case WASM_OP_ATOMIC_RMW_I64_CMPXCHG16_U: + case WASM_OP_ATOMIC_RMW_I64_CMPXCHG32_U: + POP_I64(); + POP_I64(); + POP_I32(); + PUSH_I64(); + break; + default: + bh_assert(0); + break; + } + break; + } +#endif /* end of WASM_ENABLE_SHARED_MEMORY */ + default: bh_assert(0); break; diff --git a/core/iwasm/interpreter/wasm_opcode.h b/core/iwasm/interpreter/wasm_opcode.h index abb60b8ed..d0e29e7ee 100644 --- a/core/iwasm/interpreter/wasm_opcode.h +++ b/core/iwasm/interpreter/wasm_opcode.h @@ -263,6 +263,7 @@ typedef enum WASMOpcode { /* Post-MVP extend op prefix */ WASM_OP_MISC_PREFIX = 0xfc, + WASM_OP_ATOMIC_PREFIX = 0xfe, } WASMOpcode; typedef enum WASMMiscEXTOpcode { @@ -285,6 +286,85 @@ typedef enum WASMMiscEXTOpcode { #endif } WASMMiscEXTOpcode; +typedef enum WASMAtomicEXTOpcode { + /* atomic wait and notify */ + WASM_OP_ATOMIC_NOTIFY = 0x00, + WASM_OP_ATOMIC_WAIT32 = 0x01, + WASM_OP_ATOMIC_WAIT64 = 0x02, + WASM_OP_ATOMIC_FENCE = 0x03, + /* atomic load and store */ + WASM_OP_ATOMIC_I32_LOAD = 0x10, + WASM_OP_ATOMIC_I64_LOAD = 0x11, + WASM_OP_ATOMIC_I32_LOAD8_U = 0x12, + WASM_OP_ATOMIC_I32_LOAD16_U = 0x13, + WASM_OP_ATOMIC_I64_LOAD8_U = 0x14, + WASM_OP_ATOMIC_I64_LOAD16_U = 0x15, + WASM_OP_ATOMIC_I64_LOAD32_U = 0x16, + WASM_OP_ATOMIC_I32_STORE = 0x17, + WASM_OP_ATOMIC_I64_STORE = 0x18, + WASM_OP_ATOMIC_I32_STORE8 = 0x19, + WASM_OP_ATOMIC_I32_STORE16 = 0x1a, + WASM_OP_ATOMIC_I64_STORE8 = 0x1b, + WASM_OP_ATOMIC_I64_STORE16 = 0x1c, + WASM_OP_ATOMIC_I64_STORE32 = 0x1d, + /* atomic add */ + WASM_OP_ATOMIC_RMW_I32_ADD = 0x1e, + WASM_OP_ATOMIC_RMW_I64_ADD = 0x1f, + WASM_OP_ATOMIC_RMW_I32_ADD8_U = 0x20, + WASM_OP_ATOMIC_RMW_I32_ADD16_U = 0x21, + WASM_OP_ATOMIC_RMW_I64_ADD8_U = 0x22, + WASM_OP_ATOMIC_RMW_I64_ADD16_U = 0x23, + WASM_OP_ATOMIC_RMW_I64_ADD32_U = 0x24, + /* atomic sub */ + WASM_OP_ATOMIC_RMW_I32_SUB = 0x25, + WASM_OP_ATOMIC_RMW_I64_SUB = 0x26, + WASM_OP_ATOMIC_RMW_I32_SUB8_U = 0x27, + WASM_OP_ATOMIC_RMW_I32_SUB16_U = 0x28, + WASM_OP_ATOMIC_RMW_I64_SUB8_U = 0x29, + WASM_OP_ATOMIC_RMW_I64_SUB16_U = 0x2a, + WASM_OP_ATOMIC_RMW_I64_SUB32_U = 0x2b, + /* atomic and */ + WASM_OP_ATOMIC_RMW_I32_AND = 0x2c, + WASM_OP_ATOMIC_RMW_I64_AND = 0x2d, + WASM_OP_ATOMIC_RMW_I32_AND8_U = 0x2e, + WASM_OP_ATOMIC_RMW_I32_AND16_U = 0x2f, + WASM_OP_ATOMIC_RMW_I64_AND8_U = 0x30, + WASM_OP_ATOMIC_RMW_I64_AND16_U = 0x31, + WASM_OP_ATOMIC_RMW_I64_AND32_U = 0x32, + /* atomic or */ + WASM_OP_ATOMIC_RMW_I32_OR = 0x33, + WASM_OP_ATOMIC_RMW_I64_OR = 0x34, + WASM_OP_ATOMIC_RMW_I32_OR8_U = 0x35, + WASM_OP_ATOMIC_RMW_I32_OR16_U = 0x36, + WASM_OP_ATOMIC_RMW_I64_OR8_U = 0x37, + WASM_OP_ATOMIC_RMW_I64_OR16_U = 0x38, + WASM_OP_ATOMIC_RMW_I64_OR32_U = 0x39, + /* atomic xor */ + WASM_OP_ATOMIC_RMW_I32_XOR = 0x3a, + WASM_OP_ATOMIC_RMW_I64_XOR = 0x3b, + WASM_OP_ATOMIC_RMW_I32_XOR8_U = 0x3c, + WASM_OP_ATOMIC_RMW_I32_XOR16_U = 0x3d, + WASM_OP_ATOMIC_RMW_I64_XOR8_U = 0x3e, + WASM_OP_ATOMIC_RMW_I64_XOR16_U = 0x3f, + WASM_OP_ATOMIC_RMW_I64_XOR32_U = 0x40, + /* atomic xchg */ + WASM_OP_ATOMIC_RMW_I32_XCHG = 0x41, + WASM_OP_ATOMIC_RMW_I64_XCHG = 0x42, + WASM_OP_ATOMIC_RMW_I32_XCHG8_U = 0x43, + WASM_OP_ATOMIC_RMW_I32_XCHG16_U = 0x44, + WASM_OP_ATOMIC_RMW_I64_XCHG8_U = 0x45, + WASM_OP_ATOMIC_RMW_I64_XCHG16_U = 0x46, + WASM_OP_ATOMIC_RMW_I64_XCHG32_U = 0x47, + /* atomic cmpxchg */ + WASM_OP_ATOMIC_RMW_I32_CMPXCHG = 0x48, + WASM_OP_ATOMIC_RMW_I64_CMPXCHG = 0x49, + WASM_OP_ATOMIC_RMW_I32_CMPXCHG8_U = 0x4a, + WASM_OP_ATOMIC_RMW_I32_CMPXCHG16_U = 0x4b, + WASM_OP_ATOMIC_RMW_I64_CMPXCHG8_U = 0x4c, + WASM_OP_ATOMIC_RMW_I64_CMPXCHG16_U = 0x4d, + WASM_OP_ATOMIC_RMW_I64_CMPXCHG32_U = 0x4e, +} WASMAtomicEXTOpcode; + #ifdef __cplusplus } #endif diff --git a/product-mini/platforms/linux-sgx/enclave-sample/Enclave/test_wasm.h b/product-mini/platforms/linux-sgx/enclave-sample/Enclave/test_wasm.h deleted file mode 100644 index 65b834798..000000000 --- a/product-mini/platforms/linux-sgx/enclave-sample/Enclave/test_wasm.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2019 Intel Corporation. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - */ - -/** - * The byte array buffer is the file content of a test wasm binary file, - * which is compiled by emcc or clang toolchain from C source file of: - * core/iwasm/app-samples/hello-world/main.c. - */ -unsigned char wasm_test_file[] = { 0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x0D, 0x06, 0x64, 0x79, 0x6C, 0x69, 0x6E, 0x6B, 0xC0, 0x80, - 0x04, 0x04, 0x00, 0x00, 0x01, 0x13, 0x04, 0x60, 0x01, 0x7F, 0x00, 0x60, - 0x01, 0x7F, 0x01, 0x7F, 0x60, 0x02, 0x7F, 0x7F, 0x01, 0x7F, 0x60, 0x00, - 0x00, 0x02, 0x58, 0x06, 0x03, 0x65, 0x6E, 0x76, 0x05, 0x5F, 0x66, 0x72, - 0x65, 0x65, 0x00, 0x00, 0x03, 0x65, 0x6E, 0x76, 0x07, 0x5F, 0x6D, 0x61, - 0x6C, 0x6C, 0x6F, 0x63, 0x00, 0x01, 0x03, 0x65, 0x6E, 0x76, 0x07, 0x5F, - 0x70, 0x72, 0x69, 0x6E, 0x74, 0x66, 0x00, 0x02, 0x03, 0x65, 0x6E, 0x76, - 0x05, 0x5F, 0x70, 0x75, 0x74, 0x73, 0x00, 0x01, 0x03, 0x65, 0x6E, 0x76, - 0x0D, 0x5F, 0x5F, 0x6D, 0x65, 0x6D, 0x6F, 0x72, 0x79, 0x5F, 0x62, 0x61, - 0x73, 0x65, 0x03, 0x7F, 0x00, 0x03, 0x65, 0x6E, 0x76, 0x06, 0x6D, 0x65, - 0x6D, 0x6F, 0x72, 0x79, 0x02, 0x00, 0x01, 0x03, 0x04, 0x03, 0x02, 0x03, - 0x03, 0x06, 0x10, 0x03, 0x7F, 0x01, 0x41, 0x00, 0x0B, 0x7F, 0x01, 0x41, - 0x00, 0x0B, 0x7F, 0x00, 0x41, 0x1B, 0x0B, 0x07, 0x33, 0x04, 0x12, 0x5F, - 0x5F, 0x70, 0x6F, 0x73, 0x74, 0x5F, 0x69, 0x6E, 0x73, 0x74, 0x61, 0x6E, - 0x74, 0x69, 0x61, 0x74, 0x65, 0x00, 0x06, 0x05, 0x5F, 0x6D, 0x61, 0x69, - 0x6E, 0x00, 0x04, 0x0B, 0x72, 0x75, 0x6E, 0x50, 0x6F, 0x73, 0x74, 0x53, - 0x65, 0x74, 0x73, 0x00, 0x05, 0x04, 0x5F, 0x73, 0x74, 0x72, 0x03, 0x03, - 0x0A, 0xBA, 0x01, 0x03, 0x9E, 0x01, 0x01, 0x01, 0x7F, 0x23, 0x01, 0x21, - 0x00, 0x23, 0x01, 0x41, 0x10, 0x6A, 0x24, 0x01, 0x20, 0x00, 0x41, 0x08, - 0x6A, 0x21, 0x02, 0x23, 0x00, 0x41, 0x1B, 0x6A, 0x10, 0x03, 0x1A, 0x41, - 0x80, 0x08, 0x10, 0x01, 0x21, 0x01, 0x20, 0x01, 0x04, 0x7F, 0x20, 0x00, - 0x20, 0x01, 0x36, 0x02, 0x00, 0x23, 0x00, 0x20, 0x00, 0x10, 0x02, 0x1A, - 0x20, 0x01, 0x23, 0x00, 0x2C, 0x00, 0x0D, 0x3A, 0x00, 0x00, 0x20, 0x01, - 0x23, 0x00, 0x2C, 0x00, 0x0E, 0x3A, 0x00, 0x01, 0x20, 0x01, 0x23, 0x00, - 0x2C, 0x00, 0x0F, 0x3A, 0x00, 0x02, 0x20, 0x01, 0x23, 0x00, 0x2C, 0x00, - 0x10, 0x3A, 0x00, 0x03, 0x20, 0x01, 0x23, 0x00, 0x2C, 0x00, 0x11, 0x3A, - 0x00, 0x04, 0x20, 0x01, 0x23, 0x00, 0x2C, 0x00, 0x12, 0x3A, 0x00, 0x05, - 0x20, 0x02, 0x20, 0x01, 0x36, 0x02, 0x00, 0x23, 0x00, 0x41, 0x13, 0x6A, - 0x20, 0x02, 0x10, 0x02, 0x1A, 0x20, 0x01, 0x10, 0x00, 0x20, 0x00, 0x24, - 0x01, 0x41, 0x00, 0x05, 0x23, 0x00, 0x41, 0x28, 0x6A, 0x10, 0x03, 0x1A, - 0x20, 0x00, 0x24, 0x01, 0x41, 0x7F, 0x0B, 0x0B, 0x03, 0x00, 0x01, 0x0B, - 0x14, 0x00, 0x23, 0x00, 0x41, 0x40, 0x6B, 0x24, 0x01, 0x23, 0x01, 0x41, - 0x80, 0x80, 0x04, 0x6A, 0x24, 0x02, 0x10, 0x05, 0x0B, 0x0B, 0x3F, 0x01, - 0x00, 0x23, 0x00, 0x0B, 0x39, 0x62, 0x75, 0x66, 0x20, 0x70, 0x74, 0x72, - 0x3A, 0x20, 0x25, 0x70, 0x0A, 0x00, 0x31, 0x32, 0x33, 0x34, 0x0A, 0x00, - 0x62, 0x75, 0x66, 0x3A, 0x20, 0x25, 0x73, 0x00, 0x48, 0x65, 0x6C, 0x6C, - 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x00, 0x6D, 0x61, 0x6C, - 0x6C, 0x6F, 0x63, 0x20, 0x62, 0x75, 0x66, 0x20, 0x66, 0x61, 0x69, 0x6C, - 0x65, 0x64, 0x00, 0x50, 0x04, 0x6E, 0x61, 0x6D, 0x65, 0x01, 0x49, 0x07, - 0x00, 0x05, 0x5F, 0x66, 0x72, 0x65, 0x65, 0x01, 0x07, 0x5F, 0x6D, 0x61, - 0x6C, 0x6C, 0x6F, 0x63, 0x02, 0x07, 0x5F, 0x70, 0x72, 0x69, 0x6E, 0x74, - 0x66, 0x03, 0x05, 0x5F, 0x70, 0x75, 0x74, 0x73, 0x04, 0x05, 0x5F, 0x6D, - 0x61, 0x69, 0x6E, 0x05, 0x0B, 0x72, 0x75, 0x6E, 0x50, 0x6F, 0x73, 0x74, - 0x53, 0x65, 0x74, 0x73, 0x06, 0x12, 0x5F, 0x5F, 0x70, 0x6F, 0x73, 0x74, - 0x5F, 0x69, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74, 0x69, 0x61, 0x74, 0x65, - 0x00, 0x20, 0x10, 0x73, 0x6F, 0x75, 0x72, 0x63, 0x65, 0x4D, 0x61, 0x70, - 0x70, 0x69, 0x6E, 0x67, 0x55, 0x52, 0x4C, 0x0E, 0x61, 0x2E, 0x6F, 0x75, - 0x74, 0x2E, 0x77, 0x61, 0x73, 0x6D, 0x2E, 0x6D, 0x61, 0x70 }; From ed8ddb2cea92d1d9bb8a08ae112041ada0efac5d Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Mon, 3 Aug 2020 12:38:22 +0800 Subject: [PATCH 041/207] Disable some components in llvm build script to decrease binary size (#330) --- build-scripts/runtime_lib.cmake | 3 +-- product-mini/platforms/linux/build_llvm.sh | 3 +++ wamr-compiler/build_llvm.sh | 3 +++ wamr-compiler/build_llvm_xtensa.sh | 3 +++ 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/build-scripts/runtime_lib.cmake b/build-scripts/runtime_lib.cmake index febdec225..d287c431d 100644 --- a/build-scripts/runtime_lib.cmake +++ b/build-scripts/runtime_lib.cmake @@ -88,8 +88,7 @@ set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99 -ffunction-sections -fdata-secti # include the build config template file include (${CMAKE_CURRENT_LIST_DIR}/config_common.cmake) -include_directories (${SHARED_DIR}/include - ${IWASM_DIR}/include) +include_directories (${IWASM_DIR}/include) file (GLOB header ${SHARED_DIR}/include/*.h diff --git a/product-mini/platforms/linux/build_llvm.sh b/product-mini/platforms/linux/build_llvm.sh index a21f03d66..19c589811 100755 --- a/product-mini/platforms/linux/build_llvm.sh +++ b/product-mini/platforms/linux/build_llvm.sh @@ -27,8 +27,11 @@ if [ ! -f bin/llvm-lto ]; then cmake ../llvm \ -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ -DCMAKE_BUILD_TYPE:STRING="Release" \ + -DLLVM_TARGETS_TO_BUILD:STRING="X86;ARM;AArch64;Mips" \ -DLLVM_BUILD_LLVM_DYLIB:BOOL=OFF \ -DLLVM_OPTIMIZED_TABLEGEN:BOOL=ON \ + -DLLVM_ENABLE_ZLIB:BOOL=OFF \ + -DLLVM_INCLUDE_DOCS:BOOL=OFF \ -DLLVM_INCLUDE_EXAMPLES:BOOL=OFF \ -DLLVM_INCLUDE_TESTS:BOOL=OFF \ -DLLVM_INCLUDE_BENCHMARKS:BOOL=OFF \ diff --git a/wamr-compiler/build_llvm.sh b/wamr-compiler/build_llvm.sh index f0da388a9..a84446f3a 100755 --- a/wamr-compiler/build_llvm.sh +++ b/wamr-compiler/build_llvm.sh @@ -27,8 +27,11 @@ if [ ! -f bin/llvm-lto ]; then cmake ../llvm \ -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ -DCMAKE_BUILD_TYPE:STRING="Release" \ + -DLLVM_TARGETS_TO_BUILD:STRING="X86;ARM;AArch64;Mips" \ -DLLVM_BUILD_LLVM_DYLIB:BOOL=OFF \ -DLLVM_OPTIMIZED_TABLEGEN:BOOL=ON \ + -DLLVM_ENABLE_ZLIB:BOOL=OFF \ + -DLLVM_INCLUDE_DOCS:BOOL=OFF \ -DLLVM_INCLUDE_EXAMPLES:BOOL=OFF \ -DLLVM_INCLUDE_TESTS:BOOL=OFF \ -DLLVM_INCLUDE_BENCHMARKS:BOOL=OFF \ diff --git a/wamr-compiler/build_llvm_xtensa.sh b/wamr-compiler/build_llvm_xtensa.sh index d41089c68..c5b155174 100755 --- a/wamr-compiler/build_llvm_xtensa.sh +++ b/wamr-compiler/build_llvm_xtensa.sh @@ -27,9 +27,12 @@ if [ ! -f bin/llvm-lto ]; then cmake ../llvm \ -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ -DCMAKE_BUILD_TYPE:STRING="Release" \ + -DLLVM_TARGETS_TO_BUILD:STRING="X86;ARM;AArch64;Mips" \ -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD:STRING="Xtensa" \ -DLLVM_BUILD_LLVM_DYLIB:BOOL=OFF \ -DLLVM_OPTIMIZED_TABLEGEN:BOOL=ON \ + -DLLVM_ENABLE_ZLIB:BOOL=OFF \ + -DLLVM_INCLUDE_DOCS:BOOL=OFF \ -DLLVM_INCLUDE_EXAMPLES:BOOL=OFF \ -DLLVM_INCLUDE_TESTS:BOOL=OFF \ -DLLVM_INCLUDE_BENCHMARKS:BOOL=OFF \ From 2db335c6d4015a47581419af95ccdc3c18851a00 Mon Sep 17 00:00:00 2001 From: Xu Jun <693788454@qq.com> Date: Tue, 4 Aug 2020 17:40:45 +0800 Subject: [PATCH 042/207] add spawn thread API and sample (#333) --- core/iwasm/common/wasm_runtime_common.c | 78 +++++++ core/iwasm/include/wasm_export.h | 53 +++++ .../libraries/thread-mgr/thread_manager.c | 67 +++++- .../libraries/thread-mgr/thread_manager.h | 6 + doc/embed_wamr.md | 75 +++++- doc/pthread_library.md | 2 +- samples/multi-thread/CMakeLists.txt | 2 +- samples/spawn-thread/CMakeLists.txt | 46 ++++ samples/spawn-thread/src/main.c | 220 ++++++++++++++++++ samples/spawn-thread/wasm-apps/CMakeLists.txt | 34 +++ samples/spawn-thread/wasm-apps/sum.c | 15 ++ 11 files changed, 591 insertions(+), 7 deletions(-) create mode 100644 samples/spawn-thread/CMakeLists.txt create mode 100644 samples/spawn-thread/src/main.c create mode 100644 samples/spawn-thread/wasm-apps/CMakeLists.txt create mode 100644 samples/spawn-thread/wasm-apps/sum.c diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index 97bb0c024..168c133e3 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -234,6 +234,10 @@ wasm_runtime_full_init(RuntimeInitArgs *init_args) return false; } +#if WASM_ENABLE_THREAD_MGR != 0 + wasm_cluster_set_max_thread_num(init_args->max_thread_num); +#endif + return true; } @@ -2850,3 +2854,77 @@ wasm_runtime_call_indirect(WASMExecEnv *exec_env, #endif return false; } + +#if WASM_ENABLE_THREAD_MGR != 0 +typedef struct WASMThreadArg { + WASMExecEnv *new_exec_env; + wasm_thread_callback_t callback; + void *arg; +} WASMThreadArg; + +WASMExecEnv * +wasm_runtime_spawn_exec_env(WASMExecEnv *exec_env) +{ + return wasm_cluster_spawn_exec_env(exec_env); +} + +void +wasm_runtime_destroy_spawned_exec_env(WASMExecEnv *exec_env) +{ + wasm_cluster_destroy_spawned_exec_env(exec_env); +} + +static void* +wasm_runtime_thread_routine(void *arg) +{ + WASMThreadArg *thread_arg = (WASMThreadArg *)arg; + void *ret; + + bh_assert(thread_arg->new_exec_env); + ret = thread_arg->callback(thread_arg->new_exec_env, thread_arg->arg); + + wasm_runtime_destroy_spawned_exec_env(thread_arg->new_exec_env); + wasm_runtime_free(thread_arg); + + os_thread_exit(ret); + return ret; +} + +int32 +wasm_runtime_spawn_thread(WASMExecEnv *exec_env, wasm_thread_t *tid, + wasm_thread_callback_t callback, void *arg) +{ + WASMExecEnv *new_exec_env = wasm_runtime_spawn_exec_env(exec_env); + WASMThreadArg *thread_arg; + int32 ret; + + if (!new_exec_env) + return -1; + + if (!(thread_arg = wasm_runtime_malloc(sizeof(WASMThreadArg)))) { + wasm_runtime_destroy_spawned_exec_env(new_exec_env); + return -1; + } + + thread_arg->new_exec_env = new_exec_env; + thread_arg->callback = callback; + thread_arg->arg = arg; + + ret = os_thread_create((korp_tid *)tid, wasm_runtime_thread_routine, + thread_arg, APP_THREAD_STACK_SIZE_DEFAULT); + + if (ret != 0) { + wasm_runtime_destroy_spawned_exec_env(new_exec_env); + wasm_runtime_free(thread_arg); + } + + return ret; +} + +int32 +wasm_runtime_join_thread(wasm_thread_t tid, void **retval) +{ + return os_thread_join((korp_tid)tid, retval); +} + +#endif diff --git a/core/iwasm/include/wasm_export.h b/core/iwasm/include/wasm_export.h index eb48a0e3e..7901f9e9b 100644 --- a/core/iwasm/include/wasm_export.h +++ b/core/iwasm/include/wasm_export.h @@ -114,6 +114,10 @@ typedef struct RuntimeInitArgs { const char *native_module_name; NativeSymbol *native_symbols; uint32_t n_native_symbols; + + /* maximum thread number, only used when + WASM_ENABLE_THREAD_MGR is defined */ + uint32_t max_thread_num; } RuntimeInitArgs; /** @@ -684,6 +688,11 @@ void * wasm_runtime_get_user_data(wasm_exec_env_t exec_env); #if WASM_ENABLE_THREAD_MGR != 0 +/* wasm thread callback function type */ +typedef void* (*wasm_thread_callback_t)(wasm_exec_env_t, void *); +/* wasm thread type */ +typedef uintptr_t wasm_thread_t; + /** * Set the max thread num per cluster. * @@ -691,6 +700,50 @@ wasm_runtime_get_user_data(wasm_exec_env_t exec_env); */ void wasm_runtime_set_max_thread_num(uint32_t num); + +/** + * spawn a new exec_env, the spawned exec_env + * can be used in other threads + * + * @param num the original exec_env + * + * @return the spawned exec_env if success, NULL otherwise + */ +wasm_exec_env_t +wasm_runtime_spawn_exec_env(wasm_exec_env_t exec_env); + +/** + * Destroy the spawned exec_env + * + * @param exec_env the spawned exec_env + */ +void +wasm_runtime_destroy_spawned_exec_env(wasm_exec_env_t exec_env); + +/** + * spawn a thread from the given exec_env + * + * @param exec_env the original exec_env + * @param tid thread id to be returned to the caller + * @param callback the callback function provided by the user + * @param arg the arguments passed to the callback + * + * @return 0 if success, -1 otherwise + */ +int32_t +wasm_runtime_spawn_thread(wasm_exec_env_t exec_env, wasm_thread_t *tid, + wasm_thread_callback_t callback, void *arg); + +/** + * waits a spawned thread to terminate + * + * @param tid thread id + * @param retval if not NULL, output the return value of the thread + * + * @return 0 if success, error number otherwise + */ +int32_t +wasm_runtime_join_thread(wasm_thread_t tid, void **retval); #endif #ifdef __cplusplus diff --git a/core/iwasm/libraries/thread-mgr/thread_manager.c b/core/iwasm/libraries/thread-mgr/thread_manager.c index 8a55265da..dfcd865a7 100644 --- a/core/iwasm/libraries/thread-mgr/thread_manager.c +++ b/core/iwasm/libraries/thread-mgr/thread_manager.c @@ -27,7 +27,8 @@ static uint32 cluster_max_thread_num = CLUSTER_MAX_THREAD_NUM; void wasm_cluster_set_max_thread_num(uint32 num) { - cluster_max_thread_num = num; + if (num > 0) + cluster_max_thread_num = num; } bool @@ -278,6 +279,70 @@ wasm_cluster_del_exec_env(WASMCluster *cluster, WASMExecEnv *exec_env) return ret; } +WASMExecEnv * +wasm_cluster_spawn_exec_env(WASMExecEnv *exec_env) +{ + WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env); + wasm_module_t module = wasm_exec_env_get_module(exec_env); + wasm_module_inst_t new_module_inst; + WASMExecEnv *new_exec_env; + uint32 aux_stack_start, aux_stack_size; + + if (!(new_module_inst = + wasm_runtime_instantiate_internal(module, true, 8192, + 0, NULL, 0))) { + return NULL; + } + + new_exec_env = wasm_exec_env_create_internal( + new_module_inst, exec_env->wasm_stack_size); + if (!new_exec_env) + goto fail1; + + if (!allocate_aux_stack(cluster, &aux_stack_start, &aux_stack_size)) { + LOG_ERROR("thread manager error: " + "failed to allocate aux stack space for new thread"); + goto fail2; + } + + /* Set aux stack for current thread */ + if (!wasm_exec_env_set_aux_stack(new_exec_env, aux_stack_start, + aux_stack_size)) { + goto fail3; + } + + if (!wasm_cluster_add_exec_env(cluster, new_exec_env)) + goto fail3; + + return new_exec_env; + +fail3: + /* free the allocated aux stack space */ + free_aux_stack(cluster, aux_stack_start); +fail2: + wasm_exec_env_destroy(new_exec_env); +fail1: + wasm_runtime_deinstantiate_internal(new_module_inst, true); + + return NULL; +} + +void +wasm_cluster_destroy_spawned_exec_env(WASMExecEnv *exec_env) +{ + WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env); + wasm_module_inst_t module_inst = wasm_runtime_get_module_inst(exec_env); + bh_assert(cluster != NULL); + + /* Free aux stack space */ + free_aux_stack(cluster, + exec_env->aux_stack_boundary + cluster->stack_size); + wasm_cluster_del_exec_env(cluster, exec_env); + wasm_exec_env_destroy_internal(exec_env); + + wasm_runtime_deinstantiate_internal(module_inst, true); +} + /* start routine of thread manager */ static void* thread_manager_start_routine(void *arg) diff --git a/core/iwasm/libraries/thread-mgr/thread_manager.h b/core/iwasm/libraries/thread-mgr/thread_manager.h index 139763769..eb5550a27 100644 --- a/core/iwasm/libraries/thread-mgr/thread_manager.h +++ b/core/iwasm/libraries/thread-mgr/thread_manager.h @@ -109,6 +109,12 @@ wasm_cluster_del_exec_env(WASMCluster *cluster, WASMExecEnv *exec_env); void wasm_cluster_spread_exception(WASMExecEnv *exec_env); +WASMExecEnv * +wasm_cluster_spawn_exec_env(WASMExecEnv *exec_env); + +void +wasm_cluster_destroy_spawned_exec_env(WASMExecEnv *exec_env); + #ifdef __cplusplus } #endif diff --git a/doc/embed_wamr.md b/doc/embed_wamr.md index d6f20e346..47e98b94d 100644 --- a/doc/embed_wamr.md +++ b/doc/embed_wamr.md @@ -22,7 +22,7 @@ Embedding WAMR guideline // read WASM file into a memory buffer buffer = read_wasm_binary_to_buffer(…, &size); - // Add it below if runtime needs to export native functions to WASM APP + // Add it below if runtime needs to export native functions to WASM APP // wasm_runtime_register_natives(...) // parse the WASM file from buffer and create a WASM module @@ -81,7 +81,7 @@ After a module is instantiated, the runtime native can lookup WASM functions by ```c unit32 argv[2]; - // lookup a WASM function by its name. + // lookup a WASM function by its name. // The function signature can NULL here func = wasm_runtime_lookup_function(module_inst, "fib", NULL); @@ -128,7 +128,7 @@ The parameters are transferred in an array of 32 bits elements. For parameters t // arg3 and arg4 each takes 2 elements // wasm_runtime_call_wasm(exec_env, func, 6, argv); - + // if the return value is type of 8 bytes, it takes // the first two array elements memcpy(&ret, &argv[0], sizeof(ret)); @@ -193,7 +193,7 @@ if(buffer_for_wasm != 0) argv[0] = buffer_for_wasm; // pass the buffer address for WASM space. argv[1] = 100; // the size of buffer wasm_runtime_call_wasm(exec_env, func, 2, argv); - + // it is runtime responsibility to release the memory, // unless the WASM app will free the passed pointer in its code wasm_runtime_module_free(module_inst, buffer_for_wasm); @@ -209,6 +209,73 @@ We can't pass structure data or class objects through the pointer since the memo +## Execute wasm functions in multiple threads + +The `exec_env` is not thread safety, it will cause unexpected behavior if the same `exec_env` is used in multiple threads. However, we've provided two ways to execute wasm functions concurrently: + +- You can use `pthread` APIs in your wasm application, see [pthread library](./pthread_library.md) for more details. + +- The `spawn exec_env` and `spawn thread` APIs are available, you can use these APIs to manage the threads in native: + + *spawn exec_env:* + + `spawn exec_env` API spawn a `new_exec_env` base on the original `exec_env`, use can use it in other threads: + + ```C + new_exec_env = wasm_runtime_spawn_exec_env(exec_env); + + /* Then you can use new_exec_env in your new thread */ + module_inst = wasm_runtime_get_module_inst(new_exec_env); + func_inst = wasm_runtime_lookup_function(module_inst, ...); + wasm_runtime_call_wasm(new_exec_env, func_inst, ...); + + /* you need to use this API to manually destroy the spawned exec_env */ + wasm_runtime_destroy_spawned_exec_env(new_exec_env); + ``` + + *spawn thread:* + + You can also use `spawn thread` API to avoid manually manage the spawned exec_env: + + ```C + wasm_thread_t wasm_tid; + void *wamr_thread_cb(wasm_exec_env_t exec_env, void *arg) + { + module_inst = wasm_runtime_get_module_inst(exec_env); + func_inst = wasm_runtime_lookup_function(module_inst, ...); + wasm_runtime_call_wasm(exec_env, func_inst, ...); + } + wasm_runtime_spawn_thread(exec_env, &wasm_tid, wamr_thread_cb, NULL); + /* Use wasm_runtime_join_thread to join the spawned thread */ + wasm_runtime_join_thread(wasm_tid, NULL); + ``` + +**Note1: You can manage the maximum number of threads can be created:** + +```C +init_args.max_thread_num = THREAD_NUM; +/* If this init argument is not set, the default maximum thread number is 4 */ +``` + + **Note2: The wasm application should be built with `--shared-memory` and `-pthread` enabled:** + +```bash + /opt/wasi-sdk/bin/clang -o test.wasm test.c -nostdlib -pthread \ + -Wl,--shared-memory,--max-memory=131072 \ + -Wl,--no-entry,--export=__heap_base,--export=__data_end \ + -Wl,--export=__wasm_call_ctors,--export=${your_func_name} +``` + + **Note3: The pthread library feature should be enabled while building the runtime:** + + ```bash + cmake .. -DWAMR_BUILD_LIB_PTHREAD=1 + ``` + +[Here](../samples/spawn-thread) is a sample to show how to use these APIs. + + + ## The deinitialization procedure ``` diff --git a/doc/pthread_library.md b/doc/pthread_library.md index 953f76a80..fd6964aa1 100644 --- a/doc/pthread_library.md +++ b/doc/pthread_library.md @@ -116,7 +116,7 @@ The default value of N is 4, which means you can create 4 threads at most. This ``` bash ./iwasm --max-threads=n test.wasm ``` -If you are going to develop your own runtime product, you can use the API `wasm_runtime_set_max_thread_num` to set the value, or you can change the macro `CLUSTER_MAX_THREAD_NUM` in [config.h](../core/config.h), +If you are going to develop your own runtime product, you can use the API `wasm_runtime_set_max_thread_num` or init arg `init_args.max_thread_num` to set the value, or you can change the macro `CLUSTER_MAX_THREAD_NUM` in [config.h](../core/config.h). > Note: the total size of aux stack reserved by compiler can be set with `-z stack-size` option during compilation. If you need to create more threads, please set a larger value, otherwise it is easy to cause aux stack overflow. diff --git a/samples/multi-thread/CMakeLists.txt b/samples/multi-thread/CMakeLists.txt index 52164bfeb..525c851a7 100644 --- a/samples/multi-thread/CMakeLists.txt +++ b/samples/multi-thread/CMakeLists.txt @@ -14,7 +14,7 @@ set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") # WAMR features switch set(WAMR_BUILD_TARGET "X86_64") set(WAMR_BUILD_INTERP 1) -set(WAMR_BUILD_AOT 0) +set(WAMR_BUILD_AOT 1) set(WAMR_BUILD_JIT 0) set(WAMR_BUILD_LIBC_BUILTIN 1) set(WAMR_BUILD_FAST_INTERP 1) diff --git a/samples/spawn-thread/CMakeLists.txt b/samples/spawn-thread/CMakeLists.txt new file mode 100644 index 000000000..dc753af2e --- /dev/null +++ b/samples/spawn-thread/CMakeLists.txt @@ -0,0 +1,46 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required(VERSION 2.8) +project(spawn_thread) + +################ runtime settings ################ +set(WAMR_BUILD_PLATFORM "linux") + +# Resetdefault linker flags +set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") +set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") + +# WAMR features switch +set(WAMR_BUILD_TARGET "X86_64") +set(WAMR_BUILD_INTERP 1) +set(WAMR_BUILD_AOT 1) +set(WAMR_BUILD_JIT 0) +set(WAMR_BUILD_LIBC_BUILTIN 1) +set(WAMR_BUILD_FAST_INTERP 1) +set(WAMR_BUILD_LIB_PTHREAD 1) + +# compiling and linking flags +set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections -pie -fPIE") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat -Wformat-security") + +# build out vmlib +set(WAMR_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../..) +include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) + +add_library(vmlib ${WAMR_RUNTIME_LIB_SOURCE}) +################################################ + + +################ wasm application ################ +add_subdirectory(wasm-apps) + +################ wamr runtime ################ +include (${SHARED_DIR}/utils/uncommon/shared_uncommon.cmake) + +set (RUNTIME_SOURCE_ALL + ${CMAKE_CURRENT_LIST_DIR}/src/main.c + ${UNCOMMON_SHARED_SOURCE} +) +add_executable (spawn_thread ${RUNTIME_SOURCE_ALL}) +target_link_libraries(spawn_thread vmlib -lpthread -lm) \ No newline at end of file diff --git a/samples/spawn-thread/src/main.c b/samples/spawn-thread/src/main.c new file mode 100644 index 000000000..c1d150508 --- /dev/null +++ b/samples/spawn-thread/src/main.c @@ -0,0 +1,220 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "wasm_export.h" +#include "bh_read_file.h" +#include "pthread.h" + +#define THREAD_NUM 10 + +typedef struct ThreadArgs { + wasm_exec_env_t exec_env; + int start; + int length; +} ThreadArgs; + +void *thread(void* arg) +{ + ThreadArgs *thread_arg = (ThreadArgs *)arg; + wasm_exec_env_t exec_env = thread_arg->exec_env; + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasm_function_inst_t func; + uint32 argv[2]; + + func = wasm_runtime_lookup_function(module_inst, "sum", NULL); + if (!func) { + printf("failed to lookup function sum"); + } + argv[0] = thread_arg->start; + argv[1] = thread_arg->length; + + /* call the WASM function */ + if (!wasm_runtime_call_wasm(exec_env, func, 2, argv)) { + printf("%s\n", wasm_runtime_get_exception(module_inst)); + return NULL; + } + + return (void *)(uintptr_t)argv[0]; +} + +void *wamr_thread_cb(wasm_exec_env_t exec_env, void *arg) +{ + ThreadArgs *thread_arg = (ThreadArgs *)arg; + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasm_function_inst_t func; + uint32 argv[2]; + + func = wasm_runtime_lookup_function(module_inst, "sum", NULL); + if (!func) { + printf("failed to lookup function sum"); + } + argv[0] = thread_arg->start; + argv[1] = thread_arg->length; + + /* call the WASM function */ + if (!wasm_runtime_call_wasm(exec_env, func, 2, argv)) { + printf("%s\n", wasm_runtime_get_exception(module_inst)); + return NULL; + } + + return (void *)(uintptr_t)argv[0]; +} + +int main(int argc, char *argv[]) +{ + char *wasm_file = "wasm-apps/test.wasm"; + uint8 *wasm_file_buf = NULL; + uint32 wasm_file_size, wasm_argv[2], i; + uint32 stack_size = 16 * 1024, heap_size = 16 * 1024; + wasm_module_t wasm_module = NULL; + wasm_module_inst_t wasm_module_inst = NULL; + wasm_exec_env_t exec_env = NULL; + RuntimeInitArgs init_args; + ThreadArgs thread_arg[THREAD_NUM]; + pthread_t tid[THREAD_NUM]; + wasm_thread_t wasm_tid[THREAD_NUM]; + uint32 result[THREAD_NUM], sum; + wasm_function_inst_t func; + char error_buf[128] = { 0 }; + + memset(thread_arg, 0, sizeof(ThreadArgs) * THREAD_NUM); + memset(&init_args, 0, sizeof(RuntimeInitArgs)); + init_args.mem_alloc_type = Alloc_With_Allocator; + init_args.mem_alloc_option.allocator.malloc_func = malloc; + init_args.mem_alloc_option.allocator.realloc_func = realloc; + init_args.mem_alloc_option.allocator.free_func = free; + init_args.max_thread_num = THREAD_NUM; + + /* initialize runtime environment */ + if (!wasm_runtime_full_init(&init_args)) { + printf("Init runtime environment failed.\n"); + return -1; + } + + /* load WASM byte buffer from WASM bin file */ + if (!(wasm_file_buf = + (uint8 *)bh_read_file_to_buffer(wasm_file, &wasm_file_size))) + goto fail1; + + /* load WASM module */ + if (!(wasm_module = wasm_runtime_load(wasm_file_buf, wasm_file_size, + error_buf, sizeof(error_buf)))) { + printf("%s\n", error_buf); + goto fail2; + } + + /* instantiate the module */ + if (!(wasm_module_inst = + wasm_runtime_instantiate(wasm_module, stack_size, heap_size, + error_buf, sizeof(error_buf)))) { + printf("%s\n", error_buf); + goto fail3; + } + + /* Create the first exec_env */ + if (!(exec_env = + wasm_runtime_create_exec_env(wasm_module_inst, stack_size))) { + printf("failed to create exec_env\n"); + goto fail4; + } + + func = wasm_runtime_lookup_function(wasm_module_inst, "sum", NULL); + if (!func) { + printf("failed to lookup function sum"); + } + wasm_argv[0] = 0; + wasm_argv[1] = THREAD_NUM * 10; + + /* + * Execute the wasm function in current thread, get the expect result + */ + if (!wasm_runtime_call_wasm(exec_env, func, 2, wasm_argv)) { + printf("%s\n", wasm_runtime_get_exception(wasm_module_inst)); + } + printf("expect result: %d\n", wasm_argv[0]); + + /* + * Run wasm function in multiple thread created by pthread_create + */ + memset(thread_arg, 0, sizeof(ThreadArgs) * THREAD_NUM); + for (i = 0; i < THREAD_NUM; i++) { + wasm_exec_env_t new_exec_env; + thread_arg[i].start = 10 * i; + thread_arg[i].length = 10; + + /* spawn a new exec_env to be executed in other threads */ + new_exec_env = wasm_runtime_spawn_exec_env(exec_env); + if (new_exec_env) + thread_arg[i].exec_env = new_exec_env; + else { + printf("failed to spawn exec_env\n"); + break; + } + + /* If we use: + thread_arg[i].exec_env = exec_env, + we may get wrong result */ + + if (0 != pthread_create(&tid[i], NULL, thread, &thread_arg[i])) { + printf("failed to create thread.\n"); + break; + } + } + + sum = 0; + memset(result, 0, sizeof(uint32) * THREAD_NUM); + for (i = 0; i < THREAD_NUM; i++) { + pthread_join(tid[i], (void **)&result[i]); + sum += result[i]; + /* destroy the spawned exec_env */ + if (thread_arg[0].exec_env) + wasm_runtime_destroy_spawned_exec_env(thread_arg[i].exec_env); + } + + printf("[pthread]sum result: %d\n", sum); + + /* + * Run wasm function in multiple thread created by wamr spawn API + */ + memset(thread_arg, 0, sizeof(ThreadArgs) * THREAD_NUM); + for (i = 0; i < THREAD_NUM; i++) { + thread_arg[i].start = 10 * i; + thread_arg[i].length = 10; + + /* No need to spawn exec_env manually */ + if (0 != wasm_runtime_spawn_thread(exec_env, &wasm_tid[i], + wamr_thread_cb, &thread_arg[i])) { + printf("failed to spawn thread.\n"); + break; + } + } + + sum = 0; + memset(result, 0, sizeof(uint32) * THREAD_NUM); + for (i = 0; i < THREAD_NUM; i++) { + wasm_runtime_join_thread(wasm_tid[i], (void**)&result[i]); + sum += result[i]; + /* No need to destroy the spawned exec_env */ + } + printf("[spwan_thread]sum result: %d\n", sum); + + wasm_runtime_destroy_exec_env(exec_env); + +fail4: + /* destroy the module instance */ + wasm_runtime_deinstantiate(wasm_module_inst); + +fail3: + /* unload the module */ + wasm_runtime_unload(wasm_module); + +fail2: + /* free the file buffer */ + wasm_runtime_free(wasm_file_buf); + +fail1: + /* destroy runtime environment */ + wasm_runtime_destroy(); +} \ No newline at end of file diff --git a/samples/spawn-thread/wasm-apps/CMakeLists.txt b/samples/spawn-thread/wasm-apps/CMakeLists.txt new file mode 100644 index 000000000..5e8332bca --- /dev/null +++ b/samples/spawn-thread/wasm-apps/CMakeLists.txt @@ -0,0 +1,34 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required(VERSION 2.8) +project(wasm-apps) + +set(WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../..) + +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_PROCESSOR wasm32) +set (CMAKE_SYSROOT ${WAMR_ROOT_DIR}/wamr-sdk/app/libc-builtin-sysroot) + +if (NOT DEFINED WASI_SDK_DIR) + set (WASI_SDK_DIR "/opt/wasi-sdk") +endif () + +set (CMAKE_C_FLAGS "-nostdlib -pthread -Qunused-arguments") +set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -z stack-size=32768") +set (CMAKE_C_COMPILER_TARGET "wasm32") +set (CMAKE_C_COMPILER "${WASI_SDK_DIR}/bin/clang") + +set (DEFINED_SYMBOLS +"${WAMR_ROOT_DIR}/wamr-sdk/app/libc-builtin-sysroot/share/defined-symbols.txt") + +set (CMAKE_EXE_LINKER_FLAGS + "-Wl,--shared-memory,--max-memory=131072, \ + -Wl,--no-entry,--strip-all,--export=sum, \ + -Wl,--export=__heap_base,--export=__data_end \ + -Wl,--export=__wasm_call_ctors \ + -Wl,--allow-undefined-file=${DEFINED_SYMBOLS}" +) + +add_executable(test.wasm sum.c) +target_link_libraries(test.wasm) diff --git a/samples/spawn-thread/wasm-apps/sum.c b/samples/spawn-thread/wasm-apps/sum.c new file mode 100644 index 000000000..31c06e390 --- /dev/null +++ b/samples/spawn-thread/wasm-apps/sum.c @@ -0,0 +1,15 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +int sum(int start, int length) +{ + int sum = 0, i; + + for (i = start; i < start + length; i++) { + sum += i; + } + + return sum; +} \ No newline at end of file From 37aae1bc496483ac30412b1aef73b9802d6a083c Mon Sep 17 00:00:00 2001 From: Karl Fessel Date: Tue, 4 Aug 2020 13:53:34 +0200 Subject: [PATCH 043/207] make include headers follow strict protoype rule (#331) --- core/iwasm/common/wasm_runtime_common.h | 4 ++-- core/iwasm/include/wasm_export.h | 4 ++-- core/shared/platform/include/platform_api_vmcore.h | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/core/iwasm/common/wasm_runtime_common.h b/core/iwasm/common/wasm_runtime_common.h index 95f4fb7f2..fa6d6badc 100644 --- a/core/iwasm/common/wasm_runtime_common.h +++ b/core/iwasm/common/wasm_runtime_common.h @@ -81,7 +81,7 @@ set_error_buf_v(char *error_buf, uint32 error_buf_size, const char *format, /* See wasm_export.h for description */ bool -wasm_runtime_init(); +wasm_runtime_init(void); /* See wasm_export.h for description */ bool @@ -89,7 +89,7 @@ wasm_runtime_full_init(RuntimeInitArgs *init_args); /* See wasm_export.h for description */ void -wasm_runtime_destroy(); +wasm_runtime_destroy(void); /* See wasm_export.h for description */ PackageType diff --git a/core/iwasm/include/wasm_export.h b/core/iwasm/include/wasm_export.h index 7901f9e9b..24f72f990 100644 --- a/core/iwasm/include/wasm_export.h +++ b/core/iwasm/include/wasm_export.h @@ -128,7 +128,7 @@ typedef struct RuntimeInitArgs { * @return true if success, false otherwise */ bool -wasm_runtime_init(); +wasm_runtime_init(void); /** * Initialize the WASM runtime environment, and also initialize @@ -146,7 +146,7 @@ wasm_runtime_full_init(RuntimeInitArgs *init_args); * Destroy the WASM runtime environment. */ void -wasm_runtime_destroy(); +wasm_runtime_destroy(void); /** * Allocate memory from runtime memory environment. diff --git a/core/shared/platform/include/platform_api_vmcore.h b/core/shared/platform/include/platform_api_vmcore.h index f7f2cad00..0f162fc03 100644 --- a/core/shared/platform/include/platform_api_vmcore.h +++ b/core/shared/platform/include/platform_api_vmcore.h @@ -25,13 +25,13 @@ extern "C" { * * @return 0 if success */ -int bh_platform_init(); +int bh_platform_init(void); /** * Destroy the platform internal resources if needed, * this function is called by wasm_runtime_destroy() */ -void bh_platform_destroy(); +void bh_platform_destroy(void); /** ******** memory allocator APIs ********** From aa7b0ba6b6f4f0172b2aa8727aae143c2ce65d95 Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Wed, 5 Aug 2020 09:07:30 +0800 Subject: [PATCH 044/207] Fix wamrc link error and arm assembly code issue (#335) --- core/iwasm/common/arch/invokeNative_arm.s | 3 ++- wamr-compiler/CMakeLists.txt | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/core/iwasm/common/arch/invokeNative_arm.s b/core/iwasm/common/arch/invokeNative_arm.s index 9bd576824..72318315f 100644 --- a/core/iwasm/common/arch/invokeNative_arm.s +++ b/core/iwasm/common/arch/invokeNative_arm.s @@ -17,6 +17,7 @@ invokeNative: stmfd sp!, {r4, r5, r6, r7, lr} + sub sp, sp, #4 /* make sp 8 byte aligned */ mov ip, r0 /* ip = function ptr */ mov r4, r1 /* r4 = argv */ mov r5, r2 /* r5 = argc */ @@ -48,7 +49,6 @@ invokeNative: mov r6, r5, lsl#2 /* r6 = argc * 4 */ add r6, r6, #7 /* r6 = (r6 + 7) & ~7 */ bic r6, r6, #7 - add r6, r6, #4 /* +4 because odd(5) registers are in stack */ sub sp, sp, r6 /* reserved stack space for left arguments */ mov r7, sp @@ -65,5 +65,6 @@ call_func: add sp, sp, r6 /* restore sp */ return: + add sp, sp, #4 ldmfd sp!, {r4, r5, r6, r7, lr} bx lr diff --git a/wamr-compiler/CMakeLists.txt b/wamr-compiler/CMakeLists.txt index 7cdf2fb2a..d27de87c3 100644 --- a/wamr-compiler/CMakeLists.txt +++ b/wamr-compiler/CMakeLists.txt @@ -101,6 +101,7 @@ include (${SHARED_DIR}/platform/${WAMR_BUILD_PLATFORM}/shared_platform.cmake) include (${SHARED_DIR}/mem-alloc/mem_alloc.cmake) include (${SHARED_DIR}/utils/shared_utils.cmake) include (${SHARED_DIR}/utils/uncommon/shared_uncommon.cmake) +include (${IWASM_DIR}/libraries/thread-mgr/thread_mgr.cmake) include (${IWASM_DIR}/libraries/libc-builtin/libc_builtin.cmake) include (${IWASM_DIR}/common/iwasm_common.cmake) include (${IWASM_DIR}/interpreter/iwasm_interp.cmake) @@ -129,6 +130,7 @@ add_library (vmlib ${MEM_ALLOC_SHARED_SOURCE} ${UTILS_SHARED_SOURCE} ${UNCOMMON_SHARED_SOURCE} + ${THREAD_MGR_SOURCE} ${LIBC_BUILTIN_SOURCE} ${IWASM_COMMON_SOURCE} ${IWASM_INTERP_SOURCE} From 2022b2584d401de8dc44e21f569bb22756f27d6d Mon Sep 17 00:00:00 2001 From: Karl Fessel Date: Thu, 6 Aug 2020 11:20:34 +0200 Subject: [PATCH 045/207] remove not needed ${SHARED_DIR}/include/*.h in runtime_lib.cmake (#338) --- build-scripts/runtime_lib.cmake | 1 - 1 file changed, 1 deletion(-) diff --git a/build-scripts/runtime_lib.cmake b/build-scripts/runtime_lib.cmake index d287c431d..6687ecc1b 100644 --- a/build-scripts/runtime_lib.cmake +++ b/build-scripts/runtime_lib.cmake @@ -91,7 +91,6 @@ include (${CMAKE_CURRENT_LIST_DIR}/config_common.cmake) include_directories (${IWASM_DIR}/include) file (GLOB header - ${SHARED_DIR}/include/*.h ${IWASM_DIR}/include/*.h ) LIST (APPEND RUNTIME_LIB_HEADER_LIST ${header}) From 47450f47dd6e63e2ecc5a0467d035bb16c2db93e Mon Sep 17 00:00:00 2001 From: follower Date: Fri, 7 Aug 2020 21:25:23 +1200 Subject: [PATCH 046/207] Fix typo: "wigdet" -> "widgets" (#340) --- doc/wamr_api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/wamr_api.md b/doc/wamr_api.md index 177f00861..b3cc45b8a 100644 --- a/doc/wamr_api.md +++ b/doc/wamr_api.md @@ -348,4 +348,4 @@ static void btn_event_cb(wgl_obj_t btn, wgl_event_t event) ``` -Currently supported widgets include button, label, list and check box and more wigdet would be provided in future. \ No newline at end of file +Currently supported widgets include button, label, list and check box and more widgets would be provided in future. From 8edf1e152f76a921a8f3fe1c6a17c2f83a6fa975 Mon Sep 17 00:00:00 2001 From: follower Date: Sat, 8 Aug 2020 02:16:02 +1200 Subject: [PATCH 047/207] Update URL to lvgl repository. (#341) The `lvgl` project appears to have changed their project name & repository URL. This commit updates the URLs so the links don't go to a 404 error page. The project name is now "Light and Versatile Embedded Graphics Library" but I haven't updated the name anywhere. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a5a667a76..c27b593c2 100644 --- a/README.md +++ b/README.md @@ -111,8 +111,8 @@ The WAMR [samples](./samples) integrate the iwasm VM core, application manager a - [**Basic**](./samples/basic): Demonstrating how host runtime calls WASM function as well as WASM function calls native function. - **[Simple](./samples/simple/README.md)**: The runtime is integrated with most of the WAMR APP libraries, and a few WASM applications are provided for testing the WAMR APP API set. It uses **built-in libc** and executes apps in **interpreter** mode by default. -- **[littlevgl](./samples/littlevgl/README.md)**: Demonstrating the graphic user interface application usage on WAMR. The whole [LittlevGL](https://github.com/littlevgl/) 2D user graphic library and the UI application is built into WASM application. It uses **WASI libc** and executes apps in **AoT mode** by default. -- **[gui](./samples/gui/README.md)**: Moved the [LittlevGL](https://github.com/littlevgl/) library into the runtime and defined a WASM application interface by wrapping the littlevgl API. It uses **WASI libc** and executes apps in **interpreter** mode by default. +- **[littlevgl](./samples/littlevgl/README.md)**: Demonstrating the graphic user interface application usage on WAMR. The whole [LittlevGL](https://github.com/lvgl/) 2D user graphic library and the UI application is built into WASM application. It uses **WASI libc** and executes apps in **AoT mode** by default. +- **[gui](./samples/gui/README.md)**: Moved the [LittlevGL](https://github.com/lvgl/) library into the runtime and defined a WASM application interface by wrapping the littlevgl API. It uses **WASI libc** and executes apps in **interpreter** mode by default. - **[wasm-c-api](./samples/wasm-c-api/README.md)**: they are samples from [wasm-c-api proposal](https://github.com/WebAssembly/wasm-c-api) and show supported APIs. From 1b6ddb37d054d9a1bca779f209b82f806f41c3fa Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Mon, 10 Aug 2020 15:12:26 +0800 Subject: [PATCH 048/207] Implement libc-WASI for Linux SGX platform and update documents (#343) --- README.md | 20 +- core/iwasm/aot/aot_loader.c | 4 + core/iwasm/common/wasm_c_api.c | 4 +- core/iwasm/common/wasm_runtime_common.c | 38 +- core/iwasm/common/wasm_runtime_common.h | 4 + .../libraries/libc-wasi/libc_wasi_wrapper.c | 3 +- .../include/wasmtime_ssp.h | 6 + .../sandboxed-system-primitives/src/locking.h | 250 +++--- .../src/numeric_limits.h | 2 - .../sandboxed-system-primitives/src/posix.c | 83 +- .../sandboxed-system-primitives/src/posix.h | 8 +- .../sandboxed-system-primitives/src/queue.h | 2 - .../sandboxed-system-primitives/src/random.c | 18 +- .../sandboxed-system-primitives/src/random.h | 2 - .../src/refcount.h | 97 +- .../src/ssp_config.h | 8 +- .../sandboxed-system-primitives/src/str.c | 43 +- core/shared/mem-alloc/ems/ems_alloc.c | 6 + core/shared/mem-alloc/ems/ems_hmu.c | 4 +- core/shared/mem-alloc/ems/ems_kfc.c | 11 + .../platform/android/platform_internal.h | 15 +- .../platform/darwin/platform_internal.h | 16 +- .../platform/linux-sgx/platform_internal.h | 18 +- core/shared/platform/linux-sgx/sgx_file.c | 832 ++++++++++++++++++ core/shared/platform/linux-sgx/sgx_file.h | 229 +++++ core/shared/platform/linux-sgx/sgx_platform.c | 22 +- core/shared/platform/linux-sgx/sgx_pthread.c | 75 ++ core/shared/platform/linux-sgx/sgx_pthread.h | 27 + core/shared/platform/linux-sgx/sgx_signal.c | 26 + core/shared/platform/linux-sgx/sgx_signal.h | 57 ++ core/shared/platform/linux-sgx/sgx_socket.c | 218 +++++ core/shared/platform/linux-sgx/sgx_socket.h | 74 ++ core/shared/platform/linux-sgx/sgx_thread.c | 105 ++- core/shared/platform/linux-sgx/sgx_time.c | 101 +++ core/shared/platform/linux-sgx/sgx_time.h | 47 + core/shared/platform/linux-sgx/sgx_wamr.edl | 132 +++ .../platform/linux-sgx/shared_platform.cmake | 6 +- .../platform/linux-sgx/untrusted/file.c | 288 ++++++ .../platform/linux-sgx/untrusted/pthread.c | 50 ++ .../platform/linux-sgx/untrusted/signal.c | 10 + .../platform/linux-sgx/untrusted/socket.c | 73 ++ .../platform/linux-sgx/untrusted/time.c | 47 + .../shared/platform/linux/platform_internal.h | 17 +- .../platform/vxworks/platform_internal.h | 13 +- core/shared/utils/bh_log.c | 2 +- doc/build_wamr.md | 81 +- doc/embed_wamr.md | 157 ++-- doc/linux_sgx.md | 197 +++++ .../platforms/linux-sgx/CMakeLists.txt | 70 +- .../linux-sgx/enclave-sample/App/App.cpp | 87 +- .../enclave-sample/Enclave/Enclave.config.xml | 6 +- .../enclave-sample/Enclave/Enclave.cpp | 40 +- .../enclave-sample/Enclave/Enclave.edl | 3 + .../enclave-sample/Enclave/Enclave_test.cpp | 416 +++++++++ .../linux-sgx/enclave-sample/Makefile | 38 +- 55 files changed, 3692 insertions(+), 516 deletions(-) create mode 100644 core/shared/platform/linux-sgx/sgx_file.c create mode 100644 core/shared/platform/linux-sgx/sgx_file.h create mode 100644 core/shared/platform/linux-sgx/sgx_pthread.c create mode 100644 core/shared/platform/linux-sgx/sgx_pthread.h create mode 100644 core/shared/platform/linux-sgx/sgx_signal.c create mode 100644 core/shared/platform/linux-sgx/sgx_signal.h create mode 100644 core/shared/platform/linux-sgx/sgx_socket.c create mode 100644 core/shared/platform/linux-sgx/sgx_socket.h create mode 100644 core/shared/platform/linux-sgx/sgx_time.h create mode 100644 core/shared/platform/linux-sgx/sgx_wamr.edl create mode 100644 core/shared/platform/linux-sgx/untrusted/file.c create mode 100644 core/shared/platform/linux-sgx/untrusted/pthread.c create mode 100644 core/shared/platform/linux-sgx/untrusted/signal.c create mode 100644 core/shared/platform/linux-sgx/untrusted/socket.c create mode 100644 core/shared/platform/linux-sgx/untrusted/time.c create mode 100644 doc/linux_sgx.md create mode 100644 product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave_test.cpp diff --git a/README.md b/README.md index c27b593c2..44481bc05 100644 --- a/README.md +++ b/README.md @@ -13,8 +13,6 @@ WebAssembly Micro Runtime (WAMR) is a standalone WebAssembly (WASM) runtime with - The **dynamic management** of the WASM applications - - iwasm VM core ========================= @@ -53,7 +51,8 @@ The iwasm supports the following architectures: Following platforms are supported. Refer to [WAMR porting guide](./doc/port_wamr.md) for how to port WAMR to a new platform. -- [Linux](./doc/build_wamr.md#linux), [Zephyr](./doc/build_wamr.md#zephyr), [MacOS](./doc/build_wamr.md#macos), [VxWorks](./doc/build_wamr.md#vxworks), [AliOS-Things](./doc/build_wamr.md#alios-things), [Intel Software Guard Extention (Linux)](./doc/build_wamr.md#linux-sgx-intel-software-guard-extention), [Android](./doc/build_wamr.md#android) +- [Linux](./doc/build_wamr.md#linux), [Linux SGX (Intel Software Guard Extension)](./doc/linux_sgx.md), [MacOS](./doc/build_wamr.md#macos), [Android](./doc/build_wamr.md#android) +- [Zephyr](./doc/build_wamr.md#zephyr), [AliOS-Things](./doc/build_wamr.md#alios-things), [VxWorks](./doc/build_wamr.md#vxworks) ### Build iwasm VM core (mini product) @@ -84,8 +83,6 @@ The WAMR has offered a comprehensive framework for programming WASM applications Browse the folder [core/app-framework](./core/app-framework) for how to extend the application framework. - - # Remote application management The WAMR application manager supports [remote application management](./core/app-mgr) from the host environment or the cloud through any physical communications such as TCP, UPD, UART, BLE, etc. Its modular design makes it able to support application management for different managed runtimes. @@ -109,11 +106,14 @@ Samples The WAMR [samples](./samples) integrate the iwasm VM core, application manager and selected application framework components. -- [**Basic**](./samples/basic): Demonstrating how host runtime calls WASM function as well as WASM function calls native function. -- **[Simple](./samples/simple/README.md)**: The runtime is integrated with most of the WAMR APP libraries, and a few WASM applications are provided for testing the WAMR APP API set. It uses **built-in libc** and executes apps in **interpreter** mode by default. -- **[littlevgl](./samples/littlevgl/README.md)**: Demonstrating the graphic user interface application usage on WAMR. The whole [LittlevGL](https://github.com/lvgl/) 2D user graphic library and the UI application is built into WASM application. It uses **WASI libc** and executes apps in **AoT mode** by default. -- **[gui](./samples/gui/README.md)**: Moved the [LittlevGL](https://github.com/lvgl/) library into the runtime and defined a WASM application interface by wrapping the littlevgl API. It uses **WASI libc** and executes apps in **interpreter** mode by default. -- **[wasm-c-api](./samples/wasm-c-api/README.md)**: they are samples from [wasm-c-api proposal](https://github.com/WebAssembly/wasm-c-api) and show supported APIs. +- [**basic**](./samples/basic): Demonstrating how to use runtime exposed API's to call WASM functions, how to register native functions and call them, and how to call WASM function from native function. +- **[simple](./samples/simple/README.md)**: The runtime is integrated with most of the WAMR APP libraries, and a few WASM applications are provided for testing the WAMR APP API set. It uses **built-in libc** and executes apps in **interpreter** mode by default. +- **[littlevgl](./samples/littlevgl/README.md)**: Demonstrating the graphic user interface application usage on WAMR. The whole [LittleVGL](https://github.com/lvgl/) 2D user graphic library and the UI application are built into WASM application. It uses **WASI libc** and executes apps in **AoT mode** by default. +- **[gui](./samples/gui/README.md)**: Move the [LittleVGL](https://github.com/lvgl/) library into the runtime and define a WASM application interface by wrapping the littlevgl API. It uses **WASI libc** and executes apps in **interpreter** mode by default. +- **[multi-thread](./samples/multi-thread/)**: Demonstrating how to run wasm application which creates multiple threads to execute wasm functions concurrently, and uses mutex/cond by calling pthread related API's. +- **[spawn-thread](./samples/spawn-thread)**: Demonstrating how to execute wasm functions of the same wasm application concurrently, in threads created by host embedder or runtime, but not the wasm application itself. +- **[multi-module](./samples/multi-module)**: Demonstrating the [multiple modules as dependencies](./doc/multi_module.md) feature which implements the [load-time dynamic linking](https://webassembly.org/docs/dynamic-linking/). +- **[wasm-c-api](./samples/wasm-c-api/README.md)**: Demonstrating how to run some samples from [wasm-c-api proposal](https://github.com/WebAssembly/wasm-c-api) and showing the supported API's. Releases and acknowledgments diff --git a/core/iwasm/aot/aot_loader.c b/core/iwasm/aot/aot_loader.c index e6c48cadf..f5bd2bb7f 100644 --- a/core/iwasm/aot/aot_loader.c +++ b/core/iwasm/aot/aot_loader.c @@ -972,9 +972,11 @@ load_object_data_sections(const uint8 **p_buf, const uint8 *buf_end, return false; } #if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64) +#ifndef BH_PLATFORM_LINUX_SGX /* address must be in the first 2 Gigabytes of the process address space */ bh_assert((uintptr_t)data_sections[i].data < INT32_MAX); +#endif #endif read_byte_array(buf, buf_end, @@ -1799,9 +1801,11 @@ create_sections(const uint8 *buf, uint32 size, goto fail; } #if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64) +#ifndef BH_PLATFORM_LINUX_SGX /* address must be in the first 2 Gigabytes of the process address space */ bh_assert((uintptr_t)aot_text < INT32_MAX); +#endif #endif bh_memcpy_s(aot_text, (uint32)total_size, section->section_body, (uint32)section_size); diff --git a/core/iwasm/common/wasm_c_api.c b/core/iwasm/common/wasm_c_api.c index dc6e38a29..d8e2ddc28 100644 --- a/core/iwasm/common/wasm_c_api.c +++ b/core/iwasm/common/wasm_c_api.c @@ -76,7 +76,9 @@ static inline void generic_vec_init_data(Vector *out, size_t num_of_elems, size_t size_of_elem) { if (!bh_vector_init(out, num_of_elems, size_of_elem)) { - memset(out, 0, sizeof(Vector)); + out->data = NULL; + out->max_elems = 0; + out->num_elems = 0; } else { memset(out->data, 0, num_of_elems * size_of_elem); diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index 168c133e3..e1fdbd130 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -1279,6 +1279,8 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, struct fd_table *curfds; struct fd_prestats *prestats; struct argv_environ_values *argv_environ; + bool fd_table_inited = false, fd_prestats_inited = false; + bool argv_environ_inited = false; int32 offset_argv_offsets = 0, offset_env_offsets = 0; int32 offset_argv_buf = 0, offset_env_buf = 0; int32 offset_curfds = 0; @@ -1373,9 +1375,26 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, wasi_ctx->curfds_offset = offset_curfds; wasi_ctx->prestats_offset = offset_prestats; wasi_ctx->argv_environ_offset = offset_argv_environ; + wasi_ctx->argv_buf_offset = offset_argv_buf; + wasi_ctx->argv_offsets_offset = offset_argv_offsets; + wasi_ctx->env_buf_offset = offset_env_buf; + wasi_ctx->env_offsets_offset = offset_env_offsets; - fd_table_init(curfds); - fd_prestats_init(prestats); + if (!fd_table_init(curfds)) { + set_error_buf(error_buf, error_buf_size, + "Init wasi environment failed: " + "init fd table failed."); + goto fail; + } + fd_table_inited = true; + + if (!fd_prestats_init(prestats)) { + set_error_buf(error_buf, error_buf_size, + "Init wasi environment failed: " + "init fd prestats failed."); + goto fail; + } + fd_prestats_inited = true; if (!argv_environ_init(argv_environ, argv_offsets, argc, @@ -1387,6 +1406,7 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, "init argument environment failed."); goto fail; } + argv_environ_inited = true; /* Prepopulate curfds with stdin, stdout, and stderr file descriptors. */ if (!fd_table_insert_existing(curfds, 0, 0) @@ -1424,6 +1444,12 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, return true; fail: + if (argv_environ_inited) + argv_environ_destroy(argv_environ); + if (fd_prestats_inited) + fd_prestats_destroy(prestats); + if (fd_table_inited) + fd_table_destroy(curfds); if (offset_curfds != 0) wasm_runtime_module_free(module_inst, offset_curfds); if (offset_prestats != 0) @@ -1537,6 +1563,14 @@ wasm_runtime_destroy_wasi(WASMModuleInstanceCommon *module_inst) fd_prestats_destroy(prestats); wasm_runtime_module_free(module_inst, wasi_ctx->prestats_offset); } + if (wasi_ctx->argv_buf_offset) + wasm_runtime_module_free(module_inst, wasi_ctx->argv_buf_offset); + if (wasi_ctx->argv_offsets_offset) + wasm_runtime_module_free(module_inst, wasi_ctx->argv_offsets_offset); + if (wasi_ctx->env_buf_offset) + wasm_runtime_module_free(module_inst, wasi_ctx->env_buf_offset); + if (wasi_ctx->env_offsets_offset) + wasm_runtime_module_free(module_inst, wasi_ctx->env_offsets_offset); wasm_runtime_free(wasi_ctx); } } diff --git a/core/iwasm/common/wasm_runtime_common.h b/core/iwasm/common/wasm_runtime_common.h index fa6d6badc..d8590a974 100644 --- a/core/iwasm/common/wasm_runtime_common.h +++ b/core/iwasm/common/wasm_runtime_common.h @@ -52,6 +52,10 @@ typedef struct WASIContext { int32 curfds_offset; int32 prestats_offset; int32 argv_environ_offset; + int32 argv_buf_offset; + int32 argv_offsets_offset; + int32 env_buf_offset; + int32 env_offsets_offset; } WASIContext; #endif diff --git a/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c b/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c index c3fa207bc..b2da6f3b9 100644 --- a/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c +++ b/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c @@ -4,8 +4,7 @@ */ #include "libc_wasi_wrapper.h" -#include "bh_common.h" -#include "bh_log.h" +#include "bh_platform.h" #include "wasm_export.h" void diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h index e386eebf2..c8473bdf4 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h @@ -832,9 +832,15 @@ __wasi_errno_t wasmtime_ssp_poll_oneoff( size_t *nevents ) WASMTIME_SSP_SYSCALL_NAME(poll_oneoff) __attribute__((__warn_unused_result__)); +#if 0 +/** + * We throw exception in libc-wasi wrapper function wasi_proc_exit() + * but not call this function. + */ _Noreturn void wasmtime_ssp_proc_exit( __wasi_exitcode_t rval ) WASMTIME_SSP_SYSCALL_NAME(proc_exit); +#endif __wasi_errno_t wasmtime_ssp_proc_raise( __wasi_signal_t sig diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/locking.h b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/locking.h index 1ae69667b..490f9a10a 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/locking.h +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/locking.h @@ -14,12 +14,6 @@ #include "ssp_config.h" -#include -#include -#include -#include -#include - #ifndef __has_extension #define __has_extension(x) 0 #endif @@ -30,7 +24,7 @@ #define LOCK_ANNOTATE(x) #endif -// Lock annotation macros. +/* Lock annotation macros. */ #define LOCKABLE LOCK_ANNOTATE(lockable) @@ -50,166 +44,216 @@ #define NO_LOCK_ANALYSIS LOCK_ANNOTATE(no_thread_safety_analysis) -// Mutex that uses the lock annotations. +/* Mutex that uses the lock annotations. */ struct LOCKABLE mutex { - pthread_mutex_t object; + pthread_mutex_t object; }; #define MUTEX_INITIALIZER \ { PTHREAD_MUTEX_INITIALIZER } -static inline void mutex_init(struct mutex *lock) REQUIRES_UNLOCKED(*lock) { - pthread_mutex_init(&lock->object, NULL); +static inline bool +mutex_init(struct mutex *lock) REQUIRES_UNLOCKED(*lock) +{ + return pthread_mutex_init(&lock->object, NULL) == 0 ? true : false; } -static inline void mutex_destroy(struct mutex *lock) REQUIRES_UNLOCKED(*lock) { - pthread_mutex_destroy(&lock->object); +static inline void +mutex_destroy(struct mutex *lock) REQUIRES_UNLOCKED(*lock) +{ + pthread_mutex_destroy(&lock->object); } -static inline void mutex_lock(struct mutex *lock) - LOCKS_EXCLUSIVE(*lock) NO_LOCK_ANALYSIS { - pthread_mutex_lock(&lock->object); +static inline void +mutex_lock(struct mutex *lock) LOCKS_EXCLUSIVE(*lock) NO_LOCK_ANALYSIS +{ + pthread_mutex_lock(&lock->object); } -static inline void mutex_unlock(struct mutex *lock) - UNLOCKS(*lock) NO_LOCK_ANALYSIS { - pthread_mutex_unlock(&lock->object); +static inline void +mutex_unlock(struct mutex *lock) UNLOCKS(*lock) NO_LOCK_ANALYSIS +{ + pthread_mutex_unlock(&lock->object); } -// Read-write lock that uses the lock annotations. +/* Read-write lock that uses the lock annotations. */ struct LOCKABLE rwlock { - pthread_rwlock_t object; + pthread_rwlock_t object; }; -static inline void rwlock_init(struct rwlock *lock) REQUIRES_UNLOCKED(*lock) { - pthread_rwlock_init(&lock->object, NULL); +static inline bool +rwlock_init(struct rwlock *lock) REQUIRES_UNLOCKED(*lock) +{ + return pthread_rwlock_init(&lock->object, NULL) == 0 ? true : false; } -static inline void rwlock_rdlock(struct rwlock *lock) - LOCKS_SHARED(*lock) NO_LOCK_ANALYSIS { - pthread_rwlock_rdlock(&lock->object); +static inline void +rwlock_rdlock(struct rwlock *lock) LOCKS_SHARED(*lock) NO_LOCK_ANALYSIS +{ + pthread_rwlock_rdlock(&lock->object); } -static inline void rwlock_wrlock(struct rwlock *lock) - LOCKS_EXCLUSIVE(*lock) NO_LOCK_ANALYSIS { - pthread_rwlock_wrlock(&lock->object); +static inline void +rwlock_wrlock(struct rwlock *lock) LOCKS_EXCLUSIVE(*lock) NO_LOCK_ANALYSIS +{ + pthread_rwlock_wrlock(&lock->object); } -static inline void rwlock_unlock(struct rwlock *lock) - UNLOCKS(*lock) NO_LOCK_ANALYSIS { - pthread_rwlock_unlock(&lock->object); +static inline void +rwlock_unlock(struct rwlock *lock) UNLOCKS(*lock) NO_LOCK_ANALYSIS +{ + pthread_rwlock_unlock(&lock->object); } -// Condition variable that uses the lock annotations. +static inline void +rwlock_destroy(struct rwlock *lock) UNLOCKS(*lock) NO_LOCK_ANALYSIS +{ + pthread_rwlock_destroy(&lock->object); +} + +/* Condition variable that uses the lock annotations. */ struct LOCKABLE cond { - pthread_cond_t object; + pthread_cond_t object; #if !CONFIG_HAS_PTHREAD_CONDATTR_SETCLOCK || \ !CONFIG_HAS_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP - clockid_t clock; + clockid_t clock; #endif }; -static inline void cond_init_monotonic(struct cond *cond) { +static inline bool +cond_init_monotonic(struct cond *cond) { + bool ret = false; #if CONFIG_HAS_PTHREAD_CONDATTR_SETCLOCK - pthread_condattr_t attr; - pthread_condattr_init(&attr); - pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); - pthread_cond_init(&cond->object, &attr); - pthread_condattr_destroy(&attr); + pthread_condattr_t attr; + + if (pthread_condattr_init(&attr) != 0) + return false; + + if (pthread_condattr_setclock(&attr, CLOCK_MONOTONIC) != 0) + goto fail; + + if (pthread_cond_init(&cond->object, &attr) != 0) + goto fail; + + ret = true; +fail: + pthread_condattr_destroy(&attr); #else - pthread_cond_init(&cond->object, NULL); + if (pthread_cond_init(&cond->object, NULL) != 0) + return false; + ret = true; #endif + #if !CONFIG_HAS_PTHREAD_CONDATTR_SETCLOCK || \ !CONFIG_HAS_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP - cond->clock = CLOCK_MONOTONIC; + cond->clock = CLOCK_MONOTONIC; #endif + return ret; } -static inline void cond_init_realtime(struct cond *cond) { - pthread_cond_init(&cond->object, NULL); +static inline bool +cond_init_realtime(struct cond *cond) +{ + if (pthread_cond_init(&cond->object, NULL) != 0) + return false; #if !CONFIG_HAS_PTHREAD_CONDATTR_SETCLOCK || \ !CONFIG_HAS_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP - cond->clock = CLOCK_REALTIME; + cond->clock = CLOCK_REALTIME; #endif + return true; } -static inline void cond_destroy(struct cond *cond) { - pthread_cond_destroy(&cond->object); +static inline void +cond_destroy(struct cond *cond) { + pthread_cond_destroy(&cond->object); } -static inline void cond_signal(struct cond *cond) { - pthread_cond_signal(&cond->object); +static inline void +cond_signal(struct cond *cond) { + pthread_cond_signal(&cond->object); } -static inline bool cond_timedwait(struct cond *cond, struct mutex *lock, - uint64_t timeout, bool abstime) - REQUIRES_EXCLUSIVE(*lock) NO_LOCK_ANALYSIS { - struct timespec ts = { - .tv_sec = (time_t)(timeout / 1000000000), - .tv_nsec = (long)(timeout % 1000000000), - }; +#if !CONFIG_HAS_CLOCK_NANOSLEEP +static inline bool +cond_timedwait(struct cond *cond, struct mutex *lock, + uint64_t timeout, bool abstime) + REQUIRES_EXCLUSIVE(*lock) NO_LOCK_ANALYSIS +{ + int ret; + struct timespec ts = { + .tv_sec = (time_t)(timeout / 1000000000), + .tv_nsec = (long)(timeout % 1000000000), + }; - if (abstime) { + if (abstime) { #if !CONFIG_HAS_PTHREAD_CONDATTR_SETCLOCK - // No native support for sleeping on monotonic clocks. Convert the - // timeout to a relative value and then to an absolute value for the - // realtime clock. - if (cond->clock != CLOCK_REALTIME) { - struct timespec ts_monotonic; - clock_gettime(cond->clock, &ts_monotonic); - ts.tv_sec -= ts_monotonic.tv_sec; - ts.tv_nsec -= ts_monotonic.tv_nsec; - if (ts.tv_nsec < 0) { - ts.tv_nsec += 1000000000; - --ts.tv_sec; - } + /** + * No native support for sleeping on monotonic clocks. Convert the + * timeout to a relative value and then to an absolute value for the + * realtime clock. + */ + if (cond->clock != CLOCK_REALTIME) { + struct timespec ts_monotonic; + struct timespec ts_realtime; - struct timespec ts_realtime; - clock_gettime(CLOCK_REALTIME, &ts_realtime); - ts.tv_sec += ts_realtime.tv_sec; - ts.tv_nsec += ts_realtime.tv_nsec; - if (ts.tv_nsec >= 1000000000) { - ts.tv_nsec -= 1000000000; - ++ts.tv_sec; - } - } + clock_gettime(cond->clock, &ts_monotonic); + ts.tv_sec -= ts_monotonic.tv_sec; + ts.tv_nsec -= ts_monotonic.tv_nsec; + if (ts.tv_nsec < 0) { + ts.tv_nsec += 1000000000; + --ts.tv_sec; + } + + clock_gettime(CLOCK_REALTIME, &ts_realtime); + ts.tv_sec += ts_realtime.tv_sec; + ts.tv_nsec += ts_realtime.tv_nsec; + if (ts.tv_nsec >= 1000000000) { + ts.tv_nsec -= 1000000000; + ++ts.tv_sec; + } + } #endif - } else { + } + else { #if CONFIG_HAS_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP - // Implementation supports relative timeouts. - int ret = - pthread_cond_timedwait_relative_np(&cond->object, &lock->object, &ts); - assert((ret == 0 || ret == ETIMEDOUT) && - "pthread_cond_timedwait_relative_np() failed"); - return ret == ETIMEDOUT; + /* Implementation supports relative timeouts. */ + ret = pthread_cond_timedwait_relative_np(&cond->object, + &lock->object, &ts); + bh_assert((ret == 0 || ret == ETIMEDOUT) + && "pthread_cond_timedwait_relative_np() failed"); + return ret == ETIMEDOUT; #else - // Convert to absolute timeout. - struct timespec ts_now; + /* Convert to absolute timeout. */ + struct timespec ts_now; #if CONFIG_HAS_PTHREAD_CONDATTR_SETCLOCK - clock_gettime(cond->clock, &ts_now); + clock_gettime(cond->clock, &ts_now); #else - clock_gettime(CLOCK_REALTIME, &ts_now); + clock_gettime(CLOCK_REALTIME, &ts_now); +#endif + ts.tv_sec += ts_now.tv_sec; + ts.tv_nsec += ts_now.tv_nsec; + if (ts.tv_nsec >= 1000000000) { + ts.tv_nsec -= 1000000000; + ++ts.tv_sec; + } #endif - ts.tv_sec += ts_now.tv_sec; - ts.tv_nsec += ts_now.tv_nsec; - if (ts.tv_nsec >= 1000000000) { - ts.tv_nsec -= 1000000000; - ++ts.tv_sec; } -#endif - } - int ret = pthread_cond_timedwait(&cond->object, &lock->object, &ts); - assert((ret == 0 || ret == ETIMEDOUT) && "pthread_cond_timedwait() failed"); - return ret == ETIMEDOUT; + ret = pthread_cond_timedwait(&cond->object, &lock->object, &ts); + bh_assert((ret == 0 || ret == ETIMEDOUT) + && "pthread_cond_timedwait() failed"); + return ret == ETIMEDOUT; } +#endif -static inline void cond_wait(struct cond *cond, struct mutex *lock) - REQUIRES_EXCLUSIVE(*lock) NO_LOCK_ANALYSIS { - pthread_cond_wait(&cond->object, &lock->object); +static inline void +cond_wait(struct cond *cond, struct mutex *lock) + REQUIRES_EXCLUSIVE(*lock) NO_LOCK_ANALYSIS +{ + pthread_cond_wait(&cond->object, &lock->object); } #endif diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/numeric_limits.h b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/numeric_limits.h index b6e3787db..2b815271e 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/numeric_limits.h +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/numeric_limits.h @@ -12,8 +12,6 @@ #ifndef COMMON_LIMITS_H #define COMMON_LIMITS_H -#include - #define NUMERIC_MIN(t) \ _Generic((t)0, char \ : CHAR_MIN, signed char \ diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c index ef597252d..c3d392301 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c @@ -10,34 +10,8 @@ // Copyright (c) 2016-2018 Nuxi, https://nuxi.nl/ #include "ssp_config.h" - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - +#include "bh_platform.h" +#include "wasmtime_ssp.h" #include "locking.h" #include "numeric_limits.h" #include "posix.h" @@ -46,9 +20,6 @@ #include "rights.h" #include "str.h" -#include "bh_common.h" -#include "bh_assert.h" - #if 0 /* TODO: -std=gnu99 causes compile error, comment them first */ // struct iovec must have the same layout as __wasi_iovec_t. static_assert(offsetof(struct iovec, iov_base) == @@ -252,16 +223,18 @@ struct fd_prestat { const char *dir; }; -void fd_prestats_init( +bool fd_prestats_init( struct fd_prestats *pt ) { - rwlock_init(&pt->lock); + if (!rwlock_init(&pt->lock)) + return false; pt->prestats = NULL; pt->size = 0; pt->used = 0; #if defined(WASMTIME_SSP_STATIC_CURFDS) prestats = pt; #endif + return true; } // Grows the preopened resource table to a required lower bound and a @@ -359,16 +332,18 @@ struct fd_entry { __wasi_rights_t rights_inheriting; }; -void fd_table_init( +bool fd_table_init( struct fd_table *ft ) { - rwlock_init(&ft->lock); + if (!rwlock_init(&ft->lock)) + return false; ft->entries = NULL; ft->size = 0; ft->used = 0; #if defined(WASMTIME_SSP_STATIC_CURFDS) curfds = ft; #endif + return true; } // Looks up a file descriptor table entry by number and required rights. @@ -598,17 +573,22 @@ bool fd_table_insert_existing( ) { __wasi_filetype_t type; __wasi_rights_t rights_base, rights_inheriting; - if (fd_determine_type_rights(out, &type, &rights_base, &rights_inheriting) != - 0) + struct fd_object *fo; + __wasi_errno_t error; + + if (fd_determine_type_rights(out, &type, &rights_base, + &rights_inheriting) != 0) return false; - struct fd_object *fo; - __wasi_errno_t error = fd_object_new(type, &fo); + error = fd_object_new(type, &fo); if (error != 0) return false; fo->number = out; if (type == __WASI_FILETYPE_DIRECTORY) { - mutex_init(&fo->directory.lock); + if (!mutex_init(&fo->directory.lock)) { + fd_object_release(fo); + return false; + } fo->directory.handle = NULL; } @@ -671,13 +651,17 @@ static __wasi_errno_t fd_table_insert_fd( ) REQUIRES_UNLOCKED(ft->lock) { struct fd_object *fo; __wasi_errno_t error = fd_object_new(type, &fo); + if (error != 0) { close(in); return error; } fo->number = in; if (type == __WASI_FILETYPE_DIRECTORY) { - mutex_init(&fo->directory.lock); + if (!mutex_init(&fo->directory.lock)) { + fd_object_release(fo); + return -1; + } fo->directory.handle = NULL; } return fd_table_insert(ft, fo, rights_base, rights_inheriting, out); @@ -2471,9 +2455,14 @@ __wasi_errno_t wasmtime_ssp_poll_oneoff( // Sleeping to an absolute point in time can only be done // by waiting on a condition variable. struct mutex mutex; - mutex_init(&mutex); struct cond cond; - cond_init_realtime(&cond); + + if (!mutex_init(&mutex)) + return -1; + if (!cond_init_realtime(&cond)) { + mutex_destroy(&mutex); + return -1; + } mutex_lock(&mutex); cond_timedwait(&cond, &mutex, in[0].u.clock.timeout, true); mutex_unlock(&mutex); @@ -2649,11 +2638,17 @@ __wasi_errno_t wasmtime_ssp_poll_oneoff( return error; } +#if 0 +/** + * We throw exception in libc-wasi wrapper function wasi_proc_exit() + * but not call this function. + */ void wasmtime_ssp_proc_exit( __wasi_exitcode_t rval ) { _Exit((int32)rval); } +#endif __wasi_errno_t wasmtime_ssp_proc_raise( __wasi_signal_t sig @@ -2952,6 +2947,7 @@ void fd_table_destroy(struct fd_table *ft) fd_object_release(ft->entries[i].object); } } + rwlock_destroy(&ft->lock); wasm_runtime_free(ft->entries); } } @@ -2964,6 +2960,7 @@ void fd_prestats_destroy(struct fd_prestats *pt) wasm_runtime_free((void*)pt->prestats[i].dir); } } + rwlock_destroy(&pt->lock); wasm_runtime_free(pt->prestats); } } diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.h b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.h index 01de1cb27..24e4d49ca 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.h +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.h @@ -12,9 +12,7 @@ #ifndef POSIX_H #define POSIX_H -#include -#include - +#include "bh_platform.h" #include "locking.h" struct fd_entry; @@ -46,9 +44,9 @@ struct argv_environ_values { char *environ_buf; }; -void fd_table_init(struct fd_table *); +bool fd_table_init(struct fd_table *); bool fd_table_insert_existing(struct fd_table *, __wasi_fd_t, int); -void fd_prestats_init(struct fd_prestats *); +bool fd_prestats_init(struct fd_prestats *); bool fd_prestats_insert(struct fd_prestats *, const char *, __wasi_fd_t); bool argv_environ_init(struct argv_environ_values *, const size_t *argv_offsets, size_t argv_offsets_len, diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/queue.h b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/queue.h index 62cbd4e93..b88f80d86 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/queue.h +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/queue.h @@ -12,8 +12,6 @@ #ifndef QUEUE_H #define QUEUE_H -#include - // LIST: Double-linked list. #define LIST_HEAD(name, type) \ diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/random.c b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/random.c index 914b1158d..927df140e 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/random.c +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/random.c @@ -10,15 +10,7 @@ // Copyright (c) 2016 Nuxi, https://nuxi.nl/ #include "ssp_config.h" - -#include -#include -#include -#include -#include -#include -#include - +#include "bh_platform.h" #include "random.h" #if CONFIG_HAS_ARC4RANDOM_BUF @@ -29,7 +21,9 @@ void random_buf(void *buf, size_t len) { #elif CONFIG_HAS_GETRANDOM +#ifndef BH_PLATFORM_LINUX_SGX #include +#endif void random_buf(void *buf, size_t len) { for (;;) { @@ -37,7 +31,7 @@ void random_buf(void *buf, size_t len) { if (x < 0) { if (errno == EINTR) continue; - fprintf(stderr, "getrandom failed: %s", strerror(errno)); + os_printf("getrandom failed: %s", strerror(errno)); abort(); } if ((size_t)x == len) @@ -54,7 +48,7 @@ static int urandom; static void open_urandom(void) { urandom = open("/dev/urandom", O_RDONLY); if (urandom < 0) { - fputs("Failed to open /dev/urandom\n", stderr); + os_printf("Failed to open /dev/urandom\n"); abort(); } } @@ -64,7 +58,7 @@ void random_buf(void *buf, size_t len) { pthread_once(&open_once, open_urandom); if ((size_t)read(urandom, buf, len) != len) { - fputs("Short read on /dev/urandom\n", stderr); + os_printf("Short read on /dev/urandom\n"); abort(); } } diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/random.h b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/random.h index b79ce92fe..8f9ecaf73 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/random.h +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/random.h @@ -12,8 +12,6 @@ #ifndef RANDOM_H #define RANDOM_H -#include - void random_buf(void *, size_t); uintmax_t random_uniform(uintmax_t); diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/refcount.h b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/refcount.h index 6faa51a29..a1c9541ed 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/refcount.h +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/refcount.h @@ -12,36 +12,89 @@ #ifndef REFCOUNT_H #define REFCOUNT_H -#include -#include -#include - +#include "bh_platform.h" #include "locking.h" -// Simple reference counter. -struct LOCKABLE refcount { - atomic_uint count; -}; - #define PRODUCES(...) LOCKS_SHARED(__VA_ARGS__) NO_LOCK_ANALYSIS #define CONSUMES(...) UNLOCKS(__VA_ARGS__) NO_LOCK_ANALYSIS -// Initialize the reference counter. -static void refcount_init(struct refcount *r, unsigned int count) PRODUCES(*r) { - atomic_init(&r->count, count); +#if CONFIG_HAS_STD_ATOMIC != 0 + +#include + +/* Simple reference counter. */ +struct LOCKABLE refcount { + atomic_uint count; +}; + +/* Initialize the reference counter. */ +static inline void +refcount_init(struct refcount *r, unsigned int count) PRODUCES(*r) +{ + atomic_init(&r->count, count); } -// Increment the reference counter. -static inline void refcount_acquire(struct refcount *r) PRODUCES(*r) { - atomic_fetch_add_explicit(&r->count, 1, memory_order_acquire); +/* Increment the reference counter. */ +static inline void +refcount_acquire(struct refcount *r) PRODUCES(*r) +{ + atomic_fetch_add_explicit(&r->count, 1, memory_order_acquire); } -// Decrement the reference counter, returning whether the reference -// dropped to zero. -static inline bool refcount_release(struct refcount *r) CONSUMES(*r) { - int old = (int)atomic_fetch_sub_explicit(&r->count, 1, memory_order_release); - assert(old != 0 && "Reference count becoming negative"); - return old == 1; +/* Decrement the reference counter, returning whether the reference + dropped to zero. */ +static inline bool +refcount_release(struct refcount *r) CONSUMES(*r) +{ + int old = (int)atomic_fetch_sub_explicit(&r->count, 1, + memory_order_release); + bh_assert(old != 0 && "Reference count becoming negative"); + return old == 1; } -#endif +#elif defined(BH_PLATFORM_LINUX_SGX) + +#include + +/* Simple reference counter. */ +struct refcount { + sgx_spinlock_t lock; + unsigned int count; +}; + +/* Initialize the reference counter. */ +static inline void +refcount_init(struct refcount *r, unsigned int count) +{ + r->lock = SGX_SPINLOCK_INITIALIZER; + r->count = count; +} + +/* Increment the reference counter. */ +static inline void +refcount_acquire(struct refcount *r) +{ + sgx_spin_lock(&r->lock); + r->count++; + sgx_spin_unlock(&r->lock); +} + +/* Decrement the reference counter, returning whether the reference + dropped to zero. */ +static inline bool +refcount_release(struct refcount *r) +{ + int old; + sgx_spin_lock(&r->lock); + old = (int)r->count; + r->count--; + sgx_spin_unlock(&r->lock); + bh_assert(old != 0 && "Reference count becoming negative"); + return old == 1; +} + +#else /* else of CONFIG_HAS_STD_ATOMIC */ +#error "Reference counter isn't implemented" +#endif /* end of CONFIG_HAS_STD_ATOMIC */ + +#endif /* end of REFCOUNT_H */ diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/ssp_config.h b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/ssp_config.h index de5898b84..5114366c8 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/ssp_config.h +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/ssp_config.h @@ -73,7 +73,7 @@ #define CONFIG_HAS_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP 0 #endif -#ifndef __APPLE__ +#if !defined(__APPLE__) && !defined(BH_PLATFORM_LINUX_SGX) #define CONFIG_HAS_PTHREAD_CONDATTR_SETCLOCK 1 #else #define CONFIG_HAS_PTHREAD_CONDATTR_SETCLOCK 0 @@ -97,4 +97,10 @@ #define CONFIG_TLS_USE_GSBASE 0 #endif +#if !defined(BH_PLATFORM_LINUX_SGX) +#define CONFIG_HAS_STD_ATOMIC 1 +#else +#define CONFIG_HAS_STD_ATOMIC 0 +#endif + #endif diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/str.c b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/str.c index 040d5845c..442112b9c 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/str.c +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/str.c @@ -10,24 +10,35 @@ // Copyright (c) 2016 Nuxi, https://nuxi.nl/ #include "ssp_config.h" - -#include -#include -#include - +#include "bh_platform.h" #include "str.h" -char *str_nullterminate(const char *s, size_t len) { - // Copy string. - char *ret = strndup(s, len); - if (ret == NULL) - return NULL; +static char * +bh_strndup(const char *s, size_t n) +{ + size_t l = strnlen(s, n); + char *s1 = wasm_runtime_malloc((uint32)(l + 1)); - // Ensure that it contains no null bytes within. - if (strlen(ret) != len) { - free(ret); - errno = EILSEQ; - return NULL; - } + if (!s1) + return NULL; + bh_memcpy_s(s1, (uint32)(l + 1), s, (uint32)l); + s1[l] = 0; + return s1; +} + +char * +str_nullterminate(const char *s, size_t len) { + /* Copy string */ + char *ret = bh_strndup(s, len); + + if (ret == NULL) + return NULL; + + /* Ensure that it contains no null bytes within */ + if (strlen(ret) != len) { + wasm_runtime_free(ret); + errno = EILSEQ; + return NULL; + } return ret; } diff --git a/core/shared/mem-alloc/ems/ems_alloc.c b/core/shared/mem-alloc/ems/ems_alloc.c index 167f656ac..d67775644 100644 --- a/core/shared/mem-alloc/ems/ems_alloc.c +++ b/core/shared/mem-alloc/ems/ems_alloc.c @@ -630,6 +630,12 @@ gci_dump(gc_heap_t *heap) os_printf("#%d %08x %x %x %d %c %d\n", i, (int32)((char*) cur - (char*) heap->base_addr), ut, p, mark, inuse, (int32)hmu_obj_size(size)); +#if BH_ENABLE_GC_VERIFY != 0 + if (inuse == 'V') { + gc_object_prefix_t *prefix = (gc_object_prefix_t *)(cur + 1); + os_printf("#%s:%d\n", prefix->file_name, prefix->line_no); + } +#endif cur = (hmu_t*)((char *)cur + size); i++; diff --git a/core/shared/mem-alloc/ems/ems_hmu.c b/core/shared/mem-alloc/ems/ems_hmu.c index 555989b5b..cd55dc176 100644 --- a/core/shared/mem-alloc/ems/ems_hmu.c +++ b/core/shared/mem-alloc/ems/ems_hmu.c @@ -84,8 +84,8 @@ hmu_verify(hmu_t *hmu) if(!is_padding_ok) { - printf("Invalid padding for object created at %s:%d", - (prefix->file_name ? prefix->file_name : ""), prefix->line_no); + os_printf("Invalid padding for object created at %s:%d", + (prefix->file_name ? prefix->file_name : ""), prefix->line_no); } bh_assert(is_padding_ok); } diff --git a/core/shared/mem-alloc/ems/ems_kfc.c b/core/shared/mem-alloc/ems/ems_kfc.c index e0b0edb8b..13a6aa6bd 100644 --- a/core/shared/mem-alloc/ems/ems_kfc.c +++ b/core/shared/mem-alloc/ems/ems_kfc.c @@ -80,6 +80,17 @@ int gc_destroy_with_pool(gc_handle_t handle) { gc_heap_t *heap = (gc_heap_t *) handle; +#if BH_ENABLE_GC_VERIFY != 0 + hmu_t *cur = (hmu_t*)heap->base_addr; + hmu_t *end = (hmu_t*)((char*)heap->base_addr + heap->current_size); + if ((hmu_t*)((char *)cur + hmu_get_size(cur)) != end) { + os_printf("Memory leak detected:\n"); + gci_dump(heap); +#if WASM_ENABLE_SPEC_TEST != 0 + while (1); +#endif + } +#endif os_mutex_destroy(&heap->lock); memset(heap->base_addr, 0, heap->current_size); memset(heap, 0, sizeof(gc_heap_t)); diff --git a/core/shared/platform/android/platform_internal.h b/core/shared/platform/android/platform_internal.h index 74c3f2365..2e3505f9d 100644 --- a/core/shared/platform/android/platform_internal.h +++ b/core/shared/platform/android/platform_internal.h @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include @@ -18,15 +17,24 @@ #include #include #include +#include #include #include +#include #include #include +#include +#include #include -#include +#include +#include #include #include -#include +#include +#include +#include +#include +#include #include #ifdef __cplusplus @@ -53,7 +61,6 @@ typedef pthread_t korp_thread; || defined(BUILD_TARGET_AMD_64) \ || defined(BUILD_TARGET_AARCH64) -#include #include #define OS_ENABLE_HW_BOUND_CHECK diff --git a/core/shared/platform/darwin/platform_internal.h b/core/shared/platform/darwin/platform_internal.h index e0820b32d..3aab6be0f 100644 --- a/core/shared/platform/darwin/platform_internal.h +++ b/core/shared/platform/darwin/platform_internal.h @@ -10,8 +10,6 @@ #include #include #include -#include -#include #include #include #include @@ -19,15 +17,26 @@ #include #include #include +#include #include #include +#include #include #include +#include +#include #include +#include +#include #include #include #include -#include +#include +#include +#include +#include +#include +#include #ifdef __cplusplus extern "C" { @@ -56,7 +65,6 @@ typedef pthread_t korp_thread; || defined(BUILD_TARGET_AMD_64) \ || defined(BUILD_TARGET_AARCH64) -#include #include #define OS_ENABLE_HW_BOUND_CHECK diff --git a/core/shared/platform/linux-sgx/platform_internal.h b/core/shared/platform/linux-sgx/platform_internal.h index c493db0f5..65b40872e 100644 --- a/core/shared/platform/linux-sgx/platform_internal.h +++ b/core/shared/platform/linux-sgx/platform_internal.h @@ -20,6 +20,14 @@ #include #include #include +#include + +#include "sgx_error.h" +#include "sgx_file.h" +#include "sgx_pthread.h" +#include "sgx_time.h" +#include "sgx_socket.h" +#include "sgx_signal.h" #ifdef __cplusplus extern "C" { @@ -37,14 +45,16 @@ extern "C" { /* Default thread priority */ #define BH_THREAD_DEFAULT_PRIORITY 0 -typedef sgx_thread_t korp_thread; -typedef sgx_thread_t korp_tid; -typedef sgx_thread_mutex_t korp_mutex; -typedef sgx_thread_cond_t korp_cond; +typedef pthread_t korp_thread; +typedef pthread_t korp_tid; +typedef pthread_mutex_t korp_mutex; +typedef pthread_cond_t korp_cond; typedef void (*os_print_function_t)(const char* message); void os_set_print_function(os_print_function_t pf); +char *strcpy(char *dest, const char *src); + #ifdef __cplusplus } #endif diff --git a/core/shared/platform/linux-sgx/sgx_file.c b/core/shared/platform/linux-sgx/sgx_file.c new file mode 100644 index 000000000..3a0fba342 --- /dev/null +++ b/core/shared/platform/linux-sgx/sgx_file.c @@ -0,0 +1,832 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "platform_api_vmcore.h" +#include "sgx_error.h" +#include "sgx_file.h" + +#define TRACE_FUNC() os_printf("undefined %s\n", __FUNCTION__) +#define TRACE_OCALL_FAIL() os_printf("ocall %s failed!\n", __FUNCTION__) + +/** fd **/ +int ocall_open(int *p_fd, const char *pathname, int flags, + bool has_mode, unsigned mode); + +int ocall_openat(int *p_fd, int dirfd, const char *pathname, int flags, + bool has_mode, unsigned mode); + +int ocall_read(ssize_t *p_ret, int fd, void *buf, size_t read_size); + +int ocall_close(int *p_ret, int fd); + +int ocall_lseek(off_t *p_ret, int fd, off_t offset, int whence); + +int ocall_ftruncate(int *p_ret, int fd, off_t length); + +int ocall_fsync(int *p_ret, int fd); + +int ocall_fdatasync(int *p_ret, int fd); + +int ocall_isatty(int *p_ret, int fd); +/** fd end **/ + +/** DIR **/ +int ocall_fdopendir(int fd, void **p_dirp); + +int ocall_readdir(void **p_dirent, void *dirp); + +int ocall_rewinddir(void *dirp); + +int ocall_seekdir(void *dirp, long loc); + +int ocall_telldir(long *p_dir, void *dirp); + +int ocall_closedir(int *p_ret, void *dirp); +/** DIR end **/ + +/** stat **/ +int ocall_fstat(int *p_ret, int fd, void *buf, unsigned int buf_len); +int ocall_fstatat(int *p_ret, int dirfd, const char *pathname, void *buf, + unsigned int buf_len, int flags); +/** stat end **/ + +/** link **/ +int ocall_mkdirat(int *p_ret, int dirfd, const char * pathname, + unsigned mode); +int ocall_link(int *p_ret, const char *oldpath, const char *newpath); +int ocall_linkat(int *p_ret, int olddirfd, const char *oldpath, + int newdirfd, const char *newpath, int flags); +int ocall_unlinkat(int *p_ret, int dirfd, const char *pathname, + int flags); +int ocall_readlinkat(ssize_t *p_ret, int dirfd, const char *pathname, + char *buf, size_t bufsiz); +int ocall_renameat(int *p_ret, int olddirfd,const char *oldpath, + int newdirfd,const char *newpath); +int ocall_symlinkat(int *p_ret, const char *target, int newdirfd, + const char *linkpath); +/** link end **/ + +/** control **/ +int ocall_ioctl(int *p_ret, int fd, unsigned long request, void *arg, + unsigned int arg_len); +int ocall_fcntl(int *p_ret, int fd, int cmd); +int ocall_fcntl_long(int *p_ret, int fd, int cmd, long arg); +/** control end **/ + +/** **/ +int ocall_realpath(int *p_ret, const char *path, char *buf, + unsigned int buf_len); +int ocall_posix_fallocate(int *p_ret, int fd, off_t offset, off_t len); +int ocall_poll(int *p_ret, void *fds, unsigned nfds, int timeout, + unsigned int fds_len); +int ocall_getopt(int *p_ret, int argc, char *argv_buf, + unsigned int argv_buf_len, const char *optstring); +int ocall_getrandom(ssize_t *p_ret, void *buf, size_t buflen, + unsigned int flags); +int ocall_sched_yield(int *p_ret); + +/** struct iovec **/ +ssize_t ocall_readv(ssize_t *p_ret, int fd, char *iov_buf, + unsigned int buf_size, int iovcnt, + bool has_offset, off_t offset); +ssize_t ocall_writev(ssize_t *p_ret, int fd, char *iov_buf, + unsigned int buf_size, int iovcnt, + bool has_offset, off_t offset); +/** iovec end **/ + +int ocall_get_errno(int *p_ret); + +int open(const char *pathname, int flags, ...) +{ + int fd; + bool has_mode = false; + mode_t mode = 0; + + if ((flags & O_CREAT) || (flags & O_TMPFILE) == O_TMPFILE) { + va_list ap; + va_start(ap, flags); + mode = va_arg(ap, mode_t); + va_end(ap); + has_mode = true; + } + + if (SGX_SUCCESS != ocall_open(&fd, pathname, flags, has_mode, mode)) { + TRACE_OCALL_FAIL(); + return -1; + } + + if (fd >= 0 && (flags & O_CLOEXEC)) + fcntl(fd, F_SETFD, FD_CLOEXEC); + + if (fd == -1) + errno = get_errno(); + return fd; +} + +int openat(int dirfd, const char *pathname, int flags, ...) +{ + int fd; + bool has_mode = false; + mode_t mode = 0; + + if ((flags & O_CREAT) || (flags & O_TMPFILE) == O_TMPFILE) { + va_list ap; + va_start(ap, flags); + mode = va_arg(ap, mode_t); + va_end(ap); + has_mode = true; + } + + if (SGX_SUCCESS != ocall_openat(&fd, dirfd, pathname, flags, + has_mode, mode)) { + TRACE_OCALL_FAIL(); + return -1; + } + + if (fd >= 0 && (flags & O_CLOEXEC)) + fcntl(fd, F_SETFD, FD_CLOEXEC); + + if (fd == -1) + errno = get_errno(); + return fd; +} + +int close(int fd) +{ + int ret; + + if (ocall_close(&ret, fd) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + if (ret == -1) + errno = get_errno(); + return ret; +} + +ssize_t read(int fd, void *buf, size_t size) +{ + ssize_t ret; + int size_read_max = 2048, size_read, total_size_read = 0, count, i; + char *p = buf; + + if (buf == NULL) { + TRACE_FUNC(); + return -1; + } + + count = (size + size_read_max - 1) / size_read_max; + for (i = 0; i < count; i++) { + size_read = (i < count - 1) + ? size_read_max + : size - size_read_max * i; + + if (ocall_read(&ret, fd, p, size_read) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + if (ret == -1) { + /* read failed */ + errno = get_errno(); + return -1; + } + + p += ret; + total_size_read += ret; + + if (ret < size_read) + /* end of file */ + break; + } + return total_size_read; +} + +DIR *fdopendir(int fd) +{ + DIR *result = NULL; + + result = (DIR *)BH_MALLOC(sizeof(DIR)); + if (!result) + return NULL; + + if (ocall_fdopendir(fd, (void **)result) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + BH_FREE(result); + return NULL; + } + + if ((void *)*result == NULL) { /* opendir failed */ + TRACE_FUNC(); + BH_FREE(result); + errno = get_errno(); + return NULL; + } + + return result; +} + +struct dirent *readdir(DIR *dirp) +{ + struct dirent *result; + + if (dirp == NULL) + return NULL; + + if (ocall_readdir((void **)&result, (void *)*dirp) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return NULL; + } + + if (!result) + errno = get_errno(); + return result; +} + +void rewinddir(DIR *dirp) +{ + if (ocall_rewinddir((void *)*dirp) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + } +} + +void seekdir(DIR *dirp, long loc) +{ + if (ocall_seekdir((void *)*dirp, loc) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + } +} + +long telldir(DIR *dirp) +{ + long ret; + + if (ocall_telldir(&ret, (void *)*dirp) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + if (ret == -1) + errno = get_errno(); + return ret; +} + +int closedir(DIR *dirp) +{ + int ret; + + if (ocall_closedir(&ret, (void *)*dirp) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + BH_FREE(dirp); + if (ret == -1) + errno = get_errno(); + return ret; +} + +static ssize_t +readv_internal(int fd, const struct iovec *iov, int iovcnt, + bool has_offset, off_t offset) +{ + ssize_t ret, size_left; + struct iovec *iov1; + int i; + char *p; + uint64 total_size = sizeof(struct iovec) * (uint64)iovcnt; + + if (iov == NULL || iovcnt < 1) + return -1; + + for (i = 0; i < iovcnt; i++) { + total_size += iov[i].iov_len; + } + + if (total_size >= UINT32_MAX) + return -1; + + iov1 = BH_MALLOC((uint32)total_size); + + if (iov1 == NULL) + return -1; + + memset(iov1, 0, (uint32)total_size); + + p = (char*)(uintptr_t)(sizeof(struct iovec) * iovcnt); + + for (i = 0; i < iovcnt; i++) { + iov1[i].iov_len = iov[i].iov_len; + iov1[i].iov_base = p; + p += iov[i].iov_len; + } + + if (ocall_readv(&ret, fd, (char *)iov1, (uint32)total_size, + iovcnt, has_offset, offset) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + BH_FREE(iov1); + return -1; + } + + p = (char *)(uintptr_t)(sizeof(struct iovec) * iovcnt); + + size_left = ret; + for (i = 0; i < iovcnt; i++) { + if (size_left > iov[i].iov_len) { + memcpy(iov[i].iov_base, (uintptr_t)p + (char *)iov1, + iov[i].iov_len); + p += iov[i].iov_len; + size_left -= iov[i].iov_len; + } + else { + memcpy(iov[i].iov_base, (uintptr_t)p + (char *)iov1, + size_left); + break; + } + } + + BH_FREE(iov1); + if (ret == -1) + errno = get_errno(); + return ret; +} + +static ssize_t +writev_internal(int fd, const struct iovec *iov, int iovcnt, + bool has_offset, off_t offset) +{ + ssize_t ret; + struct iovec *iov1; + int i; + char *p; + uint64 total_size = sizeof(struct iovec) * (uint64)iovcnt; + + if (iov == NULL || iovcnt < 1) + return -1; + + for (i = 0; i < iovcnt; i++) { + total_size += iov[i].iov_len; + } + + if (total_size >= UINT32_MAX) + return -1; + + iov1 = BH_MALLOC((uint32)total_size); + + if (iov1 == NULL) + return -1; + + memset(iov1, 0, (uint32)total_size); + + p = (char *)(uintptr_t)(sizeof(struct iovec) * iovcnt); + + for (i = 0; i < iovcnt; i++) { + iov1[i].iov_len = iov[i].iov_len; + iov1[i].iov_base = p; + memcpy((uintptr_t)p + (char *)iov1, iov[i].iov_base, + iov[i].iov_len); + p += iov[i].iov_len; + } + + if (ocall_writev(&ret, fd, (char *)iov1, (uint32)total_size, + iovcnt, has_offset, offset) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + BH_FREE(iov1); + return -1; + } + + BH_FREE(iov1); + if (ret == -1) + errno = get_errno(); + return ret; +} + +ssize_t readv(int fd, const struct iovec *iov, int iovcnt) +{ + return readv_internal(fd, iov, iovcnt, false, 0); +} + +ssize_t writev(int fd, const struct iovec *iov, int iovcnt) +{ + return writev_internal(fd, iov, iovcnt, false, 0); +} + +ssize_t preadv(int fd, const struct iovec *iov, int iovcnt, + off_t offset) +{ + return readv_internal(fd, iov, iovcnt, true, offset); +} + +ssize_t pwritev(int fd, const struct iovec *iov, int iovcnt, + off_t offset) +{ + return writev_internal(fd, iov, iovcnt, true, offset); +} + +off_t lseek(int fd, off_t offset, int whence) +{ + off_t ret; + if (ocall_lseek(&ret, fd, (long)offset, whence) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + if (ret == -1) + errno = get_errno(); + return ret; +} + +int ftruncate(int fd, off_t length) +{ + int ret; + + if (ocall_ftruncate(&ret, fd, length) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + if (ret == -1) + errno = get_errno(); + return ret; +} + +int fstat(int fd, struct stat *statbuf) +{ + int ret; + + if (statbuf == NULL) + return -1; + + if (ocall_fstat(&ret, fd, (void *)statbuf, + sizeof(struct stat)) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + + if (ret == -1) + errno = get_errno(); + return ret; +} + +int fstatat(int dirfd, const char *pathname, struct stat *statbuf, + int flags) +{ + int ret; + + if (statbuf == NULL) + return -1; + + if (ocall_fstatat(&ret, dirfd, pathname, (void *)statbuf, + sizeof(struct stat), flags) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + + if (ret == -1) + errno = get_errno(); + return ret; +} + +int fsync(int fd) +{ + int ret; + + if (ocall_fsync(&ret, fd) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + if (ret == -1) + errno = get_errno(); + return ret; +} + +int fdatasync(int fd) +{ + int ret; + + if (ocall_fdatasync(&ret, fd) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + if (ret == -1) + errno = get_errno(); + return ret; +} + +int mkdirat(int dirfd, const char *pathname, mode_t mode) +{ + int ret; + + if (ocall_mkdirat(&ret, dirfd, pathname, mode) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + + if (ret == -1) + errno = get_errno(); + return ret; +} + +int link(const char *oldpath, const char *newpath) +{ + int ret; + + if (ocall_link(&ret, oldpath, newpath) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + + if (ret == -1) + errno = get_errno(); + return ret; +} + +int linkat(int olddirfd, const char *oldpath, + int newdirfd, const char *newpath, int flags) +{ + int ret; + + if (ocall_linkat(&ret, olddirfd, oldpath, newdirfd, newpath, + flags) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + + if (ret == -1) + errno = get_errno(); + return ret; +} + +int unlinkat(int dirfd, const char *pathname, int flags) +{ + int ret; + + if (ocall_unlinkat(&ret, dirfd, pathname, flags) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + + if (ret == -1) + errno = get_errno(); + return ret; +} + +ssize_t readlinkat(int dirfd, const char *pathname, + char *buf, size_t bufsiz) +{ + ssize_t ret; + + if (buf == NULL) + return -1; + + if (ocall_readlinkat(&ret, dirfd, pathname, buf, + bufsiz) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + + if (ret == -1) + errno = get_errno(); + return ret; +} + +int symlinkat(const char *target, int newdirfd, const char *linkpath) +{ + int ret; + + if (ocall_symlinkat(&ret, target, + newdirfd, linkpath) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + + if (ret == -1) + errno = get_errno(); + return ret; +} + +int renameat(int olddirfd, const char *oldpath, + int newdirfd, const char *newpath) +{ + int ret; + + if (ocall_renameat(&ret, olddirfd, oldpath, + newdirfd, newpath) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + + if (ret == -1) + errno = get_errno(); + return ret; +} + +int ioctl(int fd, unsigned long request, ...) +{ + int ret; + va_list args; + + switch (request) { + case FIONREAD: + va_start(args, request); + int *arg = (int *)va_arg(args, int *); + if (ocall_ioctl(&ret, fd, request, arg, + sizeof(*arg)) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + va_end(args); + return -1; + } + va_end(args); + break; + + default: + os_printf("ioctl failed: unknown request", request); + return -1; + } + + if (ret == -1) + errno = get_errno(); + return ret; +} + +int fcntl(int fd, int cmd, ... /* arg */ ) +{ + int ret; + va_list args; + + switch (cmd) { + case F_GETFD: + case F_GETFL: + if (ocall_fcntl(&ret, fd, cmd) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + break; + + case F_DUPFD: + case F_SETFD: + case F_SETFL: + va_start(args, cmd); + long arg_1 = (long)va_arg(args, long); + if (ocall_fcntl_long(&ret, fd, cmd, arg_1) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + va_end(args); + return -1; + } + va_end(args); + break; + + default: + os_printf("fcntl failed: unknown cmd %d.\n", cmd); + return -1; + } + + if (ret == -1) + errno = get_errno(); + return ret; +} + +int isatty(int fd) +{ + int ret; + + if (ocall_isatty(&ret, fd) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + if (ret == 0) + errno = get_errno(); + return ret; +} + +char *realpath(const char *path, char *resolved_path) +{ + int ret; + char buf[PATH_MAX] = { 0 }; + + if (ocall_realpath(&ret, path, buf, PATH_MAX) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return (char *)NULL; + } + + if (ret != 0) + return (char *)NULL; + + if (resolved_path) { + strcpy(resolved_path, buf); + } + else { + resolved_path = BH_MALLOC(strlen(buf) + 1); + if (resolved_path == NULL) + return NULL; + strcpy(resolved_path, buf); + } + + return resolved_path; +} + +int posix_fallocate(int fd, off_t offset, off_t len) +{ + int ret; + + if (ocall_posix_fallocate(&ret, fd, offset, len) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + + return ret; +} + +int poll(struct pollfd *fds, nfds_t nfds, int timeout) +{ + int ret; + + if (fds == NULL) + return -1; + + if (ocall_poll(&ret, fds, nfds, timeout, + sizeof(*fds) * nfds) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + + if (ret == -1) + errno = get_errno(); + return ret; +} + +int getopt(int argc, char * const argv[], + const char *optstring) +{ + int ret; + char **argv1; + char *p; + int i; + uint64 total_size = sizeof(char *) * (uint64)argc; + + for (i = 0; i < argc; i++) { + total_size += strlen(argv[i]) + 1; + } + + if (total_size >= UINT32_MAX) + return -1; + + argv1 = BH_MALLOC((uint32)total_size); + + if (argv1 == NULL) + return -1; + + p = (char *)(uintptr_t)(sizeof(char *) * argc); + + for (i = 0; i < argc; i++) { + argv1[i] = p; + strcpy((char *)argv1 + (uintptr_t)p, argv[i]); + p += ((uintptr_t)strlen(argv[i]) + 1); + } + + if (ocall_getopt(&ret, argc, (char *)argv1, total_size, + optstring) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + BH_FREE(argv1); + return -1; + } + + BH_FREE(argv1); + if (ret == -1) + errno = get_errno(); + return ret; +} + +int sched_yield(void) +{ + int ret; + + if (ocall_sched_yield(&ret) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + if (ret == -1) + errno = get_errno(); + return ret; +} + +ssize_t getrandom(void *buf, size_t buflen, unsigned int flags) +{ + ssize_t ret; + + if (ocall_getrandom(&ret, buf, buflen, flags) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + if (ret == -1) + errno = get_errno(); + return ret; +} + +int get_errno(void) +{ + int ret; + + if (ocall_get_errno(&ret) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + return ret; +} diff --git a/core/shared/platform/linux-sgx/sgx_file.h b/core/shared/platform/linux-sgx/sgx_file.h new file mode 100644 index 000000000..7d046766c --- /dev/null +++ b/core/shared/platform/linux-sgx/sgx_file.h @@ -0,0 +1,229 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _SGX_FILE_H +#define _SGX_FILE_H + +#include "sgx_time.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define F_DUPFD 0 +#define F_GETFD 1 +#define F_SETFD 2 +#define F_GETFL 3 +#define F_SETFL 4 + +#define FD_CLOEXEC 1 + +#define O_PATH 010000000 +#define O_SEARCH O_PATH +#define O_EXEC O_PATH + +#define O_ACCMODE (03|O_SEARCH) +#define O_RDONLY 00 +#define O_WRONLY 01 +#define O_RDWR 02 + +#define O_CREAT 0100 +#define O_EXCL 0200 +#define O_NOCTTY 0400 +#define O_TRUNC 01000 +#define O_APPEND 02000 +#define O_NONBLOCK 04000 +#define O_DSYNC 010000 +#define O_SYNC 04010000 +#define O_RSYNC 04010000 +#define O_DIRECTORY 0200000 +#define O_NOFOLLOW 0400000 +#define O_CLOEXEC 02000000 + +#define O_ASYNC 020000 +#define O_DIRECT 040000 +#define O_LARGEFILE 0 +#define O_NOATIME 01000000 +#define O_PATH 010000000 +#define O_TMPFILE 020200000 +#define O_NDELAY O_NONBLOCK + +#define S_IFMT 0170000 +#define S_IFDIR 0040000 +#define S_IFCHR 0020000 +#define S_IFBLK 0060000 +#define S_IFREG 0100000 +#define S_IFIFO 0010000 +#define S_IFLNK 0120000 +#define S_IFSOCK 0140000 + +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 + +#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) +#define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR) +#define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK) +#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) +#define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO) +#define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK) +#define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK) + +#define DT_UNKNOWN 0 +#define DT_FIFO 1 +#define DT_CHR 2 +#define DT_DIR 4 +#define DT_BLK 6 +#define DT_REG 8 +#define DT_LNK 10 +#define DT_SOCK 12 +#define DT_WHT 14 + +#define AT_SYMLINK_NOFOLLOW 0x100 +#define AT_REMOVEDIR 0x200 +#define AT_SYMLINK_FOLLOW 0x400 + +#define POLLIN 0x001 +#define POLLPRI 0x002 +#define POLLOUT 0x004 +#define POLLERR 0x008 +#define POLLHUP 0x010 +#define POLLNVAL 0x020 +#define POLLRDNORM 0x040 +#define POLLRDBAND 0x080 +#define POLLWRNORM 0x100 +#define POLLWRBAND 0x200 + +#define FIONREAD 0x541B + +#define PATH_MAX 4096 + +/* Special value used to indicate openat should use the current + working directory. */ +#define AT_FDCWD -100 + +typedef long __syscall_slong_t; + +typedef unsigned long dev_t; +typedef unsigned long ino_t; +typedef unsigned mode_t; +typedef unsigned long nlink_t; +typedef unsigned socklen_t; +typedef long blksize_t; +typedef long blkcnt_t; + +typedef int pid_t; +typedef unsigned gid_t; +typedef unsigned uid_t; + +typedef unsigned long nfds_t; + +typedef uintptr_t DIR; + +struct dirent { + ino_t d_ino; + off_t d_off; + unsigned short d_reclen; + unsigned char d_type; + char d_name[256]; +}; + +struct stat { + dev_t st_dev; + ino_t st_ino; + nlink_t st_nlink; + + mode_t st_mode; + uid_t st_uid; + gid_t st_gid; + unsigned int __pad0; + dev_t st_rdev; + off_t st_size; + blksize_t st_blksize; + blkcnt_t st_blocks; + + struct timespec st_atim; + struct timespec st_mtim; + struct timespec st_ctim; + long __unused[3]; +}; + +struct iovec { + void *iov_base; + size_t iov_len; +}; + +struct pollfd { + int fd; + short events; + short revents; +}; + +int open(const char *pathname, int flags, ...); +int openat(int dirfd, const char *pathname, int flags, ...); +int close(int fd); + +DIR *fdopendir(int fd); +int closedir(DIR *dirp); +void rewinddir(DIR *dirp); +void seekdir(DIR *dirp, long loc); +struct dirent *readdir(DIR *dirp); +long telldir(DIR *dirp); + +ssize_t read(int fd, void *buf, size_t count); +ssize_t readv(int fd, const struct iovec *iov, int iovcnt); +ssize_t writev(int fd, const struct iovec *iov, int iovcnt); +ssize_t preadv(int fd, const struct iovec *iov, int iovcnt, + off_t offset); +ssize_t pwritev(int fd, const struct iovec *iov, int iovcnt, + off_t offset); + +off_t lseek(int fd, off_t offset, int whence); +int ftruncate(int fd, off_t length); + +int fstat(int fd, struct stat *statbuf); +int fstatat(int dirfd, const char *pathname, struct stat *statbuf, + int flags); + +int fsync(int fd); +int fdatasync(int fd); + +int mkdirat(int dirfd, const char *pathname, mode_t mode); +int link(const char *oldpath, const char *newpath); +int linkat(int olddirfd, const char *oldpath, + int newdirfd, const char *newpath, int flags); +int unlinkat(int dirfd, const char *pathname, int flags); +ssize_t readlinkat(int dirfd, const char *pathname, + char *buf, size_t bufsiz); +int symlinkat(const char *target, int newdirfd, const char *linkpath); +int renameat(int olddirfd, const char *oldpath, + int newdirfd, const char *newpath); + +int ioctl(int fd, unsigned long request, ...); +int fcntl(int fd, int cmd, ... /* arg */ ); + +int isatty(int fd); + +char *realpath(const char *path, char *resolved_path); + +int posix_fallocate(int fd, off_t offset, off_t len); + +int poll(struct pollfd *fds, nfds_t nfds, int timeout); + +int getopt(int argc, char * const argv[], + const char *optstring); + +int sched_yield(void); + +ssize_t getrandom(void *buf, size_t buflen, unsigned int flags); + +int get_errno(void); + +#ifdef __cplusplus +} +#endif + +#endif /* end of _SGX_FILE_H */ + diff --git a/core/shared/platform/linux-sgx/sgx_platform.c b/core/shared/platform/linux-sgx/sgx_platform.c index f018db4de..f7f5c622b 100644 --- a/core/shared/platform/linux-sgx/sgx_platform.c +++ b/core/shared/platform/linux-sgx/sgx_platform.c @@ -5,10 +5,7 @@ #include "platform_api_vmcore.h" #include "platform_api_extension.h" - -#if WASM_ENABLE_AOT != 0 #include "sgx_rsrv_mem_mngr.h" -#endif #define FIXED_BUFFER_SIZE (1<<9) @@ -82,9 +79,17 @@ int os_vprintf(const char * format, va_list arg) return 0; } +char *strcpy(char *dest, const char *src) +{ + const unsigned char *s = src; + unsigned char *d = dest; + + while ((*d++ = *s++)); + return dest; +} + void* os_mmap(void *hint, size_t size, int prot, int flags) { -#if WASM_ENABLE_AOT != 0 int mprot = 0; uint64 aligned_size, page_size; void* ret = NULL; @@ -119,25 +124,19 @@ void* os_mmap(void *hint, size_t size, int prot, int flags) } return ret; -#else - return NULL; -#endif } void os_munmap(void *addr, size_t size) { -#if WASM_ENABLE_AOT != 0 uint64 aligned_size, page_size; page_size = getpagesize(); aligned_size = (size + page_size - 1) & ~(page_size - 1); sgx_free_rsrv_mem(addr, aligned_size); -#endif } int os_mprotect(void *addr, size_t size, int prot) { -#if WASM_ENABLE_AOT != 0 int mprot = 0; sgx_status_t st = 0; uint64 aligned_size, page_size; @@ -157,9 +156,6 @@ int os_mprotect(void *addr, size_t size, int prot) addr, size, prot); return (st == SGX_SUCCESS? 0:-1); -#else - return -1; -#endif } void diff --git a/core/shared/platform/linux-sgx/sgx_pthread.c b/core/shared/platform/linux-sgx/sgx_pthread.c new file mode 100644 index 000000000..b25368aa5 --- /dev/null +++ b/core/shared/platform/linux-sgx/sgx_pthread.c @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "platform_api_vmcore.h" +#include "sgx_pthread.h" +#include "sgx_error.h" + +#define TRACE_FUNC() os_printf("undefined %s\n", __FUNCTION__) +#define TRACE_OCALL_FAIL() os_printf("ocall %s failed!\n", __FUNCTION__) + +int ocall_pthread_rwlock_init(int *p_ret, void **rwlock, void *attr); + +int ocall_pthread_rwlock_destroy(int *p_ret, void **rwlock); + +int ocall_pthread_rwlock_rdlock(int *p_ret, void **rwlock); + +int ocall_pthread_rwlock_wrlock(int *p_ret, void **rwlock); + +int ocall_pthread_rwlock_unlock(int *p_ret, void **rwlock); + +int pthread_rwlock_init(pthread_rwlock_t *rwlock, void *attr) +{ + int ret = -1; + + if (ocall_pthread_rwlock_init(&ret, (void **)rwlock, NULL) + != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + (void)attr; + return ret; +} + +int pthread_rwlock_destroy(pthread_rwlock_t *rwlock) +{ + int ret = -1; + + if (ocall_pthread_rwlock_destroy(&ret, (void *)*rwlock) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + } + return ret; +} + +int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock) +{ + int ret = -1; + + if (ocall_pthread_rwlock_rdlock(&ret, (void*)*rwlock) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + } + return ret; +} + +int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock) +{ + int ret = -1; + + if (ocall_pthread_rwlock_wrlock(&ret, (void*)*rwlock) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + } + return ret; +} + +int pthread_rwlock_unlock(pthread_rwlock_t *rwlock) +{ + int ret = -1; + + if (ocall_pthread_rwlock_unlock(&ret, (void*)*rwlock) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + } + return ret; +} + diff --git a/core/shared/platform/linux-sgx/sgx_pthread.h b/core/shared/platform/linux-sgx/sgx_pthread.h new file mode 100644 index 000000000..550cbf8c6 --- /dev/null +++ b/core/shared/platform/linux-sgx/sgx_pthread.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _SGX_PTHREAD_H +#define _SGX_PTHREAD_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef uintptr_t pthread_rwlock_t; + +int pthread_rwlock_init(pthread_rwlock_t *rwlock, void *attr); +int pthread_rwlock_destroy(pthread_rwlock_t *rwlock); + +int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock); +int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock); +int pthread_rwlock_unlock(pthread_rwlock_t *rwlock); + +#ifdef __cplusplus +} +#endif + +#endif /* end of _SGX_PTHREAD_H */ + diff --git a/core/shared/platform/linux-sgx/sgx_signal.c b/core/shared/platform/linux-sgx/sgx_signal.c new file mode 100644 index 000000000..e2487dea5 --- /dev/null +++ b/core/shared/platform/linux-sgx/sgx_signal.c @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "platform_api_vmcore.h" + +#define TRACE_OCALL_FAIL() os_printf("ocall %s failed!\n", __FUNCTION__) + +int ocall_raise(int *p_ret, int sig); + +int raise(int sig) +{ + int ret; + + if (ocall_raise(&ret, sig) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + + if (ret == -1) + errno = get_errno(); + + return ret; +} + diff --git a/core/shared/platform/linux-sgx/sgx_signal.h b/core/shared/platform/linux-sgx/sgx_signal.h new file mode 100644 index 000000000..b83a9235d --- /dev/null +++ b/core/shared/platform/linux-sgx/sgx_signal.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _SGX_SIGNAL_H +#define _SGX_SIGNAL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Signals. */ +#define SIGHUP 1 /* Hangup (POSIX). */ +#define SIGINT 2 /* Interrupt (ANSI). */ +#define SIGQUIT 3 /* Quit (POSIX). */ +#define SIGILL 4 /* Illegal instruction (ANSI). */ +#define SIGTRAP 5 /* Trace trap (POSIX). */ +#define SIGABRT 6 /* Abort (ANSI). */ +#define SIGIOT 6 /* IOT trap (4.2 BSD). */ +#define SIGBUS 7 /* BUS error (4.2 BSD). */ +#define SIGFPE 8 /* Floating-point exception (ANSI). */ +#define SIGKILL 9 /* Kill, unblockable (POSIX). */ +#define SIGUSR1 10 /* User-defined signal 1 (POSIX). */ +#define SIGSEGV 11 /* Segmentation violation (ANSI). */ +#define SIGUSR2 12 /* User-defined signal 2 (POSIX). */ +#define SIGPIPE 13 /* Broken pipe (POSIX). */ +#define SIGALRM 14 /* Alarm clock (POSIX). */ +#define SIGTERM 15 /* Termination (ANSI). */ +#define SIGSTKFLT 16 /* Stack fault. */ +#define SIGCLD SIGCHLD /* Same as SIGCHLD (System V). */ +#define SIGCHLD 17 /* Child status has changed (POSIX). */ +#define SIGCONT 18 /* Continue (POSIX). */ +#define SIGSTOP 19 /* Stop, unblockable (POSIX). */ +#define SIGTSTP 20 /* Keyboard stop (POSIX). */ +#define SIGTTIN 21 /* Background read from tty (POSIX). */ +#define SIGTTOU 22 /* Background write to tty (POSIX). */ +#define SIGURG 23 /* Urgent condition on socket (4.2 BSD). */ +#define SIGXCPU 24 /* CPU limit exceeded (4.2 BSD). */ +#define SIGXFSZ 25 /* File size limit exceeded (4.2 BSD). */ +#define SIGVTALRM 26 /* Virtual alarm clock (4.2 BSD). */ +#define SIGPROF 27 /* Profiling alarm clock (4.2 BSD). */ +#define SIGWINCH 28 /* Window size change (4.3 BSD, Sun). */ +#define SIGPOLL SIGIO /* Pollable event occurred (System V). */ +#define SIGIO 29 /* I/O now possible (4.2 BSD). */ +#define SIGPWR 30 /* Power failure restart (System V). */ +#define SIGSYS 31 /* Bad system call. */ +#define SIGUNUSED 31 + +int raise(int sig); + +#ifdef __cplusplus +} +#endif + +#endif /* end of _SGX_SIGNAL_H */ + diff --git a/core/shared/platform/linux-sgx/sgx_socket.c b/core/shared/platform/linux-sgx/sgx_socket.c new file mode 100644 index 000000000..8eb545da5 --- /dev/null +++ b/core/shared/platform/linux-sgx/sgx_socket.c @@ -0,0 +1,218 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "platform_api_vmcore.h" + +#define TRACE_OCALL_FAIL() os_printf("ocall %s failed!\n", __FUNCTION__) + + +int ocall_socket(int *p_ret, int domain, int type, int protocol); +int ocall_getsockopt(int *p_ret, int sockfd, int level, int optname, + void *val_buf, unsigned int val_buf_size, + void *len_buf); + +int ocall_sendmsg(ssize_t *p_ret, int sockfd, void *msg_buf, + unsigned int msg_buf_size, int flags); +int ocall_recvmsg(ssize_t *p_ret, int sockfd, void *msg_buf, + unsigned int msg_buf_size, int flags); +int ocall_shutdown(int *p_ret, int sockfd, int how); + +int socket(int domain, int type, int protocol) +{ + int ret; + + if (ocall_socket(&ret, domain, type, protocol) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + + if (ret == -1) + errno = get_errno(); + + return ret; +} + +int getsockopt(int sockfd, int level, int optname, + void *optval, socklen_t *optlen) +{ + int ret; + unsigned int val_buf_size = *optlen; + + if (ocall_getsockopt(&ret, sockfd, level, optname, optval, + val_buf_size, (void *)optlen) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + + if (ret == -1) + errno = get_errno(); + + return ret; +} + +ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags) +{ + ssize_t ret; + int i; + char *p; + struct msghdr *msg1; + + uint64 total_size = sizeof(struct msghdr) + (uint64)msg->msg_namelen + + (uint64)msg->msg_controllen; + + total_size += sizeof(struct iovec) * (msg->msg_iovlen); + + for (i = 0; i < msg->msg_iovlen; i++) { + total_size += msg->msg_iov[i].iov_len; + } + + if (total_size >= UINT32_MAX) + return -1; + + msg1 = BH_MALLOC((uint32)total_size); + + if (msg1 == NULL) + return -1; + + p = (char*)(uintptr_t)sizeof(struct msghdr); + + if (msg->msg_name != NULL) { + msg1->msg_name = p; + memcpy((uintptr_t)p + (char *)msg1, msg->msg_name, + (size_t)msg->msg_namelen); + p += msg->msg_namelen; + } + + if (msg->msg_control != NULL) { + msg1->msg_control = p; + memcpy((uintptr_t)p + (char *)msg1, msg->msg_control, + (size_t)msg->msg_control); + p += msg->msg_controllen; + } + + if (msg->msg_iov != NULL) { + msg1->msg_iov = (struct iovec *)p; + p += (uintptr_t)(sizeof(struct iovec) * (msg->msg_iovlen)); + + for (i = 0; i < msg->msg_iovlen; i++) { + msg1->msg_iov[i].iov_base = p; + msg1->msg_iov[i].iov_len = msg->msg_iov[i].iov_len; + memcpy((uintptr_t)p + (char *)msg1, msg->msg_iov[i].iov_base, + (size_t)(msg->msg_iov[i].iov_len)); + p += msg->msg_iov[i].iov_len; + } + } + + if (ocall_sendmsg(&ret, sockfd, (void *)msg1, (uint32)total_size, + flags) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + + if (ret == -1) + errno = get_errno(); + + return ret; +} + +ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags) +{ + ssize_t ret; + int i; + char *p; + struct msghdr *msg1; + + uint64 total_size = sizeof(struct msghdr) + (uint64)msg->msg_namelen + + (uint64)msg->msg_controllen; + + total_size += sizeof(struct iovec) * (msg->msg_iovlen); + + for (i = 0; i < msg->msg_iovlen; i++) { + total_size += msg->msg_iov[i].iov_len; + } + + if (total_size >= UINT32_MAX) + return -1; + + msg1 = BH_MALLOC((uint32)total_size); + + if (msg1 == NULL) + return -1; + + memset(msg1, 0, total_size); + + p = (char*)(uintptr_t)sizeof(struct msghdr); + + if (msg->msg_name != NULL) { + msg1->msg_name = p; + p += msg->msg_namelen; + } + + if (msg->msg_control != NULL) { + msg1->msg_control = p; + p += msg->msg_controllen; + } + + if (msg->msg_iov != NULL) { + msg1->msg_iov = (struct iovec *)p; + p += (uintptr_t)(sizeof(struct iovec) * (msg->msg_iovlen)); + + for (i = 0; i < msg->msg_iovlen; i++) { + msg1->msg_iov[i].iov_base = p; + msg1->msg_iov[i].iov_len = msg->msg_iov[i].iov_len; + p += msg->msg_iov[i].iov_len; + } + } + + if (ocall_recvmsg(&ret, sockfd, (void *)msg1, (uint32)total_size, + flags) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + + p = (char *)(uintptr_t)(sizeof(struct msghdr)); + + if (msg1->msg_name != NULL) { + memcpy(msg->msg_name, (uintptr_t)p + (char *)msg1, + (size_t)msg1->msg_namelen); + p += msg1->msg_namelen; + } + + if (msg1->msg_control != NULL) { + memcpy(msg->msg_control, (uintptr_t)p + (char *)msg1, + (size_t)msg1->msg_control); + p += msg->msg_controllen; + } + + if (msg1->msg_iov != NULL) { + p += (uintptr_t)(sizeof(struct iovec) * (msg1->msg_iovlen)); + + for (i = 0; i < msg1->msg_iovlen; i++) { + memcpy(msg->msg_iov[i].iov_base, (uintptr_t)p + (char *)msg1, + (size_t)(msg1->msg_iov[i].iov_len)); + p += msg1->msg_iov[i].iov_len; + } + } + + if (ret == -1) + errno = get_errno(); + + return ret; +} + +int shutdown(int sockfd, int how) +{ + int ret; + + if (ocall_shutdown(&ret, sockfd, how) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + + if (ret == -1) + errno = get_errno(); + + return ret; +} diff --git a/core/shared/platform/linux-sgx/sgx_socket.h b/core/shared/platform/linux-sgx/sgx_socket.h new file mode 100644 index 000000000..c07035450 --- /dev/null +++ b/core/shared/platform/linux-sgx/sgx_socket.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _SGX_SOCKET_H +#define _SGX_SOCKET_H + +#include "sgx_file.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define SOL_SOCKET 1 + +#define SOCK_STREAM 1 +#define SOCK_DGRAM 2 + +#define SO_TYPE 3 + +#define MSG_OOB 0x0001 +#define MSG_PEEK 0x0002 +#define MSG_DONTROUTE 0x0004 +#define MSG_CTRUNC 0x0008 +#define MSG_PROXY 0x0010 +#define MSG_TRUNC 0x0020 +#define MSG_DONTWAIT 0x0040 +#define MSG_EOR 0x0080 +#define MSG_WAITALL 0x0100 +#define MSG_FIN 0x0200 +#define MSG_SYN 0x0400 +#define MSG_CONFIRM 0x0800 +#define MSG_RST 0x1000 +#define MSG_ERRQUEUE 0x2000 +#define MSG_NOSIGNAL 0x4000 +#define MSG_MORE 0x8000 +#define MSG_WAITFORONE 0x10000 +#define MSG_BATCH 0x40000 +#define MSG_FASTOPEN 0x20000000 +#define MSG_CMSG_CLOEXEC 0x40000000 + +#define SHUT_RD 0 +#define SHUT_WR 1 +#define SHUT_RDWR 2 + +struct msghdr { + void *msg_name; + socklen_t msg_namelen; + struct iovec *msg_iov; + int msg_iovlen; + void *msg_control; + socklen_t msg_controllen; + int msg_flags; +}; + + +int socket(int domain, int type, int protocol); + +int getsockopt(int sockfd, int level, int optname, + void *optval, socklen_t *optlen); + +ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags); + +ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags); + +int shutdown(int sockfd, int how); + +#ifdef __cplusplus +} +#endif + +#endif /* end of _SGX_SOCKET_H */ + diff --git a/core/shared/platform/linux-sgx/sgx_thread.c b/core/shared/platform/linux-sgx/sgx_thread.c index 568b515af..5d102e1cb 100644 --- a/core/shared/platform/linux-sgx/sgx_thread.c +++ b/core/shared/platform/linux-sgx/sgx_thread.c @@ -6,47 +6,138 @@ #include "platform_api_vmcore.h" #include "platform_api_extension.h" +typedef struct { + thread_start_routine_t start; + void *arg; +} thread_wrapper_arg; + +static void *os_thread_wrapper(void *arg) +{ + thread_wrapper_arg * targ = arg; + thread_start_routine_t start_func = targ->start; + void *thread_arg = targ->arg; + os_printf("THREAD CREATED %p\n", &targ); + BH_FREE(targ); + start_func(thread_arg); + return NULL; +} + +int os_thread_create_with_prio(korp_tid *tid, thread_start_routine_t start, + void *arg, unsigned int stack_size, int prio) +{ + thread_wrapper_arg *targ; + + assert(tid); + assert(start); + + targ = (thread_wrapper_arg *) BH_MALLOC(sizeof(*targ)); + if (!targ) { + return BHT_ERROR; + } + + targ->start = start; + targ->arg = arg; + + if (pthread_create(tid, NULL, os_thread_wrapper, targ) != 0) { + BH_FREE(targ); + return BHT_ERROR; + } + + return BHT_OK; +} + +int os_thread_create(korp_tid *tid, thread_start_routine_t start, void *arg, + unsigned int stack_size) +{ + return os_thread_create_with_prio(tid, start, arg, stack_size, + BH_THREAD_DEFAULT_PRIORITY); +} + korp_tid os_self_thread() { - return sgx_thread_self(); + return pthread_self(); } int os_mutex_init(korp_mutex *mutex) { - sgx_thread_mutex_t m = SGX_THREAD_MUTEX_INITIALIZER; + pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; *mutex = m; return BHT_OK; } int os_mutex_destroy(korp_mutex *mutex) { - sgx_thread_mutex_destroy(mutex); + pthread_mutex_destroy(mutex); return BHT_OK; } int os_mutex_lock(korp_mutex *mutex) { - return sgx_thread_mutex_lock(mutex); + return pthread_mutex_lock(mutex); } int os_mutex_unlock(korp_mutex *mutex) { - return sgx_thread_mutex_unlock(mutex); + return pthread_mutex_unlock(mutex); } int os_cond_init(korp_cond *cond) { - sgx_thread_cond_t c = SGX_THREAD_COND_INITIALIZER; + pthread_cond_t c = PTHREAD_COND_INITIALIZER; *cond = c; return BHT_OK; } int os_cond_destroy(korp_cond *cond) { - sgx_thread_cond_destroy(cond); + pthread_cond_destroy(cond); return BHT_OK; } +int os_cond_wait(korp_cond *cond, korp_mutex *mutex) +{ + assert(cond); + assert(mutex); + + if (pthread_cond_wait(cond, mutex) != BHT_OK) + return BHT_ERROR; + + return BHT_OK; +} + +int os_cond_reltimedwait(korp_cond *cond, korp_mutex *mutex, int useconds) +{ + os_printf("warning: SGX pthread_cond_timedwait isn't supported, " + "calling pthread_cond_wait instead!\n"); + return BHT_ERROR; +} + +int os_cond_signal(korp_cond *cond) +{ + assert(cond); + + if (pthread_cond_signal(cond) != BHT_OK) + return BHT_ERROR; + + return BHT_OK; +} + +int os_thread_join(korp_tid thread, void **value_ptr) +{ + return pthread_join(thread, value_ptr); +} + +int os_thread_detach(korp_tid thread) +{ + /* SGX pthread_detach isn't provided, return directly. */ + return 0; +} + +void os_thread_exit(void *retval) +{ + return pthread_exit(retval); +} + uint8 *os_thread_get_stack_boundary() { /* TODO: get sgx stack boundary */ diff --git a/core/shared/platform/linux-sgx/sgx_time.c b/core/shared/platform/linux-sgx/sgx_time.c index 2094d4b17..40239d5f4 100644 --- a/core/shared/platform/linux-sgx/sgx_time.c +++ b/core/shared/platform/linux-sgx/sgx_time.c @@ -5,6 +5,22 @@ #include "platform_api_vmcore.h" +#define TRACE_FUNC() os_printf("undefined %s\n", __FUNCTION__) +#define TRACE_OCALL_FAIL() os_printf("ocall %s failed!\n", __FUNCTION__) + +int ocall_clock_gettime(int *p_ret, unsigned clock_id, + void *tp_buf, unsigned int tp_buf_size); +int ocall_clock_getres(int *p_ret, int clock_id, + void *res_buf, unsigned int res_buf_size); +int ocall_utimensat(int *p_ret, int dirfd, const char *pathname, + const void *times_buf, unsigned int times_buf_size, + int flags); +int ocall_futimens(int *p_ret, int fd, + const void *times_buf, unsigned int times_buf_size); +int ocall_clock_nanosleep(int *p_ret, unsigned clock_id, int flags, + const void *req_buf, unsigned int req_buf_size, + const void *rem_buf, unsigned int rem_buf_size); + uint64 os_time_get_boot_microsecond() { @@ -12,3 +28,88 @@ os_time_get_boot_microsecond() return 0; } +int clock_getres(int clock_id, struct timespec *res) +{ + int ret; + + if (ocall_clock_getres(&ret, clock_id, (void *)res, + sizeof(struct timespec)) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + + if (ret == -1) + errno = get_errno(); + + return ret; +} + +int clock_gettime(clockid_t clock_id, struct timespec *tp) +{ + int ret; + + if(ocall_clock_gettime(&ret, clock_id, (void *)tp, + sizeof(struct timespec)) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + + if (ret == -1) + errno = get_errno(); + + return ret; +} + +int utimensat(int dirfd, const char *pathname, + const struct timespec times[2], int flags) +{ + int ret; + + if (ocall_utimensat(&ret, dirfd, pathname, (void *)times, + sizeof(struct timespec) * 2, + flags) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + + if (ret == -1) + errno = get_errno(); + + return ret; +} + +int futimens(int fd, const struct timespec times[2]) +{ + int ret; + + if (ocall_futimens(&ret, fd, (void *)times, + sizeof(struct timespec) * 2) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + + if (ret == -1) + errno = get_errno(); + + return ret; +} + +int clock_nanosleep(clockid_t clock_id, int flags, + const struct timespec *request, + struct timespec *remain) +{ + int ret; + + if (ocall_clock_nanosleep(&ret, clock_id, flags, (void *)request, + sizeof(struct timespec), + (void *)remain, + sizeof(struct timespec)) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + + if (ret == -1) + errno = get_errno(); + + return ret; +} diff --git a/core/shared/platform/linux-sgx/sgx_time.h b/core/shared/platform/linux-sgx/sgx_time.h new file mode 100644 index 000000000..2aa83b8c5 --- /dev/null +++ b/core/shared/platform/linux-sgx/sgx_time.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _SGX_TIME_H +#define _SGX_TIME_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define CLOCK_REALTIME 0 +#define CLOCK_MONOTONIC 1 +#define CLOCK_PROCESS_CPUTIME_ID 2 +#define CLOCK_THREAD_CPUTIME_ID 3 + +#define UTIME_NOW 0x3fffffff +#define UTIME_OMIT 0x3ffffffe +#define TIMER_ABSTIME 1 + +typedef long int time_t; + +typedef int clockid_t; + +struct timespec { + time_t tv_sec; + long tv_nsec; +}; + +int clock_getres(int clock_id, struct timespec *res); + +int clock_gettime(clockid_t clock_id, struct timespec *tp); + +int utimensat(int dirfd, const char *pathname, + const struct timespec times[2], int flags); +int futimens(int fd, const struct timespec times[2]); +int clock_nanosleep(clockid_t clock_id, int flags, + const struct timespec *request, + struct timespec *remain); + +#ifdef __cplusplus +} +#endif + +#endif /* end of _SGX_TIME_H */ + diff --git a/core/shared/platform/linux-sgx/sgx_wamr.edl b/core/shared/platform/linux-sgx/sgx_wamr.edl new file mode 100644 index 000000000..6eb17172c --- /dev/null +++ b/core/shared/platform/linux-sgx/sgx_wamr.edl @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +enclave { + include "stdint.h" + include "stdbool.h" + include "unistd.h" + + untrusted { + int ocall_open([in, string]const char *pathname, int flags, + bool has_mode, unsigned mode); + int ocall_openat(int dirfd, + [in, string]const char *pathname, int flags, + bool has_mode, unsigned mode); + int ocall_close(int fd); + ssize_t ocall_read(int fd, [out, size=read_size]void *buf, + size_t read_size); + off_t ocall_lseek(int fd, off_t offset, int whence); + int ocall_ftruncate(int fd, off_t length); + int ocall_fsync(int fd); + int ocall_fdatasync(int fd); + int ocall_isatty(int fd); + void ocall_fdopendir(int fd, [out]void **p_dirp); + /* implementation related to multiple thread */ + void *ocall_readdir([user_check]void *dirp); + void ocall_rewinddir([user_check]void *dirp); + void ocall_seekdir([user_check]void *dirp, long loc); + long ocall_telldir([user_check]void *dirp); + int ocall_closedir([user_check]void *dirp); + + int ocall_fstat(int fd, [out, size=buf_len]void *buf, + unsigned int buf_len); + int ocall_fstatat(int dirfd, [in, string]const char *pathname, + [out, size=buf_len]void *buf, + unsigned int buf_len, int flags); + + int ocall_mkdirat(int dirfd, [in, string]const char *pathname, + unsigned mode); + int ocall_link([in, string] const char *oldpath, + [in, string] const char *newpath); + int ocall_linkat(int olddirfd, [in, string]const char *oldpath, + int newdirfd, [in, string]const char *newpath, + int flags); + int ocall_unlinkat(int dirfd, [in, string]const char *pathname, + int flags); + ssize_t ocall_readlinkat(int dirfd, + [in, string]const char *pathname, + [out, size=bufsiz]char *buf, + size_t bufsiz); + int ocall_renameat(int olddirfd, + [in, string]const char *oldpath, + int newdirfd, + [in, string]const char *newpath); + int ocall_symlinkat([in ,string]const char *target, + int newdirfd, + [in, string]const char *linkpath); + + int ocall_ioctl(int fd, unsigned long request, + [out, size=arg_len]void *arg, + unsigned int arg_len); + int ocall_fcntl(int fd, int cmd); + int ocall_fcntl_long(int fd, int cmd, long arg); + + int ocall_realpath([in, string]const char *path, + [out, size=buf_len]char *buf, + unsigned int buf_len); + int ocall_posix_fallocate(int fd, off_t offset, off_t len); + int ocall_poll([out, size=fds_len]void *fds, unsigned nfds, + int timeout, unsigned int fds_len); + + int ocall_getopt(int argc, + [in, size=argv_buf_len]char *argv_buf, + unsigned int argv_buf_len, + [in, string]const char *optstring); + ssize_t ocall_getrandom([out, size=buflen]void *buf, size_t buflen, + unsigned int flags); + ssize_t ocall_readv(int fd, + [in, out, size=buf_size]char *iov_buf, + unsigned int buf_size, int iovcnt, + bool has_offset, off_t offset); + ssize_t ocall_writev(int fd, + [in, size=buf_size]char *iov_buf, + unsigned int buf_size, int iovcnt, + bool has_offset, off_t offset); + + /* time clock */ + int ocall_clock_gettime(unsigned clock_id, + [out, size=tp_buf_size]void *tp_buf, + unsigned int tp_buf_size); + int ocall_clock_getres(int clock_id, + [out, size=res_buf_size]void *res_buf, + unsigned int res_buf_size); + int ocall_utimensat(int dirfd, [in, string]const char *pathname, + [in, size=times_buf_size]const void *times_buf, + unsigned int times_buf_size, int flags); + int ocall_futimens(int fd, [in, size=times_buf_size]const void *times_buf, + unsigned int times_buf_size); + int ocall_clock_nanosleep(unsigned clock_id, int flags, + [in, size=req_buf_size]const void *req_buf, + unsigned int req_buf_size, + [out, size=rem_buf_size]void *rem_buf, + unsigned int rem_buf_size); + + int ocall_raise(int sig); + + int ocall_sched_yield(); + + int ocall_pthread_rwlock_init([out]void **rwlock, [user_check]void *attr); + int ocall_pthread_rwlock_destroy([user_check]void *rwlock); + int ocall_pthread_rwlock_rdlock([user_check]void *rwlock); + int ocall_pthread_rwlock_wrlock([user_check]void *rwlock); + int ocall_pthread_rwlock_unlock([user_check]void *rwlock); + + int ocall_get_errno(); + int ocall_socket(int domain, int type, int protocol); + int ocall_getsockopt(int sockfd, int level, int optname, + [out, size=val_buf_size]void *val_buf, + unsigned int val_buf_size, + [in, out, size=4]void *len_buf); + ssize_t ocall_sendmsg(int sockfd, + [in, size=msg_buf_size]void *msg_buf, + unsigned int msg_buf_size, + int flags); + ssize_t ocall_recvmsg(int sockfd, + [in, out, size=msg_buf_size]void *msg_buf, + unsigned int msg_buf_size, + int flags); + int ocall_shutdown(int sockfd, int how); + }; +}; diff --git a/core/shared/platform/linux-sgx/shared_platform.cmake b/core/shared/platform/linux-sgx/shared_platform.cmake index a92caafee..58862b552 100644 --- a/core/shared/platform/linux-sgx/shared_platform.cmake +++ b/core/shared/platform/linux-sgx/shared_platform.cmake @@ -20,7 +20,11 @@ if (NOT BUILD_UNTRUST_PART EQUAL 1) ${SGX_SDK_DIR}/include/libcxx) endif () -file (GLOB_RECURSE source_all ${PLATFORM_SHARED_DIR}/*.c) +file (GLOB source_all ${PLATFORM_SHARED_DIR}/*.c) + +file (GLOB source_all_untrusted ${PLATFORM_SHARED_DIR}/untrusted/*.c) set (PLATFORM_SHARED_SOURCE ${source_all}) +set (PLATFORM_SHARED_SOURCE_UNTRUSTED ${source_all_untrusted}) + diff --git a/core/shared/platform/linux-sgx/untrusted/file.c b/core/shared/platform/linux-sgx/untrusted/file.c new file mode 100644 index 000000000..d19c8eda7 --- /dev/null +++ b/core/shared/platform/linux-sgx/untrusted/file.c @@ -0,0 +1,288 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int ocall_open(const char *pathname, int flags, + bool has_mode, unsigned mode) +{ + if (has_mode) { + return open(pathname, flags, (mode_t)mode); + } + else { + return open(pathname, flags); + } +} + +int ocall_openat(int dirfd, + const char *pathname, int flags, + bool has_mode, unsigned mode) +{ + if (has_mode) { + return openat(dirfd, pathname, flags, (mode_t)mode); + } + else { + return openat(dirfd, pathname, flags); + } +} + +int ocall_close(int fd) +{ + return close(fd); +} + +ssize_t ocall_read(int fd, void *buf, size_t read_size) +{ + if (buf != NULL) { + return read(fd, buf, read_size); + } + else { + return -1; + } +} + +off_t ocall_lseek(int fd, off_t offset, int whence) +{ + return lseek(fd, offset, whence); +} + +int ocall_ftruncate(int fd, off_t length) +{ + return ftruncate(fd, length); +} + +int ocall_fsync(int fd) +{ + return fsync(fd); +} + +int ocall_fdatasync(int fd) +{ + return fdatasync(fd); +} + +int ocall_isatty(int fd) +{ + return isatty(fd); +} + +void ocall_fdopendir(int fd, void **dirp) +{ + if (dirp) { + *(DIR **)dirp = fdopendir(fd); + } +} + +void *ocall_readdir(void *dirp) +{ + DIR *p_dirp = (DIR *)dirp; + return readdir(p_dirp); +} + +void ocall_rewinddir(void *dirp) +{ + DIR *p_dirp = (DIR *)dirp; + if (p_dirp) { + rewinddir(p_dirp); + } +} + +void ocall_seekdir(void *dirp, long loc) +{ + DIR *p_dirp = (DIR *)dirp; + + if (p_dirp) { + seekdir(p_dirp, loc); + } +} + +long ocall_telldir(void *dirp) +{ + DIR *p_dirp = (DIR *)dirp; + if (p_dirp) { + return telldir(p_dirp); + } + return -1; +} + +int ocall_closedir(void* dirp) +{ + DIR *p_dirp = (DIR *)dirp; + if (p_dirp) { + return closedir(p_dirp); + } + return -1; +} + +int ocall_fstat(int fd, void *buf, unsigned int buf_len) +{ + return fstat(fd, (struct stat *)buf); +} + +int ocall_fstatat(int dirfd, const char *pathname, void *buf, + unsigned int buf_len, int flags) +{ + return fstatat(dirfd, pathname, (struct stat *)buf, flags); +} + +int ocall_mkdirat(int dirfd, const char *pathname, unsigned mode) +{ + return mkdirat(dirfd, pathname, (mode_t)mode); +} + +int ocall_link(const char *oldpath, const char *newpath) +{ + return link(oldpath, newpath); +} + +int ocall_linkat(int olddirfd, const char *oldpath, + int newdirfd, const char *newpath, int flags) +{ + return linkat(olddirfd, oldpath, newdirfd, newpath, flags); +} + +int ocall_unlinkat(int dirfd, const char *pathname, int flags) +{ + return unlinkat(dirfd, pathname, flags); +} + +ssize_t ocall_readlinkat(int dirfd, const char *pathname, + char *buf, size_t bufsiz) +{ + return readlinkat(dirfd, pathname, buf, bufsiz); +} + +int ocall_renameat(int olddirfd, const char *oldpath, + int newdirfd, const char *newpath) +{ + return renameat(olddirfd, oldpath, newdirfd, newpath); +} + +int ocall_symlinkat(const char *target, int newdirfd, + const char *linkpath) +{ + return symlinkat(target, newdirfd, linkpath); +} + +int ocall_ioctl(int fd, unsigned long request, + void *arg, unsigned int arg_len) +{ + /* support just int *arg temporally */ + return ioctl(fd, request, (int *)arg); +} + +int ocall_fcntl(int fd, int cmd) +{ + return fcntl(fd, cmd); +} + +int ocall_fcntl_long(int fd, int cmd, long arg) +{ + return fcntl(fd, cmd, arg); +} + +ssize_t ocall_readv(int fd, char *iov_buf, + unsigned int buf_size, int iovcnt, + bool has_offset, off_t offset) +{ + struct iovec *iov = (struct iovec *)iov_buf; + ssize_t ret; + int i; + + for (i = 0; i < iovcnt; i++) { + iov[i].iov_base = iov_buf + (unsigned)(uintptr_t)iov[i].iov_base; + } + + if (has_offset) + ret = preadv(fd, iov, iovcnt, offset); + else + ret = readv(fd, iov, iovcnt); + + return ret; +} + +ssize_t ocall_writev(int fd, char *iov_buf, + unsigned int buf_size, int iovcnt, + bool has_offset, off_t offset) +{ + struct iovec *iov = (struct iovec *)iov_buf; + int i; + ssize_t ret; + + for (i = 0; i < iovcnt; i++) { + iov[i].iov_base = iov_buf + (unsigned)(uintptr_t)iov[i].iov_base; + } + + if (has_offset) + ret = pwritev(fd, iov, iovcnt, offset); + else + ret = writev(fd, iov, iovcnt); + + return ret; +} + +int ocall_realpath(const char *path, char *buf, unsigned int buf_len) +{ + char* val = NULL; + val = realpath(path, buf); + if (val != NULL) { + return 0; + } + return -1; +} + +int ocall_posix_fallocate(int fd, off_t offset, off_t len) +{ + return posix_fallocate(fd, offset, len); +} + +int ocall_poll(void *fds, unsigned nfds, int timeout, + unsigned int fds_len) +{ + return poll((struct pollfd *)fds, (nfds_t)nfds, timeout); +} + +int ocall_getopt(int argc, char *argv_buf, unsigned int argv_buf_len, + const char *optstring) +{ + int ret; + int i; + char **argv = (char **)argv_buf; + + for (i=0; i < argc; i++) { + argv[i] = argv_buf + (uintptr_t)argv[i]; + } + + return getopt(argc, argv, optstring); +} + +ssize_t ocall_getrandom(void *buf, size_t buflen, unsigned int flags) +{ + return getrandom(buf, buflen, flags); +} + +int ocall_sched_yield() +{ + return sched_yield(); +} + +int ocall_get_errno() +{ + return errno; +} diff --git a/core/shared/platform/linux-sgx/untrusted/pthread.c b/core/shared/platform/linux-sgx/untrusted/pthread.c new file mode 100644 index 000000000..f3026874d --- /dev/null +++ b/core/shared/platform/linux-sgx/untrusted/pthread.c @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include +#include + +int ocall_pthread_rwlock_init(void **rwlock, void *attr) +{ + int ret = 0; + + *rwlock = malloc(sizeof(pthread_rwlock_t)); + if (*rwlock == NULL) + return -1; + + ret = pthread_rwlock_init((pthread_rwlock_t *)*rwlock, NULL); + if (ret != 0) { + free(*rwlock); + *rwlock = NULL; + } + (void)attr; + return ret; +} + +int ocall_pthread_rwlock_destroy(void *rwlock) +{ + pthread_rwlock_t *lock = (pthread_rwlock_t *)rwlock; + int ret; + + ret = pthread_rwlock_destroy(lock); + free(lock); + return ret; +} + +int ocall_pthread_rwlock_rdlock(void *rwlock) +{ + return pthread_rwlock_rdlock((pthread_rwlock_t *)rwlock); +} + +int ocall_pthread_rwlock_wrlock(void *rwlock) +{ + return pthread_rwlock_wrlock((pthread_rwlock_t *)rwlock); +} + +int ocall_pthread_rwlock_unlock(void *rwlock) +{ + return pthread_rwlock_unlock((pthread_rwlock_t *)rwlock); +} + diff --git a/core/shared/platform/linux-sgx/untrusted/signal.c b/core/shared/platform/linux-sgx/untrusted/signal.c new file mode 100644 index 000000000..115fbfa56 --- /dev/null +++ b/core/shared/platform/linux-sgx/untrusted/signal.c @@ -0,0 +1,10 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ +#include + +int ocall_raise(int sig) +{ + return raise(sig); +} \ No newline at end of file diff --git a/core/shared/platform/linux-sgx/untrusted/socket.c b/core/shared/platform/linux-sgx/untrusted/socket.c new file mode 100644 index 000000000..34b5d460e --- /dev/null +++ b/core/shared/platform/linux-sgx/untrusted/socket.c @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ +#include +#include +#include +#include + +int ocall_socket(int domain, int type, int protocol) +{ + return socket(domain, type, protocol); +} + +int ocall_getsockopt(int sockfd, int level, int optname, void *val_buf, + unsigned int val_buf_size, void *len_buf) +{ + return getsockopt(sockfd, level, optname, val_buf, + (socklen_t *)len_buf); +} + +ssize_t ocall_sendmsg(int sockfd, void *msg_buf, + unsigned int msg_buf_size, int flags) +{ + struct msghdr *msg = (struct msghdr *)msg_buf; + int i; + ssize_t ret; + + if (msg->msg_name != NULL) + msg->msg_name = msg_buf + (unsigned)(uintptr_t)msg->msg_name; + + if (msg->msg_control != NULL) + msg->msg_control = msg_buf + (unsigned)(uintptr_t)msg->msg_control; + + if (msg->msg_iov != NULL) { + msg->msg_iov = msg_buf + (unsigned)(uintptr_t)msg->msg_iov; + for (i = 0; i < msg->msg_iovlen; i++) { + msg->msg_iov[i].iov_base = msg_buf + (unsigned)(uintptr_t) + msg->msg_iov[i].iov_base; + } + } + + return sendmsg(sockfd, msg, flags); +} + +ssize_t ocall_recvmsg(int sockfd, void *msg_buf, unsigned int msg_buf_size, + int flags) +{ + struct msghdr *msg = (struct msghdr *)msg_buf; + int i; + ssize_t ret; + + if (msg->msg_name != NULL) + msg->msg_name = msg_buf + (unsigned)(uintptr_t)msg->msg_name; + + if (msg->msg_control != NULL) + msg->msg_control = msg_buf + (unsigned)(uintptr_t)msg->msg_control; + + if (msg->msg_iov != NULL) { + msg->msg_iov = msg_buf + (unsigned)(uintptr_t)msg->msg_iov; + for (i = 0; i msg_iovlen; i++) { + msg->msg_iov[i].iov_base = msg_buf + (unsigned)(uintptr_t) + msg->msg_iov[i].iov_base; + } + } + + return recvmsg(sockfd, msg, flags); +} + +int ocall_shutdown(int sockfd, int how) +{ + return shutdown(sockfd, how); +} \ No newline at end of file diff --git a/core/shared/platform/linux-sgx/untrusted/time.c b/core/shared/platform/linux-sgx/untrusted/time.c new file mode 100644 index 000000000..1d15e8dfd --- /dev/null +++ b/core/shared/platform/linux-sgx/untrusted/time.c @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ +#include +#include +#include +#include + + +/** time clock **/ +int ocall_clock_gettime(unsigned clock_id, void *tp_buf, + unsigned int tp_buf_size) +{ + return clock_gettime((clockid_t)clock_id, + (struct timespec *)tp_buf); +} + +int ocall_clock_getres(int clock_id, void *res_buf, + unsigned int res_buf_size) +{ + return clock_getres(clock_id, (struct timespec *)res_buf); +} + +int ocall_utimensat(int dirfd, const char *pathname, + const void *times_buf, + unsigned int times_buf_size, int flags) +{ + return utimensat(dirfd, pathname, (struct timespec *)times_buf, flags); + +} + +int ocall_futimens(int fd, const void *times_buf, + unsigned int times_buf_size) +{ + return futimens(fd, (struct timespec *)times_buf); +} + +int ocall_clock_nanosleep(unsigned clock_id, int flags, + const void *req_buf, unsigned int req_buf_size, + const void *rem_buf, unsigned int rem_buf_size) +{ + return clock_nanosleep((clockid_t)clock_id, flags, + (struct timespec *)req_buf, + (struct timespec *)rem_buf); + +} diff --git a/core/shared/platform/linux/platform_internal.h b/core/shared/platform/linux/platform_internal.h index d3bc9d2b2..1aa22ed49 100644 --- a/core/shared/platform/linux/platform_internal.h +++ b/core/shared/platform/linux/platform_internal.h @@ -10,8 +10,6 @@ #include #include #include -#include -#include #include #include #include @@ -19,15 +17,25 @@ #include #include #include +#include #include #include +#include #include #include +#include +#include #include -#include +#include +#include #include #include -#include +#include +#include +#include +#include +#include +#include #ifdef __cplusplus extern "C" { @@ -56,7 +64,6 @@ typedef pthread_t korp_thread; || defined(BUILD_TARGET_AMD_64) \ || defined(BUILD_TARGET_AARCH64) -#include #include #define OS_ENABLE_HW_BOUND_CHECK diff --git a/core/shared/platform/vxworks/platform_internal.h b/core/shared/platform/vxworks/platform_internal.h index a78366924..701ab644d 100644 --- a/core/shared/platform/vxworks/platform_internal.h +++ b/core/shared/platform/vxworks/platform_internal.h @@ -10,8 +10,6 @@ #include #include #include -#include -#include #include #include #include @@ -19,14 +17,24 @@ #include #include #include +#include #include #include +#include #include #include +#include +#include #include #include #include #include +#include +#include +#include +#include +#include +#include #ifdef __cplusplus extern "C" { @@ -55,7 +63,6 @@ typedef pthread_t korp_thread; || defined(BUILD_TARGET_AMD_64) \ || defined(BUILD_TARGET_AARCH64) -#include #include #define OS_ENABLE_HW_BOUND_CHECK diff --git a/core/shared/utils/bh_log.c b/core/shared/utils/bh_log.c index a661591dc..e1a3eb22c 100644 --- a/core/shared/utils/bh_log.c +++ b/core/shared/utils/bh_log.c @@ -41,7 +41,7 @@ bh_log(LogLevel log_level, const char *file, int line, const char *fmt, ...) snprintf(buf, sizeof(buf), "%02u:%02u:%02u:%03u", h, m, s, mills); - os_printf("[%s - %X]: ", buf, (uint32)self); + os_printf("[%s - %X]: ", buf, (uint32)(uintptr_t)self); if (file) os_printf("%s, line %d, ", file, line); diff --git a/doc/build_wamr.md b/doc/build_wamr.md index b9405633d..378fb57a9 100644 --- a/doc/build_wamr.md +++ b/doc/build_wamr.md @@ -1,33 +1,29 @@ -Build WAMR core (iwasm) +Build WAMR vmcore (iwasm) ========================= It is recommended to use the [WAMR SDK](../wamr-sdk) tools to build a project that integrates the WAMR. This document introduces how to build the WAMR minimal product which is vmcore only (no app-framework and app-mgr) for multiple platforms. +## WAMR vmcore cmake building configurations - -## iwasm VM core CMake building configurations - -By including the script `runtime_lib.cmake` under folder [build-scripts](../build-scripts) in CMakeList.txt, it is easy to build minimal product with CMake. +By including the script `runtime_lib.cmake` under folder [build-scripts](../build-scripts) in CMakeList.txt, it is easy to build minimal product with cmake. ```cmake -# add this in your CMakeList.text +# add this into your CMakeList.txt include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) add_library(vmlib ${WAMR_RUNTIME_LIB_SOURCE}) ``` - - -The script `runtime_lib.cmake` defined a number of variables for configuring the WAMR runtime features. You can set these variables in your CMakeList.txt or pass the configurations from cmake command line. +The script `runtime_lib.cmake` defines a number of variables for configuring the WAMR runtime features. You can set these variables in your CMakeList.txt or pass the configurations from cmake command line. #### **Configure platform and architecture** - **WAMR_BUILD_PLATFORM**: set the target platform. It can be set to any platform name (folder name) under folder [core/shared/platform](../core/shared/platform). -- **WAMR_BUILD_TARGET**: set the target CPU architecture. Current supported targets: X86_64, X86_32, AArch64, ARM, THUMB, XTENSA and MIPS. For AArch64, ARM and THUMB, the format is [][_VFP] where is the ARM sub-architecture and the "_VFP" suffix means VFP coprocessor registers s0-s15 (d0-d7) are used for passing arguments or returning results in standard procedure-call. Both and "_VFP" are optional. e.g. AARCH64, AARCH64V8, AARCHV8.1, ARMV7, ARMV7_VFP, THUMBV7, THUMBV7_VFP and so on. +- **WAMR_BUILD_TARGET**: set the target CPU architecture. Current supported targets are: X86_64, X86_32, AArch64, ARM, THUMB, XTENSA and MIPS. For AArch64, ARM and THUMB, the format is \\[\]\[_VFP] where \ is the ARM sub-architecture and the "_VFP" suffix means VFP coprocessor registers s0-s15 (d0-d7) are used for passing arguments or returning results in standard procedure-call. Both \ and "_VFP" are optional, e.g. AARCH64, AARCH64V8, AARCHV8.1, ARMV7, ARMV7_VFP, THUMBV7, THUMBV7_VFP and so on. - ```bash - cmake -DWAMR_BUILD_PLATFORM=linux -DWAMR_BUILD_TARGET=ARM - ``` +```bash +cmake -DWAMR_BUILD_PLATFORM=linux -DWAMR_BUILD_TARGET=ARM +``` #### **Configure interpreter** @@ -35,18 +31,18 @@ The script `runtime_lib.cmake` defined a number of variables for configuring the - **WAMR_BUILD_FAST_INTERP**=1/0:build fast (default) or classic WASM interpreter. - NOTE: the fast interpreter will run ~2X faster than classic interpreter, but it consumes about 2X memory to hold the WASM bytecode code. + NOTE: the fast interpreter runs ~2X faster than classic interpreter, but consumes about 2X memory to hold the WASM bytecode code. #### **Configure AoT and JIT** -- **WAMR_BUILD_AOT**=1/0 -- **WAMR_BUILD_JIT**=1/0 , (Disabled if no set) +- **WAMR_BUILD_AOT**=1/0, default to enable if not set +- **WAMR_BUILD_JIT**=1/0 , default to disable if not set #### **Configure LIBC** -- **WAMR_BUILD_LIBC_BUILTIN**=1/0, default to enable if no set +- **WAMR_BUILD_LIBC_BUILTIN**=1/0, default to enable if not set -- **WAMR_BUILD_LIBC_WASI**=1/0, default to enable if no set +- **WAMR_BUILD_LIBC_WASI**=1/0, default to enable if not set #### **Enable Multi-Module feature** @@ -55,7 +51,8 @@ The script `runtime_lib.cmake` defined a number of variables for configuring the #### **Enable WASM mini loader** - **WAMR_BUILD_MINI_LOADER**=1/0, default to disable if not set -Note: the mini loader doesn't check the integrity of the WASM binary file, developer must ensure that the WASM file is not mal-formed. + +> Note: the mini loader doesn't check the integrity of the WASM binary file, developer must ensure that the WASM file is well-formed. #### **Enable shared memory feature** - **WAMR_BUILD_SHARED_MEMORY**=1/0, default to disable if not set @@ -68,7 +65,7 @@ Note: the mini loader doesn't check the integrity of the WASM binary file, devel > Note: The dependent feature of lib pthread such as the `shared memory` and `thread manager` will be enabled automatically. #### **Disable boundary check with hardware trap in AOT or JIT mode** -- **WAMR_DISABLE_HW_BOUND_CHECK=1, default to enable if not set and supported by platform +- **WAMR_DISABLE_HW_BOUND_CHECK**=1/0, default to enable if not set and supported by platform > Note: by default only platform linux/darwin/android/vxworks 64-bit will enable boundary check with hardware trap in AOT or JIT mode, and the wamrc tool will generate AOT code without boundary check instructions in all 64-bit targets except SGX to improve performance. **Combination of configurations:** @@ -85,8 +82,6 @@ Or if we want to enable interpreter, disable AOT and WASI, and build as X86_32, cmake .. -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_AOT=0 -DWAMR_BUILD_LIBC_WASI=0 -DWAMR_BUILD_TARGET=X86_32 ``` - - ## Cross compilation If you are building for ARM architecture on a X86 development machine, you can use the `CMAKE_TOOLCHAIN_FILE` to set the toolchain file for cross compling. @@ -97,9 +92,7 @@ cmake .. -DCMAKE_TOOLCHAIN_FILE=$TOOL_CHAIN_FILE \ -DWAMR_BUILD_TARGET=ARM ``` -Refer to toochain sample file [`samples/simple/profiles/arm-interp/toolchain.cmake`](../samples/simple/profiles/arm-interp/toolchain.cmake) for how to build mini product for ARM target architecture. - - +Refer to toolchain sample file [`samples/simple/profiles/arm-interp/toolchain.cmake`](../samples/simple/profiles/arm-interp/toolchain.cmake) for how to build mini product for ARM target architecture. Linux ------------------------- @@ -147,40 +140,14 @@ cmake .. -DWAMR_BUILD_JIT=1 make ``` - - -Linux SGX (Intel Software Guard Extention) +Linux SGX (Intel Software Guard Extension) ------------------------- -First of all please install the [Intel SGX SDK](https://software.intel.com/en-us/sgx/sdk). - -After installing dependencies, build the source code: -``` Bash -source /environment -cd product-mini/platforms/linux-sgx/ -mkdir build -cd build -cmake .. -make -``` -This builds the libraries used by SGX enclave sample, the generated file libvmlib.a and libextlib.a will be copied to enclave-sample folder. - -Then build the enclave sample: -``` Bash -source /environment -cd enclave-sample -make -``` -The binary file app will be generated. - -To run the sample: -``` Bash -source /environment -./app -``` +Please see [Build and Port WAMR vmcore for Linux SGX](./linux_sgx.md) for the details. MacOS ------------------------- + Make sure to install Xcode from App Store firstly, and install cmake. If you use Homebrew, install cmake from the command line: @@ -197,7 +164,7 @@ cmake .. make ``` Note: -WAMR provides some features which can be easily configured by passing options to cmake, please see [Linux platform](./build_wamr.md#linux) for details. Currently in MacOS, interpreter, AoT, and builtin libc are enabled by default. +WAMR provides some features which can be easily configured by passing options to cmake, please see [WAMR vmcore cmake building configurations](./build_wamr.md#wamr-vmcore-cmake-building-configurations) for details. Currently in MacOS, interpreter, AoT, and builtin libc are enabled by default. VxWorks ------------------------- @@ -227,7 +194,7 @@ shared libraries (libc.so.1, libllvm.so.1 or libgnu.so.1 depending on the VSB, libunix.so.1) to a supported file system (eg: romfs). Note: -WAMR provides some features which can be easily configured by passing options to cmake, please see [Linux platform](./build_wamr.md#linux) for details. Currently in VxWorks, interpreter and builtin libc are enabled by default. +WAMR provides some features which can be easily configured by passing options to cmake, please see [WAMR vmcore cmake building configurations](./build_wamr.md#wamr-vmcore-cmake-building-configurations) for details. Currently in VxWorks, interpreter and builtin libc are enabled by default. Zephyr ------------------------- @@ -245,7 +212,7 @@ source ../../zephyr-env.sh ``` Note: -WAMR provides some features which can be easily configured by passing options to cmake, please see [Linux platform](./build_wamr.md#linux) for details. Currently in Zephyr, interpreter, AoT and builtin libc are enabled by default. +WAMR provides some features which can be easily configured by passing options to cmake, please see [WAMR vmcore cmake building configurations](./build_wamr.md#wamr-vmcore-cmake-building-configurations) for details. Currently in Zephyr, interpreter, AoT and builtin libc are enabled by default. AliOS-Things diff --git a/doc/embed_wamr.md b/doc/embed_wamr.md index 47e98b94d..a9524ed5d 100644 --- a/doc/embed_wamr.md +++ b/doc/embed_wamr.md @@ -6,8 +6,6 @@ Embedding WAMR guideline ## The runtime initialization - - ``` C char *buffer, error_buf[128]; wasm_module_t module; @@ -16,64 +14,61 @@ Embedding WAMR guideline wasm_exec_env_t exec_env; uint32 size, stack_size = 8092, heap_size = 8092; - // initialize the wasm runtime by default configurations + /* initialize the wasm runtime by default configurations */ wasm_runtime_init(); - // read WASM file into a memory buffer + /* read WASM file into a memory buffer */ buffer = read_wasm_binary_to_buffer(…, &size); - // Add it below if runtime needs to export native functions to WASM APP - // wasm_runtime_register_natives(...) + /* add line below if we want to export native functions to WASM app */ + wasm_runtime_register_natives(...); - // parse the WASM file from buffer and create a WASM module + /* parse the WASM file from buffer and create a WASM module */ module = wasm_runtime_load(buffer, size, error_buf, sizeof(error_buf)); - // create an instance of the WASM module (WASM linear memory is ready) - module_inst = wasm_runtime_instantiate(module, - stack_size, - heap_size, - error_buf, - sizeof(error_buf)); + /* create an instance of the WASM module (WASM linear memory is ready) */ + module_inst = wasm_runtime_instantiate(module, stack_size, heap_size, + error_buf, sizeof(error_buf)); ``` -The `wasm_runtime_init()` will use the default memory allocator from the [`core/shared/platform`](../core/shared/platform) for the runtime memory management. +The `wasm_runtime_init()` uses the default memory allocator os_malloc/os_free function from the [`core/shared/platform`](../core/shared/platform) for the runtime memory management. - - -The WAMR supports to restrict its all memory allocations in a raw buffer. It ensures the dynamics by the WASM applications won't harm the system availability, which is extremely important for embedded systems. This can be done by using `wasm_runtime_full_init()`. This function also allows you to configure the native APIs for exporting to WASM app. +WAMR supports to restrict its all memory allocations in a raw buffer. It ensures the dynamic memories used by the WASM applications won't harm the system availability, which is extremely important for embedded systems. This can be done by using `wasm_runtime_full_init()`. This function also allows you to configure the native API's for exporting to WASM app, and set the maximum thread number when multi-thread feature is enabled. Refer to the following sample: ```c -// the native functions that will be exported to WASM app +/* the native functions that will be exported to WASM app */ static NativeSymbol native_symbols[] = { EXPORT_WASM_API_WITH_SIG(display_input_read, "(*)i"), EXPORT_WASM_API_WITH_SIG(display_flush, "(iiii*)") }; -// all the runtime memory allocations are retricted in the global_heap_buf array +/* all the runtime memory allocations are retricted in the global_heap_buf array */ static char global_heap_buf[512 * 1024]; RuntimeInitArgs init_args; memset(&init_args, 0, sizeof(RuntimeInitArgs)); -// configure the memory allocator for the runtime +/* configure the memory allocator for the runtime */ init_args.mem_alloc_type = Alloc_With_Pool; init_args.mem_alloc_option.pool.heap_buf = global_heap_buf; init_args.mem_alloc_option.pool.heap_size = sizeof(global_heap_buf); -// configure the native functions being exported to WASM app +/* configure the native functions being exported to WASM app */ init_args.native_module_name = "env"; init_args.n_native_symbols = sizeof(native_symbols) / sizeof(NativeSymbol); init_args.native_symbols = native_symbols; +/* set maximum thread number if needed when multi-thread is enabled, + the default value is 4 */ +init_args.max_thread_num = max_thread_num; + /* initialize runtime environment with user configurations*/ if (!wasm_runtime_full_init(&init_args)) { - return -1; + return -1; } ``` - - ## Native calls WASM functions and passes parameters After a module is instantiated, the runtime native can lookup WASM functions by the names and call them. @@ -81,28 +76,27 @@ After a module is instantiated, the runtime native can lookup WASM functions by ```c unit32 argv[2]; - // lookup a WASM function by its name. - // The function signature can NULL here + /* lookup a WASM function by its name + The function signature can NULL here */ func = wasm_runtime_lookup_function(module_inst, "fib", NULL); - // creat a excution environment which can be used by executing WASM functions + /* creat an execution environment to execute the WASM functions */ exec_env = wasm_runtime_create_exec_env(module_inst, stack_size); - // arguments are always transferred in 32 bits element + /* arguments are always transferred in 32-bit element */ argv[0] = 8; - // call the WASM function + /* call the WASM function */ if (wasm_runtime_call_wasm(exec_env, func, 1, argv) ) { - /* the return value is stored in argv[0] */ - printf("fib function return: %d\n", argv[0]); + /* the return value is stored in argv[0] */ + printf("fib function return: %d\n", argv[0]); } else { - printf("%s\n", wasm_runtime_get_exception(module_inst)); + /* exception is thrown if call fails */ + printf("%s\n", wasm_runtime_get_exception(module_inst)); } ``` - - The parameters are transferred in an array of 32 bits elements. For parameters that occupy 4 or fewer bytes, each parameter can be a single array element. For parameters in types like double or int64, each parameter will take two array elements. The function return value will be sent back in the first one or two elements of the array according to the value type. See the sample code below: ```c @@ -116,69 +110,60 @@ The parameters are transferred in an array of 32 bits elements. For parameters t argv[0] = arg1; argv[1] = arg2; - // use memory copy for 8 bytes parameters rather than - // *(double*)(&argv[2]) = arg3 here because some archs - // like ARM, MIPS requires address is 8 aligned. - // Or use the aligned malloc or compiler align attribute - // to ensure the array address is 8 bytes aligned + /** + * use memory copy for 8-byte parameters rather than + * *(double*)(&argv[2]) = arg3 here because some archs + * like ARM, MIPS require the address must be 8-byte aligned. + * Or use the aligned malloc or compiler align attribute + * to ensure the array address is 8-byte aligned + */ memcpy(&argv[2], &arg3, sizeof(arg3)); memcpy(&argv[4], &arg4, sizeof(arg4)); - // - // attention: the arg number is 6 here since both - // arg3 and arg4 each takes 2 elements - // + + /* attention: the arg number is 6 here since both + arg3 and arg4 each takes 2 elements */ wasm_runtime_call_wasm(exec_env, func, 6, argv); - // if the return value is type of 8 bytes, it takes - // the first two array elements + /* if the return value is type of 8 bytes, it takes + the first two array elements */ memcpy(&ret, &argv[0], sizeof(ret)); - ``` - - ## Pass buffer to WASM function - - If we need to transfer a buffer to WASM function, we can pass the buffer address through a parameter. **Attention**: The sandbox will forbid the WASM code to access outside memory, we must **allocate the buffer from WASM instance's own memory space and pass the buffer address in instance's space (not the runtime native address)**. - - There are two runtime APIs available for this purpose. ```c -/* -* description: malloc a buffer from instance's private memory space. -* -* return: the buffer address in instance's memory space (pass to the WASM funciton) -* p_native_addr: return the native address of allocated memory -* size: the buffer size to allocate -*/ +/** + * malloc a buffer from instance's private memory space. + * + * return: the buffer address in instance's memory space (pass to the WASM funciton) + * p_native_addr: return the native address of allocated memory + * size: the buffer size to allocate + */ int32_t wasm_runtime_module_malloc(wasm_module_inst_t module_inst, - uint32_t size, - void **p_native_addr); + uint32_t size, void **p_native_addr); -/* -* description: malloc a buffer from instance's private memory space, -* and copy the data from another native buffer to it. -* return: the buffer address in instance's memory space (pass to the WASM funciton) -* src: the native buffer address -* size: the size of buffer to be allocated and copy data -*/ +/** + * malloc a buffer from instance's private memory space, + * and copy the data from another native buffer to it. + * + * return: the buffer address in instance's memory space (pass to the WASM funciton) + * src: the native buffer address + * size: the size of buffer to be allocated and copy data + */ int32 wasm_runtime_module_dup_data(WASMModuleInstanceCommon *module_inst, - const char *src, - uint32 size); + const char *src, uint32 size); -// free the memory allocated from module memory space +/* free the memory allocated from module memory space */ void wasm_runtime_module_free(wasm_module_inst_t module_inst, int32_t ptr); ``` - - Usage sample: ```c @@ -186,29 +171,23 @@ char * buffer = NULL; int32_t buffer_for_wasm; buffer_for_wasm = wasm_runtime_module_malloc(module_inst, 100, &buffer); -if(buffer_for_wasm != 0) -{ +if (buffer_for_wasm != 0) { unit32 argv[2]; - strncpy(buffer, "hello", 100); // use native address for accessing in runtime - argv[0] = buffer_for_wasm; // pass the buffer address for WASM space. - argv[1] = 100; // the size of buffer + strncpy(buffer, "hello", 100); /* use native address for accessing in runtime */ + argv[0] = buffer_for_wasm; /* pass the buffer address for WASM space */ + argv[1] = 100; /* the size of buffer */ wasm_runtime_call_wasm(exec_env, func, 2, argv); - // it is runtime responsibility to release the memory, - // unless the WASM app will free the passed pointer in its code + /* it is runtime embedder's responsibility to release the memory, + unless the WASM app will free the passed pointer in its code */ wasm_runtime_module_free(module_inst, buffer_for_wasm); } - ``` - - ## Pass structured data to WASM function We can't pass structure data or class objects through the pointer since the memory layout can different in two worlds. The way to do it is serialization. Refer to [export_native_api.md](./export_native_api.md) for the details. - - ## Execute wasm functions in multiple threads The `exec_env` is not thread safety, it will cause unexpected behavior if the same `exec_env` is used in multiple threads. However, we've provided two ways to execute wasm functions concurrently: @@ -219,7 +198,7 @@ The `exec_env` is not thread safety, it will cause unexpected behavior if the sa *spawn exec_env:* - `spawn exec_env` API spawn a `new_exec_env` base on the original `exec_env`, use can use it in other threads: + `spawn exec_env` API spawns a `new_exec_env` base on the original `exec_env`, use can use it in other threads: ```C new_exec_env = wasm_runtime_spawn_exec_env(exec_env); @@ -257,7 +236,7 @@ init_args.max_thread_num = THREAD_NUM; /* If this init argument is not set, the default maximum thread number is 4 */ ``` - **Note2: The wasm application should be built with `--shared-memory` and `-pthread` enabled:** +**Note2: The wasm application should be built with `--shared-memory` and `-pthread` enabled:** ```bash /opt/wasi-sdk/bin/clang -o test.wasm test.c -nostdlib -pthread \ @@ -274,8 +253,6 @@ init_args.max_thread_num = THREAD_NUM; [Here](../samples/spawn-thread) is a sample to show how to use these APIs. - - ## The deinitialization procedure ``` @@ -286,8 +263,6 @@ init_args.max_thread_num = THREAD_NUM; ``` - - ## Native calling WASM function working flow ![WAMR embed diagram](./pics/embed.PNG "WAMR embed architecture diagram") diff --git a/doc/linux_sgx.md b/doc/linux_sgx.md new file mode 100644 index 000000000..b602dcad2 --- /dev/null +++ b/doc/linux_sgx.md @@ -0,0 +1,197 @@ + +Build and Port WAMR vmcore (iwasm) for Linux SGX +================================================ + +Build WAMR vmcore (iwasm) for Linux SGX +--------------------------------------- + +First of all please install the [Intel SGX SDK](https://software.intel.com/en-us/sgx/sdk), v2.8 or later is required, and it is recommended to install the SDK to /opt/intel/sgxsdk. + +After installing the dependencies, build the source code: +``` Bash +source /environment +cd product-mini/platforms/linux-sgx/ +mkdir build +cd build +cmake .. +make +``` + +This builds two libraries required by SGX application: + - libvmlib.a for Enclave part + - libvmlib_untrusted.a for App part + +**Note:** WAMR provides some features which can be easily configured by passing options to cmake, please see [WAMR vmcore cmake building configurations](./build_wamr.md#wamr-vmcore-cmake-building-configurations) for the details. Currently in Linux SGX, fast interpreter, AOT, libc-builtin, libc-WASI and lib-pthread are enabled by default. + +Then build the enclave sample: +``` Bash +source /environment +cd enclave-sample +make +``` + +The binary file iwasm will be generated. To run the sample: + +``` Bash +source /environment +iwasm [-options] wasm_file [args...] +or: +iwasm [-options] aot_file [args...] +``` + +Port WAMR vmcore for Linux SGX +------------------------------ + +The enclave-sample creates a sample to embed wamr vmlib of Enclave part and App part to an SGX application. To port WAMR vmcore lib to SGX application, there are some steps to do: + +**Step 1: Add "sgx_wamr.edl" and "sgx_pthread.edl" into EDL file, e.g. Enclave.edl:** + +```bash +from "sgx_pthread.edl" import *; +from "sgx_wamr.edl" import *; +``` + +The sgx_wamr.edl is under ${WAMR_ROOT}/core/shared/platform/linux-sgx, so please **add it to the search path list** when generating Enclave_u.c and Enclave_t.c from Enclave.edl: + +```bash +@cd App && $(SGX_EDGER8R) --untrusted ../Enclave/Enclave.edl \ + --search-path ../Enclave \ + --search-path $(SGX_SDK)/include \ + --search-path $(WAMR_ROOT)/core/shared/platform/linux-sgx +``` + +```bash +@cd Enclave && $(SGX_EDGER8R) --trusted ../Enclave/Enclave.edl \ + --search-path ../Enclave \ + --search-path $(SGX_SDK)/include \ + --search-path $(WAMR_ROOT)/core/shared/platform/linux-sgx +``` + +**Step 2: Link libvmlib.a to Enclave part and link libvmlib_untrusted.a to App part:** + +```makefile +Enclave_Link_Flags := ... libvmlib.a ... +``` + +```makefile +App_Link_Flags := ... libvmlib_untrusted.a ... +``` + +**And link SGX pthread lib to Enclave part:** + +```makefile +Enclave_Link_Flags := ... -lsgx_pthread ... +``` + +**Step 3: Add WAMR folders and SGX SDK folders to Enclave include path:** + +```makefile +Enclave_Include_Paths := ... -I$(WAMR_ROOT)/core/iwasm/include \ + -I$(WAMR_ROOT)/core/shared/utils \ + -I$(WAMR_ROOT)/core/shared/platform/linux-sgx \ + -I$(SGX_SDK)/include \ + -I$(SGX_SDK)/include/tlibc \ + -I$(SGX_SDK)/include/stlport +``` + +**Step 4: Configure reserved memory and thread info in file Enclave config file (e.g. Enclave.config.xml) to support WAMR AOT and multi-thread, e.g:** + +```xml +0x400000 +1 +10 +``` + +**Step 5: To support log output and os_printf() function in Enclave, please implement an ocall_print function, e.g. in Enclave.edl, add:** + +```cpp +untrusted { + void ocall_print([in, string]const char* str); +}; +``` + +In App part, add: + +```cpp +void +ocall_print(const char* str) +{ + printf("%s", str); +} +``` + +And in Enclave part, set the print function: + +```cpp +#include "wasm_export.h" +#include "bh_platform.h" + +extern "C" { + typedef void (*os_print_function_t)(const char* message); + extern void os_set_print_function(os_print_function_t pf); + + void + enclave_print(const char *message) + { + ocall_print(message); + } +} + +// In the beginning of Enclave initialization, add: +os_set_print_function(enclave_print); +``` + +Embed WAMR vmcore in Linux SGX +------------------------------ + +Normally we can embed WAMR vmcore in Linux SGX by calling the vmcore exported API's, see [Embed WAMR guide](./embed_wamr.md) for the details. And the the ecall_iwasm_main() function in file Enclave.cpp of enclave-sample also provides sample to invoke wasm app main function with wasm file buffer: + +```cpp +void +ecall_iwasm_main(uint8_t *wasm_file_buf, uint32_t wasm_file_size); +``` + +The enclave-sample also wraps an ecall function to receive commands from App to Enclave, and handle the commands in Enclave by calling the related WAMR vmcore API. The commands and related API's are: + +```cpp +typedef enum EcallCmd { + CMD_INIT_RUNTIME = 0, /* wasm_runtime_init/full_init() */ + CMD_LOAD_MODULE, /* wasm_runtime_load() */ + CMD_INSTANTIATE_MODULE, /* wasm_runtime_instantiate() */ + CMD_LOOKUP_FUNCTION, /* wasm_runtime_lookup_function() */ + CMD_CREATE_EXEC_ENV, /* wasm_runtime_create_exec_env() */ + CMD_CALL_WASM, /* wasm_runtime_call_wasm */ + CMD_EXEC_APP_FUNC, /* wasm_application_execute_func() */ + CMD_EXEC_APP_MAIN, /* wasm_application_execute_main() */ + CMD_GET_EXCEPTION, /* wasm_runtime_get_exception() */ + CMD_DEINSTANTIATE_MODULE, /* wasm_runtime_deinstantiate() */ + CMD_UNLOAD_MODULE, /* wasm_runtime_unload() */ + CMD_DESTROY_RUNTIME, /* wasm_runtime_destroy() */ + CMD_SET_WASI_ARGS, /* wasm_runtime_set_wasi_args() */ + CMD_SET_LOG_LEVEL, /* bh_log_set_verbose_level() */ +}; +``` + +Others +------ + +- Please add "-sgx" option when generating AoT file for SGX platform, e.g.: + + ```bash + wamrc -sgx -o test.aot test.wasm + ``` + +- The default max heap size of Enclave is 16 MB, it might be not enough when executing some workloads, please modify it in Enclave/Enclave.config.xml with a larger size when exception was thrown: + + ```bash + Exception: fail to enlarge memory. + or + Exception: allocate memory failed. + ``` + + Enclave/Enclave.config.xml, default max heap size is 16 MB: + + ```xml + 0x1000000 + ``` + diff --git a/product-mini/platforms/linux-sgx/CMakeLists.txt b/product-mini/platforms/linux-sgx/CMakeLists.txt index fa6fedac8..4ea38792d 100644 --- a/product-mini/platforms/linux-sgx/CMakeLists.txt +++ b/product-mini/platforms/linux-sgx/CMakeLists.txt @@ -48,8 +48,23 @@ if (NOT DEFINED WAMR_BUILD_LIBC_BUILTIN) endif () if (NOT DEFINED WAMR_BUILD_LIBC_WASI) - # Disable libc wasi support by default - set (WAMR_BUILD_LIBC_WASI 0) + # Enable libc wasi support by default + set (WAMR_BUILD_LIBC_WASI 1) +endif () + +if (NOT DEFINED WAMR_BUILD_FAST_INTERP) + # Enable fast interpreter + set (WAMR_BUILD_FAST_INTERP 1) +endif () + +if (NOT DEFINED WAMR_BUILD_MULTI_MODULE) + # Enable multiple modules + set (WAMR_BUILD_MULTI_MODULE 0) +endif () + +if (NOT DEFINED WAMR_BUILD_LIB_PTHREAD) + # Enable pthread library by default + set (WAMR_BUILD_LIB_PTHREAD 1) endif () if (COLLECT_CODE_COVERAGE EQUAL 1) @@ -62,49 +77,14 @@ set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99 -ffunction-sections -fdata-secti -nostdinc -fvisibility=hidden -fpie" ) set (WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../..) -set (SHARED_DIR ${WAMR_ROOT_DIR}/core/shared) -set (IWASM_DIR ${WAMR_ROOT_DIR}/core/iwasm) -set (APP_FRAMEWORK_DIR ${WAMR_ROOT_DIR}/core/app-framework) -# include the build config template file -include (${WAMR_ROOT_DIR}/build-scripts/config_common.cmake) +include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) +add_library(vmlib ${WAMR_RUNTIME_LIB_SOURCE}) -include_directories (${SHARED_DIR}/include - ${IWASM_DIR}/include) - -enable_language (ASM) - -include (${SHARED_DIR}/platform/${WAMR_BUILD_PLATFORM}/shared_platform.cmake) -include (${SHARED_DIR}/mem-alloc/mem_alloc.cmake) -include (${SHARED_DIR}/utils/shared_utils.cmake) -if (WAMR_BUILD_LIBC_BUILTIN EQUAL 1) - include (${IWASM_DIR}/libraries/libc-builtin/libc_builtin.cmake) -endif () -if (WAMR_BUILD_LIBC_WASI EQUAL 1) - include (${IWASM_DIR}/libraries/libc-wasi/libc_wasi.cmake) -endif () - -include (${IWASM_DIR}/common/iwasm_common.cmake) - -if (WAMR_BUILD_INTERP EQUAL 1 OR WAMR_BUILD_JIT EQUAL 1) - include (${IWASM_DIR}/interpreter/iwasm_interp.cmake) -endif () - -if (WAMR_BUILD_AOT EQUAL 1) - include (${IWASM_DIR}/aot/iwasm_aot.cmake) - if (WAMR_BUILD_JIT EQUAL 1) - include (${IWASM_DIR}/compilation/iwasm_compl.cmake) - endif () -endif () - -add_library (vmlib - ${PLATFORM_SHARED_SOURCE} - ${MEM_ALLOC_SHARED_SOURCE} - ${UTILS_SHARED_SOURCE} - ${LIBC_BUILTIN_SOURCE} - ${LIBC_WASI_SOURCE} - ${IWASM_COMMON_SOURCE} - ${IWASM_INTERP_SOURCE} - ${IWASM_AOT_SOURCE} - ${IWASM_COMPL_SOURCE}) +add_custom_command ( + OUTPUT libvmlib_untrusted.a + COMMAND mkdir -p untrusted && cd untrusted && + ${CMAKE_C_COMPILER} -c ${PLATFORM_SHARED_SOURCE_UNTRUSTED} + COMMAND ${CMAKE_AR} rc libvmlib_untrusted.a untrusted/*.o) +add_custom_target (vmlib_untrusted ALL DEPENDS libvmlib_untrusted.a) diff --git a/product-mini/platforms/linux-sgx/enclave-sample/App/App.cpp b/product-mini/platforms/linux-sgx/enclave-sample/App/App.cpp index a6d502928..350966192 100644 --- a/product-mini/platforms/linux-sgx/enclave-sample/App/App.cpp +++ b/product-mini/platforms/linux-sgx/enclave-sample/App/App.cpp @@ -27,7 +27,7 @@ #define TOKEN_FILENAME "enclave.token" #define ENCLAVE_FILENAME "enclave.signed.so" -#define MAX_PATH FILENAME_MAX +#define MAX_PATH 1024 #define TEST_OCALL_API 0 @@ -39,10 +39,25 @@ ocall_print(const char* str) printf("%s", str); } -static void -print_error_message(sgx_status_t ret) +static char * +get_exe_path(char *path_buf, unsigned path_buf_size) { - printf("SGX error code: %d\n", ret); + ssize_t i; + ssize_t size = readlink("/proc/self/exe", + path_buf, path_buf_size - 1); + + if (size < 0 || (size >= path_buf_size - 1)) { + return NULL; + } + + path_buf[size] = '\0'; + for (i = size - 1; i >= 0; i--) { + if (path_buf[i] == '/') { + path_buf[i + 1] = '\0'; + break; + } + } + return path_buf; } /* Initialize the enclave: @@ -54,16 +69,27 @@ static int enclave_init(sgx_enclave_id_t *p_eid) { - char token_path[MAX_PATH] = {'\0'}; - sgx_launch_token_t token = {0}; + char token_path[MAX_PATH] = { '\0' }; + char enclave_path[MAX_PATH] = { '\0' }; + const char *home_dir; + sgx_launch_token_t token = { 0 }; sgx_status_t ret = SGX_ERROR_UNEXPECTED; int updated = 0; + size_t write_num, enc_file_len; + FILE *fp; + + enc_file_len = strlen(ENCLAVE_FILENAME); + if (!get_exe_path(enclave_path, sizeof(enclave_path) - enc_file_len)) { + printf("Failed to get exec path\n"); + return -1; + } + memcpy(enclave_path + strlen(enclave_path), ENCLAVE_FILENAME, enc_file_len); /* Step 1: try to retrieve the launch token saved by last transaction * if there is no token, then create a new one. */ /* try to get the token saved in $HOME */ - const char *home_dir = getpwuid(getuid())->pw_dir; + home_dir = getpwuid(getuid())->pw_dir; if (home_dir != NULL && (strlen(home_dir) + strlen("/") + sizeof(TOKEN_FILENAME) + 1) <= MAX_PATH) { @@ -77,9 +103,10 @@ enclave_init(sgx_enclave_id_t *p_eid) strncpy(token_path, TOKEN_FILENAME, sizeof(TOKEN_FILENAME)); } - FILE *fp = fopen(token_path, "rb"); + fp = fopen(token_path, "rb"); if (fp == NULL && (fp = fopen(token_path, "wb")) == NULL) { - printf("Warning: Failed to create/open the launch token file \"%s\".\n", token_path); + printf("Warning: Failed to create/open the launch token file \"%s\".\n", + token_path); } if (fp != NULL) { @@ -94,9 +121,15 @@ enclave_init(sgx_enclave_id_t *p_eid) /* Step 2: call sgx_create_enclave to initialize an enclave instance */ /* Debug Support: set 2nd parameter to 1 */ - ret = sgx_create_enclave(ENCLAVE_FILENAME, SGX_DEBUG_FLAG, &token, &updated, p_eid, NULL); + ret = sgx_create_enclave(ENCLAVE_FILENAME, SGX_DEBUG_FLAG, + &token, &updated, p_eid, NULL); + if (ret != SGX_SUCCESS) + /* Try to load enclave.sign.so from the path of exe file */ + ret = sgx_create_enclave(enclave_path, SGX_DEBUG_FLAG, + &token, &updated, p_eid, NULL); if (ret != SGX_SUCCESS) { - print_error_message(ret); + printf("Failed to create enclave from %s, error code: %d\n", + ENCLAVE_FILENAME, ret); if (fp != NULL) fclose(fp); return -1; @@ -114,7 +147,7 @@ enclave_init(sgx_enclave_id_t *p_eid) if (fp == NULL) return 0; - size_t write_num = fwrite(token, 1, sizeof(sgx_launch_token_t), fp); + write_num = fwrite(token, 1, sizeof(sgx_launch_token_t), fp); if (write_num != sizeof(sgx_launch_token_t)) printf("Warning: Failed to save launch token to \"%s\".\n", token_path); @@ -129,14 +162,23 @@ read_file_to_buffer(const char *filename, uint32_t *ret_size) FILE *file; int file_size, read_size; - if (!(file = fopen(filename, "r"))) + if (!filename || !ret_size) { + printf("Read file to buffer failed: invalid filename or ret size.\n"); return NULL; + } + + if (!(file = fopen(filename, "r"))) { + printf("Read file to buffer failed: open file %s failed.\n", + filename); + return NULL; + } fseek(file, 0, SEEK_END); file_size = ftell(file); fseek(file, 0, SEEK_SET); if (!(buffer = (unsigned char*)malloc(file_size))) { + printf("Read file to buffer failed: alloc memory failed.\n"); fclose(file); return NULL; } @@ -145,6 +187,7 @@ read_file_to_buffer(const char *filename, uint32_t *ret_size) fclose(file); if (read_size < file_size) { + printf("Read file to buffer failed: read file content failed.\n"); free(buffer); return NULL; } @@ -233,7 +276,6 @@ typedef enum EcallCmd { CMD_DESTROY_RUNTIME, /* wasm_runtime_destroy() */ CMD_SET_WASI_ARGS, /* wasm_runtime_set_wasi_args() */ CMD_SET_LOG_LEVEL, /* bh_log_set_verbose_level() */ - CMD_SET_MAX_THREAD_NUM, /* wasm_runtime_set_max_thread_num() */ } EcallCmd; static void @@ -310,14 +352,15 @@ set_log_verbose_level(int log_verbose_level) } static bool -init_runtime(bool alloc_with_pool) +init_runtime(bool alloc_with_pool, uint32_t max_thread_num) { - uint64_t ecall_args[1]; + uint64_t ecall_args[2]; ecall_args[0] = alloc_with_pool; + ecall_args[1] = max_thread_num; if (SGX_SUCCESS != ecall_handle_command(g_eid, CMD_INIT_RUNTIME, (uint8_t *)ecall_args, - sizeof(uint64_t))) { + sizeof(uint64_t) * 2)) { printf("Call ecall_handle_command() failed.\n"); return false; } @@ -536,6 +579,7 @@ main(int argc, char *argv[]) uint32_t dir_list_size = 0; const char *env_list[8] = { NULL }; uint32_t env_list_size = 0; + uint32_t max_thread_num = 4; if (enclave_init(&g_eid) < 0) { std::cout << "Fail to initialize enclave." << std::endl; @@ -544,7 +588,11 @@ main(int argc, char *argv[]) #if TEST_OCALL_API != 0 { + if (!init_runtime(alloc_with_pool, max_thread_num)) { + return -1; + } ecall_iwasm_test(g_eid); + destroy_runtime(); return 0; } #endif @@ -610,8 +658,7 @@ main(int argc, char *argv[]) else if (!strncmp(argv[0], "--max-threads=", 14)) { if (argv[0][14] == '\0') return print_help(); - /*wasm_runtime_set_max_thread_num(atoi(argv[0] + 14));*/ - /* TODO */ + max_thread_num = atoi(argv[0] + 14); } else return print_help(); @@ -623,7 +670,7 @@ main(int argc, char *argv[]) wasm_file = argv[0]; /* Init runtime */ - if (!init_runtime(alloc_with_pool)) { + if (!init_runtime(alloc_with_pool, max_thread_num)) { return -1; } diff --git a/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.config.xml b/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.config.xml index 94d7e1043..6a48563ea 100644 --- a/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.config.xml +++ b/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.config.xml @@ -2,9 +2,9 @@ 0 0 - 0x40000 - 0x400000 - 0x100000 + 0x100000 + 0x1000000 + 0x400000 1 10 1 diff --git a/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.cpp b/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.cpp index 7d4472851..72bae7b90 100644 --- a/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.cpp +++ b/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.cpp @@ -38,7 +38,6 @@ typedef enum EcallCmd { CMD_DESTROY_RUNTIME, /* wasm_runtime_destroy() */ CMD_SET_WASI_ARGS, /* wasm_runtime_set_wasi_args() */ CMD_SET_LOG_LEVEL, /* bh_log_set_verbose_level() */ - CMD_SET_MAX_THREAD_NUM, /* wasm_runtime_set_max_thread_num() */ } EcallCmd; typedef struct EnclaveModule { @@ -54,7 +53,11 @@ typedef struct EnclaveModule { uint32 wasi_argc; } EnclaveModule; -static char global_heap_buf[2 * 1024 * 1024] = { 0 }; +#if WASM_ENABLE_SPEC_TEST == 0 +static char global_heap_buf[10 * 1024 * 1024] = { 0 }; +#else +static char global_heap_buf[100 * 1024 * 1024] = { 0 }; +#endif static void set_error_buf(char *error_buf, uint32 error_buf_size, const char *string) @@ -66,16 +69,23 @@ set_error_buf(char *error_buf, uint32 error_buf_size, const char *string) static void handle_cmd_init_runtime(uint64 *args, uint32 argc) { - bool alloc_with_pool = true; + bool alloc_with_pool; + uint32 max_thread_num; RuntimeInitArgs init_args; + bh_assert(argc == 2); + os_set_print_function(enclave_print); - if (argc > 0) { - alloc_with_pool = (bool)args[0]; - } +#if WASM_ENABLE_SPEC_TEST == 0 + alloc_with_pool = (bool)args[0]; +#else + alloc_with_pool = true; +#endif + max_thread_num = (uint32)args[1]; memset(&init_args, 0, sizeof(RuntimeInitArgs)); + init_args.max_thread_num = max_thread_num; if (alloc_with_pool) { init_args.mem_alloc_type = Alloc_With_Pool; @@ -290,15 +300,6 @@ handle_cmd_set_log_level(uint64 *args, uint32 argc) #endif } -static void -handle_cmd_set_max_thread_num(uint64 *args, uint32 argc) -{ -#if WASM_ENABLE_LIB_PTHREAD != 0 - LOG_VERBOSE("Set max thread num to %d.\n", (uint32)args[0]); - wasm_runtime_set_max_thread_num((uint32)args[0]); -#endif -} - static void handle_cmd_set_wasi_args(uint64 *args, int32 argc) { @@ -379,16 +380,14 @@ handle_cmd_set_wasi_args(uint64 *args, int32 argc) p += sizeof(char *) * wasi_argc; } -#if WASM_ENABLE_LIBC_WASI != 0 wasm_runtime_set_wasi_args(enclave_module->module, (const char **)enclave_module->wasi_dir_list, dir_list_size, NULL, 0, (const char **)enclave_module->wasi_env_list, env_list_size, - envclave_module->wasi_argv, - envclave_module->wasi_argc); -#endif + enclave_module->wasi_argv, + enclave_module->wasi_argc); *args_org = true; } @@ -441,9 +440,6 @@ ecall_handle_command(unsigned cmd, case CMD_SET_LOG_LEVEL: handle_cmd_set_log_level(args, argc); break; - case CMD_SET_MAX_THREAD_NUM: - handle_cmd_set_max_thread_num(args, argc); - break; default: LOG_ERROR("Unknown command %d\n", cmd); break; diff --git a/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.edl b/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.edl index 5b3bde341..752e135d1 100644 --- a/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.edl +++ b/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.edl @@ -5,6 +5,8 @@ enclave { from "sgx_tstdc.edl" import *; + from "sgx_pthread.edl" import *; + from "sgx_wamr.edl" import *; trusted { /* define ECALLs here. */ @@ -13,6 +15,7 @@ enclave { unsigned cmd_buf_size); public void ecall_iwasm_main([user_check]uint8_t *wasm_file_buf, uint32_t wasm_file_size); + public void ecall_iwasm_test(); }; untrusted { diff --git a/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave_test.cpp b/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave_test.cpp new file mode 100644 index 000000000..12632a029 --- /dev/null +++ b/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave_test.cpp @@ -0,0 +1,416 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ +#include +#include +#include "Enclave_t.h" +#include "wasm_export.h" +#include "bh_platform.h" + +void ecall_iwasm_test() +{ + ocall_print(" Prepare to invoke sgx_open ... ==>\n\n"); + + /* creat test.txt firstly */ + char file[] = "test.txt"; + char file_hd_ln[] = "test_hd_ln.txt"; + char file_sf_ln[] = "test_sf_ln.txt"; + char rlt_dir_path[] = "./tmp"; + char rlt_dir_path_new[] = "./tmp_new"; + char *str0 = (char *)"good luck, "; + char *str1 = (char *)"have fun!"; + + char buf0[4], buf1[4]; + struct iovec iov_w[2]; + struct iovec iov_r[2]; + + char buf[2048]; + ssize_t total_size; + ssize_t s_ret; + int fd; + int dird; + int file_buf; + int ret; + long ret_l; + DIR *dirp; + struct dirent *p_dirent; + struct stat *statbuf; + struct pollfd fds[1]; + char *res; + + /** getopt value **/ + int argc = 3; + char n_1[] = "./main"; + char n_2[] = "-a"; + char n_3[] = "test.txt"; + + char *argv[3]; + argv[0] = n_1; + argv[1] = n_2; + argv[2] = n_3; + + /* time clock */ + struct timespec ts; + struct timespec t_res; + struct timespec times[2]; + struct stat statbuf_2; + times[0] = statbuf_2.st_atim; + times[1] = statbuf_2.st_mtim; + struct timespec rqtp; + struct timespec rmtp; + rqtp.tv_sec = 0; + rqtp.tv_nsec = 0; + + /** mkdirat **/ + /* mkdir tmp in current directory for test + * if the ./tmp directory has exits, mkdirat will fail + */ + ret = mkdirat(AT_FDCWD, rlt_dir_path, 0755); + if (ret == 0) { + ocall_print("\tOperation mkdirat success.\n"); + } + + /* flags: + 0100: - O_CREAT + 02 : - O_RDWR */ + /** 1. open **/ + fd = open(file, O_RDWR); + if (fd !=-1) { + ocall_print("\tOperation open test_open.txt success.\n"); + } + + /** read **/ + total_size = read(fd, buf, 2048); + if (total_size != -1) { + ocall_print("\tOperation read test_open.txt success.\n"); + ocall_print("\t\tthe details of the file: "); + ocall_print(buf); + ocall_print("\n"); + } + + /** lseek **/ + ret = lseek(fd, 1, SEEK_CUR); + if (ret != -1) { + ocall_print("\tOperation lseek success.\n"); + } + + /** ftruncate **/ + ret = ftruncate(fd, 0); + if (ret == 0) { + ocall_print("\tOperation ftruncate success.\n"); + } + + /** fdatasync **/ + ret = fdatasync(fd); + if (ret == 0) { + ocall_print("\tOperation fdatasync success.\n"); + } + + /** isatty **/ + ret = isatty(fd); + if (ret == 0) { + ocall_print("\tOperation fisatty success.\n"); + } + + /** fsync **/ + ret = fsync(fd); + if (ret == 0) { + ocall_print("\tOperation fsync success.\n"); + } + + /** 1. close **/ + ret = close(fd); + if (ret != -1) { + ocall_print("\tOperation close success.\n"); + } + + /*----------------------------------------------------------------*/ + + /**-- DIR --**/ + /** fdopendir **/ + /* 2. open */ + dird = open(rlt_dir_path, O_RDONLY); + dirp = fdopendir(dird); + if (dirp != NULL) { + ocall_print("\tOperation fdopendir success.\n"); + } + + /** readdir **/ + p_dirent = readdir(dirp); + if (p_dirent != NULL) { + ocall_print("\tOperation readdir success.\t"); + ocall_print(p_dirent -> d_name); + ocall_print("\n"); + } + + /** rewinddir **/ + rewinddir(dirp); + + /** seekdir **/ + seekdir(dirp, 1); + + /** telldir **/ + ret_l = telldir(dirp); + if (ret_l != -1) { + ocall_print("\tOperation telldir success. \n"); + } + + /** closedir **/ + ret = closedir(dirp); + if (ret == 0 ) { + ocall_print("\tOperation closedir success. \n"); + } + /* 2. close */ + close(dird); + + /*----------------------------------------------------------------*/ + + /** fstat **/ + /** 3. open file firstly **/ + fd = open(file, O_RDWR); + statbuf = (stat *)malloc(sizeof(stat)); + ret = fstat(fd, statbuf); + if (ret == 0) { + ocall_print("\tOperation fstat success. \n"); + } + free(statbuf); + /* 3. close */ + close(fd); + + /*----------------------------------------------------------------*/ + + /** fstatat **/ + /* 4. open */ + dird = open(rlt_dir_path, O_RDONLY); + ret = fstatat(AT_FDCWD, rlt_dir_path, statbuf, 0); + if (ret == 0) { + ocall_print("\tOperation fstatat success. \n"); + } + + /** renameat **/ + ret = renameat(AT_FDCWD, rlt_dir_path, AT_FDCWD, rlt_dir_path_new); + if (ret == 0) { + ocall_print("\tOperation renameat ./tmp to " + "./tmp_new success. \n"); + } + renameat(AT_FDCWD, rlt_dir_path_new, AT_FDCWD, rlt_dir_path); + + /** link **/ + ret = link(file, file_hd_ln); + if (ret == 0) { + ocall_print("\tOperation link success. \n"); + } + + /** unlinkat **/ + ret = unlinkat(AT_FDCWD, file_hd_ln, 0); + if (ret == 0) { + ocall_print("\tOperation unlinkat success. \n"); + } + + /** linkat **/ + ret = linkat(AT_FDCWD, file, AT_FDCWD, file_hd_ln, 0); + if (ret == 0) { + ocall_print("\tOperation linkat success. \n"); + } + /* delete hard link file */ + unlinkat(AT_FDCWD, file_hd_ln, 0); + + /** symlinkat **/ + ret = symlinkat(file, AT_FDCWD, file_sf_ln); + if (ret == 0) { + ocall_print("\tOperation symlinkat from test.txt " + "to text_sf_ln.txt success. \n"); + } + /** readlinkat **/ + total_size = readlinkat(AT_FDCWD, file_sf_ln, buf, sizeof(buf)); + if (total_size != -1) { + ocall_print("\tOperation readlinkat success. \n"); + ocall_print("\t\t the link details of the file is: "); + ocall_print(buf); + ocall_print("\n"); + } + /* delete soft link file */ + unlinkat(AT_FDCWD, file_sf_ln, 0); + /* 4. close */ + close(dird); + + /*----------------------------------------------------------------*/ + + /* 5. open */ + fd = open(file, O_RDWR); + /** ioctl **/ + ret = ioctl(fd, FIONREAD, &file_buf); + if (ret == 0) { + ocall_print("\tOperation ioctl success. \n"); + } + /** fcntl(fd, cmd) **/ + ret = fcntl(fd, F_GETFD); + if (ret != 0 || ret != -1) { + ocall_print("\tOperation fcntl_1 success. \n"); + } + /** fcntl(fd, cmd, long) **/ + ret = fcntl(fd, F_SETFD, ret); + if (ret != 0 || ret != -1) { + ocall_print("\tOperation fcntl_2 success. \n"); + } + + /* 5. close */ + close(fd); + + /*----------------------------------------------------------------*/ + + /** posix_fallocate **/ + /* 6. open */ + fd = open(file, O_RDWR); + ret = posix_fallocate(fd, 1, 1); + if (ret != 0 || ret != -1) { + ocall_print("\tOperation posix_fallocate success. \n"); + } + /* 6. close */ + close(fd); + + /** poll **/ + ret = poll(fds, 1, 10); + if (ret != 0 || ret != -1) { + ocall_print("\tOperation poll success. \n"); + } + + /** realpath **/ + res = realpath(file, res); + if (res) { + ocall_print("\tOperation realpath success. \n"); + ocall_print("\t\t the absolute path of the file is: "); + ocall_print(res); + ocall_print("\n"); + } + + /** getrandom **/ + total_size = getrandom(buf, 1024, 0); + if (ret != -1) { + ocall_print("\tOperation getrandom success. \n"); + } + + /** writev **/ + /* 7. open */ + fd = open(file, O_RDWR); + iov_w[0].iov_base = str0; + iov_w[0].iov_len = strlen(str0); + iov_w[1].iov_base = str1; + iov_w[1].iov_len = strlen(str1); + + s_ret = writev(fd, iov_w, 2); + if (s_ret != -1) { + ocall_print("\tOperation writev success. \n"); + } + + /** readv **/ + iov_r[0].iov_base = buf0; + iov_r[0].iov_len = sizeof(buf0) - 1; + iov_r[1].iov_base = buf1; + iov_r[1].iov_len = sizeof(buf1) - 1; + + s_ret = readv(fd, iov_r, 2); + if (s_ret != -1) { + ocall_print("\tOperation readv success. \n"); + ocall_print("\t\t"); + ocall_print(buf0); + ocall_print(buf1); + ocall_print("\n"); + } + + iov_r[0].iov_base = buf0; + iov_r[0].iov_len = sizeof(buf0) - 1; + iov_r[1].iov_base = buf1; + iov_r[1].iov_len = sizeof(buf1) - 1; + + s_ret = preadv(fd, iov_r, 2, 2); + if (s_ret != -1) { + ocall_print("\tOperation readv success. \n"); + ocall_print("\t\t"); + ocall_print(buf0); + ocall_print(buf1); + ocall_print("\n"); + } + /* 7. close */ + close(fd); + + /** getopt **/ + while((ret = getopt(argc, argv, "f:abc")) != -1){ //get option from the getopt() method + switch(ret){ + //For option i, r, l, print that these are options + case 'a': + case 'b': + case 'c': + ocall_print("\tGiven Option operation success. \n"); + break; + case 'f': //here f is used for some file name + ocall_print("\tGiven File operation success.\n"); + break; + case '?': //used for some unknown options + ocall_print("\tunknown option trigger success.\n"); + break; + } + } + + /** sched_yield **/ + ret = sched_yield(); + if (ret == 0) { + ocall_print("\tOperation sched_yield success. \n"); + } + + /** clock_gettime **/ + ret = clock_gettime(CLOCK_REALTIME, &ts); + if (ret == 0) { + ocall_print("\tOperation clock_gettime success. \n"); + } + + /** clock_getres **/ + ret = clock_getres(CLOCK_REALTIME, &t_res); + if (ret == 0) { + ocall_print("\tOperation clock_getres success. \n"); + } + + /** futimens **/ + /* 8. open */ + fd = open(file, O_RDWR); + ret = futimens(fd, NULL); + if (ret == 0) { + ocall_print("\tOperation futimens NULL success. \n"); + } + + ret = futimens(fd, times); + if (ret == 0) { + ocall_print("\tOperation futimens times[2] success. \n"); + } + /* 8. close */ + close(fd); + + /** utimensat **/ + /* 9. open */ + dird = open(rlt_dir_path, O_RDONLY); + ret = utimensat(AT_FDCWD, file, NULL, AT_SYMLINK_NOFOLLOW); + if (ret == 0) { + ocall_print("\tOperation utimensat NULL success. \n"); + } + + ret = utimensat(AT_FDCWD, file, times, AT_SYMLINK_NOFOLLOW); + if (ret == 0) { + ocall_print("\tOperation utimensat times[2] success. \n"); + } + /* 9. close */ + close(fd); + + /** clock_nanosleep **/ + ret = clock_nanosleep(CLOCK_REALTIME, 0, &rqtp, NULL); + if (ret == 0) { + ocall_print("\tOperation clock_nanosleep NULL success. \n"); + } + + ret = clock_nanosleep(CLOCK_REALTIME, 0, &rqtp, &rmtp); + if (ret == 0) { + ocall_print("\tOperation clock_nanosleep 2 success. \n"); + } + + ocall_print("\n<== ... End test\n"); +} \ No newline at end of file diff --git a/product-mini/platforms/linux-sgx/enclave-sample/Makefile b/product-mini/platforms/linux-sgx/enclave-sample/Makefile index 57074f141..f5467319d 100644 --- a/product-mini/platforms/linux-sgx/enclave-sample/Makefile +++ b/product-mini/platforms/linux-sgx/enclave-sample/Makefile @@ -7,6 +7,7 @@ SGX_SDK ?= /opt/intel/sgxsdk SGX_MODE ?= SIM SGX_ARCH ?= x64 SGX_DEBUG ?= 0 +SPEC_TEST ?= 0 ifeq ($(shell getconf LONG_BIT), 32) SGX_ARCH := x86 @@ -33,9 +34,9 @@ endif endif ifeq ($(SGX_DEBUG), 1) - SGX_COMMON_CFLAGS += -O0 -g + SGX_COMMON_CFLAGS += -O0 -g else - SGX_COMMON_CFLAGS += -O2 + SGX_COMMON_CFLAGS += -O2 endif ######## App Settings ######## @@ -56,15 +57,15 @@ App_C_Flags := $(SGX_COMMON_CFLAGS) -fPIC -Wno-attributes $(App_Include_Paths) # Prerelease - Macro NDEBUG and EDEBUG enabled. # Release - Macro NDEBUG enabled. ifeq ($(SGX_DEBUG), 1) - App_C_Flags += -DDEBUG -UNDEBUG -UEDEBUG + App_C_Flags += -DDEBUG -UNDEBUG -UEDEBUG else ifeq ($(SGX_PRERELEASE), 1) - App_C_Flags += -DNDEBUG -DEDEBUG -UDEBUG + App_C_Flags += -DNDEBUG -DEDEBUG -UDEBUG else - App_C_Flags += -DNDEBUG -UEDEBUG -UDEBUG + App_C_Flags += -DNDEBUG -UEDEBUG -UDEBUG endif App_Cpp_Flags := $(App_C_Flags) -std=c++11 -App_Link_Flags := $(SGX_COMMON_CFLAGS) -L$(SGX_LIBRARY_PATH) -l$(Urts_Library_Name) -lpthread +App_Link_Flags := $(SGX_COMMON_CFLAGS) libvmlib_untrusted.a -L$(SGX_LIBRARY_PATH) -l$(Urts_Library_Name) -lpthread ifneq ($(SGX_MODE), HW) App_Link_Flags += -lsgx_uae_service_sim @@ -89,7 +90,7 @@ Crypto_Library_Name := sgx_tcrypto WAMR_ROOT := $(CURDIR)/../../../../ -Enclave_Cpp_Files := Enclave/Enclave.cpp +Enclave_Cpp_Files := Enclave/Enclave.cpp Enclave/Enclave_test.cpp Enclave_Include_Paths := -IEnclave -I$(WAMR_ROOT)/core/iwasm/include \ -I$(WAMR_ROOT)/core/shared/utils \ @@ -99,6 +100,11 @@ Enclave_Include_Paths := -IEnclave -I$(WAMR_ROOT)/core/iwasm/include \ -I$(SGX_SDK)/include/stlport Enclave_C_Flags := $(SGX_COMMON_CFLAGS) -nostdinc -fvisibility=hidden -fpie -fstack-protector $(Enclave_Include_Paths) +ifeq ($(SPEC_TEST), 1) + Enclave_C_Flags += -DWASM_ENABLE_SPEC_TEST=1 +else + Enclave_C_Flags += -DWASM_ENABLE_SPEC_TEST=0 +endif Enclave_Cpp_Flags := $(Enclave_C_Flags) -std=c++03 -nostdinc++ Enclave_Link_Flags := $(SGX_COMMON_CFLAGS) -Wl,--no-undefined -nostdlib -nodefaultlibs -nostartfiles -L$(SGX_LIBRARY_PATH) \ -Wl,--whole-archive -l$(Trts_Library_Name) -Wl,--no-whole-archive \ @@ -146,7 +152,10 @@ endif ######## App Objects ######## App/Enclave_u.c: $(SGX_EDGER8R) Enclave/Enclave.edl - @cd App && $(SGX_EDGER8R) --untrusted ../Enclave/Enclave.edl --search-path ../Enclave --search-path $(SGX_SDK)/include --search-path $(WAMR_ROOT)/core/shared/platform/linux-sgx + @cd App && $(SGX_EDGER8R) --untrusted ../Enclave/Enclave.edl \ + --search-path ../Enclave \ + --search-path $(SGX_SDK)/include \ + --search-path $(WAMR_ROOT)/core/shared/platform/linux-sgx @echo "GEN => $@" App/Enclave_u.o: App/Enclave_u.c @@ -157,7 +166,11 @@ App/%.o: App/%.cpp @$(CXX) $(App_Cpp_Flags) -c $< -o $@ @echo "CXX <= $<" -$(App_Name): App/Enclave_u.o $(App_Cpp_Objects) +libvmlib_untrusted.a: ../build/libvmlib_untrusted.a + @cp $< $@ + @echo "CP $@ <= $<" + +$(App_Name): App/Enclave_u.o $(App_Cpp_Objects) libvmlib_untrusted.a @$(CXX) $^ -o $@ $(App_Link_Flags) @echo "LINK => $@" @@ -165,7 +178,10 @@ $(App_Name): App/Enclave_u.o $(App_Cpp_Objects) ######## Enclave Objects ######## Enclave/Enclave_t.c: $(SGX_EDGER8R) Enclave/Enclave.edl - @cd Enclave && $(SGX_EDGER8R) --trusted ../Enclave/Enclave.edl --search-path ../Enclave --search-path $(SGX_SDK)/include --search-path $(WAMR_ROOT)/core/shared/platform/linux-sgx + @cd Enclave && $(SGX_EDGER8R) --trusted ../Enclave/Enclave.edl \ + --search-path ../Enclave \ + --search-path $(SGX_SDK)/include \ + --search-path $(WAMR_ROOT)/core/shared/platform/linux-sgx @echo "GEN => $@" Enclave/Enclave_t.o: Enclave/Enclave_t.c @@ -191,4 +207,4 @@ $(Signed_Enclave_Name): $(Enclave_Name) .PHONY: clean clean: - @rm -f $(App_Name) $(Enclave_Name) $(Signed_Enclave_Name) $(App_Cpp_Objects) App/Enclave_u.* $(Enclave_Cpp_Objects) Enclave/Enclave_t.* libvmlib.a + @rm -f $(App_Name) $(Enclave_Name) $(Signed_Enclave_Name) $(App_Cpp_Objects) App/Enclave_u.* $(Enclave_Cpp_Objects) Enclave/Enclave_t.* libvmlib.a libvmlib_untrusted.a From 6aeefbebb29d1dfca1c3044c642af5b923f552f1 Mon Sep 17 00:00:00 2001 From: Xu Jun <693788454@qq.com> Date: Mon, 10 Aug 2020 19:43:58 +0800 Subject: [PATCH 049/207] implement atomics opcodes for interpreter (#344) --- core/iwasm/common/wasm_shared_memory.c | 2 +- core/iwasm/common/wasm_shared_memory.h | 2 +- core/iwasm/interpreter/wasm_interp_classic.c | 436 +++++++++++++++++++ core/iwasm/interpreter/wasm_interp_fast.c | 434 ++++++++++++++++++ core/iwasm/interpreter/wasm_loader.c | 3 + core/iwasm/interpreter/wasm_mini_loader.c | 3 + core/iwasm/interpreter/wasm_opcode.h | 10 + core/iwasm/interpreter/wasm_runtime.c | 8 + core/iwasm/interpreter/wasm_runtime.h | 6 + doc/pthread_library.md | 1 - 10 files changed, 902 insertions(+), 3 deletions(-) diff --git a/core/iwasm/common/wasm_shared_memory.c b/core/iwasm/common/wasm_shared_memory.c index 220406156..a0e267590 100644 --- a/core/iwasm/common/wasm_shared_memory.c +++ b/core/iwasm/common/wasm_shared_memory.c @@ -397,7 +397,7 @@ wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address, return is_timeout ? 2 : 0; } -uint8 +uint32 wasm_runtime_atomic_notify(WASMModuleInstanceCommon *module, void *address, uint32 count) { diff --git a/core/iwasm/common/wasm_shared_memory.h b/core/iwasm/common/wasm_shared_memory.h index 5e863c194..f05e59578 100644 --- a/core/iwasm/common/wasm_shared_memory.h +++ b/core/iwasm/common/wasm_shared_memory.h @@ -57,7 +57,7 @@ uint32 wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address, uint64 expect, int64 timeout, bool wait64); -uint8 +uint32 wasm_runtime_atomic_notify(WASMModuleInstanceCommon *module, void *address, uint32 count); diff --git a/core/iwasm/interpreter/wasm_interp_classic.c b/core/iwasm/interpreter/wasm_interp_classic.c index 66c257c8d..569f0466f 100644 --- a/core/iwasm/interpreter/wasm_interp_classic.c +++ b/core/iwasm/interpreter/wasm_interp_classic.c @@ -9,6 +9,9 @@ #include "wasm_opcode.h" #include "wasm_loader.h" #include "../common/wasm_exec_env.h" +#if WASM_ENABLE_SHARED_MEMORY != 0 +#include "../common/wasm_shared_memory.h" +#endif typedef int32 CellType_I32; typedef int64 CellType_I64; @@ -243,6 +246,11 @@ LOAD_I16(void *addr) goto out_of_bounds; \ } while (0) +#define CHECK_ATOMIC_MEMORY_ACCESS() do { \ + if (((uintptr_t)maddr & ((1 << align) - 1)) != 0) \ + goto unaligned_atomic; \ + } while (0) + static inline uint32 rotl32(uint32 n, uint32 c) { @@ -748,6 +756,98 @@ trunc_f64_to_int(WASMModuleInstance *module, local_type = cur_func->local_types[local_idx - param_count]; \ } while (0) +#define DEF_ATOMIC_RMW_OPCODE(OP_NAME, op) \ + case WASM_OP_ATOMIC_RMW_I32_##OP_NAME: \ + case WASM_OP_ATOMIC_RMW_I32_##OP_NAME##8_U: \ + case WASM_OP_ATOMIC_RMW_I32_##OP_NAME##16_U: \ + { \ + uint32 readv, sval; \ + \ + sval = POP_I32(); \ + addr = POP_I32(); \ + \ + if (opcode == WASM_OP_ATOMIC_RMW_I32_##OP_NAME##8_U) { \ + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr); \ + CHECK_ATOMIC_MEMORY_ACCESS(); \ + \ + os_mutex_lock(&memory->mem_lock); \ + readv = (uint32)(*(uint8*)maddr); \ + *(uint8*)maddr = (uint8)(readv op sval); \ + os_mutex_unlock(&memory->mem_lock); \ + } \ + else if (opcode == WASM_OP_ATOMIC_RMW_I32_##OP_NAME##16_U) { \ + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); \ + CHECK_ATOMIC_MEMORY_ACCESS(); \ + \ + os_mutex_lock(&memory->mem_lock); \ + readv = (uint32)LOAD_U16(maddr); \ + STORE_U16(maddr, (uint16)(readv op sval)); \ + os_mutex_unlock(&memory->mem_lock); \ + } \ + else { \ + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); \ + CHECK_ATOMIC_MEMORY_ACCESS(); \ + \ + os_mutex_lock(&memory->mem_lock); \ + readv = LOAD_I32(maddr); \ + STORE_U32(maddr, readv op sval); \ + os_mutex_unlock(&memory->mem_lock); \ + } \ + PUSH_I32(readv); \ + break; \ + } \ + case WASM_OP_ATOMIC_RMW_I64_##OP_NAME: \ + case WASM_OP_ATOMIC_RMW_I64_##OP_NAME##8_U: \ + case WASM_OP_ATOMIC_RMW_I64_##OP_NAME##16_U: \ + case WASM_OP_ATOMIC_RMW_I64_##OP_NAME##32_U: \ + { \ + uint64 readv, sval; \ + \ + sval = (uint64)POP_I64(); \ + addr = POP_I32(); \ + \ + if (opcode == WASM_OP_ATOMIC_RMW_I64_##OP_NAME##8_U) { \ + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr); \ + CHECK_ATOMIC_MEMORY_ACCESS(); \ + \ + os_mutex_lock(&memory->mem_lock); \ + readv = (uint64)(*(uint8*)maddr); \ + *(uint8*)maddr = (uint8)(readv op sval); \ + os_mutex_unlock(&memory->mem_lock); \ + } \ + else if (opcode == WASM_OP_ATOMIC_RMW_I64_##OP_NAME##16_U) { \ + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); \ + CHECK_ATOMIC_MEMORY_ACCESS(); \ + \ + os_mutex_lock(&memory->mem_lock); \ + readv = (uint64)LOAD_U16(maddr); \ + STORE_U16(maddr, (uint16)(readv op sval)); \ + os_mutex_unlock(&memory->mem_lock); \ + } \ + else if (opcode == WASM_OP_ATOMIC_RMW_I64_##OP_NAME##32_U) { \ + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); \ + CHECK_ATOMIC_MEMORY_ACCESS(); \ + \ + os_mutex_lock(&memory->mem_lock); \ + readv = (uint64)LOAD_U32(maddr); \ + STORE_U32(maddr, (uint32)(readv op sval)); \ + os_mutex_unlock(&memory->mem_lock); \ + } \ + else { \ + uint64 op_result; \ + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr); \ + CHECK_ATOMIC_MEMORY_ACCESS(); \ + \ + os_mutex_lock(&memory->mem_lock); \ + readv = (uint64)LOAD_I64(maddr); \ + op_result = readv op sval; \ + STORE_I64(maddr, op_result); \ + os_mutex_unlock(&memory->mem_lock); \ + } \ + PUSH_I64(readv); \ + break; \ + } + static inline int32 sign_ext_8_32(int8 val) { @@ -2684,6 +2784,336 @@ label_pop_csp_n: HANDLE_OP_END (); } +#if WASM_ENABLE_SHARED_MEMORY != 0 + HANDLE_OP (WASM_OP_ATOMIC_PREFIX): + { + uint32 offset, align; + int32 addr; + + opcode = *frame_ip++; + + read_leb_uint32(frame_ip, frame_ip_end, align); + read_leb_uint32(frame_ip, frame_ip_end, offset); + switch (opcode) { + case WASM_OP_ATOMIC_NOTIFY: + { + uint32 count, ret; + + count = POP_I32(); + addr = POP_I32(); + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); + CHECK_ATOMIC_MEMORY_ACCESS(); + + ret = wasm_runtime_atomic_notify((WASMModuleInstanceCommon*)module, + maddr, count); + bh_assert((int32)ret >= 0); + + PUSH_I32(ret); + break; + } + case WASM_OP_ATOMIC_WAIT32: + { + uint64 timeout; + uint32 expect, addr, ret; + + timeout = POP_I64(); + expect = POP_I32(); + addr = POP_I32(); + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); + CHECK_ATOMIC_MEMORY_ACCESS(); + + ret = wasm_runtime_atomic_wait((WASMModuleInstanceCommon*)module, maddr, + (uint64)expect, timeout, false); + if (ret == (uint32)-1) + goto got_exception; + + PUSH_I32(ret); + break; + } + case WASM_OP_ATOMIC_WAIT64: + { + uint64 timeout, expect; + uint32 ret; + + timeout = POP_I64(); + expect = POP_I64(); + addr = POP_I32(); + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr); + CHECK_ATOMIC_MEMORY_ACCESS(); + + ret = wasm_runtime_atomic_wait((WASMModuleInstanceCommon*)module, + maddr, expect, timeout, true); + if (ret == (uint32)-1) + goto got_exception; + + PUSH_I32(ret); + break; + } + + case WASM_OP_ATOMIC_I32_LOAD: + case WASM_OP_ATOMIC_I32_LOAD8_U: + case WASM_OP_ATOMIC_I32_LOAD16_U: + { + uint32 readv; + + addr = POP_I32(); + + if (opcode == WASM_OP_ATOMIC_I32_LOAD8_U) { + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr); + CHECK_ATOMIC_MEMORY_ACCESS(); + os_mutex_lock(&memory->mem_lock); + readv = (uint32)(*(uint8*)maddr); + os_mutex_unlock(&memory->mem_lock); + } + else if (opcode == WASM_OP_ATOMIC_I32_LOAD16_U) { + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); + CHECK_ATOMIC_MEMORY_ACCESS(); + os_mutex_lock(&memory->mem_lock); + readv = (uint32)LOAD_U16(maddr); + os_mutex_unlock(&memory->mem_lock); + } + else { + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); + CHECK_ATOMIC_MEMORY_ACCESS(); + os_mutex_lock(&memory->mem_lock); + readv = LOAD_I32(maddr); + os_mutex_unlock(&memory->mem_lock); + } + + PUSH_I32(readv); + break; + } + + case WASM_OP_ATOMIC_I64_LOAD: + case WASM_OP_ATOMIC_I64_LOAD8_U: + case WASM_OP_ATOMIC_I64_LOAD16_U: + case WASM_OP_ATOMIC_I64_LOAD32_U: + { + uint64 readv; + + addr = POP_I32(); + + if (opcode == WASM_OP_ATOMIC_I64_LOAD8_U) { + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr); + CHECK_ATOMIC_MEMORY_ACCESS(); + os_mutex_lock(&memory->mem_lock); + readv = (uint64)(*(uint8*)maddr); + os_mutex_unlock(&memory->mem_lock); + } + else if (opcode == WASM_OP_ATOMIC_I64_LOAD16_U) { + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); + CHECK_ATOMIC_MEMORY_ACCESS(); + os_mutex_lock(&memory->mem_lock); + readv = (uint64)LOAD_U16(maddr); + os_mutex_unlock(&memory->mem_lock); + } + else if (opcode == WASM_OP_ATOMIC_I64_LOAD32_U) { + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); + CHECK_ATOMIC_MEMORY_ACCESS(); + os_mutex_lock(&memory->mem_lock); + readv = (uint64)LOAD_U32(maddr); + os_mutex_unlock(&memory->mem_lock); + } + else { + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr); + CHECK_ATOMIC_MEMORY_ACCESS(); + os_mutex_lock(&memory->mem_lock); + readv = LOAD_I64(maddr); + os_mutex_unlock(&memory->mem_lock); + } + + PUSH_I64(readv); + break; + } + + case WASM_OP_ATOMIC_I32_STORE: + case WASM_OP_ATOMIC_I32_STORE8: + case WASM_OP_ATOMIC_I32_STORE16: + { + uint32 sval; + + sval = (uint32)POP_I32(); + addr = POP_I32(); + + if (opcode == WASM_OP_ATOMIC_I32_STORE8) { + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr); + CHECK_ATOMIC_MEMORY_ACCESS(); + os_mutex_lock(&memory->mem_lock); + *(uint8*)maddr = (uint8)sval; + os_mutex_unlock(&memory->mem_lock); + } + else if (opcode == WASM_OP_ATOMIC_I32_STORE16) { + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); + CHECK_ATOMIC_MEMORY_ACCESS(); + os_mutex_lock(&memory->mem_lock); + STORE_U16(maddr, (uint16)sval); + os_mutex_unlock(&memory->mem_lock); + } + else { + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); + CHECK_ATOMIC_MEMORY_ACCESS(); + os_mutex_lock(&memory->mem_lock); + STORE_U32(maddr, frame_sp[1]); + os_mutex_unlock(&memory->mem_lock); + } + break; + } + + case WASM_OP_ATOMIC_I64_STORE: + case WASM_OP_ATOMIC_I64_STORE8: + case WASM_OP_ATOMIC_I64_STORE16: + case WASM_OP_ATOMIC_I64_STORE32: + { + uint64 sval; + + sval = (uint64)POP_I64(); + addr = POP_I32(); + + if (opcode == WASM_OP_ATOMIC_I64_STORE8) { + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr); + CHECK_ATOMIC_MEMORY_ACCESS(); + os_mutex_lock(&memory->mem_lock); + *(uint8*)maddr = (uint8)sval; + os_mutex_unlock(&memory->mem_lock); + } + else if(opcode == WASM_OP_ATOMIC_I64_STORE16) { + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); + CHECK_ATOMIC_MEMORY_ACCESS(); + os_mutex_lock(&memory->mem_lock); + STORE_U16(maddr, (uint16)sval); + os_mutex_unlock(&memory->mem_lock); + } + else if (opcode == WASM_OP_ATOMIC_I64_STORE32) { + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); + CHECK_ATOMIC_MEMORY_ACCESS(); + os_mutex_lock(&memory->mem_lock); + STORE_U32(maddr, (uint32)sval); + os_mutex_unlock(&memory->mem_lock); + } + else { + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr); + CHECK_ATOMIC_MEMORY_ACCESS(); + os_mutex_lock(&memory->mem_lock); + STORE_U32(maddr, frame_sp[1]); + STORE_U32(maddr + 4, frame_sp[2]); + os_mutex_unlock(&memory->mem_lock); + } + break; + } + + case WASM_OP_ATOMIC_RMW_I32_CMPXCHG: + case WASM_OP_ATOMIC_RMW_I32_CMPXCHG8_U: + case WASM_OP_ATOMIC_RMW_I32_CMPXCHG16_U: + { + uint32 readv, sval, expect; + + sval = POP_I32(); + expect = POP_I32(); + addr = POP_I32(); + + if (opcode == WASM_OP_ATOMIC_RMW_I32_CMPXCHG8_U) { + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr); + CHECK_ATOMIC_MEMORY_ACCESS(); + + os_mutex_lock(&memory->mem_lock); + readv = (uint32)(*(uint8*)maddr); + if (readv == expect) + *(uint8*)maddr = (uint8)(sval); + os_mutex_unlock(&memory->mem_lock); + } + else if (opcode == WASM_OP_ATOMIC_RMW_I32_CMPXCHG16_U) { + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); + CHECK_ATOMIC_MEMORY_ACCESS(); + + os_mutex_lock(&memory->mem_lock); + readv = (uint32)LOAD_U16(maddr); + if (readv == expect) + STORE_U16(maddr, (uint16)(sval)); + os_mutex_unlock(&memory->mem_lock); + } + else { + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); + CHECK_ATOMIC_MEMORY_ACCESS(); + + os_mutex_lock(&memory->mem_lock); + readv = LOAD_I32(maddr); + if (readv == expect) + STORE_U32(maddr, sval); + os_mutex_unlock(&memory->mem_lock); + } + PUSH_I32(readv); + break; + } + case WASM_OP_ATOMIC_RMW_I64_CMPXCHG: + case WASM_OP_ATOMIC_RMW_I64_CMPXCHG8_U: + case WASM_OP_ATOMIC_RMW_I64_CMPXCHG16_U: + case WASM_OP_ATOMIC_RMW_I64_CMPXCHG32_U: + { + uint64 readv, sval, expect; + + sval = (uint64)POP_I64(); + expect = (uint64)POP_I64(); + addr = POP_I32(); + + if (opcode == WASM_OP_ATOMIC_RMW_I64_CMPXCHG8_U) { + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr); + CHECK_ATOMIC_MEMORY_ACCESS(); + + os_mutex_lock(&memory->mem_lock); + readv = (uint64)(*(uint8*)maddr); + if (readv == expect) + *(uint8*)maddr = (uint8)(sval); + os_mutex_unlock(&memory->mem_lock); + } + else if (opcode == WASM_OP_ATOMIC_RMW_I64_CMPXCHG16_U) { + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); + CHECK_ATOMIC_MEMORY_ACCESS(); + + os_mutex_lock(&memory->mem_lock); + readv = (uint64)LOAD_U16(maddr); + if (readv == expect) + STORE_U16(maddr, (uint16)(sval)); + os_mutex_unlock(&memory->mem_lock); + } + else if (opcode == WASM_OP_ATOMIC_RMW_I64_CMPXCHG32_U) { + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); + CHECK_ATOMIC_MEMORY_ACCESS(); + + os_mutex_lock(&memory->mem_lock); + readv = (uint64)LOAD_U32(maddr); + if (readv == expect) + STORE_U32(maddr, (uint32)(sval)); + os_mutex_unlock(&memory->mem_lock); + } + else { + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr); + CHECK_ATOMIC_MEMORY_ACCESS(); + + os_mutex_lock(&memory->mem_lock); + readv = (uint64)LOAD_I64(maddr); + if (readv == expect) { + STORE_I64(maddr, sval); + } + os_mutex_unlock(&memory->mem_lock); + } + PUSH_I64(readv); + break; + } + + DEF_ATOMIC_RMW_OPCODE(ADD, +); + DEF_ATOMIC_RMW_OPCODE(SUB, -); + DEF_ATOMIC_RMW_OPCODE(AND, &); + DEF_ATOMIC_RMW_OPCODE(OR, |); + DEF_ATOMIC_RMW_OPCODE(XOR, ^); + /* xchg, ignore the read value, and store the given value: + readv * 0 + sval */ + DEF_ATOMIC_RMW_OPCODE(XCHG, *0 +); + } + + HANDLE_OP_END (); + } +#endif + HANDLE_OP (WASM_OP_IMPDEP): frame = prev_frame; frame_ip = frame->ip; @@ -2827,6 +3257,12 @@ label_pop_csp_n: HANDLE_OP_END (); } +#if WASM_ENABLE_SHARED_MEMORY != 0 + unaligned_atomic: + wasm_set_exception(module, "unaligned atomic"); + goto got_exception; +#endif + out_of_bounds: wasm_set_exception(module, "out of bounds memory access"); diff --git a/core/iwasm/interpreter/wasm_interp_fast.c b/core/iwasm/interpreter/wasm_interp_fast.c index 2e31552ae..166dc107e 100644 --- a/core/iwasm/interpreter/wasm_interp_fast.c +++ b/core/iwasm/interpreter/wasm_interp_fast.c @@ -9,6 +9,9 @@ #include "wasm_opcode.h" #include "wasm_loader.h" #include "../common/wasm_exec_env.h" +#if WASM_ENABLE_SHARED_MEMORY != 0 +#include "../common/wasm_shared_memory.h" +#endif typedef int32 CellType_I32; typedef int64 CellType_I64; @@ -245,6 +248,11 @@ LOAD_I16(void *addr) goto out_of_bounds; \ } while (0) +#define CHECK_ATOMIC_MEMORY_ACCESS(align) do { \ + if (((uintptr_t)maddr & (align - 1)) != 0) \ + goto unaligned_atomic; \ + } while (0) + static inline uint32 rotl32(uint32 n, uint32 c) { @@ -540,6 +548,98 @@ read_leb(const uint8 *buf, uint32 *p_offset, uint32 maxbits, bool sign) frame_ip += 6; \ } while (0) +#define DEF_ATOMIC_RMW_OPCODE(OP_NAME, op) \ + case WASM_OP_ATOMIC_RMW_I32_##OP_NAME: \ + case WASM_OP_ATOMIC_RMW_I32_##OP_NAME##8_U: \ + case WASM_OP_ATOMIC_RMW_I32_##OP_NAME##16_U: \ + { \ + uint32 readv, sval; \ + \ + sval = POP_I32(); \ + addr = POP_I32(); \ + \ + if (opcode == WASM_OP_ATOMIC_RMW_I32_##OP_NAME##8_U) { \ + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr); \ + CHECK_ATOMIC_MEMORY_ACCESS(1); \ + \ + os_mutex_lock(&memory->mem_lock); \ + readv = (uint32)(*(uint8*)maddr); \ + *(uint8*)maddr = (uint8)(readv op sval); \ + os_mutex_unlock(&memory->mem_lock); \ + } \ + else if (opcode == WASM_OP_ATOMIC_RMW_I32_##OP_NAME##16_U) { \ + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); \ + CHECK_ATOMIC_MEMORY_ACCESS(2); \ + \ + os_mutex_lock(&memory->mem_lock); \ + readv = (uint32)LOAD_U16(maddr); \ + STORE_U16(maddr, (uint16)(readv op sval)); \ + os_mutex_unlock(&memory->mem_lock); \ + } \ + else { \ + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); \ + CHECK_ATOMIC_MEMORY_ACCESS(4); \ + \ + os_mutex_lock(&memory->mem_lock); \ + readv = LOAD_I32(maddr); \ + STORE_U32(maddr, readv op sval); \ + os_mutex_unlock(&memory->mem_lock); \ + } \ + PUSH_I32(readv); \ + break; \ + } \ + case WASM_OP_ATOMIC_RMW_I64_##OP_NAME: \ + case WASM_OP_ATOMIC_RMW_I64_##OP_NAME##8_U: \ + case WASM_OP_ATOMIC_RMW_I64_##OP_NAME##16_U: \ + case WASM_OP_ATOMIC_RMW_I64_##OP_NAME##32_U: \ + { \ + uint64 readv, sval; \ + \ + sval = (uint64)POP_I64(); \ + addr = POP_I32(); \ + \ + if (opcode == WASM_OP_ATOMIC_RMW_I64_##OP_NAME##8_U) { \ + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr); \ + CHECK_ATOMIC_MEMORY_ACCESS(1); \ + \ + os_mutex_lock(&memory->mem_lock); \ + readv = (uint64)(*(uint8*)maddr); \ + *(uint8*)maddr = (uint8)(readv op sval); \ + os_mutex_unlock(&memory->mem_lock); \ + } \ + else if (opcode == WASM_OP_ATOMIC_RMW_I64_##OP_NAME##16_U) { \ + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); \ + CHECK_ATOMIC_MEMORY_ACCESS(2); \ + \ + os_mutex_lock(&memory->mem_lock); \ + readv = (uint64)LOAD_U16(maddr); \ + STORE_U16(maddr, (uint16)(readv op sval)); \ + os_mutex_unlock(&memory->mem_lock); \ + } \ + else if (opcode == WASM_OP_ATOMIC_RMW_I64_##OP_NAME##32_U) { \ + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); \ + CHECK_ATOMIC_MEMORY_ACCESS(4); \ + \ + os_mutex_lock(&memory->mem_lock); \ + readv = (uint64)LOAD_U32(maddr); \ + STORE_U32(maddr, (uint32)(readv op sval)); \ + os_mutex_unlock(&memory->mem_lock); \ + } \ + else { \ + uint64 op_result; \ + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr); \ + CHECK_ATOMIC_MEMORY_ACCESS(8); \ + \ + os_mutex_lock(&memory->mem_lock); \ + readv = (uint64)LOAD_I64(maddr); \ + op_result = readv op sval; \ + STORE_I64(maddr, op_result); \ + os_mutex_unlock(&memory->mem_lock); \ + } \ + PUSH_I64(readv); \ + break; \ + } + #define DEF_OP_MATH(src_type, src_op_type, method) do { \ SET_OPERAND(src_type, 2, method(GET_OPERAND(src_type, 0))); \ frame_ip += 4; \ @@ -2665,6 +2765,334 @@ recover_br_info: HANDLE_OP_END (); } +#if WASM_ENABLE_SHARED_MEMORY != 0 + HANDLE_OP (WASM_OP_ATOMIC_PREFIX): + { + uint32 offset; + int32 addr; + + GET_OPCODE(); + + offset = read_uint32(frame_ip); + + switch (opcode) { + case WASM_OP_ATOMIC_NOTIFY: + { + uint32 count, ret; + + count = POP_I32(); + addr = POP_I32(); + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); + CHECK_ATOMIC_MEMORY_ACCESS(4); + + ret = wasm_runtime_atomic_notify((WASMModuleInstanceCommon*)module, + maddr, count); + bh_assert((int32)ret >= 0); + + PUSH_I32(ret); + break; + } + case WASM_OP_ATOMIC_WAIT32: + { + uint64 timeout; + uint32 expect, addr, ret; + + timeout = POP_I64(); + expect = POP_I32(); + addr = POP_I32(); + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); + CHECK_ATOMIC_MEMORY_ACCESS(4); + + ret = wasm_runtime_atomic_wait((WASMModuleInstanceCommon*)module, maddr, + (uint64)expect, timeout, false); + if (ret == (uint32)-1) + goto got_exception; + + PUSH_I32(ret); + break; + } + case WASM_OP_ATOMIC_WAIT64: + { + uint64 timeout, expect; + uint32 ret; + + timeout = POP_I64(); + expect = POP_I64(); + addr = POP_I32(); + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr); + CHECK_ATOMIC_MEMORY_ACCESS(8); + + ret = wasm_runtime_atomic_wait((WASMModuleInstanceCommon*)module, + maddr, expect, timeout, true); + if (ret == (uint32)-1) + goto got_exception; + + PUSH_I32(ret); + break; + } + + case WASM_OP_ATOMIC_I32_LOAD: + case WASM_OP_ATOMIC_I32_LOAD8_U: + case WASM_OP_ATOMIC_I32_LOAD16_U: + { + uint32 readv; + + addr = POP_I32(); + + if (opcode == WASM_OP_ATOMIC_I32_LOAD8_U) { + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr); + CHECK_ATOMIC_MEMORY_ACCESS(1); + os_mutex_lock(&memory->mem_lock); + readv = (uint32)(*(uint8*)maddr); + os_mutex_unlock(&memory->mem_lock); + } + else if (opcode == WASM_OP_ATOMIC_I32_LOAD16_U) { + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); + CHECK_ATOMIC_MEMORY_ACCESS(2); + os_mutex_lock(&memory->mem_lock); + readv = (uint32)LOAD_U16(maddr); + os_mutex_unlock(&memory->mem_lock); + } + else { + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); + CHECK_ATOMIC_MEMORY_ACCESS(4); + os_mutex_lock(&memory->mem_lock); + readv = LOAD_I32(maddr); + os_mutex_unlock(&memory->mem_lock); + } + + PUSH_I32(readv); + break; + } + + case WASM_OP_ATOMIC_I64_LOAD: + case WASM_OP_ATOMIC_I64_LOAD8_U: + case WASM_OP_ATOMIC_I64_LOAD16_U: + case WASM_OP_ATOMIC_I64_LOAD32_U: + { + uint64 readv; + + addr = POP_I32(); + + if (opcode == WASM_OP_ATOMIC_I64_LOAD8_U) { + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr); + CHECK_ATOMIC_MEMORY_ACCESS(1); + os_mutex_lock(&memory->mem_lock); + readv = (uint64)(*(uint8*)maddr); + os_mutex_unlock(&memory->mem_lock); + } + else if (opcode == WASM_OP_ATOMIC_I64_LOAD16_U) { + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); + CHECK_ATOMIC_MEMORY_ACCESS(2); + os_mutex_lock(&memory->mem_lock); + readv = (uint64)LOAD_U16(maddr); + os_mutex_unlock(&memory->mem_lock); + } + else if (opcode == WASM_OP_ATOMIC_I64_LOAD32_U) { + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); + CHECK_ATOMIC_MEMORY_ACCESS(4); + os_mutex_lock(&memory->mem_lock); + readv = (uint64)LOAD_U32(maddr); + os_mutex_unlock(&memory->mem_lock); + } + else { + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr); + CHECK_ATOMIC_MEMORY_ACCESS(8); + os_mutex_lock(&memory->mem_lock); + readv = LOAD_I64(maddr); + os_mutex_unlock(&memory->mem_lock); + } + + PUSH_I64(readv); + break; + } + case WASM_OP_ATOMIC_I32_STORE: + case WASM_OP_ATOMIC_I32_STORE8: + case WASM_OP_ATOMIC_I32_STORE16: + { + uint32 sval; + + sval = (uint32)POP_I32(); + addr = POP_I32(); + + if (opcode == WASM_OP_ATOMIC_I32_STORE8) { + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr); + CHECK_ATOMIC_MEMORY_ACCESS(1); + os_mutex_lock(&memory->mem_lock); + *(uint8*)maddr = (uint8)sval; + os_mutex_unlock(&memory->mem_lock); + } + else if (opcode == WASM_OP_ATOMIC_I32_STORE16) { + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); + CHECK_ATOMIC_MEMORY_ACCESS(2); + os_mutex_lock(&memory->mem_lock); + STORE_U16(maddr, (uint16)sval); + os_mutex_unlock(&memory->mem_lock); + } + else { + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); + CHECK_ATOMIC_MEMORY_ACCESS(4); + os_mutex_lock(&memory->mem_lock); + STORE_U32(maddr, sval); + os_mutex_unlock(&memory->mem_lock); + } + break; + } + + case WASM_OP_ATOMIC_I64_STORE: + case WASM_OP_ATOMIC_I64_STORE8: + case WASM_OP_ATOMIC_I64_STORE16: + case WASM_OP_ATOMIC_I64_STORE32: + { + uint64 sval; + + sval = (uint64)POP_I64(); + addr = POP_I32(); + + if (opcode == WASM_OP_ATOMIC_I64_STORE8) { + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr); + CHECK_ATOMIC_MEMORY_ACCESS(1); + os_mutex_lock(&memory->mem_lock); + *(uint8*)maddr = (uint8)sval; + os_mutex_unlock(&memory->mem_lock); + } + else if(opcode == WASM_OP_ATOMIC_I64_STORE16) { + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); + CHECK_ATOMIC_MEMORY_ACCESS(2); + os_mutex_lock(&memory->mem_lock); + STORE_U16(maddr, (uint16)sval); + os_mutex_unlock(&memory->mem_lock); + } + else if (opcode == WASM_OP_ATOMIC_I64_STORE32) { + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); + CHECK_ATOMIC_MEMORY_ACCESS(4); + os_mutex_lock(&memory->mem_lock); + STORE_U32(maddr, (uint32)sval); + os_mutex_unlock(&memory->mem_lock); + } + else { + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr); + CHECK_ATOMIC_MEMORY_ACCESS(8); + os_mutex_lock(&memory->mem_lock); + STORE_I64(maddr, sval); + os_mutex_unlock(&memory->mem_lock); + } + break; + } + + case WASM_OP_ATOMIC_RMW_I32_CMPXCHG: + case WASM_OP_ATOMIC_RMW_I32_CMPXCHG8_U: + case WASM_OP_ATOMIC_RMW_I32_CMPXCHG16_U: + { + uint32 readv, sval, expect; + + sval = POP_I32(); + expect = POP_I32(); + addr = POP_I32(); + + if (opcode == WASM_OP_ATOMIC_RMW_I32_CMPXCHG8_U) { + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr); + CHECK_ATOMIC_MEMORY_ACCESS(1); + + os_mutex_lock(&memory->mem_lock); + readv = (uint32)(*(uint8*)maddr); + if (readv == expect) + *(uint8*)maddr = (uint8)(sval); + os_mutex_unlock(&memory->mem_lock); + } + else if (opcode == WASM_OP_ATOMIC_RMW_I32_CMPXCHG16_U) { + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); + CHECK_ATOMIC_MEMORY_ACCESS(2); + + os_mutex_lock(&memory->mem_lock); + readv = (uint32)LOAD_U16(maddr); + if (readv == expect) + STORE_U16(maddr, (uint16)(sval)); + os_mutex_unlock(&memory->mem_lock); + } + else { + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); + CHECK_ATOMIC_MEMORY_ACCESS(4); + + os_mutex_lock(&memory->mem_lock); + readv = LOAD_I32(maddr); + if (readv == expect) + STORE_U32(maddr, sval); + os_mutex_unlock(&memory->mem_lock); + } + PUSH_I32(readv); + break; + } + case WASM_OP_ATOMIC_RMW_I64_CMPXCHG: + case WASM_OP_ATOMIC_RMW_I64_CMPXCHG8_U: + case WASM_OP_ATOMIC_RMW_I64_CMPXCHG16_U: + case WASM_OP_ATOMIC_RMW_I64_CMPXCHG32_U: + { + uint64 readv, sval, expect; + + sval = (uint64)POP_I64(); + expect = (uint64)POP_I64(); + addr = POP_I32(); + + if (opcode == WASM_OP_ATOMIC_RMW_I64_CMPXCHG8_U) { + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr); + CHECK_ATOMIC_MEMORY_ACCESS(1); + + os_mutex_lock(&memory->mem_lock); + readv = (uint64)(*(uint8*)maddr); + if (readv == expect) + *(uint8*)maddr = (uint8)(sval); + os_mutex_unlock(&memory->mem_lock); + } + else if (opcode == WASM_OP_ATOMIC_RMW_I64_CMPXCHG16_U) { + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); + CHECK_ATOMIC_MEMORY_ACCESS(2); + + os_mutex_lock(&memory->mem_lock); + readv = (uint64)LOAD_U16(maddr); + if (readv == expect) + STORE_U16(maddr, (uint16)(sval)); + os_mutex_unlock(&memory->mem_lock); + } + else if (opcode == WASM_OP_ATOMIC_RMW_I64_CMPXCHG32_U) { + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); + CHECK_ATOMIC_MEMORY_ACCESS(4); + + os_mutex_lock(&memory->mem_lock); + readv = (uint64)LOAD_U32(maddr); + if (readv == expect) + STORE_U32(maddr, (uint32)(sval)); + os_mutex_unlock(&memory->mem_lock); + } + else { + CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr); + CHECK_ATOMIC_MEMORY_ACCESS(8); + + os_mutex_lock(&memory->mem_lock); + readv = (uint64)LOAD_I64(maddr); + if (readv == expect) { + STORE_I64(maddr, sval); + } + os_mutex_unlock(&memory->mem_lock); + } + PUSH_I64(readv); + break; + } + + DEF_ATOMIC_RMW_OPCODE(ADD, +); + DEF_ATOMIC_RMW_OPCODE(SUB, -); + DEF_ATOMIC_RMW_OPCODE(AND, &); + DEF_ATOMIC_RMW_OPCODE(OR, |); + DEF_ATOMIC_RMW_OPCODE(XOR, ^); + /* xchg, ignore the read value, and store the given value: + readv * 0 + sval */ + DEF_ATOMIC_RMW_OPCODE(XCHG, *0 +); + } + + HANDLE_OP_END (); + } +#endif + HANDLE_OP (WASM_OP_IMPDEP): frame = prev_frame; frame_ip = frame->ip; @@ -2854,6 +3282,12 @@ recover_br_info: (void)frame_ip_end; +#if WASM_ENABLE_SHARED_MEMORY != 0 + unaligned_atomic: + wasm_set_exception(module, "unaligned atomic"); + goto got_exception; +#endif + out_of_bounds: wasm_set_exception(module, "out of bounds memory access"); diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index fb12b4ae8..175f4d036 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -6596,6 +6596,9 @@ fail_data_cnt_sec_require: error_buf_size)) { goto fail; } +#if WASM_ENABLE_FAST_INTERP != 0 + emit_uint32(loader_ctx, mem_offset); +#endif } switch (opcode) { case WASM_OP_ATOMIC_NOTIFY: diff --git a/core/iwasm/interpreter/wasm_mini_loader.c b/core/iwasm/interpreter/wasm_mini_loader.c index bfa835afc..ded22b7ca 100644 --- a/core/iwasm/interpreter/wasm_mini_loader.c +++ b/core/iwasm/interpreter/wasm_mini_loader.c @@ -5348,6 +5348,9 @@ handle_op_block_and_loop: CHECK_MEMORY(); read_leb_uint32(p, p_end, align); /* align */ read_leb_uint32(p, p_end, mem_offset); /* offset */ +#if WASM_ENABLE_FAST_INTERP != 0 + emit_uint32(loader_ctx, mem_offset); +#endif } switch (opcode) { case WASM_OP_ATOMIC_NOTIFY: diff --git a/core/iwasm/interpreter/wasm_opcode.h b/core/iwasm/interpreter/wasm_opcode.h index d0e29e7ee..f546088b5 100644 --- a/core/iwasm/interpreter/wasm_opcode.h +++ b/core/iwasm/interpreter/wasm_opcode.h @@ -369,6 +369,15 @@ typedef enum WASMAtomicEXTOpcode { } #endif +/* Opcode prefix controlled by features */ +#if WASM_ENABLE_SHARED_MEMORY != 0 +#define DEF_ATOMIC_PREFIX_HANDLE(_name) \ + _name[WASM_OP_ATOMIC_PREFIX] = \ + HANDLE_OPCODE (WASM_OP_ATOMIC_PREFIX); /* 0xfe */ +#else +#define DEF_ATOMIC_PREFIX_HANDLE(_name) +#endif + /* * Macro used to generate computed goto tables for the C interpreter. */ @@ -591,5 +600,6 @@ static type _name[WASM_INSTRUCTION_NUM] = { \ do { \ _name[WASM_OP_MISC_PREFIX] = \ HANDLE_OPCODE (WASM_OP_MISC_PREFIX); /* 0xfc */ \ + DEF_ATOMIC_PREFIX_HANDLE(_name) \ } while (0) #endif /* end of _WASM_OPCODE_H */ diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index c2d9ab9cb..42829c7a2 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -91,6 +91,7 @@ memories_deinstantiate(WASMModuleInstance *module_inst, continue; #endif #if WASM_ENABLE_SHARED_MEMORY != 0 + os_mutex_destroy(&memories[0]->mem_lock); if (memories[i]->is_shared) { int32 ref_count = shared_memory_dec_reference( @@ -192,6 +193,11 @@ memory_instantiate(WASMModuleInstance *module_inst, memory->heap_base_offset = -(int32)heap_size; #if WASM_ENABLE_SHARED_MEMORY != 0 + if (0 != os_mutex_init(&memory->mem_lock)) { + mem_allocator_destroy(memory->heap_handle); + wasm_runtime_free(memory); + return NULL; + } if (is_shared_memory) { memory->is_shared = true; if (!shared_memory_set_memory_inst( @@ -200,6 +206,8 @@ memory_instantiate(WASMModuleInstance *module_inst, set_error_buf(error_buf, error_buf_size, "Instantiate memory failed:" "allocate memory failed."); + os_mutex_destroy(&memory->mem_lock); + mem_allocator_destroy(memory->heap_handle); wasm_runtime_free(memory); return NULL; } diff --git a/core/iwasm/interpreter/wasm_runtime.h b/core/iwasm/interpreter/wasm_runtime.h index 361a76111..fcb9a1e60 100644 --- a/core/iwasm/interpreter/wasm_runtime.h +++ b/core/iwasm/interpreter/wasm_runtime.h @@ -50,6 +50,12 @@ typedef struct WASMMemoryInstance { /* to indicate which module instance create it */ WASMModuleInstance *owner; #endif + +#if WASM_ENABLE_SHARED_MEMORY != 0 + /* mutex lock for the memory, used in atomic operation */ + korp_mutex mem_lock; +#endif + /* Base address, the layout is: heap_data + memory data memory data init size is: num_bytes_per_page * cur_page_count diff --git a/doc/pthread_library.md b/doc/pthread_library.md index fd6964aa1..cfc6bece4 100644 --- a/doc/pthread_library.md +++ b/doc/pthread_library.md @@ -67,7 +67,6 @@ You can also build this program with WASI, but we need to make some changes to w ``` > Note:
>1. Remember to back up the original sysroot files ->2. wasi-sdk 9.0 or above are not supported, please use 7.0 or 8.0 Then build the program with this command: ``` bash From 3be29c3f464e425c903c38f1c57a845091249e05 Mon Sep 17 00:00:00 2001 From: Karl Fessel Date: Tue, 11 Aug 2020 03:40:18 +0200 Subject: [PATCH 050/207] optimize: get_current_target for AOT thumb loader (#342) --- core/iwasm/aot/arch/aot_reloc_thumb.c | 32 ++++++++++++++++++--------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/core/iwasm/aot/arch/aot_reloc_thumb.c b/core/iwasm/aot/arch/aot_reloc_thumb.c index 316927b5e..f4023ffb5 100644 --- a/core/iwasm/aot/arch/aot_reloc_thumb.c +++ b/core/iwasm/aot/arch/aot_reloc_thumb.c @@ -117,22 +117,32 @@ get_target_symbol_map(uint32 *sym_num) return target_sym_map; } +#define BUILD_TARGET_THUMB_V4T "thumbv4t" void get_current_target(char *target_buf, uint32 target_buf_size) { - char *build_target = BUILD_TARGET; - char *p = target_buf, *p_end; - snprintf(target_buf, target_buf_size, "%s", build_target); - p_end = p + strlen(target_buf); - while (p < p_end) { - if (*p >= 'A' && *p <= 'Z') - *p++ += 'a' - 'A'; - else - p++; + const char * s = BUILD_TARGET; + size_t s_size = sizeof(BUILD_TARGET); + char *d = target_buf; + + /* Set to "thumbv4t" by default if sub version isn't specified */ + if (strcmp(s, "THUMB") == 0) { + s = BUILD_TARGET_THUMB_V4T; + s_size = sizeof(BUILD_TARGET_THUMB_V4T); } - if (!strcmp(target_buf, "thumb")) - snprintf(target_buf, target_buf_size, "thumbv4t"); + if(target_buf_size < s_size){ + s_size = target_buf_size; + } + while (--s_size) { + if (*s >= 'A' && *s <= 'Z') + *d++ = *s++ + 'a' - 'A'; + else + *d++ = *s++ ; + } + /* Ensure the string is null byte ('\0') terminated */ + *d = '\0'; } +#undef BUILD_TARGET_THUMB_V4T uint32 get_plt_item_size() From 8ad9c1775f48727eb1f88341caab3d2727b4639e Mon Sep 17 00:00:00 2001 From: sophy228 Date: Tue, 11 Aug 2020 11:30:51 +0800 Subject: [PATCH 051/207] Add wamrc AoT compiler building support for Windows(MSVC) (#332) --- README.md | 4 +- build-scripts/runtime_lib.cmake | 2 + core/config.h | 4 + core/iwasm/aot/aot_reloc.h | 11 + core/iwasm/aot/aot_runtime.c | 2 +- core/iwasm/aot/arch/aot_reloc_x86_32.c | 2 + core/iwasm/common/arch/invokeNative_ia32.asm | 27 ++ core/iwasm/common/iwasm_common.cmake | 6 +- core/iwasm/common/wasm_c_api.c | 4 +- core/iwasm/common/wasm_c_api_internal.h | 4 +- .../libc-builtin/libc_builtin_wrapper.c | 18 +- core/shared/platform/windows/platform_init.c | 18 + .../platform/windows/platform_internal.h | 66 +++ core/shared/platform/windows/posix_malloc.c | 27 ++ .../platform/windows/shared_platform.cmake | 18 + core/shared/platform/windows/win_memmap.c | 79 ++++ core/shared/platform/windows/win_thread.c | 162 +++++++ core/shared/platform/windows/win_time.c | 16 + core/shared/utils/uncommon/bh_read_file.c | 53 ++- product-mini/platforms/windows/CMakeLists.txt | 121 ++++++ product-mini/platforms/windows/main.c | 402 ++++++++++++++++++ wamr-compiler/CMakeLists.txt | 65 ++- wamr-compiler/build_llvm.py | 98 +++++ 23 files changed, 1186 insertions(+), 23 deletions(-) create mode 100644 core/iwasm/common/arch/invokeNative_ia32.asm create mode 100644 core/shared/platform/windows/platform_init.c create mode 100644 core/shared/platform/windows/platform_internal.h create mode 100644 core/shared/platform/windows/posix_malloc.c create mode 100644 core/shared/platform/windows/shared_platform.cmake create mode 100644 core/shared/platform/windows/win_memmap.c create mode 100644 core/shared/platform/windows/win_thread.c create mode 100644 core/shared/platform/windows/win_time.c create mode 100644 product-mini/platforms/windows/CMakeLists.txt create mode 100644 product-mini/platforms/windows/main.c create mode 100644 wamr-compiler/build_llvm.py diff --git a/README.md b/README.md index 44481bc05..446209f81 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,7 @@ Both wasm binary file and AoT file are supported by iwasm. The wamrc AoT compile ```shell cd wamr-compiler -./build_llvm.sh (use build_llvm_xtensa.sh instead to support xtensa target) +./build_llvm.sh (use build_llvm_xtensa.sh instead to support xtensa target; use build_llvm.py for windows) mkdir build && cd build cmake .. make @@ -72,6 +72,8 @@ ln -s {current path}/wamrc /usr/bin/wamrc ``` For MacOS, you should replace `cmake ..` with `cmake -DWAMR_BUILD_PLATFORM=darwin ..`. +For Windows you should replace `cmake ..` with `cmake -D WAMR_BUILD_PLATFORM=windows -A Win32 ..`. + Application framework =================================== diff --git a/build-scripts/runtime_lib.cmake b/build-scripts/runtime_lib.cmake index 6687ecc1b..eb5a90a15 100644 --- a/build-scripts/runtime_lib.cmake +++ b/build-scripts/runtime_lib.cmake @@ -82,8 +82,10 @@ if (WAMR_BUILD_THREAD_MGR EQUAL 1) endif () ####################### Common sources ####################### +if (NOT MSVC) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99 -ffunction-sections -fdata-sections \ -Wall -Wno-unused-parameter -Wno-pedantic") +endif () # include the build config template file include (${CMAKE_CURRENT_LIST_DIR}/config_common.cmake) diff --git a/core/config.h b/core/config.h index c14eac4e3..ba9a1a2fd 100644 --- a/core/config.h +++ b/core/config.h @@ -125,7 +125,11 @@ enum { #endif /* WASM Interpreter labels-as-values feature */ +#ifdef __GNUC__ #define WASM_ENABLE_LABELS_AS_VALUES 1 +#else +#define WASM_ENABLE_LABELS_AS_VALUES 0 +#endif /* Enable fast interpreter or not */ #ifndef WASM_ENABLE_FAST_INTERP diff --git a/core/iwasm/aot/aot_reloc.h b/core/iwasm/aot/aot_reloc.h index bd6391c07..882780a25 100644 --- a/core/iwasm/aot/aot_reloc.h +++ b/core/iwasm/aot/aot_reloc.h @@ -29,6 +29,16 @@ typedef struct { #define REG_ATOMIC_WAIT_SYM() #endif +#if (defined(_WIN32) || defined(_WIN32_)) && defined(NDEBUG) +#define REG_COMMON_SYMBOLS \ + REG_SYM(aot_set_exception_with_id), \ + REG_SYM(aot_invoke_native), \ + REG_SYM(aot_call_indirect), \ + REG_SYM(wasm_runtime_enlarge_memory), \ + REG_SYM(wasm_runtime_set_exception), \ + REG_BULK_MEMORY_SYM() \ + REG_ATOMIC_WAIT_SYM() +#else /* else of (defined(_WIN32) || defined(_WIN32_)) && defined(NDEBUG) */ #define REG_COMMON_SYMBOLS \ REG_SYM(aot_set_exception_with_id), \ REG_SYM(aot_invoke_native), \ @@ -49,6 +59,7 @@ typedef struct { REG_SYM(rintf), \ REG_BULK_MEMORY_SYM() \ REG_ATOMIC_WAIT_SYM() +#endif /* end of (defined(_WIN32) || defined(_WIN32_)) && defined(NDEBUG) */ #define CHECK_RELOC_OFFSET(data_size) do { \ if (!check_reloc_offset(target_section_size, reloc_offset, data_size, \ diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index 7be1a234e..107b5f936 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -1747,7 +1747,7 @@ aot_set_aux_stack(WASMExecEnv *exec_env, set the initial value for the global */ uint32 global_offset = module->globals[stack_top_idx].data_offset; - uint8 *global_addr = module_inst->global_data.ptr + global_offset; + uint8 *global_addr = (uint8 *)module_inst->global_data.ptr + global_offset; *(int32*)global_addr = start_offset; /* The aux stack boundary is a constant value, diff --git a/core/iwasm/aot/arch/aot_reloc_x86_32.c b/core/iwasm/aot/arch/aot_reloc_x86_32.c index a1424dae9..6cc470e91 100644 --- a/core/iwasm/aot/arch/aot_reloc_x86_32.c +++ b/core/iwasm/aot/arch/aot_reloc_x86_32.c @@ -15,11 +15,13 @@ void __umoddi3(); static SymbolMap target_sym_map[] = { REG_COMMON_SYMBOLS +#if !defined(_WIN32) && !defined(_WIN32_) /* compiler-rt symbols that come from compiler(e.g. gcc) */ REG_SYM(__divdi3), REG_SYM(__udivdi3), REG_SYM(__moddi3), REG_SYM(__umoddi3) +#endif }; static void diff --git a/core/iwasm/common/arch/invokeNative_ia32.asm b/core/iwasm/common/arch/invokeNative_ia32.asm new file mode 100644 index 000000000..8bd28722c --- /dev/null +++ b/core/iwasm/common/arch/invokeNative_ia32.asm @@ -0,0 +1,27 @@ +; +; Copyright (C) 2019 Intel Corporation. All rights reserved. +; SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +; + + .386 + .model flat + .code +_invokeNative PROC + push ebp + mov ebp,esp + mov ecx, [ebp+16] ; ecx = argc */ + mov edx, [ebp+12] ; edx = argv */ + test ecx, ecx + jz skip_push_args ; if ecx == 0, skip pushing arguments */ + lea edx, [edx+ecx*4-4] ; edx = edx + ecx * 4 - 4 */ + sub edx,esp ; edx = edx - esp */ +loop_push: + push [esp+edx] + loop loop_push ; loop ecx counts */ +skip_push_args: + mov edx, [ebp+8] ; edx = func_ptr */ + call edx + leave + ret +_invokeNative ENDP +END \ No newline at end of file diff --git a/core/iwasm/common/iwasm_common.cmake b/core/iwasm/common/iwasm_common.cmake index aa3683d35..50173c4ff 100644 --- a/core/iwasm/common/iwasm_common.cmake +++ b/core/iwasm/common/iwasm_common.cmake @@ -13,7 +13,11 @@ file (GLOB c_source_all ${IWASM_COMMON_DIR}/*.c) if (WAMR_BUILD_TARGET STREQUAL "X86_64" OR WAMR_BUILD_TARGET STREQUAL "AMD_64") set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_em64.s) elseif (WAMR_BUILD_TARGET STREQUAL "X86_32") - set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_ia32.s) + if (WAMR_BUILD_PLATFORM STREQUAL "windows") + set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_ia32.asm) + else () + set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_ia32.s) + endif () elseif (WAMR_BUILD_TARGET MATCHES "ARM.*") if (WAMR_BUILD_TARGET MATCHES "ARM.*_VFP") set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_arm_vfp.s) diff --git a/core/iwasm/common/wasm_c_api.c b/core/iwasm/common/wasm_c_api.c index d8e2ddc28..7439ef217 100644 --- a/core/iwasm/common/wasm_c_api.c +++ b/core/iwasm/common/wasm_c_api.c @@ -1785,7 +1785,7 @@ aot_global_set(const AOTModuleInstance *inst_aot, .type; } - data = inst_aot->global_data.ptr + data_offset; + data = (void *)((uint8 *)inst_aot->global_data.ptr + data_offset); switch (val_type_rt) { case VALUE_TYPE_I32: bh_assert(WASM_I32 == v->kind); @@ -1834,7 +1834,7 @@ aot_global_get(const AOTModuleInstance *inst_aot, .type; } - data = inst_aot->global_data.ptr + data_offset; + data = (void *)((uint8 *)inst_aot->global_data.ptr + data_offset); switch (val_type_rt) { case VALUE_TYPE_I32: out->kind = WASM_I32; diff --git a/core/iwasm/common/wasm_c_api_internal.h b/core/iwasm/common/wasm_c_api_internal.h index b321ff873..40d049aa7 100644 --- a/core/iwasm/common/wasm_c_api_internal.h +++ b/core/iwasm/common/wasm_c_api_internal.h @@ -91,7 +91,9 @@ struct wasm_export_type_t { }; /* Runtime Objects */ -struct wasm_ref_t {}; +struct wasm_ref_t { + uint32 obj; +}; struct wasm_trap_t { wasm_byte_vec_t *message; diff --git a/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c b/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c index 88ebc0131..4bdf55000 100644 --- a/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c +++ b/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c @@ -8,6 +8,11 @@ #include "wasm_export.h" #include "../interpreter/wasm.h" +#if defined(_WIN32) || defined(_WIN32_) +#define strncasecmp _strnicmp +#define strcasecmp _stricmp +#endif + void wasm_runtime_set_exception(wasm_module_inst_t module, const char *exception); @@ -213,8 +218,17 @@ _vprintf_wa(out_func_t out, void *ctx, const char *fmt, _va_list ap, padding = PAD_ZERO_BEFORE; goto still_might_format; } - /* Fall through */ - case '1' ... '9': + goto handle_1_to_9; + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': +handle_1_to_9: if (min_width < 0) { min_width = *fmt - '0'; } else { diff --git a/core/shared/platform/windows/platform_init.c b/core/shared/platform/windows/platform_init.c new file mode 100644 index 000000000..76594b816 --- /dev/null +++ b/core/shared/platform/windows/platform_init.c @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "platform_api_vmcore.h" + +int +bh_platform_init() +{ + return 0; +} + +void +bh_platform_destroy() +{ +} + diff --git a/core/shared/platform/windows/platform_internal.h b/core/shared/platform/windows/platform_internal.h new file mode 100644 index 000000000..8803e8029 --- /dev/null +++ b/core/shared/platform/windows/platform_internal.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _PLATFORM_INTERNAL_H +#define _PLATFORM_INTERNAL_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef BH_PLATFORM_WINDOWS +#define BH_PLATFORM_WINDOWS +#endif + +/* Stack size of applet threads's native part. */ +#define BH_APPLET_PRESERVED_STACK_SIZE (32 * 1024) + +/* Default thread priority */ +#define BH_THREAD_DEFAULT_PRIORITY 0 + +typedef void *korp_tid; +typedef void *korp_mutex; +typedef void *korp_sem; +typedef void *korp_thread; + +typedef struct { + korp_sem s; + unsigned int waiting_count; +} korp_cond; + +#define os_printf printf +#define os_vprintf vprintf + +static inline size_t getpagesize() { + SYSTEM_INFO S; + GetNativeSystemInfo(&S); + return S.dwPageSize; +} + +#ifdef __cplusplus +} +#endif + +#endif /* end of _PLATFORM_INTERNAL_H */ + diff --git a/core/shared/platform/windows/posix_malloc.c b/core/shared/platform/windows/posix_malloc.c new file mode 100644 index 000000000..e83fc7d7b --- /dev/null +++ b/core/shared/platform/windows/posix_malloc.c @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "platform_api_vmcore.h" + +void * +os_malloc(unsigned size) +{ + return malloc(size); +} + +void * +os_realloc(void *ptr, unsigned size) +{ + return realloc(ptr, size); +} + +void +os_free(void *ptr) +{ + free(ptr); +} + + + diff --git a/core/shared/platform/windows/shared_platform.cmake b/core/shared/platform/windows/shared_platform.cmake new file mode 100644 index 000000000..6ab29c890 --- /dev/null +++ b/core/shared/platform/windows/shared_platform.cmake @@ -0,0 +1,18 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +set (PLATFORM_SHARED_DIR ${CMAKE_CURRENT_LIST_DIR}) + +add_definitions(-DBH_PLATFORM_WINDOWS) +add_definitions(-DHAVE_STRUCT_TIMESPEC) + + +include_directories(${PLATFORM_SHARED_DIR}) +include_directories(${PLATFORM_SHARED_DIR}/../include) + +file (GLOB_RECURSE source_all ${PLATFORM_SHARED_DIR}/*.c) + +set (PLATFORM_SHARED_SOURCE ${source_all}) + +file (GLOB header ${PLATFORM_SHARED_DIR}/../include/*.h) +LIST (APPEND RUNTIME_LIB_HEADER_LIST ${header}) diff --git a/core/shared/platform/windows/win_memmap.c b/core/shared/platform/windows/win_memmap.c new file mode 100644 index 000000000..e5d478b16 --- /dev/null +++ b/core/shared/platform/windows/win_memmap.c @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "platform_api_vmcore.h" +void * os_mmap(void *hint, size_t size, int prot, int flags) +{ + DWORD AllocType = MEM_RESERVE | MEM_COMMIT; + DWORD flProtect = PAGE_NOACCESS; + size_t request_size, page_size; + void *addr; + + page_size = getpagesize(); + request_size = (size + page_size - 1) & ~(page_size - 1); + + if (request_size < size) + /* integer overflow */ + return NULL; + + if (prot & MMAP_PROT_EXEC) { + if (prot & MMAP_PROT_WRITE) + flProtect = PAGE_EXECUTE_READWRITE; + else + flProtect = PAGE_EXECUTE_READ; + } + else if (prot & MMAP_PROT_WRITE) + flProtect = PAGE_READWRITE; + else if (prot & MMAP_PROT_READ) + flProtect = PAGE_READONLY; + + + addr = VirtualAlloc((LPVOID)hint, request_size, AllocType, + flProtect); + return addr; +} + +void +os_munmap(void *addr, size_t size) +{ + size_t page_size = getpagesize(); + size_t request_size = (size + page_size - 1) & ~(page_size - 1); + if (addr) { + + if (VirtualFree(addr, 0, MEM_RELEASE) == 0) { + if (VirtualFree(addr, size, MEM_DECOMMIT) == 0) { + os_printf("os_munmap error addr:%p, size:0x%lx, errno:%d\n", + addr, request_size, errno); + } + } + } +} + +int +os_mprotect(void *addr, size_t size, int prot) +{ + DWORD AllocType = MEM_RESERVE | MEM_COMMIT; + DWORD flProtect = PAGE_NOACCESS; + if (!addr) + return 0; + + if (prot & MMAP_PROT_EXEC) { + if (prot & MMAP_PROT_WRITE) + flProtect = PAGE_EXECUTE_READWRITE; + else + flProtect = PAGE_EXECUTE_READ; + } + else if (prot & MMAP_PROT_WRITE) + flProtect = PAGE_READWRITE; + else if (prot & MMAP_PROT_READ) + flProtect = PAGE_READONLY; + + return VirtualProtect((LPVOID)addr, size, flProtect, NULL); +} + +void +os_dcache_flush(void) +{ +} diff --git a/core/shared/platform/windows/win_thread.c b/core/shared/platform/windows/win_thread.c new file mode 100644 index 000000000..d4b9e64a8 --- /dev/null +++ b/core/shared/platform/windows/win_thread.c @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#include "platform_api_vmcore.h" +#include "platform_api_extension.h" + +typedef struct { + thread_start_routine_t start; + void* stack; + uint32 stack_size; + void* arg; +} thread_wrapper_arg; + +static void *os_thread_wrapper(void *arg) +{ + thread_wrapper_arg * targ = arg; + thread_start_routine_t start_func = targ->start; + void *thread_arg = targ->arg; + os_printf("THREAD CREATED %p\n", &targ); + targ->stack = (void *)((uintptr_t)(&arg) & (uintptr_t)~0xfff); + BH_FREE(targ); + start_func(thread_arg); + return NULL; +} + +int os_thread_create_with_prio(korp_tid *tid, thread_start_routine_t start, + void *arg, unsigned int stack_size, int prio) +{ + return BHT_ERROR; +} + +int os_thread_create(korp_tid *tid, thread_start_routine_t start, void *arg, + unsigned int stack_size) +{ + return os_thread_create_with_prio(tid, start, arg, stack_size, + BH_THREAD_DEFAULT_PRIORITY); +} + +korp_tid os_self_thread() +{ + return NULL; +} + +int os_mutex_init(korp_mutex *mutex) +{ + return BHT_OK; +} + +int os_recursive_mutex_init(korp_mutex *mutex) +{ + return BHT_OK; +} + +int os_mutex_destroy(korp_mutex *mutex) +{ + return BHT_OK; +} + +/* Returned error (EINVAL, EAGAIN and EDEADLK) from + locking the mutex indicates some logic error present in + the program somewhere. + Don't try to recover error for an existing unknown error.*/ +int os_mutex_lock(korp_mutex *mutex) +{ + return BHT_ERROR; +} + +/* Returned error (EINVAL, EAGAIN and EPERM) from + unlocking the mutex indicates some logic error present + in the program somewhere. + Don't try to recover error for an existing unknown error.*/ +int os_mutex_unlock(korp_mutex *mutex) +{ + return BHT_OK; +} + +int os_cond_init(korp_cond *cond) +{ + return BHT_OK; +} + +int os_cond_destroy(korp_cond *cond) +{ + return BHT_OK; +} + +int os_cond_wait(korp_cond *cond, korp_mutex *mutex) +{ + return BHT_OK; +} + + +int gettimeofday(struct timeval * tp, struct timezone * tzp) +{ + // Note: some broken versions only have 8 trailing zero's, the correct epoch has 9 trailing zero's + // This magic number is the number of 100 nanosecond intervals since January 1, 1601 (UTC) + // until 00:00:00 January 1, 1970 + static const uint64_t EPOCH = ((uint64_t) 116444736000000000ULL); + + SYSTEMTIME system_time; + FILETIME file_time; + uint64_t time; + + GetSystemTime( &system_time ); + SystemTimeToFileTime( &system_time, &file_time ); + time = ((uint64_t)file_time.dwLowDateTime ) ; + time += ((uint64_t)file_time.dwHighDateTime) << 32; + + tp->tv_sec = (long) ((time - EPOCH) / 10000000L); + tp->tv_usec = (long) (system_time.wMilliseconds * 1000); + return 0; +} + +static void msec_nsec_to_abstime(struct timespec *ts, int usec) +{ + struct timeval tv; + + gettimeofday(&tv, NULL); + + ts->tv_sec = (long int)(tv.tv_sec + usec / 1000000); + ts->tv_nsec = (long int)(tv.tv_usec * 1000 + (usec % 1000000) * 1000); + + if (ts->tv_nsec >= 1000000000L) { + ts->tv_sec++; + ts->tv_nsec -= 1000000000L; + } +} + +int os_cond_reltimedwait(korp_cond *cond, korp_mutex *mutex, int useconds) +{ + return BHT_OK; +} + +int os_cond_signal(korp_cond *cond) +{ + return BHT_OK; +} + +int os_thread_join(korp_tid thread, void **value_ptr) +{ + return BHT_OK; +} + +int os_thread_detach(korp_tid thread) +{ + return BHT_OK; +} + +void os_thread_exit(void *retval) +{ + return BHT_OK; +} + +uint8 *os_thread_get_stack_boundary() +{ + return NULL; +} diff --git a/core/shared/platform/windows/win_time.c b/core/shared/platform/windows/win_time.c new file mode 100644 index 000000000..3028a2efb --- /dev/null +++ b/core/shared/platform/windows/win_time.c @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "platform_api_vmcore.h" + +uint64 +os_time_get_boot_microsecond() +{ + struct timespec ts; + timespec_get(&ts, TIME_UTC); + + return ((uint64) ts.tv_sec) * 1000 * 1000 + ((uint64)ts.tv_nsec) / 1000; +} + diff --git a/core/shared/utils/uncommon/bh_read_file.c b/core/shared/utils/uncommon/bh_read_file.c index f93b28d08..08165c535 100644 --- a/core/shared/utils/uncommon/bh_read_file.c +++ b/core/shared/utils/uncommon/bh_read_file.c @@ -2,8 +2,59 @@ #include #include +#if defined(_WIN32) || defined(_WIN32_) +#include +#else #include +#endif +#if defined(_WIN32) || defined(_WIN32_) +char* +bh_read_file_to_buffer(const char *filename, uint32 *ret_size) +{ + char *buffer; + int file; + uint32 file_size, read_size; + struct stat stat_buf; + + if (!filename || !ret_size) { + printf("Read file to buffer failed: invalid filename or ret size.\n"); + return NULL; + } + + if (_sopen_s(&file, filename, _O_RDONLY| _O_BINARY, _SH_DENYNO, 0)) { + printf("Read file to buffer failed: open file %s failed.\n", + filename); + return NULL; + } + + if (fstat(file, &stat_buf) != 0) { + printf("Read file to buffer failed: fstat file %s failed.\n", + filename); + _close(file); + return NULL; + } + file_size = (uint32)stat_buf.st_size; + + if (!(buffer = (char *)BH_MALLOC(file_size))) { + printf("Read file to buffer failed: alloc memory failed.\n"); + _close(file); + return NULL; + } + + read_size = _read(file, buffer, file_size); + _close(file); + + if (read_size < file_size) { + printf("Read file to buffer failed: read file content failed.\n"); + BH_FREE(buffer); + return NULL; + } + + *ret_size = file_size; + return buffer; +} +#else /* else of defined(_WIN32) || defined(_WIN32_) */ char* bh_read_file_to_buffer(const char *filename, uint32 *ret_size) { @@ -50,4 +101,4 @@ bh_read_file_to_buffer(const char *filename, uint32 *ret_size) *ret_size = file_size; return buffer; } - +#endif /* end of defined(_WIN32) || defined(_WIN32_) */ diff --git a/product-mini/platforms/windows/CMakeLists.txt b/product-mini/platforms/windows/CMakeLists.txt new file mode 100644 index 000000000..3bc67d4ce --- /dev/null +++ b/product-mini/platforms/windows/CMakeLists.txt @@ -0,0 +1,121 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required (VERSION 2.8) + +project (iwasm C ASM) +enable_language(ASM_MASM) +# set (CMAKE_VERBOSE_MAKEFILE 1) + +set (WAMR_BUILD_PLATFORM "windows") + +# Reset default linker flags +set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") +set (CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") + +set (CMAKE_C_STANDARD 99) + +# Set WAMR_BUILD_TARGET, currently values supported: +# "X86_64", "AMD_64", "X86_32", "AARCH64[sub]", "ARM[sub]", "THUMB[sub]", "MIPS", "XTENSA" +if (NOT DEFINED WAMR_BUILD_TARGET) + if (CMAKE_SIZEOF_VOID_P EQUAL 8) + # Build as X86_64 by default in 64-bit platform + set (WAMR_BUILD_TARGET "X86_64") + else () + # Build as X86_32 by default in 32-bit platform + set (WAMR_BUILD_TARGET "X86_32") + endif () +endif () + +if (NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Release) +endif () + +if (NOT DEFINED WAMR_BUILD_INTERP) + # Enable Interpreter by default + set (WAMR_BUILD_INTERP 1) +endif () + +if (NOT DEFINED WAMR_BUILD_AOT) + # Enable AOT by default. + set (WAMR_BUILD_AOT 1) +endif () + +if (NOT DEFINED WAMR_BUILD_JIT) + # Disable JIT by default. + set (WAMR_BUILD_JIT 0) +endif () + +if (NOT DEFINED WAMR_BUILD_LIBC_BUILTIN) + # Enable libc builtin support by default + set (WAMR_BUILD_LIBC_BUILTIN 1) +endif () + +if (NOT DEFINED WAMR_BUILD_LIBC_WASI) + # Enable libc wasi support by default + set (WAMR_BUILD_LIBC_WASI 0) +endif () + +if (NOT DEFINED WAMR_BUILD_FAST_INTERP) + # Enable fast interpreter + set (WAMR_BUILD_FAST_INTERP 0) +endif () + +if (NOT DEFINED WAMR_BUILD_MULTI_MODULE) + # Enable multiple modules + set (WAMR_BUILD_MULTI_MODULE 0) +endif () + +if (NOT DEFINED WAMR_BUILD_LIB_PTHREAD) + # Disable pthread library by default + set (WAMR_BUILD_LIB_PTHREAD 0) +endif () + +if (NOT DEFINED WAMR_BUILD_MINI_LOADER) + # Disable wasm mini loader by default + set (WAMR_BUILD_MINI_LOADER 0) +endif () + +if (COLLECT_CODE_COVERAGE EQUAL 1) + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage") +endif () + +set (WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../..) + +include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) +add_library(vmlib ${WAMR_RUNTIME_LIB_SOURCE}) + +set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SAFESEH:NO") + +# set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat -Wformat-security") +# set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wconversion -Wsign-conversion") + +if (WAMR_BUILD_TARGET MATCHES "X86_.*" OR WAMR_BUILD_TARGET STREQUAL "AMD_64") + if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang" OR MSVC)) + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mindirect-branch-register") + endif () +endif () + +# The following flags are to enhance security, but it may impact performance, +# we disable them by default. +#if (WAMR_BUILD_TARGET MATCHES "X86_.*" OR WAMR_BUILD_TARGET STREQUAL "AMD_64") +# set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ftrapv -D_FORTIFY_SOURCE=2") +#endif () +#set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fstack-protector-strong --param ssp-buffer-size=4") +#set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wl,-z,noexecstack,-z,relro,-z,now") + +include (${SHARED_DIR}/utils/uncommon/shared_uncommon.cmake) + +add_executable (iwasm main.c ${UNCOMMON_SHARED_SOURCE}) + +install (TARGETS iwasm DESTINATION bin) + +target_link_libraries (iwasm vmlib ${LLVM_AVAILABLE_LIBS}) + +add_library (libiwasm SHARED ${WAMR_RUNTIME_LIB_SOURCE}) + +install (TARGETS libiwasm DESTINATION lib) + +set_target_properties (libiwasm PROPERTIES OUTPUT_NAME iwasm) + +target_link_libraries (libiwasm ${LLVM_AVAILABLE_LIBS}) diff --git a/product-mini/platforms/windows/main.c b/product-mini/platforms/windows/main.c new file mode 100644 index 000000000..bed5ee4d5 --- /dev/null +++ b/product-mini/platforms/windows/main.c @@ -0,0 +1,402 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include +#include + +#include "bh_platform.h" +#include "bh_read_file.h" +#include "wasm_export.h" + +static int app_argc; +static char **app_argv; + +#define MODULE_PATH ("--module-path=") + +static int +print_help() +{ + printf("Usage: iwasm [-options] wasm_file [args...]\n"); + printf("options:\n"); + printf(" -f|--function name Specify a function name of the module to run rather\n" + " than main\n"); +#if WASM_ENABLE_LOG != 0 + printf(" -v=n Set log verbose level (0 to 5, default is 2) larger\n" + " level with more log\n"); +#endif + printf(" --stack-size=n Set maximum stack size in bytes, default is 16 KB\n"); + printf(" --heap-size=n Set maximum heap size in bytes, default is 16 KB\n"); + printf(" --repl Start a very simple REPL (read-eval-print-loop) mode\n" + " that runs commands in the form of `FUNC ARG...`\n"); +#if WASM_ENABLE_LIBC_WASI != 0 + printf(" --env= Pass wasi environment variables with \"key=value\"\n"); + printf(" to the program, for example:\n"); + printf(" --env=\"key1=value1\" --env=\"key2=value2\"\n"); + printf(" --dir= Grant wasi access to the given host directories\n"); + printf(" to the program, for example:\n"); + printf(" --dir= --dir=\n"); +#endif +#if WASM_ENABLE_MULTI_MODULE != 0 + printf(" --module-path= Indicate a module search path. default is current\n" + " directory('./')\n"); +#endif +#if WASM_ENABLE_LIB_PTHREAD != 0 + printf(" --max-threads=n Set maximum thread number per cluster, default is 4\n"); +#endif + return 1; +} + +static void * +app_instance_main(wasm_module_inst_t module_inst) +{ + const char *exception; + + wasm_application_execute_main(module_inst, app_argc, app_argv); + if ((exception = wasm_runtime_get_exception(module_inst))) + printf("%s\n", exception); + return NULL; +} + +static void * +app_instance_func(wasm_module_inst_t module_inst, const char *func_name) +{ + wasm_application_execute_func(module_inst, func_name, app_argc - 1, + app_argv + 1); + /* The result of wasm function or exception info was output inside + wasm_application_execute_func(), here we don't output them again. */ + return NULL; +} + +/** + * Split a space separated strings into an array of strings + * Returns NULL on failure + * Memory must be freed by caller + * Based on: http://stackoverflow.com/a/11198630/471795 + */ +static char ** +split_string(char *str, int *count) +{ + char **res = NULL; + char *p; + int idx = 0; + + /* split string and append tokens to 'res' */ + do { + p = strtok(str, " "); + str = NULL; + res = (char **)realloc(res, sizeof(char *) * (uint32)(idx + 1)); + if (res == NULL) { + return NULL; + } + res[idx++] = p; + } while (p); + + /** + * since the function name, + * res[0] might be contains a '\' to indicate a space + * func\name -> func name + */ + p = strchr(res[0], '\\'); + while (p) { + *p = ' '; + p = strchr(p, '\\'); + } + + if (count) { + *count = idx - 1; + } + return res; +} + +static void * +app_instance_repl(wasm_module_inst_t module_inst) +{ + char buffer[4096]; + char *cmd; + size_t n; + + while ((printf("webassembly> "), + cmd = fgets(buffer, sizeof(buffer), stdin)) != -1) { + bh_assert(cmd); + n = strlen(cmd); + if (cmd[n - 1] == '\n') { + if (n == 1) + continue; + else + cmd[n - 1] = '\0'; + } + if (!strcmp(cmd, "__exit__")) { + printf("exit repl mode\n"); + break; + } + app_argv = split_string(cmd, &app_argc); + if (app_argv == NULL) { + LOG_ERROR("Wasm prepare param failed: split string failed.\n"); + break; + } + if (app_argc != 0) { + wasm_application_execute_func(module_inst, app_argv[0], + app_argc - 1, app_argv + 1); + } + free(app_argv); + } + + return NULL; +} + +#if WASM_ENABLE_LIBC_WASI != 0 +static bool +validate_env_str(char *env) +{ + char *p = env; + int key_len = 0; + + while (*p != '\0' && *p != '=') { + key_len++; + p++; + } + + if (*p != '=' || key_len == 0) + return false; + + return true; +} +#endif + +#define USE_GLOBAL_HEAP_BUF 0 + +#if USE_GLOBAL_HEAP_BUF != 0 +static char global_heap_buf[10 * 1024 * 1024] = { 0 }; +#endif + +#if WASM_ENABLE_MULTI_MODULE != 0 +static char * +handle_module_path(const char *module_path) +{ + // next character after = + return (strchr(module_path, '=')) + 1; +} + +static char *module_search_path = "."; +static bool +module_reader_callback(const char *module_name, uint8 **p_buffer, + uint32 *p_size) +{ + const char *format = "%s/%s.wasm"; + int sz = strlen(module_search_path) + strlen("/") + strlen(module_name) + + strlen(".wasm") + 1; + char *wasm_file_name = BH_MALLOC(sz); + if (!wasm_file_name) { + return false; + } + + snprintf(wasm_file_name, sz, format, module_search_path, module_name); + + *p_buffer = (uint8_t *)bh_read_file_to_buffer(wasm_file_name, p_size); + + wasm_runtime_free(wasm_file_name); + return *p_buffer != NULL; +} + +static void +moudle_destroyer(uint8 *buffer, uint32 size) +{ + if (!buffer) { + return; + } + + wasm_runtime_free(buffer); + buffer = NULL; +} +#endif /* WASM_ENABLE_MULTI_MODULE */ + +int +main(int argc, char *argv[]) +{ + char *wasm_file = NULL; + const char *func_name = NULL; + uint8 *wasm_file_buf = NULL; + uint32 wasm_file_size; + uint32 stack_size = 16 * 1024, heap_size = 16 * 1024; + wasm_module_t wasm_module = NULL; + wasm_module_inst_t wasm_module_inst = NULL; + RuntimeInitArgs init_args; + char error_buf[128] = { 0 }; +#if WASM_ENABLE_LOG != 0 + int log_verbose_level = 2; +#endif + bool is_repl_mode = false; +#if WASM_ENABLE_LIBC_WASI != 0 + const char *dir_list[8] = { NULL }; + uint32 dir_list_size = 0; + const char *env_list[8] = { NULL }; + uint32 env_list_size = 0; +#endif + + /* Process options. */ + // TODO: use a option name and option handler pair table to + // optimize + for (argc--, argv++; argc > 0 && argv[0][0] == '-'; argc--, argv++) { + if (!strcmp(argv[0], "-f") || !strcmp(argv[0], "--function")) { + argc--, argv++; + if (argc < 2) { + print_help(); + return 0; + } + func_name = argv[0]; + } +#if WASM_ENABLE_LOG != 0 + else if (!strncmp(argv[0], "-v=", 3)) { + log_verbose_level = atoi(argv[0] + 3); + if (log_verbose_level < 0 || log_verbose_level > 5) + return print_help(); + } +#endif + else if (!strcmp(argv[0], "--repl")) { + is_repl_mode = true; + } + else if (!strncmp(argv[0], "--stack-size=", 13)) { + if (argv[0][13] == '\0') + return print_help(); + stack_size = atoi(argv[0] + 13); + } + else if (!strncmp(argv[0], "--heap-size=", 12)) { + if (argv[0][12] == '\0') + return print_help(); + heap_size = atoi(argv[0] + 12); + } +#if WASM_ENABLE_LIBC_WASI != 0 + else if (!strncmp(argv[0], "--dir=", 6)) { + if (argv[0][6] == '\0') + return print_help(); + if (dir_list_size >= sizeof(dir_list) / sizeof(char *)) { + printf("Only allow max dir number %d\n", + (int)(sizeof(dir_list) / sizeof(char *))); + return -1; + } + dir_list[dir_list_size++] = argv[0] + 6; + } + else if (!strncmp(argv[0], "--env=", 6)) { + char *tmp_env; + + if (argv[0][6] == '\0') + return print_help(); + if (env_list_size >= sizeof(env_list) / sizeof(char *)) { + printf("Only allow max env number %d\n", + (int)(sizeof(env_list) / sizeof(char *))); + return -1; + } + tmp_env = argv[0] + 6; + if (validate_env_str(tmp_env)) + env_list[env_list_size++] = tmp_env; + else { + printf("Wasm parse env string failed: expect \"key=value\", " + "got \"%s\"\n", + tmp_env); + return print_help(); + } + } +#endif /* WASM_ENABLE_LIBC_WASI */ +#if WASM_ENABLE_MULTI_MODULE != 0 + else if (!strncmp(argv[0], MODULE_PATH, strlen(MODULE_PATH))) { + module_search_path = handle_module_path(argv[0]); + if (!strlen(module_search_path)) { + return print_help(); + } + } +#endif +#if WASM_ENABLE_LIB_PTHREAD != 0 + else if (!strncmp(argv[0], "--max-threads=", 14)) { + if (argv[0][14] == '\0') + return print_help(); + wasm_runtime_set_max_thread_num(atoi(argv[0] + 14)); + } +#endif + else + return print_help(); + } + + if (argc == 0) + return print_help(); + + wasm_file = argv[0]; + app_argc = argc; + app_argv = argv; + + memset(&init_args, 0, sizeof(RuntimeInitArgs)); + +#if USE_GLOBAL_HEAP_BUF != 0 + init_args.mem_alloc_type = Alloc_With_Pool; + init_args.mem_alloc_option.pool.heap_buf = global_heap_buf; + init_args.mem_alloc_option.pool.heap_size = sizeof(global_heap_buf); +#else + init_args.mem_alloc_type = Alloc_With_Allocator; + init_args.mem_alloc_option.allocator.malloc_func = malloc; + init_args.mem_alloc_option.allocator.realloc_func = realloc; + init_args.mem_alloc_option.allocator.free_func = free; +#endif + + /* initialize runtime environment */ + if (!wasm_runtime_full_init(&init_args)) { + printf("Init runtime environment failed.\n"); + return -1; + } + +#if WASM_ENABLE_LOG != 0 + bh_log_set_verbose_level(log_verbose_level); +#endif + + /* load WASM byte buffer from WASM bin file */ + if (!(wasm_file_buf = + (uint8 *)bh_read_file_to_buffer(wasm_file, &wasm_file_size))) + goto fail1; + +#if WASM_ENABLE_MULTI_MODULE != 0 + wasm_runtime_set_module_reader(module_reader_callback, moudle_destroyer); +#endif + + /* load WASM module */ + if (!(wasm_module = wasm_runtime_load(wasm_file_buf, wasm_file_size, + error_buf, sizeof(error_buf)))) { + printf("%s\n", error_buf); + goto fail2; + } + +#if WASM_ENABLE_LIBC_WASI != 0 + wasm_runtime_set_wasi_args(wasm_module, dir_list, dir_list_size, NULL, 0, + env_list, env_list_size, argv, argc); +#endif + + /* instantiate the module */ + if (!(wasm_module_inst = + wasm_runtime_instantiate(wasm_module, stack_size, heap_size, + error_buf, sizeof(error_buf)))) { + printf("%s\n", error_buf); + goto fail3; + } + + if (is_repl_mode) + app_instance_repl(wasm_module_inst); + else if (func_name) + app_instance_func(wasm_module_inst, func_name); + else + app_instance_main(wasm_module_inst); + + /* destroy the module instance */ + wasm_runtime_deinstantiate(wasm_module_inst); + +fail3: + /* unload the module */ + wasm_runtime_unload(wasm_module); + +fail2: + /* free the file buffer */ + wasm_runtime_free(wasm_file_buf); + +fail1: + /* destroy runtime environment */ + wasm_runtime_destroy(); + return 0; +} diff --git a/wamr-compiler/CMakeLists.txt b/wamr-compiler/CMakeLists.txt index d27de87c3..7efe1c0e9 100644 --- a/wamr-compiler/CMakeLists.txt +++ b/wamr-compiler/CMakeLists.txt @@ -1,8 +1,14 @@ # Copyright (C) 2019 Intel Corporation. All rights reserved. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + cmake_minimum_required (VERSION 2.8) -project (aot-compiler) +if (NOT WAMR_BUILD_PLATFORM STREQUAL "windows") + project (aot-compiler) +else() + project (aot-compiler C ASM) + enable_language (ASM_MASM) +endif() if (NOT DEFINED WAMR_BUILD_PLATFORM) set (WAMR_BUILD_PLATFORM "linux") @@ -29,6 +35,11 @@ if (NOT WAMR_BUILD_TARGET) # Build as X86_32 by default in 32-bit platform set (WAMR_BUILD_TARGET "X86_32") endif () + if (WAMR_BUILD_PLATFORM STREQUAL "windows") + if (("${CMAKE_GENERATOR_PLATFORM}" STREQUAL "Win32")) + set (WAMR_BUILD_TARGET "X86_32") + endif() + endif() endif () string(TOUPPER ${WAMR_BUILD_TARGET} WAMR_BUILD_TARGET) @@ -71,10 +82,18 @@ message ("-- CMAKE_BUILD_TYPE = " ${CMAKE_BUILD_TYPE}) # Enable LLVM set (LLVM_SRC_ROOT "${PROJECT_SOURCE_DIR}/../core/deps/llvm") -if (NOT EXISTS "${LLVM_SRC_ROOT}/build") - message (FATAL_ERROR "Cannot find LLVM dir: ${LLVM_SRC_ROOT}/build") +if (WAMR_BUILD_PLATFORM STREQUAL "windows") + if (NOT EXISTS "${LLVM_SRC_ROOT}/win32build") + message (FATAL_ERROR "Cannot find LLVM dir: ${LLVM_SRC_ROOT}/win32build") + endif () + set (CMAKE_PREFIX_PATH "${LLVM_SRC_ROOT}/win32build;${CMAKE_PREFIX_PATH}") +else() + if (NOT EXISTS "${LLVM_SRC_ROOT}/build") + message (FATAL_ERROR "Cannot find LLVM dir: ${LLVM_SRC_ROOT}/build") + endif () + set (CMAKE_PREFIX_PATH "${LLVM_SRC_ROOT}/build;${CMAKE_PREFIX_PATH}") endif () -set (CMAKE_PREFIX_PATH "${LLVM_SRC_ROOT}/build;${CMAKE_PREFIX_PATH}") + find_package(LLVM REQUIRED CONFIG) include_directories(${LLVM_INCLUDE_DIRS}) add_definitions(${LLVM_DEFINITIONS}) @@ -83,10 +102,17 @@ message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang")) - set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") + if(NOT MSVC) + set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") + else() + set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SAFESEH:NO") + endif() +endif() + +if (NOT MSVC) + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ffunction-sections -fdata-sections \ + -Wall -Wno-unused-parameter -Wno-pedantic") endif() -set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ffunction-sections -fdata-sections \ - -Wall -Wno-unused-parameter -Wno-pedantic") set (SHARED_DIR ../core/shared) set (IWASM_DIR ../core/iwasm) @@ -108,20 +134,28 @@ include (${IWASM_DIR}/interpreter/iwasm_interp.cmake) include (${IWASM_DIR}/aot/iwasm_aot.cmake) include (${IWASM_DIR}/compilation/iwasm_compl.cmake) -set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat -Wformat-security") +if (NOT MSVC) + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat -Wformat-security") +endif() + # set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wconversion -Wsign-conversion") if (WAMR_BUILD_TARGET MATCHES "X86_.*" OR WAMR_BUILD_TARGET STREQUAL "AMD_64") - if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang")) + if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang" OR MSVC)) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mindirect-branch-register") endif() endif () -set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fstack-protector-strong --param ssp-buffer-size=4") -set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wl,-z,noexecstack,-z,relro,-z,now") + +if (NOT MSVC) + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fstack-protector-strong --param ssp-buffer-size=4") + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wl,-z,noexecstack,-z,relro,-z,now") +endif() # We disable these flags by default to stay the same with wasm runtime # set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mindirect-branch=thunk -mfunction-return=thunk") -set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pie -fPIE -ftrapv -D_FORTIFY_SOURCE=2") +if (NOT MSVC) + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pie -fPIE -ftrapv -D_FORTIFY_SOURCE=2") +endif() # message ("-- CMAKE_C_FLAGS: ${CMAKE_C_FLAGS}") @@ -140,5 +174,8 @@ add_library (aotclib ${IWASM_COMPL_SOURCE}) add_executable (wamrc main.c) -target_link_libraries (wamrc aotclib vmlib ${LLVM_AVAILABLE_LIBS} -lm -ldl -lpthread) - +if (NOT MSVC) + target_link_libraries (wamrc aotclib vmlib LLVMDemangle ${LLVM_AVAILABLE_LIBS} -lm -ldl -lpthread) +else() + target_link_libraries (wamrc aotclib vmlib ${LLVM_AVAILABLE_LIBS}) +endif() diff --git a/wamr-compiler/build_llvm.py b/wamr-compiler/build_llvm.py new file mode 100644 index 000000000..ba965a350 --- /dev/null +++ b/wamr-compiler/build_llvm.py @@ -0,0 +1,98 @@ +# +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# + +#!/usr/bin/env python3 +import os +import sys +from pathlib import Path + +def clone_llvm(): + llvm_dir = Path("llvm") + if(llvm_dir.exists() == False): + print("Clone llvm to core/deps/ ..") + for line in os.popen("git clone --branch release/10.x https://github.com/llvm/llvm-project.git llvm"): + print(line) + else: + print("llvm source codes already existed") + return llvm_dir + +""" def detect_VS_version(): + program_dirs = [os.environ['ProgramFiles(x86)'], os.environ['ProgramFiles']] + for dir in program_dirs: + vswhere = Path("{}\\Microsoft Visual Studio\\Installer\\vswhere.exe".format(dir)) + if (vswhere.exists()): + print('"{}" -version 14.0,16.0'.format(vswhere)) + for line in os.popen('"{}" -version 14.0,16.0'.format(vswhere)): + keyvalue = line.split(':', maxsplit=1) + if(keyvalue[0] == "installationPath"): + value = keyvalue[1].strip() + for line in os.popen('"{}\\VC\\Auxiliary\\Build\\vcvars32.bat"'.format(value)): + print(line) + break """ + + +def main(): + current_os = sys.platform + print("current OS is ", current_os) + + current_dir = Path.cwd() + deps_dir = current_dir.joinpath( "../core/deps") + + os.chdir(deps_dir) + llvm_dir = clone_llvm() + os.chdir(llvm_dir) + + if(current_os == "linux"): + build_dir_name = "build" + llvm_file = "bin/llvm-lto" + # generator = '"Unix Makefiles"' + elif(current_os == "win32"): + build_dir_name = "win32build" + llvm_file = "LLVM.sln" + # generator = '"Visual Studio 15 2017"' + else: + build_dir_name = "build" + # generator = '""' + + Path(build_dir_name).mkdir(exist_ok = True) + build_dir = Path(build_dir_name) + os.chdir(build_dir) + + if ( not Path(llvm_file).exists()): + core_number = os.cpu_count() + print("Build llvm with", core_number, " cores") + cmd = 'cmake ../llvm \ + -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ + -DCMAKE_BUILD_TYPE:STRING="Release" \ + -DLLVM_TARGETS_TO_BUILD:STRING="X86;ARM;AArch64;Mips" \ + -DLLVM_INCLUDE_GO_TESTS=OFF \ + -DLLVM_INCLUDE_TOOLS=OFF \ + -DLLVM_INCLUDE_UTILS=OFF \ + -DLLVM_ENABLE_TERMINFO=OFF \ + -DLLVM_BUILD_LLVM_DYLIB:BOOL=OFF \ + -DLLVM_OPTIMIZED_TABLEGEN:BOOL=ON \ + -DLLVM_ENABLE_ZLIB:BOOL=OFF \ + -DLLVM_INCLUDE_DOCS:BOOL=OFF \ + -DLLVM_INCLUDE_EXAMPLES:BOOL=OFF \ + -DLLVM_INCLUDE_TESTS:BOOL=OFF \ + -DLLVM_INCLUDE_BENCHMARKS:BOOL=OFF \ + -DLLVM_APPEND_VC_REV:BOOL=OFF' + print(cmd) + for line in os.popen(cmd): + print(line) + else: + print("llvm has already been Cmaked") + + if(current_os == "linux"): + for line in os.popen("make -j {}".format(core_number)): + print(line) + elif(current_os == "win32"): + print("Please open LLVM.sln in {} to build *Release* version".format(build_dir.absolute())) + + os.chdir(current_dir) + + +if __name__ == "__main__": + main() From 8c820730bac5942114eb36c94f0f956cefafb08d Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Tue, 11 Aug 2020 14:47:24 +0800 Subject: [PATCH 052/207] Add cmake variable to set the max app thread stack size (#346) --- build-scripts/config_common.cmake | 3 +++ core/config.h | 5 +++-- core/shared/platform/common/posix/posix_thread.c | 12 +++++++++++- doc/build_wamr.md | 4 ++++ 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/build-scripts/config_common.cmake b/build-scripts/config_common.cmake index 3b7728f56..f22691dd6 100644 --- a/build-scripts/config_common.cmake +++ b/build-scripts/config_common.cmake @@ -162,4 +162,7 @@ if (WAMR_DISABLE_HW_BOUND_CHECK EQUAL 1) add_definitions (-DWASM_DISABLE_HW_BOUND_CHECK=1) message (" Hardware boundary check disabled") endif () +if (DEFINED WAMR_APP_THREAD_STACK_SIZE_MAX) + add_definitions (-DAPP_THREAD_STACK_SIZE_MAX=${WAMR_APP_THREAD_STACK_SIZE_MAX}) +endif () diff --git a/core/config.h b/core/config.h index ba9a1a2fd..414056b8a 100644 --- a/core/config.h +++ b/core/config.h @@ -216,11 +216,12 @@ enum { #if !defined(BH_PLATFORM_ZEPHYR) && !defined(BH_PLATFORM_ALIOS_THINGS) #define APP_THREAD_STACK_SIZE_DEFAULT (32 * 1024) #define APP_THREAD_STACK_SIZE_MIN (24 * 1024) -#define APP_THREAD_STACK_SIZE_MAX (256 * 1024) #else #define APP_THREAD_STACK_SIZE_DEFAULT (6 * 1024) #define APP_THREAD_STACK_SIZE_MIN (4 * 1024) -#define APP_THREAD_STACK_SIZE_MAX (256 * 1024) +#endif +#if !defined(APP_THREAD_STACK_SIZE_MAX) +#define APP_THREAD_STACK_SIZE_MAX (8 * 1024 * 1024) #endif /* Reserved bytes to the native thread stack boundary, throw native diff --git a/core/shared/platform/common/posix/posix_thread.c b/core/shared/platform/common/posix/posix_thread.c index 58d8fee7e..db9adbf61 100644 --- a/core/shared/platform/common/posix/posix_thread.c +++ b/core/shared/platform/common/posix/posix_thread.c @@ -242,12 +242,19 @@ uint8 *os_thread_get_stack_boundary() uint8 *addr = NULL; size_t stack_size, guard_size; int page_size = getpagesize(); + size_t max_stack_size = (APP_THREAD_STACK_SIZE_MAX + page_size - 1) + & ~(page_size - 1); + + if (max_stack_size < APP_THREAD_STACK_SIZE_DEFAULT) + max_stack_size = APP_THREAD_STACK_SIZE_DEFAULT; #ifdef __linux__ if (pthread_getattr_np(self, &attr) == 0) { pthread_attr_getstack(&attr, (void**)&addr, &stack_size); pthread_attr_getguardsize(&attr, &guard_size); pthread_attr_destroy(&attr); + if (stack_size > max_stack_size) + addr = addr + stack_size - max_stack_size; if (guard_size < (size_t)page_size) /* Reserved 1 guard page at least for safety */ guard_size = (size_t)page_size; @@ -257,7 +264,10 @@ uint8 *os_thread_get_stack_boundary() #elif defined(__APPLE__) if ((addr = (uint8*)pthread_get_stackaddr_np(self))) { stack_size = pthread_get_stacksize_np(self); - addr -= stack_size; + if (stack_size > max_stack_size) + addr -= max_stack_size; + else + addr -= stack_size; /* Reserved 1 guard page at least for safety */ addr += page_size; } diff --git a/doc/build_wamr.md b/doc/build_wamr.md index 378fb57a9..c0b36f29b 100644 --- a/doc/build_wamr.md +++ b/doc/build_wamr.md @@ -68,6 +68,10 @@ cmake -DWAMR_BUILD_PLATFORM=linux -DWAMR_BUILD_TARGET=ARM - **WAMR_DISABLE_HW_BOUND_CHECK**=1/0, default to enable if not set and supported by platform > Note: by default only platform linux/darwin/android/vxworks 64-bit will enable boundary check with hardware trap in AOT or JIT mode, and the wamrc tool will generate AOT code without boundary check instructions in all 64-bit targets except SGX to improve performance. +#### **Set maximum app thread stack size** +- **WAMR_APP_THREAD_STACK_SIZE_MAX**=n, default to 8 MB (8388608) if not set +> Note: the AOT boundary check with hardware trap mechanism might consume large stack since the OS may lazily grow the stack mapping as a guard page is hit, we may use this configuration to reduce the total stack usage, e.g. -DWAMR_APP_THREAD_STACK_SIZE_MAX=131072 (128 KB). + **Combination of configurations:** We can combine the configurations. For example, if we want to disable interpreter, enable AOT and WASI, we can run command: From 21efe12505900c728d0c0005e3b9ced7fbf9495c Mon Sep 17 00:00:00 2001 From: Xu Jun <693788454@qq.com> Date: Thu, 13 Aug 2020 14:41:20 +0800 Subject: [PATCH 053/207] add win64 support (#348) --- core/iwasm/common/arch/invokeNative_em64.asm | 62 ++++++++++++++++++++ core/iwasm/common/iwasm_common.cmake | 6 +- 2 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 core/iwasm/common/arch/invokeNative_em64.asm diff --git a/core/iwasm/common/arch/invokeNative_em64.asm b/core/iwasm/common/arch/invokeNative_em64.asm new file mode 100644 index 000000000..8ce4fc0b9 --- /dev/null +++ b/core/iwasm/common/arch/invokeNative_em64.asm @@ -0,0 +1,62 @@ +; +; Copyright (C) 2019 Intel Corporation. All rights reserved. +; SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +; + +_TEXT SEGMENT + ; rcx func_ptr + ; rdx argv + ; r8 n_stacks + +invokeNative PROC + push rbp + mov rbp, rsp + + mov r10, rcx ; func_ptr + mov rax, rdx ; argv + mov rcx, r8 ; n_stacks + +; fill all fp args + movsd xmm0, qword ptr [rax + 0] + movsd xmm1, qword ptr [rax + 8] + movsd xmm2, qword ptr [rax + 16] + movsd xmm3, qword ptr [rax + 24] + +; check for stack args + cmp rcx, 0 + jz cycle_end + + mov rdx, rsp + and rdx, 15 + jz no_abort + int 3 +no_abort: + mov rdx, rcx + and rdx, 1 + shl rdx, 3 + sub rsp, rdx + +; store stack args + lea r9, qword ptr [rax + rcx * 8 + 64] + sub r9, rsp ; offset +cycle: + push qword ptr [rsp + r9] + loop cycle + +cycle_end: + mov rcx, [rax + 32] + mov rdx, [rax + 40] + mov r8, [rax + 48] + mov r9, [rax + 56] + + sub rsp, 32 ; shadow space + + call r10 + leave + ret + +invokeNative ENDP + +_TEXT ENDS + +END \ No newline at end of file diff --git a/core/iwasm/common/iwasm_common.cmake b/core/iwasm/common/iwasm_common.cmake index 50173c4ff..458b00a3f 100644 --- a/core/iwasm/common/iwasm_common.cmake +++ b/core/iwasm/common/iwasm_common.cmake @@ -11,7 +11,11 @@ add_definitions(-DBH_FREE=wasm_runtime_free) file (GLOB c_source_all ${IWASM_COMMON_DIR}/*.c) if (WAMR_BUILD_TARGET STREQUAL "X86_64" OR WAMR_BUILD_TARGET STREQUAL "AMD_64") - set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_em64.s) + if (WAMR_BUILD_PLATFORM STREQUAL "windows") + set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_em64.asm) + else () + set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_em64.s) + endif () elseif (WAMR_BUILD_TARGET STREQUAL "X86_32") if (WAMR_BUILD_PLATFORM STREQUAL "windows") set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_ia32.asm) From 874cc951c65eb365e0109e99e356fbf30049be79 Mon Sep 17 00:00:00 2001 From: Karl Fessel Date: Thu, 13 Aug 2020 09:13:45 +0200 Subject: [PATCH 054/207] Optimize get_current_target in AOT loader for more archs (#347) --- core/iwasm/aot/arch/aot_reloc_aarch64.c | 32 ++++++++++++++++--------- core/iwasm/aot/arch/aot_reloc_arm.c | 32 ++++++++++++++++--------- 2 files changed, 42 insertions(+), 22 deletions(-) diff --git a/core/iwasm/aot/arch/aot_reloc_aarch64.c b/core/iwasm/aot/arch/aot_reloc_aarch64.c index b2e250657..373ac2d27 100644 --- a/core/iwasm/aot/arch/aot_reloc_aarch64.c +++ b/core/iwasm/aot/arch/aot_reloc_aarch64.c @@ -27,22 +27,32 @@ get_target_symbol_map(uint32 *sym_num) return target_sym_map; } +#define BUILD_TARGET_AARCH64_DEFAULT "aarch64v8" void get_current_target(char *target_buf, uint32 target_buf_size) { - char *build_target = BUILD_TARGET; - char *p = target_buf, *p_end; - snprintf(target_buf, target_buf_size, "%s", build_target); - p_end = p + strlen(target_buf); - while (p < p_end) { - if (*p >= 'A' && *p <= 'Z') - *p++ += 'a' - 'A'; - else - p++; + const char * s = BUILD_TARGET; + size_t s_size = sizeof(BUILD_TARGET); + char *d = target_buf; + + /* Set to "aarch64v8" by default if sub version isn't specified */ + if (strcmp(s, "AARACH64") == 0) { + s = BUILD_TARGET_AARCH64_DEFAULT; + s_size = sizeof(BUILD_TARGET_AARCH64_DEFAULT); } - if (!strcmp(target_buf, "aarch64")) - snprintf(target_buf, target_buf_size, "aarch64v8"); + if(target_buf_size < s_size){ + s_size = target_buf_size; + } + while (--s_size) { + if (*s >= 'A' && *s <= 'Z') + *d++ = *s++ + 'a' - 'A'; + else + *d++ = *s++ ; + } + /* Ensure the string is null byte ('\0') terminated */ + *d = '\0'; } +#undef BUILD_TARGET_AARCH64_DEFAULT static uint32 get_plt_item_size() diff --git a/core/iwasm/aot/arch/aot_reloc_arm.c b/core/iwasm/aot/arch/aot_reloc_arm.c index a61613c2b..e3e2d1a7f 100644 --- a/core/iwasm/aot/arch/aot_reloc_arm.c +++ b/core/iwasm/aot/arch/aot_reloc_arm.c @@ -118,22 +118,32 @@ get_target_symbol_map(uint32 *sym_num) return target_sym_map; } +#define BUILD_TARGET_ARM_DEFAULT "armv4" void get_current_target(char *target_buf, uint32 target_buf_size) { - char *build_target = BUILD_TARGET; - char *p = target_buf, *p_end; - snprintf(target_buf, target_buf_size, "%s", build_target); - p_end = p + strlen(target_buf); - while (p < p_end) { - if (*p >= 'A' && *p <= 'Z') - *p++ += 'a' - 'A'; - else - p++; + const char * s = BUILD_TARGET; + size_t s_size = sizeof(BUILD_TARGET); + char *d = target_buf; + + /* Set to "armv4" by default if sub version isn't specified */ + if (strcmp(s, "ARM") == 0) { + s = BUILD_TARGET_ARM_DEFAULT; + s_size = sizeof(BUILD_TARGET_ARM_DEFAULT); } - if (!strcmp(target_buf, "arm")) - snprintf(target_buf, target_buf_size, "armv4"); + if(target_buf_size < s_size){ + s_size = target_buf_size; + } + while (--s_size) { + if (*s >= 'A' && *s <= 'Z') + *d++ = *s++ + 'a' - 'A'; + else + *d++ = *s++ ; + } + /* Ensure the string is null byte ('\0') terminated */ + *d = '\0'; } +#undef BUILD_TARGET_ARM_DEFAULT uint32 get_plt_item_size() From 1266ebb2227e5fff5aece90a7dcae081766df693 Mon Sep 17 00:00:00 2001 From: Xu Jun <693788454@qq.com> Date: Thu, 13 Aug 2020 16:40:19 +0800 Subject: [PATCH 055/207] fix coding style for windows build patch (#350) --- build-scripts/runtime_lib.cmake | 4 ++-- core/iwasm/common/arch/invokeNative_ia32.asm | 2 +- .../platform/windows/platform_internal.h | 14 ++++++----- core/shared/platform/windows/win_memmap.c | 23 +++++++++++-------- core/shared/platform/windows/win_thread.c | 18 ++++++++------- core/shared/platform/windows/win_time.c | 2 +- core/shared/utils/uncommon/bh_read_file.c | 4 ++-- wamr-compiler/build_llvm.py | 6 ++--- 8 files changed, 40 insertions(+), 33 deletions(-) diff --git a/build-scripts/runtime_lib.cmake b/build-scripts/runtime_lib.cmake index eb5a90a15..a87a2ff63 100644 --- a/build-scripts/runtime_lib.cmake +++ b/build-scripts/runtime_lib.cmake @@ -83,8 +83,8 @@ endif () ####################### Common sources ####################### if (NOT MSVC) -set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99 -ffunction-sections -fdata-sections \ - -Wall -Wno-unused-parameter -Wno-pedantic") + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99 -ffunction-sections -fdata-sections \ + -Wall -Wno-unused-parameter -Wno-pedantic") endif () # include the build config template file diff --git a/core/iwasm/common/arch/invokeNative_ia32.asm b/core/iwasm/common/arch/invokeNative_ia32.asm index 8bd28722c..c52c8d6ed 100644 --- a/core/iwasm/common/arch/invokeNative_ia32.asm +++ b/core/iwasm/common/arch/invokeNative_ia32.asm @@ -6,7 +6,7 @@ .386 .model flat .code -_invokeNative PROC +_invokeNative PROC push ebp mov ebp,esp mov ecx, [ebp+16] ; ecx = argc */ diff --git a/core/shared/platform/windows/platform_internal.h b/core/shared/platform/windows/platform_internal.h index 8803e8029..65a933ac3 100644 --- a/core/shared/platform/windows/platform_internal.h +++ b/core/shared/platform/windows/platform_internal.h @@ -45,17 +45,19 @@ typedef void *korp_sem; typedef void *korp_thread; typedef struct { - korp_sem s; - unsigned int waiting_count; + korp_sem s; + unsigned int waiting_count; } korp_cond; #define os_printf printf #define os_vprintf vprintf -static inline size_t getpagesize() { - SYSTEM_INFO S; - GetNativeSystemInfo(&S); - return S.dwPageSize; +static inline size_t +getpagesize() +{ + SYSTEM_INFO S; + GetNativeSystemInfo(&S); + return S.dwPageSize; } #ifdef __cplusplus diff --git a/core/shared/platform/windows/win_memmap.c b/core/shared/platform/windows/win_memmap.c index e5d478b16..6bcf6b3e0 100644 --- a/core/shared/platform/windows/win_memmap.c +++ b/core/shared/platform/windows/win_memmap.c @@ -4,6 +4,7 @@ */ #include "platform_api_vmcore.h" + void * os_mmap(void *hint, size_t size, int prot, int flags) { DWORD AllocType = MEM_RESERVE | MEM_COMMIT; @@ -17,14 +18,14 @@ void * os_mmap(void *hint, size_t size, int prot, int flags) if (request_size < size) /* integer overflow */ return NULL; - + if (prot & MMAP_PROT_EXEC) { if (prot & MMAP_PROT_WRITE) flProtect = PAGE_EXECUTE_READWRITE; - else + else flProtect = PAGE_EXECUTE_READ; - } - else if (prot & MMAP_PROT_WRITE) + } + else if (prot & MMAP_PROT_WRITE) flProtect = PAGE_READWRITE; else if (prot & MMAP_PROT_READ) flProtect = PAGE_READONLY; @@ -40,12 +41,12 @@ os_munmap(void *addr, size_t size) { size_t page_size = getpagesize(); size_t request_size = (size + page_size - 1) & ~(page_size - 1); + if (addr) { - if (VirtualFree(addr, 0, MEM_RELEASE) == 0) { if (VirtualFree(addr, size, MEM_DECOMMIT) == 0) { os_printf("os_munmap error addr:%p, size:0x%lx, errno:%d\n", - addr, request_size, errno); + addr, request_size, errno); } } } @@ -56,16 +57,17 @@ os_mprotect(void *addr, size_t size, int prot) { DWORD AllocType = MEM_RESERVE | MEM_COMMIT; DWORD flProtect = PAGE_NOACCESS; + if (!addr) return 0; - + if (prot & MMAP_PROT_EXEC) { if (prot & MMAP_PROT_WRITE) flProtect = PAGE_EXECUTE_READWRITE; - else + else flProtect = PAGE_EXECUTE_READ; - } - else if (prot & MMAP_PROT_WRITE) + } + else if (prot & MMAP_PROT_WRITE) flProtect = PAGE_READWRITE; else if (prot & MMAP_PROT_READ) flProtect = PAGE_READONLY; @@ -76,4 +78,5 @@ os_mprotect(void *addr, size_t size, int prot) void os_dcache_flush(void) { + } diff --git a/core/shared/platform/windows/win_thread.c b/core/shared/platform/windows/win_thread.c index d4b9e64a8..896137ef7 100644 --- a/core/shared/platform/windows/win_thread.c +++ b/core/shared/platform/windows/win_thread.c @@ -97,22 +97,24 @@ int os_cond_wait(korp_cond *cond, korp_mutex *mutex) int gettimeofday(struct timeval * tp, struct timezone * tzp) { - // Note: some broken versions only have 8 trailing zero's, the correct epoch has 9 trailing zero's - // This magic number is the number of 100 nanosecond intervals since January 1, 1601 (UTC) - // until 00:00:00 January 1, 1970 + /* Note: some broken versions only have 8 trailing zero's, + the correct epoch has 9 trailing zero's + This magic number is the number of 100 nanosecond intervals + since January 1, 1601 (UTC) until 00:00:00 January 1, 1970 */ static const uint64_t EPOCH = ((uint64_t) 116444736000000000ULL); SYSTEMTIME system_time; FILETIME file_time; uint64_t time; - GetSystemTime( &system_time ); - SystemTimeToFileTime( &system_time, &file_time ); - time = ((uint64_t)file_time.dwLowDateTime ) ; + GetSystemTime(&system_time); + SystemTimeToFileTime(&system_time, &file_time); + time = ((uint64_t)file_time.dwLowDateTime); time += ((uint64_t)file_time.dwHighDateTime) << 32; - tp->tv_sec = (long) ((time - EPOCH) / 10000000L); - tp->tv_usec = (long) (system_time.wMilliseconds * 1000); + tp->tv_sec = (long)((time - EPOCH) / 10000000L); + tp->tv_usec = (long)(system_time.wMilliseconds * 1000); + return 0; } diff --git a/core/shared/platform/windows/win_time.c b/core/shared/platform/windows/win_time.c index 3028a2efb..a48e4191d 100644 --- a/core/shared/platform/windows/win_time.c +++ b/core/shared/platform/windows/win_time.c @@ -11,6 +11,6 @@ os_time_get_boot_microsecond() struct timespec ts; timespec_get(&ts, TIME_UTC); - return ((uint64) ts.tv_sec) * 1000 * 1000 + ((uint64)ts.tv_nsec) / 1000; + return ((uint64)ts.tv_sec) * 1000 * 1000 + ((uint64)ts.tv_nsec) / 1000; } diff --git a/core/shared/utils/uncommon/bh_read_file.c b/core/shared/utils/uncommon/bh_read_file.c index 08165c535..e13b388d6 100644 --- a/core/shared/utils/uncommon/bh_read_file.c +++ b/core/shared/utils/uncommon/bh_read_file.c @@ -24,13 +24,13 @@ bh_read_file_to_buffer(const char *filename, uint32 *ret_size) if (_sopen_s(&file, filename, _O_RDONLY| _O_BINARY, _SH_DENYNO, 0)) { printf("Read file to buffer failed: open file %s failed.\n", - filename); + filename); return NULL; } if (fstat(file, &stat_buf) != 0) { printf("Read file to buffer failed: fstat file %s failed.\n", - filename); + filename); _close(file); return NULL; } diff --git a/wamr-compiler/build_llvm.py b/wamr-compiler/build_llvm.py index ba965a350..d9912af2f 100644 --- a/wamr-compiler/build_llvm.py +++ b/wamr-compiler/build_llvm.py @@ -59,7 +59,7 @@ def main(): Path(build_dir_name).mkdir(exist_ok = True) build_dir = Path(build_dir_name) os.chdir(build_dir) - + if ( not Path(llvm_file).exists()): core_number = os.cpu_count() print("Build llvm with", core_number, " cores") @@ -81,10 +81,10 @@ def main(): -DLLVM_APPEND_VC_REV:BOOL=OFF' print(cmd) for line in os.popen(cmd): - print(line) + print(line) else: print("llvm has already been Cmaked") - + if(current_os == "linux"): for line in os.popen("make -j {}".format(core_number)): print(line) From 6b5f376e79bbb6c146ee4342a2bfbcf27b700fec Mon Sep 17 00:00:00 2001 From: Xu Jun <693788454@qq.com> Date: Fri, 14 Aug 2020 19:58:19 +0800 Subject: [PATCH 056/207] fix issue in mini-loader (#353) --- core/iwasm/interpreter/wasm_mini_loader.c | 75 ++++++++++++++++------- 1 file changed, 54 insertions(+), 21 deletions(-) diff --git a/core/iwasm/interpreter/wasm_mini_loader.c b/core/iwasm/interpreter/wasm_mini_loader.c index ded22b7ca..483ee126a 100644 --- a/core/iwasm/interpreter/wasm_mini_loader.c +++ b/core/iwasm/interpreter/wasm_mini_loader.c @@ -3116,6 +3116,9 @@ wasm_loader_emit_br_info(WASMLoaderContext *ctx, BranchBlock *frame_csp, * d) each arity value's src frame offset * e) each arity values's dst dynamic offset * f) branch target address + * + * Note: b-e are omitted when arity is 0 so that + * interpreter can recover the br info quickly. */ BlockType *block_type = &frame_csp->block_type; uint8 *types = NULL, cell; @@ -3134,27 +3137,30 @@ wasm_loader_emit_br_info(WASMLoaderContext *ctx, BranchBlock *frame_csp, /* Part a */ emit_uint32(ctx, arity); - /* Part b */ - emit_uint32(ctx, wasm_get_cell_num(types, arity)); - /* Part c */ - for (i = (int32)arity - 1; i >= 0; i--) { - cell = wasm_value_type_cell_num(types[i]); - emit_byte(ctx, cell); - } - /* Part d */ - for (i = (int32)arity - 1; i >= 0; i--) { - cell = wasm_value_type_cell_num(types[i]); - frame_offset -= cell; - emit_operand(ctx, *(int16*)(frame_offset)); - } - /* Part e */ - dynamic_offset = frame_csp->dynamic_offset - + wasm_get_cell_num(types, arity); - for (i = (int32)arity - 1; i >= 0; i--) { - cell = wasm_value_type_cell_num(types[i]); - dynamic_offset -= cell; - emit_operand(ctx, dynamic_offset); + if (arity) { + /* Part b */ + emit_uint32(ctx, wasm_get_cell_num(types, arity)); + + /* Part c */ + for (i = (int32)arity - 1; i >= 0; i--) { + cell = wasm_value_type_cell_num(types[i]); + emit_byte(ctx, cell); + } + /* Part d */ + for (i = (int32)arity - 1; i >= 0; i--) { + cell = wasm_value_type_cell_num(types[i]); + frame_offset -= cell; + emit_operand(ctx, *(int16*)(frame_offset)); + } + /* Part e */ + dynamic_offset = frame_csp->dynamic_offset + + wasm_get_cell_num(types, arity); + for (i = (int32)arity - 1; i >= 0; i--) { + cell = wasm_value_type_cell_num(types[i]); + dynamic_offset -= cell; + emit_operand(ctx, dynamic_offset); + } } /* Part f */ @@ -3578,6 +3584,33 @@ reserve_block_ret(WASMLoaderContext *loader_ctx, return_count = block_type_get_result_types(block_type, &return_types); + /* If there is only one return value, use EXT_OP_COPY_STACK_TOP/_I64 instead + * of EXT_OP_COPY_STACK_VALUES for interpreter performance. */ + if (return_count == 1) { + uint8 cell = wasm_value_type_cell_num(return_types[0]); + if (block->dynamic_offset != *(loader_ctx->frame_offset - cell)) { + /* insert op_copy before else opcode */ + if (opcode == WASM_OP_ELSE) + skip_label(); + emit_label(cell == 1 ? EXT_OP_COPY_STACK_TOP : EXT_OP_COPY_STACK_TOP_I64); + emit_operand(loader_ctx, *(loader_ctx->frame_offset - cell)); + emit_operand(loader_ctx, block->dynamic_offset); + + if (opcode == WASM_OP_ELSE) { + *(loader_ctx->frame_offset - cell) = block->dynamic_offset; + } + else { + loader_ctx->frame_offset -= cell; + loader_ctx->dynamic_offset = block->dynamic_offset; + PUSH_OFFSET_TYPE(return_types[0]); + wasm_loader_emit_backspace(loader_ctx, sizeof(int16)); + } + if (opcode == WASM_OP_ELSE) + emit_label(opcode); + } + return true; + } + /* Copy stack top values to block's results which are in dynamic space. * The instruction format: * Part a: values count @@ -5498,7 +5531,7 @@ handle_op_block_and_loop: goto fail; } func_const_end = func->consts + func->const_cell_num * 4; - // reverse the const buf + /* reverse the const buf */ for (int i = loader_ctx->num_const - 1; i >= 0; i--) { Const *c = (Const*)(loader_ctx->const_buf + i * sizeof(Const)); if (c->value_type == VALUE_TYPE_F64 From 89d2937cde4f73191c1c374fdd14e8d49004394a Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Thu, 20 Aug 2020 12:43:12 +0800 Subject: [PATCH 057/207] 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 --- core/app-mgr/app-manager/module_wasm_app.c | 35 +- core/iwasm/aot/aot_loader.c | 67 ++- core/iwasm/aot/aot_runtime.c | 478 ++++++++++++------ core/iwasm/aot/aot_runtime.h | 49 +- core/iwasm/compilation/aot.c | 20 +- core/iwasm/compilation/aot.h | 17 +- core/iwasm/compilation/aot_compiler.c | 7 +- core/iwasm/compilation/aot_emit_aot_file.c | 16 +- core/iwasm/compilation/aot_emit_memory.c | 74 ++- core/iwasm/compilation/aot_llvm.c | 49 +- core/iwasm/compilation/aot_llvm.h | 2 +- core/iwasm/interpreter/wasm.h | 33 +- core/iwasm/interpreter/wasm_interp_classic.c | 70 +-- core/iwasm/interpreter/wasm_interp_fast.c | 23 +- core/iwasm/interpreter/wasm_loader.c | 319 ++++++++---- core/iwasm/interpreter/wasm_mini_loader.c | 241 ++++++--- core/iwasm/interpreter/wasm_runtime.c | 357 ++++++++----- core/iwasm/interpreter/wasm_runtime.h | 24 +- .../platform/common/posix/posix_memmap.c | 2 +- core/shared/platform/darwin/platform_init.c | 19 + .../platform/darwin/platform_internal.h | 3 - core/shared/platform/linux-sgx/sgx_platform.c | 4 +- core/shared/platform/linux/platform_init.c | 19 + .../shared/platform/linux/platform_internal.h | 3 - core/shared/platform/vxworks/platform_init.c | 19 + .../platform/vxworks/platform_internal.h | 3 - core/shared/utils/bh_log.h | 2 +- samples/wasm-c-api/src/callback.c | 4 + 28 files changed, 1311 insertions(+), 648 deletions(-) diff --git a/core/app-mgr/app-manager/module_wasm_app.c b/core/app-mgr/app-manager/module_wasm_app.c index 4d30c4a08..a84e760df 100644 --- a/core/app-mgr/app-manager/module_wasm_app.c +++ b/core/app-mgr/app-manager/module_wasm_app.c @@ -13,13 +13,14 @@ #include "event.h" #include "watchdog.h" #include "runtime_lib.h" +#include "wasm.h" #if WASM_ENABLE_AOT != 0 #include "aot_export.h" #endif #if WASM_ENABLE_INTERP != 0 || WASM_ENABLE_JIT != 0 /* Wasm bytecode file 4 version bytes */ -static uint8 wasm_bytecode_version[] = { +static uint8 wasm_bytecode_version[4] = { (uint8) 0x01, (uint8) 0x00, (uint8) 0x00, @@ -29,12 +30,13 @@ static uint8 wasm_bytecode_version[] = { #if WASM_ENABLE_AOT != 0 /* Wasm aot file 4 version bytes */ -static uint8 wasm_aot_version[] = { - (uint8) 0x01, +static uint8 wasm_aot_version[4] = { + (uint8) 0x02, (uint8) 0x00, (uint8) 0x00, (uint8) 0x00 }; +#endif static union { int a; @@ -42,8 +44,6 @@ static union { } __ue = { .a = 1 }; #define is_little_endian() (__ue.b == 1) -#endif - /* Wasm App Install Request Receiving Phase */ typedef enum wasm_app_install_req_recv_phase_t { Phase_Req_Ver, @@ -163,14 +163,6 @@ module_interface wasm_app_module_interface = { wasm_app_module_on_install_request_byte_arrive }; -static unsigned -align_uint(unsigned v, unsigned b) -{ - unsigned m = b - 1; - return (v + m) & ~m; -} - -#if WASM_ENABLE_AOT != 0 static void exchange_uint32(uint8 *p_data) { @@ -182,7 +174,6 @@ exchange_uint32(uint8 *p_data) *(p_data + 1) = *(p_data + 2); *(p_data + 2) = value; } -#endif static wasm_function_inst_t app_manager_lookup_function(const wasm_module_inst_t module_inst, @@ -546,7 +537,21 @@ cleanup_app_resource(module_data *m_data) static bool wasm_app_module_init(void) { - /* wasm runtime is already initialized by main func */ + uint32 version; + +#if WASM_ENABLE_INTERP != 0 || WASM_ENABLE_JIT != 0 + version = WASM_CURRENT_VERSION; + if (!is_little_endian()) + exchange_uint32((uint8 *)&version); + bh_memcpy_s(wasm_bytecode_version, 4, &version, 4); +#endif + +#if WASM_ENABLE_AOT != 0 + version = AOT_CURRENT_VERSION; + if (!is_little_endian()) + exchange_uint32((uint8 *)&version); + bh_memcpy_s(wasm_aot_version, 4, &version, 4); +#endif return true; } diff --git a/core/iwasm/aot/aot_loader.c b/core/iwasm/aot/aot_loader.c index f5bd2bb7f..312f8c3db 100644 --- a/core/iwasm/aot/aot_loader.c +++ b/core/iwasm/aot/aot_loader.c @@ -1039,10 +1039,13 @@ load_init_data_section(const uint8 *buf, const uint8 *buf_end, return false; } - read_uint32(p, p_end, module->llvm_aux_data_end); - read_uint32(p, p_end, module->llvm_aux_stack_bottom); - read_uint32(p, p_end, module->llvm_aux_stack_size); - read_uint32(p, p_end, module->llvm_aux_stack_global_index); + read_uint32(p, p_end, module->aux_data_end_global_index); + read_uint32(p, p_end, module->aux_data_end); + read_uint32(p, p_end, module->aux_heap_base_global_index); + read_uint32(p, p_end, module->aux_heap_base); + read_uint32(p, p_end, module->aux_stack_top_global_index); + read_uint32(p, p_end, module->aux_stack_bottom); + read_uint32(p, p_end, module->aux_stack_size); if (!load_object_data_sections_info(&p, p_end, module, error_buf, error_buf_size)) @@ -1613,6 +1616,9 @@ load_from_sections(AOTModule *module, AOTSection *sections, AOTSection *section = sections; const uint8 *buf, *buf_end; uint32 last_section_type = (uint32)-1, section_type; + uint32 i, func_index, func_type_index; + AOTFuncType *func_type; + AOTExport *exports; while (section) { buf = section->section_body; @@ -1670,6 +1676,42 @@ load_from_sections(AOTModule *module, AOTSection *sections, return false; } + /* Resolve malloc and free function */ + module->malloc_func_index = (uint32)-1; + module->free_func_index = (uint32)-1; + + exports = module->exports; + for (i = 0; i < module->export_count; i++) { + if (exports[i].kind == EXPORT_KIND_FUNC + && exports[i].index >= module->import_func_count) { + if (!strcmp(exports[i].name, "malloc")) { + func_index = exports[i].index - module->import_func_count; + func_type_index = module->func_type_indexes[func_index]; + func_type = module->func_types[func_type_index]; + if (func_type->param_count == 1 + && func_type->result_count == 1 + && func_type->types[0] == VALUE_TYPE_I32 + && func_type->types[1] == VALUE_TYPE_I32) { + module->malloc_func_index = func_index; + LOG_VERBOSE("Found malloc function, index: %u", + exports[i].index); + } + } + else if (!strcmp(exports[i].name, "free")) { + func_index = exports[i].index - module->import_func_count; + func_type_index = module->func_type_indexes[func_index]; + func_type = module->func_types[func_type_index]; + if (func_type->param_count == 1 + && func_type->result_count == 0 + && func_type->types[0] == VALUE_TYPE_I32) { + module->free_func_index = func_index; + LOG_VERBOSE("Found free function, index: %u", + exports[i].index); + } + } + } + } + /* Flush data cache before executing AOT code, * otherwise unpredictable behavior can occur. */ os_dcache_flush(); @@ -2018,14 +2060,17 @@ aot_load_from_comp_data(AOTCompData *comp_data, AOTCompContext *comp_ctx, - module->import_func_count]; } } - else { - module->start_function = NULL; - } - module->llvm_aux_data_end = comp_data->llvm_aux_data_end; - module->llvm_aux_stack_bottom = comp_data->llvm_aux_stack_bottom; - module->llvm_aux_stack_size = comp_data->llvm_aux_stack_size; - module->llvm_aux_stack_global_index = comp_data->llvm_aux_stack_global_index; + module->malloc_func_index = comp_data->malloc_func_index; + module->free_func_index = comp_data->free_func_index; + + module->aux_data_end_global_index = comp_data->aux_data_end_global_index; + module->aux_data_end = comp_data->aux_data_end; + module->aux_heap_base_global_index = comp_data->aux_heap_base_global_index; + module->aux_heap_base = comp_data->aux_heap_base; + module->aux_stack_top_global_index = comp_data->aux_stack_top_global_index; + module->aux_stack_bottom = comp_data->aux_stack_bottom; + module->aux_stack_size = comp_data->aux_stack_size; module->code = NULL; module->code_size = 0; diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index 107b5f936..79235d61f 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -176,9 +176,9 @@ memories_deinstantiate(AOTModuleInstance *module_inst) if (memory_inst->heap_data.ptr) { #ifndef OS_ENABLE_HW_BOUND_CHECK - wasm_runtime_free(memory_inst->heap_data.ptr); + wasm_runtime_free(memory_inst->memory_data.ptr); #else - os_munmap((uint8*)memory_inst->memory_data.ptr - 2 * (uint64)BH_GB, + os_munmap((uint8*)memory_inst->memory_data.ptr, 8 * (uint64)BH_GB); #endif } @@ -193,19 +193,26 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModule *module, uint32 heap_size, char *error_buf, uint32 error_buf_size) { void *heap_handle; - uint64 memory_data_size = (uint64)memory->num_bytes_per_page - * memory->mem_init_page_count; - uint64 total_size = heap_size + memory_data_size; - uint8 *p; + uint32 num_bytes_per_page = memory->num_bytes_per_page; + uint32 init_page_count = memory->mem_init_page_count; + uint32 max_page_count = memory->mem_max_page_count; + uint32 inc_page_count, aux_heap_base, global_idx; + uint32 bytes_of_last_page, bytes_to_page_end; + uint32 heap_offset = num_bytes_per_page *init_page_count; + uint64 total_size; + uint8 *p, *global_addr; +#ifdef OS_ENABLE_HW_BOUND_CHECK + uint8 *mapped_mem; + uint64 map_size = 8 * (uint64)BH_GB; + uint64 page_size = os_getpagesize(); +#endif #if WASM_ENABLE_SHARED_MEMORY != 0 - AOTMemoryInstance *shared_memory_instance; bool is_shared_memory = memory->memory_flags & 0x02 ? true : false; - uint64 max_memory_data_size = (uint64)memory->num_bytes_per_page - * memory->mem_max_page_count; /* Shared memory */ if (is_shared_memory) { + AOTMemoryInstance *shared_memory_instance; WASMSharedMemNode *node = wasm_module_get_shared_memory((WASMModuleCommon *)module); /* If the memory of this module has been instantiated, @@ -219,16 +226,94 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModule *module, (AOTMemoryInstance *)shared_memory_get_memory_inst(node); bh_assert(shared_memory_instance); - /* Set the shared memory flag, so the runtime will get the - actual memory inst through module_inst->memories array */ - memory_inst->is_shared = true; (void)ref_count; return shared_memory_instance; } -#ifndef OS_ENABLE_HW_BOUND_CHECK - /* Allocate max page for shared memory */ - total_size = heap_size + max_memory_data_size; + } #endif + + if (heap_size > 0 + && module->malloc_func_index != (uint32)-1 + && module->free_func_index != (uint32)-1) { + /* Disable app heap, use malloc/free function exported + by wasm app to allocate/free memory instead */ + heap_size = 0; + } + + if (init_page_count == max_page_count && init_page_count == 1) { + /* If only one page and at most one page, we just append + the app heap to the end of linear memory, enlarge the + num_bytes_per_page, and don't change the page count*/ + heap_offset = num_bytes_per_page; + num_bytes_per_page += heap_size; + if (num_bytes_per_page < heap_size) { + set_error_buf(error_buf, error_buf_size, + "memory size must be at most 65536 pages (4GiB)"); + return NULL; + } + } + else if (heap_size > 0) { + if (module->aux_heap_base_global_index != (uint32)-1 + && module->aux_heap_base < num_bytes_per_page + * init_page_count) { + /* Insert app heap before __heap_base */ + aux_heap_base = module->aux_heap_base; + bytes_of_last_page = aux_heap_base % num_bytes_per_page; + if (bytes_of_last_page == 0) + bytes_of_last_page = num_bytes_per_page; + bytes_to_page_end = num_bytes_per_page - bytes_of_last_page; + inc_page_count = (heap_size - bytes_to_page_end + + num_bytes_per_page - 1) / num_bytes_per_page; + heap_offset = aux_heap_base; + aux_heap_base += heap_size; + + bytes_of_last_page = aux_heap_base % num_bytes_per_page; + if (bytes_of_last_page == 0) + bytes_of_last_page = num_bytes_per_page; + bytes_to_page_end = num_bytes_per_page - bytes_of_last_page; + if (bytes_to_page_end < 1 * BH_KB) { + aux_heap_base += 1 * BH_KB; + inc_page_count++; + } + + /* Adjust __heap_base global value */ + global_idx = module->aux_heap_base_global_index + - module->import_global_count; + global_addr = (uint8*)module_inst->global_data.ptr + + module->globals[global_idx].data_offset; + *(uint32 *)global_addr = aux_heap_base; + LOG_VERBOSE("Reset __heap_base global to %u", aux_heap_base); + } + else { + /* Insert app heap before new page */ + inc_page_count = (heap_size + num_bytes_per_page - 1) + / num_bytes_per_page; + heap_offset = num_bytes_per_page * init_page_count; + heap_size = num_bytes_per_page * inc_page_count; + if (heap_size > 0) + heap_size -= 1 * BH_KB; + } + init_page_count += inc_page_count; + max_page_count += inc_page_count; + if (init_page_count > 65536) { + set_error_buf(error_buf, error_buf_size, + "memory size must be at most 65536 pages (4GiB)"); + return NULL; + } + if (max_page_count > 65536) + max_page_count = 65536; + } + + LOG_VERBOSE("Memory instantiate:"); + LOG_VERBOSE(" page bytes: %u, init pages: %u, max pages: %u", + num_bytes_per_page, init_page_count, max_page_count); + LOG_VERBOSE(" heap offset: %u, heap size: %d\n", heap_offset, heap_size); + + total_size = (uint64)num_bytes_per_page * init_page_count; +#if WASM_ENABLE_SHARED_MEMORY != 0 + if (is_shared_memory) { + /* Allocate max page for shared memory */ + total_size = (uint64)num_bytes_per_page * max_page_count; } #endif @@ -238,24 +323,21 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModule *module, return NULL; } #else - uint8 *mapped_mem; - uint64 map_size = 8 * (uint64)BH_GB; + total_size = (total_size + page_size - 1) & ~(page_size - 1); - /* Totally 8G is mapped, the opcode load/store address range is -2G to 6G: - * ea = i + memarg.offset - * i is i32, the range is -2G to 2G - * memarg.offset is u32, the range is 0 to 4G - * so the range of ea is -2G to 6G + /* Totally 8G is mapped, the opcode load/store address range is 0 to 8G: + * ea = i + memarg.offset + * both i and memarg.offset are u32 in range 0 to 4G + * so the range of ea is 0 to 8G */ if (total_size >= UINT32_MAX - || !(mapped_mem = os_mmap(NULL, map_size, - MMAP_PROT_NONE, MMAP_MAP_NONE))) { + || !(p = mapped_mem = os_mmap(NULL, map_size, + MMAP_PROT_NONE, MMAP_MAP_NONE))) { set_error_buf(error_buf, error_buf_size, "AOT module instantiate failed: mmap memory failed."); return NULL; } - p = mapped_mem + 2 * (uint64)BH_GB - heap_size; if (os_mprotect(p, total_size, MMAP_PROT_READ | MMAP_PROT_WRITE) != 0) { set_error_buf(error_buf, error_buf_size, "AOT module instantiate failed: mprotec memory failed."); @@ -263,15 +345,21 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModule *module, return NULL; } memset(p, 0, (uint32)total_size); -#endif +#endif /* end of OS_ENABLE_HW_BOUND_CHECK */ memory_inst->module_type = Wasm_Module_AoT; + memory_inst->num_bytes_per_page = num_bytes_per_page; + memory_inst->cur_page_count = init_page_count; + memory_inst->max_page_count = max_page_count; + + /* Init memory info */ + memory_inst->memory_data.ptr = p; + memory_inst->memory_data_end.ptr = p + (uint32)total_size; + memory_inst->memory_data_size = (uint32)total_size; + /* Initialize heap info */ - memory_inst->heap_data.ptr = p; - p += heap_size; - memory_inst->heap_data_end.ptr = p; - memory_inst->heap_data_size = heap_size; - memory_inst->heap_base_offset = -(int32)heap_size; + memory_inst->heap_data.ptr = p + heap_offset; + memory_inst->heap_data_end.ptr = p + heap_offset + heap_size; if (heap_size > 0) { if (!(heap_handle = mem_allocator_create(memory_inst->heap_data.ptr, heap_size))) { @@ -283,31 +371,20 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModule *module, memory_inst->heap_handle.ptr = heap_handle; } - /* Init memory info */ - memory_inst->memory_data.ptr = p; -#if WASM_ENABLE_SHARED_MEMORY != 0 - if (is_shared_memory) { - p += (uint32)max_memory_data_size; + if (total_size > 0) { + if (sizeof(uintptr_t) == sizeof(uint64)) { + memory_inst->mem_bound_check_1byte.u64 = total_size - 1; + memory_inst->mem_bound_check_2bytes.u64 = total_size - 2; + memory_inst->mem_bound_check_4bytes.u64 = total_size - 4; + memory_inst->mem_bound_check_8bytes.u64 = total_size - 8; + } + else { + memory_inst->mem_bound_check_1byte.u32[0] = (uint32)total_size - 1; + memory_inst->mem_bound_check_2bytes.u32[0] = (uint32)total_size - 2; + memory_inst->mem_bound_check_4bytes.u32[0] = (uint32)total_size - 4; + memory_inst->mem_bound_check_8bytes.u32[0] = (uint32)total_size - 8; + } } - else -#endif - { - p += (uint32)memory_data_size; - } - memory_inst->memory_data_end.ptr = p; - memory_inst->memory_data_size = (uint32)memory_data_size; - memory_inst->mem_cur_page_count = memory->mem_init_page_count; - memory_inst->mem_max_page_count = memory->mem_max_page_count; - - memory_inst->mem_bound_check_heap_base = memory_inst->heap_base_offset; - memory_inst->mem_bound_check_1byte = - (int64)memory_inst->memory_data_size - 1; - memory_inst->mem_bound_check_2bytes = - (int64)memory_inst->memory_data_size - 2; - memory_inst->mem_bound_check_4bytes = - (int64)memory_inst->memory_data_size - 4; - memory_inst->mem_bound_check_8bytes = - (int64)memory_inst->memory_data_size - 8; #if WASM_ENABLE_SHARED_MEMORY != 0 if (is_shared_memory) { @@ -333,11 +410,11 @@ fail2: #endif fail1: #ifndef OS_ENABLE_HW_BOUND_CHECK - wasm_runtime_free(memory_inst->heap_data.ptr); + wasm_runtime_free(memory_inst->memory_data.ptr); #else os_munmap(mapped_mem, map_size); #endif - memory_inst->heap_data.ptr = NULL; + memory_inst->memory_data.ptr = NULL; return NULL; } @@ -632,9 +709,6 @@ aot_instantiate(AOTModule *module, bool is_sub_inst, heap_size = align_uint(heap_size, 8); if (heap_size > APP_HEAP_SIZE_MAX) heap_size = APP_HEAP_SIZE_MAX; -#ifdef OS_ENABLE_HW_BOUND_CHECK - heap_size = align_uint(heap_size, os_getpagesize()); -#endif /* Allocate module instance, global data, table data and heap data */ if (!(module_inst = runtime_malloc(total_size, @@ -829,10 +903,9 @@ aot_signal_handler(void *sig_addr) /* Get the default memory instance */ memory_inst = aot_get_default_memory(module_inst); if (memory_inst) { - mapped_mem_start_addr = (uint8*)memory_inst->memory_data.ptr - - 2 * (uint64)BH_GB; + mapped_mem_start_addr = (uint8*)memory_inst->memory_data.ptr; mapped_mem_end_addr = (uint8*)memory_inst->memory_data.ptr - + 6 * (uint64)BH_GB; + + 8 * (uint64)BH_GB; } /* Get stack info of current thread */ @@ -1147,12 +1220,82 @@ aot_clear_exception(AOTModuleInstance *module_inst) module_inst->cur_exception[0] = '\0'; } +static bool +execute_malloc_function(AOTModuleInstance *module_inst, + AOTFunctionInstance *malloc_func, + uint32 size, uint32 *p_result) +{ + uint32 argv[2]; + bool ret; + + argv[0] = size; +#ifdef OS_ENABLE_HW_BOUND_CHECK + if (aot_exec_env != NULL) { + bh_assert(aot_exec_env->module_inst + == (WASMModuleInstanceCommon *)module_inst); + ret = aot_call_function(aot_exec_env, malloc_func, 1, argv); + } + else +#endif + { + ret = aot_create_exec_env_and_call_function + (module_inst, malloc_func, 1, argv); + } + + if (ret) + *p_result = argv[0]; + return ret; +} + +static bool +execute_free_function(AOTModuleInstance *module_inst, + AOTFunctionInstance *free_func, + uint32 offset) +{ + uint32 argv[2]; + + argv[0] = offset; +#ifdef OS_ENABLE_HW_BOUND_CHECK + if (aot_exec_env != NULL) { + bh_assert(aot_exec_env->module_inst + == (WASMModuleInstanceCommon *)module_inst); + return aot_call_function(aot_exec_env, free_func, 1, argv); + } + else +#endif + { + return aot_create_exec_env_and_call_function + (module_inst, free_func, 1, argv); + } +} + int32 aot_module_malloc(AOTModuleInstance *module_inst, uint32 size, void **p_native_addr) { AOTMemoryInstance *memory_inst = aot_get_default_memory(module_inst); - uint8 *addr = mem_allocator_malloc(memory_inst->heap_handle.ptr, size); + AOTModule *module = (AOTModule *)module_inst->aot_module.ptr; + uint8 *addr = NULL; + uint32 offset = 0; + + if (memory_inst->heap_handle.ptr) { + addr = mem_allocator_malloc(memory_inst->heap_handle.ptr, size); + } + else if (module->malloc_func_index != (uint32)-1 + && module->free_func_index != (uint32)-1) { + AOTFunctionInstance *malloc_func = + aot_lookup_function(module_inst, "malloc", "(i)i"); + + bh_assert(malloc_func); + if (!execute_malloc_function(module_inst, malloc_func, + size, &offset)) { + return 0; + } + addr = offset + ? (uint8*)memory_inst->memory_data.ptr + offset + : NULL; + } + if (!addr) { aot_set_exception(module_inst, "out of memory"); return 0; @@ -1166,11 +1309,25 @@ void aot_module_free(AOTModuleInstance *module_inst, int32 ptr) { AOTMemoryInstance *memory_inst = aot_get_default_memory(module_inst); + AOTModule *module = (AOTModule *)module_inst->aot_module.ptr; + if (ptr) { - uint8 *addr = (uint8*)memory_inst->memory_data.ptr + ptr; - if ((uint8*)memory_inst->heap_data.ptr < addr - && addr < (uint8*)memory_inst->memory_data.ptr) + uint8 *addr = (uint8 *)memory_inst->memory_data.ptr + ptr; + if (memory_inst->heap_handle.ptr + &&(uint8 *)memory_inst->heap_data.ptr < addr + && addr < (uint8 *)memory_inst->heap_data_end.ptr) { mem_allocator_free(memory_inst->heap_handle.ptr, addr); + } + else if (module->malloc_func_index != (uint32)-1 + && module->free_func_index != (uint32)-1 + && (uint8 *)memory_inst->memory_data.ptr <= addr + && addr < (uint8 *)memory_inst->memory_data_end.ptr) { + AOTFunctionInstance *free_func = + aot_lookup_function(module_inst, "free", "(i)i"); + + bh_assert(free_func); + execute_free_function(module_inst, free_func, (uint32)ptr); + } } } @@ -1184,7 +1341,7 @@ aot_module_dup_data(AOTModuleInstance *module_inst, if (buffer_offset != 0) { buffer = aot_addr_app_to_native(module_inst, buffer_offset); - memcpy(buffer, src, size); + bh_memcpy_s(buffer, size, src, size); } return buffer_offset; } @@ -1194,13 +1351,12 @@ aot_validate_app_addr(AOTModuleInstance *module_inst, int32 app_offset, uint32 size) { AOTMemoryInstance *memory_inst = aot_get_default_memory(module_inst); + /* integer overflow check */ - if(app_offset + (int32)size < app_offset) { + if((uint32)app_offset + size < (uint32)app_offset) { goto fail; } - - if (memory_inst->heap_base_offset <= app_offset - && app_offset + (int32)size <= (int32)memory_inst->memory_data_size) { + if ((uint32)app_offset + size <= memory_inst->memory_data_size) { return true; } fail: @@ -1212,20 +1368,17 @@ bool aot_validate_native_addr(AOTModuleInstance *module_inst, void *native_ptr, uint32 size) { - uint8 *addr = (uint8*)native_ptr; + uint8 *addr = (uint8 *)native_ptr; AOTMemoryInstance *memory_inst = aot_get_default_memory(module_inst); - int32 memory_data_size = (int32)memory_inst->memory_data_size; /* integer overflow check */ if (addr + size < addr) { goto fail; } - if ((uint8*)memory_inst->heap_data.ptr <= addr - && addr + size <= (uint8*)memory_inst->memory_data.ptr - + memory_data_size) { + if ((uint8 *)memory_inst->memory_data.ptr <= addr + && addr + size <= (uint8 *)memory_inst->memory_data_end.ptr) return true; - } fail: aot_set_exception(module_inst, "out of bounds memory access"); return false; @@ -1235,12 +1388,10 @@ void * aot_addr_app_to_native(AOTModuleInstance *module_inst, int32 app_offset) { AOTMemoryInstance *memory_inst = aot_get_default_memory(module_inst); - int32 memory_data_size = (int32)memory_inst->memory_data_size; - uint8 *addr = (uint8 *)memory_inst->memory_data.ptr + app_offset; + uint8 *addr = (uint8 *)memory_inst->memory_data.ptr + (uint32)app_offset; - if ((uint8*)memory_inst->heap_data.ptr <= addr - && addr < (uint8*)memory_inst->memory_data.ptr - + memory_data_size) + if ((uint8 *)memory_inst->memory_data.ptr <= addr + && addr < (uint8 *)memory_inst->memory_data_end.ptr) return addr; return NULL; } @@ -1248,14 +1399,12 @@ aot_addr_app_to_native(AOTModuleInstance *module_inst, int32 app_offset) int32 aot_addr_native_to_app(AOTModuleInstance *module_inst, void *native_ptr) { - uint8 *addr = (uint8*)native_ptr; + uint8 *addr = (uint8 *)native_ptr; AOTMemoryInstance *memory_inst = aot_get_default_memory(module_inst); - int32 memory_data_size = (int32)memory_inst->memory_data_size; - if ((uint8*)memory_inst->heap_data.ptr <= addr - && addr < (uint8*)memory_inst->memory_data.ptr - + memory_data_size) - return (int32)(addr - (uint8*)memory_inst->memory_data.ptr); + if ((uint8 *)memory_inst->memory_data.ptr <= addr + && addr < (uint8 *)memory_inst->memory_data_end.ptr) + return (int32)(addr - (uint8 *)memory_inst->memory_data.ptr); return 0; } @@ -1266,14 +1415,13 @@ aot_get_app_addr_range(AOTModuleInstance *module_inst, int32 *p_app_end_offset) { AOTMemoryInstance *memory_inst = aot_get_default_memory(module_inst); - int32 memory_data_size = (int32)memory_inst->memory_data_size; + uint32 memory_data_size = memory_inst->memory_data_size; - if (memory_inst->heap_base_offset <= app_offset - && app_offset < memory_data_size) { + if ((uint32)app_offset < memory_data_size) { if (p_app_start_offset) - *p_app_start_offset = memory_inst->heap_base_offset; + *p_app_start_offset = 0; if (p_app_end_offset) - *p_app_end_offset = memory_data_size; + *p_app_end_offset = (int32)memory_data_size; return true; } return false; @@ -1285,18 +1433,15 @@ aot_get_native_addr_range(AOTModuleInstance *module_inst, uint8 **p_native_start_addr, uint8 **p_native_end_addr) { - uint8 *addr = (uint8*)native_ptr; + uint8 *addr = (uint8 *)native_ptr; AOTMemoryInstance *memory_inst = aot_get_default_memory(module_inst); - int32 memory_data_size = (int32)memory_inst->memory_data_size; - if ((uint8*)memory_inst->heap_data.ptr <= addr - && addr < (uint8*)memory_inst->memory_data.ptr - + memory_data_size) { + if ((uint8 *)memory_inst->memory_data.ptr <= addr + && addr < (uint8 *)memory_inst->memory_data_end.ptr) { if (p_native_start_addr) - *p_native_start_addr = (uint8*)memory_inst->heap_data.ptr; + *p_native_start_addr = (uint8 *)memory_inst->memory_data.ptr; if (p_native_end_addr) - *p_native_end_addr = (uint8*)memory_inst->memory_data.ptr - + memory_data_size; + *p_native_end_addr = (uint8 *)memory_inst->memory_data_end.ptr; return true; } return false; @@ -1307,17 +1452,17 @@ bool aot_enlarge_memory(AOTModuleInstance *module_inst, uint32 inc_page_count) { AOTMemoryInstance *memory_inst = aot_get_default_memory(module_inst); - uint8 *heap_data_old = memory_inst->heap_data.ptr, *heap_data; - uint32 num_bytes_per_page = - ((AOTModule*)module_inst->aot_module.ptr)->memories[0].num_bytes_per_page; - uint32 cur_page_count = memory_inst->mem_cur_page_count; - uint32 max_page_count = memory_inst->mem_max_page_count; + uint32 num_bytes_per_page = memory_inst->num_bytes_per_page; + uint32 cur_page_count = memory_inst->cur_page_count; + uint32 max_page_count = memory_inst->max_page_count; uint32 total_page_count = cur_page_count + inc_page_count; - uint64 memory_data_size = (uint64)num_bytes_per_page * total_page_count; - uint32 heap_size = (uint32)((uint8*)memory_inst->memory_data.ptr - - (uint8*)memory_inst->heap_data.ptr); - uint32 total_size_old = heap_size + memory_inst->memory_data_size; - uint64 total_size = heap_size + memory_data_size; + uint32 total_size_old = memory_inst->memory_data_size; + uint64 total_size = (uint64)num_bytes_per_page * total_page_count; + uint32 heap_size = (uint32)((uint8 *)memory_inst->heap_data_end.ptr + - (uint8 *)memory_inst->heap_data.ptr); + uint8 *memory_data_old = (uint8 *)memory_inst->memory_data.ptr; + uint8 *heap_data_old = (uint8 *)memory_inst->heap_data.ptr; + uint8 *memory_data, *heap_data; void *heap_handle_old = memory_inst->heap_handle.ptr; if (inc_page_count <= 0) @@ -1339,7 +1484,7 @@ aot_enlarge_memory(AOTModuleInstance *module_inst, uint32 inc_page_count) if (memory_inst->is_shared) { /* For shared memory, we have reserved the maximum spaces during instantiate, only change the cur_page_count here */ - memory_inst->mem_cur_page_count = total_page_count; + memory_inst->cur_page_count = total_page_count; return true; } #endif @@ -1349,8 +1494,9 @@ aot_enlarge_memory(AOTModuleInstance *module_inst, uint32 inc_page_count) we cannot access its lock again. */ mem_allocator_destroy_lock(memory_inst->heap_handle.ptr); } - if (!(heap_data = wasm_runtime_realloc(heap_data_old, (uint32)total_size))) { - if (!(heap_data = wasm_runtime_malloc((uint32)total_size))) { + if (!(memory_data = wasm_runtime_realloc(memory_data_old, + (uint32)total_size))) { + if (!(memory_data = wasm_runtime_malloc((uint32)total_size))) { if (heap_size > 0) { /* Restore heap's lock if memory re-alloc failed */ mem_allocator_reinit_lock(memory_inst->heap_handle.ptr); @@ -1358,20 +1504,22 @@ aot_enlarge_memory(AOTModuleInstance *module_inst, uint32 inc_page_count) aot_set_exception(module_inst, "fail to enlarge memory."); return false; } - bh_memcpy_s(heap_data, (uint32)total_size, - heap_data_old, total_size_old); - wasm_runtime_free(heap_data_old); + bh_memcpy_s(memory_data, (uint32)total_size, + memory_data_old, total_size_old); + wasm_runtime_free(memory_data_old); } - memset(heap_data + total_size_old, + memset(memory_data + total_size_old, 0, (uint32)total_size - total_size_old); - memory_inst->heap_data.ptr = heap_data; - memory_inst->heap_data_end.ptr = heap_data + heap_size; + memory_inst->cur_page_count = total_page_count; + memory_inst->memory_data_size = (uint32)total_size; + memory_inst->memory_data.ptr = memory_data; + memory_inst->memory_data_end.ptr = memory_data + total_size; if (heap_size > 0) { - memory_inst->heap_handle.ptr = (uint8*)heap_handle_old - + (heap_data - heap_data_old); + memory_inst->heap_handle.ptr = (uint8 *)heap_handle_old + + (memory_data - memory_data_old); if (mem_allocator_migrate(memory_inst->heap_handle.ptr, heap_handle_old) != 0) { aot_set_exception(module_inst, "fail to enlarge memory."); @@ -1379,29 +1527,34 @@ aot_enlarge_memory(AOTModuleInstance *module_inst, uint32 inc_page_count) } } - memory_inst->mem_cur_page_count = total_page_count; - memory_inst->memory_data_size = (uint32)memory_data_size; - memory_inst->memory_data.ptr = (uint8*)heap_data + heap_size; - memory_inst->memory_data_end.ptr = (uint8*)memory_inst->memory_data.ptr - + (uint32)memory_data_size; + heap_data = heap_data_old + (memory_data - memory_data_old); + memory_inst->heap_data.ptr = heap_data; + memory_inst->heap_data_end.ptr = heap_data + heap_size; - memory_inst->mem_bound_check_1byte = memory_inst->memory_data_size - 1; - memory_inst->mem_bound_check_2bytes = memory_inst->memory_data_size - 2; - memory_inst->mem_bound_check_4bytes = memory_inst->memory_data_size - 4; - memory_inst->mem_bound_check_8bytes = memory_inst->memory_data_size - 8; + if (sizeof(uintptr_t) == sizeof(uint64)) { + memory_inst->mem_bound_check_1byte.u64 = total_size - 1; + memory_inst->mem_bound_check_2bytes.u64 = total_size - 2; + memory_inst->mem_bound_check_4bytes.u64 = total_size - 4; + memory_inst->mem_bound_check_8bytes.u64 = total_size - 8; + } + else { + memory_inst->mem_bound_check_1byte.u32[0] = (uint32)total_size - 1; + memory_inst->mem_bound_check_2bytes.u32[0] = (uint32)total_size - 2; + memory_inst->mem_bound_check_4bytes.u32[0] = (uint32)total_size - 4; + memory_inst->mem_bound_check_8bytes.u32[0] = (uint32)total_size - 8; + } return true; } -#else +#else /* else of OS_ENABLE_HW_BOUND_CHECK */ bool aot_enlarge_memory(AOTModuleInstance *module_inst, uint32 inc_page_count) { AOTMemoryInstance *memory_inst = aot_get_default_memory(module_inst); - uint32 num_bytes_per_page = - ((AOTModule*)module_inst->aot_module.ptr)->memories[0].num_bytes_per_page; - uint32 cur_page_count = memory_inst->mem_cur_page_count; - uint32 max_page_count = memory_inst->mem_max_page_count; + uint32 num_bytes_per_page = memory_inst->num_bytes_per_page; + uint32 cur_page_count = memory_inst->cur_page_count; + uint32 max_page_count = memory_inst->max_page_count; uint32 total_page_count = cur_page_count + inc_page_count; - uint64 memory_data_size = (uint64)num_bytes_per_page * total_page_count; + uint64 total_size = (uint64)num_bytes_per_page * total_page_count; if (inc_page_count <= 0) /* No need to enlarge memory */ @@ -1413,8 +1566,9 @@ aot_enlarge_memory(AOTModuleInstance *module_inst, uint32 inc_page_count) return false; } - if (os_mprotect(memory_inst->memory_data.ptr, memory_data_size, - MMAP_PROT_READ | MMAP_PROT_WRITE) != 0) { + if (os_mprotect(memory_inst->memory_data_end.ptr, + num_bytes_per_page * inc_page_count, + MMAP_PROT_READ | MMAP_PROT_WRITE) != 0) { aot_set_exception(module_inst, "fail to enlarge memory."); return false; } @@ -1422,18 +1576,26 @@ aot_enlarge_memory(AOTModuleInstance *module_inst, uint32 inc_page_count) memset(memory_inst->memory_data_end.ptr, 0, num_bytes_per_page * inc_page_count); - memory_inst->mem_cur_page_count = total_page_count; - memory_inst->memory_data_size = (uint32)memory_data_size; - memory_inst->memory_data_end.ptr = (uint8*)memory_inst->memory_data.ptr - + (uint32)memory_data_size; + memory_inst->cur_page_count = total_page_count; + memory_inst->memory_data_size = (uint32)total_size; + memory_inst->memory_data_end.ptr = (uint8 *)memory_inst->memory_data.ptr + + (uint32)total_size; - memory_inst->mem_bound_check_1byte = memory_inst->memory_data_size - 1; - memory_inst->mem_bound_check_2bytes = memory_inst->memory_data_size - 2; - memory_inst->mem_bound_check_4bytes = memory_inst->memory_data_size - 4; - memory_inst->mem_bound_check_8bytes = memory_inst->memory_data_size - 8; + if (sizeof(uintptr_t) == sizeof(uint64)) { + memory_inst->mem_bound_check_1byte.u64 = total_size - 1; + memory_inst->mem_bound_check_2bytes.u64 = total_size - 2; + memory_inst->mem_bound_check_4bytes.u64 = total_size - 4; + memory_inst->mem_bound_check_8bytes.u64 = total_size - 8; + } + else { + memory_inst->mem_bound_check_1byte.u32[0] = (uint32)total_size - 1; + memory_inst->mem_bound_check_2bytes.u32[0] = (uint32)total_size - 2; + memory_inst->mem_bound_check_4bytes.u32[0] = (uint32)total_size - 4; + memory_inst->mem_bound_check_8bytes.u32[0] = (uint32)total_size - 8; + } return true; } -#endif +#endif /* end of OS_ENABLE_HW_BOUND_CHECK */ bool aot_is_wasm_type_equal(AOTModuleInstance *module_inst, @@ -1728,21 +1890,17 @@ aot_set_aux_stack(WASMExecEnv *exec_env, (AOTModuleInstance*)exec_env->module_inst; AOTModule *module = (AOTModule *)module_inst->aot_module.ptr; - uint32 stack_top_idx = - module->llvm_aux_stack_global_index; - uint32 data_end = - module->llvm_aux_data_end; - uint32 stack_bottom = - module->llvm_aux_stack_bottom; - bool is_stack_before_data = - stack_bottom < data_end ? true : false; + uint32 stack_top_idx = module->aux_stack_top_global_index; + uint32 data_end = module->aux_data_end; + uint32 stack_bottom = module->aux_stack_bottom; + bool is_stack_before_data = stack_bottom < data_end ? true : false; /* Check the aux stack space, currently we don't allocate space in heap */ if ((is_stack_before_data && (size > start_offset)) || ((!is_stack_before_data) && (start_offset - data_end < size))) return false; - if ((stack_bottom != (uint32)-1) && (stack_top_idx != (uint32)-1)) { + if (stack_top_idx != (uint32)-1) { /* The aux stack top is a wasm global, set the initial value for the global */ uint32 global_offset = @@ -1769,8 +1927,8 @@ aot_get_aux_stack(WASMExecEnv *exec_env, /* The aux stack information is resolved in loader and store in module */ - uint32 stack_bottom = module->llvm_aux_stack_bottom; - uint32 total_aux_stack_size = module->llvm_aux_stack_size; + uint32 stack_bottom = module->aux_stack_bottom; + uint32 total_aux_stack_size = module->aux_stack_size; if (stack_bottom != 0 && total_aux_stack_size != 0) { if (start_offset) diff --git a/core/iwasm/aot/aot_runtime.h b/core/iwasm/aot/aot_runtime.h index 95b54a46e..8f7a774a7 100644 --- a/core/iwasm/aot/aot_runtime.h +++ b/core/iwasm/aot/aot_runtime.h @@ -147,6 +147,9 @@ typedef struct AOTModule { /* start function, point to AOTed/JITed function */ void *start_function; + uint32 malloc_func_index; + uint32 free_func_index; + /* AOTed code, NULL for JIT mode */ void *code; uint32 code_size; @@ -163,10 +166,25 @@ typedef struct AOTModule { /* constant string set */ HashMap *const_str_set; - uint32 llvm_aux_data_end; - uint32 llvm_aux_stack_bottom; - uint32 llvm_aux_stack_size; - uint32 llvm_aux_stack_global_index; + /* the index of auxiliary __data_end global, + -1 means unexported */ + uint32 aux_data_end_global_index; + /* auxiliary __data_end exported by wasm app */ + uint32 aux_data_end; + + /* the index of auxiliary __heap_base global, + -1 means unexported */ + uint32 aux_heap_base_global_index; + /* auxiliary __heap_base exported by wasm app */ + uint32 aux_heap_base; + + /* the index of auxiliary stack top global, + -1 means unexported */ + uint32 aux_stack_top_global_index; + /* auxiliary stack bottom resolved */ + uint32 aux_stack_bottom; + /* auxiliary stack size resolved */ + uint32 aux_stack_size; /* is jit mode or not */ bool is_jit_mode; @@ -188,31 +206,34 @@ typedef union { void *ptr; } AOTPointer; +typedef union { + uint64 u64; + uint32 u32[2]; +} MemBound; + typedef struct AOTMemoryInstance { uint32 module_type; /* shared memory flag */ bool is_shared; + /* memory space info */ - uint32 mem_cur_page_count; - uint32 mem_max_page_count; + uint32 num_bytes_per_page; + uint32 cur_page_count; + uint32 max_page_count; uint32 memory_data_size; - uint32 __padding__; AOTPointer memory_data; AOTPointer memory_data_end; /* heap space info */ - int32 heap_base_offset; - uint32 heap_data_size; AOTPointer heap_data; AOTPointer heap_data_end; AOTPointer heap_handle; /* boundary check constants for aot code */ - int64 mem_bound_check_heap_base; - int64 mem_bound_check_1byte; - int64 mem_bound_check_2bytes; - int64 mem_bound_check_4bytes; - int64 mem_bound_check_8bytes; + MemBound mem_bound_check_1byte; + MemBound mem_bound_check_2bytes; + MemBound mem_bound_check_4bytes; + MemBound mem_bound_check_8bytes; } AOTMemoryInstance; typedef struct AOTModuleInstance { diff --git a/core/iwasm/compilation/aot.c b/core/iwasm/compilation/aot.c index 35cf56c55..04a97e2f6 100644 --- a/core/iwasm/compilation/aot.c +++ b/core/iwasm/compilation/aot.c @@ -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; diff --git a/core/iwasm/compilation/aot.h b/core/iwasm/compilation/aot.h index abf86d854..ccceb75f9 100644 --- a/core/iwasm/compilation/aot.h +++ b/core/iwasm/compilation/aot.h @@ -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; diff --git a/core/iwasm/compilation/aot_compiler.c b/core/iwasm/compilation/aot_compiler.c index c631259ce..d813300ec 100644 --- a/core/iwasm/compilation/aot_compiler.c +++ b/core/iwasm/compilation/aot_compiler.c @@ -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: diff --git a/core/iwasm/compilation/aot_emit_aot_file.c b/core/iwasm/compilation/aot_emit_aot_file.c index 8b9c39bf1..1d27d4f37 100644 --- a/core/iwasm/compilation/aot_emit_aot_file.c +++ b/core/iwasm/compilation/aot_emit_aot_file.c @@ -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; diff --git a/core/iwasm/compilation/aot_emit_memory.c b/core/iwasm/compilation/aot_emit_memory.c index cf80e6300..771513946 100644 --- a/core/iwasm/compilation/aot_emit_memory.c +++ b/core/iwasm/compilation/aot_emit_memory.c @@ -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"); diff --git a/core/iwasm/compilation/aot_llvm.c b/core/iwasm/compilation/aot_llvm.c index 753f67e27..cb024e5f9 100644 --- a/core/iwasm/compilation/aot_llvm.c +++ b/core/iwasm/compilation/aot_llvm.c @@ -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; diff --git a/core/iwasm/compilation/aot_llvm.h b/core/iwasm/compilation/aot_llvm.h index 82df590e3..3658b5fd0 100644 --- a/core/iwasm/compilation/aot_llvm.h +++ b/core/iwasm/compilation/aot_llvm.h @@ -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; diff --git a/core/iwasm/interpreter/wasm.h b/core/iwasm/interpreter/wasm.h index fd7f03a82..9fa2eda9b 100644 --- a/core/iwasm/interpreter/wasm.h +++ b/core/iwasm/interpreter/wasm.h @@ -325,15 +325,30 @@ typedef struct WASMModule { WASMDataSeg **data_segments; uint32 start_function; - /* __data_end global exported by llvm */ - uint32 llvm_aux_data_end; - /* auxiliary stack bottom, or __heap_base global exported by llvm */ - uint32 llvm_aux_stack_bottom; - /* auxiliary stack size */ - uint32 llvm_aux_stack_size; - /* the index of a global exported by llvm, which is - auxiliary stack top pointer */ - uint32 llvm_aux_stack_global_index; + /* the index of auxiliary __data_end global, + -1 means unexported */ + uint32 aux_data_end_global_index; + /* auxiliary __data_end exported by wasm app */ + uint32 aux_data_end; + + /* the index of auxiliary __heap_base global, + -1 means unexported */ + uint32 aux_heap_base_global_index; + /* auxiliary __heap_base exported by wasm app */ + uint32 aux_heap_base; + + /* the index of auxiliary stack top global, + -1 means unexported */ + uint32 aux_stack_top_global_index; + /* auxiliary stack bottom resolved */ + uint32 aux_stack_bottom; + /* auxiliary stack size resolved */ + uint32 aux_stack_size; + + /* the index of malloc/free function, + -1 means unexported */ + uint32 malloc_function; + uint32 free_function; /* Whether there is possible memory grow, e.g. memory.grow opcode */ bool possible_memory_grow; diff --git a/core/iwasm/interpreter/wasm_interp_classic.c b/core/iwasm/interpreter/wasm_interp_classic.c index 569f0466f..ab37459f0 100644 --- a/core/iwasm/interpreter/wasm_interp_classic.c +++ b/core/iwasm/interpreter/wasm_interp_classic.c @@ -227,9 +227,8 @@ LOAD_I16(void *addr) #endif /* WASM_CPU_SUPPORTS_UNALIGNED_64BIT_ACCESS != 0 */ #define CHECK_MEMORY_OVERFLOW(bytes) do { \ - int64 offset1 = (int64)(uint32)offset + (int64)(int32)addr; \ - if (heap_base_offset <= offset1 \ - && offset1 <= (int64)linear_mem_size - bytes) \ + uint64 offset1 = (uint64)offset + (uint64)addr; \ + if (offset1 + bytes <= (uint64)linear_mem_size) \ /* If offset1 is in valid range, maddr must also be in valid range, \ no need to check it again. */ \ maddr = memory->memory_data + offset1; \ @@ -238,8 +237,8 @@ LOAD_I16(void *addr) } while (0) #define CHECK_BULK_MEMORY_OVERFLOW(start, bytes, maddr) do { \ - uint64 offset1 = (int32)(start); \ - if (offset1 + bytes <= linear_mem_size) \ + uint64 offset1 = (uint32)(start); \ + if (offset1 + bytes <= (uint64)linear_mem_size) \ /* App heap space is not valid space for bulk memory operation */ \ maddr = memory->memory_data + offset1; \ else \ @@ -1063,7 +1062,6 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, WASMInterpFrame *prev_frame) { WASMMemoryInstance *memory = module->default_memory; - int32 heap_base_offset = memory ? memory->heap_base_offset : 0; uint32 num_bytes_per_page = memory ? memory->num_bytes_per_page : 0; uint8 *global_data = module->global_data; uint32 linear_mem_size = memory ? num_bytes_per_page * memory->cur_page_count : 0; @@ -1579,8 +1577,7 @@ label_pop_csp_n: HANDLE_OP (WASM_OP_I32_LOAD): HANDLE_OP (WASM_OP_F32_LOAD): { - uint32 offset, flags; - int32 addr; + uint32 offset, flags, addr; read_leb_uint32(frame_ip, frame_ip_end, flags); read_leb_uint32(frame_ip, frame_ip_end, offset); @@ -1594,8 +1591,7 @@ label_pop_csp_n: HANDLE_OP (WASM_OP_I64_LOAD): HANDLE_OP (WASM_OP_F64_LOAD): { - uint32 offset, flags; - int32 addr; + uint32 offset, flags, addr; read_leb_uint32(frame_ip, frame_ip_end, flags); read_leb_uint32(frame_ip, frame_ip_end, offset); @@ -1608,8 +1604,7 @@ label_pop_csp_n: HANDLE_OP (WASM_OP_I32_LOAD8_S): { - uint32 offset, flags; - int32 addr; + uint32 offset, flags, addr; read_leb_uint32(frame_ip, frame_ip_end, flags); read_leb_uint32(frame_ip, frame_ip_end, offset); @@ -1622,8 +1617,7 @@ label_pop_csp_n: HANDLE_OP (WASM_OP_I32_LOAD8_U): { - uint32 offset, flags; - int32 addr; + uint32 offset, flags, addr; read_leb_uint32(frame_ip, frame_ip_end, flags); read_leb_uint32(frame_ip, frame_ip_end, offset); @@ -1636,8 +1630,7 @@ label_pop_csp_n: HANDLE_OP (WASM_OP_I32_LOAD16_S): { - uint32 offset, flags; - int32 addr; + uint32 offset, flags, addr; read_leb_uint32(frame_ip, frame_ip_end, flags); read_leb_uint32(frame_ip, frame_ip_end, offset); @@ -1650,8 +1643,7 @@ label_pop_csp_n: HANDLE_OP (WASM_OP_I32_LOAD16_U): { - uint32 offset, flags; - int32 addr; + uint32 offset, flags, addr; read_leb_uint32(frame_ip, frame_ip_end, flags); read_leb_uint32(frame_ip, frame_ip_end, offset); @@ -1664,8 +1656,7 @@ label_pop_csp_n: HANDLE_OP (WASM_OP_I64_LOAD8_S): { - uint32 offset, flags; - int32 addr; + uint32 offset, flags, addr; read_leb_uint32(frame_ip, frame_ip_end, flags); read_leb_uint32(frame_ip, frame_ip_end, offset); @@ -1678,8 +1669,7 @@ label_pop_csp_n: HANDLE_OP (WASM_OP_I64_LOAD8_U): { - uint32 offset, flags; - int32 addr; + uint32 offset, flags, addr; read_leb_uint32(frame_ip, frame_ip_end, flags); read_leb_uint32(frame_ip, frame_ip_end, offset); @@ -1692,8 +1682,7 @@ label_pop_csp_n: HANDLE_OP (WASM_OP_I64_LOAD16_S): { - uint32 offset, flags; - int32 addr; + uint32 offset, flags, addr; read_leb_uint32(frame_ip, frame_ip_end, flags); read_leb_uint32(frame_ip, frame_ip_end, offset); @@ -1706,8 +1695,7 @@ label_pop_csp_n: HANDLE_OP (WASM_OP_I64_LOAD16_U): { - uint32 offset, flags; - int32 addr; + uint32 offset, flags, addr; read_leb_uint32(frame_ip, frame_ip_end, flags); read_leb_uint32(frame_ip, frame_ip_end, offset); @@ -1720,8 +1708,7 @@ label_pop_csp_n: HANDLE_OP (WASM_OP_I64_LOAD32_S): { - uint32 offset, flags; - int32 addr; + uint32 offset, flags, addr; opcode = *(frame_ip - 1); read_leb_uint32(frame_ip, frame_ip_end, flags); @@ -1735,8 +1722,7 @@ label_pop_csp_n: HANDLE_OP (WASM_OP_I64_LOAD32_U): { - uint32 offset, flags; - int32 addr; + uint32 offset, flags, addr; read_leb_uint32(frame_ip, frame_ip_end, flags); read_leb_uint32(frame_ip, frame_ip_end, offset); @@ -1751,8 +1737,7 @@ label_pop_csp_n: HANDLE_OP (WASM_OP_I32_STORE): HANDLE_OP (WASM_OP_F32_STORE): { - uint32 offset, flags; - int32 addr; + uint32 offset, flags, addr; read_leb_uint32(frame_ip, frame_ip_end, flags); read_leb_uint32(frame_ip, frame_ip_end, offset); @@ -1767,8 +1752,7 @@ label_pop_csp_n: HANDLE_OP (WASM_OP_I64_STORE): HANDLE_OP (WASM_OP_F64_STORE): { - uint32 offset, flags; - int32 addr; + uint32 offset, flags, addr; read_leb_uint32(frame_ip, frame_ip_end, flags); read_leb_uint32(frame_ip, frame_ip_end, offset); @@ -1784,8 +1768,7 @@ label_pop_csp_n: HANDLE_OP (WASM_OP_I32_STORE8): HANDLE_OP (WASM_OP_I32_STORE16): { - uint32 offset, flags; - int32 addr; + uint32 offset, flags, addr; uint32 sval; opcode = *(frame_ip - 1); @@ -1811,8 +1794,7 @@ label_pop_csp_n: HANDLE_OP (WASM_OP_I64_STORE16): HANDLE_OP (WASM_OP_I64_STORE32): { - uint32 offset, flags; - int32 addr; + uint32 offset, flags, addr; uint64 sval; opcode = *(frame_ip - 1); @@ -2665,9 +2647,12 @@ label_pop_csp_n: HANDLE_OP (WASM_OP_MISC_PREFIX): { - opcode = *frame_ip++; - switch (opcode) - { + uint32 opcode1; + + read_leb_uint32(frame_ip, frame_ip_end, opcode1); + opcode = (uint8)opcode1; + + switch (opcode) { case WASM_OP_I32_TRUNC_SAT_S_F32: DEF_OP_TRUNC_SAT_F32(-2147483904.0f, 2147483648.0f, true, true); @@ -2787,8 +2772,7 @@ label_pop_csp_n: #if WASM_ENABLE_SHARED_MEMORY != 0 HANDLE_OP (WASM_OP_ATOMIC_PREFIX): { - uint32 offset, align; - int32 addr; + uint32 offset, align, addr; opcode = *frame_ip++; diff --git a/core/iwasm/interpreter/wasm_interp_fast.c b/core/iwasm/interpreter/wasm_interp_fast.c index 166dc107e..ce39dc3b4 100644 --- a/core/iwasm/interpreter/wasm_interp_fast.c +++ b/core/iwasm/interpreter/wasm_interp_fast.c @@ -229,9 +229,8 @@ LOAD_I16(void *addr) #endif /* WASM_CPU_SUPPORTS_UNALIGNED_64BIT_ACCESS != 0 */ #define CHECK_MEMORY_OVERFLOW(bytes) do { \ - int64 offset1 = (int64)(uint32)offset + (int64)(int32)addr; \ - if (heap_base_offset <= offset1 \ - && offset1 <= (int64)linear_mem_size - bytes) \ + uint64 offset1 = (uint64)offset + (uint64)addr; \ + if (offset1 + bytes <= (uint64)linear_mem_size) \ /* If offset1 is in valid range, maddr must also be in valid range,\ no need to check it again. */ \ maddr = memory->memory_data + offset1; \ @@ -239,13 +238,13 @@ LOAD_I16(void *addr) goto out_of_bounds; \ } while (0) -#define CHECK_BULK_MEMORY_OVERFLOW(start, bytes, maddr) do { \ - uint64 offset1 = (int32)(start); \ - if (offset1 + bytes <= linear_mem_size) \ - /* App heap space is not valid space for bulk memory operation */ \ - maddr = memory->memory_data + offset1; \ - else \ - goto out_of_bounds; \ +#define CHECK_BULK_MEMORY_OVERFLOW(start, bytes, maddr) do { \ + uint64 offset1 = (uint32)(start); \ + if (offset1 + bytes <= linear_mem_size) \ + /* App heap space is not valid space for bulk memory operation */ \ + maddr = memory->memory_data + offset1; \ + else \ + goto out_of_bounds; \ } while (0) #define CHECK_ATOMIC_MEMORY_ACCESS(align) do { \ @@ -1163,7 +1162,6 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, WASMInterpFrame *prev_frame) { WASMMemoryInstance *memory = module->default_memory; - int32 heap_base_offset = memory ? memory->heap_base_offset : 0; uint32 num_bytes_per_page = memory ? memory->num_bytes_per_page : 0; uint8 *global_data = module->global_data; uint32 linear_mem_size = memory ? num_bytes_per_page * memory->cur_page_count : 0; @@ -2768,8 +2766,7 @@ recover_br_info: #if WASM_ENABLE_SHARED_MEMORY != 0 HANDLE_OP (WASM_OP_ATOMIC_PREFIX): { - uint32 offset; - int32 addr; + uint32 offset, addr; GET_OPCODE(); diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index 175f4d036..f9f8d1016 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -52,14 +52,14 @@ check_buf1(const uint8 *buf, const uint8 *buf_end, uint32 length, #define CHECK_BUF(buf, buf_end, length) do { \ if (!check_buf(buf, buf_end, length, \ error_buf, error_buf_size)) { \ - return false; \ + goto fail; \ } \ } while (0) #define CHECK_BUF1(buf, buf_end, length) do { \ if (!check_buf1(buf, buf_end, length, \ error_buf, error_buf_size)) { \ - return false; \ + goto fail; \ } \ } while (0) @@ -90,6 +90,8 @@ skip_leb(const uint8 **p_buf, const uint8 *buf_end, uint32 maxbits, *p_buf += offset; return true; +fail: + return false; } #define skip_leb_int64(p, p_end) do { \ @@ -184,6 +186,7 @@ read_leb(uint8 **p_buf, const uint8 *buf_end, fail_integer_too_large: set_error_buf(error_buf, error_buf_size, "WASM module load failed: integer too large"); +fail: return false; } @@ -195,7 +198,7 @@ fail_integer_too_large: uint64 res64; \ if (!read_leb((uint8**)&p, p_end, 64, true, &res64,\ error_buf, error_buf_size)) \ - return false; \ + goto fail; \ res = (int64)res64; \ } while (0) @@ -203,7 +206,7 @@ fail_integer_too_large: uint64 res64; \ if (!read_leb((uint8**)&p, p_end, 32, false, &res64,\ error_buf, error_buf_size)) \ - return false; \ + goto fail; \ res = (uint32)res64; \ } while (0) @@ -211,7 +214,7 @@ fail_integer_too_large: uint64 res64; \ if (!read_leb((uint8**)&p, p_end, 32, true, &res64,\ error_buf, error_buf_size)) \ - return false; \ + goto fail; \ res = (int32)res64; \ } while (0) @@ -335,19 +338,19 @@ load_init_expr(const uint8 **p_buf, const uint8 *buf_end, /* i32.const */ case INIT_EXPR_TYPE_I32_CONST: if (type != VALUE_TYPE_I32) - goto fail; + goto fail_type_mismatch; read_leb_int32(p, p_end, init_expr->u.i32); break; /* i64.const */ case INIT_EXPR_TYPE_I64_CONST: if (type != VALUE_TYPE_I64) - goto fail; + goto fail_type_mismatch; read_leb_int64(p, p_end, init_expr->u.i64); break; /* f32.const */ case INIT_EXPR_TYPE_F32_CONST: if (type != VALUE_TYPE_F32) - goto fail; + goto fail_type_mismatch; CHECK_BUF(p, p_end, 4); p_float = (uint8*)&init_expr->u.f32; for (i = 0; i < sizeof(float32); i++) @@ -356,7 +359,7 @@ load_init_expr(const uint8 **p_buf, const uint8 *buf_end, /* f64.const */ case INIT_EXPR_TYPE_F64_CONST: if (type != VALUE_TYPE_F64) - goto fail; + goto fail_type_mismatch; CHECK_BUF(p, p_end, 8); p_float = (uint8*)&init_expr->u.f64; for (i = 0; i < sizeof(float64); i++) @@ -367,19 +370,20 @@ load_init_expr(const uint8 **p_buf, const uint8 *buf_end, read_leb_uint32(p, p_end, init_expr->u.global_index); break; default: - goto fail; + goto fail_type_mismatch; } CHECK_BUF(p, p_end, 1); end_byte = read_uint8(p); if (end_byte != 0x0b) - goto fail; + goto fail_type_mismatch; *p_buf = p; return true; -fail: +fail_type_mismatch: set_error_buf(error_buf, error_buf_size, "WASM module load failed: type mismatch or " "constant expression required."); +fail: return false; } @@ -472,6 +476,8 @@ load_type_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, LOG_VERBOSE("Load type section success.\n"); return true; +fail: + return false; } #if WASM_ENABLE_MULTI_MODULE != 0 @@ -804,6 +810,8 @@ load_function_import(const WASMModule *parent_module, WASMModule *sub_module, function->import_func_linked = is_built_in_module ? NULL : linked_func; #endif return true; +fail: + return false; } static bool @@ -905,6 +913,8 @@ load_table_import(WASMModule *sub_module, const char *sub_module_name, table->flags = declare_max_size_flag; table->max_size = declare_max_size; return true; +fail: + return false; } unsigned @@ -1034,6 +1044,8 @@ load_memory_import(WASMModule *sub_module, const char *sub_module_name, *p_buf = p; return true; +fail: + return false; } static bool @@ -1107,13 +1119,15 @@ load_global_import(const WASMModule *parent_module, global->type = declare_type; global->is_mutable = is_mutable; return true; +fail: + return false; } static bool load_table(const uint8 **p_buf, const uint8 *buf_end, WASMTable *table, char *error_buf, uint32 error_buf_size) { - const uint8 *p = *p_buf, *p_end = buf_end; + const uint8 *p = *p_buf, *p_end = buf_end, *p_org; CHECK_BUF(p, p_end, 1); /* 0x70 */ @@ -1123,32 +1137,40 @@ load_table(const uint8 **p_buf, const uint8 *buf_end, WASMTable *table, return false; } + p_org = p; read_leb_uint32(p, p_end, table->flags); + if (p - p_org > 1) { + set_error_buf(error_buf, error_buf_size, + "integer representation too long"); + return false; + } + if (table->flags > 1) { + set_error_buf(error_buf, error_buf_size, "integer too large"); + return false; + } + read_leb_uint32(p, p_end, table->init_size); - if (table->flags & 1) { + if (table->flags == 0) { + table->max_size = 0x10000; + } + else if (table->flags == 1) { read_leb_uint32(p, p_end, table->max_size); if (!check_table_max_size(table->init_size, table->max_size, error_buf, error_buf_size)) return false; } - else - table->max_size = 0x10000; - - if ((table->flags & 1) && table->init_size > table->max_size) { - set_error_buf(error_buf, error_buf_size, - "size minimum must not be greater than maximum"); - return false; - } *p_buf = p; return true; +fail: + return false; } static bool load_memory(const uint8 **p_buf, const uint8 *buf_end, WASMMemory *memory, char *error_buf, uint32 error_buf_size) { - const uint8 *p = *p_buf, *p_end = buf_end; + const uint8 *p = *p_buf, *p_end = buf_end, *p_org; uint32 pool_size = wasm_runtime_memory_pool_size(); #if WASM_ENABLE_APP_FRAMEWORK != 0 uint32 max_page_count = pool_size * APP_MEMORY_MAX_GLOBAL_HEAP_PERCENT @@ -1157,7 +1179,25 @@ load_memory(const uint8 **p_buf, const uint8 *buf_end, WASMMemory *memory, uint32 max_page_count = pool_size / DEFAULT_NUM_BYTES_PER_PAGE; #endif + p_org = p; read_leb_uint32(p, p_end, memory->flags); + if (p - p_org > 1) { + set_error_buf(error_buf, error_buf_size, + "integer representation too long"); + return false; + } +#if WASM_ENABLE_SHARED_MEMORY == 0 + if (memory->flags > 1) { + set_error_buf(error_buf, error_buf_size, "integer too large"); + return false; + } +#else + if (memory->flags > 3 || memory->flags == 2) { + set_error_buf(error_buf, error_buf_size, "integer too large"); + return false; + } +#endif + read_leb_uint32(p, p_end, memory->init_page_count); if (!check_memory_init_size(memory->init_page_count, error_buf, error_buf_size)) @@ -1172,14 +1212,17 @@ load_memory(const uint8 **p_buf, const uint8 *buf_end, WASMMemory *memory, if (memory->max_page_count > max_page_count) memory->max_page_count = max_page_count; } - else + else { /* Limit the maximum memory size to max_page_count */ memory->max_page_count = max_page_count; + } memory->num_bytes_per_page = DEFAULT_NUM_BYTES_PER_PAGE; *p_buf = p; return true; +fail: + return false; } #if WASM_ENABLE_MULTI_MODULE != 0 @@ -1434,7 +1477,7 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, default: set_error_buf(error_buf, error_buf_size, - "Load import section failed: invalid import type."); + "Load import section failed: invalid import kind"); return false; } } @@ -1454,7 +1497,7 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, p = p_old; - // TODO: move it out of the loop + /* TODO: move it out of the loop */ /* insert "env", "wasi_unstable" and "wasi_snapshot_preview1" to const str list */ if (!const_str_list_insert((uint8*)"env", 3, module, error_buf, error_buf_size) || !const_str_list_insert((uint8*)"wasi_unstable", 13, module, @@ -1566,7 +1609,7 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, default: set_error_buf(error_buf, error_buf_size, "Load import section failed: " - "invalid import type."); + "invalid import kind"); return false; } import->kind = kind; @@ -1598,6 +1641,8 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, (void)u32; (void)type_index; return true; +fail: + return false; } static bool @@ -1779,6 +1824,8 @@ load_function_section(const uint8 *buf, const uint8 *buf_end, LOG_VERBOSE("Load function section success.\n"); return true; +fail: + return false; } static bool @@ -1820,6 +1867,8 @@ load_table_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, LOG_VERBOSE("Load table section success.\n"); return true; +fail: + return false; } static bool @@ -1861,6 +1910,8 @@ load_memory_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, LOG_VERBOSE("Load memory section success.\n"); return true; +fail: + return false; } static bool @@ -1926,6 +1977,8 @@ load_global_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, LOG_VERBOSE("Load global section success.\n"); return true; +fail: + return false; } static bool @@ -2029,6 +2082,8 @@ load_export_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, LOG_VERBOSE("Load export section success.\n"); return true; +fail: + return false; } static bool @@ -2102,6 +2157,8 @@ load_table_segment_section(const uint8 *buf, const uint8 *buf_end, WASMModule *m LOG_VERBOSE("Load table segment section success.\n"); return true; +fail: + return false; } static bool @@ -2217,6 +2274,8 @@ check_mem_index: LOG_VERBOSE("Load data segment section success.\n"); return true; +fail: + return false; } #if WASM_ENABLE_BULK_MEMORY != 0 @@ -2238,6 +2297,8 @@ load_datacount_section(const uint8 *buf, const uint8 *buf_end, WASMModule *modul LOG_VERBOSE("Load datacount section success.\n"); return true; +fail: + return false; } #endif @@ -2268,6 +2329,8 @@ load_code_section(const uint8 *buf, const uint8 *buf_end, LOG_VERBOSE("Load code segment section success.\n"); return true; +fail: + return false; } static bool @@ -2311,6 +2374,8 @@ load_start_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, LOG_VERBOSE("Load start section success.\n"); return true; +fail: + return false; } static bool @@ -2344,6 +2409,8 @@ load_user_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, LOG_VERBOSE("Load custom section success.\n"); return true; +fail: + return false; } @@ -2367,12 +2434,14 @@ load_from_sections(WASMModule *module, WASMSection *sections, WASMSection *section = sections; const uint8 *buf, *buf_end, *buf_code = NULL, *buf_code_end = NULL, *buf_func = NULL, *buf_func_end = NULL; - WASMGlobal *llvm_data_end_global = NULL, *llvm_heap_base_global = NULL; - WASMGlobal *llvm_stack_top_global = NULL, *global; - uint32 llvm_data_end = UINT32_MAX, llvm_heap_base = UINT32_MAX; - uint32 llvm_stack_top = UINT32_MAX, global_index, i; - uint32 stack_top_global_index = UINT32_MAX; + WASMGlobal *aux_data_end_global = NULL, *aux_heap_base_global = NULL; + WASMGlobal *aux_stack_top_global = NULL, *global; + uint32 aux_data_end = (uint32)-1, aux_heap_base = (uint32)-1; + uint32 aux_stack_top = (uint32)-1, global_index, func_index, i; + uint32 aux_data_end_global_index = (uint32)-1; + uint32 aux_heap_base_global_index = (uint32)-1; BlockAddr *block_addr_cache; + WASMType *func_type; uint64 total_size; /* Find code and function sections if have */ @@ -2481,7 +2550,11 @@ load_from_sections(WASMModule *module, WASMSection *sections, } wasm_runtime_free(block_addr_cache); - /* Resolve llvm auxiliary data/stack/heap info and reset memory info */ + module->aux_data_end_global_index = (uint32)-1; + module->aux_heap_base_global_index = (uint32)-1; + module->aux_stack_top_global_index = (uint32)-1; + + /* Resolve auxiliary data/stack/heap info and reset memory info */ export = module->exports; for (i = 0; i < module->export_count; i++, export++) { if (export->kind == EXPORT_KIND_GLOBAL) { @@ -2492,10 +2565,11 @@ load_from_sections(WASMModule *module, WASMSection *sections, && !global->is_mutable && global->init_expr.init_expr_type == INIT_EXPR_TYPE_I32_CONST) { - llvm_heap_base_global = global; - llvm_heap_base = global->init_expr.u.i32; - LOG_VERBOSE("found llvm __heap_base global, value: %d\n", - llvm_heap_base); + aux_heap_base_global = global; + aux_heap_base = global->init_expr.u.i32; + aux_heap_base_global_index = export->index; + LOG_VERBOSE("Found aux __heap_base global, value: %d", + aux_heap_base); } } else if (!strcmp(export->name, "__data_end")) { @@ -2505,12 +2579,13 @@ load_from_sections(WASMModule *module, WASMSection *sections, && !global->is_mutable && global->init_expr.init_expr_type == INIT_EXPR_TYPE_I32_CONST) { - llvm_data_end_global = global; - llvm_data_end = global->init_expr.u.i32; - LOG_VERBOSE("found llvm __data_end global, value: %d\n", - llvm_data_end); + aux_data_end_global = global; + aux_data_end = global->init_expr.u.i32; + aux_data_end_global_index = export->index; + LOG_VERBOSE("Found aux __data_end global, value: %d", + aux_data_end); - llvm_data_end = align_uint(llvm_data_end, 16); + aux_data_end = align_uint(aux_data_end, 16); } } @@ -2530,64 +2605,97 @@ load_from_sections(WASMModule *module, WASMSection *sections, [3] heap_base <-- 3 [4] dso_handle */ - if (llvm_data_end_global && llvm_heap_base_global) { + if (aux_data_end_global && aux_heap_base_global + && aux_data_end <= aux_heap_base) { + module->aux_data_end_global_index = aux_data_end_global_index; + module->aux_data_end = aux_data_end; + module->aux_heap_base_global_index = aux_heap_base_global_index; + module->aux_heap_base = aux_heap_base; + /* Resolve aux stack top global */ - for (global_index = 0; global_index < module->global_count; global_index++) { + for (global_index = 0; global_index < module->global_count; + global_index++) { global = module->globals + global_index; - if (global != llvm_data_end_global - && global != llvm_heap_base_global + if (global->is_mutable /* heap_base and data_end is + not mutable */ && global->type == VALUE_TYPE_I32 - && global->is_mutable && global->init_expr.init_expr_type == INIT_EXPR_TYPE_I32_CONST - && (global->init_expr.u.i32 <= - llvm_heap_base_global->init_expr.u.i32 - && llvm_data_end_global->init_expr.u.i32 <= - llvm_heap_base_global->init_expr.u.i32)) { - llvm_stack_top_global = global; - llvm_stack_top = global->init_expr.u.i32; - stack_top_global_index = global_index; - LOG_VERBOSE("found llvm stack top global, " - "value: %d, global index: %d\n", - llvm_stack_top, global_index); + && (uint32)global->init_expr.u.i32 <= aux_heap_base) { + aux_stack_top_global = global; + aux_stack_top = (uint32)global->init_expr.u.i32; + module->aux_stack_top_global_index = + module->import_global_count + global_index; + module->aux_stack_bottom = aux_stack_top; + module->aux_stack_size = aux_stack_top > aux_data_end + ? aux_stack_top - aux_data_end + : aux_stack_top; + LOG_VERBOSE("Found aux stack top global, value: %d, " + "global index: %d, stack size: %d", + aux_stack_top, global_index, + module->aux_stack_size); break; } } - - module->llvm_aux_data_end = llvm_data_end; - module->llvm_aux_stack_bottom = llvm_stack_top; - module->llvm_aux_stack_size = llvm_stack_top > llvm_data_end - ? llvm_stack_top - llvm_data_end - : llvm_stack_top; - module->llvm_aux_stack_global_index = stack_top_global_index; - LOG_VERBOSE("aux stack bottom: %d, size: %d\n", - module->llvm_aux_stack_bottom, - module->llvm_aux_stack_size); break; } } } + module->malloc_function = (uint32)-1; + module->free_function = (uint32)-1; + + /* Resolve auxiliary data/stack/heap info and reset memory info */ + export = module->exports; + for (i = 0; i < module->export_count; i++, export++) { + if (export->kind == EXPORT_KIND_FUNC) { + if (!strcmp(export->name, "malloc") + && export->index >= module->import_function_count) { + func_index = export->index - module->import_function_count; + func_type = module->functions[func_index]->func_type; + if (func_type->param_count == 1 + && func_type->result_count == 1 + && func_type->types[0] == VALUE_TYPE_I32 + && func_type->types[1] == VALUE_TYPE_I32) { + module->malloc_function = export->index; + LOG_VERBOSE("Found malloc function, index: %u", + export->index); + } + } + else if (!strcmp(export->name, "free") + && export->index >= module->import_function_count) { + func_index = export->index - module->import_function_count; + func_type = module->functions[func_index]->func_type; + if (func_type->param_count == 1 + && func_type->result_count == 0 + && func_type->types[0] == VALUE_TYPE_I32) { + module->free_function = export->index; + LOG_VERBOSE("Found free function, index: %u", + export->index); + } + } + } + } + if (!module->possible_memory_grow) { - if (llvm_data_end_global - && llvm_heap_base_global - && llvm_stack_top_global - && llvm_stack_top <= llvm_heap_base) { - WASMMemoryImport *memory_import; - WASMMemory *memory; + WASMMemoryImport *memory_import; + WASMMemory *memory; + + if (aux_data_end_global + && aux_heap_base_global + && aux_stack_top_global) { uint64 init_memory_size; - uint32 shrunk_memory_size = llvm_heap_base > llvm_data_end - ? llvm_heap_base : llvm_data_end; + uint32 shrunk_memory_size = align_uint(aux_heap_base, 8); + if (module->import_memory_count) { memory_import = &module->import_memories[0].u.memory; init_memory_size = (uint64)memory_import->num_bytes_per_page * memory_import->init_page_count; - if (llvm_heap_base <= init_memory_size - && llvm_data_end <= init_memory_size) { + if (shrunk_memory_size <= init_memory_size) { /* Reset memory info to decrease memory usage */ memory_import->num_bytes_per_page = shrunk_memory_size; memory_import->init_page_count = 1; - LOG_VERBOSE("reset import memory size to %d\n", + LOG_VERBOSE("Shrink import memory size to %d", shrunk_memory_size); } } @@ -2595,15 +2703,31 @@ load_from_sections(WASMModule *module, WASMSection *sections, memory = &module->memories[0]; init_memory_size = (uint64)memory->num_bytes_per_page * memory->init_page_count; - if (llvm_heap_base <= init_memory_size - && llvm_data_end <= init_memory_size) { + if (shrunk_memory_size <= init_memory_size) { /* Reset memory info to decrease memory usage */ memory->num_bytes_per_page = shrunk_memory_size; memory->init_page_count = 1; - LOG_VERBOSE("reset memory size to %d\n", shrunk_memory_size); + LOG_VERBOSE("Shrink memory size to %d", shrunk_memory_size); } } } + +#if WASM_ENABLE_MULTI_MODULE == 0 + if (module->import_memory_count) { + memory_import = &module->import_memories[0].u.memory; + /* Memory init page count cannot be larger than 65536, we don't + check integer overflow again. */ + memory_import->num_bytes_per_page *= memory_import->init_page_count; + memory_import->init_page_count = memory_import->max_page_count = 1; + } + if (module->memory_count) { + /* Memory init page count cannot be larger than 65536, we don't + check integer overflow again. */ + memory = &module->memories[0]; + memory->num_bytes_per_page *= memory->init_page_count; + memory->init_page_count = memory->max_page_count = 1; + } +#endif } return true; @@ -2759,6 +2883,8 @@ create_sections(const uint8 *buf, uint32 size, } return true; +fail: + return false; } static void @@ -2819,6 +2945,8 @@ load(const uint8 *buf, uint32 size, WASMModule *module, destroy_sections(section_list); return true; +fail: + return false; } WASMModule* @@ -2834,7 +2962,7 @@ wasm_loader_load(const uint8 *buf, uint32 size, char *error_buf, uint32 error_bu goto fail; } - LOG_VERBOSE("Load module success"); + LOG_VERBOSE("Load module success.\n"); return module; fail: @@ -3275,8 +3403,11 @@ wasm_loader_find_block_addr(BlockAddr *block_addr_cache, break; case WASM_OP_MISC_PREFIX: { - opcode = read_uint8(p); - switch (opcode) { + uint32 opcode1; + + read_leb_uint32(p, p_end, opcode1); + + switch (opcode1) { case WASM_OP_I32_TRUNC_SAT_S_F32: case WASM_OP_I32_TRUNC_SAT_U_F32: case WASM_OP_I32_TRUNC_SAT_S_F64: @@ -3340,6 +3471,8 @@ wasm_loader_find_block_addr(BlockAddr *block_addr_cache, (void)u8; return false; +fail: + return false; } #define REF_I32 VALUE_TYPE_I32 @@ -6032,8 +6165,8 @@ handle_op_block_and_loop: || global_type == VALUE_TYPE_F64) { *p_org = WASM_OP_SET_GLOBAL_64; } - else if (module->llvm_aux_stack_size > 0 - && global_idx == module->llvm_aux_stack_global_index) { + else if (module->aux_stack_size > 0 + && global_idx == module->aux_stack_top_global_index) { *p_org = WASM_OP_SET_GLOBAL_AUX_STACK; } #endif @@ -6043,8 +6176,8 @@ handle_op_block_and_loop: skip_label(); emit_label(WASM_OP_SET_GLOBAL_64); } - else if (module->llvm_aux_stack_size > 0 - && global_idx == module->llvm_aux_stack_global_index) { + else if (module->aux_stack_size > 0 + && global_idx == module->aux_stack_top_global_index) { skip_label(); emit_label(WASM_OP_SET_GLOBAL_AUX_STACK); } @@ -6462,11 +6595,13 @@ handle_op_block_and_loop: case WASM_OP_MISC_PREFIX: { - opcode = read_uint8(p); + uint32 opcode1; + + read_leb_uint32(p, p_end, opcode1); #if WASM_ENABLE_FAST_INTERP != 0 - emit_byte(loader_ctx, opcode); + emit_byte(loader_ctx, ((uint8)opcode1)); #endif - switch (opcode) + switch (opcode1) { case WASM_OP_I32_TRUNC_SAT_S_F32: case WASM_OP_I32_TRUNC_SAT_U_F32: @@ -6574,7 +6709,7 @@ fail_data_cnt_sec_require: if (error_buf != NULL) snprintf(error_buf, error_buf_size, "WASM module load failed: " - "invalid opcode 0xfc %02x.", opcode); + "invalid opcode 0xfc %02x.", opcode1); goto fail; break; } diff --git a/core/iwasm/interpreter/wasm_mini_loader.c b/core/iwasm/interpreter/wasm_mini_loader.c index 483ee126a..a56c2a382 100644 --- a/core/iwasm/interpreter/wasm_mini_loader.c +++ b/core/iwasm/interpreter/wasm_mini_loader.c @@ -555,24 +555,27 @@ static bool load_table(const uint8 **p_buf, const uint8 *buf_end, WASMTable *table, char *error_buf, uint32 error_buf_size) { - const uint8 *p = *p_buf, *p_end = buf_end; + const uint8 *p = *p_buf, *p_end = buf_end, *p_org; CHECK_BUF(p, p_end, 1); /* 0x70 */ table->elem_type = read_uint8(p); bh_assert(TABLE_ELEM_TYPE_ANY_FUNC == table->elem_type); + p_org = p; read_leb_uint32(p, p_end, table->flags); + bh_assert(p - p_org <= 1); + bh_assert(table->flags <= 1); + (void)p_org; + read_leb_uint32(p, p_end, table->init_size); - if (table->flags & 1) { + if (table->flags == 0) { + table->max_size = 0x10000; + } + else if (table->flags == 1) { read_leb_uint32(p, p_end, table->max_size); bh_assert(table->init_size <= table->max_size); } - else - table->max_size = 0x10000; - - bh_assert(!((table->flags & 1) - && table->init_size > table->max_size)); *p_buf = p; return true; @@ -582,7 +585,7 @@ static bool load_memory(const uint8 **p_buf, const uint8 *buf_end, WASMMemory *memory, char *error_buf, uint32 error_buf_size) { - const uint8 *p = *p_buf, *p_end = buf_end; + const uint8 *p = *p_buf, *p_end = buf_end, *p_org; uint32 pool_size = wasm_runtime_memory_pool_size(); #if WASM_ENABLE_APP_FRAMEWORK != 0 uint32 max_page_count = pool_size * APP_MEMORY_MAX_GLOBAL_HEAP_PERCENT @@ -591,7 +594,15 @@ load_memory(const uint8 **p_buf, const uint8 *buf_end, WASMMemory *memory, uint32 max_page_count = pool_size / DEFAULT_NUM_BYTES_PER_PAGE; #endif + p_org = p; read_leb_uint32(p, p_end, memory->flags); + bh_assert(p - p_org <= 1); +#if WASM_ENABLE_SHARED_MEMORY == 0 + bh_assert(memory->flags <= 1); +#else + bh_assert(memory->flags <= 3 && memory->flags != 2); +#endif + read_leb_uint32(p, p_end, memory->init_page_count); bh_assert(memory->init_page_count <= 65536); @@ -602,9 +613,10 @@ load_memory(const uint8 **p_buf, const uint8 *buf_end, WASMMemory *memory, if (memory->max_page_count > max_page_count) memory->max_page_count = max_page_count; } - else + else { /* Limit the maximum memory size to max_page_count */ memory->max_page_count = max_page_count; + } memory->num_bytes_per_page = DEFAULT_NUM_BYTES_PER_PAGE; @@ -707,7 +719,7 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, p = p_old; - // TODO: move it out of the loop + /* TODO: move it out of the loop */ /* insert "env", "wasi_unstable" and "wasi_snapshot_preview1" to const str list */ if (!const_str_list_insert((uint8*)"env", 3, module, error_buf, error_buf_size) || !const_str_list_insert((uint8*)"wasi_unstable", 13, module, @@ -1436,12 +1448,14 @@ load_from_sections(WASMModule *module, WASMSection *sections, WASMSection *section = sections; const uint8 *buf, *buf_end, *buf_code = NULL, *buf_code_end = NULL, *buf_func = NULL, *buf_func_end = NULL; - WASMGlobal *llvm_data_end_global = NULL, *llvm_heap_base_global = NULL; - WASMGlobal *llvm_stack_top_global = NULL, *global; - uint32 llvm_data_end = UINT32_MAX, llvm_heap_base = UINT32_MAX; - uint32 llvm_stack_top = UINT32_MAX, global_index, i; - uint32 stack_top_global_index = UINT32_MAX; + WASMGlobal *aux_data_end_global = NULL, *aux_heap_base_global = NULL; + WASMGlobal *aux_stack_top_global = NULL, *global; + uint32 aux_data_end = (uint32)-1, aux_heap_base = (uint32)-1; + uint32 aux_stack_top = (uint32)-1, global_index, func_index, i; + uint32 aux_data_end_global_index = (uint32)-1; + uint32 aux_heap_base_global_index = (uint32)-1; BlockAddr *block_addr_cache; + WASMType *func_type; uint64 total_size; /* Find code and function sections if have */ @@ -1550,7 +1564,11 @@ load_from_sections(WASMModule *module, WASMSection *sections, } wasm_runtime_free(block_addr_cache); - /* Resolve llvm auxiliary data/stack/heap info and reset memory info */ + module->aux_data_end_global_index = (uint32)-1; + module->aux_heap_base_global_index = (uint32)-1; + module->aux_stack_top_global_index = (uint32)-1; + + /* Resolve auxiliary data/stack/heap info and reset memory info */ export = module->exports; for (i = 0; i < module->export_count; i++, export++) { if (export->kind == EXPORT_KIND_GLOBAL) { @@ -1561,10 +1579,11 @@ load_from_sections(WASMModule *module, WASMSection *sections, && !global->is_mutable && global->init_expr.init_expr_type == INIT_EXPR_TYPE_I32_CONST) { - llvm_heap_base_global = global; - llvm_heap_base = global->init_expr.u.i32; - LOG_VERBOSE("found llvm __heap_base global, value: %d\n", - llvm_heap_base); + aux_heap_base_global = global; + aux_heap_base = global->init_expr.u.i32; + aux_heap_base_global_index = export->index; + LOG_VERBOSE("Found aux __heap_base global, value: %d", + aux_heap_base); } } else if (!strcmp(export->name, "__data_end")) { @@ -1574,89 +1593,155 @@ load_from_sections(WASMModule *module, WASMSection *sections, && !global->is_mutable && global->init_expr.init_expr_type == INIT_EXPR_TYPE_I32_CONST) { - llvm_data_end_global = global; - llvm_data_end = global->init_expr.u.i32; - LOG_VERBOSE("found llvm __data_end global, value: %d\n", - llvm_data_end); + aux_data_end_global = global; + aux_data_end = global->init_expr.u.i32; + aux_data_end_global_index = export->index; + LOG_VERBOSE("Found aux __data_end global, value: %d", + aux_data_end); - llvm_data_end = align_uint(llvm_data_end, 16); + aux_data_end = align_uint(aux_data_end, 16); } } - if (llvm_data_end_global && llvm_heap_base_global) { + /* For module compiled with -pthread option, the global is: + [0] stack_top <-- 0 + [1] tls_pointer + [2] tls_size + [3] data_end <-- 3 + [4] global_base + [5] heap_base <-- 5 + [6] dso_handle + + For module compiled without -pthread option: + [0] stack_top <-- 0 + [1] data_end <-- 1 + [2] global_base + [3] heap_base <-- 3 + [4] dso_handle + */ + if (aux_data_end_global && aux_heap_base_global + && aux_data_end <= aux_heap_base) { + module->aux_data_end_global_index = aux_data_end_global_index; + module->aux_data_end = aux_data_end; + module->aux_heap_base_global_index = aux_heap_base_global_index; + module->aux_heap_base = aux_heap_base; + /* Resolve aux stack top global */ - for (global_index = 0; global_index < module->global_count; global_index++) { + for (global_index = 0; global_index < module->global_count; + global_index++) { global = module->globals + global_index; - if (global != llvm_data_end_global - && global != llvm_heap_base_global + if (global->is_mutable /* heap_base and data_end is + not mutable */ && global->type == VALUE_TYPE_I32 - && global->is_mutable && global->init_expr.init_expr_type == INIT_EXPR_TYPE_I32_CONST - && (global->init_expr.u.i32 <= - llvm_heap_base_global->init_expr.u.i32 - && llvm_data_end_global->init_expr.u.i32 <= - llvm_heap_base_global->init_expr.u.i32)) { - llvm_stack_top_global = global; - llvm_stack_top = global->init_expr.u.i32; - stack_top_global_index = global_index; - LOG_VERBOSE("found llvm stack top global, " - "value: %d, global index: %d\n", - llvm_stack_top, global_index); + && (uint32)global->init_expr.u.i32 <= aux_heap_base) { + aux_stack_top_global = global; + aux_stack_top = (uint32)global->init_expr.u.i32; + module->aux_stack_top_global_index = + module->import_global_count + global_index; + module->aux_stack_bottom = aux_stack_top; + module->aux_stack_size = aux_stack_top > aux_data_end + ? aux_stack_top - aux_data_end + : aux_stack_top; + LOG_VERBOSE("Found aux stack top global, value: %d, " + "global index: %d, stack size: %d", + aux_stack_top, global_index, + module->aux_stack_size); break; } } - - module->llvm_aux_data_end = llvm_data_end; - module->llvm_aux_stack_bottom = llvm_stack_top; - module->llvm_aux_stack_size = llvm_stack_top > llvm_data_end - ? llvm_stack_top - llvm_data_end - : llvm_stack_top; - module->llvm_aux_stack_global_index = stack_top_global_index; - LOG_VERBOSE("aux stack bottom: %d, size: %d\n", - module->llvm_aux_stack_bottom, - module->llvm_aux_stack_size); break; } } } + module->malloc_function = (uint32)-1; + module->free_function = (uint32)-1; + + /* Resolve auxiliary data/stack/heap info and reset memory info */ + export = module->exports; + for (i = 0; i < module->export_count; i++, export++) { + if (export->kind == EXPORT_KIND_FUNC) { + if (!strcmp(export->name, "malloc") + && export->index >= module->import_function_count) { + func_index = export->index - module->import_function_count; + func_type = module->functions[func_index]->func_type; + if (func_type->param_count == 1 + && func_type->result_count == 1 + && func_type->types[0] == VALUE_TYPE_I32 + && func_type->types[1] == VALUE_TYPE_I32) { + module->malloc_function = export->index; + LOG_VERBOSE("Found malloc function, index: %u", + export->index); + } + } + else if (!strcmp(export->name, "free") + && export->index >= module->import_function_count) { + func_index = export->index - module->import_function_count; + func_type = module->functions[func_index]->func_type; + if (func_type->param_count == 1 + && func_type->result_count == 0 + && func_type->types[0] == VALUE_TYPE_I32) { + module->free_function = export->index; + LOG_VERBOSE("Found free function, index: %u", + export->index); + } + } + } + } + if (!module->possible_memory_grow) { - if (llvm_data_end_global - && llvm_heap_base_global - && llvm_stack_top_global - && llvm_stack_top <= llvm_heap_base) { - WASMMemoryImport *memory_import; - WASMMemory *memory; + WASMMemoryImport *memory_import; + WASMMemory *memory; + + if (aux_data_end_global + && aux_heap_base_global + && aux_stack_top_global) { uint64 init_memory_size; - uint32 shrunk_memory_size = llvm_heap_base > llvm_data_end - ? llvm_heap_base : llvm_data_end; + uint32 shrunk_memory_size = align_uint(aux_heap_base, 8); + if (module->import_memory_count) { memory_import = &module->import_memories[0].u.memory; init_memory_size = (uint64)memory_import->num_bytes_per_page * memory_import->init_page_count; - if (llvm_heap_base <= init_memory_size - && llvm_data_end <= init_memory_size) { + if (shrunk_memory_size <= init_memory_size) { /* Reset memory info to decrease memory usage */ memory_import->num_bytes_per_page = shrunk_memory_size; memory_import->init_page_count = 1; - LOG_VERBOSE("reset import memory size to %d\n", + LOG_VERBOSE("Shrink import memory size to %d", shrunk_memory_size); } } if (module->memory_count) { memory = &module->memories[0]; init_memory_size = (uint64)memory->num_bytes_per_page * - memory->init_page_count; - if (llvm_heap_base <= init_memory_size - && llvm_data_end <= init_memory_size) { + memory->init_page_count; + if (shrunk_memory_size <= init_memory_size) { /* Reset memory info to decrease memory usage */ memory->num_bytes_per_page = shrunk_memory_size; memory->init_page_count = 1; - LOG_VERBOSE("reset memory size to %d\n", shrunk_memory_size); + LOG_VERBOSE("Shrink memory size to %d", shrunk_memory_size); } } } + +#if WASM_ENABLE_MULTI_MODULE == 0 + if (module->import_memory_count) { + memory_import = &module->import_memories[0].u.memory; + /* Memory init page count cannot be larger than 65536, we don't + check integer overflow again. */ + memory_import->num_bytes_per_page *= memory_import->init_page_count; + memory_import->init_page_count = memory_import->max_page_count = 1; + } + if (module->memory_count) { + /* Memory init page count cannot be larger than 65536, we don't + check integer overflow again. */ + memory = &module->memories[0]; + memory->num_bytes_per_page *= memory->init_page_count; + memory->init_page_count = memory->max_page_count = 1; + } +#endif } return true; @@ -1878,7 +1963,7 @@ wasm_loader_load(const uint8 *buf, uint32 size, char *error_buf, uint32 error_bu goto fail; } - LOG_VERBOSE("Load module success"); + LOG_VERBOSE("Load module success.\n"); return module; fail: @@ -2295,8 +2380,11 @@ wasm_loader_find_block_addr(BlockAddr *block_addr_cache, break; case WASM_OP_MISC_PREFIX: { - opcode = read_uint8(p); - switch (opcode) { + uint32 opcode1; + + read_leb_uint32(p, p_end, opcode1); + + switch (opcode1) { case WASM_OP_I32_TRUNC_SAT_S_F32: case WASM_OP_I32_TRUNC_SAT_U_F32: case WASM_OP_I32_TRUNC_SAT_S_F64: @@ -4869,8 +4957,8 @@ handle_op_block_and_loop: || global_type == VALUE_TYPE_F64) { *p_org = WASM_OP_SET_GLOBAL_64; } - else if (module->llvm_aux_stack_size > 0 - && global_idx == module->llvm_aux_stack_global_index) { + else if (module->aux_stack_size > 0 + && global_idx == module->aux_stack_top_global_index) { *p_org = WASM_OP_SET_GLOBAL_AUX_STACK; } #endif @@ -4880,8 +4968,8 @@ handle_op_block_and_loop: skip_label(); emit_label(WASM_OP_SET_GLOBAL_64); } - else if (module->llvm_aux_stack_size > 0 - && global_idx == module->llvm_aux_stack_global_index) { + else if (module->aux_stack_size > 0 + && global_idx == module->aux_stack_top_global_index) { skip_label(); emit_label(WASM_OP_SET_GLOBAL_AUX_STACK); } @@ -5289,12 +5377,13 @@ handle_op_block_and_loop: case WASM_OP_MISC_PREFIX: { - opcode = read_uint8(p); + uint32 opcode1; + + read_leb_uint32(p, p_end, opcode1); #if WASM_ENABLE_FAST_INTERP != 0 - emit_byte(loader_ctx, opcode); + emit_byte(loader_ctx, ((uint8)opcode1)); #endif - switch (opcode) - { + switch (opcode1) { case WASM_OP_I32_TRUNC_SAT_S_F32: case WASM_OP_I32_TRUNC_SAT_U_F32: POP_AND_PUSH(VALUE_TYPE_F32, VALUE_TYPE_I32); diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index 42829c7a2..9e1c427cc 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -122,11 +122,13 @@ memory_instantiate(WASMModuleInstance *module_inst, uint32 heap_size, uint32 flags, char *error_buf, uint32 error_buf_size) { + WASMModule *module = module_inst->module; WASMMemoryInstance *memory; - uint64 heap_and_inst_size = offsetof(WASMMemoryInstance, base_addr) + - (uint64)heap_size; - uint64 total_size = heap_and_inst_size + - num_bytes_per_page * (uint64)init_page_count; + uint64 total_size, memory_data_size; + uint32 heap_offset = num_bytes_per_page * init_page_count; + uint32 inc_page_count, aux_heap_base, global_idx; + uint32 bytes_of_last_page, bytes_to_page_end; + uint8 *global_addr; #if WASM_ENABLE_SHARED_MEMORY != 0 bool is_shared_memory = flags & 0x02 ? true : false; @@ -149,12 +151,96 @@ memory_instantiate(WASMModuleInstance *module_inst, (void)ref_count; return memory; } + } +#endif /* end of WASM_ENABLE_SHARED_MEMORY */ + + if (heap_size > 0 + && module_inst->module->malloc_function != (uint32)-1 + && module_inst->module->free_function != (uint32)-1) { + /* Disable app heap, use malloc/free function exported + by wasm app to allocate/free memory instead */ + heap_size = 0; + } + + if (init_page_count == max_page_count && init_page_count == 1) { + /* If only one page and at most one page, we just append + the app heap to the end of linear memory, enlarge the + num_bytes_per_page, and don't change the page count*/ + heap_offset = num_bytes_per_page; + num_bytes_per_page += heap_size; + if (num_bytes_per_page < heap_size) { + set_error_buf(error_buf, error_buf_size, + "memory size must be at most 65536 pages (4GiB)"); + return NULL; + } + } + else if (heap_size > 0) { + if (module->aux_heap_base_global_index != (uint32)-1 + && module->aux_heap_base < num_bytes_per_page + * init_page_count) { + /* Insert app heap before __heap_base */ + aux_heap_base = module->aux_heap_base; + bytes_of_last_page = aux_heap_base % num_bytes_per_page; + if (bytes_of_last_page == 0) + bytes_of_last_page = num_bytes_per_page; + bytes_to_page_end = num_bytes_per_page - bytes_of_last_page; + inc_page_count = (heap_size - bytes_to_page_end + + num_bytes_per_page - 1) / num_bytes_per_page; + heap_offset = aux_heap_base; + aux_heap_base += heap_size; + + bytes_of_last_page = aux_heap_base % num_bytes_per_page; + if (bytes_of_last_page == 0) + bytes_of_last_page = num_bytes_per_page; + bytes_to_page_end = num_bytes_per_page - bytes_of_last_page; + if (bytes_to_page_end < 1 * BH_KB) { + aux_heap_base += 1 * BH_KB; + inc_page_count++; + } + + /* Adjust __heap_base global value */ + global_idx = module->aux_heap_base_global_index; + global_addr = module_inst->global_data + + module_inst->globals[global_idx].data_offset; + *(uint32 *)global_addr = aux_heap_base; + LOG_VERBOSE("Reset __heap_base global to %u", aux_heap_base); + } + else { + /* Insert app heap before new page */ + inc_page_count = (heap_size + num_bytes_per_page - 1) + / num_bytes_per_page; + heap_offset = num_bytes_per_page * init_page_count; + heap_size = num_bytes_per_page * inc_page_count; + if (heap_size > 0) + heap_size -= 1 * BH_KB; + } + init_page_count += inc_page_count; + max_page_count += inc_page_count; + if (init_page_count > 65536) { + set_error_buf(error_buf, error_buf_size, + "memory size must be at most 65536 pages (4GiB)"); + return NULL; + } + if (max_page_count > 65536) + max_page_count = 65536; + } + + LOG_VERBOSE("Memory instantiate:"); + LOG_VERBOSE(" page bytes: %u, init pages: %u, max pages: %u", + num_bytes_per_page, init_page_count, max_page_count); + LOG_VERBOSE(" heap offset: %u, heap size: %d\n", heap_offset, heap_size); + + memory_data_size = (uint64)num_bytes_per_page * init_page_count; +#if WASM_ENABLE_SHARED_MEMORY != 0 + if (is_shared_memory) { /* Allocate max page for shared memory */ - total_size = heap_and_inst_size + - num_bytes_per_page * (uint64)max_page_count; + memory_data_size = (uint64)num_bytes_per_page * max_page_count; } #endif + total_size = offsetof(WASMMemoryInstance, memory_data) + + memory_data_size; + /* Allocate memory space, addr data and global data */ if (!(memory = runtime_malloc(total_size, error_buf, error_buf_size))) { @@ -166,37 +252,28 @@ memory_instantiate(WASMModuleInstance *module_inst, memory->cur_page_count = init_page_count; memory->max_page_count = max_page_count; - memory->heap_data = memory->base_addr; - memory->memory_data = memory->heap_data + heap_size; -#if WASM_ENABLE_SHARED_MEMORY != 0 - if (is_shared_memory) { - memory->end_addr = memory->memory_data + - num_bytes_per_page * memory->max_page_count; - } - else -#endif - { - memory->end_addr = memory->memory_data + - num_bytes_per_page * memory->cur_page_count; - } + memory->heap_data = memory->memory_data + heap_offset; + memory->heap_data_end = memory->heap_data + heap_size; + memory->memory_data_end = memory->memory_data + (uint32)memory_data_size; - bh_assert(memory->end_addr - (uint8*)memory == (uint32)total_size); + bh_assert(memory->memory_data_end - (uint8*)memory == (uint32)total_size); /* Initialize heap */ if (heap_size > 0 && !(memory->heap_handle = mem_allocator_create(memory->heap_data, heap_size))) { - wasm_runtime_free(memory); - return NULL; + set_error_buf(error_buf, error_buf_size, + "Instantiate memory failed: " + "init app heap failed."); + goto fail1; } - memory->heap_base_offset = -(int32)heap_size; - #if WASM_ENABLE_SHARED_MEMORY != 0 if (0 != os_mutex_init(&memory->mem_lock)) { - mem_allocator_destroy(memory->heap_handle); - wasm_runtime_free(memory); - return NULL; + set_error_buf(error_buf, error_buf_size, + "Instantiate memory failed: " + "init mutex failed."); + goto fail2; } if (is_shared_memory) { memory->is_shared = true; @@ -204,16 +281,23 @@ memory_instantiate(WASMModuleInstance *module_inst, (WASMModuleCommon *)module_inst->module, (WASMMemoryInstanceCommon *)memory)) { set_error_buf(error_buf, error_buf_size, - "Instantiate memory failed:" + "Instantiate memory failed: " "allocate memory failed."); - os_mutex_destroy(&memory->mem_lock); - mem_allocator_destroy(memory->heap_handle); - wasm_runtime_free(memory); - return NULL; + goto fail3; } } #endif return memory; +#if WASM_ENABLE_SHARED_MEMORY != 0 +fail3: + os_mutex_destroy(&memory->mem_lock); +fail2: + if (heap_size > 0) + mem_allocator_destroy(memory->heap_handle); +#endif +fail1: + wasm_runtime_free(memory); + return NULL; } /** @@ -275,12 +359,7 @@ memories_instantiate(const WASMModule *module, module_inst, num_bytes_per_page, init_page_count, max_page_count, actual_heap_size, flags, error_buf, error_buf_size))) { - set_error_buf(error_buf, error_buf_size, - "Instantiate memory failed: " - "allocate memory failed."); - memories_deinstantiate( - module_inst, - memories, memory_count); + memories_deinstantiate(module_inst, memories, memory_count); return NULL; } } @@ -295,12 +374,7 @@ memories_instantiate(const WASMModule *module, module->memories[i].max_page_count, heap_size, module->memories[i].flags, error_buf, error_buf_size))) { - set_error_buf(error_buf, error_buf_size, - "Instantiate memory failed: " - "allocate memory failed."); - memories_deinstantiate( - module_inst, - memories, memory_count); + memories_deinstantiate(module_inst, memories, memory_count); return NULL; } #if WASM_ENABLE_MULTI_MODULE != 0 @@ -316,9 +390,6 @@ memories_instantiate(const WASMModule *module, if (!(memory = memories[mem_index++] = memory_instantiate(module_inst, 0, 0, 0, heap_size, 0, error_buf, error_buf_size))) { - set_error_buf(error_buf, error_buf_size, - "Instantiate memory failed: " - "allocate memory failed.\n"); memories_deinstantiate(module_inst, memories, memory_count); return NULL; } @@ -914,6 +985,34 @@ execute_start_function(WASMModuleInstance *module_inst) return wasm_create_exec_env_and_call_function(module_inst, func, 0, NULL); } +static bool +execute_malloc_function(WASMModuleInstance *module_inst, + WASMFunctionInstance *malloc_func, + uint32 size, uint32 *p_result) +{ + uint32 argv[2]; + bool ret; + + argv[0] = size; + ret = wasm_create_exec_env_and_call_function + (module_inst, malloc_func, 1, argv); + if (ret) + *p_result = argv[0]; + return ret; +} + +static bool +execute_free_function(WASMModuleInstance *module_inst, + WASMFunctionInstance *free_func, + uint32 offset) +{ + uint32 argv[2]; + + argv[0] = offset; + return wasm_create_exec_env_and_call_function + (module_inst, free_func, 1, argv); +} + #if WASM_ENABLE_MULTI_MODULE != 0 static bool sub_module_instantiate(WASMModule *module, WASMModuleInstance *module_inst, @@ -1251,6 +1350,28 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, table_seg->func_indexes, (uint32)(length * sizeof(uint32))); } + /* module instance type */ + module_inst->module_type = Wasm_Module_Bytecode; + + /* Initialize the thread related data */ + if (stack_size == 0) + stack_size = DEFAULT_WASM_STACK_SIZE; +#if WASM_ENABLE_SPEC_TEST != 0 + if (stack_size < 48 *1024) + stack_size = 48 * 1024; +#endif + module_inst->default_wasm_stack_size = stack_size; + + if (module->malloc_function != (uint32)-1) { + module_inst->malloc_function = + &module_inst->functions[module->malloc_function]; + } + + if (module->free_function != (uint32)-1) { + module_inst->free_function = + &module_inst->functions[module->free_function]; + } + #if WASM_ENABLE_LIBC_WASI != 0 /* The sub-instance will get the wasi_ctx from main-instance */ if (!is_sub_inst) { @@ -1278,18 +1399,6 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, &module_inst->functions[module->start_function]; } - /* module instance type */ - module_inst->module_type = Wasm_Module_Bytecode; - - /* Initialize the thread related data */ - if (stack_size == 0) - stack_size = DEFAULT_WASM_STACK_SIZE; -#if WASM_ENABLE_SPEC_TEST != 0 - if (stack_size < 48 *1024) - stack_size = 48 * 1024; -#endif - module_inst->default_wasm_stack_size = stack_size; - /* Execute __post_instantiate function */ if (!execute_post_inst_function(module_inst) || !execute_start_function(module_inst)) { @@ -1467,7 +1576,22 @@ wasm_module_malloc(WASMModuleInstance *module_inst, uint32 size, void **p_native_addr) { WASMMemoryInstance *memory = module_inst->default_memory; - uint8 *addr = mem_allocator_malloc(memory->heap_handle, size); + uint8 *addr = NULL; + uint32 offset = 0; + + if (memory->heap_handle) { + addr = mem_allocator_malloc(memory->heap_handle, size); + } + else if (module_inst->malloc_function + && module_inst->free_function) { + if (!execute_malloc_function(module_inst, + module_inst->malloc_function, + size, &offset)) { + return 0; + } + addr = offset ? memory->memory_data + offset : NULL; + } + if (!addr) { wasm_set_exception(module_inst, "out of memory"); return 0; @@ -1482,9 +1606,21 @@ wasm_module_free(WASMModuleInstance *module_inst, int32 ptr) { if (ptr) { WASMMemoryInstance *memory = module_inst->default_memory; - uint8 *addr = memory->memory_data + ptr; - if (memory->heap_data < addr && addr < memory->memory_data) + uint8 *addr = memory->memory_data + (uint32)ptr; + + if (memory->heap_handle + && memory->heap_data <= addr + && addr < memory->heap_data_end) { mem_allocator_free(memory->heap_handle, addr); + } + else if (module_inst->malloc_function + && module_inst->free_function + && memory->memory_data <= addr + && addr < memory->memory_data_end) { + execute_free_function(module_inst, + module_inst->free_function, + (uint32)ptr); + } } } @@ -1507,16 +1643,15 @@ wasm_validate_app_addr(WASMModuleInstance *module_inst, int32 app_offset, uint32 size) { WASMMemoryInstance *memory = module_inst->default_memory; - int32 memory_data_size = - (int32)(memory->num_bytes_per_page * memory->cur_page_count); + uint32 memory_data_size = + memory->num_bytes_per_page * memory->cur_page_count; /* integer overflow check */ - if (app_offset + (int32)size < app_offset) { + if ((uint32)app_offset + size < (uint32)app_offset) { goto fail; } - if (memory->heap_base_offset <= app_offset - && app_offset + (int32)size <= memory_data_size) { + if ((uint32)app_offset + size <= memory_data_size) { return true; } fail: @@ -1528,17 +1663,16 @@ bool wasm_validate_native_addr(WASMModuleInstance *module_inst, void *native_ptr, uint32 size) { - uint8 *addr = (uint8*)native_ptr; + uint8 *addr = (uint8 *)native_ptr; WASMMemoryInstance *memory = module_inst->default_memory; - int32 memory_data_size = - (int32)(memory->num_bytes_per_page * memory->cur_page_count); + /* integer overflow check */ if (addr + size < addr) { goto fail; } - if (memory->heap_data <= addr - && addr + size <= memory->memory_data + memory_data_size) { + if (memory->memory_data <= addr + && addr + size <= memory->memory_data_end) { return true; } fail: @@ -1552,11 +1686,9 @@ wasm_addr_app_to_native(WASMModuleInstance *module_inst, { WASMMemoryInstance *memory = module_inst->default_memory; uint8 *addr = memory->memory_data + app_offset; - int32 memory_data_size = - (int32)(memory->num_bytes_per_page * memory->cur_page_count); - if (memory->heap_data <= addr - && addr < memory->memory_data + memory_data_size) + if (memory->memory_data <= addr + && addr < memory->memory_data_end) return addr; return NULL; } @@ -1566,12 +1698,10 @@ wasm_addr_native_to_app(WASMModuleInstance *module_inst, void *native_ptr) { WASMMemoryInstance *memory = module_inst->default_memory; - uint8 *addr = (uint8*)native_ptr; - int32 memory_data_size = - (int32)(memory->num_bytes_per_page * memory->cur_page_count); + uint8 *addr = (uint8 *)native_ptr; - if (memory->heap_data <= addr - && addr < memory->memory_data + memory_data_size) + if (memory->memory_data <= addr + && addr < memory->memory_data_end) return (int32)(addr - memory->memory_data); return 0; } @@ -1583,13 +1713,12 @@ wasm_get_app_addr_range(WASMModuleInstance *module_inst, int32 *p_app_end_offset) { WASMMemoryInstance *memory = module_inst->default_memory; - int32 memory_data_size = - (int32)(memory->num_bytes_per_page * memory->cur_page_count); + uint32 memory_data_size = + memory->num_bytes_per_page * memory->cur_page_count; - if (memory->heap_base_offset <= app_offset - && app_offset < memory_data_size) { + if ((uint32)app_offset < memory_data_size) { if (p_app_start_offset) - *p_app_start_offset = memory->heap_base_offset; + *p_app_start_offset = 0; if (p_app_end_offset) *p_app_end_offset = memory_data_size; return true; @@ -1604,16 +1733,14 @@ wasm_get_native_addr_range(WASMModuleInstance *module_inst, uint8 **p_native_end_addr) { WASMMemoryInstance *memory = module_inst->default_memory; - uint8 *addr = (uint8*)native_ptr; - int32 memory_data_size = - (int32)(memory->num_bytes_per_page * memory->cur_page_count); + uint8 *addr = (uint8 *)native_ptr; - if (memory->heap_data <= addr - && addr < memory->memory_data + memory_data_size) { + if (memory->memory_data <= addr + && addr < memory->memory_data_end) { if (p_native_start_addr) - *p_native_start_addr = memory->heap_data; + *p_native_start_addr = memory->memory_data; if (p_native_end_addr) - *p_native_end_addr = memory->memory_data + memory_data_size; + *p_native_end_addr = memory->memory_data_end; return true; } return false; @@ -1623,13 +1750,13 @@ bool wasm_enlarge_memory(WASMModuleInstance *module, uint32 inc_page_count) { WASMMemoryInstance *memory = module->default_memory, *new_memory; - uint32 heap_size = memory->memory_data - memory->heap_data; - uint32 total_size_old = memory->end_addr - (uint8*)memory; + uint32 heap_size = memory->heap_data_end - memory->heap_data; + uint32 total_size_old = memory->memory_data_end - (uint8 *)memory; uint32 total_page_count = inc_page_count + memory->cur_page_count; - uint64 total_size = offsetof(WASMMemoryInstance, base_addr) - + (uint64)heap_size + uint64 total_size = offsetof(WASMMemoryInstance, memory_data) + memory->num_bytes_per_page * (uint64)total_page_count; void *heap_handle_old = memory->heap_handle; + uint8 *heap_data_old = memory->heap_data; if (inc_page_count <= 0) /* No need to enlarge memory */ @@ -1669,17 +1796,17 @@ wasm_enlarge_memory(WASMModuleInstance *module, uint32 inc_page_count) wasm_set_exception(module, "fail to enlarge memory."); return false; } - bh_memcpy_s((uint8*)new_memory, (uint32)total_size, - (uint8*)memory, total_size_old); + bh_memcpy_s((uint8 *)new_memory, (uint32)total_size, + (uint8 *)memory, total_size_old); wasm_runtime_free(memory); } - memset((uint8*)new_memory + total_size_old, + memset((uint8 *)new_memory + total_size_old, 0, (uint32)total_size - total_size_old); if (heap_size > 0) { - new_memory->heap_handle = (uint8*)heap_handle_old + - ((uint8*)new_memory - (uint8*)memory); + new_memory->heap_handle = (uint8 *)heap_handle_old + + ((uint8 *)new_memory - (uint8 *)memory); if (mem_allocator_migrate(new_memory->heap_handle, heap_handle_old) != 0) { wasm_set_exception(module, "fail to enlarge memory."); @@ -1688,10 +1815,12 @@ wasm_enlarge_memory(WASMModuleInstance *module, uint32 inc_page_count) } new_memory->cur_page_count = total_page_count; - new_memory->heap_data = new_memory->base_addr; - new_memory->memory_data = new_memory->base_addr + heap_size; - new_memory->end_addr = new_memory->memory_data + - new_memory->num_bytes_per_page * total_page_count; + new_memory->heap_data = heap_data_old + + ((uint8 *)new_memory - (uint8 *)memory); + new_memory->heap_data_end = new_memory->heap_data + heap_size; + new_memory->memory_data_end = new_memory->memory_data + + new_memory->num_bytes_per_page + * total_page_count; module->memories[0] = module->default_memory = new_memory; return true; @@ -1757,13 +1886,9 @@ wasm_set_aux_stack(WASMExecEnv *exec_env, { WASMModuleInstance *module_inst = (WASMModuleInstance*)exec_env->module_inst; - - uint32 stack_top_idx = - module_inst->module->llvm_aux_stack_global_index; - uint32 data_end = - module_inst->module->llvm_aux_data_end; - uint32 stack_bottom = - module_inst->module->llvm_aux_stack_bottom; + uint32 stack_top_idx = module_inst->module->aux_stack_top_global_index; + uint32 data_end = module_inst->module->aux_data_end; + uint32 stack_bottom = module_inst->module->aux_stack_bottom; bool is_stack_before_data = stack_bottom < data_end ? true : false; @@ -1772,7 +1897,7 @@ wasm_set_aux_stack(WASMExecEnv *exec_env, || ((!is_stack_before_data) && (start_offset - data_end < size))) return false; - if ((stack_bottom != (uint32)-1) && (stack_top_idx != (uint32)-1)) { + if (stack_top_idx != (uint32)-1) { /* The aux stack top is a wasm global, set the initial value for the global */ uint8 *global_addr = @@ -1798,9 +1923,9 @@ wasm_get_aux_stack(WASMExecEnv *exec_env, /* The aux stack information is resolved in loader and store in module */ uint32 stack_bottom = - module_inst->module->llvm_aux_stack_bottom; + module_inst->module->aux_stack_bottom; uint32 total_aux_stack_size = - module_inst->module->llvm_aux_stack_size; + module_inst->module->aux_stack_size; if (stack_bottom != 0 && total_aux_stack_size != 0) { if (start_offset) diff --git a/core/iwasm/interpreter/wasm_runtime.h b/core/iwasm/interpreter/wasm_runtime.h index fcb9a1e60..2750e69c7 100644 --- a/core/iwasm/interpreter/wasm_runtime.h +++ b/core/iwasm/interpreter/wasm_runtime.h @@ -33,19 +33,13 @@ typedef struct WASMMemoryInstance { /* Maximum page count */ uint32 max_page_count; - /* Heap base offset of wasm app */ - int32 heap_base_offset; /* Heap data base address */ uint8 *heap_data; + /* Heap data end address */ + uint8 *heap_data_end; /* The heap created */ void *heap_handle; - /* Memory data */ - uint8 *memory_data; - - /* End address of memory */ - uint8 *end_addr; - #if WASM_ENABLE_MULTI_MODULE != 0 /* to indicate which module instance create it */ WASMModuleInstance *owner; @@ -56,13 +50,13 @@ typedef struct WASMMemoryInstance { korp_mutex mem_lock; #endif - /* Base address, the layout is: - heap_data + memory data - memory data init size is: num_bytes_per_page * cur_page_count + /* Memory data end address */ + uint8 *memory_data_end; + + /* Memory data begin address, the layout is: memory data + heap data Note: when memory is re-allocated, the heap data and memory data - must be copied to new memory also. - */ - uint8 base_addr[1]; + must be copied to new memory also. */ + uint8 memory_data[1]; } WASMMemoryInstance; typedef struct WASMTableInstance { @@ -188,6 +182,8 @@ typedef struct WASMModuleInstance { uint8 *global_data; WASMFunctionInstance *start_function; + WASMFunctionInstance *malloc_function; + WASMFunctionInstance *free_function; WASMModule *module; diff --git a/core/shared/platform/common/posix/posix_memmap.c b/core/shared/platform/common/posix/posix_memmap.c index 26b8d8427..0bbea2766 100644 --- a/core/shared/platform/common/posix/posix_memmap.c +++ b/core/shared/platform/common/posix/posix_memmap.c @@ -65,7 +65,7 @@ os_munmap(void *addr, size_t size) if (addr) { if (munmap(addr, request_size)) { - os_printf("os_munmap error addr:%p, size:0x%lx, errno:%d\n", + os_printf("os_munmap error addr:%p, size:0x%"PRIx64", errno:%d\n", addr, request_size, errno); } } diff --git a/core/shared/platform/darwin/platform_init.c b/core/shared/platform/darwin/platform_init.c index 76594b816..4f806083c 100644 --- a/core/shared/platform/darwin/platform_init.c +++ b/core/shared/platform/darwin/platform_init.c @@ -16,3 +16,22 @@ bh_platform_destroy() { } +int +os_printf(const char *format, ...) +{ + int ret = 0; + va_list ap; + + va_start(ap, format); + ret += vprintf(format, ap); + va_end(ap); + + return ret; +} + +int +os_vprintf(const char *format, va_list ap) +{ + return vprintf(format, ap); +} + diff --git a/core/shared/platform/darwin/platform_internal.h b/core/shared/platform/darwin/platform_internal.h index 3aab6be0f..75348df15 100644 --- a/core/shared/platform/darwin/platform_internal.h +++ b/core/shared/platform/darwin/platform_internal.h @@ -57,9 +57,6 @@ typedef pthread_mutex_t korp_mutex; typedef pthread_cond_t korp_cond; typedef pthread_t korp_thread; -#define os_printf printf -#define os_vprintf vprintf - #if WASM_DISABLE_HW_BOUND_CHECK == 0 #if defined(BUILD_TARGET_X86_64) \ || defined(BUILD_TARGET_AMD_64) \ diff --git a/core/shared/platform/linux-sgx/sgx_platform.c b/core/shared/platform/linux-sgx/sgx_platform.c index f7f5c622b..abfb99119 100644 --- a/core/shared/platform/linux-sgx/sgx_platform.c +++ b/core/shared/platform/linux-sgx/sgx_platform.c @@ -152,8 +152,8 @@ int os_mprotect(void *addr, size_t size, int prot) mprot |= SGX_PROT_EXEC; st = sgx_tprotect_rsrv_mem(addr, aligned_size, mprot); if (st != SGX_SUCCESS) - os_printf("os_mprotect(addr=0x%lx, size=%u, prot=0x%x) failed.", - addr, size, prot); + os_printf("os_mprotect(addr=0x%"PRIx64", size=%u, prot=0x%x) failed.", + (uintptr_t)addr, size, prot); return (st == SGX_SUCCESS? 0:-1); } diff --git a/core/shared/platform/linux/platform_init.c b/core/shared/platform/linux/platform_init.c index 76594b816..4f806083c 100644 --- a/core/shared/platform/linux/platform_init.c +++ b/core/shared/platform/linux/platform_init.c @@ -16,3 +16,22 @@ bh_platform_destroy() { } +int +os_printf(const char *format, ...) +{ + int ret = 0; + va_list ap; + + va_start(ap, format); + ret += vprintf(format, ap); + va_end(ap); + + return ret; +} + +int +os_vprintf(const char *format, va_list ap) +{ + return vprintf(format, ap); +} + diff --git a/core/shared/platform/linux/platform_internal.h b/core/shared/platform/linux/platform_internal.h index 1aa22ed49..7a15f85e6 100644 --- a/core/shared/platform/linux/platform_internal.h +++ b/core/shared/platform/linux/platform_internal.h @@ -56,9 +56,6 @@ typedef pthread_mutex_t korp_mutex; typedef pthread_cond_t korp_cond; typedef pthread_t korp_thread; -#define os_printf printf -#define os_vprintf vprintf - #if WASM_DISABLE_HW_BOUND_CHECK == 0 #if defined(BUILD_TARGET_X86_64) \ || defined(BUILD_TARGET_AMD_64) \ diff --git a/core/shared/platform/vxworks/platform_init.c b/core/shared/platform/vxworks/platform_init.c index 76594b816..4f806083c 100644 --- a/core/shared/platform/vxworks/platform_init.c +++ b/core/shared/platform/vxworks/platform_init.c @@ -16,3 +16,22 @@ bh_platform_destroy() { } +int +os_printf(const char *format, ...) +{ + int ret = 0; + va_list ap; + + va_start(ap, format); + ret += vprintf(format, ap); + va_end(ap); + + return ret; +} + +int +os_vprintf(const char *format, va_list ap) +{ + return vprintf(format, ap); +} + diff --git a/core/shared/platform/vxworks/platform_internal.h b/core/shared/platform/vxworks/platform_internal.h index 701ab644d..a8479361e 100644 --- a/core/shared/platform/vxworks/platform_internal.h +++ b/core/shared/platform/vxworks/platform_internal.h @@ -55,9 +55,6 @@ typedef pthread_mutex_t korp_mutex; typedef pthread_cond_t korp_cond; typedef pthread_t korp_thread; -#define os_printf printf -#define os_vprintf vprintf - #if WASM_DISABLE_HW_BOUND_CHECK == 0 #if defined(BUILD_TARGET_X86_64) \ || defined(BUILD_TARGET_AMD_64) \ diff --git a/core/shared/utils/bh_log.h b/core/shared/utils/bh_log.h index 8f7a179d1..6a5ead46b 100644 --- a/core/shared/utils/bh_log.h +++ b/core/shared/utils/bh_log.h @@ -54,7 +54,7 @@ bh_log(LogLevel log_level, const char *file, int line, const char *fmt, ...); #if BH_DEBUG == 1 #define LOG_DEBUG(...) bh_log(BH_LOG_LEVEL_DEBUG, __FILE__, __LINE__, __VA_ARGS__) #else -#define LOG_DEBUG(...) /* do nothing */ +#define LOG_DEBUG(...) (void)0 #endif void diff --git a/samples/wasm-c-api/src/callback.c b/samples/wasm-c-api/src/callback.c index df2e65592..da3e7491e 100644 --- a/samples/wasm-c-api/src/callback.c +++ b/samples/wasm-c-api/src/callback.c @@ -68,7 +68,11 @@ int main(int argc, const char* argv[]) { // Load binary. printf("Loading binary...\n"); +#if WASM_ENABLE_AOT != 0 && WASM_ENABLE_INTERP == 0 + FILE* file = fopen("callback.aot", "rb"); +#else FILE* file = fopen("callback.wasm", "rb"); +#endif if (!file) { printf("> Error loading module!\n"); return 1; From 0103f6429cdf31d411d2d7b05fbd292c8e08bb76 Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Fri, 21 Aug 2020 15:11:31 +0800 Subject: [PATCH 058/207] Refactor error/exception strings to reduce binary size (#359) --- core/iwasm/aot/aot_loader.c | 166 ++++----- core/iwasm/aot/aot_runtime.c | 38 +- core/iwasm/common/wasm_runtime_common.c | 59 ++- core/iwasm/common/wasm_runtime_common.h | 4 - core/iwasm/compilation/aot_emit_memory.c | 41 --- core/iwasm/interpreter/wasm_interp_classic.c | 39 +- core/iwasm/interpreter/wasm_interp_fast.c | 31 +- core/iwasm/interpreter/wasm_loader.c | 358 ++++++++----------- core/iwasm/interpreter/wasm_mini_loader.c | 37 +- core/iwasm/interpreter/wasm_runtime.c | 53 ++- 10 files changed, 321 insertions(+), 505 deletions(-) diff --git a/core/iwasm/aot/aot_loader.c b/core/iwasm/aot/aot_loader.c index 312f8c3db..a17cce012 100644 --- a/core/iwasm/aot/aot_loader.c +++ b/core/iwasm/aot/aot_loader.c @@ -19,8 +19,26 @@ static void set_error_buf(char *error_buf, uint32 error_buf_size, const char *string) { - if (error_buf != NULL) - snprintf(error_buf, error_buf_size, "%s", string); + if (error_buf != NULL) { + snprintf(error_buf, error_buf_size, + "AOT module load failed: %s", string); + } +} + +static void +set_error_buf_v(char *error_buf, uint32 error_buf_size, + const char *format, ...) +{ + va_list args; + char buf[128]; + + if (error_buf != NULL) { + va_start(args, format); + vsnprintf(buf, sizeof(buf), format, args); + va_end(args); + snprintf(error_buf, error_buf_size, + "AOT module load failed: %s", buf); + } } #define exchange_uint8(p_data) (void)0 @@ -64,8 +82,7 @@ check_buf(const uint8 *buf, const uint8 *buf_end, uint32 length, char *error_buf, uint32 error_buf_size) { if (buf + length > buf_end) { - set_error_buf(error_buf, error_buf_size, - "AOT module load failed: unexpect end."); + set_error_buf(error_buf, error_buf_size, "unexpect end"); return false; } return true; @@ -169,8 +186,7 @@ loader_malloc(uint64 size, char *error_buf, uint32 error_buf_size) if (size >= UINT32_MAX || !(mem = wasm_runtime_malloc((uint32)size))) { set_error_buf(error_buf, error_buf_size, - "AOT module load failed: " - "allocate memory failed."); + "allocate memory failed"); return NULL; } @@ -200,8 +216,7 @@ const_str_set_insert(const uint8 *str, int32 len, AOTModule *module, if (!bh_hash_map_insert(set, c_str, c_str)) { set_error_buf(error_buf, error_buf_size, - "AOT module load failed: " - "insert string to hash map failed."); + "insert string to hash map failed"); wasm_runtime_free(c_str); return NULL; } @@ -233,18 +248,15 @@ get_aot_file_target(AOTTargetInfo *target_info, machine_type = "xtensa"; break; default: - if (error_buf) - snprintf(error_buf, error_buf_size, - "AOT module load failed: unknown machine type %d.", - target_info->e_machine); + set_error_buf_v(error_buf, error_buf_size, + "unknown machine type %d", + target_info->e_machine); return false; } if (strncmp(target_info->arch, machine_type, strlen(machine_type))) { - if (error_buf) - snprintf(error_buf, error_buf_size, - "AOT module load failed: " - "machine type (%s) isn't consistent with target type (%s).", - machine_type, target_info->arch); + set_error_buf_v(error_buf, error_buf_size, + "machine type (%s) isn't consistent with target type (%s)", + machine_type, target_info->arch); return false; } snprintf(target_buf, target_buf_size, "%s", target_info->arch); @@ -264,12 +276,9 @@ check_machine_info(AOTTargetInfo *target_info, return false; if (strcmp(target_expected, target_got)) { - if (error_buf) { - snprintf(error_buf, error_buf_size, - "AOT module load failed: invalid target type, " - "expected %s but got %s.", - target_expected, target_got); - } + set_error_buf_v(error_buf, error_buf_size, + "invalid target type, expected %s but got %s", + target_expected, target_got); return false; } @@ -297,39 +306,35 @@ load_target_info_section(const uint8 *buf, const uint8 *buf_end, if (p != buf_end) { set_error_buf(error_buf, error_buf_size, - "AOT module load failed: invalid section size."); + "invalid section size"); return false; } /* Check target endian type */ is_target_little_endian = target_info.bin_type & 1 ? false : true; if (is_little_endian() != is_target_little_endian) { - if (error_buf) - snprintf(error_buf, error_buf_size, - "AOT module load failed: " - "invalid target endian type, expected %s but got %s.", - is_little_endian() ? "little endian" : "big endian", - is_target_little_endian ? "little endian" : "big endian"); + set_error_buf_v(error_buf, error_buf_size, + "invalid target endian type, expected %s but got %s", + is_little_endian() ? "little endian" : "big endian", + is_target_little_endian ? "little endian" : "big endian"); return false; } /* Check target bit width */ is_target_64_bit = target_info.bin_type & 2 ? true : false; if ((sizeof(void*) == 8 ? true : false) != is_target_64_bit) { - if (error_buf) - snprintf(error_buf, error_buf_size, - "AOT module load failed: " - "invalid target bit width, expected %s but got %s.", - sizeof(void*) == 8 ? "64-bit" : "32-bit", - is_target_64_bit ? "64-bit" : "32-bit"); + set_error_buf_v(error_buf, error_buf_size, + "invalid target bit width, expected %s but got %s", + sizeof(void*) == 8 ? "64-bit" : "32-bit", + is_target_64_bit ? "64-bit" : "32-bit"); return false; } /* Check target elf file type */ if (target_info.e_type != E_TYPE_REL) { set_error_buf(error_buf, error_buf_size, - "AOT module load failed: invalid object file type, " - "expected relocatable file type but got others."); + "invalid object file type, " + "expected relocatable file type but got others"); return false; } @@ -340,7 +345,7 @@ load_target_info_section(const uint8 *buf, const uint8 *buf_end, if (target_info.e_version != E_VERSION_CURRENT) { set_error_buf(error_buf, error_buf_size, - "AOT module load failed: invalid elf file version."); + "invalid elf file version"); return false; } @@ -639,7 +644,6 @@ load_func_types(const uint8 **p_buf, const uint8 *buf_end, if (param_count > UINT16_MAX || result_count > UINT16_MAX) { set_error_buf(error_buf, error_buf_size, - "AOT module load failed: " "param count or result count too large"); return false; } @@ -660,7 +664,6 @@ load_func_types(const uint8 **p_buf, const uint8 *buf_end, result_count); if (param_cell_num > UINT16_MAX || ret_cell_num > UINT16_MAX) { set_error_buf(error_buf, error_buf_size, - "AOT module load failed: " "param count or result count too large"); return false; } @@ -866,8 +869,7 @@ load_import_funcs(const uint8 **p_buf, const uint8 *buf_end, for (i = 0; i < module->import_func_count; i++) { read_uint16(buf, buf_end, import_funcs[i].func_type_index); if (import_funcs[i].func_type_index >= module->func_type_count) { - set_error_buf(error_buf, error_buf_size, - "AOT module load failed: unknown type."); + set_error_buf(error_buf, error_buf_size, "unknown type"); return false; } import_funcs[i].func_type = module->func_types[import_funcs[i].func_type_index]; @@ -967,8 +969,7 @@ load_object_data_sections(const uint8 **p_buf, const uint8 *buf_end, if (!(data_sections[i].data = os_mmap(NULL, data_sections[i].size, map_prot, map_flags))) { set_error_buf(error_buf, error_buf_size, - "AOT module load failed: " - "allocate memory failed."); + "allocate memory failed"); return false; } #if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64) @@ -1034,7 +1035,6 @@ load_init_data_section(const uint8 *buf, const uint8 *buf_end, && (module->start_func_index >= module->import_func_count + module->func_count)) { set_error_buf(error_buf, error_buf_size, - "AOT module load failed: " "invalid start function index"); return false; } @@ -1053,7 +1053,6 @@ load_init_data_section(const uint8 *buf, const uint8 *buf_end, if (p != p_end) { set_error_buf(error_buf, error_buf_size, - "AOT module load failed: " "invalid init data section size"); return false; } @@ -1073,7 +1072,7 @@ load_text_section(const uint8 *buf, const uint8 *buf_end, if (module->func_count > 0 && buf_end == buf) { set_error_buf(error_buf, error_buf_size, - "AOT module load failed: invalid code size."); + "invalid code size"); return false; } @@ -1120,8 +1119,7 @@ load_function_section(const uint8 *buf, const uint8 *buf_end, } if (text_offset >= module->code_size) { set_error_buf(error_buf, error_buf_size, - "AOT module load failed: " - "invalid function code offset."); + "invalid function code offset"); return false; } module->func_ptrs[i] = (uint8*)module->code + text_offset; @@ -1154,15 +1152,13 @@ load_function_section(const uint8 *buf, const uint8 *buf_end, for (i = 0; i < module->func_count; i++) { read_uint32(p, p_end, module->func_type_indexes[i]); if (module->func_type_indexes[i] >= module->func_type_count) { - set_error_buf(error_buf, error_buf_size, - "AOT module load failed: unknown type."); + set_error_buf(error_buf, error_buf_size, "unknown type"); return false; } } if (p != buf_end) { set_error_buf(error_buf, error_buf_size, - "AOT module load failed: " "invalid function section size"); return false; } @@ -1204,8 +1200,7 @@ load_exports(const uint8 **p_buf, const uint8 *buf_end, if (export_funcs[i].index >= module->func_count + module->import_func_count) { set_error_buf(error_buf, error_buf_size, - "AOT module load failed: " - "function index is out of range."); + "function index is out of range"); return false; } #endif @@ -1232,7 +1227,6 @@ load_export_section(const uint8 *buf, const uint8 *buf_end, if (p != p_end) { set_error_buf(error_buf, error_buf_size, - "AOT module load failed: " "invalid export section size"); return false; } @@ -1299,7 +1293,7 @@ do_text_relocation(AOTModule *module, if (group->relocation_count > 0 && !aot_text) { set_error_buf(error_buf, error_buf_size, - "AOT module load failed: invalid text relocation count."); + "invalid text relocation count"); return false; } @@ -1321,11 +1315,8 @@ do_text_relocation(AOTModule *module, p = symbol + strlen(AOT_FUNC_PREFIX); if (*p == '\0' || (func_index = (uint32)atoi(p)) > module->func_count) { - if (error_buf != NULL) - snprintf(error_buf, error_buf_size, - "AOT module load failed: " - "invalid import symbol %s.", - symbol); + set_error_buf_v(error_buf, error_buf_size, + "invalid import symbol %s", symbol); goto check_symbol_fail; } symbol_addr = module->func_ptrs[func_index]; @@ -1339,11 +1330,8 @@ do_text_relocation(AOTModule *module, || !strncmp(symbol, ".rodata.cst", strlen(".rodata.cst"))) { symbol_addr = get_data_section_addr(module, symbol, NULL); if (!symbol_addr) { - if (error_buf != NULL) - snprintf(error_buf, error_buf_size, - "AOT module load failed: " - "invalid data section (%s).", - symbol); + set_error_buf_v(error_buf, error_buf_size, + "invalid data section (%s)", symbol); goto check_symbol_fail; } } @@ -1351,11 +1339,8 @@ do_text_relocation(AOTModule *module, symbol_addr = module->literal; } else if (!(symbol_addr = resolve_target_sym(symbol, &symbol_index))) { - if (error_buf != NULL) - snprintf(error_buf, error_buf_size, - "AOT module load failed: " - "resolve symbol %s failed.", - symbol); + set_error_buf_v(error_buf, error_buf_size, + "resolve symbol %s failed", symbol); goto check_symbol_fail; } @@ -1400,8 +1385,7 @@ do_data_relocation(AOTModule *module, } else { set_error_buf(error_buf, error_buf_size, - "AOT module load failed: " - "invalid data relocation section name."); + "invalid data relocation section name"); return false; } @@ -1409,7 +1393,7 @@ do_data_relocation(AOTModule *module, &data_size); if (group->relocation_count > 0 && !data_addr) { set_error_buf(error_buf, error_buf_size, - "AOT module load failed: invalid data relocation count."); + "invalid data relocation count"); return false; } @@ -1419,11 +1403,8 @@ do_data_relocation(AOTModule *module, symbol_addr = module->code; } else { - if (error_buf != NULL) - snprintf(error_buf, error_buf_size, - "AOT module load failed: " - "invalid relocation symbol %s.", - symbol); + set_error_buf_v(error_buf, error_buf_size, + "invalid relocation symbol %s", symbol); return false; } @@ -1494,8 +1475,7 @@ load_relocation_section(const uint8 *buf, const uint8 *buf_end, symbol_offsets, symbol_count, error_buf, error_buf_size)) { set_error_buf(error_buf, error_buf_size, - "AOT module load failed: " - "validate symbol table failed."); + "validate symbol table failed"); goto fail; } @@ -1521,8 +1501,7 @@ load_relocation_section(const uint8 *buf, const uint8 *buf_end, if (name_index >= symbol_count) { set_error_buf(error_buf, error_buf_size, - "AOT module load failed: " - "symbol index out of range."); + "symbol index out of range"); goto fail; } @@ -1568,8 +1547,7 @@ load_relocation_section(const uint8 *buf, const uint8 *buf_end, if (symbol_index >= symbol_count) { set_error_buf(error_buf, error_buf_size, - "AOT module load failed: " - "symbol index out of range."); + "symbol index out of range"); goto fail; } @@ -1630,7 +1608,7 @@ load_from_sections(AOTModule *module, AOTSection *sections, || (last_section_type != (uint32)-1 && section_type != last_section_type + 1)) { set_error_buf(error_buf, error_buf_size, - "AOT module load failed: invalid section order."); + "invalid section order"); return false; } last_section_type = section_type; @@ -1672,7 +1650,7 @@ load_from_sections(AOTModule *module, AOTSection *sections, if (last_section_type != AOT_SECTION_TYPE_RELOCATION) { set_error_buf(error_buf, error_buf_size, - "AOT module load failed: section missing."); + "section missing"); return false; } @@ -1747,8 +1725,7 @@ create_module(char *error_buf, uint32 error_buf_size) NULL, aot_free))) { set_error_buf(error_buf, error_buf_size, - "AOT module load failed: " - "create const string set failed."); + "create const string set failed"); wasm_runtime_free(module); return NULL; } @@ -1838,8 +1815,7 @@ create_sections(const uint8 *buf, uint32 size, map_prot, map_flags))) { wasm_runtime_free(section); set_error_buf(error_buf, error_buf_size, - "AOT module load failed: " - "mmap memory failed."); + "mmap memory failed"); goto fail; } #if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64) @@ -1874,14 +1850,14 @@ create_sections(const uint8 *buf, uint32 size, } else { set_error_buf(error_buf, error_buf_size, - "AOT module load failed: invalid section id."); + "invalid section id"); goto fail; } } if (!section_list) { set_error_buf(error_buf, error_buf_size, - "AOT module load failed: create section list failed."); + "create section list failed"); return false; } @@ -2032,7 +2008,7 @@ aot_load_from_comp_data(AOTCompData *comp_data, AOTCompContext *comp_ctx, (void *)LLVMGetFunctionAddress(comp_ctx->exec_engine, func_name))) { set_error_buf(error_buf, error_buf_size, - "Get function address fail."); + "get function address failed"); goto fail3; } } diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index 79235d61f..4081c673c 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -13,8 +13,10 @@ static void set_error_buf(char *error_buf, uint32 error_buf_size, const char *string) { - if (error_buf != NULL) - snprintf(error_buf, error_buf_size, "%s", string); + if (error_buf != NULL) { + snprintf(error_buf, error_buf_size, + "AOT module instantiate failed: %s", string); + } } static void * @@ -25,8 +27,7 @@ runtime_malloc(uint64 size, char *error_buf, uint32 error_buf_size) if (size >= UINT32_MAX || !(mem = wasm_runtime_malloc((uint32)size))) { set_error_buf(error_buf, error_buf_size, - "AOT module instantiate failed: " - "allocate memory failed."); + "allocate memory failed"); return NULL; } @@ -60,8 +61,7 @@ global_instantiate(AOTModuleInstance *module_inst, AOTModule *module, switch (init_expr->init_expr_type) { case INIT_EXPR_TYPE_GET_GLOBAL: if (init_expr->u.global_index >= module->import_global_count + i) { - set_error_buf(error_buf, error_buf_size, - "Instantiate global failed: unknown global."); + set_error_buf(error_buf, error_buf_size, "unknown global"); return false; } memcpy(p, @@ -333,14 +333,12 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModule *module, if (total_size >= UINT32_MAX || !(p = mapped_mem = os_mmap(NULL, map_size, MMAP_PROT_NONE, MMAP_MAP_NONE))) { - set_error_buf(error_buf, error_buf_size, - "AOT module instantiate failed: mmap memory failed."); + set_error_buf(error_buf, error_buf_size, "mmap memory failed"); return NULL; } if (os_mprotect(p, total_size, MMAP_PROT_READ | MMAP_PROT_WRITE) != 0) { - set_error_buf(error_buf, error_buf_size, - "AOT module instantiate failed: mprotec memory failed."); + set_error_buf(error_buf, error_buf_size, "mprotec memory failed"); os_munmap(mapped_mem, map_size); return NULL; } @@ -364,8 +362,7 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModule *module, if (!(heap_handle = mem_allocator_create(memory_inst->heap_data.ptr, heap_size))) { set_error_buf(error_buf, error_buf_size, - "AOT module instantiate failed:" - "init app heap failed."); + "init app heap failed"); goto fail1; } memory_inst->heap_handle.ptr = heap_handle; @@ -392,8 +389,7 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModule *module, if (!shared_memory_set_memory_inst((WASMModuleCommon *)module, (WASMMemoryInstanceCommon *)memory_inst)) { set_error_buf(error_buf, error_buf_size, - "Instantiate memory failed:" - "allocate memory failed."); + "allocate memory failed"); goto fail2; } } @@ -659,7 +655,7 @@ execute_start_function(AOTModuleInstance *module_inst) if (!(exec_env = wasm_exec_env_create((WASMModuleInstanceCommon*)module_inst, module_inst->default_wasm_stack_size))) { - aot_set_exception(module_inst, "allocate memory failed."); + aot_set_exception(module_inst, "allocate memory failed"); return false; } @@ -988,7 +984,7 @@ invoke_native_with_hw_bound_check(WASMExecEnv *exec_env, void *func_ptr, if (aot_exec_env && (aot_exec_env != exec_env)) { - aot_set_exception(module_inst, "Invalid exec env."); + aot_set_exception(module_inst, "invalid exec env"); return false; } @@ -999,7 +995,7 @@ invoke_native_with_hw_bound_check(WASMExecEnv *exec_env, void *func_ptr, /* First time to call aot function, protect one page */ if (os_mprotect(stack_min_addr, page_size * guard_page_count, MMAP_PROT_NONE) != 0) { - aot_set_exception(module_inst, "Set protected page failed."); + aot_set_exception(module_inst, "set protected page failed"); return false; } } @@ -1132,7 +1128,7 @@ aot_create_exec_env_and_call_function(AOTModuleInstance *module_inst, if (!(exec_env = wasm_exec_env_create((WASMModuleInstanceCommon*)module_inst, module_inst->default_wasm_stack_size))) { - aot_set_exception(module_inst, "allocate memory failed."); + aot_set_exception(module_inst, "allocate memory failed"); return false; } @@ -1471,12 +1467,10 @@ aot_enlarge_memory(AOTModuleInstance *module_inst, uint32 inc_page_count) if (total_page_count < cur_page_count /* integer overflow */ || total_page_count > max_page_count) { - aot_set_exception(module_inst, "fail to enlarge memory."); return false; } if (total_size >= UINT32_MAX) { - aot_set_exception(module_inst, "fail to enlarge memory."); return false; } @@ -1501,7 +1495,6 @@ aot_enlarge_memory(AOTModuleInstance *module_inst, uint32 inc_page_count) /* Restore heap's lock if memory re-alloc failed */ mem_allocator_reinit_lock(memory_inst->heap_handle.ptr); } - aot_set_exception(module_inst, "fail to enlarge memory."); return false; } bh_memcpy_s(memory_data, (uint32)total_size, @@ -1522,7 +1515,6 @@ aot_enlarge_memory(AOTModuleInstance *module_inst, uint32 inc_page_count) + (memory_data - memory_data_old); if (mem_allocator_migrate(memory_inst->heap_handle.ptr, heap_handle_old) != 0) { - aot_set_exception(module_inst, "fail to enlarge memory."); return false; } } @@ -1562,14 +1554,12 @@ aot_enlarge_memory(AOTModuleInstance *module_inst, uint32 inc_page_count) if (total_page_count < cur_page_count /* integer overflow */ || total_page_count > max_page_count) { - aot_set_exception(module_inst, "fail to enlarge memory."); return false; } if (os_mprotect(memory_inst->memory_data_end.ptr, num_bytes_per_page * inc_page_count, MMAP_PROT_READ | MMAP_PROT_WRITE) != 0) { - aot_set_exception(module_inst, "fail to enlarge memory."); return false; } diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index e1fdbd130..20e97f301 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -49,16 +49,6 @@ static void wasm_runtime_destroy_registered_module_list(); #endif /* WASM_ENABLE_MULTI_MODULE */ -void -set_error_buf_v(char *error_buf, uint32 error_buf_size, const char *format, - ...) -{ - va_list args; - va_start(args, format); - vsnprintf(error_buf, error_buf_size, format, args); - va_end(args); -} - static void set_error_buf(char *error_buf, uint32 error_buf_size, const char *string) { @@ -76,11 +66,11 @@ runtime_malloc(uint64 size, WASMModuleInstanceCommon *module_inst, || !(mem = wasm_runtime_malloc((uint32)size))) { if (module_inst != NULL) { wasm_runtime_set_exception(module_inst, - "allocate memory failed."); + "allocate memory failed"); } else if (error_buf != NULL) { set_error_buf(error_buf, error_buf_size, - "allocate memory failed."); + "allocate memory failed"); } return NULL; } @@ -308,8 +298,9 @@ wasm_runtime_register_module_internal(const char *module_name, /* module has different name */ LOG_DEBUG("module(%p) has been registered with name %s", module, node->module_name); - set_error_buf_v(error_buf, error_buf_size, - "can not rename the module"); + set_error_buf(error_buf, error_buf_size, + "Register module failed: " + "failed to rename the module"); return false; } else { @@ -359,14 +350,16 @@ wasm_runtime_register_module(const char *module_name, WASMModuleCommon *module, if (!module_name || !module) { LOG_DEBUG("module_name and module are required"); - set_error_buf_v(error_buf, error_buf_size, - "module_name and module are required"); + set_error_buf(error_buf, error_buf_size, + "Register module failed: " + "module_name and module are required"); return false; } if (wasm_runtime_is_built_in_module(module_name)) { LOG_DEBUG("%s is a built-in module name", module_name); set_error_buf(error_buf, error_buf_size, + "Register module failed: " "can not register as a built-in module"); return false; } @@ -1325,7 +1318,7 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, (module_inst, (uint32)argv_buf_len, (void**)&argv_buf))) { set_error_buf(error_buf, error_buf_size, - "Init wasi environment failed: allocate memory failed."); + "Init wasi environment failed: allocate memory failed"); goto fail; } @@ -1349,7 +1342,7 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, (module_inst, (uint32)env_buf_len, (void**)&env_buf))) { set_error_buf(error_buf, error_buf_size, - "Init wasi environment failed: allocate memory failed."); + "Init wasi environment failed: allocate memory failed"); goto fail; } @@ -1368,7 +1361,7 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, (module_inst, sizeof(struct argv_environ_values), (void**)&argv_environ))) { set_error_buf(error_buf, error_buf_size, - "Init wasi environment failed: allocate memory failed."); + "Init wasi environment failed: allocate memory failed"); goto fail; } @@ -1383,7 +1376,7 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, if (!fd_table_init(curfds)) { set_error_buf(error_buf, error_buf_size, "Init wasi environment failed: " - "init fd table failed."); + "init fd table failed"); goto fail; } fd_table_inited = true; @@ -1391,7 +1384,7 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, if (!fd_prestats_init(prestats)) { set_error_buf(error_buf, error_buf_size, "Init wasi environment failed: " - "init fd prestats failed."); + "init fd prestats failed"); goto fail; } fd_prestats_inited = true; @@ -1403,7 +1396,7 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, env_buf, env_buf_len)) { set_error_buf(error_buf, error_buf_size, "Init wasi environment failed: " - "init argument environment failed."); + "init argument environment failed"); goto fail; } argv_environ_inited = true; @@ -1413,7 +1406,7 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, || !fd_table_insert_existing(curfds, 1, 1) || !fd_table_insert_existing(curfds, 2, 2)) { set_error_buf(error_buf, error_buf_size, - "Init wasi environment failed: init fd table failed."); + "Init wasi environment failed: init fd table failed"); goto fail; } @@ -1689,7 +1682,7 @@ wasm_application_execute_main(WASMModuleInstanceCommon *module_inst, if (!func) { wasm_runtime_set_exception(module_inst, - "lookup main function failed."); + "lookup main function failed"); return false; } @@ -1697,7 +1690,7 @@ wasm_application_execute_main(WASMModuleInstanceCommon *module_inst, if (module_inst->module_type == Wasm_Module_Bytecode) { if (((WASMFunctionInstance*)func)->is_import_func) { wasm_runtime_set_exception(module_inst, - "lookup main function failed."); + "lookup main function failed"); return false; } func_type = ((WASMFunctionInstance*)func)->u.func->func_type; @@ -1710,7 +1703,7 @@ wasm_application_execute_main(WASMModuleInstanceCommon *module_inst, if (!check_main_func_type(func_type)) { wasm_runtime_set_exception(module_inst, - "invalid function type of main function."); + "invalid function type of main function"); return false; } @@ -1726,7 +1719,7 @@ wasm_application_execute_main(WASMModuleInstanceCommon *module_inst, wasm_runtime_module_malloc(module_inst, (uint32)total_size, (void**)&argv_buf))) { wasm_runtime_set_exception(module_inst, - "allocate memory failed."); + "allocate memory failed"); return false; } @@ -1942,7 +1935,7 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, func = resolve_function(module_inst, name); if (!func) { - snprintf(buf, sizeof(buf), "lookup function %s failed.", name); + snprintf(buf, sizeof(buf), "lookup function %s failed", name); wasm_runtime_set_exception(module_inst, buf); goto fail; } @@ -1955,7 +1948,7 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, && !wasm_func->import_func_inst #endif ) { - snprintf(buf, sizeof(buf), "lookup function %s failed.", name); + snprintf(buf, sizeof(buf), "lookup function %s failed", name); wasm_runtime_set_exception(module_inst, buf); goto fail; } @@ -1976,7 +1969,7 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, if (type->param_count != (uint32)argc) { wasm_runtime_set_exception(module_inst, - "invalid input argument count."); + "invalid input argument count"); goto fail; } @@ -1994,7 +1987,7 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, char *endptr = NULL; bh_assert(argv[i] != NULL); if (argv[i][0] == '\0') { - snprintf(buf, sizeof(buf), "invalid input argument %d.", i); + snprintf(buf, sizeof(buf), "invalid input argument %d", i); wasm_runtime_set_exception(module_inst, buf); goto fail; } @@ -2074,14 +2067,14 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, } } if (endptr && *endptr != '\0' && *endptr != '_') { - snprintf(buf, sizeof(buf), "invalid input argument %d: %s.", + snprintf(buf, sizeof(buf), "invalid input argument %d: %s", i, argv[i]); wasm_runtime_set_exception(module_inst, buf); goto fail; } if (errno != 0) { snprintf(buf, sizeof(buf), - "prepare function argument error, errno: %d.", errno); + "prepare function argument error, errno: %d", errno); wasm_runtime_set_exception(module_inst, buf); goto fail; } diff --git a/core/iwasm/common/wasm_runtime_common.h b/core/iwasm/common/wasm_runtime_common.h index d8590a974..8d6767de5 100644 --- a/core/iwasm/common/wasm_runtime_common.h +++ b/core/iwasm/common/wasm_runtime_common.h @@ -79,10 +79,6 @@ typedef struct WASMMemoryInstanceCommon { typedef package_type_t PackageType; typedef wasm_section_t WASMSection, AOTSection; -void -set_error_buf_v(char *error_buf, uint32 error_buf_size, const char *format, - ...); - /* See wasm_export.h for description */ bool wasm_runtime_init(void); diff --git a/core/iwasm/compilation/aot_emit_memory.c b/core/iwasm/compilation/aot_emit_memory.c index 771513946..68ed1ef7e 100644 --- a/core/iwasm/compilation/aot_emit_memory.c +++ b/core/iwasm/compilation/aot_emit_memory.c @@ -700,47 +700,6 @@ aot_compile_op_memory_grow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) } PUSH_I32(ret_value); - - /* To be simple, call wasm_runtime_set_exception() no matter - enlarge success or not */ - param_types[1] = INT8_PTR_TYPE; - ret_type = VOID_TYPE; - if (!(func_type = LLVMFunctionType(ret_type, param_types, 2, 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)wasm_runtime_set_exception)) - || !(func = LLVMConstIntToPtr(value, func_ptr_type))) { - aot_set_last_error("create LLVM value failed."); - return false; - } - } - else { - char *func_name = "wasm_runtime_set_exception"; - /* 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; - } - } - - /* Call function wasm_runtime_set_exception(aot_inst, NULL) */ - param_values[1] = LLVMConstNull(INT8_PTR_TYPE); - CHECK_LLVM_CONST(param_values[1]); - if (!(LLVMBuildCall(comp_ctx->builder, func, param_values, 2, ""))) { - aot_set_last_error("llvm build call failed."); - return false; - } - return true; fail: return false; diff --git a/core/iwasm/interpreter/wasm_interp_classic.c b/core/iwasm/interpreter/wasm_interp_classic.c index ab37459f0..ec9a10237 100644 --- a/core/iwasm/interpreter/wasm_interp_classic.c +++ b/core/iwasm/interpreter/wasm_interp_classic.c @@ -903,7 +903,7 @@ ALLOC_FRAME(WASMExecEnv *exec_env, uint32 size, WASMInterpFrame *prev_frame) frame->prev_frame = prev_frame; else { wasm_set_exception((WASMModuleInstance*)exec_env->module_inst, - "WASM interp failed: stack overflow."); + "stack overflow"); } return frame; @@ -1244,8 +1244,7 @@ label_pop_csp_n: uint64 total_size = sizeof(uint32) * (uint64)count; if (total_size >= UINT32_MAX || !(depths = wasm_runtime_malloc((uint32)total_size))) { - wasm_set_exception(module, - "WASM interp failed: allocate memory failed."); + wasm_set_exception(module, "allocate memory failed"); goto got_exception; } } @@ -1303,7 +1302,7 @@ label_pop_csp_n: */ read_leb_uint32(frame_ip, frame_ip_end, tidx); if (tidx >= module->module->type_count) { - wasm_set_exception(module, "type index is overflow"); + wasm_set_exception(module, "unknown type"); goto got_exception; } cur_type = wasm_types[tidx]; @@ -1839,10 +1838,6 @@ label_pop_csp_n: if (!wasm_enlarge_memory(module, delta)) { /* fail to memory.grow, return -1 */ PUSH_I32(-1); - if (wasm_get_exception(module)) { - os_printf("%s\n", wasm_get_exception(module)); - wasm_set_exception(module, NULL); - } } else { /* success, return previous page count */ @@ -2762,7 +2757,7 @@ label_pop_csp_n: } #endif /* WASM_ENABLE_BULK_MEMORY */ default: - wasm_set_exception(module, "WASM interp failed: unsupported opcode."); + wasm_set_exception(module, "unsupported opcode"); goto got_exception; break; } @@ -3107,7 +3102,7 @@ label_pop_csp_n: #if WASM_ENABLE_LABELS_AS_VALUES == 0 default: - wasm_set_exception(module, "WASM interp failed: unsupported opcode."); + wasm_set_exception(module, "unsupported opcode"); goto got_exception; } #endif @@ -3137,7 +3132,7 @@ label_pop_csp_n: HANDLE_OP (EXT_OP_COPY_STACK_TOP_I64): HANDLE_OP (EXT_OP_COPY_STACK_VALUES): { - wasm_set_exception(module, "WASM interp failed: unsupported opcode."); + wasm_set_exception(module, "unsupported opcode"); goto got_exception; } #endif @@ -3192,7 +3187,7 @@ label_pop_csp_n: + (uint64)cur_wasm_func->max_stack_cell_num + ((uint64)cur_wasm_func->max_block_num) * sizeof(WASMBranchBlock) / 4; if (all_cell_num >= UINT32_MAX) { - wasm_set_exception(module, "WASM interp failed: stack overflow."); + wasm_set_exception(module, "stack overflow"); goto got_exception; } @@ -3288,7 +3283,7 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, if ((uint8*)&prev_frame < exec_env->native_stack_boundary) { wasm_set_exception((WASMModuleInstance*)exec_env->module_inst, - "WASM interp failed: native stack overflow."); + "native stack overflow"); return; } @@ -3310,20 +3305,16 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, #if WASM_ENABLE_MULTI_MODULE != 0 if (function->import_module_inst) { LOG_DEBUG("it is a function of a sub module"); - wasm_interp_call_func_import(module_inst, - exec_env, - function, - frame); + wasm_interp_call_func_import(module_inst, exec_env, + function, frame); } else #endif { LOG_DEBUG("it is an native function"); /* it is a native function */ - wasm_interp_call_func_native(module_inst, - exec_env, - function, - frame); + wasm_interp_call_func_native(module_inst, exec_env, + function, frame); } } else { @@ -3339,10 +3330,12 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, if (function->ret_cell_num) { LOG_DEBUG("first return value argv[0]=%d", argv[0]); - } else { + } + else { LOG_DEBUG("no return value"); } - } else { + } + else { LOG_DEBUG("meet an exception %s", wasm_get_exception(module_inst)); } diff --git a/core/iwasm/interpreter/wasm_interp_fast.c b/core/iwasm/interpreter/wasm_interp_fast.c index ce39dc3b4..2a19d8aea 100644 --- a/core/iwasm/interpreter/wasm_interp_fast.c +++ b/core/iwasm/interpreter/wasm_interp_fast.c @@ -802,8 +802,7 @@ copy_stack_values(WASMModuleInstance *module, uint64 total_size = sizeof(uint32) * (uint64)total_cell_num; if (total_size >= UINT32_MAX || !(tmp_buf = wasm_runtime_malloc((uint32)total_size))) { - wasm_set_exception(module, - "WASM interp failed: allocate memory failed."); + wasm_set_exception(module, "allocate memory failed"); return false; } } @@ -951,7 +950,7 @@ ALLOC_FRAME(WASMExecEnv *exec_env, uint32 size, WASMInterpFrame *prev_frame) frame->prev_frame = prev_frame; else { wasm_set_exception((WASMModuleInstance*)exec_env->module_inst, - "WASM interp failed: stack overflow."); + "stack overflow"); } return frame; @@ -1789,10 +1788,6 @@ recover_br_info: if (!wasm_enlarge_memory(module, delta)) { /* fail to memory.grow, return -1 */ frame_lp[addr_ret] = -1; - if (wasm_get_exception(module)) { - os_printf("%s\n", wasm_get_exception(module)); - wasm_set_exception(module, NULL); - } } else { /* success, return previous page count */ @@ -2756,7 +2751,7 @@ recover_br_info: } #endif /* WASM_ENABLE_BULK_MEMORY */ default: - wasm_set_exception(module, "WASM interp failed: unsupported opcode."); + wasm_set_exception(module, "unsupported opcode"); goto got_exception; break; } @@ -3111,7 +3106,7 @@ recover_br_info: #if WASM_ENABLE_LABELS_AS_VALUES == 0 default: - wasm_set_exception(module, "WASM interp failed: unsupported opcode."); + wasm_set_exception(module, "unsupported opcode"); goto got_exception; } #endif @@ -3155,7 +3150,7 @@ recover_br_info: HANDLE_OP (EXT_OP_LOOP): HANDLE_OP (EXT_OP_IF): { - wasm_set_exception(module, "WASM interp failed: unsupported opcode."); + wasm_set_exception(module, "unsupported opcode"); goto got_exception; } #endif @@ -3234,7 +3229,7 @@ recover_br_info: + (uint64)cur_func->const_cell_num + (uint64)cur_wasm_func->max_stack_cell_num; if (all_cell_num >= UINT32_MAX) { - wasm_set_exception(module, "WASM interp failed: stack overflow."); + wasm_set_exception(module, "stack overflow"); goto got_exception; } @@ -3336,7 +3331,7 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, if ((uint8*)&prev_frame < exec_env->native_stack_boundary) { wasm_set_exception((WASMModuleInstance*)exec_env->module_inst, - "WASM interp failed: native stack overflow."); + "native stack overflow"); return; } @@ -3359,19 +3354,15 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, #if WASM_ENABLE_MULTI_MODULE != 0 if (function->import_module_inst) { LOG_DEBUG("it is a function of a sub module"); - wasm_interp_call_func_import(module_inst, - exec_env, - function, - frame); + wasm_interp_call_func_import(module_inst, exec_env, + function, frame); } else #endif { LOG_DEBUG("it is an native function"); - wasm_interp_call_func_native(module_inst, - exec_env, - function, - frame); + wasm_interp_call_func_native(module_inst, exec_env, + function, frame); } } else { diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index f9f8d1016..7156231b9 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -20,8 +20,26 @@ static void set_error_buf(char *error_buf, uint32 error_buf_size, const char *string) { - if (error_buf != NULL) - snprintf(error_buf, error_buf_size, "%s", string); + if (error_buf != NULL) { + snprintf(error_buf, error_buf_size, + "WASM module load failed: %s", string); + } +} + +static void +set_error_buf_v(char *error_buf, uint32 error_buf_size, + const char *format, ...) +{ + va_list args; + char buf[128]; + + if (error_buf != NULL) { + va_start(args, format); + vsnprintf(buf, sizeof(buf), format, args); + va_end(args); + snprintf(error_buf, error_buf_size, + "WASM module load failed: %s", buf); + } } static bool @@ -30,7 +48,6 @@ check_buf(const uint8 *buf, const uint8 *buf_end, uint32 length, { if (buf + length > buf_end) { set_error_buf(error_buf, error_buf_size, - "WASM module load failed: " "unexpected end of section or function"); return false; } @@ -42,8 +59,7 @@ check_buf1(const uint8 *buf, const uint8 *buf_end, uint32 length, char *error_buf, uint32 error_buf_size) { if (buf + length > buf_end) { - set_error_buf(error_buf, error_buf_size, - "WASM module load failed: unexpected end"); + set_error_buf(error_buf, error_buf_size, "unexpected end"); return false; } return true; @@ -74,7 +90,6 @@ skip_leb(const uint8 **p_buf, const uint8 *buf_end, uint32 maxbits, while (true) { if (bcnt + 1 > (maxbits + 6) / 7) { set_error_buf(error_buf, error_buf_size, - "WASM module load failed: " "integer representation too long"); return false; } @@ -126,7 +141,6 @@ read_leb(uint8 **p_buf, const uint8 *buf_end, while (true) { if (bcnt + 1 > (maxbits + 6) / 7) { set_error_buf(error_buf, error_buf_size, - "WASM module load failed: " "integer representation too long"); return false; } @@ -184,8 +198,7 @@ read_leb(uint8 **p_buf, const uint8 *buf_end, return true; fail_integer_too_large: - set_error_buf(error_buf, error_buf_size, - "WASM module load failed: integer too large"); + set_error_buf(error_buf, error_buf_size, "integer too large"); fail: return false; } @@ -226,8 +239,7 @@ loader_malloc(uint64 size, char *error_buf, uint32 error_buf_size) if (size >= UINT32_MAX || !(mem = wasm_runtime_malloc((uint32)size))) { set_error_buf(error_buf, error_buf_size, - "WASM module load failed: " - "allocate memory failed."); + "allocate memory failed"); return NULL; } @@ -278,7 +290,6 @@ const_str_list_insert(const uint8 *str, uint32 len, WASMModule *module, if (!check_utf8_str(str, len)) { set_error_buf(error_buf, error_buf_size, - "WASM module load failed: " "invalid UTF-8 encoding"); return NULL; } @@ -381,8 +392,7 @@ load_init_expr(const uint8 **p_buf, const uint8 *buf_end, return true; fail_type_mismatch: set_error_buf(error_buf, error_buf_size, - "WASM module load failed: type mismatch or " - "constant expression required."); + "type mismatch or constant expression required"); fail: return false; } @@ -413,7 +423,7 @@ load_type_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, flag = read_uint8(p); if (flag != 0x60) { set_error_buf(error_buf, error_buf_size, - "Load type section failed: invalid type flag."); + "invalid type flag"); return false; } @@ -429,7 +439,6 @@ load_type_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, if (param_count > UINT16_MAX || result_count > UINT16_MAX) { set_error_buf(error_buf, error_buf_size, - "Load type section failed: " "param count or result count too large"); return false; } @@ -459,7 +468,6 @@ load_type_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, result_count); if (param_cell_num > UINT16_MAX || ret_cell_num > UINT16_MAX) { set_error_buf(error_buf, error_buf_size, - "Load type section failed: " "param count or result count too large"); return false; } @@ -469,8 +477,7 @@ load_type_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, } if (p != p_end) { - set_error_buf(error_buf, error_buf_size, - "Load type section failed: section size mismatch"); + set_error_buf(error_buf, error_buf_size, "section size mismatch"); return false; } @@ -512,8 +519,8 @@ wasm_loader_find_export(const WASMModule *module, if (i == module->export_count) { LOG_DEBUG("can not find an export %d named %s in the module %s", export_kind, field_name, module_name); - set_error_buf_v(error_buf, error_buf_size, - "unknown import or incompatible import type"); + set_error_buf(error_buf, error_buf_size, + "unknown import or incompatible import type"); return NULL; } @@ -521,7 +528,7 @@ wasm_loader_find_export(const WASMModule *module, LOG_DEBUG("%s in the module %s is out of index (%d >= %d )", field_name, module_name, export->index, export_index_boundary); - set_error_buf_v(error_buf, error_buf_size, "incompatible import type"); + set_error_buf(error_buf, error_buf_size, "incompatible import type"); return NULL; } @@ -544,7 +551,7 @@ wasm_loader_resolve_function(const char *module_name, if (!module_reg || module_reg->module_type != Wasm_Module_Bytecode) { LOG_DEBUG("can not find a module named %s for function", module_name); - set_error_buf_v(error_buf, error_buf_size, "unknown import"); + set_error_buf(error_buf, error_buf_size, "unknown import"); return NULL; } @@ -575,7 +582,7 @@ wasm_loader_resolve_function(const char *module_name, if (!wasm_type_equal(expected_function_type, target_function_type)) { LOG_DEBUG("%s.%s failed the type check", module_name, function_name); - set_error_buf_v(error_buf, error_buf_size, "incompatible import type"); + set_error_buf(error_buf, error_buf_size, "incompatible import type"); return NULL; } @@ -596,7 +603,7 @@ wasm_loader_resolve_table(const char *module_name, const char *table_name, if (!module_reg || module_reg->module_type != Wasm_Module_Bytecode) { LOG_DEBUG("can not find a module named %s for table", module_name); - set_error_buf_v(error_buf, error_buf_size, "unknown import"); + set_error_buf(error_buf, error_buf_size, "unknown import"); return NULL; } @@ -622,7 +629,7 @@ wasm_loader_resolve_table(const char *module_name, const char *table_name, LOG_DEBUG("%s,%s failed type check(%d-%d), expected(%d-%d)", module_name, table_name, table->init_size, table->max_size, init_size, max_size); - set_error_buf_v(error_buf, error_buf_size, "incompatible import type"); + set_error_buf(error_buf, error_buf_size, "incompatible import type"); return NULL; } @@ -643,7 +650,7 @@ wasm_loader_resolve_memory(const char *module_name, const char *memory_name, if (!module_reg || module_reg->module_type != Wasm_Module_Bytecode) { LOG_DEBUG("can not find a module named %s for memory", module_name); - set_error_buf_v(error_buf, error_buf_size, "unknown import"); + set_error_buf(error_buf, error_buf_size, "unknown import"); return NULL; } @@ -672,7 +679,7 @@ wasm_loader_resolve_memory(const char *module_name, const char *memory_name, LOG_DEBUG("%s,%s failed type check(%d-%d), expected(%d-%d)", module_name, memory_name, memory->init_page_count, memory->max_page_count, init_page_count, max_page_count); - set_error_buf_v(error_buf, error_buf_size, "incompatible import type"); + set_error_buf(error_buf, error_buf_size, "incompatible import type"); return NULL; } return memory; @@ -693,7 +700,7 @@ wasm_loader_resolve_global(const char *module_name, if (!module_reg || module_reg->module_type != Wasm_Module_Bytecode) { LOG_DEBUG("can not find a module named %s for global", module_name); - set_error_buf_v(error_buf, error_buf_size, "unknown import"); + set_error_buf(error_buf, error_buf_size, "unknown import"); return NULL; } @@ -719,7 +726,7 @@ wasm_loader_resolve_global(const char *module_name, LOG_DEBUG("%s,%s failed type check(%d, %d), expected(%d, %d)", module_name, global_name, global->type, global->is_mutable, type, is_mutable); - set_error_buf_v(error_buf, error_buf_size, "incompatible import type"); + set_error_buf(error_buf, error_buf_size, "incompatible import type"); return NULL; } return global; @@ -747,9 +754,7 @@ load_function_import(const WASMModule *parent_module, WASMModule *sub_module, *p_buf = p; if (declare_type_index >= parent_module->type_count) { - set_error_buf(error_buf, error_buf_size, - "Load import section failed: unknown type."); - LOG_DEBUG("the type index is out of range"); + set_error_buf(error_buf, error_buf_size, "unknown type"); return false; } @@ -758,8 +763,7 @@ load_function_import(const WASMModule *parent_module, WASMModule *sub_module, is_built_in_module = wasm_runtime_is_built_in_module(sub_module_name); if (is_built_in_module) { LOG_DEBUG("%s is a function of a built-in module %s", - function_name, - sub_module_name); + function_name, sub_module_name); /* check built-in modules */ linked_func = wasm_native_resolve_symbol(sub_module_name, function_name, @@ -771,8 +775,7 @@ load_function_import(const WASMModule *parent_module, WASMModule *sub_module, #if WASM_ENABLE_MULTI_MODULE != 0 else { LOG_DEBUG("%s is a function of a sub-module %s", - function_name, - sub_module_name); + function_name, sub_module_name); linked_func = wasm_loader_resolve_function(sub_module_name, function_name, declare_func_type, @@ -783,15 +786,13 @@ load_function_import(const WASMModule *parent_module, WASMModule *sub_module, if (!linked_func) { #if WASM_ENABLE_SPEC_TEST != 0 - set_error_buf(error_buf, - error_buf_size, + set_error_buf(error_buf, error_buf_size, "unknown import or incompatible import type"); return false; #else #if WASM_ENABLE_WAMR_COMPILER == 0 - LOG_WARNING( - "warning: fail to link import function (%s, %s)", - sub_module_name, function_name); + LOG_WARNING("warning: fail to link import function (%s, %s)", + sub_module_name, function_name); #endif #endif } @@ -1068,9 +1069,7 @@ load_global_import(const WASMModule *parent_module, *p_buf = p; if (declare_mutable >= 2) { - set_error_buf(error_buf, error_buf_size, - "Load import section failed: " - "invalid mutability"); + set_error_buf(error_buf, error_buf_size, "invalid mutability"); return false; } @@ -1108,8 +1107,8 @@ load_global_import(const WASMModule *parent_module, if (!ret) { #if WASM_ENABLE_SPEC_TEST != 0 - set_error_buf_v(error_buf, error_buf_size, - "unknown import or incompatible import type"); + set_error_buf(error_buf, error_buf_size, + "unknown import or incompatible import type"); return false; #endif } @@ -1298,7 +1297,7 @@ load_depended_module(const WASMModule *parent_module, LOG_DEBUG("error: there is no sub_module reader to load %s", sub_module_name); set_error_buf_v(error_buf, error_buf_size, - "error: there is no sub_module reader to load %s", + "no sub module reader to load %s", sub_module_name); return NULL; } @@ -1308,7 +1307,7 @@ load_depended_module(const WASMModule *parent_module, if (ret) { LOG_DEBUG("find a circular dependency on %s", sub_module_name); set_error_buf_v(error_buf, error_buf_size, - "error: find a circular dependency on %s", + "found circular dependency on %s", sub_module_name); return NULL; } @@ -1325,7 +1324,7 @@ load_depended_module(const WASMModule *parent_module, if (!ret) { LOG_DEBUG("read the file of %s failed", sub_module_name); set_error_buf_v(error_buf, error_buf_size, - "error: can not read the module file of %s", + "failed to read module file of %s", sub_module_name); goto DELETE_FROM_LOADING_LIST; } @@ -1360,12 +1359,9 @@ load_depended_module(const WASMModule *parent_module, REGISTER_SUB_MODULE: ret = register_sub_module(parent_module, sub_module_name, sub_module); if (!ret) { - LOG_DEBUG("error: can not register a sub module %s with its parent", - sizeof(WASMRegisteredModule)); - set_error_buf_v( - error_buf, error_buf_size, - "error: can not register a sub module %s with its parent", - sizeof(WASMRegisteredModule)); + set_error_buf_v(error_buf, error_buf_size, + "failed to register sub module %s", + sub_module_name); /* * since it is in the global module list, there is no need to * unload the module. the runtime_destroy() will do it @@ -1451,7 +1447,7 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, module->import_table_count++; if (module->import_table_count > 1) { set_error_buf(error_buf, error_buf_size, - "Load import section failed: multiple tables"); + "multiple tables"); return false; } break; @@ -1464,7 +1460,7 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, module->import_memory_count++; if (module->import_memory_count > 1) { set_error_buf(error_buf, error_buf_size, - "Load import section failed: multiple memories"); + "multiple memories"); return false; } break; @@ -1477,7 +1473,7 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, default: set_error_buf(error_buf, error_buf_size, - "Load import section failed: invalid import kind"); + "invalid import kind"); return false; } } @@ -1608,7 +1604,6 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, default: set_error_buf(error_buf, error_buf_size, - "Load import section failed: " "invalid import kind"); return false; } @@ -1631,8 +1626,7 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, } if (p != p_end) { - set_error_buf(error_buf, error_buf_size, - "Load import section failed: section size mismatch"); + set_error_buf(error_buf, error_buf_size, "section size mismatch"); return false; } @@ -1698,7 +1692,6 @@ load_function_section(const uint8 *buf, const uint8 *buf_end, if (func_count != code_count) { set_error_buf(error_buf, error_buf_size, - "Load function section failed: " "function and code section have inconsistent lengths"); return false; } @@ -1715,9 +1708,7 @@ load_function_section(const uint8 *buf, const uint8 *buf_end, /* Resolve function type */ read_leb_uint32(p, p_end, type_index); if (type_index >= module->type_count) { - set_error_buf(error_buf, error_buf_size, - "Load function section failed: " - "unknown type."); + set_error_buf(error_buf, error_buf_size, "unknown type"); return false; } @@ -1725,8 +1716,7 @@ load_function_section(const uint8 *buf, const uint8 *buf_end, if (code_size == 0 || p_code + code_size > buf_code_end) { set_error_buf(error_buf, error_buf_size, - "Load function section failed: " - "invalid function code size."); + "invalid function code size"); return false; } @@ -1741,7 +1731,6 @@ load_function_section(const uint8 *buf, const uint8 *buf_end, read_leb_uint32(p_code, buf_code_end, sub_local_count); if (sub_local_count > UINT32_MAX - local_count) { set_error_buf(error_buf, error_buf_size, - "Load function section failed: " "too many locals"); return false; } @@ -1786,8 +1775,7 @@ load_function_section(const uint8 *buf, const uint8 *buf_end, if (local_type_index + sub_local_count <= local_type_index || local_type_index + sub_local_count > local_count) { set_error_buf(error_buf, error_buf_size, - "Load function section failed: " - "invalid local count."); + "invalid local count"); return false; } CHECK_BUF(p_code, buf_code_end, 1); @@ -1795,8 +1783,7 @@ load_function_section(const uint8 *buf, const uint8 *buf_end, type = read_uint8(p_code); if (type < VALUE_TYPE_F64 || type > VALUE_TYPE_I32) { set_error_buf(error_buf, error_buf_size, - "Load function section failed: " - "invalid local type."); + "invalid local type"); return false; } for (k = 0; k < sub_local_count; k++) { @@ -1817,8 +1804,7 @@ load_function_section(const uint8 *buf, const uint8 *buf_end, } if (p != p_end) { - set_error_buf(error_buf, error_buf_size, - "Load function section failed: section size mismatch"); + set_error_buf(error_buf, error_buf_size, "section size mismatch"); return false; } @@ -1860,8 +1846,7 @@ load_table_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, } if (p != p_end) { - set_error_buf(error_buf, error_buf_size, - "Load table section failed: section size mismatch"); + set_error_buf(error_buf, error_buf_size, "section size mismatch"); return false; } @@ -1903,8 +1888,7 @@ load_memory_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, } if (p != p_end) { - set_error_buf(error_buf, error_buf_size, - "Load memory section failed: section size mismatch"); + set_error_buf(error_buf, error_buf_size, "section size mismatch"); return false; } @@ -1941,9 +1925,7 @@ load_global_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, global->type = read_uint8(p); mutable = read_uint8(p); if (mutable >= 2) { - set_error_buf(error_buf, error_buf_size, - "Load import section failed: " - "invalid mutability"); + set_error_buf(error_buf, error_buf_size, "invalid mutability"); return false; } global->is_mutable = mutable ? true : false; @@ -1970,8 +1952,7 @@ load_global_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, } if (p != p_end) { - set_error_buf(error_buf, error_buf_size, - "Load global section failed: section size mismatch"); + set_error_buf(error_buf, error_buf_size, "section size mismatch"); return false; } @@ -2031,44 +2012,43 @@ load_export_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, switch(export->kind) { /*function index*/ case EXPORT_KIND_FUNC: - if (index >= module->function_count + module->import_function_count) { + if (index >= module->function_count + + module->import_function_count) { set_error_buf(error_buf, error_buf_size, - "Load export section failed: " - "unknown function."); + "unknown function"); return false; } break; /*table index*/ case EXPORT_KIND_TABLE: - if (index >= module->table_count + module->import_table_count) { + if (index >= module->table_count + + module->import_table_count) { set_error_buf(error_buf, error_buf_size, - "Load export section failed: " - "unknown table."); + "unknown table"); return false; } break; /*memory index*/ case EXPORT_KIND_MEMORY: - if (index >= module->memory_count + module->import_memory_count) { + if (index >= module->memory_count + + module->import_memory_count) { set_error_buf(error_buf, error_buf_size, - "Load export section failed: " - "unknown memory."); + "unknown memory"); return false; } break; /*global index*/ case EXPORT_KIND_GLOBAL: - if (index >= module->global_count + module->import_global_count) { + if (index >= module->global_count + + module->import_global_count) { set_error_buf(error_buf, error_buf_size, - "Load export section failed: " - "unknown global."); + "unknown global"); return false; } break; default: set_error_buf(error_buf, error_buf_size, - "Load export section failed: " - "invalid export kind."); + "invalid export kind"); return false; } } @@ -2076,7 +2056,7 @@ load_export_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, if (p != p_end) { set_error_buf(error_buf, error_buf_size, - "Load export section failed: section size mismatch"); + "section size mismatch"); return false; } @@ -2108,9 +2088,7 @@ load_table_segment_section(const uint8 *buf, const uint8 *buf_end, WASMModule *m table_segment = module->table_segments; for (i = 0; i < table_segment_count; i++, table_segment++) { if (p >= p_end) { - set_error_buf(error_buf, error_buf_size, - "Load table segment section failed: " - "unexpected end"); + set_error_buf(error_buf, error_buf_size, "unexpected end"); return false; } read_leb_uint32(p, p_end, table_index); @@ -2140,7 +2118,6 @@ load_table_segment_section(const uint8 *buf, const uint8 *buf_end, WASMModule *m if (function_index >= module->import_function_count + module->function_count) { set_error_buf(error_buf, error_buf_size, - "Load table segment section failed: " "unknown function"); return false; } @@ -2150,8 +2127,7 @@ load_table_segment_section(const uint8 *buf, const uint8 *buf_end, WASMModule *m } if (p != p_end) { - set_error_buf(error_buf, error_buf_size, - "Load table segment section failed: section size mismatch"); + set_error_buf(error_buf, error_buf_size, "section size mismatch"); return false; } @@ -2267,8 +2243,7 @@ check_mem_index: } if (p != p_end) { - set_error_buf(error_buf, error_buf_size, - "Load data segment section failed: section size mismatch"); + set_error_buf(error_buf, error_buf_size, "section size mismatch"); return false; } @@ -2290,8 +2265,7 @@ load_datacount_section(const uint8 *buf, const uint8 *buf_end, WASMModule *modul module->data_seg_count1 = data_seg_count1; if (p != p_end) { - set_error_buf(error_buf, error_buf_size, - "Load datacount section failed: section size mismatch"); + set_error_buf(error_buf, error_buf_size, "section size mismatch"); return false; } @@ -2322,7 +2296,6 @@ load_code_section(const uint8 *buf, const uint8 *buf_end, if (func_count != code_count) { set_error_buf(error_buf, error_buf_size, - "Load code section failed: " "function and code section have inconsistent lengths"); return false; } @@ -2345,9 +2318,7 @@ load_start_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, if (start_function >= module->function_count + module->import_function_count) { - set_error_buf(error_buf, error_buf_size, - "Load start section failed: " - "unknown function."); + set_error_buf(error_buf, error_buf_size, "unknown function"); return false; } @@ -2358,17 +2329,14 @@ load_start_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, module->functions[start_function - module->import_function_count] ->func_type; if (type->param_count != 0 || type->result_count != 0) { - set_error_buf(error_buf, error_buf_size, - "Load start section failed: " - "invalid start function."); + set_error_buf(error_buf, error_buf_size, "invalid start function"); return false; } module->start_function = start_function; if (p != p_end) { - set_error_buf(error_buf, error_buf_size, - "Load start section failed: section size mismatch"); + set_error_buf(error_buf, error_buf_size, "section size mismatch"); return false; } @@ -2386,8 +2354,7 @@ load_user_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, uint32 name_len; if (p >= p_end) { - set_error_buf(error_buf, error_buf_size, - "Load custom section failed: unexpected end"); + set_error_buf(error_buf, error_buf_size, "unexpected end"); return false; } @@ -2395,14 +2362,12 @@ load_user_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, if (name_len == 0 || p + name_len > p_end) { - set_error_buf(error_buf, error_buf_size, - "Load custom section failed: unexpected end"); + set_error_buf(error_buf, error_buf_size, "unexpected end"); return false; } if (!check_utf8_str(p, name_len)) { set_error_buf(error_buf, error_buf_size, - "WASM module load failed: " "invalid UTF-8 encoding"); return false; } @@ -2465,44 +2430,53 @@ load_from_sections(WASMModule *module, WASMSection *sections, switch (section->section_type) { case SECTION_TYPE_USER: /* unsupported user section, ignore it. */ - if (!load_user_section(buf, buf_end, module, error_buf, error_buf_size)) + if (!load_user_section(buf, buf_end, module, + error_buf, error_buf_size)) return false; break; case SECTION_TYPE_TYPE: - if (!load_type_section(buf, buf_end, module, error_buf, error_buf_size)) + if (!load_type_section(buf, buf_end, module, + error_buf, error_buf_size)) return false; break; case SECTION_TYPE_IMPORT: - if (!load_import_section(buf, buf_end, module, error_buf, error_buf_size)) + if (!load_import_section(buf, buf_end, module, + error_buf, error_buf_size)) return false; break; case SECTION_TYPE_FUNC: if (!load_function_section(buf, buf_end, buf_code, buf_code_end, - module, error_buf, error_buf_size)) + module, error_buf, error_buf_size)) return false; break; case SECTION_TYPE_TABLE: - if (!load_table_section(buf, buf_end, module, error_buf, error_buf_size)) + if (!load_table_section(buf, buf_end, module, + error_buf, error_buf_size)) return false; break; case SECTION_TYPE_MEMORY: - if (!load_memory_section(buf, buf_end, module, error_buf, error_buf_size)) + if (!load_memory_section(buf, buf_end, module, + error_buf, error_buf_size)) return false; break; case SECTION_TYPE_GLOBAL: - if (!load_global_section(buf, buf_end, module, error_buf, error_buf_size)) + if (!load_global_section(buf, buf_end, module, + error_buf, error_buf_size)) return false; break; case SECTION_TYPE_EXPORT: - if (!load_export_section(buf, buf_end, module, error_buf, error_buf_size)) + if (!load_export_section(buf, buf_end, module, + error_buf, error_buf_size)) return false; break; case SECTION_TYPE_START: - if (!load_start_section(buf, buf_end, module, error_buf, error_buf_size)) + if (!load_start_section(buf, buf_end, module, + error_buf, error_buf_size)) return false; break; case SECTION_TYPE_ELEM: - if (!load_table_segment_section(buf, buf_end, module, error_buf, error_buf_size)) + if (!load_table_segment_section(buf, buf_end, module, + error_buf, error_buf_size)) return false; break; case SECTION_TYPE_CODE: @@ -2511,18 +2485,20 @@ load_from_sections(WASMModule *module, WASMSection *sections, return false; break; case SECTION_TYPE_DATA: - if (!load_data_segment_section(buf, buf_end, module, error_buf, error_buf_size)) + if (!load_data_segment_section(buf, buf_end, module, + error_buf, error_buf_size)) return false; break; #if WASM_ENABLE_BULK_MEMORY != 0 case SECTION_TYPE_DATACOUNT: - if (!load_datacount_section(buf, buf_end, module, error_buf, error_buf_size)) + if (!load_datacount_section(buf, buf_end, module, + error_buf, error_buf_size)) return false; break; #endif default: set_error_buf(error_buf, error_buf_size, - "WASM module load failed: invalid section id"); + "invalid section id"); return false; } @@ -2533,7 +2509,8 @@ load_from_sections(WASMModule *module, WASMSection *sections, handle_table = wasm_interp_get_handle_table(); #endif - total_size = sizeof(BlockAddr) * (uint64)BLOCK_ADDR_CACHE_SIZE * BLOCK_ADDR_CONFLICT_SIZE; + total_size = sizeof(BlockAddr) * (uint64)BLOCK_ADDR_CACHE_SIZE + * BLOCK_ADDR_CONFLICT_SIZE; if (!(block_addr_cache = loader_malloc (total_size, error_buf, error_buf_size))) { return false; @@ -2847,7 +2824,6 @@ create_sections(const uint8 *buf, uint32 size, if (last_section_index != (uint8)-1 && (section_index <= last_section_index)) { set_error_buf(error_buf, error_buf_size, - "WASM module load failed: " "junk after last section"); return false; } @@ -2877,7 +2853,7 @@ create_sections(const uint8 *buf, uint32 size, } else { set_error_buf(error_buf, error_buf_size, - "WASM module load failed: invalid section id"); + "invalid section id"); return false; } } @@ -2922,7 +2898,7 @@ load(const uint8 *buf, uint32 size, WASMModule *module, if (magic_number != WASM_MAGIC_NUMBER) { set_error_buf(error_buf, error_buf_size, - "WASM module load failed: magic header not detected"); + "magic header not detected"); return false; } @@ -2933,7 +2909,7 @@ load(const uint8 *buf, uint32 size, WASMModule *module, if (version != WASM_CURRENT_VERSION) { set_error_buf(error_buf, error_buf_size, - "WASM module load failed: unknown binary version"); + "unknown binary version"); return false; } @@ -2958,7 +2934,6 @@ wasm_loader_load(const uint8 *buf, uint32 size, char *error_buf, uint32 error_bu } if (!load(buf, size, module, error_buf, error_buf_size)) { - LOG_VERBOSE("Load module failed, %s", error_buf); goto fail; } @@ -3436,10 +3411,9 @@ wasm_loader_find_block_addr(BlockAddr *block_addr_cache, break; #endif default: - if (error_buf) - snprintf(error_buf, error_buf_size, - "WASM loader find block addr failed: " - "invalid opcode fc %02x.", opcode); + set_error_buf_v(error_buf, error_buf_size, + "%s %02x %02x", + "unsupported opcode", 0xfc, opcode); return false; } break; @@ -3461,10 +3435,9 @@ wasm_loader_find_block_addr(BlockAddr *block_addr_cache, } #endif default: - if (error_buf) - snprintf(error_buf, error_buf_size, - "WASM loader find block addr failed: " - "invalid opcode %02x.", opcode); + set_error_buf_v(error_buf, error_buf_size, + "%s %02x", + "unsupported opcode", opcode); return false; } } @@ -3488,7 +3461,7 @@ fail: #if WASM_DEBUG_PREPROCESSOR != 0 #define LOG_OP(...) os_printf(__VA_ARGS__) #else -#define LOG_OP(...) +#define LOG_OP(...) (void)0 #endif #define PATCH_ELSE 0 @@ -3611,7 +3584,7 @@ memory_realloc(void *mem_old, uint32 size_old, uint32 size_new, #define CHECK_CSP_POP() do { \ if (ctx->csp_num < 1) { \ set_error_buf(error_buf, error_buf_size, \ - "WASM module load failed: type mismatch: " \ + "type mismatch: " \ "expect data but block stack was empty"); \ goto fail; \ } \ @@ -3698,7 +3671,6 @@ check_stack_top_values(uint8 *frame_ref, int32 stack_cell_num, uint8 type, || ((type == VALUE_TYPE_I64 || type == VALUE_TYPE_F64) && stack_cell_num < 2)) { set_error_buf(error_buf, error_buf_size, - "WASM module load failed: " "type mismatch: expect data but stack was empty"); return false; } @@ -3711,10 +3683,10 @@ check_stack_top_values(uint8 *frame_ref, int32 stack_cell_num, uint8 type, || (type == VALUE_TYPE_F64 && (*(frame_ref - 2) != REF_F64_1 || *(frame_ref - 1) != REF_F64_2))) { - if (error_buf != NULL) - snprintf(error_buf, error_buf_size, "%s%s%s", - "WASM module load failed: type mismatch: expect ", - type_str[type - VALUE_TYPE_F64], " but got other"); + set_error_buf_v(error_buf, error_buf_size, "%s%s%s", + "type mismatch: expect ", + type_str[type - VALUE_TYPE_F64], + " but got other"); return false; } @@ -3949,7 +3921,6 @@ fail: int32 offset = (int32)(handle_table[opcode] - handle_table[0]); \ if (!(offset >= INT16_MIN && offset < INT16_MAX)) { \ set_error_buf(error_buf, error_buf_size, \ - "WASM module load failed: " \ "pre-compiled label offset out of range"); \ goto fail; \ } \ @@ -4892,8 +4863,7 @@ fail: read_leb_uint32(p, p_end, local_idx); \ if (local_idx >= param_count + local_count) { \ set_error_buf(error_buf, error_buf_size, \ - "WASM module load failed: " \ - "unknown local."); \ + "unknown local"); \ goto fail; \ } \ local_type = local_idx < param_count \ @@ -4914,8 +4884,7 @@ check_memory(WASMModule *module, { if (module->memory_count == 0 && module->import_memory_count == 0) { - set_error_buf(error_buf, error_buf_size, - "WASM module load failed: unknown memory"); + set_error_buf(error_buf, error_buf_size, "unknown memory"); return false; } return true; @@ -4997,7 +4966,7 @@ wasm_loader_check_br(WASMLoaderContext *loader_ctx, uint32 depth, if (loader_ctx->csp_num < depth + 1) { set_error_buf(error_buf, error_buf_size, - "WASM module load failed: unknown label, " + "unknown label, " "unexpected end of section or function"); return false; } @@ -5110,7 +5079,6 @@ check_block_stack(WASMLoaderContext *loader_ctx, BranchBlock *block, /* Check stack is empty */ if (loader_ctx->stack_cell_num != block->stack_cell_num) { set_error_buf(error_buf, error_buf_size, - "WASM module load failed: " "type mismatch: stack size does not match block type"); goto fail; } @@ -5129,7 +5097,6 @@ check_block_stack(WASMLoaderContext *loader_ctx, BranchBlock *block, /* Check stack cell num equals return cell num */ if (available_stack_cell != return_cell_num) { set_error_buf(error_buf, error_buf_size, - "WASM module load failed: " "type mismatch: stack size does not match block type"); goto fail; } @@ -5324,7 +5291,6 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, if (!(loader_ctx = wasm_loader_ctx_init(func))) { set_error_buf(error_buf, error_buf_size, - "WASM loader prepare bytecode failed: " "allocate memory failed"); goto fail; } @@ -5334,7 +5300,6 @@ re_scan: if (loader_ctx->code_compiled_size > 0) { if (!wasm_loader_ctx_reinit(loader_ctx)) { set_error_buf(error_buf, error_buf_size, - "WASM loader prepare bytecode failed: " "allocate memory failed"); goto fail; } @@ -5390,7 +5355,6 @@ handle_op_block_and_loop: read_leb_uint32(p, p_end, type_index); if (type_index >= module->type_count) { set_error_buf(error_buf, error_buf_size, - "WASM loader prepare bytecode failed: " "unknown type"); goto fail; } @@ -5502,7 +5466,6 @@ handle_op_block_and_loop: if (loader_ctx->csp_num < 2 || (loader_ctx->frame_csp - 1)->label_type != LABEL_TYPE_IF) { set_error_buf(error_buf, error_buf_size, - "WASM loader prepare bytecode failed: " "opcode else found without matched opcode if"); goto fail; } @@ -5576,7 +5539,6 @@ handle_op_block_and_loop: if (param_count != ret_count || (param_count && memcmp(param_types, ret_types, param_count))) { set_error_buf(error_buf, error_buf_size, - "WASM module load failed: " "type mismatch: else branch missing"); goto fail; } @@ -5679,7 +5641,6 @@ handle_op_block_and_loop: || (ret_count && 0 != memcmp(ret_types, tmp_ret_types, ret_count))) { set_error_buf(error_buf, error_buf_size, - "WASM loader prepare bytecode failed: " "type mismatch: br_table targets must " "all use same result type"); goto fail; @@ -5726,8 +5687,7 @@ handle_op_block_and_loop: if (func_idx >= module->import_function_count + module->function_count) { set_error_buf(error_buf, error_buf_size, - "WASM loader prepare bytecode failed: " - "unknown function."); + "unknown function"); goto fail; } @@ -5770,7 +5730,6 @@ handle_op_block_and_loop: if (module->table_count == 0 && module->import_table_count == 0) { set_error_buf(error_buf, error_buf_size, - "WASM loader prepare bytecode failed: " "call indirect with unknown table"); goto fail; } @@ -5784,7 +5743,6 @@ handle_op_block_and_loop: /* reserved byte 0x00 */ if (*p++ != 0x00) { set_error_buf(error_buf, error_buf_size, - "WASM loader prepare bytecode failed: " "zero flag expected"); goto fail; } @@ -5793,7 +5751,6 @@ handle_op_block_and_loop: if (type_idx >= module->type_count) { set_error_buf(error_buf, error_buf_size, - "WASM loader prepare bytecode failed: " "unknown type"); goto fail; } @@ -5830,7 +5787,6 @@ handle_op_block_and_loop: if (available_stack_cell <= 0 && !cur_block->is_stack_polymorphic) { set_error_buf(error_buf, error_buf_size, - "WASM loader prepare bytecode failed: " "type mismatch, opcode drop was found " "but stack was empty"); goto fail; @@ -5887,7 +5843,6 @@ handle_op_block_and_loop: if (available_stack_cell <= 0 && !cur_block->is_stack_polymorphic) { set_error_buf(error_buf, error_buf_size, - "WASM loader prepare bytecode failed: " "type mismatch, opcode select was found " "but stack was empty"); goto fail; @@ -6094,8 +6049,7 @@ handle_op_block_and_loop: read_leb_uint32(p, p_end, global_idx); if (global_idx >= global_count) { set_error_buf(error_buf, error_buf_size, - "WASM loader prepare bytecode failed: " - "unknown global."); + "unknown global"); goto fail; } @@ -6134,8 +6088,7 @@ handle_op_block_and_loop: read_leb_uint32(p, p_end, global_idx); if (global_idx >= global_count) { set_error_buf(error_buf, error_buf_size, - "WASM loader prepare bytecode failed: " - "unknown global."); + "unknown global"); goto fail; } @@ -6145,8 +6098,7 @@ handle_op_block_and_loop: : module->globals[global_idx - module->import_global_count] .is_mutable; if (!is_mutable) { - set_error_buf(error_buf, - error_buf_size, + set_error_buf(error_buf, error_buf_size, "global is immutable"); goto fail; } @@ -6300,7 +6252,6 @@ handle_op_block_and_loop: /* reserved byte 0x00 */ if (*p++ != 0x00) { set_error_buf(error_buf, error_buf_size, - "WASM loader prepare bytecode failed: " "zero flag expected"); goto fail; } @@ -6314,7 +6265,6 @@ handle_op_block_and_loop: /* reserved byte 0x00 */ if (*p++ != 0x00) { set_error_buf(error_buf, error_buf_size, - "WASM loader prepare bytecode failed: " "zero flag expected"); goto fail; } @@ -6632,10 +6582,8 @@ handle_op_block_and_loop: goto fail_zero_flag_expected; if (segment_index >= module->data_seg_count) { - char msg[128]; - snprintf(msg, 128, "WASM loader prepare bytecode failed: " - "unknown data segment %d", segment_index); - set_error_buf(error_buf, error_buf_size, msg); + set_error_buf(error_buf, error_buf_size, + "unknown data segment"); goto fail; } @@ -6653,7 +6601,6 @@ handle_op_block_and_loop: #endif if (segment_index >= module->data_seg_count) { set_error_buf(error_buf, error_buf_size, - "WASM loader prepare bytecode failed: " "unknown data segment"); goto fail; } @@ -6689,29 +6636,24 @@ handle_op_block_and_loop: break; fail_zero_flag_expected: set_error_buf(error_buf, error_buf_size, - "WASM loader prepare bytecode failed: " "zero flag expected"); goto fail; fail_unknown_memory: set_error_buf(error_buf, error_buf_size, - "WASM loader prepare bytecode failed: " "unknown memory 0"); goto fail; fail_data_cnt_sec_require: set_error_buf(error_buf, error_buf_size, - "WASM loader prepare bytecode failed: " "data count section required"); goto fail; /* TODO: to support bulk table operation */ #endif /* WASM_ENABLE_BULK_MEMORY */ default: - if (error_buf != NULL) - snprintf(error_buf, error_buf_size, - "WASM module load failed: " - "invalid opcode 0xfc %02x.", opcode1); + set_error_buf_v(error_buf, error_buf_size, + "%s %02x %02x", + "unsupported opcode", 0xfc, opcode1); goto fail; - break; } break; } @@ -6755,7 +6697,6 @@ fail_data_cnt_sec_require: /* reserved byte 0x00 */ if (*p++ != 0x00) { set_error_buf(error_buf, error_buf_size, - "WASM loader prepare bytecode failed: " "zero flag expected"); goto fail; } @@ -6850,20 +6791,18 @@ fail_data_cnt_sec_require: PUSH_I64(); break; default: - if (error_buf != NULL) - snprintf(error_buf, error_buf_size, - "WASM module load failed: " - "invalid opcode 0xfe %02x.", opcode); + set_error_buf_v(error_buf, error_buf_size, + "%s %02x %02x", + "unsupported opcode", 0xfe, opcode); goto fail; } break; } #endif /* end of WASM_ENABLE_SHARED_MEMORY */ default: - if (error_buf != NULL) - snprintf(error_buf, error_buf_size, - "WASM module load failed: " - "invalid opcode %02x.", opcode); + set_error_buf_v(error_buf, error_buf_size, + "%s %02x", + "unsupported opcode", opcode); goto fail; } @@ -6874,8 +6813,7 @@ fail_data_cnt_sec_require: if (loader_ctx->csp_num > 0) { set_error_buf(error_buf, error_buf_size, - "WASM module load failed: " - "function body must end with END opcode."); + "function body must end with END opcode"); goto fail; } diff --git a/core/iwasm/interpreter/wasm_mini_loader.c b/core/iwasm/interpreter/wasm_mini_loader.c index a56c2a382..d1541a68d 100644 --- a/core/iwasm/interpreter/wasm_mini_loader.c +++ b/core/iwasm/interpreter/wasm_mini_loader.c @@ -21,7 +21,8 @@ static void set_error_buf(char *error_buf, uint32 error_buf_size, const char *string) { if (error_buf != NULL) - snprintf(error_buf, error_buf_size, "%s", string); + snprintf(error_buf, error_buf_size, + "WASM module load failed: %s", string); } #define CHECK_BUF(buf, buf_end, length) do { \ @@ -168,8 +169,7 @@ loader_malloc(uint64 size, char *error_buf, uint32 error_buf_size) if (size >= UINT32_MAX || !(mem = wasm_runtime_malloc((uint32)size))) { set_error_buf(error_buf, error_buf_size, - "WASM module load failed: " - "allocate memory failed."); + "allocate memory failed"); return NULL; } @@ -378,8 +378,7 @@ load_function_import(const WASMModule *parent_module, WASMModule *sub_module, is_built_in_module = wasm_runtime_is_built_in_module(sub_module_name); if (is_built_in_module) { LOG_DEBUG("%s is a function of a built-in module %s", - function_name, - sub_module_name); + function_name, sub_module_name); /* check built-in modules */ linked_func = wasm_native_resolve_symbol(sub_module_name, function_name, @@ -391,15 +390,13 @@ load_function_import(const WASMModule *parent_module, WASMModule *sub_module, if (!linked_func) { #if WASM_ENABLE_SPEC_TEST != 0 - set_error_buf(error_buf, - error_buf_size, + set_error_buf(error_buf, error_buf_size, "unknown import or incompatible import type"); return false; #else #if WASM_ENABLE_WAMR_COMPILER == 0 - LOG_WARNING( - "warning: fail to link import function (%s, %s)", - sub_module_name, function_name); + LOG_WARNING("warning: fail to link import function (%s, %s)", + sub_module_name, function_name); #endif #endif } @@ -538,8 +535,8 @@ load_global_import(const WASMModule *parent_module, #endif /* WASM_ENABLE_LIBC_BUILTIN */ if (!ret) { - set_error_buf_v(error_buf, error_buf_size, - "unknown import or incompatible import type"); + set_error_buf(error_buf, error_buf_size, + "unknown import or incompatible import type"); return false; } @@ -597,6 +594,7 @@ load_memory(const uint8 **p_buf, const uint8 *buf_end, WASMMemory *memory, p_org = p; read_leb_uint32(p, p_end, memory->flags); bh_assert(p - p_org <= 1); + (void)p_org; #if WASM_ENABLE_SHARED_MEMORY == 0 bh_assert(memory->flags <= 1); #else @@ -1536,7 +1534,7 @@ load_from_sections(WASMModule *module, WASMSection *sections, #endif default: set_error_buf(error_buf, error_buf_size, - "WASM module load failed: invalid section id"); + "invalid section id"); return false; } @@ -1934,8 +1932,7 @@ load(const uint8 *buf, uint32 size, WASMModule *module, exchange32((uint8*)&version); if (version != WASM_CURRENT_VERSION) { - set_error_buf(error_buf, error_buf_size, - "WASM module load failed: unknown binary version"); + set_error_buf(error_buf, error_buf_size, "unknown binary version"); return false; } @@ -1959,7 +1956,6 @@ wasm_loader_load(const uint8 *buf, uint32 size, char *error_buf, uint32 error_bu } if (!load(buf, size, module, error_buf, error_buf_size)) { - LOG_VERBOSE("Load module failed, %s", error_buf); goto fail; } @@ -2459,7 +2455,7 @@ wasm_loader_find_block_addr(BlockAddr *block_addr_cache, #if WASM_DEBUG_PREPROCESSOR != 0 #define LOG_OP(...) os_printf(__VA_ARGS__) #else -#define LOG_OP(...) +#define LOG_OP(...) (void)0 #endif #define PATCH_ELSE 0 @@ -3878,7 +3874,7 @@ wasm_loader_check_br(WASMLoaderContext *loader_ctx, uint32 depth, if (loader_ctx->csp_num < depth + 1) { set_error_buf(error_buf, error_buf_size, - "WASM module load failed: unknown label, " + "unknown label, " "unexpected end of section or function"); return false; } @@ -4196,7 +4192,6 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, if (!(loader_ctx = wasm_loader_ctx_init(func))) { set_error_buf(error_buf, error_buf_size, - "WASM loader prepare bytecode failed: " "allocate memory failed"); goto fail; } @@ -4206,7 +4201,6 @@ re_scan: if (loader_ctx->code_compiled_size > 0) { if (!wasm_loader_ctx_reinit(loader_ctx)) { set_error_buf(error_buf, error_buf_size, - "WASM loader prepare bytecode failed: " "allocate memory failed"); goto fail; } @@ -5604,8 +5598,7 @@ handle_op_block_and_loop: if (loader_ctx->csp_num > 0) { set_error_buf(error_buf, error_buf_size, - "WASM module load failed: " - "function body must end with END opcode."); + "function body must end with END opcode"); goto fail; } diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index 9e1c427cc..d89e68e4b 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -17,8 +17,10 @@ static void set_error_buf(char *error_buf, uint32 error_buf_size, const char *string) { - if (error_buf != NULL) - snprintf(error_buf, error_buf_size, "%s", string); + if (error_buf != NULL) { + snprintf(error_buf, error_buf_size, + "WASM module instantiate failed: %s", string); + } } WASMModule* @@ -50,8 +52,7 @@ runtime_malloc(uint64 size, char *error_buf, uint32 error_buf_size) if (size >= UINT32_MAX || !(mem = wasm_runtime_malloc((uint32)size))) { set_error_buf(error_buf, error_buf_size, - "WASM module instantiate failed: " - "allocate memory failed."); + "allocate memory failed"); return NULL; } @@ -262,17 +263,13 @@ memory_instantiate(WASMModuleInstance *module_inst, if (heap_size > 0 && !(memory->heap_handle = mem_allocator_create(memory->heap_data, heap_size))) { - set_error_buf(error_buf, error_buf_size, - "Instantiate memory failed: " - "init app heap failed."); + set_error_buf(error_buf, error_buf_size, "init app heap failed"); goto fail1; } #if WASM_ENABLE_SHARED_MEMORY != 0 if (0 != os_mutex_init(&memory->mem_lock)) { - set_error_buf(error_buf, error_buf_size, - "Instantiate memory failed: " - "init mutex failed."); + set_error_buf(error_buf, error_buf_size, "init mutex failed"); goto fail2; } if (is_shared_memory) { @@ -281,8 +278,7 @@ memory_instantiate(WASMModuleInstance *module_inst, (WASMModuleCommon *)module_inst->module, (WASMMemoryInstanceCommon *)memory)) { set_error_buf(error_buf, error_buf_size, - "Instantiate memory failed: " - "allocate memory failed."); + "allocate memory failed"); goto fail3; } } @@ -735,8 +731,7 @@ globals_instantiate(const WASMModule *module, sub_module_inst->globals, sub_module_inst->global_count, &(global->initial_value)); if (!ret) { - set_error_buf(error_buf, error_buf_size, - "Instantiate global failed: unknown global."); + set_error_buf(error_buf, error_buf_size, "unknown global"); return NULL; } } @@ -774,8 +769,7 @@ globals_instantiate(const WASMModule *module, parse_init_expr(init_expr, globals, global_count, &(global->initial_value)); if (!ret) { - set_error_buf(error_buf, error_buf_size, - "Instantiate global failed: unknown global."); + set_error_buf(error_buf, error_buf_size, "unknown global"); return NULL; } } @@ -811,8 +805,7 @@ globals_instantiate_fix(WASMGlobalInstance *globals, ret = parse_init_expr(init_expr, globals, global_count, &global->initial_value); if (!ret) { - set_error_buf(error_buf, error_buf_size, - "Instantiate global failed: unknown global."); + set_error_buf(error_buf, error_buf_size, "unknown global"); return false; } } @@ -1024,18 +1017,18 @@ sub_module_instantiate(WASMModule *module, WASMModuleInstance *module_inst, bh_list_first_elem(module->import_module_list); while (sub_module_list_node) { + WASMSubModInstNode *sub_module_inst_list_node; WASMModule *sub_module = (WASMModule*)sub_module_list_node->module; - WASMModuleInstance *sub_module_inst = wasm_instantiate( - sub_module, false, stack_size, heap_size, error_buf, error_buf_size); + WASMModuleInstance *sub_module_inst = + wasm_instantiate(sub_module, false, stack_size, heap_size, + error_buf, error_buf_size); if (!sub_module_inst) { LOG_DEBUG("instantiate %s failed", sub_module_list_node->module_name); - set_error_buf_v(error_buf, error_buf_size, "instantiate %s failed", - sub_module_list_node->module_name); return false; } - WASMSubModInstNode *sub_module_inst_list_node = runtime_malloc + sub_module_inst_list_node = runtime_malloc (sizeof(WASMSubModInstNode), error_buf, error_buf_size); if (!sub_module_inst_list_node) { LOG_DEBUG("Malloc WASMSubModInstNode failed, SZ:%d", @@ -1102,7 +1095,6 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, error_buf, error_buf_size))) { return NULL; } - memset(module_inst, 0, (uint32)sizeof(WASMModuleInstance)); module_inst->module = module; @@ -1264,7 +1256,7 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, LOG_DEBUG("base_offset(%d) > memory_size(%d)", base_offset, memory_size); set_error_buf(error_buf, error_buf_size, - "data segment does not fit."); + "data segment does not fit"); wasm_deinstantiate(module_inst, false); return NULL; } @@ -1274,9 +1266,8 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, if (base_offset + length > memory_size) { LOG_DEBUG("base_offset(%d) + length(%d) > memory_size(%d)", base_offset, length, memory_size); - set_error_buf( - error_buf, error_buf_size, - "Instantiate module failed: data segment does not fit."); + set_error_buf(error_buf, error_buf_size, + "data segment does not fit"); wasm_deinstantiate(module_inst, false); return NULL; } @@ -1538,7 +1529,7 @@ wasm_create_exec_env_and_call_function(WASMModuleInstance *module_inst, if (!(exec_env = wasm_exec_env_create( (WASMModuleInstanceCommon*)module_inst, module_inst->default_wasm_stack_size))) { - wasm_set_exception(module_inst, "allocate memory failed."); + wasm_set_exception(module_inst, "allocate memory failed"); return false; } @@ -1764,12 +1755,10 @@ wasm_enlarge_memory(WASMModuleInstance *module, uint32 inc_page_count) if (total_page_count < memory->cur_page_count /* integer overflow */ || total_page_count > memory->max_page_count) { - wasm_set_exception(module, "fail to enlarge memory."); return false; } if (total_size >= UINT32_MAX) { - wasm_set_exception(module, "fail to enlarge memory."); return false; } @@ -1793,7 +1782,6 @@ wasm_enlarge_memory(WASMModuleInstance *module, uint32 inc_page_count) /* Restore heap's lock if memory re-alloc failed */ mem_allocator_reinit_lock(memory->heap_handle); } - wasm_set_exception(module, "fail to enlarge memory."); return false; } bh_memcpy_s((uint8 *)new_memory, (uint32)total_size, @@ -1809,7 +1797,6 @@ wasm_enlarge_memory(WASMModuleInstance *module, uint32 inc_page_count) ((uint8 *)new_memory - (uint8 *)memory); if (mem_allocator_migrate(new_memory->heap_handle, heap_handle_old) != 0) { - wasm_set_exception(module, "fail to enlarge memory."); return false; } } From 049760b84966d119b2f95a3d9be6e17d638e2d9b Mon Sep 17 00:00:00 2001 From: qinxk-inter <69961735+qinxk-inter@users.noreply.github.com> Date: Fri, 21 Aug 2020 15:14:04 +0800 Subject: [PATCH 059/207] Fix the build issues on mac for some samples (#358) Fix the build issues on mac for basic/multi-module/multi-thread/ simple/spawn-thread/wasm-c-api under samples. And all these samples could be run as expected. Signed-off-by: Xiaokang Qin --- .../sandboxed-system-primitives/src/posix.c | 4 ++++ samples/basic/CMakeLists.txt | 22 +++++++++++++++---- samples/multi-module/CMakeLists.txt | 17 +++++++++++--- samples/multi-thread/CMakeLists.txt | 10 +++++++-- samples/multi-thread/wasm-apps/CMakeLists.txt | 8 +++++-- samples/spawn-thread/CMakeLists.txt | 12 +++++++--- samples/spawn-thread/wasm-apps/CMakeLists.txt | 6 ++++- samples/wasm-c-api/CMakeLists.txt | 17 +++++++++++--- 8 files changed, 78 insertions(+), 18 deletions(-) diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c index c3d392301..f456d681e 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c @@ -2137,7 +2137,11 @@ static void convert_timestamp( struct timespec *out ) { // Store sub-second remainder. +#ifndef __APPLE__ out->tv_nsec = (__syscall_slong_t)(in % 1000000000); +#else + out->tv_nsec = (long)(in % 1000000000); +#endif in /= 1000000000; // Clamp to the maximum in case it would overflow our system's time_t. diff --git a/samples/basic/CMakeLists.txt b/samples/basic/CMakeLists.txt index d55054c07..1c7db658e 100644 --- a/samples/basic/CMakeLists.txt +++ b/samples/basic/CMakeLists.txt @@ -6,7 +6,10 @@ cmake_minimum_required (VERSION 2.8) project (basic) ################ runtime settings ################ -set (WAMR_BUILD_PLATFORM "linux") +string (TOLOWER ${CMAKE_HOST_SYSTEM_NAME} WAMR_BUILD_PLATFORM) +if (APPLE) + add_definitions(-DBH_PLATFORM_DARWIN) +endif () # Reset default linker flags set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") @@ -23,9 +26,16 @@ set (WAMR_BUILD_LIBC_WASI 1) set (WAMR_BUILD_FAST_INTERP 0) # linker flags -set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections -pie -fPIE") +set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pie -fPIE") +if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang")) + set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") +endif () set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat -Wformat-security") -set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mindirect-branch-register") +if (WAMR_BUILD_TARGET MATCHES "X86_.*" OR WAMR_BUILD_TARGET STREQUAL "AMD_64") + if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang")) + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mindirect-branch-register") + endif () +endif () # build out vmlib set (WAMR_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../..) @@ -39,4 +49,8 @@ include (${SHARED_DIR}/utils/uncommon/shared_uncommon.cmake) add_executable (basic src/main.c src/native_impl.c ${UNCOMMON_SHARED_SOURCE}) -target_link_libraries (basic vmlib -lm -ldl -lpthread -lrt) \ No newline at end of file +if (APPLE) + target_link_libraries (basic vmlib -lm -ldl -lpthread) +else () + target_link_libraries (basic vmlib -lm -ldl -lpthread -lrt) +endif () diff --git a/samples/multi-module/CMakeLists.txt b/samples/multi-module/CMakeLists.txt index ac06fcb38..ba239d567 100644 --- a/samples/multi-module/CMakeLists.txt +++ b/samples/multi-module/CMakeLists.txt @@ -5,7 +5,10 @@ cmake_minimum_required(VERSION 2.8) project(multi_module) ################ runtime settings ################ -set(WAMR_BUILD_PLATFORM "linux") +string (TOLOWER ${CMAKE_HOST_SYSTEM_NAME} WAMR_BUILD_PLATFORM) +if (APPLE) + add_definitions(-DBH_PLATFORM_DARWIN) +endif () # Resetdefault linker flags set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") @@ -22,8 +25,16 @@ set(WAMR_BUILD_FAST_INTERP 0) set(WAMR_BUILD_MULTI_MODULE 1) # compiling and linking flags -set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections -pie -fPIE") -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat -Wformat-security -mindirect-branch-register") +set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pie -fPIE") +if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang")) + set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") +endif () +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat -Wformat-security") +if (WAMR_BUILD_TARGET MATCHES "X86_.*" OR WAMR_BUILD_TARGET STREQUAL "AMD_64") + if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang")) + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mindirect-branch-register") + endif () +endif () # build out vmlib set(WAMR_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../..) diff --git a/samples/multi-thread/CMakeLists.txt b/samples/multi-thread/CMakeLists.txt index 525c851a7..34151d05f 100644 --- a/samples/multi-thread/CMakeLists.txt +++ b/samples/multi-thread/CMakeLists.txt @@ -5,7 +5,10 @@ cmake_minimum_required(VERSION 2.8) project(pthread) ################ runtime settings ################ -set(WAMR_BUILD_PLATFORM "linux") +string (TOLOWER ${CMAKE_HOST_SYSTEM_NAME} WAMR_BUILD_PLATFORM) +if (APPLE) + add_definitions(-DBH_PLATFORM_DARWIN) +endif () # Resetdefault linker flags set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") @@ -21,7 +24,10 @@ set(WAMR_BUILD_FAST_INTERP 1) set(WAMR_BUILD_LIB_PTHREAD 1) # compiling and linking flags -set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections -pie -fPIE") +set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pie -fPIE") +if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang")) + set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") +endif () set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat -Wformat-security") # build out vmlib diff --git a/samples/multi-thread/wasm-apps/CMakeLists.txt b/samples/multi-thread/wasm-apps/CMakeLists.txt index 8ef729fde..171c5e01d 100644 --- a/samples/multi-thread/wasm-apps/CMakeLists.txt +++ b/samples/multi-thread/wasm-apps/CMakeLists.txt @@ -6,7 +6,11 @@ project(wasm-apps) set(WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../..) -set(CMAKE_SYSTEM_NAME Linux) +if (APPLE) + set (HAVE_FLAG_SEARCH_PATHS_FIRST 0) + set (CMAKE_C_LINK_FLAGS "") + set (CMAKE_CXX_LINK_FLAGS "") +endif () set(CMAKE_SYSTEM_PROCESSOR wasm32) set (CMAKE_SYSROOT ${WAMR_ROOT_DIR}/wamr-sdk/app/libc-builtin-sysroot) @@ -31,4 +35,4 @@ set (CMAKE_EXE_LINKER_FLAGS ) add_executable(test.wasm main.c) -target_link_libraries(test.wasm) \ No newline at end of file +target_link_libraries(test.wasm) diff --git a/samples/spawn-thread/CMakeLists.txt b/samples/spawn-thread/CMakeLists.txt index dc753af2e..b40af9a85 100644 --- a/samples/spawn-thread/CMakeLists.txt +++ b/samples/spawn-thread/CMakeLists.txt @@ -5,7 +5,10 @@ cmake_minimum_required(VERSION 2.8) project(spawn_thread) ################ runtime settings ################ -set(WAMR_BUILD_PLATFORM "linux") +string (TOLOWER ${CMAKE_HOST_SYSTEM_NAME} WAMR_BUILD_PLATFORM) +if (APPLE) + add_definitions(-DBH_PLATFORM_DARWIN) +endif () # Resetdefault linker flags set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") @@ -21,7 +24,10 @@ set(WAMR_BUILD_FAST_INTERP 1) set(WAMR_BUILD_LIB_PTHREAD 1) # compiling and linking flags -set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections -pie -fPIE") +set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pie -fPIE") +if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang")) + set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") +endif () set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat -Wformat-security") # build out vmlib @@ -43,4 +49,4 @@ set (RUNTIME_SOURCE_ALL ${UNCOMMON_SHARED_SOURCE} ) add_executable (spawn_thread ${RUNTIME_SOURCE_ALL}) -target_link_libraries(spawn_thread vmlib -lpthread -lm) \ No newline at end of file +target_link_libraries(spawn_thread vmlib -lpthread -lm) diff --git a/samples/spawn-thread/wasm-apps/CMakeLists.txt b/samples/spawn-thread/wasm-apps/CMakeLists.txt index 5e8332bca..52ee7d752 100644 --- a/samples/spawn-thread/wasm-apps/CMakeLists.txt +++ b/samples/spawn-thread/wasm-apps/CMakeLists.txt @@ -6,7 +6,11 @@ project(wasm-apps) set(WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../..) -set(CMAKE_SYSTEM_NAME Linux) +if (APPLE) + set (HAVE_FLAG_SEARCH_PATHS_FIRST 0) + set (CMAKE_C_LINK_FLAGS "") + set (CMAKE_CXX_LINK_FLAGS "") +endif () set(CMAKE_SYSTEM_PROCESSOR wasm32) set (CMAKE_SYSROOT ${WAMR_ROOT_DIR}/wamr-sdk/app/libc-builtin-sysroot) diff --git a/samples/wasm-c-api/CMakeLists.txt b/samples/wasm-c-api/CMakeLists.txt index 6e0a47222..dc55540fd 100644 --- a/samples/wasm-c-api/CMakeLists.txt +++ b/samples/wasm-c-api/CMakeLists.txt @@ -8,7 +8,10 @@ if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Release) endif() ################ runtime settings ################ -set(WAMR_BUILD_PLATFORM "linux") +string (TOLOWER ${CMAKE_HOST_SYSTEM_NAME} WAMR_BUILD_PLATFORM) +if (APPLE) + add_definitions(-DBH_PLATFORM_DARWIN) +endif () # Resetdefault linker flags set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") @@ -37,8 +40,16 @@ if(NOT DEFINED WAMR_BUILD_FAST_INTERP) endif() # compiling and linking flags -set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections -pie -fPIE") -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat -Wformat-security -mindirect-branch-register") +set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pie -fPIE") +if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang")) + set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") +endif () +set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat -Wformat-security") +if (WAMR_BUILD_TARGET MATCHES "X86_.*" OR WAMR_BUILD_TARGET STREQUAL "AMD_64") + if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang")) + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mindirect-branch-register") + endif () +endif () # build out vmlib set(WAMR_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../..) From 034606b0a986a43f6063368e1ac28587472710bd Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Wed, 26 Aug 2020 18:33:29 +0800 Subject: [PATCH 060/207] Change wasm app offset type from int32 to uint32 (#361) And fix some sign/unsigned conversion compilation warnings. --- core/iwasm/aot/aot_runtime.c | 41 +++++++------- core/iwasm/aot/aot_runtime.h | 20 +++---- core/iwasm/common/wasm_c_api.c | 20 +++---- core/iwasm/common/wasm_native.c | 2 +- core/iwasm/common/wasm_runtime_common.c | 49 ++++++++--------- core/iwasm/common/wasm_runtime_common.h | 34 ++++++------ core/iwasm/include/wasm_export.h | 28 +++++----- core/iwasm/interpreter/wasm.h | 3 +- core/iwasm/interpreter/wasm_loader.c | 6 ++- core/iwasm/interpreter/wasm_runtime.c | 36 ++++++------- core/iwasm/interpreter/wasm_runtime.h | 20 +++---- .../libc-builtin/libc_builtin_wrapper.c | 54 +++++++++---------- .../libraries/libc-wasi/libc_wasi_wrapper.c | 30 ++++++----- .../sandboxed-system-primitives/src/posix.c | 2 +- .../sandboxed-system-primitives/src/random.c | 2 +- .../platform/common/posix/posix_memmap.c | 6 +-- .../platform/common/posix/posix_thread.c | 3 +- doc/embed_wamr.md | 10 ++-- samples/basic/src/main.c | 2 +- .../src/platform/linux/display_indev.c | 2 +- 20 files changed, 191 insertions(+), 179 deletions(-) diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index 4081c673c..0b4fbfc73 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -885,7 +885,8 @@ aot_signal_handler(void *sig_addr) AOTModuleInstance *module_inst; AOTMemoryInstance *memory_inst; WASMJmpBuf *jmpbuf_node; - uint8 *mapped_mem_start_addr, *mapped_mem_end_addr; + uint8 *mapped_mem_start_addr = NULL; + uint8 *mapped_mem_end_addr = NULL; uint8 *stack_min_addr; uint32 page_size; uint32 guard_page_count = STACK_OVERFLOW_CHECK_GUARD_PAGE_COUNT; @@ -1265,7 +1266,7 @@ execute_free_function(AOTModuleInstance *module_inst, } } -int32 +uint32 aot_module_malloc(AOTModuleInstance *module_inst, uint32 size, void **p_native_addr) { @@ -1298,11 +1299,11 @@ aot_module_malloc(AOTModuleInstance *module_inst, uint32 size, } if (p_native_addr) *p_native_addr = addr; - return (int32)(addr - (uint8*)memory_inst->memory_data.ptr); + return (uint32)(addr - (uint8*)memory_inst->memory_data.ptr); } void -aot_module_free(AOTModuleInstance *module_inst, int32 ptr) +aot_module_free(AOTModuleInstance *module_inst, uint32 ptr) { AOTMemoryInstance *memory_inst = aot_get_default_memory(module_inst); AOTModule *module = (AOTModule *)module_inst->aot_module.ptr; @@ -1322,18 +1323,18 @@ aot_module_free(AOTModuleInstance *module_inst, int32 ptr) aot_lookup_function(module_inst, "free", "(i)i"); bh_assert(free_func); - execute_free_function(module_inst, free_func, (uint32)ptr); + execute_free_function(module_inst, free_func, ptr); } } } -int32 +uint32 aot_module_dup_data(AOTModuleInstance *module_inst, const char *src, uint32 size) { char *buffer; - int32 buffer_offset = aot_module_malloc(module_inst, size, - (void**)&buffer); + uint32 buffer_offset = aot_module_malloc(module_inst, size, + (void**)&buffer); if (buffer_offset != 0) { buffer = aot_addr_app_to_native(module_inst, buffer_offset); @@ -1344,15 +1345,15 @@ aot_module_dup_data(AOTModuleInstance *module_inst, bool aot_validate_app_addr(AOTModuleInstance *module_inst, - int32 app_offset, uint32 size) + uint32 app_offset, uint32 size) { AOTMemoryInstance *memory_inst = aot_get_default_memory(module_inst); /* integer overflow check */ - if((uint32)app_offset + size < (uint32)app_offset) { + if(app_offset + size < app_offset) { goto fail; } - if ((uint32)app_offset + size <= memory_inst->memory_data_size) { + if (app_offset + size <= memory_inst->memory_data_size) { return true; } fail: @@ -1381,10 +1382,10 @@ fail: } void * -aot_addr_app_to_native(AOTModuleInstance *module_inst, int32 app_offset) +aot_addr_app_to_native(AOTModuleInstance *module_inst, uint32 app_offset) { AOTMemoryInstance *memory_inst = aot_get_default_memory(module_inst); - uint8 *addr = (uint8 *)memory_inst->memory_data.ptr + (uint32)app_offset; + uint8 *addr = (uint8 *)memory_inst->memory_data.ptr + app_offset; if ((uint8 *)memory_inst->memory_data.ptr <= addr && addr < (uint8 *)memory_inst->memory_data_end.ptr) @@ -1392,7 +1393,7 @@ aot_addr_app_to_native(AOTModuleInstance *module_inst, int32 app_offset) return NULL; } -int32 +uint32 aot_addr_native_to_app(AOTModuleInstance *module_inst, void *native_ptr) { uint8 *addr = (uint8 *)native_ptr; @@ -1400,24 +1401,24 @@ aot_addr_native_to_app(AOTModuleInstance *module_inst, void *native_ptr) if ((uint8 *)memory_inst->memory_data.ptr <= addr && addr < (uint8 *)memory_inst->memory_data_end.ptr) - return (int32)(addr - (uint8 *)memory_inst->memory_data.ptr); + return (uint32)(addr - (uint8 *)memory_inst->memory_data.ptr); return 0; } bool aot_get_app_addr_range(AOTModuleInstance *module_inst, - int32 app_offset, - int32 *p_app_start_offset, - int32 *p_app_end_offset) + uint32 app_offset, + uint32 *p_app_start_offset, + uint32 *p_app_end_offset) { AOTMemoryInstance *memory_inst = aot_get_default_memory(module_inst); uint32 memory_data_size = memory_inst->memory_data_size; - if ((uint32)app_offset < memory_data_size) { + if (app_offset < memory_data_size) { if (p_app_start_offset) *p_app_start_offset = 0; if (p_app_end_offset) - *p_app_end_offset = (int32)memory_data_size; + *p_app_end_offset = memory_data_size; return true; } return false; diff --git a/core/iwasm/aot/aot_runtime.h b/core/iwasm/aot/aot_runtime.h index 8f7a774a7..1b49d13ed 100644 --- a/core/iwasm/aot/aot_runtime.h +++ b/core/iwasm/aot/aot_runtime.h @@ -275,7 +275,7 @@ typedef struct AOTModuleInstance { AOTPointer wasi_ctx; /* others */ - int32 temp_ret; + uint32 temp_ret; uint32 llvm_stack; uint32 default_wasm_stack_size; @@ -456,20 +456,20 @@ aot_get_exception(AOTModuleInstance *module_inst); void aot_clear_exception(AOTModuleInstance *module_inst); -int32 +uint32 aot_module_malloc(AOTModuleInstance *module_inst, uint32 size, void **p_native_addr); void -aot_module_free(AOTModuleInstance *module_inst, int32 ptr); +aot_module_free(AOTModuleInstance *module_inst, uint32 ptr); -int32 +uint32 aot_module_dup_data(AOTModuleInstance *module_inst, const char *src, uint32 size); bool aot_validate_app_addr(AOTModuleInstance *module_inst, - int32 app_offset, uint32 size); + uint32 app_offset, uint32 size); bool @@ -477,16 +477,16 @@ aot_validate_native_addr(AOTModuleInstance *module_inst, void *native_ptr, uint32 size); void * -aot_addr_app_to_native(AOTModuleInstance *module_inst, int32 app_offset); +aot_addr_app_to_native(AOTModuleInstance *module_inst, uint32 app_offset); -int32 +uint32 aot_addr_native_to_app(AOTModuleInstance *module_inst, void *native_ptr); bool aot_get_app_addr_range(AOTModuleInstance *module_inst, - int32 app_offset, - int32 *p_app_start_offset, - int32 *p_app_end_offset); + uint32 app_offset, + uint32 *p_app_start_offset, + uint32 *p_app_end_offset); bool aot_get_native_addr_range(AOTModuleInstance *module_inst, diff --git a/core/iwasm/common/wasm_c_api.c b/core/iwasm/common/wasm_c_api.c index 7439ef217..21d612c6d 100644 --- a/core/iwasm/common/wasm_c_api.c +++ b/core/iwasm/common/wasm_c_api.c @@ -1034,13 +1034,13 @@ argv_to_params(const uint64 *argv, switch (param_def->kind) { case WASM_I32: param->kind = WASM_I32; - param->of.i32 = *(uint32 *)argv_p; + param->of.i32 = *(int32 *)argv_p; argv_p = (uint32 *)argv_p + 1; argc++; break; case WASM_I64: param->kind = WASM_I64; - param->of.i64 = *(uint64 *)argv_p; + param->of.i64 = *(int64 *)argv_p; argv_p = (uint64 *)argv_p + 1; argc++; break; @@ -1081,12 +1081,12 @@ results_to_argv(const wasm_val_t *results, const wasm_val_t *result = results + i; switch (result_def->kind) { case WASM_I32: - *(uint32 *)argv_p = result->of.i32; + *(int32 *)argv_p = result->of.i32; argv_p = (uint32 *)argv_p + 1; argc++; break; case WASM_I64: - *(uint64 *)argv_p = result->of.i64; + *(int64 *)argv_p = result->of.i64; argv_p = (uint64 *)argv_p + 1; argc++; break; @@ -2099,7 +2099,7 @@ interp_link_table(const WASMModule *module_interp, return false; } -static int32 +static uint32 interp_link(const wasm_instance_t *inst, const WASMModule *module_interp, wasm_extern_t *imports[]) @@ -2157,7 +2157,7 @@ interp_link(const wasm_instance_t *inst, failed: LOG_DEBUG("%s failed", __FUNCTION__); - return -1; + return (uint32)-1; } static bool @@ -2296,7 +2296,7 @@ failed: return false; } -static int32 +static uint32 aot_link(const wasm_instance_t *inst, const AOTModule *module_aot, wasm_extern_t *imports[]) @@ -2346,7 +2346,7 @@ aot_link(const wasm_instance_t *inst, failed: LOG_DEBUG("%s failed", __FUNCTION__); - return -1; + return (uint32)-1; } static bool @@ -2419,7 +2419,7 @@ wasm_instance_new(wasm_store_t *store, char error[128] = { 0 }; const uint32 stack_size = 16 * 1024; const uint32 heap_size = 16 * 1024; - int32 import_count = 0; + uint32 import_count = 0; wasm_instance_t *instance = NULL; uint32 i = 0; (void)traps; @@ -2459,7 +2459,7 @@ wasm_instance_new(wasm_store_t *store, aot_link(instance, (AOTModule *)*module, (wasm_extern_t **)imports); #endif } - if (import_count < 0) { + if ((int32)import_count < 0) { goto failed; } diff --git a/core/iwasm/common/wasm_native.c b/core/iwasm/common/wasm_native.c index ed95b59b4..4712aba69 100644 --- a/core/iwasm/common/wasm_native.c +++ b/core/iwasm/common/wasm_native.c @@ -188,7 +188,7 @@ lookup_symbol(NativeSymbol *native_symbols, uint32 n_native_symbols, const char *symbol, const char **p_signature, void **p_attachment) { int low = 0, mid, ret; - int high = n_native_symbols - 1; + int high = (int32)n_native_symbols - 1; while (low <= high) { mid = (low + high) / 2; diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index 20e97f301..92ea9c299 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -957,7 +957,7 @@ wasm_runtime_get_custom_data(WASMModuleInstanceCommon *module_inst) return NULL; } -int32 +uint32 wasm_runtime_module_malloc(WASMModuleInstanceCommon *module_inst, uint32 size, void **p_native_addr) { @@ -975,7 +975,7 @@ wasm_runtime_module_malloc(WASMModuleInstanceCommon *module_inst, uint32 size, } void -wasm_runtime_module_free(WASMModuleInstanceCommon *module_inst, int32 ptr) +wasm_runtime_module_free(WASMModuleInstanceCommon *module_inst, uint32 ptr) { #if WASM_ENABLE_INTERP != 0 if (module_inst->module_type == Wasm_Module_Bytecode) { @@ -991,7 +991,7 @@ wasm_runtime_module_free(WASMModuleInstanceCommon *module_inst, int32 ptr) #endif } -int32 +uint32 wasm_runtime_module_dup_data(WASMModuleInstanceCommon *module_inst, const char *src, uint32 size) { @@ -1010,7 +1010,7 @@ wasm_runtime_module_dup_data(WASMModuleInstanceCommon *module_inst, bool wasm_runtime_validate_app_addr(WASMModuleInstanceCommon *module_inst, - int32 app_offset, uint32 size) + uint32 app_offset, uint32 size) { #if WASM_ENABLE_INTERP != 0 if (module_inst->module_type == Wasm_Module_Bytecode) @@ -1027,9 +1027,9 @@ wasm_runtime_validate_app_addr(WASMModuleInstanceCommon *module_inst, bool wasm_runtime_validate_app_str_addr(WASMModuleInstanceCommon *module_inst, - int32 app_str_offset) + uint32 app_str_offset) { - int32 app_end_offset; + uint32 app_end_offset; char *str, *str_end; if (!wasm_runtime_get_app_addr_range(module_inst, app_str_offset, @@ -1068,7 +1068,7 @@ wasm_runtime_validate_native_addr(WASMModuleInstanceCommon *module_inst, void * wasm_runtime_addr_app_to_native(WASMModuleInstanceCommon *module_inst, - int32 app_offset) + uint32 app_offset) { #if WASM_ENABLE_INTERP != 0 if (module_inst->module_type == Wasm_Module_Bytecode) @@ -1083,7 +1083,7 @@ wasm_runtime_addr_app_to_native(WASMModuleInstanceCommon *module_inst, return NULL; } -int32 +uint32 wasm_runtime_addr_native_to_app(WASMModuleInstanceCommon *module_inst, void *native_ptr) { @@ -1102,9 +1102,9 @@ wasm_runtime_addr_native_to_app(WASMModuleInstanceCommon *module_inst, bool wasm_runtime_get_app_addr_range(WASMModuleInstanceCommon *module_inst, - int32 app_offset, - int32 *p_app_start_offset, - int32 *p_app_end_offset) + uint32 app_offset, + uint32 *p_app_start_offset, + uint32 *p_app_end_offset) { #if WASM_ENABLE_INTERP != 0 if (module_inst->module_type == Wasm_Module_Bytecode) @@ -1250,7 +1250,7 @@ wasm_runtime_set_wasi_args(WASMModuleCommon *module, wasi_args->env = env_list; wasi_args->env_count = env_count; wasi_args->argv = argv; - wasi_args->argc = argc; + wasi_args->argc = (uint32)argc; } } @@ -1274,11 +1274,11 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, struct argv_environ_values *argv_environ; bool fd_table_inited = false, fd_prestats_inited = false; bool argv_environ_inited = false; - int32 offset_argv_offsets = 0, offset_env_offsets = 0; - int32 offset_argv_buf = 0, offset_env_buf = 0; - int32 offset_curfds = 0; - int32 offset_prestats = 0; - int32 offset_argv_environ = 0; + uint32 offset_argv_offsets = 0, offset_env_offsets = 0; + uint32 offset_argv_buf = 0, offset_env_buf = 0; + uint32 offset_curfds = 0; + uint32 offset_prestats = 0; + uint32 offset_argv_environ = 0; __wasi_fd_t wasm_fd = 3; int32 raw_fd; char *path, resolved_path[PATH_MAX]; @@ -1657,9 +1657,10 @@ wasm_application_execute_main(WASMModuleInstanceCommon *module_inst, uint32 argc1 = 0, argv1[2] = { 0 }; uint32 total_argv_size = 0; uint64 total_size; - int32 argv_buf_offset, i; + uint32 argv_buf_offset; + int32 i; char *argv_buf, *p, *p_end; - int32 *argv_offsets; + uint32 *argv_offsets; #if WASM_ENABLE_LIBC_WASI != 0 if (wasm_runtime_is_wasi_mode(module_inst)) { @@ -1724,12 +1725,12 @@ wasm_application_execute_main(WASMModuleInstanceCommon *module_inst, } p = argv_buf; - argv_offsets = (int32*)(p + total_argv_size); + argv_offsets = (uint32*)(p + total_argv_size); p_end = p + total_size; for (i = 0; i < argc; i++) { bh_memcpy_s(p, (uint32)(p_end - p), argv[i], (uint32)(strlen(argv[i]) + 1)); - argv_offsets[i] = argv_buf_offset + (int32)(p - argv_buf); + argv_offsets[i] = argv_buf_offset + (uint32)(p - argv_buf); p += strlen(argv[i]) + 1; } @@ -2173,7 +2174,7 @@ wasm_runtime_invoke_native_raw(WASMExecEnv *exec_env, void *func_ptr, NativeRawFuncPtr invokeNativeRaw = (NativeRawFuncPtr)func_ptr; uint64 argv_buf[16] = { 0 }, *argv1 = argv_buf, *argv_dst, size; uint32 *argv_src = argv, i, argc1, ptr_len; - int32 arg_i32; + uint32 arg_i32; bool ret = false; argc1 = func_type->param_count; @@ -2192,7 +2193,7 @@ wasm_runtime_invoke_native_raw(WASMExecEnv *exec_env, void *func_ptr, switch (func_type->types[i]) { case VALUE_TYPE_I32: { - *(int32*)argv_dst = arg_i32 = (int32)*argv_src++; + *(uint32*)argv_dst = arg_i32 = *argv_src++; if (signature) { if (signature[i + 1] == '*') { /* param is a pointer */ @@ -2729,7 +2730,7 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, int n_fps = 0; #endif - argc1 = 1 + MAX_REG_FLOATS + func_type->param_count + ext_ret_count; + argc1 = 1 + MAX_REG_FLOATS + (uint32)func_type->param_count + ext_ret_count; if (argc1 > sizeof(argv_buf) / sizeof(uint64)) { size = sizeof(uint64) * (uint64)argc1; if (!(argv1 = runtime_malloc((uint32)size, exec_env->module_inst, diff --git a/core/iwasm/common/wasm_runtime_common.h b/core/iwasm/common/wasm_runtime_common.h index 8d6767de5..ba03e59aa 100644 --- a/core/iwasm/common/wasm_runtime_common.h +++ b/core/iwasm/common/wasm_runtime_common.h @@ -49,13 +49,13 @@ typedef struct WASIContext { allocated from app's heap, and the heap space may be re-allocated after memory.grow opcode is executed, the original native address cannot be accessed again. */ - int32 curfds_offset; - int32 prestats_offset; - int32 argv_environ_offset; - int32 argv_buf_offset; - int32 argv_offsets_offset; - int32 env_buf_offset; - int32 env_offsets_offset; + uint32 curfds_offset; + uint32 prestats_offset; + uint32 argv_environ_offset; + uint32 argv_buf_offset; + uint32 argv_offsets_offset; + uint32 env_buf_offset; + uint32 env_offsets_offset; } WASIContext; #endif @@ -227,28 +227,28 @@ void * wasm_runtime_get_custom_data(WASMModuleInstanceCommon *module_inst); /* See wasm_export.h for description */ -int32 +uint32 wasm_runtime_module_malloc(WASMModuleInstanceCommon *module_inst, uint32 size, void **p_native_addr); /* See wasm_export.h for description */ void -wasm_runtime_module_free(WASMModuleInstanceCommon *module_inst, int32 ptr); +wasm_runtime_module_free(WASMModuleInstanceCommon *module_inst, uint32 ptr); /* See wasm_export.h for description */ -int32 +uint32 wasm_runtime_module_dup_data(WASMModuleInstanceCommon *module_inst, const char *src, uint32 size); /* See wasm_export.h for description */ bool wasm_runtime_validate_app_addr(WASMModuleInstanceCommon *module_inst, - int32 app_offset, uint32 size); + uint32 app_offset, uint32 size); /* See wasm_export.h for description */ bool wasm_runtime_validate_app_str_addr(WASMModuleInstanceCommon *module_inst, - int32 app_str_offset); + uint32 app_str_offset); /* See wasm_export.h for description */ bool @@ -258,19 +258,19 @@ wasm_runtime_validate_native_addr(WASMModuleInstanceCommon *module_inst, /* See wasm_export.h for description */ void * wasm_runtime_addr_app_to_native(WASMModuleInstanceCommon *module_inst, - int32 app_offset); + uint32 app_offset); /* See wasm_export.h for description */ -int32 +uint32 wasm_runtime_addr_native_to_app(WASMModuleInstanceCommon *module_inst, void *native_ptr); /* See wasm_export.h for description */ bool wasm_runtime_get_app_addr_range(WASMModuleInstanceCommon *module_inst, - int32 app_offset, - int32 *p_app_start_offset, - int32 *p_app_end_offset); + uint32 app_offset, + uint32 *p_app_start_offset, + uint32 *p_app_end_offset); /* See wasm_export.h for description */ bool diff --git a/core/iwasm/include/wasm_export.h b/core/iwasm/include/wasm_export.h index 24f72f990..79ec96f63 100644 --- a/core/iwasm/include/wasm_export.h +++ b/core/iwasm/include/wasm_export.h @@ -476,11 +476,11 @@ wasm_runtime_get_custom_data(wasm_module_inst_t module_inst); * if it is not NULL, and return NULL if memory malloc failed * * @return the allocated memory address, which is a relative offset to the - * base address of the module instance's memory space, the value range - * is (-heap_size, 0). Note that it is not an absolute address. + * base address of the module instance's memory space. Note that + * it is not an absolute address. * Return non-zero if success, zero if failed. */ -int32_t +uint32_t wasm_runtime_module_malloc(wasm_module_inst_t module_inst, uint32_t size, void **p_native_addr); @@ -491,7 +491,7 @@ wasm_runtime_module_malloc(wasm_module_inst_t module_inst, uint32_t size, * @param ptr the pointer to free */ void -wasm_runtime_module_free(wasm_module_inst_t module_inst, int32_t ptr); +wasm_runtime_module_free(wasm_module_inst_t module_inst, uint32_t ptr); /** * Allocate memory from the heap of WASM module instance and initialize @@ -502,11 +502,11 @@ wasm_runtime_module_free(wasm_module_inst_t module_inst, int32_t ptr); * @param size the size of the source data * * @return the allocated memory address, which is a relative offset to the - * base address of the module instance's memory space, the value range - * is (-heap_size, 0). Note that it is not an absolute address. + * base address of the module instance's memory space. Note that + * it is not an absolute address. * Return non-zero if success, zero if failed. */ -int32_t +uint32_t wasm_runtime_module_dup_data(wasm_module_inst_t module_inst, const char *src, uint32_t size); @@ -523,7 +523,7 @@ wasm_runtime_module_dup_data(wasm_module_inst_t module_inst, */ bool wasm_runtime_validate_app_addr(wasm_module_inst_t module_inst, - int32_t app_offset, uint32_t size); + uint32_t app_offset, uint32_t size); /** * Similar to wasm_runtime_validate_app_addr(), except that the size parameter @@ -540,7 +540,7 @@ wasm_runtime_validate_app_addr(wasm_module_inst_t module_inst, */ bool wasm_runtime_validate_app_str_addr(wasm_module_inst_t module_inst, - int32_t app_str_offset); + uint32_t app_str_offset); /** * Validate the native address, check whether it belongs to WASM module @@ -568,7 +568,7 @@ wasm_runtime_validate_native_addr(wasm_module_inst_t module_inst, */ void* wasm_runtime_addr_app_to_native(wasm_module_inst_t module_inst, - int32_t app_offset); + uint32_t app_offset); /** * Convert native address(absolute address) to app address(relative address) @@ -578,7 +578,7 @@ wasm_runtime_addr_app_to_native(wasm_module_inst_t module_inst, * * @return the app address converted */ -int32_t +uint32_t wasm_runtime_addr_native_to_app(wasm_module_inst_t module_inst, void *native_ptr); @@ -594,9 +594,9 @@ wasm_runtime_addr_native_to_app(wasm_module_inst_t module_inst, */ bool wasm_runtime_get_app_addr_range(wasm_module_inst_t module_inst, - int32_t app_offset, - int32_t *p_app_start_offset, - int32_t *p_app_end_offset); + uint32_t app_offset, + uint32_t *p_app_start_offset, + uint32_t *p_app_end_offset); /** * Get the native address range (absolute address) that a native address belongs to diff --git a/core/iwasm/interpreter/wasm.h b/core/iwasm/interpreter/wasm.h index 9fa2eda9b..3696c2e81 100644 --- a/core/iwasm/interpreter/wasm.h +++ b/core/iwasm/interpreter/wasm.h @@ -479,7 +479,8 @@ wasm_type_equal(const WASMType *type1, const WASMType *type2) return (type1->param_count == type2->param_count && type1->result_count == type2->result_count && memcmp(type1->types, type2->types, - type1->param_count + type1->result_count) == 0) + (uint32)(type1->param_count + + type1->result_count)) == 0) ? true : false; } diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index 7156231b9..21e6b2f2e 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -1191,10 +1191,14 @@ load_memory(const uint8 **p_buf, const uint8 *buf_end, WASMMemory *memory, return false; } #else - if (memory->flags > 3 || memory->flags == 2) { + if (memory->flags > 3) { set_error_buf(error_buf, error_buf_size, "integer too large"); return false; } + else if (memory->flags == 2) { + set_error_buf(error_buf, error_buf_size, "shared memory must have maximum"); + return false; + } #endif read_leb_uint32(p, p_end, memory->init_page_count); diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index d89e68e4b..dee8ea986 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -1562,7 +1562,7 @@ wasm_get_exception(WASMModuleInstance *module_inst) return module_inst->cur_exception; } -int32 +uint32 wasm_module_malloc(WASMModuleInstance *module_inst, uint32 size, void **p_native_addr) { @@ -1589,15 +1589,15 @@ wasm_module_malloc(WASMModuleInstance *module_inst, uint32 size, } if (p_native_addr) *p_native_addr = addr; - return (int32)(addr - memory->memory_data); + return (uint32)(addr - memory->memory_data); } void -wasm_module_free(WASMModuleInstance *module_inst, int32 ptr) +wasm_module_free(WASMModuleInstance *module_inst, uint32 ptr) { if (ptr) { WASMMemoryInstance *memory = module_inst->default_memory; - uint8 *addr = memory->memory_data + (uint32)ptr; + uint8 *addr = memory->memory_data + ptr; if (memory->heap_handle && memory->heap_data <= addr @@ -1610,18 +1610,18 @@ wasm_module_free(WASMModuleInstance *module_inst, int32 ptr) && addr < memory->memory_data_end) { execute_free_function(module_inst, module_inst->free_function, - (uint32)ptr); + ptr); } } } -int32 +uint32 wasm_module_dup_data(WASMModuleInstance *module_inst, const char *src, uint32 size) { char *buffer; - int32 buffer_offset = wasm_module_malloc(module_inst, size, - (void**)&buffer); + uint32 buffer_offset = wasm_module_malloc(module_inst, size, + (void**)&buffer); if (buffer_offset != 0) { buffer = wasm_addr_app_to_native(module_inst, buffer_offset); bh_memcpy_s(buffer, size, src, size); @@ -1631,18 +1631,18 @@ wasm_module_dup_data(WASMModuleInstance *module_inst, bool wasm_validate_app_addr(WASMModuleInstance *module_inst, - int32 app_offset, uint32 size) + uint32 app_offset, uint32 size) { WASMMemoryInstance *memory = module_inst->default_memory; uint32 memory_data_size = memory->num_bytes_per_page * memory->cur_page_count; /* integer overflow check */ - if ((uint32)app_offset + size < (uint32)app_offset) { + if (app_offset + size < app_offset) { goto fail; } - if ((uint32)app_offset + size <= memory_data_size) { + if (app_offset + size <= memory_data_size) { return true; } fail: @@ -1673,7 +1673,7 @@ fail: void * wasm_addr_app_to_native(WASMModuleInstance *module_inst, - int32 app_offset) + uint32 app_offset) { WASMMemoryInstance *memory = module_inst->default_memory; uint8 *addr = memory->memory_data + app_offset; @@ -1684,7 +1684,7 @@ wasm_addr_app_to_native(WASMModuleInstance *module_inst, return NULL; } -int32 +uint32 wasm_addr_native_to_app(WASMModuleInstance *module_inst, void *native_ptr) { @@ -1693,21 +1693,21 @@ wasm_addr_native_to_app(WASMModuleInstance *module_inst, if (memory->memory_data <= addr && addr < memory->memory_data_end) - return (int32)(addr - memory->memory_data); + return (uint32)(addr - memory->memory_data); return 0; } bool wasm_get_app_addr_range(WASMModuleInstance *module_inst, - int32 app_offset, - int32 *p_app_start_offset, - int32 *p_app_end_offset) + uint32 app_offset, + uint32 *p_app_start_offset, + uint32 *p_app_end_offset) { WASMMemoryInstance *memory = module_inst->default_memory; uint32 memory_data_size = memory->num_bytes_per_page * memory->cur_page_count; - if ((uint32)app_offset < memory_data_size) { + if (app_offset < memory_data_size) { if (p_app_start_offset) *p_app_start_offset = 0; if (p_app_end_offset) diff --git a/core/iwasm/interpreter/wasm_runtime.h b/core/iwasm/interpreter/wasm_runtime.h index 2750e69c7..1682c3903 100644 --- a/core/iwasm/interpreter/wasm_runtime.h +++ b/core/iwasm/interpreter/wasm_runtime.h @@ -313,24 +313,24 @@ wasm_set_exception(WASMModuleInstance *module, const char *exception); const char* wasm_get_exception(WASMModuleInstance *module); -int32 +uint32 wasm_module_malloc(WASMModuleInstance *module_inst, uint32 size, void **p_native_addr); void -wasm_module_free(WASMModuleInstance *module_inst, int32 ptr); +wasm_module_free(WASMModuleInstance *module_inst, uint32 ptr); -int32 +uint32 wasm_module_dup_data(WASMModuleInstance *module_inst, const char *src, uint32 size); bool wasm_validate_app_addr(WASMModuleInstance *module_inst, - int32 app_offset, uint32 size); + uint32 app_offset, uint32 size); bool wasm_validate_app_str_addr(WASMModuleInstance *module_inst, - int32 app_offset); + uint32 app_offset); bool wasm_validate_native_addr(WASMModuleInstance *module_inst, @@ -338,17 +338,17 @@ wasm_validate_native_addr(WASMModuleInstance *module_inst, void * wasm_addr_app_to_native(WASMModuleInstance *module_inst, - int32 app_offset); + uint32 app_offset); -int32 +uint32 wasm_addr_native_to_app(WASMModuleInstance *module_inst, void *native_ptr); bool wasm_get_app_addr_range(WASMModuleInstance *module_inst, - int32 app_offset, - int32 *p_app_start_offset, - int32 *p_app_end_offset); + uint32 app_offset, + uint32 *p_app_start_offset, + uint32 *p_app_end_offset); bool wasm_get_native_addr_range(WASMModuleInstance *module_inst, diff --git a/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c b/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c index 4bdf55000..c00fd02d3 100644 --- a/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c +++ b/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c @@ -321,10 +321,10 @@ handle_1_to_9: case 's': { char *s; char *start; - int32 s_offset; + uint32 s_offset; CHECK_VA_ARG(ap, int32); - s_offset = _va_arg(ap, int32); + s_offset = _va_arg(ap, uint32); if (!validate_app_str_addr(s_offset)) { return false; @@ -494,13 +494,13 @@ putchar_wrapper(wasm_exec_env_t exec_env, int c) return 1; } -static int32 +static uint32 strdup_wrapper(wasm_exec_env_t exec_env, const char *str) { wasm_module_inst_t module_inst = get_module_inst(exec_env); char *str_ret; uint32 len; - int32 str_ret_offset = 0; + uint32 str_ret_offset = 0; /* str has been checked by runtime */ if (str) { @@ -515,7 +515,7 @@ strdup_wrapper(wasm_exec_env_t exec_env, const char *str) return str_ret_offset; } -static int32 +static uint32 _strdup_wrapper(wasm_exec_env_t exec_env, const char *str) { return strdup_wrapper(exec_env, str); @@ -534,12 +534,12 @@ memcmp_wrapper(wasm_exec_env_t exec_env, return memcmp(s1, s2, size); } -static int32 +static uint32 memcpy_wrapper(wasm_exec_env_t exec_env, void *dst, const void *src, uint32 size) { wasm_module_inst_t module_inst = get_module_inst(exec_env); - int32 dst_offset = addr_native_to_app(dst); + uint32 dst_offset = addr_native_to_app(dst); if (size == 0) return dst_offset; @@ -552,12 +552,12 @@ memcpy_wrapper(wasm_exec_env_t exec_env, return dst_offset; } -static int32 +static uint32 memmove_wrapper(wasm_exec_env_t exec_env, void *dst, void *src, uint32 size) { wasm_module_inst_t module_inst = get_module_inst(exec_env); - int32 dst_offset = addr_native_to_app(dst); + uint32 dst_offset = addr_native_to_app(dst); if (size == 0) return dst_offset; @@ -570,12 +570,12 @@ memmove_wrapper(wasm_exec_env_t exec_env, return dst_offset; } -static int32 +static uint32 memset_wrapper(wasm_exec_env_t exec_env, void *s, int32 c, uint32 size) { wasm_module_inst_t module_inst = get_module_inst(exec_env); - int32 s_offset = addr_native_to_app(s); + uint32 s_offset = addr_native_to_app(s); if (!validate_native_addr(s, size)) return s_offset; @@ -584,7 +584,7 @@ memset_wrapper(wasm_exec_env_t exec_env, return s_offset; } -static int32 +static uint32 strchr_wrapper(wasm_exec_env_t exec_env, const char *s, int32 c) { @@ -617,7 +617,7 @@ strncmp_wrapper(wasm_exec_env_t exec_env, return strncmp(s1, s2, size); } -static int32 +static uint32 strcpy_wrapper(wasm_exec_env_t exec_env, char *dst, const char *src) { wasm_module_inst_t module_inst = get_module_inst(exec_env); @@ -631,7 +631,7 @@ strcpy_wrapper(wasm_exec_env_t exec_env, char *dst, const char *src) return addr_native_to_app(dst); } -static int32 +static uint32 strncpy_wrapper(wasm_exec_env_t exec_env, char *dst, const char *src, uint32 size) { @@ -652,19 +652,19 @@ strlen_wrapper(wasm_exec_env_t exec_env, const char *s) return (uint32)strlen(s); } -static int32 +static uint32 malloc_wrapper(wasm_exec_env_t exec_env, uint32 size) { wasm_module_inst_t module_inst = get_module_inst(exec_env); return module_malloc(size, NULL); } -static int32 +static uint32 calloc_wrapper(wasm_exec_env_t exec_env, uint32 nmemb, uint32 size) { wasm_module_inst_t module_inst = get_module_inst(exec_env); uint64 total_size = (uint64) nmemb * (uint64) size; - int32 ret_offset = 0; + uint32 ret_offset = 0; uint8 *ret_ptr; if (total_size >= UINT32_MAX) @@ -672,7 +672,7 @@ calloc_wrapper(wasm_exec_env_t exec_env, uint32 nmemb, uint32 size) ret_offset = module_malloc((uint32)total_size, (void**)&ret_ptr); if (ret_offset) { - memset(ret_ptr, 0, (uint32) total_size); + memset(ret_ptr, 0, (uint32)total_size); } return ret_offset; @@ -717,7 +717,7 @@ strtol_wrapper(wasm_exec_env_t exec_env, return 0; num = (int32)strtol(nptr, endptr, base); - *(int32*)endptr = addr_native_to_app(*endptr); + *(uint32*)endptr = addr_native_to_app(*endptr); return num; } @@ -734,12 +734,12 @@ strtoul_wrapper(wasm_exec_env_t exec_env, return 0; num = (uint32)strtoul(nptr, endptr, base); - *(int32 *)endptr = addr_native_to_app(*endptr); + *(uint32 *)endptr = addr_native_to_app(*endptr); return num; } -static int32 +static uint32 memchr_wrapper(wasm_exec_env_t exec_env, const void *s, int32 c, uint32 n) { @@ -755,7 +755,7 @@ memchr_wrapper(wasm_exec_env_t exec_env, static int32 strncasecmp_wrapper(wasm_exec_env_t exec_env, - const char *s1, const char *s2, int32 n) + const char *s1, const char *s2, uint32 n) { /* s1 and s2 have been checked by runtime */ return strncasecmp(s1, s2, n); @@ -777,7 +777,7 @@ strcspn_wrapper(wasm_exec_env_t exec_env, return (uint32)strcspn(s, reject); } -static int32 +static uint32 strstr_wrapper(wasm_exec_env_t exec_env, const char *s, const char *find) { @@ -934,12 +934,12 @@ llvm_stacksave_wrapper(wasm_exec_env_t exec_env) return wasm_runtime_get_llvm_stack(module_inst); } -static int32 +static uint32 emscripten_memcpy_big_wrapper(wasm_exec_env_t exec_env, void *dst, const void *src, uint32 size) { wasm_module_inst_t module_inst = get_module_inst(exec_env); - int32 dst_offset = addr_native_to_app(dst); + uint32 dst_offset = addr_native_to_app(dst); /* src has been checked by runtime */ if (!validate_native_addr(dst, size)) @@ -976,12 +976,12 @@ nullFunc_X_wrapper(wasm_exec_env_t exec_env, int32 code) wasm_runtime_set_exception(module_inst, buf); } -static int32 +static uint32 __cxa_allocate_exception_wrapper(wasm_exec_env_t exec_env, uint32 thrown_size) { wasm_module_inst_t module_inst = get_module_inst(exec_env); - int32 exception = module_malloc(thrown_size, NULL); + uint32 exception = module_malloc(thrown_size, NULL); if (!exception) return 0; diff --git a/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c b/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c index b2da6f3b9..6a968c482 100644 --- a/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c +++ b/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c @@ -40,14 +40,18 @@ typedef struct wasi_prestat_app { } wasi_prestat_app_t; typedef struct iovec_app { - int32 buf_offset; + uint32 buf_offset; uint32 buf_len; } iovec_app_t; typedef struct WASIContext { - int32 curfds_offset; - int32 prestats_offset; - int32 argv_environ_offset; + uint32 curfds_offset; + uint32 prestats_offset; + uint32 argv_environ_offset; + uint32 argv_buf_offset; + uint32 argv_offsets_offset; + uint32 env_buf_offset; + uint32 env_offsets_offset; } *wasi_ctx_t; wasi_ctx_t @@ -87,7 +91,7 @@ wasi_ctx_get_prestats(wasm_module_inst_t module_inst, } static wasi_errno_t -wasi_args_get(wasm_exec_env_t exec_env, int32 *argv_offsets, char *argv_buf) +wasi_args_get(wasm_exec_env_t exec_env, uint32 *argv_offsets, char *argv_buf) { wasm_module_inst_t module_inst = get_module_inst(exec_env); wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); @@ -191,7 +195,7 @@ wasi_clock_time_get(wasm_exec_env_t exec_env, static wasi_errno_t wasi_environ_get(wasm_exec_env_t exec_env, - int32 *environ_offsets, char *environ_buf) + uint32 *environ_offsets, char *environ_buf) { wasm_module_inst_t module_inst = get_module_inst(exec_env); wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); @@ -344,7 +348,7 @@ wasi_fd_pread(wasm_exec_env_t exec_env, wasi_iovec_t *iovec, *iovec_begin; uint64 total_size; size_t nread; - int32 mem; + uint32 mem; uint32 i; wasi_errno_t err; @@ -399,7 +403,7 @@ wasi_fd_pwrite(wasm_exec_env_t exec_env, wasi_ciovec_t *ciovec, *ciovec_begin; uint64 total_size; size_t nwritten; - int32 mem; + uint32 mem; uint32 i; wasi_errno_t err; @@ -455,7 +459,7 @@ wasi_fd_read(wasm_exec_env_t exec_env, uint64 total_size; size_t nread; uint32 i; - int32 mem; + uint32 mem; wasi_errno_t err; if (!wasi_ctx) @@ -626,7 +630,7 @@ wasi_fd_write(wasm_exec_env_t exec_env, wasi_fd_t fd, wasi_ciovec_t *ciovec, *ciovec_begin; uint64 total_size; size_t nwritten; - int32 mem; + uint32 mem; uint32 i; wasi_errno_t err; @@ -753,7 +757,7 @@ wasi_path_open(wasm_exec_env_t exec_env, wasm_module_inst_t module_inst = get_module_inst(exec_env); wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); - wasi_fd_t fd = -1; /* set fd_app -1 if path open failed */ + wasi_fd_t fd = (wasi_fd_t)-1; /* set fd_app -1 if path open failed */ wasi_errno_t err; if (!wasi_ctx) @@ -1052,7 +1056,7 @@ wasi_sock_recv(wasm_exec_env_t exec_env, wasi_iovec_t *iovec, *iovec_begin; uint64 total_size; size_t ro_datalen; - int32 mem; + uint32 mem; uint32 i; wasi_errno_t err; @@ -1112,7 +1116,7 @@ wasi_sock_send(wasm_exec_env_t exec_env, wasi_ciovec_t *ciovec, *ciovec_begin; uint64 total_size; size_t so_datalen; - int32 mem; + uint32 mem; uint32 i; wasi_errno_t err; diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c index f456d681e..90978a175 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c @@ -660,7 +660,7 @@ static __wasi_errno_t fd_table_insert_fd( if (type == __WASI_FILETYPE_DIRECTORY) { if (!mutex_init(&fo->directory.lock)) { fd_object_release(fo); - return -1; + return (__wasi_errno_t)-1; } fo->directory.handle = NULL; } diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/random.c b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/random.c index 927df140e..042882895 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/random.c +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/random.c @@ -37,7 +37,7 @@ void random_buf(void *buf, size_t len) { if ((size_t)x == len) return; buf = (void *)((unsigned char *)buf + x); - len -= x; + len -= (size_t)x; } } diff --git a/core/shared/platform/common/posix/posix_memmap.c b/core/shared/platform/common/posix/posix_memmap.c index 0bbea2766..825afefcd 100644 --- a/core/shared/platform/common/posix/posix_memmap.c +++ b/core/shared/platform/common/posix/posix_memmap.c @@ -14,7 +14,7 @@ os_mmap(void *hint, size_t size, int prot, int flags) uint8 *addr; uint32 i; - page_size = getpagesize(); + page_size = (uint64)getpagesize(); request_size = (size + page_size - 1) & ~(page_size - 1); if ((size_t)request_size < size) @@ -60,7 +60,7 @@ os_mmap(void *hint, size_t size, int prot, int flags) void os_munmap(void *addr, size_t size) { - uint64 page_size = getpagesize(); + uint64 page_size = (uint64)getpagesize(); uint64 request_size = (size + page_size - 1) & ~(page_size - 1); if (addr) { @@ -75,7 +75,7 @@ int os_mprotect(void *addr, size_t size, int prot) { int map_prot = PROT_NONE; - uint64 page_size = getpagesize(); + uint64 page_size = (uint64)getpagesize(); uint64 request_size = (size + page_size - 1) & ~(page_size - 1); if (!addr) diff --git a/core/shared/platform/common/posix/posix_thread.c b/core/shared/platform/common/posix/posix_thread.c index db9adbf61..5f1bcf13b 100644 --- a/core/shared/platform/common/posix/posix_thread.c +++ b/core/shared/platform/common/posix/posix_thread.c @@ -242,7 +242,8 @@ uint8 *os_thread_get_stack_boundary() uint8 *addr = NULL; size_t stack_size, guard_size; int page_size = getpagesize(); - size_t max_stack_size = (APP_THREAD_STACK_SIZE_MAX + page_size - 1) + size_t max_stack_size = (size_t) + (APP_THREAD_STACK_SIZE_MAX + page_size - 1) & ~(page_size - 1); if (max_stack_size < APP_THREAD_STACK_SIZE_DEFAULT) diff --git a/doc/embed_wamr.md b/doc/embed_wamr.md index a9524ed5d..4503e84c5 100644 --- a/doc/embed_wamr.md +++ b/doc/embed_wamr.md @@ -143,7 +143,7 @@ There are two runtime APIs available for this purpose. * p_native_addr: return the native address of allocated memory * size: the buffer size to allocate */ -int32_t +uint32_t wasm_runtime_module_malloc(wasm_module_inst_t module_inst, uint32_t size, void **p_native_addr); @@ -155,20 +155,20 @@ wasm_runtime_module_malloc(wasm_module_inst_t module_inst, * src: the native buffer address * size: the size of buffer to be allocated and copy data */ -int32 +uint32_t wasm_runtime_module_dup_data(WASMModuleInstanceCommon *module_inst, - const char *src, uint32 size); + const char *src, uint32_t size); /* free the memory allocated from module memory space */ void -wasm_runtime_module_free(wasm_module_inst_t module_inst, int32_t ptr); +wasm_runtime_module_free(wasm_module_inst_t module_inst, uint32_t ptr); ``` Usage sample: ```c char * buffer = NULL; -int32_t buffer_for_wasm; +uint32_t buffer_for_wasm; buffer_for_wasm = wasm_runtime_module_malloc(module_inst, 100, &buffer); if (buffer_for_wasm != 0) { diff --git a/samples/basic/src/main.c b/samples/basic/src/main.c index 7411434f6..e2b5dd6bb 100644 --- a/samples/basic/src/main.c +++ b/samples/basic/src/main.c @@ -32,7 +32,7 @@ int main(int argc, char *argv_main[]) wasm_function_inst_t func = NULL; wasm_function_inst_t func2 = NULL; char * native_buffer = NULL; - int32_t wasm_buffer = 0; + uint32_t wasm_buffer = 0; RuntimeInitArgs init_args; memset(&init_args, 0, sizeof(RuntimeInitArgs)); diff --git a/samples/littlevgl/vgl-wasm-runtime/src/platform/linux/display_indev.c b/samples/littlevgl/vgl-wasm-runtime/src/platform/linux/display_indev.c index 956d55d0c..93ee7a430 100644 --- a/samples/littlevgl/vgl-wasm-runtime/src/platform/linux/display_indev.c +++ b/samples/littlevgl/vgl-wasm-runtime/src/platform/linux/display_indev.c @@ -183,7 +183,7 @@ display_map(wasm_exec_env_t exec_env, typedef struct display_input_data { lv_point_t point; - int32 user_data_offset; + uint32 user_data_offset; uint8 state; } display_input_data; From e113298d7f366795eadc58df1121f700cea235a1 Mon Sep 17 00:00:00 2001 From: Xu Jun <693788454@qq.com> Date: Tue, 1 Sep 2020 16:00:15 +0800 Subject: [PATCH 061/207] use llvm release 10.x (#365) --- product-mini/platforms/linux/build_llvm.sh | 2 +- wamr-compiler/build_llvm.sh | 2 +- wamr-compiler/build_llvm_xtensa.sh | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/product-mini/platforms/linux/build_llvm.sh b/product-mini/platforms/linux/build_llvm.sh index 19c589811..7821eeedf 100755 --- a/product-mini/platforms/linux/build_llvm.sh +++ b/product-mini/platforms/linux/build_llvm.sh @@ -8,7 +8,7 @@ DEPS_DIR=${PWD}/../../../core/deps cd ${DEPS_DIR} if [ ! -d "llvm" ]; then echo "Clone llvm to core/deps/ .." - git clone --depth 1 https://github.com/llvm/llvm-project.git llvm + git clone --depth 1 --branch release/10.x https://github.com/llvm/llvm-project.git llvm fi cd llvm diff --git a/wamr-compiler/build_llvm.sh b/wamr-compiler/build_llvm.sh index a84446f3a..98f7a6767 100755 --- a/wamr-compiler/build_llvm.sh +++ b/wamr-compiler/build_llvm.sh @@ -8,7 +8,7 @@ DEPS_DIR=${PWD}/../core/deps cd ${DEPS_DIR} if [ ! -d "llvm" ]; then echo "Clone llvm to core/deps/ .." - git clone --depth 1 https://github.com/llvm/llvm-project.git llvm + git clone --depth 1 --branch release/10.x https://github.com/llvm/llvm-project.git llvm fi cd llvm diff --git a/wamr-compiler/build_llvm_xtensa.sh b/wamr-compiler/build_llvm_xtensa.sh index c5b155174..c8bb9b83d 100755 --- a/wamr-compiler/build_llvm_xtensa.sh +++ b/wamr-compiler/build_llvm_xtensa.sh @@ -8,7 +8,7 @@ DEPS_DIR=${PWD}/../core/deps cd ${DEPS_DIR} if [ ! -d "llvm" ]; then echo "Clone llvm Xtensa to core/deps/ .." - git clone https://github.com/espressif/llvm-project.git llvm + git clone --depth 1 --branch xtensa_release_10.0.1 https://github.com/espressif/llvm-project.git llvm fi cd llvm From c8df3f6eedbc06d802496a787a7f59cc72663b5c Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Thu, 3 Sep 2020 11:16:38 +0800 Subject: [PATCH 062/207] Fix app heap migrate issue and aot compilation warning (#368) --- core/iwasm/compilation/aot_emit_const.c | 2 +- core/shared/mem-alloc/ems/ems_kfc.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/iwasm/compilation/aot_emit_const.c b/core/iwasm/compilation/aot_emit_const.c index 5e9085b89..a862a7d3a 100644 --- a/core/iwasm/compilation/aot_emit_const.c +++ b/core/iwasm/compilation/aot_emit_const.c @@ -45,7 +45,7 @@ aot_compile_op_f32_const(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, int32 i32_const; memcpy(&i32_const, &f32_const, sizeof(int32)); if (!(alloca = LLVMBuildAlloca(comp_ctx->builder, - INT32_PTR_TYPE, "i32_ptr"))) { + I32_TYPE, "i32_ptr"))) { aot_set_last_error("llvm build alloca failed."); return false; } diff --git a/core/shared/mem-alloc/ems/ems_kfc.c b/core/shared/mem-alloc/ems/ems_kfc.c index 13a6aa6bd..8e389ca8e 100644 --- a/core/shared/mem-alloc/ems/ems_kfc.c +++ b/core/shared/mem-alloc/ems/ems_kfc.c @@ -131,7 +131,7 @@ gc_migrate(gc_handle_t handle, gc_handle_t handle_old) size = hmu_get_size(cur); bh_assert(size > 0); - if (!HMU_IS_FC_NORMAL(size)) { + if (hmu_get_ut(cur) == HMU_FC && !HMU_IS_FC_NORMAL(size)) { tree_node = (hmu_tree_node_t *)cur; adjust_ptr((uint8**)&tree_node->left, offset); adjust_ptr((uint8**)&tree_node->right, offset); From 2e0cef3ef135b8a0c41e08d4df27366e1915e4e2 Mon Sep 17 00:00:00 2001 From: Xu Jun <693788454@qq.com> Date: Sat, 5 Sep 2020 14:48:08 +0800 Subject: [PATCH 063/207] fix exec_env not checked issue, export __heap_base and __data_end in sample to decrease memory usage (#371) --- core/iwasm/common/wasm_exec_env.c | 11 ++++++----- core/iwasm/common/wasm_native.c | 4 ++-- core/iwasm/common/wasm_runtime_common.c | 16 ++++++++-------- samples/simple/build.sh | 1 + 4 files changed, 17 insertions(+), 15 deletions(-) diff --git a/core/iwasm/common/wasm_exec_env.c b/core/iwasm/common/wasm_exec_env.c index 4975b4d2c..631d449b7 100644 --- a/core/iwasm/common/wasm_exec_env.c +++ b/core/iwasm/common/wasm_exec_env.c @@ -84,16 +84,17 @@ WASMExecEnv * wasm_exec_env_create(struct WASMModuleInstanceCommon *module_inst, uint32 stack_size) { - WASMExecEnv *exec_env = wasm_exec_env_create_internal(module_inst, - stack_size); + WASMExecEnv *exec_env = + wasm_exec_env_create_internal(module_inst, stack_size); + + if (!exec_env) + return NULL; + /* Set the aux_stack_boundary to 0 */ exec_env->aux_stack_boundary = 0; #if WASM_ENABLE_THREAD_MGR != 0 WASMCluster *cluster; - if (!exec_env) - return NULL; - /* Create a new cluster for this exec_env */ cluster = wasm_cluster_create(exec_env); if (!cluster) { diff --git a/core/iwasm/common/wasm_native.c b/core/iwasm/common/wasm_native.c index 4712aba69..c90007665 100644 --- a/core/iwasm/common/wasm_native.c +++ b/core/iwasm/common/wasm_native.c @@ -335,14 +335,14 @@ wasm_native_init() #if WASM_ENABLE_LIBC_BUILTIN != 0 n_native_symbols = get_libc_builtin_export_apis(&native_symbols); if (!wasm_native_register_natives("env", - native_symbols, n_native_symbols)) + native_symbols, n_native_symbols)) return false; #endif /* WASM_ENABLE_LIBC_BUILTIN */ #if WASM_ENABLE_SPEC_TEST n_native_symbols = get_spectest_export_apis(&native_symbols); if (!wasm_native_register_natives("spectest", - native_symbols, n_native_symbols)) + native_symbols, n_native_symbols)) return false; #endif /* WASM_ENABLE_SPEC_TEST */ diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index 92ea9c299..2cba0d5b9 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -1365,14 +1365,6 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, goto fail; } - wasi_ctx->curfds_offset = offset_curfds; - wasi_ctx->prestats_offset = offset_prestats; - wasi_ctx->argv_environ_offset = offset_argv_environ; - wasi_ctx->argv_buf_offset = offset_argv_buf; - wasi_ctx->argv_offsets_offset = offset_argv_offsets; - wasi_ctx->env_buf_offset = offset_env_buf; - wasi_ctx->env_offsets_offset = offset_env_offsets; - if (!fd_table_init(curfds)) { set_error_buf(error_buf, error_buf_size, "Init wasi environment failed: " @@ -1434,6 +1426,14 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, fd_prestats_insert(prestats, dir_list[i], wasm_fd); } + wasi_ctx->curfds_offset = offset_curfds; + wasi_ctx->prestats_offset = offset_prestats; + wasi_ctx->argv_environ_offset = offset_argv_environ; + wasi_ctx->argv_buf_offset = offset_argv_buf; + wasi_ctx->argv_offsets_offset = offset_argv_offsets; + wasi_ctx->env_buf_offset = offset_env_buf; + wasi_ctx->env_offsets_offset = offset_env_offsets; + return true; fail: diff --git a/samples/simple/build.sh b/samples/simple/build.sh index 85f306774..51ec8bc28 100755 --- a/samples/simple/build.sh +++ b/samples/simple/build.sh @@ -153,6 +153,7 @@ OUT_FILE=${i%.*}.wasm -Wl,--export=on_request -Wl,--export=on_response \ -Wl,--export=on_sensor_event -Wl,--export=on_timer_callback \ -Wl,--export=on_connection_data \ + -Wl,--export=__heap_base -Wl,--export=__data_end \ -o ${OUT_DIR}/wasm-apps/${OUT_FILE} ${APP_SRC} if [ -f ${OUT_DIR}/wasm-apps/${OUT_FILE} ]; then echo "build ${OUT_FILE} success" From 2135badc54eb2ea937ffd370b7718ea983e501d6 Mon Sep 17 00:00:00 2001 From: Xu Jun <693788454@qq.com> Date: Mon, 7 Sep 2020 17:32:00 +0800 Subject: [PATCH 064/207] fix problem in wasm_module_malloc (#374) --- core/iwasm/interpreter/wasm_runtime.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index dee8ea986..f139ae3e1 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -1580,6 +1580,9 @@ wasm_module_malloc(WASMModuleInstance *module_inst, uint32 size, size, &offset)) { return 0; } + /* If we use app's malloc function, + the default memory may be changed while memory growing */ + memory = module_inst->default_memory; addr = offset ? memory->memory_data + offset : NULL; } @@ -1589,6 +1592,7 @@ wasm_module_malloc(WASMModuleInstance *module_inst, uint32 size, } if (p_native_addr) *p_native_addr = addr; + return (uint32)(addr - memory->memory_data); } From 5418e09712a8ba53aac1d822d639d16f20147e9f Mon Sep 17 00:00:00 2001 From: Xiaokang Qin <69961735+qinxk-inter@users.noreply.github.com> Date: Tue, 8 Sep 2020 13:03:35 +0800 Subject: [PATCH 065/207] Add two apis for wasm function call (#375) Add below two apis: bool wasm_runtime_call_wasm_a(WASMExecEnv *exec_env, WASMFunctionInstanceCommon *function, uint32 num_results, wasm_val_t results[], uint32 num_args, wasm_val_t args[]) bool wasm_runtime_call_wasm_v(WASMExecEnv *exec_env, WASMFunctionInstanceCommon *function, uint32 num_results, wasm_val_t results[], uint32 num_args, ...) Signed-off-by: Xiaokang Qin --- core/iwasm/common/wasm_runtime_common.c | 221 ++++++++++++++++++++++++ core/iwasm/common/wasm_runtime_common.h | 12 ++ core/iwasm/include/wasm_c_api.h | 6 + core/iwasm/include/wasm_export.h | 73 ++++++++ doc/embed_wamr.md | 50 +++++- 5 files changed, 359 insertions(+), 3 deletions(-) diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index 2cba0d5b9..b729751b8 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -863,6 +863,227 @@ wasm_runtime_call_wasm(WASMExecEnv *exec_env, return false; } +static uint32 +parse_args_to_uint32_array(WASMType *type, + uint32 num_args, wasm_val_t *args, + uint32 *out_argv) +{ + int i, p; + + for (i = 0, p = 0; i < num_args; i++) { + switch (args[i].kind) { + case WASM_I32: + out_argv[p++] = args[i].of.i32; + break; + case WASM_I64: + { + union { uint64 val; uint32 parts[2]; } u; + u.val = args[i].of.i64; + out_argv[p++] = u.parts[0]; + out_argv[p++] = u.parts[1]; + break; + } + case WASM_F32: + { + union { float32 val; uint32 part; } u; + u.val = args[i].of.f32; + out_argv[p++] = u.part; + break; + } + case WASM_F64: + { + union { float64 val; uint32 parts[2]; } u; + u.val = args[i].of.f64; + out_argv[p++] = u.parts[0]; + out_argv[p++] = u.parts[1]; + break; + } + default: + bh_assert(0); + break; + } + } + return p; +} + +static uint32 +parse_uint32_array_to_results(WASMType *type, + uint32 argc, uint32 *argv, + wasm_val_t *out_results) +{ + int i, p; + + for (i = 0, p = 0; i < type->result_count; i++) { + switch (type->types[type->param_count + i]) { + case VALUE_TYPE_I32: + out_results[i].kind = WASM_I32; + out_results[i].of.i32 = *(int32 *)argv[p++]; + break; + case VALUE_TYPE_I64: + { + union { uint64 val; uint32 parts[2]; } u; + u.parts[0] = argv[p++]; + u.parts[1] = argv[p++]; + out_results[i].kind = WASM_I64; + out_results[i].of.i64 = u.val; + break; + } + case VALUE_TYPE_F32: + { + union { float32 val; uint32 part; } u; + u.part = argv[p++]; + out_results[i].kind = WASM_F32; + out_results[i].of.f32 = u.val; + break; + } + case VALUE_TYPE_F64: + { + union { float64 val; uint32 parts[2]; } u; + u.parts[0] = argv[p++]; + u.parts[1] = argv[p++]; + out_results[i].kind = WASM_F64; + out_results[i].of.f64 = u.val; + break; + } + default: + bh_assert(0); + break; + } + } + bh_assert(argc == p); + return type->result_count; +} + +bool +wasm_runtime_call_wasm_a(WASMExecEnv *exec_env, + WASMFunctionInstanceCommon *function, + uint32 num_results, wasm_val_t results[], + uint32 num_args, wasm_val_t args[]) +{ + uint32 argc, *argv, ret_num, cell_num, total_size; + bool ret = false; + WASMType *type = NULL; + +#if WASM_ENABLE_INTERP != 0 + if (exec_env->module_inst->module_type == Wasm_Module_Bytecode) { + WASMFunctionInstance *wasm_func = (WASMFunctionInstance*)function; + type = wasm_func->u.func->func_type; + argc = wasm_func->param_cell_num; + cell_num = argc > wasm_func->ret_cell_num ? + argc : wasm_func->ret_cell_num; + } +#endif +#if WASM_ENABLE_AOT != 0 + if (exec_env->module_inst->module_type == Wasm_Module_AoT) { + type = ((AOTFunctionInstance*)function)->u.func.func_type; + argc = type->param_cell_num; + cell_num = argc > type->ret_cell_num ? + argc : type->ret_cell_num; + } +#endif + if (!type) { + LOG_ERROR("Function type get failed, WAMR Interpreter and AOT must be enabled at least one."); + goto fail1; + } + + if (num_results != type->result_count) { + LOG_ERROR("The result value number does not match the function declaration."); + goto fail1; + } + + if (num_args != type->param_count) { + LOG_ERROR("The argument value number does not match the function declaration."); + goto fail1; + } + + total_size = sizeof(uint32) * (uint64)(cell_num > 2 ? cell_num : 2); + if (!(argv = runtime_malloc((uint32)total_size, exec_env->module_inst, NULL, 0))) { + wasm_runtime_set_exception(exec_env->module_inst, "allocate memory failed"); + goto fail1; + } + + argc = parse_args_to_uint32_array(type, num_args, args, argv); + if (!(ret = wasm_runtime_call_wasm(exec_env, function, argc, argv))) + goto fail2; + + ret_num = parse_uint32_array_to_results(type, type->ret_cell_num, argv, results); + bh_assert(ret_num == num_results); + +fail2: + wasm_runtime_free(argv); +fail1: + return ret; +} + +bool +wasm_runtime_call_wasm_v(WASMExecEnv *exec_env, + WASMFunctionInstanceCommon *function, + uint32 num_results, wasm_val_t results[], + uint32 num_args, ...) +{ + wasm_val_t *args = NULL; + WASMType *type = NULL; + bool ret = false; + int i = 0; + va_list vargs; + +#if WASM_ENABLE_INTERP != 0 + if (exec_env->module_inst->module_type == Wasm_Module_Bytecode) { + WASMFunctionInstance *wasm_func = (WASMFunctionInstance*)function; + type = wasm_func->u.func->func_type; + } +#endif +#if WASM_ENABLE_AOT != 0 + if (exec_env->module_inst->module_type == Wasm_Module_AoT) { + type = ((AOTFunctionInstance*)function)->u.func.func_type; + } +#endif + if (!type) { + LOG_ERROR("Function type get failed, WAMR Interpreter and AOT must be enabled at least one."); + goto fail1; + } + + if (num_args != type->param_count) { + LOG_ERROR("The argument value number does not match the function declaration."); + goto fail1; + } + if (!(args = runtime_malloc(sizeof(wasm_val_t) * num_args, NULL, NULL, 0))) { + wasm_runtime_set_exception(exec_env->module_inst, "allocate memory failed"); + goto fail1; + } + + va_start(vargs, num_args); + for (i = 0; i < num_args; i++) { + switch (type->types[i]) { + case VALUE_TYPE_I32: + args[i].kind = WASM_I32; + args[i].of.i32 = va_arg(vargs, uint32); + break; + case VALUE_TYPE_I64: + args[i].kind = WASM_I64; + args[i].of.i64 = va_arg(vargs, uint64); + break; + case VALUE_TYPE_F32: + args[i].kind = WASM_F32; + args[i].of.f32 = (float32)va_arg(vargs, float64); + break; + case VALUE_TYPE_F64: + args[i].kind = WASM_F64; + args[i].of.f64 = va_arg(vargs, float64);; + break; + default: + bh_assert(0); + break; + } + } + va_end(vargs); + ret = wasm_runtime_call_wasm_a(exec_env, function, num_results, results, num_args, args); + wasm_runtime_free(args); + +fail1: + return ret; +} + bool wasm_runtime_create_exec_env_and_call_wasm(WASMModuleInstanceCommon *module_inst, WASMFunctionInstanceCommon *function, diff --git a/core/iwasm/common/wasm_runtime_common.h b/core/iwasm/common/wasm_runtime_common.h index ba03e59aa..51ef6c777 100644 --- a/core/iwasm/common/wasm_runtime_common.h +++ b/core/iwasm/common/wasm_runtime_common.h @@ -167,6 +167,18 @@ wasm_runtime_call_wasm(WASMExecEnv *exec_env, WASMFunctionInstanceCommon *function, uint32 argc, uint32 argv[]); +bool +wasm_runtime_call_wasm_a(WASMExecEnv *exec_env, + WASMFunctionInstanceCommon *function, + uint32 num_results, wasm_val_t *results, + uint32 num_args, wasm_val_t *args); + +bool +wasm_runtime_call_wasm_v(WASMExecEnv *exec_env, + WASMFunctionInstanceCommon *function, + uint32 num_results, wasm_val_t *results, + uint32 num_args, ...); + /** * Call a function reference of a given WASM runtime instance with * arguments. diff --git a/core/iwasm/include/wasm_c_api.h b/core/iwasm/include/wasm_c_api.h index 5b5bd79e4..fdc072327 100644 --- a/core/iwasm/include/wasm_c_api.h +++ b/core/iwasm/include/wasm_c_api.h @@ -165,6 +165,8 @@ static const uint32_t wasm_limits_max_default = 0xffffffff; WASM_DECLARE_TYPE(valtype) +#ifndef WASM_VALKIND_T_DEFINED +#define WASM_VALKIND_T_DEFINED typedef uint8_t wasm_valkind_t; enum wasm_valkind_enum { WASM_I32, @@ -174,6 +176,7 @@ enum wasm_valkind_enum { WASM_ANYREF = 128, WASM_FUNCREF, }; +#endif WASM_API_EXTERN own wasm_valtype_t* wasm_valtype_new(wasm_valkind_t); @@ -299,6 +302,8 @@ WASM_API_EXTERN const wasm_externtype_t* wasm_exporttype_type(const wasm_exportt // Values +#ifndef WASM_VAL_T_DEFINED +#define WASM_VAL_T_DEFINED struct wasm_ref_t; typedef struct wasm_val_t { @@ -311,6 +316,7 @@ typedef struct wasm_val_t { struct wasm_ref_t* ref; } of; } wasm_val_t; +#endif WASM_API_EXTERN void wasm_val_delete(own wasm_val_t* v); WASM_API_EXTERN void wasm_val_copy(own wasm_val_t* out, const wasm_val_t*); diff --git a/core/iwasm/include/wasm_export.h b/core/iwasm/include/wasm_export.h index 79ec96f63..0f392e279 100644 --- a/core/iwasm/include/wasm_export.h +++ b/core/iwasm/include/wasm_export.h @@ -120,6 +120,35 @@ typedef struct RuntimeInitArgs { uint32_t max_thread_num; } RuntimeInitArgs; +#ifndef WASM_VALKIND_T_DEFINED +#define WASM_VALKIND_T_DEFINED +typedef uint8_t wasm_valkind_t; +enum wasm_valkind_enum { + WASM_I32, + WASM_I64, + WASM_F32, + WASM_F64, + WASM_ANYREF = 128, + WASM_FUNCREF, +}; +#endif + +#ifndef WASM_VAL_T_DEFINED +#define WASM_VAL_T_DEFINED +struct wasm_ref_t; + +typedef struct wasm_val_t { + wasm_valkind_t kind; + union { + int32_t i32; + int64_t i64; + float f32; + double f64; + struct wasm_ref_t* ref; + } of; +} wasm_val_t; +#endif + /** * Initialize the WASM runtime environment, and also initialize * the memory allocator with system allocator, which calls os_malloc @@ -385,6 +414,50 @@ wasm_runtime_call_wasm(wasm_exec_env_t exec_env, wasm_function_inst_t function, uint32_t argc, uint32_t argv[]); +/** + * Call the given WASM function of a WASM module instance with + * provided results space and arguments (bytecode and AoT). + * + * @param exec_env the execution environment to call the function, + * which must be created from wasm_create_exec_env() + * @param function the function to call + * @param num_results the number of results + * @param results the pre-alloced pointer to get the results + * @param num_args the number of arguments + * @param args the arguments + * + * @return true if success, false otherwise and exception will be thrown, + * the caller can call wasm_runtime_get_exception to get the exception + * info. + */ +bool +wasm_runtime_call_wasm_a(wasm_exec_env_t exec_env, + wasm_function_inst_t function, + uint32_t num_results, wasm_val_t results[], + uint32_t num_args, wasm_val_t *args); + +/** + * Call the given WASM function of a WASM module instance with + * provided results space and variant arguments (bytecode and AoT). + * + * @param exec_env the execution environment to call the function, + * which must be created from wasm_create_exec_env() + * @param function the function to call + * @param num_results the number of results + * @param results the pre-alloced pointer to get the results + * @param num_args the number of arguments + * @param ... the variant arguments + * + * @return true if success, false otherwise and exception will be thrown, + * the caller can call wasm_runtime_get_exception to get the exception + * info. + */ +bool +wasm_runtime_call_wasm_v(wasm_exec_env_t exec_env, + wasm_function_inst_t function, + uint32_t num_results, wasm_val_t results[], + uint32_t num_args, ...); + /** * Find the unique main function from a WASM module instance * and execute that function. diff --git a/doc/embed_wamr.md b/doc/embed_wamr.md index 4503e84c5..d0c8e3612 100644 --- a/doc/embed_wamr.md +++ b/doc/embed_wamr.md @@ -71,17 +71,23 @@ if (!wasm_runtime_full_init(&init_args)) { ## Native calls WASM functions and passes parameters -After a module is instantiated, the runtime native can lookup WASM functions by the names and call them. +After a module is instantiated, the runtime embedder can lookup the target WASM function by name, and create execution environment to call the function. ```c - unit32 argv[2]; - /* lookup a WASM function by its name The function signature can NULL here */ func = wasm_runtime_lookup_function(module_inst, "fib", NULL); /* creat an execution environment to execute the WASM functions */ exec_env = wasm_runtime_create_exec_env(module_inst, stack_size); +``` + +There are several ways to call WASM function: + +1. Function call with parameters in an array of 32 bits elements and size: + +```c + unit32 argv[2]; /* arguments are always transferred in 32-bit element */ argv[0] = 8; @@ -129,6 +135,44 @@ The parameters are transferred in an array of 32 bits elements. For parameters t memcpy(&ret, &argv[0], sizeof(ret)); ``` +2. Function call with results and arguments both in `wasm_val_t` struct and size: + +```c + unit32 num_args = 1, num_results = 1; + wasm_val_t args[1], results[1]; + + /* set the argument type and value */ + args[0].kind = WASM_I32; + args[0].of.i32 = 8; + + /* call the WASM function */ + if (wasm_runtime_call_wasm_a(exec_env, func, num_results, results, num_args, args)) { + /* the return value is stored in results */ + printf("fib function return: %d\n", results[0].of.i32); + } + else { + /* exception is thrown if call fails */ + printf("%s\n", wasm_runtime_get_exception(module_inst)); + } +``` + +3. Function call with variant argument support: + +```c + unit32 num_args = 1, num_results = 1; + wasm_val_t results[1]; + + /* call the WASM function */ + if (wasm_runtime_call_wasm_v(exec_env, func, 1, results, 1, 8)) { + /* the return value is stored in results */ + printf("fib function return: %d\n", results[0].of.i32); + } + else { + /* exception is thrown if call fails */ + printf("%s\n", wasm_runtime_get_exception(module_inst)); + } +``` + ## Pass buffer to WASM function If we need to transfer a buffer to WASM function, we can pass the buffer address through a parameter. **Attention**: The sandbox will forbid the WASM code to access outside memory, we must **allocate the buffer from WASM instance's own memory space and pass the buffer address in instance's space (not the runtime native address)**. From 264e18969041c789948facee1a15a1a312450637 Mon Sep 17 00:00:00 2001 From: Xiaokang Qin Date: Fri, 11 Sep 2020 17:36:04 +0800 Subject: [PATCH 066/207] Add Windows support for C-API and Runtime API libraries and examples. (#379) * Add Windows support for C-API and Runtime API libraries and examples. Signed-off-by: Wu Zhongmin Signed-off-by: Xiaokang Qin * Address the review comments Signed-off-by: Xiaokang Qin * Rewrite the the bh_getopt to make it avaliable for more kinds of options Signed-off-by: Wu Zhongmin Signed-off-by: Xiaokang Qin * Add the license header Signed-off-by: Xiaokang Qin Co-authored-by: Zhongmin Wu --- .gitignore | 1 + core/iwasm/include/wasm_export.h | 127 ++++++++++-------- .../shared/platform/include/platform_common.h | 5 + core/shared/utils/uncommon/bh_getopt.c | 60 +++++++++ core/shared/utils/uncommon/bh_getopt.h | 27 ++++ product-mini/platforms/windows/CMakeLists.txt | 2 + samples/basic/CMakeLists.txt | 29 ++-- samples/basic/src/main.c | 1 + samples/wasm-c-api/CMakeLists.txt | 38 ++++-- 9 files changed, 213 insertions(+), 77 deletions(-) create mode 100644 core/shared/utils/uncommon/bh_getopt.c create mode 100644 core/shared/utils/uncommon/bh_getopt.h diff --git a/.gitignore b/.gitignore index cf9f70360..4e8eec854 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.vs .vscode **/*build/ core/deps/** diff --git a/core/iwasm/include/wasm_export.h b/core/iwasm/include/wasm_export.h index 0f392e279..b8f535b20 100644 --- a/core/iwasm/include/wasm_export.h +++ b/core/iwasm/include/wasm_export.h @@ -11,6 +11,18 @@ #include "lib_export.h" +#ifndef WASM_RUNTIME_API_EXTERN +#if defined(MSVC) + #if defined(COMPILING_WASM_RUNTIME_API) + #define WASM_RUNTIME_API_EXTERN __declspec(dllexport) + #else + #define WASM_RUNTIME_API_EXTERN __declspec(dllimport) + #endif +#else +#define WASM_RUNTIME_API_EXTERN +#endif +#endif + #ifdef __cplusplus extern "C" { #endif @@ -156,7 +168,7 @@ typedef struct wasm_val_t { * * @return true if success, false otherwise */ -bool +WASM_RUNTIME_API_EXTERN bool wasm_runtime_init(void); /** @@ -168,13 +180,13 @@ wasm_runtime_init(void); * * @return return true if success, false otherwise */ -bool +WASM_RUNTIME_API_EXTERN bool wasm_runtime_full_init(RuntimeInitArgs *init_args); /** * Destroy the WASM runtime environment. */ -void +WASM_RUNTIME_API_EXTERN void wasm_runtime_destroy(void); /** @@ -184,7 +196,7 @@ wasm_runtime_destroy(void); * * @return the pointer to memory allocated */ -void * +WASM_RUNTIME_API_EXTERN void * wasm_runtime_malloc(unsigned int size); /** @@ -195,13 +207,14 @@ wasm_runtime_malloc(unsigned int size); * * @return the pointer to memory reallocated */ -void * +WASM_RUNTIME_API_EXTERN void * wasm_runtime_realloc(void *ptr, unsigned int size); /* * Free memory to runtime memory environment. */ -void wasm_runtime_free(void *ptr); +WASM_RUNTIME_API_EXTERN void +wasm_runtime_free(void *ptr); /** * Get the package type of a buffer. @@ -211,7 +224,7 @@ void wasm_runtime_free(void *ptr); * * @return the package type, return Package_Type_Unknown if the type is unknown */ -package_type_t +WASM_RUNTIME_API_EXTERN package_type_t get_package_type(const uint8_t *buf, uint32_t size); #if WASM_ENABLE_MULTI_MODULE != 0 @@ -234,7 +247,7 @@ typedef void (*module_destroyer)(uint8_t *buffer, uint32_t size); * @param reader a callback to read a module file into a buffer * @param destroyer a callback to release above buffer */ -void +WASM_RUNTIME_API_EXTERN void wasm_runtime_set_module_reader(const module_reader reader, const module_destroyer destroyer); /** @@ -248,7 +261,7 @@ wasm_runtime_set_module_reader(const module_reader reader, * * @return true means success, false means failed */ -bool +WASM_RUNTIME_API_EXTERN bool wasm_runtime_register_module(const char *module_name, wasm_module_t module, char *error_buf, uint32_t error_buf_size); @@ -260,7 +273,7 @@ wasm_runtime_register_module(const char *module_name, wasm_module_t module, * * @return return WASM module loaded, NULL if failed */ -wasm_module_t +WASM_RUNTIME_API_EXTERN wasm_module_t wasm_runtime_find_module_registered(const char *module_name); #endif /* WASM_ENABLE_MULTI_MODULE */ @@ -276,7 +289,7 @@ wasm_runtime_find_module_registered(const char *module_name); * * @return return WASM module loaded, NULL if failed */ -wasm_module_t +WASM_RUNTIME_API_EXTERN wasm_module_t wasm_runtime_load(const uint8_t *buf, uint32_t size, char *error_buf, uint32_t error_buf_size); @@ -290,7 +303,7 @@ wasm_runtime_load(const uint8_t *buf, uint32_t size, * * @return return WASM module loaded, NULL if failed */ -wasm_module_t +WASM_RUNTIME_API_EXTERN wasm_module_t wasm_runtime_load_from_sections(wasm_section_list_t section_list, bool is_aot, char *error_buf, uint32_t error_buf_size); @@ -299,10 +312,10 @@ wasm_runtime_load_from_sections(wasm_section_list_t section_list, bool is_aot, * * @param module the module to be unloaded */ -void +WASM_RUNTIME_API_EXTERN void wasm_runtime_unload(wasm_module_t module); -void +WASM_RUNTIME_API_EXTERN void wasm_runtime_set_wasi_args(wasm_module_t module, const char *dir_list[], uint32_t dir_count, const char *map_dir_list[], uint32_t map_dir_count, @@ -329,7 +342,7 @@ wasm_runtime_set_wasi_args(wasm_module_t module, * * @return return the instantiated WASM module instance, NULL if failed */ -wasm_module_inst_t +WASM_RUNTIME_API_EXTERN wasm_module_inst_t wasm_runtime_instantiate(const wasm_module_t module, uint32_t stack_size, uint32_t heap_size, char *error_buf, uint32_t error_buf_size); @@ -339,13 +352,13 @@ wasm_runtime_instantiate(const wasm_module_t module, * * @param module_inst the WASM module instance to destroy */ -void +WASM_RUNTIME_API_EXTERN void wasm_runtime_deinstantiate(wasm_module_inst_t module_inst); -bool +WASM_RUNTIME_API_EXTERN bool wasm_runtime_is_wasi_mode(wasm_module_inst_t module_inst); -wasm_function_inst_t +WASM_RUNTIME_API_EXTERN wasm_function_inst_t wasm_runtime_lookup_wasi_start_function(wasm_module_inst_t module_inst); /** @@ -357,7 +370,7 @@ wasm_runtime_lookup_wasi_start_function(wasm_module_inst_t module_inst); * * @return the function instance found, NULL if not found */ -wasm_function_inst_t +WASM_RUNTIME_API_EXTERN wasm_function_inst_t wasm_runtime_lookup_function(wasm_module_inst_t const module_inst, const char *name, const char *signature); @@ -370,7 +383,7 @@ wasm_runtime_lookup_function(wasm_module_inst_t const module_inst, * @return the execution environment, NULL if failed, e.g. invalid * stack size is passed */ -wasm_exec_env_t +WASM_RUNTIME_API_EXTERN wasm_exec_env_t wasm_runtime_create_exec_env(wasm_module_inst_t module_inst, uint32_t stack_size); @@ -379,7 +392,7 @@ wasm_runtime_create_exec_env(wasm_module_inst_t module_inst, * * @param exec_env the execution environment to destroy */ -void +WASM_RUNTIME_API_EXTERN void wasm_runtime_destroy_exec_env(wasm_exec_env_t exec_env); /** @@ -389,7 +402,7 @@ wasm_runtime_destroy_exec_env(wasm_exec_env_t exec_env); * * @return the WASM module instance */ -wasm_module_inst_t +WASM_RUNTIME_API_EXTERN wasm_module_inst_t wasm_runtime_get_module_inst(wasm_exec_env_t exec_env); /** @@ -409,7 +422,7 @@ wasm_runtime_get_module_inst(wasm_exec_env_t exec_env); * the caller can call wasm_runtime_get_exception to get the exception * info. */ -bool +WASM_RUNTIME_API_EXTERN bool wasm_runtime_call_wasm(wasm_exec_env_t exec_env, wasm_function_inst_t function, uint32_t argc, uint32_t argv[]); @@ -430,7 +443,7 @@ wasm_runtime_call_wasm(wasm_exec_env_t exec_env, * the caller can call wasm_runtime_get_exception to get the exception * info. */ -bool +WASM_RUNTIME_API_EXTERN bool wasm_runtime_call_wasm_a(wasm_exec_env_t exec_env, wasm_function_inst_t function, uint32_t num_results, wasm_val_t results[], @@ -452,7 +465,7 @@ wasm_runtime_call_wasm_a(wasm_exec_env_t exec_env, * the caller can call wasm_runtime_get_exception to get the exception * info. */ -bool +WASM_RUNTIME_API_EXTERN bool wasm_runtime_call_wasm_v(wasm_exec_env_t exec_env, wasm_function_inst_t function, uint32_t num_results, wasm_val_t results[], @@ -470,7 +483,7 @@ wasm_runtime_call_wasm_v(wasm_exec_env_t exec_env, * will be thrown, the caller can call wasm_runtime_get_exception to get * the exception info. */ -bool +WASM_RUNTIME_API_EXTERN bool wasm_application_execute_main(wasm_module_inst_t module_inst, int32_t argc, char *argv[]); @@ -489,7 +502,7 @@ wasm_application_execute_main(wasm_module_inst_t module_inst, * exception will be thrown, the caller can call wasm_runtime_get_exception * to get the exception info. */ -bool +WASM_RUNTIME_API_EXTERN bool wasm_application_execute_func(wasm_module_inst_t module_inst, const char *name, int32_t argc, char *argv[]); /** @@ -499,7 +512,7 @@ wasm_application_execute_func(wasm_module_inst_t module_inst, * * @return the exception string */ -const char * +WASM_RUNTIME_API_EXTERN const char * wasm_runtime_get_exception(wasm_module_inst_t module_inst); /** @@ -509,7 +522,7 @@ wasm_runtime_get_exception(wasm_module_inst_t module_inst); * * @param exception the exception string */ -void +WASM_RUNTIME_API_EXTERN void wasm_runtime_set_exception(wasm_module_inst_t module_inst, const char *exception); @@ -518,7 +531,7 @@ wasm_runtime_set_exception(wasm_module_inst_t module_inst, * * @param module_inst the WASM module instance */ -void +WASM_RUNTIME_API_EXTERN void wasm_runtime_clear_exception(wasm_module_inst_t module_inst); /** @@ -527,7 +540,7 @@ wasm_runtime_clear_exception(wasm_module_inst_t module_inst); * @param module_inst the WASM module instance * @param custom_data the custom data to be set */ -void +WASM_RUNTIME_API_EXTERN void wasm_runtime_set_custom_data(wasm_module_inst_t module_inst, void *custom_data); /** @@ -537,7 +550,7 @@ wasm_runtime_set_custom_data(wasm_module_inst_t module_inst, * * @return the custom data (NULL if not set yet) */ -void * +WASM_RUNTIME_API_EXTERN void * wasm_runtime_get_custom_data(wasm_module_inst_t module_inst); /** @@ -553,7 +566,7 @@ wasm_runtime_get_custom_data(wasm_module_inst_t module_inst); * it is not an absolute address. * Return non-zero if success, zero if failed. */ -uint32_t +WASM_RUNTIME_API_EXTERN uint32_t wasm_runtime_module_malloc(wasm_module_inst_t module_inst, uint32_t size, void **p_native_addr); @@ -563,7 +576,7 @@ wasm_runtime_module_malloc(wasm_module_inst_t module_inst, uint32_t size, * @param module_inst the WASM module instance which contains heap * @param ptr the pointer to free */ -void +WASM_RUNTIME_API_EXTERN void wasm_runtime_module_free(wasm_module_inst_t module_inst, uint32_t ptr); /** @@ -579,7 +592,7 @@ wasm_runtime_module_free(wasm_module_inst_t module_inst, uint32_t ptr); * it is not an absolute address. * Return non-zero if success, zero if failed. */ -uint32_t +WASM_RUNTIME_API_EXTERN uint32_t wasm_runtime_module_dup_data(wasm_module_inst_t module_inst, const char *src, uint32_t size); @@ -594,7 +607,7 @@ wasm_runtime_module_dup_data(wasm_module_inst_t module_inst, * @return true if success, false otherwise. If failed, an exception will * be thrown. */ -bool +WASM_RUNTIME_API_EXTERN bool wasm_runtime_validate_app_addr(wasm_module_inst_t module_inst, uint32_t app_offset, uint32_t size); @@ -611,7 +624,7 @@ wasm_runtime_validate_app_addr(wasm_module_inst_t module_inst, * @return true if success, false otherwise. If failed, an exception will * be thrown. */ -bool +WASM_RUNTIME_API_EXTERN bool wasm_runtime_validate_app_str_addr(wasm_module_inst_t module_inst, uint32_t app_str_offset); @@ -627,7 +640,7 @@ wasm_runtime_validate_app_str_addr(wasm_module_inst_t module_inst, * @return true if success, false otherwise. If failed, an exception will * be thrown. */ -bool +WASM_RUNTIME_API_EXTERN bool wasm_runtime_validate_native_addr(wasm_module_inst_t module_inst, void *native_ptr, uint32_t size); @@ -639,7 +652,7 @@ wasm_runtime_validate_native_addr(wasm_module_inst_t module_inst, * * @return the native address converted */ -void* +WASM_RUNTIME_API_EXTERN void * wasm_runtime_addr_app_to_native(wasm_module_inst_t module_inst, uint32_t app_offset); @@ -651,7 +664,7 @@ wasm_runtime_addr_app_to_native(wasm_module_inst_t module_inst, * * @return the app address converted */ -uint32_t +WASM_RUNTIME_API_EXTERN uint32_t wasm_runtime_addr_native_to_app(wasm_module_inst_t module_inst, void *native_ptr); @@ -665,7 +678,7 @@ wasm_runtime_addr_native_to_app(wasm_module_inst_t module_inst, * * @return true if success, false otherwise. */ -bool +WASM_RUNTIME_API_EXTERN bool wasm_runtime_get_app_addr_range(wasm_module_inst_t module_inst, uint32_t app_offset, uint32_t *p_app_start_offset, @@ -681,7 +694,7 @@ wasm_runtime_get_app_addr_range(wasm_module_inst_t module_inst, * * @return true if success, false otherwise. */ -bool +WASM_RUNTIME_API_EXTERN bool wasm_runtime_get_native_addr_range(wasm_module_inst_t module_inst, uint8_t *native_ptr, uint8_t **p_native_start_addr, @@ -713,9 +726,10 @@ wasm_runtime_get_native_addr_range(wasm_module_inst_t module_inst, * * @return true if success, false otherwise */ -bool wasm_runtime_register_natives(const char *module_name, - NativeSymbol *native_symbols, - uint32_t n_native_symbols); +WASM_RUNTIME_API_EXTERN bool +wasm_runtime_register_natives(const char *module_name, + NativeSymbol *native_symbols, + uint32_t n_native_symbols); /** * Register native functions with same module name, similar to @@ -727,9 +741,10 @@ bool wasm_runtime_register_natives(const char *module_name, * and write the return value back to args[0] with macro * native_raw_return_type and native_raw_set_return */ -bool wasm_runtime_register_natives_raw(const char *module_name, - NativeSymbol *native_symbols, - uint32_t n_native_symbols); +WASM_RUNTIME_API_EXTERN bool +wasm_runtime_register_natives_raw(const char *module_name, + NativeSymbol *native_symbols, + uint32_t n_native_symbols); /** * Get attachment of native function from execution environment @@ -738,7 +753,7 @@ bool wasm_runtime_register_natives_raw(const char *module_name, * * @return the attachment of native function */ -void * +WASM_RUNTIME_API_EXTERN void * wasm_runtime_get_function_attachment(wasm_exec_env_t exec_env); /** @@ -747,7 +762,7 @@ wasm_runtime_get_function_attachment(wasm_exec_env_t exec_env); * @param exec_env the execution environment * @param user_data the user data to be set */ -void +WASM_RUNTIME_API_EXTERN void wasm_runtime_set_user_data(wasm_exec_env_t exec_env, void *user_data); /** @@ -757,7 +772,7 @@ wasm_runtime_set_user_data(wasm_exec_env_t exec_env, * * @return the user data (NULL if not set yet) */ -void * +WASM_RUNTIME_API_EXTERN void * wasm_runtime_get_user_data(wasm_exec_env_t exec_env); #if WASM_ENABLE_THREAD_MGR != 0 @@ -771,7 +786,7 @@ typedef uintptr_t wasm_thread_t; * * @param num maximum thread num */ -void +WASM_RUNTIME_API_EXTERN void wasm_runtime_set_max_thread_num(uint32_t num); /** @@ -782,7 +797,7 @@ wasm_runtime_set_max_thread_num(uint32_t num); * * @return the spawned exec_env if success, NULL otherwise */ -wasm_exec_env_t +WASM_RUNTIME_API_EXTERN wasm_exec_env_t wasm_runtime_spawn_exec_env(wasm_exec_env_t exec_env); /** @@ -790,7 +805,7 @@ wasm_runtime_spawn_exec_env(wasm_exec_env_t exec_env); * * @param exec_env the spawned exec_env */ -void +WASM_RUNTIME_API_EXTERN void wasm_runtime_destroy_spawned_exec_env(wasm_exec_env_t exec_env); /** @@ -803,7 +818,7 @@ wasm_runtime_destroy_spawned_exec_env(wasm_exec_env_t exec_env); * * @return 0 if success, -1 otherwise */ -int32_t +WASM_RUNTIME_API_EXTERN int32_t wasm_runtime_spawn_thread(wasm_exec_env_t exec_env, wasm_thread_t *tid, wasm_thread_callback_t callback, void *arg); @@ -815,7 +830,7 @@ wasm_runtime_spawn_thread(wasm_exec_env_t exec_env, wasm_thread_t *tid, * * @return 0 if success, error number otherwise */ -int32_t +WASM_RUNTIME_API_EXTERN int32_t wasm_runtime_join_thread(wasm_thread_t tid, void **retval); #endif diff --git a/core/shared/platform/include/platform_common.h b/core/shared/platform/include/platform_common.h index 60570d7c2..33c93e432 100644 --- a/core/shared/platform/include/platform_common.h +++ b/core/shared/platform/include/platform_common.h @@ -34,8 +34,13 @@ extern "C" { #define BH_FREE os_free #endif +#if defined(MSVC) +__declspec(dllimport) void *BH_MALLOC(unsigned int size); +__declspec(dllimport) void BH_FREE(void *ptr); +#else void *BH_MALLOC(unsigned int size); void BH_FREE(void *ptr); +#endif #ifndef NULL #define NULL (void*)0 diff --git a/core/shared/utils/uncommon/bh_getopt.c b/core/shared/utils/uncommon/bh_getopt.c new file mode 100644 index 000000000..b7000c3db --- /dev/null +++ b/core/shared/utils/uncommon/bh_getopt.c @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2020 Ant Financial Services Group. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef __GNUC__ + +#include "bh_getopt.h" +#include + +char* optarg = NULL; +int optind = 1; + +int getopt(int argc, char *const argv[], const char *optstring) +{ + static int sp = 1; + int c; + int opt; + char *p; + + if (sp == 1) { + if ((optind >= argc) || (argv[optind][0] != '-') || (argv[optind][1] == 0)){ + return -1; + } else if (!strcmp(argv[optind], "--")) { + optind++; + return -1; + } + } + + opt = argv[optind][sp]; + p = strchr(optstring, opt); + if (opt == ':' || p == NULL) { + printf("illegal option : '-%c'\n", opt); + if ( argv[optind][++sp] == '\0') { + optind ++; + sp = 1; + } + return ('?'); + } + if (p[1] == ':') { + if (argv[optind][sp + 1] != '\0') + optarg = &argv[optind++][sp + 1]; + else if (++optind >= argc) { + printf("option '-%c' requires an argument :\n", opt); + sp = 1; + return ('?'); + } else { + optarg = argv[optind++]; + } + sp = 1; + } else { + if (argv[optind][++sp] == '\0') { + sp = 1; + optind++; + } + optarg = NULL; + } + return (opt); +} +#endif diff --git a/core/shared/utils/uncommon/bh_getopt.h b/core/shared/utils/uncommon/bh_getopt.h new file mode 100644 index 000000000..e6243bfda --- /dev/null +++ b/core/shared/utils/uncommon/bh_getopt.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2020 Ant Financial Services Group. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifdef __GNUC__ +#include +#endif +#ifndef __GNUC__ +#ifndef GETOPT_H__ +#define GETOPT_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +extern char *optarg; +extern int optind; + +int getopt(int argc, char *const argv[], const char *optstring); + +#ifdef __cplusplus +} +#endif + +#endif /* end of GETOPT_H__ */ +#endif /* end of __GNUC__ */ diff --git a/product-mini/platforms/windows/CMakeLists.txt b/product-mini/platforms/windows/CMakeLists.txt index 3bc67d4ce..b01830c40 100644 --- a/product-mini/platforms/windows/CMakeLists.txt +++ b/product-mini/platforms/windows/CMakeLists.txt @@ -119,3 +119,5 @@ install (TARGETS libiwasm DESTINATION lib) set_target_properties (libiwasm PROPERTIES OUTPUT_NAME iwasm) target_link_libraries (libiwasm ${LLVM_AVAILABLE_LIBS}) + +target_compile_definitions(libiwasm PRIVATE COMPILING_WASM_RUNTIME_API=1) diff --git a/samples/basic/CMakeLists.txt b/samples/basic/CMakeLists.txt index 1c7db658e..dfa6f0fa4 100644 --- a/samples/basic/CMakeLists.txt +++ b/samples/basic/CMakeLists.txt @@ -3,7 +3,12 @@ cmake_minimum_required (VERSION 2.8) -project (basic) +if (NOT WAMR_BUILD_PLATFORM STREQUAL "windows") + project (basic) +else() + project (basic C ASM) + enable_language (ASM_MASM) +endif() ################ runtime settings ################ string (TOLOWER ${CMAKE_HOST_SYSTEM_NAME} WAMR_BUILD_PLATFORM) @@ -22,18 +27,22 @@ set (WAMR_BUILD_INTERP 1) set (WAMR_BUILD_AOT 1) set (WAMR_BUILD_JIT 0) set (WAMR_BUILD_LIBC_BUILTIN 1) -set (WAMR_BUILD_LIBC_WASI 1) +if (NOT MSVC) + set (WAMR_BUILD_LIBC_WASI 1) +endif () set (WAMR_BUILD_FAST_INTERP 0) -# linker flags -set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pie -fPIE") -if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang")) - set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") -endif () -set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat -Wformat-security") -if (WAMR_BUILD_TARGET MATCHES "X86_.*" OR WAMR_BUILD_TARGET STREQUAL "AMD_64") +if (NOT MSVC) + # linker flags + set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pie -fPIE") if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang")) - set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mindirect-branch-register") + set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") + endif () + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat -Wformat-security") + if (WAMR_BUILD_TARGET MATCHES "X86_.*" OR WAMR_BUILD_TARGET STREQUAL "AMD_64") + if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang")) + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mindirect-branch-register") + endif () endif () endif () diff --git a/samples/basic/src/main.c b/samples/basic/src/main.c index e2b5dd6bb..d937be3c8 100644 --- a/samples/basic/src/main.c +++ b/samples/basic/src/main.c @@ -6,6 +6,7 @@ #include "wasm_export.h" #include "bh_read_file.h" +#include "bh_getopt.h" int intToStr(int x, char* str, int str_len, int digit); int get_pow(int x, int y); diff --git a/samples/wasm-c-api/CMakeLists.txt b/samples/wasm-c-api/CMakeLists.txt index dc55540fd..682f2dc0b 100644 --- a/samples/wasm-c-api/CMakeLists.txt +++ b/samples/wasm-c-api/CMakeLists.txt @@ -2,7 +2,13 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception cmake_minimum_required (VERSION 2.8) -project(c-api) + +if (NOT WAMR_BUILD_PLATFORM STREQUAL "windows") + project(c-api) +else() + project (c-api C ASM) + enable_language (ASM_MASM) +endif() if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Release) @@ -39,24 +45,28 @@ if(NOT DEFINED WAMR_BUILD_FAST_INTERP) set(WAMR_BUILD_FAST_INTERP 0) endif() -# compiling and linking flags -set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pie -fPIE") -if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang")) - set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") -endif () -set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat -Wformat-security") -if (WAMR_BUILD_TARGET MATCHES "X86_.*" OR WAMR_BUILD_TARGET STREQUAL "AMD_64") +if (NOT MSVC) + # compiling and linking flags + set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pie -fPIE") if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang")) - set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mindirect-branch-register") + set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") endif () -endif () - + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat -Wformat-security") + if (WAMR_BUILD_TARGET MATCHES "X86_.*" OR WAMR_BUILD_TARGET STREQUAL "AMD_64") + if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang")) + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mindirect-branch-register") + endif () + endif () +endif() # build out vmlib set(WAMR_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../..) set(WAMRC ${WAMR_ROOT_DIR}/wamr-compiler/build/wamrc) include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) add_library(vmlib STATIC ${WAMR_RUNTIME_LIB_SOURCE}) +if (MSVC) + target_compile_definitions(vmlib PRIVATE WASM_API_EXTERN=) +endif() ################################################ ################ application related ################ @@ -66,6 +76,9 @@ target_include_directories(c-api PRIVATE ${C_API_PATH}/include ) target_link_libraries(c-api PRIVATE vmlib -lpthread -lm) +if (MSVC) + target_compile_definitions(c-api PRIVATE WASM_API_EXTERN=) +endif() foreach(SRC ${SOURCES}) get_filename_component(APPNAME ${SRC} NAME_WE) @@ -74,6 +87,9 @@ foreach(SRC ${SOURCES}) add_executable(${APPNAME} ${SRC}) message("create executable about ${APPNAME}") target_link_libraries(${APPNAME} c-api) + if (MSVC) + target_compile_definitions(${APPNAME} PRIVATE WASM_API_EXTERN=) + endif() # copy .wasm add_custom_command(TARGET ${APPNAME} POST_BUILD From 728890103b137f35a572650166ba5dabf791ce9f Mon Sep 17 00:00:00 2001 From: Xiaokang Qin Date: Fri, 11 Sep 2020 18:32:58 +0800 Subject: [PATCH 067/207] Add the Windows COFF format support for AOT (#382) Add the Windows COFF format support to wamr-compiler and iwasm can load and excute it on Windows(X64) platform. Signed-off-by: Wu Zhongmin Signed-off-by: Xiaokang Qin Co-authored-by: Wu Zhongmin --- core/iwasm/aot/aot_loader.c | 13 ++++- core/iwasm/aot/arch/aot_reloc_x86_64.c | 6 +- core/iwasm/compilation/aot_emit_aot_file.c | 67 +++++++++++++++++++--- core/shared/platform/windows/win_memmap.c | 3 + 4 files changed, 77 insertions(+), 12 deletions(-) diff --git a/core/iwasm/aot/aot_loader.c b/core/iwasm/aot/aot_loader.c index a17cce012..90a4f2e2e 100644 --- a/core/iwasm/aot/aot_loader.c +++ b/core/iwasm/aot/aot_loader.c @@ -156,6 +156,7 @@ GET_U64_FROM_ADDR(uint32 *addr) #define BIN_TYPE_ELF32B 1 /* 32-bit big endian */ #define BIN_TYPE_ELF64L 2 /* 64-bit little endian */ #define BIN_TYPE_ELF64B 3 /* 64-bit big endian */ +#define BIN_TYPE_COFF64 6 /* 64-bit little endian */ /* Legal values for e_type (object file type). */ #define E_TYPE_NONE 0 /* No file type */ @@ -174,6 +175,7 @@ GET_U64_FROM_ADDR(uint32 *addr) #define E_MACHINE_MIPS_X 51 /* Stanford MIPS-X */ #define E_MACHINE_X86_64 62 /* AMD x86-64 architecture */ #define E_MACHINE_XTENSA 94 /* Tensilica Xtensa Architecture */ +#define E_MACHINE_WIN_X86_64 0x8664 /* Windowx x86-64 architecture */ /* Legal values for e_version */ #define E_VERSION_CURRENT 1 /* Current version */ @@ -232,6 +234,7 @@ get_aot_file_target(AOTTargetInfo *target_info, char *machine_type = NULL; switch (target_info->e_machine) { case E_MACHINE_X86_64: + case E_MACHINE_WIN_X86_64: machine_type = "x86_64"; break; case E_MACHINE_386: @@ -973,7 +976,7 @@ load_object_data_sections(const uint8 **p_buf, const uint8 *buf_end, return false; } #if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64) -#ifndef BH_PLATFORM_LINUX_SGX +#if !defined(BH_PLATFORM_LINUX_SGX) && !defined(BH_PLATFORM_WINDOWS) /* address must be in the first 2 Gigabytes of the process address space */ bh_assert((uintptr_t)data_sections[i].data < INT32_MAX); @@ -1564,7 +1567,11 @@ load_relocation_section(const uint8 *buf, const uint8 *buf_end, if (!strcmp(group->section_name, ".rel.text") || !strcmp(group->section_name, ".rela.text") - || !strcmp(group->section_name, ".rela.literal")) { + || !strcmp(group->section_name, ".rela.literal") +#ifdef BH_PLATFORM_WINDOWS + || !strcmp(group->section_name, ".text") +#endif + ) { if (!do_text_relocation(module, group, error_buf, error_buf_size)) return false; } @@ -1819,7 +1826,7 @@ create_sections(const uint8 *buf, uint32 size, goto fail; } #if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64) -#ifndef BH_PLATFORM_LINUX_SGX +#if !defined(BH_PLATFORM_LINUX_SGX) && !defined(BH_PLATFORM_WINDOWS) /* address must be in the first 2 Gigabytes of the process address space */ bh_assert((uintptr_t)aot_text < INT32_MAX); diff --git a/core/iwasm/aot/arch/aot_reloc_x86_64.c b/core/iwasm/aot/arch/aot_reloc_x86_64.c index a18b1c35e..cd45e096a 100644 --- a/core/iwasm/aot/arch/aot_reloc_x86_64.c +++ b/core/iwasm/aot/arch/aot_reloc_x86_64.c @@ -11,6 +11,8 @@ #define R_X86_64_32 10 /* Direct 32 bit zero extended */ #define R_X86_64_32S 11 /* Direct 32 bit sign extended */ +#define IMAGE_REL_AMD64_REL32 4 /* The 32-bit relative address from the byte following the relocation. */ + void __divdi3(); void __udivdi3(); void __moddi3(); @@ -174,7 +176,9 @@ apply_relocation(AOTModule *module, "Try using wamrc with --size-level=1 option."); return false; } - +#ifdef BH_PLATFORM_WINDOWS + target_addr -= sizeof(int32); +#endif *(int32*)(target_section_addr + reloc_offset) = (int32)target_addr; break; } diff --git a/core/iwasm/compilation/aot_emit_aot_file.c b/core/iwasm/compilation/aot_emit_aot_file.c index 1d27d4f37..e11efbb4f 100644 --- a/core/iwasm/compilation/aot_emit_aot_file.c +++ b/core/iwasm/compilation/aot_emit_aot_file.c @@ -1399,6 +1399,27 @@ aot_emit_relocation_section(uint8 *buf, uint8 *buf_end, uint32 *p_offset, return true; } +typedef uint32 U32; +typedef int32 I32; +typedef uint16 U16; +typedef uint8 U8; + +struct coff_hdr { + U16 u16Machine; + U16 u16NumSections; + U32 u32DateTimeStamp; + U32 u32SymTblPtr; + U32 u32NumSymbols; + U16 u16PeHdrSize; + U16 u16Characs; +}; + +#define IMAGE_FILE_MACHINE_AMD64 0x8664 +#define IMAGE_FILE_MACHINE_I386 0x014c +#define IMAGE_FILE_MACHINE_IA64 0x0200 + +#define AOT_COFF_BIN_TYPE 6 + #define EI_NIDENT 16 typedef uint32 elf32_word; @@ -1487,7 +1508,8 @@ aot_resolve_target_info(AOTCompContext *comp_ctx, AOTObjectData *obj_data) const uint8 *elf_buf = (uint8 *)LLVMGetBufferStart(obj_data->mem_buf); uint32 elf_size = (uint32)LLVMGetBufferSize(obj_data->mem_buf); - if (bin_type != LLVMBinaryTypeELF32L + if (bin_type != LLVMBinaryTypeCOFF + && bin_type != LLVMBinaryTypeELF32L && bin_type != LLVMBinaryTypeELF32B && bin_type != LLVMBinaryTypeELF64L && bin_type != LLVMBinaryTypeELF64B @@ -1501,7 +1523,23 @@ aot_resolve_target_info(AOTCompContext *comp_ctx, AOTObjectData *obj_data) obj_data->target_info.bin_type = bin_type - LLVMBinaryTypeELF32L; - if (bin_type == LLVMBinaryTypeELF32L + if (bin_type == LLVMBinaryTypeCOFF) { + struct coff_hdr * coff_header; + + if (!elf_buf || elf_size < sizeof(struct coff_hdr)) { + aot_set_last_error("invalid coff_hdr buffer."); + return false; + } + coff_header = (struct coff_hdr *)elf_buf; + obj_data->target_info.e_type = 1; + obj_data->target_info.e_machine = coff_header->u16Machine; + obj_data->target_info.e_version = 1; + obj_data->target_info.e_flags = 0; + + if (coff_header->u16Machine == IMAGE_FILE_MACHINE_AMD64) + obj_data->target_info.bin_type = AOT_COFF_BIN_TYPE; + } + else if (bin_type == LLVMBinaryTypeELF32L || bin_type == LLVMBinaryTypeELF32B) { struct elf32_ehdr *elf_header; bool is_little_bin = bin_type == LLVMBinaryTypeELF32L; @@ -1847,7 +1885,7 @@ fail: } static bool -is_relocation_section(char *section_name) +is_relocation_section_name(char *section_name) { return (!strcmp(section_name, ".rela.text") || !strcmp(section_name, ".rel.text") @@ -1864,20 +1902,33 @@ is_relocation_section(char *section_name) strlen(".rel.rodata.cst"))); } +static bool +is_relocation_section(LLVMSectionIteratorRef sec_itr) +{ + uint32 count = 0; + char *name = (char *)LLVMGetSectionName(sec_itr); + if (name) { + if (is_relocation_section_name(name)) + return true; + else if (!strncmp(name, ".text", strlen(".text")) + && get_relocations_count(sec_itr, &count) && count > 0) + return true; + } + return false; +} + static bool get_relocation_groups_count(AOTObjectData *obj_data, uint32 *p_count) { uint32 count = 0; LLVMSectionIteratorRef sec_itr; - char *name; if (!(sec_itr = LLVMObjectFileCopySectionIterator(obj_data->binary))) { aot_set_last_error("llvm get section iterator failed."); return false; } while (!LLVMObjectFileIsSectionIteratorAtEnd(obj_data->binary, sec_itr)) { - if ((name = (char *)LLVMGetSectionName(sec_itr)) - && is_relocation_section(name)) { + if (is_relocation_section(sec_itr)) { count++; } LLVMMoveToNextSection(sec_itr); @@ -1918,8 +1969,8 @@ aot_resolve_object_relocation_groups(AOTObjectData *obj_data) return false; } while (!LLVMObjectFileIsSectionIteratorAtEnd(obj_data->binary, sec_itr)) { - if ((name = (char *)LLVMGetSectionName(sec_itr)) - && is_relocation_section(name)) { + if (is_relocation_section(sec_itr)) { + name = (char *)LLVMGetSectionName(sec_itr); relocation_group->section_name = name; if (!aot_resolve_object_relocation_group( obj_data, diff --git a/core/shared/platform/windows/win_memmap.c b/core/shared/platform/windows/win_memmap.c index 6bcf6b3e0..1e7d7fd8e 100644 --- a/core/shared/platform/windows/win_memmap.c +++ b/core/shared/platform/windows/win_memmap.c @@ -19,6 +19,9 @@ void * os_mmap(void *hint, size_t size, int prot, int flags) /* integer overflow */ return NULL; + if (request_size == 0) + request_size = page_size; + if (prot & MMAP_PROT_EXEC) { if (prot & MMAP_PROT_WRITE) flProtect = PAGE_EXECUTE_READWRITE; From 2499e1ec4ba1a6dd222d40ba4a5009c74a328b78 Mon Sep 17 00:00:00 2001 From: Xu Jun <693788454@qq.com> Date: Mon, 14 Sep 2020 15:30:42 +0800 Subject: [PATCH 068/207] Fix issue and compilation warnings of new function call APIs (#383) --- core/iwasm/aot/arch/aot_reloc_x86_64.c | 3 ++- core/iwasm/common/wasm_runtime_common.c | 9 +++++---- core/iwasm/compilation/aot_emit_aot_file.c | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/core/iwasm/aot/arch/aot_reloc_x86_64.c b/core/iwasm/aot/arch/aot_reloc_x86_64.c index cd45e096a..b19fd9da9 100644 --- a/core/iwasm/aot/arch/aot_reloc_x86_64.c +++ b/core/iwasm/aot/arch/aot_reloc_x86_64.c @@ -11,7 +11,8 @@ #define R_X86_64_32 10 /* Direct 32 bit zero extended */ #define R_X86_64_32S 11 /* Direct 32 bit sign extended */ -#define IMAGE_REL_AMD64_REL32 4 /* The 32-bit relative address from the byte following the relocation. */ +#define IMAGE_REL_AMD64_REL32 4 /* The 32-bit relative address from + the byte following the relocation */ void __divdi3(); void __udivdi3(); diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index b729751b8..ee82a6b4a 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -868,7 +868,7 @@ parse_args_to_uint32_array(WASMType *type, uint32 num_args, wasm_val_t *args, uint32 *out_argv) { - int i, p; + uint32 i, p; for (i = 0, p = 0; i < num_args; i++) { switch (args[i].kind) { @@ -911,13 +911,13 @@ parse_uint32_array_to_results(WASMType *type, uint32 argc, uint32 *argv, wasm_val_t *out_results) { - int i, p; + uint32 i, p; for (i = 0, p = 0; i < type->result_count; i++) { switch (type->types[type->param_count + i]) { case VALUE_TYPE_I32: out_results[i].kind = WASM_I32; - out_results[i].of.i32 = *(int32 *)argv[p++]; + out_results[i].of.i32 = (int32)argv[p++]; break; case VALUE_TYPE_I64: { @@ -1008,6 +1008,7 @@ wasm_runtime_call_wasm_a(WASMExecEnv *exec_env, ret_num = parse_uint32_array_to_results(type, type->ret_cell_num, argv, results); bh_assert(ret_num == num_results); + (void)ret_num; fail2: wasm_runtime_free(argv); @@ -1024,7 +1025,7 @@ wasm_runtime_call_wasm_v(WASMExecEnv *exec_env, wasm_val_t *args = NULL; WASMType *type = NULL; bool ret = false; - int i = 0; + uint32 i = 0; va_list vargs; #if WASM_ENABLE_INTERP != 0 diff --git a/core/iwasm/compilation/aot_emit_aot_file.c b/core/iwasm/compilation/aot_emit_aot_file.c index e11efbb4f..98311ec92 100644 --- a/core/iwasm/compilation/aot_emit_aot_file.c +++ b/core/iwasm/compilation/aot_emit_aot_file.c @@ -1540,7 +1540,7 @@ aot_resolve_target_info(AOTCompContext *comp_ctx, AOTObjectData *obj_data) obj_data->target_info.bin_type = AOT_COFF_BIN_TYPE; } else if (bin_type == LLVMBinaryTypeELF32L - || bin_type == LLVMBinaryTypeELF32B) { + || bin_type == LLVMBinaryTypeELF32B) { struct elf32_ehdr *elf_header; bool is_little_bin = bin_type == LLVMBinaryTypeELF32L; From 547298d4e72bf293aed5776242fd3923e21e399b Mon Sep 17 00:00:00 2001 From: Xu Jun <693788454@qq.com> Date: Tue, 15 Sep 2020 15:49:09 +0800 Subject: [PATCH 069/207] Add macro to exclude sgx wasi/pthread ocalls if not needed (#384) --- core/shared/platform/linux-sgx/sgx_file.c | 5 + core/shared/platform/linux-sgx/sgx_pthread.c | 4 + core/shared/platform/linux-sgx/sgx_signal.c | 4 + core/shared/platform/linux-sgx/sgx_socket.c | 6 +- core/shared/platform/linux-sgx/sgx_thread.c | 36 ++- core/shared/platform/linux-sgx/sgx_time.c | 5 + .../platform/linux-sgx/shared_platform.cmake | 8 + doc/linux_sgx.md | 15 ++ .../linux-sgx/CMakeLists_minimal.txt | 90 ++++++++ .../enclave-sample/Enclave/Enclave.cpp | 8 + .../enclave-sample/Enclave/Enclave.edl | 1 - .../Enclave/Enclave_minimal.edl | 22 ++ .../linux-sgx/enclave-sample/Makefile | 2 +- .../linux-sgx/enclave-sample/Makefile_minimal | 210 ++++++++++++++++++ 14 files changed, 412 insertions(+), 4 deletions(-) create mode 100644 product-mini/platforms/linux-sgx/CMakeLists_minimal.txt create mode 100644 product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave_minimal.edl create mode 100644 product-mini/platforms/linux-sgx/enclave-sample/Makefile_minimal diff --git a/core/shared/platform/linux-sgx/sgx_file.c b/core/shared/platform/linux-sgx/sgx_file.c index 3a0fba342..1b34ea504 100644 --- a/core/shared/platform/linux-sgx/sgx_file.c +++ b/core/shared/platform/linux-sgx/sgx_file.c @@ -7,6 +7,8 @@ #include "sgx_error.h" #include "sgx_file.h" +#ifndef SGX_DISABLE_WASI + #define TRACE_FUNC() os_printf("undefined %s\n", __FUNCTION__) #define TRACE_OCALL_FAIL() os_printf("ocall %s failed!\n", __FUNCTION__) @@ -830,3 +832,6 @@ int get_errno(void) } return ret; } + +#endif + diff --git a/core/shared/platform/linux-sgx/sgx_pthread.c b/core/shared/platform/linux-sgx/sgx_pthread.c index b25368aa5..0d8a9933b 100644 --- a/core/shared/platform/linux-sgx/sgx_pthread.c +++ b/core/shared/platform/linux-sgx/sgx_pthread.c @@ -7,6 +7,8 @@ #include "sgx_pthread.h" #include "sgx_error.h" +#ifndef SGX_DISABLE_WASI + #define TRACE_FUNC() os_printf("undefined %s\n", __FUNCTION__) #define TRACE_OCALL_FAIL() os_printf("ocall %s failed!\n", __FUNCTION__) @@ -73,3 +75,5 @@ int pthread_rwlock_unlock(pthread_rwlock_t *rwlock) return ret; } +#endif + diff --git a/core/shared/platform/linux-sgx/sgx_signal.c b/core/shared/platform/linux-sgx/sgx_signal.c index e2487dea5..698272ca5 100644 --- a/core/shared/platform/linux-sgx/sgx_signal.c +++ b/core/shared/platform/linux-sgx/sgx_signal.c @@ -5,6 +5,8 @@ #include "platform_api_vmcore.h" +#ifndef SGX_DISABLE_WASI + #define TRACE_OCALL_FAIL() os_printf("ocall %s failed!\n", __FUNCTION__) int ocall_raise(int *p_ret, int sig); @@ -24,3 +26,5 @@ int raise(int sig) return ret; } +#endif + diff --git a/core/shared/platform/linux-sgx/sgx_socket.c b/core/shared/platform/linux-sgx/sgx_socket.c index 8eb545da5..e4ed97d2d 100644 --- a/core/shared/platform/linux-sgx/sgx_socket.c +++ b/core/shared/platform/linux-sgx/sgx_socket.c @@ -5,8 +5,9 @@ #include "platform_api_vmcore.h" -#define TRACE_OCALL_FAIL() os_printf("ocall %s failed!\n", __FUNCTION__) +#ifndef SGX_DISABLE_WASI +#define TRACE_OCALL_FAIL() os_printf("ocall %s failed!\n", __FUNCTION__) int ocall_socket(int *p_ret, int domain, int type, int protocol); int ocall_getsockopt(int *p_ret, int sockfd, int level, int optname, @@ -216,3 +217,6 @@ int shutdown(int sockfd, int how) return ret; } + +#endif + diff --git a/core/shared/platform/linux-sgx/sgx_thread.c b/core/shared/platform/linux-sgx/sgx_thread.c index 5d102e1cb..5616a6ad5 100644 --- a/core/shared/platform/linux-sgx/sgx_thread.c +++ b/core/shared/platform/linux-sgx/sgx_thread.c @@ -6,6 +6,7 @@ #include "platform_api_vmcore.h" #include "platform_api_extension.h" +#ifndef SGX_DISABLE_PTHREAD typedef struct { thread_start_routine_t start; void *arg; @@ -52,56 +53,79 @@ int os_thread_create(korp_tid *tid, thread_start_routine_t start, void *arg, return os_thread_create_with_prio(tid, start, arg, stack_size, BH_THREAD_DEFAULT_PRIORITY); } +#endif korp_tid os_self_thread() { +#ifndef SGX_DISABLE_PTHREAD return pthread_self(); +#else + return 0; +#endif } int os_mutex_init(korp_mutex *mutex) { +#ifndef SGX_DISABLE_PTHREAD pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; *mutex = m; +#endif return BHT_OK; } int os_mutex_destroy(korp_mutex *mutex) { +#ifndef SGX_DISABLE_PTHREAD pthread_mutex_destroy(mutex); +#endif return BHT_OK; } int os_mutex_lock(korp_mutex *mutex) { +#ifndef SGX_DISABLE_PTHREAD return pthread_mutex_lock(mutex); +#else + return 0; +#endif } int os_mutex_unlock(korp_mutex *mutex) { +#ifndef SGX_DISABLE_PTHREAD return pthread_mutex_unlock(mutex); +#else + return 0; +#endif } int os_cond_init(korp_cond *cond) { +#ifndef SGX_DISABLE_PTHREAD pthread_cond_t c = PTHREAD_COND_INITIALIZER; *cond = c; +#endif return BHT_OK; } int os_cond_destroy(korp_cond *cond) { +#ifndef SGX_DISABLE_PTHREAD pthread_cond_destroy(cond); +#endif return BHT_OK; } int os_cond_wait(korp_cond *cond, korp_mutex *mutex) { +#ifndef SGX_DISABLE_PTHREAD assert(cond); assert(mutex); if (pthread_cond_wait(cond, mutex) != BHT_OK) return BHT_ERROR; +#endif return BHT_OK; } @@ -114,17 +138,23 @@ int os_cond_reltimedwait(korp_cond *cond, korp_mutex *mutex, int useconds) int os_cond_signal(korp_cond *cond) { +#ifndef SGX_DISABLE_PTHREAD assert(cond); if (pthread_cond_signal(cond) != BHT_OK) return BHT_ERROR; +#endif return BHT_OK; } int os_thread_join(korp_tid thread, void **value_ptr) { +#ifndef SGX_DISABLE_PTHREAD return pthread_join(thread, value_ptr); +#else + return 0; +#endif } int os_thread_detach(korp_tid thread) @@ -135,7 +165,11 @@ int os_thread_detach(korp_tid thread) void os_thread_exit(void *retval) { - return pthread_exit(retval); +#ifndef SGX_DISABLE_PTHREAD + pthread_exit(retval); +#else + return; +#endif } uint8 *os_thread_get_stack_boundary() diff --git a/core/shared/platform/linux-sgx/sgx_time.c b/core/shared/platform/linux-sgx/sgx_time.c index 40239d5f4..34fe12570 100644 --- a/core/shared/platform/linux-sgx/sgx_time.c +++ b/core/shared/platform/linux-sgx/sgx_time.c @@ -28,6 +28,8 @@ os_time_get_boot_microsecond() return 0; } +#ifndef SGX_DISABLE_WASI + int clock_getres(int clock_id, struct timespec *res) { int ret; @@ -113,3 +115,6 @@ int clock_nanosleep(clockid_t clock_id, int flags, return ret; } + +#endif + diff --git a/core/shared/platform/linux-sgx/shared_platform.cmake b/core/shared/platform/linux-sgx/shared_platform.cmake index 58862b552..b2de1ab06 100644 --- a/core/shared/platform/linux-sgx/shared_platform.cmake +++ b/core/shared/platform/linux-sgx/shared_platform.cmake @@ -20,6 +20,14 @@ if (NOT BUILD_UNTRUST_PART EQUAL 1) ${SGX_SDK_DIR}/include/libcxx) endif () +if (NOT WAMR_BUILD_LIBC_WASI EQUAL 1) + add_definitions(-DSGX_DISABLE_WASI) +endif () + +if (NOT WAMR_BUILD_THREAD_MGR EQUAL 1) + add_definitions(-DSGX_DISABLE_PTHREAD) +endif () + file (GLOB source_all ${PLATFORM_SHARED_DIR}/*.c) file (GLOB source_all_untrusted ${PLATFORM_SHARED_DIR}/untrusted/*.c) diff --git a/doc/linux_sgx.md b/doc/linux_sgx.md index b602dcad2..a28f35963 100644 --- a/doc/linux_sgx.md +++ b/doc/linux_sgx.md @@ -39,12 +39,25 @@ or: iwasm [-options] aot_file [args...] ``` +### Minimal build +The libc-WASI and lib-pthread features require a lot of ocalls, if you don't need so much ocalls in your application, you can use the `minimal` version + +``` Bash +# replace the build files with minimal version +cd product-mini/platforms/linux-sgx/ +cp CMakeLists_minimal.txt CMakeLists.txt +cp enclave-sample/Makefile_minimal enclave-sample/Makefile +cp enclave-sample/Enclave/Enclave_minimal.edl enclave-sample/Enclave/Enclave.edl +# follow the building process above +``` + Port WAMR vmcore for Linux SGX ------------------------------ The enclave-sample creates a sample to embed wamr vmlib of Enclave part and App part to an SGX application. To port WAMR vmcore lib to SGX application, there are some steps to do: **Step 1: Add "sgx_wamr.edl" and "sgx_pthread.edl" into EDL file, e.g. Enclave.edl:** +> This step is not required in minimal version ```bash from "sgx_pthread.edl" import *; @@ -68,6 +81,7 @@ The sgx_wamr.edl is under ${WAMR_ROOT}/core/shared/platform/linux-sgx, so please ``` **Step 2: Link libvmlib.a to Enclave part and link libvmlib_untrusted.a to App part:** +> libvmlib_untrusted.a is not required in minimal version ```makefile Enclave_Link_Flags := ... libvmlib.a ... @@ -78,6 +92,7 @@ App_Link_Flags := ... libvmlib_untrusted.a ... ``` **And link SGX pthread lib to Enclave part:** +> SGX pthread lib is not required in minimal version ```makefile Enclave_Link_Flags := ... -lsgx_pthread ... diff --git a/product-mini/platforms/linux-sgx/CMakeLists_minimal.txt b/product-mini/platforms/linux-sgx/CMakeLists_minimal.txt new file mode 100644 index 000000000..336757401 --- /dev/null +++ b/product-mini/platforms/linux-sgx/CMakeLists_minimal.txt @@ -0,0 +1,90 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required (VERSION 2.8) + +project (iwasm) + +set (WAMR_BUILD_PLATFORM "linux-sgx") + +# Reset default linker flags +set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") +set (CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") + +# Set WAMR_BUILD_TARGET +if (NOT DEFINED WAMR_BUILD_TARGET) + if (CMAKE_SIZEOF_VOID_P EQUAL 8) + # Build as X86_64 by default in 64-bit platform + set (WAMR_BUILD_TARGET "X86_64") + else () + # Build as X86_32 by default in 32-bit platform + set (WAMR_BUILD_TARGET "X86_32") + endif () +endif () + +if (NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Release) +endif () + +if (NOT DEFINED WAMR_BUILD_INTERP) + # Enable Interpreter by default + set (WAMR_BUILD_INTERP 1) +endif () + +if (NOT DEFINED WAMR_BUILD_AOT) + # Enable AOT by default + # Please install Intel SGX SDKv2.8 or later. + set (WAMR_BUILD_AOT 1) +endif () + +if (NOT DEFINED WAMR_BUILD_JIT) + # Disable JIT by default. + set (WAMR_BUILD_JIT 0) +endif () + +if (NOT DEFINED WAMR_BUILD_LIBC_BUILTIN) + # Enable libc builtin support by default + set (WAMR_BUILD_LIBC_BUILTIN 1) +endif () + +if (NOT DEFINED WAMR_BUILD_LIBC_WASI) + # Enable libc wasi support by default + set (WAMR_BUILD_LIBC_WASI 0) +endif () + +if (NOT DEFINED WAMR_BUILD_FAST_INTERP) + # Enable fast interpreter + set (WAMR_BUILD_FAST_INTERP 1) +endif () + +if (NOT DEFINED WAMR_BUILD_MULTI_MODULE) + # Enable multiple modules + set (WAMR_BUILD_MULTI_MODULE 0) +endif () + +if (NOT DEFINED WAMR_BUILD_LIB_PTHREAD) + # Enable pthread library by default + set (WAMR_BUILD_LIB_PTHREAD 0) +endif () + +if (COLLECT_CODE_COVERAGE EQUAL 1) + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage") +endif () + +set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") +set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99 -ffunction-sections -fdata-sections \ + -Wall -Wno-unused-parameter -Wno-pedantic \ + -nostdinc -fvisibility=hidden -fpie" ) + +set (WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../..) + +include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) +add_library(vmlib ${WAMR_RUNTIME_LIB_SOURCE}) + +add_custom_command ( + OUTPUT libvmlib_untrusted.a + COMMAND mkdir -p untrusted && cd untrusted && + ${CMAKE_C_COMPILER} -c ${PLATFORM_SHARED_SOURCE_UNTRUSTED} + COMMAND ${CMAKE_AR} rc libvmlib_untrusted.a untrusted/*.o) + +add_custom_target (vmlib_untrusted ALL DEPENDS libvmlib_untrusted.a) diff --git a/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.cpp b/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.cpp index 72bae7b90..5d2b96e32 100644 --- a/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.cpp +++ b/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.cpp @@ -300,6 +300,7 @@ handle_cmd_set_log_level(uint64 *args, uint32 argc) #endif } +#ifndef SGX_DISABLE_WASI static void handle_cmd_set_wasi_args(uint64 *args, int32 argc) { @@ -391,6 +392,13 @@ handle_cmd_set_wasi_args(uint64 *args, int32 argc) *args_org = true; } +#else +static void +handle_cmd_set_wasi_args(uint64 *args, int32 argc) +{ + *args = true; +} +#endif /* end of SGX_DISABLE_WASI */ void ecall_handle_command(unsigned cmd, diff --git a/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.edl b/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.edl index 752e135d1..77d0d3ea1 100644 --- a/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.edl +++ b/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.edl @@ -15,7 +15,6 @@ enclave { unsigned cmd_buf_size); public void ecall_iwasm_main([user_check]uint8_t *wasm_file_buf, uint32_t wasm_file_size); - public void ecall_iwasm_test(); }; untrusted { diff --git a/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave_minimal.edl b/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave_minimal.edl new file mode 100644 index 000000000..5b3bde341 --- /dev/null +++ b/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave_minimal.edl @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +enclave { + from "sgx_tstdc.edl" import *; + + trusted { + /* define ECALLs here. */ + public void ecall_handle_command(unsigned cmd, + [in, out, size=cmd_buf_size]uint8_t *cmd_buf, + unsigned cmd_buf_size); + public void ecall_iwasm_main([user_check]uint8_t *wasm_file_buf, + uint32_t wasm_file_size); + }; + + untrusted { + /* define OCALLs here. */ + void ocall_print([in, string]const char* str); + }; +}; diff --git a/product-mini/platforms/linux-sgx/enclave-sample/Makefile b/product-mini/platforms/linux-sgx/enclave-sample/Makefile index f5467319d..f06b5b89d 100644 --- a/product-mini/platforms/linux-sgx/enclave-sample/Makefile +++ b/product-mini/platforms/linux-sgx/enclave-sample/Makefile @@ -90,7 +90,7 @@ Crypto_Library_Name := sgx_tcrypto WAMR_ROOT := $(CURDIR)/../../../../ -Enclave_Cpp_Files := Enclave/Enclave.cpp Enclave/Enclave_test.cpp +Enclave_Cpp_Files := Enclave/Enclave.cpp Enclave_Include_Paths := -IEnclave -I$(WAMR_ROOT)/core/iwasm/include \ -I$(WAMR_ROOT)/core/shared/utils \ diff --git a/product-mini/platforms/linux-sgx/enclave-sample/Makefile_minimal b/product-mini/platforms/linux-sgx/enclave-sample/Makefile_minimal new file mode 100644 index 000000000..a64d57744 --- /dev/null +++ b/product-mini/platforms/linux-sgx/enclave-sample/Makefile_minimal @@ -0,0 +1,210 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +######## SGX SDK Settings ######## + +SGX_SDK ?= /opt/intel/sgxsdk +SGX_MODE ?= SIM +SGX_ARCH ?= x64 +SGX_DEBUG ?= 0 +SPEC_TEST ?= 0 + +ifeq ($(shell getconf LONG_BIT), 32) + SGX_ARCH := x86 +else ifeq ($(findstring -m32, $(CXXFLAGS)), -m32) + SGX_ARCH := x86 +endif + +ifeq ($(SGX_ARCH), x86) + SGX_COMMON_CFLAGS := -m32 + SGX_LIBRARY_PATH := $(SGX_SDK)/lib + SGX_ENCLAVE_SIGNER := $(SGX_SDK)/bin/x86/sgx_sign + SGX_EDGER8R := $(SGX_SDK)/bin/x86/sgx_edger8r +else + SGX_COMMON_CFLAGS := -m64 + SGX_LIBRARY_PATH := $(SGX_SDK)/lib64 + SGX_ENCLAVE_SIGNER := $(SGX_SDK)/bin/x64/sgx_sign + SGX_EDGER8R := $(SGX_SDK)/bin/x64/sgx_edger8r +endif + +ifeq ($(SGX_DEBUG), 1) +ifeq ($(SGX_PRERELEASE), 1) +$(error Cannot set SGX_DEBUG and SGX_PRERELEASE at the same time!!) +endif +endif + +ifeq ($(SGX_DEBUG), 1) + SGX_COMMON_CFLAGS += -O0 -g +else + SGX_COMMON_CFLAGS += -O2 +endif + +######## App Settings ######## + +ifneq ($(SGX_MODE), HW) + Urts_Library_Name := sgx_urts_sim +else + Urts_Library_Name := sgx_urts +endif + +App_Cpp_Files := App/App.cpp +App_Include_Paths := -IApp -I$(SGX_SDK)/include + +App_C_Flags := $(SGX_COMMON_CFLAGS) -fPIC -Wno-attributes $(App_Include_Paths) + +# Three configuration modes - Debug, prerelease, release +# Debug - Macro DEBUG enabled. +# Prerelease - Macro NDEBUG and EDEBUG enabled. +# Release - Macro NDEBUG enabled. +ifeq ($(SGX_DEBUG), 1) + App_C_Flags += -DDEBUG -UNDEBUG -UEDEBUG +else ifeq ($(SGX_PRERELEASE), 1) + App_C_Flags += -DNDEBUG -DEDEBUG -UDEBUG +else + App_C_Flags += -DNDEBUG -UEDEBUG -UDEBUG +endif + +App_Cpp_Flags := $(App_C_Flags) -std=c++11 +App_Link_Flags := $(SGX_COMMON_CFLAGS) -L$(SGX_LIBRARY_PATH) -l$(Urts_Library_Name) -lpthread + +ifneq ($(SGX_MODE), HW) + App_Link_Flags += -lsgx_uae_service_sim +else + App_Link_Flags += -lsgx_uae_service +endif + +App_Cpp_Objects := $(App_Cpp_Files:.cpp=.o) + +App_Name := iwasm + +######## Enclave Settings ######## + +ifneq ($(SGX_MODE), HW) + Trts_Library_Name := sgx_trts_sim + Service_Library_Name := sgx_tservice_sim +else + Trts_Library_Name := sgx_trts + Service_Library_Name := sgx_tservice +endif +Crypto_Library_Name := sgx_tcrypto + +WAMR_ROOT := $(CURDIR)/../../../../ + +Enclave_Cpp_Files := Enclave/Enclave.cpp + +Enclave_Include_Paths := -IEnclave -I$(WAMR_ROOT)/core/iwasm/include \ + -I$(WAMR_ROOT)/core/shared/utils \ + -I$(WAMR_ROOT)/core/shared/platform/linux-sgx \ + -I$(SGX_SDK)/include \ + -I$(SGX_SDK)/include/tlibc \ + -I$(SGX_SDK)/include/stlport + +Enclave_C_Flags := $(SGX_COMMON_CFLAGS) -nostdinc -fvisibility=hidden -fpie -fstack-protector $(Enclave_Include_Paths) + +# disable wasi +Enclave_C_Flags += -DSGX_DISABLE_WASI + +ifeq ($(SPEC_TEST), 1) + Enclave_C_Flags += -DWASM_ENABLE_SPEC_TEST=1 +else + Enclave_C_Flags += -DWASM_ENABLE_SPEC_TEST=0 +endif +Enclave_Cpp_Flags := $(Enclave_C_Flags) -std=c++03 -nostdinc++ +Enclave_Link_Flags := $(SGX_COMMON_CFLAGS) -Wl,--no-undefined -nostdlib -nodefaultlibs -nostartfiles -L$(SGX_LIBRARY_PATH) \ + -Wl,--whole-archive -l$(Trts_Library_Name) -Wl,--no-whole-archive \ + libvmlib.a \ + -Wl,--start-group -lsgx_tstdc -lsgx_tcxx -l$(Crypto_Library_Name) -l$(Service_Library_Name) -Wl,--end-group \ + -Wl,-Bstatic -Wl,-Bsymbolic -Wl,--no-undefined \ + -Wl,-pie,-eenclave_entry -Wl,--export-dynamic \ + -Wl,--defsym,__ImageBase=0 + +Enclave_Cpp_Objects := $(Enclave_Cpp_Files:.cpp=.o) + +Enclave_Name := enclave.so +Signed_Enclave_Name := enclave.signed.so +Enclave_Config_File := Enclave/Enclave.config.xml + +ifeq ($(SGX_MODE), HW) +ifneq ($(SGX_DEBUG), 1) +ifneq ($(SGX_PRERELEASE), 1) +Build_Mode = HW_RELEASE +endif +endif +endif + + +.PHONY: all run + +ifeq ($(Build_Mode), HW_RELEASE) +all: $(App_Name) $(Enclave_Name) + @echo "The project has been built in release hardware mode." + @echo "Please sign the $(Enclave_Name) first with your signing key before you run the $(App_Name) to launch and access the enclave." + @echo "To sign the enclave use the command:" + @echo " $(SGX_ENCLAVE_SIGNER) sign -key -enclave $(Enclave_Name) -out <$(Signed_Enclave_Name)> -config $(Enclave_Config_File)" + @echo "You can also sign the enclave using an external signing tool. See User's Guide for more details." + @echo "To build the project in simulation mode set SGX_MODE=SIM. To build the project in prerelease mode set SGX_PRERELEASE=1 and SGX_MODE=HW." +else +all: $(App_Name) $(Signed_Enclave_Name) +endif + +run: all +ifneq ($(Build_Mode), HW_RELEASE) + @$(CURDIR)/$(App_Name) + @echo "RUN => $(App_Name) [$(SGX_MODE)|$(SGX_ARCH), OK]" +endif + +######## App Objects ######## + +App/Enclave_u.c: $(SGX_EDGER8R) Enclave/Enclave.edl + @cd App && $(SGX_EDGER8R) --untrusted ../Enclave/Enclave.edl \ + --search-path ../Enclave \ + --search-path $(SGX_SDK)/include \ + --search-path $(WAMR_ROOT)/core/shared/platform/linux-sgx + @echo "GEN => $@" + +App/Enclave_u.o: App/Enclave_u.c + @$(CC) $(App_C_Flags) -c $< -o $@ + @echo "CC <= $<" + +App/%.o: App/%.cpp + @$(CXX) $(App_Cpp_Flags) -c $< -o $@ + @echo "CXX <= $<" + +$(App_Name): App/Enclave_u.o $(App_Cpp_Objects) + @$(CXX) $^ -o $@ $(App_Link_Flags) + @echo "LINK => $@" + + +######## Enclave Objects ######## + +Enclave/Enclave_t.c: $(SGX_EDGER8R) Enclave/Enclave.edl + @cd Enclave && $(SGX_EDGER8R) --trusted ../Enclave/Enclave.edl \ + --search-path ../Enclave \ + --search-path $(SGX_SDK)/include \ + --search-path $(WAMR_ROOT)/core/shared/platform/linux-sgx + @echo "GEN => $@" + +Enclave/Enclave_t.o: Enclave/Enclave_t.c + @$(CC) $(Enclave_C_Flags) -c $< -o $@ + @echo "CC <= $<" + +Enclave/%.o: Enclave/%.cpp + @$(CXX) $(Enclave_Cpp_Flags) -c $< -o $@ + @echo "CXX <= $<" + +libvmlib.a: ../build/libvmlib.a + @cp $< $@ + @echo "CP $@ <= $<" + +$(Enclave_Name): Enclave/Enclave_t.o $(Enclave_Cpp_Objects) libvmlib.a + @$(CXX) $^ -o $@ $(Enclave_Link_Flags) + @echo "LINK => $@" + +$(Signed_Enclave_Name): $(Enclave_Name) + @$(SGX_ENCLAVE_SIGNER) sign -key Enclave/Enclave_private.pem -enclave $(Enclave_Name) -out $@ -config $(Enclave_Config_File) + @echo "SIGN => $@" + +.PHONY: clean + +clean: + @rm -f $(App_Name) $(Enclave_Name) $(Signed_Enclave_Name) $(App_Cpp_Objects) App/Enclave_u.* $(Enclave_Cpp_Objects) Enclave/Enclave_t.* libvmlib.a From c004b01be30c84c4ded3f899584b4cbc00f2b1ab Mon Sep 17 00:00:00 2001 From: Huang Qi <757509347@qq.com> Date: Tue, 15 Sep 2020 20:56:45 +0800 Subject: [PATCH 070/207] Introduce support for NuttX RTOS (#377) Signed-off-by: Huang Qi Co-authored-by: Huang Qi --- README.md | 2 +- core/shared/platform/nuttx/nuttx_platform.c | 70 ++++ core/shared/platform/nuttx/nuttx_thread.c | 86 +++++ .../shared/platform/nuttx/platform_internal.h | 45 +++ .../platform/nuttx/shared_platform.cmake | 14 + doc/build_wamr.md | 3 + product-mini/platforms/nuttx/main.c | 320 ++++++++++++++++++ product-mini/platforms/nuttx/wamr.mk | 141 ++++++++ 8 files changed, 680 insertions(+), 1 deletion(-) create mode 100644 core/shared/platform/nuttx/nuttx_platform.c create mode 100644 core/shared/platform/nuttx/nuttx_thread.c create mode 100644 core/shared/platform/nuttx/platform_internal.h create mode 100644 core/shared/platform/nuttx/shared_platform.cmake create mode 100644 product-mini/platforms/nuttx/main.c create mode 100644 product-mini/platforms/nuttx/wamr.mk diff --git a/README.md b/README.md index 446209f81..a3e062a2b 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ The iwasm supports the following architectures: Following platforms are supported. Refer to [WAMR porting guide](./doc/port_wamr.md) for how to port WAMR to a new platform. - [Linux](./doc/build_wamr.md#linux), [Linux SGX (Intel Software Guard Extension)](./doc/linux_sgx.md), [MacOS](./doc/build_wamr.md#macos), [Android](./doc/build_wamr.md#android) -- [Zephyr](./doc/build_wamr.md#zephyr), [AliOS-Things](./doc/build_wamr.md#alios-things), [VxWorks](./doc/build_wamr.md#vxworks) +- [Zephyr](./doc/build_wamr.md#zephyr), [AliOS-Things](./doc/build_wamr.md#alios-things), [VxWorks](./doc/build_wamr.md#vxworks), [NuttX](./doc/build_wamr.md#nuttx) ### Build iwasm VM core (mini product) diff --git a/core/shared/platform/nuttx/nuttx_platform.c b/core/shared/platform/nuttx/nuttx_platform.c new file mode 100644 index 000000000..4a126c731 --- /dev/null +++ b/core/shared/platform/nuttx/nuttx_platform.c @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2020 XiaoMi Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "platform_api_extension.h" +#include "platform_api_vmcore.h" + +int +bh_platform_init() +{ + return 0; +} + +void +bh_platform_destroy() +{} + +void * +os_malloc(unsigned size) +{ + return malloc(size); +} + +void * +os_realloc(void *ptr, unsigned size) +{ + return realloc(ptr, size); +} + +void +os_free(void *ptr) +{ + free(ptr); +} + +void * +os_mmap(void *hint, size_t size, int prot, int flags) +{ + if ((uint64)size >= UINT32_MAX) + return NULL; + return malloc((uint32)size); +} + +void +os_munmap(void *addr, size_t size) +{ + return free(addr); +} + +int +os_mprotect(void *addr, size_t size, int prot) +{ + return 0; +} + +void +os_dcache_flush() +{} + +uint64 +os_time_get_boot_microsecond() +{ + struct timespec ts; + if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) { + return 0; + } + + return ((uint64)ts.tv_sec) * 1000 * 1000 + ((uint64)ts.tv_nsec) / 1000; +} diff --git a/core/shared/platform/nuttx/nuttx_thread.c b/core/shared/platform/nuttx/nuttx_thread.c new file mode 100644 index 000000000..aa69ee4d0 --- /dev/null +++ b/core/shared/platform/nuttx/nuttx_thread.c @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2020 XiaoMi Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "platform_api_extension.h" +#include "platform_api_vmcore.h" + +korp_tid +os_self_thread() +{ + return (korp_tid)pthread_self(); +} + +int +os_mutex_init(korp_mutex *mutex) +{ + return pthread_mutex_init(mutex, NULL) == 0 ? BHT_OK : BHT_ERROR; +} + +int +os_mutex_destroy(korp_mutex *mutex) +{ + int ret; + + assert(mutex); + ret = pthread_mutex_destroy(mutex); + + return ret == 0 ? BHT_OK : BHT_ERROR; +} + +int +os_mutex_lock(korp_mutex *mutex) +{ + int ret; + + assert(mutex); + ret = pthread_mutex_lock(mutex); + if (0 != ret) { + os_printf("vm mutex lock failed (ret=%d)!\n", ret); + exit(-1); + } + return ret; +} + +int +os_mutex_unlock(korp_mutex *mutex) +{ + int ret; + + assert(mutex); + ret = pthread_mutex_unlock(mutex); + if (0 != ret) { + os_printf("vm mutex unlock failed (ret=%d)!\n", ret); + exit(-1); + } + return ret; +} + +uint8 * +os_thread_get_stack_boundary() +{ + return NULL; +} + +int +os_cond_init(korp_cond *cond) +{ + assert(cond); + + if (pthread_cond_init(cond, NULL) != BHT_OK) + return BHT_ERROR; + + return BHT_OK; +} + +int +os_cond_destroy(korp_cond *cond) +{ + assert(cond); + + if (pthread_cond_destroy(cond) != BHT_OK) + return BHT_ERROR; + + return BHT_OK; +} diff --git a/core/shared/platform/nuttx/platform_internal.h b/core/shared/platform/nuttx/platform_internal.h new file mode 100644 index 000000000..856aab432 --- /dev/null +++ b/core/shared/platform/nuttx/platform_internal.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2020 XiaoMi Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _PLATFORM_INTERNAL_H +#define _PLATFORM_INTERNAL_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef BH_PLATFORM_NUTTX +#define BH_PLATFORM_NUTTX +#endif + +typedef pthread_t korp_tid; +typedef pthread_mutex_t korp_mutex; +typedef pthread_cond_t korp_cond; +typedef pthread_t korp_thread; + +#define BH_APPLET_PRESERVED_STACK_SIZE (2 * BH_KB) + +/* Default thread priority */ +#define BH_THREAD_DEFAULT_PRIORITY 100 + +#define os_printf printf +#define os_vprintf vprintf + +#ifdef __cplusplus +} +#endif + +#endif /* end of _BH_PLATFORM_H */ diff --git a/core/shared/platform/nuttx/shared_platform.cmake b/core/shared/platform/nuttx/shared_platform.cmake new file mode 100644 index 000000000..7b29b5f09 --- /dev/null +++ b/core/shared/platform/nuttx/shared_platform.cmake @@ -0,0 +1,14 @@ +# Copyright (C) 2020 XiaoMi Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +set (PLATFORM_SHARED_DIR ${CMAKE_CURRENT_LIST_DIR}) + +add_definitions(-DBH_PLATFORM_NUTTX) + +include_directories(${PLATFORM_SHARED_DIR}) +include_directories(${PLATFORM_SHARED_DIR}/../include) + +file (GLOB_RECURSE source_all ${PLATFORM_SHARED_DIR}/*.c) + +set (PLATFORM_SHARED_SOURCE ${source_all} ${PLATFORM_COMMON_MATH_SOURCE}) + diff --git a/doc/build_wamr.md b/doc/build_wamr.md index c0b36f29b..f7fc9e21a 100644 --- a/doc/build_wamr.md +++ b/doc/build_wamr.md @@ -301,6 +301,9 @@ $ # include/ includes all necesary head files $ # lib includes libiwasm.so ``` +NuttX +------------------------- +WAMR is intergrated with NuttX, just enable the WAMR in Kconfig option (Application Configuration/Interpreters). Docker ------------------------- diff --git a/product-mini/platforms/nuttx/main.c b/product-mini/platforms/nuttx/main.c new file mode 100644 index 000000000..25c654fd1 --- /dev/null +++ b/product-mini/platforms/nuttx/main.c @@ -0,0 +1,320 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#include +#include + +#include "bh_platform.h" +#include "bh_read_file.h" +#include "wasm_export.h" + +static int app_argc; +static char **app_argv; + +#define MODULE_PATH ("--module-path=") + +static int +print_help() +{ + printf("Usage: iwasm [-options] wasm_file [args...]\n"); + printf("options:\n"); + printf(" -f|--function name Specify a function name of the module to run rather\n" + " than main\n"); +#if WASM_ENABLE_LOG != 0 + printf(" -v=n Set log verbose level (0 to 5, default is 2) larger\n" + " level with more log\n"); +#endif + printf(" --stack-size=n Set maximum stack size in bytes, default is 16 KB\n"); + printf(" --heap-size=n Set maximum heap size in bytes, default is 16 KB\n"); +#if WASM_ENABLE_LIBC_WASI != 0 + printf(" --env= Pass wasi environment variables with \"key=value\"\n"); + printf(" to the program, for example:\n"); + printf(" --env=\"key1=value1\" --env=\"key2=value2\"\n"); + printf(" --dir= Grant wasi access to the given host directories\n"); + printf(" to the program, for example:\n"); + printf(" --dir= --dir=\n"); +#endif +#if WASM_ENABLE_MULTI_MODULE != 0 + printf(" --module-path= Indicate a module search path. default is current\n" + " directory('./')\n"); +#endif +#if WASM_ENABLE_LIB_PTHREAD != 0 + printf(" --max-threads=n Set maximum thread number per cluster, default is 4\n"); +#endif + return 1; +} + +static void * +app_instance_main(wasm_module_inst_t module_inst) +{ + const char *exception; + + wasm_application_execute_main(module_inst, app_argc, app_argv); + if ((exception = wasm_runtime_get_exception(module_inst))) + printf("%s\n", exception); + return NULL; +} + +static void * +app_instance_func(wasm_module_inst_t module_inst, const char *func_name) +{ + wasm_application_execute_func(module_inst, func_name, app_argc - 1, + app_argv + 1); + /* The result of wasm function or exception info was output inside + wasm_application_execute_func(), here we don't output them again. */ + return NULL; +} + +#if WASM_ENABLE_LIBC_WASI != 0 +static bool +validate_env_str(char *env) +{ + char *p = env; + int key_len = 0; + + while (*p != '\0' && *p != '=') { + key_len++; + p++; + } + + if (*p != '=' || key_len == 0) + return false; + + return true; +} +#endif + +#define USE_GLOBAL_HEAP_BUF 1 + +#if USE_GLOBAL_HEAP_BUF != 0 +static char global_heap_buf[164 * 1024] = { 0 }; +#endif + +#if WASM_ENABLE_MULTI_MODULE != 0 +static char * +handle_module_path(const char *module_path) +{ + // next character after = + return (strchr(module_path, '=')) + 1; +} + +static char *module_search_path = "."; +static bool +module_reader_callback(const char *module_name, uint8 **p_buffer, + uint32 *p_size) +{ + const char *format = "%s/%s.wasm"; + int sz = strlen(module_search_path) + strlen("/") + strlen(module_name) + + strlen(".wasm") + 1; + char *wasm_file_name = BH_MALLOC(sz); + if (!wasm_file_name) { + return false; + } + + snprintf(wasm_file_name, sz, format, module_search_path, module_name); + + *p_buffer = (uint8_t *)bh_read_file_to_buffer(wasm_file_name, p_size); + + wasm_runtime_free(wasm_file_name); + return *p_buffer != NULL; +} + +static void +moudle_destroyer(uint8 *buffer, uint32 size) +{ + if (!buffer) { + return; + } + + wasm_runtime_free(buffer); + buffer = NULL; +} +#endif /* WASM_ENABLE_MULTI_MODULE */ + +int +main(int argc, char *argv[]) +{ + char *wasm_file = NULL; + const char *func_name = NULL; + uint8 *wasm_file_buf = NULL; + uint32 wasm_file_size; + uint32 stack_size = 16 * 1024, heap_size = 16 * 1024; + wasm_module_t wasm_module = NULL; + wasm_module_inst_t wasm_module_inst = NULL; + RuntimeInitArgs init_args; + char error_buf[128] = { 0 }; +#if WASM_ENABLE_LOG != 0 + int log_verbose_level = 2; +#endif +#if WASM_ENABLE_LIBC_WASI != 0 + const char *dir_list[8] = { NULL }; + uint32 dir_list_size = 0; + const char *env_list[8] = { NULL }; + uint32 env_list_size = 0; +#endif + + /* Process options. */ + // TODO: use a option name and option handler pair table to + // optimize + for (argc--, argv++; argc > 0 && argv[0][0] == '-'; argc--, argv++) { + if (!strcmp(argv[0], "-f") || !strcmp(argv[0], "--function")) { + argc--, argv++; + if (argc < 2) { + print_help(); + return 0; + } + func_name = argv[0]; + } +#if WASM_ENABLE_LOG != 0 + else if (!strncmp(argv[0], "-v=", 3)) { + log_verbose_level = atoi(argv[0] + 3); + if (log_verbose_level < 0 || log_verbose_level > 5) + return print_help(); + } +#endif + else if (!strncmp(argv[0], "--stack-size=", 13)) { + if (argv[0][13] == '\0') + return print_help(); + stack_size = atoi(argv[0] + 13); + } + else if (!strncmp(argv[0], "--heap-size=", 12)) { + if (argv[0][12] == '\0') + return print_help(); + heap_size = atoi(argv[0] + 12); + } +#if WASM_ENABLE_LIBC_WASI != 0 + else if (!strncmp(argv[0], "--dir=", 6)) { + if (argv[0][6] == '\0') + return print_help(); + if (dir_list_size >= sizeof(dir_list) / sizeof(char *)) { + printf("Only allow max dir number %d\n", + (int)(sizeof(dir_list) / sizeof(char *))); + return -1; + } + dir_list[dir_list_size++] = argv[0] + 6; + } + else if (!strncmp(argv[0], "--env=", 6)) { + char *tmp_env; + + if (argv[0][6] == '\0') + return print_help(); + if (env_list_size >= sizeof(env_list) / sizeof(char *)) { + printf("Only allow max env number %d\n", + (int)(sizeof(env_list) / sizeof(char *))); + return -1; + } + tmp_env = argv[0] + 6; + if (validate_env_str(tmp_env)) + env_list[env_list_size++] = tmp_env; + else { + printf("Wasm parse env string failed: expect \"key=value\", " + "got \"%s\"\n", + tmp_env); + return print_help(); + } + } +#endif /* WASM_ENABLE_LIBC_WASI */ +#if WASM_ENABLE_MULTI_MODULE != 0 + else if (!strncmp(argv[0], MODULE_PATH, strlen(MODULE_PATH))) { + module_search_path = handle_module_path(argv[0]); + if (!strlen(module_search_path)) { + return print_help(); + } + } +#endif +#if WASM_ENABLE_LIB_PTHREAD != 0 + else if (!strncmp(argv[0], "--max-threads=", 14)) { + if (argv[0][14] == '\0') + return print_help(); + wasm_runtime_set_max_thread_num(atoi(argv[0] + 14)); + } +#endif + else + return print_help(); + } + + if (argc == 0) + return print_help(); + + wasm_file = argv[0]; + app_argc = argc; + app_argv = argv; + + memset(&init_args, 0, sizeof(RuntimeInitArgs)); + +#if USE_GLOBAL_HEAP_BUF != 0 + init_args.mem_alloc_type = Alloc_With_Pool; + init_args.mem_alloc_option.pool.heap_buf = global_heap_buf; + init_args.mem_alloc_option.pool.heap_size = sizeof(global_heap_buf); +#else + init_args.mem_alloc_type = Alloc_With_Allocator; + init_args.mem_alloc_option.allocator.malloc_func = malloc; + init_args.mem_alloc_option.allocator.realloc_func = realloc; + init_args.mem_alloc_option.allocator.free_func = free; +#endif + + /* initialize runtime environment */ + if (!wasm_runtime_full_init(&init_args)) { + printf("Init runtime environment failed.\n"); + return -1; + } + +#if WASM_ENABLE_LOG != 0 + bh_log_set_verbose_level(log_verbose_level); +#endif + + /* load WASM byte buffer from WASM bin file */ + if (!(wasm_file_buf = + (uint8 *)bh_read_file_to_buffer(wasm_file, &wasm_file_size))) + goto fail1; + +#if WASM_ENABLE_MULTI_MODULE != 0 + wasm_runtime_set_module_reader(module_reader_callback, moudle_destroyer); +#endif + + /* load WASM module */ + if (!(wasm_module = wasm_runtime_load(wasm_file_buf, wasm_file_size, + error_buf, sizeof(error_buf)))) { + printf("%s\n", error_buf); + goto fail2; + } + +#if WASM_ENABLE_LIBC_WASI != 0 + wasm_runtime_set_wasi_args(wasm_module, dir_list, dir_list_size, NULL, 0, + env_list, env_list_size, argv, argc); +#endif + + /* instantiate the module */ + if (!(wasm_module_inst = + wasm_runtime_instantiate(wasm_module, stack_size, heap_size, + error_buf, sizeof(error_buf)))) { + printf("%s\n", error_buf); + goto fail3; + } + + if (func_name) + app_instance_func(wasm_module_inst, func_name); + else + app_instance_main(wasm_module_inst); + + /* destroy the module instance */ + wasm_runtime_deinstantiate(wasm_module_inst); + +fail3: + /* unload the module */ + wasm_runtime_unload(wasm_module); + +fail2: + /* free the file buffer */ + wasm_runtime_free(wasm_file_buf); + +fail1: + /* destroy runtime environment */ + wasm_runtime_destroy(); + return 0; +} diff --git a/product-mini/platforms/nuttx/wamr.mk b/product-mini/platforms/nuttx/wamr.mk new file mode 100644 index 000000000..56fadfae3 --- /dev/null +++ b/product-mini/platforms/nuttx/wamr.mk @@ -0,0 +1,141 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +CORE_ROOT := wamr/core +IWASM_ROOT := wamr/core/iwasm +SHARED_ROOT := wamr/core/shared + +ifeq ($(CONFIG_ARCH_ARMV7M),y) +WAMR_BUILD_TARGET := THUMBV7EM +else ifeq ($(CONFIG_ARCH_ARMV8M),y) +WAMR_BUILD_TARGET := THUMBV8M +else ifeq ($(CONFIG_ARCH_X86),y) +WAMR_BUILD_TARGET := X86_32 +else ifeq ($(CONFIG_ARCH_X86_64),y) +WAMR_BUILD_TARGET := X86_64 +else ifeq ($(CONFIG_ARCH_XTENSA),y) +WAMR_BUILD_TARGET := XTENSA +endif + +WAMR_BUILD_PLATFORM := nuttx + +ifeq (${WAMR_BUILD_TARGET}, X86_32) + CFLAGS += -DBUILD_TARGET_X86_32 + INVOKE_NATIVE := invokeNative_ia32.s + AOT_RELOC := aot_reloc_x86_32.c +else ifeq (${WAMR_BUILD_TARGET}, X86_64) + CFLAGS += -DBUILD_TARGET_X86_64 + INVOKE_NATIVE := invokeNative_em64.s + AOT_RELOC := aot_reloc_x86_64.c +else ifeq ($(findstring ARM,$(WAMR_BUILD_TARGET)), ARM) + CFLAGS += -DBUILD_TARGET_ARM + CFLAGS += -DBUILD_TARGET=\"$(WAMR_BUILD_TARGET)\" + INVOKE_NATIVE := invokeNative_arm.s + AOT_RELOC := aot_reloc_arm.c +else ifeq ($(findstring THUMB,$(WAMR_BUILD_TARGET)), THUMB) + CFLAGS += -DBUILD_TARGET_THUMB + CFLAGS += -DBUILD_TARGET=\"$(WAMR_BUILD_TARGET)\" + ifeq ($(CONFIG_ARCH_FPU),y) + INVOKE_NATIVE := invokeNative_thumb_vfp.s + else + INVOKE_NATIVE := invokeNative_thumb.s + endif + AOT_RELOC := aot_reloc_thumb.c +else ifeq (${WAMR_BUILD_TARGET}, MIPS) + CFLAGS += -DBUILD_TARGET_MIPS + INVOKE_NATIVE := invokeNative_mips.s + AOT_RELOC := aot_reloc_mips.c +else ifeq (${WAMR_BUILD_TARGET}, XTENSA) + CFLAGS += -DBUILD_TARGET_XTENSA + INVOKE_NATIVE := invokeNative_xtensa.s + AOT_RELOC := aot_reloc_xtensa.c +else + $(error Build target don't support) +endif + +ifeq (${CONFIG_INTERPRETERS_WAMR_LOG},y) +CFLAGS += -DWASM_ENABLE_LOG=1 +else +CFLAGS += -DWASM_ENABLE_LOG=0 +endif + +ifeq (${CONFIG_INTERPRETERS_WAMR_AOT},y) +CFLAGS += -I${IWASM_ROOT}/aot +CFLAGS += -DWASM_ENABLE_AOT=1 +CSRCS += aot_loader.c \ + ${AOT_RELOC} \ + aot_runtime.c +else +CFLAGS += -DWASM_ENABLE_AOT=0 +endif + +CFLAGS += -DWASM_ENABLE_INTERP=1 +CSRCS += wasm_runtime.c wasm_loader.c + +ifeq (${CONFIG_INTERPRETERS_WAMR_FAST},y) +CFLAGS += -DWASM_ENABLE_FAST_INTERP=1 +CSRCS += wasm_interp_fast.c +else +CSRCS += wasm_interp_classic.c +endif + +ifeq ($(CONFIG_INTERPRETERS_WAMR_LIBC_BUILTIN),y) +CFLAGS += -DWASM_ENABLE_LIBC_BUILTIN=1 +else +CFLAGS += -DWASM_ENABLE_LIBC_BUILTIN=0 +endif + +CFLAGS += -DWASM_ENABLE_MULTI_MODULE=0 +CFLAGS += -DWASM_ENABLE_THREAD_MGR=0 +CFLAGS += -Wno-strict-prototypes + +CFLAGS += -I${CORE_ROOT} \ + -I${IWASM_ROOT}/include \ + -I${IWASM_ROOT}/common \ + -I${SHARED_ROOT}/include \ + -I${SHARED_ROOT}/platform/include \ + -I${SHARED_ROOT}/utils \ + -I${SHARED_ROOT}/utils/uncommon \ + -I${SHARED_ROOT}/mem-alloc \ + -I${SHARED_ROOT}/platform/nuttx + + +ifeq (${WAMR_BUILD_INTERP}, 1) +CFLAGS += -I${IWASM_ROOT}/interpreter +endif + +CSRCS += nuttx_platform.c \ + nuttx_thread.c \ + mem_alloc.c \ + ems_kfc.c \ + ems_alloc.c \ + ems_hmu.c \ + bh_assert.c \ + bh_common.c \ + bh_hashmap.c \ + bh_list.c \ + bh_log.c \ + bh_queue.c \ + bh_vector.c \ + bh_read_file.c \ + runtime_timer.c \ + libc_builtin_wrapper.c \ + wasm_runtime_common.c \ + wasm_native.c \ + wasm_exec_env.c \ + wasm_memory.c + +ASRCS += ${INVOKE_NATIVE} + +VPATH += ${SHARED_ROOT}/platform/nuttx +VPATH += ${SHARED_ROOT}/mem-alloc +VPATH += ${SHARED_ROOT}/mem-alloc/ems +VPATH += ${SHARED_ROOT}/utils +VPATH += ${SHARED_ROOT}/utils/uncommon +VPATH += ${IWASM_ROOT}/common +VPATH += ${IWASM_ROOT}/interpreter +VPATH += ${IWASM_ROOT}/libraries +VPATH += ${IWASM_ROOT}/libraries/libc-builtin +VPATH += ${IWASM_ROOT}/common/arch +VPATH += ${IWASM_ROOT}/aot +VPATH += ${IWASM_ROOT}/aot/arch From 04a7cc322f0cf16ecea5a906e74a1893127d696e Mon Sep 17 00:00:00 2001 From: Huang Qi <757509347@qq.com> Date: Wed, 16 Sep 2020 17:53:03 +0800 Subject: [PATCH 071/207] core/shared: Add guard to avoid redefine macro (#386) Signed-off-by: Huang Qi Co-authored-by: Huang Qi --- core/shared/platform/include/platform_common.h | 10 ++++++++++ core/shared/utils/bh_log.h | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/core/shared/platform/include/platform_common.h b/core/shared/platform/include/platform_common.h index 33c93e432..02d71fc68 100644 --- a/core/shared/platform/include/platform_common.h +++ b/core/shared/platform/include/platform_common.h @@ -47,11 +47,21 @@ void BH_FREE(void *ptr); #endif #ifndef __cplusplus + +#ifndef true #define true 1 +#endif + +#ifndef false #define false 0 +#endif + +#ifndef inline #define inline __inline #endif +#endif + /* Return the offset of the given field in the given type */ #ifndef offsetof #define offsetof(Type, field) ((size_t)(&((Type *)0)->field)) diff --git a/core/shared/utils/bh_log.h b/core/shared/utils/bh_log.h index 6a5ead46b..e0720964e 100644 --- a/core/shared/utils/bh_log.h +++ b/core/shared/utils/bh_log.h @@ -41,6 +41,16 @@ bh_log_set_verbose_level(uint32 level); void bh_log(LogLevel log_level, const char *file, int line, const char *fmt, ...); +#ifdef BH_PLATFORM_NUTTX + +#undef LOG_FATAL +#undef LOG_ERROR +#undef LOG_WARNING +#undef LOG_VERBOSE +#undef LOG_DEBUG + +#endif + #if BH_DEBUG == 1 #define LOG_FATAL(...) bh_log(BH_LOG_LEVEL_FATAL, __FILE__, __LINE__, __VA_ARGS__) #else From 0226dbbb3d00ab8ce7599df7d938819b57b3c22e Mon Sep 17 00:00:00 2001 From: Xu Jun <693788454@qq.com> Date: Fri, 18 Sep 2020 18:04:56 +0800 Subject: [PATCH 072/207] introduce WAMR memory profiling tool (experimental) (#390) --- build-scripts/config_common.cmake | 4 + core/config.h | 20 ++- core/iwasm/aot/aot_loader.c | 14 +- core/iwasm/aot/aot_runtime.c | 139 +++++++++++++++ core/iwasm/aot/aot_runtime.h | 8 + core/iwasm/common/wasm_exec_env.c | 4 + core/iwasm/common/wasm_exec_env.h | 16 +- core/iwasm/common/wasm_memory.c | 177 ++++++++++--------- core/iwasm/common/wasm_native.c | 3 + core/iwasm/common/wasm_runtime_common.c | 172 +++++++++++++++++- core/iwasm/common/wasm_runtime_common.h | 39 ++++ core/iwasm/include/wasm_export.h | 12 ++ core/iwasm/interpreter/wasm.h | 2 +- core/iwasm/interpreter/wasm_interp_classic.c | 8 + core/iwasm/interpreter/wasm_interp_fast.c | 8 + core/iwasm/interpreter/wasm_loader.c | 57 +++--- core/iwasm/interpreter/wasm_mini_loader.c | 55 +++--- core/iwasm/interpreter/wasm_runtime.c | 150 +++++++++++++++- core/iwasm/interpreter/wasm_runtime.h | 16 +- core/shared/mem-alloc/ems/ems_alloc.c | 17 +- core/shared/mem-alloc/ems/ems_gc_internal.h | 2 + core/shared/mem-alloc/ems/ems_kfc.c | 21 ++- core/shared/utils/bh_hashmap.c | 58 +++++- core/shared/utils/bh_hashmap.h | 35 ++++ core/shared/utils/uncommon/bh_read_file.c | 6 + doc/build_wamr.md | 5 + test-tools/host-tool/CMakeLists.txt | 5 +- 27 files changed, 848 insertions(+), 205 deletions(-) diff --git a/build-scripts/config_common.cmake b/build-scripts/config_common.cmake index f22691dd6..9d441b2a0 100644 --- a/build-scripts/config_common.cmake +++ b/build-scripts/config_common.cmake @@ -162,6 +162,10 @@ if (WAMR_DISABLE_HW_BOUND_CHECK EQUAL 1) add_definitions (-DWASM_DISABLE_HW_BOUND_CHECK=1) message (" Hardware boundary check disabled") endif () +if (WAMR_BUILD_MEMORY_PROFILING EQUAL 1) + add_definitions (-DWASM_ENABLE_MEMORY_PROFILING=1) + message (" Memory profiling enabled") +endif () if (DEFINED WAMR_APP_THREAD_STACK_SIZE_MAX) add_definitions (-DAPP_THREAD_STACK_SIZE_MAX=${WAMR_APP_THREAD_STACK_SIZE_MAX}) endif () diff --git a/core/config.h b/core/config.h index 414056b8a..1c932a652 100644 --- a/core/config.h +++ b/core/config.h @@ -164,11 +164,20 @@ enum { #define WASM_DISABLE_HW_BOUND_CHECK 0 #endif -/* Heap and stack profiling */ -#define BH_ENABLE_MEMORY_PROFILING 0 +/* Memory profiling */ +#ifndef WASM_ENABLE_MEMORY_PROFILING +#define WASM_ENABLE_MEMORY_PROFILING 0 +#endif + +/* Memory tracing */ +#ifndef WASM_ENABLE_MEMORY_TRACING +#define WASM_ENABLE_MEMORY_TRACING 0 +#endif /* Heap verification */ +#ifndef BH_ENABLE_GC_VERIFY #define BH_ENABLE_GC_VERIFY 0 +#endif /* Max app number of all modules */ #define MAX_APP_INSTALLATIONS 3 @@ -197,12 +206,9 @@ enum { /* The max percentage of global heap that app memory space can grow */ #define APP_MEMORY_MAX_GLOBAL_HEAP_PERCENT 1 / 3 -/* Default base offset of app heap space */ -#define DEFAULT_APP_HEAP_BASE_OFFSET (1 * BH_GB) - /* Default min/max heap size of each app */ #define APP_HEAP_SIZE_DEFAULT (8 * 1024) -#define APP_HEAP_SIZE_MIN (2 * 1024) +#define APP_HEAP_SIZE_MIN (512) #define APP_HEAP_SIZE_MAX (512 * 1024 * 1024) /* Default wasm stack size of each app */ @@ -229,7 +235,9 @@ enum { #define RESERVED_BYTES_TO_NATIVE_STACK_BOUNDARY (512) /* Default wasm block address cache size and conflict list size */ +#ifndef BLOCK_ADDR_CACHE_SIZE #define BLOCK_ADDR_CACHE_SIZE 64 +#endif #define BLOCK_ADDR_CONFLICT_SIZE 2 #ifndef WASM_ENABLE_SPEC_TEST diff --git a/core/iwasm/aot/aot_loader.c b/core/iwasm/aot/aot_loader.c index 90a4f2e2e..a3dacd33d 100644 --- a/core/iwasm/aot/aot_loader.c +++ b/core/iwasm/aot/aot_loader.c @@ -1701,18 +1701,12 @@ load_from_sections(AOTModule *module, AOTSection *sections, * otherwise unpredictable behavior can occur. */ os_dcache_flush(); +#if WASM_ENABLE_MEMORY_TRACING != 0 + wasm_runtime_dump_module_mem_consumption((WASMModuleCommon*)module); +#endif return true; } -#if BH_ENABLE_MEMORY_PROFILING != 0 -static void aot_free(void *ptr) -{ - wasm_runtime_free(ptr); -} -#else -#define aot_free wasm_runtime_free -#endif - static AOTModule* create_module(char *error_buf, uint32 error_buf_size) { @@ -1730,7 +1724,7 @@ create_module(char *error_buf, uint32 error_buf_size) (HashFunc)wasm_string_hash, (KeyEqualFunc)wasm_string_equal, NULL, - aot_free))) { + wasm_runtime_free))) { set_error_buf(error_buf, error_buf_size, "create const string set failed"); wasm_runtime_free(module); diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index 0b4fbfc73..ad5c438ba 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -801,6 +801,11 @@ aot_instantiate(AOTModule *module, bool is_sub_inst, #endif #endif +#if WASM_ENABLE_MEMORY_TRACING != 0 + wasm_runtime_dump_module_inst_mem_consumption + ((WASMModuleInstanceCommon *)module_inst); +#endif + return module_inst; fail: @@ -1932,3 +1937,137 @@ aot_get_aux_stack(WASMExecEnv *exec_env, } #endif + +#if (WASM_ENABLE_MEMORY_PROFILING != 0) || (WASM_ENABLE_MEMORY_TRACING != 0) +static uint32 const_string_size; + +void const_string_node_size_cb(void *key, void *value) +{ + const_string_size += bh_hash_map_get_elem_struct_size(); + const_string_size += strlen((const char *)value) + 1; +} + +void +aot_get_module_mem_consumption(const AOTModule *module, + WASMModuleMemConsumption *mem_conspn) +{ + uint32 i, size; + + memset(mem_conspn, 0, sizeof(*mem_conspn)); + + mem_conspn->module_struct_size = sizeof(AOTModule); + + mem_conspn->types_size = sizeof(AOTFuncType *) * module->func_type_count; + for (i = 0; i < module->func_type_count; i++) { + AOTFuncType *type = module->func_types[i]; + size = offsetof(AOTFuncType, types) + + sizeof(uint8) * (type->param_count + type->result_count); + mem_conspn->types_size += size; + } + + mem_conspn->imports_size = + sizeof(AOTImportMemory) * module->import_memory_count + + sizeof(AOTImportTable) * module->import_table_count + + sizeof(AOTImportGlobal) * module->import_global_count + + sizeof(AOTImportFunc) * module->import_func_count; + + /* func_ptrs and func_type_indexes */ + mem_conspn->functions_size = + (sizeof(void *) + sizeof(uint32)) * module->func_count; + + mem_conspn->tables_size = sizeof(AOTTable) * module->table_count; + + mem_conspn->memories_size = sizeof(AOTMemory) * module->memory_count; + mem_conspn->globals_size = sizeof(AOTGlobal) * module->global_count; + mem_conspn->exports_size = sizeof(AOTExport) * module->export_count; + + mem_conspn->table_segs_size = + sizeof(AOTTableInitData *) * module->table_init_data_count; + for (i = 0; i < module->table_init_data_count; i++) { + AOTTableInitData *init_data = module->table_init_data_list[i]; + size = offsetof(AOTTableInitData, func_indexes) + + sizeof(uint32) * init_data->func_index_count; + mem_conspn->table_segs_size += size; + } + + mem_conspn->data_segs_size = sizeof(AOTMemInitData *) + * module->mem_init_data_count; + for (i = 0; i < module->mem_init_data_count; i++) { + mem_conspn->data_segs_size += sizeof(AOTMemInitData); + } + + mem_conspn->const_strs_size = + bh_hash_map_get_struct_size(module->const_str_set); + + const_string_size = 0; + if (module->const_str_set) { + bh_hash_map_traverse(module->const_str_set, + const_string_node_size_cb); + } + mem_conspn->const_strs_size += const_string_size; + + /* code size + literal size + object data section size */ + mem_conspn->aot_code_size = module->code_size + module->literal_size + + sizeof(AOTObjectDataSection) * module->data_section_count; + for (i = 0; i < module->data_section_count; i++) { + AOTObjectDataSection *obj_data = module->data_sections + i; + mem_conspn->aot_code_size += sizeof(uint8) * obj_data->size; + } + + mem_conspn->total_size += mem_conspn->module_struct_size; + mem_conspn->total_size += mem_conspn->types_size; + mem_conspn->total_size += mem_conspn->imports_size; + mem_conspn->total_size += mem_conspn->functions_size; + mem_conspn->total_size += mem_conspn->tables_size; + mem_conspn->total_size += mem_conspn->memories_size; + mem_conspn->total_size += mem_conspn->globals_size; + mem_conspn->total_size += mem_conspn->exports_size; + mem_conspn->total_size += mem_conspn->table_segs_size; + mem_conspn->total_size += mem_conspn->data_segs_size; + mem_conspn->total_size += mem_conspn->const_strs_size; + mem_conspn->total_size += mem_conspn->aot_code_size; +} + +void +aot_get_module_inst_mem_consumption(const AOTModuleInstance *module_inst, + WASMModuleInstMemConsumption *mem_conspn) +{ + uint32 i; + + memset(mem_conspn, 0, sizeof(*mem_conspn)); + + mem_conspn->module_inst_struct_size = sizeof(AOTModuleInstance); + + mem_conspn->memories_size = + sizeof(AOTPointer) * module_inst->memory_count + + sizeof(AOTMemoryInstance) * module_inst->memory_count; + for (i = 0; i < module_inst->memory_count; i++) { + AOTMemoryInstance *mem_inst = + ((AOTMemoryInstance **)module_inst->memories.ptr)[i]; + mem_conspn->memories_size += + mem_inst->num_bytes_per_page * mem_inst->cur_page_count; + mem_conspn->app_heap_size = + mem_inst->heap_data_end.ptr - mem_inst->heap_data.ptr; + } + + mem_conspn->tables_size = sizeof(uint32) * module_inst->table_size; + + /* func_ptrs and func_type_indexes */ + mem_conspn->functions_size = (sizeof(void *) + sizeof(uint32)) * + (((AOTModule *)module_inst->aot_module.ptr)->import_func_count + + ((AOTModule *)module_inst->aot_module.ptr)->func_count); + + mem_conspn->globals_size = module_inst->global_data_size; + + mem_conspn->exports_size = + sizeof(AOTFunctionInstance) * (uint64)module_inst->export_func_count; + + mem_conspn->total_size += mem_conspn->module_inst_struct_size; + mem_conspn->total_size += mem_conspn->memories_size; + mem_conspn->total_size += mem_conspn->functions_size; + mem_conspn->total_size += mem_conspn->tables_size; + mem_conspn->total_size += mem_conspn->globals_size; + mem_conspn->total_size += mem_conspn->exports_size; +} +#endif /* end of (WASM_ENABLE_MEMORY_PROFILING != 0) + || (WASM_ENABLE_MEMORY_TRACING != 0) */ diff --git a/core/iwasm/aot/aot_runtime.h b/core/iwasm/aot/aot_runtime.h index 1b49d13ed..ee1d36ba0 100644 --- a/core/iwasm/aot/aot_runtime.h +++ b/core/iwasm/aot/aot_runtime.h @@ -553,6 +553,14 @@ void aot_signal_destroy(); #endif +void +aot_get_module_mem_consumption(const AOTModule *module, + WASMModuleMemConsumption *mem_conspn); + +void +aot_get_module_inst_mem_consumption(const AOTModuleInstance *module_inst, + WASMModuleInstMemConsumption *mem_conspn); + #ifdef __cplusplus } /* end of extern "C" */ #endif diff --git a/core/iwasm/common/wasm_exec_env.c b/core/iwasm/common/wasm_exec_env.c index 631d449b7..478239dd0 100644 --- a/core/iwasm/common/wasm_exec_env.c +++ b/core/iwasm/common/wasm_exec_env.c @@ -43,6 +43,10 @@ wasm_exec_env_create_internal(struct WASMModuleInstanceCommon *module_inst, exec_env->wasm_stack.s.top_boundary = exec_env->wasm_stack.s.bottom + stack_size; exec_env->wasm_stack.s.top = exec_env->wasm_stack.s.bottom; + +#if WASM_ENABLE_MEMORY_TRACING != 0 + wasm_runtime_dump_exec_env_mem_consumption(exec_env); +#endif return exec_env; #if WASM_ENABLE_THREAD_MGR != 0 diff --git a/core/iwasm/common/wasm_exec_env.h b/core/iwasm/common/wasm_exec_env.h index 625676353..454ee8670 100644 --- a/core/iwasm/common/wasm_exec_env.h +++ b/core/iwasm/common/wasm_exec_env.h @@ -92,7 +92,7 @@ typedef struct WASMExecEnv { /* The native thread handle of current thread */ korp_tid handle; -#if WASM_ENABLE_INTERP != 0 +#if WASM_ENABLE_INTERP != 0 && WASM_ENABLE_FAST_INTERP == 0 BlockAddr block_addr_cache[BLOCK_ADDR_CACHE_SIZE][BLOCK_ADDR_CONFLICT_SIZE]; #endif @@ -100,6 +100,10 @@ typedef struct WASMExecEnv { WASMJmpBuf *jmpbuf_stack_top; #endif +#if WASM_ENABLE_MEMORY_PROFILING != 0 + uint32 max_wasm_stack_used; +#endif + /* The WASM stack size */ uint32 wasm_stack_size; @@ -154,13 +158,19 @@ wasm_exec_env_alloc_wasm_frame(WASMExecEnv *exec_env, unsigned size) multiplying by 2 is enough. */ if (addr + size * 2 > exec_env->wasm_stack.s.top_boundary) { /* WASM stack overflow. */ - /* When throwing SOE, the preserved space must be enough. */ - /* bh_assert(!exec_env->throwing_soe);*/ return NULL; } exec_env->wasm_stack.s.top += size; +#if WASM_ENABLE_MEMORY_PROFILING != 0 + { + uint32 wasm_stack_used = exec_env->wasm_stack.s.top + - exec_env->wasm_stack.s.bottom; + if (wasm_stack_used > exec_env->max_wasm_stack_used) + exec_env->max_wasm_stack_used = wasm_stack_used; + } +#endif return addr; } diff --git a/core/iwasm/common/wasm_memory.c b/core/iwasm/common/wasm_memory.c index 9032bc0c0..151de2828 100644 --- a/core/iwasm/common/wasm_memory.c +++ b/core/iwasm/common/wasm_memory.c @@ -32,8 +32,6 @@ static memory_profile_t *memory_profiles_list = NULL; static korp_mutex profile_lock; #endif /* end of BH_ENABLE_MEMORY_PROFILING */ -#ifndef MALLOC_MEMORY_FROM_SYSTEM - typedef enum Memory_Mode { MEMORY_MODE_UNKNOWN = 0, MEMORY_MODE_POOL, @@ -125,28 +123,32 @@ wasm_runtime_memory_pool_size() return 1 * BH_GB; } -void * -wasm_runtime_malloc(unsigned int size) +static inline void * +wasm_runtime_malloc_internal(unsigned int size) { if (memory_mode == MEMORY_MODE_UNKNOWN) { LOG_WARNING("wasm_runtime_malloc failed: memory hasn't been initialize.\n"); return NULL; - } else if (memory_mode == MEMORY_MODE_POOL) { + } + else if (memory_mode == MEMORY_MODE_POOL) { return mem_allocator_malloc(pool_allocator, size); - } else { + } + else { return malloc_func(size); } } -void * -wasm_runtime_realloc(void *ptr, unsigned int size) +static inline void * +wasm_runtime_realloc_internal(void *ptr, unsigned int size) { if (memory_mode == MEMORY_MODE_UNKNOWN) { LOG_WARNING("wasm_runtime_realloc failed: memory hasn't been initialize.\n"); return NULL; - } else if (memory_mode == MEMORY_MODE_POOL) { + } + else if (memory_mode == MEMORY_MODE_POOL) { return mem_allocator_realloc(pool_allocator, ptr, size); - } else { + } + else { if (realloc_func) return realloc_func(ptr, size); else @@ -154,20 +156,97 @@ wasm_runtime_realloc(void *ptr, unsigned int size) } } -void -wasm_runtime_free(void *ptr) +static inline void +wasm_runtime_free_internal(void *ptr) { if (memory_mode == MEMORY_MODE_UNKNOWN) { LOG_WARNING("wasm_runtime_free failed: memory hasn't been initialize.\n"); - } else if (memory_mode == MEMORY_MODE_POOL) { + } + else if (memory_mode == MEMORY_MODE_POOL) { mem_allocator_free(pool_allocator, ptr); - } else { + } + else { free_func(ptr); } } -#if BH_ENABLE_MEMORY_PROFILING != 0 +void * +wasm_runtime_malloc(unsigned int size) +{ + return wasm_runtime_malloc_internal(size); +} +void * +wasm_runtime_realloc(void *ptr, unsigned int size) +{ + return wasm_runtime_realloc_internal(ptr, size); +} + +void +wasm_runtime_free(void *ptr) +{ + wasm_runtime_free_internal(ptr); +} + +#if 0 +static uint64 total_malloc = 0; +static uint64 total_free = 0; + +void * +wasm_runtime_malloc(unsigned int size) +{ + void *ret = wasm_runtime_malloc_internal(size + 8); + + if (ret) { + total_malloc += size; + *(uint32 *)ret = size; + return (uint8 *)ret + 8; + } + else + return NULL; +} + +void * +wasm_runtime_realloc(void *ptr, unsigned int size) +{ + if (!ptr) + return wasm_runtime_malloc(size); + else { + uint8 *ptr_old = (uint8 *)ptr - 8; + uint32 size_old = *(uint32 *)ptr_old; + + ptr = wasm_runtime_realloc_internal(ptr_old, size + 8); + if (ptr) { + total_free += size_old; + total_malloc += size; + *(uint32 *)ptr = size; + return (uint8 *)ptr + 8; + } + return NULL; + } +} + +void +wasm_runtime_free(void *ptr) +{ + if (ptr) { + uint8 *ptr_old = (uint8 *)ptr - 8; + uint32 size_old = *(uint32 *)ptr_old; + + total_free += size_old; + wasm_runtime_free_internal(ptr_old); + } +} + +void dump_memory_usage() +{ + os_printf("Memory usage:\n"); + os_printf(" total malloc: %"PRIu64"\n", total_malloc); + os_printf(" total free: %"PRIu64"\n", total_free); +} +#endif + +#if BH_ENABLE_MEMORY_PROFILING != 0 void memory_profile_print(const char *file, int line, const char *func, int alloc) @@ -300,73 +379,5 @@ void memory_usage_summarize() os_mutex_unlock(&profile_lock); } - #endif /* end of BH_ENABLE_MEMORY_PROFILING */ -#else /* else of MALLOC_MEMORY_FROM_SYSTEM */ - - -void * -wasm_runtime_malloc(unsigned int size) -{ - return malloc(size); -} - -void * -wasm_runtime_realloc(void *ptr, unsigned int size) -{ - return realloc(ptr, size); -} - -void -wasm_runtime_free(void *ptr) -{ - if (ptr) - free(ptr); -} - -#if BH_ENABLE_MEMORY_PROFILING != 0 -void * -wasm_runtime_malloc_profile(const char *file, int line, - const char *func, unsigned int size) -{ - (void)file; - (void)line; - (void)func; - - (void)memory_profiles_list; - (void)profile_lock; - (void)memory_in_use; - - return malloc(size); -} - -void * -wasm_runtime_realloc_profile(const char *file, int line, - const char *func, void *ptr, unsigned int size) -{ - (void)file; - (void)line; - (void)func; - - (void)memory_profiles_list; - (void)profile_lock; - (void)memory_in_use; - - return realloc(ptr, size); -} - -void -wasm_runtime_free_profile(const char *file, int line, - const char *func, void *ptr) -{ - (void)file; - (void)line; - (void)func; - - if (ptr) - free(ptr); -} -#endif /* end of BH_ENABLE_MEMORY_PROFILING */ -#endif /* end of MALLOC_MEMORY_FROM_SYSTEM*/ - diff --git a/core/iwasm/common/wasm_native.c b/core/iwasm/common/wasm_native.c index c90007665..ff6946457 100644 --- a/core/iwasm/common/wasm_native.c +++ b/core/iwasm/common/wasm_native.c @@ -275,6 +275,9 @@ register_natives(const char *module_name, if (!(node = wasm_runtime_malloc(sizeof(NativeSymbolsNode)))) return false; +#if WASM_ENABLE_MEMORY_TRACING != 0 + os_printf("Register native, size: %u\n", sizeof(NativeSymbolsNode)); +#endif node->module_name = module_name; node->native_symbols = native_symbols; diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index ee82a6b4a..2d3fbeb55 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -791,6 +791,168 @@ wasm_runtime_destroy_exec_env(WASMExecEnv *exec_env) wasm_exec_env_destroy(exec_env); } +void +wasm_runtime_dump_module_mem_consumption(const WASMModuleCommon *module) +{ + WASMModuleMemConsumption mem_conspn = { 0 }; + +#if WASM_ENABLE_INTERP != 0 + if (module->module_type == Wasm_Module_Bytecode) { + wasm_get_module_mem_consumption((WASMModule*)module, &mem_conspn); + } +#endif +#if WASM_ENABLE_AOT != 0 + if (module->module_type == Wasm_Module_AoT) { + aot_get_module_mem_consumption((AOTModule*)module, &mem_conspn); + } +#endif + + os_printf("WASM module memory consumption, total size: %u\n", + mem_conspn.total_size); + os_printf(" module struct size: %u\n", mem_conspn.module_struct_size); + os_printf(" types size: %u\n", mem_conspn.types_size); + os_printf(" imports size: %u\n", mem_conspn.imports_size); + os_printf(" funcs size: %u\n", mem_conspn.functions_size); + os_printf(" tables size: %u\n", mem_conspn.tables_size); + os_printf(" memories size: %u\n", mem_conspn.memories_size); + os_printf(" globals size: %u\n", mem_conspn.globals_size); + os_printf(" exports size: %u\n", mem_conspn.exports_size); + os_printf(" table segs size: %u\n", mem_conspn.table_segs_size); + os_printf(" data segs size: %u\n", mem_conspn.data_segs_size); + os_printf(" const strings size: %u\n", mem_conspn.const_strs_size); +#if WASM_ENABLE_AOT != 0 + os_printf(" aot code size: %u\n", mem_conspn.aot_code_size); +#endif +} + +void +wasm_runtime_dump_module_inst_mem_consumption(const WASMModuleInstanceCommon + *module_inst) +{ + WASMModuleInstMemConsumption mem_conspn = { 0 }; + +#if WASM_ENABLE_INTERP != 0 + if (module_inst->module_type == Wasm_Module_Bytecode) { + wasm_get_module_inst_mem_consumption((WASMModuleInstance*)module_inst, + &mem_conspn); + } +#endif +#if WASM_ENABLE_AOT != 0 + if (module_inst->module_type == Wasm_Module_AoT) { + aot_get_module_inst_mem_consumption((AOTModuleInstance*)module_inst, + &mem_conspn); + } +#endif + + os_printf("WASM module inst memory consumption, total size: %u\n", + mem_conspn.total_size); + os_printf(" module inst struct size: %u\n", + mem_conspn.module_inst_struct_size); + os_printf(" memories size: %u\n", mem_conspn.memories_size); + os_printf(" app heap size: %u\n", mem_conspn.app_heap_size); + os_printf(" tables size: %u\n", mem_conspn.tables_size); + os_printf(" functions size: %u\n", mem_conspn.functions_size); + os_printf(" globals size: %u\n", mem_conspn.globals_size); + os_printf(" exports size: %u\n", mem_conspn.exports_size); +} + +void +wasm_runtime_dump_exec_env_mem_consumption(const WASMExecEnv *exec_env) +{ + uint32 total_size = offsetof(WASMExecEnv, wasm_stack.s.bottom) + + exec_env->wasm_stack_size; + + os_printf("Exec env memory consumption, total size: %u\n", total_size); + os_printf(" exec env struct size: %u\n", + offsetof(WASMExecEnv, wasm_stack.s.bottom)); +#if WASM_ENABLE_INTERP != 0 && WASM_ENABLE_FAST_INTERP == 0 + os_printf(" block addr cache size: %u\n", + sizeof(exec_env->block_addr_cache)); +#endif + os_printf(" stack size: %u\n", exec_env->wasm_stack_size); +} + +#if WASM_ENABLE_MEMORY_PROFILING != 0 +uint32 +gc_get_heap_highmark_size(void *heap); + +void +wasm_runtime_dump_mem_consumption(WASMExecEnv *exec_env) +{ + WASMModuleInstMemConsumption module_inst_mem_consps; + WASMModuleMemConsumption module_mem_consps; + WASMModuleInstanceCommon *module_inst_common; + WASMModuleCommon *module_common = NULL; + void *heap_handle = NULL; + uint32 total_size = 0, app_heap_peak_size = 0; + uint32 max_aux_stack_used = -1; + + module_inst_common = exec_env->module_inst; +#if WASM_ENABLE_INTERP != 0 + if (module_inst_common->module_type == Wasm_Module_Bytecode) { + WASMModuleInstance *wasm_module_inst = + (WASMModuleInstance*)module_inst_common; + WASMModule *wasm_module = wasm_module_inst->module; + module_common = (WASMModuleCommon*)wasm_module; + if (wasm_module_inst->memories) { + heap_handle = wasm_module_inst->memories[0]->heap_handle; + } + wasm_get_module_inst_mem_consumption + (wasm_module_inst, &module_inst_mem_consps); + wasm_get_module_mem_consumption + (wasm_module, &module_mem_consps); + if (wasm_module_inst->module->aux_stack_top_global_index != (uint32)-1) + max_aux_stack_used = wasm_module_inst->max_aux_stack_used; + } +#endif +#if WASM_ENABLE_AOT != 0 + if (module_inst_common->module_type == Wasm_Module_AoT) { + AOTModuleInstance *aot_module_inst = + (AOTModuleInstance*)module_inst_common; + AOTModule *aot_module = + (AOTModule*)aot_module_inst->aot_module.ptr; + module_common = (WASMModuleCommon*)aot_module; + if (aot_module_inst->memories.ptr) { + AOTMemoryInstance **memories = + (AOTMemoryInstance **)aot_module_inst->memories.ptr; + heap_handle = memories[0]->heap_handle.ptr; + } + aot_get_module_inst_mem_consumption + (aot_module_inst, &module_inst_mem_consps); + aot_get_module_mem_consumption + (aot_module, &module_mem_consps); + } +#endif + + bh_assert(module_common != NULL); + + if (heap_handle) { + app_heap_peak_size = gc_get_heap_highmark_size(heap_handle); + } + + total_size = offsetof(WASMExecEnv, wasm_stack.s.bottom) + + exec_env->wasm_stack_size + + module_mem_consps.total_size + + module_inst_mem_consps.total_size; + + os_printf("\nMemory consumption summary (bytes):\n"); + wasm_runtime_dump_module_mem_consumption(module_common); + wasm_runtime_dump_module_inst_mem_consumption(module_inst_common); + wasm_runtime_dump_exec_env_mem_consumption(exec_env); + os_printf("\nTotal memory consumption of module, module inst and " + "exec env: %u\n", total_size); + os_printf("Total interpreter stack used: %u\n", + exec_env->max_wasm_stack_used); + + if (max_aux_stack_used != (uint32)-1) + os_printf("Total auxiliary stack used: %u\n", max_aux_stack_used); + else + os_printf("Total aux stack used: no enough info to profile\n"); + + os_printf("Total app heap used: %u\n", app_heap_peak_size); +} +#endif + WASMModuleInstanceCommon * wasm_runtime_get_module_inst(WASMExecEnv *exec_env) { @@ -1879,10 +2041,11 @@ wasm_application_execute_main(WASMModuleInstanceCommon *module_inst, uint32 argc1 = 0, argv1[2] = { 0 }; uint32 total_argv_size = 0; uint64 total_size; - uint32 argv_buf_offset; + uint32 argv_buf_offset = 0; int32 i; char *argv_buf, *p, *p_end; uint32 *argv_offsets; + bool ret; #if WASM_ENABLE_LIBC_WASI != 0 if (wasm_runtime_is_wasi_mode(module_inst)) { @@ -1961,8 +2124,11 @@ wasm_application_execute_main(WASMModuleInstanceCommon *module_inst, argv1[1] = (uint32)wasm_runtime_addr_native_to_app(module_inst, argv_offsets); } - return wasm_runtime_create_exec_env_and_call_wasm(module_inst, func, - argc1, argv1); + ret = wasm_runtime_create_exec_env_and_call_wasm(module_inst, func, + argc1, argv1); + if (argv_buf_offset) + wasm_runtime_module_free(module_inst, argv_buf_offset); + return ret; } diff --git a/core/iwasm/common/wasm_runtime_common.h b/core/iwasm/common/wasm_runtime_common.h index 51ef6c777..8dd98dc41 100644 --- a/core/iwasm/common/wasm_runtime_common.h +++ b/core/iwasm/common/wasm_runtime_common.h @@ -43,6 +43,35 @@ typedef struct WASMModuleInstanceCommon { uint8 module_inst_data[1]; } WASMModuleInstanceCommon; +typedef struct WASMModuleMemConsumption { + uint32 total_size; + uint32 module_struct_size; + uint32 types_size; + uint32 imports_size; + uint32 functions_size; + uint32 tables_size; + uint32 memories_size; + uint32 globals_size; + uint32 exports_size; + uint32 table_segs_size; + uint32 data_segs_size; + uint32 const_strs_size; +#if WASM_ENABLE_AOT != 0 + uint32 aot_code_size; +#endif +} WASMModuleMemConsumption; + +typedef struct WASMModuleInstMemConsumption { + uint32 total_size; + uint32 module_inst_struct_size; + uint32 memories_size; + uint32 app_heap_size; + uint32 tables_size; + uint32 globals_size; + uint32 functions_size; + uint32 exports_size; +} WASMModuleInstMemConsumption; + #if WASM_ENABLE_LIBC_WASI != 0 typedef struct WASIContext { /* Use offset but not native address, since these fields are @@ -432,6 +461,16 @@ wasm_runtime_invoke_native_raw(WASMExecEnv *exec_env, void *func_ptr, void *attachment, uint32 *argv, uint32 argc, uint32 *ret); +void +wasm_runtime_dump_module_mem_consumption(const WASMModuleCommon *module); + +void +wasm_runtime_dump_module_inst_mem_consumption(const WASMModuleInstanceCommon + *module_inst); + +void +wasm_runtime_dump_exec_env_mem_consumption(const WASMExecEnv *exec_env); + #ifdef __cplusplus } #endif diff --git a/core/iwasm/include/wasm_export.h b/core/iwasm/include/wasm_export.h index b8f535b20..44c32b6f8 100644 --- a/core/iwasm/include/wasm_export.h +++ b/core/iwasm/include/wasm_export.h @@ -775,6 +775,18 @@ wasm_runtime_set_user_data(wasm_exec_env_t exec_env, WASM_RUNTIME_API_EXTERN void * wasm_runtime_get_user_data(wasm_exec_env_t exec_env); +/** + * Dump runtime memory consumption, including: + * Exec env memory consumption + * WASM module memory consumption + * WASM module instance memory consumption + * stack and app heap used info + * + * @param exec_env the execution environment + */ +WASM_RUNTIME_API_EXTERN void +wasm_runtime_dump_mem_consumption(wasm_exec_env_t exec_env); + #if WASM_ENABLE_THREAD_MGR != 0 /* wasm thread callback function type */ typedef void* (*wasm_thread_callback_t)(wasm_exec_env_t, void *); diff --git a/core/iwasm/interpreter/wasm.h b/core/iwasm/interpreter/wasm.h index 3696c2e81..a24720c33 100644 --- a/core/iwasm/interpreter/wasm.h +++ b/core/iwasm/interpreter/wasm.h @@ -361,7 +361,7 @@ typedef struct WASMModule { #endif #if WASM_ENABLE_MULTI_MODULE != 0 - // TODO: mutex ? mutli-threads ? + /* TODO: add mutex for mutli-thread? */ bh_list import_module_list_head; bh_list *import_module_list; #endif diff --git a/core/iwasm/interpreter/wasm_interp_classic.c b/core/iwasm/interpreter/wasm_interp_classic.c index ec9a10237..a0d9d2fc7 100644 --- a/core/iwasm/interpreter/wasm_interp_classic.c +++ b/core/iwasm/interpreter/wasm_interp_classic.c @@ -1552,6 +1552,14 @@ label_pop_csp_n: if (*(uint32*)(frame_sp - 1) < exec_env->aux_stack_boundary) goto out_of_bounds; *(int32*)global_addr = POP_I32(); +#if WASM_ENABLE_MEMORY_PROFILING != 0 + if (module->module->aux_stack_top_global_index != (uint32)-1) { + uint32 aux_stack_used = + module->module->aux_stack_bottom - *(uint32*)global_addr; + if (aux_stack_used > module->max_aux_stack_used) + module->max_aux_stack_used = aux_stack_used; + } +#endif HANDLE_OP_END (); } diff --git a/core/iwasm/interpreter/wasm_interp_fast.c b/core/iwasm/interpreter/wasm_interp_fast.c index 2a19d8aea..48b989d1d 100644 --- a/core/iwasm/interpreter/wasm_interp_fast.c +++ b/core/iwasm/interpreter/wasm_interp_fast.c @@ -1510,6 +1510,14 @@ recover_br_info: if (frame_lp[addr1] < exec_env->aux_stack_boundary) goto out_of_bounds; *(int32*)global_addr = frame_lp[addr1]; +#if WASM_ENABLE_MEMORY_PROFILING != 0 + if (module->module->aux_stack_top_global_index != (uint32)-1) { + uint32 aux_stack_used = + module->module->aux_stack_bottom - *(uint32*)global_addr; + if (aux_stack_used > module->max_aux_stack_used) + module->max_aux_stack_used = aux_stack_used; + } +#endif HANDLE_OP_END (); } diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index 21e6b2f2e..ee2de95c5 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -2382,7 +2382,6 @@ fail: return false; } - static bool wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, BlockAddr *block_addr_cache, @@ -2509,28 +2508,6 @@ load_from_sections(WASMModule *module, WASMSection *sections, section = section->next; } -#if WASM_ENABLE_FAST_INTERP != 0 - handle_table = wasm_interp_get_handle_table(); -#endif - - total_size = sizeof(BlockAddr) * (uint64)BLOCK_ADDR_CACHE_SIZE - * BLOCK_ADDR_CONFLICT_SIZE; - if (!(block_addr_cache = loader_malloc - (total_size, error_buf, error_buf_size))) { - return false; - } - - for (i = 0; i < module->function_count; i++) { - WASMFunction *func = module->functions[i]; - memset(block_addr_cache, 0, (uint32)total_size); - if (!wasm_loader_prepare_bytecode(module, func, block_addr_cache, - error_buf, error_buf_size)) { - wasm_runtime_free(block_addr_cache); - return false; - } - } - wasm_runtime_free(block_addr_cache); - module->aux_data_end_global_index = (uint32)-1; module->aux_heap_base_global_index = (uint32)-1; module->aux_stack_top_global_index = (uint32)-1; @@ -2658,6 +2635,28 @@ load_from_sections(WASMModule *module, WASMSection *sections, } } +#if WASM_ENABLE_FAST_INTERP != 0 + handle_table = wasm_interp_get_handle_table(); +#endif + + total_size = sizeof(BlockAddr) * (uint64)BLOCK_ADDR_CACHE_SIZE + * BLOCK_ADDR_CONFLICT_SIZE; + if (!(block_addr_cache = loader_malloc + (total_size, error_buf, error_buf_size))) { + return false; + } + + for (i = 0; i < module->function_count; i++) { + WASMFunction *func = module->functions[i]; + memset(block_addr_cache, 0, (uint32)total_size); + if (!wasm_loader_prepare_bytecode(module, func, block_addr_cache, + error_buf, error_buf_size)) { + wasm_runtime_free(block_addr_cache); + return false; + } + } + wasm_runtime_free(block_addr_cache); + if (!module->possible_memory_grow) { WASMMemoryImport *memory_import; WASMMemory *memory; @@ -2711,18 +2710,12 @@ load_from_sections(WASMModule *module, WASMSection *sections, #endif } +#if WASM_ENABLE_MEMORY_TRACING != 0 + wasm_runtime_dump_module_mem_consumption((WASMModuleCommon*)module); +#endif return true; } -#if BH_ENABLE_MEMORY_PROFILING != 0 -static void wasm_loader_free(void *ptr) -{ - wasm_runtime_free(ptr); -} -#else -#define wasm_loader_free wasm_free -#endif - static WASMModule* create_module(char *error_buf, uint32 error_buf_size) { diff --git a/core/iwasm/interpreter/wasm_mini_loader.c b/core/iwasm/interpreter/wasm_mini_loader.c index d1541a68d..2a39a83a4 100644 --- a/core/iwasm/interpreter/wasm_mini_loader.c +++ b/core/iwasm/interpreter/wasm_mini_loader.c @@ -1425,7 +1425,6 @@ load_user_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, return true; } - static bool wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, BlockAddr *block_addr_cache, @@ -1541,27 +1540,6 @@ load_from_sections(WASMModule *module, WASMSection *sections, section = section->next; } -#if WASM_ENABLE_FAST_INTERP != 0 - handle_table = wasm_interp_get_handle_table(); -#endif - - total_size = sizeof(BlockAddr) * (uint64)BLOCK_ADDR_CACHE_SIZE * BLOCK_ADDR_CONFLICT_SIZE; - if (!(block_addr_cache = loader_malloc - (total_size, error_buf, error_buf_size))) { - return false; - } - - for (i = 0; i < module->function_count; i++) { - WASMFunction *func = module->functions[i]; - memset(block_addr_cache, 0, (uint32)total_size); - if (!wasm_loader_prepare_bytecode(module, func, block_addr_cache, - error_buf, error_buf_size)) { - wasm_runtime_free(block_addr_cache); - return false; - } - } - wasm_runtime_free(block_addr_cache); - module->aux_data_end_global_index = (uint32)-1; module->aux_heap_base_global_index = (uint32)-1; module->aux_stack_top_global_index = (uint32)-1; @@ -1689,6 +1667,27 @@ load_from_sections(WASMModule *module, WASMSection *sections, } } +#if WASM_ENABLE_FAST_INTERP != 0 + handle_table = wasm_interp_get_handle_table(); +#endif + + total_size = sizeof(BlockAddr) * (uint64)BLOCK_ADDR_CACHE_SIZE * BLOCK_ADDR_CONFLICT_SIZE; + if (!(block_addr_cache = loader_malloc + (total_size, error_buf, error_buf_size))) { + return false; + } + + for (i = 0; i < module->function_count; i++) { + WASMFunction *func = module->functions[i]; + memset(block_addr_cache, 0, (uint32)total_size); + if (!wasm_loader_prepare_bytecode(module, func, block_addr_cache, + error_buf, error_buf_size)) { + wasm_runtime_free(block_addr_cache); + return false; + } + } + wasm_runtime_free(block_addr_cache); + if (!module->possible_memory_grow) { WASMMemoryImport *memory_import; WASMMemory *memory; @@ -1742,18 +1741,12 @@ load_from_sections(WASMModule *module, WASMSection *sections, #endif } +#if WASM_ENABLE_MEMORY_TRACING != 0 + wasm_runtime_dump_module_mem_consumption(module); +#endif return true; } -#if BH_ENABLE_MEMORY_PROFILING != 0 -static void wasm_loader_free(void *ptr) -{ - wasm_runtime_free(ptr); -} -#else -#define wasm_loader_free wasm_free -#endif - static WASMModule* create_module(char *error_buf, uint32 error_buf_size) { diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index f139ae3e1..5a434766a 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -257,7 +257,8 @@ memory_instantiate(WASMModuleInstance *module_inst, memory->heap_data_end = memory->heap_data + heap_size; memory->memory_data_end = memory->memory_data + (uint32)memory_data_size; - bh_assert(memory->memory_data_end - (uint8*)memory == (uint32)total_size); + bh_assert((uint32)(memory->memory_data_end - (uint8*)memory) + == (uint32)total_size); /* Initialize heap */ if (heap_size > 0 @@ -1112,10 +1113,10 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, /* Instantiate global firstly to get the mutable data size */ global_count = module->import_global_count + module->global_count; - if (global_count && !(globals = globals_instantiate( - module, - module_inst, - &global_data_size, error_buf, error_buf_size))) { + if (global_count + && !(globals = globals_instantiate(module, module_inst, + &global_data_size, + error_buf, error_buf_size))) { wasm_deinstantiate(module_inst, false); return NULL; } @@ -1419,6 +1420,10 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, #endif #endif +#if WASM_ENABLE_MEMORY_TRACING != 0 + wasm_runtime_dump_module_inst_mem_consumption + ((WASMModuleInstanceCommon *)module_inst); +#endif (void)global_data_end; return module_inst; } @@ -1928,3 +1933,138 @@ wasm_get_aux_stack(WASMExecEnv *exec_env, return false; } #endif + +#if (WASM_ENABLE_MEMORY_PROFILING != 0) || (WASM_ENABLE_MEMORY_TRACING != 0) +void +wasm_get_module_mem_consumption(const WASMModule *module, + WASMModuleMemConsumption *mem_conspn) +{ + uint32 i, size; + + memset(mem_conspn, 0, sizeof(*mem_conspn)); + + mem_conspn->module_struct_size = sizeof(WASMModule); + + mem_conspn->types_size = sizeof(WASMType *) * module->type_count; + for (i = 0; i < module->type_count; i++) { + WASMType *type = module->types[i]; + size = offsetof(WASMType, types) + + sizeof(uint8) * (type->param_count + type->result_count); + mem_conspn->types_size += size; + } + + mem_conspn->imports_size = sizeof(WASMImport) * module->import_count; + + mem_conspn->functions_size = sizeof(WASMFunction *) + * module->function_count; + for (i = 0; i < module->function_count; i++) { + WASMFunction *func = module->functions[i]; + WASMType *type = func->func_type; + size = sizeof(WASMFunction) + func->local_count + + sizeof(uint16) * (type->param_count + func->local_count); +#if WASM_ENABLE_FAST_INTERP != 0 + size += func->code_compiled_size + + sizeof(uint32) * func->const_cell_num; +#endif + mem_conspn->functions_size += size; + } + + mem_conspn->tables_size = sizeof(WASMTable) * module->table_count; + mem_conspn->memories_size = sizeof(WASMMemory) * module->memory_count; + mem_conspn->globals_size = sizeof(WASMGlobal) * module->global_count; + mem_conspn->exports_size = sizeof(WASMExport) * module->export_count; + + mem_conspn->table_segs_size = sizeof(WASMTableSeg) + * module->table_seg_count; + for (i = 0; i < module->table_seg_count; i++) { + WASMTableSeg *table_seg = &module->table_segments[i]; + mem_conspn->tables_size += sizeof(uint32) + * table_seg->function_count; + } + + mem_conspn->data_segs_size = sizeof(WASMDataSeg*) + * module->data_seg_count; + for (i = 0; i < module->data_seg_count; i++) { + mem_conspn->data_segs_size += sizeof(WASMDataSeg); + } + + if (module->const_str_list) { + StringNode *node = module->const_str_list, *node_next; + while (node) { + node_next = node->next; + mem_conspn->const_strs_size += sizeof(StringNode) + + strlen(node->str) + 1; + node = node_next; + } + } + + mem_conspn->total_size += mem_conspn->module_struct_size; + mem_conspn->total_size += mem_conspn->types_size; + mem_conspn->total_size += mem_conspn->imports_size; + mem_conspn->total_size += mem_conspn->functions_size; + mem_conspn->total_size += mem_conspn->tables_size; + mem_conspn->total_size += mem_conspn->memories_size; + mem_conspn->total_size += mem_conspn->globals_size; + mem_conspn->total_size += mem_conspn->exports_size; + mem_conspn->total_size += mem_conspn->table_segs_size; + mem_conspn->total_size += mem_conspn->data_segs_size; + mem_conspn->total_size += mem_conspn->const_strs_size; +#if WASM_ENABLE_AOT != 0 + mem_conspn->total_size += mem_conspn->aot_code_size; +#endif +} + +void +wasm_get_module_inst_mem_consumption(const WASMModuleInstance *module_inst, + WASMModuleInstMemConsumption *mem_conspn) +{ + uint32 i, size; + + memset(mem_conspn, 0, sizeof(*mem_conspn)); + + mem_conspn->module_inst_struct_size = sizeof(WASMModuleInstance); + + mem_conspn->memories_size = sizeof(WASMMemoryInstance *) + * module_inst->memory_count; + for (i = 0; i < module_inst->memory_count; i++) { + WASMMemoryInstance *memory = module_inst->memories[i]; + size = offsetof(WASMMemoryInstance, memory_data) + + memory->num_bytes_per_page * memory->cur_page_count; + mem_conspn->memories_size += size; + mem_conspn->app_heap_size += memory->heap_data_end + - memory->heap_data; + } + + mem_conspn->tables_size = sizeof(WASMTableInstance *) + * module_inst->table_count; + for (i = 0; i < module_inst->table_count; i++) { + WASMTableInstance *table = module_inst->tables[i]; + size = offsetof(WASMTableInstance, base_addr) + + sizeof(uint32) * table->cur_size; + mem_conspn->tables_size += size; + } + + mem_conspn->functions_size = sizeof(WASMFunctionInstance) + * module_inst->function_count; + + mem_conspn->globals_size = sizeof(WASMGlobalInstance) + * module_inst->global_count; + if (module_inst->global_count > 0) { + WASMGlobalInstance *global = + &module_inst->globals[module_inst->global_count - 1]; + mem_conspn->globals_size += global->data_offset + + wasm_value_type_size(global->type); + } + + mem_conspn->exports_size = sizeof(WASMExportFuncInstance) + * module_inst->export_func_count; + + mem_conspn->total_size += mem_conspn->module_inst_struct_size; + mem_conspn->total_size += mem_conspn->memories_size; + mem_conspn->total_size += mem_conspn->functions_size; + mem_conspn->total_size += mem_conspn->tables_size; + mem_conspn->total_size += mem_conspn->globals_size; + mem_conspn->total_size += mem_conspn->exports_size; +} +#endif /* end of (WASM_ENABLE_MEMORY_PROFILING != 0) + || (WASM_ENABLE_MEMORY_TRACING != 0) */ diff --git a/core/iwasm/interpreter/wasm_runtime.h b/core/iwasm/interpreter/wasm_runtime.h index 1682c3903..c151ada03 100644 --- a/core/iwasm/interpreter/wasm_runtime.h +++ b/core/iwasm/interpreter/wasm_runtime.h @@ -204,14 +204,15 @@ typedef struct WASMModuleInstance { * wasm_set_custom_data/wasm_get_custom_data */ void *custom_data; - /* Main exec env */ - WASMExecEnv *main_exec_env; - #if WASM_ENABLE_MULTI_MODULE != 0 - // TODO: mutex ? mutli-threads ? + /* TODO: add mutex for mutli-threads? */ bh_list sub_module_inst_list_head; bh_list *sub_module_inst_list; #endif + +#if WASM_ENABLE_MEMORY_PROFILING != 0 + uint32 max_aux_stack_used; +#endif } WASMModuleInstance; struct WASMInterpFrame; @@ -374,6 +375,13 @@ wasm_get_aux_stack(WASMExecEnv *exec_env, uint32 *start_offset, uint32 *size); #endif +void +wasm_get_module_mem_consumption(const WASMModule *module, + WASMModuleMemConsumption *mem_conspn); + +void +wasm_get_module_inst_mem_consumption(const WASMModuleInstance *module, + WASMModuleInstMemConsumption *mem_conspn); #ifdef __cplusplus } #endif diff --git a/core/shared/mem-alloc/ems/ems_alloc.c b/core/shared/mem-alloc/ems/ems_alloc.c index d67775644..e8d478d28 100644 --- a/core/shared/mem-alloc/ems/ems_alloc.c +++ b/core/shared/mem-alloc/ems/ems_alloc.c @@ -385,10 +385,6 @@ gc_alloc_vo_internal(void *vheap, gc_size_t size, /* clear buffer appended by GC_ALIGN_8() */ memset((uint8*)ret + size, 0, tot_size - tot_size_unaligned); -#if BH_ENABLE_MEMORY_PROFILING != 0 - os_printf("HEAP.ALLOC: heap: %p, size: %u\n", heap, size); -#endif - finish: os_mutex_unlock(&heap->lock); return ret; @@ -469,10 +465,6 @@ gc_realloc_vo_internal(void *vheap, void *ptr, gc_size_t size, ret = hmu_to_obj(hmu); -#if BH_ENABLE_MEMORY_PROFILING != 0 - os_printf("HEAP.ALLOC: heap: %p, size: %u\n", heap, size); -#endif - finish: os_mutex_unlock(&heap->lock); @@ -548,9 +540,6 @@ gc_free_vo_internal(void *vheap, gc_object_t obj, g_total_free += size; heap->total_free_size += size; -#if BH_ENABLE_MEMORY_PROFILING != 0 - os_printf("HEAP.FREE, heap: %p, size: %u\n", heap, size); -#endif if (!hmu_get_pinuse(hmu)) { prev = (hmu_t*) ((char*) hmu - *((int*) hmu - 1)); @@ -600,6 +589,12 @@ gc_dump_heap_stats(gc_heap_t *heap) g_total_malloc, g_total_free, g_total_malloc - g_total_free); } +uint32 +gc_get_heap_highmark_size(gc_heap_t *heap) +{ + return heap->highmark_size; +} + void gci_dump(gc_heap_t *heap) { diff --git a/core/shared/mem-alloc/ems/ems_gc_internal.h b/core/shared/mem-alloc/ems/ems_gc_internal.h index 976a32a64..680d70e74 100644 --- a/core/shared/mem-alloc/ems/ems_gc_internal.h +++ b/core/shared/mem-alloc/ems/ems_gc_internal.h @@ -145,7 +145,9 @@ hmu_verify(hmu_t *hmu); * HMU free chunk management */ +#ifndef HMU_NORMAL_NODE_CNT #define HMU_NORMAL_NODE_CNT 32 +#endif #define HMU_FC_NORMAL_MAX_SIZE ((HMU_NORMAL_NODE_CNT - 1) << 3) #define HMU_IS_FC_NORMAL(size) ((size) < HMU_FC_NORMAL_MAX_SIZE) #if HMU_FC_NORMAL_MAX_SIZE >= GC_MAX_HEAP_SIZE diff --git a/core/shared/mem-alloc/ems/ems_kfc.c b/core/shared/mem-alloc/ems/ems_kfc.c index 8e389ca8e..fcf487bb9 100644 --- a/core/shared/mem-alloc/ems/ems_kfc.c +++ b/core/shared/mem-alloc/ems/ems_kfc.c @@ -9,16 +9,17 @@ gc_handle_t gc_init_with_pool(char *buf, gc_size_t buf_size) { char *buf_end = buf + buf_size; - char *buf_aligned = (char*) (((uintptr_t) buf + 7) & (uintptr_t)~7); + char *buf_aligned = (char*)(((uintptr_t) buf + 7) & (uintptr_t)~7); char *base_addr = buf_aligned + sizeof(gc_heap_t); - gc_heap_t *heap = (gc_heap_t*) buf_aligned; + gc_heap_t *heap = (gc_heap_t*)buf_aligned; gc_size_t heap_max_size; hmu_normal_node_t *p = NULL; hmu_tree_node_t *root = NULL, *q = NULL; int i = 0, ret; - if (buf_size < 1024) { - os_printf("[GC_ERROR]heap_init_size(%d) < 1024\n", buf_size); + if (buf_size < APP_HEAP_SIZE_MIN) { + os_printf("[GC_ERROR]heap init buf size (%u) < %u\n", + buf_size, APP_HEAP_SIZE_MIN); return NULL; } @@ -66,12 +67,14 @@ gc_init_with_pool(char *buf, gc_size_t buf_size) q->parent = root; q->size = heap->current_size; - bh_assert(root->size <= HMU_FC_NORMAL_MAX_SIZE - && HMU_FC_NORMAL_MAX_SIZE < q->size); + bh_assert(root->size <= HMU_FC_NORMAL_MAX_SIZE); -#if BH_ENABLE_MEMORY_PROFILING != 0 - os_printf("heap is successfully initialized with max_size=%u.\n", - heap_max_size); +#if WASM_ENABLE_MEMORY_TRACING != 0 + os_printf("Heap created, total size: %u\n", buf_size); + os_printf(" heap struct size: %u\n", sizeof(gc_heap_t)); + os_printf(" actual heap size: %u\n", heap_max_size); + os_printf(" padding bytes: %u\n", + buf_size - sizeof(gc_heap_t) - heap_max_size); #endif return heap; } diff --git a/core/shared/utils/bh_hashmap.c b/core/shared/utils/bh_hashmap.c index 5c7b9e8f3..59fca9cdf 100644 --- a/core/shared/utils/bh_hashmap.c +++ b/core/shared/utils/bh_hashmap.c @@ -47,7 +47,7 @@ bh_hash_map_create(uint32 size, bool use_lock, } total_size = offsetof(HashMap, elements) + - sizeof(HashMapElem) * (uint64)size + + sizeof(HashMapElem *) * (uint64)size + (use_lock ? sizeof(korp_mutex) : 0); if (total_size >= UINT32_MAX @@ -61,7 +61,7 @@ bh_hash_map_create(uint32 size, bool use_lock, if (use_lock) { map->lock = (korp_mutex*) ((uint8*)map + offsetof(HashMap, elements) - + sizeof(HashMapElem) * size); + + sizeof(HashMapElem *) * size); if (os_mutex_init(map->lock)) { LOG_ERROR("HashMap create failed: init map lock failed.\n"); BH_FREE(map); @@ -188,8 +188,8 @@ bh_hash_map_update(HashMap *map, void *key, void *value, os_mutex_unlock(map->lock); } return true; - } - elem = elem->next; + } + elem = elem->next; } if (map->lock) { @@ -286,3 +286,53 @@ bh_hash_map_destroy(HashMap *map) BH_FREE(map); return true; } + +uint32 +bh_hash_map_get_struct_size(HashMap *hashmap) +{ + uint32 size = offsetof(HashMap, elements) + + sizeof(HashMapElem *) * hashmap->size; + + if (hashmap->lock) { + size += sizeof(korp_mutex); + } + + return size; +} + +uint32 +bh_hash_map_get_elem_struct_size() +{ + return sizeof(HashMapElem); +} + +bool +bh_hash_map_traverse(HashMap *map, TraverseCallbackFunc callback) +{ + uint32 index; + HashMapElem *elem, *next; + + if (!map || !callback) { + LOG_ERROR("HashMap traverse failed: map or callback is NULL.\n"); + return false; + } + + if (map->lock) { + os_mutex_lock(map->lock); + } + + for (index = 0; index < map->size; index++) { + elem = map->elements[index]; + while (elem) { + next = elem->next; + callback(elem->key, elem->value); + elem = next; + } + } + + if (map->lock) { + os_mutex_unlock(map->lock); + } + + return true; +} \ No newline at end of file diff --git a/core/shared/utils/bh_hashmap.h b/core/shared/utils/bh_hashmap.h index 633c727e7..8cb02300c 100644 --- a/core/shared/utils/bh_hashmap.h +++ b/core/shared/utils/bh_hashmap.h @@ -32,6 +32,10 @@ typedef void (*KeyDestroyFunc)(void *key); when an hash element is removed. */ typedef void (*ValueDestroyFunc)(void *key); +/* traverse callback function: + auto called when traverse every hash element */ +typedef void (*TraverseCallbackFunc)(void *key, void *value); + /** * Create a hash map. * @@ -124,6 +128,37 @@ bh_hash_map_remove(HashMap *map, void *key, bool bh_hash_map_destroy(HashMap *map); +/** + * Get the structure size of HashMap + * + * @param map the hash map to calculate + * + * @return the memory space occupied by HashMap structure + */ +uint32 +bh_hash_map_get_struct_size(HashMap *hashmap); + +/** + * Get the structure size of HashMap Element + * + * @return the memory space occupied by HashMapElem structure + */ +uint32 +bh_hash_map_get_elem_struct_size(); + +/** + * Traverse the hash map and call the callback function + * + * @param map the hash map to traverse + * @callback the function to be called for every element + * + * @return true if success, false otherwise + * Note: if the hash map has lock, the map will be locked during traverse, + * keep the callback function as simple as possible. + */ +bool +bh_hash_map_traverse(HashMap *map, TraverseCallbackFunc callback); + #ifdef __cplusplus } #endif diff --git a/core/shared/utils/uncommon/bh_read_file.c b/core/shared/utils/uncommon/bh_read_file.c index e13b388d6..ce616743b 100644 --- a/core/shared/utils/uncommon/bh_read_file.c +++ b/core/shared/utils/uncommon/bh_read_file.c @@ -41,6 +41,9 @@ bh_read_file_to_buffer(const char *filename, uint32 *ret_size) _close(file); return NULL; } +#if WASM_ENABLE_MEMORY_TRACING != 0 + printf("Read file, total size: %u\n", file_size); +#endif read_size = _read(file, buffer, file_size); _close(file); @@ -88,6 +91,9 @@ bh_read_file_to_buffer(const char *filename, uint32 *ret_size) close(file); return NULL; } +#if WASM_ENABLE_MEMORY_TRACING != 0 + printf("Read file, total size: %u\n", file_size); +#endif read_size = (uint32)read(file, buffer, file_size); close(file); diff --git a/doc/build_wamr.md b/doc/build_wamr.md index f7fc9e21a..4e3627a7a 100644 --- a/doc/build_wamr.md +++ b/doc/build_wamr.md @@ -68,6 +68,11 @@ cmake -DWAMR_BUILD_PLATFORM=linux -DWAMR_BUILD_TARGET=ARM - **WAMR_DISABLE_HW_BOUND_CHECK**=1/0, default to enable if not set and supported by platform > Note: by default only platform linux/darwin/android/vxworks 64-bit will enable boundary check with hardware trap in AOT or JIT mode, and the wamrc tool will generate AOT code without boundary check instructions in all 64-bit targets except SGX to improve performance. +#### **Enable memory profiling (Experiment)** +- **WAMR_BUILD_MEMORY_PROFLING**=1/0, default to disable if not set +> Note: if it is enabled, developer can use API `void wasm_runtime_dump_mem_consumption(wasm_exec_env_t exec_env)` to dump the memory consumption info. +Currently we only profile the memory consumption of module, module_instance and exec_env, the memory consumed by other components such as `wasi-ctx`, `multi-module` and `thread-manager` are not included. + #### **Set maximum app thread stack size** - **WAMR_APP_THREAD_STACK_SIZE_MAX**=n, default to 8 MB (8388608) if not set > Note: the AOT boundary check with hardware trap mechanism might consume large stack since the OS may lazily grow the stack mapping as a guard page is hit, we may use this configuration to reduce the total stack usage, e.g. -DWAMR_APP_THREAD_STACK_SIZE_MAX=131072 (128 KB). diff --git a/test-tools/host-tool/CMakeLists.txt b/test-tools/host-tool/CMakeLists.txt index b5755aa06..660c9a13e 100644 --- a/test-tools/host-tool/CMakeLists.txt +++ b/test-tools/host-tool/CMakeLists.txt @@ -39,7 +39,7 @@ if (CMAKE_SIZEOF_VOID_P EQUAL 8) SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32") endif () -add_definitions(-Wall -Wno-pointer-sign -DMALLOC_MEMORY_FROM_SYSTEM) +add_definitions(-Wall -Wno-pointer-sign) include_directories( ${CMAKE_CURRENT_LIST_DIR}/src @@ -48,7 +48,6 @@ include_directories( file (GLOB_RECURSE HOST_TOOL_SRC src/*.c) - SET(SOURCES ${HOST_TOOL_SRC} ${PLATFORM_SHARED_SOURCE} @@ -57,6 +56,6 @@ SET(SOURCES ${CJSON_SOURCE} ${LIB_HOST_AGENT_SOURCE} ) - + add_executable(host_tool ${SOURCES}) target_link_libraries(host_tool pthread) From 2d06567cd1919ff8b0df6ee649e0a9366b5a304c Mon Sep 17 00:00:00 2001 From: Xiaokang Qin Date: Fri, 18 Sep 2020 18:06:13 +0800 Subject: [PATCH 073/207] Reimplement the utf8 string check (#389) Previous implementation doesn't take care of overlong encoding Signed-off-by: Xiaokang Qin --- core/iwasm/interpreter/wasm_loader.c | 84 ++++++++++++++++++++-------- 1 file changed, 60 insertions(+), 24 deletions(-) diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index ee2de95c5..2b8de26c3 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -250,36 +250,72 @@ loader_malloc(uint64 size, char *error_buf, uint32 error_buf_size) static bool check_utf8_str(const uint8* str, uint32 len) { - const uint8 *p = str, *p_end = str + len, *p_end1; - uint8 chr, n_bytes; + /* The valid ranges are taken from page 125, below link + https://www.unicode.org/versions/Unicode9.0.0/ch03.pdf */ + const uint8 *p = str, *p_end = str + len; + uint8 chr; while (p < p_end) { - chr = *p++; - if (chr >= 0x80) { - /* Calculate the byte count: the first byte must be - 110XXXXX, 1110XXXX, 11110XXX, 111110XX, or 1111110X, - the count of leading '1' denotes the total byte count */ - n_bytes = 0; - while ((chr & 0x80) != 0) { - chr = (uint8)(chr << 1); - n_bytes++; - } - - /* Check byte count */ - if (n_bytes < 2 || n_bytes > 6 - || p + n_bytes - 1 > p_end) + chr = *p; + if (chr < 0x80) { + p++; + } + else if (chr >= 0xC2 && chr <= 0xDF && p + 1 < p_end) { + if (p[1] < 0x80 || p[1] > 0xBF) { return false; - - /* Check the following bytes, which must be 10XXXXXX */ - p_end1 = p + n_bytes - 1; - while (p < p_end1) { - if (!(*p & 0x80) || (*p | 0x40)) - return false; - p++; } + p += 2; + } + else if (chr >= 0xE0 && chr <= 0xEF && p + 2 < p_end) { + if (chr == 0xE0) { + if (p[1] < 0xA0 || p[1] > 0xBF + || p[2] < 0x80 || p[2] > 0xBF) { + return false; + } + } + else if (chr == 0xED) { + if (p[1] < 0x80 || p[1] > 0x9F + || p[2] < 0x80 || p[2] > 0xBF) { + return false; + } + } + else if (chr >= 0xE1 && chr <= 0xEF) { + if (p[1] < 0x80 || p[1] > 0xBF + || p[2] < 0x80 || p[2] > 0xBF) { + return false; + } + } + p += 3; + } + else if (chr >= 0xF0 && chr <= 0xF4 && p + 3 < p_end) { + if (chr == 0xF0) { + if (p[1] < 0x90 || p[1] > 0xBF + || p[2] < 0x80 || p[2] > 0xBF + || p[3] < 0x80 || p[3] > 0xBF) { + return false; + } + } + else if (chr >= 0xF1 && chr <= 0xF3) { + if (p[1] < 0x80 || p[1] > 0xBF + || p[2] < 0x80 || p[2] > 0xBF + || p[3] < 0x80 || p[3] > 0xBF) { + return false; + } + } + else if (chr == 0xF4) { + if (p[1] < 0x80 || p[1] > 0x8F + || p[2] < 0x80 || p[2] > 0xBF + || p[3] < 0x80 || p[3] > 0xBF) { + return false; + } + } + p += 4; + } + else { + return false; } } - return true; + return (p == p_end); } static char* From 7c8ccc7c26cad83d42b1f803ca970bf605e8e938 Mon Sep 17 00:00:00 2001 From: Xiaokang Qin Date: Fri, 18 Sep 2020 18:22:26 +0800 Subject: [PATCH 074/207] Fix the build warnings on Mac (#388) Signed-off-by: Xiaokang Qin --- core/iwasm/common/wasm_runtime_common.c | 14 ++--- core/iwasm/compilation/aot_emit_function.c | 2 +- core/iwasm/compilation/aot_emit_numberic.c | 62 +++++++++---------- core/iwasm/interpreter/wasm.h | 12 ++-- core/iwasm/interpreter/wasm_runtime.h | 20 +++--- .../platform/common/posix/posix_thread.c | 5 +- wamr-compiler/CMakeLists.txt | 19 +++--- 7 files changed, 71 insertions(+), 63 deletions(-) diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index 2d3fbeb55..0cf9f4b18 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -2657,13 +2657,6 @@ fail: * Implementation of wasm_runtime_invoke_native() */ -static inline void -word_copy(uint32 *dest, uint32 *src, unsigned num) -{ - for (; num > 0; num--) - *dest++ = *src++; -} - #define PUT_I64_TO_ADDR(addr, value) do { \ union { int64 val; uint32 parts[2]; } u; \ u.val = (value); \ @@ -2936,6 +2929,13 @@ static Float64FuncPtr invokeNative_Float64 = (Float64FuncPtr)invokeNative; static Float32FuncPtr invokeNative_Float32 = (Float32FuncPtr)invokeNative; static VoidFuncPtr invokeNative_Void = (VoidFuncPtr)invokeNative; +static inline void +word_copy(uint32 *dest, uint32 *src, unsigned num) +{ + for (; num > 0; num--) + *dest++ = *src++; +} + bool wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, const WASMType *func_type, const char *signature, diff --git a/core/iwasm/compilation/aot_emit_function.c b/core/iwasm/compilation/aot_emit_function.c index af7362f50..21b49ad0c 100644 --- a/core/iwasm/compilation/aot_emit_function.c +++ b/core/iwasm/compilation/aot_emit_function.c @@ -661,7 +661,7 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, uint32 param_cell_num; uint64 total_size; uint8 *wasm_ret_types = NULL; - bool ret; + bool ret = false; /* Check function type index */ if (type_idx >= comp_ctx->comp_data->func_type_count) { diff --git a/core/iwasm/compilation/aot_emit_numberic.c b/core/iwasm/compilation/aot_emit_numberic.c index fc6a51382..d686dead6 100644 --- a/core/iwasm/compilation/aot_emit_numberic.c +++ b/core/iwasm/compilation/aot_emit_numberic.c @@ -241,10 +241,10 @@ call_llvm_intrinsic_v(AOTCompContext *comp_ctx, /* Call llvm constrained floating-point intrinsic */ static LLVMValueRef -call_llvm_float_expermental_constrained_intrinsic(AOTCompContext *comp_ctx, - const char *intrinsic, - bool is_f32, - ...) +call_llvm_float_experimental_constrained_intrinsic(AOTCompContext *comp_ctx, + bool is_f32, + const char *intrinsic, + ...) { va_list param_value_list; LLVMValueRef ret; @@ -253,7 +253,7 @@ call_llvm_float_expermental_constrained_intrinsic(AOTCompContext *comp_ctx, param_types[0] = param_types[1] = ret_type; param_types[2] = param_types[3] = MD_TYPE; - va_start(param_value_list, is_f32); + va_start(param_value_list, intrinsic); ret = call_llvm_intrinsic_v(comp_ctx, intrinsic, @@ -269,10 +269,10 @@ call_llvm_float_expermental_constrained_intrinsic(AOTCompContext *comp_ctx, /* Call llvm constrained libm-equivalent intrinsic */ static LLVMValueRef -call_llvm_libm_expermental_constrained_intrinsic(AOTCompContext *comp_ctx, - const char *intrinsic, - bool is_f32, - ...) +call_llvm_libm_experimental_constrained_intrinsic(AOTCompContext *comp_ctx, + bool is_f32, + const char *intrinsic, + ...) { va_list param_value_list; LLVMValueRef ret; @@ -281,7 +281,7 @@ call_llvm_libm_expermental_constrained_intrinsic(AOTCompContext *comp_ctx, param_types[0] = ret_type; param_types[1] = param_types[2] = MD_TYPE; - va_start(param_value_list, is_f32); + va_start(param_value_list, intrinsic); ret = call_llvm_intrinsic_v(comp_ctx, intrinsic, @@ -929,12 +929,12 @@ compile_op_float_arithmetic(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, DEF_FP_BINARY_OP(LLVMBuildFAdd(comp_ctx->builder, left, right, "fadd"), "llvm build fadd fail."); else - DEF_FP_BINARY_OP(call_llvm_float_expermental_constrained_intrinsic( + DEF_FP_BINARY_OP(call_llvm_float_experimental_constrained_intrinsic( comp_ctx, + is_f32, (is_f32 ? "llvm.experimental.constrained.fadd.f32" : "llvm.experimental.constrained.fadd.f64"), - is_f32, left, right, comp_ctx->fp_rounding_mode, @@ -946,12 +946,12 @@ compile_op_float_arithmetic(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, DEF_FP_BINARY_OP(LLVMBuildFSub(comp_ctx->builder, left, right, "fsub"), "llvm build fsub fail."); else - DEF_FP_BINARY_OP(call_llvm_float_expermental_constrained_intrinsic( + DEF_FP_BINARY_OP(call_llvm_float_experimental_constrained_intrinsic( comp_ctx, + is_f32, (is_f32 ? "llvm.experimental.constrained.fsub.f32" : "llvm.experimental.constrained.fsub.f64"), - is_f32, left, right, comp_ctx->fp_rounding_mode, @@ -963,12 +963,12 @@ compile_op_float_arithmetic(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, DEF_FP_BINARY_OP(LLVMBuildFMul(comp_ctx->builder, left, right, "fmul"), "llvm build fmul fail."); else - DEF_FP_BINARY_OP(call_llvm_float_expermental_constrained_intrinsic( + DEF_FP_BINARY_OP(call_llvm_float_experimental_constrained_intrinsic( comp_ctx, + is_f32, (is_f32 ? "llvm.experimental.constrained.fmul.f32" : "llvm.experimental.constrained.fmul.f64"), - is_f32, left, right, comp_ctx->fp_rounding_mode, @@ -980,12 +980,12 @@ compile_op_float_arithmetic(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, DEF_FP_BINARY_OP(LLVMBuildFDiv(comp_ctx->builder, left, right, "fdiv"), "llvm build fdiv fail."); else - DEF_FP_BINARY_OP(call_llvm_float_expermental_constrained_intrinsic( + DEF_FP_BINARY_OP(call_llvm_float_experimental_constrained_intrinsic( comp_ctx, + is_f32, (is_f32 ? "llvm.experimental.constrained.fdiv.f32" : "llvm.experimental.constrained.fdiv.f64"), - is_f32, left, right, comp_ctx->fp_rounding_mode, @@ -1020,9 +1020,9 @@ fail: static LLVMValueRef call_llvm_float_math_intrinsic(AOTCompContext *comp_ctx, - const char *intrinsic, - bool is_f32, - ...) + bool is_f32, + const char *intrinsic, + ...) { va_list param_value_list; LLVMValueRef ret; @@ -1030,7 +1030,7 @@ call_llvm_float_math_intrinsic(AOTCompContext *comp_ctx, param_type = ret_type; - va_start(param_value_list, is_f32); + va_start(param_value_list, intrinsic); ret = call_llvm_intrinsic_v(comp_ctx, intrinsic, @@ -1051,9 +1051,9 @@ compile_op_float_math(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, switch (math_op) { case FLOAT_ABS: DEF_FP_UNARY_OP(call_llvm_float_math_intrinsic(comp_ctx, + is_f32, is_f32 ? "llvm.fabs.f32" : "llvm.fabs.f64", - is_f32, operand), NULL); return true; @@ -1064,51 +1064,51 @@ compile_op_float_math(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, case FLOAT_CEIL: DEF_FP_UNARY_OP(call_llvm_float_math_intrinsic(comp_ctx, + is_f32, is_f32 ? "llvm.ceil.f32" : "llvm.ceil.f64", - is_f32, operand), NULL); return true; case FLOAT_FLOOR: DEF_FP_UNARY_OP(call_llvm_float_math_intrinsic(comp_ctx, - is_f32 ? "llvm.floor.f32" : - "llvm.floor.f64", is_f32, + is_f32 ? "llvm.floor.f32": + "llvm.floor.f64", operand), NULL); return true; case FLOAT_TRUNC: DEF_FP_UNARY_OP(call_llvm_float_math_intrinsic(comp_ctx, + is_f32, is_f32 ? "llvm.trunc.f32" : "llvm.trunc.f64", - is_f32, operand), NULL); return true; case FLOAT_NEAREST: DEF_FP_UNARY_OP(call_llvm_float_math_intrinsic(comp_ctx, + is_f32, is_f32 ? "llvm.rint.f32" : "llvm.rint.f64", - is_f32, operand), NULL); return true; case FLOAT_SQRT: if (is_targeting_soft_float(comp_ctx, is_f32)) DEF_FP_UNARY_OP(call_llvm_float_math_intrinsic(comp_ctx, + is_f32, is_f32 ? "llvm.sqrt.f32" : "llvm.sqrt.f64", - is_f32, operand), NULL); else - DEF_FP_UNARY_OP(call_llvm_libm_expermental_constrained_intrinsic( + DEF_FP_UNARY_OP(call_llvm_libm_experimental_constrained_intrinsic( comp_ctx, + is_f32, (is_f32 ? "llvm.experimental.constrained.sqrt.f32" : "llvm.experimental.constrained.sqrt.f64"), - is_f32, operand, comp_ctx->fp_rounding_mode, comp_ctx->fp_exception_behavior), diff --git a/core/iwasm/interpreter/wasm.h b/core/iwasm/interpreter/wasm.h index a24720c33..6b4e71daf 100644 --- a/core/iwasm/interpreter/wasm.h +++ b/core/iwasm/interpreter/wasm.h @@ -195,7 +195,7 @@ typedef struct WASMImport { } u; } WASMImport; -typedef struct WASMFunction { +struct WASMFunction { /* the type of function */ WASMType *func_type; uint32 local_count; @@ -226,13 +226,13 @@ typedef struct WASMFunction { uint8 *consts; uint32 const_cell_num; #endif -} WASMFunction; +}; -typedef struct WASMGlobal { +struct WASMGlobal { uint8 type; bool is_mutable; InitializerExpression init_expr; -} WASMGlobal; +}; typedef struct WASMExport { char *name; @@ -281,7 +281,7 @@ typedef struct StringNode { char *str; } StringNode, *StringList; -typedef struct WASMModule { +struct WASMModule { /* Module type, for module loaded from WASM bytecode binary, this field is Wasm_Module_Bytecode; for module loaded from AOT file, this field is @@ -365,7 +365,7 @@ typedef struct WASMModule { bh_list import_module_list_head; bh_list *import_module_list; #endif -} WASMModule; +}; typedef struct BlockType { /* Block type may be expressed in one of two forms: diff --git a/core/iwasm/interpreter/wasm_runtime.h b/core/iwasm/interpreter/wasm_runtime.h index c151ada03..852431027 100644 --- a/core/iwasm/interpreter/wasm_runtime.h +++ b/core/iwasm/interpreter/wasm_runtime.h @@ -21,7 +21,7 @@ typedef struct WASMMemoryInstance WASMMemoryInstance; typedef struct WASMTableInstance WASMTableInstance; typedef struct WASMGlobalInstance WASMGlobalInstance; -typedef struct WASMMemoryInstance { +struct WASMMemoryInstance { /* Module type */ uint32 module_type; /* Shared memory flag */ @@ -57,9 +57,9 @@ typedef struct WASMMemoryInstance { Note: when memory is re-allocated, the heap data and memory data must be copied to new memory also. */ uint8 memory_data[1]; -} WASMMemoryInstance; +}; -typedef struct WASMTableInstance { +struct WASMTableInstance { /* The element type, TABLE_ELEM_TYPE_ANY_FUNC currently */ uint8 elem_type; /* Current size */ @@ -72,9 +72,9 @@ typedef struct WASMTableInstance { #endif /* Base address */ uint8 base_addr[1]; -} WASMTableInstance; +}; -typedef struct WASMGlobalInstance { +struct WASMGlobalInstance { /* value type, VALUE_TYPE_I32/I64/F32/F64 */ uint8 type; /* mutable or constant */ @@ -88,9 +88,9 @@ typedef struct WASMGlobalInstance { WASMModuleInstance *import_module_inst; WASMGlobalInstance *import_global_inst; #endif -} WASMGlobalInstance; +}; -typedef struct WASMFunctionInstance { +struct WASMFunctionInstance { /* whether it is import function or WASM function */ bool is_import_func; /* parameter count */ @@ -120,7 +120,7 @@ typedef struct WASMFunctionInstance { WASMModuleInstance *import_module_inst; WASMFunctionInstance *import_func_inst; #endif -} WASMFunctionInstance; +}; typedef struct WASMExportFuncInstance { char *name; @@ -144,7 +144,7 @@ typedef struct WASMExportMemInstance { } WASMExportMemInstance; #endif -typedef struct WASMModuleInstance { +struct WASMModuleInstance { /* Module instance type, for module instance loaded from WASM bytecode binary, this field is Wasm_Module_Bytecode; for module instance loaded from AOT file, this field is @@ -213,7 +213,7 @@ typedef struct WASMModuleInstance { #if WASM_ENABLE_MEMORY_PROFILING != 0 uint32 max_aux_stack_used; #endif -} WASMModuleInstance; +}; struct WASMInterpFrame; typedef struct WASMInterpFrame WASMRuntimeFrame; diff --git a/core/shared/platform/common/posix/posix_thread.c b/core/shared/platform/common/posix/posix_thread.c index 5f1bcf13b..42621f587 100644 --- a/core/shared/platform/common/posix/posix_thread.c +++ b/core/shared/platform/common/posix/posix_thread.c @@ -238,9 +238,12 @@ void os_thread_exit(void *retval) uint8 *os_thread_get_stack_boundary() { pthread_t self = pthread_self(); +#ifdef __linux__ pthread_attr_t attr; + size_t guard_size; +#endif uint8 *addr = NULL; - size_t stack_size, guard_size; + size_t stack_size; int page_size = getpagesize(); size_t max_stack_size = (size_t) (APP_THREAD_STACK_SIZE_MAX + page_size - 1) diff --git a/wamr-compiler/CMakeLists.txt b/wamr-compiler/CMakeLists.txt index 7efe1c0e9..2d82452db 100644 --- a/wamr-compiler/CMakeLists.txt +++ b/wamr-compiler/CMakeLists.txt @@ -110,8 +110,11 @@ if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".* endif() if (NOT MSVC) - set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ffunction-sections -fdata-sections \ - -Wall -Wno-unused-parameter -Wno-pedantic") + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat -Wformat-security \ + -ffunction-sections -fdata-sections \ + -Wno-unused-parameter -Wno-pedantic") + # Remove the extra spaces for better make log + string (REGEX REPLACE " *" " " CMAKE_C_FLAGS ${CMAKE_C_FLAGS}) endif() set (SHARED_DIR ../core/shared) @@ -134,10 +137,6 @@ include (${IWASM_DIR}/interpreter/iwasm_interp.cmake) include (${IWASM_DIR}/aot/iwasm_aot.cmake) include (${IWASM_DIR}/compilation/iwasm_compl.cmake) -if (NOT MSVC) - set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat -Wformat-security") -endif() - # set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wconversion -Wsign-conversion") if (WAMR_BUILD_TARGET MATCHES "X86_.*" OR WAMR_BUILD_TARGET STREQUAL "AMD_64") if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang" OR MSVC)) @@ -147,6 +146,8 @@ endif () if (NOT MSVC) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fstack-protector-strong --param ssp-buffer-size=4") +endif() +if (NOT (MSVC OR CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang")) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wl,-z,noexecstack,-z,relro,-z,now") endif() @@ -154,7 +155,11 @@ endif() # set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mindirect-branch=thunk -mfunction-return=thunk") if (NOT MSVC) - set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pie -fPIE -ftrapv -D_FORTIFY_SOURCE=2") + if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang")) + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pie -fPIE -ftrapv -D_FORTIFY_SOURCE=2") + else() + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIE -ftrapv -D_FORTIFY_SOURCE=2") + endif() endif() # message ("-- CMAKE_C_FLAGS: ${CMAKE_C_FLAGS}") From e501a6963bb093bf81cc1682f753a2e60963a357 Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Sun, 20 Sep 2020 08:20:45 +0800 Subject: [PATCH 075/207] Fix some coding style issues, fix doc typo and refine some codes (#392) --- core/iwasm/common/wasm_c_api.c | 2 +- core/iwasm/common/wasm_c_api_internal.h | 10 +-- core/iwasm/common/wasm_runtime_common.c | 13 +-- core/iwasm/interpreter/wasm.h | 2 +- core/iwasm/interpreter/wasm_interp_classic.c | 1 - core/iwasm/interpreter/wasm_interp_fast.c | 2 +- core/iwasm/interpreter/wasm_loader.c | 10 +-- core/iwasm/interpreter/wasm_mini_loader.c | 10 +-- core/iwasm/interpreter/wasm_runtime.c | 10 +-- .../platform/common/posix/posix_thread.c | 22 +---- core/shared/platform/nuttx/nuttx_thread.c | 14 +-- core/shared/platform/windows/win_thread.c | 8 -- doc/build_wamr.md | 2 +- product-mini/app-samples/hello-world/build.sh | 1 + .../platforms/alios-things/src/test_wasm.h | 89 ++++++++----------- product-mini/platforms/android/wasm-jni.cpp | 86 ++++++++---------- product-mini/platforms/linux/main.c | 5 +- product-mini/platforms/nuttx/main.c | 4 +- product-mini/platforms/windows/main.c | 2 - .../platforms/zephyr/simple/src/test_wasm.h | 89 ++++++++----------- 20 files changed, 155 insertions(+), 227 deletions(-) diff --git a/core/iwasm/common/wasm_c_api.c b/core/iwasm/common/wasm_c_api.c index 21d612c6d..f87edf6be 100644 --- a/core/iwasm/common/wasm_c_api.c +++ b/core/iwasm/common/wasm_c_api.c @@ -2202,9 +2202,9 @@ interp_process_export(wasm_store_t *store, external = wasm_global_as_extern(global); break; - // TODO: case EXPORT_KIND_MEMORY: case EXPORT_KIND_TABLE: + /* TODO: */ break; default: goto failed; diff --git a/core/iwasm/common/wasm_c_api_internal.h b/core/iwasm/common/wasm_c_api_internal.h index 40d049aa7..f2d5c65f8 100644 --- a/core/iwasm/common/wasm_c_api_internal.h +++ b/core/iwasm/common/wasm_c_api_internal.h @@ -31,9 +31,9 @@ typedef enum runtime_mode_e { } runtime_mode_e; struct wasm_engine_t { - // support one store for now + /* support one store for now */ wasm_store_vec_t *stores; - // Interpreter by deault + /* Interpreter by deault */ runtime_mode_e mode; }; @@ -49,21 +49,21 @@ struct wasm_valtype_t { struct wasm_functype_t { uint32 extern_kind; - // gona to new and delete own + /* gona to new and delete own */ wasm_valtype_vec_t *params; wasm_valtype_vec_t *results; }; struct wasm_globaltype_t { uint32 extern_kind; - // gona to new and delete own + /* gona to new and delete own */ wasm_valtype_t *val_type; wasm_mutability_t mutability; }; struct wasm_tabletype_t { uint32 extern_kind; - // always be WASM_FUNCREF + /* always be WASM_FUNCREF */ wasm_valtype_t *type; wasm_limits_t *limits; }; diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index 0cf9f4b18..6c50fa2cb 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -791,6 +791,7 @@ wasm_runtime_destroy_exec_env(WASMExecEnv *exec_env) wasm_exec_env_destroy(exec_env); } +#if (WASM_ENABLE_MEMORY_PROFILING != 0) || (WASM_ENABLE_MEMORY_TRACING != 0) void wasm_runtime_dump_module_mem_consumption(const WASMModuleCommon *module) { @@ -872,7 +873,6 @@ wasm_runtime_dump_exec_env_mem_consumption(const WASMExecEnv *exec_env) os_printf(" stack size: %u\n", exec_env->wasm_stack_size); } -#if WASM_ENABLE_MEMORY_PROFILING != 0 uint32 gc_get_heap_highmark_size(void *heap); @@ -951,7 +951,8 @@ wasm_runtime_dump_mem_consumption(WASMExecEnv *exec_env) os_printf("Total app heap used: %u\n", app_heap_peak_size); } -#endif +#endif /* end of (WASM_ENABLE_MEMORY_PROFILING != 0) + || (WASM_ENABLE_MEMORY_TRACING != 0) */ WASMModuleInstanceCommon * wasm_runtime_get_module_inst(WASMExecEnv *exec_env) @@ -2645,7 +2646,7 @@ wasm_runtime_invoke_native_raw(WASMExecEnv *exec_env, void *func_ptr, } } - ret = true; + ret = !wasm_runtime_get_exception(module) ? true : false; fail: if (argv1 != argv_buf) @@ -2900,7 +2901,7 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, } exec_env->attachment = NULL; - ret = true; + ret = !wasm_runtime_get_exception(module) ? true : false; fail: if (argv1 != argv_buf) @@ -3053,7 +3054,7 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, } exec_env->attachment = NULL; - ret = true; + ret = !wasm_runtime_get_exception(module) ? true : false; fail: if (argv1 != argv_buf) @@ -3231,7 +3232,7 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, } exec_env->attachment = NULL; - ret = true; + ret = !wasm_runtime_get_exception(module) ? true : false; fail: if (argv1 != argv_buf) wasm_runtime_free(argv1); diff --git a/core/iwasm/interpreter/wasm.h b/core/iwasm/interpreter/wasm.h index 6b4e71daf..1fb99baec 100644 --- a/core/iwasm/interpreter/wasm.h +++ b/core/iwasm/interpreter/wasm.h @@ -175,7 +175,7 @@ typedef struct WASMGlobalImport { WASMValue global_data_linked; #if WASM_ENABLE_MULTI_MODULE != 0 /* imported function pointer after linked */ - // TODO: remove if not necessary + /* TODO: remove if not needed */ WASMModule *import_module; WASMGlobal *import_global_linked; #endif diff --git a/core/iwasm/interpreter/wasm_interp_classic.c b/core/iwasm/interpreter/wasm_interp_classic.c index a0d9d2fc7..ec0aca844 100644 --- a/core/iwasm/interpreter/wasm_interp_classic.c +++ b/core/iwasm/interpreter/wasm_interp_classic.c @@ -3269,7 +3269,6 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMFunctionInstance *function, uint32 argc, uint32 argv[]) { - // TODO: since module_inst = exec_env->module_inst, shall we remove the 1st arg? WASMRuntimeFrame *prev_frame = wasm_exec_env_get_cur_frame(exec_env); WASMInterpFrame *frame, *outs_area; diff --git a/core/iwasm/interpreter/wasm_interp_fast.c b/core/iwasm/interpreter/wasm_interp_fast.c index 48b989d1d..2a6262deb 100644 --- a/core/iwasm/interpreter/wasm_interp_fast.c +++ b/core/iwasm/interpreter/wasm_interp_fast.c @@ -1117,7 +1117,7 @@ wasm_interp_dump_op_count() #if WASM_ENABLE_LABELS_AS_VALUES != 0 -//#define HANDLE_OP(opcode) HANDLE_##opcode:printf(#opcode"\n");h_##opcode +/* #define HANDLE_OP(opcode) HANDLE_##opcode:printf(#opcode"\n");h_##opcode */ #if WASM_ENABLE_OPCODE_COUNTER != 0 #define HANDLE_OP(opcode) HANDLE_##opcode:opcode_table[opcode].count++;h_##opcode #else diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index 2b8de26c3..f1da1b11d 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -3961,7 +3961,7 @@ fail: LOG_OP("\nemit_op [%02x]\t", opcode); \ } while (0) -// drop local.get / const / block / loop / end +/* drop local.get / const / block / loop / end */ #define skip_label() do { \ wasm_loader_emit_backspace(loader_ctx, sizeof(int16)); \ LOG_OP("\ndelete last op\n"); \ @@ -4334,7 +4334,7 @@ wasm_loader_push_frame_offset(WASMLoaderContext *ctx, uint8 type, if (type == VALUE_TYPE_VOID) return true; - // only check memory overflow in first traverse + /* only check memory overflow in first traverse */ if (ctx->p_code_compiled == NULL) { if (!check_offset_push(ctx, error_buf, error_buf_size)) return false; @@ -5695,7 +5695,7 @@ handle_op_block_and_loop: + func->func_type->param_count + idx); POP_TYPE(ret_type); #if WASM_ENABLE_FAST_INTERP != 0 - // emit the offset after return opcode + /* emit the offset after return opcode */ POP_OFFSET_TYPE(ret_type); #endif } @@ -5714,7 +5714,7 @@ handle_op_block_and_loop: read_leb_uint32(p, p_end, func_idx); #if WASM_ENABLE_FAST_INTERP != 0 - // we need to emit func_idx before arguments + /* we need to emit func_idx before arguments */ emit_uint32(loader_ctx, func_idx); #endif @@ -5769,7 +5769,7 @@ handle_op_block_and_loop: read_leb_uint32(p, p_end, type_idx); #if WASM_ENABLE_FAST_INTERP != 0 - // we need to emit func_idx before arguments + /* we need to emit func_idx before arguments */ emit_uint32(loader_ctx, type_idx); #endif diff --git a/core/iwasm/interpreter/wasm_mini_loader.c b/core/iwasm/interpreter/wasm_mini_loader.c index 2a39a83a4..0d83c2dcd 100644 --- a/core/iwasm/interpreter/wasm_mini_loader.c +++ b/core/iwasm/interpreter/wasm_mini_loader.c @@ -2890,7 +2890,7 @@ wasm_loader_pop_frame_csp(WASMLoaderContext *ctx, LOG_OP("\nemit_op [%02x]\t", opcode); \ } while (0) -// drop local.get / const / block / loop / end +/* drop local.get / const / block / loop / end */ #define skip_label() do { \ wasm_loader_emit_backspace(loader_ctx, sizeof(int16)); \ LOG_OP("\ndelete last op\n"); \ @@ -3264,7 +3264,7 @@ wasm_loader_push_frame_offset(WASMLoaderContext *ctx, uint8 type, if (type == VALUE_TYPE_VOID) return true; - // only check memory overflow in first traverse + /* only check memory overflow in first traverse */ if (ctx->p_code_compiled == NULL) { if (!check_offset_push(ctx, error_buf, error_buf_size)) return false; @@ -4525,7 +4525,7 @@ handle_op_block_and_loop: + func->func_type->param_count + idx); POP_TYPE(ret_type); #if WASM_ENABLE_FAST_INTERP != 0 - // emit the offset after return opcode + /* emit the offset after return opcode */ POP_OFFSET_TYPE(ret_type); #endif } @@ -4544,7 +4544,7 @@ handle_op_block_and_loop: read_leb_uint32(p, p_end, func_idx); #if WASM_ENABLE_FAST_INTERP != 0 - // we need to emit func_idx before arguments + /* we need to emit func_idx before arguments */ emit_uint32(loader_ctx, func_idx); #endif @@ -4592,7 +4592,7 @@ handle_op_block_and_loop: read_leb_uint32(p, p_end, type_idx); #if WASM_ENABLE_FAST_INTERP != 0 - // we need to emit func_idx before arguments + /* we need to emit func_idx before arguments */ emit_uint32(loader_ctx, type_idx); #endif diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index 5a434766a..edea3fae0 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -330,15 +330,15 @@ memories_instantiate(const WASMModule *module, #if WASM_ENABLE_MULTI_MODULE != 0 WASMMemoryInstance *memory_inst_linked = NULL; if (import->u.memory.import_module != NULL) { + WASMModuleInstance *module_inst_linked; + LOG_DEBUG("(%s, %s) is a memory of a sub-module", import->u.memory.module_name, import->u.memory.field_name); - // TODO: how about native memory ? - WASMModuleInstance *module_inst_linked = - get_sub_module_inst( - module_inst, - import->u.memory.import_module); + module_inst_linked = + get_sub_module_inst(module_inst, + import->u.memory.import_module); bh_assert(module_inst_linked); memory_inst_linked = diff --git a/core/shared/platform/common/posix/posix_thread.c b/core/shared/platform/common/posix/posix_thread.c index 42621f587..39c12b8c8 100644 --- a/core/shared/platform/common/posix/posix_thread.c +++ b/core/shared/platform/common/posix/posix_thread.c @@ -112,38 +112,24 @@ int os_mutex_destroy(korp_mutex *mutex) return ret == 0 ? BHT_OK : BHT_ERROR; } -/* Returned error (EINVAL, EAGAIN and EDEADLK) from - locking the mutex indicates some logic error present in - the program somewhere. - Don't try to recover error for an existing unknown error.*/ int os_mutex_lock(korp_mutex *mutex) { int ret; assert(mutex); ret = pthread_mutex_lock(mutex); - if (0 != ret) { - os_printf("vm mutex lock failed (ret=%d)!\n", ret); - exit(-1); - } - return ret; + + return ret == 0 ? BHT_OK : BHT_ERROR; } -/* Returned error (EINVAL, EAGAIN and EPERM) from - unlocking the mutex indicates some logic error present - in the program somewhere. - Don't try to recover error for an existing unknown error.*/ int os_mutex_unlock(korp_mutex *mutex) { int ret; assert(mutex); ret = pthread_mutex_unlock(mutex); - if (0 != ret) { - os_printf("vm mutex unlock failed (ret=%d)!\n", ret); - exit(-1); - } - return ret; + + return ret == 0 ? BHT_OK : BHT_ERROR; } int os_cond_init(korp_cond *cond) diff --git a/core/shared/platform/nuttx/nuttx_thread.c b/core/shared/platform/nuttx/nuttx_thread.c index aa69ee4d0..d1c8be996 100644 --- a/core/shared/platform/nuttx/nuttx_thread.c +++ b/core/shared/platform/nuttx/nuttx_thread.c @@ -36,11 +36,8 @@ os_mutex_lock(korp_mutex *mutex) assert(mutex); ret = pthread_mutex_lock(mutex); - if (0 != ret) { - os_printf("vm mutex lock failed (ret=%d)!\n", ret); - exit(-1); - } - return ret; + + return ret == 0 ? BHT_OK : BHT_ERROR; } int @@ -50,11 +47,8 @@ os_mutex_unlock(korp_mutex *mutex) assert(mutex); ret = pthread_mutex_unlock(mutex); - if (0 != ret) { - os_printf("vm mutex unlock failed (ret=%d)!\n", ret); - exit(-1); - } - return ret; + + return ret == 0 ? BHT_OK : BHT_ERROR; } uint8 * diff --git a/core/shared/platform/windows/win_thread.c b/core/shared/platform/windows/win_thread.c index 896137ef7..f356dcc32 100644 --- a/core/shared/platform/windows/win_thread.c +++ b/core/shared/platform/windows/win_thread.c @@ -61,19 +61,11 @@ int os_mutex_destroy(korp_mutex *mutex) return BHT_OK; } -/* Returned error (EINVAL, EAGAIN and EDEADLK) from - locking the mutex indicates some logic error present in - the program somewhere. - Don't try to recover error for an existing unknown error.*/ int os_mutex_lock(korp_mutex *mutex) { return BHT_ERROR; } -/* Returned error (EINVAL, EAGAIN and EPERM) from - unlocking the mutex indicates some logic error present - in the program somewhere. - Don't try to recover error for an existing unknown error.*/ int os_mutex_unlock(korp_mutex *mutex) { return BHT_OK; diff --git a/doc/build_wamr.md b/doc/build_wamr.md index 4e3627a7a..7397e2097 100644 --- a/doc/build_wamr.md +++ b/doc/build_wamr.md @@ -69,7 +69,7 @@ cmake -DWAMR_BUILD_PLATFORM=linux -DWAMR_BUILD_TARGET=ARM > Note: by default only platform linux/darwin/android/vxworks 64-bit will enable boundary check with hardware trap in AOT or JIT mode, and the wamrc tool will generate AOT code without boundary check instructions in all 64-bit targets except SGX to improve performance. #### **Enable memory profiling (Experiment)** -- **WAMR_BUILD_MEMORY_PROFLING**=1/0, default to disable if not set +- **WAMR_BUILD_MEMORY_PROFILING**=1/0, default to disable if not set > Note: if it is enabled, developer can use API `void wasm_runtime_dump_mem_consumption(wasm_exec_env_t exec_env)` to dump the memory consumption info. Currently we only profile the memory consumption of module, module_instance and exec_env, the memory consumed by other components such as `wasi-ctx`, `multi-module` and `thread-manager` are not included. diff --git a/product-mini/app-samples/hello-world/build.sh b/product-mini/app-samples/hello-world/build.sh index 9407c700e..4d4fb0ee8 100755 --- a/product-mini/app-samples/hello-world/build.sh +++ b/product-mini/app-samples/hello-world/build.sh @@ -9,6 +9,7 @@ WAMR_DIR=${PWD}/../../.. --sysroot=${WAMR_DIR}/wamr-sdk/app/libc-builtin-sysroot \ -Wl,--allow-undefined-file=${WAMR_DIR}/wamr-sdk/app/libc-builtin-sysroot/share/defined-symbols.txt \ -Wl,--export=main, \ + -Wl,--export=__data_end, -Wl,--export=__heap_base \ -Wl,--no-threads,--strip-all,--no-entry \ -nostdlib -o test.wasm *.c #./jeffdump -o test_wasm.h -n wasm_test_file test.wasm diff --git a/product-mini/platforms/alios-things/src/test_wasm.h b/product-mini/platforms/alios-things/src/test_wasm.h index 65b834798..0c343024a 100644 --- a/product-mini/platforms/alios-things/src/test_wasm.h +++ b/product-mini/platforms/alios-things/src/test_wasm.h @@ -5,55 +5,42 @@ /** * The byte array buffer is the file content of a test wasm binary file, - * which is compiled by emcc or clang toolchain from C source file of: - * core/iwasm/app-samples/hello-world/main.c. + * which is compiled by wasi-sdk toolchain from C source file of: + * product-mini/app-samples/hello-world/main.c. */ -unsigned char wasm_test_file[] = { 0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x0D, 0x06, 0x64, 0x79, 0x6C, 0x69, 0x6E, 0x6B, 0xC0, 0x80, - 0x04, 0x04, 0x00, 0x00, 0x01, 0x13, 0x04, 0x60, 0x01, 0x7F, 0x00, 0x60, - 0x01, 0x7F, 0x01, 0x7F, 0x60, 0x02, 0x7F, 0x7F, 0x01, 0x7F, 0x60, 0x00, - 0x00, 0x02, 0x58, 0x06, 0x03, 0x65, 0x6E, 0x76, 0x05, 0x5F, 0x66, 0x72, - 0x65, 0x65, 0x00, 0x00, 0x03, 0x65, 0x6E, 0x76, 0x07, 0x5F, 0x6D, 0x61, - 0x6C, 0x6C, 0x6F, 0x63, 0x00, 0x01, 0x03, 0x65, 0x6E, 0x76, 0x07, 0x5F, - 0x70, 0x72, 0x69, 0x6E, 0x74, 0x66, 0x00, 0x02, 0x03, 0x65, 0x6E, 0x76, - 0x05, 0x5F, 0x70, 0x75, 0x74, 0x73, 0x00, 0x01, 0x03, 0x65, 0x6E, 0x76, - 0x0D, 0x5F, 0x5F, 0x6D, 0x65, 0x6D, 0x6F, 0x72, 0x79, 0x5F, 0x62, 0x61, - 0x73, 0x65, 0x03, 0x7F, 0x00, 0x03, 0x65, 0x6E, 0x76, 0x06, 0x6D, 0x65, - 0x6D, 0x6F, 0x72, 0x79, 0x02, 0x00, 0x01, 0x03, 0x04, 0x03, 0x02, 0x03, - 0x03, 0x06, 0x10, 0x03, 0x7F, 0x01, 0x41, 0x00, 0x0B, 0x7F, 0x01, 0x41, - 0x00, 0x0B, 0x7F, 0x00, 0x41, 0x1B, 0x0B, 0x07, 0x33, 0x04, 0x12, 0x5F, - 0x5F, 0x70, 0x6F, 0x73, 0x74, 0x5F, 0x69, 0x6E, 0x73, 0x74, 0x61, 0x6E, - 0x74, 0x69, 0x61, 0x74, 0x65, 0x00, 0x06, 0x05, 0x5F, 0x6D, 0x61, 0x69, - 0x6E, 0x00, 0x04, 0x0B, 0x72, 0x75, 0x6E, 0x50, 0x6F, 0x73, 0x74, 0x53, - 0x65, 0x74, 0x73, 0x00, 0x05, 0x04, 0x5F, 0x73, 0x74, 0x72, 0x03, 0x03, - 0x0A, 0xBA, 0x01, 0x03, 0x9E, 0x01, 0x01, 0x01, 0x7F, 0x23, 0x01, 0x21, - 0x00, 0x23, 0x01, 0x41, 0x10, 0x6A, 0x24, 0x01, 0x20, 0x00, 0x41, 0x08, - 0x6A, 0x21, 0x02, 0x23, 0x00, 0x41, 0x1B, 0x6A, 0x10, 0x03, 0x1A, 0x41, - 0x80, 0x08, 0x10, 0x01, 0x21, 0x01, 0x20, 0x01, 0x04, 0x7F, 0x20, 0x00, - 0x20, 0x01, 0x36, 0x02, 0x00, 0x23, 0x00, 0x20, 0x00, 0x10, 0x02, 0x1A, - 0x20, 0x01, 0x23, 0x00, 0x2C, 0x00, 0x0D, 0x3A, 0x00, 0x00, 0x20, 0x01, - 0x23, 0x00, 0x2C, 0x00, 0x0E, 0x3A, 0x00, 0x01, 0x20, 0x01, 0x23, 0x00, - 0x2C, 0x00, 0x0F, 0x3A, 0x00, 0x02, 0x20, 0x01, 0x23, 0x00, 0x2C, 0x00, - 0x10, 0x3A, 0x00, 0x03, 0x20, 0x01, 0x23, 0x00, 0x2C, 0x00, 0x11, 0x3A, - 0x00, 0x04, 0x20, 0x01, 0x23, 0x00, 0x2C, 0x00, 0x12, 0x3A, 0x00, 0x05, - 0x20, 0x02, 0x20, 0x01, 0x36, 0x02, 0x00, 0x23, 0x00, 0x41, 0x13, 0x6A, - 0x20, 0x02, 0x10, 0x02, 0x1A, 0x20, 0x01, 0x10, 0x00, 0x20, 0x00, 0x24, - 0x01, 0x41, 0x00, 0x05, 0x23, 0x00, 0x41, 0x28, 0x6A, 0x10, 0x03, 0x1A, - 0x20, 0x00, 0x24, 0x01, 0x41, 0x7F, 0x0B, 0x0B, 0x03, 0x00, 0x01, 0x0B, - 0x14, 0x00, 0x23, 0x00, 0x41, 0x40, 0x6B, 0x24, 0x01, 0x23, 0x01, 0x41, - 0x80, 0x80, 0x04, 0x6A, 0x24, 0x02, 0x10, 0x05, 0x0B, 0x0B, 0x3F, 0x01, - 0x00, 0x23, 0x00, 0x0B, 0x39, 0x62, 0x75, 0x66, 0x20, 0x70, 0x74, 0x72, - 0x3A, 0x20, 0x25, 0x70, 0x0A, 0x00, 0x31, 0x32, 0x33, 0x34, 0x0A, 0x00, - 0x62, 0x75, 0x66, 0x3A, 0x20, 0x25, 0x73, 0x00, 0x48, 0x65, 0x6C, 0x6C, - 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x00, 0x6D, 0x61, 0x6C, - 0x6C, 0x6F, 0x63, 0x20, 0x62, 0x75, 0x66, 0x20, 0x66, 0x61, 0x69, 0x6C, - 0x65, 0x64, 0x00, 0x50, 0x04, 0x6E, 0x61, 0x6D, 0x65, 0x01, 0x49, 0x07, - 0x00, 0x05, 0x5F, 0x66, 0x72, 0x65, 0x65, 0x01, 0x07, 0x5F, 0x6D, 0x61, - 0x6C, 0x6C, 0x6F, 0x63, 0x02, 0x07, 0x5F, 0x70, 0x72, 0x69, 0x6E, 0x74, - 0x66, 0x03, 0x05, 0x5F, 0x70, 0x75, 0x74, 0x73, 0x04, 0x05, 0x5F, 0x6D, - 0x61, 0x69, 0x6E, 0x05, 0x0B, 0x72, 0x75, 0x6E, 0x50, 0x6F, 0x73, 0x74, - 0x53, 0x65, 0x74, 0x73, 0x06, 0x12, 0x5F, 0x5F, 0x70, 0x6F, 0x73, 0x74, - 0x5F, 0x69, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74, 0x69, 0x61, 0x74, 0x65, - 0x00, 0x20, 0x10, 0x73, 0x6F, 0x75, 0x72, 0x63, 0x65, 0x4D, 0x61, 0x70, - 0x70, 0x69, 0x6E, 0x67, 0x55, 0x52, 0x4C, 0x0E, 0x61, 0x2E, 0x6F, 0x75, - 0x74, 0x2E, 0x77, 0x61, 0x73, 0x6D, 0x2E, 0x6D, 0x61, 0x70 }; +unsigned char wasm_test_file[] = { + 0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x10, 0x03, 0x60, + 0x01, 0x7F, 0x01, 0x7F, 0x60, 0x02, 0x7F, 0x7F, 0x01, 0x7F, 0x60, 0x01, + 0x7F, 0x00, 0x02, 0x31, 0x04, 0x03, 0x65, 0x6E, 0x76, 0x04, 0x70, 0x75, + 0x74, 0x73, 0x00, 0x00, 0x03, 0x65, 0x6E, 0x76, 0x06, 0x6D, 0x61, 0x6C, + 0x6C, 0x6F, 0x63, 0x00, 0x00, 0x03, 0x65, 0x6E, 0x76, 0x06, 0x70, 0x72, + 0x69, 0x6E, 0x74, 0x66, 0x00, 0x01, 0x03, 0x65, 0x6E, 0x76, 0x04, 0x66, + 0x72, 0x65, 0x65, 0x00, 0x02, 0x03, 0x02, 0x01, 0x01, 0x04, 0x05, 0x01, + 0x70, 0x01, 0x01, 0x01, 0x05, 0x03, 0x01, 0x00, 0x01, 0x06, 0x13, 0x03, + 0x7F, 0x01, 0x41, 0xC0, 0x28, 0x0B, 0x7F, 0x00, 0x41, 0xBA, 0x08, 0x0B, + 0x7F, 0x00, 0x41, 0xC0, 0x28, 0x0B, 0x07, 0x2C, 0x04, 0x06, 0x6D, 0x65, + 0x6D, 0x6F, 0x72, 0x79, 0x02, 0x00, 0x0A, 0x5F, 0x5F, 0x64, 0x61, 0x74, + 0x61, 0x5F, 0x65, 0x6E, 0x64, 0x03, 0x01, 0x0B, 0x5F, 0x5F, 0x68, 0x65, + 0x61, 0x70, 0x5F, 0x62, 0x61, 0x73, 0x65, 0x03, 0x02, 0x04, 0x6D, 0x61, + 0x69, 0x6E, 0x00, 0x04, 0x0A, 0xB2, 0x01, 0x01, 0xAF, 0x01, 0x01, 0x03, + 0x7F, 0x23, 0x80, 0x80, 0x80, 0x80, 0x00, 0x41, 0x20, 0x6B, 0x22, 0x02, + 0x24, 0x80, 0x80, 0x80, 0x80, 0x00, 0x41, 0x9B, 0x88, 0x80, 0x80, 0x00, + 0x10, 0x80, 0x80, 0x80, 0x80, 0x00, 0x1A, 0x02, 0x40, 0x02, 0x40, 0x41, + 0x80, 0x08, 0x10, 0x81, 0x80, 0x80, 0x80, 0x00, 0x22, 0x03, 0x0D, 0x00, + 0x41, 0xA8, 0x88, 0x80, 0x80, 0x00, 0x10, 0x80, 0x80, 0x80, 0x80, 0x00, + 0x1A, 0x41, 0x7F, 0x21, 0x04, 0x0C, 0x01, 0x0B, 0x20, 0x02, 0x20, 0x03, + 0x36, 0x02, 0x10, 0x41, 0x80, 0x88, 0x80, 0x80, 0x00, 0x20, 0x02, 0x41, + 0x10, 0x6A, 0x10, 0x82, 0x80, 0x80, 0x80, 0x00, 0x1A, 0x41, 0x00, 0x21, + 0x04, 0x20, 0x03, 0x41, 0x04, 0x6A, 0x41, 0x00, 0x2F, 0x00, 0x91, 0x88, + 0x80, 0x80, 0x00, 0x3B, 0x00, 0x00, 0x20, 0x03, 0x41, 0x00, 0x28, 0x00, + 0x8D, 0x88, 0x80, 0x80, 0x00, 0x36, 0x00, 0x00, 0x20, 0x02, 0x20, 0x03, + 0x36, 0x02, 0x00, 0x41, 0x93, 0x88, 0x80, 0x80, 0x00, 0x20, 0x02, 0x10, + 0x82, 0x80, 0x80, 0x80, 0x00, 0x1A, 0x20, 0x03, 0x10, 0x83, 0x80, 0x80, + 0x80, 0x00, 0x0B, 0x20, 0x02, 0x41, 0x20, 0x6A, 0x24, 0x80, 0x80, 0x80, + 0x80, 0x00, 0x20, 0x04, 0x0B, 0x0B, 0x41, 0x01, 0x00, 0x41, 0x80, 0x08, + 0x0B, 0x3A, 0x62, 0x75, 0x66, 0x20, 0x70, 0x74, 0x72, 0x3A, 0x20, 0x25, + 0x70, 0x0A, 0x00, 0x31, 0x32, 0x33, 0x34, 0x0A, 0x00, 0x62, 0x75, 0x66, + 0x3A, 0x20, 0x25, 0x73, 0x00, 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, + 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x00, 0x6D, 0x61, 0x6C, 0x6C, 0x6F, 0x63, + 0x20, 0x62, 0x75, 0x66, 0x20, 0x66, 0x61, 0x69, 0x6C, 0x65, 0x64, 0x00 +}; diff --git a/product-mini/platforms/android/wasm-jni.cpp b/product-mini/platforms/android/wasm-jni.cpp index 82722364e..294175422 100644 --- a/product-mini/platforms/android/wasm-jni.cpp +++ b/product-mini/platforms/android/wasm-jni.cpp @@ -20,56 +20,42 @@ app_instance_main(wasm_module_inst_t module_inst) { } // WARNING! CAN NOT BE READ ONLY!!! -static unsigned char wasm_test_file[] = { 0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x0D, 0x06, 0x64, 0x79, 0x6C, 0x69, 0x6E, 0x6B, 0xC0, 0x80, - 0x04, 0x04, 0x00, 0x00, 0x01, 0x13, 0x04, 0x60, 0x01, 0x7F, 0x00, 0x60, - 0x01, 0x7F, 0x01, 0x7F, 0x60, 0x02, 0x7F, 0x7F, 0x01, 0x7F, 0x60, 0x00, - 0x00, 0x02, 0x58, 0x06, 0x03, 0x65, 0x6E, 0x76, 0x05, 0x5F, 0x66, 0x72, - 0x65, 0x65, 0x00, 0x00, 0x03, 0x65, 0x6E, 0x76, 0x07, 0x5F, 0x6D, 0x61, - 0x6C, 0x6C, 0x6F, 0x63, 0x00, 0x01, 0x03, 0x65, 0x6E, 0x76, 0x07, 0x5F, - 0x70, 0x72, 0x69, 0x6E, 0x74, 0x66, 0x00, 0x02, 0x03, 0x65, 0x6E, 0x76, - 0x05, 0x5F, 0x70, 0x75, 0x74, 0x73, 0x00, 0x01, 0x03, 0x65, 0x6E, 0x76, - 0x0D, 0x5F, 0x5F, 0x6D, 0x65, 0x6D, 0x6F, 0x72, 0x79, 0x5F, 0x62, 0x61, - 0x73, 0x65, 0x03, 0x7F, 0x00, 0x03, 0x65, 0x6E, 0x76, 0x06, 0x6D, 0x65, - 0x6D, 0x6F, 0x72, 0x79, 0x02, 0x00, 0x01, 0x03, 0x04, 0x03, 0x02, 0x03, - 0x03, 0x06, 0x10, 0x03, 0x7F, 0x01, 0x41, 0x00, 0x0B, 0x7F, 0x01, 0x41, - 0x00, 0x0B, 0x7F, 0x00, 0x41, 0x1B, 0x0B, 0x07, 0x33, 0x04, 0x12, 0x5F, - 0x5F, 0x70, 0x6F, 0x73, 0x74, 0x5F, 0x69, 0x6E, 0x73, 0x74, 0x61, 0x6E, - 0x74, 0x69, 0x61, 0x74, 0x65, 0x00, 0x06, 0x05, 0x5F, 0x6D, 0x61, 0x69, - 0x6E, 0x00, 0x04, 0x0B, 0x72, 0x75, 0x6E, 0x50, 0x6F, 0x73, 0x74, 0x53, - 0x65, 0x74, 0x73, 0x00, 0x05, 0x04, 0x5F, 0x73, 0x74, 0x72, 0x03, 0x03, - 0x0A, 0xBA, 0x01, 0x03, 0x9E, 0x01, 0x01, 0x01, 0x7F, 0x23, 0x01, 0x21, - 0x00, 0x23, 0x01, 0x41, 0x10, 0x6A, 0x24, 0x01, 0x20, 0x00, 0x41, 0x08, - 0x6A, 0x21, 0x02, 0x23, 0x00, 0x41, 0x1B, 0x6A, 0x10, 0x03, 0x1A, 0x41, - 0x80, 0x08, 0x10, 0x01, 0x21, 0x01, 0x20, 0x01, 0x04, 0x7F, 0x20, 0x00, - 0x20, 0x01, 0x36, 0x02, 0x00, 0x23, 0x00, 0x20, 0x00, 0x10, 0x02, 0x1A, - 0x20, 0x01, 0x23, 0x00, 0x2C, 0x00, 0x0D, 0x3A, 0x00, 0x00, 0x20, 0x01, - 0x23, 0x00, 0x2C, 0x00, 0x0E, 0x3A, 0x00, 0x01, 0x20, 0x01, 0x23, 0x00, - 0x2C, 0x00, 0x0F, 0x3A, 0x00, 0x02, 0x20, 0x01, 0x23, 0x00, 0x2C, 0x00, - 0x10, 0x3A, 0x00, 0x03, 0x20, 0x01, 0x23, 0x00, 0x2C, 0x00, 0x11, 0x3A, - 0x00, 0x04, 0x20, 0x01, 0x23, 0x00, 0x2C, 0x00, 0x12, 0x3A, 0x00, 0x05, - 0x20, 0x02, 0x20, 0x01, 0x36, 0x02, 0x00, 0x23, 0x00, 0x41, 0x13, 0x6A, - 0x20, 0x02, 0x10, 0x02, 0x1A, 0x20, 0x01, 0x10, 0x00, 0x20, 0x00, 0x24, - 0x01, 0x41, 0x00, 0x05, 0x23, 0x00, 0x41, 0x28, 0x6A, 0x10, 0x03, 0x1A, - 0x20, 0x00, 0x24, 0x01, 0x41, 0x7F, 0x0B, 0x0B, 0x03, 0x00, 0x01, 0x0B, - 0x14, 0x00, 0x23, 0x00, 0x41, 0x40, 0x6B, 0x24, 0x01, 0x23, 0x01, 0x41, - 0x80, 0x80, 0x04, 0x6A, 0x24, 0x02, 0x10, 0x05, 0x0B, 0x0B, 0x3F, 0x01, - 0x00, 0x23, 0x00, 0x0B, 0x39, 0x62, 0x75, 0x66, 0x20, 0x70, 0x74, 0x72, - 0x3A, 0x20, 0x25, 0x70, 0x0A, 0x00, 0x31, 0x32, 0x33, 0x34, 0x0A, 0x00, - 0x62, 0x75, 0x66, 0x3A, 0x20, 0x25, 0x73, 0x00, 0x48, 0x65, 0x6C, 0x6C, - 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x00, 0x6D, 0x61, 0x6C, - 0x6C, 0x6F, 0x63, 0x20, 0x62, 0x75, 0x66, 0x20, 0x66, 0x61, 0x69, 0x6C, - 0x65, 0x64, 0x00, 0x50, 0x04, 0x6E, 0x61, 0x6D, 0x65, 0x01, 0x49, 0x07, - 0x00, 0x05, 0x5F, 0x66, 0x72, 0x65, 0x65, 0x01, 0x07, 0x5F, 0x6D, 0x61, - 0x6C, 0x6C, 0x6F, 0x63, 0x02, 0x07, 0x5F, 0x70, 0x72, 0x69, 0x6E, 0x74, - 0x66, 0x03, 0x05, 0x5F, 0x70, 0x75, 0x74, 0x73, 0x04, 0x05, 0x5F, 0x6D, - 0x61, 0x69, 0x6E, 0x05, 0x0B, 0x72, 0x75, 0x6E, 0x50, 0x6F, 0x73, 0x74, - 0x53, 0x65, 0x74, 0x73, 0x06, 0x12, 0x5F, 0x5F, 0x70, 0x6F, 0x73, 0x74, - 0x5F, 0x69, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74, 0x69, 0x61, 0x74, 0x65, - 0x00, 0x20, 0x10, 0x73, 0x6F, 0x75, 0x72, 0x63, 0x65, 0x4D, 0x61, 0x70, - 0x70, 0x69, 0x6E, 0x67, 0x55, 0x52, 0x4C, 0x0E, 0x61, 0x2E, 0x6F, 0x75, - 0x74, 0x2E, 0x77, 0x61, 0x73, 0x6D, 0x2E, 0x6D, 0x61, 0x70 }; - +static unsigned char wasm_test_file[] = { + 0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x10, 0x03, 0x60, + 0x01, 0x7F, 0x01, 0x7F, 0x60, 0x02, 0x7F, 0x7F, 0x01, 0x7F, 0x60, 0x01, + 0x7F, 0x00, 0x02, 0x31, 0x04, 0x03, 0x65, 0x6E, 0x76, 0x04, 0x70, 0x75, + 0x74, 0x73, 0x00, 0x00, 0x03, 0x65, 0x6E, 0x76, 0x06, 0x6D, 0x61, 0x6C, + 0x6C, 0x6F, 0x63, 0x00, 0x00, 0x03, 0x65, 0x6E, 0x76, 0x06, 0x70, 0x72, + 0x69, 0x6E, 0x74, 0x66, 0x00, 0x01, 0x03, 0x65, 0x6E, 0x76, 0x04, 0x66, + 0x72, 0x65, 0x65, 0x00, 0x02, 0x03, 0x02, 0x01, 0x01, 0x04, 0x05, 0x01, + 0x70, 0x01, 0x01, 0x01, 0x05, 0x03, 0x01, 0x00, 0x01, 0x06, 0x13, 0x03, + 0x7F, 0x01, 0x41, 0xC0, 0x28, 0x0B, 0x7F, 0x00, 0x41, 0xBA, 0x08, 0x0B, + 0x7F, 0x00, 0x41, 0xC0, 0x28, 0x0B, 0x07, 0x2C, 0x04, 0x06, 0x6D, 0x65, + 0x6D, 0x6F, 0x72, 0x79, 0x02, 0x00, 0x0A, 0x5F, 0x5F, 0x64, 0x61, 0x74, + 0x61, 0x5F, 0x65, 0x6E, 0x64, 0x03, 0x01, 0x0B, 0x5F, 0x5F, 0x68, 0x65, + 0x61, 0x70, 0x5F, 0x62, 0x61, 0x73, 0x65, 0x03, 0x02, 0x04, 0x6D, 0x61, + 0x69, 0x6E, 0x00, 0x04, 0x0A, 0xB2, 0x01, 0x01, 0xAF, 0x01, 0x01, 0x03, + 0x7F, 0x23, 0x80, 0x80, 0x80, 0x80, 0x00, 0x41, 0x20, 0x6B, 0x22, 0x02, + 0x24, 0x80, 0x80, 0x80, 0x80, 0x00, 0x41, 0x9B, 0x88, 0x80, 0x80, 0x00, + 0x10, 0x80, 0x80, 0x80, 0x80, 0x00, 0x1A, 0x02, 0x40, 0x02, 0x40, 0x41, + 0x80, 0x08, 0x10, 0x81, 0x80, 0x80, 0x80, 0x00, 0x22, 0x03, 0x0D, 0x00, + 0x41, 0xA8, 0x88, 0x80, 0x80, 0x00, 0x10, 0x80, 0x80, 0x80, 0x80, 0x00, + 0x1A, 0x41, 0x7F, 0x21, 0x04, 0x0C, 0x01, 0x0B, 0x20, 0x02, 0x20, 0x03, + 0x36, 0x02, 0x10, 0x41, 0x80, 0x88, 0x80, 0x80, 0x00, 0x20, 0x02, 0x41, + 0x10, 0x6A, 0x10, 0x82, 0x80, 0x80, 0x80, 0x00, 0x1A, 0x41, 0x00, 0x21, + 0x04, 0x20, 0x03, 0x41, 0x04, 0x6A, 0x41, 0x00, 0x2F, 0x00, 0x91, 0x88, + 0x80, 0x80, 0x00, 0x3B, 0x00, 0x00, 0x20, 0x03, 0x41, 0x00, 0x28, 0x00, + 0x8D, 0x88, 0x80, 0x80, 0x00, 0x36, 0x00, 0x00, 0x20, 0x02, 0x20, 0x03, + 0x36, 0x02, 0x00, 0x41, 0x93, 0x88, 0x80, 0x80, 0x00, 0x20, 0x02, 0x10, + 0x82, 0x80, 0x80, 0x80, 0x00, 0x1A, 0x20, 0x03, 0x10, 0x83, 0x80, 0x80, + 0x80, 0x00, 0x0B, 0x20, 0x02, 0x41, 0x20, 0x6A, 0x24, 0x80, 0x80, 0x80, + 0x80, 0x00, 0x20, 0x04, 0x0B, 0x0B, 0x41, 0x01, 0x00, 0x41, 0x80, 0x08, + 0x0B, 0x3A, 0x62, 0x75, 0x66, 0x20, 0x70, 0x74, 0x72, 0x3A, 0x20, 0x25, + 0x70, 0x0A, 0x00, 0x31, 0x32, 0x33, 0x34, 0x0A, 0x00, 0x62, 0x75, 0x66, + 0x3A, 0x20, 0x25, 0x73, 0x00, 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, + 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x00, 0x6D, 0x61, 0x6C, 0x6C, 0x6F, 0x63, + 0x20, 0x62, 0x75, 0x66, 0x20, 0x66, 0x61, 0x69, 0x6C, 0x65, 0x64, 0x00 +}; extern "C" JNIEXPORT void JNICALL Java_com_intel_wasm_api_Runtime_run(JNIEnv *env, jclass thiz) { diff --git a/product-mini/platforms/linux/main.c b/product-mini/platforms/linux/main.c index 1d1a828a7..7184e7ebd 100644 --- a/product-mini/platforms/linux/main.c +++ b/product-mini/platforms/linux/main.c @@ -176,11 +176,12 @@ static char global_heap_buf[10 * 1024 * 1024] = { 0 }; static char * handle_module_path(const char *module_path) { - // next character after = + /* next character after = */ return (strchr(module_path, '=')) + 1; } static char *module_search_path = "."; + static bool module_reader_callback(const char *module_name, uint8 **p_buffer, uint32 *p_size) @@ -237,8 +238,6 @@ main(int argc, char *argv[]) #endif /* Process options. */ - // TODO: use a option name and option handler pair table to - // optimize for (argc--, argv++; argc > 0 && argv[0][0] == '-'; argc--, argv++) { if (!strcmp(argv[0], "-f") || !strcmp(argv[0], "--function")) { argc--, argv++; diff --git a/product-mini/platforms/nuttx/main.c b/product-mini/platforms/nuttx/main.c index 25c654fd1..265be84d4 100644 --- a/product-mini/platforms/nuttx/main.c +++ b/product-mini/platforms/nuttx/main.c @@ -99,7 +99,7 @@ static char global_heap_buf[164 * 1024] = { 0 }; static char * handle_module_path(const char *module_path) { - // next character after = + /* next character after = */ return (strchr(module_path, '=')) + 1; } @@ -159,8 +159,6 @@ main(int argc, char *argv[]) #endif /* Process options. */ - // TODO: use a option name and option handler pair table to - // optimize for (argc--, argv++; argc > 0 && argv[0][0] == '-'; argc--, argv++) { if (!strcmp(argv[0], "-f") || !strcmp(argv[0], "--function")) { argc--, argv++; diff --git a/product-mini/platforms/windows/main.c b/product-mini/platforms/windows/main.c index bed5ee4d5..8db96b0a7 100644 --- a/product-mini/platforms/windows/main.c +++ b/product-mini/platforms/windows/main.c @@ -236,8 +236,6 @@ main(int argc, char *argv[]) #endif /* Process options. */ - // TODO: use a option name and option handler pair table to - // optimize for (argc--, argv++; argc > 0 && argv[0][0] == '-'; argc--, argv++) { if (!strcmp(argv[0], "-f") || !strcmp(argv[0], "--function")) { argc--, argv++; diff --git a/product-mini/platforms/zephyr/simple/src/test_wasm.h b/product-mini/platforms/zephyr/simple/src/test_wasm.h index 23e87b5be..a729cadef 100644 --- a/product-mini/platforms/zephyr/simple/src/test_wasm.h +++ b/product-mini/platforms/zephyr/simple/src/test_wasm.h @@ -5,55 +5,42 @@ /** * The byte array buffer is the file content of a test wasm binary file, - * which is compiled by emcc or clang toolchain from C source file of: - * core/iwasm/app-samples/hello-world/main.c. + * which is compiled by wasi-sdk toolchain from C source file of: + * product-mini/app-samples/hello-world/main.c. */ -unsigned char __aligned(4) wasm_test_file[] = { 0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x0D, 0x06, 0x64, 0x79, 0x6C, 0x69, 0x6E, 0x6B, 0xC0, 0x80, - 0x04, 0x04, 0x00, 0x00, 0x01, 0x13, 0x04, 0x60, 0x01, 0x7F, 0x00, 0x60, - 0x01, 0x7F, 0x01, 0x7F, 0x60, 0x02, 0x7F, 0x7F, 0x01, 0x7F, 0x60, 0x00, - 0x00, 0x02, 0x58, 0x06, 0x03, 0x65, 0x6E, 0x76, 0x05, 0x5F, 0x66, 0x72, - 0x65, 0x65, 0x00, 0x00, 0x03, 0x65, 0x6E, 0x76, 0x07, 0x5F, 0x6D, 0x61, - 0x6C, 0x6C, 0x6F, 0x63, 0x00, 0x01, 0x03, 0x65, 0x6E, 0x76, 0x07, 0x5F, - 0x70, 0x72, 0x69, 0x6E, 0x74, 0x66, 0x00, 0x02, 0x03, 0x65, 0x6E, 0x76, - 0x05, 0x5F, 0x70, 0x75, 0x74, 0x73, 0x00, 0x01, 0x03, 0x65, 0x6E, 0x76, - 0x0D, 0x5F, 0x5F, 0x6D, 0x65, 0x6D, 0x6F, 0x72, 0x79, 0x5F, 0x62, 0x61, - 0x73, 0x65, 0x03, 0x7F, 0x00, 0x03, 0x65, 0x6E, 0x76, 0x06, 0x6D, 0x65, - 0x6D, 0x6F, 0x72, 0x79, 0x02, 0x00, 0x01, 0x03, 0x04, 0x03, 0x02, 0x03, - 0x03, 0x06, 0x10, 0x03, 0x7F, 0x01, 0x41, 0x00, 0x0B, 0x7F, 0x01, 0x41, - 0x00, 0x0B, 0x7F, 0x00, 0x41, 0x1B, 0x0B, 0x07, 0x33, 0x04, 0x12, 0x5F, - 0x5F, 0x70, 0x6F, 0x73, 0x74, 0x5F, 0x69, 0x6E, 0x73, 0x74, 0x61, 0x6E, - 0x74, 0x69, 0x61, 0x74, 0x65, 0x00, 0x06, 0x05, 0x5F, 0x6D, 0x61, 0x69, - 0x6E, 0x00, 0x04, 0x0B, 0x72, 0x75, 0x6E, 0x50, 0x6F, 0x73, 0x74, 0x53, - 0x65, 0x74, 0x73, 0x00, 0x05, 0x04, 0x5F, 0x73, 0x74, 0x72, 0x03, 0x03, - 0x0A, 0xBA, 0x01, 0x03, 0x9E, 0x01, 0x01, 0x01, 0x7F, 0x23, 0x01, 0x21, - 0x00, 0x23, 0x01, 0x41, 0x10, 0x6A, 0x24, 0x01, 0x20, 0x00, 0x41, 0x08, - 0x6A, 0x21, 0x02, 0x23, 0x00, 0x41, 0x1B, 0x6A, 0x10, 0x03, 0x1A, 0x41, - 0x80, 0x08, 0x10, 0x01, 0x21, 0x01, 0x20, 0x01, 0x04, 0x7F, 0x20, 0x00, - 0x20, 0x01, 0x36, 0x02, 0x00, 0x23, 0x00, 0x20, 0x00, 0x10, 0x02, 0x1A, - 0x20, 0x01, 0x23, 0x00, 0x2C, 0x00, 0x0D, 0x3A, 0x00, 0x00, 0x20, 0x01, - 0x23, 0x00, 0x2C, 0x00, 0x0E, 0x3A, 0x00, 0x01, 0x20, 0x01, 0x23, 0x00, - 0x2C, 0x00, 0x0F, 0x3A, 0x00, 0x02, 0x20, 0x01, 0x23, 0x00, 0x2C, 0x00, - 0x10, 0x3A, 0x00, 0x03, 0x20, 0x01, 0x23, 0x00, 0x2C, 0x00, 0x11, 0x3A, - 0x00, 0x04, 0x20, 0x01, 0x23, 0x00, 0x2C, 0x00, 0x12, 0x3A, 0x00, 0x05, - 0x20, 0x02, 0x20, 0x01, 0x36, 0x02, 0x00, 0x23, 0x00, 0x41, 0x13, 0x6A, - 0x20, 0x02, 0x10, 0x02, 0x1A, 0x20, 0x01, 0x10, 0x00, 0x20, 0x00, 0x24, - 0x01, 0x41, 0x00, 0x05, 0x23, 0x00, 0x41, 0x28, 0x6A, 0x10, 0x03, 0x1A, - 0x20, 0x00, 0x24, 0x01, 0x41, 0x7F, 0x0B, 0x0B, 0x03, 0x00, 0x01, 0x0B, - 0x14, 0x00, 0x23, 0x00, 0x41, 0x40, 0x6B, 0x24, 0x01, 0x23, 0x01, 0x41, - 0x80, 0x80, 0x04, 0x6A, 0x24, 0x02, 0x10, 0x05, 0x0B, 0x0B, 0x3F, 0x01, - 0x00, 0x23, 0x00, 0x0B, 0x39, 0x62, 0x75, 0x66, 0x20, 0x70, 0x74, 0x72, - 0x3A, 0x20, 0x25, 0x70, 0x0A, 0x00, 0x31, 0x32, 0x33, 0x34, 0x0A, 0x00, - 0x62, 0x75, 0x66, 0x3A, 0x20, 0x25, 0x73, 0x00, 0x48, 0x65, 0x6C, 0x6C, - 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x00, 0x6D, 0x61, 0x6C, - 0x6C, 0x6F, 0x63, 0x20, 0x62, 0x75, 0x66, 0x20, 0x66, 0x61, 0x69, 0x6C, - 0x65, 0x64, 0x00, 0x50, 0x04, 0x6E, 0x61, 0x6D, 0x65, 0x01, 0x49, 0x07, - 0x00, 0x05, 0x5F, 0x66, 0x72, 0x65, 0x65, 0x01, 0x07, 0x5F, 0x6D, 0x61, - 0x6C, 0x6C, 0x6F, 0x63, 0x02, 0x07, 0x5F, 0x70, 0x72, 0x69, 0x6E, 0x74, - 0x66, 0x03, 0x05, 0x5F, 0x70, 0x75, 0x74, 0x73, 0x04, 0x05, 0x5F, 0x6D, - 0x61, 0x69, 0x6E, 0x05, 0x0B, 0x72, 0x75, 0x6E, 0x50, 0x6F, 0x73, 0x74, - 0x53, 0x65, 0x74, 0x73, 0x06, 0x12, 0x5F, 0x5F, 0x70, 0x6F, 0x73, 0x74, - 0x5F, 0x69, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74, 0x69, 0x61, 0x74, 0x65, - 0x00, 0x20, 0x10, 0x73, 0x6F, 0x75, 0x72, 0x63, 0x65, 0x4D, 0x61, 0x70, - 0x70, 0x69, 0x6E, 0x67, 0x55, 0x52, 0x4C, 0x0E, 0x61, 0x2E, 0x6F, 0x75, - 0x74, 0x2E, 0x77, 0x61, 0x73, 0x6D, 0x2E, 0x6D, 0x61, 0x70 }; +unsigned char __aligned(4) wasm_test_file[] = { + 0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x10, 0x03, 0x60, + 0x01, 0x7F, 0x01, 0x7F, 0x60, 0x02, 0x7F, 0x7F, 0x01, 0x7F, 0x60, 0x01, + 0x7F, 0x00, 0x02, 0x31, 0x04, 0x03, 0x65, 0x6E, 0x76, 0x04, 0x70, 0x75, + 0x74, 0x73, 0x00, 0x00, 0x03, 0x65, 0x6E, 0x76, 0x06, 0x6D, 0x61, 0x6C, + 0x6C, 0x6F, 0x63, 0x00, 0x00, 0x03, 0x65, 0x6E, 0x76, 0x06, 0x70, 0x72, + 0x69, 0x6E, 0x74, 0x66, 0x00, 0x01, 0x03, 0x65, 0x6E, 0x76, 0x04, 0x66, + 0x72, 0x65, 0x65, 0x00, 0x02, 0x03, 0x02, 0x01, 0x01, 0x04, 0x05, 0x01, + 0x70, 0x01, 0x01, 0x01, 0x05, 0x03, 0x01, 0x00, 0x01, 0x06, 0x13, 0x03, + 0x7F, 0x01, 0x41, 0xC0, 0x28, 0x0B, 0x7F, 0x00, 0x41, 0xBA, 0x08, 0x0B, + 0x7F, 0x00, 0x41, 0xC0, 0x28, 0x0B, 0x07, 0x2C, 0x04, 0x06, 0x6D, 0x65, + 0x6D, 0x6F, 0x72, 0x79, 0x02, 0x00, 0x0A, 0x5F, 0x5F, 0x64, 0x61, 0x74, + 0x61, 0x5F, 0x65, 0x6E, 0x64, 0x03, 0x01, 0x0B, 0x5F, 0x5F, 0x68, 0x65, + 0x61, 0x70, 0x5F, 0x62, 0x61, 0x73, 0x65, 0x03, 0x02, 0x04, 0x6D, 0x61, + 0x69, 0x6E, 0x00, 0x04, 0x0A, 0xB2, 0x01, 0x01, 0xAF, 0x01, 0x01, 0x03, + 0x7F, 0x23, 0x80, 0x80, 0x80, 0x80, 0x00, 0x41, 0x20, 0x6B, 0x22, 0x02, + 0x24, 0x80, 0x80, 0x80, 0x80, 0x00, 0x41, 0x9B, 0x88, 0x80, 0x80, 0x00, + 0x10, 0x80, 0x80, 0x80, 0x80, 0x00, 0x1A, 0x02, 0x40, 0x02, 0x40, 0x41, + 0x80, 0x08, 0x10, 0x81, 0x80, 0x80, 0x80, 0x00, 0x22, 0x03, 0x0D, 0x00, + 0x41, 0xA8, 0x88, 0x80, 0x80, 0x00, 0x10, 0x80, 0x80, 0x80, 0x80, 0x00, + 0x1A, 0x41, 0x7F, 0x21, 0x04, 0x0C, 0x01, 0x0B, 0x20, 0x02, 0x20, 0x03, + 0x36, 0x02, 0x10, 0x41, 0x80, 0x88, 0x80, 0x80, 0x00, 0x20, 0x02, 0x41, + 0x10, 0x6A, 0x10, 0x82, 0x80, 0x80, 0x80, 0x00, 0x1A, 0x41, 0x00, 0x21, + 0x04, 0x20, 0x03, 0x41, 0x04, 0x6A, 0x41, 0x00, 0x2F, 0x00, 0x91, 0x88, + 0x80, 0x80, 0x00, 0x3B, 0x00, 0x00, 0x20, 0x03, 0x41, 0x00, 0x28, 0x00, + 0x8D, 0x88, 0x80, 0x80, 0x00, 0x36, 0x00, 0x00, 0x20, 0x02, 0x20, 0x03, + 0x36, 0x02, 0x00, 0x41, 0x93, 0x88, 0x80, 0x80, 0x00, 0x20, 0x02, 0x10, + 0x82, 0x80, 0x80, 0x80, 0x00, 0x1A, 0x20, 0x03, 0x10, 0x83, 0x80, 0x80, + 0x80, 0x00, 0x0B, 0x20, 0x02, 0x41, 0x20, 0x6A, 0x24, 0x80, 0x80, 0x80, + 0x80, 0x00, 0x20, 0x04, 0x0B, 0x0B, 0x41, 0x01, 0x00, 0x41, 0x80, 0x08, + 0x0B, 0x3A, 0x62, 0x75, 0x66, 0x20, 0x70, 0x74, 0x72, 0x3A, 0x20, 0x25, + 0x70, 0x0A, 0x00, 0x31, 0x32, 0x33, 0x34, 0x0A, 0x00, 0x62, 0x75, 0x66, + 0x3A, 0x20, 0x25, 0x73, 0x00, 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, + 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x00, 0x6D, 0x61, 0x6C, 0x6C, 0x6F, 0x63, + 0x20, 0x62, 0x75, 0x66, 0x20, 0x66, 0x61, 0x69, 0x6C, 0x65, 0x64, 0x00 +}; From b9f195ce910c797318ed30c11f5bd07e63b0056a Mon Sep 17 00:00:00 2001 From: Huang Qi <757509347@qq.com> Date: Sun, 20 Sep 2020 08:33:08 +0800 Subject: [PATCH 076/207] Introduce CI support (#391) Co-authored-by: Huang Qi --- .github/workflows/linux.yml | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 .github/workflows/linux.yml diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml new file mode 100644 index 000000000..6dc2b1fdb --- /dev/null +++ b/.github/workflows/linux.yml @@ -0,0 +1,36 @@ +name: Linux + +# Controls when the action will run. Triggers the workflow on push or pull request +# events but only for the master branch +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + + build: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-18.04, ubuntu-20.04] + steps: + - uses: actions/checkout@v2 + + - name: Build iwasm + run: | + cd product-mini/platforms/linux + mkdir build && cd build + cmake .. + make + + - name: Build wasm-c-api + run: | + cd samples/wasm-c-api + mkdir build && cd build + cmake .. + make + ./hello + ./global + ./callback From 21850aeb0a8a30d01575d9c4d0a8307a73a7d1e3 Mon Sep 17 00:00:00 2001 From: Xu Jun <693788454@qq.com> Date: Sun, 20 Sep 2020 13:16:13 +0800 Subject: [PATCH 077/207] add more build option and samples in CI (#394) * Update linux.yml * Create mac.yml --- .github/workflows/linux.yml | 80 +++++++++++++++++++++++++++++++++++-- .github/workflows/mac.yml | 78 ++++++++++++++++++++++++++++++++++++ 2 files changed, 155 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/mac.yml diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 6dc2b1fdb..1f941b68c 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -18,14 +18,62 @@ jobs: steps: - uses: actions/checkout@v2 - - name: Build iwasm + - name: Build iwasm [default] run: | cd product-mini/platforms/linux mkdir build && cd build cmake .. make - - - name: Build wasm-c-api + cd .. && rm -rf build + - name: Build iwasm [Classic interp] + run: | + cd product-mini/platforms/linux + mkdir build && cd build + cmake .. -DWAMR_BUILD_FAST_INTERP=0 + make + cd .. && rm -rf build + - name: Build iwasm [Multi module] + run: | + cd product-mini/platforms/linux + mkdir build && cd build + cmake .. -DWAMR_BUILD_MULTI_MODULE=1 + make + cd .. && rm -rf build + - name: Build iwasm [lib-pthread] + run: | + cd product-mini/platforms/linux + mkdir build && cd build + cmake .. -DWAMR_BUILD_LIB_PTHREAD=1 + make + cd .. && rm -rf build + - name: Build iwasm [aot only] + run: | + cd product-mini/platforms/linux + mkdir build && cd build + cmake .. -DWAMR_BUILD_AOT=1 -DWAMR_BUILD_INTERP=0 + make + cd .. && rm -rf build + - name: Build iwasm [interp only] + run: | + cd product-mini/platforms/linux + mkdir build && cd build + cmake .. -DWAMR_BUILD_AOT=0 + make + cd .. && rm -rf build + - name: Build iwasm [memory profiling] + run: | + cd product-mini/platforms/linux + mkdir build && cd build + cmake .. -DWAMR_BUILD_MEMORY_PROFILING=1 + make + cd .. && rm -rf build + - name: download wasi-sdk + run: | + cd /opt + wget https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-8/wasi-sdk-8.0-linux.tar.gz + tar -xzf wasi-sdk-8.0-linux.tar.gz + mv wasi-sdk-8.0 wasi-sdk + - name: Build Sample [wasm-c-api] run: | cd samples/wasm-c-api mkdir build && cd build @@ -34,3 +82,29 @@ jobs: ./hello ./global ./callback + - name: Build Sample [basic] + run: | + cd samples/basic + ./build.sh + ./run.sh + - name: Build Sample [multi-thread] + run: | + cd samples/multi-thread + mkdir build && cd build + cmake .. + make + ./iwasm wasm-apps/test.wasm + - name: Build Sample [multi-module] + run: | + cd samples/multi-module + mkdir build && cd build + cmake .. + make + ./multi_module + - name: Build Sample [spawn-thread] + run: | + cd samples/spawn-thread + mkdir build && cd build + cmake .. + make + ./spawn_thread diff --git a/.github/workflows/mac.yml b/.github/workflows/mac.yml new file mode 100644 index 000000000..134f4c1ed --- /dev/null +++ b/.github/workflows/mac.yml @@ -0,0 +1,78 @@ +name: Mac + +# Controls when the action will run. Triggers the workflow on push or pull request +# events but only for the master branch +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + + build: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [macos-latest] + steps: + - uses: actions/checkout@v2 + + - name: Build iwasm [default] + run: | + cd product-mini/platforms/darwin + mkdir build && cd build + cmake .. + make + cd .. && rm -rf build + - name: Build iwasm [Classic interp] + run: | + cd product-mini/platforms/darwin + mkdir build && cd build + cmake .. -DWAMR_BUILD_FAST_INTERP=0 + make + cd .. && rm -rf build + - name: Build iwasm [Multi module] + run: | + cd product-mini/platforms/darwin + mkdir build && cd build + cmake .. -DWAMR_BUILD_MULTI_MODULE=1 + make + cd .. && rm -rf build + - name: Build iwasm [lib-pthread] + run: | + cd product-mini/platforms/darwin + mkdir build && cd build + cmake .. -DWAMR_BUILD_LIB_PTHREAD=1 + make + cd .. && rm -rf build + - name: Build iwasm [aot only] + run: | + cd product-mini/platforms/darwin + mkdir build && cd build + cmake .. -DWAMR_BUILD_AOT=1 -DWAMR_BUILD_INTERP=0 + make + cd .. && rm -rf build + - name: Build iwasm [interp only] + run: | + cd product-mini/platforms/darwin + mkdir build && cd build + cmake .. -DWAMR_BUILD_AOT=0 + make + cd .. && rm -rf build + - name: Build iwasm [memory profiling] + run: | + cd product-mini/platforms/darwin + mkdir build && cd build + cmake .. -DWAMR_BUILD_MEMORY_PROFILING=1 + make + cd .. && rm -rf build + - name: Build Sample [wasm-c-api] + run: | + cd samples/wasm-c-api + mkdir build && cd build + cmake .. + make + ./hello + ./global + ./callback From dc4b8c482241ebaad3535cd6c5b91c26be5fdf82 Mon Sep 17 00:00:00 2001 From: Xu Jun <693788454@qq.com> Date: Wed, 23 Sep 2020 11:50:37 +0800 Subject: [PATCH 078/207] remove errno in wasm_application_execute_func (#396) --- .github/workflows/linux.yml | 5 ++++- .github/workflows/mac.yml | 5 ++++- core/iwasm/common/wasm_runtime_common.c | 9 --------- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 1f941b68c..fcb3a2ebf 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -1,7 +1,10 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + name: Linux # Controls when the action will run. Triggers the workflow on push or pull request -# events but only for the master branch +# events but only for the main branch on: push: branches: [ main ] diff --git a/.github/workflows/mac.yml b/.github/workflows/mac.yml index 134f4c1ed..f81e46f62 100644 --- a/.github/workflows/mac.yml +++ b/.github/workflows/mac.yml @@ -1,7 +1,10 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + name: Mac # Controls when the action will run. Triggers the workflow on push or pull request -# events but only for the master branch +# events but only for the main branch on: push: branches: [ main ] diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index 6c50fa2cb..abd2d752a 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -2369,9 +2369,6 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, goto fail; } - /* Clear errno before parsing arguments */ - errno = 0; - /* Parse arguments */ for (i = 0, p = 0; i < argc; i++) { char *endptr = NULL; @@ -2462,12 +2459,6 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, wasm_runtime_set_exception(module_inst, buf); goto fail; } - if (errno != 0) { - snprintf(buf, sizeof(buf), - "prepare function argument error, errno: %d", errno); - wasm_runtime_set_exception(module_inst, buf); - goto fail; - } } bh_assert(p == (int32)argc1); From d8d367b3671e6557a391fe2650adb8c490d03f7e Mon Sep 17 00:00:00 2001 From: "jmpews(AKA.zz)" Date: Wed, 23 Sep 2020 13:10:26 +0800 Subject: [PATCH 079/207] Update some assembler directives for darwin target (#395) --- core/iwasm/common/arch/invokeNative_aarch64.s | 11 ++++++++--- core/iwasm/common/arch/invokeNative_arm.s | 11 ++++++++--- core/iwasm/common/arch/invokeNative_arm_vfp.s | 11 ++++++++--- core/iwasm/common/arch/invokeNative_thumb.s | 11 ++++++++--- core/iwasm/common/arch/invokeNative_thumb_vfp.s | 11 ++++++++--- 5 files changed, 40 insertions(+), 15 deletions(-) diff --git a/core/iwasm/common/arch/invokeNative_aarch64.s b/core/iwasm/common/arch/invokeNative_aarch64.s index 68390cb54..33b6b5bc2 100644 --- a/core/iwasm/common/arch/invokeNative_aarch64.s +++ b/core/iwasm/common/arch/invokeNative_aarch64.s @@ -4,8 +4,14 @@ */ .text .align 2 - .global invokeNative - .type invokeNative,function +#ifndef BH_PLATFORM_DARWIN + .globl invokeNative + .type invokeNative, @function +invokeNative: +#else + .globl _invokeNative +_invokeNative: +#endif /* end of BH_PLATFORM_DARWIN */ /* * Arguments passed in: @@ -15,7 +21,6 @@ * x2 nstacks */ -invokeNative: sub sp, sp, #0x30 stp x19, x20, [sp, #0x20] /* save the registers */ stp x21, x22, [sp, #0x10] diff --git a/core/iwasm/common/arch/invokeNative_arm.s b/core/iwasm/common/arch/invokeNative_arm.s index 72318315f..d494c2bbb 100644 --- a/core/iwasm/common/arch/invokeNative_arm.s +++ b/core/iwasm/common/arch/invokeNative_arm.s @@ -4,8 +4,14 @@ */ .text .align 2 - .global invokeNative - .type invokeNative,function +#ifndef BH_PLATFORM_DARWIN + .globl invokeNative + .type invokeNative, @function +invokeNative: +#else + .globl _invokeNative +_invokeNative: +#endif /* end of BH_PLATFORM_DARWIN */ /* * Arguments passed in: @@ -15,7 +21,6 @@ * r2 argc */ -invokeNative: stmfd sp!, {r4, r5, r6, r7, lr} sub sp, sp, #4 /* make sp 8 byte aligned */ mov ip, r0 /* ip = function ptr */ diff --git a/core/iwasm/common/arch/invokeNative_arm_vfp.s b/core/iwasm/common/arch/invokeNative_arm_vfp.s index 679fdedf1..8b1fe91ab 100644 --- a/core/iwasm/common/arch/invokeNative_arm_vfp.s +++ b/core/iwasm/common/arch/invokeNative_arm_vfp.s @@ -4,8 +4,14 @@ */ .text .align 2 - .global invokeNative - .type invokeNative,function +#ifndef BH_PLATFORM_DARWIN + .globl invokeNative + .type invokeNative, @function +invokeNative: +#else + .globl _invokeNative +_invokeNative: +#endif /* end of BH_PLATFORM_DARWIN */ /* * Arguments passed in: @@ -15,7 +21,6 @@ * r2 nstacks */ -invokeNative: stmfd sp!, {r4, r5, r6, r7, lr} mov ip, r0 /* ip = function ptr */ mov r4, r1 /* r4 = argv */ diff --git a/core/iwasm/common/arch/invokeNative_thumb.s b/core/iwasm/common/arch/invokeNative_thumb.s index 571c6a262..50f162210 100644 --- a/core/iwasm/common/arch/invokeNative_thumb.s +++ b/core/iwasm/common/arch/invokeNative_thumb.s @@ -4,8 +4,14 @@ */ .text .align 2 - .global invokeNative - .type invokeNative,function +#ifndef BH_PLATFORM_DARWIN + .globl invokeNative + .type invokeNative, @function +invokeNative: +#else + .globl _invokeNative +_invokeNative: +#endif /* end of BH_PLATFORM_DARWIN */ /* * Arguments passed in: @@ -15,7 +21,6 @@ * r2 argc */ -invokeNative: push {r4, r5, r6, r7} push {lr} mov ip, r0 /* ip = function ptr */ diff --git a/core/iwasm/common/arch/invokeNative_thumb_vfp.s b/core/iwasm/common/arch/invokeNative_thumb_vfp.s index faab2139f..89abf032d 100644 --- a/core/iwasm/common/arch/invokeNative_thumb_vfp.s +++ b/core/iwasm/common/arch/invokeNative_thumb_vfp.s @@ -4,8 +4,14 @@ */ .text .align 2 - .global invokeNative - .type invokeNative,function +#ifndef BH_PLATFORM_DARWIN + .globl invokeNative + .type invokeNative, @function +invokeNative: +#else + .globl _invokeNative +_invokeNative: +#endif /* end of BH_PLATFORM_DARWIN */ /* * Arguments passed in: @@ -15,7 +21,6 @@ * r2 nstacks */ -invokeNative: push {r4, r5, r6, r7} push {lr} mov ip, r0 /* ip = function ptr */ From a290aaf93e153b0f7ee40af0f073f173bc561aeb Mon Sep 17 00:00:00 2001 From: Huang Qi <757509347@qq.com> Date: Wed, 23 Sep 2020 15:54:22 +0800 Subject: [PATCH 080/207] Fix wasm loader malloc(0) issue which returns NULL is some platforms (#397) Signed-off-by: Huang Qi Co-authored-by: Huang Qi --- core/iwasm/interpreter/wasm_loader.c | 10 ++++++++-- core/iwasm/interpreter/wasm_mini_loader.c | 5 +++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index f1da1b11d..ccd7fbdb1 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -1691,8 +1691,14 @@ init_function_local_offsets(WASMFunction *func, uint32 i, local_offset = 0; uint64 total_size = sizeof(uint16) * ((uint64)param_count + local_count); - if (!(func->local_offsets = - loader_malloc(total_size, error_buf, error_buf_size))) { + /* + * Only allocate memory when total_size is not 0, + * or the return value of malloc(0) might be NULL on some platforms, + * which causes wasm loader return false. + */ + if (total_size > 0 + && !(func->local_offsets = + loader_malloc(total_size, error_buf, error_buf_size))) { return false; } diff --git a/core/iwasm/interpreter/wasm_mini_loader.c b/core/iwasm/interpreter/wasm_mini_loader.c index 0d83c2dcd..030d93833 100644 --- a/core/iwasm/interpreter/wasm_mini_loader.c +++ b/core/iwasm/interpreter/wasm_mini_loader.c @@ -853,8 +853,9 @@ init_function_local_offsets(WASMFunction *func, uint32 i, local_offset = 0; uint64 total_size = sizeof(uint16) * ((uint64)param_count + local_count); - if (!(func->local_offsets = - loader_malloc(total_size, error_buf, error_buf_size))) { + if (total_size > 0 + && !(func->local_offsets = + loader_malloc(total_size, error_buf, error_buf_size))) { return false; } From a7e7711f639a423527216ced797c95fd6a54f380 Mon Sep 17 00:00:00 2001 From: Xiaokang Qin Date: Wed, 23 Sep 2020 16:12:09 +0800 Subject: [PATCH 081/207] Add the support for custom name section (#398) Add the function name field for internal function struct Signed-off-by: Zhongmin Wu Signed-off-by: Xiaokang Qin Co-authored-by: Zhongmin Wu --- build-scripts/config_common.cmake | 4 + core/iwasm/interpreter/wasm.h | 7 ++ core/iwasm/interpreter/wasm_loader.c | 99 +++++++++++++++++++++++ core/iwasm/interpreter/wasm_mini_loader.c | 74 +++++++++++++++++ doc/build_wamr.md | 4 + 5 files changed, 188 insertions(+) diff --git a/build-scripts/config_common.cmake b/build-scripts/config_common.cmake index 9d441b2a0..2e2750bb4 100644 --- a/build-scripts/config_common.cmake +++ b/build-scripts/config_common.cmake @@ -169,4 +169,8 @@ endif () if (DEFINED WAMR_APP_THREAD_STACK_SIZE_MAX) add_definitions (-DAPP_THREAD_STACK_SIZE_MAX=${WAMR_APP_THREAD_STACK_SIZE_MAX}) endif () +if (WAMR_BUILD_CUSTOM_NAME_SECTION EQUAL 1) + add_definitions (-DWASM_ENABLE_CUSTOM_NAME_SECTION=1) + message (" Custom name section enabled") +endif () diff --git a/core/iwasm/interpreter/wasm.h b/core/iwasm/interpreter/wasm.h index 1fb99baec..f45464e0c 100644 --- a/core/iwasm/interpreter/wasm.h +++ b/core/iwasm/interpreter/wasm.h @@ -56,6 +56,10 @@ extern "C" { #define SECTION_TYPE_DATACOUNT 12 #endif +#define SUB_SECTION_TYPE_MODULE 0 +#define SUB_SECTION_TYPE_FUNC 1 +#define SUB_SECTION_TYPE_LOCAL 2 + #define IMPORT_KIND_FUNC 0 #define IMPORT_KIND_TABLE 1 #define IMPORT_KIND_MEMORY 2 @@ -196,6 +200,9 @@ typedef struct WASMImport { } WASMImport; struct WASMFunction { +#if WASM_ENABLE_CUSTOM_NAME_SECTION != 0 + char *field_name; +#endif /* the type of function */ WASMType *func_type; uint32 local_count; diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index ccd7fbdb1..e99f04e8a 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -2392,6 +2392,99 @@ fail: return false; } +#if WASM_ENABLE_CUSTOM_NAME_SECTION != 0 +static bool +handle_name_section(const uint8 *buf, const uint8 *buf_end,Ø + WASMModule *module, + char *error_buf, uint32 error_buf_size) +{ + const uint8 *p = buf, *p_end = buf_end; + uint32 name_type, subsection_size; + uint32 previous_name_type = 0; + uint32 num_func_name; + uint32 func_index; + uint32 previous_func_index = ~0U; + uint32 func_name_len; + uint32 name_index; + int i = 0; + + if (p >= p_end) { + set_error_buf(error_buf, error_buf_size, "unexpected end"); + return false; + } + + while (p < p_end) { + read_leb_uint32(p, p_end, name_type); + if (i != 0) { + if (name_type == previous_name_type) { + set_error_buf(error_buf, error_buf_size, + "duplicate sub-section"); + return false; + } + if (name_type < previous_name_type) { + set_error_buf(error_buf, error_buf_size, + "out-of-order sub-section"); + return false; + } + } + previous_name_type = name_type; + read_leb_uint32(p, p_end, subsection_size); + CHECK_BUF(p, p_end, subsection_size); + switch (name_type) { + case SUB_SECTION_TYPE_FUNC: + if (subsection_size) { + read_leb_uint32(p, p_end, num_func_name); + for (name_index = 0; name_index < num_func_name; + name_index++) { + read_leb_uint32(p, p_end, func_index); + if (func_index == previous_func_index) { + set_error_buf(error_buf, error_buf_size, + "duplicate function name"); + return false; + } + if (func_index < previous_func_index + && previous_func_index != ~0U) { + set_error_buf(error_buf, error_buf_size, + "out-of-order function index "); + return false; + } + previous_func_index = func_index; + read_leb_uint32(p, p_end, func_name_len); + CHECK_BUF(p, p_end, func_name_len); + // Skip the import functions + if (func_index >= module->import_count) { + func_index -= module->import_count; + if (func_index >= module->function_count) { + set_error_buf(error_buf, error_buf_size, + "out-of-range function index"); + return false; + } + if (!(module->functions[func_index]->field_name = + const_str_list_insert(p, func_name_len, + module, error_buf, + error_buf_size))) { + return false; + } + } + p += func_name_len; + } + } + break; + case SUB_SECTION_TYPE_MODULE: /* TODO: Parse for module subsection */ + case SUB_SECTION_TYPE_LOCAL: /* TODO: Parse for local subsection */ + default: + p = p + subsection_size; + break; + } + i++; + } + + return true; +fail: + return false; +} +#endif + static bool load_user_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, char *error_buf, uint32 error_buf_size) @@ -2418,6 +2511,12 @@ load_user_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, return false; } +#if WASM_ENABLE_CUSTOM_NAME_SECTION != 0 + if (memcmp(p, "name", 4) == 0) { + p += name_len; + handle_name_section(p, p_end, module, error_buf, error_buf_size); + } +#endif LOG_VERBOSE("Load custom section success.\n"); return true; fail: diff --git a/core/iwasm/interpreter/wasm_mini_loader.c b/core/iwasm/interpreter/wasm_mini_loader.c index 030d93833..499db1245 100644 --- a/core/iwasm/interpreter/wasm_mini_loader.c +++ b/core/iwasm/interpreter/wasm_mini_loader.c @@ -1408,6 +1408,73 @@ load_start_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, return true; } +#if WASM_ENABLE_CUSTOM_NAME_SECTION != 0 +static bool +handle_name_section(const uint8 *buf, const uint8 *buf_end, + WASMModule *module, + char *error_buf, uint32 error_buf_size) +{ + const uint8 *p = buf, *p_end = buf_end; + uint32 name_type, subsection_size; + uint32 previous_name_type = 0; + uint32 num_func_name; + uint32 func_index; + uint32 previous_func_index = ~0U; + uint32 func_name_len; + uint32 name_index; + int i = 0; + + bh_assert(p < p_end); + + while (p < p_end) { + read_leb_uint32(p, p_end, name_type); + if (i != 0) { + bh_assert(name_type > previous_name_type); + } + previous_name_type = name_type; + read_leb_uint32(p, p_end, subsection_size); + CHECK_BUF(p, p_end, subsection_size); + switch (name_type) { + case SUB_SECTION_TYPE_FUNC: + if (subsection_size) { + read_leb_uint32(p, p_end, num_func_name); + for (name_index = 0; name_index < num_func_name; + name_index++) { + read_leb_uint32(p, p_end, func_index); + bh_assert(func_index > previous_func_index); + previous_func_index = func_index; + read_leb_uint32(p, p_end, func_name_len); + CHECK_BUF(p, p_end, func_name_len); + // Skip the import functions + if (func_index >= module->import_count) { + func_index -= module->import_count; + bh_assert(func_index < module->function_count); + if (!(module->functions[func_index]->field_name = + const_str_list_insert(p, func_name_len, + module, error_buf, + error_buf_size))) { + return false; + } + } + p += func_name_len; + } + } + break; + case SUB_SECTION_TYPE_MODULE: /* TODO: Parse for module subsection */ + case SUB_SECTION_TYPE_LOCAL: /* TODO: Parse for local subsection */ + default: + p = p + subsection_size; + break; + } + i++; + } + + return true; +fail: + return false; +} +#endif + static bool load_user_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, char *error_buf, uint32 error_buf_size) @@ -1421,6 +1488,13 @@ load_user_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, bh_assert(name_len > 0 && p + name_len <= p_end); + +#if WASM_ENABLE_CUSTOM_NAME_SECTION != 0 + if (memcmp(p, "name", 4) == 0) { + p += name_len; + handle_name_section(p, p_end, module, error_buf, error_buf_size); + } +#endif LOG_VERBOSE("Load custom section success.\n"); (void)name_len; return true; diff --git a/doc/build_wamr.md b/doc/build_wamr.md index 7397e2097..08c0930e6 100644 --- a/doc/build_wamr.md +++ b/doc/build_wamr.md @@ -44,6 +44,10 @@ cmake -DWAMR_BUILD_PLATFORM=linux -DWAMR_BUILD_TARGET=ARM - **WAMR_BUILD_LIBC_WASI**=1/0, default to enable if not set +#### **Configure Debug** + +- **WAMR_BUILD_CUSTOM_NAME_SECTION**=1/0, load the function name from custom name section, default to disable if not set + #### **Enable Multi-Module feature** - **WAMR_BUILD_MULTI_MODULE**=1/0, default to disable if not set From b639c3ce61a68aef8e75c5becf9d2877c05d0a12 Mon Sep 17 00:00:00 2001 From: Huang Qi <757509347@qq.com> Date: Thu, 24 Sep 2020 10:48:34 +0800 Subject: [PATCH 082/207] Use macro instead of enum to define MEM_ALLOCATOR for better compatibility (#399) Co-authored-by: Huang Qi --- core/config.h | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/core/config.h b/core/config.h index 1c932a652..26aa715a2 100644 --- a/core/config.h +++ b/core/config.h @@ -43,12 +43,8 @@ #define BH_DEBUG 0 #endif -enum { - /* Memory allocator ems */ - MEM_ALLOCATOR_EMS = 0, - /* Memory allocator tlsf */ - MEM_ALLOCATOR_TLSF -}; +#define MEM_ALLOCATOR_EMS 0 +#define MEM_ALLOCATOR_TLSF 1 /* Default memory allocator */ #define DEFAULT_MEM_ALLOCATOR MEM_ALLOCATOR_EMS From a3d374eb57d57e9ae1ae6e9e16613490c63100c6 Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Thu, 24 Sep 2020 11:21:20 +0800 Subject: [PATCH 083/207] Fix jit target arch not set issue and custom name section typo issue (#400) And set target machine's cpu to host cpu when creating JIT execution engine. Signed-off-by: Wenyong Huang wenyong.huang@intel.com --- core/iwasm/compilation/aot_llvm.c | 23 +++- core/iwasm/compilation/aot_llvm_extra.cpp | 147 ++++++++++++++++++++++ core/iwasm/compilation/iwasm_compl.cmake | 4 +- core/iwasm/interpreter/wasm_loader.c | 2 +- 4 files changed, 172 insertions(+), 4 deletions(-) create mode 100644 core/iwasm/compilation/aot_llvm_extra.cpp diff --git a/core/iwasm/compilation/aot_llvm.c b/core/iwasm/compilation/aot_llvm.c index cb024e5f9..6dea84524 100644 --- a/core/iwasm/compilation/aot_llvm.c +++ b/core/iwasm/compilation/aot_llvm.c @@ -997,6 +997,13 @@ get_target_arch_from_triple(const char *triple, char *arch_buf, uint32 buf_size) bh_assert(*triple == '-' || *triple == '\0'); } +LLVMBool +WAMRCreateMCJITCompilerForModule(LLVMExecutionEngineRef *OutJIT, + LLVMModuleRef M, + struct LLVMMCJITCompilerOptions *Options, + size_t SizeOfOptions, + char **OutError); + void LLVMAddPromoteMemoryToRegisterPass(LLVMPassManagerRef PM); AOTCompContext * @@ -1007,7 +1014,8 @@ aot_create_comp_context(AOTCompData *comp_data, /*LLVMTypeRef elem_types[8];*/ struct LLVMMCJITCompilerOptions jit_options; LLVMTargetRef target; - char *triple = NULL, *triple_norm, *arch, *abi, *cpu, *features, buf[128]; + char *triple = NULL, *triple_jit = NULL, *triple_norm, *arch, *abi; + char *cpu = NULL, *features, buf[128]; char *triple_norm_new = NULL, *cpu_new = NULL; char *err = NULL, *fp_round= "round.tonearest", *fp_exce = "fpexcept.strict"; char triple_buf[32] = {0}; @@ -1060,7 +1068,7 @@ aot_create_comp_context(AOTCompData *comp_data, jit_options.OptLevel = LLVMCodeGenLevelAggressive; jit_options.EnableFastISel = true; /*jit_options.CodeModel = LLVMCodeModelSmall;*/ - if (LLVMCreateMCJITCompilerForModule + if (WAMRCreateMCJITCompilerForModule (&comp_ctx->exec_engine, comp_ctx->module, &jit_options, sizeof(jit_options), &err) != 0) { if (err) { @@ -1078,6 +1086,17 @@ aot_create_comp_context(AOTCompData *comp_data, #else comp_ctx->enable_bound_check = false; #endif + + if (!(triple_jit = + LLVMGetTargetMachineTriple(comp_ctx->target_machine))) { + aot_set_last_error("can not get triple from the target machine"); + goto fail; + } + + /* Save target arch */ + get_target_arch_from_triple(triple_jit, comp_ctx->target_arch, + sizeof(comp_ctx->target_arch)); + LLVMDisposeMessage(triple_jit); } else { /* Create LLVM target machine */ diff --git a/core/iwasm/compilation/aot_llvm_extra.cpp b/core/iwasm/compilation/aot_llvm_extra.cpp new file mode 100644 index 000000000..895f29049 --- /dev/null +++ b/core/iwasm/compilation/aot_llvm_extra.cpp @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace llvm; + +extern "C" LLVMBool +WAMRCreateMCJITCompilerForModule(LLVMExecutionEngineRef *OutJIT, + LLVMModuleRef M, + LLVMMCJITCompilerOptions *PassedOptions, + size_t SizeOfPassedOptions, + char **OutError); + +extern "C" bool +aot_check_simd_compatibility(const char *arch_c_str, const char *cpu_c_str); + +LLVMBool +WAMRCreateMCJITCompilerForModule(LLVMExecutionEngineRef *OutJIT, + LLVMModuleRef M, + LLVMMCJITCompilerOptions *PassedOptions, + size_t SizeOfPassedOptions, + char **OutError) +{ + LLVMMCJITCompilerOptions options; + // If the user passed a larger sized options struct, then they were compiled + // against a newer LLVM. Tell them that something is wrong. + if (SizeOfPassedOptions > sizeof(options)) { + *OutError = strdup( + "Refusing to use options struct that is larger than my own; assuming " + "LLVM library mismatch."); + return 1; + } + + // Defend against the user having an old version of the API by ensuring that + // any fields they didn't see are cleared. We must defend against fields being + // set to the bitwise equivalent of zero, and assume that this means "do the + // default" as if that option hadn't been available. + LLVMInitializeMCJITCompilerOptions(&options, sizeof(options)); + memcpy(&options, PassedOptions, SizeOfPassedOptions); + + TargetOptions targetOptions; + targetOptions.EnableFastISel = options.EnableFastISel; + std::unique_ptr Mod(unwrap(M)); + + if (Mod) { + // Set function attribute "frame-pointer" based on + // NoFramePointerElim. + for (auto &F : *Mod) { + auto Attrs = F.getAttributes(); + StringRef Value = options.NoFramePointerElim ? "all" : "none"; + Attrs = Attrs.addAttribute(F.getContext(), AttributeList::FunctionIndex, + "frame-pointer", Value); + F.setAttributes(Attrs); + } + } + + std::string Error; + bool JIT; + char *host_cpu = LLVMGetHostCPUName(); + + if (!host_cpu) { + *OutError = NULL; + return false; + } + + std::string mcpu(host_cpu); + LLVMDisposeMessage(host_cpu); + + EngineBuilder builder(std::move(Mod)); + builder.setEngineKind(EngineKind::JIT) + .setErrorStr(&Error) + .setMCPU(mcpu) + .setOptLevel((CodeGenOpt::Level)options.OptLevel) + .setTargetOptions(targetOptions); + if (Optional CM = unwrap(options.CodeModel, JIT)) + builder.setCodeModel(*CM); + if (options.MCJMM) + builder.setMCJITMemoryManager( + std::unique_ptr(unwrap(options.MCJMM))); + if (ExecutionEngine *JIT = builder.create()) { + *OutJIT = wrap(JIT); + return 0; + } + *OutError = strdup(Error.c_str()); + return 1; +} + +bool +aot_check_simd_compatibility(const char *arch_c_str, const char *cpu_c_str) +{ +#if WASM_ENABLE_SIMD != 0 + if (!arch_c_str || !cpu_c_str) { + return false; + } + + llvm::SmallVector targetAttributes; + llvm::Triple targetTriple(arch_c_str, "", ""); + llvm::TargetMachine *targetMachine = llvm::EngineBuilder().selectTarget( + targetTriple, "", std::string(cpu_c_str), targetAttributes); + if (targetMachine == nullptr) { + return false; + } + + const llvm::Triple::ArchType targetArch = + targetMachine->getTargetTriple().getArch(); + const llvm::MCSubtargetInfo *subTargetInfo = + targetMachine->getMCSubtargetInfo(); + if (subTargetInfo == nullptr) { + return false; + } + + if (targetArch == llvm::Triple::x86_64) { + return subTargetInfo->checkFeatures("+sse4.1"); + } + else if (targetArch == llvm::Triple::aarch64) { + return subTargetInfo->checkFeatures("+neon"); + } + else { + return false; + } +#else + (void)arch_c_str; + (void)cpu_c_str; + return true; +#endif /* WASM_ENABLE_SIMD */ +} + diff --git a/core/iwasm/compilation/iwasm_compl.cmake b/core/iwasm/compilation/iwasm_compl.cmake index 36efd335e..09b3b9ecc 100644 --- a/core/iwasm/compilation/iwasm_compl.cmake +++ b/core/iwasm/compilation/iwasm_compl.cmake @@ -2,7 +2,9 @@ set (IWASM_COMPL_DIR ${CMAKE_CURRENT_LIST_DIR}) include_directories(${IWASM_COMPL_DIR}) -file (GLOB_RECURSE source_all ${IWASM_COMPL_DIR}/*.c) +file (GLOB_RECURSE source_all + ${IWASM_COMPL_DIR}/*.c + ${IWASM_COMPL_DIR}/*.cpp) set (IWASM_COMPL_SOURCE ${source_all}) diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index e99f04e8a..ac8d15500 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -2394,7 +2394,7 @@ fail: #if WASM_ENABLE_CUSTOM_NAME_SECTION != 0 static bool -handle_name_section(const uint8 *buf, const uint8 *buf_end,Ø +handle_name_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, char *error_buf, uint32 error_buf_size) { From a70daed17d08a0c407f518614043166de26dc360 Mon Sep 17 00:00:00 2001 From: Xiaokang Qin Date: Thu, 24 Sep 2020 12:38:54 +0800 Subject: [PATCH 084/207] Add the tail-call feature support for classic-interp (#401) * Add the tail-call feature support for classic-interp Signed-off-by: Xiaokang Qin * add CI for tail call and custom name section * add CI for tail call and custom name section * update CI for mac Co-authored-by: Xu Jun <693788454@qq.com> --- .github/workflows/linux.yml | 14 +++ .github/workflows/mac.yml | 14 +++ build-scripts/config_common.cmake | 4 + core/config.h | 4 + core/iwasm/interpreter/wasm_interp_classic.c | 44 ++++++++- core/iwasm/interpreter/wasm_interp_fast.c | 4 +- core/iwasm/interpreter/wasm_loader.c | 95 +++++++++++++++++--- core/iwasm/interpreter/wasm_mini_loader.c | 63 ++++++++++--- core/iwasm/interpreter/wasm_opcode.h | 8 +- 9 files changed, 213 insertions(+), 37 deletions(-) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index fcb3a2ebf..128af62e8 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -70,6 +70,20 @@ jobs: cmake .. -DWAMR_BUILD_MEMORY_PROFILING=1 make cd .. && rm -rf build + - name: Build iwasm [tail call] + run: | + cd product-mini/platforms/linux + mkdir build && cd build + cmake .. -DWAMR_BUILD_TAIL_CALL=1 + make + cd .. && rm -rf build + - name: Build iwasm [custom name section] + run: | + cd product-mini/platforms/linux + mkdir build && cd build + cmake .. -DWAMR_BUILD_CUSTOM_NAME_SECTION=1 + make + cd .. && rm -rf build - name: download wasi-sdk run: | cd /opt diff --git a/.github/workflows/mac.yml b/.github/workflows/mac.yml index f81e46f62..361a9c2e4 100644 --- a/.github/workflows/mac.yml +++ b/.github/workflows/mac.yml @@ -70,6 +70,20 @@ jobs: cmake .. -DWAMR_BUILD_MEMORY_PROFILING=1 make cd .. && rm -rf build + - name: Build iwasm [tail call] + run: | + cd product-mini/platforms/darwin + mkdir build && cd build + cmake .. -DWAMR_BUILD_TAIL_CALL=1 + make + cd .. && rm -rf build + - name: Build iwasm [custom name section] + run: | + cd product-mini/platforms/darwin + mkdir build && cd build + cmake .. -DWAMR_BUILD_CUSTOM_NAME_SECTION=1 + make + cd .. && rm -rf build - name: Build Sample [wasm-c-api] run: | cd samples/wasm-c-api diff --git a/build-scripts/config_common.cmake b/build-scripts/config_common.cmake index 2e2750bb4..8ac8e4de6 100644 --- a/build-scripts/config_common.cmake +++ b/build-scripts/config_common.cmake @@ -173,4 +173,8 @@ if (WAMR_BUILD_CUSTOM_NAME_SECTION EQUAL 1) add_definitions (-DWASM_ENABLE_CUSTOM_NAME_SECTION=1) message (" Custom name section enabled") endif () +if (WAMR_BUILD_TAIL_CALL EQUAL 1) + add_definitions (-DWASM_ENABLE_TAIL_CALL=1) + message (" Tail call enabled") +endif () diff --git a/core/config.h b/core/config.h index 26aa715a2..d21396aa9 100644 --- a/core/config.h +++ b/core/config.h @@ -244,5 +244,9 @@ wasm_runtime_set_max_thread_num */ #define CLUSTER_MAX_THREAD_NUM 4 +#ifndef WASM_ENABLE_TAIL_CALL +#define WASM_ENABLE_TAIL_CALL 0 +#endif + #endif /* end of _CONFIG_H_ */ diff --git a/core/iwasm/interpreter/wasm_interp_classic.c b/core/iwasm/interpreter/wasm_interp_classic.c index ec0aca844..a241f19be 100644 --- a/core/iwasm/interpreter/wasm_interp_classic.c +++ b/core/iwasm/interpreter/wasm_interp_classic.c @@ -1285,11 +1285,33 @@ label_pop_csp_n: cur_func = module->functions + fidx; goto call_func_from_interp; +#if WASM_ENABLE_TAIL_CALL != 0 + HANDLE_OP (WASM_OP_RETURN_CALL): +#if WASM_ENABLE_THREAD_MGR != 0 + CHECK_SUSPEND_FLAGS(); +#endif + read_leb_uint32(frame_ip, frame_ip_end, fidx); +#if WASM_ENABLE_MULTI_MODULE != 0 + if (fidx >= module->function_count) { + wasm_set_exception(module, "unknown function"); + goto got_exception; + } +#endif + cur_func = module->functions + fidx; + + goto call_func_from_return_call; +#endif /* WASM_ENABLE_TAIL_CALL */ + HANDLE_OP (WASM_OP_CALL_INDIRECT): +#if WASM_ENABLE_TAIL_CALL != 0 + HANDLE_OP (WASM_OP_RETURN_CALL_INDIRECT): +#endif { WASMType *cur_type, *cur_func_type; WASMTableInstance *cur_table_inst; - +#if WASM_ENABLE_TAIL_CALL != 0 + opcode = *(frame_ip - 1); +#endif #if WASM_ENABLE_THREAD_MGR != 0 CHECK_SUSPEND_FLAGS(); #endif @@ -1352,7 +1374,10 @@ label_pop_csp_n: wasm_set_exception(module, "indirect call type mismatch"); goto got_exception; } - +#if WASM_ENABLE_TAIL_CALL != 0 + if (opcode == WASM_OP_RETURN_CALL_INDIRECT) + goto call_func_from_return_call; +#endif goto call_func_from_interp; } @@ -3121,8 +3146,10 @@ label_pop_csp_n: HANDLE_OP (WASM_OP_UNUSED_0x08): HANDLE_OP (WASM_OP_UNUSED_0x09): HANDLE_OP (WASM_OP_UNUSED_0x0a): - HANDLE_OP (WASM_OP_UNUSED_0x12): - HANDLE_OP (WASM_OP_UNUSED_0x13): +#if WASM_ENABLE_TAIL_CALL == 0 + HANDLE_OP (WASM_OP_RETURN_CALL): + HANDLE_OP (WASM_OP_RETURN_CALL_INDIRECT): +#endif HANDLE_OP (WASM_OP_UNUSED_0x14): HANDLE_OP (WASM_OP_UNUSED_0x15): HANDLE_OP (WASM_OP_UNUSED_0x16): @@ -3151,6 +3178,15 @@ label_pop_csp_n: FETCH_OPCODE_AND_DISPATCH (); #endif +#if WASM_ENABLE_TAIL_CALL != 0 + call_func_from_return_call: + POP(cur_func->param_cell_num); + word_copy(frame->lp, frame_sp, cur_func->param_cell_num); + FREE_FRAME(exec_env, frame); + wasm_exec_env_set_cur_frame(exec_env, + (WASMRuntimeFrame *)prev_frame); + goto call_func_from_entry; +#endif call_func_from_interp: /* Only do the copy when it's called from interpreter. */ { diff --git a/core/iwasm/interpreter/wasm_interp_fast.c b/core/iwasm/interpreter/wasm_interp_fast.c index 2a6262deb..c36567f6f 100644 --- a/core/iwasm/interpreter/wasm_interp_fast.c +++ b/core/iwasm/interpreter/wasm_interp_fast.c @@ -3125,8 +3125,8 @@ recover_br_info: HANDLE_OP (WASM_OP_UNUSED_0x08): HANDLE_OP (WASM_OP_UNUSED_0x09): HANDLE_OP (WASM_OP_UNUSED_0x0a): - HANDLE_OP (WASM_OP_UNUSED_0x12): - HANDLE_OP (WASM_OP_UNUSED_0x13): + HANDLE_OP (WASM_OP_RETURN_CALL): + HANDLE_OP (WASM_OP_RETURN_CALL_INDIRECT): HANDLE_OP (WASM_OP_UNUSED_0x14): HANDLE_OP (WASM_OP_UNUSED_0x15): HANDLE_OP (WASM_OP_UNUSED_0x16): diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index ac8d15500..483b46071 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -3307,10 +3307,16 @@ wasm_loader_find_block_addr(BlockAddr *block_addr_cache, break; case WASM_OP_CALL: +#if WASM_ENABLE_TAIL_CALL != 0 + case WASM_OP_RETURN_CALL: +#endif skip_leb_uint32(p, p_end); /* funcidx */ break; case WASM_OP_CALL_INDIRECT: +#if WASM_ENABLE_TAIL_CALL != 0 + case WASM_OP_RETURN_CALL_INDIRECT: +#endif skip_leb_uint32(p, p_end); /* typeidx */ CHECK_BUF(p, p_end, 1); u8 = read_uint8(p); /* 0x00 */ @@ -5812,6 +5818,9 @@ handle_op_block_and_loop: } case WASM_OP_CALL: +#if WASM_ENABLE_TAIL_CALL != 0 + case WASM_OP_RETURN_CALL: +#endif { WASMType *func_type; uint32 func_idx; @@ -5844,22 +5853,53 @@ handle_op_block_and_loop: } } - for (i = 0; i < func_type->result_count; i++) { - PUSH_TYPE(func_type->types[func_type->param_count + i]); -#if WASM_ENABLE_FAST_INTERP != 0 - /* Here we emit each return value's dynamic_offset. But in fact - * these offsets are continuous, so interpreter only need to get - * the first return value's offset. - */ - PUSH_OFFSET_TYPE(func_type->types[func_type->param_count + i]); +#if WASM_ENABLE_TAIL_CALL != 0 + if (opcode == WASM_OP_CALL) { #endif + for (i = 0; i < func_type->result_count; i++) { + PUSH_TYPE(func_type->types[func_type->param_count + i]); +#if WASM_ENABLE_FAST_INTERP != 0 + /* Here we emit each return value's dynamic_offset. But in fact + * these offsets are continuous, so interpreter only need to get + * the first return value's offset. + */ + PUSH_OFFSET_TYPE(func_type->types[func_type->param_count + i]); +#endif + } +#if WASM_ENABLE_TAIL_CALL != 0 } - + else { + char *type_str[] = { "f64", "f32", "i64", "i32" }; + uint8 type; + if (func_type->result_count != func->func_type->result_count) { + set_error_buf_v(error_buf, error_buf_size, + "%s%u%s", "type mismatch: expect ", + func->func_type->result_count, + " return values but got other"); + goto fail; + } + for (i = 0; i < func_type->result_count; i++) { + type = func->func_type->types[func->func_type->param_count + i]; + if (func_type->types[func_type->param_count + i] != type) { + set_error_buf_v(error_buf, error_buf_size, + "%s%s%s", "type mismatch: expect ", + type_str[type - VALUE_TYPE_F64], + " but got other"); + goto fail; + } + } + RESET_STACK(); + SET_CUR_BLOCK_STACK_POLYMORPHIC_STATE(true); + } +#endif func->has_op_func_call = true; break; } case WASM_OP_CALL_INDIRECT: +#if WASM_ENABLE_TAIL_CALL != 0 + case WASM_OP_RETURN_CALL_INDIRECT: +#endif { int32 idx; WASMType *func_type; @@ -5904,13 +5944,40 @@ handle_op_block_and_loop: } } - for (i = 0; i < func_type->result_count; i++) { - PUSH_TYPE(func_type->types[func_type->param_count + i]); -#if WASM_ENABLE_FAST_INTERP != 0 - PUSH_OFFSET_TYPE(func_type->types[func_type->param_count + i]); +#if WASM_ENABLE_TAIL_CALL != 0 + if (opcode == WASM_OP_CALL_INDIRECT) { #endif + for (i = 0; i < func_type->result_count; i++) { + PUSH_TYPE(func_type->types[func_type->param_count + i]); +#if WASM_ENABLE_FAST_INTERP != 0 + PUSH_OFFSET_TYPE(func_type->types[func_type->param_count + i]); +#endif + } +#if WASM_ENABLE_TAIL_CALL != 0 } - + else { + char *type_str[] = { "f64", "f32", "i64", "i32" }; + uint8 type; + if (func_type->result_count != func->func_type->result_count) { + set_error_buf_v(error_buf, error_buf_size, + "%s%u%s", "type mismatch: expect ", + func->func_type->result_count, + " return values but got other"); + goto fail; + } + for (i = 0; i < func_type->result_count; i++) { + type = func->func_type->types[func->func_type->param_count + i]; + if (func_type->types[func_type->param_count + i] != type) + set_error_buf_v(error_buf, error_buf_size, "%s%s%s", + "type mismatch: expect ", + type_str[type - VALUE_TYPE_F64], + " but got other"); + goto fail; + } + RESET_STACK(); + SET_CUR_BLOCK_STACK_POLYMORPHIC_STATE(true); + } +#endif func->has_op_func_call = true; break; } diff --git a/core/iwasm/interpreter/wasm_mini_loader.c b/core/iwasm/interpreter/wasm_mini_loader.c index 499db1245..5bfff5771 100644 --- a/core/iwasm/interpreter/wasm_mini_loader.c +++ b/core/iwasm/interpreter/wasm_mini_loader.c @@ -2235,10 +2235,16 @@ wasm_loader_find_block_addr(BlockAddr *block_addr_cache, break; case WASM_OP_CALL: +#if WASM_ENABLE_TAIL_CALL != 0 + case WASM_OP_RETURN_CALL: +#endif skip_leb_uint32(p, p_end); /* funcidx */ break; case WASM_OP_CALL_INDIRECT: +#if WASM_ENABLE_TAIL_CALL != 0 + case WASM_OP_RETURN_CALL_INDIRECT: +#endif skip_leb_uint32(p, p_end); /* typeidx */ CHECK_BUF(p, p_end, 1); u8 = read_uint8(p); /* 0x00 */ @@ -4612,6 +4618,9 @@ handle_op_block_and_loop: } case WASM_OP_CALL: +#if WASM_ENABLE_TAIL_CALL != 0 + case WASM_OP_RETURN_CALL: +#endif { WASMType *func_type; uint32 func_idx; @@ -4641,22 +4650,37 @@ handle_op_block_and_loop: } } - for (i = 0; i < func_type->result_count; i++) { - PUSH_TYPE(func_type->types[func_type->param_count + i]); -#if WASM_ENABLE_FAST_INTERP != 0 - /* Here we emit each return value's dynamic_offset. But in fact - * these offsets are continuous, so interpreter only need to get - * the first return value's offset. - */ - PUSH_OFFSET_TYPE(func_type->types[func_type->param_count + i]); +#if WASM_ENABLE_TAIL_CALL != 0 + if (opcode == WASM_OP_CALL) { #endif + for (i = 0; i < func_type->result_count; i++) { + PUSH_TYPE(func_type->types[func_type->param_count + i]); +#if WASM_ENABLE_FAST_INTERP != 0 + /* Here we emit each return value's dynamic_offset. But in fact + * these offsets are continuous, so interpreter only need to get + * the first return value's offset. + */ + PUSH_OFFSET_TYPE(func_type->types[func_type->param_count + i]); +#endif + } +#if WASM_ENABLE_TAIL_CALL != 0 } - + else { + bh_assert(func_type->result_count == func->func_type->result_count); + for (i = 0; i < func_type->result_count; i++) { + bh_assert(func_type->types[func_type->param_count + i] == + func->func_type->types[func->func_type->param_count + i]); + } + } +#endif func->has_op_func_call = true; break; } case WASM_OP_CALL_INDIRECT: +#if WASM_ENABLE_TAIL_CALL != 0 + case WASM_OP_RETURN_CALL_INDIRECT: +#endif { int32 idx; WASMType *func_type; @@ -4690,12 +4714,25 @@ handle_op_block_and_loop: } } - for (i = 0; i < func_type->result_count; i++) { - PUSH_TYPE(func_type->types[func_type->param_count + i]); -#if WASM_ENABLE_FAST_INTERP != 0 - PUSH_OFFSET_TYPE(func_type->types[func_type->param_count + i]); +#if WASM_ENABLE_TAIL_CALL != 0 + if (opcode == WASM_OP_CALL) { #endif + for (i = 0; i < func_type->result_count; i++) { + PUSH_TYPE(func_type->types[func_type->param_count + i]); +#if WASM_ENABLE_FAST_INTERP != 0 + PUSH_OFFSET_TYPE(func_type->types[func_type->param_count + i]); +#endif + } +#if WASM_ENABLE_TAIL_CALL != 0 } + else { + bh_assert(func_type->result_count == func->func_type->result_count); + for (i = 0; i < func_type->result_count; i++) { + bh_assert(func_type->types[func_type->param_count + i] == + func->func_type->types[func->func_type->param_count + i]); + } + } +#endif func->has_op_func_call = true; break; diff --git a/core/iwasm/interpreter/wasm_opcode.h b/core/iwasm/interpreter/wasm_opcode.h index f546088b5..65c1dbf7e 100644 --- a/core/iwasm/interpreter/wasm_opcode.h +++ b/core/iwasm/interpreter/wasm_opcode.h @@ -34,9 +34,9 @@ typedef enum WASMOpcode { WASM_OP_RETURN = 0x0f, /* return */ WASM_OP_CALL = 0x10, /* call */ WASM_OP_CALL_INDIRECT = 0x11, /* call_indirect */ + WASM_OP_RETURN_CALL = 0x12, /* return_call */ + WASM_OP_RETURN_CALL_INDIRECT = 0x13, /* return_call_indirect */ - WASM_OP_UNUSED_0x12 = 0x12, - WASM_OP_UNUSED_0x13 = 0x13, WASM_OP_UNUSED_0x14 = 0x14, WASM_OP_UNUSED_0x15 = 0x15, WASM_OP_UNUSED_0x16 = 0x16, @@ -403,8 +403,8 @@ static type _name[WASM_INSTRUCTION_NUM] = { \ HANDLE_OPCODE (WASM_OP_RETURN), /* 0x0f */ \ HANDLE_OPCODE (WASM_OP_CALL), /* 0x10 */ \ HANDLE_OPCODE (WASM_OP_CALL_INDIRECT), /* 0x11 */ \ - HANDLE_OPCODE (WASM_OP_UNUSED_0x12), /* 0x12 */ \ - HANDLE_OPCODE (WASM_OP_UNUSED_0x13), /* 0x13 */ \ + HANDLE_OPCODE (WASM_OP_RETURN_CALL), /* 0x12 */ \ + HANDLE_OPCODE (WASM_OP_RETURN_CALL_INDIRECT), /* 0x13 */ \ HANDLE_OPCODE (WASM_OP_UNUSED_0x14), /* 0x14 */ \ HANDLE_OPCODE (WASM_OP_UNUSED_0x15), /* 0x15 */ \ HANDLE_OPCODE (WASM_OP_UNUSED_0x16), /* 0x16 */ \ From c59bfe24fbde6679f408299606126f39491c8b95 Mon Sep 17 00:00:00 2001 From: Huang Qi <757509347@qq.com> Date: Thu, 24 Sep 2020 14:36:21 +0800 Subject: [PATCH 085/207] platforms/nuttx: Use symbol from NuttX to configure build (#402) Signed-off-by: Huang Qi Co-authored-by: Huang Qi --- product-mini/platforms/nuttx/wamr.mk | 33 ++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/product-mini/platforms/nuttx/wamr.mk b/product-mini/platforms/nuttx/wamr.mk index 56fadfae3..53e03836d 100644 --- a/product-mini/platforms/nuttx/wamr.mk +++ b/product-mini/platforms/nuttx/wamr.mk @@ -70,7 +70,7 @@ CFLAGS += -DWASM_ENABLE_AOT=0 endif CFLAGS += -DWASM_ENABLE_INTERP=1 -CSRCS += wasm_runtime.c wasm_loader.c +CSRCS += wasm_runtime.c ifeq (${CONFIG_INTERPRETERS_WAMR_FAST},y) CFLAGS += -DWASM_ENABLE_FAST_INTERP=1 @@ -85,9 +85,38 @@ else CFLAGS += -DWASM_ENABLE_LIBC_BUILTIN=0 endif +ifeq ($(CONFIG_INTERPRETERS_WAMR_MULTI_MODULE),y) +CFLAGS += -DWASM_ENABLE_MULTI_MODULE=1 +else CFLAGS += -DWASM_ENABLE_MULTI_MODULE=0 +endif + +ifeq ($(CONFIG_INTERPRETERS_WAMR_THREAD_MGR),y) +CFLAGS += -DWASM_ENABLE_THREAD_MGR=1 +CSRCS += thread_manager.c +VPATH += ${IWASM_ROOT}/libraries/thread-mgr +else CFLAGS += -DWASM_ENABLE_THREAD_MGR=0 -CFLAGS += -Wno-strict-prototypes +endif + +ifeq ($(CONFIG_INTERPRETERS_WAMR_MINILOADER),y) +CFLAGS += -DWASM_ENABLE_MINI_LOADER=1 +CSRCS += wasm_mini_loader.c +else +CFLAGS += -DWASM_ENABLE_MINI_LOADER=0 +CSRCS += wasm_loader.c +endif + +ifeq ($(CONFIG_INTERPRETERS_WAMR_DISABLE_HW_BOUND_CHECK),y) +CFLAGS += -DWASM_DISABLE_HW_BOUND_CHECK=1 +else +CFLAGS += -DWASM_DISABLE_HW_BOUND_CHECK=0 +endif + +CFLAGS += -DBH_ENABLE_MEMORY_PROFILING=0 + +CFLAGS += -Wno-strict-prototypes -Wno-shadow -Wno-unused-variable +CFLAGS += -Wno-int-conversion -Wno-implicit-function-declaration CFLAGS += -I${CORE_ROOT} \ -I${IWASM_ROOT}/include \ From 4bfcbc2cab36267262c9c7d71c8e23f95f2334ba Mon Sep 17 00:00:00 2001 From: Xu Jun <693788454@qq.com> Date: Sun, 27 Sep 2020 18:05:20 +0800 Subject: [PATCH 086/207] fix problem about local in fast-interp (#406) --- core/iwasm/interpreter/wasm_loader.c | 64 +++++++++++++++++++++-- core/iwasm/interpreter/wasm_mini_loader.c | 64 +++++++++++++++++++++-- wamr-compiler/CMakeLists.txt | 2 + 3 files changed, 122 insertions(+), 8 deletions(-) diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index 483b46071..20e204042 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -4273,24 +4273,30 @@ preserve_referenced_local(WASMLoaderContext *loader_ctx, uint8 opcode, uint32 local_index, uint32 local_type, bool *preserved, char *error_buf, uint32 error_buf_size) { + uint32 i = 0; int16 preserved_offset = (int16)local_index; + *preserved = false; - for (uint32 i = 0; i < loader_ctx->stack_cell_num; i++) { + while (i < loader_ctx->stack_cell_num) { + uint8 cur_type = loader_ctx->frame_ref_bottom[i]; + /* move previous local into dynamic space before a set/tee_local opcode */ if (loader_ctx->frame_offset_bottom[i] == (int16)local_index) { - if (preserved_offset == (int16)local_index) { + if (!(*preserved)) { *preserved = true; skip_label(); + preserved_offset = loader_ctx->preserved_local_offset; + if (loader_ctx->p_code_compiled) { + bh_assert(preserved_offset != (int16)local_index); + } if (local_type == VALUE_TYPE_I32 || local_type == VALUE_TYPE_F32) { - preserved_offset = loader_ctx->preserved_local_offset; /* Only increase preserve offset in the second traversal */ if (loader_ctx->p_code_compiled) loader_ctx->preserved_local_offset++; emit_label(EXT_OP_COPY_STACK_TOP); } else { - preserved_offset = loader_ctx->preserved_local_offset; if (loader_ctx->p_code_compiled) loader_ctx->preserved_local_offset += 2; emit_label(EXT_OP_COPY_STACK_TOP_I64); @@ -4301,6 +4307,11 @@ preserve_referenced_local(WASMLoaderContext *loader_ctx, uint8 opcode, } loader_ctx->frame_offset_bottom[i] = preserved_offset; } + + if (cur_type == VALUE_TYPE_I32 || cur_type == VALUE_TYPE_F32) + i++; + else + i += 2; } return true; @@ -4311,6 +4322,38 @@ fail: #endif } +static bool +preserve_local_for_block(WASMLoaderContext *loader_ctx, uint8 opcode, + char *error_buf, uint32 error_buf_size) +{ + uint32 i = 0; + bool preserve_local; + + /* preserve locals before blocks to ensure that "tee/set_local" inside + blocks will not influence the value of these locals */ + while (i < loader_ctx->stack_cell_num) { + int16 cur_offset = loader_ctx->frame_offset_bottom[i]; + uint8 cur_type = loader_ctx->frame_ref_bottom[i]; + + if ((cur_offset < loader_ctx->start_dynamic_offset) + && (cur_offset >= 0)) { + if (!(preserve_referenced_local(loader_ctx, opcode, cur_offset, + cur_type, &preserve_local, + error_buf, error_buf_size))) + return false; + } + + if (cur_type == VALUE_TYPE_I32 || cur_type == VALUE_TYPE_F32) { + i++; + } + else { + i += 2; + } + } + + return true; +} + static bool add_label_patch_to_list(BranchBlock *frame_csp, uint8 patch_type, uint8 *p_code_compiled, @@ -5387,6 +5430,13 @@ fail: #define BLOCK_HAS_PARAM(block_type) \ (!block_type.is_value_type && block_type.u.type->param_count > 0) +#define PRESERVE_LOCAL_FOR_BLOCK() do { \ + if (!(preserve_local_for_block(loader_ctx, opcode, \ + error_buf, error_buf_size))) { \ + goto fail; \ + } \ +} while (0) + static bool wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, BlockAddr *block_addr_cache, @@ -5475,10 +5525,16 @@ re_scan: break; case WASM_OP_IF: +#if WASM_ENABLE_FAST_INTERP != 0 + PRESERVE_LOCAL_FOR_BLOCK(); +#endif POP_I32(); goto handle_op_block_and_loop; case WASM_OP_BLOCK: case WASM_OP_LOOP: +#if WASM_ENABLE_FAST_INTERP != 0 + PRESERVE_LOCAL_FOR_BLOCK(); +#endif handle_op_block_and_loop: { uint8 value_type; diff --git a/core/iwasm/interpreter/wasm_mini_loader.c b/core/iwasm/interpreter/wasm_mini_loader.c index 5bfff5771..c358dab45 100644 --- a/core/iwasm/interpreter/wasm_mini_loader.c +++ b/core/iwasm/interpreter/wasm_mini_loader.c @@ -3172,24 +3172,30 @@ preserve_referenced_local(WASMLoaderContext *loader_ctx, uint8 opcode, uint32 local_index, uint32 local_type, bool *preserved, char *error_buf, uint32 error_buf_size) { + uint32 i = 0; int16 preserved_offset = (int16)local_index; + *preserved = false; - for (uint32 i = 0; i < loader_ctx->stack_cell_num; i++) { + while (i < loader_ctx->stack_cell_num) { + uint8 cur_type = loader_ctx->frame_ref_bottom[i]; + /* move previous local into dynamic space before a set/tee_local opcode */ if (loader_ctx->frame_offset_bottom[i] == (int16)local_index) { - if (preserved_offset == (int16)local_index) { + if (!(*preserved)) { *preserved = true; skip_label(); + preserved_offset = loader_ctx->preserved_local_offset; + if (loader_ctx->p_code_compiled) { + bh_assert(preserved_offset != (int16)local_index); + } if (local_type == VALUE_TYPE_I32 || local_type == VALUE_TYPE_F32) { - preserved_offset = loader_ctx->preserved_local_offset; /* Only increase preserve offset in the second traversal */ if (loader_ctx->p_code_compiled) loader_ctx->preserved_local_offset++; emit_label(EXT_OP_COPY_STACK_TOP); } else { - preserved_offset = loader_ctx->preserved_local_offset; if (loader_ctx->p_code_compiled) loader_ctx->preserved_local_offset += 2; emit_label(EXT_OP_COPY_STACK_TOP_I64); @@ -3200,6 +3206,11 @@ preserve_referenced_local(WASMLoaderContext *loader_ctx, uint8 opcode, } loader_ctx->frame_offset_bottom[i] = preserved_offset; } + + if (cur_type == VALUE_TYPE_I32 || cur_type == VALUE_TYPE_F32) + i++; + else + i += 2; } return true; @@ -3210,6 +3221,38 @@ fail: #endif } +static bool +preserve_local_for_block(WASMLoaderContext *loader_ctx, uint8 opcode, + char *error_buf, uint32 error_buf_size) +{ + uint32 i = 0; + bool preserve_local; + + /* preserve locals before blocks to ensure that "tee/set_local" inside + blocks will not influence the value of these locals */ + while (i < loader_ctx->stack_cell_num) { + int16 cur_offset = loader_ctx->frame_offset_bottom[i]; + uint8 cur_type = loader_ctx->frame_ref_bottom[i]; + + if ((cur_offset < loader_ctx->start_dynamic_offset) + && (cur_offset >= 0)) { + if (!(preserve_referenced_local(loader_ctx, opcode, cur_offset, + cur_type, &preserve_local, + error_buf, error_buf_size))) + return false; + } + + if (cur_type == VALUE_TYPE_I32 || cur_type == VALUE_TYPE_F32) { + i++; + } + else { + i += 2; + } + } + + return true; +} + static bool add_label_patch_to_list(BranchBlock *frame_csp, uint8 patch_type, uint8 *p_code_compiled, @@ -4218,6 +4261,13 @@ fail: #define BLOCK_HAS_PARAM(block_type) \ (!block_type.is_value_type && block_type.u.type->param_count > 0) +#define PRESERVE_LOCAL_FOR_BLOCK() do { \ + if (!(preserve_local_for_block(loader_ctx, opcode, \ + error_buf, error_buf_size))) { \ + goto fail; \ + } \ +} while (0) + static bool wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, BlockAddr *block_addr_cache, @@ -4306,10 +4356,16 @@ re_scan: break; case WASM_OP_IF: +#if WASM_ENABLE_FAST_INTERP != 0 + PRESERVE_LOCAL_FOR_BLOCK(); +#endif POP_I32(); goto handle_op_block_and_loop; case WASM_OP_BLOCK: case WASM_OP_LOOP: +#if WASM_ENABLE_FAST_INTERP != 0 + PRESERVE_LOCAL_FOR_BLOCK(); +#endif handle_op_block_and_loop: { uint8 value_type; diff --git a/wamr-compiler/CMakeLists.txt b/wamr-compiler/CMakeLists.txt index 2d82452db..8de6f65d5 100644 --- a/wamr-compiler/CMakeLists.txt +++ b/wamr-compiler/CMakeLists.txt @@ -10,6 +10,8 @@ else() enable_language (ASM_MASM) endif() +set (CMAKE_CXX_STANDARD 14) + if (NOT DEFINED WAMR_BUILD_PLATFORM) set (WAMR_BUILD_PLATFORM "linux") endif() From 0bf7f7310b644210a0885dc9ef91d7ec6af85ef3 Mon Sep 17 00:00:00 2001 From: Huang Qi <757509347@qq.com> Date: Mon, 28 Sep 2020 12:44:23 +0800 Subject: [PATCH 087/207] Add NULL check for memory inst in aot/wasm module malloc/free (#403) * Add NULL check for memory page in aot/wasm module malloc/free Signed-off-by: Huang Qi * Update aot_runtime.c * Update wasm_runtime.c Co-authored-by: Huang Qi Co-authored-by: Wenyong Huang --- core/iwasm/aot/aot_runtime.c | 9 +++++++++ core/iwasm/interpreter/wasm_runtime.c | 13 ++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index ad5c438ba..668d03645 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -1280,6 +1280,11 @@ aot_module_malloc(AOTModuleInstance *module_inst, uint32 size, uint8 *addr = NULL; uint32 offset = 0; + if (!memory_inst) { + aot_set_exception(module_inst, "uninitialized memory"); + return 0; + } + if (memory_inst->heap_handle.ptr) { addr = mem_allocator_malloc(memory_inst->heap_handle.ptr, size); } @@ -1313,6 +1318,10 @@ aot_module_free(AOTModuleInstance *module_inst, uint32 ptr) AOTMemoryInstance *memory_inst = aot_get_default_memory(module_inst); AOTModule *module = (AOTModule *)module_inst->aot_module.ptr; + if (!memory_inst) { + return; + } + if (ptr) { uint8 *addr = (uint8 *)memory_inst->memory_data.ptr + ptr; if (memory_inst->heap_handle.ptr diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index edea3fae0..4610065d1 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -1575,6 +1575,11 @@ wasm_module_malloc(WASMModuleInstance *module_inst, uint32 size, uint8 *addr = NULL; uint32 offset = 0; + if (!memory) { + wasm_set_exception(module_inst, "uninitialized memory"); + return 0; + } + if (memory->heap_handle) { addr = mem_allocator_malloc(memory->heap_handle, size); } @@ -1606,7 +1611,13 @@ wasm_module_free(WASMModuleInstance *module_inst, uint32 ptr) { if (ptr) { WASMMemoryInstance *memory = module_inst->default_memory; - uint8 *addr = memory->memory_data + ptr; + uint8* addr; + + if (!memory) { + return; + } + + addr = memory->memory_data + ptr; if (memory->heap_handle && memory->heap_data <= addr From c13746c22ce0dbfae32a5408c41145984e52031d Mon Sep 17 00:00:00 2001 From: Xu Jun <693788454@qq.com> Date: Mon, 28 Sep 2020 18:38:15 +0800 Subject: [PATCH 088/207] move memory_data out from MemoryInstance, add call stack (#408) --- core/iwasm/interpreter/wasm_interp.h | 5 + core/iwasm/interpreter/wasm_interp_classic.c | 3 + core/iwasm/interpreter/wasm_interp_fast.c | 5 + core/iwasm/interpreter/wasm_runtime.c | 111 +++++++++++++------ core/iwasm/interpreter/wasm_runtime.h | 2 +- doc/build_wamr.md | 2 + 6 files changed, 91 insertions(+), 37 deletions(-) diff --git a/core/iwasm/interpreter/wasm_interp.h b/core/iwasm/interpreter/wasm_interp.h index c3c2c1b34..5f8672498 100644 --- a/core/iwasm/interpreter/wasm_interp.h +++ b/core/iwasm/interpreter/wasm_interp.h @@ -74,6 +74,11 @@ wasm_interp_call_wasm(struct WASMModuleInstance *module_inst, struct WASMFunctionInstance *function, uint32 argc, uint32 argv[]); +#if WASM_ENABLE_CUSTOM_NAME_SECTION != 0 +void +wasm_interp_dump_call_stack(struct WASMExecEnv *exec_env); +#endif + #ifdef __cplusplus } #endif diff --git a/core/iwasm/interpreter/wasm_interp_classic.c b/core/iwasm/interpreter/wasm_interp_classic.c index a241f19be..e18235d8b 100644 --- a/core/iwasm/interpreter/wasm_interp_classic.c +++ b/core/iwasm/interpreter/wasm_interp_classic.c @@ -3379,6 +3379,9 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, } } else { +#if WASM_ENABLE_CUSTOM_NAME_SECTION != 0 + wasm_interp_dump_call_stack(exec_env); +#endif LOG_DEBUG("meet an exception %s", wasm_get_exception(module_inst)); } diff --git a/core/iwasm/interpreter/wasm_interp_fast.c b/core/iwasm/interpreter/wasm_interp_fast.c index c36567f6f..bbb39a381 100644 --- a/core/iwasm/interpreter/wasm_interp_fast.c +++ b/core/iwasm/interpreter/wasm_interp_fast.c @@ -3382,6 +3382,11 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, for (i = 0; i < function->ret_cell_num; i++) argv[i] = *(frame->lp + i); } + else { +#if WASM_ENABLE_CUSTOM_NAME_SECTION != 0 + wasm_interp_dump_call_stack(exec_env); +#endif + } wasm_exec_env_set_cur_frame(exec_env, prev_frame); FREE_FRAME(exec_env, frame); diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index 4610065d1..8a1e66fc3 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -85,7 +85,7 @@ memories_deinstantiate(WASMModuleInstance *module_inst, { uint32 i; if (memories) { - for (i = 0; i < count; i++) + for (i = 0; i < count; i++) { if (memories[i]) { #if WASM_ENABLE_MULTI_MODULE != 0 if (memories[i]->owner != module_inst) @@ -109,8 +109,10 @@ memories_deinstantiate(WASMModuleInstance *module_inst, mem_allocator_destroy(memories[i]->heap_handle); memories[i]->heap_handle = NULL; } + wasm_runtime_free(memories[i]->memory_data); wasm_runtime_free(memories[i]); } + } wasm_runtime_free(memories); } (void)module_inst; @@ -125,7 +127,7 @@ memory_instantiate(WASMModuleInstance *module_inst, { WASMModule *module = module_inst->module; WASMMemoryInstance *memory; - uint64 total_size, memory_data_size; + uint64 memory_data_size; uint32 heap_offset = num_bytes_per_page * init_page_count; uint32 inc_page_count, aux_heap_base, global_idx; uint32 bytes_of_last_page, bytes_to_page_end; @@ -239,15 +241,17 @@ memory_instantiate(WASMModuleInstance *module_inst, } #endif - total_size = offsetof(WASMMemoryInstance, memory_data) - + memory_data_size; - /* Allocate memory space, addr data and global data */ - if (!(memory = runtime_malloc(total_size, + if (!(memory = runtime_malloc((uint64)sizeof(WASMMemoryInstance), error_buf, error_buf_size))) { return NULL; } + if (!(memory->memory_data = + runtime_malloc(memory_data_size, error_buf, error_buf_size))) { + goto fail1; + } + memory->module_type = Wasm_Module_Bytecode; memory->num_bytes_per_page = num_bytes_per_page; memory->cur_page_count = init_page_count; @@ -257,21 +261,18 @@ memory_instantiate(WASMModuleInstance *module_inst, memory->heap_data_end = memory->heap_data + heap_size; memory->memory_data_end = memory->memory_data + (uint32)memory_data_size; - bh_assert((uint32)(memory->memory_data_end - (uint8*)memory) - == (uint32)total_size); - /* Initialize heap */ if (heap_size > 0 && !(memory->heap_handle = mem_allocator_create(memory->heap_data, heap_size))) { set_error_buf(error_buf, error_buf_size, "init app heap failed"); - goto fail1; + goto fail2; } #if WASM_ENABLE_SHARED_MEMORY != 0 if (0 != os_mutex_init(&memory->mem_lock)) { set_error_buf(error_buf, error_buf_size, "init mutex failed"); - goto fail2; + goto fail3; } if (is_shared_memory) { memory->is_shared = true; @@ -280,18 +281,20 @@ memory_instantiate(WASMModuleInstance *module_inst, (WASMMemoryInstanceCommon *)memory)) { set_error_buf(error_buf, error_buf_size, "allocate memory failed"); - goto fail3; + goto fail4; } } #endif return memory; #if WASM_ENABLE_SHARED_MEMORY != 0 -fail3: +fail4: os_mutex_destroy(&memory->mem_lock); -fail2: +fail3: if (heap_size > 0) mem_allocator_destroy(memory->heap_handle); #endif +fail2: + wasm_runtime_free(memory->memory_data); fail1: wasm_runtime_free(memory); return NULL; @@ -1760,12 +1763,12 @@ wasm_get_native_addr_range(WASMModuleInstance *module_inst, bool wasm_enlarge_memory(WASMModuleInstance *module, uint32 inc_page_count) { - WASMMemoryInstance *memory = module->default_memory, *new_memory; + WASMMemoryInstance *memory = module->default_memory; + uint8 *new_memory_data, *memory_data = memory->memory_data; uint32 heap_size = memory->heap_data_end - memory->heap_data; - uint32 total_size_old = memory->memory_data_end - (uint8 *)memory; + uint32 total_size_old = memory->memory_data_end - memory_data; uint32 total_page_count = inc_page_count + memory->cur_page_count; - uint64 total_size = offsetof(WASMMemoryInstance, memory_data) - + memory->num_bytes_per_page * (uint64)total_page_count; + uint64 total_size = memory->num_bytes_per_page * (uint64)total_page_count; void *heap_handle_old = memory->heap_handle; uint8 *heap_data_old = memory->heap_data; @@ -1796,40 +1799,39 @@ wasm_enlarge_memory(WASMModuleInstance *module, uint32 inc_page_count) we cannot access its lock again. */ mem_allocator_destroy_lock(memory->heap_handle); } - if (!(new_memory = wasm_runtime_realloc(memory, (uint32)total_size))) { - if (!(new_memory = wasm_runtime_malloc((uint32)total_size))) { + if (!(new_memory_data = wasm_runtime_realloc(memory_data, (uint32)total_size))) { + if (!(new_memory_data = wasm_runtime_malloc((uint32)total_size))) { if (heap_size > 0) { /* Restore heap's lock if memory re-alloc failed */ mem_allocator_reinit_lock(memory->heap_handle); } return false; } - bh_memcpy_s((uint8 *)new_memory, (uint32)total_size, - (uint8 *)memory, total_size_old); - wasm_runtime_free(memory); + bh_memcpy_s(new_memory_data, (uint32)total_size, + memory_data, total_size_old); + wasm_runtime_free(memory_data); } - memset((uint8 *)new_memory + total_size_old, + memset(new_memory_data + total_size_old, 0, (uint32)total_size - total_size_old); if (heap_size > 0) { - new_memory->heap_handle = (uint8 *)heap_handle_old + - ((uint8 *)new_memory - (uint8 *)memory); - if (mem_allocator_migrate(new_memory->heap_handle, + memory->heap_handle = (uint8 *)heap_handle_old + + (new_memory_data - memory_data); + if (mem_allocator_migrate(memory->heap_handle, heap_handle_old) != 0) { return false; } } - new_memory->cur_page_count = total_page_count; - new_memory->heap_data = heap_data_old + - ((uint8 *)new_memory - (uint8 *)memory); - new_memory->heap_data_end = new_memory->heap_data + heap_size; - new_memory->memory_data_end = new_memory->memory_data - + new_memory->num_bytes_per_page - * total_page_count; + memory->memory_data = new_memory_data; + memory->cur_page_count = total_page_count; + memory->heap_data = heap_data_old + (new_memory_data - memory_data); + memory->heap_data_end = memory->heap_data + heap_size; + memory->memory_data_end = memory->memory_data + + memory->num_bytes_per_page + * total_page_count; - module->memories[0] = module->default_memory = new_memory; return true; } @@ -2039,7 +2041,7 @@ wasm_get_module_inst_mem_consumption(const WASMModuleInstance *module_inst, * module_inst->memory_count; for (i = 0; i < module_inst->memory_count; i++) { WASMMemoryInstance *memory = module_inst->memories[i]; - size = offsetof(WASMMemoryInstance, memory_data) + size = sizeof(WASMMemoryInstance) + memory->num_bytes_per_page * memory->cur_page_count; mem_conspn->memories_size += size; mem_conspn->app_heap_size += memory->heap_data_end @@ -2079,3 +2081,40 @@ wasm_get_module_inst_mem_consumption(const WASMModuleInstance *module_inst, } #endif /* end of (WASM_ENABLE_MEMORY_PROFILING != 0) || (WASM_ENABLE_MEMORY_TRACING != 0) */ + +#if WASM_ENABLE_CUSTOM_NAME_SECTION != 0 +void +wasm_interp_dump_call_stack(struct WASMExecEnv *exec_env) +{ + WASMModuleInstance *module_inst = + (WASMModuleInstance *)wasm_exec_env_get_module_inst(exec_env); + WASMInterpFrame *cur_frame = + wasm_exec_env_get_cur_frame(exec_env); + WASMFunctionInstance *func_inst; + const char *func_name = NULL; + uint32 n; + + os_printf("\n"); + for (n = 0; cur_frame && cur_frame->function; n++) { + func_inst = cur_frame->function; + + if (func_inst->is_import_func) { + func_name = func_inst->u.func_import->field_name; + } + else { + func_name = func_inst->u.func->field_name; + } + + /* function name not exported, print number instead */ + if (func_name == NULL) { + os_printf("#%02d $f%d \n", n, func_inst - module_inst->functions); + } + else { + os_printf("#%02d %s \n", n, func_name); + } + + cur_frame = cur_frame->prev_frame; + } + os_printf("\n"); +} +#endif /* end of WASM_ENABLE_CUSTOM_NAME_SECTION */ diff --git a/core/iwasm/interpreter/wasm_runtime.h b/core/iwasm/interpreter/wasm_runtime.h index 852431027..242d5f12f 100644 --- a/core/iwasm/interpreter/wasm_runtime.h +++ b/core/iwasm/interpreter/wasm_runtime.h @@ -56,7 +56,7 @@ struct WASMMemoryInstance { /* Memory data begin address, the layout is: memory data + heap data Note: when memory is re-allocated, the heap data and memory data must be copied to new memory also. */ - uint8 memory_data[1]; + uint8 *memory_data; }; struct WASMTableInstance { diff --git a/doc/build_wamr.md b/doc/build_wamr.md index 08c0930e6..659f3d839 100644 --- a/doc/build_wamr.md +++ b/doc/build_wamr.md @@ -48,6 +48,8 @@ cmake -DWAMR_BUILD_PLATFORM=linux -DWAMR_BUILD_TARGET=ARM - **WAMR_BUILD_CUSTOM_NAME_SECTION**=1/0, load the function name from custom name section, default to disable if not set +> Note: if it is enabled, the call stack will be dumped when exception occurs. + #### **Enable Multi-Module feature** - **WAMR_BUILD_MULTI_MODULE**=1/0, default to disable if not set From 78c525d21ccecb32a6c1479daa9020d4a107893c Mon Sep 17 00:00:00 2001 From: Huang Qi <757509347@qq.com> Date: Mon, 28 Sep 2020 18:38:58 +0800 Subject: [PATCH 089/207] platforms/nuttx: Add support for custom name sections & configurable heap pool (#407) Co-authored-by: Huang Qi --- product-mini/platforms/nuttx/main.c | 17 +++++++++-------- product-mini/platforms/nuttx/wamr.mk | 13 +++++++++++++ 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/product-mini/platforms/nuttx/main.c b/product-mini/platforms/nuttx/main.c index 265be84d4..520d8dd21 100644 --- a/product-mini/platforms/nuttx/main.c +++ b/product-mini/platforms/nuttx/main.c @@ -21,6 +21,7 @@ static char **app_argv; static int print_help() { + /* clang-format off */ printf("Usage: iwasm [-options] wasm_file [args...]\n"); printf("options:\n"); printf(" -f|--function name Specify a function name of the module to run rather\n" @@ -46,6 +47,7 @@ print_help() #if WASM_ENABLE_LIB_PTHREAD != 0 printf(" --max-threads=n Set maximum thread number per cluster, default is 4\n"); #endif + /* clang-format on */ return 1; } @@ -89,10 +91,8 @@ validate_env_str(char *env) } #endif -#define USE_GLOBAL_HEAP_BUF 1 - -#if USE_GLOBAL_HEAP_BUF != 0 -static char global_heap_buf[164 * 1024] = { 0 }; +#if WASM_ENABLE_GLOBAL_HEAP_POOL != 0 +static char global_heap_buf[WASM_GLOBAL_HEAP_SIZE * BH_KB] = { 0 }; #endif #if WASM_ENABLE_MULTI_MODULE != 0 @@ -105,12 +105,13 @@ handle_module_path(const char *module_path) static char *module_search_path = "."; static bool -module_reader_callback(const char *module_name, uint8 **p_buffer, +module_reader_callback(const char *module_name, + uint8 **p_buffer, uint32 *p_size) { const char *format = "%s/%s.wasm"; - int sz = strlen(module_search_path) + strlen("/") + strlen(module_name) + - strlen(".wasm") + 1; + int sz = strlen(module_search_path) + strlen("/") + strlen(module_name) + + strlen(".wasm") + 1; char *wasm_file_name = BH_MALLOC(sz); if (!wasm_file_name) { return false; @@ -245,7 +246,7 @@ main(int argc, char *argv[]) memset(&init_args, 0, sizeof(RuntimeInitArgs)); -#if USE_GLOBAL_HEAP_BUF != 0 +#if WASM_ENABLE_GLOBAL_HEAP_POOL != 0 init_args.mem_alloc_type = Alloc_With_Pool; init_args.mem_alloc_option.pool.heap_buf = global_heap_buf; init_args.mem_alloc_option.pool.heap_size = sizeof(global_heap_buf); diff --git a/product-mini/platforms/nuttx/wamr.mk b/product-mini/platforms/nuttx/wamr.mk index 53e03836d..267b2dc95 100644 --- a/product-mini/platforms/nuttx/wamr.mk +++ b/product-mini/platforms/nuttx/wamr.mk @@ -113,6 +113,19 @@ else CFLAGS += -DWASM_DISABLE_HW_BOUND_CHECK=0 endif +ifeq ($(CONFIG_INTERPRETERS_WAMR_CUSTOM_NAME_SECTIONS),y) +CFLAGS += -DWASM_ENABLE_CUSTOM_NAME_SECTION=1 +else +CFLAGS += -DWASM_ENABLE_CUSTOM_NAME_SECTION=0 +endif + +ifeq ($(CONFIG_INTERPRETERS_WAMR_GLOBAL_HEAP_POOL),y) +CFLAGS += -DWASM_ENABLE_GLOBAL_HEAP_POOL=1 +CFLAGS += -DWASM_GLOBAL_HEAP_SIZE=$(CONFIG_INTERPRETERS_WAMR_GLOBAL_HEAP_POOL_SIZE) +else +CFLAGS += -DWASM_ENABLE_GLOBAL_HEAP_POOL=0 +endif + CFLAGS += -DBH_ENABLE_MEMORY_PROFILING=0 CFLAGS += -Wno-strict-prototypes -Wno-shadow -Wno-unused-variable From dc536538ad8819d2afc1fe6c9f66ddd5aa014d9e Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Tue, 29 Sep 2020 10:34:06 +0800 Subject: [PATCH 090/207] Fix sgx enclave module not destroyed issue when loading module failed (#410) --- .../platforms/linux-sgx/enclave-sample/Enclave/Enclave.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.cpp b/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.cpp index 5d2b96e32..ed9ca4182 100644 --- a/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.cpp +++ b/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.cpp @@ -148,6 +148,7 @@ handle_cmd_load_module(uint64 *args, uint32 argc) if (!(enclave_module->module = wasm_runtime_load(enclave_module->wasm_file, wasm_file_size, error_buf, error_buf_size))) { + wasm_runtime_free(enclave_module); *(void **)args_org = NULL; return; } From c83a5713f9b7bc33cbb0f94d75a35e4b2e35ca89 Mon Sep 17 00:00:00 2001 From: Xiaokang Qin Date: Tue, 29 Sep 2020 10:35:10 +0800 Subject: [PATCH 091/207] Add the fast-interp tail call support (#409) And also fix one bug in loader for tail-call Signed-off-by: Xiaokang Qin --- README.md | 1 + core/iwasm/interpreter/wasm_interp_fast.c | 62 +++++++++++++++++++++++ core/iwasm/interpreter/wasm_loader.c | 12 +++-- doc/build_wamr.md | 3 ++ 4 files changed, 74 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index a3e062a2b..95d07c020 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,7 @@ iwasm VM core - [Shared memory](https://github.com/WebAssembly/threads/blob/main/proposals/threads/Overview.md#shared-linear-memory) - [Multi-value](https://github.com/WebAssembly/multi-value) - [wasm-c-api](https://github.com/WebAssembly/wasm-c-api) +- [Tail-call](https://github.com/WebAssembly/tail-call) ### Performance and memory usage The WAMR performance, footprint and memory usage data are available at the [performance](../../wiki/Performance) wiki page. diff --git a/core/iwasm/interpreter/wasm_interp_fast.c b/core/iwasm/interpreter/wasm_interp_fast.c index bbb39a381..37a10ad2a 100644 --- a/core/iwasm/interpreter/wasm_interp_fast.c +++ b/core/iwasm/interpreter/wasm_interp_fast.c @@ -1301,10 +1301,16 @@ recover_br_info: goto return_func; HANDLE_OP (WASM_OP_CALL_INDIRECT): +#if WASM_ENABLE_TAIL_CALL != 0 + HANDLE_OP (WASM_OP_RETURN_CALL_INDIRECT): +#endif { WASMType *cur_type, *cur_func_type; WASMTableInstance *cur_table_inst; +#if WASM_ENABLE_TAIL_CALL != 0 + GET_OPCODE(); +#endif #if WASM_ENABLE_THREAD_MGR != 0 CHECK_SUSPEND_FLAGS(); #endif @@ -1360,6 +1366,10 @@ recover_br_info: wasm_set_exception(module, "indirect call type mismatch"); goto got_exception; } +#if WASM_ENABLE_TAIL_CALL != 0 + if (opcode == WASM_OP_RETURN_CALL_INDIRECT) + goto call_func_from_return_call; +#endif goto call_func_from_interp; } @@ -3112,6 +3122,22 @@ recover_br_info: cur_func = module->functions + fidx; goto call_func_from_interp; +#if WASM_ENABLE_TAIL_CALL != 0 + HANDLE_OP (WASM_OP_RETURN_CALL): +#if WASM_ENABLE_THREAD_MGR != 0 + CHECK_SUSPEND_FLAGS(); +#endif + fidx = read_uint32(frame_ip); +#if WASM_ENABLE_MULTI_MODULE != 0 + if (fidx >= module->function_count) { + wasm_set_exception(module, "unknown function"); + goto got_exception; + } +#endif + cur_func = module->functions + fidx; + goto call_func_from_return_call; +#endif /* WASM_ENABLE_TAIL_CALL */ + #if WASM_ENABLE_LABELS_AS_VALUES == 0 default: wasm_set_exception(module, "unsupported opcode"); @@ -3125,8 +3151,10 @@ recover_br_info: HANDLE_OP (WASM_OP_UNUSED_0x08): HANDLE_OP (WASM_OP_UNUSED_0x09): HANDLE_OP (WASM_OP_UNUSED_0x0a): +#if WASM_ENABLE_TAIL_CALL == 0 HANDLE_OP (WASM_OP_RETURN_CALL): HANDLE_OP (WASM_OP_RETURN_CALL_INDIRECT): +#endif HANDLE_OP (WASM_OP_UNUSED_0x14): HANDLE_OP (WASM_OP_UNUSED_0x15): HANDLE_OP (WASM_OP_UNUSED_0x16): @@ -3169,6 +3197,40 @@ recover_br_info: FETCH_OPCODE_AND_DISPATCH (); #endif +#if WASM_ENABLE_TAIL_CALL !=0 + call_func_from_return_call: + { + uint32 *lp_base; + uint32 *lp; + int i; + + if (!(lp_base = lp = wasm_runtime_malloc(cur_func->param_cell_num * sizeof(uint32)))) { + wasm_set_exception(module, "allocate memory failed"); + goto got_exception; + } + for (i = 0; i < cur_func->param_count; i++) { + if (cur_func->param_types[i] == VALUE_TYPE_I64 + || cur_func->param_types[i] == VALUE_TYPE_F64) { + *(int64*)(lp) = + GET_OPERAND(int64, (2 * (cur_func->param_count - i - 1))); + lp += 2; + } + else { + *(lp) = GET_OPERAND(int32, (2 * (cur_func->param_count - i - 1))); + lp ++; + } + } + frame->lp = frame->operand + cur_func->const_cell_num; + bh_memcpy_s(frame->lp, (lp - lp_base) * sizeof(uint32), + lp_base, (lp - lp_base) * sizeof(uint32)); + wasm_runtime_free(lp_base); + FREE_FRAME(exec_env, frame); + frame_ip += cur_func->param_count * sizeof(int16); + wasm_exec_env_set_cur_frame(exec_env, + (WASMRuntimeFrame *)prev_frame); + goto call_func_from_entry; + } +#endif /* WASM_ENABLE_TAIL_CALL */ call_func_from_interp: /* Only do the copy when it's called from interpreter. */ { diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index 20e204042..a8d54b519 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -5970,6 +5970,9 @@ handle_op_block_and_loop: read_leb_uint32(p, p_end, type_idx); #if WASM_ENABLE_FAST_INTERP != 0 +#if WASM_ENABLE_TAIL_CALL != 0 + emit_byte(loader_ctx, opcode); +#endif /* we need to emit func_idx before arguments */ emit_uint32(loader_ctx, type_idx); #endif @@ -6023,12 +6026,13 @@ handle_op_block_and_loop: } for (i = 0; i < func_type->result_count; i++) { type = func->func_type->types[func->func_type->param_count + i]; - if (func_type->types[func_type->param_count + i] != type) - set_error_buf_v(error_buf, error_buf_size, "%s%s%s", - "type mismatch: expect ", + if (func_type->types[func_type->param_count + i] != type) { + set_error_buf_v(error_buf, error_buf_size, + "%s%s%s", "type mismatch: expect ", type_str[type - VALUE_TYPE_F64], " but got other"); - goto fail; + goto fail; + } } RESET_STACK(); SET_CUR_BLOCK_STACK_POLYMORPHIC_STATE(true); diff --git a/doc/build_wamr.md b/doc/build_wamr.md index 659f3d839..52090e297 100644 --- a/doc/build_wamr.md +++ b/doc/build_wamr.md @@ -83,6 +83,9 @@ Currently we only profile the memory consumption of module, module_instance and - **WAMR_APP_THREAD_STACK_SIZE_MAX**=n, default to 8 MB (8388608) if not set > Note: the AOT boundary check with hardware trap mechanism might consume large stack since the OS may lazily grow the stack mapping as a guard page is hit, we may use this configuration to reduce the total stack usage, e.g. -DWAMR_APP_THREAD_STACK_SIZE_MAX=131072 (128 KB). +#### **Enable tail call feature** +- **WAMR_BUILD_TAIL_CALL**=1/0, default to disable if not set + **Combination of configurations:** We can combine the configurations. For example, if we want to disable interpreter, enable AOT and WASI, we can run command: From 06b045a972e3f2ceb788298aac9c58569f246f31 Mon Sep 17 00:00:00 2001 From: Wang Xin Date: Wed, 30 Sep 2020 08:30:58 +0800 Subject: [PATCH 092/207] Update readme --- README.md | 33 +++++++------------------ doc/release_ack.md | 61 ---------------------------------------------- doc/roadmap.md | 23 ----------------- 3 files changed, 9 insertions(+), 108 deletions(-) delete mode 100644 doc/release_ack.md delete mode 100644 doc/roadmap.md diff --git a/README.md b/README.md index 95d07c020..4c44f1909 100644 --- a/README.md +++ b/README.md @@ -37,9 +37,6 @@ iwasm VM core - [wasm-c-api](https://github.com/WebAssembly/wasm-c-api) - [Tail-call](https://github.com/WebAssembly/tail-call) -### Performance and memory usage -The WAMR performance, footprint and memory usage data are available at the [performance](../../wiki/Performance) wiki page. - ### Supported architectures and platforms The iwasm supports the following architectures: @@ -52,7 +49,7 @@ The iwasm supports the following architectures: Following platforms are supported. Refer to [WAMR porting guide](./doc/port_wamr.md) for how to port WAMR to a new platform. -- [Linux](./doc/build_wamr.md#linux), [Linux SGX (Intel Software Guard Extension)](./doc/linux_sgx.md), [MacOS](./doc/build_wamr.md#macos), [Android](./doc/build_wamr.md#android) +- [Linux](./doc/build_wamr.md#linux), [Linux SGX (Intel Software Guard Extension)](./doc/linux_sgx.md), [MacOS](./doc/build_wamr.md#macos), [Android](./doc/build_wamr.md#android), Windows - [Zephyr](./doc/build_wamr.md#zephyr), [AliOS-Things](./doc/build_wamr.md#alios-things), [VxWorks](./doc/build_wamr.md#vxworks), [NuttX](./doc/build_wamr.md#nuttx) ### Build iwasm VM core (mini product) @@ -119,22 +116,6 @@ The WAMR [samples](./samples) integrate the iwasm VM core, application manager a - **[wasm-c-api](./samples/wasm-c-api/README.md)**: Demonstrating how to run some samples from [wasm-c-api proposal](https://github.com/WebAssembly/wasm-c-api) and showing the supported API's. -Releases and acknowledgments -============================ - -WAMR is a community effort. Since Intel Corp contributed the first release of this open source project, this project has received many good contributions from the community. - -See the [major features releasing history and contributor names](./doc/release_ack.md) - - -Roadmap -======= - -See the [roadmap](./doc/roadmap.md) to understand what major features are planned or under development. - -Please submit issues for any new feature request or your plan for contributing new features. - - License ======= WAMR uses the same license as LLVM: the `Apache 2.0 license` with the LLVM @@ -143,9 +124,13 @@ use, modify, distribute and sell your own products based on WAMR. Any contributions you make will be under the same license. -Submit issues and contact the maintainers -========================================= -[Click here to submit. Your feedback is always welcome!](https://github.com/intel/wasm-micro-runtime/issues/new) +# More resources + +Check out the [Wiki documents ](../../wiki) for more resources: + +- [Performance and footprint data](../../wiki/Performance) +- Community news and events +- Roadmap +- Technical documents -Contact the maintainers: imrt-public@intel.com diff --git a/doc/release_ack.md b/doc/release_ack.md deleted file mode 100644 index a0adfff41..000000000 --- a/doc/release_ack.md +++ /dev/null @@ -1,61 +0,0 @@ -Major feature releases and contributors -========================================= - - -**May 07, 2019: WAMR first GitHub release** - -- Contributors: Wenyong Huang, Weining Lu, Lei Shi, Li Tian, Jizhao Zhang, Yi Zhang, Daoming Qiu, Xin Wang (Intel) - -**May 17, 2019: Application manager, WASM APP API, samples and test tools** - -- Contributors: Wenyong Huang, Weining Lu, Lei Shi, Li Tian, Jizhao Zhang, Yi Zhang, Daoming Qiu, Xin Wang (Intel) - - -**May 23, 2019: Support AliOS Things** - -- Contributor: JinZhou Zhu (Alibaba) - -**May 24, 2019: Support memory usage profiler** - -- Contributors Wenyong Huang (Intel) - -**Jun 11, 2019: Add WASM APP API connection** - - -- Contributor: Weining Lu (Intel) - -**Jun 10, 2019: Support VxWorks** - -- Contributor: Yiting Wang (WindRiver) - -**Aug 1, 2019: Add WGL graphic user interface API** - -- Contributor: Weining Lu - -**Aug 14, 2019: Add Docker support** - - -- Contributor: beriberikix - - -**Aug 14, 2019: WASM IoT app store demo** - - -- Contributor: Luhanzhi Li, Jun Xu (Intel) - - -**Aug 28, 2019: SGX support** - - -- Contributor: Mic Bowman (Intel) - - -**Sep 6, 2019: Mac platform support** - - -- Contributor: Jonathan Dong (Alibaba) - -**Nov 2019: WASI support** (Intel) - -**Jan 2020: Ahead of time and Just-in-Time compilation support** (Intel) - diff --git a/doc/roadmap.md b/doc/roadmap.md deleted file mode 100644 index c5c7b84a9..000000000 --- a/doc/roadmap.md +++ /dev/null @@ -1,23 +0,0 @@ - -# WebAssembly Micro Runtime Roadmap - - - -## Data serialization -Evaluating using cbor as the default data serialization - -No plan yet. - - - -## Threading -Plan: 2020 Q1 - - - -## AssemblyScript Support and API - -Currently under evaluation - - - From cc0aab106379db3368655f5a2b891686a288d09f Mon Sep 17 00:00:00 2001 From: Karl Fessel Date: Mon, 12 Oct 2020 10:52:28 +0200 Subject: [PATCH 093/207] Remove '@' when declare function invokeNative to fix compile error (#417) --- core/iwasm/common/arch/invokeNative_aarch64.s | 2 +- core/iwasm/common/arch/invokeNative_arm.s | 2 +- core/iwasm/common/arch/invokeNative_arm_vfp.s | 2 +- core/iwasm/common/arch/invokeNative_thumb.s | 2 +- core/iwasm/common/arch/invokeNative_thumb_vfp.s | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/core/iwasm/common/arch/invokeNative_aarch64.s b/core/iwasm/common/arch/invokeNative_aarch64.s index 33b6b5bc2..77536c923 100644 --- a/core/iwasm/common/arch/invokeNative_aarch64.s +++ b/core/iwasm/common/arch/invokeNative_aarch64.s @@ -6,7 +6,7 @@ .align 2 #ifndef BH_PLATFORM_DARWIN .globl invokeNative - .type invokeNative, @function + .type invokeNative, function invokeNative: #else .globl _invokeNative diff --git a/core/iwasm/common/arch/invokeNative_arm.s b/core/iwasm/common/arch/invokeNative_arm.s index d494c2bbb..bfe8e3b09 100644 --- a/core/iwasm/common/arch/invokeNative_arm.s +++ b/core/iwasm/common/arch/invokeNative_arm.s @@ -6,7 +6,7 @@ .align 2 #ifndef BH_PLATFORM_DARWIN .globl invokeNative - .type invokeNative, @function + .type invokeNative, function invokeNative: #else .globl _invokeNative diff --git a/core/iwasm/common/arch/invokeNative_arm_vfp.s b/core/iwasm/common/arch/invokeNative_arm_vfp.s index 8b1fe91ab..c7dbb980a 100644 --- a/core/iwasm/common/arch/invokeNative_arm_vfp.s +++ b/core/iwasm/common/arch/invokeNative_arm_vfp.s @@ -6,7 +6,7 @@ .align 2 #ifndef BH_PLATFORM_DARWIN .globl invokeNative - .type invokeNative, @function + .type invokeNative, function invokeNative: #else .globl _invokeNative diff --git a/core/iwasm/common/arch/invokeNative_thumb.s b/core/iwasm/common/arch/invokeNative_thumb.s index 50f162210..30c64e1d4 100644 --- a/core/iwasm/common/arch/invokeNative_thumb.s +++ b/core/iwasm/common/arch/invokeNative_thumb.s @@ -6,7 +6,7 @@ .align 2 #ifndef BH_PLATFORM_DARWIN .globl invokeNative - .type invokeNative, @function + .type invokeNative, function invokeNative: #else .globl _invokeNative diff --git a/core/iwasm/common/arch/invokeNative_thumb_vfp.s b/core/iwasm/common/arch/invokeNative_thumb_vfp.s index 89abf032d..2d836fb82 100644 --- a/core/iwasm/common/arch/invokeNative_thumb_vfp.s +++ b/core/iwasm/common/arch/invokeNative_thumb_vfp.s @@ -6,7 +6,7 @@ .align 2 #ifndef BH_PLATFORM_DARWIN .globl invokeNative - .type invokeNative, @function + .type invokeNative, function invokeNative: #else .globl _invokeNative From c87f28eacd09e2e8860c486b035ac40e694f0fef Mon Sep 17 00:00:00 2001 From: Xu Jun <693788454@qq.com> Date: Tue, 13 Oct 2020 08:34:31 +0800 Subject: [PATCH 094/207] support tail-call in AoT (#419) --- core/iwasm/aot/aot_loader.c | 6 +++++ core/iwasm/compilation/aot_compiler.c | 30 +++++++++++++++++++++- core/iwasm/compilation/aot_emit_function.c | 8 ++++-- core/iwasm/compilation/aot_emit_function.h | 2 +- core/iwasm/compilation/aot_llvm.c | 3 +++ core/iwasm/compilation/aot_llvm.h | 4 +++ core/iwasm/include/aot_export.h | 1 + wamr-compiler/CMakeLists.txt | 1 + wamr-compiler/main.c | 4 +++ 9 files changed, 55 insertions(+), 4 deletions(-) diff --git a/core/iwasm/aot/aot_loader.c b/core/iwasm/aot/aot_loader.c index a3dacd33d..5f8ed0ebd 100644 --- a/core/iwasm/aot/aot_loader.c +++ b/core/iwasm/aot/aot_loader.c @@ -2093,8 +2093,14 @@ aot_convert_wasm_module(WASMModule *wasm_module, } option.is_jit_mode = true; +#if WASM_ENABLE_BULK_MEMORY != 0 + option.enable_bulk_memory = true; +#endif #if WASM_ENABLE_THREAD_MGR != 0 option.enable_thread_mgr = true; +#endif +#if WASM_ENABLE_TAIL_CALL != 0 + option.enable_tail_call = true; #endif comp_ctx = aot_create_comp_context(comp_data, &option); if (!comp_ctx) { diff --git a/core/iwasm/compilation/aot_compiler.c b/core/iwasm/compilation/aot_compiler.c index d813300ec..d4aa718dc 100644 --- a/core/iwasm/compilation/aot_compiler.c +++ b/core/iwasm/compilation/aot_compiler.c @@ -240,7 +240,7 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index) case WASM_OP_CALL: read_leb_uint32(frame_ip, frame_ip_end, func_idx); - if (!aot_compile_op_call(comp_ctx, func_ctx, func_idx, &frame_ip)) + if (!aot_compile_op_call(comp_ctx, func_ctx, func_idx, false)) return false; break; @@ -251,6 +251,33 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index) return false; break; +#if WASM_ENABLE_TAIL_CALL != 0 + case WASM_OP_RETURN_CALL: + if (!comp_ctx->enable_tail_call) { + aot_set_last_error("unsupported opcode"); + return false; + } + read_leb_uint32(frame_ip, frame_ip_end, func_idx); + if (!aot_compile_op_call(comp_ctx, func_ctx, func_idx, true)) + return false; + if (!aot_compile_op_return(comp_ctx, func_ctx, &frame_ip)) + return false; + break; + + case WASM_OP_RETURN_CALL_INDIRECT: + if (!comp_ctx->enable_tail_call) { + aot_set_last_error("unsupported opcode"); + return false; + } + read_leb_uint32(frame_ip, frame_ip_end, type_idx); + frame_ip++; /* skip 0x00 */ + if (!aot_compile_op_call_indirect(comp_ctx, func_ctx, type_idx)) + return false; + if (!aot_compile_op_return(comp_ctx, func_ctx, &frame_ip)) + return false; + break; +#endif /* end of WASM_ENABLE_TAIL_CALL */ + case WASM_OP_DROP: if (!aot_compile_op_drop(comp_ctx, func_ctx, true)) return false; @@ -993,6 +1020,7 @@ build_atomic_rmw: #endif /* end of WASM_ENABLE_SHARED_MEMORY */ default: + aot_set_last_error("unsupported opcode"); break; } } diff --git a/core/iwasm/compilation/aot_emit_function.c b/core/iwasm/compilation/aot_emit_function.c index 21b49ad0c..054275115 100644 --- a/core/iwasm/compilation/aot_emit_function.c +++ b/core/iwasm/compilation/aot_emit_function.c @@ -304,7 +304,7 @@ check_stack_boundary(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, bool aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, - uint32 func_idx, uint8 **p_frame_ip) + uint32 func_idx, bool tail_call) { uint32 import_func_count = comp_ctx->comp_data->import_func_count; AOTImportFunc *import_funcs = comp_ctx->comp_data->import_funcs; @@ -476,8 +476,12 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, /* Set calling convention for the call with the func's calling convention */ LLVMSetInstructionCallConv(value_ret, LLVMGetFunctionCallConv(func)); + if (tail_call) + LLVMSetTailCall(value_ret, true); + /* Check whether there was exception thrown when executing the function */ - if (!check_exception_thrown(comp_ctx, func_ctx)) + if (!tail_call + && !check_exception_thrown(comp_ctx, func_ctx)) goto fail; } diff --git a/core/iwasm/compilation/aot_emit_function.h b/core/iwasm/compilation/aot_emit_function.h index 28d7bff98..70aa4c5d1 100644 --- a/core/iwasm/compilation/aot_emit_function.h +++ b/core/iwasm/compilation/aot_emit_function.h @@ -14,7 +14,7 @@ extern "C" { bool aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, - uint32 func_idx, uint8 **p_frame_ip); + uint32 func_idx, bool tail_call); bool aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, diff --git a/core/iwasm/compilation/aot_llvm.c b/core/iwasm/compilation/aot_llvm.c index 6dea84524..e81e4602c 100644 --- a/core/iwasm/compilation/aot_llvm.c +++ b/core/iwasm/compilation/aot_llvm.c @@ -1062,6 +1062,9 @@ aot_create_comp_context(AOTCompData *comp_data, if (option->enable_thread_mgr) comp_ctx->enable_thread_mgr = true; + if (option->enable_tail_call) + comp_ctx->enable_tail_call = true; + if (option->is_jit_mode) { /* Create LLVM execution engine */ LLVMInitializeMCJITCompilerOptions(&jit_options, sizeof(jit_options)); diff --git a/core/iwasm/compilation/aot_llvm.h b/core/iwasm/compilation/aot_llvm.h index 3658b5fd0..c15db867c 100644 --- a/core/iwasm/compilation/aot_llvm.h +++ b/core/iwasm/compilation/aot_llvm.h @@ -204,6 +204,9 @@ typedef struct AOTCompContext { /* Thread Manager */ bool enable_thread_mgr; + /* Tail Call */ + bool enable_tail_call; + /* Whether optimize the JITed code */ bool optimize; @@ -244,6 +247,7 @@ typedef struct AOTCompOption{ char *cpu_features; bool enable_bulk_memory; bool enable_thread_mgr; + bool enable_tail_call; bool is_sgx_platform; uint32 opt_level; uint32 size_level; diff --git a/core/iwasm/include/aot_export.h b/core/iwasm/include/aot_export.h index 778400d2f..ca0ffb6a8 100644 --- a/core/iwasm/include/aot_export.h +++ b/core/iwasm/include/aot_export.h @@ -41,6 +41,7 @@ typedef struct AOTCompOption{ char *cpu_features; bool enable_bulk_memory; bool enable_thread_mgr; + bool enable_tail_call; bool is_sgx_platform; uint32_t opt_level; uint32_t size_level; diff --git a/wamr-compiler/CMakeLists.txt b/wamr-compiler/CMakeLists.txt index 8de6f65d5..114e186d2 100644 --- a/wamr-compiler/CMakeLists.txt +++ b/wamr-compiler/CMakeLists.txt @@ -26,6 +26,7 @@ add_definitions(-DWASM_ENABLE_BULK_MEMORY=1) add_definitions(-DWASM_DISABLE_HW_BOUND_CHECK=1) add_definitions(-DWASM_ENABLE_SHARED_MEMORY=1) add_definitions(-DWASM_ENABLE_THREAD_MGR=1) +add_definitions(-DWASM_ENABLE_TAIL_CALL=1) # Set WAMR_BUILD_TARGET, currently values supported: # "X86_64", "AMD_64", "X86_32", "ARM_32", "MIPS_32", "XTENSA_32" diff --git a/wamr-compiler/main.c b/wamr-compiler/main.c index 3c72dc381..d3505ad01 100644 --- a/wamr-compiler/main.c +++ b/wamr-compiler/main.c @@ -41,6 +41,7 @@ print_help() printf(" llvmir-opt Optimized LLVM IR\n"); printf(" --enable-bulk-memory Enable the post-MVP bulk memory feature\n"); printf(" --enable-multi-thread Enable multi-thread feature, the dependent features bulk-memory and\n"); + printf(" --enable-tail-call Enable the post-MVP tail call feature\n"); printf(" thread-mgr will be enabled automatically\n"); printf(" -v=n Set log verbose level (0 to 5, default is 2), larger with more log\n"); printf("Examples: wamrc -o test.aot test.wasm\n"); @@ -146,6 +147,9 @@ main(int argc, char *argv[]) option.enable_bulk_memory = true; option.enable_thread_mgr = true; } + else if (!strcmp(argv[0], "--enable-tail-call")) { + option.enable_tail_call = true; + } else return print_help(); } From b929ee3f715a1f90b052ca675c6131e5beafa6a0 Mon Sep 17 00:00:00 2001 From: Xu Jun <693788454@qq.com> Date: Tue, 13 Oct 2020 12:13:18 +0800 Subject: [PATCH 095/207] Update windows build step, add CI support for windows (#420) --- .github/workflows/windows.yml | 59 +++++++++++++++++++++++++++++++++++ README.md | 2 +- doc/build_wamr.md | 17 +++++++++- 3 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/windows.yml diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml new file mode 100644 index 000000000..9b94ca1f9 --- /dev/null +++ b/.github/workflows/windows.yml @@ -0,0 +1,59 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +name: Windows + +# Controls when the action will run. Triggers the workflow on push or pull request +# events but only for the main branch +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + + build: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [windows-latest] + steps: + - uses: actions/checkout@v2 + + - name: Build iwasm [default] + run: | + cd product-mini/platforms/windows + mkdir build && cd build + cmake .. + cmake --build . --config Release + cd .. && rm -r build + - name: Build iwasm [aot only] + run: | + cd product-mini/platforms/windows + mkdir build && cd build + cmake .. -DWAMR_BUILD_AOT=1 -DWAMR_BUILD_INTERP=0 + cmake --build . --config Release + cd .. && rm -r build + - name: Build iwasm [interp only] + run: | + cd product-mini/platforms/windows + mkdir build && cd build + cmake .. -DWAMR_BUILD_AOT=0 + cmake --build . --config Release + cd .. && rm -r build + - name: Build iwasm [tail call] + run: | + cd product-mini/platforms/windows + mkdir build && cd build + cmake .. -DWAMR_BUILD_TAIL_CALL=1 + cmake --build . --config Release + cd .. && rm -r build + - name: Build iwasm [custom name section] + run: | + cd product-mini/platforms/windows + mkdir build && cd build + cmake .. -DWAMR_BUILD_CUSTOM_NAME_SECTION=1 + cmake --build . --config Release + cd .. && rm -r build + diff --git a/README.md b/README.md index 4c44f1909..aa892f874 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ The iwasm supports the following architectures: Following platforms are supported. Refer to [WAMR porting guide](./doc/port_wamr.md) for how to port WAMR to a new platform. -- [Linux](./doc/build_wamr.md#linux), [Linux SGX (Intel Software Guard Extension)](./doc/linux_sgx.md), [MacOS](./doc/build_wamr.md#macos), [Android](./doc/build_wamr.md#android), Windows +- [Linux](./doc/build_wamr.md#linux), [Linux SGX (Intel Software Guard Extension)](./doc/linux_sgx.md), [MacOS](./doc/build_wamr.md#macos), [Android](./doc/build_wamr.md#android), [Windows](./doc/build_wamr.md#windows) - [Zephyr](./doc/build_wamr.md#zephyr), [AliOS-Things](./doc/build_wamr.md#alios-things), [VxWorks](./doc/build_wamr.md#vxworks), [NuttX](./doc/build_wamr.md#nuttx) ### Build iwasm VM core (mini product) diff --git a/doc/build_wamr.md b/doc/build_wamr.md index 52090e297..8872f2dab 100644 --- a/doc/build_wamr.md +++ b/doc/build_wamr.md @@ -174,7 +174,7 @@ brew install cmake ``` Then build the source codes: -``` +``` Bash cd product-mini/platforms/darwin/ mkdir build cd build @@ -184,6 +184,21 @@ make Note: WAMR provides some features which can be easily configured by passing options to cmake, please see [WAMR vmcore cmake building configurations](./build_wamr.md#wamr-vmcore-cmake-building-configurations) for details. Currently in MacOS, interpreter, AoT, and builtin libc are enabled by default. +Windows +------------------------- + +Make sure `MSVC` and `cmake` are installed and available in the command line environment + +Then build the source codes: +``` Bash +cd product-mini/platforms/windows/ +mkdir build +cd build +cmake .. +cmake --build . --config Release +``` +The executable file is `build/Release/iwasm.exe` + VxWorks ------------------------- VxWorks 7 SR0620 release is validated. From f7903caa65ebe9fe912c517331f93a1a9dc81b3c Mon Sep 17 00:00:00 2001 From: YAMAMOTO Takashi Date: Tue, 13 Oct 2020 15:13:30 +0900 Subject: [PATCH 096/207] wasm_loader_ctx_init: Don't use false as a pointer (#422) --- core/iwasm/interpreter/wasm_loader.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index a8d54b519..804c497c3 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -3885,7 +3885,7 @@ wasm_loader_ctx_init(WASMFunction *func) WASMLoaderContext *loader_ctx = wasm_runtime_malloc(sizeof(WASMLoaderContext)); if (!loader_ctx) - return false; + return NULL; memset(loader_ctx, 0, sizeof(WASMLoaderContext)); loader_ctx->frame_ref_size = 32; From 2dd3875fd909bbfa2e041e14f4ed2155d5b5f80b Mon Sep 17 00:00:00 2001 From: YAMAMOTO Takashi Date: Tue, 13 Oct 2020 15:14:55 +0900 Subject: [PATCH 097/207] nuttx: Fix build for sim on macOS (#423) --- product-mini/platforms/nuttx/wamr.mk | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/product-mini/platforms/nuttx/wamr.mk b/product-mini/platforms/nuttx/wamr.mk index 267b2dc95..f76bf0cc2 100644 --- a/product-mini/platforms/nuttx/wamr.mk +++ b/product-mini/platforms/nuttx/wamr.mk @@ -15,6 +15,14 @@ else ifeq ($(CONFIG_ARCH_X86_64),y) WAMR_BUILD_TARGET := X86_64 else ifeq ($(CONFIG_ARCH_XTENSA),y) WAMR_BUILD_TARGET := XTENSA +else ifeq ($(CONFIG_ARCH_SIM),y) +ifeq ($(CONFIG_HOST_X86_64),y) +WAMR_BUILD_TARGET := X86_64 +endif +ifeq ($(CONFIG_HOST_MACOS),y) +# Note: invokeNative_em64.s needs BH_PLATFORM_DARWIN +CFLAGS += -DBH_PLATFORM_DARWIN +endif endif WAMR_BUILD_PLATFORM := nuttx From f1fe5d7872a2aaae98ede5d0c3aab0bbde8fcefa Mon Sep 17 00:00:00 2001 From: Karl Fessel Date: Fri, 16 Oct 2020 05:21:53 +0200 Subject: [PATCH 098/207] add RIOT-OS support to WAMR (#425) * add RIOT platform see riot-os.org * add simple RIOT example --- core/shared/platform/riot/platform_internal.h | 75 +++ core/shared/platform/riot/riot_platform.c | 73 +++ core/shared/platform/riot/riot_thread.c | 429 ++++++++++++++++++ core/shared/platform/riot/riot_time.c | 15 + .../platform/riot/shared_platform.cmake | 17 + product-mini/platforms/riot/CMakeLists.txt | 59 +++ product-mini/platforms/riot/Makefile | 96 ++++ product-mini/platforms/riot/iwasmt.c | 148 ++++++ product-mini/platforms/riot/test_wasm.h | 46 ++ 9 files changed, 958 insertions(+) create mode 100644 core/shared/platform/riot/platform_internal.h create mode 100644 core/shared/platform/riot/riot_platform.c create mode 100644 core/shared/platform/riot/riot_thread.c create mode 100644 core/shared/platform/riot/riot_time.c create mode 100644 core/shared/platform/riot/shared_platform.cmake create mode 100644 product-mini/platforms/riot/CMakeLists.txt create mode 100644 product-mini/platforms/riot/Makefile create mode 100644 product-mini/platforms/riot/iwasmt.c create mode 100644 product-mini/platforms/riot/test_wasm.h diff --git a/core/shared/platform/riot/platform_internal.h b/core/shared/platform/riot/platform_internal.h new file mode 100644 index 000000000..0f79c6f7b --- /dev/null +++ b/core/shared/platform/riot/platform_internal.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * Copyright (C) 2020 TU Bergakademie Freiberg Karl Fessel + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _PLATFORM_INTERNAL_H +#define _PLATFORM_INTERNAL_H + +//Riot includes core +#include +#include +#include + +//Riot includes sys +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef BH_PLATFORM_RIOT +#define BH_PLATFORM_RIOT +#endif + +#define BH_APPLET_PRESERVED_STACK_SIZE (2 * BH_KB) + +/* Default thread priority */ +#define BH_THREAD_DEFAULT_PRIORITY 7 + +typedef thread_t korp_thread; +typedef kernel_pid_t korp_tid; +typedef mutex_t korp_mutex; + +// typedef sema_t korp_sem; + +struct os_thread_wait_node; +typedef struct os_thread_wait_node *os_thread_wait_list; +typedef struct korp_cond { + mutex_t wait_list_lock; + os_thread_wait_list thread_wait_list; +} korp_cond; + +#define os_printf printf +#define os_vprintf vprintf + +#if WA_MATH +/* math functions which are not provided by os*/ +double sqrt(double x); +double floor(double x); +double ceil(double x); +double fmin(double x, double y); +double fmax(double x, double y); +double rint(double x); +double fabs(double x); +double trunc(double x); +float floorf(float x); +float ceilf(float x); +float fminf(float x, float y); +float fmaxf(float x, float y); +float rintf(float x); +float truncf(float x); +int signbit(double x); +int isnan(double x); +#endif + +#endif /* end of _BH_PLATFORM_H */ + diff --git a/core/shared/platform/riot/riot_platform.c b/core/shared/platform/riot/riot_platform.c new file mode 100644 index 000000000..bad690769 --- /dev/null +++ b/core/shared/platform/riot/riot_platform.c @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * Copyright (C) 2020 TU Bergakademie Freiberg Karl Fessel + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "platform_api_vmcore.h" +#include "platform_api_extension.h" + +int +os_thread_sys_init(void); + +void +os_thread_sys_destroy(void); + +int +bh_platform_init(void) +{ + return os_thread_sys_init(); +} + +void +bh_platform_destroy(void) +{ + os_thread_sys_destroy(); +} + +void * +os_malloc(unsigned size) +{ + return malloc(size); +} + +void * +os_realloc(void *ptr, unsigned size) +{ + return realloc(ptr, size); +} + +void +os_free(void *ptr) +{ + free(ptr); +} + +void * +os_mmap(void *hint, unsigned int size, int prot, int flags) +{ + return BH_MALLOC(size); +} + +void +os_munmap(void *addr, size_t size) +{ + return BH_FREE(addr); +} + +int +os_mprotect(void *addr, size_t size, int prot) +{ + return 0; +} + +void +os_dcache_flush(void) +{ +#if defined(CONFIG_CPU_CORTEX_M7) && defined(CONFIG_ARM_MPU) + uint32 key; + key = irq_lock(); + SCB_CleanDCache(); + irq_unlock(key); +#endif +} diff --git a/core/shared/platform/riot/riot_thread.c b/core/shared/platform/riot/riot_thread.c new file mode 100644 index 000000000..75576114f --- /dev/null +++ b/core/shared/platform/riot/riot_thread.c @@ -0,0 +1,429 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * Copyright (C) 2020 TU Bergakademie Freiberg Karl Fessel + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "platform_api_vmcore.h" +#include "platform_api_extension.h" + +#include + +#define bh_assert(v) do { \ + if (!(v)) { \ + printf("\nASSERTION FAILED: %s, at %s, line %d\n", \ + #v, __FILE__, __LINE__); \ + core_panic(0,0/*expr_string*/); \ + while (1); \ + } \ + } while (0) + +struct os_thread_data; +typedef struct os_thread_wait_node { + sema_t sem; + void * ret; + os_thread_wait_list next; +} os_thread_wait_node; + +// all information for thread to cleanup it self +typedef struct os_thread_data { + /* Next thread data */ + struct os_thread_data *next; + /* thread handle */ + kernel_pid_t tid; + /* Thread start routine */ + thread_start_routine_t start_routine; + /* Thread start routine argument */ + void *arg; + /* thread local root */ + void *tlr; + /* Lock for waiting list */ + mutex_t wait_list_lock; + /* Waiting list of other threads who are joining this thread */ + os_thread_wait_list thread_wait_list; + /* Thread stack size */ + unsigned stack_size; + /* Thread stack */ + char stack[1]; +} os_thread_data; + +typedef struct os_thread_obj { + korp_tid thread; + /* Whether the thread is terminated and this thread object is to + be freed in the future. */ + bool to_be_freed; + struct os_thread_obj *next; +} os_thread_obj; + +static bool is_thread_sys_inited = false; + +/* Lock for thread data list */ +static mutex_t thread_data_lock; + +/* Thread data list */ +static os_thread_data *thread_data_list = NULL; + +static void thread_data_list_add(os_thread_data *thread_data) +{ + mutex_lock(&thread_data_lock); + if (!thread_data_list) + thread_data_list = thread_data; + else { + /* If already in list, just return */ + os_thread_data *p = thread_data_list; + while (p) { + if (p == thread_data) { + mutex_unlock(&thread_data_lock); + return; + } + p = p->next; + } + + /* Set as head of list */ + thread_data->next = thread_data_list; + thread_data_list = thread_data; + } + mutex_unlock(&thread_data_lock); +} + +static void thread_data_list_remove(os_thread_data *thread_data) +{ + mutex_lock(&thread_data_lock); + if (thread_data_list) { + if (thread_data_list == thread_data) + thread_data_list = thread_data_list->next; + else { + /* Search and remove it from list */ + os_thread_data *p = thread_data_list; + while (p && p->next != thread_data) + p = p->next; + if (p && p->next == thread_data) + p->next = p->next->next; + } + } + mutex_unlock(&thread_data_lock); +} + +static os_thread_data * +thread_data_list_lookup(korp_tid tid) +{ + mutex_lock(&thread_data_lock); + if (thread_data_list) { + os_thread_data *p = thread_data_list; + while (p) { + if (p->tid == tid) { + /* Found */ + mutex_unlock(&thread_data_lock); + return p; + } + p = p->next; + } + } + mutex_unlock(&thread_data_lock); + return NULL; +} + +int +os_thread_sys_init() +{ + if (is_thread_sys_inited) + return BHT_OK; + + mutex_init(&thread_data_lock); + + is_thread_sys_inited = true; + return BHT_OK; +} + +void +os_thread_sys_destroy() +{ + if (is_thread_sys_inited) { + is_thread_sys_inited = false; + } +} + +static os_thread_data * +thread_data_current() +{ + kernel_pid_t tid = thread_getpid(); + return thread_data_list_lookup(tid); +} + +static void +os_thread_cleanup(void) +{ + //TODO Check this (Join sema trigger, cleanup of thread_data) + os_thread_data *thread_data = thread_data_current(); + bh_assert(thread_data != NULL); + mutex_lock(&thread_data->wait_list_lock); + if (thread_data->thread_wait_list) { + /* Signal each joining thread */ + os_thread_wait_list head = thread_data->thread_wait_list; + while (head) { + os_thread_wait_list next = head->next; + head->ret = thread_data->arg; + sema_post(&head->sem); + head = next; + } + thread_data->thread_wait_list = NULL; + } + mutex_unlock(&thread_data->wait_list_lock); + + thread_data_list_remove(thread_data); +} + +static void * +os_thread_wrapper(void *thread_data) +{ + /* Set thread custom data */ + os_thread_data * t = (os_thread_data*) thread_data; + t->tid = thread_getpid(); + thread_data_list_add(t); + + // save the return value to arg since it is not need after the call + t->arg = (t->start_routine)(t->arg); + + os_thread_cleanup(); // internal structures and joiners + + BH_FREE(thread_data); + sched_task_exit();// stop thread //clean + return NULL; //never reached +} + +int +os_thread_create(korp_tid *p_tid, thread_start_routine_t start, + void *arg, unsigned int stack_size) +{ + return os_thread_create_with_prio(p_tid, start, arg, stack_size, + BH_THREAD_DEFAULT_PRIORITY); +} + +int +os_thread_create_with_prio(korp_tid *p_tid, thread_start_routine_t start, + void *arg, unsigned int stack_size, int prio) +{ + kernel_pid_t tid; + os_thread_data *thread_data; + unsigned thread_data_size; + + if (!p_tid || !stack_size) + return BHT_ERROR; + + /* Create and initialize thread data */ + thread_data_size = offsetof(os_thread_data, stack) + stack_size; + if (!(thread_data = BH_MALLOC(thread_data_size))) { + return BHT_ERROR; + } + + memset(thread_data, 0, thread_data_size); + mutex_init(&thread_data->wait_list_lock); + thread_data->stack_size = stack_size; + thread_data->start_routine = start; + thread_data->arg = arg; + + /* Create the thread &*/ + if (!((tid = thread_create( thread_data->stack, + stack_size,prio,0, os_thread_wrapper, thread_data,"WASM")))) { + BH_FREE(thread_data); + return BHT_ERROR; + } + + thread_data->tid = tid; + + /* Set thread custom data */ + thread_data_list_add(thread_data); + *p_tid = tid; + return BHT_OK; +} + +korp_tid +os_self_thread() +{ + return (korp_tid) thread_getpid(); +} + +int +os_thread_join (korp_tid thread, void **value_ptr) +{ + // will test if thread is still working, + // wait if it is +// (void) value_ptr; + os_thread_data *thread_data; + os_thread_wait_node node; + + sema_create(&node.sem, 0); + node.next = NULL; + + /* Get thread data */ + thread_data = thread_data_list_lookup(thread); + if(thread_data == NULL){ + //thread not found + sema_destroy(&node.sem); + return BHT_ERROR; + } + bh_assert(thread_data != NULL); + + mutex_lock(&thread_data->wait_list_lock); + if (!thread_data->thread_wait_list) + thread_data->thread_wait_list = &node; + else { + /* Add to end of waiting list */ + os_thread_wait_node *p = thread_data->thread_wait_list; + while (p->next) + p = p->next; + p->next = &node; + } + mutex_unlock(&thread_data->wait_list_lock); + + sema_wait(&node.sem); + //get the return value pointer conted may not be availible after return + if(value_ptr) (* value_ptr) = node.ret; + /* Wait some time for the thread to be actually terminated */ +// TODO: k_sleep(100); + + //TODO: bump target prio to make it finish and free its resources + thread_yield(); + + //node has done its job + sema_destroy(&node.sem); + + return BHT_OK; +} + + + +// int vm_mutex_trylock(korp_mutex *mutex) +// { +// return mutex_trylock(mutex); +// } + +int +os_mutex_init(korp_mutex *mutex) +{ + mutex_init(mutex); + return BHT_OK; +} + +int +os_mutex_destroy(korp_mutex *mutex) +{ + (void) mutex; + return BHT_OK; +} + +int +os_mutex_lock(korp_mutex *mutex) +{ + mutex_lock(mutex); + return 0; //Riot mutexes do not return until success +} + +int +os_mutex_unlock(korp_mutex *mutex) +{ + mutex_unlock(mutex); + return 0; //Riot mutexes do not return until success + +} + +int +os_cond_init(korp_cond *cond) +{ + mutex_init(&cond->wait_list_lock); + cond->thread_wait_list = NULL; + return BHT_OK; +} + +int +os_cond_destroy(korp_cond *cond) +{ + (void) cond; + return BHT_OK; +} + +static int +os_cond_wait_internal(korp_cond *cond, korp_mutex *mutex, + bool timed, uint64 useconds) +{ + os_thread_wait_node *node; + + /* Create wait node and append it to wait list */ + if (!(node = BH_MALLOC(sizeof(os_thread_wait_node)))) + return BHT_ERROR; + + sema_create(&node->sem, 0); + node->next = NULL; + + mutex_lock(&cond->wait_list_lock); + if (!cond->thread_wait_list) + cond->thread_wait_list = node; + else { + /* Add to end of wait list */ + os_thread_wait_node *p = cond->thread_wait_list; + while (p->next) + p = p->next; + p->next = node; + } + mutex_unlock(&cond->wait_list_lock); + + /* Unlock mutex, wait sem and lock mutex again */ + mutex_unlock(mutex); + if(timed) + sema_wait(&node->sem); + else + sema_wait_timed(&node->sem,useconds); + mutex_lock(mutex); + + /* Remove wait node from wait list */ + mutex_lock(&cond->wait_list_lock); + if (cond->thread_wait_list == node) + cond->thread_wait_list = node->next; + else { + /* Remove from the wait list */ + os_thread_wait_node *p = cond->thread_wait_list; + while (p->next != node) + p = p->next; + p->next = node->next; + } + BH_FREE(node); + mutex_unlock(&cond->wait_list_lock); + + return BHT_OK; +} + +int +os_cond_wait(korp_cond *cond, korp_mutex *mutex) +{ + return os_cond_wait_internal(cond, mutex, false, 0); +} + +int +os_cond_reltimedwait(korp_cond *cond, korp_mutex *mutex, int useconds) +{ + uint64 useconds64 = (uint64) useconds; + return os_cond_wait_internal(cond, mutex, + (useconds64 != BHT_WAIT_FOREVER), useconds64); +} + +int +os_cond_signal(korp_cond *cond) +{ + /* Signal the head wait node of wait list */ + mutex_lock(&cond->wait_list_lock); + if (cond->thread_wait_list) + sema_post(&cond->thread_wait_list->sem); + mutex_unlock(&cond->wait_list_lock); + + return BHT_OK; +} + +uint8 *os_thread_get_stack_boundary() +{ +#if defined(DEVELHELP) || defined(SCHED_TEST_STACK) \ + || defined(MODULE_MPU_STACK_GUARD) + return (uint8*)thread_get_active()->stack_start; +#else + return NULL; +#endif +} diff --git a/core/shared/platform/riot/riot_time.c b/core/shared/platform/riot/riot_time.c new file mode 100644 index 000000000..8b480f69c --- /dev/null +++ b/core/shared/platform/riot/riot_time.c @@ -0,0 +1,15 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * Copyright (C) 2020 TU Bergakademie Freiberg Karl Fessel + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "platform_api_vmcore.h" +#include + +uint64 +os_time_get_boot_microsecond() +{ + return xtimer_now_usec64(); +} + diff --git a/core/shared/platform/riot/shared_platform.cmake b/core/shared/platform/riot/shared_platform.cmake new file mode 100644 index 000000000..52cf90463 --- /dev/null +++ b/core/shared/platform/riot/shared_platform.cmake @@ -0,0 +1,17 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# Copyright (C) 2020 TU Bergakademie Freiberg Karl Fessel +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +set (PLATFORM_SHARED_DIR ${CMAKE_CURRENT_LIST_DIR}) + +add_definitions(-DBH_PLATFORM_RIOT) + +include_directories(${PLATFORM_SHARED_DIR}) +include_directories(${PLATFORM_SHARED_DIR}/../include) + +# include (${CMAKE_CURRENT_LIST_DIR}/../common/math/platform_api_math.cmake) + +file (GLOB_RECURSE source_all ${PLATFORM_SHARED_DIR}/*.c) + +set (PLATFORM_SHARED_SOURCE ${source_all} ${PLATFORM_COMMON_MATH_SOURCE}) + diff --git a/product-mini/platforms/riot/CMakeLists.txt b/product-mini/platforms/riot/CMakeLists.txt new file mode 100644 index 000000000..9b8b2229c --- /dev/null +++ b/product-mini/platforms/riot/CMakeLists.txt @@ -0,0 +1,59 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# Copyright (C) 2020 TU Bergakademie Freiberg Karl Fessel +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required(VERSION 3.8.2) + +set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY") + +project(NONE) + +enable_language (ASM) + +set (WAMR_BUILD_PLATFORM "riot") + +# Build as X86_32 by default, change to "AARCH64[sub]", "ARM[sub]", "THUMB[sub]", "MIPS" or "XTENSA" +# if we want to support arm, thumb, mips or xtensa + + +if (NOT DEFINED WAMR_BUILD_TARGET) + set (WAMR_BUILD_TARGET "X86_32") +endif () + +if (NOT DEFINED WAMR_BUILD_INTERP) + # Enable Interpreter by default + set (WAMR_BUILD_INTERP 1) +endif () + +if (NOT DEFINED WAMR_BUILD_AOT) + # Disable AOT by default. + set (WAMR_BUILD_AOT 0) +endif () + +if (NOT DEFINED WAMR_BUILD_LIBC_BUILTIN) + # Enable libc builtin support by default + set (WAMR_BUILD_LIBC_BUILTIN 1) +endif () + +if (NOT DEFINED WAMR_BUILD_LIBC_WASI) + # Disable libc wasi support by default + set (WAMR_BUILD_LIBC_WASI 0) +endif () + +if (NOT DEFINED WAMR_ROOT_DIR) + # this assumption is true if this file is copied to WAMR_ROOT + set (WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}) +endif () + + +include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) + +# need includes from RIOT prepare them as a cmake list +string(REGEX MATCHALL "([^\ ]+\ |[^\ ]+$)" RIOT_INCLUDES_LIST "${RIOT_INCLUDES}") + +include_directories(SYSTEM ${RIOT_INCLUDES_LIST}) + +# target_sources( ${WAMR_RUNTIME_LIB_SOURCE} ) +# executable linking is done by RIOT build system + +add_library( wamr ${WAMR_RUNTIME_LIB_SOURCE}) diff --git a/product-mini/platforms/riot/Makefile b/product-mini/platforms/riot/Makefile new file mode 100644 index 000000000..a6df95494 --- /dev/null +++ b/product-mini/platforms/riot/Makefile @@ -0,0 +1,96 @@ +APPLICATION = wamr-mini +# If no BOARD is defined in the environment, use this default: +BOARD ?= native + +# This has to be the absolute path to the RIOT base directory: +RIOTBASE ?= $(CURDIR)/../../../../RIOT + +USEMODULE += xtimer +USEMODULE += sema + +WPEDANTIC := 0 +WERROR := 0 + +# Comment this out to disable code in RIOT that does safety checking +# which is not needed in a production environment but helps in the +# development process: +DEVELHELP ?= 1 + +# Change this to 0 show compiler invocation lines by default: +QUIET ?= 1 + +ARCHIVES += $(BINDIR)/libwamr.a + +#Load the usual RIOT make infastructure + +include $(RIOTBASE)/Makefile.include + + +WAMR_SOURCE = $(CURDIR)/../../.. +WAMR_BUILD_DIR = $(BINDIR)/wamr + +#less Wall TODO: get things fixed +CFLAGS := $(filter-out -pedantic, $(CFLAGS)) +CFLAGS += -Wno-format +CFLAGS += -Wno-strict-prototypes +CFLAGS += -Wno-old-style-definition +CFLAGS += -Wno-cast-function-type + +WAMR_CORE = $(WAMR_SOURCE)/core +IWASM_ROOT = $(WAMR_CORE)/iwasm +SHARED_LIB_ROOT = $(WAMR_CORE)/shared + +IWASM_INCLUDES += ${IWASM_ROOT}/include \ + ${SHARED_LIB_ROOT}/platform/include \ + ${SHARED_LIB_ROOT}/platform/riot \ + + +INCLUDES += $(addprefix -I,${IWASM_INCLUDES}) + + + +RIOT_INCLUDES = $(filter-out -%,$(subst -I,,$(INCLUDES))) + +#WAMR_BUILD_TARGET is "X86_32" "AARCH64[sub]", "ARM[sub]", +# "THUMB[sub]", "MIPS" or "XTENSA" +#no msp430, no AVR support for now + +#translate (CPU_ARCH) to Build Target +ifeq ($(CPU),native) +#$(CPU) is defined for every CPU +#Riot native is x86_32 + WAMR_BUILD_TARGET = X86_32 +else ifeq ($(findstring arm,$(CPU_ARCH)),arm) + WAMR_BUILD_TARGET = THUMB +else ifeq ($(CPU_ARCH),mips32r2) + WAMR_BUILD_TARGET = MIPS +else ifeq ($(CPU_ARCH),xtensa) + WAMR_BUILD_TARGET = XTENSA +endif + +ifeq ($(QUIET), 0) + CMAKEMAKEFLAGS += VERBOSE=1 +endif + + +$(BINDIR)/libwamr.a: $(WAMR_BUILD_DIR)/libwamr.a + cp $< $@ + +$(WAMR_BUILD_DIR)/libwamr.a: $(WAMR_BUILD_DIR)/Makefile + $(MAKE) -C $(WAMR_BUILD_DIR) $(CMAKEMAKEFLAGS) + +$(WAMR_BUILD_DIR)/Makefile: CMakeLists.txt + cmake -B$(WAMR_BUILD_DIR) \ + "-DRIOT_INCLUDES=$(RIOT_INCLUDES)"\ + -DWAMR_ROOT_DIR=$(WAMR_SOURCE)\ + -DWAMR_BUILD_TARGET=$(WAMR_BUILD_TARGET)\ + -DCMAKE_SYSTEM_NAME=Generic \ + -DCMAKE_SYSTEM_PROCESSOR="$(MCPU)" \ + -DCMAKE_C_COMPILER=$(CC) \ + -DCMAKE_C_COMPILER_WORKS=TRUE \ + +print_build_target: + @echo CPU_ARCH: $(CPU_ARCH) + @echo CPU: $(CPU) + @echo CFLAGS: $(CFLAGS) + @echo WAMR_BUILD_TARGET: $(WAMR_BUILD_TARGET) diff --git a/product-mini/platforms/riot/iwasmt.c b/product-mini/platforms/riot/iwasmt.c new file mode 100644 index 000000000..7f6b75fbc --- /dev/null +++ b/product-mini/platforms/riot/iwasmt.c @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * Copyright (C) 2020 TU Bergakademie Freiberg Karl Fessel + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +// +#include +#include +#include + +#include + +// #include "platform_api_extension.h" +#include "wasm_export.h" + +#include + +/*provide some test program*/ +#include "test_wasm.h" + +#define DEFAULT_THREAD_STACKSIZE (6 * 1024) +#define DEFAULT_THREAD_PRIORITY 50 + +static int app_argc; +static char **app_argv; + +static void* +app_instance_main(wasm_module_inst_t module_inst) +{ + const char *exception; + + wasm_application_execute_main(module_inst, app_argc, app_argv); + if ((exception = wasm_runtime_get_exception(module_inst))){ + puts(exception); + } + return NULL; +} + + +void * +iwasm_t(void *arg1) +{ + wasm_module_t wasm_module = (wasm_module_t) arg1; + wasm_module_inst_t wasm_module_inst = NULL; + char error_buf[128]; + + /* instantiate the module */ + if (!(wasm_module_inst = wasm_runtime_instantiate(wasm_module, 8 * 1024, + 8 * 1024, error_buf, sizeof(error_buf)))) { + puts(error_buf); + }else{ + app_instance_main(wasm_module_inst); + /* destroy the module instance */ + wasm_runtime_deinstantiate(wasm_module_inst); + } + return NULL; +} + +void * +iwasm_main(void *arg1) +{ + (void) arg1; /*unused*/ + uint8_t *wasm_file_buf = NULL; + unsigned wasm_file_buf_size = 0; + wasm_module_t wasm_module = NULL; + char error_buf[128]; + + RuntimeInitArgs init_args; + +//chose allocator +#define FUNC_ALLOC +//#define POOL_ALLOC + + memset(&init_args, 0, sizeof(RuntimeInitArgs)); +#ifdef POOL_ALLOC + static char global_heap_buf[256 * 1024] = { 0 };//(256 kB) + + init_args.mem_alloc_type = Alloc_With_Pool; + init_args.mem_alloc_option.pool.heap_buf = global_heap_buf; + init_args.mem_alloc_option.pool.heap_size = sizeof(global_heap_buf); +#elif defined(FUNC_ALLOC) + init_args.mem_alloc_type = Alloc_With_Allocator; + init_args.mem_alloc_option.allocator.malloc_func = malloc; + init_args.mem_alloc_option.allocator.realloc_func = realloc; + init_args.mem_alloc_option.allocator.free_func = free; +#else + init_args.mem_alloc_type = Alloc_With_System_Allocator; +#endif + + /* initialize runtime environment */ + if (!wasm_runtime_full_init(&init_args)) { + puts("Init runtime environment failed."); + return NULL; + } + + + /* load WASM byte buffer from byte buffer of include file */ + wasm_file_buf = (uint8_t *) wasm_test_file; + wasm_file_buf_size = sizeof(wasm_test_file); + + /* load WASM module */ + if (!(wasm_module = wasm_runtime_load(wasm_file_buf, wasm_file_buf_size, + error_buf, sizeof(error_buf)))) { + puts(error_buf); + + }else{ + iwasm_t(wasm_module); + wasm_runtime_unload(wasm_module); + } + + wasm_runtime_destroy(); + return NULL; +} + +bool +iwasm_init(void) +{ + struct{ + char * stack; + int stacksize; + uint8_t priority; + int flags; + thread_task_func_t task_func; + void * arg; + const char * name; + } b = { + .stacksize = DEFAULT_THREAD_STACKSIZE, + .priority = 8, + .flags = 0, + .task_func = iwasm_main, + .arg = NULL, + .name = "simple_wamr" + }; + + b.stack=malloc(b.stacksize); + kernel_pid_t tpid = thread_create (b.stack, b.stacksize, b.priority, b.flags, b.task_func, b.arg, b.name); + + return tpid != 0 ? true : false;; +} +#define telltruth(X) ((X) ? "true" : "false") + + +int +main(void) +{ + printf("iwasm_initilised: %s\n",telltruth(iwasm_init())); +} diff --git a/product-mini/platforms/riot/test_wasm.h b/product-mini/platforms/riot/test_wasm.h new file mode 100644 index 000000000..0c343024a --- /dev/null +++ b/product-mini/platforms/riot/test_wasm.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +/** + * The byte array buffer is the file content of a test wasm binary file, + * which is compiled by wasi-sdk toolchain from C source file of: + * product-mini/app-samples/hello-world/main.c. + */ +unsigned char wasm_test_file[] = { + 0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x10, 0x03, 0x60, + 0x01, 0x7F, 0x01, 0x7F, 0x60, 0x02, 0x7F, 0x7F, 0x01, 0x7F, 0x60, 0x01, + 0x7F, 0x00, 0x02, 0x31, 0x04, 0x03, 0x65, 0x6E, 0x76, 0x04, 0x70, 0x75, + 0x74, 0x73, 0x00, 0x00, 0x03, 0x65, 0x6E, 0x76, 0x06, 0x6D, 0x61, 0x6C, + 0x6C, 0x6F, 0x63, 0x00, 0x00, 0x03, 0x65, 0x6E, 0x76, 0x06, 0x70, 0x72, + 0x69, 0x6E, 0x74, 0x66, 0x00, 0x01, 0x03, 0x65, 0x6E, 0x76, 0x04, 0x66, + 0x72, 0x65, 0x65, 0x00, 0x02, 0x03, 0x02, 0x01, 0x01, 0x04, 0x05, 0x01, + 0x70, 0x01, 0x01, 0x01, 0x05, 0x03, 0x01, 0x00, 0x01, 0x06, 0x13, 0x03, + 0x7F, 0x01, 0x41, 0xC0, 0x28, 0x0B, 0x7F, 0x00, 0x41, 0xBA, 0x08, 0x0B, + 0x7F, 0x00, 0x41, 0xC0, 0x28, 0x0B, 0x07, 0x2C, 0x04, 0x06, 0x6D, 0x65, + 0x6D, 0x6F, 0x72, 0x79, 0x02, 0x00, 0x0A, 0x5F, 0x5F, 0x64, 0x61, 0x74, + 0x61, 0x5F, 0x65, 0x6E, 0x64, 0x03, 0x01, 0x0B, 0x5F, 0x5F, 0x68, 0x65, + 0x61, 0x70, 0x5F, 0x62, 0x61, 0x73, 0x65, 0x03, 0x02, 0x04, 0x6D, 0x61, + 0x69, 0x6E, 0x00, 0x04, 0x0A, 0xB2, 0x01, 0x01, 0xAF, 0x01, 0x01, 0x03, + 0x7F, 0x23, 0x80, 0x80, 0x80, 0x80, 0x00, 0x41, 0x20, 0x6B, 0x22, 0x02, + 0x24, 0x80, 0x80, 0x80, 0x80, 0x00, 0x41, 0x9B, 0x88, 0x80, 0x80, 0x00, + 0x10, 0x80, 0x80, 0x80, 0x80, 0x00, 0x1A, 0x02, 0x40, 0x02, 0x40, 0x41, + 0x80, 0x08, 0x10, 0x81, 0x80, 0x80, 0x80, 0x00, 0x22, 0x03, 0x0D, 0x00, + 0x41, 0xA8, 0x88, 0x80, 0x80, 0x00, 0x10, 0x80, 0x80, 0x80, 0x80, 0x00, + 0x1A, 0x41, 0x7F, 0x21, 0x04, 0x0C, 0x01, 0x0B, 0x20, 0x02, 0x20, 0x03, + 0x36, 0x02, 0x10, 0x41, 0x80, 0x88, 0x80, 0x80, 0x00, 0x20, 0x02, 0x41, + 0x10, 0x6A, 0x10, 0x82, 0x80, 0x80, 0x80, 0x00, 0x1A, 0x41, 0x00, 0x21, + 0x04, 0x20, 0x03, 0x41, 0x04, 0x6A, 0x41, 0x00, 0x2F, 0x00, 0x91, 0x88, + 0x80, 0x80, 0x00, 0x3B, 0x00, 0x00, 0x20, 0x03, 0x41, 0x00, 0x28, 0x00, + 0x8D, 0x88, 0x80, 0x80, 0x00, 0x36, 0x00, 0x00, 0x20, 0x02, 0x20, 0x03, + 0x36, 0x02, 0x00, 0x41, 0x93, 0x88, 0x80, 0x80, 0x00, 0x20, 0x02, 0x10, + 0x82, 0x80, 0x80, 0x80, 0x00, 0x1A, 0x20, 0x03, 0x10, 0x83, 0x80, 0x80, + 0x80, 0x00, 0x0B, 0x20, 0x02, 0x41, 0x20, 0x6A, 0x24, 0x80, 0x80, 0x80, + 0x80, 0x00, 0x20, 0x04, 0x0B, 0x0B, 0x41, 0x01, 0x00, 0x41, 0x80, 0x08, + 0x0B, 0x3A, 0x62, 0x75, 0x66, 0x20, 0x70, 0x74, 0x72, 0x3A, 0x20, 0x25, + 0x70, 0x0A, 0x00, 0x31, 0x32, 0x33, 0x34, 0x0A, 0x00, 0x62, 0x75, 0x66, + 0x3A, 0x20, 0x25, 0x73, 0x00, 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, + 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x00, 0x6D, 0x61, 0x6C, 0x6C, 0x6F, 0x63, + 0x20, 0x62, 0x75, 0x66, 0x20, 0x66, 0x61, 0x69, 0x6C, 0x65, 0x64, 0x00 +}; From 4787b150b86ff1153559fbcc99c45df17a64a507 Mon Sep 17 00:00:00 2001 From: lum1n0us <62137521+lum1n0us@users.noreply.github.com> Date: Fri, 16 Oct 2020 17:43:57 +0800 Subject: [PATCH 099/207] Enable multi-module support for wasm-c-api (#426) it is allowed that all imported functions and globals can be linked by multi-module feature automatically or by wasm-c-api manually --- .github/workflows/linux.yml | 8 +- .github/workflows/mac.yml | 6 + core/iwasm/common/wasm_c_api.c | 70 +++++--- core/iwasm/common/wasm_runtime_common.c | 9 +- core/iwasm/common/wasm_runtime_common.h | 3 + core/iwasm/interpreter/wasm.h | 1 + core/iwasm/interpreter/wasm_interp_classic.c | 8 +- core/iwasm/interpreter/wasm_interp_fast.c | 18 +- core/iwasm/interpreter/wasm_loader.c | 69 ++------ core/iwasm/interpreter/wasm_mini_loader.c | 11 +- core/iwasm/interpreter/wasm_runtime.c | 115 +++++++----- core/shared/mem-alloc/tlsf | 1 + doc/release_ack.md | 61 +++++++ doc/roadmap.md | 23 +++ samples/wasm-c-api/CMakeLists.txt | 62 ++++--- samples/wasm-c-api/README.md | 15 +- samples/wasm-c-api/src/callback.c | 10 ++ samples/wasm-c-api/src/callback.wasm | Bin 102 -> 0 bytes samples/wasm-c-api/src/global.c | 10 ++ samples/wasm-c-api/src/global.wasm | Bin 576 -> 0 bytes .../wasm-c-api/src/globalexportimport-0.wat | 5 + .../wasm-c-api/src/globalexportimport-1.wat | 7 + samples/wasm-c-api/src/globalexportimport.c | 166 ++++++++++++++++++ samples/wasm-c-api/src/hello.c | 10 ++ samples/wasm-c-api/src/hello.wasm | Bin 71 -> 0 bytes .../wasm-c-api/src/utils/multi_module_utils.c | 47 +++++ 26 files changed, 550 insertions(+), 185 deletions(-) create mode 160000 core/shared/mem-alloc/tlsf create mode 100644 doc/release_ack.md create mode 100644 doc/roadmap.md delete mode 100644 samples/wasm-c-api/src/callback.wasm delete mode 100644 samples/wasm-c-api/src/global.wasm create mode 100644 samples/wasm-c-api/src/globalexportimport-0.wat create mode 100644 samples/wasm-c-api/src/globalexportimport-1.wat create mode 100644 samples/wasm-c-api/src/globalexportimport.c delete mode 100644 samples/wasm-c-api/src/hello.wasm create mode 100644 samples/wasm-c-api/src/utils/multi_module_utils.c diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 128af62e8..22d13e57e 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -84,12 +84,18 @@ jobs: cmake .. -DWAMR_BUILD_CUSTOM_NAME_SECTION=1 make cd .. && rm -rf build - - name: download wasi-sdk + - name: download and install wasi-sdk run: | cd /opt wget https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-8/wasi-sdk-8.0-linux.tar.gz tar -xzf wasi-sdk-8.0-linux.tar.gz mv wasi-sdk-8.0 wasi-sdk + - name: download and install wabt + run: | + cd /opt + wget https://github.com/WebAssembly/wabt/releases/download/1.0.19/wabt-1.0.19-ubuntu.tar.gz + tar -xzf wabt-1.0.19-ubuntu.tar.gz + mv wabt-1.0.19 wabt - name: Build Sample [wasm-c-api] run: | cd samples/wasm-c-api diff --git a/.github/workflows/mac.yml b/.github/workflows/mac.yml index 361a9c2e4..6c8704b2b 100644 --- a/.github/workflows/mac.yml +++ b/.github/workflows/mac.yml @@ -84,6 +84,12 @@ jobs: cmake .. -DWAMR_BUILD_CUSTOM_NAME_SECTION=1 make cd .. && rm -rf build + - name: download and install wabt + run: | + cd /opt + sudo wget https://github.com/WebAssembly/wabt/releases/download/1.0.19/wabt-1.0.19-macos.tar.gz + sudo tar -xzf wabt-1.0.19-macos.tar.gz + sudo mv wabt-1.0.19 wabt - name: Build Sample [wasm-c-api] run: | cd samples/wasm-c-api diff --git a/core/iwasm/common/wasm_c_api.c b/core/iwasm/common/wasm_c_api.c index f87edf6be..0ef9d4ceb 100644 --- a/core/iwasm/common/wasm_c_api.c +++ b/core/iwasm/common/wasm_c_api.c @@ -1696,7 +1696,14 @@ interp_global_set(const WASMModuleInstance *inst_interp, const WASMGlobalInstance *global_interp = inst_interp->globals + global_idx_rt; uint8 val_type_rt = global_interp->type; +#if WASM_ENABLE_MULTI_MODULE != 0 + uint8 *data = global_interp->import_global_inst + ? global_interp->import_module_inst->global_data + + global_interp->import_global_inst->data_offset + : inst_interp->global_data + global_interp->data_offset; +#else uint8 *data = inst_interp->global_data + global_interp->data_offset; +#endif bool ret = true; switch (val_type_rt) { @@ -1732,7 +1739,14 @@ interp_global_get(const WASMModuleInstance *inst_interp, { WASMGlobalInstance *global_interp = inst_interp->globals + global_idx_rt; uint8 val_type_rt = global_interp->type; +#if WASM_ENABLE_MULTI_MODULE != 0 + uint8 *data = global_interp->import_global_inst + ? global_interp->import_module_inst->global_data + + global_interp->import_global_inst->data_offset + : inst_interp->global_data + global_interp->data_offset; +#else uint8 *data = inst_interp->global_data + global_interp->data_offset; +#endif bool ret = true; switch (val_type_rt) { @@ -2080,6 +2094,7 @@ interp_link_global(const WASMModule *module_interp, } import->global_idx_rt = global_idx_rt; + imported_global_interp->u.global.is_linked = true; return true; } @@ -2432,35 +2447,44 @@ wasm_instance_new(wasm_store_t *store, } /* link module and imports */ - if (INTERP_MODE == current_runtime_mode()) { + if (imports) { + if (INTERP_MODE == current_runtime_mode()) { #if WASM_ENABLE_INTERP != 0 - import_count = ((WASMModule *)*module)->import_count; - INIT_VEC(instance->imports, wasm_extern_vec, import_count); - if (!instance->imports) { - goto failed; - } + import_count = ((WASMModule *)*module)->import_count; + INIT_VEC(instance->imports, wasm_extern_vec, import_count); + if (!instance->imports) { + goto failed; + } - import_count = interp_link(instance, (WASMModule *)*module, - (wasm_extern_t **)imports); + if (import_count) { + import_count = interp_link(instance, (WASMModule *)*module, + (wasm_extern_t **)imports); + if ((int32)import_count < 0) { + goto failed; + } + } #endif - } - else { + } + else { #if WASM_ENABLE_AOT != 0 - import_count = ((AOTModule *)*module)->import_func_count - + ((AOTModule *)*module)->import_global_count - + ((AOTModule *)*module)->import_memory_count - + ((AOTModule *)*module)->import_table_count; - INIT_VEC(instance->imports, wasm_extern_vec, import_count); - if (!instance->imports) { - goto failed; - } + import_count = ((AOTModule *)*module)->import_func_count + + ((AOTModule *)*module)->import_global_count + + ((AOTModule *)*module)->import_memory_count + + ((AOTModule *)*module)->import_table_count; + INIT_VEC(instance->imports, wasm_extern_vec, import_count); + if (!instance->imports) { + goto failed; + } - import_count = - aot_link(instance, (AOTModule *)*module, (wasm_extern_t **)imports); + if (import_count) { + import_count = aot_link(instance, (AOTModule *)*module, + (wasm_extern_t **)imports); + if ((int32)import_count < 0) { + goto failed; + } + } #endif - } - if ((int32)import_count < 0) { - goto failed; + } } instance->inst_comm_rt = wasm_runtime_instantiate( diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index abd2d752a..8d75eca45 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -539,6 +539,12 @@ wasm_runtime_destroy_loading_module_list() } #endif /* WASM_ENABLE_MULTI_MODULE */ +bool +wasm_runtime_is_host_module(const char *module_name) +{ + return strlen(module_name) == 0; +} + bool wasm_runtime_is_built_in_module(const char *module_name) { @@ -2342,7 +2348,8 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, wasm_runtime_set_exception(module_inst, buf); goto fail; } - type = wasm_func->u.func->func_type; + type = wasm_func->is_import_func ? wasm_func->u.func_import->func_type + : wasm_func->u.func->func_type; argc1 = wasm_func->param_cell_num; cell_num = argc1 > wasm_func->ret_cell_num ? argc1 : wasm_func->ret_cell_num; diff --git a/core/iwasm/common/wasm_runtime_common.h b/core/iwasm/common/wasm_runtime_common.h index 8dd98dc41..111bfec2c 100644 --- a/core/iwasm/common/wasm_runtime_common.h +++ b/core/iwasm/common/wasm_runtime_common.h @@ -373,6 +373,9 @@ void wasm_runtime_destroy_loading_module_list(); #endif /* WASM_ENALBE_MULTI_MODULE */ +bool +wasm_runtime_is_host_module(const char *module_name); + bool wasm_runtime_is_built_in_module(const char *module_name); diff --git a/core/iwasm/interpreter/wasm.h b/core/iwasm/interpreter/wasm.h index f45464e0c..fea564260 100644 --- a/core/iwasm/interpreter/wasm.h +++ b/core/iwasm/interpreter/wasm.h @@ -177,6 +177,7 @@ typedef struct WASMGlobalImport { bool is_mutable; /* global data after linked */ WASMValue global_data_linked; + bool is_linked; #if WASM_ENABLE_MULTI_MODULE != 0 /* imported function pointer after linked */ /* TODO: remove if not needed */ diff --git a/core/iwasm/interpreter/wasm_interp_classic.c b/core/iwasm/interpreter/wasm_interp_classic.c index e18235d8b..d8ad05053 100644 --- a/core/iwasm/interpreter/wasm_interp_classic.c +++ b/core/iwasm/interpreter/wasm_interp_classic.c @@ -1362,12 +1362,8 @@ label_pop_csp_n: /* always call module own functions */ cur_func = module->functions + fidx; - if (cur_func->is_import_func -#if WASM_ENABLE_MULTI_MODULE != 0 - && !cur_func->import_func_inst -#endif - ) - cur_func_type = cur_func->u.func_import->func_type; + if (cur_func->is_import_func) + cur_func_type = cur_func->u.func_import->func_type; else cur_func_type = cur_func->u.func->func_type; if (!wasm_type_equal(cur_type, cur_func_type)) { diff --git a/core/iwasm/interpreter/wasm_interp_fast.c b/core/iwasm/interpreter/wasm_interp_fast.c index 37a10ad2a..643f680f7 100644 --- a/core/iwasm/interpreter/wasm_interp_fast.c +++ b/core/iwasm/interpreter/wasm_interp_fast.c @@ -1270,11 +1270,7 @@ recover_br_info: WASMType *func_type; uint32 off, ret_offset; uint8 *ret_types; - if (cur_func->is_import_func -#if WASM_ENABLE_MULTI_MODULE != 0 - && !cur_func->import_func_inst -#endif - ) + if (cur_func->is_import_func) func_type = cur_func->u.func_import->func_type; else func_type = cur_func->u.func->func_type; @@ -1354,11 +1350,7 @@ recover_br_info: /* always call module own functions */ cur_func = module->functions + fidx; - if (cur_func->is_import_func -#if WASM_ENABLE_MULTI_MODULE != 0 - && !cur_func->import_func_inst -#endif - ) + if (cur_func->is_import_func) cur_func_type = cur_func->u.func_import->func_type; else cur_func_type = cur_func->u.func->func_type; @@ -3253,11 +3245,7 @@ recover_br_info: * values' offset so we must skip remain return values' offsets. */ WASMType *func_type; - if (cur_func->is_import_func -#if WASM_ENABLE_MULTI_MODULE != 0 - && !cur_func->import_func_inst -#endif - ) + if (cur_func->is_import_func) func_type = cur_func->u.func_import->func_type; else func_type = cur_func->u.func->func_type; diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index 804c497c3..f542f9deb 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -796,10 +796,11 @@ load_function_import(const WASMModule *parent_module, WASMModule *sub_module, declare_func_type = parent_module->types[declare_type_index]; - is_built_in_module = wasm_runtime_is_built_in_module(sub_module_name); - if (is_built_in_module) { - LOG_DEBUG("%s is a function of a built-in module %s", - function_name, sub_module_name); + if (wasm_runtime_is_host_module(sub_module_name)) { + /* do nothing, wait for injecting host created fuctions */ + } + else if ((is_built_in_module = + wasm_runtime_is_built_in_module(sub_module_name))) { /* check built-in modules */ linked_func = wasm_native_resolve_symbol(sub_module_name, function_name, @@ -810,8 +811,6 @@ load_function_import(const WASMModule *parent_module, WASMModule *sub_module, } #if WASM_ENABLE_MULTI_MODULE != 0 else { - LOG_DEBUG("%s is a function of a sub-module %s", - function_name, sub_module_name); linked_func = wasm_loader_resolve_function(sub_module_name, function_name, declare_func_type, @@ -820,19 +819,6 @@ load_function_import(const WASMModule *parent_module, WASMModule *sub_module, } #endif - if (!linked_func) { -#if WASM_ENABLE_SPEC_TEST != 0 - set_error_buf(error_buf, error_buf_size, - "unknown import or incompatible import type"); - return false; -#else -#if WASM_ENABLE_WAMR_COMPILER == 0 - LOG_WARNING("warning: fail to link import function (%s, %s)", - sub_module_name, function_name); -#endif -#endif - } - function->module_name = sub_module_name; function->field_name = function_name; function->func_type = declare_func_type; @@ -1096,8 +1082,6 @@ load_global_import(const WASMModule *parent_module, const uint8 *p = *p_buf, *p_end = buf_end; uint8 declare_type = 0; uint8 declare_mutable = 0; - bool is_mutable = false; - bool ret = false; CHECK_BUF(p, p_end, 2); declare_type = read_uint8(p); @@ -1109,50 +1093,33 @@ load_global_import(const WASMModule *parent_module, return false; } - is_mutable = declare_mutable & 1 ? true : false; - -#if WASM_ENABLE_LIBC_BUILTIN != 0 - ret = wasm_runtime_is_built_in_module(sub_module_name); - if (ret) { - /* check built-in modules */ - ret = wasm_native_lookup_libc_builtin_global(sub_module_name, - global_name, global); - if (ret) { - LOG_DEBUG("(%s, %s) is a global of a built-in module", - sub_module_name, global_name); - } + if (wasm_runtime_is_host_module(sub_module_name)) { + /* do nothing, let host injects the symbol */ + } + else if (wasm_runtime_is_built_in_module(sub_module_name)) { + /* check built-in modules */ + global->is_linked = wasm_native_lookup_libc_builtin_global( + sub_module_name, global_name, global); } -#endif /* WASM_ENABLE_LIBC_BUILTIN */ - #if WASM_ENABLE_MULTI_MODULE != 0 - if (!ret) { + else { /* check sub modules */ WASMGlobal *linked_global = wasm_loader_resolve_global(sub_module_name, global_name, declare_type, declare_mutable, error_buf, error_buf_size); if (linked_global) { - LOG_DEBUG("(%s, %s) is a global of external module", - sub_module_name, global_name); global->import_module = sub_module; global->import_global_linked = linked_global; - ret = true; + global->is_linked = true; } } #endif - if (!ret) { -#if WASM_ENABLE_SPEC_TEST != 0 - set_error_buf(error_buf, error_buf_size, - "unknown import or incompatible import type"); - return false; -#endif - } - global->module_name = sub_module_name; global->field_name = global_name; global->type = declare_type; - global->is_mutable = is_mutable; + global->is_mutable = (declare_mutable == 1); return true; fail: return false; @@ -1363,8 +1330,7 @@ load_depended_module(const WASMModule *parent_module, ret = reader(sub_module_name, &buffer, &buffer_size); if (!ret) { LOG_DEBUG("read the file of %s failed", sub_module_name); - set_error_buf_v(error_buf, error_buf_size, - "failed to read module file of %s", + set_error_buf_v(error_buf, error_buf_size, "unknown import", sub_module_name); goto DELETE_FROM_LOADING_LIST; } @@ -1568,7 +1534,8 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, LOG_DEBUG("import #%d: (%s, %s)", i, sub_module_name, field_name); #if WASM_ENABLE_MULTI_MODULE != 0 /* assume built-in modules have been loaded */ - if (!wasm_runtime_is_built_in_module(sub_module_name)) { + if (!wasm_runtime_is_host_module(sub_module_name) + && !wasm_runtime_is_built_in_module(sub_module_name)) { LOG_DEBUG("%s is an exported field of a %s", field_name, sub_module_name); /* diff --git a/core/iwasm/interpreter/wasm_mini_loader.c b/core/iwasm/interpreter/wasm_mini_loader.c index c358dab45..d25a310fe 100644 --- a/core/iwasm/interpreter/wasm_mini_loader.c +++ b/core/iwasm/interpreter/wasm_mini_loader.c @@ -527,19 +527,10 @@ load_global_import(const WASMModule *parent_module, /* check built-in modules */ ret = wasm_native_lookup_libc_builtin_global(sub_module_name, global_name, global); - if (ret) { - LOG_DEBUG("(%s, %s) is a global of a built-in module", - sub_module_name, global_name); - } } #endif /* WASM_ENABLE_LIBC_BUILTIN */ - if (!ret) { - set_error_buf(error_buf, error_buf_size, - "unknown import or incompatible import type"); - return false; - } - + global->is_linked = ret; global->module_name = sub_module_name; global->field_name = global_name; global->type = declare_type; diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index 8a1e66fc3..bad93e1e5 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -550,56 +550,27 @@ functions_instantiate(const WASMModule *module, #if WASM_ENABLE_MULTI_MODULE != 0 if (import->u.function.import_module) { - LOG_DEBUG("(%s, %s) is a function of a sub-module", - import->u.function.module_name, - import->u.function.field_name); - function->import_module_inst = get_sub_module_inst(module_inst, import->u.function.import_module); - bh_assert(function->import_module_inst); - WASMFunction *function_linked = - import->u.function.import_func_linked; - - function->u.func = function_linked; - function->import_func_inst = - wasm_lookup_function(function->import_module_inst, - import->u.function.field_name, - NULL); - bh_assert(function->import_func_inst); - - function->param_cell_num = function->u.func->param_cell_num; - function->ret_cell_num = function->u.func->ret_cell_num; - function->local_cell_num = function->u.func->local_cell_num; - function->param_count = - (uint16)function->u.func->func_type->param_count; - function->local_count = (uint16)function->u.func->local_count; - function->param_types = function->u.func->func_type->types; - function->local_types = function->u.func->local_types; - function->local_offsets = function->u.func->local_offsets; -#if WASM_ENABLE_FAST_INTERP != 0 - function->const_cell_num = function->u.func->const_cell_num; -#endif + if (function->import_module_inst) { + function->import_func_inst = + wasm_lookup_function(function->import_module_inst, + import->u.function.field_name, NULL); + } } - else #endif /* WASM_ENABLE_MULTI_MODULE */ - { - LOG_DEBUG("(%s, %s) is a function of native", - import->u.function.module_name, - import->u.function.field_name); - function->u.func_import = &import->u.function; - function->param_cell_num = - import->u.function.func_type->param_cell_num; - function->ret_cell_num = - import->u.function.func_type->ret_cell_num; - function->param_count = - (uint16)function->u.func_import->func_type->param_count; - function->param_types = function->u.func_import->func_type->types; - function->local_cell_num = 0; - function->local_count = 0; - function->local_types = NULL; - } + function->u.func_import = &import->u.function; + function->param_cell_num = + import->u.function.func_type->param_cell_num; + function->ret_cell_num = import->u.function.func_type->ret_cell_num; + function->param_count = + (uint16)function->u.func_import->func_type->param_count; + function->param_types = function->u.func_import->func_type->types; + function->local_cell_num = 0; + function->local_count = 0; + function->local_types = NULL; function++; } @@ -1069,6 +1040,57 @@ sub_module_deinstantiate(WASMModuleInstance *module_inst) } #endif +static bool +check_linked_symbol(WASMModuleInstance *module_inst, char *error_buf, + uint32 error_buf_size) +{ + WASMModule *module = module_inst->module; + uint32 i; + + for (i = 0; i < module->import_function_count; i++) { + WASMFunctionImport *func = + &((module->import_functions + i)->u.function); + if (!func->func_ptr_linked +#if WASM_ENABLE_MULTI_MODULE != 0 + && !func->import_func_linked +#endif + ) { +#if WASM_ENABLE_SPEC_TEST != 0 + set_error_buf(error_buf, error_buf_size, + "unknown import or incompatible import type"); + return false; +#else +#if WASM_ENABLE_WAMR_COMPILER == 0 + LOG_WARNING("warning: fail to link import function (%s, %s)", + func->module_name, func->field_name); +#else + /* do nothing to avoid confused message */ +#endif /* WASM_ENABLE_WAMR_COMPILER == 0 */ +#endif /* WASM_ENABLE_SPEC_TEST != 0 */ + } + } + + for (i = 0; i < module->import_global_count; i++) { + WASMGlobalImport *global = &((module->import_globals + i)->u.global); + if (!global->is_linked) { +#if WASM_ENABLE_SPEC_TEST != 0 + set_error_buf(error_buf, error_buf_size, + "unknown import or incompatible import type"); + return false; +#else +#if WASM_ENABLE_WAMR_COMPILER == 0 + LOG_DEBUG("warning: fail to link import global (%s, %s)", + global->module_name, global->field_name); +#else + /* do nothing to avoid confused message */ +#endif /* WASM_ENABLE_WAMR_COMPILER == 0 */ +#endif /* WASM_ENABLE_SPEC_TEST != 0 */ + } + } + + return true; +} + /** * Instantiate module */ @@ -1215,6 +1237,11 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, bh_assert(global_data == global_data_end); } + if (!check_linked_symbol(module_inst, error_buf, error_buf_size)) { + wasm_deinstantiate(module_inst, false); + return NULL; + } + /* Initialize the memory data with data segment section */ module_inst->default_memory = module_inst->memory_count ? module_inst->memories[0] : NULL; diff --git a/core/shared/mem-alloc/tlsf b/core/shared/mem-alloc/tlsf new file mode 160000 index 000000000..a1f743ffa --- /dev/null +++ b/core/shared/mem-alloc/tlsf @@ -0,0 +1 @@ +Subproject commit a1f743ffac0305408b39e791e0ffb45f6d9bc777 diff --git a/doc/release_ack.md b/doc/release_ack.md new file mode 100644 index 000000000..a0adfff41 --- /dev/null +++ b/doc/release_ack.md @@ -0,0 +1,61 @@ +Major feature releases and contributors +========================================= + + +**May 07, 2019: WAMR first GitHub release** + +- Contributors: Wenyong Huang, Weining Lu, Lei Shi, Li Tian, Jizhao Zhang, Yi Zhang, Daoming Qiu, Xin Wang (Intel) + +**May 17, 2019: Application manager, WASM APP API, samples and test tools** + +- Contributors: Wenyong Huang, Weining Lu, Lei Shi, Li Tian, Jizhao Zhang, Yi Zhang, Daoming Qiu, Xin Wang (Intel) + + +**May 23, 2019: Support AliOS Things** + +- Contributor: JinZhou Zhu (Alibaba) + +**May 24, 2019: Support memory usage profiler** + +- Contributors Wenyong Huang (Intel) + +**Jun 11, 2019: Add WASM APP API connection** + + +- Contributor: Weining Lu (Intel) + +**Jun 10, 2019: Support VxWorks** + +- Contributor: Yiting Wang (WindRiver) + +**Aug 1, 2019: Add WGL graphic user interface API** + +- Contributor: Weining Lu + +**Aug 14, 2019: Add Docker support** + + +- Contributor: beriberikix + + +**Aug 14, 2019: WASM IoT app store demo** + + +- Contributor: Luhanzhi Li, Jun Xu (Intel) + + +**Aug 28, 2019: SGX support** + + +- Contributor: Mic Bowman (Intel) + + +**Sep 6, 2019: Mac platform support** + + +- Contributor: Jonathan Dong (Alibaba) + +**Nov 2019: WASI support** (Intel) + +**Jan 2020: Ahead of time and Just-in-Time compilation support** (Intel) + diff --git a/doc/roadmap.md b/doc/roadmap.md new file mode 100644 index 000000000..c5c7b84a9 --- /dev/null +++ b/doc/roadmap.md @@ -0,0 +1,23 @@ + +# WebAssembly Micro Runtime Roadmap + + + +## Data serialization +Evaluating using cbor as the default data serialization + +No plan yet. + + + +## Threading +Plan: 2020 Q1 + + + +## AssemblyScript Support and API + +Currently under evaluation + + + diff --git a/samples/wasm-c-api/CMakeLists.txt b/samples/wasm-c-api/CMakeLists.txt index 682f2dc0b..46b30ce94 100644 --- a/samples/wasm-c-api/CMakeLists.txt +++ b/samples/wasm-c-api/CMakeLists.txt @@ -40,6 +40,7 @@ endif() set(WAMR_BUILD_LIBC_BUILTIN 1) set(WAMR_BUILD_LIBC_WASI 0) +set(WAMR_BUILD_MULTI_MODULE 1) if(NOT DEFINED WAMR_BUILD_FAST_INTERP) set(WAMR_BUILD_FAST_INTERP 0) @@ -70,47 +71,44 @@ endif() ################################################ ################ application related ################ -file(GLOB SOURCES src/*.c) -add_library(c-api ${SOURCES}) -target_include_directories(c-api - PRIVATE ${C_API_PATH}/include +## locate wat2wasm +find_program(WAT2WASM + wat2wasm + PATHS /opt/wabt/bin /opt/wabt-1.0.18/bin + REQUIRED ) -target_link_libraries(c-api PRIVATE vmlib -lpthread -lm) -if (MSVC) - target_compile_definitions(c-api PRIVATE WASM_API_EXTERN=) + +if(NOT WAT2WASM) + message(SEND_ERROR "can not find wat2wasm") endif() +include (${SHARED_DIR}/utils/uncommon/shared_uncommon.cmake) + +set(MM_UTIL src/utils/multi_module_utils.c) +# build executable for each .c +file(GLOB SOURCES src/*.c) foreach(SRC ${SOURCES}) get_filename_component(APPNAME ${SRC} NAME_WE) - # build executable for each .c - add_executable(${APPNAME} ${SRC}) - message("create executable about ${APPNAME}") - target_link_libraries(${APPNAME} c-api) + add_executable(${APPNAME} ${SRC} ${UNCOMMON_SHARED_SOURCE} ${MM_UTIL}) + target_include_directories(${APPNAME} PRIVATE ${UNCOMMON_SHARED_DIR}) + target_link_libraries(${APPNAME} vmlib -lpthread -lm) if (MSVC) target_compile_definitions(${APPNAME} PRIVATE WASM_API_EXTERN=) endif() +endforeach() - # copy .wasm - add_custom_command(TARGET ${APPNAME} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy - ${CMAKE_CURRENT_SOURCE_DIR}/src/${APPNAME}.wasm - ${PROJECT_BINARY_DIR}/ - BYPRODUCTS ${APPNAME}.wasm - COMMENT "Copy ${SRC} to the output directory" +# wat to wasm +file(GLOB WAT_FILES src/*.wat) +foreach(WAT_FILE ${WAT_FILES}) + get_filename_component(WATNAME ${WAT_FILE} NAME_WE) + + add_custom_target(${WATNAME}_WASM ALL + COMMAND ${WAT2WASM} ${WAT_FILE} -o ${PROJECT_BINARY_DIR}/${WATNAME}.wasm + DEPENDS ${WAT_FILE} + BYPRODUCTS ${PROJECT_BINARY_DIR}/${WATNAME}.wasm + VERBATIM + SOURCES ${WAT_FILE} ) - - # generate .aot file - if(${WAMR_BUILD_AOT} EQUAL 1) - if(EXISTS ${WAMRC}) - add_custom_command(TARGET ${APPNAME} POST_BUILD - COMMAND ${WAMRC} -o ${APPNAME}.aot - ${CMAKE_CURRENT_SOURCE_DIR}/src/${APPNAME}.wasm - BYPRODUCTS ${APPNAME}.aot - COMMENT "generate a aot file ${APPNAME}.aot" - ) - endif() - endif() - -endforeach(SRC ${SOURCES}) +endforeach() ################################################ diff --git a/samples/wasm-c-api/README.md b/samples/wasm-c-api/README.md index 31d2aea09..51b8642a2 100644 --- a/samples/wasm-c-api/README.md +++ b/samples/wasm-c-api/README.md @@ -1,5 +1,16 @@ -WAMR supports *wasm-c-api* in both *interpreter* mode and *aot* mode. By default, -all samples are compiled and run in "interpreter" mode. +WAMR supports *wasm-c-api* in both *interpreter* mode and *aot* mode. + +Before staring, we need to download and intall [WABT](https://github.com/WebAssembly/wabt/releases/latest). + +``` shell +$ cd /opt +$ wget https://github.com/WebAssembly/wabt/releases/download/1.0.19/wabt-1.0.19-ubuntu.tar.gz +$ tar -xzf wabt-1.0.19-ubuntu.tar.gz +$ mv wabt-1.0.19 wabt +``` + +By default, all samples are compiled and run in "interpreter" mode. + ``` shell $ mkdir build diff --git a/samples/wasm-c-api/src/callback.c b/samples/wasm-c-api/src/callback.c index da3e7491e..52349c330 100644 --- a/samples/wasm-c-api/src/callback.c +++ b/samples/wasm-c-api/src/callback.c @@ -4,6 +4,14 @@ #include #include "wasm_c_api.h" +#include "wasm_export.h" +#include "bh_platform.h" + +extern bool +reader(const char *module_name, uint8 **p_buffer, uint32 *p_size); + +extern void +destroyer(uint8 *buffer, uint32 size); #define own @@ -61,6 +69,8 @@ own wasm_trap_t* closure_callback( int main(int argc, const char* argv[]) { + wasm_runtime_set_module_reader(reader, destroyer); + // Initialize. printf("Initializing...\n"); wasm_engine_t* engine = wasm_engine_new(); diff --git a/samples/wasm-c-api/src/callback.wasm b/samples/wasm-c-api/src/callback.wasm deleted file mode 100644 index 7e00b580142c1e8171c18577fca06d1a39f2b48c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 102 zcmW+sy9$6H6g~G!2(|bLewq;tNm*#lN=r*a1pRN?aNY-fSO@^!IcEq%iIPD9r{egn nEu-1|Lqn5QP-MFgPD&Y~ diff --git a/samples/wasm-c-api/src/global.c b/samples/wasm-c-api/src/global.c index ba73d95ed..a7b5c16af 100644 --- a/samples/wasm-c-api/src/global.c +++ b/samples/wasm-c-api/src/global.c @@ -4,6 +4,14 @@ #include #include "wasm_c_api.h" +#include "wasm_export.h" +#include "bh_platform.h" + +extern bool +reader(const char *module_name, uint8 **p_buffer, uint32 *p_size); + +extern void +destroyer(uint8 *buffer, uint32 size); #define own @@ -46,6 +54,8 @@ wasm_func_t* get_export_func(const wasm_extern_vec_t* exports, size_t i) { int main(int argc, const char* argv[]) { + wasm_runtime_set_module_reader(reader, destroyer); + // Initialize. printf("Initializing...\n"); wasm_engine_t* engine = wasm_engine_new(); diff --git a/samples/wasm-c-api/src/global.wasm b/samples/wasm-c-api/src/global.wasm deleted file mode 100644 index 0e76863278e62f064730544392e92c0194097134..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 576 zcmZXQO-{ow5JtbT6T7Whpo#-nYEMuq)~H-06)II1rKpK2HjbhSv17rS4Od{neYgaB zY$yJaP?YG+%lMl~u&(z6fZn^VLs5Z@z1xZmDr&*Ly~ga0h(esunAu4B6tx7PJ~E`E|BuF0*OHz%H|llY}Sd z7SvjF?mdh_gai%h%jL6lIOEopM_L z-(VDFw!t{cEOU}%nyx0l{#U=aCuUFsPyiNy2PguR0Ym_)UVV +#include +#include +#include + +#include "wasm_c_api.h" +#include "wasm_export.h" +#include "bh_platform.h" + +extern bool +reader(const char *module_name, uint8 **p_buffer, uint32 *p_size); + +extern void +destroyer(uint8 *buffer, uint32 size); + +#define own + +wasm_global_t* get_export_global(const wasm_extern_vec_t* exports, size_t i) { + if (exports->size <= i || !wasm_extern_as_global(exports->data[i])) { + printf("> Error accessing global export %zu!\n", i); + exit(1); + } + return wasm_extern_as_global(exports->data[i]); +} + +wasm_func_t* get_export_func(const wasm_extern_vec_t* exports, size_t i) { + if (exports->size <= i || !wasm_extern_as_func(exports->data[i])) { + printf("> Error accessing function export %zu!\n", i); + exit(1); + } + return wasm_extern_as_func(exports->data[i]); +} + + +#define check(val, type, expected) \ + if (val.of.type != expected) { \ + printf("> Expected reading value %f or %d \n", expected, expected); \ + printf("> Error reading value %f or %d\n", val.of.type, val.of.type); \ + } + +#define check_global(global, type, expected) \ + { \ + wasm_val_t val; \ + wasm_global_get(global, &val); \ + check(val, type, expected); \ + } + +#define check_call(func, type, expected) \ + { \ + wasm_val_t results[1]; \ + wasm_func_call(func, NULL, results); \ + check(results[0], type, expected); \ + } + +wasm_module_t * create_module_from_file(wasm_store_t* store, const char * filename) +{ + FILE* file = fopen(filename, "rb"); + fseek(file, 0L, SEEK_END); + size_t file_size = ftell(file); + fseek(file, 0L, SEEK_SET); + wasm_byte_vec_t binary; + wasm_byte_vec_new_uninitialized(&binary, file_size); + if (fread(binary.data, file_size, 1, file) != 1) { + printf("> Error loading module!\n"); + return 1; + } + // Compile. + printf("Compiling module...\n"); + own wasm_module_t* module = wasm_module_new(store, &binary); + if (!module) { + printf("> Error compiling module!\n"); + return 1; + } + wasm_byte_vec_delete(&binary); + fclose(file); + return module; +} + + +int main(int argc, const char* argv[]) { + wasm_runtime_set_module_reader(reader, destroyer); + + // Initialize. + printf("Initializing...\n"); + wasm_engine_t* engine = wasm_engine_new(); + wasm_store_t* store = wasm_store_new(engine); + + // Load binary. + printf("Loading binary...\n"); +#if WASM_ENABLE_AOT != 0 && WASM_ENABLE_INTERP == 0 + wasm_module_t* moduleimport = create_module_from_file(store, "globalimport.aot"); +#else + wasm_module_t* moduleimport = create_module_from_file(store, "globalexportimport-1.wasm"); +#endif + + // Instantiate. + printf("Instantiating Import module...\n"); + own wasm_instance_t* instance_import = + wasm_instance_new(store, moduleimport, NULL, NULL); //after this var_f32_export->inst_comm_rt is module_import + if (!instance_import) { + printf("> Error instantiating Import module!\n"); + return 1; + } + wasm_module_delete(moduleimport); + + // Extract export. + printf("Extracting exports from Import module...\n"); + own wasm_extern_vec_t exports_of_import; + wasm_instance_exports(instance_import, &exports_of_import); + int i = 0; + wasm_global_t *var_f32_export = get_export_global(&exports_of_import, i++); + wasm_func_t *get_var_f32_export = get_export_func(&exports_of_import, i++); + wasm_func_t* set_var_f32_export = get_export_func(&exports_of_import, i++); + wasm_func_t* get_var_f32_import = get_export_func(&exports_of_import, i++); + wasm_func_t* set_var_f32_import = get_export_func(&exports_of_import, i++); + + // Interact. + + // Check initial values. + printf("Check initial values...\n"); + check_global(var_f32_export, f32, 7.0); + check_call(get_var_f32_export, f32, 7.0); //Call to module export + check_call(get_var_f32_import, f32, 7.0); //Call to module import + + + // Modify variables through API and check again. + printf("Modify the variable to 37.0...\n"); + wasm_val_t val37 = {.kind = WASM_F32, .of = {.f32 = 37.0}}; + wasm_global_set(var_f32_export, &val37); // var_f32_export->inst_comm_rt is module_import now + + check_global(var_f32_export, f32, 37.0); + check_call(get_var_f32_export, f32, 37.0); //Call to module export Failed here, still 7 + check_call(get_var_f32_import, f32, 37.0); //Call to module import + + // Modify variables through calls and check again. + printf("Modify the variable to 77.0...\n"); + wasm_val_t args77[] = { {.kind = WASM_F32, .of = {.f32 = 77.}} }; + wasm_func_call(set_var_f32_export, args77, NULL); //Call to module export + check_call(get_var_f32_export, f32, 77.0); //Call to module export + check_global(var_f32_export, f32, 77.0); //Failed here, still 37 + check_call(get_var_f32_import, f32, 77.0); //Call to module import Failed here, still 37 + + + printf("Modify the variable to 78.0...\n"); + wasm_val_t args78[] = { {.kind = WASM_F32, .of = {.f32 = 78.0}} }; + wasm_func_call(set_var_f32_import, args78, NULL); + check_global(var_f32_export, f32, 78.0); + check_call(get_var_f32_export, f32, 78.0); //Call to module export Failed here, still 77 + check_call(get_var_f32_import, f32, 78.0); //Call to module import + + + // wasm_extern_vec_delete(&exports_of_export); + //wasm_instance_delete(instance_export); + wasm_extern_vec_delete(&exports_of_import); + //wasm_instance_delete(instance_import); + + // Shut down. + printf("Shutting down...\n"); + wasm_store_delete(store); + wasm_engine_delete(engine); + + // All done. + printf("Done.\n"); + return 0; + +} \ No newline at end of file diff --git a/samples/wasm-c-api/src/hello.c b/samples/wasm-c-api/src/hello.c index 491a24b3d..db8281c36 100644 --- a/samples/wasm-c-api/src/hello.c +++ b/samples/wasm-c-api/src/hello.c @@ -4,6 +4,14 @@ #include #include "wasm_c_api.h" +#include "wasm_export.h" +#include "bh_platform.h" + +extern bool +reader(const char *module_name, uint8 **p_buffer, uint32 *p_size); + +extern void +destroyer(uint8 *buffer, uint32 size); #define own @@ -18,6 +26,8 @@ own wasm_trap_t* hello_callback( int main(int argc, const char* argv[]) { + wasm_runtime_set_module_reader(reader, destroyer); + // Initialize. printf("Initializing...\n"); wasm_engine_t* engine = wasm_engine_new(); diff --git a/samples/wasm-c-api/src/hello.wasm b/samples/wasm-c-api/src/hello.wasm deleted file mode 100644 index 2207c03eead3f45f13dfa58b73c6bce27716bffa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 71 zcmZQbEY4+QU|?WuX=rF*U`$|OVCn+17+5n>b8_+-7?_(NeD-!Q&0JKP$H2%1Q3Te+ IAi%&40BKwiaR2}S diff --git a/samples/wasm-c-api/src/utils/multi_module_utils.c b/samples/wasm-c-api/src/utils/multi_module_utils.c new file mode 100644 index 000000000..67010914b --- /dev/null +++ b/samples/wasm-c-api/src/utils/multi_module_utils.c @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "bh_read_file.h" +#include "wasm_export.h" + +static char * +build_module_path(const char *module_name) +{ + const char *module_search_path = "."; + const char *format = "%s/%s.wasm"; + int sz = strlen(module_search_path) + strlen("/") + strlen(module_name) + + strlen(".wasm") + 1; + char *wasm_file_name = BH_MALLOC(sz); + if (!wasm_file_name) { + return NULL; + } + + snprintf(wasm_file_name, sz, format, module_search_path, module_name); + return wasm_file_name; +} + +bool +reader(const char *module_name, uint8 **p_buffer, uint32 *p_size) +{ + char *wasm_file_path = build_module_path(module_name); + if (!wasm_file_path) { + return false; + } + + *p_buffer = (uint8_t *)bh_read_file_to_buffer(wasm_file_path, p_size); + BH_FREE(wasm_file_path); + return *p_buffer != NULL; +} + +void +destroyer(uint8 *buffer, uint32 size) +{ + if (!buffer) { + return; + } + + BH_FREE(buffer); + buffer = NULL; +} From c515fb1b7514015e8c1a2a54c443df197e3c2633 Mon Sep 17 00:00:00 2001 From: Wang Ning Date: Thu, 22 Oct 2020 16:18:37 +0800 Subject: [PATCH 100/207] Add tensorflow sample under samples/workload/tensorflow (#427) --- build-scripts/config_common.cmake | 3 + build-scripts/runtime_lib.cmake | 5 + core/config.h | 5 + core/iwasm/common/wasm_native.c | 11 + .../iwasm/libraries/libc-emcc/libc_emcc.cmake | 12 ++ .../libraries/libc-emcc/libc_emcc_wrapper.c | 196 ++++++++++++++++++ samples/workload/tensorflow/README.md | 19 ++ samples/workload/tensorflow/build.sh | 97 +++++++++ samples/workload/tensorflow/tf_lite.patch | 78 +++++++ 9 files changed, 426 insertions(+) create mode 100644 core/iwasm/libraries/libc-emcc/libc_emcc.cmake create mode 100644 core/iwasm/libraries/libc-emcc/libc_emcc_wrapper.c create mode 100644 samples/workload/tensorflow/README.md create mode 100755 samples/workload/tensorflow/build.sh create mode 100644 samples/workload/tensorflow/tf_lite.patch diff --git a/build-scripts/config_common.cmake b/build-scripts/config_common.cmake index 8ac8e4de6..9f3d5bb68 100644 --- a/build-scripts/config_common.cmake +++ b/build-scripts/config_common.cmake @@ -152,6 +152,9 @@ endif () if (WAMR_BUILD_LIB_PTHREAD EQUAL 1) message (" Lib pthread enabled") endif () +if (WAMR_BUILD_LIBC_EMCC EQUAL 1) + message (" Libc emcc enabled") +endif () if (WAMR_BUILD_MINI_LOADER EQUAL 1) add_definitions (-DWASM_ENABLE_MINI_LOADER=1) message (" WASM mini loader enabled") diff --git a/build-scripts/runtime_lib.cmake b/build-scripts/runtime_lib.cmake index a87a2ff63..aaddc0046 100644 --- a/build-scripts/runtime_lib.cmake +++ b/build-scripts/runtime_lib.cmake @@ -81,6 +81,10 @@ if (WAMR_BUILD_THREAD_MGR EQUAL 1) include (${IWASM_DIR}/libraries/thread-mgr/thread_mgr.cmake) endif () +if (WAMR_BUILD_LIBC_EMCC EQUAL 1) + include (${IWASM_DIR}/libraries/libc-emcc/libc_emcc.cmake) +endif() + ####################### Common sources ####################### if (NOT MSVC) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99 -ffunction-sections -fdata-sections \ @@ -120,6 +124,7 @@ set (source_all ${APP_MGR_SOURCE} ${LIB_PTHREAD_SOURCE} ${THREAD_MGR_SOURCE} + ${LIBC_EMCC_SOURCE} ) set (WAMR_RUNTIME_LIB_SOURCE ${source_all}) diff --git a/core/config.h b/core/config.h index d21396aa9..1b474b0bb 100644 --- a/core/config.h +++ b/core/config.h @@ -82,6 +82,11 @@ #define WASM_ENABLE_LIBC_WASI 0 #endif +/* Default disable libc emcc */ +#ifndef WASM_ENABLE_LIBC_EMCC +#define WASM_ENABLE_LIBC_EMCC 0 +#endif + #ifndef WASM_ENABLE_LIB_PTHREAD #define WASM_ENABLE_LIB_PTHREAD 0 #endif diff --git a/core/iwasm/common/wasm_native.c b/core/iwasm/common/wasm_native.c index ff6946457..ad9ebae01 100644 --- a/core/iwasm/common/wasm_native.c +++ b/core/iwasm/common/wasm_native.c @@ -50,6 +50,9 @@ uint32 get_lib_pthread_export_apis(NativeSymbol **p_lib_pthread_apis); #endif +uint32 +get_libc_emcc_export_apis(NativeSymbol **p_libc_emcc_apis); + static bool check_symbol_signature(const WASMType *type, const char *signature) { @@ -386,6 +389,14 @@ wasm_native_init() return false; #endif +#if WASM_ENABLE_LIBC_EMCC != 0 + n_native_symbols = get_libc_emcc_export_apis(&native_symbols); + if (n_native_symbols > 0 + && !wasm_native_register_natives("env", + native_symbols, n_native_symbols)) + return false; +#endif /* WASM_ENABLE_LIBC_EMCC */ + return true; } diff --git a/core/iwasm/libraries/libc-emcc/libc_emcc.cmake b/core/iwasm/libraries/libc-emcc/libc_emcc.cmake new file mode 100644 index 000000000..d237a16ee --- /dev/null +++ b/core/iwasm/libraries/libc-emcc/libc_emcc.cmake @@ -0,0 +1,12 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +set (LIBC_EMCC_DIR ${CMAKE_CURRENT_LIST_DIR}) + +add_definitions (-DWASM_ENABLE_LIBC_EMCC=1) + +include_directories(${LIBC_EMCC_DIR}) + +file (GLOB source_all ${LIBC_EMCC_DIR}/*.c) + +set (LIBC_EMCC_SOURCE ${source_all}) \ No newline at end of file diff --git a/core/iwasm/libraries/libc-emcc/libc_emcc_wrapper.c b/core/iwasm/libraries/libc-emcc/libc_emcc_wrapper.c new file mode 100644 index 000000000..0e3652b39 --- /dev/null +++ b/core/iwasm/libraries/libc-emcc/libc_emcc_wrapper.c @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "bh_common.h" +#include "bh_log.h" +#include "wasm_export.h" +#include "../interpreter/wasm.h" + +#define get_module_inst(exec_env) \ + wasm_runtime_get_module_inst(exec_env) + +#define validate_native_addr(addr, size) \ + wasm_runtime_validate_native_addr(module_inst, addr, size) + +#define module_malloc(size, p_native_addr) \ + wasm_runtime_module_malloc(module_inst, size, p_native_addr) + +#define module_free(offset) \ + wasm_runtime_module_free(module_inst, offset) + +#define REG_NATIVE_FUNC(func_name, signature) \ + { #func_name, func_name##_wrapper, signature, NULL } + +struct timespec_emcc { + int tv_sec; + int tv_nsec; +}; + +struct stat_emcc { + unsigned st_dev; + int __st_dev_padding; + unsigned __st_ino_truncated; + unsigned st_mode; + unsigned st_nlink; + unsigned st_uid; + unsigned st_gid; + unsigned st_rdev; + int __st_rdev_padding; + int64 st_size; + int st_blksize; + int st_blocks; + struct timespec_emcc st_atim; + struct timespec_emcc st_mtim; + struct timespec_emcc st_ctim; + int64 st_ino; +}; + +static int +open_wrapper(wasm_exec_env_t exec_env, const char *pathname, + int flags, int mode) +{ + if (pathname == NULL) + return -1; + return open(pathname, flags, mode); +} + +static int +__sys_read_wrapper(wasm_exec_env_t exec_env, + int fd, void *buf, uint32 count) +{ + return read(fd, buf, count); +} + +static void +statbuf_native2app(const struct stat *statbuf_native, + struct stat_emcc *statbuf_app) +{ + statbuf_app->st_dev = (unsigned)statbuf_native->st_dev; + statbuf_app->__st_ino_truncated = (unsigned)statbuf_native->st_ino; + statbuf_app->st_mode = (unsigned)statbuf_native->st_mode; + statbuf_app->st_nlink = (unsigned)statbuf_native->st_nlink; + statbuf_app->st_uid = (unsigned)statbuf_native->st_uid; + statbuf_app->st_gid = (unsigned)statbuf_native->st_gid; + statbuf_app->st_rdev = (unsigned)statbuf_native->st_rdev; + statbuf_app->st_size = (int64)statbuf_native->st_size; + statbuf_app->st_blksize = (unsigned)statbuf_native->st_blksize; + statbuf_app->st_blocks = (unsigned)statbuf_native->st_blocks; + statbuf_app->st_ino = (int64)statbuf_native->st_ino; + statbuf_app->st_atim.tv_sec = (int)statbuf_native->st_atim.tv_sec; + statbuf_app->st_atim.tv_nsec = (int)statbuf_native->st_atim.tv_nsec; + statbuf_app->st_mtim.tv_sec = (int)statbuf_native->st_mtim.tv_sec; + statbuf_app->st_mtim.tv_nsec = (int)statbuf_native->st_mtim.tv_nsec; + statbuf_app->st_ctim.tv_sec = (int)statbuf_native->st_ctim.tv_sec; + statbuf_app->st_ctim.tv_nsec = (int)statbuf_native->st_ctim.tv_nsec; +} + +static int +__sys_stat64_wrapper(wasm_exec_env_t exec_env, + const char *pathname, + struct stat_emcc *statbuf_app) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + int ret; + struct stat statbuf; + + if (!validate_native_addr((void*)statbuf_app, sizeof(struct stat_emcc))) + return -1; + + if (pathname == NULL) + return -1; + + ret = stat(pathname, &statbuf); + if (ret == 0) + statbuf_native2app(&statbuf, statbuf_app); + return ret; +} + +static int +__sys_fstat64_wrapper(wasm_exec_env_t exec_env, + int fd, struct stat_emcc *statbuf_app) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + int ret; + struct stat statbuf; + + if (!validate_native_addr((void*)statbuf_app, sizeof(struct stat_emcc))) + return -1; + + if (fd <= 0) + return -1; + + ret = fstat(fd, &statbuf); + if (ret == 0) + statbuf_native2app(&statbuf, statbuf_app); + return ret; +} + +static int +mmap_wrapper(wasm_exec_env_t exec_env, + void *addr, int length, int prot, int flags, + int fd, int64 offset) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uint32 buf_offset; + char *buf; + int size_read; + + buf_offset = module_malloc(length, (void**)&buf); + if (buf_offset == 0) + return -1; + + if (fd <= 0) + return -1; + + if (lseek(fd, offset, SEEK_SET) == -1) + return -1; + + size_read = read(fd, buf, length); + (void)size_read; + return buf_offset; +} + +static int +munmap_wrapper(wasm_exec_env_t exec_env, uint32 buf_offset, int length) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + module_free(buf_offset); + return 0; +} + +static int +__munmap_wrapper(wasm_exec_env_t exec_env, uint32 buf_offset, int length) +{ + return munmap_wrapper(exec_env, buf_offset, length); +} + +static int +getentropy_wrapper(wasm_exec_env_t exec_env, void *buffer, uint32 length) +{ + if (buffer == NULL) + return -1; + return getentropy(buffer, length); +} + +#define REG_NATIVE_FUNC(func_name, signature) \ + { #func_name, func_name##_wrapper, signature, NULL } + +static NativeSymbol native_symbols_libc_emcc[] = { + REG_NATIVE_FUNC(open, "($ii)i"), + REG_NATIVE_FUNC(__sys_read, "(i*~)i"), + REG_NATIVE_FUNC(__sys_stat64, "($*)i"), + REG_NATIVE_FUNC(__sys_fstat64, "(i*)i"), + REG_NATIVE_FUNC(mmap, "(*iiiiI)i"), + REG_NATIVE_FUNC(munmap, "(ii)i"), + REG_NATIVE_FUNC(__munmap, "(ii)i"), + REG_NATIVE_FUNC(getentropy, "(*~)i"), +}; + +uint32 +get_libc_emcc_export_apis(NativeSymbol **p_libc_emcc_apis) +{ + *p_libc_emcc_apis = native_symbols_libc_emcc; + return sizeof(native_symbols_libc_emcc) / sizeof(NativeSymbol); +} diff --git a/samples/workload/tensorflow/README.md b/samples/workload/tensorflow/README.md new file mode 100644 index 000000000..d34f51ec3 --- /dev/null +++ b/samples/workload/tensorflow/README.md @@ -0,0 +1,19 @@ +"tensorflow" sample introduction +============== +This sample demonstrates how to build [tensorflow](https://github.com/tensorflow/tensorflow) into WebAssembly with emcc toolchain and run it with iwasm. Please first install [emsdk](https://github.com/emscripten-core/emsdk): +```bash +git clone https://github.com/emscripten-core/emsdk.git +cd emsdk +./emsdk install latest +./emsdk activate latest +``` +And set up ensdk environment: +```bash +source emsdk_env.sh +``` +Then run ./build.sh to build tensorflow and run it with iwasm, which basically contains the following steps: +- hack emcc to delete some objects in libc.a +- build tf-lite with emcc compiler +- build iwasm with pthread enable and include libiary under libc-emcc +- run benchmark model with iwasm: + --max-secs 300: means the max training time cost is 5 minutes, you can adjust by yourself diff --git a/samples/workload/tensorflow/build.sh b/samples/workload/tensorflow/build.sh new file mode 100755 index 000000000..d1fdde048 --- /dev/null +++ b/samples/workload/tensorflow/build.sh @@ -0,0 +1,97 @@ +#!/bin/bash + +#################################### +# build tensorflow-lite sample # +#################################### +set -x +set -e + +EMSDK_WASM_DIR="$EM_CACHE/wasm" +BUILD_SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +OUT_DIR=${BUILD_SCRIPT_DIR}/out +TENSORFLOW_DIR="${BUILD_SCRIPT_DIR}/tensorflow" +TF_LITE_BUILD_DIR=${TENSORFLOW_DIR}/tensorflow/lite/tools/make +WAMR_DIR="${BUILD_SCRIPT_DIR}/../../../product-mini/platforms/linux" + +function Clear_Before_Exit +{ + [[ -f ${TENSORFLOW_DIR}/tf_lite.patch ]] && + rm -f ${TENSORFLOW_DIR}/tf_lite.patch + # resume the libc.a under EMSDK_WASM_DIR + cd ${EMSDK_WASM_DIR} + mv libc.a.bak libc.a +} + +# 1.hack emcc +cd ${EMSDK_WASM_DIR} +# back up libc.a +cp libc.a libc.a.bak +# delete some objects in libc.a +emar d libc.a open.o +emar d libc.a mmap.o +emar d libc.a munmap.o +emranlib libc.a + +# 2. build tf-lite +cd ${BUILD_SCRIPT_DIR} +# 2.1 clone tf repo from Github and checkout to 2303ed commit +if [ ! -d "tensorflow" ]; then + git clone https://github.com/tensorflow/tensorflow.git +fi + +cd ${TENSORFLOW_DIR} +git checkout 2303ed4bdb344a1fc4545658d1df6d9ce20331dd + +# 2.2 copy the tf-lite.patch to tensorflow_root_dir and apply +cd ${TENSORFLOW_DIR} +cp ${BUILD_SCRIPT_DIR}/tf_lite.patch . +git checkout tensorflow/lite/tools/make/Makefile +git checkout tensorflow/lite/tools/make/targets/linux_makefile.inc + +if [[ $(git apply tf_lite.patch 2>&1) =~ "error" ]]; then + echo "git apply patch failed, please check tf-lite related changes..." + Clear_Before_Exit + exit 0 +fi + +cd ${TF_LITE_BUILD_DIR} +# 2.3 download dependencies +if [ ! -d "${TF_LITE_BUILD_DIR}/downloads" ]; then + source download_dependencies.sh +fi + +# 2.4 build tf-lite target +if [ -d "${TF_LITE_BUILD_DIR}/gen" ]; then + rm -fr ${TF_LITE_BUILD_DIR}/gen +fi +make -j 4 -C "${TENSORFLOW_DIR}" -f ${TF_LITE_BUILD_DIR}/Makefile $@ + +# 2.5 copy /make/gen target files to out/ +rm -rf ${OUT_DIR} +mkdir ${OUT_DIR} +cp -r ${TF_LITE_BUILD_DIR}/gen/linux_x86_64/bin/. ${OUT_DIR}/ + +# 3. build iwasm with pthread and libc_emcc enable +cd ${WAMR_DIR} +rm -fr build && mkdir build +cd build && cmake .. -DWAMR_BUILD_LIB_PTHREAD=1 -DWAMR_BUILD_LIBC_EMCC=1 +make + +# 4. run tensorflow with iwasm +cd ${BUILD_SCRIPT_DIR} +# 4.1 download tf-lite model +if [ ! -f mobilenet_quant_v1_224.tflite ]; then + wget "https://storage.googleapis.com/download.tensorflow.org/models/tflite/mobilenet_v1_224_android_quant_2017_11_08.zip" + unzip mobilenet_v1_224_android_quant_2017_11_08.zip +fi + +# 4.2 run tf-lite model with iwasm +echo "---> run tensorflow benchmark model with iwasm" +${WAMR_DIR}/build/iwasm --heap-size=10475860 \ + ${OUT_DIR}/benchmark_model.wasm \ + --graph=mobilenet_quant_v1_224.tflite --max_secs=300 + +Clear_Before_Exit + + + diff --git a/samples/workload/tensorflow/tf_lite.patch b/samples/workload/tensorflow/tf_lite.patch new file mode 100644 index 000000000..85700778a --- /dev/null +++ b/samples/workload/tensorflow/tf_lite.patch @@ -0,0 +1,78 @@ +diff --git a/tensorflow/lite/tools/make/Makefile b/tensorflow/lite/tools/make/Makefile +index c7ddff5844..1082644043 100644 +--- a/tensorflow/lite/tools/make/Makefile ++++ b/tensorflow/lite/tools/make/Makefile +@@ -48,11 +48,7 @@ INCLUDES += -I/usr/local/include + + # These are the default libraries needed, but they can be added to or + # overridden by the platform-specific settings in target makefiles. +-LIBS := \ +--lstdc++ \ +--lpthread \ +--lm \ +--lz \ ++LIBS := -lm \ + -ldl + + # There are no rules for compiling objects for the host system (since we don't +@@ -84,14 +80,18 @@ endif # ifeq ($(HOST_ARCH),$(TARGET_ARCH)) + endif # ifeq ($(HOST_OS),$(TARGET)) + endif + ++LIBFLAGS += -s TOTAL_STACK=1048576 \ ++ -Wl,--export=__data_end -Wl,--export=__heap_base \ ++ -s ERROR_ON_UNDEFINED_SYMBOLS=0 ++ + # This library is the main target for this makefile. It will contain a minimal + # runtime that can be linked in to other programs. + LIB_NAME := libtensorflow-lite.a + + # Benchmark static library and binary + BENCHMARK_LIB_NAME := benchmark-lib.a +-BENCHMARK_BINARY_NAME := benchmark_model +-BENCHMARK_PERF_OPTIONS_BINARY_NAME := benchmark_model_performance_options ++BENCHMARK_BINARY_NAME := benchmark_model.wasm ++BENCHMARK_PERF_OPTIONS_BINARY_NAME := benchmark_model_performance_options.wasm + + # A small example program that shows how to link against the library. + MINIMAL_SRCS := \ +@@ -277,12 +277,16 @@ LIB_PATH := $(LIBDIR)$(LIB_NAME) + BENCHMARK_LIB := $(LIBDIR)$(BENCHMARK_LIB_NAME) + BENCHMARK_BINARY := $(BINDIR)$(BENCHMARK_BINARY_NAME) + BENCHMARK_PERF_OPTIONS_BINARY := $(BINDIR)$(BENCHMARK_PERF_OPTIONS_BINARY_NAME) +-MINIMAL_BINARY := $(BINDIR)minimal ++MINIMAL_BINARY := $(BINDIR)minimal.wasm + LABEL_IMAGE_BINARY := $(BINDIR)label_image + +-CXX := $(CC_PREFIX)${TARGET_TOOLCHAIN_PREFIX}g++ +-CC := $(CC_PREFIX)${TARGET_TOOLCHAIN_PREFIX}gcc +-AR := $(CC_PREFIX)${TARGET_TOOLCHAIN_PREFIX}ar ++# CXX := $(CC_PREFIX)${TARGET_TOOLCHAIN_PREFIX}g++ ++# CC := $(CC_PREFIX)${TARGET_TOOLCHAIN_PREFIX}gcc ++# AR := $(CC_PREFIX)${TARGET_TOOLCHAIN_PREFIX}ar ++ ++CXX := em++ ++CC := emcc ++AR := emar + + MINIMAL_OBJS := $(addprefix $(OBJDIR), \ + $(patsubst %.cc,%.o,$(patsubst %.c,%.o,$(MINIMAL_SRCS)))) +diff --git a/tensorflow/lite/tools/make/targets/linux_makefile.inc b/tensorflow/lite/tools/make/targets/linux_makefile.inc +index 222cef9e5f..eea89a38f0 100644 +--- a/tensorflow/lite/tools/make/targets/linux_makefile.inc ++++ b/tensorflow/lite/tools/make/targets/linux_makefile.inc +@@ -2,12 +2,10 @@ + ifeq ($(TARGET), linux) + CXXFLAGS += \ + -fPIC \ +- -DGEMMLOWP_ALLOW_SLOW_SCALAR_FALLBACK \ +- -pthread ++ -DGEMMLOWP_ALLOW_SLOW_SCALAR_FALLBACK + CFLAGS += \ + -fPIC \ +- -DGEMMLOWP_ALLOW_SLOW_SCALAR_FALLBACK \ +- -pthread ++ -DGEMMLOWP_ALLOW_SLOW_SCALAR_FALLBACK + # TODO(petewarden): In the future we may want to add architecture-specific + # flags like -msse4.2 + LIBS += -ldl From 91b9458ebd42711614f59c8ad54785271302337e Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Thu, 22 Oct 2020 18:52:33 +0800 Subject: [PATCH 101/207] Add more checks to enhance app heap's security (#428) --- core/iwasm/aot/aot_runtime.c | 48 ++-- core/iwasm/common/wasm_runtime_common.c | 2 - core/iwasm/interpreter/wasm_runtime.c | 46 ++-- core/shared/mem-alloc/ems/ems_alloc.c | 278 +++++++++++++++----- core/shared/mem-alloc/ems/ems_gc.h | 39 ++- core/shared/mem-alloc/ems/ems_gc_internal.h | 14 +- core/shared/mem-alloc/ems/ems_hmu.c | 28 +- core/shared/mem-alloc/ems/ems_kfc.c | 139 ++++++---- core/shared/mem-alloc/mem_alloc.c | 28 +- core/shared/mem-alloc/mem_alloc.h | 14 +- 10 files changed, 431 insertions(+), 205 deletions(-) diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index 668d03645..6507281c0 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -171,8 +171,10 @@ memories_deinstantiate(AOTModuleInstance *module_inst) continue; } #endif - if (memory_inst->heap_handle.ptr) + if (memory_inst->heap_handle.ptr) { mem_allocator_destroy(memory_inst->heap_handle.ptr); + wasm_runtime_free(memory_inst->heap_handle.ptr); + } if (memory_inst->heap_data.ptr) { #ifndef OS_ENABLE_HW_BOUND_CHECK @@ -359,13 +361,22 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModule *module, memory_inst->heap_data.ptr = p + heap_offset; memory_inst->heap_data_end.ptr = p + heap_offset + heap_size; if (heap_size > 0) { - if (!(heap_handle = mem_allocator_create(memory_inst->heap_data.ptr, - heap_size))) { - set_error_buf(error_buf, error_buf_size, - "init app heap failed"); + uint32 heap_struct_size = mem_allocator_get_heap_struct_size(); + + if (!(heap_handle = runtime_malloc((uint64)heap_struct_size, + error_buf, error_buf_size))) { goto fail1; } + memory_inst->heap_handle.ptr = heap_handle; + + if (!mem_allocator_create_with_struct_and_pool + (heap_handle, heap_struct_size, + memory_inst->heap_data.ptr, heap_size)) { + set_error_buf(error_buf, error_buf_size, + "init app heap failed"); + goto fail2; + } } if (total_size > 0) { @@ -390,7 +401,7 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModule *module, (WASMMemoryInstanceCommon *)memory_inst)) { set_error_buf(error_buf, error_buf_size, "allocate memory failed"); - goto fail2; + goto fail3; } } #endif @@ -398,12 +409,13 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModule *module, return memory_inst; #if WASM_ENABLE_SHARED_MEMORY != 0 -fail2: - if (heap_size > 0) { +fail3: + if (heap_size > 0) mem_allocator_destroy(memory_inst->heap_handle.ptr); - memory_inst->heap_handle.ptr = NULL; - } #endif +fail2: + if (heap_size > 0) + wasm_runtime_free(memory_inst->heap_handle.ptr); fail1: #ifndef OS_ENABLE_HW_BOUND_CHECK wasm_runtime_free(memory_inst->memory_data.ptr); @@ -1474,7 +1486,6 @@ aot_enlarge_memory(AOTModuleInstance *module_inst, uint32 inc_page_count) uint8 *memory_data_old = (uint8 *)memory_inst->memory_data.ptr; uint8 *heap_data_old = (uint8 *)memory_inst->heap_data.ptr; uint8 *memory_data, *heap_data; - void *heap_handle_old = memory_inst->heap_handle.ptr; if (inc_page_count <= 0) /* No need to enlarge memory */ @@ -1498,18 +1509,9 @@ aot_enlarge_memory(AOTModuleInstance *module_inst, uint32 inc_page_count) } #endif - if (heap_size > 0) { - /* Destroy heap's lock firstly, if its memory is re-allocated, - we cannot access its lock again. */ - mem_allocator_destroy_lock(memory_inst->heap_handle.ptr); - } if (!(memory_data = wasm_runtime_realloc(memory_data_old, (uint32)total_size))) { if (!(memory_data = wasm_runtime_malloc((uint32)total_size))) { - if (heap_size > 0) { - /* Restore heap's lock if memory re-alloc failed */ - mem_allocator_reinit_lock(memory_inst->heap_handle.ptr); - } return false; } bh_memcpy_s(memory_data, (uint32)total_size, @@ -1526,10 +1528,10 @@ aot_enlarge_memory(AOTModuleInstance *module_inst, uint32 inc_page_count) memory_inst->memory_data_end.ptr = memory_data + total_size; if (heap_size > 0) { - memory_inst->heap_handle.ptr = (uint8 *)heap_handle_old - + (memory_data - memory_data_old); if (mem_allocator_migrate(memory_inst->heap_handle.ptr, - heap_handle_old) != 0) { + (char*)heap_data_old + + (memory_data - memory_data_old), + heap_size)) { return false; } } diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index 8d75eca45..5e1983fde 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -2138,8 +2138,6 @@ wasm_application_execute_main(WASMModuleInstanceCommon *module_inst, return ret; } - - #if WASM_ENABLE_MULTI_MODULE != 0 static WASMModuleInstance * get_sub_module_inst(const WASMModuleInstance *parent_module_inst, diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index bad93e1e5..d01e52813 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -107,6 +107,7 @@ memories_deinstantiate(WASMModuleInstance *module_inst, #endif if (memories[i]->heap_handle) { mem_allocator_destroy(memories[i]->heap_handle); + wasm_runtime_free(memories[i]->heap_handle); memories[i]->heap_handle = NULL; } wasm_runtime_free(memories[i]->memory_data); @@ -262,17 +263,25 @@ memory_instantiate(WASMModuleInstance *module_inst, memory->memory_data_end = memory->memory_data + (uint32)memory_data_size; /* Initialize heap */ - if (heap_size > 0 - && !(memory->heap_handle = - mem_allocator_create(memory->heap_data, heap_size))) { - set_error_buf(error_buf, error_buf_size, "init app heap failed"); - goto fail2; + if (heap_size > 0) { + uint32 heap_struct_size = mem_allocator_get_heap_struct_size(); + + if (!(memory->heap_handle = runtime_malloc((uint64)heap_struct_size, + error_buf, error_buf_size))) { + goto fail2; + } + if (!mem_allocator_create_with_struct_and_pool + (memory->heap_handle, heap_struct_size, + memory->heap_data, heap_size)) { + set_error_buf(error_buf, error_buf_size, "init app heap failed"); + goto fail3; + } } #if WASM_ENABLE_SHARED_MEMORY != 0 if (0 != os_mutex_init(&memory->mem_lock)) { set_error_buf(error_buf, error_buf_size, "init mutex failed"); - goto fail3; + goto fail4; } if (is_shared_memory) { memory->is_shared = true; @@ -281,18 +290,21 @@ memory_instantiate(WASMModuleInstance *module_inst, (WASMMemoryInstanceCommon *)memory)) { set_error_buf(error_buf, error_buf_size, "allocate memory failed"); - goto fail4; + goto fail5; } } #endif return memory; #if WASM_ENABLE_SHARED_MEMORY != 0 -fail4: +fail5: os_mutex_destroy(&memory->mem_lock); -fail3: +fail4: if (heap_size > 0) mem_allocator_destroy(memory->heap_handle); #endif +fail3: + if (heap_size > 0) + wasm_runtime_free(memory->heap_handle); fail2: wasm_runtime_free(memory->memory_data); fail1: @@ -1796,7 +1808,6 @@ wasm_enlarge_memory(WASMModuleInstance *module, uint32 inc_page_count) uint32 total_size_old = memory->memory_data_end - memory_data; uint32 total_page_count = inc_page_count + memory->cur_page_count; uint64 total_size = memory->num_bytes_per_page * (uint64)total_page_count; - void *heap_handle_old = memory->heap_handle; uint8 *heap_data_old = memory->heap_data; if (inc_page_count <= 0) @@ -1821,17 +1832,8 @@ wasm_enlarge_memory(WASMModuleInstance *module, uint32 inc_page_count) } #endif - if (heap_size > 0) { - /* Destroy heap's lock firstly, if its memory is re-allocated, - we cannot access its lock again. */ - mem_allocator_destroy_lock(memory->heap_handle); - } if (!(new_memory_data = wasm_runtime_realloc(memory_data, (uint32)total_size))) { if (!(new_memory_data = wasm_runtime_malloc((uint32)total_size))) { - if (heap_size > 0) { - /* Restore heap's lock if memory re-alloc failed */ - mem_allocator_reinit_lock(memory->heap_handle); - } return false; } bh_memcpy_s(new_memory_data, (uint32)total_size, @@ -1843,10 +1845,10 @@ wasm_enlarge_memory(WASMModuleInstance *module, uint32 inc_page_count) 0, (uint32)total_size - total_size_old); if (heap_size > 0) { - memory->heap_handle = (uint8 *)heap_handle_old + - (new_memory_data - memory_data); if (mem_allocator_migrate(memory->heap_handle, - heap_handle_old) != 0) { + (char *)heap_data_old + + (new_memory_data - memory_data), + heap_size) != 0) { return false; } } diff --git a/core/shared/mem-alloc/ems/ems_alloc.c b/core/shared/mem-alloc/ems/ems_alloc.c index e8d478d28..956bae616 100644 --- a/core/shared/mem-alloc/ems/ems_alloc.c +++ b/core/shared/mem-alloc/ems/ems_alloc.c @@ -6,12 +6,14 @@ #include "ems_gc_internal.h" -static int -hmu_is_in_heap(gc_heap_t* heap, hmu_t* hmu) +static inline bool +hmu_is_in_heap(void *hmu, + gc_uint8 *heap_base_addr, + gc_uint8 *heap_end_addr) { - return heap && hmu - && (gc_uint8*) hmu >= heap->base_addr - && (gc_uint8*) hmu < heap->base_addr + heap->current_size; + gc_uint8 *addr = (gc_uint8 *)hmu; + return (addr >= heap_base_addr && addr < heap_end_addr) + ? true : false; } /** @@ -23,21 +25,35 @@ hmu_is_in_heap(gc_heap_t* heap, hmu_t* hmu) * won't be touched. The tree will be re-organized so that the order * conditions are still satisified. */ -static void -remove_tree_node(hmu_tree_node_t *p) +static bool +remove_tree_node(gc_heap_t *heap, hmu_tree_node_t *p) { - hmu_tree_node_t *q = NULL, **slot = NULL; + hmu_tree_node_t *q = NULL, **slot = NULL, *parent; + hmu_tree_node_t *root = &heap->kfc_tree_root; + gc_uint8 *base_addr = heap->base_addr; + gc_uint8 *end_addr = base_addr + heap->current_size; bh_assert(p); - bh_assert(p->parent); /* @p can not be the ROOT node*/ + + parent = p->parent; + if (!parent || p == root /* p can not be the ROOT node */ + || !hmu_is_in_heap(p, base_addr, end_addr) + || (parent != root + && !hmu_is_in_heap(parent, base_addr, end_addr))) { + goto fail; + } /* get the slot which holds pointer to node p*/ if (p == p->parent->right) { slot = &p->parent->right; - } else { - bh_assert(p == p->parent->left); /* @p should be a child of its parent*/ + } + else if (p == p->parent->left) { + /* p should be a child of its parent*/ slot = &p->parent->left; } + else { + goto fail; + } /** * algorithms used to remove node p @@ -51,65 +67,110 @@ remove_tree_node(hmu_tree_node_t *p) if (!p->left) { /* move right child up*/ *slot = p->right; - if (p->right) + if (p->right) { + if (!hmu_is_in_heap(p->right, base_addr, end_addr)) { + goto fail; + } p->right->parent = p->parent; + } p->left = p->right = p->parent = NULL; - return; + return true; } if (!p->right) { /* move left child up*/ *slot = p->left; - p->left->parent = p->parent; /* p->left can never be NULL.*/ + if (!hmu_is_in_heap(p->left, base_addr, end_addr)) { + goto fail; + } + /* p->left can never be NULL unless it is corrupted. */ + p->left->parent = p->parent; p->left = p->right = p->parent = NULL; - return; + return true; } /* both left & right exist, find p's predecessor at first*/ q = p->left; - while (q->right) + if (!hmu_is_in_heap(q, base_addr, end_addr)) { + goto fail; + } + while (q->right) { q = q->right; + if (!hmu_is_in_heap(q, base_addr, end_addr)) { + goto fail; + } + } + /* remove from the tree*/ - remove_tree_node(q); + if (!remove_tree_node(heap, q)) + return false; *slot = q; q->parent = p->parent; q->left = p->left; q->right = p->right; - if (q->left) + if (q->left) { + if (!hmu_is_in_heap(q->left, base_addr, end_addr)) { + goto fail; + } q->left->parent = q; - if (q->right) + } + if (q->right) { + if (!hmu_is_in_heap(q->right, base_addr, end_addr)) { + goto fail; + } q->right->parent = q; + } p->left = p->right = p->parent = NULL; + + return true; +fail: + heap->is_heap_corrupted = true; + return false; } -static void +static bool unlink_hmu(gc_heap_t *heap, hmu_t *hmu) { + gc_uint8 *base_addr, *end_addr; gc_size_t size; bh_assert(gci_is_heap_valid(heap)); bh_assert(hmu && (gc_uint8*) hmu >= heap->base_addr && (gc_uint8*) hmu < heap->base_addr + heap->current_size); - bh_assert(hmu_get_ut(hmu) == HMU_FC); + if (hmu_get_ut(hmu) != HMU_FC) { + heap->is_heap_corrupted = true; + return false; + } + + base_addr = heap->base_addr; + end_addr = base_addr + heap->current_size; size = hmu_get_size(hmu); if (HMU_IS_FC_NORMAL(size)) { uint32 node_idx = size >> 3; - hmu_normal_node_t *node_prev = &heap->kfc_normal_list[node_idx]; - hmu_normal_node_t *node = - get_hmu_normal_node_next(&heap->kfc_normal_list[node_idx]); + hmu_normal_node_t *node_prev = NULL, *node_next; + hmu_normal_node_t *node = heap->kfc_normal_list[node_idx].next; + while (node) { - if ((hmu_t*) node == hmu) { - set_hmu_normal_node_next(node_prev, get_hmu_normal_node_next(node)); + if (!hmu_is_in_heap(node, base_addr, end_addr)) { + heap->is_heap_corrupted = true; + return false; + } + node_next = get_hmu_normal_node_next(node); + if ((hmu_t*)node == hmu) { + if (!node_prev) /* list head */ + heap->kfc_normal_list[node_idx].next = node_next; + else + set_hmu_normal_node_next(node_prev, node_next); break; } node_prev = node; - node = get_hmu_normal_node_next(node); + node = node_next; } if (!node) { @@ -117,8 +178,10 @@ unlink_hmu(gc_heap_t *heap, hmu_t *hmu) } } else { - remove_tree_node((hmu_tree_node_t *) hmu); + if (!remove_tree_node(heap, (hmu_tree_node_t *)hmu)) + return false; } + return true; } static void @@ -140,37 +203,44 @@ hmu_set_free_size(hmu_t *hmu) * @param size should be positive and multiple of 8 * hmu with size @size will be added into KFC as a new FC. */ -void +bool gci_add_fc(gc_heap_t *heap, hmu_t *hmu, gc_size_t size) { + gc_uint8 *base_addr, *end_addr; hmu_normal_node_t *np = NULL; hmu_tree_node_t *root = NULL, *tp = NULL, *node = NULL; uint32 node_idx; bh_assert(gci_is_heap_valid(heap)); - bh_assert(hmu && (gc_uint8*) hmu >= heap->base_addr - && (gc_uint8*) hmu < heap->base_addr + heap->current_size); + bh_assert(hmu && (gc_uint8*)hmu >= heap->base_addr + && (gc_uint8*)hmu < heap->base_addr + heap->current_size); bh_assert(((gc_uint32)(uintptr_t)hmu_to_obj(hmu) & 7) == 0); bh_assert(size > 0 - && ((gc_uint8*) hmu) + size <= heap->base_addr + heap->current_size); + && ((gc_uint8*)hmu) + size <= heap->base_addr + heap->current_size); bh_assert(!(size & 7)); + base_addr = heap->base_addr; + end_addr = base_addr + heap->current_size; + hmu_set_ut(hmu, HMU_FC); hmu_set_size(hmu, size); hmu_set_free_size(hmu); if (HMU_IS_FC_NORMAL(size)) { - np = (hmu_normal_node_t*) hmu; + np = (hmu_normal_node_t*)hmu; + if (!hmu_is_in_heap(np, base_addr, end_addr)) { + heap->is_heap_corrupted = true; + return false; + } node_idx = size >> 3; - set_hmu_normal_node_next(np, get_hmu_normal_node_next - (&heap->kfc_normal_list[node_idx])); - set_hmu_normal_node_next(&heap->kfc_normal_list[node_idx], np); - return; + set_hmu_normal_node_next(np, heap->kfc_normal_list[node_idx].next); + heap->kfc_normal_list[node_idx].next = np; + return true; } /* big block*/ - node = (hmu_tree_node_t*) hmu; + node = (hmu_tree_node_t*)hmu; node->size = size; node->left = node->right = node->parent = NULL; @@ -195,7 +265,12 @@ gci_add_fc(gc_heap_t *heap, hmu_t *hmu, gc_size_t size) } tp = tp->left; } + if (!hmu_is_in_heap(tp, base_addr, end_addr)) { + heap->is_heap_corrupted = true; + return false; + } } + return true; } /** @@ -212,7 +287,9 @@ gci_add_fc(gc_heap_t *heap, hmu_t *hmu, gc_size_t size) static hmu_t * alloc_hmu(gc_heap_t *heap, gc_size_t size) { - hmu_normal_node_t *node = NULL, *p = NULL; + gc_uint8 *base_addr, *end_addr; + hmu_normal_list_t *normal_head = NULL; + hmu_normal_node_t *p = NULL; uint32 node_idx = 0, init_node_idx = 0; hmu_tree_node_t *root = NULL, *tp = NULL, *last_tp = NULL; hmu_t *next, *rest; @@ -220,6 +297,9 @@ alloc_hmu(gc_heap_t *heap, gc_size_t size) bh_assert(gci_is_heap_valid(heap)); bh_assert(size > 0 && !(size & 7)); + base_addr = heap->base_addr; + end_addr = base_addr + heap->current_size; + if (size < GC_SMALLEST_SIZE) size = GC_SMALLEST_SIZE; @@ -229,31 +309,40 @@ alloc_hmu(gc_heap_t *heap, gc_size_t size) init_node_idx = (size >> 3); for (node_idx = init_node_idx; node_idx < HMU_NORMAL_NODE_CNT; node_idx++) { - node = heap->kfc_normal_list + node_idx; - if (get_hmu_normal_node_next(node)) + normal_head = heap->kfc_normal_list + node_idx; + if (normal_head->next) break; - node = NULL; + normal_head = NULL; } - /* not found in normal list*/ - if (node) { + /* found in normal list*/ + if (normal_head) { bh_assert(node_idx >= init_node_idx); - p = get_hmu_normal_node_next(node); - set_hmu_normal_node_next(node, get_hmu_normal_node_next(p)); - bh_assert(((gc_int32)(uintptr_t)hmu_to_obj(p) & 7) == 0); + p = normal_head->next; + if (!hmu_is_in_heap(p, base_addr, end_addr)) { + heap->is_heap_corrupted = true; + return NULL; + } + normal_head->next = get_hmu_normal_node_next(p); + if (((gc_int32)(uintptr_t)hmu_to_obj(p) & 7) != 0) { + heap->is_heap_corrupted = true; + return NULL; + } if ((gc_size_t)node_idx != (uint32)init_node_idx /* with bigger size*/ && ((gc_size_t)node_idx << 3) >= size + GC_SMALLEST_SIZE) { rest = (hmu_t*) (((char *) p) + size); - gci_add_fc(heap, rest, (node_idx << 3) - size); + if (!gci_add_fc(heap, rest, (node_idx << 3) - size)) { + return NULL; + } hmu_mark_pinuse(rest); } else { size = node_idx << 3; next = (hmu_t*) ((char*) p + size); - if (hmu_is_in_heap(heap, next)) + if (hmu_is_in_heap(next, base_addr, end_addr)) hmu_mark_pinuse(next); } @@ -275,6 +364,11 @@ alloc_hmu(gc_heap_t *heap, gc_size_t size) bh_assert(root); tp = root->right; while (tp) { + if (!hmu_is_in_heap(tp, base_addr, end_addr)) { + heap->is_heap_corrupted = true; + return NULL; + } + if (tp->size < size) { tp = tp->right; continue; @@ -291,17 +385,19 @@ alloc_hmu(gc_heap_t *heap, gc_size_t size) /* alloc in last_p*/ /* remove node last_p from tree*/ - remove_tree_node(last_tp); + if (!remove_tree_node(heap, last_tp)) + return NULL; if (last_tp->size >= size + GC_SMALLEST_SIZE) { - rest = (hmu_t*) ((char*) last_tp + size); - gci_add_fc(heap, rest, last_tp->size - size); + rest = (hmu_t*)((char*)last_tp + size); + if (!gci_add_fc(heap, rest, last_tp->size - size)) + return NULL; hmu_mark_pinuse(rest); } else { size = last_tp->size; - next = (hmu_t*) ((char*) last_tp + size); - if (hmu_is_in_heap(heap, next)) + next = (hmu_t*)((char*)last_tp + size); + if (hmu_is_in_heap(next, base_addr, end_addr)) hmu_mark_pinuse(next); } @@ -309,8 +405,8 @@ alloc_hmu(gc_heap_t *heap, gc_size_t size) if ((heap->current_size - heap->total_free_size) > heap->highmark_size) heap->highmark_size = heap->current_size - heap->total_free_size; - hmu_set_size((hmu_t* ) last_tp, size); - return (hmu_t*) last_tp; + hmu_set_size((hmu_t*)last_tp, size); + return (hmu_t*)last_tp; } return NULL; @@ -365,6 +461,11 @@ gc_alloc_vo_internal(void *vheap, gc_size_t size, /* integer overflow */ return NULL; + if (heap->is_heap_corrupted) { + os_printf("[GC_ERROR]Heap is corrupted, allocate memory failed.\n"); + return NULL; + } + os_mutex_lock(&heap->lock); hmu = alloc_hmu_ex(heap, tot_size); @@ -404,6 +505,7 @@ gc_realloc_vo_internal(void *vheap, void *ptr, gc_size_t size, gc_object_t ret = (gc_object_t) NULL, obj_old = (gc_object_t)ptr; gc_size_t tot_size, tot_size_unaligned, tot_size_old = 0, tot_size_next; gc_size_t obj_size, obj_size_old; + gc_uint8 *base_addr, *end_addr; hmu_type_t ut; /* hmu header + prefix + obj + suffix */ @@ -414,6 +516,11 @@ gc_realloc_vo_internal(void *vheap, void *ptr, gc_size_t size, /* integer overflow */ return NULL; + if (heap->is_heap_corrupted) { + os_printf("[GC_ERROR]Heap is corrupted, allocate memory failed.\n"); + return NULL; + } + if (obj_old) { hmu_old = obj_to_hmu(obj_old); tot_size_old = hmu_get_size(hmu_old); @@ -422,17 +529,23 @@ gc_realloc_vo_internal(void *vheap, void *ptr, gc_size_t size, return obj_old; } + base_addr = heap->base_addr; + end_addr = base_addr + heap->current_size; + os_mutex_lock(&heap->lock); if (hmu_old) { hmu_next = (hmu_t*)((char *)hmu_old + tot_size_old); - if (hmu_is_in_heap(heap, hmu_next)) { + if (hmu_is_in_heap(hmu_next, base_addr, end_addr)) { ut = hmu_get_ut(hmu_next); tot_size_next = hmu_get_size(hmu_next); if (ut == HMU_FC && tot_size <= tot_size_old + tot_size_next) { /* current node and next node meets requirement */ - unlink_hmu(heap, hmu_next); + if (!unlink_hmu(heap, hmu_next)) { + os_mutex_unlock(&heap->lock); + return NULL; + } hmu_set_size(hmu_old, tot_size); memset((char*)hmu_old + tot_size_old, 0, tot_size - tot_size_old); #if BH_ENABLE_GC_VERIFY != 0 @@ -441,7 +554,10 @@ gc_realloc_vo_internal(void *vheap, void *ptr, gc_size_t size, if (tot_size < tot_size_old + tot_size_next) { hmu_next = (hmu_t*)((char*)hmu_old + tot_size); tot_size_next = tot_size_old + tot_size_next - tot_size; - gci_add_fc(heap, hmu_next, tot_size_next); + if (!gci_add_fc(heap, hmu_next, tot_size_next)) { + os_mutex_unlock(&heap->lock); + return NULL; + } } os_mutex_unlock(&heap->lock); return obj_old; @@ -507,6 +623,7 @@ gc_free_vo_internal(void *vheap, gc_object_t obj, #endif { gc_heap_t* heap = (gc_heap_t*) vheap; + gc_uint8 *base_addr, *end_addr; hmu_t *hmu = NULL; hmu_t *prev = NULL; hmu_t *next = NULL; @@ -518,14 +635,21 @@ gc_free_vo_internal(void *vheap, gc_object_t obj, return GC_SUCCESS; } + if (heap->is_heap_corrupted) { + os_printf("[GC_ERROR]Heap is corrupted, free memory failed.\n"); + return GC_ERROR; + } + hmu = obj_to_hmu(obj); + base_addr = heap->base_addr; + end_addr = base_addr + heap->current_size; + os_mutex_lock(&heap->lock); - if ((gc_uint8 *)hmu >= heap->base_addr - && (gc_uint8 *)hmu < heap->base_addr + heap->current_size) { + if (hmu_is_in_heap(hmu, base_addr, end_addr)) { #if BH_ENABLE_GC_VERIFY != 0 - hmu_verify(hmu); + hmu_verify(heap, hmu); #endif ut = hmu_get_ut(hmu); if (ut == HMU_VO) { @@ -544,25 +668,35 @@ gc_free_vo_internal(void *vheap, gc_object_t obj, if (!hmu_get_pinuse(hmu)) { prev = (hmu_t*) ((char*) hmu - *((int*) hmu - 1)); - if (hmu_is_in_heap(heap, prev) && hmu_get_ut(prev) == HMU_FC) { + if (hmu_is_in_heap(prev, base_addr, end_addr) + && hmu_get_ut(prev) == HMU_FC) { size += hmu_get_size(prev); hmu = prev; - unlink_hmu(heap, prev); + if (!unlink_hmu(heap, prev)) { + ret = GC_ERROR; + goto out; + } } } next = (hmu_t*) ((char*) hmu + size); - if (hmu_is_in_heap(heap, next)) { + if (hmu_is_in_heap(next, base_addr, end_addr)) { if (hmu_get_ut(next) == HMU_FC) { size += hmu_get_size(next); - unlink_hmu(heap, next); - next = (hmu_t*) ((char*) hmu + size); + if (!unlink_hmu(heap, next)) { + ret = GC_ERROR; + goto out; + } + next = (hmu_t*)((char*) hmu + size); } } - gci_add_fc(heap, hmu, size); + if (!gci_add_fc(heap, hmu, size)) { + ret = GC_ERROR; + goto out; + } - if (hmu_is_in_heap(heap, next)) { + if (hmu_is_in_heap(next, base_addr, end_addr)) { hmu_unmark_pinuse(next); } @@ -620,7 +754,11 @@ gci_dump(gc_heap_t *heap) else if (ut == HMU_FC) inuse = 'F'; - bh_assert(size > 0); + if (size == 0) { + os_printf("[GC_ERROR]Heap is corrupted, heap dump failed.\n"); + heap->is_heap_corrupted = true; + return; + } os_printf("#%d %08x %x %x %d %c %d\n", i, (int32)((char*) cur - (char*) heap->base_addr), diff --git a/core/shared/mem-alloc/ems/ems_gc.h b/core/shared/mem-alloc/ems/ems_gc.h index 206c8bd0f..c712c9087 100644 --- a/core/shared/mem-alloc/ems/ems_gc.h +++ b/core/shared/mem-alloc/ems/ems_gc.h @@ -51,7 +51,10 @@ typedef enum { } GC_STAT_INDEX; /** - * GC initialization from a buffer + * GC initialization from a buffer, which is separated into + * two parts: the beginning of the buffer is used to create + * the heap structure, and the left is used to create the + * actual pool data * * @param buf the buffer to be initialized to a heap * @param buf_size the size of buffer @@ -61,6 +64,20 @@ typedef enum { gc_handle_t gc_init_with_pool(char *buf, gc_size_t buf_size); +/** + * GC initialization from heap struct buffer and pool buffer + * + * @param struct_buf the struct buffer to create the heap structure + * @param struct_buf_size the size of struct buffer + * @param pool_buf the pool buffer to create pool data + * @param pool_buf_size the size of poll buffer + * + * @return gc handle if success, NULL otherwise + */ +gc_handle_t +gc_init_with_struct_and_pool(char *struct_buf, gc_size_t struct_buf_size, + char *pool_buf, gc_size_t pool_buf_size); + /** * Destroy heap which is initilized from a buffer * @@ -73,25 +90,23 @@ int gc_destroy_with_pool(gc_handle_t handle); /** - * Migrate heap from one place to another place - * - * @param handle handle of the new heap - * @param handle_old handle of the old heap - * - * @return GC_SUCCESS if success, GC_ERROR otherwise + * Return heap struct size */ -int -gc_migrate(gc_handle_t handle, gc_handle_t handle_old); +uint32 +gc_get_heap_struct_size(void); /** - * Re-initialize lock of heap + * Migrate heap from one pool buf to another pool buf * - * @param handle the heap handle + * @param handle handle of the new heap + * @param pool_buf_new the new pool buffer + * @param pool_buf_size the size of new pool buffer * * @return GC_SUCCESS if success, GC_ERROR otherwise */ int -gc_reinit_lock(gc_handle_t handle); +gc_migrate(gc_handle_t handle, + char *pool_buf_new, gc_size_t pool_buf_size); /** * Destroy lock of heap diff --git a/core/shared/mem-alloc/ems/ems_gc_internal.h b/core/shared/mem-alloc/ems/ems_gc_internal.h index 680d70e74..aaf49068d 100644 --- a/core/shared/mem-alloc/ems/ems_gc_internal.h +++ b/core/shared/mem-alloc/ems/ems_gc_internal.h @@ -52,7 +52,7 @@ hmu_init_prefix_and_suffix(hmu_t *hmu, gc_size_t tot_size, const char *file_name, int line_no); void -hmu_verify(hmu_t *hmu); +hmu_verify(void *vheap, hmu_t *hmu); #define SKIP_OBJ_PREFIX(p) ((void*)((gc_uint8*)(p) + OBJ_PREFIX_SIZE)) #define SKIP_OBJ_SUFFIX(p) ((void*)((gc_uint8*)(p) + OBJ_SUFFIX_SIZE)) @@ -159,6 +159,10 @@ typedef struct hmu_normal_node { gc_int32 next_offset; } hmu_normal_node_t; +typedef struct hmu_normal_list { + hmu_normal_node_t *next; +} hmu_normal_list_t; + static inline hmu_normal_node_t * get_hmu_normal_node_next(hmu_normal_node_t *node) { @@ -197,11 +201,15 @@ typedef struct gc_heap_struct { korp_mutex lock; - hmu_normal_node_t kfc_normal_list[HMU_NORMAL_NODE_CNT]; + hmu_normal_list_t kfc_normal_list[HMU_NORMAL_NODE_CNT]; /* order in kfc_tree is: size[left] <= size[cur] < size[right]*/ hmu_tree_node_t kfc_tree_root; + /* whether heap is corrupted, e.g. the hmu nodes are modified + by user */ + bool is_heap_corrupted; + gc_size_t init_size; gc_size_t highmark_size; gc_size_t total_free_size; @@ -211,7 +219,7 @@ typedef struct gc_heap_struct { * MISC internal used APIs */ -void +bool gci_add_fc(gc_heap_t *heap, hmu_t *hmu, gc_size_t size); int diff --git a/core/shared/mem-alloc/ems/ems_hmu.c b/core/shared/mem-alloc/ems/ems_hmu.c index cd55dc176..d7cf34189 100644 --- a/core/shared/mem-alloc/ems/ems_hmu.c +++ b/core/shared/mem-alloc/ems/ems_hmu.c @@ -45,8 +45,9 @@ hmu_init_prefix_and_suffix(hmu_t *hmu, gc_size_t tot_size, } void -hmu_verify(hmu_t *hmu) +hmu_verify(void *vheap, hmu_t *hmu) { + gc_heap_t *heap = (gc_heap_t *)vheap; gc_object_prefix_t *prefix = NULL; gc_object_suffix_t *suffix = NULL; gc_uint32 i = 0; @@ -62,32 +63,27 @@ hmu_verify(hmu_t *hmu) size = prefix->size; suffix = (gc_object_suffix_t *)((gc_uint8*)hmu + size - OBJ_SUFFIX_SIZE); - if(ut == HMU_VO || ut == HMU_JO) - { + if (ut == HMU_VO || ut == HMU_JO) { /* check padding*/ - for(i = 0;i < GC_OBJECT_PREFIX_PADDING_CNT;i++) - { - if(prefix->padding[i] != GC_OBJECT_PADDING_VALUE) - { + for (i = 0;i < GC_OBJECT_PREFIX_PADDING_CNT;i++) { + if (prefix->padding[i] != GC_OBJECT_PADDING_VALUE) { is_padding_ok = 0; break; } } - for(i = 0;i < GC_OBJECT_SUFFIX_PADDING_CNT;i++) - { - if(suffix->padding[i] != GC_OBJECT_PADDING_VALUE) - { + for (i = 0;i < GC_OBJECT_SUFFIX_PADDING_CNT;i++) { + if (suffix->padding[i] != GC_OBJECT_PADDING_VALUE) { is_padding_ok = 0; break; } } - if(!is_padding_ok) - { - os_printf("Invalid padding for object created at %s:%d", - (prefix->file_name ? prefix->file_name : ""), prefix->line_no); + if (!is_padding_ok) { + os_printf("Invalid padding for object created at %s:%d\n", + (prefix->file_name ? prefix->file_name : ""), + prefix->line_no); + heap->is_heap_corrupted = true; } - bh_assert(is_padding_ok); } } diff --git a/core/shared/mem-alloc/ems/ems_kfc.c b/core/shared/mem-alloc/ems/ems_kfc.c index fcf487bb9..ddfc5e4fe 100644 --- a/core/shared/mem-alloc/ems/ems_kfc.c +++ b/core/shared/mem-alloc/ems/ems_kfc.c @@ -5,26 +5,11 @@ #include "ems_gc_internal.h" -gc_handle_t -gc_init_with_pool(char *buf, gc_size_t buf_size) +static gc_handle_t +gc_init_internal(gc_heap_t *heap, char *base_addr, gc_size_t heap_max_size) { - char *buf_end = buf + buf_size; - char *buf_aligned = (char*)(((uintptr_t) buf + 7) & (uintptr_t)~7); - char *base_addr = buf_aligned + sizeof(gc_heap_t); - gc_heap_t *heap = (gc_heap_t*)buf_aligned; - gc_size_t heap_max_size; - hmu_normal_node_t *p = NULL; hmu_tree_node_t *root = NULL, *q = NULL; - int i = 0, ret; - - if (buf_size < APP_HEAP_SIZE_MIN) { - os_printf("[GC_ERROR]heap init buf size (%u) < %u\n", - buf_size, APP_HEAP_SIZE_MIN); - return NULL; - } - - base_addr = (char*) (((uintptr_t) base_addr + 7) & (uintptr_t)~7) + GC_HEAD_PADDING; - heap_max_size = (uint32)(buf_end - base_addr) & (uint32)~7; + int ret; memset(heap, 0, sizeof *heap); memset(base_addr, 0, heap_max_size); @@ -43,14 +28,6 @@ gc_init_with_pool(char *buf, gc_size_t buf_size) heap->total_free_size = heap->current_size; heap->highmark_size = 0; - for (i = 0; i < HMU_NORMAL_NODE_CNT; i++) { - /* make normal node look like a FC*/ - p = &heap->kfc_normal_list[i]; - memset(p, 0, sizeof *p); - hmu_set_ut(&p->hmu_header, HMU_FC); - hmu_set_size(&p->hmu_header, sizeof *p); - } - root = &heap->kfc_tree_root; memset(root, 0, sizeof *root); root->size = sizeof *root; @@ -79,6 +56,63 @@ gc_init_with_pool(char *buf, gc_size_t buf_size) return heap; } +gc_handle_t +gc_init_with_pool(char *buf, gc_size_t buf_size) +{ + char *buf_end = buf + buf_size; + char *buf_aligned = (char*)(((uintptr_t) buf + 7) & (uintptr_t)~7); + char *base_addr = buf_aligned + sizeof(gc_heap_t); + gc_heap_t *heap = (gc_heap_t*)buf_aligned; + gc_size_t heap_max_size; + + if (buf_size < APP_HEAP_SIZE_MIN) { + os_printf("[GC_ERROR]heap init buf size (%u) < %u\n", + buf_size, APP_HEAP_SIZE_MIN); + return NULL; + } + + base_addr = (char*) (((uintptr_t) base_addr + 7) & (uintptr_t)~7) + GC_HEAD_PADDING; + heap_max_size = (uint32)(buf_end - base_addr) & (uint32)~7; + + return gc_init_internal(heap, base_addr, heap_max_size); +} + +gc_handle_t +gc_init_with_struct_and_pool(char *struct_buf, gc_size_t struct_buf_size, + char *pool_buf, gc_size_t pool_buf_size) +{ + gc_heap_t *heap = (gc_heap_t*)struct_buf; + char *base_addr = pool_buf + GC_HEAD_PADDING; + char *pool_buf_end = pool_buf + pool_buf_size; + gc_size_t heap_max_size; + + if ((((uintptr_t)struct_buf) & 7) != 0) { + os_printf("[GC_ERROR]heap init struct buf not 8-byte aligned\n"); + return NULL; + } + + if (struct_buf_size < sizeof(gc_handle_t)) { + os_printf("[GC_ERROR]heap init struct buf size (%u) < %u\n", + struct_buf_size, sizeof(gc_handle_t)); + return NULL; + } + + if ((((uintptr_t)pool_buf) & 7) != 0) { + os_printf("[GC_ERROR]heap init pool buf not 8-byte aligned\n"); + return NULL; + } + + if (pool_buf_size < APP_HEAP_SIZE_MIN) { + os_printf("[GC_ERROR]heap init buf size (%u) < %u\n", + pool_buf_size, APP_HEAP_SIZE_MIN); + return NULL; + } + + heap_max_size = (uint32)(pool_buf_end - base_addr) & (uint32)~7; + + return gc_init_internal(heap, base_addr, heap_max_size); +} + int gc_destroy_with_pool(gc_handle_t handle) { @@ -86,7 +120,8 @@ gc_destroy_with_pool(gc_handle_t handle) #if BH_ENABLE_GC_VERIFY != 0 hmu_t *cur = (hmu_t*)heap->base_addr; hmu_t *end = (hmu_t*)((char*)heap->base_addr + heap->current_size); - if ((hmu_t*)((char *)cur + hmu_get_size(cur)) != end) { + if (!heap->is_heap_corrupted + && (hmu_t*)((char *)cur + hmu_get_size(cur)) != end) { os_printf("Memory leak detected:\n"); gci_dump(heap); #if WASM_ENABLE_SPEC_TEST != 0 @@ -100,6 +135,12 @@ gc_destroy_with_pool(gc_handle_t handle) return GC_SUCCESS; } +uint32 +gc_get_heap_struct_size() +{ + return sizeof(gc_heap_t); +} + static void adjust_ptr(uint8 **p_ptr, intptr_t offset) { @@ -108,21 +149,34 @@ adjust_ptr(uint8 **p_ptr, intptr_t offset) } int -gc_migrate(gc_handle_t handle, gc_handle_t handle_old) +gc_migrate(gc_handle_t handle, + char *pool_buf_new, gc_size_t pool_buf_size) { - gc_heap_t *heap = (gc_heap_t *) handle; - intptr_t offset = (uint8*)handle - (uint8*)handle_old; + gc_heap_t *heap = (gc_heap_t *)handle; + char *base_addr_new = pool_buf_new + GC_HEAD_PADDING; + char *pool_buf_end = pool_buf_new + pool_buf_size; + intptr_t offset = (uint8*)base_addr_new - (uint8*)heap->base_addr; hmu_t *cur = NULL, *end = NULL; hmu_tree_node_t *tree_node; - gc_size_t size; + gc_size_t heap_max_size, size; - os_mutex_init(&heap->lock); + if ((((uintptr_t)pool_buf_new) & 7) != 0) { + os_printf("[GC_ERROR]heap migrate pool buf not 8-byte aligned\n"); + return GC_ERROR; + } + + heap_max_size = (uint32)(pool_buf_end - base_addr_new) & (uint32)~7; + + if (pool_buf_end < base_addr_new + || heap_max_size < heap->current_size) { + os_printf("[GC_ERROR]heap migrate invlaid pool buf size\n"); + return GC_ERROR; + } if (offset == 0) return 0; - heap->heap_id = (gc_handle_t)heap; - heap->base_addr += offset; + heap->base_addr = (uint8*)base_addr_new; adjust_ptr((uint8**)&heap->kfc_tree_root.left, offset); adjust_ptr((uint8**)&heap->kfc_tree_root.right, offset); adjust_ptr((uint8**)&heap->kfc_tree_root.parent, offset); @@ -138,7 +192,10 @@ gc_migrate(gc_handle_t handle, gc_handle_t handle_old) tree_node = (hmu_tree_node_t *)cur; adjust_ptr((uint8**)&tree_node->left, offset); adjust_ptr((uint8**)&tree_node->right, offset); - adjust_ptr((uint8**)&tree_node->parent, offset); + if (tree_node->parent != &heap->kfc_tree_root) + /* The root node belongs to heap structure, + it is fixed part and isn't changed. */ + adjust_ptr((uint8**)&tree_node->parent, offset); } cur = (hmu_t*)((char *)cur + size); } @@ -147,13 +204,6 @@ gc_migrate(gc_handle_t handle, gc_handle_t handle_old) return 0; } -int -gc_reinit_lock(gc_handle_t handle) -{ - gc_heap_t *heap = (gc_heap_t *) handle; - return os_mutex_init(&heap->lock); -} - void gc_destroy_lock(gc_handle_t handle) { @@ -170,9 +220,8 @@ gci_verify_heap(gc_heap_t *heap) bh_assert(heap && gci_is_heap_valid(heap)); cur = (hmu_t *)heap->base_addr; end = (hmu_t *)(heap->base_addr + heap->current_size); - while(cur < end) - { - hmu_verify(cur); + while(cur < end) { + hmu_verify(heap, cur); cur = (hmu_t *)((gc_uint8*)cur + hmu_get_size(cur)); } bh_assert(cur == end); diff --git a/core/shared/mem-alloc/mem_alloc.c b/core/shared/mem-alloc/mem_alloc.c index 32d07513f..f2304f8e4 100644 --- a/core/shared/mem-alloc/mem_alloc.c +++ b/core/shared/mem-alloc/mem_alloc.c @@ -14,11 +14,29 @@ mem_allocator_t mem_allocator_create(void *mem, uint32_t size) return gc_init_with_pool((char *) mem, size); } +mem_allocator_t +mem_allocator_create_with_struct_and_pool(void *struct_buf, + uint32_t struct_buf_size, + void *pool_buf, + uint32_t pool_buf_size) +{ + return gc_init_with_struct_and_pool((char *)struct_buf, + struct_buf_size, + pool_buf, + pool_buf_size); +} + void mem_allocator_destroy(mem_allocator_t allocator) { gc_destroy_with_pool((gc_handle_t) allocator); } +uint32 +mem_allocator_get_heap_struct_size() +{ + return gc_get_heap_struct_size(); +} + void * mem_allocator_malloc(mem_allocator_t allocator, uint32_t size) { @@ -39,16 +57,10 @@ void mem_allocator_free(mem_allocator_t allocator, void *ptr) int mem_allocator_migrate(mem_allocator_t allocator, - mem_allocator_t allocator_old) + char *pool_buf_new, uint32 pool_buf_size) { return gc_migrate((gc_handle_t) allocator, - (gc_handle_t) allocator_old); -} - -int -mem_allocator_reinit_lock(mem_allocator_t allocator) -{ - return gc_reinit_lock((gc_handle_t) allocator); + pool_buf_new, pool_buf_size); } void diff --git a/core/shared/mem-alloc/mem_alloc.h b/core/shared/mem-alloc/mem_alloc.h index eb1032e5c..21e97f5bc 100644 --- a/core/shared/mem-alloc/mem_alloc.h +++ b/core/shared/mem-alloc/mem_alloc.h @@ -17,9 +17,18 @@ typedef void *mem_allocator_t; mem_allocator_t mem_allocator_create(void *mem, uint32_t size); +mem_allocator_t +mem_allocator_create_with_struct_and_pool(void *struct_buf, + uint32_t struct_buf_size, + void *pool_buf, + uint32_t pool_buf_size); + void mem_allocator_destroy(mem_allocator_t allocator); +uint32 +mem_allocator_get_heap_struct_size(void); + void * mem_allocator_malloc(mem_allocator_t allocator, uint32_t size); @@ -31,10 +40,7 @@ mem_allocator_free(mem_allocator_t allocator, void *ptr); int mem_allocator_migrate(mem_allocator_t allocator, - mem_allocator_t allocator_old); - -int -mem_allocator_reinit_lock(mem_allocator_t allocator); + char *pool_buf_new, uint32 pool_buf_size); void mem_allocator_destroy_lock(mem_allocator_t allocator); From c9c882e43da63e540c3d36340b81b0a06bb31f3d Mon Sep 17 00:00:00 2001 From: Wang Ning Date: Fri, 23 Oct 2020 18:16:56 +0800 Subject: [PATCH 102/207] Fix compilation error for sgxsdk-2.11 (#431) sgxsdk-2.11 enable pthread_rwlock APIs support, and causes compilation error. We use macro SGX_THREAD_LOCK_INITIALIZER to control it. --- core/shared/platform/linux-sgx/sgx_pthread.c | 4 ++++ core/shared/platform/linux-sgx/sgx_pthread.h | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/core/shared/platform/linux-sgx/sgx_pthread.c b/core/shared/platform/linux-sgx/sgx_pthread.c index 0d8a9933b..cf000565a 100644 --- a/core/shared/platform/linux-sgx/sgx_pthread.c +++ b/core/shared/platform/linux-sgx/sgx_pthread.c @@ -12,6 +12,9 @@ #define TRACE_FUNC() os_printf("undefined %s\n", __FUNCTION__) #define TRACE_OCALL_FAIL() os_printf("ocall %s failed!\n", __FUNCTION__) +#ifndef SGX_THREAD_LOCK_INITIALIZER /* defined since sgxsdk-2.11 */ +/* sgxsdk doesn't support pthread_rwlock related APIs until + version 2.11, we implement them by ourselves. */ int ocall_pthread_rwlock_init(int *p_ret, void **rwlock, void *attr); int ocall_pthread_rwlock_destroy(int *p_ret, void **rwlock); @@ -74,6 +77,7 @@ int pthread_rwlock_unlock(pthread_rwlock_t *rwlock) } return ret; } +#endif /* end of SGX_THREAD_LOCK_INITIALIZER */ #endif diff --git a/core/shared/platform/linux-sgx/sgx_pthread.h b/core/shared/platform/linux-sgx/sgx_pthread.h index 550cbf8c6..513bd3ab0 100644 --- a/core/shared/platform/linux-sgx/sgx_pthread.h +++ b/core/shared/platform/linux-sgx/sgx_pthread.h @@ -10,6 +10,9 @@ extern "C" { #endif +#ifndef SGX_THREAD_LOCK_INITIALIZER /* defined since sgxsdk-2.11 */ +/* sgxsdk doesn't support pthread_rwlock related APIs until + version 2.11, we implement them by ourselves. */ typedef uintptr_t pthread_rwlock_t; int pthread_rwlock_init(pthread_rwlock_t *rwlock, void *attr); @@ -18,6 +21,7 @@ int pthread_rwlock_destroy(pthread_rwlock_t *rwlock); int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock); int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock); int pthread_rwlock_unlock(pthread_rwlock_t *rwlock); +#endif /* end of SGX_THREAD_LOCK_INITIALIZER */ #ifdef __cplusplus } From ad4aa9a85f4199948732ded65207270f996fea40 Mon Sep 17 00:00:00 2001 From: Wang Ning Date: Thu, 29 Oct 2020 11:33:49 +0800 Subject: [PATCH 103/207] Update build script to enable running tensorflow workload in linux-sgx (#435) --- .../enclave-sample/Enclave/Enclave.config.xml | 4 +- samples/workload/tensorflow/README.md | 9 ++- samples/workload/tensorflow/build.sh | 64 ++++++++++++++----- 3 files changed, 58 insertions(+), 19 deletions(-) diff --git a/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.config.xml b/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.config.xml index 6a48563ea..5b7387b55 100644 --- a/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.config.xml +++ b/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.config.xml @@ -3,8 +3,8 @@ 0 0 0x100000 - 0x1000000 - 0x400000 + 0x2000000 + 0x1000000 1 10 1 diff --git a/samples/workload/tensorflow/README.md b/samples/workload/tensorflow/README.md index d34f51ec3..8883a57e1 100644 --- a/samples/workload/tensorflow/README.md +++ b/samples/workload/tensorflow/README.md @@ -11,7 +11,14 @@ And set up ensdk environment: ```bash source emsdk_env.sh ``` -Then run ./build.sh to build tensorflow and run it with iwasm, which basically contains the following steps: +Then run +```bash +./build.sh +# for linux platform, or +./build.sh --sgx +# for linux-sgx platform +``` +to build tensorflow and run it with iwasm, which basically contains the following steps: - hack emcc to delete some objects in libc.a - build tf-lite with emcc compiler - build iwasm with pthread enable and include libiary under libc-emcc diff --git a/samples/workload/tensorflow/build.sh b/samples/workload/tensorflow/build.sh index d1fdde048..d519ec5b0 100755 --- a/samples/workload/tensorflow/build.sh +++ b/samples/workload/tensorflow/build.sh @@ -3,15 +3,15 @@ #################################### # build tensorflow-lite sample # #################################### -set -x -set -e +set -xe EMSDK_WASM_DIR="$EM_CACHE/wasm" BUILD_SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -OUT_DIR=${BUILD_SCRIPT_DIR}/out +OUT_DIR="${BUILD_SCRIPT_DIR}/out" TENSORFLOW_DIR="${BUILD_SCRIPT_DIR}/tensorflow" -TF_LITE_BUILD_DIR=${TENSORFLOW_DIR}/tensorflow/lite/tools/make -WAMR_DIR="${BUILD_SCRIPT_DIR}/../../../product-mini/platforms/linux" +TF_LITE_BUILD_DIR="${TENSORFLOW_DIR}/tensorflow/lite/tools/make" +WAMR_PLATFORM_DIR="${BUILD_SCRIPT_DIR}/../../../product-mini/platforms" +WAMRC_DIR="${BUILD_SCRIPT_DIR}/../../../wamr-compiler" function Clear_Before_Exit { @@ -64,34 +64,66 @@ fi if [ -d "${TF_LITE_BUILD_DIR}/gen" ]; then rm -fr ${TF_LITE_BUILD_DIR}/gen fi -make -j 4 -C "${TENSORFLOW_DIR}" -f ${TF_LITE_BUILD_DIR}/Makefile $@ +make -j 4 -C "${TENSORFLOW_DIR}" -f ${TF_LITE_BUILD_DIR}/Makefile # 2.5 copy /make/gen target files to out/ rm -rf ${OUT_DIR} mkdir ${OUT_DIR} cp -r ${TF_LITE_BUILD_DIR}/gen/linux_x86_64/bin/. ${OUT_DIR}/ -# 3. build iwasm with pthread and libc_emcc enable -cd ${WAMR_DIR} +# 3. compile tf-model.wasm to tf-model.aot with wamrc +# 3.1 build wamr-compiler +cd ${WAMRC_DIR} +./build_llvm.sh rm -fr build && mkdir build -cd build && cmake .. -DWAMR_BUILD_LIB_PTHREAD=1 -DWAMR_BUILD_LIBC_EMCC=1 +cd build && cmake .. make +# 3.2 compile tf-mode.wasm to tf-model.aot +WAMRC_CMD="$(pwd)/wamrc" +cd ${OUT_DIR} +if [[ $1 == '--sgx' ]]; then + ${WAMRC_CMD} -sgx -o benchmark_model.aot benchmark_model.wasm +else + ${WAMRC_CMD} -o benchmark_model.aot benchmark_model.wasm +fi -# 4. run tensorflow with iwasm +# 4. build iwasm with pthread and libc_emcc enable +# platform: +# linux by default +# linux-sgx if $1 equals '--sgx' +if [[ $1 == '--sgx' ]]; then + cd ${WAMR_PLATFORM_DIR}/linux-sgx + rm -fr build && mkdir build + cd build && cmake .. -DWAMR_BUILD_LIB_PTHREAD=1 -DWAMR_BUILD_LIBC_EMCC=1 + make + cd ../enclave-sample + make +else + cd ${WAMR_PLATFORM_DIR}/linux + rm -fr build && mkdir build + cd build && cmake .. -DWAMR_BUILD_LIB_PTHREAD=1 -DWAMR_BUILD_LIBC_EMCC=1 + make +fi + +# 5. run tensorflow with iwasm cd ${BUILD_SCRIPT_DIR} -# 4.1 download tf-lite model +# 5.1 download tf-lite model if [ ! -f mobilenet_quant_v1_224.tflite ]; then wget "https://storage.googleapis.com/download.tensorflow.org/models/tflite/mobilenet_v1_224_android_quant_2017_11_08.zip" unzip mobilenet_v1_224_android_quant_2017_11_08.zip fi -# 4.2 run tf-lite model with iwasm +# 5.2 run tf-lite model with iwasm echo "---> run tensorflow benchmark model with iwasm" -${WAMR_DIR}/build/iwasm --heap-size=10475860 \ - ${OUT_DIR}/benchmark_model.wasm \ +if [[ $1 == '--sgx' ]]; then + IWASM_CMD="${WAMR_PLATFORM_DIR}/linux-sgx/enclave-sample/iwasm" +else + IWASM_CMD="${WAMR_PLATFORM_DIR}/linux/build/iwasm" +fi + +${IWASM_CMD} --heap-size=10475860 \ + ${OUT_DIR}/benchmark_model.aot \ --graph=mobilenet_quant_v1_224.tflite --max_secs=300 Clear_Before_Exit - - From ed94b7dcc4355b02f445b88f4ba115d77fdefe83 Mon Sep 17 00:00:00 2001 From: YaoLe Date: Thu, 29 Oct 2020 11:34:34 +0800 Subject: [PATCH 104/207] Implement Inclavare Containers PAL interface in WAMR Linux-SGX (#429) * Implement the PAL interface for rune Work in progress Signed-off-by: Le Yao * Support PAL for one runtime with multi-instances Load runtime into enclave and run multi-instances Signed-off-by: Le Yao --- .../linux-sgx/enclave-sample/App/App.cpp | 167 ++++++++++++++ .../linux-sgx/enclave-sample/App/README.md | 206 ++++++++++++++++++ .../linux-sgx/enclave-sample/App/pal_api.h | 146 +++++++++++++ .../enclave-sample/App/wamr-bundle.md | 65 ++++++ 4 files changed, 584 insertions(+) create mode 100644 product-mini/platforms/linux-sgx/enclave-sample/App/README.md create mode 100644 product-mini/platforms/linux-sgx/enclave-sample/App/pal_api.h create mode 100644 product-mini/platforms/linux-sgx/enclave-sample/App/wamr-bundle.md diff --git a/product-mini/platforms/linux-sgx/enclave-sample/App/App.cpp b/product-mini/platforms/linux-sgx/enclave-sample/App/App.cpp index 350966192..e3c37a1fc 100644 --- a/product-mini/platforms/linux-sgx/enclave-sample/App/App.cpp +++ b/product-mini/platforms/linux-sgx/enclave-sample/App/App.cpp @@ -16,6 +16,7 @@ #include "Enclave_u.h" #include "sgx_urts.h" +#include "pal_api.h" #ifndef TRUE #define TRUE 1 @@ -33,6 +34,12 @@ static sgx_enclave_id_t g_eid = 0; +sgx_enclave_id_t +pal_get_enclave_id(void) +{ + return g_eid; +} + void ocall_print(const char* str) { @@ -734,3 +741,163 @@ fail1: return 0; } +int +wamr_pal_get_version(void) +{ + return WAMR_PAL_VERSION; +} + +int +wamr_pal_init(const struct wamr_pal_attr *args) +{ + sgx_enclave_id_t *p_eid = &g_eid; + + if (enclave_init(&g_eid) < 0) { + std::cout << "Fail to initialize enclave." << std::endl; + return 1; + } +} + +int +wamr_pal_create_process(struct wamr_pal_create_process_args *args) +{ + uint32_t stack_size = 16 * 1024, heap_size = 16 * 1024; + int log_verbose_level = 2; + bool is_repl_mode = false, alloc_with_pool = false; + const char *dir_list[8] = { NULL }; + uint32_t dir_list_size = 0; + const char *env_list[8] = { NULL }; + uint32_t env_list_size = 0; + uint32_t max_thread_num = 4; + char *wasm_files[16]; + void *wasm_module_inst[16]; + + int argc = 2; + char *argv[argc] = { (char*)"./iwasm", (char *)args->argv[0] }; + + uint8_t *wasm_files_buf = NULL; + void *wasm_modules = NULL; + int len = 0, i; + + char *temp = (char *)args->argv[0]; + while(temp) { + len++; + temp=(char *)args->argv[len]; + } + + if (len > sizeof(wasm_files)/sizeof(char *)) { + printf("Number of input files is out of range\n"); + return -1; + } + + for (i = 0; i < len; ++i) { + wasm_files[i] = (char *)args->argv[i]; + } + + /* Init runtime */ + if (!init_runtime(alloc_with_pool, max_thread_num)) { + printf("Failed to init runtime\n"); + return -1; + } + + /* Set log verbose level */ + if (!set_log_verbose_level(log_verbose_level)) { + printf("Failed to set log level\n"); + destroy_runtime(); + return -1; + } + + for (i = 0; i < len; ++i) { + uint8_t *wasm_file_buf = NULL; + uint32_t wasm_file_size; + void *wasm_module = NULL; + char error_buf[128] = { 0 }; + + /* Load WASM byte buffer from WASM bin file */ + if (!(wasm_file_buf = (uint8_t *)read_file_to_buffer + (wasm_files[i], &wasm_file_size))) { + printf("Failed to read file to buffer\n"); + destroy_runtime(); + return -1; + } + + /* Load module */ + if (!(wasm_module = load_module(wasm_file_buf, wasm_file_size, + error_buf, sizeof(error_buf)))) { + printf("%s\n", error_buf); + free(wasm_file_buf); + destroy_runtime(); + return -1; + } + + /* Set wasi arguments */ + if (!set_wasi_args(wasm_module, dir_list, dir_list_size, + env_list, env_list_size, argv, argc)) { + printf("%s\n", "set wasi arguments failed.\n"); + unload_module(wasm_module); + free(wasm_file_buf); + destroy_runtime(); + return -1; + } + + /* Instantiate module */ + if (!(wasm_module_inst[i] = instantiate_module(wasm_module, + stack_size, heap_size, + error_buf, + sizeof(error_buf)))) { + printf("%s\n", error_buf); + unload_module(wasm_module); + free(wasm_file_buf); + destroy_runtime(); + return -1; + } + + app_instance_main(wasm_module_inst[i], argc, argv); + + /* Deinstantiate module */ + deinstantiate_module(wasm_module_inst[i]); + unload_module(wasm_module); + free(wasm_file_buf); + } + + destroy_runtime(); + return 0; +} + +int +wamr_pal_destroy(void) +{ + //sgx_destroy_enclave(g_eid); + return 0; +} + +int +wamr_pal_exec(struct wamr_pal_exec_args *args) +{ + //app_instance_main(wasm_module_inst[i], argc, argv); + return 0; +} + +int +wamr_pal_kill(int pid, int sig) +{ + //deinstantiate_module(wasm_module_inst[i]); + //unload_module(wasm_module); + //free(wasm_file_buf); + return 0; +} + +int pal_get_version(void) __attribute__((weak, alias ("wamr_pal_get_version"))); + +int pal_init(const struct wamr_pal_attr *attr)\ +__attribute__ ((weak, alias ("wamr_pal_init"))); + +int pal_create_process(struct wamr_pal_create_process_args *args)\ +__attribute__ ((weak, alias ("wamr_pal_create_process"))); + +int pal_exec(struct wamr_pal_exec_args *args)\ +__attribute__ ((weak, alias ("wamr_pal_exec"))); + +int pal_kill(int pid, int sig) __attribute__ ((weak, alias ("wamr_pal_kill"))); + +int pal_destroy(void) __attribute__ ((weak, alias ("wamr_pal_destroy"))); diff --git a/product-mini/platforms/linux-sgx/enclave-sample/App/README.md b/product-mini/platforms/linux-sgx/enclave-sample/App/README.md new file mode 100644 index 000000000..49ec39a21 --- /dev/null +++ b/product-mini/platforms/linux-sgx/enclave-sample/App/README.md @@ -0,0 +1,206 @@ +# WAMR as an Enclave Runtime for Rune + +## Build WAMR vmcore (iwasm) for Linux-SGX + +### SIM Mode + +The default SGX mode in WAMR is the SIM mode. Build the source code and enclave example, please refer to [this guild](https://github.com/bytecodealliance/wasm-micro-runtime/blob/main/doc/linux_sgx.md#build-wamr-vmcore-iwasm-for-linux-sgx). + +### HW Mode + +Please do the following changes before execute [this guild](https://github.com/bytecodealliance/wasm-micro-runtime/blob/main/doc/linux_sgx.md#build-wamr-vmcore-iwasm-for-linux-sgx). + +```shell +diff --git a/product-mini/platforms/linux-sgx/enclave-sample/Makefile b/product-mini/platforms/linux-sgx/enclave-sample/Makefile +index f06b5b8..f247f3e 100644 +--- a/product-mini/platforms/linux-sgx/enclave-sample/Makefile ++++ b/product-mini/platforms/linux-sgx/enclave-sample/Makefile +@@ -4,7 +4,7 @@ + ######## SGX SDK Settings ######## + + SGX_SDK ?= /opt/intel/sgxsdk +-SGX_MODE ?= SIM ++SGX_MODE ?= HW + SGX_ARCH ?= x64 + SGX_DEBUG ?= 0 + SPEC_TEST ?= 0 +``` + +```shell +diff --git a/product-mini/platforms/linux-sgx/enclave-sample/Makefile_minimal b/product-mini/platforms/linux-sgx/enclave-sample/Makefile_minimal +index a64d577..747d995 100644 +--- a/product-mini/platforms/linux-sgx/enclave-sample/Makefile_minimal ++++ b/product-mini/platforms/linux-sgx/enclave-sample/Makefile_minimal +@@ -4,7 +4,7 @@ + ######## SGX SDK Settings ######## + + SGX_SDK ?= /opt/intel/sgxsdk +-SGX_MODE ?= SIM ++SGX_MODE ?= HW + SGX_ARCH ?= x64 + SGX_DEBUG ?= 0 + SPEC_TEST ?= 0 + +``` + +```shell +diff --git a/product-mini/platforms/linux-sgx/enclave-sample/App/App.cpp b/product-mini/platforms/linux-sgx/enclave-sample/App/App.cpp +index c321575..3b41c30 100644 +--- a/product-mini/platforms/linux-sgx/enclave-sample/App/App.cpp ++++ b/product-mini/platforms/linux-sgx/enclave-sample/App/App.cpp +@@ -31,6 +31,7 @@ + #define MAX_PATH 1024 + + #define TEST_OCALL_API 0 ++#define SGX_DEBUG_FLAG 1 + +``` + +After building, please sign enclave.so to generate enclave.signed.so which is needed in PAL + +```shell +/opt/intel/sgxsdk/bin/x64/sgx_sign sign -key Enclave/Enclave_private.pem -enclave enclave.so -out enclave.signed.so -config Enclave/Enclave.config.xml +``` + +--- + +## Build PAL dynamically linked shared object + +To build WAMR as an Enclave Runtime for [Inclavare Containers](https://github.com/alibaba/inclavare-containers), we should implement the [PAL interface](https://github.com/alibaba/inclavare-containers/blob/master/rune/libenclave/internal/runtime/pal/spec_v2.md) in WAMR for rune to call the PAL to create the enclave with WAMR and run applications. + +```shell +g++ -shared -fPIC -o libwamr-pal.so App/*.o libvmlib_untrusted.a -L/opt/intel/sgxsdk/lib64 -lsgx_urts -lpthread -lssl -lcrypto +cp ./libwamr-pal.so /usr/lib/libwamr-pal.so +``` + +Note: `/opt/intel/sgxsdk/` is where you installed the SGX SDK + +--- + +## Build WAMR application + +To Build a WAMR application, please refer to [this guide](https://github.com/bytecodealliance/wasm-micro-runtime/blob/main/doc/build_wasm_app.md#build-wasm-applications) + +To run a WAMR application with Intel SGX enclave by `rune`, please compile the `.wasm` file to `.aot` file, refer to [this guide](https://github.com/bytecodealliance/wasm-micro-runtime/blob/main/doc/build_wasm_app.md#compile-wasm-to-aot-module) + +--- + +## Build WAMR container image + +Under the `enclave-sample` directory, to create the WAMR docker images to load the `enclave.signed.so` and target application wasm files, please type the following commands to create a `Dockerfile`: + +For centos: + +```shell +cat >Dockerfile < Dockerfile < 0, then success; otherwise, it is an invalid version. + */ +int wamr_pal_get_version(void); + +/* + * WAMR PAL attributes + */ +typedef struct wamr_pal_attr { + // WAMR instance directory. + // + // The default value is "."; that is, the current working directory + const char *instance_dir; + // Log level. + // + // Specifies the log verbose level (0 to 5, default is 2) + // large level with more log + // + const char *log_level; +} wamr_pal_attr_t; + +#define WAMR_PAL_ATTR_INITVAL { \ + .instance_dir = ".", \ + .log_level = 2 \ +} + +/* + * The struct which consists of file descriptors of standard I/O + */ +typedef struct wamr_stdio_fds { + int stdin_fd; + int stdout_fd; + int stderr_fd; +} wamr_stdio_fds_t; + +/* + * The struct which consists of arguments needed by wamr_pal_create_process + */ +struct wamr_pal_create_process_args { + + // Path to new process. + // + // The path of the command which will be created as a new process. + // + // Mandatory field. Must not be NULL. + const char *path; + + // Argments array pass to new process. + // + // The arguments to the command. By convention, the argv[0] should be the program name. + // And the last element of the array must be NULL to indicate the length of array. + // + // Mandatory field. Must not be NULL. + const char **argv; + + // Untrusted environment variable array pass to new process. + // + // The untrusted env vars to the command. And the last element of the array must be + // NULL to indicate the length of array. + // + // Optional field. + const char **env; + + // File descriptors of the redirected standard I/O (i.e., stdin, stdout, stderr) + // + // If set to NULL, will use the original standard I/O file descriptors. + // + // Optional field. + const struct wamr_stdio_fds *stdio; + + // Output. Pid of new process in libos. + // + // If wamr_pal_create_process returns success, pid of the new process will + // be updated. + // + // Mandatory field. Must not be NULL. + int *pid; +}; + +/* + * The struct which consists of arguments needed by wamr_pal_exec + */ +struct wamr_pal_exec_args { + // Pid of new process created with wamr_pal_create_process. + // + // Mandatory field. + int pid; + + // Output. The exit status of the command. The semantic of + // this value follows the one described in wait(2) man + // page. For example, if the program terminated normally, + // then WEXITSTATUS(exit_status) gives the value returned + // from a main function. + // + // Mandatory field. Must not be NULL. + int *exit_value; +}; + +int wamr_pal_init(const struct wamr_pal_attr *args); + +int wamr_pal_create_process(struct wamr_pal_create_process_args *args); + +int wamr_pal_destroy(void); + +int wamr_pal_exec(struct wamr_pal_exec_args *args); + +int wamr_pal_kill(int pid, int sig); + +int pal_get_version(void); + +int pal_init(const struct wamr_pal_attr *attr); + +int pal_create_process(struct wamr_pal_create_process_args *args); + +int pal_exec(struct wamr_pal_exec_args *args); + +int pal_kill(int pid, int sig); + +int pal_destroy(void); + + +#ifdef __cplusplus +} +#endif + +#endif /* __WAMR_PAL_API_H__ */ + diff --git a/product-mini/platforms/linux-sgx/enclave-sample/App/wamr-bundle.md b/product-mini/platforms/linux-sgx/enclave-sample/App/wamr-bundle.md new file mode 100644 index 000000000..0c64f2ee8 --- /dev/null +++ b/product-mini/platforms/linux-sgx/enclave-sample/App/wamr-bundle.md @@ -0,0 +1,65 @@ +# Run WAMR bundle for Rune + +## Create WAMR Application bundle + +In order to use `rune` you must have your container image in the format of an OCI bundle. If you have Docker installed you can use its `export` method to acquire a root filesystem from an existing WAMR application container image. + +```shell +# create the top most bundle directory +mkdir -p "$HOME/rune_workdir" +cd "$HOME/rune_workdir" +mkdir rune-container +cd rune-container + +# create the rootfs directory +mkdir rootfs + +# export wamr application image via Docker into the rootfs directory +docker export $(docker create ${wamr_application_image}) | sudo tar -C rootfs -xvf - +``` + +After a root filesystem is populated you just generate a spec in the format of a config.json file inside your bundle. `rune` provides a spec command which is similar to `runc` to generate a template file that you are then able to edit. + +```shell +rune spec +``` + +To find features and documentation for fields in the spec please refer to the [specs](https://github.com/opencontainers/runtime-spec) repository. + +In order to run the target applications in WAMR with `rune`, you need to change the entrypoint from `sh` to `/run/rune/${wasm_app1.wasm}`, and in order to run multi-applications in one runtime with enclave, change it to `/run/rune/${wasm_app1.aot}`, `/run/rune/${wasm_app2.aot}` ... + +```yaml + "process": { + "args": [ + "/run/rune/demo.aot" + ], + } +``` + +and then configure enclave runtime as following: + +```yaml + "annotations": { + "enclave.type": "intelSgx", + "enclave.runtime.path": "/usr/lib/libwamr-pal.so", + "enclave.runtime.args": "./" + } +``` + +where: + +- @enclave.type: specify the type of enclave hardware to use, such as `intelSgx`. +- @enclave.runtime.path: specify the path to enclave runtime to launch. For an WAMR application, you need to specify the path to `libwamr-pal.so`. +- @enclave.runtime.args: specify the specific arguments to enclave runtime, separated by the comma. + +--- + +## Run WAMR Application + +Assuming you have an OCI bundle from the previous step you can execute the container in this way. + +```shell +cd "$HOME/rune_workdir/rune-container" +sudo rune run ${wamr_application_container_name} +``` + From 667282eea94066e5ed361b1e5a8e18e76aad0a91 Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Fri, 30 Oct 2020 12:36:00 +0800 Subject: [PATCH 105/207] Implement stat and getentropy for sgx with ocall to run tensorflow (#436) --- core/shared/platform/linux-sgx/sgx_file.c | 39 ++++++++++++++++++- core/shared/platform/linux-sgx/sgx_file.h | 2 + core/shared/platform/linux-sgx/sgx_wamr.edl | 4 ++ .../platform/linux-sgx/untrusted/file.c | 11 ++++++ 4 files changed, 54 insertions(+), 2 deletions(-) diff --git a/core/shared/platform/linux-sgx/sgx_file.c b/core/shared/platform/linux-sgx/sgx_file.c index 1b34ea504..4e21b8b42 100644 --- a/core/shared/platform/linux-sgx/sgx_file.c +++ b/core/shared/platform/linux-sgx/sgx_file.c @@ -49,9 +49,11 @@ int ocall_closedir(int *p_ret, void *dirp); /** DIR end **/ /** stat **/ +int ocall_stat(int *p_ret, const char *pathname, + void *buf, unsigned int buf_len); int ocall_fstat(int *p_ret, int fd, void *buf, unsigned int buf_len); -int ocall_fstatat(int *p_ret, int dirfd, const char *pathname, void *buf, - unsigned int buf_len, int flags); +int ocall_fstatat(int *p_ret, int dirfd, const char *pathname, + void *buf, unsigned int buf_len, int flags); /** stat end **/ /** link **/ @@ -87,6 +89,7 @@ int ocall_getopt(int *p_ret, int argc, char *argv_buf, unsigned int argv_buf_len, const char *optstring); int ocall_getrandom(ssize_t *p_ret, void *buf, size_t buflen, unsigned int flags); +int ocall_getentropy(int *p_ret, void *buffer, size_t length); int ocall_sched_yield(int *p_ret); /** struct iovec **/ @@ -449,6 +452,25 @@ int ftruncate(int fd, off_t length) return ret; } +int stat(const char *pathname, struct stat *statbuf) +{ + int ret; + + if (statbuf == NULL) + return -1; + + if (ocall_stat(&ret, pathname, + (void *)statbuf, + sizeof(struct stat)) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + + if (ret == -1) + errno = get_errno(); + return ret; +} + int fstat(int fd, struct stat *statbuf) { int ret; @@ -822,6 +844,19 @@ ssize_t getrandom(void *buf, size_t buflen, unsigned int flags) return ret; } +int getentropy(void *buffer, size_t length) +{ + int ret; + + if (ocall_getentropy(&ret, buffer, length) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + if (ret == -1) + errno = get_errno(); + return ret; +} + int get_errno(void) { int ret; diff --git a/core/shared/platform/linux-sgx/sgx_file.h b/core/shared/platform/linux-sgx/sgx_file.h index 7d046766c..178e6e7f4 100644 --- a/core/shared/platform/linux-sgx/sgx_file.h +++ b/core/shared/platform/linux-sgx/sgx_file.h @@ -183,6 +183,7 @@ ssize_t pwritev(int fd, const struct iovec *iov, int iovcnt, off_t lseek(int fd, off_t offset, int whence); int ftruncate(int fd, off_t length); +int stat(const char *pathname, struct stat *statbuf); int fstat(int fd, struct stat *statbuf); int fstatat(int dirfd, const char *pathname, struct stat *statbuf, int flags); @@ -218,6 +219,7 @@ int getopt(int argc, char * const argv[], int sched_yield(void); ssize_t getrandom(void *buf, size_t buflen, unsigned int flags); +int getentropy(void *buffer, size_t length); int get_errno(void); diff --git a/core/shared/platform/linux-sgx/sgx_wamr.edl b/core/shared/platform/linux-sgx/sgx_wamr.edl index 6eb17172c..b8985396f 100644 --- a/core/shared/platform/linux-sgx/sgx_wamr.edl +++ b/core/shared/platform/linux-sgx/sgx_wamr.edl @@ -30,6 +30,9 @@ enclave { long ocall_telldir([user_check]void *dirp); int ocall_closedir([user_check]void *dirp); + int ocall_stat([in, string]const char *pathname, + [out, size=buf_len]void *buf, + unsigned int buf_len); int ocall_fstat(int fd, [out, size=buf_len]void *buf, unsigned int buf_len); int ocall_fstatat(int dirfd, [in, string]const char *pathname, @@ -76,6 +79,7 @@ enclave { [in, string]const char *optstring); ssize_t ocall_getrandom([out, size=buflen]void *buf, size_t buflen, unsigned int flags); + int ocall_getentropy([out, size=length]void *buffer, size_t length); ssize_t ocall_readv(int fd, [in, out, size=buf_size]char *iov_buf, unsigned int buf_size, int iovcnt, diff --git a/core/shared/platform/linux-sgx/untrusted/file.c b/core/shared/platform/linux-sgx/untrusted/file.c index d19c8eda7..6852f222f 100644 --- a/core/shared/platform/linux-sgx/untrusted/file.c +++ b/core/shared/platform/linux-sgx/untrusted/file.c @@ -130,6 +130,12 @@ int ocall_closedir(void* dirp) return -1; } +int ocall_stat(const char *pathname, + void *buf, unsigned int buf_len) +{ + return stat(pathname, (struct stat *)buf); +} + int ocall_fstat(int fd, void *buf, unsigned int buf_len) { return fstat(fd, (struct stat *)buf); @@ -277,6 +283,11 @@ ssize_t ocall_getrandom(void *buf, size_t buflen, unsigned int flags) return getrandom(buf, buflen, flags); } +int ocall_getentropy(void *buffer, size_t length) +{ + return getentropy(buffer, length); +} + int ocall_sched_yield() { return sched_yield(); From a3074df21ba614845226a49a5ebe01b3819db4e9 Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Thu, 5 Nov 2020 18:15:15 +0800 Subject: [PATCH 106/207] Import SIMD feature and add some workload samples (#438) --- README.md | 1 + build-scripts/config_common.cmake | 4 + core/config.h | 5 + core/deps/download.sh | 2 +- core/iwasm/aot/aot_loader.c | 22 +- core/iwasm/aot/aot_runtime.c | 6 + core/iwasm/aot/aot_runtime.h | 1 + .../common/arch/invokeNative_em64_simd.s | 64 ++ core/iwasm/common/iwasm_common.cmake | 14 +- core/iwasm/common/wasm_runtime_common.c | 161 +++- core/iwasm/common/wasm_runtime_common.h | 3 + core/iwasm/compilation/aot.c | 9 + core/iwasm/compilation/aot.h | 14 + core/iwasm/compilation/aot_compiler.c | 741 +++++++++++++++++- core/iwasm/compilation/aot_compiler.h | 55 ++ core/iwasm/compilation/aot_emit_aot_file.c | 45 +- core/iwasm/compilation/aot_emit_control.c | 36 +- core/iwasm/compilation/aot_emit_exception.c | 26 +- core/iwasm/compilation/aot_emit_function.c | 20 +- core/iwasm/compilation/aot_emit_memory.c | 73 +- core/iwasm/compilation/aot_emit_memory.h | 4 + core/iwasm/compilation/aot_emit_numberic.c | 179 +---- core/iwasm/compilation/aot_emit_parametric.c | 3 +- core/iwasm/compilation/aot_emit_variable.c | 12 +- core/iwasm/compilation/aot_llvm.c | 242 +++++- core/iwasm/compilation/aot_llvm.h | 44 ++ .../compilation/simd/simd_access_lanes.c | 381 +++++++++ .../compilation/simd/simd_access_lanes.h | 89 +++ core/iwasm/compilation/simd/simd_bit_shifts.c | 164 ++++ core/iwasm/compilation/simd/simd_bit_shifts.h | 39 + .../compilation/simd/simd_bitmask_extracts.c | 109 +++ .../compilation/simd/simd_bitmask_extracts.h | 29 + .../iwasm/compilation/simd/simd_bitwise_ops.c | 146 ++++ .../iwasm/compilation/simd/simd_bitwise_ops.h | 24 + .../compilation/simd/simd_bool_reductions.c | 183 +++++ .../compilation/simd/simd_bool_reductions.h | 43 + core/iwasm/compilation/simd/simd_common.c | 47 ++ core/iwasm/compilation/simd/simd_common.h | 23 + .../iwasm/compilation/simd/simd_comparisons.c | 231 ++++++ .../iwasm/compilation/simd/simd_comparisons.h | 44 ++ .../compilation/simd/simd_construct_values.c | 190 +++++ .../compilation/simd/simd_construct_values.h | 29 + .../iwasm/compilation/simd/simd_conversions.c | 422 ++++++++++ .../iwasm/compilation/simd/simd_conversions.h | 51 ++ .../compilation/simd/simd_floating_point.c | 273 +++++++ .../compilation/simd/simd_floating_point.h | 49 ++ core/iwasm/compilation/simd/simd_int_arith.c | 207 +++++ core/iwasm/compilation/simd/simd_int_arith.h | 51 ++ core/iwasm/compilation/simd/simd_load_store.c | 301 +++++++ core/iwasm/compilation/simd/simd_load_store.h | 45 ++ .../compilation/simd/simd_sat_int_arith.c | 367 +++++++++ .../compilation/simd/simd_sat_int_arith.h | 66 ++ core/iwasm/include/aot_export.h | 1 + core/iwasm/interpreter/wasm.h | 21 + core/iwasm/interpreter/wasm_loader.c | 686 +++++++++++++++- core/iwasm/interpreter/wasm_opcode.h | 215 +++++ .../libraries/libc-emcc/libc_emcc_wrapper.c | 192 +++++ doc/build_wamr.md | 4 + product-mini/platforms/linux/CMakeLists.txt | 5 + samples/basic/build.sh | 5 + samples/gui/build.sh | 5 + samples/littlevgl/build.sh | 5 + samples/simple/build.sh | 5 + samples/workload/README.md | 34 + samples/workload/bwa/.gitignore | 4 + samples/workload/bwa/CMakeLists.bwa_wasm.txt | 134 ++++ samples/workload/bwa/CMakeLists.txt | 91 +++ samples/workload/bwa/README.md | 47 ++ samples/workload/cmake/toolchain.cmake | 100 +++ samples/workload/docker/.gitignore | 1 + samples/workload/docker/Dockerfile | 77 ++ samples/workload/docker/build.sh | 48 ++ samples/workload/docker/run.sh | 10 + samples/workload/meshoptimizer/.gitignore | 2 + samples/workload/meshoptimizer/CMakeLists.txt | 39 + samples/workload/meshoptimizer/README.md | 59 ++ .../workload/meshoptimizer/codecbench.patch | 47 ++ samples/workload/tensorflow/build.sh | 32 +- samples/workload/tensorflow/tf_lite.patch | 12 +- samples/workload/wasm-av1/README.md | 22 + samples/workload/wasm-av1/build.sh | 100 +++ samples/workload/wasm-av1/wasm-av1.patch | 696 ++++++++++++++++ wamr-compiler/CMakeLists.txt | 1 + wamr-compiler/main.c | 9 +- 84 files changed, 7780 insertions(+), 318 deletions(-) create mode 100644 core/iwasm/common/arch/invokeNative_em64_simd.s create mode 100644 core/iwasm/compilation/simd/simd_access_lanes.c create mode 100644 core/iwasm/compilation/simd/simd_access_lanes.h create mode 100644 core/iwasm/compilation/simd/simd_bit_shifts.c create mode 100644 core/iwasm/compilation/simd/simd_bit_shifts.h create mode 100644 core/iwasm/compilation/simd/simd_bitmask_extracts.c create mode 100644 core/iwasm/compilation/simd/simd_bitmask_extracts.h create mode 100644 core/iwasm/compilation/simd/simd_bitwise_ops.c create mode 100644 core/iwasm/compilation/simd/simd_bitwise_ops.h create mode 100644 core/iwasm/compilation/simd/simd_bool_reductions.c create mode 100644 core/iwasm/compilation/simd/simd_bool_reductions.h create mode 100644 core/iwasm/compilation/simd/simd_common.c create mode 100644 core/iwasm/compilation/simd/simd_common.h create mode 100644 core/iwasm/compilation/simd/simd_comparisons.c create mode 100644 core/iwasm/compilation/simd/simd_comparisons.h create mode 100644 core/iwasm/compilation/simd/simd_construct_values.c create mode 100644 core/iwasm/compilation/simd/simd_construct_values.h create mode 100644 core/iwasm/compilation/simd/simd_conversions.c create mode 100644 core/iwasm/compilation/simd/simd_conversions.h create mode 100644 core/iwasm/compilation/simd/simd_floating_point.c create mode 100644 core/iwasm/compilation/simd/simd_floating_point.h create mode 100644 core/iwasm/compilation/simd/simd_int_arith.c create mode 100644 core/iwasm/compilation/simd/simd_int_arith.h create mode 100644 core/iwasm/compilation/simd/simd_load_store.c create mode 100644 core/iwasm/compilation/simd/simd_load_store.h create mode 100644 core/iwasm/compilation/simd/simd_sat_int_arith.c create mode 100644 core/iwasm/compilation/simd/simd_sat_int_arith.h create mode 100644 samples/workload/README.md create mode 100644 samples/workload/bwa/.gitignore create mode 100644 samples/workload/bwa/CMakeLists.bwa_wasm.txt create mode 100644 samples/workload/bwa/CMakeLists.txt create mode 100644 samples/workload/bwa/README.md create mode 100644 samples/workload/cmake/toolchain.cmake create mode 100644 samples/workload/docker/.gitignore create mode 100644 samples/workload/docker/Dockerfile create mode 100755 samples/workload/docker/build.sh create mode 100755 samples/workload/docker/run.sh create mode 100644 samples/workload/meshoptimizer/.gitignore create mode 100644 samples/workload/meshoptimizer/CMakeLists.txt create mode 100644 samples/workload/meshoptimizer/README.md create mode 100644 samples/workload/meshoptimizer/codecbench.patch create mode 100644 samples/workload/wasm-av1/README.md create mode 100755 samples/workload/wasm-av1/build.sh create mode 100644 samples/workload/wasm-av1/wasm-av1.patch diff --git a/README.md b/README.md index aa892f874..b34f81540 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,7 @@ iwasm VM core - [Multi-value](https://github.com/WebAssembly/multi-value) - [wasm-c-api](https://github.com/WebAssembly/wasm-c-api) - [Tail-call](https://github.com/WebAssembly/tail-call) +- [128-bit SIMD](https://github.com/WebAssembly/simd) ### Supported architectures and platforms diff --git a/build-scripts/config_common.cmake b/build-scripts/config_common.cmake index 9f3d5bb68..822be12af 100644 --- a/build-scripts/config_common.cmake +++ b/build-scripts/config_common.cmake @@ -165,6 +165,10 @@ if (WAMR_DISABLE_HW_BOUND_CHECK EQUAL 1) add_definitions (-DWASM_DISABLE_HW_BOUND_CHECK=1) message (" Hardware boundary check disabled") endif () +if (WAMR_BUILD_SIMD EQUAL 1) + add_definitions (-DWASM_ENABLE_SIMD=1) + message (" SIMD enabled") +endif () if (WAMR_BUILD_MEMORY_PROFILING EQUAL 1) add_definitions (-DWASM_ENABLE_MEMORY_PROFILING=1) message (" Memory profiling enabled") diff --git a/core/config.h b/core/config.h index 1b474b0bb..7ab1d2fec 100644 --- a/core/config.h +++ b/core/config.h @@ -165,6 +165,11 @@ #define WASM_DISABLE_HW_BOUND_CHECK 0 #endif +/* Disable SIMD unless it is manualy enabled somewhere */ +#ifndef WASM_ENABLE_SIMD +#define WASM_ENABLE_SIMD 0 +#endif + /* Memory profiling */ #ifndef WASM_ENABLE_MEMORY_PROFILING #define WASM_ENABLE_MEMORY_PROFILING 0 diff --git a/core/deps/download.sh b/core/deps/download.sh index 923a9e03d..c7e40de84 100755 --- a/core/deps/download.sh +++ b/core/deps/download.sh @@ -13,7 +13,7 @@ if [ ! -d "lvgl" ]; then fi if [ ! -d "lv_drivers" ]; then echo "git pull lv_drivers..." - git clone https://github.com/littlevgl/lv_drivers.git + git clone https://github.com/littlevgl/lv_drivers.git --branch v6.0.1 [ $? -eq 0 ] || exit $? fi diff --git a/core/iwasm/aot/aot_loader.c b/core/iwasm/aot/aot_loader.c index 5f8ed0ebd..478570764 100644 --- a/core/iwasm/aot/aot_loader.c +++ b/core/iwasm/aot/aot_loader.c @@ -66,6 +66,11 @@ exchange_uint32(uint8 *p_data) static void exchange_uint64(uint8 *pData) { + uint32 value; + + value = *(uint32 *)pData; + *(uint32 *)pData = *(uint32 *)(pData + 4); + *(uint32 *)(pData + 4) = value; exchange_uint32(pData); exchange_uint32(pData + 4); } @@ -801,14 +806,22 @@ load_globals(const uint8 **p_buf, const uint8 *buf_end, /* Create each global */ for (i = 0; i < module->global_count; i++) { uint16 init_expr_type; - uint64 init_expr_value; read_uint8(buf, buf_end, globals[i].type); read_uint8(buf, buf_end, globals[i].is_mutable); read_uint16(buf, buf_end, init_expr_type); - read_uint64(buf, buf_end, init_expr_value); + + if (init_expr_type != INIT_EXPR_TYPE_V128_CONST) { + read_uint64(buf, buf_end, globals[i].init_expr.u.i64); + } + else { + uint64 *i64x2 = (uint64 *)globals[i].init_expr.u.v128.i64x2; + CHECK_BUF(buf, buf_end, sizeof(uint64) * 2); + wasm_runtime_read_v128(buf, &i64x2[0], &i64x2[1]); + buf += sizeof(uint64) * 2; + } + globals[i].init_expr.init_expr_type = (uint8)init_expr_type; - globals[i].init_expr.u.i64 = (int64)init_expr_value; globals[i].size = wasm_value_type_size(globals[i].type); globals[i].data_offset = data_offset; @@ -2101,6 +2114,9 @@ aot_convert_wasm_module(WASMModule *wasm_module, #endif #if WASM_ENABLE_TAIL_CALL != 0 option.enable_tail_call = true; +#endif +#if WASM_ENABLE_SIMD != 0 + option.enable_simd = true; #endif comp_ctx = aot_create_comp_context(comp_data, &option); if (!comp_ctx) { diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index 6507281c0..f31d36dfd 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -385,12 +385,14 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModule *module, memory_inst->mem_bound_check_2bytes.u64 = total_size - 2; memory_inst->mem_bound_check_4bytes.u64 = total_size - 4; memory_inst->mem_bound_check_8bytes.u64 = total_size - 8; + memory_inst->mem_bound_check_16bytes.u64 = total_size - 16; } else { memory_inst->mem_bound_check_1byte.u32[0] = (uint32)total_size - 1; memory_inst->mem_bound_check_2bytes.u32[0] = (uint32)total_size - 2; memory_inst->mem_bound_check_4bytes.u32[0] = (uint32)total_size - 4; memory_inst->mem_bound_check_8bytes.u32[0] = (uint32)total_size - 8; + memory_inst->mem_bound_check_16bytes.u32[0] = (uint32)total_size - 16; } } @@ -1545,12 +1547,14 @@ aot_enlarge_memory(AOTModuleInstance *module_inst, uint32 inc_page_count) memory_inst->mem_bound_check_2bytes.u64 = total_size - 2; memory_inst->mem_bound_check_4bytes.u64 = total_size - 4; memory_inst->mem_bound_check_8bytes.u64 = total_size - 8; + memory_inst->mem_bound_check_16bytes.u64 = total_size - 16; } else { memory_inst->mem_bound_check_1byte.u32[0] = (uint32)total_size - 1; memory_inst->mem_bound_check_2bytes.u32[0] = (uint32)total_size - 2; memory_inst->mem_bound_check_4bytes.u32[0] = (uint32)total_size - 4; memory_inst->mem_bound_check_8bytes.u32[0] = (uint32)total_size - 8; + memory_inst->mem_bound_check_16bytes.u32[0] = (uint32)total_size - 16; } return true; } @@ -1593,12 +1597,14 @@ aot_enlarge_memory(AOTModuleInstance *module_inst, uint32 inc_page_count) memory_inst->mem_bound_check_2bytes.u64 = total_size - 2; memory_inst->mem_bound_check_4bytes.u64 = total_size - 4; memory_inst->mem_bound_check_8bytes.u64 = total_size - 8; + memory_inst->mem_bound_check_16bytes.u64 = total_size - 16; } else { memory_inst->mem_bound_check_1byte.u32[0] = (uint32)total_size - 1; memory_inst->mem_bound_check_2bytes.u32[0] = (uint32)total_size - 2; memory_inst->mem_bound_check_4bytes.u32[0] = (uint32)total_size - 4; memory_inst->mem_bound_check_8bytes.u32[0] = (uint32)total_size - 8; + memory_inst->mem_bound_check_16bytes.u32[0] = (uint32)total_size - 16; } return true; } diff --git a/core/iwasm/aot/aot_runtime.h b/core/iwasm/aot/aot_runtime.h index ee1d36ba0..93a0cf5d8 100644 --- a/core/iwasm/aot/aot_runtime.h +++ b/core/iwasm/aot/aot_runtime.h @@ -234,6 +234,7 @@ typedef struct AOTMemoryInstance { MemBound mem_bound_check_2bytes; MemBound mem_bound_check_4bytes; MemBound mem_bound_check_8bytes; + MemBound mem_bound_check_16bytes; } AOTMemoryInstance; typedef struct AOTModuleInstance { diff --git a/core/iwasm/common/arch/invokeNative_em64_simd.s b/core/iwasm/common/arch/invokeNative_em64_simd.s new file mode 100644 index 000000000..eb9a58bc0 --- /dev/null +++ b/core/iwasm/common/arch/invokeNative_em64_simd.s @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + .text + .align 2 +#ifndef BH_PLATFORM_DARWIN +.globl invokeNative + .type invokeNative, @function +invokeNative: +#else +.globl _invokeNative +_invokeNative: +#endif /* end of BH_PLATFORM_DARWIN */ + /* rdi - function ptr */ + /* rsi - argv */ + /* rdx - n_stacks */ + + push %rbp + mov %rsp, %rbp + + mov %rdx, %r10 + mov %rsp, %r11 /* Check that stack is aligned on */ + and $8, %r11 /* 16 bytes. This code may be removed */ + je check_stack_succ /* when we are sure that compiler always */ + int3 /* calls us with aligned stack */ +check_stack_succ: + mov %r10, %r11 /* Align stack on 16 bytes before pushing */ + and $1, %r11 /* stack arguments in case we have an odd */ + shl $3, %r11 /* number of stack arguments */ + sub %r11, %rsp + /* store memory args */ + movq %rdi, %r11 /* func ptr */ + movq %r10, %rcx /* counter */ + lea 128+48-8(%rsi,%rcx,8), %r10 + sub %rsp, %r10 + cmpq $0, %rcx + je push_args_end +push_args: + push 0(%rsp,%r10) + loop push_args +push_args_end: + /* fill all fp args */ + movdqa 0x00(%rsi), %xmm0 + movdqa 0x10(%rsi), %xmm1 + movdqa 0x20(%rsi), %xmm2 + movdqa 0x30(%rsi), %xmm3 + movdqa 0x40(%rsi), %xmm4 + movdqa 0x50(%rsi), %xmm5 + movdqa 0x60(%rsi), %xmm6 + movdqa 0x70(%rsi), %xmm7 + + /* fill all int args */ + movq 0x80(%rsi), %rdi + movq 0x90(%rsi), %rdx + movq 0x98(%rsi), %rcx + movq 0xa0(%rsi), %r8 + movq 0xa8(%rsi), %r9 + movq 0x88(%rsi), %rsi + + call *%r11 + leave + ret + diff --git a/core/iwasm/common/iwasm_common.cmake b/core/iwasm/common/iwasm_common.cmake index 458b00a3f..ba0c0d0b4 100644 --- a/core/iwasm/common/iwasm_common.cmake +++ b/core/iwasm/common/iwasm_common.cmake @@ -11,10 +11,18 @@ add_definitions(-DBH_FREE=wasm_runtime_free) file (GLOB c_source_all ${IWASM_COMMON_DIR}/*.c) if (WAMR_BUILD_TARGET STREQUAL "X86_64" OR WAMR_BUILD_TARGET STREQUAL "AMD_64") - if (WAMR_BUILD_PLATFORM STREQUAL "windows") - set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_em64.asm) + if (NOT WAMR_BUILD_SIMD EQUAL 1) + if (WAMR_BUILD_PLATFORM STREQUAL "windows") + set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_em64.asm) + else () + set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_em64.s) + endif () else () - set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_em64.s) + if (WAMR_BUILD_PLATFORM STREQUAL "windows") + message(FATAL_ERROR "need an implementation of SIMD on windows") + else() + set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_em64_simd.s) + endif() endif () elseif (WAMR_BUILD_TARGET STREQUAL "X86_32") if (WAMR_BUILD_PLATFORM STREQUAL "windows") diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index 5e1983fde..bcc68a10b 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -2457,6 +2457,23 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, argv1[p++] = u.parts[1]; break; } +#if WASM_ENABLE_SIMD != 0 + case VALUE_TYPE_V128: + { + /* it likes 0x123\0x234 or 123\234 */ + /* retrive first i64 */ + *(uint64*)(argv1 + p) = strtoull(argv[i], &endptr, 0); + /* skip \ */ + endptr++; + /* retrive second i64 */ + *(uint64*)(argv1 + p + 2) = strtoull(endptr, &endptr, 0); + p += 4; + break; + } +#endif /* WASM_ENABLE_SIMD != 0 */ + default: + bh_assert(0); + break; } if (endptr && *endptr != '\0' && *endptr != '_') { snprintf(buf, sizeof(buf), "invalid input argument %d: %s", @@ -2477,9 +2494,11 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, for (j = 0; j < type->result_count; j++) { switch (type->types[type->param_count + j]) { case VALUE_TYPE_I32: + { os_printf("0x%x:i32", argv1[k]); k++; break; + } case VALUE_TYPE_I64: { union { uint64 val; uint32 parts[2]; } u; @@ -2511,6 +2530,27 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, os_printf("%.7g:f64", u.val); break; } +#if WASM_ENABLE_SIMD != 0 + case VALUE_TYPE_V128: + { + uint64 *v = (uint64*)(argv1 + k); +#if defined(PRIx64) + os_printf("<0x%016"PRIx64" 0x%016"PRIx64">:v128", *v, *(v + 1)); +#else + if (4 == sizeof(long)) { + os_printf("<0x%016llx 0x%016llx>:v128", *v, *(v + 1)); + } + else { + os_printf("<0x%016lx 0x%016lx>:v128", *v, *(v + 1)); + } +#endif /* PRIx64 */ + k += 4; + break; + } +#endif /* WASM_ENABLE_SIMD != 0 */ + default: + bh_assert(0); + break; } if (j < (uint32)(type->result_count - 1)) os_printf(","); @@ -3067,12 +3107,31 @@ fail: #if defined(BUILD_TARGET_X86_64) \ || defined(BUILD_TARGET_AMD_64) \ || defined(BUILD_TARGET_AARCH64) + +#if WASM_ENABLE_SIMD != 0 +#ifdef v128 +#undef v128 +#endif + +#if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64) +#include +/* unaligned */ +#define v128 __m128i_u +#else +#warning "Include header files for v128 to support SIMD feature" +#endif + +#ifndef v128 +#error "v128 type isn't defined" +#endif +#endif /* end of WASM_ENABLE_SIMD != 0 */ + typedef void (*GenericFunctionPointer)(); int64 invokeNative(GenericFunctionPointer f, uint64 *args, uint64 n_stacks); typedef float64 (*Float64FuncPtr)(GenericFunctionPointer, uint64*, uint64); typedef float32 (*Float32FuncPtr)(GenericFunctionPointer, uint64*, uint64); -typedef int64 (*Int64FuncPtr)(GenericFunctionPointer, uint64*,uint64); +typedef int64 (*Int64FuncPtr)(GenericFunctionPointer, uint64*, uint64); typedef int32 (*Int32FuncPtr)(GenericFunctionPointer, uint64*, uint64); typedef void (*VoidFuncPtr)(GenericFunctionPointer, uint64*, uint64); @@ -3082,10 +3141,15 @@ static Int64FuncPtr invokeNative_Int64 = (Int64FuncPtr)(uintptr_t)invokeNative; static Int32FuncPtr invokeNative_Int32 = (Int32FuncPtr)(uintptr_t)invokeNative; static VoidFuncPtr invokeNative_Void = (VoidFuncPtr)(uintptr_t)invokeNative; +#if WASM_ENABLE_SIMD != 0 +typedef v128 (*V128FuncPtr)(GenericFunctionPointer, uint64*, uint64); +static V128FuncPtr invokeNative_V128 = (V128FuncPtr)(uintptr_t)invokeNative; +#endif + #if defined(_WIN32) || defined(_WIN32_) #define MAX_REG_FLOATS 4 #define MAX_REG_INTS 4 -#else +#else /* else of defined(_WIN32) || defined(_WIN32_) */ #define MAX_REG_FLOATS 8 #if defined(BUILD_TARGET_AARCH64) #define MAX_REG_INTS 8 @@ -3101,12 +3165,17 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, uint32 *argv, uint32 argc, uint32 *argv_ret) { WASMModuleInstanceCommon *module = wasm_runtime_get_module_inst(exec_env); - uint64 argv_buf[32], *argv1 = argv_buf, *fps, *ints, *stacks, size, arg_i64; + uint64 argv_buf[32], *argv1 = argv_buf, *ints, *stacks, size, arg_i64; uint32 *argv_src = argv, i, argc1, n_ints = 0, n_stacks = 0; uint32 arg_i32, ptr_len; uint32 result_count = func_type->result_count; uint32 ext_ret_count = result_count > 1 ? result_count - 1 : 0; bool ret = false; +#if WASM_ENABLE_SIMD == 0 + uint64 *fps; +#else + v128 *fps; +#endif #if defined(_WIN32) || defined(_WIN32_) /* important difference in calling conventions */ @@ -3115,7 +3184,13 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, int n_fps = 0; #endif - argc1 = 1 + MAX_REG_FLOATS + (uint32)func_type->param_count + ext_ret_count; +#if WASM_ENABLE_SIMD == 0 + argc1 = 1 + MAX_REG_FLOATS + (uint32)func_type->param_count + + ext_ret_count; +#else + argc1 = 1 + MAX_REG_FLOATS * 2 + (uint32)func_type->param_count * 2 + + ext_ret_count; +#endif if (argc1 > sizeof(argv_buf) / sizeof(uint64)) { size = sizeof(uint64) * (uint64)argc1; if (!(argv1 = runtime_malloc((uint32)size, exec_env->module_inst, @@ -3124,8 +3199,13 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, } } +#if WASM_ENABLE_SIMD == 0 fps = argv1; ints = fps + MAX_REG_FLOATS; +#else + fps = (v128 *)argv1; + ints = (uint64 *)(fps + MAX_REG_FLOATS); +#endif stacks = ints + MAX_REG_INTS; ints[n_ints++] = (uint64)(uintptr_t)exec_env; @@ -3175,18 +3255,34 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, argv_src += 2; break; case VALUE_TYPE_F32: - if (n_fps < MAX_REG_FLOATS) + if (n_fps < MAX_REG_FLOATS) { *(float32*)&fps[n_fps++] = *(float32*)argv_src++; - else + } + else { *(float32*)&stacks[n_stacks++] = *(float32*)argv_src++; + } break; case VALUE_TYPE_F64: - if (n_fps < MAX_REG_FLOATS) + if (n_fps < MAX_REG_FLOATS) { *(float64*)&fps[n_fps++] = *(float64*)argv_src; - else + } + else { *(float64*)&stacks[n_stacks++] = *(float64*)argv_src; + } argv_src += 2; break; +#if WASM_ENABLE_SIMD != 0 + case VALUE_TYPE_V128: + if (n_fps < MAX_REG_FLOATS) { + *(v128*)&fps[n_fps++] = *(v128*)argv_src; + } + else { + *(v128*)&stacks[n_stacks++] = *(v128*)argv_src; + n_stacks++; + } + argv_src += 4; + break; +#endif default: bh_assert(0); break; @@ -3221,6 +3317,11 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, case VALUE_TYPE_F64: PUT_F64_TO_ADDR(argv_ret, invokeNative_Float64(func_ptr, argv1, n_stacks)); break; +#if WASM_ENABLE_SIMD != 0 + case VALUE_TYPE_V128: + *(v128*)argv_ret = invokeNative_V128(func_ptr, argv1, n_stacks); + break; +#endif default: bh_assert(0); break; @@ -3268,6 +3369,50 @@ wasm_runtime_call_indirect(WASMExecEnv *exec_env, return false; } +static void +exchange_uint32(uint8 *p_data) +{ + uint8 value = *p_data; + *p_data = *(p_data + 3); + *(p_data + 3) = value; + + value = *(p_data + 1); + *(p_data + 1) = *(p_data + 2); + *(p_data + 2) = value; +} + +static void +exchange_uint64(uint8 *p_data) +{ + uint32 value; + + value = *(uint32 *)p_data; + *(uint32 *)p_data = *(uint32 *)(p_data + 4); + *(uint32 *)(p_data + 4) = value; + exchange_uint32(p_data); + exchange_uint32(p_data + 4); +} + +void +wasm_runtime_read_v128(const uint8 *bytes, uint64 *ret1, uint64 *ret2) +{ + uint64 u1, u2; + + bh_memcpy_s(&u1, 8, bytes, 8); + bh_memcpy_s(&u2, 8, bytes + 8, 8); + + if (!is_little_endian()) { + exchange_uint64((uint8*)&u1); + exchange_uint64((uint8*)&u2); + *ret1 = u2; + *ret2 = u1; + } + else { + *ret1 = u1; + *ret2 = u2; + } +} + #if WASM_ENABLE_THREAD_MGR != 0 typedef struct WASMThreadArg { WASMExecEnv *new_exec_env; diff --git a/core/iwasm/common/wasm_runtime_common.h b/core/iwasm/common/wasm_runtime_common.h index 111bfec2c..86907d469 100644 --- a/core/iwasm/common/wasm_runtime_common.h +++ b/core/iwasm/common/wasm_runtime_common.h @@ -464,6 +464,9 @@ wasm_runtime_invoke_native_raw(WASMExecEnv *exec_env, void *func_ptr, void *attachment, uint32 *argv, uint32 argc, uint32 *ret); +void +wasm_runtime_read_v128(const uint8 *bytes, uint64 *ret1, uint64 *ret2); + void wasm_runtime_dump_module_mem_consumption(const WASMModuleCommon *module); diff --git a/core/iwasm/compilation/aot.c b/core/iwasm/compilation/aot.c index 04a97e2f6..5e85cc1fa 100644 --- a/core/iwasm/compilation/aot.c +++ b/core/iwasm/compilation/aot.c @@ -14,6 +14,15 @@ aot_get_last_error() return aot_error[0] == '\0' ? "" : aot_error; } +void +aot_set_last_error_v(const char *format, ...) +{ + va_list args; + va_start(args, format); + vsnprintf(aot_error, sizeof(aot_error), format, args); + va_end(args); +} + void aot_set_last_error(const char *error) { diff --git a/core/iwasm/compilation/aot.h b/core/iwasm/compilation/aot.h index ccceb75f9..a898ad04c 100644 --- a/core/iwasm/compilation/aot.h +++ b/core/iwasm/compilation/aot.h @@ -230,6 +230,20 @@ aot_get_last_error(); void aot_set_last_error(const char *error); +void +aot_set_last_error_v(const char *format, ...); + +#if BH_DEBUG == 1 +#define HANDLE_FAILURE(callee) do { \ + aot_set_last_error_v("call %s failed in %s:%d", (callee),\ + __FUNCTION__, __LINE__); \ + } while (0) +#else +#define HANDLE_FAILURE(callee) do { \ + aot_set_last_error_v("call %s failed", (callee)); \ + } while (0) +#endif + #ifdef __cplusplus } /* end of extern "C" */ #endif diff --git a/core/iwasm/compilation/aot_compiler.c b/core/iwasm/compilation/aot_compiler.c index d4aa718dc..403515995 100644 --- a/core/iwasm/compilation/aot_compiler.c +++ b/core/iwasm/compilation/aot_compiler.c @@ -14,6 +14,18 @@ #include "aot_emit_control.h" #include "aot_emit_function.h" #include "aot_emit_parametric.h" +#include "simd/simd_access_lanes.h" +#include "simd/simd_bitmask_extracts.h" +#include "simd/simd_bit_shifts.h" +#include "simd/simd_bitwise_ops.h" +#include "simd/simd_bool_reductions.h" +#include "simd/simd_comparisons.h" +#include "simd/simd_construct_values.h" +#include "simd/simd_conversions.h" +#include "simd/simd_floating_point.h" +#include "simd/simd_int_arith.h" +#include "simd/simd_load_store.h" +#include "simd/simd_sat_int_arith.h" #include "../aot/aot_runtime.h" #include "../interpreter/wasm_opcode.h" #include @@ -163,6 +175,7 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index) || value_type == VALUE_TYPE_I64 || value_type == VALUE_TYPE_F32 || value_type == VALUE_TYPE_F64 + || value_type == VALUE_TYPE_V128 || value_type == VALUE_TYPE_VOID) { param_count = 0; param_types = NULL; @@ -280,12 +293,12 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index) case WASM_OP_DROP: if (!aot_compile_op_drop(comp_ctx, func_ctx, true)) - return false; + return false; break; case WASM_OP_DROP_64: if (!aot_compile_op_drop(comp_ctx, func_ctx, false)) - return false; + return false; break; case WASM_OP_SELECT: @@ -761,22 +774,22 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index) case WASM_OP_I32_REINTERPRET_F32: if (!aot_compile_op_i32_reinterpret_f32(comp_ctx, func_ctx)) - return false; + return false; break; case WASM_OP_I64_REINTERPRET_F64: if (!aot_compile_op_i64_reinterpret_f64(comp_ctx, func_ctx)) - return false; + return false; break; case WASM_OP_F32_REINTERPRET_I32: if (!aot_compile_op_f32_reinterpret_i32(comp_ctx, func_ctx)) - return false; + return false; break; case WASM_OP_F64_REINTERPRET_I64: if (!aot_compile_op_f64_reinterpret_i64(comp_ctx, func_ctx)) - return false; + return false; break; case WASM_OP_I32_EXTEND8_S: @@ -1019,6 +1032,722 @@ build_atomic_rmw: } #endif /* end of WASM_ENABLE_SHARED_MEMORY */ +#if WASM_ENABLE_SIMD != 0 + case WASM_OP_SIMD_PREFIX: + { + if (!comp_ctx->enable_simd) { + aot_set_last_error( + "current building does not support SIMD instructions"); + return false; + } + + opcode = *frame_ip++; + switch (opcode) { + case SIMD_v128_load: + { + read_leb_uint32(frame_ip, frame_ip_end, align); + read_leb_uint32(frame_ip, frame_ip_end, offset); + if (!aot_compile_simd_v128_load(comp_ctx, func_ctx, align, offset)) + return false; + break; + } + + case SIMD_i16x8_load8x8_s: + case SIMD_i16x8_load8x8_u: + case SIMD_i32x4_load16x4_s: + case SIMD_i32x4_load16x4_u: + case SIMD_i64x2_load32x2_s: + case SIMD_i64x2_load32x2_u: + { + read_leb_uint32(frame_ip, frame_ip_end, align); + read_leb_uint32(frame_ip, frame_ip_end, offset); + if (!aot_compile_simd_load_extend(comp_ctx, func_ctx, + opcode, align, offset)) + return false; + break; + } + + case SIMD_v8x16_load_splat: + case SIMD_v16x8_load_splat: + case SIMD_v32x4_load_splat: + case SIMD_v64x2_load_splat: + { + read_leb_uint32(frame_ip, frame_ip_end, align); + read_leb_uint32(frame_ip, frame_ip_end, offset); + if (!aot_compile_simd_load_splat(comp_ctx, func_ctx, + opcode, align, offset)) + return false; + break; + } + + case SIMD_v128_store: + { + read_leb_uint32(frame_ip, frame_ip_end, align); + read_leb_uint32(frame_ip, frame_ip_end, offset); + if (!aot_compile_simd_v128_store(comp_ctx, func_ctx, align, offset)) + return false; + break; + } + + case SIMD_v128_const: + { + if (!aot_compile_simd_v128_const(comp_ctx, func_ctx, frame_ip)) + return false; + frame_ip += 16; + break; + } + + case SIMD_v8x16_shuffle: + { + if (!aot_compile_simd_shuffle(comp_ctx, func_ctx, frame_ip)) + return false; + frame_ip += 16; + break; + } + + case SIMD_v8x16_swizzle: + { + if (!aot_compile_simd_swizzle(comp_ctx, func_ctx)) + return false; + break; + } + + case SIMD_i8x16_splat: + case SIMD_i16x8_splat: + case SIMD_i32x4_splat: + case SIMD_i64x2_splat: + case SIMD_f32x4_splat: + case SIMD_f64x2_splat: + { + if (!aot_compile_simd_splat(comp_ctx, func_ctx, opcode)) + return false; + break; + } + + case SIMD_i8x16_extract_lane_s: + { + if (!aot_compile_simd_extract_i8x16(comp_ctx, func_ctx, *frame_ip++, + true)) + return false; + break; + } + case SIMD_i8x16_extract_lane_u: + { + if (!aot_compile_simd_extract_i8x16(comp_ctx, func_ctx, *frame_ip++, + false)) + return false; + break; + } + case SIMD_i16x8_extract_lane_s: + { + if (!aot_compile_simd_extract_i16x8(comp_ctx, func_ctx, *frame_ip++, + true)) + return false; + break; + } + case SIMD_i16x8_extract_lane_u: + { + if (!aot_compile_simd_extract_i16x8(comp_ctx, func_ctx, *frame_ip++, + false)) + return false; + break; + } + case SIMD_i32x4_extract_lane: + { + if (!aot_compile_simd_extract_i32x4(comp_ctx, func_ctx, *frame_ip++)) + return false; + break; + } + case SIMD_i64x2_extract_lane: + { + if (!aot_compile_simd_extract_i64x2(comp_ctx, func_ctx, *frame_ip++)) + return false; + break; + } + case SIMD_f32x4_extract_lane: + { + if (!aot_compile_simd_extract_f32x4(comp_ctx, func_ctx, *frame_ip++)) + return false; + break; + } + case SIMD_f64x2_extract_lane: + { + if (!aot_compile_simd_extract_f64x2(comp_ctx, func_ctx, *frame_ip++)) + return false; + break; + } + + case SIMD_i8x16_replace_lane: + { + if (!aot_compile_simd_replace_i8x16(comp_ctx, func_ctx, *frame_ip++)) + return false; + break; + } + case SIMD_i16x8_replace_lane: + { + if (!aot_compile_simd_replace_i16x8(comp_ctx, func_ctx, *frame_ip++)) + return false; + break; + } + case SIMD_i32x4_replace_lane: + { + if (!aot_compile_simd_replace_i32x4(comp_ctx, func_ctx, *frame_ip++)) + return false; + break; + } + case SIMD_i64x2_replace_lane: + { + if (!aot_compile_simd_replace_i64x2(comp_ctx, func_ctx, *frame_ip++)) + return false; + break; + } + case SIMD_f32x4_replace_lane: + { + if (!aot_compile_simd_replace_f32x4(comp_ctx, func_ctx, *frame_ip++)) + return false; + break; + } + case SIMD_f64x2_replace_lane: + { + if (!aot_compile_simd_replace_f64x2(comp_ctx, func_ctx, *frame_ip++)) + return false; + break; + } + + case SIMD_i8x16_eq: + case SIMD_i8x16_ne: + case SIMD_i8x16_lt_s: + case SIMD_i8x16_lt_u: + case SIMD_i8x16_gt_s: + case SIMD_i8x16_gt_u: + case SIMD_i8x16_le_s: + case SIMD_i8x16_le_u: + case SIMD_i8x16_ge_s: + case SIMD_i8x16_ge_u: + { + if (!aot_compile_simd_i8x16_compare(comp_ctx, func_ctx, + INT_EQ + opcode - SIMD_i8x16_eq)) + return false; + break; + } + + case SIMD_i16x8_eq: + case SIMD_i16x8_ne: + case SIMD_i16x8_lt_s: + case SIMD_i16x8_lt_u: + case SIMD_i16x8_gt_s: + case SIMD_i16x8_gt_u: + case SIMD_i16x8_le_s: + case SIMD_i16x8_le_u: + case SIMD_i16x8_ge_s: + case SIMD_i16x8_ge_u: + { + if (!aot_compile_simd_i16x8_compare(comp_ctx, func_ctx, + INT_EQ + opcode - SIMD_i16x8_eq)) + return false; + break; + } + + case SIMD_i32x4_eq: + case SIMD_i32x4_ne: + case SIMD_i32x4_lt_s: + case SIMD_i32x4_lt_u: + case SIMD_i32x4_gt_s: + case SIMD_i32x4_gt_u: + case SIMD_i32x4_le_s: + case SIMD_i32x4_le_u: + case SIMD_i32x4_ge_s: + case SIMD_i32x4_ge_u: + { + if (!aot_compile_simd_i32x4_compare(comp_ctx, func_ctx, + INT_EQ + opcode - SIMD_i32x4_eq)) + return false; + break; + } + + case SIMD_f32x4_eq: + case SIMD_f32x4_ne: + case SIMD_f32x4_lt: + case SIMD_f32x4_gt: + case SIMD_f32x4_le: + case SIMD_f32x4_ge: + { + if (!aot_compile_simd_f32x4_compare(comp_ctx, func_ctx, + FLOAT_EQ + opcode - SIMD_f32x4_eq)) + return false; + break; + } + + case SIMD_f64x2_eq: + case SIMD_f64x2_ne: + case SIMD_f64x2_lt: + case SIMD_f64x2_gt: + case SIMD_f64x2_le: + case SIMD_f64x2_ge: + { + if (!aot_compile_simd_f64x2_compare(comp_ctx, func_ctx, + FLOAT_EQ + opcode - SIMD_f64x2_eq)) + return false; + break; + } + + case SIMD_v128_not: + case SIMD_v128_and: + case SIMD_v128_andnot: + case SIMD_v128_or: + case SIMD_v128_xor: + case SIMD_v128_bitselect: + { + if (!aot_compile_simd_v128_bitwise(comp_ctx, func_ctx, + V128_NOT + opcode - SIMD_v128_not)) + return false; + break; + } + + case SIMD_i8x16_add: + case SIMD_i8x16_sub: + { + V128Arithmetic arith_op = (opcode == SIMD_i8x16_add) + ? V128_ADD : V128_SUB; + if (!aot_compile_simd_i8x16_arith(comp_ctx, func_ctx, arith_op)) + return false; + break; + } + + case SIMD_i16x8_add: + case SIMD_i16x8_sub: + case SIMD_i16x8_mul: + { + V128Arithmetic arith_op = V128_ADD; + if (opcode == SIMD_i16x8_sub) + arith_op = V128_SUB; + else if (opcode == SIMD_i16x8_mul) + arith_op = V128_MUL; + if (!aot_compile_simd_i16x8_arith(comp_ctx, func_ctx, arith_op)) + return false; + break; + } + + case SIMD_i32x4_add: + case SIMD_i32x4_sub: + case SIMD_i32x4_mul: + { + V128Arithmetic arith_op = V128_ADD; + if (opcode == SIMD_i32x4_sub) + arith_op = V128_SUB; + else if (opcode == SIMD_i32x4_mul) + arith_op = V128_MUL; + if (!aot_compile_simd_i32x4_arith(comp_ctx, func_ctx, arith_op)) + return false; + break; + } + + case SIMD_i64x2_add: + case SIMD_i64x2_sub: + case SIMD_i64x2_mul: + { + V128Arithmetic arith_op = V128_ADD; + if (opcode == SIMD_i64x2_sub) + arith_op = V128_SUB; + else if (opcode == SIMD_i64x2_mul) + arith_op = V128_MUL; + if (!aot_compile_simd_i64x2_arith(comp_ctx, func_ctx, arith_op)) + return false; + break; + } + + case SIMD_i8x16_neg: + { + if (!aot_compile_simd_i8x16_neg(comp_ctx, func_ctx)) + return false; + break; + } + case SIMD_i16x8_neg: + { + if (!aot_compile_simd_i16x8_neg(comp_ctx, func_ctx)) + return false; + break; + } + case SIMD_i32x4_neg: + { + if (!aot_compile_simd_i32x4_neg(comp_ctx, func_ctx)) + return false; + break; + } + case SIMD_i64x2_neg: + { + if (!aot_compile_simd_i64x2_neg(comp_ctx, func_ctx)) + return false; + break; + } + + case SIMD_i8x16_add_saturate_s: + case SIMD_i8x16_add_saturate_u: + { + if (!aot_compile_simd_i8x16_saturate(comp_ctx, func_ctx, V128_ADD, + opcode == SIMD_i8x16_add_saturate_s + ? true : false)) + return false; + break; + } + case SIMD_i8x16_sub_saturate_s: + case SIMD_i8x16_sub_saturate_u: + { + if (!aot_compile_simd_i8x16_saturate(comp_ctx, func_ctx, V128_SUB, + opcode == SIMD_i8x16_sub_saturate_s + ? true : false)) + return false; + break; + } + case SIMD_i16x8_add_saturate_s: + case SIMD_i16x8_add_saturate_u: + { + if (!aot_compile_simd_i16x8_saturate(comp_ctx, func_ctx, V128_ADD, + opcode == SIMD_i16x8_add_saturate_s + ? true : false)) + return false; + break; + } + case SIMD_i16x8_sub_saturate_s: + case SIMD_i16x8_sub_saturate_u: + { + if (!aot_compile_simd_i16x8_saturate(comp_ctx, func_ctx, V128_SUB, + opcode == SIMD_i16x8_sub_saturate_s + ? true : false)) + return false; + break; + } + + case SIMD_i8x16_min_s: + case SIMD_i8x16_min_u: + { + if (!aot_compile_simd_i8x16_cmp(comp_ctx, func_ctx, V128_MIN, + opcode == SIMD_i8x16_min_s + ? true : false)) + return false; + break; + } + case SIMD_i8x16_max_s: + case SIMD_i8x16_max_u: + { + if (!aot_compile_simd_i8x16_cmp(comp_ctx, func_ctx, V128_MAX, + opcode == SIMD_i8x16_max_s + ? true : false)) + return false; + break; + } + case SIMD_i16x8_min_s: + case SIMD_i16x8_min_u: + { + if (!aot_compile_simd_i16x8_cmp(comp_ctx, func_ctx, V128_MIN, + opcode == SIMD_i16x8_min_s + ? true : false)) + return false; + break; + } + case SIMD_i16x8_max_s: + case SIMD_i16x8_max_u: + { + if (!aot_compile_simd_i16x8_cmp(comp_ctx, func_ctx, V128_MAX, + opcode == SIMD_i16x8_max_s + ? true : false)) + return false; + break; + } + case SIMD_i32x4_min_s: + case SIMD_i32x4_min_u: + { + if (!aot_compile_simd_i32x4_cmp(comp_ctx, func_ctx, V128_MIN, + opcode == SIMD_i32x4_min_s + ? true : false)) + return false; + break; + } + case SIMD_i32x4_max_s: + case SIMD_i32x4_max_u: + { + if (!aot_compile_simd_i32x4_cmp(comp_ctx, func_ctx, V128_MAX, + opcode == SIMD_i32x4_max_s + ? true : false)) + return false; + break; + } + + case SIMD_i8x16_abs: + { + if (!aot_compile_simd_i8x16_abs(comp_ctx, func_ctx)) + return false; + break; + } + case SIMD_i16x8_abs: + { + if (!aot_compile_simd_i16x8_abs(comp_ctx, func_ctx)) + return false; + break; + } + case SIMD_i32x4_abs: + { + if (!aot_compile_simd_i32x4_abs(comp_ctx, func_ctx)) + return false; + break; + } + + case SIMD_i8x16_avgr_u: + { + if (!aot_compile_simd_i8x16_avgr_u(comp_ctx, func_ctx)) + return false; + break; + } + case SIMD_i16x8_avgr_u: + { + if (!aot_compile_simd_i16x8_avgr_u(comp_ctx, func_ctx)) + return false; + break; + } + + case SIMD_i8x16_any_true: + { + if (!aot_compile_simd_i8x16_any_true(comp_ctx, func_ctx)) + return false; + break; + } + case SIMD_i16x8_any_true: + { + if (!aot_compile_simd_i16x8_any_true(comp_ctx, func_ctx)) + return false; + break; + } + case SIMD_i32x4_any_true: + { + if (!aot_compile_simd_i32x4_any_true(comp_ctx, func_ctx)) + return false; + break; + } + case SIMD_i8x16_all_true: + { + if (!aot_compile_simd_i8x16_all_true(comp_ctx, func_ctx)) + return false; + break; + } + case SIMD_i16x8_all_true: + { + if (!aot_compile_simd_i16x8_all_true(comp_ctx, func_ctx)) + return false; + break; + } + case SIMD_i32x4_all_true: + { + if (!aot_compile_simd_i32x4_all_true(comp_ctx, func_ctx)) + return false; + break; + } + case SIMD_i8x16_bitmask: + { + if (!aot_compile_simd_i8x16_bitmask(comp_ctx, func_ctx)) + return false; + break; + } + case SIMD_i16x8_bitmask: + { + if (!aot_compile_simd_i16x8_bitmask(comp_ctx, func_ctx)) + return false; + break; + } + case SIMD_i32x4_bitmask: + { + if (!aot_compile_simd_i32x4_bitmask(comp_ctx, func_ctx)) + return false; + break; + } + + case SIMD_i8x16_shl: + case SIMD_i8x16_shr_s: + case SIMD_i8x16_shr_u: + { + if (!aot_compile_simd_i8x16_shift(comp_ctx, func_ctx, + INT_SHL + opcode - SIMD_i8x16_shl)) + return false; + break; + } + case SIMD_i16x8_shl: + case SIMD_i16x8_shr_s: + case SIMD_i16x8_shr_u: + { + if (!aot_compile_simd_i16x8_shift(comp_ctx, func_ctx, + INT_SHL + opcode - SIMD_i16x8_shl)) + return false; + break; + } + case SIMD_i32x4_shl: + case SIMD_i32x4_shr_s: + case SIMD_i32x4_shr_u: + { + if (!aot_compile_simd_i32x4_shift(comp_ctx, func_ctx, + INT_SHL + opcode - SIMD_i32x4_shl)) + return false; + break; + } + case SIMD_i64x2_shl: + case SIMD_i64x2_shr_s: + case SIMD_i64x2_shr_u: + { + if (!aot_compile_simd_i64x2_shift(comp_ctx, func_ctx, + INT_SHL + opcode - SIMD_i64x2_shl)) + return false; + break; + } + + case SIMD_i8x16_narrow_i16x8_s: + case SIMD_i8x16_narrow_i16x8_u: + { + bool is_signed = (opcode == SIMD_i8x16_narrow_i16x8_s) + ? true : false; + if (!aot_compile_simd_i8x16_narrow_i16x8(comp_ctx, func_ctx, + is_signed)) + return false; + break; + } + case SIMD_i16x8_narrow_i32x4_s: + case SIMD_i16x8_narrow_i32x4_u: + { + bool is_signed = (opcode == SIMD_i16x8_narrow_i32x4_s) + ? true : false; + if (!aot_compile_simd_i16x8_narrow_i32x4(comp_ctx, func_ctx, + is_signed)) + return false; + break; + } + case SIMD_i16x8_widen_low_i8x16_s: + case SIMD_i16x8_widen_high_i8x16_s: + { + bool is_low = (opcode == SIMD_i16x8_widen_low_i8x16_s) + ? true : false; + if (!aot_compile_simd_i16x8_widen_i8x16(comp_ctx, func_ctx, + is_low, true)) + return false; + break; + } + case SIMD_i16x8_widen_low_i8x16_u: + case SIMD_i16x8_widen_high_i8x16_u: + { + bool is_low = (opcode == SIMD_i16x8_widen_low_i8x16_u) + ? true : false; + if (!aot_compile_simd_i16x8_widen_i8x16(comp_ctx, func_ctx, + is_low, false)) + return false; + break; + } + case SIMD_i32x4_widen_low_i16x8_s: + case SIMD_i32x4_widen_high_i16x8_s: + { + bool is_low = (opcode == SIMD_i32x4_widen_low_i16x8_s) + ? true : false; + if (!aot_compile_simd_i32x4_widen_i16x8(comp_ctx, func_ctx, + is_low, true)) + return false; + break; + } + case SIMD_i32x4_widen_low_i16x8_u: + case SIMD_i32x4_widen_high_i16x8_u: + { + bool is_low = (opcode == SIMD_i32x4_widen_low_i16x8_u) + ? true : false; + if (!aot_compile_simd_i32x4_widen_i16x8(comp_ctx, func_ctx, + is_low, false)) + return false; + break; + } + + case SIMD_i32x4_trunc_sat_f32x4_s: + case SIMD_i32x4_trunc_sat_f32x4_u: + { + bool is_signed = (opcode == SIMD_i32x4_trunc_sat_f32x4_s) + ? true : false; + if (!aot_compile_simd_i32x4_trunc_sat_f32x4(comp_ctx, func_ctx, + is_signed)) + return false; + break; + } + case SIMD_f32x4_convert_i32x4_s: + case SIMD_f32x4_convert_i32x4_u: + { + bool is_signed = (opcode == SIMD_f32x4_convert_i32x4_s) + ? true : false; + if (!aot_compile_simd_f32x4_convert_i32x4(comp_ctx, func_ctx, + is_signed)) + return false; + break; + } + + case SIMD_f32x4_add: + case SIMD_f32x4_sub: + case SIMD_f32x4_mul: + case SIMD_f32x4_div: + case SIMD_f32x4_min: + case SIMD_f32x4_max: + { + if (!aot_compile_simd_f32x4_arith(comp_ctx, func_ctx, + FLOAT_ADD + opcode - SIMD_f32x4_add)) + return false; + break; + } + case SIMD_f64x2_add: + case SIMD_f64x2_sub: + case SIMD_f64x2_mul: + case SIMD_f64x2_div: + case SIMD_f64x2_min: + case SIMD_f64x2_max: + { + if (!aot_compile_simd_f64x2_arith(comp_ctx, func_ctx, + FLOAT_ADD + opcode - SIMD_f64x2_add)) + return false; + break; + } + + case SIMD_f32x4_neg: + { + if (!aot_compile_simd_f32x4_neg(comp_ctx, func_ctx)) + return false; + break; + } + case SIMD_f64x2_neg: + { + if (!aot_compile_simd_f64x2_neg(comp_ctx, func_ctx)) + return false; + break; + } + case SIMD_f32x4_abs: + { + if (!aot_compile_simd_f32x4_abs(comp_ctx, func_ctx)) + return false; + break; + } + case SIMD_f64x2_abs: + { + if (!aot_compile_simd_f64x2_abs(comp_ctx, func_ctx)) + return false; + break; + } + case SIMD_f32x4_sqrt: + { + if (!aot_compile_simd_f32x4_sqrt(comp_ctx, func_ctx)) + return false; + break; + } + case SIMD_f64x2_sqrt: + { + if (!aot_compile_simd_f64x2_sqrt(comp_ctx, func_ctx)) + return false; + break; + } + + default: + break; + } + break; + } +#endif /* end of WASM_ENABLE_SIMD */ + default: aot_set_last_error("unsupported opcode"); break; diff --git a/core/iwasm/compilation/aot_compiler.h b/core/iwasm/compilation/aot_compiler.h index b44ab4ddf..88bccc552 100644 --- a/core/iwasm/compilation/aot_compiler.h +++ b/core/iwasm/compilation/aot_compiler.h @@ -46,12 +46,35 @@ typedef enum IntArithmetic { INT_REM_U } IntArithmetic; +typedef enum V128Arithmetic { + V128_ADD = 0, + V128_ADD_SATURATE_S, + V128_ADD_SATURATE_U, + V128_SUB, + V128_SUB_SATURATE_S, + V128_SUB_SATURATE_U, + V128_MUL, + V128_DIV, + V128_NEG, + V128_MIN, + V128_MAX, +} V128Arithmetic; + typedef enum IntBitwise { INT_AND = 0, INT_OR, INT_XOR, } IntBitwise; +typedef enum V128Bitwise { + V128_NOT, + V128_AND, + V128_ANDNOT, + V128_OR, + V128_XOR, + V128_BITSELECT +} V128Bitwise; + typedef enum IntShift { INT_SHL = 0, INT_SHR_S, @@ -123,6 +146,7 @@ typedef enum FloatArithmetic { #define POP_I64(v) POP(v, VALUE_TYPE_I64) #define POP_F32(v) POP(v, VALUE_TYPE_F32) #define POP_F64(v) POP(v, VALUE_TYPE_F64) +#define POP_V128(v) POP(v, VALUE_TYPE_V128) #define POP_COND(llvm_value) do { \ AOTValue *aot_value; \ @@ -172,6 +196,7 @@ typedef enum FloatArithmetic { #define PUSH_I64(v) PUSH(v, VALUE_TYPE_I64) #define PUSH_F32(v) PUSH(v, VALUE_TYPE_F32) #define PUSH_F64(v) PUSH(v, VALUE_TYPE_F64) +#define PUSH_V128(v) PUSH(v, VALUE_TYPE_V128) #define PUSH_COND(v) PUSH(v, VALUE_TYPE_I1) #define TO_LLVM_TYPE(wasm_type) \ @@ -218,6 +243,36 @@ typedef enum FloatArithmetic { #define I64_63 (comp_ctx->llvm_consts.i64_63) #define I64_64 (comp_ctx->llvm_consts.i64_64) +#define V128_TYPE comp_ctx->basic_types.v128_type +#define V128_PTR_TYPE comp_ctx->basic_types.v128_ptr_type +#define V128_i8x16_TYPE comp_ctx->basic_types.i8x16_vec_type +#define V128_i16x8_TYPE comp_ctx->basic_types.i16x8_vec_type +#define V128_i32x4_TYPE comp_ctx->basic_types.i32x4_vec_type +#define V128_i64x2_TYPE comp_ctx->basic_types.i64x2_vec_type +#define V128_f32x4_TYPE comp_ctx->basic_types.f32x4_vec_type +#define V128_f64x2_TYPE comp_ctx->basic_types.f64x2_vec_type + +#define V128_ZERO (comp_ctx->llvm_consts.v128_zero) +#define V128_i8x16_ZERO (comp_ctx->llvm_consts.i8x16_vec_zero) +#define V128_i16x8_ZERO (comp_ctx->llvm_consts.i16x8_vec_zero) +#define V128_i32x4_ZERO (comp_ctx->llvm_consts.i32x4_vec_zero) +#define V128_i64x2_ZERO (comp_ctx->llvm_consts.i64x2_vec_zero) +#define V128_f32x4_ZERO (comp_ctx->llvm_consts.f32x4_vec_zero) +#define V128_f64x2_ZERO (comp_ctx->llvm_consts.f64x2_vec_zero) + +#define TO_V128_i8x16(v) LLVMBuildBitCast(comp_ctx->builder, v, \ + V128_i8x16_TYPE, "i8x16_val") +#define TO_V128_i16x8(v) LLVMBuildBitCast(comp_ctx->builder, v, \ + V128_i16x8_TYPE, "i16x8_val") +#define TO_V128_i32x4(v) LLVMBuildBitCast(comp_ctx->builder, v, \ + V128_i32x4_TYPE, "i32x4_val") +#define TO_V128_i64x2(v) LLVMBuildBitCast(comp_ctx->builder, v, \ + V128_i64x2_TYPE, "i64x2_val") +#define TO_V128_f32x4(v) LLVMBuildBitCast(comp_ctx->builder, v, \ + V128_f32x4_TYPE, "f32x4_val") +#define TO_V128_f64x2(v) LLVMBuildBitCast(comp_ctx->builder, v, \ + V128_f64x2_TYPE, "f64x2_val") + #define CHECK_LLVM_CONST(v) do { \ if (!v) { \ aot_set_last_error("create llvm const failed."); \ diff --git a/core/iwasm/compilation/aot_emit_aot_file.c b/core/iwasm/compilation/aot_emit_aot_file.c index 98311ec92..3a5641de6 100644 --- a/core/iwasm/compilation/aot_emit_aot_file.c +++ b/core/iwasm/compilation/aot_emit_aot_file.c @@ -299,9 +299,14 @@ get_import_global_info_size(AOTCompData *comp_data) static uint32 get_global_size(AOTGlobal *global) { - /* type (1 byte) + is_mutable (1 byte) - + init expr type (2 byes) + init expr value (8 byes) */ - return sizeof(uint8) * 2 + sizeof(uint16) + sizeof(uint64); + if (global->init_expr.init_expr_type != INIT_EXPR_TYPE_V128_CONST) + /* type (1 byte) + is_mutable (1 byte) + + init expr type (2 byes) + init expr value (8 byes) */ + return sizeof(uint8) * 2 + sizeof(uint16) + sizeof(uint64); + else + /* type (1 byte) + is_mutable (1 byte) + + init expr type (2 byes) + v128 value (16 byes) */ + return sizeof(uint8) * 2 + sizeof(uint16) + sizeof(uint64) * 2; } static uint32 @@ -800,10 +805,28 @@ exchange_uint32(uint8 *p_data) static void exchange_uint64(uint8 *pData) { + uint32 value; + + value = *(uint32 *)pData; + *(uint32 *)pData = *(uint32 *)(pData + 4); + *(uint32 *)(pData + 4) = value; exchange_uint32(pData); exchange_uint32(pData + 4); } +static void +exchange_uint128(uint8 *pData) +{ + /* swap high 64bit and low 64bit */ + uint64 value = *(uint64*)pData; + *(uint64*)pData = *(uint64*)(pData + 8); + *(uint64*)(pData + 8) = value; + /* exchange high 64bit */ + exchange_uint64(pData); + /* exchange low 64bit */ + exchange_uint64(pData + 8); +} + static union { int a; char b; @@ -851,6 +874,17 @@ static union { offset += (uint32)sizeof(uint64); \ } while (0) +#define EMIT_V128(v) do { \ + uint64 *t = (uint64*)v.i64x2; \ + CHECK_BUF(16); \ + if (!is_little_endian()) \ + exchange_uint128((uint8 *)&t); \ + PUT_U64_TO_ADDR(buf + offset, t[0]); \ + offset += (uint32)sizeof(uint64); \ + PUT_U64_TO_ADDR(buf + offset, t[1]); \ + offset += (uint32)sizeof(uint64); \ + } while (0) + #define EMIT_BUF(v, len) do { \ CHECK_BUF(len); \ memcpy(buf + offset, v, len); \ @@ -1093,7 +1127,10 @@ aot_emit_global_info(uint8 *buf, uint8 *buf_end, uint32 *p_offset, EMIT_U8(global->type); EMIT_U8(global->is_mutable); EMIT_U16(global->init_expr.init_expr_type); - EMIT_U64(global->init_expr.u.i64); + if (global->init_expr.init_expr_type != INIT_EXPR_TYPE_V128_CONST) + EMIT_U64(global->init_expr.u.i64); + else + EMIT_V128(global->init_expr.u.v128); } if (offset - *p_offset != get_global_info_size(comp_data)) { diff --git a/core/iwasm/compilation/aot_emit_control.c b/core/iwasm/compilation/aot_emit_control.c index a2799a7e5..783fb527d 100644 --- a/core/iwasm/compilation/aot_emit_control.c +++ b/core/iwasm/compilation/aot_emit_control.c @@ -96,11 +96,17 @@ format_block_name(char *name, uint32 name_size, } \ } while (0) -#define ADD_TO_RESULT_PHIS(block, value, idx) do { \ - LLVMBasicBlockRef block_curr = CURR_BLOCK(); \ - LLVMAddIncoming(block->result_phis[idx], \ - &value, &block_curr, 1); \ - } while (0) +#define ADD_TO_RESULT_PHIS(block, value, idx) do { \ + LLVMBasicBlockRef block_curr = CURR_BLOCK(); \ + LLVMTypeRef phi_ty = LLVMTypeOf(block->result_phis[idx]); \ + LLVMTypeRef value_ty = LLVMTypeOf(value); \ + bh_assert(LLVMGetTypeKind(phi_ty) == LLVMGetTypeKind(value_ty)); \ + bh_assert(LLVMGetTypeContext(phi_ty) \ + == LLVMGetTypeContext(value_ty)); \ + LLVMAddIncoming(block->result_phis[idx], &value, &block_curr, 1); \ + (void)phi_ty; \ + (void)value_ty; \ + } while (0) #define BUILD_ICMP(op, left, right, res, name) do { \ if (!(res = LLVMBuildICmp(comp_ctx->builder, op, \ @@ -686,24 +692,8 @@ check_suspend_flags(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) /* Move builder to terminate block */ SET_BUILDER_POS(terminate_block); - 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); + if (!aot_build_zero_function_ret(comp_ctx, aot_func_type)) { + goto fail; } /* Move builder to terminate block */ diff --git a/core/iwasm/compilation/aot_emit_exception.c b/core/iwasm/compilation/aot_emit_exception.c index 62911189b..3f5b6548c 100644 --- a/core/iwasm/compilation/aot_emit_exception.c +++ b/core/iwasm/compilation/aot_emit_exception.c @@ -53,10 +53,8 @@ aot_emit_exception(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, func_ctx->got_exception_block); /* Create exection id phi */ - if (!(func_ctx->exception_id_phi = - LLVMBuildPhi(comp_ctx->builder, - comp_ctx->basic_types.int32_type, - "exception_id_phi"))) { + if (!(func_ctx->exception_id_phi = LLVMBuildPhi( + comp_ctx->builder, I32_TYPE, "exception_id_phi"))) { aot_set_last_error("llvm build phi failed."); return false; } @@ -110,24 +108,8 @@ aot_emit_exception(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, /* Create return IR */ AOTFuncType *aot_func_type = func_ctx->aot_func->func_type; - 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); + if (!aot_build_zero_function_ret(comp_ctx, aot_func_type)) { + return false; } /* Resume the builder position */ diff --git a/core/iwasm/compilation/aot_emit_function.c b/core/iwasm/compilation/aot_emit_function.c index 054275115..dd701d89e 100644 --- a/core/iwasm/compilation/aot_emit_function.c +++ b/core/iwasm/compilation/aot_emit_function.c @@ -25,24 +25,8 @@ create_func_return_block(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) /* Create return IR */ LLVMPositionBuilderAtEnd(comp_ctx->builder, func_ctx->func_return_block); - 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); + if (!aot_build_zero_function_ret(comp_ctx, aot_func_type)) { + return false; } } diff --git a/core/iwasm/compilation/aot_emit_memory.c b/core/iwasm/compilation/aot_emit_memory.c index 68ed1ef7e..f717b02c6 100644 --- a/core/iwasm/compilation/aot_emit_memory.c +++ b/core/iwasm/compilation/aot_emit_memory.c @@ -53,6 +53,9 @@ get_memory_check_bound(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, case 8: mem_check_bound = func_ctx->mem_info[0].mem_bound_check_8bytes; break; + case 16: + mem_check_bound = func_ctx->mem_info[0].mem_bound_check_16bytes; + break; default: bh_assert(0); return NULL; @@ -73,9 +76,9 @@ get_memory_check_bound(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, 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 +aot_check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, + uint32 offset, uint32 bytes) { LLVMValueRef offset_const = I32_CONST(offset); LLVMValueRef addr, maddr, offset1, cmp1, cmp2, cmp; @@ -348,7 +351,7 @@ aot_compile_op_i32_load(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, { LLVMValueRef maddr, value = NULL; - if (!(maddr = check_memory_overflow(comp_ctx, func_ctx, offset, bytes))) + if (!(maddr = aot_check_memory_overflow(comp_ctx, func_ctx, offset, bytes))) return false; switch (bytes) { @@ -400,7 +403,7 @@ aot_compile_op_i64_load(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, { LLVMValueRef maddr, value = NULL; - if (!(maddr = check_memory_overflow(comp_ctx, func_ctx, offset, bytes))) + if (!(maddr = aot_check_memory_overflow(comp_ctx, func_ctx, offset, bytes))) return false; switch (bytes) { @@ -454,7 +457,7 @@ aot_compile_op_f32_load(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, { LLVMValueRef maddr, value; - if (!(maddr = check_memory_overflow(comp_ctx, func_ctx, offset, 4))) + if (!(maddr = aot_check_memory_overflow(comp_ctx, func_ctx, offset, 4))) return false; BUILD_PTR_CAST(F32_PTR_TYPE); @@ -471,7 +474,7 @@ aot_compile_op_f64_load(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, { LLVMValueRef maddr, value; - if (!(maddr = check_memory_overflow(comp_ctx, func_ctx, offset, 8))) + if (!(maddr = aot_check_memory_overflow(comp_ctx, func_ctx, offset, 8))) return false; BUILD_PTR_CAST(F64_PTR_TYPE); @@ -490,7 +493,7 @@ aot_compile_op_i32_store(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, POP_I32(value); - if (!(maddr = check_memory_overflow(comp_ctx, func_ctx, offset, bytes))) + if (!(maddr = aot_check_memory_overflow(comp_ctx, func_ctx, offset, bytes))) return false; switch (bytes) { @@ -529,7 +532,7 @@ aot_compile_op_i64_store(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, POP_I64(value); - if (!(maddr = check_memory_overflow(comp_ctx, func_ctx, offset, bytes))) + if (!(maddr = aot_check_memory_overflow(comp_ctx, func_ctx, offset, bytes))) return false; switch (bytes) { @@ -572,7 +575,7 @@ aot_compile_op_f32_store(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, POP_F32(value); - if (!(maddr = check_memory_overflow(comp_ctx, func_ctx, offset, 4))) + if (!(maddr = aot_check_memory_overflow(comp_ctx, func_ctx, offset, 4))) return false; BUILD_PTR_CAST(F32_PTR_TYPE); @@ -590,7 +593,7 @@ aot_compile_op_f64_store(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, POP_F64(value); - if (!(maddr = check_memory_overflow(comp_ctx, func_ctx, offset, 8))) + if (!(maddr = aot_check_memory_overflow(comp_ctx, func_ctx, offset, 8))) return false; BUILD_PTR_CAST(F64_PTR_TYPE); @@ -877,24 +880,8 @@ aot_compile_op_memory_init(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, /* 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); + if (!aot_build_zero_function_ret(comp_ctx, aot_func_type)) { + goto fail; } LLVMPositionBuilderAtEnd(comp_ctx->builder, init_success); @@ -1002,7 +989,7 @@ aot_compile_op_atomic_rmw(AOTCompContext *comp_ctx, else POP_I64(value); - if (!(maddr = check_memory_overflow(comp_ctx, func_ctx, offset, bytes))) + if (!(maddr = aot_check_memory_overflow(comp_ctx, func_ctx, offset, bytes))) return false; if (!check_memory_alignment(comp_ctx, func_ctx, maddr, align)) @@ -1076,7 +1063,7 @@ aot_compile_op_atomic_cmpxchg(AOTCompContext *comp_ctx, POP_I64(expect); } - if (!(maddr = check_memory_overflow(comp_ctx, func_ctx, offset, bytes))) + if (!(maddr = aot_check_memory_overflow(comp_ctx, func_ctx, offset, bytes))) return false; if (!check_memory_alignment(comp_ctx, func_ctx, maddr, align)) @@ -1175,7 +1162,7 @@ aot_compile_op_atomic_wait(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, CHECK_LLVM_CONST(is_wait64); - if (!(maddr = check_memory_overflow(comp_ctx, func_ctx, offset, bytes))) + if (!(maddr = aot_check_memory_overflow(comp_ctx, func_ctx, offset, bytes))) return false; if (!check_memory_alignment(comp_ctx, func_ctx, maddr, align)) @@ -1219,24 +1206,8 @@ aot_compile_op_atomic_wait(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, /* If atomic wait failed, return this function so the runtime can catch the exception */ LLVMPositionBuilderAtEnd(comp_ctx->builder, wait_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); + if (!aot_build_zero_function_ret(comp_ctx, aot_func_type)) { + goto fail; } LLVMPositionBuilderAtEnd(comp_ctx->builder, wait_success); @@ -1259,7 +1230,7 @@ aot_compiler_op_atomic_notify(AOTCompContext *comp_ctx, POP_I32(count); - if (!(maddr = check_memory_overflow(comp_ctx, func_ctx, offset, bytes))) + if (!(maddr = aot_check_memory_overflow(comp_ctx, func_ctx, offset, bytes))) return false; if (!check_memory_alignment(comp_ctx, func_ctx, maddr, align)) diff --git a/core/iwasm/compilation/aot_emit_memory.h b/core/iwasm/compilation/aot_emit_memory.h index 82465ae37..f505a23ea 100644 --- a/core/iwasm/compilation/aot_emit_memory.h +++ b/core/iwasm/compilation/aot_emit_memory.h @@ -49,6 +49,10 @@ bool aot_compile_op_f64_store(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, uint32 align, uint32 offset); +LLVMValueRef +aot_check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, + uint32 offset, uint32 bytes); + bool aot_compile_op_memory_size(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx); diff --git a/core/iwasm/compilation/aot_emit_numberic.c b/core/iwasm/compilation/aot_emit_numberic.c index d686dead6..f54140da8 100644 --- a/core/iwasm/compilation/aot_emit_numberic.c +++ b/core/iwasm/compilation/aot_emit_numberic.c @@ -135,110 +135,6 @@ } while (0) -static LLVMValueRef -__call_llvm_intrinsic(AOTCompContext *comp_ctx, - const char *name, - LLVMTypeRef ret_type, - LLVMTypeRef *param_types, - int param_count, - LLVMValueRef *param_values) -{ - LLVMValueRef func, ret; - LLVMTypeRef func_type; - - /* Declare llvm intrinsic function if necessary */ - if (!(func = LLVMGetNamedFunction(comp_ctx->module, name))) { - if (!(func_type = - LLVMFunctionType(ret_type, param_types, (uint32)param_count, false))) { - aot_set_last_error("create LLVM function type failed."); - return NULL; - } - - if (!(func = LLVMAddFunction(comp_ctx->module, name, func_type))) { - aot_set_last_error("add LLVM function failed."); - return NULL; - } - } - - /* Call the LLVM intrinsic function */ - if (!(ret = LLVMBuildCall(comp_ctx->builder, func, param_values, - (uint32)param_count, "call"))) { - aot_set_last_error("llvm build call failed."); - return NULL; - } - - return ret; -} - -static LLVMValueRef -call_llvm_intrinsic(AOTCompContext *comp_ctx, - const char *name, - LLVMTypeRef ret_type, - LLVMTypeRef *param_types, - int param_count, - ...) -{ - LLVMValueRef *param_values, ret; - va_list argptr; - uint64 total_size; - int i = 0; - - /* Create param values */ - total_size = sizeof(LLVMValueRef) * (uint64)param_count; - if (total_size >= UINT32_MAX - || !(param_values = wasm_runtime_malloc((uint32)total_size))) { - aot_set_last_error("allocate memory for param values failed."); - return false; - } - - /* Load each param value */ - va_start(argptr, param_count); - while (i < param_count) - param_values[i++] = va_arg(argptr, LLVMValueRef); - va_end(argptr); - - ret = __call_llvm_intrinsic(comp_ctx, name, ret_type, - param_types, param_count, - param_values); - - wasm_runtime_free(param_values); - - return ret; -} - -static LLVMValueRef -call_llvm_intrinsic_v(AOTCompContext *comp_ctx, - const char *name, - LLVMTypeRef ret_type, - LLVMTypeRef *param_types, - int param_count, - va_list param_value_list) -{ - LLVMValueRef *param_values, ret; - uint64 total_size; - int i = 0; - - /* Create param values */ - total_size = sizeof(LLVMValueRef) * (uint64)param_count; - if (total_size >= UINT32_MAX - || !(param_values = wasm_runtime_malloc((uint32)total_size))) { - aot_set_last_error("allocate memory for param values failed."); - return false; - } - - /* Load each param value */ - while (i < param_count) - param_values[i++] = va_arg(param_value_list, LLVMValueRef); - - ret = __call_llvm_intrinsic(comp_ctx, name, ret_type, - param_types, param_count, - param_values); - - wasm_runtime_free(param_values); - - return ret; -} - /* Call llvm constrained floating-point intrinsic */ static LLVMValueRef call_llvm_float_experimental_constrained_intrinsic(AOTCompContext *comp_ctx, @@ -255,12 +151,8 @@ call_llvm_float_experimental_constrained_intrinsic(AOTCompContext *comp_ctx, va_start(param_value_list, intrinsic); - ret = call_llvm_intrinsic_v(comp_ctx, - intrinsic, - ret_type, - param_types, - 4, - param_value_list); + ret = aot_call_llvm_intrinsic_v(comp_ctx, intrinsic, ret_type, param_types, + 4, param_value_list); va_end(param_value_list); @@ -283,12 +175,8 @@ call_llvm_libm_experimental_constrained_intrinsic(AOTCompContext *comp_ctx, va_start(param_value_list, intrinsic); - ret = call_llvm_intrinsic_v(comp_ctx, - intrinsic, - ret_type, - param_types, - 3, - param_value_list); + ret = aot_call_llvm_intrinsic_v(comp_ctx, intrinsic, ret_type, param_types, + 3, param_value_list); va_end(param_value_list); @@ -342,13 +230,8 @@ compile_op_float_min_max(AOTCompContext *comp_ctx, return NULL; } - if (!(cmp = call_llvm_intrinsic(comp_ctx, - intrinsic, - ret_type, - param_types, - 2, - left, - right))) + if (!(cmp = aot_call_llvm_intrinsic(comp_ctx, intrinsic, ret_type, + param_types, 2, left, right))) return NULL; if (!(cmp = LLVMBuildSelect(comp_ctx->builder, @@ -406,21 +289,21 @@ aot_compile_int_bit_count(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, /* Call the LLVM intrinsic function */ if (type < POP_CNT32) - DEF_INT_UNARY_OP(call_llvm_intrinsic(comp_ctx, - bit_cnt_llvm_intrinsic[type], - ret_type, - param_types, - 2, - operand, - zero_undef), + DEF_INT_UNARY_OP(aot_call_llvm_intrinsic(comp_ctx, + bit_cnt_llvm_intrinsic[type], + ret_type, + param_types, + 2, + operand, + zero_undef), NULL); else - DEF_INT_UNARY_OP(call_llvm_intrinsic(comp_ctx, - bit_cnt_llvm_intrinsic[type], - ret_type, - param_types, - 1, - operand), + DEF_INT_UNARY_OP(aot_call_llvm_intrinsic(comp_ctx, + bit_cnt_llvm_intrinsic[type], + ret_type, + param_types, + 1, + operand), NULL); return true; @@ -1032,12 +915,8 @@ call_llvm_float_math_intrinsic(AOTCompContext *comp_ctx, va_start(param_value_list, intrinsic); - ret = call_llvm_intrinsic_v(comp_ctx, - intrinsic, - ret_type, - ¶m_type, - 1, - param_value_list); + ret = aot_call_llvm_intrinsic_v(comp_ctx, intrinsic, ret_type, ¶m_type, + 1, param_value_list); va_end(param_value_list); @@ -1133,14 +1012,14 @@ compile_float_copysign(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, param_types[0] = param_types[1] = ret_type = is_f32 ? F32_TYPE : F64_TYPE; - DEF_FP_BINARY_OP(call_llvm_intrinsic(comp_ctx, - is_f32 ? "llvm.copysign.f32" : - "llvm.copysign.f64", - ret_type, - param_types, - 2, - left, - right), + DEF_FP_BINARY_OP(aot_call_llvm_intrinsic(comp_ctx, + is_f32 ? "llvm.copysign.f32" : + "llvm.copysign.f64", + ret_type, + param_types, + 2, + left, + right), NULL); return true; diff --git a/core/iwasm/compilation/aot_emit_parametric.c b/core/iwasm/compilation/aot_emit_parametric.c index dc81ad53e..498e9e8a6 100644 --- a/core/iwasm/compilation/aot_emit_parametric.c +++ b/core/iwasm/compilation/aot_emit_parametric.c @@ -46,7 +46,8 @@ pop_value_from_wasm_stack(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, wasm_runtime_free(aot_value); if ((is_32 - && (type != VALUE_TYPE_I32 && type != VALUE_TYPE_F32)) + && (type != VALUE_TYPE_I32 && type != VALUE_TYPE_F32 + && type != VALUE_TYPE_V128)) || (!is_32 && (type != VALUE_TYPE_I64 && type != VALUE_TYPE_F64))) { aot_set_last_error("invalid WASM stack data type."); diff --git a/core/iwasm/compilation/aot_emit_variable.c b/core/iwasm/compilation/aot_emit_variable.c index f9e18a5fd..78d39f7d3 100644 --- a/core/iwasm/compilation/aot_emit_variable.c +++ b/core/iwasm/compilation/aot_emit_variable.c @@ -116,7 +116,7 @@ compile_global(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, + sizeof(AOTMemoryInstance) * comp_ctx->comp_data->memory_count; uint32 global_offset; uint8 global_type; - LLVMValueRef offset, global_ptr, global; + LLVMValueRef offset, global_ptr, global, res; LLVMTypeRef ptr_type = NULL; bh_assert(global_idx < import_global_count + comp_data->global_count); @@ -153,6 +153,9 @@ compile_global(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, 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(0); break; @@ -170,14 +173,19 @@ compile_global(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, 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 (!LLVMBuildStore(comp_ctx->builder, global, global_ptr)) { + 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; diff --git a/core/iwasm/compilation/aot_llvm.c b/core/iwasm/compilation/aot_llvm.c index e81e4602c..371f69cdb 100644 --- a/core/iwasm/compilation/aot_llvm.c +++ b/core/iwasm/compilation/aot_llvm.c @@ -21,6 +21,10 @@ wasm_type_to_llvm_type(AOTLLVMTypes *llvm_types, uint8 wasm_type) return llvm_types->float32_type; case VALUE_TYPE_F64: return llvm_types->float64_type; +#if WASM_ENABLE_SIMD != 0 + case VALUE_TYPE_V128: + return llvm_types->i64x2_vec_type; +#endif case VALUE_TYPE_VOID: return llvm_types->void_type; } @@ -444,6 +448,31 @@ create_memory_info(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } } + offset = I32_CONST(offsetof(AOTMemoryInstance, mem_bound_check_16bytes) + - offsetof(AOTMemoryInstance, memory_data.ptr)); + if (!(func_ctx->mem_info[0].mem_bound_check_16bytes = + LLVMBuildInBoundsGEP(comp_ctx->builder, mem_info_base, + &offset, 1, "bound_check_16bytes_offset"))) { + aot_set_last_error("llvm build in bounds gep failed"); + return false; + } + if (!(func_ctx->mem_info[0].mem_bound_check_16bytes = + LLVMBuildBitCast(comp_ctx->builder, + func_ctx->mem_info[0].mem_bound_check_16bytes, + bound_check_type, "bound_check_16bytes_ptr"))) { + aot_set_last_error("llvm build bit cast failed"); + return false; + } + if (mem_space_unchanged) { + if (!(func_ctx->mem_info[0].mem_bound_check_16bytes = + LLVMBuildLoad(comp_ctx->builder, + func_ctx->mem_info[0].mem_bound_check_16bytes, + "bound_check_16bytes"))) { + aot_set_last_error("llvm build load failed"); + return false; + } + } + return true; } @@ -676,6 +705,11 @@ aot_create_func_context(AOTCompData *comp_data, AOTCompContext *comp_ctx, case VALUE_TYPE_F64: local_value = F64_ZERO; break; +#if WASM_ENABLE_SIMD != 0 + case VALUE_TYPE_V128: + local_value = V128_ZERO; + break; +#endif default: bh_assert(0); break; @@ -814,23 +848,55 @@ aot_set_llvm_basic_types(AOTLLVMTypes *basic_types, LLVMContextRef context) basic_types->float32_ptr_type = LLVMPointerType(basic_types->float32_type, 0); basic_types->float64_ptr_type = LLVMPointerType(basic_types->float64_type, 0); + basic_types->i8x16_vec_type = LLVMVectorType(basic_types->int8_type, 16); + basic_types->i16x8_vec_type = LLVMVectorType(basic_types->int16_type, 8); + basic_types->i32x4_vec_type = LLVMVectorType(basic_types->int32_type, 4); + basic_types->i64x2_vec_type = LLVMVectorType(basic_types->int64_type, 2); + basic_types->f32x4_vec_type = LLVMVectorType(basic_types->float32_type, 4); + basic_types->f64x2_vec_type = LLVMVectorType(basic_types->float64_type, 2); + + basic_types->v128_type = basic_types->i64x2_vec_type; + basic_types->v128_ptr_type = LLVMPointerType(basic_types->v128_type, 0); + return (basic_types->int8_ptr_type && basic_types->int16_ptr_type && basic_types->int32_ptr_type && basic_types->int64_ptr_type && basic_types->float32_ptr_type && basic_types->float64_ptr_type + && basic_types->i8x16_vec_type + && basic_types->i16x8_vec_type + && basic_types->i32x4_vec_type + && basic_types->i64x2_vec_type + && basic_types->f32x4_vec_type + && basic_types->f64x2_vec_type && basic_types->meta_data_type) ? true : false; } static bool aot_create_llvm_consts(AOTLLVMConsts *consts, AOTCompContext *comp_ctx) { + LLVMValueRef i64_consts[2]; + consts->i8_zero = I8_CONST(0); consts->i32_zero = I32_CONST(0); consts->i64_zero = I64_CONST(0); consts->f32_zero = F32_CONST(0); consts->f64_zero = F64_CONST(0); + + if (consts->i64_zero) { + i64_consts[0] = i64_consts[1] = consts->i64_zero; + consts->v128_zero = consts->i64x2_vec_zero = + LLVMConstVector(i64_consts, 2); + if (consts->i64x2_vec_zero) { + consts->i8x16_vec_zero = TO_V128_i8x16(consts->i64x2_vec_zero); + consts->i16x8_vec_zero = TO_V128_i16x8(consts->i64x2_vec_zero); + consts->i32x4_vec_zero = TO_V128_i32x4(consts->i64x2_vec_zero); + consts->f32x4_vec_zero = TO_V128_f32x4(consts->i64x2_vec_zero); + consts->f64x2_vec_zero = TO_V128_f64x2(consts->i64x2_vec_zero); + } + } + consts->i32_one = I32_CONST(1); consts->i32_two = I32_CONST(2); consts->i32_three = I32_CONST(3); @@ -850,6 +916,12 @@ aot_create_llvm_consts(AOTLLVMConsts *consts, AOTCompContext *comp_ctx) && consts->i64_zero && consts->f32_zero && consts->f64_zero + && consts->i8x16_vec_zero + && consts->i16x8_vec_zero + && consts->i32x4_vec_zero + && consts->i64x2_vec_zero + && consts->f32x4_vec_zero + && consts->f64x2_vec_zero && consts->i32_one && consts->i32_two && consts->i32_three @@ -1014,7 +1086,7 @@ aot_create_comp_context(AOTCompData *comp_data, /*LLVMTypeRef elem_types[8];*/ struct LLVMMCJITCompilerOptions jit_options; LLVMTargetRef target; - char *triple = NULL, *triple_jit = NULL, *triple_norm, *arch, *abi; + char *triple = NULL, *triple_norm, *arch, *abi; char *cpu = NULL, *features, buf[128]; char *triple_norm_new = NULL, *cpu_new = NULL; char *err = NULL, *fp_round= "round.tonearest", *fp_exce = "fpexcept.strict"; @@ -1065,7 +1137,12 @@ aot_create_comp_context(AOTCompData *comp_data, if (option->enable_tail_call) comp_ctx->enable_tail_call = true; + if (option->enable_simd) + comp_ctx->enable_simd = true; + if (option->is_jit_mode) { + char *triple_jit = NULL; + /* Create LLVM execution engine */ LLVMInitializeMCJITCompilerOptions(&jit_options, sizeof(jit_options)); jit_options.OptLevel = LLVMCodeGenLevelAggressive; @@ -1186,7 +1263,8 @@ aot_create_comp_context(AOTCompData *comp_data, if (!cpu) cpu = ""; } - else { /* triple is NULL, cpu isn't NULL */ + else { + /* triple is NULL, cpu isn't NULL */ snprintf(buf, sizeof(buf), "target isn't specified for cpu %s.", cpu); aot_set_last_error(buf); @@ -1283,6 +1361,23 @@ aot_create_comp_context(AOTCompData *comp_data, } } + if (option->enable_simd) { + char *tmp; + bool ret; + + if (!(tmp = LLVMGetTargetMachineCPU(comp_ctx->target_machine))) { + aot_set_last_error("get CPU from Target Machine fail"); + goto fail; + } + + ret = aot_check_simd_compatibility(comp_ctx->target_arch, tmp); + LLVMDisposeMessage(tmp); + if (!ret) { + aot_set_last_error("SIMD compatibility check failed"); + goto fail; + } + } + if (!(target_data_ref = LLVMCreateTargetDataLayout(comp_ctx->target_machine))) { aot_set_last_error("create LLVM target data layout failed."); @@ -1349,11 +1444,13 @@ aot_create_comp_context(AOTCompData *comp_data, fail: if (triple_norm_new) LLVMDisposeMessage(triple_norm_new); + if (cpu_new) LLVMDisposeMessage(cpu_new); if (!ret) aot_destroy_comp_context(comp_ctx); + return ret; } @@ -1567,3 +1664,144 @@ aot_checked_addr_list_destroy(AOTFuncContext *func_ctx) func_ctx->checked_addr_list = NULL; } +bool +aot_build_zero_function_ret(AOTCompContext *comp_ctx, + AOTFuncType *func_type) +{ + LLVMValueRef ret = NULL; + + if (func_type->result_count) { + switch (func_type->types[func_type->param_count]) { + case VALUE_TYPE_I32: + ret = LLVMBuildRet(comp_ctx->builder, I32_ZERO); + break; + case VALUE_TYPE_I64: + ret = LLVMBuildRet(comp_ctx->builder, I64_ZERO); + break; + case VALUE_TYPE_F32: + ret = LLVMBuildRet(comp_ctx->builder, F32_ZERO); + break; + case VALUE_TYPE_F64: + ret = LLVMBuildRet(comp_ctx->builder, F64_ZERO); + break; +#if WASM_ENABLE_SIMD != 0 + case VALUE_TYPE_V128: + ret = LLVMBuildRet(comp_ctx->builder, V128_ZERO); + break; +#endif + default: + bh_assert(0); + } + } + else { + ret = LLVMBuildRetVoid(comp_ctx->builder); + } + + if (!ret) { + aot_set_last_error("llvm build ret failed."); + return false; + } + return true; +} + +static LLVMValueRef +__call_llvm_intrinsic(const AOTCompContext *comp_ctx, + const char *name, + LLVMTypeRef ret_type, + LLVMTypeRef *param_types, + int param_count, + LLVMValueRef *param_values) +{ + LLVMValueRef func, ret; + LLVMTypeRef func_type; + + /* Declare llvm intrinsic function if necessary */ + if (!(func = LLVMGetNamedFunction(comp_ctx->module, name))) { + if (!(func_type = LLVMFunctionType(ret_type, param_types, + (uint32)param_count, false))) { + aot_set_last_error("create LLVM function type failed."); + return NULL; + } + + if (!(func = LLVMAddFunction(comp_ctx->module, name, func_type))) { + aot_set_last_error("add LLVM function failed."); + return NULL; + } + } + + /* Call the LLVM intrinsic function */ + if (!(ret = LLVMBuildCall(comp_ctx->builder, func, param_values, + (uint32)param_count, "call"))) { + aot_set_last_error("llvm build call failed."); + return NULL; + } + + return ret; +} + +LLVMValueRef +aot_call_llvm_intrinsic(const AOTCompContext *comp_ctx, + const char *name, + LLVMTypeRef ret_type, + LLVMTypeRef *param_types, + int param_count, + ...) +{ + LLVMValueRef *param_values, ret; + va_list argptr; + uint64 total_size; + int i = 0; + + /* Create param values */ + total_size = sizeof(LLVMValueRef) * (uint64)param_count; + if (total_size >= UINT32_MAX + || !(param_values = wasm_runtime_malloc((uint32)total_size))) { + aot_set_last_error("allocate memory for param values failed."); + return false; + } + + /* Load each param value */ + va_start(argptr, param_count); + while (i < param_count) + param_values[i++] = va_arg(argptr, LLVMValueRef); + va_end(argptr); + + ret = __call_llvm_intrinsic(comp_ctx, name, ret_type, param_types, + param_count, param_values); + + wasm_runtime_free(param_values); + + return ret; +} + +LLVMValueRef +aot_call_llvm_intrinsic_v(const AOTCompContext *comp_ctx, + const char *name, + LLVMTypeRef ret_type, + LLVMTypeRef *param_types, + int param_count, + va_list param_value_list) +{ + LLVMValueRef *param_values, ret; + uint64 total_size; + int i = 0; + + /* Create param values */ + total_size = sizeof(LLVMValueRef) * (uint64)param_count; + if (total_size >= UINT32_MAX + || !(param_values = wasm_runtime_malloc((uint32)total_size))) { + aot_set_last_error("allocate memory for param values failed."); + return false; + } + + /* Load each param value */ + while (i < param_count) + param_values[i++] = va_arg(param_value_list, LLVMValueRef); + + ret = __call_llvm_intrinsic(comp_ctx, name, ret_type, param_types, + param_count, param_values); + + wasm_runtime_free(param_values); + + return ret; +} diff --git a/core/iwasm/compilation/aot_llvm.h b/core/iwasm/compilation/aot_llvm.h index c15db867c..3da5ea98e 100644 --- a/core/iwasm/compilation/aot_llvm.h +++ b/core/iwasm/compilation/aot_llvm.h @@ -106,6 +106,7 @@ typedef struct AOTMemInfo { LLVMValueRef mem_bound_check_2bytes; LLVMValueRef mem_bound_check_4bytes; LLVMValueRef mem_bound_check_8bytes; + LLVMValueRef mem_bound_check_16bytes; } AOTMemInfo; typedef struct AOTFuncContext { @@ -152,6 +153,15 @@ typedef struct AOTLLVMTypes { LLVMTypeRef float32_ptr_type; LLVMTypeRef float64_ptr_type; + LLVMTypeRef v128_type; + LLVMTypeRef v128_ptr_type; + LLVMTypeRef i8x16_vec_type; + LLVMTypeRef i16x8_vec_type; + LLVMTypeRef i32x4_vec_type; + LLVMTypeRef i64x2_vec_type; + LLVMTypeRef f32x4_vec_type; + LLVMTypeRef f64x2_vec_type; + LLVMTypeRef meta_data_type; } AOTLLVMTypes; @@ -161,6 +171,13 @@ typedef struct AOTLLVMConsts { LLVMValueRef i64_zero; LLVMValueRef f32_zero; LLVMValueRef f64_zero; + LLVMValueRef v128_zero; + LLVMValueRef i8x16_vec_zero; + LLVMValueRef i16x8_vec_zero; + LLVMValueRef i32x4_vec_zero; + LLVMValueRef i64x2_vec_zero; + LLVMValueRef f32x4_vec_zero; + LLVMValueRef f64x2_vec_zero; LLVMValueRef i32_one; LLVMValueRef i32_two; LLVMValueRef i32_three; @@ -201,6 +218,9 @@ typedef struct AOTCompContext { /* Bounday Check */ bool enable_bound_check; + /* 128-bit SIMD */ + bool enable_simd; + /* Thread Manager */ bool enable_thread_mgr; @@ -248,6 +268,7 @@ typedef struct AOTCompOption{ bool enable_bulk_memory; bool enable_thread_mgr; bool enable_tail_call; + bool enable_simd; bool is_sgx_platform; uint32 opt_level; uint32 size_level; @@ -309,6 +330,29 @@ aot_checked_addr_list_find(AOTFuncContext *func_ctx, void aot_checked_addr_list_destroy(AOTFuncContext *func_ctx); +bool +aot_build_zero_function_ret(AOTCompContext *comp_ctx, + AOTFuncType *func_type); + +LLVMValueRef +aot_call_llvm_intrinsic(const AOTCompContext *comp_ctx, + const char *name, + LLVMTypeRef ret_type, + LLVMTypeRef *param_types, + int param_count, + ...); + +LLVMValueRef +aot_call_llvm_intrinsic_v(const AOTCompContext *comp_ctx, + const char *name, + LLVMTypeRef ret_type, + LLVMTypeRef *param_types, + int param_count, + va_list param_value_list); + +bool +aot_check_simd_compatibility(const char *arch_c_str, const char *cpu_c_str); + #ifdef __cplusplus } /* end of extern "C" */ #endif diff --git a/core/iwasm/compilation/simd/simd_access_lanes.c b/core/iwasm/compilation/simd/simd_access_lanes.c new file mode 100644 index 000000000..4778d6368 --- /dev/null +++ b/core/iwasm/compilation/simd/simd_access_lanes.c @@ -0,0 +1,381 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "simd_access_lanes.h" +#include "simd_common.h" +#include "../aot_emit_exception.h" +#include "../../aot/aot_runtime.h" + +static LLVMValueRef +build_intx16_vector(const AOTCompContext *comp_ctx, + const LLVMTypeRef element_type, + const int *element_value) +{ + LLVMValueRef vector, elements[16]; + unsigned i; + + for (i = 0; i < 16; i++) { + if (!(elements[i] = + LLVMConstInt(element_type, element_value[i], true))) { + HANDLE_FAILURE("LLVMConstInst"); + goto fail; + } + } + + if (!(vector = LLVMConstVector(elements, 16))) { + HANDLE_FAILURE("LLVMConstVector"); + goto fail; + } + + return vector; +fail: + return NULL; +} + +bool +aot_compile_simd_shuffle(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + const uint8 *frame_ip) +{ + LLVMValueRef vec1, vec2, mask, result; + uint8 imm[16] = { 0 }; + int values[16]; + unsigned i; + + wasm_runtime_read_v128(frame_ip, (uint64 *)imm, (uint64 *)(imm + 8)); + for (i = 0; i < 16; i++) { + values[i] = imm[i]; + } + + if (!(vec2 = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, V128_i8x16_TYPE, + "vec2"))) { + goto fail; + } + + if (!(vec1 = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, V128_i8x16_TYPE, + "vec1"))) { + goto fail; + } + + /* build a vector <16 x i32> */ + if (!(mask = build_intx16_vector(comp_ctx, I32_TYPE, values))) { + goto fail; + } + + if (!(result = LLVMBuildShuffleVector(comp_ctx->builder, vec1, vec2, mask, + "new_vector"))) { + HANDLE_FAILURE("LLVMBuildShuffleVector"); + goto fail; + } + + if (!(result = LLVMBuildBitCast(comp_ctx->builder, result, V128_i64x2_TYPE, + "ret"))) { + HANDLE_FAILURE("LLVMBuildBitCast"); + goto fail; + } + + PUSH_V128(result); + + return true; +fail: + return false; +} + +// TODO: instructions for other CPUs +/* shufflevector is not an option, since it requires *mask as a const */ +bool +aot_compile_simd_swizzle(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) +{ + LLVMValueRef vector, mask, max_lanes, condition, mask_lanes, result; + LLVMTypeRef param_types[2]; + int max_lane_id[16] = { 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16 }, + mask_lane_id[16] = { 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 }; + + if (!(mask = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, V128_i8x16_TYPE, + "mask"))) { + goto fail; + } + + if (!(vector = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, + V128_i8x16_TYPE, "vec"))) { + goto fail; + } + + /* icmp uge <16 x i8> mask, <16, 16, 16, 16, ...> */ + if (!(max_lanes = build_intx16_vector(comp_ctx, INT8_TYPE, max_lane_id))) { + goto fail; + } + + if (!(condition = LLVMBuildICmp(comp_ctx->builder, LLVMIntUGE, mask, + max_lanes, "compare_with_16"))) { + HANDLE_FAILURE("LLVMBuldICmp"); + goto fail; + } + + /* if the highest bit of every i8 of mask is 1, means doesn't pick up from vector */ + /* select <16 x i1> %condition, <16 x i8> <0x80, 0x80, ...>, <16 x i8> %mask */ + if (!(mask_lanes = + build_intx16_vector(comp_ctx, INT8_TYPE, mask_lane_id))) { + goto fail; + } + + if (!(mask = LLVMBuildSelect(comp_ctx->builder, condition, mask_lanes, + mask, "mask"))) { + HANDLE_FAILURE("LLVMBuildSelect"); + goto fail; + } + + param_types[0] = V128_i8x16_TYPE; + param_types[1] = V128_i8x16_TYPE; + if (!(result = aot_call_llvm_intrinsic( + comp_ctx, "llvm.x86.ssse3.pshuf.b.128", V128_i8x16_TYPE, + param_types, 2, vector, mask))) { + HANDLE_FAILURE("LLVMBuildCall"); + goto fail; + } + + if (!(result = LLVMBuildBitCast(comp_ctx->builder, result, V128_i64x2_TYPE, + "ret"))) { + HANDLE_FAILURE("LLVMBuildBitCast"); + goto fail; + } + + PUSH_V128(result); + + return true; +fail: + return false; +} + +static bool +aot_compile_simd_extract(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + uint8 lane_id, + bool need_extend, + bool is_signed, + LLVMTypeRef vector_type, + LLVMTypeRef result_type, + unsigned aot_value_type) +{ + LLVMValueRef vector, idx, result; + + if (!(idx = I8_CONST(lane_id))) { + HANDLE_FAILURE("LLVMConstInt"); + goto fail; + } + + /* bitcast <2 x i64> %0 to */ + if (!(vector = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type, + "vec"))) { + goto fail; + } + + /* extractelement %vector, i8 lane_id*/ + if (!(result = LLVMBuildExtractElement(comp_ctx->builder, vector, idx, + "element"))) { + HANDLE_FAILURE("LLVMBuildExtractElement"); + goto fail; + } + + if (need_extend) { + if (is_signed) { + /* sext %element to */ + if (!(result = LLVMBuildSExt(comp_ctx->builder, result, + result_type, "ret"))) { + HANDLE_FAILURE("LLVMBuildSExt"); + goto fail; + } + } + else { + /* sext %element to */ + if (!(result = LLVMBuildZExt(comp_ctx->builder, result, + result_type, "ret"))) { + HANDLE_FAILURE("LLVMBuildZExt"); + goto fail; + } + } + } + + PUSH(result, aot_value_type); + + return true; +fail: + return false; +} + +bool +aot_compile_simd_extract_i8x16(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + uint8 lane_id, + bool is_signed) +{ + return aot_compile_simd_extract(comp_ctx, func_ctx, lane_id, true, + is_signed, V128_i8x16_TYPE, I32_TYPE, + VALUE_TYPE_I32); +} + +bool +aot_compile_simd_extract_i16x8(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + uint8 lane_id, + bool is_signed) +{ + return aot_compile_simd_extract(comp_ctx, func_ctx, lane_id, true, + is_signed, V128_i16x8_TYPE, I32_TYPE, + VALUE_TYPE_I32); +} + +bool +aot_compile_simd_extract_i32x4(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + uint8 lane_id) +{ + return aot_compile_simd_extract(comp_ctx, func_ctx, lane_id, false, false, + V128_i32x4_TYPE, I32_TYPE, VALUE_TYPE_I32); +} + +bool +aot_compile_simd_extract_i64x2(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + uint8 lane_id) +{ + return aot_compile_simd_extract(comp_ctx, func_ctx, lane_id, false, false, + V128_i64x2_TYPE, I64_TYPE, VALUE_TYPE_I64); +} + +bool +aot_compile_simd_extract_f32x4(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + uint8 lane_id) +{ + return aot_compile_simd_extract(comp_ctx, func_ctx, lane_id, false, false, + V128_f32x4_TYPE, F32_TYPE, VALUE_TYPE_F32); +} + +bool +aot_compile_simd_extract_f64x2(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + uint8 lane_id) +{ + return aot_compile_simd_extract(comp_ctx, func_ctx, lane_id, false, false, + V128_f64x2_TYPE, F64_TYPE, VALUE_TYPE_F64); +} + +static bool +aot_compile_simd_replace(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + uint8 lane_id, + unsigned new_value_type, + LLVMTypeRef vector_type, + bool need_reduce, + LLVMTypeRef element_type) +{ + LLVMValueRef vector, new_value, idx, result; + + POP(new_value, new_value_type); + + if (!(idx = I8_CONST(lane_id))) { + HANDLE_FAILURE("LLVMConstInt"); + goto fail; + } + + /* bitcast <2 x i64> %0 to */ + + if (!(vector = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type, + "vec"))) { + goto fail; + } + + /* bitcast to */ + if (need_reduce) { + if (!(new_value = LLVMBuildTrunc(comp_ctx->builder, new_value, + element_type, "element"))) { + HANDLE_FAILURE("LLVMBuildTrunc"); + goto fail; + } + } + + /* insertelement %vector, %element, i8 idx */ + if (!(result = LLVMBuildInsertElement(comp_ctx->builder, vector, new_value, + idx, "new_vector"))) { + HANDLE_FAILURE("LLVMBuildInsertElement"); + goto fail; + } + + /* bitcast %result to <2 x i64> */ + if (!(result = LLVMBuildBitCast(comp_ctx->builder, result, V128_i64x2_TYPE, + "ret"))) { + HANDLE_FAILURE("LLVMBuildBitCast"); + goto fail; + } + + PUSH_V128(result); + + return true; +fail: + return false; +} + +bool +aot_compile_simd_replace_i8x16(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + uint8 lane_id) +{ + return aot_compile_simd_replace(comp_ctx, func_ctx, lane_id, + VALUE_TYPE_I32, V128_i8x16_TYPE, true, + INT8_TYPE); +} + +bool +aot_compile_simd_replace_i16x8(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + uint8 lane_id) +{ + return aot_compile_simd_replace(comp_ctx, func_ctx, lane_id, + VALUE_TYPE_I32, V128_i16x8_TYPE, true, + INT16_TYPE); +} + +bool +aot_compile_simd_replace_i32x4(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + uint8 lane_id) +{ + return aot_compile_simd_replace(comp_ctx, func_ctx, lane_id, + VALUE_TYPE_I32, V128_i32x4_TYPE, false, + I32_TYPE); +} + +bool +aot_compile_simd_replace_i64x2(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + uint8 lane_id) +{ + return aot_compile_simd_replace(comp_ctx, func_ctx, lane_id, + VALUE_TYPE_I64, V128_i64x2_TYPE, false, + I64_TYPE); +} + +bool +aot_compile_simd_replace_f32x4(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + uint8 lane_id) +{ + return aot_compile_simd_replace(comp_ctx, func_ctx, lane_id, + VALUE_TYPE_F32, V128_f32x4_TYPE, false, + F32_TYPE); +} + +bool +aot_compile_simd_replace_f64x2(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + uint8 lane_id) +{ + return aot_compile_simd_replace(comp_ctx, func_ctx, lane_id, + VALUE_TYPE_F64, V128_f64x2_TYPE, false, + F64_TYPE); +} diff --git a/core/iwasm/compilation/simd/simd_access_lanes.h b/core/iwasm/compilation/simd/simd_access_lanes.h new file mode 100644 index 000000000..ae90242df --- /dev/null +++ b/core/iwasm/compilation/simd/simd_access_lanes.h @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _SIMD_ACCESS_LANES_H_ +#define _SIMD_ACCESS_LANES_H_ + +#include "../aot_compiler.h" + +#ifdef __cplusplus +extern "C" { +#endif + +bool +aot_compile_simd_shuffle(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + const uint8 *frame_ip); + +bool +aot_compile_simd_swizzle(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx); + +bool +aot_compile_simd_extract_i8x16(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + uint8 lane_id, + bool is_signed); + +bool +aot_compile_simd_extract_i16x8(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + uint8 lane_id, + bool is_signed); + +bool +aot_compile_simd_extract_i32x4(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + uint8 lane_id); + +bool +aot_compile_simd_extract_i64x2(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + uint8 lane_id); + +bool +aot_compile_simd_extract_f32x4(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + uint8 lane_id); + +bool +aot_compile_simd_extract_f64x2(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + uint8 lane_id); + +bool +aot_compile_simd_replace_i8x16(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + uint8 lane_id); + +bool +aot_compile_simd_replace_i16x8(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + uint8 lane_id); + +bool +aot_compile_simd_replace_i32x4(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + uint8 lane_id); + +bool +aot_compile_simd_replace_i64x2(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + uint8 lane_id); + +bool +aot_compile_simd_replace_f32x4(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + uint8 lane_id); + +bool +aot_compile_simd_replace_f64x2(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + uint8 lane_id); + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif + +#endif /* end of _SIMD_ACCESS_LANES_H_ */ diff --git a/core/iwasm/compilation/simd/simd_bit_shifts.c b/core/iwasm/compilation/simd/simd_bit_shifts.c new file mode 100644 index 000000000..5b1ee9024 --- /dev/null +++ b/core/iwasm/compilation/simd/simd_bit_shifts.c @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "simd_bit_shifts.h" +#include "simd_common.h" +#include "../aot_emit_exception.h" +#include "../../aot/aot_runtime.h" + +static bool +simd_shift(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + IntShift shift_op, + LLVMTypeRef vector_type, + LLVMTypeRef element_type, + unsigned lane_width) +{ + LLVMValueRef vector, offset, width, undef, zeros, result; + LLVMTypeRef zeros_type; + + POP_I32(offset); + + if (!(vector = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type, + "vec"))) { + goto fail; + } + + if (!(width = LLVMConstInt(I32_TYPE, lane_width, true))) { + HANDLE_FAILURE("LLVMConstInt"); + goto fail; + } + + if (!(offset = + LLVMBuildURem(comp_ctx->builder, offset, width, "remainder"))) { + HANDLE_FAILURE("LLVMBuildURem"); + goto fail; + } + + if (I64_TYPE == element_type) { + if (!(offset = LLVMBuildZExt(comp_ctx->builder, offset, element_type, + "offset_scalar"))) { + HANDLE_FAILURE("LLVMBuildZExt"); + goto fail; + } + } + else { + if (!(offset = LLVMBuildTruncOrBitCast( + comp_ctx->builder, offset, element_type, "offset_scalar"))) { + HANDLE_FAILURE("LLVMBuildTrunc"); + goto fail; + } + } + + /* create a vector with offset */ + if (!(undef = LLVMGetUndef(vector_type))) { + HANDLE_FAILURE("LLVMGetUndef"); + goto fail; + } + + if (!(zeros_type = LLVMVectorType(I32_TYPE, 128 / lane_width))) { + HANDLE_FAILURE("LVMVectorType"); + goto fail; + } + + if (!(zeros = LLVMConstNull(zeros_type))) { + HANDLE_FAILURE("LLVMConstNull"); + goto fail; + } + + if (!(offset = LLVMBuildInsertElement(comp_ctx->builder, undef, offset, + I32_ZERO, "base_vector"))) { + HANDLE_FAILURE("LLVMBuildInsertElement"); + goto fail; + } + + if (!(offset = LLVMBuildShuffleVector(comp_ctx->builder, offset, undef, + zeros, "offset_vector"))) { + HANDLE_FAILURE("LLVMBuildShuffleVector"); + goto fail; + } + + switch (shift_op) { + case INT_SHL: + { + if (!(result = + LLVMBuildShl(comp_ctx->builder, vector, offset, "shl"))) { + HANDLE_FAILURE("LLVMBuildShl"); + goto fail; + } + break; + } + case INT_SHR_S: + { + if (!(result = LLVMBuildAShr(comp_ctx->builder, vector, offset, + "ashr"))) { + HANDLE_FAILURE("LLVMBuildAShr"); + goto fail; + } + break; + } + case INT_SHR_U: + { + if (!(result = LLVMBuildLShr(comp_ctx->builder, vector, offset, + "lshr"))) { + HANDLE_FAILURE("LLVMBuildLShr"); + goto fail; + } + break; + } + default: + { + bh_assert(0); + goto fail; + } + } + + if (!(result = LLVMBuildBitCast(comp_ctx->builder, result, V128_i64x2_TYPE, + "result"))) { + HANDLE_FAILURE("LLVMBuildBitCast"); + goto fail; + } + + PUSH_V128(result); + return true; +fail: + return false; +} + +bool +aot_compile_simd_i8x16_shift(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + IntShift shift_op) +{ + return simd_shift(comp_ctx, func_ctx, shift_op, V128_i8x16_TYPE, INT8_TYPE, + 8); +} + +bool +aot_compile_simd_i16x8_shift(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + IntShift shift_op) +{ + return simd_shift(comp_ctx, func_ctx, shift_op, V128_i16x8_TYPE, + INT16_TYPE, 16); +} + +bool +aot_compile_simd_i32x4_shift(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + IntShift shift_op) +{ + return simd_shift(comp_ctx, func_ctx, shift_op, V128_i32x4_TYPE, I32_TYPE, + 32); +} + +bool +aot_compile_simd_i64x2_shift(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + IntShift shift_op) +{ + return simd_shift(comp_ctx, func_ctx, shift_op, V128_i64x2_TYPE, I64_TYPE, + 64); +} diff --git a/core/iwasm/compilation/simd/simd_bit_shifts.h b/core/iwasm/compilation/simd/simd_bit_shifts.h new file mode 100644 index 000000000..503406079 --- /dev/null +++ b/core/iwasm/compilation/simd/simd_bit_shifts.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _SIMD_BIT_SHIFTS_H_ +#define _SIMD_BIT_SHIFTS_H_ + +#include "../aot_compiler.h" + +#ifdef __cplusplus +extern "C" { +#endif + +bool +aot_compile_simd_i8x16_shift(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + IntShift shift_op); + +bool +aot_compile_simd_i16x8_shift(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + IntShift shift_op); + +bool +aot_compile_simd_i32x4_shift(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + IntShift shift_op); + +bool +aot_compile_simd_i64x2_shift(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + IntShift shift_op); + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif + +#endif /* end of _SIMD_BIT_SHIFTS_H_ */ diff --git a/core/iwasm/compilation/simd/simd_bitmask_extracts.c b/core/iwasm/compilation/simd/simd_bitmask_extracts.c new file mode 100644 index 000000000..79565cfc2 --- /dev/null +++ b/core/iwasm/compilation/simd/simd_bitmask_extracts.c @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "simd_bitmask_extracts.h" +#include "simd_common.h" +#include "../aot_emit_exception.h" +#include "../../aot/aot_runtime.h" + +static bool +simd_build_bitmask(const AOTCompContext *comp_ctx, + const AOTFuncContext *func_ctx, + uint8 length, + LLVMTypeRef vector_type, + LLVMTypeRef element_type, + const char *intrinsic) +{ + LLVMValueRef vector, zeros, mask, mask_elements[16], cond, result; + LLVMTypeRef param_types[1], vector_ext_type; + const uint32 numbers[16] = { 0x1, 0x2, 0x4, 0x8, 0x10, 0x20, + 0x40, 0x80, 0x100, 0x200, 0x400, 0x800, + 0x1000, 0x2000, 0x4000, 0x8000 }; + uint8 i; + + if (!(vector = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type, + "vec"))) { + goto fail; + } + + if (!(vector_ext_type = LLVMVectorType(I32_TYPE, length))) { + HANDLE_FAILURE("LLVMVectorType"); + goto fail; + } + + if (!(vector = LLVMBuildSExt(comp_ctx->builder, vector, vector_ext_type, + "vec_ext"))) { + HANDLE_FAILURE("LLVMBuildSExt"); + goto fail; + } + + if (!(zeros = LLVMConstNull(vector_ext_type))) { + HANDLE_FAILURE("LLVMConstNull"); + goto fail; + } + + for (i = 0; i < 16; i++) { + if (!(mask_elements[i] = LLVMConstInt(I32_TYPE, numbers[i], false))) { + HANDLE_FAILURE("LLVMConstInt"); + goto fail; + } + } + + if (!(mask = LLVMConstVector(mask_elements, length))) { + HANDLE_FAILURE("LLVMConstVector"); + goto fail; + } + + if (!(cond = LLVMBuildICmp(comp_ctx->builder, LLVMIntSLT, vector, zeros, + "lt_zero"))) { + HANDLE_FAILURE("LLVMBuildICmp"); + goto fail; + } + + if (!(result = + LLVMBuildSelect(comp_ctx->builder, cond, mask, zeros, "select"))) { + HANDLE_FAILURE("LLVMBuildSelect"); + goto fail; + } + + param_types[0] = vector_ext_type; + if (!(result = aot_call_llvm_intrinsic(comp_ctx, intrinsic, I32_TYPE, + param_types, 1, result))) { + HANDLE_FAILURE("LLVMBuildCall"); + goto fail; + } + + PUSH_I32(result); + + return true; +fail: + return false; +} + +bool +aot_compile_simd_i8x16_bitmask(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx) +{ + return simd_build_bitmask(comp_ctx, func_ctx, 16, V128_i8x16_TYPE, + INT8_TYPE, + "llvm.experimental.vector.reduce.or.v16i32"); +} + +bool +aot_compile_simd_i16x8_bitmask(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx) +{ + return simd_build_bitmask(comp_ctx, func_ctx, 8, V128_i16x8_TYPE, + INT16_TYPE, + "llvm.experimental.vector.reduce.or.v8i32"); +} + +bool +aot_compile_simd_i32x4_bitmask(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx) +{ + return simd_build_bitmask(comp_ctx, func_ctx, 4, V128_i32x4_TYPE, I32_TYPE, + "llvm.experimental.vector.reduce.or.v4i32"); +} diff --git a/core/iwasm/compilation/simd/simd_bitmask_extracts.h b/core/iwasm/compilation/simd/simd_bitmask_extracts.h new file mode 100644 index 000000000..b8cd5e86f --- /dev/null +++ b/core/iwasm/compilation/simd/simd_bitmask_extracts.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _SIMD_BITMASK_EXTRACTS_H_ +#define _SIMD_BITMASK_EXTRACTS_H_ + +#include "../aot_compiler.h" + +#ifdef __cplusplus +extern "C" { +#endif + +bool +aot_compile_simd_i8x16_bitmask(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx); + +bool +aot_compile_simd_i16x8_bitmask(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx); + +bool +aot_compile_simd_i32x4_bitmask(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx); + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif + +#endif /* end of _SIMD_BITMASK_EXTRACTS_H_ */ + diff --git a/core/iwasm/compilation/simd/simd_bitwise_ops.c b/core/iwasm/compilation/simd/simd_bitwise_ops.c new file mode 100644 index 000000000..69e82bb85 --- /dev/null +++ b/core/iwasm/compilation/simd/simd_bitwise_ops.c @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "simd_bitwise_ops.h" +#include "../aot_emit_exception.h" +#include "../../aot/aot_runtime.h" + +static bool +v128_bitwise_two_component(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + V128Bitwise bitwise_op) +{ + LLVMValueRef vector1, vector2, result; + + POP_V128(vector2); + POP_V128(vector1); + + switch (bitwise_op) { + case V128_AND: + if (!(result = LLVMBuildAnd(comp_ctx->builder, vector1, vector2, + "and"))) { + HANDLE_FAILURE("LLVMBuildAnd"); + goto fail; + } + break; + case V128_OR: + if (!(result = + LLVMBuildOr(comp_ctx->builder, vector1, vector2, "or"))) { + HANDLE_FAILURE("LLVMBuildAnd"); + goto fail; + } + break; + case V128_XOR: + if (!(result = LLVMBuildXor(comp_ctx->builder, vector1, vector2, + "xor"))) { + HANDLE_FAILURE("LLVMBuildAnd"); + goto fail; + } + break; + case V128_ANDNOT: + { + /* v128.and(a, v128.not(b)) */ + if (!(vector2 = LLVMBuildNot(comp_ctx->builder, vector2, "not"))) { + HANDLE_FAILURE("LLVMBuildNot"); + goto fail; + } + + if (!(result = LLVMBuildAnd(comp_ctx->builder, vector1, vector2, + "and"))) { + HANDLE_FAILURE("LLVMBuildAnd"); + goto fail; + } + + break; + } + default: + bh_assert(0); + goto fail; + } + + PUSH_V128(result); + return true; +fail: + return false; +} + +static bool +v128_bitwise_not(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) +{ + LLVMValueRef vector, result; + + POP_V128(vector); + + if (!(result = LLVMBuildNot(comp_ctx->builder, vector, "not"))) { + HANDLE_FAILURE("LLVMBuildNot"); + goto fail; + } + + PUSH_V128(result); + return true; +fail: + return false; +} + +/* v128.or(v128.and(v1, c), v128.and(v2, v128.not(c))) */ +static bool +v128_bitwise_bit_select(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) +{ + LLVMValueRef vector1, vector2, vector3, result; + + POP_V128(vector3); + POP_V128(vector2); + POP_V128(vector1); + + if (!(vector1 = + LLVMBuildAnd(comp_ctx->builder, vector1, vector3, "a_and_c"))) { + HANDLE_FAILURE("LLVMBuildAdd"); + goto fail; + } + + if (!(vector3 = LLVMBuildNot(comp_ctx->builder, vector3, "not_c"))) { + HANDLE_FAILURE("LLVMBuildNot"); + goto fail; + } + + if (!(vector2 = + LLVMBuildAnd(comp_ctx->builder, vector2, vector3, "b_and_c"))) { + HANDLE_FAILURE("LLVMBuildAdd"); + goto fail; + } + + if (!(result = + LLVMBuildOr(comp_ctx->builder, vector1, vector2, "a_or_b"))) { + HANDLE_FAILURE("LLVMBuildOr"); + goto fail; + } + + PUSH_V128(result); + + return true; +fail: + return false; +} + +bool +aot_compile_simd_v128_bitwise(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + V128Bitwise bitwise_op) +{ + switch (bitwise_op) { + case V128_AND: + case V128_OR: + case V128_XOR: + case V128_ANDNOT: + return v128_bitwise_two_component(comp_ctx, func_ctx, bitwise_op); + case V128_NOT: + return v128_bitwise_not(comp_ctx, func_ctx); + case V128_BITSELECT: + return v128_bitwise_bit_select(comp_ctx, func_ctx); + default: + bh_assert(0); + return false; + } +} diff --git a/core/iwasm/compilation/simd/simd_bitwise_ops.h b/core/iwasm/compilation/simd/simd_bitwise_ops.h new file mode 100644 index 000000000..4717d0158 --- /dev/null +++ b/core/iwasm/compilation/simd/simd_bitwise_ops.h @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _SIMD_BITWISE_OPS_H_ +#define _SIMD_BITWISE_OPS_H_ + +#include "../aot_compiler.h" + +#ifdef __cplusplus +extern "C" { +#endif + +bool +aot_compile_simd_v128_bitwise(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + V128Bitwise bitwise_op); + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif + +#endif /* end of _SIMD_BITWISE_OPS_H_ */ diff --git a/core/iwasm/compilation/simd/simd_bool_reductions.c b/core/iwasm/compilation/simd/simd_bool_reductions.c new file mode 100644 index 000000000..c2abb3027 --- /dev/null +++ b/core/iwasm/compilation/simd/simd_bool_reductions.c @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "simd_bool_reductions.h" +#include "simd_common.h" +#include "../aot_emit_exception.h" +#include "../../aot/aot_runtime.h" + +static bool +simd_any_true(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + LLVMTypeRef vector_type, + LLVMTypeRef element_type, + const char *intrinsic) +{ + LLVMValueRef vector, zeros, non_zero, result; + + if (!(vector = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type, + "vec"))) { + goto fail; + } + + if (!(zeros = LLVMConstNull(vector_type))) { + HANDLE_FAILURE("LLVMConstNull"); + goto fail; + } + + /* icmp eq %vector, zeroinitialize */ + if (!(non_zero = LLVMBuildICmp(comp_ctx->builder, LLVMIntNE, vector, zeros, + "non_zero"))) { + HANDLE_FAILURE("LLVMBuildICmp"); + goto fail; + } + + /* zext to */ + if (!(non_zero = LLVMBuildZExt(comp_ctx->builder, non_zero, vector_type, + "non_zero_ex"))) { + HANDLE_FAILURE("LLVMBuildZExt"); + goto fail; + } + + if (!(result = aot_call_llvm_intrinsic(comp_ctx, intrinsic, element_type, + &vector_type, 1, non_zero))) { + HANDLE_FAILURE("LLVMBuildCall"); + goto fail; + } + + if (!(zeros = LLVMConstNull(element_type))) { + HANDLE_FAILURE("LLVMConstNull"); + goto fail; + } + + if (!(result = LLVMBuildICmp(comp_ctx->builder, LLVMIntNE, result, zeros, + "gt_zero"))) { + HANDLE_FAILURE("LLVMBuildICmp"); + goto fail; + } + + if (!(result = + LLVMBuildZExt(comp_ctx->builder, result, I32_TYPE, "ret"))) { + HANDLE_FAILURE("LLVMBuildZExt"); + goto fail; + } + + PUSH_I32(result); + + return true; +fail: + return false; +} + +bool +aot_compile_simd_i8x16_any_true(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx) +{ + return simd_any_true(comp_ctx, func_ctx, V128_i8x16_TYPE, INT8_TYPE, + "llvm.experimental.vector.reduce.add.v16i8"); +} + +bool +aot_compile_simd_i16x8_any_true(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx) +{ + return simd_any_true(comp_ctx, func_ctx, V128_i16x8_TYPE, INT16_TYPE, + "llvm.experimental.vector.reduce.add.v8i16"); +} + +bool +aot_compile_simd_i32x4_any_true(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx) +{ + return simd_any_true(comp_ctx, func_ctx, V128_i32x4_TYPE, I32_TYPE, + "llvm.experimental.vector.reduce.add.v4i32"); +} + +static bool +simd_all_true(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + LLVMTypeRef vector_type, + LLVMTypeRef element_type, + const char *intrinsic) +{ + LLVMValueRef vector, zeros, is_zero, result; + + if (!(vector = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type, + "vec"))) { + goto fail; + } + + if (!(zeros = LLVMConstNull(vector_type))) { + HANDLE_FAILURE("LLVMConstNull"); + goto fail; + } + + /* icmp eq %vector, zeroinitialize */ + if (!(is_zero = LLVMBuildICmp(comp_ctx->builder, LLVMIntEQ, vector, zeros, + "is_zero"))) { + HANDLE_FAILURE("LLVMBuildICmp"); + goto fail; + } + + /* zext to */ + if (!(is_zero = LLVMBuildZExt(comp_ctx->builder, is_zero, vector_type, + "is_zero_ex"))) { + HANDLE_FAILURE("LLVMBuildZExt"); + goto fail; + } + + if (!(result = aot_call_llvm_intrinsic(comp_ctx, intrinsic, element_type, + &vector_type, 1, is_zero))) { + HANDLE_FAILURE("LLVMBuildCall"); + goto fail; + } + + if (!(zeros = LLVMConstNull(element_type))) { + HANDLE_FAILURE("LLVMConstNull"); + goto fail; + } + + if (!(result = LLVMBuildICmp(comp_ctx->builder, LLVMIntEQ, result, zeros, + "none"))) { + HANDLE_FAILURE("LLVMBuildICmp"); + goto fail; + } + + if (!(result = + LLVMBuildZExt(comp_ctx->builder, result, I32_TYPE, "ret"))) { + HANDLE_FAILURE("LLVMBuildZExt"); + goto fail; + } + + PUSH_I32(result); + + return true; +fail: + return false; +} + +bool +aot_compile_simd_i8x16_all_true(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx) +{ + return simd_all_true(comp_ctx, func_ctx, V128_i8x16_TYPE, INT8_TYPE, + "llvm.experimental.vector.reduce.add.v16i8"); +} + +bool +aot_compile_simd_i16x8_all_true(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx) +{ + return simd_all_true(comp_ctx, func_ctx, V128_i16x8_TYPE, INT16_TYPE, + "llvm.experimental.vector.reduce.add.v8i16"); +} + +bool +aot_compile_simd_i32x4_all_true(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx) +{ + return simd_all_true(comp_ctx, func_ctx, V128_i32x4_TYPE, I32_TYPE, + "llvm.experimental.vector.reduce.add.v4i32"); +} diff --git a/core/iwasm/compilation/simd/simd_bool_reductions.h b/core/iwasm/compilation/simd/simd_bool_reductions.h new file mode 100644 index 000000000..e67f00e7e --- /dev/null +++ b/core/iwasm/compilation/simd/simd_bool_reductions.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _SIMD_BOOL_REDUCTIONS_H_ +#define _SIMD_BOOL_REDUCTIONS_H_ + +#include "../aot_compiler.h" + +#ifdef __cplusplus +extern "C" { +#endif + +bool +aot_compile_simd_i8x16_any_true(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx); + +bool +aot_compile_simd_i16x8_any_true(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx); + +bool +aot_compile_simd_i32x4_any_true(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx); + +bool +aot_compile_simd_i8x16_all_true(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx); + +bool +aot_compile_simd_i16x8_all_true(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx); + +bool +aot_compile_simd_i32x4_all_true(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx); + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif + +#endif /* end of _SIMD_BOOL_REDUCTIONS_H_ */ diff --git a/core/iwasm/compilation/simd/simd_common.c b/core/iwasm/compilation/simd/simd_common.c new file mode 100644 index 000000000..81378fa00 --- /dev/null +++ b/core/iwasm/compilation/simd/simd_common.c @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "simd_common.h" + +LLVMValueRef +simd_pop_v128_and_bitcast(const AOTCompContext *comp_ctx, + const AOTFuncContext *func_ctx, + LLVMTypeRef vec_type, + const char *name) +{ + LLVMValueRef number; + + POP_V128(number); + + if (!(number = + LLVMBuildBitCast(comp_ctx->builder, number, vec_type, name))) { + HANDLE_FAILURE("LLVMBuildBitCast"); + goto fail; + } + + return number; +fail: + return NULL; +} + +bool +simd_bitcast_and_push_v128(const AOTCompContext *comp_ctx, + const AOTFuncContext *func_ctx, + LLVMValueRef vector, + const char *name) +{ + if (!(vector = LLVMBuildBitCast(comp_ctx->builder, vector, V128_i64x2_TYPE, + name))) { + HANDLE_FAILURE("LLVMBuildBitCast"); + goto fail; + } + + /* push result into the stack */ + PUSH_V128(vector); + + return true; +fail: + return false; +} \ No newline at end of file diff --git a/core/iwasm/compilation/simd/simd_common.h b/core/iwasm/compilation/simd/simd_common.h new file mode 100644 index 000000000..5f029b01e --- /dev/null +++ b/core/iwasm/compilation/simd/simd_common.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _SIMD_COMMON_H_ +#define _SIMD_COMMON_H_ + +#include "../aot_compiler.h" + +LLVMValueRef +simd_pop_v128_and_bitcast(const AOTCompContext *comp_ctx, + const AOTFuncContext *func_ctx, + LLVMTypeRef vec_type, + const char *name); + +bool +simd_bitcast_and_push_v128(const AOTCompContext *comp_ctx, + const AOTFuncContext *func_ctx, + LLVMValueRef vector, + const char *name); + +#endif /* _SIMD_COMMON_H_ */ \ No newline at end of file diff --git a/core/iwasm/compilation/simd/simd_comparisons.c b/core/iwasm/compilation/simd/simd_comparisons.c new file mode 100644 index 000000000..9b95a85b8 --- /dev/null +++ b/core/iwasm/compilation/simd/simd_comparisons.c @@ -0,0 +1,231 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "simd_comparisons.h" +#include "simd_common.h" +#include "../aot_emit_exception.h" +#include "../../aot/aot_runtime.h" + +static bool +float_cond_2_predicate(FloatCond cond, LLVMRealPredicate *out) +{ + switch (cond) { + case FLOAT_EQ: + *out = LLVMRealOEQ; + break; + case FLOAT_NE: + *out = LLVMRealUNE; + break; + case FLOAT_LT: + *out = LLVMRealOLT; + break; + case FLOAT_GT: + *out = LLVMRealOGT; + break; + case FLOAT_LE: + *out = LLVMRealOLE; + break; + case FLOAT_GE: + *out = LLVMRealOGE; + break; + default: + bh_assert(0); + goto fail; + } + + return true; +fail: + return false; +} + +static bool +int_cond_2_predicate(IntCond cond, LLVMIntPredicate *out) +{ + switch (cond) { + case INT_EQZ: + case INT_EQ: + *out = LLVMIntEQ; + break; + case INT_NE: + *out = LLVMIntNE; + break; + case INT_LT_S: + *out = LLVMIntSLT; + break; + case INT_LT_U: + *out = LLVMIntULT; + break; + case INT_GT_S: + *out = LLVMIntSGT; + break; + case INT_GT_U: + *out = LLVMIntUGT; + break; + case INT_LE_S: + *out = LLVMIntSLE; + break; + case INT_LE_U: + *out = LLVMIntULE; + break; + case INT_GE_S: + *out = LLVMIntSGE; + break; + case INT_GE_U: + *out = LLVMIntUGE; + break; + default: + bh_assert(0); + goto fail; + } + + return true; +fail: + return false; +} + +static bool +interger_vector_compare(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + IntCond cond, + LLVMTypeRef vector_type) +{ + LLVMValueRef vec1, vec2, result; + LLVMIntPredicate int_pred; + + if (!(vec2 = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type, + "vec2"))) { + goto fail; + } + + if (!(vec1 = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type, + "vec1"))) { + goto fail; + } + + if (!int_cond_2_predicate(cond, &int_pred)) { + HANDLE_FAILURE("int_cond_2_predicate"); + goto fail; + } + /* icmp %vec1, %vec2 */ + if (!(result = + LLVMBuildICmp(comp_ctx->builder, int_pred, vec1, vec2, "cmp"))) { + HANDLE_FAILURE("LLVMBuildICmp"); + goto fail; + } + + /* sext %result to */ + if (!(result = + LLVMBuildSExt(comp_ctx->builder, result, vector_type, "ext"))) { + HANDLE_FAILURE("LLVMBuildSExt"); + goto fail; + } + + /* bitcast %result to <2 x i64> */ + if (!(result = LLVMBuildBitCast(comp_ctx->builder, result, V128_i64x2_TYPE, + "result"))) { + HANDLE_FAILURE("LLVMBuildBitCast"); + goto fail; + } + + PUSH_V128(result); + + return true; +fail: + return false; +} + +bool +aot_compile_simd_i8x16_compare(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + IntCond cond) +{ + return interger_vector_compare(comp_ctx, func_ctx, cond, V128_i8x16_TYPE); +} + +bool +aot_compile_simd_i16x8_compare(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + IntCond cond) +{ + return interger_vector_compare(comp_ctx, func_ctx, cond, V128_i16x8_TYPE); +} + +bool +aot_compile_simd_i32x4_compare(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + IntCond cond) +{ + return interger_vector_compare(comp_ctx, func_ctx, cond, V128_i32x4_TYPE); +} + +static bool +float_vector_compare(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + FloatCond cond, + LLVMTypeRef vector_type, + LLVMTypeRef result_type) +{ + LLVMValueRef vec1, vec2, result; + LLVMRealPredicate real_pred; + + if (!(vec2 = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type, + "vec2"))) { + goto fail; + } + + if (!(vec1 = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type, + "vec1"))) { + goto fail; + } + + if (!float_cond_2_predicate(cond, &real_pred)) { + HANDLE_FAILURE("float_cond_2_predicate"); + goto fail; + } + /* fcmp %vec1, %vec2 */ + if (!(result = + LLVMBuildFCmp(comp_ctx->builder, real_pred, vec1, vec2, "cmp"))) { + HANDLE_FAILURE("LLVMBuildFCmp"); + goto fail; + } + + /* sext %result to */ + if (!(result = + LLVMBuildSExt(comp_ctx->builder, result, result_type, "ext"))) { + HANDLE_FAILURE("LLVMBuildSExt"); + goto fail; + } + + /* bitcast %result to <2 x i64> */ + if (!(result = LLVMBuildBitCast(comp_ctx->builder, result, V128_i64x2_TYPE, + "result"))) { + HANDLE_FAILURE("LLVMBuildBitCast"); + goto fail; + } + + PUSH_V128(result); + + return true; +fail: + return false; +} + +bool +aot_compile_simd_f32x4_compare(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + FloatCond cond) +{ + return float_vector_compare(comp_ctx, func_ctx, cond, V128_f32x4_TYPE, + V128_i32x4_TYPE); +} + +bool +aot_compile_simd_f64x2_compare(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + FloatCond cond) +{ + return float_vector_compare(comp_ctx, func_ctx, cond, V128_f64x2_TYPE, + V128_i64x2_TYPE); +} diff --git a/core/iwasm/compilation/simd/simd_comparisons.h b/core/iwasm/compilation/simd/simd_comparisons.h new file mode 100644 index 000000000..46d816714 --- /dev/null +++ b/core/iwasm/compilation/simd/simd_comparisons.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _SIMD_COMPARISONS_H_ +#define _SIMD_COMPARISONS_H_ + +#include "../aot_compiler.h" + +#ifdef __cplusplus +extern "C" { +#endif + +bool +aot_compile_simd_i8x16_compare(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + IntCond cond); + +bool +aot_compile_simd_i16x8_compare(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + IntCond cond); + +bool +aot_compile_simd_i32x4_compare(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + IntCond cond); + +bool +aot_compile_simd_f32x4_compare(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + FloatCond cond); + +bool +aot_compile_simd_f64x2_compare(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + FloatCond cond); + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif + +#endif /* end of _SIMD_COMPARISONS_H_ */ diff --git a/core/iwasm/compilation/simd/simd_construct_values.c b/core/iwasm/compilation/simd/simd_construct_values.c new file mode 100644 index 000000000..1438a1639 --- /dev/null +++ b/core/iwasm/compilation/simd/simd_construct_values.c @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "simd_construct_values.h" +#include "../aot_emit_exception.h" +#include "../interpreter/wasm_opcode.h" +#include "../../aot/aot_runtime.h" + +bool +aot_compile_simd_v128_const(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + const uint8 *imm_bytes) +{ + uint64 imm1, imm2; + LLVMValueRef undef, first_long, agg1, second_long, agg2; + + wasm_runtime_read_v128(imm_bytes, &imm1, &imm2); + + if (!(undef = LLVMGetUndef(V128_i64x2_TYPE))) { + HANDLE_FAILURE("LLVMGetUndef"); + goto fail; + } + + /* %agg1 = insertelement <2 x i64> undef, i16 0, i64 ${*imm} */ + if (!(first_long = I64_CONST(imm1))) { + HANDLE_FAILURE("LLVMConstInt"); + goto fail; + } + + if (!(agg1 = LLVMBuildInsertElement(comp_ctx->builder, undef, first_long, + I32_ZERO, "agg1"))) { + HANDLE_FAILURE("LLVMBuildInsertElement"); + goto fail; + } + + /* %agg2 = insertelement <2 x i64> %agg1, i16 1, i64 ${*(imm + 1)} */ + if (!(second_long = I64_CONST(imm2))) { + HANDLE_FAILURE("LLVMGetUndef"); + goto fail; + } + + if (!(agg2 = LLVMBuildInsertElement(comp_ctx->builder, agg1, second_long, + I32_ONE, "agg2"))) { + HANDLE_FAILURE("LLVMBuildInsertElement"); + goto fail; + } + + PUSH_V128(agg2); + + return true; +fail: + return false; +} + +bool +aot_compile_simd_splat(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + uint8 splat_opcode) +{ + LLVMValueRef value, undef, base, mask, new_vector, result; + LLVMTypeRef all_zero_ty; + + switch (splat_opcode) { + case SIMD_i8x16_splat: + { + LLVMValueRef input; + POP_I32(input); + + /* trunc i32 %input to i8 */ + if (!(value = LLVMBuildTrunc(comp_ctx->builder, input, INT8_TYPE, + "trunc"))) { + HANDLE_FAILURE("LLVMBuildTrunc"); + goto fail; + } + undef = LLVMGetUndef(V128_i8x16_TYPE); + if (!(all_zero_ty = LLVMVectorType(I32_TYPE, 16))) { + HANDLE_FAILURE("LLVMVectorType"); + goto fail; + } + break; + } + case SIMD_i16x8_splat: + { + LLVMValueRef input; + POP_I32(input); + + /* trunc i32 %input to i16 */ + if (!(value = LLVMBuildTrunc(comp_ctx->builder, input, INT16_TYPE, + "trunc"))) { + HANDLE_FAILURE("LLVMBuildTrunc"); + goto fail; + } + undef = LLVMGetUndef(V128_i16x8_TYPE); + if (!(all_zero_ty = LLVMVectorType(I32_TYPE, 8))) { + HANDLE_FAILURE("LLVMVectorType"); + goto fail; + } + break; + } + case SIMD_i32x4_splat: + { + POP_I32(value); + undef = LLVMGetUndef(V128_i32x4_TYPE); + + if (!(all_zero_ty = LLVMVectorType(I32_TYPE, 4))) { + HANDLE_FAILURE("LLVMVectorType"); + goto fail; + } + break; + } + case SIMD_i64x2_splat: + { + POP(value, VALUE_TYPE_I64); + undef = LLVMGetUndef(V128_i64x2_TYPE); + + if (!(all_zero_ty = LLVMVectorType(I32_TYPE, 2))) { + HANDLE_FAILURE("LLVMVectorType"); + goto fail; + } + break; + } + case SIMD_f32x4_splat: + { + POP(value, VALUE_TYPE_F32); + undef = LLVMGetUndef(V128_f32x4_TYPE); + + if (!(all_zero_ty = LLVMVectorType(I32_TYPE, 4))) { + HANDLE_FAILURE("LLVMVectorType"); + goto fail; + } + break; + } + case SIMD_f64x2_splat: + { + POP(value, VALUE_TYPE_F64); + undef = LLVMGetUndef(V128_f64x2_TYPE); + + if (!(all_zero_ty = LLVMVectorType(I32_TYPE, 2))) { + HANDLE_FAILURE("LLVMVectorType"); + goto fail; + } + break; + } + default: + { + bh_assert(0); + goto fail; + } + } + if (!undef) { + HANDLE_FAILURE("LVMGetUndef"); + goto fail; + } + + /* insertelement undef, ty %value, i32 0 */ + if (!(base = LLVMBuildInsertElement(comp_ctx->builder, undef, value, + I32_ZERO, "base"))) { + HANDLE_FAILURE("LLVMBuildInsertElement"); + goto fail; + } + + /* zeroinitializer */ + if (!(mask = LLVMConstNull(all_zero_ty))) { + HANDLE_FAILURE("LLVMConstNull"); + goto fail; + } + + /* shufflevector %base, undef, zeroinitializer */ + if (!(new_vector = LLVMBuildShuffleVector(comp_ctx->builder, base, undef, + mask, "new_vector"))) { + HANDLE_FAILURE("LLVMBuildShuffleVector"); + goto fail; + } + + /* bitcast to <2 x i64> */ + if (!(result = LLVMBuildBitCast(comp_ctx->builder, new_vector, + V128_i64x2_TYPE, "ret"))) { + HANDLE_FAILURE("LLVMBuidlCast"); + goto fail; + } + + /* push result into the stack */ + PUSH_V128(result); + + return true; +fail: + return false; +} diff --git a/core/iwasm/compilation/simd/simd_construct_values.h b/core/iwasm/compilation/simd/simd_construct_values.h new file mode 100644 index 000000000..12bc3dedf --- /dev/null +++ b/core/iwasm/compilation/simd/simd_construct_values.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _SIMD_CONSTRUCT_VALUES_H_ +#define _SIMD_CONSTRUCT_VALUES_H_ + +#include "../aot_compiler.h" + +#ifdef __cplusplus +extern "C" { +#endif + +bool +aot_compile_simd_v128_const(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + const uint8 *imm_bytes); + +bool +aot_compile_simd_splat(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + uint8 splat_opcode); + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif + +#endif /* end of _SIMD_CONSTRUCT_VALUES_H_ */ diff --git a/core/iwasm/compilation/simd/simd_conversions.c b/core/iwasm/compilation/simd/simd_conversions.c new file mode 100644 index 000000000..f2d32c090 --- /dev/null +++ b/core/iwasm/compilation/simd/simd_conversions.c @@ -0,0 +1,422 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "simd_conversions.h" +#include "simd_common.h" +#include "../aot_emit_exception.h" +#include "../aot_emit_numberic.h" +#include "../../aot/aot_runtime.h" + +static bool +simd_integer_narrow(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + bool is_signed, + LLVMTypeRef in_vector_type, + LLVMTypeRef out_vector_type, + const char *instrinsic) +{ + LLVMValueRef vector1, vector2, result; + LLVMTypeRef param_types[2] = { in_vector_type, in_vector_type }; + + if (!(vector2 = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, + in_vector_type, "vec2"))) { + goto fail; + } + + if (!(vector1 = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, + in_vector_type, "vec1"))) { + goto fail; + } + + if (!(result = + aot_call_llvm_intrinsic(comp_ctx, instrinsic, out_vector_type, + param_types, 2, vector1, vector2))) { + HANDLE_FAILURE("LLVMBuildCall"); + goto fail; + } + + if (!(result = LLVMBuildBitCast(comp_ctx->builder, result, V128_i64x2_TYPE, + "ret"))) { + HANDLE_FAILURE("LLVMBuildBitCast"); + goto fail; + } + + PUSH_V128(result); + return true; +fail: + return false; +} + +bool +aot_compile_simd_i8x16_narrow_i16x8(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + bool is_signed) +{ + return simd_integer_narrow( + comp_ctx, func_ctx, is_signed, V128_i16x8_TYPE, V128_i8x16_TYPE, + is_signed ? "llvm.x86.sse2.packsswb.128" : "llvm.x86.sse2.packuswb.128"); +} + +bool +aot_compile_simd_i16x8_narrow_i32x4(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + bool is_signed) +{ + return simd_integer_narrow( + comp_ctx, func_ctx, is_signed, V128_i32x4_TYPE, V128_i16x8_TYPE, + is_signed ? "llvm.x86.sse2.packssdw.128" : "llvm.x86.sse41.packusdw"); +} + +bool +aot_compile_simd_i16x8_widen_i8x16(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + bool is_low_half, + bool is_signed) +{ + LLVMValueRef vector, undef, mask_high[8], mask_low[8], mask, shuffled, + result; + uint8 mask_high_value[8] = { 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf }, + mask_low_value[8] = { 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7 }, i; + + if (!(vector = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, + V128_i8x16_TYPE, "vec"))) { + goto fail; + } + + if (!(undef = LLVMGetUndef(V128_i8x16_TYPE))) { + HANDLE_FAILURE("LLVMGetUndef"); + goto fail; + } + + /* create a mask */ + for (i = 0; i < 8; i++) { + mask_high[i] = LLVMConstInt(I32_TYPE, mask_high_value[i], true); + mask_low[i] = LLVMConstInt(I32_TYPE, mask_low_value[i], true); + } + + mask = is_low_half ? LLVMConstVector(mask_low, 8) + : LLVMConstVector(mask_high, 8); + if (!mask) { + HANDLE_FAILURE("LLVMConstVector"); + goto fail; + } + + /* retrive the low or high half */ + if (!(shuffled = LLVMBuildShuffleVector(comp_ctx->builder, vector, undef, + mask, "shuffled"))) { + HANDLE_FAILURE("LLVMBuildShuffleVector"); + goto fail; + } + + if (is_signed) { + if (!(result = LLVMBuildSExt(comp_ctx->builder, shuffled, + V128_i16x8_TYPE, "ext"))) { + HANDLE_FAILURE("LLVMBuildSExt"); + goto fail; + } + } + else { + if (!(result = LLVMBuildZExt(comp_ctx->builder, shuffled, + V128_i16x8_TYPE, "ext"))) { + HANDLE_FAILURE("LLVMBuildZExt"); + goto fail; + } + } + + if (!(result = LLVMBuildBitCast(comp_ctx->builder, result, V128_i64x2_TYPE, + "ret"))) { + HANDLE_FAILURE("LLVMBuildBitCast"); + goto fail; + } + + PUSH_V128(result); + return true; +fail: + return false; +} + +bool +aot_compile_simd_i32x4_widen_i16x8(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + bool is_low_half, + bool is_signed) +{ + LLVMValueRef vector, undef, mask_high[4], mask_low[4], mask, shuffled, + result; + uint8 mask_high_value[4] = { 0x4, 0x5, 0x6, 0x7 }, + mask_low_value[4] = { 0x0, 0x1, 0x2, 0x3 }, i; + + if (!(vector = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, + V128_i16x8_TYPE, "vec"))) { + goto fail; + } + + if (!(undef = LLVMGetUndef(V128_i16x8_TYPE))) { + HANDLE_FAILURE("LLVMGetUndef"); + goto fail; + } + + /* create a mask */ + for (i = 0; i < 4; i++) { + mask_high[i] = LLVMConstInt(I32_TYPE, mask_high_value[i], true); + mask_low[i] = LLVMConstInt(I32_TYPE, mask_low_value[i], true); + } + + mask = is_low_half ? LLVMConstVector(mask_low, 4) + : LLVMConstVector(mask_high, 4); + if (!mask) { + HANDLE_FAILURE("LLVMConstVector"); + goto fail; + } + + /* retrive the low or high half */ + if (!(shuffled = LLVMBuildShuffleVector(comp_ctx->builder, vector, undef, + mask, "shuffled"))) { + HANDLE_FAILURE("LLVMBuildShuffleVector"); + goto fail; + } + + if (is_signed) { + if (!(result = LLVMBuildSExt(comp_ctx->builder, shuffled, + V128_i32x4_TYPE, "ext"))) { + HANDLE_FAILURE("LLVMBuildSExt"); + goto fail; + } + } + else { + if (!(result = LLVMBuildZExt(comp_ctx->builder, shuffled, + V128_i32x4_TYPE, "ext"))) { + HANDLE_FAILURE("LLVMBuildZExt"); + goto fail; + } + } + + if (!(result = LLVMBuildBitCast(comp_ctx->builder, result, V128_i64x2_TYPE, + "ret"))) { + HANDLE_FAILURE("LLVMBuildBitCast"); + goto fail; + } + + PUSH_V128(result); + return true; +fail: + return false; +} + +static LLVMValueRef +simd_build_const_f32x4(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + float f) +{ + LLVMValueRef elements[4], vector; + + if (!(elements[0] = LLVMConstReal(F32_TYPE, f))) { + HANDLE_FAILURE("LLVMConstInt"); + goto fail; + } + + elements[1] = elements[2] = elements[3] = elements[0]; + + if (!(vector = LLVMConstVector(elements, 4))) { + HANDLE_FAILURE("LLVMConstVector"); + goto fail; + } + + return vector; +fail: + return NULL; +} + +static LLVMValueRef +simd_build_const_i32x4(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + uint64 integer, + bool is_signed) +{ + LLVMValueRef elements[4], vector; + + if (!(elements[0] = LLVMConstInt(I32_TYPE, integer, is_signed))) { + HANDLE_FAILURE("LLVMConstInt"); + goto fail; + } + + elements[1] = elements[2] = elements[3] = elements[0]; + + if (!(vector = LLVMConstVector(elements, 4))) { + HANDLE_FAILURE("LLVMConstVector"); + goto fail; + } + + return vector; +fail: + return NULL; +} + +bool +aot_compile_simd_i32x4_trunc_sat_f32x4(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + bool is_signed) +{ + LLVMValueRef vector, zeros, is_nan, max_float_v, min_float_v, is_ge_max, + is_le_min, result, max_int_v, min_int_v; + uint32 max_ui = 0xFFffFFff, min_ui = 0x0; + int32 max_si = 0x7FFFffff, min_si = 0x80000000; + float max_f_ui = 4294967296.0f, min_f_ui = 0.0f, max_f_si = 2147483647.0f, + min_f_si = -2147483648.0f; + + if (!(vector = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, + V128_f32x4_TYPE, "vec"))) { + goto fail; + } + + if (!(zeros = LLVMConstNull(V128_f32x4_TYPE))) { + HANDLE_FAILURE("LLVMConstNull"); + goto fail; + } + + if (is_signed) { + if (!(max_float_v = + simd_build_const_f32x4(comp_ctx, func_ctx, max_f_si))) { + goto fail; + } + + if (!(min_float_v = + simd_build_const_f32x4(comp_ctx, func_ctx, min_f_si))) { + goto fail; + } + + if (!(max_int_v = + simd_build_const_i32x4(comp_ctx, func_ctx, max_si, true))) { + goto fail; + } + + if (!(min_int_v = + simd_build_const_i32x4(comp_ctx, func_ctx, min_si, true))) { + goto fail; + } + } + else { + if (!(max_float_v = + simd_build_const_f32x4(comp_ctx, func_ctx, max_f_ui))) { + goto fail; + } + + if (!(min_float_v = + simd_build_const_f32x4(comp_ctx, func_ctx, min_f_ui))) { + goto fail; + } + + if (!(max_int_v = + simd_build_const_i32x4(comp_ctx, func_ctx, max_ui, false))) { + goto fail; + } + + if (!(min_int_v = + simd_build_const_i32x4(comp_ctx, func_ctx, min_ui, false))) { + goto fail; + } + } + + if (!(is_nan = LLVMBuildFCmp(comp_ctx->builder, LLVMRealORD, vector, zeros, + "is_nan"))) { + HANDLE_FAILURE("LLVMBuildFCmp"); + goto fail; + } + + if (!(is_le_min = LLVMBuildFCmp(comp_ctx->builder, LLVMRealOLE, vector, + min_float_v, "le_min"))) { + HANDLE_FAILURE("LLVMBuildFCmp"); + goto fail; + } + + if (!(is_ge_max = LLVMBuildFCmp(comp_ctx->builder, LLVMRealOGE, vector, + max_float_v, "ge_max"))) { + HANDLE_FAILURE("LLVMBuildFCmp"); + goto fail; + } + + if (is_signed) { + if (!(result = LLVMBuildFPToSI(comp_ctx->builder, vector, + V128_i32x4_TYPE, "truncated"))) { + HANDLE_FAILURE("LLVMBuildSIToFP"); + goto fail; + } + } + else { + if (!(result = LLVMBuildFPToUI(comp_ctx->builder, vector, + V128_i32x4_TYPE, "truncated"))) { + HANDLE_FAILURE("LLVMBuildUIToFP"); + goto fail; + } + } + + if (!(result = LLVMBuildSelect(comp_ctx->builder, is_ge_max, max_int_v, + result, "sat_w_max"))) { + HANDLE_FAILURE("LLVMBuildSelect"); + goto fail; + } + + if (!(result = LLVMBuildSelect(comp_ctx->builder, is_le_min, min_int_v, + result, "sat_w_min"))) { + HANDLE_FAILURE("LLVMBuildSelect"); + goto fail; + } + + if (!(result = LLVMBuildSelect(comp_ctx->builder, is_nan, result, + V128_i32x4_ZERO, "sat_w_nan"))) { + HANDLE_FAILURE("LLVMBuildSelect"); + goto fail; + } + + if (!(result = LLVMBuildBitCast(comp_ctx->builder, result, V128_i64x2_TYPE, + "ret"))) { + HANDLE_FAILURE("LLVMBuildBitCast"); + goto fail; + } + + PUSH_V128(result); + return true; +fail: + return false; +} + +bool +aot_compile_simd_f32x4_convert_i32x4(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + bool is_signed) +{ + LLVMValueRef vector, result; + + if (!(vector = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, + V128_i32x4_TYPE, "vec"))) { + goto fail; + } + + if (is_signed) { + if (!(result = LLVMBuildSIToFP(comp_ctx->builder, vector, + V128_f32x4_TYPE, "converted"))) { + HANDLE_FAILURE("LLVMBuildSIToFP"); + goto fail; + } + } + else { + if (!(result = LLVMBuildUIToFP(comp_ctx->builder, vector, + V128_f32x4_TYPE, "converted"))) { + HANDLE_FAILURE("LLVMBuildSIToFP"); + goto fail; + } + } + + if (!(result = LLVMBuildBitCast(comp_ctx->builder, result, V128_i64x2_TYPE, + "ret"))) { + HANDLE_FAILURE("LLVMBuildBitCast"); + goto fail; + } + + PUSH_V128(result); + return true; +fail: + return false; +} diff --git a/core/iwasm/compilation/simd/simd_conversions.h b/core/iwasm/compilation/simd/simd_conversions.h new file mode 100644 index 000000000..823b5dc3a --- /dev/null +++ b/core/iwasm/compilation/simd/simd_conversions.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _SIMD_CONVERSIONS_H_ +#define _SIMD_CONVERSIONS_H_ + +#include "../aot_compiler.h" + +#ifdef __cplusplus +extern "C" { +#endif + +bool +aot_compile_simd_i8x16_narrow_i16x8(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + bool is_signed); + +bool +aot_compile_simd_i16x8_narrow_i32x4(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + bool is_signed); + +bool +aot_compile_simd_i16x8_widen_i8x16(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + bool is_low, + bool is_signed); + +bool +aot_compile_simd_i32x4_widen_i16x8(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + bool is_low, + bool is_signed); + +bool +aot_compile_simd_i32x4_trunc_sat_f32x4(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + bool is_signed); + +bool +aot_compile_simd_f32x4_convert_i32x4(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + bool is_signed); + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif + +#endif /* end of _SIMD_CONVERSIONS_H_ */ diff --git a/core/iwasm/compilation/simd/simd_floating_point.c b/core/iwasm/compilation/simd/simd_floating_point.c new file mode 100644 index 000000000..24dc8fc51 --- /dev/null +++ b/core/iwasm/compilation/simd/simd_floating_point.c @@ -0,0 +1,273 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "simd_floating_point.h" +#include "simd_common.h" +#include "../aot_emit_exception.h" +#include "../aot_emit_numberic.h" +#include "../../aot/aot_runtime.h" + +static LLVMValueRef +simd_v128_float_cmp(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + FloatArithmetic arith_op, + LLVMValueRef lhs, + LLVMValueRef rhs) +{ + LLVMValueRef result; + LLVMRealPredicate op; + + op = FLOAT_MIN == arith_op ? LLVMRealULT : LLVMRealUGT; + + if (!(result = LLVMBuildFCmp(comp_ctx->builder, op, lhs, rhs, "cmp"))) { + HANDLE_FAILURE("LLVMBuildFCmp"); + goto fail; + } + + if (!(result = + LLVMBuildSelect(comp_ctx->builder, result, lhs, rhs, "select"))) { + HANDLE_FAILURE("LLVMBuildSelect"); + goto fail; + } + + return result; +fail: + return NULL; +} + +static bool +simd_v128_float_arith(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + FloatArithmetic arith_op, + LLVMTypeRef vector_type) +{ + LLVMValueRef lhs, rhs, result; + + if (!(rhs = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type, + "rhs"))) { + goto fail; + } + + if (!(lhs = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type, + "lhs"))) { + goto fail; + } + + switch (arith_op) { + case FLOAT_ADD: + if (!(result = + LLVMBuildFAdd(comp_ctx->builder, lhs, rhs, "sum"))) { + HANDLE_FAILURE("LLVMBuildFAdd"); + goto fail; + } + break; + case FLOAT_SUB: + if (!(result = LLVMBuildFSub(comp_ctx->builder, lhs, rhs, + "difference"))) { + HANDLE_FAILURE("LLVMBuildFSub"); + goto fail; + } + break; + case FLOAT_MUL: + if (!(result = + LLVMBuildFMul(comp_ctx->builder, lhs, rhs, "product"))) { + HANDLE_FAILURE("LLVMBuildFMul"); + goto fail; + } + break; + case FLOAT_DIV: + if (!(result = + LLVMBuildFDiv(comp_ctx->builder, lhs, rhs, "quotient"))) { + HANDLE_FAILURE("LLVMBuildFDiv"); + goto fail; + } + break; + case FLOAT_MIN: + if (!(result = simd_v128_float_cmp(comp_ctx, func_ctx, FLOAT_MIN, + lhs, rhs))) { + goto fail; + } + break; + case FLOAT_MAX: + if (!(result = simd_v128_float_cmp(comp_ctx, func_ctx, FLOAT_MAX, + lhs, rhs))) { + goto fail; + } + break; + default: + result = NULL; + bh_assert(0); + break; + } + + if (!(result = LLVMBuildBitCast(comp_ctx->builder, result, V128_i64x2_TYPE, + "ret"))) { + HANDLE_FAILURE("LLVMBuildBitCast"); + goto fail; + } + + /* push result into the stack */ + PUSH_V128(result); + + return true; +fail: + return false; +} + +bool +aot_compile_simd_f32x4_arith(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + FloatArithmetic arith_op) +{ + return simd_v128_float_arith(comp_ctx, func_ctx, arith_op, + V128_f32x4_TYPE); +} + +bool +aot_compile_simd_f64x2_arith(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + FloatArithmetic arith_op) +{ + return simd_v128_float_arith(comp_ctx, func_ctx, arith_op, + V128_f64x2_TYPE); +} + +static bool +simd_v128_float_neg(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + LLVMTypeRef vector_type) +{ + LLVMValueRef number, result; + + if (!(number = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type, + "number"))) { + goto fail; + } + + if (!(result = LLVMBuildFNeg(comp_ctx->builder, number, "neg"))) { + HANDLE_FAILURE("LLVMBuildFNeg"); + goto fail; + } + + if (!(result = LLVMBuildBitCast(comp_ctx->builder, result, V128_i64x2_TYPE, + "ret"))) { + HANDLE_FAILURE("LLVMBuildBitCast"); + goto fail; + } + + /* push result into the stack */ + PUSH_V128(result); + + return true; +fail: + return false; +} + +bool +aot_compile_simd_f32x4_neg(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) +{ + return simd_v128_float_neg(comp_ctx, func_ctx, V128_f32x4_TYPE); +} + +bool +aot_compile_simd_f64x2_neg(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) +{ + return simd_v128_float_neg(comp_ctx, func_ctx, V128_f64x2_TYPE); +} + +static bool +simd_v128_float_abs(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + LLVMTypeRef vector_type, + const char *intrinsic) +{ + LLVMValueRef vector, result; + LLVMTypeRef param_types[1] = { vector_type }; + + if (!(vector = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type, + "vec"))) { + goto fail; + } + + if (!(result = aot_call_llvm_intrinsic(comp_ctx, intrinsic, vector_type, + param_types, 1, vector))) { + HANDLE_FAILURE("LLVMBuildCall"); + goto fail; + } + + if (!(result = LLVMBuildBitCast(comp_ctx->builder, result, V128_i64x2_TYPE, + "ret"))) { + HANDLE_FAILURE("LLVMBuildBitCast"); + goto fail; + } + + /* push result into the stack */ + PUSH_V128(result); + return true; +fail: + return false; +} + +bool +aot_compile_simd_f32x4_abs(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) +{ + return simd_v128_float_abs(comp_ctx, func_ctx, V128_f32x4_TYPE, + "llvm.fabs.v4f32"); +} + +bool +aot_compile_simd_f64x2_abs(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) +{ + return simd_v128_float_abs(comp_ctx, func_ctx, V128_f64x2_TYPE, + "llvm.fabs.v2f64"); +} + +static bool +simd_v128_float_sqrt(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + LLVMTypeRef vector_type, + const char *intrinsic) +{ + LLVMValueRef number, result; + LLVMTypeRef param_types[1] = { vector_type }; + + if (!(number = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type, + "number"))) { + goto fail; + } + + if (!(result = aot_call_llvm_intrinsic(comp_ctx, intrinsic, vector_type, + param_types, 1, number))) { + HANDLE_FAILURE("LLVMBuildCall"); + goto fail; + } + + if (!(result = LLVMBuildBitCast(comp_ctx->builder, result, V128_i64x2_TYPE, + "ret"))) { + HANDLE_FAILURE("LLVMBuildBitCast"); + goto fail; + } + + /* push result into the stack */ + PUSH_V128(result); + + return true; +fail: + return false; +} + +bool +aot_compile_simd_f32x4_sqrt(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) +{ + return simd_v128_float_sqrt(comp_ctx, func_ctx, V128_f32x4_TYPE, + "llvm.sqrt.v4f32"); +} + +bool +aot_compile_simd_f64x2_sqrt(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) +{ + return simd_v128_float_sqrt(comp_ctx, func_ctx, V128_f64x2_TYPE, + "llvm.sqrt.v2f64"); +} diff --git a/core/iwasm/compilation/simd/simd_floating_point.h b/core/iwasm/compilation/simd/simd_floating_point.h new file mode 100644 index 000000000..cb254b614 --- /dev/null +++ b/core/iwasm/compilation/simd/simd_floating_point.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _SIMD_FLOATING_POINT_H_ +#define _SIMD_FLOATING_POINT_H_ + +#include "../aot_compiler.h" + +#ifdef __cplusplus +extern "C" { +#endif + +bool +aot_compile_simd_f32x4_arith(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + FloatArithmetic arith_op); + +bool +aot_compile_simd_f64x2_arith(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + FloatArithmetic arith_op); + +bool +aot_compile_simd_f32x4_neg(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx); + +bool +aot_compile_simd_f64x2_neg(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx); + +bool +aot_compile_simd_f32x4_abs(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx); + +bool +aot_compile_simd_f64x2_abs(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx); + +bool +aot_compile_simd_f32x4_sqrt(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx); + +bool +aot_compile_simd_f64x2_sqrt(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx); + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif + +#endif /* end of _SIMD_FLOATING_POINT_H_ */ diff --git a/core/iwasm/compilation/simd/simd_int_arith.c b/core/iwasm/compilation/simd/simd_int_arith.c new file mode 100644 index 000000000..4a83e3be7 --- /dev/null +++ b/core/iwasm/compilation/simd/simd_int_arith.c @@ -0,0 +1,207 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "simd_int_arith.h" +#include "simd_common.h" +#include "../aot_emit_exception.h" +#include "../../aot/aot_runtime.h" + +static bool +simd_v128_integer_arith(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + V128Arithmetic arith_op, + LLVMValueRef lhs, + LLVMValueRef rhs) +{ + LLVMValueRef result; + + switch (arith_op) { + case V128_ADD: + if (!(result = LLVMBuildAdd(comp_ctx->builder, lhs, rhs, "sum"))) { + HANDLE_FAILURE("LLVMBuildAdd"); + goto fail; + } + break; + case V128_SUB: + if (!(result = + LLVMBuildSub(comp_ctx->builder, lhs, rhs, "difference"))) { + HANDLE_FAILURE("LLVMBuildSub"); + goto fail; + } + break; + case V128_MUL: + if (!(result = + LLVMBuildMul(comp_ctx->builder, lhs, rhs, "product"))) { + HANDLE_FAILURE("LLVMBuildMul"); + goto fail; + } + break; + case V128_NEG: + if (!(result = LLVMBuildNeg(comp_ctx->builder, lhs, "neg"))) { + HANDLE_FAILURE("LLVMBuildNeg"); + goto fail; + } + break; + default: + result = NULL; + bh_assert(0); + break; + } + + if (!(result = LLVMBuildBitCast(comp_ctx->builder, result, V128_i64x2_TYPE, + "ret"))) { + HANDLE_FAILURE("LLVMBuildBitCast"); + goto fail; + } + + /* push result into the stack */ + PUSH_V128(result); + + return true; +fail: + return false; +} + +bool +aot_compile_simd_i8x16_arith(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + V128Arithmetic arith_op) +{ + LLVMValueRef lhs, rhs; + + if (!(rhs = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, V128_i8x16_TYPE, + "rhs"))) { + goto fail; + } + + if (!(lhs = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, V128_i8x16_TYPE, + "lhs"))) { + goto fail; + } + + return simd_v128_integer_arith(comp_ctx, func_ctx, arith_op, lhs, rhs); +fail: + return NULL; +} + +bool +aot_compile_simd_i16x8_arith(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + V128Arithmetic arith_op) +{ + LLVMValueRef lhs, rhs; + + if (!(rhs = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, V128_i16x8_TYPE, + "rhs"))) { + goto fail; + } + + if (!(lhs = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, V128_i16x8_TYPE, + "lhs"))) { + goto fail; + } + + return simd_v128_integer_arith(comp_ctx, func_ctx, arith_op, lhs, rhs); +fail: + return NULL; +} + +bool +aot_compile_simd_i32x4_arith(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + V128Arithmetic arith_op) +{ + LLVMValueRef lhs, rhs; + + if (!(rhs = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, V128_i32x4_TYPE, + "rhs"))) { + goto fail; + } + + if (!(lhs = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, V128_i32x4_TYPE, + "lhs"))) { + goto fail; + } + + return simd_v128_integer_arith(comp_ctx, func_ctx, arith_op, lhs, rhs); +fail: + return NULL; +} + +bool +aot_compile_simd_i64x2_arith(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + V128Arithmetic arith_op) +{ + LLVMValueRef lhs, rhs; + + POP_V128(rhs); + POP_V128(lhs); + + return simd_v128_integer_arith(comp_ctx, func_ctx, arith_op, lhs, rhs); +fail: + return false; +} + +bool +aot_compile_simd_i8x16_neg(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) +{ + LLVMValueRef number; + + if (!(number = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, + V128_i8x16_TYPE, "number"))) { + goto fail; + } + + return simd_v128_integer_arith(comp_ctx, func_ctx, V128_NEG, number, NULL); + +fail: + return false; +} + +bool +aot_compile_simd_i16x8_neg(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) +{ + LLVMValueRef number; + + if (!(number = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, + V128_i16x8_TYPE, "number"))) { + goto fail; + } + + return simd_v128_integer_arith(comp_ctx, func_ctx, V128_NEG, number, NULL); + +fail: + return false; +} + +bool +aot_compile_simd_i32x4_neg(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) +{ + LLVMValueRef number; + + if (!(number = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, + V128_i32x4_TYPE, "number"))) { + goto fail; + } + + return simd_v128_integer_arith(comp_ctx, func_ctx, V128_NEG, number, NULL); + +fail: + return false; +} + +bool +aot_compile_simd_i64x2_neg(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) +{ + LLVMValueRef number; + + POP_V128(number); + + return simd_v128_integer_arith(comp_ctx, func_ctx, V128_NEG, number, NULL); + +fail: + return false; +} diff --git a/core/iwasm/compilation/simd/simd_int_arith.h b/core/iwasm/compilation/simd/simd_int_arith.h new file mode 100644 index 000000000..5cd77899d --- /dev/null +++ b/core/iwasm/compilation/simd/simd_int_arith.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _SIMD_INT_ARITH_H_ +#define _SIMD_INT_ARITH_H_ + +#include "../aot_compiler.h" + +#ifdef __cplusplus +extern "C" { +#endif + +bool +aot_compile_simd_i8x16_arith(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + V128Arithmetic cond); + +bool +aot_compile_simd_i16x8_arith(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + V128Arithmetic cond); + +bool +aot_compile_simd_i32x4_arith(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + V128Arithmetic cond); + +bool +aot_compile_simd_i64x2_arith(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + V128Arithmetic cond); + +bool +aot_compile_simd_i8x16_neg(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx); + +bool +aot_compile_simd_i16x8_neg(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx); + +bool +aot_compile_simd_i32x4_neg(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx); + +bool +aot_compile_simd_i64x2_neg(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx); + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif + +#endif /* end of _SIMD_INT_ARITH_H_ */ diff --git a/core/iwasm/compilation/simd/simd_load_store.c b/core/iwasm/compilation/simd/simd_load_store.c new file mode 100644 index 000000000..6a15ff98b --- /dev/null +++ b/core/iwasm/compilation/simd/simd_load_store.c @@ -0,0 +1,301 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "simd_load_store.h" +#include "../aot_emit_exception.h" +#include "../aot_emit_memory.h" +#include "../../aot/aot_runtime.h" +#include "../../interpreter/wasm_opcode.h" + +/* data_length in bytes */ +static LLVMValueRef +simd_load(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + uint32 align, + uint32 offset, + uint32 data_length, + LLVMTypeRef ptr_type) +{ + LLVMValueRef maddr, data; + + if (!(maddr = aot_check_memory_overflow(comp_ctx, func_ctx, offset, + data_length))) { + HANDLE_FAILURE("aot_check_memory_overflow"); + goto fail; + } + + if (!(maddr = LLVMBuildBitCast(comp_ctx->builder, maddr, ptr_type, + "data_ptr"))) { + HANDLE_FAILURE("LLVMBuildBitCast"); + goto fail; + } + + if (!(data = LLVMBuildLoad(comp_ctx->builder, maddr, "data"))) { + HANDLE_FAILURE("LLVMBuildLoad"); + goto fail; + } + + LLVMSetAlignment(data, 1); + + return data; +fail: + return NULL; +} + +/* data_length in bytes */ +static LLVMValueRef +simd_splat(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + LLVMValueRef element, + LLVMTypeRef vectory_type, + unsigned lane_count) +{ + LLVMValueRef undef, zeros, vector; + LLVMTypeRef zeros_type; + + if (!(undef = LLVMGetUndef(vectory_type))) { + HANDLE_FAILURE("LLVMGetUndef"); + goto fail; + } + + if (!(zeros_type = LLVMVectorType(I32_TYPE, lane_count))) { + HANDLE_FAILURE("LVMVectorType"); + goto fail; + } + + if (!(zeros = LLVMConstNull(zeros_type))) { + HANDLE_FAILURE("LLVMConstNull"); + goto fail; + } + + if (!(vector = LLVMBuildInsertElement(comp_ctx->builder, undef, element, + I32_ZERO, "base"))) { + HANDLE_FAILURE("LLVMBuildInsertElement"); + goto fail; + } + + if (!(vector = LLVMBuildShuffleVector(comp_ctx->builder, vector, undef, + zeros, "vector"))) { + HANDLE_FAILURE("LLVMBuildShuffleVector"); + goto fail; + } + + return vector; +fail: + return NULL; +} + +bool +aot_compile_simd_v128_load(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + uint32 align, + uint32 offset) +{ + LLVMValueRef result; + + if (!(result = + simd_load(comp_ctx, func_ctx, align, offset, 16, V128_PTR_TYPE))) { + goto fail; + } + + PUSH_V128(result); + return true; +fail: + return false; +} + +bool +aot_compile_simd_v128_store(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + uint32 align, + uint32 offset) +{ + LLVMValueRef maddr, value, result; + + POP_V128(value); + + if (!(maddr = aot_check_memory_overflow(comp_ctx, func_ctx, offset, 16))) + return false; + + if (!(maddr = LLVMBuildBitCast(comp_ctx->builder, maddr, V128_PTR_TYPE, + "data_ptr"))) { + HANDLE_FAILURE("LLVMBuildBitCast"); + goto fail; + } + + if (!(result = LLVMBuildStore(comp_ctx->builder, value, maddr))) { + HANDLE_FAILURE("LLVMBuildStore"); + goto fail; + } + + LLVMSetAlignment(result, 1); + + return true; +fail: + return false; +} + +bool +aot_compile_simd_load_extend(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + uint8 load_opcode, + uint32 align, + uint32 offset) +{ + LLVMValueRef sub_vector, result; + LLVMTypeRef sub_vector_type, vector_type; + bool is_signed; + uint32 data_length; + + switch (load_opcode) { + case SIMD_i16x8_load8x8_s: + case SIMD_i16x8_load8x8_u: + { + data_length = 8; + vector_type = V128_i16x8_TYPE; + is_signed = (load_opcode == SIMD_i16x8_load8x8_s); + + if (!(sub_vector_type = LLVMVectorType(INT8_TYPE, 8))) { + HANDLE_FAILURE("LLVMVectorType"); + goto fail; + } + + break; + } + case SIMD_i32x4_load16x4_s: + case SIMD_i32x4_load16x4_u: + { + data_length = 8; + vector_type = V128_i32x4_TYPE; + is_signed = (load_opcode == SIMD_i32x4_load16x4_s); + + if (!(sub_vector_type = LLVMVectorType(INT16_TYPE, 4))) { + HANDLE_FAILURE("LLVMVectorType"); + goto fail; + } + + break; + } + case SIMD_i64x2_load32x2_s: + case SIMD_i64x2_load32x2_u: + { + data_length = 8; + vector_type = V128_i64x2_TYPE; + is_signed = (load_opcode == SIMD_i64x2_load32x2_s); + + if (!(sub_vector_type = LLVMVectorType(I32_TYPE, 2))) { + HANDLE_FAILURE("LLVMVectorType"); + goto fail; + } + + break; + } + default: + { + bh_assert(0); + goto fail; + } + } + + /* to vector ptr type */ + if (!(sub_vector_type = LLVMPointerType(sub_vector_type, 0))) { + HANDLE_FAILURE("LLVMPointerType"); + goto fail; + } + + if (!(sub_vector = simd_load(comp_ctx, func_ctx, align, offset, + data_length, sub_vector_type))) { + goto fail; + } + + if (is_signed) { + if (!(result = LLVMBuildSExt(comp_ctx->builder, sub_vector, + vector_type, "vector"))) { + HANDLE_FAILURE("LLVMBuildSExt"); + goto fail; + } + } + else { + if (!(result = LLVMBuildZExt(comp_ctx->builder, sub_vector, + vector_type, "vector"))) { + HANDLE_FAILURE("LLVMBuildZExt"); + goto fail; + } + } + + if (!(result = LLVMBuildBitCast(comp_ctx->builder, result, V128_i64x2_TYPE, + "result"))) { + HANDLE_FAILURE("LLVMBuildBitCast"); + goto fail; + } + + PUSH_V128(result); + return true; +fail: + return false; +} + +bool +aot_compile_simd_load_splat(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + uint8 load_opcode, + uint32 align, + uint32 offset) +{ + LLVMValueRef element, result; + LLVMTypeRef element_ptr_type, vector_type; + unsigned data_length, lane_count; + + switch (load_opcode) { + case SIMD_v8x16_load_splat: + data_length = 1; + lane_count = 16; + element_ptr_type = INT8_PTR_TYPE; + vector_type = V128_i8x16_TYPE; + break; + case SIMD_v16x8_load_splat: + data_length = 2; + lane_count = 8; + element_ptr_type = INT16_PTR_TYPE; + vector_type = V128_i16x8_TYPE; + break; + case SIMD_v32x4_load_splat: + data_length = 4; + lane_count = 4; + element_ptr_type = INT32_PTR_TYPE; + vector_type = V128_i32x4_TYPE; + break; + case SIMD_v64x2_load_splat: + data_length = 8; + lane_count = 2; + element_ptr_type = INT64_PTR_TYPE; + vector_type = V128_i64x2_TYPE; + break; + default: + bh_assert(0); + goto fail; + } + + if (!(element = simd_load(comp_ctx, func_ctx, align, offset, data_length, + element_ptr_type))) { + goto fail; + } + + if (!(result = simd_splat(comp_ctx, func_ctx, element, vector_type, + lane_count))) { + goto fail; + } + + if (!(result = LLVMBuildBitCast(comp_ctx->builder, result, V128_i64x2_TYPE, + "result"))) { + HANDLE_FAILURE("LLVMBuildBitCast"); + goto fail; + } + + PUSH_V128(result); + return true; +fail: + return false; +} diff --git a/core/iwasm/compilation/simd/simd_load_store.h b/core/iwasm/compilation/simd/simd_load_store.h new file mode 100644 index 000000000..dbf662ad1 --- /dev/null +++ b/core/iwasm/compilation/simd/simd_load_store.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _SIMD_LOAD_STORE_H_ +#define _SIMD_LOAD_STORE_H_ + +#include "../aot_compiler.h" + +#ifdef __cplusplus +extern "C" { +#endif + +bool +aot_compile_simd_v128_load(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + uint32 align, + uint32 offset); + +bool +aot_compile_simd_v128_store(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + uint32 align, + uint32 offset); + +bool +aot_compile_simd_load_extend(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + uint8 load_opcode, + uint32 align, + uint32 offset); + +bool +aot_compile_simd_load_splat(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + uint8 load_opcode, + uint32 align, + uint32 offset); + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif + +#endif /* end of _SIMD_LOAD_STORE_H_ */ diff --git a/core/iwasm/compilation/simd/simd_sat_int_arith.c b/core/iwasm/compilation/simd/simd_sat_int_arith.c new file mode 100644 index 000000000..d8f85da76 --- /dev/null +++ b/core/iwasm/compilation/simd/simd_sat_int_arith.c @@ -0,0 +1,367 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "simd_sat_int_arith.h" +#include "simd_common.h" +#include "../aot_emit_exception.h" +#include "../../aot/aot_runtime.h" + +static bool +simd_v128_integer_arith(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + LLVMTypeRef vector_type, + char *intrinsics_s_u[2], + bool is_signed) +{ + LLVMValueRef lhs, rhs, result; + LLVMTypeRef param_types[2]; + + if (!(rhs = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type, + "rhs"))) { + goto fail; + } + + if (!(lhs = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type, + "lhs"))) { + goto fail; + } + + param_types[0] = vector_type; + param_types[1] = vector_type; + + if (!(result = aot_call_llvm_intrinsic( + comp_ctx, is_signed ? intrinsics_s_u[0] : intrinsics_s_u[1], + vector_type, param_types, 2, lhs, rhs))) { + HANDLE_FAILURE("LLVMBuildCall"); + goto fail; + } + + if (!(result = LLVMBuildBitCast(comp_ctx->builder, result, V128_i64x2_TYPE, + "ret"))) { + HANDLE_FAILURE("LLVMBuildBitCast"); + goto fail; + } + + /* push result into the stack */ + PUSH_V128(result); + return true; +fail: + return false; +} + +bool +aot_compile_simd_i8x16_saturate(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + V128Arithmetic arith_op, + bool is_signed) +{ + char *intrinsics[2] = { 0 }; + bool result = false; + switch (arith_op) { + case V128_ADD: + intrinsics[0] = "llvm.sadd.sat.v16i8"; + intrinsics[1] = "llvm.uadd.sat.v16i8"; + result = simd_v128_integer_arith( + comp_ctx, func_ctx, V128_i8x16_TYPE, intrinsics, is_signed); + break; + case V128_SUB: + intrinsics[0] = "llvm.ssub.sat.v16i8"; + intrinsics[1] = "llvm.usub.sat.v16i8"; + result = simd_v128_integer_arith( + comp_ctx, func_ctx, V128_i8x16_TYPE, intrinsics, is_signed); + break; + default: + bh_assert(0); + break; + } + + return result; +} + +bool +aot_compile_simd_i16x8_saturate(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + V128Arithmetic arith_op, + bool is_signed) +{ + char *intrinsics[2] = { 0 }; + bool result = false; + switch (arith_op) { + case V128_ADD: + intrinsics[0] = "llvm.sadd.sat.v8i16"; + intrinsics[1] = "llvm.uadd.sat.v8i16"; + result = simd_v128_integer_arith( + comp_ctx, func_ctx, V128_i16x8_TYPE, intrinsics, is_signed); + break; + case V128_SUB: + intrinsics[0] = "llvm.ssub.sat.v8i16"; + intrinsics[1] = "llvm.usub.sat.v8i16"; + result = simd_v128_integer_arith( + comp_ctx, func_ctx, V128_i16x8_TYPE, intrinsics, is_signed); + break; + default: + bh_assert(0); + break; + } + + return result; +} + +static bool +simd_v128_cmp(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + LLVMTypeRef vector_type, + V128Arithmetic arith_op, + bool is_signed) +{ + LLVMValueRef lhs, rhs, result; + LLVMIntPredicate op; + + if (!(rhs = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type, + "rhs"))) { + goto fail; + } + + if (!(lhs = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type, + "lhs"))) { + goto fail; + } + + if (V128_MIN == arith_op) { + op = is_signed ? LLVMIntSLT : LLVMIntULT; + } + else { + op = is_signed ? LLVMIntSGT : LLVMIntUGT; + } + + if (!(result = LLVMBuildICmp(comp_ctx->builder, op, lhs, rhs, "cmp"))) { + HANDLE_FAILURE("LLVMBuildICmp"); + goto fail; + } + + if (!(result = + LLVMBuildSelect(comp_ctx->builder, result, lhs, rhs, "select"))) { + HANDLE_FAILURE("LLVMBuildSelect"); + goto fail; + } + + if (!(result = LLVMBuildBitCast(comp_ctx->builder, result, V128_i64x2_TYPE, + "ret"))) { + HANDLE_FAILURE("LLVMBuildBitCast"); + goto fail; + } + + /* push result into the stack */ + PUSH_V128(result); + return true; +fail: + return false; +} + +bool +aot_compile_simd_i8x16_cmp(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + V128Arithmetic arith_op, + bool is_signed) +{ + return simd_v128_cmp(comp_ctx, func_ctx, V128_i8x16_TYPE, arith_op, + is_signed); +} + +bool +aot_compile_simd_i16x8_cmp(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + V128Arithmetic arith_op, + bool is_signed) +{ + return simd_v128_cmp(comp_ctx, func_ctx, V128_i16x8_TYPE, arith_op, + is_signed); +} + +bool +aot_compile_simd_i32x4_cmp(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + V128Arithmetic arith_op, + bool is_signed) +{ + return simd_v128_cmp(comp_ctx, func_ctx, V128_i32x4_TYPE, arith_op, + is_signed); +} + +static bool +simd_v128_abs(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + LLVMTypeRef vector_type) +{ + LLVMValueRef vector, negs, zeros, cond, result; + + if (!(vector = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type, + "vec"))) { + goto fail; + } + + if (!(negs = LLVMBuildNeg(comp_ctx->builder, vector, "neg"))) { + HANDLE_FAILURE("LLVMBuildNeg"); + goto fail; + } + + if (!(zeros = LLVMConstNull(vector_type))) { + HANDLE_FAILURE("LLVMConstNull"); + goto fail; + } + + if (!(cond = LLVMBuildICmp(comp_ctx->builder, LLVMIntSGE, vector, zeros, + "ge_zero"))) { + HANDLE_FAILURE("LLVMBuildICmp"); + goto fail; + } + + if (!(result = LLVMBuildSelect(comp_ctx->builder, cond, vector, negs, + "select"))) { + HANDLE_FAILURE("LLVMBuildSelect"); + goto fail; + } + + if (!(result = LLVMBuildBitCast(comp_ctx->builder, result, V128_i64x2_TYPE, + "ret"))) { + HANDLE_FAILURE("LLVMBuildBitCast"); + goto fail; + } + + /* push result into the stack */ + PUSH_V128(result); + return true; +fail: + return false; +} + +bool +aot_compile_simd_i8x16_abs(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) +{ + return simd_v128_abs(comp_ctx, func_ctx, V128_i8x16_TYPE); +} + +bool +aot_compile_simd_i16x8_abs(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) +{ + return simd_v128_abs(comp_ctx, func_ctx, V128_i16x8_TYPE); +} + +bool +aot_compile_simd_i32x4_abs(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) +{ + return simd_v128_abs(comp_ctx, func_ctx, V128_i32x4_TYPE); +} + +/* (v1 + v2 + 1) / 2 */ +static bool +simd_v128_avg(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + LLVMTypeRef vector_type, + LLVMTypeRef element_type, + unsigned lane_width) +{ + LLVMValueRef lhs, rhs, undef, zeros, ones, result; + LLVMTypeRef ext_type; + + if (!(rhs = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type, + "rhs"))) { + goto fail; + } + + if (!(lhs = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type, + "lhs"))) { + goto fail; + } + + if (!(ext_type = LLVMVectorType(I32_TYPE, lane_width))) { + HANDLE_FAILURE("LLVMVectorType"); + goto fail; + } + + if (!(lhs = LLVMBuildZExt(comp_ctx->builder, lhs, ext_type, "left_ext"))) { + HANDLE_FAILURE("LLVMBuildZExt"); + goto fail; + } + + if (!(rhs = + LLVMBuildZExt(comp_ctx->builder, rhs, ext_type, "right_ext"))) { + HANDLE_FAILURE("LLVMBuildZExt"); + goto fail; + } + + if (!(undef = LLVMGetUndef(ext_type))) { + HANDLE_FAILURE("LLVMGetUndef"); + goto fail; + } + + if (!(zeros = LLVMConstNull(ext_type))) { + HANDLE_FAILURE("LLVMConstNull"); + goto fail; + } + + if (!(ones = LLVMConstInt(I32_TYPE, 1, true))) { + HANDLE_FAILURE("LLVMConstInt"); + goto fail; + } + + if (!(ones = LLVMBuildInsertElement(comp_ctx->builder, undef, ones, + I32_ZERO, "base_ones"))) { + HANDLE_FAILURE("LLVMBuildInsertElement"); + goto fail; + } + + if (!(ones = LLVMBuildShuffleVector(comp_ctx->builder, ones, undef, zeros, + "ones"))) { + HANDLE_FAILURE("LLVMBuildShuffleVector"); + goto fail; + } + + if (!(result = LLVMBuildAdd(comp_ctx->builder, lhs, rhs, "a_add_b"))) { + HANDLE_FAILURE("LLVMBuildAdd"); + goto fail; + } + + if (!(result = LLVMBuildAdd(comp_ctx->builder, result, ones, "plus_1"))) { + HANDLE_FAILURE("LLVMBuildAdd"); + goto fail; + } + + if (!(result = LLVMBuildLShr(comp_ctx->builder, result, ones, "avg"))) { + HANDLE_FAILURE("LLVMBuildLShr"); + goto fail; + } + + if (!(result = LLVMBuildTrunc(comp_ctx->builder, result, vector_type, + "avg_trunc"))) { + HANDLE_FAILURE("LLVMBuildTrunc"); + goto fail; + } + + if (!(result = LLVMBuildBitCast(comp_ctx->builder, result, V128_i64x2_TYPE, + "ret"))) { + HANDLE_FAILURE("LLVMBuildBitCast"); + goto fail; + } + + /* push result into the stack */ + PUSH_V128(result); + return true; +fail: + return false; +} +bool +aot_compile_simd_i8x16_avgr_u(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx) +{ + return simd_v128_avg(comp_ctx, func_ctx, V128_i8x16_TYPE, INT8_TYPE, 16); +} + +bool +aot_compile_simd_i16x8_avgr_u(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx) +{ + return simd_v128_avg(comp_ctx, func_ctx, V128_i16x8_TYPE, INT16_TYPE, 8); +} \ No newline at end of file diff --git a/core/iwasm/compilation/simd/simd_sat_int_arith.h b/core/iwasm/compilation/simd/simd_sat_int_arith.h new file mode 100644 index 000000000..57669878e --- /dev/null +++ b/core/iwasm/compilation/simd/simd_sat_int_arith.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _SIMD_SAT_INT_ARITH_H_ +#define _SIMD_SAT_INT_ARITH_H_ + +#include "../aot_compiler.h" + +#ifdef __cplusplus +extern "C" { +#endif + +bool +aot_compile_simd_i8x16_saturate(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + V128Arithmetic arith_op, + bool is_signed); + +bool +aot_compile_simd_i16x8_saturate(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + V128Arithmetic arith_op, + bool is_signed); + +bool +aot_compile_simd_i8x16_cmp(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + V128Arithmetic arith_op, + bool is_signed); + +bool +aot_compile_simd_i16x8_cmp(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + V128Arithmetic arith_op, + bool is_signed); + +bool +aot_compile_simd_i32x4_cmp(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + V128Arithmetic arith_op, + bool is_signed); + +bool +aot_compile_simd_i8x16_abs(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx); + +bool +aot_compile_simd_i16x8_abs(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx); + +bool +aot_compile_simd_i32x4_abs(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx); + +bool +aot_compile_simd_i8x16_avgr_u(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx); + +bool +aot_compile_simd_i16x8_avgr_u(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx); + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif + +#endif /* end of _SIMD_SAT_INT_ARITH_H_ */ diff --git a/core/iwasm/include/aot_export.h b/core/iwasm/include/aot_export.h index ca0ffb6a8..f2d339622 100644 --- a/core/iwasm/include/aot_export.h +++ b/core/iwasm/include/aot_export.h @@ -42,6 +42,7 @@ typedef struct AOTCompOption{ bool enable_bulk_memory; bool enable_thread_mgr; bool enable_tail_call; + bool enable_simd; bool is_sgx_platform; uint32_t opt_level; uint32_t size_level; diff --git a/core/iwasm/interpreter/wasm.h b/core/iwasm/interpreter/wasm.h index fea564260..040b33128 100644 --- a/core/iwasm/interpreter/wasm.h +++ b/core/iwasm/interpreter/wasm.h @@ -19,6 +19,7 @@ extern "C" { #define VALUE_TYPE_I64 0X7E #define VALUE_TYPE_F32 0x7D #define VALUE_TYPE_F64 0x7C +#define VALUE_TYPE_V128 0x7B #define VALUE_TYPE_VOID 0x40 /* Used by AOT */ #define VALUE_TYPE_I1 0x41 @@ -34,6 +35,7 @@ extern "C" { #define INIT_EXPR_TYPE_I64_CONST 0x42 #define INIT_EXPR_TYPE_F32_CONST 0x43 #define INIT_EXPR_TYPE_F64_CONST 0x44 +#define INIT_EXPR_TYPE_V128_CONST 0xFD #define INIT_EXPR_TYPE_GET_GLOBAL 0x23 #define INIT_EXPR_TYPE_ERROR 0xff @@ -79,6 +81,15 @@ typedef struct WASMModule WASMModule; typedef struct WASMFunction WASMFunction; typedef struct WASMGlobal WASMGlobal; +typedef union V128 { + int8 i8x16[16]; + int16 i16x8[8]; + int32 i32x8[4]; + int64 i64x2[2]; + float32 f32x4[4]; + float64 f64x2[2]; +} V128; + typedef union WASMValue { int32 i32; uint32 u32; @@ -87,6 +98,7 @@ typedef union WASMValue { float32 f32; float64 f64; uintptr_t addr; + V128 v128; } WASMValue; typedef struct InitializerExpression { @@ -98,6 +110,7 @@ typedef struct InitializerExpression { float32 f32; float64 f64; uint32 global_index; + V128 v128; } u; } InitializerExpression; @@ -448,6 +461,10 @@ wasm_value_type_size(uint8 value_type) case VALUE_TYPE_I64: case VALUE_TYPE_F64: return sizeof(int64); +#if WASM_ENABLE_SIMD != 0 + case VALUE_TYPE_V128: + return sizeof(int64) * 2; +#endif default: bh_assert(0); } @@ -465,6 +482,10 @@ wasm_value_type_cell_num(uint8 value_type) else if (value_type == VALUE_TYPE_I64 || value_type == VALUE_TYPE_F64) return 2; +#if WASM_ENABLE_SIMD != 0 + else if (value_type == VALUE_TYPE_V128) + return 4; +#endif else { bh_assert(0); } diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index f542f9deb..5d8b997e1 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -231,6 +231,23 @@ fail: res = (int32)res64; \ } while (0) +#if WASM_ENABLE_SIMD != 0 +#if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0) +static V128 +read_i8x16(uint8 *p_buf, char* error_buf, uint32 error_buf_size) +{ + V128 result; + uint8 i; + + for (i = 0; i != 16; ++i) { + result.i8x16[i] = read_uint8(p_buf); + } + + return result; +} +#endif /* end of (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0) */ +#endif /* end of WASM_ENABLE_SIMD */ + static void * loader_malloc(uint64 size, char *error_buf, uint32 error_buf_size) { @@ -412,6 +429,29 @@ load_init_expr(const uint8 **p_buf, const uint8 *buf_end, for (i = 0; i < sizeof(float64); i++) *p_float++ = *p++; break; +#if WASM_ENABLE_SIMD != 0 +#if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0) + case INIT_EXPR_TYPE_V128_CONST: + { + uint8 flag; + uint64 high, low; + + if (type != VALUE_TYPE_V128) + goto fail; + + flag = read_uint8(p); + (void)flag; + + CHECK_BUF(p, p_end, 16); + wasm_runtime_read_v128(p, &high, &low); + p += 16; + + init_expr->u.v128.i64x2[0] = high; + init_expr->u.v128.i64x2[1] = low; + break; + } +#endif /* end of (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0) */ +#endif /* end of WASM_ENABLE_SIMD */ /* get_global */ case INIT_EXPR_TYPE_GET_GLOBAL: read_leb_uint32(p, p_end, init_expr->u.global_index); @@ -1794,7 +1834,13 @@ load_function_section(const uint8 *buf, const uint8 *buf_end, CHECK_BUF(p_code, buf_code_end, 1); /* 0x7F/0x7E/0x7D/0x7C */ type = read_uint8(p_code); - if (type < VALUE_TYPE_F64 || type > VALUE_TYPE_I32) { + if ((type < VALUE_TYPE_F64 || type > VALUE_TYPE_I32) +#if WASM_ENABLE_SIMD != 0 +#if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0) + && type != VALUE_TYPE_V128 +#endif +#endif + ) { set_error_buf(error_buf, error_buf_size, "invalid local type"); return false; @@ -2031,6 +2077,12 @@ load_export_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, "unknown function"); return false; } +#if WASM_ENABLE_SIMD != 0 +#if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0) + /* TODO: check func type, if it has v128 param or result, + report error */ +#endif +#endif break; /*table index*/ case EXPORT_KIND_TABLE: @@ -3529,6 +3581,81 @@ wasm_loader_find_block_addr(BlockAddr *block_addr_cache, } break; } + +#if WASM_ENABLE_SIMD != 0 +#if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0) + case WASM_OP_SIMD_PREFIX: + { + opcode = read_uint8(p); + if (SIMD_i8x16_eq <= opcode + && opcode <= SIMD_f32x4_convert_i32x4_u) { + break; + } + + switch (opcode) { + case SIMD_v128_load: + case SIMD_i16x8_load8x8_s: + case SIMD_i16x8_load8x8_u: + case SIMD_i32x4_load16x4_s: + case SIMD_i32x4_load16x4_u: + case SIMD_i64x2_load32x2_s: + case SIMD_i64x2_load32x2_u: + case SIMD_v8x16_load_splat: + case SIMD_v16x8_load_splat: + case SIMD_v32x4_load_splat: + case SIMD_v64x2_load_splat: + case SIMD_v128_store: + skip_leb_uint32(p, p_end); /* align */ + skip_leb_uint32(p, p_end); /* offset */ + break; + + case SIMD_v128_const: + case SIMD_v8x16_shuffle: + CHECK_BUF1(p, p_end, 16); + p += 16; + break; + + case SIMD_v8x16_swizzle: + case SIMD_i8x16_splat: + case SIMD_i16x8_splat: + case SIMD_i32x4_splat: + case SIMD_i64x2_splat: + case SIMD_f32x4_splat: + case SIMD_f64x2_splat: + break; + + case SIMD_i8x16_extract_lane_s: + case SIMD_i8x16_extract_lane_u: + case SIMD_i8x16_replace_lane: + case SIMD_i16x8_extract_lane_s: + case SIMD_i16x8_extract_lane_u: + case SIMD_i16x8_replace_lane: + case SIMD_i32x4_extract_lane: + case SIMD_i32x4_replace_lane: + case SIMD_i64x2_extract_lane: + case SIMD_i64x2_replace_lane: + case SIMD_f32x4_extract_lane: + case SIMD_f32x4_replace_lane: + case SIMD_f64x2_extract_lane: + case SIMD_f64x2_replace_lane: + CHECK_BUF(p, p_end, 1); + p++; + break; + + default: + LOG_WARNING("WASM loader find block addr failed: " + "invalid opcode fd 0x%02x.", opcode); + if (error_buf) + snprintf(error_buf, error_buf_size, + "WASM loader find block addr failed: " + "invalid opcode fd %02x.", opcode); + return false; + } + break; + } +#endif /* end of (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0) */ +#endif /* end of WASM_ENABLE_SIMD */ + #if WASM_ENABLE_SHARED_MEMORY != 0 case WASM_OP_ATOMIC_PREFIX: { @@ -3545,6 +3672,7 @@ wasm_loader_find_block_addr(BlockAddr *block_addr_cache, break; } #endif + default: set_error_buf_v(error_buf, error_buf_size, "%s %02x", @@ -3565,6 +3693,10 @@ fail: #define REF_I64_2 VALUE_TYPE_I64 #define REF_F64_1 VALUE_TYPE_F64 #define REF_F64_2 VALUE_TYPE_F64 +#define REF_V128_1 VALUE_TYPE_V128 +#define REF_V128_2 VALUE_TYPE_V128 +#define REF_V128_3 VALUE_TYPE_V128 +#define REF_V128_4 VALUE_TYPE_V128 #define REF_ANY VALUE_TYPE_ANY #if WASM_ENABLE_FAST_INTERP != 0 @@ -3775,12 +3907,18 @@ static bool check_stack_top_values(uint8 *frame_ref, int32 stack_cell_num, uint8 type, char *error_buf, uint32 error_buf_size) { - char *type_str[] = { "f64", "f32", "i64", "i32" }; + char *type_str[] = { "v128", "f64", "f32", "i64", "i32" }; if (((type == VALUE_TYPE_I32 || type == VALUE_TYPE_F32) && stack_cell_num < 1) || ((type == VALUE_TYPE_I64 || type == VALUE_TYPE_F64) - && stack_cell_num < 2)) { + && stack_cell_num < 2) +#if WASM_ENABLE_SIMD != 0 +#if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0) + || (type == VALUE_TYPE_V128 && stack_cell_num < 4) +#endif +#endif + ) { set_error_buf(error_buf, error_buf_size, "type mismatch: expect data but stack was empty"); return false; @@ -3793,10 +3931,20 @@ check_stack_top_values(uint8 *frame_ref, int32 stack_cell_num, uint8 type, || *(frame_ref - 1) != REF_I64_2)) || (type == VALUE_TYPE_F64 && (*(frame_ref - 2) != REF_F64_1 - || *(frame_ref - 1) != REF_F64_2))) { + || *(frame_ref - 1) != REF_F64_2)) +#if WASM_ENABLE_SIMD != 0 +#if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0) + || (type == VALUE_TYPE_V128 + && (*(frame_ref - 4) != REF_V128_1 + || *(frame_ref - 3) != REF_V128_2 + || *(frame_ref - 2) != REF_V128_3 + || *(frame_ref - 1) != REF_V128_4)) +#endif +#endif + ) { set_error_buf_v(error_buf, error_buf_size, "%s%s%s", "type mismatch: expect ", - type_str[type - VALUE_TYPE_F64], + type_str[type - VALUE_TYPE_V128], " but got other"); return false; } @@ -3922,6 +4070,23 @@ wasm_loader_push_frame_ref(WASMLoaderContext *ctx, uint8 type, ctx->stack_cell_num++; if (ctx->stack_cell_num > ctx->max_stack_cell_num) ctx->max_stack_cell_num = ctx->stack_cell_num; + +#if WASM_ENABLE_SIMD != 0 +#if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0) + if (type == VALUE_TYPE_V128) { + if (!check_stack_push(ctx, error_buf, error_buf_size)) + return false; + *ctx->frame_ref++ = type; + ctx->stack_cell_num++; + if (!check_stack_push(ctx, error_buf, error_buf_size)) + return false; + *ctx->frame_ref++ = type; + ctx->stack_cell_num++; + if (ctx->stack_cell_num > ctx->max_stack_cell_num) + ctx->max_stack_cell_num = ctx->stack_cell_num; + } +#endif +#endif return true; } @@ -3954,6 +4119,15 @@ wasm_loader_pop_frame_ref(WASMLoaderContext *ctx, uint8 type, ctx->frame_ref--; ctx->stack_cell_num--; + +#if WASM_ENABLE_SIMD != 0 +#if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0) + if (type == VALUE_TYPE_V128) { + ctx->frame_ref -= 2; + ctx->stack_cell_num -= 2; + } +#endif +#endif return true; } @@ -4713,6 +4887,13 @@ fail: goto fail; \ } while (0) +#define PUSH_V128() do { \ + if (!(wasm_loader_push_frame_ref_offset(loader_ctx, VALUE_TYPE_V128,\ + disable_emit, operand_offset,\ + error_buf, error_buf_size)))\ + goto fail; \ + } while (0) + #define POP_I32() do { \ if (!wasm_loader_pop_frame_ref_offset(loader_ctx, VALUE_TYPE_I32, \ error_buf, error_buf_size)) \ @@ -4737,6 +4918,12 @@ fail: goto fail; \ } while (0) +#define POP_V128() do { \ + if (!wasm_loader_pop_frame_ref_offset(loader_ctx, VALUE_TYPE_V128, \ + error_buf, error_buf_size)) \ + goto fail; \ + } while (0) + #define PUSH_OFFSET_TYPE(type) do { \ if (!(wasm_loader_push_frame_offset(loader_ctx, type, \ disable_emit, operand_offset, \ @@ -4793,6 +4980,12 @@ fail: goto fail; \ } while (0) +#define PUSH_V128() do { \ + if (!(wasm_loader_push_frame_ref(loader_ctx, VALUE_TYPE_V128, \ + error_buf, error_buf_size))) \ + goto fail; \ + } while (0) + #define POP_I32() do { \ if (!(wasm_loader_pop_frame_ref(loader_ctx, VALUE_TYPE_I32, \ error_buf, error_buf_size))) \ @@ -4817,6 +5010,12 @@ fail: goto fail; \ } while (0) +#define POP_V128() do { \ + if (!(wasm_loader_pop_frame_ref(loader_ctx, VALUE_TYPE_V128, \ + error_buf, error_buf_size))) \ + goto fail; \ + } while (0) + #define POP_AND_PUSH(type_pop, type_push) do { \ if (!(wasm_loader_push_pop_frame_ref(loader_ctx, 1, \ type_push, type_pop, \ @@ -5054,8 +5253,8 @@ check_memory_access_align(uint8 opcode, uint32 align, char *error_buf, uint32 error_buf_size) { uint8 mem_access_aligns[] = { - 2, 3, 2, 3, 0, 0, 1, 1, 0, 0, 1, 1, 2, 2, /* loads */ - 2, 3, 2, 3, 0, 1, 0, 1, 2 /* stores */ + 2, 3, 2, 3, 0, 0, 1, 1, 0, 0, 1, 1, 2, 2, /* loads */ + 2, 3, 2, 3, 0, 1, 0, 1, 2 /* stores */ }; bh_assert(opcode >= WASM_OP_I32_LOAD && opcode <= WASM_OP_I64_STORE32); @@ -5067,6 +5266,92 @@ check_memory_access_align(uint8 opcode, uint32 align, return true; } +#if WASM_ENABLE_SIMD != 0 +#if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0) +static bool +check_simd_memory_access_align(uint8 opcode, uint32 align, + char *error_buf, uint32 error_buf_size) +{ + uint8 mem_access_aligns[] = { + 4, /* load */ + 3, 3, 3, 3, 3, 3, /* load and extend */ + 0, 1, 2, 3, /* load and splat */ + 4, /* store */ + }; + + bh_assert(opcode <= SIMD_v128_store); + + if (align > mem_access_aligns[opcode - SIMD_v128_load]) { + set_error_buf(error_buf, error_buf_size, + "alignment must not be larger than natural"); + return false; + } + + return true; +} + +static bool +check_simd_access_lane(uint8 opcode, uint8 lane, + char *error_buf, uint32 error_buf_size) +{ + switch (opcode) { + case SIMD_i8x16_extract_lane_s: + case SIMD_i8x16_extract_lane_u: + case SIMD_i8x16_replace_lane: + if (lane >= 16) { + goto fail; + } + break; + case SIMD_i16x8_extract_lane_s: + case SIMD_i16x8_extract_lane_u: + case SIMD_i16x8_replace_lane: + if (lane >= 8) { + goto fail; + } + break; + case SIMD_i32x4_extract_lane: + case SIMD_i32x4_replace_lane: + case SIMD_f32x4_extract_lane: + case SIMD_f32x4_replace_lane: + if (lane >= 4) { + goto fail; + } + break; + case SIMD_i64x2_extract_lane: + case SIMD_i64x2_replace_lane: + case SIMD_f64x2_extract_lane: + case SIMD_f64x2_replace_lane: + if (lane >= 2) { + goto fail; + } + break; + default: + goto fail; + } + + return true; +fail: + set_error_buf(error_buf, error_buf_size, "invalid lane index"); + return false; +} + +static bool +check_simd_shuffle_mask(V128 mask, + char *error_buf, + uint32 error_buf_size) +{ + uint8 i; + for (i = 0; i != 16; ++i) { + if (mask.i8x16[i] < 0 || mask.i8x16[i] >= 32) { + set_error_buf(error_buf, error_buf_size, "invalid lane index"); + return false; + } + } + return true; +} +#endif /* end of (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0) */ +#endif /* end of WASM_ENABLE_SIMD */ + #if WASM_ENABLE_SHARED_MEMORY != 0 static bool check_memory_align_equal(uint8 opcode, uint32 align, @@ -5104,6 +5389,7 @@ is_value_type(uint8 type) type == VALUE_TYPE_I64 || type == VALUE_TYPE_F32 || type == VALUE_TYPE_F64 || + type == VALUE_TYPE_V128 || type == VALUE_TYPE_VOID; } @@ -5892,7 +6178,7 @@ handle_op_block_and_loop: #if WASM_ENABLE_TAIL_CALL != 0 } else { - char *type_str[] = { "f64", "f32", "i64", "i32" }; + char *type_str[] = { "v128", "f64", "f32", "i64", "i32" }; uint8 type; if (func_type->result_count != func->func_type->result_count) { set_error_buf_v(error_buf, error_buf_size, @@ -5906,7 +6192,7 @@ handle_op_block_and_loop: if (func_type->types[func_type->param_count + i] != type) { set_error_buf_v(error_buf, error_buf_size, "%s%s%s", "type mismatch: expect ", - type_str[type - VALUE_TYPE_F64], + type_str[type - VALUE_TYPE_V128], " but got other"); goto fail; } @@ -5982,7 +6268,7 @@ handle_op_block_and_loop: #if WASM_ENABLE_TAIL_CALL != 0 } else { - char *type_str[] = { "f64", "f32", "i64", "i32" }; + char *type_str[] = { "v128", "f64", "f32", "i64", "i32" }; uint8 type; if (func_type->result_count != func->func_type->result_count) { set_error_buf_v(error_buf, error_buf_size, @@ -5996,7 +6282,7 @@ handle_op_block_and_loop: if (func_type->types[func_type->param_count + i] != type) { set_error_buf_v(error_buf, error_buf_size, "%s%s%s", "type mismatch: expect ", - type_str[type - VALUE_TYPE_F64], + type_str[type - VALUE_TYPE_V128], " but got other"); goto fail; } @@ -6037,7 +6323,8 @@ handle_op_block_and_loop: loader_ctx->dynamic_offset --; #endif } - else { + else if (*(loader_ctx->frame_ref - 1) == REF_I64_1 + || *(loader_ctx->frame_ref - 1) == REF_F64_1) { loader_ctx->frame_ref -= 2; loader_ctx->stack_cell_num -= 2; #if (WASM_ENABLE_FAST_INTERP == 0) || (WASM_ENABLE_JIT != 0) @@ -6051,6 +6338,10 @@ handle_op_block_and_loop: loader_ctx->dynamic_offset -= 2; #endif } + else { /* V128 */ + loader_ctx->frame_ref -= 4; + loader_ctx->stack_cell_num -= 4; + } } else { #if WASM_ENABLE_FAST_INTERP != 0 @@ -6889,6 +7180,376 @@ fail_data_cnt_sec_require: } break; } + +#if WASM_ENABLE_SIMD != 0 +#if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0) + case WASM_OP_SIMD_PREFIX: + { + uint8 lane; + + opcode = read_uint8(p); + switch (opcode) { + case SIMD_v128_load: + case SIMD_i16x8_load8x8_s: + case SIMD_i16x8_load8x8_u: + case SIMD_i32x4_load16x4_s: + case SIMD_i32x4_load16x4_u: + case SIMD_i64x2_load32x2_s: + case SIMD_i64x2_load32x2_u: + case SIMD_v8x16_load_splat: + case SIMD_v16x8_load_splat: + case SIMD_v32x4_load_splat: + case SIMD_v64x2_load_splat: + { + CHECK_MEMORY(); + + read_leb_uint32(p, p_end, align); /* align */ + if (!check_simd_memory_access_align( + opcode, align, error_buf, error_buf_size)) { + goto fail; + } + + read_leb_uint32(p, p_end, mem_offset); /* offset */ + + /* pop(i32 %i), push(v128 *result) */ + POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_V128); + break; + } + + case SIMD_v128_store: + { + CHECK_MEMORY(); + + read_leb_uint32(p, p_end, align); /* align */ + if (!check_simd_memory_access_align( + opcode, align, error_buf, error_buf_size)) { + goto fail; + } + + read_leb_uint32(p, p_end, mem_offset); /* offset */ + + /* pop(v128 %value) */ + POP_V128(); + /* pop(i32 %i) */ + POP_I32(); + break; + } + + case SIMD_v128_const: + CHECK_BUF1(p, p_end, 16); + p += 16; + PUSH_V128(); + break; + + case SIMD_v8x16_shuffle: + { + V128 mask; + + CHECK_BUF1(p, p_end, 16); + mask = read_i8x16(p, error_buf, error_buf_size); + p += 16; + if (!check_simd_shuffle_mask(mask, error_buf, + error_buf_size)) { + goto fail; + } + + POP2_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128); + break; + } + + case SIMD_v8x16_swizzle: + POP2_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128); + break; + + case SIMD_i8x16_splat: + case SIMD_i16x8_splat: + case SIMD_i32x4_splat: + POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_V128); + break; + case SIMD_i64x2_splat: + POP_AND_PUSH(VALUE_TYPE_I64, VALUE_TYPE_V128); + break; + case SIMD_f32x4_splat: + POP_AND_PUSH(VALUE_TYPE_F32, VALUE_TYPE_V128); + break; + case SIMD_f64x2_splat: + POP_AND_PUSH(VALUE_TYPE_F64, VALUE_TYPE_V128); + break; + + case SIMD_i8x16_extract_lane_s: + case SIMD_i8x16_extract_lane_u: + case SIMD_i16x8_extract_lane_s: + case SIMD_i16x8_extract_lane_u: + case SIMD_i32x4_extract_lane: + CHECK_BUF(p, p_end, 1); + lane = read_uint8(p); + + if (!check_simd_access_lane(opcode, lane, error_buf, + error_buf_size)) { + goto fail; + } + + POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_I32); + break; + case SIMD_i64x2_extract_lane: + CHECK_BUF(p, p_end, 1); + lane = read_uint8(p); + + if (!check_simd_access_lane(opcode, lane, error_buf, + error_buf_size)) { + goto fail; + } + + POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_I64); + break; + case SIMD_f32x4_extract_lane: + CHECK_BUF(p, p_end, 1); + lane = read_uint8(p); + + if (!check_simd_access_lane(opcode, lane, error_buf, + error_buf_size)) { + goto fail; + } + + POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_F32); + break; + case SIMD_f64x2_extract_lane: + CHECK_BUF(p, p_end, 1); + lane = read_uint8(p); + + if (!check_simd_access_lane(opcode, lane, error_buf, + error_buf_size)) { + goto fail; + } + + POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_F64); + break; + case SIMD_i8x16_replace_lane: + case SIMD_i16x8_replace_lane: + case SIMD_i32x4_replace_lane: + CHECK_BUF(p, p_end, 1); + lane = read_uint8(p); + + if (!check_simd_access_lane(opcode, lane, error_buf, + error_buf_size)) { + goto fail; + } + + POP_I32(); + POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128); + break; + case SIMD_i64x2_replace_lane: + CHECK_BUF(p, p_end, 1); + lane = read_uint8(p); + + if (!check_simd_access_lane(opcode, lane, error_buf, + error_buf_size)) { + goto fail; + } + + POP_I64(); + POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128); + break; + case SIMD_f32x4_replace_lane: + CHECK_BUF(p, p_end, 1); + lane = read_uint8(p); + + if (!check_simd_access_lane(opcode, lane, error_buf, + error_buf_size)) { + goto fail; + } + + POP_F32(); + POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128); + break; + case SIMD_f64x2_replace_lane: + CHECK_BUF(p, p_end, 1); + lane = read_uint8(p); + + if (!check_simd_access_lane(opcode, lane, error_buf, + error_buf_size)) { + goto fail; + } + + POP_F64(); + POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128); + break; + case SIMD_i8x16_eq: + case SIMD_i8x16_ne: + case SIMD_i8x16_lt_s: + case SIMD_i8x16_lt_u: + case SIMD_i8x16_gt_s: + case SIMD_i8x16_gt_u: + case SIMD_i8x16_le_s: + case SIMD_i8x16_le_u: + case SIMD_i8x16_ge_s: + case SIMD_i8x16_ge_u: + case SIMD_i16x8_eq: + case SIMD_i16x8_ne: + case SIMD_i16x8_lt_s: + case SIMD_i16x8_lt_u: + case SIMD_i16x8_gt_s: + case SIMD_i16x8_gt_u: + case SIMD_i16x8_le_s: + case SIMD_i16x8_le_u: + case SIMD_i16x8_ge_s: + case SIMD_i16x8_ge_u: + case SIMD_i32x4_eq: + case SIMD_i32x4_ne: + case SIMD_i32x4_lt_s: + case SIMD_i32x4_lt_u: + case SIMD_i32x4_gt_s: + case SIMD_i32x4_gt_u: + case SIMD_i32x4_le_s: + case SIMD_i32x4_le_u: + case SIMD_i32x4_ge_s: + case SIMD_i32x4_ge_u: + case SIMD_f32x4_eq: + case SIMD_f32x4_ne: + case SIMD_f32x4_lt: + case SIMD_f32x4_gt: + case SIMD_f32x4_le: + case SIMD_f32x4_ge: + case SIMD_f64x2_eq: + case SIMD_f64x2_ne: + case SIMD_f64x2_lt: + case SIMD_f64x2_gt: + case SIMD_f64x2_le: + case SIMD_f64x2_ge: + POP2_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128); + break; + + case SIMD_v128_not: + case SIMD_i8x16_abs: + case SIMD_i8x16_neg: + case SIMD_i16x8_abs: + case SIMD_i16x8_neg: + case SIMD_i32x4_abs: + case SIMD_i32x4_neg: + case SIMD_i64x2_neg: + case SIMD_f32x4_abs: + case SIMD_f32x4_neg: + case SIMD_f32x4_sqrt: + case SIMD_f64x2_abs: + case SIMD_f64x2_neg: + case SIMD_f64x2_sqrt: + case SIMD_i16x8_widen_low_i8x16_s: + case SIMD_i16x8_widen_high_i8x16_s: + case SIMD_i16x8_widen_low_i8x16_u: + case SIMD_i16x8_widen_high_i8x16_u: + case SIMD_i32x4_widen_low_i16x8_s: + case SIMD_i32x4_widen_high_i16x8_s: + case SIMD_i32x4_widen_low_i16x8_u: + case SIMD_i32x4_widen_high_i16x8_u: + case SIMD_i32x4_trunc_sat_f32x4_s: + case SIMD_i32x4_trunc_sat_f32x4_u: + case SIMD_f32x4_convert_i32x4_s: + case SIMD_f32x4_convert_i32x4_u: + POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128); + break; + + case SIMD_v128_bitselect: + POP_V128(); + POP2_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128); + break; + + case SIMD_i8x16_any_true: + case SIMD_i8x16_all_true: + case SIMD_i8x16_bitmask: + case SIMD_i16x8_any_true: + case SIMD_i16x8_all_true: + case SIMD_i16x8_bitmask: + case SIMD_i32x4_any_true: + case SIMD_i32x4_all_true: + case SIMD_i32x4_bitmask: + POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_I32); + break; + + case SIMD_i8x16_shl: + case SIMD_i8x16_shr_s: + case SIMD_i8x16_shr_u: + case SIMD_i16x8_shl: + case SIMD_i16x8_shr_s: + case SIMD_i16x8_shr_u: + case SIMD_i32x4_shl: + case SIMD_i32x4_shr_s: + case SIMD_i32x4_shr_u: + case SIMD_i64x2_shl: + case SIMD_i64x2_shr_s: + case SIMD_i64x2_shr_u: + POP_I32(); + POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128); + break; + + case SIMD_i8x16_narrow_i16x8_s: + case SIMD_i8x16_narrow_i16x8_u: + case SIMD_i16x8_narrow_i32x4_s: + case SIMD_i16x8_narrow_i32x4_u: + case SIMD_v128_and: + case SIMD_v128_andnot: + case SIMD_v128_or: + case SIMD_v128_xor: + case SIMD_i8x16_add: + case SIMD_i8x16_add_saturate_s: + case SIMD_i8x16_add_saturate_u: + case SIMD_i8x16_sub: + case SIMD_i8x16_sub_saturate_s: + case SIMD_i8x16_sub_saturate_u: + case SIMD_i8x16_min_s: + case SIMD_i8x16_min_u: + case SIMD_i8x16_max_s: + case SIMD_i8x16_max_u: + case SIMD_i8x16_avgr_u: + case SIMD_i16x8_add: + case SIMD_i16x8_add_saturate_s: + case SIMD_i16x8_add_saturate_u: + case SIMD_i16x8_sub: + case SIMD_i16x8_sub_saturate_s: + case SIMD_i16x8_sub_saturate_u: + case SIMD_i16x8_mul: + case SIMD_i16x8_min_s: + case SIMD_i16x8_min_u: + case SIMD_i16x8_max_s: + case SIMD_i16x8_max_u: + case SIMD_i16x8_avgr_u: + case SIMD_i32x4_add: + case SIMD_i32x4_sub: + case SIMD_i32x4_mul: + case SIMD_i32x4_min_s: + case SIMD_i32x4_min_u: + case SIMD_i32x4_max_s: + case SIMD_i32x4_max_u: + case SIMD_i64x2_add: + case SIMD_i64x2_sub: + case SIMD_i64x2_mul: + case SIMD_f32x4_add: + case SIMD_f32x4_sub: + case SIMD_f32x4_mul: + case SIMD_f32x4_div: + case SIMD_f32x4_min: + case SIMD_f32x4_max: + case SIMD_f64x2_add: + case SIMD_f64x2_sub: + case SIMD_f64x2_mul: + case SIMD_f64x2_div: + case SIMD_f64x2_min: + case SIMD_f64x2_max: + POP2_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128); + break; + + default: + if (error_buf != NULL) { + snprintf(error_buf, error_buf_size, + "WASM module load failed: " + "invalid opcode 0xfd %02x.", opcode); + } + goto fail; + } + break; + } +#endif /* end of (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0) */ +#endif /* end of WASM_ENABLE_SIMD */ + #if WASM_ENABLE_SHARED_MEMORY != 0 case WASM_OP_ATOMIC_PREFIX: { @@ -7031,6 +7692,7 @@ fail_data_cnt_sec_require: break; } #endif /* end of WASM_ENABLE_SHARED_MEMORY */ + default: set_error_buf_v(error_buf, error_buf_size, "%s %02x", diff --git a/core/iwasm/interpreter/wasm_opcode.h b/core/iwasm/interpreter/wasm_opcode.h index 65c1dbf7e..650e9f25a 100644 --- a/core/iwasm/interpreter/wasm_opcode.h +++ b/core/iwasm/interpreter/wasm_opcode.h @@ -263,6 +263,7 @@ typedef enum WASMOpcode { /* Post-MVP extend op prefix */ WASM_OP_MISC_PREFIX = 0xfc, + WASM_OP_SIMD_PREFIX = 0xfd, WASM_OP_ATOMIC_PREFIX = 0xfe, } WASMOpcode; @@ -286,6 +287,220 @@ typedef enum WASMMiscEXTOpcode { #endif } WASMMiscEXTOpcode; +typedef enum WASMSimdEXTOpcode { + /* memory instruction */ + SIMD_v128_load = 0x00, + SIMD_i16x8_load8x8_s = 0x01, + SIMD_i16x8_load8x8_u = 0x02, + SIMD_i32x4_load16x4_s = 0x03, + SIMD_i32x4_load16x4_u = 0x04, + SIMD_i64x2_load32x2_s = 0x05, + SIMD_i64x2_load32x2_u = 0x06, + SIMD_v8x16_load_splat = 0x07, + SIMD_v16x8_load_splat = 0x08, + SIMD_v32x4_load_splat = 0x09, + SIMD_v64x2_load_splat = 0x0a, + SIMD_v128_store = 0x0b, + + /* basic operation */ + SIMD_v128_const = 0x0c, + SIMD_v8x16_shuffle = 0x0d, + SIMD_v8x16_swizzle = 0x0e, + + /* splat operation */ + SIMD_i8x16_splat = 0x0f, + SIMD_i16x8_splat = 0x10, + SIMD_i32x4_splat = 0x11, + SIMD_i64x2_splat = 0x12, + SIMD_f32x4_splat = 0x13, + SIMD_f64x2_splat = 0x14, + + /* lane operation */ + SIMD_i8x16_extract_lane_s = 0x15, + SIMD_i8x16_extract_lane_u = 0x16, + SIMD_i8x16_replace_lane = 0x17, + SIMD_i16x8_extract_lane_s = 0x18, + SIMD_i16x8_extract_lane_u = 0x19, + SIMD_i16x8_replace_lane = 0x1a, + SIMD_i32x4_extract_lane = 0x1b, + SIMD_i32x4_replace_lane = 0x1c, + SIMD_i64x2_extract_lane = 0x1d, + SIMD_i64x2_replace_lane = 0x1e, + SIMD_f32x4_extract_lane = 0x1f, + SIMD_f32x4_replace_lane = 0x20, + SIMD_f64x2_extract_lane = 0x21, + SIMD_f64x2_replace_lane = 0x22, + + /* i8x16 compare operation */ + SIMD_i8x16_eq = 0x23, + SIMD_i8x16_ne = 0x24, + SIMD_i8x16_lt_s = 0x25, + SIMD_i8x16_lt_u = 0x26, + SIMD_i8x16_gt_s = 0x27, + SIMD_i8x16_gt_u = 0x28, + SIMD_i8x16_le_s = 0x29, + SIMD_i8x16_le_u = 0x2a, + SIMD_i8x16_ge_s = 0x2b, + SIMD_i8x16_ge_u = 0x2c, + + /* i16x8 compare operation */ + SIMD_i16x8_eq = 0x2d, + SIMD_i16x8_ne = 0x2e, + SIMD_i16x8_lt_s = 0x2f, + SIMD_i16x8_lt_u = 0x30, + SIMD_i16x8_gt_s = 0x31, + SIMD_i16x8_gt_u = 0x32, + SIMD_i16x8_le_s = 0x33, + SIMD_i16x8_le_u = 0x34, + SIMD_i16x8_ge_s = 0x35, + SIMD_i16x8_ge_u = 0x36, + + /* i32x4 compare operation */ + SIMD_i32x4_eq = 0x37, + SIMD_i32x4_ne = 0x38, + SIMD_i32x4_lt_s = 0x39, + SIMD_i32x4_lt_u = 0x3a, + SIMD_i32x4_gt_s = 0x3b, + SIMD_i32x4_gt_u = 0x3c, + SIMD_i32x4_le_s = 0x3d, + SIMD_i32x4_le_u = 0x3e, + SIMD_i32x4_ge_s = 0x3f, + SIMD_i32x4_ge_u = 0x40, + + /* f32x4 compare operation */ + SIMD_f32x4_eq = 0x41, + SIMD_f32x4_ne = 0x42, + SIMD_f32x4_lt = 0x43, + SIMD_f32x4_gt = 0x44, + SIMD_f32x4_le = 0x45, + SIMD_f32x4_ge = 0x46, + + /* f64x2 compare operation */ + SIMD_f64x2_eq = 0x47, + SIMD_f64x2_ne = 0x48, + SIMD_f64x2_lt = 0x49, + SIMD_f64x2_gt = 0x4a, + SIMD_f64x2_le = 0x4b, + SIMD_f64x2_ge = 0x4c, + + /* v128 operation */ + SIMD_v128_not = 0x4d, + SIMD_v128_and = 0x4e, + SIMD_v128_andnot = 0x4f, + SIMD_v128_or = 0x50, + SIMD_v128_xor = 0x51, + SIMD_v128_bitselect = 0x52, + + /* i8x16 Operation */ + SIMD_i8x16_abs = 0x60, + SIMD_i8x16_neg = 0x61, + SIMD_i8x16_any_true = 0x62, + SIMD_i8x16_all_true = 0x63, + SIMD_i8x16_bitmask = 0x64, + SIMD_i8x16_narrow_i16x8_s = 0x65, + SIMD_i8x16_narrow_i16x8_u = 0x66, + SIMD_i8x16_shl = 0x6b, + SIMD_i8x16_shr_s = 0x6c, + SIMD_i8x16_shr_u = 0x6d, + SIMD_i8x16_add = 0x6e, + SIMD_i8x16_add_saturate_s = 0x6f, + SIMD_i8x16_add_saturate_u = 0x70, + SIMD_i8x16_sub = 0x71, + SIMD_i8x16_sub_saturate_s = 0x72, + SIMD_i8x16_sub_saturate_u = 0x73, + SIMD_i8x16_min_s = 0x76, + SIMD_i8x16_min_u = 0x77, + SIMD_i8x16_max_s = 0x78, + SIMD_i8x16_max_u = 0x79, + SIMD_i8x16_avgr_u = 0x7b, + + /* i16x8 operation */ + SIMD_i16x8_abs = 0x80, + SIMD_i16x8_neg = 0x81, + SIMD_i16x8_any_true = 0x82, + SIMD_i16x8_all_true = 0x83, + SIMD_i16x8_bitmask = 0x84, + SIMD_i16x8_narrow_i32x4_s = 0x85, + SIMD_i16x8_narrow_i32x4_u = 0x86, + SIMD_i16x8_widen_low_i8x16_s = 0x87, + SIMD_i16x8_widen_high_i8x16_s = 0x88, + SIMD_i16x8_widen_low_i8x16_u = 0x89, + SIMD_i16x8_widen_high_i8x16_u = 0x8a, + SIMD_i16x8_shl = 0x8b, + SIMD_i16x8_shr_s = 0x8c, + SIMD_i16x8_shr_u = 0x8d, + SIMD_i16x8_add = 0x8e, + SIMD_i16x8_add_saturate_s = 0x8f, + SIMD_i16x8_add_saturate_u = 0x90, + SIMD_i16x8_sub = 0x91, + SIMD_i16x8_sub_saturate_s = 0x92, + SIMD_i16x8_sub_saturate_u = 0x93, + SIMD_i16x8_mul = 0x95, + SIMD_i16x8_min_s = 0x96, + SIMD_i16x8_min_u = 0x97, + SIMD_i16x8_max_s = 0x98, + SIMD_i16x8_max_u = 0x99, + SIMD_i16x8_avgr_u = 0x9b, + + /* i32x4 operation */ + SIMD_i32x4_abs = 0xa0, + SIMD_i32x4_neg = 0xa1, + SIMD_i32x4_any_true = 0xa2, + SIMD_i32x4_all_true = 0xa3, + SIMD_i32x4_bitmask = 0xa4, + SIMD_i32x4_widen_low_i16x8_s = 0xa7, + SIMD_i32x4_widen_high_i16x8_s = 0xa8, + SIMD_i32x4_widen_low_i16x8_u = 0xa9, + SIMD_i32x4_widen_high_i16x8_u = 0xaa, + SIMD_i32x4_shl = 0xab, + SIMD_i32x4_shr_s = 0xac, + SIMD_i32x4_shr_u = 0xad, + SIMD_i32x4_add = 0xae, + SIMD_i32x4_sub = 0xb1, + SIMD_i32x4_mul = 0xb5, + SIMD_i32x4_min_s = 0xb6, + SIMD_i32x4_min_u = 0xb7, + SIMD_i32x4_max_s = 0xb8, + SIMD_i32x4_max_u = 0xb9, + + /* i64x2 operation */ + SIMD_i64x2_neg = 0xc1, + SIMD_i64x2_shl = 0xcb, + SIMD_i64x2_shr_s = 0xcc, + SIMD_i64x2_shr_u = 0xcd, + SIMD_i64x2_add = 0xce, + SIMD_i64x2_sub = 0xd1, + SIMD_i64x2_mul = 0xd5, + + /* f32x4 operation */ + SIMD_f32x4_abs = 0xe0, + SIMD_f32x4_neg = 0xe1, + SIMD_f32x4_sqrt = 0xe3, + SIMD_f32x4_add = 0xe4, + SIMD_f32x4_sub = 0xe5, + SIMD_f32x4_mul = 0xe6, + SIMD_f32x4_div = 0xe7, + SIMD_f32x4_min = 0xe8, + SIMD_f32x4_max = 0xe9, + + /* f64x2 operation */ + SIMD_f64x2_abs = 0xec, + SIMD_f64x2_neg = 0xed, + SIMD_f64x2_sqrt = 0xef, + SIMD_f64x2_add = 0xf0, + SIMD_f64x2_sub = 0xf1, + SIMD_f64x2_mul = 0xf2, + SIMD_f64x2_div = 0xf3, + SIMD_f64x2_min = 0xf4, + SIMD_f64x2_max = 0xf5, + + /* conversion operation */ + SIMD_i32x4_trunc_sat_f32x4_s = 0xf8, + SIMD_i32x4_trunc_sat_f32x4_u = 0xf9, + SIMD_f32x4_convert_i32x4_s = 0xfa, + SIMD_f32x4_convert_i32x4_u = 0xfb, +} WASMSimdEXTOpcode; + typedef enum WASMAtomicEXTOpcode { /* atomic wait and notify */ WASM_OP_ATOMIC_NOTIFY = 0x00, diff --git a/core/iwasm/libraries/libc-emcc/libc_emcc_wrapper.c b/core/iwasm/libraries/libc-emcc/libc_emcc_wrapper.c index 0e3652b39..0930fbc1a 100644 --- a/core/iwasm/libraries/libc-emcc/libc_emcc_wrapper.c +++ b/core/iwasm/libraries/libc-emcc/libc_emcc_wrapper.c @@ -23,6 +23,90 @@ #define REG_NATIVE_FUNC(func_name, signature) \ { #func_name, func_name##_wrapper, signature, NULL } +extern bool +wasm_runtime_call_indirect(wasm_exec_env_t exec_env, + uint32 element_idx, + uint32 argc, uint32 argv[]); + +static void +invoke_viiii_wrapper(wasm_exec_env_t exec_env, uint32 elem_idx, + int arg0, int arg1, int arg2, int arg3) +{ + uint32 argv[4]; + bool ret; + + argv[0] = arg0; + argv[1] = arg1; + argv[2] = arg2; + argv[3] = arg3; + ret = wasm_runtime_call_indirect(exec_env, elem_idx, 4, argv); + (void)ret; +} + +static void +invoke_viii_wrapper(wasm_exec_env_t exec_env, uint32 elem_idx, + int arg0, int arg1, int arg2) +{ + uint32 argv[4]; + bool ret; + + argv[0] = arg0; + argv[1] = arg1; + argv[2] = arg2; + ret = wasm_runtime_call_indirect(exec_env, elem_idx, 3, argv); + (void)ret; +} + +static void +invoke_vii_wrapper(wasm_exec_env_t exec_env, + uint32 elem_idx, int arg0, int arg1) +{ + uint32 argv[4]; + bool ret; + + argv[0] = arg0; + argv[1] = arg1; + ret = wasm_runtime_call_indirect(exec_env, elem_idx, 2, argv); + (void)ret; +} + +static void +invoke_vi_wrapper(wasm_exec_env_t exec_env, + uint32 elem_idx, int arg0) +{ + uint32 argv[4]; + bool ret; + + argv[0] = arg0; + ret = wasm_runtime_call_indirect(exec_env, elem_idx, 1, argv); + (void)ret; +} + +static int +invoke_iii_wrapper(wasm_exec_env_t exec_env, + uint32 elem_idx, int arg0, int arg1) +{ + uint32 argv[4]; + bool ret; + + argv[0] = arg0; + argv[1] = arg1; + ret = wasm_runtime_call_indirect(exec_env, elem_idx, 2, argv); + return ret ? argv[0] : 0; +} + +static int +invoke_ii_wrapper(wasm_exec_env_t exec_env, + uint32 elem_idx, int arg0) +{ + uint32 argv[4]; + bool ret; + + argv[0] = arg0; + ret = wasm_runtime_call_indirect(exec_env, elem_idx, 1, argv); + return ret ? argv[0] : 0; +} + struct timespec_emcc { int tv_sec; int tv_nsec; @@ -174,10 +258,111 @@ getentropy_wrapper(wasm_exec_env_t exec_env, void *buffer, uint32 length) return getentropy(buffer, length); } +#if !defined(BH_PLATFORM_LINUX_SGX) +static FILE *file_list[32] = { 0 }; + +static int +get_free_file_slot() +{ + unsigned int i; + + for (i = 0; i < sizeof(file_list) / sizeof(FILE *); i++) { + if (file_list[i] == NULL) + return (int)i; + } + return -1; +} + +static int +fopen_wrapper(wasm_exec_env_t exec_env, + const char *pathname, + const char *mode) +{ + FILE *file; + int file_id; + + if (pathname == NULL || mode == NULL) + return -1; + + if ((file_id = get_free_file_slot()) == -1) + return -1; + + file = fopen(pathname, mode); + file_list[file_id] = file; + return file_id + 1; +} + +static uint32 +fread_wrapper(wasm_exec_env_t exec_env, + void *ptr, uint32 size, uint32 nmemb, int file_id) +{ + FILE *file; + + file_id = file_id - 1; + if ((unsigned)file_id >= sizeof(file_list) / sizeof(FILE *)) { + return 0; + } + if ((file = file_list[file_id]) == NULL) { + return 0; + } + return (uint32)fread(ptr, size, nmemb, file); +} + +static uint32 +emcc_fwrite_wrapper(wasm_exec_env_t exec_env, + const void *ptr, uint32 size, uint32 nmemb, + int file_id) +{ + FILE *file; + + file_id = file_id - 1; + if ((unsigned)file_id >= sizeof(file_list) / sizeof(FILE *)) { + return 0; + } + if ((file = file_list[file_id]) == NULL) { + return 0; + } + return (uint32)fwrite(ptr, size, nmemb, file); +} + +static int +feof_wrapper(wasm_exec_env_t exec_env, int file_id) +{ + FILE *file; + + file_id = file_id - 1; + if ((unsigned)file_id >= sizeof(file_list) / sizeof(FILE *)) + return 1; + if ((file = file_list[file_id]) == NULL) + return 1; + return feof(file); +} + +static int +fclose_wrapper(wasm_exec_env_t exec_env, int file_id) +{ + FILE *file; + + file_id = file_id - 1; + if ((unsigned)file_id >= sizeof(file_list) / sizeof(FILE *)) + return -1; + if ((file = file_list[file_id]) == NULL) + return -1; + file_list[file_id] = NULL; + return fclose(file); +} +#endif /* end of BH_PLATFORM_LINUX_SGX */ + #define REG_NATIVE_FUNC(func_name, signature) \ { #func_name, func_name##_wrapper, signature, NULL } static NativeSymbol native_symbols_libc_emcc[] = { + REG_NATIVE_FUNC(invoke_viiii, "(iiiii)"), + REG_NATIVE_FUNC(invoke_viii, "(iiii)"), + REG_NATIVE_FUNC(invoke_vii, "(iii)"), + REG_NATIVE_FUNC(invoke_vi, "(ii)"), + REG_NATIVE_FUNC(invoke_iii, "(iii)i"), + REG_NATIVE_FUNC(invoke_ii, "(ii)i"), REG_NATIVE_FUNC(open, "($ii)i"), REG_NATIVE_FUNC(__sys_read, "(i*~)i"), REG_NATIVE_FUNC(__sys_stat64, "($*)i"), @@ -186,6 +371,13 @@ static NativeSymbol native_symbols_libc_emcc[] = { REG_NATIVE_FUNC(munmap, "(ii)i"), REG_NATIVE_FUNC(__munmap, "(ii)i"), REG_NATIVE_FUNC(getentropy, "(*~)i"), +#if !defined(BH_PLATFORM_LINUX_SGX) + REG_NATIVE_FUNC(fopen, "($$)i"), + REG_NATIVE_FUNC(fread, "(*iii)i"), + REG_NATIVE_FUNC(emcc_fwrite, "(*iii)i"), + REG_NATIVE_FUNC(feof, "(i)i"), + REG_NATIVE_FUNC(fclose, "(i)i"), +#endif /* end of BH_PLATFORM_LINUX_SGX */ }; uint32 diff --git a/doc/build_wamr.md b/doc/build_wamr.md index 8872f2dab..57a65a738 100644 --- a/doc/build_wamr.md +++ b/doc/build_wamr.md @@ -86,6 +86,10 @@ Currently we only profile the memory consumption of module, module_instance and #### **Enable tail call feature** - **WAMR_BUILD_TAIL_CALL**=1/0, default to disable if not set +#### **Enable 128-bit SIMD feature** +- **WAMR_BUILD_SIMD**=1/0, default to disable if not set +> Note: only supported in AOT mode, and the *--enable-simd* flag should be added for wamrc when generating aot file. + **Combination of configurations:** We can combine the configurations. For example, if we want to disable interpreter, enable AOT and WASI, we can run command: diff --git a/product-mini/platforms/linux/CMakeLists.txt b/product-mini/platforms/linux/CMakeLists.txt index 6b1b6e753..63b49c049 100644 --- a/product-mini/platforms/linux/CMakeLists.txt +++ b/product-mini/platforms/linux/CMakeLists.txt @@ -75,6 +75,11 @@ if (NOT DEFINED WAMR_BUILD_MINI_LOADER) set (WAMR_BUILD_MINI_LOADER 0) endif () +if (NOT DEFINED WAMR_BUILD_SIMD) + # Disable SIMD by default + set (WAMR_BUILD_SIMD 0) +endif () + if (COLLECT_CODE_COVERAGE EQUAL 1) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage") endif () diff --git a/samples/basic/build.sh b/samples/basic/build.sh index 7e3442c5a..cb195efd7 100755 --- a/samples/basic/build.sh +++ b/samples/basic/build.sh @@ -1,3 +1,8 @@ +# +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# + #!/bin/bash CURR_DIR=$PWD diff --git a/samples/gui/build.sh b/samples/gui/build.sh index a57aa48e8..f910f450b 100755 --- a/samples/gui/build.sh +++ b/samples/gui/build.sh @@ -1,3 +1,8 @@ +# +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# + #!/bin/bash PROJECT_DIR=$PWD diff --git a/samples/littlevgl/build.sh b/samples/littlevgl/build.sh index 9e12fe1c3..64e8f9275 100755 --- a/samples/littlevgl/build.sh +++ b/samples/littlevgl/build.sh @@ -1,3 +1,8 @@ +# +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# + #!/bin/bash PROJECT_DIR=$PWD diff --git a/samples/simple/build.sh b/samples/simple/build.sh index 51ec8bc28..ef67aea5d 100755 --- a/samples/simple/build.sh +++ b/samples/simple/build.sh @@ -1,3 +1,8 @@ +# +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# + #!/bin/bash CURR_DIR=$PWD diff --git a/samples/workload/README.md b/samples/workload/README.md new file mode 100644 index 000000000..f32fb4b9c --- /dev/null +++ b/samples/workload/README.md @@ -0,0 +1,34 @@ +All workloads have similar a requirment of software dependencies. It includes +**wasi-sdk**, **clang-11**, **emsdk**, **wabt** and **binaryen** + +> It might slightly different when using MacOS, and other linux distro than Ubuntu. This document only target +Ubuntu 18.04 as an example. + +## Installation instructions + +- **wasi-sdk**. Install + [latest release](https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-11/wasi-sdk-11.0-linux.tar.gz) + in */opt/wasi-sdk* or */opt/wasi-sdk-11* + +- **wabt**. Install + [latest release](https://github.com/WebAssembly/wabt/releases/download/${WABT_VER}/wabt-1.0.19-ubuntu.tar.gz) + in */opt/wabt* or */opt/wabt-1.0.19* + +- **clang-11**. Refer to [the guide](https://apt.llvm.org/). + +- **emsdk**. Refer to [the guide](https://emscripten.org/docs/getting_started/downloads.html). Don't forget to activate + emsdk and set up environment variables. Verify it with `echo ${EMSDK}`. + +- **libclang_rt.builtins-wasm32.a**. *wasi* has its private rt library. Put it under clang search path + +``` shell +# copy it +$ cp -r /opt/wasi-sdk-11.0/lib/clang/10.0.0/lib/wasi /usr/lib/llvm-11/lib/clang/11.0.0/lib/ + +# or just link it +$ ln -sf /opt/wasi-sdk-11.0/lib/clang/10.0.0/lib/wasi/ /usr/lib/llvm-11/lib/clang/11.0.0/lib/ +``` + +- **binaryen**. Install + [latest release](https://github.com/WebAssembly/binaryen/releases/download/version_97/binaryen-version_97-x86_64-linux.tar.gz) + in */opt/binaryen* or */opt/binaryen-version_97* diff --git a/samples/workload/bwa/.gitignore b/samples/workload/bwa/.gitignore new file mode 100644 index 000000000..cd7209590 --- /dev/null +++ b/samples/workload/bwa/.gitignore @@ -0,0 +1,4 @@ +build +libz +bwa +include diff --git a/samples/workload/bwa/CMakeLists.bwa_wasm.txt b/samples/workload/bwa/CMakeLists.bwa_wasm.txt new file mode 100644 index 000000000..8cda6b694 --- /dev/null +++ b/samples/workload/bwa/CMakeLists.bwa_wasm.txt @@ -0,0 +1,134 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required (VERSION 3.0) + +project(bwa_wasm C) + +################ LIBZ ################ +set(LIBZ_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../libz) +add_library(z_wasm STATIC + ${LIBZ_SRC_DIR}/adler32.c + ${LIBZ_SRC_DIR}/compress.c + ${LIBZ_SRC_DIR}/crc32.c + ${LIBZ_SRC_DIR}/deflate.c + ${LIBZ_SRC_DIR}/gzclose.c + ${LIBZ_SRC_DIR}/gzlib.c + ${LIBZ_SRC_DIR}/gzread.c + ${LIBZ_SRC_DIR}/gzwrite.c + ${LIBZ_SRC_DIR}/infback.c + ${LIBZ_SRC_DIR}/inffast.c + ${LIBZ_SRC_DIR}/inflate.c + ${LIBZ_SRC_DIR}/inftrees.c + ${LIBZ_SRC_DIR}/trees.c + ${LIBZ_SRC_DIR}/uncompr.c + ${LIBZ_SRC_DIR}/zutil.c +) + +set_target_properties(z_wasm PROPERTIES LINKER_LANGUAGE C) + +target_compile_definitions(z_wasm PRIVATE Z_HAVE_UNISTD_H _LARGEFILE64_SOURCE=1) + +target_compile_options(z_wasm + PRIVATE + -Wno-unused-function + -Wno-unused-variable +) + +target_include_directories(z_wasm + PUBLIC + ${LIBZ_SRC_DIR} +) + +################ BWA_WASM ################ +set(BWA_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}) +set(BWA_SOURCE + ${BWA_SRC_DIR}/utils.c + ${BWA_SRC_DIR}/kthread.c + ${BWA_SRC_DIR}/kstring.c + ${BWA_SRC_DIR}/ksw.c + ${BWA_SRC_DIR}/bwt.c + ${BWA_SRC_DIR}/bntseq.c + ${BWA_SRC_DIR}/bwa.c + ${BWA_SRC_DIR}/bwamem.c + ${BWA_SRC_DIR}/bwamem_pair.c + ${BWA_SRC_DIR}/bwamem_extra.c + ${BWA_SRC_DIR}/malloc_wrap.c + ${BWA_SRC_DIR}/QSufSort.c + ${BWA_SRC_DIR}/bwt_gen.c + ${BWA_SRC_DIR}/rope.c + ${BWA_SRC_DIR}/rle.c + ${BWA_SRC_DIR}/is.c + ${BWA_SRC_DIR}/bwtindex.c + ${BWA_SRC_DIR}/bwashm.c + ${BWA_SRC_DIR}/bwase.c + ${BWA_SRC_DIR}/bwaseqio.c + ${BWA_SRC_DIR}/bwtgap.c + ${BWA_SRC_DIR}/bwtaln.c + ${BWA_SRC_DIR}/bamlite.c + ${BWA_SRC_DIR}/bwape.c + ${BWA_SRC_DIR}/kopen.c + ${BWA_SRC_DIR}/pemerge.c + ${BWA_SRC_DIR}/maxk.c + ${BWA_SRC_DIR}/bwtsw2_core.c + ${BWA_SRC_DIR}/bwtsw2_main.c + ${BWA_SRC_DIR}/bwtsw2_aux.c + ${BWA_SRC_DIR}/bwt_lite.c + ${BWA_SRC_DIR}/bwtsw2_chain.c + ${BWA_SRC_DIR}/fastmap.c + ${BWA_SRC_DIR}/bwtsw2_pair.c + ${BWA_SRC_DIR}/main.c +) + +add_executable(${PROJECT_NAME} ${BWA_SOURCE}) + +set_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME bwa.wasm) + +target_include_directories(${PROJECT_NAME} + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/../include + ${CMAKE_CURRENT_SOURCE_DIR}/../include/SSE + ${CMAKE_CURRENT_SOURCE_DIR}/../include/pthread +) + +target_compile_definitions(${PROJECT_NAME} + PRIVATE + USE_MALLOC_WRAPPERS + __SSE__ __SSE2__ __SSE4_1__ + _WASI_EMULATED_MMAN _WASI_EMULATED_SIGNAL +) + +target_compile_options(${PROJECT_NAME} + PRIVATE + -Wno-unused-function + -Wno-unused-variable +) + +target_link_options(${PROJECT_NAME} + PRIVATE + -Wno-unused-command-line-argument + LINKER:--allow-undefined,--export=__heap_base,--export=__data_end + LINKER:-z,stack-size=1048576 +) + +target_link_libraries(${PROJECT_NAME} z_wasm) + +find_program(WASM_OPT + NAMES wasm-opt + PATHS /opt/binaryen-version_97/bin /opt/binaryen/bin +) + +if (NOT WASM_OPT) + message(WARNING "can not find wasm-opt and will not optimize any wasm module") +endif() + +add_custom_target(bwa_wasm_opt ALL + COMMAND + ${WASM_OPT} -Oz --enable-simd -o bwa.opt.wasm bwa.wasm + BYPRODUCTS + ${CMAKE_CURRENT_BINARY_DIR}/bwa.opt.wasm + WORKING_DIRECTORY + ${CMAKE_CURRENT_BINARY_DIR} +) + +add_dependencies(bwa_wasm_opt ${PROJECT_NAME}) diff --git a/samples/workload/bwa/CMakeLists.txt b/samples/workload/bwa/CMakeLists.txt new file mode 100644 index 000000000..6e785a149 --- /dev/null +++ b/samples/workload/bwa/CMakeLists.txt @@ -0,0 +1,91 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required (VERSION 3.0) + +project(bwa_wasm) + +################ EMCC ################ +if(NOT DEFINED ENV{EMSDK}) + message(FATAL_ERROR + "can not find emsdk. " + "please refer to https://emscripten.org/docs/getting_started/downloads.html " + "and install it, " + "or active emsdk by 'source ./emsdk_env.sh'" + ) +endif() + +################ BINARYEN ################ +find_program(WASM_OPT + NAMES wasm-opt + PATHS /opt/binaryen-version_97/bin /opt/binaryen/bin +) + +if (NOT WASM_OPT) + message(FATAL_ERROR + "can not find wasm-opt. " + "please download it from " + "https://github.com/WebAssembly/binaryen/releases/download/version_97/binaryen-version_97-x86_64-linux.tar.gz " + "and install it under /opt" + ) +endif() + +####################################### +include(ExternalProject) + +################ HEADERS ################ +ExternalProject_Add(headers_from_emcc + PREFIX headers + SOURCE_DIR "$ENV{EMSDK}/upstream/emscripten/system/include/SSE" + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND mkdir -p ${CMAKE_CURRENT_SOURCE_DIR}/include/SSE + && ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_SOURCE_DIR}/include/pthread/sys + && ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_SOURCE_DIR}/include/emscripten + # copy emscripten SSE header files + && ${CMAKE_COMMAND} -E copy $ENV{EMSDK}/upstream/emscripten/system/include/SSE/immintrin.h ${CMAKE_CURRENT_SOURCE_DIR}/include/SSE/ + # SSE + && ${CMAKE_COMMAND} -E copy $ENV{EMSDK}/upstream/emscripten/system/include/SSE/xmmintrin.h ${CMAKE_CURRENT_SOURCE_DIR}/include/SSE/ + # SSE2 + && ${CMAKE_COMMAND} -E copy $ENV{EMSDK}/upstream/emscripten/system/include/SSE/emmintrin.h ${CMAKE_CURRENT_SOURCE_DIR}/include/SSE/ + # SSE4.1 + && ${CMAKE_COMMAND} -E copy $ENV{EMSDK}/upstream/emscripten/system/include/SSE/smmintrin.h ${CMAKE_CURRENT_SOURCE_DIR}/include/SSE/ + # a fake empty header to aovid further depenency + && ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_SOURCE_DIR}/include/emscripten/emscripten.h + # copy emscripten pthread related header files + && ${CMAKE_COMMAND} -E copy $ENV{EMSDK}/upstream/emscripten/system/include/libc/pthread.h ${CMAKE_CURRENT_SOURCE_DIR}/include/pthread/ + && ${CMAKE_COMMAND} -E copy $ENV{EMSDK}/upstream/emscripten/system/include/libc/signal.h ${CMAKE_CURRENT_SOURCE_DIR}/include/pthread/ + && ${CMAKE_COMMAND} -E copy $ENV{EMSDK}/upstream/emscripten/system/include/libc/netdb.h ${CMAKE_CURRENT_SOURCE_DIR}/include/pthread/ + && ${CMAKE_COMMAND} -E copy $ENV{EMSDK}/upstream/emscripten/system/include/libc/sys/wait.h ${CMAKE_CURRENT_SOURCE_DIR}/include/pthread/sys/ + && ${CMAKE_COMMAND} -E copy $ENV{EMSDK}/upstream/emscripten/system/include/libc/sys/socket.h ${CMAKE_CURRENT_SOURCE_DIR}/include/pthread/sys/ +) + +################ libz ################ +ExternalProject_Add(libz_src + PREFIX libz + GIT_REPOSITORY https://github.com/madler/zlib.git + GIT_TAG master + GIT_PROGRESS ON + GIT_SHALLOW ON + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/libz + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" +) + +################ bwa ################ +ExternalProject_Add(bwa + PREFIX bwa + GIT_REPOSITORY https://github.com/lh3/bwa.git + GIT_TAG master + GIT_PROGRESS ON + GIT_SHALLOW ON + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/bwa + DEPENDS libz_src headers_from_emcc + UPDATE_COMMAND git clean -fd && git checkout -- * + && ${CMAKE_COMMAND} -E echo "Copying pre-installed CMakeLists.txt" + && ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.bwa_wasm.txt CMakeLists.txt + CONFIGURE_COMMAND ${CMAKE_COMMAND} -DCMAKE_TOOLCHAIN_FILE=${CMAKE_CURRENT_SOURCE_DIR}/../cmake/toolchain.cmake ${CMAKE_CURRENT_SOURCE_DIR}/bwa + BUILD_COMMAND make bwa_wasm_opt + INSTALL_COMMAND ${CMAKE_COMMAND} -E copy ./bwa.opt.wasm ${CMAKE_CURRENT_SOURCE_DIR}/build/bwa.wasm +) diff --git a/samples/workload/bwa/README.md b/samples/workload/bwa/README.md new file mode 100644 index 000000000..f9688f6ca --- /dev/null +++ b/samples/workload/bwa/README.md @@ -0,0 +1,47 @@ +"bwa" sample introduction +============== + +This sample demonstrates how to build [bwa](https://github.com/lh3/bwa) into +WebAssembly with simd support and run it with iwasm. + +## Preparation + +please refer to [installation instructions](../README.md). + +## Build + +``` shell +$ mkdir build && cd build +$ cmake .. +$ make +# to verify +$ ls bwa.wasm +``` + +## Download sample data + +Download the bwa-0.7.15 binary package from +[such an address](https://sourceforge.net/projects/bio-bwa/files/bwakit/bwakit-0.7.15_x64-linux.tar.bz2/download), +a sample data file named **hs38DH.fa** will be used later. + +If want more data, please refer to http://hgdownload.cse.ucsc.edu/goldenpath/hg19/bigZips/ + +## Run workload + +Firstly please build iwasm with simd support: + +``` shell +$ cd /product-mini/platforms/linux/ +$ mkdir build && cd build +$ cmake .. -DWAMR_BUILD_SIMD=1 +$ make +``` + +Then compile wasm file to aot file and run: + +``` shell +$ cd /wamr-compiler/build +$ ./wamrc --enable-simd -o bwa.aot ./bwa.wasm +$ cd /product-mini/platforms/linux/ +$ ./iwasm --dir=. ./bwa.aot index hs38DH.fa +``` diff --git a/samples/workload/cmake/toolchain.cmake b/samples/workload/cmake/toolchain.cmake new file mode 100644 index 000000000..4b9ae8fd7 --- /dev/null +++ b/samples/workload/cmake/toolchain.cmake @@ -0,0 +1,100 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required (VERSION 3.0) + +if(DEFINED _WAMR_TOOLCHAIN_CMAKE_) + return() +else() + set(_WAMR_TOOLCHAIN_CMAKE_ 1) +endif() + +SET(CMAKE_SYSTEM_NAME Linux) + +################ COMPILER ################ +find_program(CLANG_11 NAMES clang clang-11 REQUIRED) +find_program(CLANG++_11 NAMES clang++ clang++-11 REQUIRED) + +if(NOT CLANG_11) + message(FATAL_ERROR "clang not found") +else() + message(STATUS "use ${CLANG_11} as the c compiler") +endif() + +if(NOT CLANG++_11) + message(FATAL_ERROR "clang++ not found") +else() + message(STATUS "use ${CLANG++_11} as the c++ compiler") +endif() + +set(CMAKE_C_COMPILER "${CLANG_11}" CACHE STRING "C compiler" FORCE) +set(CMAKE_C_COMPILER_ID Clang CACHE STRING "C compiler ID" FORCE) + +set(CMAKE_CXX_COMPILER "${CLANG++_11}" CACHE STRING "C++ compiler" FORCE) +set(CMAKE_CXX_COMPILER_ID Clang CACHE STRING "C++ compiler ID" FORCE) + +################ WASI AS SYSROOT ################ +find_path(WASI_SYSROOT + wasi-sysroot + PATHS /opt/wasi-sdk-11.0/share /opt/wasi-sdk/share + REQUIRED +) + +if(NOT WASI_SYSROOT) + message(FATAL_ERROR + "can not find wasi sysroot. " + "please download it from " + "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-11/wasi-sdk-11.0-linux.tar.gz " + "and install it under /opt" + ) +endif() + +set(CMAKE_SYSROOT ${WASI_SYSROOT}/wasi-sysroot CACHE STRING "--sysroot to compiler" FORCE) + +add_compile_options( + --target=wasm32-wasi + -msimd128 + $,-O0,-O3> + $<$:-g> + $<$:-v> +) + +################ AR ################ +find_program(LLVM_AR NAMES llvm-ar llvm-ar-11 REQUIRED) + +if(NOT LLVM_AR) + message(FATAL_ERROR "llvm-ar not found") +else() + message(STATUS "use ${LLVM_AR} as the AR") +endif() + +set(CMAKE_AR "${LLVM_AR}" CACHE STRING "AR" FORCE) + +################ RANLIB ################ +find_program(LLVM_RANLIB NAMES llvm-ranlib llvm-ranlib-11 REQUIRED) + +if(NOT LLVM_RANLIB) + message(FATAL_ERROR "llvm-ranlib not found") +else() + message(STATUS "use ${LLVM_RANLIB} as the ranlib") +endif() + +set(CMAKE_RANLIB "${LLVM_RANLIB}" CACHE STRING "RANLIB" FORCE) + +################ LD ################ +find_program(WASM_LD NAMES wasm-ld wasm-ld-11 REQUIRED) + +if(NOT WASM_LD) + message(FATAL_ERROR "wasm-ld not found") +else() + message(STATUS "use ${WASM_LD} as the linker") +endif() + +add_link_options( + --target=wasm32-wasi + -fuse-ld=${WASM_LD} + LINKER:--allow-undefined + $,-O0,-O3> + $<$:-g> + $<$:-v> +) diff --git a/samples/workload/docker/.gitignore b/samples/workload/docker/.gitignore new file mode 100644 index 000000000..9db0a2807 --- /dev/null +++ b/samples/workload/docker/.gitignore @@ -0,0 +1 @@ +build_scripts diff --git a/samples/workload/docker/Dockerfile b/samples/workload/docker/Dockerfile new file mode 100644 index 000000000..56f3adb22 --- /dev/null +++ b/samples/workload/docker/Dockerfile @@ -0,0 +1,77 @@ +FROM ubuntu:18.04 as builder + +# +# install clang and llvm +COPY llvm.sh /tmp +RUN apt update \ + && apt install -y lsb-release wget software-properties-common build-essential \ + && cd /tmp \ + && chmod a+x llvm.sh \ + && ./llvm.sh 11 + +ARG WASI_SDK_VER=11.0 +ARG WABT_VER=1.0.19 +ARG CMAKE_VER=3.16.2 +ARG BINARYEN_VER=version_97 + +# +# install wasi-sdk +ARG WASI_SDK_FILE="wasi-sdk-${WASI_SDK_VER}-linux.tar.gz" +COPY ${WASI_SDK_FILE} /opt +RUN cd /opt \ + && tar zxf ${WASI_SDK_FILE} \ + && rm ${WASI_SDK_FILE} \ + && ln -sf /opt/wasi-sdk-${WASI_SDK_VER} /opt/wasi-sdk \ + && ln -sf /opt/wasi-sdk/lib/clang/10.0.0/lib/wasi/ /usr/lib/llvm-11/lib/clang/11.0.0/lib/ + +# +# install wabt +ARG WABT_FILE="wabt-${WABT_VER}-ubuntu.tar.gz" +COPY ${WABT_FILE} /opt +RUN cd /opt \ + && tar zxf ${WABT_FILE} \ + && rm ${WABT_FILE} \ + && ln -sf /opt/wabt-${WABT_VER} /opt/wabt + +# +# install cmake +ARG CMAKE_FILE="cmake-${CMAKE_VER}-Linux-x86_64.sh" +COPY ${CMAKE_FILE} /tmp +RUN cd /tmp \ + && chmod a+x ${CMAKE_FILE} \ + && mkdir /opt/cmake \ + && ./${CMAKE_FILE} --prefix=/opt/cmake --skip-license \ + && ln -sf /opt/cmake/bin/cmake /usr/local/bin/cmake + +# +# install tools +RUN apt install -y git tree + +# +# install emsdk +RUN cd /opt \ + && git clone https://github.com/emscripten-core/emsdk.git \ + && cd emsdk \ + && git pull \ + && ./emsdk install latest \ + && ./emsdk activate latest \ + && echo "source /opt/emsdk/emsdk_env.sh" >> /root/.bashrc + +# +# install binaryen +ARG BINARYEN_FILE="binaryen-${BINARYEN_VER}-x86_64-linux.tar.gz" +COPY ${BINARYEN_FILE} /opt +RUN cd /opt \ + && tar zxf ${BINARYEN_FILE} \ + && rm ${BINARYEN_FILE} \ + && ln -sf /opt/binaryen-${BINARYEN_VER} /opt/binaryen + +# +# Clean up +RUN apt-get autoremove -y \ + && apt-get clean -y \ + && rm -rf /var/lib/apt/lists/* \ + && rm -rf /tmp/* + +VOLUME /data +WORKDIR /data diff --git a/samples/workload/docker/build.sh b/samples/workload/docker/build.sh new file mode 100755 index 000000000..c73c5bceb --- /dev/null +++ b/samples/workload/docker/build.sh @@ -0,0 +1,48 @@ +# +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# + +#!/bin/bash + +if [[ ! -d build_scripts ]]; then + mkdir build_scripts +fi + +WASI_SDK_VER=11.0 +WABT_VER=1.0.19 +CMAKE_VER=3.16.2 +BINARYEN_VER=version_97 + +cd build_scripts +if [[ ! -f wasi-sdk-${WASI_SDK_VER}-linux.tar.gz ]]; then + wget https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-11/wasi-sdk-${WASI_SDK_VER}-linux.tar.gz +fi + +if [[ ! -f wabt-${WABT_VER}-ubuntu.tar.gz ]]; then + wget https://github.com/WebAssembly/wabt/releases/download/${WABT_VER}/wabt-${WABT_VER}-ubuntu.tar.gz +fi + +if [[ ! -f llvm.sh ]]; then + wget https://apt.llvm.org/llvm.sh +fi + +if [[ ! -f cmake-${CMAKE_VER}-Linux-x86_64.sh ]]; then + wget https://github.com/Kitware/CMake/releases/download/v${CMAKE_VER}/cmake-${CMAKE_VER}-Linux-x86_64.sh +fi + +if [[ ! -f binaryen-${BINARYEN_VER}-x86_64-linux.tar.gz ]]; then + wget https://github.com/WebAssembly/binaryen/releases/download/${BINARYEN_VER}/binaryen-${BINARYEN_VER}-x86_64-linux.tar.gz +fi +cd - + +docker build \ + --build-arg http_proxy=${http_proxy} \ + --build-arg https_proxy=${https_proxy} \ + --build-arg HTTP_PROXY=${http_proxy} \ + --build-arg HTTPS_PROXY=${https_proxy} \ + --build-arg WASI_SDK_VER=11.0 \ + --build-arg WABT_VER=${WABT_VER} \ + --build-arg CMAKE_VER=${CMAKE_VER} \ + --build-arg BINARYEN_VER=${BINARYEN_VER} \ + -t clang_env:0.1 -f Dockerfile build_scripts diff --git a/samples/workload/docker/run.sh b/samples/workload/docker/run.sh new file mode 100755 index 000000000..8c5943027 --- /dev/null +++ b/samples/workload/docker/run.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +docker run --rm -it \ + -e http_proxy=${http_proxy} \ + -e https_proxy=${https_proxy} \ + -e HTTP_PROXY=${http_proxy} \ + -e HTTPS_PROXY=${htpps_proxy} \ + --name workload_w_clang \ + --mount type=bind,source=$(pwd)/..,target=/data \ + clang_env:0.1 diff --git a/samples/workload/meshoptimizer/.gitignore b/samples/workload/meshoptimizer/.gitignore new file mode 100644 index 000000000..dd97754d4 --- /dev/null +++ b/samples/workload/meshoptimizer/.gitignore @@ -0,0 +1,2 @@ +build +meshoptimizer \ No newline at end of file diff --git a/samples/workload/meshoptimizer/CMakeLists.txt b/samples/workload/meshoptimizer/CMakeLists.txt new file mode 100644 index 000000000..1270582df --- /dev/null +++ b/samples/workload/meshoptimizer/CMakeLists.txt @@ -0,0 +1,39 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required (VERSION 3.0) + +project(bench-meshoptimizer) + +################ BINARYEN ################ +find_program(WASM_OPT + NAMES wasm-opt + PATHS /opt/binaryen-version_97/bin /opt/binaryen/bin +) + +if (NOT WASM_OPT) + message(FATAL_ERROR + "can not find wasm-opt. " + "please download it from " + "https://github.com/WebAssembly/binaryen/releases/download/version_97/binaryen-version_97-x86_64-linux.tar.gz " + "and install it under /opt" + ) +endif() + +################ MESHOPTIMIZER ################ +include(ExternalProject) + +ExternalProject_Add(codecbench + PREFIX codecbench + GIT_REPOSITORY https://github.com/zeux/meshoptimizer.git + GIT_TAG master + GIT_SHALLOW ON + GIT_PROGRESS ON + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/meshoptimizer + UPDATE_COMMAND git clean -fd && git checkout -- * + && ${CMAKE_COMMAND} -E echo "Applying patch" + && git apply ${CMAKE_CURRENT_SOURCE_DIR}/codecbench.patch + CONFIGURE_COMMAND ${CMAKE_COMMAND} -DCMAKE_TOOLCHAIN_FILE=${CMAKE_CURRENT_SOURCE_DIR}/../cmake/toolchain.cmake ${CMAKE_CURRENT_SOURCE_DIR}/meshoptimizer + BUILD_COMMAND make codecbench.opt + INSTALL_COMMAND ${CMAKE_COMMAND} -E copy ./codecbench.opt.wasm ${CMAKE_CURRENT_SOURCE_DIR}/build/codecbench.wasm +) diff --git a/samples/workload/meshoptimizer/README.md b/samples/workload/meshoptimizer/README.md new file mode 100644 index 000000000..c29a07afd --- /dev/null +++ b/samples/workload/meshoptimizer/README.md @@ -0,0 +1,59 @@ +"codecbench of meshoptimizer" sample introduction +============== + +This sample demonstrates how to build [codecbench of messoptimizer](https://github.com/zeux/meshoptimizer) into +WebAssembly with simd support and run it with iwasm. + +## Preparation + +please refer to [installation instructions](../README.md). + +## Build with clang-11 and wasi-sdk + +``` shell +$ mkdir build && cd build +$ cmake .. +$ make +# to verify +$ ls codecbench.wasm +``` + +## Or build with EMCC + +EMCC is another toolchain to compile C code to WASM. In this case, will have +a higher performance with EMCC. + +``` shell +$ git clone https://github.com/zeux/meshoptimizer.git +$ cd messoptimizer +$ emcc tools/codecbench.cpp src/vertexcodec.cpp src/vertexfilter.cpp \ + src/overdrawanalyzer.cpp src/indexgenerator.cpp src/vcacheoptimizer.cpp \ + src/clusterizer.cpp src/indexcodec.cpp src/vfetchanalyzer.cpp \ + src/spatialorder.cpp src/allocator.cpp src/vcacheanalyzer.cpp \ + src/vfetchoptimizer.cpp src/overdrawoptimizer.cpp src/simplifier.cpp \ + src/stripifier.cpp -O3 -msimd128 \ + -s TOTAL_MEMORY=268435456 -s "EXPORTED_FUNCTIONS=['_main']" \ + -o codecbench.wasm +$ ls -l codecbench.wasm +``` + +## Run workload + +Firstly please build iwasm with simd support: + +``` shell +$ cd /product-mini/platforms/linux/ +$ mkdir build && cd build +$ cmake .. -DWAMR_BUILD_SIMD=1 +$ make +``` + +Then compile wasm file to aot file and run: + +``` shell +$ cd /wamr-compiler/build +$ ./wamrc --enable-simd -o codecbench.aot codecbench.wasm +$ cd /product-mini/platforms/linux/ +$ ./iwasm codecbench.aot +``` + diff --git a/samples/workload/meshoptimizer/codecbench.patch b/samples/workload/meshoptimizer/codecbench.patch new file mode 100644 index 000000000..4adebed4b --- /dev/null +++ b/samples/workload/meshoptimizer/codecbench.patch @@ -0,0 +1,47 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index eccc49e..dac126c 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -127,3 +127,42 @@ install(FILES + ${CMAKE_CURRENT_BINARY_DIR}/meshoptimizerConfig.cmake + ${CMAKE_CURRENT_BINARY_DIR}/meshoptimizerConfigVersion.cmake + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/meshoptimizer) ++ ++################################################## ++# codecbench ++################################################## ++add_executable(codecbench tools/codecbench.cpp ${SOURCES}) ++ ++set_target_properties(codecbench PROPERTIES OUTPUT_NAME codecbench.wasm) ++ ++target_compile_options(codecbench ++ PUBLIC ++ -std=c++11 ++ -Wno-unused-function ++ -Wno-unused-variable ++) ++ ++target_link_options(codecbench ++ PUBLIC ++ LINKER:-allow-undefined,--demangle ++) ++ ++find_program(WASM_OPT ++ NAMES wasm-opt ++ PATHS /opt/binaryen-version_97/bin /opt/binaryen/bin ++) ++ ++if (NOT WASM_OPT) ++ message(WARNING "can not find wasm-opt and will not optimize any wasm module") ++endif() ++ ++add_custom_target(codecbench.opt ALL ++ COMMAND ++ ${WASM_OPT} -Oz --enable-simd -o codecbench.opt.wasm codecbench.wasm ++ BYPRODUCTS ++ ${CMAKE_CURRENT_BINARY_DIR}/codecbench.opt.wasm ++ WORKING_DIRECTORY ++ ${CMAKE_CURRENT_BINARY_DIR} ++) ++ ++add_dependencies(codecbench.opt codecbench) diff --git a/samples/workload/tensorflow/build.sh b/samples/workload/tensorflow/build.sh index d519ec5b0..ec9424842 100755 --- a/samples/workload/tensorflow/build.sh +++ b/samples/workload/tensorflow/build.sh @@ -1,8 +1,20 @@ +# +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# + #!/bin/bash #################################### # build tensorflow-lite sample # #################################### +if [ ! -d "${EMSDK}" ]; then + echo "can not find emsdk. " + echo "please refer to https://emscripten.org/docs/getting_started/downloads.html " + echo "to install it, or active it by 'source emsdk_env.sh'" + exit +fi + set -xe EMSDK_WASM_DIR="$EM_CACHE/wasm" @@ -64,7 +76,15 @@ fi if [ -d "${TF_LITE_BUILD_DIR}/gen" ]; then rm -fr ${TF_LITE_BUILD_DIR}/gen fi -make -j 4 -C "${TENSORFLOW_DIR}" -f ${TF_LITE_BUILD_DIR}/Makefile +if [[ $1 == '--sgx' ]]; then + make -j 4 -C "${TENSORFLOW_DIR}" -f ${TF_LITE_BUILD_DIR}/Makefile +else + export BUILD_WITH_SIMD=true + make -j 4 -C "${TENSORFLOW_DIR}" -f ${TF_LITE_BUILD_DIR}/Makefile +fi + +# remove patch file and recover emcc libc.a after building +Clear_Before_Exit # 2.5 copy /make/gen target files to out/ rm -rf ${OUT_DIR} @@ -84,7 +104,7 @@ cd ${OUT_DIR} if [[ $1 == '--sgx' ]]; then ${WAMRC_CMD} -sgx -o benchmark_model.aot benchmark_model.wasm else - ${WAMRC_CMD} -o benchmark_model.aot benchmark_model.wasm + ${WAMRC_CMD} --enable-simd -o benchmark_model.aot benchmark_model.wasm fi # 4. build iwasm with pthread and libc_emcc enable @@ -101,7 +121,7 @@ if [[ $1 == '--sgx' ]]; then else cd ${WAMR_PLATFORM_DIR}/linux rm -fr build && mkdir build - cd build && cmake .. -DWAMR_BUILD_LIB_PTHREAD=1 -DWAMR_BUILD_LIBC_EMCC=1 + cd build && cmake .. -DWAMR_BUILD_SIMD=1 -DWAMR_BUILD_LIB_PTHREAD=1 -DWAMR_BUILD_LIBC_EMCC=1 make fi @@ -122,8 +142,6 @@ else fi ${IWASM_CMD} --heap-size=10475860 \ - ${OUT_DIR}/benchmark_model.aot \ - --graph=mobilenet_quant_v1_224.tflite --max_secs=300 - -Clear_Before_Exit + ${OUT_DIR}/benchmark_model.aot \ + --graph=mobilenet_quant_v1_224.tflite --max_secs=300 diff --git a/samples/workload/tensorflow/tf_lite.patch b/samples/workload/tensorflow/tf_lite.patch index 85700778a..b76dd5219 100644 --- a/samples/workload/tensorflow/tf_lite.patch +++ b/samples/workload/tensorflow/tf_lite.patch @@ -1,5 +1,5 @@ diff --git a/tensorflow/lite/tools/make/Makefile b/tensorflow/lite/tools/make/Makefile -index c7ddff5844..1082644043 100644 +index c7ddff5844..17146868f7 100644 --- a/tensorflow/lite/tools/make/Makefile +++ b/tensorflow/lite/tools/make/Makefile @@ -48,11 +48,7 @@ INCLUDES += -I/usr/local/include @@ -15,10 +15,16 @@ index c7ddff5844..1082644043 100644 -ldl # There are no rules for compiling objects for the host system (since we don't -@@ -84,14 +80,18 @@ endif # ifeq ($(HOST_ARCH),$(TARGET_ARCH)) +@@ -84,14 +80,24 @@ endif # ifeq ($(HOST_ARCH),$(TARGET_ARCH)) endif # ifeq ($(HOST_OS),$(TARGET)) endif ++BUILD_WITH_SIMD ?= false ++ifeq ($(BUILD_WITH_SIMD), true) ++CFLAGS+=-msimd128 ++CXXFLAGS+=-msimd128 ++endif ++ +LIBFLAGS += -s TOTAL_STACK=1048576 \ + -Wl,--export=__data_end -Wl,--export=__heap_base \ + -s ERROR_ON_UNDEFINED_SYMBOLS=0 @@ -36,7 +42,7 @@ index c7ddff5844..1082644043 100644 # A small example program that shows how to link against the library. MINIMAL_SRCS := \ -@@ -277,12 +277,16 @@ LIB_PATH := $(LIBDIR)$(LIB_NAME) +@@ -277,12 +283,16 @@ LIB_PATH := $(LIBDIR)$(LIB_NAME) BENCHMARK_LIB := $(LIBDIR)$(BENCHMARK_LIB_NAME) BENCHMARK_BINARY := $(BINDIR)$(BENCHMARK_BINARY_NAME) BENCHMARK_PERF_OPTIONS_BINARY := $(BINDIR)$(BENCHMARK_PERF_OPTIONS_BINARY_NAME) diff --git a/samples/workload/wasm-av1/README.md b/samples/workload/wasm-av1/README.md new file mode 100644 index 000000000..30cb6ca52 --- /dev/null +++ b/samples/workload/wasm-av1/README.md @@ -0,0 +1,22 @@ +"wasm-av1" sample introduction +============== +This sample demonstrates how to build [wasm-av1](https://github.com/GoogleChromeLabs/wasm-av1) into WebAssembly with emcc toolchain and run it with iwasm. Please first install [emsdk](https://github.com/emscripten-core/emsdk): +```bash +git clone https://github.com/emscripten-core/emsdk.git +cd emsdk +./emsdk install latest +./emsdk activate latest +``` +And set up ensdk environment: +```bash +source emsdk_env.sh +``` +Then run +```bash +./build.sh +``` +to build wasm-av1 and run it with iwasm, which basically contains the following steps: +- hack emcc to delete some objects in libc.a +- patch wasm-av1 and build it with emcc compiler +- build iwasm with simd and libc-emcc support +- run testav1.aot with iwasm diff --git a/samples/workload/wasm-av1/build.sh b/samples/workload/wasm-av1/build.sh new file mode 100755 index 000000000..2d52b20d8 --- /dev/null +++ b/samples/workload/wasm-av1/build.sh @@ -0,0 +1,100 @@ +# +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# + +#!/bin/bash + +#################################### +# build wasm-av1 sample # +#################################### +if [ ! -d "${EMSDK}" ]; then + echo "can not find emsdk. " + echo "please refer to https://emscripten.org/docs/getting_started/downloads.html " + echo "to install it, or active it by 'source emsdk_env.sh'" + exit +fi + +set -xe + +EMSDK_WASM_DIR="$EM_CACHE/wasm" +BUILD_SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +OUT_DIR="${BUILD_SCRIPT_DIR}/out" +WASM_AV1_DIR="${BUILD_SCRIPT_DIR}/wasm-av1" + +WAMR_PLATFORM_DIR="${BUILD_SCRIPT_DIR}/../../../product-mini/platforms" +IWASM_CMD="${WAMR_PLATFORM_DIR}/linux/build/iwasm" + +WAMRC_DIR="${BUILD_SCRIPT_DIR}/../../../wamr-compiler" +WAMRC_CMD="${WAMRC_DIR}/build/wamrc" + +function Clear_Before_Exit +{ + [[ -f ${WASM_AV1_DIR}/wasm-av1.patch ]] && + rm -f ${WASM_AV1_DIR}/wasm-av1.patch + # resume the libc.a under EMSDK_WASM_DIR + cd ${EMSDK_WASM_DIR} + mv libc.a.bak libc.a +} + +# 1.hack emcc +cd ${EMSDK_WASM_DIR} +# back up libc.a +cp libc.a libc.a.bak +# delete some objects in libc.a +emar d libc.a fopen.o +emar d libc.a fread.o +emar d libc.a feof.o +emar d libc.a fclose.o + +# 2. build wasm-av1 +cd ${BUILD_SCRIPT_DIR} +# 2.1 clone wasm-av1 repo from Github +if [ ! -d "wasm-av1" ]; then + git clone https://github.com/GoogleChromeLabs/wasm-av1.git +fi + +# 2.2 copy the wasm-av1.patch to wasm-av1 and apply the patch +cd ${WASM_AV1_DIR} +cp -a ${BUILD_SCRIPT_DIR}/wasm-av1.patch . +git checkout Makefile +git checkout test.c +git checkout third_party/aom + +if [[ $(git apply wasm-av1.patch 2>&1) =~ "error" ]]; then + echo "git apply patch failed, please check wasm-av1 related changes..." + Clear_Before_Exit + exit 0 +fi + +make testavx -j 4 + +# remove patch file and recover emcc libc.a after building +Clear_Before_Exit + +# 2.3 copy /make/gen target files to out/ +rm -rf ${OUT_DIR} && mkdir ${OUT_DIR} +cp -a ${WASM_AV1_DIR}/testavx.wasm ${OUT_DIR}/ + +# 3. compile wasm-av1.wasm to wasm-av1.aot with wamrc +# 3.1 build wamr-compiler +cd ${WAMRC_DIR} +./build_llvm.sh +rm -fr build && mkdir build +cd build && cmake .. +make +# 3.2 compile wasm-av1.wasm to wasm-av1.aot +cd ${OUT_DIR} +${WAMRC_CMD} --enable-simd -o testavx.aot testavx.wasm + +# 4. build iwasm with pthread and libc_emcc enable +cd ${WAMR_PLATFORM_DIR}/linux +rm -fr build && mkdir build +cd build && cmake .. -DWAMR_BUILD_SIMD=1 -DWAMR_BUILD_LIB_PTHREAD=1 -DWAMR_BUILD_LIBC_EMCC=1 +make + +# 5. run wasm-av1 with iwasm +echo "---> run testav1.aot with iwasm" +cd ${OUT_DIR} +${IWASM_CMD} testavx.aot ../wasm-av1/third_party/samples/elephants_dream_480p24.ivf + diff --git a/samples/workload/wasm-av1/wasm-av1.patch b/samples/workload/wasm-av1/wasm-av1.patch new file mode 100644 index 000000000..1db8f7fb3 --- /dev/null +++ b/samples/workload/wasm-av1/wasm-av1.patch @@ -0,0 +1,696 @@ +diff --git a/Makefile b/Makefile +index c39fff6..4682d43 100644 +--- a/Makefile ++++ b/Makefile +@@ -59,11 +59,13 @@ $(TARGET): $(DEPS) blob-api.c yuv-to-rgb.c $(EMLIBAV1) + ]" \ + blob-api.c yuv-to-rgb.c $(SRCS) $(INC) -L $(LIBDIR) -l$(LIB) + +-$(TESTTARGET): test.c $(DEPS) $(X86LIBAV1) +- cc -o $@ -O3 test.c $(SRCS) $(INC) -L $(X86LIBDIR) -l$(LIB) ++$(TESTTARGET): test.c $(DEPS) $(EMLIBAV1) ++ emcc -o $@.wasm -O3 test.c $(SRCS) $(INC) -L $(LIBDIR) -l$(LIB) \ ++ -s TOTAL_MEMORY=104857600 -s ERROR_ON_UNDEFINED_SYMBOLS=0 + +-$(TESTTARGET)g: test.c $(DEPS) $(X86LIBAV1) +- cc -o $@ -g test.c $(SRCS) $(INC) -L $(X86LIBDIR) -l$(LIB) ++$(TESTTARGET)g: test.c $(DEPS) $(EMLIBAV1) ++ emcc -o $@.wasm -g test.c $(SRCS) $(INC) -L $(LIBDIR) -l$(LIB) \ ++ -s TOTAL_MEMORY=104857600 -s ERROR_ON_UNDEFINED_SYMBOLS=0 + + clean: + -rm $(TARGET) $(TESTTARGET) $(TESTTARGET)g +@@ -80,7 +82,7 @@ $(EMLIBAV1): $(LIBDIR) + -DCONFIG_RUNTIME_CPU_DETECT=0 \ + -DCONFIG_UNIT_TESTS=0 \ + -DCONFIG_WEBM_IO=0 \ +- -DCMAKE_TOOLCHAIN_FILE=`../../get-emcmake.sh`; \ ++ -DCMAKE_TOOLCHAIN_FILE=${EMSDK}/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake; \ + make \ + ) + +diff --git a/test.c b/test.c +index df2d44b..8e81cdc 100644 +--- a/test.c ++++ b/test.c +@@ -18,6 +18,9 @@ + + #include "decode-av1-priv.h" + ++size_t ++emcc_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream); ++ + static void + dump_raw_frame(AVX_Video_Frame *avf, int id) { + FILE *f; +@@ -26,12 +29,13 @@ dump_raw_frame(AVX_Video_Frame *avf, int id) { + void *buf; + + sprintf(name, "frame%04d.yuv", id); ++ printf("writing %s ..\n", name); + if ((f = fopen(name, "wb")) == NULL) { + return; + } + buf = AVX_Video_Frame_get_buffer(avf); + size = AVX_Video_Frame_get_size(avf); +- fwrite(buf, size, 1, f); ++ emcc_fwrite(buf, size, 1, f); + fclose(f); + } + +@@ -63,6 +67,7 @@ main(int argc, char *argv[]) { + static int i = 0; + + ++i; ++ printf("##decode raw frame %d\n", i); + if (30 <= i && i < 40) { + dump_raw_frame(af, i); + } +diff --git a/third_party/aom/CMakeLists.txt b/third_party/aom/CMakeLists.txt +index 9dbe301..20c7be4 100644 +--- a/third_party/aom/CMakeLists.txt ++++ b/third_party/aom/CMakeLists.txt +@@ -56,6 +56,10 @@ option(BUILD_SHARED_LIBS "CMake should generate a shared library build." OFF) + + project(AOM C CXX) + ++set(CMAKE_C_FLAGS "-msimd128 -msse2 -msse3 -msse4.1 -msse4.2 ${CMAKE_C_FLAGS}") ++set(CMAKE_CXX_FLAGS "-msimd128 -msse2 -msse3 -msse4.1 -msse4.2 ${CMAKE_CXX_FLAGS}") ++set(CMAKE_VERBOSE_MAKEFILE on) ++ + set(AOM_ROOT "${CMAKE_CURRENT_SOURCE_DIR}") + set(AOM_CONFIG_DIR "${CMAKE_CURRENT_BINARY_DIR}") + set(INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/include" +@@ -347,7 +351,7 @@ if(CONFIG_AV1_DECODER AND ENABLE_EXAMPLES) + em_link_post_js(inspect "${AOM_ROOT}/tools/inspect-post.js") + # Force generation of Wasm instead of asm.js + append_link_flag_to_target("inspect" "-s WASM=1") +- append_compiler_flag("-s WASM=1") ++ append_compiler_flag("-O3 -s WASM=1 -s ERROR_ON_UNDEFINED_SYMBOLS=0") + endif() + endif() + +diff --git a/third_party/aom/aom/src/aom_codec.c b/third_party/aom/aom/src/aom_codec.c +index dbd6fa5..a8d2a49 100644 +--- a/third_party/aom/aom/src/aom_codec.c ++++ b/third_party/aom/aom/src/aom_codec.c +@@ -132,6 +132,7 @@ void aom_internal_error(struct aom_internal_error_info *info, + info->detail[sz - 1] = '\0'; + } + ++ printf("##aom internal error: %s\n", info->detail); + if (info->setjmp) longjmp(info->jmp, info->error_code); + } + +diff --git a/third_party/aom/aom_dsp/grain_table.c b/third_party/aom/aom_dsp/grain_table.c +index 0d6a73f..4b05833 100644 +--- a/third_party/aom/aom_dsp/grain_table.c ++++ b/third_party/aom/aom_dsp/grain_table.c +@@ -293,6 +293,9 @@ aom_codec_err_t aom_film_grain_table_read( + return error_info->error_code; + } + ++size_t ++emcc_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream); ++ + aom_codec_err_t aom_film_grain_table_write( + const aom_film_grain_table_t *t, const char *filename, + struct aom_internal_error_info *error_info) { +@@ -305,7 +308,7 @@ aom_codec_err_t aom_film_grain_table_write( + return error_info->error_code; + } + +- if (!fwrite(kFileMagic, 8, 1, file)) { ++ if (!emcc_fwrite(kFileMagic, 8, 1, file)) { + aom_internal_error(error_info, AOM_CODEC_ERROR, + "Unable to write file magic"); + fclose(file); +diff --git a/third_party/aom/aomdec.c b/third_party/aom/aomdec.c +index 4addee8..f850147 100644 +--- a/third_party/aom/aomdec.c ++++ b/third_party/aom/aomdec.c +@@ -274,6 +274,9 @@ static void update_image_md5(const aom_image_t *img, const int planes[3], + } + } + ++size_t ++emcc_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream); ++ + static void write_image_file(const aom_image_t *img, const int *planes, + const int num_planes, FILE *file) { + int i, y; +@@ -287,7 +290,7 @@ static void write_image_file(const aom_image_t *img, const int *planes, + const int h = aom_img_plane_height(img, plane); + + for (y = 0; y < h; ++y) { +- fwrite(buf, bytes_per_sample, w, file); ++ emcc_fwrite(buf, bytes_per_sample, w, file); + buf += stride; + } + } +diff --git a/third_party/aom/aomenc.c b/third_party/aom/aomenc.c +index 64155b0..3ed5080 100644 +--- a/third_party/aom/aomenc.c ++++ b/third_party/aom/aomenc.c +@@ -59,9 +59,12 @@ static size_t wrap_fread(void *ptr, size_t size, size_t nmemb, FILE *stream) { + } + #define fread wrap_fread + ++size_t ++emcc_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream); ++ + static size_t wrap_fwrite(const void *ptr, size_t size, size_t nmemb, + FILE *stream) { +- return fwrite(ptr, size, nmemb, stream); ++ return emcc_fwrite(ptr, size, nmemb, stream); + } + #define fwrite wrap_fwrite + +diff --git a/third_party/aom/aomstats.c b/third_party/aom/aomstats.c +index 0cfeea2..6833776 100644 +--- a/third_party/aom/aomstats.c ++++ b/third_party/aom/aomstats.c +@@ -80,9 +80,12 @@ void stats_close(stats_io_t *stats, int last_pass) { + } + } + ++size_t ++emcc_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream); ++ + void stats_write(stats_io_t *stats, const void *pkt, size_t len) { + if (stats->file) { +- (void)fwrite(pkt, 1, len, stats->file); ++ (void)emcc_fwrite(pkt, 1, len, stats->file); + } else { + if (stats->buf.sz + len > stats->buf_alloc_sz) { + size_t new_sz = stats->buf_alloc_sz + 64 * 1024; +diff --git a/third_party/aom/av1/common/debugmodes.c b/third_party/aom/av1/common/debugmodes.c +index 868f341..c44258c 100644 +--- a/third_party/aom/av1/common/debugmodes.c ++++ b/third_party/aom/av1/common/debugmodes.c +@@ -89,10 +89,13 @@ void av1_print_modes_and_motion_vectors(AV1_COMMON *cm, const char *file) { + fclose(mvs); + } + ++size_t ++emcc_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream); ++ + void av1_print_uncompressed_frame_header(const uint8_t *data, int size, + const char *filename) { + FILE *hdrFile = fopen(filename, "w"); +- fwrite(data, size, sizeof(uint8_t), hdrFile); ++ emcc_fwrite(data, size, sizeof(uint8_t), hdrFile); + fclose(hdrFile); + } + +diff --git a/third_party/aom/av1/encoder/encoder.c b/third_party/aom/av1/encoder/encoder.c +index a557380..d709d26 100644 +--- a/third_party/aom/av1/encoder/encoder.c ++++ b/third_party/aom/av1/encoder/encoder.c +@@ -2799,6 +2799,9 @@ AV1_COMP *av1_create_compressor(AV1EncoderConfig *oxcf, + snprintf((H) + strlen(H), sizeof(H) - strlen(H), (T), (V)) + #endif // CONFIG_INTERNAL_STATS + ++size_t ++emcc_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream); ++ + void av1_remove_compressor(AV1_COMP *cpi) { + AV1_COMMON *cm; + unsigned int i; +@@ -2814,7 +2817,7 @@ void av1_remove_compressor(AV1_COMP *cpi) { + if (cpi->oxcf.pass != 1) { + fprintf(stderr, "Writing counts.stt\n"); + FILE *f = fopen("counts.stt", "wb"); +- fwrite(&aggregate_fc, sizeof(aggregate_fc), 1, f); ++ emcc_fwrite(&aggregate_fc, sizeof(aggregate_fc), 1, f); + fclose(f); + } + #endif // CONFIG_ENTROPY_STATS +@@ -3013,7 +3016,7 @@ void aom_write_yuv_frame_420(YV12_BUFFER_CONFIG *s, FILE *f) { + int h = s->y_height; + + do { +- fwrite(src, s->y_width, 1, f); ++ emcc_fwrite(src, s->y_width, 1, f); + src += s->y_stride; + } while (--h); + +@@ -3021,7 +3024,7 @@ void aom_write_yuv_frame_420(YV12_BUFFER_CONFIG *s, FILE *f) { + h = s->uv_height; + + do { +- fwrite(src, s->uv_width, 1, f); ++ emcc_fwrite(src, s->uv_width, 1, f); + src += s->uv_stride; + } while (--h); + +@@ -3029,7 +3032,7 @@ void aom_write_yuv_frame_420(YV12_BUFFER_CONFIG *s, FILE *f) { + h = s->uv_height; + + do { +- fwrite(src, s->uv_width, 1, f); ++ emcc_fwrite(src, s->uv_width, 1, f); + src += s->uv_stride; + } while (--h); + } +@@ -3121,7 +3124,7 @@ void aom_write_one_yuv_frame(AV1_COMMON *cm, YV12_BUFFER_CONFIG *s) { + uint16_t *src16 = CONVERT_TO_SHORTPTR(s->y_buffer); + + do { +- fwrite(src16, s->y_width, 2, yuv_rec_file); ++ emcc_fwrite(src16, s->y_width, 2, yuv_rec_file); + src16 += s->y_stride; + } while (--h); + +@@ -3129,7 +3132,7 @@ void aom_write_one_yuv_frame(AV1_COMMON *cm, YV12_BUFFER_CONFIG *s) { + h = s->uv_height; + + do { +- fwrite(src16, s->uv_width, 2, yuv_rec_file); ++ emcc_fwrite(src16, s->uv_width, 2, yuv_rec_file); + src16 += s->uv_stride; + } while (--h); + +@@ -3137,7 +3140,7 @@ void aom_write_one_yuv_frame(AV1_COMMON *cm, YV12_BUFFER_CONFIG *s) { + h = s->uv_height; + + do { +- fwrite(src16, s->uv_width, 2, yuv_rec_file); ++ emcc_fwrite(src16, s->uv_width, 2, yuv_rec_file); + src16 += s->uv_stride; + } while (--h); + +@@ -3146,7 +3149,7 @@ void aom_write_one_yuv_frame(AV1_COMMON *cm, YV12_BUFFER_CONFIG *s) { + } + + do { +- fwrite(src, s->y_width, 1, yuv_rec_file); ++ emcc_fwrite(src, s->y_width, 1, yuv_rec_file); + src += s->y_stride; + } while (--h); + +@@ -3154,7 +3157,7 @@ void aom_write_one_yuv_frame(AV1_COMMON *cm, YV12_BUFFER_CONFIG *s) { + h = s->uv_height; + + do { +- fwrite(src, s->uv_width, 1, yuv_rec_file); ++ emcc_fwrite(src, s->uv_width, 1, yuv_rec_file); + src += s->uv_stride; + } while (--h); + +@@ -3162,7 +3165,7 @@ void aom_write_one_yuv_frame(AV1_COMMON *cm, YV12_BUFFER_CONFIG *s) { + h = s->uv_height; + + do { +- fwrite(src, s->uv_width, 1, yuv_rec_file); ++ emcc_fwrite(src, s->uv_width, 1, yuv_rec_file); + src += s->uv_stride; + } while (--h); + +@@ -3241,16 +3244,16 @@ static int dump_one_image(AV1_COMMON *cm, + + // --- Y --- + for (h = 0; h < cm->height; ++h) { +- fwrite(&ref_buf->y_buffer[h * ref_buf->y_stride], 1, cm->width, f_ref); ++ emcc_fwrite(&ref_buf->y_buffer[h * ref_buf->y_stride], 1, cm->width, f_ref); + } + // --- U --- + for (h = 0; h < (cm->height >> 1); ++h) { +- fwrite(&ref_buf->u_buffer[h * ref_buf->uv_stride], 1, (cm->width >> 1), ++ emcc_fwrite(&ref_buf->u_buffer[h * ref_buf->uv_stride], 1, (cm->width >> 1), + f_ref); + } + // --- V --- + for (h = 0; h < (cm->height >> 1); ++h) { +- fwrite(&ref_buf->v_buffer[h * ref_buf->uv_stride], 1, (cm->width >> 1), ++ emcc_fwrite(&ref_buf->v_buffer[h * ref_buf->uv_stride], 1, (cm->width >> 1), + f_ref); + } + +@@ -4692,17 +4695,17 @@ static void dump_filtered_recon_frames(AV1_COMP *cpi) { + + // --- Y --- + for (h = 0; h < cm->height; ++h) { +- fwrite(&recon_buf->y_buffer[h * recon_buf->y_stride], 1, cm->width, ++ emcc_fwrite(&recon_buf->y_buffer[h * recon_buf->y_stride], 1, cm->width, + f_recon); + } + // --- U --- + for (h = 0; h < (cm->height >> 1); ++h) { +- fwrite(&recon_buf->u_buffer[h * recon_buf->uv_stride], 1, (cm->width >> 1), ++ emcc_fwrite(&recon_buf->u_buffer[h * recon_buf->uv_stride], 1, (cm->width >> 1), + f_recon); + } + // --- V --- + for (h = 0; h < (cm->height >> 1); ++h) { +- fwrite(&recon_buf->v_buffer[h * recon_buf->uv_stride], 1, (cm->width >> 1), ++ emcc_fwrite(&recon_buf->v_buffer[h * recon_buf->uv_stride], 1, (cm->width >> 1), + f_recon); + } + +diff --git a/third_party/aom/av1/encoder/firstpass.c b/third_party/aom/av1/encoder/firstpass.c +index bb73fde..b963043 100644 +--- a/third_party/aom/av1/encoder/firstpass.c ++++ b/third_party/aom/av1/encoder/firstpass.c +@@ -476,6 +476,9 @@ static double raw_motion_error_stdev(int *raw_motion_err_list, + return raw_err_stdev; + } + ++size_t ++emcc_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream); ++ + #define UL_INTRA_THRESH 50 + #define INVALID_ROW -1 + void av1_first_pass(AV1_COMP *cpi, const struct lookahead_entry *source) { +@@ -1077,7 +1080,7 @@ void av1_first_pass(AV1_COMP *cpi, const struct lookahead_entry *source) { + else + recon_file = fopen(filename, "ab"); + +- (void)fwrite(lst_yv12->buffer_alloc, lst_yv12->frame_size, 1, recon_file); ++ (void)emcc_fwrite(lst_yv12->buffer_alloc, lst_yv12->frame_size, 1, recon_file); + fclose(recon_file); + } + +diff --git a/third_party/aom/build/cmake/aom_configure.cmake b/third_party/aom/build/cmake/aom_configure.cmake +index 9220a32..fb8bf9f 100644 +--- a/third_party/aom/build/cmake/aom_configure.cmake ++++ b/third_party/aom/build/cmake/aom_configure.cmake +@@ -260,7 +260,7 @@ if(MSVC) + add_compiler_flag_if_supported("/WX") + endif() + else() +- require_c_flag("-std=c99" YES) ++ #require_c_flag("-std=c99" YES) + add_compiler_flag_if_supported("-Wall") + add_compiler_flag_if_supported("-Wdisabled-optimization") + add_compiler_flag_if_supported("-Wextra") +diff --git a/third_party/aom/examples/resize_util.c b/third_party/aom/examples/resize_util.c +index 5485691..e60ed86 100644 +--- a/third_party/aom/examples/resize_util.c ++++ b/third_party/aom/examples/resize_util.c +@@ -45,6 +45,9 @@ static int parse_dim(char *v, int *width, int *height) { + return 1; + } + ++size_t ++emcc_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream); ++ + int main(int argc, char *argv[]) { + char *fin, *fout; + FILE *fpin, *fpout; +@@ -111,7 +114,7 @@ int main(int argc, char *argv[]) { + av1_resize_frame420(inbuf, width, inbuf_u, inbuf_v, width / 2, height, + width, outbuf, target_width, outbuf_u, outbuf_v, + target_width / 2, target_height, target_width); +- fwrite(outbuf, target_width * target_height * 3 / 2, 1, fpout); ++ emcc_fwrite(outbuf, target_width * target_height * 3 / 2, 1, fpout); + f++; + } + printf("%d frames processed\n", f); +diff --git a/third_party/aom/examples/scalable_encoder.c b/third_party/aom/examples/scalable_encoder.c +index 10d647e..fcf31e1 100644 +--- a/third_party/aom/examples/scalable_encoder.c ++++ b/third_party/aom/examples/scalable_encoder.c +@@ -91,6 +91,9 @@ void usage_exit(void) { + exit(EXIT_FAILURE); + } + ++size_t ++emcc_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream); ++ + static int encode_frame(aom_codec_ctx_t *codec, aom_image_t *img, + int frame_index, int flags, FILE *outfile) { + int got_pkts = 0; +@@ -105,7 +108,7 @@ static int encode_frame(aom_codec_ctx_t *codec, aom_image_t *img, + + if (pkt->kind == AOM_CODEC_CX_FRAME_PKT) { + const int keyframe = (pkt->data.frame.flags & AOM_FRAME_IS_KEY) != 0; +- if (fwrite(pkt->data.frame.buf, 1, pkt->data.frame.sz, outfile) != ++ if (emcc_fwrite(pkt->data.frame.buf, 1, pkt->data.frame.sz, outfile) != + pkt->data.frame.sz) { + die_codec(codec, "Failed to write compressed frame"); + } +diff --git a/third_party/aom/ivfenc.c b/third_party/aom/ivfenc.c +index 80f4d14..d0e4e34 100644 +--- a/third_party/aom/ivfenc.c ++++ b/third_party/aom/ivfenc.c +@@ -14,6 +14,9 @@ + #include "aom/aom_encoder.h" + #include "aom_ports/mem_ops.h" + ++size_t ++emcc_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream); ++ + void ivf_write_file_header(FILE *outfile, const struct aom_codec_enc_cfg *cfg, + unsigned int fourcc, int frame_cnt) { + char header[32]; +@@ -32,7 +35,7 @@ void ivf_write_file_header(FILE *outfile, const struct aom_codec_enc_cfg *cfg, + mem_put_le32(header + 24, frame_cnt); // length + mem_put_le32(header + 28, 0); // unused + +- fwrite(header, 1, 32, outfile); ++ emcc_fwrite(header, 1, 32, outfile); + } + + void ivf_write_frame_header(FILE *outfile, int64_t pts, size_t frame_size) { +@@ -41,12 +44,12 @@ void ivf_write_frame_header(FILE *outfile, int64_t pts, size_t frame_size) { + mem_put_le32(header, (int)frame_size); + mem_put_le32(header + 4, (int)(pts & 0xFFFFFFFF)); + mem_put_le32(header + 8, (int)(pts >> 32)); +- fwrite(header, 1, 12, outfile); ++ emcc_fwrite(header, 1, 12, outfile); + } + + void ivf_write_frame_size(FILE *outfile, size_t frame_size) { + char header[4]; + + mem_put_le32(header, (int)frame_size); +- fwrite(header, 1, 4, outfile); ++ emcc_fwrite(header, 1, 4, outfile); + } +diff --git a/third_party/aom/test/decode_perf_test.cc b/third_party/aom/test/decode_perf_test.cc +index 3c93e7d..2d364ae 100644 +--- a/third_party/aom/test/decode_perf_test.cc ++++ b/third_party/aom/test/decode_perf_test.cc +@@ -24,6 +24,11 @@ + + using ::testing::make_tuple; + ++extern "C" { ++ size_t ++ emcc_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream); ++} ++ + namespace { + + #define VIDEO_NAME 0 +@@ -153,7 +158,7 @@ class AV1NewEncodeDecodePerfTest + + // Write frame header and data. + ivf_write_frame_header(outfile_, out_frames_, pkt->data.frame.sz); +- ASSERT_EQ(fwrite(pkt->data.frame.buf, 1, pkt->data.frame.sz, outfile_), ++ ASSERT_EQ(emcc_fwrite(pkt->data.frame.buf, 1, pkt->data.frame.sz, outfile_), + pkt->data.frame.sz); + } + +diff --git a/third_party/aom/test/film_grain_table_test.cc b/third_party/aom/test/film_grain_table_test.cc +index 0688146..dbb8e6b 100644 +--- a/third_party/aom/test/film_grain_table_test.cc ++++ b/third_party/aom/test/film_grain_table_test.cc +@@ -5,6 +5,11 @@ + #include "av1/encoder/grain_test_vectors.h" + #include "test/video_source.h" + ++extern "C" { ++ size_t ++ emcc_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream); ++} ++ + void grain_equal(const aom_film_grain_t *expected, + const aom_film_grain_t *actual) { + EXPECT_EQ(expected->apply_grain, actual->apply_grain); +@@ -168,7 +173,7 @@ TEST_F(FilmGrainTableIOTest, ReadTruncatedFile) { + + std::string grain_file; + FILE *file = libaom_test::GetTempOutFile(&grain_file); +- fwrite("deadbeef", 8, 1, file); ++ emcc_fwrite("deadbeef", 8, 1, file); + fclose(file); + ASSERT_EQ(AOM_CODEC_ERROR, + aom_film_grain_table_read(&table, grain_file.c_str(), &error_)); +diff --git a/third_party/aom/test/resize_test.cc b/third_party/aom/test/resize_test.cc +index e1c4e9f..9c2bce8 100644 +--- a/third_party/aom/test/resize_test.cc ++++ b/third_party/aom/test/resize_test.cc +@@ -22,6 +22,11 @@ + // Enable(1) or Disable(0) writing of the compressed bitstream. + #define WRITE_COMPRESSED_STREAM 0 + ++extern "C" { ++ size_t ++ emcc_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream); ++} ++ + namespace { + + #if WRITE_COMPRESSED_STREAM +@@ -55,13 +60,13 @@ static void write_ivf_file_header(const aom_codec_enc_cfg_t *const cfg, + mem_put_le32(header + 24, frame_cnt); /* length */ + mem_put_le32(header + 28, 0); /* unused */ + +- (void)fwrite(header, 1, 32, outfile); ++ (void)emcc_fwrite(header, 1, 32, outfile); + } + + static void write_ivf_frame_size(FILE *const outfile, const size_t size) { + char header[4]; + mem_put_le32(header, static_cast(size)); +- (void)fwrite(header, 1, 4, outfile); ++ (void)emcc_fwrite(header, 1, 4, outfile); + } + + static void write_ivf_frame_header(const aom_codec_cx_pkt_t *const pkt, +@@ -76,7 +81,7 @@ static void write_ivf_frame_header(const aom_codec_cx_pkt_t *const pkt, + mem_put_le32(header + 4, pts & 0xFFFFFFFF); + mem_put_le32(header + 8, pts >> 32); + +- (void)fwrite(header, 1, 12, outfile); ++ (void)emcc_fwrite(header, 1, 12, outfile); + } + #endif // WRITE_COMPRESSED_STREAM + +@@ -309,7 +314,7 @@ class ResizeInternalTestLarge : public ResizeTest { + + // Write frame header and data. + write_ivf_frame_header(pkt, outfile_); +- (void)fwrite(pkt->data.frame.buf, 1, pkt->data.frame.sz, outfile_); ++ (void)emcc_fwrite(pkt->data.frame.buf, 1, pkt->data.frame.sz, outfile_); + } + #endif + +@@ -608,7 +613,7 @@ class ResizeCspTest : public ResizeTest { + + // Write frame header and data. + write_ivf_frame_header(pkt, outfile_); +- (void)fwrite(pkt->data.frame.buf, 1, pkt->data.frame.sz, outfile_); ++ (void)emcc_fwrite(pkt->data.frame.buf, 1, pkt->data.frame.sz, outfile_); + } + #endif + +diff --git a/third_party/aom/test/y4m_test.cc b/third_party/aom/test/y4m_test.cc +index ad901d9..f24093f 100644 +--- a/third_party/aom/test/y4m_test.cc ++++ b/third_party/aom/test/y4m_test.cc +@@ -19,6 +19,11 @@ + #include "test/util.h" + #include "test/y4m_video_source.h" + ++extern "C" { ++ size_t ++ emcc_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream); ++} ++ + namespace { + + using std::string; +@@ -68,7 +73,7 @@ static void write_image_file(const aom_image_t *img, FILE *file) { + (plane ? (img->d_w + img->x_chroma_shift) >> img->x_chroma_shift + : img->d_w); + for (y = 0; y < h; ++y) { +- fwrite(buf, bytes_per_sample, w, file); ++ emcc_fwrite(buf, bytes_per_sample, w, file); + buf += stride; + } + } +diff --git a/third_party/aom/third_party/googletest/src/googletest/src/gtest.cc b/third_party/aom/third_party/googletest/src/googletest/src/gtest.cc +index 5a8932c..ac2c435 100644 +--- a/third_party/aom/third_party/googletest/src/googletest/src/gtest.cc ++++ b/third_party/aom/third_party/googletest/src/googletest/src/gtest.cc +@@ -146,6 +146,11 @@ + # define vsnprintf _vsnprintf + #endif // GTEST_OS_WINDOWS + ++extern "C" { ++ size_t ++ emcc_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream); ++} ++ + namespace testing { + + using internal::CountIf; +@@ -3867,7 +3872,7 @@ class ScopedPrematureExitFile { + // errors are ignored as there's nothing better we can do and we + // don't want to fail the test because of this. + FILE* pfile = posix::FOpen(premature_exit_filepath, "w"); +- fwrite("0", 1, 1, pfile); ++ emcc_fwrite("0", 1, 1, pfile); + fclose(pfile); + } + } +diff --git a/third_party/aom/third_party/libwebm/mkvmuxer/mkvwriter.cc b/third_party/aom/third_party/libwebm/mkvmuxer/mkvwriter.cc +index 84655d8..0004093 100644 +--- a/third_party/aom/third_party/libwebm/mkvmuxer/mkvwriter.cc ++++ b/third_party/aom/third_party/libwebm/mkvmuxer/mkvwriter.cc +@@ -14,6 +14,11 @@ + #include // for _SH_DENYWR + #endif + ++extern "C" { ++ size_t ++ emcc_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream); ++} ++ + namespace mkvmuxer { + + MkvWriter::MkvWriter() : file_(NULL), writer_owns_file_(true) {} +@@ -32,7 +37,7 @@ int32 MkvWriter::Write(const void* buffer, uint32 length) { + if (buffer == NULL) + return -1; + +- const size_t bytes_written = fwrite(buffer, 1, length, file_); ++ const size_t bytes_written = emcc_fwrite(buffer, 1, length, file_); + + return (bytes_written == length) ? 0 : -1; + } +diff --git a/third_party/aom/tools_common.c b/third_party/aom/tools_common.c +index 7abc20c..fbc30bc 100644 +--- a/third_party/aom/tools_common.c ++++ b/third_party/aom/tools_common.c +@@ -185,6 +185,9 @@ const AvxInterface *get_aom_decoder_by_fourcc(uint32_t fourcc) { + } + #endif // CONFIG_AV1_DECODER + ++size_t ++emcc_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream); ++ + void aom_img_write(const aom_image_t *img, FILE *file) { + int plane; + +@@ -197,7 +200,7 @@ void aom_img_write(const aom_image_t *img, FILE *file) { + int y; + + for (y = 0; y < h; ++y) { +- fwrite(buf, 1, w, file); ++ emcc_fwrite(buf, 1, w, file); + buf += stride; + } + } +diff --git a/third_party/aom/video_writer.c b/third_party/aom/video_writer.c +index 4e072c7..6b1ca54 100644 +--- a/third_party/aom/video_writer.c ++++ b/third_party/aom/video_writer.c +@@ -66,10 +66,13 @@ void aom_video_writer_close(AvxVideoWriter *writer) { + } + } + ++size_t ++emcc_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream); ++ + int aom_video_writer_write_frame(AvxVideoWriter *writer, const uint8_t *buffer, + size_t size, int64_t pts) { + ivf_write_frame_header(writer->file, pts, size); +- if (fwrite(buffer, 1, size, writer->file) != size) return 0; ++ if (emcc_fwrite(buffer, 1, size, writer->file) != size) return 0; + + ++writer->frame_count; + diff --git a/wamr-compiler/CMakeLists.txt b/wamr-compiler/CMakeLists.txt index 114e186d2..c75049caf 100644 --- a/wamr-compiler/CMakeLists.txt +++ b/wamr-compiler/CMakeLists.txt @@ -27,6 +27,7 @@ add_definitions(-DWASM_DISABLE_HW_BOUND_CHECK=1) add_definitions(-DWASM_ENABLE_SHARED_MEMORY=1) add_definitions(-DWASM_ENABLE_THREAD_MGR=1) add_definitions(-DWASM_ENABLE_TAIL_CALL=1) +add_definitions(-DWASM_ENABLE_SIMD=1) # Set WAMR_BUILD_TARGET, currently values supported: # "X86_64", "AMD_64", "X86_32", "ARM_32", "MIPS_32", "XTENSA_32" diff --git a/wamr-compiler/main.c b/wamr-compiler/main.c index d3505ad01..835fea25a 100644 --- a/wamr-compiler/main.c +++ b/wamr-compiler/main.c @@ -43,6 +43,7 @@ print_help() printf(" --enable-multi-thread Enable multi-thread feature, the dependent features bulk-memory and\n"); printf(" --enable-tail-call Enable the post-MVP tail call feature\n"); printf(" thread-mgr will be enabled automatically\n"); + printf(" --enable-simd Enable the post-MVP 128-bit SIMD feature\n"); printf(" -v=n Set log verbose level (0 to 5, default is 2), larger with more log\n"); printf("Examples: wamrc -o test.aot test.wasm\n"); printf(" wamrc --target=i386 -o test.aot test.wasm\n"); @@ -70,6 +71,7 @@ main(int argc, char *argv[]) option.output_format = AOT_FORMAT_FILE; /* default value, enable or disable depends on the platform */ option.bounds_checks = 2; + option.enable_simd = false; /* Process options. */ for (argc--, argv++; argc > 0 && argv[0][0] == '-'; argc--, argv++) { @@ -150,6 +152,9 @@ main(int argc, char *argv[]) else if (!strcmp(argv[0], "--enable-tail-call")) { option.enable_tail_call = true; } + else if (!strcmp(argv[0], "--enable-simd")) { + option.enable_simd = true; + } else return print_help(); } @@ -158,8 +163,8 @@ main(int argc, char *argv[]) return print_help(); if (sgx_mode) { - option.size_level = 1; - option.is_sgx_platform = true; + option.size_level = 1; + option.is_sgx_platform = true; } wasm_file_name = argv[0]; From 8f4a1963fc3893536003537bfb3048646f7383f6 Mon Sep 17 00:00:00 2001 From: Jia Zhang Date: Thu, 12 Nov 2020 20:59:03 +0800 Subject: [PATCH 107/207] Update SGX documents (#439) This commit mainly simplifies the description about building a debug and hw mode enclave. Signed-off-by: Jia Zhang Co-authored-by: root --- doc/linux_sgx.md | 2 + .../linux-sgx/enclave-sample/App/README.md | 100 ++++++------------ 2 files changed, 32 insertions(+), 70 deletions(-) diff --git a/doc/linux_sgx.md b/doc/linux_sgx.md index a28f35963..935a35ac7 100644 --- a/doc/linux_sgx.md +++ b/doc/linux_sgx.md @@ -17,6 +17,8 @@ cmake .. make ``` +**Note:** By default, the generated SGX application assumes it is signed with production key and running on simulation mode. In order to build a debug enclave on hardware-based SGX platform, execute `make SGX_DEBUG=1 SGX_MODE=HW` instead. + This builds two libraries required by SGX application: - libvmlib.a for Enclave part - libvmlib_untrusted.a for App part diff --git a/product-mini/platforms/linux-sgx/enclave-sample/App/README.md b/product-mini/platforms/linux-sgx/enclave-sample/App/README.md index 49ec39a21..ee2cf492b 100644 --- a/product-mini/platforms/linux-sgx/enclave-sample/App/README.md +++ b/product-mini/platforms/linux-sgx/enclave-sample/App/README.md @@ -2,78 +2,30 @@ ## Build WAMR vmcore (iwasm) for Linux-SGX -### SIM Mode +Please follow [this guide](https://github.com/bytecodealliance/wasm-micro-runtime/blob/main/doc/linux_sgx.md#build-wamr-vmcore-iwasm-for-linux-sgx) to build iwasm as the prerequisite. -The default SGX mode in WAMR is the SIM mode. Build the source code and enclave example, please refer to [this guild](https://github.com/bytecodealliance/wasm-micro-runtime/blob/main/doc/linux_sgx.md#build-wamr-vmcore-iwasm-for-linux-sgx). - -### HW Mode - -Please do the following changes before execute [this guild](https://github.com/bytecodealliance/wasm-micro-runtime/blob/main/doc/linux_sgx.md#build-wamr-vmcore-iwasm-for-linux-sgx). - -```shell -diff --git a/product-mini/platforms/linux-sgx/enclave-sample/Makefile b/product-mini/platforms/linux-sgx/enclave-sample/Makefile -index f06b5b8..f247f3e 100644 ---- a/product-mini/platforms/linux-sgx/enclave-sample/Makefile -+++ b/product-mini/platforms/linux-sgx/enclave-sample/Makefile -@@ -4,7 +4,7 @@ - ######## SGX SDK Settings ######## - - SGX_SDK ?= /opt/intel/sgxsdk --SGX_MODE ?= SIM -+SGX_MODE ?= HW - SGX_ARCH ?= x64 - SGX_DEBUG ?= 0 - SPEC_TEST ?= 0 -``` - -```shell -diff --git a/product-mini/platforms/linux-sgx/enclave-sample/Makefile_minimal b/product-mini/platforms/linux-sgx/enclave-sample/Makefile_minimal -index a64d577..747d995 100644 ---- a/product-mini/platforms/linux-sgx/enclave-sample/Makefile_minimal -+++ b/product-mini/platforms/linux-sgx/enclave-sample/Makefile_minimal -@@ -4,7 +4,7 @@ - ######## SGX SDK Settings ######## - - SGX_SDK ?= /opt/intel/sgxsdk --SGX_MODE ?= SIM -+SGX_MODE ?= HW - SGX_ARCH ?= x64 - SGX_DEBUG ?= 0 - SPEC_TEST ?= 0 - -``` - -```shell -diff --git a/product-mini/platforms/linux-sgx/enclave-sample/App/App.cpp b/product-mini/platforms/linux-sgx/enclave-sample/App/App.cpp -index c321575..3b41c30 100644 ---- a/product-mini/platforms/linux-sgx/enclave-sample/App/App.cpp -+++ b/product-mini/platforms/linux-sgx/enclave-sample/App/App.cpp -@@ -31,6 +31,7 @@ - #define MAX_PATH 1024 - - #define TEST_OCALL_API 0 -+#define SGX_DEBUG_FLAG 1 - -``` - -After building, please sign enclave.so to generate enclave.signed.so which is needed in PAL +Then build enclave image and sign it: ```shell +cd enclave-sample +make /opt/intel/sgxsdk/bin/x64/sgx_sign sign -key Enclave/Enclave_private.pem -enclave enclave.so -out enclave.signed.so -config Enclave/Enclave.config.xml ``` +The generated enclave.signed.so is required by PAL. + --- ## Build PAL dynamically linked shared object -To build WAMR as an Enclave Runtime for [Inclavare Containers](https://github.com/alibaba/inclavare-containers), we should implement the [PAL interface](https://github.com/alibaba/inclavare-containers/blob/master/rune/libenclave/internal/runtime/pal/spec_v2.md) in WAMR for rune to call the PAL to create the enclave with WAMR and run applications. +To build WAMR as an Enclave Runtime for [Inclavare Containers](https://github.com/alibaba/inclavare-containers), we should implement the [PAL API v2](https://github.com/alibaba/inclavare-containers/blob/master/rune/libenclave/internal/runtime/pal/spec_v2.md) in WAMR for rune to call the PAL to create the enclave with WAMR and run applications. ```shell g++ -shared -fPIC -o libwamr-pal.so App/*.o libvmlib_untrusted.a -L/opt/intel/sgxsdk/lib64 -lsgx_urts -lpthread -lssl -lcrypto cp ./libwamr-pal.so /usr/lib/libwamr-pal.so ``` -Note: `/opt/intel/sgxsdk/` is where you installed the SGX SDK +Note: Assuming `/opt/intel/sgxsdk/` is where you installed the SGX SDK. --- @@ -81,11 +33,17 @@ Note: `/opt/intel/sgxsdk/` is where you installed the SGX SDK To Build a WAMR application, please refer to [this guide](https://github.com/bytecodealliance/wasm-micro-runtime/blob/main/doc/build_wasm_app.md#build-wasm-applications) -To run a WAMR application with Intel SGX enclave by `rune`, please compile the `.wasm` file to `.aot` file, refer to [this guide](https://github.com/bytecodealliance/wasm-micro-runtime/blob/main/doc/build_wasm_app.md#compile-wasm-to-aot-module) +To run a WAMR application with Intel SGX enclave by `rune`, please refer to [this guide](https://github.com/bytecodealliance/wasm-micro-runtime#build-wamrc-aot-compiler) to generate wamrc AoT compiler, and then refer to [this guide](https://github.com/bytecodealliance/wasm-micro-runtime/blob/main/doc/build_wasm_app.md#compile-wasm-to-aot-module) to compile the `.wasm` file to `.aot` file. + +Note: the AoT file must be generated using --size-level=1 to set a bigger code size, e.g, + +```shell +wamrc --size-level=1 -o test.aot test.wasm +``` --- -## Build WAMR container image +## Build WAMR docker image Under the `enclave-sample` directory, to create the WAMR docker images to load the `enclave.signed.so` and target application wasm files, please type the following commands to create a `Dockerfile`: @@ -99,13 +57,13 @@ RUN mkdir -p /run/rune WORKDIR /run/rune COPY enclave.signed.so . -COPY ${wasm_app1.aot} . +COPY ${wasm_app.aot} . #COPY ${wasm_app2.aot} . #... EOF ``` - For ubuntu: +For ubuntu: ```shell cat > Dockerfile < Date: Fri, 13 Nov 2020 13:11:34 +0800 Subject: [PATCH 108/207] Enhance the readability of WAMR SGX docs (#442) The global doc/linux_sgx.md needs to explicitly describe the methods to build a debug enclave and hardware running mode. Because using debug key to signing enclave image rather than production key is still not trivial in reality. For the adaption of Inclavare Containers part, add a prolog and give more details in order to enhance the readability. Signed-off-by: Jia Zhang --- doc/linux_sgx.md | 4 +- .../linux-sgx/enclave-sample/App/README.md | 67 +++++++++---------- .../enclave-sample/App/wamr-bundle.md | 23 +++---- 3 files changed, 44 insertions(+), 50 deletions(-) diff --git a/doc/linux_sgx.md b/doc/linux_sgx.md index 935a35ac7..ee4fbefc7 100644 --- a/doc/linux_sgx.md +++ b/doc/linux_sgx.md @@ -17,8 +17,6 @@ cmake .. make ``` -**Note:** By default, the generated SGX application assumes it is signed with production key and running on simulation mode. In order to build a debug enclave on hardware-based SGX platform, execute `make SGX_DEBUG=1 SGX_MODE=HW` instead. - This builds two libraries required by SGX application: - libvmlib.a for Enclave part - libvmlib_untrusted.a for App part @@ -32,6 +30,8 @@ cd enclave-sample make ``` +**Note:** By default, the generated SGX application assumes it is signed with production key and running on simulation mode. The user can explicitly specify the relative variables in commandline to overwrite the default settings. For example, to build a debug enclave, please build the enclave with `make SGX_DEBUG=1`. To build the enclave running on a hardware-based SGX platform, execute `make SGX_MODE=HW`. + The binary file iwasm will be generated. To run the sample: ``` Bash diff --git a/product-mini/platforms/linux-sgx/enclave-sample/App/README.md b/product-mini/platforms/linux-sgx/enclave-sample/App/README.md index ee2cf492b..78d8b25af 100644 --- a/product-mini/platforms/linux-sgx/enclave-sample/App/README.md +++ b/product-mini/platforms/linux-sgx/enclave-sample/App/README.md @@ -1,53 +1,48 @@ -# WAMR as an Enclave Runtime for Rune +# Running WAMR as an [Enclave Runtime](https://github.com/alibaba/inclavare-containers/blob/master/docs/design/terminology.md#enclave-runtime) for [Inclavare Containers](https://github.com/alibaba/inclavare-containers) -## Build WAMR vmcore (iwasm) for Linux-SGX +In order to establish with `rune`, a novel OCI Runtime for spawning and running enclaves in containers, it is required to implement an [enclave runtime PAL](https://github.com/alibaba/inclavare-containers/blob/master/docs/design/terminology.md#enclave-runtime-pal) to make the communications with WAMR. -Please follow [this guide](https://github.com/bytecodealliance/wasm-micro-runtime/blob/main/doc/linux_sgx.md#build-wamr-vmcore-iwasm-for-linux-sgx) to build iwasm as the prerequisite. +With the assist of `rune`, WAMR is brought to the cloud-native ecosystem beyond the basis. This is the so-called term "WAMR enclave runtime". -Then build enclave image and sign it: +This guide will provide the information about the build, integration and deployment for WAMR enclave runtime. Eventually, the resulting docker image will be launched by `rune`, and the WARM application as the entrypoint of docker image will run in Intel SGX enclave with the hardware-enforced isolation and cryptographically data protection. -```shell -cd enclave-sample -make -/opt/intel/sgxsdk/bin/x64/sgx_sign sign -key Enclave/Enclave_private.pem -enclave enclave.so -out enclave.signed.so -config Enclave/Enclave.config.xml -``` +## Build WAMR vmcore (iwasm) and enclave image -The generated enclave.signed.so is required by PAL. +Please follow [this guide](https://github.com/bytecodealliance/wasm-micro-runtime/blob/main/doc/linux_sgx.md#build-wamr-vmcore-iwasm-for-linux-sgx) to build iwasm and enclave image as the prerequisite. + +The generated enclave image enclave.signed.so will be consumed by WAMR enclave runtime mentioned below. --- -## Build PAL dynamically linked shared object - -To build WAMR as an Enclave Runtime for [Inclavare Containers](https://github.com/alibaba/inclavare-containers), we should implement the [PAL API v2](https://github.com/alibaba/inclavare-containers/blob/master/rune/libenclave/internal/runtime/pal/spec_v2.md) in WAMR for rune to call the PAL to create the enclave with WAMR and run applications. +## Build and install the PAL of WAMR enclave runtime ```shell g++ -shared -fPIC -o libwamr-pal.so App/*.o libvmlib_untrusted.a -L/opt/intel/sgxsdk/lib64 -lsgx_urts -lpthread -lssl -lcrypto cp ./libwamr-pal.so /usr/lib/libwamr-pal.so ``` -Note: Assuming `/opt/intel/sgxsdk/` is where you installed the SGX SDK. - --- ## Build WAMR application -To Build a WAMR application, please refer to [this guide](https://github.com/bytecodealliance/wasm-micro-runtime/blob/main/doc/build_wasm_app.md#build-wasm-applications) - -To run a WAMR application with Intel SGX enclave by `rune`, please refer to [this guide](https://github.com/bytecodealliance/wasm-micro-runtime#build-wamrc-aot-compiler) to generate wamrc AoT compiler, and then refer to [this guide](https://github.com/bytecodealliance/wasm-micro-runtime/blob/main/doc/build_wasm_app.md#compile-wasm-to-aot-module) to compile the `.wasm` file to `.aot` file. - -Note: the AoT file must be generated using --size-level=1 to set a bigger code size, e.g, +As the prerequisite, please +- refer to [this step](https://github.com/bytecodealliance/wasm-micro-runtime/blob/main/doc/build_wasm_app.md#prepare-wasm-building-environments) to install wasi-sdk. Note that the binaries of wasi-sdk must be installed at `/opt/wasi-sdk/bin/`. +- refer to [this guide](https://github.com/bytecodealliance/wasm-micro-runtime#build-wamrc-aot-compiler) to generate wamrc AoT compiler. +The sample WAMR application test.c is provided in [this guide](https://github.com/bytecodealliance/wasm-micro-runtime/blob/main/doc/build_wasm_app.md#build-wasm-applications). Don't forget to compile the `.wasm` file to `.aot` file: ```shell -wamrc --size-level=1 -o test.aot test.wasm +wamrc -sgx -o test.aot test.wasm ``` +The generated test.aot is the WAMR application launched by WAMR enclave runtime. + --- ## Build WAMR docker image Under the `enclave-sample` directory, to create the WAMR docker images to load the `enclave.signed.so` and target application wasm files, please type the following commands to create a `Dockerfile`: -For centos: +For CentOS: ```shell cat >Dockerfile < Date: Fri, 13 Nov 2020 17:53:23 +0800 Subject: [PATCH 109/207] Update sample workload wasm-av1 and add workload XNNPACK (#443) --- README.md | 1 + core/iwasm/aot/aot_reloc.h | 4 + .../libc-builtin/libc_builtin_wrapper.c | 19 +- .../libraries/libc-emcc/libc_emcc_wrapper.c | 152 +++- samples/workload/XNNPACK/CMakeLists.txt | 102 +++ samples/workload/XNNPACK/README.md | 60 ++ .../workload/XNNPACK/toolchain/BUILD.bazel | 30 + .../toolchain/emscripten_toolchain_config.bzl | 137 ++++ samples/workload/XNNPACK/xnnpack.patch | 742 ++++++++++++++++++ samples/workload/cmake/toolchain.cmake | 2 + samples/workload/docker/Dockerfile | 11 + samples/workload/docker/build.sh | 6 + samples/workload/wasm-av1/.gitignore | 8 + .../workload/wasm-av1/CMakeLists.avx_wasm.txt | 79 ++ samples/workload/wasm-av1/CMakeLists.txt | 61 ++ samples/workload/wasm-av1/README.md | 60 +- samples/workload/wasm-av1/av1-clang.patch | 19 + 17 files changed, 1474 insertions(+), 19 deletions(-) create mode 100644 samples/workload/XNNPACK/CMakeLists.txt create mode 100644 samples/workload/XNNPACK/README.md create mode 100644 samples/workload/XNNPACK/toolchain/BUILD.bazel create mode 100644 samples/workload/XNNPACK/toolchain/emscripten_toolchain_config.bzl create mode 100644 samples/workload/XNNPACK/xnnpack.patch create mode 100644 samples/workload/wasm-av1/.gitignore create mode 100644 samples/workload/wasm-av1/CMakeLists.avx_wasm.txt create mode 100644 samples/workload/wasm-av1/CMakeLists.txt create mode 100644 samples/workload/wasm-av1/av1-clang.patch diff --git a/README.md b/README.md index b34f81540..2a4a5fbba 100644 --- a/README.md +++ b/README.md @@ -115,6 +115,7 @@ The WAMR [samples](./samples) integrate the iwasm VM core, application manager a - **[spawn-thread](./samples/spawn-thread)**: Demonstrating how to execute wasm functions of the same wasm application concurrently, in threads created by host embedder or runtime, but not the wasm application itself. - **[multi-module](./samples/multi-module)**: Demonstrating the [multiple modules as dependencies](./doc/multi_module.md) feature which implements the [load-time dynamic linking](https://webassembly.org/docs/dynamic-linking/). - **[wasm-c-api](./samples/wasm-c-api/README.md)**: Demonstrating how to run some samples from [wasm-c-api proposal](https://github.com/WebAssembly/wasm-c-api) and showing the supported API's. +- **[workload](./samples/workload/README.md)**: Demonstrating how to build and run some complex workloads, e.g. tensorflow-lite, XNNPACK, wasm-av1, meshoptimizer and bwa. License diff --git a/core/iwasm/aot/aot_reloc.h b/core/iwasm/aot/aot_reloc.h index 882780a25..9df623e92 100644 --- a/core/iwasm/aot/aot_reloc.h +++ b/core/iwasm/aot/aot_reloc.h @@ -36,6 +36,8 @@ typedef struct { REG_SYM(aot_call_indirect), \ REG_SYM(wasm_runtime_enlarge_memory), \ REG_SYM(wasm_runtime_set_exception), \ + REG_SYM(memset), \ + REG_SYM(memmove), \ REG_BULK_MEMORY_SYM() \ REG_ATOMIC_WAIT_SYM() #else /* else of (defined(_WIN32) || defined(_WIN32_)) && defined(NDEBUG) */ @@ -45,6 +47,8 @@ typedef struct { REG_SYM(aot_call_indirect), \ REG_SYM(wasm_runtime_enlarge_memory), \ REG_SYM(wasm_runtime_set_exception), \ + REG_SYM(memset), \ + REG_SYM(memmove), \ REG_SYM(fmin), \ REG_SYM(fminf), \ REG_SYM(fmax), \ diff --git a/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c b/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c index c00fd02d3..6d4fcc5f9 100644 --- a/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c +++ b/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c @@ -1007,6 +1007,21 @@ __cxa_throw_wrapper(wasm_exec_env_t exec_env, wasm_runtime_set_exception(module_inst, buf); } +static int +setjmp_wrapper(wasm_exec_env_t exec_env, + void *jmp_buf) +{ + os_printf("in setjmp()\n"); + return 0; +} + +static void +longjmp_wrapper(wasm_exec_env_t exec_env, + void *jmp_buf, int val) +{ + os_printf("in longjmp()\n"); +} + #if WASM_ENABLE_SPEC_TEST != 0 static void print_wrapper(wasm_exec_env_t exec_env) @@ -1104,7 +1119,9 @@ static NativeSymbol native_symbols_libc_builtin[] = { REG_NATIVE_FUNC(nullFunc_X, "(i)"), REG_NATIVE_FUNC(__cxa_allocate_exception, "(i)i"), REG_NATIVE_FUNC(__cxa_begin_catch, "(*)"), - REG_NATIVE_FUNC(__cxa_throw, "(**i)") + REG_NATIVE_FUNC(__cxa_throw, "(**i)"), + REG_NATIVE_FUNC(setjmp, "(*)i"), + REG_NATIVE_FUNC(longjmp, "(*i)"), }; #if WASM_ENABLE_SPEC_TEST != 0 diff --git a/core/iwasm/libraries/libc-emcc/libc_emcc_wrapper.c b/core/iwasm/libraries/libc-emcc/libc_emcc_wrapper.c index 0930fbc1a..22a42814f 100644 --- a/core/iwasm/libraries/libc-emcc/libc_emcc_wrapper.c +++ b/core/iwasm/libraries/libc-emcc/libc_emcc_wrapper.c @@ -11,18 +11,27 @@ #define get_module_inst(exec_env) \ wasm_runtime_get_module_inst(exec_env) +#define validate_app_addr(offset, size) \ + wasm_runtime_validate_app_addr(module_inst, offset, size) + +#define validate_app_str_addr(offset) \ + wasm_runtime_validate_app_str_addr(module_inst, offset) + #define validate_native_addr(addr, size) \ wasm_runtime_validate_native_addr(module_inst, addr, size) +#define addr_app_to_native(offset) \ + wasm_runtime_addr_app_to_native(module_inst, offset) + +#define addr_native_to_app(ptr) \ + wasm_runtime_addr_native_to_app(module_inst, ptr) + #define module_malloc(size, p_native_addr) \ wasm_runtime_module_malloc(module_inst, size, p_native_addr) #define module_free(offset) \ wasm_runtime_module_free(module_inst, offset) -#define REG_NATIVE_FUNC(func_name, signature) \ - { #func_name, func_name##_wrapper, signature, NULL } - extern bool wasm_runtime_call_indirect(wasm_exec_env_t exec_env, uint32 element_idx, @@ -282,12 +291,15 @@ fopen_wrapper(wasm_exec_env_t exec_env, int file_id; if (pathname == NULL || mode == NULL) - return -1; + return 0; if ((file_id = get_free_file_slot()) == -1) - return -1; + return 0; file = fopen(pathname, mode); + if (!file) + return 0; + file_list[file_id] = file; return file_id + 1; } @@ -308,6 +320,22 @@ fread_wrapper(wasm_exec_env_t exec_env, return (uint32)fread(ptr, size, nmemb, file); } +static int +fseeko_wrapper(wasm_exec_env_t exec_env, + int file_id, int64 offset, int whence) +{ + FILE *file; + + file_id = file_id - 1; + if ((unsigned)file_id >= sizeof(file_list) / sizeof(FILE *)) { + return -1; + } + if ((file = file_list[file_id]) == NULL) { + return -1; + } + return (uint32)fseek(file, offset, whence); +} + static uint32 emcc_fwrite_wrapper(wasm_exec_env_t exec_env, const void *ptr, uint32 size, uint32 nmemb, @@ -351,6 +379,113 @@ fclose_wrapper(wasm_exec_env_t exec_env, int file_id) file_list[file_id] = NULL; return fclose(file); } + +static int +__sys_mkdir_wrapper(wasm_exec_env_t exec_env, + const char *pathname, int mode) +{ + if (!pathname) + return -1; + return mkdir(pathname, mode); +} + +static int +__sys_rmdir_wrapper(wasm_exec_env_t exec_env, const char *pathname) +{ + if (!pathname) + return -1; + return rmdir(pathname); +} + +static int +__sys_unlink_wrapper(wasm_exec_env_t exec_env, const char *pathname) +{ + if (!pathname) + return -1; + return unlink(pathname); +} + +static uint32 +__sys_getcwd_wrapper(wasm_exec_env_t exec_env, char *buf, uint32 size) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + char *ret; + + if (!buf) + return -1; + + ret = getcwd(buf, size); + return ret ? addr_native_to_app(ret) : 0; +} + +#include + +struct utsname_app { + char sysname[64]; + char nodename[64]; + char release[64]; + char version[64]; + char machine[64]; + char domainname[64]; +}; + +static int +__sys_uname_wrapper(wasm_exec_env_t exec_env, struct utsname_app *uname_app) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + struct utsname uname_native = { 0 }; + uint32 length; + + if (!validate_native_addr(uname_app, sizeof(struct utsname_app))) + return -1; + + if (uname(&uname_native) != 0) { + return -1; + } + + memset(uname_app, 0, sizeof(struct utsname_app)); + + length = strlen(uname_native.sysname); + if (length > sizeof(uname_app->sysname) - 1) + length = sizeof(uname_app->sysname) - 1; + bh_memcpy_s(uname_app->sysname, sizeof(uname_app->sysname), + uname_native.sysname, length); + + length = strlen(uname_native.nodename); + if (length > sizeof(uname_app->nodename) - 1) + length = sizeof(uname_app->nodename) - 1; + bh_memcpy_s(uname_app->nodename, sizeof(uname_app->nodename), + uname_native.nodename, length); + + length = strlen(uname_native.release); + if (length > sizeof(uname_app->release) - 1) + length = sizeof(uname_app->release) - 1; + bh_memcpy_s(uname_app->release, sizeof(uname_app->release), + uname_native.release, length); + + length = strlen(uname_native.version); + if (length > sizeof(uname_app->version) - 1) + length = sizeof(uname_app->version) - 1; + bh_memcpy_s(uname_app->version, sizeof(uname_app->version), + uname_native.version, length); + +#ifdef _GNU_SOURCE + length = strlen(uname_native.domainname); + if (length > sizeof(uname_app->domainname) - 1) + length = sizeof(uname_app->domainname) - 1; + bh_memcpy_s(uname_app->domainname, sizeof(uname_app->domainname), + uname_native.domainname, length); +#endif + + return 0; +} + +static void +emscripten_notify_memory_growth_wrapper(wasm_exec_env_t exec_env, int i) +{ + (void)i; +} + #endif /* end of BH_PLATFORM_LINUX_SGX */ #define REG_NATIVE_FUNC(func_name, signature) \ @@ -374,9 +509,16 @@ static NativeSymbol native_symbols_libc_emcc[] = { #if !defined(BH_PLATFORM_LINUX_SGX) REG_NATIVE_FUNC(fopen, "($$)i"), REG_NATIVE_FUNC(fread, "(*iii)i"), + REG_NATIVE_FUNC(fseeko, "(iIi)i"), REG_NATIVE_FUNC(emcc_fwrite, "(*iii)i"), REG_NATIVE_FUNC(feof, "(i)i"), REG_NATIVE_FUNC(fclose, "(i)i"), + REG_NATIVE_FUNC(__sys_mkdir, "($i)i"), + REG_NATIVE_FUNC(__sys_rmdir, "($)i"), + REG_NATIVE_FUNC(__sys_unlink, "($)i"), + REG_NATIVE_FUNC(__sys_getcwd, "(*~)i"), + REG_NATIVE_FUNC(__sys_uname, "(*)i"), + REG_NATIVE_FUNC(emscripten_notify_memory_growth, "(i)"), #endif /* end of BH_PLATFORM_LINUX_SGX */ }; diff --git a/samples/workload/XNNPACK/CMakeLists.txt b/samples/workload/XNNPACK/CMakeLists.txt new file mode 100644 index 000000000..044230012 --- /dev/null +++ b/samples/workload/XNNPACK/CMakeLists.txt @@ -0,0 +1,102 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required (VERSION 3.0) + +project(xnnpack_wasm) + +################ EMCC ################ +if(NOT DEFINED ENV{EMSDK}) + message(SEND_ERROR + "can not find emsdk. " + "please refer to https://emscripten.org/docs/getting_started/downloads.html " + "and install it, " + "or active emsdk by 'source ./emsdk_env.sh'" + ) +endif() + +include(ExternalProject) + +ExternalProject_Add(xnnpack + PREFIX xnnpack + GIT_REPOSITORY https://github.com/google/XNNPACK.git + GIT_TAG 2da0de89960b829c6fae74204a102db524e73047 + GIT_PROGRESS ON + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/xnnpack + UPDATE_COMMAND git checkout .bazelrc BUILD.bazel emscripten.bzl + && git apply ${CMAKE_CURRENT_SOURCE_DIR}/xnnpack.patch + && cmake -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/toolchain ${CMAKE_CURRENT_SOURCE_DIR}/xnnpack/toolchain + CONFIGURE_COMMAND "" + BUILD_COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR}/xnnpack + && bazel build -c opt --sandbox_writable_path=$ENV{HOME} --config=emscripten_wasm + //:qs8_gemm_bench.wasm + //:qs8_requantization_bench.wasm + //:qu8_gemm_bench.wasm + //:qu8_requantization_bench.wasm + //:f16_igemm_bench.wasm + //:f16_gemm_bench.wasm + //:f16_spmm_bench.wasm + //:f32_igemm_bench.wasm + //:f16_relu_bench.wasm + //:f32_conv_hwc_bench.wasm + //:f32_conv_hwc2chw_bench.wasm + //:f16_dwconv_bench.wasm + //:f32_dwconv_bench.wasm + //:f32_dwconv2d_chw_bench.wasm + //:f32_gemm_bench.wasm + //:f32_hswish_bench.wasm + //:f32_raddexpminusmax_bench.wasm + //:f32_raddextexp_bench.wasm + //:f32_raddstoreexpminusmax_bench.wasm + //:f32_relu_bench.wasm + //:f32_rmax_bench.wasm + //:f32_sigmoid_bench.wasm + //:f32_spmm_bench.wasm + //:f32_softmax_bench.wasm + //:f32_vscaleexpminusmax_bench.wasm + //:f32_vscaleextexp_bench.wasm + //:f32_vsqrt_bench.wasm + //:f32_im2col_gemm_bench.wasm + //:rounding_bench.wasm + //:average_pooling_bench.wasm + //:bankers_rounding_bench.wasm + //:ceiling_bench.wasm + //:channel_shuffle_bench.wasm + //:convolution_bench.wasm + //:deconvolution_bench.wasm + //:floor_bench.wasm + //:global_average_pooling_bench.wasm + //:hardswish_bench.wasm + //:max_pooling_bench.wasm + //:sigmoid_bench.wasm + //:prelu_bench.wasm + //:softmax_bench.wasm + //:square_root_bench.wasm + //:truncation_bench.wasm + //:fp32_mobilenet_v1.wasm + //:fp16_mobilenet_v1.wasm + //:qs8_mobilenet_v1.wasm + //:qs8_mobilenet_v2.wasm + //:fp32_mobilenet_v2.wasm + //:fp16_mobilenet_v2.wasm + //:fp32_mobilenet_v3_large.wasm + //:fp16_mobilenet_v3_large.wasm + //:fp32_mobilenet_v3_small.wasm + //:fp16_mobilenet_v3_small.wasm + //:f32_dwconv_e2e_bench.wasm + //:f32_gemm_e2e_bench.wasm + //:end2end_bench.wasm + //:f32_exp_eval.wasm + //:f32_expminus_eval.wasm + //:f32_extexp_eval.wasm + //:f32_roundne_eval.wasm + //:f32_roundd_eval.wasm + //:f32_roundu_eval.wasm + //:f32_roundz_eval.wasm + //:f32_sigmoid_eval.wasm + //:f32_sqrt_eval.wasm + #--sandbox_debug + INSTALL_COMMAND ${CMAKE_COMMAND} -E create_symlink + ${CMAKE_CURRENT_SOURCE_DIR}/xnnpack/bazel-out/wasm-opt/bin/ + ${CMAKE_CURRENT_SOURCE_DIR}/build/wasm-opt +) diff --git a/samples/workload/XNNPACK/README.md b/samples/workload/XNNPACK/README.md new file mode 100644 index 000000000..a34f66217 --- /dev/null +++ b/samples/workload/XNNPACK/README.md @@ -0,0 +1,60 @@ +"XNNPACK" sample introduction +============== +This sample demonstrates how to build [XNNPACK](https://github.com/google/XNNPACK) benchmarks into WebAssembly with emcc toolchain and run them with iwasm. + +## Installation toolchains + +- **bazel**. Please install bazel from [latest release](https://github.com/bazelbuild/bazel/releases) + +- **emsdk**. Please install [emsdk](https://github.com/emscripten-core/emsdk) to /opt/emsdk: +```bash +cd /opt +git clone https://github.com/emscripten-core/emsdk.git +cd emsdk +./emsdk install latest +./emsdk activate latest +``` +And set up ensdk environment: +```bash +source /opt/emsdk/emsdk_env.sh +``` + +## Build XNNPACK + +```bash +cd /samples/workload/XNNPACK +mkdir build +cd build +cmake .. +``` +The wasm files are generated under folder samples/workload/XNNPACK/xnnpack/bazel-bin. + +## Run benchmarks + +Firstly please build iwasm with simd, libc-emcc and lib-pthread support: + +``` bash +$ cd /product-mini/platforms/linux/ +$ mkdir build && cd build +$ cmake .. -DWAMR_BUILD_SIMD=1 -DWAMR_BUILD_LIBC_EMCC=1 -DWAMR_BUILD_LIB_PTHREAD=1 +$ make +``` + +And please build wamrc: + +``` bash +cd /wamr-compiler +./build_llvm.sh +mkdir build && cd build +cmake .. +make +``` + +Then compile wasm file to aot file and run: + +``` shell +$ cd /samples/workload/XNNPACK/xnnpack/bazel-bin +$ wamrc --enable-simd -o average_pooling_bench.aot average_pooling_bench.wasm (or other wasm files) +$ iwasm average_pooling_bench.aot +``` + diff --git a/samples/workload/XNNPACK/toolchain/BUILD.bazel b/samples/workload/XNNPACK/toolchain/BUILD.bazel new file mode 100644 index 000000000..9cf9b9693 --- /dev/null +++ b/samples/workload/XNNPACK/toolchain/BUILD.bazel @@ -0,0 +1,30 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +package(default_visibility = ['//visibility:public']) + +load(":emscripten_toolchain_config.bzl", "emsdk_toolchain_config") + +cc_toolchain_suite( + name = "emscripten", + toolchains = { + "wasm": ":emsdk_toolchain", + }, +) + +filegroup(name = "empty") + +emsdk_toolchain_config(name = "emsdk_toolchain_config") + +cc_toolchain( + name = "emsdk_toolchain", + toolchain_identifier = "emsdk-toolchain", + toolchain_config = ":emsdk_toolchain_config", + all_files = ":empty", + compiler_files = ":empty", + dwp_files = ":empty", + linker_files = ":empty", + objcopy_files = ":empty", + strip_files = ":empty", + supports_param_files = 0, +) diff --git a/samples/workload/XNNPACK/toolchain/emscripten_toolchain_config.bzl b/samples/workload/XNNPACK/toolchain/emscripten_toolchain_config.bzl new file mode 100644 index 000000000..b90a7abab --- /dev/null +++ b/samples/workload/XNNPACK/toolchain/emscripten_toolchain_config.bzl @@ -0,0 +1,137 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +load("@bazel_tools//tools/build_defs/cc:action_names.bzl", "ACTION_NAMES") +load( + "@bazel_tools//tools/cpp:cc_toolchain_config_lib.bzl", + "feature", + "flag_group", + "flag_set", + "tool_path", +) + +all_compile_actions = [ + ACTION_NAMES.c_compile, + ACTION_NAMES.cpp_compile, +] + +all_link_actions = [ + ACTION_NAMES.cpp_link_executable, + ACTION_NAMES.cpp_link_dynamic_library, + ACTION_NAMES.cpp_link_nodeps_dynamic_library, +] + +def _impl(ctx): + tool_paths = [ + tool_path( + name = "gcc", + path = "/opt/emsdk/upstream/emscripten/emcc", + ), + tool_path( + name = "ld", + path = "/opt/emsdk/upstream/emscripten/emcc", + ), + tool_path( + name = "ar", + path = "/opt/emsdk/upstream/emscripten/emar", + ), + tool_path( + name = "cpp", + path = "/opt/emsdk/upstream/emscripten/em++", + ), + tool_path( + name = "gcov", + path = "/bin/false", + ), + tool_path( + name = "nm", + path = "/bin/false", + ), + tool_path( + name = "objdump", + path = "/bin/false", + ), + tool_path( + name = "strip", + path = "/bin/false", + ), + ] + + features = [ # NEW + feature( + name = "default_compile_flags", + enabled = True, + flag_sets = [ + flag_set( + actions = all_compile_actions, + flag_groups = ([ + flag_group( + flags = [ + "-O3", + "-msimd128", + "-s", + "USE_PTHREADS=0", + "-s", + "ERROR_ON_UNDEFINED_SYMBOLS=0", + "-s", + "STANDALONE_WASM=1", + ], + ), + ]), + ), + ], + ), + feature( + name = "default_linker_flags", + enabled = True, + flag_sets = [ + flag_set( + actions = all_link_actions, + flag_groups = ([ + flag_group( + flags = [ + "-O3", + "-msimd128", + "-s", + "USE_PTHREADS=0", + "-s", + "ERROR_ON_UNDEFINED_SYMBOLS=0", + "-s", + "STANDALONE_WASM=1", + "-Wl,--export=__heap_base", + "-Wl,--export=__data_end", + ], + ), + ]), + ), + ], + ), + ] + + return cc_common.create_cc_toolchain_config_info( + ctx = ctx, + features = features, # NEW + cxx_builtin_include_directories = [ + "/opt/emsdk/upstream/emscripten/system/include/libcxx", + "/opt/emsdk/upstream/emscripten/system/lib/libcxxabi/include", + "/opt/emsdk/upstream/emscripten/system/include", + "/opt/emsdk/upstream/emscripten/system/include/libc", + "/opt/emsdk/upstream/emscripten/system/lib/libc/musl/arch/emscripten", + "/opt/emsdk/upstream/lib/clang/12.0.0/include/", + ], + toolchain_identifier = "wasm-emsdk", + host_system_name = "i686-unknown-linux-gnu", + target_system_name = "wasm32-unknown-emscripten", + target_cpu = "wasm32", + target_libc = "unknown", + compiler = "emsdk", + abi_version = "unknown", + abi_libc_version = "unknown", + tool_paths = tool_paths, + ) + +emsdk_toolchain_config = rule( + implementation = _impl, + attrs = {}, + provides = [CcToolchainConfigInfo], +) diff --git a/samples/workload/XNNPACK/xnnpack.patch b/samples/workload/XNNPACK/xnnpack.patch new file mode 100644 index 000000000..b58cbc795 --- /dev/null +++ b/samples/workload/XNNPACK/xnnpack.patch @@ -0,0 +1,742 @@ +diff --git a/.bazelrc b/.bazelrc +index ea28201..ffd4ed4 100644 +--- a/.bazelrc ++++ b/.bazelrc +@@ -44,3 +44,7 @@ build:ios_arm64e --watchos_cpus=armv7k + build:ios_fat --config=ios + build:ios_fat --ios_multi_cpus=armv7,arm64 + build:ios_fat --watchos_cpus=armv7k ++ ++# WASM configs ++build:emscripten_wasm --cpu=wasm ++build:emscripten_wasm --crosstool_top=//toolchain:emscripten +diff --git a/BUILD.bazel b/BUILD.bazel +index d38ef1e..f261eb5 100644 +--- a/BUILD.bazel ++++ b/BUILD.bazel +@@ -3228,13 +3228,19 @@ xnnpack_cc_library( + hdrs = INTERNAL_HDRS, + gcc_copts = xnnpack_gcc_std_copts(), + msvc_copts = xnnpack_msvc_std_copts(), +- wasm_srcs = WASM_UKERNELS, +- wasmsimd_srcs = WASM_UKERNELS + WASMSIMD_UKERNELS, ++ optimized_copts = [ ++ "-ffast-math", ++ ], ++ wasm_srcs = WASM_UKERNELS + WASMSIMD_UKERNELS + ++ PSIMD_FASTMATH_UKERNELS + PSIMD_ACCMATH_UKERNELS, ++ wasmsimd_srcs = WASM_UKERNELS + WASMSIMD_UKERNELS + ++ PSIMD_FASTMATH_UKERNELS + PSIMD_ACCMATH_UKERNELS, + deps = [ + ":tables", + "@FP16", + "@FXdiv", + "@pthreadpool", ++ "@psimd", + ], + ) + +@@ -3247,13 +3253,19 @@ xnnpack_cc_library( + ], + gcc_copts = xnnpack_gcc_std_copts(), + msvc_copts = xnnpack_msvc_std_copts(), +- wasm_srcs = WASM_UKERNELS, +- wasmsimd_srcs = WASM_UKERNELS + WASMSIMD_UKERNELS, ++ optimized_copts = [ ++ "-ffast-math", ++ ], ++ wasm_srcs = WASM_UKERNELS + WASMSIMD_UKERNELS + ++ PSIMD_FASTMATH_UKERNELS + PSIMD_ACCMATH_UKERNELS, ++ wasmsimd_srcs = WASM_UKERNELS + WASMSIMD_UKERNELS + ++ PSIMD_FASTMATH_UKERNELS + PSIMD_ACCMATH_UKERNELS, + deps = [ + ":tables", + "@FP16", + "@FXdiv", + "@pthreadpool", ++ "@psimd", + ], + ) + +@@ -4495,7 +4507,7 @@ xnnpack_cc_library( + ######################### Benchmarks for micro-kernels ######################### + + xnnpack_benchmark( +- name = "qs8_gemm_bench", ++ name = "qs8_gemm_bench.wasm", + srcs = [ + "bench/gemm.h", + "bench/qs8-gemm.cc", +@@ -4506,7 +4518,7 @@ xnnpack_benchmark( + ) + + xnnpack_benchmark( +- name = "qs8_requantization_bench", ++ name = "qs8_requantization_bench.wasm", + srcs = [ + "bench/qs8-requantization.cc", + "src/xnnpack/AlignedAllocator.h", +@@ -4516,7 +4528,7 @@ xnnpack_benchmark( + ) + + xnnpack_benchmark( +- name = "qu8_gemm_bench", ++ name = "qu8_gemm_bench.wasm", + srcs = [ + "bench/gemm.h", + "bench/qu8-gemm.cc", +@@ -4527,7 +4539,7 @@ xnnpack_benchmark( + ) + + xnnpack_benchmark( +- name = "qu8_requantization_bench", ++ name = "qu8_requantization_bench.wasm", + srcs = [ + "bench/qu8-requantization.cc", + "src/xnnpack/AlignedAllocator.h", +@@ -4537,11 +4549,11 @@ xnnpack_benchmark( + ) + + xnnpack_benchmark( +- name = "f16_igemm_bench", ++ name = "f16_igemm_bench.wasm", + srcs = [ + "bench/f16-igemm.cc", + "bench/conv.h", +- "bench/google/conv.h", ++ #"bench/google/conv.h", + "src/xnnpack/AlignedAllocator.h", + ] + MICROKERNEL_BENCHMARK_HDRS, + deps = MICROKERNEL_BENCHMARK_DEPS + [ +@@ -4551,7 +4563,7 @@ xnnpack_benchmark( + ) + + xnnpack_benchmark( +- name = "f16_gemm_bench", ++ name = "f16_gemm_bench.wasm", + srcs = [ + "bench/f16-gemm.cc", + "bench/gemm.h", +@@ -4563,7 +4575,7 @@ xnnpack_benchmark( + ) + + xnnpack_benchmark( +- name = "f16_spmm_bench", ++ name = "f16_spmm_bench.wasm", + srcs = [ + "bench/f16-spmm.cc", + "bench/gemm.h", +@@ -4573,7 +4585,7 @@ xnnpack_benchmark( + ) + + xnnpack_benchmark( +- name = "f32_igemm_bench", ++ name = "f32_igemm_bench.wasm", + srcs = [ + "bench/f32-igemm.cc", + "bench/conv.h", +@@ -4586,7 +4598,7 @@ xnnpack_benchmark( + ) + + xnnpack_benchmark( +- name = "f16_relu_bench", ++ name = "f16_relu_bench.wasm", + srcs = [ + "bench/f16-relu.cc", + "src/xnnpack/AlignedAllocator.h", +@@ -4595,7 +4607,7 @@ xnnpack_benchmark( + ) + + xnnpack_benchmark( +- name = "f32_conv_hwc_bench", ++ name = "f32_conv_hwc_bench.wasm", + srcs = [ + "bench/f32-conv-hwc.cc", + "bench/dconv.h", +@@ -4607,7 +4619,7 @@ xnnpack_benchmark( + ) + + xnnpack_benchmark( +- name = "f32_conv_hwc2chw_bench", ++ name = "f32_conv_hwc2chw_bench.wasm", + srcs = [ + "bench/f32-conv-hwc2chw.cc", + "bench/dconv.h", +@@ -4619,11 +4631,11 @@ xnnpack_benchmark( + ) + + xnnpack_benchmark( +- name = "f16_dwconv_bench", ++ name = "f16_dwconv_bench.wasm", + srcs = [ + "bench/f16-dwconv.cc", + "bench/dwconv.h", +- "bench/google/dwconv.h", ++ #"bench/google/dwconv.h", + "src/xnnpack/AlignedAllocator.h", + ] + MICROKERNEL_BENCHMARK_HDRS, + deps = MICROKERNEL_BENCHMARK_DEPS + [ +@@ -4633,7 +4645,7 @@ xnnpack_benchmark( + ) + + xnnpack_benchmark( +- name = "f32_dwconv_bench", ++ name = "f32_dwconv_bench.wasm", + srcs = [ + "bench/f32-dwconv.cc", + "bench/dwconv.h", +@@ -4646,7 +4658,7 @@ xnnpack_benchmark( + ) + + xnnpack_benchmark( +- name = "f32_dwconv2d_chw_bench", ++ name = "f32_dwconv2d_chw_bench.wasm", + srcs = [ + "bench/f32-dwconv2d-chw.cc", + "bench/dwconv.h", +@@ -4659,7 +4671,7 @@ xnnpack_benchmark( + ) + + xnnpack_benchmark( +- name = "f32_gemm_bench", ++ name = "f32_gemm_bench.wasm", + srcs = [ + "bench/f32-gemm.cc", + "bench/gemm.h", +@@ -4670,7 +4682,7 @@ xnnpack_benchmark( + ) + + xnnpack_benchmark( +- name = "f32_hswish_bench", ++ name = "f32_hswish_bench.wasm", + srcs = [ + "bench/f32-hswish.cc", + "src/xnnpack/AlignedAllocator.h", +@@ -4679,7 +4691,7 @@ xnnpack_benchmark( + ) + + xnnpack_benchmark( +- name = "f32_raddexpminusmax_bench", ++ name = "f32_raddexpminusmax_bench.wasm", + srcs = [ + "bench/f32-raddexpminusmax.cc", + "src/xnnpack/AlignedAllocator.h", +@@ -4688,7 +4700,7 @@ xnnpack_benchmark( + ) + + xnnpack_benchmark( +- name = "f32_raddextexp_bench", ++ name = "f32_raddextexp_bench.wasm", + srcs = [ + "bench/f32-raddextexp.cc", + "src/xnnpack/AlignedAllocator.h", +@@ -4697,7 +4709,7 @@ xnnpack_benchmark( + ) + + xnnpack_benchmark( +- name = "f32_raddstoreexpminusmax_bench", ++ name = "f32_raddstoreexpminusmax_bench.wasm", + srcs = [ + "bench/f32-raddstoreexpminusmax.cc", + "src/xnnpack/AlignedAllocator.h", +@@ -4706,7 +4718,7 @@ xnnpack_benchmark( + ) + + xnnpack_benchmark( +- name = "f32_relu_bench", ++ name = "f32_relu_bench.wasm", + srcs = [ + "bench/f32-relu.cc", + "src/xnnpack/AlignedAllocator.h", +@@ -4715,7 +4727,7 @@ xnnpack_benchmark( + ) + + xnnpack_benchmark( +- name = "f32_rmax_bench", ++ name = "f32_rmax_bench.wasm", + srcs = [ + "bench/f32-rmax.cc", + "src/xnnpack/AlignedAllocator.h", +@@ -4724,7 +4736,7 @@ xnnpack_benchmark( + ) + + xnnpack_benchmark( +- name = "f32_sigmoid_bench", ++ name = "f32_sigmoid_bench.wasm", + srcs = [ + "bench/f32-sigmoid.cc", + "src/xnnpack/AlignedAllocator.h", +@@ -4733,7 +4745,7 @@ xnnpack_benchmark( + ) + + xnnpack_benchmark( +- name = "f32_spmm_bench", ++ name = "f32_spmm_bench.wasm", + srcs = [ + "bench/f32-spmm.cc", + "bench/gemm.h", +@@ -4743,7 +4755,7 @@ xnnpack_benchmark( + ) + + xnnpack_benchmark( +- name = "f32_softmax_bench", ++ name = "f32_softmax_bench.wasm", + srcs = [ + "bench/f32-softmax.cc", + ] + MICROKERNEL_BENCHMARK_HDRS, +@@ -4752,7 +4764,7 @@ xnnpack_benchmark( + ) + + xnnpack_benchmark( +- name = "f32_vscaleexpminusmax_bench", ++ name = "f32_vscaleexpminusmax_bench.wasm", + srcs = [ + "bench/f32-vscaleexpminusmax.cc", + "src/xnnpack/AlignedAllocator.h", +@@ -4761,7 +4773,7 @@ xnnpack_benchmark( + ) + + xnnpack_benchmark( +- name = "f32_vscaleextexp_bench", ++ name = "f32_vscaleextexp_bench.wasm", + srcs = [ + "bench/f32-vscaleextexp.cc", + "src/xnnpack/AlignedAllocator.h", +@@ -4770,7 +4782,7 @@ xnnpack_benchmark( + ) + + xnnpack_benchmark( +- name = "f32_vsqrt_bench", ++ name = "f32_vsqrt_bench.wasm", + srcs = [ + "bench/f32-vsqrt.cc", + "src/xnnpack/AlignedAllocator.h", +@@ -4779,7 +4791,7 @@ xnnpack_benchmark( + ) + + xnnpack_benchmark( +- name = "f32_im2col_gemm_bench", ++ name = "f32_im2col_gemm_bench.wasm", + srcs = [ + "bench/f32-im2col-gemm.cc", + "bench/conv.h", +@@ -4792,7 +4804,7 @@ xnnpack_benchmark( + ) + + xnnpack_benchmark( +- name = "rounding_bench", ++ name = "rounding_bench.wasm", + srcs = [ + "bench/rounding.cc", + "src/xnnpack/AlignedAllocator.h", +@@ -4804,7 +4816,7 @@ xnnpack_benchmark( + ########################### Benchmarks for operators ########################### + + xnnpack_benchmark( +- name = "average_pooling_bench", ++ name = "average_pooling_bench.wasm", + srcs = ["bench/average-pooling.cc"], + copts = xnnpack_optional_tflite_copts(), + tags = ["nowin32"], +@@ -4812,7 +4824,7 @@ xnnpack_benchmark( + ) + + xnnpack_benchmark( +- name = "bankers_rounding_bench", ++ name = "bankers_rounding_bench.wasm", + srcs = ["bench/bankers-rounding.cc"], + copts = xnnpack_optional_tflite_copts(), + tags = ["nowin32"], +@@ -4820,7 +4832,7 @@ xnnpack_benchmark( + ) + + xnnpack_benchmark( +- name = "ceiling_bench", ++ name = "ceiling_bench.wasm", + srcs = ["bench/ceiling.cc"], + copts = xnnpack_optional_tflite_copts(), + tags = ["nowin32"], +@@ -4828,13 +4840,13 @@ xnnpack_benchmark( + ) + + xnnpack_benchmark( +- name = "channel_shuffle_bench", ++ name = "channel_shuffle_bench.wasm", + srcs = ["bench/channel-shuffle.cc"], + deps = OPERATOR_BENCHMARK_DEPS, + ) + + xnnpack_benchmark( +- name = "convolution_bench", ++ name = "convolution_bench.wasm", + srcs = ["bench/convolution.cc"], + copts = xnnpack_optional_tflite_copts() + xnnpack_optional_armcl_copts(), + tags = ["nowin32"], +@@ -4842,7 +4854,7 @@ xnnpack_benchmark( + ) + + xnnpack_benchmark( +- name = "deconvolution_bench", ++ name = "deconvolution_bench.wasm", + srcs = ["bench/deconvolution.cc"], + copts = xnnpack_optional_tflite_copts(), + tags = ["nowin32"], +@@ -4850,7 +4862,7 @@ xnnpack_benchmark( + ) + + xnnpack_benchmark( +- name = "floor_bench", ++ name = "floor_bench.wasm", + srcs = ["bench/floor.cc"], + copts = xnnpack_optional_tflite_copts(), + tags = ["nowin32"], +@@ -4858,13 +4870,13 @@ xnnpack_benchmark( + ) + + xnnpack_benchmark( +- name = "global_average_pooling_bench", ++ name = "global_average_pooling_bench.wasm", + srcs = ["bench/global-average-pooling.cc"], + deps = OPERATOR_BENCHMARK_DEPS, + ) + + xnnpack_benchmark( +- name = "hardswish_bench", ++ name = "hardswish_bench.wasm", + srcs = ["bench/hardswish.cc"], + copts = xnnpack_optional_tflite_copts(), + tags = ["nowin32"], +@@ -4872,13 +4884,13 @@ xnnpack_benchmark( + ) + + xnnpack_benchmark( +- name = "max_pooling_bench", ++ name = "max_pooling_bench.wasm", + srcs = ["bench/max-pooling.cc"], + deps = OPERATOR_BENCHMARK_DEPS, + ) + + xnnpack_benchmark( +- name = "sigmoid_bench", ++ name = "sigmoid_bench.wasm", + srcs = ["bench/sigmoid.cc"], + copts = xnnpack_optional_tflite_copts(), + tags = ["nowin32"], +@@ -4886,7 +4898,7 @@ xnnpack_benchmark( + ) + + xnnpack_benchmark( +- name = "prelu_bench", ++ name = "prelu_bench.wasm", + srcs = ["bench/prelu.cc"], + copts = xnnpack_optional_tflite_copts(), + tags = ["nowin32"], +@@ -4894,7 +4906,7 @@ xnnpack_benchmark( + ) + + xnnpack_benchmark( +- name = "softmax_bench", ++ name = "softmax_bench.wasm", + srcs = ["bench/softmax.cc"], + copts = xnnpack_optional_tflite_copts(), + tags = ["nowin32"], +@@ -4902,7 +4914,7 @@ xnnpack_benchmark( + ) + + xnnpack_benchmark( +- name = "square_root_bench", ++ name = "square_root_bench.wasm", + srcs = ["bench/square-root.cc"], + copts = xnnpack_optional_tflite_copts(), + tags = ["nowin32"], +@@ -4910,7 +4922,7 @@ xnnpack_benchmark( + ) + + xnnpack_benchmark( +- name = "truncation_bench", ++ name = "truncation_bench.wasm", + srcs = ["bench/truncation.cc"], + deps = OPERATOR_BENCHMARK_DEPS, + ) +@@ -4918,7 +4930,7 @@ xnnpack_benchmark( + ############################# End-to-end benchmarks ############################ + + cc_library( +- name = "fp32_mobilenet_v1", ++ name = "fp32_mobilenet_v1.wasm", + srcs = ["models/fp32-mobilenet-v1.cc"], + hdrs = ["models/models.h"], + copts = xnnpack_std_cxxopts(), +@@ -4930,7 +4942,7 @@ cc_library( + ) + + cc_library( +- name = "fp16_mobilenet_v1", ++ name = "fp16_mobilenet_v1.wasm", + srcs = ["models/fp16-mobilenet-v1.cc"], + hdrs = ["models/models.h"], + copts = xnnpack_std_cxxopts(), +@@ -4943,7 +4955,7 @@ cc_library( + ) + + cc_library( +- name = "qs8_mobilenet_v1", ++ name = "qs8_mobilenet_v1.wasm", + srcs = ["models/qs8-mobilenet-v1.cc"], + hdrs = ["models/models.h"], + copts = xnnpack_std_cxxopts(), +@@ -4955,7 +4967,7 @@ cc_library( + ) + + cc_library( +- name = "qs8_mobilenet_v2", ++ name = "qs8_mobilenet_v2.wasm", + srcs = ["models/qs8-mobilenet-v2.cc"], + hdrs = ["models/models.h"], + copts = xnnpack_std_cxxopts(), +@@ -4967,7 +4979,7 @@ cc_library( + ) + + cc_library( +- name = "fp32_mobilenet_v2", ++ name = "fp32_mobilenet_v2.wasm", + srcs = ["models/fp32-mobilenet-v2.cc"], + hdrs = ["models/models.h"], + copts = xnnpack_std_cxxopts(), +@@ -4979,7 +4991,7 @@ cc_library( + ) + + cc_library( +- name = "fp16_mobilenet_v2", ++ name = "fp16_mobilenet_v2.wasm", + srcs = ["models/fp16-mobilenet-v2.cc"], + hdrs = ["models/models.h"], + copts = xnnpack_std_cxxopts(), +@@ -4992,7 +5004,7 @@ cc_library( + ) + + cc_library( +- name = "fp32_mobilenet_v3_large", ++ name = "fp32_mobilenet_v3_large.wasm", + srcs = ["models/fp32-mobilenet-v3-large.cc"], + hdrs = ["models/models.h"], + copts = xnnpack_std_cxxopts(), +@@ -5004,7 +5016,7 @@ cc_library( + ) + + cc_library( +- name = "fp16_mobilenet_v3_large", ++ name = "fp16_mobilenet_v3_large.wasm", + srcs = ["models/fp16-mobilenet-v3-large.cc"], + hdrs = ["models/models.h"], + copts = xnnpack_std_cxxopts(), +@@ -5017,7 +5029,7 @@ cc_library( + ) + + cc_library( +- name = "fp32_mobilenet_v3_small", ++ name = "fp32_mobilenet_v3_small.wasm", + srcs = ["models/fp32-mobilenet-v3-small.cc"], + hdrs = ["models/models.h"], + copts = xnnpack_std_cxxopts(), +@@ -5029,7 +5041,7 @@ cc_library( + ) + + cc_library( +- name = "fp16_mobilenet_v3_small", ++ name = "fp16_mobilenet_v3_small.wasm", + srcs = ["models/fp16-mobilenet-v3-small.cc"], + hdrs = ["models/models.h"], + copts = xnnpack_std_cxxopts(), +@@ -5042,51 +5054,51 @@ cc_library( + ) + + xnnpack_benchmark( +- name = "f32_dwconv_e2e_bench", ++ name = "f32_dwconv_e2e_bench.wasm", + srcs = [ + "bench/f32-dwconv-e2e.cc", + "bench/end2end.h", + ] + MICROKERNEL_BENCHMARK_HDRS, + deps = MICROKERNEL_BENCHMARK_DEPS + [ + ":XNNPACK", +- ":fp32_mobilenet_v1", +- ":fp32_mobilenet_v2", +- ":fp32_mobilenet_v3_large", +- ":fp32_mobilenet_v3_small", ++ ":fp32_mobilenet_v1.wasm", ++ ":fp32_mobilenet_v2.wasm", ++ ":fp32_mobilenet_v3_large.wasm", ++ ":fp32_mobilenet_v3_small.wasm", + ], + ) + + xnnpack_benchmark( +- name = "f32_gemm_e2e_bench", ++ name = "f32_gemm_e2e_bench.wasm", + srcs = [ + "bench/f32-gemm-e2e.cc", + "bench/end2end.h", + ] + MICROKERNEL_BENCHMARK_HDRS, + deps = MICROKERNEL_BENCHMARK_DEPS + [ + ":XNNPACK", +- ":fp32_mobilenet_v1", +- ":fp32_mobilenet_v2", +- ":fp32_mobilenet_v3_large", +- ":fp32_mobilenet_v3_small", ++ ":fp32_mobilenet_v1.wasm", ++ ":fp32_mobilenet_v2.wasm", ++ ":fp32_mobilenet_v3_large.wasm", ++ ":fp32_mobilenet_v3_small.wasm", + ], + ) + + xnnpack_benchmark( +- name = "end2end_bench", ++ name = "end2end_bench.wasm", + srcs = ["bench/end2end.cc"], + deps = [ + ":XNNPACK", + ":bench_utils", +- ":fp16_mobilenet_v1", +- ":fp16_mobilenet_v2", +- ":fp16_mobilenet_v3_large", +- ":fp16_mobilenet_v3_small", +- ":fp32_mobilenet_v1", +- ":fp32_mobilenet_v2", +- ":fp32_mobilenet_v3_large", +- ":fp32_mobilenet_v3_small", +- ":qs8_mobilenet_v1", +- ":qs8_mobilenet_v2", ++ ":fp16_mobilenet_v1.wasm", ++ ":fp16_mobilenet_v2.wasm", ++ ":fp16_mobilenet_v3_large.wasm", ++ ":fp16_mobilenet_v3_small.wasm", ++ ":fp32_mobilenet_v1.wasm", ++ ":fp32_mobilenet_v2.wasm", ++ ":fp32_mobilenet_v3_large.wasm", ++ ":fp32_mobilenet_v3_small.wasm", ++ ":qs8_mobilenet_v1.wasm", ++ ":qs8_mobilenet_v2.wasm", + "@pthreadpool", + ], + ) +@@ -5094,7 +5106,7 @@ xnnpack_benchmark( + #################### Accuracy evaluation for math functions #################### + + xnnpack_benchmark( +- name = "f32_exp_eval", ++ name = "f32_exp_eval.wasm", + srcs = [ + "eval/f32-exp.cc", + "src/xnnpack/AlignedAllocator.h", +@@ -5103,7 +5115,7 @@ xnnpack_benchmark( + ) + + xnnpack_benchmark( +- name = "f32_expminus_eval", ++ name = "f32_expminus_eval.wasm", + srcs = [ + "eval/f32-expminus.cc", + "src/xnnpack/AlignedAllocator.h", +@@ -5112,7 +5124,7 @@ xnnpack_benchmark( + ) + + xnnpack_benchmark( +- name = "f32_extexp_eval", ++ name = "f32_extexp_eval.wasm", + srcs = [ + "eval/f32-extexp.cc", + "src/xnnpack/AlignedAllocator.h", +@@ -5121,7 +5133,7 @@ xnnpack_benchmark( + ) + + xnnpack_unit_test( +- name = "f32_roundne_eval", ++ name = "f32_roundne_eval.wasm", + srcs = [ + "eval/f32-roundne.cc", + "src/xnnpack/AlignedAllocator.h", +@@ -5132,7 +5144,7 @@ xnnpack_unit_test( + ) + + xnnpack_unit_test( +- name = "f32_roundd_eval", ++ name = "f32_roundd_eval.wasm", + srcs = [ + "eval/f32-roundd.cc", + "src/xnnpack/AlignedAllocator.h", +@@ -5143,7 +5155,7 @@ xnnpack_unit_test( + ) + + xnnpack_unit_test( +- name = "f32_roundu_eval", ++ name = "f32_roundu_eval.wasm", + srcs = [ + "eval/f32-roundu.cc", + "src/xnnpack/AlignedAllocator.h", +@@ -5154,7 +5166,7 @@ xnnpack_unit_test( + ) + + xnnpack_unit_test( +- name = "f32_roundz_eval", ++ name = "f32_roundz_eval.wasm", + srcs = [ + "eval/f32-roundz.cc", + "src/xnnpack/AlignedAllocator.h", +@@ -5165,7 +5177,7 @@ xnnpack_unit_test( + ) + + xnnpack_benchmark( +- name = "f32_sigmoid_eval", ++ name = "f32_sigmoid_eval.wasm", + srcs = [ + "eval/f32-sigmoid.cc", + "src/xnnpack/AlignedAllocator.h", +@@ -5174,7 +5186,7 @@ xnnpack_benchmark( + ) + + xnnpack_benchmark( +- name = "f32_sqrt_eval", ++ name = "f32_sqrt_eval.wasm", + srcs = [ + "eval/f32-sqrt.cc", + "src/xnnpack/AlignedAllocator.h", +diff --git a/emscripten.bzl b/emscripten.bzl +index faad087..2b4763f 100644 +--- a/emscripten.bzl ++++ b/emscripten.bzl +@@ -4,30 +4,25 @@ def xnnpack_emscripten_minimal_linkopts(): + """Minimal Emscripten-specific linkopts for binaries.""" + return [ + "-s ASSERTIONS=0", +- "-s ERROR_ON_UNDEFINED_SYMBOLS=1", +- "-s EXIT_RUNTIME=1", ++ "-s ERROR_ON_UNDEFINED_SYMBOLS=0", + ] + + def xnnpack_emscripten_test_linkopts(): + """Emscripten-specific linkopts for unit tests.""" + return [ + "-s ASSERTIONS=2", +- "-s ERROR_ON_UNDEFINED_SYMBOLS=1", ++ "-s ERROR_ON_UNDEFINED_SYMBOLS=0", + "-s DEMANGLE_SUPPORT=1", +- "-s EXIT_RUNTIME=1", + "-s ALLOW_MEMORY_GROWTH=1", +- "--pre-js $(location :preamble.js.lds)", + ] + + def xnnpack_emscripten_benchmark_linkopts(): + """Emscripten-specific linkopts for benchmarks.""" + return [ + "-s ASSERTIONS=1", +- "-s ERROR_ON_UNDEFINED_SYMBOLS=1", +- "-s EXIT_RUNTIME=1", ++ "-s ERROR_ON_UNDEFINED_SYMBOLS=0", + "-s ALLOW_MEMORY_GROWTH=1", + "-s TOTAL_MEMORY=268435456", # 256M +- "--pre-js $(location :preamble.js.lds)", + ] + + def xnnpack_emscripten_deps(): diff --git a/samples/workload/cmake/toolchain.cmake b/samples/workload/cmake/toolchain.cmake index 4b9ae8fd7..855913235 100644 --- a/samples/workload/cmake/toolchain.cmake +++ b/samples/workload/cmake/toolchain.cmake @@ -59,6 +59,8 @@ add_compile_options( $<$:-v> ) +# need users to create their own additional include files + ################ AR ################ find_program(LLVM_AR NAMES llvm-ar llvm-ar-11 REQUIRED) diff --git a/samples/workload/docker/Dockerfile b/samples/workload/docker/Dockerfile index 56f3adb22..cb96768c5 100644 --- a/samples/workload/docker/Dockerfile +++ b/samples/workload/docker/Dockerfile @@ -13,6 +13,7 @@ ARG WASI_SDK_VER=11.0 ARG WABT_VER=1.0.19 ARG CMAKE_VER=3.16.2 ARG BINARYEN_VER=version_97 +ARG BAZEL_VER=3.7.0 # # install wasi-sdk @@ -66,6 +67,16 @@ RUN cd /opt \ && rm ${BINARYEN_FILE} \ && ln -sf /opt/binaryen-${BINARYEN_VER} /opt/binaryen +RUN apt install -y unzip zip + +# +# install bazel +ARG BAZEL_FILE=bazel-${BAZEL_VER}-installer-linux-x86_64.sh +COPY ${BAZEL_FILE} /tmp +RUN cd /tmp \ + && chmod a+x ${BAZEL_FILE} \ + && ./${BAZEL_FILE} + # # Clean up RUN apt-get autoremove -y \ diff --git a/samples/workload/docker/build.sh b/samples/workload/docker/build.sh index c73c5bceb..d14606c8a 100755 --- a/samples/workload/docker/build.sh +++ b/samples/workload/docker/build.sh @@ -13,6 +13,7 @@ WASI_SDK_VER=11.0 WABT_VER=1.0.19 CMAKE_VER=3.16.2 BINARYEN_VER=version_97 +BAZEL_VER=3.7.0 cd build_scripts if [[ ! -f wasi-sdk-${WASI_SDK_VER}-linux.tar.gz ]]; then @@ -34,6 +35,10 @@ fi if [[ ! -f binaryen-${BINARYEN_VER}-x86_64-linux.tar.gz ]]; then wget https://github.com/WebAssembly/binaryen/releases/download/${BINARYEN_VER}/binaryen-${BINARYEN_VER}-x86_64-linux.tar.gz fi + +if [[ ! -f bazel-${BAZEL_VER}-installer-linux-x86_64.sh ]]; then + wget https://github.com/bazelbuild/bazel/releases/download/${BAZEL_VER}/bazel-${BAZEL_VER}-installer-linux-x86_64.sh +fi cd - docker build \ @@ -45,4 +50,5 @@ docker build \ --build-arg WABT_VER=${WABT_VER} \ --build-arg CMAKE_VER=${CMAKE_VER} \ --build-arg BINARYEN_VER=${BINARYEN_VER} \ + --build-arg BAZEL_VER=${BAZEL_VER} \ -t clang_env:0.1 -f Dockerfile build_scripts diff --git a/samples/workload/wasm-av1/.gitignore b/samples/workload/wasm-av1/.gitignore new file mode 100644 index 000000000..e8bec70e4 --- /dev/null +++ b/samples/workload/wasm-av1/.gitignore @@ -0,0 +1,8 @@ +# from CMakeLists +av1 +build +include + +# from build.sh +wasm-av1 +out diff --git a/samples/workload/wasm-av1/CMakeLists.avx_wasm.txt b/samples/workload/wasm-av1/CMakeLists.avx_wasm.txt new file mode 100644 index 000000000..78244b456 --- /dev/null +++ b/samples/workload/wasm-av1/CMakeLists.avx_wasm.txt @@ -0,0 +1,79 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required (VERSION 3.0) + +project(testavx) + +# a workaround to let aom find our non-public headers +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../include/libc) + +################ AOM ################ +set(ENABLE_CCACHE ON) +set(ENABLE_DOCS OFF CACHE BOOL "ENABLE_DOCS" FORCE) +set(ENABLE_EXAMPLES OFF CACHE BOOL "ENABLE_EXAMPLES" FORCE) +set(ENABLE_NEON OFF CACHE BOOL "ENABLE_EXAMPLES" FORCE) +set(ENABLE_NEON_ASM OFF CACHE BOOL "ENABLE_EXAMPLES" FORCE) +set(ENABLE_VSX OFF CACHE BOOL "ENABLE_EXAMPLES" FORCE) +set(ENABLE_MMX OFF CACHE BOOL "ENABLE_EXAMPLES" FORCE) +set(AOM_TARGET_CPU generic) +set(CONFIG_ACCOUNTING 1 CACHE NUMBER "" FORCE) +set(CONFIG_INSPECTION 1 CACHE NUMBER "" FORCE) +set(CONFIG_MULTITHREAD 0 CACHE NUMBER "" FORCE) +set(CONFIG_RUNTIME_CPU_DETECT 0 CACHE NUMBER "" FORCE) +set(CONFIG_UNIT_TESTS 0 CACHE NUMBER "" FORCE) +set(CONFIG_WEBM_IO 0 CACHE NUMBER "" FORCE) +add_subdirectory(third_party/aom third_party/aom/bin EXCLUDE_FROM_ALL) + +################ AV ################ +add_executable(${PROJECT_NAME} + test.c + decode-av1.c +) + +target_include_directories(${PROJECT_NAME} + PRIVATE + third_party/aom/ + ${CMAKE_CURRENT_BINARY_DIR}/third_party/aom/bin +) + +set_target_properties(${PROJECT_NAME} + PROPERTIES + OUTPUT_NAME ${PROJECT_NAME}.wasm +) + +target_link_options(${PROJECT_NAME} + PRIVATE + LINKER:--allow-undefined + LINKER:--export=__heap_base + LINKER:--export=__data_end + LINKER:--initial-memory=33554432 + LINKER:-z,stack-size=25165824 +) + +target_link_libraries(${PROJECT_NAME} + PRIVATE + aom +) + +add_dependencies(${PROJECT_NAME} aom) + +find_program(WASM_OPT + NAMES wasm-opt + PATHS /opt/binaryen-version_97/bin /opt/binaryen/bin +) + +if (NOT WASM_OPT) + message(WARNING "can not find wasm-opt and will not optimize any wasm module") +endif() + +add_custom_target(${PROJECT_NAME}_opt ALL + COMMAND + ${WASM_OPT} -Oz --enable-simd -o ${PROJECT_NAME}.opt.wasm ${PROJECT_NAME}.wasm + BYPRODUCTS + ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.opt.wasm + WORKING_DIRECTORY + ${CMAKE_CURRENT_BINARY_DIR} +) + +add_dependencies(${PROJECT_NAME}_opt ${PROJECT_NAME}) diff --git a/samples/workload/wasm-av1/CMakeLists.txt b/samples/workload/wasm-av1/CMakeLists.txt new file mode 100644 index 000000000..ae33e6ff6 --- /dev/null +++ b/samples/workload/wasm-av1/CMakeLists.txt @@ -0,0 +1,61 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required (VERSION 3.0) + +project(av1_wasm) + +################ BINARYEN ################ +find_program(WASM_OPT + NAMES wasm-opt + PATHS /opt/binaryen-version_97/bin /opt/binaryen/bin +) + +if (NOT WASM_OPT) + message(FATAL_ERROR + "can not find wasm-opt. " + "please download it from " + "https://github.com/WebAssembly/binaryen/releases/download/version_97/binaryen-version_97-x86_64-linux.tar.gz " + "and install it under /opt" + ) +endif() + +####################################### +include(ExternalProject) + +################ HEADERS ################ +ExternalProject_Add(headers_from_emcc + PREFIX headers + SOURCE_DIR "$ENV{EMSDK}/upstream/emscripten/system/" + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_SOURCE_DIR}/include/pthread/sys + && ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_SOURCE_DIR}/include/libc/bits + # copy emscripten pthread related header files + && ${CMAKE_COMMAND} -E copy $ENV{EMSDK}/upstream/emscripten/system/include/libc/pthread.h ${CMAKE_CURRENT_SOURCE_DIR}/include/pthread/ + && ${CMAKE_COMMAND} -E copy $ENV{EMSDK}/upstream/emscripten/system/include/libc/signal.h ${CMAKE_CURRENT_SOURCE_DIR}/include/pthread/ + && ${CMAKE_COMMAND} -E copy $ENV{EMSDK}/upstream/emscripten/system/include/libc/netdb.h ${CMAKE_CURRENT_SOURCE_DIR}/include/pthread/ + && ${CMAKE_COMMAND} -E copy $ENV{EMSDK}/upstream/emscripten/system/include/libc/sys/wait.h ${CMAKE_CURRENT_SOURCE_DIR}/include/pthread/sys/ + && ${CMAKE_COMMAND} -E copy $ENV{EMSDK}/upstream/emscripten/system/include/libc/sys/socket.h ${CMAKE_CURRENT_SOURCE_DIR}/include/pthread/sys/ + # copy emscripten setjmp headers + && ${CMAKE_COMMAND} -E copy $ENV{EMSDK}/upstream/emscripten/system/include/libc/setjmp.h ${CMAKE_CURRENT_SOURCE_DIR}/include/libc/setjmp.h + && ${CMAKE_COMMAND} -E copy $ENV{EMSDK}/upstream/emscripten/system/lib/libc/musl/arch/emscripten/bits/setjmp.h ${CMAKE_CURRENT_SOURCE_DIR}/include/libc/bits/setjmp.h +) + +################ av1 ################ +ExternalProject_Add(av1 + PREFIX av1 + GIT_REPOSITORY https://github.com/GoogleChromeLabs/wasm-av1.git + GIT_TAG master + GIT_PROGRESS ON + GIT_SHALLOW ON + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/av1 + DEPENDS headers_from_emcc + UPDATE_COMMAND git clean -fd && git checkout -- * + && ${CMAKE_COMMAND} -E echo "Copying pre-installed CMakeLists.txt" + && ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.avx_wasm.txt CMakeLists.txt + && git apply ../av1-clang.patch + CONFIGURE_COMMAND ${CMAKE_COMMAND} -DCMAKE_TOOLCHAIN_FILE=${CMAKE_CURRENT_SOURCE_DIR}/../cmake/toolchain.cmake ${CMAKE_CURRENT_SOURCE_DIR}/av1 + BUILD_COMMAND make testavx_opt + INSTALL_COMMAND ${CMAKE_COMMAND} -E copy testavx.opt.wasm ${CMAKE_CURRENT_BINARY_DIR}/testavx.wasm +) diff --git a/samples/workload/wasm-av1/README.md b/samples/workload/wasm-av1/README.md index 30cb6ca52..68dad1773 100644 --- a/samples/workload/wasm-av1/README.md +++ b/samples/workload/wasm-av1/README.md @@ -1,22 +1,56 @@ "wasm-av1" sample introduction ============== -This sample demonstrates how to build [wasm-av1](https://github.com/GoogleChromeLabs/wasm-av1) into WebAssembly with emcc toolchain and run it with iwasm. Please first install [emsdk](https://github.com/emscripten-core/emsdk): -```bash -git clone https://github.com/emscripten-core/emsdk.git -cd emsdk -./emsdk install latest -./emsdk activate latest -``` -And set up ensdk environment: -```bash -source emsdk_env.sh -``` -Then run + +This sample demonstrates how to build [wasm-av1](https://github.com/GoogleChromeLabs/wasm-av1) into +WebAssembly with simd support and run it with iwasm. + +## Preparation + +please refer to [installation instructions](../README.md). + +## Build with EMSDK + +just run the convenience script: + ```bash ./build.sh ``` -to build wasm-av1 and run it with iwasm, which basically contains the following steps: + +it is going to build wasm-av1 and run it with iwasm, which basically contains the following steps: - hack emcc to delete some objects in libc.a - patch wasm-av1 and build it with emcc compiler - build iwasm with simd and libc-emcc support - run testav1.aot with iwasm + +## Or build with clang-11 and wasi-sdk + +``` shell +$ mkdir build && cd build +$ cmake .. +$ make +# to verify +$ ls testavx.wasm +``` + +### Run workload + +Firstly please build iwasm with simd support: + +``` shell +$ cd /product-mini/platforms/linux/ +$ mkdir build && cd build +$ cmake .. -DWAMR_BUILD_SIMD=1 +$ make +``` + +Then compile wasm file to aot file and run: + +``` shell +$ cd /wamr-compiler/build +$ ./wamrc --enable-simd -o testavx.aot testavx.wasm +$ cd /product-mini/platforms/linux/ +$ # copy sample data like /samples/workload/wasm-av1/av1/third_party/samples/elephants_dream_480p24.ivf +$ # copy testavx.aot +$ # make sure you declare the access priority of the directory in which the sample data is +$ ./iwasm --dir=. ./testavx.aot ./elephants_dream_480p24.ivf +``` \ No newline at end of file diff --git a/samples/workload/wasm-av1/av1-clang.patch b/samples/workload/wasm-av1/av1-clang.patch new file mode 100644 index 000000000..97e795482 --- /dev/null +++ b/samples/workload/wasm-av1/av1-clang.patch @@ -0,0 +1,19 @@ +diff --git a/test.c b/test.c +index df2d44b..520bf13 100644 +--- a/test.c ++++ b/test.c +@@ -63,9 +63,14 @@ main(int argc, char *argv[]) { + static int i = 0; + + ++i; ++ printf("Decoding frame #%d\n", i); + if (30 <= i && i < 40) { ++ printf("Dumping frame #%d\n", i); + dump_raw_frame(af, i); + } ++ if (i >= 1000) { ++ break; ++ } + } + /* + * Run the decoder every time, so that we keep From f4770ae8c846a5bc4474fb3550ed9ef9d5f77b5b Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Mon, 23 Nov 2020 10:48:22 +0800 Subject: [PATCH 110/207] Add more llvm optimization passes (#445) Add more llvm optimization passes to improve AOT/JIT performance --- core/iwasm/compilation/aot_llvm.c | 14 ++++++++++++++ core/iwasm/compilation/aot_llvm.h | 2 ++ 2 files changed, 16 insertions(+) diff --git a/core/iwasm/compilation/aot_llvm.c b/core/iwasm/compilation/aot_llvm.c index 371f69cdb..352d53989 100644 --- a/core/iwasm/compilation/aot_llvm.c +++ b/core/iwasm/compilation/aot_llvm.c @@ -1401,6 +1401,20 @@ aot_create_comp_context(AOTCompData *comp_data, LLVMAddCFGSimplificationPass(comp_ctx->pass_mgr); LLVMAddJumpThreadingPass(comp_ctx->pass_mgr); LLVMAddConstantPropagationPass(comp_ctx->pass_mgr); + LLVMAddIndVarSimplifyPass(comp_ctx->pass_mgr); + + if (!option->is_jit_mode) { + LLVMAddLoopRotatePass(comp_ctx->pass_mgr); + LLVMAddLoopUnswitchPass(comp_ctx->pass_mgr); + LLVMAddInstructionCombiningPass(comp_ctx->pass_mgr); + LLVMAddCFGSimplificationPass(comp_ctx->pass_mgr); + LLVMAddGVNPass(comp_ctx->pass_mgr); + LLVMAddLICMPass(comp_ctx->pass_mgr); + LLVMAddLoopVectorizePass(comp_ctx->pass_mgr); + LLVMAddSLPVectorizePass(comp_ctx->pass_mgr); + LLVMAddInstructionCombiningPass(comp_ctx->pass_mgr); + LLVMAddCFGSimplificationPass(comp_ctx->pass_mgr); + } /* Create metadata for llvm float experimental constrained intrinsics */ if (!(comp_ctx->fp_rounding_mode = diff --git a/core/iwasm/compilation/aot_llvm.h b/core/iwasm/compilation/aot_llvm.h index 3da5ea98e..30163a8b1 100644 --- a/core/iwasm/compilation/aot_llvm.h +++ b/core/iwasm/compilation/aot_llvm.h @@ -13,7 +13,9 @@ #include "llvm-c/Object.h" #include "llvm-c/ExecutionEngine.h" #include "llvm-c/Analysis.h" +#include "llvm-c/Transforms/Utils.h" #include "llvm-c/Transforms/Scalar.h" +#include "llvm-c/Transforms/Vectorize.h" #ifdef __cplusplus extern "C" { From 74be7a0b7c05c30321dfb3fe7ba74047a650c19d Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Tue, 24 Nov 2020 14:00:09 +0800 Subject: [PATCH 111/207] Add more checks to enhance security (#446) add more checks to enhance security clear "wasi proc exit" exception before return to caller in wasm/aot call functions fix memory profiling issue change movdqa to movdqu in simd invokeNative asm codes to fix issue of unaligned address access move setjmp/longjmp from libc-builtin to libc-emcc fix zephyr platform compilation issue in latest zephyr version --- core/iwasm/aot/aot_runtime.c | 135 +++++++--- .../common/arch/invokeNative_em64_simd.s | 16 +- core/iwasm/common/wasm_c_api.c | 21 +- core/iwasm/common/wasm_runtime_common.c | 12 +- core/iwasm/common/wasm_shared_memory.c | 4 +- core/iwasm/compilation/aot_compiler.h | 2 +- core/iwasm/compilation/aot_emit_aot_file.c | 2 +- core/iwasm/compilation/aot_emit_control.c | 4 +- core/iwasm/compilation/aot_emit_function.c | 80 +++--- core/iwasm/interpreter/wasm_loader.c | 2 +- core/iwasm/interpreter/wasm_runtime.c | 233 +++++++++++------- .../lib-pthread/lib_pthread_wrapper.c | 11 + .../libc-builtin/libc_builtin_wrapper.c | 17 -- .../libraries/libc-emcc/libc_emcc_wrapper.c | 17 ++ .../libraries/libc-wasi/libc_wasi_wrapper.c | 6 +- .../sandboxed-system-primitives/src/posix.c | 4 +- .../libraries/thread-mgr/thread_manager.c | 4 + core/shared/platform/zephyr/zephyr_platform.c | 7 + core/shared/utils/bh_assert.c | 8 +- core/shared/utils/bh_hashmap.c | 10 +- .../src/platform/linux/iwasm_main.c | 5 +- samples/workload/wasm-av1/README.md | 2 +- samples/workload/wasm-av1/wasm-av1.patch | 9 +- wamr-compiler/main.c | 2 +- 24 files changed, 397 insertions(+), 216 deletions(-) diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index f31d36dfd..db047dc4a 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -643,6 +643,24 @@ create_exports(AOTModuleInstance *module_inst, AOTModule *module, error_buf, error_buf_size); } +static bool +clear_wasi_proc_exit_exception(AOTModuleInstance *module_inst) +{ +#if WASM_ENABLE_LIBC_WASI != 0 + const char *exception = aot_get_exception(module_inst); + if (exception && !strcmp(exception, "Exception: wasi proc exit")) { + /* The "wasi proc exit" exception is thrown by native lib to + let wasm app exit, which is a normal behavior, we clear + the exception here. */ + aot_set_exception(module_inst, NULL); + return true; + } + return false; +#else + return false; +#endif +} + static bool execute_post_inst_function(AOTModuleInstance *module_inst) { @@ -677,6 +695,7 @@ execute_start_function(AOTModuleInstance *module_inst) u.f(exec_env); wasm_exec_env_destroy(exec_env); + (void)clear_wasi_proc_exit_exception(module_inst); return !aot_get_exception(module_inst); } @@ -974,6 +993,7 @@ touch_pages(uint8 *stack_min_addr, uint32 page_size) sum += *(stack_min_addr + page_size - 1); break; } + *touch_addr = 0; sum += *touch_addr; } return sum; @@ -1011,7 +1031,7 @@ invoke_native_with_hw_bound_check(WASMExecEnv *exec_env, void *func_ptr, if (!exec_env->jmpbuf_stack_top) { /* Touch each stack page to ensure that it has been mapped: the OS may lazily grow the stack mapping as a guard page is hit. */ - touch_pages(stack_min_addr, page_size); + (void)touch_pages(stack_min_addr, page_size); /* First time to call aot function, protect one page */ if (os_mprotect(stack_min_addr, page_size * guard_page_count, MMAP_PROT_NONE) != 0) { @@ -1106,6 +1126,8 @@ aot_call_function(WASMExecEnv *exec_env, if (!ret || aot_get_exception(module_inst)) { if (argv1 != argv1_buf) wasm_runtime_free(argv1); + if (clear_wasi_proc_exit_exception(module_inst)) + return true; return false; } @@ -1134,6 +1156,8 @@ aot_call_function(WASMExecEnv *exec_env, else { ret = invoke_native_internal(exec_env, function->u.func.func_ptr, func_type, NULL, NULL, argv, argc, argv); + if (clear_wasi_proc_exit_exception(module_inst)) + return true; return ret && !aot_get_exception(module_inst) ? true : false; } } @@ -1377,10 +1401,15 @@ aot_validate_app_addr(AOTModuleInstance *module_inst, { AOTMemoryInstance *memory_inst = aot_get_default_memory(module_inst); + if (!memory_inst) { + goto fail; + } + /* integer overflow check */ if(app_offset + size < app_offset) { goto fail; } + if (app_offset + size <= memory_inst->memory_data_size) { return true; } @@ -1393,8 +1422,12 @@ bool aot_validate_native_addr(AOTModuleInstance *module_inst, void *native_ptr, uint32 size) { - uint8 *addr = (uint8 *)native_ptr; AOTMemoryInstance *memory_inst = aot_get_default_memory(module_inst); + uint8 *addr = (uint8 *)native_ptr; + + if (!memory_inst) { + goto fail; + } /* integer overflow check */ if (addr + size < addr) { @@ -1413,7 +1446,13 @@ void * aot_addr_app_to_native(AOTModuleInstance *module_inst, uint32 app_offset) { AOTMemoryInstance *memory_inst = aot_get_default_memory(module_inst); - uint8 *addr = (uint8 *)memory_inst->memory_data.ptr + app_offset; + uint8 *addr; + + if (!memory_inst) { + return NULL; + } + + addr = (uint8 *)memory_inst->memory_data.ptr + app_offset; if ((uint8 *)memory_inst->memory_data.ptr <= addr && addr < (uint8 *)memory_inst->memory_data_end.ptr) @@ -1424,8 +1463,12 @@ aot_addr_app_to_native(AOTModuleInstance *module_inst, uint32 app_offset) uint32 aot_addr_native_to_app(AOTModuleInstance *module_inst, void *native_ptr) { - uint8 *addr = (uint8 *)native_ptr; AOTMemoryInstance *memory_inst = aot_get_default_memory(module_inst); + uint8 *addr = (uint8 *)native_ptr; + + if (!memory_inst) { + return 0; + } if ((uint8 *)memory_inst->memory_data.ptr <= addr && addr < (uint8 *)memory_inst->memory_data_end.ptr) @@ -1440,7 +1483,13 @@ aot_get_app_addr_range(AOTModuleInstance *module_inst, uint32 *p_app_end_offset) { AOTMemoryInstance *memory_inst = aot_get_default_memory(module_inst); - uint32 memory_data_size = memory_inst->memory_data_size; + uint32 memory_data_size; + + if (!memory_inst) { + return false; + } + + memory_data_size = memory_inst->memory_data_size; if (app_offset < memory_data_size) { if (p_app_start_offset) @@ -1458,8 +1507,12 @@ aot_get_native_addr_range(AOTModuleInstance *module_inst, uint8 **p_native_start_addr, uint8 **p_native_end_addr) { - uint8 *addr = (uint8 *)native_ptr; AOTMemoryInstance *memory_inst = aot_get_default_memory(module_inst); + uint8 *addr = (uint8 *)native_ptr; + + if (!memory_inst) { + return false; + } if ((uint8 *)memory_inst->memory_data.ptr <= addr && addr < (uint8 *)memory_inst->memory_data_end.ptr) { @@ -1477,17 +1530,24 @@ bool aot_enlarge_memory(AOTModuleInstance *module_inst, uint32 inc_page_count) { AOTMemoryInstance *memory_inst = aot_get_default_memory(module_inst); - uint32 num_bytes_per_page = memory_inst->num_bytes_per_page; - uint32 cur_page_count = memory_inst->cur_page_count; - uint32 max_page_count = memory_inst->max_page_count; - uint32 total_page_count = cur_page_count + inc_page_count; - uint32 total_size_old = memory_inst->memory_data_size; - uint64 total_size = (uint64)num_bytes_per_page * total_page_count; - uint32 heap_size = (uint32)((uint8 *)memory_inst->heap_data_end.ptr - - (uint8 *)memory_inst->heap_data.ptr); - uint8 *memory_data_old = (uint8 *)memory_inst->memory_data.ptr; - uint8 *heap_data_old = (uint8 *)memory_inst->heap_data.ptr; - uint8 *memory_data, *heap_data; + uint32 num_bytes_per_page, cur_page_count, max_page_count; + uint32 total_page_count, total_size_old, heap_size; + uint64 total_size; + uint8 *memory_data_old, *heap_data_old, *memory_data, *heap_data; + + if (!memory_inst) + return false; + + num_bytes_per_page = memory_inst->num_bytes_per_page; + cur_page_count = memory_inst->cur_page_count; + max_page_count = memory_inst->max_page_count; + total_page_count = cur_page_count + inc_page_count; + total_size_old = memory_inst->memory_data_size; + total_size = (uint64)num_bytes_per_page * total_page_count; + heap_size = (uint32)((uint8 *)memory_inst->heap_data_end.ptr + - (uint8 *)memory_inst->heap_data.ptr); + memory_data_old = (uint8 *)memory_inst->memory_data.ptr; + heap_data_old = (uint8 *)memory_inst->heap_data.ptr; if (inc_page_count <= 0) /* No need to enlarge memory */ @@ -1563,11 +1623,18 @@ bool aot_enlarge_memory(AOTModuleInstance *module_inst, uint32 inc_page_count) { AOTMemoryInstance *memory_inst = aot_get_default_memory(module_inst); - uint32 num_bytes_per_page = memory_inst->num_bytes_per_page; - uint32 cur_page_count = memory_inst->cur_page_count; - uint32 max_page_count = memory_inst->max_page_count; - uint32 total_page_count = cur_page_count + inc_page_count; - uint64 total_size = (uint64)num_bytes_per_page * total_page_count; + uint32 num_bytes_per_page, cur_page_count, max_page_count; + uint32 total_page_count; + uint64 total_size; + + if (!memory_inst) + return false; + + num_bytes_per_page = memory_inst->num_bytes_per_page; + cur_page_count = memory_inst->cur_page_count; + max_page_count = memory_inst->max_page_count; + total_page_count = cur_page_count + inc_page_count; + total_size = (uint64)num_bytes_per_page * total_page_count; if (inc_page_count <= 0) /* No need to enlarge memory */ @@ -1802,6 +1869,8 @@ aot_call_indirect(WASMExecEnv *exec_env, if (!ret || aot_get_exception(module_inst)) { if (argv1 != argv1_buf) wasm_runtime_free(argv1); + if (clear_wasi_proc_exit_exception(module_inst)) + return true; return false; } @@ -1829,9 +1898,12 @@ aot_call_indirect(WASMExecEnv *exec_env, return true; } else { - return invoke_native_internal(exec_env, func_ptr, - func_type, signature, attachment, - argv, argc, argv); + ret = invoke_native_internal(exec_env, func_ptr, + func_type, signature, attachment, + argv, argc, argv); + if (clear_wasi_proc_exit_exception(module_inst)) + return true; + return ret; } } @@ -2013,15 +2085,15 @@ aot_get_module_mem_consumption(const AOTModule *module, mem_conspn->data_segs_size += sizeof(AOTMemInitData); } - mem_conspn->const_strs_size = - bh_hash_map_get_struct_size(module->const_str_set); - - const_string_size = 0; if (module->const_str_set) { + mem_conspn->const_strs_size = + bh_hash_map_get_struct_size(module->const_str_set); + + const_string_size = 0; bh_hash_map_traverse(module->const_str_set, const_string_node_size_cb); + mem_conspn->const_strs_size += const_string_size; } - mem_conspn->const_strs_size += const_string_size; /* code size + literal size + object data section size */ mem_conspn->aot_code_size = module->code_size + module->literal_size @@ -2065,6 +2137,9 @@ aot_get_module_inst_mem_consumption(const AOTModuleInstance *module_inst, mem_inst->num_bytes_per_page * mem_inst->cur_page_count; mem_conspn->app_heap_size = mem_inst->heap_data_end.ptr - mem_inst->heap_data.ptr; + /* size of app heap structure */ + mem_conspn->memories_size += + mem_allocator_get_heap_struct_size(); } mem_conspn->tables_size = sizeof(uint32) * module_inst->table_size; diff --git a/core/iwasm/common/arch/invokeNative_em64_simd.s b/core/iwasm/common/arch/invokeNative_em64_simd.s index eb9a58bc0..0043ac941 100644 --- a/core/iwasm/common/arch/invokeNative_em64_simd.s +++ b/core/iwasm/common/arch/invokeNative_em64_simd.s @@ -41,14 +41,14 @@ push_args: loop push_args push_args_end: /* fill all fp args */ - movdqa 0x00(%rsi), %xmm0 - movdqa 0x10(%rsi), %xmm1 - movdqa 0x20(%rsi), %xmm2 - movdqa 0x30(%rsi), %xmm3 - movdqa 0x40(%rsi), %xmm4 - movdqa 0x50(%rsi), %xmm5 - movdqa 0x60(%rsi), %xmm6 - movdqa 0x70(%rsi), %xmm7 + movdqu 0x00(%rsi), %xmm0 + movdqu 0x10(%rsi), %xmm1 + movdqu 0x20(%rsi), %xmm2 + movdqu 0x30(%rsi), %xmm3 + movdqu 0x40(%rsi), %xmm4 + movdqu 0x50(%rsi), %xmm5 + movdqu 0x60(%rsi), %xmm6 + movdqu 0x70(%rsi), %xmm7 /* fill all int args */ movq 0x80(%rsi), %rdi diff --git a/core/iwasm/common/wasm_c_api.c b/core/iwasm/common/wasm_c_api.c index 0ef9d4ceb..c8f7701a6 100644 --- a/core/iwasm/common/wasm_c_api.c +++ b/core/iwasm/common/wasm_c_api.c @@ -579,8 +579,10 @@ wasm_functype_new(wasm_valtype_vec_t *params, wasm_valtype_vec_t *results) failed: LOG_DEBUG("%s failed", __FUNCTION__); - FREEIF(func_type->params); - FREEIF(func_type->results); + if (func_type) + FREEIF(func_type->params); + if (func_type) + FREEIF(func_type->results); FREEIF(func_type); return NULL; } @@ -1151,10 +1153,15 @@ native_func_trampoline(wasm_exec_env_t exec_env, uint64 *argv) } if (trap) { - wasm_name_t *message = NULL; - wasm_trap_message(trap, message); - LOG_WARNING("got a trap %s", message->data); - wasm_name_delete(message); + wasm_name_t *message = malloc_internal(sizeof(wasm_name_t)); + if (message) { + wasm_trap_message(trap, message); + if (message->data) { + LOG_WARNING("got a trap %s", message->data); + wasm_name_delete(message); + } + FREEIF(message); + } } /* there is no result or there is an exception */ @@ -2188,7 +2195,7 @@ interp_process_export(wasm_store_t *store, uint32 export_cnt = 0; uint32 i = 0; - bh_assert(store && inst_interp && externals); + bh_assert(store && inst_interp && inst_interp->module && externals); exports = inst_interp->module->exports; export_cnt = inst_interp->module->export_count; diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index bcc68a10b..b5b700b4b 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -2094,6 +2094,11 @@ wasm_application_execute_main(WASMModuleInstanceCommon *module_inst, func_type = ((AOTFunctionInstance*)func)->u.func.func_type; #endif + if (!func_type) { + LOG_ERROR("invalid module instance type"); + return false; + } + if (!check_main_func_type(func_type)) { wasm_runtime_set_exception(module_inst, "invalid function type of main function"); @@ -2318,7 +2323,7 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, { WASMFunctionInstanceCommon *func; WASMType *type = NULL; - uint32 argc1, *argv1 = NULL, cell_num, j, k = 0; + uint32 argc1, *argv1 = NULL, cell_num = 0, j, k = 0; int32 i, p; uint64 total_size; const char *exception; @@ -2362,6 +2367,11 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, } #endif + if (!type) { + LOG_ERROR("invalid module instance type"); + return false; + } + if (type->param_count != (uint32)argc) { wasm_runtime_set_exception(module_inst, "invalid input argument count"); diff --git a/core/iwasm/common/wasm_shared_memory.c b/core/iwasm/common/wasm_shared_memory.c index a0e267590..cef0aa364 100644 --- a/core/iwasm/common/wasm_shared_memory.c +++ b/core/iwasm/common/wasm_shared_memory.c @@ -200,8 +200,10 @@ notify_wait_list(bh_list *wait_list, uint32 count) notify_count = wait_list->len; node = bh_list_first_elem(wait_list); + if (!node) + return 0; - for (i = 0; i < count; i++) { + for (i = 0; i < notify_count; i++) { bh_assert(node); next = bh_list_elem_next(node); diff --git a/core/iwasm/compilation/aot_compiler.h b/core/iwasm/compilation/aot_compiler.h index 88bccc552..5031d3a47 100644 --- a/core/iwasm/compilation/aot_compiler.h +++ b/core/iwasm/compilation/aot_compiler.h @@ -180,11 +180,11 @@ typedef enum FloatArithmetic { goto fail; \ } \ aot_value = wasm_runtime_malloc(sizeof(AOTValue)); \ - memset(aot_value, 0, sizeof(AOTValue)); \ if (!aot_value) { \ aot_set_last_error("allocate memory failed."); \ goto fail; \ } \ + memset(aot_value, 0, sizeof(AOTValue)); \ aot_value->type = value_type; \ aot_value->value = llvm_value; \ aot_value_stack_push \ diff --git a/core/iwasm/compilation/aot_emit_aot_file.c b/core/iwasm/compilation/aot_emit_aot_file.c index 3a5641de6..17cc32622 100644 --- a/core/iwasm/compilation/aot_emit_aot_file.c +++ b/core/iwasm/compilation/aot_emit_aot_file.c @@ -878,7 +878,7 @@ static union { uint64 *t = (uint64*)v.i64x2; \ CHECK_BUF(16); \ if (!is_little_endian()) \ - exchange_uint128((uint8 *)&t); \ + exchange_uint128((uint8 *)t); \ PUT_U64_TO_ADDR(buf + offset, t[0]); \ offset += (uint32)sizeof(uint64); \ PUT_U64_TO_ADDR(buf + offset, t[1]); \ diff --git a/core/iwasm/compilation/aot_emit_control.c b/core/iwasm/compilation/aot_emit_control.c index 783fb527d..6c1c6f9e7 100644 --- a/core/iwasm/compilation/aot_emit_control.c +++ b/core/iwasm/compilation/aot_emit_control.c @@ -155,12 +155,14 @@ handle_next_reachable_block(AOTCompContext *comp_ctx, { AOTBlock *block = func_ctx->block_stack.block_list_end; AOTBlock *block_prev; - uint8 *frame_ip; + uint8 *frame_ip = NULL; uint32 i; AOTFuncType *func_type; aot_checked_addr_list_destroy(func_ctx); + bh_assert(block); + if (block->label_type == LABEL_TYPE_IF && block->llvm_else_block && !block->skip_wasm_code_else diff --git a/core/iwasm/compilation/aot_emit_function.c b/core/iwasm/compilation/aot_emit_function.c index dd701d89e..e20e175d2 100644 --- a/core/iwasm/compilation/aot_emit_function.c +++ b/core/iwasm/compilation/aot_emit_function.c @@ -358,6 +358,46 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, for (i = param_count - 1; i >= 0; i--) POP(param_values[i + j], func_type->types[i]); + /* Set parameters for multiple return values, the first return value + is returned by function return value, and the other return values + are returned by function parameters with pointer types */ + if (ext_ret_count > 0) { + ext_ret_types = func_type->types + param_count + 1; + ext_ret_cell_num = wasm_get_cell_num(ext_ret_types, ext_ret_count); + if (ext_ret_cell_num > 64) { + aot_set_last_error("prepare extra results's return " + "address arguments failed: " + "maximum 64 parameter cell number supported."); + goto fail; + } + + for (i = 0; i < ext_ret_count; i++) { + if (!(ext_ret_idx = I32_CONST(cell_num)) + || !(ext_ret_ptr_type = + LLVMPointerType(TO_LLVM_TYPE(ext_ret_types[i]), 0))) { + aot_set_last_error("llvm add const or pointer type failed."); + goto fail; + } + + snprintf(buf, sizeof(buf), "ext_ret%d_ptr", i); + if (!(ext_ret_ptr = LLVMBuildInBoundsGEP(comp_ctx->builder, + func_ctx->argv_buf, + &ext_ret_idx, 1, buf))) { + aot_set_last_error("llvm build GEP failed."); + goto fail; + } + snprintf(buf, sizeof(buf), "ext_ret%d_ptr_cast", i); + if (!(ext_ret_ptr = LLVMBuildBitCast(comp_ctx->builder, + ext_ret_ptr, ext_ret_ptr_type, + buf))) { + aot_set_last_error("llvm build bit cast failed."); + goto fail; + } + param_values[param_count + 1 + i] = ext_ret_ptr; + cell_num += wasm_value_type_cell_num(ext_ret_types[i]); + } + } + if (func_idx < import_func_count) { if (!(import_func_idx = I32_CONST(func_idx))) { aot_set_last_error("llvm build inbounds gep failed."); @@ -407,46 +447,6 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, && !check_stack_boundary(comp_ctx, func_ctx, callee_cell_num)) goto fail; - /* Prepare parameters for extra results */ - if (ext_ret_count > 0) { - ext_ret_types = func_type->types + param_count + 1; - ext_ret_cell_num = - wasm_get_cell_num(ext_ret_types, ext_ret_count); - if (ext_ret_cell_num > 64) { - aot_set_last_error("prepare extra results's return " - "address arguments failed: " - "maximum 64 parameter cell number supported."); - goto fail; - } - - for (i = 0; i < ext_ret_count; i++) { - if (!(ext_ret_idx = I32_CONST(cell_num)) - || !(ext_ret_ptr_type = - LLVMPointerType(TO_LLVM_TYPE(ext_ret_types[i]), 0))) { - aot_set_last_error("llvm add const or pointer type failed."); - goto fail; - } - - snprintf(buf, sizeof(buf), "func%d_ext_ret%d_ptr", func_idx, i); - if (!(ext_ret_ptr = LLVMBuildInBoundsGEP(comp_ctx->builder, - func_ctx->argv_buf, - &ext_ret_idx, 1, buf))) { - aot_set_last_error("llvm build GEP failed."); - goto fail; - } - snprintf(buf, sizeof(buf), "func%d_ext_ret%d_ptr_cast", func_idx, i); - if (!(ext_ret_ptr = LLVMBuildBitCast(comp_ctx->builder, - ext_ret_ptr, - ext_ret_ptr_type, - buf))) { - aot_set_last_error("llvm build bit cast failed."); - goto fail; - } - param_values[1 + param_count + i] = ext_ret_ptr; - cell_num += wasm_value_type_cell_num(ext_ret_types[i]); - } - } - /* Call the function */ if (!(value_ret = LLVMBuildCall(comp_ctx->builder, func, param_values, diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index 5d8b997e1..a92bb3195 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -2999,7 +2999,7 @@ create_sections(const uint8 *buf, uint32 size, section->section_body = (uint8*)p; section->section_body_size = section_size; - if (!*p_section_list) + if (!section_list_end) *p_section_list = section_list_end = section; else { section_list_end->next = section; diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index d01e52813..7f32b5ae3 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -343,26 +343,22 @@ memories_instantiate(const WASMModule *module, uint32 actual_heap_size = heap_size; #if WASM_ENABLE_MULTI_MODULE != 0 - WASMMemoryInstance *memory_inst_linked = NULL; if (import->u.memory.import_module != NULL) { WASMModuleInstance *module_inst_linked; - LOG_DEBUG("(%s, %s) is a memory of a sub-module", - import->u.memory.module_name, - import->u.memory.field_name); + if (!(module_inst_linked = get_sub_module_inst( + module_inst, import->u.memory.import_module))) { + set_error_buf(error_buf, error_buf_size, "unknown memory"); + memories_deinstantiate(module_inst, memories, memory_count); + return NULL; + } - module_inst_linked = - get_sub_module_inst(module_inst, - import->u.memory.import_module); - bh_assert(module_inst_linked); - - memory_inst_linked = - wasm_lookup_memory(module_inst_linked, - import->u.memory.field_name); - bh_assert(memory_inst_linked); - - memories[mem_index++] = memory_inst_linked; - memory = memory_inst_linked; + if (!(memory = memories[mem_index++] = wasm_lookup_memory( + module_inst_linked, import->u.memory.field_name))) { + set_error_buf(error_buf, error_buf_size, "unknown memory"); + memories_deinstantiate(module_inst, memories, memory_count); + return NULL; + } } else #endif @@ -374,6 +370,13 @@ memories_instantiate(const WASMModule *module, memories_deinstantiate(module_inst, memories, memory_count); return NULL; } +#if WASM_ENABLE_MULTI_MODULE != 0 + /* The module of the import memory is a builtin module, and + the memory is created by current module, set its owner + to current module, so the memory can be destroyed in + memories_deinstantiate. */ + memory->owner = module_inst; +#endif } } @@ -453,17 +456,19 @@ tables_instantiate(const WASMModule *module, WASMTableInstance *table_inst_linked = NULL; WASMModuleInstance *module_inst_linked = NULL; if (import->u.table.import_module) { - LOG_DEBUG("(%s, %s) is a table of a sub-module", - import->u.table.module_name, - import->u.memory.field_name); + if (!(module_inst_linked = + get_sub_module_inst(module_inst, import->u.table.import_module))) { + set_error_buf(error_buf, error_buf_size, "unknown table"); + tables_deinstantiate(tables, table_count); + return NULL; + } - module_inst_linked = - get_sub_module_inst(module_inst, import->u.table.import_module); - bh_assert(module_inst_linked); - - table_inst_linked = wasm_lookup_table(module_inst_linked, - import->u.table.field_name); - bh_assert(table_inst_linked); + if (!(table_inst_linked = wasm_lookup_table(module_inst_linked, + import->u.table.field_name))) { + set_error_buf(error_buf, error_buf_size, "unknown table"); + tables_deinstantiate(tables, table_count); + return NULL; + } total_size = offsetof(WASMTableInstance, base_addr); } @@ -692,16 +697,17 @@ globals_instantiate(const WASMModule *module, global->is_mutable = global_import->is_mutable; #if WASM_ENABLE_MULTI_MODULE != 0 if (global_import->import_module) { - WASMModuleInstance *sub_module_inst = get_sub_module_inst( - module_inst, global_import->import_module); - bh_assert(sub_module_inst); + if (!(global->import_module_inst = get_sub_module_inst( + module_inst, global_import->import_module))) { + set_error_buf(error_buf, error_buf_size, "unknown global"); + return NULL; + } - WASMGlobalInstance *global_inst_linked = - wasm_lookup_global(sub_module_inst, global_import->field_name); - bh_assert(global_inst_linked); - - global->import_global_inst = global_inst_linked; - global->import_module_inst = sub_module_inst; + if (!(global->import_global_inst = wasm_lookup_global( + global->import_module_inst, global_import->field_name))) { + set_error_buf(error_buf, error_buf_size, "unknown global"); + return NULL; + } /** * although, actually don't need initial_value for an imported @@ -709,15 +715,11 @@ globals_instantiate(const WASMModule *module, * global-data and * (global $g2 i32 (global.get $g1)) */ - WASMGlobal *linked_global = global_import->import_global_linked; - InitializerExpression *linked_init_expr = - &(linked_global->init_expr); - - bool ret = parse_init_expr( - linked_init_expr, - sub_module_inst->globals, - sub_module_inst->global_count, &(global->initial_value)); - if (!ret) { + if (!parse_init_expr( + &(global_import->import_global_linked->init_expr), + global->import_module_inst->globals, + global->import_module_inst->global_count, + &(global->initial_value))) { set_error_buf(error_buf, error_buf_size, "unknown global"); return NULL; } @@ -1047,6 +1049,7 @@ sub_module_deinstantiate(WASMModuleInstance *module_inst) WASMSubModInstNode *next_node = bh_list_elem_next(node); bh_list_remove(list, node); wasm_deinstantiate(node->module_inst, false); + wasm_runtime_free(node); node = next_node; } } @@ -1143,8 +1146,7 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, error_buf, error_buf_size); if (!ret) { LOG_DEBUG("build a sub module list failed"); - wasm_deinstantiate(module_inst, false); - return NULL; + goto fail; } #endif @@ -1154,8 +1156,7 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, && !(globals = globals_instantiate(module, module_inst, &global_data_size, error_buf, error_buf_size))) { - wasm_deinstantiate(module_inst, false); - return NULL; + goto fail; } module_inst->global_count = global_count; module_inst->globals = globals; @@ -1178,8 +1179,7 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, if (global_count > 0) { if (!(module_inst->global_data = runtime_malloc (global_data_size, error_buf, error_buf_size))) { - wasm_deinstantiate(module_inst, false); - return NULL; + goto fail; } } @@ -1210,8 +1210,7 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, error_buf, error_buf_size))) #endif ) { - wasm_deinstantiate(module_inst, false); - return NULL; + goto fail; } if (global_count > 0) { @@ -1221,8 +1220,7 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, */ if (!globals_instantiate_fix(globals, module, error_buf, error_buf_size)) { - wasm_deinstantiate(module_inst, false); - return NULL; + goto fail; } /* Initialize the global data */ @@ -1250,8 +1248,7 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, } if (!check_linked_symbol(module_inst, error_buf, error_buf_size)) { - wasm_deinstantiate(module_inst, false); - return NULL; + goto fail; } /* Initialize the memory data with data segment section */ @@ -1285,9 +1282,14 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, if (data_seg->base_offset.init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL) { - bh_assert(data_seg->base_offset.u.global_index < global_count - && globals[data_seg->base_offset.u.global_index].type - == VALUE_TYPE_I32); + if (!globals + || data_seg->base_offset.u.global_index >= global_count + || globals[data_seg->base_offset.u.global_index].type + != VALUE_TYPE_I32) { + set_error_buf(error_buf, error_buf_size, + "data segment does not fit"); + goto fail; + } data_seg->base_offset.u.i32 = globals[data_seg->base_offset.u.global_index] .initial_value.i32; @@ -1300,8 +1302,7 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, memory_size); set_error_buf(error_buf, error_buf_size, "data segment does not fit"); - wasm_deinstantiate(module_inst, false); - return NULL; + goto fail; } /* check offset + length(could be zero) */ @@ -1311,8 +1312,7 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, base_offset, length, memory_size); set_error_buf(error_buf, error_buf_size, "data segment does not fit"); - wasm_deinstantiate(module_inst, false); - return NULL; + goto fail; } bh_memcpy_s(memory_data + base_offset, memory_size - base_offset, @@ -1344,9 +1344,14 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, if (table_seg->base_offset.init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL) { - bh_assert(table_seg->base_offset.u.global_index < global_count - && globals[table_seg->base_offset.u.global_index].type - == VALUE_TYPE_I32); + if (!globals + || table_seg->base_offset.u.global_index >= global_count + || globals[table_seg->base_offset.u.global_index].type + != VALUE_TYPE_I32) { + set_error_buf(error_buf, error_buf_size, + "elements segment does not fit"); + goto fail; + } table_seg->base_offset.u.i32 = globals[table_seg->base_offset.u.global_index].initial_value.i32; } @@ -1357,8 +1362,7 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, table_seg->base_offset.u.i32, table->cur_size); set_error_buf(error_buf, error_buf_size, "elements segment does not fit"); - wasm_deinstantiate(module_inst, false); - return NULL; + goto fail; } /* check offset + length(could be zero) */ @@ -1368,8 +1372,7 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, table_seg->base_offset.u.i32, length, table->cur_size); set_error_buf(error_buf, error_buf_size, "elements segment does not fit"); - wasm_deinstantiate(module_inst, false); - return NULL; + goto fail; } /** @@ -1420,8 +1423,7 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, module->wasi_args.argv, module->wasi_args.argc, error_buf, error_buf_size)) { - wasm_deinstantiate(module_inst, false); - return NULL; + goto fail; } } #endif @@ -1438,8 +1440,7 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, || !execute_start_function(module_inst)) { set_error_buf(error_buf, error_buf_size, module_inst->cur_exception); - wasm_deinstantiate(module_inst, false); - return NULL; + goto fail; } #if WASM_ENABLE_BULK_MEMORY != 0 @@ -1453,8 +1454,7 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, if (!execute_memory_init_function(module_inst)) { set_error_buf(error_buf, error_buf_size, module_inst->cur_exception); - wasm_deinstantiate(module_inst, false); - return NULL; + goto fail; } } #if WASM_ENABLE_LIBC_WASI != 0 @@ -1468,6 +1468,9 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, #endif (void)global_data_end; return module_inst; +fail: + wasm_deinstantiate(module_inst, false); + return NULL; } void @@ -1555,6 +1558,24 @@ wasm_lookup_table(const WASMModuleInstance *module_inst, const char *name) } #endif +static bool +clear_wasi_proc_exit_exception(WASMModuleInstance *module_inst) +{ +#if WASM_ENABLE_LIBC_WASI != 0 + const char *exception = wasm_get_exception(module_inst); + if (exception && !strcmp(exception, "Exception: wasi proc exit")) { + /* The "wasi proc exit" exception is thrown by native lib to + let wasm app exit, which is a normal behavior, we clear + the exception here. */ + wasm_set_exception(module_inst, NULL); + return true; + } + return false; +#else + return false; +#endif +} + bool wasm_call_function(WASMExecEnv *exec_env, WASMFunctionInstance *function, @@ -1562,6 +1583,7 @@ wasm_call_function(WASMExecEnv *exec_env, { WASMModuleInstance *module_inst = (WASMModuleInstance*)exec_env->module_inst; wasm_interp_call_wasm(module_inst, exec_env, function, argc, argv); + (void)clear_wasi_proc_exit_exception(module_inst); return !wasm_get_exception(module_inst) ? true : false; } @@ -1696,8 +1718,13 @@ wasm_validate_app_addr(WASMModuleInstance *module_inst, uint32 app_offset, uint32 size) { WASMMemoryInstance *memory = module_inst->default_memory; - uint32 memory_data_size = - memory->num_bytes_per_page * memory->cur_page_count; + uint32 memory_data_size; + + if (!memory) { + goto fail; + } + + memory_data_size = memory->num_bytes_per_page * memory->cur_page_count; /* integer overflow check */ if (app_offset + size < app_offset) { @@ -1716,8 +1743,12 @@ bool wasm_validate_native_addr(WASMModuleInstance *module_inst, void *native_ptr, uint32 size) { - uint8 *addr = (uint8 *)native_ptr; WASMMemoryInstance *memory = module_inst->default_memory; + uint8 *addr = (uint8 *)native_ptr; + + if (!memory) { + goto fail; + } /* integer overflow check */ if (addr + size < addr) { @@ -1738,7 +1769,12 @@ wasm_addr_app_to_native(WASMModuleInstance *module_inst, uint32 app_offset) { WASMMemoryInstance *memory = module_inst->default_memory; - uint8 *addr = memory->memory_data + app_offset; + uint8 *addr; + + if (!memory) + return NULL; + + addr = memory->memory_data + app_offset; if (memory->memory_data <= addr && addr < memory->memory_data_end) @@ -1753,6 +1789,9 @@ wasm_addr_native_to_app(WASMModuleInstance *module_inst, WASMMemoryInstance *memory = module_inst->default_memory; uint8 *addr = (uint8 *)native_ptr; + if (!memory) + return 0; + if (memory->memory_data <= addr && addr < memory->memory_data_end) return (uint32)(addr - memory->memory_data); @@ -1766,8 +1805,12 @@ wasm_get_app_addr_range(WASMModuleInstance *module_inst, uint32 *p_app_end_offset) { WASMMemoryInstance *memory = module_inst->default_memory; - uint32 memory_data_size = - memory->num_bytes_per_page * memory->cur_page_count; + uint32 memory_data_size; + + if (!memory) + return false; + + memory_data_size = memory->num_bytes_per_page * memory->cur_page_count; if (app_offset < memory_data_size) { if (p_app_start_offset) @@ -1788,6 +1831,9 @@ wasm_get_native_addr_range(WASMModuleInstance *module_inst, WASMMemoryInstance *memory = module_inst->default_memory; uint8 *addr = (uint8 *)native_ptr; + if (!memory) + return false; + if (memory->memory_data <= addr && addr < memory->memory_data_end) { if (p_native_start_addr) @@ -1803,12 +1849,19 @@ bool wasm_enlarge_memory(WASMModuleInstance *module, uint32 inc_page_count) { WASMMemoryInstance *memory = module->default_memory; - uint8 *new_memory_data, *memory_data = memory->memory_data; - uint32 heap_size = memory->heap_data_end - memory->heap_data; - uint32 total_size_old = memory->memory_data_end - memory_data; - uint32 total_page_count = inc_page_count + memory->cur_page_count; - uint64 total_size = memory->num_bytes_per_page * (uint64)total_page_count; - uint8 *heap_data_old = memory->heap_data; + uint8 *new_memory_data, *memory_data, *heap_data_old; + uint32 heap_size, total_size_old, total_page_count; + uint64 total_size; + + if (!memory) + return false; + + memory_data = memory->memory_data; + heap_size = memory->heap_data_end - memory->heap_data; + total_size_old = memory->memory_data_end - memory_data; + total_page_count = inc_page_count + memory->cur_page_count; + total_size = memory->num_bytes_per_page * (uint64)total_page_count; + heap_data_old = memory->heap_data; if (inc_page_count <= 0) /* No need to enlarge memory */ @@ -1911,6 +1964,7 @@ wasm_call_indirect(WASMExecEnv *exec_env, wasm_interp_call_wasm(module_inst, exec_env, function_inst, argc, argv); + (void)clear_wasi_proc_exit_exception(module_inst); return !wasm_get_exception(module_inst) ? true : false; got_exception: @@ -2075,6 +2129,9 @@ wasm_get_module_inst_mem_consumption(const WASMModuleInstance *module_inst, mem_conspn->memories_size += size; mem_conspn->app_heap_size += memory->heap_data_end - memory->heap_data; + /* size of app heap structure */ + mem_conspn->memories_size += + mem_allocator_get_heap_struct_size(); } mem_conspn->tables_size = sizeof(WASMTableInstance *) diff --git a/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c b/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c index c13e8c57a..a31691120 100644 --- a/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c +++ b/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c @@ -265,6 +265,10 @@ call_key_destructor(wasm_exec_env_t exec_env) WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env); ClusterInfoNode *info = get_cluster_info(cluster); + if (!info) { + return; + } + value_node = bh_list_first_elem(info->thread_list); while (value_node) { if (value_node->exec_env == exec_env) @@ -435,6 +439,11 @@ get_thread_info(wasm_exec_env_t exec_env, uint32 handle) { WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env); ClusterInfoNode *info = get_cluster_info(cluster); + + if (!info) { + return NULL; + } + return bh_hash_map_find(info->thread_info_map, (void *)(uintptr_t)handle); } @@ -524,6 +533,8 @@ pthread_create_wrapper(wasm_exec_env_t exec_env, WASIContext *wasi_ctx = get_wasi_ctx(module_inst); #endif + bh_assert(module); + if (!(new_module_inst = wasm_runtime_instantiate_internal(module, true, 8192, 0, NULL, 0))) diff --git a/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c b/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c index 6d4fcc5f9..584ee6009 100644 --- a/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c +++ b/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c @@ -1007,21 +1007,6 @@ __cxa_throw_wrapper(wasm_exec_env_t exec_env, wasm_runtime_set_exception(module_inst, buf); } -static int -setjmp_wrapper(wasm_exec_env_t exec_env, - void *jmp_buf) -{ - os_printf("in setjmp()\n"); - return 0; -} - -static void -longjmp_wrapper(wasm_exec_env_t exec_env, - void *jmp_buf, int val) -{ - os_printf("in longjmp()\n"); -} - #if WASM_ENABLE_SPEC_TEST != 0 static void print_wrapper(wasm_exec_env_t exec_env) @@ -1120,8 +1105,6 @@ static NativeSymbol native_symbols_libc_builtin[] = { REG_NATIVE_FUNC(__cxa_allocate_exception, "(i)i"), REG_NATIVE_FUNC(__cxa_begin_catch, "(*)"), REG_NATIVE_FUNC(__cxa_throw, "(**i)"), - REG_NATIVE_FUNC(setjmp, "(*)i"), - REG_NATIVE_FUNC(longjmp, "(*i)"), }; #if WASM_ENABLE_SPEC_TEST != 0 diff --git a/core/iwasm/libraries/libc-emcc/libc_emcc_wrapper.c b/core/iwasm/libraries/libc-emcc/libc_emcc_wrapper.c index 22a42814f..b7dd4a9f2 100644 --- a/core/iwasm/libraries/libc-emcc/libc_emcc_wrapper.c +++ b/core/iwasm/libraries/libc-emcc/libc_emcc_wrapper.c @@ -267,6 +267,21 @@ getentropy_wrapper(wasm_exec_env_t exec_env, void *buffer, uint32 length) return getentropy(buffer, length); } +static int +setjmp_wrapper(wasm_exec_env_t exec_env, + void *jmp_buf) +{ + os_printf("setjmp() called\n"); + return 0; +} + +static void +longjmp_wrapper(wasm_exec_env_t exec_env, + void *jmp_buf, int val) +{ + os_printf("longjmp() called\n"); +} + #if !defined(BH_PLATFORM_LINUX_SGX) static FILE *file_list[32] = { 0 }; @@ -506,6 +521,8 @@ static NativeSymbol native_symbols_libc_emcc[] = { REG_NATIVE_FUNC(munmap, "(ii)i"), REG_NATIVE_FUNC(__munmap, "(ii)i"), REG_NATIVE_FUNC(getentropy, "(*~)i"), + REG_NATIVE_FUNC(setjmp, "(*)i"), + REG_NATIVE_FUNC(longjmp, "(*i)"), #if !defined(BH_PLATFORM_LINUX_SGX) REG_NATIVE_FUNC(fopen, "($$)i"), REG_NATIVE_FUNC(fread, "(*iii)i"), diff --git a/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c b/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c index 6a968c482..35b917de2 100644 --- a/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c +++ b/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c @@ -1019,9 +1019,13 @@ wasi_poll_oneoff(wasm_exec_env_t exec_env, return 0; } -void wasi_proc_exit(wasm_exec_env_t exec_env, wasi_exitcode_t rval) +static void +wasi_proc_exit(wasm_exec_env_t exec_env, wasi_exitcode_t rval) { wasm_module_inst_t module_inst = get_module_inst(exec_env); + /* Here throwing exception is just to let wasm app exit, + the upper layer should clear the exception and return + as normal */ wasm_runtime_set_exception(module_inst, "wasi proc exit"); } diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c index 90978a175..01e60f90f 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c @@ -1902,9 +1902,9 @@ __wasi_errno_t wasmtime_ssp_path_open( } if (S_ISDIR(sb.st_mode)) - rights_base |= RIGHTS_DIRECTORY_BASE; + rights_base |= (__wasi_rights_t)RIGHTS_DIRECTORY_BASE; else if (S_ISREG(sb.st_mode)) - rights_base |= RIGHTS_REGULAR_FILE_BASE; + rights_base |= (__wasi_rights_t)RIGHTS_REGULAR_FILE_BASE; } return fd_table_insert_fd(curfds, nfd, type, rights_base & max_base, diff --git a/core/iwasm/libraries/thread-mgr/thread_manager.c b/core/iwasm/libraries/thread-mgr/thread_manager.c index dfcd865a7..dfed25be4 100644 --- a/core/iwasm/libraries/thread-mgr/thread_manager.c +++ b/core/iwasm/libraries/thread-mgr/thread_manager.c @@ -288,6 +288,10 @@ wasm_cluster_spawn_exec_env(WASMExecEnv *exec_env) WASMExecEnv *new_exec_env; uint32 aux_stack_start, aux_stack_size; + if (!module) { + return NULL; + } + if (!(new_module_inst = wasm_runtime_instantiate_internal(module, true, 8192, 0, NULL, 0))) { diff --git a/core/shared/platform/zephyr/zephyr_platform.c b/core/shared/platform/zephyr/zephyr_platform.c index 8c701a203..2bb08fc47 100644 --- a/core/shared/platform/zephyr/zephyr_platform.c +++ b/core/shared/platform/zephyr/zephyr_platform.c @@ -87,6 +87,7 @@ os_free(void *ptr) { } +#if 0 struct out_context { int count; }; @@ -100,13 +101,19 @@ char_out(int c, void *ctx) out_ctx->count++; return _stdout_hook_iwasm(c); } +#endif int os_vprintf(const char *fmt, va_list ap) { +#if 0 struct out_context ctx = { 0 }; z_vprintk(char_out, &ctx, fmt, ap); return ctx.count; +#else + vprintk(fmt, ap); + return 0; +#endif } void * diff --git a/core/shared/utils/bh_assert.c b/core/shared/utils/bh_assert.c index b9ac28ed6..cf93b170b 100644 --- a/core/shared/utils/bh_assert.c +++ b/core/shared/utils/bh_assert.c @@ -8,8 +8,6 @@ void bh_assert_internal(int v, const char *file_name, int line_number, const char *expr_string) { - int i; - if (v) return; @@ -22,10 +20,6 @@ void bh_assert_internal(int v, const char *file_name, int line_number, os_printf("\nASSERTION FAILED: %s, at file %s, line %d\n", expr_string, file_name, line_number); - i = os_printf(" "); - - /* divived by 0 to make it abort */ - os_printf("%d\n", i / (i - 1)); - while (1); + abort(); } diff --git a/core/shared/utils/bh_hashmap.c b/core/shared/utils/bh_hashmap.c index 59fca9cdf..f774546a9 100644 --- a/core/shared/utils/bh_hashmap.c +++ b/core/shared/utils/bh_hashmap.c @@ -290,11 +290,11 @@ bh_hash_map_destroy(HashMap *map) uint32 bh_hash_map_get_struct_size(HashMap *hashmap) { - uint32 size = offsetof(HashMap, elements) - + sizeof(HashMapElem *) * hashmap->size; + uint32 size = (uint32)(uintptr_t)offsetof(HashMap, elements) + + (uint32)sizeof(HashMapElem *) * hashmap->size; if (hashmap->lock) { - size += sizeof(korp_mutex); + size += (uint32)sizeof(korp_mutex); } return size; @@ -303,7 +303,7 @@ bh_hash_map_get_struct_size(HashMap *hashmap) uint32 bh_hash_map_get_elem_struct_size() { - return sizeof(HashMapElem); + return (uint32)sizeof(HashMapElem); } bool @@ -335,4 +335,4 @@ bh_hash_map_traverse(HashMap *map, TraverseCallbackFunc callback) } return true; -} \ No newline at end of file +} diff --git a/samples/gui/wasm-runtime-wgl/src/platform/linux/iwasm_main.c b/samples/gui/wasm-runtime-wgl/src/platform/linux/iwasm_main.c index 856a1caea..321cd8f6f 100644 --- a/samples/gui/wasm-runtime-wgl/src/platform/linux/iwasm_main.c +++ b/samples/gui/wasm-runtime-wgl/src/platform/linux/iwasm_main.c @@ -443,7 +443,10 @@ static void hal_init(void) /*Create a display*/ lv_disp_drv_t disp_drv; - lv_disp_drv_init(&disp_drv); /*Basic initialization*/ + + /*Basic initialization*/ + memset(&disp_drv, 0, sizeof(disp_drv)); + lv_disp_drv_init(&disp_drv); disp_drv.buffer = &disp_buf1; disp_drv.flush_cb = monitor_flush; // disp_drv.hor_res = 200; diff --git a/samples/workload/wasm-av1/README.md b/samples/workload/wasm-av1/README.md index 68dad1773..784812413 100644 --- a/samples/workload/wasm-av1/README.md +++ b/samples/workload/wasm-av1/README.md @@ -39,7 +39,7 @@ Firstly please build iwasm with simd support: ``` shell $ cd /product-mini/platforms/linux/ $ mkdir build && cd build -$ cmake .. -DWAMR_BUILD_SIMD=1 +$ cmake .. -DWAMR_BUILD_SIMD=1 -DWAMR_BUILD_LIBC_EMCC=1 $ make ``` diff --git a/samples/workload/wasm-av1/wasm-av1.patch b/samples/workload/wasm-av1/wasm-av1.patch index 1db8f7fb3..98f262562 100644 --- a/samples/workload/wasm-av1/wasm-av1.patch +++ b/samples/workload/wasm-av1/wasm-av1.patch @@ -30,7 +30,7 @@ index c39fff6..4682d43 100644 ) diff --git a/test.c b/test.c -index df2d44b..8e81cdc 100644 +index df2d44b..cb270de 100644 --- a/test.c +++ b/test.c @@ -18,6 +18,9 @@ @@ -58,7 +58,7 @@ index df2d44b..8e81cdc 100644 fclose(f); } -@@ -63,6 +67,7 @@ main(int argc, char *argv[]) { +@@ -63,9 +67,12 @@ main(int argc, char *argv[]) { static int i = 0; ++i; @@ -66,6 +66,11 @@ index df2d44b..8e81cdc 100644 if (30 <= i && i < 40) { dump_raw_frame(af, i); } ++ if (i >= 1000) ++ break; + } + /* + * Run the decoder every time, so that we keep diff --git a/third_party/aom/CMakeLists.txt b/third_party/aom/CMakeLists.txt index 9dbe301..20c7be4 100644 --- a/third_party/aom/CMakeLists.txt diff --git a/wamr-compiler/main.c b/wamr-compiler/main.c index 835fea25a..0fb5710c2 100644 --- a/wamr-compiler/main.c +++ b/wamr-compiler/main.c @@ -159,7 +159,7 @@ main(int argc, char *argv[]) return print_help(); } - if (argc == 0) + if (argc == 0 || !out_file_name) return print_help(); if (sgx_mode) { From 0359805c82189a3fdf8e96fc13b53b3c2d297491 Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Thu, 26 Nov 2020 19:10:05 +0800 Subject: [PATCH 112/207] Import FreeRTOS platform experiment codes for further development (#451) --- core/config.h | 3 +- core/iwasm/common/wasm_native.c | 3 +- .../platform/freertos/freertos_platform.c | 315 +++++++++++++ .../platform/freertos/freertos_thread.c | 426 ++++++++++++++++++ core/shared/platform/freertos/freertos_time.c | 14 + .../platform/freertos/platform_internal.h | 97 ++++ .../platform/freertos/shared_platform.cmake | 16 + .../platforms/freertos/simple/iwasm_main.c | 106 +++++ product-mini/platforms/freertos/simple/main.c | 39 ++ .../platforms/freertos/simple/sources.mk | 54 +++ .../platforms/freertos/simple/test_wasm.h | 46 ++ 11 files changed, 1117 insertions(+), 2 deletions(-) create mode 100644 core/shared/platform/freertos/freertos_platform.c create mode 100644 core/shared/platform/freertos/freertos_thread.c create mode 100644 core/shared/platform/freertos/freertos_time.c create mode 100644 core/shared/platform/freertos/platform_internal.h create mode 100644 core/shared/platform/freertos/shared_platform.cmake create mode 100644 product-mini/platforms/freertos/simple/iwasm_main.c create mode 100644 product-mini/platforms/freertos/simple/main.c create mode 100644 product-mini/platforms/freertos/simple/sources.mk create mode 100644 product-mini/platforms/freertos/simple/test_wasm.h diff --git a/core/config.h b/core/config.h index 7ab1d2fec..234b43e3e 100644 --- a/core/config.h +++ b/core/config.h @@ -225,7 +225,8 @@ #endif /* Default/min/max stack size of each app thread */ -#if !defined(BH_PLATFORM_ZEPHYR) && !defined(BH_PLATFORM_ALIOS_THINGS) +#if !defined(BH_PLATFORM_ZEPHYR) && !defined(BH_PLATFORM_ALIOS_THINGS) \ + && !defined(BH_PLATFORM_FREERTOS) #define APP_THREAD_STACK_SIZE_DEFAULT (32 * 1024) #define APP_THREAD_STACK_SIZE_MIN (24 * 1024) #else diff --git a/core/iwasm/common/wasm_native.c b/core/iwasm/common/wasm_native.c index ad9ebae01..de252c2e5 100644 --- a/core/iwasm/common/wasm_native.c +++ b/core/iwasm/common/wasm_native.c @@ -7,7 +7,8 @@ #include "wasm_runtime_common.h" #include "bh_log.h" -#if !defined(BH_PLATFORM_ZEPHYR) && !defined(BH_PLATFORM_ALIOS_THINGS) +#if !defined(BH_PLATFORM_ZEPHYR) && !defined(BH_PLATFORM_ALIOS_THINGS) \ + && !defined(BH_PLATFORM_FREERTOS) #define ENABLE_QUICKSORT 1 #else #define ENABLE_QUICKSORT 0 diff --git a/core/shared/platform/freertos/freertos_platform.c b/core/shared/platform/freertos/freertos_platform.c new file mode 100644 index 000000000..4a47a4989 --- /dev/null +++ b/core/shared/platform/freertos/freertos_platform.c @@ -0,0 +1,315 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "platform_api_vmcore.h" +#include "platform_api_extension.h" + + +int errno = 0; + +int +os_thread_sys_init(); + +void +os_thread_sys_destroy(); + +int +bh_platform_init() +{ + return os_thread_sys_init(); +} + +void +bh_platform_destroy() +{ + os_thread_sys_destroy(); +} + +void * +os_malloc(unsigned size) +{ + return NULL; +} + +void * +os_realloc(void *ptr, unsigned size) +{ + return NULL; +} + +void +os_free(void *ptr) +{ +} + +int os_printf(const char *format, ...) +{ + /* TODO: implement os_printf */ + return 0; +} + +int +os_vprintf(const char *format, va_list ap) +{ + /* TODO: implement os_vprintf */ + return 1; +} + +void * +os_mmap(void *hint, size_t size, int prot, int flags) +{ + + return BH_MALLOC(size); +} + +void +os_munmap(void *addr, size_t size) +{ + BH_FREE(addr); +} + +int +os_mprotect(void *addr, size_t size, int prot) +{ + return 0; +} + +void +os_dcache_flush() +{ +} + +int atoi(const char *nptr) +{ + bool is_negative = false; + int total = 0; + const char *p = nptr; + char temp = '0'; + + if (NULL == p) { + os_printf("invlaid atoi input\n"); + return 0; + } + + if (*p == '-') { + is_negative = true; + p++; + } + + while ((temp = *p++) != '\0') { + if (temp > '9' || temp < '0') { + continue; + } + + total = total * 10 + (int)(temp - '0'); + } + + if (is_negative) + total = 0 - total; + + return total; +} + +/** + * TODO: implement these APIs which are needed by libc_builtin_wrapper.c + * and wasm_runtime_common.c + */ +int strncasecmp(const char *s1, const char *s2, size_t n) +{ + os_printf("### unimplemented function strncasecmp called!\n"); + return 0; +} + +long int strtol(const char *str, char **endptr, int base) +{ + os_printf("### unimplemented function strtol called!\n"); + return 0; +} + +unsigned long int strtoul(const char *str, char **endptr, int base) +{ + os_printf("### unimplemented function strtoul called!\n"); + return 0; +} + +unsigned long long int strtoull(const char *nptr, char **endptr, int base) +{ + os_printf("### unimplemented function strtoull called!\n"); + return 0; +} + +double strtod(const char *nptr, char **endptr) +{ + os_printf("### unimplemented function strtod called!\n"); + return 0; +} + +float strtof(const char *nptr, char **endptr) +{ + os_printf("### unimplemented function strtof called!\n"); + return 0; +} + +char *strstr(const char *haystack, const char *needle) +{ + os_printf("### unimplemented function strstr called!\n"); + return NULL; +} + +size_t strspn(const char *s, const char *accept) +{ + os_printf("### unimplemented function strspn called!\n"); + return 0; +} + +size_t strcspn(const char *s, const char *reject) +{ + os_printf("### unimplemented function strcspn called!\n"); + return 0; +} + +void *memchr(const void *s, int c, size_t n) +{ + os_printf("### unimplemented function memchr called!\n"); + return NULL; +} + +int isalnum(int c) +{ + os_printf("### unimplemented function isalnum called!\n"); + return 0; +} + +int isxdigit(int c) +{ + os_printf("### unimplemented function isxdigit called!\n"); + return 0; +} + +int isdigit(int c) +{ + os_printf("### unimplemented function isdigit called!\n"); + return 0; +} + +int isprint(int c) +{ + os_printf("### unimplemented function isprint called!\n"); + return 0; +} + +int isgraph(int c) +{ + os_printf("### unimplemented function isgraph called!\n"); + return 0; +} + +int isspace(int c) +{ + os_printf("### unimplemented function isspace called!\n"); + return 0; +} + +int isalpha(int c) +{ + os_printf("### unimplemented function isalpha called!\n"); + return 0; +} + +int isupper(int c) +{ + os_printf("### unimplemented function isupper called!\n"); + return 0; +} + +int toupper(int c) +{ + os_printf("### unimplemented function toupper called!\n"); + return 0; +} + +int tolower(int c) +{ + os_printf("### unimplemented function tolower called!\n"); + return 0; +} + +void *memmove(void *dest, const void *src, size_t n) +{ + char *d = dest; + const char *s = src; + + if (d < s) { + while (n--) + *d++ = *s++; + } + else { + const char *lasts = s + (n-1); + char *lastd = d + (n-1); + while (n--) + *lastd-- = *lasts--; + } + return dest; +} + +static union { + int a; + char b; +} __ue = { .a = 1 }; + +#define is_little_endian() (__ue.b == 1) + +static void swap32(uint8_t* pData) +{ + uint8_t value = *pData; + *pData = *(pData + 3); + *(pData + 3) = value; + + value = *(pData + 1); + *(pData + 1) = *(pData + 2); + *(pData + 2) = value; +} + +static void swap16(uint8_t* pData) +{ + uint8_t value = *pData; + *(pData) = *(pData + 1); + *(pData + 1) = value; +} + +uint32_t htonl(uint32_t value) +{ + uint32_t ret; + if (is_little_endian()) { + ret = value; + swap32((uint8*) &ret); + return ret; + } + + return value; +} + +uint32_t ntohl(uint32_t value) +{ + return htonl(value); +} + +uint16_t htons(uint16_t value) +{ + uint16_t ret; + if (is_little_endian()) { + ret = value; + swap16((uint8_t *)&ret); + return ret; + } + + return value; +} + +uint16_t ntohs(uint16_t value) +{ + return htons(value); +} + diff --git a/core/shared/platform/freertos/freertos_thread.c b/core/shared/platform/freertos/freertos_thread.c new file mode 100644 index 000000000..b0b2d2af6 --- /dev/null +++ b/core/shared/platform/freertos/freertos_thread.c @@ -0,0 +1,426 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "platform_api_vmcore.h" +#include "platform_api_extension.h" + +#define bh_assert(v) do { \ + if (!(v)) { \ + os_printf("\nASSERTION FAILED: %s, at %s, line %d\n",\ + #v, __FILE__, __LINE__); \ + abort(); \ + } \ + } while (0) + +struct os_thread_data; +typedef struct os_thread_wait_node { + /* Binary semaphore */ + SemaphoreHandle_t sem; + os_thread_wait_list next; +} os_thread_wait_node; + +typedef struct os_thread_data { + /* Next thread data */ + struct os_thread_data *next; + /* Thread handle */ + TaskHandle_t handle; + /* Thread start routine */ + thread_start_routine_t start_routine; + /* Thread start routine argument */ + void *arg; + /* Thread local root */ + void *tlr; + /* Wait node of current thread */ + os_thread_wait_node wait_node; + /* Lock for waiting list */ + SemaphoreHandle_t wait_list_lock; + /* Waiting list of other threads who are joining this thread */ + os_thread_wait_list thread_wait_list; +} os_thread_data; + +static bool is_thread_sys_inited = false; + +/* Lock for thread data list */ +static SemaphoreHandle_t thread_data_lock; + +/* Thread data list */ +static os_thread_data *thread_data_list = NULL; +/* Thread data of supervisor thread */ +static os_thread_data supervisor_thread_data; + +/* Thread name index */ +static int thread_name_index; + +static void thread_data_list_add(os_thread_data *thread_data) +{ + xSemaphoreTake(thread_data_lock, portMAX_DELAY); + if (!thread_data_list) + thread_data_list = thread_data; + else { + /* If already in list, just return */ + os_thread_data *p = thread_data_list; + while (p) { + if (p == thread_data) { + xSemaphoreGive(thread_data_lock); + return; + } + p = p->next; + } + + /* Set as head of list */ + thread_data->next = thread_data_list; + thread_data_list = thread_data; + } + xSemaphoreGive(thread_data_lock); +} + +static void thread_data_list_remove(os_thread_data *thread_data) +{ + xSemaphoreTake(thread_data_lock, portMAX_DELAY); + if (thread_data_list) { + if (thread_data_list == thread_data) + thread_data_list = thread_data_list->next; + else { + /* Search and remove it from list */ + os_thread_data *p = thread_data_list; + while (p && p->next != thread_data) + p = p->next; + if (p && p->next == thread_data) + p->next = p->next->next; + } + } + xSemaphoreGive(thread_data_lock); +} + +static os_thread_data * +thread_data_list_lookup(TaskHandle_t handle) +{ + xSemaphoreTake(thread_data_lock, portMAX_DELAY); + if (thread_data_list) { + os_thread_data *p = thread_data_list; + while (p) { + if (p->handle == handle) { + /* Found */ + xSemaphoreGive(thread_data_lock); + return p; + } + p = p->next; + } + } + xSemaphoreGive(thread_data_lock); + return NULL; +} + +int +os_thread_sys_init() +{ + if (is_thread_sys_inited) + return BHT_OK; + + if (!(thread_data_lock = xSemaphoreCreateMutex())) + return BHT_ERROR; + + /* Initialize supervisor thread data */ + memset(&supervisor_thread_data, 0, sizeof(supervisor_thread_data)); + + if (!(supervisor_thread_data.wait_node.sem = xSemaphoreCreateBinary())) { + vSemaphoreDelete(thread_data_lock); + return BHT_ERROR; + } + + supervisor_thread_data.handle = xTaskGetCurrentTaskHandle(); + /* Set as head of thread data list */ + thread_data_list = &supervisor_thread_data; + + is_thread_sys_inited = true; + return BHT_OK; +} + +void +os_thread_sys_destroy() +{ + if (is_thread_sys_inited) { + vSemaphoreDelete(supervisor_thread_data.wait_node.sem); + vSemaphoreDelete(thread_data_lock); + is_thread_sys_inited = false; + } +} + +static os_thread_data * +thread_data_current() +{ + TaskHandle_t handle = xTaskGetCurrentTaskHandle(); + return thread_data_list_lookup(handle); +} + +static void +os_thread_cleanup(void) +{ + os_thread_data *thread_data = thread_data_current(); + os_thread_wait_list thread_wait_list; + SemaphoreHandle_t wait_list_lock; + SemaphoreHandle_t wait_node_sem; + + bh_assert(thread_data != NULL); + wait_list_lock = thread_data->wait_list_lock; + thread_wait_list = thread_data->thread_wait_list; + wait_node_sem = thread_data->wait_node.sem; + + xSemaphoreTake(wait_list_lock, portMAX_DELAY); + if (thread_wait_list) { + /* Signal each joining thread */ + os_thread_wait_list head = thread_wait_list; + while (head) { + os_thread_wait_list next = head->next; + xSemaphoreGive(head->sem); + head = next; + } + } + xSemaphoreGive(wait_list_lock); + + /* Free sem and lock */ + vSemaphoreDelete(wait_node_sem); + vSemaphoreDelete(wait_list_lock); + + thread_data_list_remove(thread_data); + BH_FREE(thread_data); +} + +static void +os_thread_wrapper(void *arg) +{ + os_thread_data *thread_data = arg; + + thread_data->handle = xTaskGetCurrentTaskHandle(); + thread_data_list_add(thread_data); + + thread_data->start_routine(thread_data->arg); + os_thread_cleanup(); + vTaskDelete(NULL); +} + +int os_thread_create(korp_tid *p_tid, thread_start_routine_t start, void *arg, + unsigned int stack_size) +{ + return os_thread_create_with_prio(p_tid, start, arg, stack_size, + BH_THREAD_DEFAULT_PRIORITY); +} + +int os_thread_create_with_prio(korp_tid *p_tid, thread_start_routine_t start, + void *arg, unsigned int stack_size, int prio) +{ + os_thread_data *thread_data; + char thread_name[32]; + + if (!p_tid || !stack_size) + return BHT_ERROR; + + /* Create and initialize thread data */ + if (!(thread_data = BH_MALLOC(sizeof(os_thread_data)))) + return BHT_ERROR; + + memset(thread_data, 0, sizeof(os_thread_data)); + + thread_data->start_routine = start; + thread_data->arg = arg; + + if (!(thread_data->wait_node.sem = xSemaphoreCreateBinary())) + goto fail1; + + if (!(thread_data->wait_list_lock = xSemaphoreCreateMutex())) + goto fail2; + + snprintf(thread_name, sizeof(thread_name), "%s%d", + "wasm-thread-", ++thread_name_index); + + /* Create the thread */ + if (pdPASS != xTaskCreate(os_thread_wrapper, thread_name, + stack_size / 4, thread_data, + prio, &thread_data->handle)) + goto fail3; + + thread_data_list_add(thread_data); + *p_tid = thread_data->handle; + return BHT_OK; + +fail3: + vSemaphoreDelete(thread_data->wait_list_lock); +fail2: + vSemaphoreDelete(thread_data->wait_node.sem); +fail1: + BH_FREE(thread_data); + return BHT_ERROR; +} + +korp_tid os_self_thread() +{ + return xTaskGetCurrentTaskHandle(); +} + +int os_thread_join(korp_tid thread, void **value_ptr) +{ + os_thread_data *thread_data, *curr_thread_data; + TaskHandle_t handle = thread; + + (void)value_ptr; + + /* Get thread data of current thread */ + curr_thread_data = thread_data_current(); + curr_thread_data->wait_node.next = NULL; + + /* Get thread data */ + thread_data = thread_data_list_lookup(handle); + + xSemaphoreTake(thread_data->wait_list_lock, portMAX_DELAY); + if (!thread_data->thread_wait_list) + thread_data->thread_wait_list = &curr_thread_data->wait_node; + else { + /* Add to end of waiting list */ + os_thread_wait_node *p = thread_data->thread_wait_list; + while (p->next) + p = p->next; + p->next = &curr_thread_data->wait_node; + } + xSemaphoreGive(thread_data->wait_list_lock); + + /* Wait the sem */ + xSemaphoreTake(curr_thread_data->wait_node.sem, portMAX_DELAY); + return BHT_OK; +} + +int os_mutex_init(korp_mutex *mutex) +{ + SemaphoreHandle_t semaphore; + if (!(semaphore = xSemaphoreCreateMutex())) + return BHT_ERROR; + mutex->sem = semaphore; + mutex->is_recursive = false; + return BHT_OK; +} + +int os_recursive_mutex_init(korp_mutex *mutex) +{ + SemaphoreHandle_t semaphore; + if (!(semaphore = xSemaphoreCreateRecursiveMutex())) + return BHT_ERROR; + mutex->sem = semaphore; + mutex->is_recursive = true; + return BHT_OK; +} + +int os_mutex_destroy(korp_mutex *mutex) +{ + vSemaphoreDelete(mutex->sem); + return BHT_OK; +} + +int os_mutex_lock(korp_mutex *mutex) +{ + int ret = -1; + + if (!mutex->is_recursive) + ret = xSemaphoreTake(mutex->sem, portMAX_DELAY); + else + ret = xSemaphoreTakeRecursive(mutex->sem, portMAX_DELAY); + return ret == pdPASS ? BHT_OK : BHT_ERROR; +} + +int os_mutex_unlock(korp_mutex *mutex) +{ + int ret = -1; + + if (!mutex->is_recursive) + ret = xSemaphoreGive(mutex->sem); + else + ret = xSemaphoreGiveRecursive(mutex->sem); + return ret == pdPASS ? BHT_OK : BHT_ERROR; +} + +int os_cond_init(korp_cond *cond) +{ + if (!(cond->wait_list_lock = xSemaphoreCreateMutex())) + return BHT_ERROR; + + cond->thread_wait_list = NULL; + return BHT_OK; +} + +int os_cond_destroy(korp_cond *cond) +{ + vSemaphoreDelete(cond->wait_list_lock); + return BHT_OK; +} + +static int +os_cond_wait_internal(korp_cond *cond, korp_mutex *mutex, + bool timed, int mills) +{ + os_thread_wait_node *node = &thread_data_current()->wait_node; + + node->next = NULL; + + xSemaphoreTake(cond->wait_list_lock, portMAX_DELAY); + if (!cond->thread_wait_list) + cond->thread_wait_list = node; + else { + /* Add to end of wait list */ + os_thread_wait_node *p = cond->thread_wait_list; + while (p->next) + p = p->next; + p->next = node; + } + xSemaphoreGive(cond->wait_list_lock); + + /* Unlock mutex, wait sem and lock mutex again */ + os_mutex_unlock(mutex); + xSemaphoreTake(node->sem, timed ? mills / portTICK_RATE_MS : portMAX_DELAY); + os_mutex_lock(mutex); + + /* Remove wait node from wait list */ + xSemaphoreTake(cond->wait_list_lock, portMAX_DELAY); + if (cond->thread_wait_list == node) + cond->thread_wait_list = node->next; + else { + /* Remove from the wait list */ + os_thread_wait_node *p = cond->thread_wait_list; + while (p->next != node) + p = p->next; + p->next = node->next; + } + xSemaphoreGive(cond->wait_list_lock); + + return BHT_OK; +} + +int os_cond_wait(korp_cond *cond, korp_mutex *mutex) +{ + return os_cond_wait_internal(cond, mutex, false, 0); +} + +int os_cond_reltimedwait(korp_cond *cond, korp_mutex *mutex, int useconds) +{ + if (useconds == BHT_WAIT_FOREVER) + return os_cond_wait_internal(cond, mutex, false, 0); + else + return os_cond_wait_internal(cond, mutex, true, useconds / 1000); +} + +int os_cond_signal(korp_cond *cond) +{ + /* Signal the head wait node of wait list */ + xSemaphoreTake(cond->wait_list_lock, portMAX_DELAY); + if (cond->thread_wait_list) + xSemaphoreGive(cond->thread_wait_list->sem); + xSemaphoreGive(cond->wait_list_lock); + + return BHT_OK; +} + +uint8 *os_thread_get_stack_boundary() +{ + /* TODO: implement os_thread_get_stack_boundary */ + return NULL; +} + diff --git a/core/shared/platform/freertos/freertos_time.c b/core/shared/platform/freertos/freertos_time.c new file mode 100644 index 000000000..72b1b5842 --- /dev/null +++ b/core/shared/platform/freertos/freertos_time.c @@ -0,0 +1,14 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "platform_api_vmcore.h" + +uint64 +os_time_get_boot_microsecond() +{ + TickType_t ticks = xTaskGetTickCount(); + return (uint64)1000 * 1000 / configTICK_RATE_HZ * ticks; +} + diff --git a/core/shared/platform/freertos/platform_internal.h b/core/shared/platform/freertos/platform_internal.h new file mode 100644 index 000000000..baa9e069f --- /dev/null +++ b/core/shared/platform/freertos/platform_internal.h @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _PLATFORM_INTERNAL_H +#define _PLATFORM_INTERNAL_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#ifndef BH_PLATFORM_FREERTOS +#define BH_PLATFORM_FREERTOS +#endif + +#define BH_APPLET_PRESERVED_STACK_SIZE (2 * BH_KB) + +/* Default thread priority */ +#define BH_THREAD_DEFAULT_PRIORITY 5 + +extern int errno; + +typedef TaskHandle_t korp_thread; +typedef korp_thread korp_tid; +typedef struct { + bool is_recursive; + SemaphoreHandle_t sem; +} korp_mutex; + +struct os_thread_wait_node; +typedef struct os_thread_wait_node *os_thread_wait_list; +typedef struct korp_cond { + SemaphoreHandle_t wait_list_lock; + os_thread_wait_list thread_wait_list; +} korp_cond; + +int os_printf(const char *format, ...); +int os_vprintf(const char *format, va_list ap); + +/* math functions which are not provided by os */ +double sqrt(double x); +double floor(double x); +double ceil(double x); +double fmin(double x, double y); +double fmax(double x, double y); +double rint(double x); +double fabs(double x); +double trunc(double x); +float floorf(float x); +float ceilf(float x); +float fminf(float x, float y); +float fmaxf(float x, float y); +float rintf(float x); +float truncf(float x); +int signbit(double x); +int isnan(double x); + +int atoi(const char *s); +int strncasecmp(const char *s1, const char *s2, size_t n); +long int strtol(const char *str, char **endptr, int base); +unsigned long int strtoul(const char *str, char **endptr, int base); +unsigned long long int strtoull(const char *nptr, char **endptr, int base); +double strtod(const char *nptr, char **endptr); +float strtof(const char *nptr, char **endptr); +char *strstr(const char *haystack, const char *needle); +size_t strspn(const char *s, const char *accept); +size_t strcspn(const char *s, const char *reject); +void *memchr(const void *s, int c, size_t n); +int isalnum(int c); +int isxdigit(int c); +int isdigit(int c); +int isprint(int c); +int isgraph(int c); +int isspace(int c); +int isalpha(int c); +int isupper(int c); +int toupper(int c); +int tolower(int c); +void *memmove(void *dest, const void *src, size_t n); + +uint32_t htonl(uint32_t hostlong); +uint16_t htons(uint16_t hostshort); +uint32_t ntohl(uint32_t netlong); +uint16_t ntohs(uint16_t netshort); + +#endif diff --git a/core/shared/platform/freertos/shared_platform.cmake b/core/shared/platform/freertos/shared_platform.cmake new file mode 100644 index 000000000..1938acfd9 --- /dev/null +++ b/core/shared/platform/freertos/shared_platform.cmake @@ -0,0 +1,16 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +set (PLATFORM_SHARED_DIR ${CMAKE_CURRENT_LIST_DIR}) + +add_definitions(-DBH_PLATFORM_FREERTOS) + +include_directories(${PLATFORM_SHARED_DIR}) +include_directories(${PLATFORM_SHARED_DIR}/../include) + +include (${CMAKE_CURRENT_LIST_DIR}/../common/math/platform_api_math.cmake) + +file (GLOB_RECURSE source_all ${PLATFORM_SHARED_DIR}/*.c) + +set (PLATFORM_SHARED_SOURCE ${source_all} ${PLATFORM_COMMON_MATH_SOURCE}) + diff --git a/product-mini/platforms/freertos/simple/iwasm_main.c b/product-mini/platforms/freertos/simple/iwasm_main.c new file mode 100644 index 000000000..fd0d0a9a7 --- /dev/null +++ b/product-mini/platforms/freertos/simple/iwasm_main.c @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "bh_platform.h" +#include "wasm_export.h" +#include "test_wasm.h" + +#define CONFIG_GLOBAL_HEAP_BUF_SIZE 131072 +#define CONFIG_APP_STACK_SIZE 8192 +#define CONFIG_APP_HEAP_SIZE 8192 + +static int app_argc; +static char **app_argv; + +static void* +app_instance_main(wasm_module_inst_t module_inst) +{ + const char *exception; + + wasm_application_execute_main(module_inst, app_argc, app_argv); + if ((exception = wasm_runtime_get_exception(module_inst))) + os_printf("%s\n", exception); + return NULL; +} + +static char global_heap_buf[CONFIG_GLOBAL_HEAP_BUF_SIZE] = { 0 }; + +void iwasm_main(void) +{ + uint8 *wasm_file_buf = NULL; + uint32 wasm_file_size; + wasm_module_t wasm_module = NULL; + wasm_module_inst_t wasm_module_inst = NULL; + RuntimeInitArgs init_args; + char error_buf[128]; +#if WASM_ENABLE_LOG != 0 + int log_verbose_level = 2; +#endif + + os_printf("### iwasm main begin\n"); + + memset(&init_args, 0, sizeof(RuntimeInitArgs)); + + init_args.mem_alloc_type = Alloc_With_Pool; + init_args.mem_alloc_option.pool.heap_buf = global_heap_buf; + init_args.mem_alloc_option.pool.heap_size = sizeof(global_heap_buf); + + /* initialize runtime environment */ + if (!wasm_runtime_full_init(&init_args)) { + os_printf("Init runtime environment failed.\n"); + return; + } + + os_printf("### wasm runtime initialized.\n"); + +#if WASM_ENABLE_LOG != 0 + bh_log_set_verbose_level(log_verbose_level); +#endif + + /* load WASM byte buffer from byte buffer of include file */ + wasm_file_buf = (uint8*)wasm_test_file; + wasm_file_size = sizeof(wasm_test_file); + + /* load WASM module */ + if (!(wasm_module = wasm_runtime_load(wasm_file_buf, wasm_file_size, + error_buf, sizeof(error_buf)))) { + os_printf("%s\n", error_buf); + goto fail1; + } + + os_printf("### wasm runtime load module success.\n"); + + /* instantiate the module */ + if (!(wasm_module_inst = wasm_runtime_instantiate(wasm_module, + CONFIG_APP_STACK_SIZE, + CONFIG_APP_HEAP_SIZE, + error_buf, + sizeof(error_buf)))) { + os_printf("%s\n", error_buf); + goto fail2; + } + + os_printf("### wasm runtime instantiate module success.\n"); + + /* invoke the main function */ + app_instance_main(wasm_module_inst); + + os_printf("### wasm runtime execute app's main function success.\n"); + + /* destroy the module instance */ + wasm_runtime_deinstantiate(wasm_module_inst); + + os_printf("### wasm runtime deinstantiate module success.\n"); + +fail2: + /* unload the module */ + wasm_runtime_unload(wasm_module); + + os_printf("### wasm runtime unload module success.\n"); +fail1: + /* destroy runtime environment */ + wasm_runtime_destroy(); + os_printf("### wasm runtime destroy success.\n"); +} diff --git a/product-mini/platforms/freertos/simple/main.c b/product-mini/platforms/freertos/simple/main.c new file mode 100644 index 000000000..520754818 --- /dev/null +++ b/product-mini/platforms/freertos/simple/main.c @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "bh_platform.h" + +extern void +iwasm_main(void); + +static void +wamr_task(void *param) +{ + os_printf("WAMR task started\n"); + + iwasm_main(); + + while (1) { + task_sleep(1000); + /*os_printf("Hello WAMR\n");*/ + } + (void)param; +} + +static bool +app_init(uint32_t id) +{ + os_printf("WAMR init, id: %d\n", id); + task_start("wamr_task", 8192, 4, wamr_task, NULL); + return true; +} + +static void +app_exit(uint32_t id) +{ + os_printf("WAMR exit, id: %d\n", id); +} + +INTERNAL_APP_DEFINE("WAMR", APP_VERSION(0, 0, 0, 1), 0, app_init, app_exit); diff --git a/product-mini/platforms/freertos/simple/sources.mk b/product-mini/platforms/freertos/simple/sources.mk new file mode 100644 index 000000000..466769ee4 --- /dev/null +++ b/product-mini/platforms/freertos/simple/sources.mk @@ -0,0 +1,54 @@ +# TODO: set WAMR root dir +WAMR_ROOT := ../../../../ + +override PROJECT_CFLAGS := $(PROJECT_CFLAGS) -Wno-unused-parameter -Wno-pedantic + +override PROJECT_CFLAGS := $(PROJECT_CFLAGS) -I$(PROJECTS_SRC_ROOT)/include + +override PROJECT_CFLAGS := $(PROJECT_CFLAGS) \ + -I$(WAMR_INC_ROOT)/core \ + -I$(WAMR_INC_ROOT)/core/iwasm/include \ + -I$(WAMR_INC_ROOT)/core/iwasm/common \ + -I$(WAMR_INC_ROOT)/core/shared/utils \ + -I$(WAMR_INC_ROOT)/core/shared/mem-alloc \ + -I$(WAMR_INC_ROOT)/core/shared/platform/include \ + -I$(WAMR_INC_ROOT)/core/shared/platform/freertos \ + -I$(WAMR_INC_ROOT)/core/iwasm/interpreter + +override PROJECT_CFLAGS := $(PROJECT_CFLAGS) \ + -DBH_PLATFORM_FREERTOS \ + -DBH_MALLOC=wasm_runtime_malloc \ + -DBH_FREE=wasm_runtime_free \ + -DBUILD_TARGET_X86_32 \ + -DWASM_ENABLE_INTERP=1 \ + -DWASM_ENABLE_FAST_INTERP=0 \ + -DWASM_ENABLE_LIBC_BUILTIN=1 + +override PROJECT_CSRC := $(PROJECT_CSRC) \ + $(WAMR_SRC_ROOT)/core/shared/platform/freertos/freertos_platform.c \ + $(WAMR_SRC_ROOT)/core/shared/platform/freertos/freertos_thread.c \ + $(WAMR_SRC_ROOT)/core/shared/platform/freertos/freertos_time.c \ + $(WAMR_SRC_ROOT)/core/shared/platform/common/math/math.c \ + $(WAMR_SRC_ROOT)/core/shared/mem-alloc/mem_alloc.c \ + $(WAMR_SRC_ROOT)/core/shared/mem-alloc/ems/ems_kfc.c \ + $(WAMR_SRC_ROOT)/core/shared/mem-alloc/ems/ems_hmu.c \ + $(WAMR_SRC_ROOT)/core/shared/mem-alloc/ems/ems_alloc.c \ + $(WAMR_SRC_ROOT)/core/shared/utils/bh_assert.c \ + $(WAMR_SRC_ROOT)/core/shared/utils/bh_common.c \ + $(WAMR_SRC_ROOT)/core/shared/utils/bh_hashmap.c \ + $(WAMR_SRC_ROOT)/core/shared/utils/bh_list.c \ + $(WAMR_SRC_ROOT)/core/shared/utils/bh_log.c \ + $(WAMR_SRC_ROOT)/core/shared/utils/bh_vector.c \ + $(WAMR_SRC_ROOT)/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c \ + $(WAMR_SRC_ROOT)/core/iwasm/common/wasm_runtime_common.c \ + $(WAMR_SRC_ROOT)/core/iwasm/common/wasm_exec_env.c \ + $(WAMR_SRC_ROOT)/core/iwasm/common/wasm_native.c \ + $(WAMR_SRC_ROOT)/core/iwasm/common/wasm_memory.c \ + $(WAMR_SRC_ROOT)/core/iwasm/common/wasm_shared_memory.c \ + $(WAMR_SRC_ROOT)/core/iwasm/common/wasm_c_api.c \ + $(WAMR_SRC_ROOT)/core/iwasm/common/arch/invokeNative_ia32.s \ + $(WAMR_SRC_ROOT)/core/iwasm/interpreter/wasm_interp_classic.c \ + $(WAMR_SRC_ROOT)/core/iwasm/interpreter/wasm_loader.c \ + $(WAMR_SRC_ROOT)/core/iwasm/interpreter/wasm_runtime.c \ + $(WAMR_SRC_ROOT)/product-mini/platforms/freertos/simple/iwasm_main.c \ + $(WAMR_SRC_ROOT)/product-mini/platforms/freertos/simple/main.c diff --git a/product-mini/platforms/freertos/simple/test_wasm.h b/product-mini/platforms/freertos/simple/test_wasm.h new file mode 100644 index 000000000..a729cadef --- /dev/null +++ b/product-mini/platforms/freertos/simple/test_wasm.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +/** + * The byte array buffer is the file content of a test wasm binary file, + * which is compiled by wasi-sdk toolchain from C source file of: + * product-mini/app-samples/hello-world/main.c. + */ +unsigned char __aligned(4) wasm_test_file[] = { + 0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x10, 0x03, 0x60, + 0x01, 0x7F, 0x01, 0x7F, 0x60, 0x02, 0x7F, 0x7F, 0x01, 0x7F, 0x60, 0x01, + 0x7F, 0x00, 0x02, 0x31, 0x04, 0x03, 0x65, 0x6E, 0x76, 0x04, 0x70, 0x75, + 0x74, 0x73, 0x00, 0x00, 0x03, 0x65, 0x6E, 0x76, 0x06, 0x6D, 0x61, 0x6C, + 0x6C, 0x6F, 0x63, 0x00, 0x00, 0x03, 0x65, 0x6E, 0x76, 0x06, 0x70, 0x72, + 0x69, 0x6E, 0x74, 0x66, 0x00, 0x01, 0x03, 0x65, 0x6E, 0x76, 0x04, 0x66, + 0x72, 0x65, 0x65, 0x00, 0x02, 0x03, 0x02, 0x01, 0x01, 0x04, 0x05, 0x01, + 0x70, 0x01, 0x01, 0x01, 0x05, 0x03, 0x01, 0x00, 0x01, 0x06, 0x13, 0x03, + 0x7F, 0x01, 0x41, 0xC0, 0x28, 0x0B, 0x7F, 0x00, 0x41, 0xBA, 0x08, 0x0B, + 0x7F, 0x00, 0x41, 0xC0, 0x28, 0x0B, 0x07, 0x2C, 0x04, 0x06, 0x6D, 0x65, + 0x6D, 0x6F, 0x72, 0x79, 0x02, 0x00, 0x0A, 0x5F, 0x5F, 0x64, 0x61, 0x74, + 0x61, 0x5F, 0x65, 0x6E, 0x64, 0x03, 0x01, 0x0B, 0x5F, 0x5F, 0x68, 0x65, + 0x61, 0x70, 0x5F, 0x62, 0x61, 0x73, 0x65, 0x03, 0x02, 0x04, 0x6D, 0x61, + 0x69, 0x6E, 0x00, 0x04, 0x0A, 0xB2, 0x01, 0x01, 0xAF, 0x01, 0x01, 0x03, + 0x7F, 0x23, 0x80, 0x80, 0x80, 0x80, 0x00, 0x41, 0x20, 0x6B, 0x22, 0x02, + 0x24, 0x80, 0x80, 0x80, 0x80, 0x00, 0x41, 0x9B, 0x88, 0x80, 0x80, 0x00, + 0x10, 0x80, 0x80, 0x80, 0x80, 0x00, 0x1A, 0x02, 0x40, 0x02, 0x40, 0x41, + 0x80, 0x08, 0x10, 0x81, 0x80, 0x80, 0x80, 0x00, 0x22, 0x03, 0x0D, 0x00, + 0x41, 0xA8, 0x88, 0x80, 0x80, 0x00, 0x10, 0x80, 0x80, 0x80, 0x80, 0x00, + 0x1A, 0x41, 0x7F, 0x21, 0x04, 0x0C, 0x01, 0x0B, 0x20, 0x02, 0x20, 0x03, + 0x36, 0x02, 0x10, 0x41, 0x80, 0x88, 0x80, 0x80, 0x00, 0x20, 0x02, 0x41, + 0x10, 0x6A, 0x10, 0x82, 0x80, 0x80, 0x80, 0x00, 0x1A, 0x41, 0x00, 0x21, + 0x04, 0x20, 0x03, 0x41, 0x04, 0x6A, 0x41, 0x00, 0x2F, 0x00, 0x91, 0x88, + 0x80, 0x80, 0x00, 0x3B, 0x00, 0x00, 0x20, 0x03, 0x41, 0x00, 0x28, 0x00, + 0x8D, 0x88, 0x80, 0x80, 0x00, 0x36, 0x00, 0x00, 0x20, 0x02, 0x20, 0x03, + 0x36, 0x02, 0x00, 0x41, 0x93, 0x88, 0x80, 0x80, 0x00, 0x20, 0x02, 0x10, + 0x82, 0x80, 0x80, 0x80, 0x00, 0x1A, 0x20, 0x03, 0x10, 0x83, 0x80, 0x80, + 0x80, 0x00, 0x0B, 0x20, 0x02, 0x41, 0x20, 0x6A, 0x24, 0x80, 0x80, 0x80, + 0x80, 0x00, 0x20, 0x04, 0x0B, 0x0B, 0x41, 0x01, 0x00, 0x41, 0x80, 0x08, + 0x0B, 0x3A, 0x62, 0x75, 0x66, 0x20, 0x70, 0x74, 0x72, 0x3A, 0x20, 0x25, + 0x70, 0x0A, 0x00, 0x31, 0x32, 0x33, 0x34, 0x0A, 0x00, 0x62, 0x75, 0x66, + 0x3A, 0x20, 0x25, 0x73, 0x00, 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, + 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x00, 0x6D, 0x61, 0x6C, 0x6C, 0x6F, 0x63, + 0x20, 0x62, 0x75, 0x66, 0x20, 0x66, 0x61, 0x69, 0x6C, 0x65, 0x64, 0x00 +}; From 7d8b79a7a783ced568ebeb45622387d2bea0dbef Mon Sep 17 00:00:00 2001 From: Karl Fessel Date: Fri, 27 Nov 2020 02:10:00 +0100 Subject: [PATCH 113/207] Addapt to RIOT changes (#452) RIOT removed kernel_types.h in favor of sched.h --- core/shared/platform/riot/platform_internal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/shared/platform/riot/platform_internal.h b/core/shared/platform/riot/platform_internal.h index 0f79c6f7b..91d08cfe7 100644 --- a/core/shared/platform/riot/platform_internal.h +++ b/core/shared/platform/riot/platform_internal.h @@ -8,7 +8,7 @@ #define _PLATFORM_INTERNAL_H //Riot includes core -#include +#include #include #include From 282831eba5ac1b19c6d535a4c60a15d935e13e60 Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Mon, 30 Nov 2020 16:03:51 +0800 Subject: [PATCH 114/207] Fix some compilation warnings and add esp-idf platform for experiment (#454) And fix some code indent issues. --- .../app-native-shared/attr_container.c | 19 +- .../app-framework/base/native/timer_wrapper.c | 2 +- core/app-mgr/app-manager/app_manager.c | 3 +- core/app-mgr/app-manager/app_manager_host.c | 5 +- core/app-mgr/app-manager/message.c | 4 +- .../app-mgr-shared/app_manager_export.h | 4 +- core/config.h | 6 +- core/iwasm/aot/aot_loader.c | 4 + core/iwasm/aot/aot_reloc.h | 8 +- core/iwasm/aot/aot_runtime.c | 12 + core/iwasm/aot/aot_runtime.h | 6 + core/iwasm/common/wasm_memory.c | 2 + core/iwasm/common/wasm_native.c | 2 +- core/iwasm/include/aot_export.h | 2 +- core/iwasm/interpreter/wasm_loader.c | 3 + .../libc-builtin/libc_builtin_wrapper.c | 26 ++ core/shared/coap/er-coap/coap-constants.h | 2 +- .../common/freertos/freertos_malloc.c | 25 ++ .../{ => common}/freertos/freertos_thread.c | 17 +- .../{ => common}/freertos/freertos_time.c | 0 .../freertos/platform_api_freertos.cmake | 8 + core/shared/platform/common/math/math.c | 4 + .../shared/platform/esp-idf/espidf_platform.c | 122 +++++++ core/shared/platform/esp-idf/espidf_thread.c | 14 + .../{freertos => esp-idf}/platform_internal.h | 4 +- .../shared_platform.cmake | 7 +- .../platform/freertos/freertos_platform.c | 315 ------------------ core/shared/platform/windows/win_thread.c | 1 - core/shared/utils/bh_log.c | 2 +- product-mini/platforms/esp-idf/CMakeLists.txt | 55 +++ .../{freertos/simple => esp-idf}/iwasm_main.c | 0 .../{freertos/simple => esp-idf}/main.c | 0 .../{freertos/simple => esp-idf}/sources.mk | 19 +- .../{freertos/simple => esp-idf}/test_wasm.h | 0 product-mini/platforms/nuttx/wamr.mk | 2 - 35 files changed, 342 insertions(+), 363 deletions(-) create mode 100644 core/shared/platform/common/freertos/freertos_malloc.c rename core/shared/platform/{ => common}/freertos/freertos_thread.c (96%) rename core/shared/platform/{ => common}/freertos/freertos_time.c (100%) create mode 100644 core/shared/platform/common/freertos/platform_api_freertos.cmake create mode 100644 core/shared/platform/esp-idf/espidf_platform.c create mode 100644 core/shared/platform/esp-idf/espidf_thread.c rename core/shared/platform/{freertos => esp-idf}/platform_internal.h (97%) rename core/shared/platform/{freertos => esp-idf}/shared_platform.cmake (58%) delete mode 100644 core/shared/platform/freertos/freertos_platform.c create mode 100644 product-mini/platforms/esp-idf/CMakeLists.txt rename product-mini/platforms/{freertos/simple => esp-idf}/iwasm_main.c (100%) rename product-mini/platforms/{freertos/simple => esp-idf}/main.c (100%) rename product-mini/platforms/{freertos/simple => esp-idf}/sources.mk (85%) rename product-mini/platforms/{freertos/simple => esp-idf}/test_wasm.h (100%) diff --git a/core/app-framework/app-native-shared/attr_container.c b/core/app-framework/app-native-shared/attr_container.c index 2cd816c6d..b27dacdf7 100644 --- a/core/app-framework/app-native-shared/attr_container.c +++ b/core/app-framework/app-native-shared/attr_container.c @@ -106,13 +106,13 @@ attr_container_get_attr_begin(const attr_container_t *attr_cont, /* tag content */ p += str_len; - if (p - attr_cont->buf >= total_length) + if ((uint32_t)(p - attr_cont->buf) >= total_length) return NULL; /* attribute num */ attr_num = get_uint16(p); p += sizeof(uint16_t); - if (p - attr_cont->buf >= total_length) + if ((uint32_t)(p - attr_cont->buf) >= total_length) return NULL; if (p_total_length) @@ -174,7 +174,8 @@ attr_container_find_attr(const attr_container_t *attr_cont, const char *key) if (str_len == strlen(key) + 1 && memcmp(p + sizeof(uint16_t), key, str_len) == 0) { - if (p + sizeof(uint16_t) + str_len - attr_cont->buf >= total_length) + if ((uint32_t)(p + sizeof(uint16_t) + str_len + - attr_cont->buf) >= total_length) return NULL; return p; } @@ -337,7 +338,7 @@ bool attr_container_set_attr(attr_container_t **p_attr_cont, const char *key, } /* Set the attr buf */ - str_len = strlen(key) + 1; + str_len = (uint16_t)(strlen(key) + 1); set_uint16(p, str_len); p += sizeof(uint16_t); bh_memcpy_s(p, str_len, key, str_len); @@ -366,7 +367,7 @@ bool attr_container_set_attr(attr_container_t **p_attr_cont, const char *key, return true; } - if (p1 - p + msg_end - attr_end >= attr_len) { + if ((uint32_t)(p1 - p + msg_end - attr_end) >= attr_len) { memmove(p, p1, attr_end - p1); bh_memcpy_s(p + (attr_end - p1), attr_len, attr_buf, attr_len); attr_container_free(attr_buf); @@ -399,7 +400,7 @@ bool attr_container_set_attr(attr_container_t **p_attr_cont, const char *key, return true; } else { /* key not found */ - if (msg_end - attr_end >= attr_len) { + if ((uint32_t)(msg_end - attr_end) >= attr_len) { bh_memcpy_s(attr_end, msg_end - attr_end, attr_buf, attr_len); attr_container_inc_attr_num(attr_cont); attr_container_free(attr_buf); @@ -564,6 +565,9 @@ attr_container_get_attr(const attr_container_t *attr_cont, const char *key) bh_memcpy_s(&val.var_name, sizeof(val.var_name), addr, len); \ break; \ } \ + default: \ + bh_assert(0); \ + break; \ } \ return val.var_name; \ } while (0) @@ -819,6 +823,9 @@ void attr_container_dump(const attr_container_t *attr_cont) get_uint32(p)); p += sizeof(uint32_t) + get_uint32(p); break; + default: + bh_assert(0); + break; } } diff --git a/core/app-framework/base/native/timer_wrapper.c b/core/app-framework/base/native/timer_wrapper.c index fd3ef4bbc..1f565aaa0 100644 --- a/core/app-framework/base/native/timer_wrapper.c +++ b/core/app-framework/base/native/timer_wrapper.c @@ -5,7 +5,7 @@ #include "bh_platform.h" #include "app_manager_export.h" -#include "module_wasm_app.h" +#include "../app-manager/module_wasm_app.h" #include "timer_native_api.h" static bool timer_thread_run = true; diff --git a/core/app-mgr/app-manager/app_manager.c b/core/app-mgr/app-manager/app_manager.c index d68861823..6418fecbc 100644 --- a/core/app-mgr/app-manager/app_manager.c +++ b/core/app-mgr/app-manager/app_manager.c @@ -396,4 +396,5 @@ module_interface *g_module_interfaces[Module_Max] = { #else NULL #endif - }; +}; + diff --git a/core/app-mgr/app-manager/app_manager_host.c b/core/app-mgr/app-manager/app_manager_host.c index a6b13baac..f134eed6f 100644 --- a/core/app-mgr/app-manager/app_manager_host.c +++ b/core/app-mgr/app-manager/app_manager_host.c @@ -209,13 +209,14 @@ int aee_host_msg_callback(void *msg, uint16_t msg_len) memset(&request, 0, sizeof(request)); if (!unpack_request(recv_ctx.message.payload, - recv_ctx.message.payload_size, &request)) + recv_ctx.message.payload_size, &request)) continue; request.sender = ID_HOST; am_dispatch_request(&request); - } else { + } + else { app_manager_printf("unexpected host msg type: %d\n", msg_type); } diff --git a/core/app-mgr/app-manager/message.c b/core/app-mgr/app-manager/message.c index 2aed14757..e9c594ec2 100644 --- a/core/app-mgr/app-manager/message.c +++ b/core/app-mgr/app-manager/message.c @@ -73,8 +73,8 @@ bool send_error_response_to_host(int mid, int status, const char *msg) } } - set_response(response, status, - FMT_ATTR_CONTAINER, (const char *)payload, payload_len); + set_response(response, status, FMT_ATTR_CONTAINER, + (const char *)payload, payload_len); response->mid = mid; send_response_to_host(response); diff --git a/core/app-mgr/app-mgr-shared/app_manager_export.h b/core/app-mgr/app-mgr-shared/app_manager_export.h index aa676d2a4..4d8ced8d5 100644 --- a/core/app-mgr/app-mgr-shared/app_manager_export.h +++ b/core/app-mgr/app-mgr-shared/app_manager_export.h @@ -173,11 +173,11 @@ typedef struct host_interface { * @return true if success, false otherwise */ bool -app_manager_host_init(host_interface *interface); +app_manager_host_init(host_interface *intf); /* Startup app manager */ void -app_manager_startup(host_interface *interface); +app_manager_startup(host_interface *intf); /* Get queue of current applet */ void * diff --git a/core/config.h b/core/config.h index 234b43e3e..0e9c87ae7 100644 --- a/core/config.h +++ b/core/config.h @@ -226,7 +226,7 @@ /* Default/min/max stack size of each app thread */ #if !defined(BH_PLATFORM_ZEPHYR) && !defined(BH_PLATFORM_ALIOS_THINGS) \ - && !defined(BH_PLATFORM_FREERTOS) + && !defined(BH_PLATFORM_ESP_IDF) && !defined(BH_PLATFORM_OPENRTOS) #define APP_THREAD_STACK_SIZE_DEFAULT (32 * 1024) #define APP_THREAD_STACK_SIZE_MIN (24 * 1024) #else @@ -259,5 +259,9 @@ #define WASM_ENABLE_TAIL_CALL 0 #endif +#ifndef WASM_ENABLE_CUSTOM_NAME_SECTION +#define WASM_ENABLE_CUSTOM_NAME_SECTION 0 +#endif + #endif /* end of _CONFIG_H_ */ diff --git a/core/iwasm/aot/aot_loader.c b/core/iwasm/aot/aot_loader.c index 478570764..5bf2453dc 100644 --- a/core/iwasm/aot/aot_loader.c +++ b/core/iwasm/aot/aot_loader.c @@ -1663,6 +1663,10 @@ load_from_sections(AOTModule *module, AOTSection *sections, error_buf, error_buf_size)) return false; break; + default: + set_error_buf(error_buf, error_buf_size, + "invalid aot section type"); + return false; } section = section->next; diff --git a/core/iwasm/aot/aot_reloc.h b/core/iwasm/aot/aot_reloc.h index 9df623e92..cbf2f9cd5 100644 --- a/core/iwasm/aot/aot_reloc.h +++ b/core/iwasm/aot/aot_reloc.h @@ -36,8 +36,8 @@ typedef struct { REG_SYM(aot_call_indirect), \ REG_SYM(wasm_runtime_enlarge_memory), \ REG_SYM(wasm_runtime_set_exception), \ - REG_SYM(memset), \ - REG_SYM(memmove), \ + REG_SYM(aot_memset), \ + REG_SYM(aot_memmove), \ REG_BULK_MEMORY_SYM() \ REG_ATOMIC_WAIT_SYM() #else /* else of (defined(_WIN32) || defined(_WIN32_)) && defined(NDEBUG) */ @@ -47,8 +47,8 @@ typedef struct { REG_SYM(aot_call_indirect), \ REG_SYM(wasm_runtime_enlarge_memory), \ REG_SYM(wasm_runtime_set_exception), \ - REG_SYM(memset), \ - REG_SYM(memmove), \ + REG_SYM(aot_memset), \ + REG_SYM(aot_memmove), \ REG_SYM(fmin), \ REG_SYM(fminf), \ REG_SYM(fmax), \ diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index db047dc4a..d6db2d511 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -1907,6 +1907,18 @@ aot_call_indirect(WASMExecEnv *exec_env, } } +void * +aot_memmove(void *dest, const void *src, size_t n) +{ + return memmove(dest, src, n); +} + +void * +aot_memset(void *s, int c, size_t n) +{ + return memset(s, c, n); +} + #if WASM_ENABLE_BULK_MEMORY != 0 bool aot_memory_init(AOTModuleInstance *module_inst, uint32 seg_index, diff --git a/core/iwasm/aot/aot_runtime.h b/core/iwasm/aot/aot_runtime.h index 93a0cf5d8..2fa721587 100644 --- a/core/iwasm/aot/aot_runtime.h +++ b/core/iwasm/aot/aot_runtime.h @@ -527,6 +527,12 @@ aot_call_indirect(WASMExecEnv *exec_env, uint32 aot_get_plt_table_size(); +void * +aot_memmove(void *dest, const void *src, size_t n); + +void * +aot_memset(void *s, int c, size_t n); + #if WASM_ENABLE_BULK_MEMORY != 0 bool aot_memory_init(AOTModuleInstance *module_inst, uint32 seg_index, diff --git a/core/iwasm/common/wasm_memory.c b/core/iwasm/common/wasm_memory.c index 151de2828..0b94beeb4 100644 --- a/core/iwasm/common/wasm_memory.c +++ b/core/iwasm/common/wasm_memory.c @@ -7,6 +7,8 @@ #include "bh_platform.h" #include "mem_alloc.h" +#define BH_ENABLE_MEMORY_PROFILING 0 + #if BH_ENABLE_MEMORY_PROFILING != 0 /* Memory profile data of a function */ diff --git a/core/iwasm/common/wasm_native.c b/core/iwasm/common/wasm_native.c index de252c2e5..c4313a6e6 100644 --- a/core/iwasm/common/wasm_native.c +++ b/core/iwasm/common/wasm_native.c @@ -8,7 +8,7 @@ #include "bh_log.h" #if !defined(BH_PLATFORM_ZEPHYR) && !defined(BH_PLATFORM_ALIOS_THINGS) \ - && !defined(BH_PLATFORM_FREERTOS) + && !defined(BH_PLATFORM_OPENRTOS) && !defined(BH_PLATFORM_ESP_IDF) #define ENABLE_QUICKSORT 1 #else #define ENABLE_QUICKSORT 0 diff --git a/core/iwasm/include/aot_export.h b/core/iwasm/include/aot_export.h index f2d339622..78d2edc19 100644 --- a/core/iwasm/include/aot_export.h +++ b/core/iwasm/include/aot_export.h @@ -6,7 +6,7 @@ #ifndef _AOT_EXPORT_H #define _AOT_EXPORT_H -#include +#include #include diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index a92bb3195..f4b71805f 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -6393,6 +6393,9 @@ handle_op_block_and_loop: } #endif break; + default: + bh_assert(0); + break; } ref_type = *(loader_ctx->frame_ref - 1); diff --git a/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c b/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c index 584ee6009..b1a20b1d2 100644 --- a/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c +++ b/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c @@ -399,6 +399,31 @@ sprintf_out(int c, struct str_context *ctx) return c; } +#ifdef BH_PLATFORM_OPENRTOS +PRIVILEGED_DATA static char print_buf[128] = { 0 }; +PRIVILEGED_DATA static int print_buf_size = 0; + +static int +printf_out(int c, struct str_context *ctx) +{ + if (c == '\n') { + print_buf[print_buf_size] = '\0'; + os_printf("%s\n", print_buf); + print_buf_size = 0; + } + else if (print_buf_size >= sizeof(print_buf) - 2) { + print_buf[print_buf_size++] = (char)c; + print_buf[print_buf_size] = '\0'; + os_printf("%s\n", print_buf); + print_buf_size = 0; + } + else { + print_buf[print_buf_size++] = (char)c; + } + ctx->count++; + return c; +} +#else static int printf_out(int c, struct str_context *ctx) { @@ -406,6 +431,7 @@ printf_out(int c, struct str_context *ctx) ctx->count++; return c; } +#endif static int printf_wrapper(wasm_exec_env_t exec_env, diff --git a/core/shared/coap/er-coap/coap-constants.h b/core/shared/coap/er-coap/coap-constants.h index f73a5b950..d2898f89d 100644 --- a/core/shared/coap/er-coap/coap-constants.h +++ b/core/shared/coap/er-coap/coap-constants.h @@ -84,7 +84,7 @@ typedef enum { /* CoAP response codes */ typedef enum { - NO_ERROR = 0, + COAP_NO_ERROR = 0, CREATED_2_01 = 65, /* CREATED */ DELETED_2_02 = 66, /* DELETED */ diff --git a/core/shared/platform/common/freertos/freertos_malloc.c b/core/shared/platform/common/freertos/freertos_malloc.c new file mode 100644 index 000000000..70002163c --- /dev/null +++ b/core/shared/platform/common/freertos/freertos_malloc.c @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "platform_api_vmcore.h" + + +void * +os_malloc(unsigned size) +{ + return NULL; +} + +void * +os_realloc(void *ptr, unsigned size) +{ + return NULL; +} + +void +os_free(void *ptr) +{ +} + diff --git a/core/shared/platform/freertos/freertos_thread.c b/core/shared/platform/common/freertos/freertos_thread.c similarity index 96% rename from core/shared/platform/freertos/freertos_thread.c rename to core/shared/platform/common/freertos/freertos_thread.c index b0b2d2af6..78643419a 100644 --- a/core/shared/platform/freertos/freertos_thread.c +++ b/core/shared/platform/common/freertos/freertos_thread.c @@ -8,9 +8,12 @@ #define bh_assert(v) do { \ if (!(v)) { \ + int _count = 1; \ os_printf("\nASSERTION FAILED: %s, at %s, line %d\n",\ - #v, __FILE__, __LINE__); \ - abort(); \ + #v, __FILE__, __LINE__); \ + /* divived by 0 to make it abort */ \ + os_printf("%d\n", _count / (_count - 1)); \ + while (1); \ } \ } while (0) @@ -293,7 +296,8 @@ int os_thread_join(korp_tid thread, void **value_ptr) int os_mutex_init(korp_mutex *mutex) { SemaphoreHandle_t semaphore; - if (!(semaphore = xSemaphoreCreateMutex())) + + if (!(semaphore = xSemaphoreCreateMutex())) return BHT_ERROR; mutex->sem = semaphore; mutex->is_recursive = false; @@ -303,6 +307,7 @@ int os_mutex_init(korp_mutex *mutex) int os_recursive_mutex_init(korp_mutex *mutex) { SemaphoreHandle_t semaphore; + if (!(semaphore = xSemaphoreCreateRecursiveMutex())) return BHT_ERROR; mutex->sem = semaphore; @@ -418,9 +423,3 @@ int os_cond_signal(korp_cond *cond) return BHT_OK; } -uint8 *os_thread_get_stack_boundary() -{ - /* TODO: implement os_thread_get_stack_boundary */ - return NULL; -} - diff --git a/core/shared/platform/freertos/freertos_time.c b/core/shared/platform/common/freertos/freertos_time.c similarity index 100% rename from core/shared/platform/freertos/freertos_time.c rename to core/shared/platform/common/freertos/freertos_time.c diff --git a/core/shared/platform/common/freertos/platform_api_freertos.cmake b/core/shared/platform/common/freertos/platform_api_freertos.cmake new file mode 100644 index 000000000..ebfc19d78 --- /dev/null +++ b/core/shared/platform/common/freertos/platform_api_freertos.cmake @@ -0,0 +1,8 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +set (PLATFORM_COMMON_FREERTOS_DIR ${CMAKE_CURRENT_LIST_DIR}) + +file (GLOB_RECURSE source_all ${PLATFORM_COMMON_FREERTOS_DIR}/*.c) + +set (PLATFORM_COMMON_FREERTOS_SOURCE ${source_all} ) diff --git a/core/shared/platform/common/math/math.c b/core/shared/platform/common/math/math.c index 1c1137bad..4f6a7ce7c 100644 --- a/core/shared/platform/common/math/math.c +++ b/core/shared/platform/common/math/math.c @@ -32,6 +32,10 @@ #define __FDLIBM_STDC__ +#ifndef FLT_EVAL_METHOD +#define FLT_EVAL_METHOD 0 +#endif + typedef uint32_t u_int32_t; typedef uint64_t u_int64_t; diff --git a/core/shared/platform/esp-idf/espidf_platform.c b/core/shared/platform/esp-idf/espidf_platform.c new file mode 100644 index 000000000..7660ada43 --- /dev/null +++ b/core/shared/platform/esp-idf/espidf_platform.c @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "platform_api_vmcore.h" +#include "platform_api_extension.h" + + +int errno = 0; + +int +os_thread_sys_init(); + +void +os_thread_sys_destroy(); + +int +bh_platform_init() +{ + return os_thread_sys_init(); +} + +void +bh_platform_destroy() +{ + os_thread_sys_destroy(); +} + +int os_printf(const char *format, ...) +{ + int ret = 0; + va_list ap; + + va_start(ap, format); + ret += vprintf(format, ap); + va_end(ap); + + return ret; +} + +int +os_vprintf(const char *format, va_list ap) +{ + return vprintf(format, ap); +} + +void * +os_mmap(void *hint, size_t size, int prot, int flags) +{ + + return BH_MALLOC(size); +} + +void +os_munmap(void *addr, size_t size) +{ + BH_FREE(addr); +} + +int +os_mprotect(void *addr, size_t size, int prot) +{ + return 0; +} + +void +os_dcache_flush() +{ +} + +int +atoi(const char *nptr) +{ + bool is_negative = false; + int total = 0; + const char *p = nptr; + char temp = '0'; + + if (NULL == p) { + os_printf("invlaid atoi input\n"); + return 0; + } + + if (*p == '-') { + is_negative = true; + p++; + } + + while ((temp = *p++) != '\0') { + if (temp > '9' || temp < '0') { + continue; + } + + total = total * 10 + (int)(temp - '0'); + } + + if (is_negative) + total = 0 - total; + + return total; +} + +void * +memmove(void *dest, const void *src, size_t n) +{ + char *d = dest; + const char *s = src; + + if (d < s) { + while (n--) + *d++ = *s++; + } + else { + const char *lasts = s + (n-1); + char *lastd = d + (n-1); + while (n--) + *lastd-- = *lasts--; + } + return dest; +} + diff --git a/core/shared/platform/esp-idf/espidf_thread.c b/core/shared/platform/esp-idf/espidf_thread.c new file mode 100644 index 000000000..d5228dc2b --- /dev/null +++ b/core/shared/platform/esp-idf/espidf_thread.c @@ -0,0 +1,14 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "platform_api_vmcore.h" +#include "platform_api_extension.h" + +uint8 *os_thread_get_stack_boundary() +{ + /* TODO: implement os_thread_get_stack_boundary */ + return NULL; +} + diff --git a/core/shared/platform/freertos/platform_internal.h b/core/shared/platform/esp-idf/platform_internal.h similarity index 97% rename from core/shared/platform/freertos/platform_internal.h rename to core/shared/platform/esp-idf/platform_internal.h index baa9e069f..5703fa789 100644 --- a/core/shared/platform/freertos/platform_internal.h +++ b/core/shared/platform/esp-idf/platform_internal.h @@ -20,8 +20,8 @@ #include #include -#ifndef BH_PLATFORM_FREERTOS -#define BH_PLATFORM_FREERTOS +#ifndef BH_PLATFORM_ESP_IDF +#define BH_PLATFORM_ESP_IDF #endif #define BH_APPLET_PRESERVED_STACK_SIZE (2 * BH_KB) diff --git a/core/shared/platform/freertos/shared_platform.cmake b/core/shared/platform/esp-idf/shared_platform.cmake similarity index 58% rename from core/shared/platform/freertos/shared_platform.cmake rename to core/shared/platform/esp-idf/shared_platform.cmake index 1938acfd9..656fcfaed 100644 --- a/core/shared/platform/freertos/shared_platform.cmake +++ b/core/shared/platform/esp-idf/shared_platform.cmake @@ -3,14 +3,17 @@ set (PLATFORM_SHARED_DIR ${CMAKE_CURRENT_LIST_DIR}) -add_definitions(-DBH_PLATFORM_FREERTOS) +add_definitions(-DBH_PLATFORM_ESP_IDF) include_directories(${PLATFORM_SHARED_DIR}) include_directories(${PLATFORM_SHARED_DIR}/../include) +include (${CMAKE_CURRENT_LIST_DIR}/../common/freertos/platform_api_freertos.cmake) include (${CMAKE_CURRENT_LIST_DIR}/../common/math/platform_api_math.cmake) file (GLOB_RECURSE source_all ${PLATFORM_SHARED_DIR}/*.c) -set (PLATFORM_SHARED_SOURCE ${source_all} ${PLATFORM_COMMON_MATH_SOURCE}) +set (PLATFORM_SHARED_SOURCE ${source_all} + ${PLATFORM_COMMON_MATH_SOURCE} + ${PLATFORM_COMMON_FREERTOS_SOURCE}) diff --git a/core/shared/platform/freertos/freertos_platform.c b/core/shared/platform/freertos/freertos_platform.c deleted file mode 100644 index 4a47a4989..000000000 --- a/core/shared/platform/freertos/freertos_platform.c +++ /dev/null @@ -1,315 +0,0 @@ -/* - * Copyright (C) 2019 Intel Corporation. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - */ - -#include "platform_api_vmcore.h" -#include "platform_api_extension.h" - - -int errno = 0; - -int -os_thread_sys_init(); - -void -os_thread_sys_destroy(); - -int -bh_platform_init() -{ - return os_thread_sys_init(); -} - -void -bh_platform_destroy() -{ - os_thread_sys_destroy(); -} - -void * -os_malloc(unsigned size) -{ - return NULL; -} - -void * -os_realloc(void *ptr, unsigned size) -{ - return NULL; -} - -void -os_free(void *ptr) -{ -} - -int os_printf(const char *format, ...) -{ - /* TODO: implement os_printf */ - return 0; -} - -int -os_vprintf(const char *format, va_list ap) -{ - /* TODO: implement os_vprintf */ - return 1; -} - -void * -os_mmap(void *hint, size_t size, int prot, int flags) -{ - - return BH_MALLOC(size); -} - -void -os_munmap(void *addr, size_t size) -{ - BH_FREE(addr); -} - -int -os_mprotect(void *addr, size_t size, int prot) -{ - return 0; -} - -void -os_dcache_flush() -{ -} - -int atoi(const char *nptr) -{ - bool is_negative = false; - int total = 0; - const char *p = nptr; - char temp = '0'; - - if (NULL == p) { - os_printf("invlaid atoi input\n"); - return 0; - } - - if (*p == '-') { - is_negative = true; - p++; - } - - while ((temp = *p++) != '\0') { - if (temp > '9' || temp < '0') { - continue; - } - - total = total * 10 + (int)(temp - '0'); - } - - if (is_negative) - total = 0 - total; - - return total; -} - -/** - * TODO: implement these APIs which are needed by libc_builtin_wrapper.c - * and wasm_runtime_common.c - */ -int strncasecmp(const char *s1, const char *s2, size_t n) -{ - os_printf("### unimplemented function strncasecmp called!\n"); - return 0; -} - -long int strtol(const char *str, char **endptr, int base) -{ - os_printf("### unimplemented function strtol called!\n"); - return 0; -} - -unsigned long int strtoul(const char *str, char **endptr, int base) -{ - os_printf("### unimplemented function strtoul called!\n"); - return 0; -} - -unsigned long long int strtoull(const char *nptr, char **endptr, int base) -{ - os_printf("### unimplemented function strtoull called!\n"); - return 0; -} - -double strtod(const char *nptr, char **endptr) -{ - os_printf("### unimplemented function strtod called!\n"); - return 0; -} - -float strtof(const char *nptr, char **endptr) -{ - os_printf("### unimplemented function strtof called!\n"); - return 0; -} - -char *strstr(const char *haystack, const char *needle) -{ - os_printf("### unimplemented function strstr called!\n"); - return NULL; -} - -size_t strspn(const char *s, const char *accept) -{ - os_printf("### unimplemented function strspn called!\n"); - return 0; -} - -size_t strcspn(const char *s, const char *reject) -{ - os_printf("### unimplemented function strcspn called!\n"); - return 0; -} - -void *memchr(const void *s, int c, size_t n) -{ - os_printf("### unimplemented function memchr called!\n"); - return NULL; -} - -int isalnum(int c) -{ - os_printf("### unimplemented function isalnum called!\n"); - return 0; -} - -int isxdigit(int c) -{ - os_printf("### unimplemented function isxdigit called!\n"); - return 0; -} - -int isdigit(int c) -{ - os_printf("### unimplemented function isdigit called!\n"); - return 0; -} - -int isprint(int c) -{ - os_printf("### unimplemented function isprint called!\n"); - return 0; -} - -int isgraph(int c) -{ - os_printf("### unimplemented function isgraph called!\n"); - return 0; -} - -int isspace(int c) -{ - os_printf("### unimplemented function isspace called!\n"); - return 0; -} - -int isalpha(int c) -{ - os_printf("### unimplemented function isalpha called!\n"); - return 0; -} - -int isupper(int c) -{ - os_printf("### unimplemented function isupper called!\n"); - return 0; -} - -int toupper(int c) -{ - os_printf("### unimplemented function toupper called!\n"); - return 0; -} - -int tolower(int c) -{ - os_printf("### unimplemented function tolower called!\n"); - return 0; -} - -void *memmove(void *dest, const void *src, size_t n) -{ - char *d = dest; - const char *s = src; - - if (d < s) { - while (n--) - *d++ = *s++; - } - else { - const char *lasts = s + (n-1); - char *lastd = d + (n-1); - while (n--) - *lastd-- = *lasts--; - } - return dest; -} - -static union { - int a; - char b; -} __ue = { .a = 1 }; - -#define is_little_endian() (__ue.b == 1) - -static void swap32(uint8_t* pData) -{ - uint8_t value = *pData; - *pData = *(pData + 3); - *(pData + 3) = value; - - value = *(pData + 1); - *(pData + 1) = *(pData + 2); - *(pData + 2) = value; -} - -static void swap16(uint8_t* pData) -{ - uint8_t value = *pData; - *(pData) = *(pData + 1); - *(pData + 1) = value; -} - -uint32_t htonl(uint32_t value) -{ - uint32_t ret; - if (is_little_endian()) { - ret = value; - swap32((uint8*) &ret); - return ret; - } - - return value; -} - -uint32_t ntohl(uint32_t value) -{ - return htonl(value); -} - -uint16_t htons(uint16_t value) -{ - uint16_t ret; - if (is_little_endian()) { - ret = value; - swap16((uint8_t *)&ret); - return ret; - } - - return value; -} - -uint16_t ntohs(uint16_t value) -{ - return htons(value); -} - diff --git a/core/shared/platform/windows/win_thread.c b/core/shared/platform/windows/win_thread.c index f356dcc32..a2f4a4d45 100644 --- a/core/shared/platform/windows/win_thread.c +++ b/core/shared/platform/windows/win_thread.c @@ -147,7 +147,6 @@ int os_thread_detach(korp_tid thread) void os_thread_exit(void *retval) { - return BHT_OK; } uint8 *os_thread_get_stack_boundary() diff --git a/core/shared/utils/bh_log.c b/core/shared/utils/bh_log.c index e1a3eb22c..a3b392e87 100644 --- a/core/shared/utils/bh_log.c +++ b/core/shared/utils/bh_log.c @@ -26,7 +26,7 @@ bh_log(LogLevel log_level, const char *file, int line, const char *fmt, ...) uint64 usec; uint32 t, h, m, s, mills; - if (log_level > log_verbose_level) + if ((uint32)log_level > log_verbose_level) return; self = os_self_thread(); diff --git a/product-mini/platforms/esp-idf/CMakeLists.txt b/product-mini/platforms/esp-idf/CMakeLists.txt new file mode 100644 index 000000000..f0896d5b3 --- /dev/null +++ b/product-mini/platforms/esp-idf/CMakeLists.txt @@ -0,0 +1,55 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +# from ESP-IDF 4.0 examples/build_system/cmake/idf_as_lib +cmake_minimum_required(VERSION 3.5) + +project(wamr_esp_idf C) + +enable_language (ASM) + +# Include for ESP-IDF build system functions +include($ENV{IDF_PATH}/tools/cmake/idf.cmake) + +# Create idf::esp32 and idf::freertos static libraries +idf_build_process(esp32 + # try and trim the build; additional components + # will be included as needed based on dependency tree + # + # although esptool_py does not generate static library, + # processing the component is needed for flashing related + # targets and file generation + COMPONENTS esp32 freertos esptool_py + SDKCONFIG ${CMAKE_BINARY_DIR}/sdkconfig + BUILD_DIR ${CMAKE_BINARY_DIR}) + +include_directories(build/config + xtensa/include + $ENV{IDF_PATH}/components/esp32/include + $ENV{IDF_PATH}/components/esp_common/include + $ENV{IDF_PATH}/components/esp_rom/include + $ENV{IDF_PATH}/components/freertos/include + $ENV{IDF_PATH}/components/heap/include + $ENV{IDF_PATH}/components/soc/esp32/include + $ENV{IDF_PATH}/components/xtensa/include + $ENV{IDF_PATH}/components/xtensa/esp32/include) + +set(WAMR_BUILD_PLATFORM "esp-idf") +set(WAMR_BUILD_TARGET "XTENSA") +set(WAMR_BUILD_INTERP 1) +set(WAMR_BUILD_FAST_INTERP 1) +set(WAMR_BUILD_AOT 1) +set(WAMR_BUILD_LIBC_BUILTIN 1) +set(WAMR_BUILD_LIBC_WASI 0) + +set(WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../..) + +include(${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) +add_library(vmlib ${WAMR_RUNTIME_LIB_SOURCE}) + +set(elf_file ${CMAKE_PROJECT_NAME}.elf) +add_executable(${elf_file} main.c iwasm_main.c) + +# Link the static libraries to the executable +target_link_libraries(${elf_file} idf::esp32 idf::freertos idf::spi_flash vmlib) + diff --git a/product-mini/platforms/freertos/simple/iwasm_main.c b/product-mini/platforms/esp-idf/iwasm_main.c similarity index 100% rename from product-mini/platforms/freertos/simple/iwasm_main.c rename to product-mini/platforms/esp-idf/iwasm_main.c diff --git a/product-mini/platforms/freertos/simple/main.c b/product-mini/platforms/esp-idf/main.c similarity index 100% rename from product-mini/platforms/freertos/simple/main.c rename to product-mini/platforms/esp-idf/main.c diff --git a/product-mini/platforms/freertos/simple/sources.mk b/product-mini/platforms/esp-idf/sources.mk similarity index 85% rename from product-mini/platforms/freertos/simple/sources.mk rename to product-mini/platforms/esp-idf/sources.mk index 466769ee4..c9e5ce0f8 100644 --- a/product-mini/platforms/freertos/simple/sources.mk +++ b/product-mini/platforms/esp-idf/sources.mk @@ -1,5 +1,5 @@ # TODO: set WAMR root dir -WAMR_ROOT := ../../../../ +WAMR_ROOT := ../../.. override PROJECT_CFLAGS := $(PROJECT_CFLAGS) -Wno-unused-parameter -Wno-pedantic @@ -12,11 +12,11 @@ override PROJECT_CFLAGS := $(PROJECT_CFLAGS) \ -I$(WAMR_INC_ROOT)/core/shared/utils \ -I$(WAMR_INC_ROOT)/core/shared/mem-alloc \ -I$(WAMR_INC_ROOT)/core/shared/platform/include \ - -I$(WAMR_INC_ROOT)/core/shared/platform/freertos \ + -I$(WAMR_INC_ROOT)/core/shared/platform/esp-idf \ -I$(WAMR_INC_ROOT)/core/iwasm/interpreter override PROJECT_CFLAGS := $(PROJECT_CFLAGS) \ - -DBH_PLATFORM_FREERTOS \ + -DBH_PLATFORM_ESP_IDF \ -DBH_MALLOC=wasm_runtime_malloc \ -DBH_FREE=wasm_runtime_free \ -DBUILD_TARGET_X86_32 \ @@ -25,10 +25,11 @@ override PROJECT_CFLAGS := $(PROJECT_CFLAGS) \ -DWASM_ENABLE_LIBC_BUILTIN=1 override PROJECT_CSRC := $(PROJECT_CSRC) \ - $(WAMR_SRC_ROOT)/core/shared/platform/freertos/freertos_platform.c \ - $(WAMR_SRC_ROOT)/core/shared/platform/freertos/freertos_thread.c \ - $(WAMR_SRC_ROOT)/core/shared/platform/freertos/freertos_time.c \ - $(WAMR_SRC_ROOT)/core/shared/platform/common/math/math.c \ + $(WAMR_SRC_ROOT)/core/shared/platform/esp-idf/espidf_platform.c \ + $(WAMR_SRC_ROOT)/core/shared/platform/esp-idf/espidf_thread.c \ + $(WAMR_SRC_ROOT)/core/shared/platform/common/freertos/freertos_malloc.c \ + $(WAMR_SRC_ROOT)/core/shared/platform/common/freertos/freertos_thread.c \ + $(WAMR_SRC_ROOT)/core/shared/platform/common/freertos/freertos_time.c \ $(WAMR_SRC_ROOT)/core/shared/mem-alloc/mem_alloc.c \ $(WAMR_SRC_ROOT)/core/shared/mem-alloc/ems/ems_kfc.c \ $(WAMR_SRC_ROOT)/core/shared/mem-alloc/ems/ems_hmu.c \ @@ -50,5 +51,5 @@ override PROJECT_CSRC := $(PROJECT_CSRC) \ $(WAMR_SRC_ROOT)/core/iwasm/interpreter/wasm_interp_classic.c \ $(WAMR_SRC_ROOT)/core/iwasm/interpreter/wasm_loader.c \ $(WAMR_SRC_ROOT)/core/iwasm/interpreter/wasm_runtime.c \ - $(WAMR_SRC_ROOT)/product-mini/platforms/freertos/simple/iwasm_main.c \ - $(WAMR_SRC_ROOT)/product-mini/platforms/freertos/simple/main.c + $(WAMR_SRC_ROOT)/product-mini/platforms/esp-idf/iwasm_main.c \ + $(WAMR_SRC_ROOT)/product-mini/platforms/esp-idf/main.c diff --git a/product-mini/platforms/freertos/simple/test_wasm.h b/product-mini/platforms/esp-idf/test_wasm.h similarity index 100% rename from product-mini/platforms/freertos/simple/test_wasm.h rename to product-mini/platforms/esp-idf/test_wasm.h diff --git a/product-mini/platforms/nuttx/wamr.mk b/product-mini/platforms/nuttx/wamr.mk index f76bf0cc2..2efdbd703 100644 --- a/product-mini/platforms/nuttx/wamr.mk +++ b/product-mini/platforms/nuttx/wamr.mk @@ -134,8 +134,6 @@ else CFLAGS += -DWASM_ENABLE_GLOBAL_HEAP_POOL=0 endif -CFLAGS += -DBH_ENABLE_MEMORY_PROFILING=0 - CFLAGS += -Wno-strict-prototypes -Wno-shadow -Wno-unused-variable CFLAGS += -Wno-int-conversion -Wno-implicit-function-declaration From 0700dc9cd47817684dd9a5e90a150f9397864f4d Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Mon, 30 Nov 2020 17:00:53 +0800 Subject: [PATCH 115/207] Fix wasi ctx memory free issue when app heap is corrupted (#455) --- core/iwasm/common/wasm_runtime_common.c | 161 +++++++----------- core/iwasm/common/wasm_runtime_common.h | 18 +- .../libraries/libc-wasi/libc_wasi_wrapper.c | 36 ++-- .../sandboxed-system-primitives/src/posix.c | 78 ++------- .../sandboxed-system-primitives/src/posix.h | 22 +-- 5 files changed, 112 insertions(+), 203 deletions(-) diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index b5b700b4b..d132c742b 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -1654,26 +1654,20 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, char *error_buf, uint32 error_buf_size) { WASIContext *wasi_ctx; - size_t *argv_offsets = NULL; char *argv_buf = NULL; - size_t *env_offsets = NULL; + char **argv_list = NULL; char *env_buf = NULL; - uint64 argv_buf_len = 0, env_buf_len = 0; + char **env_list = NULL; + uint64 argv_buf_size = 0, env_buf_size = 0, total_size; uint32 argv_buf_offset = 0, env_buf_offset = 0; - struct fd_table *curfds; - struct fd_prestats *prestats; - struct argv_environ_values *argv_environ; + struct fd_table *curfds = NULL; + struct fd_prestats *prestats = NULL; + struct argv_environ_values *argv_environ = NULL; bool fd_table_inited = false, fd_prestats_inited = false; bool argv_environ_inited = false; - uint32 offset_argv_offsets = 0, offset_env_offsets = 0; - uint32 offset_argv_buf = 0, offset_env_buf = 0; - uint32 offset_curfds = 0; - uint32 offset_prestats = 0; - uint32 offset_argv_environ = 0; __wasi_fd_t wasm_fd = 3; int32 raw_fd; char *path, resolved_path[PATH_MAX]; - uint64 total_size; uint32 i; if (!(wasi_ctx = runtime_malloc(sizeof(WASIContext), NULL, @@ -1697,60 +1691,49 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, /* process argv[0], trip the path and suffix, only keep the program name */ for (i = 0; i < argc; i++) - argv_buf_len += strlen(argv[i]) + 1; + argv_buf_size += strlen(argv[i]) + 1; - total_size = sizeof(size_t) * (uint64)argc; + total_size = sizeof(char *) * (uint64)argc; if (total_size >= UINT32_MAX - || !(offset_argv_offsets = wasm_runtime_module_malloc - (module_inst, (uint32)total_size, - (void**)&argv_offsets)) - || argv_buf_len >= UINT32_MAX - || !(offset_argv_buf = wasm_runtime_module_malloc - (module_inst, (uint32)argv_buf_len, - (void**)&argv_buf))) { + || !(argv_list = wasm_runtime_malloc((uint32)total_size)) + || argv_buf_size >= UINT32_MAX + || !(argv_buf = wasm_runtime_malloc((uint32)argv_buf_size))) { set_error_buf(error_buf, error_buf_size, "Init wasi environment failed: allocate memory failed"); goto fail; } for (i = 0; i < argc; i++) { - argv_offsets[i] = argv_buf_offset; + argv_list[i] = argv_buf + argv_buf_offset; bh_strcpy_s(argv_buf + argv_buf_offset, - (uint32)argv_buf_len - argv_buf_offset, argv[i]); + (uint32)argv_buf_size - argv_buf_offset, argv[i]); argv_buf_offset += (uint32)(strlen(argv[i]) + 1); } for (i = 0; i < env_count; i++) - env_buf_len += strlen(env[i]) + 1; + env_buf_size += strlen(env[i]) + 1; - total_size = sizeof(size_t) * (uint64)argc; + total_size = sizeof(char *) * (uint64)argc; if (total_size >= UINT32_MAX - || !(offset_env_offsets = wasm_runtime_module_malloc - (module_inst, (uint32)total_size, - (void**)&env_offsets)) - || env_buf_len >= UINT32_MAX - || !(offset_env_buf = wasm_runtime_module_malloc - (module_inst, (uint32)env_buf_len, - (void**)&env_buf))) { + || !(env_list = wasm_runtime_malloc((uint32)total_size)) + || env_buf_size >= UINT32_MAX + || !(env_buf = wasm_runtime_malloc((uint32)env_buf_size))) { set_error_buf(error_buf, error_buf_size, "Init wasi environment failed: allocate memory failed"); goto fail; } for (i = 0; i < env_count; i++) { - env_offsets[i] = env_buf_offset; + env_list[i] = env_buf + env_buf_offset; bh_strcpy_s(env_buf + env_buf_offset, - (uint32)env_buf_len - env_buf_offset, env[i]); + (uint32)env_buf_size - env_buf_offset, env[i]); env_buf_offset += (uint32)(strlen(env[i]) + 1); } - if (!(offset_curfds = wasm_runtime_module_malloc - (module_inst, sizeof(struct fd_table), (void**)&curfds)) - || !(offset_prestats = wasm_runtime_module_malloc - (module_inst, sizeof(struct fd_prestats), (void**)&prestats)) - || !(offset_argv_environ = wasm_runtime_module_malloc - (module_inst, sizeof(struct argv_environ_values), - (void**)&argv_environ))) { + if (!(curfds = wasm_runtime_malloc(sizeof(struct fd_table))) + || !(prestats = wasm_runtime_malloc(sizeof(struct fd_prestats))) + || !(argv_environ = + wasm_runtime_malloc(sizeof(struct argv_environ_values)))) { set_error_buf(error_buf, error_buf_size, "Init wasi environment failed: allocate memory failed"); goto fail; @@ -1773,10 +1756,10 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, fd_prestats_inited = true; if (!argv_environ_init(argv_environ, - argv_offsets, argc, - argv_buf, argv_buf_len, - env_offsets, env_count, - env_buf, env_buf_len)) { + argv_buf, argv_buf_size, + argv_list, argc, + env_buf, env_buf_size, + env_list, env_count)) { set_error_buf(error_buf, error_buf_size, "Init wasi environment failed: " "init argument environment failed"); @@ -1817,13 +1800,13 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, fd_prestats_insert(prestats, dir_list[i], wasm_fd); } - wasi_ctx->curfds_offset = offset_curfds; - wasi_ctx->prestats_offset = offset_prestats; - wasi_ctx->argv_environ_offset = offset_argv_environ; - wasi_ctx->argv_buf_offset = offset_argv_buf; - wasi_ctx->argv_offsets_offset = offset_argv_offsets; - wasi_ctx->env_buf_offset = offset_env_buf; - wasi_ctx->env_offsets_offset = offset_env_offsets; + wasi_ctx->curfds = curfds; + wasi_ctx->prestats = prestats; + wasi_ctx->argv_environ = argv_environ; + wasi_ctx->argv_buf = argv_buf; + wasi_ctx->argv_list = argv_list; + wasi_ctx->env_buf = env_buf; + wasi_ctx->env_list = env_list; return true; @@ -1834,20 +1817,20 @@ fail: fd_prestats_destroy(prestats); if (fd_table_inited) fd_table_destroy(curfds); - if (offset_curfds != 0) - wasm_runtime_module_free(module_inst, offset_curfds); - if (offset_prestats != 0) - wasm_runtime_module_free(module_inst, offset_prestats); - if (offset_argv_environ != 0) - wasm_runtime_module_free(module_inst, offset_argv_environ); - if (offset_argv_buf) - wasm_runtime_module_free(module_inst, offset_argv_buf); - if (offset_argv_offsets) - wasm_runtime_module_free(module_inst, offset_argv_offsets); - if (offset_env_buf) - wasm_runtime_module_free(module_inst, offset_env_buf); - if (offset_env_offsets) - wasm_runtime_module_free(module_inst, offset_env_offsets); + if (curfds) + wasm_runtime_free(curfds); + if (prestats) + wasm_runtime_free(prestats); + if (argv_environ) + wasm_runtime_free(argv_environ); + if (argv_buf) + wasm_runtime_free(argv_buf); + if (argv_list) + wasm_runtime_free(argv_list); + if (env_buf) + wasm_runtime_free(env_buf); + if (env_list) + wasm_runtime_free(env_list); return false; } @@ -1921,40 +1904,28 @@ void wasm_runtime_destroy_wasi(WASMModuleInstanceCommon *module_inst) { WASIContext *wasi_ctx = wasm_runtime_get_wasi_ctx(module_inst); - struct argv_environ_values *argv_environ; - struct fd_table *curfds; - struct fd_prestats *prestats; if (wasi_ctx) { - if (wasi_ctx->argv_environ_offset) { - argv_environ = (struct argv_environ_values *) - wasm_runtime_addr_app_to_native(module_inst, - wasi_ctx->argv_environ_offset); - argv_environ_destroy(argv_environ); - wasm_runtime_module_free(module_inst, wasi_ctx->argv_environ_offset); + if (wasi_ctx->argv_environ) { + argv_environ_destroy(wasi_ctx->argv_environ); + wasm_runtime_free(wasi_ctx->argv_environ); } - if (wasi_ctx->curfds_offset) { - curfds = (struct fd_table *) - wasm_runtime_addr_app_to_native(module_inst, - wasi_ctx->curfds_offset); - fd_table_destroy(curfds); - wasm_runtime_module_free(module_inst, wasi_ctx->curfds_offset); + if (wasi_ctx->curfds) { + fd_table_destroy(wasi_ctx->curfds); + wasm_runtime_free(wasi_ctx->curfds); } - if (wasi_ctx->prestats_offset) { - prestats = (struct fd_prestats *) - wasm_runtime_addr_app_to_native(module_inst, - wasi_ctx->prestats_offset); - fd_prestats_destroy(prestats); - wasm_runtime_module_free(module_inst, wasi_ctx->prestats_offset); + if (wasi_ctx->prestats) { + fd_prestats_destroy(wasi_ctx->prestats); + wasm_runtime_free(wasi_ctx->prestats); } - if (wasi_ctx->argv_buf_offset) - wasm_runtime_module_free(module_inst, wasi_ctx->argv_buf_offset); - if (wasi_ctx->argv_offsets_offset) - wasm_runtime_module_free(module_inst, wasi_ctx->argv_offsets_offset); - if (wasi_ctx->env_buf_offset) - wasm_runtime_module_free(module_inst, wasi_ctx->env_buf_offset); - if (wasi_ctx->env_offsets_offset) - wasm_runtime_module_free(module_inst, wasi_ctx->env_offsets_offset); + if (wasi_ctx->argv_buf) + wasm_runtime_free(wasi_ctx->argv_buf); + if (wasi_ctx->argv_list) + wasm_runtime_free(wasi_ctx->argv_list); + if (wasi_ctx->env_buf) + wasm_runtime_free(wasi_ctx->env_buf); + if (wasi_ctx->env_list) + wasm_runtime_free(wasi_ctx->env_list); wasm_runtime_free(wasi_ctx); } } diff --git a/core/iwasm/common/wasm_runtime_common.h b/core/iwasm/common/wasm_runtime_common.h index 86907d469..74ac7b400 100644 --- a/core/iwasm/common/wasm_runtime_common.h +++ b/core/iwasm/common/wasm_runtime_common.h @@ -74,17 +74,13 @@ typedef struct WASMModuleInstMemConsumption { #if WASM_ENABLE_LIBC_WASI != 0 typedef struct WASIContext { - /* Use offset but not native address, since these fields are - allocated from app's heap, and the heap space may be re-allocated - after memory.grow opcode is executed, the original native address - cannot be accessed again. */ - uint32 curfds_offset; - uint32 prestats_offset; - uint32 argv_environ_offset; - uint32 argv_buf_offset; - uint32 argv_offsets_offset; - uint32 env_buf_offset; - uint32 env_offsets_offset; + struct fd_table *curfds; + struct fd_prestats *prestats; + struct argv_environ_values *argv_environ; + char *argv_buf; + char **argv_list; + char *env_buf; + char **env_list; } WASIContext; #endif diff --git a/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c b/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c index 35b917de2..a6674d714 100644 --- a/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c +++ b/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c @@ -45,49 +45,43 @@ typedef struct iovec_app { } iovec_app_t; typedef struct WASIContext { - uint32 curfds_offset; - uint32 prestats_offset; - uint32 argv_environ_offset; - uint32 argv_buf_offset; - uint32 argv_offsets_offset; - uint32 env_buf_offset; - uint32 env_offsets_offset; + struct fd_table *curfds; + struct fd_prestats *prestats; + struct argv_environ_values *argv_environ; + char *argv_buf; + char **argv_list; + char *env_buf; + char **env_list; } *wasi_ctx_t; wasi_ctx_t wasm_runtime_get_wasi_ctx(wasm_module_inst_t module_inst); -static struct fd_table * +static inline struct fd_table * wasi_ctx_get_curfds(wasm_module_inst_t module_inst, wasi_ctx_t wasi_ctx) { if (!wasi_ctx) return NULL; - return (struct fd_table *) - wasm_runtime_addr_app_to_native(module_inst, - wasi_ctx->curfds_offset); + return wasi_ctx->curfds; } -static struct argv_environ_values * +static inline struct argv_environ_values * wasi_ctx_get_argv_environ(wasm_module_inst_t module_inst, wasi_ctx_t wasi_ctx) { if (!wasi_ctx) return NULL; - return (struct argv_environ_values *) - wasm_runtime_addr_app_to_native(module_inst, - wasi_ctx->argv_environ_offset); + return wasi_ctx->argv_environ; } -static struct fd_prestats * +static inline struct fd_prestats * wasi_ctx_get_prestats(wasm_module_inst_t module_inst, wasi_ctx_t wasi_ctx) { if (!wasi_ctx) return NULL; - return (struct fd_prestats *) - wasm_runtime_addr_app_to_native(module_inst, - wasi_ctx->prestats_offset); + return wasi_ctx->prestats; } static wasi_errno_t @@ -152,9 +146,7 @@ wasi_args_sizes_get(wasm_exec_env_t exec_env, || !validate_native_addr(argv_buf_size_app, sizeof(uint32))) return (wasi_errno_t)-1; - argv_environ = (struct argv_environ_values *) - wasm_runtime_addr_app_to_native(module_inst, - wasi_ctx->argv_environ_offset); + argv_environ = wasi_ctx->argv_environ; err = wasmtime_ssp_args_sizes_get(argv_environ, &argc, &argv_buf_size); diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c index 01e60f90f..df31ea3f7 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c @@ -2822,7 +2822,7 @@ __wasi_errno_t wasmtime_ssp_args_get( char *argv_buf ) { for (size_t i = 0; i < argv_environ->argc; ++i) { - argv[i] = argv_buf + (argv_environ->argv[i] - argv_environ->argv_buf); + argv[i] = argv_buf + (argv_environ->argv_list[i] - argv_environ->argv_buf); } argv[argv_environ->argc] = NULL; bh_memcpy_s(argv_buf, (uint32)argv_environ->argv_buf_size, @@ -2850,7 +2850,7 @@ __wasi_errno_t wasmtime_ssp_environ_get( char *environ_buf ) { for (size_t i = 0; i < argv_environ->environ_count; ++i) { - environ[i] = environ_buf + (argv_environ->environ[i] - argv_environ->environ_buf); + environ[i] = environ_buf + (argv_environ->environ_list[i] - argv_environ->environ_buf); } environ[argv_environ->environ_count] = NULL; bh_memcpy_s(environ_buf, (uint32)argv_environ->environ_buf_size, @@ -2871,76 +2871,26 @@ __wasi_errno_t wasmtime_ssp_environ_sizes_get( } bool argv_environ_init(struct argv_environ_values *argv_environ, - const size_t *argv_offsets, size_t argv_offsets_len, - const char *argv_buf, size_t argv_buf_len, - const size_t *environ_offsets, size_t environ_offsets_len, - const char *environ_buf, size_t environ_buf_len) + char *argv_buf, size_t argv_buf_size, + char **argv_list, size_t argc, + char *environ_buf, size_t environ_buf_size, + char **environ_list, size_t environ_count) { - uint64 total_size; - size_t i; - memset(argv_environ, 0, sizeof(struct argv_environ_values)); - argv_environ->argc = argv_offsets_len; - argv_environ->argv_buf_size = argv_buf_len; - - total_size = sizeof(char *) * (uint64)argv_offsets_len; - if (total_size >= UINT32_MAX - || !(argv_environ->argv = wasm_runtime_malloc((uint32)total_size))) - return false; - - - if (argv_buf_len >= UINT32_MAX - || !(argv_environ->argv_buf = wasm_runtime_malloc((uint32)argv_buf_len))) - goto fail1; - - for (i = 0; i < argv_offsets_len; ++i) { - argv_environ->argv[i] = argv_environ->argv_buf + argv_offsets[i]; - } - bh_memcpy_s(argv_environ->argv_buf, (uint32)argv_buf_len, - argv_buf, (uint32)argv_buf_len); - - argv_environ->environ_count = environ_offsets_len; - argv_environ->environ_buf_size = environ_buf_len; - - total_size = sizeof(char *) * (uint64)environ_offsets_len; - if (total_size >= UINT32_MAX - || !(argv_environ->environ = wasm_runtime_malloc((uint32)total_size))) - goto fail2; - - if (environ_buf_len >= UINT32_MAX - || !(argv_environ->environ_buf = wasm_runtime_malloc((uint32)environ_buf_len))) - goto fail3; - - for (i = 0; i < environ_offsets_len; ++i) { - argv_environ->environ[i] = argv_environ->environ_buf + environ_offsets[i]; - } - bh_memcpy_s(argv_environ->environ_buf, (uint32)environ_buf_len, - environ_buf, (uint32)environ_buf_len); - + argv_environ->argv_buf = argv_buf; + argv_environ->argv_buf_size = argv_buf_size; + argv_environ->argv_list = argv_list; + argv_environ->argc = argc; + argv_environ->environ_buf = environ_buf; + argv_environ->environ_buf_size = environ_buf_size; + argv_environ->environ_list = environ_list; + argv_environ->environ_count = environ_count; return true; - -fail3: - wasm_runtime_free(argv_environ->environ); -fail2: - wasm_runtime_free(argv_environ->argv_buf); -fail1: - wasm_runtime_free(argv_environ->argv); - - memset(argv_environ, 0, sizeof(struct argv_environ_values)); - return false; } void argv_environ_destroy(struct argv_environ_values *argv_environ) { - if (argv_environ->argv_buf) - wasm_runtime_free(argv_environ->argv_buf); - if (argv_environ->argv) - wasm_runtime_free(argv_environ->argv); - if (argv_environ->environ_buf) - wasm_runtime_free(argv_environ->environ_buf); - if (argv_environ->environ) - wasm_runtime_free(argv_environ->environ); } void fd_table_destroy(struct fd_table *ft) diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.h b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.h index 24e4d49ca..1aca4dac4 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.h +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.h @@ -34,25 +34,25 @@ struct fd_prestats { }; struct argv_environ_values { - size_t argc; + const char *argv_buf; size_t argv_buf_size; - char **argv; - char *argv_buf; - size_t environ_count; - size_t environ_buf_size; - char **environ; + char **argv_list; + size_t argc; char *environ_buf; + size_t environ_buf_size; + char **environ_list; + size_t environ_count; }; bool fd_table_init(struct fd_table *); bool fd_table_insert_existing(struct fd_table *, __wasi_fd_t, int); bool fd_prestats_init(struct fd_prestats *); bool fd_prestats_insert(struct fd_prestats *, const char *, __wasi_fd_t); -bool argv_environ_init(struct argv_environ_values *, - const size_t *argv_offsets, size_t argv_offsets_len, - const char *argv_buf, size_t argv_buf_len, - const size_t *environ_offsets, size_t environ_offsets_len, - const char *environ_buf, size_t environ_buf_len); +bool argv_environ_init(struct argv_environ_values *argv_environ, + char *argv_buf, size_t argv_buf_size, + char **argv_list, size_t argc, + char *environ_buf, size_t environ_buf_size, + char **environ_list, size_t environ_count); void argv_environ_destroy(struct argv_environ_values *argv_environ); void fd_table_destroy(struct fd_table *ft); void fd_prestats_destroy(struct fd_prestats *pt); From 591e4ce5364e0a75e49ded9278ca8b0baaf320b7 Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Mon, 30 Nov 2020 17:57:22 +0800 Subject: [PATCH 116/207] Refine aot exception throw, remove unnecessary labels (#456) --- core/iwasm/compilation/aot_compiler.c | 7 --- core/iwasm/compilation/aot_emit_exception.c | 49 ++------------------- core/iwasm/compilation/aot_emit_function.c | 2 +- core/iwasm/compilation/aot_llvm.c | 22 --------- 4 files changed, 5 insertions(+), 75 deletions(-) diff --git a/core/iwasm/compilation/aot_compiler.c b/core/iwasm/compilation/aot_compiler.c index 403515995..d29e8ec6c 100644 --- a/core/iwasm/compilation/aot_compiler.c +++ b/core/iwasm/compilation/aot_compiler.c @@ -1770,13 +1770,6 @@ build_atomic_rmw: if (last_block != func_ctx->got_exception_block) LLVMMoveBasicBlockAfter(func_ctx->got_exception_block, last_block); - - /* Move all other exception blocks before got_exception block */ - for (i = 0; i < EXCE_NUM; i++) { - if (func_ctx->exception_blocks[i]) - LLVMMoveBasicBlockBefore(func_ctx->exception_blocks[i], - func_ctx->got_exception_block); - } } return true; diff --git a/core/iwasm/compilation/aot_emit_exception.c b/core/iwasm/compilation/aot_emit_exception.c index 3f5b6548c..b6eb8429c 100644 --- a/core/iwasm/compilation/aot_emit_exception.c +++ b/core/iwasm/compilation/aot_emit_exception.c @@ -6,22 +6,6 @@ #include "aot_emit_exception.h" #include "../aot/aot_runtime.h" -static char *exce_block_names[] = { - "exce_unreachable", /* EXCE_UNREACHABLE */ - "exce_out_of_memory", /* EXCE_OUT_OF_MEMORY */ - "exce_out_of_bounds_mem_access",/* EXCE_OUT_OF_BOUNDS_MEMORY_ACCESS */ - "exce_integer_overflow", /* EXCE_INTEGER_OVERFLOW */ - "exce_divide_by_zero", /* EXCE_INTEGER_DIVIDE_BY_ZERO */ - "exce_invalid_convert_to_int", /* EXCE_INVALID_CONVERSION_TO_INTEGER */ - "exce_invalid_func_type_idx", /* EXCE_INVALID_FUNCTION_TYPE_INDEX */ - "exce_invalid_func_idx", /* EXCE_INVALID_FUNCTION_INDEX */ - "exce_undefined_element", /* EXCE_UNDEFINED_ELEMENT */ - "exce_uninit_element", /* EXCE_UNINITIALIZED_ELEMENT */ - "exce_call_unlinked", /* EXCE_CALL_UNLINKED_IMPORT_FUNC */ - "exce_native_stack_overflow", /* EXCE_NATIVE_STACK_OVERFLOW */ - "exce_unaligned_atomic" /* EXCE_UNALIGNED_ATOMIC */ -}; - bool aot_emit_exception(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, int32 exception_id, @@ -29,7 +13,6 @@ aot_emit_exception(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, LLVMValueRef cond_br_if, LLVMBasicBlockRef cond_br_else_block) { - LLVMBasicBlockRef exce_block; LLVMBasicBlockRef block_curr = LLVMGetInsertBlock(comp_ctx->builder); LLVMValueRef exce_id = I32_CONST((uint32)exception_id), func_const, func; LLVMTypeRef param_types[2], ret_type, func_type, func_ptr_type; @@ -116,36 +99,12 @@ aot_emit_exception(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, LLVMPositionBuilderAtEnd(comp_ctx->builder, block_curr); } - /* Create exception block if needed */ - if (!(exce_block = func_ctx->exception_blocks[exception_id])) { - if (!(func_ctx->exception_blocks[exception_id] = exce_block = - LLVMAppendBasicBlockInContext(comp_ctx->context, - func_ctx->func, - exce_block_names[exception_id]))) { - aot_set_last_error("add LLVM basic block failed."); - return false; - } - - /* Move before got_exception block */ - LLVMMoveBasicBlockBefore(exce_block, func_ctx->got_exception_block); - - /* Add phi incoming value to got_exception block */ - LLVMAddIncoming(func_ctx->exception_id_phi, &exce_id, &exce_block, 1); - - /* Jump to got exception block */ - LLVMPositionBuilderAtEnd(comp_ctx->builder, exce_block); - if (!LLVMBuildBr(comp_ctx->builder, func_ctx->got_exception_block)) { - aot_set_last_error("llvm build br failed."); - return false; - } - } - - /* Resume builder position */ - LLVMPositionBuilderAtEnd(comp_ctx->builder, block_curr); + /* Add phi incoming value to got_exception block */ + LLVMAddIncoming(func_ctx->exception_id_phi, &exce_id, &block_curr, 1); if (!is_cond_br) { /* not condition br, create br IR */ - if (!LLVMBuildBr(comp_ctx->builder, exce_block)) { + if (!LLVMBuildBr(comp_ctx->builder, func_ctx->got_exception_block)) { aot_set_last_error("llvm build br failed."); return false; } @@ -153,7 +112,7 @@ aot_emit_exception(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, else { /* Create condition br */ if (!LLVMBuildCondBr(comp_ctx->builder, cond_br_if, - exce_block, cond_br_else_block)) { + func_ctx->got_exception_block, cond_br_else_block)) { aot_set_last_error("llvm build cond br failed."); return false; } diff --git a/core/iwasm/compilation/aot_emit_function.c b/core/iwasm/compilation/aot_emit_function.c index e20e175d2..ade942d52 100644 --- a/core/iwasm/compilation/aot_emit_function.c +++ b/core/iwasm/compilation/aot_emit_function.c @@ -99,7 +99,7 @@ check_call_return(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, /* Add check exection success block */ if (!(check_call_succ = LLVMAppendBasicBlockInContext(comp_ctx->context, func_ctx->func, - "check_exce_succ"))) { + "check_call_succ"))) { aot_set_last_error("llvm add basic block failed."); return false; } diff --git a/core/iwasm/compilation/aot_llvm.c b/core/iwasm/compilation/aot_llvm.c index 352d53989..2502fda40 100644 --- a/core/iwasm/compilation/aot_llvm.c +++ b/core/iwasm/compilation/aot_llvm.c @@ -172,20 +172,6 @@ fail: return NULL; } -static bool -create_exception_blocks(AOTFuncContext *func_ctx) -{ - if (!(func_ctx->exception_blocks = - wasm_runtime_malloc(sizeof(LLVMBasicBlockRef) * EXCE_NUM))) { - aot_set_last_error("allocate memory failed."); - return false;; - } - - memset(func_ctx->exception_blocks, 0, - sizeof(LLVMBasicBlockRef) * EXCE_NUM); - return true; -} - static bool create_memory_info(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, LLVMTypeRef int8_ptr_type, uint32 func_index) @@ -744,10 +730,6 @@ aot_create_func_context(AOTCompData *comp_data, AOTCompContext *comp_ctx, goto fail; } - /* Create exception blocks */ - if (!create_exception_blocks(func_ctx)) - goto fail; - /* Create base addr, end addr, data size of mem, heap */ if (!create_memory_info(comp_ctx, func_ctx, int8_ptr_type, func_index)) goto fail; @@ -769,8 +751,6 @@ aot_create_func_context(AOTCompData *comp_data, AOTCompContext *comp_ctx, fail: if (func_ctx->mem_info) wasm_runtime_free(func_ctx->mem_info); - if (func_ctx->exception_blocks) - wasm_runtime_free(func_ctx->exception_blocks); aot_block_stack_destroy(&func_ctx->block_stack); wasm_runtime_free(func_ctx); return NULL; @@ -785,8 +765,6 @@ aot_destroy_func_contexts(AOTFuncContext **func_ctxes, uint32 count) if (func_ctxes[i]) { if (func_ctxes[i]->mem_info) wasm_runtime_free(func_ctxes[i]->mem_info); - if (func_ctxes[i]->exception_blocks) - wasm_runtime_free(func_ctxes[i]->exception_blocks); aot_block_stack_destroy(&func_ctxes[i]->block_stack); aot_checked_addr_list_destroy(func_ctxes[i]); wasm_runtime_free(func_ctxes[i]); From c8b0a1cee1de04b385bac2991e0663d9ae7bb05b Mon Sep 17 00:00:00 2001 From: sophy228 Date: Wed, 2 Dec 2020 10:22:55 +0800 Subject: [PATCH 117/207] Fix some issues for Arm platform. (#457) Motivation: we found some issues during enable the WAMR on arm devices, such as relocation issues, stack alignment issues. Proposed change: We optimized the relocation process for arm platform, for relocation jump table, the SP should be aligned to 16 bytes. And we also make "getentropy" worked for other non-supported platform. --- core/iwasm/aot/arch/aot_reloc_aarch64.c | 168 ++++++++++++++++-- core/iwasm/compilation/aot_emit_numberic.c | 3 +- .../libraries/libc-emcc/libc_emcc_wrapper.c | 9 +- product-mini/platforms/windows/CMakeLists.txt | 2 +- wamr-compiler/CMakeLists.txt | 2 +- 5 files changed, 166 insertions(+), 18 deletions(-) diff --git a/core/iwasm/aot/arch/aot_reloc_aarch64.c b/core/iwasm/aot/arch/aot_reloc_aarch64.c index 373ac2d27..86ca6c696 100644 --- a/core/iwasm/aot/arch/aot_reloc_aarch64.c +++ b/core/iwasm/aot/arch/aot_reloc_aarch64.c @@ -1,12 +1,36 @@ /* - * Copyright (C) 2019 Intel Corporation. All rights reserved. + * Copyright (C) 2020 Intel Corporation. All rights reserved. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception */ #include "aot_reloc.h" +#define R_AARCH64_MOVW_UABS_G0 263 +#define R_AARCH64_MOVW_UABS_G0_NC 264 +#define R_AARCH64_MOVW_UABS_G1 265 +#define R_AARCH64_MOVW_UABS_G1_NC 266 +#define R_AARCH64_MOVW_UABS_G2 267 +#define R_AARCH64_MOVW_UABS_G2_NC 268 +#define R_AARCH64_MOVW_UABS_G3 269 + +#define R_AARCH64_MOVW_SABS_G0 270 +#define R_AARCH64_MOVW_SABS_G1 271 +#define R_AARCH64_MOVW_SABS_G2 272 + +#define R_AARCH64_ADR_PREL_LO19 273 +#define R_AARCH64_ADR_PREL_LO21 274 #define R_AARCH64_ADR_PREL_PG_HI21 275 +#define R_AARCH64_ADR_PREL_PG_HI21_NC 276 + #define R_AARCH64_ADD_ABS_LO12_NC 277 + +#define R_AARCH64_LDST8_ABS_LO12_NC 278 +#define R_AARCH64_LDST16_ABS_LO12_NC 284 +#define R_AARCH64_LDST32_ABS_LO12_NC 285 +#define R_AARCH64_LDST64_ABS_LO12_NC 286 +#define R_AARCH64_LDST128_ABS_LO12_NC 299 + +#define R_AARCH64_JUMP26 282 #define R_AARCH64_CALL26 283 static SymbolMap target_sym_map[] = { @@ -57,8 +81,8 @@ get_current_target(char *target_buf, uint32 target_buf_size) static uint32 get_plt_item_size() { - /* 8*4 bytes instructions and 8 bytes symbol address */ - return 40; + /* 6*4 bytes instructions and 8 bytes symbol address */ + return 32; } void @@ -67,13 +91,11 @@ init_plt_table(uint8 *plt) uint32 i, num = sizeof(target_sym_map) / sizeof(SymbolMap); for (i = 0; i < num; i++) { uint32 *p = (uint32*)plt; - *p++ = 0xd10023ff; /* sub sp, sp, #0x8 */ - *p++ = 0xf90003fe; /* str x30, [sp] */ - *p++ = 0x100000de; /* adr x30, #24 */ + *p++ = 0xf81f0ffe; /* str x30, [sp, #-16]! */ + *p++ = 0x100000be; /* adr x30, #20 ;symbol addr is PC + 5 instructions below */ *p++ = 0xf94003de; /* ldr x30, [x30] */ *p++ = 0xd63f03c0; /* blr x30 */ - *p++ = 0xf94003fe; /* ldr x30, [sp] */ - *p++ = 0x910023ff; /* add sp, sp, #0x8 */ + *p++ = 0xf84107fe; /* ldr x30, [sp], #16 */ *p++ = 0xd61f03c0; /* br x30 */ /* symbol addr */ *(uint64*)p = (uint64)(uintptr_t)target_sym_map[i].symbol_addr; @@ -173,7 +195,74 @@ apply_relocation(AOTModule *module, break; } + case R_AARCH64_MOVW_UABS_G0: + case R_AARCH64_MOVW_UABS_G0_NC: + case R_AARCH64_MOVW_UABS_G1: + case R_AARCH64_MOVW_UABS_G1_NC: + case R_AARCH64_MOVW_UABS_G2: + case R_AARCH64_MOVW_UABS_G2_NC: + case R_AARCH64_MOVW_UABS_G3: + { + void *S = symbol_addr, *P = (void*)(target_section_addr + reloc_offset); + int64 X, A, initial_addend; + int32 insn, imm16; + + CHECK_RELOC_OFFSET(sizeof(int32)); + + insn = *(int32*)P; + imm16 = (insn >> 5) & 0xFFFF; + + SIGN_EXTEND_TO_INT64(imm16, 16, initial_addend); + A = initial_addend; + A += (int64)reloc_addend; + + /* S + A */ + X = (int64)S + A; + + /* No need to check overflow for this reloction type */ + switch (reloc_type) { + case R_AARCH64_MOVW_UABS_G0: + if (X < 0 || X >= (1LL << 16)) + goto overflow_check_fail; + break; + case R_AARCH64_MOVW_UABS_G1: + if (X < 0 || X >= (1LL << 32)) + goto overflow_check_fail; + break; + case R_AARCH64_MOVW_UABS_G2: + if (X < 0 || X >= (1LL << 48)) + goto overflow_check_fail; + break; + default: + break; + } + + /* write the imm16 back to bits[5:20] of instruction */ + switch (reloc_type) { + case R_AARCH64_MOVW_UABS_G0: + case R_AARCH64_MOVW_UABS_G0_NC: + *(int32*)P = (insn & 0xFFE0001F) | ((int32)((X & 0xFFFF) << 5)); + break; + case R_AARCH64_MOVW_UABS_G1: + case R_AARCH64_MOVW_UABS_G1_NC: + *(int32*)P = (insn & 0xFFE0001F) | ((int32)(((X >> 16) & 0xFFFF) << 5)); + break; + case R_AARCH64_MOVW_UABS_G2: + case R_AARCH64_MOVW_UABS_G2_NC: + *(int32*)P = (insn & 0xFFE0001F) | ((int32)(((X >> 32) & 0xFFFF) << 5)); + break; + case R_AARCH64_MOVW_UABS_G3: + *(int32*)P = (insn & 0xFFE0001F) | ((int32)(((X >> 48) & 0xFFFF) << 5)); + break; + default: + bh_assert(0); + break; + } + break; + } + case R_AARCH64_ADR_PREL_PG_HI21: + case R_AARCH64_ADR_PREL_PG_HI21_NC: { void *S = symbol_addr, *P = (void*)(target_section_addr + reloc_offset); int64 X, A, initial_addend; @@ -194,12 +283,9 @@ apply_relocation(AOTModule *module, X = Page((int64)S + A) - Page((int64)P); /* Check overflow: +-4GB */ - if (X > ((int64)4 * BH_GB) || X < ((int64)-4 * BH_GB)) { - set_error_buf(error_buf, error_buf_size, - "AOT module load failed: " - "target address out of range."); - return false; - } + if (reloc_type == R_AARCH64_ADR_PREL_PG_HI21 + && (X > ((int64)4 * BH_GB) || X < ((int64)-4 * BH_GB))) + goto overflow_check_fail; /* write the imm21 back to instruction */ immhi19 = (int32)(((X >> 12) >> 2) & 0x7FFFF); @@ -234,6 +320,54 @@ apply_relocation(AOTModule *module, break; } + case R_AARCH64_LDST8_ABS_LO12_NC: + case R_AARCH64_LDST16_ABS_LO12_NC: + case R_AARCH64_LDST32_ABS_LO12_NC: + case R_AARCH64_LDST64_ABS_LO12_NC: + case R_AARCH64_LDST128_ABS_LO12_NC: + { + void *S = symbol_addr, *P = (void*)(target_section_addr + reloc_offset); + int64 X, A, initial_addend; + int32 insn, imm12; + + CHECK_RELOC_OFFSET(sizeof(int32)); + + insn = *(int32*)P; + imm12 = (insn >> 10) & 0xFFF; + + SIGN_EXTEND_TO_INT64(imm12, 12, initial_addend); + A = initial_addend; + A += (int64)reloc_addend; + + /* S + A */ + X = (int64)S + A; + + /* No need to check overflow for this reloction type */ + + /* write the imm12 back to instruction */ + switch (reloc_type) { + case R_AARCH64_LDST8_ABS_LO12_NC: + *(int32*)P = (insn & 0xFFC003FF) | ((int32)((X & 0xFFF) << 10)); + break; + case R_AARCH64_LDST16_ABS_LO12_NC: + *(int32*)P = (insn & 0xFFC003FF) | ((int32)(((X & 0xFFF) >> 1) << 10)); + break; + case R_AARCH64_LDST32_ABS_LO12_NC: + *(int32*)P = (insn & 0xFFC003FF) | ((int32)(((X & 0xFFF) >> 2) << 10)); + break; + case R_AARCH64_LDST64_ABS_LO12_NC: + *(int32*)P = (insn & 0xFFC003FF) | ((int32)(((X & 0xFFF) >> 3) << 10)); + break; + case R_AARCH64_LDST128_ABS_LO12_NC: + *(int32*)P = (insn & 0xFFC003FF) | ((int32)(((X & 0xFFF) >> 4) << 10)); + break; + default: + bh_assert(0); + break; + } + break; + } + default: if (error_buf != NULL) snprintf(error_buf, error_buf_size, @@ -244,5 +378,11 @@ apply_relocation(AOTModule *module, } return true; + +overflow_check_fail: + set_error_buf(error_buf, error_buf_size, + "AOT module load failed: " + "target address out of range."); + return false; } diff --git a/core/iwasm/compilation/aot_emit_numberic.c b/core/iwasm/compilation/aot_emit_numberic.c index f54140da8..dc267d726 100644 --- a/core/iwasm/compilation/aot_emit_numberic.c +++ b/core/iwasm/compilation/aot_emit_numberic.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 Intel Corporation. All rights reserved. + * Copyright (C) 2020 Intel Corporation. All rights reserved. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception */ @@ -744,6 +744,7 @@ static bool is_target_arm(AOTCompContext *comp_ctx) { return !strncmp(comp_ctx->target_arch, "arm", 3) || + !strncmp(comp_ctx->target_arch, "aarch64", 7) || !strncmp(comp_ctx->target_arch, "thumb", 5); } diff --git a/core/iwasm/libraries/libc-emcc/libc_emcc_wrapper.c b/core/iwasm/libraries/libc-emcc/libc_emcc_wrapper.c index b7dd4a9f2..83186c400 100644 --- a/core/iwasm/libraries/libc-emcc/libc_emcc_wrapper.c +++ b/core/iwasm/libraries/libc-emcc/libc_emcc_wrapper.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 Intel Corporation. All rights reserved. + * Copyright (C) 2020 Intel Corporation. All rights reserved. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception */ @@ -7,6 +7,9 @@ #include "bh_log.h" #include "wasm_export.h" #include "../interpreter/wasm.h" +#ifndef _DEFAULT_SOURCE +#include "sys/syscall.h" +#endif #define get_module_inst(exec_env) \ wasm_runtime_get_module_inst(exec_env) @@ -264,7 +267,11 @@ getentropy_wrapper(wasm_exec_env_t exec_env, void *buffer, uint32 length) { if (buffer == NULL) return -1; +#ifdef _DEFAULT_SOURCE return getentropy(buffer, length); +#else + return syscall(SYS_getrandom, buffer, length, 0); +#endif } static int diff --git a/product-mini/platforms/windows/CMakeLists.txt b/product-mini/platforms/windows/CMakeLists.txt index b01830c40..85f5edc82 100644 --- a/product-mini/platforms/windows/CMakeLists.txt +++ b/product-mini/platforms/windows/CMakeLists.txt @@ -3,7 +3,7 @@ cmake_minimum_required (VERSION 2.8) -project (iwasm C ASM) +project (iwasm C ASM CXX) enable_language(ASM_MASM) # set (CMAKE_VERBOSE_MAKEFILE 1) diff --git a/wamr-compiler/CMakeLists.txt b/wamr-compiler/CMakeLists.txt index c75049caf..de15a272a 100644 --- a/wamr-compiler/CMakeLists.txt +++ b/wamr-compiler/CMakeLists.txt @@ -6,7 +6,7 @@ cmake_minimum_required (VERSION 2.8) if (NOT WAMR_BUILD_PLATFORM STREQUAL "windows") project (aot-compiler) else() - project (aot-compiler C ASM) + project (aot-compiler C ASM CXX) enable_language (ASM_MASM) endif() From 2f530e67fceb192eef14dbf759bf1dcec698f674 Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Fri, 4 Dec 2020 15:35:45 +0800 Subject: [PATCH 118/207] Fix app manager install atomics app issue and optimize workload scripts (#458) --- core/app-framework/base/app/bh_platform.h | 14 ++ core/app-mgr/app-manager/module_wasm_app.c | 13 +- core/shared/platform/zephyr/zephyr_thread.c | 6 +- samples/workload/README.md | 4 + samples/workload/XNNPACK/.gitignore | 2 + samples/workload/XNNPACK/docker_build.sh | 1 + samples/workload/bwa/docker_build.sh | 1 + samples/workload/docker/Dockerfile | 22 ++- .../docker/{build.sh => docker_build.sh} | 28 +++- samples/workload/docker/run.sh | 10 -- .../workload/meshoptimizer/docker_build.sh | 1 + samples/workload/preparation.sh | 129 ++++++++++++++++++ samples/workload/wasm-av1/docker_build.sh | 1 + 13 files changed, 206 insertions(+), 26 deletions(-) create mode 100644 samples/workload/XNNPACK/.gitignore create mode 120000 samples/workload/XNNPACK/docker_build.sh create mode 120000 samples/workload/bwa/docker_build.sh rename samples/workload/docker/{build.sh => docker_build.sh} (69%) delete mode 100755 samples/workload/docker/run.sh create mode 120000 samples/workload/meshoptimizer/docker_build.sh create mode 100755 samples/workload/preparation.sh create mode 120000 samples/workload/wasm-av1/docker_build.sh diff --git a/core/app-framework/base/app/bh_platform.h b/core/app-framework/base/app/bh_platform.h index 2539ec58d..70760e9c1 100755 --- a/core/app-framework/base/app/bh_platform.h +++ b/core/app-framework/base/app/bh_platform.h @@ -45,4 +45,18 @@ uint16 ntohs(uint16 value); // We are not worried for the WASM world since the sandbox will catch it. #define bh_memcpy_s(dst, dst_len, src, src_len) memcpy(dst, src, src_len) +#ifdef NDEBUG +#define bh_assert(v) (void)0 +#else +#define bh_assert(v) do { \ + if (!(v)) { \ + int _count; \ + printf("ASSERTION FAILED: %s, at %s, line %d",\ + #v, __FILE__, __LINE__); \ + _count = printf("\n"); \ + printf("%d\n", _count / (_count - 1)); \ + } \ + } while (0) +#endif + #endif /* DEPS_IWASM_APP_LIBS_BASE_BH_PLATFORM_H_ */ diff --git a/core/app-mgr/app-manager/module_wasm_app.c b/core/app-mgr/app-manager/module_wasm_app.c index a84e760df..6fda5355e 100644 --- a/core/app-mgr/app-manager/module_wasm_app.c +++ b/core/app-mgr/app-manager/module_wasm_app.c @@ -703,7 +703,11 @@ wasm_app_module_install(request_t * msg) SECTION_TYPE_GLOBAL, SECTION_TYPE_EXPORT, SECTION_TYPE_START, - SECTION_TYPE_ELEM + SECTION_TYPE_ELEM, +#if WASM_ENABLE_BULK_MEMORY != 0 + SECTION_TYPE_DATACOUNT +#endif + }; /* Sections to be released after instantiating */ uint8 sections2[] = { SECTION_TYPE_DATA }; @@ -1174,7 +1178,12 @@ wasm_app_module_on_install_request_byte_arrive(uint8 ch, } else if (recv_ctx.phase == Phase_Wasm_Section_Type) { uint8 section_type = ch; - if (section_type <= SECTION_TYPE_DATA) { +#if WASM_ENABLE_BULK_MEMORY == 0 + uint8 section_type_max = SECTION_TYPE_DATA; +#else + uint8 section_type_max = SECTION_TYPE_DATACOUNT; +#endif + if (section_type <= section_type_max) { wasm_section_t *new_section; if (!(new_section = (wasm_section_t *) APP_MGR_MALLOC(sizeof(wasm_section_t)))) { app_manager_printf("Allocate memory failed!\n"); diff --git a/core/shared/platform/zephyr/zephyr_thread.c b/core/shared/platform/zephyr/zephyr_thread.c index ebcb37b42..56032f97d 100644 --- a/core/shared/platform/zephyr/zephyr_thread.c +++ b/core/shared/platform/zephyr/zephyr_thread.c @@ -8,13 +8,9 @@ #define bh_assert(v) do { \ if (!(v)) { \ - int _count; \ printf("\nASSERTION FAILED: %s, at %s, line %d\n", \ #v, __FILE__, __LINE__); \ - _count = printf(" "); \ - /* divived by 0 to make it abort */ \ - printf("%d\n", _count / (_count - 1)); \ - while (1); \ + abort(); \ } \ } while (0) diff --git a/samples/workload/README.md b/samples/workload/README.md index f32fb4b9c..2af6ec6bd 100644 --- a/samples/workload/README.md +++ b/samples/workload/README.md @@ -6,6 +6,10 @@ Ubuntu 18.04 as an example. ## Installation instructions +use [preparation.sh](./preparation.sh) to install all dependencies before compiling any workload. + +for details, the script includes below steps: + - **wasi-sdk**. Install [latest release](https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-11/wasi-sdk-11.0-linux.tar.gz) in */opt/wasi-sdk* or */opt/wasi-sdk-11* diff --git a/samples/workload/XNNPACK/.gitignore b/samples/workload/XNNPACK/.gitignore new file mode 100644 index 000000000..09f3fe927 --- /dev/null +++ b/samples/workload/XNNPACK/.gitignore @@ -0,0 +1,2 @@ +xnnpack +build diff --git a/samples/workload/XNNPACK/docker_build.sh b/samples/workload/XNNPACK/docker_build.sh new file mode 120000 index 000000000..3c6de9bca --- /dev/null +++ b/samples/workload/XNNPACK/docker_build.sh @@ -0,0 +1 @@ +../docker/docker_build.sh \ No newline at end of file diff --git a/samples/workload/bwa/docker_build.sh b/samples/workload/bwa/docker_build.sh new file mode 120000 index 000000000..3c6de9bca --- /dev/null +++ b/samples/workload/bwa/docker_build.sh @@ -0,0 +1 @@ +../docker/docker_build.sh \ No newline at end of file diff --git a/samples/workload/docker/Dockerfile b/samples/workload/docker/Dockerfile index cb96768c5..8afa4738a 100644 --- a/samples/workload/docker/Dockerfile +++ b/samples/workload/docker/Dockerfile @@ -23,7 +23,7 @@ RUN cd /opt \ && tar zxf ${WASI_SDK_FILE} \ && rm ${WASI_SDK_FILE} \ && ln -sf /opt/wasi-sdk-${WASI_SDK_VER} /opt/wasi-sdk \ - && ln -sf /opt/wasi-sdk/lib/clang/10.0.0/lib/wasi/ /usr/lib/llvm-11/lib/clang/11.0.0/lib/ + && ln -sf /opt/wasi-sdk/lib/clang/10.0.0/lib/wasi/ /usr/lib/llvm-11/lib/clang/11.0.1/lib/ # # install wabt @@ -46,7 +46,8 @@ RUN cd /tmp \ # # install tools -RUN apt install -y git tree +RUN apt update \ + && apt install -y git tree # # install emsdk @@ -85,4 +86,19 @@ RUN apt-get autoremove -y \ && rm -rf /tmp/* VOLUME /data -WORKDIR /data + +# +# +RUN touch /build.sh \ + && echo "\ +#!/bin/bash \n\ +if [[ -d /data/project/build ]]; then \n\ + rm -r /data/project/build \n\ +fi \n\ +mkdir /data/project/build \n\ +cd /data/project/build \n\ +source /opt/emsdk/emsdk_env.sh \n\ +cmake .. \n\ +make \n\ +cd - > /dev/null" > /build.sh \ + && chmod a+x /build.sh diff --git a/samples/workload/docker/build.sh b/samples/workload/docker/docker_build.sh similarity index 69% rename from samples/workload/docker/build.sh rename to samples/workload/docker/docker_build.sh index d14606c8a..a5fb54bbb 100755 --- a/samples/workload/docker/build.sh +++ b/samples/workload/docker/docker_build.sh @@ -5,8 +5,10 @@ #!/bin/bash -if [[ ! -d build_scripts ]]; then - mkdir build_scripts +BUILD_CONTENT="/tmp/build_content" + +if [[ ! -d ${BUILD_CONTENT} ]]; then + mkdir ${BUILD_CONTENT} fi WASI_SDK_VER=11.0 @@ -15,7 +17,7 @@ CMAKE_VER=3.16.2 BINARYEN_VER=version_97 BAZEL_VER=3.7.0 -cd build_scripts +cd ${BUILD_CONTENT} if [[ ! -f wasi-sdk-${WASI_SDK_VER}-linux.tar.gz ]]; then wget https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-11/wasi-sdk-${WASI_SDK_VER}-linux.tar.gz fi @@ -39,16 +41,30 @@ fi if [[ ! -f bazel-${BAZEL_VER}-installer-linux-x86_64.sh ]]; then wget https://github.com/bazelbuild/bazel/releases/download/${BAZEL_VER}/bazel-${BAZEL_VER}-installer-linux-x86_64.sh fi -cd - +cd - > /dev/null + +DOCKERFILE_PATH=$(dirname $(realpath $0)) docker build \ --build-arg http_proxy=${http_proxy} \ --build-arg https_proxy=${https_proxy} \ --build-arg HTTP_PROXY=${http_proxy} \ --build-arg HTTPS_PROXY=${https_proxy} \ - --build-arg WASI_SDK_VER=11.0 \ + --build-arg WASI_SDK_VER=${WASI_SDK_VER} \ --build-arg WABT_VER=${WABT_VER} \ --build-arg CMAKE_VER=${CMAKE_VER} \ --build-arg BINARYEN_VER=${BINARYEN_VER} \ --build-arg BAZEL_VER=${BAZEL_VER} \ - -t clang_env:0.1 -f Dockerfile build_scripts + -t clang_env:0.1 -f ${DOCKERFILE_PATH}/Dockerfile ${BUILD_CONTENT} + +docker run --rm -it \ + -e http_proxy=${http_proxy} \ + -e https_proxy=${https_proxy} \ + -e HTTP_PROXY=${http_proxy} \ + -e HTTPS_PROXY=${htpps_proxy} \ + --name workload_w_clang \ + --mount type=bind,source=$(pwd),target=/data/project \ + --mount type=bind,source=$(pwd)/../cmake,target=/data/cmake \ + -w /data/project \ + clang_env:0.1 \ + /bin/bash -c /build.sh diff --git a/samples/workload/docker/run.sh b/samples/workload/docker/run.sh deleted file mode 100755 index 8c5943027..000000000 --- a/samples/workload/docker/run.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash - -docker run --rm -it \ - -e http_proxy=${http_proxy} \ - -e https_proxy=${https_proxy} \ - -e HTTP_PROXY=${http_proxy} \ - -e HTTPS_PROXY=${htpps_proxy} \ - --name workload_w_clang \ - --mount type=bind,source=$(pwd)/..,target=/data \ - clang_env:0.1 diff --git a/samples/workload/meshoptimizer/docker_build.sh b/samples/workload/meshoptimizer/docker_build.sh new file mode 120000 index 000000000..3c6de9bca --- /dev/null +++ b/samples/workload/meshoptimizer/docker_build.sh @@ -0,0 +1 @@ +../docker/docker_build.sh \ No newline at end of file diff --git a/samples/workload/preparation.sh b/samples/workload/preparation.sh new file mode 100755 index 000000000..81b1aea2c --- /dev/null +++ b/samples/workload/preparation.sh @@ -0,0 +1,129 @@ +#!/bin/bash + +readonly BUILD_CONTENT="/tmp/build_content" +readonly WASI_SDK_VER=11.0 +readonly WASI_SDK_FILE="wasi-sdk-${WASI_SDK_VER}-linux.tar.gz" +readonly WABT_VER=1.0.19 +readonly WABT_FILE="wabt-${WABT_VER}-ubuntu.tar.gz" +readonly CMAKE_VER=3.16.2 +readonly CMAKE_FILE="cmake-${CMAKE_VER}-Linux-x86_64.sh" +readonly BINARYEN_VER=version_97 +readonly BINARYEN_FILE="binaryen-${BINARYEN_VER}-x86_64-linux.tar.gz" +readonly BAZEL_VER=3.7.0 +readonly BAZEL_FILE=bazel-${BAZEL_VER}-installer-linux-x86_64.sh + +function DEBUG() { + [[ -n $(env | grep "\") ]] +} + +# +# install dependency +function install_deps() { + apt update + apt install -y lsb-release wget software-properties-common \ + build-essential git tree zip unzip +} + +# +# install clang +function install_clang() { + if [[ ! -f llvm.sh ]]; then + wget https://apt.llvm.org/llvm.sh + fi + + chmod a+x llvm.sh + ./llvm.sh 11 +} + +# +# install wasi-sdk +function install_wasi-sdk() { + if [[ ! -f ${WASI_SDK_FILE} ]]; then + wget https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-11/${WASI_SDK_FILE} + fi + + tar zxf ${WASI_SDK_FILE} -C /opt + ln -sf /opt/wasi-sdk-${WASI_SDK_VER} /opt/wasi-sdk + ln -sf /opt/wasi-sdk/lib/clang/10.0.0/lib/wasi/ /usr/lib/llvm-11/lib/clang/11.0.1/lib/ +} + +# +# install wabt +function install_wabt() { + if [[ ! -f ${WABT_FILE} ]]; then + wget https://github.com/WebAssembly/wabt/releases/download/${WABT_VER}/${WABT_FILE} + fi + + tar zxf ${WABT_FILE} -C /opt + ln -sf /opt/wabt-${WABT_VER} /opt/wabt +} + +# +# install cmake +function install_cmake() { + if [[ ! -f cmake-${CMAKE_VER}-Linux-x86_64.sh ]]; then + wget https://github.com/Kitware/CMake/releases/download/v${CMAKE_VER}/${CMAKE_FILE} + fi + + chmod a+x ${CMAKE_FILE} + mkdir /opt/cmake + ./${CMAKE_FILE} --prefix=/opt/cmake --skip-license + ln -sf /opt/cmake/bin/cmake /usr/local/bin/cmake +} + +# +# install emsdk +function install_emsdk() { + cd /opt + git clone https://github.com/emscripten-core/emsdk.git + cd emsdk + git pull + ./emsdk install latest + ./emsdk activate latest + echo "source /opt/emsdk/emsdk_env.sh" >> ${HOME}/.bashrc +} + +# +# install binaryen +function install_binaryen() { + if [[ ! -f ${BINARYEN_FILE} ]]; then + wget https://github.com/WebAssembly/binaryen/releases/download/${BINARYEN_VER}/${BINARYEN_FILE} + fi + + tar zxf ${BINARYEN_FILE} -C /opt + ln -sf /opt/binaryen-${BINARYEN_VER} /opt/binaryen +} + +# +# install bazel +function install_bazel() { + if [[ ! -f ${BAZEL_FILE} ]]; then + wget https://github.com/bazelbuild/bazel/releases/download/${BAZEL_VER}/${BAZEL_FILE} + fi + + chmod a+x ${BAZEL_FILE} + ./${BAZEL_FILE} +} + +# +# MAIN +DEBUG && set -xevu +if [[ ! -d ${BUILD_CONTENT} ]]; then + mkdir ${BUILD_CONTENT} +fi + +cd ${BUILD_CONTENT} +if DEBUG; then + $@ +else + install_deps \ + && install_clang \ + && install_wasi \ + && install_wabt \ + && install_cmake \ + && install_emsdk \ + && install_binaryen \ + && install_bazel +fi +cd - > /dev/null +DEBUG && set +xevu diff --git a/samples/workload/wasm-av1/docker_build.sh b/samples/workload/wasm-av1/docker_build.sh new file mode 120000 index 000000000..3c6de9bca --- /dev/null +++ b/samples/workload/wasm-av1/docker_build.sh @@ -0,0 +1 @@ +../docker/docker_build.sh \ No newline at end of file From 5176fe25959229a2c2fe3f540a7c0a5d39c92b76 Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Fri, 4 Dec 2020 18:07:52 +0800 Subject: [PATCH 119/207] Fix timer setTimeout issue and some coding style issues (#459) --- .../app-framework/base/native/timer_wrapper.c | 61 ++-- core/app-mgr/app-manager/module_utils.c | 11 +- core/shared/utils/runtime_timer.c | 277 ++++++++++-------- core/shared/utils/runtime_timer.h | 2 +- 4 files changed, 196 insertions(+), 155 deletions(-) diff --git a/core/app-framework/base/native/timer_wrapper.c b/core/app-framework/base/native/timer_wrapper.c index 1f565aaa0..42b91a743 100644 --- a/core/app-framework/base/native/timer_wrapper.c +++ b/core/app-framework/base/native/timer_wrapper.c @@ -8,17 +8,19 @@ #include "../app-manager/module_wasm_app.h" #include "timer_native_api.h" -static bool timer_thread_run = true; - -bh_list g_timer_ctx_list; -korp_cond g_timer_ctx_list_cond; -korp_mutex g_timer_ctx_list_mutex; typedef struct { bh_list_link l; timer_ctx_t timer_ctx; } timer_ctx_node_t; -void wasm_timer_callback(timer_id_t id, unsigned int mod_id) +static bool timer_thread_run = true; + +static bh_list g_timer_ctx_list; +static korp_cond g_timer_ctx_list_cond; +static korp_mutex g_timer_ctx_list_mutex; + +void +wasm_timer_callback(timer_id_t id, unsigned int mod_id) { module_data* module = module_data_list_lookup_id(mod_id); if (module == NULL) @@ -29,13 +31,14 @@ void wasm_timer_callback(timer_id_t id, unsigned int mod_id) bh_post_msg(module->queue, TIMER_EVENT_WASM, (char *)(uintptr_t)id, 0); } -/// -/// why we create a separate link for module timer contexts -/// rather than traverse the module list? -/// It helps to reduce the lock frequency for the module list. -/// Also when we lock the module list and then call the callback for -/// timer expire, the callback is request the list lock again for lookup -/// the module from module id. It is for avoiding that situation. +/** + * why we create a separate link for module timer contexts + * rather than traverse the module list? + * It helps to reduce the lock frequency for the module list. + * Also when we lock the module list and then call the callback for + * timer expire, the callback is request the list lock again for lookup + * the module from module id. It is for avoiding that situation. + */ void * thread_modulers_timer_check(void * arg) { @@ -68,37 +71,41 @@ void * thread_modulers_timer_check(void * arg) return NULL; } -void wakeup_modules_timer_thread(timer_ctx_t ctx) +void +wakeup_modules_timer_thread(timer_ctx_t ctx) { os_mutex_lock(&g_timer_ctx_list_mutex); os_cond_signal(&g_timer_ctx_list_cond); os_mutex_unlock(&g_timer_ctx_list_mutex); } -void init_wasm_timer() +void +init_wasm_timer() { korp_tid tm_tid; bh_list_init(&g_timer_ctx_list); os_cond_init(&g_timer_ctx_list_cond); - /* temp solution for: thread_modulers_timer_check thread would recursive lock the mutex */ + /* temp solution for: thread_modulers_timer_check thread + would recursive lock the mutex */ os_recursive_mutex_init(&g_timer_ctx_list_mutex); os_thread_create(&tm_tid, thread_modulers_timer_check, NULL, BH_APPLET_PRESERVED_STACK_SIZE); } -void exit_wasm_timer() +void +exit_wasm_timer() { timer_thread_run = false; } -timer_ctx_t create_wasm_timer_ctx(unsigned int module_id, int prealloc_num) +timer_ctx_t +create_wasm_timer_ctx(unsigned int module_id, int prealloc_num) { timer_ctx_t ctx = create_timer_ctx(wasm_timer_callback, wakeup_modules_timer_thread, - prealloc_num, - module_id); + prealloc_num, module_id); if (ctx == NULL) return NULL; @@ -119,11 +126,14 @@ timer_ctx_t create_wasm_timer_ctx(unsigned int module_id, int prealloc_num) return ctx; } -void destroy_module_timer_ctx(unsigned int module_id) +void +destroy_module_timer_ctx(unsigned int module_id) { + timer_ctx_node_t* elem; + os_mutex_lock(&g_timer_ctx_list_mutex); - timer_ctx_node_t* elem = (timer_ctx_node_t*) - bh_list_first_elem(&g_timer_ctx_list); + elem = (timer_ctx_node_t*) + bh_list_first_elem(&g_timer_ctx_list); while (elem) { if (timer_ctx_get_owner(elem->timer_ctx) == module_id) { bh_list_remove(&g_timer_ctx_list, elem); @@ -137,7 +147,8 @@ void destroy_module_timer_ctx(unsigned int module_id) os_mutex_unlock(&g_timer_ctx_list_mutex); } -timer_ctx_t get_wasm_timer_ctx(wasm_module_inst_t module_inst) +timer_ctx_t +get_wasm_timer_ctx(wasm_module_inst_t module_inst) { module_data * m = app_manager_get_module_data(Module_WASM_App, module_inst); @@ -184,8 +195,6 @@ wasm_timer_restart(wasm_exec_env_t exec_env, sys_timer_restart(timer_ctx, timer_id, interval); } -extern uint32 get_sys_tick_ms(); - uint32 wasm_get_sys_tick_ms(wasm_exec_env_t exec_env) { diff --git a/core/app-mgr/app-manager/module_utils.c b/core/app-mgr/app-manager/module_utils.c index 637feeaed..561ef24fe 100644 --- a/core/app-mgr/app-manager/module_utils.c +++ b/core/app-mgr/app-manager/module_utils.c @@ -198,17 +198,16 @@ void release_module(module_data *m_data) APP_MGR_FREE(m_data); } -int check_modules_timer_expiry() +uint32 check_modules_timer_expiry() { os_mutex_lock(&module_data_list_lock); module_data *p = module_data_list; - int ms_to_expiry = -1; + uint32 ms_to_expiry = (uint32)-1; while (p) { - - int next = get_expiry_ms(p->timer_ctx); - if (next != -1) { - if (ms_to_expiry == -1 || ms_to_expiry > next) + uint32 next = get_expiry_ms(p->timer_ctx); + if (next != (uint32)-1) { + if (ms_to_expiry == (uint32)-1 || ms_to_expiry > next) ms_to_expiry = next; } diff --git a/core/shared/utils/runtime_timer.c b/core/shared/utils/runtime_timer.c index 68b25f8fa..873ba341c 100644 --- a/core/shared/utils/runtime_timer.c +++ b/core/shared/utils/runtime_timer.c @@ -5,101 +5,111 @@ #include "runtime_timer.h" -#define PRINT(...) -//#define PRINT printf +#if 1 +#define PRINT(...) (void)0 +#else +#define PRINT printf +#endif typedef struct _app_timer { struct _app_timer * next; uint32 id; - unsigned int interval; + uint32 interval; uint64 expiry; bool is_periodic; } app_timer_t; -struct _timer_ctx { - app_timer_t * g_app_timers; - app_timer_t * idle_timers; - app_timer_t * free_timers; - unsigned int g_max_id; +typedef struct _timer_ctx { + app_timer_t *app_timers; + app_timer_t *idle_timers; + app_timer_t *free_timers; + uint32 max_timer_id; int pre_allocated; - unsigned int owner; + uint32 owner; - //add mutext and conditions + /* mutex and condition */ korp_cond cond; korp_mutex mutex; timer_callback_f timer_callback; check_timer_expiry_f refresh_checker; -}; +} *timer_ctx_t; -uint64 bh_get_tick_ms() +uint64 +bh_get_tick_ms() { return os_time_get_boot_microsecond() / 1000; } -uint32 bh_get_elpased_ms(uint32 * last_system_clock) +uint32 +bh_get_elpased_ms(uint32 *last_system_clock) { uint32 elpased_ms; - - // attention: the bh_get_tick_ms() return 64 bits integer. - // but the bh_get_elpased_ms() is designed to use 32 bits clock count. + /* attention: the bh_get_tick_ms() return 64 bits integer, but + the bh_get_elpased_ms() is designed to use 32 bits clock count */ uint32 now = (uint32)bh_get_tick_ms(); - // system clock overrun + /* system clock overrun */ if (now < *last_system_clock) { - elpased_ms = now + (0xFFFFFFFF - *last_system_clock) + 1; - } else { + PRINT("system clock overrun!\n"); + elpased_ms = now + (UINT32_MAX - *last_system_clock) + 1; + } + else { elpased_ms = now - *last_system_clock; } *last_system_clock = now; - return elpased_ms; } -static app_timer_t * remove_timer_from(timer_ctx_t ctx, uint32 timer_id, - bool active_list) +static app_timer_t * +remove_timer_from(timer_ctx_t ctx, uint32 timer_id, bool active_list) { + app_timer_t **head, *prev, *t; + os_mutex_lock(&ctx->mutex); - app_timer_t ** head; + if (active_list) - head = &ctx->g_app_timers; + head = &ctx->app_timers; else head = &ctx->idle_timers; - app_timer_t * t = *head; - app_timer_t * prev = NULL; + t = *head; + prev = NULL; while (t) { if (t->id == timer_id) { if (prev == NULL) { *head = t->next; - PRINT("removed timer [%d] at head from list %d\n", t->id, active_list); - } else { + PRINT("removed timer [%d] at head from list %d\n", + t->id, active_list); + } + else { prev->next = t->next; - PRINT("removed timer [%d] after [%d] from list %d\n", t->id, prev->id, active_list); + PRINT("removed timer [%d] after [%d] from list %d\n", + t->id, prev->id, active_list); } os_mutex_unlock(&ctx->mutex); if (active_list && prev == NULL && ctx->refresh_checker) ctx->refresh_checker(ctx); - return t; - } else { + } + else { prev = t; t = t->next; } } os_mutex_unlock(&ctx->mutex); - return NULL; } -static app_timer_t * remove_timer(timer_ctx_t ctx, uint32 timer_id, - bool * active) +static app_timer_t * +remove_timer(timer_ctx_t ctx, uint32 timer_id, bool *active) { - app_timer_t* t = remove_timer_from(ctx, timer_id, true); + app_timer_t *t = remove_timer_from(ctx, timer_id, true); + if (t) { if (active) *active = true; @@ -111,61 +121,63 @@ static app_timer_t * remove_timer(timer_ctx_t ctx, uint32 timer_id, return remove_timer_from(ctx, timer_id, false); } -static void reschedule_timer(timer_ctx_t ctx, app_timer_t * timer) +static void +reschedule_timer(timer_ctx_t ctx, app_timer_t *timer) { + app_timer_t *t; + app_timer_t *prev = NULL; os_mutex_lock(&ctx->mutex); - app_timer_t * t = ctx->g_app_timers; - app_timer_t * prev = NULL; + t = ctx->app_timers; timer->next = NULL; timer->expiry = bh_get_tick_ms() + timer->interval; while (t) { if (timer->expiry < t->expiry) { if (prev == NULL) { - timer->next = ctx->g_app_timers; - ctx->g_app_timers = timer; + timer->next = ctx->app_timers; + ctx->app_timers = timer; PRINT("rescheduled timer [%d] at head\n", timer->id); - } else { + } + else { timer->next = t; prev->next = timer; - PRINT("rescheduled timer [%d] after [%d]\n", timer->id, prev->id); + PRINT("rescheduled timer [%d] after [%d]\n", + timer->id, prev->id); } - os_mutex_unlock(&ctx->mutex); - - // ensure the refresh_checker() is called out of the lock - if (prev == NULL && ctx->refresh_checker) - ctx->refresh_checker(ctx); - - return; - } else { + goto out; + } + else { prev = t; t = t->next; } } if (prev) { - // insert to the list end + /* insert to the list end */ prev->next = timer; - PRINT("rescheduled timer [%d] at end, after [%d]\n", timer->id, prev->id); - } else { - // insert at the begin - bh_assert(ctx->g_app_timers == NULL); - ctx->g_app_timers = timer; + PRINT("rescheduled timer [%d] at end, after [%d]\n", + timer->id, prev->id); + } + else { + /* insert at the begin */ + bh_assert(ctx->app_timers == NULL); + ctx->app_timers = timer; PRINT("rescheduled timer [%d] as first\n", timer->id); } +out: os_mutex_unlock(&ctx->mutex); - // ensure the refresh_checker() is called out of the lock + /* ensure the refresh_checker() is called out of the lock */ if (prev == NULL && ctx->refresh_checker) ctx->refresh_checker(ctx); - } -static void release_timer(timer_ctx_t ctx, app_timer_t * t) +static void +release_timer(timer_ctx_t ctx, app_timer_t *t) { if (ctx->pre_allocated) { os_mutex_lock(&ctx->mutex); @@ -173,15 +185,18 @@ static void release_timer(timer_ctx_t ctx, app_timer_t * t) ctx->free_timers = t; PRINT("recycle timer :%d\n", t->id); os_mutex_unlock(&ctx->mutex); - } else { + } + else { PRINT("destroy timer :%d\n", t->id); BH_FREE(t); } } -void release_timer_list(app_timer_t ** p_list) +void +release_timer_list(app_timer_t **p_list) { app_timer_t *t = *p_list; + while (t) { app_timer_t *next = t->next; PRINT("destroy timer list:%d\n", t->id); @@ -193,18 +208,19 @@ void release_timer_list(app_timer_t ** p_list) } /* - * - * API exposed - * + * API exposed */ -timer_ctx_t create_timer_ctx(timer_callback_f timer_handler, - check_timer_expiry_f expiery_checker, int prealloc_num, - unsigned int owner) +timer_ctx_t +create_timer_ctx(timer_callback_f timer_handler, + check_timer_expiry_f expiery_checker, + int prealloc_num, unsigned int owner) { - timer_ctx_t ctx = (timer_ctx_t) BH_MALLOC(sizeof(struct _timer_ctx)); + timer_ctx_t ctx = (timer_ctx_t)BH_MALLOC(sizeof(struct _timer_ctx)); + if (ctx == NULL) return NULL; + memset(ctx, 0, sizeof(struct _timer_ctx)); ctx->timer_callback = timer_handler; @@ -213,7 +229,8 @@ timer_ctx_t create_timer_ctx(timer_callback_f timer_handler, ctx->owner = owner; while (prealloc_num > 0) { - app_timer_t *timer = (app_timer_t*) BH_MALLOC(sizeof(app_timer_t)); + app_timer_t *timer = (app_timer_t*)BH_MALLOC(sizeof(app_timer_t)); + if (timer == NULL) goto cleanup; @@ -223,15 +240,18 @@ timer_ctx_t create_timer_ctx(timer_callback_f timer_handler, prealloc_num--; } - os_cond_init(&ctx->cond); - os_mutex_init(&ctx->mutex); + if (os_cond_init(&ctx->cond) != 0) + goto cleanup; + + if (os_mutex_init(&ctx->mutex) != 0) { + os_cond_destroy(&ctx->cond); + goto cleanup; + } PRINT("timer ctx created. pre-alloc: %d\n", ctx->pre_allocated); - return ctx; cleanup: - if (ctx) { release_timer_list(&ctx->free_timers); BH_FREE(ctx); @@ -240,10 +260,11 @@ cleanup: return NULL; } -void destroy_timer_ctx(timer_ctx_t ctx) +void +destroy_timer_ctx(timer_ctx_t ctx) { while (ctx->free_timers) { - void * tmp = ctx->free_timers; + void *tmp = ctx->free_timers; ctx->free_timers = ctx->free_timers->next; BH_FREE(tmp); } @@ -255,12 +276,14 @@ void destroy_timer_ctx(timer_ctx_t ctx) BH_FREE(ctx); } -unsigned int timer_ctx_get_owner(timer_ctx_t ctx) +unsigned int +timer_ctx_get_owner(timer_ctx_t ctx) { return ctx->owner; } -void add_idle_timer(timer_ctx_t ctx, app_timer_t * timer) +void +add_idle_timer(timer_ctx_t ctx, app_timer_t * timer) { os_mutex_lock(&ctx->mutex); timer->next = ctx->idle_timers; @@ -268,31 +291,33 @@ void add_idle_timer(timer_ctx_t ctx, app_timer_t * timer) os_mutex_unlock(&ctx->mutex); } -uint32 sys_create_timer(timer_ctx_t ctx, int interval, bool is_period, - bool auto_start) +uint32 +sys_create_timer(timer_ctx_t ctx, int interval, bool is_period, + bool auto_start) { - app_timer_t *timer; if (ctx->pre_allocated) { - if (ctx->free_timers == NULL) + if (ctx->free_timers == NULL) { return (uint32)-1; + } else { timer = ctx->free_timers; ctx->free_timers = timer->next; } - } else { - timer = (app_timer_t*) BH_MALLOC(sizeof(app_timer_t)); + } + else { + timer = (app_timer_t*)BH_MALLOC(sizeof(app_timer_t)); if (timer == NULL) return (uint32)-1; } memset(timer, 0, sizeof(*timer)); - ctx->g_max_id++; - if (ctx->g_max_id == (uint32)-1) - ctx->g_max_id++; - timer->id = ctx->g_max_id; + ctx->max_timer_id++; + if (ctx->max_timer_id == (uint32)-1) + ctx->max_timer_id++; + timer->id = ctx->max_timer_id; timer->interval = (uint32)interval; timer->is_periodic = is_period; @@ -304,10 +329,12 @@ uint32 sys_create_timer(timer_ctx_t ctx, int interval, bool is_period, return timer->id; } -bool sys_timer_cancel(timer_ctx_t ctx, uint32 timer_id) +bool +sys_timer_cancel(timer_ctx_t ctx, uint32 timer_id) { bool from_active; app_timer_t * t = remove_timer(ctx, timer_id, &from_active); + if (t == NULL) return false; @@ -317,10 +344,12 @@ bool sys_timer_cancel(timer_ctx_t ctx, uint32 timer_id) return from_active; } -bool sys_timer_destroy(timer_ctx_t ctx, uint32 timer_id) +bool +sys_timer_destroy(timer_ctx_t ctx, uint32 timer_id) { bool from_active; app_timer_t * t = remove_timer(ctx, timer_id, &from_active); + if (t == NULL) return false; @@ -330,14 +359,15 @@ bool sys_timer_destroy(timer_ctx_t ctx, uint32 timer_id) return true; } -bool sys_timer_restart(timer_ctx_t ctx, uint32 timer_id, int interval) +bool +sys_timer_restart(timer_ctx_t ctx, uint32 timer_id, int interval) { app_timer_t * t = remove_timer(ctx, timer_id, NULL); + if (t == NULL) return false; - if (interval > 0) - t->interval = (uint32)interval; + t->interval = (uint32)interval; reschedule_timer(ctx, t); @@ -346,44 +376,46 @@ bool sys_timer_restart(timer_ctx_t ctx, uint32 timer_id, int interval) } /* - * - * * API called by the timer manager from another thread or the kernel timer handler - * - * */ -// lookup the app queue by the module name -//post a timeout message to the app queue -// -static void handle_expired_timers(timer_ctx_t ctx, app_timer_t * expired) +/** + * lookup the app queue by the module name + * post a timeout message to the app queue + */ +static void +handle_expired_timers(timer_ctx_t ctx, app_timer_t *expired) { while (expired) { - app_timer_t * t = expired; + app_timer_t *t = expired; ctx->timer_callback(t->id, ctx->owner); + /* get next expired timer first, since the following + operation may change expired->next */ expired = expired->next; if (t->is_periodic) { - // if it is repeating, then reschedule it; + /* if it is repeating, then reschedule it; */ reschedule_timer(ctx, t); - } else { - // else move it to idle list + } + else { + /* else move it to idle list */ add_idle_timer(ctx, t); } } } -int get_expiry_ms(timer_ctx_t ctx) +uint32 +get_expiry_ms(timer_ctx_t ctx) { - int ms_to_next_expiry; + uint32 ms_to_next_expiry; uint64 now = bh_get_tick_ms(); os_mutex_lock(&ctx->mutex); - if (ctx->g_app_timers == NULL) - ms_to_next_expiry = 7 * 24 * 60 * 60 * 1000; // 1 week - else if (ctx->g_app_timers->expiry >= now) - ms_to_next_expiry = (int)(ctx->g_app_timers->expiry - now); + if (ctx->app_timers == NULL) + ms_to_next_expiry = (uint32)-1; + else if (ctx->app_timers->expiry >= now) + ms_to_next_expiry = (uint32)(ctx->app_timers->expiry - now); else ms_to_next_expiry = 0; os_mutex_unlock(&ctx->mutex); @@ -391,39 +423,40 @@ int get_expiry_ms(timer_ctx_t ctx) return ms_to_next_expiry; } -int check_app_timers(timer_ctx_t ctx) +int +check_app_timers(timer_ctx_t ctx) { - os_mutex_lock(&ctx->mutex); - - app_timer_t * t = ctx->g_app_timers; - app_timer_t * expired = NULL; - + app_timer_t *t, *expired = NULL; uint64 now = bh_get_tick_ms(); + os_mutex_lock(&ctx->mutex); + + t = ctx->app_timers; while (t) { if (now >= t->expiry) { - ctx->g_app_timers = t->next; + ctx->app_timers = t->next; t->next = expired; expired = t; - t = ctx->g_app_timers; - } else { + t = ctx->app_timers; + } + else { break; } } os_mutex_unlock(&ctx->mutex); handle_expired_timers(ctx, expired); - return get_expiry_ms(ctx); } -void cleanup_app_timers(timer_ctx_t ctx) +void +cleanup_app_timers(timer_ctx_t ctx) { os_mutex_lock(&ctx->mutex); - release_timer_list(&ctx->g_app_timers); + release_timer_list(&ctx->app_timers); release_timer_list(&ctx->idle_timers); os_mutex_unlock(&ctx->mutex); diff --git a/core/shared/utils/runtime_timer.h b/core/shared/utils/runtime_timer.h index 8e8cc59ef..e54105c5e 100644 --- a/core/shared/utils/runtime_timer.h +++ b/core/shared/utils/runtime_timer.h @@ -33,7 +33,7 @@ bool sys_timer_cancel(timer_ctx_t ctx, uint32 timer_id); bool sys_timer_restart(timer_ctx_t ctx, uint32 timer_id, int interval); void cleanup_app_timers(timer_ctx_t ctx); int check_app_timers(timer_ctx_t ctx); -int get_expiry_ms(timer_ctx_t ctx); +uint32 get_expiry_ms(timer_ctx_t ctx); #ifdef __cplusplus } From a84d51271cc7e320a35aa74b11e771ea2a107b21 Mon Sep 17 00:00:00 2001 From: Xu Jun <693788454@qq.com> Date: Mon, 7 Dec 2020 16:37:49 +0800 Subject: [PATCH 120/207] Support AssemblyScript's new/retain/release APIs (#460) --- .clang-format | 3 +- assembly-script/package-lock.json | 16 +++--- assembly-script/package.json | 12 ++-- core/iwasm/aot/aot_loader.c | 64 ++++++++++++++++++++-- core/iwasm/aot/aot_runtime.c | 57 ++++++++++++++++--- core/iwasm/aot/aot_runtime.h | 1 + core/iwasm/compilation/aot.c | 1 + core/iwasm/compilation/aot.h | 1 + core/iwasm/interpreter/wasm.h | 4 ++ core/iwasm/interpreter/wasm_loader.c | 67 +++++++++++++++++++++-- core/iwasm/interpreter/wasm_mini_loader.c | 66 ++++++++++++++++++++-- core/iwasm/interpreter/wasm_runtime.c | 31 ++++++++++- core/iwasm/interpreter/wasm_runtime.h | 1 + 13 files changed, 282 insertions(+), 42 deletions(-) diff --git a/.clang-format b/.clang-format index aa4cde60a..f0ecd63bf 100644 --- a/.clang-format +++ b/.clang-format @@ -44,7 +44,7 @@ BinPackParameters: false BreakBeforeBinaryOperators: NonAssignment BreakBeforeBraces: Custom BraceWrapping: - AfterCaseLabel: false + AfterCaseLabel: true AfterClass: true AfterControlStatement: false AfterEnum: false @@ -76,6 +76,7 @@ KeepEmptyLinesAtTheStartOfBlocks: false NamespaceIndentation: None PointerAlignment: Right ReflowComments: false +SortIncludes: false Standard: Auto StatementMacros: - Q_UNUSED diff --git a/assembly-script/package-lock.json b/assembly-script/package-lock.json index 97d4e290c..0750cc05e 100644 --- a/assembly-script/package-lock.json +++ b/assembly-script/package-lock.json @@ -5,24 +5,24 @@ "requires": true, "dependencies": { "assemblyscript": { - "version": "0.8.1", - "resolved": "https://registry.npm.taobao.org/assemblyscript/download/assemblyscript-0.8.1.tgz", - "integrity": "sha1-xcYnSSQG5th/QmiXs9kr0qUz9/4=", + "version": "0.17.4", + "resolved": "https://registry.npm.taobao.org/assemblyscript/download/assemblyscript-0.17.4.tgz", + "integrity": "sha1-1GEduJpClDNa1H7DxmYaJqRCh3E=", "dev": true, "requires": { - "binaryen": "89.0.0-nightly.20191113", + "binaryen": "98.0.0-nightly.20201109", "long": "^4.0.0" } }, "binaryen": { - "version": "89.0.0-nightly.20191113", - "resolved": "https://registry.npm.taobao.org/binaryen/download/binaryen-89.0.0-nightly.20191113.tgz", - "integrity": "sha1-oNORTzXJKXhzQeApELf/rrfYl6k=", + "version": "98.0.0-nightly.20201109", + "resolved": "https://registry.npm.taobao.org/binaryen/download/binaryen-98.0.0-nightly.20201109.tgz", + "integrity": "sha1-USv2yhXGe/dAIURzSkg25jmTqgU=", "dev": true }, "long": { "version": "4.0.0", - "resolved": "https://registry.npm.taobao.org/long/download/long-4.0.0.tgz", + "resolved": "https://registry.npm.taobao.org/long/download/long-4.0.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flong%2Fdownload%2Flong-4.0.0.tgz", "integrity": "sha1-mntxz7fTYaGU6lVSQckvdGjVvyg=", "dev": true } diff --git a/assembly-script/package.json b/assembly-script/package.json index 00aaaaf97..56a64f3d2 100644 --- a/assembly-script/package.json +++ b/assembly-script/package.json @@ -5,16 +5,16 @@ "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", - "build:request_handler": "asc samples/request_handler.ts -b build/request_handler.wasm -t build/request_handler.wat --sourceMap --validate --optimize --use abort=", - "build:request_sender": "asc samples/request_sender.ts -b build/request_sender.wasm -t build/request_sender.wat --sourceMap --validate --optimize --use abort=", - "build:timer": "asc samples/timer.ts -b build/timer.wasm -t build/timer.wat --sourceMap --validate --optimize --use abort=", - "build:publisher": "asc samples/event_publisher.ts -b build/event_publisher.wasm -t build/event_publisher.wat --sourceMap --validate --optimize --use abort=", - "build:subscriber": "asc samples/event_subscriber.ts -b build/event_subscriber.wasm -t build/event_subscriber.wat --sourceMap --validate --optimize --use abort=", + "build:request_handler": "asc samples/request_handler.ts -b build/request_handler.wasm -t build/request_handler.wat --sourceMap --optimize --use abort=", + "build:request_sender": "asc samples/request_sender.ts -b build/request_sender.wasm -t build/request_sender.wat --sourceMap --optimize --use abort=", + "build:timer": "asc samples/timer.ts -b build/timer.wasm -t build/timer.wat --sourceMap --optimize --use abort=", + "build:publisher": "asc samples/event_publisher.ts -b build/event_publisher.wasm -t build/event_publisher.wat --sourceMap --optimize --use abort=", + "build:subscriber": "asc samples/event_subscriber.ts -b build/event_subscriber.wasm -t build/event_subscriber.wat --sourceMap --optimize --use abort=", "build:all": "npm run build:request_handler; npm run build:request_sender; npm run build:timer; npm run build:subscriber; npm run build:publisher" }, "author": "", "license": "ISC", "devDependencies": { - "assemblyscript": "^0.8.1" + "assemblyscript": "^0.17.4" } } diff --git a/core/iwasm/aot/aot_loader.c b/core/iwasm/aot/aot_loader.c index 5bf2453dc..5493b0c7b 100644 --- a/core/iwasm/aot/aot_loader.c +++ b/core/iwasm/aot/aot_loader.c @@ -1681,6 +1681,7 @@ load_from_sections(AOTModule *module, AOTSection *sections, /* Resolve malloc and free function */ module->malloc_func_index = (uint32)-1; module->free_func_index = (uint32)-1; + module->retain_func_index = (uint32)-1; exports = module->exports; for (i = 0; i < module->export_count; i++) { @@ -1694,21 +1695,73 @@ load_from_sections(AOTModule *module, AOTSection *sections, && func_type->result_count == 1 && func_type->types[0] == VALUE_TYPE_I32 && func_type->types[1] == VALUE_TYPE_I32) { + bh_assert(module->malloc_func_index == (uint32)-1); module->malloc_func_index = func_index; - LOG_VERBOSE("Found malloc function, index: %u", - exports[i].index); + LOG_VERBOSE("Found malloc function, name: %s, index: %u", + exports[i].name, exports[i].index); } } - else if (!strcmp(exports[i].name, "free")) { + else if (!strcmp(exports[i].name, "__new")) { + func_index = exports[i].index - module->import_func_count; + func_type_index = module->func_type_indexes[func_index]; + func_type = module->func_types[func_type_index]; + if (func_type->param_count == 2 + && func_type->result_count == 1 + && func_type->types[0] == VALUE_TYPE_I32 + && func_type->types[1] == VALUE_TYPE_I32 + && func_type->types[2] == VALUE_TYPE_I32) { + uint32 j; + WASMExport *export_tmp; + + bh_assert(module->malloc_func_index == (uint32)-1); + module->malloc_func_index = func_index; + LOG_VERBOSE("Found malloc function, name: %s, index: %u", + exports[i].name, exports[i].index); + + /* resolve retain function. + If not find, reset malloc function index */ + export_tmp = module->exports; + for (j = 0; j < module->export_count; j++, export_tmp++) { + if ((export_tmp->kind == EXPORT_KIND_FUNC) + && (!strcmp(export_tmp->name, "__retain"))) { + func_index = export_tmp->index + - module->import_func_count; + func_type_index = + module->func_type_indexes[func_index]; + func_type = module->func_types[func_type_index]; + if (func_type->param_count == 1 + && func_type->result_count == 1 + && func_type->types[0] == VALUE_TYPE_I32 + && func_type->types[1] == VALUE_TYPE_I32) { + bh_assert( + module->retain_func_index == (uint32)-1); + module->retain_func_index = export_tmp->index; + LOG_VERBOSE( + "Found retain function, name: %s, index: %u", + export_tmp->name, export_tmp->index); + break; + } + } + } + if (j == module->export_count) { + module->malloc_func_index = (uint32)-1; + LOG_VERBOSE("Can't find retain function," + "reset malloc function index to -1"); + } + } + } + else if ((!strcmp(exports[i].name, "free")) + || (!strcmp(exports[i].name, "__release"))) { func_index = exports[i].index - module->import_func_count; func_type_index = module->func_type_indexes[func_index]; func_type = module->func_types[func_type_index]; if (func_type->param_count == 1 && func_type->result_count == 0 && func_type->types[0] == VALUE_TYPE_I32) { + bh_assert(module->free_func_index == (uint32)-1); module->free_func_index = func_index; - LOG_VERBOSE("Found free function, index: %u", - exports[i].index); + LOG_VERBOSE("Found free function, name: %s, index: %u", + exports[i].name, exports[i].index); } } } @@ -2057,6 +2110,7 @@ aot_load_from_comp_data(AOTCompData *comp_data, AOTCompContext *comp_ctx, module->malloc_func_index = comp_data->malloc_func_index; module->free_func_index = comp_data->free_func_index; + module->retain_func_index = comp_data->retain_func_index; module->aux_data_end_global_index = comp_data->aux_data_end_global_index; module->aux_data_end = comp_data->aux_data_end; diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index d6db2d511..323945183 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -1263,23 +1263,39 @@ aot_clear_exception(AOTModuleInstance *module_inst) static bool execute_malloc_function(AOTModuleInstance *module_inst, AOTFunctionInstance *malloc_func, + AOTFunctionInstance *retain_func, uint32 size, uint32 *p_result) { - uint32 argv[2]; + uint32 argv[2], argc; bool ret; argv[0] = size; + argc = 1; + if (retain_func) { + argv[1] = 0; + argc = 2; + } + #ifdef OS_ENABLE_HW_BOUND_CHECK if (aot_exec_env != NULL) { bh_assert(aot_exec_env->module_inst == (WASMModuleInstanceCommon *)module_inst); - ret = aot_call_function(aot_exec_env, malloc_func, 1, argv); + ret = aot_call_function(aot_exec_env, malloc_func, argc, argv); + + if (retain_func && ret) { + ret = aot_call_function(aot_exec_env, retain_func, 1, argv); + } } else #endif { ret = aot_create_exec_env_and_call_function - (module_inst, malloc_func, 1, argv); + (module_inst, malloc_func, argc, argv); + + if (retain_func && ret) { + ret = aot_create_exec_env_and_call_function + (module_inst, retain_func, 1, argv); + } } if (ret) @@ -1328,11 +1344,27 @@ aot_module_malloc(AOTModuleInstance *module_inst, uint32 size, } else if (module->malloc_func_index != (uint32)-1 && module->free_func_index != (uint32)-1) { - AOTFunctionInstance *malloc_func = - aot_lookup_function(module_inst, "malloc", "(i)i"); + AOTFunctionInstance *malloc_func, *retain_func = NULL; + char *malloc_func_name; + char *malloc_func_sig; + + if (module->retain_func_index != (uint32)-1) { + malloc_func_name = "__new"; + malloc_func_sig = "(ii)i"; + retain_func = + aot_lookup_function(module_inst, "__retain", "(i)i"); + bh_assert(retain_func); + } + else { + malloc_func_name = "malloc"; + malloc_func_sig = "(i)i"; + } + malloc_func = + aot_lookup_function(module_inst, + malloc_func_name, malloc_func_sig); bh_assert(malloc_func); - if (!execute_malloc_function(module_inst, malloc_func, + if (!execute_malloc_function(module_inst, malloc_func, retain_func, size, &offset)) { return 0; } @@ -1371,8 +1403,17 @@ aot_module_free(AOTModuleInstance *module_inst, uint32 ptr) && module->free_func_index != (uint32)-1 && (uint8 *)memory_inst->memory_data.ptr <= addr && addr < (uint8 *)memory_inst->memory_data_end.ptr) { - AOTFunctionInstance *free_func = - aot_lookup_function(module_inst, "free", "(i)i"); + AOTFunctionInstance *free_func; + char *free_func_name; + + if (module->retain_func_index != (uint32)-1) { + free_func_name = "__release"; + } + else { + free_func_name = "free"; + } + free_func = + aot_lookup_function(module_inst, free_func_name, "(i)i"); bh_assert(free_func); execute_free_function(module_inst, free_func, ptr); diff --git a/core/iwasm/aot/aot_runtime.h b/core/iwasm/aot/aot_runtime.h index 2fa721587..87dc11662 100644 --- a/core/iwasm/aot/aot_runtime.h +++ b/core/iwasm/aot/aot_runtime.h @@ -149,6 +149,7 @@ typedef struct AOTModule { uint32 malloc_func_index; uint32 free_func_index; + uint32 retain_func_index; /* AOTed code, NULL for JIT mode */ void *code; diff --git a/core/iwasm/compilation/aot.c b/core/iwasm/compilation/aot.c index 5e85cc1fa..fd127c817 100644 --- a/core/iwasm/compilation/aot.c +++ b/core/iwasm/compilation/aot.c @@ -512,6 +512,7 @@ aot_create_comp_data(WASMModule *module) 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->retain_func_index = module->retain_function; comp_data->wasm_module = module; diff --git a/core/iwasm/compilation/aot.h b/core/iwasm/compilation/aot.h index a898ad04c..633792360 100644 --- a/core/iwasm/compilation/aot.h +++ b/core/iwasm/compilation/aot.h @@ -206,6 +206,7 @@ typedef struct AOTCompData { uint32 start_func_index; uint32 malloc_func_index; uint32 free_func_index; + uint32 retain_func_index; uint32 aux_data_end_global_index; uint32 aux_data_end; diff --git a/core/iwasm/interpreter/wasm.h b/core/iwasm/interpreter/wasm.h index 040b33128..feae8effe 100644 --- a/core/iwasm/interpreter/wasm.h +++ b/core/iwasm/interpreter/wasm.h @@ -371,6 +371,10 @@ struct WASMModule { uint32 malloc_function; uint32 free_function; + /* the index of __retain function, + -1 means unexported */ + uint32 retain_function; + /* Whether there is possible memory grow, e.g. memory.grow opcode */ bool possible_memory_grow; diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index f4b71805f..5ba092575 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -2762,8 +2762,9 @@ load_from_sections(WASMModule *module, WASMSection *sections, module->malloc_function = (uint32)-1; module->free_function = (uint32)-1; + module->retain_function = (uint32)-1; - /* Resolve auxiliary data/stack/heap info and reset memory info */ + /* Resolve malloc/free function exported by wasm module */ export = module->exports; for (i = 0; i < module->export_count; i++, export++) { if (export->kind == EXPORT_KIND_FUNC) { @@ -2775,21 +2776,75 @@ load_from_sections(WASMModule *module, WASMSection *sections, && func_type->result_count == 1 && func_type->types[0] == VALUE_TYPE_I32 && func_type->types[1] == VALUE_TYPE_I32) { + bh_assert(module->malloc_function == (uint32)-1); module->malloc_function = export->index; - LOG_VERBOSE("Found malloc function, index: %u", - export->index); + LOG_VERBOSE("Found malloc function, name: %s, index: %u", + export->name, export->index); } } - else if (!strcmp(export->name, "free") + else if (!strcmp(export->name, "__new") + && export->index >= module->import_function_count) { + /* __new && __retain for AssemblyScript */ + func_index = export->index - module->import_function_count; + func_type = module->functions[func_index]->func_type; + if (func_type->param_count == 2 + && func_type->result_count == 1 + && func_type->types[0] == VALUE_TYPE_I32 + && func_type->types[1] == VALUE_TYPE_I32 + && func_type->types[2] == VALUE_TYPE_I32) { + uint32 j; + WASMExport *export_tmp; + + bh_assert(module->malloc_function == (uint32)-1); + module->malloc_function = export->index; + LOG_VERBOSE("Found malloc function, name: %s, index: %u", + export->name, export->index); + + /* resolve retain function. + If not find, reset malloc function index */ + export_tmp = module->exports; + for (j = 0; j < module->export_count; j++, export_tmp++) { + if ((export_tmp->kind == EXPORT_KIND_FUNC) + && (!strcmp(export_tmp->name, "__retain")) + && (export_tmp->index + >= module->import_function_count)) { + func_index = export_tmp->index + - module->import_function_count; + func_type = + module->functions[func_index]->func_type; + if (func_type->param_count == 1 + && func_type->result_count == 1 + && func_type->types[0] == VALUE_TYPE_I32 + && func_type->types[1] == VALUE_TYPE_I32) { + bh_assert( + module->retain_function == (uint32)-1); + module->retain_function = export_tmp->index; + LOG_VERBOSE( + "Found retain function, name: %s, index: %u", + export_tmp->name, export_tmp->index); + break; + } + } + } + if (j == module->export_count) { + module->malloc_function = (uint32)-1; + LOG_VERBOSE("Can't find retain function," + "reset malloc function index to -1"); + } + } + } + else if (((!strcmp(export->name, "free")) + || (!strcmp(export->name, "__release"))) && export->index >= module->import_function_count) { func_index = export->index - module->import_function_count; func_type = module->functions[func_index]->func_type; if (func_type->param_count == 1 && func_type->result_count == 0 && func_type->types[0] == VALUE_TYPE_I32) { + bh_assert(module->free_function == (uint32)-1); module->free_function = export->index; - LOG_VERBOSE("Found free function, index: %u", - export->index); + LOG_VERBOSE("Found free function, name: %s, index: %u", + export->name, export->index); } } } diff --git a/core/iwasm/interpreter/wasm_mini_loader.c b/core/iwasm/interpreter/wasm_mini_loader.c index d25a310fe..cb1222a4f 100644 --- a/core/iwasm/interpreter/wasm_mini_loader.c +++ b/core/iwasm/interpreter/wasm_mini_loader.c @@ -1701,7 +1701,7 @@ load_from_sections(WASMModule *module, WASMSection *sections, module->malloc_function = (uint32)-1; module->free_function = (uint32)-1; - /* Resolve auxiliary data/stack/heap info and reset memory info */ + /* Resolve malloc/free function exported by wasm module */ export = module->exports; for (i = 0; i < module->export_count; i++, export++) { if (export->kind == EXPORT_KIND_FUNC) { @@ -1713,21 +1713,75 @@ load_from_sections(WASMModule *module, WASMSection *sections, && func_type->result_count == 1 && func_type->types[0] == VALUE_TYPE_I32 && func_type->types[1] == VALUE_TYPE_I32) { + bh_assert(module->malloc_function == (uint32)-1); module->malloc_function = export->index; - LOG_VERBOSE("Found malloc function, index: %u", - export->index); + LOG_VERBOSE("Found malloc function, name: %s, index: %u", + export->name, export->index); } } - else if (!strcmp(export->name, "free") + else if (!strcmp(export->name, "__new") + && export->index >= module->import_function_count) { + /* __new && __retain for AssemblyScript */ + func_index = export->index - module->import_function_count; + func_type = module->functions[func_index]->func_type; + if (func_type->param_count == 2 + && func_type->result_count == 1 + && func_type->types[0] == VALUE_TYPE_I32 + && func_type->types[1] == VALUE_TYPE_I32 + && func_type->types[2] == VALUE_TYPE_I32) { + uint32 j; + WASMExport *export_tmp; + + bh_assert(module->malloc_function == (uint32)-1); + module->malloc_function = export->index; + LOG_VERBOSE("Found malloc function, name: %s, index: %u", + export->name, export->index); + + /* resolve retain function. + If not find, reset malloc function index */ + export_tmp = module->exports; + for (j = 0; j < module->export_count; j++, export_tmp++) { + if ((export_tmp->kind == EXPORT_KIND_FUNC) + && (!strcmp(export_tmp->name, "__retain")) + && (export_tmp->index + >= module->import_function_count)) { + func_index = export_tmp->index + - module->import_function_count; + func_type = + module->functions[func_index]->func_type; + if (func_type->param_count == 1 + && func_type->result_count == 1 + && func_type->types[0] == VALUE_TYPE_I32 + && func_type->types[1] == VALUE_TYPE_I32) { + bh_assert( + module->retain_function == (uint32)-1); + module->retain_function = export_tmp->index; + LOG_VERBOSE( + "Found retain function, name: %s, index: %u", + export_tmp->name, export_tmp->index); + break; + } + } + } + if (j == module->export_count) { + module->malloc_function = (uint32)-1; + LOG_VERBOSE("Can't find retain function," + "reset malloc function index to -1"); + } + } + } + else if (((!strcmp(export->name, "free")) + || (!strcmp(export->name, "__release"))) && export->index >= module->import_function_count) { func_index = export->index - module->import_function_count; func_type = module->functions[func_index]->func_type; if (func_type->param_count == 1 && func_type->result_count == 0 && func_type->types[0] == VALUE_TYPE_I32) { + bh_assert(module->free_function == (uint32)-1); module->free_function = export->index; - LOG_VERBOSE("Found free function, index: %u", - export->index); + LOG_VERBOSE("Found free function, name: %s, index: %u", + export->name, export->index); } } } diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index 7f32b5ae3..f6382f609 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -970,14 +970,35 @@ execute_start_function(WASMModuleInstance *module_inst) static bool execute_malloc_function(WASMModuleInstance *module_inst, WASMFunctionInstance *malloc_func, + WASMFunctionInstance *retain_func, uint32 size, uint32 *p_result) { - uint32 argv[2]; + uint32 argv[2], argc; bool ret; argv[0] = size; + argc = 1; + + /* if __retain is exported, then this module is compiled by + assemblyscript, the memory should be managed by as's runtime, + in this case we need to call the retain function after malloc + the memory */ + if (retain_func) { + /* the malloc functino from assemblyscript is: + function __new(size: usize, id: u32) + id = 0 means this is an ArrayBuffer object */ + argv[1] = 0; + argc = 2; + } + ret = wasm_create_exec_env_and_call_function - (module_inst, malloc_func, 1, argv); + (module_inst, malloc_func, argc, argv); + + if (retain_func && ret) { + ret = wasm_create_exec_env_and_call_function + (module_inst, retain_func, 1, argv); + } + if (ret) *p_result = argv[0]; return ret; @@ -1409,6 +1430,11 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, &module_inst->functions[module->free_function]; } + if (module->retain_function != (uint32)-1) { + module_inst->retain_function = + &module_inst->functions[module->retain_function]; + } + #if WASM_ENABLE_LIBC_WASI != 0 /* The sub-instance will get the wasi_ctx from main-instance */ if (!is_sub_inst) { @@ -1651,6 +1677,7 @@ wasm_module_malloc(WASMModuleInstance *module_inst, uint32 size, && module_inst->free_function) { if (!execute_malloc_function(module_inst, module_inst->malloc_function, + module_inst->retain_function, size, &offset)) { return 0; } diff --git a/core/iwasm/interpreter/wasm_runtime.h b/core/iwasm/interpreter/wasm_runtime.h index 242d5f12f..4f13b689a 100644 --- a/core/iwasm/interpreter/wasm_runtime.h +++ b/core/iwasm/interpreter/wasm_runtime.h @@ -184,6 +184,7 @@ struct WASMModuleInstance { WASMFunctionInstance *start_function; WASMFunctionInstance *malloc_function; WASMFunctionInstance *free_function; + WASMFunctionInstance *retain_function; WASMModule *module; From 388530c738265b632a1d619f929cbfb34cecfbbb Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Mon, 7 Dec 2020 17:37:53 +0800 Subject: [PATCH 121/207] Modify os_cond_reltimedwait to support long time wait (#461) Modify the argument of os_cond_reltimedwait to uint64 type to support long time wait, and handle possible integer overflow. --- .../app-framework/base/native/timer_wrapper.c | 19 +++++---- .../lib-pthread/lib_pthread_wrapper.c | 6 +-- core/shared/platform/alios/alios_thread.c | 23 ++++++++--- .../common/freertos/freertos_thread.c | 21 ++++++++-- .../platform/common/posix/posix_thread.c | 41 +++++++++++++------ .../platform/include/platform_api_extension.h | 2 +- .../shared/platform/include/platform_common.h | 3 +- core/shared/platform/linux-sgx/sgx_thread.c | 2 +- core/shared/platform/riot/riot_thread.c | 5 +-- core/shared/platform/windows/win_thread.c | 2 +- core/shared/platform/zephyr/zephyr_thread.c | 21 ++++++++-- core/shared/utils/bh_queue.c | 8 ++-- core/shared/utils/bh_queue.h | 2 +- core/shared/utils/runtime_timer.c | 16 +++++--- core/shared/utils/runtime_timer.h | 2 +- .../libc-builtin-sysroot/include/pthread.h | 6 ++- 16 files changed, 121 insertions(+), 58 deletions(-) diff --git a/core/app-framework/base/native/timer_wrapper.c b/core/app-framework/base/native/timer_wrapper.c index 42b91a743..07aca8b41 100644 --- a/core/app-framework/base/native/timer_wrapper.c +++ b/core/app-framework/base/native/timer_wrapper.c @@ -42,17 +42,18 @@ wasm_timer_callback(timer_id_t id, unsigned int mod_id) void * thread_modulers_timer_check(void * arg) { - int ms_to_expiry; + uint32 ms_to_expiry; + uint64 us_to_wait; while (timer_thread_run) { - ms_to_expiry = -1; + ms_to_expiry = (uint32)-1; os_mutex_lock(&g_timer_ctx_list_mutex); timer_ctx_node_t* elem = (timer_ctx_node_t*) bh_list_first_elem(&g_timer_ctx_list); while (elem) { - int next = check_app_timers(elem->timer_ctx); - if (next != -1) { - if (ms_to_expiry == -1 || ms_to_expiry > next) + uint32 next = check_app_timers(elem->timer_ctx); + if (next != (uint32)-1) { + if (ms_to_expiry == (uint32)-1 || ms_to_expiry > next) ms_to_expiry = next; } @@ -60,11 +61,13 @@ void * thread_modulers_timer_check(void * arg) } os_mutex_unlock(&g_timer_ctx_list_mutex); - if (ms_to_expiry == -1) - ms_to_expiry = 60 * 1000; + if (ms_to_expiry == (uint32)-1) + us_to_wait = BHT_WAIT_FOREVER; + else + us_to_wait = (uint64)ms_to_expiry * 1000; os_mutex_lock(&g_timer_ctx_list_mutex); os_cond_reltimedwait(&g_timer_ctx_list_cond, &g_timer_ctx_list_mutex, - ms_to_expiry * 1000); + us_to_wait); os_mutex_unlock(&g_timer_ctx_list_mutex); } diff --git a/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c b/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c index a31691120..c0dcb9da9 100644 --- a/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c +++ b/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c @@ -848,7 +848,7 @@ pthread_cond_wait_wrapper(wasm_exec_env_t exec_env, uint32 *cond, uint32 *mutex) */ static int32 pthread_cond_timedwait_wrapper(wasm_exec_env_t exec_env, uint32 *cond, - uint32 *mutex, uint32 useconds) + uint32 *mutex, uint64 useconds) { ThreadInfoNode *cond_info_node, *mutex_info_node; @@ -1014,7 +1014,7 @@ static NativeSymbol native_symbols_lib_pthread[] = { REG_NATIVE_FUNC(pthread_mutex_destroy, "(*)i"), REG_NATIVE_FUNC(pthread_cond_init, "(**)i"), REG_NATIVE_FUNC(pthread_cond_wait, "(**)i"), - REG_NATIVE_FUNC(pthread_cond_timedwait, "(**i)i"), + REG_NATIVE_FUNC(pthread_cond_timedwait, "(**I)i"), REG_NATIVE_FUNC(pthread_cond_signal, "(*)i"), REG_NATIVE_FUNC(pthread_cond_destroy, "(*)i"), REG_NATIVE_FUNC(pthread_key_create, "(*i)i"), @@ -1028,4 +1028,4 @@ get_lib_pthread_export_apis(NativeSymbol **p_lib_pthread_apis) { *p_lib_pthread_apis = native_symbols_lib_pthread; return sizeof(native_symbols_lib_pthread) / sizeof(NativeSymbol); -} \ No newline at end of file +} diff --git a/core/shared/platform/alios/alios_thread.c b/core/shared/platform/alios/alios_thread.c index f4028fbf3..f6165bd99 100644 --- a/core/shared/platform/alios/alios_thread.c +++ b/core/shared/platform/alios/alios_thread.c @@ -273,7 +273,7 @@ os_cond_destroy(korp_cond *cond) static int os_cond_wait_internal(korp_cond *cond, korp_mutex *mutex, - bool timed, int mills) + bool timed, uint32 mills) { os_thread_wait_node *node = &thread_data_current()->wait_node; @@ -319,12 +319,25 @@ os_cond_wait(korp_cond *cond, korp_mutex *mutex) } int -os_cond_reltimedwait(korp_cond *cond, korp_mutex *mutex, int useconds) +os_cond_reltimedwait(korp_cond *cond, korp_mutex *mutex, uint64 useconds) { - if (useconds == BHT_WAIT_FOREVER) + if (useconds == BHT_WAIT_FOREVER) { return os_cond_wait_internal(cond, mutex, false, 0); - else - return os_cond_wait_internal(cond, mutex, true, useconds / 1000); + } + else { + uint64 mills_64 = useconds / 1000; + uint32 mills; + + if (mills_64 < (uint64)(UINT32_MAX - 1)) { + mills = (uint64)mills_64; + } + else { + mills = UINT32_MAX - 1; + os_printf("Warning: os_cond_reltimedwait exceeds limit, " + "set to max timeout instead\n"); + } + return os_cond_wait_internal(cond, mutex, true, mills); + } } int diff --git a/core/shared/platform/common/freertos/freertos_thread.c b/core/shared/platform/common/freertos/freertos_thread.c index 78643419a..9b9dbea05 100644 --- a/core/shared/platform/common/freertos/freertos_thread.c +++ b/core/shared/platform/common/freertos/freertos_thread.c @@ -404,12 +404,25 @@ int os_cond_wait(korp_cond *cond, korp_mutex *mutex) return os_cond_wait_internal(cond, mutex, false, 0); } -int os_cond_reltimedwait(korp_cond *cond, korp_mutex *mutex, int useconds) +int os_cond_reltimedwait(korp_cond *cond, korp_mutex *mutex, uint64 useconds) { - if (useconds == BHT_WAIT_FOREVER) + if (useconds == BHT_WAIT_FOREVER) { return os_cond_wait_internal(cond, mutex, false, 0); - else - return os_cond_wait_internal(cond, mutex, true, useconds / 1000); + } + else { + uint64 mills_64 = useconds / 1000; + int32 mills; + + if (mills_64 < (uint64)INT32_MAX) { + mills = (int32)mills_64; + } + else { + mills = INT32_MAX; + os_printf("Warning: os_cond_reltimedwait exceeds limit, " + "set to max timeout instead\n"); + } + return os_cond_wait_internal(cond, mutex, true, mills); + } } int os_cond_signal(korp_cond *cond) diff --git a/core/shared/platform/common/posix/posix_thread.c b/core/shared/platform/common/posix/posix_thread.c index 39c12b8c8..a7662f4e4 100644 --- a/core/shared/platform/common/posix/posix_thread.c +++ b/core/shared/platform/common/posix/posix_thread.c @@ -163,27 +163,48 @@ int os_cond_wait(korp_cond *cond, korp_mutex *mutex) return BHT_OK; } -static void msec_nsec_to_abstime(struct timespec *ts, int usec) +static void msec_nsec_to_abstime(struct timespec *ts, uint64 usec) { struct timeval tv; + long int tv_sec_new, tv_nsec_new; gettimeofday(&tv, NULL); - ts->tv_sec = (long int)(tv.tv_sec + usec / 1000000); - ts->tv_nsec = (long int)(tv.tv_usec * 1000 + (usec % 1000000) * 1000); + tv_sec_new = (long int)(tv.tv_sec + usec / 1000000); + if (tv_sec_new >= tv.tv_sec) { + ts->tv_sec = tv_sec_new; + } + else { + /* integer overflow */ + ts->tv_sec = LONG_MAX; + os_printf("Warning: os_cond_reltimedwait exceeds limit, " + "set to max timeout instead\n"); + } - if (ts->tv_nsec >= 1000000000L) { + tv_nsec_new = (long int)(tv.tv_usec * 1000 + (usec % 1000000) * 1000); + if (tv.tv_usec * 1000 >= tv.tv_usec + && tv_nsec_new >= tv.tv_usec * 1000) { + ts->tv_nsec = tv_nsec_new; + } + else { + /* integer overflow */ + ts->tv_nsec = LONG_MAX; + os_printf("Warning: os_cond_reltimedwait exceeds limit, " + "set to max timeout instead\n"); + } + + if (ts->tv_nsec >= 1000000000L && ts->tv_sec < LONG_MAX) { ts->tv_sec++; ts->tv_nsec -= 1000000000L; } } -int os_cond_reltimedwait(korp_cond *cond, korp_mutex *mutex, int useconds) +int os_cond_reltimedwait(korp_cond *cond, korp_mutex *mutex, uint64 useconds) { int ret; struct timespec abstime; - if (useconds == (int)BHT_WAIT_FOREVER) + if (useconds == BHT_WAIT_FOREVER) ret = pthread_cond_wait(cond, mutex); else { msec_nsec_to_abstime(&abstime, useconds); @@ -290,7 +311,6 @@ mask_signals(int how) __attribute__((noreturn)) static void signal_callback(int sig_num, siginfo_t *sig_info, void *sig_ucontext) { - int i; void *sig_addr = sig_info->si_addr; mask_signals(SIG_BLOCK); @@ -314,12 +334,7 @@ signal_callback(int sig_num, siginfo_t *sig_info, void *sig_ucontext) break; } - /* divived by 0 to make it abort */ - i = os_printf(" "); - os_printf("%d\n", i / (i - 1)); - /* access NULL ptr to make it abort */ - os_printf("%d\n", *(uint32*)(uintptr_t)(i - 1)); - exit(1); + abort(); } int diff --git a/core/shared/platform/include/platform_api_extension.h b/core/shared/platform/include/platform_api_extension.h index 55cd9c99c..5239929d0 100644 --- a/core/shared/platform/include/platform_api_extension.h +++ b/core/shared/platform/include/platform_api_extension.h @@ -138,7 +138,7 @@ int os_cond_wait(korp_cond *cond, korp_mutex *mutex); * * @return 0 if success */ -int os_cond_reltimedwait(korp_cond *cond, korp_mutex *mutex, int useconds); +int os_cond_reltimedwait(korp_cond *cond, korp_mutex *mutex, uint64 useconds); /** * Signals the condition variable diff --git a/core/shared/platform/include/platform_common.h b/core/shared/platform/include/platform_common.h index 02d71fc68..57b20912b 100644 --- a/core/shared/platform/include/platform_common.h +++ b/core/shared/platform/include/platform_common.h @@ -19,8 +19,7 @@ extern "C" { #define BHT_TIMED_OUT (1) #define BHT_OK (0) -#define BHT_NO_WAIT 0x00000000 -#define BHT_WAIT_FOREVER 0xFFFFFFFF +#define BHT_WAIT_FOREVER ((uint64)-1LL) #define BH_KB (1024) #define BH_MB ((BH_KB)*1024) diff --git a/core/shared/platform/linux-sgx/sgx_thread.c b/core/shared/platform/linux-sgx/sgx_thread.c index 5616a6ad5..d1503b47c 100644 --- a/core/shared/platform/linux-sgx/sgx_thread.c +++ b/core/shared/platform/linux-sgx/sgx_thread.c @@ -129,7 +129,7 @@ int os_cond_wait(korp_cond *cond, korp_mutex *mutex) return BHT_OK; } -int os_cond_reltimedwait(korp_cond *cond, korp_mutex *mutex, int useconds) +int os_cond_reltimedwait(korp_cond *cond, korp_mutex *mutex, uint64 useconds) { os_printf("warning: SGX pthread_cond_timedwait isn't supported, " "calling pthread_cond_wait instead!\n"); diff --git a/core/shared/platform/riot/riot_thread.c b/core/shared/platform/riot/riot_thread.c index 75576114f..e324a9d05 100644 --- a/core/shared/platform/riot/riot_thread.c +++ b/core/shared/platform/riot/riot_thread.c @@ -399,11 +399,10 @@ os_cond_wait(korp_cond *cond, korp_mutex *mutex) } int -os_cond_reltimedwait(korp_cond *cond, korp_mutex *mutex, int useconds) +os_cond_reltimedwait(korp_cond *cond, korp_mutex *mutex, uint64 useconds) { - uint64 useconds64 = (uint64) useconds; return os_cond_wait_internal(cond, mutex, - (useconds64 != BHT_WAIT_FOREVER), useconds64); + (useconds != BHT_WAIT_FOREVER), useconds); } int diff --git a/core/shared/platform/windows/win_thread.c b/core/shared/platform/windows/win_thread.c index a2f4a4d45..ed2b598e5 100644 --- a/core/shared/platform/windows/win_thread.c +++ b/core/shared/platform/windows/win_thread.c @@ -125,7 +125,7 @@ static void msec_nsec_to_abstime(struct timespec *ts, int usec) } } -int os_cond_reltimedwait(korp_cond *cond, korp_mutex *mutex, int useconds) +int os_cond_reltimedwait(korp_cond *cond, korp_mutex *mutex, uint64 useconds) { return BHT_OK; } diff --git a/core/shared/platform/zephyr/zephyr_thread.c b/core/shared/platform/zephyr/zephyr_thread.c index 56032f97d..69dc092e8 100644 --- a/core/shared/platform/zephyr/zephyr_thread.c +++ b/core/shared/platform/zephyr/zephyr_thread.c @@ -420,13 +420,26 @@ int os_cond_wait(korp_cond *cond, korp_mutex *mutex) return os_cond_wait_internal(cond, mutex, false, 0); } -int os_cond_reltimedwait(korp_cond *cond, korp_mutex *mutex, int useconds) +int os_cond_reltimedwait(korp_cond *cond, korp_mutex *mutex, uint64 useconds) { - if (useconds == BHT_WAIT_FOREVER) + if (useconds == BHT_WAIT_FOREVER) { return os_cond_wait_internal(cond, mutex, false, 0); - else - return os_cond_wait_internal(cond, mutex, true, useconds / 1000); + } + else { + uint64 mills_64 = useconds / 1000; + int32 mills; + + if (mills_64 < (uint64)INT32_MAX) { + mills = (int32)mills_64; + } + else { + mills = INT32_MAX; + os_printf("Warning: os_cond_reltimedwait exceeds limit, " + "set to max timeout instead\n"); + } + return os_cond_wait_internal(cond, mutex, true, mills); + } } int os_cond_signal(korp_cond *cond) diff --git a/core/shared/utils/bh_queue.c b/core/shared/utils/bh_queue.c index 60d873605..602c2cdfb 100644 --- a/core/shared/utils/bh_queue.c +++ b/core/shared/utils/bh_queue.c @@ -171,7 +171,7 @@ void bh_free_msg(bh_queue_node *msg) bh_queue_free(msg); } -bh_message_t bh_get_msg(bh_queue *queue, int timeout) +bh_message_t bh_get_msg(bh_queue *queue, uint64 timeout_us) { bh_queue_node *msg = NULL; bh_queue_mutex_lock(&queue->queue_lock); @@ -180,13 +180,13 @@ bh_message_t bh_get_msg(bh_queue *queue, int timeout) bh_assert(queue->head == NULL); bh_assert(queue->tail == NULL); - if (timeout == 0) { + if (timeout_us == 0) { bh_queue_mutex_unlock(&queue->queue_lock); return NULL; } bh_queue_cond_timedwait(&queue->queue_wait_cond, &queue->queue_lock, - timeout); + timeout_us); } if (queue->cnt == 0) { @@ -226,7 +226,7 @@ void bh_queue_enter_loop_run(bh_queue *queue, return; while (!queue->exit_loop_run) { - bh_queue_node * message = bh_get_msg(queue, (int)BHT_WAIT_FOREVER); + bh_queue_node * message = bh_get_msg(queue, BHT_WAIT_FOREVER); if (message) { handle_cb(message, arg); diff --git a/core/shared/utils/bh_queue.h b/core/shared/utils/bh_queue.h index 8a98ac421..09d1a7421 100644 --- a/core/shared/utils/bh_queue.h +++ b/core/shared/utils/bh_queue.h @@ -56,7 +56,7 @@ bool bh_post_msg(bh_queue *queue, unsigned short tag, void *body, unsigned int len); bool bh_post_msg2(bh_queue *queue, bh_message_t msg); -bh_message_t bh_get_msg(bh_queue *queue, int timeout); +bh_message_t bh_get_msg(bh_queue *queue, uint64 timeout_us); unsigned bh_queue_get_message_count(bh_queue *queue); diff --git a/core/shared/utils/runtime_timer.c b/core/shared/utils/runtime_timer.c index 873ba341c..ba495369c 100644 --- a/core/shared/utils/runtime_timer.c +++ b/core/shared/utils/runtime_timer.c @@ -396,7 +396,6 @@ handle_expired_timers(timer_ctx_t ctx, app_timer_t *expired) if (t->is_periodic) { /* if it is repeating, then reschedule it; */ reschedule_timer(ctx, t); - } else { /* else move it to idle list */ @@ -423,10 +422,10 @@ get_expiry_ms(timer_ctx_t ctx) return ms_to_next_expiry; } -int +uint32 check_app_timers(timer_ctx_t ctx) { - app_timer_t *t, *expired = NULL; + app_timer_t *t, *expired = NULL, *expired_end = NULL; uint64 now = bh_get_tick_ms(); os_mutex_lock(&ctx->mutex); @@ -436,8 +435,15 @@ check_app_timers(timer_ctx_t ctx) if (now >= t->expiry) { ctx->app_timers = t->next; - t->next = expired; - expired = t; + /* append t to the end of expired list */ + t->next = NULL; + if (!expired_end) { + expired = expired_end = t; + } + else { + expired_end->next = t; + expired_end = t; + } t = ctx->app_timers; } diff --git a/core/shared/utils/runtime_timer.h b/core/shared/utils/runtime_timer.h index e54105c5e..db81d77b8 100644 --- a/core/shared/utils/runtime_timer.h +++ b/core/shared/utils/runtime_timer.h @@ -32,7 +32,7 @@ bool sys_timer_destroy(timer_ctx_t ctx, uint32 timer_id); bool sys_timer_cancel(timer_ctx_t ctx, uint32 timer_id); bool sys_timer_restart(timer_ctx_t ctx, uint32 timer_id, int interval); void cleanup_app_timers(timer_ctx_t ctx); -int check_app_timers(timer_ctx_t ctx); +uint32 check_app_timers(timer_ctx_t ctx); uint32 get_expiry_ms(timer_ctx_t ctx); #ifdef __cplusplus diff --git a/wamr-sdk/app/libc-builtin-sysroot/include/pthread.h b/wamr-sdk/app/libc-builtin-sysroot/include/pthread.h index 38be34e13..308414457 100644 --- a/wamr-sdk/app/libc-builtin-sysroot/include/pthread.h +++ b/wamr-sdk/app/libc-builtin-sysroot/include/pthread.h @@ -6,6 +6,8 @@ #ifndef _WAMR_LIB_PTHREAD_H #define _WAMR_LIB_PTHREAD_H +#include + /* Data type define of pthread, mutex, cond and key */ typedef unsigned int pthread_t; typedef unsigned int pthread_mutex_t; @@ -41,7 +43,7 @@ int pthread_cond_init(pthread_cond_t *cond, const void *attr); int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, - unsigned int useconds); + uint64_t useconds); int pthread_cond_signal(pthread_cond_t *cond); @@ -56,4 +58,4 @@ void *pthread_getspecific(pthread_key_t key); int pthread_key_delete(pthread_key_t key); -#endif /* end of _WAMR_LIB_PTHREAD_H */ \ No newline at end of file +#endif /* end of _WAMR_LIB_PTHREAD_H */ From b75224ce032059f0796e4540618d8c2d96fd6c9a Mon Sep 17 00:00:00 2001 From: Huang Qi <757509347@qq.com> Date: Mon, 7 Dec 2020 21:15:41 +0800 Subject: [PATCH 122/207] Using posix thread implementation for NuttX (#462) Signed-off-by: Huang Qi Co-authored-by: Huang Qi --- core/shared/platform/nuttx/nuttx_platform.c | 11 --- core/shared/platform/nuttx/nuttx_thread.c | 80 ------------------- .../shared/platform/nuttx/platform_internal.h | 2 + product-mini/platforms/nuttx/wamr.mk | 4 +- 4 files changed, 5 insertions(+), 92 deletions(-) delete mode 100644 core/shared/platform/nuttx/nuttx_thread.c diff --git a/core/shared/platform/nuttx/nuttx_platform.c b/core/shared/platform/nuttx/nuttx_platform.c index 4a126c731..160147cca 100644 --- a/core/shared/platform/nuttx/nuttx_platform.c +++ b/core/shared/platform/nuttx/nuttx_platform.c @@ -57,14 +57,3 @@ os_mprotect(void *addr, size_t size, int prot) void os_dcache_flush() {} - -uint64 -os_time_get_boot_microsecond() -{ - struct timespec ts; - if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) { - return 0; - } - - return ((uint64)ts.tv_sec) * 1000 * 1000 + ((uint64)ts.tv_nsec) / 1000; -} diff --git a/core/shared/platform/nuttx/nuttx_thread.c b/core/shared/platform/nuttx/nuttx_thread.c deleted file mode 100644 index d1c8be996..000000000 --- a/core/shared/platform/nuttx/nuttx_thread.c +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2020 XiaoMi Corporation. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - */ - -#include "platform_api_extension.h" -#include "platform_api_vmcore.h" - -korp_tid -os_self_thread() -{ - return (korp_tid)pthread_self(); -} - -int -os_mutex_init(korp_mutex *mutex) -{ - return pthread_mutex_init(mutex, NULL) == 0 ? BHT_OK : BHT_ERROR; -} - -int -os_mutex_destroy(korp_mutex *mutex) -{ - int ret; - - assert(mutex); - ret = pthread_mutex_destroy(mutex); - - return ret == 0 ? BHT_OK : BHT_ERROR; -} - -int -os_mutex_lock(korp_mutex *mutex) -{ - int ret; - - assert(mutex); - ret = pthread_mutex_lock(mutex); - - return ret == 0 ? BHT_OK : BHT_ERROR; -} - -int -os_mutex_unlock(korp_mutex *mutex) -{ - int ret; - - assert(mutex); - ret = pthread_mutex_unlock(mutex); - - return ret == 0 ? BHT_OK : BHT_ERROR; -} - -uint8 * -os_thread_get_stack_boundary() -{ - return NULL; -} - -int -os_cond_init(korp_cond *cond) -{ - assert(cond); - - if (pthread_cond_init(cond, NULL) != BHT_OK) - return BHT_ERROR; - - return BHT_OK; -} - -int -os_cond_destroy(korp_cond *cond) -{ - assert(cond); - - if (pthread_cond_destroy(cond) != BHT_OK) - return BHT_ERROR; - - return BHT_OK; -} diff --git a/core/shared/platform/nuttx/platform_internal.h b/core/shared/platform/nuttx/platform_internal.h index 856aab432..77a18e8e9 100644 --- a/core/shared/platform/nuttx/platform_internal.h +++ b/core/shared/platform/nuttx/platform_internal.h @@ -16,6 +16,8 @@ #include #include #include +#include +#include #ifdef __cplusplus extern "C" { diff --git a/product-mini/platforms/nuttx/wamr.mk b/product-mini/platforms/nuttx/wamr.mk index 2efdbd703..ae1b301ab 100644 --- a/product-mini/platforms/nuttx/wamr.mk +++ b/product-mini/platforms/nuttx/wamr.mk @@ -153,7 +153,8 @@ CFLAGS += -I${IWASM_ROOT}/interpreter endif CSRCS += nuttx_platform.c \ - nuttx_thread.c \ + posix_thread.c \ + posix_time.c \ mem_alloc.c \ ems_kfc.c \ ems_alloc.c \ @@ -176,6 +177,7 @@ CSRCS += nuttx_platform.c \ ASRCS += ${INVOKE_NATIVE} VPATH += ${SHARED_ROOT}/platform/nuttx +VPATH += ${SHARED_ROOT}/platform/common/posix VPATH += ${SHARED_ROOT}/mem-alloc VPATH += ${SHARED_ROOT}/mem-alloc/ems VPATH += ${SHARED_ROOT}/utils From 35acc7f3365f1701299ec0be8563c2afaa61683d Mon Sep 17 00:00:00 2001 From: Huang Qi <757509347@qq.com> Date: Tue, 8 Dec 2020 17:44:08 +0800 Subject: [PATCH 123/207] platform/NuttX: Add support for lib pthread (#463) Signed-off-by: Huang Qi Co-authored-by: Huang Qi --- product-mini/platforms/nuttx/wamr.mk | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/product-mini/platforms/nuttx/wamr.mk b/product-mini/platforms/nuttx/wamr.mk index ae1b301ab..1fcb74c36 100644 --- a/product-mini/platforms/nuttx/wamr.mk +++ b/product-mini/platforms/nuttx/wamr.mk @@ -107,6 +107,13 @@ else CFLAGS += -DWASM_ENABLE_THREAD_MGR=0 endif +ifeq ($(CONFIG_INTERPRETERS_WAMR_LIB_PTHREAD),y) +CFLAGS += -DWASM_ENABLE_LIB_PTHREAD=1 +CSRCS += lib_pthread_wrapper.c +else +CFLAGS += -DWASM_ENABLE_LIB_PTHREAD=0 +endif + ifeq ($(CONFIG_INTERPRETERS_WAMR_MINILOADER),y) CFLAGS += -DWASM_ENABLE_MINI_LOADER=1 CSRCS += wasm_mini_loader.c @@ -140,6 +147,7 @@ CFLAGS += -Wno-int-conversion -Wno-implicit-function-declaration CFLAGS += -I${CORE_ROOT} \ -I${IWASM_ROOT}/include \ -I${IWASM_ROOT}/common \ + -I${IWASM_ROOT}/libraries/thread-mgr \ -I${SHARED_ROOT}/include \ -I${SHARED_ROOT}/platform/include \ -I${SHARED_ROOT}/utils \ @@ -186,6 +194,7 @@ VPATH += ${IWASM_ROOT}/common VPATH += ${IWASM_ROOT}/interpreter VPATH += ${IWASM_ROOT}/libraries VPATH += ${IWASM_ROOT}/libraries/libc-builtin +VPATH += ${IWASM_ROOT}/libraries/lib-pthread VPATH += ${IWASM_ROOT}/common/arch VPATH += ${IWASM_ROOT}/aot VPATH += ${IWASM_ROOT}/aot/arch From 7f4e519edc089d9bfc2797c92afd52e688acb14d Mon Sep 17 00:00:00 2001 From: Huang Qi <757509347@qq.com> Date: Wed, 9 Dec 2020 16:45:41 +0800 Subject: [PATCH 124/207] product-mini/nuttx: Add support for repl mode (#466) Signed-off-by: Huang Qi Co-authored-by: Huang Qi --- product-mini/platforms/nuttx/main.c | 86 ++++++++++++++++++++++++++++- 1 file changed, 85 insertions(+), 1 deletion(-) diff --git a/product-mini/platforms/nuttx/main.c b/product-mini/platforms/nuttx/main.c index 520d8dd21..2467cf8ed 100644 --- a/product-mini/platforms/nuttx/main.c +++ b/product-mini/platforms/nuttx/main.c @@ -7,6 +7,7 @@ #define _GNU_SOURCE #endif #include +#include #include #include "bh_platform.h" @@ -26,6 +27,8 @@ print_help() printf("options:\n"); printf(" -f|--function name Specify a function name of the module to run rather\n" " than main\n"); + printf(" --repl Start a very simple REPL (read-eval-print-loop) mode\n" + " that runs commands in the form of `FUNC ARG...`\n"); #if WASM_ENABLE_LOG != 0 printf(" -v=n Set log verbose level (0 to 5, default is 2) larger\n" " level with more log\n"); @@ -72,6 +75,81 @@ app_instance_func(wasm_module_inst_t module_inst, const char *func_name) return NULL; } +/** + * Split a space separated strings into an array of strings + * Returns NULL on failure + * Memory must be freed by caller + * Based on: http://stackoverflow.com/a/11198630/471795 + */ +static char ** +split_string(char *str, int *count) +{ + char **res = NULL; + char *p; + int idx = 0; + + /* split string and append tokens to 'res' */ + do { + p = strtok(str, " "); + str = NULL; + res = (char **)realloc(res, sizeof(char *) * (uint32)(idx + 1)); + if (res == NULL) { + return NULL; + } + res[idx++] = p; + } while (p); + + /** + * since the function name, + * res[0] might be contains a '\' to indicate a space + * func\name -> func name + */ + p = strchr(res[0], '\\'); + while (p) { + *p = ' '; + p = strchr(p, '\\'); + } + + if (count) { + *count = idx - 1; + } + return res; +} + +static void * +app_instance_repl(wasm_module_inst_t module_inst) +{ + char *cmd = NULL; + size_t len = 0; + ssize_t n; + + while ((printf("webassembly> "), n = getline(&cmd, &len, stdin)) != -1) { + bh_assert(n > 0); + if (cmd[n - 1] == '\n') { + if (n == 1) + continue; + else + cmd[n - 1] = '\0'; + } + if (!strcmp(cmd, "__exit__")) { + printf("exit repl mode\n"); + break; + } + app_argv = split_string(cmd, &app_argc); + if (app_argv == NULL) { + LOG_ERROR("Wasm prepare param failed: split string failed.\n"); + break; + } + if (app_argc != 0) { + wasm_application_execute_func(module_inst, app_argv[0], + app_argc - 1, app_argv + 1); + } + free(app_argv); + } + free(cmd); + return NULL; +} + #if WASM_ENABLE_LIBC_WASI != 0 static bool validate_env_str(char *env) @@ -152,6 +230,7 @@ main(int argc, char *argv[]) #if WASM_ENABLE_LOG != 0 int log_verbose_level = 2; #endif + bool is_repl_mode = false; #if WASM_ENABLE_LIBC_WASI != 0 const char *dir_list[8] = { NULL }; uint32 dir_list_size = 0; @@ -176,6 +255,9 @@ main(int argc, char *argv[]) return print_help(); } #endif + else if (!strcmp(argv[0], "--repl")) { + is_repl_mode = true; + } else if (!strncmp(argv[0], "--stack-size=", 13)) { if (argv[0][13] == '\0') return print_help(); @@ -296,7 +378,9 @@ main(int argc, char *argv[]) goto fail3; } - if (func_name) + if (is_repl_mode) + app_instance_repl(wasm_module_inst); + else if (func_name) app_instance_func(wasm_module_inst, func_name); else app_instance_main(wasm_module_inst); From 619c2b383cb90ee1c141a14edc0f5cfa7c05f35f Mon Sep 17 00:00:00 2001 From: Huang Qi <757509347@qq.com> Date: Fri, 11 Dec 2020 19:48:35 +0800 Subject: [PATCH 125/207] product-mini/nuttx: Use readline for repl mode (#469) The EOL of NuttX is configurable (CR/LF/CRLF), the implementation of getline in NuttX need CR or LF as line delimiter(CRLF not supported). Then we should use readline for better compatibility. Signed-off-by: Huang Qi Co-authored-by: Huang Qi --- product-mini/platforms/nuttx/main.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/product-mini/platforms/nuttx/main.c b/product-mini/platforms/nuttx/main.c index 2467cf8ed..0ddf7c128 100644 --- a/product-mini/platforms/nuttx/main.c +++ b/product-mini/platforms/nuttx/main.c @@ -10,6 +10,8 @@ #include #include +#include + #include "bh_platform.h" #include "bh_read_file.h" #include "wasm_export.h" @@ -119,13 +121,20 @@ split_string(char *str, int *count) static void * app_instance_repl(wasm_module_inst_t module_inst) { - char *cmd = NULL; - size_t len = 0; + size_t len = 128; + char *cmd = malloc(len); ssize_t n; - while ((printf("webassembly> "), n = getline(&cmd, &len, stdin)) != -1) { + if (NULL == cmd) { + LOG_ERROR("Wasm repl cmd buffer alloc failed.\n"); + return NULL; + } + + while ( + (printf("webassembly> "), fflush(stdout), n = std_readline(cmd, len)) + != -1) { bh_assert(n > 0); - if (cmd[n - 1] == '\n') { + if ((cmd[n - 1] == '\n') || (cmd[n - 1] == '\r')) { if (n == 1) continue; else From 16e6f41b3a8f265128be3ac557aa5980a969a6cc Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Mon, 14 Dec 2020 23:05:39 -0600 Subject: [PATCH 126/207] Fix wamr compiler issues and refine some error messages (#470) Fix potential memory leak issue when using llvm::EngineBuilder().selectTarget() Fix issue of accessing aot_value's fields after it is freed Fix JIT not print failed to link import warning Change some error messages: 'fail to' to 'failed to' Update error message when SIMD isn't enabled Fix install littlevgl wasm app of wasi version failed Signed-off-by: Wenyong Huang --- core/iwasm/aot/aot_loader.c | 7 ++----- core/iwasm/aot/aot_runtime.c | 15 +++++++++++---- core/iwasm/compilation/aot_compiler.c | 4 ++-- core/iwasm/compilation/aot_emit_memory.c | 17 ++++++++++++----- core/iwasm/compilation/aot_llvm_extra.cpp | 7 ++++--- core/iwasm/interpreter/wasm_interp_classic.c | 6 +++--- core/iwasm/interpreter/wasm_interp_fast.c | 8 ++++---- core/iwasm/interpreter/wasm_loader.c | 8 ++++++-- core/iwasm/interpreter/wasm_mini_loader.c | 13 ------------- core/iwasm/interpreter/wasm_runtime.c | 4 ++-- samples/littlevgl/wasm-apps/src/main.c | 9 ++++++++- 11 files changed, 54 insertions(+), 44 deletions(-) diff --git a/core/iwasm/aot/aot_loader.c b/core/iwasm/aot/aot_loader.c index 5493b0c7b..a910e0155 100644 --- a/core/iwasm/aot/aot_loader.c +++ b/core/iwasm/aot/aot_loader.c @@ -894,15 +894,12 @@ load_import_funcs(const uint8 **p_buf, const uint8 *buf_end, module_name = import_funcs[i].module_name; field_name = import_funcs[i].func_name; - if (!(import_funcs[i].func_ptr_linked = + import_funcs[i].func_ptr_linked = wasm_native_resolve_symbol(module_name, field_name, import_funcs[i].func_type, &import_funcs[i].signature, &import_funcs[i].attachment, - &import_funcs[i].call_conv_raw))) { - LOG_WARNING("warning: fail to link import function (%s, %s)\n", - module_name, field_name); - } + &import_funcs[i].call_conv_raw); #if WASM_ENABLE_LIBC_WASI != 0 if (!strcmp(import_funcs[i].module_name, "wasi_unstable") diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index 323945183..7b5df64df 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -551,8 +551,15 @@ init_func_ptrs(AOTModuleInstance *module_inst, AOTModule *module, /* Set import function pointers */ func_ptrs = (void**)module_inst->func_ptrs.ptr; - for (i = 0; i < module->import_func_count; i++, func_ptrs++) + for (i = 0; i < module->import_func_count; i++, func_ptrs++) { *func_ptrs = (void*)module->import_funcs[i].func_ptr_linked; + if (!*func_ptrs) { + const char *module_name = module->import_funcs[i].module_name; + const char *field_name = module->import_funcs[i].func_name; + LOG_WARNING("warning: failed to link import function (%s, %s)", + module_name, field_name); + } + } /* Set defined function pointers */ memcpy(func_ptrs, module->func_ptrs, module->func_count * sizeof(void*)); @@ -1232,7 +1239,7 @@ aot_set_exception_with_id(AOTModuleInstance *module_inst, aot_set_exception(module_inst, "uninitialized element"); break; case EXCE_CALL_UNLINKED_IMPORT_FUNC: - aot_set_exception(module_inst, "fail to call unlinked import function"); + aot_set_exception(module_inst, "failed to call unlinked import function"); break; case EXCE_NATIVE_STACK_OVERFLOW: aot_set_exception(module_inst, "native stack overflow"); @@ -1775,7 +1782,7 @@ aot_invoke_native(WASMExecEnv *exec_env, uint32 func_idx, import_func = aot_module->import_funcs + func_idx; if (!func_ptr) { snprintf(buf, sizeof(buf), - "fail to call unlinked import function (%s, %s)", + "failed to call unlinked import function (%s, %s)", import_func->module_name, import_func->func_name); aot_set_exception(module_inst, buf); return false; @@ -1851,7 +1858,7 @@ aot_call_indirect(WASMExecEnv *exec_env, bh_assert(func_idx < aot_module->import_func_count); import_func = aot_module->import_funcs + func_idx; snprintf(buf, sizeof(buf), - "fail to call unlinked import function (%s, %s)", + "failed to call unlinked import function (%s, %s)", import_func->module_name, import_func->func_name); aot_set_exception(module_inst, buf); return false; diff --git a/core/iwasm/compilation/aot_compiler.c b/core/iwasm/compilation/aot_compiler.c index d29e8ec6c..d02bcd758 100644 --- a/core/iwasm/compilation/aot_compiler.c +++ b/core/iwasm/compilation/aot_compiler.c @@ -1036,8 +1036,8 @@ build_atomic_rmw: case WASM_OP_SIMD_PREFIX: { if (!comp_ctx->enable_simd) { - aot_set_last_error( - "current building does not support SIMD instructions"); + aot_set_last_error("SIMD instruction was found, " + "try adding --enable-simd option?"); return false; } diff --git a/core/iwasm/compilation/aot_emit_memory.c b/core/iwasm/compilation/aot_emit_memory.c index f717b02c6..99d6593d7 100644 --- a/core/iwasm/compilation/aot_emit_memory.c +++ b/core/iwasm/compilation/aot_emit_memory.c @@ -86,7 +86,8 @@ aot_check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, LLVMBasicBlockRef block_curr = LLVMGetInsertBlock(comp_ctx->builder); LLVMBasicBlockRef check_succ; AOTValue *aot_value; - bool is_target_64bit; + uint32 local_idx_of_aot_value = 0; + bool is_target_64bit, is_local_of_aot_value = false; #if WASM_ENABLE_SHARED_MEMORY != 0 bool is_shared_memory = comp_ctx->comp_data->memories[0].memory_flags & 0x02; @@ -116,6 +117,12 @@ aot_check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } aot_value = func_ctx->block_stack.block_list_end->value_stack.value_list_end; + if (aot_value) { + /* aot_value is freed in the following POP_I32(addr), + so save its fields here for further use */ + is_local_of_aot_value = aot_value->is_local; + local_idx_of_aot_value = aot_value->local_idx; + } POP_I32(addr); @@ -156,8 +163,8 @@ aot_check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, BUILD_OP(Add, offset_const, addr, offset1, "offset1"); if (comp_ctx->enable_bound_check - && !(aot_value->is_local - && aot_checked_addr_list_find(func_ctx, aot_value->local_idx, + && !(is_local_of_aot_value + && aot_checked_addr_list_find(func_ctx, local_idx_of_aot_value, offset, bytes))) { uint32 init_page_count = comp_ctx->comp_data->memories[0].mem_init_page_count; @@ -207,8 +214,8 @@ aot_check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, SET_BUILD_POS(check_succ); - if (aot_value->is_local) { - if (!aot_checked_addr_list_add(func_ctx, aot_value->local_idx, + if (is_local_of_aot_value) { + if (!aot_checked_addr_list_add(func_ctx, local_idx_of_aot_value, offset, bytes)) goto fail; } diff --git a/core/iwasm/compilation/aot_llvm_extra.cpp b/core/iwasm/compilation/aot_llvm_extra.cpp index 895f29049..05c097600 100644 --- a/core/iwasm/compilation/aot_llvm_extra.cpp +++ b/core/iwasm/compilation/aot_llvm_extra.cpp @@ -115,9 +115,10 @@ aot_check_simd_compatibility(const char *arch_c_str, const char *cpu_c_str) llvm::SmallVector targetAttributes; llvm::Triple targetTriple(arch_c_str, "", ""); - llvm::TargetMachine *targetMachine = llvm::EngineBuilder().selectTarget( - targetTriple, "", std::string(cpu_c_str), targetAttributes); - if (targetMachine == nullptr) { + auto targetMachine = + std::unique_ptr(llvm::EngineBuilder().selectTarget( + targetTriple, "", std::string(cpu_c_str), targetAttributes)); + if (!targetMachine) { return false; } diff --git a/core/iwasm/interpreter/wasm_interp_classic.c b/core/iwasm/interpreter/wasm_interp_classic.c index d8ad05053..141ab5de3 100644 --- a/core/iwasm/interpreter/wasm_interp_classic.c +++ b/core/iwasm/interpreter/wasm_interp_classic.c @@ -941,7 +941,7 @@ wasm_interp_call_func_native(WASMModuleInstance *module_inst, if (!func_import->func_ptr_linked) { snprintf(buf, sizeof(buf), - "fail to call unlinked import function (%s, %s)", + "failed to call unlinked import function (%s, %s)", func_import->module_name, func_import->field_name); wasm_set_exception(module_inst, buf); return; @@ -998,7 +998,7 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst, if (!sub_func_inst) { snprintf(buf, sizeof(buf), - "fail to call unlinked import function (%s, %s)", + "failed to call unlinked import function (%s, %s)", func_import->module_name, func_import->field_name); wasm_set_exception(module_inst, buf); return; @@ -1865,7 +1865,7 @@ label_pop_csp_n: delta = (uint32)POP_I32(); if (!wasm_enlarge_memory(module, delta)) { - /* fail to memory.grow, return -1 */ + /* failed to memory.grow, return -1 */ PUSH_I32(-1); } else { diff --git a/core/iwasm/interpreter/wasm_interp_fast.c b/core/iwasm/interpreter/wasm_interp_fast.c index 643f680f7..359c4e327 100644 --- a/core/iwasm/interpreter/wasm_interp_fast.c +++ b/core/iwasm/interpreter/wasm_interp_fast.c @@ -987,8 +987,8 @@ wasm_interp_call_func_native(WASMModuleInstance *module_inst, if (!func_import->func_ptr_linked) { char buf[128]; - snprintf(buf, - sizeof(buf), "fail to call unlinked import function (%s, %s)", + snprintf(buf, sizeof(buf), + "failed to call unlinked import function (%s, %s)", func_import->module_name, func_import->field_name); wasm_set_exception((WASMModuleInstance*)module_inst, buf); return; @@ -1043,7 +1043,7 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst, if (!sub_func_inst) { snprintf(buf, sizeof(buf), - "fail to call unlinked import function (%s, %s)", + "failed to call unlinked import function (%s, %s)", func_import->module_name, func_import->field_name); wasm_set_exception(module_inst, buf); return; @@ -1796,7 +1796,7 @@ recover_br_info: delta = (uint32)frame_lp[addr1]; if (!wasm_enlarge_memory(module, delta)) { - /* fail to memory.grow, return -1 */ + /* failed to memory.grow, return -1 */ frame_lp[addr_ret] = -1; } else { diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index 5ba092575..6dd97aef0 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -1841,8 +1841,12 @@ load_function_section(const uint8 *buf, const uint8 *buf_end, #endif #endif ) { - set_error_buf(error_buf, error_buf_size, - "invalid local type"); + if (type == VALUE_TYPE_V128) + set_error_buf(error_buf, error_buf_size, + "v128 value type requires simd feature"); + else + set_error_buf_v(error_buf, error_buf_size, + "invalid local type 0x%02X", type); return false; } for (k = 0; k < sub_local_count; k++) { diff --git a/core/iwasm/interpreter/wasm_mini_loader.c b/core/iwasm/interpreter/wasm_mini_loader.c index cb1222a4f..27085b0af 100644 --- a/core/iwasm/interpreter/wasm_mini_loader.c +++ b/core/iwasm/interpreter/wasm_mini_loader.c @@ -388,19 +388,6 @@ load_function_import(const WASMModule *parent_module, WASMModule *sub_module, &linked_call_conv_raw); } - if (!linked_func) { -#if WASM_ENABLE_SPEC_TEST != 0 - set_error_buf(error_buf, error_buf_size, - "unknown import or incompatible import type"); - return false; -#else -#if WASM_ENABLE_WAMR_COMPILER == 0 - LOG_WARNING("warning: fail to link import function (%s, %s)", - sub_module_name, function_name); -#endif -#endif - } - function->module_name = sub_module_name; function->field_name = function_name; function->func_type = declare_func_type; diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index f6382f609..12d10f5db 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -1097,7 +1097,7 @@ check_linked_symbol(WASMModuleInstance *module_inst, char *error_buf, return false; #else #if WASM_ENABLE_WAMR_COMPILER == 0 - LOG_WARNING("warning: fail to link import function (%s, %s)", + LOG_WARNING("warning: failed to link import function (%s, %s)", func->module_name, func->field_name); #else /* do nothing to avoid confused message */ @@ -1115,7 +1115,7 @@ check_linked_symbol(WASMModuleInstance *module_inst, char *error_buf, return false; #else #if WASM_ENABLE_WAMR_COMPILER == 0 - LOG_DEBUG("warning: fail to link import global (%s, %s)", + LOG_DEBUG("warning: failed to link import global (%s, %s)", global->module_name, global->field_name); #else /* do nothing to avoid confused message */ diff --git a/samples/littlevgl/wasm-apps/src/main.c b/samples/littlevgl/wasm-apps/src/main.c index 04da156da..5b31e86e6 100644 --- a/samples/littlevgl/wasm-apps/src/main.c +++ b/samples/littlevgl/wasm-apps/src/main.c @@ -159,6 +159,13 @@ static void hal_init(void) indev_drv.type = LV_INDEV_TYPE_POINTER; indev_drv.read = display_input_read; /*This function will be called periodically (by the library) to get the mouse position and state*/ lv_indev_t * mouse_indev = lv_indev_drv_register(&indev_drv); - +} + +/* Implement empry main function as wasi start function calls it */ +int main(int argc, char **argv) +{ + (void)argc; + (void)argv; + return 0; } From ad35c3c21b3c62c57175204df7e531f602115f89 Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Wed, 16 Dec 2020 01:33:25 -0600 Subject: [PATCH 127/207] Implement SIMD float ceil/floor/trunc/nearest opcodes (#472) Implement SIMD f32x4/f64x2 ceil/floor/trunc/nearest opcodes Signed-off-by: Wenyong Huang --- core/iwasm/compilation/aot_compiler.c | 49 +++++++ .../compilation/simd/simd_floating_point.c | 133 ++++++++++-------- .../compilation/simd/simd_floating_point.h | 30 +++- core/iwasm/interpreter/wasm_loader.c | 8 ++ core/iwasm/interpreter/wasm_opcode.h | 10 ++ 5 files changed, 171 insertions(+), 59 deletions(-) diff --git a/core/iwasm/compilation/aot_compiler.c b/core/iwasm/compilation/aot_compiler.c index d02bcd758..a0ebec6e1 100644 --- a/core/iwasm/compilation/aot_compiler.c +++ b/core/iwasm/compilation/aot_compiler.c @@ -1741,6 +1741,55 @@ build_atomic_rmw: break; } + case SIMD_f32x4_ceil: + { + if (!aot_compile_simd_f32x4_ceil(comp_ctx, func_ctx)) + return false; + break; + } + case SIMD_f64x2_ceil: + { + if (!aot_compile_simd_f64x2_ceil(comp_ctx, func_ctx)) + return false; + break; + } + case SIMD_f32x4_floor: + { + if (!aot_compile_simd_f32x4_floor(comp_ctx, func_ctx)) + return false; + break; + } + case SIMD_f64x2_floor: + { + if (!aot_compile_simd_f64x2_floor(comp_ctx, func_ctx)) + return false; + break; + } + case SIMD_f32x4_trunc: + { + if (!aot_compile_simd_f32x4_trunc(comp_ctx, func_ctx)) + return false; + break; + } + case SIMD_f64x2_trunc: + { + if (!aot_compile_simd_f64x2_trunc(comp_ctx, func_ctx)) + return false; + break; + } + case SIMD_f32x4_nearest: + { + if (!aot_compile_simd_f32x4_nearest(comp_ctx, func_ctx)) + return false; + break; + } + case SIMD_f64x2_nearest: + { + if (!aot_compile_simd_f64x2_nearest(comp_ctx, func_ctx)) + return false; + break; + } + default: break; } diff --git a/core/iwasm/compilation/simd/simd_floating_point.c b/core/iwasm/compilation/simd/simd_floating_point.c index 24dc8fc51..e26b3a518 100644 --- a/core/iwasm/compilation/simd/simd_floating_point.c +++ b/core/iwasm/compilation/simd/simd_floating_point.c @@ -178,57 +178,10 @@ aot_compile_simd_f64x2_neg(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) } static bool -simd_v128_float_abs(AOTCompContext *comp_ctx, - AOTFuncContext *func_ctx, - LLVMTypeRef vector_type, - const char *intrinsic) -{ - LLVMValueRef vector, result; - LLVMTypeRef param_types[1] = { vector_type }; - - if (!(vector = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type, - "vec"))) { - goto fail; - } - - if (!(result = aot_call_llvm_intrinsic(comp_ctx, intrinsic, vector_type, - param_types, 1, vector))) { - HANDLE_FAILURE("LLVMBuildCall"); - goto fail; - } - - if (!(result = LLVMBuildBitCast(comp_ctx->builder, result, V128_i64x2_TYPE, - "ret"))) { - HANDLE_FAILURE("LLVMBuildBitCast"); - goto fail; - } - - /* push result into the stack */ - PUSH_V128(result); - return true; -fail: - return false; -} - -bool -aot_compile_simd_f32x4_abs(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) -{ - return simd_v128_float_abs(comp_ctx, func_ctx, V128_f32x4_TYPE, - "llvm.fabs.v4f32"); -} - -bool -aot_compile_simd_f64x2_abs(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) -{ - return simd_v128_float_abs(comp_ctx, func_ctx, V128_f64x2_TYPE, - "llvm.fabs.v2f64"); -} - -static bool -simd_v128_float_sqrt(AOTCompContext *comp_ctx, - AOTFuncContext *func_ctx, - LLVMTypeRef vector_type, - const char *intrinsic) +simd_v128_float_intrinsic(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + LLVMTypeRef vector_type, + const char *intrinsic) { LLVMValueRef number, result; LLVMTypeRef param_types[1] = { vector_type }; @@ -258,16 +211,86 @@ fail: return false; } +bool +aot_compile_simd_f32x4_abs(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) +{ + return simd_v128_float_intrinsic(comp_ctx, func_ctx, V128_f32x4_TYPE, + "llvm.fabs.v4f32"); +} + +bool +aot_compile_simd_f64x2_abs(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) +{ + return simd_v128_float_intrinsic(comp_ctx, func_ctx, V128_f64x2_TYPE, + "llvm.fabs.v2f64"); +} + bool aot_compile_simd_f32x4_sqrt(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) { - return simd_v128_float_sqrt(comp_ctx, func_ctx, V128_f32x4_TYPE, - "llvm.sqrt.v4f32"); + return simd_v128_float_intrinsic(comp_ctx, func_ctx, V128_f32x4_TYPE, + "llvm.sqrt.v4f32"); } bool aot_compile_simd_f64x2_sqrt(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) { - return simd_v128_float_sqrt(comp_ctx, func_ctx, V128_f64x2_TYPE, - "llvm.sqrt.v2f64"); + return simd_v128_float_intrinsic(comp_ctx, func_ctx, V128_f64x2_TYPE, + "llvm.sqrt.v2f64"); +} + +bool +aot_compile_simd_f32x4_ceil(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) +{ + return simd_v128_float_intrinsic(comp_ctx, func_ctx, V128_f32x4_TYPE, + "llvm.ceil.v4f32"); +} + +bool +aot_compile_simd_f64x2_ceil(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) +{ + return simd_v128_float_intrinsic(comp_ctx, func_ctx, V128_f64x2_TYPE, + "llvm.ceil.v2f64"); +} + +bool +aot_compile_simd_f32x4_floor(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) +{ + return simd_v128_float_intrinsic(comp_ctx, func_ctx, V128_f32x4_TYPE, + "llvm.floor.v4f32"); +} + +bool +aot_compile_simd_f64x2_floor(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) +{ + return simd_v128_float_intrinsic(comp_ctx, func_ctx, V128_f64x2_TYPE, + "llvm.floor.v2f64"); +} + +bool +aot_compile_simd_f32x4_trunc(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) +{ + return simd_v128_float_intrinsic(comp_ctx, func_ctx, V128_f32x4_TYPE, + "llvm.trunc.v4f32"); +} + +bool +aot_compile_simd_f64x2_trunc(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) +{ + return simd_v128_float_intrinsic(comp_ctx, func_ctx, V128_f64x2_TYPE, + "llvm.trunc.v2f64"); +} + +bool +aot_compile_simd_f32x4_nearest(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) +{ + return simd_v128_float_intrinsic(comp_ctx, func_ctx, V128_f32x4_TYPE, + "llvm.rint.v4f32"); +} + +bool +aot_compile_simd_f64x2_nearest(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) +{ + return simd_v128_float_intrinsic(comp_ctx, func_ctx, V128_f64x2_TYPE, + "llvm.rint.v2f64"); } diff --git a/core/iwasm/compilation/simd/simd_floating_point.h b/core/iwasm/compilation/simd/simd_floating_point.h index cb254b614..e95cab6ee 100644 --- a/core/iwasm/compilation/simd/simd_floating_point.h +++ b/core/iwasm/compilation/simd/simd_floating_point.h @@ -35,12 +35,34 @@ bool aot_compile_simd_f64x2_abs(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx); bool -aot_compile_simd_f32x4_sqrt(AOTCompContext *comp_ctx, - AOTFuncContext *func_ctx); +aot_compile_simd_f32x4_sqrt(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx); bool -aot_compile_simd_f64x2_sqrt(AOTCompContext *comp_ctx, - AOTFuncContext *func_ctx); +aot_compile_simd_f64x2_sqrt(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx); + +bool +aot_compile_simd_f32x4_ceil(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx); + +bool +aot_compile_simd_f64x2_ceil(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx); + +bool +aot_compile_simd_f32x4_floor(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx); + +bool +aot_compile_simd_f64x2_floor(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx); + +bool +aot_compile_simd_f32x4_trunc(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx); + +bool +aot_compile_simd_f64x2_trunc(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx); + +bool +aot_compile_simd_f32x4_nearest(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx); + +bool +aot_compile_simd_f64x2_nearest(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx); #ifdef __cplusplus } /* end of extern "C" */ diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index 6dd97aef0..c68425c18 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -7481,6 +7481,14 @@ fail_data_cnt_sec_require: POP2_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128); break; + case SIMD_f32x4_ceil: + case SIMD_f32x4_floor: + case SIMD_f32x4_trunc: + case SIMD_f32x4_nearest: + case SIMD_f64x2_ceil: + case SIMD_f64x2_floor: + case SIMD_f64x2_trunc: + case SIMD_f64x2_nearest: case SIMD_v128_not: case SIMD_i8x16_abs: case SIMD_i8x16_neg: diff --git a/core/iwasm/interpreter/wasm_opcode.h b/core/iwasm/interpreter/wasm_opcode.h index 650e9f25a..fa0fed74a 100644 --- a/core/iwasm/interpreter/wasm_opcode.h +++ b/core/iwasm/interpreter/wasm_opcode.h @@ -472,6 +472,16 @@ typedef enum WASMSimdEXTOpcode { SIMD_i64x2_sub = 0xd1, SIMD_i64x2_mul = 0xd5, + /* float ceil/floor/trunc/nearest */ + SIMD_f32x4_ceil = 0xd8, + SIMD_f32x4_floor = 0xd9, + SIMD_f32x4_trunc = 0xda, + SIMD_f32x4_nearest = 0xdb, + SIMD_f64x2_ceil = 0xdc, + SIMD_f64x2_floor = 0xdd, + SIMD_f64x2_trunc = 0xde, + SIMD_f64x2_nearest = 0xdf, + /* f32x4 operation */ SIMD_f32x4_abs = 0xe0, SIMD_f32x4_neg = 0xe1, From a2294877f5ad25d1391849a05c6103e40296bfda Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Mon, 21 Dec 2020 11:56:33 +0900 Subject: [PATCH 128/207] Fix struct stat fields for darwin (#473) Darwin doesn't support POSIX compatible stat fields when -fmodule --- .../libc-wasi/sandboxed-system-primitives/src/ssp_config.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/ssp_config.h b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/ssp_config.h index 5114366c8..c08d28b2c 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/ssp_config.h +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/ssp_config.h @@ -86,9 +86,9 @@ #endif #ifdef __APPLE__ -#define st_atimespec st_atim -#define st_mtimespec st_mtim -#define st_ctimespec st_ctim +#define st_atim st_atimespec +#define st_ctim st_ctimespec +#define st_mtim st_mtimespec #endif #ifdef __APPLE__ From adb05ea719a3c39a05e94c23cf298bbe01ea147d Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Mon, 21 Dec 2020 01:17:36 -0600 Subject: [PATCH 129/207] Enable SIMD support for Linux SGX platform (#474) --- core/iwasm/common/wasm_runtime_common.c | 14 +++----------- core/iwasm/libraries/libc-emcc/libc_emcc_wrapper.c | 4 ++-- product-mini/platforms/linux-sgx/CMakeLists.txt | 5 +++++ samples/workload/tensorflow/build.sh | 12 ++++-------- samples/workload/tensorflow/tf_lite.patch | 11 ++++------- 5 files changed, 18 insertions(+), 28 deletions(-) diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index d132c742b..de90eb395 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -294,7 +294,7 @@ wasm_runtime_register_module_internal(const char *module_name, node = wasm_runtime_find_module_registered_by_reference(module); if (node) { /* module has been registered */ if (node->module_name) { /* module has name */ - if (strcmp(node->module_name, module_name)) { + if (!module_name || strcmp(node->module_name, module_name)) { /* module has different name */ LOG_DEBUG("module(%p) has been registered with name %s", module, node->module_name); @@ -3094,17 +3094,9 @@ fail: #undef v128 #endif -#if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64) -#include -/* unaligned */ -#define v128 __m128i_u -#else -#warning "Include header files for v128 to support SIMD feature" -#endif +typedef long long v128 __attribute__ ((__vector_size__ (16), + __may_alias__, __aligned__ (1))); -#ifndef v128 -#error "v128 type isn't defined" -#endif #endif /* end of WASM_ENABLE_SIMD != 0 */ typedef void (*GenericFunctionPointer)(); diff --git a/core/iwasm/libraries/libc-emcc/libc_emcc_wrapper.c b/core/iwasm/libraries/libc-emcc/libc_emcc_wrapper.c index 83186c400..0f9a35645 100644 --- a/core/iwasm/libraries/libc-emcc/libc_emcc_wrapper.c +++ b/core/iwasm/libraries/libc-emcc/libc_emcc_wrapper.c @@ -7,7 +7,7 @@ #include "bh_log.h" #include "wasm_export.h" #include "../interpreter/wasm.h" -#ifndef _DEFAULT_SOURCE +#if !defined(_DEFAULT_SOURCE) && !defined(BH_PLATFORM_LINUX_SGX) #include "sys/syscall.h" #endif @@ -267,7 +267,7 @@ getentropy_wrapper(wasm_exec_env_t exec_env, void *buffer, uint32 length) { if (buffer == NULL) return -1; -#ifdef _DEFAULT_SOURCE +#if defined(_DEFAULT_SOURCE) || defined(BH_PLATFORM_LINUX_SGX) return getentropy(buffer, length); #else return syscall(SYS_getrandom, buffer, length, 0); diff --git a/product-mini/platforms/linux-sgx/CMakeLists.txt b/product-mini/platforms/linux-sgx/CMakeLists.txt index 4ea38792d..286d90596 100644 --- a/product-mini/platforms/linux-sgx/CMakeLists.txt +++ b/product-mini/platforms/linux-sgx/CMakeLists.txt @@ -67,6 +67,11 @@ if (NOT DEFINED WAMR_BUILD_LIB_PTHREAD) set (WAMR_BUILD_LIB_PTHREAD 1) endif () +if (NOT DEFINED WAMR_BUILD_SIMD) + # Disable SIMD by default + set (WAMR_BUILD_SIMD 0) +endif () + if (COLLECT_CODE_COVERAGE EQUAL 1) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage") endif () diff --git a/samples/workload/tensorflow/build.sh b/samples/workload/tensorflow/build.sh index ec9424842..f3c10be33 100755 --- a/samples/workload/tensorflow/build.sh +++ b/samples/workload/tensorflow/build.sh @@ -76,12 +76,8 @@ fi if [ -d "${TF_LITE_BUILD_DIR}/gen" ]; then rm -fr ${TF_LITE_BUILD_DIR}/gen fi -if [[ $1 == '--sgx' ]]; then - make -j 4 -C "${TENSORFLOW_DIR}" -f ${TF_LITE_BUILD_DIR}/Makefile -else - export BUILD_WITH_SIMD=true - make -j 4 -C "${TENSORFLOW_DIR}" -f ${TF_LITE_BUILD_DIR}/Makefile -fi + +make -j 4 -C "${TENSORFLOW_DIR}" -f ${TF_LITE_BUILD_DIR}/Makefile # remove patch file and recover emcc libc.a after building Clear_Before_Exit @@ -102,7 +98,7 @@ make WAMRC_CMD="$(pwd)/wamrc" cd ${OUT_DIR} if [[ $1 == '--sgx' ]]; then - ${WAMRC_CMD} -sgx -o benchmark_model.aot benchmark_model.wasm + ${WAMRC_CMD} --enable-simd -sgx -o benchmark_model.aot benchmark_model.wasm else ${WAMRC_CMD} --enable-simd -o benchmark_model.aot benchmark_model.wasm fi @@ -114,7 +110,7 @@ fi if [[ $1 == '--sgx' ]]; then cd ${WAMR_PLATFORM_DIR}/linux-sgx rm -fr build && mkdir build - cd build && cmake .. -DWAMR_BUILD_LIB_PTHREAD=1 -DWAMR_BUILD_LIBC_EMCC=1 + cd build && cmake .. -DWAMR_BUILD_SIMD=1 -DWAMR_BUILD_LIB_PTHREAD=1 -DWAMR_BUILD_LIBC_EMCC=1 make cd ../enclave-sample make diff --git a/samples/workload/tensorflow/tf_lite.patch b/samples/workload/tensorflow/tf_lite.patch index b76dd5219..f83c1d952 100644 --- a/samples/workload/tensorflow/tf_lite.patch +++ b/samples/workload/tensorflow/tf_lite.patch @@ -1,5 +1,5 @@ diff --git a/tensorflow/lite/tools/make/Makefile b/tensorflow/lite/tools/make/Makefile -index c7ddff5844..17146868f7 100644 +index c7ddff58440..ed69c452b67 100644 --- a/tensorflow/lite/tools/make/Makefile +++ b/tensorflow/lite/tools/make/Makefile @@ -48,11 +48,7 @@ INCLUDES += -I/usr/local/include @@ -15,15 +15,12 @@ index c7ddff5844..17146868f7 100644 -ldl # There are no rules for compiling objects for the host system (since we don't -@@ -84,14 +80,24 @@ endif # ifeq ($(HOST_ARCH),$(TARGET_ARCH)) +@@ -84,14 +80,21 @@ endif # ifeq ($(HOST_ARCH),$(TARGET_ARCH)) endif # ifeq ($(HOST_OS),$(TARGET)) endif -+BUILD_WITH_SIMD ?= false -+ifeq ($(BUILD_WITH_SIMD), true) +CFLAGS+=-msimd128 +CXXFLAGS+=-msimd128 -+endif + +LIBFLAGS += -s TOTAL_STACK=1048576 \ + -Wl,--export=__data_end -Wl,--export=__heap_base \ @@ -42,7 +39,7 @@ index c7ddff5844..17146868f7 100644 # A small example program that shows how to link against the library. MINIMAL_SRCS := \ -@@ -277,12 +283,16 @@ LIB_PATH := $(LIBDIR)$(LIB_NAME) +@@ -277,12 +280,16 @@ LIB_PATH := $(LIBDIR)$(LIB_NAME) BENCHMARK_LIB := $(LIBDIR)$(BENCHMARK_LIB_NAME) BENCHMARK_BINARY := $(BINDIR)$(BENCHMARK_BINARY_NAME) BENCHMARK_PERF_OPTIONS_BINARY := $(BINDIR)$(BENCHMARK_PERF_OPTIONS_BINARY_NAME) @@ -64,7 +61,7 @@ index c7ddff5844..17146868f7 100644 MINIMAL_OBJS := $(addprefix $(OBJDIR), \ $(patsubst %.cc,%.o,$(patsubst %.c,%.o,$(MINIMAL_SRCS)))) diff --git a/tensorflow/lite/tools/make/targets/linux_makefile.inc b/tensorflow/lite/tools/make/targets/linux_makefile.inc -index 222cef9e5f..eea89a38f0 100644 +index 222cef9e5ff..eea89a38f01 100644 --- a/tensorflow/lite/tools/make/targets/linux_makefile.inc +++ b/tensorflow/lite/tools/make/targets/linux_makefile.inc @@ -2,12 +2,10 @@ From cb0e593c15903827987f8a9e618f40b3e204eac1 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Mon, 21 Dec 2020 19:24:14 +0900 Subject: [PATCH 130/207] Remove debris tlsf in git repo (#475) --- core/shared/mem-alloc/tlsf | 1 - 1 file changed, 1 deletion(-) delete mode 160000 core/shared/mem-alloc/tlsf diff --git a/core/shared/mem-alloc/tlsf b/core/shared/mem-alloc/tlsf deleted file mode 160000 index a1f743ffa..000000000 --- a/core/shared/mem-alloc/tlsf +++ /dev/null @@ -1 +0,0 @@ -Subproject commit a1f743ffac0305408b39e791e0ffb45f6d9bc777 From 50f9a3e340eb849ab9a7e464c7883241217f5a82 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Sat, 26 Dec 2020 01:45:11 +0000 Subject: [PATCH 131/207] NFC: fix typo in invokeNative_aarch64.s comment (#479) `inteter` -> `integer` --- core/iwasm/common/arch/invokeNative_aarch64.s | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/iwasm/common/arch/invokeNative_aarch64.s b/core/iwasm/common/arch/invokeNative_aarch64.s index 77536c923..ea5cbcb36 100644 --- a/core/iwasm/common/arch/invokeNative_aarch64.s +++ b/core/iwasm/common/arch/invokeNative_aarch64.s @@ -37,7 +37,7 @@ _invokeNative: ldp d4, d5, [x20], #16 /* d4 = argv[4], d5 = argv[5] */ ldp d6, d7, [x20], #16 /* d6 = argv[6], d7 = argv[7] */ - /* Fill inteter registers */ + /* Fill integer registers */ ldp x0, x1, [x20], #16 /* x0 = argv[8] = exec_env, x1 = argv[9] */ ldp x2, x3, [x20], #16 /* x2 = argv[10], x3 = argv[11] */ ldp x4, x5, [x20], #16 /* x4 = argv[12], x5 = argv[13] */ From 13f0b2485b2ab1a1ff8942617940c828cfcf623b Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Sun, 27 Dec 2020 04:16:46 +0000 Subject: [PATCH 132/207] Update darwin CMakeLists.txt to support Apple Silicon on macOS (#480) Without this change in a corresponding `CMakeLists.txt` it attempts to build `invokeNative` assembly for `X86_64` on Macs with Apple Silicon. Co-authored-by: Wenyong Huang --- product-mini/platforms/darwin/CMakeLists.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/product-mini/platforms/darwin/CMakeLists.txt b/product-mini/platforms/darwin/CMakeLists.txt index 352b6fbe9..15367caf1 100644 --- a/product-mini/platforms/darwin/CMakeLists.txt +++ b/product-mini/platforms/darwin/CMakeLists.txt @@ -14,7 +14,10 @@ set (CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") # Set WAMR_BUILD_TARGET, currently values supported: # "X86_64", "AMD_64", "X86_32", "ARM[sub]", "THUMB[sub]", "MIPS", "XTENSA" if (NOT DEFINED WAMR_BUILD_TARGET) - if (CMAKE_SIZEOF_VOID_P EQUAL 8) + if (CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") + # Handle Apple Silicon + set (WAMR_BUILD_TARGET "AARCH64") + elseif (CMAKE_SIZEOF_VOID_P EQUAL 8) # Build as X86_64 by default in 64-bit platform set (WAMR_BUILD_TARGET "X86_64") else () From 724858c7317f9b6bd6d848a55265126c59a507a5 Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Sun, 27 Dec 2020 20:46:31 -0600 Subject: [PATCH 133/207] Update wasm app build scripts for wasi-sdk-12 and refine interpreter (#481) Update wasm app build scripts for wasi-sdk-12.0: add --export=__main_argc_argv, remove --no-threads Lookup function with name "__main_argc_argv" as main function besides "main" Change module_malloc to runtime_malloc in wasi native lib Refine classic interpreter op_block and op_br_table Refine faster interpreter op_br_table Signed-off-by: Wenyong Huang --- core/iwasm/common/wasm_runtime_common.c | 9 +- core/iwasm/compilation/aot_emit_control.c | 2 +- core/iwasm/interpreter/wasm.h | 4 +- core/iwasm/interpreter/wasm_interp_classic.c | 84 ++++++++---------- core/iwasm/interpreter/wasm_interp_fast.c | 36 +++++--- core/iwasm/interpreter/wasm_loader.c | 86 ++++--------------- core/iwasm/interpreter/wasm_loader.h | 4 +- .../libraries/libc-wasi/libc_wasi_wrapper.c | 30 +++---- doc/build_wasm_app.md | 9 +- product-mini/app-samples/hello-world/build.sh | 28 ++++-- samples/basic/build.sh | 2 +- samples/gui/wasm-apps/decrease/Makefile | 4 +- samples/gui/wasm-apps/increase/Makefile | 2 +- samples/littlevgl/wasm-apps/Makefile_wasm_app | 4 +- .../wasm-apps/Makefile_wasm_app_no_wasi | 4 +- samples/multi-thread/wasm-apps/CMakeLists.txt | 12 +-- samples/simple/build.sh | 2 +- .../suites/01-life-cycle/test-app/build.sh | 12 +-- wamr-sdk/app/wamr_toolchain.cmake | 2 +- 19 files changed, 144 insertions(+), 192 deletions(-) diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index de90eb395..45b81b9d6 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -2039,12 +2039,9 @@ wasm_application_execute_main(WASMModuleInstanceCommon *module_inst, } #endif /* end of WASM_ENABLE_LIBC_WASI */ - func = resolve_function(module_inst, "_main"); - if (!func) { - func = resolve_function(module_inst, "main"); - } - - if (!func) { + if (!(func = resolve_function(module_inst, "main")) + && !(func = resolve_function(module_inst, "__main_argc_argv")) + && !(func = resolve_function(module_inst, "_main"))) { wasm_runtime_set_exception(module_inst, "lookup main function failed"); return false; diff --git a/core/iwasm/compilation/aot_emit_control.c b/core/iwasm/compilation/aot_emit_control.c index 6c1c6f9e7..2b8a8a526 100644 --- a/core/iwasm/compilation/aot_emit_control.c +++ b/core/iwasm/compilation/aot_emit_control.c @@ -383,7 +383,7 @@ aot_compile_op_block(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, /* Get block info */ if (!(wasm_loader_find_block_addr((BlockAddr*)block_addr_cache, *p_frame_ip, frame_ip_end, (uint8)label_type, - &else_addr, &end_addr, NULL, 0))) { + &else_addr, &end_addr))) { aot_set_last_error("find block end addr failed."); return false; } diff --git a/core/iwasm/interpreter/wasm.h b/core/iwasm/interpreter/wasm.h index feae8effe..f6034d563 100644 --- a/core/iwasm/interpreter/wasm.h +++ b/core/iwasm/interpreter/wasm.h @@ -405,10 +405,10 @@ typedef struct BlockType { } BlockType; typedef struct WASMBranchBlock { - uint8 label_type; - uint32 cell_num; + uint8 *begin_addr; uint8 *target_addr; uint32 *frame_sp; + uint32 cell_num; } WASMBranchBlock; /* Execution environment, e.g. stack info */ diff --git a/core/iwasm/interpreter/wasm_interp_classic.c b/core/iwasm/interpreter/wasm_interp_classic.c index 141ab5de3..55c619c2e 100644 --- a/core/iwasm/interpreter/wasm_interp_classic.c +++ b/core/iwasm/interpreter/wasm_interp_classic.c @@ -381,28 +381,28 @@ popcount64(uint64 u) static uint64 read_leb(const uint8 *buf, uint32 *p_offset, uint32 maxbits, bool sign) { - uint64 result = 0; + uint64 result = 0, byte; + uint32 offset = *p_offset; uint32 shift = 0; - uint32 bcnt = 0; - uint64 byte; while (true) { - byte = buf[*p_offset]; - *p_offset += 1; + byte = buf[offset++]; result |= ((byte & 0x7f) << shift); shift += 7; if ((byte & 0x80) == 0) { break; } - bcnt += 1; } if (sign && (shift < maxbits) && (byte & 0x40)) { /* Sign extend */ result |= - ((uint64)1 << shift); } + *p_offset = offset; return result; } +#define skip_leb(p) while (*p++ & 0x80) + #define PUSH_I32(value) do { \ *(int32*)frame_sp++ = (int32)(value); \ } while (0) @@ -423,8 +423,9 @@ read_leb(const uint8 *buf, uint32 *p_offset, uint32 maxbits, bool sign) #define PUSH_CSP(_label_type, cell_num, _target_addr) do { \ bh_assert(frame_csp < frame->csp_boundary); \ - frame_csp->label_type = _label_type; \ + /* frame_csp->label_type = _label_type; */ \ frame_csp->cell_num = cell_num; \ + frame_csp->begin_addr = frame_ip; \ frame_csp->target_addr = _target_addr; \ frame_csp->frame_sp = frame_sp; \ frame_csp++; \ @@ -1078,11 +1079,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, BlockAddr *cache_items; uint8 *frame_ip_end = frame_ip + 1; uint8 opcode; - uint32 *depths = NULL; - uint32 depth_buf[BR_TABLE_TMP_BUF_LEN]; - uint32 i, depth, cond, count, fidx, tidx, frame_size = 0; + uint32 i, depth, cond, count, fidx, tidx, lidx, frame_size = 0; uint64 all_cell_num = 0; - int32 didx, val; + int32 val; uint8 *else_addr, *end_addr, *maddr = NULL; uint32 local_idx, local_offset, global_idx; uint8 local_type, *global_addr; @@ -1127,15 +1126,9 @@ handle_op_block: else if (cache_items[1].start_addr == frame_ip) { end_addr = cache_items[1].end_addr; } - else if (!wasm_loader_find_block_addr((BlockAddr*)exec_env->block_addr_cache, - frame_ip, (uint8*)-1, - LABEL_TYPE_BLOCK, - &else_addr, &end_addr, - NULL, 0)) { - wasm_set_exception(module, "find block address failed"); - goto got_exception; + else { + end_addr = NULL; } - PUSH_CSP(LABEL_TYPE_BLOCK, cell_num, end_addr); HANDLE_OP_END (); @@ -1173,26 +1166,26 @@ handle_op_if: else if (!wasm_loader_find_block_addr((BlockAddr*)exec_env->block_addr_cache, frame_ip, (uint8*)-1, LABEL_TYPE_IF, - &else_addr, &end_addr, - NULL, 0)) { + &else_addr, &end_addr)) { wasm_set_exception(module, "find block address failed"); goto got_exception; } cond = (uint32)POP_I32(); - PUSH_CSP(LABEL_TYPE_IF, cell_num, end_addr); - - /* condition of the if branch is false, else condition is met */ - if (cond == 0) { + if (cond) { /* if branch is met */ + PUSH_CSP(LABEL_TYPE_IF, cell_num, end_addr); + } + else { /* if branch is not met */ /* if there is no else branch, go to the end addr */ if (else_addr == NULL) { - POP_CSP(); frame_ip = end_addr + 1; } /* if there is an else branch, go to the else addr */ - else + else { + PUSH_CSP(LABEL_TYPE_IF, cell_num, end_addr); frame_ip = else_addr + 1; + } } HANDLE_OP_END (); @@ -1221,6 +1214,16 @@ handle_op_if: read_leb_uint32(frame_ip, frame_ip_end, depth); label_pop_csp_n: POP_CSP_N(depth); + if (!frame_ip) { /* must be label pushed by WASM_OP_BLOCK */ + if (!wasm_loader_find_block_addr((BlockAddr*)exec_env->block_addr_cache, + (frame_csp - 1)->begin_addr, (uint8*)-1, + LABEL_TYPE_BLOCK, + &else_addr, &end_addr)) { + wasm_set_exception(module, "find block address failed"); + goto got_exception; + } + frame_ip = end_addr; + } HANDLE_OP_END (); HANDLE_OP (WASM_OP_BR_IF): @@ -1238,30 +1241,13 @@ label_pop_csp_n: CHECK_SUSPEND_FLAGS(); #endif read_leb_uint32(frame_ip, frame_ip_end, count); - if (count <= BR_TABLE_TMP_BUF_LEN) - depths = depth_buf; - else { - uint64 total_size = sizeof(uint32) * (uint64)count; - if (total_size >= UINT32_MAX - || !(depths = wasm_runtime_malloc((uint32)total_size))) { - wasm_set_exception(module, "allocate memory failed"); - goto got_exception; - } - } - for (i = 0; i < count; i++) { - read_leb_uint32(frame_ip, frame_ip_end, depths[i]); - } + lidx = POP_I32(); + if (lidx > count) + lidx = count; + for (i = 0; i < lidx; i++) + skip_leb(frame_ip); read_leb_uint32(frame_ip, frame_ip_end, depth); - didx = POP_I32(); - if (didx >= 0 && (uint32)didx < count) { - depth = depths[didx]; - } - if (depths != depth_buf) { - wasm_runtime_free(depths); - depths = NULL; - } goto label_pop_csp_n; - HANDLE_OP_END (); HANDLE_OP (WASM_OP_RETURN): frame_sp -= cur_func->ret_cell_num; diff --git a/core/iwasm/interpreter/wasm_interp_fast.c b/core/iwasm/interpreter/wasm_interp_fast.c index 359c4e327..2815e63d4 100644 --- a/core/iwasm/interpreter/wasm_interp_fast.c +++ b/core/iwasm/interpreter/wasm_interp_fast.c @@ -1249,20 +1249,36 @@ recover_br_info: HANDLE_OP_END (); HANDLE_OP (WASM_OP_BR_TABLE): -#if WASM_ENABLE_THREAD_MGR != 0 - CHECK_SUSPEND_FLAGS(); -#endif - count = read_uint32(frame_ip); - didx = GET_OPERAND(uint32, 0); - frame_ip += 2; + { + uint32 arity, br_item_size; - if (!(didx >= 0 && (uint32)didx < count)) +#if WASM_ENABLE_THREAD_MGR != 0 + CHECK_SUSPEND_FLAGS(); +#endif + count = read_uint32(frame_ip); + didx = GET_OPERAND(uint32, 0); + frame_ip += 2; + + if (!(didx >= 0 && (uint32)didx < count)) didx = count; - while (didx--) - SKIP_BR_INFO(); + /* all br items must have the same arity and item size, + so we only calculate the first item size */ + arity = *(uint32*)frame_ip; + br_item_size = sizeof(uint32); /* arity */ + if (arity) { + /* total cell num */ + br_item_size += sizeof(uint32); + /* cells, src offsets and dst offsets */ + br_item_size += (sizeof(uint8) + sizeof(int16) + sizeof(uint16)) + * arity; + } + /* target address */ + br_item_size += sizeof(uint8*); - goto recover_br_info; + frame_ip += br_item_size * didx; + goto recover_br_info; + } HANDLE_OP (WASM_OP_RETURN): { diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index c68425c18..3db4c6799 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -79,53 +79,10 @@ check_buf1(const uint8 *buf, const uint8 *buf_end, uint32 length, } \ } while (0) -static bool -skip_leb(const uint8 **p_buf, const uint8 *buf_end, uint32 maxbits, - char* error_buf, uint32 error_buf_size) -{ - const uint8 *buf = *p_buf; - uint32 offset = 0, bcnt = 0; - uint64 byte; - - while (true) { - if (bcnt + 1 > (maxbits + 6) / 7) { - set_error_buf(error_buf, error_buf_size, - "integer representation too long"); - return false; - } - - CHECK_BUF(buf, buf_end, offset + 1); - byte = buf[offset]; - offset += 1; - bcnt += 1; - if ((byte & 0x80) == 0) { - break; - } - } - - *p_buf += offset; - return true; -fail: - return false; -} - -#define skip_leb_int64(p, p_end) do { \ - if (!skip_leb(&p, p_end, 64, \ - error_buf, error_buf_size)) \ - return false; \ -} while (0) - -#define skip_leb_uint32(p, p_end) do { \ - if (!skip_leb(&p, p_end, 32, \ - error_buf, error_buf_size)) \ - return false; \ -} while (0) - -#define skip_leb_int32(p, p_end) do { \ - if (!skip_leb(&p, p_end, 32, \ - error_buf, error_buf_size)) \ - return false; \ -} while (0) +#define skip_leb(p) while (*p++ & 0x80) +#define skip_leb_int64(p, p_end) skip_leb(p) +#define skip_leb_uint32(p, p_end) skip_leb(p) +#define skip_leb_int32(p, p_end) skip_leb(p) static bool read_leb(uint8 **p_buf, const uint8 *buf_end, @@ -1134,13 +1091,15 @@ load_global_import(const WASMModule *parent_module, } if (wasm_runtime_is_host_module(sub_module_name)) { - /* do nothing, let host injects the symbol */ + /* do nothing, let host inject the symbol */ } +#if WASM_ENABLE_LIBC_BUILTIN != 0 else if (wasm_runtime_is_built_in_module(sub_module_name)) { /* check built-in modules */ global->is_linked = wasm_native_lookup_libc_builtin_global( sub_module_name, global_name, global); } +#endif #if WASM_ENABLE_MULTI_MODULE != 0 else { /* check sub modules */ @@ -3267,17 +3226,17 @@ wasm_loader_find_block_addr(BlockAddr *block_addr_cache, const uint8 *code_end_addr, uint8 label_type, uint8 **p_else_addr, - uint8 **p_end_addr, - char *error_buf, - uint32 error_buf_size) + uint8 **p_end_addr) { const uint8 *p = start_addr, *p_end = code_end_addr; uint8 *else_addr = NULL; + char error_buf[128]; uint32 block_nested_depth = 1, count, i, j, t; + uint32 error_buf_size = sizeof(error_buf); uint8 opcode, u8; BlockAddr block_stack[16] = { 0 }, *block; - i = ((uintptr_t)start_addr) % BLOCK_ADDR_CACHE_SIZE; + i = ((uintptr_t)start_addr) & (uintptr_t)(BLOCK_ADDR_CACHE_SIZE - 1); block = block_addr_cache + BLOCK_ADDR_CONFLICT_SIZE * i; for (j = 0; j < BLOCK_ADDR_CONFLICT_SIZE; j++) { @@ -3303,7 +3262,6 @@ wasm_loader_find_block_addr(BlockAddr *block_addr_cache, case WASM_OP_BLOCK: case WASM_OP_LOOP: case WASM_OP_IF: - CHECK_BUF(p, p_end, 1); /* block result type: 0x40/0x7F/0x7E/0x7D/0x7C */ u8 = read_uint8(p); if (block_nested_depth < sizeof(block_stack)/sizeof(BlockAddr)) { @@ -3342,7 +3300,8 @@ wasm_loader_find_block_addr(BlockAddr *block_addr_cache, for (t = 0; t < sizeof(block_stack)/sizeof(BlockAddr); t++) { start_addr = block_stack[t].start_addr; if (start_addr) { - i = ((uintptr_t)start_addr) % BLOCK_ADDR_CACHE_SIZE; + i = ((uintptr_t)start_addr) + & (uintptr_t)(BLOCK_ADDR_CACHE_SIZE - 1); block = block_addr_cache + BLOCK_ADDR_CONFLICT_SIZE * i; for (j = 0; j < BLOCK_ADDR_CONFLICT_SIZE; j++) if (!block[j].start_addr) @@ -3633,9 +3592,6 @@ wasm_loader_find_block_addr(BlockAddr *block_addr_cache, break; #endif default: - set_error_buf_v(error_buf, error_buf_size, - "%s %02x %02x", - "unsupported opcode", 0xfc, opcode); return false; } break; @@ -3704,10 +3660,6 @@ wasm_loader_find_block_addr(BlockAddr *block_addr_cache, default: LOG_WARNING("WASM loader find block addr failed: " "invalid opcode fd 0x%02x.", opcode); - if (error_buf) - snprintf(error_buf, error_buf_size, - "WASM loader find block addr failed: " - "invalid opcode fd %02x.", opcode); return false; } break; @@ -3733,9 +3685,6 @@ wasm_loader_find_block_addr(BlockAddr *block_addr_cache, #endif default: - set_error_buf_v(error_buf, error_buf_size, - "%s %02x", - "unsupported opcode", opcode); return false; } } @@ -6126,7 +6075,6 @@ handle_op_block_and_loop: #endif POP_I32(); - /* TODO: check the const */ for (i = 0; i <= count; i++) { if (!(frame_csp_tmp = check_branch_block(loader_ctx, &p, p_end, @@ -6136,8 +6084,8 @@ handle_op_block_and_loop: if (i == 0) { if (frame_csp_tmp->label_type != LABEL_TYPE_LOOP) ret_count = - block_type_get_result_types(&frame_csp_tmp->block_type, - &ret_types); + block_type_get_result_types(&frame_csp_tmp->block_type, + &ret_types); } else { uint8 *tmp_ret_types = NULL; @@ -6146,8 +6094,8 @@ handle_op_block_and_loop: /* Check whether all table items have the same return type */ if (frame_csp_tmp->label_type != LABEL_TYPE_LOOP) tmp_ret_count = - block_type_get_result_types(&frame_csp_tmp->block_type, - &tmp_ret_types); + block_type_get_result_types(&frame_csp_tmp->block_type, + &tmp_ret_types); if (ret_count != tmp_ret_count || (ret_count diff --git a/core/iwasm/interpreter/wasm_loader.h b/core/iwasm/interpreter/wasm_loader.h index c7a57e60d..0e9c48888 100644 --- a/core/iwasm/interpreter/wasm_loader.h +++ b/core/iwasm/interpreter/wasm_loader.h @@ -68,9 +68,7 @@ wasm_loader_find_block_addr(BlockAddr *block_addr_cache, const uint8 *code_end_addr, uint8 block_type, uint8 **p_else_addr, - uint8 **p_end_addr, - char *error_buf, - uint32 error_buf_size); + uint8 **p_end_addr); #ifdef __cplusplus } diff --git a/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c b/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c index a6674d714..467a9e2ce 100644 --- a/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c +++ b/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c @@ -340,7 +340,6 @@ wasi_fd_pread(wasm_exec_env_t exec_env, wasi_iovec_t *iovec, *iovec_begin; uint64 total_size; size_t nread; - uint32 mem; uint32 i; wasi_errno_t err; @@ -355,7 +354,7 @@ wasi_fd_pread(wasm_exec_env_t exec_env, total_size = sizeof(wasi_iovec_t) * (uint64)iovs_len; if (total_size >= UINT32_MAX - || !(mem = module_malloc((uint32)total_size, (void**)&iovec_begin))) + || !(iovec_begin = wasm_runtime_malloc((uint32)total_size))) return (wasi_errno_t)-1; iovec = iovec_begin; @@ -380,7 +379,7 @@ wasi_fd_pread(wasm_exec_env_t exec_env, err = 0; fail: - module_free(mem); + wasm_runtime_free(iovec_begin); return err; } @@ -395,7 +394,6 @@ wasi_fd_pwrite(wasm_exec_env_t exec_env, wasi_ciovec_t *ciovec, *ciovec_begin; uint64 total_size; size_t nwritten; - uint32 mem; uint32 i; wasi_errno_t err; @@ -410,7 +408,7 @@ wasi_fd_pwrite(wasm_exec_env_t exec_env, total_size = sizeof(wasi_ciovec_t) * (uint64)iovs_len; if (total_size >= UINT32_MAX - || !(mem = module_malloc((uint32)total_size, (void**)&ciovec_begin))) + || !(ciovec_begin = wasm_runtime_malloc((uint32)total_size))) return (wasi_errno_t)-1; ciovec = ciovec_begin; @@ -435,7 +433,7 @@ wasi_fd_pwrite(wasm_exec_env_t exec_env, err = 0; fail: - module_free(mem); + wasm_runtime_free(ciovec_begin); return err; } @@ -451,7 +449,6 @@ wasi_fd_read(wasm_exec_env_t exec_env, uint64 total_size; size_t nread; uint32 i; - uint32 mem; wasi_errno_t err; if (!wasi_ctx) @@ -465,7 +462,7 @@ wasi_fd_read(wasm_exec_env_t exec_env, total_size = sizeof(wasi_iovec_t) * (uint64)iovs_len; if (total_size >= UINT32_MAX - || !(mem = module_malloc((uint32)total_size, (void**)&iovec_begin))) + || !(iovec_begin = wasm_runtime_malloc((uint32)total_size))) return (wasi_errno_t)-1; iovec = iovec_begin; @@ -490,7 +487,7 @@ wasi_fd_read(wasm_exec_env_t exec_env, err = 0; fail: - module_free(mem); + wasm_runtime_free(iovec_begin); return err; } @@ -622,7 +619,6 @@ wasi_fd_write(wasm_exec_env_t exec_env, wasi_fd_t fd, wasi_ciovec_t *ciovec, *ciovec_begin; uint64 total_size; size_t nwritten; - uint32 mem; uint32 i; wasi_errno_t err; @@ -637,7 +633,7 @@ wasi_fd_write(wasm_exec_env_t exec_env, wasi_fd_t fd, total_size = sizeof(wasi_ciovec_t) * (uint64)iovs_len; if (total_size >= UINT32_MAX - || !(mem = module_malloc((uint32)total_size, (void**)&ciovec_begin))) + || !(ciovec_begin = wasm_runtime_malloc((uint32)total_size))) return (wasi_errno_t)-1; ciovec = ciovec_begin; @@ -662,7 +658,7 @@ wasi_fd_write(wasm_exec_env_t exec_env, wasi_fd_t fd, err = 0; fail: - module_free(mem); + wasm_runtime_free(ciovec_begin); return err; } @@ -1052,7 +1048,6 @@ wasi_sock_recv(wasm_exec_env_t exec_env, wasi_iovec_t *iovec, *iovec_begin; uint64 total_size; size_t ro_datalen; - uint32 mem; uint32 i; wasi_errno_t err; @@ -1068,7 +1063,7 @@ wasi_sock_recv(wasm_exec_env_t exec_env, total_size = sizeof(wasi_iovec_t) * (uint64)ri_data_len; if (total_size >= UINT32_MAX - || !(mem = module_malloc((uint32)total_size, (void**)&iovec_begin))) + || !(iovec_begin = wasm_runtime_malloc((uint32)total_size))) return (wasi_errno_t)-1; iovec = iovec_begin; @@ -1095,7 +1090,7 @@ wasi_sock_recv(wasm_exec_env_t exec_env, err = 0; fail: - module_free(mem); + wasm_runtime_free(iovec_begin); return err; } @@ -1112,7 +1107,6 @@ wasi_sock_send(wasm_exec_env_t exec_env, wasi_ciovec_t *ciovec, *ciovec_begin; uint64 total_size; size_t so_datalen; - uint32 mem; uint32 i; wasi_errno_t err; @@ -1127,7 +1121,7 @@ wasi_sock_send(wasm_exec_env_t exec_env, total_size = sizeof(wasi_ciovec_t) * (uint64)si_data_len; if (total_size >= UINT32_MAX - || !(mem = module_malloc((uint32)total_size, (void**)&ciovec_begin))) + || !(ciovec_begin = wasm_runtime_malloc((uint32)total_size))) return (wasi_errno_t)-1; ciovec = ciovec_begin; @@ -1153,7 +1147,7 @@ wasi_sock_send(wasm_exec_env_t exec_env, err = 0; fail: - module_free(mem); + wasm_runtime_free(ciovec_begin); return err; } diff --git a/doc/build_wasm_app.md b/doc/build_wasm_app.md index b110de3b8..ba1927837 100644 --- a/doc/build_wasm_app.md +++ b/doc/build_wasm_app.md @@ -64,18 +64,19 @@ There are some useful options which can be specified to build the source code: - **-Wl,--shared-memory** Use shared linear memory -- **-Wl,--threads** or **-Wl,--no-threads** Run or do not run the linker multi-threaded - - **-Wl,--allow-undefined** Allow undefined symbols in linked binary - **-Wl,--allow-undefined-file=** Allow symbols listed in to be undefined in linked binary +- **-pthread** Support POSIX threads in generated code + For example, we can build the wasm app with command: ``` Bash /opt/wasi-sdk/bin/clang -O3 -nostdlib \ -z stack-size=8192 -Wl,--initial-memory=65536 \ - -Wl,--export=main -o test.wasm test.c \ - -Wl,--export=__heap_base,--export=__data_end \ + -o test.wasm test.c \ + -Wl,--export=main -Wl,--export=__main_argc_argv \ + -Wl,--export=__heap_base -Wl,--export=__data_end \ -Wl,--no-entry -Wl,--strip-all -Wl,--allow-undefined ``` to generate a wasm binary with small footprint. diff --git a/product-mini/app-samples/hello-world/build.sh b/product-mini/app-samples/hello-world/build.sh index 4d4fb0ee8..5dc612bca 100755 --- a/product-mini/app-samples/hello-world/build.sh +++ b/product-mini/app-samples/hello-world/build.sh @@ -3,13 +3,23 @@ WAMR_DIR=${PWD}/../../.. -/opt/wasi-sdk/bin/clang \ - --target=wasm32 -O3 \ +echo "Build wasm app .." +/opt/wasi-sdk/bin/clang -O3 \ -z stack-size=4096 -Wl,--initial-memory=65536 \ - --sysroot=${WAMR_DIR}/wamr-sdk/app/libc-builtin-sysroot \ - -Wl,--allow-undefined-file=${WAMR_DIR}/wamr-sdk/app/libc-builtin-sysroot/share/defined-symbols.txt \ - -Wl,--export=main, \ - -Wl,--export=__data_end, -Wl,--export=__heap_base \ - -Wl,--no-threads,--strip-all,--no-entry \ - -nostdlib -o test.wasm *.c -#./jeffdump -o test_wasm.h -n wasm_test_file test.wasm + -o test.wasm main.c \ + -Wl,--export=main -Wl,--export=__main_argc_argv \ + -Wl,--export=__data_end -Wl,--export=__heap_base \ + -Wl,--strip-all,--no-entry \ + -Wl,--allow-undefined \ + -nostdlib \ + +echo "Build binarydump tool .." +rm -fr build && mkdir build && cd build +cmake ../../../../test-tools/binarydump-tool +make +cd .. + +echo "Generate test_wasm.h .." +./build/binarydump -o test_wasm.h -n wasm_test_file test.wasm + +echo "Done" diff --git a/samples/basic/build.sh b/samples/basic/build.sh index cb195efd7..253ee2776 100755 --- a/samples/basic/build.sh +++ b/samples/basic/build.sh @@ -46,7 +46,7 @@ OUT_FILE=${i%.*}.wasm --target=wasm32 -O0 -z stack-size=4096 -Wl,--initial-memory=65536 \ --sysroot=${WAMR_DIR}/wamr-sdk/app/libc-builtin-sysroot \ -Wl,--allow-undefined-file=${WAMR_DIR}/wamr-sdk/app/libc-builtin-sysroot/share/defined-symbols.txt \ - -Wl,--no-threads,--strip-all,--no-entry -nostdlib \ + -Wl,--strip-all,--no-entry -nostdlib \ -Wl,--export=generate_float \ -Wl,--export=float_to_string \ -Wl,--export=calculate\ diff --git a/samples/gui/wasm-apps/decrease/Makefile b/samples/gui/wasm-apps/decrease/Makefile index 6e18fc73c..d99008beb 100644 --- a/samples/gui/wasm-apps/decrease/Makefile +++ b/samples/gui/wasm-apps/decrease/Makefile @@ -21,8 +21,8 @@ all: --target=wasm32 -O3 -z stack-size=2048 -Wl,--initial-memory=65536 \ --sysroot=$(SDK_DIR)/libc-builtin-sysroot \ -L$(APP_FRAMEWORK_DIR)/lib -lapp_framework \ - -Wl,--allow-undefined-file=$(SDK_DIR)/libc-builtin-sysroot/share/defined-symbols.txt \ - -Wl,--no-threads,--strip-all,--no-entry -nostdlib \ + -Wl,--allow-undefined-file=$(SDK_DIR)/libc-builtin-sysroot/share/defined-symbols.txt \ + -Wl,--strip-all,--no-entry -nostdlib \ -Wl,--export=on_init -Wl,--export=on_timer_callback \ -Wl,--export=on_widget_event \ -Wl,--export=__heap_base,--export=__data_end \ diff --git a/samples/gui/wasm-apps/increase/Makefile b/samples/gui/wasm-apps/increase/Makefile index 3e49913e0..2c150332a 100644 --- a/samples/gui/wasm-apps/increase/Makefile +++ b/samples/gui/wasm-apps/increase/Makefile @@ -27,7 +27,7 @@ all: @$(CC) $(CFLAGS) $(SRCS) \ --target=wasm32 -O3 -z stack-size=2048 -Wl,--initial-memory=65536 \ -Wl,--allow-undefined \ - -Wl,--no-threads,--strip-all,--no-entry -nostdlib \ + -Wl,--strip-all,--no-entry -nostdlib \ -Wl,--export=on_init -Wl,--export=on_timer_callback \ -Wl,--export=on_widget_event \ -Wl,--export=__heap_base,--export=__data_end \ diff --git a/samples/littlevgl/wasm-apps/Makefile_wasm_app b/samples/littlevgl/wasm-apps/Makefile_wasm_app index adbeddcc5..8c053cc6d 100644 --- a/samples/littlevgl/wasm-apps/Makefile_wasm_app +++ b/samples/littlevgl/wasm-apps/Makefile_wasm_app @@ -49,9 +49,9 @@ all: @$(CC) $(CFLAGS) $(SRCS) \ -O3 -z stack-size=2048 -Wl,--initial-memory=65536 \ -DLV_CONF_INCLUDE_SIMPLE \ - -L$(APP_FRAMEWORK_DIR)/lib -lapp_framework \ + -L$(APP_FRAMEWORK_DIR)/lib -lapp_framework \ -Wl,--allow-undefined \ - -Wl,--no-threads,--strip-all,--no-entry \ + -Wl,--strip-all,--no-entry \ -Wl,--export=on_init -Wl,--export=on_timer_callback \ -Wl,--export=__heap_base,--export=__data_end \ -o ui_app_wasi.wasm diff --git a/samples/littlevgl/wasm-apps/Makefile_wasm_app_no_wasi b/samples/littlevgl/wasm-apps/Makefile_wasm_app_no_wasi index 435934a52..d18c0a222 100644 --- a/samples/littlevgl/wasm-apps/Makefile_wasm_app_no_wasi +++ b/samples/littlevgl/wasm-apps/Makefile_wasm_app_no_wasi @@ -52,8 +52,8 @@ all: --sysroot=$(WAMR_DIR)/wamr-sdk/app/libc-builtin-sysroot \ -O3 -z stack-size=2048 -Wl,--initial-memory=65536 \ -DLV_CONF_INCLUDE_SIMPLE \ - -L$(APP_FRAMEWORK_DIR)/lib -lapp_framework \ + -L$(APP_FRAMEWORK_DIR)/lib -lapp_framework \ -Wl,--allow-undefined \ - -Wl,--no-threads,--strip-all,--no-entry -nostdlib \ + -Wl,--strip-all,--no-entry -nostdlib \ -Wl,--export=on_init -Wl,--export=on_timer_callback \ -o ui_app_builtin_libc.wasm diff --git a/samples/multi-thread/wasm-apps/CMakeLists.txt b/samples/multi-thread/wasm-apps/CMakeLists.txt index 171c5e01d..44ced1cc8 100644 --- a/samples/multi-thread/wasm-apps/CMakeLists.txt +++ b/samples/multi-thread/wasm-apps/CMakeLists.txt @@ -27,11 +27,13 @@ set (DEFINED_SYMBOLS "${WAMR_ROOT_DIR}/wamr-sdk/app/libc-builtin-sysroot/share/defined-symbols.txt") set (CMAKE_EXE_LINKER_FLAGS - "-Wl,--shared-memory,--max-memory=131072, \ - -Wl,--no-entry,--strip-all,--export=main, \ - -Wl,--export=__heap_base,--export=__data_end \ - -Wl,--export=__wasm_call_ctors \ - -Wl,--allow-undefined-file=${DEFINED_SYMBOLS}" + "-Wl,--shared-memory,--max-memory=131072, \ + -Wl,--no-entry,--strip-all, \ + -Wl,--export=__heap_base,--export=__data_end \ + -Wl,--export=__wasm_call_ctors \ + -Wl,--export=main -Wl,--export=__main_argc_argv \ + -Wl,--allow-undefined" + #-Wl,--allow-undefined-file=${DEFINED_SYMBOLS}" ) add_executable(test.wasm main.c) diff --git a/samples/simple/build.sh b/samples/simple/build.sh index ef67aea5d..e95092d21 100755 --- a/samples/simple/build.sh +++ b/samples/simple/build.sh @@ -153,7 +153,7 @@ OUT_FILE=${i%.*}.wasm --target=wasm32 -O3 -z stack-size=4096 -Wl,--initial-memory=65536 \ --sysroot=${WAMR_DIR}/wamr-sdk/out/$PROFILE/app-sdk/libc-builtin-sysroot \ -Wl,--allow-undefined-file=${WAMR_DIR}/wamr-sdk/out/$PROFILE/app-sdk/libc-builtin-sysroot/share/defined-symbols.txt \ - -Wl,--no-threads,--strip-all,--no-entry -nostdlib \ + -Wl,--strip-all,--no-entry -nostdlib \ -Wl,--export=on_init -Wl,--export=on_destroy \ -Wl,--export=on_request -Wl,--export=on_response \ -Wl,--export=on_sensor_event -Wl,--export=on_timer_callback \ diff --git a/test-tools/component_test/suites/01-life-cycle/test-app/build.sh b/test-tools/component_test/suites/01-life-cycle/test-app/build.sh index 7ea7f3129..4b5428051 100755 --- a/test-tools/component_test/suites/01-life-cycle/test-app/build.sh +++ b/test-tools/component_test/suites/01-life-cycle/test-app/build.sh @@ -20,11 +20,11 @@ OUT_FILE=${i%.*}.wasm -Wno-int-conversion \ -I${APP_FRAMEWORK_DIR}/include \ -I${DEPS_DIR} \ - --target=wasm32 -O3 -z stack-size=4096 -Wl,--initial-memory=65536 \ - --sysroot=${SDK_DIR}/app-sdk/libc-builtin-sysroot \ - -L${APP_FRAMEWORK_DIR}/lib -lapp_framework \ - -Wl,--allow-undefined-file=${SDK_DIR}/app-sdk/libc-builtin-sysroot/share/defined-symbols.txt \ - -Wl,--no-threads,--strip-all,--no-entry -nostdlib \ + -O3 -z stack-size=4096 -Wl,--initial-memory=65536 \ + --sysroot=${SDK_DIR}/app-sdk/libc-builtin-sysroot \ + -L${APP_FRAMEWORK_DIR}/lib -lapp_framework \ + -Wl,--allow-undefined-file=${SDK_DIR}/app-sdk/libc-builtin-sysroot/share/defined-symbols.txt \ + -Wl,--strip-all,--no-entry -nostdlib \ -Wl,--export=on_init -Wl,--export=on_destroy \ -Wl,--export=on_request -Wl,--export=on_response \ -Wl,--export=on_sensor_event -Wl,--export=on_timer_callback \ @@ -36,4 +36,4 @@ if [ -f ${OUT_FILE} ]; then else echo "build ${OUT_FILE} fail" fi -done \ No newline at end of file +done diff --git a/wamr-sdk/app/wamr_toolchain.cmake b/wamr-sdk/app/wamr_toolchain.cmake index c2e0cdff1..17fc35d20 100644 --- a/wamr-sdk/app/wamr_toolchain.cmake +++ b/wamr-sdk/app/wamr_toolchain.cmake @@ -18,7 +18,7 @@ SET (CMAKE_CXX_COMPILER_TARGET "wasm32") SET (CMAKE_CXX_COMPILER "${WASI_SDK_DIR}/bin/clang++") SET (CMAKE_EXE_LINKER_FLAGS - "-Wl,--initial-memory=65536,--no-entry,--no-threads,--strip-all" CACHE INTERNAL "") + "-Wl,--initial-memory=65536,--no-entry,--strip-all" CACHE INTERNAL "") SET (CMAKE_LINKER "${WASI_SDK_DIR}/bin/wasm-ld" CACHE INTERNAL "") SET (CMAKE_AR "${WASI_SDK_DIR}/bin/llvm-ar" CACHE INTERNAL "") From 365ec6360becd551ffd11cc10022b5069459e0b6 Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Tue, 29 Dec 2020 00:41:09 -0600 Subject: [PATCH 134/207] Update build scripts and documents of workload samples for wasi-sdk-12.0 (#484) Update the build scripts of sample workloads (meshoptimizer/bwa/wasm-av1) to use the wasi-sdk-12.0 firstly to build the workload and discard clang-11, as wasi-sdk-12 supports wasi, simd and pthread better. And update the related documents. Also modify wasm mini loader to sync up with the change of wasm normal loader. Signed-off-by: Wenyong Huang --- core/iwasm/interpreter/wasm_mini_loader.c | 53 ++------- samples/workload/README.md | 30 ++---- samples/workload/XNNPACK/README.md | 3 +- samples/workload/bwa/CMakeLists.bwa_wasm.txt | 1 + samples/workload/bwa/CMakeLists.txt | 37 ++++++- samples/workload/bwa/README.md | 7 +- samples/workload/cmake/toolchain.cmake | 102 ------------------ samples/workload/docker/Dockerfile | 46 ++++---- samples/workload/docker/docker_build.sh | 45 +++----- samples/workload/meshoptimizer/CMakeLists.txt | 37 ++++++- samples/workload/meshoptimizer/README.md | 16 ++- .../workload/meshoptimizer/codecbench.patch | 5 +- samples/workload/preparation.sh | 44 ++++---- samples/workload/tensorflow/README.md | 3 +- samples/workload/wasm-av1/CMakeLists.txt | 37 ++++++- samples/workload/wasm-av1/README.md | 44 ++++---- 16 files changed, 227 insertions(+), 283 deletions(-) delete mode 100644 samples/workload/cmake/toolchain.cmake diff --git a/core/iwasm/interpreter/wasm_mini_loader.c b/core/iwasm/interpreter/wasm_mini_loader.c index 27085b0af..d082d46a1 100644 --- a/core/iwasm/interpreter/wasm_mini_loader.c +++ b/core/iwasm/interpreter/wasm_mini_loader.c @@ -33,42 +33,10 @@ set_error_buf(char *error_buf, uint32 error_buf_size, const char *string) bh_assert(buf + length <= buf_end); \ } while (0) -static void -skip_leb(const uint8 **p_buf, const uint8 *buf_end, uint32 maxbits, - char* error_buf, uint32 error_buf_size) -{ - const uint8 *buf = *p_buf; - uint32 offset = 0, bcnt = 0; - uint64 byte; - - while (true) { - bh_assert(bcnt + 1 <= (maxbits + 6) / 7); - CHECK_BUF(buf, buf_end, offset + 1); - byte = buf[offset]; - offset += 1; - bcnt += 1; - if ((byte & 0x80) == 0) { - break; - } - } - - *p_buf += offset; -} - -#define skip_leb_int64(p, p_end) do { \ - skip_leb(&p, p_end, 64, \ - error_buf, error_buf_size); \ - } while (0) - -#define skip_leb_uint32(p, p_end) do { \ - skip_leb(&p, p_end, 32, \ - error_buf, error_buf_size); \ - } while (0) - -#define skip_leb_int32(p, p_end) do { \ - skip_leb(&p, p_end, 32, \ - error_buf, error_buf_size); \ - } while (0) +#define skip_leb(p) while (*p++ & 0x80) +#define skip_leb_int64(p, p_end) skip_leb(p) +#define skip_leb_uint32(p, p_end) skip_leb(p) +#define skip_leb_int32(p, p_end) skip_leb(p) static void read_leb(uint8 **p_buf, const uint8 *buf_end, @@ -2149,17 +2117,17 @@ wasm_loader_find_block_addr(BlockAddr *block_addr_cache, const uint8 *code_end_addr, uint8 label_type, uint8 **p_else_addr, - uint8 **p_end_addr, - char *error_buf, - uint32 error_buf_size) + uint8 **p_end_addr) { const uint8 *p = start_addr, *p_end = code_end_addr; uint8 *else_addr = NULL; + char error_buf[128]; uint32 block_nested_depth = 1, count, i, j, t; + uint32 error_buf_size = sizeof(error_buf); uint8 opcode, u8; BlockAddr block_stack[16] = { 0 }, *block; - i = ((uintptr_t)start_addr) % BLOCK_ADDR_CACHE_SIZE; + i = ((uintptr_t)start_addr) & (uintptr_t)(BLOCK_ADDR_CACHE_SIZE - 1); block = block_addr_cache + BLOCK_ADDR_CONFLICT_SIZE * i; for (j = 0; j < BLOCK_ADDR_CONFLICT_SIZE; j++) { @@ -2185,7 +2153,6 @@ wasm_loader_find_block_addr(BlockAddr *block_addr_cache, case WASM_OP_BLOCK: case WASM_OP_LOOP: case WASM_OP_IF: - CHECK_BUF(p, p_end, 1); /* block result type: 0x40/0x7F/0x7E/0x7D/0x7C */ u8 = read_uint8(p); if (block_nested_depth < sizeof(block_stack)/sizeof(BlockAddr)) { @@ -2224,7 +2191,8 @@ wasm_loader_find_block_addr(BlockAddr *block_addr_cache, for (t = 0; t < sizeof(block_stack)/sizeof(BlockAddr); t++) { start_addr = block_stack[t].start_addr; if (start_addr) { - i = ((uintptr_t)start_addr) % BLOCK_ADDR_CACHE_SIZE; + i = ((uintptr_t)start_addr) + & (uintptr_t)(BLOCK_ADDR_CACHE_SIZE - 1); block = block_addr_cache + BLOCK_ADDR_CONFLICT_SIZE * i; for (j = 0; j < BLOCK_ADDR_CONFLICT_SIZE; j++) if (!block[j].start_addr) @@ -4669,7 +4637,6 @@ handle_op_block_and_loop: #endif POP_I32(); - /* TODO: check the const */ for (i = 0; i <= count; i++) { if (!(frame_csp_tmp = check_branch_block(loader_ctx, &p, p_end, diff --git a/samples/workload/README.md b/samples/workload/README.md index 2af6ec6bd..624126cbc 100644 --- a/samples/workload/README.md +++ b/samples/workload/README.md @@ -1,8 +1,8 @@ -All workloads have similar a requirment of software dependencies. It includes -**wasi-sdk**, **clang-11**, **emsdk**, **wabt** and **binaryen** +All workloads have similar requirment of software dependencies, including +**wasi-sdk**, **emsdk**, **wabt** and **binaryen** -> It might slightly different when using MacOS, and other linux distro than Ubuntu. This document only target -Ubuntu 18.04 as an example. +> There might be slight differences when using MacOS and other Linux distro than Ubuntu. This document only target +Ubuntu 18.04 as example. ## Installation instructions @@ -11,28 +11,16 @@ use [preparation.sh](./preparation.sh) to install all dependencies before compil for details, the script includes below steps: - **wasi-sdk**. Install - [latest release](https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-11/wasi-sdk-11.0-linux.tar.gz) - in */opt/wasi-sdk* or */opt/wasi-sdk-11* + [latest release](https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk-12.0-linux.tar.gz) + to */opt/wasi-sdk* - **wabt**. Install - [latest release](https://github.com/WebAssembly/wabt/releases/download/${WABT_VER}/wabt-1.0.19-ubuntu.tar.gz) - in */opt/wabt* or */opt/wabt-1.0.19* - -- **clang-11**. Refer to [the guide](https://apt.llvm.org/). + [latest release](https://github.com/WebAssembly/wabt/releases/download/1.0.20/wabt-1.0.20-ubuntu.tar.gz) + to */opt/wabt* or */opt/wabt-1.0.20* - **emsdk**. Refer to [the guide](https://emscripten.org/docs/getting_started/downloads.html). Don't forget to activate emsdk and set up environment variables. Verify it with `echo ${EMSDK}`. -- **libclang_rt.builtins-wasm32.a**. *wasi* has its private rt library. Put it under clang search path - -``` shell -# copy it -$ cp -r /opt/wasi-sdk-11.0/lib/clang/10.0.0/lib/wasi /usr/lib/llvm-11/lib/clang/11.0.0/lib/ - -# or just link it -$ ln -sf /opt/wasi-sdk-11.0/lib/clang/10.0.0/lib/wasi/ /usr/lib/llvm-11/lib/clang/11.0.0/lib/ -``` - - **binaryen**. Install [latest release](https://github.com/WebAssembly/binaryen/releases/download/version_97/binaryen-version_97-x86_64-linux.tar.gz) - in */opt/binaryen* or */opt/binaryen-version_97* + to */opt/binaryen* or */opt/binaryen-version_97* diff --git a/samples/workload/XNNPACK/README.md b/samples/workload/XNNPACK/README.md index a34f66217..ffbe23610 100644 --- a/samples/workload/XNNPACK/README.md +++ b/samples/workload/XNNPACK/README.md @@ -1,6 +1,7 @@ "XNNPACK" sample introduction ============== -This sample demonstrates how to build [XNNPACK](https://github.com/google/XNNPACK) benchmarks into WebAssembly with emcc toolchain and run them with iwasm. + +This sample demonstrates how to build [XNNPACK](https://github.com/google/XNNPACK) benchmarks into WebAssembly with emsdk toolchain and run them with iwasm. ## Installation toolchains diff --git a/samples/workload/bwa/CMakeLists.bwa_wasm.txt b/samples/workload/bwa/CMakeLists.bwa_wasm.txt index 8cda6b694..f315bf9c2 100644 --- a/samples/workload/bwa/CMakeLists.bwa_wasm.txt +++ b/samples/workload/bwa/CMakeLists.bwa_wasm.txt @@ -102,6 +102,7 @@ target_compile_options(${PROJECT_NAME} PRIVATE -Wno-unused-function -Wno-unused-variable + -msimd128 ) target_link_options(${PROJECT_NAME} diff --git a/samples/workload/bwa/CMakeLists.txt b/samples/workload/bwa/CMakeLists.txt index 6e785a149..5c1d4a8f8 100644 --- a/samples/workload/bwa/CMakeLists.txt +++ b/samples/workload/bwa/CMakeLists.txt @@ -5,6 +5,38 @@ cmake_minimum_required (VERSION 3.0) project(bwa_wasm) +################ WASI-SDK ################ +find_path(WASI_SDK_HOME + NAMES wasi-sdk + PATHS /opt/ + REQUIRED +) + +if (NOT WASI_SDK_HOME) + message(FATAL_ERROR + "can not find wasi-sdk. " + "please download it from " + "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk-12.0-linux.tar.gz " + "and install it under /opt/wasi-sdk" + ) +endif() + +# +# check clang version +execute_process(COMMAND + ${WASI_SDK_HOME}/wasi-sdk/bin/clang --version + OUTPUT_VARIABLE clang_full_version_string +) +string(REGEX REPLACE ".*clang version ([0-9]+\\.[0-9]+).*" "\\1" + CLANG_VERSION_STRING ${clang_full_version_string} +) +message("cur clang version is ${CLANG_VERSION_STRING}") +if(CLANG_VERSION_STRING VERSION_LESS 11.0) + message(FATAL_ERROR + "please install latest wai-sdk to get a clang-11 at least" + ) +endif() + ################ EMCC ################ if(NOT DEFINED ENV{EMSDK}) message(FATAL_ERROR @@ -85,7 +117,10 @@ ExternalProject_Add(bwa UPDATE_COMMAND git clean -fd && git checkout -- * && ${CMAKE_COMMAND} -E echo "Copying pre-installed CMakeLists.txt" && ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.bwa_wasm.txt CMakeLists.txt - CONFIGURE_COMMAND ${CMAKE_COMMAND} -DCMAKE_TOOLCHAIN_FILE=${CMAKE_CURRENT_SOURCE_DIR}/../cmake/toolchain.cmake ${CMAKE_CURRENT_SOURCE_DIR}/bwa + CONFIGURE_COMMAND ${CMAKE_COMMAND} + -DWASI_SDK_PREFIX=${WASI_SDK_HOME}/wasi-sdk + -DCMAKE_TOOLCHAIN_FILE=${WASI_SDK_HOME}/wasi-sdk/share/cmake/wasi-sdk.cmake + ${CMAKE_CURRENT_SOURCE_DIR}/bwa BUILD_COMMAND make bwa_wasm_opt INSTALL_COMMAND ${CMAKE_COMMAND} -E copy ./bwa.opt.wasm ${CMAKE_CURRENT_SOURCE_DIR}/build/bwa.wasm ) diff --git a/samples/workload/bwa/README.md b/samples/workload/bwa/README.md index f9688f6ca..e826bb61f 100644 --- a/samples/workload/bwa/README.md +++ b/samples/workload/bwa/README.md @@ -40,8 +40,7 @@ $ make Then compile wasm file to aot file and run: ``` shell -$ cd /wamr-compiler/build -$ ./wamrc --enable-simd -o bwa.aot ./bwa.wasm -$ cd /product-mini/platforms/linux/ -$ ./iwasm --dir=. ./bwa.aot index hs38DH.fa +$ cd /samples/workload/bwa/build +$ /wamr-compiler/build/wamrc --enable-simd -o bwa.aot bwa.wasm +$ /product-mini/platforms/linux/iwasm --dir=. bwa.aot index hs38DH.fa ``` diff --git a/samples/workload/cmake/toolchain.cmake b/samples/workload/cmake/toolchain.cmake deleted file mode 100644 index 855913235..000000000 --- a/samples/workload/cmake/toolchain.cmake +++ /dev/null @@ -1,102 +0,0 @@ -# Copyright (C) 2019 Intel Corporation. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -cmake_minimum_required (VERSION 3.0) - -if(DEFINED _WAMR_TOOLCHAIN_CMAKE_) - return() -else() - set(_WAMR_TOOLCHAIN_CMAKE_ 1) -endif() - -SET(CMAKE_SYSTEM_NAME Linux) - -################ COMPILER ################ -find_program(CLANG_11 NAMES clang clang-11 REQUIRED) -find_program(CLANG++_11 NAMES clang++ clang++-11 REQUIRED) - -if(NOT CLANG_11) - message(FATAL_ERROR "clang not found") -else() - message(STATUS "use ${CLANG_11} as the c compiler") -endif() - -if(NOT CLANG++_11) - message(FATAL_ERROR "clang++ not found") -else() - message(STATUS "use ${CLANG++_11} as the c++ compiler") -endif() - -set(CMAKE_C_COMPILER "${CLANG_11}" CACHE STRING "C compiler" FORCE) -set(CMAKE_C_COMPILER_ID Clang CACHE STRING "C compiler ID" FORCE) - -set(CMAKE_CXX_COMPILER "${CLANG++_11}" CACHE STRING "C++ compiler" FORCE) -set(CMAKE_CXX_COMPILER_ID Clang CACHE STRING "C++ compiler ID" FORCE) - -################ WASI AS SYSROOT ################ -find_path(WASI_SYSROOT - wasi-sysroot - PATHS /opt/wasi-sdk-11.0/share /opt/wasi-sdk/share - REQUIRED -) - -if(NOT WASI_SYSROOT) - message(FATAL_ERROR - "can not find wasi sysroot. " - "please download it from " - "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-11/wasi-sdk-11.0-linux.tar.gz " - "and install it under /opt" - ) -endif() - -set(CMAKE_SYSROOT ${WASI_SYSROOT}/wasi-sysroot CACHE STRING "--sysroot to compiler" FORCE) - -add_compile_options( - --target=wasm32-wasi - -msimd128 - $,-O0,-O3> - $<$:-g> - $<$:-v> -) - -# need users to create their own additional include files - -################ AR ################ -find_program(LLVM_AR NAMES llvm-ar llvm-ar-11 REQUIRED) - -if(NOT LLVM_AR) - message(FATAL_ERROR "llvm-ar not found") -else() - message(STATUS "use ${LLVM_AR} as the AR") -endif() - -set(CMAKE_AR "${LLVM_AR}" CACHE STRING "AR" FORCE) - -################ RANLIB ################ -find_program(LLVM_RANLIB NAMES llvm-ranlib llvm-ranlib-11 REQUIRED) - -if(NOT LLVM_RANLIB) - message(FATAL_ERROR "llvm-ranlib not found") -else() - message(STATUS "use ${LLVM_RANLIB} as the ranlib") -endif() - -set(CMAKE_RANLIB "${LLVM_RANLIB}" CACHE STRING "RANLIB" FORCE) - -################ LD ################ -find_program(WASM_LD NAMES wasm-ld wasm-ld-11 REQUIRED) - -if(NOT WASM_LD) - message(FATAL_ERROR "wasm-ld not found") -else() - message(STATUS "use ${WASM_LD} as the linker") -endif() - -add_link_options( - --target=wasm32-wasi - -fuse-ld=${WASM_LD} - LINKER:--allow-undefined - $,-O0,-O3> - $<$:-g> - $<$:-v> -) diff --git a/samples/workload/docker/Dockerfile b/samples/workload/docker/Dockerfile index 8afa4738a..4c57c668b 100644 --- a/samples/workload/docker/Dockerfile +++ b/samples/workload/docker/Dockerfile @@ -1,29 +1,32 @@ FROM ubuntu:18.04 as builder +RUN apt update \ + && apt install -y lsb-release software-properties-common build-essential \ + wget curl git tree zip unzip + # # install clang and llvm -COPY llvm.sh /tmp -RUN apt update \ - && apt install -y lsb-release wget software-properties-common build-essential \ - && cd /tmp \ - && chmod a+x llvm.sh \ - && ./llvm.sh 11 +# COPY llvm.sh /tmp +# RUN apt update \ +# && apt install -y lsb-release wget software-properties-common build-essential \ +# && cd /tmp \ +# && chmod a+x llvm.sh \ +# && ./llvm.sh 11 -ARG WASI_SDK_VER=11.0 -ARG WABT_VER=1.0.19 +ARG WASI_SDK_VER=12 +ARG WABT_VER=1.0.20 ARG CMAKE_VER=3.16.2 ARG BINARYEN_VER=version_97 ARG BAZEL_VER=3.7.0 # # install wasi-sdk -ARG WASI_SDK_FILE="wasi-sdk-${WASI_SDK_VER}-linux.tar.gz" +ARG WASI_SDK_FILE="wasi-sdk-${WASI_SDK_VER}.0-linux.tar.gz" COPY ${WASI_SDK_FILE} /opt RUN cd /opt \ && tar zxf ${WASI_SDK_FILE} \ && rm ${WASI_SDK_FILE} \ - && ln -sf /opt/wasi-sdk-${WASI_SDK_VER} /opt/wasi-sdk \ - && ln -sf /opt/wasi-sdk/lib/clang/10.0.0/lib/wasi/ /usr/lib/llvm-11/lib/clang/11.0.1/lib/ + && ln -sf /opt/wasi-sdk-${WASI_SDK_VER}.0 /opt/wasi-sdk # # install wabt @@ -44,11 +47,6 @@ RUN cd /tmp \ && ./${CMAKE_FILE} --prefix=/opt/cmake --skip-license \ && ln -sf /opt/cmake/bin/cmake /usr/local/bin/cmake -# -# install tools -RUN apt update \ - && apt install -y git tree - # # install emsdk RUN cd /opt \ @@ -68,15 +66,13 @@ RUN cd /opt \ && rm ${BINARYEN_FILE} \ && ln -sf /opt/binaryen-${BINARYEN_VER} /opt/binaryen -RUN apt install -y unzip zip - -# -# install bazel -ARG BAZEL_FILE=bazel-${BAZEL_VER}-installer-linux-x86_64.sh -COPY ${BAZEL_FILE} /tmp -RUN cd /tmp \ - && chmod a+x ${BAZEL_FILE} \ - && ./${BAZEL_FILE} +# # +# # install bazel +# ARG BAZEL_FILE=bazel-${BAZEL_VER}-installer-linux-x86_64.sh +# COPY ${BAZEL_FILE} /tmp +# RUN cd /tmp \ +# && chmod a+x ${BAZEL_FILE} \ +# && ./${BAZEL_FILE} # # Clean up diff --git a/samples/workload/docker/docker_build.sh b/samples/workload/docker/docker_build.sh index a5fb54bbb..ec502d55a 100755 --- a/samples/workload/docker/docker_build.sh +++ b/samples/workload/docker/docker_build.sh @@ -1,34 +1,32 @@ +#!/usr/bin/env bash # # Copyright (C) 2019 Intel Corporation. All rights reserved. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception # -#!/bin/bash - -BUILD_CONTENT="/tmp/build_content" - +readonly BUILD_CONTENT="/tmp/build_content" if [[ ! -d ${BUILD_CONTENT} ]]; then mkdir ${BUILD_CONTENT} fi -WASI_SDK_VER=11.0 -WABT_VER=1.0.19 -CMAKE_VER=3.16.2 -BINARYEN_VER=version_97 -BAZEL_VER=3.7.0 +readonly WASI_SDK_VER=12 +readonly WABT_VER=1.0.20 +readonly CMAKE_VER=3.16.2 +readonly BINARYEN_VER=version_97 +readonly BAZEL_VER=3.7.0 -cd ${BUILD_CONTENT} -if [[ ! -f wasi-sdk-${WASI_SDK_VER}-linux.tar.gz ]]; then - wget https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-11/wasi-sdk-${WASI_SDK_VER}-linux.tar.gz +cd ${BUILD_CONTENT} || exit +if [[ ! -f wasi-sdk-${WASI_SDK_VER}.0-linux.tar.gz ]]; then + wget https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-${WASI_SDK_VER}/wasi-sdk-${WASI_SDK_VER}.0-linux.tar.gz fi if [[ ! -f wabt-${WABT_VER}-ubuntu.tar.gz ]]; then wget https://github.com/WebAssembly/wabt/releases/download/${WABT_VER}/wabt-${WABT_VER}-ubuntu.tar.gz fi -if [[ ! -f llvm.sh ]]; then - wget https://apt.llvm.org/llvm.sh -fi +# if [[ ! -f llvm.sh ]]; then +# wget https://apt.llvm.org/llvm.sh +# fi if [[ ! -f cmake-${CMAKE_VER}-Linux-x86_64.sh ]]; then wget https://github.com/Kitware/CMake/releases/download/v${CMAKE_VER}/cmake-${CMAKE_VER}-Linux-x86_64.sh @@ -41,30 +39,21 @@ fi if [[ ! -f bazel-${BAZEL_VER}-installer-linux-x86_64.sh ]]; then wget https://github.com/bazelbuild/bazel/releases/download/${BAZEL_VER}/bazel-${BAZEL_VER}-installer-linux-x86_64.sh fi -cd - > /dev/null +cd - > /dev/null || exit -DOCKERFILE_PATH=$(dirname $(realpath $0)) +DOCKERFILE_PATH=$(dirname "$(realpath "$0")") docker build \ - --build-arg http_proxy=${http_proxy} \ - --build-arg https_proxy=${https_proxy} \ - --build-arg HTTP_PROXY=${http_proxy} \ - --build-arg HTTPS_PROXY=${https_proxy} \ --build-arg WASI_SDK_VER=${WASI_SDK_VER} \ --build-arg WABT_VER=${WABT_VER} \ --build-arg CMAKE_VER=${CMAKE_VER} \ --build-arg BINARYEN_VER=${BINARYEN_VER} \ --build-arg BAZEL_VER=${BAZEL_VER} \ - -t clang_env:0.1 -f ${DOCKERFILE_PATH}/Dockerfile ${BUILD_CONTENT} + -t clang_env:0.1 -f "${DOCKERFILE_PATH}"/Dockerfile ${BUILD_CONTENT} docker run --rm -it \ - -e http_proxy=${http_proxy} \ - -e https_proxy=${https_proxy} \ - -e HTTP_PROXY=${http_proxy} \ - -e HTTPS_PROXY=${htpps_proxy} \ --name workload_w_clang \ - --mount type=bind,source=$(pwd),target=/data/project \ - --mount type=bind,source=$(pwd)/../cmake,target=/data/cmake \ + --mount type=bind,source="$(pwd)",target=/data/project \ -w /data/project \ clang_env:0.1 \ /bin/bash -c /build.sh diff --git a/samples/workload/meshoptimizer/CMakeLists.txt b/samples/workload/meshoptimizer/CMakeLists.txt index 1270582df..1ac8ee18d 100644 --- a/samples/workload/meshoptimizer/CMakeLists.txt +++ b/samples/workload/meshoptimizer/CMakeLists.txt @@ -5,6 +5,38 @@ cmake_minimum_required (VERSION 3.0) project(bench-meshoptimizer) +################ WASI-SDK ################ +find_path(WASI_SDK_HOME + NAMES wasi-sdk + PATHS /opt/ + REQUIRED +) + +if (NOT WASI_SDK_HOME) + message(FATAL_ERROR + "can not find wasi-sdk. " + "please download it from " + "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk-12.0-linux.tar.gz " + "and install it under /opt/wasi-sdk" + ) +endif() + +# +# check clang version +execute_process(COMMAND + ${WASI_SDK_HOME}/wasi-sdk/bin/clang --version + OUTPUT_VARIABLE clang_full_version_string +) +string(REGEX REPLACE ".*clang version ([0-9]+\\.[0-9]+).*" "\\1" + CLANG_VERSION_STRING ${clang_full_version_string} +) +message("cur clang version is ${CLANG_VERSION_STRING}") +if(CLANG_VERSION_STRING VERSION_LESS 11.0) + message(FATAL_ERROR + "please install latest wai-sdk to get a clang-11 at least" + ) +endif() + ################ BINARYEN ################ find_program(WASM_OPT NAMES wasm-opt @@ -33,7 +65,10 @@ ExternalProject_Add(codecbench UPDATE_COMMAND git clean -fd && git checkout -- * && ${CMAKE_COMMAND} -E echo "Applying patch" && git apply ${CMAKE_CURRENT_SOURCE_DIR}/codecbench.patch - CONFIGURE_COMMAND ${CMAKE_COMMAND} -DCMAKE_TOOLCHAIN_FILE=${CMAKE_CURRENT_SOURCE_DIR}/../cmake/toolchain.cmake ${CMAKE_CURRENT_SOURCE_DIR}/meshoptimizer + CONFIGURE_COMMAND ${CMAKE_COMMAND} + -DWASI_SDK_PREFIX=${WASI_SDK_HOME}/wasi-sdk + -DCMAKE_TOOLCHAIN_FILE=${WASI_SDK_HOME}/wasi-sdk/share/cmake/wasi-sdk.cmake + ${CMAKE_CURRENT_SOURCE_DIR}/meshoptimizer BUILD_COMMAND make codecbench.opt INSTALL_COMMAND ${CMAKE_COMMAND} -E copy ./codecbench.opt.wasm ${CMAKE_CURRENT_SOURCE_DIR}/build/codecbench.wasm ) diff --git a/samples/workload/meshoptimizer/README.md b/samples/workload/meshoptimizer/README.md index c29a07afd..92e10391e 100644 --- a/samples/workload/meshoptimizer/README.md +++ b/samples/workload/meshoptimizer/README.md @@ -8,7 +8,7 @@ WebAssembly with simd support and run it with iwasm. please refer to [installation instructions](../README.md). -## Build with clang-11 and wasi-sdk +## Build with wasi-sdk ``` shell $ mkdir build && cd build @@ -18,15 +18,15 @@ $ make $ ls codecbench.wasm ``` -## Or build with EMCC +## Or build with EMSDK -EMCC is another toolchain to compile C code to WASM. In this case, will have -a higher performance with EMCC. +EMSDK is another toolchain to compile C/C++ code to WASM. In this case, the output wasm file +might have a higher performance than the file generated by wasi-sdk. ``` shell $ git clone https://github.com/zeux/meshoptimizer.git $ cd messoptimizer -$ emcc tools/codecbench.cpp src/vertexcodec.cpp src/vertexfilter.cpp \ +$ em++ tools/codecbench.cpp src/vertexcodec.cpp src/vertexfilter.cpp \ src/overdrawanalyzer.cpp src/indexgenerator.cpp src/vcacheoptimizer.cpp \ src/clusterizer.cpp src/indexcodec.cpp src/vfetchanalyzer.cpp \ src/spatialorder.cpp src/allocator.cpp src/vcacheanalyzer.cpp \ @@ -51,9 +51,7 @@ $ make Then compile wasm file to aot file and run: ``` shell -$ cd /wamr-compiler/build -$ ./wamrc --enable-simd -o codecbench.aot codecbench.wasm -$ cd /product-mini/platforms/linux/ -$ ./iwasm codecbench.aot +$ /wamr-compiler/build/wamrc --enable-simd -o codecbench.aot codecbench.wasm +$ /product-mini/platforms/linux/build/iwasm codecbench.aot ``` diff --git a/samples/workload/meshoptimizer/codecbench.patch b/samples/workload/meshoptimizer/codecbench.patch index 4adebed4b..2d6e9d4fa 100644 --- a/samples/workload/meshoptimizer/codecbench.patch +++ b/samples/workload/meshoptimizer/codecbench.patch @@ -1,8 +1,8 @@ diff --git a/CMakeLists.txt b/CMakeLists.txt -index eccc49e..dac126c 100644 +index ffdb4da..536a5c8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt -@@ -127,3 +127,42 @@ install(FILES +@@ -127,3 +127,43 @@ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/meshoptimizerConfig.cmake ${CMAKE_CURRENT_BINARY_DIR}/meshoptimizerConfigVersion.cmake DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/meshoptimizer) @@ -16,6 +16,7 @@ index eccc49e..dac126c 100644 + +target_compile_options(codecbench + PUBLIC ++ -O3 -msimd128 + -std=c++11 + -Wno-unused-function + -Wno-unused-variable diff --git a/samples/workload/preparation.sh b/samples/workload/preparation.sh index 81b1aea2c..1d086f109 100755 --- a/samples/workload/preparation.sh +++ b/samples/workload/preparation.sh @@ -1,9 +1,13 @@ #!/bin/bash +# +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# readonly BUILD_CONTENT="/tmp/build_content" -readonly WASI_SDK_VER=11.0 -readonly WASI_SDK_FILE="wasi-sdk-${WASI_SDK_VER}-linux.tar.gz" -readonly WABT_VER=1.0.19 +readonly WASI_SDK_VER=12 +readonly WASI_SDK_FILE="wasi-sdk-${WASI_SDK_VER}.0-linux.tar.gz" +readonly WABT_VER=1.0.20 readonly WABT_FILE="wabt-${WABT_VER}-ubuntu.tar.gz" readonly CMAKE_VER=3.16.2 readonly CMAKE_FILE="cmake-${CMAKE_VER}-Linux-x86_64.sh" @@ -13,7 +17,7 @@ readonly BAZEL_VER=3.7.0 readonly BAZEL_FILE=bazel-${BAZEL_VER}-installer-linux-x86_64.sh function DEBUG() { - [[ -n $(env | grep "\") ]] + env | grep -q "\" } # @@ -26,25 +30,24 @@ function install_deps() { # # install clang -function install_clang() { - if [[ ! -f llvm.sh ]]; then - wget https://apt.llvm.org/llvm.sh - fi - - chmod a+x llvm.sh - ./llvm.sh 11 -} +#function install_clang() { +# if [[ ! -f llvm.sh ]]; then +# wget https://apt.llvm.org/llvm.sh +# fi +# +# chmod a+x llvm.sh +# ./llvm.sh 11 +#} # # install wasi-sdk function install_wasi-sdk() { if [[ ! -f ${WASI_SDK_FILE} ]]; then - wget https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-11/${WASI_SDK_FILE} + wget https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-${WASI_SDK_VER}/${WASI_SDK_FILE} fi tar zxf ${WASI_SDK_FILE} -C /opt - ln -sf /opt/wasi-sdk-${WASI_SDK_VER} /opt/wasi-sdk - ln -sf /opt/wasi-sdk/lib/clang/10.0.0/lib/wasi/ /usr/lib/llvm-11/lib/clang/11.0.1/lib/ + ln -sf /opt/wasi-sdk-${WASI_SDK_VER}.0 /opt/wasi-sdk } # @@ -80,7 +83,7 @@ function install_emsdk() { git pull ./emsdk install latest ./emsdk activate latest - echo "source /opt/emsdk/emsdk_env.sh" >> ${HOME}/.bashrc + echo "source /opt/emsdk/emsdk_env.sh" >> "${HOME}"/.bashrc } # @@ -112,18 +115,17 @@ if [[ ! -d ${BUILD_CONTENT} ]]; then mkdir ${BUILD_CONTENT} fi -cd ${BUILD_CONTENT} +cd ${BUILD_CONTENT} || exit if DEBUG; then - $@ + "$@" else install_deps \ - && install_clang \ - && install_wasi \ + && install_wasi-sdk \ && install_wabt \ && install_cmake \ && install_emsdk \ && install_binaryen \ && install_bazel fi -cd - > /dev/null +cd - > /dev/null || exit DEBUG && set +xevu diff --git a/samples/workload/tensorflow/README.md b/samples/workload/tensorflow/README.md index 8883a57e1..11fa28b8b 100644 --- a/samples/workload/tensorflow/README.md +++ b/samples/workload/tensorflow/README.md @@ -1,6 +1,7 @@ "tensorflow" sample introduction ============== -This sample demonstrates how to build [tensorflow](https://github.com/tensorflow/tensorflow) into WebAssembly with emcc toolchain and run it with iwasm. Please first install [emsdk](https://github.com/emscripten-core/emsdk): + +This sample demonstrates how to build [tensorflow](https://github.com/tensorflow/tensorflow) into WebAssembly with emsdk toolchain and run it with iwasm. Please first install [emsdk](https://github.com/emscripten-core/emsdk): ```bash git clone https://github.com/emscripten-core/emsdk.git cd emsdk diff --git a/samples/workload/wasm-av1/CMakeLists.txt b/samples/workload/wasm-av1/CMakeLists.txt index ae33e6ff6..873af6071 100644 --- a/samples/workload/wasm-av1/CMakeLists.txt +++ b/samples/workload/wasm-av1/CMakeLists.txt @@ -5,6 +5,38 @@ cmake_minimum_required (VERSION 3.0) project(av1_wasm) +################ WASI-SDK ################ +find_path(WASI_SDK_HOME + NAMES wasi-sdk + PATHS /opt/ + REQUIRED +) + +if (NOT WASI_SDK_HOME) + message(FATAL_ERROR + "can not find wasi-sdk. " + "please download it from " + "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk-12.0-linux.tar.gz " + "and install it under /opt/wasi-sdk" + ) +endif() + +# +# check clang version +execute_process(COMMAND + ${WASI_SDK_HOME}/wasi-sdk/bin/clang --version + OUTPUT_VARIABLE clang_full_version_string +) +string(REGEX REPLACE ".*clang version ([0-9]+\\.[0-9]+).*" "\\1" + CLANG_VERSION_STRING ${clang_full_version_string} +) +message("cur clang version is ${CLANG_VERSION_STRING}") +if(CLANG_VERSION_STRING VERSION_LESS 11.0) + message(FATAL_ERROR + "please install latest wai-sdk to get a clang-11 at least" + ) +endif() + ################ BINARYEN ################ find_program(WASM_OPT NAMES wasm-opt @@ -55,7 +87,10 @@ ExternalProject_Add(av1 && ${CMAKE_COMMAND} -E echo "Copying pre-installed CMakeLists.txt" && ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.avx_wasm.txt CMakeLists.txt && git apply ../av1-clang.patch - CONFIGURE_COMMAND ${CMAKE_COMMAND} -DCMAKE_TOOLCHAIN_FILE=${CMAKE_CURRENT_SOURCE_DIR}/../cmake/toolchain.cmake ${CMAKE_CURRENT_SOURCE_DIR}/av1 + CONFIGURE_COMMAND ${CMAKE_COMMAND} + -DWASI_SDK_PREFIX=${WASI_SDK_HOME}/wasi-sdk + -DCMAKE_TOOLCHAIN_FILE=${WASI_SDK_HOME}/wasi-sdk/share/cmake/wasi-sdk.cmake + ${CMAKE_CURRENT_SOURCE_DIR}/av1 BUILD_COMMAND make testavx_opt INSTALL_COMMAND ${CMAKE_COMMAND} -E copy testavx.opt.wasm ${CMAKE_CURRENT_BINARY_DIR}/testavx.wasm ) diff --git a/samples/workload/wasm-av1/README.md b/samples/workload/wasm-av1/README.md index 784812413..e7a92f2af 100644 --- a/samples/workload/wasm-av1/README.md +++ b/samples/workload/wasm-av1/README.md @@ -8,21 +8,7 @@ WebAssembly with simd support and run it with iwasm. please refer to [installation instructions](../README.md). -## Build with EMSDK - -just run the convenience script: - -```bash -./build.sh -``` - -it is going to build wasm-av1 and run it with iwasm, which basically contains the following steps: -- hack emcc to delete some objects in libc.a -- patch wasm-av1 and build it with emcc compiler -- build iwasm with simd and libc-emcc support -- run testav1.aot with iwasm - -## Or build with clang-11 and wasi-sdk +## Build with wasi-sdk ``` shell $ mkdir build && cd build @@ -32,6 +18,20 @@ $ make $ ls testavx.wasm ``` +## Or build with EMSDK + +just run the convenience script: + +```bash +./build.sh +``` + +the script builds wasm-av1 and runs it with iwasm, which basically contains the following steps: +- hack emcc to delete some objects in libc.a +- patch wasm-av1 and build it with emcc compiler +- build iwasm with simd and libc-emcc support +- run testav1.aot with iwasm + ### Run workload Firstly please build iwasm with simd support: @@ -46,11 +46,9 @@ $ make Then compile wasm file to aot file and run: ``` shell -$ cd /wamr-compiler/build -$ ./wamrc --enable-simd -o testavx.aot testavx.wasm -$ cd /product-mini/platforms/linux/ -$ # copy sample data like /samples/workload/wasm-av1/av1/third_party/samples/elephants_dream_480p24.ivf -$ # copy testavx.aot -$ # make sure you declare the access priority of the directory in which the sample data is -$ ./iwasm --dir=. ./testavx.aot ./elephants_dream_480p24.ivf -``` \ No newline at end of file +$ cd +$ /wamr-compiler/build/wamrc --enable-simd -o testavx.aot testavx.wasm +# copy sample data like /samples/workload/wasm-av1/av1/third_party/samples/elephants_dream_480p24.ivf +# make sure you declare the access priority of the directory in which the sample data is +$ /product-mini/platforms/linux/build/iwasm --dir=. testavx.aot elephants_dream_480p24.ivf +``` From 6c967b71f107ba21b60e01c5454ea5b6543cc4f7 Mon Sep 17 00:00:00 2001 From: Xiaokang Qin Date: Wed, 30 Dec 2020 13:37:19 +0800 Subject: [PATCH 135/207] Fix two issues for wasm-c-api (#487) Fix incorrect func_type unpacking for results Fix crash for multiple instance usage due to wrong size provided Signed-off-by: Kanghua Yu Signed-off-by: Xiaokang Qin Co-authored-by: Kanghua Yu --- core/iwasm/common/wasm_c_api.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/iwasm/common/wasm_c_api.c b/core/iwasm/common/wasm_c_api.c index c8f7701a6..cc1082b99 100644 --- a/core/iwasm/common/wasm_c_api.c +++ b/core/iwasm/common/wasm_c_api.c @@ -523,9 +523,9 @@ wasm_functype_new_internal(WASMType *type_rt) /* WASMType->types[type_rt->param_count : type_rt->result_count) -> func_type->results */ INIT_VEC(func_type->results, wasm_valtype_vec, type_rt->result_count); - for (i = type_rt->param_count; i < type_rt->result_count; ++i) { + for (i = 0; i < type_rt->result_count; ++i) { wasm_valtype_t *result_type = - wasm_valtype_new_internal(*(type_rt->types + i)); + wasm_valtype_new_internal(*(type_rt->types + type_rt->param_count + i)); if (!result_type) { goto failed; } @@ -2603,7 +2603,7 @@ wasm_instance_exports(const wasm_instance_t *instance, wasm_extern_vec_t *out) void wasm_instance_vec_new_uninitialized(wasm_instance_vec_t *out, size_t size) { - generic_vec_init_data((Vector *)out, size, sizeof(wasm_instance_t)); + generic_vec_init_data((Vector *)out, size, sizeof(wasm_instance_t *)); } void From f2a63d8623c3517a5ce6b10b46f92182aa351fa5 Mon Sep 17 00:00:00 2001 From: Javan Date: Wed, 30 Dec 2020 21:01:36 +0800 Subject: [PATCH 136/207] Fix aot bh_assert failed issue on darwin platform x86_64 target (#476) (#488) Modify the macro control sentences as darwin platform doesn't support mmap with MAP_32BIT flag to put the mapping address into 0-2G range. Co-authored-by: Wenyong Huang --- core/iwasm/aot/aot_loader.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/iwasm/aot/aot_loader.c b/core/iwasm/aot/aot_loader.c index a910e0155..ced314949 100644 --- a/core/iwasm/aot/aot_loader.c +++ b/core/iwasm/aot/aot_loader.c @@ -986,7 +986,8 @@ load_object_data_sections(const uint8 **p_buf, const uint8 *buf_end, return false; } #if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64) -#if !defined(BH_PLATFORM_LINUX_SGX) && !defined(BH_PLATFORM_WINDOWS) +#if !defined(BH_PLATFORM_LINUX_SGX) && !defined(BH_PLATFORM_WINDOWS) \ + && !defined(BH_PLATFORM_DARWIN) /* address must be in the first 2 Gigabytes of the process address space */ bh_assert((uintptr_t)data_sections[i].data < INT32_MAX); @@ -1887,7 +1888,8 @@ create_sections(const uint8 *buf, uint32 size, goto fail; } #if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64) -#if !defined(BH_PLATFORM_LINUX_SGX) && !defined(BH_PLATFORM_WINDOWS) +#if !defined(BH_PLATFORM_LINUX_SGX) && !defined(BH_PLATFORM_WINDOWS) \ + && !defined(BH_PLATFORM_DARWIN) /* address must be in the first 2 Gigabytes of the process address space */ bh_assert((uintptr_t)aot_text < INT32_MAX); From 788cbf2a1945cf04cc8139f7a363e268f18cbe34 Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Tue, 5 Jan 2021 04:05:30 -0600 Subject: [PATCH 137/207] Refine aot call_indirect opcode translation (#492) Re-implement aot call_indirect opcode translation: when calling non-import function, translate it by LLVM call IR to call the function in AOTed code, so as to avoid calling runtime aot_call_indirect API which is much slower. For import function, keep calling aot_call_indirect API due to the possible pointer/string argument conversion. And add prompt info while app heap is corrupted, change emit_leb to emit_uint32 inter fast-interp to refine footprint. Signed-off-by: Wenyong Huang --- core/iwasm/aot/aot_runtime.c | 27 +- core/iwasm/aot/aot_runtime.h | 1 - core/iwasm/common/wasm_runtime_common.c | 7 +- core/iwasm/compilation/aot_emit_function.c | 466 ++++++++++++++++++--- core/iwasm/compilation/aot_llvm.c | 45 ++ core/iwasm/compilation/aot_llvm.h | 2 +- core/iwasm/interpreter/wasm.h | 13 + core/iwasm/interpreter/wasm_interp_fast.c | 39 +- core/iwasm/interpreter/wasm_loader.c | 38 +- core/iwasm/interpreter/wasm_mini_loader.c | 27 +- core/iwasm/interpreter/wasm_runtime.c | 12 +- core/shared/mem-alloc/ems/ems_gc.h | 10 +- core/shared/mem-alloc/ems/ems_kfc.c | 9 +- core/shared/mem-alloc/mem_alloc.c | 20 +- core/shared/mem-alloc/mem_alloc.h | 4 +- 15 files changed, 529 insertions(+), 191 deletions(-) diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index 7b5df64df..d26f2161c 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -1381,7 +1381,17 @@ aot_module_malloc(AOTModuleInstance *module_inst, uint32 size, } if (!addr) { - aot_set_exception(module_inst, "out of memory"); + if (memory_inst->heap_handle.ptr + && mem_allocator_is_heap_corrupted(memory_inst->heap_handle.ptr)) { + LOG_ERROR("Error: app heap is corrupted, if the wasm file " + "is compiled by wasi-sdk-12.0 or larger version, " + "please add -Wl,--export=malloc -Wl,--export=free " + " to export malloc and free functions."); + aot_set_exception(module_inst, "app heap corrupted"); + } + else { + aot_set_exception(module_inst, "out of memory"); + } return 0; } if (p_native_addr) @@ -1804,7 +1814,6 @@ aot_invoke_native(WASMExecEnv *exec_env, uint32 func_idx, bool aot_call_indirect(WASMExecEnv *exec_env, - bool check_func_type, uint32 func_type_idx, uint32 table_elem_idx, uint32 argc, uint32 *argv) { @@ -1816,8 +1825,7 @@ aot_call_indirect(WASMExecEnv *exec_env, AOTFuncType *func_type; void **func_ptrs = (void**)module_inst->func_ptrs.ptr, *func_ptr; uint32 table_size = module_inst->table_size; - uint32 func_idx, func_type_idx1; - uint32 ext_ret_count; + uint32 func_type_idx, func_idx, ext_ret_count; AOTImportFunc *import_func; const char *signature = NULL; void *attachment = NULL; @@ -1844,15 +1852,8 @@ aot_call_indirect(WASMExecEnv *exec_env, return false; } - func_type_idx1 = func_type_indexes[func_idx]; - if (check_func_type - && !aot_is_wasm_type_equal(module_inst, func_type_idx, - func_type_idx1)) { - aot_set_exception_with_id(module_inst, - EXCE_INVALID_FUNCTION_TYPE_INDEX); - return false; - } - func_type = aot_module->func_types[func_type_idx1]; + func_type_idx = func_type_indexes[func_idx]; + func_type = aot_module->func_types[func_type_idx]; if (!(func_ptr = func_ptrs[func_idx])) { bh_assert(func_idx < aot_module->import_func_count); diff --git a/core/iwasm/aot/aot_runtime.h b/core/iwasm/aot/aot_runtime.h index 87dc11662..4fab1903b 100644 --- a/core/iwasm/aot/aot_runtime.h +++ b/core/iwasm/aot/aot_runtime.h @@ -521,7 +521,6 @@ aot_invoke_native(WASMExecEnv *exec_env, uint32 func_idx, bool aot_call_indirect(WASMExecEnv *exec_env, - bool check_func_type, uint32 func_type_idx, uint32 table_elem_idx, uint32 argc, uint32 *argv); diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index 45b81b9d6..9c8b3a068 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -3327,14 +3327,11 @@ wasm_runtime_call_indirect(WASMExecEnv *exec_env, #if WASM_ENABLE_INTERP != 0 if (exec_env->module_inst->module_type == Wasm_Module_Bytecode) - return wasm_call_indirect(exec_env, - element_indices, - argc, argv); + return wasm_call_indirect(exec_env, element_indices, argc, argv); #endif #if WASM_ENABLE_AOT != 0 if (exec_env->module_inst->module_type == Wasm_Module_AoT) - return aot_call_indirect(exec_env, false, 0, - element_indices, argc, argv); + return aot_call_indirect(exec_env, element_indices, argc, argv); #endif return false; } diff --git a/core/iwasm/compilation/aot_emit_function.c b/core/iwasm/compilation/aot_emit_function.c index ade942d52..1aa9eb57b 100644 --- a/core/iwasm/compilation/aot_emit_function.c +++ b/core/iwasm/compilation/aot_emit_function.c @@ -347,7 +347,7 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, + ext_ret_count); if (total_size >= UINT32_MAX || !(param_values = wasm_runtime_malloc((uint32)total_size))) { - aot_set_last_error("Allocate memory failed."); + aot_set_last_error("allocate memory failed."); return false; } @@ -408,7 +408,7 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, total_size = sizeof(LLVMTypeRef) * (uint64)(param_count + 1); if (total_size >= UINT32_MAX || !(param_types = wasm_runtime_malloc((uint32)total_size))) { - aot_set_last_error("Allocate memory failed."); + aot_set_last_error("allocate memory failed."); goto fail; } @@ -510,22 +510,12 @@ call_aot_call_indirect_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, char buf[32], *func_name = "aot_call_indirect"; uint32 i, cell_num = 0, ret_cell_num, argv_cell_num; -#if WASM_ENABLE_THREAD_MGR != 0 - /* Insert suspend check point */ - if (comp_ctx->enable_thread_mgr) { - if (!check_suspend_flags(comp_ctx, func_ctx)) - return false; - } -#endif - /* prepare function type of aot_call_indirect */ func_param_types[0] = comp_ctx->exec_env_type; /* exec_env */ - func_param_types[1] = INT8_TYPE; /* check_func_type */ - func_param_types[2] = I32_TYPE; /* func_type_idx */ - func_param_types[3] = I32_TYPE; /* table_elem_idx */ - func_param_types[4] = I32_TYPE; /* argc */ - func_param_types[5] = INT32_PTR_TYPE; /* argv */ - if (!(func_type = LLVMFunctionType(INT8_TYPE, func_param_types, 6, false))) { + func_param_types[1] = I32_TYPE; /* table_elem_idx */ + func_param_types[2] = I32_TYPE; /* argc */ + func_param_types[3] = INT32_PTR_TYPE; /* argv */ + if (!(func_type = LLVMFunctionType(INT8_TYPE, func_param_types, 4, false))) { aot_set_last_error("llvm add function type failed."); return false; } @@ -588,20 +578,18 @@ call_aot_call_indirect_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } func_param_values[0] = func_ctx->exec_env; - func_param_values[1] = I8_CONST(true); - func_param_values[2] = func_type_idx; - func_param_values[3] = table_elem_idx; - func_param_values[4] = I32_CONST(param_cell_num); - func_param_values[5] = func_ctx->argv_buf; + func_param_values[1] = table_elem_idx; + func_param_values[2] = I32_CONST(param_cell_num); + func_param_values[3] = func_ctx->argv_buf; - if (!func_param_values[1] || !func_param_values[4]) { + if (!func_param_values[2]) { aot_set_last_error("llvm create const failed."); return false; } /* call aot_call_indirect() function */ if (!(res = LLVMBuildCall(comp_ctx->builder, func, - func_param_values, 6, "res"))) { + func_param_values, 4, "res"))) { aot_set_last_error("llvm build call failed."); return false; } @@ -642,89 +630,453 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, uint32 type_idx) { AOTFuncType *func_type; - LLVMValueRef elem_idx, ftype_idx; - LLVMValueRef *param_values = NULL, *value_rets = NULL, res = NULL; - LLVMTypeRef *param_types = NULL; - int32 i, param_count, result_count; - uint32 param_cell_num; + LLVMValueRef elem_idx, table_elem, func_idx; + LLVMValueRef ftype_idx_ptr, ftype_idx, ftype_idx_const; + LLVMValueRef cmp_elem_idx, cmp_func_idx, cmp_ftype_idx; + LLVMValueRef func, func_ptr, table_size_const; + LLVMValueRef ext_ret_offset, ext_ret_ptr, ext_ret, res; + LLVMValueRef *param_values = NULL, *value_rets = NULL; + LLVMValueRef *result_phis = NULL, value_ret, import_func_count; + LLVMTypeRef *param_types = NULL, ret_type; + LLVMTypeRef llvm_func_type, llvm_func_ptr_type; + LLVMTypeRef ext_ret_ptr_type; + LLVMBasicBlockRef check_elem_idx_succ, check_ftype_idx_succ; + LLVMBasicBlockRef check_func_idx_succ, block_return, block_curr; + LLVMBasicBlockRef block_call_import, block_call_non_import; + uint32 total_param_count, func_param_count, func_result_count; + uint32 table_init_size = 0, ext_cell_num, param_cell_num, i, j; + uint8 wasm_ret_type, *wasm_ret_types; uint64 total_size; - uint8 *wasm_ret_types = NULL; - bool ret = false; + char buf[32]; + bool ret; /* Check function type index */ if (type_idx >= comp_ctx->comp_data->func_type_count) { - aot_set_last_error("type index is overflow"); + aot_set_last_error("function type index out of range"); return false; } - ftype_idx = I32_CONST(type_idx); - CHECK_LLVM_CONST(ftype_idx); + /* Find the equivalent function type whose type index is the smallest: + the callee function's type index is also converted to the smallest + one in wasm loader, so we can just check whether the two type indexes + are equal (the type index of call_indirect opcode and callee func), + we don't need to check whether the whole function types are equal, + including param types and result types. */ + type_idx = wasm_get_smallest_type_idx(comp_ctx->comp_data->func_types, + comp_ctx->comp_data->func_type_count, + type_idx); + ftype_idx_const = I32_CONST(type_idx); + CHECK_LLVM_CONST(ftype_idx_const); func_type = comp_ctx->comp_data->func_types[type_idx]; - - param_cell_num = func_type->param_cell_num; - result_count = func_type->result_count; - wasm_ret_types = func_type->types + func_type->param_count; + func_param_count = func_type->param_count; + func_result_count = func_type->result_count; POP_I32(elem_idx); + if (comp_ctx->comp_data->import_table_count > 0) { + table_init_size = comp_ctx->comp_data->import_tables[0] + .table_init_size; + } + else if (comp_ctx->comp_data->table_count > 0) { + table_init_size = comp_ctx->comp_data->tables[0] + .table_init_size; + } + else { + aot_set_last_error("table index out of range"); + goto fail; + } + table_size_const = I32_CONST(table_init_size); + CHECK_LLVM_CONST(table_size_const); + + /* Check if (uint32)elem index >= table size */ + if (!(cmp_elem_idx = LLVMBuildICmp(comp_ctx->builder, LLVMIntUGE, + elem_idx, table_size_const, + "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_UNDEFINED_ELEMENT, + true, cmp_elem_idx, check_elem_idx_succ))) + goto fail; + + /* Load function index */ + if (!(table_elem = LLVMBuildInBoundsGEP(comp_ctx->builder, + func_ctx->table_base, + &elem_idx, 1, "table_elem"))) { + aot_set_last_error("llvm build add failed."); + goto fail; + } + + if (!(func_idx = LLVMBuildLoad(comp_ctx->builder, + table_elem, "func_idx"))) { + aot_set_last_error("llvm build load failed."); + goto fail; + } + + /* Check if func_idx == -1 */ + if (!(cmp_func_idx = LLVMBuildICmp(comp_ctx->builder, LLVMIntEQ, + func_idx, I32_NEG_ONE, + "cmp_func_idx"))) { + aot_set_last_error("llvm build icmp failed."); + goto fail; + } + + /* Throw exception if func_idx == -1 */ + if (!(check_func_idx_succ = + LLVMAppendBasicBlockInContext(comp_ctx->context, + func_ctx->func, + "check_func_idx_succ"))) { + aot_set_last_error("llvm add basic block failed."); + goto fail; + } + + LLVMMoveBasicBlockAfter(check_func_idx_succ, + LLVMGetInsertBlock(comp_ctx->builder)); + + if (!(aot_emit_exception(comp_ctx, func_ctx, EXCE_UNINITIALIZED_ELEMENT, + true, cmp_func_idx, check_func_idx_succ))) + goto fail; + + /* Load function type index */ + if (!(ftype_idx_ptr = LLVMBuildInBoundsGEP(comp_ctx->builder, + func_ctx->func_type_indexes, + &func_idx, 1, + "ftype_idx_ptr"))) { + aot_set_last_error("llvm build inbounds gep failed."); + goto fail; + } + + if (!(ftype_idx = LLVMBuildLoad(comp_ctx->builder, ftype_idx_ptr, + "ftype_idx"))) { + aot_set_last_error("llvm build load failed."); + goto fail; + } + + /* Check if function type index not equal */ + if (!(cmp_ftype_idx = LLVMBuildICmp(comp_ctx->builder, LLVMIntNE, + ftype_idx, ftype_idx_const, + "cmp_ftype_idx"))) { + aot_set_last_error("llvm build icmp failed."); + goto fail; + } + + /* Throw exception if ftype_idx != ftype_idx_const */ + if (!(check_ftype_idx_succ = + LLVMAppendBasicBlockInContext(comp_ctx->context, + func_ctx->func, + "check_ftype_idx_succ"))) { + aot_set_last_error("llvm add basic block failed."); + goto fail; + } + + LLVMMoveBasicBlockAfter(check_ftype_idx_succ, + LLVMGetInsertBlock(comp_ctx->builder)); + + if (!(aot_emit_exception(comp_ctx, func_ctx, + EXCE_INVALID_FUNCTION_TYPE_INDEX, + true, cmp_ftype_idx, check_ftype_idx_succ))) + goto fail; + /* Initialize parameter types of the LLVM function */ - param_count = (int32)func_type->param_count; - total_size = sizeof(LLVMTypeRef) * (uint64)param_count; + total_param_count = 1 + func_param_count; + + /* Extra function results' addresses (except the first one) are + * appended to aot function parameters. */ + if (func_result_count > 1) + total_param_count += func_result_count - 1; + + total_size = sizeof(LLVMTypeRef) * (uint64)total_param_count; if (total_size >= UINT32_MAX || !(param_types = wasm_runtime_malloc((uint32)total_size))) { - aot_set_last_error("Allocate memory failed."); + aot_set_last_error("allocate memory failed."); goto fail; } - for (i = 0; i < param_count; i++) - param_types[i] = TO_LLVM_TYPE(func_type->types[i]); + /* Prepare param types */ + j = 0; + param_types[j++] = comp_ctx->exec_env_type; + for (i = 0; i < func_param_count; i++) + param_types[j++] = TO_LLVM_TYPE(func_type->types[i]); + + for (i = 1; i < func_result_count; i++, j++) { + param_types[j] = + TO_LLVM_TYPE(func_type->types[func_param_count + i]); + if (!(param_types[j] = LLVMPointerType(param_types[j], 0))) { + aot_set_last_error("llvm get pointer type failed."); + goto fail; + } + } + + /* Resolve return type of the LLVM function */ + if (func_result_count) { + wasm_ret_type = func_type->types[func_param_count]; + ret_type = TO_LLVM_TYPE(wasm_ret_type); + } + else { + wasm_ret_type = VALUE_TYPE_VOID; + ret_type = VOID_TYPE; + } /* Allocate memory for parameters */ - total_size = sizeof(LLVMValueRef) * (uint64)param_count; + total_size = sizeof(LLVMValueRef) * (uint64)total_param_count; if (total_size >= UINT32_MAX || !(param_values = wasm_runtime_malloc((uint32)total_size))) { - aot_set_last_error("Allocate memory failed."); + aot_set_last_error("allocate memory failed."); goto fail; } + /* First parameter is exec env */ + j = 0; + param_values[j++] = func_ctx->exec_env; + /* Pop parameters from stack */ - for (i = param_count - 1; i >= 0; i--) - POP(param_values[i], func_type->types[i]); + for (i = func_param_count - 1; (int32)i >= 0; i--) + POP(param_values[i + j], func_type->types[i]); + + /* Prepare extra parameters */ + ext_cell_num = 0; + for (i = 1; i < func_result_count; i++) { + ext_ret_offset = I32_CONST(ext_cell_num); + CHECK_LLVM_CONST(ext_ret_offset); + + snprintf(buf, sizeof(buf), "ext_ret%d_ptr", i - 1); + if (!(ext_ret_ptr = LLVMBuildInBoundsGEP(comp_ctx->builder, + func_ctx->argv_buf, + &ext_ret_offset, 1, buf))) { + aot_set_last_error("llvm build GEP failed."); + goto fail; + } + + ext_ret_ptr_type = param_types[func_param_count + i]; + snprintf(buf, sizeof(buf), "ext_ret%d_ptr_cast", i - 1); + if (!(ext_ret_ptr = LLVMBuildBitCast(comp_ctx->builder, + ext_ret_ptr, ext_ret_ptr_type, + buf))) { + aot_set_last_error("llvm build bit cast failed."); + goto fail; + } + + param_values[func_param_count + i] = ext_ret_ptr; + ext_cell_num += wasm_value_type_cell_num( + func_type->types[func_param_count + i]); + } + + if (ext_cell_num > 64) { + aot_set_last_error("prepare call-indirect arguments failed: " + "maximum 64 extra cell number supported."); + goto fail; + } + +#if WASM_ENABLE_THREAD_MGR != 0 + /* Insert suspend check point */ + if (comp_ctx->enable_thread_mgr) { + if (!check_suspend_flags(comp_ctx, func_ctx)) + goto fail; + } +#endif + + /* Add basic blocks */ + block_call_import = + LLVMAppendBasicBlockInContext(comp_ctx->context, func_ctx->func, + "call_import"); + block_call_non_import = + LLVMAppendBasicBlockInContext(comp_ctx->context, func_ctx->func, + "call_non_import"); + block_return = + LLVMAppendBasicBlockInContext(comp_ctx->context, func_ctx->func, + "func_return"); + if (!block_call_import || !block_call_non_import || !block_return) { + aot_set_last_error("llvm add basic block failed."); + goto fail; + } + + LLVMMoveBasicBlockAfter(block_call_import, + LLVMGetInsertBlock(comp_ctx->builder)); + LLVMMoveBasicBlockAfter(block_call_non_import, block_call_import); + LLVMMoveBasicBlockAfter(block_return, block_call_non_import); + + import_func_count = I32_CONST(comp_ctx->comp_data->import_func_count); + CHECK_LLVM_CONST(import_func_count); + + /* Check if func_idx < import_func_count */ + if (!(cmp_func_idx = LLVMBuildICmp(comp_ctx->builder, LLVMIntULT, + func_idx, import_func_count, + "cmp_func_idx"))) { + aot_set_last_error("llvm build icmp failed."); + goto fail; + } + + /* If func_idx < import_func_count, jump to call import block, + else jump to call non-import block */ + if (!LLVMBuildCondBr(comp_ctx->builder, cmp_func_idx, + block_call_import, block_call_non_import)) { + aot_set_last_error("llvm build cond br failed."); + goto fail; + } + + /* Add result phis for return block */ + LLVMPositionBuilderAtEnd(comp_ctx->builder, block_return); + + if (func_result_count > 0) { + total_size = sizeof(LLVMValueRef) * (uint64)func_result_count; + if (total_size >= UINT32_MAX + || !(result_phis = wasm_runtime_malloc((uint32)total_size))) { + aot_set_last_error("allocate memory failed."); + goto fail; + } + memset(result_phis, 0, (uint32)total_size); + for (i = 0; i < func_result_count; i++) { + LLVMTypeRef tmp_type = + TO_LLVM_TYPE(func_type->types[func_param_count + i]); + if (!(result_phis[i] = LLVMBuildPhi(comp_ctx->builder, + tmp_type, "phi"))) { + aot_set_last_error("llvm build phi failed."); + goto fail; + } + } + } + + /* Translate call import block */ + LLVMPositionBuilderAtEnd(comp_ctx->builder, block_call_import); /* Allocate memory for result values */ - total_size = sizeof(LLVMValueRef) * (uint64)result_count; + total_size = sizeof(LLVMValueRef) * (uint64)func_result_count; if (total_size >= UINT32_MAX || !(value_rets = wasm_runtime_malloc((uint32)total_size))) { - aot_set_last_error("Allocate memory failed."); + aot_set_last_error("allocate memory failed."); goto fail; } memset(value_rets, 0, total_size); + param_cell_num = func_type->param_cell_num; + wasm_ret_types = func_type->types + func_type->param_count; + if (!call_aot_call_indirect_func(comp_ctx, func_ctx, func_type, ftype_idx, elem_idx, - param_types, param_values, - param_count, param_cell_num, - result_count, wasm_ret_types, + param_types + 1, param_values + 1, + func_param_count, param_cell_num, + func_result_count, wasm_ret_types, value_rets, &res)) goto fail; - for (i = 0; i < func_type->result_count; i++) - PUSH(value_rets[i], func_type->types[func_type->param_count + i]); - - /* Check whether there was exception thrown when executing the function */ + /* Check whether exception was thrown when executing the function */ if (!check_call_return(comp_ctx, func_ctx, res)) goto fail; + block_curr = LLVMGetInsertBlock(comp_ctx->builder); + for (i = 0; i < func_result_count; i++) { + LLVMAddIncoming(result_phis[i], &value_rets[i], &block_curr, 1); + } + + if (!LLVMBuildBr(comp_ctx->builder, block_return)) { + aot_set_last_error("llvm build br failed."); + goto fail; + } + + /* Translate call non-import block */ + LLVMPositionBuilderAtEnd(comp_ctx->builder, block_call_non_import); + + if (comp_ctx->enable_bound_check + && !check_stack_boundary(comp_ctx, func_ctx, + param_cell_num + ext_cell_num + 1 + /* Reserve some local variables */ + + 16)) + goto fail; + + /* Load function pointer */ + if (!(func_ptr = LLVMBuildInBoundsGEP(comp_ctx->builder, func_ctx->func_ptrs, + &func_idx, 1, "func_ptr_tmp"))) { + aot_set_last_error("llvm build inbounds gep failed."); + goto fail; + } + + if (!(func_ptr = LLVMBuildLoad(comp_ctx->builder, func_ptr, "func_ptr"))) { + aot_set_last_error("llvm build load failed."); + goto fail; + } + + if (!(llvm_func_type = LLVMFunctionType(ret_type, param_types, + total_param_count, false)) + || !(llvm_func_ptr_type = LLVMPointerType(llvm_func_type, 0))) { + aot_set_last_error("llvm add function type failed."); + goto fail; + } + + if (!(func = LLVMBuildBitCast(comp_ctx->builder, + func_ptr, llvm_func_ptr_type, + "indirect_func"))) { + aot_set_last_error("llvm build bit cast failed."); + goto fail; + } + + if (!(value_ret = LLVMBuildCall(comp_ctx->builder, func, + param_values, total_param_count, + func_result_count > 0 + ? "ret" : ""))) { + aot_set_last_error("llvm build call failed."); + goto fail; + } + + /* Check whether exception was thrown when executing the function */ + if (!check_exception_thrown(comp_ctx, func_ctx)) + goto fail; + + if (func_result_count > 0) { + block_curr = LLVMGetInsertBlock(comp_ctx->builder); + + /* Push the first result to stack */ + LLVMAddIncoming(result_phis[0], &value_ret, &block_curr, 1); + + /* Load extra result from its address and push to stack */ + for (i = 1; i < func_result_count; i++) { + snprintf(buf, sizeof(buf), "ext_ret%d", i - 1); + if (!(ext_ret = LLVMBuildLoad(comp_ctx->builder, + param_values[func_param_count + i], + buf))) { + aot_set_last_error("llvm build load failed."); + goto fail; + } + LLVMAddIncoming(result_phis[i], &ext_ret, &block_curr, 1); + } + } + + if (!LLVMBuildBr(comp_ctx->builder, block_return)) { + aot_set_last_error("llvm build br failed."); + goto fail; + } + + /* Translate function return block */ + LLVMPositionBuilderAtEnd(comp_ctx->builder, block_return); + + for (i = 0; i < func_result_count; i++) { + PUSH(result_phis[i], func_type->types[func_param_count + i]); + } + ret = true; fail: - if (value_rets) - wasm_runtime_free(value_rets); if (param_values) wasm_runtime_free(param_values); if (param_types) wasm_runtime_free(param_types); + if (value_rets) + wasm_runtime_free(value_rets); + if (result_phis) + wasm_runtime_free(result_phis); return ret; } diff --git a/core/iwasm/compilation/aot_llvm.c b/core/iwasm/compilation/aot_llvm.c index 2502fda40..26338dc6f 100644 --- a/core/iwasm/compilation/aot_llvm.c +++ b/core/iwasm/compilation/aot_llvm.c @@ -465,9 +465,13 @@ create_memory_info(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, static bool create_table_base(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) { + AOTCompData *comp_data = comp_ctx->comp_data; + uint64 module_inst_mem_inst_size = + (uint64)comp_data->memory_count * sizeof(AOTMemoryInstance); LLVMValueRef offset; offset = I32_CONST(offsetof(AOTModuleInstance, global_table_data.bytes) + + module_inst_mem_inst_size + comp_ctx->comp_data->global_data_size); func_ctx->table_base = LLVMBuildInBoundsGEP(comp_ctx->builder, func_ctx->aot_inst, @@ -544,6 +548,43 @@ create_func_type_indexes(AOTCompContext *comp_ctx, return true; } +static bool +create_func_ptrs(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) +{ + LLVMValueRef offset; + + offset = I32_CONST(offsetof(AOTModuleInstance, func_ptrs)); + func_ctx->func_ptrs = LLVMBuildInBoundsGEP(comp_ctx->builder, + func_ctx->aot_inst, + &offset, 1, "func_ptrs_offset"); + if (!func_ctx->func_ptrs) { + aot_set_last_error("llvm build in bounds gep failed."); + return false; + } + func_ctx->func_ptrs = LLVMBuildBitCast(comp_ctx->builder, func_ctx->func_ptrs, + comp_ctx->exec_env_type, "func_ptrs_tmp"); + if (!func_ctx->func_ptrs) { + aot_set_last_error("llvm build bit cast failed."); + return false; + } + + func_ctx->func_ptrs = LLVMBuildLoad(comp_ctx->builder, func_ctx->func_ptrs, + "func_ptrs_ptr"); + if (!func_ctx->func_ptrs) { + aot_set_last_error("llvm build load failed."); + return false; + } + + func_ctx->func_ptrs = LLVMBuildBitCast(comp_ctx->builder, func_ctx->func_ptrs, + comp_ctx->exec_env_type, "func_ptrs"); + if (!func_ctx->func_ptrs) { + aot_set_last_error("llvm build bit cast failed."); + return false; + } + + return true; +} + /** * Create function compiler context */ @@ -746,6 +787,10 @@ aot_create_func_context(AOTCompData *comp_data, AOTCompContext *comp_ctx, if (!create_func_type_indexes(comp_ctx, func_ctx)) goto fail; + /* Load function pointers */ + if (!create_func_ptrs(comp_ctx, func_ctx)) + goto fail; + return func_ctx; fail: diff --git a/core/iwasm/compilation/aot_llvm.h b/core/iwasm/compilation/aot_llvm.h index 30163a8b1..599e664d9 100644 --- a/core/iwasm/compilation/aot_llvm.h +++ b/core/iwasm/compilation/aot_llvm.h @@ -122,6 +122,7 @@ typedef struct AOTFuncContext { LLVMValueRef argv_buf; LLVMValueRef native_stack_bound; LLVMValueRef last_alloca; + LLVMValueRef func_ptrs; AOTMemInfo *mem_info; @@ -130,7 +131,6 @@ typedef struct AOTFuncContext { bool mem_space_unchanged; AOTCheckedAddrList checked_addr_list; - LLVMBasicBlockRef *exception_blocks; LLVMBasicBlockRef got_exception_block; LLVMBasicBlockRef func_return_block; LLVMValueRef exception_id_phi; diff --git a/core/iwasm/interpreter/wasm.h b/core/iwasm/interpreter/wasm.h index f6034d563..c8ab721de 100644 --- a/core/iwasm/interpreter/wasm.h +++ b/core/iwasm/interpreter/wasm.h @@ -517,6 +517,19 @@ wasm_type_equal(const WASMType *type1, const WASMType *type2) ? true : false; } +inline static uint32 +wasm_get_smallest_type_idx(WASMType **types, uint32 type_count, + uint32 cur_type_idx) +{ + uint32 i; + + for (i = 0; i < cur_type_idx; i++) { + if (wasm_type_equal(types[cur_type_idx], types[i])) + return i; + } + return cur_type_idx; +} + static inline uint32 block_type_get_param_types(BlockType *block_type, uint8 **p_param_types) diff --git a/core/iwasm/interpreter/wasm_interp_fast.c b/core/iwasm/interpreter/wasm_interp_fast.c index 2815e63d4..53810bad0 100644 --- a/core/iwasm/interpreter/wasm_interp_fast.c +++ b/core/iwasm/interpreter/wasm_interp_fast.c @@ -380,48 +380,11 @@ popcount64(uint64 u) return ret; } -static uint64 -read_leb(const uint8 *buf, uint32 *p_offset, uint32 maxbits, bool sign) -{ - uint64 result = 0; - uint32 shift = 0; - uint32 bcnt = 0; - uint64 byte; - - while (true) { - byte = buf[*p_offset]; - *p_offset += 1; - result |= ((byte & 0x7f) << shift); - shift += 7; - if ((byte & 0x80) == 0) { - break; - } - bcnt += 1; - } - if (sign && (shift < maxbits) && (byte & 0x40)) { - /* Sign extend */ - result |= - ((uint64)1 << shift); - } - return result; -} - -#define read_leb_uint32(p, p_end, res) do { \ - uint8 _val = *p; \ - if (!(_val & 0x80)) { \ - res = _val; \ - p++; \ - break; \ - } \ - uint32 _off = 0; \ - res = (uint32)read_leb(p, &_off, 32, false); \ - p += _off; \ -} while (0) - #define read_uint32(p) (p += sizeof(uint32), *(uint32 *)(p - sizeof(uint32))) #define GET_LOCAL_INDEX_TYPE_AND_OFFSET() do { \ uint32 param_count = cur_func->param_count; \ - read_leb_uint32(frame_ip, frame_ip_end, local_idx); \ + local_idx = read_uint32(frame_ip); \ bh_assert(local_idx < param_count + cur_func->local_count); \ local_offset = cur_func->local_offsets[local_idx]; \ if (local_idx < param_count) \ diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index 3db4c6799..5315ca4aa 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -791,6 +791,12 @@ load_function_import(const WASMModule *parent_module, WASMModule *sub_module, return false; } +#if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0) + declare_type_index = wasm_get_smallest_type_idx( + parent_module->types, parent_module->type_count, + declare_type_index); +#endif + declare_func_type = parent_module->types[declare_type_index]; if (wasm_runtime_is_host_module(sub_module_name)) { @@ -1724,6 +1730,11 @@ load_function_section(const uint8 *buf, const uint8 *buf_end, return false; } +#if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0) + type_index = wasm_get_smallest_type_idx( + module->types, module->type_count, type_index); +#endif + read_leb_uint32(p_code, buf_code_end, code_size); if (code_size == 0 || p_code + code_size > buf_code_end) { @@ -4312,10 +4323,6 @@ fail: LOG_OP("%d\t", value); \ } while (0) -#define emit_leb() do { \ - wasm_loader_emit_leb(loader_ctx, p_org, p); \ - } while (0) - static bool wasm_loader_ctx_reinit(WASMLoaderContext *ctx) { @@ -4402,21 +4409,6 @@ wasm_loader_emit_backspace(WASMLoaderContext *ctx, uint32 size) ctx->code_compiled_size -= size; } -static void -wasm_loader_emit_leb(WASMLoaderContext *ctx, uint8* start, uint8* end) -{ - if (ctx->p_code_compiled) { - bh_memcpy_s(ctx->p_code_compiled, - ctx->p_code_compiled_end - ctx->p_code_compiled, - start, end - start); - ctx->p_code_compiled += (end - start); - } - else { - ctx->code_compiled_size += (end - start); - } - -} - static bool preserve_referenced_local(WASMLoaderContext *loader_ctx, uint8 opcode, uint32 local_index, uint32 local_type, bool *preserved, @@ -6497,8 +6489,7 @@ handle_op_block_and_loop: } } else { /* local index larger than 255, reserve leb */ - p_org ++; - emit_leb(); + emit_uint32(loader_ctx, local_idx); POP_OFFSET_TYPE(local_type); } #else @@ -6554,11 +6545,10 @@ handle_op_block_and_loop: } } else { /* local index larger than 255, reserve leb */ - p_org ++; - emit_leb(); + emit_uint32(loader_ctx, local_idx); } emit_operand(loader_ctx, *(loader_ctx->frame_offset - - wasm_value_type_cell_num(local_type))); + wasm_value_type_cell_num(local_type))); #else #if (WASM_ENABLE_WAMR_COMPILER == 0) && (WASM_ENABLE_JIT == 0) if (local_offset < 0x80) { diff --git a/core/iwasm/interpreter/wasm_mini_loader.c b/core/iwasm/interpreter/wasm_mini_loader.c index d082d46a1..2dc387686 100644 --- a/core/iwasm/interpreter/wasm_mini_loader.c +++ b/core/iwasm/interpreter/wasm_mini_loader.c @@ -3062,10 +3062,6 @@ wasm_loader_pop_frame_csp(WASMLoaderContext *ctx, LOG_OP("%d\t", value); \ } while (0) -#define emit_leb() do { \ - wasm_loader_emit_leb(loader_ctx, p_org, p); \ - } while (0) - static bool wasm_loader_ctx_reinit(WASMLoaderContext *ctx) { @@ -3152,21 +3148,6 @@ wasm_loader_emit_backspace(WASMLoaderContext *ctx, uint32 size) ctx->code_compiled_size -= size; } -static void -wasm_loader_emit_leb(WASMLoaderContext *ctx, uint8* start, uint8* end) -{ - if (ctx->p_code_compiled) { - bh_memcpy_s(ctx->p_code_compiled, - ctx->p_code_compiled_end - ctx->p_code_compiled, - start, end - start); - ctx->p_code_compiled += (end - start); - } - else { - ctx->code_compiled_size += (end - start); - } - -} - static bool preserve_referenced_local(WASMLoaderContext *loader_ctx, uint8 opcode, uint32 local_index, uint32 local_type, bool *preserved, @@ -4970,8 +4951,7 @@ handle_op_block_and_loop: } } else { /* local index larger than 255, reserve leb */ - p_org ++; - emit_leb(); + emit_uint32(loader_ctx, local_idx); POP_OFFSET_TYPE(local_type); } #else @@ -5027,11 +5007,10 @@ handle_op_block_and_loop: } } else { /* local index larger than 255, reserve leb */ - p_org ++; - emit_leb(); + emit_uint32(loader_ctx, local_idx); } emit_operand(loader_ctx, *(loader_ctx->frame_offset - - wasm_value_type_cell_num(local_type))); + wasm_value_type_cell_num(local_type))); #else #if (WASM_ENABLE_WAMR_COMPILER == 0) && (WASM_ENABLE_JIT == 0) if (local_offset < 0x80) { diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index 12d10f5db..6bf75c513 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -1688,7 +1688,17 @@ wasm_module_malloc(WASMModuleInstance *module_inst, uint32 size, } if (!addr) { - wasm_set_exception(module_inst, "out of memory"); + if (memory->heap_handle + && mem_allocator_is_heap_corrupted(memory->heap_handle)) { + LOG_ERROR("Error: app heap is corrupted, if the wasm file " + "is compiled by wasi-sdk-12.0 or larger version, " + "please add -Wl,--export=malloc -Wl,--export=free " + " to export malloc and free functions."); + wasm_set_exception(module_inst, "app heap corrupted"); + } + else { + wasm_set_exception(module_inst, "out of memory"); + } return 0; } if (p_native_addr) diff --git a/core/shared/mem-alloc/ems/ems_gc.h b/core/shared/mem-alloc/ems/ems_gc.h index c712c9087..a9db04c7d 100644 --- a/core/shared/mem-alloc/ems/ems_gc.h +++ b/core/shared/mem-alloc/ems/ems_gc.h @@ -109,12 +109,14 @@ gc_migrate(gc_handle_t handle, char *pool_buf_new, gc_size_t pool_buf_size); /** - * Destroy lock of heap + * Check whether the heap is corrupted * - * @param handle the heap handle + * @param handle handle of the heap + * + * @return true if success, false otherwise */ -void -gc_destroy_lock(gc_handle_t handle); +bool +gc_is_heap_corrupted(gc_handle_t handle); /** * Get Heap Stats diff --git a/core/shared/mem-alloc/ems/ems_kfc.c b/core/shared/mem-alloc/ems/ems_kfc.c index ddfc5e4fe..95664dc9a 100644 --- a/core/shared/mem-alloc/ems/ems_kfc.c +++ b/core/shared/mem-alloc/ems/ems_kfc.c @@ -204,11 +204,12 @@ gc_migrate(gc_handle_t handle, return 0; } -void -gc_destroy_lock(gc_handle_t handle) +bool +gc_is_heap_corrupted(gc_handle_t handle) { - gc_heap_t *heap = (gc_heap_t *) handle; - os_mutex_destroy(&heap->lock); + gc_heap_t *heap = (gc_heap_t *)handle; + + return heap->is_heap_corrupted ? true : false; } #if BH_ENABLE_GC_VERIFY != 0 diff --git a/core/shared/mem-alloc/mem_alloc.c b/core/shared/mem-alloc/mem_alloc.c index f2304f8e4..b460e6d19 100644 --- a/core/shared/mem-alloc/mem_alloc.c +++ b/core/shared/mem-alloc/mem_alloc.c @@ -63,10 +63,10 @@ mem_allocator_migrate(mem_allocator_t allocator, pool_buf_new, pool_buf_size); } -void -mem_allocator_destroy_lock(mem_allocator_t allocator) +bool +mem_allocator_is_heap_corrupted(mem_allocator_t allocator) { - gc_destroy_lock((gc_handle_t) allocator); + return gc_is_heap_corrupted((gc_handle_t) allocator); } #else /* else of DEFAULT_MEM_ALLOCATOR */ @@ -181,19 +181,5 @@ mem_allocator_migrate(mem_allocator_t allocator, (mem_allocator_tlsf *) allocator_old); } -int -mem_allocator_init_lock(mem_allocator_t allocator) -{ - mem_allocator_tlsf *allocator_tlsf = (mem_allocator_tlsf *)allocator; - return os_mutex_init(&allocator_tlsf->lock); -} - -void -mem_allocator_destroy_lock(mem_allocator_t allocator) -{ - mem_allocator_tlsf *allocator_tlsf = (mem_allocator_tlsf *)allocator; - os_mutex_destroy(&allocator_tlsf->lock); -} - #endif /* end of DEFAULT_MEM_ALLOCATOR */ diff --git a/core/shared/mem-alloc/mem_alloc.h b/core/shared/mem-alloc/mem_alloc.h index 21e97f5bc..8224889e9 100644 --- a/core/shared/mem-alloc/mem_alloc.h +++ b/core/shared/mem-alloc/mem_alloc.h @@ -42,8 +42,8 @@ int mem_allocator_migrate(mem_allocator_t allocator, char *pool_buf_new, uint32 pool_buf_size); -void -mem_allocator_destroy_lock(mem_allocator_t allocator); +bool +mem_allocator_is_heap_corrupted(mem_allocator_t allocator); #ifdef __cplusplus } From 8a477786f1539b943943f9a470e0de14c177c29b Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Fri, 8 Jan 2021 05:11:12 -0600 Subject: [PATCH 138/207] Remove unused block_addr_cache buffer in wasm loader (#493) And fix possible memory leak issue in aot loader when apply relocation failed. Signed-off-by: Wenyong Huang --- core/iwasm/aot/aot_loader.c | 4 ++-- core/iwasm/interpreter/wasm_loader.c | 16 +--------------- 2 files changed, 3 insertions(+), 17 deletions(-) diff --git a/core/iwasm/aot/aot_loader.c b/core/iwasm/aot/aot_loader.c index ced314949..c322d407e 100644 --- a/core/iwasm/aot/aot_loader.c +++ b/core/iwasm/aot/aot_loader.c @@ -1584,11 +1584,11 @@ load_relocation_section(const uint8 *buf, const uint8 *buf_end, #endif ) { if (!do_text_relocation(module, group, error_buf, error_buf_size)) - return false; + goto fail; } else { if (!do_data_relocation(module, group, error_buf, error_buf_size)) - return false; + goto fail; } } diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index 5315ca4aa..a83e02105 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -2518,7 +2518,6 @@ fail: static bool wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, - BlockAddr *block_addr_cache, char *error_buf, uint32 error_buf_size); #if WASM_ENABLE_FAST_INTERP != 0 @@ -2542,9 +2541,7 @@ load_from_sections(WASMModule *module, WASMSection *sections, uint32 aux_stack_top = (uint32)-1, global_index, func_index, i; uint32 aux_data_end_global_index = (uint32)-1; uint32 aux_heap_base_global_index = (uint32)-1; - BlockAddr *block_addr_cache; WASMType *func_type; - uint64 total_size; /* Find code and function sections if have */ while (section) { @@ -2828,23 +2825,13 @@ load_from_sections(WASMModule *module, WASMSection *sections, handle_table = wasm_interp_get_handle_table(); #endif - total_size = sizeof(BlockAddr) * (uint64)BLOCK_ADDR_CACHE_SIZE - * BLOCK_ADDR_CONFLICT_SIZE; - if (!(block_addr_cache = loader_malloc - (total_size, error_buf, error_buf_size))) { - return false; - } - for (i = 0; i < module->function_count; i++) { WASMFunction *func = module->functions[i]; - memset(block_addr_cache, 0, (uint32)total_size); - if (!wasm_loader_prepare_bytecode(module, func, block_addr_cache, + if (!wasm_loader_prepare_bytecode(module, func, error_buf, error_buf_size)) { - wasm_runtime_free(block_addr_cache); return false; } } - wasm_runtime_free(block_addr_cache); if (!module->possible_memory_grow) { WASMMemoryImport *memory_import; @@ -5692,7 +5679,6 @@ fail: static bool wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, - BlockAddr *block_addr_cache, char *error_buf, uint32 error_buf_size) { uint8 *p = func->code, *p_end = func->code + func->code_size, *p_org; From 8ec03a5165358265fff85217066a10d344a2a07d Mon Sep 17 00:00:00 2001 From: alvkeke Date: Thu, 14 Jan 2021 11:26:35 +0800 Subject: [PATCH 139/207] add porting codes of rt-thread (#494) --- README.md | 2 +- SConscript | 33 ++ build-scripts/SConscript | 88 +++++ build-scripts/SConscript_config | 123 +++++++ core/iwasm/aot/SConscript | 31 ++ core/iwasm/common/SConscript | 26 ++ core/iwasm/interpreter/SConscript | 30 ++ core/iwasm/libraries/lib-pthread/SConscript | 20 + core/iwasm/libraries/libc-builtin/SConscript | 24 ++ core/iwasm/libraries/libc-emcc/SConscript | 19 + core/iwasm/libraries/libc-wasi/SConscript | 34 ++ core/iwasm/libraries/thread-mgr/SConscript | 19 + core/shared/mem-alloc/SConscript | 33 ++ core/shared/platform/rt-thread/SConscript | 34 ++ .../platform/rt-thread/platform_internal.h | 32 ++ core/shared/platform/rt-thread/rtt_platform.c | 196 ++++++++++ .../platform/rt-thread/shared_platform.cmake | 19 + core/shared/utils/SConscript | 17 + core/shared/utils/uncommon/SConscript | 32 ++ doc/build_wamr.md | 54 +++ product-mini/platforms/rt-thread/SConscript | 18 + .../platforms/rt-thread/rtt_embed_entry.cmake | 66 ++++ .../platforms/rt-thread/rtt_wamr_entry.c | 345 ++++++++++++++++++ 23 files changed, 1294 insertions(+), 1 deletion(-) create mode 100644 SConscript create mode 100644 build-scripts/SConscript create mode 100644 build-scripts/SConscript_config create mode 100644 core/iwasm/aot/SConscript create mode 100644 core/iwasm/common/SConscript create mode 100644 core/iwasm/interpreter/SConscript create mode 100644 core/iwasm/libraries/lib-pthread/SConscript create mode 100644 core/iwasm/libraries/libc-builtin/SConscript create mode 100644 core/iwasm/libraries/libc-emcc/SConscript create mode 100644 core/iwasm/libraries/libc-wasi/SConscript create mode 100644 core/iwasm/libraries/thread-mgr/SConscript create mode 100644 core/shared/mem-alloc/SConscript create mode 100644 core/shared/platform/rt-thread/SConscript create mode 100644 core/shared/platform/rt-thread/platform_internal.h create mode 100644 core/shared/platform/rt-thread/rtt_platform.c create mode 100644 core/shared/platform/rt-thread/shared_platform.cmake create mode 100644 core/shared/utils/SConscript create mode 100644 core/shared/utils/uncommon/SConscript create mode 100644 product-mini/platforms/rt-thread/SConscript create mode 100644 product-mini/platforms/rt-thread/rtt_embed_entry.cmake create mode 100644 product-mini/platforms/rt-thread/rtt_wamr_entry.c diff --git a/README.md b/README.md index 2a4a5fbba..1b644dc21 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ The iwasm supports the following architectures: Following platforms are supported. Refer to [WAMR porting guide](./doc/port_wamr.md) for how to port WAMR to a new platform. - [Linux](./doc/build_wamr.md#linux), [Linux SGX (Intel Software Guard Extension)](./doc/linux_sgx.md), [MacOS](./doc/build_wamr.md#macos), [Android](./doc/build_wamr.md#android), [Windows](./doc/build_wamr.md#windows) -- [Zephyr](./doc/build_wamr.md#zephyr), [AliOS-Things](./doc/build_wamr.md#alios-things), [VxWorks](./doc/build_wamr.md#vxworks), [NuttX](./doc/build_wamr.md#nuttx) +- [Zephyr](./doc/build_wamr.md#zephyr), [AliOS-Things](./doc/build_wamr.md#alios-things), [VxWorks](./doc/build_wamr.md#vxworks), [NuttX](./doc/build_wamr.md#nuttx), [RT-Thread](./doc/build_wamr.md#RT-Thread) ### Build iwasm VM core (mini product) diff --git a/SConscript b/SConscript new file mode 100644 index 000000000..af4c3efef --- /dev/null +++ b/SConscript @@ -0,0 +1,33 @@ +# +# Copyright (c) 2021, RT-Thread Development Team +# +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# + +# for module compiling +import os + +from building import * + +objs = [] +cwd = GetCurrentDir() +list = os.listdir(cwd) + +if GetDepend(['PKG_USING_WAMR']): + wamr_entry_sconscript = os.path.join(cwd, "product-mini", "platforms", "rt-thread", 'SConscript') + + if os.path.isfile(wamr_entry_sconscript): + objs = objs + SConscript(wamr_entry_sconscript) + else: + print("[WAMR] entry script wrong:", wamr_entry_sconscript) + Return('objs') + + wamr_runlib_sconsript = os.path.join(cwd, "build-scripts", 'SConscript') + + if os.path.isfile(wamr_runlib_sconsript): + objs = objs + SConscript(wamr_runlib_sconsript) + else: + print("[WAMR] runtime lib script wrong:", wamr_runlib_sconsript) + +Return('objs') + diff --git a/build-scripts/SConscript b/build-scripts/SConscript new file mode 100644 index 000000000..a1839642b --- /dev/null +++ b/build-scripts/SConscript @@ -0,0 +1,88 @@ +# +# Copyright (c) 2021, RT-Thread Development Team +# +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# + +import os +from building import * + +cwd = GetCurrentDir() +objs = [] + +WAMR_ROOT_DIR = os.path.join(cwd, "..") + + +SHARED_DIR = os.path.join(WAMR_ROOT_DIR, 'core', 'shared') + +IWASM_DIR = os.path.join(WAMR_ROOT_DIR, 'core', 'iwasm') + +APP_MGR_DIR = os.path.join(WAMR_ROOT_DIR, 'core', 'app-mgr') + +APP_FRAMEWORK_DIR = os.path.join(WAMR_ROOT_DIR, 'core', 'app-framework') + +DEPS_DIR = os.path.join(WAMR_ROOT_DIR, 'core', 'deps') + +if GetDepend(['WAMR_BUILD_INTERP']): + script_path = os.path.join(IWASM_DIR, 'interpreter', 'SConscript') + objs += SConscript(script_path) + + +if GetDepend(['WAMR_BUILD_AOT']): + script_path = os.path.join(IWASM_DIR, 'aot', 'SConscript') + objs += SConscript(script_path) + if GetDepend(['WAMR_BUILD_JIT']): + script_path = os.path.join(IWASM_DIR, 'compilation', 'SConscript') + objs += SConscript(script_path) + + +if GetDepend(['WAMR_BUILD_APP_FRAMEWORK']): + objs += SConscript(os.path.join(APP_FRAMEWORK_DIR, 'SConscript')) + objs += SConscript(os.path.join(SHARED_DIR, 'coap', 'SConscript')) + objs += SConscript(os.path.join(APP_MGR_DIR, 'app-manager', 'SConscript')) + objs += SConscript(os.path.join(APP_MGR_DIR, 'app-mgr-shared', 'SConscript')) + + + +if GetDepend(['WAMR_BUILD_LIBC_BUILTIN']): + objs += SConscript(os.path.join(IWASM_DIR, 'libraries', 'libc-builtin', 'SConscript')) + + + +if GetDepend(['WAMR_BUILD_LIBC_WASI']): + objs += SConscript(os.path.join(IWASM_DIR, 'libraries', 'libc-wasi', 'SConscript')) + + +if GetDepend(['WAMR_BUILD_LIB_PTHREAD']): + objs += SConscript(os.path.join(IWASM_DIR, 'libraries', 'libc-pthread', 'SConscript')) + # TODO: 这里加一下 + + + +# if (WAMR_BUILD_THREAD_MGR EQUAL 1) +# include (${IWASM_DIR}/libraries/thread-mgr/thread_mgr.cmake) +# endif () + +if GetDepend(['WAMR_BUILD_THREAD_MGR']): + objs += SConscript(os.path.join(IWASM_DIR, 'libraries', 'thread-mgr', 'SConscript')) + + + +# if (WAMR_BUILD_LIBC_EMCC EQUAL 1) +# include (${IWASM_DIR}/libraries/libc-emcc/libc_emcc.cmake) +# endif() + +if GetDepend(['WAMR_BUILD_LIBC_EMCC']): + objs += SConscript(os.path.join(IWASM_DIR, 'libraries', 'libc-emmc', 'SConscript')) + +objs += SConscript(os.path.join(cwd, 'SConscript_config')); + + +objs += SConscript(os.path.join(SHARED_DIR, 'platform', 'rt-thread', 'SConscript')) +objs += SConscript(os.path.join(SHARED_DIR, 'mem-alloc', 'SConscript')) +objs += SConscript(os.path.join(IWASM_DIR, 'common', 'SConscript')) +objs += SConscript(os.path.join(SHARED_DIR, 'utils', 'SConscript')) + + + +Return('objs') diff --git a/build-scripts/SConscript_config b/build-scripts/SConscript_config new file mode 100644 index 000000000..1626086e5 --- /dev/null +++ b/build-scripts/SConscript_config @@ -0,0 +1,123 @@ + + +import os +import re + +from building import * +# +# Copyright (c) 2021, RT-Thread Development Team +# +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# + +Import('rtconfig') + +src = Split(''' +''') +objs = [] +cwd = GetCurrentDir() + +IWASM_INC_DIR = os.path.join(cwd, '..', 'core', 'iwasm', 'include') + +# include_directories (${IWASM_DIR}/include) + +CPPPATH = [IWASM_INC_DIR] + +if rtconfig.BUILD == 'debug': + CPPDEFINES = ['BH_DEBUG=1'] +else: + CPPDEFINES = ['BH_DEBUG=0'] + +if rtconfig.ARCH == 'arm': + if re.match('^cortex-m.*', rtconfig.CPU): + print('[WAMR] using thumbv4t') + CPPDEFINES += ['BUILD_TARGET_THUMB'] + CPPDEFINES += [r'BUILD_TARGET=\"thumbv4t\"'] + elif re.match('^cortex-a.*', rtconfig.CPU): + print('[WAMR] using armv7') + CPPDEFINES += ['BUILD_TARGET_ARM'] + CPPDEFINES += [r'BUILD_TARGET=\"armv7\"'] + elif re.match('^cortex-r.*', rtconfig.CPU): + print('[WAMR] using armv7') + CPPDEFINES += ['BUILD_TARGET_ARM'] + CPPDEFINES += [r'BUILD_TARGET=\"armv7\"'] + elif rtconfig.CPU == 'armv6': + print('[WAMR] using armv6') + CPPDEFINES += ['BUILD_TARGET_ARM'] + CPPDEFINES += [r'BUILD_TARGET=\"armv6\"'] + elif re.match('^arm9*', rtconfig.CPU): + print('[WAMR] using armv4') + CPPDEFINES += ['BUILD_TARGET_ARM'] + CPPDEFINES += [r'BUILD_TARGET=\"armv4\"'] + +else: + print("[WAMR] unknown arch", rtconfig.ARCH) + + +LIBS = ['m'] + +if GetDepend(['WAMR_BUILD_INTERP']): + CPPDEFINES += ['WASM_ENABLE_INTERP=1'] + if GetDepend(['WAMR_BUILD_FAST_INTERP']): + CPPDEFINES += ['WASM_ENABLE_FAST_INTERP=1'] + print("[WAMR] fast interpreter was enabled") + else: + CPPDEFINES += ['WASM_ENABLE_FAST_INTERP=0'] + print("[WAMR] fast interpreter was disabled") +else: + CPPDEFINES += ['WASM_ENABLE_INTERP=0'] + +CPPDEFINES += ['WASM_ENABLE_JIT=0'] + +if GetDepend(['WAMR_BUILD_MULTI_MODULE']): + CPPDEFINES += ['WASM_ENABLE_MULTI_MODULE=1'] +else: + CPPDEFINES += ['WASM_ENABLE_MULTI_MODULE=0'] + +if GetDepend(['WAMR_BUILD_SPEC_TEST']): + CPPDEFINES += ['WASM_ENABLE_SPEC_TEST=1'] + print("[WAMR] spec test compatible mode was enabled") + +if GetDepend(['WAMR_BUILD_BULK_MEMORY']): + CPPDEFINES += ['WASM_ENABLE_BULK_MEMORY=1'] + print("[WAMR] Bulk memory feature was enabled") +else: + CPPDEFINES += ['WASM_ENABLE_BULK_MEMORY=0'] + +if GetDepend(['WAMR_BUILD_SHARED_MEMORY']): + CPPDEFINES += ['WASM_ENABLE_SHARED_MEMORY=1'] + print("[WAMR] Shared memory enabled") +else: + CPPDEFINES += ['WASM_ENABLE_SHARED_MEMORY=0'] + +if GetDepend(['WAMR_BUILD_MINI_LOADER']): + CPPDEFINES += ['WASM_ENABLE_MINI_LOADER=1'] + print("[WAMR] mini loader enabled") +else: + CPPDEFINES += ['WASM_ENABLE_MINI_LOADER=0'] + +if GetDepend(['WAMR_DISABLE_HW_BOUND_CHECK']): + CPPDEFINES += ['WASM_DISABLE_HW_BOUND_CHECK=1'] + print("[WAMR] Hardware boundary check disabled") + +if GetDepend(['WAMR_BUILD_SIMD']): + CPPDEFINES += ['WASM_ENABLE_SIMD=1'] + print('[WAMR] SIMD enabled') + +if GetDepend(['WAMR_BUILD_MEMORY_PROFILING']): + CPPDEFINES += ['WASM_ENABLE_MEMORY_PROFILING=1'] + print('[WAMR] Memory profiling enabled') + +if GetDepend(['WAMR_BUILD_CUSTOM_NAME_SECTION']): + CPPDEFINES += ['WASM_ENABLE_CUSTOM_NAME_SECTION=1'] + print('[WAMR] Custom name section enabled') + +if GetDepend(['WAMR_BUILD_TAIL_CALL']): + CPPDEFINES += ['WASM_ENABLE_TAIL_CALL=1'] + print('[WAMR] Tail call enabledd') + + +group = DefineGroup('wamr_config_common', src, depend = ['PKG_USING_WAMR'], CPPPATH = CPPPATH, CPPDEFINES = CPPDEFINES, LIBS = LIBS) + +Return('group') + diff --git a/core/iwasm/aot/SConscript b/core/iwasm/aot/SConscript new file mode 100644 index 000000000..c1a3c96e7 --- /dev/null +++ b/core/iwasm/aot/SConscript @@ -0,0 +1,31 @@ +# +# Copyright (c) 2021, RT-Thread Development Team +# +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# + +from building import * +import re +Import('rtconfig') + +cwd = GetCurrentDir() + +src = Split(''' +aot_loader.c +aot_runtime.c +''') + +if rtconfig.ARCH == 'arm': + if re.match('^cortex-m.*', rtconfig.CPU): + src += ['arch/aot_reloc_thumb.c'] + elif re.match('^cortex-a.*', rtconfig.CPU): + src += ['arch/aot_reloc_arm.c'] + + +CPPPATH = [cwd, cwd + '/../include'] + +CPPDEFINES = ['WASM_ENABLE_AOT=1'] + +group = DefineGroup('iwasm_aot', src, depend = [''], CPPPATH = CPPPATH, CPPDEFINES = CPPDEFINES) + +Return('group') diff --git a/core/iwasm/common/SConscript b/core/iwasm/common/SConscript new file mode 100644 index 000000000..235b0e88b --- /dev/null +++ b/core/iwasm/common/SConscript @@ -0,0 +1,26 @@ +# +# Copyright (c) 2021, RT-Thread Development Team +# +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# + +from building import * +import re + +Import('rtconfig') + +cwd = GetCurrentDir() + +src = Glob('*.c') + +if rtconfig.ARCH == 'arm': + if re.match('^cortex-m.*', rtconfig.CPU): + src += ['arch/invokeNative_thumb.s'] + elif re.match('^cortex-a.*', rtconfig.CPU): + src += ['arch/invokeNative_arm.s'] + +CPPPATH = [cwd, cwd + '/../include'] + +group = DefineGroup('iwasm_common', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/core/iwasm/interpreter/SConscript b/core/iwasm/interpreter/SConscript new file mode 100644 index 000000000..7c0605ee9 --- /dev/null +++ b/core/iwasm/interpreter/SConscript @@ -0,0 +1,30 @@ +# +# Copyright (c) 2021, RT-Thread Development Team +# +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# + +from building import * + +cwd = GetCurrentDir() + +src = Split(''' +wasm_runtime.c +''') + +if GetDepend(['WAMR_BUILD_FAST_INTERP']): + src += ["wasm_interp_fast.c"] +else: + src += ["wasm_interp_classic.c"] + +if GetDepend(['WAMR_BUILD_MINI_LOADER']): + src += ["wasm_mini_loader.c"] +else: + src += ["wasm_loader.c"] + + +CPPPATH = [cwd] + +group = DefineGroup('iwasm_interpreter', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/core/iwasm/libraries/lib-pthread/SConscript b/core/iwasm/libraries/lib-pthread/SConscript new file mode 100644 index 000000000..d03936c2f --- /dev/null +++ b/core/iwasm/libraries/lib-pthread/SConscript @@ -0,0 +1,20 @@ +# +# Copyright (c) 2021, RT-Thread Development Team +# +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# + +from building import * + +cwd = GetCurrentDir() + +src = Split(''' +libc_pthread_wrapper.c +''') + +CPPPATH = [cwd] + + +group = DefineGroup('iwasm_libc_pthread', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/core/iwasm/libraries/libc-builtin/SConscript b/core/iwasm/libraries/libc-builtin/SConscript new file mode 100644 index 000000000..8dd004382 --- /dev/null +++ b/core/iwasm/libraries/libc-builtin/SConscript @@ -0,0 +1,24 @@ +# +# Copyright (c) 2021, RT-Thread Development Team +# +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# + +from building import * + +cwd = GetCurrentDir() + +#src = Split(''' +#libc_builtin_wrapper.c +#''') + +src = Glob('*.c') + +CPPDEFINES = ['WASM_ENABLE_LIBC_BUILTIN=1'] + +CPPPATH = [cwd] + + +group = DefineGroup('iwasm_libc_builtin', src, depend = [''], CPPPATH = CPPPATH, CPPDEFINES = CPPDEFINES) + +Return('group') diff --git a/core/iwasm/libraries/libc-emcc/SConscript b/core/iwasm/libraries/libc-emcc/SConscript new file mode 100644 index 000000000..432ed4a05 --- /dev/null +++ b/core/iwasm/libraries/libc-emcc/SConscript @@ -0,0 +1,19 @@ +# +# Copyright (c) 2021, RT-Thread Development Team +# +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# + +from building import * + +cwd = GetCurrentDir() + +src = Split(''' +libc_emcc_wrapper.c +''') + +CPPPATH = [cwd] + +group = DefineGroup('iwasm_libc_emcc', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/core/iwasm/libraries/libc-wasi/SConscript b/core/iwasm/libraries/libc-wasi/SConscript new file mode 100644 index 000000000..6ed3799e0 --- /dev/null +++ b/core/iwasm/libraries/libc-wasi/SConscript @@ -0,0 +1,34 @@ +# +# Copyright (c) 2021, RT-Thread Development Team +# +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# + +from building import * +import os + +cwd = GetCurrentDir() + +src = Split(''' +''') + +CPPPATH = [cwd, + cwd+'/sandboxed-system-primitives/include', + cwd+'/sandboxed-system-primitives/src'] + +def addSrcFiles(arr, path): + for f in os.listdir(path): + fpath = os.path.join(path, f); + if os.path.isfile(fpath): + ext = os.path.splitext(fpath)[-1] + if ext == '.c' or ext == '.cpp': + arr += [fpath] + elif os.path.isdir(fpath): + addSrcFiles(arr, fpath) + + +addSrcFiles(src, cwd) + +group = DefineGroup('iwasm_libc_wasi', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/core/iwasm/libraries/thread-mgr/SConscript b/core/iwasm/libraries/thread-mgr/SConscript new file mode 100644 index 000000000..65f561ae2 --- /dev/null +++ b/core/iwasm/libraries/thread-mgr/SConscript @@ -0,0 +1,19 @@ +# +# Copyright (c) 2021, RT-Thread Development Team +# +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# + +from building import * + +cwd = GetCurrentDir() + +src = Split(''' +thread_manager.c +''') + +CPPPATH = [cwd] + +group = DefineGroup('iwasm_lib_thread_mgr', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/core/shared/mem-alloc/SConscript b/core/shared/mem-alloc/SConscript new file mode 100644 index 000000000..602d87158 --- /dev/null +++ b/core/shared/mem-alloc/SConscript @@ -0,0 +1,33 @@ +# +# Copyright (c) 2021, RT-Thread Development Team +# +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# + +from building import * +import os + +cwd = GetCurrentDir() + +src = Split(''' +''') + + +def addSrcFiles(arr, path): + for f in os.listdir(path): + fpath = os.path.join(path, f); + if os.path.isfile(fpath): + ext = os.path.splitext(fpath)[-1] + if ext == '.c' or ext == '.cpp': + arr += [fpath] + elif os.path.isdir(fpath): + addSrcFiles(arr, fpath) + + + +addSrcFiles(src, cwd); +CPPPATH = [cwd, cwd+'/../include'] + +group = DefineGroup('iwasm_platform_core', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/core/shared/platform/rt-thread/SConscript b/core/shared/platform/rt-thread/SConscript new file mode 100644 index 000000000..1e93f4755 --- /dev/null +++ b/core/shared/platform/rt-thread/SConscript @@ -0,0 +1,34 @@ +# +# Copyright (c) 2021, RT-Thread Development Team +# +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# + + +from building import * +import os + +cwd = GetCurrentDir() + +src = Split(''' +''') + + +def addSrcFiles(arr, path): + for f in os.listdir(path): + fpath = os.path.join(path, f); + if os.path.isfile(fpath): + ext = os.path.splitext(fpath)[-1] + if ext == '.c' or ext == '.cpp': + arr += [fpath] + elif os.path.isdir(fpath): + addSrcFiles(arr, fpath) + + + +addSrcFiles(src, cwd); +CPPPATH = [cwd, cwd+'/../include'] + +group = DefineGroup('iwasm_platform_core', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/core/shared/platform/rt-thread/platform_internal.h b/core/shared/platform/rt-thread/platform_internal.h new file mode 100644 index 000000000..9ca34422b --- /dev/null +++ b/core/shared/platform/rt-thread/platform_internal.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef RTTHREAD_PLATFORM_INTERNAL_H +#define RTTHREAD_PLATFORM_INTERNAL_H + +#include +#include +#include +#include +#include +#include +#include +#include + +typedef rt_thread_t korp_tid; +typedef struct rt_mutex korp_mutex; +typedef struct rt_thread korp_cond; +typedef struct rt_thread korp_thread; + +typedef rt_uint8_t uint8_t; +typedef rt_int8_t int8_t; +typedef rt_uint16_t uint16_t; +typedef rt_int16_t int16_t; +typedef rt_uint64_t uint64_t; +typedef rt_int64_t int64_t; + + +#endif //RTTHREAD_PLATFORM_INTERNAL_H diff --git a/core/shared/platform/rt-thread/rtt_platform.c b/core/shared/platform/rt-thread/rtt_platform.c new file mode 100644 index 000000000..508d89538 --- /dev/null +++ b/core/shared/platform/rt-thread/rtt_platform.c @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include +#include + +typedef struct os_malloc_list { + void* real; + void* used; + rt_list_t node; +}os_malloc_list_t; + +int bh_platform_init(void) +{ + return 0; +} + +void bh_platform_destroy(void) +{ +} + +void *os_malloc(unsigned size) +{ + void *buf_origin; + void *buf_fixed; + rt_ubase_t *addr_field; + + if (size == 0) + { + return RT_NULL; + } + buf_origin = rt_malloc(size + 8 + sizeof(rt_ubase_t)); + buf_fixed = buf_origin + sizeof(void*); + if ((rt_ubase_t)buf_fixed & 0x7) + { + buf_fixed = (void*)((rt_ubase_t)(buf_fixed+8)&(~7)); + } + + addr_field = buf_fixed - sizeof(rt_ubase_t); + *addr_field = (rt_ubase_t )buf_origin; + + return buf_fixed; + +} + +void *os_realloc(void *ptr, unsigned size) +{ + + void* mem_origin; + void* mem_new; + void *mem_new_fixed; + rt_ubase_t *addr_field; + + if (!ptr) + { + return RT_NULL; + } + + addr_field = ptr - sizeof(rt_ubase_t); + mem_origin = (void*)(*addr_field); + mem_new = rt_realloc(mem_origin, size + 8 + sizeof(rt_ubase_t)); + + if (mem_origin != mem_new) + { + mem_new_fixed = mem_new + sizeof(rt_ubase_t); + if ((rt_ubase_t)mem_new_fixed & 0x7) + { + mem_new_fixed = (void*)((rt_ubase_t)(mem_new_fixed+8)&(~7)); + } + + addr_field = mem_new_fixed - sizeof(rt_ubase_t); + *addr_field = (rt_ubase_t )mem_new; + + return mem_new_fixed; + } + + return ptr; +} + +void os_free(void *ptr) +{ + void* mem_origin; + rt_ubase_t *addr_field; + + if (ptr) + { + addr_field = ptr - sizeof(rt_ubase_t); + mem_origin = (void*)(*addr_field); + + rt_free(mem_origin); + } + +} + + +static char wamr_vprint_buf[RT_CONSOLEBUF_SIZE * 2]; +int os_printf(const char *format, ...) +{ + va_list ap; + va_start(ap, format); + rt_size_t len = vsnprintf(wamr_vprint_buf, sizeof(wamr_vprint_buf)-1, format, ap); + wamr_vprint_buf[len] = 0x00; + rt_kputs(wamr_vprint_buf); + va_end(ap); + return 0; +} + +int os_vprintf(const char *format, va_list ap) +{ + rt_size_t len = vsnprintf(wamr_vprint_buf, sizeof(wamr_vprint_buf)-1, format, ap); + wamr_vprint_buf[len] = 0; + rt_kputs(wamr_vprint_buf); + return 0; +} + +uint64 os_time_get_boot_microsecond(void) +{ + uint64 ret = rt_tick_get()*1000; + ret /= RT_TICK_PER_SECOND; + return ret; +} + +korp_tid os_self_thread(void) +{ + return rt_thread_self(); +} + +uint8 *os_thread_get_stack_boundary(void) +{ + rt_thread_t tid = rt_thread_self(); + return tid->stack_addr; +} + +int os_mutex_init(korp_mutex *mutex) +{ + return rt_mutex_init(mutex, "wamr0", RT_IPC_FLAG_FIFO); +} + +int os_mutex_destroy(korp_mutex *mutex) +{ + return rt_mutex_detach(mutex); +} + +int os_mutex_lock(korp_mutex *mutex) +{ + return rt_mutex_take(mutex, RT_WAITING_FOREVER); +} + +int os_mutex_unlock(korp_mutex *mutex) +{ + return rt_mutex_release(mutex); +} + + +/* + * functions below was not implement + */ + +int os_cond_init(korp_cond *cond) +{ + return 0; +} + +int os_cond_destroy(korp_cond *cond) +{ + return 0; +} + +int os_cond_wait(korp_cond *cond, korp_mutex *mutex) +{ + return 0; +} + +void *os_mmap(void *hint, size_t size, int prot, int flags) +{ + return rt_malloc(size); +} + +void os_munmap(void *addr, size_t size) +{ + rt_free(addr); +} + +#ifdef OS_ENABLE_HW_BOUND_CHECK +int os_mprotect(void *addr, size_t size, int prot) +{ + return 0; +} +#endif + +void os_dcache_flush(void) +{ +} diff --git a/core/shared/platform/rt-thread/shared_platform.cmake b/core/shared/platform/rt-thread/shared_platform.cmake new file mode 100644 index 000000000..fce9bff33 --- /dev/null +++ b/core/shared/platform/rt-thread/shared_platform.cmake @@ -0,0 +1,19 @@ +# +# Copyright (c) 2021, RT-Thread Development Team +# +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# + +set (PLATFORM_SHARED_DIR ${CMAKE_CURRENT_LIST_DIR}) + +add_definitions(-DBH_PLATFORM_RTT) + +include_directories(${PLATFORM_SHARED_DIR}) +include_directories(${PLATFORM_SHARED_DIR}/../include) + +# include (${CMAKE_CURRENT_LIST_DIR}/../common/math/platform_api_math.cmake) + +file (GLOB_RECURSE source_all ${PLATFORM_SHARED_DIR}/*.c) + +set (PLATFORM_SHARED_SOURCE ${source_all} ${PLATFORM_COMMON_MATH_SOURCE}) + diff --git a/core/shared/utils/SConscript b/core/shared/utils/SConscript new file mode 100644 index 000000000..358f2ffca --- /dev/null +++ b/core/shared/utils/SConscript @@ -0,0 +1,17 @@ +# +# Copyright (c) 2021, RT-Thread Development Team +# +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# + +from building import * +import os + +cwd = GetCurrentDir() + +src = Glob('*.c') +CPPPATH = [cwd] + +group = DefineGroup('iwasm_shared_utils', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/core/shared/utils/uncommon/SConscript b/core/shared/utils/uncommon/SConscript new file mode 100644 index 000000000..f608645fe --- /dev/null +++ b/core/shared/utils/uncommon/SConscript @@ -0,0 +1,32 @@ +# +# Copyright (c) 2021, RT-Thread Development Team +# +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# + +from building import * +import os + +cwd = GetCurrentDir() + +# src = Split(''' +# ''') + + +def addSrcFiles(arr, path): + for f in os.listdir(path): + fpath = os.path.join(path, f); + if os.path.isfile(fpath): + ext = os.path.splitext(fpath)[-1] + if ext == '.c' or ext == '.cpp': + arr += [fpath] + #elif os.path.isdir(fpath): + # addSrcFiles(arr, fpath) + +src = Glob('*.c') +src += Glob('*.cpp') +CPPPATH = [cwd] + +group = DefineGroup('iwasm_shared_utils_uncommon', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/doc/build_wamr.md b/doc/build_wamr.md index 57a65a738..f26f1a2bc 100644 --- a/doc/build_wamr.md +++ b/doc/build_wamr.md @@ -305,6 +305,60 @@ AliOS-Things ``` download the binary to developerkit board, check the output from serial port +RT-Thread +------------------------- + +1. Get rt-thread [system codes](https://github.com/RT-Thread/rt-thread). + +2. Enable WAMR software package with menuconfig tool which provided by RT-Thread. + + * Environment in Linux, run command below: + + ```bash + scons --menuconfig + ``` + + * Environment in Windows ConEmu, run command below: + + ```bash + menuconfig + ``` + + Select and enable `WAMR` in: + + * RT-Thread online packages + * tools packages + * WebAssembly Micro Runtime (WAMR) + +3. Configure `WAMR` with menuconfig tool. + + you can choice features of iwasm below: + + * Enable testing parameters of iwasm + * Enable interpreter Mode / Fast interpreter Mode + * Use built-libc + * Enable AOT + +4. Exit menuconfig tool and save configure, update and download package. + + ```bash + pkgs --update + ``` + +5. build project and download the binary to boards. + + ```bash + scons + ``` + + or build project with 8-thread by using command below: + + ```bash + scons -j8 + ``` + + after project building, you can got an binary file named `rtthread.bin`, then you can download this file to the MCU board. + Android ------------------------- able to generate a shared library support Android platform. diff --git a/product-mini/platforms/rt-thread/SConscript b/product-mini/platforms/rt-thread/SConscript new file mode 100644 index 000000000..8f866caf1 --- /dev/null +++ b/product-mini/platforms/rt-thread/SConscript @@ -0,0 +1,18 @@ +# +# Copyright (c) 2021, RT-Thread Development Team +# +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# + +from building import * + +cwd = GetCurrentDir() + + +src = Glob('*.c') + +CPPPATH = [cwd] + +group = DefineGroup('iwasm_entry', src, depend = ['PKG_USING_WAMR'], CPPPATH = CPPPATH) + +Return('group') diff --git a/product-mini/platforms/rt-thread/rtt_embed_entry.cmake b/product-mini/platforms/rt-thread/rtt_embed_entry.cmake new file mode 100644 index 000000000..0ec54ae6b --- /dev/null +++ b/product-mini/platforms/rt-thread/rtt_embed_entry.cmake @@ -0,0 +1,66 @@ +# +# Copyright (c) 2021, RT-Thread Development Team +# +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# + +set(CMAKE_ASM_COMPILER_WORKS 1) + +set(WAMR_BUILD_PLATFORM "rt-thread") +set(WAMR_BUILD_TARGET "ARM") + +#set(WAMR_BUILD_INTERP 1) +#set(WAMR_BUILD_FAST_INTERP 1) +#set(WAMR_BUILD_AOT 0) +#set(WAMR_BUILD_JIT 0) +#set(WAMR_BUILD_LIBC_BUILTIN 1) +#set(WAMR_BUILD_LIBC_WASI 0) + +if (NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Release) +endif () + +if (NOT DEFINED WAMR_BUILD_INTERP) + # Enable Interpreter by default + set (WAMR_BUILD_INTERP 1) +endif () + +if (NOT DEFINED WAMR_BUILD_AOT) + # Enable AOT by default. + set (WAMR_BUILD_AOT 0) +endif () + +# Disable JIT by default. +set (WAMR_BUILD_JIT 0) + +if (NOT DEFINED WAMR_BUILD_LIBC_BUILTIN) + # Enable libc builtin support by default + set (WAMR_BUILD_LIBC_BUILTIN 1) +endif () + +set (WAMR_BUILD_LIBC_WASI 0) + +if (NOT DEFINED WAMR_BUILD_FAST_INTERP) + # Enable fast interpreter + set (WAMR_BUILD_FAST_INTERP 1) +endif () + +set (WAMR_BUILD_MULTI_MODULE 0) +set (WAMR_BUILD_LIB_PTHREAD 0) +set (WAMR_BUILD_MINI_LOADER 0) +set (WAMR_BUILD_SIMD 0) + + +set(WAMR_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../../..) + +set(CMAKE_ASM_COMPILER_WORKS 1) + +include(${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) + +file (GLOB wamr_entry_src + ${WAMR_ROOT_DIR}/product-mini/platforms/rt-thread/rtt_wamr_entry.c + ) + +set(WAMR_SOURCE ${wamr_entry_src} ${WAMR_RUNTIME_LIB_SOURCE}) + + diff --git a/product-mini/platforms/rt-thread/rtt_wamr_entry.c b/product-mini/platforms/rt-thread/rtt_wamr_entry.c new file mode 100644 index 000000000..0b9b25e28 --- /dev/null +++ b/product-mini/platforms/rt-thread/rtt_wamr_entry.c @@ -0,0 +1,345 @@ +/* + * Copyright (c) 2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include +#include "wasm_export.h" +#include "platform_api_vmcore.h" +#include +#include +#include +#include + +static int wasm_vprintf(wasm_exec_env_t env, const char* fmt, va_list va) +{ + return vprintf(fmt, va); +} + +static int wasm_vsprintf(wasm_exec_env_t env, char* buf, const char* fmt, va_list va) +{ + return vsprintf(buf, fmt, va); +} + +static int wasm_vsnprintf(wasm_exec_env_t env, char *buf, int n, const char *fmt, va_list va) +{ + return vsnprintf(buf, n, fmt, va); +} + +static rt_device_t wasm_rt_device_find(wasm_exec_env_t env, const char *name) +{ + return rt_device_find(name); +} + +static rt_err_t wasm_rt_device_open(wasm_exec_env_t env, rt_device_t dev, rt_uint16_t o_flag) +{ + return rt_device_open(dev , o_flag); +} + +static rt_size_t wasm_rt_device_write(wasm_exec_env_t env, rt_device_t dev, rt_off_t offset, const void*buf, rt_size_t size) +{ + return rt_device_write(dev, offset, buf, size); +} + +static rt_size_t wasm_rt_device_read(wasm_exec_env_t env, rt_device_t dev, rt_off_t offset, void *buf, rt_size_t size) +{ + return rt_device_read(dev, offset, buf, size); +} + +static rt_err_t wasm_rt_device_close(wasm_exec_env_t env, rt_device_t dev) +{ + return rt_device_close(dev); +} + +static rt_err_t wasm_rt_device_control(wasm_exec_env_t env, rt_device_t dev, int cmd, void *arg) +{ + return rt_device_control(dev, cmd, arg); +} + +static NativeSymbol native_export_symbols[] = { + { + "vprintf", + wasm_vprintf, + "($*)i" + }, + { + "vsprintf", + wasm_vsprintf, + "($$*)i" + }, + { + "vsnprintf", + wasm_vsnprintf, + "($i$*)i" + }, + { + "rt_device_find", + wasm_rt_device_find, + "($)i" + }, + { + "rt_device_open", + wasm_rt_device_open, + "(ii)i" + }, + { + "rt_device_write", + wasm_rt_device_write, + "(ii*~)i" + }, + { + "rt_device_read", + wasm_rt_device_read, + "(ii*~)i" + }, + { + "rt_device_close", + wasm_rt_device_close, + "(i)i" + }, + { + "rt_device_control", + wasm_rt_device_control, + "(ii*)i" + } +}; + +/** + * run WASM module instance. + * @param module_inst instance of wasm module + * @param app_argc wasm argument count + * @param app_argv wasm arguments + * @return NULL + */ +static void * +app_instance_main(wasm_module_inst_t module_inst, int app_argc, char **app_argv) +{ + const char *exception; + + wasm_application_execute_main(module_inst, app_argc, app_argv); + if ((exception = wasm_runtime_get_exception(module_inst))) + rt_kprintf("%s\n", exception); + return NULL; +} + +rt_uint8_t *my_read_file_to_buffer(char* filename, rt_uint32_t *size) +{ + struct stat f_stat; + dfs_file_stat(filename, &f_stat); + struct dfs_fd fd; + + rt_uint8_t* buff = rt_malloc(f_stat.st_size); + *size = 0; + if (!buff) + { + rt_set_errno(-ENOMEM); + return RT_NULL; + } + + int ret = dfs_file_open(&fd, filename, O_RDONLY); + if (ret) + { + rt_free(buff); + rt_set_errno(ret); + return RT_NULL; + } + + *size = dfs_file_read(&fd, buff, f_stat.st_size); + + dfs_file_close(&fd); + + if (*size != f_stat.st_size) + { + rt_free(buff); + rt_set_errno(-EBADF); + return RT_NULL; + } + + return buff; +} + +void iwasm_help(void) +{ +#ifdef WAMR_ENABLE_IWASM_PARAMS + rt_kputs("wrong input: iwasm [-t] [-m] [-s] <*.wasm> \n iwasm [-h]\n"); + rt_kputs("\t -h: show this tips.\n"); + rt_kputs("\t -t: show time taking to run this app.\n"); + rt_kputs("\t -m: show memory taking to run this app\n"); + rt_kputs("\t wasm file name and exec params must behind of all vm-param\n"); +#else + rt_kputs("wrong input: iwasm <*.wasm> \n"); +#endif /* WAMR_ENABLE_PARAMS */ +} + +int iwasm(int argc, char **argv) +{ + rt_uint8_t *wasm_file_buf = NULL; + rt_uint32_t wasm_file_size; + rt_uint32_t stack_size = 4 * 1024, heap_size = 4 * 1024; + wasm_module_t wasm_module = NULL; + wasm_module_inst_t wasm_module_inst = NULL; + RuntimeInitArgs init_args; + static char error_buf[128] = { 0 }; + // avoid stack overflow + +#ifdef WAMR_ENABLE_IWASM_PARAMS + int i_arg_begin; + bool show_mem = false; + bool show_stack = false; + bool show_time_exec = false; + for(i_arg_begin=1; i_arg_begin < argc; i_arg_begin++) + { + if (argv[i_arg_begin][0] != '-') + { + break; + } + + if (argv[i_arg_begin][1] == 'm') + { + show_mem = true; + } + else if (argv[i_arg_begin][1] == 's') + { + show_stack = true; + } + else if (argv[i_arg_begin][1] == 't') + { + show_time_exec = true; + } + else if (argv[i_arg_begin][1] == 'h') + { + iwasm_help(); + return 0; + } + else if (argv[i_arg_begin][1] == 0x00) + { + continue; + } + else + { + rt_kprintf("[iwasm] unknown param: %s\n", argv[i_arg_begin]); + } + } +#else /* WAMR_ENABLE_PARAMS */ +#define i_arg_begin 1 +#endif /* WAMR_ENABLE_PARAMS */ + + if (argc - i_arg_begin < 1) + { + iwasm_help(); + return -1; + } + + rt_memset(&init_args, 0, sizeof(RuntimeInitArgs)); + init_args.mem_alloc_type = Alloc_With_Allocator; + init_args.mem_alloc_option.allocator.malloc_func = os_malloc; + init_args.mem_alloc_option.allocator.realloc_func = os_realloc; + init_args.mem_alloc_option.allocator.free_func = os_free; + init_args.native_symbols = native_export_symbols; + init_args.n_native_symbols = sizeof(native_export_symbols) / sizeof(NativeSymbol); + init_args.native_module_name = "env"; + +#ifdef WAMR_ENABLE_IWASM_PARAMS +#if defined(RT_USING_HEAP) && defined(RT_USING_MEMHEAP_AS_HEAP) + extern long list_memheap(void); + if (show_mem) + { + list_memheap(); + } +#else + rt_uint32_t total, max, used; + if (show_mem) + { + rt_memory_info(&total, &used, &max); + } +#endif + rt_thread_t tid; + if (show_stack) + { + tid = rt_thread_self(); + printf("thread stack addr: %p, size: %u, sp: %p\n", tid->stack_addr, tid->stack_size, tid->sp); + } +#endif /* WAMR_ENABLE_PARAMS */ + + if (wasm_runtime_full_init(&init_args) == false) + { + rt_kprintf("Init WASM runtime environment failed.\n"); + return -1; + } + + wasm_file_buf = my_read_file_to_buffer (argv[i_arg_begin], &wasm_file_size); + if (!wasm_file_buf) + { + rt_err_t err = rt_get_errno(); + rt_kprintf("WASM load file to RAM failed: %d\n", err); + goto fail1; + } + rt_memset(error_buf, 0x00, sizeof(error_buf)); + wasm_module = wasm_runtime_load(wasm_file_buf, wasm_file_size, error_buf, sizeof(error_buf)); + if (!wasm_module) + { + rt_kprintf("%s\n", error_buf); + goto fail2; + } + rt_memset(error_buf, 0x00, sizeof(error_buf)); + wasm_module_inst = wasm_runtime_instantiate(wasm_module, stack_size, heap_size, error_buf, sizeof(error_buf)); + if (!wasm_module_inst) + { + rt_kprintf("%s\n", error_buf); + goto fail3; + } + +#ifdef WAMR_ENABLE_IWASM_PARAMS + rt_tick_t ticks_exec; + if (show_time_exec) { + ticks_exec = rt_tick_get(); + } +#endif /* WAMR_ENABLE_PARAMS */ + + app_instance_main(wasm_module_inst, argc - i_arg_begin, &argv[i_arg_begin]); + +#ifdef WAMR_ENABLE_IWASM_PARAMS + if (show_time_exec) + { + ticks_exec = rt_tick_get() - ticks_exec; + printf("[iwasm] execute ticks took: %u [ticks/s = %u]\n", ticks_exec, RT_TICK_PER_SECOND); + } +#if defined(RT_USING_HEAP) && defined(RT_USING_MEMHEAP_AS_HEAP) + if (show_mem) + { + list_memheap(); + } +#else + rt_uint32_t total_after, max_after, used_after; + if (show_mem) + { + rt_memory_info(&total_after, &used_after, &max_after); + rt_kprintf("[iwasm] memory took: %u\n", used_after - used); + } +#endif + if (show_stack) + { + printf("[iwasm] thread stack addr: %p, size: %u, sp: %p\n", tid->stack_addr, tid->stack_size, tid->sp); + } + +#endif /* WAMR_ENABLE_PARAMS */ + + /* destroy the module instance */ + wasm_runtime_deinstantiate(wasm_module_inst); + + fail3: + /* unload the module */ + wasm_runtime_unload(wasm_module); + + fail2: + /* free the file buffer */ + rt_free(wasm_file_buf); + + fail1: + /* destroy runtime environment */ + wasm_runtime_destroy(); + return 0; +} +MSH_CMD_EXPORT(iwasm, Embeded VM of WebAssembly); + From 794028a9687f57d03677bc5275f94d970be960bb Mon Sep 17 00:00:00 2001 From: alvkeke Date: Thu, 14 Jan 2021 18:47:52 +0800 Subject: [PATCH 140/207] 1. fix error while building project with RT-Thread Studio. (#497) 2. add macro to enable/disable export native method of rt-thread. --- build-scripts/SConscript_config | 11 ++--- .../platform/rt-thread/platform_internal.h | 14 ++++++ .../platforms/rt-thread/rtt_wamr_entry.c | 47 ++++++++++++++++++- 3 files changed, 65 insertions(+), 7 deletions(-) diff --git a/build-scripts/SConscript_config b/build-scripts/SConscript_config index 1626086e5..37f59df9f 100644 --- a/build-scripts/SConscript_config +++ b/build-scripts/SConscript_config @@ -32,24 +32,23 @@ if rtconfig.ARCH == 'arm': if re.match('^cortex-m.*', rtconfig.CPU): print('[WAMR] using thumbv4t') CPPDEFINES += ['BUILD_TARGET_THUMB'] - CPPDEFINES += [r'BUILD_TARGET=\"thumbv4t\"'] + CPPDEFINES += ['RTT_WAMR_BUILD_TARGET_THUMB'] elif re.match('^cortex-a.*', rtconfig.CPU): print('[WAMR] using armv7') CPPDEFINES += ['BUILD_TARGET_ARM'] - CPPDEFINES += [r'BUILD_TARGET=\"armv7\"'] + CPPDEFINES += ['RTT_WAMR_BUILD_TARGET_ARMV7'] elif re.match('^cortex-r.*', rtconfig.CPU): print('[WAMR] using armv7') CPPDEFINES += ['BUILD_TARGET_ARM'] - CPPDEFINES += [r'BUILD_TARGET=\"armv7\"'] + CPPDEFINES += ['RTT_WAMR_BUILD_TARGET_ARMV7'] elif rtconfig.CPU == 'armv6': print('[WAMR] using armv6') CPPDEFINES += ['BUILD_TARGET_ARM'] - CPPDEFINES += [r'BUILD_TARGET=\"armv6\"'] + CPPDEFINES += ['RTT_WAMR_BUILD_TARGET_ARMV6'] elif re.match('^arm9*', rtconfig.CPU): print('[WAMR] using armv4') CPPDEFINES += ['BUILD_TARGET_ARM'] - CPPDEFINES += [r'BUILD_TARGET=\"armv4\"'] - + CPPDEFINES += ['RTT_WAMR_BUILD_TARGET_ARMV4'] else: print("[WAMR] unknown arch", rtconfig.ARCH) diff --git a/core/shared/platform/rt-thread/platform_internal.h b/core/shared/platform/rt-thread/platform_internal.h index 9ca34422b..1480a9e44 100644 --- a/core/shared/platform/rt-thread/platform_internal.h +++ b/core/shared/platform/rt-thread/platform_internal.h @@ -16,6 +16,20 @@ #include #include +#if defined(WASM_ENABLE_AOT) +#if defined(RTT_WAMR_BUILD_TARGET_THUMB) +#define BUILD_TARGET "thumbv4t" +#elif defined(RTT_WAMR_BUILD_TARGET_ARMV7) +#define BUILD_TARGET "armv7" +#elif defined(RTT_WAMR_BUILD_TARGET_ARMV6) +#define BUILD_TARGET "armv6" +#elif defined(RTT_WAMR_BUILD_TARGET_ARMV4) +#define BUILD_TARGET "armv4" +#else +#error "unsupported aot platform." +#endif +#endif /* WASM_ENABLE_AOT */ + typedef rt_thread_t korp_tid; typedef struct rt_mutex korp_mutex; typedef struct rt_thread korp_cond; diff --git a/product-mini/platforms/rt-thread/rtt_wamr_entry.c b/product-mini/platforms/rt-thread/rtt_wamr_entry.c index 0b9b25e28..799fd44d2 100644 --- a/product-mini/platforms/rt-thread/rtt_wamr_entry.c +++ b/product-mini/platforms/rt-thread/rtt_wamr_entry.c @@ -12,6 +12,9 @@ #include #include +#ifdef WAMR_ENABLE_RTT_EXPORT + +#ifdef WAMR_RTT_EXPORT_VPRINTF static int wasm_vprintf(wasm_exec_env_t env, const char* fmt, va_list va) { return vprintf(fmt, va); @@ -27,6 +30,9 @@ static int wasm_vsnprintf(wasm_exec_env_t env, char *buf, int n, const char *fmt return vsnprintf(buf, n, fmt, va); } +#endif /* WAMR_RTT_EXPORT_VPRINTF */ + +#ifdef WAMR_RTT_EXPORT_DEVICE_OPS static rt_device_t wasm_rt_device_find(wasm_exec_env_t env, const char *name) { return rt_device_find(name); @@ -57,7 +63,11 @@ static rt_err_t wasm_rt_device_control(wasm_exec_env_t env, rt_device_t dev, in return rt_device_control(dev, cmd, arg); } +#endif /* WAMR_RTT_EXPORT_DEVICE_OPS */ + static NativeSymbol native_export_symbols[] = { + +#ifdef WAMR_RTT_EXPORT_VPRINTF { "vprintf", wasm_vprintf, @@ -73,6 +83,9 @@ static NativeSymbol native_export_symbols[] = { wasm_vsnprintf, "($i$*)i" }, +#endif /* WAMR_RTT_EXPORT_VPRINTF */ + +#ifdef WAMR_RTT_EXPORT_DEVICE_OPS { "rt_device_find", wasm_rt_device_find, @@ -102,9 +115,39 @@ static NativeSymbol native_export_symbols[] = { "rt_device_control", wasm_rt_device_control, "(ii*)i" - } + }, +#ifdef WAMR_RTT_EXPORT_DEVICE_OPS_CPP + { + "_Z15rt_device_closeP9rt_device", + wasm_rt_device_close, + "(i)i" + }, + { + "_Z14rt_device_readP9rt_devicejPvj", + wasm_rt_device_read, + "(ii*~)i" + }, + { + "_Z15rt_device_writeP9rt_devicejPKvj", + wasm_rt_device_write, + "(ii*~)i" + }, + { + "_Z14rt_device_openP9rt_devicet", + wasm_rt_device_open, + "(ii)i" + }, + { + "_Z14rt_device_findPKc", + wasm_rt_device_find, + "($)i" + }, +#endif /* WAMR_RTT_EXPORT_DEVICE_OPS_CPP */ +#endif /* WAMR_RTT_EXPORT_DEVICE_OPS */ }; +#endif /* WAMR_ENABLE_RTT_EXPORT */ + /** * run WASM module instance. * @param module_inst instance of wasm module @@ -236,9 +279,11 @@ int iwasm(int argc, char **argv) init_args.mem_alloc_option.allocator.malloc_func = os_malloc; init_args.mem_alloc_option.allocator.realloc_func = os_realloc; init_args.mem_alloc_option.allocator.free_func = os_free; +#ifdef WAMR_ENABLE_RTT_EXPORT init_args.native_symbols = native_export_symbols; init_args.n_native_symbols = sizeof(native_export_symbols) / sizeof(NativeSymbol); init_args.native_module_name = "env"; +#endif /* WAMR_ENABLE_RTT_EXPORT */ #ifdef WAMR_ENABLE_IWASM_PARAMS #if defined(RT_USING_HEAP) && defined(RT_USING_MEMHEAP_AS_HEAP) From 240ca2ed46e1eb5d0f6901c2282f7cc9fdf4e331 Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Sun, 17 Jan 2021 23:23:10 -0600 Subject: [PATCH 141/207] Implement performance profiler and call stack dump, and update toolchain document (#501) And remove redundant FAST_INTERP macros in wasm_interp_fast.c, and fix wamrc --help wrong line order issue. Signed-off-by: Wenyong Huang --- build-scripts/SConscript_config | 11 +- build-scripts/config_common.cmake | 8 + core/config.h | 10 + core/iwasm/aot/aot_loader.c | 3 + core/iwasm/aot/aot_reloc.h | 14 +- core/iwasm/aot/aot_runtime.c | 191 +++++++++++++++++- core/iwasm/aot/aot_runtime.h | 37 +++- core/iwasm/common/wasm_runtime_common.c | 36 ++++ core/iwasm/compilation/aot_emit_function.c | 160 ++++++++++++++- core/iwasm/compilation/aot_llvm.c | 3 + core/iwasm/compilation/aot_llvm.h | 4 + core/iwasm/include/aot_export.h | 1 + core/iwasm/include/wasm_export.h | 20 +- core/iwasm/interpreter/wasm_interp.h | 9 +- core/iwasm/interpreter/wasm_interp_classic.c | 15 +- core/iwasm/interpreter/wasm_interp_fast.c | 25 +-- core/iwasm/interpreter/wasm_mini_loader.c | 15 +- core/iwasm/interpreter/wasm_runtime.c | 64 +++++- core/iwasm/interpreter/wasm_runtime.h | 17 +- .../lib-pthread/lib_pthread_wrapper.c | 2 +- doc/build_wamr.md | 12 ++ doc/build_wasm_app.md | 150 ++++++++++++-- doc/other_wasm_compilers.md | 37 ---- doc/pthread_library.md | 4 +- wamr-compiler/CMakeLists.txt | 3 + wamr-compiler/main.c | 10 +- 26 files changed, 752 insertions(+), 109 deletions(-) diff --git a/build-scripts/SConscript_config b/build-scripts/SConscript_config index 37f59df9f..f5fe373dc 100644 --- a/build-scripts/SConscript_config +++ b/build-scripts/SConscript_config @@ -1,15 +1,14 @@ - - -import os -import re - -from building import * # # Copyright (c) 2021, RT-Thread Development Team # # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception # +import os +import re + +from building import * + Import('rtconfig') src = Split(''' diff --git a/build-scripts/config_common.cmake b/build-scripts/config_common.cmake index 822be12af..2ee2a9644 100644 --- a/build-scripts/config_common.cmake +++ b/build-scripts/config_common.cmake @@ -173,6 +173,10 @@ if (WAMR_BUILD_MEMORY_PROFILING EQUAL 1) add_definitions (-DWASM_ENABLE_MEMORY_PROFILING=1) message (" Memory profiling enabled") endif () +if (WAMR_BUILD_PERF_PROFILING EQUAL 1) + add_definitions (-DWASM_ENABLE_PERF_PROFILING=1) + message (" Performance profiling enabled") +endif () if (DEFINED WAMR_APP_THREAD_STACK_SIZE_MAX) add_definitions (-DAPP_THREAD_STACK_SIZE_MAX=${WAMR_APP_THREAD_STACK_SIZE_MAX}) endif () @@ -180,6 +184,10 @@ if (WAMR_BUILD_CUSTOM_NAME_SECTION EQUAL 1) add_definitions (-DWASM_ENABLE_CUSTOM_NAME_SECTION=1) message (" Custom name section enabled") endif () +if (WAMR_BUILD_DUMP_CALL_STACK EQUAL 1) + add_definitions (-DWASM_ENABLE_DUMP_CALL_STACK=1) + message (" Dump call stack enabled") +endif () if (WAMR_BUILD_TAIL_CALL EQUAL 1) add_definitions (-DWASM_ENABLE_TAIL_CALL=1) message (" Tail call enabled") diff --git a/core/config.h b/core/config.h index 0e9c87ae7..e9f396de1 100644 --- a/core/config.h +++ b/core/config.h @@ -180,6 +180,16 @@ #define WASM_ENABLE_MEMORY_TRACING 0 #endif +/* Performance profiling */ +#ifndef WASM_ENABLE_PERF_PROFILING +#define WASM_ENABLE_PERF_PROFILING 0 +#endif + +/* Dump call stack */ +#ifndef WASM_ENABLE_DUMP_CALL_STACK +#define WASM_ENABLE_DUMP_CALL_STACK 0 +#endif + /* Heap verification */ #ifndef BH_ENABLE_GC_VERIFY #define BH_ENABLE_GC_VERIFY 0 diff --git a/core/iwasm/aot/aot_loader.c b/core/iwasm/aot/aot_loader.c index c322d407e..eb9f198f6 100644 --- a/core/iwasm/aot/aot_loader.c +++ b/core/iwasm/aot/aot_loader.c @@ -2174,6 +2174,9 @@ aot_convert_wasm_module(WASMModule *wasm_module, #endif #if WASM_ENABLE_SIMD != 0 option.enable_simd = true; +#endif +#if (WASM_ENABLE_PERF_PROFILING != 0) || (WASM_ENABLE_DUMP_CALL_STACK != 0) + option.enable_aux_stack_frame = true; #endif comp_ctx = aot_create_comp_context(comp_data, &option); if (!comp_ctx) { diff --git a/core/iwasm/aot/aot_reloc.h b/core/iwasm/aot/aot_reloc.h index cbf2f9cd5..cba15036b 100644 --- a/core/iwasm/aot/aot_reloc.h +++ b/core/iwasm/aot/aot_reloc.h @@ -29,6 +29,14 @@ typedef struct { #define REG_ATOMIC_WAIT_SYM() #endif +#if (WASM_ENABLE_PERF_PROFILING != 0) || (WASM_ENABLE_DUMP_CALL_STACK != 0) +#define REG_AOT_TRACE_SYM() \ + REG_SYM(aot_alloc_frame), \ + REG_SYM(aot_free_frame), +#else +#define REG_AOT_TRACE_SYM() +#endif + #if (defined(_WIN32) || defined(_WIN32_)) && defined(NDEBUG) #define REG_COMMON_SYMBOLS \ REG_SYM(aot_set_exception_with_id), \ @@ -39,7 +47,8 @@ typedef struct { REG_SYM(aot_memset), \ REG_SYM(aot_memmove), \ REG_BULK_MEMORY_SYM() \ - REG_ATOMIC_WAIT_SYM() + REG_ATOMIC_WAIT_SYM() \ + REG_AOT_TRACE_SYM() #else /* else of (defined(_WIN32) || defined(_WIN32_)) && defined(NDEBUG) */ #define REG_COMMON_SYMBOLS \ REG_SYM(aot_set_exception_with_id), \ @@ -62,7 +71,8 @@ typedef struct { REG_SYM(rint), \ REG_SYM(rintf), \ REG_BULK_MEMORY_SYM() \ - REG_ATOMIC_WAIT_SYM() + REG_ATOMIC_WAIT_SYM() \ + REG_AOT_TRACE_SYM() #endif /* end of (defined(_WIN32) || defined(_WIN32_)) && defined(NDEBUG) */ #define CHECK_RELOC_OFFSET(data_size) do { \ diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index d26f2161c..18518e0bb 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -814,6 +814,15 @@ aot_instantiate(AOTModule *module, bool is_sub_inst, #endif module_inst->default_wasm_stack_size = stack_size; +#if WASM_ENABLE_PERF_PROFILING != 0 + total_size = (uint64)sizeof(AOTFuncPerfProfInfo) * + (module->import_func_count + module->func_count); + if (!(module_inst->func_perf_profilings.ptr = + runtime_malloc(total_size, error_buf, error_buf_size))) { + goto fail; + } +#endif + /* Execute __post_instantiate function and start function*/ if (!execute_post_inst_function(module_inst) || !execute_start_function(module_inst)) { @@ -866,6 +875,11 @@ aot_deinstantiate(AOTModuleInstance *module_inst, bool is_sub_inst) wasm_runtime_destroy_wasi((WASMModuleInstanceCommon*)module_inst); #endif +#if WASM_ENABLE_PERF_PROFILING != 0 + if (module_inst->func_perf_profilings.ptr) + wasm_runtime_free(module_inst->func_perf_profilings.ptr); +#endif + if (module_inst->memories.ptr) memories_deinstantiate(module_inst); @@ -1128,16 +1142,38 @@ aot_call_function(WASMExecEnv *exec_env, cell_num += wasm_value_type_cell_num(ext_ret_types[i]); } +#if (WASM_ENABLE_DUMP_CALL_STACK != 0) || (WASM_ENABLE_PERF_PROFILING != 0) + if (!aot_alloc_frame(exec_env, function->func_index)) { + wasm_runtime_free(argv1); + return false; + } +#endif + ret = invoke_native_internal(exec_env, function->u.func.func_ptr, func_type, NULL, NULL, argv1, argc, argv); + if (!ret || aot_get_exception(module_inst)) { if (argv1 != argv1_buf) wasm_runtime_free(argv1); + if (clear_wasi_proc_exit_exception(module_inst)) - return true; - return false; + ret = true; + else + ret = false; } +#if WASM_ENABLE_DUMP_CALL_STACK != 0 + if (!ret) { + aot_dump_call_stack(exec_env); + } +#endif + +#if (WASM_ENABLE_DUMP_CALL_STACK != 0) || (WASM_ENABLE_PERF_PROFILING != 0) + aot_free_frame(exec_env); +#endif + if (!ret) + return ret; + /* Get extra result values */ switch (func_type->types[func_type->param_count]) { case VALUE_TYPE_I32: @@ -1161,10 +1197,28 @@ aot_call_function(WASMExecEnv *exec_env, return true; } else { +#if (WASM_ENABLE_DUMP_CALL_STACK != 0) || (WASM_ENABLE_PERF_PROFILING != 0) + if (!aot_alloc_frame(exec_env, function->func_index)) { + return false; + } +#endif + ret = invoke_native_internal(exec_env, function->u.func.func_ptr, func_type, NULL, NULL, argv, argc, argv); + if (clear_wasi_proc_exit_exception(module_inst)) - return true; + ret = true; + +#if WASM_ENABLE_DUMP_CALL_STACK != 0 + if (aot_get_exception(module_inst)) { + aot_dump_call_stack(exec_env); + } +#endif + +#if (WASM_ENABLE_DUMP_CALL_STACK != 0) || (WASM_ENABLE_PERF_PROFILING != 0) + aot_free_frame(exec_env); +#endif + return ret && !aot_get_exception(module_inst) ? true : false; } } @@ -2224,3 +2278,134 @@ aot_get_module_inst_mem_consumption(const AOTModuleInstance *module_inst, } #endif /* end of (WASM_ENABLE_MEMORY_PROFILING != 0) || (WASM_ENABLE_MEMORY_TRACING != 0) */ + +#if (WASM_ENABLE_DUMP_CALL_STACK != 0) || (WASM_ENABLE_PERF_PROFILING != 0) +static const char * +get_func_name_from_index(const AOTModuleInstance *module_inst, + uint32 func_index) +{ + const char *func_name = NULL; + AOTModule *module = module_inst->aot_module.ptr; + + if (func_index < module->import_func_count) { + func_name = module->import_funcs[func_index].func_name; + } + else { + uint32 i; + + for (i = 0; i < module->export_count; i++) { + AOTExport export = module->exports[i]; + if (export.index == func_index + && export.kind == EXPORT_KIND_FUNC) { + func_name = export.name; + break; + } + } + } + + return func_name; +} + +bool +aot_alloc_frame(WASMExecEnv *exec_env, uint32 func_index) +{ + AOTFrame *frame = + wasm_exec_env_alloc_wasm_frame(exec_env, sizeof(AOTFrame)); +#if WASM_ENABLE_PERF_PROFILING != 0 + AOTModuleInstance *module_inst = + (AOTModuleInstance*)exec_env->module_inst; + AOTFuncPerfProfInfo *func_perf_prof = + (AOTFuncPerfProfInfo*)module_inst->func_perf_profilings.ptr + func_index; +#endif + + if (!frame) { + aot_set_exception((AOTModuleInstance*)exec_env->module_inst, + "auxiliary call stack overflow"); + return false; + } + +#if WASM_ENABLE_PERF_PROFILING != 0 + frame->time_started = os_time_get_boot_microsecond(); + frame->func_perf_prof_info = func_perf_prof; +#endif + + frame->prev_frame = (AOTFrame *)exec_env->cur_frame; + exec_env->cur_frame = (struct WASMInterpFrame *)frame; + + frame->func_index = func_index; + return true; +} + +void +aot_free_frame(WASMExecEnv *exec_env) +{ + AOTFrame *cur_frame = (AOTFrame *)exec_env->cur_frame; + AOTFrame *prev_frame = cur_frame->prev_frame; + +#if WASM_ENABLE_PERF_PROFILING != 0 + cur_frame->func_perf_prof_info->total_exec_time += + os_time_get_boot_microsecond() - cur_frame->time_started; + cur_frame->func_perf_prof_info->total_exec_cnt++; +#endif + + wasm_exec_env_free_wasm_frame(exec_env, cur_frame); + exec_env->cur_frame = (struct WASMInterpFrame *)prev_frame; +} +#endif /* end of (WASM_ENABLE_DUMP_CALL_STACK != 0) + || (WASM_ENABLE_PERF_PROFILING != 0) */ + +#if WASM_ENABLE_DUMP_CALL_STACK != 0 +void +aot_dump_call_stack(WASMExecEnv *exec_env) +{ + AOTFrame *cur_frame = (AOTFrame *)exec_env->cur_frame; + AOTModuleInstance *module_inst = + (AOTModuleInstance *)exec_env->module_inst; + const char *func_name; + uint32 n = 0; + + os_printf("\n"); + while (cur_frame) { + func_name = + get_func_name_from_index(module_inst, cur_frame->func_index); + + /* function name not exported, print number instead */ + if (func_name == NULL) { + os_printf("#%02d $f%d \n", n, cur_frame->func_index); + } + else { + os_printf("#%02d %s \n", n, func_name); + } + + cur_frame = cur_frame->prev_frame; + n++; + } + os_printf("\n"); +} +#endif /* end of WASM_ENABLE_DUMP_CALL_STACK */ + +#if WASM_ENABLE_PERF_PROFILING != 0 +void +aot_dump_perf_profiling(const AOTModuleInstance *module_inst) +{ + AOTFuncPerfProfInfo *perf_prof = (AOTFuncPerfProfInfo *) + module_inst->func_perf_profilings.ptr; + AOTModule *module = (AOTModule *)module_inst->aot_module.ptr; + uint32 total_func_count = module->import_func_count + module->func_count, i; + const char *func_name; + + os_printf("Performance profiler data:\n"); + for (i = 0; i < total_func_count; i++, perf_prof++) { + func_name = get_func_name_from_index(module_inst, i); + + if (func_name) + os_printf(" func %s, execution time: %.3f ms, execution count: %d times\n", + func_name, perf_prof->total_exec_time / 1000.0f, + perf_prof->total_exec_cnt); + else + os_printf(" func %d, execution time: %.3f ms, execution count: %d times\n", + i, perf_prof->total_exec_time / 1000.0f, + perf_prof->total_exec_cnt); + } +} +#endif /* end of WASM_ENABLE_PERF_PROFILING */ diff --git a/core/iwasm/aot/aot_runtime.h b/core/iwasm/aot/aot_runtime.h index 4fab1903b..b165b9f81 100644 --- a/core/iwasm/aot/aot_runtime.h +++ b/core/iwasm/aot/aot_runtime.h @@ -281,8 +281,13 @@ typedef struct AOTModuleInstance { uint32 llvm_stack; uint32 default_wasm_stack_size; + uint32 __padding; + + /* function performance profiling info list */ + AOTPointer func_perf_profilings; + /* reserved */ - uint32 reserved[11]; + uint32 reserved[8]; union { uint64 _make_it_8_byte_aligned_; @@ -311,6 +316,24 @@ typedef struct AOTTargetInfo { char arch[16]; } AOTTargetInfo; +typedef struct AOTFuncPerfProfInfo +{ + /* total execution time */ + uint64 total_exec_time; + /* total execution count */ + uint32 total_exec_cnt; +} AOTFuncPerfProfInfo; + +/* AOT auxiliary call stack */ +typedef struct AOTFrame { + struct AOTFrame *prev_frame; + uint32 func_index; +#if WASM_ENABLE_PERF_PROFILING != 0 + uint64 time_started; + AOTFuncPerfProfInfo *func_perf_prof_info; +#endif +} AOTFrame; + /** * Load a AOT module from aot file buffer * @param buf the byte buffer which contains the AOT file data @@ -568,6 +591,18 @@ void aot_get_module_inst_mem_consumption(const AOTModuleInstance *module_inst, WASMModuleInstMemConsumption *mem_conspn); +bool +aot_alloc_frame(WASMExecEnv *exec_env, uint32 func_index); + +void +aot_free_frame(WASMExecEnv *exec_env); + +void +aot_dump_call_stack(WASMExecEnv *exec_env); + +void +aot_dump_perf_profiling(const AOTModuleInstance *module_inst); + #ifdef __cplusplus } /* end of extern "C" */ #endif diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index 9c8b3a068..125dd103d 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -960,6 +960,23 @@ wasm_runtime_dump_mem_consumption(WASMExecEnv *exec_env) #endif /* end of (WASM_ENABLE_MEMORY_PROFILING != 0) || (WASM_ENABLE_MEMORY_TRACING != 0) */ +#if WASM_ENABLE_PERF_PROFILING != 0 +void +wasm_runtime_dump_perf_profiling(WASMModuleInstanceCommon *module_inst) +{ +#if WASM_ENABLE_INTERP != 0 + if (module_inst->module_type == Wasm_Module_Bytecode) { + wasm_dump_perf_profiling((WASMModuleInstance*)module_inst); + } +#endif +#if WASM_ENABLE_AOT != 0 + if (module_inst->module_type == Wasm_Module_AoT) { + aot_dump_perf_profiling((AOTModuleInstance*)module_inst); + } +#endif +} +#endif + WASMModuleInstanceCommon * wasm_runtime_get_module_inst(WASMExecEnv *exec_env) { @@ -3453,3 +3470,22 @@ wasm_runtime_join_thread(wasm_thread_t tid, void **retval) } #endif + +#if WASM_ENABLE_DUMP_CALL_STACK != 0 +void +wasm_runtime_dump_call_stack(WASMExecEnv *exec_env) +{ + WASMModuleInstanceCommon *module_inst + = wasm_exec_env_get_module_inst(exec_env); +#if WASM_ENABLE_INTERP != 0 + if (module_inst->module_type == Wasm_Module_Bytecode) { + wasm_interp_dump_call_stack(exec_env); + } +#endif +#if WASM_ENABLE_AOT != 0 + if (module_inst->module_type == Wasm_Module_AoT) { + aot_dump_call_stack(exec_env); + } +#endif +} +#endif /* end of WASM_ENABLE_DUMP_CALL_STACK */ diff --git a/core/iwasm/compilation/aot_emit_function.c b/core/iwasm/compilation/aot_emit_function.c index 1aa9eb57b..57cac163c 100644 --- a/core/iwasm/compilation/aot_emit_function.c +++ b/core/iwasm/compilation/aot_emit_function.c @@ -8,6 +8,45 @@ #include "aot_emit_control.h" #include "../aot/aot_runtime.h" +#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) + +#define ADD_BASIC_BLOCK(block, name) do { \ + if (!(block = LLVMAppendBasicBlockInContext(comp_ctx->context, \ + func_ctx->func, \ + name))) { \ + aot_set_last_error("llvm add basic block failed."); \ + goto fail; \ + } \ + } while (0) + static bool create_func_return_block(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) { @@ -239,6 +278,91 @@ call_aot_invoke_native_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, return true; } +#if (WASM_ENABLE_DUMP_CALL_STACK != 0) || (WASM_ENABLE_PERF_PROFILING != 0) +static bool +call_aot_alloc_frame_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, + LLVMValueRef func_idx) +{ + LLVMValueRef param_values[2], ret_value, value, func; + LLVMTypeRef param_types[2], ret_type, func_type, func_ptr_type; + LLVMBasicBlockRef block_curr = LLVMGetInsertBlock(comp_ctx->builder); + LLVMBasicBlockRef frame_alloc_fail, frame_alloc_success; + AOTFuncType *aot_func_type = func_ctx->aot_func->func_type; + + param_types[0] = comp_ctx->exec_env_type; + param_types[1] = I32_TYPE; + ret_type = INT8_TYPE; + + GET_AOT_FUNCTION(aot_alloc_frame, 2); + + param_values[0] = func_ctx->exec_env; + param_values[1] = func_idx; + + if (!(ret_value = LLVMBuildCall(comp_ctx->builder, func, + param_values, 2, + "call_aot_alloc_frame"))) { + aot_set_last_error("llvm build call failed."); + return false; + } + + if (!(ret_value = LLVMBuildICmp(comp_ctx->builder, LLVMIntUGT, + ret_value, I8_ZERO, "frame_alloc_ret"))) { + aot_set_last_error("llvm build icmp failed."); + return false; + } + + ADD_BASIC_BLOCK(frame_alloc_fail, "frame_alloc_fail"); + ADD_BASIC_BLOCK(frame_alloc_success, "frame_alloc_success"); + + LLVMMoveBasicBlockAfter(frame_alloc_fail, block_curr); + LLVMMoveBasicBlockAfter(frame_alloc_success, block_curr); + + if (!LLVMBuildCondBr(comp_ctx->builder, ret_value, + frame_alloc_success, frame_alloc_fail)) { + aot_set_last_error("llvm build cond br failed."); + return false; + } + + /* If frame alloc failed, return this function + so the runtime can catch the exception */ + LLVMPositionBuilderAtEnd(comp_ctx->builder, frame_alloc_fail); + if (!aot_build_zero_function_ret(comp_ctx, aot_func_type)) { + return false; + } + + LLVMPositionBuilderAtEnd(comp_ctx->builder, frame_alloc_success); + + return true; + +fail: + return false; +} + +static bool +call_aot_free_frame_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) +{ + LLVMValueRef param_values[1], ret_value, value, func; + LLVMTypeRef param_types[1], ret_type, func_type, func_ptr_type; + + param_types[0] = comp_ctx->exec_env_type; + ret_type = INT8_TYPE; + + GET_AOT_FUNCTION(aot_free_frame, 1); + + param_values[0] = func_ctx->exec_env; + + if (!(ret_value = LLVMBuildCall(comp_ctx->builder, func, + param_values, 1, + "call_aot_free_frame"))) { + aot_set_last_error("llvm build call failed."); + return false; + } + + return true; +} +#endif /* end of (WASM_ENABLE_DUMP_CALL_STACK != 0) + || (WASM_ENABLE_PERF_PROFILING != 0) */ + static bool check_stack_boundary(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, uint32 callee_cell_num) @@ -334,6 +458,19 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, /* Get param cell number */ param_cell_num = func_type->param_cell_num; +#if (WASM_ENABLE_DUMP_CALL_STACK != 0) || (WASM_ENABLE_PERF_PROFILING != 0) + if (comp_ctx->enable_aux_stack_frame) { + LLVMValueRef func_idx_const; + + if (!(func_idx_const = I32_CONST(func_idx))) { + aot_set_last_error("llvm build const failed."); + return false; + } + if (!call_aot_alloc_frame_func(comp_ctx, func_ctx, func_idx_const)) + return false; + } +#endif + /* Allocate memory for parameters. * Parameters layout: * - exec env @@ -485,13 +622,20 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } } +#if (WASM_ENABLE_DUMP_CALL_STACK != 0) || (WASM_ENABLE_PERF_PROFILING != 0) + if (comp_ctx->enable_aux_stack_frame) { + if (!call_aot_free_frame_func(comp_ctx, func_ctx)) + goto fail; + } +#endif + ret = true; fail: if (param_types) wasm_runtime_free(param_types); if (param_values) wasm_runtime_free(param_values); - return ret; + return ret; } static bool @@ -889,6 +1033,13 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } #endif +#if (WASM_ENABLE_DUMP_CALL_STACK != 0) || (WASM_ENABLE_PERF_PROFILING != 0) + if (comp_ctx->enable_aux_stack_frame) { + if (!call_aot_alloc_frame_func(comp_ctx, func_ctx, func_idx)) + goto fail; + } +#endif + /* Add basic blocks */ block_call_import = LLVMAppendBasicBlockInContext(comp_ctx->context, func_ctx->func, @@ -1066,6 +1217,13 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, PUSH(result_phis[i], func_type->types[func_param_count + i]); } +#if (WASM_ENABLE_DUMP_CALL_STACK != 0) || (WASM_ENABLE_PERF_PROFILING != 0) + if (comp_ctx->enable_aux_stack_frame) { + if (!call_aot_free_frame_func(comp_ctx, func_ctx)) + goto fail; + } +#endif + ret = true; fail: diff --git a/core/iwasm/compilation/aot_llvm.c b/core/iwasm/compilation/aot_llvm.c index 26338dc6f..15ca7e562 100644 --- a/core/iwasm/compilation/aot_llvm.c +++ b/core/iwasm/compilation/aot_llvm.c @@ -1163,6 +1163,9 @@ aot_create_comp_context(AOTCompData *comp_data, if (option->enable_simd) comp_ctx->enable_simd = true; + if (option->enable_aux_stack_frame) + comp_ctx->enable_aux_stack_frame = true; + if (option->is_jit_mode) { char *triple_jit = NULL; diff --git a/core/iwasm/compilation/aot_llvm.h b/core/iwasm/compilation/aot_llvm.h index 599e664d9..02b249285 100644 --- a/core/iwasm/compilation/aot_llvm.h +++ b/core/iwasm/compilation/aot_llvm.h @@ -223,6 +223,9 @@ typedef struct AOTCompContext { /* 128-bit SIMD */ bool enable_simd; + /* generate auxiliary stack frame */ + bool enable_aux_stack_frame; + /* Thread Manager */ bool enable_thread_mgr; @@ -271,6 +274,7 @@ typedef struct AOTCompOption{ bool enable_thread_mgr; bool enable_tail_call; bool enable_simd; + bool enable_aux_stack_frame; bool is_sgx_platform; uint32 opt_level; uint32 size_level; diff --git a/core/iwasm/include/aot_export.h b/core/iwasm/include/aot_export.h index 78d2edc19..c1cac6782 100644 --- a/core/iwasm/include/aot_export.h +++ b/core/iwasm/include/aot_export.h @@ -43,6 +43,7 @@ typedef struct AOTCompOption{ bool enable_thread_mgr; bool enable_tail_call; bool enable_simd; + bool enable_aux_stack_frame; bool is_sgx_platform; uint32_t opt_level; uint32_t size_level; diff --git a/core/iwasm/include/wasm_export.h b/core/iwasm/include/wasm_export.h index 44c32b6f8..d8f585fc4 100644 --- a/core/iwasm/include/wasm_export.h +++ b/core/iwasm/include/wasm_export.h @@ -227,7 +227,6 @@ wasm_runtime_free(void *ptr); WASM_RUNTIME_API_EXTERN package_type_t get_package_type(const uint8_t *buf, uint32_t size); -#if WASM_ENABLE_MULTI_MODULE != 0 /** * It is a callback for WAMR providing by embedding to load a module file * into a buffer @@ -275,7 +274,6 @@ wasm_runtime_register_module(const char *module_name, wasm_module_t module, */ WASM_RUNTIME_API_EXTERN wasm_module_t wasm_runtime_find_module_registered(const char *module_name); -#endif /* WASM_ENABLE_MULTI_MODULE */ /** * Load a WASM module from a specified byte buffer. The byte buffer can be @@ -787,7 +785,14 @@ wasm_runtime_get_user_data(wasm_exec_env_t exec_env); WASM_RUNTIME_API_EXTERN void wasm_runtime_dump_mem_consumption(wasm_exec_env_t exec_env); -#if WASM_ENABLE_THREAD_MGR != 0 +/** + * Dump runtime performance profiler data of each function + * + * @param module_inst the WASM module instance to profile + */ +WASM_RUNTIME_API_EXTERN void +wasm_runtime_dump_perf_profiling(wasm_module_inst_t module_inst); + /* wasm thread callback function type */ typedef void* (*wasm_thread_callback_t)(wasm_exec_env_t, void *); /* wasm thread type */ @@ -844,7 +849,14 @@ wasm_runtime_spawn_thread(wasm_exec_env_t exec_env, wasm_thread_t *tid, */ WASM_RUNTIME_API_EXTERN int32_t wasm_runtime_join_thread(wasm_thread_t tid, void **retval); -#endif + +/** + * dump the call stack + * + * @param exec_env the execution environment + */ +WASM_RUNTIME_API_EXTERN void +wasm_runtime_dump_call_stack(wasm_exec_env_t exec_env); #ifdef __cplusplus } diff --git a/core/iwasm/interpreter/wasm_interp.h b/core/iwasm/interpreter/wasm_interp.h index 5f8672498..a0d56f328 100644 --- a/core/iwasm/interpreter/wasm_interp.h +++ b/core/iwasm/interpreter/wasm_interp.h @@ -26,6 +26,10 @@ typedef struct WASMInterpFrame { /* Instruction pointer of the bytecode array. */ uint8 *ip; +#if WASM_ENABLE_PERF_PROFILING != 0 + uint64 time_started; +#endif + #if WASM_ENABLE_FAST_INTERP != 0 /* return offset of the first return value of current frame. the callee will put return values here continuously */ @@ -74,11 +78,6 @@ wasm_interp_call_wasm(struct WASMModuleInstance *module_inst, struct WASMFunctionInstance *function, uint32 argc, uint32 argv[]); -#if WASM_ENABLE_CUSTOM_NAME_SECTION != 0 -void -wasm_interp_dump_call_stack(struct WASMExecEnv *exec_env); -#endif - #ifdef __cplusplus } #endif diff --git a/core/iwasm/interpreter/wasm_interp_classic.c b/core/iwasm/interpreter/wasm_interp_classic.c index 55c619c2e..bf39335ee 100644 --- a/core/iwasm/interpreter/wasm_interp_classic.c +++ b/core/iwasm/interpreter/wasm_interp_classic.c @@ -900,8 +900,12 @@ ALLOC_FRAME(WASMExecEnv *exec_env, uint32 size, WASMInterpFrame *prev_frame) { WASMInterpFrame *frame = wasm_exec_env_alloc_wasm_frame(exec_env, size); - if (frame) + if (frame) { frame->prev_frame = prev_frame; +#if WASM_ENABLE_PERF_PROFILING != 0 + frame->time_started = os_time_get_boot_microsecond(); +#endif + } else { wasm_set_exception((WASMModuleInstance*)exec_env->module_inst, "stack overflow"); @@ -913,6 +917,13 @@ ALLOC_FRAME(WASMExecEnv *exec_env, uint32 size, WASMInterpFrame *prev_frame) static inline void FREE_FRAME(WASMExecEnv *exec_env, WASMInterpFrame *frame) { +#if WASM_ENABLE_PERF_PROFILING != 0 + if (frame->function) { + frame->function->total_exec_time += os_time_get_boot_microsecond() + - frame->time_started; + frame->function->total_exec_cnt++; + } +#endif wasm_exec_env_free_wasm_frame(exec_env, frame); } @@ -3361,7 +3372,7 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, } } else { -#if WASM_ENABLE_CUSTOM_NAME_SECTION != 0 +#if WASM_ENABLE_DUMP_CALL_STACK != 0 wasm_interp_dump_call_stack(exec_env); #endif LOG_DEBUG("meet an exception %s", wasm_get_exception(module_inst)); diff --git a/core/iwasm/interpreter/wasm_interp_fast.c b/core/iwasm/interpreter/wasm_interp_fast.c index 53810bad0..de157f8c1 100644 --- a/core/iwasm/interpreter/wasm_interp_fast.c +++ b/core/iwasm/interpreter/wasm_interp_fast.c @@ -909,8 +909,12 @@ ALLOC_FRAME(WASMExecEnv *exec_env, uint32 size, WASMInterpFrame *prev_frame) { WASMInterpFrame *frame = wasm_exec_env_alloc_wasm_frame(exec_env, size); - if (frame) + if (frame) { frame->prev_frame = prev_frame; +#if WASM_ENABLE_PERF_PROFILING != 0 + frame->time_started = os_time_get_boot_microsecond(); +#endif + } else { wasm_set_exception((WASMModuleInstance*)exec_env->module_inst, "stack overflow"); @@ -922,6 +926,13 @@ ALLOC_FRAME(WASMExecEnv *exec_env, uint32 size, WASMInterpFrame *prev_frame) static inline void FREE_FRAME(WASMExecEnv *exec_env, WASMInterpFrame *frame) { +#if WASM_ENABLE_PERF_PROFILING != 0 + if (frame->function) { + frame->function->total_exec_time += os_time_get_boot_microsecond() + - frame->time_started; + frame->function->total_exec_cnt++; + } +#endif wasm_exec_env_free_wasm_frame(exec_env, frame); } @@ -1086,9 +1097,6 @@ wasm_interp_dump_op_count() #else #define HANDLE_OP(opcode) HANDLE_##opcode #endif -#if WASM_ENABLE_FAST_INTERP == 0 -#define FETCH_OPCODE_AND_DISPATCH() goto *handle_table[*frame_ip++] -#else #if WASM_ENABLE_ABS_LABEL_ADDR != 0 #define FETCH_OPCODE_AND_DISPATCH() do { \ const void *p_label_addr = *(void**)frame_ip; \ @@ -1103,7 +1111,6 @@ wasm_interp_dump_op_count() goto *p_label_addr; \ } while (0) #endif -#endif #define HANDLE_OP_END() FETCH_OPCODE_AND_DISPATCH() #else /* else of WASM_ENABLE_LABELS_AS_VALUES */ @@ -1113,9 +1120,7 @@ wasm_interp_dump_op_count() #endif /* end of WASM_ENABLE_LABELS_AS_VALUES */ -#if WASM_ENABLE_FAST_INTERP != 0 static void **global_handle_table; -#endif static void wasm_interp_call_func_bytecode(WASMModuleInstance *module, @@ -1150,13 +1155,11 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, #define HANDLE_OPCODE(op) &&HANDLE_##op DEFINE_GOTO_TABLE (const void*, handle_table); #undef HANDLE_OPCODE -#if WASM_ENABLE_FAST_INTERP != 0 if (exec_env == NULL) { global_handle_table = (void **)handle_table; return; } #endif -#endif #if WASM_ENABLE_LABELS_AS_VALUES == 0 while (frame_ip < frame_ip_end) { @@ -3330,7 +3333,6 @@ recover_br_info: #endif } -#if WASM_ENABLE_FAST_INTERP != 0 void ** wasm_interp_get_handle_table() { @@ -3339,7 +3341,6 @@ wasm_interp_get_handle_table() wasm_interp_call_func_bytecode(&module, NULL, NULL, NULL); return global_handle_table; } -#endif void wasm_interp_call_wasm(WASMModuleInstance *module_inst, @@ -3412,7 +3413,7 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, argv[i] = *(frame->lp + i); } else { -#if WASM_ENABLE_CUSTOM_NAME_SECTION != 0 +#if WASM_ENABLE_DUMP_CALL_STACK != 0 wasm_interp_dump_call_stack(exec_env); #endif } diff --git a/core/iwasm/interpreter/wasm_mini_loader.c b/core/iwasm/interpreter/wasm_mini_loader.c index 2dc387686..f2c19bcd8 100644 --- a/core/iwasm/interpreter/wasm_mini_loader.c +++ b/core/iwasm/interpreter/wasm_mini_loader.c @@ -1448,7 +1448,6 @@ load_user_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, static bool wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, - BlockAddr *block_addr_cache, char *error_buf, uint32 error_buf_size); #if WASM_ENABLE_FAST_INTERP != 0 @@ -1472,9 +1471,7 @@ load_from_sections(WASMModule *module, WASMSection *sections, uint32 aux_stack_top = (uint32)-1, global_index, func_index, i; uint32 aux_data_end_global_index = (uint32)-1; uint32 aux_heap_base_global_index = (uint32)-1; - BlockAddr *block_addr_cache; WASMType *func_type; - uint64 total_size; /* Find code and function sections if have */ while (section) { @@ -1746,22 +1743,13 @@ load_from_sections(WASMModule *module, WASMSection *sections, handle_table = wasm_interp_get_handle_table(); #endif - total_size = sizeof(BlockAddr) * (uint64)BLOCK_ADDR_CACHE_SIZE * BLOCK_ADDR_CONFLICT_SIZE; - if (!(block_addr_cache = loader_malloc - (total_size, error_buf, error_buf_size))) { - return false; - } - for (i = 0; i < module->function_count; i++) { WASMFunction *func = module->functions[i]; - memset(block_addr_cache, 0, (uint32)total_size); - if (!wasm_loader_prepare_bytecode(module, func, block_addr_cache, + if (!wasm_loader_prepare_bytecode(module, func, error_buf, error_buf_size)) { - wasm_runtime_free(block_addr_cache); return false; } } - wasm_runtime_free(block_addr_cache); if (!module->possible_memory_grow) { WASMMemoryImport *memory_import; @@ -4251,7 +4239,6 @@ fail: static bool wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, - BlockAddr *block_addr_cache, char *error_buf, uint32 error_buf_size) { uint8 *p = func->code, *p_end = func->code + func->code_size, *p_org; diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index 6bf75c513..f444bdc14 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -1657,6 +1657,49 @@ wasm_get_exception(WASMModuleInstance *module_inst) return module_inst->cur_exception; } +#if WASM_ENABLE_PERF_PROFILING != 0 +void +wasm_dump_perf_profiling(const WASMModuleInstance *module_inst) +{ + WASMExportFuncInstance *export_func; + WASMFunctionInstance *func_inst; + char *func_name; + uint32 i, j; + + os_printf("Performance profiler data:\n"); + for (i = 0; i < module_inst->function_count; i++) { + func_inst = module_inst->functions + i; + if (func_inst->is_import_func) { + func_name = func_inst->u.func_import->field_name; + } +#if WASM_ENABLE_CUSTOM_NAME_SECTION != 0 + else if (func_inst->u.func->field_name) { + func_name = func_inst->u.func->field_name; + } +#endif + else { + func_name = NULL; + for (j = 0; j < module_inst->export_func_count; j++) { + export_func = module_inst->export_functions + j; + if (export_func->function == func_inst) { + func_name = export_func->name; + break; + } + } + } + + if (func_name) + os_printf(" func %s, execution time: %.3f ms, execution count: %d times\n", + func_name, module_inst->functions[i].total_exec_time / 1000.0f, + module_inst->functions[i].total_exec_cnt); + else + os_printf(" func %d, execution time: %.3f ms, execution count: %d times\n", + i, module_inst->functions[i].total_exec_time / 1000.0f, + module_inst->functions[i].total_exec_cnt); + } +} +#endif + uint32 wasm_module_malloc(WASMModuleInstance *module_inst, uint32 size, void **p_native_addr) @@ -2205,7 +2248,7 @@ wasm_get_module_inst_mem_consumption(const WASMModuleInstance *module_inst, #endif /* end of (WASM_ENABLE_MEMORY_PROFILING != 0) || (WASM_ENABLE_MEMORY_TRACING != 0) */ -#if WASM_ENABLE_CUSTOM_NAME_SECTION != 0 +#if WASM_ENABLE_DUMP_CALL_STACK != 0 void wasm_interp_dump_call_stack(struct WASMExecEnv *exec_env) { @@ -2214,18 +2257,33 @@ wasm_interp_dump_call_stack(struct WASMExecEnv *exec_env) WASMInterpFrame *cur_frame = wasm_exec_env_get_cur_frame(exec_env); WASMFunctionInstance *func_inst; + WASMExportFuncInstance *export_func; const char *func_name = NULL; - uint32 n; + uint32 n, i; os_printf("\n"); for (n = 0; cur_frame && cur_frame->function; n++) { + func_name = NULL; func_inst = cur_frame->function; if (func_inst->is_import_func) { func_name = func_inst->u.func_import->field_name; } else { +#if WASM_ENABLE_CUSTOM_NAME_SECTION != 0 func_name = func_inst->u.func->field_name; +#endif + /* if custom name section is not generated, + search symbols from export table */ + if (!func_name) { + for (i = 0; i < module_inst->export_func_count; i++) { + export_func = module_inst->export_functions + i; + if (export_func->function == func_inst) { + func_name = export_func->name; + break; + } + } + } } /* function name not exported, print number instead */ @@ -2240,4 +2298,4 @@ wasm_interp_dump_call_stack(struct WASMExecEnv *exec_env) } os_printf("\n"); } -#endif /* end of WASM_ENABLE_CUSTOM_NAME_SECTION */ +#endif /* end of WASM_ENABLE_DUMP_CALL_STACK */ diff --git a/core/iwasm/interpreter/wasm_runtime.h b/core/iwasm/interpreter/wasm_runtime.h index 4f13b689a..ccde47e49 100644 --- a/core/iwasm/interpreter/wasm_runtime.h +++ b/core/iwasm/interpreter/wasm_runtime.h @@ -120,6 +120,12 @@ struct WASMFunctionInstance { WASMModuleInstance *import_module_inst; WASMFunctionInstance *import_func_inst; #endif +#if WASM_ENABLE_PERF_PROFILING != 0 + /* total execution time */ + uint64 total_exec_time; + /* total execution count */ + uint32 total_exec_cnt; +#endif }; typedef struct WASMExportFuncInstance { @@ -281,12 +287,15 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, uint32 stack_size, uint32 heap_size, char *error_buf, uint32 error_buf_size); +void +wasm_dump_perf_profiling(const WASMModuleInstance *module_inst); + void wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst); WASMFunctionInstance * wasm_lookup_function(const WASMModuleInstance *module_inst, - const char *name, const char *signature); + const char *name, const char *signature); #if WASM_ENABLE_MULTI_MODULE != 0 WASMGlobalInstance * @@ -383,6 +392,12 @@ wasm_get_module_mem_consumption(const WASMModule *module, void wasm_get_module_inst_mem_consumption(const WASMModuleInstance *module, WASMModuleInstMemConsumption *mem_conspn); + +#if WASM_ENABLE_DUMP_CALL_STACK != 0 +void +wasm_interp_dump_call_stack(struct WASMExecEnv *exec_env); +#endif + #ifdef __cplusplus } #endif diff --git a/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c b/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c index c0dcb9da9..35359c50c 100644 --- a/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c +++ b/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c @@ -616,7 +616,7 @@ pthread_join_wrapper(wasm_exec_env_t exec_env, uint32 thread, /* validate addr before join thread, otherwise the module_inst may be freed */ - if (!validate_app_addr(retval_offset, sizeof(uint32))) { + if (!validate_app_addr(retval_offset, sizeof(void *))) { /* Join failed, but we don't want to terminate all threads, do not spread exception here */ wasm_runtime_set_exception(module_inst, NULL); diff --git a/doc/build_wamr.md b/doc/build_wamr.md index f26f1a2bc..add8412ec 100644 --- a/doc/build_wamr.md +++ b/doc/build_wamr.md @@ -48,8 +48,14 @@ cmake -DWAMR_BUILD_PLATFORM=linux -DWAMR_BUILD_TARGET=ARM - **WAMR_BUILD_CUSTOM_NAME_SECTION**=1/0, load the function name from custom name section, default to disable if not set +#### **Enable dump call stack feature** +- **WAMR_BUILD_DUMP_CALL_STACK**=1/0, default to disable if not set + > Note: if it is enabled, the call stack will be dumped when exception occurs. +> - For interpreter mode, the function names are firstly extracted from *custom name section*, if this section doesn't exist or the feature is not enabled, then the name will be extracted from the import/export sections +> - For AoT/JIT mode, the function names are extracted from import/export section, please export as many functions as possible (for `wasi-sdk` you can use `-Wl,--export-all`) when compiling wasm module, and add `--enable-dump-call-stack` option to wamrc during compiling AoT module. + #### **Enable Multi-Module feature** - **WAMR_BUILD_MULTI_MODULE**=1/0, default to disable if not set @@ -79,6 +85,12 @@ cmake -DWAMR_BUILD_PLATFORM=linux -DWAMR_BUILD_TARGET=ARM > Note: if it is enabled, developer can use API `void wasm_runtime_dump_mem_consumption(wasm_exec_env_t exec_env)` to dump the memory consumption info. Currently we only profile the memory consumption of module, module_instance and exec_env, the memory consumed by other components such as `wasi-ctx`, `multi-module` and `thread-manager` are not included. +#### **Enable performance profiling (Experiment)** +- **WAMR_BUILD_PERF_PROFILING**=1/0, default to disable if not set +> Note: if it is enabled, developer can use API `void wasm_runtime_dump_perf_profiling(wasm_module_inst_t module_inst)` to dump the performance consumption info. Currently we only profile the performance consumption of each WASM function. + +> The function name searching sequence is the same with dump call stack feature. + #### **Set maximum app thread stack size** - **WAMR_APP_THREAD_STACK_SIZE_MAX**=n, default to 8 MB (8388608) if not set > Note: the AOT boundary check with hardware trap mechanism might consume large stack since the OS may lazily grow the stack mapping as a guard page is hit, we may use this configuration to reduce the total stack usage, e.g. -DWAMR_APP_THREAD_STACK_SIZE_MAX=131072 (128 KB). diff --git a/doc/build_wasm_app.md b/doc/build_wasm_app.md index ba1927837..ca82531f0 100644 --- a/doc/build_wasm_app.md +++ b/doc/build_wasm_app.md @@ -2,12 +2,16 @@ # Prepare WASM building environments -WASI-SDK version 8.0+ is the major tool supported by WAMR to build WASM applications. There are some other WASM compilers such as the standard clang compiler and Emscripten might also work [here](./other_wasm_compilers.md). +For C and C++, WASI-SDK version 12.0+ is the major tool supported by WAMR to build WASM applications. Also we can use [Emscripten SDK (EMSDK)](https://github.com/emscripten-core/emsdk), but it is not recommended. And there are some other compilers such as the standard clang compiler, which might also work [here](./other_wasm_compilers.md). -Install WASI SDK: Download the [wasi-sdk](https://github.com/CraneStation/wasi-sdk/releases) and extract the archive to default path `/opt/wasi-sdk` +To install WASI SDK, please download the [wasi-sdk release](https://github.com/CraneStation/wasi-sdk/releases) and extract the archive to default path `/opt/wasi-sdk`. + +For [AssemblyScript](https://github.com/AssemblyScript/assemblyscript), please refer to [AssemblyScript quick start](https://www.assemblyscript.org/quick-start.html) and [AssemblyScript compiler](https://www.assemblyscript.org/compiler.html#command-line-options) for how to install `asc` compiler and build WASM applications. + +For Rust, please firstly ref to [Install Rust and Cargo](https://doc.rust-lang.org/cargo/getting-started/installation.html) to install cargo, rustc and rustup, by default they are installed under ~/.cargo/bin, and then run `rustup target add wasm32-wasi` to install wasm32-wasi target for Rust toolchain. To build WASM applications, we can run `cargo build --target wasm32-wasi`, the output files are under `target/wasm32-wasi`. -Build WASM applications +Build WASM applications with wasi-sdk ========================= You can write a simple ```test.c``` as the first sample. @@ -44,21 +48,23 @@ To build the source file to WASM bytecode, we can input the following command: /opt/wasi-sdk/bin/clang -O3 -o test.wasm test.c ``` -There are some useful options which can be specified to build the source code: +## 1. wasi-sdk options -- **-nostdlib** Do not use the standard system startup files or libraries when linking. In this mode, the libc-builtin library of WAMR must be built to run the wasm app, otherwise, the libc-wasi library must be built. You can specify **-DWAMR_BUILD_LIBC_BUILTIN** or **-DWAMR_BUILD_LIBC_WASI** for cmake to build WAMR with libc-builtin support or libc-wasi support. +There are some useful options which can be specified to build the source code (for more link options, please run `/opt/wasi-sdk/bin/wasm-ld --help`): + +- **-nostdlib** Do not use the standard system startup files or libraries when linking. In this mode, the **libc-builtin** library of WAMR must be built to run the wasm app, otherwise, the **libc-wasi** library must be built. You can specify **-DWAMR_BUILD_LIBC_BUILTIN=1** or **-DWAMR_BUILD_LIBC_WASI=1** for cmake to build WAMR with libc-builtin support or libc-wasi support. - **-Wl,--no-entry** Do not output any entry point -- **-Wl,--export=** Force a symbol to be exported, e.g. **-Wl,--export=main** to export main function +- **-Wl,--export=\** Force a symbol to be exported, e.g. **-Wl,--export=foo** to export foo function - **-Wl,--export-all** Export all symbols (normally combined with --no-gc-sections) -- **-Wl,--initial-memory=** Initial size of the linear memory, which must be a multiple of 65536 +- **-Wl,--initial-memory=\** Initial size of the linear memory, which must be a multiple of 65536 -- **-Wl,--max-memory=** Maximum size of the linear memory, which must be a multiple of 65536 +- **-Wl,--max-memory=\** Maximum size of the linear memory, which must be a multiple of 65536 -- **-z stack-size=** The auxiliary stack size, which is an area of linear memory, and must be smaller than initial memory size. +- **-z stack-size=\** The auxiliary stack size, which is an area of linear memory, and must be smaller than initial memory size. - **-Wl,--strip-all** Strip all symbols @@ -66,11 +72,12 @@ There are some useful options which can be specified to build the source code: - **-Wl,--allow-undefined** Allow undefined symbols in linked binary -- **-Wl,--allow-undefined-file=** Allow symbols listed in to be undefined in linked binary +- **-Wl,--allow-undefined-file=\** Allow symbols listed in \ to be undefined in linked binary - **-pthread** Support POSIX threads in generated code For example, we can build the wasm app with command: + ``` Bash /opt/wasi-sdk/bin/clang -O3 -nostdlib \ -z stack-size=8192 -Wl,--initial-memory=65536 \ @@ -79,7 +86,112 @@ For example, we can build the wasm app with command: -Wl,--export=__heap_base -Wl,--export=__data_end \ -Wl,--no-entry -Wl,--strip-all -Wl,--allow-undefined ``` -to generate a wasm binary with small footprint. +to generate a wasm binary with nostdlib mode, auxiliary stack size is 8192 bytes, initial memory size is 64 KB, main function, heap base global and data end global are exported, no entry function is generated (no _start function is exported), and all symbols are stripped. Note that it is nostdlib mode, so libc-builtin should be enabled by runtime embedder or iwasm (with cmake -DWAMR_BUILD_LIBC_BUILT=1, enabled by iwasm in Linux by default). + +If we want to build the wasm app with wasi mode, we may build the wasm app with command: + +```bash +/opt/wasi-sdk/bin/clang -O3 \ + -z stack-size=8192 -Wl,--initial-memory=65536 \ + -o test.wasm test.c \ + -Wl,--export=__heap_base -Wl,--export=__data_end \ + -Wl,--strip-all +``` + +to generate a wasm binary with wasi mode, auxiliary stack size is 8192 bytes, initial memory size is 64 KB, heap base global and data end global are exported, wasi entry function exported (_start function), and all symbols are stripped. Note that it is wasi mode, so libc-wasi should be enabled by runtime embedder or iwasm (with cmake -DWAMR_BUILD_LIBC_WASI=1, enabled by iwasm in Linux by default), and normally no need to export main function, by default _start function is executed by iwasm. + +## 2. How to reduce the footprint? + +Firstly if libc-builtin (-nostdlib) mode meets the requirements, e.g. there are no file io operations in wasm app, we should build the wasm app with -nostdlib option as possible as we can, since the compiler doesn't build the libc source code into wasm bytecodes, which greatly reduces the binary size. + +### (1) Methods to reduce the libc-builtin (-nostdlib) mode footprint + +- export \_\_heap_base global and \_\_data_end global + ```bash + -Wl,--export=__heap_base -Wl,--export=__data_end + ``` + If the two globals are exported, and there are no memory.grow and memory.size opcodes (normally nostdlib mode doesn't introduce these opcodes since the libc malloc function isn't built into wasm bytecode), WAMR runtime will truncate the linear memory at the place of \__heap_base and append app heap to the end, so we don't need to allocate the memory specified by `-Wl,--initial-memory=n` which must be at least 64 KB. This is helpful for some embedded devices whose memory resource might be limited. + +- reduce auxiliary stack size + + The auxiliary stack is an area of linear memory, normally the size is 64 KB by default which might be a little large for embedded devices and actually partly used, we can use `-z stack-size=n` to set its size. + +- use -O3 and -Wl,--strip-all + +- reduce app heap size when running iwasm + + We can pass `--heap-size=n` option to set the maximum app heap size for iwasm, by default it is 16 KB. For the runtime embedder, we can set the `uint32_t heap_size` argument when calling API ` wasm_runtime_instantiate`. + +- reduce wasm operand stack size when running iwasm + + WebAssembly is a binary instruction format for a stack-based virtual machine, which requires a stack to execute the bytecodes. We can pass `--stack-size=n` option to set the maximum stack size for iwasm, by default it is 16 KB. For the runtime embedder, we can set the `uint32_t stack_size` argument when calling API ` wasm_runtime_instantiate` and `wasm_runtime_create_exec_env`. + +- decrease block_addr_cache size for classic interpreter + + The block_addr_cache is an hash cache to store the else/end addresses for WebAssembly blocks (BLOCK/IF/LOOP) to speed up address lookup. This is only available in classic interpreter. We can set it by define macro `-DBLOCK_ADDR_CACHE_SIZE=n`, e.g. add `add_defintion (-DBLOCK_ADDR_CACHE_SIZE=n)` in CMakeLists.txt, by default it is 64, and total block_addr_cache size is 3072 bytes in 64-bit platform and 1536 bytes in 32-bit platform. + +### (2) Methods to reduce the libc-wasi (without -nostdlib) mode footprint + +Most of the above methods are also available for libc-wasi mode, besides them, we can export malloc and free functions with `-Wl,--export=malloc -Wl,--export=free` option, so WAMR runtime will disable its app heap and call the malloc/free function exported to allocate/free the memory from/to the heap space managed by libc. + +## 3. Build wasm app with pthread support + +Please ref to [pthread library](./pthread_library.md) for more details. + +## 4. Build wasm app with SIMD support + +Normally we should install emsdk and use its SSE header files, please ref to workload samples, e.g. [bwa CMakeLists.txt](../samples/workload/bwa/CMakeLists.txt) and [wasm-av1 CMakeLists.txt](../samples/workload/wasm-av1/CMakeLists.txt) for more details. + +# Build WASM applications with emsdk + +## 1. Install emsdk + +Assuming you are using Linux, you may install emcc and em++ from Emscripten EMSDK following the steps below: + +``` +git clone https://github.com/emscripten-core/emsdk.git +cd emsdk +./emsdk install latest +./emsdk activate latest +# And then source the emsdk_env.sh script before build wasm app +source emsdk_env.sh (or add it to ~/.bashrc if you don't want to run it each time) +``` + +The Emscripten website provides other installation methods beyond Linux. + +## 2. emsdk options + +To build the wasm C source code into wasm binary, we can use the following command: + +```bash +EMCC_ONLY_FORCED_STDLIBS=1 emcc -O3 -s STANDALONE_WASM=1 \ + -o test.wasm test.c \ + -s TOTAL_STACK=4096 -s TOTAL_MEMORY=65536 \ + -s "EXPORTED_FUNCTIONS=['_main']" \ + -s ERROR_ON_UNDEFINED_SYMBOLS=0 +``` + +There are some useful options: + +- **EMCC_ONLY_FORCED_STDLIBS=1** whether to link libc library into the output binary or not, similar to `-nostdlib` option of wasi-sdk clang. If specified, then no libc library is linked and the **libc-builtin** library of WAMR must be built to run the wasm app, otherwise, the **libc-wasi** library must be built. You can specify **-DWAMR_BUILD_LIBC_BUILTIN=1** or **-DWAMR_BUILD_LIBC_WASI=1** for cmake to build WAMR with libc-builtin support or libc-wasi support. + + The emsdk's wasi implementation is incomplete, e.g. open a file might just return fail, so it is strongly not recommended to use this mode, especially when there are file io operations in wasm app, please use wasi-sdk instead. + +- **-s STANDALONE_WASM=1** build wasm app in standalone mode (non-web mode), if the output file has suffix ".wasm", then only wasm file is generated (without html file and JavaScript file). + +- **-s TOTAL_STACK=\** the auxiliary stack size, same as `-z stack-size=\` of wasi-sdk + +- **-s TOTAL_MEMORY=\** or **-s INITIAL_MEORY=\** the initial linear memory size + +- **-s MAXIMUM_MEMORY=\** the maximum linear memory size, only take effect if **-s ALLOW_MEMORY_GROWTH=1** is set + +- **-s ALLOW_MEMORY_GROWTH=1/0** whether the linear memory is allowed to grow or not + +- **-s "EXPORTED_FUNCTIONS=['func name1', 'func name2']"** to export functions + +- **-s ERROR_ON_UNDEFINED_SYMBOLS=0** disable the errors when there are undefined symbols + +For more options, please ref to /upstream/emscripten/src/settings.js, or [Emscripten document](https://emscripten.org/docs/compiling/Building-Projects.html). # Build a project with cmake @@ -136,19 +248,29 @@ Usage: wamrc [options] -o output_file wasm_file Use +feature to enable a feature, or -feature to disable it For example, --cpu-features=+feature1,-feature2 Use --cpu-features=+help to list all the features supported - --opt-level=n Set the optimization level (0 to 3, default: 3, which is fastest) - --size-level=n Set the code size level (0 to 3, default: 3, which is smallest) + --opt-level=n Set the optimization level (0 to 3, default is 3) + --size-level=n Set the code size level (0 to 3, default is 3) -sgx Generate code for SGX platform (Intel Software Guard Extention) + --bounds-checks=1/0 Enable or disable the bounds checks for memory access: + by default it is disabled in all 64-bit platforms except SGX and + in these platforms runtime does bounds checks with hardware trap, + and by default it is enabled in all 32-bit platforms --format= Specifies the format of the output file The format supported: aot (default) AoT file object Native object file llvmir-unopt Unoptimized LLVM IR llvmir-opt Optimized LLVM IR + --enable-bulk-memory Enable the post-MVP bulk memory feature + --enable-multi-thread Enable multi-thread feature, the dependent features bulk-memory and + --enable-tail-call Enable the post-MVP tail call feature + thread-mgr will be enabled automatically + --enable-simd Enable the post-MVP 128-bit SIMD feature + --enable-dump-call-stack Enable stack trace feature + -v=n Set log verbose level (0 to 5, default is 2), larger with more log Examples: wamrc -o test.aot test.wasm wamrc --target=i386 -o test.aot test.wasm wamrc --target=i386 --format=object -o test.o test.wasm - ``` diff --git a/doc/other_wasm_compilers.md b/doc/other_wasm_compilers.md index ac1ac175f..5aa505ab3 100644 --- a/doc/other_wasm_compilers.md +++ b/doc/other_wasm_compilers.md @@ -1,5 +1,4 @@ - ## Use clang compiler The recommended method to build a WASM binary is to use clang compiler ```clang-8```. You can refer to [apt.llvm.org](https://apt.llvm.org) for the detailed instructions. Here are referenced steps to install clang-8 in Ubuntu 16.04 and Ubuntu 18.04. @@ -61,42 +60,6 @@ clang-8 --target=wasm32 -O3 \ You will get ```test.wasm``` which is the WASM app binary. - - - - -## Use Emscripten tool - -The last method to build a WASM binary is to use Emscripten tool ```emcc```. -Assuming you are using Linux, you may install emcc from Emscripten EMSDK following the steps below: - -``` -git clone https://github.com/emscripten-core/emsdk.git -cd emsdk -./emsdk install latest-fastcomp -./emsdk activate latest-fastcomp -``` - -The Emscripten website provides other installation methods beyond Linux. - -Use the emcc command below to build the WASM C source code into the WASM binary. - -``` Bash -cd emsdk -source emsdk_env.sh (or add it to ~/.bashrc if you don't want to run it each time) -cd -EMCC_ONLY_FORCED_STDLIBS=1 emcc -g -O3 -s WASM=1 -s ERROR_ON_UNDEFINED_SYMBOLS=0 \ - -s TOTAL_MEMORY=65536 -s TOTAL_STACK=4096 \ - -s ASSERTIONS=1 -s STACK_OVERFLOW_CHECK=2 \ - -s "EXPORTED_FUNCTIONS=['_main']" -o test.wasm test.c -``` - -You will get ```test.wasm``` which is the WASM app binary. - - - - - ## Using Docker Another method availble is using [Docker](https://www.docker.com/). We assume you've already configured Docker (see Platform section above) and have a running interactive shell. Currently the Dockerfile only supports compiling apps with clang, with Emscripten planned for the future. diff --git a/doc/pthread_library.md b/doc/pthread_library.md index cfc6bece4..927300c56 100644 --- a/doc/pthread_library.md +++ b/doc/pthread_library.md @@ -57,7 +57,7 @@ To build this C program into WebAssembly app with libc-builtin, you can use this You can also build this program with WASI, but we need to make some changes to wasi-sysroot: -1. disable malloc / free of wasi as they don't support shared memory +1. disable malloc/free of wasi if the wasi-sdk version is smaller than wasi-sdk-12.0 (not include 12.0), as they don't support shared memory: ``` bash /opt/wasi-sdk/bin/llvm-ar -d /opt/wasi-sdk/share/wasi-sysroot/lib/wasm32-wasi/libc.a dlmalloc.o ``` @@ -169,4 +169,4 @@ int pthread_key_delete(pthread_key_t key); ## Known limits - `pthread_attr_t`, `pthread_mutexattr_t` and `pthread_condattr_t` are not supported yet, so please pass `NULL` as the second argument of `pthread_create`, `pthread_mutex_init` and `pthread_cond_init`. - The `errno.o` in wasi-sysroot is not compatible with this feature, so using errno in multi-thread may cause unexpected behavior. -- Currently `struct timespec` is not supported, so the prototype of `pthread_cond_timedwait` is different from the native one, it takes an unsigned int argument `useconds` to indicate the waiting time. \ No newline at end of file +- Currently `struct timespec` is not supported, so the prototype of `pthread_cond_timedwait` is different from the native one, it takes an unsigned int argument `useconds` to indicate the waiting time. diff --git a/wamr-compiler/CMakeLists.txt b/wamr-compiler/CMakeLists.txt index de15a272a..03eaf344a 100644 --- a/wamr-compiler/CMakeLists.txt +++ b/wamr-compiler/CMakeLists.txt @@ -28,6 +28,9 @@ add_definitions(-DWASM_ENABLE_SHARED_MEMORY=1) add_definitions(-DWASM_ENABLE_THREAD_MGR=1) add_definitions(-DWASM_ENABLE_TAIL_CALL=1) add_definitions(-DWASM_ENABLE_SIMD=1) +add_definitions(-DWASM_ENABLE_CUSTOM_NAME_SECTION=1) +add_definitions(-DWASM_ENABLE_DUMP_CALL_STACK=1) +add_definitions(-DWASM_ENABLE_PERF_PROFILING=1) # Set WAMR_BUILD_TARGET, currently values supported: # "X86_64", "AMD_64", "X86_32", "ARM_32", "MIPS_32", "XTENSA_32" diff --git a/wamr-compiler/main.c b/wamr-compiler/main.c index 0fb5710c2..d04941166 100644 --- a/wamr-compiler/main.c +++ b/wamr-compiler/main.c @@ -41,9 +41,11 @@ print_help() printf(" llvmir-opt Optimized LLVM IR\n"); printf(" --enable-bulk-memory Enable the post-MVP bulk memory feature\n"); printf(" --enable-multi-thread Enable multi-thread feature, the dependent features bulk-memory and\n"); - printf(" --enable-tail-call Enable the post-MVP tail call feature\n"); printf(" thread-mgr will be enabled automatically\n"); + printf(" --enable-tail-call Enable the post-MVP tail call feature\n"); printf(" --enable-simd Enable the post-MVP 128-bit SIMD feature\n"); + printf(" --enable-dump-call-stack Enable stack trace feature\n"); + printf(" --enable-perf-profiling Enable function performance profiling\n"); printf(" -v=n Set log verbose level (0 to 5, default is 2), larger with more log\n"); printf("Examples: wamrc -o test.aot test.wasm\n"); printf(" wamrc --target=i386 -o test.aot test.wasm\n"); @@ -155,6 +157,12 @@ main(int argc, char *argv[]) else if (!strcmp(argv[0], "--enable-simd")) { option.enable_simd = true; } + else if (!strcmp(argv[0], "--enable-dump-call-stack")) { + option.enable_aux_stack_frame = true; + } + else if (!strcmp(argv[0], "--enable-perf-profiling")) { + option.enable_aux_stack_frame = true; + } else return print_help(); } From 6847e15f64a6d8c333ba92225425f7c6932a3d30 Mon Sep 17 00:00:00 2001 From: alvkeke Date: Mon, 18 Jan 2021 13:24:10 +0800 Subject: [PATCH 142/207] Fix failed in loading wasm byte-code if return NULL while size == 0 in os_malloc (#500) --- core/shared/platform/rt-thread/rtt_platform.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/core/shared/platform/rt-thread/rtt_platform.c b/core/shared/platform/rt-thread/rtt_platform.c index 508d89538..6ac8c70f6 100644 --- a/core/shared/platform/rt-thread/rtt_platform.c +++ b/core/shared/platform/rt-thread/rtt_platform.c @@ -28,10 +28,6 @@ void *os_malloc(unsigned size) void *buf_fixed; rt_ubase_t *addr_field; - if (size == 0) - { - return RT_NULL; - } buf_origin = rt_malloc(size + 8 + sizeof(rt_ubase_t)); buf_fixed = buf_origin + sizeof(void*); if ((rt_ubase_t)buf_fixed & 0x7) From ee217d5af1856d8ca5cf4912fa2059c6c8ef450b Mon Sep 17 00:00:00 2001 From: Huang Qi <757509347@qq.com> Date: Thu, 21 Jan 2021 16:07:07 +0800 Subject: [PATCH 143/207] Add some missing intrinsic symbols for thumb ISA (#503) Signed-off-by: Huang Qi Co-authored-by: Huang Qi --- core/iwasm/aot/arch/aot_reloc_thumb.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/core/iwasm/aot/arch/aot_reloc_thumb.c b/core/iwasm/aot/arch/aot_reloc_thumb.c index f4023ffb5..8b7bc748b 100644 --- a/core/iwasm/aot/arch/aot_reloc_thumb.c +++ b/core/iwasm/aot/arch/aot_reloc_thumb.c @@ -8,6 +8,19 @@ #define R_ARM_THM_CALL 10 /* PC relative (Thumb BL and ARMv5 Thumb BLX). */ #define R_ARM_THM_JMP24 30 /* B.W */ +void __ltdf2(); +void __adddf3(); +void __eqdf2(); +void __unorddf2(); +void __muldf3(); +void __subdf3(); +void __gedf2(); +void __ledf2(); +void __fixunsdfsi(); +void __floatunsidf(); +void __fixdfsi(); +void __nedf2(); +void __floatsidf(); void __divdi3(); void __udivdi3(); void __moddi3(); @@ -57,6 +70,19 @@ void __aeabi_f2d(); static SymbolMap target_sym_map[] = { REG_COMMON_SYMBOLS /* compiler-rt symbols that come from compiler(e.g. gcc) */ + REG_SYM(__ltdf2), + REG_SYM(__adddf3), + REG_SYM(__eqdf2), + REG_SYM(__unorddf2), + REG_SYM(__muldf3), + REG_SYM(__subdf3), + REG_SYM(__gedf2), + REG_SYM(__ledf2), + REG_SYM(__fixunsdfsi), + REG_SYM(__floatunsidf), + REG_SYM(__fixdfsi), + REG_SYM(__nedf2), + REG_SYM(__floatsidf), REG_SYM(__divdi3), REG_SYM(__udivdi3), REG_SYM(__umoddi3), From 4c9cb30ed9c48a9b2249c7bfbcc39c36c2321873 Mon Sep 17 00:00:00 2001 From: Huang Qi <757509347@qq.com> Date: Fri, 22 Jan 2021 10:01:44 +0800 Subject: [PATCH 144/207] Auto detect host platform for wamr-compiler (#504) Signed-off-by: Huang Qi Co-authored-by: Huang Qi --- wamr-compiler/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/wamr-compiler/CMakeLists.txt b/wamr-compiler/CMakeLists.txt index 03eaf344a..4d81b09cc 100644 --- a/wamr-compiler/CMakeLists.txt +++ b/wamr-compiler/CMakeLists.txt @@ -3,6 +3,8 @@ cmake_minimum_required (VERSION 2.8) +string (TOLOWER ${CMAKE_HOST_SYSTEM_NAME} WAMR_BUILD_PLATFORM) + if (NOT WAMR_BUILD_PLATFORM STREQUAL "windows") project (aot-compiler) else() From da8c879953827ed945d8d8a121b11ec8da8e6e5c Mon Sep 17 00:00:00 2001 From: Wang Ning Date: Mon, 25 Jan 2021 18:41:48 +0800 Subject: [PATCH 145/207] Implement riscv support for interpreter (#505) --- build-scripts/config_common.cmake | 18 +- build-scripts/runtime_lib.cmake | 14 +- core/config.h | 12 +- core/iwasm/aot/aot_reloc.h | 8 +- .../common/arch/invokeNative_riscv32_ilp32.s | 95 ++++++++ .../common/arch/invokeNative_riscv32_ilp32d.s | 104 +++++++++ .../common/arch/invokeNative_riscv64_lp64.s | 95 ++++++++ .../common/arch/invokeNative_riscv64_lp64d.s | 108 +++++++++ core/iwasm/common/iwasm_common.cmake | 8 + core/iwasm/common/wasm_runtime_common.c | 205 ++++++++++++++++-- core/iwasm/interpreter/wasm_runtime.c | 1 + core/shared/platform/zephyr/zephyr_platform.c | 2 +- doc/build_wamr.md | 5 +- product-mini/platforms/darwin/CMakeLists.txt | 6 +- product-mini/platforms/linux/CMakeLists.txt | 9 +- .../platforms/zephyr/simple/CMakeLists.txt | 4 + .../platforms/zephyr/simple/build_and_run.sh | 22 +- .../zephyr/simple/prj_qemu_riscv32.conf | 6 + .../zephyr/simple/prj_qemu_riscv64.conf | 6 + .../platforms/zephyr/simple/src/main.c | 20 +- .../zephyr/simple/src/test_wasm_riscv64.h | 41 ++++ .../simple/src/wasm-app-riscv64/build.sh | 27 +++ .../zephyr/simple/src/wasm-app-riscv64/main.c | 28 +++ 23 files changed, 805 insertions(+), 39 deletions(-) create mode 100644 core/iwasm/common/arch/invokeNative_riscv32_ilp32.s create mode 100644 core/iwasm/common/arch/invokeNative_riscv32_ilp32d.s create mode 100644 core/iwasm/common/arch/invokeNative_riscv64_lp64.s create mode 100644 core/iwasm/common/arch/invokeNative_riscv64_lp64d.s create mode 100644 product-mini/platforms/zephyr/simple/prj_qemu_riscv32.conf create mode 100644 product-mini/platforms/zephyr/simple/prj_qemu_riscv64.conf create mode 100644 product-mini/platforms/zephyr/simple/src/test_wasm_riscv64.h create mode 100755 product-mini/platforms/zephyr/simple/src/wasm-app-riscv64/build.sh create mode 100644 product-mini/platforms/zephyr/simple/src/wasm-app-riscv64/main.c diff --git a/build-scripts/config_common.cmake b/build-scripts/config_common.cmake index 2ee2a9644..5d7833b62 100644 --- a/build-scripts/config_common.cmake +++ b/build-scripts/config_common.cmake @@ -34,8 +34,16 @@ elseif (WAMR_BUILD_TARGET STREQUAL "MIPS") add_definitions(-DBUILD_TARGET_MIPS) elseif (WAMR_BUILD_TARGET STREQUAL "XTENSA") add_definitions(-DBUILD_TARGET_XTENSA) +elseif (WAMR_BUILD_TARGET STREQUAL "RISCV64" OR WAMR_BUILD_TARGET STREQUAL "RISCV64_LP64D") + add_definitions(-DBUILD_TARGET_RISCV64_LP64D) +elseif (WAMR_BUILD_TARGET STREQUAL "RISCV64_LP64") + add_definitions(-DBUILD_TARGET_RISCV64_LP64) +elseif (WAMR_BUILD_TARGET STREQUAL "RISCV32" OR WAMR_BUILD_TARGET STREQUAL "RISCV32_ILP32D") + add_definitions(-DBUILD_TARGET_RISCV32_ILP32D) +elseif (WAMR_BUILD_TARGET STREQUAL "RISCV32_ILP32") + add_definitions(-DBUILD_TARGET_RISCV32_ILP32) else () - message (FATAL_ERROR "-- WAMR build target isn't set") + message (FATAL_ERROR "-- WAMR build target isn't set") endif () if (CMAKE_BUILD_TYPE STREQUAL "Debug") @@ -43,7 +51,7 @@ if (CMAKE_BUILD_TYPE STREQUAL "Debug") endif () if (CMAKE_SIZEOF_VOID_P EQUAL 8) - if (WAMR_BUILD_TARGET STREQUAL "X86_64" OR WAMR_BUILD_TARGET STREQUAL "AMD_64" OR WAMR_BUILD_TARGET MATCHES "AARCH64.*") + if (WAMR_BUILD_TARGET STREQUAL "X86_64" OR WAMR_BUILD_TARGET STREQUAL "AMD_64" OR WAMR_BUILD_TARGET MATCHES "AARCH64.*" OR WAMR_BUILD_TARGET MATCHES "RISCV64.*") # Add -fPIC flag if build as 64-bit set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC") set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "${CMAKE_SHARED_LIBRARY_LINK_C_FLAGS} -fPIC") @@ -55,10 +63,10 @@ if (CMAKE_SIZEOF_VOID_P EQUAL 8) endif () if (WAMR_BUILD_TARGET MATCHES "ARM.*") - set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -marm") + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -marm") elseif (WAMR_BUILD_TARGET MATCHES "THUMB.*") - set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mthumb") - set (CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -Wa,-mthumb") + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mthumb") + set (CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -Wa,-mthumb") endif () if (NOT WAMR_BUILD_INTERP EQUAL 1) diff --git a/build-scripts/runtime_lib.cmake b/build-scripts/runtime_lib.cmake index aaddc0046..4cc495490 100644 --- a/build-scripts/runtime_lib.cmake +++ b/build-scripts/runtime_lib.cmake @@ -31,9 +31,14 @@ endif () # Set default options # Set WAMR_BUILD_TARGET, currently values supported: -# "X86_64", "AMD_64", "X86_32", "AARCH64[sub]", "ARM[sub]", "THUMB[sub]", "MIPS", "XTENSA" +# "X86_64", "AMD_64", "X86_32", "AARCH64[sub]", "ARM[sub]", "THUMB[sub]", +# "MIPS", "XTENSA", "RISCV64[sub]", "RISCV32[sub]" if (NOT DEFINED WAMR_BUILD_TARGET) - if (CMAKE_SIZEOF_VOID_P EQUAL 8) + if (CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") + set (WAMR_BUILD_TARGET "AARCH64") + elseif (CMAKE_SYSTEM_PROCESSOR STREQUAL "riscv64") + set (WAMR_BUILD_TARGET "RISCV64") + elseif (CMAKE_SIZEOF_VOID_P EQUAL 8) # Build as X86_64 by default in 64-bit platform set (WAMR_BUILD_TARGET "X86_64") else () @@ -47,6 +52,11 @@ if (WAMR_BUILD_INTERP EQUAL 1 OR WAMR_BUILD_JIT EQUAL 1) include (${IWASM_DIR}/interpreter/iwasm_interp.cmake) endif () +if (WAMR_BUILD_TARGET MATCHES "RISCV.*" AND WAMR_BUILD_AOT EQUAL 1) + set (WAMR_BUILD_AOT 0) + message ("-- WAMR AOT disabled as it isn't supported by riscv currently") +endif () + if (WAMR_BUILD_AOT EQUAL 1) include (${IWASM_DIR}/aot/iwasm_aot.cmake) if (WAMR_BUILD_JIT EQUAL 1) diff --git a/core/config.h b/core/config.h index e9f396de1..74ada1714 100644 --- a/core/config.h +++ b/core/config.h @@ -15,7 +15,11 @@ && !defined(BUILD_TARGET_THUMB) \ && !defined(BUILD_TARGET_THUMB_VFP) \ && !defined(BUILD_TARGET_MIPS) \ - && !defined(BUILD_TARGET_XTENSA) + && !defined(BUILD_TARGET_XTENSA) \ + && !defined(BUILD_TARGET_RISCV64_LP64D) \ + && !defined(BUILD_TARGET_RISCV64_LP64) \ + && !defined(BUILD_TARGET_RISCV32_ILP32D) \ + && !defined(BUILD_TARGET_RISCV32_ILP32) #if defined(__x86_64__) || defined(__x86_64) #define BUILD_TARGET_X86_64 #elif defined(__amd64__) || defined(__amd64) @@ -34,6 +38,10 @@ #define BUILD_TARGET_MIPS #elif defined(__XTENSA__) #define BUILD_TARGET_XTENSA +#elif defined(__riscv) && (__riscv_xlen == 64) +#define BUILD_TARGET_RISCV64_LP64D +#elif defined(__riscv) && (__riscv_xlen == 32) +#define BUILD_TARGET_RISCV32_ILP32D #else #error "Build target isn't set" #endif @@ -224,7 +232,7 @@ /* Default min/max heap size of each app */ #define APP_HEAP_SIZE_DEFAULT (8 * 1024) -#define APP_HEAP_SIZE_MIN (512) +#define APP_HEAP_SIZE_MIN (256) #define APP_HEAP_SIZE_MAX (512 * 1024 * 1024) /* Default wasm stack size of each app */ diff --git a/core/iwasm/aot/aot_reloc.h b/core/iwasm/aot/aot_reloc.h index cba15036b..ff7ce8c2e 100644 --- a/core/iwasm/aot/aot_reloc.h +++ b/core/iwasm/aot/aot_reloc.h @@ -44,8 +44,8 @@ typedef struct { REG_SYM(aot_call_indirect), \ REG_SYM(wasm_runtime_enlarge_memory), \ REG_SYM(wasm_runtime_set_exception), \ - REG_SYM(aot_memset), \ - REG_SYM(aot_memmove), \ + {"memset", (void*)aot_memset}, \ + {"memmove", (void*)aot_memmove}, \ REG_BULK_MEMORY_SYM() \ REG_ATOMIC_WAIT_SYM() \ REG_AOT_TRACE_SYM() @@ -56,8 +56,8 @@ typedef struct { REG_SYM(aot_call_indirect), \ REG_SYM(wasm_runtime_enlarge_memory), \ REG_SYM(wasm_runtime_set_exception), \ - REG_SYM(aot_memset), \ - REG_SYM(aot_memmove), \ + {"memset", (void*)aot_memset}, \ + {"memmove", (void*)aot_memmove}, \ REG_SYM(fmin), \ REG_SYM(fminf), \ REG_SYM(fmax), \ diff --git a/core/iwasm/common/arch/invokeNative_riscv32_ilp32.s b/core/iwasm/common/arch/invokeNative_riscv32_ilp32.s new file mode 100644 index 000000000..b0b41aa06 --- /dev/null +++ b/core/iwasm/common/arch/invokeNative_riscv32_ilp32.s @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + .text + .align 2 +#ifndef BH_PLATFORM_DARWIN + .globl invokeNative + .type invokeNative, function +invokeNative: +#else + .globl _invokeNative +_invokeNative: +#endif /* end of BH_PLATFORM_DARWIN */ + + +/* + * Arguments passed in: + * + * a0 function ptr + * a1 argv + * a2 nstacks + */ + +/* + * sp (stack pointer) + * |- sw to store 32-bit values from register to memory + * |- lw to load from stack to register + * fp/s0 (frame pointer) + * a0-a7 (8 integer arguments) + * |- sw to store + * |- lw to load + * t0-t6 (temporaries regisgers) + * |- caller saved + */ + + /* reserve space on stack to save return address and frame pointer */ + addi sp, sp, -8 + sw fp, 0(sp) /* save frame pointer */ + sw ra, 4(sp) /* save return address */ + + mv fp, sp /* set frame pointer to bottom of fixed frame */ + + /* save function ptr, argv & nstacks */ + mv t0, a0 /* t0 = function ptr */ + mv t1, a1 /* t1 = argv array address */ + mv t2, a2 /* t2 = nstack */ + + /* fill in a0-7 integer-registers */ + lw a0, 0(t1) /* a0 = argv[0] */ + lw a1, 4(t1) /* a1 = argv[1] */ + lw a2, 8(t1) /* a2 = argv[2] */ + lw a3, 12(t1) /* a3 = argv[3] */ + lw a4, 16(t1) /* a4 = argv[4] */ + lw a5, 20(t1) /* a5 = argv[5] */ + lw a6, 24(t1) /* a6 = argv[6] */ + lw a7, 28(t1) /* a7 = argv[7] */ + + addi t1, t1, 32 /* t1 points to stack args */ + + /* directly call the function if no args in stack, + x0 always holds 0 */ + beq t2, x0, call_func + + /* reserve enough stack space for function arguments */ + sll t3, t2, 2 /* shift left 2 bits. t3 = n_stacks * 4 */ + sub sp, sp, t3 + + /* make 16-byte aligned */ + and sp, sp, ~15 + + /* save sp in t4 register */ + mv t4, sp + + /* copy left arguments from caller stack to own frame stack */ +loop_stack_args: + beq t2, x0, call_func + lw t5, 0(t1) /* load stack argument, t5 = argv[i] */ + sw t5, 0(t4) /* store t5 to reseved stack, sp[j] = t5 */ + addi t1, t1, 4 /* move to next stack argument */ + addi t4, t4, 4 /* move to next stack pointer */ + addi t2, t2, -1 /* decrease t2 every loop, nstacks = nstacks -1 */ + j loop_stack_args + +call_func: + jalr t0 + + /* restore registers pushed in stack or saved in another register */ +return: + mv sp, fp /* restore sp saved in fp before function call */ + lw fp, 0(sp) /* load previous frame poniter to fp register */ + lw ra, 4(sp) /* load previous return address to ra register */ + addi sp, sp, 8 /* pop frame, restore sp */ + jr ra + diff --git a/core/iwasm/common/arch/invokeNative_riscv32_ilp32d.s b/core/iwasm/common/arch/invokeNative_riscv32_ilp32d.s new file mode 100644 index 000000000..49e8ec766 --- /dev/null +++ b/core/iwasm/common/arch/invokeNative_riscv32_ilp32d.s @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + .text + .align 2 +#ifndef BH_PLATFORM_DARWIN + .globl invokeNative + .type invokeNative, function +invokeNative: +#else + .globl _invokeNative +_invokeNative: +#endif /* end of BH_PLATFORM_DARWIN */ + + +/* + * Arguments passed in: + * + * a0 function ptr + * a1 argv + * a2 nstacks + */ + +/* + * sp (stack pointer) + * |- sw to store 32-bit values from register to memory + * |- lw to load from stack to register + * fp/s0 (frame pointer) + * a0-a7 (8 integer arguments) + * |- sw to store + * |- lw to load + * t0-t6 (temporaries regisgers) + * |- caller saved + */ + + /* reserve space on stack to save return address and frame pointer */ + addi sp, sp, -8 + sw fp, 0(sp) /* save frame pointer */ + sw ra, 4(sp) /* save return address */ + + mv fp, sp /* set frame pointer to bottom of fixed frame */ + + /* save function ptr, argv & nstacks */ + mv t0, a0 /* t0 = function ptr */ + mv t1, a1 /* t1 = argv array address */ + mv t2, a2 /* t2 = nstack */ + + /* fill in a0-7 integer-registers */ + lw a0, 0(t1) /* a0 = argv[0] */ + lw a1, 4(t1) /* a1 = argv[1] */ + lw a2, 8(t1) /* a2 = argv[2] */ + lw a3, 12(t1) /* a3 = argv[3] */ + lw a4, 16(t1) /* a4 = argv[4] */ + lw a5, 20(t1) /* a5 = argv[5] */ + lw a6, 24(t1) /* a6 = argv[6] */ + lw a7, 28(t1) /* a7 = argv[7] */ + + /* fill in fa0-7 float-registers*/ + fld fa0, 32(t1) /* fa0 = argv[8] */ + fld fa1, 40(t1) /* fa1 = argv[9] */ + fld fa2, 48(t1) /* fa2 = argv[10] */ + fld fa3, 56(t1) /* fa3 = argv[11] */ + fld fa4, 64(t1) /* fa4 = argv[12] */ + fld fa5, 72(t1) /* fa5 = argv[13] */ + fld fa6, 80(t1) /* fa6 = argv[14] */ + fld fa7, 88(t1) /* fa7 = argv[15] */ + + addi t1, t1, 96 /* t1 points to stack args */ + + /* directly call the function if no args in stack, + x0 always holds 0 */ + beq t2, x0, call_func + + /* reserve enough stack space for function arguments */ + sll t3, t2, 2 /* shift left 2 bits. t3 = n_stacks * 4 */ + sub sp, sp, t3 + + /* make 16-byte aligned */ + and sp, sp, ~15 + + /* save sp in t4 register */ + mv t4, sp + + /* copy left arguments from caller stack to own frame stack */ +loop_stack_args: + beq t2, x0, call_func + lw t5, 0(t1) /* load stack argument, t5 = argv[i] */ + sw t5, 0(t4) /* store t5 to reseved stack, sp[j] = t5 */ + addi t1, t1, 4 /* move to next stack argument */ + addi t4, t4, 4 /* move to next stack pointer */ + addi t2, t2, -1 /* decrease t2 every loop, nstacks = nstacks -1 */ + j loop_stack_args + +call_func: + jalr t0 + + /* restore registers pushed in stack or saved in another register */ +return: + mv sp, fp /* restore sp saved in fp before function call */ + lw fp, 0(sp) /* load previous frame poniter to fp register */ + lw ra, 4(sp) /* load previous return address to ra register */ + addi sp, sp, 8 /* pop frame, restore sp */ + jr ra diff --git a/core/iwasm/common/arch/invokeNative_riscv64_lp64.s b/core/iwasm/common/arch/invokeNative_riscv64_lp64.s new file mode 100644 index 000000000..86a3c9c82 --- /dev/null +++ b/core/iwasm/common/arch/invokeNative_riscv64_lp64.s @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + .text + .align 2 +#ifndef BH_PLATFORM_DARWIN + .globl invokeNative + .type invokeNative, function +invokeNative: +#else + .globl _invokeNative +_invokeNative: +#endif /* end of BH_PLATFORM_DARWIN */ + + +/* + * Arguments passed in: + * + * a0 function ptr + * a1 argv + * a2 nstacks + */ + +/* + * sp (stack pointer) + * |- sd to store 64-bit values from register to memory + * |- ld to load from stack to register + * fp/s0 (frame pointer) + * a0-a7 (8 integer arguments) + * |- sd to store + * |- ld to load + * t0-t6 (temporaries regisgers) + * |- caller saved + */ + + /* reserve space on stack to save return address and frame pointer */ + addi sp, sp, -16 + sd fp, 0(sp) /* save frame pointer */ + sd ra, 8(sp) /* save return address */ + + mv fp, sp /* set frame pointer to bottom of fixed frame */ + + /* save function ptr, argv & nstacks */ + mv t0, a0 /* t0 = function ptr */ + mv t1, a1 /* t1 = argv array address */ + mv t2, a2 /* t2 = nstack */ + + /* fill in a0-7 integer-registers*/ + ld a0, 0(t1) /* a0 = argv[0] */ + ld a1, 8(t1) /* a1 = argv[1] */ + ld a2, 16(t1) /* a2 = argv[2] */ + ld a3, 24(t1) /* a3 = argv[3] */ + ld a4, 32(t1) /* a4 = argv[4] */ + ld a5, 40(t1) /* a5 = argv[5] */ + ld a6, 48(t1) /* a6 = argv[6] */ + ld a7, 56(t1) /* a7 = argv[7] */ + + addi t1, t1, 64 /* t1 points to stack args */ + + /* directly call the function if no args in stack, + x0 always holds 0 */ + beq t2, x0, call_func + + /* reserve enough stack space for function arguments */ + sll t3, t2, 3 /* shift left 3 bits. t3 = n_stacks * 8 */ + sub sp, sp, t3 + + /* make 16-byte aligned */ + and sp, sp, ~(15LL) + + /* save sp in t4 register */ + mv t4, sp + + /* copy left arguments from caller stack to own frame stack */ +loop_stack_args: + beq t2, x0, call_func + ld t5, 0(t1) /* load stack argument, t5 = argv[i] */ + sd t5, 0(t4) /* store t5 to reseved stack, sp[j] = t5 */ + addi t1, t1, 8 /* move to next stack argument */ + addi t4, t4, 8 /* move to next stack pointer */ + addi t2, t2, -1 /* decrease t2 every loop, nstacks = nstacks -1 */ + j loop_stack_args + +call_func: + jalr t0 + + /* restore registers pushed in stack or saved in another register */ +return: + mv sp, fp /* restore sp saved in fp before function call */ + ld fp, 0(sp) /* load previous frame poniter to fp register */ + ld ra, 8(sp) /* load previous return address to ra register */ + addi sp, sp, 16 /* pop frame, restore sp */ + jr ra + diff --git a/core/iwasm/common/arch/invokeNative_riscv64_lp64d.s b/core/iwasm/common/arch/invokeNative_riscv64_lp64d.s new file mode 100644 index 000000000..a82df0264 --- /dev/null +++ b/core/iwasm/common/arch/invokeNative_riscv64_lp64d.s @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + .text + .align 2 +#ifndef BH_PLATFORM_DARWIN + .globl invokeNative + .type invokeNative, function +invokeNative: +#else + .globl _invokeNative +_invokeNative: +#endif /* end of BH_PLATFORM_DARWIN */ + +/* + * Arguments passed in: + * + * a0 function ptr + * a1 argv + * a2 nstacks + */ + +/* + * sp (stack pointer) + * |- sd to store 64-bit values from register to memory + * |- ld to load from stack to register + * fp/s0 (frame pointer) + * a0-a7 (8 integer arguments) + * |- sd to store + * |- ld to load + * fa0-a7 (8 float arguments) + * |- fsd to store + * |- fld to load + * t0-t6 (temporaries regisgers) + * |- caller saved + */ + + /* reserve space on stack to save return address and frame pointer */ + addi sp, sp, -16 + sd fp, 0(sp) /* save frame pointer */ + sd ra, 8(sp) /* save return address */ + + mv fp, sp /* set frame pointer to bottom of fixed frame */ + + /* save function ptr, argv & nstacks */ + mv t0, a0 /* t0 = function ptr */ + mv t1, a1 /* t1 = argv array address */ + mv t2, a2 /* t2 = nstack */ + + /* fill in fa0-7 float-registers*/ + fld fa0, 0(t1) /* fa0 = argv[0] */ + fld fa1, 8(t1) /* fa1 = argv[1] */ + fld fa2, 16(t1) /* fa2 = argv[2] */ + fld fa3, 24(t1) /* fa3 = argv[3] */ + fld fa4, 32(t1) /* fa4 = argv[4] */ + fld fa5, 40(t1) /* fa5 = argv[5] */ + fld fa6, 48(t1) /* fa6 = argv[6] */ + fld fa7, 56(t1) /* fa7 = argv[7] */ + + /* fill in a0-7 integer-registers*/ + ld a0, 64(t1) /* a0 = argv[8] */ + ld a1, 72(t1) /* a1 = argv[9] */ + ld a2, 80(t1) /* a2 = argv[10] */ + ld a3, 88(t1) /* a3 = argv[11] */ + ld a4, 96(t1) /* a4 = argv[12] */ + ld a5, 104(t1) /* a5 = argv[13] */ + ld a6, 112(t1) /* a6 = argv[14] */ + ld a7, 120(t1) /* a7 = argv[15] */ + + addi t1, t1, 128 /* t1 points to stack args */ + + /* directly call the function if no args in stack, + x0 always holds 0 */ + beq t2, x0, call_func + + /* reserve enough stack space for function arguments */ + sll t3, t2, 3 /* shift left 3 bits. t3 = n_stacks * 8 */ + sub sp, sp, t3 + + /* make 16-byte aligned */ + and sp, sp, ~(15LL) + + /* save sp in t4 register */ + mv t4, sp + + /* copy left arguments from caller stack to own frame stack */ +loop_stack_args: + beq t2, x0, call_func + ld t5, 0(t1) /* load stack argument, t5 = argv[i] */ + sd t5, 0(t4) /* store t5 to reseved stack, sp[j] = t5 */ + addi t1, t1, 8 /* move to next stack argument */ + addi t4, t4, 8 /* move to next stack pointer */ + addi t2, t2, -1 /* decrease t2 every loop, nstacks = nstacks -1 */ + j loop_stack_args + +call_func: + jalr t0 + + /* restore registers pushed in stack or saved in another register */ +return: + mv sp, fp /* restore sp saved in fp before function call */ + ld fp, 0(sp) /* load previous frame poniter to fp register */ + ld ra, 8(sp) /* load previous return address to ra register */ + addi sp, sp, 16 /* pop frame, restore sp */ + jr ra + + diff --git a/core/iwasm/common/iwasm_common.cmake b/core/iwasm/common/iwasm_common.cmake index ba0c0d0b4..a91da8d77 100644 --- a/core/iwasm/common/iwasm_common.cmake +++ b/core/iwasm/common/iwasm_common.cmake @@ -48,6 +48,14 @@ elseif (WAMR_BUILD_TARGET STREQUAL "MIPS") set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_mips.s) elseif (WAMR_BUILD_TARGET STREQUAL "XTENSA") set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_xtensa.s) +elseif (WAMR_BUILD_TARGET STREQUAL "RISCV64" OR WAMR_BUILD_TARGET STREQUAL "RISCV64_LP64D") + set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_riscv64_lp64d.s) +elseif (WAMR_BUILD_TARGET STREQUAL "RISCV64_LP64") + set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_riscv64_lp64.s) +elseif (WAMR_BUILD_TARGET STREQUAL "RISCV32" OR WAMR_BUILD_TARGET STREQUAL "RISCV32_ILP32D") + set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_riscv32_ilp32d.s) +elseif (WAMR_BUILD_TARGET STREQUAL "RISCV32_ILP32") + set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_riscv32_ilp32.s) elseif (WAMR_BUILD_TARGET STREQUAL "GENERAL") # Use invokeNative_general.c instead of assembly code, # but the maximum number of native arguments is limited to 20, diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index 125dd103d..65ab805c6 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -2704,7 +2704,10 @@ fail: } while (0) /* The invoke native implementation on ARM platform with VFP co-processor */ -#if defined(BUILD_TARGET_ARM_VFP) || defined(BUILD_TARGET_THUMB_VFP) +#if defined(BUILD_TARGET_ARM_VFP) \ + || defined(BUILD_TARGET_THUMB_VFP) \ + || defined(BUILD_TARGET_RISCV32_ILP32D) \ + || defined(BUILD_TARGET_RISCV32_ILP32) typedef void (*GenericFunctionPointer)(); int64 invokeNative(GenericFunctionPointer f, uint32 *args, uint32 n_stacks); @@ -2714,14 +2717,20 @@ typedef int64 (*Int64FuncPtr)(GenericFunctionPointer, uint32*,uint32); typedef int32 (*Int32FuncPtr)(GenericFunctionPointer, uint32*, uint32); typedef void (*VoidFuncPtr)(GenericFunctionPointer, uint32*, uint32); -static Float64FuncPtr invokeNative_Float64 = (Float64FuncPtr)invokeNative; -static Float32FuncPtr invokeNative_Float32 = (Float32FuncPtr)invokeNative; -static Int64FuncPtr invokeNative_Int64 = (Int64FuncPtr)invokeNative; -static Int32FuncPtr invokeNative_Int32 = (Int32FuncPtr)invokeNative; -static VoidFuncPtr invokeNative_Void = (VoidFuncPtr)invokeNative; +static Float64FuncPtr invokeNative_Float64 = (Float64FuncPtr)(uintptr_t)invokeNative; +static Float32FuncPtr invokeNative_Float32 = (Float32FuncPtr)(uintptr_t)invokeNative; +static Int64FuncPtr invokeNative_Int64 = (Int64FuncPtr)(uintptr_t)invokeNative; +static Int32FuncPtr invokeNative_Int32 = (Int32FuncPtr)(uintptr_t)invokeNative; +static VoidFuncPtr invokeNative_Void = (VoidFuncPtr)(uintptr_t)invokeNative; +#if !defined(BUILD_TARGET_RISCV32_ILP32D) \ + && !defined(BUILD_TARGET_RISCV32_ILP32) #define MAX_REG_INTS 4 #define MAX_REG_FLOATS 16 +#else +#define MAX_REG_INTS 8 +#define MAX_REG_FLOATS 8 +#endif bool wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, @@ -2731,12 +2740,19 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, { WASMModuleInstanceCommon *module = wasm_runtime_get_module_inst(exec_env); /* argv buf layout: int args(fix cnt) + float args(fix cnt) + stack args */ - uint32 argv_buf[32], *argv1 = argv_buf, *fps, *ints, *stacks, size; - uint32 *argv_src = argv, i, argc1, n_ints = 0, n_fps = 0, n_stacks = 0; + uint32 argv_buf[32], *argv1 = argv_buf, *ints, *stacks, size; + uint32 *argv_src = argv, i, argc1, n_ints = 0, n_stacks = 0; uint32 arg_i32, ptr_len; uint32 result_count = func_type->result_count; uint32 ext_ret_count = result_count > 1 ? result_count - 1 : 0; bool ret = false; +#if !defined(BUILD_TARGET_RISCV32_ILP32) + uint32 *fps; + int n_fps = 0; +#else +#define fps ints +#define n_fps n_ints +#endif n_ints++; /* exec env */ @@ -2751,18 +2767,29 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, break; case VALUE_TYPE_I64: if (n_ints < MAX_REG_INTS - 1) { +#if !defined(BUILD_TARGET_RISCV32_ILP32) && !defined(BUILD_TARGET_RISCV32_ILP32D) /* 64-bit data must be 8 bytes aligned in arm */ if (n_ints & 1) n_ints++; +#endif n_ints += 2; } +#if defined(BUILD_TARGET_RISCV32_ILP32) || defined(BUILD_TARGET_RISCV32_ILP32D) + /* part in register, part in stack */ + else if (n_ints == MAX_REG_INTS - 1) { + n_ints++; + n_stacks++; + } +#endif else { - /* 64-bit data must be 8 bytes aligned in arm */ + /* 64-bit data in stack must be 8 bytes aligned + in arm and riscv32 */ if (n_stacks & 1) n_stacks++; n_stacks += 2; } break; +#if !defined(BUILD_TARGET_RISCV32_ILP32D) case VALUE_TYPE_F32: if (n_fps < MAX_REG_FLOATS) n_fps++; @@ -2771,11 +2798,19 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, break; case VALUE_TYPE_F64: if (n_fps < MAX_REG_FLOATS - 1) { +#if !defined(BUILD_TARGET_RISCV32_ILP32) /* 64-bit data must be 8 bytes aligned in arm */ if (n_fps & 1) n_fps++; +#endif n_fps += 2; } +#if defined(BUILD_TARGET_RISCV32_ILP32) + else if (n_fps == MAX_REG_FLOATS - 1) { + n_fps++; + n_stacks++; + } +#endif else { /* 64-bit data must be 8 bytes aligned in arm */ if (n_stacks & 1) @@ -2783,6 +2818,31 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, n_stacks += 2; } break; +#else /* BUILD_TARGET_RISCV32_ILP32D */ + case VALUE_TYPE_F32: + case VALUE_TYPE_F64: + if (n_fps < MAX_REG_FLOATS) { + n_fps++; + } + else if (func_type->types[i] == VALUE_TYPE_F32 + && n_ints < MAX_REG_INTS) { + /* use int reg firstly if available */ + n_ints++; + } + else if (func_type->types[i] == VALUE_TYPE_F64 + && n_ints < MAX_REG_INTS - 1) { + /* use int regs firstly if available */ + if (n_ints & 1) + n_ints++; + ints += 2; + } + else { + /* 64-bit data in stack must be 8 bytes aligned in riscv32 */ + if (n_stacks & 1) + n_stacks++; + n_stacks += 2; + } +#endif /* BUILD_TARGET_RISCV32_ILP32D */ default: bh_assert(0); break; @@ -2796,7 +2856,14 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, n_stacks++; } +#if !defined(BUILD_TARGET_RISCV32_ILP32) && !defined(BUILD_TARGET_RISCV32_ILP32D) argc1 = MAX_REG_INTS + MAX_REG_FLOATS + n_stacks; +#elif defined(BUILD_TARGET_RISCV32_ILP32) + argc1 = MAX_REG_INTS + n_stacks; +#else + argc1 = MAX_REG_INTS + MAX_REG_FLOATS * 2 + n_stacks; +#endif + if (argc1 > sizeof(argv_buf) / sizeof(uint32)) { size = sizeof(uint32) * (uint32)argc1; if (!(argv1 = runtime_malloc((uint32)size, exec_env->module_inst, @@ -2806,8 +2873,15 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, } ints = argv1; +#if !defined(BUILD_TARGET_RISCV32_ILP32) && !defined(BUILD_TARGET_RISCV32_ILP32D) fps = ints + MAX_REG_INTS; stacks = fps + MAX_REG_FLOATS; +#elif defined(BUILD_TARGET_RISCV32_ILP32) + stacks = ints + MAX_REG_INTS; +#else + fps = ints + MAX_REG_INTS; + stacks = fps + MAX_REG_FLOATS * 2; +#endif n_ints = 0; n_fps = 0; @@ -2854,45 +2928,121 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, break; } case VALUE_TYPE_I64: + { if (n_ints < MAX_REG_INTS - 1) { +#if !defined(BUILD_TARGET_RISCV32_ILP32) && !defined(BUILD_TARGET_RISCV32_ILP32D) /* 64-bit data must be 8 bytes aligned in arm */ if (n_ints & 1) n_ints++; +#endif *(uint64*)&ints[n_ints] = *(uint64*)argv_src; n_ints += 2; + argv_src += 2; } +#if defined(BUILD_TARGET_RISCV32_ILP32) || defined(BUILD_TARGET_RISCV32_ILP32D) + else if (n_ints == MAX_REG_INTS - 1) { + ints[n_ints++] = *argv_src++; + stacks[n_stacks++] = *argv_src++; + } +#endif else { - /* 64-bit data must be 8 bytes aligned in arm */ + /* 64-bit data in stack must be 8 bytes aligned + in arm and riscv32 */ if (n_stacks & 1) n_stacks++; *(uint64*)&stacks[n_stacks] = *(uint64*)argv_src; n_stacks += 2; + argv_src += 2; } - argv_src += 2; break; + } +#if !defined(BUILD_TARGET_RISCV32_ILP32D) case VALUE_TYPE_F32: + { if (n_fps < MAX_REG_FLOATS) *(float32*)&fps[n_fps++] = *(float32*)argv_src++; else *(float32*)&stacks[n_stacks++] = *(float32*)argv_src++; break; + } case VALUE_TYPE_F64: + { if (n_fps < MAX_REG_FLOATS - 1) { +#if !defined(BUILD_TARGET_RISCV32_ILP32) /* 64-bit data must be 8 bytes aligned in arm */ if (n_fps & 1) n_fps++; +#endif *(float64*)&fps[n_fps] = *(float64*)argv_src; n_fps += 2; + argv_src += 2; } +#if defined(BUILD_TARGET_RISCV32_ILP32) + else if (n_fps == MAX_REG_FLOATS - 1) { + fps[n_fps++] = *argv_src++; + stacks[n_stacks++] = *argv_src++; + } +#endif else { /* 64-bit data must be 8 bytes aligned in arm */ if (n_stacks & 1) n_stacks++; *(float64*)&stacks[n_stacks] = *(float64*)argv_src; n_stacks += 2; + argv_src += 2; } - argv_src += 2; break; + } +#else /* BUILD_TARGET_RISCV32_ILP32D */ + case VALUE_TYPE_F32: + case VALUE_TYPE_F64: + { + if (n_fps < MAX_REG_FLOATS) { + if (func_type->types[i] == VALUE_TYPE_F32) { + *(float32*)&fps[n_fps * 2] = *(float32*)argv_src++; + /* NaN boxing, the upper bits of a valid NaN-boxed + value must be all 1s. */ + fps[n_fps * 2 + 1] = 0xFFFFFFFF; + } + else { + *(float64*)&fps[n_fps * 2] = *(float64*)argv_src; + argv_src += 2; + } + n_fps++; + } + else if (func_type->types[i] == VALUE_TYPE_F32 + && n_ints < MAX_REG_INTS) { + /* use int reg firstly if available */ + *(float32*)&ints[n_ints++] = *(float32*)argv_src++; + } + else if (func_type->types[i] == VALUE_TYPE_F64 + && n_ints < MAX_REG_INTS - 1) { + /* use int regs firstly if available */ + if (n_ints & 1) + n_ints++; + *(float64*)&ints[n_ints] = *(float64*)argv_src; + n_ints += 2; + argv_src += 2; + } + else { + /* 64-bit data in stack must be 8 bytes aligned in riscv32 */ + if (n_stacks & 1) + n_stacks++; + if (func_type->types[i] == VALUE_TYPE_F32) { + *(float32*)&stacks[n_stacks] = *(float32*)argv_src++; + /* NaN boxing, the upper bits of a valid NaN-boxed + value must be all 1s. */ + stacks[n_stacks + 1] = 0xFFFFFFFF; + } + else { + *(float64*)&stacks[n_stacks] = *(float64*)argv_src; + argv_src += 2; + } + n_stacks += 2; + } + break; + } +#endif /* BUILD_TARGET_RISCV32_ILP32D */ default: bh_assert(0); break; @@ -2939,7 +3089,10 @@ fail: wasm_runtime_free(argv1); return ret; } -#endif /* end of defined(BUILD_TARGET_ARM_VFP) || defined(BUILD_TARGET_THUMB_VFP) */ +#endif /* end of defined(BUILD_TARGET_ARM_VFP) + || defined(BUILD_TARGET_THUMB_VFP) \ + || defined(BUILD_TARGET_RISCV32_ILP32D) + || defined(BUILD_TARGET_RISCV32_ILP32) */ #if defined(BUILD_TARGET_X86_32) \ || defined(BUILD_TARGET_ARM) \ @@ -3101,7 +3254,9 @@ fail: #if defined(BUILD_TARGET_X86_64) \ || defined(BUILD_TARGET_AMD_64) \ - || defined(BUILD_TARGET_AARCH64) + || defined(BUILD_TARGET_AARCH64) \ + || defined(BUILD_TARGET_RISCV64_LP64D) \ + || defined(BUILD_TARGET_RISCV64_LP64) #if WASM_ENABLE_SIMD != 0 #ifdef v128 @@ -3138,11 +3293,15 @@ static V128FuncPtr invokeNative_V128 = (V128FuncPtr)(uintptr_t)invokeNative; #define MAX_REG_INTS 4 #else /* else of defined(_WIN32) || defined(_WIN32_) */ #define MAX_REG_FLOATS 8 -#if defined(BUILD_TARGET_AARCH64) +#if defined(BUILD_TARGET_AARCH64) \ + || defined(BUILD_TARGET_RISCV64_LP64D) \ + || defined(BUILD_TARGET_RISCV64_LP64) #define MAX_REG_INTS 8 #else #define MAX_REG_INTS 6 -#endif /* end of defined(BUILD_TARGET_AARCH64 */ +#endif /* end of defined(BUILD_TARGET_AARCH64) \ + || defined(BUILD_TARGET_RISCV64_LP64D) \ + || defined(BUILD_TARGET_RISCV64_LP64) */ #endif /* end of defined(_WIN32) || defined(_WIN32_) */ bool @@ -3158,13 +3317,17 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, uint32 result_count = func_type->result_count; uint32 ext_ret_count = result_count > 1 ? result_count - 1 : 0; bool ret = false; +#ifndef BUILD_TARGET_RISCV64_LP64 #if WASM_ENABLE_SIMD == 0 uint64 *fps; #else v128 *fps; #endif +#else /* else of BUILD_TARGET_RISCV64_LP64 */ +#define fps ints +#endif /* end of BUILD_TARGET_RISCV64_LP64 */ -#if defined(_WIN32) || defined(_WIN32_) +#if defined(_WIN32) || defined(_WIN32_) || defined(BUILD_TARGET_RISCV64_LP64) /* important difference in calling conventions */ #define n_fps n_ints #else @@ -3186,6 +3349,7 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, } } +#ifndef BUILD_TARGET_RISCV64_LP64 #if WASM_ENABLE_SIMD == 0 fps = argv1; ints = fps + MAX_REG_FLOATS; @@ -3193,6 +3357,9 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, fps = (v128 *)argv1; ints = (uint64 *)(fps + MAX_REG_FLOATS); #endif +#else /* else of BUILD_TARGET_RISCV64_LP64 */ + ints = argv1; +#endif /* end of BUILD_TARGET_RISCV64_LP64 */ stacks = ints + MAX_REG_INTS; ints[n_ints++] = (uint64)(uintptr_t)exec_env; @@ -3326,7 +3493,9 @@ fail: #endif /* end of defined(BUILD_TARGET_X86_64) \ || defined(BUILD_TARGET_AMD_64) \ - || defined(BUILD_TARGET_AARCH64) */ + || defined(BUILD_TARGET_AARCH64) \ + || defined(BUILD_TARGET_RISCV64_LP64D) \ + || defined(BUILD_TARGET_RISCV64_LP64) */ bool wasm_runtime_call_indirect(WASMExecEnv *exec_env, diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index f444bdc14..6a371e5e5 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -294,6 +294,7 @@ memory_instantiate(WASMModuleInstance *module_inst, } } #endif + LOG_VERBOSE("Memory instantiate success."); return memory; #if WASM_ENABLE_SHARED_MEMORY != 0 fail5: diff --git a/core/shared/platform/zephyr/zephyr_platform.c b/core/shared/platform/zephyr/zephyr_platform.c index 2bb08fc47..1666a56d0 100644 --- a/core/shared/platform/zephyr/zephyr_platform.c +++ b/core/shared/platform/zephyr/zephyr_platform.c @@ -108,7 +108,7 @@ os_vprintf(const char *fmt, va_list ap) { #if 0 struct out_context ctx = { 0 }; - z_vprintk(char_out, &ctx, fmt, ap); + cbvprintf(char_out, &ctx, fmt, ap); return ctx.count; #else vprintk(fmt, ap); diff --git a/doc/build_wamr.md b/doc/build_wamr.md index add8412ec..4c09ff913 100644 --- a/doc/build_wamr.md +++ b/doc/build_wamr.md @@ -19,7 +19,10 @@ The script `runtime_lib.cmake` defines a number of variables for configuring the - **WAMR_BUILD_PLATFORM**: set the target platform. It can be set to any platform name (folder name) under folder [core/shared/platform](../core/shared/platform). -- **WAMR_BUILD_TARGET**: set the target CPU architecture. Current supported targets are: X86_64, X86_32, AArch64, ARM, THUMB, XTENSA and MIPS. For AArch64, ARM and THUMB, the format is \\[\]\[_VFP] where \ is the ARM sub-architecture and the "_VFP" suffix means VFP coprocessor registers s0-s15 (d0-d7) are used for passing arguments or returning results in standard procedure-call. Both \ and "_VFP" are optional, e.g. AARCH64, AARCH64V8, AARCHV8.1, ARMV7, ARMV7_VFP, THUMBV7, THUMBV7_VFP and so on. +- **WAMR_BUILD_TARGET**: set the target CPU architecture. Current supported targets are: X86_64, X86_32, AARCH64, ARM, THUMB, XTENSA, RISCV64 and MIPS. + - For AARCH64, ARM and THUMB, the format is \\[\]\[_VFP], where \ is the ARM sub-architecture and the "_VFP" suffix means using VFP coprocessor registers s0-s15 (d0-d7) for passing arguments or returning results in standard procedure-call. Both \ and "_VFP" are optional, e.g. AARCH64, AARCH64V8, AARCHV8.1, ARMV7, ARMV7_VFP, THUMBV7, THUMBV7_VFP and so on. + - For RISCV64, the format is \[_abi], where "_abi" is optional, currently the supported formats are RISCV64, RISCV64_LP64D and RISCV64_LP64: RISCV64 and RISCV64_LP64D are identical, using [LP64D](https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-elf.md#-named-abis) as abi (LP64 with hardware floating-point calling convention for FLEN=64). And RISCV64_LP64 uses [LP64](https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-elf.md#-named-abis) as abi (Integer calling-convention only, and hardware floating-point calling convention is not used). + - For RISCV32, the format is \[_abi], where "_abi" is optional, currently the supported formats are RISCV32, RISCV32_ILP32D and RISCV32_ILP32: RISCV32 and RISCV32_ILP32D are identical, using [ILP32D](https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-elf.md#-named-abis) as abi (ILP32 with hardware floating-point calling convention for FLEN=64). And RISCV32_ILP32 uses [ILP32](https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-elf.md#-named-abis) as abi (Integer calling-convention only, and hardware floating-point calling convention is not used). ```bash cmake -DWAMR_BUILD_PLATFORM=linux -DWAMR_BUILD_TARGET=ARM diff --git a/product-mini/platforms/darwin/CMakeLists.txt b/product-mini/platforms/darwin/CMakeLists.txt index 15367caf1..45c6038a6 100644 --- a/product-mini/platforms/darwin/CMakeLists.txt +++ b/product-mini/platforms/darwin/CMakeLists.txt @@ -12,11 +12,13 @@ set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") set (CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") # Set WAMR_BUILD_TARGET, currently values supported: -# "X86_64", "AMD_64", "X86_32", "ARM[sub]", "THUMB[sub]", "MIPS", "XTENSA" +# "X86_64", "AMD_64", "X86_32", "AARCH64[sub]", "ARM[sub]", "THUMB[sub]", +# "MIPS", "XTENSA", "RISCV64[sub]", "RISCV32[sub]" if (NOT DEFINED WAMR_BUILD_TARGET) if (CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") - # Handle Apple Silicon set (WAMR_BUILD_TARGET "AARCH64") + elseif (CMAKE_SYSTEM_PROCESSOR STREQUAL "riscv64") + set (WAMR_BUILD_TARGET "RISCV64") elseif (CMAKE_SIZEOF_VOID_P EQUAL 8) # Build as X86_64 by default in 64-bit platform set (WAMR_BUILD_TARGET "X86_64") diff --git a/product-mini/platforms/linux/CMakeLists.txt b/product-mini/platforms/linux/CMakeLists.txt index 63b49c049..6e14530ed 100644 --- a/product-mini/platforms/linux/CMakeLists.txt +++ b/product-mini/platforms/linux/CMakeLists.txt @@ -15,9 +15,14 @@ set (CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") set (CMAKE_C_STANDARD 99) # Set WAMR_BUILD_TARGET, currently values supported: -# "X86_64", "AMD_64", "X86_32", "AARCH64[sub]", "ARM[sub]", "THUMB[sub]", "MIPS", "XTENSA" +# "X86_64", "AMD_64", "X86_32", "AARCH64[sub]", "ARM[sub]", "THUMB[sub]", +# "MIPS", "XTENSA", "RISCV64[sub]", "RISCV32[sub]" if (NOT DEFINED WAMR_BUILD_TARGET) - if (CMAKE_SIZEOF_VOID_P EQUAL 8) + if (CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") + set (WAMR_BUILD_TARGET "AARCH64") + elseif (CMAKE_SYSTEM_PROCESSOR STREQUAL "riscv64") + set (WAMR_BUILD_TARGET "RISCV64") + elseif (CMAKE_SIZEOF_VOID_P EQUAL 8) # Build as X86_64 by default in 64-bit platform set (WAMR_BUILD_TARGET "X86_64") else () diff --git a/product-mini/platforms/zephyr/simple/CMakeLists.txt b/product-mini/platforms/zephyr/simple/CMakeLists.txt index affa755ab..ed9b66e1e 100644 --- a/product-mini/platforms/zephyr/simple/CMakeLists.txt +++ b/product-mini/platforms/zephyr/simple/CMakeLists.txt @@ -36,6 +36,10 @@ if (NOT DEFINED WAMR_BUILD_LIBC_WASI) set (WAMR_BUILD_LIBC_WASI 0) endif () +if (WAMR_BUILD_TARGET STREQUAL "RISCV64_LP64" OR WAMR_BUILD_TARGET STREQUAL "RISCV32_ILP32") + set (WAMR_BUILD_FAST_INTERP 1) +endif () + set (WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/wamr) include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) diff --git a/product-mini/platforms/zephyr/simple/build_and_run.sh b/product-mini/platforms/zephyr/simple/build_and_run.sh index e222366f2..2c7befde9 100755 --- a/product-mini/platforms/zephyr/simple/build_and_run.sh +++ b/product-mini/platforms/zephyr/simple/build_and_run.sh @@ -8,17 +8,21 @@ STM32_TARGET="stm32" QEMU_CORTEX_A53="qemu_cortex_a53" XTENSA_QEMU_TARGET="xtensa-qemu" ESP32_TARGET="esp32" +QEMU_RISCV64_TARGET="qemu_riscv64" +QEMU_RISCV32_TARGET="qemu_riscv32" usage () { echo "USAGE:" - echo "$0 $X86_TARGET|$STM32_TARGET|$QEMU_CORTEX_A53|$XTENSA_QEMU_TARGET|$ESP32_TARGET" + echo "$0 $X86_TARGET|$STM32_TARGET|$QEMU_CORTEX_A53|$XTENSA_QEMU_TARGET|$ESP32_TARGET|$QEMU_RISCV64_TARGET|$QEMU_RISCV32_TARGET" echo "Example:" echo " $0 $X86_TARGET" echo " $0 $STM32_TARGET" echo " $0 $QEMU_CORTEX_A53" echo " $0 $XTENSA_QEMU_TARGET" echo " $0 $ESP32_TARGET" + echo " $0 $QEMU_RISCV64_TARGET" + echo " $0 $QEMU_RISCV32_TARGET" exit 1 } @@ -68,6 +72,22 @@ case $TARGET in -DWAMR_BUILD_TARGET=AARCH64 west build -t run ;; + $QEMU_RISCV64_TARGET) + west build -b qemu_riscv64 \ + . -p always -- \ + -DCONF_FILE=prj_qemu_riscv64.conf \ + -DWAMR_BUILD_TARGET=RISCV64_LP64 \ + -DWAMR_BUILD_AOT=0 + west build -t run + ;; + $QEMU_RISCV32_TARGET) + west build -b qemu_riscv32 \ + . -p always -- \ + -DCONF_FILE=prj_qemu_riscv32.conf \ + -DWAMR_BUILD_TARGET=RISCV32_ILP32 \ + -DWAMR_BUILD_AOT=0 + west build -t run + ;; *) echo "unsupported target: $TARGET" usage diff --git a/product-mini/platforms/zephyr/simple/prj_qemu_riscv32.conf b/product-mini/platforms/zephyr/simple/prj_qemu_riscv32.conf new file mode 100644 index 000000000..f3705504b --- /dev/null +++ b/product-mini/platforms/zephyr/simple/prj_qemu_riscv32.conf @@ -0,0 +1,6 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +CONFIG_STACK_SENTINEL=y +CONFIG_PRINTK=y +CONFIG_LOG=n diff --git a/product-mini/platforms/zephyr/simple/prj_qemu_riscv64.conf b/product-mini/platforms/zephyr/simple/prj_qemu_riscv64.conf new file mode 100644 index 000000000..f3705504b --- /dev/null +++ b/product-mini/platforms/zephyr/simple/prj_qemu_riscv64.conf @@ -0,0 +1,6 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +CONFIG_STACK_SENTINEL=y +CONFIG_PRINTK=y +CONFIG_LOG=n diff --git a/product-mini/platforms/zephyr/simple/src/main.c b/product-mini/platforms/zephyr/simple/src/main.c index 5079888ef..14e6fad2f 100644 --- a/product-mini/platforms/zephyr/simple/src/main.c +++ b/product-mini/platforms/zephyr/simple/src/main.c @@ -9,11 +9,28 @@ #include "bh_assert.h" #include "bh_log.h" #include "wasm_export.h" +#if defined(BUILD_TARGET_RISCV64_LP64) || defined(BUILD_TARGET_RISCV32_ILP32) +#include "test_wasm_riscv64.h" +#else #include "test_wasm.h" +#endif /* end of BUILD_TARGET_RISCV64_LP64 || BUILD_TARGET_RISCV32_ILP32 */ #include #include +#if defined(BUILD_TARGET_RISCV64_LP64) || defined(BUILD_TARGET_RISCV32_ILP32) +#if defined(BUILD_TARGET_RISCV64_LP64) +#define CONFIG_GLOBAL_HEAP_BUF_SIZE 4360 +#define CONFIG_APP_STACK_SIZE 288 +#define CONFIG_MAIN_THREAD_STACK_SIZE 2400 +#else +#define CONFIG_GLOBAL_HEAP_BUF_SIZE 5120 +#define CONFIG_APP_STACK_SIZE 512 +#define CONFIG_MAIN_THREAD_STACK_SIZE 4096 +#endif +#define CONFIG_APP_HEAP_SIZE 256 +#else /* else of BUILD_TARGET_RISCV64_LP64 || BUILD_TARGET_RISCV32_ILP32 */ + #define CONFIG_GLOBAL_HEAP_BUF_SIZE 131072 #define CONFIG_APP_STACK_SIZE 8192 #define CONFIG_APP_HEAP_SIZE 8192 @@ -24,6 +41,8 @@ #define CONFIG_MAIN_THREAD_STACK_SIZE 4096 #endif +#endif /* end of BUILD_TARGET_RISCV64_LP64 || BUILD_TARGET_RISCV32_ILP32 */ + static int app_argc; static char **app_argv; @@ -120,7 +139,6 @@ void iwasm_main(void *arg1, void *arg2, void *arg3) (void) arg2; (void) arg3; - memset(&init_args, 0, sizeof(RuntimeInitArgs)); init_args.mem_alloc_type = Alloc_With_Pool; diff --git a/product-mini/platforms/zephyr/simple/src/test_wasm_riscv64.h b/product-mini/platforms/zephyr/simple/src/test_wasm_riscv64.h new file mode 100644 index 000000000..526317afa --- /dev/null +++ b/product-mini/platforms/zephyr/simple/src/test_wasm_riscv64.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +unsigned char __aligned(4) wasm_test_file[] = { + 0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x10, 0x03, 0x60, + 0x01, 0x7F, 0x01, 0x7F, 0x60, 0x02, 0x7F, 0x7F, 0x01, 0x7F, 0x60, 0x01, + 0x7F, 0x00, 0x02, 0x31, 0x04, 0x03, 0x65, 0x6E, 0x76, 0x04, 0x70, 0x75, + 0x74, 0x73, 0x00, 0x00, 0x03, 0x65, 0x6E, 0x76, 0x06, 0x6D, 0x61, 0x6C, + 0x6C, 0x6F, 0x63, 0x00, 0x00, 0x03, 0x65, 0x6E, 0x76, 0x06, 0x70, 0x72, + 0x69, 0x6E, 0x74, 0x66, 0x00, 0x01, 0x03, 0x65, 0x6E, 0x76, 0x04, 0x66, + 0x72, 0x65, 0x65, 0x00, 0x02, 0x03, 0x02, 0x01, 0x01, 0x04, 0x05, 0x01, + 0x70, 0x01, 0x01, 0x01, 0x05, 0x03, 0x01, 0x00, 0x01, 0x06, 0x12, 0x03, + 0x7F, 0x01, 0x41, 0xC0, 0x01, 0x0B, 0x7F, 0x00, 0x41, 0x3A, 0x0B, 0x7F, + 0x00, 0x41, 0xC0, 0x01, 0x0B, 0x07, 0x2C, 0x04, 0x06, 0x6D, 0x65, 0x6D, + 0x6F, 0x72, 0x79, 0x02, 0x00, 0x04, 0x6D, 0x61, 0x69, 0x6E, 0x00, 0x04, + 0x0A, 0x5F, 0x5F, 0x64, 0x61, 0x74, 0x61, 0x5F, 0x65, 0x6E, 0x64, 0x03, + 0x01, 0x0B, 0x5F, 0x5F, 0x68, 0x65, 0x61, 0x70, 0x5F, 0x62, 0x61, 0x73, + 0x65, 0x03, 0x02, 0x0A, 0xB1, 0x01, 0x01, 0xAE, 0x01, 0x01, 0x03, 0x7F, + 0x23, 0x80, 0x80, 0x80, 0x80, 0x00, 0x41, 0x20, 0x6B, 0x22, 0x02, 0x24, + 0x80, 0x80, 0x80, 0x80, 0x00, 0x41, 0x9B, 0x80, 0x80, 0x80, 0x00, 0x10, + 0x80, 0x80, 0x80, 0x80, 0x00, 0x1A, 0x02, 0x40, 0x02, 0x40, 0x41, 0x10, + 0x10, 0x81, 0x80, 0x80, 0x80, 0x00, 0x22, 0x03, 0x0D, 0x00, 0x41, 0xA8, + 0x80, 0x80, 0x80, 0x00, 0x10, 0x80, 0x80, 0x80, 0x80, 0x00, 0x1A, 0x41, + 0x7F, 0x21, 0x04, 0x0C, 0x01, 0x0B, 0x20, 0x02, 0x20, 0x03, 0x36, 0x02, + 0x10, 0x41, 0x80, 0x80, 0x80, 0x80, 0x00, 0x20, 0x02, 0x41, 0x10, 0x6A, + 0x10, 0x82, 0x80, 0x80, 0x80, 0x00, 0x1A, 0x41, 0x00, 0x21, 0x04, 0x20, + 0x03, 0x41, 0x04, 0x6A, 0x41, 0x00, 0x2F, 0x00, 0x91, 0x80, 0x80, 0x80, + 0x00, 0x3B, 0x00, 0x00, 0x20, 0x03, 0x41, 0x00, 0x28, 0x00, 0x8D, 0x80, + 0x80, 0x80, 0x00, 0x36, 0x00, 0x00, 0x20, 0x02, 0x20, 0x03, 0x36, 0x02, + 0x00, 0x41, 0x93, 0x80, 0x80, 0x80, 0x00, 0x20, 0x02, 0x10, 0x82, 0x80, + 0x80, 0x80, 0x00, 0x1A, 0x20, 0x03, 0x10, 0x83, 0x80, 0x80, 0x80, 0x00, + 0x0B, 0x20, 0x02, 0x41, 0x20, 0x6A, 0x24, 0x80, 0x80, 0x80, 0x80, 0x00, + 0x20, 0x04, 0x0B, 0x0B, 0x40, 0x01, 0x00, 0x41, 0x00, 0x0B, 0x3A, 0x62, + 0x75, 0x66, 0x20, 0x70, 0x74, 0x72, 0x3A, 0x20, 0x25, 0x70, 0x0A, 0x00, + 0x31, 0x32, 0x33, 0x34, 0x0A, 0x00, 0x62, 0x75, 0x66, 0x3A, 0x20, 0x25, + 0x73, 0x00, 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, + 0x64, 0x21, 0x00, 0x6D, 0x61, 0x6C, 0x6C, 0x6F, 0x63, 0x20, 0x62, 0x75, + 0x66, 0x20, 0x66, 0x61, 0x69, 0x6C, 0x65, 0x64, 0x00 +}; diff --git a/product-mini/platforms/zephyr/simple/src/wasm-app-riscv64/build.sh b/product-mini/platforms/zephyr/simple/src/wasm-app-riscv64/build.sh new file mode 100755 index 000000000..73e734935 --- /dev/null +++ b/product-mini/platforms/zephyr/simple/src/wasm-app-riscv64/build.sh @@ -0,0 +1,27 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +WAMR_DIR=${PWD}/../../.. + +echo "Build wasm app .." +/opt/wasi-sdk/bin/clang -O3 \ + -z stack-size=128 -Wl,--initial-memory=65536 \ + -Wl,--global-base=0 \ + -o test.wasm main.c \ + -Wl,--export=main -Wl,--export=__main_argc_argv \ + -Wl,--export=__data_end -Wl,--export=__heap_base \ + -Wl,--strip-all,--no-entry \ + -Wl,--allow-undefined \ + -nostdlib \ + +echo "Build binarydump tool .." +rm -fr build && mkdir build && cd build +cmake ../../../../../../../test-tools/binarydump-tool +make +cd .. + +echo "Generate test_wasm.h .." +./build/binarydump -o test_wasm.h -n wasm_test_file test.wasm +cp -a test_wasm.h ../test_wasm_riscv64.h + +echo "Done" diff --git a/product-mini/platforms/zephyr/simple/src/wasm-app-riscv64/main.c b/product-mini/platforms/zephyr/simple/src/wasm-app-riscv64/main.c new file mode 100644 index 000000000..760634525 --- /dev/null +++ b/product-mini/platforms/zephyr/simple/src/wasm-app-riscv64/main.c @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include +#include + +int main(int argc, char **argv) +{ + char *buf; + + printf("Hello world!\n"); + + buf = malloc(16); + if (!buf) { + printf("malloc buf failed\n"); + return -1; + } + + printf("buf ptr: %p\n", buf); + + snprintf(buf, 1024, "%s", "1234\n"); + printf("buf: %s", buf); + + free(buf); + return 0; +} From efd648959c74859467f56cb5a84db7e5da555a85 Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Mon, 25 Jan 2021 18:43:44 +0800 Subject: [PATCH 146/207] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 1b644dc21..d5fabc6ce 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,7 @@ The iwasm supports the following architectures: - AArch64 (Cortex-A57 and Cortex-A53 are tested) - MIPS - XTENSA +- RISCV64, RISCV32 (interpreter only) Following platforms are supported. Refer to [WAMR porting guide](./doc/port_wamr.md) for how to port WAMR to a new platform. From a5188f5574a0f0aed7d178ca3774ff8657f4ac95 Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Thu, 28 Jan 2021 02:16:02 -0600 Subject: [PATCH 147/207] Add checks to avoid wasm_runtime_malloc memory with size 0 (#507) In some platforms, allocating memory with size 0 may return NULL but not an empty memory block, which causes runtime load, instantiate or execute wasm/aot file failed. We add checks to try to avoid allocating memory in runtime if the size is 0. And in wasm_runtime_malloc/free, output warning if allocate memory with size 0 and free memory with NULL ptr. Also fix some coding style issues, fix handle riscv32 ilp32d issue, and fix several wasm-c-api issues. Signed-off-by: Wenyong Huang --- core/iwasm/aot/aot_loader.c | 26 +++-- core/iwasm/aot/aot_runtime.c | 43 +++++--- core/iwasm/common/wasm_c_api.c | 100 ++++++++++-------- core/iwasm/common/wasm_memory.c | 14 ++- core/iwasm/common/wasm_runtime_common.c | 15 ++- core/iwasm/compilation/aot.h | 2 +- core/iwasm/compilation/aot_emit_aot_file.c | 14 +-- core/iwasm/compilation/aot_emit_function.c | 16 +-- core/iwasm/compilation/aot_emit_memory.c | 24 +++-- core/iwasm/compilation/aot_llvm.c | 38 ++++++- core/iwasm/compilation/aot_llvm.h | 1 + .../compilation/simd/simd_access_lanes.c | 2 +- core/iwasm/interpreter/wasm_loader.c | 10 +- core/iwasm/interpreter/wasm_mini_loader.c | 10 +- core/iwasm/interpreter/wasm_runtime.c | 29 +++-- .../sandboxed-system-primitives/src/posix.c | 3 +- core/shared/utils/bh_log.h | 4 +- core/shared/utils/uncommon/bh_read_file.c | 14 ++- samples/wasm-c-api/CMakeLists.txt | 2 +- .../workload/meshoptimizer/codecbench.patch | 4 +- 20 files changed, 240 insertions(+), 131 deletions(-) diff --git a/core/iwasm/aot/aot_loader.c b/core/iwasm/aot/aot_loader.c index eb9f198f6..769e47d62 100644 --- a/core/iwasm/aot/aot_loader.c +++ b/core/iwasm/aot/aot_loader.c @@ -1117,8 +1117,9 @@ load_function_section(const uint8 *buf, const uint8 *buf_end, uint64 size, text_offset; size = sizeof(void*) * (uint64)module->func_count; - if (!(module->func_ptrs = loader_malloc - (size, error_buf, error_buf_size))) { + if (size > 0 + && !(module->func_ptrs = loader_malloc + (size, error_buf, error_buf_size))) { return false; } @@ -1158,8 +1159,9 @@ load_function_section(const uint8 *buf, const uint8 *buf_end, } size = sizeof(uint32) * (uint64)module->func_count; - if (!(module->func_type_indexes = loader_malloc - (size, error_buf, error_buf_size))) { + if (size > 0 + && !(module->func_type_indexes = loader_malloc + (size, error_buf, error_buf_size))) { return false; } @@ -1498,7 +1500,8 @@ load_relocation_section(const uint8 *buf, const uint8 *buf_end, /* Allocate memory for relocation groups */ size = sizeof(AOTRelocationGroup) * (uint64)group_count; - if (!(groups = loader_malloc(size, error_buf, error_buf_size))) { + if (size > 0 + && !(groups = loader_malloc(size, error_buf, error_buf_size))) { goto fail; } @@ -2065,8 +2068,9 @@ aot_load_from_comp_data(AOTCompData *comp_data, AOTCompContext *comp_ctx, /* Allocate memory for function pointers */ size = (uint64)module->func_count * sizeof(void *); - if (!(module->func_ptrs = - loader_malloc(size, error_buf, error_buf_size))) { + if (size > 0 + && !(module->func_ptrs = + loader_malloc(size, error_buf, error_buf_size))) { goto fail2; } @@ -2085,8 +2089,9 @@ aot_load_from_comp_data(AOTCompData *comp_data, AOTCompContext *comp_ctx, /* Allocation memory for function type indexes */ size = (uint64)module->func_count * sizeof(uint32); - if (!(module->func_type_indexes = - loader_malloc(size, error_buf, error_buf_size))) { + if (size > 0 + && !(module->func_type_indexes = + loader_malloc(size, error_buf, error_buf_size))) { goto fail3; } for (i = 0; i < comp_data->func_count; i++) @@ -2135,7 +2140,8 @@ aot_load_from_comp_data(AOTCompData *comp_data, AOTCompContext *comp_ctx, return module; fail3: - wasm_runtime_free(module->func_ptrs); + if (module->func_ptrs) + wasm_runtime_free(module->func_ptrs); fail2: if (module->memory_count > 0) wasm_runtime_free(module->memories); diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index 18518e0bb..f52e4eb24 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -176,7 +176,7 @@ memories_deinstantiate(AOTModuleInstance *module_inst) wasm_runtime_free(memory_inst->heap_handle.ptr); } - if (memory_inst->heap_data.ptr) { + if (memory_inst->memory_data.ptr) { #ifndef OS_ENABLE_HW_BOUND_CHECK wasm_runtime_free(memory_inst->memory_data.ptr); #else @@ -202,7 +202,7 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModule *module, uint32 bytes_of_last_page, bytes_to_page_end; uint32 heap_offset = num_bytes_per_page *init_page_count; uint64 total_size; - uint8 *p, *global_addr; + uint8 *p = NULL, *global_addr; #ifdef OS_ENABLE_HW_BOUND_CHECK uint8 *mapped_mem; uint64 map_size = 8 * (uint64)BH_GB; @@ -321,7 +321,8 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModule *module, #ifndef OS_ENABLE_HW_BOUND_CHECK /* Allocate memory */ - if (!(p = runtime_malloc(total_size, error_buf, error_buf_size))) { + if (total_size > 0 + && !(p = runtime_malloc(total_size, error_buf, error_buf_size))) { return NULL; } #else @@ -420,7 +421,8 @@ fail2: wasm_runtime_free(memory_inst->heap_handle.ptr); fail1: #ifndef OS_ENABLE_HW_BOUND_CHECK - wasm_runtime_free(memory_inst->memory_data.ptr); + if (memory_inst->memory_data.ptr) + wasm_runtime_free(memory_inst->memory_data.ptr); #else os_munmap(mapped_mem, map_size); #endif @@ -504,7 +506,8 @@ memories_instantiate(AOTModuleInstance *module_inst, AOTModule *module, } /* Copy memory data */ - bh_assert(memory_inst->memory_data.ptr); + bh_assert(memory_inst->memory_data.ptr + || memory_inst->memory_data_size == 0); /* Check memory data */ /* check offset since length might negative */ @@ -526,9 +529,11 @@ memories_instantiate(AOTModuleInstance *module_inst, AOTModule *module, return false; } - bh_memcpy_s((uint8*)memory_inst->memory_data.ptr + base_offset, - memory_inst->memory_data_size - base_offset, - data_seg->bytes, length); + if (memory_inst->memory_data.ptr) { + bh_memcpy_s((uint8*)memory_inst->memory_data.ptr + base_offset, + memory_inst->memory_data_size - base_offset, + data_seg->bytes, length); + } } return true; @@ -543,6 +548,9 @@ init_func_ptrs(AOTModuleInstance *module_inst, AOTModule *module, uint64 total_size = ((uint64)module->import_func_count + module->func_count) * sizeof(void*); + if (module->import_func_count + module->func_count == 0) + return true; + /* Allocate memory */ if (!(module_inst->func_ptrs.ptr = runtime_malloc (total_size, error_buf, error_buf_size))) { @@ -562,7 +570,8 @@ init_func_ptrs(AOTModuleInstance *module_inst, AOTModule *module, } /* Set defined function pointers */ - memcpy(func_ptrs, module->func_ptrs, module->func_count * sizeof(void*)); + bh_memcpy_s(func_ptrs, sizeof(void*) * module->func_count, + module->func_ptrs, sizeof(void*) * module->func_count); return true; } @@ -575,6 +584,9 @@ init_func_type_indexes(AOTModuleInstance *module_inst, AOTModule *module, uint64 total_size = ((uint64)module->import_func_count + module->func_count) * sizeof(uint32); + if (module->import_func_count + module->func_count == 0) + return true; + /* Allocate memory */ if (!(module_inst->func_type_indexes.ptr = runtime_malloc(total_size, error_buf, error_buf_size))) { @@ -586,9 +598,8 @@ init_func_type_indexes(AOTModuleInstance *module_inst, AOTModule *module, for (i = 0; i < module->import_func_count; i++, func_type_index++) *func_type_index = module->import_funcs[i].func_type_index; - memcpy(func_type_index, module->func_type_indexes, - module->func_count * sizeof(uint32)); - + bh_memcpy_s(func_type_index, sizeof(uint32) * module->func_count, + module->func_type_indexes, sizeof(uint32) * module->func_count); return true; } @@ -1688,9 +1699,11 @@ aot_enlarge_memory(AOTModuleInstance *module_inst, uint32 inc_page_count) if (!(memory_data = wasm_runtime_malloc((uint32)total_size))) { return false; } - bh_memcpy_s(memory_data, (uint32)total_size, - memory_data_old, total_size_old); - wasm_runtime_free(memory_data_old); + if (memory_data_old) { + bh_memcpy_s(memory_data, (uint32)total_size, + memory_data_old, total_size_old); + wasm_runtime_free(memory_data_old); + } } memset(memory_data + total_size_old, diff --git a/core/iwasm/common/wasm_c_api.c b/core/iwasm/common/wasm_c_api.c index cc1082b99..9e65989b1 100644 --- a/core/iwasm/common/wasm_c_api.c +++ b/core/iwasm/common/wasm_c_api.c @@ -23,7 +23,7 @@ void wasm_instance_delete_internal(wasm_instance_t *); static void * -malloc_internal(size_t size) +malloc_internal(uint64 size) { void *mem = NULL; @@ -47,8 +47,7 @@ malloc_internal(size_t size) /* Vectors */ #define INIT_VEC(vector_p, func_prefix, size) \ do { \ - vector_p = malloc_internal(sizeof(*(vector_p))); \ - if (!vector_p) { \ + if (!(vector_p = malloc_internal(sizeof(*(vector_p))))) { \ goto failed; \ } \ func_prefix##_new_uninitialized(vector_p, size); \ @@ -75,7 +74,8 @@ malloc_internal(size_t size) static inline void generic_vec_init_data(Vector *out, size_t num_of_elems, size_t size_of_elem) { - if (!bh_vector_init(out, num_of_elems, size_of_elem)) { + /* size 0 is meaningless for a elemment */ + if (!size_of_elem || !bh_vector_init(out, num_of_elems, size_of_elem)) { out->data = NULL; out->max_elems = 0; out->num_elems = 0; @@ -99,7 +99,7 @@ wasm_byte_vec_copy(wasm_byte_vec_t *out, const wasm_byte_vec_t *src) bh_assert(out && src); - generic_vec_init_data((Vector *)out, src->size, src->size_of_elem); + generic_vec_init_data((Vector *)out, src->size, sizeof(wasm_byte_t)); if (!out->data) { goto failed; } @@ -187,7 +187,7 @@ wasm_engine_new_internal(mem_alloc_type_t type, goto failed; } -#if BH_DEBUG == 1 +#if BH_DEBUG != 0 bh_log_set_verbose_level(5); #else bh_log_set_verbose_level(3); @@ -459,7 +459,7 @@ wasm_valtype_vec_copy(wasm_valtype_vec_t *out, const wasm_valtype_vec_t *src) bh_assert(out && src); - generic_vec_init_data((Vector *)out, src->size, src->size_of_elem); + generic_vec_init_data((Vector *)out, src->size, sizeof(wasm_valtype_t *)); if (!out->data) { goto failed; } @@ -1116,33 +1116,41 @@ failed: static void native_func_trampoline(wasm_exec_env_t exec_env, uint64 *argv) { - wasm_val_t *params = NULL; - wasm_val_t *results = NULL; + wasm_val_t *params = NULL, *results = NULL; uint32 argc = 0; const wasm_func_t *func = NULL; wasm_trap_t *trap = NULL; - - bh_assert(argv); + size_t param_count, result_count; func = wasm_runtime_get_function_attachment(exec_env); bh_assert(func); - params = malloc_internal(wasm_func_param_arity(func) * sizeof(wasm_val_t)); - if (!params) { - goto failed; + param_count = wasm_func_param_arity(func); + if (param_count) { + if (!argv) { + goto failed; + } + + if (!(params = malloc_internal(param_count * sizeof(wasm_val_t)))) { + goto failed; + } + + /* argv -> const wasm_val_t params[] */ + if (!(argc = argv_to_params( + argv, wasm_functype_params(wasm_func_type(func)), params))) { + goto failed; + } } - results = - malloc_internal(wasm_func_result_arity(func) * sizeof(wasm_val_t)); - if (!results) { - goto failed; - } + result_count = wasm_func_result_arity(func); + if (result_count) { + if (!argv) { + goto failed; + } - /* argv -> const wasm_val_t params[] */ - argc = - argv_to_params(argv, wasm_functype_params(wasm_func_type(func)), params); - if (wasm_func_param_arity(func) && !argc) { - goto failed; + if (!(results = malloc_internal(result_count * sizeof(wasm_val_t)))) { + goto failed; + } } if (func->with_env) { @@ -1164,16 +1172,17 @@ native_func_trampoline(wasm_exec_env_t exec_env, uint64 *argv) } } - /* there is no result or there is an exception */ - if (trap || !wasm_func_result_arity(func)) { + if (argv) { memset(argv, 0, wasm_func_param_arity(func) * sizeof(uint64)); } - /* wasm_val_t results[] -> argv */ - argc = results_to_argv(results, - wasm_functype_results(wasm_func_type(func)), argv); - if (wasm_func_result_arity(func) && !argc) { - goto failed; + /* there is no trap and there is return values */ + if (!trap && result_count) { + /* wasm_val_t results[] -> argv */ + if (!(argc = results_to_argv( + results, wasm_functype_results(wasm_func_type(func)), argv))) { + goto failed; + } } failed: @@ -1503,8 +1512,7 @@ wasm_func_call(const wasm_func_t *func, /* a parameter list and a return value list */ uint32 *argv = NULL; WASMFunctionInstanceCommon *func_comm_rt = NULL; - size_t param_count = 0; - size_t result_count = 0; + size_t param_count, result_count, alloc_count; bh_assert(func && func->func_type && func->inst_comm_rt); @@ -1527,17 +1535,18 @@ wasm_func_call(const wasm_func_t *func, param_count = wasm_func_param_arity(func); result_count = wasm_func_result_arity(func); - argv = malloc_internal( - sizeof(uint64) - * (param_count > result_count ? param_count : result_count)); - if (!argv) { - goto failed; + alloc_count = (param_count > result_count) ? param_count : result_count; + if (alloc_count) { + if (!(argv = malloc_internal(sizeof(uint64) * alloc_count))) { + goto failed; + } } /* copy parametes */ - argc = params_to_argv(params, wasm_functype_params(wasm_func_type(func)), - wasm_func_param_arity(func), argv); - if (wasm_func_param_arity(func) && !argc) { + if (param_count + && !(argc = params_to_argv(params, + wasm_functype_params(wasm_func_type(func)), + wasm_func_param_arity(func), argv))) { goto failed; } @@ -1548,9 +1557,10 @@ wasm_func_call(const wasm_func_t *func, } /* copy results */ - argc = argv_to_results(argv, wasm_functype_results(wasm_func_type(func)), - wasm_func_result_arity(func), results); - if (wasm_func_result_arity(func) && !argc) { + if (result_count + && !(argc = argv_to_results( + argv, wasm_functype_results(wasm_func_type(func)), + wasm_func_result_arity(func), results))) { goto failed; } @@ -2734,7 +2744,7 @@ wasm_extern_vec_copy(wasm_extern_vec_t *out, const wasm_extern_vec_t *src) size_t i = 0; bh_assert(out && src); - generic_vec_init_data((Vector *)out, src->size, src->size_of_elem); + generic_vec_init_data((Vector *)out, src->size, sizeof(wasm_extern_t *)); if (!out->data) { goto failed; } diff --git a/core/iwasm/common/wasm_memory.c b/core/iwasm/common/wasm_memory.c index 0b94beeb4..1d8faffbe 100644 --- a/core/iwasm/common/wasm_memory.c +++ b/core/iwasm/common/wasm_memory.c @@ -161,8 +161,14 @@ wasm_runtime_realloc_internal(void *ptr, unsigned int size) static inline void wasm_runtime_free_internal(void *ptr) { + if (!ptr) { + LOG_WARNING("warning: wasm_runtime_free with NULL pointer\n"); + return; + } + if (memory_mode == MEMORY_MODE_UNKNOWN) { - LOG_WARNING("wasm_runtime_free failed: memory hasn't been initialize.\n"); + LOG_WARNING("warning: wasm_runtime_free failed: " + "memory hasn't been initialize.\n"); } else if (memory_mode == MEMORY_MODE_POOL) { mem_allocator_free(pool_allocator, ptr); @@ -175,6 +181,12 @@ wasm_runtime_free_internal(void *ptr) void * wasm_runtime_malloc(unsigned int size) { + if (size == 0) { + LOG_WARNING("warning: wasm_runtime_malloc with size zero\n"); + /* At lease alloc 1 byte to avoid malloc failed */ + size = 1; + } + return wasm_runtime_malloc_internal(size); } diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index 65ab805c6..56e90e19c 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -1712,9 +1712,11 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, total_size = sizeof(char *) * (uint64)argc; if (total_size >= UINT32_MAX - || !(argv_list = wasm_runtime_malloc((uint32)total_size)) + || (total_size > 0 && + !(argv_list = wasm_runtime_malloc((uint32)total_size))) || argv_buf_size >= UINT32_MAX - || !(argv_buf = wasm_runtime_malloc((uint32)argv_buf_size))) { + || (argv_buf_size > 0 && + !(argv_buf = wasm_runtime_malloc((uint32)argv_buf_size)))) { set_error_buf(error_buf, error_buf_size, "Init wasi environment failed: allocate memory failed"); goto fail; @@ -1730,11 +1732,13 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, for (i = 0; i < env_count; i++) env_buf_size += strlen(env[i]) + 1; - total_size = sizeof(char *) * (uint64)argc; + total_size = sizeof(char *) * (uint64)env_count; if (total_size >= UINT32_MAX - || !(env_list = wasm_runtime_malloc((uint32)total_size)) + || (total_size > 0 + && !(env_list = wasm_runtime_malloc((uint32)total_size))) || env_buf_size >= UINT32_MAX - || !(env_buf = wasm_runtime_malloc((uint32)env_buf_size))) { + || (env_buf_size > 0 + && !(env_buf = wasm_runtime_malloc((uint32)env_buf_size)))) { set_error_buf(error_buf, error_buf_size, "Init wasi environment failed: allocate memory failed"); goto fail; @@ -2842,6 +2846,7 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, n_stacks++; n_stacks += 2; } + break; #endif /* BUILD_TARGET_RISCV32_ILP32D */ default: bh_assert(0); diff --git a/core/iwasm/compilation/aot.h b/core/iwasm/compilation/aot.h index 633792360..32f8da2c7 100644 --- a/core/iwasm/compilation/aot.h +++ b/core/iwasm/compilation/aot.h @@ -234,7 +234,7 @@ aot_set_last_error(const char *error); void aot_set_last_error_v(const char *format, ...); -#if BH_DEBUG == 1 +#if BH_DEBUG != 0 #define HANDLE_FAILURE(callee) do { \ aot_set_last_error_v("call %s failed in %s:%d", (callee),\ __FUNCTION__, __LINE__); \ diff --git a/core/iwasm/compilation/aot_emit_aot_file.c b/core/iwasm/compilation/aot_emit_aot_file.c index 17cc32622..b194c2aca 100644 --- a/core/iwasm/compilation/aot_emit_aot_file.c +++ b/core/iwasm/compilation/aot_emit_aot_file.c @@ -1751,16 +1751,18 @@ aot_resolve_functions(AOTCompContext *comp_ctx, AOTObjectData *obj_data) AOTObjectFunc *func; LLVMSymbolIteratorRef sym_itr; char *name, *prefix = AOT_FUNC_PREFIX; - uint32 func_index; + uint32 func_index, total_size; /* allocate memory for aot function */ obj_data->func_count = comp_ctx->comp_data->func_count; - if (!(obj_data->funcs - = wasm_runtime_malloc((uint32)sizeof(AOTObjectFunc) * obj_data->func_count))) { - aot_set_last_error("allocate memory for functions failed."); - return false; + if (obj_data->func_count) { + total_size = (uint32)sizeof(AOTObjectFunc) * obj_data->func_count; + if (!(obj_data->funcs = wasm_runtime_malloc(total_size))) { + aot_set_last_error("allocate memory for functions failed."); + return false; + } + memset(obj_data->funcs, 0, total_size); } - memset(obj_data->funcs, 0, sizeof(AOTObjectFunc) * obj_data->func_count); if (!(sym_itr = LLVMObjectFileCopySymbolIterator(obj_data->binary))) { aot_set_last_error("llvm get symbol iterator failed."); diff --git a/core/iwasm/compilation/aot_emit_function.c b/core/iwasm/compilation/aot_emit_function.c index 57cac163c..32cb40158 100644 --- a/core/iwasm/compilation/aot_emit_function.c +++ b/core/iwasm/compilation/aot_emit_function.c @@ -792,7 +792,7 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, uint8 wasm_ret_type, *wasm_ret_types; uint64 total_size; char buf[32]; - bool ret; + bool ret = false; /* Check function type index */ if (type_idx >= comp_ctx->comp_data->func_type_count) { @@ -1105,13 +1105,15 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, LLVMPositionBuilderAtEnd(comp_ctx->builder, block_call_import); /* Allocate memory for result values */ - total_size = sizeof(LLVMValueRef) * (uint64)func_result_count; - if (total_size >= UINT32_MAX - || !(value_rets = wasm_runtime_malloc((uint32)total_size))) { - aot_set_last_error("allocate memory failed."); - goto fail; + if (func_result_count > 0) { + total_size = sizeof(LLVMValueRef) * (uint64)func_result_count; + if (total_size >= UINT32_MAX + || !(value_rets = wasm_runtime_malloc((uint32)total_size))) { + aot_set_last_error("allocate memory failed."); + goto fail; + } + memset(value_rets, 0, (uint32)total_size); } - memset(value_rets, 0, total_size); param_cell_num = func_type->param_cell_num; wasm_ret_types = func_type->types + func_type->param_count; diff --git a/core/iwasm/compilation/aot_emit_memory.c b/core/iwasm/compilation/aot_emit_memory.c index 99d6593d7..883f4b9df 100644 --- a/core/iwasm/compilation/aot_emit_memory.c +++ b/core/iwasm/compilation/aot_emit_memory.c @@ -74,7 +74,7 @@ get_memory_check_bound(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } static LLVMValueRef -get_memory_size(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx); +get_memory_curr_page_count(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx); LLVMValueRef aot_check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, @@ -171,7 +171,7 @@ aot_check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, if (init_page_count == 0) { LLVMValueRef mem_size; - if (!(mem_size = get_memory_size(comp_ctx, func_ctx))) { + if (!(mem_size = get_memory_curr_page_count(comp_ctx, func_ctx))) { goto fail; } BUILD_ICMP(LLVMIntEQ, mem_size, I32_ZERO, cmp, "is_zero"); @@ -611,7 +611,7 @@ fail: } static LLVMValueRef -get_memory_size(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) +get_memory_curr_page_count(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) { LLVMValueRef mem_size; @@ -636,7 +636,7 @@ fail: bool aot_compile_op_memory_size(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) { - LLVMValueRef mem_size = get_memory_size(comp_ctx, func_ctx); + LLVMValueRef mem_size = get_memory_curr_page_count(comp_ctx, func_ctx); if (mem_size) PUSH_I32(mem_size); @@ -648,7 +648,7 @@ fail: bool aot_compile_op_memory_grow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) { - LLVMValueRef mem_size = get_memory_size(comp_ctx, func_ctx); + LLVMValueRef mem_size = get_memory_curr_page_count(comp_ctx, func_ctx); LLVMValueRef delta, param_values[2], ret_value, func, value; LLVMTypeRef param_types[2], ret_type, func_type, func_ptr_type; @@ -801,9 +801,17 @@ check_bulk_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } } - /* mem_size_offset = aot_inst + off */ - if (!(mem_size = get_memory_size(comp_ctx, func_ctx))) { - goto fail; + if (func_ctx->mem_space_unchanged) { + mem_size = func_ctx->mem_info[0].mem_data_size_addr; + } + else { + if (!(mem_size = + LLVMBuildLoad(comp_ctx->builder, + func_ctx->mem_info[0].mem_data_size_addr, + "mem_size"))) { + aot_set_last_error("llvm build load failed."); + goto fail; + } } ADD_BASIC_BLOCK(check_succ, "check_succ"); diff --git a/core/iwasm/compilation/aot_llvm.c b/core/iwasm/compilation/aot_llvm.c index 15ca7e562..7c7e73a0c 100644 --- a/core/iwasm/compilation/aot_llvm.c +++ b/core/iwasm/compilation/aot_llvm.c @@ -262,6 +262,13 @@ 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, memory_data_size)); + if (!(func_ctx->mem_info[0].mem_data_size_addr = + LLVMBuildInBoundsGEP(comp_ctx->builder, shared_mem_addr, + &offset, 1, "mem_data_size_offset"))) { + aot_set_last_error("llvm build in bounds gep failed"); + return false; + } } else #endif @@ -282,6 +289,14 @@ 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(AOTModuleInstance, global_table_data) + + offsetof(AOTMemoryInstance, memory_data_size)); + if (!(func_ctx->mem_info[0].mem_data_size_addr = + LLVMBuildInBoundsGEP(comp_ctx->builder, func_ctx->aot_inst, + &offset, 1, "mem_data_size_offset"))) { + aot_set_last_error("llvm build in bounds gep failed"); + return false; + } } /* Store mem info base address before cast */ mem_info_base = func_ctx->mem_info[0].mem_base_addr; @@ -300,6 +315,13 @@ create_memory_info(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, aot_set_last_error("llvm build bit cast failed"); return false; } + if (!(func_ctx->mem_info[0].mem_data_size_addr = + LLVMBuildBitCast(comp_ctx->builder, + func_ctx->mem_info[0].mem_data_size_addr, + INT32_PTR_TYPE, "mem_data_size_ptr"))) { + aot_set_last_error("llvm build bit cast failed"); + return false; + } if (mem_space_unchanged) { if (!(func_ctx->mem_info[0].mem_base_addr = LLVMBuildLoad(comp_ctx->builder, @@ -311,7 +333,14 @@ create_memory_info(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, if (!(func_ctx->mem_info[0].mem_cur_page_count_addr = LLVMBuildLoad(comp_ctx->builder, func_ctx->mem_info[0].mem_cur_page_count_addr, - "mem_cur_page_count_addr"))) { + "mem_cur_page_count"))) { + aot_set_last_error("llvm build load failed"); + return false; + } + if (!(func_ctx->mem_info[0].mem_data_size_addr = + LLVMBuildLoad(comp_ctx->builder, + func_ctx->mem_info[0].mem_data_size_addr, + "mem_data_size"))) { aot_set_last_error("llvm build load failed"); return false; } @@ -1476,7 +1505,9 @@ aot_create_comp_context(AOTCompData *comp_data, /* Create function context for each function */ comp_ctx->func_ctx_count = comp_data->func_count; - if (!(comp_ctx->func_ctxes = aot_create_func_contexts(comp_data, comp_ctx))) + if (comp_data->func_count > 0 + && !(comp_ctx->func_ctxes = + aot_create_func_contexts(comp_data, comp_ctx))) goto fail; ret = comp_ctx; @@ -1521,7 +1552,8 @@ aot_destroy_comp_context(AOTCompContext *comp_ctx) LLVMContextDispose(comp_ctx->context); if (comp_ctx->func_ctxes) - aot_destroy_func_contexts(comp_ctx->func_ctxes, comp_ctx->func_ctx_count); + aot_destroy_func_contexts(comp_ctx->func_ctxes, + comp_ctx->func_ctx_count); wasm_runtime_free(comp_ctx); } diff --git a/core/iwasm/compilation/aot_llvm.h b/core/iwasm/compilation/aot_llvm.h index 02b249285..0fa11ed3e 100644 --- a/core/iwasm/compilation/aot_llvm.h +++ b/core/iwasm/compilation/aot_llvm.h @@ -103,6 +103,7 @@ typedef struct AOTCheckedAddr { typedef struct AOTMemInfo { LLVMValueRef mem_base_addr; + LLVMValueRef mem_data_size_addr; LLVMValueRef mem_cur_page_count_addr; LLVMValueRef mem_bound_check_1byte; LLVMValueRef mem_bound_check_2bytes; diff --git a/core/iwasm/compilation/simd/simd_access_lanes.c b/core/iwasm/compilation/simd/simd_access_lanes.c index 4778d6368..eef22ea8f 100644 --- a/core/iwasm/compilation/simd/simd_access_lanes.c +++ b/core/iwasm/compilation/simd/simd_access_lanes.c @@ -83,7 +83,7 @@ fail: return false; } -// TODO: instructions for other CPUs +/* TODO: instructions for other CPUs */ /* shufflevector is not an option, since it requires *mask as a const */ bool aot_compile_simd_swizzle(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index a83e02105..a95c00090 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -2148,7 +2148,8 @@ load_table_segment_section(const uint8 *buf, const uint8 *buf_end, WASMModule *m read_leb_uint32(p, p_end, function_count); table_segment->function_count = function_count; total_size = sizeof(uint32) * (uint64)function_count; - if (!(table_segment->func_indexes = (uint32 *) + if (total_size > 0 + && !(table_segment->func_indexes = (uint32 *) loader_malloc(total_size, error_buf, error_buf_size))) { return false; } @@ -2444,7 +2445,7 @@ handle_name_section(const uint8 *buf, const uint8 *buf_end, previous_func_index = func_index; read_leb_uint32(p, p_end, func_name_len); CHECK_BUF(p, p_end, func_name_len); - // Skip the import functions + /* Skip the import functions */ if (func_index >= module->import_count) { func_index -= module->import_count; if (func_index >= module->function_count) { @@ -5697,7 +5698,7 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, uint32 segment_index; #endif #if WASM_ENABLE_FAST_INTERP != 0 - uint8 *func_const_end, *func_const; + uint8 *func_const_end, *func_const = NULL; int16 operand_offset; uint8 last_op = 0; bool disable_emit, preserve_local = false; @@ -7710,7 +7711,8 @@ fail_data_cnt_sec_require: goto re_scan; func->const_cell_num = loader_ctx->const_cell_num; - if (!(func->consts = func_const = + if (func->const_cell_num > 0 + && !(func->consts = func_const = loader_malloc(func->const_cell_num * 4, error_buf, error_buf_size))) { goto fail; diff --git a/core/iwasm/interpreter/wasm_mini_loader.c b/core/iwasm/interpreter/wasm_mini_loader.c index f2c19bcd8..36ab505a2 100644 --- a/core/iwasm/interpreter/wasm_mini_loader.c +++ b/core/iwasm/interpreter/wasm_mini_loader.c @@ -1167,7 +1167,8 @@ load_table_segment_section(const uint8 *buf, const uint8 *buf_end, WASMModule *m read_leb_uint32(p, p_end, function_count); table_segment->function_count = function_count; total_size = sizeof(uint32) * (uint64)function_count; - if (!(table_segment->func_indexes = (uint32 *) + if (total_size > 0 + && !(table_segment->func_indexes = (uint32 *) loader_malloc(total_size, error_buf, error_buf_size))) { return false; } @@ -1391,7 +1392,7 @@ handle_name_section(const uint8 *buf, const uint8 *buf_end, previous_func_index = func_index; read_leb_uint32(p, p_end, func_name_len); CHECK_BUF(p, p_end, func_name_len); - // Skip the import functions + /* Skip the import functions */ if (func_index >= module->import_count) { func_index -= module->import_count; bh_assert(func_index < module->function_count); @@ -4257,7 +4258,7 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, uint32 segment_index; #endif #if WASM_ENABLE_FAST_INTERP != 0 - uint8 *func_const_end, *func_const; + uint8 *func_const_end, *func_const = NULL; int16 operand_offset; uint8 last_op = 0; bool disable_emit, preserve_local = false; @@ -5733,7 +5734,8 @@ handle_op_block_and_loop: goto re_scan; func->const_cell_num = loader_ctx->const_cell_num; - if (!(func->consts = func_const = + if (func->const_cell_num > 0 + && !(func->consts = func_const = loader_malloc(func->const_cell_num * 4, error_buf, error_buf_size))) { goto fail; diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index 6a371e5e5..ca28af030 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -110,7 +110,8 @@ memories_deinstantiate(WASMModuleInstance *module_inst, wasm_runtime_free(memories[i]->heap_handle); memories[i]->heap_handle = NULL; } - wasm_runtime_free(memories[i]->memory_data); + if (memories[i]->memory_data) + wasm_runtime_free(memories[i]->memory_data); wasm_runtime_free(memories[i]); } } @@ -248,8 +249,10 @@ memory_instantiate(WASMModuleInstance *module_inst, return NULL; } - if (!(memory->memory_data = - runtime_malloc(memory_data_size, error_buf, error_buf_size))) { + if (memory_data_size > 0 + && !(memory->memory_data = + runtime_malloc(memory_data_size, + error_buf, error_buf_size))) { goto fail1; } @@ -307,7 +310,8 @@ fail3: if (heap_size > 0) wasm_runtime_free(memory->heap_handle); fail2: - wasm_runtime_free(memory->memory_data); + if (memory->memory_data) + wasm_runtime_free(memory->memory_data); fail1: wasm_runtime_free(memory); return NULL; @@ -1293,9 +1297,8 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, bh_assert(memory); memory_data = memory->memory_data; - bh_assert(memory_data); - memory_size = memory->num_bytes_per_page * memory->cur_page_count; + bh_assert(memory_data || memory_size == 0); bh_assert(data_seg->base_offset.init_expr_type == INIT_EXPR_TYPE_I32_CONST @@ -1337,8 +1340,10 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, goto fail; } - bh_memcpy_s(memory_data + base_offset, memory_size - base_offset, - data_seg->data, length); + if (memory_data) { + bh_memcpy_s(memory_data + base_offset, memory_size - base_offset, + data_seg->data, length); + } } /* Initialize the table data with table segment section */ @@ -1970,9 +1975,11 @@ wasm_enlarge_memory(WASMModuleInstance *module, uint32 inc_page_count) if (!(new_memory_data = wasm_runtime_malloc((uint32)total_size))) { return false; } - bh_memcpy_s(new_memory_data, (uint32)total_size, - memory_data, total_size_old); - wasm_runtime_free(memory_data); + if (memory_data) { + bh_memcpy_s(new_memory_data, (uint32)total_size, + memory_data, total_size_old); + wasm_runtime_free(memory_data); + } } memset(new_memory_data + total_size_old, diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c index df31ea3f7..9e4d989f5 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c @@ -1652,7 +1652,8 @@ static __wasi_errno_t path_get_nofollow( static void path_put( struct path_access *pa ) UNLOCKS(pa->fd_object->refcount) { - wasm_runtime_free(pa->path_start); + if (pa->path_start) + wasm_runtime_free(pa->path_start); if (fd_number(pa->fd_object) != pa->fd) close(pa->fd); fd_object_release(pa->fd_object); diff --git a/core/shared/utils/bh_log.h b/core/shared/utils/bh_log.h index e0720964e..dd24dc043 100644 --- a/core/shared/utils/bh_log.h +++ b/core/shared/utils/bh_log.h @@ -51,7 +51,7 @@ bh_log(LogLevel log_level, const char *file, int line, const char *fmt, ...); #endif -#if BH_DEBUG == 1 +#if BH_DEBUG != 0 #define LOG_FATAL(...) bh_log(BH_LOG_LEVEL_FATAL, __FILE__, __LINE__, __VA_ARGS__) #else #define LOG_FATAL(...) bh_log(BH_LOG_LEVEL_FATAL, __FUNCTION__, __LINE__, __VA_ARGS__) @@ -61,7 +61,7 @@ bh_log(LogLevel log_level, const char *file, int line, const char *fmt, ...); #define LOG_WARNING(...) bh_log(BH_LOG_LEVEL_WARNING, NULL, 0, __VA_ARGS__) #define LOG_VERBOSE(...) bh_log(BH_LOG_LEVEL_VERBOSE, NULL, 0, __VA_ARGS__) -#if BH_DEBUG == 1 +#if BH_DEBUG != 0 #define LOG_DEBUG(...) bh_log(BH_LOG_LEVEL_DEBUG, __FILE__, __LINE__, __VA_ARGS__) #else #define LOG_DEBUG(...) (void)0 diff --git a/core/shared/utils/uncommon/bh_read_file.c b/core/shared/utils/uncommon/bh_read_file.c index ce616743b..5513fe52e 100644 --- a/core/shared/utils/uncommon/bh_read_file.c +++ b/core/shared/utils/uncommon/bh_read_file.c @@ -14,7 +14,7 @@ bh_read_file_to_buffer(const char *filename, uint32 *ret_size) { char *buffer; int file; - uint32 file_size, read_size; + uint32 file_size, buf_size, read_size; struct stat stat_buf; if (!filename || !ret_size) { @@ -36,7 +36,10 @@ bh_read_file_to_buffer(const char *filename, uint32 *ret_size) } file_size = (uint32)stat_buf.st_size; - if (!(buffer = (char *)BH_MALLOC(file_size))) { + /* At lease alloc 1 byte to avoid malloc failed */ + buf_size = file_size > 0 ? file_size : 1; + + if (!(buffer = (char *)BH_MALLOC(buf_size))) { printf("Read file to buffer failed: alloc memory failed.\n"); _close(file); return NULL; @@ -63,7 +66,7 @@ bh_read_file_to_buffer(const char *filename, uint32 *ret_size) { char *buffer; int file; - uint32 file_size, read_size; + uint32 file_size, buf_size, read_size; struct stat stat_buf; if (!filename || !ret_size) { @@ -86,7 +89,10 @@ bh_read_file_to_buffer(const char *filename, uint32 *ret_size) file_size = (uint32)stat_buf.st_size; - if (!(buffer = BH_MALLOC(file_size))) { + /* At lease alloc 1 byte to avoid malloc failed */ + buf_size = file_size > 0 ? file_size : 1; + + if (!(buffer = BH_MALLOC(buf_size))) { printf("Read file to buffer failed: alloc memory failed.\n"); close(file); return NULL; diff --git a/samples/wasm-c-api/CMakeLists.txt b/samples/wasm-c-api/CMakeLists.txt index 46b30ce94..93235eaff 100644 --- a/samples/wasm-c-api/CMakeLists.txt +++ b/samples/wasm-c-api/CMakeLists.txt @@ -74,7 +74,7 @@ endif() ## locate wat2wasm find_program(WAT2WASM wat2wasm - PATHS /opt/wabt/bin /opt/wabt-1.0.18/bin + PATHS /opt/wabt/bin REQUIRED ) diff --git a/samples/workload/meshoptimizer/codecbench.patch b/samples/workload/meshoptimizer/codecbench.patch index 2d6e9d4fa..d739558a2 100644 --- a/samples/workload/meshoptimizer/codecbench.patch +++ b/samples/workload/meshoptimizer/codecbench.patch @@ -1,5 +1,5 @@ diff --git a/CMakeLists.txt b/CMakeLists.txt -index ffdb4da..536a5c8 100644 +index ffdb4da..a397427 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -127,3 +127,43 @@ install(FILES @@ -24,7 +24,7 @@ index ffdb4da..536a5c8 100644 + +target_link_options(codecbench + PUBLIC -+ LINKER:-allow-undefined,--demangle ++ LINKER:-allow-undefined,--demangle,--export=malloc,--export=free +) + +find_program(WASM_OPT From 5947ea492dd6df21d1e540bac28f1384fa43d625 Mon Sep 17 00:00:00 2001 From: Xu Jun <693788454@qq.com> Date: Thu, 4 Feb 2021 08:50:15 +0800 Subject: [PATCH 148/207] Update invokeNative_em64.asm (#511) Fix the issue of WIN64 parameter passing --- core/iwasm/common/arch/invokeNative_em64.asm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/iwasm/common/arch/invokeNative_em64.asm b/core/iwasm/common/arch/invokeNative_em64.asm index 8ce4fc0b9..df8115397 100644 --- a/core/iwasm/common/arch/invokeNative_em64.asm +++ b/core/iwasm/common/arch/invokeNative_em64.asm @@ -37,7 +37,7 @@ no_abort: sub rsp, rdx ; store stack args - lea r9, qword ptr [rax + rcx * 8 + 64] + lea r9, qword ptr [rax + rcx * 8 + 56] sub r9, rsp ; offset cycle: push qword ptr [rsp + r9] @@ -59,4 +59,4 @@ invokeNative ENDP _TEXT ENDS -END \ No newline at end of file +END From 1630cb2524b19d497ff236cf91d5d144aae857eb Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Sat, 6 Feb 2021 21:05:48 -0600 Subject: [PATCH 149/207] Fix duplicated destroy shared memory's lock issue (#514) And add native symbol node to list head when registering native symbol, so as to lookup developer's registered node firstly when linking. Signed-off-by: Wenyong Huang --- core/iwasm/common/wasm_native.c | 14 ++++---------- core/iwasm/interpreter/wasm_runtime.c | 2 +- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/core/iwasm/common/wasm_native.c b/core/iwasm/common/wasm_native.c index c4313a6e6..fb64c6495 100644 --- a/core/iwasm/common/wasm_native.c +++ b/core/iwasm/common/wasm_native.c @@ -21,7 +21,6 @@ #endif static NativeSymbolsList g_native_symbols_list = NULL; -static NativeSymbolsList g_native_symbols_list_end = NULL; uint32 get_libc_builtin_export_apis(NativeSymbol **p_libc_builtin_apis); @@ -287,15 +286,10 @@ register_natives(const char *module_name, node->native_symbols = native_symbols; node->n_native_symbols = n_native_symbols; node->call_conv_raw = call_conv_raw; - node->next = NULL; - if (g_native_symbols_list_end) { - g_native_symbols_list_end->next = node; - g_native_symbols_list_end = node; - } - else { - g_native_symbols_list = g_native_symbols_list_end = node; - } + /* Add to list head */ + node->next = g_native_symbols_list; + g_native_symbols_list = node; #if ENABLE_SORT_DEBUG != 0 gettimeofday(&start, NULL); @@ -417,5 +411,5 @@ wasm_native_destroy() node = node_next; } - g_native_symbols_list = g_native_symbols_list_end = NULL; + g_native_symbols_list = NULL; } diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index ca28af030..6ffe90b32 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -92,7 +92,6 @@ memories_deinstantiate(WASMModuleInstance *module_inst, continue; #endif #if WASM_ENABLE_SHARED_MEMORY != 0 - os_mutex_destroy(&memories[0]->mem_lock); if (memories[i]->is_shared) { int32 ref_count = shared_memory_dec_reference( @@ -104,6 +103,7 @@ memories_deinstantiate(WASMModuleInstance *module_inst, if (ref_count > 0) continue; } + os_mutex_destroy(&memories[i]->mem_lock); #endif if (memories[i]->heap_handle) { mem_allocator_destroy(memories[i]->heap_handle); From 52f422dba0bb7f208729673d99508168128a5542 Mon Sep 17 00:00:00 2001 From: Xu Jun <693788454@qq.com> Date: Tue, 9 Feb 2021 10:36:44 +0800 Subject: [PATCH 150/207] fix pthread library issues: (#522) 1. pthread_join can't get return value from exited threads 2. pthread_cond_wait return success when timeout --- .../lib-pthread/lib_pthread_wrapper.c | 79 +++++++++++++------ .../platform/common/posix/posix_thread.c | 2 +- 2 files changed, 58 insertions(+), 23 deletions(-) diff --git a/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c b/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c index 35359c50c..0930a9785 100644 --- a/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c +++ b/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c @@ -97,10 +97,13 @@ typedef struct ThreadInfoNode { /* Thread status, this variable should be volatile as its value may be changed in different threads */ volatile uint32 status; + bool joinable; union { korp_tid thread; korp_mutex *mutex; korp_cond *cond; + /* A copy of the thread return value */ + void *ret; } u; } ThreadInfoNode; @@ -136,16 +139,9 @@ static void thread_info_destroy(void *node) { ThreadInfoNode *info_node = (ThreadInfoNode *)node; - ThreadRoutineArgs *args; pthread_mutex_lock(&pthread_global_lock); - if (info_node->type == T_THREAD) { - args = get_thread_arg(info_node->exec_env); - if (args) { - wasm_runtime_free(args); - } - } - else if (info_node->type == T_MUTEX) { + if (info_node->type == T_MUTEX) { if (info_node->status != MUTEX_DESTROYED) os_mutex_destroy(info_node->u.mutex); wasm_runtime_free(info_node->u.mutex); @@ -510,7 +506,17 @@ pthread_start_routine(void *arg) info_node->status = THREAD_EXIT; - delete_thread_info_node(info_node); + wasm_runtime_free(routine_args); + + /* if the thread is joinable, store the result in its info node, + if the other threads join this thread after exited, then we + can return the stored result */ + if (!info_node->joinable) { + delete_thread_info_node(info_node); + } + else { + info_node->u.ret = (void *)(uintptr_t)argv[0]; + } return (void *)(uintptr_t)argv[0]; } @@ -554,6 +560,7 @@ pthread_create_wrapper(wasm_exec_env_t exec_env, info_node->handle = thread_handle; info_node->type = T_THREAD; info_node->status = THREAD_INIT; + info_node->joinable = true; if (!(routine_args = wasm_runtime_malloc(sizeof(ThreadRoutineArgs)))) goto fail; @@ -604,27 +611,41 @@ pthread_join_wrapper(wasm_exec_env_t exec_env, uint32 thread, wasm_module_inst_t module_inst; wasm_exec_env_t target_exec_env; - node = get_thread_info(exec_env, thread); - if (!node) { - /* The thread has exited, return 0 to app */ - return 0; - } + module_inst = get_module_inst(exec_env); - target_exec_env = node->exec_env; - bh_assert(target_exec_env != NULL); - module_inst = get_module_inst(target_exec_env); - - /* validate addr before join thread, otherwise - the module_inst may be freed */ + /* validate addr, we can use current thread's + module instance here as the memory is shared */ if (!validate_app_addr(retval_offset, sizeof(void *))) { /* Join failed, but we don't want to terminate all threads, do not spread exception here */ wasm_runtime_set_exception(module_inst, NULL); return -1; } + retval = (void **)addr_app_to_native(retval_offset); - join_ret = wasm_cluster_join_thread(target_exec_env, (void **)&ret); + node = get_thread_info(exec_env, thread); + if (!node) { + /* The thread has exited and not joinable, return 0 to app */ + return 0; + } + + target_exec_env = node->exec_env; + bh_assert(target_exec_env); + + if (node->status != THREAD_EXIT) { + /* if the thread is still running, call the platforms join API */ + join_ret = wasm_cluster_join_thread(target_exec_env, (void **)&ret); + } + else { + /* if the thread has exited, return stored results */ + + /* this thread must be joinable, otherwise the + info_node should be destroyed once exit */ + bh_assert(node->joinable); + join_ret = 0; + ret = node->u.ret; + } if (retval_offset != 0) *retval = (void*)ret; @@ -642,6 +663,8 @@ pthread_detach_wrapper(wasm_exec_env_t exec_env, uint32 thread) if (!node) return 0; + node->joinable = false; + target_exec_env = node->exec_env; bh_assert(target_exec_env != NULL); @@ -658,6 +681,9 @@ pthread_cancel_wrapper(wasm_exec_env_t exec_env, uint32 thread) if (!node) return 0; + node->status = THREAD_CANCELLED; + node->joinable = false; + target_exec_env = node->exec_env; bh_assert(target_exec_env != NULL); @@ -700,7 +726,16 @@ pthread_exit_wrapper(wasm_exec_env_t exec_env, int32 retval_offset) /* routine exit, destroy instance */ wasm_runtime_deinstantiate_internal(module_inst, true); - delete_thread_info_node(args->info_node); + args->info_node->status = THREAD_EXIT; + + if (!args->info_node->joinable) { + delete_thread_info_node(args->info_node); + } + else { + args->info_node->u.ret = (void *)(uintptr_t)retval_offset; + } + + wasm_runtime_free(args); wasm_cluster_exit_thread(exec_env, (void *)(uintptr_t)retval_offset); } diff --git a/core/shared/platform/common/posix/posix_thread.c b/core/shared/platform/common/posix/posix_thread.c index a7662f4e4..3580eca74 100644 --- a/core/shared/platform/common/posix/posix_thread.c +++ b/core/shared/platform/common/posix/posix_thread.c @@ -214,7 +214,7 @@ int os_cond_reltimedwait(korp_cond *cond, korp_mutex *mutex, uint64 useconds) if (ret != BHT_OK && ret != ETIMEDOUT) return BHT_ERROR; - return BHT_OK; + return ret; } int os_cond_signal(korp_cond *cond) From 3849ece49675dc5120a57bff587dcdc84f5ddc4c Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Tue, 9 Feb 2021 20:11:32 -0600 Subject: [PATCH 151/207] Fix auxiliary stack size not 16-byte aligned issue (#524) --- core/config.h | 2 ++ core/iwasm/libraries/thread-mgr/thread_manager.c | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/core/config.h b/core/config.h index 74ada1714..e8ab5bb27 100644 --- a/core/config.h +++ b/core/config.h @@ -241,6 +241,8 @@ #else #define DEFAULT_WASM_STACK_SIZE (12 * 1024) #endif +/* Min auxilliary stack size of each wasm thread */ +#define WASM_THREAD_AUX_STACK_SIZE_MIN (256) /* Default/min/max stack size of each app thread */ #if !defined(BH_PLATFORM_ZEPHYR) && !defined(BH_PLATFORM_ALIOS_THINGS) \ diff --git a/core/iwasm/libraries/thread-mgr/thread_manager.c b/core/iwasm/libraries/thread-mgr/thread_manager.c index dfed25be4..6f2dcbae1 100644 --- a/core/iwasm/libraries/thread-mgr/thread_manager.c +++ b/core/iwasm/libraries/thread-mgr/thread_manager.c @@ -151,9 +151,11 @@ wasm_cluster_create(WASMExecEnv *exec_env) } cluster->stack_size = aux_stack_size / (cluster_max_thread_num + 1); - if (cluster->stack_size == 0) { + if (cluster->stack_size < WASM_THREAD_AUX_STACK_SIZE_MIN) { goto fail; } + /* Make stack size 16-byte aligned */ + cluster->stack_size = cluster->stack_size & (~15); /* Set initial aux stack top to the instance and aux stack boundary to the main exec_env */ From 370cc83fbd0f5bb7aa7716e994bb1ec392fdd947 Mon Sep 17 00:00:00 2001 From: Xu Jun <693788454@qq.com> Date: Fri, 19 Feb 2021 11:14:40 +0800 Subject: [PATCH 152/207] Fix loader fail to lookup registered native symbol issue (#529) --- core/iwasm/common/wasm_runtime_common.c | 8 +- core/iwasm/common/wasm_runtime_common.h | 3 - core/iwasm/interpreter/wasm_loader.c | 541 +++++++++++----------- core/iwasm/interpreter/wasm_mini_loader.c | 130 +++--- 4 files changed, 322 insertions(+), 360 deletions(-) diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index 56e90e19c..ceddc1d86 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -539,12 +539,6 @@ wasm_runtime_destroy_loading_module_list() } #endif /* WASM_ENABLE_MULTI_MODULE */ -bool -wasm_runtime_is_host_module(const char *module_name) -{ - return strlen(module_name) == 0; -} - bool wasm_runtime_is_built_in_module(const char *module_name) { @@ -552,7 +546,7 @@ wasm_runtime_is_built_in_module(const char *module_name) || !strcmp("wasi_unstable", module_name) || !strcmp("wasi_snapshot_preview1", module_name) || !strcmp("spectest", module_name) - ); + || !strcmp("", module_name)); } #if WASM_ENABLE_THREAD_MGR != 0 diff --git a/core/iwasm/common/wasm_runtime_common.h b/core/iwasm/common/wasm_runtime_common.h index 74ac7b400..8a0fef0ba 100644 --- a/core/iwasm/common/wasm_runtime_common.h +++ b/core/iwasm/common/wasm_runtime_common.h @@ -369,9 +369,6 @@ void wasm_runtime_destroy_loading_module_list(); #endif /* WASM_ENALBE_MULTI_MODULE */ -bool -wasm_runtime_is_host_module(const char *module_name); - bool wasm_runtime_is_built_in_module(const char *module_name); diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index a95c00090..3f24101c0 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -598,7 +598,7 @@ wasm_loader_resolve_function(const char *module_name, return NULL; } - /* run a function type check */ + /* resolve function type and function */ if (export->index < module->import_function_count) { target_function_type = module->import_functions[export->index].u.function.func_type; @@ -613,6 +613,7 @@ wasm_loader_resolve_function(const char *module_name, module->functions[export->index - module->import_function_count]; } + /* check function type */ if (!wasm_type_equal(expected_function_type, target_function_type)) { LOG_DEBUG("%s.%s failed the type check", module_name, function_name); set_error_buf(error_buf, error_buf_size, "incompatible import type"); @@ -650,7 +651,7 @@ wasm_loader_resolve_table(const char *module_name, const char *table_name, return NULL; } - /* run a table type check */ + /* resolve table and check the init/max size */ if (export->index < module->import_table_count) { table = module->import_tables[export->index].u.table.import_table_linked; @@ -698,7 +699,7 @@ wasm_loader_resolve_memory(const char *module_name, const char *memory_name, } - /* run a memory check */ + /* resolve memory and check the init/max page count */ if (export->index < module->import_memory_count) { memory = module->import_memories[export->index].u.memory.import_memory_linked; @@ -747,7 +748,7 @@ wasm_loader_resolve_global(const char *module_name, return NULL; } - /* run a global check */ + /* resolve and check the global */ if (export->index < module->import_global_count) { global = module->import_globals[export->index].u.global.import_global_linked; @@ -764,12 +765,164 @@ wasm_loader_resolve_global(const char *module_name, } return global; } + +static WASMModule * +search_sub_module(const WASMModule *parent_module, const char *sub_module_name) +{ + WASMRegisteredModule *node = + bh_list_first_elem(parent_module->import_module_list); + while (node && strcmp(sub_module_name, node->module_name)) { + node = bh_list_elem_next(node); + } + return node ? (WASMModule*)node->module : NULL; +} + +static bool +register_sub_module(const WASMModule *parent_module, + const char *sub_module_name, WASMModule *sub_module) +{ + /* register sub_module into its parent sub module list */ + WASMRegisteredModule *node = NULL; + bh_list_status ret; + + if (search_sub_module(parent_module, sub_module_name)) { + LOG_DEBUG("%s has been registered in its parent", sub_module_name); + return true; + } + + node = wasm_runtime_malloc(sizeof(WASMRegisteredModule)); + if (!node) { + return false; + } + + node->module_name = sub_module_name; + node->module = (WASMModuleCommon*)sub_module; + ret = bh_list_insert(parent_module->import_module_list, node); + bh_assert(BH_LIST_SUCCESS == ret); + (void)ret; + return true; +} + +static WASMModule * +load_depended_module(const WASMModule *parent_module, + const char *sub_module_name, char *error_buf, + uint32 error_buf_size) +{ + WASMModule *sub_module = NULL; + bool ret = false; + uint8 *buffer = NULL; + uint32 buffer_size = 0; + const module_reader reader = wasm_runtime_get_module_reader(); + const module_destroyer destroyer = wasm_runtime_get_module_destroyer(); + + /* check the registered module list of the parent */ + sub_module = search_sub_module(parent_module, sub_module_name); + if (sub_module) { + LOG_DEBUG("%s has been loaded before", sub_module_name); + return sub_module; + } + + /* check the global registered module list */ + sub_module = + (WASMModule *)wasm_runtime_find_module_registered(sub_module_name); + if (sub_module) { + LOG_DEBUG("%s has been loaded", sub_module_name); + goto register_sub_module; + } + + LOG_VERBOSE("loading %s", sub_module_name); + + if (!reader) { + set_error_buf_v(error_buf, error_buf_size, + "no sub module reader to load %s", + sub_module_name); + return NULL; + } + + /* start to maintain a loading module list */ + ret = wasm_runtime_is_loading_module(sub_module_name); + if (ret) { + set_error_buf_v(error_buf, error_buf_size, + "found circular dependency on %s", + sub_module_name); + return NULL; + } + + ret = wasm_runtime_add_loading_module(sub_module_name, error_buf, + error_buf_size); + if (!ret) { + LOG_DEBUG("can not add %s into loading module list\n", + sub_module_name); + return NULL; + } + + ret = reader(sub_module_name, &buffer, &buffer_size); + if (!ret) { + LOG_DEBUG("read the file of %s failed", sub_module_name); + set_error_buf_v(error_buf, error_buf_size, "unknown import", + sub_module_name); + goto delete_loading_module; + } + + sub_module = + wasm_loader_load(buffer, buffer_size, error_buf, error_buf_size); + if (!sub_module) { + LOG_DEBUG("error: can not load the sub_module %s", sub_module_name); + /* others will be destroyed in runtime_destroy() */ + goto destroy_file_buffer; + } + + wasm_runtime_delete_loading_module(sub_module_name); + + /* register on a global list */ + ret = wasm_runtime_register_module_internal(sub_module_name, + (WASMModuleCommon*)sub_module, + buffer, buffer_size, error_buf, + error_buf_size); + if (!ret) { + LOG_DEBUG("error: can not register module %s globally\n", sub_module_name); + /* others will be unloaded in runtime_destroy() */ + goto unload_module; + } + + /* register into its parent list */ +register_sub_module: + ret = register_sub_module(parent_module, sub_module_name, sub_module); + if (!ret) { + set_error_buf_v(error_buf, error_buf_size, + "failed to register sub module %s", + sub_module_name); + /* since it is in the global module list, no need to + * unload the module. the runtime_destroy() will do it + */ + return NULL; + } + + return sub_module; + +unload_module: + wasm_loader_unload(sub_module); + +destroy_file_buffer: + if (destroyer) { + destroyer(buffer, buffer_size); + } + else { + LOG_WARNING("need to release the reading buffer of %s manually", + sub_module_name); + } + +delete_loading_module: + wasm_runtime_delete_loading_module(sub_module_name); + return NULL; +} #endif /* end of WASM_ENABLE_MULTI_MODULE */ static bool -load_function_import(const WASMModule *parent_module, WASMModule *sub_module, - char *sub_module_name, char *function_name, - const uint8 **p_buf, const uint8 *buf_end, +load_function_import(const uint8 **p_buf, const uint8 *buf_end, + const WASMModule *parent_module, + const char *sub_module_name, + const char *function_name, WASMFunctionImport *function, char *error_buf, uint32 error_buf_size) { @@ -777,10 +930,14 @@ load_function_import(const WASMModule *parent_module, WASMModule *sub_module, uint32 declare_type_index = 0; WASMType *declare_func_type = NULL; WASMFunction *linked_func = NULL; +#if WASM_ENABLE_MULTI_MODULE != 0 + WASMModule *sub_module = NULL; +#endif const char *linked_signature = NULL; void *linked_attachment = NULL; bool linked_call_conv_raw = false; - bool is_built_in_module = false; + bool is_native_symbol = false; + CHECK_BUF(p, p_end, 1); read_leb_uint32(p, p_end, declare_type_index); @@ -799,21 +956,25 @@ load_function_import(const WASMModule *parent_module, WASMModule *sub_module, declare_func_type = parent_module->types[declare_type_index]; - if (wasm_runtime_is_host_module(sub_module_name)) { - /* do nothing, wait for injecting host created fuctions */ - } - else if ((is_built_in_module = - wasm_runtime_is_built_in_module(sub_module_name))) { - /* check built-in modules */ - linked_func = wasm_native_resolve_symbol(sub_module_name, - function_name, - declare_func_type, - &linked_signature, - &linked_attachment, - &linked_call_conv_raw); + /* lookup registered native symbols first */ + linked_func = wasm_native_resolve_symbol(sub_module_name, + function_name, + declare_func_type, + &linked_signature, + &linked_attachment, + &linked_call_conv_raw); + if (linked_func) { + is_native_symbol = true; } #if WASM_ENABLE_MULTI_MODULE != 0 else { + if (!wasm_runtime_is_built_in_module(sub_module_name)) { + sub_module = load_depended_module(parent_module, sub_module_name, + error_buf, error_buf_size); + if (!sub_module) { + return false; + } + } linked_func = wasm_loader_resolve_function(sub_module_name, function_name, declare_func_type, @@ -822,18 +983,17 @@ load_function_import(const WASMModule *parent_module, WASMModule *sub_module, } #endif - function->module_name = sub_module_name; - function->field_name = function_name; + function->module_name = (char *)sub_module_name; + function->field_name = (char *)function_name; function->func_type = declare_func_type; - /* func_ptr_linked is for built-in functions */ - function->func_ptr_linked = is_built_in_module ? linked_func : NULL; + /* func_ptr_linked is for native registered symbol */ + function->func_ptr_linked = is_native_symbol ? linked_func : NULL; function->signature = linked_signature; function->attachment = linked_attachment; function->call_conv_raw = linked_call_conv_raw; #if WASM_ENABLE_MULTI_MODULE != 0 - function->import_module = is_built_in_module ? NULL : sub_module; - /* can not set both func_ptr_linked and import_func_linked not NULL */ - function->import_func_linked = is_built_in_module ? NULL : linked_func; + function->import_module = is_native_symbol ? NULL : sub_module; + function->import_func_linked = is_native_symbol ? NULL : linked_func; #endif return true; fail: @@ -853,9 +1013,11 @@ check_table_max_size(uint32 init_size, uint32 max_size, } static bool -load_table_import(WASMModule *sub_module, const char *sub_module_name, - const char *table_name, const uint8 **p_buf, - const uint8 *buf_end, WASMTableImport *table, +load_table_import(const uint8 **p_buf, const uint8 *buf_end, + WASMModule *parent_module, + const char *sub_module_name, + const char *table_name, + WASMTableImport *table, char *error_buf, uint32 error_buf_size) { const uint8 *p = *p_buf, *p_end = buf_end; @@ -864,6 +1026,7 @@ load_table_import(WASMModule *sub_module, const char *sub_module_name, uint32 declare_init_size = 0; uint32 declare_max_size = 0; #if WASM_ENABLE_MULTI_MODULE != 0 + WASMModule *sub_module = NULL; WASMTable *linked_table = NULL; #endif @@ -889,19 +1052,21 @@ load_table_import(WASMModule *sub_module, const char *sub_module_name, #if WASM_ENABLE_MULTI_MODULE != 0 if (!wasm_runtime_is_built_in_module(sub_module_name)) { - linked_table = wasm_loader_resolve_table( - sub_module_name, table_name, - declare_init_size, declare_max_size, - error_buf, error_buf_size); - if (!linked_table) { - LOG_DEBUG("(%s, %s) is not an exported from one of modules", - table_name, sub_module_name); + sub_module = load_depended_module(parent_module, sub_module_name, + error_buf, error_buf_size); + if (!sub_module) { return false; } - /** - * reset with linked table limit - */ + linked_table = wasm_loader_resolve_table( + sub_module_name, table_name, + declare_init_size, declare_max_size, + error_buf, error_buf_size); + if (!linked_table) { + return false; + } + + /* reset with linked table limit */ declare_elem_type = linked_table->elem_type; declare_init_size = linked_table->init_size; declare_max_size = linked_table->max_size; @@ -977,9 +1142,11 @@ check_memory_max_size(uint32 init_size, uint32 max_size, } static bool -load_memory_import(WASMModule *sub_module, const char *sub_module_name, - const char *memory_name, const uint8 **p_buf, - const uint8 *buf_end, WASMMemoryImport *memory, +load_memory_import(const uint8 **p_buf, const uint8 *buf_end, + WASMModule *parent_module, + const char *sub_module_name, + const char *memory_name, + WASMMemoryImport *memory, char *error_buf, uint32 error_buf_size) { const uint8 *p = *p_buf, *p_end = buf_end; @@ -994,6 +1161,7 @@ load_memory_import(WASMModule *sub_module, const char *sub_module_name, uint32 declare_init_page_count = 0; uint32 declare_max_page_count = 0; #if WASM_ENABLE_MULTI_MODULE != 0 + WASMModule *sub_module = NULL; WASMMemory *linked_memory = NULL; #endif @@ -1022,6 +1190,12 @@ load_memory_import(WASMModule *sub_module, const char *sub_module_name, #if WASM_ENABLE_MULTI_MODULE != 0 if (!wasm_runtime_is_built_in_module(sub_module_name)) { + sub_module = load_depended_module(parent_module, sub_module_name, + error_buf, error_buf_size); + if (!sub_module) { + return false; + } + linked_memory = wasm_loader_resolve_memory( sub_module_name, memory_name, declare_init_page_count, declare_max_page_count, @@ -1075,16 +1249,19 @@ fail: } static bool -load_global_import(const WASMModule *parent_module, - WASMModule *sub_module, +load_global_import(const uint8 **p_buf, const uint8 *buf_end, + const WASMModule *parent_module, char *sub_module_name, char *global_name, - const uint8 **p_buf, const uint8 *buf_end, WASMGlobalImport *global, char *error_buf, uint32 error_buf_size) { const uint8 *p = *p_buf, *p_end = buf_end; uint8 declare_type = 0; uint8 declare_mutable = 0; +#if WASM_ENABLE_MULTI_MODULE != 0 + WASMModule *sub_module = NULL; + WASMGlobal *linked_global = NULL; +#endif CHECK_BUF(p, p_end, 2); declare_type = read_uint8(p); @@ -1096,20 +1273,21 @@ load_global_import(const WASMModule *parent_module, return false; } - if (wasm_runtime_is_host_module(sub_module_name)) { - /* do nothing, let host inject the symbol */ - } #if WASM_ENABLE_LIBC_BUILTIN != 0 - else if (wasm_runtime_is_built_in_module(sub_module_name)) { - /* check built-in modules */ - global->is_linked = wasm_native_lookup_libc_builtin_global( - sub_module_name, global_name, global); - } + global->is_linked = wasm_native_lookup_libc_builtin_global( + sub_module_name, global_name, global); #endif #if WASM_ENABLE_MULTI_MODULE != 0 - else { + if (!global->is_linked + && !wasm_runtime_is_built_in_module(sub_module_name)) { + sub_module = load_depended_module(parent_module, sub_module_name, + error_buf, error_buf_size); + if (!sub_module) { + return false; + } + /* check sub modules */ - WASMGlobal *linked_global = + linked_global = wasm_loader_resolve_global(sub_module_name, global_name, declare_type, declare_mutable, error_buf, error_buf_size); @@ -1236,170 +1414,6 @@ fail: return false; } -#if WASM_ENABLE_MULTI_MODULE != 0 -static WASMModule * -search_sub_module(const WASMModule *parent_module, const char *sub_module_name) -{ - WASMRegisteredModule *node = - bh_list_first_elem(parent_module->import_module_list); - while (node && strcmp(sub_module_name, node->module_name)) { - node = bh_list_elem_next(node); - } - return node ? (WASMModule*)node->module : NULL; -} - -static bool -register_sub_module(const WASMModule *parent_module, - const char *sub_module_name, WASMModule *sub_module) -{ - /* register a sub_module on its parent sub module list */ - WASMRegisteredModule *node = NULL; - bh_list_status ret; - - if (search_sub_module(parent_module, sub_module_name)) { - LOG_DEBUG("%s has been registered in its parent", sub_module_name); - return true; - } - - node = wasm_runtime_malloc(sizeof(WASMRegisteredModule)); - if (!node) { - LOG_DEBUG("malloc WASMRegisteredModule failed. SZ %d\n", - sizeof(WASMRegisteredModule)); - return false; - } - - node->module_name = sub_module_name; - node->module = (WASMModuleCommon*)sub_module; - ret = bh_list_insert(parent_module->import_module_list, node); - bh_assert(BH_LIST_SUCCESS == ret); - (void)ret; - return true; -} - -static WASMModule * -load_depended_module(const WASMModule *parent_module, - const char *sub_module_name, char *error_buf, - uint32 error_buf_size) -{ - WASMModule *sub_module = NULL; - bool ret = false; - uint8 *buffer = NULL; - uint32 buffer_size = 0; - const module_reader reader = wasm_runtime_get_module_reader(); - const module_destroyer destroyer = wasm_runtime_get_module_destroyer(); - - /* check the registered module list of the parent */ - sub_module = search_sub_module(parent_module, sub_module_name); - if (sub_module) { - LOG_DEBUG("%s has been loaded before", sub_module_name); - return sub_module; - } - - /* check the global registered module list */ - sub_module = - (WASMModule *)wasm_runtime_find_module_registered(sub_module_name); - if (sub_module) { - LOG_DEBUG("%s has been loaded", sub_module_name); - goto REGISTER_SUB_MODULE; - } - - LOG_VERBOSE("to load %s", sub_module_name); - - if (!reader) { - LOG_DEBUG("error: there is no sub_module reader to load %s", - sub_module_name); - set_error_buf_v(error_buf, error_buf_size, - "no sub module reader to load %s", - sub_module_name); - return NULL; - } - - /* start to maintain a loading module list */ - ret = wasm_runtime_is_loading_module(sub_module_name); - if (ret) { - LOG_DEBUG("find a circular dependency on %s", sub_module_name); - set_error_buf_v(error_buf, error_buf_size, - "found circular dependency on %s", - sub_module_name); - return NULL; - } - - ret = wasm_runtime_add_loading_module(sub_module_name, error_buf, - error_buf_size); - if (!ret) { - LOG_DEBUG("can not add %s into loading module list\n", - sub_module_name); - return NULL; - } - - ret = reader(sub_module_name, &buffer, &buffer_size); - if (!ret) { - LOG_DEBUG("read the file of %s failed", sub_module_name); - set_error_buf_v(error_buf, error_buf_size, "unknown import", - sub_module_name); - goto DELETE_FROM_LOADING_LIST; - } - - sub_module = - wasm_loader_load(buffer, buffer_size, error_buf, error_buf_size); - if (!sub_module) { - LOG_DEBUG("error: can not load the sub_module %s", sub_module_name); - /* - * others will be destroyed in runtime_destroy() - */ - goto DESTROY_FILE_BUFFER; - } - - wasm_runtime_delete_loading_module(sub_module_name); - - /* register on a global list */ - ret = wasm_runtime_register_module_internal(sub_module_name, - (WASMModuleCommon*)sub_module, - buffer, buffer_size, error_buf, - error_buf_size); - if (!ret) { - LOG_DEBUG("error: can not register module %s globally\n", - sub_module_name); - /* - * others will be unload in runtime_destroy() - */ - goto UNLOAD_MODULE; - } - - /* register on its parent list */ -REGISTER_SUB_MODULE: - ret = register_sub_module(parent_module, sub_module_name, sub_module); - if (!ret) { - set_error_buf_v(error_buf, error_buf_size, - "failed to register sub module %s", - sub_module_name); - /* - * since it is in the global module list, there is no need to - * unload the module. the runtime_destroy() will do it - */ - return NULL; - } - - return sub_module; - -UNLOAD_MODULE: - wasm_loader_unload(sub_module); - -DESTROY_FILE_BUFFER: - if (destroyer) { - destroyer(buffer, buffer_size); - } - else { - LOG_WARNING("need to release the reading buffer of %s manually", - sub_module_name); - } - -DELETE_FROM_LOADING_LIST: - wasm_runtime_delete_loading_module(sub_module_name); - return NULL; -} -#endif /* WASM_ENABLE_MULTI_MODULE */ - static bool load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, char *error_buf, uint32 error_buf_size) @@ -1413,6 +1427,15 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, char *sub_module_name, *field_name; uint8 u8, kind; + /* insert builtin module names into const str list */ + if (!const_str_list_insert((uint8*)"env", 3, module, error_buf, error_buf_size) + || !const_str_list_insert((uint8*)"wasi_unstable", 13, module, + error_buf, error_buf_size) + || !const_str_list_insert((uint8*)"wasi_snapshot_preview1", 22, module, + error_buf, error_buf_size)) { + return false; + } + read_leb_uint32(p, p_end, import_count); if (import_count) { @@ -1504,20 +1527,8 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, p = p_old; - /* TODO: move it out of the loop */ - /* insert "env", "wasi_unstable" and "wasi_snapshot_preview1" to const str list */ - if (!const_str_list_insert((uint8*)"env", 3, module, error_buf, error_buf_size) - || !const_str_list_insert((uint8*)"wasi_unstable", 13, module, - error_buf, error_buf_size) - || !const_str_list_insert((uint8*)"wasi_snapshot_preview1", 22, module, - error_buf, error_buf_size)) { - return false; - } - - /* Scan again to read the data */ + /* Scan again to resolve the data */ for (i = 0; i < import_count; i++) { - WASMModule *sub_module = NULL; - /* load module name */ read_leb_uint32(p, p_end, name_len); CHECK_BUF(p, p_end, name_len); @@ -1536,36 +1547,19 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, } p += name_len; - LOG_DEBUG("import #%d: (%s, %s)", i, sub_module_name, field_name); -#if WASM_ENABLE_MULTI_MODULE != 0 - /* assume built-in modules have been loaded */ - if (!wasm_runtime_is_host_module(sub_module_name) - && !wasm_runtime_is_built_in_module(sub_module_name)) { - LOG_DEBUG("%s is an exported field of a %s", field_name, - sub_module_name); - /* - * if it returns well, guarantee that - * the sub_module_name and its dependencies - * have been loaded well - */ - sub_module = load_depended_module(module, sub_module_name, - error_buf, error_buf_size); - if (!sub_module) { - return false; - } - } -#endif - CHECK_BUF(p, p_end, 1); /* 0x00/0x01/0x02/0x03 */ kind = read_uint8(p); + + LOG_DEBUG("import #%d: (%s, %s), kind: %d", + i, sub_module_name, field_name, kind); switch (kind) { case IMPORT_KIND_FUNC: /* import function */ bh_assert(import_functions); import = import_functions++; - if (!load_function_import(module, sub_module, - sub_module_name, field_name, &p, - p_end, &import->u.function, + if (!load_function_import(&p, p_end, module, + sub_module_name, field_name, + &import->u.function, error_buf, error_buf_size)) { return false; } @@ -1574,14 +1568,10 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, case IMPORT_KIND_TABLE: /* import table */ bh_assert(import_tables); import = import_tables++; - if (!load_table_import(sub_module, - sub_module_name, - field_name, - &p, - p_end, + if (!load_table_import(&p, p_end, module, + sub_module_name, field_name, &import->u.table, - error_buf, - error_buf_size)) { + error_buf, error_buf_size)) { LOG_DEBUG("can not import such a table (%s,%s)", sub_module_name, field_name); return false; @@ -1591,14 +1581,10 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, case IMPORT_KIND_MEMORY: /* import memory */ bh_assert(import_memories); import = import_memories++; - if (!load_memory_import(sub_module, - sub_module_name, - field_name, - &p, - p_end, + if (!load_memory_import(&p, p_end, module, + sub_module_name, field_name, &import->u.memory, - error_buf, - error_buf_size)) { + error_buf, error_buf_size)) { return false; } break; @@ -1606,9 +1592,9 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, case IMPORT_KIND_GLOBAL: /* import global */ bh_assert(import_globals); import = import_globals++; - if (!load_global_import(module, sub_module, + if (!load_global_import(&p, p_end, module, sub_module_name, field_name, - &p, p_end, &import->u.global, + &import->u.global, error_buf, error_buf_size)) { return false; } @@ -1622,7 +1608,6 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, import->kind = kind; import->u.names.module_name = sub_module_name; import->u.names.field_name = field_name; - (void)sub_module; } #if WASM_ENABLE_LIBC_WASI != 0 @@ -2043,7 +2028,7 @@ load_export_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, export->index = index; switch(export->kind) { - /*function index*/ + /* function index */ case EXPORT_KIND_FUNC: if (index >= module->function_count + module->import_function_count) { @@ -2058,7 +2043,7 @@ load_export_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, #endif #endif break; - /*table index*/ + /* table index */ case EXPORT_KIND_TABLE: if (index >= module->table_count + module->import_table_count) { @@ -2067,7 +2052,7 @@ load_export_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, return false; } break; - /*memory index*/ + /* memory index */ case EXPORT_KIND_MEMORY: if (index >= module->memory_count + module->import_memory_count) { @@ -2076,7 +2061,7 @@ load_export_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, return false; } break; - /*global index*/ + /* global index */ case EXPORT_KIND_GLOBAL: if (index >= module->global_count + module->import_global_count) { @@ -2561,7 +2546,7 @@ load_from_sections(WASMModule *module, WASMSection *sections, while (section) { buf = section->section_body; buf_end = buf + section->section_body_size; - LOG_DEBUG("to section %d", section->section_type); + LOG_DEBUG("load section, type: %d", section->section_type); switch (section->section_type) { case SECTION_TYPE_USER: /* unsupported user section, ignore it. */ diff --git a/core/iwasm/interpreter/wasm_mini_loader.c b/core/iwasm/interpreter/wasm_mini_loader.c index 36ab505a2..478b3cc34 100644 --- a/core/iwasm/interpreter/wasm_mini_loader.c +++ b/core/iwasm/interpreter/wasm_mini_loader.c @@ -320,9 +320,10 @@ load_type_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, } static bool -load_function_import(const WASMModule *parent_module, WASMModule *sub_module, - char *sub_module_name, char *function_name, - const uint8 **p_buf, const uint8 *buf_end, +load_function_import(const uint8 **p_buf, const uint8 *buf_end, + const WASMModule *parent_module, + const char *sub_module_name, + const char *function_name, WASMFunctionImport *function, char *error_buf, uint32 error_buf_size) { @@ -333,7 +334,6 @@ load_function_import(const WASMModule *parent_module, WASMModule *sub_module, const char *linked_signature = NULL; void *linked_attachment = NULL; bool linked_call_conv_raw = false; - bool is_built_in_module = false; CHECK_BUF(p, p_end, 1); read_leb_uint32(p, p_end, declare_type_index); @@ -343,24 +343,18 @@ load_function_import(const WASMModule *parent_module, WASMModule *sub_module, declare_func_type = parent_module->types[declare_type_index]; - is_built_in_module = wasm_runtime_is_built_in_module(sub_module_name); - if (is_built_in_module) { - LOG_DEBUG("%s is a function of a built-in module %s", - function_name, sub_module_name); - /* check built-in modules */ - linked_func = wasm_native_resolve_symbol(sub_module_name, - function_name, - declare_func_type, - &linked_signature, - &linked_attachment, - &linked_call_conv_raw); - } + /* check built-in modules */ + linked_func = wasm_native_resolve_symbol(sub_module_name, + function_name, + declare_func_type, + &linked_signature, + &linked_attachment, + &linked_call_conv_raw); - function->module_name = sub_module_name; - function->field_name = function_name; + function->module_name = (char *)sub_module_name; + function->field_name = (char *)function_name; function->func_type = declare_func_type; - /* func_ptr_linked is for built-in functions */ - function->func_ptr_linked = is_built_in_module ? linked_func : NULL; + function->func_ptr_linked = linked_func; function->signature = linked_signature; function->attachment = linked_attachment; function->call_conv_raw = linked_call_conv_raw; @@ -368,9 +362,11 @@ load_function_import(const WASMModule *parent_module, WASMModule *sub_module, } static bool -load_table_import(WASMModule *sub_module, const char *sub_module_name, - const char *table_name, const uint8 **p_buf, - const uint8 *buf_end, WASMTableImport *table, +load_table_import(const uint8 **p_buf, const uint8 *buf_end, + WASMModule *parent_module, + const char *sub_module_name, + const char *table_name, + WASMTableImport *table, char *error_buf, uint32 error_buf_size) { const uint8 *p = *p_buf, *p_end = buf_end; @@ -409,9 +405,11 @@ unsigned wasm_runtime_memory_pool_size(); static bool -load_memory_import(WASMModule *sub_module, const char *sub_module_name, - const char *memory_name, const uint8 **p_buf, - const uint8 *buf_end, WASMMemoryImport *memory, +load_memory_import(const uint8 **p_buf, const uint8 *buf_end, + WASMModule *parent_module, + const char *sub_module_name, + const char *memory_name, + WASMMemoryImport *memory, char *error_buf, uint32 error_buf_size) { const uint8 *p = *p_buf, *p_end = buf_end; @@ -454,10 +452,9 @@ load_memory_import(WASMModule *sub_module, const char *sub_module_name, } static bool -load_global_import(const WASMModule *parent_module, - WASMModule *sub_module, +load_global_import(const uint8 **p_buf, const uint8 *buf_end, + const WASMModule *parent_module, char *sub_module_name, char *global_name, - const uint8 **p_buf, const uint8 *buf_end, WASMGlobalImport *global, char *error_buf, uint32 error_buf_size) { @@ -477,12 +474,9 @@ load_global_import(const WASMModule *parent_module, is_mutable = declare_mutable & 1 ? true : false; #if WASM_ENABLE_LIBC_BUILTIN != 0 - ret = wasm_runtime_is_built_in_module(sub_module_name); - if (ret) { - /* check built-in modules */ - ret = wasm_native_lookup_libc_builtin_global(sub_module_name, - global_name, global); - } + /* check built-in modules */ + ret = wasm_native_lookup_libc_builtin_global(sub_module_name, + global_name, global); #endif /* WASM_ENABLE_LIBC_BUILTIN */ global->is_linked = ret; @@ -581,6 +575,15 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, char *sub_module_name, *field_name; uint8 u8, kind; + /* insert builtin module names into const str list */ + if (!const_str_list_insert((uint8*)"env", 3, module, error_buf, error_buf_size) + || !const_str_list_insert((uint8*)"wasi_unstable", 13, module, + error_buf, error_buf_size) + || !const_str_list_insert((uint8*)"wasi_snapshot_preview1", 22, module, + error_buf, error_buf_size)) { + return false; + } + read_leb_uint32(p, p_end, import_count); if (import_count) { @@ -663,17 +666,7 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, p = p_old; - /* TODO: move it out of the loop */ - /* insert "env", "wasi_unstable" and "wasi_snapshot_preview1" to const str list */ - if (!const_str_list_insert((uint8*)"env", 3, module, error_buf, error_buf_size) - || !const_str_list_insert((uint8*)"wasi_unstable", 13, module, - error_buf, error_buf_size) - || !const_str_list_insert((uint8*)"wasi_snapshot_preview1", 22, module, - error_buf, error_buf_size)) { - return false; - } - - /* Scan again to read the data */ + /* Scan again to resolve the data */ for (i = 0; i < import_count; i++) { WASMModule *sub_module = NULL; @@ -695,18 +688,19 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, } p += name_len; - LOG_DEBUG("import #%d: (%s, %s)", i, sub_module_name, field_name); - CHECK_BUF(p, p_end, 1); /* 0x00/0x01/0x02/0x03 */ kind = read_uint8(p); + + LOG_DEBUG("import #%d: (%s, %s), kind: %d", + i, sub_module_name, field_name, kind); switch (kind) { case IMPORT_KIND_FUNC: /* import function */ bh_assert(import_functions); import = import_functions++; - if (!load_function_import(module, sub_module, - sub_module_name, field_name, &p, - p_end, &import->u.function, + if (!load_function_import(&p, p_end, module, + sub_module_name, field_name, + &import->u.function, error_buf, error_buf_size)) { return false; } @@ -715,14 +709,10 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, case IMPORT_KIND_TABLE: /* import table */ bh_assert(import_tables); import = import_tables++; - if (!load_table_import(sub_module, - sub_module_name, - field_name, - &p, - p_end, + if (!load_table_import(&p, p_end, module, + sub_module_name, field_name, &import->u.table, - error_buf, - error_buf_size)) { + error_buf, error_buf_size)) { LOG_DEBUG("can not import such a table (%s,%s)", sub_module_name, field_name); return false; @@ -732,14 +722,10 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, case IMPORT_KIND_MEMORY: /* import memory */ bh_assert(import_memories); import = import_memories++; - if (!load_memory_import(sub_module, - sub_module_name, - field_name, - &p, - p_end, + if (!load_memory_import(&p, p_end, module, + sub_module_name, field_name, &import->u.memory, - error_buf, - error_buf_size)) { + error_buf, error_buf_size)) { return false; } break; @@ -747,9 +733,9 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, case IMPORT_KIND_GLOBAL: /* import global */ bh_assert(import_globals); import = import_globals++; - if (!load_global_import(module, sub_module, + if (!load_global_import(&p, p_end, module, sub_module_name, field_name, - &p, p_end, &import->u.global, + &import->u.global, error_buf, error_buf_size)) { return false; } @@ -1098,22 +1084,22 @@ load_export_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, export->index = index; switch(export->kind) { - /*function index*/ + /* function index */ case EXPORT_KIND_FUNC: bh_assert(index < module->function_count + module->import_function_count); break; - /*table index*/ + /* table index */ case EXPORT_KIND_TABLE: bh_assert(index < module->table_count + module->import_table_count); break; - /*memory index*/ + /* memory index */ case EXPORT_KIND_MEMORY: bh_assert(index < module->memory_count + module->import_memory_count); break; - /*global index*/ + /* global index */ case EXPORT_KIND_GLOBAL: bh_assert(index < module->global_count + module->import_global_count); @@ -1491,7 +1477,7 @@ load_from_sections(WASMModule *module, WASMSection *sections, while (section) { buf = section->section_body; buf_end = buf + section->section_body_size; - LOG_DEBUG("to section %d", section->section_type); + LOG_DEBUG("load section, type: %d", section->section_type); switch (section->section_type) { case SECTION_TYPE_USER: /* unsupported user section, ignore it. */ From fc504041150aedb0000685f6a202791d45d23fa7 Mon Sep 17 00:00:00 2001 From: Xu Jun <693788454@qq.com> Date: Mon, 22 Feb 2021 14:17:46 +0800 Subject: [PATCH 153/207] add uvwasi implementation to support wasi on windows [experimental] (#534) add uvwasi implementation to support wasi on windows [experimental] and update windows.yml Co-authored-by: Wenyong Huang --- .github/workflows/windows.yml | 14 +- build-scripts/config_common.cmake | 4 +- build-scripts/runtime_lib.cmake | 4 +- core/config.h | 4 + core/iwasm/common/wasm_runtime_common.c | 136 ++ core/iwasm/common/wasm_runtime_common.h | 8 + .../libraries/libc-uvwasi/libc_uvwasi.cmake | 30 + .../libc-uvwasi/libc_uvwasi_wrapper.c | 1168 +++++++++++++++++ core/shared/mem-alloc/ems/ems_alloc.c | 8 + core/shared/mem-alloc/ems/ems_gc_internal.h | 6 + doc/build_wamr.md | 15 +- product-mini/platforms/linux/CMakeLists.txt | 2 +- product-mini/platforms/windows/CMakeLists.txt | 11 +- 13 files changed, 1394 insertions(+), 16 deletions(-) create mode 100644 core/iwasm/libraries/libc-uvwasi/libc_uvwasi.cmake create mode 100644 core/iwasm/libraries/libc-uvwasi/libc_uvwasi_wrapper.c diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 9b94ca1f9..3ae374f90 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -21,39 +21,43 @@ jobs: steps: - uses: actions/checkout@v2 + - name: clone uvwasi library + run: | + cd core/deps + git clone https://github.com/nodejs/uvwasi.git - name: Build iwasm [default] run: | cd product-mini/platforms/windows mkdir build && cd build cmake .. cmake --build . --config Release - cd .. && rm -r build + cd .. && rm -force -r build - name: Build iwasm [aot only] run: | cd product-mini/platforms/windows mkdir build && cd build cmake .. -DWAMR_BUILD_AOT=1 -DWAMR_BUILD_INTERP=0 cmake --build . --config Release - cd .. && rm -r build + cd .. && rm -force -r build - name: Build iwasm [interp only] run: | cd product-mini/platforms/windows mkdir build && cd build cmake .. -DWAMR_BUILD_AOT=0 cmake --build . --config Release - cd .. && rm -r build + cd .. && rm -force -r build - name: Build iwasm [tail call] run: | cd product-mini/platforms/windows mkdir build && cd build cmake .. -DWAMR_BUILD_TAIL_CALL=1 cmake --build . --config Release - cd .. && rm -r build + cd .. && rm -force -r build - name: Build iwasm [custom name section] run: | cd product-mini/platforms/windows mkdir build && cd build cmake .. -DWAMR_BUILD_CUSTOM_NAME_SECTION=1 cmake --build . --config Release - cd .. && rm -r build + cd .. && rm -force -r build diff --git a/build-scripts/config_common.cmake b/build-scripts/config_common.cmake index 5d7833b62..b296f89fd 100644 --- a/build-scripts/config_common.cmake +++ b/build-scripts/config_common.cmake @@ -119,7 +119,9 @@ if (WAMR_BUILD_LIBC_BUILTIN EQUAL 1) else () message (" Libc builtin disabled") endif () -if (WAMR_BUILD_LIBC_WASI EQUAL 1) +if (WAMR_BUILD_LIBC_UVWASI EQUAL 1) + message (" Libc WASI enabled with uvwasi implementation") +elseif (WAMR_BUILD_LIBC_WASI EQUAL 1) message (" Libc WASI enabled") else () message (" Libc WASI disabled") diff --git a/build-scripts/runtime_lib.cmake b/build-scripts/runtime_lib.cmake index 4cc495490..b647219d6 100644 --- a/build-scripts/runtime_lib.cmake +++ b/build-scripts/runtime_lib.cmake @@ -75,7 +75,9 @@ if (WAMR_BUILD_LIBC_BUILTIN EQUAL 1) include (${IWASM_DIR}/libraries/libc-builtin/libc_builtin.cmake) endif () -if (WAMR_BUILD_LIBC_WASI EQUAL 1) +if (WAMR_BUILD_LIBC_UVWASI EQUAL 1) + include (${IWASM_DIR}/libraries/libc-uvwasi/libc_uvwasi.cmake) +elseif (WAMR_BUILD_LIBC_WASI EQUAL 1) include (${IWASM_DIR}/libraries/libc-wasi/libc_wasi.cmake) endif () diff --git a/core/config.h b/core/config.h index e8ab5bb27..1fbc77c59 100644 --- a/core/config.h +++ b/core/config.h @@ -90,6 +90,10 @@ #define WASM_ENABLE_LIBC_WASI 0 #endif +#ifndef WASM_ENABLE_UVWASI +#define WASM_ENABLE_UVWASI 0 +#endif + /* Default disable libc emcc */ #ifndef WASM_ENABLE_LIBC_EMCC #define WASM_ENABLE_LIBC_EMCC 0 diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index ceddc1d86..5a72bac7a 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -1656,6 +1656,7 @@ wasm_runtime_set_wasi_args(WASMModuleCommon *module, } } +#if WASM_ENABLE_UVWASI == 0 bool wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, const char *dir_list[], uint32 dir_count, @@ -1848,6 +1849,128 @@ fail: wasm_runtime_free(env_list); return false; } +#else /* else of WASM_ENABLE_UVWASI == 0 */ +static void * +wasm_uvwasi_malloc(size_t size, void *mem_user_data) +{ + return runtime_malloc(size, NULL, NULL, 0); + (void)mem_user_data; +} + +static void +wasm_uvwasi_free(void *ptr, void *mem_user_data) +{ + if (ptr) + wasm_runtime_free(ptr); + (void)mem_user_data; +} + +static void * +wasm_uvwasi_calloc(size_t nmemb, size_t size, + void *mem_user_data) +{ + uint64 total_size = (uint64)nmemb * size; + return runtime_malloc(total_size, NULL, NULL, 0); + (void)mem_user_data; +} + +static void * +wasm_uvwasi_realloc(void *ptr, size_t size, + void *mem_user_data) +{ + if (size >= UINT32_MAX) { + return NULL; + } + return wasm_runtime_realloc(ptr, (uint32)size); +} + +static uvwasi_mem_t uvwasi_allocator = { + .mem_user_data = 0, + .malloc = wasm_uvwasi_malloc, + .free = wasm_uvwasi_free, + .calloc = wasm_uvwasi_calloc, + .realloc = wasm_uvwasi_realloc +}; + +bool +wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, + const char *dir_list[], uint32 dir_count, + const char *map_dir_list[], uint32 map_dir_count, + const char *env[], uint32 env_count, + char *argv[], uint32 argc, + char *error_buf, uint32 error_buf_size) +{ + uvwasi_t *uvwasi = NULL; + uvwasi_options_t init_options; + const char **envp = NULL; + uint64 total_size; + uint32 i; + bool ret = false; + + uvwasi = runtime_malloc(sizeof(uvwasi_t), module_inst, + error_buf, error_buf_size); + if (!uvwasi) + return false; + + /* Setup the initialization options */ + uvwasi_options_init(&init_options); + init_options.allocator = &uvwasi_allocator; + init_options.argc = argc; + init_options.argv = (const char **)argv; + + if (dir_count > 0) { + init_options.preopenc = dir_count; + + total_size = sizeof(uvwasi_preopen_t) * (uint64)init_options.preopenc; + init_options.preopens = + (uvwasi_preopen_t *)runtime_malloc(total_size, module_inst, + error_buf, error_buf_size); + if (init_options.preopens == NULL) + goto fail; + + for (i = 0; i < init_options.preopenc; i++) { + init_options.preopens[i].real_path = dir_list[i]; + init_options.preopens[i].mapped_path = + (i < map_dir_count) ? map_dir_list[i] : dir_list[i]; + } + } + + if (env_count > 0) { + total_size = sizeof(char *) * (uint64)(env_count + 1); + envp = runtime_malloc(total_size, module_inst, + error_buf, error_buf_size); + if (envp == NULL) + goto fail; + + for (i = 0; i < env_count; i++) { + envp[i] = env[i]; + } + envp[env_count] = NULL; + init_options.envp = envp; + } + + if (UVWASI_ESUCCESS != uvwasi_init(uvwasi, &init_options)) { + set_error_buf(error_buf, error_buf_size, "uvwasi init failed"); + goto fail; + } + + wasm_runtime_set_wasi_ctx(module_inst, uvwasi); + + ret = true; + +fail: + if (envp) + wasm_runtime_free(envp); + + if (init_options.preopens) + wasm_runtime_free(init_options.preopens); + + if (!ret && uvwasi) + wasm_runtime_free(uvwasi); + + return ret; +} +#endif /* end of WASM_ENABLE_UVWASI */ bool wasm_runtime_is_wasi_mode(WASMModuleInstanceCommon *module_inst) @@ -1915,6 +2038,7 @@ wasm_runtime_lookup_wasi_start_function(WASMModuleInstanceCommon *module_inst) return NULL; } +#if WASM_ENABLE_UVWASI == 0 void wasm_runtime_destroy_wasi(WASMModuleInstanceCommon *module_inst) { @@ -1944,6 +2068,18 @@ wasm_runtime_destroy_wasi(WASMModuleInstanceCommon *module_inst) wasm_runtime_free(wasi_ctx); } } +#else +void +wasm_runtime_destroy_wasi(WASMModuleInstanceCommon *module_inst) +{ + WASIContext *wasi_ctx = wasm_runtime_get_wasi_ctx(module_inst); + + if (wasi_ctx) { + uvwasi_destroy(wasi_ctx); + wasm_runtime_free(wasi_ctx); + } +} +#endif WASIContext * wasm_runtime_get_wasi_ctx(WASMModuleInstanceCommon *module_inst) diff --git a/core/iwasm/common/wasm_runtime_common.h b/core/iwasm/common/wasm_runtime_common.h index 8a0fef0ba..3baa101b4 100644 --- a/core/iwasm/common/wasm_runtime_common.h +++ b/core/iwasm/common/wasm_runtime_common.h @@ -13,8 +13,12 @@ #include "../include/wasm_export.h" #include "../interpreter/wasm.h" #if WASM_ENABLE_LIBC_WASI != 0 +#if WASM_ENABLE_UVWASI == 0 #include "wasmtime_ssp.h" #include "posix.h" +#else +#include "uvwasi.h" +#endif #endif #ifdef __cplusplus @@ -73,6 +77,7 @@ typedef struct WASMModuleInstMemConsumption { } WASMModuleInstMemConsumption; #if WASM_ENABLE_LIBC_WASI != 0 +#if WASM_ENABLE_UVWASI == 0 typedef struct WASIContext { struct fd_table *curfds; struct fd_prestats *prestats; @@ -82,6 +87,9 @@ typedef struct WASIContext { char *env_buf; char **env_list; } WASIContext; +#else +typedef uvwasi_t WASIContext; +#endif #endif #if WASM_ENABLE_MULTI_MODULE != 0 diff --git a/core/iwasm/libraries/libc-uvwasi/libc_uvwasi.cmake b/core/iwasm/libraries/libc-uvwasi/libc_uvwasi.cmake new file mode 100644 index 000000000..262bc610c --- /dev/null +++ b/core/iwasm/libraries/libc-uvwasi/libc_uvwasi.cmake @@ -0,0 +1,30 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +set (LIBC_WASI_DIR ${CMAKE_CURRENT_LIST_DIR}) +set (UVWASI_DIR ${CMAKE_CURRENT_LIST_DIR}/../../../deps/uvwasi) +set (LIBUV_VERSION v1.39.0) + +add_definitions (-DWASM_ENABLE_LIBC_WASI=1 -DWASM_ENABLE_UVWASI=1) + +include(FetchContent) +## https://libuv.org +FetchContent_Declare( + libuv + GIT_REPOSITORY https://github.com/libuv/libuv.git + GIT_TAG ${LIBUV_VERSION}) + +FetchContent_GetProperties(libuv) +if(NOT libuv_POPULATED) + message ("-- Fetching libuv ..") + FetchContent_Populate(libuv) + include_directories("${libuv_SOURCE_DIR}/include") + add_subdirectory(${libuv_SOURCE_DIR} ${libuv_BINARY_DIR} EXCLUDE_FROM_ALL) + set (UV_A_LIBS uv_a) +endif() + +include_directories(${UVWASI_DIR}/include) + +file (GLOB_RECURSE source_all ${LIBC_WASI_DIR}/*.c ${UVWASI_DIR}/src/*.c) + +set (LIBC_WASI_SOURCE ${source_all}) diff --git a/core/iwasm/libraries/libc-uvwasi/libc_uvwasi_wrapper.c b/core/iwasm/libraries/libc-uvwasi/libc_uvwasi_wrapper.c new file mode 100644 index 000000000..1263b0dc4 --- /dev/null +++ b/core/iwasm/libraries/libc-uvwasi/libc_uvwasi_wrapper.c @@ -0,0 +1,1168 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "uvwasi.h" +#include "bh_platform.h" +#include "wasm_export.h" + +#define get_module_inst(exec_env) \ + wasm_runtime_get_module_inst(exec_env) + +#define get_wasi_ctx(module_inst) \ + wasm_runtime_get_wasi_ctx(module_inst) + +#define validate_app_addr(offset, size) \ + wasm_runtime_validate_app_addr(module_inst, offset, size) + +#define validate_native_addr(addr, size) \ + wasm_runtime_validate_native_addr(module_inst, addr, size) + +#define addr_app_to_native(offset) \ + wasm_runtime_addr_app_to_native(module_inst, offset) + +#define addr_native_to_app(ptr) \ + wasm_runtime_addr_native_to_app(module_inst, ptr) + +#define module_malloc(size, p_native_addr) \ + wasm_runtime_module_malloc(module_inst, size, p_native_addr) + +#define module_free(offset) \ + wasm_runtime_module_free(module_inst, offset) + +#define wasi_errno_t uvwasi_errno_t +#define wasi_fd_t uvwasi_fd_t +#define wasi_clockid_t uvwasi_clockid_t +#define wasi_timestamp_t uvwasi_timestamp_t +#define wasi_filesize_t uvwasi_filesize_t +#define wasi_prestat_app_t uvwasi_prestat_app_t +#define wasi_filedelta_t uvwasi_filedelta_t +#define wasi_whence_t uvwasi_whence_t +#define wasi_fdflags_t uvwasi_fdflags_t +#define wasi_rights_t uvwasi_rights_t +#define wasi_advice_t uvwasi_advice_t +#define wasi_lookupflags_t uvwasi_lookupflags_t +#define wasi_preopentype_t uvwasi_preopentype_t +#define wasi_fdstat_t uvwasi_fdstat_t +#define wasi_oflags_t uvwasi_oflags_t +#define wasi_dircookie_t uvwasi_dircookie_t +#define wasi_filestat_t uvwasi_filestat_t +#define wasi_fstflags_t uvwasi_fstflags_t +#define wasi_subscription_t uvwasi_subscription_t +#define wasi_event_t uvwasi_event_t +#define wasi_exitcode_t uvwasi_exitcode_t +#define wasi_signal_t uvwasi_signal_t +#define wasi_riflags_t uvwasi_riflags_t +#define wasi_roflags_t uvwasi_roflags_t +#define wasi_siflags_t uvwasi_siflags_t +#define wasi_sdflags_t uvwasi_sdflags_t +#define wasi_iovec_t uvwasi_iovec_t +#define wasi_ciovec_t uvwasi_ciovec_t + +typedef struct wasi_prestat_app { + wasi_preopentype_t pr_type; + uint32 pr_name_len; +} wasi_prestat_app_t; + +typedef struct iovec_app { + uint32 buf_offset; + uint32 buf_len; +} iovec_app_t; + +void * +wasm_runtime_get_wasi_ctx(wasm_module_inst_t module_inst); + +static wasi_errno_t +wasi_args_get(wasm_exec_env_t exec_env, uint32 *argv_offsets, char *argv_buf) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + uvwasi_size_t argc, argv_buf_size, i; + char **argv; + uint64 total_size; + wasi_errno_t err; + + if (!uvwasi) + return (wasi_errno_t)-1; + + err = uvwasi_args_sizes_get(uvwasi, &argc, &argv_buf_size); + if (err) + return err; + + total_size = sizeof(int32) * ((uint64)argc + 1); + if (total_size >= UINT32_MAX + || !validate_native_addr(argv_offsets, (uint32)total_size) + || argv_buf_size >= UINT32_MAX + || !validate_native_addr(argv_buf, (uint32)argv_buf_size)) + return (wasi_errno_t)-1; + + total_size = sizeof(char *) * ((uint64)argc + 1); + if (total_size >= UINT32_MAX + || !(argv = wasm_runtime_malloc((uint32)total_size))) + return (wasi_errno_t)-1; + + err = uvwasi_args_get(uvwasi, argv, argv_buf); + if (err) { + wasm_runtime_free(argv); + return err; + } + + for (i = 0; i < argc; i++) + argv_offsets[i] = addr_native_to_app(argv[i]); + argv_offsets[argc] = 0; + + wasm_runtime_free(argv); + return 0; +} + +static wasi_errno_t +wasi_args_sizes_get(wasm_exec_env_t exec_env, + uint32 *argc_app, uint32 *argv_buf_size_app) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + uvwasi_size_t argc, argv_buf_size; + wasi_errno_t err; + + if (!uvwasi) + return (wasi_errno_t)-1; + + if (!validate_native_addr(argc_app, sizeof(uint32)) + || !validate_native_addr(argv_buf_size_app, sizeof(uint32))) + return (wasi_errno_t)-1; + + + err = uvwasi_args_sizes_get(uvwasi, &argc, &argv_buf_size); + if (err) + return err; + + *argc_app = (uint32)argc; + *argv_buf_size_app = (uint32)argv_buf_size; + return 0; +} + +static wasi_errno_t +wasi_clock_res_get(wasm_exec_env_t exec_env, + wasi_clockid_t clock_id, + wasi_timestamp_t *resolution) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + + if (!validate_native_addr(resolution, sizeof(wasi_timestamp_t))) + return (wasi_errno_t)-1; + + return uvwasi_clock_res_get(uvwasi, clock_id, resolution); +} + +static wasi_errno_t +wasi_clock_time_get(wasm_exec_env_t exec_env, + wasi_clockid_t clock_id, + wasi_timestamp_t precision, + wasi_timestamp_t *time) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + + if (!validate_native_addr(time, sizeof(wasi_timestamp_t))) + return (wasi_errno_t)-1; + + return uvwasi_clock_time_get(uvwasi, clock_id, precision, time); +} + +static wasi_errno_t +wasi_environ_get(wasm_exec_env_t exec_env, + uint32 *environ_offsets, char *environ_buf) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + uvwasi_size_t environ_count, environ_buf_size, i; + uint64 total_size; + char **environs; + wasi_errno_t err; + + if (!uvwasi) + return (wasi_errno_t)-1; + + err = uvwasi_environ_sizes_get(uvwasi, &environ_count, &environ_buf_size); + if (err) + return err; + + total_size = sizeof(int32) * ((uint64)environ_count + 1); + if (total_size >= UINT32_MAX + || !validate_native_addr(environ_offsets, (uint32)total_size) + || environ_buf_size >= UINT32_MAX + || !validate_native_addr(environ_buf, (uint32)environ_buf_size)) + return (wasi_errno_t)-1; + + total_size = sizeof(char *) * (((uint64)environ_count + 1)); + + if (total_size >= UINT32_MAX + || !(environs = wasm_runtime_malloc((uint32)total_size))) + return (wasi_errno_t)-1; + + err = uvwasi_environ_get(uvwasi, environs, environ_buf); + if (err) { + wasm_runtime_free(environs); + return err; + } + + for (i = 0; i < environ_count; i++) + environ_offsets[i] = addr_native_to_app(environs[i]); + environ_offsets[environ_count] = 0; + + wasm_runtime_free(environs); + return 0; +} + +static wasi_errno_t +wasi_environ_sizes_get(wasm_exec_env_t exec_env, + uint32 *environ_count_app, uint32 *environ_buf_size_app) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + uvwasi_size_t environ_count, environ_buf_size; + wasi_errno_t err; + + if (!uvwasi) + return (wasi_errno_t)-1; + + if (!validate_native_addr(environ_count_app, sizeof(uint32)) + || !validate_native_addr(environ_buf_size_app, sizeof(uint32))) + return (wasi_errno_t)-1; + + err = uvwasi_environ_sizes_get(uvwasi, &environ_count, &environ_buf_size); + if (err) + return err; + + *environ_count_app = (uint32)environ_count; + *environ_buf_size_app = (uint32)environ_buf_size; + return 0; +} + +static wasi_errno_t +wasi_fd_prestat_get(wasm_exec_env_t exec_env, + wasi_fd_t fd, wasi_prestat_app_t *prestat_app) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + uvwasi_prestat_t prestat; + wasi_errno_t err; + + if (!uvwasi) + return (wasi_errno_t)-1; + + if (!validate_native_addr(prestat_app, sizeof(wasi_prestat_app_t))) + return (wasi_errno_t)-1; + + err = uvwasi_fd_prestat_get(uvwasi, fd, &prestat); + if (err) + return err; + + prestat_app->pr_type = prestat.pr_type; + prestat_app->pr_name_len = (uint32)prestat.u.dir.pr_name_len; + return 0; +} + +static wasi_errno_t +wasi_fd_prestat_dir_name(wasm_exec_env_t exec_env, + wasi_fd_t fd, char *path, uint32 path_len) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + + if (!uvwasi) + return (wasi_errno_t)-1; + + return uvwasi_fd_prestat_dir_name(uvwasi, fd, path, path_len); +} + +static wasi_errno_t +wasi_fd_close(wasm_exec_env_t exec_env, wasi_fd_t fd) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + + if (!uvwasi) + return (wasi_errno_t)-1; + + return uvwasi_fd_close(uvwasi, fd); +} + +static wasi_errno_t +wasi_fd_datasync(wasm_exec_env_t exec_env, wasi_fd_t fd) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + + if (!uvwasi) + return (wasi_errno_t)-1; + + return uvwasi_fd_datasync(uvwasi, fd); +} + +static wasi_errno_t +wasi_fd_pread(wasm_exec_env_t exec_env, + wasi_fd_t fd, iovec_app_t *iovec_app, uint32 iovs_len, + wasi_filesize_t offset, uint32 *nread_app) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + wasi_iovec_t *iovec, *iovec_begin; + uint64 total_size; + uvwasi_size_t nread; + uint32 i; + wasi_errno_t err; + + if (!uvwasi) + return (wasi_errno_t)-1; + + total_size = sizeof(iovec_app_t) * (uint64)iovs_len; + if (!validate_native_addr(nread_app, (uint32)sizeof(uint32)) + || total_size >= UINT32_MAX + || !validate_native_addr(iovec_app, (uint32)total_size)) + return (wasi_errno_t)-1; + + total_size = sizeof(wasi_iovec_t) * (uint64)iovs_len; + if (total_size >= UINT32_MAX + || !(iovec_begin = wasm_runtime_malloc((uint32)total_size))) + return (wasi_errno_t)-1; + + iovec = iovec_begin; + for (i = 0; i < iovs_len; i++, iovec_app++, iovec++) { + if (!validate_app_addr(iovec_app->buf_offset, iovec_app->buf_len)) { + err = (wasi_errno_t)-1; + goto fail; + } + iovec->buf = (void*)addr_app_to_native(iovec_app->buf_offset); + iovec->buf_len = iovec_app->buf_len; + } + + err = uvwasi_fd_pread(uvwasi, fd, iovec_begin, + iovs_len, offset, &nread); + if (err) + goto fail; + + *nread_app = (uint32)nread; + + /* success */ + err = 0; + +fail: + wasm_runtime_free(iovec_begin); + return err; +} + +static wasi_errno_t +wasi_fd_pwrite(wasm_exec_env_t exec_env, + wasi_fd_t fd, const iovec_app_t *iovec_app, uint32 iovs_len, + wasi_filesize_t offset, uint32 *nwritten_app) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + wasi_ciovec_t *ciovec, *ciovec_begin; + uint64 total_size; + uvwasi_size_t nwritten; + uint32 i; + wasi_errno_t err; + + if (!uvwasi) + return (wasi_errno_t)-1; + + total_size = sizeof(iovec_app_t) * (uint64)iovs_len; + if (!validate_native_addr(nwritten_app, (uint32)sizeof(uint32)) + || total_size >= UINT32_MAX + || !validate_native_addr((void*)iovec_app, (uint32)total_size)) + return (wasi_errno_t)-1; + + total_size = sizeof(wasi_ciovec_t) * (uint64)iovs_len; + if (total_size >= UINT32_MAX + || !(ciovec_begin = wasm_runtime_malloc((uint32)total_size))) + return (wasi_errno_t)-1; + + ciovec = ciovec_begin; + for (i = 0; i < iovs_len; i++, iovec_app++, ciovec++) { + if (!validate_app_addr(iovec_app->buf_offset, iovec_app->buf_len)) { + err = (wasi_errno_t)-1; + goto fail; + } + ciovec->buf = (char*)addr_app_to_native(iovec_app->buf_offset); + ciovec->buf_len = iovec_app->buf_len; + } + + err = uvwasi_fd_pwrite(uvwasi, fd, ciovec_begin, + iovs_len, offset, &nwritten); + if (err) + goto fail; + + *nwritten_app = (uint32)nwritten; + + /* success */ + err = 0; + +fail: + wasm_runtime_free(ciovec_begin); + return err; +} + +static wasi_errno_t +wasi_fd_read(wasm_exec_env_t exec_env, + wasi_fd_t fd, const iovec_app_t *iovec_app, uint32 iovs_len, + uint32 *nread_app) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + wasi_iovec_t *iovec, *iovec_begin; + uint64 total_size; + uvwasi_size_t nread; + uint32 i; + wasi_errno_t err; + + if (!uvwasi) + return (wasi_errno_t)-1; + + total_size = sizeof(iovec_app_t) * (uint64)iovs_len; + if (!validate_native_addr(nread_app, (uint32)sizeof(uint32)) + || total_size >= UINT32_MAX + || !validate_native_addr((void*)iovec_app, (uint32)total_size)) + return (wasi_errno_t)-1; + + total_size = sizeof(wasi_iovec_t) * (uint64)iovs_len; + if (total_size >= UINT32_MAX + || !(iovec_begin = wasm_runtime_malloc((uint32)total_size))) + return (wasi_errno_t)-1; + + iovec = iovec_begin; + for (i = 0; i < iovs_len; i++, iovec_app++, iovec++) { + if (!validate_app_addr(iovec_app->buf_offset, iovec_app->buf_len)) { + err = (wasi_errno_t)-1; + goto fail; + } + iovec->buf = (void*)addr_app_to_native(iovec_app->buf_offset); + iovec->buf_len = iovec_app->buf_len; + } + + err = uvwasi_fd_read(uvwasi, fd, + iovec_begin, iovs_len, &nread); + if (err) + goto fail; + + *nread_app = (uint32)nread; + + /* success */ + err = 0; + +fail: + wasm_runtime_free(iovec_begin); + return err; +} + +static wasi_errno_t +wasi_fd_renumber(wasm_exec_env_t exec_env, wasi_fd_t from, wasi_fd_t to) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + + if (!uvwasi) + return (wasi_errno_t)-1; + + return uvwasi_fd_renumber(uvwasi, from, to); +} + +static wasi_errno_t +wasi_fd_seek(wasm_exec_env_t exec_env, + wasi_fd_t fd, wasi_filedelta_t offset, wasi_whence_t whence, + wasi_filesize_t *newoffset) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + + if (!uvwasi) + return (wasi_errno_t)-1; + + if (!validate_native_addr(newoffset, sizeof(wasi_filesize_t))) + return (wasi_errno_t)-1; + + return uvwasi_fd_seek(uvwasi, fd, offset, whence, newoffset); +} + +static wasi_errno_t +wasi_fd_tell(wasm_exec_env_t exec_env, + wasi_fd_t fd, wasi_filesize_t *newoffset) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + + if (!uvwasi) + return (wasi_errno_t)-1; + + if (!validate_native_addr(newoffset, sizeof(wasi_filesize_t))) + return (wasi_errno_t)-1; + + return uvwasi_fd_tell(uvwasi, fd, newoffset); +} + +static wasi_errno_t +wasi_fd_fdstat_get(wasm_exec_env_t exec_env, + wasi_fd_t fd, wasi_fdstat_t *fdstat_app) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + wasi_fdstat_t fdstat; + wasi_errno_t err; + + if (!uvwasi) + return (wasi_errno_t)-1; + + if (!validate_native_addr(fdstat_app, sizeof(wasi_fdstat_t))) + return (wasi_errno_t)-1; + + err = uvwasi_fd_fdstat_get(uvwasi, fd, &fdstat); + if (err) + return err; + + memcpy(fdstat_app, &fdstat, sizeof(wasi_fdstat_t)); + return 0; +} + +static wasi_errno_t +wasi_fd_fdstat_set_flags(wasm_exec_env_t exec_env, + wasi_fd_t fd, wasi_fdflags_t flags) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + + if (!uvwasi) + return (wasi_errno_t)-1; + + return uvwasi_fd_fdstat_set_flags(uvwasi, fd, flags); +} + +static wasi_errno_t +wasi_fd_fdstat_set_rights(wasm_exec_env_t exec_env, + wasi_fd_t fd, + wasi_rights_t fs_rights_base, + wasi_rights_t fs_rights_inheriting) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + + if (!uvwasi) + return (wasi_errno_t)-1; + + return uvwasi_fd_fdstat_set_rights(uvwasi, fd, + fs_rights_base, fs_rights_inheriting); +} + +static wasi_errno_t +wasi_fd_sync(wasm_exec_env_t exec_env, wasi_fd_t fd) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + + if (!uvwasi) + return (wasi_errno_t)-1; + + return uvwasi_fd_sync(uvwasi, fd); +} + +static wasi_errno_t +wasi_fd_write(wasm_exec_env_t exec_env, wasi_fd_t fd, + const iovec_app_t *iovec_app, uint32 iovs_len, + uint32 *nwritten_app) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + wasi_ciovec_t *ciovec, *ciovec_begin; + uint64 total_size; + uvwasi_size_t nwritten; + uint32 i; + wasi_errno_t err; + + if (!uvwasi) + return (wasi_errno_t)-1; + + total_size = sizeof(iovec_app_t) * (uint64)iovs_len; + if (!validate_native_addr(nwritten_app, (uint32)sizeof(uint32)) + || total_size >= UINT32_MAX + || !validate_native_addr((void*)iovec_app, (uint32)total_size)) + return (wasi_errno_t)-1; + + total_size = sizeof(wasi_ciovec_t) * (uint64)iovs_len; + if (total_size >= UINT32_MAX + || !(ciovec_begin = wasm_runtime_malloc((uint32)total_size))) + return (wasi_errno_t)-1; + + ciovec = ciovec_begin; + for (i = 0; i < iovs_len; i++, iovec_app++, ciovec++) { + if (!validate_app_addr(iovec_app->buf_offset, iovec_app->buf_len)) { + err = (wasi_errno_t)-1; + goto fail; + } + ciovec->buf = (char*)addr_app_to_native(iovec_app->buf_offset); + ciovec->buf_len = iovec_app->buf_len; + } + + err = uvwasi_fd_write(uvwasi, fd, + ciovec_begin, iovs_len, &nwritten); + if (err) + goto fail; + + *nwritten_app = (uint32)nwritten; + + /* success */ + err = 0; + +fail: + wasm_runtime_free(ciovec_begin); + return err; +} + +static wasi_errno_t +wasi_fd_advise(wasm_exec_env_t exec_env, + wasi_fd_t fd, + wasi_filesize_t offset, + wasi_filesize_t len, + wasi_advice_t advice) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + + if (!uvwasi) + return (wasi_errno_t)-1; + + return uvwasi_fd_advise(uvwasi, fd, offset, len, advice); +} + +static wasi_errno_t +wasi_fd_allocate(wasm_exec_env_t exec_env, + wasi_fd_t fd, + wasi_filesize_t offset, + wasi_filesize_t len) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + + if (!uvwasi) + return (wasi_errno_t)-1; + + return uvwasi_fd_allocate(uvwasi, fd, offset, len); +} + +static wasi_errno_t +wasi_path_create_directory(wasm_exec_env_t exec_env, + wasi_fd_t fd, const char *path, uint32 path_len) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + + if (!uvwasi) + return (wasi_errno_t)-1; + + return uvwasi_path_create_directory(uvwasi, fd, path, path_len); +} + +static wasi_errno_t +wasi_path_link(wasm_exec_env_t exec_env, + wasi_fd_t old_fd, + wasi_lookupflags_t old_flags, + const char *old_path, uint32 old_path_len, + wasi_fd_t new_fd, + const char *new_path, uint32 new_path_len) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + + if (!uvwasi) + return (wasi_errno_t)-1; + + return uvwasi_path_link(uvwasi, + old_fd, old_flags, old_path, old_path_len, + new_fd, new_path, new_path_len); +} + +static wasi_errno_t +wasi_path_open(wasm_exec_env_t exec_env, + wasi_fd_t dirfd, + wasi_lookupflags_t dirflags, + const char *path, uint32 path_len, + wasi_oflags_t oflags, + wasi_rights_t fs_rights_base, + wasi_rights_t fs_rights_inheriting, + wasi_fdflags_t fs_flags, + wasi_fd_t *fd_app) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + wasi_fd_t fd = (wasi_fd_t)-1; /* set fd_app -1 if path open failed */ + wasi_errno_t err; + + if (!uvwasi) + return (wasi_errno_t)-1; + + if (!validate_native_addr(fd_app, sizeof(wasi_fd_t))) + return (wasi_errno_t)-1; + + err = uvwasi_path_open(uvwasi, + dirfd, dirflags, + path, path_len, + oflags, + fs_rights_base, + fs_rights_inheriting, + fs_flags, + &fd); + + *fd_app = fd; + return err; +} + +static wasi_errno_t +wasi_fd_readdir(wasm_exec_env_t exec_env, + wasi_fd_t fd, + void *buf, uint32 buf_len, + wasi_dircookie_t cookie, + uint32 *bufused_app) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + uvwasi_size_t bufused; + wasi_errno_t err; + + if (!uvwasi) + return (wasi_errno_t)-1; + + if (!validate_native_addr(bufused_app, sizeof(uint32))) + return (wasi_errno_t)-1; + + err = uvwasi_fd_readdir(uvwasi, fd, + buf, buf_len, cookie, &bufused); + if (err) + return err; + + *bufused_app = (uint32)bufused; + return 0; +} + +static wasi_errno_t +wasi_path_readlink(wasm_exec_env_t exec_env, + wasi_fd_t fd, + const char *path, uint32 path_len, + char *buf, uint32 buf_len, + uint32 *bufused_app) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + uvwasi_size_t bufused; + wasi_errno_t err; + + if (!uvwasi) + return (wasi_errno_t)-1; + + if (!validate_native_addr(bufused_app, sizeof(uint32))) + return (wasi_errno_t)-1; + + err = uvwasi_path_readlink(uvwasi, fd, + path, path_len, + buf, buf_len, &bufused); + if (err) + return err; + + *bufused_app = (uint32)bufused; + return 0; +} + +static wasi_errno_t +wasi_path_rename(wasm_exec_env_t exec_env, + wasi_fd_t old_fd, const char *old_path, uint32 old_path_len, + wasi_fd_t new_fd, const char *new_path, uint32 new_path_len) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + + if (!uvwasi) + return (wasi_errno_t)-1; + + return uvwasi_path_rename(uvwasi, + old_fd, old_path, old_path_len, + new_fd, new_path, new_path_len); +} + +static wasi_errno_t +wasi_fd_filestat_get(wasm_exec_env_t exec_env, + wasi_fd_t fd, wasi_filestat_t *filestat) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + + if (!uvwasi) + return (wasi_errno_t)-1; + + if (!validate_native_addr(filestat, sizeof(wasi_filestat_t))) + return (wasi_errno_t)-1; + + return uvwasi_fd_filestat_get(uvwasi, fd, filestat); +} + +static wasi_errno_t +wasi_fd_filestat_set_times(wasm_exec_env_t exec_env, + wasi_fd_t fd, + wasi_timestamp_t st_atim, + wasi_timestamp_t st_mtim, + wasi_fstflags_t fstflags) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + + if (!uvwasi) + return (wasi_errno_t)-1; + + return uvwasi_fd_filestat_set_times(uvwasi, fd, + st_atim, st_mtim, fstflags); +} + +static wasi_errno_t +wasi_fd_filestat_set_size(wasm_exec_env_t exec_env, + wasi_fd_t fd, + wasi_filesize_t st_size) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + + if (!uvwasi) + return (wasi_errno_t)-1; + + return uvwasi_fd_filestat_set_size(uvwasi, fd, st_size); +} + +static wasi_errno_t +wasi_path_filestat_get(wasm_exec_env_t exec_env, + wasi_fd_t fd, + wasi_lookupflags_t flags, + const char *path, uint32 path_len, + wasi_filestat_t *filestat) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + + if (!uvwasi) + return (wasi_errno_t)-1; + + if (!validate_native_addr(filestat, sizeof(wasi_filestat_t))) + return (wasi_errno_t)-1; + + return uvwasi_path_filestat_get(uvwasi, fd, + flags, path, path_len, filestat); +} + +static wasi_errno_t +wasi_path_filestat_set_times(wasm_exec_env_t exec_env, + wasi_fd_t fd, + wasi_lookupflags_t flags, + const char *path, uint32 path_len, + wasi_timestamp_t st_atim, + wasi_timestamp_t st_mtim, + wasi_fstflags_t fstflags) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + + if (!uvwasi) + return (wasi_errno_t)-1; + + return uvwasi_path_filestat_set_times(uvwasi, fd, + flags, path, path_len, + st_atim, st_mtim, fstflags); +} + +static wasi_errno_t +wasi_path_symlink(wasm_exec_env_t exec_env, + const char *old_path, uint32 old_path_len, + wasi_fd_t fd, const char *new_path, uint32 new_path_len) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + + if (!uvwasi) + return (wasi_errno_t)-1; + + return uvwasi_path_symlink(uvwasi, + old_path, old_path_len, fd, + new_path, new_path_len); +} + +static wasi_errno_t +wasi_path_unlink_file(wasm_exec_env_t exec_env, + wasi_fd_t fd, const char *path, uint32 path_len) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + + if (!uvwasi) + return (wasi_errno_t)-1; + + return uvwasi_path_unlink_file(uvwasi, fd, path, path_len); +} + +static wasi_errno_t +wasi_path_remove_directory(wasm_exec_env_t exec_env, + wasi_fd_t fd, const char *path, uint32 path_len) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + + if (!uvwasi) + return (wasi_errno_t)-1; + + return uvwasi_path_remove_directory(uvwasi, fd, path, path_len); +} + +static wasi_errno_t +wasi_poll_oneoff(wasm_exec_env_t exec_env, + const wasi_subscription_t *in, wasi_event_t *out, + uint32 nsubscriptions, uint32 *nevents_app) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + uvwasi_size_t nevents; + wasi_errno_t err; + + if (!uvwasi) + return (wasi_errno_t)-1; + + if (!validate_native_addr((void*)in, sizeof(wasi_subscription_t)) + || !validate_native_addr(out, sizeof(wasi_event_t)) + || !validate_native_addr(nevents_app, sizeof(uint32))) + return (wasi_errno_t)-1; + + err = uvwasi_poll_oneoff(uvwasi, in, out, + nsubscriptions, &nevents); + if (err) + return err; + + *nevents_app = (uint32)nevents; + return 0; +} + +static void +wasi_proc_exit(wasm_exec_env_t exec_env, wasi_exitcode_t rval) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + /* Here throwing exception is just to let wasm app exit, + the upper layer should clear the exception and return + as normal */ + wasm_runtime_set_exception(module_inst, "wasi proc exit"); +} + +static wasi_errno_t +wasi_proc_raise(wasm_exec_env_t exec_env, wasi_signal_t sig) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + char buf[32]; + + snprintf(buf, sizeof(buf), "%s%d", "wasi proc raise ", sig); + wasm_runtime_set_exception(module_inst, buf); + return 0; +} + +static wasi_errno_t +wasi_random_get(wasm_exec_env_t exec_env, void *buf, uint32 buf_len) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + return uvwasi_random_get(uvwasi, buf, buf_len); +} + +static wasi_errno_t +wasi_sock_recv(wasm_exec_env_t exec_env, + wasi_fd_t sock, + iovec_app_t *ri_data, uint32 ri_data_len, + wasi_riflags_t ri_flags, + uint32 *ro_datalen_app, + wasi_roflags_t *ro_flags) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + wasi_iovec_t *iovec, *iovec_begin; + uint64 total_size; + uvwasi_size_t ro_datalen; + uint32 i; + wasi_errno_t err; + + if (!uvwasi) + return (wasi_errno_t)-1; + + total_size = sizeof(iovec_app_t) * (uint64)ri_data_len; + if (!validate_native_addr(ro_datalen_app, (uint32)sizeof(uint32)) + || !validate_native_addr(ro_flags, (uint32)sizeof(wasi_roflags_t)) + || total_size >= UINT32_MAX + || !validate_native_addr(ri_data, (uint32)total_size)) + return (wasi_errno_t)-1; + + total_size = sizeof(wasi_iovec_t) * (uint64)ri_data_len; + if (total_size >= UINT32_MAX + || !(iovec_begin = wasm_runtime_malloc((uint32)total_size))) + return (wasi_errno_t)-1; + + iovec = iovec_begin; + for (i = 0; i < ri_data_len; i++, ri_data++, iovec++) { + if (!validate_app_addr(ri_data->buf_offset, ri_data->buf_len)) { + err = (wasi_errno_t)-1; + goto fail; + } + iovec->buf = (void*)addr_app_to_native(ri_data->buf_offset); + iovec->buf_len = ri_data->buf_len; + } + + err = uvwasi_sock_recv(uvwasi, sock, + iovec_begin, ri_data_len, + ri_flags, &ro_datalen, + ro_flags); + if (err) + goto fail; + + *(uint32*)ro_datalen_app = (uint32)ro_datalen; + + /* success */ + err = 0; + +fail: + wasm_runtime_free(iovec_begin); + return err; +} + +static wasi_errno_t +wasi_sock_send(wasm_exec_env_t exec_env, + wasi_fd_t sock, + const iovec_app_t *si_data, uint32 si_data_len, + wasi_siflags_t si_flags, + uint32 *so_datalen_app) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + wasi_ciovec_t *ciovec, *ciovec_begin; + uint64 total_size; + uvwasi_size_t so_datalen; + uint32 i; + wasi_errno_t err; + + if (!uvwasi) + return (wasi_errno_t)-1; + + total_size = sizeof(iovec_app_t) * (uint64)si_data_len; + if (!validate_native_addr(so_datalen_app, sizeof(uint32)) + || total_size >= UINT32_MAX + || !validate_native_addr((void*)si_data, (uint32)total_size)) + return (wasi_errno_t)-1; + + total_size = sizeof(wasi_ciovec_t) * (uint64)si_data_len; + if (total_size >= UINT32_MAX + || !(ciovec_begin = wasm_runtime_malloc((uint32)total_size))) + return (wasi_errno_t)-1; + + ciovec = ciovec_begin; + for (i = 0; i < si_data_len; i++, si_data++, ciovec++) { + if (!validate_app_addr(si_data->buf_offset, si_data->buf_len)) { + err = (wasi_errno_t)-1; + goto fail; + } + ciovec->buf = (char*)addr_app_to_native(si_data->buf_offset); + ciovec->buf_len = si_data->buf_len; + } + + err = uvwasi_sock_send(uvwasi, sock, + ciovec_begin, si_data_len, + si_flags, &so_datalen); + if (err) + goto fail; + + *so_datalen_app = (uint32)so_datalen; + + /* success */ + err = 0; + +fail: + wasm_runtime_free(ciovec_begin); + return err; +} + +static wasi_errno_t +wasi_sock_shutdown(wasm_exec_env_t exec_env, + wasi_fd_t sock, wasi_sdflags_t how) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + + if (!uvwasi) + return (wasi_errno_t)-1; + + return uvwasi_sock_shutdown(uvwasi, sock, how); +} + +static wasi_errno_t +wasi_sched_yield(wasm_exec_env_t exec_env) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + + return uvwasi_sched_yield(uvwasi); +} + +#define REG_NATIVE_FUNC(func_name, signature) \ + { #func_name, wasi_##func_name, signature, NULL } + +static NativeSymbol native_symbols_libc_wasi[] = { + REG_NATIVE_FUNC(args_get, "(**)i"), + REG_NATIVE_FUNC(args_sizes_get, "(**)i"), + REG_NATIVE_FUNC(clock_res_get, "(i*)i"), + REG_NATIVE_FUNC(clock_time_get, "(iI*)i"), + REG_NATIVE_FUNC(environ_get, "(**)i"), + REG_NATIVE_FUNC(environ_sizes_get, "(**)i"), + REG_NATIVE_FUNC(fd_prestat_get, "(i*)i"), + REG_NATIVE_FUNC(fd_prestat_dir_name, "(i*~)i"), + REG_NATIVE_FUNC(fd_close, "(i)i"), + REG_NATIVE_FUNC(fd_datasync, "(i)i"), + REG_NATIVE_FUNC(fd_pread, "(i*iI*)i"), + REG_NATIVE_FUNC(fd_pwrite, "(i*iI*)i"), + REG_NATIVE_FUNC(fd_read, "(i*i*)i"), + REG_NATIVE_FUNC(fd_renumber, "(ii)i"), + REG_NATIVE_FUNC(fd_seek, "(iIi*)i"), + REG_NATIVE_FUNC(fd_tell, "(i*)i"), + REG_NATIVE_FUNC(fd_fdstat_get, "(i*)i"), + REG_NATIVE_FUNC(fd_fdstat_set_flags, "(ii)i"), + REG_NATIVE_FUNC(fd_fdstat_set_rights, "(iII)i"), + REG_NATIVE_FUNC(fd_sync, "(i)i"), + REG_NATIVE_FUNC(fd_write, "(i*i*)i"), + REG_NATIVE_FUNC(fd_advise, "(iIIi)i"), + REG_NATIVE_FUNC(fd_allocate, "(iII)i"), + REG_NATIVE_FUNC(path_create_directory, "(i*~)i"), + REG_NATIVE_FUNC(path_link, "(ii*~i*~)i"), + REG_NATIVE_FUNC(path_open, "(ii*~iIIi*)i"), + REG_NATIVE_FUNC(fd_readdir, "(i*~I*)i"), + REG_NATIVE_FUNC(path_readlink, "(i*~*~*)i"), + REG_NATIVE_FUNC(path_rename, "(i*~i*~)i"), + REG_NATIVE_FUNC(fd_filestat_get, "(i*)i"), + REG_NATIVE_FUNC(fd_filestat_set_times, "(iIIi)i"), + REG_NATIVE_FUNC(fd_filestat_set_size, "(iI)i"), + REG_NATIVE_FUNC(path_filestat_get, "(ii*~*)i"), + REG_NATIVE_FUNC(path_filestat_set_times, "(ii*~IIi)i"), + REG_NATIVE_FUNC(path_symlink, "(*~i*~)i"), + REG_NATIVE_FUNC(path_unlink_file, "(i*~)i"), + REG_NATIVE_FUNC(path_remove_directory, "(i*~)i"), + REG_NATIVE_FUNC(poll_oneoff, "(**i*)i"), + REG_NATIVE_FUNC(proc_exit, "(i)"), + REG_NATIVE_FUNC(proc_raise, "(i)i"), + REG_NATIVE_FUNC(random_get, "(*~)i"), + REG_NATIVE_FUNC(sock_recv, "(i*ii**)i"), + REG_NATIVE_FUNC(sock_send, "(i*ii*)i"), + REG_NATIVE_FUNC(sock_shutdown, "(ii)i"), + REG_NATIVE_FUNC(sched_yield, "()i"), +}; + +uint32 +get_libc_wasi_export_apis(NativeSymbol **p_libc_wasi_apis) +{ + *p_libc_wasi_apis = native_symbols_libc_wasi; + return sizeof(native_symbols_libc_wasi) / sizeof(NativeSymbol); +} + diff --git a/core/shared/mem-alloc/ems/ems_alloc.c b/core/shared/mem-alloc/ems/ems_alloc.c index 956bae616..51b556924 100644 --- a/core/shared/mem-alloc/ems/ems_alloc.c +++ b/core/shared/mem-alloc/ems/ems_alloc.c @@ -472,6 +472,11 @@ gc_alloc_vo_internal(void *vheap, gc_size_t size, if (!hmu) goto finish; + bh_assert(hmu_get_size(hmu) >= tot_size); + /* the total size allocated may be larger than + the required size, reset it here */ + tot_size = hmu_get_size(hmu); + g_total_malloc += tot_size; hmu_set_ut(hmu, HMU_VO); @@ -570,6 +575,9 @@ gc_realloc_vo_internal(void *vheap, void *ptr, gc_size_t size, if (!hmu) goto finish; + bh_assert(hmu_get_size(hmu) >= tot_size); + /* the total size allocated may be larger than + the required size, reset it here */ g_total_malloc += tot_size; hmu_set_ut(hmu, HMU_VO); diff --git a/core/shared/mem-alloc/ems/ems_gc_internal.h b/core/shared/mem-alloc/ems/ems_gc_internal.h index aaf49068d..e72e47017 100644 --- a/core/shared/mem-alloc/ems/ems_gc_internal.h +++ b/core/shared/mem-alloc/ems/ems_gc_internal.h @@ -29,7 +29,13 @@ typedef struct hmu_struct { #if BH_ENABLE_GC_VERIFY != 0 +#if UINTPTR_MAX > UINT32_MAX +/* 2 prefix paddings for 64-bit pointer */ +#define GC_OBJECT_PREFIX_PADDING_CNT 2 +#else +/* 3 prefix paddings for 32-bit pointer */ #define GC_OBJECT_PREFIX_PADDING_CNT 3 +#endif #define GC_OBJECT_SUFFIX_PADDING_CNT 4 #define GC_OBJECT_PADDING_VALUE (0x12345678) diff --git a/doc/build_wamr.md b/doc/build_wamr.md index 4c09ff913..347f2c0b8 100644 --- a/doc/build_wamr.md +++ b/doc/build_wamr.md @@ -43,13 +43,22 @@ cmake -DWAMR_BUILD_PLATFORM=linux -DWAMR_BUILD_TARGET=ARM #### **Configure LIBC** -- **WAMR_BUILD_LIBC_BUILTIN**=1/0, default to enable if not set +- **WAMR_BUILD_LIBC_BUILTIN**=1/0, build the built-in libc subset for WASM app, default to enable if not set -- **WAMR_BUILD_LIBC_WASI**=1/0, default to enable if not set +- **WAMR_BUILD_LIBC_WASI**=1/0, build the [WASI](https://github.com/WebAssembly/WASI) libc subset for WASM app, default to enable if not set + +- **WAMR_BUILD_LIBC_UVWASI**=1/0 (Experiment), build the [WASI](https://github.com/WebAssembly/WASI) libc subset for WASM app based on [uvwasi](https://github.com/nodejs/uvwasi) implementation, default to disable if not set + +> Note: for platform which doesn't support **WAMR_BUILD_LIBC_WASI**, e.g. Windows, developer can try using **WAMR_BUILD_LIBC_UVWASI**. And the uvwasi source code must be cloned under core/deps: +> +> ```bash +> cd /core/deps +> git clone https://github.com/nodejs/uvwasi.git +> ``` #### **Configure Debug** -- **WAMR_BUILD_CUSTOM_NAME_SECTION**=1/0, load the function name from custom name section, default to disable if not set +- **WAMR_BUILD_CUSTOM_NAME_SECTION**=1/0, load the function name from custom name section, default to disable if not set #### **Enable dump call stack feature** - **WAMR_BUILD_DUMP_CALL_STACK**=1/0, default to disable if not set diff --git a/product-mini/platforms/linux/CMakeLists.txt b/product-mini/platforms/linux/CMakeLists.txt index 6e14530ed..e64c2e708 100644 --- a/product-mini/platforms/linux/CMakeLists.txt +++ b/product-mini/platforms/linux/CMakeLists.txt @@ -119,7 +119,7 @@ add_executable (iwasm main.c ${UNCOMMON_SHARED_SOURCE}) install (TARGETS iwasm DESTINATION bin) -target_link_libraries (iwasm vmlib ${LLVM_AVAILABLE_LIBS} -lm -ldl -lpthread) +target_link_libraries (iwasm vmlib ${LLVM_AVAILABLE_LIBS} ${UV_A_LIBS} -lm -ldl -lpthread) add_library (libiwasm SHARED ${WAMR_RUNTIME_LIB_SOURCE}) diff --git a/product-mini/platforms/windows/CMakeLists.txt b/product-mini/platforms/windows/CMakeLists.txt index 85f5edc82..49b4cef84 100644 --- a/product-mini/platforms/windows/CMakeLists.txt +++ b/product-mini/platforms/windows/CMakeLists.txt @@ -51,9 +51,9 @@ if (NOT DEFINED WAMR_BUILD_LIBC_BUILTIN) set (WAMR_BUILD_LIBC_BUILTIN 1) endif () -if (NOT DEFINED WAMR_BUILD_LIBC_WASI) - # Enable libc wasi support by default - set (WAMR_BUILD_LIBC_WASI 0) +if (NOT DEFINED WAMR_BUILD_LIBC_UVWASI) + # Enable libc uvwasi support by default + set (WAMR_BUILD_LIBC_UVWASI 1) endif () if (NOT DEFINED WAMR_BUILD_FAST_INTERP) @@ -86,6 +86,7 @@ include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) add_library(vmlib ${WAMR_RUNTIME_LIB_SOURCE}) set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SAFESEH:NO") +set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SAFESEH:NO") # set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat -Wformat-security") # set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wconversion -Wsign-conversion") @@ -110,7 +111,7 @@ add_executable (iwasm main.c ${UNCOMMON_SHARED_SOURCE}) install (TARGETS iwasm DESTINATION bin) -target_link_libraries (iwasm vmlib ${LLVM_AVAILABLE_LIBS}) +target_link_libraries (iwasm vmlib ${LLVM_AVAILABLE_LIBS} ${UV_A_LIBS}) add_library (libiwasm SHARED ${WAMR_RUNTIME_LIB_SOURCE}) @@ -118,6 +119,6 @@ install (TARGETS libiwasm DESTINATION lib) set_target_properties (libiwasm PROPERTIES OUTPUT_NAME iwasm) -target_link_libraries (libiwasm ${LLVM_AVAILABLE_LIBS}) +target_link_libraries (libiwasm ${LLVM_AVAILABLE_LIBS} ${UV_A_LIBS}) target_compile_definitions(libiwasm PRIVATE COMPILING_WASM_RUNTIME_API=1) From 79afa493aa9895cffeeefbc0b9020bb2020a3ae8 Mon Sep 17 00:00:00 2001 From: Jonathan Date: Tue, 23 Feb 2021 07:55:50 -0500 Subject: [PATCH 154/207] Fix windows aot loader fail to resolve symbol issue (#540) --- core/iwasm/aot/aot_reloc.h | 14 ----------- core/iwasm/aot/aot_runtime.c | 2 +- core/iwasm/aot/arch/aot_reloc_x86_32.c | 31 +++++++++++++++++++++++-- core/iwasm/aot/arch/aot_reloc_x86_64.c | 10 ++++---- core/iwasm/common/wasm_runtime_common.c | 6 ++--- product-mini/platforms/windows/main.c | 2 +- 6 files changed, 40 insertions(+), 25 deletions(-) diff --git a/core/iwasm/aot/aot_reloc.h b/core/iwasm/aot/aot_reloc.h index ff7ce8c2e..27fecf00e 100644 --- a/core/iwasm/aot/aot_reloc.h +++ b/core/iwasm/aot/aot_reloc.h @@ -37,19 +37,6 @@ typedef struct { #define REG_AOT_TRACE_SYM() #endif -#if (defined(_WIN32) || defined(_WIN32_)) && defined(NDEBUG) -#define REG_COMMON_SYMBOLS \ - REG_SYM(aot_set_exception_with_id), \ - REG_SYM(aot_invoke_native), \ - REG_SYM(aot_call_indirect), \ - REG_SYM(wasm_runtime_enlarge_memory), \ - REG_SYM(wasm_runtime_set_exception), \ - {"memset", (void*)aot_memset}, \ - {"memmove", (void*)aot_memmove}, \ - REG_BULK_MEMORY_SYM() \ - REG_ATOMIC_WAIT_SYM() \ - REG_AOT_TRACE_SYM() -#else /* else of (defined(_WIN32) || defined(_WIN32_)) && defined(NDEBUG) */ #define REG_COMMON_SYMBOLS \ REG_SYM(aot_set_exception_with_id), \ REG_SYM(aot_invoke_native), \ @@ -73,7 +60,6 @@ typedef struct { REG_BULK_MEMORY_SYM() \ REG_ATOMIC_WAIT_SYM() \ REG_AOT_TRACE_SYM() -#endif /* end of (defined(_WIN32) || defined(_WIN32_)) && defined(NDEBUG) */ #define CHECK_RELOC_OFFSET(data_size) do { \ if (!check_reloc_offset(target_section_size, reloc_offset, data_size, \ diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index f52e4eb24..55c266e38 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -2264,7 +2264,7 @@ aot_get_module_inst_mem_consumption(const AOTModuleInstance *module_inst, mem_conspn->memories_size += mem_inst->num_bytes_per_page * mem_inst->cur_page_count; mem_conspn->app_heap_size = - mem_inst->heap_data_end.ptr - mem_inst->heap_data.ptr; + (uint8 *) mem_inst->heap_data_end.ptr - (uint8 *) mem_inst->heap_data.ptr; /* size of app heap structure */ mem_conspn->memories_size += mem_allocator_get_heap_struct_size(); diff --git a/core/iwasm/aot/arch/aot_reloc_x86_32.c b/core/iwasm/aot/arch/aot_reloc_x86_32.c index 6cc470e91..2b13b1dab 100644 --- a/core/iwasm/aot/arch/aot_reloc_x86_32.c +++ b/core/iwasm/aot/arch/aot_reloc_x86_32.c @@ -8,20 +8,47 @@ #define R_386_32 1 /* Direct 32 bit */ #define R_386_PC32 2 /* PC relative 32 bit */ +#if !defined(_WIN32) && !defined(_WIN32_) void __divdi3(); void __udivdi3(); void __moddi3(); void __umoddi3(); +#else +#pragma function (floor) +#pragma function (ceil) + +static int64 +__divdi3(int64 a, int64 b) +{ + return a / b; +} + +static uint64 +__udivdi3(uint64 a, uint64 b) +{ + return a / b; +} + +static int64 +__moddi3(int64 a, int64 b) +{ + return a % b; +} + +static uint64 +__umoddi3(uint64 a, uint64 b) +{ + return a % b; +} +#endif static SymbolMap target_sym_map[] = { REG_COMMON_SYMBOLS -#if !defined(_WIN32) && !defined(_WIN32_) /* compiler-rt symbols that come from compiler(e.g. gcc) */ REG_SYM(__divdi3), REG_SYM(__udivdi3), REG_SYM(__moddi3), REG_SYM(__umoddi3) -#endif }; static void diff --git a/core/iwasm/aot/arch/aot_reloc_x86_64.c b/core/iwasm/aot/arch/aot_reloc_x86_64.c index b19fd9da9..676bdd5c9 100644 --- a/core/iwasm/aot/arch/aot_reloc_x86_64.c +++ b/core/iwasm/aot/arch/aot_reloc_x86_64.c @@ -14,10 +14,12 @@ #define IMAGE_REL_AMD64_REL32 4 /* The 32-bit relative address from the byte following the relocation */ -void __divdi3(); -void __udivdi3(); -void __moddi3(); -void __umoddi3(); +#if defined(_WIN64) || defined(_WIN64_) +#pragma function (floor) +#pragma function (ceil) +#pragma function (floorf) +#pragma function (ceilf) +#endif static SymbolMap target_sym_map[] = { REG_COMMON_SYMBOLS diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index 5a72bac7a..7b1f7de12 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -1525,9 +1525,9 @@ wasm_runtime_get_app_addr_range(WASMModuleInstanceCommon *module_inst, bool wasm_runtime_get_native_addr_range(WASMModuleInstanceCommon *module_inst, - uint8_t *native_ptr, - uint8_t **p_native_start_addr, - uint8_t **p_native_end_addr) + uint8 *native_ptr, + uint8 **p_native_start_addr, + uint8 **p_native_end_addr) { #if WASM_ENABLE_INTERP != 0 if (module_inst->module_type == Wasm_Module_Bytecode) diff --git a/product-mini/platforms/windows/main.c b/product-mini/platforms/windows/main.c index 8db96b0a7..5cb3415a4 100644 --- a/product-mini/platforms/windows/main.c +++ b/product-mini/platforms/windows/main.c @@ -194,7 +194,7 @@ module_reader_callback(const char *module_name, uint8 **p_buffer, snprintf(wasm_file_name, sz, format, module_search_path, module_name); - *p_buffer = (uint8_t *)bh_read_file_to_buffer(wasm_file_name, p_size); + *p_buffer = (uint8 *)bh_read_file_to_buffer(wasm_file_name, p_size); wasm_runtime_free(wasm_file_name); return *p_buffer != NULL; From 3cafb2f9c1a3c3131795bb0eb64590816c16eefb Mon Sep 17 00:00:00 2001 From: Huang Qi <757509347@qq.com> Date: Wed, 24 Feb 2021 10:03:43 +0800 Subject: [PATCH 155/207] platforms/nuttx: Add FPU relative macro for thumb vfp (#541) Signed-off-by: Huang Qi Co-authored-by: Huang Qi --- product-mini/platforms/nuttx/wamr.mk | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/product-mini/platforms/nuttx/wamr.mk b/product-mini/platforms/nuttx/wamr.mk index 1fcb74c36..d82852cf3 100644 --- a/product-mini/platforms/nuttx/wamr.mk +++ b/product-mini/platforms/nuttx/wamr.mk @@ -41,11 +41,12 @@ else ifeq ($(findstring ARM,$(WAMR_BUILD_TARGET)), ARM) INVOKE_NATIVE := invokeNative_arm.s AOT_RELOC := aot_reloc_arm.c else ifeq ($(findstring THUMB,$(WAMR_BUILD_TARGET)), THUMB) - CFLAGS += -DBUILD_TARGET_THUMB CFLAGS += -DBUILD_TARGET=\"$(WAMR_BUILD_TARGET)\" ifeq ($(CONFIG_ARCH_FPU),y) + CFLAGS += -DBUILD_TARGET_THUMB_VFP INVOKE_NATIVE := invokeNative_thumb_vfp.s else + CFLAGS += -DBUILD_TARGET_THUMB INVOKE_NATIVE := invokeNative_thumb.s endif AOT_RELOC := aot_reloc_thumb.c From 686733170c0c51075dd04aa1dbb2422cd18ae401 Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Wed, 24 Feb 2021 21:53:17 -0600 Subject: [PATCH 156/207] Enhance ems memory allocator (#544) The total size actually allocated by ealloc_hmu() might be larger than the size required to allocate, we reset the total size after allocating, so that if heap verification feature is enabled, the data to verify can be written to the right place of the suffix verification area. And in gc_realloc_vo_internal(), free the heap lock until the original data is copied to new object to return. Signed-off-by: Wenyong Huang --- core/shared/mem-alloc/ems/ems_alloc.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/core/shared/mem-alloc/ems/ems_alloc.c b/core/shared/mem-alloc/ems/ems_alloc.c index 51b556924..3dc631709 100644 --- a/core/shared/mem-alloc/ems/ems_alloc.c +++ b/core/shared/mem-alloc/ems/ems_alloc.c @@ -570,7 +570,6 @@ gc_realloc_vo_internal(void *vheap, void *ptr, gc_size_t size, } } - hmu = alloc_hmu_ex(heap, tot_size); if (!hmu) goto finish; @@ -578,6 +577,7 @@ gc_realloc_vo_internal(void *vheap, void *ptr, gc_size_t size, bh_assert(hmu_get_size(hmu) >= tot_size); /* the total size allocated may be larger than the required size, reset it here */ + tot_size = hmu_get_size(hmu); g_total_malloc += tot_size; hmu_set_ut(hmu, HMU_VO); @@ -590,7 +590,6 @@ gc_realloc_vo_internal(void *vheap, void *ptr, gc_size_t size, ret = hmu_to_obj(hmu); finish: - os_mutex_unlock(&heap->lock); if (ret) { obj_size = tot_size - HMU_SIZE - OBJ_PREFIX_SIZE - OBJ_SUFFIX_SIZE; @@ -599,10 +598,14 @@ finish: obj_size_old = tot_size_old - HMU_SIZE - OBJ_PREFIX_SIZE - OBJ_SUFFIX_SIZE; bh_memcpy_s(ret, obj_size, obj_old, obj_size_old); - gc_free_vo(vheap, obj_old); } } + os_mutex_unlock(&heap->lock); + + if (ret && obj_old) + gc_free_vo(vheap, obj_old); + return ret; } From fe76ce3b685abf2ea214f7f93f2aa98194b6882b Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Tue, 2 Mar 2021 04:24:15 -0600 Subject: [PATCH 157/207] Update global initialization process for latest spec cases (#553) --- core/iwasm/aot/aot_loader.c | 19 ++ core/iwasm/aot/aot_runtime.c | 112 ++++++++++-- core/iwasm/common/wasm_runtime_common.c | 2 + core/iwasm/interpreter/wasm.h | 11 +- core/iwasm/interpreter/wasm_loader.c | 31 +++- core/iwasm/interpreter/wasm_mini_loader.c | 4 + core/iwasm/interpreter/wasm_runtime.c | 173 +++++++----------- .../libc-builtin/libc_builtin_wrapper.c | 36 ++-- 8 files changed, 240 insertions(+), 148 deletions(-) diff --git a/core/iwasm/aot/aot_loader.c b/core/iwasm/aot/aot_loader.c index 769e47d62..4faa89b67 100644 --- a/core/iwasm/aot/aot_loader.c +++ b/core/iwasm/aot/aot_loader.c @@ -722,6 +722,9 @@ load_import_globals(const uint8 **p_buf, const uint8 *buf_end, AOTImportGlobal *import_globals; uint64 size; uint32 i, data_offset = 0; +#if WASM_ENABLE_LIBC_BUILTIN != 0 + WASMGlobalImport tmp_global; +#endif /* Allocate memory */ size = sizeof(AOTImportGlobal) * (uint64)module->import_global_count; @@ -738,6 +741,22 @@ load_import_globals(const uint8 **p_buf, const uint8 *buf_end, read_string(buf, buf_end, import_globals[i].module_name); read_string(buf, buf_end, import_globals[i].global_name); +#if WASM_ENABLE_LIBC_BUILTIN != 0 + if (wasm_native_lookup_libc_builtin_global( + import_globals[i].module_name, + import_globals[i].global_name, + &tmp_global)) { + if (tmp_global.type != import_globals[i].type + || tmp_global.is_mutable != import_globals[i].is_mutable) { + set_error_buf(error_buf, error_buf_size, + "incompatible import type"); + return false; + } + import_globals[i].global_data_linked = + tmp_global.global_data_linked; + } +#endif + import_globals[i].size = wasm_value_type_size(import_globals[i].type); import_globals[i].data_offset = data_offset; data_offset += import_globals[i].size; diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index 55c266e38..38c91d58e 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -6,6 +6,7 @@ #include "aot_runtime.h" #include "bh_log.h" #include "mem_alloc.h" +#include "../common/wasm_runtime_common.h" #if WASM_ENABLE_SHARED_MEMORY != 0 #include "../common/wasm_shared_memory.h" #endif @@ -19,6 +20,22 @@ set_error_buf(char *error_buf, uint32 error_buf_size, const char *string) } } +static void +set_error_buf_v(char *error_buf, uint32 error_buf_size, + const char *format, ...) +{ + va_list args; + char buf[128]; + + if (error_buf != NULL) { + va_start(args, format); + vsnprintf(buf, sizeof(buf), format, args); + va_end(args); + snprintf(error_buf, error_buf_size, + "AOT module instantiate failed: %s", buf); + } +} + static void * runtime_malloc(uint64 size, char *error_buf, uint32 error_buf_size) { @@ -35,6 +52,58 @@ runtime_malloc(uint64 size, char *error_buf, uint32 error_buf_size) return mem; } +static bool +check_global_init_expr(const AOTModule *module, uint32 global_index, + char *error_buf, uint32 error_buf_size) +{ + if (global_index >= module->import_global_count + module->global_count) { + set_error_buf_v(error_buf, error_buf_size, + "unknown global %d", global_index); + return false; + } + + /** + * Currently, constant expressions occurring as initializers of + * globals are further constrained in that contained global.get + * instructions are only allowed to refer to imported globals. + * + * And initializer expression cannot reference a mutable global. + */ + if (global_index >= module->import_global_count + || module->import_globals->is_mutable) { + set_error_buf(error_buf, error_buf_size, + "constant expression required"); + return false; + } + + return true; +} + +static void +init_global_data(uint8 *global_data, uint8 type, + WASMValue *initial_value) +{ + switch (type) { + case VALUE_TYPE_I32: + case VALUE_TYPE_F32: + *(int32*)global_data = initial_value->i32; + break; + case VALUE_TYPE_I64: + case VALUE_TYPE_F64: + bh_memcpy_s(global_data, sizeof(int64), + &initial_value->i64, sizeof(int64)); + break; +#if WASM_ENABLE_SIMD != 0 + case VALUE_TYPE_V128: + bh_memcpy_s(global_data, sizeof(V128), + &initial_value->i64, sizeof(V128)); + break; +#endif + default: + bh_assert(0); + } +} + static bool global_instantiate(AOTModuleInstance *module_inst, AOTModule *module, char *error_buf, uint32 error_buf_size) @@ -49,7 +118,8 @@ global_instantiate(AOTModuleInstance *module_inst, AOTModule *module, for (i = 0; i < module->import_global_count; i++, import_global++) { bh_assert(import_global->data_offset == (uint32)(p - (uint8*)module_inst->global_data.ptr)); - memcpy(p, &import_global->global_data_linked, import_global->size); + init_global_data(p, import_global->type, + &import_global->global_data_linked); p += import_global->size; } @@ -60,18 +130,21 @@ global_instantiate(AOTModuleInstance *module_inst, AOTModule *module, init_expr = &global->init_expr; switch (init_expr->init_expr_type) { case INIT_EXPR_TYPE_GET_GLOBAL: - if (init_expr->u.global_index >= module->import_global_count + i) { - set_error_buf(error_buf, error_buf_size, "unknown global"); + { + if (!check_global_init_expr(module, init_expr->u.global_index, + error_buf, error_buf_size)) { return false; } - memcpy(p, - &module->import_globals[init_expr->u.global_index].global_data_linked, - global->size); + init_global_data(p, global->type, + &module->import_globals[init_expr->u.global_index] + .global_data_linked); break; + } default: - /* TODO: check whether global type and init_expr type are matching */ - memcpy(p, &init_expr->u, global->size); + { + init_global_data(p, global->type, &init_expr->u); break; + } } p += global->size; } @@ -98,10 +171,12 @@ table_instantiate(AOTModuleInstance *module_inst, AOTModule *module, /* Resolve table data base offset */ if (table_seg->offset.init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL) { global_index = table_seg->offset.u.global_index; - bh_assert(global_index < - module->import_global_count + module->global_count); - /* TODO: && globals[table_seg->offset.u.global_index].type == - VALUE_TYPE_I32*/ + + if (!check_global_init_expr(module, global_index, + error_buf, error_buf_size)) { + return false; + } + if (global_index < module->import_global_count) global_data_offset = module->import_globals[global_index].data_offset; @@ -487,10 +562,12 @@ memories_instantiate(AOTModuleInstance *module_inst, AOTModule *module, /* Resolve memory data base offset */ if (data_seg->offset.init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL) { global_index = data_seg->offset.u.global_index; - bh_assert(global_index < - module->import_global_count + module->global_count); - /* TODO: && globals[data_seg->offset.u.global_index].type == - VALUE_TYPE_I32*/ + + if (!check_global_init_expr(module, global_index, + error_buf, error_buf_size)) { + return false; + } + if (global_index < module->import_global_count) global_data_offset = module->import_globals[global_index].data_offset; @@ -501,7 +578,8 @@ memories_instantiate(AOTModuleInstance *module_inst, AOTModule *module, base_offset = *(uint32*) ((uint8*)module_inst->global_data.ptr + global_data_offset); - } else { + } + else { base_offset = (uint32)data_seg->offset.u.i32; } diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index 7b1f7de12..1e7e363dc 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -545,7 +545,9 @@ wasm_runtime_is_built_in_module(const char *module_name) return (!strcmp("env", module_name) || !strcmp("wasi_unstable", module_name) || !strcmp("wasi_snapshot_preview1", module_name) +#if WASM_ENABLE_SPEC_TEST != 0 || !strcmp("spectest", module_name) +#endif || !strcmp("", module_name)); } diff --git a/core/iwasm/interpreter/wasm.h b/core/iwasm/interpreter/wasm.h index c8ab721de..ab3476c0f 100644 --- a/core/iwasm/interpreter/wasm.h +++ b/core/iwasm/interpreter/wasm.h @@ -93,6 +93,8 @@ typedef union V128 { typedef union WASMValue { int32 i32; uint32 u32; + uint32 global_index; + uint32 ref_index; int64 i64; uint64 u64; float32 f32; @@ -104,14 +106,7 @@ typedef union WASMValue { typedef struct InitializerExpression { /* type of INIT_EXPR_TYPE_XXX */ uint8 init_expr_type; - union { - int32 i32; - int64 i64; - float32 f32; - float64 f64; - uint32 global_index; - V128 v128; - } u; + WASMValue u; } InitializerExpression; typedef struct WASMType { diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index 3f24101c0..aa798ae3a 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -1276,6 +1276,14 @@ load_global_import(const uint8 **p_buf, const uint8 *buf_end, #if WASM_ENABLE_LIBC_BUILTIN != 0 global->is_linked = wasm_native_lookup_libc_builtin_global( sub_module_name, global_name, global); + if (global->is_linked) { + if (global->type != declare_type + || global->is_mutable != declare_mutable) { + set_error_buf(error_buf, error_buf_size, + "incompatible import type"); + return false; + } + } #endif #if WASM_ENABLE_MULTI_MODULE != 0 if (!global->is_linked @@ -1324,6 +1332,7 @@ load_table(const uint8 **p_buf, const uint8 *buf_end, WASMTable *table, p_org = p; read_leb_uint32(p, p_end, table->flags); +#if WASM_ENABLE_SHARED_MEMORY == 0 if (p - p_org > 1) { set_error_buf(error_buf, error_buf_size, "integer representation too long"); @@ -1333,6 +1342,20 @@ load_table(const uint8 **p_buf, const uint8 *buf_end, WASMTable *table, set_error_buf(error_buf, error_buf_size, "integer too large"); return false; } +#else + if (p - p_org > 1) { + set_error_buf(error_buf, error_buf_size, "invalid limits flags"); + return false; + } + if (table->flags == 2) { + set_error_buf(error_buf, error_buf_size, "tables cannot be shared"); + return false; + } + if (table->flags > 1) { + set_error_buf(error_buf, error_buf_size, "invalid limits flags"); + return false; + } +#endif read_leb_uint32(p, p_end, table->init_size); if (table->flags == 0) { @@ -1366,19 +1389,23 @@ load_memory(const uint8 **p_buf, const uint8 *buf_end, WASMMemory *memory, p_org = p; read_leb_uint32(p, p_end, memory->flags); +#if WASM_ENABLE_SHARED_MEMORY == 0 if (p - p_org > 1) { set_error_buf(error_buf, error_buf_size, "integer representation too long"); return false; } -#if WASM_ENABLE_SHARED_MEMORY == 0 if (memory->flags > 1) { set_error_buf(error_buf, error_buf_size, "integer too large"); return false; } #else + if (p - p_org > 1) { + set_error_buf(error_buf, error_buf_size, "invalid limits flags"); + return false; + } if (memory->flags > 3) { - set_error_buf(error_buf, error_buf_size, "integer too large"); + set_error_buf(error_buf, error_buf_size, "invalid limits flags"); return false; } else if (memory->flags == 2) { diff --git a/core/iwasm/interpreter/wasm_mini_loader.c b/core/iwasm/interpreter/wasm_mini_loader.c index 478b3cc34..bdbc36b88 100644 --- a/core/iwasm/interpreter/wasm_mini_loader.c +++ b/core/iwasm/interpreter/wasm_mini_loader.c @@ -477,6 +477,10 @@ load_global_import(const uint8 **p_buf, const uint8 *buf_end, /* check built-in modules */ ret = wasm_native_lookup_libc_builtin_global(sub_module_name, global_name, global); + if (ret) { + bh_assert(global->type == declare_type + && global->is_mutable != declare_mutable); + } #endif /* WASM_ENABLE_LIBC_BUILTIN */ global->is_linked = ret; diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index 6ffe90b32..005822bdd 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -23,6 +23,22 @@ set_error_buf(char *error_buf, uint32 error_buf_size, const char *string) } } +static void +set_error_buf_v(char *error_buf, uint32 error_buf_size, + const char *format, ...) +{ + va_list args; + char buf[128]; + + if (error_buf != NULL) { + va_start(args, format); + vsnprintf(buf, sizeof(buf), format, args); + va_end(args); + snprintf(error_buf, error_buf_size, + "WASM module instantiate failed: %s", buf); + } +} + WASMModule* wasm_load(const uint8 *buf, uint32 size, char *error_buf, uint32 error_buf_size) @@ -635,40 +651,30 @@ globals_deinstantiate(WASMGlobalInstance *globals) wasm_runtime_free(globals); } -/** - * init_expr->u ==> init_val - */ static bool -parse_init_expr(const InitializerExpression *init_expr, - const WASMGlobalInstance *global_inst_array, - uint32 boundary, WASMValue *init_val) +check_global_init_expr(const WASMModule *module, uint32 global_index, + char *error_buf, uint32 error_buf_size) { - if (init_expr->init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL) { - uint32 target_global_index = init_expr->u.global_index; - /** - * a global gets the init value of another global - */ - if (target_global_index >= boundary) { - LOG_DEBUG("unknown target global, %d", target_global_index); - return false; - } + if (global_index >= module->import_global_count + module->global_count) { + set_error_buf_v(error_buf, error_buf_size, + "unknown global %d", global_index); + return false; + } - /** - * it will work if using WASMGlobalImport and WASMGlobal in - * WASMModule, but will have to face complicated cases - * - * but we still have no sure the target global has been - * initialized before - */ - WASMValue target_value = - global_inst_array[target_global_index].initial_value; - bh_memcpy_s(init_val, sizeof(WASMValue), &target_value, - sizeof(target_value)); - } - else { - bh_memcpy_s(init_val, sizeof(WASMValue), &init_expr->u, - sizeof(init_expr->u)); + /** + * Currently, constant expressions occurring as initializers of + * globals are further constrained in that contained global.get + * instructions are only allowed to refer to imported globals. + * + * And initializer expression cannot reference a mutable global. + */ + if (global_index >= module->import_global_count + || (module->import_globals + global_index)->u.global.is_mutable) { + set_error_buf(error_buf, error_buf_size, + "constant expression required"); + return false; } + return true; } @@ -714,26 +720,19 @@ globals_instantiate(const WASMModule *module, return NULL; } - /** - * although, actually don't need initial_value for an imported - * global, we keep it here like a place holder because of - * global-data and - * (global $g2 i32 (global.get $g1)) - */ - if (!parse_init_expr( - &(global_import->import_global_linked->init_expr), - global->import_module_inst->globals, - global->import_module_inst->global_count, - &(global->initial_value))) { - set_error_buf(error_buf, error_buf_size, "unknown global"); - return NULL; - } + /* The linked global instance has been initialized, we + just need to copy the value. */ + bh_memcpy_s(&(global->initial_value), sizeof(WASMValue), + &(global_import->import_global_linked->init_expr), + sizeof(WASMValue)); } else #endif { /* native globals share their initial_values in one module */ - global->initial_value = global_import->global_data_linked; + bh_memcpy_s(&(global->initial_value), sizeof(WASMValue), + &(global_import->global_data_linked), + sizeof(WASMValue)); } global->data_offset = global_data_offset; global_data_offset += wasm_value_type_size(global->type); @@ -743,9 +742,6 @@ globals_instantiate(const WASMModule *module, /* instantiate globals from global section */ for (i = 0; i < module->global_count; i++) { - bool ret = false; - uint32 global_count = - module->import_global_count + module->global_count; InitializerExpression *init_expr = &(module->globals[i].init_expr); global->type = module->globals[i].type; @@ -754,18 +750,20 @@ globals_instantiate(const WASMModule *module, global_data_offset += wasm_value_type_size(global->type); - /** - * first init, it might happen that the target global instance - * has not been initialize yet - */ - if (init_expr->init_expr_type != INIT_EXPR_TYPE_GET_GLOBAL) { - ret = - parse_init_expr(init_expr, globals, global_count, - &(global->initial_value)); - if (!ret) { - set_error_buf(error_buf, error_buf_size, "unknown global"); + if (init_expr->init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL) { + if (!check_global_init_expr(module, init_expr->u.global_index, + error_buf, error_buf_size)) { return NULL; } + + bh_memcpy_s( + &(global->initial_value), sizeof(WASMValue), + &(globals[init_expr->u.global_index].initial_value), + sizeof(globals[init_expr->u.global_index].initial_value)); + } + else { + bh_memcpy_s(&(global->initial_value), sizeof(WASMValue), + &(init_expr->u), sizeof(init_expr->u)); } global++; } @@ -776,39 +774,6 @@ globals_instantiate(const WASMModule *module, return globals; } -static bool -globals_instantiate_fix(WASMGlobalInstance *globals, - const WASMModule *module, - char *error_buf, uint32 error_buf_size) -{ - WASMGlobalInstance *global = globals; - uint32 i; - uint32 global_count = module->import_global_count + module->global_count; - - /** - * second init, only target global instances from global - * (ignore import_global) - * to fix skipped init_value in the previous round - * hope two rounds are enough but how about a chain ? - */ - for (i = 0; i < module->global_count; i++) { - bool ret = false; - InitializerExpression *init_expr = &module->globals[i].init_expr; - - if (init_expr->init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL) { - ret = parse_init_expr(init_expr, globals, global_count, - &global->initial_value); - if (!ret) { - set_error_buf(error_buf, error_buf_size, "unknown global"); - return false; - } - } - - global++; - } - return true; -} - /** * Return export function count in module export section. */ @@ -1240,15 +1205,6 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, } if (global_count > 0) { - /** - * since there might be some globals are not instantiate the first - * instantiate round - */ - if (!globals_instantiate_fix(globals, module, - error_buf, error_buf_size)) { - goto fail; - } - /* Initialize the global data */ global_data = module_inst->global_data; global_data_end = global_data + global_data_size; @@ -1307,14 +1263,20 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, if (data_seg->base_offset.init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL) { + if (!check_global_init_expr(module, + data_seg->base_offset.u.global_index, + error_buf, error_buf_size)) { + goto fail; + } + if (!globals - || data_seg->base_offset.u.global_index >= global_count || globals[data_seg->base_offset.u.global_index].type - != VALUE_TYPE_I32) { + != VALUE_TYPE_I32) { set_error_buf(error_buf, error_buf_size, "data segment does not fit"); goto fail; } + data_seg->base_offset.u.i32 = globals[data_seg->base_offset.u.global_index] .initial_value.i32; @@ -1371,8 +1333,13 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, if (table_seg->base_offset.init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL) { + if (!check_global_init_expr(module, + table_seg->base_offset.u.global_index, + error_buf, error_buf_size)) { + goto fail; + } + if (!globals - || table_seg->base_offset.u.global_index >= global_count || globals[table_seg->base_offset.u.global_index].type != VALUE_TYPE_I32) { set_error_buf(error_buf, error_buf_size, diff --git a/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c b/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c index b1a20b1d2..23d982485 100644 --- a/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c +++ b/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c @@ -1167,26 +1167,24 @@ get_spectest_export_apis(NativeSymbol **p_libc_builtin_apis) typedef struct WASMNativeGlobalDef { const char *module_name; const char *global_name; - WASMValue global_data; + uint8 type; + bool is_mutable; + WASMValue value; } WASMNativeGlobalDef; static WASMNativeGlobalDef native_global_defs[] = { - { "spectest", "global_i32", .global_data.i32 = 666 }, - { "spectest", "global_f32", .global_data.f32 = 666.6 }, - { "spectest", "global_f64", .global_data.f64 = 666.6 }, - { "test", "global-i32", .global_data.i32 = 0 }, - { "test", "global-f32", .global_data.f32 = 0 }, - { "env", "STACKTOP", .global_data.u32 = 0 }, - { "env", "STACK_MAX", .global_data.u32 = 0 }, - { "env", "ABORT", .global_data.u32 = 0 }, - { "env", "memoryBase", .global_data.u32 = 0 }, - { "env", "__memory_base", .global_data.u32 = 0 }, - { "env", "tableBase", .global_data.u32 = 0 }, - { "env", "__table_base", .global_data.u32 = 0 }, - { "env", "DYNAMICTOP_PTR", .global_data.addr = 0 }, - { "env", "tempDoublePtr", .global_data.addr = 0 }, - { "global", "NaN", .global_data.u64 = 0x7FF8000000000000LL }, - { "global", "Infinity", .global_data.u64 = 0x7FF0000000000000LL } +#if WASM_ENABLE_SPEC_TEST != 0 + { "spectest", "global_i32", VALUE_TYPE_I32, false, .value.i32 = 666 }, + { "spectest", "global_i64", VALUE_TYPE_I64, false, .value.i64 = 666 }, + { "spectest", "global_f32", VALUE_TYPE_F32, false, .value.f32 = 666.6 }, + { "spectest", "global_f64", VALUE_TYPE_F64, false, .value.f64 = 666.6 }, + { "test", "global-i32", VALUE_TYPE_I32, false, .value.i32 = 0 }, + { "test", "global-f32", VALUE_TYPE_F32, false, .value.f32 = 0 }, + { "test", "global-mut-i32", VALUE_TYPE_I32, true, .value.i32 = 0 }, + { "test", "global-mut-i64", VALUE_TYPE_I64, true, .value.i64 = 0 }, +#endif + { "global", "NaN", VALUE_TYPE_F64, .value.u64 = 0x7FF8000000000000LL }, + { "global", "Infinity", VALUE_TYPE_F64, .value.u64 = 0x7FF0000000000000LL } }; bool @@ -1205,7 +1203,9 @@ wasm_native_lookup_libc_builtin_global(const char *module_name, while (global_def < global_def_end) { if (!strcmp(global_def->module_name, module_name) && !strcmp(global_def->global_name, global_name)) { - global->global_data_linked = global_def->global_data; + global->type = global_def->type; + global->is_mutable = global_def->is_mutable; + global->global_data_linked = global_def->value; return true; } global_def++; From 54e82ec439552018d0f26c60b0fd6cc9e36b42a8 Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Wed, 3 Mar 2021 06:19:24 -0600 Subject: [PATCH 158/207] Fix app manager fail to install large app file issue (#555) Remove the limit of app file size no larger than 1 MB, fix possible memory leak issues when fail to install app file, change message size of aee_host_msg_callback() from uint16 type to uint32 type to fix possible integer overflow issue, and fix some coding style issues of app manager. Signed-off-by: Wenyong Huang --- core/app-mgr/app-manager/app_manager.c | 66 ++++---- core/app-mgr/app-manager/app_manager_host.c | 80 +++++---- core/app-mgr/app-manager/module_wasm_app.c | 153 ++++++++++++------ core/app-mgr/app-manager/resource_reg.c | 5 +- core/app-mgr/app-manager/watchdog.c | 6 + core/app-mgr/app-manager/watchdog.h | 3 + core/shared/mem-alloc/ems/ems_alloc.c | 1 + .../src/platform/linux/iwasm_main.c | 2 +- .../src/platform/zephyr/iwasm_main.c | 2 +- .../src/platform/linux/iwasm_main.c | 2 +- .../src/platform/zephyr/iwasm_main.c | 2 +- samples/simple/src/iwasm_main.c | 2 +- test-tools/host-tool/src/main.c | 149 ++++++++--------- test-tools/host-tool/src/transport.c | 27 ++-- 14 files changed, 293 insertions(+), 207 deletions(-) diff --git a/core/app-mgr/app-manager/app_manager.c b/core/app-mgr/app-manager/app_manager.c index 6418fecbc..daf5bca64 100644 --- a/core/app-mgr/app-manager/app_manager.c +++ b/core/app-mgr/app-manager/app_manager.c @@ -32,8 +32,8 @@ void app_manager_post_applets_update_event() return; if (!(attr_cont = attr_container_create("All Applets"))) { - app_manager_printf( - "Post applets update event failed: allocate memory failed."); + app_manager_printf("Post applets update event failed: " + "allocate memory failed."); return; } @@ -46,8 +46,8 @@ void app_manager_post_applets_update_event() } if (!(attr_container_set_int(&attr_cont, "num", num))) { - app_manager_printf( - "Post applets update event failed: set attr container key failed."); + app_manager_printf("Post applets update event failed: " + "set attr container key failed."); goto fail; } @@ -57,14 +57,14 @@ void app_manager_post_applets_update_event() i++; snprintf(buf, sizeof(buf), "%s%d", "applet", i); if (!(attr_container_set_string(&attr_cont, buf, m_data->module_name))) { - app_manager_printf( - "Post applets update event failed: set attr applet name key failed."); + app_manager_printf("Post applets update event failed: " + "set attr applet name key failed."); goto fail; } snprintf(buf, sizeof(buf), "%s%d", "heap", i); if (!(attr_container_set_int(&attr_cont, buf, m_data->heap_size))) { - app_manager_printf( - "Post applets update event failed: set attr heap key failed."); + app_manager_printf("Post applets update event failed: " + "set attr heap key failed."); goto fail; } m_data = m_data->next; @@ -114,7 +114,7 @@ static bool app_manager_query_applets(request_t *msg, const char *name) attr_cont = attr_container_create("Applets Info"); if (!attr_cont) { SEND_ERR_RESPONSE(msg->mid, - "Query Applets failed: allocate memory failed."); + "Query Applets failed: allocate memory failed."); return false; } @@ -128,7 +128,7 @@ static bool app_manager_query_applets(request_t *msg, const char *name) if (name == NULL && !(attr_container_set_int(&attr_cont, "num", num))) { SEND_ERR_RESPONSE(msg->mid, - "Query Applets failed: set attr container key failed."); + "Query Applets failed: set attr container key failed."); goto fail; } @@ -142,26 +142,31 @@ static bool app_manager_query_applets(request_t *msg, const char *name) if (!(attr_container_set_string(&attr_cont, buf, m_data->module_name))) { SEND_ERR_RESPONSE(msg->mid, - "Query Applets failed: set attr container key failed."); + "Query Applets failed: " + "set attr container key failed."); goto fail; } snprintf(buf, sizeof(buf), "%s%d", "heap", i); if (!(attr_container_set_int(&attr_cont, buf, m_data->heap_size))) { SEND_ERR_RESPONSE(msg->mid, - "Query Applets failed: set attr container heap key failed."); + "Query Applets failed: " + "set attr container heap key failed."); goto fail; } - } else if (!strcmp(name, m_data->module_name)) { + } + else if (!strcmp(name, m_data->module_name)) { found = true; if (!(attr_container_set_string(&attr_cont, "name", m_data->module_name))) { SEND_ERR_RESPONSE(msg->mid, - "Query Applet failed: set attr container key failed."); + "Query Applet failed: " + "set attr container key failed."); goto fail; } if (!(attr_container_set_int(&attr_cont, "heap", m_data->heap_size))) { SEND_ERR_RESPONSE(msg->mid, - "Query Applet failed: set attr container heap key failed."); + "Query Applet failed: " + "set attr container heap key failed."); goto fail; } } @@ -266,7 +271,7 @@ static void app_manager_queue_callback(void *message, void *arg) goto fail; } if (g_module_interfaces[module_type] - && g_module_interfaces[module_type]->module_install) { + && g_module_interfaces[module_type]->module_install) { if (!g_module_interfaces[module_type]->module_install(request)) goto fail; } @@ -276,14 +281,13 @@ static void app_manager_queue_callback(void *message, void *arg) module_type = get_module_type(request->url + offset); if (module_type == -1) { SEND_ERR_RESPONSE(mid, - "Uninstall Applet failed: invalid module type."); + "Uninstall Applet failed: invalid module type."); goto fail; } if (g_module_interfaces[module_type] && g_module_interfaces[module_type]->module_uninstall) { - if (!g_module_interfaces[module_type]->module_uninstall( - request)) + if (!g_module_interfaces[module_type]->module_uninstall(request)) goto fail; } } @@ -292,18 +296,19 @@ static void app_manager_queue_callback(void *message, void *arg) char name[APP_NAME_MAX_LEN] = { 0 }; char *properties = request->url + offset; find_key_value(properties, strlen(properties), "name", name, - sizeof(name) - 1, '&'); + sizeof(name) - 1, '&'); if (strlen(name) > 0) app_manager_query_applets(request, name); else app_manager_query_applets(request, NULL); - } else { + } + else { SEND_ERR_RESPONSE(mid, "Invalid request of applet: invalid action"); } } /* Event Register/Unregister */ else if ((offset = check_url_start(request->url, strlen(request->url), - "/event/")) > 0) { + "/event/")) > 0) { char url_buf[256] = { 0 }; strncpy(url_buf, request->url + offset, sizeof(url_buf) - 1); @@ -313,11 +318,12 @@ static void app_manager_queue_callback(void *message, void *arg) goto fail; } send_error_response_to_host(mid, CONTENT_2_05, NULL); /* OK */ - } else { + } + else { int i; for (i = 0; i < Module_Max; i++) { if (g_module_interfaces[i] - && g_module_interfaces[i]->module_handle_host_url) { + && g_module_interfaces[i]->module_handle_host_url) { if (g_module_interfaces[i]->module_handle_host_url(request)) break; } @@ -325,10 +331,8 @@ static void app_manager_queue_callback(void *message, void *arg) } - fail: - +fail: return; - } static void module_interfaces_init() @@ -360,7 +364,7 @@ void app_manager_startup(host_interface *interface) am_register_resource("/app/", targeted_app_request_handler, ID_APP_MGR); - /*/app/ and /event/ are both processed by applet_mgt_reqeust_handler*/ + /* /app/ and /event/ are both processed by applet_mgt_reqeust_handler */ am_register_resource("/applet", applet_mgt_reqeust_handler, ID_APP_MGR); am_register_resource("/event/", applet_mgt_reqeust_handler, ID_APP_MGR); @@ -369,6 +373,12 @@ void app_manager_startup(host_interface *interface) /* Enter loop run */ bh_queue_enter_loop_run(g_app_mgr_queue, app_manager_queue_callback, NULL); + /* Destroy registered resources */ + am_cleanup_registeration(ID_APP_MGR); + + /* Destroy watchdog */ + watchdog_destroy(); + fail2: module_data_list_destroy(); diff --git a/core/app-mgr/app-manager/app_manager_host.c b/core/app-mgr/app-manager/app_manager_host.c index f134eed6f..c7429da2a 100644 --- a/core/app-mgr/app-manager/app_manager_host.c +++ b/core/app-mgr/app-manager/app_manager_host.c @@ -13,11 +13,19 @@ static host_interface host_commu; /* IMRTLink Two leading bytes */ -static unsigned char leadings[] = { (unsigned char) 0x12, (unsigned char) 0x34 }; +static unsigned char leadings[] = { + (unsigned char)0x12, + (unsigned char)0x34 +}; /* IMRTLink Receiving Phase */ typedef enum recv_phase_t { - Phase_Non_Start, Phase_Leading, Phase_Type, Phase_Size, Phase_Payload + Phase_Non_Start, + Phase_Leading, + Phase_Type, + Phase_Size, + Phase_Payload, + Phase_Ignoring } recv_phase_t; /* IMRTLink Receive Context */ @@ -74,7 +82,8 @@ static int on_imrt_link_byte_arrive(unsigned char ch, recv_context_t *ctx) } return 0; - } else if (ctx->phase == Phase_Leading) { + } + else if (ctx->phase == Phase_Leading) { if (ch == leadings[1]) { if (enable_log) app_manager_printf("##On byte arrive: got leading 1\n"); @@ -83,12 +92,14 @@ static int on_imrt_link_byte_arrive(unsigned char ch, recv_context_t *ctx) ctx->phase = Phase_Non_Start; return 0; - } else if (ctx->phase == Phase_Type) { + } + else if (ctx->phase == Phase_Type) { if (ctx->size_in_phase++ == 0) { if (enable_log) app_manager_printf("##On byte arrive: got type 0\n"); ctx->message.message_type = ch; - } else { + } + else { if (enable_log) app_manager_printf("##On byte arrive: got type 1\n"); ctx->message.message_type |= (ch << 8); @@ -98,12 +109,13 @@ static int on_imrt_link_byte_arrive(unsigned char ch, recv_context_t *ctx) } return 0; - } else if (ctx->phase == Phase_Size) { + } + else if (ctx->phase == Phase_Size) { unsigned char *p = (unsigned char *) &ctx->message.payload_size; if (enable_log) app_manager_printf("##On byte arrive: got payload_size, byte %d\n", - ctx->size_in_phase); + ctx->size_in_phase); p[ctx->size_in_phase++] = ch; if (ctx->size_in_phase == sizeof(ctx->message.payload_size)) { @@ -112,7 +124,7 @@ static int on_imrt_link_byte_arrive(unsigned char ch, recv_context_t *ctx) if (enable_log) app_manager_printf("##On byte arrive: payload_size: %d\n", - ctx->message.payload_size); + ctx->message.payload_size); if (ctx->message.payload) { APP_MGR_FREE(ctx->message.payload); ctx->message.payload = NULL; @@ -122,16 +134,11 @@ static int on_imrt_link_byte_arrive(unsigned char ch, recv_context_t *ctx) if (ctx->message.payload_size == 0) { ctx->phase = Phase_Non_Start; if (enable_log) - app_manager_printf( - "##On byte arrive: receive end, payload_size is 0.\n"); + app_manager_printf("##On byte arrive: receive end, " + "payload_size is 0.\n"); return 1; } - if (ctx->message.payload_size > 1024 * 1024) { - ctx->phase = Phase_Non_Start; - return 0; - } - if (ctx->message.message_type != INSTALL_WASM_APP) { ctx->message.payload = (char *) APP_MGR_MALLOC(ctx->message.payload_size); @@ -146,7 +153,8 @@ static int on_imrt_link_byte_arrive(unsigned char ch, recv_context_t *ctx) } return 0; - } else if (ctx->phase == Phase_Payload) { + } + else if (ctx->phase == Phase_Payload) { if (ctx->message.message_type == INSTALL_WASM_APP) { int received_size; module_on_install_request_byte_arrive_func module_on_install = @@ -162,36 +170,53 @@ static int on_imrt_link_byte_arrive(unsigned char ch, recv_context_t *ctx) ctx->phase = Phase_Non_Start; return 1; } - } else { + } + else { /* receive or handle fail */ - ctx->phase = Phase_Non_Start; - ctx->size_in_phase = 0; + if (ctx->size_in_phase < ctx->message.payload_size) { + ctx->phase = Phase_Ignoring; + } + else { + ctx->phase = Phase_Non_Start; + ctx->size_in_phase = 0; + } return 0; } - return 0; - } else { + } + else { ctx->phase = Phase_Non_Start; ctx->size_in_phase = 0; return 0; } - } else { + } + else { ctx->message.payload[ctx->size_in_phase++] = ch; if (ctx->size_in_phase == ctx->message.payload_size) { ctx->phase = Phase_Non_Start; if (enable_log) - app_manager_printf("##On byte arrive: receive end, payload_size is %d.\n", + app_manager_printf("##On byte arrive: receive end, " + "payload_size is %d.\n", ctx->message.payload_size); return 1; } return 0; } } + else if (ctx->phase == Phase_Ignoring) { + ctx->size_in_phase++; + if (ctx->size_in_phase == ctx->message.payload_size) { + if (ctx->message.payload) + APP_MGR_FREE(ctx->message.payload); + memset(ctx, 0, sizeof(*ctx)); + return 0; + } + } return 0; } -int aee_host_msg_callback(void *msg, uint16_t msg_len) +int aee_host_msg_callback(void *msg, uint32_t msg_len) { unsigned char *p = msg, *p_end = p + msg_len; @@ -259,8 +284,8 @@ int app_manager_host_send_msg(int msg_type, const char *buf, int size) bh_memcpy_s(header, 2, leadings, 2); /* message type */ - // todo: check if use network byte order!!! - *((uint16*) (header + 2)) = htons(msg_type); + /* TODO: check if use network byte order!!! */ + *((uint16*)(header + 2)) = htons(msg_type); /* payload length */ if (is_little_endian()) @@ -279,7 +304,8 @@ int app_manager_host_send_msg(int msg_type, const char *buf, int size) app_manager_printf("sent %d bytes to host\n", n); return n; - } else { + } + else { app_manager_printf("no send api provided\n"); } return 0; diff --git a/core/app-mgr/app-manager/module_wasm_app.c b/core/app-mgr/app-manager/module_wasm_app.c index 6fda5355e..a7d993ade 100644 --- a/core/app-mgr/app-manager/module_wasm_app.c +++ b/core/app-mgr/app-manager/module_wasm_app.c @@ -504,18 +504,20 @@ cleanup_app_resource(module_data *m_data) /* Destroy remain sections (i.e. data segment section for bytecode file * or text section of aot file) from app file's section list. */ - if (is_bytecode) + if (is_bytecode) { #if WASM_ENABLE_INTERP != 0 || WASM_ENABLE_JIT != 0 destroy_all_wasm_sections((wasm_section_list_t)(wasm_app_data->sections)); #else bh_assert(0); #endif - else + } + else { #if WASM_ENABLE_AOT != 0 destroy_all_aot_sections((aot_section_list_t)(wasm_app_data->sections)); #else bh_assert(0); #endif + } if (wasm_app_data->wasm_module) wasm_runtime_unload(wasm_app_data->wasm_module); @@ -568,7 +570,7 @@ wasm_app_module_install(request_t * msg) wasm_app_file_t *wasm_app_file; wasm_data *wasm_app_data; package_type_t package_type; - module_data *m_data; + module_data *m_data = NULL; wasm_module_t module = NULL; wasm_module_inst_t inst = NULL; wasm_exec_env_t exec_env = NULL; @@ -589,23 +591,30 @@ wasm_app_module_install(request_t * msg) return false; } + /* Judge the app type is AOTed or not */ + package_type = get_package_type((uint8 *)msg->payload, msg->payload_len); + wasm_app_file = (wasm_app_file_t *)msg->payload; + /* Check app name */ properties_offset = check_url_start(msg->url, strlen(msg->url), "/applet"); bh_assert(properties_offset > 0); - if (properties_offset <= 0) - return false; + if (properties_offset <= 0) { + SEND_ERR_RESPONSE(msg->mid, "Install WASM app failed: invalid app name."); + goto fail; + } + properties = msg->url + properties_offset; find_key_value(properties, strlen(properties), "name", m_name, sizeof(m_name) - 1, '&'); if (strlen(m_name) == 0) { SEND_ERR_RESPONSE(msg->mid, "Install WASM app failed: invalid app name."); - return false; + goto fail; } if (app_manager_lookup_module_data(m_name)) { SEND_ERR_RESPONSE(msg->mid, "Install WASM app failed: app already installed."); - return false; + goto fail; } /* Parse heap size */ @@ -620,9 +629,6 @@ wasm_app_module_install(request_t * msg) heap_size = APP_HEAP_SIZE_MAX; } - /* Judge the app type is AOTed or not */ - package_type = get_package_type((uint8 *) msg->payload, msg->payload_len); - /* Load WASM file and instantiate*/ switch (package_type) { #if WASM_ENABLE_AOT != 0 @@ -639,8 +645,6 @@ wasm_app_module_install(request_t * msg) AOT_SECTION_TYPE_SIGANATURE }; - wasm_app_file = (wasm_app_file_t *) msg->payload; - bh_assert(wasm_app_file); aot_file = &wasm_app_file->u.aot; /* Load AOT module from sections */ @@ -649,9 +653,7 @@ wasm_app_module_install(request_t * msg) if (!module) { SEND_ERR_RESPONSE(msg->mid, "Install WASM app failed: load WASM file failed."); - app_manager_printf("error: %s\n", err); - destroy_all_aot_sections(aot_file->sections); - return false; + goto fail; } /* Destroy useless sections from list after load */ destroy_part_aot_sections(&aot_file->sections, @@ -663,9 +665,7 @@ wasm_app_module_install(request_t * msg) wasi_dir_buf, sizeof(wasi_dir_buf))) { SEND_ERR_RESPONSE(msg->mid, "Install WASM app failed: prepare wasi env failed."); - wasm_runtime_unload(module); - destroy_all_aot_sections(aot_file->sections); - return false; + goto fail; } wasm_runtime_set_wasi_args(module, wasi_dir_list, 1, @@ -679,10 +679,7 @@ wasm_app_module_install(request_t * msg) if (!inst) { SEND_ERR_RESPONSE(msg->mid, "Install WASM app failed: instantiate wasm runtime failed."); - app_manager_printf("error: %s\n", err); - wasm_runtime_unload(module); - destroy_all_aot_sections(aot_file->sections); - return false; + goto fail; } break; } @@ -712,8 +709,6 @@ wasm_app_module_install(request_t * msg) /* Sections to be released after instantiating */ uint8 sections2[] = { SECTION_TYPE_DATA }; - wasm_app_file = (wasm_app_file_t *) msg->payload; - bh_assert(wasm_app_file); bytecode_file = &wasm_app_file->u.bytecode; /* Load wasm module from sections */ @@ -722,9 +717,7 @@ wasm_app_module_install(request_t * msg) if (!module) { SEND_ERR_RESPONSE(msg->mid, "Install WASM app failed: load WASM file failed."); - app_manager_printf("error: %s\n", err); - destroy_all_wasm_sections(bytecode_file->sections); - return false; + goto fail; } /* Destroy useless sections from list after load */ @@ -737,9 +730,7 @@ wasm_app_module_install(request_t * msg) wasi_dir_buf, sizeof(wasi_dir_buf))) { SEND_ERR_RESPONSE(msg->mid, "Install WASM app failed: prepare wasi env failed."); - wasm_runtime_unload(module); - destroy_all_wasm_sections(bytecode_file->sections); - return false; + goto fail; } wasm_runtime_set_wasi_args(module, wasi_dir_list, 1, @@ -753,10 +744,7 @@ wasm_app_module_install(request_t * msg) if (!inst) { SEND_ERR_RESPONSE(msg->mid, "Install WASM app failed: instantiate wasm runtime failed."); - app_manager_printf("error: %s\n", err); - wasm_runtime_unload(module); - destroy_all_wasm_sections(bytecode_file->sections); - return false; + goto fail; } /* Destroy useless sections from list after instantiate */ @@ -769,7 +757,7 @@ wasm_app_module_install(request_t * msg) default: SEND_ERR_RESPONSE(msg->mid, "Install WASM app failed: invalid wasm package type."); - return false; + goto fail; } /* Create module data including the wasm_app_data as its internal_data*/ @@ -875,8 +863,13 @@ wasm_app_module_install(request_t * msg) fail: if (m_data) release_module(m_data); - wasm_runtime_deinstantiate(inst); - wasm_runtime_unload(module); + + if (inst) + wasm_runtime_deinstantiate(inst); + + if (module) + wasm_runtime_unload(module); + if (exec_env) wasm_runtime_destroy_exec_env(exec_env); @@ -969,7 +962,7 @@ wasm_app_module_uninstall(request_t *msg) static bool wasm_app_module_handle_host_url(void *queue_msg) { - //todo: implement in future + /* TODO: implement in future */ app_manager_printf("App handles host url address %d\n", (int)(uintptr_t)queue_msg); return false; @@ -985,7 +978,7 @@ wasm_app_module_get_module_data(void *inst) static void wasm_app_module_watchdog_kill(module_data *m_data) { - //todo: implement in future + /* TODO: implement in future */ app_manager_printf("Watchdog kills app: %s\n", m_data->module_name); return; } @@ -997,7 +990,7 @@ wasm_register_msg_callback(int message_type, int i; int freeslot = -1; for (i = 0; i < Max_Msg_Callback; i++) { - // replace handler for the same event registered + /* replace handler for the same event registered */ if (g_msg_type[i] == message_type) break; @@ -1055,6 +1048,7 @@ wasm_app_module_on_install_request_byte_arrive(uint8 ch, int *received_size) { uint8 *p; + int magic; package_type_t package_type = Package_Type_Unknown; if (recv_ctx.phase == Phase_Req_Ver) { @@ -1102,6 +1096,9 @@ wasm_app_module_on_install_request_byte_arrive(uint8 ch, APP_MGR_MALLOC(recv_ctx.message.request_url_len + 1); if (NULL == recv_ctx.message.request_url) { app_manager_printf("Allocate memory failed!\n"); + SEND_ERR_RESPONSE(recv_ctx.message.request_mid, + "Install WASM app failed: " + "allocate memory failed."); goto fail; } memset(recv_ctx.message.request_url, 0, @@ -1131,7 +1128,7 @@ wasm_app_module_on_install_request_byte_arrive(uint8 ch, if (recv_ctx.size_in_phase == sizeof(recv_ctx.message.app_file_magic)) { - int magic = recv_ctx.message.app_file_magic; + magic = recv_ctx.message.app_file_magic; package_type = get_package_type((uint8 *)&magic, sizeof(magic) + 1); switch (package_type) { #if WASM_ENABLE_INTERP != 0 || WASM_ENABLE_JIT != 0 @@ -1152,7 +1149,8 @@ wasm_app_module_on_install_request_byte_arrive(uint8 ch, #endif default: SEND_ERR_RESPONSE(recv_ctx.message.request_mid, - "Install WASM app failed: invalid file format."); + "Install WASM app failed: " + "invalid file format."); goto fail; } } @@ -1166,6 +1164,8 @@ wasm_app_module_on_install_request_byte_arrive(uint8 ch, p[recv_ctx.size_in_phase++] = ch; else { app_manager_printf("Invalid WASM version!\n"); + SEND_ERR_RESPONSE(recv_ctx.message.request_mid, + "Install WASM app failed: invalid WASM version."); goto fail; } @@ -1185,8 +1185,12 @@ wasm_app_module_on_install_request_byte_arrive(uint8 ch, #endif if (section_type <= section_type_max) { wasm_section_t *new_section; - if (!(new_section = (wasm_section_t *) APP_MGR_MALLOC(sizeof(wasm_section_t)))) { + if (!(new_section = (wasm_section_t *) + APP_MGR_MALLOC(sizeof(wasm_section_t)))) { app_manager_printf("Allocate memory failed!\n"); + SEND_ERR_RESPONSE(recv_ctx.message.request_mid, + "Install WASM app failed: " + "allocate memory failed."); goto fail; } memset(new_section, 0, sizeof(wasm_section_t)); @@ -1209,7 +1213,13 @@ wasm_app_module_on_install_request_byte_arrive(uint8 ch, return true; } else { + char error_buf[128]; + app_manager_printf("Invalid wasm section type: %d\n", section_type); + snprintf(error_buf, sizeof(error_buf), + "Install WASM app failed: invalid wasm section type %d", + section_type); + SEND_ERR_RESPONSE(recv_ctx.message.request_mid, error_buf); goto fail; } } @@ -1228,7 +1238,10 @@ wasm_app_module_on_install_request_byte_arrive(uint8 ch, /* check leab128 overflow for uint32 value */ if (recv_ctx.size_in_phase > (sizeof(section->section_body_size) * 8 + 7 - 1) / 7) { - app_manager_printf(" LEB overflow when parsing section size\n"); + app_manager_printf("LEB overflow when parsing section size\n"); + SEND_ERR_RESPONSE(recv_ctx.message.request_mid, + "Install WASM app failed: " + "LEB overflow when parsing section size"); goto fail; } @@ -1236,6 +1249,8 @@ wasm_app_module_on_install_request_byte_arrive(uint8 ch, /* leb128 encoded section size parsed done */ if (!(section->section_body = APP_MGR_MALLOC(section->section_body_size))) { app_manager_printf("Allocate memory failed!\n"); + SEND_ERR_RESPONSE(recv_ctx.message.request_mid, + "Install WASM app failed: allocate memory failed"); goto fail; } recv_ctx.phase = Phase_Wasm_Section_Content; @@ -1263,7 +1278,15 @@ wasm_app_module_on_install_request_byte_arrive(uint8 ch, } else { app_manager_printf("Handle install message failed!\n"); - goto fail; + SEND_ERR_RESPONSE(recv_ctx.message.request_mid, + "Install WASM app failed: " + "handle install message failed"); + /** + * The sections were destroyed inside + * module_wasm_app_handle_install_msg(), + * no need to destroy again. + */ + return false; } } else { @@ -1283,7 +1306,9 @@ wasm_app_module_on_install_request_byte_arrive(uint8 ch, if (ch == wasm_aot_version[recv_ctx.size_in_phase]) p[recv_ctx.size_in_phase++] = ch; else { - app_manager_printf("Invalid WASM AOT version!\n"); + app_manager_printf("Invalid AOT version!\n"); + SEND_ERR_RESPONSE(recv_ctx.message.request_mid, + "Install WASM app failed: invalid AOT version"); goto fail; } @@ -1305,8 +1330,12 @@ wasm_app_module_on_install_request_byte_arrive(uint8 ch, if (aot_file_cur_offset % 4) return true; - if (!(cur_section = (aot_section_t *) APP_MGR_MALLOC(sizeof(aot_section_t)))) { + if (!(cur_section = (aot_section_t *) + APP_MGR_MALLOC(sizeof(aot_section_t)))) { app_manager_printf("Allocate memory failed!\n"); + SEND_ERR_RESPONSE(recv_ctx.message.request_mid, + "Install WASM app failed: " + "allocate memory failed"); goto fail; } memset(cur_section, 0, sizeof(aot_section_t)); @@ -1336,8 +1365,14 @@ wasm_app_module_on_install_request_byte_arrive(uint8 ch, recv_ctx.size_in_phase = 0; } else { + char error_buf[128]; + app_manager_printf("Invalid AOT section id: %d\n", cur_section->section_type); + snprintf(error_buf, sizeof(error_buf), + "Install WASM app failed: invalid AOT section id %d", + cur_section->section_type); + SEND_ERR_RESPONSE(recv_ctx.message.request_mid, error_buf); goto fail; } } @@ -1375,6 +1410,9 @@ wasm_app_module_on_install_request_byte_arrive(uint8 ch, os_mmap(NULL, (uint32)total_size, map_prot, map_flags))) { app_manager_printf("Allocate executable memory failed!\n"); + SEND_ERR_RESPONSE(recv_ctx.message.request_mid, + "Install WASM app failed: " + "allocate memory failed"); goto fail; } #if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64) @@ -1387,6 +1425,9 @@ wasm_app_module_on_install_request_byte_arrive(uint8 ch, if (!(section->section_body = APP_MGR_MALLOC(section->section_body_size))) { app_manager_printf("Allocate memory failed!\n"); + SEND_ERR_RESPONSE(recv_ctx.message.request_mid, + "Install WASM app failed: " + "allocate memory failed"); goto fail; } } @@ -1426,7 +1467,15 @@ wasm_app_module_on_install_request_byte_arrive(uint8 ch, } else { app_manager_printf("Handle install message failed!\n"); - goto fail; + SEND_ERR_RESPONSE(recv_ctx.message.request_mid, + "Install WASM app failed: " + "handle install message failed"); + /** + * The sections were destroyed inside + * module_wasm_app_handle_install_msg(), + * no need to destroy again. + */ + return false; } } else { @@ -1441,6 +1490,9 @@ wasm_app_module_on_install_request_byte_arrive(uint8 ch, #endif /* end of WASM_ENABLE_AOT != 0 */ fail: + /* Restore the package type */ + magic = recv_ctx.message.app_file_magic; + package_type = get_package_type((uint8 *)&magic, sizeof(magic) + 1); switch (package_type) { #if WASM_ENABLE_INTERP != 0 || WASM_ENABLE_JIT != 0 case Wasm_Module_Bytecode: @@ -1461,10 +1513,7 @@ fail: recv_ctx.message.request_url = NULL; } - recv_ctx.phase = Phase_Req_Ver; - recv_ctx.size_in_phase = 0; - recv_ctx.total_received_size = 0; - + memset(&recv_ctx, 0, sizeof(recv_ctx)); return false; } diff --git a/core/app-mgr/app-manager/resource_reg.c b/core/app-mgr/app-manager/resource_reg.c index 83bc37d98..fbeb803ae 100644 --- a/core/app-mgr/app-manager/resource_reg.c +++ b/core/app-mgr/app-manager/resource_reg.c @@ -136,7 +136,8 @@ void * am_dispatch_request(request_t *request) } bool am_register_resource(const char *url, - void (*request_handler)(request_t *, void *), uint32 register_id) + void (*request_handler)(request_t *, void *), + uint32 register_id) { app_res_register_t * r = g_resources; int register_num = 0; @@ -158,7 +159,7 @@ bool am_register_resource(const char *url, if (register_num >= RESOURCE_REGISTRATION_NUM_MAX) return false; - r = (app_res_register_t *) APP_MGR_MALLOC(sizeof(app_res_register_t)); + r = (app_res_register_t *)APP_MGR_MALLOC(sizeof(app_res_register_t)); if (r == NULL) return false; diff --git a/core/app-mgr/app-manager/watchdog.c b/core/app-mgr/app-manager/watchdog.c index ccaf5c2c4..e608ef556 100644 --- a/core/app-mgr/app-manager/watchdog.c +++ b/core/app-mgr/app-manager/watchdog.c @@ -124,3 +124,9 @@ bool watchdog_startup() #endif return true; } + +bool watchdog_destroy() +{ + bh_queue_exit_loop_run(watchdog_queue); + bh_queue_destroy(watchdog_queue); +} diff --git a/core/app-mgr/app-manager/watchdog.h b/core/app-mgr/app-manager/watchdog.h index a7a508bdb..a11fff3fe 100644 --- a/core/app-mgr/app-manager/watchdog.h +++ b/core/app-mgr/app-manager/watchdog.h @@ -31,6 +31,9 @@ app_manager_get_watchdog_timer(void *timer); bool watchdog_startup(); +bool +watchdog_destroy(); + #ifdef __cplusplus } /* end of extern "C" */ #endif diff --git a/core/shared/mem-alloc/ems/ems_alloc.c b/core/shared/mem-alloc/ems/ems_alloc.c index 3dc631709..92094d7d4 100644 --- a/core/shared/mem-alloc/ems/ems_alloc.c +++ b/core/shared/mem-alloc/ems/ems_alloc.c @@ -570,6 +570,7 @@ gc_realloc_vo_internal(void *vheap, void *ptr, gc_size_t size, } } + hmu = alloc_hmu_ex(heap, tot_size); if (!hmu) goto finish; diff --git a/samples/gui/wasm-runtime-wgl/src/platform/linux/iwasm_main.c b/samples/gui/wasm-runtime-wgl/src/platform/linux/iwasm_main.c index 321cd8f6f..58fb8a2c8 100644 --- a/samples/gui/wasm-runtime-wgl/src/platform/linux/iwasm_main.c +++ b/samples/gui/wasm-runtime-wgl/src/platform/linux/iwasm_main.c @@ -48,7 +48,7 @@ static int baudrate = B115200; extern void init_sensor_framework(); extern void exit_sensor_framework(); extern void exit_connection_framework(); -extern int aee_host_msg_callback(void *msg, uint16_t msg_len); +extern int aee_host_msg_callback(void *msg, uint32_t msg_len); extern bool init_connection_framework(); #ifndef CONNECTION_UART diff --git a/samples/gui/wasm-runtime-wgl/src/platform/zephyr/iwasm_main.c b/samples/gui/wasm-runtime-wgl/src/platform/zephyr/iwasm_main.c index 26e04b87b..f2a98530f 100644 --- a/samples/gui/wasm-runtime-wgl/src/platform/zephyr/iwasm_main.c +++ b/samples/gui/wasm-runtime-wgl/src/platform/zephyr/iwasm_main.c @@ -18,7 +18,7 @@ extern void init_sensor_framework(); extern void exit_sensor_framework(); -extern int aee_host_msg_callback(void *msg, uint16_t msg_len); +extern int aee_host_msg_callback(void *msg, uint32_t msg_len); extern bool touchscreen_read(lv_indev_data_t * data); extern int ili9340_init(); extern void xpt2046_init(void); diff --git a/samples/littlevgl/vgl-wasm-runtime/src/platform/linux/iwasm_main.c b/samples/littlevgl/vgl-wasm-runtime/src/platform/linux/iwasm_main.c index 9b5fa2868..fac649f45 100644 --- a/samples/littlevgl/vgl-wasm-runtime/src/platform/linux/iwasm_main.c +++ b/samples/littlevgl/vgl-wasm-runtime/src/platform/linux/iwasm_main.c @@ -46,7 +46,7 @@ static int baudrate = B115200; extern void init_sensor_framework(); extern void exit_sensor_framework(); extern void exit_connection_framework(); -extern int aee_host_msg_callback(void *msg, uint16_t msg_len); +extern int aee_host_msg_callback(void *msg, uint32_t msg_len); extern bool init_connection_framework(); #ifndef CONNECTION_UART diff --git a/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/iwasm_main.c b/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/iwasm_main.c index cc0111eb3..391e48e04 100644 --- a/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/iwasm_main.c +++ b/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/iwasm_main.c @@ -23,7 +23,7 @@ extern void init_sensor_framework(); extern void exit_sensor_framework(); -extern int aee_host_msg_callback(void *msg, uint16_t msg_len); +extern int aee_host_msg_callback(void *msg, uint32_t msg_len); int uart_char_cnt = 0; diff --git a/samples/simple/src/iwasm_main.c b/samples/simple/src/iwasm_main.c index 41bfbbf07..4d0a355fb 100644 --- a/samples/simple/src/iwasm_main.c +++ b/samples/simple/src/iwasm_main.c @@ -44,7 +44,7 @@ static int baudrate = B115200; extern void init_sensor_framework(); extern void exit_sensor_framework(); extern void exit_connection_framework(); -extern int aee_host_msg_callback(void *msg, uint16_t msg_len); +extern int aee_host_msg_callback(void *msg, uint32_t msg_len); extern bool init_connection_framework(); #ifndef CONNECTION_UART diff --git a/test-tools/host-tool/src/main.c b/test-tools/host-tool/src/main.c index 4918cc779..f2fa8dcda 100644 --- a/test-tools/host-tool/src/main.c +++ b/test-tools/host-tool/src/main.c @@ -30,7 +30,12 @@ #define CONNECTION_MODE_UART 2 typedef enum { - INSTALL, UNINSTALL, QUERY, REQUEST, REGISTER, UNREGISTER + INSTALL, + UNINSTALL, + QUERY, + REQUEST, + REGISTER, + UNREGISTER } op_type; typedef struct { @@ -81,7 +86,8 @@ typedef struct { } operation; typedef enum REPLY_PACKET_TYPE { - REPLY_TYPE_EVENT = 0, REPLY_TYPE_RESPONSE = 1 + REPLY_TYPE_EVENT = 0, + REPLY_TYPE_RESPONSE = 1 } REPLY_PACKET_TYPE; static uint32_t g_timeout_ms = DEFAULT_TIMEOUT_MS; @@ -119,7 +125,7 @@ static int send_request(request_t *request, uint16_t msg_type) /* payload length */ req_size_n = htonl(req_size); if (!host_tool_send_data(g_conn_fd, (char *) &req_size_n, - sizeof(req_size_n))) + sizeof(req_size_n))) goto ret; /* payload */ @@ -128,29 +134,16 @@ static int send_request(request_t *request, uint16_t msg_type) ret = 0; - ret: free_req_resp_packet(req_p); - +ret: + free_req_resp_packet(req_p); return ret; } -/* -static package_type_t get_app_package_type(const char *buf, int size) -{ - if (buf && size > 4) { - if (buf[0] == '\0' && buf[1] == 'a' && buf[2] == 's' && buf[3] == 'm') - return Wasm_Module_Bytecode; - if (buf[0] == '\0' && buf[1] == 'a' && buf[2] == 'o' && buf[3] == 't') - return Wasm_Module_AoT; - } - return Package_Type_Unknown; -} -*/ - #define url_remain_space (sizeof(url) - strlen(url)) -/*return: - 0: success - others: fail*/ +/** + * return: 0: success, others: fail + */ static int install(inst_info *info) { request_t request[1] = { 0 }; @@ -176,13 +169,11 @@ static int install(inst_info *info) snprintf(url + strlen(url), url_remain_space, "&wd=%d", info->watchdog_interval); - /*TODO: permissions to access JLF resource: AUDIO LOCATION SENSOR VISION platform.SERVICE */ - if ((app_file_buf = read_file_to_buffer(info->file, &app_size)) == NULL) return -1; - init_request(request, url, COAP_PUT, - FMT_APP_RAW_BINARY, app_file_buf, app_size); + init_request(request, url, COAP_PUT, FMT_APP_RAW_BINARY, + app_file_buf, app_size); request->mid = gen_random_id(); if (info->module_type == NULL || strcmp(info->module_type, "wasm") == 0) @@ -204,11 +195,10 @@ static int uninstall(uninst_info *info) if (info->module_type != NULL && url_remain_space > 0) snprintf(url + strlen(url), url_remain_space, "&type=%s", - info->module_type); + info->module_type); - init_request(request, url, COAP_DELETE, - FMT_ATTR_CONTAINER, - NULL, 0); + init_request(request, url, COAP_DELETE, FMT_ATTR_CONTAINER, + NULL, 0); request->mid = gen_random_id(); return send_request(request, REQUEST_PACKET); @@ -217,7 +207,6 @@ static int uninstall(uninst_info *info) static int query(query_info *info) { request_t request[1] = { 0 }; - int ret = -1; char url[URL_MAX_LEN] = { 0 }; if (info->name != NULL) @@ -225,14 +214,10 @@ static int query(query_info *info) else snprintf(url, sizeof(url) - 1, "/applet"); - init_request(request, url, COAP_GET, - FMT_ATTR_CONTAINER, - NULL, 0); + init_request(request, url, COAP_GET, FMT_ATTR_CONTAINER, NULL, 0); request->mid = gen_random_id(); - ret = send_request(request, REQUEST_PACKET); - - return ret; + return send_request(request, REQUEST_PACKET); } static int request(req_info *info) @@ -247,7 +232,7 @@ static int request(req_info *info) int payload_file_size; if ((payload_file = read_file_to_buffer(info->json_payload_file, - &payload_file_size)) == NULL) + &payload_file_size)) == NULL) return -1; if (NULL == (json = cJSON_Parse(payload_file))) { @@ -267,7 +252,7 @@ static int request(req_info *info) } init_request(request, (char *)info->url, info->action, - FMT_ATTR_CONTAINER, payload, payload_len); + FMT_ATTR_CONTAINER, payload, payload_len); request->mid = gen_random_id(); ret = send_request(request, REQUEST_PACKET); @@ -275,12 +260,13 @@ static int request(req_info *info) if (info->json_payload_file != NULL && payload != NULL) attr_container_destroy(payload); - fail: return ret; +fail: + return ret; } -/* - TODO: currently only support 1 url. - how to handle multiple responses and set process's exit code? +/** + * TODO: currently only support 1 url. + * how to handle multiple responses and set process's exit code? */ static int subscribe(reg_info *info) { @@ -307,9 +293,8 @@ static int subscribe(reg_info *info) char url[URL_MAX_LEN] = { 0 }; char *prefix = info->urls[0] == '/' ? "/event" : "/event/"; snprintf(url, URL_MAX_LEN, "%s%s", prefix, info->urls); - init_request(request, url, COAP_PUT, - FMT_ATTR_CONTAINER, - NULL, 0); + init_request(request, url, COAP_PUT, FMT_ATTR_CONTAINER, + NULL, 0); request->mid = gen_random_id(); ret = send_request(request, REQUEST_PACKET); #endif @@ -340,9 +325,8 @@ static int unsubscribe(unreg_info *info) #else char url[URL_MAX_LEN] = { 0 }; snprintf(url, URL_MAX_LEN, "%s%s", "/event/", info->urls); - init_request(request, url, COAP_DELETE, - FMT_ATTR_CONTAINER, - NULL, 0); + init_request(request, url, COAP_DELETE, FMT_ATTR_CONTAINER, + NULL, 0); request->mid = gen_random_id(); ret = send_request(request, REQUEST_PACKET); #endif @@ -357,7 +341,8 @@ static int init() return -1; g_conn_fd = fd; return 0; - } else if (g_connection_mode == CONNECTION_MODE_UART) { + } + else if (g_connection_mode == CONNECTION_MODE_UART) { int fd; if (!uart_init(g_uart_dev, g_baudrate, &fd)) return -1; @@ -389,7 +374,6 @@ static int parse_action(const char *str) static void showUsage() { printf("\n"); - /*printf("Usage: host_tool [-i|--install]|[-u|--uninstall]|[-q|--query]|[-r|--request]|[-s|--register]|[-d|--deregister] ...\n");*/ printf("Usage:\n\thost_tool -i|-u|-q|-r|-s|-d ...\n\n"); printf("\thost_tool -i -f \n" @@ -453,26 +437,24 @@ static void showUsage() printf("\t=Watchdog interval in ms.\n"); } -#define CHECK_DUPLICATE_OPERATION do{ \ - if (operation_parsed) \ - { \ - showUsage(); \ - return false; \ - } \ -}while(0) +#define CHECK_DUPLICATE_OPERATION do { \ + if (operation_parsed) { \ + showUsage(); \ + return false; \ + } \ +} while(0) -#define ERROR_RETURN do{ \ - showUsage(); \ - return false; \ -}while(0) +#define ERROR_RETURN do { \ + showUsage(); \ + return false; \ +} while(0) -#define CHECK_ARGS_UNMATCH_OPERATION(op_type) do{ \ - if (!operation_parsed || op->type != op_type) \ - { \ - showUsage(); \ - return false; \ - } \ -}while(0) +#define CHECK_ARGS_UNMATCH_OPERATION(op_type) do { \ + if (!operation_parsed || op->type != op_type) { \ + showUsage(); \ + return false; \ + } \ +} while(0) static bool parse_args(int argc, char *argv[], operation *op) { @@ -509,7 +491,7 @@ static bool parse_args(int argc, char *argv[], operation *op) }; c = getopt_long(argc, argv, "i:u:q::r:s:d:t:a:o:U:A:f:p:S:P:D:B:h", - longOpts, &optIndex); + longOpts, &optIndex); if (c == -1) break; @@ -661,11 +643,10 @@ static bool parse_args(int argc, char *argv[], operation *op) return true; } -/* - return value: - < 0: not complete message - REPLY_TYPE_EVENT: event(request) - REPLY_TYPE_RESPONSE: response +/** + * return value: < 0: not complete message + * REPLY_TYPE_EVENT: event(request) + * REPLY_TYPE_RESPONSE: response */ static int preocess_reply_data(const char *buf, int len, imrt_link_recv_context_t *ctx) @@ -696,6 +677,7 @@ static int preocess_reply_data(const char *buf, int len, break; } } + return -1; } @@ -717,8 +699,8 @@ parse_event_from_imrtlink(imrt_link_message_t *message, request_t *request) return request; } -static void output(const char *header, attr_container_t *payload, int foramt, - int payload_len) +static void output(const char *header, attr_container_t *payload, + int foramt, int payload_len) { cJSON *json = NULL; char *json_str = NULL; @@ -780,7 +762,7 @@ int main(int argc, char *argv[]) if (!parse_args(argc, argv, &op)) return -1; - //TODO: reconnect 3 times + /* TODO: reconnect 3 times */ if (init() != 0) return -1; @@ -853,8 +835,10 @@ int main(int argc, char *argv[]) ret = -1; goto ret; } - } else if (result == 0) { /* select timeout */ - } else if (result > 0) { + } + else if (result == 0) { /* select timeout */ + } + else if (result > 0) { int n; if (FD_ISSET(g_conn_fd, &readfds)) { int reply_type = -1; @@ -886,7 +870,8 @@ int main(int argc, char *argv[]) total_elpased_ms = 0; bh_get_elpased_ms(&last_check); } - } else if (reply_type == REPLY_TYPE_EVENT) { + } + else if (reply_type == REPLY_TYPE_EVENT) { request_t event[1] = { 0 }; parse_event_from_imrtlink(&recv_ctx.message, event); @@ -899,10 +884,10 @@ int main(int argc, char *argv[]) } } /* end of while(1) */ - ret: if (recv_ctx.message.payload != NULL) +ret: + if (recv_ctx.message.payload != NULL) free(recv_ctx.message.payload); deinit(); - return ret; } diff --git a/test-tools/host-tool/src/transport.c b/test-tools/host-tool/src/transport.c index b1fb0e9e2..d63a0fede 100644 --- a/test-tools/host-tool/src/transport.c +++ b/test-tools/host-tool/src/transport.c @@ -115,7 +115,6 @@ bool uart_init(const char *device, int baudrate, int *fd) } *fd = uart_fd; - return true; } @@ -133,11 +132,10 @@ bool udp_send(const char *address, int port, const char *buf, int len) servaddr.sin_port = htons(port); servaddr.sin_addr.s_addr = INADDR_ANY; - sendto(sockfd, buf, len, MSG_CONFIRM, (const struct sockaddr *) &servaddr, - sizeof(servaddr)); + sendto(sockfd, buf, len, MSG_CONFIRM, + (const struct sockaddr *)&servaddr, sizeof(servaddr)); close(sockfd); - return true; } @@ -150,7 +148,8 @@ bool host_tool_send_data(int fd, const char *buf, unsigned int len) return false; } - resend: ret = write(fd, buf, len); +resend: + ret = write(fd, buf, len); if (ret == -1) { if (errno == ECONNRESET) { @@ -192,17 +191,21 @@ int on_imrt_link_byte_arrive(unsigned char ch, imrt_link_recv_context_t *ctx) if (leading[0] == ch) { ctx->phase = Phase_Leading; - } else { + } + else { return -1; } - } else if (ctx->phase == Phase_Leading) { + } + else if (ctx->phase == Phase_Leading) { if (leading[1] == ch) { SET_RECV_PHASE(ctx, Phase_Type); - } else { + } + else { ctx->phase = Phase_Non_Start; return -1; } - } else if (ctx->phase == Phase_Type) { + } + else if (ctx->phase == Phase_Type) { unsigned char *p = (unsigned char *) &ctx->message.message_type; p[ctx->size_in_phase++] = ch; @@ -210,7 +213,8 @@ int on_imrt_link_byte_arrive(unsigned char ch, imrt_link_recv_context_t *ctx) ctx->message.message_type = ntohs(ctx->message.message_type); SET_RECV_PHASE(ctx, Phase_Size); } - } else if (ctx->phase == Phase_Size) { + } + else if (ctx->phase == Phase_Size) { unsigned char * p = (unsigned char *) &ctx->message.payload_size; p[ctx->size_in_phase++] = ch; @@ -237,7 +241,8 @@ int on_imrt_link_byte_arrive(unsigned char ch, imrt_link_recv_context_t *ctx) ctx->message.payload = (char *) malloc(ctx->message.payload_size); SET_RECV_PHASE(ctx, Phase_Payload); } - } else if (ctx->phase == Phase_Payload) { + } + else if (ctx->phase == Phase_Payload) { ctx->message.payload[ctx->size_in_phase++] = ch; if (ctx->size_in_phase == ctx->message.payload_size) { From a4239f1ffd9e594ac1d5cd09ffc5f5290b10b17b Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Sat, 6 Mar 2021 07:30:14 -0600 Subject: [PATCH 159/207] Enable SIMD by default for wamrc and iwasm (#559) Enable SIMD by default for wamrc on x86-64 target, for iwasm on platform Linux and Darwin. And update build wamr document, fix app manager compile warning. Signed-off-by: Wenyong Huang --- core/app-mgr/app-manager/watchdog.c | 2 +- core/app-mgr/app-manager/watchdog.h | 2 +- core/iwasm/compilation/aot_llvm.c | 15 +++++-- doc/build_wamr.md | 46 ++++++++++---------- product-mini/platforms/darwin/CMakeLists.txt | 25 +++++++++++ product-mini/platforms/linux/CMakeLists.txt | 4 +- wamr-compiler/main.c | 11 ++++- 7 files changed, 72 insertions(+), 33 deletions(-) diff --git a/core/app-mgr/app-manager/watchdog.c b/core/app-mgr/app-manager/watchdog.c index e608ef556..6ed88bbdb 100644 --- a/core/app-mgr/app-manager/watchdog.c +++ b/core/app-mgr/app-manager/watchdog.c @@ -125,7 +125,7 @@ bool watchdog_startup() return true; } -bool watchdog_destroy() +void watchdog_destroy() { bh_queue_exit_loop_run(watchdog_queue); bh_queue_destroy(watchdog_queue); diff --git a/core/app-mgr/app-manager/watchdog.h b/core/app-mgr/app-manager/watchdog.h index a11fff3fe..c1478d40e 100644 --- a/core/app-mgr/app-manager/watchdog.h +++ b/core/app-mgr/app-manager/watchdog.h @@ -31,7 +31,7 @@ app_manager_get_watchdog_timer(void *timer); bool watchdog_startup(); -bool +void watchdog_destroy(); #ifdef __cplusplus diff --git a/core/iwasm/compilation/aot_llvm.c b/core/iwasm/compilation/aot_llvm.c index 7c7e73a0c..d5863e4b0 100644 --- a/core/iwasm/compilation/aot_llvm.c +++ b/core/iwasm/compilation/aot_llvm.c @@ -1189,9 +1189,6 @@ aot_create_comp_context(AOTCompData *comp_data, if (option->enable_tail_call) comp_ctx->enable_tail_call = true; - if (option->enable_simd) - comp_ctx->enable_simd = true; - if (option->enable_aux_stack_frame) comp_ctx->enable_aux_stack_frame = true; @@ -1416,10 +1413,18 @@ aot_create_comp_context(AOTCompData *comp_data, } } + if (option->enable_simd + && strcmp(comp_ctx->target_arch, "x86_64") != 0) { + /* Disable simd if it isn't supported by target arch */ + option->enable_simd = false; + } + if (option->enable_simd) { char *tmp; bool ret; + comp_ctx->enable_simd = true; + if (!(tmp = LLVMGetTargetMachineCPU(comp_ctx->target_machine))) { aot_set_last_error("get CPU from Target Machine fail"); goto fail; @@ -1428,7 +1433,9 @@ aot_create_comp_context(AOTCompData *comp_data, ret = aot_check_simd_compatibility(comp_ctx->target_arch, tmp); LLVMDisposeMessage(tmp); if (!ret) { - aot_set_last_error("SIMD compatibility check failed"); + aot_set_last_error("SIMD compatibility check failed, " + "try adding --cpu= to specify a cpu " + "or adding --disable-simd to disable SIMD"); goto fail; } } diff --git a/doc/build_wamr.md b/doc/build_wamr.md index 347f2c0b8..92f04a7b4 100644 --- a/doc/build_wamr.md +++ b/doc/build_wamr.md @@ -20,7 +20,7 @@ The script `runtime_lib.cmake` defines a number of variables for configuring the - **WAMR_BUILD_PLATFORM**: set the target platform. It can be set to any platform name (folder name) under folder [core/shared/platform](../core/shared/platform). - **WAMR_BUILD_TARGET**: set the target CPU architecture. Current supported targets are: X86_64, X86_32, AARCH64, ARM, THUMB, XTENSA, RISCV64 and MIPS. - - For AARCH64, ARM and THUMB, the format is \\[\]\[_VFP], where \ is the ARM sub-architecture and the "_VFP" suffix means using VFP coprocessor registers s0-s15 (d0-d7) for passing arguments or returning results in standard procedure-call. Both \ and "_VFP" are optional, e.g. AARCH64, AARCH64V8, AARCHV8.1, ARMV7, ARMV7_VFP, THUMBV7, THUMBV7_VFP and so on. + - For ARM and THUMB, the format is \\[\]\[_VFP], where \ is the ARM sub-architecture and the "_VFP" suffix means using VFP coprocessor registers s0-s15 (d0-d7) for passing arguments or returning results in standard procedure-call. For AARCH64, the format is\[\], VFP is enabled by default. Both \ and "_VFP" are optional, e.g. AARCH64, AARCH64V8, AARCHV8.1, ARMV7, ARMV7_VFP, THUMBV7, THUMBV7_VFP and so on. - For RISCV64, the format is \[_abi], where "_abi" is optional, currently the supported formats are RISCV64, RISCV64_LP64D and RISCV64_LP64: RISCV64 and RISCV64_LP64D are identical, using [LP64D](https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-elf.md#-named-abis) as abi (LP64 with hardware floating-point calling convention for FLEN=64). And RISCV64_LP64 uses [LP64](https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-elf.md#-named-abis) as abi (Integer calling-convention only, and hardware floating-point calling convention is not used). - For RISCV32, the format is \[_abi], where "_abi" is optional, currently the supported formats are RISCV32, RISCV32_ILP32D and RISCV32_ILP32: RISCV32 and RISCV32_ILP32D are identical, using [ILP32D](https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-elf.md#-named-abis) as abi (ILP32 with hardware floating-point calling convention for FLEN=64). And RISCV32_ILP32 uses [ILP32](https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-elf.md#-named-abis) as abi (Integer calling-convention only, and hardware floating-point calling convention is not used). @@ -30,16 +30,16 @@ cmake -DWAMR_BUILD_PLATFORM=linux -DWAMR_BUILD_TARGET=ARM #### **Configure interpreter** -- **WAMR_BUILD_INTERP**=1/0: enable or disable WASM interpreter +- **WAMR_BUILD_INTERP**=1/0: enable or disable WASM interpreter -- **WAMR_BUILD_FAST_INTERP**=1/0:build fast (default) or classic WASM interpreter. +- **WAMR_BUILD_FAST_INTERP**=1/0: build fast (default) or classic WASM interpreter. NOTE: the fast interpreter runs ~2X faster than classic interpreter, but consumes about 2X memory to hold the WASM bytecode code. #### **Configure AoT and JIT** - **WAMR_BUILD_AOT**=1/0, default to enable if not set -- **WAMR_BUILD_JIT**=1/0 , default to disable if not set +- **WAMR_BUILD_JIT**=1/0, default to disable if not set #### **Configure LIBC** @@ -56,18 +56,6 @@ cmake -DWAMR_BUILD_PLATFORM=linux -DWAMR_BUILD_TARGET=ARM > git clone https://github.com/nodejs/uvwasi.git > ``` -#### **Configure Debug** - -- **WAMR_BUILD_CUSTOM_NAME_SECTION**=1/0, load the function name from custom name section, default to disable if not set - -#### **Enable dump call stack feature** -- **WAMR_BUILD_DUMP_CALL_STACK**=1/0, default to disable if not set - -> Note: if it is enabled, the call stack will be dumped when exception occurs. - -> - For interpreter mode, the function names are firstly extracted from *custom name section*, if this section doesn't exist or the feature is not enabled, then the name will be extracted from the import/export sections -> - For AoT/JIT mode, the function names are extracted from import/export section, please export as many functions as possible (for `wasi-sdk` you can use `-Wl,--export-all`) when compiling wasm module, and add `--enable-dump-call-stack` option to wamrc during compiling AoT module. - #### **Enable Multi-Module feature** - **WAMR_BUILD_MULTI_MODULE**=1/0, default to disable if not set @@ -92,6 +80,25 @@ cmake -DWAMR_BUILD_PLATFORM=linux -DWAMR_BUILD_TARGET=ARM - **WAMR_DISABLE_HW_BOUND_CHECK**=1/0, default to enable if not set and supported by platform > Note: by default only platform linux/darwin/android/vxworks 64-bit will enable boundary check with hardware trap in AOT or JIT mode, and the wamrc tool will generate AOT code without boundary check instructions in all 64-bit targets except SGX to improve performance. +#### **Enable tail call feature** +- **WAMR_BUILD_TAIL_CALL**=1/0, default to disable if not set + +#### **Enable 128-bit SIMD feature** +- **WAMR_BUILD_SIMD**=1/0, default to enable if not set +> Note: only supported in AOT mode x86-64 target. + +#### **Configure Debug** + +- **WAMR_BUILD_CUSTOM_NAME_SECTION**=1/0, load the function name from custom name section, default to disable if not set + +#### **Enable dump call stack feature** +- **WAMR_BUILD_DUMP_CALL_STACK**=1/0, default to disable if not set + +> Note: if it is enabled, the call stack will be dumped when exception occurs. + +> - For interpreter mode, the function names are firstly extracted from *custom name section*, if this section doesn't exist or the feature is not enabled, then the name will be extracted from the import/export sections +> - For AoT/JIT mode, the function names are extracted from import/export section, please export as many functions as possible (for `wasi-sdk` you can use `-Wl,--export-all`) when compiling wasm module, and add `--enable-dump-call-stack` option to wamrc during compiling AoT module. + #### **Enable memory profiling (Experiment)** - **WAMR_BUILD_MEMORY_PROFILING**=1/0, default to disable if not set > Note: if it is enabled, developer can use API `void wasm_runtime_dump_mem_consumption(wasm_exec_env_t exec_env)` to dump the memory consumption info. @@ -107,13 +114,6 @@ Currently we only profile the memory consumption of module, module_instance and - **WAMR_APP_THREAD_STACK_SIZE_MAX**=n, default to 8 MB (8388608) if not set > Note: the AOT boundary check with hardware trap mechanism might consume large stack since the OS may lazily grow the stack mapping as a guard page is hit, we may use this configuration to reduce the total stack usage, e.g. -DWAMR_APP_THREAD_STACK_SIZE_MAX=131072 (128 KB). -#### **Enable tail call feature** -- **WAMR_BUILD_TAIL_CALL**=1/0, default to disable if not set - -#### **Enable 128-bit SIMD feature** -- **WAMR_BUILD_SIMD**=1/0, default to disable if not set -> Note: only supported in AOT mode, and the *--enable-simd* flag should be added for wamrc when generating aot file. - **Combination of configurations:** We can combine the configurations. For example, if we want to disable interpreter, enable AOT and WASI, we can run command: diff --git a/product-mini/platforms/darwin/CMakeLists.txt b/product-mini/platforms/darwin/CMakeLists.txt index 45c6038a6..71f8b5f39 100644 --- a/product-mini/platforms/darwin/CMakeLists.txt +++ b/product-mini/platforms/darwin/CMakeLists.txt @@ -57,6 +57,31 @@ if (NOT DEFINED WAMR_BUILD_LIBC_WASI) set (WAMR_BUILD_LIBC_WASI 0) endif () +if (NOT DEFINED WAMR_BUILD_FAST_INTERP) + # Enable fast interpreter + set (WAMR_BUILD_FAST_INTERP 1) +endif () + +if (NOT DEFINED WAMR_BUILD_MULTI_MODULE) + # Enable multiple modules + set (WAMR_BUILD_MULTI_MODULE 0) +endif () + +if (NOT DEFINED WAMR_BUILD_LIB_PTHREAD) + # Disable pthread library by default + set (WAMR_BUILD_LIB_PTHREAD 0) +endif () + +if (NOT DEFINED WAMR_BUILD_MINI_LOADER) + # Disable wasm mini loader by default + set (WAMR_BUILD_MINI_LOADER 0) +endif () + +if (NOT DEFINED WAMR_BUILD_SIMD) + # Enable SIMD by default + set (WAMR_BUILD_SIMD 1) +endif () + set (CMAKE_SHARED_LINKER_FLAGS "-Wl,-U,_get_ext_lib_export_apis") set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}") diff --git a/product-mini/platforms/linux/CMakeLists.txt b/product-mini/platforms/linux/CMakeLists.txt index e64c2e708..0f8537970 100644 --- a/product-mini/platforms/linux/CMakeLists.txt +++ b/product-mini/platforms/linux/CMakeLists.txt @@ -81,8 +81,8 @@ if (NOT DEFINED WAMR_BUILD_MINI_LOADER) endif () if (NOT DEFINED WAMR_BUILD_SIMD) - # Disable SIMD by default - set (WAMR_BUILD_SIMD 0) + # Enable SIMD by default + set (WAMR_BUILD_SIMD 1) endif () if (COLLECT_CODE_COVERAGE EQUAL 1) diff --git a/wamr-compiler/main.c b/wamr-compiler/main.c index d04941166..fd041d817 100644 --- a/wamr-compiler/main.c +++ b/wamr-compiler/main.c @@ -43,7 +43,10 @@ print_help() printf(" --enable-multi-thread Enable multi-thread feature, the dependent features bulk-memory and\n"); printf(" thread-mgr will be enabled automatically\n"); printf(" --enable-tail-call Enable the post-MVP tail call feature\n"); - printf(" --enable-simd Enable the post-MVP 128-bit SIMD feature\n"); + printf(" --disable-simd Disable the post-MVP 128-bit SIMD feature:\n"); + printf(" currently 128-bit SIMD is only supported for x86-64 target,\n"); + printf(" and by default it is enabled in x86-64 target and disabled\n"); + printf(" in other targets\n"); printf(" --enable-dump-call-stack Enable stack trace feature\n"); printf(" --enable-perf-profiling Enable function performance profiling\n"); printf(" -v=n Set log verbose level (0 to 5, default is 2), larger with more log\n"); @@ -73,7 +76,7 @@ main(int argc, char *argv[]) option.output_format = AOT_FORMAT_FILE; /* default value, enable or disable depends on the platform */ option.bounds_checks = 2; - option.enable_simd = false; + option.enable_simd = true; /* Process options. */ for (argc--, argv++; argc > 0 && argv[0][0] == '-'; argc--, argv++) { @@ -155,8 +158,12 @@ main(int argc, char *argv[]) option.enable_tail_call = true; } else if (!strcmp(argv[0], "--enable-simd")) { + /* obsolete option, kept for compatibility */ option.enable_simd = true; } + else if (!strcmp(argv[0], "--disable-simd")) { + option.enable_simd = false; + } else if (!strcmp(argv[0], "--enable-dump-call-stack")) { option.enable_aux_stack_frame = true; } From a1568825e85f010cec27e0cf6e88617846481d9b Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Sat, 6 Mar 2021 08:29:58 -0600 Subject: [PATCH 160/207] Enable to use BH_VPRINTF macro to redirect stdout output (#560) Enable to use BH_VPRINTF macro for platform Linux/Windows/Darwin/VxWorks to redirect the stdout output from platform os_printf/os_vprintf, or the wasi output from wasm app to the vprintf like callback function specified by BH_VPRINTF macro of cmake WAMR_BH_VPRINTF variable. Signed-off-by: Wenyong Huang --- build-scripts/config_common.cmake | 3 +++ .../libc-uvwasi/libc_uvwasi_wrapper.c | 27 +++++++++++++++++-- .../sandboxed-system-primitives/src/posix.c | 22 +++++++++++++++ core/shared/platform/darwin/platform_init.c | 8 ++++++ .../shared/platform/include/platform_common.h | 12 +++++++-- core/shared/platform/linux/platform_init.c | 8 ++++++ core/shared/platform/vxworks/platform_init.c | 8 ++++++ core/shared/platform/windows/platform_init.c | 27 +++++++++++++++++++ .../platform/windows/platform_internal.h | 3 --- doc/build_wamr.md | 21 +++++++++++++++ 10 files changed, 132 insertions(+), 7 deletions(-) diff --git a/build-scripts/config_common.cmake b/build-scripts/config_common.cmake index b296f89fd..e0ecc5407 100644 --- a/build-scripts/config_common.cmake +++ b/build-scripts/config_common.cmake @@ -202,4 +202,7 @@ if (WAMR_BUILD_TAIL_CALL EQUAL 1) add_definitions (-DWASM_ENABLE_TAIL_CALL=1) message (" Tail call enabled") endif () +if (DEFINED WAMR_BH_VPRINTF) + add_definitions (-DBH_VPRINTF=${WAMR_BH_VPRINTF}) +endif () diff --git a/core/iwasm/libraries/libc-uvwasi/libc_uvwasi_wrapper.c b/core/iwasm/libraries/libc-uvwasi/libc_uvwasi_wrapper.c index 1263b0dc4..af6e0de3d 100644 --- a/core/iwasm/libraries/libc-uvwasi/libc_uvwasi_wrapper.c +++ b/core/iwasm/libraries/libc-uvwasi/libc_uvwasi_wrapper.c @@ -604,8 +604,31 @@ wasi_fd_write(wasm_exec_env_t exec_env, wasi_fd_t fd, ciovec->buf_len = iovec_app->buf_len; } - err = uvwasi_fd_write(uvwasi, fd, - ciovec_begin, iovs_len, &nwritten); +#ifndef BH_VPRINTF + err = uvwasi_fd_write(uvwasi, fd, ciovec_begin, iovs_len, &nwritten); +#else + /* redirect stdout/stderr output to BH_VPRINTF function */ + if (fd == 1 || fd == 2) { + int i; + const struct iovec *iov1 = (const struct iovec *)ciovec_begin; + + nwritten = 0; + for (i = 0; i < (int)iovs_len; i++, iov1++) { + if (iov1->iov_len > 0 && iov1->iov_base) { + char format[16]; + + /* make up format string "%.ns" */ + snprintf(format, sizeof(format), "%%.%ds", (int)iov1->iov_len); + nwritten += (uvwasi_size_t)os_printf(format, iov1->iov_base); + } + } + err = 0; + } + else { + err = uvwasi_fd_write(uvwasi, fd, ciovec_begin, iovs_len, &nwritten); + } +#endif /* end of BH_VPRINTF */ + if (err) goto fail; diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c index 9e4d989f5..6b4cbe20a 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c @@ -1237,7 +1237,29 @@ __wasi_errno_t wasmtime_ssp_fd_write( if (error != 0) return error; +#ifndef BH_VPRINTF ssize_t len = writev(fd_number(fo), (const struct iovec *)iov, (int)iovcnt); +#else + ssize_t len = 0; + /* redirect stdout/stderr output to BH_VPRINTF function */ + if (fd_number(fo) == 1 || fd_number(fo) == 2) { + int i; + const struct iovec *iov1 = (const struct iovec *)iov; + + for (i = 0; i < (int)iovcnt; i++, iov1++) { + if (iov1->iov_len > 0 && iov1->iov_base) { + char format[16]; + + /* make up format string "%.ns" */ + snprintf(format, sizeof(format), "%%.%ds", (int)iov1->iov_len); + len += (ssize_t)os_printf(format, iov1->iov_base); + } + } + } + else { + len = writev(fd_number(fo), (const struct iovec *)iov, (int)iovcnt); + } +#endif /* end of BH_VPRINTF */ fd_object_release(fo); if (len < 0) return convert_errno(errno); diff --git a/core/shared/platform/darwin/platform_init.c b/core/shared/platform/darwin/platform_init.c index 4f806083c..17aeb8baa 100644 --- a/core/shared/platform/darwin/platform_init.c +++ b/core/shared/platform/darwin/platform_init.c @@ -23,7 +23,11 @@ os_printf(const char *format, ...) va_list ap; va_start(ap, format); +#ifndef BH_VPRINTF ret += vprintf(format, ap); +#else + ret += BH_VPRINTF(format, ap); +#endif va_end(ap); return ret; @@ -32,6 +36,10 @@ os_printf(const char *format, ...) int os_vprintf(const char *format, va_list ap) { +#ifndef BH_VPRINTF return vprintf(format, ap); +#else + return BH_VPRINTF(format, ap); +#endif } diff --git a/core/shared/platform/include/platform_common.h b/core/shared/platform/include/platform_common.h index 57b20912b..ca2780206 100644 --- a/core/shared/platform/include/platform_common.h +++ b/core/shared/platform/include/platform_common.h @@ -34,13 +34,21 @@ extern "C" { #endif #if defined(MSVC) -__declspec(dllimport) void *BH_MALLOC(unsigned int size); -__declspec(dllimport) void BH_FREE(void *ptr); +__declspec(dllimport) void *BH_MALLOC(unsigned int size); +__declspec(dllimport) void BH_FREE(void *ptr); #else void *BH_MALLOC(unsigned int size); void BH_FREE(void *ptr); #endif +#if defined(BH_VPRINTF) +#if defined(MSVC) +__declspec(dllimport) int BH_VPRINTF(const char *format, va_list ap); +#else +int BH_VPRINTF(const char *format, va_list ap); +#endif +#endif + #ifndef NULL #define NULL (void*)0 #endif diff --git a/core/shared/platform/linux/platform_init.c b/core/shared/platform/linux/platform_init.c index 4f806083c..17aeb8baa 100644 --- a/core/shared/platform/linux/platform_init.c +++ b/core/shared/platform/linux/platform_init.c @@ -23,7 +23,11 @@ os_printf(const char *format, ...) va_list ap; va_start(ap, format); +#ifndef BH_VPRINTF ret += vprintf(format, ap); +#else + ret += BH_VPRINTF(format, ap); +#endif va_end(ap); return ret; @@ -32,6 +36,10 @@ os_printf(const char *format, ...) int os_vprintf(const char *format, va_list ap) { +#ifndef BH_VPRINTF return vprintf(format, ap); +#else + return BH_VPRINTF(format, ap); +#endif } diff --git a/core/shared/platform/vxworks/platform_init.c b/core/shared/platform/vxworks/platform_init.c index 4f806083c..17aeb8baa 100644 --- a/core/shared/platform/vxworks/platform_init.c +++ b/core/shared/platform/vxworks/platform_init.c @@ -23,7 +23,11 @@ os_printf(const char *format, ...) va_list ap; va_start(ap, format); +#ifndef BH_VPRINTF ret += vprintf(format, ap); +#else + ret += BH_VPRINTF(format, ap); +#endif va_end(ap); return ret; @@ -32,6 +36,10 @@ os_printf(const char *format, ...) int os_vprintf(const char *format, va_list ap) { +#ifndef BH_VPRINTF return vprintf(format, ap); +#else + return BH_VPRINTF(format, ap); +#endif } diff --git a/core/shared/platform/windows/platform_init.c b/core/shared/platform/windows/platform_init.c index 76594b816..17aeb8baa 100644 --- a/core/shared/platform/windows/platform_init.c +++ b/core/shared/platform/windows/platform_init.c @@ -16,3 +16,30 @@ bh_platform_destroy() { } +int +os_printf(const char *format, ...) +{ + int ret = 0; + va_list ap; + + va_start(ap, format); +#ifndef BH_VPRINTF + ret += vprintf(format, ap); +#else + ret += BH_VPRINTF(format, ap); +#endif + va_end(ap); + + return ret; +} + +int +os_vprintf(const char *format, va_list ap) +{ +#ifndef BH_VPRINTF + return vprintf(format, ap); +#else + return BH_VPRINTF(format, ap); +#endif +} + diff --git a/core/shared/platform/windows/platform_internal.h b/core/shared/platform/windows/platform_internal.h index 65a933ac3..877336be5 100644 --- a/core/shared/platform/windows/platform_internal.h +++ b/core/shared/platform/windows/platform_internal.h @@ -49,9 +49,6 @@ typedef struct { unsigned int waiting_count; } korp_cond; -#define os_printf printf -#define os_vprintf vprintf - static inline size_t getpagesize() { diff --git a/doc/build_wamr.md b/doc/build_wamr.md index 92f04a7b4..c18fbcb23 100644 --- a/doc/build_wamr.md +++ b/doc/build_wamr.md @@ -114,6 +114,27 @@ Currently we only profile the memory consumption of module, module_instance and - **WAMR_APP_THREAD_STACK_SIZE_MAX**=n, default to 8 MB (8388608) if not set > Note: the AOT boundary check with hardware trap mechanism might consume large stack since the OS may lazily grow the stack mapping as a guard page is hit, we may use this configuration to reduce the total stack usage, e.g. -DWAMR_APP_THREAD_STACK_SIZE_MAX=131072 (128 KB). +#### **WAMR_BH_VPRINTF**=, default to disable if not set +> Note: if the vprintf_callback function is provided by developer, the os_printf() and os_vprintf() in Linux, Darwin, Windows and VxWorks platforms, besides WASI Libc output will call the callback function instead of libc vprintf() function to redirect the stdout output. For example, developer can define the callback function like below outside runtime lib: +> +> ```C +> int my_vprintf(const char *format, va_list ap) +> { +> /* output to pre-opened file stream */ +> FILE *my_file = ...; +> return vfprintf(my_file, format, ap); +> /* or output to pre-opened file descriptor */ +> int my_fd = ...; +> return vdprintf(my_fd, format, ap); +> /* or output to string buffer and print the string */ +> char buf[128]; +> vsnprintf(buf, sizeof(buf), format, ap); +> return my_printf("%s", buf); +> } +> ``` +> +> and then use `cmake -DWAMR_BH_VPRINTF=my_vprintf ..` to pass the callback function, or add `BH_VPRINTF=my_vprintf` macro for the compiler, e.g. add line `add_defintions(-DBH_VPRINTF=my_vprintf)` in CMakeListst.txt. + **Combination of configurations:** We can combine the configurations. For example, if we want to disable interpreter, enable AOT and WASI, we can run command: From e9e75a6b09a40f7f539dde0b95aa7f1d1931c41e Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Wed, 10 Mar 2021 15:07:16 +0800 Subject: [PATCH 161/207] Fix interpreter not update memory size after call native func (#563) The native function might call wasm function exported, in which the memory.grow opcode might be executed, and interpreter should update memory size after that, or load/store opcodes may run failed with "out of bounds memory access" exception thrown. Update tensorflow sample patch, allow tensorflow wasm app to grow memory so as to run more models. And fix some compile issues of littlevgl zephyr sample for latest zephyr source code. Signed-off-by: Wenyong Huang --- core/iwasm/interpreter/wasm_interp_classic.c | 5 +- core/iwasm/interpreter/wasm_interp_fast.c | 5 +- .../src/platform/zephyr/XPT2046.c | 3 +- .../src/platform/zephyr/display.h | 87 +++++++++++-------- .../src/platform/zephyr/display_ili9340.c | 87 +++++++++++-------- .../src/platform/zephyr/display_ili9340.h | 4 +- .../zephyr/display_ili9340_adafruit_1480.c | 2 +- .../src/platform/zephyr/display_indev.c | 6 +- samples/workload/tensorflow/tf_lite.patch | 9 +- 9 files changed, 123 insertions(+), 85 deletions(-) diff --git a/core/iwasm/interpreter/wasm_interp_classic.c b/core/iwasm/interpreter/wasm_interp_classic.c index bf39335ee..c3ccf2d94 100644 --- a/core/iwasm/interpreter/wasm_interp_classic.c +++ b/core/iwasm/interpreter/wasm_interp_classic.c @@ -1868,7 +1868,7 @@ label_pop_csp_n: else { /* success, return previous page count */ PUSH_I32(prev_page_count); - /* update the memory instance ptr */ + /* update memory instance ptr and memory size */ memory = module->default_memory; linear_mem_size = num_bytes_per_page * memory->cur_page_count; } @@ -3209,7 +3209,10 @@ label_pop_csp_n: cur_func = frame->function; UPDATE_ALL_FROM_FRAME(); + /* update memory instance ptr and memory size */ memory = module->default_memory; + if (memory) + linear_mem_size = num_bytes_per_page * memory->cur_page_count; if (wasm_get_exception(module)) goto got_exception; } diff --git a/core/iwasm/interpreter/wasm_interp_fast.c b/core/iwasm/interpreter/wasm_interp_fast.c index de157f8c1..5f5dd5f1d 100644 --- a/core/iwasm/interpreter/wasm_interp_fast.c +++ b/core/iwasm/interpreter/wasm_interp_fast.c @@ -1784,7 +1784,7 @@ recover_br_info: else { /* success, return previous page count */ frame_lp[addr_ret] = prev_page_count; - /* update the memory instance ptr */ + /* update memory instance ptr and memory size */ memory = module->default_memory; linear_mem_size = num_bytes_per_page * memory->cur_page_count; } @@ -3257,7 +3257,10 @@ recover_br_info: cur_func = frame->function; UPDATE_ALL_FROM_FRAME(); + /* update memory instance ptr and memory size */ memory = module->default_memory; + if (memory) + linear_mem_size = num_bytes_per_page * memory->cur_page_count; if (wasm_get_exception(module)) goto got_exception; } diff --git a/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/XPT2046.c b/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/XPT2046.c index 11d356221..8c5e84270 100644 --- a/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/XPT2046.c +++ b/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/XPT2046.c @@ -72,8 +72,9 @@ K_MUTEX_DEFINE( spi_display_touch_mutex); int cnt = 0; int touch_read_times = 0; int last_pen_interrupt_time = 0; + void xpt2046_pen_gpio_callback(struct device *port, struct gpio_callback *cb, - u32_t pins) + uint32_t pins) { cnt++; if ((k_uptime_get_32() - last_pen_interrupt_time) > 500) { diff --git a/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display.h b/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display.h index b820b9ce9..113c1ed67 100644 --- a/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display.h +++ b/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display.h @@ -28,9 +28,11 @@ extern "C" { #endif enum display_pixel_format { - PIXEL_FORMAT_RGB_888 = BIT(0), PIXEL_FORMAT_MONO01 = BIT(1), /* 0=Black 1=White */ + PIXEL_FORMAT_RGB_888 = BIT(0), + PIXEL_FORMAT_MONO01 = BIT(1), /* 0=Black 1=White */ PIXEL_FORMAT_MONO10 = BIT(2), /* 1=Black 0=White */ - PIXEL_FORMAT_ARGB_8888 = BIT(3), PIXEL_FORMAT_RGB_565 = BIT(4), + PIXEL_FORMAT_ARGB_8888 = BIT(3), + PIXEL_FORMAT_RGB_565 = BIT(4), }; enum display_screen_info { @@ -90,10 +92,10 @@ enum display_orientation { * */ struct display_capabilities { - u16_t x_resolution; - u16_t y_resolution; - u32_t supported_pixel_formats; - u32_t screen_info; + uint16_t x_resolution; + uint16_t y_resolution; + uint32_t supported_pixel_formats; + uint32_t screen_info; enum display_pixel_format current_pixel_format; enum display_orientation current_orientation; }; @@ -116,10 +118,10 @@ struct display_capabilities { * */ struct display_buffer_descriptor { - u32_t buf_size; - u16_t width; - u16_t height; - u16_t pitch; + uint32_t buf_size; + uint16_t width; + uint16_t height; + uint16_t pitch; }; /** @@ -141,17 +143,20 @@ typedef int (*display_blanking_off_api)(const struct device *dev); * @brief Callback API for writing data to the display * See display_write() for argument description */ -typedef int (*display_write_api)(const struct device *dev, const u16_t x, - const u16_t y, const struct display_buffer_descriptor *desc, - const void *buf); +typedef int (*display_write_api)(const struct device *dev, + const uint16_t x, const uint16_t y, + const struct display_buffer_descriptor *desc, + const void *buf); /** * @typedef display_read_api * @brief Callback API for reading data from the display * See display_read() for argument description */ -typedef int (*display_read_api)(const struct device *dev, const u16_t x, - const u16_t y, const struct display_buffer_descriptor *desc, void *buf); +typedef int (*display_read_api)(const struct device *dev, + const uint16_t x, const uint16_t y, + const struct display_buffer_descriptor *desc, + void *buf); /** * @typedef display_get_framebuffer_api @@ -166,7 +171,7 @@ typedef void *(*display_get_framebuffer_api)(const struct device *dev); * See display_set_brightness() for argument description */ typedef int (*display_set_brightness_api)(const struct device *dev, - const u8_t brightness); + const uint8_t brightness); /** * @typedef display_set_contrast_api @@ -174,7 +179,7 @@ typedef int (*display_set_brightness_api)(const struct device *dev, * See display_set_contrast() for argument description */ typedef int (*display_set_contrast_api)(const struct device *dev, - const u8_t contrast); + const uint8_t contrast); /** * @typedef display_get_capabilities_api @@ -182,7 +187,7 @@ typedef int (*display_set_contrast_api)(const struct device *dev, * See display_get_capabilities() for argument description */ typedef void (*display_get_capabilities_api)(const struct device *dev, - struct display_capabilities * capabilities); + struct display_capabilities * capabilities); /** * @typedef display_set_pixel_format_api @@ -190,7 +195,7 @@ typedef void (*display_get_capabilities_api)(const struct device *dev, * See display_set_pixel_format() for argument description */ typedef int (*display_set_pixel_format_api)(const struct device *dev, - const enum display_pixel_format pixel_format); + const enum display_pixel_format pixel_format); /** * @typedef display_set_orientation_api @@ -198,7 +203,7 @@ typedef int (*display_set_pixel_format_api)(const struct device *dev, * See display_set_orientation() for argument description */ typedef int (*display_set_orientation_api)(const struct device *dev, - const enum display_orientation orientation); + const enum display_orientation orientation); /** * @brief Display driver API @@ -229,9 +234,9 @@ extern struct display_driver_api ili9340_api1; * * @retval 0 on success else negative errno code. */ -static inline int display_write(const struct device *dev, const u16_t x, - const u16_t y, const struct display_buffer_descriptor *desc, - const void *buf) +static inline int +display_write(const struct device *dev, const uint16_t x, const uint16_t y, + const struct display_buffer_descriptor *desc, const void *buf) { struct display_driver_api *api = &ili9340_api1; //(struct display_driver_api *)dev->driver_api; @@ -250,8 +255,9 @@ static inline int display_write(const struct device *dev, const u16_t x, * * @retval 0 on success else negative errno code. */ -static inline int display_read(const struct device *dev, const u16_t x, - const u16_t y, const struct display_buffer_descriptor *desc, void *buf) +static inline int +display_read(const struct device *dev, const uint16_t x, const uint16_t y, + const struct display_buffer_descriptor *desc, void *buf) { struct display_driver_api *api = &ili9340_api1; //(struct display_driver_api *)dev->driver_api; @@ -268,7 +274,8 @@ static inline int display_read(const struct device *dev, const u16_t x, * is not supported * */ -static inline void *display_get_framebuffer(const struct device *dev) +static inline void * +display_get_framebuffer(const struct device *dev) { struct display_driver_api *api = &ili9340_api1; //(struct display_driver_api *)dev->driver_api; @@ -283,7 +290,8 @@ static inline void *display_get_framebuffer(const struct device *dev) * * @retval 0 on success else negative errno code. */ -static inline int display_blanking_on(const struct device *dev) +static inline int +display_blanking_on(const struct device *dev) { struct display_driver_api *api = &ili9340_api1; //(struct display_driver_api *)dev->driver_api; @@ -298,7 +306,8 @@ static inline int display_blanking_on(const struct device *dev) * * @retval 0 on success else negative errno code. */ -static inline int display_blanking_off(const struct device *dev) +static inline int +display_blanking_off(const struct device *dev) { struct display_driver_api *api = &ili9340_api1; //(struct display_driver_api *)dev->driver_api; @@ -317,8 +326,8 @@ static inline int display_blanking_off(const struct device *dev) * * @retval 0 on success else negative errno code. */ -static inline int display_set_brightness(const struct device *dev, - u8_t brightness) +static inline int +display_set_brightness(const struct device *dev, uint8_t brightness) { struct display_driver_api *api = &ili9340_api1; //(struct display_driver_api *)dev->driver_api; @@ -337,7 +346,8 @@ static inline int display_set_brightness(const struct device *dev, * * @retval 0 on success else negative errno code. */ -static inline int display_set_contrast(const struct device *dev, u8_t contrast) +static inline int +display_set_contrast(const struct device *dev, uint8_t contrast) { struct display_driver_api *api = &ili9340_api1; //(struct display_driver_api *)dev->driver_api; @@ -351,8 +361,9 @@ static inline int display_set_contrast(const struct device *dev, u8_t contrast) * @param dev Pointer to device structure * @param capabilities Pointer to capabilities structure to populate */ -static inline void display_get_capabilities(const struct device *dev, - struct display_capabilities * capabilities) +static inline void +display_get_capabilities(const struct device *dev, + struct display_capabilities * capabilities) { struct display_driver_api *api = &ili9340_api1; //(struct display_driver_api *)dev->driver_api; @@ -368,8 +379,9 @@ static inline void display_get_capabilities(const struct device *dev, * * @retval 0 on success else negative errno code. */ -static inline int display_set_pixel_format(const struct device *dev, - const enum display_pixel_format pixel_format) +static inline int +display_set_pixel_format(const struct device *dev, + const enum display_pixel_format pixel_format) { struct display_driver_api *api = &ili9340_api1; //(struct display_driver_api *)dev->driver_api; @@ -385,8 +397,9 @@ static inline int display_set_pixel_format(const struct device *dev, * * @retval 0 on success else negative errno code. */ -static inline int display_set_orientation(const struct device *dev, - const enum display_orientation orientation) +static inline int +display_set_orientation(const struct device *dev, + const enum display_orientation orientation) { struct display_driver_api *api = &ili9340_api1; //(struct display_driver_api *)dev->driver_api; diff --git a/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_ili9340.c b/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_ili9340.c index 4d4ed390b..352c51a0b 100644 --- a/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_ili9340.c +++ b/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_ili9340.c @@ -35,15 +35,18 @@ struct ili9340_data ili9340_data1; #define ILI9340_CMD_DATA_PIN_COMMAND 0 #define ILI9340_CMD_DATA_PIN_DATA 1 -static void ili9340_exit_sleep(struct ili9340_data *data) +static void +ili9340_exit_sleep(struct ili9340_data *data) { ili9340_transmit(data, ILI9340_CMD_EXIT_SLEEP, NULL, 0); //k_sleep(Z_TIMEOUT_MS(120)); } -int ili9340_init() +int +ili9340_init() { struct ili9340_data *data = &ili9340_data1; + printf("Initializing display driver\n"); data->spi_dev = device_get_binding(DT_ILITEK_ILI9340_0_BUS_NAME); if (data->spi_dev == NULL) { @@ -97,10 +100,12 @@ int ili9340_init() return 0; } -static void ili9340_set_mem_area(struct ili9340_data *data, const u16_t x, - const u16_t y, const u16_t w, const u16_t h) +static void +ili9340_set_mem_area(struct ili9340_data *data, + const uint16_t x, const uint16_t y, + const uint16_t w, const uint16_t h) { - u16_t spi_data[2]; + uint16_t spi_data[2]; spi_data[0] = sys_cpu_to_be16(x); spi_data[1] = sys_cpu_to_be16(x + w - 1); @@ -111,16 +116,17 @@ static void ili9340_set_mem_area(struct ili9340_data *data, const u16_t x, ili9340_transmit(data, ILI9340_CMD_PAGE_ADDR, &spi_data[0], 4); } -static int ili9340_write(const struct device *dev, const u16_t x, const u16_t y, - const struct display_buffer_descriptor *desc, const void *buf) +static int +ili9340_write(const struct device *dev, const uint16_t x, const uint16_t y, + const struct display_buffer_descriptor *desc, const void *buf) { struct ili9340_data *data = (struct ili9340_data *) &ili9340_data1; - const u8_t *write_data_start = (u8_t *) buf; + const uint8_t *write_data_start = (uint8_t *) buf; struct spi_buf tx_buf; struct spi_buf_set tx_bufs; - u16_t write_cnt; - u16_t nbr_of_writes; - u16_t write_h; + uint16_t write_cnt; + uint16_t nbr_of_writes; + uint16_t write_h; __ASSERT(desc->width <= desc->pitch, "Pitch is smaller then width"); __ASSERT((3 * desc->pitch * desc->height) <= desc->buf_size, @@ -151,62 +157,69 @@ static int ili9340_write(const struct device *dev, const u16_t x, const u16_t y, return 0; } -static int ili9340_read(const struct device *dev, const u16_t x, const u16_t y, - const struct display_buffer_descriptor *desc, void *buf) +static int +ili9340_read(const struct device *dev, const uint16_t x, const uint16_t y, + const struct display_buffer_descriptor *desc, void *buf) { LOG_ERR("Reading not supported\n"); return -ENOTSUP; } -static void *ili9340_get_framebuffer(const struct device *dev) +static void * +ili9340_get_framebuffer(const struct device *dev) { LOG_ERR("Direct framebuffer access not supported\n"); return NULL; } -static int ili9340_display_blanking_off(const struct device *dev) +static int +ili9340_display_blanking_off(const struct device *dev) { - struct ili9340_data *data = (struct ili9340_data *) dev->driver_data; + struct ili9340_data *data = (struct ili9340_data *)dev->data; LOG_DBG("Turning display blanking off\n"); ili9340_transmit(data, ILI9340_CMD_DISPLAY_ON, NULL, 0); return 0; } -static int ili9340_display_blanking_on(const struct device *dev) +static int +ili9340_display_blanking_on(const struct device *dev) { - struct ili9340_data *data = (struct ili9340_data *) dev->driver_data; + struct ili9340_data *data = (struct ili9340_data *)dev->data; LOG_DBG("Turning display blanking on\n"); ili9340_transmit(data, ILI9340_CMD_DISPLAY_OFF, NULL, 0); return 0; } -static int ili9340_set_brightness(const struct device *dev, - const u8_t brightness) +static int +ili9340_set_brightness(const struct device *dev, const uint8_t brightness) { LOG_WRN("Set brightness not implemented\n"); return -ENOTSUP; } -static int ili9340_set_contrast(const struct device *dev, const u8_t contrast) +static int +ili9340_set_contrast(const struct device *dev, const uint8_t contrast) { LOG_ERR("Set contrast not supported\n"); return -ENOTSUP; } -static int ili9340_set_pixel_format(const struct device *dev, - const enum display_pixel_format pixel_format) +static int +ili9340_set_pixel_format(const struct device *dev, + const enum display_pixel_format pixel_format) { if (pixel_format == PIXEL_FORMAT_RGB_888) { - return 0; -} + return 0; + } LOG_ERR("Pixel format change not implemented\n"); return -ENOTSUP; } -static int ili9340_set_orientation(const struct device *dev, - const enum display_orientation orientation) +static int +ili9340_set_orientation(const struct device *dev, + const enum display_orientation orientation) { if (orientation == DISPLAY_ORIENTATION_NORMAL) { return 0; @@ -215,8 +228,9 @@ static int ili9340_set_orientation(const struct device *dev, return -ENOTSUP; } -static void ili9340_get_capabilities(const struct device *dev, - struct display_capabilities *capabilities) +static void +ili9340_get_capabilities(const struct device *dev, + struct display_capabilities *capabilities) { memset(capabilities, 0, sizeof(struct display_capabilities)); capabilities->x_resolution = 320; @@ -226,13 +240,14 @@ static void ili9340_get_capabilities(const struct device *dev, capabilities->current_orientation = DISPLAY_ORIENTATION_NORMAL; } -void ili9340_transmit(struct ili9340_data *data, u8_t cmd, void *tx_data, - size_t tx_len) +void +ili9340_transmit(struct ili9340_data *data, uint8_t cmd, + void *tx_data, size_t tx_len) { - data = (struct ili9340_data *) &ili9340_data1; struct spi_buf tx_buf = { .buf = &cmd, .len = 1 }; struct spi_buf_set tx_bufs = { .buffers = &tx_buf, .count = 1 }; + data = (struct ili9340_data *) &ili9340_data1; gpio_pin_set(data->command_data_gpio, DT_ILITEK_ILI9340_0_CMD_DATA_GPIOS_PIN, ILI9340_CMD_DATA_PIN_COMMAND); spi_transceive(data->spi_dev, &data->spi_config, &tx_bufs, NULL); @@ -260,7 +275,7 @@ struct display_driver_api ili9340_api1 = { }; /* - DEVICE_AND_API_INIT(ili9340, DT_ILITEK_ILI9340_0_LABEL, &ili9340_init, - &ili9340_data, NULL, APPLICATION, - CONFIG_APPLICATION_INIT_PRIORITY, &ili9340_api); - */ +DEVICE_AND_API_INIT(ili9340, DT_ILITEK_ILI9340_0_LABEL, &ili9340_init, + &ili9340_data, NULL, APPLICATION, + CONFIG_APPLICATION_INIT_PRIORITY, &ili9340_api); +*/ diff --git a/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_ili9340.h b/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_ili9340.h index 8aab97a65..27f2cff09 100644 --- a/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_ili9340.h +++ b/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_ili9340.h @@ -52,8 +52,8 @@ struct ili9340_data; * @param tx_len Number of bytes in tx_data buffer * */ -void ili9340_transmit(struct ili9340_data *data, u8_t cmd, void *tx_data, - size_t tx_len); +void ili9340_transmit(struct ili9340_data *data, uint8_t cmd, + void *tx_data, size_t tx_len); /** * Perform LCD specific initialization diff --git a/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_ili9340_adafruit_1480.c b/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_ili9340_adafruit_1480.c index a8581a72d..b55121ce5 100644 --- a/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_ili9340_adafruit_1480.c +++ b/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_ili9340_adafruit_1480.c @@ -8,7 +8,7 @@ void ili9340_lcd_init(struct ili9340_data *data) { - u8_t tx_data[15]; + uint8_t tx_data[15]; tx_data[0] = 0x23; ili9340_transmit(data, ILI9340_CMD_POWER_CTRL_1, tx_data, 1); diff --git a/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_indev.c b/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_indev.c index 6701ceebb..6e96cff2d 100644 --- a/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_indev.c +++ b/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_indev.c @@ -43,8 +43,8 @@ display_flush(wasm_exec_env_t exec_env, color, sizeof(lv_color_t))) return; - u16_t w = x2 - x1 + 1; - u16_t h = y2 - y1 + 1; + uint16_t w = x2 - x1 + 1; + uint16_t h = y2 - y1 + 1; desc.buf_size = 3 * w * h; desc.width = w; @@ -93,7 +93,7 @@ display_vdb_write(wasm_exec_env_t exec_env, lv_color_t *color, lv_opa_t opa) { wasm_module_inst_t module_inst = get_module_inst(exec_env); - u8_t *buf_xy = (u8_t*)buf + 3 * x + 3 * y * buf_w; + uint8_t *buf_xy = (uint8_t*)buf + 3 * x + 3 * y * buf_w; if (!wasm_runtime_validate_native_addr(module_inst, color, sizeof(lv_color_t))) diff --git a/samples/workload/tensorflow/tf_lite.patch b/samples/workload/tensorflow/tf_lite.patch index f83c1d952..4d510b1be 100644 --- a/samples/workload/tensorflow/tf_lite.patch +++ b/samples/workload/tensorflow/tf_lite.patch @@ -1,5 +1,5 @@ diff --git a/tensorflow/lite/tools/make/Makefile b/tensorflow/lite/tools/make/Makefile -index c7ddff58440..ed69c452b67 100644 +index c7ddff58440..ebfebaead35 100644 --- a/tensorflow/lite/tools/make/Makefile +++ b/tensorflow/lite/tools/make/Makefile @@ -48,11 +48,7 @@ INCLUDES += -I/usr/local/include @@ -15,7 +15,7 @@ index c7ddff58440..ed69c452b67 100644 -ldl # There are no rules for compiling objects for the host system (since we don't -@@ -84,14 +80,21 @@ endif # ifeq ($(HOST_ARCH),$(TARGET_ARCH)) +@@ -84,14 +80,24 @@ endif # ifeq ($(HOST_ARCH),$(TARGET_ARCH)) endif # ifeq ($(HOST_OS),$(TARGET)) endif @@ -23,6 +23,9 @@ index c7ddff58440..ed69c452b67 100644 +CXXFLAGS+=-msimd128 + +LIBFLAGS += -s TOTAL_STACK=1048576 \ ++ -s INITIAL_MEMORY=16777216 \ ++ -s MAXIMUM_MEMORY=167772160 \ ++ -s ALLOW_MEMORY_GROWTH=1 \ + -Wl,--export=__data_end -Wl,--export=__heap_base \ + -s ERROR_ON_UNDEFINED_SYMBOLS=0 + @@ -39,7 +42,7 @@ index c7ddff58440..ed69c452b67 100644 # A small example program that shows how to link against the library. MINIMAL_SRCS := \ -@@ -277,12 +280,16 @@ LIB_PATH := $(LIBDIR)$(LIB_NAME) +@@ -277,12 +283,16 @@ LIB_PATH := $(LIBDIR)$(LIB_NAME) BENCHMARK_LIB := $(LIBDIR)$(BENCHMARK_LIB_NAME) BENCHMARK_BINARY := $(BINDIR)$(BENCHMARK_BINARY_NAME) BENCHMARK_PERF_OPTIONS_BINARY := $(BINDIR)$(BENCHMARK_PERF_OPTIONS_BINARY_NAME) From 9327f20ae2d2a81ebca8c43809f357311058644d Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Wed, 10 Mar 2021 16:08:50 +0800 Subject: [PATCH 162/207] Upgrade llvm version from 10.x to 11.x for wamrc and iwasm JIT (#564) Upgrade it as the latest version of wasi-sdk and emsdk are based on llvm-11, align to it to use the same compiler version. And this also fixes compilation error when building wamrc with llvm-10 in Windows platform. Signed-off-by: Wenyong Huang --- doc/build_wamr.md | 2 ++ product-mini/platforms/linux/build_llvm.sh | 2 +- wamr-compiler/build_llvm.py | 2 +- wamr-compiler/build_llvm.sh | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/doc/build_wamr.md b/doc/build_wamr.md index c18fbcb23..3ea474289 100644 --- a/doc/build_wamr.md +++ b/doc/build_wamr.md @@ -240,6 +240,8 @@ Make sure `MSVC` and `cmake` are installed and available in the command line env Then build the source codes: ``` Bash +cd core/deps/ +git clone https://github.com/nodejs/uvwasi.git cd product-mini/platforms/windows/ mkdir build cd build diff --git a/product-mini/platforms/linux/build_llvm.sh b/product-mini/platforms/linux/build_llvm.sh index 7821eeedf..f4e4ee533 100755 --- a/product-mini/platforms/linux/build_llvm.sh +++ b/product-mini/platforms/linux/build_llvm.sh @@ -8,7 +8,7 @@ DEPS_DIR=${PWD}/../../../core/deps cd ${DEPS_DIR} if [ ! -d "llvm" ]; then echo "Clone llvm to core/deps/ .." - git clone --depth 1 --branch release/10.x https://github.com/llvm/llvm-project.git llvm + git clone --depth 1 --branch release/11.x https://github.com/llvm/llvm-project.git llvm fi cd llvm diff --git a/wamr-compiler/build_llvm.py b/wamr-compiler/build_llvm.py index d9912af2f..34ae7b03f 100644 --- a/wamr-compiler/build_llvm.py +++ b/wamr-compiler/build_llvm.py @@ -12,7 +12,7 @@ def clone_llvm(): llvm_dir = Path("llvm") if(llvm_dir.exists() == False): print("Clone llvm to core/deps/ ..") - for line in os.popen("git clone --branch release/10.x https://github.com/llvm/llvm-project.git llvm"): + for line in os.popen("git clone --branch release/11.x https://github.com/llvm/llvm-project.git llvm"): print(line) else: print("llvm source codes already existed") diff --git a/wamr-compiler/build_llvm.sh b/wamr-compiler/build_llvm.sh index 98f7a6767..7960e3646 100755 --- a/wamr-compiler/build_llvm.sh +++ b/wamr-compiler/build_llvm.sh @@ -8,7 +8,7 @@ DEPS_DIR=${PWD}/../core/deps cd ${DEPS_DIR} if [ ! -d "llvm" ]; then echo "Clone llvm to core/deps/ .." - git clone --depth 1 --branch release/10.x https://github.com/llvm/llvm-project.git llvm + git clone --depth 1 --branch release/11.x https://github.com/llvm/llvm-project.git llvm fi cd llvm From b06ae7272f40df297fe96a30bbb9b6ff8259e0b4 Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Wed, 10 Mar 2021 16:25:07 +0800 Subject: [PATCH 163/207] Remove heap size check when creating wasi ctx (#565) Remove check for heap_size==0 when creating wasi ctx, as the related data structures are allocated from global heap instead of app heap now, so it also works when app heap isn't created. Also add v128 type for Windows so as to fix wamrc compilation error in Windows platform. Signed-off-by: Wenyong Huang --- core/iwasm/aot/aot_runtime.c | 21 ++++++++++----------- core/iwasm/common/wasm_runtime_common.c | 13 +++++++++++++ core/iwasm/include/wasm_export.h | 3 +-- core/iwasm/interpreter/wasm_runtime.c | 21 ++++++++++----------- 4 files changed, 34 insertions(+), 24 deletions(-) diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index 38c91d58e..772518efd 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -879,17 +879,16 @@ aot_instantiate(AOTModule *module, bool is_sub_inst, #if WASM_ENABLE_LIBC_WASI != 0 if (!is_sub_inst) { - if (heap_size > 0 - && !wasm_runtime_init_wasi((WASMModuleInstanceCommon*)module_inst, - module->wasi_args.dir_list, - module->wasi_args.dir_count, - module->wasi_args.map_dir_list, - module->wasi_args.map_dir_count, - module->wasi_args.env, - module->wasi_args.env_count, - module->wasi_args.argv, - module->wasi_args.argc, - error_buf, error_buf_size)) + if (!wasm_runtime_init_wasi((WASMModuleInstanceCommon*)module_inst, + module->wasi_args.dir_list, + module->wasi_args.dir_count, + module->wasi_args.map_dir_list, + module->wasi_args.map_dir_count, + module->wasi_args.env, + module->wasi_args.env_count, + module->wasi_args.argv, + module->wasi_args.argc, + error_buf, error_buf_size)) goto fail; } #endif diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index 1e7e363dc..f863fb4d3 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -3400,8 +3400,21 @@ fail: #undef v128 #endif +#if defined(_WIN32) || defined(_WIN32_) +typedef union __declspec(intrin_type) __declspec(align(1)) v128 { + __int8 m128i_i8[16]; + __int16 m128i_i16[8]; + __int32 m128i_i32[4]; + __int64 m128i_i64[2]; + unsigned __int8 m128i_u8[16]; + unsigned __int16 m128i_u16[8]; + unsigned __int32 m128i_u32[4]; + unsigned __int64 m128i_u64[2]; +} v128; +#else typedef long long v128 __attribute__ ((__vector_size__ (16), __may_alias__, __aligned__ (1))); +#endif /* end of defined(_WIN32) || defined(_WIN32_) */ #endif /* end of WASM_ENABLE_SIMD != 0 */ diff --git a/core/iwasm/include/wasm_export.h b/core/iwasm/include/wasm_export.h index d8f585fc4..768ee36ea 100644 --- a/core/iwasm/include/wasm_export.h +++ b/core/iwasm/include/wasm_export.h @@ -333,8 +333,7 @@ wasm_runtime_set_wasi_args(wasm_module_t module, * specified here is ignored. * @param heap_size the default heap size of the module instance, a heap will * be created besides the app memory space. Both wasm app and native - * function can allocate memory from the heap. If heap_size is 0, the - * default heap size will be used. + * function can allocate memory from the heap. * @param error_buf buffer to output the error info if failed * @param error_buf_size the size of the error buffer * diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index 005822bdd..4b8b374e1 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -1411,17 +1411,16 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, #if WASM_ENABLE_LIBC_WASI != 0 /* The sub-instance will get the wasi_ctx from main-instance */ if (!is_sub_inst) { - if (heap_size > 0 - && !wasm_runtime_init_wasi((WASMModuleInstanceCommon*)module_inst, - module->wasi_args.dir_list, - module->wasi_args.dir_count, - module->wasi_args.map_dir_list, - module->wasi_args.map_dir_count, - module->wasi_args.env, - module->wasi_args.env_count, - module->wasi_args.argv, - module->wasi_args.argc, - error_buf, error_buf_size)) { + if (!wasm_runtime_init_wasi((WASMModuleInstanceCommon*)module_inst, + module->wasi_args.dir_list, + module->wasi_args.dir_count, + module->wasi_args.map_dir_list, + module->wasi_args.map_dir_count, + module->wasi_args.env, + module->wasi_args.env_count, + module->wasi_args.argv, + module->wasi_args.argc, + error_buf, error_buf_size)) { goto fail; } } From afa1feb1a818a28b92980227b809cb793a6781f5 Mon Sep 17 00:00:00 2001 From: Wang Ning Date: Fri, 12 Mar 2021 12:59:37 +0800 Subject: [PATCH 164/207] Update build wamrc aot compiler document (#570) --- README.md | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index d5fabc6ce..c20640596 100644 --- a/README.md +++ b/README.md @@ -60,19 +60,28 @@ WAMR supports building the iwasm VM core only (no app framework) to the mini pro ### Build wamrc AoT compiler -Both wasm binary file and AoT file are supported by iwasm. The wamrc AoT compiler is to compile wasm binary file to AoT file which can also be run by iwasm. Execute following commands to build **wamrc** compiler: +Both wasm binary file and AoT file are supported by iwasm. The wamrc AoT compiler is to compile wasm binary file to AoT file which can also be run by iwasm. Execute following commands to build **wamrc** compiler for Linux: ```shell cd wamr-compiler -./build_llvm.sh (use build_llvm_xtensa.sh instead to support xtensa target; use build_llvm.py for windows) +./build_llvm.sh (or "./build_llvm_xtensa.sh" to support xtensa target) +mkdir build && cd build +cmake .. (or "cmake .. -DWAMR_BUILD_TARGET=darwin" for MacOS) +make +# wamrc is generated under current directory +``` + +For **Windows**: +```shell +cd wamr-compiler +python build_llvm.py +open LLVM.sln in wasm-micro-runtime\core\deps\llvm\win32build with Visual Studio +build LLVM.sln Release mkdir build && cd build cmake .. -make -ln -s {current path}/wamrc /usr/bin/wamrc +cmake --build . --config Release +# wamrc.exe is generated under .\Release directory ``` -For MacOS, you should replace `cmake ..` with `cmake -DWAMR_BUILD_PLATFORM=darwin ..`. - -For Windows you should replace `cmake ..` with `cmake -D WAMR_BUILD_PLATFORM=windows -A Win32 ..`. Application framework =================================== From fda3a26903512c13078f47e7c9e082f1b2c7c794 Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Tue, 16 Mar 2021 03:59:16 -0500 Subject: [PATCH 165/207] Fix some relocation type issues in windows (#574) Implement Windows PE file relocation type IMAGE_REL_AMD64_ADDR64/ADDR32/REL32, implement relocation for symbol "__xmm@xxx"/"__plt@xxx"/".rdata", implement Windows invokeNative simd asm code and enable SIMD by default for windows platform. Also update wamrc tool. Signed-off-by: Wenyong Huang --- core/iwasm/aot/aot_loader.c | 230 +++++++++++++++++- core/iwasm/aot/aot_runtime.h | 11 + core/iwasm/aot/arch/aot_reloc_x86_64.c | 67 ++++- .../common/arch/invokeNative_em64_simd.asm | 62 +++++ core/iwasm/common/iwasm_common.cmake | 2 +- core/iwasm/compilation/aot_emit_aot_file.c | 36 ++- product-mini/platforms/windows/CMakeLists.txt | 7 +- 7 files changed, 385 insertions(+), 30 deletions(-) create mode 100644 core/iwasm/common/arch/invokeNative_em64_simd.asm diff --git a/core/iwasm/aot/aot_loader.c b/core/iwasm/aot/aot_loader.c index 4faa89b67..25b65ddaa 100644 --- a/core/iwasm/aot/aot_loader.c +++ b/core/iwasm/aot/aot_loader.c @@ -15,6 +15,8 @@ #include "../interpreter/wasm_loader.h" #endif +#define XMM_PLT_PREFIX "__xmm@" +#define REAL_PLT_PREFIX "__real@" static void set_error_buf(char *error_buf, uint32 error_buf_size, const char *string) @@ -1280,12 +1282,13 @@ get_data_section_addr(AOTModule *module, const char *section_name, uint32 i; AOTObjectDataSection *data_section = module->data_sections; - for (i = 0; i < module->data_section_count; i++, data_section++) + for (i = 0; i < module->data_section_count; i++, data_section++) { if (!strcmp(data_section->name, section_name)) { if (p_data_size) *p_data_size = data_section->size; return data_section->data; } + } return NULL; } @@ -1313,6 +1316,53 @@ is_literal_relocation(const char *reloc_sec_name) return !strcmp(reloc_sec_name, ".rela.literal"); } +#if defined(BH_PLATFORM_WINDOWS) +static bool +str2uint32(const char *buf, uint32 *p_res) +{ + uint32 res = 0, val; + const char *buf_end = buf + 8; + char ch; + + while (buf < buf_end) { + ch = *buf++; + if (ch >= '0' && ch <= '9') + val = ch - '0'; + else if (ch >= 'a' && ch <= 'f') + val = ch - 'a' + 0xA; + else if (ch >= 'A' && ch <= 'F') + val = ch - 'A' + 0xA; + else + return false; + res = (res << 4) | val; + } + *p_res = res; + return true; +} +static bool +str2uint64(const char *buf, uint64 *p_res) +{ + uint64 res = 0, val; + const char *buf_end = buf + 16; + char ch; + + while (buf < buf_end) { + ch = *buf++; + if (ch >= '0' && ch <= '9') + val = ch - '0'; + else if (ch >= 'a' && ch <= 'f') + val = ch - 'a' + 0xA; + else if (ch >= 'A' && ch <= 'F') + val = ch - 'A' + 0xA; + else + return false; + res = (res << 4) | val; + } + *p_res = res; + return true; +} +#endif + static bool do_text_relocation(AOTModule *module, AOTRelocationGroup *group, @@ -1322,6 +1372,9 @@ do_text_relocation(AOTModule *module, uint8 *aot_text = is_literal ? module->literal : module->code; uint32 aot_text_size = is_literal ? module->literal_size : module->code_size; uint32 i, func_index, symbol_len; +#if defined(BH_PLATFORM_WINDOWS) + uint32 xmm_plt_index = 0, real_plt_index = 0, float_plt_index = 0; +#endif char symbol_buf[128] = { 0 }, *symbol, *p; void *symbol_addr; AOTRelocation *relocation = group->relocations; @@ -1360,6 +1413,7 @@ do_text_relocation(AOTModule *module, symbol_addr = module->code; } else if (!strcmp(symbol, ".data") + || !strcmp(symbol, ".rdata") || !strcmp(symbol, ".rodata") /* ".rodata.cst4/8/16/.." */ || !strncmp(symbol, ".rodata.cst", strlen(".rodata.cst"))) { @@ -1373,9 +1427,66 @@ do_text_relocation(AOTModule *module, else if (!strcmp(symbol, ".literal")) { symbol_addr = module->literal; } +#if defined(BH_PLATFORM_WINDOWS) + else if (!strcmp(group->section_name, ".text") + && !strncmp(symbol, XMM_PLT_PREFIX, strlen(XMM_PLT_PREFIX)) + && strlen(symbol) == strlen(XMM_PLT_PREFIX) + 32) { + char xmm_buf[17] = { 0 }; + + symbol_addr = module->extra_plt_data + xmm_plt_index * 16; + bh_memcpy_s(xmm_buf, sizeof(xmm_buf), + symbol + strlen(XMM_PLT_PREFIX) + 16, 16); + if (!str2uint64(xmm_buf, (uint64*)symbol_addr)) { + set_error_buf(error_buf, error_buf, + "resolve symbol %s failed", symbol); + goto check_symbol_fail; + } + + bh_memcpy_s(xmm_buf, sizeof(xmm_buf), + symbol + strlen(XMM_PLT_PREFIX), 16); + if (!str2uint64(xmm_buf, (uint64*)((uint8*)symbol_addr + 8))) { + set_error_buf(error_buf, error_buf, + "resolve symbol %s failed", symbol); + goto check_symbol_fail; + } + xmm_plt_index++; + } + else if (!strcmp(group->section_name, ".text") + && !strncmp(symbol, REAL_PLT_PREFIX, strlen(REAL_PLT_PREFIX)) + && strlen(symbol) == strlen(REAL_PLT_PREFIX) + 16) { + char real_buf[17] = { 0 }; + + symbol_addr = module->extra_plt_data + module->xmm_plt_count * 16 + + real_plt_index * 8; + bh_memcpy_s(real_buf, sizeof(real_buf), + symbol + strlen(REAL_PLT_PREFIX), 16); + if (!str2uint64(real_buf, (uint64*)symbol_addr)) { + set_error_buf(error_buf, error_buf, + "resolve symbol %s failed", symbol); + goto check_symbol_fail; + } + real_plt_index++; + } + else if (!strcmp(group->section_name, ".text") + && !strncmp(symbol, REAL_PLT_PREFIX, strlen(REAL_PLT_PREFIX)) + && strlen(symbol) == strlen(REAL_PLT_PREFIX) + 8) { + char float_buf[9] = { 0 }; + + symbol_addr = module->extra_plt_data + module->xmm_plt_count * 16 + + module->real_plt_count * 8 + float_plt_index * 4; + bh_memcpy_s(float_buf, sizeof(float_buf), + symbol + strlen(REAL_PLT_PREFIX), 8); + if (!str2uint32(float_buf, (uint32*)symbol_addr)) { + set_error_buf(error_buf, error_buf, + "resolve symbol %s failed", symbol); + goto check_symbol_fail; + } + float_plt_index++; + } +#endif /* end of defined(BH_PLATFORM_WINDOWS) */ else if (!(symbol_addr = resolve_target_sym(symbol, &symbol_index))) { set_error_buf_v(error_buf, error_buf_size, - "resolve symbol %s failed", symbol); + "resolve symbol %s failed", symbol); goto check_symbol_fail; } @@ -1418,6 +1529,9 @@ do_data_relocation(AOTModule *module, else if (!strncmp(group->section_name, ".rel.", 5)) { data_section_name = group->section_name + strlen(".rel"); } + else if (!strcmp(group->section_name, ".rdata")) { + data_section_name = group->section_name; + } else { set_error_buf(error_buf, error_buf_size, "invalid data relocation section name"); @@ -1426,6 +1540,7 @@ do_data_relocation(AOTModule *module, data_addr = get_data_section_addr(module, data_section_name, &data_size); + if (group->relocation_count > 0 && !data_addr) { set_error_buf(error_buf, error_buf_size, "invalid data relocation count"); @@ -1514,6 +1629,106 @@ load_relocation_section(const uint8 *buf, const uint8 *buf_end, goto fail; } +#if defined(BH_PLATFORM_WINDOWS) + buf = symbol_buf_end; + read_uint32(buf, buf_end, group_count); + + for (i = 0; i < group_count; i++) { + uint32 name_index, relocation_count; + uint16 group_name_len; + uint8 *group_name; + + /* section name address is 4 bytes aligned. */ + buf = (uint8*)align_ptr(buf, sizeof(uint32)); + read_uint32(buf, buf_end, name_index); + + if (name_index >= symbol_count) { + set_error_buf(error_buf, error_buf_size, + "symbol index out of range"); + goto fail; + } + + group_name = symbol_buf + symbol_offsets[name_index]; + group_name_len = *(uint16 *)group_name; + group_name += sizeof(uint16); + + read_uint32(buf, buf_end, relocation_count); + + for (j = 0; j < relocation_count; j++) { + AOTRelocation relocation = { 0 }; + uint32 symbol_index, offset32, addend32; + uint16 symbol_name_len; + uint8 *symbol_name; + + if (sizeof(void *) == 8) { + read_uint64(buf, buf_end, relocation.relocation_offset); + read_uint64(buf, buf_end, relocation.relocation_addend); + } + else { + read_uint32(buf, buf_end, offset32); + relocation.relocation_offset = (uint64)offset32; + read_uint32(buf, buf_end, addend32); + relocation.relocation_addend = (uint64)addend32; + } + read_uint32(buf, buf_end, relocation.relocation_type); + read_uint32(buf, buf_end, symbol_index); + + if (symbol_index >= symbol_count) { + set_error_buf(error_buf, error_buf_size, + "symbol index out of range"); + goto fail; + } + + symbol_name = symbol_buf + symbol_offsets[symbol_index]; + symbol_name_len = *(uint16 *)symbol_name; + symbol_name += sizeof(uint16); + + char group_name_buf[128] = { 0 }; + char symbol_name_buf[128] = { 0 }; + memcpy(group_name_buf, group_name, group_name_len); + memcpy(symbol_name_buf, symbol_name, symbol_name_len); + + if (group_name_len == strlen(".text") + && !strncmp(group_name, ".text", strlen(".text"))) { + if (symbol_name_len == strlen(XMM_PLT_PREFIX) + 32 + && !strncmp(symbol_name, XMM_PLT_PREFIX, + strlen(XMM_PLT_PREFIX))) { + module->xmm_plt_count++; + } + else if (symbol_name_len == strlen(REAL_PLT_PREFIX) + 16 + && !strncmp(symbol_name, REAL_PLT_PREFIX, + strlen(REAL_PLT_PREFIX))) { + module->real_plt_count++; + } + else if (symbol_name_len == strlen(REAL_PLT_PREFIX) + 8 + && !strncmp(symbol_name, REAL_PLT_PREFIX, + strlen(REAL_PLT_PREFIX))) { + module->float_plt_count++; + } + } + } + } + + /* Allocate memory for extra plt data */ + size = sizeof(uint64) * 2 * module->xmm_plt_count + + sizeof(uint64) * module->real_plt_count + + sizeof(uint32) * module->float_plt_count; + if (size > 0) { + int map_prot = MMAP_PROT_READ | MMAP_PROT_WRITE | MMAP_PROT_EXEC; + /* aot code and data in x86_64 must be in range 0 to 2G due to + relocation for R_X86_64_32/32S/PC32 */ + int map_flags = MMAP_MAP_32BIT; + + if (size > UINT32_MAX + || !(module->extra_plt_data = os_mmap(NULL, (uint32)size, + map_prot, map_flags))) { + set_error_buf(error_buf, error_buf_size, "mmap memory failed"); + goto fail; + } + module->extra_plt_data_size = (uint32)size; + } +#endif /* end of defined(BH_PLATFORM_WINDOWS) */ + buf = symbol_buf_end; read_uint32(buf, buf_end, group_count); @@ -1614,6 +1829,8 @@ load_relocation_section(const uint8 *buf, const uint8 *buf_end, } } + /* TODO: set code and data read only */ + ret = true; fail: @@ -2304,10 +2521,17 @@ aot_unload(AOTModule *module) if (module->code) { uint8 *mmap_addr = module->literal - sizeof(module->literal_size); - uint32 total_size = sizeof(module->literal_size) + module->literal_size + module->code_size; + uint32 total_size = sizeof(module->literal_size) + + module->literal_size + module->code_size; os_munmap(mmap_addr, total_size); } +#if defined(BH_PLATFORM_WINDOWS) + if (module->extra_plt_data) { + os_munmap(module->extra_plt_data, module->extra_plt_data_size); + } +#endif + if (module->data_sections) destroy_object_data_sections(module->data_sections, module->data_section_count); diff --git a/core/iwasm/aot/aot_runtime.h b/core/iwasm/aot/aot_runtime.h index b165b9f81..527be0dd4 100644 --- a/core/iwasm/aot/aot_runtime.h +++ b/core/iwasm/aot/aot_runtime.h @@ -159,6 +159,17 @@ typedef struct AOTModule { uint8 *literal; uint32 literal_size; +#if (defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64)) \ + && defined(BH_PLATFORM_WINDOWS) + /* extra plt data area for __xmm and __real constants + in Windows platform, NULL for JIT mode */ + uint8 *extra_plt_data; + uint32 extra_plt_data_size; + uint32 xmm_plt_count; + uint32 real_plt_count; + uint32 float_plt_count; +#endif + /* data sections in AOT object file, including .data, .rodata * and .rodata.cstN. NULL for JIT mode. */ AOTObjectDataSection *data_sections; diff --git a/core/iwasm/aot/arch/aot_reloc_x86_64.c b/core/iwasm/aot/arch/aot_reloc_x86_64.c index 676bdd5c9..41e678033 100644 --- a/core/iwasm/aot/arch/aot_reloc_x86_64.c +++ b/core/iwasm/aot/arch/aot_reloc_x86_64.c @@ -5,16 +5,20 @@ #include "aot_reloc.h" -#define R_X86_64_64 1 /* Direct 64 bit */ -#define R_X86_64_PC32 2 /* PC relative 32 bit signed */ -#define R_X86_64_PLT32 4 /* 32 bit PLT address */ -#define R_X86_64_32 10 /* Direct 32 bit zero extended */ -#define R_X86_64_32S 11 /* Direct 32 bit sign extended */ +#if !defined(BH_PLATFORM_WINDOWS) +#define R_X86_64_64 1 /* Direct 64 bit */ +#define R_X86_64_PC32 2 /* PC relative 32 bit signed */ +#define R_X86_64_PLT32 4 /* 32 bit PLT address */ +#define R_X86_64_32 10 /* Direct 32 bit zero extended */ +#define R_X86_64_32S 11 /* Direct 32 bit sign extended */ +#else +#define IMAGE_REL_AMD64_ADDR64 1 /* The 64-bit VA of the relocation target */ +#define IMAGE_REL_AMD64_ADDR32 2 /* The 32-bit VA of the relocation target */ +#define IMAGE_REL_AMD64_REL32 4 /* The 32-bit relative address from + the byte following the relocation*/ +#endif -#define IMAGE_REL_AMD64_REL32 4 /* The 32-bit relative address from - the byte following the relocation */ - -#if defined(_WIN64) || defined(_WIN64_) +#if defined(BH_PLATFORM_WINDOWS) #pragma function (floor) #pragma function (ceil) #pragma function (floorf) @@ -98,7 +102,11 @@ apply_relocation(AOTModule *module, char *error_buf, uint32 error_buf_size) { switch (reloc_type) { +#if !defined(BH_PLATFORM_WINDOWS) case R_X86_64_64: +#else + case IMAGE_REL_AMD64_ADDR64: +#endif { intptr_t value; @@ -108,6 +116,29 @@ apply_relocation(AOTModule *module, = (uint8*)symbol_addr + reloc_addend + value; /* S + A */ break; } +#if defined(BH_PLATFORM_WINDOWS) + case IMAGE_REL_AMD64_ADDR32: + { + int32 value; + uintptr_t target_addr; + + CHECK_RELOC_OFFSET(sizeof(void *)); + value = *(int32*)(target_section_addr + (uint32)reloc_offset); + target_addr = (uintptr_t)symbol_addr + reloc_addend + value; + if ((int32)target_addr != target_addr) { + set_error_buf( + error_buf, error_buf_size, + "AOT module load failed: " + "relocation truncated to fit IMAGE_REL_AMD64_ADDR32 failed. " + "Try using wamrc with --size-level=1 option."); + return false; + } + + *(int32 *)(target_section_addr + reloc_offset) = (int32)target_addr; + break; + } +#endif +#if !defined(BH_PLATFORM_WINDOWS) case R_X86_64_PC32: { intptr_t target_addr = (intptr_t) /* S + A - P */ @@ -152,7 +183,12 @@ apply_relocation(AOTModule *module, *(int32*)(target_section_addr + reloc_offset) = (int32)target_addr; break; } +#endif +#if !defined(BH_PLATFORM_WINDOWS) case R_X86_64_PLT32: +#else + case IMAGE_REL_AMD64_REL32: +#endif { uint8 *plt; intptr_t target_addr = 0; @@ -172,16 +208,21 @@ apply_relocation(AOTModule *module, - (target_section_addr + reloc_offset)); } +#if defined(BH_PLATFORM_WINDOWS) + target_addr -= sizeof(int32); +#endif if ((int32)target_addr != target_addr) { set_error_buf(error_buf, error_buf_size, "AOT module load failed: " - "relocation truncated to fit R_X86_64_PC32 failed. " + "relocation truncated to fit " +#if !defined(BH_PLATFORM_WINDOWS) + "R_X86_64_PLT32 failed. " +#else + "IMAGE_REL_AMD64_32 failed." +#endif "Try using wamrc with --size-level=1 option."); return false; } -#ifdef BH_PLATFORM_WINDOWS - target_addr -= sizeof(int32); -#endif *(int32*)(target_section_addr + reloc_offset) = (int32)target_addr; break; } diff --git a/core/iwasm/common/arch/invokeNative_em64_simd.asm b/core/iwasm/common/arch/invokeNative_em64_simd.asm new file mode 100644 index 000000000..084a0f667 --- /dev/null +++ b/core/iwasm/common/arch/invokeNative_em64_simd.asm @@ -0,0 +1,62 @@ +; +; Copyright (C) 2019 Intel Corporation. All rights reserved. +; SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +; + +_TEXT SEGMENT + ; rcx func_ptr + ; rdx argv + ; r8 n_stacks + +invokeNative PROC + push rbp + mov rbp, rsp + + mov r10, rcx ; func_ptr + mov rax, rdx ; argv + mov rcx, r8 ; n_stacks + +; fill all fp args + movdqu xmm0, xmmword ptr [rax + 0] + movdqu xmm1, xmmword ptr [rax + 16] + movdqu xmm2, xmmword ptr [rax + 32] + movdqu xmm3, xmmword ptr [rax + 48] + +; check for stack args + cmp rcx, 0 + jz cycle_end + + mov rdx, rsp + and rdx, 15 + jz no_abort + int 3 +no_abort: + mov rdx, rcx + and rdx, 1 + shl rdx, 3 + sub rsp, rdx + +; store stack args + lea r9, qword ptr [rax + rcx * 8 + 88] + sub r9, rsp ; offset +cycle: + push qword ptr [rsp + r9] + loop cycle + +cycle_end: + mov rcx, [rax + 64] + mov rdx, [rax + 72] + mov r8, [rax + 80] + mov r9, [rax + 88] + + sub rsp, 32 ; shadow space + + call r10 + leave + ret + +invokeNative ENDP + +_TEXT ENDS + +END diff --git a/core/iwasm/common/iwasm_common.cmake b/core/iwasm/common/iwasm_common.cmake index a91da8d77..e1b8d822f 100644 --- a/core/iwasm/common/iwasm_common.cmake +++ b/core/iwasm/common/iwasm_common.cmake @@ -19,7 +19,7 @@ if (WAMR_BUILD_TARGET STREQUAL "X86_64" OR WAMR_BUILD_TARGET STREQUAL "AMD_64") endif () else () if (WAMR_BUILD_PLATFORM STREQUAL "windows") - message(FATAL_ERROR "need an implementation of SIMD on windows") + set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_em64_simd.asm) else() set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_em64_simd.s) endif() diff --git a/core/iwasm/compilation/aot_emit_aot_file.c b/core/iwasm/compilation/aot_emit_aot_file.c index b194c2aca..58cc4b4a9 100644 --- a/core/iwasm/compilation/aot_emit_aot_file.c +++ b/core/iwasm/compilation/aot_emit_aot_file.c @@ -1675,16 +1675,24 @@ aot_resolve_literal(AOTObjectData *obj_data) } static bool -is_data_section(char *section_name) +get_relocations_count(LLVMSectionIteratorRef sec_itr, uint32 *p_count); + +static bool +is_data_section(LLVMSectionIteratorRef sec_itr, char *section_name) { + uint32 relocation_count = 0; + return (!strcmp(section_name, ".data") || !strcmp(section_name, ".rodata") /* ".rodata.cst4/8/16/.." */ - || !strncmp(section_name, ".rodata.cst", strlen(".rodata.cst"))); + || !strncmp(section_name, ".rodata.cst", strlen(".rodata.cst")) + || (!strcmp(section_name, ".rdata") + && get_relocations_count(sec_itr, &relocation_count) + && relocation_count > 0)); } -static uint32 -get_object_data_sections_count(AOTObjectData *obj_data) +static bool +get_object_data_sections_count(AOTObjectData *obj_data, uint32 *p_count) { LLVMSectionIteratorRef sec_itr; char *name; @@ -1692,18 +1700,19 @@ get_object_data_sections_count(AOTObjectData *obj_data) if (!(sec_itr = LLVMObjectFileCopySectionIterator(obj_data->binary))) { aot_set_last_error("llvm get section iterator failed."); - return 0; + return false; } while (!LLVMObjectFileIsSectionIteratorAtEnd(obj_data->binary, sec_itr)) { if ((name = (char *)LLVMGetSectionName(sec_itr)) - && (is_data_section(name))) { + && (is_data_section(sec_itr, name))) { count++; } LLVMMoveToNextSection(sec_itr); } LLVMDisposeSectionIterator(sec_itr); - return count; + *p_count = count; + return true; } static bool @@ -1712,9 +1721,13 @@ aot_resolve_object_data_sections(AOTObjectData *obj_data) LLVMSectionIteratorRef sec_itr; char *name; AOTObjectDataSection *data_section; - uint32 sections_count = get_object_data_sections_count(obj_data); + uint32 sections_count; uint32 size; + if (!get_object_data_sections_count(obj_data, §ions_count)) { + return false; + } + if (sections_count > 0) { size = (uint32)sizeof(AOTObjectDataSection) * sections_count; if (!(data_section = obj_data->data_sections = wasm_runtime_malloc(size))) { @@ -1728,10 +1741,9 @@ aot_resolve_object_data_sections(AOTObjectData *obj_data) aot_set_last_error("llvm get section iterator failed."); return false; } - while (!LLVMObjectFileIsSectionIteratorAtEnd(obj_data->binary, - sec_itr)) { + while (!LLVMObjectFileIsSectionIteratorAtEnd(obj_data->binary, sec_itr)) { if ((name = (char *)LLVMGetSectionName(sec_itr)) - && (is_data_section(name))) { + && (is_data_section(sec_itr, name))) { data_section->name = name; data_section->data = (uint8 *)LLVMGetSectionContents(sec_itr); data_section->size = (uint32)LLVMGetSectionSize(sec_itr); @@ -1949,7 +1961,7 @@ is_relocation_section(LLVMSectionIteratorRef sec_itr) if (name) { if (is_relocation_section_name(name)) return true; - else if (!strncmp(name, ".text", strlen(".text")) + else if ((!strcmp(name, ".text") || !strcmp(name, ".rdata")) && get_relocations_count(sec_itr, &count) && count > 0) return true; } diff --git a/product-mini/platforms/windows/CMakeLists.txt b/product-mini/platforms/windows/CMakeLists.txt index 49b4cef84..cc1d389ae 100644 --- a/product-mini/platforms/windows/CMakeLists.txt +++ b/product-mini/platforms/windows/CMakeLists.txt @@ -58,7 +58,7 @@ endif () if (NOT DEFINED WAMR_BUILD_FAST_INTERP) # Enable fast interpreter - set (WAMR_BUILD_FAST_INTERP 0) + set (WAMR_BUILD_FAST_INTERP 1) endif () if (NOT DEFINED WAMR_BUILD_MULTI_MODULE) @@ -76,6 +76,11 @@ if (NOT DEFINED WAMR_BUILD_MINI_LOADER) set (WAMR_BUILD_MINI_LOADER 0) endif () +if (NOT DEFINED WAMR_BUILD_SIMD) + # Enable SIMD by default + set (WAMR_BUILD_SIMD 1) +endif () + if (COLLECT_CODE_COVERAGE EQUAL 1) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage") endif () From ca67af91bc5efc881f432ac4a9c7c58278bdf4e9 Mon Sep 17 00:00:00 2001 From: Javan Date: Thu, 18 Mar 2021 16:33:02 +0800 Subject: [PATCH 166/207] Call asc app exported new/pin/unpin APIs to align with its latest compiler (#577) AssemblyScript's latest compiler 0.18 exports __new__/__pin__/unpin APIs to allocate/retain/free memory instead of __new/__retain/__release APIs in older version, we lookup functions of both version to make it compatible for both version. --- assembly-script/package.json | 12 ++++++------ core/iwasm/aot/aot_loader.c | 6 ++++-- core/iwasm/aot/aot_runtime.c | 4 ++++ core/iwasm/interpreter/wasm_loader.c | 8 +++++--- core/iwasm/interpreter/wasm_mini_loader.c | 8 +++++--- 5 files changed, 24 insertions(+), 14 deletions(-) diff --git a/assembly-script/package.json b/assembly-script/package.json index 56a64f3d2..b80145fae 100644 --- a/assembly-script/package.json +++ b/assembly-script/package.json @@ -5,16 +5,16 @@ "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", - "build:request_handler": "asc samples/request_handler.ts -b build/request_handler.wasm -t build/request_handler.wat --sourceMap --optimize --use abort=", - "build:request_sender": "asc samples/request_sender.ts -b build/request_sender.wasm -t build/request_sender.wat --sourceMap --optimize --use abort=", - "build:timer": "asc samples/timer.ts -b build/timer.wasm -t build/timer.wat --sourceMap --optimize --use abort=", - "build:publisher": "asc samples/event_publisher.ts -b build/event_publisher.wasm -t build/event_publisher.wat --sourceMap --optimize --use abort=", - "build:subscriber": "asc samples/event_subscriber.ts -b build/event_subscriber.wasm -t build/event_subscriber.wat --sourceMap --optimize --use abort=", + "build:request_handler": "asc samples/request_handler.ts -b build/request_handler.wasm -t build/request_handler.wat --sourceMap --optimize --exportRuntime --use abort=", + "build:request_sender": "asc samples/request_sender.ts -b build/request_sender.wasm -t build/request_sender.wat --sourceMap --optimize --exportRuntime --use abort=", + "build:timer": "asc samples/timer.ts -b build/timer.wasm -t build/timer.wat --sourceMap --optimize --exportRuntime --use abort=", + "build:publisher": "asc samples/event_publisher.ts -b build/event_publisher.wasm -t build/event_publisher.wat --sourceMap --optimize --exportRuntime --use abort=", + "build:subscriber": "asc samples/event_subscriber.ts -b build/event_subscriber.wasm -t build/event_subscriber.wat --sourceMap --optimize --exportRuntime --use abort=", "build:all": "npm run build:request_handler; npm run build:request_sender; npm run build:timer; npm run build:subscriber; npm run build:publisher" }, "author": "", "license": "ISC", "devDependencies": { - "assemblyscript": "^0.17.4" + "assemblyscript": "^0.18.15" } } diff --git a/core/iwasm/aot/aot_loader.c b/core/iwasm/aot/aot_loader.c index 25b65ddaa..6d7b54017 100644 --- a/core/iwasm/aot/aot_loader.c +++ b/core/iwasm/aot/aot_loader.c @@ -1960,7 +1960,8 @@ load_from_sections(AOTModule *module, AOTSection *sections, export_tmp = module->exports; for (j = 0; j < module->export_count; j++, export_tmp++) { if ((export_tmp->kind == EXPORT_KIND_FUNC) - && (!strcmp(export_tmp->name, "__retain"))) { + && (!strcmp(export_tmp->name, "__retain") + || !strcmp(export_tmp->name, "__pin"))) { func_index = export_tmp->index - module->import_func_count; func_type_index = @@ -1988,7 +1989,8 @@ load_from_sections(AOTModule *module, AOTSection *sections, } } else if ((!strcmp(exports[i].name, "free")) - || (!strcmp(exports[i].name, "__release"))) { + || (!strcmp(exports[i].name, "__release")) + || (!strcmp(exports[i].name, "__unpin"))) { func_index = exports[i].index - module->import_func_count; func_type_index = module->func_type_indexes[func_index]; func_type = module->func_types[func_type_index]; diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index 772518efd..136e97652 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -1502,6 +1502,8 @@ aot_module_malloc(AOTModuleInstance *module_inst, uint32 size, malloc_func_sig = "(ii)i"; retain_func = aot_lookup_function(module_inst, "__retain", "(i)i"); + if (!retain_func) + retain_func = aot_lookup_function(module_inst, "__pin", "(i)i"); bh_assert(retain_func); } else { @@ -1573,6 +1575,8 @@ aot_module_free(AOTModuleInstance *module_inst, uint32 ptr) } free_func = aot_lookup_function(module_inst, free_func_name, "(i)i"); + if (!free_func && module->retain_func_index != (uint32)-1) + free_func = aot_lookup_function(module_inst, "__unpin", "(i)i"); bh_assert(free_func); execute_free_function(module_inst, free_func, ptr); diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index aa798ae3a..3da1c056f 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -2768,7 +2768,7 @@ load_from_sections(WASMModule *module, WASMSection *sections, } else if (!strcmp(export->name, "__new") && export->index >= module->import_function_count) { - /* __new && __retain for AssemblyScript */ + /* __new && __pin for AssemblyScript */ func_index = export->index - module->import_function_count; func_type = module->functions[func_index]->func_type; if (func_type->param_count == 2 @@ -2789,7 +2789,8 @@ load_from_sections(WASMModule *module, WASMSection *sections, export_tmp = module->exports; for (j = 0; j < module->export_count; j++, export_tmp++) { if ((export_tmp->kind == EXPORT_KIND_FUNC) - && (!strcmp(export_tmp->name, "__retain")) + && (!strcmp(export_tmp->name, "__retain") + || (!strcmp(export_tmp->name, "__pin"))) && (export_tmp->index >= module->import_function_count)) { func_index = export_tmp->index @@ -2818,7 +2819,8 @@ load_from_sections(WASMModule *module, WASMSection *sections, } } else if (((!strcmp(export->name, "free")) - || (!strcmp(export->name, "__release"))) + || (!strcmp(export->name, "__release")) + || (!strcmp(export->name, "__unpin"))) && export->index >= module->import_function_count) { func_index = export->index - module->import_function_count; func_type = module->functions[func_index]->func_type; diff --git a/core/iwasm/interpreter/wasm_mini_loader.c b/core/iwasm/interpreter/wasm_mini_loader.c index bdbc36b88..35b0950d1 100644 --- a/core/iwasm/interpreter/wasm_mini_loader.c +++ b/core/iwasm/interpreter/wasm_mini_loader.c @@ -1664,7 +1664,7 @@ load_from_sections(WASMModule *module, WASMSection *sections, } else if (!strcmp(export->name, "__new") && export->index >= module->import_function_count) { - /* __new && __retain for AssemblyScript */ + /* __new && __pin for AssemblyScript */ func_index = export->index - module->import_function_count; func_type = module->functions[func_index]->func_type; if (func_type->param_count == 2 @@ -1685,7 +1685,8 @@ load_from_sections(WASMModule *module, WASMSection *sections, export_tmp = module->exports; for (j = 0; j < module->export_count; j++, export_tmp++) { if ((export_tmp->kind == EXPORT_KIND_FUNC) - && (!strcmp(export_tmp->name, "__retain")) + && (!strcmp(export_tmp->name, "__retain") + || !strcmp(export_tmp->name, "__pin")) && (export_tmp->index >= module->import_function_count)) { func_index = export_tmp->index @@ -1714,7 +1715,8 @@ load_from_sections(WASMModule *module, WASMSection *sections, } } else if (((!strcmp(export->name, "free")) - || (!strcmp(export->name, "__release"))) + || (!strcmp(export->name, "__release")) + || (!strcmp(export->name, "__unpin"))) && export->index >= module->import_function_count) { func_index = export->index - module->import_function_count; func_type = module->functions[func_index]->func_type; From 68ff3a830e6afba396a303ae416704055dd69b94 Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Thu, 18 Mar 2021 07:03:40 -0500 Subject: [PATCH 167/207] Set AOT code and data readonly after relocation (#579) --- core/iwasm/aot/aot_loader.c | 63 +++++++++++++++++++++++++++++-------- 1 file changed, 50 insertions(+), 13 deletions(-) diff --git a/core/iwasm/aot/aot_loader.c b/core/iwasm/aot/aot_loader.c index 6d7b54017..f533758ef 100644 --- a/core/iwasm/aot/aot_loader.c +++ b/core/iwasm/aot/aot_loader.c @@ -1111,6 +1111,7 @@ load_text_section(const uint8 *buf, const uint8 *buf_end, return false; } + /* The layout is: literal size + literal + code (with plt table) */ read_uint32(buf, buf_end, module->literal_size); /* literal data is at begining of the text section */ @@ -1339,6 +1340,7 @@ str2uint32(const char *buf, uint32 *p_res) *p_res = res; return true; } + static bool str2uint64(const char *buf, uint64 *p_res) { @@ -1428,6 +1430,11 @@ do_text_relocation(AOTModule *module, symbol_addr = module->literal; } #if defined(BH_PLATFORM_WINDOWS) + /* Relocation for symbols which start with "__xmm@" or "__real@" and + end with the xmm value or real value. In Windows PE file, the data + is stored in some individual ".rdata" sections. We simply create + extra plt data, parse the values from the symbols and stored them + into the extra plt data. */ else if (!strcmp(group->section_name, ".text") && !strncmp(symbol, XMM_PLT_PREFIX, strlen(XMM_PLT_PREFIX)) && strlen(symbol) == strlen(XMM_PLT_PREFIX) + 32) { @@ -1437,16 +1444,16 @@ do_text_relocation(AOTModule *module, bh_memcpy_s(xmm_buf, sizeof(xmm_buf), symbol + strlen(XMM_PLT_PREFIX) + 16, 16); if (!str2uint64(xmm_buf, (uint64*)symbol_addr)) { - set_error_buf(error_buf, error_buf, - "resolve symbol %s failed", symbol); + set_error_buf_v(error_buf, error_buf, + "resolve symbol %s failed", symbol); goto check_symbol_fail; } bh_memcpy_s(xmm_buf, sizeof(xmm_buf), symbol + strlen(XMM_PLT_PREFIX), 16); if (!str2uint64(xmm_buf, (uint64*)((uint8*)symbol_addr + 8))) { - set_error_buf(error_buf, error_buf, - "resolve symbol %s failed", symbol); + set_error_buf_v(error_buf, error_buf, + "resolve symbol %s failed", symbol); goto check_symbol_fail; } xmm_plt_index++; @@ -1461,8 +1468,8 @@ do_text_relocation(AOTModule *module, bh_memcpy_s(real_buf, sizeof(real_buf), symbol + strlen(REAL_PLT_PREFIX), 16); if (!str2uint64(real_buf, (uint64*)symbol_addr)) { - set_error_buf(error_buf, error_buf, - "resolve symbol %s failed", symbol); + set_error_buf_v(error_buf, error_buf, + "resolve symbol %s failed", symbol); goto check_symbol_fail; } real_plt_index++; @@ -1477,8 +1484,8 @@ do_text_relocation(AOTModule *module, bh_memcpy_s(float_buf, sizeof(float_buf), symbol + strlen(REAL_PLT_PREFIX), 8); if (!str2uint32(float_buf, (uint32*)symbol_addr)) { - set_error_buf(error_buf, error_buf, - "resolve symbol %s failed", symbol); + set_error_buf_v(error_buf, error_buf, + "resolve symbol %s failed", symbol); goto check_symbol_fail; } float_plt_index++; @@ -1607,6 +1614,7 @@ load_relocation_section(const uint8 *buf, const uint8 *buf_end, uint64 size; uint32 *symbol_offsets, total_string_len; uint8 *symbol_buf, *symbol_buf_end; + int map_prot, map_flags; bool ret = false; read_uint32(buf, buf_end, symbol_count); @@ -1714,10 +1722,10 @@ load_relocation_section(const uint8 *buf, const uint8 *buf_end, + sizeof(uint64) * module->real_plt_count + sizeof(uint32) * module->float_plt_count; if (size > 0) { - int map_prot = MMAP_PROT_READ | MMAP_PROT_WRITE | MMAP_PROT_EXEC; + map_prot = MMAP_PROT_READ | MMAP_PROT_WRITE | MMAP_PROT_EXEC; /* aot code and data in x86_64 must be in range 0 to 2G due to relocation for R_X86_64_32/32S/PC32 */ - int map_flags = MMAP_MAP_32BIT; + map_flags = MMAP_MAP_32BIT; if (size > UINT32_MAX || !(module->extra_plt_data = os_mmap(NULL, (uint32)size, @@ -1829,7 +1837,34 @@ load_relocation_section(const uint8 *buf, const uint8 *buf_end, } } - /* TODO: set code and data read only */ + /* Set read only for AOT code and some data sections */ + map_prot = MMAP_PROT_READ; + + if (module->code) { + /* The layout is: literal size + literal + code (with plt table) */ + uint8 *mmap_addr = module->literal - sizeof(uint32); + uint32 total_size = sizeof(uint32) + + module->literal_size + module->code_size; + os_mprotect(mmap_addr, total_size, map_prot); + } + +#if defined(BH_PLATFORM_WINDOWS) + if (module->extra_plt_data) { + os_mprotect(module->extra_plt_data, module->extra_plt_data_size, + map_prot); + } +#endif + + for (i = 0; i < module->data_section_count; i++) { + AOTObjectDataSection *data_section = module->data_sections + i; + if (!strcmp(data_section->name, ".rdata") + || !strcmp(data_section->name, ".rodata") + /* ".rodata.cst4/8/16/.." */ + || !strncmp(data_section->name, ".rodata.cst", + strlen(".rodata.cst"))) { + os_mprotect(data_section->data, data_section->size, map_prot); + } + } ret = true; @@ -1841,6 +1876,7 @@ fail: wasm_runtime_free(groups); } + (void)map_flags; return ret; } @@ -2522,8 +2558,9 @@ aot_unload(AOTModule *module) bh_hash_map_destroy(module->const_str_set); if (module->code) { - uint8 *mmap_addr = module->literal - sizeof(module->literal_size); - uint32 total_size = sizeof(module->literal_size) + /* The layout is: literal size + literal + code (with plt table) */ + uint8 *mmap_addr = module->literal - sizeof(uint32); + uint32 total_size = sizeof(uint32) + module->literal_size + module->code_size; os_munmap(mmap_addr, total_size); } From a4e4d4198f0740c36117b0d82be14cb49690ef94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E7=B1=B3-=E5=91=A8=E4=BA=AE?= <52808759+DS-LK@users.noreply.github.com> Date: Fri, 19 Mar 2021 13:48:39 +0800 Subject: [PATCH 168/207] platforms/nuttx: Add SIM compilation for WAMR (#581) N/A Signed-off-by: zhouliang3 Change-Id: Ic95cd0fa1b386c80e2cc3e8037cc638710a1c8a9 Co-authored-by: zhouliang3 --- product-mini/platforms/nuttx/wamr.mk | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/product-mini/platforms/nuttx/wamr.mk b/product-mini/platforms/nuttx/wamr.mk index d82852cf3..5fe31448a 100644 --- a/product-mini/platforms/nuttx/wamr.mk +++ b/product-mini/platforms/nuttx/wamr.mk @@ -16,7 +16,9 @@ WAMR_BUILD_TARGET := X86_64 else ifeq ($(CONFIG_ARCH_XTENSA),y) WAMR_BUILD_TARGET := XTENSA else ifeq ($(CONFIG_ARCH_SIM),y) -ifeq ($(CONFIG_HOST_X86_64),y) +ifeq ($(CONFIG_SIM_M32),y) +WAMR_BUILD_TARGET := X86_32 +else WAMR_BUILD_TARGET := X86_64 endif ifeq ($(CONFIG_HOST_MACOS),y) From 02d27e13ee53bfae3097aaebdc182af38b037e9a Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Mon, 22 Mar 2021 06:28:51 -0500 Subject: [PATCH 169/207] Fix some compilation warnings and enable Windows JIT (#586) --- build-scripts/config_common.cmake | 10 ++- core/iwasm/aot/aot_loader.c | 13 ++-- core/iwasm/common/wasm_runtime_common.c | 4 +- core/iwasm/compilation/simd/simd_int_arith.c | 6 +- core/iwasm/interpreter/wasm_runtime.c | 4 +- .../libc-builtin/libc_builtin_wrapper.c | 4 +- core/shared/utils/bh_vector.c | 14 ++-- core/shared/utils/bh_vector.h | 4 +- core/shared/utils/uncommon/bh_getopt.c | 2 +- product-mini/platforms/windows/CMakeLists.txt | 2 +- product-mini/platforms/windows/build_llvm.py | 69 +++++++++++++++++++ product-mini/platforms/windows/main.c | 2 +- samples/workload/bwa/CMakeLists.txt | 1 + samples/workload/bwa/bwa.patch | 13 ++++ 14 files changed, 119 insertions(+), 29 deletions(-) create mode 100644 product-mini/platforms/windows/build_llvm.py create mode 100644 samples/workload/bwa/bwa.patch diff --git a/build-scripts/config_common.cmake b/build-scripts/config_common.cmake index e0ecc5407..03a4b23bd 100644 --- a/build-scripts/config_common.cmake +++ b/build-scripts/config_common.cmake @@ -79,10 +79,14 @@ if (WAMR_BUILD_JIT EQUAL 1) if (WAMR_BUILD_AOT EQUAL 1) add_definitions("-DWASM_ENABLE_JIT=1") set (LLVM_SRC_ROOT "${WAMR_ROOT_DIR}/core/deps/llvm") - if (NOT EXISTS "${LLVM_SRC_ROOT}/build") - message (FATAL_ERROR "Cannot find LLVM dir: ${LLVM_SRC_ROOT}/build") + set (LLVM_BUILD_ROOT "${LLVM_SRC_ROOT}/build") + if (WAMR_BUILD_PLATFORM STREQUAL "windows") + set (LLVM_BUILD_ROOT "${LLVM_SRC_ROOT}/win32build") endif () - set (CMAKE_PREFIX_PATH "${LLVM_SRC_ROOT}/build;${CMAKE_PREFIX_PATH}") + if (NOT EXISTS "${LLVM_BUILD_ROOT}") + message (FATAL_ERROR "Cannot find LLVM dir: ${LLVM_BUILD_ROOT}") + endif () + set (CMAKE_PREFIX_PATH "${LLVM_BUILD_ROOT};${CMAKE_PREFIX_PATH}") find_package(LLVM REQUIRED CONFIG) include_directories(${LLVM_INCLUDE_DIRS}) add_definitions(${LLVM_DEFINITIONS}) diff --git a/core/iwasm/aot/aot_loader.c b/core/iwasm/aot/aot_loader.c index f533758ef..40d497369 100644 --- a/core/iwasm/aot/aot_loader.c +++ b/core/iwasm/aot/aot_loader.c @@ -574,7 +574,7 @@ load_table_init_data_list(const uint8 **p_buf, const uint8 *buf_end, data_list[i]->offset.init_expr_type = (uint8)init_expr_type; data_list[i]->offset.u.i64 = (int64)init_expr_value; data_list[i]->func_index_count = func_index_count; - read_byte_array(buf, buf_end, data_list[i]->func_indexes, size1); + read_byte_array(buf, buf_end, data_list[i]->func_indexes, (uint32)size1); } *p_buf = buf; @@ -1444,7 +1444,7 @@ do_text_relocation(AOTModule *module, bh_memcpy_s(xmm_buf, sizeof(xmm_buf), symbol + strlen(XMM_PLT_PREFIX) + 16, 16); if (!str2uint64(xmm_buf, (uint64*)symbol_addr)) { - set_error_buf_v(error_buf, error_buf, + set_error_buf_v(error_buf, error_buf_size, "resolve symbol %s failed", symbol); goto check_symbol_fail; } @@ -1452,7 +1452,7 @@ do_text_relocation(AOTModule *module, bh_memcpy_s(xmm_buf, sizeof(xmm_buf), symbol + strlen(XMM_PLT_PREFIX), 16); if (!str2uint64(xmm_buf, (uint64*)((uint8*)symbol_addr + 8))) { - set_error_buf_v(error_buf, error_buf, + set_error_buf_v(error_buf, error_buf_size, "resolve symbol %s failed", symbol); goto check_symbol_fail; } @@ -1468,7 +1468,7 @@ do_text_relocation(AOTModule *module, bh_memcpy_s(real_buf, sizeof(real_buf), symbol + strlen(REAL_PLT_PREFIX), 16); if (!str2uint64(real_buf, (uint64*)symbol_addr)) { - set_error_buf_v(error_buf, error_buf, + set_error_buf_v(error_buf, error_buf_size, "resolve symbol %s failed", symbol); goto check_symbol_fail; } @@ -1484,7 +1484,7 @@ do_text_relocation(AOTModule *module, bh_memcpy_s(float_buf, sizeof(float_buf), symbol + strlen(REAL_PLT_PREFIX), 8); if (!str2uint32(float_buf, (uint32*)symbol_addr)) { - set_error_buf_v(error_buf, error_buf, + set_error_buf_v(error_buf, error_buf_size, "resolve symbol %s failed", symbol); goto check_symbol_fail; } @@ -2306,7 +2306,8 @@ aot_load_from_comp_data(AOTCompData *comp_data, AOTCompContext *comp_ctx, goto fail1; } - bh_memcpy_s(module->memories, size, comp_data->memories, size); + bh_memcpy_s(module->memories, (uint32)size, + comp_data->memories, (uint32)size); } module->mem_init_data_list = comp_data->mem_init_data_list; diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index f863fb4d3..95d2fd7af 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -777,7 +777,7 @@ wasm_runtime_deinstantiate_internal(WASMModuleInstanceCommon *module_inst, void wasm_runtime_deinstantiate(WASMModuleInstanceCommon *module_inst) { - return wasm_runtime_deinstantiate_internal(module_inst, false); + wasm_runtime_deinstantiate_internal(module_inst, false); } WASMExecEnv * @@ -1962,7 +1962,7 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, fail: if (envp) - wasm_runtime_free(envp); + wasm_runtime_free((void*)envp); if (init_options.preopens) wasm_runtime_free(init_options.preopens); diff --git a/core/iwasm/compilation/simd/simd_int_arith.c b/core/iwasm/compilation/simd/simd_int_arith.c index 4a83e3be7..f61b67bcd 100644 --- a/core/iwasm/compilation/simd/simd_int_arith.c +++ b/core/iwasm/compilation/simd/simd_int_arith.c @@ -83,7 +83,7 @@ aot_compile_simd_i8x16_arith(AOTCompContext *comp_ctx, return simd_v128_integer_arith(comp_ctx, func_ctx, arith_op, lhs, rhs); fail: - return NULL; + return false; } bool @@ -105,7 +105,7 @@ aot_compile_simd_i16x8_arith(AOTCompContext *comp_ctx, return simd_v128_integer_arith(comp_ctx, func_ctx, arith_op, lhs, rhs); fail: - return NULL; + return false; } bool @@ -127,7 +127,7 @@ aot_compile_simd_i32x4_arith(AOTCompContext *comp_ctx, return simd_v128_integer_arith(comp_ctx, func_ctx, arith_op, lhs, rhs); fail: - return NULL; + return false; } bool diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index 4b8b374e1..a17bd9035 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -1909,8 +1909,8 @@ wasm_enlarge_memory(WASMModuleInstance *module, uint32 inc_page_count) return false; memory_data = memory->memory_data; - heap_size = memory->heap_data_end - memory->heap_data; - total_size_old = memory->memory_data_end - memory_data; + heap_size = (uint32)(memory->heap_data_end - memory->heap_data); + total_size_old = (uint32)(memory->memory_data_end - memory_data); total_page_count = inc_page_count + memory->cur_page_count; total_size = memory->num_bytes_per_page * (uint64)total_page_count; heap_data_old = memory->heap_data; diff --git a/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c b/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c index 23d982485..195c55ad3 100644 --- a/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c +++ b/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c @@ -647,7 +647,7 @@ static uint32 strcpy_wrapper(wasm_exec_env_t exec_env, char *dst, const char *src) { wasm_module_inst_t module_inst = get_module_inst(exec_env); - uint32 len = strlen(src) + 1; + uint32 len = (uint32)strlen(src) + 1; /* src has been checked by runtime */ if (!validate_native_addr(dst, len)) @@ -712,7 +712,7 @@ free_wrapper(wasm_exec_env_t exec_env, void *ptr) if (!validate_native_addr(ptr, sizeof(uint32))) return; - return module_free(addr_native_to_app(ptr)); + module_free(addr_native_to_app(ptr)); } static int32 diff --git a/core/shared/utils/bh_vector.c b/core/shared/utils/bh_vector.c index dfb8339bc..33ea7265e 100644 --- a/core/shared/utils/bh_vector.c +++ b/core/shared/utils/bh_vector.c @@ -6,12 +6,14 @@ #include "bh_vector.h" static uint8* -alloc_vector_data(uint32 length, uint32 size_elem) +alloc_vector_data(size_t length, size_t size_elem) { uint64 total_size = ((uint64)size_elem) * length; uint8 *data; - if (total_size > UINT32_MAX) { + if (length > UINT32_MAX + || size_elem > UINT32_MAX + || total_size > UINT32_MAX) { return NULL; } @@ -23,7 +25,7 @@ alloc_vector_data(uint32 length, uint32 size_elem) } static bool -extend_vector(Vector *vector, uint32 length) +extend_vector(Vector *vector, size_t length) { uint8 *data; @@ -45,7 +47,7 @@ extend_vector(Vector *vector, uint32 length) } bool -bh_vector_init(Vector *vector, uint32 init_length, uint32 size_elem) +bh_vector_init(Vector *vector, size_t init_length, size_t size_elem) { if (!vector) { LOG_ERROR("Init vector failed: vector is NULL.\n"); @@ -104,7 +106,7 @@ bool bh_vector_get(const Vector *vector, uint32 index, void *elem_buf) bool bh_vector_insert(Vector *vector, uint32 index, const void *elem_buf) { - uint32 i; + size_t i; uint8 *p; if (!vector || !elem_buf) { @@ -182,7 +184,7 @@ bh_vector_remove(Vector *vector, uint32 index, void *old_elem_buf) return true; } -uint32 +size_t bh_vector_size(const Vector *vector) { return vector ? vector->num_elems : 0; diff --git a/core/shared/utils/bh_vector.h b/core/shared/utils/bh_vector.h index 1ae7c279b..59f432f78 100644 --- a/core/shared/utils/bh_vector.h +++ b/core/shared/utils/bh_vector.h @@ -35,7 +35,7 @@ typedef struct Vector { * @return true if success, false otherwise */ bool -bh_vector_init(Vector *vector, uint32 init_length, uint32 size_elem); +bh_vector_init(Vector *vector, size_t init_length, size_t size_elem); /** * Set element of vector @@ -104,7 +104,7 @@ bh_vector_remove(Vector *vector, uint32 index, void *old_elem_buf); * * @return return the size of the vector */ -uint32 +size_t bh_vector_size(const Vector *vector); /** diff --git a/core/shared/utils/uncommon/bh_getopt.c b/core/shared/utils/uncommon/bh_getopt.c index b7000c3db..67815e19d 100644 --- a/core/shared/utils/uncommon/bh_getopt.c +++ b/core/shared/utils/uncommon/bh_getopt.c @@ -6,6 +6,7 @@ #ifndef __GNUC__ #include "bh_getopt.h" +#include #include char* optarg = NULL; @@ -14,7 +15,6 @@ int optind = 1; int getopt(int argc, char *const argv[], const char *optstring) { static int sp = 1; - int c; int opt; char *p; diff --git a/product-mini/platforms/windows/CMakeLists.txt b/product-mini/platforms/windows/CMakeLists.txt index cc1d389ae..4f130de0c 100644 --- a/product-mini/platforms/windows/CMakeLists.txt +++ b/product-mini/platforms/windows/CMakeLists.txt @@ -58,7 +58,7 @@ endif () if (NOT DEFINED WAMR_BUILD_FAST_INTERP) # Enable fast interpreter - set (WAMR_BUILD_FAST_INTERP 1) + set (WAMR_BUILD_FAST_INTERP 0) endif () if (NOT DEFINED WAMR_BUILD_MULTI_MODULE) diff --git a/product-mini/platforms/windows/build_llvm.py b/product-mini/platforms/windows/build_llvm.py new file mode 100644 index 000000000..f476e9e6c --- /dev/null +++ b/product-mini/platforms/windows/build_llvm.py @@ -0,0 +1,69 @@ +# +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# + +#!/usr/bin/env python3 +import os +import sys +from pathlib import Path + +def clone_llvm(): + llvm_dir = Path("llvm") + if(llvm_dir.exists() == False): + print("Clone llvm to core/deps/ ..") + for line in os.popen("git clone --branch release/11.x https://github.com/llvm/llvm-project.git llvm"): + print(line) + else: + print("llvm source codes already existed") + return llvm_dir + +def main(): + current_os = sys.platform + print("current OS is ", current_os) + + current_dir = Path.cwd() + deps_dir = current_dir.joinpath( "../../../core/deps") + + os.chdir(deps_dir) + llvm_dir = clone_llvm() + os.chdir(llvm_dir) + + build_dir_name = "win32build" + llvm_file = "LLVM.sln" + + Path(build_dir_name).mkdir(exist_ok = True) + build_dir = Path(build_dir_name) + os.chdir(build_dir) + + if ( not Path(llvm_file).exists()): + core_number = os.cpu_count() + print("Build llvm with", core_number, " cores") + cmd = 'cmake ../llvm \ + -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ + -DCMAKE_BUILD_TYPE:STRING="Release" \ + -DLLVM_TARGETS_TO_BUILD:STRING="X86;ARM;AArch64;Mips" \ + -DLLVM_INCLUDE_GO_TESTS=OFF \ + -DLLVM_INCLUDE_TOOLS=OFF \ + -DLLVM_INCLUDE_UTILS=OFF \ + -DLLVM_ENABLE_TERMINFO=OFF \ + -DLLVM_BUILD_LLVM_DYLIB:BOOL=OFF \ + -DLLVM_OPTIMIZED_TABLEGEN:BOOL=ON \ + -DLLVM_ENABLE_ZLIB:BOOL=OFF \ + -DLLVM_INCLUDE_DOCS:BOOL=OFF \ + -DLLVM_INCLUDE_EXAMPLES:BOOL=OFF \ + -DLLVM_INCLUDE_TESTS:BOOL=OFF \ + -DLLVM_INCLUDE_BENCHMARKS:BOOL=OFF \ + -DLLVM_APPEND_VC_REV:BOOL=OFF' + print(cmd) + for line in os.popen(cmd): + print(line) + else: + print("llvm has already been Cmaked") + + print("Please open LLVM.sln in {} to build *Release* version".format(build_dir.absolute())) + + os.chdir(current_dir) + +if __name__ == "__main__": + main() diff --git a/product-mini/platforms/windows/main.c b/product-mini/platforms/windows/main.c index 5cb3415a4..c9ad6821c 100644 --- a/product-mini/platforms/windows/main.c +++ b/product-mini/platforms/windows/main.c @@ -118,7 +118,7 @@ app_instance_repl(wasm_module_inst_t module_inst) size_t n; while ((printf("webassembly> "), - cmd = fgets(buffer, sizeof(buffer), stdin)) != -1) { + cmd = fgets(buffer, sizeof(buffer), stdin)) != NULL) { bh_assert(cmd); n = strlen(cmd); if (cmd[n - 1] == '\n') { diff --git a/samples/workload/bwa/CMakeLists.txt b/samples/workload/bwa/CMakeLists.txt index 5c1d4a8f8..0ea2c2947 100644 --- a/samples/workload/bwa/CMakeLists.txt +++ b/samples/workload/bwa/CMakeLists.txt @@ -117,6 +117,7 @@ ExternalProject_Add(bwa UPDATE_COMMAND git clean -fd && git checkout -- * && ${CMAKE_COMMAND} -E echo "Copying pre-installed CMakeLists.txt" && ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.bwa_wasm.txt CMakeLists.txt + && git apply ../bwa.patch CONFIGURE_COMMAND ${CMAKE_COMMAND} -DWASI_SDK_PREFIX=${WASI_SDK_HOME}/wasi-sdk -DCMAKE_TOOLCHAIN_FILE=${WASI_SDK_HOME}/wasi-sdk/share/cmake/wasi-sdk.cmake diff --git a/samples/workload/bwa/bwa.patch b/samples/workload/bwa/bwa.patch new file mode 100644 index 000000000..5599ca319 --- /dev/null +++ b/samples/workload/bwa/bwa.patch @@ -0,0 +1,13 @@ +diff --git a/utils.c b/utils.c +index 9ceb1be..323299f 100644 +--- a/utils.c ++++ b/utils.c +@@ -301,6 +301,7 @@ long peakrss(void) + #ifdef __linux__ + return r.ru_maxrss * 1024; + #else +- return r.ru_maxrss; ++ /*return r.ru_maxrss;*/ ++ return 0; + #endif + } From be54b4c7ccc293d42be6680d245110896e11f408 Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Tue, 23 Mar 2021 01:20:50 -0500 Subject: [PATCH 170/207] Fix sample littlevgl/gui build issues on zephyr platform (#588) Fix sample littlevgl/guil build issues on zephyr platform, modify code of zephyr platform by adding some macros to control some apis to fit different zephyr version, and align to zephyr-v2.3.0 for sample littlevgl/gui as the latest zephyr version (>=v2.4.0) requires that the thread stack for the thread to create must be defined by macro but not allocating stack memory dynamically. Signed-off-by: Wenyong Huang --- .../platform/zephyr/platform_internal.h | 13 +- core/shared/platform/zephyr/zephyr_platform.c | 54 +++++++- core/shared/platform/zephyr/zephyr_thread.c | 5 + .../platforms/zephyr/simple/build_and_run.sh | 24 ++-- samples/gui/README.md | 125 ++++++++++-------- samples/littlevgl/README.md | 122 +++++++++-------- .../src/platform/zephyr/display_ili9340.c | 6 +- test-tools/host-tool/src/main.c | 8 +- test-tools/host-tool/src/transport.c | 5 - 9 files changed, 229 insertions(+), 133 deletions(-) diff --git a/core/shared/platform/zephyr/platform_internal.h b/core/shared/platform/zephyr/platform_internal.h index c208bacd4..256d98de7 100644 --- a/core/shared/platform/zephyr/platform_internal.h +++ b/core/shared/platform/zephyr/platform_internal.h @@ -9,7 +9,12 @@ #include #include #include +#include +#if KERNEL_VERSION_NUMBER >= 0x020200 /* version 2.2.0 */ #include +#else +#include +#endif #include #include #include @@ -53,7 +58,13 @@ typedef struct korp_cond { os_thread_wait_list thread_wait_list; } korp_cond; -#define os_printf printf +#ifndef Z_TIMEOUT_MS +#define Z_TIMEOUT_MS(ms) ms +#endif + +void abort(void); +size_t strspn(const char *s, const char *accept); +size_t strcspn(const char *s, const char *reject); /* math functions which are not provided by os */ double sqrt(double x); diff --git a/core/shared/platform/zephyr/zephyr_platform.c b/core/shared/platform/zephyr/zephyr_platform.c index 1666a56d0..42a9d00aa 100644 --- a/core/shared/platform/zephyr/zephyr_platform.c +++ b/core/shared/platform/zephyr/zephyr_platform.c @@ -101,7 +101,6 @@ char_out(int c, void *ctx) out_ctx->count++; return _stdout_hook_iwasm(c); } -#endif int os_vprintf(const char *fmt, va_list ap) @@ -115,6 +114,59 @@ os_vprintf(const char *fmt, va_list ap) return 0; #endif } +#endif + +int +os_printf(const char *format, ...) +{ + int ret = 0; + va_list ap; + + va_start(ap, format); +#ifndef BH_VPRINTF + ret += vprintf(format, ap); +#else + ret += BH_VPRINTF(format, ap); +#endif + va_end(ap); + + return ret; +} + +int +os_vprintf(const char *format, va_list ap) +{ +#ifndef BH_VPRINTF + return vprintf(format, ap); +#else + return BH_VPRINTF(format, ap); +#endif +} + +#if KERNEL_VERSION_NUMBER <= 0x020400 /* version 2.4.0 */ +void +abort(void) +{ + int i = 0; + os_printf("%d\n", 1 / i); +} +#endif + +#if KERNEL_VERSION_NUMBER <= 0x010E01 /* version 1.14.1 */ +size_t +strspn(const char *s, const char *accept) +{ + os_printf("## unimplemented function %s called", __FUNCTION__); + return 0; +} + +size_t +strcspn(const char *s, const char *reject) +{ + os_printf("## unimplemented function %s called", __FUNCTION__); + return 0; +} +#endif void * os_mmap(void *hint, size_t size, int prot, int flags) diff --git a/core/shared/platform/zephyr/zephyr_thread.c b/core/shared/platform/zephyr/zephyr_thread.c index 69dc092e8..3244c6a99 100644 --- a/core/shared/platform/zephyr/zephyr_thread.c +++ b/core/shared/platform/zephyr/zephyr_thread.c @@ -353,7 +353,12 @@ int os_mutex_lock(korp_mutex *mutex) int os_mutex_unlock(korp_mutex *mutex) { +#if KERNEL_VERSION_NUMBER >= 0x020200 /* version 2.2.0 */ return k_mutex_unlock(mutex); +#else + k_mutex_unlock(mutex); + return 0; +#endif } int os_cond_init(korp_cond *cond) diff --git a/product-mini/platforms/zephyr/simple/build_and_run.sh b/product-mini/platforms/zephyr/simple/build_and_run.sh index 2c7befde9..e928e4b13 100755 --- a/product-mini/platforms/zephyr/simple/build_and_run.sh +++ b/product-mini/platforms/zephyr/simple/build_and_run.sh @@ -5,22 +5,22 @@ X86_TARGET="x86" STM32_TARGET="stm32" -QEMU_CORTEX_A53="qemu_cortex_a53" -XTENSA_QEMU_TARGET="xtensa-qemu" ESP32_TARGET="esp32" +QEMU_CORTEX_A53="qemu_cortex_a53" +QEMU_XTENSA_TARGET="qemu_xtensa" QEMU_RISCV64_TARGET="qemu_riscv64" QEMU_RISCV32_TARGET="qemu_riscv32" usage () { echo "USAGE:" - echo "$0 $X86_TARGET|$STM32_TARGET|$QEMU_CORTEX_A53|$XTENSA_QEMU_TARGET|$ESP32_TARGET|$QEMU_RISCV64_TARGET|$QEMU_RISCV32_TARGET" + echo "$0 $X86_TARGET|$STM32_TARGET|$ESP32_TARGET|$QEMU_CORTEX_A53|$QEMU_XTENSA_TARGET|$QEMU_RISCV64_TARGET|$QEMU_RISCV32_TARGET" echo "Example:" echo " $0 $X86_TARGET" echo " $0 $STM32_TARGET" - echo " $0 $QEMU_CORTEX_A53" - echo " $0 $XTENSA_QEMU_TARGET" echo " $0 $ESP32_TARGET" + echo " $0 $QEMU_CORTEX_A53" + echo " $0 $QEMU_XTENSA_TARGET" echo " $0 $QEMU_RISCV64_TARGET" echo " $0 $QEMU_RISCV32_TARGET" exit 1 @@ -47,13 +47,6 @@ case $TARGET in -DWAMR_BUILD_TARGET=THUMBV7 west flash ;; - $XTENSA_QEMU_TARGET) - west build -b qemu_xtensa \ - . -p always -- \ - -DCONF_FILE=prj_qemu_xtensa.conf \ - -DWAMR_BUILD_TARGET=XTENSA - west build -t run - ;; $ESP32_TARGET) # suppose you have set environment variable ESP_IDF_PATH west build -b esp32 \ @@ -65,6 +58,13 @@ case $TARGET in # the real name accordingly west flash --esp-device /dev/ttyUSB1 ;; + $QEMU_XTENSA_TARGET) + west build -b qemu_xtensa \ + . -p always -- \ + -DCONF_FILE=prj_qemu_xtensa.conf \ + -DWAMR_BUILD_TARGET=XTENSA + west build -t run + ;; $QEMU_CORTEX_A53) west build -b qemu_cortex_a53 \ . -p always -- \ diff --git a/samples/gui/README.md b/samples/gui/README.md index b285754c5..2d3d062cb 100644 --- a/samples/gui/README.md +++ b/samples/gui/README.md @@ -1,16 +1,14 @@ "gui" sample introduction ============== -This sample demonstrates that a graphic user interface application in WebAssembly programming with WAMR graphic library(WGL) which is part of WAMR app-framework. +This sample demonstrates that a graphic user interface application in WebAssembly programming with WAMR graphic library(WGL) which is part of WAMR app-framework. Compared with the [littlevgl](../littlevgl) sample, WGL compiles LittlevGL source code into the WAMR runtime and defines a set of wrapper API's for exporting to Webassembly application. - Below picture shows the WASM application is running on an STM board with an LCD touch panel. - ![WAMR UI SAMPLE](../../doc/pics/vgl_demo2.png "WAMR UI DEMO") - When users click the blue button, the WASM application increases the counter, and the latest counter value is displayed on the top banner of the touch panel. The number on top will plus one each second, and the number on the bottom will plus one when clicked. + When user clicks the blue button, the WASM application increases the counter, and the latest counter value is displayed on the top banner of the touch panel. The number on top will plus one each second, and the number on the bottom will plus one when clicked. # Test on Linux @@ -18,61 +16,81 @@ Install required SDK and libraries -------------- - 32 bit SDL(simple directmedia layer) (Note: only necessary when `WAMR_BUILD_TARGET` is set to `X86_32` when building WAMR runtime) Use apt-get: - `sudo apt-get install libsdl2-dev:i386` + ```bash + sudo apt-get install libsdl2-dev:i386 + ``` Or download source from www.libsdl.org: -``` -./configure C_FLAGS=-m32 CXX_FLAGS=-m32 LD_FLAGS=-m32 -make -sudo make install -``` + ```bash + ./configure C_FLAGS=-m32 CXX_FLAGS=-m32 LD_FLAGS=-m32 + make + sudo make install + ``` - 64 bit SDL(simple directmedia layer) (Note: only necessary when `WAMR_BUILD_TARGET` is set to `X86_64` when building WAMR runtime) Use apt-get: - `sudo apt-get install libsdl2-dev` -Or download source from www.libsdl.org: -``` -./configure -make -sudo make install -``` + + ```bash + sudo apt-get install libsdl2-dev + ``` + Or download source from www.libsdl.org: + ```bash + ./configure + make + sudo make install + ``` Build and Run -------------- -- Build
-`./build.sh`
+- Build + ```bash + ./build.sh + ``` All binaries are in "out", which contains "host_tool", "ui_decrease.wasm", "ui_increase.wasm" and "wasm_runtime_wgl". -- Run WASM VM Linux applicaton & install WASM APP
- First start wasm_runtime_wgl in server mode.
-`./wasm_runtime_wgl -s`
- Then install wasm APP use host tool.
-`./host_tool -i inc -f ui_increase.wasm`
-`./host_tool -i dec -f ui_decrease.wasm`
- - +- Run WASM VM Linux applicaton & install WASM APP + First start wasm_runtime_wgl in server mode. + ```bash + ./wasm_runtime_wgl -s + ``` + Then install wasm APP by using host tool. + ```bash + ./host_tool -i inc -f ui_increase.wasm + # or + ./host_tool -i dec -f ui_decrease.wasm + ``` Test on Zephyr ================================ We can use a STM32 NUCLEO_F767ZI board with ILI9341 display and XPT2046 touch screen to run the test. Then use host_tool to remotely install wasm app into STM32. -- Build WASM VM into Zephyr system
- a. clone zephyr source code
-Refer to Zephyr getting started.
-https://docs.zephyrproject.org/latest/getting_started/index.html
-`west init zephyrproject`
-`cd zephyrproject`
-`west update`
- b. copy samples
- `cd zephyr/samples/`
- `cp -a samples/gui/wasm-runtime-wgl wasm-runtime-wgl`
- `cd wasm-runtime-wgl/zephyr_build`
- c. create a link to wamr root dir
- ` ln -s wamr`
- d. build source code
- `mkdir build && cd build`
- `source ../../../../zephyr-env.sh`
- `cmake -GNinja -DBOARD=nucleo_f767zi ..`
- ` ninja flash`
+- Build WASM VM into Zephyr system + a. clone zephyr source code +Refer to [Zephyr getting started](https://docs.zephyrproject.org/latest/getting_started/index.html). + + ```bash + west init zephyrproject + cd zephyrproject/zephyr + git checkout zephyr-v2.3.0 + cd .. + west update + ``` + b. copy samples + ```bash + cd zephyr/samples + cp -a samples/gui/wasm-runtime-wgl wasm-runtime-wgl + cd wasm-runtime-wgl/zephyr_build + ``` + c. create a link to wamr root dir + ```bash + ln -s wamr + ``` + d. build source code + ```bash + mkdir build && cd build + source ../../../../zephyr-env.sh + cmake -GNinja -DBOARD=nucleo_f767zi .. + ninja flash + ``` - Hardware Connections @@ -102,16 +120,17 @@ https://docs.zephyrproject.org/latest/getting_started/index.html
+-------------------+-+------------------+ ``` - -- Install WASM application to Zephyr using host_tool
-First, connect PC and STM32 with UART. Then install to use host_tool.
-`./host_tool -D /dev/ttyUSBXXX -i inc -f ui_increase.wasm` +- Install WASM application to Zephyr using host_tool +First, connect PC and STM32 with UART. Then install to use host_tool. + ```bash + ./host_tool -D /dev/ttyUSBXXX -i inc -f ui_increase.wasm + ``` - Install AOT version WASM application -`wamrc --target=thumbv7 --target-abi=eabi --cpu=cortex-m7 -o ui_app.aot ui_increase.wasm` -`./host_tool -D /dev/ttyUSBXXX -i inc -f ui_app.aot` - - + ```bash + wamrc --target=thumbv7 --target-abi=eabi --cpu=cortex-m7 -o ui_app.aot ui_increase.wasm + ./host_tool -D /dev/ttyUSBXXX -i inc -f ui_app.aot + ``` The graphic user interface demo photo: diff --git a/samples/littlevgl/README.md b/samples/littlevgl/README.md index b5e3124d2..0b6bbe9fb 100644 --- a/samples/littlevgl/README.md +++ b/samples/littlevgl/README.md @@ -4,7 +4,7 @@ This sample demonstrates that a graphic user interface application in WebAssembl In this sample, the whole LittlevGL v5.3 source code is built into the WebAssembly code with the user application. The platform interfaces defined by LittlevGL is implemented in the runtime and registered for WASM application through calling wasm_runtime_full_init(). -``` +```C static NativeSymbol native_symbols[] = { EXPORT_WASM_API_WITH_SIG(display_input_read, "(*)i"), EXPORT_WASM_API_WITH_SIG(display_flush, "(iiii*)"), @@ -18,14 +18,14 @@ static NativeSymbol native_symbols[] = { The runtime component supports building target for Linux and Zephyr/STM Nucleo board. The beauty of this sample is the WebAssembly application can have identical display and behavior when running from both runtime environments. That implies we can do majority of application validation from desktop environment as long as two runtime distributions support the same set of application interface. -Below pictures show the WASM application is running on an STM board with an LCD touch panel. +Below pictures show the WASM application is running on an STM board with an LCD touch panel. ![WAMR UI SAMPLE](../../doc/pics/vgl_demo2.png "WAMR UI DEMO STM32") ![WAMR UI SAMPLE](../../doc/pics/vgl_demo_linux.png "WAMR UI DEMO LINUX") -The number on top will plus one each second, and the number on the bottom will plus one when clicked. When users click the blue button, the WASM application increases the counter, and the latest counter value is displayed on the top banner of the touch panel. +The number on top will plus one each second, and the number on the bottom will plus one when clicked. When users click the blue button, the WASM application increases the counter, and the latest counter value is displayed on the top banner of the touch panel. The sample also provides the native Linux version of application without the runtime under folder "vgl-native-ui-app". It can help to check differences between the implementations in native and WebAssembly. @@ -36,57 +36,67 @@ Install required SDK and libraries -------------- - 32 bit SDL(simple directmedia layer) (Note: only necessary when `WAMR_BUILD_TARGET` is set to `X86_32` when building WAMR runtime) Use apt-get: - `sudo apt-get install libsdl2-dev:i386` + ```bash + sudo apt-get install libsdl2-dev:i386 + ``` Or download source from www.libsdl.org: -``` -./configure C_FLAGS=-m32 CXX_FLAGS=-m32 LD_FLAGS=-m32 -make -sudo make install -``` + ```bash + ./configure C_FLAGS=-m32 CXX_FLAGS=-m32 LD_FLAGS=-m32 + make + sudo make install + ``` - 64 bit SDL(simple directmedia layer) (Note: only necessary when `WAMR_BUILD_TARGET` is set to `X86_64` when building WAMR runtime) Use apt-get: - `sudo apt-get install libsdl2-dev` + ```bash + sudo apt-get install libsdl2-dev + ``` Or download source from www.libsdl.org: -``` -./configure -make -sudo make install -``` - + ```bash + ./configure + make + sudo make install + ``` Build and Run -------------- -- Build
-`./build.sh`
+- Build + ```bash + ./build.sh + ``` All binaries are in "out", which contains "host_tool", "vgl_native_ui_app", "ui_app.wasm" "ui_app_no_wasi.wasm "and "vgl_wasm_runtime". -- Run the native Linux build of the lvgl sample (no wasm)
-`./vgl_native_ui_app`
- -- Run WASM VM Linux applicaton & install WASM APP
- First start vgl_wasm_runtime in server mode.
-`./vgl_wasm_runtime -s`
- Then install and uninstall wasm APPs by using host tool.
-`./host_tool -i ui_wasi -f ui_app_wasi.wasm`
-`./host_tool -q`
-`./host_tool -u ui_wasi`
-`./host_tool -i ui_no_wasi -f ui_app_builtin_libc.wasm`
-`./host_tool -q`
-`./host_tool -u ui_no_wasi`
- +- Run the native Linux build of the lvgl sample (no wasm) + ```bash + ./vgl_native_ui_app + ``` +- Run WASM VM Linux applicaton & install WASM APP + First start vgl_wasm_runtime in server mode. + ```bash + ./vgl_wasm_runtime -s + ``` + Then install and uninstall wasm APPs by using host tool. + ```bash + ./host_tool -i ui_wasi -f ui_app_wasi.wasm + ./host_tool -q + ./host_tool -u ui_wasi + ./host_tool -i ui_no_wasi -f ui_app_builtin_libc.wasm + ./host_tool -q + ./host_tool -u ui_no_wasi + ``` Test on Zephyr ================================ We can use a STM32 NUCLEO_F767ZI board with ILI9341 display and XPT2046 touch screen to run the test. Then use host_tool to remotely install wasm app into STM32. - Build WASM VM into Zephyr system a. clone zephyr source code - Refer to Zephyr getting started. - https://docs.zephyrproject.org/latest/getting_started/index.html + Refer to [Zephyr getting started](https://docs.zephyrproject.org/latest/getting_started/index.html). ```bash west init zephyrproject - cd zephyrproject + cd zephyrproject/zephyr + git checkout zephyr-v2.3.0 + cd .. west update ``` @@ -101,24 +111,24 @@ We can use a STM32 NUCLEO_F767ZI board with ILI9341 display and XPT2046 touch s ln -s wamr ``` - d. build source code +d. build source code Since ui_app incorporated LittlevGL source code, so it needs more RAM on the device to install the application. It is recommended that RAM SIZE not less than 380KB. In our test use nucleo_f767zi, which is supported by Zephyr. Since the littlevgl wasm app is quite big (~100KB in wasm format and ~200KB in AOT format ), there isn't enough SRAM to build interpreter and AOT together. You can only choose one of them: - Interpreter - ``` Bash - mkdir build && cd build - source ../../../../zephyr-env.sh - cmake -GNinja -DBOARD=nucleo_f767zi -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_AOT=0 .. - ninja flash - ``` + ```bash + mkdir build && cd build + source ../../../../zephyr-env.sh + cmake -GNinja -DBOARD=nucleo_f767zi -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_AOT=0 .. + ninja flash + ``` - AOT - ``` Bash - mkdir build && cd build - source ../../../../zephyr-env.sh - cmake -GNinja -DBOARD=nucleo_f767zi -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_AOT=1 .. - ninja flash - ``` + ```bash + mkdir build && cd build + source ../../../../zephyr-env.sh + cmake -GNinja -DBOARD=nucleo_f767zi -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_AOT=1 .. + ninja flash + ``` - Hardware Connections @@ -148,12 +158,16 @@ We can use a STM32 NUCLEO_F767ZI board with ILI9341 display and XPT2046 touch s +-------------------+-+------------------+ ``` - -- Install WASM application to Zephyr using host_tool
-First, connect PC and STM32 with UART. Then install to use host_tool.
-`./host_tool -D /dev/ttyUSBXXX -i ui_app -f ui_app_builtin_libc.wasm` +- Install WASM application to Zephyr using host_tool +First, connect PC and STM32 with UART. Then install to use host_tool. + ```bash + ./host_tool -D /dev/ttyUSBXXX -i ui_app -f ui_app_builtin_libc.wasm + ``` **Note**: WASI is unavailable on zephyr currently, so you have to use the ui_app_builtin_libc.wasm which doesn't depend on WASI. - Install AOT version WASM application -`wamrc --target=thumbv7 --target-abi=eabi --cpu=cortex-m7 -o ui_app_no_wasi.aot ui_app_builtin_libc.wasm` -`./host_tool -D /dev/ttyUSBXXX -i ui_app -f ui_app_no_wasi.aot` + ```bash + wamrc --target=thumbv7 --target-abi=eabi --cpu=cortex-m7 -o ui_app_no_wasi.aot ui_app_builtin_libc.wasm + ./host_tool -D /dev/ttyUSBXXX -i ui_app -f ui_app_no_wasi.aot + ``` + diff --git a/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_ili9340.c b/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_ili9340.c index 352c51a0b..eb4295094 100644 --- a/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_ili9340.c +++ b/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_ili9340.c @@ -76,7 +76,7 @@ ili9340_init() data->command_data_gpio = device_get_binding( DT_ILITEK_ILI9340_0_CMD_DATA_GPIOS_CONTROLLER); - if (data->command_data_gpio == NULL) { + if (data->command_data_gpio == NULL) { return -EPERM; } @@ -175,7 +175,7 @@ ili9340_get_framebuffer(const struct device *dev) static int ili9340_display_blanking_off(const struct device *dev) { - struct ili9340_data *data = (struct ili9340_data *)dev->data; + struct ili9340_data *data = (struct ili9340_data *)dev->driver_data; LOG_DBG("Turning display blanking off\n"); ili9340_transmit(data, ILI9340_CMD_DISPLAY_ON, NULL, 0); @@ -185,7 +185,7 @@ ili9340_display_blanking_off(const struct device *dev) static int ili9340_display_blanking_on(const struct device *dev) { - struct ili9340_data *data = (struct ili9340_data *)dev->data; + struct ili9340_data *data = (struct ili9340_data *)dev->driver_data; LOG_DBG("Turning display blanking on\n"); ili9340_transmit(data, ILI9340_CMD_DISPLAY_OFF, NULL, 0); diff --git a/test-tools/host-tool/src/main.c b/test-tools/host-tool/src/main.c index f2fa8dcda..230977b4c 100644 --- a/test-tools/host-tool/src/main.c +++ b/test-tools/host-tool/src/main.c @@ -113,7 +113,7 @@ static int send_request(request_t *request, uint16_t msg_type) if ((req_p = pack_request(request, &req_size)) == NULL) return -1; - /* leanding bytes */ + /* leading bytes */ if (!host_tool_send_data(g_conn_fd, leading, sizeof(leading))) goto ret; @@ -648,8 +648,8 @@ static bool parse_args(int argc, char *argv[], operation *op) * REPLY_TYPE_EVENT: event(request) * REPLY_TYPE_RESPONSE: response */ -static int preocess_reply_data(const char *buf, int len, - imrt_link_recv_context_t *ctx) +static int process_reply_data(const char *buf, int len, + imrt_link_recv_context_t *ctx) { int result = -1; const char *pos = buf; @@ -849,7 +849,7 @@ int main(int argc, char *argv[]) continue; } - reply_type = preocess_reply_data((char *) buffer, n, &recv_ctx); + reply_type = process_reply_data((char *) buffer, n, &recv_ctx); if (reply_type == REPLY_TYPE_RESPONSE) { response_t response[1] = { 0 }; diff --git a/test-tools/host-tool/src/transport.c b/test-tools/host-tool/src/transport.c index d63a0fede..a5d16d2bf 100644 --- a/test-tools/host-tool/src/transport.c +++ b/test-tools/host-tool/src/transport.c @@ -233,11 +233,6 @@ int on_imrt_link_byte_arrive(unsigned char ch, imrt_link_recv_context_t *ctx) return 0; } - if (ctx->message.payload_size > 1024 * 1024) { - SET_RECV_PHASE(ctx, Phase_Non_Start); - return -1; - } - ctx->message.payload = (char *) malloc(ctx->message.payload_size); SET_RECV_PHASE(ctx, Phase_Payload); } From 8f902fa9aeafcf9119198a856240914d75dc73df Mon Sep 17 00:00:00 2001 From: Javan Date: Wed, 24 Mar 2021 15:53:55 +0800 Subject: [PATCH 171/207] Enable Android libc wasi support. (#590) Some libc APIs required by wasi native lib are missing in some Android API versions, only when the version >= 24, all APIs are supported. Add the missing APIs in android platform layer, leave them empty, report error and return failed if they are called. Also update CMakeLists.txt to enable libc wasi by default. Co-authored-by: Wenyong Huang --- .../src/ssp_config.h | 2 +- core/shared/platform/android/platform_init.c | 81 +++++++++++++++++++ .../platform/android/platform_internal.h | 39 +++++++++ product-mini/platforms/android/CMakeLists.txt | 5 +- 4 files changed, 125 insertions(+), 2 deletions(-) diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/ssp_config.h b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/ssp_config.h index c08d28b2c..3dd40b67a 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/ssp_config.h +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/ssp_config.h @@ -14,7 +14,7 @@ #include -#if defined(__FreeBSD__) || defined(__APPLE__) +#if defined(__FreeBSD__) || defined(__APPLE__) || (defined(ANDROID) && __ANDROID_API__ < 28) #define CONFIG_HAS_ARC4RANDOM_BUF 1 #else #define CONFIG_HAS_ARC4RANDOM_BUF 0 diff --git a/core/shared/platform/android/platform_init.c b/core/shared/platform/android/platform_init.c index d250d439b..5353308c1 100644 --- a/core/shared/platform/android/platform_init.c +++ b/core/shared/platform/android/platform_init.c @@ -5,6 +5,12 @@ #include "platform_api_vmcore.h" #include "platform_api_extension.h" + +#define API_NOT_SUPPORT_ERROR(API, VERSION) \ + __android_log_print(ANDROID_LOG_ERROR, "wasm_runtime::", \ + "%s() is only supported when __ANDROID_API__ >= %s.", \ + #API, #VERSION); + int bh_platform_init() { @@ -33,3 +39,78 @@ int os_vprintf(const char *fmt, va_list ap) return __android_log_vprint(ANDROID_LOG_INFO, "wasm_runtime::", fmt, ap); } +#if __ANDROID_API__ < 19 + +int futimens(int __dir_fd, const struct timespec __times[2]) +{ + API_NOT_SUPPORT_ERROR(futimens, 19); + return -1; +} + +#endif + +#if __ANDROID_API__ < 21 + +int posix_fallocate(int __fd, off_t __offset, off_t __length) +{ + API_NOT_SUPPORT_ERROR(posix_fallocate, 21); + return -1; +} + +int posix_fadvise(int fd, off_t offset, off_t len, int advice) +{ + API_NOT_SUPPORT_ERROR(posix_fadvise, 21); + return -1; +} + +int linkat(int __old_dir_fd, const char *__old_path, + int __new_dir_fd, const char *__new_path, int __flags) +{ + API_NOT_SUPPORT_ERROR(linkat, 21); + return -1; +} + +int symlinkat(const char *__old_path, int __new_dir_fd, const char *__new_path) +{ + API_NOT_SUPPORT_ERROR(symlinkat, 21); + return -1; +} + +ssize_t readlinkat(int __dir_fd, const char *__path, char *__buf, size_t __buf_size) +{ + API_NOT_SUPPORT_ERROR(readlinkat, 21); + return -1; +} + +#endif + +#if __ANDROID_API__ < 23 + +long telldir(DIR *__dir) +{ + API_NOT_SUPPORT_ERROR(telldir, 23); + return -1; +} + +void seekdir(DIR *__dir, long __location) +{ + API_NOT_SUPPORT_ERROR(seekdir, 23); +} + +#endif + +#if __ANDROID_API__ < 24 + +ssize_t preadv(int __fd, const struct iovec *__iov, int __count, off_t __offset) +{ + API_NOT_SUPPORT_ERROR(preadv, 24); + return -1; +} + +ssize_t pwritev(int __fd, const struct iovec *__iov, int __count, off_t __offset) +{ + API_NOT_SUPPORT_ERROR(pwritev, 24); + return -1; +} + +#endif diff --git a/core/shared/platform/android/platform_internal.h b/core/shared/platform/android/platform_internal.h index 2e3505f9d..b8b99f16a 100644 --- a/core/shared/platform/android/platform_internal.h +++ b/core/shared/platform/android/platform_internal.h @@ -87,6 +87,45 @@ void os_sigreturn(); #endif /* end of BUILD_TARGET_X86_64/AMD_64/AARCH64 */ #endif /* end of WASM_DISABLE_HW_BOUND_CHECK */ +typedef long int __syscall_slong_t; + +#if __ANDROID_API__ < 19 + +int futimens(int __dir_fd, const struct timespec __times[2]); + +#endif + +#if __ANDROID_API__ < 21 + +int posix_fallocate(int __fd, off_t __offset, off_t __length); + +int posix_fadvise(int fd, off_t offset, off_t len, int advice); + +int linkat(int __old_dir_fd, const char *__old_path, + int __new_dir_fd, const char *__new_path, int __flags); + +int symlinkat(const char *__old_path, int __new_dir_fd, const char *__new_path); + +ssize_t readlinkat(int __dir_fd, const char *__path, char *__buf, size_t __buf_size); + +#endif + +#if __ANDROID_API__ < 23 + +long telldir(DIR *__dir); + +void seekdir(DIR *__dir, long __location); + +#endif + +#if __ANDROID_API__ < 24 + +ssize_t preadv(int __fd, const struct iovec *__iov, int __count, off_t __offset); + +ssize_t pwritev(int __fd, const struct iovec *__iov, int __count, off_t __offset); + +#endif + #ifdef __cplusplus } #endif diff --git a/product-mini/platforms/android/CMakeLists.txt b/product-mini/platforms/android/CMakeLists.txt index 26f9c737e..062a3823c 100644 --- a/product-mini/platforms/android/CMakeLists.txt +++ b/product-mini/platforms/android/CMakeLists.txt @@ -11,6 +11,9 @@ set (ANDROID_NDK $ENV{ANDROID_NDK_HOME}) set (ANDROID_SDK $ENV{ANDROID_SDK_HOME}) set (ANDROID_ABI "x86") set (ANDROID_LD lld) +if (NOT DEFINED ANDROID_PLATFORM) + set (ANDROID_PLATFORM 24) +endif () project (iwasm) @@ -20,7 +23,7 @@ set (WAMR_BUILD_TYPE Release) set (WAMR_BUILD_INTERP 1) set (WAMR_BUILD_AOT 0) set (WAMR_BUILD_LIBC_BUILTIN 1) -set (WAMR_BUILD_LIBC_WASI 0) +set (WAMR_BUILD_LIBC_WASI 1) # Reset default linker flags set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") From 621231a48bb98e0584153d8b8ab7300b4311c3a4 Mon Sep 17 00:00:00 2001 From: Xu Jun <693788454@qq.com> Date: Wed, 24 Mar 2021 18:05:23 +0800 Subject: [PATCH 172/207] Create CI script for android platform (#591) --- .github/workflows/android.yml | 91 +++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 .github/workflows/android.yml diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml new file mode 100644 index 000000000..9be92ad0a --- /dev/null +++ b/.github/workflows/android.yml @@ -0,0 +1,91 @@ +# This is a basic workflow to help you get started with Actions + +name: android + +# Controls when the action will run. +on: + # Triggers the workflow on push or pull request events but only for the master branch + push: + branches: [ main ] + pull_request: + branches: [ main ] + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + # This workflow contains a single job called "build" + build: + # The type of runner that the job will run on + runs-on: ubuntu-latest + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it + - uses: actions/checkout@v2 + + - name: Build iwasm [default] + run: | + cd product-mini/platforms/android + mkdir build && cd build + cmake .. + make + cd .. && rm -rf build + - name: Build iwasm [Classic interp] + run: | + cd product-mini/platforms/android + mkdir build && cd build + cmake .. -DWAMR_BUILD_FAST_INTERP=0 + make + cd .. && rm -rf build + - name: Build iwasm [Multi module] + run: | + cd product-mini/platforms/android + mkdir build && cd build + cmake .. -DWAMR_BUILD_MULTI_MODULE=1 + make + cd .. && rm -rf build + - name: Build iwasm [lib-pthread] + run: | + cd product-mini/platforms/android + mkdir build && cd build + cmake .. -DWAMR_BUILD_LIB_PTHREAD=1 + make + cd .. && rm -rf build + - name: Build iwasm [aot only] + run: | + cd product-mini/platforms/android + mkdir build && cd build + cmake .. -DWAMR_BUILD_AOT=1 -DWAMR_BUILD_INTERP=0 + make + cd .. && rm -rf build + - name: Build iwasm [interp only] + run: | + cd product-mini/platforms/android + mkdir build && cd build + cmake .. -DWAMR_BUILD_AOT=0 + make + cd .. && rm -rf build + - name: Build iwasm [memory profiling] + run: | + cd product-mini/platforms/android + mkdir build && cd build + cmake .. -DWAMR_BUILD_MEMORY_PROFILING=1 + make + cd .. && rm -rf build + - name: Build iwasm [tail call] + run: | + cd product-mini/platforms/android + mkdir build && cd build + cmake .. -DWAMR_BUILD_TAIL_CALL=1 + make + cd .. && rm -rf build + - name: Build iwasm [custom name section] + run: | + cd product-mini/platforms/android + mkdir build && cd build + cmake .. -DWAMR_BUILD_CUSTOM_NAME_SECTION=1 + make + cd .. && rm -rf build From 5a13e1bbbccf2a2db9f256aa948bfde2af1aa946 Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Wed, 24 Mar 2021 21:13:34 -0500 Subject: [PATCH 173/207] Fix compile warnings of wasm-c-api and add more checks (#592) --- core/iwasm/common/wasm_c_api.c | 40 +++++++++++++-------- samples/wasm-c-api/src/globalexportimport.c | 20 +++++++---- 2 files changed, 39 insertions(+), 21 deletions(-) diff --git a/core/iwasm/common/wasm_c_api.c b/core/iwasm/common/wasm_c_api.c index 9e65989b1..5087c30b6 100644 --- a/core/iwasm/common/wasm_c_api.c +++ b/core/iwasm/common/wasm_c_api.c @@ -104,7 +104,9 @@ wasm_byte_vec_copy(wasm_byte_vec_t *out, const wasm_byte_vec_t *src) goto failed; } - len = src->size * src->size_of_elem; + /* integer overflow has been checked in generic_vec_init_data, + no need to check again */ + len = (uint32)(src->size * src->size_of_elem); bh_memcpy_s(out->data, len, src->data, len); out->num_elems = src->num_elems; return; @@ -117,7 +119,7 @@ failed: void wasm_byte_vec_new(wasm_byte_vec_t *out, size_t size, const wasm_byte_t *data) { - size_t size_in_bytes = 0; + uint32 size_in_bytes = 0; bh_assert(out && data); @@ -126,7 +128,9 @@ wasm_byte_vec_new(wasm_byte_vec_t *out, size_t size, const wasm_byte_t *data) goto failed; } - size_in_bytes = size * sizeof(wasm_byte_t); + /* integer overflow has been checked in generic_vec_init_data, + no need to check again */ + size_in_bytes = (uint32)(size * sizeof(wasm_byte_t)); bh_memcpy_s(out->data, size_in_bytes, data, size_in_bytes); out->num_elems = size; return; @@ -435,14 +439,16 @@ wasm_valtype_vec_new(wasm_valtype_vec_t *out, size_t size, wasm_valtype_t *const data[]) { - size_t size_in_bytes = 0; + uint32 size_in_bytes = 0; bh_assert(out && data); generic_vec_init_data((Vector *)out, size, sizeof(wasm_valtype_t *)); if (!out->data) { goto failed; } - size_in_bytes = size * sizeof(wasm_valtype_t *); + /* integer overflow has been checked in generic_vec_init_data, + no need to check again */ + size_in_bytes = (uint32)(size * sizeof(wasm_valtype_t *)); bh_memcpy_s(out->data, size_in_bytes, data, size_in_bytes); out->num_elems = size; return; @@ -924,17 +930,21 @@ wasm_module_new(wasm_store_t *store, const wasm_byte_vec_t *binary) check_engine_and_store(singleton_engine, store); bh_assert(binary && binary->data && binary->size); - pkg_type = get_package_type((uint8 *)binary->data, binary->size); + if (binary->size > UINT32_MAX) { + LOG_ERROR("%s failed", __FUNCTION__); + return NULL; + } + + pkg_type = get_package_type((uint8 *)binary->data, (uint32)binary->size); if (Package_Type_Unknown == pkg_type || (Wasm_Module_Bytecode == pkg_type && INTERP_MODE != current_runtime_mode()) || (Wasm_Module_AoT == pkg_type && INTERP_MODE == current_runtime_mode())) { - LOG_WARNING( - "current runtime mode %d doesn\'t support the package type " - "%d", + LOG_ERROR( + "current runtime mode %d doesn\'t support the package type %d", current_runtime_mode(), pkg_type); - goto failed; + return NULL; } module_ex = malloc_internal(sizeof(wasm_module_ex_t)); @@ -954,10 +964,12 @@ wasm_module_new(wasm_store_t *store, const wasm_byte_vec_t *binary) module_ex->module_comm_rt = wasm_runtime_load((uint8 *)module_ex->binary->data, - module_ex->binary->size, error, (uint32)sizeof(error)); + (uint32)module_ex->binary->size, + error, (uint32)sizeof(error)); if (!(module_ex->module_comm_rt)) { LOG_ERROR(error); - goto failed; + wasm_module_delete_internal(module_ext_to_module(module_ex)); + return NULL; } /* add it to a watching list in store */ @@ -968,7 +980,7 @@ wasm_module_new(wasm_store_t *store, const wasm_byte_vec_t *binary) return module_ext_to_module(module_ex); failed: - LOG_DEBUG("%s failed", __FUNCTION__); + LOG_ERROR("%s failed", __FUNCTION__); wasm_module_delete_internal(module_ext_to_module(module_ex)); return NULL; } @@ -2687,7 +2699,7 @@ wasm_extern_delete(wasm_extern_t *external) wasm_externkind_t wasm_extern_kind(const wasm_extern_t *extrenal) { - return extrenal->kind; + return (wasm_externkind_t)extrenal->kind; } wasm_func_t * diff --git a/samples/wasm-c-api/src/globalexportimport.c b/samples/wasm-c-api/src/globalexportimport.c index 6fc1958a5..076b632eb 100644 --- a/samples/wasm-c-api/src/globalexportimport.c +++ b/samples/wasm-c-api/src/globalexportimport.c @@ -34,8 +34,8 @@ wasm_func_t* get_export_func(const wasm_extern_vec_t* exports, size_t i) { #define check(val, type, expected) \ if (val.of.type != expected) { \ - printf("> Expected reading value %f or %d \n", expected, expected); \ - printf("> Error reading value %f or %d\n", val.of.type, val.of.type); \ + printf("> Expected reading value %f or %f \n", expected, expected); \ + printf("> Error reading value %f or %f\n", val.of.type, val.of.type); \ } #define check_global(global, type, expected) \ @@ -62,14 +62,14 @@ wasm_module_t * create_module_from_file(wasm_store_t* store, const char * filena wasm_byte_vec_new_uninitialized(&binary, file_size); if (fread(binary.data, file_size, 1, file) != 1) { printf("> Error loading module!\n"); - return 1; + return NULL; } // Compile. printf("Compiling module...\n"); own wasm_module_t* module = wasm_module_new(store, &binary); if (!module) { printf("> Error compiling module!\n"); - return 1; + return NULL; } wasm_byte_vec_delete(&binary); fclose(file); @@ -88,11 +88,17 @@ int main(int argc, const char* argv[]) { // Load binary. printf("Loading binary...\n"); #if WASM_ENABLE_AOT != 0 && WASM_ENABLE_INTERP == 0 - wasm_module_t* moduleimport = create_module_from_file(store, "globalimport.aot"); + wasm_module_t* moduleimport = + create_module_from_file(store, "globalimport.aot"); #else - wasm_module_t* moduleimport = create_module_from_file(store, "globalexportimport-1.wasm"); + wasm_module_t* moduleimport = + create_module_from_file(store, "globalexportimport-1.wasm"); #endif + if (!moduleimport) { + return 1; + } + // Instantiate. printf("Instantiating Import module...\n"); own wasm_instance_t* instance_import = @@ -163,4 +169,4 @@ int main(int argc, const char* argv[]) { printf("Done.\n"); return 0; -} \ No newline at end of file +} From 22bcfe204e322dfce82bc60cf76ea88a603a745c Mon Sep 17 00:00:00 2001 From: Xu Jun <693788454@qq.com> Date: Thu, 1 Apr 2021 15:07:00 +0800 Subject: [PATCH 174/207] fix aux stack overwritten issue when lib-pthread is enabled (#596) --- core/iwasm/aot/aot_runtime.c | 35 +++++++++++---- core/iwasm/interpreter/wasm_runtime.c | 37 ++++++++++++---- .../libraries/thread-mgr/thread_manager.c | 43 +++++++++++++++++++ .../libraries/thread-mgr/thread_manager.h | 3 ++ 4 files changed, 101 insertions(+), 17 deletions(-) diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index 136e97652..594118239 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -10,6 +10,9 @@ #if WASM_ENABLE_SHARED_MEMORY != 0 #include "../common/wasm_shared_memory.h" #endif +#if WASM_ENABLE_THREAD_MGR != 0 +#include "../libraries/thread-mgr/thread_manager.h" +#endif static void set_error_buf(char *error_buf, uint32 error_buf_size, const char *string) @@ -1319,17 +1322,33 @@ aot_create_exec_env_and_call_function(AOTModuleInstance *module_inst, WASMExecEnv *exec_env; bool ret; - if (!(exec_env = wasm_exec_env_create((WASMModuleInstanceCommon*)module_inst, - module_inst->default_wasm_stack_size))) { - aot_set_exception(module_inst, "allocate memory failed"); - return false; - } +#if WASM_ENABLE_THREAD_MGR != 0 + WASMExecEnv *existing_exec_env = NULL; - /* set thread handle and stack boundary */ - wasm_exec_env_set_thread_info(exec_env); + if (!(existing_exec_env = exec_env = + wasm_clusters_search_exec_env( + (WASMModuleInstanceCommon*)module_inst))) { +#endif + if (!(exec_env = wasm_exec_env_create((WASMModuleInstanceCommon*)module_inst, + module_inst->default_wasm_stack_size))) { + aot_set_exception(module_inst, "allocate memory failed"); + return false; + } + + /* set thread handle and stack boundary */ + wasm_exec_env_set_thread_info(exec_env); +#if WASM_ENABLE_THREAD_MGR != 0 + } +#endif ret = aot_call_function(exec_env, func, argc, argv); - wasm_exec_env_destroy(exec_env); + +#if WASM_ENABLE_THREAD_MGR != 0 + /* don't destroy the exec_env if it's searched from the cluster */ + if (!existing_exec_env) +#endif + wasm_exec_env_destroy(exec_env); + return ret; } diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index a17bd9035..c742553c3 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -13,6 +13,9 @@ #if WASM_ENABLE_SHARED_MEMORY != 0 #include "../common/wasm_shared_memory.h" #endif +#if WASM_ENABLE_THREAD_MGR != 0 +#include "../libraries/thread-mgr/thread_manager.h" +#endif static void set_error_buf(char *error_buf, uint32 error_buf_size, const char *string) @@ -1593,18 +1596,34 @@ wasm_create_exec_env_and_call_function(WASMModuleInstance *module_inst, WASMExecEnv *exec_env; bool ret; - if (!(exec_env = wasm_exec_env_create( - (WASMModuleInstanceCommon*)module_inst, - module_inst->default_wasm_stack_size))) { - wasm_set_exception(module_inst, "allocate memory failed"); - return false; - } +#if WASM_ENABLE_THREAD_MGR != 0 + WASMExecEnv *existing_exec_env = NULL; - /* set thread handle and stack boundary */ - wasm_exec_env_set_thread_info(exec_env); + if (!(existing_exec_env = exec_env = + wasm_clusters_search_exec_env( + (WASMModuleInstanceCommon*)module_inst))) { +#endif + if (!(exec_env = wasm_exec_env_create( + (WASMModuleInstanceCommon*)module_inst, + module_inst->default_wasm_stack_size))) { + wasm_set_exception(module_inst, "allocate memory failed"); + return false; + } + + /* set thread handle and stack boundary */ + wasm_exec_env_set_thread_info(exec_env); +#if WASM_ENABLE_THREAD_MGR != 0 + } +#endif ret = wasm_call_function(exec_env, func, argc, argv); - wasm_exec_env_destroy(exec_env); + +#if WASM_ENABLE_THREAD_MGR != 0 + /* don't destroy the exec_env if it's searched from the cluster */ + if (!existing_exec_env) +#endif + wasm_exec_env_destroy(exec_env); + return ret; } diff --git a/core/iwasm/libraries/thread-mgr/thread_manager.c b/core/iwasm/libraries/thread-mgr/thread_manager.c index 6f2dcbae1..afcc170c8 100644 --- a/core/iwasm/libraries/thread-mgr/thread_manager.c +++ b/core/iwasm/libraries/thread-mgr/thread_manager.c @@ -281,6 +281,49 @@ wasm_cluster_del_exec_env(WASMCluster *cluster, WASMExecEnv *exec_env) return ret; } +static WASMExecEnv * +wasm_cluster_search_exec_env(WASMCluster *cluster, + WASMModuleInstanceCommon *module_inst) +{ + WASMExecEnv *node = NULL; + + os_mutex_lock(&cluster->lock); + node = bh_list_first_elem(&cluster->exec_env_list); + while (node) { + if (node->module_inst == module_inst) { + os_mutex_unlock(&cluster->lock); + return node; + } + node = bh_list_elem_next(node); + } + + os_mutex_unlock(&cluster->lock); + return NULL; +} + +/* search the global cluster list to find if the given + module instance have a corresponding exec_env */ +WASMExecEnv * +wasm_clusters_search_exec_env(WASMModuleInstanceCommon *module_inst) +{ + WASMCluster *cluster = NULL; + WASMExecEnv *exec_env = NULL; + + os_mutex_lock(&cluster_list_lock); + cluster = bh_list_first_elem(cluster_list); + while (cluster) { + exec_env = wasm_cluster_search_exec_env(cluster, module_inst); + if (exec_env) { + os_mutex_unlock(&cluster_list_lock); + return exec_env; + } + cluster = bh_list_elem_next(cluster); + } + + os_mutex_unlock(&cluster_list_lock); + return NULL; +} + WASMExecEnv * wasm_cluster_spawn_exec_env(WASMExecEnv *exec_env) { diff --git a/core/iwasm/libraries/thread-mgr/thread_manager.h b/core/iwasm/libraries/thread-mgr/thread_manager.h index eb5550a27..c43d0e644 100644 --- a/core/iwasm/libraries/thread-mgr/thread_manager.h +++ b/core/iwasm/libraries/thread-mgr/thread_manager.h @@ -106,6 +106,9 @@ wasm_cluster_add_exec_env(WASMCluster *cluster, WASMExecEnv *exec_env); bool wasm_cluster_del_exec_env(WASMCluster *cluster, WASMExecEnv *exec_env); +WASMExecEnv * +wasm_clusters_search_exec_env(WASMModuleInstanceCommon *module_inst); + void wasm_cluster_spread_exception(WASMExecEnv *exec_env); From 7db2221ad94cd73e88e958a2040e2b66a75519e1 Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Thu, 1 Apr 2021 03:50:46 -0500 Subject: [PATCH 175/207] Re-org address unalignment access for fast-interp (#597) And clear some compile warnings on wasm loader, add ${UV_A_LIBS} for some CMakeLists.txt. --- core/config.h | 14 +- core/iwasm/aot/aot_runtime.c | 15 - core/iwasm/common/wasm_runtime_common.c | 14 - core/iwasm/common/wasm_runtime_common.h | 224 ++++++ core/iwasm/interpreter/wasm_interp_classic.c | 208 +---- core/iwasm/interpreter/wasm_interp_fast.c | 752 +++++++----------- core/iwasm/interpreter/wasm_loader.c | 171 ++-- core/iwasm/interpreter/wasm_mini_loader.c | 174 ++-- product-mini/platforms/android/CMakeLists.txt | 4 +- product-mini/platforms/darwin/CMakeLists.txt | 4 +- product-mini/platforms/linux/CMakeLists.txt | 2 +- product-mini/platforms/windows/CMakeLists.txt | 4 +- 12 files changed, 790 insertions(+), 796 deletions(-) diff --git a/core/config.h b/core/config.h index 1fbc77c59..02ceb680f 100644 --- a/core/config.h +++ b/core/config.h @@ -131,18 +131,23 @@ #define WASM_ENABLE_LOG 1 #endif -#if defined(BUILD_TARGET_X86_32) || defined(BUILD_TARGET_X86_64) -#define WASM_CPU_SUPPORTS_UNALIGNED_64BIT_ACCESS 1 +#ifndef WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS +#if defined(BUILD_TARGET_X86_32) || defined(BUILD_TARGET_X86_64) \ + || defined(BUILD_TARGET_AARCH64) +#define WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS 1 #else -#define WASM_CPU_SUPPORTS_UNALIGNED_64BIT_ACCESS 0 +#define WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS 0 +#endif #endif /* WASM Interpreter labels-as-values feature */ +#ifndef WASM_ENABLE_LABELS_AS_VALUES #ifdef __GNUC__ #define WASM_ENABLE_LABELS_AS_VALUES 1 #else #define WASM_ENABLE_LABELS_AS_VALUES 0 #endif +#endif /* Enable fast interpreter or not */ #ifndef WASM_ENABLE_FAST_INTERP @@ -150,10 +155,7 @@ #endif #if WASM_ENABLE_FAST_INTERP != 0 -#define WASM_ENABLE_ABS_LABEL_ADDR 1 #define WASM_DEBUG_PREPROCESSOR 0 -#else -#define WASM_ENABLE_ABS_LABEL_ADDR 0 #endif /* Enable opcode counter or not */ diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index 594118239..8dc964f39 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -1001,21 +1001,6 @@ aot_lookup_function(const AOTModuleInstance *module_inst, return NULL; } -#define PUT_I64_TO_ADDR(addr, value) do { \ - union { int64 val; uint32 parts[2]; } u; \ - u.val = (value); \ - (addr)[0] = u.parts[0]; \ - (addr)[1] = u.parts[1]; \ - } while (0) - -#define PUT_F64_TO_ADDR(addr, value) do { \ - union { float64 val; uint32 parts[2]; } u; \ - u.val = (value); \ - (addr)[0] = u.parts[0]; \ - (addr)[1] = u.parts[1]; \ - } while (0) - - #ifdef OS_ENABLE_HW_BOUND_CHECK #define STACK_OVERFLOW_CHECK_GUARD_PAGE_COUNT 3 diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index 95d2fd7af..b6ce8eff9 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -2825,20 +2825,6 @@ fail: * Implementation of wasm_runtime_invoke_native() */ -#define PUT_I64_TO_ADDR(addr, value) do { \ - union { int64 val; uint32 parts[2]; } u; \ - u.val = (value); \ - (addr)[0] = u.parts[0]; \ - (addr)[1] = u.parts[1]; \ - } while (0) - -#define PUT_F64_TO_ADDR(addr, value) do { \ - union { float64 val; uint32 parts[2]; } u; \ - u.val = (value); \ - (addr)[0] = u.parts[0]; \ - (addr)[1] = u.parts[1]; \ - } while (0) - /* The invoke native implementation on ARM platform with VFP co-processor */ #if defined(BUILD_TARGET_ARM_VFP) \ || defined(BUILD_TARGET_THUMB_VFP) \ diff --git a/core/iwasm/common/wasm_runtime_common.h b/core/iwasm/common/wasm_runtime_common.h index 3baa101b4..06c8bfc8f 100644 --- a/core/iwasm/common/wasm_runtime_common.h +++ b/core/iwasm/common/wasm_runtime_common.h @@ -25,6 +25,230 @@ extern "C" { #endif +#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS != 0 + +#define PUT_I64_TO_ADDR(addr, value) do { \ + *(int64*)(addr) = (int64)(value); \ + } while (0) +#define PUT_F64_TO_ADDR(addr, value) do { \ + *(float64*)(addr) = (float64)(value); \ + } while (0) + +#define GET_I64_FROM_ADDR(addr) (*(int64*)(addr)) +#define GET_F64_FROM_ADDR(addr) (*(float64*)(addr)) + +/* For STORE opcodes */ +#define STORE_I64 PUT_I64_TO_ADDR +#define STORE_U32(addr, value) do { \ + *(uint32*)(addr) = (uint32)(value); \ + } while (0) +#define STORE_U16(addr, value) do { \ + *(uint16*)(addr) = (uint16)(value); \ + } while (0) + +/* For LOAD opcodes */ +#define LOAD_I64(addr) (*(int64*)(addr)) +#define LOAD_F64(addr) (*(float64*)(addr)) +#define LOAD_I32(addr) (*(int32*)(addr)) +#define LOAD_U32(addr) (*(uint32*)(addr)) +#define LOAD_I16(addr) (*(int16*)(addr)) +#define LOAD_U16(addr) (*(uint16*)(addr)) + +#define STORE_PTR(addr, ptr) do { \ + *(void**)addr = (void*)ptr; \ + } while (0) +#define LOAD_PTR(addr) (*(void**)(addr)) + +#else /* WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS != 0 */ + +#define PUT_I64_TO_ADDR(addr, value) do { \ + uint32 *addr_u32 = (uint32*)(addr); \ + union { int64 val; uint32 parts[2]; } u; \ + u.val = (int64)(value); \ + addr_u32[0] = u.parts[0]; \ + addr_u32[1] = u.parts[1]; \ + } while (0) +#define PUT_F64_TO_ADDR(addr, value) do { \ + uint32 *addr_u32 = (uint32*)(addr); \ + union { float64 val; uint32 parts[2]; } u; \ + u.val = (value); \ + addr_u32[0] = u.parts[0]; \ + addr_u32[1] = u.parts[1]; \ + } while (0) + +static inline int64 +GET_I64_FROM_ADDR(uint32 *addr) +{ + union { int64 val; uint32 parts[2]; } u; + u.parts[0] = addr[0]; + u.parts[1] = addr[1]; + return u.val; +} + +static inline float64 +GET_F64_FROM_ADDR (uint32 *addr) +{ + union { float64 val; uint32 parts[2]; } u; + u.parts[0] = addr[0]; + u.parts[1] = addr[1]; + return u.val; +} + +/* For STORE opcodes */ +#define STORE_I64(addr, value) do { \ + uintptr_t addr1 = (uintptr_t)(addr); \ + union { int64 val; uint32 u32[2]; \ + uint16 u16[4]; uint8 u8[8]; } u; \ + if ((addr1 & (uintptr_t)7) == 0) \ + *(int64*)(addr) = (int64)(value); \ + else { \ + u.val = (int64)(value); \ + if ((addr1 & (uintptr_t)3) == 0) { \ + ((uint32*)(addr))[0] = u.u32[0]; \ + ((uint32*)(addr))[1] = u.u32[1]; \ + } \ + else if ((addr1 & (uintptr_t)1) == 0) { \ + ((uint16*)(addr))[0] = u.u16[0]; \ + ((uint16*)(addr))[1] = u.u16[1]; \ + ((uint16*)(addr))[2] = u.u16[2]; \ + ((uint16*)(addr))[3] = u.u16[3]; \ + } \ + else { \ + int32 t; \ + for (t = 0; t < 8; t++) \ + ((uint8*)(addr))[t] = u.u8[t]; \ + } \ + } \ + } while (0) + +#define STORE_U32(addr, value) do { \ + uintptr_t addr1 = (uintptr_t)(addr); \ + union { uint32 val; \ + uint16 u16[2]; uint8 u8[4]; } u; \ + if ((addr1 & (uintptr_t)3) == 0) \ + *(uint32*)(addr) = (uint32)(value); \ + else { \ + u.val = (uint32)(value); \ + if ((addr1 & (uintptr_t)1) == 0) { \ + ((uint16*)(addr))[0] = u.u16[0]; \ + ((uint16*)(addr))[1] = u.u16[1]; \ + } \ + else { \ + ((uint8*)(addr))[0] = u.u8[0]; \ + ((uint8*)(addr))[1] = u.u8[1]; \ + ((uint8*)(addr))[2] = u.u8[2]; \ + ((uint8*)(addr))[3] = u.u8[3]; \ + } \ + } \ + } while (0) + +#define STORE_U16(addr, value) do { \ + union { uint16 val; uint8 u8[2]; } u; \ + u.val = (uint16)(value); \ + ((uint8*)(addr))[0] = u.u8[0]; \ + ((uint8*)(addr))[1] = u.u8[1]; \ + } while (0) + +/* For LOAD opcodes */ +static inline int64 +LOAD_I64(void *addr) +{ + uintptr_t addr1 = (uintptr_t)addr; + union { int64 val; uint32 u32[2]; + uint16 u16[4]; uint8 u8[8]; } u; + if ((addr1 & (uintptr_t)7) == 0) + return *(int64*)addr; + + if ((addr1 & (uintptr_t)3) == 0) { + u.u32[0] = ((uint32*)addr)[0]; + u.u32[1] = ((uint32*)addr)[1]; + } + else if ((addr1 & (uintptr_t)1) == 0) { + u.u16[0] = ((uint16*)addr)[0]; + u.u16[1] = ((uint16*)addr)[1]; + u.u16[2] = ((uint16*)addr)[2]; + u.u16[3] = ((uint16*)addr)[3]; + } + else { + int32 t; + for (t = 0; t < 8; t++) + u.u8[t] = ((uint8*)addr)[t]; + } + return u.val; +} + +static inline float64 +LOAD_F64(void *addr) +{ + uintptr_t addr1 = (uintptr_t)addr; + union { float64 val; uint32 u32[2]; + uint16 u16[4]; uint8 u8[8]; } u; + if ((addr1 & (uintptr_t)7) == 0) + return *(float64*)addr; + + if ((addr1 & (uintptr_t)3) == 0) { + u.u32[0] = ((uint32*)addr)[0]; + u.u32[1] = ((uint32*)addr)[1]; + } + else if ((addr1 & (uintptr_t)1) == 0) { + u.u16[0] = ((uint16*)addr)[0]; + u.u16[1] = ((uint16*)addr)[1]; + u.u16[2] = ((uint16*)addr)[2]; + u.u16[3] = ((uint16*)addr)[3]; + } + else { + int32 t; + for (t = 0; t < 8; t++) + u.u8[t] = ((uint8*)addr)[t]; + } + return u.val; +} + +static inline int32 +LOAD_I32(void *addr) +{ + uintptr_t addr1 = (uintptr_t)addr; + union { int32 val; uint16 u16[2]; uint8 u8[4]; } u; + if ((addr1 & (uintptr_t)3) == 0) + return *(int32*)addr; + + if ((addr1 & (uintptr_t)1) == 0) { + u.u16[0] = ((uint16*)addr)[0]; + u.u16[1] = ((uint16*)addr)[1]; + } + else { + u.u8[0] = ((uint8*)addr)[0]; + u.u8[1] = ((uint8*)addr)[1]; + u.u8[2] = ((uint8*)addr)[2]; + u.u8[3] = ((uint8*)addr)[3]; + } + return u.val; +} + +static inline int16 +LOAD_I16(void *addr) +{ + uintptr_t addr1 = (uintptr_t)addr; + union { int16 val; uint8 u8[2]; } u; + if ((addr1 & (uintptr_t)1)) { + u.u8[0] = ((uint8*)addr)[0]; + u.u8[1] = ((uint8*)addr)[1]; + return u.val; + } + return *(int16*)addr; +} + +#define LOAD_U32(addr) ((uint32)LOAD_I32(addr)) +#define LOAD_U16(addr) ((uint16)LOAD_I16(addr)) + +#if UINTPTR_MAX == UINT32_MAX +#define STORE_PTR(addr, ptr) STORE_U32(addr, (uintptr_t)ptr) +#elif UINTPTR_MAX == UINT64_MAX +#define STORE_PTR(addr, ptr) STORE_I64(addr, (uintptr_t)ptr) +#endif + +#endif /* WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS != 0 */ + typedef struct WASMModuleCommon { /* Module type, for module loaded from WASM bytecode binary, this field is Wasm_Module_Bytecode, and this structure should diff --git a/core/iwasm/interpreter/wasm_interp_classic.c b/core/iwasm/interpreter/wasm_interp_classic.c index c3ccf2d94..16dd27cc8 100644 --- a/core/iwasm/interpreter/wasm_interp_classic.c +++ b/core/iwasm/interpreter/wasm_interp_classic.c @@ -20,212 +20,6 @@ typedef float64 CellType_F64; #define BR_TABLE_TMP_BUF_LEN 32 -/* 64-bit Memory accessors. */ -#if WASM_CPU_SUPPORTS_UNALIGNED_64BIT_ACCESS != 0 -#define PUT_I64_TO_ADDR(addr, value) do { \ - *(int64*)(addr) = (int64)(value); \ - } while (0) -#define PUT_F64_TO_ADDR(addr, value) do { \ - *(float64*)(addr) = (float64)(value); \ - } while (0) - -#define GET_I64_FROM_ADDR(addr) (*(int64*)(addr)) -#define GET_F64_FROM_ADDR(addr) (*(float64*)(addr)) - -/* For STORE opcodes */ -#define STORE_I64 PUT_I64_TO_ADDR -#define STORE_U32(addr, value) do { \ - *(uint32*)(addr) = (uint32)(value); \ - } while (0) -#define STORE_U16(addr, value) do { \ - *(uint16*)(addr) = (uint16)(value); \ - } while (0) - -/* For LOAD opcodes */ -#define LOAD_I64(addr) (*(int64*)(addr)) -#define LOAD_F64(addr) (*(float64*)(addr)) -#define LOAD_I32(addr) (*(int32*)(addr)) -#define LOAD_U32(addr) (*(uint32*)(addr)) -#define LOAD_I16(addr) (*(int16*)(addr)) -#define LOAD_U16(addr) (*(uint16*)(addr)) - -#else /* WASM_CPU_SUPPORTS_UNALIGNED_64BIT_ACCESS != 0 */ -#define PUT_I64_TO_ADDR(addr, value) do { \ - union { int64 val; uint32 parts[2]; } u; \ - u.val = (int64)(value); \ - (addr)[0] = u.parts[0]; \ - (addr)[1] = u.parts[1]; \ - } while (0) -#define PUT_F64_TO_ADDR(addr, value) do { \ - union { float64 val; uint32 parts[2]; } u; \ - u.val = (value); \ - (addr)[0] = u.parts[0]; \ - (addr)[1] = u.parts[1]; \ - } while (0) - -static inline int64 -GET_I64_FROM_ADDR(uint32 *addr) -{ - union { int64 val; uint32 parts[2]; } u; - u.parts[0] = addr[0]; - u.parts[1] = addr[1]; - return u.val; -} - -static inline float64 -GET_F64_FROM_ADDR (uint32 *addr) -{ - union { float64 val; uint32 parts[2]; } u; - u.parts[0] = addr[0]; - u.parts[1] = addr[1]; - return u.val; -} - -/* For STORE opcodes */ -#define STORE_I64(addr, value) do { \ - uintptr_t addr1 = (uintptr_t)(addr); \ - union { int64 val; uint32 u32[2]; \ - uint16 u16[4]; uint8 u8[8]; } u; \ - if ((addr1 & (uintptr_t)7) == 0) \ - *(int64*)(addr) = (int64)(value); \ - else { \ - u.val = (int64)(value); \ - if ((addr1 & (uintptr_t)3) == 0) { \ - ((uint32*)(addr))[0] = u.u32[0]; \ - ((uint32*)(addr))[1] = u.u32[1]; \ - } \ - else if ((addr1 & (uintptr_t)1) == 0) { \ - ((uint16*)(addr))[0] = u.u16[0]; \ - ((uint16*)(addr))[1] = u.u16[1]; \ - ((uint16*)(addr))[2] = u.u16[2]; \ - ((uint16*)(addr))[3] = u.u16[3]; \ - } \ - else { \ - int32 t; \ - for (t = 0; t < 8; t++) \ - ((uint8*)(addr))[t] = u.u8[t]; \ - } \ - } \ - } while (0) - -#define STORE_U32(addr, value) do { \ - uintptr_t addr1 = (uintptr_t)(addr); \ - union { uint32 val; \ - uint16 u16[2]; uint8 u8[4]; } u; \ - if ((addr1 & (uintptr_t)3) == 0) \ - *(uint32*)(addr) = (uint32)(value); \ - else { \ - u.val = (uint32)(value); \ - if ((addr1 & (uintptr_t)1) == 0) { \ - ((uint16*)(addr))[0] = u.u16[0]; \ - ((uint16*)(addr))[1] = u.u16[1]; \ - } \ - else { \ - ((uint8*)(addr))[0] = u.u8[0]; \ - ((uint8*)(addr))[1] = u.u8[1]; \ - ((uint8*)(addr))[2] = u.u8[2]; \ - ((uint8*)(addr))[3] = u.u8[3]; \ - } \ - } \ - } while (0) - -#define STORE_U16(addr, value) do { \ - union { uint16 val; uint8 u8[2]; } u; \ - u.val = (uint16)(value); \ - ((uint8*)(addr))[0] = u.u8[0]; \ - ((uint8*)(addr))[1] = u.u8[1]; \ - } while (0) - -/* For LOAD opcodes */ -static inline int64 -LOAD_I64(void *addr) -{ - uintptr_t addr1 = (uintptr_t)addr; - union { int64 val; uint32 u32[2]; - uint16 u16[4]; uint8 u8[8]; } u; - if ((addr1 & (uintptr_t)7) == 0) - return *(int64*)addr; - - if ((addr1 & (uintptr_t)3) == 0) { - u.u32[0] = ((uint32*)addr)[0]; - u.u32[1] = ((uint32*)addr)[1]; - } - else if ((addr1 & (uintptr_t)1) == 0) { - u.u16[0] = ((uint16*)addr)[0]; - u.u16[1] = ((uint16*)addr)[1]; - u.u16[2] = ((uint16*)addr)[2]; - u.u16[3] = ((uint16*)addr)[3]; - } - else { - int32 t; - for (t = 0; t < 8; t++) - u.u8[t] = ((uint8*)addr)[t]; - } - return u.val; -} - -static inline float64 -LOAD_F64(void *addr) -{ - uintptr_t addr1 = (uintptr_t)addr; - union { float64 val; uint32 u32[2]; - uint16 u16[4]; uint8 u8[8]; } u; - if ((addr1 & (uintptr_t)7) == 0) - return *(float64*)addr; - - if ((addr1 & (uintptr_t)3) == 0) { - u.u32[0] = ((uint32*)addr)[0]; - u.u32[1] = ((uint32*)addr)[1]; - } - else if ((addr1 & (uintptr_t)1) == 0) { - u.u16[0] = ((uint16*)addr)[0]; - u.u16[1] = ((uint16*)addr)[1]; - u.u16[2] = ((uint16*)addr)[2]; - u.u16[3] = ((uint16*)addr)[3]; - } - else { - int32 t; - for (t = 0; t < 8; t++) - u.u8[t] = ((uint8*)addr)[t]; - } - return u.val; -} - -static inline int32 -LOAD_I32(void *addr) -{ - uintptr_t addr1 = (uintptr_t)addr; - union { int32 val; uint16 u16[2]; uint8 u8[4]; } u; - if ((addr1 & (uintptr_t)3) == 0) - return *(int32*)addr; - - if ((addr1 & (uintptr_t)1) == 0) { - u.u16[0] = ((uint16*)addr)[0]; - u.u16[1] = ((uint16*)addr)[1]; - } - else { - u.u8[0] = ((uint8*)addr)[0]; - u.u8[1] = ((uint8*)addr)[1]; - u.u8[2] = ((uint8*)addr)[2]; - u.u8[3] = ((uint8*)addr)[3]; - } - return u.val; -} - -static inline int16 -LOAD_I16(void *addr) -{ - union { int16 val; uint8 u8[2]; } u; - u.u8[0] = ((uint8*)addr)[0]; - u.u8[1] = ((uint8*)addr)[1]; - return u.val; -} - -#define LOAD_U32(addr) ((uint32)LOAD_I32(addr)) -#define LOAD_U16(addr) ((uint16)LOAD_I16(addr)) - -#endif /* WASM_CPU_SUPPORTS_UNALIGNED_64BIT_ACCESS != 0 */ - #define CHECK_MEMORY_OVERFLOW(bytes) do { \ uint64 offset1 = (uint64)offset + (uint64)addr; \ if (offset1 + bytes <= (uint64)linear_mem_size) \ @@ -579,7 +373,7 @@ read_leb(const uint8 *buf, uint32 *p_offset, uint32 maxbits, bool sign) *(src_type2*)(frame_sp); \ } while (0) -#if WASM_CPU_SUPPORTS_UNALIGNED_64BIT_ACCESS != 0 +#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS != 0 #define DEF_OP_NUMERIC_64 DEF_OP_NUMERIC #else #define DEF_OP_NUMERIC_64(src_type1, src_type2, src_op_type, operation) do {\ diff --git a/core/iwasm/interpreter/wasm_interp_fast.c b/core/iwasm/interpreter/wasm_interp_fast.c index 5f5dd5f1d..465d8b0e1 100644 --- a/core/iwasm/interpreter/wasm_interp_fast.c +++ b/core/iwasm/interpreter/wasm_interp_fast.c @@ -18,216 +18,6 @@ typedef int64 CellType_I64; typedef float32 CellType_F32; typedef float64 CellType_F64; -#define BR_TABLE_TMP_BUF_LEN 32 - -/* 64-bit Memory accessors. */ -#if WASM_CPU_SUPPORTS_UNALIGNED_64BIT_ACCESS != 0 -#define PUT_I64_TO_ADDR(addr, value) do { \ - *(int64*)(addr) = (int64)(value); \ - } while (0) -#define PUT_F64_TO_ADDR(addr, value) do { \ - *(float64*)(addr) = (float64)(value); \ - } while (0) - -#define GET_I64_FROM_ADDR(addr) (*(int64*)(addr)) -#define GET_F64_FROM_ADDR(addr) (*(float64*)(addr)) - -/* For STORE opcodes */ -#define STORE_I64 PUT_I64_TO_ADDR -#define STORE_U32(addr, value) do { \ - *(uint32*)(addr) = (uint32)(value); \ - } while (0) -#define STORE_U16(addr, value) do { \ - *(uint16*)(addr) = (uint16)(value); \ - } while (0) - -/* For LOAD opcodes */ -#define LOAD_I64(addr) (*(int64*)(addr)) -#define LOAD_F64(addr) (*(float64*)(addr)) -#define LOAD_F32(addr) (*(float32*)(addr)) -#define LOAD_I32(addr) (*(int32*)(addr)) -#define LOAD_U32(addr) (*(uint32*)(addr)) -#define LOAD_I16(addr) (*(int16*)(addr)) -#define LOAD_U16(addr) (*(uint16*)(addr)) - -#else /* WASM_CPU_SUPPORTS_UNALIGNED_64BIT_ACCESS != 0 */ -#define PUT_I64_TO_ADDR(addr, value) do { \ - union { int64 val; uint32 parts[2]; } u; \ - u.val = (int64)(value); \ - (addr)[0] = u.parts[0]; \ - (addr)[1] = u.parts[1]; \ - } while (0) -#define PUT_F64_TO_ADDR(addr, value) do { \ - union { float64 val; uint32 parts[2]; } u; \ - u.val = (value); \ - (addr)[0] = u.parts[0]; \ - (addr)[1] = u.parts[1]; \ - } while (0) - -static inline int64 -GET_I64_FROM_ADDR(uint32 *addr) -{ - union { int64 val; uint32 parts[2]; } u; - u.parts[0] = addr[0]; - u.parts[1] = addr[1]; - return u.val; -} - -static inline float64 -GET_F64_FROM_ADDR (uint32 *addr) -{ - union { float64 val; uint32 parts[2]; } u; - u.parts[0] = addr[0]; - u.parts[1] = addr[1]; - return u.val; -} - -/* For STORE opcodes */ -#define STORE_I64(addr, value) do { \ - uintptr_t addr1 = (uintptr_t)(addr); \ - union { int64 val; uint32 u32[2]; \ - uint16 u16[4]; uint8 u8[8]; } u; \ - if ((addr1 & (uintptr_t)7) == 0) \ - *(int64*)(addr) = (int64)(value); \ - else { \ - u.val = (int64)(value); \ - if ((addr1 & (uintptr_t)3) == 0) { \ - ((uint32*)(addr))[0] = u.u32[0]; \ - ((uint32*)(addr))[1] = u.u32[1]; \ - } \ - else if ((addr1 & (uintptr_t)1) == 0) { \ - ((uint16*)(addr))[0] = u.u16[0]; \ - ((uint16*)(addr))[1] = u.u16[1]; \ - ((uint16*)(addr))[2] = u.u16[2]; \ - ((uint16*)(addr))[3] = u.u16[3]; \ - } \ - else { \ - int32 t; \ - for (t = 0; t < 8; t++) \ - ((uint8*)(addr))[t] = u.u8[t]; \ - } \ - } \ - } while (0) - -#define STORE_U32(addr, value) do { \ - uintptr_t addr1 = (uintptr_t)(addr); \ - union { uint32 val; \ - uint16 u16[2]; uint8 u8[4]; } u; \ - if ((addr1 & (uintptr_t)3) == 0) \ - *(uint32*)(addr) = (uint32)(value); \ - else { \ - u.val = (uint32)(value); \ - if ((addr1 & (uintptr_t)1) == 0) { \ - ((uint16*)(addr))[0] = u.u16[0]; \ - ((uint16*)(addr))[1] = u.u16[1]; \ - } \ - else { \ - ((uint8*)(addr))[0] = u.u8[0]; \ - ((uint8*)(addr))[1] = u.u8[1]; \ - ((uint8*)(addr))[2] = u.u8[2]; \ - ((uint8*)(addr))[3] = u.u8[3]; \ - } \ - } \ - } while (0) - -#define STORE_U16(addr, value) do { \ - union { uint16 val; uint8 u8[2]; } u; \ - u.val = (uint16)(value); \ - ((uint8*)(addr))[0] = u.u8[0]; \ - ((uint8*)(addr))[1] = u.u8[1]; \ - } while (0) - -/* For LOAD opcodes */ -static inline int64 -LOAD_I64(void *addr) -{ - uintptr_t addr1 = (uintptr_t)addr; - union { int64 val; uint32 u32[2]; - uint16 u16[4]; uint8 u8[8]; } u; - if ((addr1 & (uintptr_t)7) == 0) - return *(int64*)addr; - - if ((addr1 & (uintptr_t)3) == 0) { - u.u32[0] = ((uint32*)addr)[0]; - u.u32[1] = ((uint32*)addr)[1]; - } - else if ((addr1 & (uintptr_t)1) == 0) { - u.u16[0] = ((uint16*)addr)[0]; - u.u16[1] = ((uint16*)addr)[1]; - u.u16[2] = ((uint16*)addr)[2]; - u.u16[3] = ((uint16*)addr)[3]; - } - else { - int32 t; - for (t = 0; t < 8; t++) - u.u8[t] = ((uint8*)addr)[t]; - } - return u.val; -} - -static inline float64 -LOAD_F64(void *addr) -{ - uintptr_t addr1 = (uintptr_t)addr; - union { float64 val; uint32 u32[2]; - uint16 u16[4]; uint8 u8[8]; } u; - if ((addr1 & (uintptr_t)7) == 0) - return *(float64*)addr; - - if ((addr1 & (uintptr_t)3) == 0) { - u.u32[0] = ((uint32*)addr)[0]; - u.u32[1] = ((uint32*)addr)[1]; - } - else if ((addr1 & (uintptr_t)1) == 0) { - u.u16[0] = ((uint16*)addr)[0]; - u.u16[1] = ((uint16*)addr)[1]; - u.u16[2] = ((uint16*)addr)[2]; - u.u16[3] = ((uint16*)addr)[3]; - } - else { - int32 t; - for (t = 0; t < 8; t++) - u.u8[t] = ((uint8*)addr)[t]; - } - return u.val; -} - -static inline int32 -LOAD_I32(void *addr) -{ - uintptr_t addr1 = (uintptr_t)addr; - union { int32 val; uint16 u16[2]; uint8 u8[4]; } u; - if ((addr1 & (uintptr_t)3) == 0) - return *(int32*)addr; - - if ((addr1 & (uintptr_t)1) == 0) { - u.u16[0] = ((uint16*)addr)[0]; - u.u16[1] = ((uint16*)addr)[1]; - } - else { - u.u8[0] = ((uint8*)addr)[0]; - u.u8[1] = ((uint8*)addr)[1]; - u.u8[2] = ((uint8*)addr)[2]; - u.u8[3] = ((uint8*)addr)[3]; - } - return u.val; -} - -static inline int16 -LOAD_I16(void *addr) -{ - union { int16 val; uint8 u8[2]; } u; - u.u8[0] = ((uint8*)addr)[0]; - u.u8[1] = ((uint8*)addr)[1]; - return u.val; -} - -#define LOAD_U32(addr) ((uint32)LOAD_I32(addr)) -#define LOAD_U16(addr) ((uint16)LOAD_I16(addr)) -#define LOAD_F32(addr) ((float32)LOAD_I32(addr)) - -#endif /* WASM_CPU_SUPPORTS_UNALIGNED_64BIT_ACCESS != 0 */ - #define CHECK_MEMORY_OVERFLOW(bytes) do { \ uint64 offset1 = (uint64)offset + (uint64)addr; \ if (offset1 + bytes <= (uint64)linear_mem_size) \ @@ -380,7 +170,50 @@ popcount64(uint64 u) return ret; } -#define read_uint32(p) (p += sizeof(uint32), *(uint32 *)(p - sizeof(uint32))) +#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS != 0 +#define LOAD_U32_WITH_2U16S(addr) (*(uint32*)(addr)) +#define LOAD_PTR(addr) (*(void**)(addr)) +#else /* else of WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS */ +static inline uint32 +LOAD_U32_WITH_2U16S(void *addr) +{ + union { uint32 val; uint16 u16[2]; } u; + + bh_assert(((uintptr_t)addr & 1) == 0); + u.u16[0] = ((uint16*)addr)[0]; + u.u16[1] = ((uint16*)addr)[1]; + return u.val; +} +#if UINTPTR_MAX == UINT32_MAX +#define LOAD_PTR(addr) ((void*)LOAD_U32_WITH_2U16S(addr)) +#elif UINTPTR_MAX == UINT64_MAX +static inline void * +LOAD_PTR(void *addr) +{ + uintptr_t addr1 = (uintptr_t)addr; + union { void *val; uint32 u32[2]; uint16 u16[4]; } u; + + bh_assert(((uintptr_t)addr & 1) == 0); + if ((addr1 & (uintptr_t)7) == 0) + return *(void**)addr; + + if ((addr1 & (uintptr_t)3) == 0) { + u.u32[0] = ((uint32*)addr)[0]; + u.u32[1] = ((uint32*)addr)[1]; + } + else { + u.u16[0] = ((uint16*)addr)[0]; + u.u16[1] = ((uint16*)addr)[1]; + u.u16[2] = ((uint16*)addr)[2]; + u.u16[3] = ((uint16*)addr)[3]; + } + return u.val; +} +#endif /* end of UINTPTR_MAX */ +#endif /* end of WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS */ + +#define read_uint32(p) \ + (p += sizeof(uint32), LOAD_U32_WITH_2U16S(p - sizeof(uint32))) #define GET_LOCAL_INDEX_TYPE_AND_OFFSET() do { \ uint32 param_count = cur_func->param_count; \ @@ -393,36 +226,61 @@ popcount64(uint64 u) local_type = cur_func->local_types[local_idx - param_count]; \ } while (0) -#define GET_OFFSET() (frame_ip += 2, *(int16 *)(frame_ip - 2)) +#define GET_OFFSET() (frame_ip += 2, *(int16*)(frame_ip - 2)) -#define SET_OPERAND(type, off, value) \ - (*(type*)(frame_lp + *(int16*)(frame_ip + off))) = value - -#define GET_OPERAND(type, off) (*(type*)(frame_lp + *(int16*)(frame_ip + off))) - -#define PUSH_I32(value) do { \ - *(int32*)(frame_lp + GET_OFFSET()) = value; \ +#define SET_OPERAND_I32(off, value) do { \ + *(uint32*)(frame_lp + *(int16*)(frame_ip + off)) = value; \ + } while (0) +#define SET_OPERAND_F32(off, value) do { \ + *(float32*)(frame_lp + *(int16*)(frame_ip + off)) = value; \ + } while (0) +#define SET_OPERAND_I64(off, value) do { \ + uint32 *addr_tmp = frame_lp + *(int16*)(frame_ip + off); \ + PUT_I64_TO_ADDR(addr_tmp, value); \ + } while (0) +#define SET_OPERAND_F64(off, value) do { \ + uint32 *addr_tmp = frame_lp + *(int16*)(frame_ip + off); \ + PUT_F64_TO_ADDR(addr_tmp, value); \ } while (0) -#define PUSH_F32(value) do { \ - *(float32*)(frame_lp + GET_OFFSET()) = value; \ +#define SET_OPERAND(op_type, off, value) SET_OPERAND_##op_type(off, value) + +#define GET_OPERAND_I32(type, off) \ + *(type*)(frame_lp + *(int16*)(frame_ip + off)) +#define GET_OPERAND_F32(type, off) \ + *(type*)(frame_lp + *(int16*)(frame_ip + off)) +#define GET_OPERAND_I64(type, off) \ + (type)GET_I64_FROM_ADDR(frame_lp + *(int16*)(frame_ip + off)) +#define GET_OPERAND_F64(type, off) \ + (type)GET_F64_FROM_ADDR(frame_lp + *(int16*)(frame_ip + off)) + +#define GET_OPERAND(type, op_type, off) GET_OPERAND_##op_type(type, off) + +#define PUSH_I32(value) do { \ + *(int32*)(frame_lp + GET_OFFSET()) = value; \ } while (0) -#define PUSH_I64(value) do { \ - *(int64*)(frame_lp + GET_OFFSET()) = value; \ +#define PUSH_F32(value) do { \ + *(float32*)(frame_lp + GET_OFFSET()) = value; \ } while (0) -#define PUSH_F64(value) do { \ - *(float64*)(frame_lp + GET_OFFSET()) = value; \ +#define PUSH_I64(value) do { \ + uint32 *addr_tmp = frame_lp + GET_OFFSET(); \ + PUT_I64_TO_ADDR(addr_tmp, value); \ + } while (0) + +#define PUSH_F64(value) do { \ + uint32 *addr_tmp = frame_lp + GET_OFFSET(); \ + PUT_F64_TO_ADDR(addr_tmp, value); \ } while (0) #define POP_I32() (*(int32*)(frame_lp + GET_OFFSET())) #define POP_F32() (*(float32*)(frame_lp + GET_OFFSET())) -#define POP_I64() (*(int64*)(frame_lp + GET_OFFSET())) +#define POP_I64() (GET_I64_FROM_ADDR(frame_lp + GET_OFFSET())) -#define POP_F64() (*(float64*)(frame_lp + GET_OFFSET())) +#define POP_F64() (GET_F64_FROM_ADDR(frame_lp + GET_OFFSET())) #define SYNC_ALL_TO_FRAME() do { \ frame->ip = frame_ip; \ @@ -432,82 +290,75 @@ popcount64(uint64 u) frame_ip = frame->ip; \ } while (0) +#if WASM_ENABLE_LABELS_AS_VALUES != 0 +#define UPDATE_FRAME_IP_END() (void)0 +#else +#define UPDATE_FRAME_IP_END() \ + frame_ip_end = wasm_get_func_code_end(cur_func) +#endif + #define RECOVER_CONTEXT(new_frame) do { \ frame = (new_frame); \ cur_func = frame->function; \ prev_frame = frame->prev_frame; \ frame_ip = frame->ip; \ + UPDATE_FRAME_IP_END(); \ frame_lp = frame->lp; \ } while (0) -#if WASM_ENABLE_LABELS_AS_VALUES != 0 -#define GET_OPCODE() opcode = *(frame_ip++); +#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS != 0 +#define GET_OPCODE() opcode = *frame_ip++; #else -#define GET_OPCODE() (void)0 +#define GET_OPCODE() opcode = *frame_ip; frame_ip += 2; #endif #define DEF_OP_EQZ(ctype, src_op_type) do { \ - SET_OPERAND(int32, 2, (GET_OPERAND(ctype, 0) == 0)); \ + SET_OPERAND(I32, 2, (GET_OPERAND(ctype, src_op_type, 0) == 0)); \ frame_ip += 4; \ } while (0) #define DEF_OP_CMP(src_type, src_op_type, cond) do { \ - SET_OPERAND(uint32, 4, GET_OPERAND(src_type, 2) cond \ - GET_OPERAND(src_type, 0)); \ + SET_OPERAND(I32, 4, GET_OPERAND(src_type, src_op_type, 2) cond \ + GET_OPERAND(src_type, src_op_type, 0)); \ frame_ip += 6; \ } while (0) #define DEF_OP_BIT_COUNT(src_type, src_op_type, operation) do { \ - SET_OPERAND(src_type, 2, \ - (src_type)operation(GET_OPERAND(src_type, 0))); \ + SET_OPERAND(src_op_type, 2, (src_type)operation( \ + GET_OPERAND(src_type, src_op_type, 0))); \ frame_ip += 4; \ } while (0) -#define DEF_OP_NUMERIC(src_type1, src_type2, src_op_type, operation) do { \ - SET_OPERAND(src_type1, 4, (GET_OPERAND(src_type1, 2) \ - operation GET_OPERAND(src_type2, 0))); \ - frame_ip += 6; \ +#define DEF_OP_NUMERIC(src_type1, src_type2, \ + src_op_type, operation) do { \ + SET_OPERAND(src_op_type, 4, \ + GET_OPERAND(src_type1, src_op_type, 2) operation \ + GET_OPERAND(src_type2, src_op_type, 0)); \ + frame_ip += 6; \ } while (0) -#if defined(BUILD_TARGET_X86_32) -#define DEF_OP_REINTERPRET(src_type) do { \ - void *src = frame_lp + GET_OFFSET(); \ - void *dst = frame_lp + GET_OFFSET(); \ - bh_memcpy_s(dst, sizeof(src_type), src, sizeof(src_type)); \ +#define DEF_OP_REINTERPRET(src_type, src_op_type) do { \ + SET_OPERAND(src_op_type, 2, \ + GET_OPERAND(src_type, src_op_type, 0)); \ + frame_ip += 4; \ } while (0) -#else -#define DEF_OP_REINTERPRET(src_type) do { \ - SET_OPERAND(src_type, 2, GET_OPERAND(src_type, 0)); \ - frame_ip += 4; \ - } while (0) -#endif -#if WASM_CPU_SUPPORTS_UNALIGNED_64BIT_ACCESS != 0 #define DEF_OP_NUMERIC_64 DEF_OP_NUMERIC -#else -#define DEF_OP_NUMERIC_64(src_type1, src_type2, src_op_type, operation) do { \ - src_type1 val1; \ - src_type2 val2; \ - val1 = \ - (src_type1)GET_##src_op_type##_FROM_ADDR(frame_lp + (*(int16*)(frame_ip + 2))); \ - val2 = \ - (src_type2)GET_##src_op_type##_FROM_ADDR(frame_lp + (*(int16*)(frame_ip))); \ - val1 operation##= val2; \ - PUT_##src_op_type##_TO_ADDR(frame_lp + (*(int16*)(frame_ip + 4)), val1); \ - frame_ip += 6; \ - } while (0) -#endif -#define DEF_OP_NUMERIC2(src_type1, src_type2, src_op_type, operation) do { \ - SET_OPERAND(src_type1, 4, (GET_OPERAND(src_type1, 2) \ - operation (GET_OPERAND(src_type2, 0) % 32))); \ - frame_ip += 6; \ +#define DEF_OP_NUMERIC2(src_type1, src_type2, \ + src_op_type, operation) do { \ + SET_OPERAND(src_op_type, 4, \ + GET_OPERAND(src_type1, src_op_type, 2) operation \ + (GET_OPERAND(src_type2, src_op_type, 0) % 32)); \ + frame_ip += 6; \ } while (0) -#define DEF_OP_NUMERIC2_64(src_type1, src_type2, src_op_type, operation) do { \ - SET_OPERAND(src_type1, 4, (GET_OPERAND(src_type1, 2) \ - operation (GET_OPERAND(src_type2, 0) % 64))); \ - frame_ip += 6; \ +#define DEF_OP_NUMERIC2_64(src_type1, src_type2, \ + src_op_type, operation) do { \ + SET_OPERAND(src_op_type, 4, \ + GET_OPERAND(src_type1, src_op_type, 2) operation \ + (GET_OPERAND(src_type2, src_op_type, 0) % 64)); \ + frame_ip += 6; \ } while (0) #define DEF_ATOMIC_RMW_OPCODE(OP_NAME, op) \ @@ -603,8 +454,9 @@ popcount64(uint64 u) } #define DEF_OP_MATH(src_type, src_op_type, method) do { \ - SET_OPERAND(src_type, 2, method(GET_OPERAND(src_type, 0))); \ - frame_ip += 4; \ + SET_OPERAND(src_op_type, 2, \ + method(GET_OPERAND(src_type, src_op_type, 0))); \ + frame_ip += 4; \ } while (0) #define TRUNC_FUNCTION(func_name, src_type, dst_type, signed_type) \ @@ -639,7 +491,7 @@ trunc_f32_to_int(WASMModuleInstance *module, float32 src_min, float32 src_max, bool saturating, bool is_i32, bool is_sign) { - float32 src_value = GET_OPERAND(float32, 0); + float32 src_value = GET_OPERAND(float32, F32, 0); uint64 dst_value_i64; uint32 dst_value_i32; @@ -659,14 +511,14 @@ trunc_f32_to_int(WASMModuleInstance *module, uint32 dst_max = is_sign ? INT32_MAX : UINT32_MAX; dst_value_i32 = trunc_f32_to_i32(src_value, src_min, src_max, dst_min, dst_max, is_sign); - SET_OPERAND(uint32, 2, dst_value_i32); + SET_OPERAND(I32, 2, dst_value_i32); } else { uint64 dst_min = is_sign ? INT64_MIN : 0; uint64 dst_max = is_sign ? INT64_MAX : UINT64_MAX; dst_value_i64 = trunc_f32_to_i64(src_value, src_min, src_max, dst_min, dst_max, is_sign); - SET_OPERAND(uint64, 2, dst_value_i64); + SET_OPERAND(I64, 2, dst_value_i64); } return false; } @@ -677,7 +529,7 @@ trunc_f64_to_int(WASMModuleInstance *module, float64 src_min, float64 src_max, bool saturating, bool is_i32, bool is_sign) { - float64 src_value = GET_OPERAND(float64, 0); + float64 src_value = GET_OPERAND(float64, F64, 0); uint64 dst_value_i64; uint32 dst_value_i32; @@ -697,14 +549,14 @@ trunc_f64_to_int(WASMModuleInstance *module, uint32 dst_max = is_sign ? INT32_MAX : UINT32_MAX; dst_value_i32 = trunc_f64_to_i32(src_value, src_min, src_max, dst_min, dst_max, is_sign); - SET_OPERAND(uint32, 2, dst_value_i32); + SET_OPERAND(I32, 2, dst_value_i32); } else { uint64 dst_min = is_sign ? INT64_MIN : 0; uint64 dst_max = is_sign ? INT64_MAX : UINT64_MAX; dst_value_i64 = trunc_f64_to_i64(src_value, src_min, src_max, dst_min, dst_max, is_sign); - SET_OPERAND(uint64, 2, dst_value_i64); + SET_OPERAND(I64, 2, dst_value_i64); } return false; } @@ -741,14 +593,16 @@ trunc_f64_to_int(WASMModuleInstance *module, PUSH_##dst_op_type(value); \ } while (0) +#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS != 0 +#define CELL_SIZE sizeof(uint8) +#else +#define CELL_SIZE (sizeof(uint8) * 2) +#endif + static bool -copy_stack_values(WASMModuleInstance *module, - uint32 *frame_lp, - uint32 arity, - uint32 total_cell_num, - const uint8 *cells, - const int16 *src_offsets, - const uint16 *dst_offsets) +copy_stack_values(WASMModuleInstance *module, uint32 *frame_lp, + uint32 arity, uint32 total_cell_num, const uint8 *cells, + const int16 *src_offsets, const uint16 *dst_offsets) { /* To avoid the overlap issue between src offsets and dst offset, * we use 2 steps to do the copy. First step, copy the src values @@ -772,24 +626,28 @@ copy_stack_values(WASMModuleInstance *module, /* 1) Copy values from src to tmp buf */ for (i = 0; i < arity; i++) { - cell = cells[i]; + cell = cells[i * CELL_SIZE]; src = src_offsets[i]; if (cell == 1) tmp_buf[buf_index] = frame_lp[src]; - else - *(uint64*)(tmp_buf + buf_index) = *(uint64*)(frame_lp + src); + else { + tmp_buf[buf_index] = frame_lp[src]; + tmp_buf[buf_index + 1] = frame_lp[src + 1]; + } buf_index += cell; } /* 2) Copy values from tmp buf to dest */ buf_index = 0; for (i = 0; i < arity; i++) { - cell = cells[i]; + cell = cells[i * CELL_SIZE]; dst = dst_offsets[i]; if (cell == 1) frame_lp[dst] = tmp_buf[buf_index]; - else - *(uint64*)(frame_lp + dst) = *(uint64*)(tmp_buf + buf_index); + else { + frame_lp[dst] = tmp_buf[buf_index]; + frame_lp[dst + 1] = tmp_buf[buf_index + 1]; + } buf_index += cell; } @@ -797,25 +655,23 @@ copy_stack_values(WASMModuleInstance *module, wasm_runtime_free(tmp_buf); } - return true; + return true; } #define RECOVER_BR_INFO() do { \ uint32 arity; \ /* read arity */ \ - arity = *(uint32*)frame_ip; \ - frame_ip += sizeof(arity); \ + arity = read_uint32(frame_ip); \ if (arity) { \ uint32 total_cell; \ uint16 *dst_offsets = NULL; \ uint8 *cells; \ int16 *src_offsets = NULL; \ /* read total cell num */ \ - total_cell = *(uint32*)frame_ip; \ - frame_ip += sizeof(total_cell); \ + total_cell = read_uint32(frame_ip); \ /* cells */ \ cells = (uint8 *)frame_ip; \ - frame_ip += arity * sizeof(uint8); \ + frame_ip += arity * CELL_SIZE; \ /* src offsets */ \ src_offsets = (int16 *)frame_ip; \ frame_ip += arity * sizeof(int16); \ @@ -827,8 +683,10 @@ copy_stack_values(WASMModuleInstance *module, frame_lp[dst_offsets[0]] = \ frame_lp[src_offsets[0]]; \ else if (cells[0] == 2) { \ - *(int64*)(frame_lp + dst_offsets[0]) = \ - *(int64*)(frame_lp + src_offsets[0]); \ + frame_lp[dst_offsets[0]] = \ + frame_lp[src_offsets[0]]; \ + frame_lp[dst_offsets[0] + 1] = \ + frame_lp[src_offsets[0] + 1]; \ } \ } \ else { \ @@ -839,22 +697,22 @@ copy_stack_values(WASMModuleInstance *module, goto got_exception; \ } \ } \ - frame_ip = *(uint8**)frame_ip; \ + frame_ip = (uint8*)LOAD_PTR(frame_ip); \ } while (0) -#define SKIP_BR_INFO() do { \ - uint32 arity; \ - /* read and skip arity */ \ - arity = *(uint32*)frame_ip; \ - frame_ip += sizeof(arity); \ - if (arity) { \ - /* skip total cell num */ \ - frame_ip += sizeof(uint32); \ - /* skip cells, src offsets and dst offsets */ \ - frame_ip += (sizeof(uint8) + sizeof(int16) + sizeof(uint16)) * arity; \ - } \ - /* skip target address */ \ - frame_ip += sizeof(uint8*); \ +#define SKIP_BR_INFO() do { \ + uint32 arity; \ + /* read and skip arity */ \ + arity = read_uint32(frame_ip); \ + if (arity) { \ + /* skip total cell num */ \ + frame_ip += sizeof(uint32); \ + /* skip cells, src offsets and dst offsets */ \ + frame_ip += (CELL_SIZE + sizeof(int16) \ + + sizeof(uint16)) * arity; \ + } \ + /* skip target address */ \ + frame_ip += sizeof(uint8*); \ } while (0) static inline int32 @@ -1088,7 +946,6 @@ wasm_interp_dump_op_count() } #endif - #if WASM_ENABLE_LABELS_AS_VALUES != 0 /* #define HANDLE_OP(opcode) HANDLE_##opcode:printf(#opcode"\n");h_##opcode */ @@ -1097,7 +954,7 @@ wasm_interp_dump_op_count() #else #define HANDLE_OP(opcode) HANDLE_##opcode #endif -#if WASM_ENABLE_ABS_LABEL_ADDR != 0 +#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS != 0 #define FETCH_OPCODE_AND_DISPATCH() do { \ const void *p_label_addr = *(void**)frame_ip; \ frame_ip += sizeof(void*); \ @@ -1110,7 +967,7 @@ wasm_interp_dump_op_count() frame_ip += sizeof(int16); \ goto *p_label_addr; \ } while (0) -#endif +#endif /* end of WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS */ #define HANDLE_OP_END() FETCH_OPCODE_AND_DISPATCH() #else /* else of WASM_ENABLE_LABELS_AS_VALUES */ @@ -1120,7 +977,9 @@ wasm_interp_dump_op_count() #endif /* end of WASM_ENABLE_LABELS_AS_VALUES */ +#if WASM_ENABLE_LABELS_AS_VALUES != 0 static void **global_handle_table; +#endif static void wasm_interp_call_func_bytecode(WASMModuleInstance *module, @@ -1139,10 +998,13 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, /* Points to this special opcode so as to jump to the call_method_from_entry. */ register uint8 *frame_ip = &opcode_IMPDEP; /* cache of frame->ip */ register uint32 *frame_lp = NULL; /* cache of frame->lp */ -#if WASM_ENABLE_ABS_LABEL_ADDR == 0 - register uint8 *label_base = &&HANDLE_WASM_OP_UNREACHABLE; /* cache of label base addr */ +#if WASM_ENABLE_LABELS_AS_VALUES != 0 +#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 + /* cache of label base addr */ + register uint8 *label_base = &&HANDLE_WASM_OP_UNREACHABLE; #endif - uint8 *frame_ip_end; +#endif + uint8 *frame_ip_end = frame_ip + 1; uint32 cond, count, fidx, tidx, frame_size = 0; uint64 all_cell_num = 0; int16 addr1, addr2, addr_ret = 0; @@ -1164,6 +1026,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, #if WASM_ENABLE_LABELS_AS_VALUES == 0 while (frame_ip < frame_ip_end) { opcode = *frame_ip++; +#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 + frame_ip++; +#endif switch (opcode) { #else goto *handle_table[WASM_OP_IMPDEP]; @@ -1177,11 +1042,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, cond = (uint32)POP_I32(); if (cond == 0) { - if (*(uint8**)frame_ip == NULL) { - frame_ip = *(uint8**)(frame_ip + sizeof(uint8*)); + uint8 *else_addr = (uint8*)LOAD_PTR(frame_ip); + if (else_addr == NULL) { + frame_ip = (uint8*)LOAD_PTR(frame_ip + sizeof(uint8*)); } else { - frame_ip = *(uint8**)(frame_ip); + frame_ip = else_addr; } } else { @@ -1190,7 +1056,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP_END (); HANDLE_OP (WASM_OP_ELSE): - frame_ip = *(uint8**)(frame_ip); + frame_ip = (uint8*)LOAD_PTR(frame_ip); HANDLE_OP_END (); HANDLE_OP (WASM_OP_BR): @@ -1222,7 +1088,7 @@ recover_br_info: CHECK_SUSPEND_FLAGS(); #endif count = read_uint32(frame_ip); - didx = GET_OPERAND(uint32, 0); + didx = GET_OPERAND(uint32, I32, 0); frame_ip += 2; if (!(didx >= 0 && (uint32)didx < count)) @@ -1230,13 +1096,13 @@ recover_br_info: /* all br items must have the same arity and item size, so we only calculate the first item size */ - arity = *(uint32*)frame_ip; + arity = LOAD_U32_WITH_2U16S(frame_ip); br_item_size = sizeof(uint32); /* arity */ if (arity) { /* total cell num */ br_item_size += sizeof(uint32); /* cells, src offsets and dst offsets */ - br_item_size += (sizeof(uint8) + sizeof(int16) + sizeof(uint16)) + br_item_size += (CELL_SIZE + sizeof(int16) + sizeof(uint16)) * arity; } /* target address */ @@ -1266,12 +1132,12 @@ recover_br_info: ret_idx++, off -= sizeof(int16)) { if (ret_types[ret_idx] == VALUE_TYPE_I64 || ret_types[ret_idx] == VALUE_TYPE_F64) { - *((uint64 *)(prev_frame->lp + ret_offset)) = - GET_OPERAND(uint64, off); + PUT_I64_TO_ADDR(prev_frame->lp + ret_offset, + GET_OPERAND(uint64, I64, off)); ret_offset += 2; } else { - prev_frame->lp[ret_offset] = GET_OPERAND(int32, off); + prev_frame->lp[ret_offset] = GET_OPERAND(uint32, I32, off); ret_offset++; } } @@ -1294,7 +1160,7 @@ recover_br_info: #endif tidx = read_uint32(frame_ip); - val = GET_OPERAND(int32, 0); + val = GET_OPERAND(uint32, I32, 0); frame_ip += 2; if (tidx >= module->module->type_count) { @@ -1356,22 +1222,12 @@ recover_br_info: addr_ret = GET_OFFSET(); if (!cond) { -#if defined(BUILD_TARGET_X86_32) if (addr_ret != addr1) - bh_memcpy_s(frame_lp + addr_ret, sizeof(int32), - frame_lp + addr1, sizeof(int32)); -#else - frame_lp[addr_ret] = frame_lp[addr1]; -#endif + frame_lp[addr_ret] = frame_lp[addr1]; } else { -#if defined(BUILD_TARGET_X86_32) if (addr_ret != addr2) - bh_memcpy_s(frame_lp + addr_ret, sizeof(int32), - frame_lp + addr2, sizeof(int32)); -#else - frame_lp[addr_ret] = frame_lp[addr2]; -#endif + frame_lp[addr_ret] = frame_lp[addr2]; } HANDLE_OP_END (); } @@ -1384,22 +1240,14 @@ recover_br_info: addr_ret = GET_OFFSET(); if (!cond) { -#if defined(BUILD_TARGET_X86_32) if (addr_ret != addr1) - bh_memcpy_s(frame_lp + addr_ret, sizeof(int64), - frame_lp + addr1, sizeof(int64)); -#else - *(int64*)(frame_lp + addr_ret) = *(int64*)(frame_lp + addr1); -#endif + PUT_I64_TO_ADDR(frame_lp + addr_ret, + GET_I64_FROM_ADDR(frame_lp + addr1)); } else { -#if defined(BUILD_TARGET_X86_32) if (addr_ret != addr2) - bh_memcpy_s(frame_lp + addr_ret, sizeof(int64), - frame_lp + addr2, sizeof(int64)); -#else - *(int64*)(frame_lp + addr_ret) = *(int64*)(frame_lp + addr2); -#endif + PUT_I64_TO_ADDR(frame_lp + addr_ret, + GET_I64_FROM_ADDR(frame_lp + addr2)); } HANDLE_OP_END (); } @@ -1408,8 +1256,13 @@ recover_br_info: HANDLE_OP (EXT_OP_SET_LOCAL_FAST): HANDLE_OP (EXT_OP_TEE_LOCAL_FAST): { +#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS != 0 local_offset = *frame_ip++; - *(int32*)(frame_lp + local_offset) = GET_OPERAND(uint32, 0); +#else + local_offset = *frame_ip; + frame_ip += 2; +#endif + *(uint32*)(frame_lp + local_offset) = GET_OPERAND(uint32, I32, 0); frame_ip += 2; HANDLE_OP_END (); } @@ -1417,8 +1270,14 @@ recover_br_info: HANDLE_OP (EXT_OP_SET_LOCAL_FAST_I64): HANDLE_OP (EXT_OP_TEE_LOCAL_FAST_I64): { +#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS != 0 local_offset = *frame_ip++; - PUT_I64_TO_ADDR((uint32*)(frame_lp + local_offset), GET_OPERAND(uint64, 0)); +#else + local_offset = *frame_ip; + frame_ip += 2; +#endif + PUT_I64_TO_ADDR((uint32*)(frame_lp + local_offset), + GET_OPERAND(uint64, I64, 0)); frame_ip += 2; HANDLE_OP_END (); } @@ -1455,7 +1314,8 @@ recover_br_info: : global_data + global->data_offset; #endif addr_ret = GET_OFFSET(); - *(uint64 *)(frame_lp + addr_ret) = GET_I64_FROM_ADDR((uint32*)global_addr); + PUT_I64_TO_ADDR(frame_lp + addr_ret, + GET_I64_FROM_ADDR((uint32*)global_addr)); HANDLE_OP_END (); } @@ -1519,7 +1379,8 @@ recover_br_info: : global_data + global->data_offset; #endif addr1 = GET_OFFSET(); - PUT_I64_TO_ADDR((uint32*)global_addr, *(int64 *)(frame_lp + addr1)); + PUT_I64_TO_ADDR((uint32*)global_addr, + GET_I64_FROM_ADDR(frame_lp + addr1)); HANDLE_OP_END (); } @@ -1528,7 +1389,7 @@ recover_br_info: { uint32 offset, addr; offset = read_uint32(frame_ip); - addr = GET_OPERAND(uint32, 0); + addr = GET_OPERAND(uint32, I32, 0); frame_ip += 2; addr_ret = GET_OFFSET(); CHECK_MEMORY_OVERFLOW(4); @@ -1540,7 +1401,7 @@ recover_br_info: { uint32 offset, addr; offset = read_uint32(frame_ip); - addr = GET_OPERAND(uint32, 0); + addr = GET_OPERAND(uint32, I32, 0); frame_ip += 2; addr_ret = GET_OFFSET(); CHECK_MEMORY_OVERFLOW(8); @@ -1552,7 +1413,7 @@ recover_br_info: { uint32 offset, addr; offset = read_uint32(frame_ip); - addr = GET_OPERAND(uint32, 0); + addr = GET_OPERAND(uint32, I32, 0); frame_ip += 2; addr_ret = GET_OFFSET(); CHECK_MEMORY_OVERFLOW(1); @@ -1564,7 +1425,7 @@ recover_br_info: { uint32 offset, addr; offset = read_uint32(frame_ip); - addr = GET_OPERAND(uint32, 0); + addr = GET_OPERAND(uint32, I32, 0); frame_ip += 2; addr_ret = GET_OFFSET(); CHECK_MEMORY_OVERFLOW(1); @@ -1576,7 +1437,7 @@ recover_br_info: { uint32 offset, addr; offset = read_uint32(frame_ip); - addr = GET_OPERAND(uint32, 0); + addr = GET_OPERAND(uint32, I32, 0); frame_ip += 2; addr_ret = GET_OFFSET(); CHECK_MEMORY_OVERFLOW(2); @@ -1588,7 +1449,7 @@ recover_br_info: { uint32 offset, addr; offset = read_uint32(frame_ip); - addr = GET_OPERAND(uint32, 0); + addr = GET_OPERAND(uint32, I32, 0); frame_ip += 2; addr_ret = GET_OFFSET(); CHECK_MEMORY_OVERFLOW(2); @@ -1600,11 +1461,11 @@ recover_br_info: { uint32 offset, addr; offset = read_uint32(frame_ip); - addr = GET_OPERAND(uint32, 0); + addr = GET_OPERAND(uint32, I32, 0); frame_ip += 2; addr_ret = GET_OFFSET(); CHECK_MEMORY_OVERFLOW(1); - *(int64 *)(frame_lp + addr_ret) = sign_ext_8_64(*(int8*)maddr); + PUT_I64_TO_ADDR(frame_lp + addr_ret, sign_ext_8_64(*(int8*)maddr)); HANDLE_OP_END (); } @@ -1612,11 +1473,11 @@ recover_br_info: { uint32 offset, addr; offset = read_uint32(frame_ip); - addr = GET_OPERAND(uint32, 0); + addr = GET_OPERAND(uint32, I32, 0); frame_ip += 2; addr_ret = GET_OFFSET(); CHECK_MEMORY_OVERFLOW(1); - *(int64 *)(frame_lp + addr_ret) = (uint64)(*(uint8*)maddr); + PUT_I64_TO_ADDR(frame_lp + addr_ret, (uint64)(*(uint8*)maddr)); HANDLE_OP_END (); } @@ -1624,11 +1485,11 @@ recover_br_info: { uint32 offset, addr; offset = read_uint32(frame_ip); - addr = GET_OPERAND(uint32, 0); + addr = GET_OPERAND(uint32, I32, 0); frame_ip += 2; addr_ret = GET_OFFSET(); CHECK_MEMORY_OVERFLOW(2); - *(int64 *)(frame_lp + addr_ret) = sign_ext_16_64(LOAD_I16(maddr)); + PUT_I64_TO_ADDR(frame_lp + addr_ret, sign_ext_16_64(LOAD_I16(maddr))); HANDLE_OP_END (); } @@ -1636,11 +1497,11 @@ recover_br_info: { uint32 offset, addr; offset = read_uint32(frame_ip); - addr = GET_OPERAND(uint32, 0); + addr = GET_OPERAND(uint32, I32, 0); frame_ip += 2; addr_ret = GET_OFFSET(); CHECK_MEMORY_OVERFLOW(2); - *(int64 *)(frame_lp + addr_ret) = (uint64)(LOAD_U16(maddr)); + PUT_I64_TO_ADDR(frame_lp + addr_ret, (uint64)(LOAD_U16(maddr))); HANDLE_OP_END (); } @@ -1648,11 +1509,11 @@ recover_br_info: { uint32 offset, addr; offset = read_uint32(frame_ip); - addr = GET_OPERAND(uint32, 0); + addr = GET_OPERAND(uint32, I32, 0); frame_ip += 2; addr_ret = GET_OFFSET(); CHECK_MEMORY_OVERFLOW(4); - *(int64 *)(frame_lp + addr_ret) = sign_ext_32_64(LOAD_I32(maddr)); + PUT_I64_TO_ADDR(frame_lp + addr_ret, sign_ext_32_64(LOAD_I32(maddr))); HANDLE_OP_END (); } @@ -1660,11 +1521,11 @@ recover_br_info: { uint32 offset, addr; offset = read_uint32(frame_ip); - addr = GET_OPERAND(uint32, 0); + addr = GET_OPERAND(uint32, I32, 0); frame_ip += 2; addr_ret = GET_OFFSET(); CHECK_MEMORY_OVERFLOW(4); - *(int64 *)(frame_lp + addr_ret) = (uint64)(LOAD_U32(maddr)); + PUT_I64_TO_ADDR(frame_lp + addr_ret, (uint64)(LOAD_U32(maddr))); HANDLE_OP_END (); } @@ -1673,8 +1534,8 @@ recover_br_info: uint32 offset, addr; uint32 sval; offset = read_uint32(frame_ip); - sval = GET_OPERAND(uint32, 0); - addr = GET_OPERAND(uint32, 2); + sval = GET_OPERAND(uint32, I32, 0); + addr = GET_OPERAND(uint32, I32, 2); frame_ip += 4; CHECK_MEMORY_OVERFLOW(4); STORE_U32(maddr, sval); @@ -1686,8 +1547,8 @@ recover_br_info: uint32 offset, addr; uint32 sval; offset = read_uint32(frame_ip); - sval = GET_OPERAND(uint32, 0); - addr = GET_OPERAND(uint32, 2); + sval = GET_OPERAND(uint32, I32, 0); + addr = GET_OPERAND(uint32, I32, 2); frame_ip += 4; CHECK_MEMORY_OVERFLOW(1); *(uint8*)maddr = (uint8)sval; @@ -1699,8 +1560,8 @@ recover_br_info: uint32 offset, addr; uint32 sval; offset = read_uint32(frame_ip); - sval = GET_OPERAND(uint32, 0); - addr = GET_OPERAND(uint32, 2); + sval = GET_OPERAND(uint32, I32, 0); + addr = GET_OPERAND(uint32, I32, 2); frame_ip += 4; CHECK_MEMORY_OVERFLOW(2); STORE_U16(maddr, (uint16)sval); @@ -1712,8 +1573,8 @@ recover_br_info: uint32 offset, addr; uint64 sval; offset = read_uint32(frame_ip); - sval = GET_OPERAND(uint64, 0); - addr = GET_OPERAND(uint32, 2); + sval = GET_OPERAND(uint64, I64, 0); + addr = GET_OPERAND(uint32, I32, 2); frame_ip += 4; CHECK_MEMORY_OVERFLOW(8); STORE_I64(maddr, sval); @@ -1725,8 +1586,8 @@ recover_br_info: uint32 offset, addr; uint64 sval; offset = read_uint32(frame_ip); - sval = GET_OPERAND(uint64, 0); - addr = GET_OPERAND(uint32, 2); + sval = GET_OPERAND(uint64, I64, 0); + addr = GET_OPERAND(uint32, I32, 2); frame_ip += 4; CHECK_MEMORY_OVERFLOW(1); *(uint8*)maddr = (uint8)sval; @@ -1738,8 +1599,8 @@ recover_br_info: uint32 offset, addr; uint64 sval; offset = read_uint32(frame_ip); - sval = GET_OPERAND(uint64, 0); - addr = GET_OPERAND(uint32, 2); + sval = GET_OPERAND(uint64, I64, 0); + addr = GET_OPERAND(uint32, I32, 2); frame_ip += 4; CHECK_MEMORY_OVERFLOW(2); STORE_U16(maddr, (uint16)sval); @@ -1751,8 +1612,8 @@ recover_br_info: uint32 offset, addr; uint64 sval; offset = read_uint32(frame_ip); - sval = GET_OPERAND(uint64, 0); - addr = GET_OPERAND(uint32, 2); + sval = GET_OPERAND(uint64, I64, 0); + addr = GET_OPERAND(uint32, I32, 2); frame_ip += 4; CHECK_MEMORY_OVERFLOW(4); STORE_U32(maddr, (uint32)sval); @@ -2126,8 +1987,8 @@ recover_br_info: { int64 a, b; - b = *(int64*)(frame_lp + GET_OFFSET()); - a = *(int64*)(frame_lp + GET_OFFSET()); + b = GET_I64_FROM_ADDR(frame_lp + GET_OFFSET()); + a = GET_I64_FROM_ADDR(frame_lp + GET_OFFSET()); if (a == (int64)0x8000000000000000LL && b == -1) { wasm_set_exception(module, "integer overflow"); goto got_exception; @@ -2136,7 +1997,7 @@ recover_br_info: wasm_set_exception(module, "integer divide by zero"); goto got_exception; } - *(int64*)(frame_lp + GET_OFFSET()) = (a / b); + PUT_I64_TO_ADDR(frame_lp + GET_OFFSET(), a / b); HANDLE_OP_END (); } @@ -2144,13 +2005,13 @@ recover_br_info: { uint64 a, b; - b = *(uint64*)(frame_lp + GET_OFFSET()); - a = *(uint64*)(frame_lp + GET_OFFSET()); + b = GET_I64_FROM_ADDR(frame_lp + GET_OFFSET()); + a = GET_I64_FROM_ADDR(frame_lp + GET_OFFSET()); if (b == 0) { wasm_set_exception(module, "integer divide by zero"); goto got_exception; } - *(uint64*)(frame_lp + GET_OFFSET()) = (a / b); + PUT_I64_TO_ADDR(frame_lp + GET_OFFSET(), a / b); HANDLE_OP_END (); } @@ -2158,8 +2019,8 @@ recover_br_info: { int64 a, b; - b = *(int64*)(frame_lp + GET_OFFSET()); - a = *(int64*)(frame_lp + GET_OFFSET()); + b = GET_I64_FROM_ADDR(frame_lp + GET_OFFSET()); + a = GET_I64_FROM_ADDR(frame_lp + GET_OFFSET()); if (a == (int64)0x8000000000000000LL && b == -1) { *(int64*)(frame_lp + GET_OFFSET()) = 0; HANDLE_OP_END (); @@ -2168,7 +2029,7 @@ recover_br_info: wasm_set_exception(module, "integer divide by zero"); goto got_exception; } - *(int64*)(frame_lp + GET_OFFSET()) = (a % b); + PUT_I64_TO_ADDR(frame_lp + GET_OFFSET(), a % b); HANDLE_OP_END (); } @@ -2176,13 +2037,13 @@ recover_br_info: { uint64 a, b; - b = *(uint64*)(frame_lp + GET_OFFSET()); - a = *(uint64*)(frame_lp + GET_OFFSET()); + b = GET_I64_FROM_ADDR(frame_lp + GET_OFFSET()); + a = GET_I64_FROM_ADDR(frame_lp + GET_OFFSET()); if (b == 0) { wasm_set_exception(module, "integer divide by zero"); goto got_exception; } - *(uint64*)(frame_lp + GET_OFFSET()) = (a % b); + PUT_I64_TO_ADDR(frame_lp + GET_OFFSET(), a % b); HANDLE_OP_END (); } @@ -2232,9 +2093,9 @@ recover_br_info: { uint64 a, b; - b = *(int64*)(frame_lp + GET_OFFSET()); - a = *(int64*)(frame_lp + GET_OFFSET()); - *(int64*)(frame_lp + GET_OFFSET()) = rotl64(a, b); + b = GET_I64_FROM_ADDR(frame_lp + GET_OFFSET()); + a = GET_I64_FROM_ADDR(frame_lp + GET_OFFSET()); + PUT_I64_TO_ADDR(frame_lp + GET_OFFSET(), rotl64(a, b)); HANDLE_OP_END (); } @@ -2242,9 +2103,9 @@ recover_br_info: { uint64 a, b; - b = *(uint64*)(frame_lp + GET_OFFSET()); - a = *(uint64*)(frame_lp + GET_OFFSET()); - *(uint64*)(frame_lp + GET_OFFSET()) = rotr64(a, b); + b = GET_I64_FROM_ADDR(frame_lp + GET_OFFSET()); + a = GET_I64_FROM_ADDR(frame_lp + GET_OFFSET()); + PUT_I64_TO_ADDR(frame_lp + GET_OFFSET(), rotr64(a, b)); HANDLE_OP_END (); } @@ -2350,12 +2211,14 @@ recover_br_info: HANDLE_OP (WASM_OP_F64_NEG): { - int64 i64 = *(int64*)(frame_lp + GET_OFFSET()); + int64 i64 = GET_I64_FROM_ADDR(frame_lp + GET_OFFSET()); int64 sign_bit = i64 & (((int64)1) << 63); if (sign_bit) - *(int64*)(frame_lp + GET_OFFSET()) = (uint64)i64 & ~(((uint64)1) << 63); + PUT_I64_TO_ADDR(frame_lp + GET_OFFSET(), + ((uint64)i64 & ~(((uint64)1) << 63))); else - *(int64*)(frame_lp + GET_OFFSET()) = (uint64)i64 | (((uint64)1) << 63); + PUT_I64_TO_ADDR(frame_lp + GET_OFFSET(), + ((uint64)i64 | (((uint64)1) << 63))); HANDLE_OP_END (); } @@ -2539,16 +2402,12 @@ recover_br_info: /* reinterpretations */ HANDLE_OP (WASM_OP_I32_REINTERPRET_F32): - DEF_OP_REINTERPRET(float32); + HANDLE_OP (WASM_OP_F32_REINTERPRET_I32): + DEF_OP_REINTERPRET(uint32, I32); HANDLE_OP_END (); HANDLE_OP (WASM_OP_I64_REINTERPRET_F64): - DEF_OP_REINTERPRET(float64); - HANDLE_OP_END (); - HANDLE_OP (WASM_OP_F32_REINTERPRET_I32): - DEF_OP_REINTERPRET(int32); - HANDLE_OP_END (); HANDLE_OP (WASM_OP_F64_REINTERPRET_I64): - DEF_OP_REINTERPRET(int64); + DEF_OP_REINTERPRET(int64, I64); HANDLE_OP_END (); HANDLE_OP (EXT_OP_COPY_STACK_TOP): @@ -2560,7 +2419,8 @@ recover_br_info: HANDLE_OP (EXT_OP_COPY_STACK_TOP_I64): addr1 = GET_OFFSET(); addr2 = GET_OFFSET(); - *(uint64*)(frame_lp + addr2) = *(uint64*)(frame_lp + addr1); + frame_lp[addr2] = frame_lp[addr1]; + frame_lp[addr2 + 1] = frame_lp[addr1 + 1]; HANDLE_OP_END (); HANDLE_OP (EXT_OP_COPY_STACK_VALUES): @@ -2571,14 +2431,12 @@ recover_br_info: uint16 *dst_offsets = NULL; /* read values_count */ - values_count = *(uint32*)frame_ip; - frame_ip += sizeof(values_count); + values_count = read_uint32(frame_ip); /* read total cell num */ - total_cell = *(uint32*)frame_ip; - frame_ip += sizeof(total_cell); + total_cell = read_uint32(frame_ip); /* cells */ cells = (uint8 *)frame_ip; - frame_ip += values_count * sizeof(uint8); + frame_ip += values_count * CELL_SIZE; /* src offsets */ src_offsets = (int16 *)frame_ip; frame_ip += values_count * sizeof(int16); @@ -2586,10 +2444,9 @@ recover_br_info: dst_offsets = (uint16*)frame_ip; frame_ip += values_count * sizeof(uint16); - if (!copy_stack_values(module, frame_lp, - values_count, total_cell, - cells, src_offsets, - dst_offsets)) + if (!copy_stack_values(module, frame_lp, values_count, + total_cell, cells, + src_offsets, dst_offsets)) goto got_exception; HANDLE_OP_END (); @@ -2694,8 +2551,7 @@ recover_br_info: if (offset + bytes > seg_len) goto out_of_bounds; - bh_memcpy_s(maddr, linear_mem_size - addr, - data + offset, bytes); + bh_memcpy_s(maddr, linear_mem_size - addr, data + offset, bytes); break; } case WASM_OP_DATA_DROP: @@ -2721,8 +2577,7 @@ recover_br_info: CHECK_BULK_MEMORY_OVERFLOW(dst, len, mdst); /* allowing the destination and source to overlap */ - bh_memmove_s(mdst, linear_mem_size - dst, - msrc, len); + bh_memmove_s(mdst, linear_mem_size - dst, msrc, len); break; } @@ -3178,25 +3033,25 @@ recover_br_info: uint32 *lp; int i; - if (!(lp_base = lp = wasm_runtime_malloc(cur_func->param_cell_num * sizeof(uint32)))) { + if (!(lp_base = lp = + wasm_runtime_malloc(cur_func->param_cell_num * sizeof(uint32)))) { wasm_set_exception(module, "allocate memory failed"); goto got_exception; } for (i = 0; i < cur_func->param_count; i++) { if (cur_func->param_types[i] == VALUE_TYPE_I64 || cur_func->param_types[i] == VALUE_TYPE_F64) { - *(int64*)(lp) = - GET_OPERAND(int64, (2 * (cur_func->param_count - i - 1))); + PUT_I64_TO_ADDR(lp, GET_OPERAND(uint64, I64, + 2 * (cur_func->param_count - i - 1))); lp += 2; } else { - *(lp) = GET_OPERAND(int32, (2 * (cur_func->param_count - i - 1))); + *lp = GET_OPERAND(uint32, I32, (2 * (cur_func->param_count - i - 1))); lp ++; } } frame->lp = frame->operand + cur_func->const_cell_num; - bh_memcpy_s(frame->lp, (lp - lp_base) * sizeof(uint32), - lp_base, (lp - lp_base) * sizeof(uint32)); + word_copy(frame->lp, lp_base, lp - lp_base); wasm_runtime_free(lp_base); FREE_FRAME(exec_env, frame); frame_ip += cur_func->param_count * sizeof(int16); @@ -3213,11 +3068,14 @@ recover_br_info: for (int i = 0; i < cur_func->param_count; i++) { if (cur_func->param_types[i] == VALUE_TYPE_I64 || cur_func->param_types[i] == VALUE_TYPE_F64) { - *(int64*)(outs_area->lp) = - GET_OPERAND(int64, (2 * (cur_func->param_count - i - 1))); + PUT_I64_TO_ADDR(outs_area->lp, + GET_OPERAND(uint64, I64, + 2 * (cur_func->param_count - i - 1))); outs_area->lp += 2; - } else { - *(outs_area->lp) = GET_OPERAND(int32, (2 * (cur_func->param_count - i - 1))); + } + else { + *outs_area->lp = GET_OPERAND(uint32, I32, + (2 * (cur_func->param_count - i - 1))); outs_area->lp ++; } } @@ -3290,8 +3148,8 @@ recover_br_info: frame_lp = frame->lp = frame->operand + cur_wasm_func->const_cell_num; /* Initialize the consts */ - bh_memcpy_s(frame->operand, all_cell_num * 4, - cur_wasm_func->consts, cur_wasm_func->const_cell_num * 4); + word_copy(frame->operand, (uint32*)cur_wasm_func->consts, + cur_wasm_func->const_cell_num); /* Initialize the local varialbes */ memset(frame_lp + cur_func->param_cell_num, 0, @@ -3336,6 +3194,7 @@ recover_br_info: #endif } +#if WASM_ENABLE_LABELS_AS_VALUES != 0 void ** wasm_interp_get_handle_table() { @@ -3344,6 +3203,7 @@ wasm_interp_get_handle_table() wasm_interp_call_func_bytecode(&module, NULL, NULL, NULL); return global_handle_table; } +#endif void wasm_interp_call_wasm(WASMModuleInstance *module_inst, diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index 3da1c056f..e346eabe1 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -2533,7 +2533,7 @@ static bool wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, char *error_buf, uint32 error_buf_size); -#if WASM_ENABLE_FAST_INTERP != 0 +#if WASM_ENABLE_FAST_INTERP != 0 && WASM_ENABLE_LABELS_AS_VALUES != 0 void ** wasm_interp_get_handle_table(); @@ -2836,7 +2836,7 @@ load_from_sections(WASMModule *module, WASMSection *sections, } } -#if WASM_ENABLE_FAST_INTERP != 0 +#if WASM_ENABLE_FAST_INTERP != 0 && WASM_ENABLE_LABELS_AS_VALUES != 0 handle_table = wasm_interp_get_handle_table(); #endif @@ -3859,7 +3859,7 @@ static bool check_offset_push(WASMLoaderContext *ctx, char *error_buf, uint32 error_buf_size) { - uint32 cell_num = (ctx->frame_offset - ctx->frame_offset_bottom); + uint32 cell_num = (uint32)(ctx->frame_offset - ctx->frame_offset_bottom); if (ctx->frame_offset >= ctx->frame_offset_boundary) { MEM_REALLOC(ctx->frame_offset_bottom, ctx->frame_offset_size, ctx->frame_offset_size + 16); @@ -4209,22 +4209,20 @@ fail: #if WASM_ENABLE_FAST_INTERP != 0 -#if WASM_ENABLE_ABS_LABEL_ADDR != 0 - +#if WASM_ENABLE_LABELS_AS_VALUES != 0 +#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS != 0 #define emit_label(opcode) do { \ wasm_loader_emit_ptr(loader_ctx, handle_table[opcode]); \ LOG_OP("\nemit_op [%02x]\t", opcode); \ } while (0) - #define skip_label() do { \ wasm_loader_emit_backspace(loader_ctx, sizeof(void *)); \ LOG_OP("\ndelete last op\n"); \ } while (0) - -#else - +#else /* else of WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS */ #define emit_label(opcode) do { \ - int32 offset = (int32)(handle_table[opcode] - handle_table[0]); \ + int32 offset = (int32)((uint8*)handle_table[opcode] \ + - (uint8*)handle_table[0]); \ if (!(offset >= INT16_MIN && offset < INT16_MAX)) { \ set_error_buf(error_buf, error_buf_size, \ "pre-compiled label offset out of range"); \ @@ -4233,14 +4231,21 @@ fail: wasm_loader_emit_int16(loader_ctx, offset); \ LOG_OP("\nemit_op [%02x]\t", opcode); \ } while (0) - -/* drop local.get / const / block / loop / end */ #define skip_label() do { \ wasm_loader_emit_backspace(loader_ctx, sizeof(int16)); \ LOG_OP("\ndelete last op\n"); \ } while (0) - -#endif /* WASM_ENABLE_ABS_LABEL_ADDR */ +#endif /* end of WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS */ +#else /* else of WASM_ENABLE_LABELS_AS_VALUES */ +#define emit_label(opcode) do { \ + wasm_loader_emit_uint8(loader_ctx, opcode); \ + LOG_OP("\nemit_op [%02x]\t", opcode); \ + } while (0) +#define skip_label() do { \ + wasm_loader_emit_backspace(loader_ctx, sizeof(uint8)); \ + LOG_OP("\ndelete last op\n"); \ + } while (0) +#endif /* end of WASM_ENABLE_LABELS_AS_VALUES */ #define emit_empty_label_addr_and_frame_ip(type) do { \ if (!add_label_patch_to_list(loader_ctx->frame_csp - 1, type, \ @@ -4361,22 +4366,36 @@ static void wasm_loader_emit_uint32(WASMLoaderContext *ctx, uint32 value) { if (ctx->p_code_compiled) { - *(uint32*)(ctx->p_code_compiled) = value; +#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 + bh_assert(((uintptr_t)ctx->p_code_compiled & 1) == 0); +#endif + STORE_U32(ctx->p_code_compiled, value); ctx->p_code_compiled += sizeof(uint32); } - else + else { +#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 + bh_assert((ctx->code_compiled_size & 1) == 0); +#endif ctx->code_compiled_size += sizeof(uint32); + } } static void wasm_loader_emit_int16(WASMLoaderContext *ctx, int16 value) { if (ctx->p_code_compiled) { - *(int16*)(ctx->p_code_compiled) = value; +#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 + bh_assert(((uintptr_t)ctx->p_code_compiled & 1) == 0); +#endif + STORE_U16(ctx->p_code_compiled, (uint16)value); ctx->p_code_compiled += sizeof(int16); } - else + else { +#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 + bh_assert((ctx->code_compiled_size & 1) == 0); +#endif ctx->code_compiled_size += sizeof(int16); + } } static void @@ -4385,20 +4404,36 @@ wasm_loader_emit_uint8(WASMLoaderContext *ctx, uint8 value) if (ctx->p_code_compiled) { *(ctx->p_code_compiled) = value; ctx->p_code_compiled += sizeof(uint8); +#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 + ctx->p_code_compiled++; + bh_assert(((uintptr_t)ctx->p_code_compiled & 1) == 0); +#endif } - else + else { ctx->code_compiled_size += sizeof(uint8); +#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 + ctx->code_compiled_size++; + bh_assert((ctx->code_compiled_size & 1) == 0); +#endif + } } static void wasm_loader_emit_ptr(WASMLoaderContext *ctx, void *value) { if (ctx->p_code_compiled) { - *(uint8**)(ctx->p_code_compiled) = value; +#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 + bh_assert(((uintptr_t)ctx->p_code_compiled & 1) == 0); +#endif + STORE_PTR(ctx->p_code_compiled, value); ctx->p_code_compiled += sizeof(void *); } - else + else { +#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 + bh_assert((ctx->code_compiled_size & 1) == 0); +#endif ctx->code_compiled_size += sizeof(void *); + } } static void @@ -4406,9 +4441,22 @@ wasm_loader_emit_backspace(WASMLoaderContext *ctx, uint32 size) { if (ctx->p_code_compiled) { ctx->p_code_compiled -= size; +#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 + if (size == sizeof(uint8)) { + ctx->p_code_compiled--; + bh_assert(((uintptr_t)ctx->p_code_compiled & 1) == 0); + } +#endif } - else + else { ctx->code_compiled_size -= size; +#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 + if (size == sizeof(uint8)) { + ctx->code_compiled_size--; + bh_assert((ctx->code_compiled_size & 1) == 0); + } +#endif + } } static bool @@ -4458,11 +4506,12 @@ preserve_referenced_local(WASMLoaderContext *loader_ctx, uint8 opcode, } return true; - -#if WASM_ENABLE_ABS_LABEL_ADDR == 0 +#if WASM_ENABLE_LABELS_AS_VALUES != 0 +#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 fail: return false; #endif +#endif } static bool @@ -4534,7 +4583,7 @@ apply_label_patch(WASMLoaderContext *ctx, uint8 depth, while (node) { node_next = node->next; if (node->patch_type == patch_type) { - *((uint8**)node->code_compiled) = ctx->p_code_compiled; + STORE_PTR(node->code_compiled, ctx->p_code_compiled); if (node_prev == NULL) { frame_csp->patch_list = node_next; } @@ -4588,12 +4637,12 @@ wasm_loader_emit_br_info(WASMLoaderContext *ctx, BranchBlock *frame_csp, emit_uint32(ctx, wasm_get_cell_num(types, arity)); /* Part c */ for (i = (int32)arity - 1; i >= 0; i--) { - cell = wasm_value_type_cell_num(types[i]); + cell = (uint8)wasm_value_type_cell_num(types[i]); emit_byte(ctx, cell); } /* Part d */ for (i = (int32)arity - 1; i >= 0; i--) { - cell = wasm_value_type_cell_num(types[i]); + cell = (uint8)wasm_value_type_cell_num(types[i]); frame_offset -= cell; emit_operand(ctx, *(int16*)(frame_offset)); } @@ -4601,7 +4650,7 @@ wasm_loader_emit_br_info(WASMLoaderContext *ctx, BranchBlock *frame_csp, dynamic_offset = frame_csp->dynamic_offset + wasm_get_cell_num(types, arity); for (i = (int32)arity - 1; i >= 0; i--) { - cell = wasm_value_type_cell_num(types[i]); + cell = (uint8)wasm_value_type_cell_num(types[i]); dynamic_offset -= cell; emit_operand(ctx, dynamic_offset); } @@ -5056,7 +5105,7 @@ reserve_block_ret(WASMLoaderContext *loader_ctx, /* If there is only one return value, use EXT_OP_COPY_STACK_TOP/_I64 instead * of EXT_OP_COPY_STACK_VALUES for interpreter performance. */ if (return_count == 1) { - uint8 cell = wasm_value_type_cell_num(return_types[0]); + uint8 cell = (uint8)wasm_value_type_cell_num(return_types[0]); if (block->dynamic_offset != *(loader_ctx->frame_offset - cell)) { /* insert op_copy before else opcode */ if (opcode == WASM_OP_ELSE) @@ -5095,7 +5144,7 @@ reserve_block_ret(WASMLoaderContext *loader_ctx, /* First traversal to get the count of values needed to be copied. */ for (i = (int32)return_count - 1; i >= 0; i--) { - uint8 cells = wasm_value_type_cell_num(return_types[i]); + uint8 cells = (uint8)wasm_value_type_cell_num(return_types[i]); frame_offset -= cells; dynamic_offset -= cells; @@ -5135,7 +5184,7 @@ reserve_block_ret(WASMLoaderContext *loader_ctx, frame_offset = frame_offset_org; dynamic_offset = dynamic_offset_org; for (i = (int32)return_count - 1, j = 0; i >= 0; i--) { - uint8 cell = wasm_value_type_cell_num(return_types[i]); + uint8 cell = (uint8)wasm_value_type_cell_num(return_types[i]); frame_offset -= cell; dynamic_offset -= cell; if (dynamic_offset != *frame_offset) { @@ -5614,7 +5663,7 @@ copy_params_to_dynamic_space(WASMLoaderContext *loader_ctx, bool is_if_block, /* Get each param's cell num and src offset */ for (i = 0; i < param_count; i++) { - cell = wasm_value_type_cell_num(wasm_type->types[i]); + cell = (uint8)wasm_value_type_cell_num(wasm_type->types[i]); cells[i] = cell; src_offsets[i] = *frame_offset; frame_offset += cell; @@ -5753,6 +5802,7 @@ re_scan: } p = func->code; func->code_compiled = loader_ctx->p_code_compiled; + func->code_compiled_size = loader_ctx->code_compiled_size; } #endif @@ -5901,9 +5951,9 @@ handle_op_block_and_loop: loader_malloc(size, error_buf, error_buf_size))) goto fail; bh_memcpy_s(block->param_frame_offsets, - size, + (uint32)size, loader_ctx->frame_offset - size/sizeof(int16), - size); + (uint32)size); } emit_empty_label_addr_and_frame_ip(PATCH_ELSE); @@ -6383,15 +6433,34 @@ handle_op_block_and_loop: #endif #if WASM_ENABLE_FAST_INTERP != 0 if (loader_ctx->p_code_compiled) { -#if WASM_ENABLE_ABS_LABEL_ADDR != 0 - *(void**)(loader_ctx->p_code_compiled - 2 - sizeof(void*)) = - handle_table[WASM_OP_SELECT_64]; + uint8 opcode_tmp = WASM_OP_SELECT_64; + uint8 *p_code_compiled_tmp = + loader_ctx->p_code_compiled - 2; +#if WASM_ENABLE_LABELS_AS_VALUES != 0 +#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS != 0 + *(void**)(p_code_compiled_tmp - sizeof(void*)) = + handle_table[opcode_tmp]; #else - *((int16*)loader_ctx->p_code_compiled - 2) = (int16) - (handle_table[WASM_OP_SELECT_64] - handle_table[0]); -#endif + int32 offset = (int32) + ((uint8*)handle_table[opcode_tmp] + - (uint8*)handle_table[0]); + if (!(offset >= INT16_MIN && offset < INT16_MAX)) { + set_error_buf(error_buf, error_buf_size, + "pre-compiled label offset out of range"); + goto fail; + } + *(int16*)(p_code_compiled_tmp - sizeof(int16)) = + (int16)offset; +#endif /* end of WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS */ +#else /* else of WASM_ENABLE_LABELS_AS_VALUES */ +#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS != 0 + *(p_code_compiled_tmp - 1) = opcode_tmp; +#else + *(p_code_compiled_tmp - 2) = opcode_tmp; +#endif /* end of WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS */ +#endif /* end of WASM_ENABLE_LABELS_AS_VALUES */ } -#endif +#endif /* end of WASM_ENABLE_FAST_INTERP */ break; default: bh_assert(0); @@ -6466,13 +6535,13 @@ handle_op_block_and_loop: skip_label(); if ((!preserve_local) && (LAST_OP_OUTPUT_I32())) { if (loader_ctx->p_code_compiled) - *(int16*)(loader_ctx->p_code_compiled - 2) = local_offset; + STORE_U16(loader_ctx->p_code_compiled - 2, local_offset); loader_ctx->frame_offset --; loader_ctx->dynamic_offset --; } else if ((!preserve_local) && (LAST_OP_OUTPUT_I64())) { if (loader_ctx->p_code_compiled) - *(int16*)(loader_ctx->p_code_compiled - 2) = local_offset; + STORE_U16(loader_ctx->p_code_compiled - 2, local_offset); loader_ctx->frame_offset -= 2; loader_ctx->dynamic_offset -= 2; } @@ -6480,11 +6549,11 @@ handle_op_block_and_loop: if (local_type == VALUE_TYPE_I32 || local_type == VALUE_TYPE_F32) { emit_label(EXT_OP_SET_LOCAL_FAST); - emit_byte(loader_ctx, local_offset); + emit_byte(loader_ctx, (uint8)local_offset); } else { emit_label(EXT_OP_SET_LOCAL_FAST_I64); - emit_byte(loader_ctx, local_offset); + emit_byte(loader_ctx, (uint8)local_offset); } POP_OFFSET_TYPE(local_type); } @@ -6538,11 +6607,11 @@ handle_op_block_and_loop: if (local_type == VALUE_TYPE_I32 || local_type == VALUE_TYPE_F32) { emit_label(EXT_OP_TEE_LOCAL_FAST); - emit_byte(loader_ctx, local_offset); + emit_byte(loader_ctx, (uint8)local_offset); } else { emit_label(EXT_OP_TEE_LOCAL_FAST_I64); - emit_byte(loader_ctx, local_offset); + emit_byte(loader_ctx, (uint8)local_offset); } } else { /* local index larger than 255, reserve leb */ @@ -7737,12 +7806,12 @@ fail_data_cnt_sec_require: Const *c = (Const*)(loader_ctx->const_buf + i * sizeof(Const)); if (c->value_type == VALUE_TYPE_F64 || c->value_type == VALUE_TYPE_I64) { - bh_memcpy_s(func_const, func_const_end - func_const, - &(c->value.f64), sizeof(int64)); + bh_memcpy_s(func_const, (uint32)(func_const_end - func_const), + &(c->value.f64), (uint32)sizeof(int64)); func_const += sizeof(int64); } else { - bh_memcpy_s(func_const, func_const_end - func_const, - &(c->value.f32), sizeof(int32)); + bh_memcpy_s(func_const, (uint32)(func_const_end - func_const), + &(c->value.f32), (uint32)sizeof(int32)); func_const += sizeof(int32); } } diff --git a/core/iwasm/interpreter/wasm_mini_loader.c b/core/iwasm/interpreter/wasm_mini_loader.c index 35b0950d1..b1854899a 100644 --- a/core/iwasm/interpreter/wasm_mini_loader.c +++ b/core/iwasm/interpreter/wasm_mini_loader.c @@ -1441,7 +1441,7 @@ static bool wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, char *error_buf, uint32 error_buf_size); -#if WASM_ENABLE_FAST_INTERP != 0 +#if WASM_ENABLE_FAST_INTERP != 0 && WASM_ENABLE_LABELS_AS_VALUES != 0 void ** wasm_interp_get_handle_table(); @@ -1732,7 +1732,7 @@ load_from_sections(WASMModule *module, WASMSection *sections, } } -#if WASM_ENABLE_FAST_INTERP != 0 +#if WASM_ENABLE_FAST_INTERP != 0 && WASM_ENABLE_LABELS_AS_VALUES != 0 handle_table = wasm_interp_get_handle_table(); #endif @@ -2639,7 +2639,7 @@ static bool check_offset_push(WASMLoaderContext *ctx, char *error_buf, uint32 error_buf_size) { - uint32 cell_num = (ctx->frame_offset - ctx->frame_offset_bottom); + uint32 cell_num = (uint32)(ctx->frame_offset - ctx->frame_offset_bottom); if (ctx->frame_offset >= ctx->frame_offset_boundary) { MEM_REALLOC(ctx->frame_offset_bottom, ctx->frame_offset_size, ctx->frame_offset_size + 16); @@ -2931,34 +2931,43 @@ wasm_loader_pop_frame_csp(WASMLoaderContext *ctx, #if WASM_ENABLE_FAST_INTERP != 0 -#if WASM_ENABLE_ABS_LABEL_ADDR != 0 - +#if WASM_ENABLE_LABELS_AS_VALUES != 0 +#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS != 0 #define emit_label(opcode) do { \ wasm_loader_emit_ptr(loader_ctx, handle_table[opcode]); \ LOG_OP("\nemit_op [%02x]\t", opcode); \ } while (0) - #define skip_label() do { \ wasm_loader_emit_backspace(loader_ctx, sizeof(void *)); \ LOG_OP("\ndelete last op\n"); \ } while (0) - -#else - +#else /* else of WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS */ #define emit_label(opcode) do { \ - int32 offset = (int32)(handle_table[opcode] - handle_table[0]); \ - bh_assert(offset >= INT16_MIN && offset < INT16_MAX); \ + int32 offset = (int32)((uint8*)handle_table[opcode] \ + - (uint8*)handle_table[0]); \ + if (!(offset >= INT16_MIN && offset < INT16_MAX)) { \ + set_error_buf(error_buf, error_buf_size, \ + "pre-compiled label offset out of range"); \ + goto fail; \ + } \ wasm_loader_emit_int16(loader_ctx, offset); \ LOG_OP("\nemit_op [%02x]\t", opcode); \ } while (0) - -/* drop local.get / const / block / loop / end */ #define skip_label() do { \ wasm_loader_emit_backspace(loader_ctx, sizeof(int16)); \ LOG_OP("\ndelete last op\n"); \ } while (0) - -#endif /* WASM_ENABLE_ABS_LABEL_ADDR */ +#endif /* end of WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS */ +#else /* else of WASM_ENABLE_LABELS_AS_VALUES */ +#define emit_label(opcode) do { \ + wasm_loader_emit_uint8(loader_ctx, opcode); \ + LOG_OP("\nemit_op [%02x]\t", opcode); \ + } while (0) +#define skip_label() do { \ + wasm_loader_emit_backspace(loader_ctx, sizeof(uint8)); \ + LOG_OP("\ndelete last op\n"); \ + } while (0) +#endif /* end of WASM_ENABLE_LABELS_AS_VALUES */ #define emit_empty_label_addr_and_frame_ip(type) do { \ if (!add_label_patch_to_list(loader_ctx->frame_csp - 1, type, \ @@ -3079,22 +3088,36 @@ static void wasm_loader_emit_uint32(WASMLoaderContext *ctx, uint32 value) { if (ctx->p_code_compiled) { - *(uint32*)(ctx->p_code_compiled) = value; +#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 + bh_assert(((uintptr_t)ctx->p_code_compiled & 1) == 0); +#endif + STORE_U32(ctx->p_code_compiled, value); ctx->p_code_compiled += sizeof(uint32); } - else + else { +#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 + bh_assert((ctx->code_compiled_size & 1) == 0); +#endif ctx->code_compiled_size += sizeof(uint32); + } } static void wasm_loader_emit_int16(WASMLoaderContext *ctx, int16 value) { if (ctx->p_code_compiled) { - *(int16*)(ctx->p_code_compiled) = value; +#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 + bh_assert(((uintptr_t)ctx->p_code_compiled & 1) == 0); +#endif + STORE_U16(ctx->p_code_compiled, (uint16)value); ctx->p_code_compiled += sizeof(int16); } - else + else { +#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 + bh_assert((ctx->code_compiled_size & 1) == 0); +#endif ctx->code_compiled_size += sizeof(int16); + } } static void @@ -3103,20 +3126,36 @@ wasm_loader_emit_uint8(WASMLoaderContext *ctx, uint8 value) if (ctx->p_code_compiled) { *(ctx->p_code_compiled) = value; ctx->p_code_compiled += sizeof(uint8); +#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 + ctx->p_code_compiled++; + bh_assert(((uintptr_t)ctx->p_code_compiled & 1) == 0); +#endif } - else + else { ctx->code_compiled_size += sizeof(uint8); +#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 + ctx->code_compiled_size++; + bh_assert((ctx->code_compiled_size & 1) == 0); +#endif + } } static void wasm_loader_emit_ptr(WASMLoaderContext *ctx, void *value) { if (ctx->p_code_compiled) { - *(uint8**)(ctx->p_code_compiled) = value; +#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 + bh_assert(((uintptr_t)ctx->p_code_compiled & 1) == 0); +#endif + STORE_PTR(ctx->p_code_compiled, value); ctx->p_code_compiled += sizeof(void *); } - else + else { +#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 + bh_assert((ctx->code_compiled_size & 1) == 0); +#endif ctx->code_compiled_size += sizeof(void *); + } } static void @@ -3124,9 +3163,22 @@ wasm_loader_emit_backspace(WASMLoaderContext *ctx, uint32 size) { if (ctx->p_code_compiled) { ctx->p_code_compiled -= size; +#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 + if (size == sizeof(uint8)) { + ctx->p_code_compiled--; + bh_assert(((uintptr_t)ctx->p_code_compiled & 1) == 0); + } +#endif } - else + else { ctx->code_compiled_size -= size; +#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 + if (size == sizeof(uint8)) { + ctx->code_compiled_size--; + bh_assert((ctx->code_compiled_size & 1) == 0); + } +#endif + } } static bool @@ -3177,10 +3229,12 @@ preserve_referenced_local(WASMLoaderContext *loader_ctx, uint8 opcode, return true; -#if WASM_ENABLE_ABS_LABEL_ADDR == 0 +#if WASM_ENABLE_LABELS_AS_VALUES != 0 +#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 fail: return false; #endif +#endif } static bool @@ -3252,7 +3306,7 @@ apply_label_patch(WASMLoaderContext *ctx, uint8 depth, while (node) { node_next = node->next; if (node->patch_type == patch_type) { - *((uint8**)node->code_compiled) = ctx->p_code_compiled; + STORE_PTR(node->code_compiled, ctx->p_code_compiled); if (node_prev == NULL) { frame_csp->patch_list = node_next; } @@ -3307,12 +3361,12 @@ wasm_loader_emit_br_info(WASMLoaderContext *ctx, BranchBlock *frame_csp, /* Part c */ for (i = (int32)arity - 1; i >= 0; i--) { - cell = wasm_value_type_cell_num(types[i]); + cell = (uint8)wasm_value_type_cell_num(types[i]); emit_byte(ctx, cell); } /* Part d */ for (i = (int32)arity - 1; i >= 0; i--) { - cell = wasm_value_type_cell_num(types[i]); + cell = (uint8)wasm_value_type_cell_num(types[i]); frame_offset -= cell; emit_operand(ctx, *(int16*)(frame_offset)); } @@ -3320,7 +3374,7 @@ wasm_loader_emit_br_info(WASMLoaderContext *ctx, BranchBlock *frame_csp, dynamic_offset = frame_csp->dynamic_offset + wasm_get_cell_num(types, arity); for (i = (int32)arity - 1; i >= 0; i--) { - cell = wasm_value_type_cell_num(types[i]); + cell = (uint8)wasm_value_type_cell_num(types[i]); dynamic_offset -= cell; emit_operand(ctx, dynamic_offset); } @@ -3750,7 +3804,7 @@ reserve_block_ret(WASMLoaderContext *loader_ctx, /* If there is only one return value, use EXT_OP_COPY_STACK_TOP/_I64 instead * of EXT_OP_COPY_STACK_VALUES for interpreter performance. */ if (return_count == 1) { - uint8 cell = wasm_value_type_cell_num(return_types[0]); + uint8 cell = (uint8)wasm_value_type_cell_num(return_types[0]); if (block->dynamic_offset != *(loader_ctx->frame_offset - cell)) { /* insert op_copy before else opcode */ if (opcode == WASM_OP_ELSE) @@ -3789,7 +3843,7 @@ reserve_block_ret(WASMLoaderContext *loader_ctx, /* First traversal to get the count of values needed to be copied. */ for (i = (int32)return_count - 1; i >= 0; i--) { - uint8 cells = wasm_value_type_cell_num(return_types[i]); + uint8 cells = (uint8)wasm_value_type_cell_num(return_types[i]); frame_offset -= cells; dynamic_offset -= cells; @@ -3829,7 +3883,7 @@ reserve_block_ret(WASMLoaderContext *loader_ctx, frame_offset = frame_offset_org; dynamic_offset = dynamic_offset_org; for (i = (int32)return_count - 1, j = 0; i >= 0; i--) { - uint8 cell = wasm_value_type_cell_num(return_types[i]); + uint8 cell = (uint8)wasm_value_type_cell_num(return_types[i]); frame_offset -= cell; dynamic_offset -= cell; if (dynamic_offset != *frame_offset) { @@ -4152,7 +4206,7 @@ copy_params_to_dynamic_space(WASMLoaderContext *loader_ctx, bool is_if_block, /* Get each param's cell num and src offset */ for (i = 0; i < param_count; i++) { - cell = wasm_value_type_cell_num(wasm_type->types[i]); + cell = (uint8)wasm_value_type_cell_num(wasm_type->types[i]); cells[i] = cell; src_offsets[i] = *frame_offset; frame_offset += cell; @@ -4291,6 +4345,7 @@ re_scan: } p = func->code; func->code_compiled = loader_ctx->p_code_compiled; + func->code_compiled_size = loader_ctx->code_compiled_size; } #endif @@ -4435,9 +4490,9 @@ handle_op_block_and_loop: loader_malloc(size, error_buf, error_buf_size))) goto fail; bh_memcpy_s(block->param_frame_offsets, - size, + (uint32)size, loader_ctx->frame_offset - size/sizeof(int16), - size); + (uint32)size); } emit_empty_label_addr_and_frame_ip(PATCH_ELSE); @@ -4827,13 +4882,32 @@ handle_op_block_and_loop: #endif #if WASM_ENABLE_FAST_INTERP != 0 if (loader_ctx->p_code_compiled) { -#if WASM_ENABLE_ABS_LABEL_ADDR != 0 - *(void**)(loader_ctx->p_code_compiled - 2 - sizeof(void*)) = - handle_table[WASM_OP_SELECT_64]; + uint8 opcode_tmp = WASM_OP_SELECT_64; + uint8 *p_code_compiled_tmp = + loader_ctx->p_code_compiled - 2; +#if WASM_ENABLE_LABELS_AS_VALUES != 0 +#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS != 0 + *(void**)(p_code_compiled_tmp - sizeof(void*)) = + handle_table[opcode_tmp]; #else - *((int16*)loader_ctx->p_code_compiled - 2) = (int16) - (handle_table[WASM_OP_SELECT_64] - handle_table[0]); -#endif + int32 offset = (int32) + ((uint8*)handle_table[opcode_tmp] + - (uint8*)handle_table[0]); + if (!(offset >= INT16_MIN && offset < INT16_MAX)) { + set_error_buf(error_buf, error_buf_size, + "pre-compiled label offset out of range"); + goto fail; + } + *(int16*)(p_code_compiled_tmp - sizeof(int16)) = + (int16)offset; +#endif /* end of WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS */ +#else /* else of WASM_ENABLE_LABELS_AS_VALUES */ +#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS != 0 + *(p_code_compiled_tmp - 1) = opcode_tmp; +#else + *(p_code_compiled_tmp - 2) = opcode_tmp; +#endif /* end of WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS */ +#endif /* end of WASM_ENABLE_LABELS_AS_VALUES */ } #endif break; @@ -4907,13 +4981,13 @@ handle_op_block_and_loop: skip_label(); if ((!preserve_local) && (LAST_OP_OUTPUT_I32())) { if (loader_ctx->p_code_compiled) - *(int16*)(loader_ctx->p_code_compiled - 2) = local_offset; + STORE_U16(loader_ctx->p_code_compiled - 2, local_offset); loader_ctx->frame_offset --; loader_ctx->dynamic_offset --; } else if ((!preserve_local) && (LAST_OP_OUTPUT_I64())) { if (loader_ctx->p_code_compiled) - *(int16*)(loader_ctx->p_code_compiled - 2) = local_offset; + STORE_U16(loader_ctx->p_code_compiled - 2, local_offset); loader_ctx->frame_offset -= 2; loader_ctx->dynamic_offset -= 2; } @@ -4921,11 +4995,11 @@ handle_op_block_and_loop: if (local_type == VALUE_TYPE_I32 || local_type == VALUE_TYPE_F32) { emit_label(EXT_OP_SET_LOCAL_FAST); - emit_byte(loader_ctx, local_offset); + emit_byte(loader_ctx, (uint8)local_offset); } else { emit_label(EXT_OP_SET_LOCAL_FAST_I64); - emit_byte(loader_ctx, local_offset); + emit_byte(loader_ctx, (uint8)local_offset); } POP_OFFSET_TYPE(local_type); } @@ -4979,11 +5053,11 @@ handle_op_block_and_loop: if (local_type == VALUE_TYPE_I32 || local_type == VALUE_TYPE_F32) { emit_label(EXT_OP_TEE_LOCAL_FAST); - emit_byte(loader_ctx, local_offset); + emit_byte(loader_ctx, (uint8)local_offset); } else { emit_label(EXT_OP_TEE_LOCAL_FAST_I64); - emit_byte(loader_ctx, local_offset); + emit_byte(loader_ctx, (uint8)local_offset); } } else { /* local index larger than 255, reserve leb */ @@ -5738,12 +5812,12 @@ handle_op_block_and_loop: Const *c = (Const*)(loader_ctx->const_buf + i * sizeof(Const)); if (c->value_type == VALUE_TYPE_F64 || c->value_type == VALUE_TYPE_I64) { - bh_memcpy_s(func_const, func_const_end - func_const, - &(c->value.f64), sizeof(int64)); + bh_memcpy_s(func_const, (uint32)(func_const_end - func_const), + &(c->value.f64), (uint32)sizeof(int64)); func_const += sizeof(int64); } else { - bh_memcpy_s(func_const, func_const_end - func_const, - &(c->value.f32), sizeof(int32)); + bh_memcpy_s(func_const, (uint32)(func_const_end - func_const), + &(c->value.f32), (uint32)sizeof(int32)); func_const += sizeof(int32); } } diff --git a/product-mini/platforms/android/CMakeLists.txt b/product-mini/platforms/android/CMakeLists.txt index 062a3823c..c59f98c0d 100644 --- a/product-mini/platforms/android/CMakeLists.txt +++ b/product-mini/platforms/android/CMakeLists.txt @@ -95,9 +95,9 @@ endif () add_library (iwasm SHARED ${WAMR_RUNTIME_LIB_SOURCE}) if (CMAKE_BUILD_TYPE STREQUAL Release) -target_link_libraries (iwasm ${LLVM_AVAILABLE_LIBS} -lm -ldl -landroid -llog -s) +target_link_libraries (iwasm ${LLVM_AVAILABLE_LIBS} ${UV_A_LIBS} -lm -ldl -landroid -llog -s) else() -target_link_libraries (iwasm ${LLVM_AVAILABLE_LIBS} -lm -ldl -landroid -llog) +target_link_libraries (iwasm ${LLVM_AVAILABLE_LIBS} ${UV_A_LIBS} -lm -ldl -landroid -llog) endif() set (distribution_DIR ${CMAKE_CURRENT_SOURCE_DIR}/build/distribution) diff --git a/product-mini/platforms/darwin/CMakeLists.txt b/product-mini/platforms/darwin/CMakeLists.txt index 71f8b5f39..6c3845632 100644 --- a/product-mini/platforms/darwin/CMakeLists.txt +++ b/product-mini/platforms/darwin/CMakeLists.txt @@ -98,7 +98,7 @@ add_executable (iwasm main.c ${UNCOMMON_SHARED_SOURCE}) install (TARGETS iwasm DESTINATION bin) -target_link_libraries (iwasm vmlib ${LLVM_AVAILABLE_LIBS} -lm -ldl -lpthread) +target_link_libraries (iwasm vmlib ${LLVM_AVAILABLE_LIBS} ${UV_A_LIBS} -lm -ldl -lpthread) add_library (libiwasm SHARED ${WAMR_RUNTIME_LIB_SOURCE}) @@ -106,5 +106,5 @@ install (TARGETS libiwasm DESTINATION lib) set_target_properties (libiwasm PROPERTIES OUTPUT_NAME iwasm) -target_link_libraries (libiwasm ${LLVM_AVAILABLE_LIBS} -lm -ldl -lpthread) +target_link_libraries (libiwasm ${LLVM_AVAILABLE_LIBS} ${UV_A_LIBS} -lm -ldl -lpthread) diff --git a/product-mini/platforms/linux/CMakeLists.txt b/product-mini/platforms/linux/CMakeLists.txt index 0f8537970..cefb9bff5 100644 --- a/product-mini/platforms/linux/CMakeLists.txt +++ b/product-mini/platforms/linux/CMakeLists.txt @@ -127,4 +127,4 @@ install (TARGETS libiwasm DESTINATION lib) set_target_properties (libiwasm PROPERTIES OUTPUT_NAME iwasm) -target_link_libraries (libiwasm ${LLVM_AVAILABLE_LIBS} -lm -ldl -lpthread) +target_link_libraries (libiwasm ${LLVM_AVAILABLE_LIBS} ${UV_A_LIBS} -lm -ldl -lpthread) diff --git a/product-mini/platforms/windows/CMakeLists.txt b/product-mini/platforms/windows/CMakeLists.txt index 4f130de0c..04d505d6c 100644 --- a/product-mini/platforms/windows/CMakeLists.txt +++ b/product-mini/platforms/windows/CMakeLists.txt @@ -58,7 +58,7 @@ endif () if (NOT DEFINED WAMR_BUILD_FAST_INTERP) # Enable fast interpreter - set (WAMR_BUILD_FAST_INTERP 0) + set (WAMR_BUILD_FAST_INTERP 1) endif () if (NOT DEFINED WAMR_BUILD_MULTI_MODULE) @@ -91,7 +91,7 @@ include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) add_library(vmlib ${WAMR_RUNTIME_LIB_SOURCE}) set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SAFESEH:NO") -set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SAFESEH:NO") +set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /SAFESEH:NO") # set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat -Wformat-security") # set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wconversion -Wsign-conversion") From fe76c89c258a00b12164ce0a3753f77a3329f222 Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Thu, 1 Apr 2021 23:34:21 -0500 Subject: [PATCH 176/207] Fix aot code failed to run on darwin/android issue (#599) --- core/iwasm/aot/aot_loader.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/iwasm/aot/aot_loader.c b/core/iwasm/aot/aot_loader.c index 40d497369..5c4b7e1ac 100644 --- a/core/iwasm/aot/aot_loader.c +++ b/core/iwasm/aot/aot_loader.c @@ -1838,7 +1838,7 @@ load_relocation_section(const uint8 *buf, const uint8 *buf_end, } /* Set read only for AOT code and some data sections */ - map_prot = MMAP_PROT_READ; + map_prot = MMAP_PROT_READ | MMAP_PROT_EXEC; if (module->code) { /* The layout is: literal size + literal + code (with plt table) */ @@ -1848,6 +1848,8 @@ load_relocation_section(const uint8 *buf, const uint8 *buf_end, os_mprotect(mmap_addr, total_size, map_prot); } + map_prot = MMAP_PROT_READ; + #if defined(BH_PLATFORM_WINDOWS) if (module->extra_plt_data) { os_mprotect(module->extra_plt_data, module->extra_plt_data_size, From 77c3ddf7d0d946258cbf56ea6c9b1c14e46e4061 Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Wed, 7 Apr 2021 16:15:59 +0800 Subject: [PATCH 177/207] Implement aux stack overflow/underflow check for AOT/interp (#601) --- core/iwasm/aot/aot_runtime.c | 9 ++- core/iwasm/aot/aot_runtime.h | 2 + core/iwasm/common/wasm_exec_env.c | 35 ++++++++-- core/iwasm/common/wasm_exec_env.h | 34 +++++++--- core/iwasm/compilation/aot_compiler.c | 6 +- core/iwasm/compilation/aot_compiler.h | 3 + core/iwasm/compilation/aot_emit_control.c | 3 +- core/iwasm/compilation/aot_emit_variable.c | 64 +++++++++++++++++-- core/iwasm/compilation/aot_emit_variable.h | 2 +- core/iwasm/compilation/aot_llvm.c | 58 +++++++++++++++++ core/iwasm/compilation/aot_llvm.h | 11 +++- core/iwasm/include/aot_export.h | 1 + core/iwasm/interpreter/wasm_interp_classic.c | 20 ++++-- core/iwasm/interpreter/wasm_interp_fast.c | 20 ++++-- core/iwasm/interpreter/wasm_loader.c | 2 - core/iwasm/interpreter/wasm_runtime.c | 3 +- .../libraries/thread-mgr/thread_manager.c | 9 +-- wamr-compiler/main.c | 5 ++ 18 files changed, 242 insertions(+), 45 deletions(-) diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index 8dc964f39..50b224351 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -1393,6 +1393,12 @@ aot_set_exception_with_id(AOTModuleInstance *module_inst, case EXCE_UNALIGNED_ATOMIC: aot_set_exception(module_inst, "unaligned atomic"); break; + case EXCE_AUX_STACK_OVERFLOW: + aot_set_exception(module_inst, "wasm auxiliary stack overflow"); + break; + case EXCE_AUX_STACK_UNDERFLOW: + aot_set_exception(module_inst, "wasm auxiliary stack underflow"); + break; default: break; } @@ -2208,7 +2214,8 @@ aot_set_aux_stack(WASMExecEnv *exec_env, /* The aux stack boundary is a constant value, set the value to exec_env */ - exec_env->aux_stack_boundary = start_offset - size; + exec_env->aux_stack_boundary.boundary = start_offset - size; + exec_env->aux_stack_bottom.bottom = start_offset; return true; } diff --git a/core/iwasm/aot/aot_runtime.h b/core/iwasm/aot/aot_runtime.h index 527be0dd4..4c461d65e 100644 --- a/core/iwasm/aot/aot_runtime.h +++ b/core/iwasm/aot/aot_runtime.h @@ -32,6 +32,8 @@ typedef enum AOTExceptionID { EXCE_CALL_UNLINKED_IMPORT_FUNC, EXCE_NATIVE_STACK_OVERFLOW, EXCE_UNALIGNED_ATOMIC, + EXCE_AUX_STACK_OVERFLOW, + EXCE_AUX_STACK_UNDERFLOW, EXCE_NUM, } AOTExceptionID; diff --git a/core/iwasm/common/wasm_exec_env.c b/core/iwasm/common/wasm_exec_env.c index 478239dd0..382efd7f8 100644 --- a/core/iwasm/common/wasm_exec_env.c +++ b/core/iwasm/common/wasm_exec_env.c @@ -5,6 +5,12 @@ #include "wasm_exec_env.h" #include "wasm_runtime_common.h" +#if WASM_ENABLE_INTERP != 0 +#include "../interpreter/wasm_runtime.h" +#endif +#if WASM_ENABLE_AOT != 0 +#include "../aot/aot_runtime.h" +#endif #if WASM_ENABLE_THREAD_MGR != 0 #include "../libraries/thread-mgr/thread_manager.h" @@ -88,20 +94,37 @@ WASMExecEnv * wasm_exec_env_create(struct WASMModuleInstanceCommon *module_inst, uint32 stack_size) { +#if WASM_ENABLE_THREAD_MGR != 0 + WASMCluster *cluster; +#endif WASMExecEnv *exec_env = wasm_exec_env_create_internal(module_inst, stack_size); if (!exec_env) return NULL; - /* Set the aux_stack_boundary to 0 */ - exec_env->aux_stack_boundary = 0; -#if WASM_ENABLE_THREAD_MGR != 0 - WASMCluster *cluster; + /* Set the aux_stack_boundary and aux_stack_bottom */ +#if WASM_ENABLE_INTERP != 0 + if (module_inst->module_type == Wasm_Module_Bytecode) { + WASMModule *module = ((WASMModuleInstance *)module_inst)->module; + exec_env->aux_stack_bottom.bottom = module->aux_stack_bottom; + exec_env->aux_stack_boundary.boundary = module->aux_stack_bottom + - module->aux_stack_size; + } +#endif +#if WASM_ENABLE_AOT != 0 + if (module_inst->module_type == Wasm_Module_AoT) { + AOTModule *module = + (AOTModule *)(((AOTModuleInstance *)module_inst)->aot_module.ptr); + exec_env->aux_stack_bottom.bottom = module->aux_stack_bottom; + exec_env->aux_stack_boundary.boundary = module->aux_stack_bottom + - module->aux_stack_size; + } +#endif +#if WASM_ENABLE_THREAD_MGR != 0 /* Create a new cluster for this exec_env */ - cluster = wasm_cluster_create(exec_env); - if (!cluster) { + if (!(cluster = wasm_cluster_create(exec_env))) { wasm_exec_env_destroy_internal(exec_env); return NULL; } diff --git a/core/iwasm/common/wasm_exec_env.h b/core/iwasm/common/wasm_exec_env.h index 454ee8670..df6131209 100644 --- a/core/iwasm/common/wasm_exec_env.h +++ b/core/iwasm/common/wasm_exec_env.h @@ -37,8 +37,10 @@ typedef struct WASMExecEnv { /* Previous thread's exec env of a WASM module instance. */ struct WASMExecEnv *prev; - /* Note: field module_inst, argv_buf and native_stack_boundary - are used by AOTed code, don't change the places of them */ + /* Note: field module_inst, argv_buf, native_stack_boundary, + suspend_flags, aux_stack_boundary, aux_stack_bottom, and + native_symbol are used by AOTed code, don't change the + places of them */ /* The WASM module instance of current thread */ struct WASMModuleInstanceCommon *module_inst; @@ -52,10 +54,9 @@ typedef struct WASMExecEnv { exception. */ uint8 *native_stack_boundary; -#if WASM_ENABLE_THREAD_MGR != 0 - /* Used to terminate or suspend the interpreter - bit 0: need terminate - bit 1: need suspend + /* Used to terminate or suspend current thread + bit 0: need to terminate + bit 1: need to suspend bit 2: need to go into breakpoint bit 3: return from pthread_exit */ union { @@ -63,6 +64,24 @@ typedef struct WASMExecEnv { uintptr_t __padding__; } suspend_flags; + /* Auxiliary stack boundary */ + union { + uint32 boundary; + uintptr_t __padding__; + } aux_stack_boundary; + + /* Auxiliary stack bottom */ + union { + uint32 bottom; + uintptr_t __padding__; + } aux_stack_bottom; + +#if WASM_ENABLE_AOT != 0 + /* Native symbol list, reserved */ + void **native_symbol; +#endif + +#if WASM_ENABLE_THREAD_MGR != 0 /* thread return value */ void *thread_ret_value; @@ -78,9 +97,6 @@ typedef struct WASMExecEnv { korp_cond wait_cond; #endif - /* Aux stack boundary */ - uint32 aux_stack_boundary; - /* attachment for native function */ void *attachment; diff --git a/core/iwasm/compilation/aot_compiler.c b/core/iwasm/compilation/aot_compiler.c index a0ebec6e1..766ce24d6 100644 --- a/core/iwasm/compilation/aot_compiler.c +++ b/core/iwasm/compilation/aot_compiler.c @@ -336,8 +336,12 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index) break; case WASM_OP_SET_GLOBAL: + case WASM_OP_SET_GLOBAL_64: + case WASM_OP_SET_GLOBAL_AUX_STACK: read_leb_uint32(frame_ip, frame_ip_end, global_idx); - if (!aot_compile_op_set_global(comp_ctx, func_ctx, global_idx)) + if (!aot_compile_op_set_global(comp_ctx, func_ctx, global_idx, + opcode == WASM_OP_SET_GLOBAL_AUX_STACK + ? true : false)) return false; break; diff --git a/core/iwasm/compilation/aot_compiler.h b/core/iwasm/compilation/aot_compiler.h index 5031d3a47..c1c05cd6c 100644 --- a/core/iwasm/compilation/aot_compiler.h +++ b/core/iwasm/compilation/aot_compiler.h @@ -233,6 +233,9 @@ typedef enum FloatArithmetic { #define I32_TWO (comp_ctx->llvm_consts.i32_two) #define I32_THREE (comp_ctx->llvm_consts.i32_three) #define I32_FOUR (comp_ctx->llvm_consts.i32_four) +#define I32_FIVE (comp_ctx->llvm_consts.i32_five) +#define I32_SIX (comp_ctx->llvm_consts.i32_six) +#define I32_SEVEN (comp_ctx->llvm_consts.i32_seven) #define I32_EIGHT (comp_ctx->llvm_consts.i32_eight) #define I32_NEG_ONE (comp_ctx->llvm_consts.i32_neg_one) #define I64_NEG_ONE (comp_ctx->llvm_consts.i64_neg_one) diff --git a/core/iwasm/compilation/aot_emit_control.c b/core/iwasm/compilation/aot_emit_control.c index 2b8a8a526..ca2cc75a6 100644 --- a/core/iwasm/compilation/aot_emit_control.c +++ b/core/iwasm/compilation/aot_emit_control.c @@ -640,8 +640,7 @@ check_suspend_flags(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) LLVMBasicBlockRef terminate_block; /* Offset of suspend_flags */ - offset = I32_CONST(5); - CHECK_LLVM_CONST(offset); + offset = I32_FIVE; if (!(terminate_addr = LLVMBuildInBoundsGEP(comp_ctx->builder, func_ctx->exec_env, diff --git a/core/iwasm/compilation/aot_emit_variable.c b/core/iwasm/compilation/aot_emit_variable.c index 78d39f7d3..f79588cda 100644 --- a/core/iwasm/compilation/aot_emit_variable.c +++ b/core/iwasm/compilation/aot_emit_variable.c @@ -4,6 +4,7 @@ */ #include "aot_emit_variable.h" +#include "aot_emit_exception.h" #include "../aot/aot_runtime.h" #define CHECK_LOCAL(idx) do { \ @@ -107,7 +108,7 @@ fail: static bool compile_global(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, - uint32 global_idx, bool is_set) + 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; @@ -179,6 +180,61 @@ compile_global(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } 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."); @@ -197,13 +253,13 @@ 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); + 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) + uint32 global_idx, bool is_aux_stack) { - return compile_global(comp_ctx, func_ctx, global_idx, true); + return compile_global(comp_ctx, func_ctx, global_idx, true, is_aux_stack); } diff --git a/core/iwasm/compilation/aot_emit_variable.h b/core/iwasm/compilation/aot_emit_variable.h index de2b35f62..e3b588352 100644 --- a/core/iwasm/compilation/aot_emit_variable.h +++ b/core/iwasm/compilation/aot_emit_variable.h @@ -30,7 +30,7 @@ aot_compile_op_get_global(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, bool aot_compile_op_set_global(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, - uint32 global_idx); + uint32 global_idx, bool is_aux_stack); #ifdef __cplusplus } /* end of extern "C" */ diff --git a/core/iwasm/compilation/aot_llvm.c b/core/iwasm/compilation/aot_llvm.c index d5863e4b0..9651ef95e 100644 --- a/core/iwasm/compilation/aot_llvm.c +++ b/core/iwasm/compilation/aot_llvm.c @@ -628,6 +628,8 @@ aot_create_func_context(AOTCompData *comp_data, AOTCompContext *comp_ctx, LLVMValueRef aot_inst_offset = I32_TWO, aot_inst_addr; LLVMValueRef argv_buf_offset = I32_THREE, argv_buf_addr; LLVMValueRef stack_bound_offset = I32_FOUR, stack_bound_addr; + LLVMValueRef aux_stack_bound_offset = I32_SIX, aux_stack_bound_addr; + LLVMValueRef aux_stack_bottom_offset = I32_SEVEN, aux_stack_bottom_addr; char local_name[32]; uint64 size; uint32 i, j = 0; @@ -718,6 +720,53 @@ aot_create_func_context(AOTCompData *comp_data, AOTCompContext *comp_ctx, goto fail; } + /* Get aux stack boundary address */ + if (!(aux_stack_bound_addr = + LLVMBuildInBoundsGEP(comp_ctx->builder, func_ctx->exec_env, + &aux_stack_bound_offset, 1, + "aux_stack_bound_addr"))) { + aot_set_last_error("llvm build in bounds gep failed"); + goto fail; + } + + if (!(aux_stack_bound_addr = + LLVMBuildBitCast(comp_ctx->builder, + aux_stack_bound_addr, + INT32_PTR_TYPE, "aux_stack_bound_ptr"))) { + aot_set_last_error("llvm build bit cast failed"); + goto fail; + } + + if (!(func_ctx->aux_stack_bound = + LLVMBuildLoad(comp_ctx->builder, + aux_stack_bound_addr, "aux_stack_bound"))) { + aot_set_last_error("llvm build load failed"); + goto fail; + } + + /* Get aux stack bottom address */ + if (!(aux_stack_bottom_addr = + LLVMBuildInBoundsGEP(comp_ctx->builder, func_ctx->exec_env, + &aux_stack_bottom_offset, 1, + "aux_stack_bottom_addr"))) { + aot_set_last_error("llvm build in bounds gep failed"); + goto fail; + } + + if (!(aux_stack_bottom_addr = + LLVMBuildBitCast(comp_ctx->builder, + aux_stack_bottom_addr, + INT32_PTR_TYPE, "aux_stack_bottom_ptr"))) { + aot_set_last_error("llvm build bit cast failed"); + goto fail; + } + if (!(func_ctx->aux_stack_bottom = + LLVMBuildLoad(comp_ctx->builder, + aux_stack_bottom_addr, "aux_stack_bottom"))) { + aot_set_last_error("llvm build load failed"); + goto fail; + } + for (i = 0; i < aot_func_type->param_count; i++, j++) { snprintf(local_name, sizeof(local_name), "l%d", i); func_ctx->locals[i] = @@ -953,6 +1002,9 @@ aot_create_llvm_consts(AOTLLVMConsts *consts, AOTCompContext *comp_ctx) consts->i32_two = I32_CONST(2); consts->i32_three = I32_CONST(3); consts->i32_four = I32_CONST(4); + consts->i32_five = I32_CONST(5); + consts->i32_six = I32_CONST(6); + consts->i32_seven = I32_CONST(7); consts->i32_eight = I32_CONST(8); consts->i32_neg_one = I32_CONST((uint32)-1); consts->i64_neg_one = I64_CONST((uint64)-1); @@ -978,6 +1030,9 @@ aot_create_llvm_consts(AOTLLVMConsts *consts, AOTCompContext *comp_ctx) && consts->i32_two && consts->i32_three && consts->i32_four + && consts->i32_five + && consts->i32_six + && consts->i32_seven && consts->i32_eight && consts->i32_neg_one && consts->i64_neg_one @@ -1192,6 +1247,9 @@ aot_create_comp_context(AOTCompData *comp_data, if (option->enable_aux_stack_frame) comp_ctx->enable_aux_stack_frame = true; + if (option->enable_aux_stack_check) + comp_ctx->enable_aux_stack_check = true; + if (option->is_jit_mode) { char *triple_jit = NULL; diff --git a/core/iwasm/compilation/aot_llvm.h b/core/iwasm/compilation/aot_llvm.h index 0fa11ed3e..83ed0e781 100644 --- a/core/iwasm/compilation/aot_llvm.h +++ b/core/iwasm/compilation/aot_llvm.h @@ -122,6 +122,8 @@ typedef struct AOTFuncContext { LLVMValueRef table_base; LLVMValueRef argv_buf; LLVMValueRef native_stack_bound; + LLVMValueRef aux_stack_bound; + LLVMValueRef aux_stack_bottom; LLVMValueRef last_alloca; LLVMValueRef func_ptrs; @@ -185,6 +187,9 @@ typedef struct AOTLLVMConsts { LLVMValueRef i32_two; LLVMValueRef i32_three; LLVMValueRef i32_four; + LLVMValueRef i32_five; + LLVMValueRef i32_six; + LLVMValueRef i32_seven; LLVMValueRef i32_eight; LLVMValueRef i32_neg_one; LLVMValueRef i64_neg_one; @@ -224,7 +229,10 @@ typedef struct AOTCompContext { /* 128-bit SIMD */ bool enable_simd; - /* generate auxiliary stack frame */ + /* Auxiliary stack overflow/underflow check */ + bool enable_aux_stack_check; + + /* Generate auxiliary stack frame */ bool enable_aux_stack_frame; /* Thread Manager */ @@ -275,6 +283,7 @@ typedef struct AOTCompOption{ bool enable_thread_mgr; bool enable_tail_call; bool enable_simd; + bool enable_aux_stack_check; bool enable_aux_stack_frame; bool is_sgx_platform; uint32 opt_level; diff --git a/core/iwasm/include/aot_export.h b/core/iwasm/include/aot_export.h index c1cac6782..8edabeb31 100644 --- a/core/iwasm/include/aot_export.h +++ b/core/iwasm/include/aot_export.h @@ -43,6 +43,7 @@ typedef struct AOTCompOption{ bool enable_thread_mgr; bool enable_tail_call; bool enable_simd; + bool enable_aux_stack_check; bool enable_aux_stack_frame; bool is_sgx_platform; uint32_t opt_level; diff --git a/core/iwasm/interpreter/wasm_interp_classic.c b/core/iwasm/interpreter/wasm_interp_classic.c index 16dd27cc8..8f37c0d77 100644 --- a/core/iwasm/interpreter/wasm_interp_classic.c +++ b/core/iwasm/interpreter/wasm_interp_classic.c @@ -702,7 +702,7 @@ ALLOC_FRAME(WASMExecEnv *exec_env, uint32 size, WASMInterpFrame *prev_frame) } else { wasm_set_exception((WASMModuleInstance*)exec_env->module_inst, - "stack overflow"); + "wasm operand stack overflow"); } return frame; @@ -1350,6 +1350,8 @@ label_pop_csp_n: HANDLE_OP (WASM_OP_SET_GLOBAL_AUX_STACK): { + uint32 aux_stack_top; + read_leb_uint32(frame_ip, frame_ip_end, global_idx); bh_assert(global_idx < module->global_count); global = globals + global_idx; @@ -1361,9 +1363,17 @@ label_pop_csp_n: + global->import_global_inst->data_offset : global_data + global->data_offset; #endif - if (*(uint32*)(frame_sp - 1) < exec_env->aux_stack_boundary) - goto out_of_bounds; - *(int32*)global_addr = POP_I32(); + aux_stack_top = *(uint32*)(frame_sp - 1); + if (aux_stack_top <= exec_env->aux_stack_boundary.boundary) { + wasm_set_exception(module, "wasm auxiliary stack overflow"); + goto got_exception; + } + if (aux_stack_top > exec_env->aux_stack_bottom.bottom) { + wasm_set_exception(module, "wasm auxiliary stack underflow"); + goto got_exception; + } + *(int32*)global_addr = aux_stack_top; + frame_sp--; #if WASM_ENABLE_MEMORY_PROFILING != 0 if (module->module->aux_stack_top_global_index != (uint32)-1) { uint32 aux_stack_used = @@ -3021,7 +3031,7 @@ label_pop_csp_n: + (uint64)cur_wasm_func->max_stack_cell_num + ((uint64)cur_wasm_func->max_block_num) * sizeof(WASMBranchBlock) / 4; if (all_cell_num >= UINT32_MAX) { - wasm_set_exception(module, "stack overflow"); + wasm_set_exception(module, "wasm operand stack overflow"); goto got_exception; } diff --git a/core/iwasm/interpreter/wasm_interp_fast.c b/core/iwasm/interpreter/wasm_interp_fast.c index 465d8b0e1..e98ec760d 100644 --- a/core/iwasm/interpreter/wasm_interp_fast.c +++ b/core/iwasm/interpreter/wasm_interp_fast.c @@ -775,7 +775,7 @@ ALLOC_FRAME(WASMExecEnv *exec_env, uint32 size, WASMInterpFrame *prev_frame) } else { wasm_set_exception((WASMModuleInstance*)exec_env->module_inst, - "stack overflow"); + "wasm operand stack overflow"); } return frame; @@ -1339,6 +1339,8 @@ recover_br_info: HANDLE_OP (WASM_OP_SET_GLOBAL_AUX_STACK): { + uint32 aux_stack_top; + global_idx = read_uint32(frame_ip); bh_assert(global_idx < module->global_count); global = globals + global_idx; @@ -1350,10 +1352,16 @@ recover_br_info: + global->import_global_inst->data_offset : global_data + global->data_offset; #endif - addr1 = GET_OFFSET(); - if (frame_lp[addr1] < exec_env->aux_stack_boundary) - goto out_of_bounds; - *(int32*)global_addr = frame_lp[addr1]; + aux_stack_top = frame_lp[GET_OFFSET()]; + if (aux_stack_top <= exec_env->aux_stack_boundary.boundary) { + wasm_set_exception(module, "wasm auxiliary stack overflow"); + goto got_exception; + } + if (aux_stack_top > exec_env->aux_stack_bottom.bottom) { + wasm_set_exception(module, "wasm auxiliary stack underflow"); + goto got_exception; + } + *(int32*)global_addr = aux_stack_top; #if WASM_ENABLE_MEMORY_PROFILING != 0 if (module->module->aux_stack_top_global_index != (uint32)-1) { uint32 aux_stack_used = @@ -3130,7 +3138,7 @@ recover_br_info: + (uint64)cur_func->const_cell_num + (uint64)cur_wasm_func->max_stack_cell_num; if (all_cell_num >= UINT32_MAX) { - wasm_set_exception(module, "stack overflow"); + wasm_set_exception(module, "wasm operand stack overflow"); goto got_exception; } diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index e346eabe1..2ab8aa53d 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -6705,7 +6705,6 @@ handle_op_block_and_loop: POP_TYPE(global_type); #if WASM_ENABLE_FAST_INTERP == 0 -#if (WASM_ENABLE_WAMR_COMPILER == 0) && (WASM_ENABLE_JIT == 0) if (global_type == VALUE_TYPE_I64 || global_type == VALUE_TYPE_F64) { *p_org = WASM_OP_SET_GLOBAL_64; @@ -6714,7 +6713,6 @@ handle_op_block_and_loop: && global_idx == module->aux_stack_top_global_index) { *p_org = WASM_OP_SET_GLOBAL_AUX_STACK; } -#endif #else /* else of WASM_ENABLE_FAST_INTERP */ if (global_type == VALUE_TYPE_I64 || global_type == VALUE_TYPE_F64) { diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index c742553c3..d32ac9950 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -2071,7 +2071,8 @@ wasm_set_aux_stack(WASMExecEnv *exec_env, *(int32*)global_addr = start_offset; /* The aux stack boundary is a constant value, set the value to exec_env */ - exec_env->aux_stack_boundary = start_offset - size; + exec_env->aux_stack_boundary.boundary = start_offset - size; + exec_env->aux_stack_bottom.bottom = start_offset; return true; } diff --git a/core/iwasm/libraries/thread-mgr/thread_manager.c b/core/iwasm/libraries/thread-mgr/thread_manager.c index afcc170c8..ea4edf826 100644 --- a/core/iwasm/libraries/thread-mgr/thread_manager.c +++ b/core/iwasm/libraries/thread-mgr/thread_manager.c @@ -384,8 +384,7 @@ wasm_cluster_destroy_spawned_exec_env(WASMExecEnv *exec_env) bh_assert(cluster != NULL); /* Free aux stack space */ - free_aux_stack(cluster, - exec_env->aux_stack_boundary + cluster->stack_size); + free_aux_stack(cluster, exec_env->aux_stack_bottom.bottom); wasm_cluster_del_exec_env(cluster, exec_env); wasm_exec_env_destroy_internal(exec_env); @@ -411,8 +410,7 @@ thread_manager_start_routine(void *arg) /* Routine exit */ /* Free aux stack space */ - free_aux_stack(cluster, - exec_env->aux_stack_boundary + cluster->stack_size); + free_aux_stack(cluster, exec_env->aux_stack_bottom.bottom); /* Detach the native thread here to ensure the resources are freed */ wasm_cluster_detach_thread(exec_env); /* Remove and destroy exec_env */ @@ -519,8 +517,7 @@ wasm_cluster_exit_thread(WASMExecEnv *exec_env, void *retval) /* App exit the thread, free the resources before exit native thread */ /* Free aux stack space */ - free_aux_stack(cluster, - exec_env->aux_stack_boundary + cluster->stack_size); + free_aux_stack(cluster, exec_env->aux_stack_bottom.bottom); /* Detach the native thread here to ensure the resources are freed */ wasm_cluster_detach_thread(exec_env); /* Remove and destroy exec_env */ diff --git a/wamr-compiler/main.c b/wamr-compiler/main.c index fd041d817..f552e9b2d 100644 --- a/wamr-compiler/main.c +++ b/wamr-compiler/main.c @@ -47,6 +47,7 @@ print_help() printf(" currently 128-bit SIMD is only supported for x86-64 target,\n"); printf(" and by default it is enabled in x86-64 target and disabled\n"); printf(" in other targets\n"); + printf(" --disable-aux-stack-check Disable auxiliary stack overflow/underflow check\n"); printf(" --enable-dump-call-stack Enable stack trace feature\n"); printf(" --enable-perf-profiling Enable function performance profiling\n"); printf(" -v=n Set log verbose level (0 to 5, default is 2), larger with more log\n"); @@ -77,6 +78,7 @@ main(int argc, char *argv[]) /* default value, enable or disable depends on the platform */ option.bounds_checks = 2; option.enable_simd = true; + option.enable_aux_stack_check = true; /* Process options. */ for (argc--, argv++; argc > 0 && argv[0][0] == '-'; argc--, argv++) { @@ -164,6 +166,9 @@ main(int argc, char *argv[]) else if (!strcmp(argv[0], "--disable-simd")) { option.enable_simd = false; } + else if (!strcmp(argv[0], "--disable-aux-stack-check")) { + option.enable_aux_stack_check = false; + } else if (!strcmp(argv[0], "--enable-dump-call-stack")) { option.enable_aux_stack_frame = true; } From dfe52ab42f8c371215d857e5be0e555dba3852bc Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Fri, 9 Apr 2021 14:55:58 +0800 Subject: [PATCH 178/207] Fix compile warnings on windows platform: dll linkage and others (#604) --- core/iwasm/aot/arch/aot_reloc_x86_64.c | 2 + core/iwasm/common/wasm_runtime_common.c | 4 +- core/iwasm/common/wasm_runtime_common.h | 84 +++++++++---------- core/iwasm/include/wasm_c_api.h | 8 +- core/iwasm/include/wasm_export.h | 2 +- .../shared/platform/include/platform_common.h | 11 ++- product-mini/platforms/windows/CMakeLists.txt | 3 +- product-mini/platforms/windows/main.c | 4 +- wamr-compiler/CMakeLists.txt | 1 + 9 files changed, 66 insertions(+), 53 deletions(-) diff --git a/core/iwasm/aot/arch/aot_reloc_x86_64.c b/core/iwasm/aot/arch/aot_reloc_x86_64.c index 41e678033..af090429d 100644 --- a/core/iwasm/aot/arch/aot_reloc_x86_64.c +++ b/core/iwasm/aot/arch/aot_reloc_x86_64.c @@ -12,11 +12,13 @@ #define R_X86_64_32 10 /* Direct 32 bit zero extended */ #define R_X86_64_32S 11 /* Direct 32 bit sign extended */ #else +#ifndef IMAGE_REL_AMD64_ADDR64 #define IMAGE_REL_AMD64_ADDR64 1 /* The 64-bit VA of the relocation target */ #define IMAGE_REL_AMD64_ADDR32 2 /* The 32-bit VA of the relocation target */ #define IMAGE_REL_AMD64_REL32 4 /* The 32-bit relative address from the byte following the relocation*/ #endif +#endif #if defined(BH_PLATFORM_WINDOWS) #pragma function (floor) diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index b6ce8eff9..97d939979 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -2325,7 +2325,7 @@ resolve_function(const WASMModuleInstanceCommon *module_inst, char *orig_name = NULL; char *sub_module_name = NULL; char *function_name = NULL; - uint32 length = strlen(name) + 1; + uint32 length = (uint32)(strlen(name) + 1); orig_name = runtime_malloc(sizeof(char) * length, NULL, NULL, 0); if (!orig_name) { @@ -3387,7 +3387,7 @@ fail: #endif #if defined(_WIN32) || defined(_WIN32_) -typedef union __declspec(intrin_type) __declspec(align(1)) v128 { +typedef union __declspec(intrin_type) __declspec(align(8)) v128 { __int8 m128i_i8[16]; __int16 m128i_i16[8]; __int32 m128i_i32[4]; diff --git a/core/iwasm/common/wasm_runtime_common.h b/core/iwasm/common/wasm_runtime_common.h index 06c8bfc8f..d61df2751 100644 --- a/core/iwasm/common/wasm_runtime_common.h +++ b/core/iwasm/common/wasm_runtime_common.h @@ -337,34 +337,34 @@ typedef package_type_t PackageType; typedef wasm_section_t WASMSection, AOTSection; /* See wasm_export.h for description */ -bool +WASM_RUNTIME_API_EXTERN bool wasm_runtime_init(void); /* See wasm_export.h for description */ -bool +WASM_RUNTIME_API_EXTERN bool wasm_runtime_full_init(RuntimeInitArgs *init_args); /* See wasm_export.h for description */ -void +WASM_RUNTIME_API_EXTERN void wasm_runtime_destroy(void); /* See wasm_export.h for description */ -PackageType +WASM_RUNTIME_API_EXTERN PackageType get_package_type(const uint8 *buf, uint32 size); /* See wasm_export.h for description */ -WASMModuleCommon * +WASM_RUNTIME_API_EXTERN WASMModuleCommon * wasm_runtime_load(const uint8 *buf, uint32 size, char *error_buf, uint32 error_buf_size); /* See wasm_export.h for description */ -WASMModuleCommon * +WASM_RUNTIME_API_EXTERN WASMModuleCommon * wasm_runtime_load_from_sections(WASMSection *section_list, bool is_aot, char *error_buf, uint32 error_buf_size); /* See wasm_export.h for description */ -void +WASM_RUNTIME_API_EXTERN void wasm_runtime_unload(WASMModuleCommon *module); /* Internal API */ @@ -379,58 +379,58 @@ wasm_runtime_deinstantiate_internal(WASMModuleInstanceCommon *module_inst, bool is_sub_inst); /* See wasm_export.h for description */ -WASMModuleInstanceCommon * +WASM_RUNTIME_API_EXTERN WASMModuleInstanceCommon * wasm_runtime_instantiate(WASMModuleCommon *module, uint32 stack_size, uint32 heap_size, char *error_buf, uint32 error_buf_size); /* See wasm_export.h for description */ -void +WASM_RUNTIME_API_EXTERN void wasm_runtime_deinstantiate(WASMModuleInstanceCommon *module_inst); /* See wasm_export.h for description */ -WASMFunctionInstanceCommon * +WASM_RUNTIME_API_EXTERN WASMFunctionInstanceCommon * wasm_runtime_lookup_function(WASMModuleInstanceCommon * const module_inst, const char *name, const char *signature); /* See wasm_export.h for description */ -WASMExecEnv * +WASM_RUNTIME_API_EXTERN WASMExecEnv * wasm_runtime_create_exec_env(WASMModuleInstanceCommon *module_inst, uint32 stack_size); /* See wasm_export.h for description */ -void +WASM_RUNTIME_API_EXTERN void wasm_runtime_destroy_exec_env(WASMExecEnv *exec_env); /* See wasm_export.h for description */ -WASMModuleInstanceCommon * +WASM_RUNTIME_API_EXTERN WASMModuleInstanceCommon * wasm_runtime_get_module_inst(WASMExecEnv *exec_env); /* See wasm_export.h for description */ -void * +WASM_RUNTIME_API_EXTERN void * wasm_runtime_get_function_attachment(WASMExecEnv *exec_env); /* See wasm_export.h for description */ -void +WASM_RUNTIME_API_EXTERN void wasm_runtime_set_user_data(WASMExecEnv *exec_env, void *user_data); /* See wasm_export.h for description */ -void * +WASM_RUNTIME_API_EXTERN void * wasm_runtime_get_user_data(WASMExecEnv *exec_env); /* See wasm_export.h for description */ -bool +WASM_RUNTIME_API_EXTERN bool wasm_runtime_call_wasm(WASMExecEnv *exec_env, WASMFunctionInstanceCommon *function, uint32 argc, uint32 argv[]); -bool +WASM_RUNTIME_API_EXTERN bool wasm_runtime_call_wasm_a(WASMExecEnv *exec_env, WASMFunctionInstanceCommon *function, uint32 num_results, wasm_val_t *results, uint32 num_args, wasm_val_t *args); -bool +WASM_RUNTIME_API_EXTERN bool wasm_runtime_call_wasm_v(WASMExecEnv *exec_env, WASMFunctionInstanceCommon *function, uint32 num_results, wasm_val_t *results, @@ -464,85 +464,85 @@ wasm_runtime_create_exec_env_and_call_wasm(WASMModuleInstanceCommon *module_inst uint32 argc, uint32 argv[]); /* See wasm_export.h for description */ -bool +WASM_RUNTIME_API_EXTERN bool wasm_application_execute_main(WASMModuleInstanceCommon *module_inst, int32 argc, char *argv[]); /* See wasm_export.h for description */ -bool +WASM_RUNTIME_API_EXTERN bool wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, const char *name, int32 argc, char *argv[]); /* See wasm_export.h for description */ -void +WASM_RUNTIME_API_EXTERN void wasm_runtime_set_exception(WASMModuleInstanceCommon *module, const char *exception); /* See wasm_export.h for description */ -const char * +WASM_RUNTIME_API_EXTERN const char * wasm_runtime_get_exception(WASMModuleInstanceCommon *module); /* See wasm_export.h for description */ -void +WASM_RUNTIME_API_EXTERN void wasm_runtime_clear_exception(WASMModuleInstanceCommon *module_inst); /* See wasm_export.h for description */ -void +WASM_RUNTIME_API_EXTERN void wasm_runtime_set_custom_data(WASMModuleInstanceCommon *module_inst, void *custom_data); /* See wasm_export.h for description */ -void * +WASM_RUNTIME_API_EXTERN void * wasm_runtime_get_custom_data(WASMModuleInstanceCommon *module_inst); /* See wasm_export.h for description */ -uint32 +WASM_RUNTIME_API_EXTERN uint32 wasm_runtime_module_malloc(WASMModuleInstanceCommon *module_inst, uint32 size, void **p_native_addr); /* See wasm_export.h for description */ -void +WASM_RUNTIME_API_EXTERN void wasm_runtime_module_free(WASMModuleInstanceCommon *module_inst, uint32 ptr); /* See wasm_export.h for description */ -uint32 +WASM_RUNTIME_API_EXTERN uint32 wasm_runtime_module_dup_data(WASMModuleInstanceCommon *module_inst, const char *src, uint32 size); /* See wasm_export.h for description */ -bool +WASM_RUNTIME_API_EXTERN bool wasm_runtime_validate_app_addr(WASMModuleInstanceCommon *module_inst, uint32 app_offset, uint32 size); /* See wasm_export.h for description */ -bool +WASM_RUNTIME_API_EXTERN bool wasm_runtime_validate_app_str_addr(WASMModuleInstanceCommon *module_inst, uint32 app_str_offset); /* See wasm_export.h for description */ -bool +WASM_RUNTIME_API_EXTERN bool wasm_runtime_validate_native_addr(WASMModuleInstanceCommon *module_inst, void *native_ptr, uint32 size); /* See wasm_export.h for description */ -void * +WASM_RUNTIME_API_EXTERN void * wasm_runtime_addr_app_to_native(WASMModuleInstanceCommon *module_inst, uint32 app_offset); /* See wasm_export.h for description */ -uint32 +WASM_RUNTIME_API_EXTERN uint32 wasm_runtime_addr_native_to_app(WASMModuleInstanceCommon *module_inst, void *native_ptr); /* See wasm_export.h for description */ -bool +WASM_RUNTIME_API_EXTERN bool wasm_runtime_get_app_addr_range(WASMModuleInstanceCommon *module_inst, uint32 app_offset, uint32 *p_app_start_offset, uint32 *p_app_end_offset); /* See wasm_export.h for description */ -bool +WASM_RUNTIME_API_EXTERN bool wasm_runtime_get_native_addr_range(WASMModuleInstanceCommon *module_inst, uint8 *native_ptr, uint8 **p_native_start_addr, @@ -563,7 +563,7 @@ wasm_runtime_set_llvm_stack(WASMModuleInstanceCommon *module_inst, uint32 llvm_stack); #if WASM_ENABLE_MULTI_MODULE != 0 -void +WASM_RUNTIME_API_EXTERN void wasm_runtime_set_module_reader(const module_reader reader, const module_destroyer destroyer); @@ -616,7 +616,7 @@ wasm_exec_env_set_aux_stack(WASMExecEnv *exec_env, #if WASM_ENABLE_LIBC_WASI != 0 /* See wasm_export.h for description */ -void +WASM_RUNTIME_API_EXTERN void wasm_runtime_set_wasi_args(WASMModuleCommon *module, const char *dir_list[], uint32 dir_count, const char *map_dir_list[], uint32 map_dir_count, @@ -624,11 +624,11 @@ wasm_runtime_set_wasi_args(WASMModuleCommon *module, char *argv[], int argc); /* See wasm_export.h for description */ -bool +WASM_RUNTIME_API_EXTERN bool wasm_runtime_is_wasi_mode(WASMModuleInstanceCommon *module_inst); /* See wasm_export.h for description */ -WASMFunctionInstanceCommon * +WASM_RUNTIME_API_EXTERN WASMFunctionInstanceCommon * wasm_runtime_lookup_wasi_start_function(WASMModuleInstanceCommon *module_inst); bool @@ -666,13 +666,13 @@ bool wasm_runtime_enlarge_memory(WASMModuleInstanceCommon *module, uint32 inc_page_count); /* See wasm_export.h for description */ -bool +WASM_RUNTIME_API_EXTERN bool wasm_runtime_register_natives(const char *module_name, NativeSymbol *native_symbols, uint32 n_native_symbols); /* See wasm_export.h for description */ -bool +WASM_RUNTIME_API_EXTERN bool wasm_runtime_register_natives_raw(const char *module_name, NativeSymbol *native_symbols, uint32 n_native_symbols); diff --git a/core/iwasm/include/wasm_c_api.h b/core/iwasm/include/wasm_c_api.h index fdc072327..6f1a9c519 100644 --- a/core/iwasm/include/wasm_c_api.h +++ b/core/iwasm/include/wasm_c_api.h @@ -10,8 +10,12 @@ #include #ifndef WASM_API_EXTERN -#ifdef _WIN32 -#define WASM_API_EXTERN __declspec(dllimport) +#if defined(_MSC_BUILD) + #if defined(COMPILING_WASM_RUNTIME_API) + #define WASM_API_EXTERN __declspec(dllexport) + #else + #define WASM_API_EXTERN __declspec(dllimport) + #endif #else #define WASM_API_EXTERN #endif diff --git a/core/iwasm/include/wasm_export.h b/core/iwasm/include/wasm_export.h index 768ee36ea..137692911 100644 --- a/core/iwasm/include/wasm_export.h +++ b/core/iwasm/include/wasm_export.h @@ -12,7 +12,7 @@ #ifndef WASM_RUNTIME_API_EXTERN -#if defined(MSVC) +#if defined(_MSC_BUILD ) #if defined(COMPILING_WASM_RUNTIME_API) #define WASM_RUNTIME_API_EXTERN __declspec(dllexport) #else diff --git a/core/shared/platform/include/platform_common.h b/core/shared/platform/include/platform_common.h index ca2780206..9cd5c2d8e 100644 --- a/core/shared/platform/include/platform_common.h +++ b/core/shared/platform/include/platform_common.h @@ -33,9 +33,14 @@ extern "C" { #define BH_FREE os_free #endif -#if defined(MSVC) -__declspec(dllimport) void *BH_MALLOC(unsigned int size); -__declspec(dllimport) void BH_FREE(void *ptr); +#if defined(_MSC_BUILD) +#if defined(COMPILING_WASM_RUNTIME_API) +__declspec(dllexport) void *BH_MALLOC(unsigned int size); +__declspec(dllexport) void BH_FREE(void *ptr); +#else +__declspec(dllimport) void* BH_MALLOC(unsigned int size); +__declspec(dllimport) void BH_FREE(void* ptr); +#endif #else void *BH_MALLOC(unsigned int size); void BH_FREE(void *ptr); diff --git a/product-mini/platforms/windows/CMakeLists.txt b/product-mini/platforms/windows/CMakeLists.txt index 04d505d6c..377297a34 100644 --- a/product-mini/platforms/windows/CMakeLists.txt +++ b/product-mini/platforms/windows/CMakeLists.txt @@ -15,6 +15,8 @@ set (CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") set (CMAKE_C_STANDARD 99) +add_definitions(-DCOMPILING_WASM_RUNTIME_API=1) + # Set WAMR_BUILD_TARGET, currently values supported: # "X86_64", "AMD_64", "X86_32", "AARCH64[sub]", "ARM[sub]", "THUMB[sub]", "MIPS", "XTENSA" if (NOT DEFINED WAMR_BUILD_TARGET) @@ -126,4 +128,3 @@ set_target_properties (libiwasm PROPERTIES OUTPUT_NAME iwasm) target_link_libraries (libiwasm ${LLVM_AVAILABLE_LIBS} ${UV_A_LIBS}) -target_compile_definitions(libiwasm PRIVATE COMPILING_WASM_RUNTIME_API=1) diff --git a/product-mini/platforms/windows/main.c b/product-mini/platforms/windows/main.c index c9ad6821c..1e857283d 100644 --- a/product-mini/platforms/windows/main.c +++ b/product-mini/platforms/windows/main.c @@ -185,8 +185,8 @@ module_reader_callback(const char *module_name, uint8 **p_buffer, uint32 *p_size) { const char *format = "%s/%s.wasm"; - int sz = strlen(module_search_path) + strlen("/") + strlen(module_name) + - strlen(".wasm") + 1; + uint32 sz = (uint32)(strlen(module_search_path) + strlen("/") + + strlen(module_name) + strlen(".wasm") + 1); char *wasm_file_name = BH_MALLOC(sz); if (!wasm_file_name) { return false; diff --git a/wamr-compiler/CMakeLists.txt b/wamr-compiler/CMakeLists.txt index 4d81b09cc..e47ce833d 100644 --- a/wamr-compiler/CMakeLists.txt +++ b/wamr-compiler/CMakeLists.txt @@ -10,6 +10,7 @@ if (NOT WAMR_BUILD_PLATFORM STREQUAL "windows") else() project (aot-compiler C ASM CXX) enable_language (ASM_MASM) + add_definitions(-DCOMPILING_WASM_RUNTIME_API=1) endif() set (CMAKE_CXX_STANDARD 14) From 09eb858a0227715a63eb677050ee088849462d18 Mon Sep 17 00:00:00 2001 From: Xu Jun <693788454@qq.com> Date: Fri, 9 Apr 2021 15:27:12 +0800 Subject: [PATCH 179/207] add realloc wrapper, fix pthread_join overwrite issue (#605) --- core/iwasm/aot/aot_runtime.c | 37 +++++++++++++++++++ core/iwasm/aot/aot_runtime.h | 4 ++ core/iwasm/common/wasm_runtime_common.c | 17 +++++++++ core/iwasm/interpreter/wasm_runtime.c | 35 ++++++++++++++++++ core/iwasm/interpreter/wasm_runtime.h | 4 ++ .../lib-pthread/lib_pthread_wrapper.c | 2 +- .../libc-builtin/libc_builtin_wrapper.c | 13 +++++++ doc/pthread_library.md | 2 +- .../share/defined-symbols.txt | 1 + 9 files changed, 113 insertions(+), 2 deletions(-) diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index 50b224351..74a710324 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -1553,6 +1553,43 @@ aot_module_malloc(AOTModuleInstance *module_inst, uint32 size, return (uint32)(addr - (uint8*)memory_inst->memory_data.ptr); } +uint32 +aot_module_realloc(AOTModuleInstance *module_inst, uint32 ptr, + uint32 size, void **p_native_addr) +{ + AOTMemoryInstance *memory_inst = aot_get_default_memory(module_inst); + uint8 *addr = NULL; + + if (!memory_inst) { + aot_set_exception(module_inst, "uninitialized memory"); + return 0; + } + + if (memory_inst->heap_handle.ptr) { + addr = + mem_allocator_realloc(memory_inst->heap_handle.ptr, + (uint8*)memory_inst->memory_data.ptr + ptr, + size); + } + + /* Only support realloc in WAMR's app heap */ + + if (!addr) { + if (memory_inst->heap_handle.ptr + && mem_allocator_is_heap_corrupted(memory_inst->heap_handle.ptr)) { + aot_set_exception(module_inst, "app heap corrupted"); + } + else { + aot_set_exception(module_inst, "out of memory"); + } + return 0; + } + + if (p_native_addr) + *p_native_addr = addr; + return (uint32)(addr - (uint8*)memory_inst->memory_data.ptr); +} + void aot_module_free(AOTModuleInstance *module_inst, uint32 ptr) { diff --git a/core/iwasm/aot/aot_runtime.h b/core/iwasm/aot/aot_runtime.h index 4c461d65e..990523934 100644 --- a/core/iwasm/aot/aot_runtime.h +++ b/core/iwasm/aot/aot_runtime.h @@ -498,6 +498,10 @@ uint32 aot_module_malloc(AOTModuleInstance *module_inst, uint32 size, void **p_native_addr); +uint32 +aot_module_realloc(AOTModuleInstance *module_inst, uint32 ptr, + uint32 size, void **p_native_addr); + void aot_module_free(AOTModuleInstance *module_inst, uint32 ptr); diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index 97d939979..aad71e1a7 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -1378,6 +1378,23 @@ wasm_runtime_module_malloc(WASMModuleInstanceCommon *module_inst, uint32 size, return 0; } +uint32 +wasm_runtime_module_realloc(WASMModuleInstanceCommon *module_inst, uint32 ptr, + uint32 size, void **p_native_addr) +{ +#if WASM_ENABLE_INTERP != 0 + if (module_inst->module_type == Wasm_Module_Bytecode) + return wasm_module_realloc((WASMModuleInstance*)module_inst, ptr, + size, p_native_addr); +#endif +#if WASM_ENABLE_AOT != 0 + if (module_inst->module_type == Wasm_Module_AoT) + return aot_module_realloc((AOTModuleInstance*)module_inst, ptr, + size, p_native_addr); +#endif + return 0; +} + void wasm_runtime_module_free(WASMModuleInstanceCommon *module_inst, uint32 ptr) { diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index d32ac9950..360958cb0 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -1741,6 +1741,41 @@ wasm_module_malloc(WASMModuleInstance *module_inst, uint32 size, return (uint32)(addr - memory->memory_data); } +uint32 +wasm_module_realloc(WASMModuleInstance *module_inst, uint32 ptr, uint32 size, + void **p_native_addr) +{ + WASMMemoryInstance *memory = module_inst->default_memory; + uint8 *addr = NULL; + + if (!memory) { + wasm_set_exception(module_inst, "uninitialized memory"); + return 0; + } + + if (memory->heap_handle) { + addr = mem_allocator_realloc(memory->heap_handle, + memory->memory_data + ptr, size); + } + + /* Only support realloc in WAMR's app heap */ + + if (!addr) { + if (memory->heap_handle + && mem_allocator_is_heap_corrupted(memory->heap_handle)) { + wasm_set_exception(module_inst, "app heap corrupted"); + } + else { + wasm_set_exception(module_inst, "out of memory"); + } + return 0; + } + if (p_native_addr) + *p_native_addr = addr; + + return (uint32)(addr - memory->memory_data); +} + void wasm_module_free(WASMModuleInstance *module_inst, uint32 ptr) { diff --git a/core/iwasm/interpreter/wasm_runtime.h b/core/iwasm/interpreter/wasm_runtime.h index ccde47e49..3d7d47c6e 100644 --- a/core/iwasm/interpreter/wasm_runtime.h +++ b/core/iwasm/interpreter/wasm_runtime.h @@ -328,6 +328,10 @@ uint32 wasm_module_malloc(WASMModuleInstance *module_inst, uint32 size, void **p_native_addr); +uint32 +wasm_module_realloc(WASMModuleInstance *module_inst, uint32 ptr, uint32 size, + void **p_native_addr); + void wasm_module_free(WASMModuleInstance *module_inst, uint32 ptr); diff --git a/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c b/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c index 0930a9785..0dd1faa9a 100644 --- a/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c +++ b/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c @@ -648,7 +648,7 @@ pthread_join_wrapper(wasm_exec_env_t exec_env, uint32 thread, } if (retval_offset != 0) - *retval = (void*)ret; + *(uint32*)retval = (uint32)(uintptr_t)ret; return join_ret; } diff --git a/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c b/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c index 195c55ad3..b2701bcc8 100644 --- a/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c +++ b/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c @@ -28,6 +28,10 @@ wasm_runtime_get_llvm_stack(wasm_module_inst_t module); void wasm_runtime_set_llvm_stack(wasm_module_inst_t module, uint32 llvm_stack); +uint32 +wasm_runtime_module_realloc(wasm_module_inst_t module, uint32 ptr, + uint32 size, void **p_native_addr); + #define get_module_inst(exec_env) \ wasm_runtime_get_module_inst(exec_env) @@ -704,6 +708,14 @@ calloc_wrapper(wasm_exec_env_t exec_env, uint32 nmemb, uint32 size) return ret_offset; } +static uint32 +realloc_wrapper(wasm_exec_env_t exec_env, uint32 ptr, uint32 new_size) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + + return wasm_runtime_module_realloc(module_inst, ptr, new_size, NULL); +} + static void free_wrapper(wasm_exec_env_t exec_env, void *ptr) { @@ -1092,6 +1104,7 @@ static NativeSymbol native_symbols_libc_builtin[] = { REG_NATIVE_FUNC(strncmp, "(**~)i"), REG_NATIVE_FUNC(strncpy, "(**~)i"), REG_NATIVE_FUNC(malloc, "(i)i"), + REG_NATIVE_FUNC(realloc, "(ii)i"), REG_NATIVE_FUNC(calloc, "(ii)i"), REG_NATIVE_FUNC(strdup, "($)i"), /* clang may introduce __strdup */ diff --git a/doc/pthread_library.md b/doc/pthread_library.md index 927300c56..882bb59de 100644 --- a/doc/pthread_library.md +++ b/doc/pthread_library.md @@ -57,7 +57,7 @@ To build this C program into WebAssembly app with libc-builtin, you can use this You can also build this program with WASI, but we need to make some changes to wasi-sysroot: -1. disable malloc/free of wasi if the wasi-sdk version is smaller than wasi-sdk-12.0 (not include 12.0), as they don't support shared memory: +1. disable malloc/free of wasi, as they are not atomic operations: ``` bash /opt/wasi-sdk/bin/llvm-ar -d /opt/wasi-sdk/share/wasi-sysroot/lib/wasm32-wasi/libc.a dlmalloc.o ``` diff --git a/wamr-sdk/app/libc-builtin-sysroot/share/defined-symbols.txt b/wamr-sdk/app/libc-builtin-sysroot/share/defined-symbols.txt index 08a378462..332aedb7d 100644 --- a/wamr-sdk/app/libc-builtin-sysroot/share/defined-symbols.txt +++ b/wamr-sdk/app/libc-builtin-sysroot/share/defined-symbols.txt @@ -40,6 +40,7 @@ strncmp strncpy malloc calloc +realloc strdup free atoi From ee97618bdb1ac5b54f6423a921a4741e1a9e4358 Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Fri, 9 Apr 2021 17:24:01 +0800 Subject: [PATCH 180/207] Fix llvm target vendor-sys-abi not correctly set issue on windows platform (#606) --- core/iwasm/compilation/aot_llvm.c | 32 +++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/core/iwasm/compilation/aot_llvm.c b/core/iwasm/compilation/aot_llvm.c index 9651ef95e..418ded3db 100644 --- a/core/iwasm/compilation/aot_llvm.c +++ b/core/iwasm/compilation/aot_llvm.c @@ -1107,7 +1107,8 @@ static ArchItem valid_archs[] = { static const char *valid_abis[] = { "gnu", "eabi", - "gnueabihf" + "gnueabihf", + "msvc" }; static void @@ -1335,9 +1336,32 @@ aot_create_comp_context(AOTCompData *comp_data, if (arch) { /* Construct target triple: --- */ - const char *vendor_sys = "-pc-linux-"; - if (!abi) - abi = "gnu"; + const char *vendor_sys; + char *default_triple = LLVMGetDefaultTargetTriple(); + + if (!default_triple) { + aot_set_last_error("llvm get default target triple failed."); + goto fail; + } + + if (strstr(default_triple, "windows")) { + vendor_sys = "-pc-windows-"; + if (!abi) + abi = "msvc"; + } + else if (strstr(default_triple, "win32")) { + vendor_sys = "-pc-win32-"; + if (!abi) + abi = "msvc"; + } + else { + vendor_sys = "-pc-linux-"; + if (!abi) + abi = "gnu"; + } + + LLVMDisposeMessage(default_triple); + bh_assert(strlen(arch) + strlen(vendor_sys) + strlen(abi) < sizeof(triple_buf)); memcpy(triple_buf, arch, strlen(arch)); memcpy(triple_buf + strlen(arch), vendor_sys, strlen(vendor_sys)); From 8b96f4fb71bc31178d057bd7a643a07423bab7eb Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Tue, 13 Apr 2021 13:42:08 +0800 Subject: [PATCH 181/207] Update sample workload's scripts to align with latest emcc (#609) And enable auxiliary stack overflow/underflow check in JIT mode --- core/iwasm/aot/aot_loader.c | 1 + .../libraries/libc-emcc/libc_emcc_wrapper.c | 13 ++++++++++++ samples/workload/XNNPACK/CMakeLists.txt | 2 ++ .../toolchain/emscripten_toolchain_config.bzl | 13 ++++++++---- samples/workload/bwa/CMakeLists.txt | 20 +++++++++---------- samples/workload/tensorflow/build.sh | 2 +- samples/workload/wasm-av1/CMakeLists.txt | 14 ++++++------- samples/workload/wasm-av1/build.sh | 2 +- 8 files changed, 44 insertions(+), 23 deletions(-) diff --git a/core/iwasm/aot/aot_loader.c b/core/iwasm/aot/aot_loader.c index 5c4b7e1ac..e59937cf1 100644 --- a/core/iwasm/aot/aot_loader.c +++ b/core/iwasm/aot/aot_loader.c @@ -2458,6 +2458,7 @@ aot_convert_wasm_module(WASMModule *wasm_module, #if WASM_ENABLE_SIMD != 0 option.enable_simd = true; #endif + option.enable_aux_stack_check = true; #if (WASM_ENABLE_PERF_PROFILING != 0) || (WASM_ENABLE_DUMP_CALL_STACK != 0) option.enable_aux_stack_frame = true; #endif diff --git a/core/iwasm/libraries/libc-emcc/libc_emcc_wrapper.c b/core/iwasm/libraries/libc-emcc/libc_emcc_wrapper.c index 0f9a35645..545bfe6a5 100644 --- a/core/iwasm/libraries/libc-emcc/libc_emcc_wrapper.c +++ b/core/iwasm/libraries/libc-emcc/libc_emcc_wrapper.c @@ -508,6 +508,18 @@ emscripten_notify_memory_growth_wrapper(wasm_exec_env_t exec_env, int i) (void)i; } +static void +emscripten_thread_sleep_wrapper(wasm_exec_env_t exec_env, double timeout_ms) +{ + uint64 ms = (uint64)timeout_ms; + uint64 sec = ms / 1000, us = (ms % 1000) * 1000; + + if (sec > 0) + sleep(sec); + if (us > 0) + usleep(us); +} + #endif /* end of BH_PLATFORM_LINUX_SGX */ #define REG_NATIVE_FUNC(func_name, signature) \ @@ -543,6 +555,7 @@ static NativeSymbol native_symbols_libc_emcc[] = { REG_NATIVE_FUNC(__sys_getcwd, "(*~)i"), REG_NATIVE_FUNC(__sys_uname, "(*)i"), REG_NATIVE_FUNC(emscripten_notify_memory_growth, "(i)"), + REG_NATIVE_FUNC(emscripten_thread_sleep, "(F)"), #endif /* end of BH_PLATFORM_LINUX_SGX */ }; diff --git a/samples/workload/XNNPACK/CMakeLists.txt b/samples/workload/XNNPACK/CMakeLists.txt index 044230012..86a784cbb 100644 --- a/samples/workload/XNNPACK/CMakeLists.txt +++ b/samples/workload/XNNPACK/CMakeLists.txt @@ -26,6 +26,8 @@ ExternalProject_Add(xnnpack UPDATE_COMMAND git checkout .bazelrc BUILD.bazel emscripten.bzl && git apply ${CMAKE_CURRENT_SOURCE_DIR}/xnnpack.patch && cmake -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/toolchain ${CMAKE_CURRENT_SOURCE_DIR}/xnnpack/toolchain + # replace string "$ENV{HOME}" with actual home directory + && sed -i "s|\$ENV{HOME}|$ENV{HOME}|g" ${CMAKE_CURRENT_SOURCE_DIR}/xnnpack/toolchain/emscripten_toolchain_config.bzl CONFIGURE_COMMAND "" BUILD_COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR}/xnnpack && bazel build -c opt --sandbox_writable_path=$ENV{HOME} --config=emscripten_wasm diff --git a/samples/workload/XNNPACK/toolchain/emscripten_toolchain_config.bzl b/samples/workload/XNNPACK/toolchain/emscripten_toolchain_config.bzl index b90a7abab..d3e440590 100644 --- a/samples/workload/XNNPACK/toolchain/emscripten_toolchain_config.bzl +++ b/samples/workload/XNNPACK/toolchain/emscripten_toolchain_config.bzl @@ -100,6 +100,8 @@ def _impl(ctx): "STANDALONE_WASM=1", "-Wl,--export=__heap_base", "-Wl,--export=__data_end", + "-Wl,--export=malloc", + "-Wl,--export=free", ], ), ]), @@ -112,12 +114,15 @@ def _impl(ctx): ctx = ctx, features = features, # NEW cxx_builtin_include_directories = [ - "/opt/emsdk/upstream/emscripten/system/include/libcxx", - "/opt/emsdk/upstream/emscripten/system/lib/libcxxabi/include", "/opt/emsdk/upstream/emscripten/system/include", - "/opt/emsdk/upstream/emscripten/system/include/libc", + "/opt/emsdk/upstream/emscripten/system/lib/libc/include", + "/opt/emsdk/upstream/emscripten/system/lib/libcxx/include", + "/opt/emsdk/upstream/emscripten/system/lib/libcxxabi/include", "/opt/emsdk/upstream/emscripten/system/lib/libc/musl/arch/emscripten", - "/opt/emsdk/upstream/lib/clang/12.0.0/include/", + "/opt/emsdk/upstream/emscripten/system/include/compat", + "/opt/emsdk/upstream/emscripten/cache/sysroot/include", + "/opt/emsdk/upstream/lib/clang/13.0.0/include", + "$ENV{HOME}/.emscripten_cache/sysroot/include", ], toolchain_identifier = "wasm-emsdk", host_system_name = "i686-unknown-linux-gnu", diff --git a/samples/workload/bwa/CMakeLists.txt b/samples/workload/bwa/CMakeLists.txt index 0ea2c2947..489c3e7d6 100644 --- a/samples/workload/bwa/CMakeLists.txt +++ b/samples/workload/bwa/CMakeLists.txt @@ -68,28 +68,28 @@ include(ExternalProject) ################ HEADERS ################ ExternalProject_Add(headers_from_emcc PREFIX headers - SOURCE_DIR "$ENV{EMSDK}/upstream/emscripten/system/include/SSE" + SOURCE_DIR "$ENV{EM_CACHE}/sysroot/include" CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND mkdir -p ${CMAKE_CURRENT_SOURCE_DIR}/include/SSE && ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_SOURCE_DIR}/include/pthread/sys && ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_SOURCE_DIR}/include/emscripten # copy emscripten SSE header files - && ${CMAKE_COMMAND} -E copy $ENV{EMSDK}/upstream/emscripten/system/include/SSE/immintrin.h ${CMAKE_CURRENT_SOURCE_DIR}/include/SSE/ + && ${CMAKE_COMMAND} -E copy $ENV{EM_CACHE}/sysroot/include/compat/immintrin.h ${CMAKE_CURRENT_SOURCE_DIR}/include/SSE/ # SSE - && ${CMAKE_COMMAND} -E copy $ENV{EMSDK}/upstream/emscripten/system/include/SSE/xmmintrin.h ${CMAKE_CURRENT_SOURCE_DIR}/include/SSE/ + && ${CMAKE_COMMAND} -E copy $ENV{EM_CACHE}/sysroot/include/compat/xmmintrin.h ${CMAKE_CURRENT_SOURCE_DIR}/include/SSE/ # SSE2 - && ${CMAKE_COMMAND} -E copy $ENV{EMSDK}/upstream/emscripten/system/include/SSE/emmintrin.h ${CMAKE_CURRENT_SOURCE_DIR}/include/SSE/ + && ${CMAKE_COMMAND} -E copy $ENV{EM_CACHE}/sysroot/include/compat/emmintrin.h ${CMAKE_CURRENT_SOURCE_DIR}/include/SSE/ # SSE4.1 - && ${CMAKE_COMMAND} -E copy $ENV{EMSDK}/upstream/emscripten/system/include/SSE/smmintrin.h ${CMAKE_CURRENT_SOURCE_DIR}/include/SSE/ + && ${CMAKE_COMMAND} -E copy $ENV{EM_CACHE}/sysroot/include/compat/smmintrin.h ${CMAKE_CURRENT_SOURCE_DIR}/include/SSE/ # a fake empty header to aovid further depenency && ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_SOURCE_DIR}/include/emscripten/emscripten.h # copy emscripten pthread related header files - && ${CMAKE_COMMAND} -E copy $ENV{EMSDK}/upstream/emscripten/system/include/libc/pthread.h ${CMAKE_CURRENT_SOURCE_DIR}/include/pthread/ - && ${CMAKE_COMMAND} -E copy $ENV{EMSDK}/upstream/emscripten/system/include/libc/signal.h ${CMAKE_CURRENT_SOURCE_DIR}/include/pthread/ - && ${CMAKE_COMMAND} -E copy $ENV{EMSDK}/upstream/emscripten/system/include/libc/netdb.h ${CMAKE_CURRENT_SOURCE_DIR}/include/pthread/ - && ${CMAKE_COMMAND} -E copy $ENV{EMSDK}/upstream/emscripten/system/include/libc/sys/wait.h ${CMAKE_CURRENT_SOURCE_DIR}/include/pthread/sys/ - && ${CMAKE_COMMAND} -E copy $ENV{EMSDK}/upstream/emscripten/system/include/libc/sys/socket.h ${CMAKE_CURRENT_SOURCE_DIR}/include/pthread/sys/ + && ${CMAKE_COMMAND} -E copy $ENV{EM_CACHE}/sysroot/include/pthread.h ${CMAKE_CURRENT_SOURCE_DIR}/include/pthread/ + && ${CMAKE_COMMAND} -E copy $ENV{EM_CACHE}/sysroot/include/signal.h ${CMAKE_CURRENT_SOURCE_DIR}/include/pthread/ + && ${CMAKE_COMMAND} -E copy $ENV{EM_CACHE}/sysroot/include/netdb.h ${CMAKE_CURRENT_SOURCE_DIR}/include/pthread/ + && ${CMAKE_COMMAND} -E copy $ENV{EM_CACHE}/sysroot/include/sys/wait.h ${CMAKE_CURRENT_SOURCE_DIR}/include/pthread/sys/ + && ${CMAKE_COMMAND} -E copy $ENV{EM_CACHE}/sysroot/include/sys/socket.h ${CMAKE_CURRENT_SOURCE_DIR}/include/pthread/sys/ ) ################ libz ################ diff --git a/samples/workload/tensorflow/build.sh b/samples/workload/tensorflow/build.sh index f3c10be33..80d2540d5 100755 --- a/samples/workload/tensorflow/build.sh +++ b/samples/workload/tensorflow/build.sh @@ -17,7 +17,7 @@ fi set -xe -EMSDK_WASM_DIR="$EM_CACHE/wasm" +EMSDK_WASM_DIR="$EM_CACHE/sysroot/lib/wasm32-emscripten" BUILD_SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" OUT_DIR="${BUILD_SCRIPT_DIR}/out" TENSORFLOW_DIR="${BUILD_SCRIPT_DIR}/tensorflow" diff --git a/samples/workload/wasm-av1/CMakeLists.txt b/samples/workload/wasm-av1/CMakeLists.txt index 873af6071..0dd57d905 100644 --- a/samples/workload/wasm-av1/CMakeLists.txt +++ b/samples/workload/wasm-av1/CMakeLists.txt @@ -58,19 +58,19 @@ include(ExternalProject) ################ HEADERS ################ ExternalProject_Add(headers_from_emcc PREFIX headers - SOURCE_DIR "$ENV{EMSDK}/upstream/emscripten/system/" + SOURCE_DIR "$ENV{EM_CACHE}/sysroot/include" CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_SOURCE_DIR}/include/pthread/sys && ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_SOURCE_DIR}/include/libc/bits # copy emscripten pthread related header files - && ${CMAKE_COMMAND} -E copy $ENV{EMSDK}/upstream/emscripten/system/include/libc/pthread.h ${CMAKE_CURRENT_SOURCE_DIR}/include/pthread/ - && ${CMAKE_COMMAND} -E copy $ENV{EMSDK}/upstream/emscripten/system/include/libc/signal.h ${CMAKE_CURRENT_SOURCE_DIR}/include/pthread/ - && ${CMAKE_COMMAND} -E copy $ENV{EMSDK}/upstream/emscripten/system/include/libc/netdb.h ${CMAKE_CURRENT_SOURCE_DIR}/include/pthread/ - && ${CMAKE_COMMAND} -E copy $ENV{EMSDK}/upstream/emscripten/system/include/libc/sys/wait.h ${CMAKE_CURRENT_SOURCE_DIR}/include/pthread/sys/ - && ${CMAKE_COMMAND} -E copy $ENV{EMSDK}/upstream/emscripten/system/include/libc/sys/socket.h ${CMAKE_CURRENT_SOURCE_DIR}/include/pthread/sys/ + && ${CMAKE_COMMAND} -E copy $ENV{EM_CACHE}/sysroot/include/pthread.h ${CMAKE_CURRENT_SOURCE_DIR}/include/pthread/ + && ${CMAKE_COMMAND} -E copy $ENV{EM_CACHE}/sysroot/include/signal.h ${CMAKE_CURRENT_SOURCE_DIR}/include/pthread/ + && ${CMAKE_COMMAND} -E copy $ENV{EM_CACHE}/sysroot/include/netdb.h ${CMAKE_CURRENT_SOURCE_DIR}/include/pthread/ + && ${CMAKE_COMMAND} -E copy $ENV{EM_CACHE}/sysroot/include/sys/wait.h ${CMAKE_CURRENT_SOURCE_DIR}/include/pthread/sys/ + && ${CMAKE_COMMAND} -E copy $ENV{EM_CACHE}/sysroot/include/sys/socket.h ${CMAKE_CURRENT_SOURCE_DIR}/include/pthread/sys/ # copy emscripten setjmp headers - && ${CMAKE_COMMAND} -E copy $ENV{EMSDK}/upstream/emscripten/system/include/libc/setjmp.h ${CMAKE_CURRENT_SOURCE_DIR}/include/libc/setjmp.h + && ${CMAKE_COMMAND} -E copy $ENV{EM_CACHE}/sysroot/include/setjmp.h ${CMAKE_CURRENT_SOURCE_DIR}/include/libc/setjmp.h && ${CMAKE_COMMAND} -E copy $ENV{EMSDK}/upstream/emscripten/system/lib/libc/musl/arch/emscripten/bits/setjmp.h ${CMAKE_CURRENT_SOURCE_DIR}/include/libc/bits/setjmp.h ) diff --git a/samples/workload/wasm-av1/build.sh b/samples/workload/wasm-av1/build.sh index 2d52b20d8..1ef9a3ab2 100755 --- a/samples/workload/wasm-av1/build.sh +++ b/samples/workload/wasm-av1/build.sh @@ -17,7 +17,7 @@ fi set -xe -EMSDK_WASM_DIR="$EM_CACHE/wasm" +EMSDK_WASM_DIR="$EM_CACHE/sysroot/lib/wasm32-emscripten" BUILD_SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" OUT_DIR="${BUILD_SCRIPT_DIR}/out" WASM_AV1_DIR="${BUILD_SCRIPT_DIR}/wasm-av1" From 46db3530172d0c6e6e151dd787a757f74cf92e59 Mon Sep 17 00:00:00 2001 From: Xiaokang Qin Date: Tue, 13 Apr 2021 14:45:51 +0800 Subject: [PATCH 182/207] Enable SIMD for AARCH64 Platform (#11) (#610) Signed-off-by: Wu Zhongmin Signed-off-by: Xiaokang Qin Co-authored-by: Wu Zhongmin Co-authored-by: Wu Zhongmin --- core/iwasm/aot/aot_loader.c | 2 +- .../common/arch/invokeNative_aarch64_simd.s | 79 ++++ core/iwasm/common/iwasm_common.cmake | 6 +- core/iwasm/common/wasm_runtime_common.c | 8 +- core/iwasm/compilation/aot_llvm.c | 3 +- .../compilation/simd/simd_access_lanes.c | 112 +++++- .../iwasm/compilation/simd/simd_conversions.c | 355 +++++++++++++++++- 7 files changed, 557 insertions(+), 8 deletions(-) create mode 100644 core/iwasm/common/arch/invokeNative_aarch64_simd.s diff --git a/core/iwasm/aot/aot_loader.c b/core/iwasm/aot/aot_loader.c index e59937cf1..fac0c4856 100644 --- a/core/iwasm/aot/aot_loader.c +++ b/core/iwasm/aot/aot_loader.c @@ -285,7 +285,7 @@ check_machine_info(AOTTargetInfo *target_info, error_buf, error_buf_size)) return false; - if (strcmp(target_expected, target_got)) { + if (strncmp(target_expected, target_got, strlen(target_expected))) { set_error_buf_v(error_buf, error_buf_size, "invalid target type, expected %s but got %s", target_expected, target_got); diff --git a/core/iwasm/common/arch/invokeNative_aarch64_simd.s b/core/iwasm/common/arch/invokeNative_aarch64_simd.s new file mode 100644 index 000000000..a6ccc1508 --- /dev/null +++ b/core/iwasm/common/arch/invokeNative_aarch64_simd.s @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2020 Intel Corporation Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + .text + .align 2 +#ifndef BH_PLATFORM_DARWIN + .globl invokeNative + .type invokeNative, function +invokeNative: +#else + .globl _invokeNative +_invokeNative: +#endif /* end of BH_PLATFORM_DARWIN */ + +/* + * Arguments passed in: + * + * x0 function ptr + * x1 argv + * x2 nstacks + */ + + sub sp, sp, #0x30 + stp x19, x20, [sp, #0x20] /* save the registers */ + stp x21, x22, [sp, #0x10] + stp x23, x24, [sp, #0x0] + + mov x19, x0 /* x19 = function ptr */ + mov x20, x1 /* x20 = argv */ + mov x21, x2 /* x21 = nstacks */ + mov x22, sp /* save the sp before call function */ + + /* Fill in float-point registers */ + ld1 {v0.2D, v1.2D, v2.2D, v3.2D}, [x20], #64 /* v0 = argv[0], v1 = argv[1], v2 = argv[2], v3 = argv[3]*/ + ld1 {v4.2D, v5.2D, v6.2D, v7.2D}, [x20], #64 /* v4 = argv[4], v5 = argv[5], v6 = argv[6], v7 = argv[7]*/ + + /* Fill inteter registers */ + ldp x0, x1, [x20], #16 /* x0 = argv[8] = exec_env, x1 = argv[9] */ + ldp x2, x3, [x20], #16 /* x2 = argv[10], x3 = argv[11] */ + ldp x4, x5, [x20], #16 /* x4 = argv[12], x5 = argv[13] */ + ldp x6, x7, [x20], #16 /* x6 = argv[14], x7 = argv[15] */ + + /* Now x20 points to stack args */ + + /* Directly call the fucntion if no args in stack */ + cmp x21, #0 + beq call_func + + /* Fill all stack args: reserve stack space and fill one by one */ + mov x23, sp + bic sp, x23, #15 /* Ensure stack is 16 bytes aligned */ + lsl x23, x21, #3 /* x23 = nstacks * 8 */ + add x23, x23, #15 /* x23 = (x23 + 15) & ~15 */ + bic x23, x23, #15 + sub sp, sp, x23 /* reserved stack space for stack arguments */ + mov x23, sp + +loop_stack_args: /* copy stack arguments to stack */ + cmp x21, #0 + beq call_func + ldr x24, [x20], #8 + str x24, [x23], #8 + sub x21, x21, #1 + b loop_stack_args + +call_func: + mov x20, x30 /* save x30(lr) */ + blr x19 + mov sp, x22 /* restore sp which is saved before calling fuction*/ + +return: + mov x30, x20 /* restore x30(lr) */ + ldp x19, x20, [sp, #0x20] /* restore the registers in stack */ + ldp x21, x22, [sp, #0x10] + ldp x23, x24, [sp, #0x0] + add sp, sp, #0x30 /* restore sp */ + ret + diff --git a/core/iwasm/common/iwasm_common.cmake b/core/iwasm/common/iwasm_common.cmake index e1b8d822f..608f840bb 100644 --- a/core/iwasm/common/iwasm_common.cmake +++ b/core/iwasm/common/iwasm_common.cmake @@ -43,7 +43,11 @@ elseif (WAMR_BUILD_TARGET MATCHES "THUMB.*") set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_thumb.s) endif () elseif (WAMR_BUILD_TARGET MATCHES "AARCH64.*") - set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_aarch64.s) + if (NOT WAMR_BUILD_SIMD EQUAL 1) + set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_aarch64.s) + else() + set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_aarch64_simd.s) + endif() elseif (WAMR_BUILD_TARGET STREQUAL "MIPS") set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_mips.s) elseif (WAMR_BUILD_TARGET STREQUAL "XTENSA") diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index aad71e1a7..e2721301c 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -3414,10 +3414,14 @@ typedef union __declspec(intrin_type) __declspec(align(8)) v128 { unsigned __int32 m128i_u32[4]; unsigned __int64 m128i_u64[2]; } v128; -#else +#elif defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64) typedef long long v128 __attribute__ ((__vector_size__ (16), __may_alias__, __aligned__ (1))); -#endif /* end of defined(_WIN32) || defined(_WIN32_) */ +#elif defined(BUILD_TARGET_AARCH64) +#include +typedef uint32x4_t __m128i; +#define v128 __m128i +#endif #endif /* end of WASM_ENABLE_SIMD != 0 */ diff --git a/core/iwasm/compilation/aot_llvm.c b/core/iwasm/compilation/aot_llvm.c index 418ded3db..0044a3b40 100644 --- a/core/iwasm/compilation/aot_llvm.c +++ b/core/iwasm/compilation/aot_llvm.c @@ -1496,7 +1496,8 @@ aot_create_comp_context(AOTCompData *comp_data, } if (option->enable_simd - && strcmp(comp_ctx->target_arch, "x86_64") != 0) { + && strcmp(comp_ctx->target_arch, "x86_64") != 0 + && strncmp(comp_ctx->target_arch, "aarch64", 7) != 0) { /* Disable simd if it isn't supported by target arch */ option->enable_simd = false; } diff --git a/core/iwasm/compilation/simd/simd_access_lanes.c b/core/iwasm/compilation/simd/simd_access_lanes.c index eef22ea8f..5abefbd47 100644 --- a/core/iwasm/compilation/simd/simd_access_lanes.c +++ b/core/iwasm/compilation/simd/simd_access_lanes.c @@ -8,6 +8,13 @@ #include "../aot_emit_exception.h" #include "../../aot/aot_runtime.h" +static bool +is_target_x86(AOTCompContext *comp_ctx) +{ + return !strncmp(comp_ctx->target_arch, "x86_64", 6) || + !strncmp(comp_ctx->target_arch, "i386", 4); +} + static LLVMValueRef build_intx16_vector(const AOTCompContext *comp_ctx, const LLVMTypeRef element_type, @@ -86,7 +93,7 @@ fail: /* TODO: instructions for other CPUs */ /* shufflevector is not an option, since it requires *mask as a const */ bool -aot_compile_simd_swizzle(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) +aot_compile_simd_swizzle_x86(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) { LLVMValueRef vector, mask, max_lanes, condition, mask_lanes, result; LLVMTypeRef param_types[2]; @@ -151,6 +158,109 @@ fail: return false; } +bool +aot_compile_simd_swizzle(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) +{ + LLVMValueRef vector, mask, default_lane_value, condition, max_lane_id, + result, idx, id, replace_with_zero, elem, elem_or_zero, undef; + uint8 i; + + if (is_target_x86(comp_ctx)) { + return aot_compile_simd_swizzle_x86(comp_ctx, func_ctx); + } + + int const_lane_ids[16] = { 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16 }, + const_zeors[16] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; + + if (!(mask = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, V128_i8x16_TYPE, + "mask"))) { + goto fail; + } + + if (!(vector = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, + V128_i8x16_TYPE, "vec"))) { + goto fail; + } + + if (!(undef = LLVMGetUndef(V128_i8x16_TYPE))) { + HANDLE_FAILURE("LLVMGetUndef"); + goto fail; + } + + /* icmp uge <16 x i8> mask, <16, 16, 16, 16, ...> */ + if (!(max_lane_id = + build_intx16_vector(comp_ctx, INT8_TYPE, const_lane_ids))) { + goto fail; + } + + if (!(condition = LLVMBuildICmp(comp_ctx->builder, LLVMIntUGE, mask, + max_lane_id, "out_of_range"))) { + HANDLE_FAILURE("LLVMBuldICmp"); + goto fail; + } + + /* if the id is out of range (>=16), set the id as 0 */ + if (!(default_lane_value = + build_intx16_vector(comp_ctx, INT8_TYPE, const_zeors))) { + goto fail; + } + + if (!(idx = LLVMBuildSelect(comp_ctx->builder, condition, + default_lane_value, mask, "mask"))) { + HANDLE_FAILURE("LLVMBuildSelect"); + goto fail; + } + + for (i = 0; i < 16; i++) { + if (!(id = LLVMBuildExtractElement(comp_ctx->builder, idx, I8_CONST(i), + "id"))) { + HANDLE_FAILURE("LLVMBuildExtractElement"); + goto fail; + } + + if (!(replace_with_zero = + LLVMBuildExtractElement(comp_ctx->builder, condition, + I8_CONST(i), "replace_with_zero"))) { + HANDLE_FAILURE("LLVMBuildExtractElement"); + goto fail; + } + + if (!(elem = LLVMBuildExtractElement(comp_ctx->builder, vector, id, + "vector[mask[i]]"))) { + HANDLE_FAILURE("LLVMBuildExtractElement"); + goto fail; + } + + if (!(elem_or_zero = + LLVMBuildSelect(comp_ctx->builder, replace_with_zero, + I8_CONST(0), elem, "elem_or_zero"))) { + HANDLE_FAILURE("LLVMBuildSelect"); + goto fail; + } + + if (!(undef = + LLVMBuildInsertElement(comp_ctx->builder, undef, elem_or_zero, + I8_CONST(i), "new_vector"))) { + HANDLE_FAILURE("LLVMBuildInsertElement"); + goto fail; + } + } + + if (!(result = LLVMBuildBitCast(comp_ctx->builder, undef, V128_i64x2_TYPE, + "ret"))) { + HANDLE_FAILURE("LLVMBuildBitCast"); + goto fail; + } + + PUSH_V128(result); + + return true; +fail: + return false; +} + static bool aot_compile_simd_extract(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, diff --git a/core/iwasm/compilation/simd/simd_conversions.c b/core/iwasm/compilation/simd/simd_conversions.c index f2d32c090..1f725f429 100644 --- a/core/iwasm/compilation/simd/simd_conversions.c +++ b/core/iwasm/compilation/simd/simd_conversions.c @@ -9,6 +9,13 @@ #include "../aot_emit_numberic.h" #include "../../aot/aot_runtime.h" +static bool +is_target_x86(AOTCompContext *comp_ctx) +{ + return !strncmp(comp_ctx->target_arch, "x86_64", 6) || + !strncmp(comp_ctx->target_arch, "i386", 4); +} + static bool simd_integer_narrow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, @@ -49,8 +56,85 @@ fail: return false; } +static LLVMValueRef +build_intx4_vector(const AOTCompContext *comp_ctx, + const LLVMTypeRef element_type, + const int *element_value) +{ + LLVMValueRef vector, elements[4]; + unsigned i; + + for (i = 0; i < 4; i++) { + if (!(elements[i] = + LLVMConstInt(element_type, element_value[i], true))) { + HANDLE_FAILURE("LLVMConstInst"); + goto fail; + } + } + + if (!(vector = LLVMConstVector(elements, 4))) { + HANDLE_FAILURE("LLVMConstVector"); + goto fail; + } + return vector; +fail: + return NULL; +} + +static LLVMValueRef +build_intx8_vector(const AOTCompContext *comp_ctx, + const LLVMTypeRef element_type, + const int *element_value) +{ + LLVMValueRef vector, elements[8]; + unsigned i; + + for (i = 0; i < 8; i++) { + if (!(elements[i] = + LLVMConstInt(element_type, element_value[i], true))) { + HANDLE_FAILURE("LLVMConstInst"); + goto fail; + } + } + + if (!(vector = LLVMConstVector(elements, 8))) { + HANDLE_FAILURE("LLVMConstVector"); + goto fail; + } + + return vector; +fail: + return NULL; +} + +static LLVMValueRef +build_intx16_vector(const AOTCompContext *comp_ctx, + const LLVMTypeRef element_type, + const int *element_value) +{ + LLVMValueRef vector, elements[16]; + unsigned i; + + for (i = 0; i < 16; i++) { + if (!(elements[i] = + LLVMConstInt(element_type, element_value[i], true))) { + HANDLE_FAILURE("LLVMConstInst"); + goto fail; + } + } + + if (!(vector = LLVMConstVector(elements, 16))) { + HANDLE_FAILURE("LLVMConstVector"); + goto fail; + } + + return vector; +fail: + return NULL; +} + bool -aot_compile_simd_i8x16_narrow_i16x8(AOTCompContext *comp_ctx, +aot_compile_simd_i8x16_narrow_i16x8_x86(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, bool is_signed) { @@ -60,7 +144,7 @@ aot_compile_simd_i8x16_narrow_i16x8(AOTCompContext *comp_ctx, } bool -aot_compile_simd_i16x8_narrow_i32x4(AOTCompContext *comp_ctx, +aot_compile_simd_i16x8_narrow_i32x4_x86(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, bool is_signed) { @@ -69,6 +153,273 @@ aot_compile_simd_i16x8_narrow_i32x4(AOTCompContext *comp_ctx, is_signed ? "llvm.x86.sse2.packssdw.128" : "llvm.x86.sse41.packusdw"); } +bool +aot_compile_simd_i8x16_narrow_i16x8(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + bool is_signed) +{ + LLVMValueRef vector1, vector2, result, vector_min, vector_max, shuffle, + vector1_clamped, vector2_clamped, vector1_trunced, vector2_trunced, + shuffle_vector; + LLVMValueRef v1_gt_max, v1_lt_min, v2_gt_max, v2_lt_min; + + if (is_target_x86(comp_ctx)) { + return aot_compile_simd_i8x16_narrow_i16x8_x86(comp_ctx, func_ctx, + is_signed); + } + + int min_s_array[8] = { 0xff80, 0xff80, 0xff80, 0xff80, + 0xff80, 0xff80, 0xff80, 0xff80 }; + int max_s_array[8] = { 0x007f, 0x007f, 0x007f, 0x007f, + 0x007f, 0x007f, 0x007f, 0x007f }; + + int min_u_array[8] = { 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000 }; + int max_u_array[8] = { 0x00ff, 0x00ff, 0x00ff, 0x00ff, + 0x00ff, 0x00ff, 0x00ff, 0x00ff }; + + int shuffle_array[16] = { 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15 }; + + if (!(vector2 = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, + V128_i16x8_TYPE, "vec2"))) { + goto fail; + } + + if (!(vector1 = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, + V128_i16x8_TYPE, "vec1"))) { + goto fail; + } + + if (!(vector_min = build_intx8_vector( + comp_ctx, INT16_TYPE, is_signed ? min_s_array : min_u_array))) { + goto fail; + } + if (!(vector_max = build_intx8_vector( + comp_ctx, INT16_TYPE, is_signed ? max_s_array : max_u_array))) { + goto fail; + } + if (!(shuffle = build_intx16_vector(comp_ctx, I32_TYPE, shuffle_array))) { + goto fail; + } + + if (!(v1_gt_max = LLVMBuildICmp(comp_ctx->builder, LLVMIntSGT, vector1, + vector_max, "v1_great_than_max"))) { + HANDLE_FAILURE("LLVMBuldICmp"); + goto fail; + } + + if (!(v2_gt_max = LLVMBuildICmp(comp_ctx->builder, LLVMIntSGT, vector2, + vector_max, "v2_great_than_max"))) { + HANDLE_FAILURE("LLVMBuldICmp"); + goto fail; + } + + if (!(v1_lt_min = LLVMBuildICmp(comp_ctx->builder, LLVMIntSLT, vector1, + vector_min, "v1_less_than_min"))) { + HANDLE_FAILURE("LLVMBuldICmp"); + goto fail; + } + + if (!(v2_lt_min = LLVMBuildICmp(comp_ctx->builder, LLVMIntSLT, vector2, + vector_min, "v2_less_than_min"))) { + HANDLE_FAILURE("LLVMBuldICmp"); + goto fail; + } + + if (!(vector1_clamped = + LLVMBuildSelect(comp_ctx->builder, v1_gt_max, vector_max, vector1, + "vector1_clamped_max"))) { + HANDLE_FAILURE("LLVMBuildSelect"); + goto fail; + } + + if (!(vector1_clamped = + LLVMBuildSelect(comp_ctx->builder, v1_lt_min, vector_min, + vector1_clamped, "vector1_clamped_min"))) { + HANDLE_FAILURE("LLVMBuildSelect"); + goto fail; + } + + if (!(vector2_clamped = + LLVMBuildSelect(comp_ctx->builder, v2_gt_max, vector_max, vector2, + "vector2_clamped_max"))) { + HANDLE_FAILURE("LLVMBuildSelect"); + goto fail; + } + + if (!(vector2_clamped = + LLVMBuildSelect(comp_ctx->builder, v2_lt_min, vector_min, + vector2_clamped, "vector2_clamped_min"))) { + HANDLE_FAILURE("LLVMBuildSelect"); + goto fail; + } + + if (!(vector1_trunced = + LLVMBuildTrunc(comp_ctx->builder, vector1_clamped, + LLVMVectorType(INT8_TYPE, 8), "vector1_trunced"))) { + HANDLE_FAILURE("LLVMBuildTrunc"); + goto fail; + } + + if (!(vector2_trunced = + LLVMBuildTrunc(comp_ctx->builder, vector2_clamped, + LLVMVectorType(INT8_TYPE, 8), "vector2_trunced"))) { + HANDLE_FAILURE("LLVMBuildTrunc"); + goto fail; + } + + if (!(shuffle_vector = LLVMBuildShuffleVector( + comp_ctx->builder, vector1_trunced, vector2_trunced, shuffle, + "shuffle_vector"))) { + HANDLE_FAILURE("LLVMBuildShuffleVector"); + goto fail; + } + + if (!(result = LLVMBuildBitCast(comp_ctx->builder, shuffle_vector, + V128_i64x2_TYPE, "ret"))) { + HANDLE_FAILURE("LLVMBuildBitCast"); + goto fail; + } + + PUSH_V128(result); + return true; + +fail: + return false; +} + +bool +aot_compile_simd_i16x8_narrow_i32x4(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + bool is_signed) +{ + LLVMValueRef vector1, vector2, result, vector_min, vector_max, shuffle, + vector1_clamped, vector2_clamped, vector1_trunced, vector2_trunced, + shuffle_vector; + LLVMValueRef v1_gt_max, v1_lt_min, v2_gt_max, v2_lt_min; + + if (is_target_x86(comp_ctx)) { + return aot_compile_simd_i16x8_narrow_i32x4_x86(comp_ctx, func_ctx, + is_signed); + } + + int min_s_array[4] = { 0xffff8000, 0xffff8000, 0xffff8000, 0xffff8000 }; + int32 max_s_array[4] = { 0x00007fff, 0x00007fff, 0x00007fff, 0x00007fff }; + + int min_u_array[4] = { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }; + int max_u_array[4] = { 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff }; + + int shuffle_array[8] = { 0, 1, 2, 3, 4, 5, 6, 7 }; + + if (!(vector2 = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, + V128_i32x4_TYPE, "vec2"))) { + goto fail; + } + + if (!(vector1 = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, + V128_i32x4_TYPE, "vec1"))) { + goto fail; + } + + if (!(vector_min = build_intx4_vector( + comp_ctx, I32_TYPE, is_signed ? min_s_array : min_u_array))) { + goto fail; + } + if (!(vector_max = build_intx4_vector( + comp_ctx, I32_TYPE, is_signed ? max_s_array : max_u_array))) { + goto fail; + } + if (!(shuffle = build_intx8_vector(comp_ctx, I32_TYPE, shuffle_array))) { + goto fail; + } + + if (!(v1_gt_max = LLVMBuildICmp(comp_ctx->builder, LLVMIntSGT, vector1, + vector_max, "v1_great_than_max"))) { + HANDLE_FAILURE("LLVMBuldICmp"); + goto fail; + } + + if (!(v2_gt_max = LLVMBuildICmp(comp_ctx->builder, LLVMIntSGT, vector2, + vector_max, "v2_great_than_max"))) { + HANDLE_FAILURE("LLVMBuldICmp"); + goto fail; + } + + if (!(v1_lt_min = LLVMBuildICmp(comp_ctx->builder, LLVMIntSLT, vector1, + vector_min, "v1_less_than_min"))) { + HANDLE_FAILURE("LLVMBuldICmp"); + goto fail; + } + + if (!(v2_lt_min = LLVMBuildICmp(comp_ctx->builder, LLVMIntSLT, vector2, + vector_min, "v2_less_than_min"))) { + HANDLE_FAILURE("LLVMBuldICmp"); + goto fail; + } + + if (!(vector1_clamped = + LLVMBuildSelect(comp_ctx->builder, v1_gt_max, vector_max, vector1, + "vector1_clamped_max"))) { + HANDLE_FAILURE("LLVMBuildSelect"); + goto fail; + } + + if (!(vector1_clamped = + LLVMBuildSelect(comp_ctx->builder, v1_lt_min, vector_min, + vector1_clamped, "vector1_clamped_min"))) { + HANDLE_FAILURE("LLVMBuildSelect"); + goto fail; + } + + if (!(vector2_clamped = + LLVMBuildSelect(comp_ctx->builder, v2_gt_max, vector_max, vector2, + "vector2_clamped_max"))) { + HANDLE_FAILURE("LLVMBuildSelect"); + goto fail; + } + + if (!(vector2_clamped = + LLVMBuildSelect(comp_ctx->builder, v2_lt_min, vector_min, + vector2_clamped, "vector2_clamped_min"))) { + HANDLE_FAILURE("LLVMBuildSelect"); + goto fail; + } + + if (!(vector1_trunced = LLVMBuildTrunc(comp_ctx->builder, vector1_clamped, + LLVMVectorType(INT16_TYPE, 4), + "vector1_trunced"))) { + HANDLE_FAILURE("LLVMBuildTrunc"); + goto fail; + } + + if (!(vector2_trunced = LLVMBuildTrunc(comp_ctx->builder, vector2_clamped, + LLVMVectorType(INT16_TYPE, 4), + "vector2_trunced"))) { + HANDLE_FAILURE("LLVMBuildTrunc"); + goto fail; + } + + if (!(shuffle_vector = LLVMBuildShuffleVector( + comp_ctx->builder, vector1_trunced, vector2_trunced, shuffle, + "shuffle_vector"))) { + HANDLE_FAILURE("LLVMBuildShuffleVector"); + goto fail; + } + + if (!(result = LLVMBuildBitCast(comp_ctx->builder, shuffle_vector, + V128_i64x2_TYPE, "ret"))) { + HANDLE_FAILURE("LLVMBuildBitCast"); + goto fail; + } + + PUSH_V128(result); + return true; + +fail: + return false; +} + bool aot_compile_simd_i16x8_widen_i8x16(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, From 7706e4b1514e5fd95a1c5efe258ecd08467d030a Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Tue, 13 Apr 2021 15:23:22 +0800 Subject: [PATCH 183/207] Re-org SIMD code structure for non-x86 target (#611) --- .../compilation/simd/simd_access_lanes.c | 20 +++++--- .../iwasm/compilation/simd/simd_conversions.c | 50 +++++++++++++------ 2 files changed, 48 insertions(+), 22 deletions(-) diff --git a/core/iwasm/compilation/simd/simd_access_lanes.c b/core/iwasm/compilation/simd/simd_access_lanes.c index 5abefbd47..8f1489c84 100644 --- a/core/iwasm/compilation/simd/simd_access_lanes.c +++ b/core/iwasm/compilation/simd/simd_access_lanes.c @@ -90,7 +90,6 @@ fail: return false; } -/* TODO: instructions for other CPUs */ /* shufflevector is not an option, since it requires *mask as a const */ bool aot_compile_simd_swizzle_x86(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) @@ -158,17 +157,13 @@ fail: return false; } -bool -aot_compile_simd_swizzle(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) +static bool +aot_compile_simd_swizzle_common(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) { LLVMValueRef vector, mask, default_lane_value, condition, max_lane_id, result, idx, id, replace_with_zero, elem, elem_or_zero, undef; uint8 i; - if (is_target_x86(comp_ctx)) { - return aot_compile_simd_swizzle_x86(comp_ctx, func_ctx); - } - int const_lane_ids[16] = { 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16 }, const_zeors[16] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, @@ -261,6 +256,17 @@ fail: return false; } +bool +aot_compile_simd_swizzle(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) +{ + if (is_target_x86(comp_ctx)) { + return aot_compile_simd_swizzle_x86(comp_ctx, func_ctx); + } + else { + return aot_compile_simd_swizzle_common(comp_ctx, func_ctx); + } +} + static bool aot_compile_simd_extract(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, diff --git a/core/iwasm/compilation/simd/simd_conversions.c b/core/iwasm/compilation/simd/simd_conversions.c index 1f725f429..d330c38a3 100644 --- a/core/iwasm/compilation/simd/simd_conversions.c +++ b/core/iwasm/compilation/simd/simd_conversions.c @@ -153,21 +153,16 @@ aot_compile_simd_i16x8_narrow_i32x4_x86(AOTCompContext *comp_ctx, is_signed ? "llvm.x86.sse2.packssdw.128" : "llvm.x86.sse41.packusdw"); } -bool -aot_compile_simd_i8x16_narrow_i16x8(AOTCompContext *comp_ctx, - AOTFuncContext *func_ctx, - bool is_signed) +static bool +aot_compile_simd_i8x16_narrow_i16x8_common(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + bool is_signed) { LLVMValueRef vector1, vector2, result, vector_min, vector_max, shuffle, vector1_clamped, vector2_clamped, vector1_trunced, vector2_trunced, shuffle_vector; LLVMValueRef v1_gt_max, v1_lt_min, v2_gt_max, v2_lt_min; - if (is_target_x86(comp_ctx)) { - return aot_compile_simd_i8x16_narrow_i16x8_x86(comp_ctx, func_ctx, - is_signed); - } - int min_s_array[8] = { 0xff80, 0xff80, 0xff80, 0xff80, 0xff80, 0xff80, 0xff80, 0xff80 }; int max_s_array[8] = { 0x007f, 0x007f, 0x007f, 0x007f, @@ -290,20 +285,30 @@ fail: } bool -aot_compile_simd_i16x8_narrow_i32x4(AOTCompContext *comp_ctx, +aot_compile_simd_i8x16_narrow_i16x8(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, bool is_signed) +{ + if (is_target_x86(comp_ctx)) { + return aot_compile_simd_i8x16_narrow_i16x8_x86(comp_ctx, func_ctx, + is_signed); + } + else { + return aot_compile_simd_i8x16_narrow_i16x8_common(comp_ctx, func_ctx, + is_signed); + } +} + +static bool +aot_compile_simd_i16x8_narrow_i32x4_common(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + bool is_signed) { LLVMValueRef vector1, vector2, result, vector_min, vector_max, shuffle, vector1_clamped, vector2_clamped, vector1_trunced, vector2_trunced, shuffle_vector; LLVMValueRef v1_gt_max, v1_lt_min, v2_gt_max, v2_lt_min; - if (is_target_x86(comp_ctx)) { - return aot_compile_simd_i16x8_narrow_i32x4_x86(comp_ctx, func_ctx, - is_signed); - } - int min_s_array[4] = { 0xffff8000, 0xffff8000, 0xffff8000, 0xffff8000 }; int32 max_s_array[4] = { 0x00007fff, 0x00007fff, 0x00007fff, 0x00007fff }; @@ -420,6 +425,21 @@ fail: return false; } +bool +aot_compile_simd_i16x8_narrow_i32x4(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + bool is_signed) +{ + if (is_target_x86(comp_ctx)) { + return aot_compile_simd_i16x8_narrow_i32x4_x86(comp_ctx, func_ctx, + is_signed); + } + else { + return aot_compile_simd_i16x8_narrow_i32x4_common(comp_ctx, func_ctx, + is_signed); + } +} + bool aot_compile_simd_i16x8_widen_i8x16(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, From 03d45f1d62dbcfdff1cb0893318ab5d4298f726a Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Thu, 15 Apr 2021 11:29:20 +0800 Subject: [PATCH 184/207] Import reference-types feature (#612) Implement spec reference-types proposal for interpreter, AOT and JIT, update documents and add sample. And upgrade AOT_CURRENT_VERSION to 3 as AOT file format and AOT module instance layout are changed. Signed-off-by: Wenyong Huang --- README.md | 10 +- build-scripts/config_common.cmake | 6 + core/config.h | 6 +- core/iwasm/aot/aot_loader.c | 56 +- core/iwasm/aot/aot_reloc.h | 16 +- core/iwasm/aot/aot_runtime.c | 374 ++++- core/iwasm/aot/aot_runtime.h | 75 +- core/iwasm/common/wasm_exec_env.h | 4 + core/iwasm/common/wasm_native.c | 8 +- core/iwasm/common/wasm_runtime_common.c | 654 +++++++- core/iwasm/common/wasm_runtime_common.h | 44 +- core/iwasm/compilation/aot.c | 19 +- core/iwasm/compilation/aot.h | 20 + core/iwasm/compilation/aot_compiler.c | 252 +++- core/iwasm/compilation/aot_compiler.h | 96 +- core/iwasm/compilation/aot_emit_aot_file.c | 103 +- core/iwasm/compilation/aot_emit_control.c | 2 + core/iwasm/compilation/aot_emit_function.c | 185 ++- core/iwasm/compilation/aot_emit_function.h | 16 +- core/iwasm/compilation/aot_emit_memory.c | 37 +- core/iwasm/compilation/aot_emit_parametric.c | 17 +- core/iwasm/compilation/aot_emit_table.c | 487 ++++++ core/iwasm/compilation/aot_emit_table.h | 71 + core/iwasm/compilation/aot_emit_variable.c | 4 +- core/iwasm/compilation/aot_llvm.c | 76 +- core/iwasm/compilation/aot_llvm.h | 10 +- core/iwasm/include/aot_export.h | 1 + core/iwasm/include/wasm_export.h | 39 + core/iwasm/interpreter/wasm.h | 37 +- core/iwasm/interpreter/wasm_interp_classic.c | 326 +++- core/iwasm/interpreter/wasm_interp_fast.c | 276 +++- core/iwasm/interpreter/wasm_loader.c | 1424 ++++++++++++++---- core/iwasm/interpreter/wasm_loader.h | 8 + core/iwasm/interpreter/wasm_mini_loader.c | 1029 +++++++++++-- core/iwasm/interpreter/wasm_opcode.h | 73 +- core/iwasm/interpreter/wasm_runtime.c | 151 +- core/iwasm/interpreter/wasm_runtime.h | 42 +- core/shared/utils/bh_hashmap.c | 5 +- core/shared/utils/bh_hashmap.h | 8 +- doc/build_wamr.md | 3 + doc/export_native_api.md | 2 +- doc/ref_types.md | 22 + product-mini/platforms/linux/CMakeLists.txt | 5 + samples/ref-types/CMakeLists.txt | 108 ++ samples/ref-types/src/hello.c | 165 ++ samples/ref-types/src/hello.wat | 22 + wamr-compiler/CMakeLists.txt | 5 + wamr-compiler/main.c | 14 + 48 files changed, 5557 insertions(+), 856 deletions(-) create mode 100644 core/iwasm/compilation/aot_emit_table.c create mode 100644 core/iwasm/compilation/aot_emit_table.h create mode 100644 doc/ref_types.md create mode 100644 samples/ref-types/CMakeLists.txt create mode 100644 samples/ref-types/src/hello.c create mode 100644 samples/ref-types/src/hello.wat diff --git a/README.md b/README.md index c20640596..3cd807e86 100644 --- a/README.md +++ b/README.md @@ -25,8 +25,8 @@ iwasm VM core - Choices of WASM application libc support: the built-in libc subset for the embedded environment or [WASI](https://github.com/WebAssembly/WASI) for standard libc - [Embeddable with the supporting C API's](./doc/embed_wamr.md) - [The mechanism for exporting native API's to WASM applications](./doc/export_native_api.md) -- [Multiple modules as dependencies](./doc/multi_module.md) -- [Thread management and pthread library](./doc/pthread_library.md) +- [Multiple modules as dependencies](./doc/multi_module.md), ref to [sample](samples/multi-module) +- [Thread management and pthread library](./doc/pthread_library.md), ref to [sample](samples/multi-thread) ### post-MVP features - [Non-trapping float-to-int conversions](https://github.com/WebAssembly/nontrapping-float-to-int-conversions) @@ -34,9 +34,10 @@ iwasm VM core - [Bulk memory operations](https://github.com/WebAssembly/bulk-memory-operations) - [Shared memory](https://github.com/WebAssembly/threads/blob/main/proposals/threads/Overview.md#shared-linear-memory) - [Multi-value](https://github.com/WebAssembly/multi-value) -- [wasm-c-api](https://github.com/WebAssembly/wasm-c-api) +- [wasm-c-api](https://github.com/WebAssembly/wasm-c-api), ref to [document](doc/wasm_c_api.md) and [sample](samples/wasm-c-api) - [Tail-call](https://github.com/WebAssembly/tail-call) -- [128-bit SIMD](https://github.com/WebAssembly/simd) +- [128-bit SIMD](https://github.com/WebAssembly/simd), ref to [samples/workload](samples/workload) +- [Reference Types](https://github.com/WebAssembly/reference-types), ref to [document](doc/ref_types.md) and [sample](samples/ref-types) ### Supported architectures and platforms @@ -124,6 +125,7 @@ The WAMR [samples](./samples) integrate the iwasm VM core, application manager a - **[multi-thread](./samples/multi-thread/)**: Demonstrating how to run wasm application which creates multiple threads to execute wasm functions concurrently, and uses mutex/cond by calling pthread related API's. - **[spawn-thread](./samples/spawn-thread)**: Demonstrating how to execute wasm functions of the same wasm application concurrently, in threads created by host embedder or runtime, but not the wasm application itself. - **[multi-module](./samples/multi-module)**: Demonstrating the [multiple modules as dependencies](./doc/multi_module.md) feature which implements the [load-time dynamic linking](https://webassembly.org/docs/dynamic-linking/). +- **[ref-types](./samples/ref-types)**: Demonstrating how to call wasm functions with argument of externref type introduced by [reference types proposal](https://github.com/WebAssembly/reference-types). - **[wasm-c-api](./samples/wasm-c-api/README.md)**: Demonstrating how to run some samples from [wasm-c-api proposal](https://github.com/WebAssembly/wasm-c-api) and showing the supported API's. - **[workload](./samples/workload/README.md)**: Demonstrating how to build and run some complex workloads, e.g. tensorflow-lite, XNNPACK, wasm-av1, meshoptimizer and bwa. diff --git a/build-scripts/config_common.cmake b/build-scripts/config_common.cmake index 03a4b23bd..816471633 100644 --- a/build-scripts/config_common.cmake +++ b/build-scripts/config_common.cmake @@ -206,6 +206,12 @@ if (WAMR_BUILD_TAIL_CALL EQUAL 1) add_definitions (-DWASM_ENABLE_TAIL_CALL=1) message (" Tail call enabled") endif () +if (WAMR_BUILD_REF_TYPES EQUAL 1) + add_definitions (-DWASM_ENABLE_REF_TYPES=1) + message (" Reference types enabled") +else () + message (" Reference types disabled") +endif () if (DEFINED WAMR_BH_VPRINTF) add_definitions (-DBH_VPRINTF=${WAMR_BH_VPRINTF}) endif () diff --git a/core/config.h b/core/config.h index 02ceb680f..878a42280 100644 --- a/core/config.h +++ b/core/config.h @@ -66,7 +66,7 @@ #endif #define AOT_MAGIC_NUMBER 0x746f6100 -#define AOT_CURRENT_VERSION 2 +#define AOT_CURRENT_VERSION 3 #ifndef WASM_ENABLE_JIT #define WASM_ENABLE_JIT 0 @@ -289,5 +289,9 @@ #define WASM_ENABLE_CUSTOM_NAME_SECTION 0 #endif +#ifndef WASM_ENABLE_REF_TYPES +#define WASM_ENABLE_REF_TYPES 0 +#endif + #endif /* end of _CONFIG_H_ */ diff --git a/core/iwasm/aot/aot_loader.c b/core/iwasm/aot/aot_loader.c index fac0c4856..eba9a9dfb 100644 --- a/core/iwasm/aot/aot_loader.c +++ b/core/iwasm/aot/aot_loader.c @@ -506,6 +506,39 @@ destroy_table_init_data_list(AOTTableInitData **data_list, uint32 count, } } +static bool +load_import_table_list(const uint8 **p_buf, + const uint8 *buf_end, + AOTModule *module, + char *error_buf, + uint32 error_buf_size) +{ + const uint8 *buf = *p_buf; + AOTImportTable *import_table; + uint64 size; + uint32 i, possible_grow; + + /* Allocate memory */ + size = sizeof(AOTImportTable) * (uint64)module->import_table_count; + if (!(module->import_tables = import_table = + loader_malloc(size, error_buf, error_buf_size))) { + return false; + } + + /* keep sync with aot_emit_table_info() aot_emit_aot_file */ + for (i = 0; i < module->import_table_count; i++, import_table++) { + read_uint32(buf, buf_end, import_table->table_init_size); + read_uint32(buf, buf_end, import_table->table_max_size); + read_uint32(buf, buf_end, possible_grow); + import_table->possible_grow = (possible_grow & 0x1); + } + + *p_buf = buf; + return true; +fail: + return false; +} + static bool load_table_list(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module, char *error_buf, uint32 error_buf_size) @@ -513,7 +546,7 @@ load_table_list(const uint8 **p_buf, const uint8 *buf_end, const uint8 *buf = *p_buf; AOTTable *table; uint64 size; - uint32 i; + uint32 i, possible_grow; /* Allocate memory */ size = sizeof(AOTTable) * (uint64)module->table_count; @@ -528,6 +561,8 @@ load_table_list(const uint8 **p_buf, const uint8 *buf_end, read_uint32(buf, buf_end, table->table_flags); read_uint32(buf, buf_end, table->table_init_size); read_uint32(buf, buf_end, table->table_max_size); + read_uint32(buf, buf_end, possible_grow); + table->possible_grow = (possible_grow & 0x1); } *p_buf = buf; @@ -555,9 +590,12 @@ load_table_init_data_list(const uint8 **p_buf, const uint8 *buf_end, /* Create each table data segment */ for (i = 0; i < module->table_init_data_count; i++) { + uint32 mode, elem_type; uint32 table_index, init_expr_type, func_index_count; uint64 init_expr_value, size1; + read_uint32(buf, buf_end, mode); + read_uint32(buf, buf_end, elem_type); read_uint32(buf, buf_end, table_index); read_uint32(buf, buf_end, init_expr_type); read_uint64(buf, buf_end, init_expr_value); @@ -570,6 +608,9 @@ load_table_init_data_list(const uint8 **p_buf, const uint8 *buf_end, return false; } + data_list[i]->mode = mode; + data_list[i]->elem_type = elem_type; + data_list[i]->is_dropped = false; data_list[i]->table_index = table_index; data_list[i]->offset.init_expr_type = (uint8)init_expr_type; data_list[i]->offset.u.i64 = (int64)init_expr_value; @@ -591,13 +632,14 @@ load_table_info(const uint8 **p_buf, const uint8 *buf_end, const uint8 *buf = *p_buf; read_uint32(buf, buf_end, module->import_table_count); - /* We don't support import_table_count > 0 currently */ - bh_assert(module->import_table_count == 0); + if (module->import_table_count > 0 + && !load_import_table_list(&buf, buf_end, module, error_buf, + error_buf_size)) + return false; read_uint32(buf, buf_end, module->table_count); if (module->table_count > 0 - && !load_table_list(&buf, buf_end, module, - error_buf, error_buf_size)) + && !load_table_list(&buf, buf_end, module, error_buf, error_buf_size)) return false; read_uint32(buf, buf_end, module->table_init_data_count); @@ -2457,11 +2499,15 @@ aot_convert_wasm_module(WASMModule *wasm_module, #endif #if WASM_ENABLE_SIMD != 0 option.enable_simd = true; +#endif +#if WASM_ENABLE_REF_TYPES != 0 + option.enable_ref_types = true; #endif option.enable_aux_stack_check = true; #if (WASM_ENABLE_PERF_PROFILING != 0) || (WASM_ENABLE_DUMP_CALL_STACK != 0) option.enable_aux_stack_frame = true; #endif + comp_ctx = aot_create_comp_context(comp_data, &option); if (!comp_ctx) { aot_last_error = aot_get_last_error(); diff --git a/core/iwasm/aot/aot_reloc.h b/core/iwasm/aot/aot_reloc.h index 27fecf00e..7c1673cf7 100644 --- a/core/iwasm/aot/aot_reloc.h +++ b/core/iwasm/aot/aot_reloc.h @@ -29,6 +29,17 @@ typedef struct { #define REG_ATOMIC_WAIT_SYM() #endif +#if WASM_ENABLE_REF_TYPES != 0 +#define REG_REF_TYPES_SYM() \ + REG_SYM(aot_drop_table_seg), \ + REG_SYM(aot_table_init), \ + REG_SYM(aot_table_copy), \ + REG_SYM(aot_table_fill), \ + REG_SYM(aot_table_grow), +#else +#define REG_REF_TYPES_SYM() +#endif + #if (WASM_ENABLE_PERF_PROFILING != 0) || (WASM_ENABLE_DUMP_CALL_STACK != 0) #define REG_AOT_TRACE_SYM() \ REG_SYM(aot_alloc_frame), \ @@ -41,8 +52,8 @@ typedef struct { REG_SYM(aot_set_exception_with_id), \ REG_SYM(aot_invoke_native), \ REG_SYM(aot_call_indirect), \ - REG_SYM(wasm_runtime_enlarge_memory), \ - REG_SYM(wasm_runtime_set_exception), \ + REG_SYM(aot_enlarge_memory), \ + REG_SYM(aot_set_exception), \ {"memset", (void*)aot_memset}, \ {"memmove", (void*)aot_memmove}, \ REG_SYM(fmin), \ @@ -59,6 +70,7 @@ typedef struct { REG_SYM(rintf), \ REG_BULK_MEMORY_SYM() \ REG_ATOMIC_WAIT_SYM() \ + REG_REF_TYPES_SYM() \ REG_AOT_TRACE_SYM() #define CHECK_RELOC_OFFSET(data_size) do { \ diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index 74a710324..139c0d034 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -89,6 +89,10 @@ init_global_data(uint8 *global_data, uint8 type, switch (type) { case VALUE_TYPE_I32: case VALUE_TYPE_F32: +#if WASM_ENABLE_REF_TYPES + case VALUE_TYPE_FUNCREF: + case VALUE_TYPE_EXTERNREF: +#endif *(int32*)global_data = initial_value->i32; break; case VALUE_TYPE_I64: @@ -143,6 +147,13 @@ global_instantiate(AOTModuleInstance *module_inst, AOTModule *module, .global_data_linked); break; } +#if WASM_ENABLE_REF_TYPES != 0 + case INIT_EXPR_TYPE_REFNULL_CONST: + { + *(uint32 *)p = NULL_REF; + break; + } +#endif default: { init_global_data(p, global->type, &init_expr->u); @@ -157,22 +168,86 @@ global_instantiate(AOTModuleInstance *module_inst, AOTModule *module, return true; } +AOTTableInstance * +aot_next_tbl_inst(const AOTTableInstance *tbl_inst) +{ + uint32 offset = offsetof(AOTTableInstance, data); + offset += tbl_inst->max_size * sizeof(uint32); + return (AOTTableInstance *)((uint8 *)tbl_inst + offset); +} + +static inline AOTTableInstance * +aot_get_table_inst(const AOTModuleInstance *module_inst, uint32 tbl_idx) +{ + uint32 i = 0; + AOTTableInstance *tbl_inst = (AOTTableInstance*)module_inst->tables.ptr; + + while (i != tbl_idx) { + tbl_inst = aot_next_tbl_inst(tbl_inst); + ++i; + } + + return tbl_inst; +} + static bool table_instantiate(AOTModuleInstance *module_inst, AOTModule *module, char *error_buf, uint32 error_buf_size) { uint32 i, global_index, global_data_offset, base_offset, length; AOTTableInitData *table_seg; + AOTTableInstance *tbl_inst = (AOTTableInstance*)module_inst->tables.ptr; + /* + * treat import table like a local one until we enable module linking + * in AOT mode + */ + for (i = 0; i != module_inst->table_count; ++i) { + if (i < module->import_table_count) { + AOTImportTable *import_table = module->import_tables + i; + tbl_inst->cur_size = import_table->table_init_size; + tbl_inst->max_size = aot_get_imp_tbl_data_slots(import_table); + } + else { + AOTTable *table = + module->tables + (i - module->import_table_count); + tbl_inst->cur_size = table->table_init_size; + tbl_inst->max_size = aot_get_tbl_data_slots(table); + } + + tbl_inst = aot_next_tbl_inst(tbl_inst); + } + + /* fill table with element segment content */ for (i = 0; i < module->table_init_data_count; i++) { + AOTTableInstance *tbl_inst; + table_seg = module->table_init_data_list[i]; - bh_assert(table_seg->offset.init_expr_type == - INIT_EXPR_TYPE_I32_CONST - || table_seg->offset.init_expr_type == - INIT_EXPR_TYPE_GET_GLOBAL); + +#if WASM_ENABLE_REF_TYPES != 0 + if (!wasm_elem_is_active(table_seg->mode)) + continue; +#endif + + bh_assert(table_seg->table_index < module_inst->table_count); + + tbl_inst = aot_get_table_inst(module_inst, table_seg->table_index); + bh_assert(tbl_inst); + + bh_assert( + table_seg->offset.init_expr_type == INIT_EXPR_TYPE_I32_CONST + || table_seg->offset.init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL +#if WASM_ENABLE_REF_TYPES != 0 + || table_seg->offset.init_expr_type + == INIT_EXPR_TYPE_FUNCREF_CONST + || table_seg->offset.init_expr_type + == INIT_EXPR_TYPE_REFNULL_CONST +#endif + ); /* Resolve table data base offset */ - if (table_seg->offset.init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL) { + if (table_seg->offset.init_expr_type + == INIT_EXPR_TYPE_GET_GLOBAL) { global_index = table_seg->offset.u.global_index; if (!check_global_init_expr(module, global_index, @@ -182,36 +257,42 @@ table_instantiate(AOTModuleInstance *module_inst, AOTModule *module, if (global_index < module->import_global_count) global_data_offset = - module->import_globals[global_index].data_offset; + module->import_globals[global_index].data_offset; else global_data_offset = - module->globals[global_index - module->import_global_count] - .data_offset; + module + ->globals[global_index - module->import_global_count] + .data_offset; - base_offset = *(uint32*) - ((uint8*)module_inst->global_data.ptr + global_data_offset); + base_offset = *(uint32 *)((uint8 *)module_inst->global_data.ptr + + global_data_offset); } else base_offset = (uint32)table_seg->offset.u.i32; /* Copy table data */ - bh_assert(module_inst->table_data.ptr); /* base_offset only since length might negative */ - if (base_offset > module_inst->table_size) { - LOG_DEBUG("base_offset(%d) > table_size(%d)", base_offset, - module_inst->table_size); + if (base_offset > tbl_inst->cur_size) { +#if WASM_ENABLE_REF_TYPES != 0 + set_error_buf(error_buf, error_buf_size, + "out of bounds table access"); +#else set_error_buf(error_buf, error_buf_size, "elements segment does not fit"); +#endif return false; } /* base_offset + length(could be zero) */ length = table_seg->func_index_count; - if (base_offset + length > module_inst->table_size) { - LOG_DEBUG("base_offset(%d) + length(%d) > table_size(%d)", - base_offset, length, module_inst->table_size); + if (base_offset + length > tbl_inst->cur_size) { +#if WASM_ENABLE_REF_TYPES != 0 + set_error_buf(error_buf, error_buf_size, + "out of bounds table access"); +#else set_error_buf(error_buf, error_buf_size, "elements segment does not fit"); +#endif return false; } @@ -219,9 +300,9 @@ table_instantiate(AOTModuleInstance *module_inst, AOTModule *module, * Check function index in the current module inst for now. * will check the linked table inst owner in future */ - memcpy((uint32 *)module_inst->table_data.ptr + base_offset, - table_seg->func_indexes, - length * sizeof(uint32)); + bh_memcpy_s((uint32 *)tbl_inst->data + base_offset, + (tbl_inst->max_size - base_offset) * sizeof(uint32), + table_seg->func_indexes, length * sizeof(uint32)); } return true; @@ -595,8 +676,13 @@ memories_instantiate(AOTModuleInstance *module_inst, AOTModule *module, if (base_offset > memory_inst->memory_data_size) { LOG_DEBUG("base_offset(%d) > memory_data_size(%d)", base_offset, memory_inst->memory_data_size); +#if WASM_ENABLE_REF_TYPES != 0 + set_error_buf(error_buf, error_buf_size, + "out of bounds memory access"); +#else set_error_buf(error_buf, error_buf_size, "data segment does not fit"); +#endif return false; } @@ -605,8 +691,13 @@ memories_instantiate(AOTModuleInstance *module_inst, AOTModule *module, if (base_offset + length > memory_inst->memory_data_size) { LOG_DEBUG("base_offset(%d) + length(%d) > memory_data_size(%d)", base_offset, length, memory_inst->memory_data_size); +#if WASM_ENABLE_REF_TYPES != 0 + set_error_buf(error_buf, error_buf_size, + "out of bounds memory access"); +#else set_error_buf(error_buf, error_buf_size, "data segment does not fit"); +#endif return false; } @@ -820,24 +911,39 @@ aot_instantiate(AOTModule *module, bool is_sub_inst, char *error_buf, uint32 error_buf_size) { AOTModuleInstance *module_inst; - uint32 module_inst_struct_size = + const uint32 module_inst_struct_size = offsetof(AOTModuleInstance, global_table_data.bytes); - uint64 module_inst_mem_inst_size = + const uint64 module_inst_mem_inst_size = (uint64)module->memory_count * sizeof(AOTMemoryInstance); - uint32 table_size = module->table_count > 0 ? - module->tables[0].table_init_size : 0; - uint64 table_data_size = (uint64)table_size * sizeof(uint32); - uint64 total_size = (uint64)module_inst_struct_size - + module_inst_mem_inst_size - + module->global_data_size - + table_data_size; + uint64 total_size, table_size = 0; uint8 *p; + uint32 i; /* Check heap size */ heap_size = align_uint(heap_size, 8); if (heap_size > APP_HEAP_SIZE_MAX) heap_size = APP_HEAP_SIZE_MAX; + total_size = (uint64)module_inst_struct_size + module_inst_mem_inst_size + + module->global_data_size; + + /* + * calculate size of table data + */ + for (i = 0; i != module->import_table_count; ++i) { + table_size += offsetof(AOTTableInstance, data); + table_size += + (uint64)sizeof(uint32) + * (uint64)aot_get_imp_tbl_data_slots(module->import_tables + i); + } + + for (i = 0; i != module->table_count; ++i) { + table_size += offsetof(AOTTableInstance, data); + table_size += (uint64)sizeof(uint32) + * (uint64)aot_get_tbl_data_slots(module->tables + i); + } + total_size += table_size; + /* Allocate module instance, global data, table data and heap data */ if (!(module_inst = runtime_malloc(total_size, error_buf, error_buf_size))) { @@ -857,10 +963,11 @@ aot_instantiate(AOTModule *module, bool is_sub_inst, /* Initialize table info */ p += module->global_data_size; - module_inst->table_data.ptr = p; - module_inst->table_size = table_size; + module_inst->tables.ptr = p; + module_inst->table_count = + module->table_count + module->import_table_count; /* Set all elements to -1 to mark them as uninitialized elements */ - memset(module_inst->table_data.ptr, -1, (uint32)table_data_size); + memset(module_inst->tables.ptr, 0xff, (uint32)table_size); if (!table_instantiate(module_inst, module, error_buf, error_buf_size)) goto fail; @@ -1254,12 +1361,21 @@ aot_call_function(WASMExecEnv *exec_env, switch (func_type->types[func_type->param_count]) { case VALUE_TYPE_I32: case VALUE_TYPE_F32: +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_FUNCREF: + case VALUE_TYPE_EXTERNREF: +#endif argv_ret++; break; case VALUE_TYPE_I64: case VALUE_TYPE_F64: argv_ret += 2; break; +#if WASM_ENABLE_SIMD != 0 + case VALUE_TYPE_V128: + argv_ret += 4; + break; +#endif - default: bh_assert(0); break; @@ -1326,8 +1442,16 @@ aot_create_exec_env_and_call_function(AOTModuleInstance *module_inst, } #endif +#if WASM_ENABLE_REF_TYPES != 0 + wasm_runtime_prepare_call_function(exec_env, func); +#endif + ret = aot_call_function(exec_env, func, argc, argv); +#if WASM_ENABLE_REF_TYPES != 0 + wasm_runtime_finalize_call_function(exec_env, func, ret, argv); +#endif + #if WASM_ENABLE_THREAD_MGR != 0 /* don't destroy the exec_env if it's searched from the cluster */ if (!existing_exec_env) @@ -1399,6 +1523,9 @@ aot_set_exception_with_id(AOTModuleInstance *module_inst, case EXCE_AUX_STACK_UNDERFLOW: aot_set_exception(module_inst, "wasm auxiliary stack underflow"); break; + case EXCE_OUT_OF_BOUNDS_TABLE_ACCESS: + aot_set_exception(module_inst, "out of bounds table access"); + break; default: break; } @@ -2009,17 +2136,16 @@ aot_invoke_native(WASMExecEnv *exec_env, uint32 func_idx, bool aot_call_indirect(WASMExecEnv *exec_env, - uint32 table_elem_idx, + uint32 tbl_idx, uint32 table_elem_idx, uint32 argc, uint32 *argv) { AOTModuleInstance *module_inst = (AOTModuleInstance*) wasm_runtime_get_module_inst(exec_env); AOTModule *aot_module = (AOTModule*)module_inst->aot_module.ptr; uint32 *func_type_indexes = (uint32*)module_inst->func_type_indexes.ptr; - uint32 *table_data = (uint32*)module_inst->table_data.ptr; + AOTTableInstance *tbl_inst; AOTFuncType *func_type; void **func_ptrs = (void**)module_inst->func_ptrs.ptr, *func_ptr; - uint32 table_size = module_inst->table_size; uint32 func_type_idx, func_idx, ext_ret_count; AOTImportFunc *import_func; const char *signature = NULL; @@ -2036,12 +2162,15 @@ aot_call_indirect(WASMExecEnv *exec_env, return false; } - if (table_elem_idx >= table_size) { + tbl_inst = aot_get_table_inst(module_inst, tbl_idx); + bh_assert(tbl_inst); + + if (table_elem_idx >= tbl_inst->cur_size) { aot_set_exception_with_id(module_inst, EXCE_UNDEFINED_ELEMENT); return false; } - func_idx = table_data[table_elem_idx]; + func_idx = ((uint32*)tbl_inst->data)[table_elem_idx]; if (func_idx == (uint32)-1) { aot_set_exception_with_id(module_inst, EXCE_UNINITIALIZED_ELEMENT); return false; @@ -2122,12 +2251,21 @@ aot_call_indirect(WASMExecEnv *exec_env, switch (func_type->types[func_type->param_count]) { case VALUE_TYPE_I32: case VALUE_TYPE_F32: +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_FUNCREF: + case VALUE_TYPE_EXTERNREF: +#endif argv_ret++; break; case VALUE_TYPE_I64: case VALUE_TYPE_F64: argv_ret += 2; break; +#if WASM_ENABLE_SIMD != 0 + case VALUE_TYPE_V128: + argv_ret += 4; + break; +#endif - default: bh_assert(0); break; @@ -2281,16 +2419,17 @@ aot_get_aux_stack(WASMExecEnv *exec_env, } return false; } - #endif #if (WASM_ENABLE_MEMORY_PROFILING != 0) || (WASM_ENABLE_MEMORY_TRACING != 0) -static uint32 const_string_size; - -void const_string_node_size_cb(void *key, void *value) +static void +const_string_node_size_cb(void *key, void *value, + void *p_const_string_size) { + uint32 const_string_size = *(uint32*)p_const_string_size; const_string_size += bh_hash_map_get_elem_struct_size(); const_string_size += strlen((const char *)value) + 1; + *(uint32*)p_const_string_size += const_string_size; } void @@ -2343,12 +2482,14 @@ aot_get_module_mem_consumption(const AOTModule *module, } if (module->const_str_set) { + uint32 const_string_size = 0; + mem_conspn->const_strs_size = bh_hash_map_get_struct_size(module->const_str_set); - const_string_size = 0; bh_hash_map_traverse(module->const_str_set, - const_string_node_size_cb); + const_string_node_size_cb, + (void*)&const_string_size); mem_conspn->const_strs_size += const_string_size; } @@ -2378,6 +2519,7 @@ void aot_get_module_inst_mem_consumption(const AOTModuleInstance *module_inst, WASMModuleInstMemConsumption *mem_conspn) { + AOTTableInstance *tbl_inst; uint32 i; memset(mem_conspn, 0, sizeof(*mem_conspn)); @@ -2399,7 +2541,12 @@ aot_get_module_inst_mem_consumption(const AOTModuleInstance *module_inst, mem_allocator_get_heap_struct_size(); } - mem_conspn->tables_size = sizeof(uint32) * module_inst->table_size; + tbl_inst = module_inst->tables.ptr; + for (i = 0; i < module_inst->table_count; i++) { + mem_conspn->tables_size += offsetof(AOTTableInstance, data); + mem_conspn->tables_size += sizeof(uint32) * tbl_inst->max_size; + tbl_inst = aot_next_tbl_inst(tbl_inst); + } /* func_ptrs and func_type_indexes */ mem_conspn->functions_size = (sizeof(void *) + sizeof(uint32)) * @@ -2421,6 +2568,144 @@ aot_get_module_inst_mem_consumption(const AOTModuleInstance *module_inst, #endif /* end of (WASM_ENABLE_MEMORY_PROFILING != 0) || (WASM_ENABLE_MEMORY_TRACING != 0) */ +#if WASM_ENABLE_REF_TYPES != 0 +void +aot_drop_table_seg(AOTModuleInstance *module_inst, uint32 tbl_seg_idx) +{ + AOTModule *module = (AOTModule *)module_inst->aot_module.ptr; + AOTTableInitData *tbl_seg = module->table_init_data_list[tbl_seg_idx]; + tbl_seg->is_dropped = true; +} + +void +aot_table_init(AOTModuleInstance *module_inst, + uint32 tbl_idx, uint32 tbl_seg_idx, + uint32 length, uint32 src_offset, uint32 dst_offset) +{ + AOTTableInstance *tbl_inst; + AOTTableInitData *tbl_seg; + const AOTModule *module = module_inst->aot_module.ptr; + + tbl_inst = aot_get_table_inst(module_inst, tbl_idx); + bh_assert(tbl_inst); + + tbl_seg = module->table_init_data_list[tbl_seg_idx]; + bh_assert(tbl_seg); + + if (!length) { + return; + } + + if (length + src_offset > tbl_seg->func_index_count + || dst_offset + length > tbl_inst->cur_size) { + aot_set_exception_with_id(module_inst, + EXCE_OUT_OF_BOUNDS_TABLE_ACCESS); + return; + } + + if (tbl_seg->is_dropped) { + aot_set_exception_with_id(module_inst, + EXCE_OUT_OF_BOUNDS_TABLE_ACCESS); + return; + } + + if (!wasm_elem_is_passive(tbl_seg->mode)) { + aot_set_exception_with_id(module_inst, + EXCE_OUT_OF_BOUNDS_TABLE_ACCESS); + return; + } + + bh_memcpy_s((uint8 *)tbl_inst + offsetof(AOTTableInstance, data) + + dst_offset * sizeof(uint32), + (tbl_inst->cur_size - dst_offset) * sizeof(uint32), + tbl_seg->func_indexes + src_offset, length * sizeof(uint32)); +} + +void +aot_table_copy(AOTModuleInstance *module_inst, + uint32 src_tbl_idx, uint32 dst_tbl_idx, + uint32 length, uint32 src_offset, uint32 dst_offset) +{ + AOTTableInstance *src_tbl_inst, *dst_tbl_inst; + + src_tbl_inst = aot_get_table_inst(module_inst, src_tbl_idx); + bh_assert(src_tbl_inst); + + dst_tbl_inst = aot_get_table_inst(module_inst, dst_tbl_idx); + bh_assert(dst_tbl_inst); + + if ((uint64)src_offset + length > dst_tbl_inst->cur_size + || (uint64)dst_offset + length > src_tbl_inst->cur_size) { + aot_set_exception_with_id(module_inst, + EXCE_OUT_OF_BOUNDS_TABLE_ACCESS); + return; + } + + /* if src_offset >= dst_offset, copy from front to back */ + /* if src_offset < dst_offset, copy from back to front */ + /* merge all together */ + bh_memcpy_s((uint8 *)(dst_tbl_inst) + offsetof(AOTTableInstance, data) + + dst_offset * sizeof(uint32), + (dst_tbl_inst->cur_size - dst_offset) * sizeof(uint32), + (uint8 *)(src_tbl_inst) + offsetof(AOTTableInstance, data) + + src_offset * sizeof(uint32), + length * sizeof(uint32)); +} + +void +aot_table_fill(AOTModuleInstance *module_inst, uint32 tbl_idx, + uint32 length, uint32 val, uint32 data_offset) +{ + AOTTableInstance *tbl_inst; + + tbl_inst = aot_get_table_inst(module_inst, tbl_idx); + bh_assert(tbl_inst); + + if (data_offset + length > tbl_inst->cur_size) { + aot_set_exception_with_id(module_inst, + EXCE_OUT_OF_BOUNDS_TABLE_ACCESS); + return; + } + + for (; length != 0; data_offset++, length--) { + tbl_inst->data[data_offset] = val; + } +} + +uint32 +aot_table_grow(AOTModuleInstance *module_inst, uint32 tbl_idx, + uint32 inc_entries, uint32 init_val) +{ + uint32 entry_count, i, orig_tbl_sz; + AOTTableInstance *tbl_inst; + + tbl_inst = aot_get_table_inst(module_inst, tbl_idx); + if (!tbl_inst) { + return (uint32)-1; + } + + orig_tbl_sz = tbl_inst->cur_size; + + if (!inc_entries) { + return orig_tbl_sz; + } + + entry_count = tbl_inst->cur_size + inc_entries; + /* prevent from integer overflow */ + if (entry_count < tbl_inst->cur_size || entry_count > tbl_inst->max_size) { + return (uint32)-1; + } + + /* fill in */ + for (i = 0; i < inc_entries; ++i) { + tbl_inst->data[tbl_inst->cur_size + i] = init_val; + } + + tbl_inst->cur_size = entry_count; + return orig_tbl_sz; +} +#endif /* WASM_ENABLE_REF_TYPES != 0 */ + #if (WASM_ENABLE_DUMP_CALL_STACK != 0) || (WASM_ENABLE_PERF_PROFILING != 0) static const char * get_func_name_from_index(const AOTModuleInstance *module_inst, @@ -2551,3 +2836,4 @@ aot_dump_perf_profiling(const AOTModuleInstance *module_inst) } } #endif /* end of WASM_ENABLE_PERF_PROFILING */ + diff --git a/core/iwasm/aot/aot_runtime.h b/core/iwasm/aot/aot_runtime.h index 990523934..f93e8f0c6 100644 --- a/core/iwasm/aot/aot_runtime.h +++ b/core/iwasm/aot/aot_runtime.h @@ -34,6 +34,7 @@ typedef enum AOTExceptionID { EXCE_UNALIGNED_ATOMIC, EXCE_AUX_STACK_OVERFLOW, EXCE_AUX_STACK_UNDERFLOW, + EXCE_OUT_OF_BOUNDS_TABLE_ACCESS, EXCE_NUM, } AOTExceptionID; @@ -251,6 +252,22 @@ typedef struct AOTMemoryInstance { MemBound mem_bound_check_16bytes; } AOTMemoryInstance; +typedef struct AOTTableInstance { + uint32 cur_size; + /* + * only grow in the range of [:max_size) + * if the table is growable, max_size equals to its declared maximum size + * otherwise, max_size equals to its declared minimum size + */ + uint32 max_size; + /* + * +------------------------------+ <--- data + * | ref.func[] or ref.extern[] + * +------------------------------+ + */ + uint32 data[1]; +} AOTTableInstance; + typedef struct AOTModuleInstance { uint32 module_type; @@ -260,9 +277,17 @@ typedef struct AOTModuleInstance { /* global and table info */ uint32 global_data_size; - uint32 table_size; + /* + * the count of AOTTableInstance. + * it includes imported tables and local tables. + * + * TODO: for now we treate imported table like a local table + */ + uint32 table_count; + /* points to global_data */ AOTPointer global_data; - AOTPointer table_data; + /* points to AOTTableInstance[] */ + AOTPointer tables; /* funciton pointer array */ AOTPointer func_ptrs; @@ -288,20 +313,26 @@ typedef struct AOTModuleInstance { AOTPointer aot_module; /* WASI context */ AOTPointer wasi_ctx; + /* function performance profiling info list */ + AOTPointer func_perf_profilings; /* others */ uint32 temp_ret; uint32 llvm_stack; uint32 default_wasm_stack_size; - uint32 __padding; - - /* function performance profiling info list */ - AOTPointer func_perf_profilings; - /* reserved */ - uint32 reserved[8]; + uint32 reserved[11]; + /* + * +------------------------------+ <-- memories.ptr + * | #0 AOTMemoryInstance + * +------------------------------+ <-- global_data.ptr + * | global data + * +------------------------------+ <-- tables.ptr + * | AOTTableInstance[table_count] + * +------------------------------+ + */ union { uint64 _make_it_8_byte_aligned_; AOTMemoryInstance memory_instances[1]; @@ -561,7 +592,7 @@ aot_invoke_native(WASMExecEnv *exec_env, uint32 func_idx, bool aot_call_indirect(WASMExecEnv *exec_env, - uint32 table_elem_idx, + uint32 tbl_idx, uint32 table_elem_idx, uint32 argc, uint32 *argv); uint32 @@ -608,6 +639,32 @@ void aot_get_module_inst_mem_consumption(const AOTModuleInstance *module_inst, WASMModuleInstMemConsumption *mem_conspn); +#if WASM_ENABLE_REF_TYPES != 0 +void +aot_drop_table_seg(AOTModuleInstance *module_inst, uint32 tbl_seg_idx); + +void +aot_table_init(AOTModuleInstance *module_inst, + uint32 tbl_idx, uint32 tbl_seg_idx, + uint32 length, uint32 src_offset, uint32 dst_offset); + +void +aot_table_copy(AOTModuleInstance *module_inst, + uint32 src_tbl_idx, uint32 dst_tbl_idx, + uint32 length, uint32 src_offset, uint32 dst_offset); + +void +aot_table_fill(AOTModuleInstance *module_inst, uint32 tbl_idx, + uint32 length, uint32 val, uint32 data_offset); + +uint32 +aot_table_grow(AOTModuleInstance *module_inst, uint32 tbl_idx, + uint32 inc_entries, uint32 init_val); +#endif + +AOTTableInstance * +aot_next_tbl_inst(const AOTTableInstance *tbl_inst); + bool aot_alloc_frame(WASMExecEnv *exec_env, uint32 func_index); diff --git a/core/iwasm/common/wasm_exec_env.h b/core/iwasm/common/wasm_exec_env.h index df6131209..f101504dd 100644 --- a/core/iwasm/common/wasm_exec_env.h +++ b/core/iwasm/common/wasm_exec_env.h @@ -116,6 +116,10 @@ typedef struct WASMExecEnv { WASMJmpBuf *jmpbuf_stack_top; #endif +#if WASM_ENABLE_REF_TYPES != 0 + uint16 nested_calling_depth; +#endif + #if WASM_ENABLE_MEMORY_PROFILING != 0 uint32 max_wasm_stack_used; #endif diff --git a/core/iwasm/common/wasm_native.c b/core/iwasm/common/wasm_native.c index fb64c6495..1522b95e7 100644 --- a/core/iwasm/common/wasm_native.c +++ b/core/iwasm/common/wasm_native.c @@ -74,7 +74,13 @@ check_symbol_signature(const WASMType *type, const char *signature) for (i = 0; i < type->param_count; i++) { sig = *p++; - if (sig == sig_map[type->types[i] - VALUE_TYPE_F64]) + if ((type->types[i] >= VALUE_TYPE_F64 + && type->types[i] <= VALUE_TYPE_I32 + && sig == sig_map[type->types[i] - VALUE_TYPE_F64]) +#if WASM_ENABLE_REF_TYPES != 0 + || (sig == 'i' && type->types[i] == VALUE_TYPE_EXTERNREF) +#endif + ) /* normal parameter */ continue; diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index e2721301c..82f8a0f8c 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -49,6 +49,16 @@ static void wasm_runtime_destroy_registered_module_list(); #endif /* WASM_ENABLE_MULTI_MODULE */ +#if WASM_ENABLE_REF_TYPES != 0 +/* Initialize externref hashmap */ +static bool +wasm_externref_map_init(); + +/* Destroy externref hashmap */ +static void +wasm_externref_map_destroy(); +#endif /* WASM_ENABLE_REF_TYPES */ + static void set_error_buf(char *error_buf, uint32 error_buf_size, const char *string) { @@ -119,10 +129,20 @@ wasm_runtime_env_init() #endif #endif +#if WASM_ENABLE_REF_TYPES != 0 + if (!wasm_externref_map_init()) { + goto fail7; + } +#endif + return true; +#if WASM_ENABLE_REF_TYPES != 0 +fail7: +#endif #if WASM_ENABLE_AOT != 0 #ifdef OS_ENABLE_HW_BOUND_CHECK + aot_signal_destroy(); fail6: #endif #endif @@ -175,6 +195,10 @@ wasm_runtime_init() void wasm_runtime_destroy() { +#if WASM_ENABLE_REF_TYPES != 0 + wasm_externref_map_destroy(); +#endif + #if WASM_ENABLE_AOT != 0 #ifdef OS_ENABLE_HW_BOUND_CHECK aot_signal_destroy(); @@ -997,10 +1021,35 @@ wasm_runtime_get_user_data(WASMExecEnv *exec_env) return exec_env->user_data; } +WASMType * +wasm_runtime_get_function_type(const WASMFunctionInstanceCommon *function, + uint32 module_type) +{ + WASMType *type = NULL; + +#if WASM_ENABLE_INTERP != 0 + if (module_type == Wasm_Module_Bytecode) { + WASMFunctionInstance *wasm_func = (WASMFunctionInstance *)function; + type = wasm_func->is_import_func + ? wasm_func->u.func_import->func_type + : wasm_func->u.func->func_type; + } +#endif +#if WASM_ENABLE_AOT != 0 + if (module_type == Wasm_Module_AoT) { + AOTFunctionInstance *aot_func = (AOTFunctionInstance *)function; + type = aot_func->is_import_func + ? aot_func->u.func_import->func_type + : aot_func->u.func.func_type; + } +#endif + + return type; +} + WASMFunctionInstanceCommon * wasm_runtime_lookup_function(WASMModuleInstanceCommon * const module_inst, - const char *name, - const char *signature) + const char *name, const char *signature) { #if WASM_ENABLE_INTERP != 0 if (module_inst->module_type == Wasm_Module_Bytecode) @@ -1017,11 +1066,57 @@ wasm_runtime_lookup_function(WASMModuleInstanceCommon * const module_inst, return NULL; } +#if WASM_ENABLE_REF_TYPES != 0 +static void +wasm_runtime_reclaim_externref(WASMExecEnv *exec_env, + WASMFunctionInstanceCommon *function, + uint32 *argv) +{ + uint32 i = 0, cell_num = 0; + WASMType *func_type = wasm_runtime_get_function_type( + function, exec_env->module_inst->module_type); + bh_assert(func_type); + + while (i < func_type->result_count) { + uint8 result_type = func_type->types[func_type->param_count + i]; + if (result_type == VALUE_TYPE_EXTERNREF && argv[i] != NULL_REF) { + /* Retain the externref returned to runtime embedder */ + (void)wasm_externref_retain(argv[i]); + } + + cell_num += wasm_value_type_cell_num(result_type); + i++; + } + + wasm_externref_reclaim(exec_env->module_inst); +} + +void +wasm_runtime_prepare_call_function(WASMExecEnv *exec_env, + WASMFunctionInstanceCommon *function) +{ + exec_env->nested_calling_depth++; +} + +void +wasm_runtime_finalize_call_function(WASMExecEnv *exec_env, + WASMFunctionInstanceCommon *function, + bool ret, uint32 *argv) +{ + exec_env->nested_calling_depth--; + if (!exec_env->nested_calling_depth && ret) { + wasm_runtime_reclaim_externref(exec_env, function, argv); + } +} +#endif + bool wasm_runtime_call_wasm(WASMExecEnv *exec_env, WASMFunctionInstanceCommon *function, uint32 argc, uint32 argv[]) { + bool ret = false; + if (!wasm_runtime_exec_env_check(exec_env)) { LOG_ERROR("Invalid exec env stack info."); return false; @@ -1030,19 +1125,28 @@ wasm_runtime_call_wasm(WASMExecEnv *exec_env, /* set thread handle and stack boundary */ wasm_exec_env_set_thread_info(exec_env); +#if WASM_ENABLE_REF_TYPES != 0 + wasm_runtime_prepare_call_function(exec_env, function); +#endif + #if WASM_ENABLE_INTERP != 0 if (exec_env->module_inst->module_type == Wasm_Module_Bytecode) - return wasm_call_function(exec_env, + ret = wasm_call_function(exec_env, (WASMFunctionInstance*)function, argc, argv); #endif #if WASM_ENABLE_AOT != 0 if (exec_env->module_inst->module_type == Wasm_Module_AoT) - return aot_call_function(exec_env, + ret = aot_call_function(exec_env, (AOTFunctionInstance*)function, argc, argv); #endif - return false; + +#if WASM_ENABLE_REF_TYPES != 0 + wasm_runtime_finalize_call_function(exec_env, function, ret, argv); +#endif + + return ret; } static uint32 @@ -1142,32 +1246,21 @@ wasm_runtime_call_wasm_a(WASMExecEnv *exec_env, uint32 num_results, wasm_val_t results[], uint32 num_args, wasm_val_t args[]) { - uint32 argc, *argv, ret_num, cell_num, total_size; + uint32 argc, *argv, ret_num, cell_num, total_size, module_type; + WASMType *type; bool ret = false; - WASMType *type = NULL; -#if WASM_ENABLE_INTERP != 0 - if (exec_env->module_inst->module_type == Wasm_Module_Bytecode) { - WASMFunctionInstance *wasm_func = (WASMFunctionInstance*)function; - type = wasm_func->u.func->func_type; - argc = wasm_func->param_cell_num; - cell_num = argc > wasm_func->ret_cell_num ? - argc : wasm_func->ret_cell_num; - } -#endif -#if WASM_ENABLE_AOT != 0 - if (exec_env->module_inst->module_type == Wasm_Module_AoT) { - type = ((AOTFunctionInstance*)function)->u.func.func_type; - argc = type->param_cell_num; - cell_num = argc > type->ret_cell_num ? - argc : type->ret_cell_num; - } -#endif + module_type = exec_env->module_inst->module_type; + type = wasm_runtime_get_function_type(function, module_type); + if (!type) { LOG_ERROR("Function type get failed, WAMR Interpreter and AOT must be enabled at least one."); goto fail1; } + argc = type->param_cell_num; + cell_num = (argc > type->ret_cell_num) ? argc : type->ret_cell_num; + if (num_results != type->result_count) { LOG_ERROR("The result value number does not match the function declaration."); goto fail1; @@ -1207,27 +1300,21 @@ wasm_runtime_call_wasm_v(WASMExecEnv *exec_env, wasm_val_t *args = NULL; WASMType *type = NULL; bool ret = false; - uint32 i = 0; + uint32 i = 0, module_type; va_list vargs; -#if WASM_ENABLE_INTERP != 0 - if (exec_env->module_inst->module_type == Wasm_Module_Bytecode) { - WASMFunctionInstance *wasm_func = (WASMFunctionInstance*)function; - type = wasm_func->u.func->func_type; - } -#endif -#if WASM_ENABLE_AOT != 0 - if (exec_env->module_inst->module_type == Wasm_Module_AoT) { - type = ((AOTFunctionInstance*)function)->u.func.func_type; - } -#endif + module_type = exec_env->module_inst->module_type; + type = wasm_runtime_get_function_type(function, module_type); + if (!type) { - LOG_ERROR("Function type get failed, WAMR Interpreter and AOT must be enabled at least one."); + LOG_ERROR("Function type get failed, WAMR Interpreter and AOT " + "must be enabled at least one."); goto fail1; } if (num_args != type->param_count) { - LOG_ERROR("The argument value number does not match the function declaration."); + LOG_ERROR("The argument value number does not match the " + "function declaration."); goto fail1; } if (!(args = runtime_malloc(sizeof(wasm_val_t) * num_args, NULL, NULL, 0))) { @@ -1260,7 +1347,8 @@ wasm_runtime_call_wasm_v(WASMExecEnv *exec_env, } } va_end(vargs); - ret = wasm_runtime_call_wasm_a(exec_env, function, num_results, results, num_args, args); + ret = wasm_runtime_call_wasm_a(exec_env, function, num_results, results, + num_args, args); wasm_runtime_free(args); fail1: @@ -1272,21 +1360,21 @@ wasm_runtime_create_exec_env_and_call_wasm(WASMModuleInstanceCommon *module_inst WASMFunctionInstanceCommon *function, uint32 argc, uint32 argv[]) { + bool ret = false; + #if WASM_ENABLE_INTERP != 0 if (module_inst->module_type == Wasm_Module_Bytecode) - return wasm_create_exec_env_and_call_function( - (WASMModuleInstance*)module_inst, - (WASMFunctionInstance*)function, - argc, argv); + ret = wasm_create_exec_env_and_call_function( + (WASMModuleInstance *)module_inst, (WASMFunctionInstance *)function, + argc, argv); #endif #if WASM_ENABLE_AOT != 0 if (module_inst->module_type == Wasm_Module_AoT) - return aot_create_exec_env_and_call_function( - (AOTModuleInstance*)module_inst, - (AOTFunctionInstance*)function, - argc, argv); + ret = aot_create_exec_env_and_call_function( + (AOTModuleInstance *)module_inst, (AOTFunctionInstance *)function, + argc, argv); #endif - return false; + return ret; } void @@ -2192,8 +2280,8 @@ wasm_application_execute_main(WASMModuleInstanceCommon *module_inst, uint32 argv_buf_offset = 0; int32 i; char *argv_buf, *p, *p_end; - uint32 *argv_offsets; - bool ret; + uint32 *argv_offsets, module_type; + bool ret, is_import_func = true; #if WASM_ENABLE_LIBC_WASI != 0 if (wasm_runtime_is_wasi_mode(module_inst)) { @@ -2219,19 +2307,24 @@ wasm_application_execute_main(WASMModuleInstanceCommon *module_inst, #if WASM_ENABLE_INTERP != 0 if (module_inst->module_type == Wasm_Module_Bytecode) { - if (((WASMFunctionInstance*)func)->is_import_func) { - wasm_runtime_set_exception(module_inst, - "lookup main function failed"); - return false; - } - func_type = ((WASMFunctionInstance*)func)->u.func->func_type; + is_import_func = ((WASMFunctionInstance*)func)->is_import_func; } #endif #if WASM_ENABLE_AOT != 0 - if (module_inst->module_type == Wasm_Module_AoT) - func_type = ((AOTFunctionInstance*)func)->u.func.func_type; + if (module_inst->module_type == Wasm_Module_AoT) { + is_import_func = ((AOTFunctionInstance*)func)->is_import_func; + } #endif + if (is_import_func) { + wasm_runtime_set_exception(module_inst, + "lookup main function failed"); + return false; + } + + module_type = module_inst->module_type; + func_type = wasm_runtime_get_function_type(func, module_type); + if (!func_type) { LOG_ERROR("invalid module instance type"); return false; @@ -2462,7 +2555,7 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, WASMFunctionInstanceCommon *func; WASMType *type = NULL; uint32 argc1, *argv1 = NULL, cell_num = 0, j, k = 0; - int32 i, p; + int32 i, p, module_type; uint64 total_size; const char *exception; char buf[128]; @@ -2489,22 +2582,12 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, wasm_runtime_set_exception(module_inst, buf); goto fail; } - type = wasm_func->is_import_func ? wasm_func->u.func_import->func_type - : wasm_func->u.func->func_type; - argc1 = wasm_func->param_cell_num; - cell_num = argc1 > wasm_func->ret_cell_num ? - argc1 : wasm_func->ret_cell_num; - } -#endif -#if WASM_ENABLE_AOT != 0 - if (module_inst->module_type == Wasm_Module_AoT) { - type = ((AOTFunctionInstance*)func)->u.func.func_type; - argc1 = type->param_cell_num; - cell_num = argc1 > type->ret_cell_num ? - argc1 : type->ret_cell_num; } #endif + module_type = module_inst->module_type; + type = wasm_runtime_get_function_type(func, module_type); + if (!type) { LOG_ERROR("invalid module instance type"); return false; @@ -2516,6 +2599,9 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, goto fail; } + argc1 = type->param_cell_num; + cell_num = (argc1 > type->ret_cell_num) ? argc1 : type->ret_cell_num; + total_size = sizeof(uint32) * (uint64)(cell_num > 2 ? cell_num : 2); if ((!(argv1 = runtime_malloc((uint32)total_size, module_inst, NULL, 0)))) { @@ -2619,6 +2705,38 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, break; } #endif /* WASM_ENABLE_SIMD != 0 */ +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_FUNCREF: + { + if (strncasecmp(argv[i], "null", 4) == 0) { + argv1[p++] = NULL_REF; + } + else { + argv1[p++] = (uint32)strtoul(argv[i], &endptr, 0); + } + break; + } + case VALUE_TYPE_EXTERNREF: + { + if (strncasecmp(argv[i], "null", 4) == 0) { + argv1[p++] = NULL_REF; + } + else { + uint64 val = strtoull(argv[i], &endptr, 0); + void *extern_obj = (void *)(uintptr_t)val; + uint32 externref_idx; + + if (!wasm_externref_obj2ref(module_inst, extern_obj, + &externref_idx)) { + wasm_runtime_set_exception( + module_inst, "map extern object to ref failed"); + goto fail; + } + argv1[p++] = externref_idx; + } + break; + } +#endif /* WASM_ENABLE_REF_TYPES */ default: bh_assert(0); break; @@ -2666,9 +2784,11 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, break; } case VALUE_TYPE_F32: + { os_printf("%.7g:f32", *(float32*)(argv1 + k)); k++; break; + } case VALUE_TYPE_F64: { union { float64 val; uint32 parts[2]; } u; @@ -2678,6 +2798,31 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, os_printf("%.7g:f64", u.val); break; } +#if WASM_ENABLE_REF_TYPES + case VALUE_TYPE_FUNCREF: + { + if (argv1[k] != NULL_REF) + os_printf("%u:ref.func", argv1[k]); + else + os_printf("func:ref.null"); + k++; + break; + } + case VALUE_TYPE_EXTERNREF: + { + if (argv1[k] != NULL_REF) { + void *extern_obj = NULL; + bool ret = wasm_externref_ref2obj(argv1[k], &extern_obj); + bh_assert(ret); + (void)ret; + os_printf("%p:ref.extern", extern_obj); + } + else + os_printf("extern:ref.null"); + k++; + break; + } +#endif #if WASM_ENABLE_SIMD != 0 case VALUE_TYPE_V128: { @@ -2802,6 +2947,12 @@ wasm_runtime_invoke_native_raw(WASMExecEnv *exec_env, void *func_ptr, case VALUE_TYPE_F32: *(float32*)argv_dst = *(float32*)argv_src++; break; +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_FUNCREF: + case VALUE_TYPE_EXTERNREF: + *(uint32*)argv_dst = *argv_src++; + break; +#endif default: bh_assert(0); break; @@ -2815,6 +2966,10 @@ wasm_runtime_invoke_native_raw(WASMExecEnv *exec_env, void *func_ptr, if (func_type->result_count > 0) { switch (func_type->types[func_type->param_count]) { case VALUE_TYPE_I32: +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_FUNCREF: + case VALUE_TYPE_EXTERNREF: +#endif argv_ret[0] = *(uint32*)argv1; break; case VALUE_TYPE_F32: @@ -2899,6 +3054,10 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, for (i = 0; i < func_type->param_count; i++) { switch (func_type->types[i]) { case VALUE_TYPE_I32: +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_FUNCREF: + case VALUE_TYPE_EXTERNREF: +#endif if (n_ints < MAX_REG_INTS) n_ints++; else @@ -3067,6 +3226,17 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, stacks[n_stacks++] = arg_i32; break; } +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_FUNCREF: + case VALUE_TYPE_EXTERNREF: + { + if (n_ints < MAX_REG_INTS) + ints[n_ints++] = *argv_src++; + else + stacks[n_stacks++] = *argv_src++; + break; + } +#endif case VALUE_TYPE_I64: { if (n_ints < MAX_REG_INTS - 1) { @@ -3204,6 +3374,10 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, else { switch (func_type->types[func_type->param_count]) { case VALUE_TYPE_I32: +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_FUNCREF: + case VALUE_TYPE_EXTERNREF: +#endif argv_ret[0] = (uint32)invokeNative_Int32(func_ptr, argv1, n_stacks); break; case VALUE_TYPE_I64: @@ -3341,6 +3515,10 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, argv1[j++] = *argv++; break; case VALUE_TYPE_F32: +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_FUNCREF: + case VALUE_TYPE_EXTERNREF: +#endif argv1[j++] = *argv++; break; default: @@ -3360,6 +3538,10 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, else { switch (func_type->types[func_type->param_count]) { case VALUE_TYPE_I32: +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_FUNCREF: + case VALUE_TYPE_EXTERNREF: +#endif argv_ret[0] = (uint32)invokeNative_Int32(func_ptr, argv1, argc1); break; case VALUE_TYPE_I64: @@ -3582,6 +3764,15 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, } argv_src += 2; break; +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_FUNCREF: + case VALUE_TYPE_EXTERNREF: + if (n_ints < MAX_REG_INTS) + ints[n_ints++] = *argv_src++; + else + stacks[n_stacks++] = *argv_src++; + break; +#endif #if WASM_ENABLE_SIMD != 0 case VALUE_TYPE_V128: if (n_fps < MAX_REG_FLOATS) { @@ -3617,6 +3808,10 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, /* Invoke the native function and get the first result value */ switch (func_type->types[func_type->param_count]) { case VALUE_TYPE_I32: +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_FUNCREF: + case VALUE_TYPE_EXTERNREF: +#endif argv_ret[0] = (uint32)invokeNative_Int32(func_ptr, argv1, n_stacks); break; case VALUE_TYPE_I64: @@ -3670,11 +3865,11 @@ wasm_runtime_call_indirect(WASMExecEnv *exec_env, #if WASM_ENABLE_INTERP != 0 if (exec_env->module_inst->module_type == Wasm_Module_Bytecode) - return wasm_call_indirect(exec_env, element_indices, argc, argv); + return wasm_call_indirect(exec_env, 0, element_indices, argc, argv); #endif #if WASM_ENABLE_AOT != 0 if (exec_env->module_inst->module_type == Wasm_Module_AoT) - return aot_call_indirect(exec_env, element_indices, argc, argv); + return aot_call_indirect(exec_env, 0, element_indices, argc, argv); #endif return false; } @@ -3795,8 +3990,318 @@ wasm_runtime_join_thread(wasm_thread_t tid, void **retval) return os_thread_join((korp_tid)tid, retval); } +#endif /* end of WASM_ENABLE_THREAD_MGR */ + +#if WASM_ENABLE_REF_TYPES != 0 + +static korp_mutex externref_lock; +static uint32 externref_global_id = 1; +static HashMap *externref_map; + +typedef struct ExternRefMapNode { + /* The extern object from runtime embedder */ + void *extern_obj; + /* The module instance it belongs to */ + WASMModuleInstanceCommon *module_inst; + /* Whether it is retained */ + bool retained; + /* Whether it is marked by runtime */ + bool marked; +} ExternRefMapNode; + +static uint32 +wasm_externref_hash(const void *key) +{ + uint32 externref_idx = (uint32)(uintptr_t)key; + return externref_idx; +} + +static bool +wasm_externref_equal(void *key1, void *key2) +{ + uint32 externref_idx1 = (uint32)(uintptr_t)key1; + uint32 externref_idx2 = (uint32)(uintptr_t)key2; + return externref_idx1 == externref_idx2 ? true : false; +} + +static bool +wasm_externref_map_init() +{ + if (os_mutex_init(&externref_lock) != 0) + return false; + + if (!(externref_map = bh_hash_map_create(32, false, + wasm_externref_hash, + wasm_externref_equal, + NULL, + wasm_runtime_free))) { + os_mutex_destroy(&externref_lock); + return false; + } + + externref_global_id = 1; + return true; +} + +static void +wasm_externref_map_destroy() +{ + bh_hash_map_destroy(externref_map); + os_mutex_destroy(&externref_lock); +} + +typedef struct LookupExtObj_UserData { + ExternRefMapNode node; + bool found; + uint32 externref_idx; +} LookupExtObj_UserData; + +static void +lookup_extobj_callback(void *key, void *value, void *user_data) +{ + uint32 externref_idx = (uint32)(uintptr_t)key; + ExternRefMapNode *node = (ExternRefMapNode *)value; + LookupExtObj_UserData *user_data_lookup = (LookupExtObj_UserData *) + user_data; + + if (node->extern_obj == user_data_lookup->node.extern_obj + && node->module_inst == user_data_lookup->node.module_inst) { + user_data_lookup->found = true; + user_data_lookup->externref_idx = externref_idx; + } +} + +bool +wasm_externref_obj2ref(WASMModuleInstanceCommon *module_inst, + void *extern_obj, uint32 *p_externref_idx) +{ + LookupExtObj_UserData lookup_user_data; + ExternRefMapNode *node; + uint32 externref_idx; + + lookup_user_data.node.extern_obj = extern_obj; + lookup_user_data.node.module_inst = module_inst; + lookup_user_data.found = false; + + os_mutex_lock(&externref_lock); + + /* Lookup hashmap firstly */ + bh_hash_map_traverse(externref_map, lookup_extobj_callback, + (void*)&lookup_user_data); + if (lookup_user_data.found) { + *p_externref_idx = lookup_user_data.externref_idx; + os_mutex_unlock(&externref_lock); + return true; + } + + /* Not found in hashmap */ + if (externref_global_id == NULL_REF + || externref_global_id == 0) { + goto fail1; + } + + if (!(node = wasm_runtime_malloc(sizeof(ExternRefMapNode)))) { + goto fail1; + } + + memset(node, 0, sizeof(ExternRefMapNode)); + node->extern_obj = extern_obj; + node->module_inst = module_inst; + + externref_idx = externref_global_id; + + if (!bh_hash_map_insert(externref_map, + (void*)(uintptr_t)externref_idx, + (void*)node)) { + goto fail2; + } + + externref_global_id++; + *p_externref_idx = externref_idx; + os_mutex_unlock(&externref_lock); + return true; +fail2: + wasm_runtime_free(node); +fail1: + os_mutex_unlock(&externref_lock); + return false; +} + +bool +wasm_externref_ref2obj(uint32 externref_idx, void **p_extern_obj) +{ + ExternRefMapNode *node; + + if (externref_idx == NULL_REF) { + return false; + } + + os_mutex_lock(&externref_lock); + node = bh_hash_map_find(externref_map, + (void*)(uintptr_t)externref_idx); + os_mutex_unlock(&externref_lock); + + if (!node) + return false; + + *p_extern_obj = node->extern_obj; + return true; +} + +static void +reclaim_extobj_callback(void *key, void *value, void *user_data) +{ + ExternRefMapNode *node = (ExternRefMapNode *)value; + WASMModuleInstanceCommon *module_inst = (WASMModuleInstanceCommon *) + user_data; + + if (node->module_inst == module_inst) { + if (!node->marked && !node->retained) { + bh_hash_map_remove(externref_map, key, NULL, NULL); + wasm_runtime_free(value); + } + else { + node->marked = false; + } + } +} + +static void +mark_externref(uint32 externref_idx) +{ + ExternRefMapNode *node; + + if (externref_idx != NULL_REF) { + node = bh_hash_map_find(externref_map, + (void*)(uintptr_t)externref_idx); + if (node) { + node->marked = true; + } + } +} + +#if WASM_ENABLE_INTERP != 0 +static void +interp_mark_all_externrefs(WASMModuleInstance *module_inst) +{ + uint32 i, j, externref_idx, *table_data; + uint8 *global_data = module_inst->global_data; + WASMGlobalInstance *global; + WASMTableInstance *table; + + global = module_inst->globals; + for (i = 0; i < module_inst->global_count; i++, global++) { + if (global->type == VALUE_TYPE_EXTERNREF) { + externref_idx = *(uint32*)(global_data + global->data_offset); + mark_externref(externref_idx); + } + } + + for (i = 0; i < module_inst->table_count; i++) { + table = wasm_get_table_inst(module_inst, i); + if (table->elem_type == VALUE_TYPE_EXTERNREF) { + table_data = (uint32 *)table->base_addr; + for (j = 0; j < table->cur_size; j++) { + externref_idx = table_data[j]; + mark_externref(externref_idx); + } + } + } +} #endif +#if WASM_ENABLE_AOT != 0 +static void +aot_mark_all_externrefs(AOTModuleInstance *module_inst) +{ + uint32 i = 0, j = 0; + const AOTModule *module = (AOTModule *)(module_inst->aot_module.ptr); + const AOTTable *table = module->tables; + const AOTGlobal *global = module->globals; + const AOTTableInstance *table_inst = + (AOTTableInstance *)module_inst->tables.ptr; + + for (i = 0; i < module->global_count; i++, global++) { + if (global->type == VALUE_TYPE_EXTERNREF) { + mark_externref(*(uint32 *)((uint8 *)module_inst->global_data.ptr + + global->data_offset)); + } + } + + for (i = 0; i < module->table_count; + i++, table_inst = aot_next_tbl_inst(table_inst)) { + + if ((table + i)->elem_type == VALUE_TYPE_EXTERNREF) { + while (j < table_inst->cur_size) { + mark_externref(table_inst->data[j++]); + } + } + } +} +#endif + +void +wasm_externref_reclaim(WASMModuleInstanceCommon *module_inst) +{ + os_mutex_lock(&externref_lock); +#if WASM_ENABLE_INTERP != 0 + if (module_inst->module_type == Wasm_Module_Bytecode) + interp_mark_all_externrefs((WASMModuleInstance*)module_inst); +#endif +#if WASM_ENABLE_AOT != 0 + if (module_inst->module_type == Wasm_Module_AoT) + aot_mark_all_externrefs((AOTModuleInstance*)module_inst); +#endif + + bh_hash_map_traverse(externref_map, reclaim_extobj_callback, + (void*)module_inst); + os_mutex_unlock(&externref_lock); +} + +static void +cleanup_extobj_callback(void *key, void *value, void *user_data) +{ + ExternRefMapNode *node = (ExternRefMapNode *)value; + WASMModuleInstanceCommon *module_inst = (WASMModuleInstanceCommon *) + user_data; + + if (node->module_inst == module_inst) { + bh_hash_map_remove(externref_map, key, NULL, NULL); + wasm_runtime_free(value); + } +} + +void +wasm_externref_cleanup(WASMModuleInstanceCommon *module_inst) +{ + os_mutex_lock(&externref_lock); + bh_hash_map_traverse(externref_map, cleanup_extobj_callback, + (void*)module_inst); + os_mutex_unlock(&externref_lock); +} + +bool +wasm_externref_retain(uint32 externref_idx) +{ + ExternRefMapNode *node; + + os_mutex_lock(&externref_lock); + + if (externref_idx != NULL_REF) { + node = bh_hash_map_find(externref_map, + (void*)(uintptr_t)externref_idx); + if (node) { + node->retained = true; + os_mutex_unlock(&externref_lock); + return true; + } + } + + os_mutex_unlock(&externref_lock); + return false; +} +#endif /* end of WASM_ENABLE_REF_TYPES */ + #if WASM_ENABLE_DUMP_CALL_STACK != 0 void wasm_runtime_dump_call_stack(WASMExecEnv *exec_env) @@ -3815,3 +4320,4 @@ wasm_runtime_dump_call_stack(WASMExecEnv *exec_env) #endif } #endif /* end of WASM_ENABLE_DUMP_CALL_STACK */ + diff --git a/core/iwasm/common/wasm_runtime_common.h b/core/iwasm/common/wasm_runtime_common.h index d61df2751..01a0c21be 100644 --- a/core/iwasm/common/wasm_runtime_common.h +++ b/core/iwasm/common/wasm_runtime_common.h @@ -352,7 +352,6 @@ wasm_runtime_destroy(void); WASM_RUNTIME_API_EXTERN PackageType get_package_type(const uint8 *buf, uint32 size); - /* See wasm_export.h for description */ WASM_RUNTIME_API_EXTERN WASMModuleCommon * wasm_runtime_load(const uint8 *buf, uint32 size, @@ -393,6 +392,11 @@ WASM_RUNTIME_API_EXTERN WASMFunctionInstanceCommon * wasm_runtime_lookup_function(WASMModuleInstanceCommon * const module_inst, const char *name, const char *signature); +/* Internal API */ +WASMType * +wasm_runtime_get_function_type(const WASMFunctionInstanceCommon *function, + uint32 module_type); + /* See wasm_export.h for description */ WASM_RUNTIME_API_EXTERN WASMExecEnv * wasm_runtime_create_exec_env(WASMModuleInstanceCommon *module_inst, @@ -651,6 +655,34 @@ wasm_runtime_get_wasi_ctx(WASMModuleInstanceCommon *module_inst); #endif /* end of WASM_ENABLE_LIBC_WASI */ +#if WASM_ENABLE_REF_TYPES != 0 +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN bool +wasm_externref_obj2ref(WASMModuleInstanceCommon *module_inst, + void *extern_obj, uint32 *p_externref_idx); + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN bool +wasm_externref_ref2obj(uint32 externref_idx, void **p_extern_obj); + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN bool +wasm_externref_retain(uint32 externref_idx); + +/** + * Reclaim the externref objects/indexes which are not used by + * module instance + */ +void +wasm_externref_reclaim(WASMModuleInstanceCommon *module_inst); + +/** + * Cleanup the externref objects/indexes of the module instance + */ +void +wasm_externref_cleanup(WASMModuleInstanceCommon *module_inst); +#endif /* end of WASM_ENABLE_REF_TYPES */ + /* Get module of the current exec_env */ WASMModuleCommon* wasm_exec_env_get_module(WASMExecEnv *exec_env); @@ -702,6 +734,16 @@ wasm_runtime_dump_module_inst_mem_consumption(const WASMModuleInstanceCommon void wasm_runtime_dump_exec_env_mem_consumption(const WASMExecEnv *exec_env); +#if WASM_ENABLE_REF_TYPES != 0 +void +wasm_runtime_prepare_call_function(WASMExecEnv *exec_env, + WASMFunctionInstanceCommon *function); +void +wasm_runtime_finalize_call_function(WASMExecEnv *exec_env, + WASMFunctionInstanceCommon *function, + bool ret, uint32 *argv); +#endif + #ifdef __cplusplus } #endif diff --git a/core/iwasm/compilation/aot.c b/core/iwasm/compilation/aot.c index fd127c817..1bb67f3f1 100644 --- a/core/iwasm/compilation/aot.c +++ b/core/iwasm/compilation/aot.c @@ -125,8 +125,18 @@ aot_create_table_init_data_list(const WASMModule *module) data_list[i]->offset = module->table_segments[i].base_offset; data_list[i]->func_index_count = module->table_segments[i].function_count; - memcpy(data_list[i]->func_indexes, module->table_segments[i].func_indexes, - sizeof(uint32) * module->table_segments[i].function_count); + data_list[i]->mode = module->table_segments[i].mode; + data_list[i]->elem_type = module->table_segments[i].elem_type; + /* runtime control it */ + data_list[i]->is_dropped = false; + data_list[i]->table_index = module->table_segments[i].table_index; + bh_memcpy_s(&data_list[i]->offset, sizeof(AOTInitExpr), + &module->table_segments[i].base_offset, sizeof(AOTInitExpr)); + data_list[i]->func_index_count = module->table_segments[i].function_count; + bh_memcpy_s(data_list[i]->func_indexes, + sizeof(uint32) * module->table_segments[i].function_count, + module->table_segments[i].func_indexes, + sizeof(uint32) * module->table_segments[i].function_count); } return data_list; @@ -424,8 +434,6 @@ aot_create_comp_data(WASMModule *module) aot_create_mem_init_data_list(module))) goto fail; - /* TODO: create import tables */ - /* Create tables */ comp_data->table_count = module->import_table_count + module->table_count; @@ -447,6 +455,8 @@ aot_create_comp_data(WASMModule *module) module->import_tables[i].u.table.init_size; comp_data->tables[i].table_max_size = module->import_tables[i].u.table.max_size; + comp_data->tables[i].possible_grow = + module->import_tables[i].u.table.possible_grow; } else { j = i - module->import_table_count; @@ -454,6 +464,7 @@ aot_create_comp_data(WASMModule *module) comp_data->tables[i].table_flags = module->tables[i].flags; comp_data->tables[i].table_init_size = module->tables[i].init_size; comp_data->tables[i].table_max_size = module->tables[i].max_size; + comp_data->tables[i].possible_grow = module->tables[i].possible_grow; } } } diff --git a/core/iwasm/compilation/aot.h b/core/iwasm/compilation/aot.h index 32f8da2c7..015c84a7d 100644 --- a/core/iwasm/compilation/aot.h +++ b/core/iwasm/compilation/aot.h @@ -71,6 +71,7 @@ typedef struct AOTImportTable { uint32 table_flags; uint32 table_init_size; uint32 table_max_size; + bool possible_grow; } AOTImportTable; /** @@ -81,12 +82,19 @@ typedef struct AOTTable { uint32 table_flags; uint32 table_init_size; uint32 table_max_size; + bool possible_grow; } AOTTable; /** * A segment of table init data */ typedef struct AOTTableInitData { + /* 0 to 7 */ + uint32 mode; + /* funcref or externref, elemkind will be considered as funcref */ + uint32 elem_type; + bool is_dropped; + /* optional, only for active */ uint32 table_index; /* Start address of init data */ AOTInitExpr offset; @@ -245,6 +253,18 @@ aot_set_last_error_v(const char *format, ...); } while (0) #endif +static inline uint32 +aot_get_tbl_data_slots(const AOTTable *tbl) +{ + return tbl->possible_grow ? tbl->table_max_size : tbl->table_init_size; +} + +static inline uint32 +aot_get_imp_tbl_data_slots(const AOTImportTable *tbl) +{ + return tbl->possible_grow ? tbl->table_max_size : tbl->table_init_size; +} + #ifdef __cplusplus } /* end of extern "C" */ #endif diff --git a/core/iwasm/compilation/aot_compiler.c b/core/iwasm/compilation/aot_compiler.c index 766ce24d6..781e1f9fb 100644 --- a/core/iwasm/compilation/aot_compiler.c +++ b/core/iwasm/compilation/aot_compiler.c @@ -14,6 +14,7 @@ #include "aot_emit_control.h" #include "aot_emit_function.h" #include "aot_emit_parametric.h" +#include "aot_emit_table.h" #include "simd/simd_access_lanes.h" #include "simd/simd_bitmask_extracts.h" #include "simd/simd_bit_shifts.h" @@ -176,7 +177,9 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index) || value_type == VALUE_TYPE_F32 || value_type == VALUE_TYPE_F64 || value_type == VALUE_TYPE_V128 - || value_type == VALUE_TYPE_VOID) { + || value_type == VALUE_TYPE_VOID + || value_type == VALUE_TYPE_FUNCREF + || value_type == VALUE_TYPE_EXTERNREF) { param_count = 0; param_types = NULL; if (value_type == VALUE_TYPE_VOID) { @@ -258,11 +261,27 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index) break; case WASM_OP_CALL_INDIRECT: + { + uint32 tbl_idx; + read_leb_uint32(frame_ip, frame_ip_end, type_idx); - frame_ip++; /* skip 0x00 */ - if (!aot_compile_op_call_indirect(comp_ctx, func_ctx, type_idx)) + +#if WASM_ENABLE_REF_TYPES != 0 + if (comp_ctx->enable_ref_types) { + read_leb_uint32(frame_ip, frame_ip_end, tbl_idx); + } + else +#endif + { + frame_ip++; + tbl_idx = 0; + } + + if (!aot_compile_op_call_indirect(comp_ctx, func_ctx, type_idx, + tbl_idx)) return false; break; + } #if WASM_ENABLE_TAIL_CALL != 0 case WASM_OP_RETURN_CALL: @@ -278,17 +297,33 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index) break; case WASM_OP_RETURN_CALL_INDIRECT: + { + uint32 tbl_idx; + if (!comp_ctx->enable_tail_call) { aot_set_last_error("unsupported opcode"); return false; } + read_leb_uint32(frame_ip, frame_ip_end, type_idx); - frame_ip++; /* skip 0x00 */ - if (!aot_compile_op_call_indirect(comp_ctx, func_ctx, type_idx)) +#if WASM_ENABLE_REF_TYPES != 0 + if (comp_ctx->enable_ref_types) { + read_leb_uint32(frame_ip, frame_ip_end, tbl_idx); + } + else +#endif + { + frame_ip++; + tbl_idx = 0; + } + + if (!aot_compile_op_call_indirect(comp_ctx, func_ctx, type_idx, + tbl_idx)) return false; if (!aot_compile_op_return(comp_ctx, func_ctx, &frame_ip)) return false; break; + } #endif /* end of WASM_ENABLE_TAIL_CALL */ case WASM_OP_DROP: @@ -311,6 +346,93 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index) return false; break; +#if WASM_ENABLE_REF_TYPES != 0 + case WASM_OP_SELECT_T: + { + uint32 vec_len; + + if (!comp_ctx->enable_ref_types) { + goto unsupport_ref_types; + } + + read_leb_uint32(frame_ip, frame_ip_end, vec_len); + bh_assert(vec_len == 1); + vec_len = vec_len; + + type_idx = *frame_ip++; + if (!aot_compile_op_select(comp_ctx, func_ctx, + (type_idx != VALUE_TYPE_I64) + && (type_idx != VALUE_TYPE_F64))) + return false; + break; + } + case WASM_OP_TABLE_GET: + { + uint32 tbl_idx; + + if (!comp_ctx->enable_ref_types) { + goto unsupport_ref_types; + } + + read_leb_uint32(frame_ip, frame_ip_end, tbl_idx); + if (!aot_compile_op_table_get(comp_ctx, func_ctx, tbl_idx)) + return false; + break; + } + case WASM_OP_TABLE_SET: + { + uint32 tbl_idx; + + if (!comp_ctx->enable_ref_types) { + goto unsupport_ref_types; + } + + read_leb_uint32(frame_ip, frame_ip_end, tbl_idx); + if (!aot_compile_op_table_set(comp_ctx, func_ctx, tbl_idx)) + return false; + break; + } + case WASM_OP_REF_NULL: + { + uint32 type; + + if (!comp_ctx->enable_ref_types) { + goto unsupport_ref_types; + } + + read_leb_uint32(frame_ip, frame_ip_end, type); + + if (!aot_compile_op_ref_null(comp_ctx, func_ctx)) + return false; + + (void)type; + break; + } + case WASM_OP_REF_IS_NULL: + { + if (!comp_ctx->enable_ref_types) { + goto unsupport_ref_types; + } + + if (!aot_compile_op_ref_is_null(comp_ctx, func_ctx)) + return false; + break; + } + case WASM_OP_REF_FUNC: + { + uint32 func_idx; + + if (!comp_ctx->enable_ref_types) { + goto unsupport_ref_types; + } + + read_leb_uint32(frame_ip, frame_ip_end, func_idx); + if (!aot_compile_op_ref_func(comp_ctx, func_ctx, func_idx)) + return false; + break; + } +#endif + case WASM_OP_GET_LOCAL: read_leb_uint32(frame_ip, frame_ip_end, local_idx); if (!aot_compile_op_get_local(comp_ctx, func_ctx, local_idx)) @@ -828,6 +950,15 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index) read_leb_uint32(frame_ip, frame_ip_end, opcode1); opcode = (uint32)opcode1; + //TODO: --enable-bulk-memory ? + +#if WASM_ENABLE_REF_TYPES != 0 + if (WASM_OP_TABLE_INIT <= opcode && opcode <= WASM_OP_TABLE_FILL + && !comp_ctx->enable_ref_types) { + goto unsupport_ref_types; + } +#endif + switch (opcode) { case WASM_OP_I32_TRUNC_SAT_S_F32: case WASM_OP_I32_TRUNC_SAT_U_F32: @@ -886,11 +1017,74 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index) break; } #endif /* WASM_ENABLE_BULK_MEMORY */ - default: +#if WASM_ENABLE_REF_TYPES != 0 + case WASM_OP_TABLE_INIT: + { + uint32 tbl_idx, tbl_seg_idx; + + read_leb_uint32(frame_ip, frame_ip_end, tbl_seg_idx); + read_leb_uint32(frame_ip, frame_ip_end, tbl_idx); + if (!aot_compile_op_table_init(comp_ctx, func_ctx, tbl_idx, + tbl_seg_idx)) + return false; break; + } + case WASM_OP_ELEM_DROP: + { + uint32 tbl_seg_idx; + + read_leb_uint32(frame_ip, frame_ip_end, tbl_seg_idx); + if (!aot_compile_op_elem_drop(comp_ctx, func_ctx, tbl_seg_idx)) + return false; + break; + } + case WASM_OP_TABLE_COPY: + { + uint32 src_tbl_idx, dst_tbl_idx; + + read_leb_uint32(frame_ip, frame_ip_end, dst_tbl_idx); + read_leb_uint32(frame_ip, frame_ip_end, src_tbl_idx); + if (!aot_compile_op_table_copy(comp_ctx, func_ctx, src_tbl_idx, + dst_tbl_idx)) + return false; + break; + } + case WASM_OP_TABLE_GROW: + { + uint32 tbl_idx; + + read_leb_uint32(frame_ip, frame_ip_end, tbl_idx); + if (!aot_compile_op_table_grow(comp_ctx, func_ctx, tbl_idx)) + return false; + break; + } + + case WASM_OP_TABLE_SIZE: + { + uint32 tbl_idx; + + read_leb_uint32(frame_ip, frame_ip_end, tbl_idx); + if (!aot_compile_op_table_size(comp_ctx, func_ctx, tbl_idx)) + return false; + break; + } + case WASM_OP_TABLE_FILL: + { + uint32 tbl_idx; + + read_leb_uint32(frame_ip, frame_ip_end, tbl_idx); + if (!aot_compile_op_table_fill(comp_ctx, func_ctx, tbl_idx)) + return false; + break; + } +#endif /* WASM_ENABLE_REF_TYPES */ + default: + aot_set_last_error("unsupported opcode"); + return false; } break; } + #if WASM_ENABLE_SHARED_MEMORY != 0 case WASM_OP_ATOMIC_PREFIX: { @@ -1030,7 +1224,8 @@ build_atomic_rmw: break; default: - break; + aot_set_last_error("unsupported opcode"); + return false; } break; } @@ -1040,9 +1235,7 @@ build_atomic_rmw: case WASM_OP_SIMD_PREFIX: { if (!comp_ctx->enable_simd) { - aot_set_last_error("SIMD instruction was found, " - "try adding --enable-simd option?"); - return false; + goto unsupport_simd; } opcode = *frame_ip++; @@ -1795,7 +1988,8 @@ build_atomic_rmw: } default: - break; + aot_set_last_error("unsupported opcode"); + return false; } break; } @@ -1803,29 +1997,43 @@ build_atomic_rmw: default: aot_set_last_error("unsupported opcode"); - break; + return false; } } /* Move func_return block to the bottom */ if (func_ctx->func_return_block) { - LLVMBasicBlockRef last_block = - LLVMGetLastBasicBlock(func_ctx->func); - if (last_block != func_ctx->func_return_block) - LLVMMoveBasicBlockAfter(func_ctx->func_return_block, - last_block); + LLVMBasicBlockRef last_block = + LLVMGetLastBasicBlock(func_ctx->func); + if (last_block != func_ctx->func_return_block) + LLVMMoveBasicBlockAfter(func_ctx->func_return_block, + last_block); } /* Move got_exception block to the bottom */ if (func_ctx->got_exception_block) { - LLVMBasicBlockRef last_block = - LLVMGetLastBasicBlock(func_ctx->func); - if (last_block != func_ctx->got_exception_block) - LLVMMoveBasicBlockAfter(func_ctx->got_exception_block, - last_block); + LLVMBasicBlockRef last_block = + LLVMGetLastBasicBlock(func_ctx->func); + if (last_block != func_ctx->got_exception_block) + LLVMMoveBasicBlockAfter(func_ctx->got_exception_block, + last_block); } return true; +#if WASM_ENABLE_SIMD != 0 +unsupport_simd: + aot_set_last_error("SIMD instruction was found, " + "try adding --enable-simd option?"); + return false; +#endif + +#if WASM_ENABLE_REF_TYPES != 0 +unsupport_ref_types: + aot_set_last_error("reference type instruction was found, " + "try adding --enable-ref-types option?"); + return false; +#endif + fail: return false; } diff --git a/core/iwasm/compilation/aot_compiler.h b/core/iwasm/compilation/aot_compiler.h index c1c05cd6c..182e180db 100644 --- a/core/iwasm/compilation/aot_compiler.h +++ b/core/iwasm/compilation/aot_compiler.h @@ -102,6 +102,34 @@ typedef enum FloatArithmetic { FLOAT_MAX } FloatArithmetic; +static inline bool +check_type_compatible(uint8 src_type, uint8 dst_type) +{ + if (src_type == dst_type) { + return true; + } + + /* ext i1 to i32 */ + if (src_type == VALUE_TYPE_I1 && dst_type == VALUE_TYPE_I32) { + return true; + } + + /* i32 <==> func.ref, i32 <==> extern.ref */ + if (src_type == VALUE_TYPE_I32 + && (dst_type == VALUE_TYPE_EXTERNREF + || dst_type == VALUE_TYPE_FUNCREF)) { + return true; + } + + if (dst_type == VALUE_TYPE_I32 + && (src_type == VALUE_TYPE_FUNCREF + || src_type == VALUE_TYPE_EXTERNREF)) { + return true; + } + + return false; +} + #define CHECK_STACK() do { \ if (!func_ctx->block_stack.block_list_end) { \ aot_set_last_error("WASM block stack underflow."); \ @@ -119,11 +147,8 @@ typedef enum FloatArithmetic { CHECK_STACK(); \ aot_value = aot_value_stack_pop \ (&func_ctx->block_stack.block_list_end->value_stack); \ - if ((value_type != VALUE_TYPE_I32 \ - && aot_value->type != value_type) \ - || (value_type == VALUE_TYPE_I32 \ - && (aot_value->type != VALUE_TYPE_I32 \ - && aot_value->type != VALUE_TYPE_I1))) { \ + if (!check_type_compatible(aot_value->type, \ + value_type)) { \ aot_set_last_error("invalid WASM stack data type."); \ wasm_runtime_free(aot_value); \ goto fail; \ @@ -131,12 +156,23 @@ typedef enum FloatArithmetic { if (aot_value->type == value_type) \ llvm_value = aot_value->value; \ else { \ - bh_assert(aot_value->type == VALUE_TYPE_I1); \ - if (!(llvm_value = LLVMBuildZExt(comp_ctx->builder, \ - aot_value->value, I32_TYPE, "i1toi32"))) { \ - aot_set_last_error("invalid WASM stack data type.");\ - wasm_runtime_free(aot_value); \ - goto fail; \ + if (aot_value->type == VALUE_TYPE_I1) { \ + if (!(llvm_value = LLVMBuildZExt(comp_ctx->builder, \ + aot_value->value, I32_TYPE, "i1toi32"))) { \ + aot_set_last_error("invalid WASM stack " \ + "data type."); \ + wasm_runtime_free(aot_value); \ + goto fail; \ + } \ + } \ + else { \ + bh_assert(aot_value->type == VALUE_TYPE_I32 \ + || aot_value->type == VALUE_TYPE_FUNCREF \ + || aot_value->type == VALUE_TYPE_EXTERNREF); \ + bh_assert(value_type == VALUE_TYPE_I32 \ + || value_type == VALUE_TYPE_FUNCREF \ + || value_type == VALUE_TYPE_EXTERNREF); \ + llvm_value = aot_value->value; \ } \ } \ wasm_runtime_free(aot_value); \ @@ -147,6 +183,8 @@ typedef enum FloatArithmetic { #define POP_F32(v) POP(v, VALUE_TYPE_F32) #define POP_F64(v) POP(v, VALUE_TYPE_F64) #define POP_V128(v) POP(v, VALUE_TYPE_V128) +#define POP_FUNCREF(v) POP(v, VALUE_TYPE_FUNCREF) +#define POP_EXTERNREF(v) POP(v, VALUE_TYPE_EXTERNREF) #define POP_COND(llvm_value) do { \ AOTValue *aot_value; \ @@ -198,6 +236,8 @@ typedef enum FloatArithmetic { #define PUSH_F64(v) PUSH(v, VALUE_TYPE_F64) #define PUSH_V128(v) PUSH(v, VALUE_TYPE_V128) #define PUSH_COND(v) PUSH(v, VALUE_TYPE_I1) +#define PUSH_FUNCREF(v) PUSH(v, VALUE_TYPE_FUNCREF) +#define PUSH_EXTERNREF(v) PUSH(v, VALUE_TYPE_EXTERNREF) #define TO_LLVM_TYPE(wasm_type) \ wasm_type_to_llvm_type(&comp_ctx->basic_types, wasm_type) @@ -217,6 +257,8 @@ typedef enum FloatArithmetic { #define INT64_PTR_TYPE comp_ctx->basic_types.int64_ptr_type #define F32_PTR_TYPE comp_ctx->basic_types.float32_ptr_type #define F64_PTR_TYPE comp_ctx->basic_types.float64_ptr_type +#define FUNC_REF_TYPE comp_ctx->basic_types.funcref_type +#define EXTERN_REF_TYPE comp_ctx->basic_types.externref_type #define I32_CONST(v) LLVMConstInt(I32_TYPE, v, true) #define I64_CONST(v) LLVMConstInt(I64_TYPE, v, true) @@ -263,6 +305,8 @@ typedef enum FloatArithmetic { #define V128_f32x4_ZERO (comp_ctx->llvm_consts.f32x4_vec_zero) #define V128_f64x2_ZERO (comp_ctx->llvm_consts.f64x2_vec_zero) +#define REF_NULL (comp_ctx->llvm_consts.i32_neg_one) + #define TO_V128_i8x16(v) LLVMBuildBitCast(comp_ctx->builder, v, \ V128_i8x16_TYPE, "i8x16_val") #define TO_V128_i16x8(v) LLVMBuildBitCast(comp_ctx->builder, v, \ @@ -283,6 +327,36 @@ typedef enum FloatArithmetic { } \ } while (0) +#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_wasm(AOTCompContext *comp_ctx); diff --git a/core/iwasm/compilation/aot_emit_aot_file.c b/core/iwasm/compilation/aot_emit_aot_file.c index 58cc4b4a9..8102f846c 100644 --- a/core/iwasm/compilation/aot_emit_aot_file.c +++ b/core/iwasm/compilation/aot_emit_aot_file.c @@ -183,9 +183,13 @@ get_mem_info_size(AOTCompData *comp_data) static uint32 get_table_init_data_size(AOTTableInitData *table_init_data) { - /* table_index + init expr type (4 bytes) + init expr value (8 bytes) - + func index count (4 bytes) + func indexes */ - return (uint32)(sizeof(uint32) + sizeof(uint32) + /* + * mode (4 bytes), elem_type (4 bytes), do not need is_dropped field + * + * table_index(4 bytes) + init expr type (4 bytes) + init expr value (8 bytes) + * + func index count (4 bytes) + func indexes + */ + return (uint32)(sizeof(uint32) * 2 + sizeof(uint32) + sizeof(uint32) + sizeof(uint64) + sizeof(uint32) + sizeof(uint32) * table_init_data->func_index_count); } @@ -194,9 +198,24 @@ static uint32 get_table_init_data_list_size(AOTTableInitData **table_init_data_list, uint32 table_init_data_count) { + /* + * ------------------------------ + * | table_init_data_count + * ------------------------------ + * | | U32 mode + * | AOTTableInitData[N] | U32 elem_type + * | | U32 table_index + * | | U32 offset.init_expr_type + * | | U64 offset.u.i64 + * | | U32 func_index_count + * | | U32[func_index_count] + * ------------------------------ + */ AOTTableInitData **table_init_data = table_init_data_list; uint32 size = 0, i; + size = (uint32)sizeof(uint32); + for (i = 0; i < table_init_data_count; i++, table_init_data++) { size = align_uint(size, 4); size += get_table_init_data_size(*table_init_data); @@ -207,27 +226,66 @@ get_table_init_data_list_size(AOTTableInitData **table_init_data_list, static uint32 get_import_table_size(AOTCompData *comp_data) { - /* currently we only emit import_table_count = 0 */ - return sizeof(uint32); + /* + * ------------------------------ + * | import_table_count + * ------------------------------ + * | | U32 table_init_size + * | | ---------------------- + * | AOTImpotTable[N] | U32 table_init_size + * | | ---------------------- + * | | U32 possible_grow (convenient than U8) + * ------------------------------ + */ + return (uint32)(sizeof(uint32) + + comp_data->import_table_count + * (sizeof(uint32) * 3)); } static uint32 get_table_size(AOTCompData *comp_data) { - /* table_count + table_count * (elem_type + table_flags - * + init_size + max_size) */ + /* + * ------------------------------ + * | table_count + * ------------------------------ + * | | U32 elem_type + * | AOTTable[N] | U32 table_flags + * | | U32 table_init_size + * | | U32 table_max_size + * | | U32 possible_grow (convenient than U8) + * ------------------------------ + */ return (uint32)(sizeof(uint32) - + comp_data->table_count * sizeof(uint32) * 4); + + comp_data->table_count + * (sizeof(uint32) * 5)); } static uint32 get_table_info_size(AOTCompData *comp_data) { - /* import_table size + table_size - + init data count + init data list */ - return get_import_table_size(comp_data) - + get_table_size(comp_data) - + (uint32)sizeof(uint32) + /* + * ------------------------------ + * | import_table_count + * ------------------------------ + * | + * | AOTImportTable[import_table_count] + * | + * ------------------------------ + * | table_count + * ------------------------------ + * | + * | AOTTable[table_count] + * | + * ------------------------------ + * | table_init_data_count + * ------------------------------ + * | + * | AOTTableInitData*[table_init_data_count] + * | + * ------------------------------ + */ + return get_import_table_size(comp_data) + get_table_size(comp_data) + get_table_init_data_list_size(comp_data->table_init_data_list, comp_data->table_init_data_count); } @@ -1014,10 +1072,18 @@ aot_emit_table_info(uint8 *buf, uint8 *buf_end, uint32 *p_offset, *p_offset = offset = align_uint(offset, 4); - /* Emit import table count, only emit 0 currently. - TODO: emit the actual import table count and - the full import table info. */ - EMIT_U32(0); + /* Emit import table count */ + EMIT_U32(comp_data->import_table_count); + /* Emit table items */ + for (i = 0; i < comp_data->import_table_count; i++) { + /* TODO: + * EMIT_STR(comp_data->import_tables[i].module_name ); + * EMIT_STR(comp_data->import_tables[i].table_name); + */ + EMIT_U32(comp_data->import_tables[i].table_init_size); + EMIT_U32(comp_data->import_tables[i].table_max_size); + EMIT_U32(comp_data->import_tables[i].possible_grow & 0x000000FF); + } /* Emit table count */ EMIT_U32(comp_data->table_count); @@ -1027,6 +1093,7 @@ aot_emit_table_info(uint8 *buf, uint8 *buf_end, uint32 *p_offset, EMIT_U32(comp_data->tables[i].table_flags); EMIT_U32(comp_data->tables[i].table_init_size); EMIT_U32(comp_data->tables[i].table_max_size); + EMIT_U32(comp_data->tables[i].possible_grow & 0x000000FF); } /* Emit table init data count */ @@ -1034,6 +1101,8 @@ aot_emit_table_info(uint8 *buf, uint8 *buf_end, uint32 *p_offset, /* Emit table init data items */ for (i = 0; i < comp_data->table_init_data_count; i++) { offset = align_uint(offset, 4); + EMIT_U32(init_datas[i]->mode); + EMIT_U32(init_datas[i]->elem_type); EMIT_U32(init_datas[i]->table_index); EMIT_U32(init_datas[i]->offset.init_expr_type); EMIT_U64(init_datas[i]->offset.u.i64); diff --git a/core/iwasm/compilation/aot_emit_control.c b/core/iwasm/compilation/aot_emit_control.c index ca2cc75a6..39f882d41 100644 --- a/core/iwasm/compilation/aot_emit_control.c +++ b/core/iwasm/compilation/aot_emit_control.c @@ -616,8 +616,10 @@ aot_compile_op_end(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, /* Handle block result values */ CREATE_RESULT_VALUE_PHIS(block); for (i = 0; i < block->result_count; i++) { + value = NULL; result_index = block->result_count - 1 - i; POP(value, block->result_types[result_index]); + bh_assert(value); ADD_TO_RESULT_PHIS(block, value, result_index); } diff --git a/core/iwasm/compilation/aot_emit_function.c b/core/iwasm/compilation/aot_emit_function.c index 32cb40158..a0fe2412f 100644 --- a/core/iwasm/compilation/aot_emit_function.c +++ b/core/iwasm/compilation/aot_emit_function.c @@ -6,38 +6,9 @@ #include "aot_emit_function.h" #include "aot_emit_exception.h" #include "aot_emit_control.h" +#include "aot_emit_table.h" #include "../aot/aot_runtime.h" -#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) - #define ADD_BASIC_BLOCK(block, name) do { \ if (!(block = LLVMAppendBasicBlockInContext(comp_ctx->context, \ func_ctx->func, \ @@ -640,8 +611,8 @@ fail: static bool call_aot_call_indirect_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, - AOTFuncType *aot_func_type, - LLVMValueRef func_type_idx, LLVMValueRef table_elem_idx, + AOTFuncType *aot_func_type, LLVMValueRef func_type_idx, + LLVMValueRef table_idx, LLVMValueRef table_elem_idx, LLVMTypeRef *param_types, LLVMValueRef *param_values, uint32 param_count, uint32 param_cell_num, uint32 result_count, uint8 *wasm_ret_types, @@ -656,10 +627,11 @@ call_aot_call_indirect_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, /* prepare function type of aot_call_indirect */ func_param_types[0] = comp_ctx->exec_env_type; /* exec_env */ - func_param_types[1] = I32_TYPE; /* table_elem_idx */ - func_param_types[2] = I32_TYPE; /* argc */ - func_param_types[3] = INT32_PTR_TYPE; /* argv */ - if (!(func_type = LLVMFunctionType(INT8_TYPE, func_param_types, 4, false))) { + func_param_types[1] = I32_TYPE; /* table_idx */ + func_param_types[2] = I32_TYPE; /* table_elem_idx */ + func_param_types[3] = I32_TYPE; /* argc */ + func_param_types[4] = INT32_PTR_TYPE; /* argv */ + if (!(func_type = LLVMFunctionType(INT8_TYPE, func_param_types, 5, false))) { aot_set_last_error("llvm add function type failed."); return false; } @@ -722,18 +694,19 @@ call_aot_call_indirect_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } func_param_values[0] = func_ctx->exec_env; - func_param_values[1] = table_elem_idx; - func_param_values[2] = I32_CONST(param_cell_num); - func_param_values[3] = func_ctx->argv_buf; + func_param_values[1] = table_idx; + func_param_values[2] = table_elem_idx; + func_param_values[3] = I32_CONST(param_cell_num); + func_param_values[4] = func_ctx->argv_buf; - if (!func_param_values[2]) { + if (!func_param_values[3]) { aot_set_last_error("llvm create const failed."); return false; } /* call aot_call_indirect() function */ if (!(res = LLVMBuildCall(comp_ctx->builder, func, - func_param_values, 4, "res"))) { + func_param_values, 5, "res"))) { aot_set_last_error("llvm build call failed."); return false; } @@ -771,10 +744,10 @@ call_aot_call_indirect_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, bool aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, - uint32 type_idx) + uint32 type_idx, uint32 tbl_idx) { AOTFuncType *func_type; - LLVMValueRef elem_idx, table_elem, func_idx; + LLVMValueRef tbl_idx_value, elem_idx, table_elem, func_idx; LLVMValueRef ftype_idx_ptr, ftype_idx, ftype_idx_const; LLVMValueRef cmp_elem_idx, cmp_func_idx, cmp_ftype_idx; LLVMValueRef func, func_ptr, table_size_const; @@ -787,8 +760,9 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, LLVMBasicBlockRef check_elem_idx_succ, check_ftype_idx_succ; LLVMBasicBlockRef check_func_idx_succ, block_return, block_curr; LLVMBasicBlockRef block_call_import, block_call_non_import; + LLVMValueRef offset; uint32 total_param_count, func_param_count, func_result_count; - uint32 table_init_size = 0, ext_cell_num, param_cell_num, i, j; + uint32 ext_cell_num, param_cell_num, i, j; uint8 wasm_ret_type, *wasm_ret_types; uint64 total_size; char buf[32]; @@ -818,20 +792,31 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, POP_I32(elem_idx); - if (comp_ctx->comp_data->import_table_count > 0) { - table_init_size = comp_ctx->comp_data->import_tables[0] - .table_init_size; - } - else if (comp_ctx->comp_data->table_count > 0) { - table_init_size = comp_ctx->comp_data->tables[0] - .table_init_size; - } - else { - aot_set_last_error("table index out of range"); + /* 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 (!(table_size_const = + LLVMBuildGEP(comp_ctx->builder, func_ctx->aot_inst, &offset, 1, + "cur_size_i8p"))) { + HANDLE_FAILURE("LLVMBuildGEP"); + goto fail; + } + + if (!(table_size_const = + LLVMBuildBitCast(comp_ctx->builder, table_size_const, + INT32_PTR_TYPE, "cur_siuze_i32p"))) { + HANDLE_FAILURE("LLVMBuildBitCast"); + goto fail; + } + + if (!(table_size_const = LLVMBuildLoad(comp_ctx->builder, table_size_const, "cur_size"))) { + HANDLE_FAILURE("LLVMBuildLoad"); goto fail; } - table_size_const = I32_CONST(table_init_size); - CHECK_LLVM_CONST(table_size_const); /* Check if (uint32)elem index >= table size */ if (!(cmp_elem_idx = LLVMBuildICmp(comp_ctx->builder, LLVMIntUGE, @@ -857,14 +842,32 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, true, cmp_elem_idx, check_elem_idx_succ))) goto fail; - /* Load function index */ - if (!(table_elem = LLVMBuildInBoundsGEP(comp_ctx->builder, - func_ctx->table_base, - &elem_idx, 1, "table_elem"))) { + /* load data as i32* */ + if (!(offset = I32_CONST(get_tbl_inst_offset(comp_ctx, func_ctx, tbl_idx) + + offsetof(AOTTableInstance, data)))) { + HANDLE_FAILURE("LLVMConstInt"); + goto fail; + } + + if (!(table_elem = LLVMBuildGEP(comp_ctx->builder, 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 = LLVMBuildGEP(comp_ctx->builder, table_elem, &elem_idx, + 1, "table_elem"))) { + HANDLE_FAILURE("LLVMBuildNUWAdd"); + goto fail; + } + if (!(func_idx = LLVMBuildLoad(comp_ctx->builder, table_elem, "func_idx"))) { aot_set_last_error("llvm build load failed."); @@ -1118,8 +1121,15 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, param_cell_num = func_type->param_cell_num; wasm_ret_types = func_type->types + func_type->param_count; + tbl_idx_value = I32_CONST(tbl_idx); + if (!tbl_idx_value) { + aot_set_last_error("llvm create const failed."); + goto fail; + } + if (!call_aot_call_indirect_func(comp_ctx, func_ctx, - func_type, ftype_idx, elem_idx, + func_type, ftype_idx, + tbl_idx_value, elem_idx, param_types + 1, param_values + 1, func_param_count, param_cell_num, func_result_count, wasm_ret_types, @@ -1240,3 +1250,56 @@ fail: return ret; } +bool +aot_compile_op_ref_null(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) +{ + PUSH_I32(REF_NULL); + + return true; +fail: + return false; +} + +bool +aot_compile_op_ref_is_null(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) +{ + LLVMValueRef lhs, res; + + POP_I32(lhs); + + if (!(res = LLVMBuildICmp(comp_ctx->builder, LLVMIntEQ, lhs, REF_NULL, + "cmp_w_null"))) { + HANDLE_FAILURE("LLVMBuildICmp"); + goto fail; + } + + if (!(res = LLVMBuildZExt(comp_ctx->builder, res, I32_TYPE, "r_i"))) { + HANDLE_FAILURE("LLVMBuildZExt"); + goto fail; + } + + PUSH_I32(res); + + return true; +fail: + return false; +} + +bool +aot_compile_op_ref_func(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + uint32 func_idx) +{ + LLVMValueRef ref_idx; + + if (!(ref_idx = I32_CONST(func_idx))) { + HANDLE_FAILURE("LLVMConstInt"); + goto fail; + } + + PUSH_I32(ref_idx); + + return true; +fail: + return false; +} diff --git a/core/iwasm/compilation/aot_emit_function.h b/core/iwasm/compilation/aot_emit_function.h index 70aa4c5d1..23a384da8 100644 --- a/core/iwasm/compilation/aot_emit_function.h +++ b/core/iwasm/compilation/aot_emit_function.h @@ -17,9 +17,21 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, uint32 func_idx, bool tail_call); bool -aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, - uint32 type_idx); +aot_compile_op_call_indirect(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + uint32 type_idx, + uint32 tbl_idx); +bool +aot_compile_op_ref_null(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx); + +bool +aot_compile_op_ref_is_null(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx); + +bool +aot_compile_op_ref_func(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + uint32 func_idx); #ifdef __cplusplus } /* end of extern "C" */ #endif diff --git a/core/iwasm/compilation/aot_emit_memory.c b/core/iwasm/compilation/aot_emit_memory.c index 883f4b9df..0a506143c 100644 --- a/core/iwasm/compilation/aot_emit_memory.c +++ b/core/iwasm/compilation/aot_emit_memory.c @@ -657,7 +657,7 @@ aot_compile_op_memory_grow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) POP_I32(delta); - /* Function type of wasm_runtime_enlarge_memory() */ + /* Function type of aot_enlarge_memory() */ param_types[0] = INT8_PTR_TYPE; param_types[1] = I32_TYPE; ret_type = INT8_TYPE; @@ -673,14 +673,14 @@ aot_compile_op_memory_grow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) aot_set_last_error("llvm add pointer type failed."); return false; } - if (!(value = I64_CONST((uint64)(uintptr_t)wasm_runtime_enlarge_memory)) + if (!(value = I64_CONST((uint64)(uintptr_t)aot_enlarge_memory)) || !(func = LLVMConstIntToPtr(value, func_ptr_type))) { aot_set_last_error("create LLVM value failed."); return false; } } else { - char *func_name = "wasm_runtime_enlarge_memory"; + char *func_name = "aot_enlarge_memory"; /* AOT mode, delcare the function */ if (!(func = LLVMGetNamedFunction(comp_ctx->module, func_name)) && !(func = LLVMAddFunction(comp_ctx->module, @@ -690,7 +690,7 @@ aot_compile_op_memory_grow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) } } - /* Call function wasm_runtime_enlarge_memory() */ + /* Call function aot_enlarge_memory() */ param_values[0] = func_ctx->aot_inst; param_values[1] = delta; if (!(ret_value = LLVMBuildCall(comp_ctx->builder, func, @@ -715,35 +715,6 @@ fail: return false; } -#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) #if WASM_ENABLE_BULK_MEMORY != 0 diff --git a/core/iwasm/compilation/aot_emit_parametric.c b/core/iwasm/compilation/aot_emit_parametric.c index 498e9e8a6..fba89e273 100644 --- a/core/iwasm/compilation/aot_emit_parametric.c +++ b/core/iwasm/compilation/aot_emit_parametric.c @@ -45,11 +45,18 @@ pop_value_from_wasm_stack(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, wasm_runtime_free(aot_value); - if ((is_32 - && (type != VALUE_TYPE_I32 && type != VALUE_TYPE_F32 - && type != VALUE_TYPE_V128)) - || (!is_32 - && (type != VALUE_TYPE_I64 && type != VALUE_TYPE_F64))) { + /* is_32: i32, f32, ref.func, ref.extern, v128 */ + if (is_32 + && !(type == VALUE_TYPE_I32 || type == VALUE_TYPE_F32 + || type == VALUE_TYPE_FUNCREF || type == VALUE_TYPE_EXTERNREF + || type == VALUE_TYPE_V128)) { + aot_set_last_error("invalid WASM stack data type."); + return false; + } + + /* !is_32: i64, f64 */ + if (!is_32 + && !(type == VALUE_TYPE_I64 || type == VALUE_TYPE_F64)) { aot_set_last_error("invalid WASM stack data type."); return false; } diff --git a/core/iwasm/compilation/aot_emit_table.c b/core/iwasm/compilation/aot_emit_table.c new file mode 100644 index 000000000..e84cad5d4 --- /dev/null +++ b/core/iwasm/compilation/aot_emit_table.c @@ -0,0 +1,487 @@ +/* + * 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; + + /* from the head of AOTModuleInstance */ + 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, data); + offset += sizeof(uint32) * aot_get_imp_tbl_data_slots(imp_tbls + i); + ++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, data); + offset += sizeof(uint32) * aot_get_tbl_data_slots(tbls + i); + ++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 = LLVMBuildGEP(comp_ctx->builder, func_ctx->aot_inst, + &offset, 1, "tbl_inst"))) { + HANDLE_FAILURE("LLVMBuildGEP"); + 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; + + 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 = + LLVMBuildCall(comp_ctx->builder, 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 = LLVMBuildGEP(comp_ctx->builder, func_ctx->aot_inst, &offset, + 1, "cur_size_i8p"))) { + HANDLE_FAILURE("LLVMBuildGEP"); + 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 = LLVMBuildLoad(comp_ctx->builder, 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, data)))) { + HANDLE_FAILURE("LLVMConstInt"); + goto fail; + } + + if (!(table_elem = LLVMBuildGEP(comp_ctx->builder, 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 = LLVMBuildGEP(comp_ctx->builder, table_elem, &elem_idx, + 1, "table_elem"))) { + HANDLE_FAILURE("LLVMBuildNUWAdd"); + goto fail; + } + + if (!(func_idx = + LLVMBuildLoad(comp_ctx->builder, 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, data)))) { + HANDLE_FAILURE("LLVMConstInt"); + goto fail; + } + + if (!(table_elem = LLVMBuildGEP(comp_ctx->builder, func_ctx->aot_inst, + &offset, 1, "table_elem_i8p"))) { + HANDLE_FAILURE("LLVMBuildGEP"); + 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 = LLVMBuildGEP(comp_ctx->builder, table_elem, &elem_idx, + 1, "table_elem"))) { + HANDLE_FAILURE("LLVMBuildGEP"); + 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; + + 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 (!(LLVMBuildCall(comp_ctx->builder, 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; + + 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 (!(LLVMBuildCall(comp_ctx->builder, 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 = LLVMBuildGEP(comp_ctx->builder, func_ctx->aot_inst, &offset, + 1, "tbl_sz_ptr_i8"))) { + HANDLE_FAILURE("LLVMBuildGEP"); + 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 = LLVMBuildLoad(comp_ctx->builder, 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; + + 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 = LLVMBuildCall(comp_ctx->builder, 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; + + 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 (!(LLVMBuildCall(comp_ctx->builder, func, param_values, 5, ""))) { + HANDLE_FAILURE("LLVMBuildCall"); + goto fail; + } + + return true; +fail: + return false; +} + +#endif /* WASM_ENABLE_REF_TYPES != 0 */ \ No newline at end of file diff --git a/core/iwasm/compilation/aot_emit_table.h b/core/iwasm/compilation/aot_emit_table.h new file mode 100644 index 000000000..78c5b90c3 --- /dev/null +++ b/core/iwasm/compilation/aot_emit_table.h @@ -0,0 +1,71 @@ + +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _AOT_EMIT_TABLE_H_ +#define _AOT_EMIT_TABLE_H_ + +#include "aot_compiler.h" + +#ifdef __cplusplus +extern "C" { +#endif + +bool +aot_compile_op_elem_drop(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + uint32 tbl_seg_idx); + +bool +aot_compile_op_table_get(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + uint32 tbl_idx); + +bool +aot_compile_op_table_set(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + uint32 tbl_idx); + +bool +aot_compile_op_table_init(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + uint32 tbl_idx, + uint32 tbl_seg_idx); + +bool +aot_compile_op_table_copy(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + uint32 src_tbl_idx, + uint32 dst_tbl_idx); + +bool +aot_compile_op_table_size(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + uint32 tbl_idx); + +bool +aot_compile_op_table_grow(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + uint32 tbl_idx); + +bool +aot_compile_op_table_fill(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + uint32 tbl_idx); + +uint64 +get_tbl_inst_offset(const AOTCompContext *comp_ctx, + const AOTFuncContext *func_ctx, + uint32 tbl_idx); + +LLVMValueRef +aot_compile_get_tbl_inst(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + uint32 tbl_idx); + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif +#endif \ No newline at end of file diff --git a/core/iwasm/compilation/aot_emit_variable.c b/core/iwasm/compilation/aot_emit_variable.c index f79588cda..c3ddc356f 100644 --- a/core/iwasm/compilation/aot_emit_variable.c +++ b/core/iwasm/compilation/aot_emit_variable.c @@ -143,6 +143,8 @@ compile_global(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, 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: @@ -158,7 +160,7 @@ compile_global(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, ptr_type = comp_ctx->basic_types.v128_ptr_type; break; default: - bh_assert(0); + bh_assert("unknown type"); break; } diff --git a/core/iwasm/compilation/aot_llvm.c b/core/iwasm/compilation/aot_llvm.c index 0044a3b40..0784e87e9 100644 --- a/core/iwasm/compilation/aot_llvm.c +++ b/core/iwasm/compilation/aot_llvm.c @@ -14,6 +14,8 @@ wasm_type_to_llvm_type(AOTLLVMTypes *llvm_types, uint8 wasm_type) { switch (wasm_type) { case VALUE_TYPE_I32: + case VALUE_TYPE_FUNCREF: + case VALUE_TYPE_EXTERNREF: return llvm_types->int32_type; case VALUE_TYPE_I64: return llvm_types->int64_type; @@ -21,12 +23,12 @@ wasm_type_to_llvm_type(AOTLLVMTypes *llvm_types, uint8 wasm_type) return llvm_types->float32_type; case VALUE_TYPE_F64: return llvm_types->float64_type; -#if WASM_ENABLE_SIMD != 0 case VALUE_TYPE_V128: return llvm_types->i64x2_vec_type; -#endif case VALUE_TYPE_VOID: return llvm_types->void_type; + default: + break; } return NULL; } @@ -491,34 +493,6 @@ create_memory_info(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, return true; } -static bool -create_table_base(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) -{ - AOTCompData *comp_data = comp_ctx->comp_data; - uint64 module_inst_mem_inst_size = - (uint64)comp_data->memory_count * sizeof(AOTMemoryInstance); - LLVMValueRef offset; - - offset = I32_CONST(offsetof(AOTModuleInstance, global_table_data.bytes) - + module_inst_mem_inst_size - + comp_ctx->comp_data->global_data_size); - func_ctx->table_base = LLVMBuildInBoundsGEP(comp_ctx->builder, - func_ctx->aot_inst, - &offset, 1, - "table_base_tmp"); - if (!func_ctx->table_base) { - aot_set_last_error("llvm build in bounds gep failed."); - return false; - } - func_ctx->table_base = LLVMBuildBitCast(comp_ctx->builder, func_ctx->table_base, - INT32_PTR_TYPE, "table_base"); - if (!func_ctx->table_base) { - aot_set_last_error("llvm build bit cast failed."); - return false; - } - return true; -} - static bool create_cur_exception(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) { @@ -810,11 +784,13 @@ aot_create_func_context(AOTCompData *comp_data, AOTCompContext *comp_ctx, case VALUE_TYPE_F64: local_value = F64_ZERO; break; -#if WASM_ENABLE_SIMD != 0 case VALUE_TYPE_V128: local_value = V128_ZERO; break; -#endif + case VALUE_TYPE_FUNCREF: + case VALUE_TYPE_EXTERNREF: + local_value = REF_NULL; + break; default: bh_assert(0); break; @@ -853,10 +829,6 @@ aot_create_func_context(AOTCompData *comp_data, AOTCompContext *comp_ctx, if (!create_memory_info(comp_ctx, func_ctx, int8_ptr_type, func_index)) goto fail; - /* Load table base */ - if (!create_table_base(comp_ctx, func_ctx)) - goto fail; - /* Load current exception */ if (!create_cur_exception(comp_ctx, func_ctx)) goto fail; @@ -943,6 +915,12 @@ aot_set_llvm_basic_types(AOTLLVMTypes *basic_types, LLVMContextRef context) basic_types->meta_data_type = LLVMMetadataTypeInContext(context); basic_types->int8_ptr_type = LLVMPointerType(basic_types->int8_type, 0); + + if (basic_types->int8_ptr_type) { + basic_types->int8_pptr_type = + LLVMPointerType(basic_types->int8_ptr_type, 0); + } + basic_types->int16_ptr_type = LLVMPointerType(basic_types->int16_type, 0); basic_types->int32_ptr_type = LLVMPointerType(basic_types->int32_type, 0); basic_types->int64_ptr_type = LLVMPointerType(basic_types->int64_type, 0); @@ -959,7 +937,11 @@ aot_set_llvm_basic_types(AOTLLVMTypes *basic_types, LLVMContextRef context) basic_types->v128_type = basic_types->i64x2_vec_type; basic_types->v128_ptr_type = LLVMPointerType(basic_types->v128_type, 0); + basic_types->funcref_type = LLVMInt32TypeInContext(context); + basic_types->externref_type = LLVMInt32TypeInContext(context); + return (basic_types->int8_ptr_type + && basic_types->int8_pptr_type && basic_types->int16_ptr_type && basic_types->int32_ptr_type && basic_types->int64_ptr_type @@ -971,7 +953,9 @@ aot_set_llvm_basic_types(AOTLLVMTypes *basic_types, LLVMContextRef context) && basic_types->i64x2_vec_type && basic_types->f32x4_vec_type && basic_types->f64x2_vec_type - && basic_types->meta_data_type) ? true : false; + && basic_types->meta_data_type + && basic_types->funcref_type + && basic_types->externref_type) ? true : false; } static bool @@ -1014,6 +998,7 @@ aot_create_llvm_consts(AOTLLVMConsts *consts, AOTCompContext *comp_ctx) consts->i32_32 = I32_CONST(32); consts->i64_63 = I64_CONST(63); consts->i64_64 = I64_CONST(64); + consts->ref_null = I32_CONST(NULL_REF); return (consts->i8_zero && consts->i32_zero @@ -1041,7 +1026,8 @@ aot_create_llvm_consts(AOTLLVMConsts *consts, AOTCompContext *comp_ctx) && consts->i32_31 && consts->i32_32 && consts->i64_63 - && consts->i64_64) ? true : false; + && consts->i64_64 + && consts->ref_null) ? true : false; } typedef struct ArchItem { @@ -1245,6 +1231,9 @@ aot_create_comp_context(AOTCompData *comp_data, if (option->enable_tail_call) comp_ctx->enable_tail_call = true; + if (option->enable_ref_types) + comp_ctx->enable_ref_types = true; + if (option->enable_aux_stack_frame) comp_ctx->enable_aux_stack_frame = true; @@ -1585,10 +1574,7 @@ aot_create_comp_context(AOTCompData *comp_data, } /* set exec_env data type to int8** */ - if (!(comp_ctx->exec_env_type = LLVMPointerType(INT8_PTR_TYPE, 0))) { - aot_set_last_error("llvm get pointer type failed."); - goto fail; - } + comp_ctx->exec_env_type = comp_ctx->basic_types.int8_pptr_type; /* set aot_inst data type to int8* */ comp_ctx->aot_inst_type = INT8_PTR_TYPE; @@ -1846,11 +1832,13 @@ aot_build_zero_function_ret(AOTCompContext *comp_ctx, case VALUE_TYPE_F64: ret = LLVMBuildRet(comp_ctx->builder, F64_ZERO); break; -#if WASM_ENABLE_SIMD != 0 case VALUE_TYPE_V128: ret = LLVMBuildRet(comp_ctx->builder, V128_ZERO); break; -#endif + case VALUE_TYPE_FUNCREF: + case VALUE_TYPE_EXTERNREF: + ret = LLVMBuildRet(comp_ctx->builder, REF_NULL); + break; default: bh_assert(0); } diff --git a/core/iwasm/compilation/aot_llvm.h b/core/iwasm/compilation/aot_llvm.h index 83ed0e781..95d0e8f5c 100644 --- a/core/iwasm/compilation/aot_llvm.h +++ b/core/iwasm/compilation/aot_llvm.h @@ -119,7 +119,6 @@ typedef struct AOTFuncContext { LLVMValueRef exec_env; LLVMValueRef aot_inst; - LLVMValueRef table_base; LLVMValueRef argv_buf; LLVMValueRef native_stack_bound; LLVMValueRef aux_stack_bound; @@ -152,6 +151,7 @@ typedef struct AOTLLVMTypes { LLVMTypeRef void_type; LLVMTypeRef int8_ptr_type; + LLVMTypeRef int8_pptr_type; LLVMTypeRef int16_ptr_type; LLVMTypeRef int32_ptr_type; LLVMTypeRef int64_ptr_type; @@ -168,6 +168,9 @@ typedef struct AOTLLVMTypes { LLVMTypeRef f64x2_vec_type; LLVMTypeRef meta_data_type; + + LLVMTypeRef funcref_type; + LLVMTypeRef externref_type; } AOTLLVMTypes; typedef struct AOTLLVMConsts { @@ -199,6 +202,7 @@ typedef struct AOTLLVMConsts { LLVMValueRef i32_32; LLVMValueRef i64_63; LLVMValueRef i64_64; + LLVMValueRef ref_null; } AOTLLVMConsts; /** @@ -241,6 +245,9 @@ typedef struct AOTCompContext { /* Tail Call */ bool enable_tail_call; + /* Reference Types */ + bool enable_ref_types; + /* Whether optimize the JITed code */ bool optimize; @@ -283,6 +290,7 @@ typedef struct AOTCompOption{ bool enable_thread_mgr; bool enable_tail_call; bool enable_simd; + bool enable_ref_types; bool enable_aux_stack_check; bool enable_aux_stack_frame; bool is_sgx_platform; diff --git a/core/iwasm/include/aot_export.h b/core/iwasm/include/aot_export.h index 8edabeb31..8adf663a3 100644 --- a/core/iwasm/include/aot_export.h +++ b/core/iwasm/include/aot_export.h @@ -43,6 +43,7 @@ typedef struct AOTCompOption{ bool enable_thread_mgr; bool enable_tail_call; bool enable_simd; + bool enable_ref_types; bool enable_aux_stack_check; bool enable_aux_stack_frame; bool is_sgx_platform; diff --git a/core/iwasm/include/wasm_export.h b/core/iwasm/include/wasm_export.h index 137692911..e20404bf0 100644 --- a/core/iwasm/include/wasm_export.h +++ b/core/iwasm/include/wasm_export.h @@ -849,6 +849,45 @@ wasm_runtime_spawn_thread(wasm_exec_env_t exec_env, wasm_thread_t *tid, WASM_RUNTIME_API_EXTERN int32_t wasm_runtime_join_thread(wasm_thread_t tid, void **retval); +/** + * Map external object to an internal externref index: if the index + * has been created, return it, otherwise create the index. + * + * @param module_inst the WASM module instance that the extern object + * belongs to + * @param extern_obj the external object to be mapped + * @param p_externref_idx return externref index of the external object + * + * @return true if success, false otherwise + */ +WASM_RUNTIME_API_EXTERN bool +wasm_externref_obj2ref(wasm_module_inst_t module_inst, + void *extern_obj, uint32_t *p_externref_idx); + +/** + * Retrieve the external object from an internal externref index + * + * @param externref_idx the externref index to retrieve + * @param p_extern_obj return the mapped external object of + * the externref index + * + * @return true if success, false otherwise + */ +WASM_RUNTIME_API_EXTERN bool +wasm_externref_ref2obj(uint32_t externref_idx, void **p_extern_obj); + +/** + * Retain an extern object which is mapped to the internal externref + * so that the object won't be cleaned during extern object reclaim + * if it isn't used. + * + * @param externref_idx the externref index of an external object + * to retain + * @return true if success, false otherwise + */ +WASM_RUNTIME_API_EXTERN bool +wasm_externref_retain(uint32_t externref_idx); + /** * dump the call stack * diff --git a/core/iwasm/interpreter/wasm.h b/core/iwasm/interpreter/wasm.h index ab3476c0f..d99036e5e 100644 --- a/core/iwasm/interpreter/wasm.h +++ b/core/iwasm/interpreter/wasm.h @@ -20,22 +20,29 @@ extern "C" { #define VALUE_TYPE_F32 0x7D #define VALUE_TYPE_F64 0x7C #define VALUE_TYPE_V128 0x7B +#define VALUE_TYPE_FUNCREF 0x70 +#define VALUE_TYPE_EXTERNREF 0x6F #define VALUE_TYPE_VOID 0x40 /* Used by AOT */ #define VALUE_TYPE_I1 0x41 /* Used by loader to represent any type of i32/i64/f32/f64 */ #define VALUE_TYPE_ANY 0x42 -/* Table Element Type */ -#define TABLE_ELEM_TYPE_ANY_FUNC 0x70 - #define DEFAULT_NUM_BYTES_PER_PAGE 65536 +#define NULL_REF (0xFFFFFFFF) + +#define TABLE_MAX_SIZE (1024) + #define INIT_EXPR_TYPE_I32_CONST 0x41 #define INIT_EXPR_TYPE_I64_CONST 0x42 #define INIT_EXPR_TYPE_F32_CONST 0x43 #define INIT_EXPR_TYPE_F64_CONST 0x44 #define INIT_EXPR_TYPE_V128_CONST 0xFD +/* = WASM_OP_REF_FUNC */ +#define INIT_EXPR_TYPE_FUNCREF_CONST 0xD2 +/* = WASM_OP_REF_NULL */ +#define INIT_EXPR_TYPE_REFNULL_CONST 0xD0 #define INIT_EXPR_TYPE_GET_GLOBAL 0x23 #define INIT_EXPR_TYPE_ERROR 0xff @@ -105,6 +112,7 @@ typedef union WASMValue { typedef struct InitializerExpression { /* type of INIT_EXPR_TYPE_XXX */ + /* it actually is instr, in some places, requires constant only */ uint8 init_expr_type; WASMValue u; } InitializerExpression; @@ -124,6 +132,7 @@ typedef struct WASMTable { uint32 init_size; /* specified if (flags & 1), else it is 0x10000 */ uint32 max_size; + bool possible_grow; } WASMTable; typedef struct WASMMemory { @@ -141,6 +150,7 @@ typedef struct WASMTableImport { uint32 init_size; /* specified if (flags & 1), else it is 0x10000 */ uint32 max_size; + bool possible_grow; #if WASM_ENABLE_MULTI_MODULE != 0 WASMModule *import_module; WASMTable *import_table_linked; @@ -257,6 +267,12 @@ typedef struct WASMExport { } WASMExport; typedef struct WASMTableSeg { + /* 0 to 7 */ + uint32 mode; + /* funcref or externref, elemkind will be considered as funcref */ + uint32 elem_type; + bool is_dropped; + /* optional, only for active */ uint32 table_index; InitializerExpression base_offset; uint32 function_count; @@ -456,6 +472,10 @@ wasm_value_type_size(uint8 value_type) switch (value_type) { case VALUE_TYPE_I32: case VALUE_TYPE_F32: +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_FUNCREF: + case VALUE_TYPE_EXTERNREF: +#endif return sizeof(int32); case VALUE_TYPE_I64: case VALUE_TYPE_F64: @@ -475,11 +495,14 @@ wasm_value_type_cell_num(uint8 value_type) { if (value_type == VALUE_TYPE_VOID) return 0; - else if (value_type == VALUE_TYPE_I32 - || value_type == VALUE_TYPE_F32) + else if (value_type == VALUE_TYPE_I32 || value_type == VALUE_TYPE_F32 +#if WASM_ENABLE_REF_TYPES != 0 + || value_type == VALUE_TYPE_FUNCREF + || value_type == VALUE_TYPE_EXTERNREF +#endif + ) return 1; - else if (value_type == VALUE_TYPE_I64 - || value_type == VALUE_TYPE_F64) + else if (value_type == VALUE_TYPE_I64 || value_type == VALUE_TYPE_F64) return 2; #if WASM_ENABLE_SIMD != 0 else if (value_type == VALUE_TYPE_V128) diff --git a/core/iwasm/interpreter/wasm_interp_classic.c b/core/iwasm/interpreter/wasm_interp_classic.c index 8f37c0d77..3861376a5 100644 --- a/core/iwasm/interpreter/wasm_interp_classic.c +++ b/core/iwasm/interpreter/wasm_interp_classic.c @@ -871,7 +871,6 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, uint32 num_bytes_per_page = memory ? memory->num_bytes_per_page : 0; uint8 *global_data = module->global_data; uint32 linear_mem_size = memory ? num_bytes_per_page * memory->cur_page_count : 0; - WASMTableInstance *table = module->default_table; WASMType **wasm_types = module->module->types; WASMGlobalInstance *globals = module->globals, *global; uint8 opcode_IMPDEP = WASM_OP_IMPDEP; @@ -1099,7 +1098,8 @@ label_pop_csp_n: #endif { WASMType *cur_type, *cur_func_type; - WASMTableInstance *cur_table_inst; + WASMTableInstance *tbl_inst; + uint32 tbl_idx; #if WASM_ENABLE_TAIL_CALL != 0 opcode = *(frame_ip - 1); #endif @@ -1114,41 +1114,35 @@ label_pop_csp_n: * no matter it is used or not */ read_leb_uint32(frame_ip, frame_ip_end, tidx); - if (tidx >= module->module->type_count) { - wasm_set_exception(module, "unknown type"); - goto got_exception; - } + bh_assert(tidx < module->module->type_count); cur_type = wasm_types[tidx]; - /* to skip 0x00 here */ - frame_ip++; + read_leb_uint32(frame_ip, frame_ip_end, tbl_idx); + bh_assert(tbl_idx < module->table_count); + + tbl_inst = wasm_get_table_inst(module, tbl_idx); + val = POP_I32(); - - /* careful, it might be a table in another module */ - cur_table_inst = table; -#if WASM_ENABLE_MULTI_MODULE != 0 - if (table->table_inst_linked) { - cur_table_inst = table->table_inst_linked; - } -#endif - - if (val < 0 || val >= (int32)cur_table_inst->cur_size) { + if (val < 0 || val >= (int32)tbl_inst->cur_size) { wasm_set_exception(module, "undefined element"); goto got_exception; } - fidx = ((uint32*)cur_table_inst->base_addr)[val]; + fidx = ((uint32*)tbl_inst->base_addr)[val]; if (fidx == (uint32)-1) { wasm_set_exception(module, "uninitialized element"); goto got_exception; } -#if WASM_ENABLE_MULTI_MODULE != 0 - if (fidx >= module->function_count) { + /* + * we might be using a table injected by host or + * another module. In that case, we don't validate + * the elem value while loading + */ + if (fidx >= module->function_count) { wasm_set_exception(module, "unknown function"); goto got_exception; } -#endif /* always call module own functions */ cur_func = module->functions + fidx; @@ -1201,6 +1195,99 @@ label_pop_csp_n: HANDLE_OP_END (); } +#if WASM_ENABLE_REF_TYPES != 0 + HANDLE_OP (WASM_OP_SELECT_T): + { + uint32 vec_len; + uint8 type; + + read_leb_uint32(frame_ip, frame_ip_end, vec_len); + type = *frame_ip++; + + cond = (uint32)POP_I32(); + if (type == VALUE_TYPE_I64 || type == VALUE_TYPE_F64) { + frame_sp -= 2; + if (!cond) { + *(frame_sp - 2) = *frame_sp; + *(frame_sp - 1) = *(frame_sp + 1); + } + } + else { + frame_sp--; + if (!cond) + *(frame_sp - 1) = *frame_sp; + } + + (void)vec_len; + HANDLE_OP_END (); + } + HANDLE_OP (WASM_OP_TABLE_GET): + { + uint32 tbl_idx, elem_idx; + WASMTableInstance *tbl_inst; + + read_leb_uint32(frame_ip, frame_ip_end, tbl_idx); + bh_assert(tbl_idx < module->table_count); + + tbl_inst = wasm_get_table_inst(module, tbl_idx); + + elem_idx = POP_I32(); + if (elem_idx >= tbl_inst->cur_size) { + wasm_set_exception(module, "out of bounds table access"); + goto got_exception; + } + + PUSH_I32(((uint32 *)tbl_inst->base_addr)[elem_idx]); + HANDLE_OP_END (); + } + + HANDLE_OP (WASM_OP_TABLE_SET): + { + uint32 tbl_idx, elem_idx, val; + WASMTableInstance *tbl_inst; + + read_leb_uint32(frame_ip, frame_ip_end, tbl_idx); + bh_assert(tbl_idx < module->table_count); + + tbl_inst = wasm_get_table_inst(module, tbl_idx); + + val = POP_I32(); + elem_idx = POP_I32(); + if (elem_idx >= tbl_inst->cur_size) { + wasm_set_exception(module, "out of bounds table access"); + goto got_exception; + } + + ((uint32 *)(tbl_inst->base_addr))[elem_idx] = val; + HANDLE_OP_END(); + } + + HANDLE_OP (WASM_OP_REF_NULL): + { + uint32 ref_type; + read_leb_uint32(frame_ip, frame_ip_end, ref_type); + PUSH_I32(NULL_REF); + (void)ref_type; + HANDLE_OP_END(); + } + + HANDLE_OP (WASM_OP_REF_IS_NULL): + { + uint32 val; + val = POP_I32(); + PUSH_I32(val == NULL_REF ? 1 : 0); + HANDLE_OP_END(); + } + + HANDLE_OP (WASM_OP_REF_FUNC): + { + uint32 func_idx; + read_leb_uint32(frame_ip, frame_ip_end, func_idx); + PUSH_I32(func_idx); + HANDLE_OP_END(); + } +#endif /* WASM_ENABLE_REF_TYPES */ + /* variable instructions */ HANDLE_OP (WASM_OP_GET_LOCAL): { @@ -1209,6 +1296,10 @@ label_pop_csp_n: switch (local_type) { case VALUE_TYPE_I32: case VALUE_TYPE_F32: +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_FUNCREF: + case VALUE_TYPE_EXTERNREF: +#endif PUSH_I32(*(int32*)(frame_lp + local_offset)); break; case VALUE_TYPE_I64: @@ -1240,6 +1331,10 @@ label_pop_csp_n: switch (local_type) { case VALUE_TYPE_I32: case VALUE_TYPE_F32: +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_FUNCREF: + case VALUE_TYPE_EXTERNREF: +#endif *(int32*)(frame_lp + local_offset) = POP_I32(); break; case VALUE_TYPE_I64: @@ -1271,6 +1366,10 @@ label_pop_csp_n: switch (local_type) { case VALUE_TYPE_I32: case VALUE_TYPE_F32: +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_FUNCREF: + case VALUE_TYPE_EXTERNREF: +#endif *(int32*)(frame_lp + local_offset) = *(int32*)(frame_sp - 1); break; case VALUE_TYPE_I64: @@ -2586,10 +2685,173 @@ label_pop_csp_n: break; } #endif /* WASM_ENABLE_BULK_MEMORY */ +#if WASM_ENABLE_REF_TYPES != 0 + case WASM_OP_TABLE_INIT: + { + uint32 tbl_idx, elem_idx; + uint64 n, s, d; + WASMTableInstance *tbl_inst; + + read_leb_uint32(frame_ip, frame_ip_end, elem_idx); + bh_assert(elem_idx < module->module->table_seg_count); + + read_leb_uint32(frame_ip, frame_ip_end, tbl_idx); + bh_assert(tbl_idx < module->module->table_count); + + tbl_inst = wasm_get_table_inst(module, tbl_idx); + + n = (uint32)POP_I32(); + s = (uint32)POP_I32(); + d = (uint32)POP_I32(); + + /* TODO: what if the element is not passive? */ + + if (!n) { + break; + } + + if (n + s > module->module->table_segments[elem_idx].function_count + || d + n > tbl_inst->cur_size) { + wasm_set_exception(module, "out of bounds table access"); + goto got_exception; + } + + if (module->module->table_segments[elem_idx].is_dropped) { + wasm_set_exception(module, "out of bounds table access"); + goto got_exception; + } + + if (!wasm_elem_is_passive( + module->module->table_segments[elem_idx].mode)) { + wasm_set_exception(module, "out of bounds table access"); + goto got_exception; + } + + bh_memcpy_s( + (uint8 *)(tbl_inst) + + offsetof(WASMTableInstance, base_addr) + d * sizeof(uint32), + (tbl_inst->cur_size - d) * sizeof(uint32), + module->module->table_segments[elem_idx].func_indexes + s, + n * sizeof(uint32)); + + break; + } + case WASM_OP_ELEM_DROP: + { + uint32 elem_idx; + read_leb_uint32(frame_ip, frame_ip_end, elem_idx); + bh_assert(elem_idx < module->module->table_seg_count); + + module->module->table_segments[elem_idx].is_dropped = true; + break; + } + case WASM_OP_TABLE_COPY: + { + uint32 src_tbl_idx, dst_tbl_idx; + uint64 n, s, d; + WASMTableInstance *src_tbl_inst, *dst_tbl_inst; + + read_leb_uint32(frame_ip, frame_ip_end, dst_tbl_idx); + bh_assert(dst_tbl_idx < module->table_count); + + dst_tbl_inst = wasm_get_table_inst(module, dst_tbl_idx); + + read_leb_uint32(frame_ip, frame_ip_end, src_tbl_idx); + bh_assert(src_tbl_idx < module->table_count); + + src_tbl_inst = wasm_get_table_inst(module, src_tbl_idx); + + n = (uint32)POP_I32(); + s = (uint32)POP_I32(); + d = (uint32)POP_I32(); + + if (s + n > dst_tbl_inst->cur_size + || d + n > src_tbl_inst->cur_size) { + wasm_set_exception(module, "out of bounds table access"); + goto got_exception; + } + + /* if s >= d, copy from front to back */ + /* if s < d, copy from back to front */ + /* merge all together */ + bh_memcpy_s( + (uint8 *)(dst_tbl_inst) + offsetof(WASMTableInstance, base_addr) + + d * sizeof(uint32), + (dst_tbl_inst->cur_size - d) * sizeof(uint32), + (uint8 *)(src_tbl_inst) + offsetof(WASMTableInstance, base_addr) + + s * sizeof(uint32), + n * sizeof(uint32)); + break; + } + case WASM_OP_TABLE_GROW: + { + uint32 tbl_idx, n, init_val, orig_tbl_sz; + WASMTableInstance *tbl_inst; + + read_leb_uint32(frame_ip, frame_ip_end, tbl_idx); + bh_assert(tbl_idx < module->table_count); + + tbl_inst = wasm_get_table_inst(module, tbl_idx); + + orig_tbl_sz = tbl_inst->cur_size; + + n = POP_I32(); + init_val = POP_I32(); + + if (!wasm_enlarge_table(module, tbl_idx, n, init_val)) { + PUSH_I32(-1); + } + else { + PUSH_I32(orig_tbl_sz); + } + break; + } + case WASM_OP_TABLE_SIZE: + { + uint32 tbl_idx; + WASMTableInstance *tbl_inst; + + read_leb_uint32(frame_ip, frame_ip_end, tbl_idx); + bh_assert(tbl_idx < module->table_count); + + tbl_inst = wasm_get_table_inst(module, tbl_idx); + + PUSH_I32(tbl_inst->cur_size); + break; + } + case WASM_OP_TABLE_FILL: + { + uint32 tbl_idx, n, val, i; + WASMTableInstance *tbl_inst; + + read_leb_uint32(frame_ip, frame_ip_end, tbl_idx); + bh_assert(tbl_idx < module->table_count); + + tbl_inst = wasm_get_table_inst(module, tbl_idx); + + n = POP_I32(); + val = POP_I32(); + i = POP_I32(); + + /* TODO: what if the element is not passive? */ + /* TODO: what if the element is dropped? */ + + if (i + n > tbl_inst->cur_size) { + /* TODO: verify warning content */ + wasm_set_exception(module, "out of bounds table access"); + goto got_exception; + } + + for (; n != 0; i++, n--) { + ((uint32 *)(tbl_inst->base_addr))[i] = val; + } + + break; + } +#endif /* WASM_ENABLE_REF_TYPES */ default: wasm_set_exception(module, "unsupported opcode"); - goto got_exception; - break; + goto got_exception; } HANDLE_OP_END (); } @@ -2946,6 +3208,17 @@ label_pop_csp_n: #if WASM_ENABLE_TAIL_CALL == 0 HANDLE_OP (WASM_OP_RETURN_CALL): HANDLE_OP (WASM_OP_RETURN_CALL_INDIRECT): +#endif +#if WASM_ENABLE_SHARED_MEMORY == 0 + HANDLE_OP (WASM_OP_ATOMIC_PREFIX): +#endif +#if WASM_ENABLE_REF_TYPES == 0 + HANDLE_OP (WASM_OP_SELECT_T): + HANDLE_OP (WASM_OP_TABLE_GET): + HANDLE_OP (WASM_OP_TABLE_SET): + HANDLE_OP (WASM_OP_REF_NULL): + HANDLE_OP (WASM_OP_REF_IS_NULL): + HANDLE_OP (WASM_OP_REF_FUNC): #endif HANDLE_OP (WASM_OP_UNUSED_0x14): HANDLE_OP (WASM_OP_UNUSED_0x15): @@ -2953,10 +3226,7 @@ label_pop_csp_n: HANDLE_OP (WASM_OP_UNUSED_0x17): HANDLE_OP (WASM_OP_UNUSED_0x18): HANDLE_OP (WASM_OP_UNUSED_0x19): - HANDLE_OP (WASM_OP_UNUSED_0x1c): - HANDLE_OP (WASM_OP_UNUSED_0x1d): - HANDLE_OP (WASM_OP_UNUSED_0x1e): - HANDLE_OP (WASM_OP_UNUSED_0x1f): + HANDLE_OP (WASM_OP_UNUSED_0x27): /* Used by fast interpreter */ HANDLE_OP (EXT_OP_SET_LOCAL_FAST_I64): HANDLE_OP (EXT_OP_TEE_LOCAL_FAST_I64): diff --git a/core/iwasm/interpreter/wasm_interp_fast.c b/core/iwasm/interpreter/wasm_interp_fast.c index e98ec760d..786ba7b12 100644 --- a/core/iwasm/interpreter/wasm_interp_fast.c +++ b/core/iwasm/interpreter/wasm_interp_fast.c @@ -991,7 +991,6 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, uint32 num_bytes_per_page = memory ? memory->num_bytes_per_page : 0; uint8 *global_data = module->global_data; uint32 linear_mem_size = memory ? num_bytes_per_page * memory->cur_page_count : 0; - WASMTableInstance *table = module->default_table; WASMGlobalInstance *globals = module->globals, *global; uint8 opcode_IMPDEP = WASM_OP_IMPDEP; WASMInterpFrame *frame = NULL; @@ -1150,7 +1149,8 @@ recover_br_info: #endif { WASMType *cur_type, *cur_func_type; - WASMTableInstance *cur_table_inst; + WASMTableInstance *tbl_inst; + uint32 tbl_idx; #if WASM_ENABLE_TAIL_CALL != 0 GET_OPCODE(); @@ -1160,40 +1160,36 @@ recover_br_info: #endif tidx = read_uint32(frame_ip); + cur_type = module->module->types[tidx]; + + tbl_idx = read_uint32(frame_ip); + bh_assert(tbl_idx < module->table_count); + + tbl_inst = wasm_get_table_inst(module, tbl_idx); + val = GET_OPERAND(uint32, I32, 0); frame_ip += 2; - if (tidx >= module->module->type_count) { - wasm_set_exception(module, "type index is overflow"); - goto got_exception; - } - cur_type = module->module->types[tidx]; - - /* careful, it might be a table in another module */ - cur_table_inst = table; -#if WASM_ENABLE_MULTI_MODULE != 0 - if (table->table_inst_linked) { - cur_table_inst = table->table_inst_linked; - } -#endif - - if (val < 0 || val >= (int32)cur_table_inst->cur_size) { + if (val < 0 || val >= (int32)tbl_inst->cur_size) { wasm_set_exception(module, "undefined element"); goto got_exception; } - fidx = ((uint32*)cur_table_inst->base_addr)[val]; + fidx = ((uint32*)tbl_inst->base_addr)[val]; if (fidx == (uint32)-1) { wasm_set_exception(module, "uninitialized element"); goto got_exception; } -#if WASM_ENABLE_MULTI_MODULE != 0 + /* + * we might be using a table injected by host or + * another module. in that case, we don't validate + * the elem value while loading + */ if (fidx >= module->function_count) { wasm_set_exception(module, "unknown function"); goto got_exception; } -#endif /* always call module own functions */ cur_func = module->functions + fidx; @@ -1252,6 +1248,70 @@ recover_br_info: HANDLE_OP_END (); } +#if WASM_ENABLE_REF_TYPES != 0 + HANDLE_OP (WASM_OP_TABLE_GET): + { + uint32 tbl_idx, elem_idx; + WASMTableInstance *tbl_inst; + + tbl_idx = read_uint32(frame_ip); + bh_assert(tbl_idx < module->table_count); + + tbl_inst = wasm_get_table_inst(module, tbl_idx); + + elem_idx = POP_I32(); + if (elem_idx >= tbl_inst->cur_size) { + wasm_set_exception(module, "out of bounds table access"); + goto got_exception; + } + + PUSH_I32(((uint32 *)tbl_inst->base_addr)[elem_idx]); + HANDLE_OP_END(); + } + + HANDLE_OP (WASM_OP_TABLE_SET): + { + uint32 tbl_idx, elem_idx, val; + WASMTableInstance *tbl_inst; + + tbl_idx = read_uint32(frame_ip); + bh_assert(tbl_idx < module->table_count); + + tbl_inst = wasm_get_table_inst(module, tbl_idx); + + val = POP_I32(); + elem_idx = POP_I32(); + if (elem_idx >= tbl_inst->cur_size) { + wasm_set_exception(module, "out of bounds table access"); + goto got_exception; + } + + ((uint32 *)tbl_inst->base_addr)[elem_idx] = val; + HANDLE_OP_END (); + } + + HANDLE_OP (WASM_OP_REF_NULL): + { + PUSH_I32(NULL_REF); + HANDLE_OP_END(); + } + + HANDLE_OP (WASM_OP_REF_IS_NULL): + { + uint32 val; + val = POP_I32(); + PUSH_I32(val == NULL_REF ? 1 : 0); + HANDLE_OP_END(); + } + + HANDLE_OP (WASM_OP_REF_FUNC): + { + uint32 func_idx = read_uint32(frame_ip); + PUSH_I32(func_idx); + HANDLE_OP_END(); + } +#endif /* WASM_ENABLE_REF_TYPES */ + /* variable instructions */ HANDLE_OP (EXT_OP_SET_LOCAL_FAST): HANDLE_OP (EXT_OP_TEE_LOCAL_FAST): @@ -2605,10 +2665,165 @@ recover_br_info: break; } #endif /* WASM_ENABLE_BULK_MEMORY */ +#if WASM_ENABLE_REF_TYPES != 0 + case WASM_OP_TABLE_INIT: + { + uint32 tbl_idx, elem_idx; + uint64 n, s, d; + WASMTableInstance *tbl_inst; + + elem_idx = read_uint32(frame_ip); + bh_assert(elem_idx < module->module->table_seg_count); + + tbl_idx = read_uint32(frame_ip); + bh_assert(tbl_idx < module->module->table_count); + + tbl_inst = wasm_get_table_inst(module, tbl_idx); + + n = (uint32)POP_I32(); + s = (uint32)POP_I32(); + d = (uint32)POP_I32(); + + if (!n) { + break; + } + + if (n + s > module->module->table_segments[elem_idx].function_count + || d + n > tbl_inst->cur_size) { + wasm_set_exception(module, "out of bounds table access"); + goto got_exception; + } + + if (module->module->table_segments[elem_idx].is_dropped) { + wasm_set_exception(module, "out of bounds table access"); + goto got_exception; + } + + if (!wasm_elem_is_passive( + module->module->table_segments[elem_idx].mode)) { + wasm_set_exception(module, "out of bounds table access"); + goto got_exception; + } + + bh_memcpy_s( + (uint8 *)tbl_inst + offsetof(WASMTableInstance, base_addr) + + d * sizeof(uint32), + (tbl_inst->cur_size - d) * sizeof(uint32), + module->module->table_segments[elem_idx].func_indexes + s, + n * sizeof(uint32)); + break; + } + case WASM_OP_ELEM_DROP: + { + uint32 elem_idx = read_uint32(frame_ip); + bh_assert(elem_idx < module->module->table_seg_count); + + module->module->table_segments[elem_idx].is_dropped = true; + break; + } + case WASM_OP_TABLE_COPY: + { + uint32 src_tbl_idx, dst_tbl_idx; + uint64 n, s, d; + WASMTableInstance *src_tbl_inst, *dst_tbl_inst; + + dst_tbl_idx = read_uint32(frame_ip); + bh_assert(dst_tbl_idx < module->table_count); + + dst_tbl_inst = wasm_get_table_inst(module, dst_tbl_idx); + + src_tbl_idx = read_uint32(frame_ip); + bh_assert(src_tbl_idx < module->table_count); + + src_tbl_inst = wasm_get_table_inst(module, src_tbl_idx); + + n = (uint32)POP_I32(); + s = (uint32)POP_I32(); + d = (uint32)POP_I32(); + + if (s + n > dst_tbl_inst->cur_size + || d + n > src_tbl_inst->cur_size) { + wasm_set_exception(module, "out of bounds table access"); + goto got_exception; + } + + /* if s >= d, copy from front to back */ + /* if s < d, copy from back to front */ + /* merge all together */ + bh_memcpy_s( + (uint8 *)dst_tbl_inst + offsetof(WASMTableInstance, base_addr) + + d * sizeof(uint32), + (dst_tbl_inst->cur_size - d) * sizeof(uint32), + (uint8 *)src_tbl_inst + + offsetof(WASMTableInstance, base_addr) + s * sizeof(uint32), + n * sizeof(uint32)); + break; + } + case WASM_OP_TABLE_GROW: + { + uint32 tbl_idx, n, init_val, orig_tbl_sz; + WASMTableInstance *tbl_inst; + + tbl_idx = read_uint32(frame_ip); + bh_assert(tbl_idx < module->table_count); + + tbl_inst = wasm_get_table_inst(module, tbl_idx); + + orig_tbl_sz = tbl_inst->cur_size; + + n = POP_I32(); + init_val = POP_I32(); + + if (!wasm_enlarge_table(module, tbl_idx, n, init_val)) { + PUSH_I32(-1); + } else { + PUSH_I32(orig_tbl_sz); + } + + break; + } + case WASM_OP_TABLE_SIZE: + { + uint32 tbl_idx; + WASMTableInstance *tbl_inst; + + tbl_idx = read_uint32(frame_ip); + bh_assert(tbl_idx < module->table_count); + + tbl_inst = wasm_get_table_inst(module, tbl_idx); + + PUSH_I32(tbl_inst->cur_size); + break; + } + case WASM_OP_TABLE_FILL: + { + uint32 tbl_idx, n, val, i; + WASMTableInstance *tbl_inst; + + tbl_idx = read_uint32(frame_ip); + bh_assert(tbl_idx < module->table_count); + + tbl_inst = wasm_get_table_inst(module, tbl_idx); + + n = POP_I32(); + val = POP_I32(); + i = POP_I32(); + + if (i + n > tbl_inst->cur_size) { + wasm_set_exception(module, "out of bounds table access"); + goto got_exception; + } + + for (; n != 0; i++, n--) { + ((uint32 *)(tbl_inst->base_addr))[i] = val; + } + + break; + } +#endif /* WASM_ENABLE_REF_TYPES */ default: wasm_set_exception(module, "unsupported opcode"); - goto got_exception; - break; + goto got_exception; } HANDLE_OP_END (); } @@ -2992,16 +3207,25 @@ recover_br_info: HANDLE_OP (WASM_OP_RETURN_CALL): HANDLE_OP (WASM_OP_RETURN_CALL_INDIRECT): #endif +#if WASM_ENABLE_SHARED_MEMORY == 0 + HANDLE_OP (WASM_OP_ATOMIC_PREFIX): +#endif +#if WASM_ENABLE_REF_TYPES == 0 + HANDLE_OP (WASM_OP_TABLE_GET): + HANDLE_OP (WASM_OP_TABLE_SET): + HANDLE_OP (WASM_OP_REF_NULL): + HANDLE_OP (WASM_OP_REF_IS_NULL): + HANDLE_OP (WASM_OP_REF_FUNC): +#endif + /* SELECT_T is converted to SELECT or SELECT_64 */ + HANDLE_OP (WASM_OP_SELECT_T): HANDLE_OP (WASM_OP_UNUSED_0x14): HANDLE_OP (WASM_OP_UNUSED_0x15): HANDLE_OP (WASM_OP_UNUSED_0x16): HANDLE_OP (WASM_OP_UNUSED_0x17): HANDLE_OP (WASM_OP_UNUSED_0x18): HANDLE_OP (WASM_OP_UNUSED_0x19): - HANDLE_OP (WASM_OP_UNUSED_0x1c): - HANDLE_OP (WASM_OP_UNUSED_0x1d): - HANDLE_OP (WASM_OP_UNUSED_0x1e): - HANDLE_OP (WASM_OP_UNUSED_0x1f): + HANDLE_OP (WASM_OP_UNUSED_0x27): /* optimized op code */ HANDLE_OP (WASM_OP_F32_STORE): HANDLE_OP (WASM_OP_F64_STORE): diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index 2ab8aa53d..c1af8a8fd 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -96,6 +96,7 @@ read_leb(uint8 **p_buf, const uint8 *buf_end, uint64 byte; while (true) { + /* uN or SN must not exceed ceil(N/7) bytes */ if (bcnt + 1 > (maxbits + 6) / 7) { set_error_buf(error_buf, error_buf_size, "integer representation too long"); @@ -188,6 +189,67 @@ fail: res = (int32)res64; \ } while (0) +static char * +type2str(uint8 type) +{ + char *type_str[] = { "v128", "f64", "f32", "i64", "i32" }; + + if (type >= VALUE_TYPE_V128 && type <= VALUE_TYPE_I32) + return type_str[type - VALUE_TYPE_V128]; + else if (type == VALUE_TYPE_FUNCREF) + return "funcref"; + else if (type == VALUE_TYPE_EXTERNREF) + return "externref"; + else + return "unknown type"; +} + +static bool +is_32bit_type(uint8 type) +{ + if (type == VALUE_TYPE_I32 || type == VALUE_TYPE_F32 +#if WASM_ENABLE_REF_TYPES != 0 + || (wasm_get_ref_types_flag() + && (type == VALUE_TYPE_FUNCREF || type == VALUE_TYPE_EXTERNREF)) +#endif + ) + return true; + return false; +} + +static bool +is_64bit_type(uint8 type) +{ + if (type == VALUE_TYPE_I64 || type == VALUE_TYPE_F64) + return true; + return false; +} + +static bool +is_value_type(uint8 type) +{ + if (type == VALUE_TYPE_I32 || type == VALUE_TYPE_I64 + || type == VALUE_TYPE_F32 || type == VALUE_TYPE_F64 +#if WASM_ENABLE_REF_TYPES != 0 + || (wasm_get_ref_types_flag() + && (type == VALUE_TYPE_FUNCREF || type == VALUE_TYPE_EXTERNREF)) +#endif +#if WASM_ENABLE_SIMD != 0 +#if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0) + || type == VALUE_TYPE_V128 +#endif +#endif + ) + return true; + return false; +} + +static bool +is_byte_a_type(uint8 type) +{ + return is_value_type(type) || (type == VALUE_TYPE_VOID); +} + #if WASM_ENABLE_SIMD != 0 #if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0) static V128 @@ -394,7 +456,7 @@ load_init_expr(const uint8 **p_buf, const uint8 *buf_end, uint64 high, low; if (type != VALUE_TYPE_V128) - goto fail; + goto fail_type_mismatch; flag = read_uint8(p); (void)flag; @@ -409,20 +471,57 @@ load_init_expr(const uint8 **p_buf, const uint8 *buf_end, } #endif /* end of (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0) */ #endif /* end of WASM_ENABLE_SIMD */ +#if WASM_ENABLE_REF_TYPES != 0 + case INIT_EXPR_TYPE_FUNCREF_CONST: + { + if (!wasm_get_ref_types_flag()) { + goto illegal_opcode; + } + + if (type != VALUE_TYPE_FUNCREF) + goto fail_type_mismatch; + read_leb_uint32(p, p_end, init_expr->u.ref_index); + break; + } + case INIT_EXPR_TYPE_REFNULL_CONST: + { + uint8 reftype; + + if (!wasm_get_ref_types_flag()) { + goto illegal_opcode; + } + + CHECK_BUF(p, p_end, 1); + reftype = read_uint8(p); + if (reftype != type) + goto fail_type_mismatch; + + init_expr->u.ref_index = NULL_REF; + break; + } +#endif /* WASM_ENABLE_REF_TYPES != 0 */ /* get_global */ case INIT_EXPR_TYPE_GET_GLOBAL: read_leb_uint32(p, p_end, init_expr->u.global_index); break; - default: - goto fail_type_mismatch; + default: { +#if WASM_ENABLE_REF_TYPES != 0 +illegal_opcode: +#endif + set_error_buf(error_buf, error_buf_size, + "illegal opcode " + "or constant expression required " + "or type mismatch"); + goto fail; + } } CHECK_BUF(p, p_end, 1); end_byte = read_uint8(p); if (end_byte != 0x0b) goto fail_type_mismatch; *p_buf = p; - return true; + fail_type_mismatch: set_error_buf(error_buf, error_buf_size, "type mismatch or constant expression required"); @@ -520,6 +619,27 @@ fail: return false; } +static void +adjust_table_max_size(uint32 init_size, uint32 max_size_flag, uint32 *max_size) +{ + uint32 default_max_size = + init_size * 2 > TABLE_MAX_SIZE ? init_size * 2 : TABLE_MAX_SIZE; + + if (max_size_flag) { + /* module defines the table limitation */ + bh_assert(init_size <= *max_size); + + if (init_size < *max_size) { + *max_size = + *max_size < default_max_size ? *max_size : default_max_size; + } + } + else { + /* partial defined table limitation, gives a default value */ + *max_size = default_max_size; + } +} + #if WASM_ENABLE_MULTI_MODULE != 0 /** * Find export item of a module with export info: @@ -752,7 +872,8 @@ wasm_loader_resolve_global(const char *module_name, if (export->index < module->import_global_count) { global = module->import_globals[export->index].u.global.import_global_linked; - } else { + } + else { global = &(module->globals[export->index - module->import_global_count]); } @@ -1021,33 +1142,44 @@ load_table_import(const uint8 **p_buf, const uint8 *buf_end, char *error_buf, uint32 error_buf_size) { const uint8 *p = *p_buf, *p_end = buf_end; - uint32 declare_elem_type = 0; - uint32 declare_max_size_flag = 0; - uint32 declare_init_size = 0; - uint32 declare_max_size = 0; + uint32 declare_elem_type = 0, declare_max_size_flag = 0, + declare_init_size = 0, declare_max_size = 0; #if WASM_ENABLE_MULTI_MODULE != 0 WASMModule *sub_module = NULL; WASMTable *linked_table = NULL; #endif CHECK_BUF(p, p_end, 1); - /* 0x70 */ + /* 0x70 or 0x6F */ declare_elem_type = read_uint8(p); - if (TABLE_ELEM_TYPE_ANY_FUNC != declare_elem_type) { + if (VALUE_TYPE_FUNCREF != declare_elem_type +#if WASM_ENABLE_REF_TYPES != 0 + && (wasm_get_ref_types_flag() + && VALUE_TYPE_EXTERNREF != declare_elem_type) +#endif + ) { set_error_buf(error_buf, error_buf_size, "incompatible import type"); return false; } read_leb_uint32(p, p_end, declare_max_size_flag); + if (declare_max_size_flag > 1) { + set_error_buf(error_buf, error_buf_size, "integer too large"); + return false; + } + read_leb_uint32(p, p_end, declare_init_size); - if (declare_max_size_flag & 1) { + + if (declare_max_size_flag) { read_leb_uint32(p, p_end, declare_max_size); - if (!check_table_max_size(table->init_size, table->max_size, + if (!check_table_max_size(declare_init_size, declare_max_size, error_buf, error_buf_size)) return false; - } else { - declare_max_size = 0x10000; } + + adjust_table_max_size(declare_init_size, declare_max_size_flag, + &declare_max_size); + *p_buf = p; #if WASM_ENABLE_MULTI_MODULE != 0 @@ -1074,12 +1206,13 @@ load_table_import(const uint8 **p_buf, const uint8 *buf_end, table->import_table_linked = linked_table; table->import_module = sub_module; } -#endif +#endif /* WASM_ENABLE_MULTI_MODULE != 0 */ /* (table (export "table") 10 20 funcref) */ + /* we need this section working in wamrc */ if (!strcmp("spectest", sub_module_name)) { - uint32 spectest_table_init_size = 10; - uint32 spectest_table_max_size = 20; + const uint32 spectest_table_init_size = 10; + const uint32 spectest_table_max_size = 20; if (strcmp("table", table_name)) { set_error_buf(error_buf, error_buf_size, @@ -1323,9 +1456,14 @@ load_table(const uint8 **p_buf, const uint8 *buf_end, WASMTable *table, const uint8 *p = *p_buf, *p_end = buf_end, *p_org; CHECK_BUF(p, p_end, 1); - /* 0x70 */ + /* 0x70 or 0x6F */ table->elem_type = read_uint8(p); - if (TABLE_ELEM_TYPE_ANY_FUNC != table->elem_type) { + if (VALUE_TYPE_FUNCREF != table->elem_type +#if WASM_ENABLE_REF_TYPES != 0 + && (wasm_get_ref_types_flag() + && VALUE_TYPE_EXTERNREF != table->elem_type) +#endif + ) { set_error_buf(error_buf, error_buf_size, "incompatible import type"); return false; } @@ -1358,16 +1496,16 @@ load_table(const uint8 **p_buf, const uint8 *buf_end, WASMTable *table, #endif read_leb_uint32(p, p_end, table->init_size); - if (table->flags == 0) { - table->max_size = 0x10000; - } - else if (table->flags == 1) { + + if (table->flags) { read_leb_uint32(p, p_end, table->max_size); - if (!check_table_max_size(table->init_size, table->max_size, - error_buf, error_buf_size)) + if (!check_table_max_size(table->init_size, table->max_size, error_buf, + error_buf_size)) return false; } + adjust_table_max_size(table->init_size, table->flags, &table->max_size); + *p_buf = p; return true; fail: @@ -1506,7 +1644,13 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, if (flags & 1) read_leb_uint32(p, p_end, u32); module->import_table_count++; - if (module->import_table_count > 1) { + + if ( +#if WASM_ENABLE_REF_TYPES != 0 + !wasm_get_ref_types_flag() && + +#endif + module->import_table_count > 1) { set_error_buf(error_buf, error_buf_size, "multiple tables"); return false; @@ -1722,7 +1866,8 @@ load_function_section(const uint8 *buf, const uint8 *buf_end, if (func_count != code_count) { set_error_buf(error_buf, error_buf_size, - "function and code section have inconsistent lengths"); + "function and code section have inconsistent lengths or " + "unexpected end"); return false; } @@ -1822,10 +1967,19 @@ load_function_section(const uint8 *buf, const uint8 *buf_end, && type != VALUE_TYPE_V128 #endif #endif - ) { +#if WASM_ENABLE_REF_TYPES != 0 + && (wasm_get_ref_types_flag() && type != VALUE_TYPE_FUNCREF + && type != VALUE_TYPE_EXTERNREF) +#endif + ) { if (type == VALUE_TYPE_V128) set_error_buf(error_buf, error_buf_size, "v128 value type requires simd feature"); + else if (type == VALUE_TYPE_FUNCREF + || type == VALUE_TYPE_EXTERNREF) + set_error_buf(error_buf, error_buf_size, + "ref value type requires " + "reference types feature"); else set_error_buf_v(error_buf, error_buf_size, "invalid local type 0x%02X", type); @@ -1859,6 +2013,21 @@ fail: return false; } +static bool +check_function_index(const WASMModule *module, + uint32 function_index, + char *error_buf, + uint32 error_buf_size) +{ + if (function_index + >= module->import_function_count + module->function_count) { + set_error_buf_v(error_buf, error_buf_size, "unknown function %d", + function_index); + return false; + } + return true; +} + static bool load_table_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, char *error_buf, uint32 error_buf_size) @@ -1869,8 +2038,12 @@ load_table_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, WASMTable *table; read_leb_uint32(p, p_end, table_count); - /* a total of one table is allowed */ - if (module->import_table_count + table_count > 1) { + if ( +#if WASM_ENABLE_REF_TYPES != 0 + !wasm_get_ref_types_flag() && +#endif + module->import_table_count + table_count > 1) { + /* a total of one table is allowed */ set_error_buf(error_buf, error_buf_size, "multiple tables"); return false; } @@ -1993,6 +2166,13 @@ load_global_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, return false; } } + else if (INIT_EXPR_TYPE_FUNCREF_CONST == global->init_expr.init_expr_type) { + if (!check_function_index(module, + global->init_expr.u.ref_index, + error_buf, error_buf_size)) { + return false; + } + } } } @@ -2117,12 +2297,140 @@ fail: return false; } +static bool +check_table_index(const WASMModule *module, uint32 table_index, + char *error_buf, uint32 error_buf_size) +{ + if ( +#if WASM_ENABLE_REF_TYPES != 0 + !wasm_get_ref_types_flag() && +#endif + table_index != 0) { + set_error_buf(error_buf, error_buf_size, "zero flag expected"); + return false; + } + + if (table_index >= module->import_table_count + module->table_count) { + set_error_buf_v(error_buf, error_buf_size, "unknown table %d", + table_index); + return false; + } + return true; +} + +static bool +load_table_index(const uint8 **p_buf, const uint8 *buf_end, + WASMModule *module, uint32 *p_table_index, + char *error_buf, uint32 error_buf_size) +{ + const uint8 *p = *p_buf, *p_end = buf_end; + uint32 table_index; + + read_leb_uint32(p, p_end, table_index); + if (!check_table_index(module, table_index, error_buf, error_buf_size)) { + return false; + } + + *p_table_index = table_index; + *p_buf = p; + return true; +fail: + return false; +} + +#if WASM_ENABLE_REF_TYPES != 0 +static bool +load_elem_type(const uint8 **p_buf, const uint8 *buf_end, + uint32 *p_elem_type, bool elemkind_zero, + char *error_buf, uint32 error_buf_size) +{ + const uint8 *p = *p_buf, *p_end = buf_end; + uint8 elem_type; + + CHECK_BUF(p, p_end, 1); + elem_type = read_uint8(p); + if ((elemkind_zero && elem_type != 0) + || (!elemkind_zero && elem_type != VALUE_TYPE_FUNCREF + && elem_type != VALUE_TYPE_EXTERNREF)) { + set_error_buf(error_buf, error_buf_size, "invalid reference type"); + return false; + } + + if (elemkind_zero) + *p_elem_type = VALUE_TYPE_FUNCREF; + else + *p_elem_type = elem_type; + *p_buf = p; + return true; +fail: + return false; +} +#endif /* WASM_ENABLE_REF_TYPES != 0*/ + +static bool +load_func_index_vec(const uint8 **p_buf, const uint8 *buf_end, + WASMModule *module, WASMTableSeg *table_segment, + bool use_init_expr, + char *error_buf, uint32 error_buf_size) +{ + const uint8 *p = *p_buf, *p_end = buf_end; + uint32 function_count, function_index = 0, i; + uint64 total_size; + + read_leb_uint32(p, p_end, function_count); + table_segment->function_count = function_count; + total_size = sizeof(uint32) * (uint64)function_count; + if (total_size > 0 + && !(table_segment->func_indexes = (uint32 *) + loader_malloc(total_size, error_buf, error_buf_size))) { + return false; + } + + for (i = 0; i < function_count; i++) { + InitializerExpression init_expr = { 0 }; + +#if WASM_ENABLE_REF_TYPES != 0 + if (!wasm_get_ref_types_flag()) { + read_leb_uint32(p, p_end, function_index); + } + else { + if (!use_init_expr) { + read_leb_uint32(p, p_end, function_index); + } + else { + if (!load_init_expr(&p, p_end, &init_expr, + table_segment->elem_type, error_buf, + error_buf_size)) + return false; + + function_index = init_expr.u.ref_index; + } + } +#else + read_leb_uint32(p, p_end, function_index); +#endif + + /* since we are using -1 to indicate ref.null */ + if (init_expr.init_expr_type != INIT_EXPR_TYPE_REFNULL_CONST + && !check_function_index(module, function_index, error_buf, + error_buf_size)) { + return false; + } + table_segment->func_indexes[i] = function_index; + } + + *p_buf = p; + return true; +fail: + return false; +} + static bool load_table_segment_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, char *error_buf, uint32 error_buf_size) { const uint8 *p = buf, *p_end = buf_end; - uint32 table_segment_count, i, j, table_index, function_count, function_index; + uint32 table_segment_count, i; uint64 total_size; WASMTableSeg *table_segment; @@ -2139,41 +2447,106 @@ load_table_segment_section(const uint8 *buf, const uint8 *buf_end, WASMModule *m table_segment = module->table_segments; for (i = 0; i < table_segment_count; i++, table_segment++) { if (p >= p_end) { - set_error_buf(error_buf, error_buf_size, "unexpected end"); - return false; - } - read_leb_uint32(p, p_end, table_index); - if (table_index - >= module->import_table_count + module->table_count) { - LOG_DEBUG("table#%d does not exist", table_index); - set_error_buf(error_buf, error_buf_size, "unknown table"); + set_error_buf(error_buf, error_buf_size, + "invalid value type or " + "invalid elements segment kind"); return false; } - table_segment->table_index = table_index; +#if WASM_ENABLE_REF_TYPES != 0 + if (wasm_get_ref_types_flag()) { + read_leb_uint32(p, p_end, table_segment->mode); + /* last three bits */ + table_segment->mode = table_segment->mode & 0x07; + switch (table_segment->mode) { + /* elemkind/elemtype + active */ + case 0: + case 4: + table_segment->elem_type = VALUE_TYPE_FUNCREF; + table_segment->table_index = 0; - /* initialize expression */ - if (!load_init_expr(&p, p_end, &(table_segment->base_offset), - VALUE_TYPE_I32, error_buf, error_buf_size)) - return false; - - read_leb_uint32(p, p_end, function_count); - table_segment->function_count = function_count; - total_size = sizeof(uint32) * (uint64)function_count; - if (total_size > 0 - && !(table_segment->func_indexes = (uint32 *) - loader_malloc(total_size, error_buf, error_buf_size))) { - return false; - } - for (j = 0; j < function_count; j++) { - read_leb_uint32(p, p_end, function_index); - if (function_index >= module->import_function_count - + module->function_count) { - set_error_buf(error_buf, error_buf_size, - "unknown function"); - return false; + if (!check_table_index(module, + table_segment->table_index, + error_buf, error_buf_size)) + return false; + if (!load_init_expr( + &p, p_end, &table_segment->base_offset, + VALUE_TYPE_I32, error_buf, error_buf_size)) + return false; + if (!load_func_index_vec( + &p, p_end, module, table_segment, + table_segment->mode == 0 ? false : true, + error_buf, error_buf_size)) + return false; + break; + /* elemkind + passive/declarative */ + case 1: + case 3: + if (!load_elem_type(&p, p_end, + &table_segment->elem_type, true, + error_buf, error_buf_size)) + return false; + if (!load_func_index_vec(&p, p_end, module, + table_segment, false, + error_buf, error_buf_size)) + return false; + break; + /* elemkind/elemtype + table_idx + active */ + case 2: + case 6: + if (!load_table_index(&p, p_end, module, + &table_segment->table_index, + error_buf, error_buf_size)) + return false; + if (!load_init_expr( + &p, p_end, &table_segment->base_offset, + VALUE_TYPE_I32, error_buf, error_buf_size)) + return false; + if (!load_elem_type( + &p, p_end, &table_segment->elem_type, + table_segment->mode == 2 ? true : false, + error_buf, error_buf_size)) + return false; + if (!load_func_index_vec( + &p, p_end, module, table_segment, + table_segment->mode == 2 ? false : true, + error_buf, error_buf_size)) + return false; + break; + case 5: + case 7: + if (!load_elem_type(&p, p_end, + &table_segment->elem_type, false, + error_buf, error_buf_size)) + return false; + if (!load_func_index_vec(&p, p_end, module, + table_segment, true, + error_buf, error_buf_size)) + return false; + break; + default: + set_error_buf(error_buf, error_buf_size, + "unknown element segment kind"); + return false; } - table_segment->func_indexes[j] = function_index; + } + else +#endif /* WASM_ENABLE_REF_TYPES != 0 */ + { + /* + * like: 00 41 05 0b 04 00 01 00 01 + * for: (elem 0 (offset (i32.const 5)) $f1 $f2 $f1 $f2) + */ + if (!load_table_index(&p, p_end, module, + &table_segment->table_index, error_buf, + error_buf_size)) + return false; + if (!load_init_expr(&p, p_end, &table_segment->base_offset, + VALUE_TYPE_I32, error_buf, error_buf_size)) + return false; + if (!load_func_index_vec(&p, p_end, module, table_segment, + false, error_buf, error_buf_size)) + return false; } } } @@ -2242,8 +2615,8 @@ load_data_segment_section(const uint8 *buf, const uint8 *buf_end, check_mem_index: if (mem_index >= module->import_memory_count + module->memory_count) { - LOG_DEBUG("memory#%d does not exist", mem_index); - set_error_buf(error_buf, error_buf_size, "unknown memory"); + set_error_buf_v(error_buf, error_buf_size, + "unknown memory %d", mem_index); return false; } break; @@ -2256,8 +2629,8 @@ check_mem_index: #else if (mem_index >= module->import_memory_count + module->memory_count) { - LOG_DEBUG("memory#%d does not exist", mem_index); - set_error_buf(error_buf, error_buf_size, "unknown memory"); + set_error_buf_v(error_buf, error_buf_size, "unknown memory %d", + mem_index); return false; } #endif /* WASM_ENABLE_BULK_MEMORY */ @@ -2530,7 +2903,8 @@ fail: } static bool -wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, +wasm_loader_prepare_bytecode(WASMModule *module, + WASMFunction *func, uint32 cur_func_idx, char *error_buf, uint32 error_buf_size); #if WASM_ENABLE_FAST_INTERP != 0 && WASM_ENABLE_LABELS_AS_VALUES != 0 @@ -2842,7 +3216,7 @@ load_from_sections(WASMModule *module, WASMSection *sections, for (i = 0; i < module->function_count; i++) { WASMFunction *func = module->functions[i]; - if (!wasm_loader_prepare_bytecode(module, func, + if (!wasm_loader_prepare_bytecode(module, func, i, error_buf, error_buf_size)) { return false; } @@ -3378,6 +3752,46 @@ wasm_loader_find_block_addr(BlockAddr *block_addr_cache, case WASM_OP_SELECT_64: break; +#if WASM_ENABLE_REF_TYPES != 0 + case WASM_OP_SELECT_T: + if (!wasm_get_ref_types_flag()) { + return false; + } + + skip_leb_uint32(p, p_end); /* vec length */ + CHECK_BUF(p, p_end, 1); + u8 = read_uint8(p); /* typeidx */ + break; + case WASM_OP_TABLE_GET: + case WASM_OP_TABLE_SET: + if (!wasm_get_ref_types_flag()) { + return false; + } + + skip_leb_uint32(p, p_end); /* table index */ + break; + case WASM_OP_REF_NULL: + if (!wasm_get_ref_types_flag()) { + return false; + } + + CHECK_BUF(p, p_end, 1); + u8 = read_uint8(p); /* type */ + break; + case WASM_OP_REF_IS_NULL: + if (!wasm_get_ref_types_flag()) { + return false; + } + + break; + case WASM_OP_REF_FUNC: + if (!wasm_get_ref_types_flag()) { + return false; + } + + skip_leb_uint32(p, p_end); /* func index */ + break; +#endif /* WASM_ENABLE_REF_TYPES */ case WASM_OP_GET_LOCAL: case WASM_OP_SET_LOCAL: case WASM_OP_TEE_LOCAL: @@ -3386,7 +3800,7 @@ wasm_loader_find_block_addr(BlockAddr *block_addr_cache, case WASM_OP_GET_GLOBAL_64: case WASM_OP_SET_GLOBAL_64: case WASM_OP_SET_GLOBAL_AUX_STACK: - skip_leb_uint32(p, p_end); /* localidx */ + skip_leb_uint32(p, p_end); /* local index */ break; case EXT_OP_GET_LOCAL_FAST: @@ -3603,7 +4017,34 @@ wasm_loader_find_block_addr(BlockAddr *block_addr_cache, /* skip memory idx */ p++; break; -#endif +#endif /* WASM_ENABLE_BULK_MEMORY */ +#if WASM_ENABLE_REF_TYPES != 0 + case WASM_OP_TABLE_INIT: + case WASM_OP_TABLE_COPY: + if (!wasm_get_ref_types_flag()) { + return false; + } + /* tableidx */ + skip_leb_uint32(p, p_end); + /* elemidx */ + skip_leb_uint32(p, p_end); + break; + case WASM_OP_ELEM_DROP: + if (!wasm_get_ref_types_flag()) { + return false; + } + /* elemidx */ + skip_leb_uint32(p, p_end); + break; + case WASM_OP_TABLE_SIZE: + case WASM_OP_TABLE_GROW: + case WASM_OP_TABLE_FILL: + if (!wasm_get_ref_types_flag()) { + return false; + } + skip_leb_uint32(p, p_end); /* table idx */ + break; +#endif /* WASM_ENABLE_REF_TYPES */ default: return false; } @@ -3708,6 +4149,7 @@ fail: return false; } +#define REF_ANY VALUE_TYPE_ANY #define REF_I32 VALUE_TYPE_I32 #define REF_F32 VALUE_TYPE_F32 #define REF_I64_1 VALUE_TYPE_I64 @@ -3718,7 +4160,8 @@ fail: #define REF_V128_2 VALUE_TYPE_V128 #define REF_V128_3 VALUE_TYPE_V128 #define REF_V128_4 VALUE_TYPE_V128 -#define REF_ANY VALUE_TYPE_ANY +#define REF_FUNCREF VALUE_TYPE_FUNCREF +#define REF_EXTERNREF VALUE_TYPE_EXTERNREF #if WASM_ENABLE_FAST_INTERP != 0 @@ -3905,7 +4348,7 @@ free_all_label_patch_lists(BranchBlock *frame_csp, uint32 csp_num) } } -#endif +#endif /* end of WASM_ENABLE_FAST_INTERP */ static bool check_stack_push(WASMLoaderContext *ctx, @@ -3928,12 +4371,8 @@ static bool check_stack_top_values(uint8 *frame_ref, int32 stack_cell_num, uint8 type, char *error_buf, uint32 error_buf_size) { - char *type_str[] = { "v128", "f64", "f32", "i64", "i32" }; - - if (((type == VALUE_TYPE_I32 || type == VALUE_TYPE_F32) - && stack_cell_num < 1) - || ((type == VALUE_TYPE_I64 || type == VALUE_TYPE_F64) - && stack_cell_num < 2) + if ((is_32bit_type(type) && stack_cell_num < 1) + || (is_64bit_type(type) && stack_cell_num < 2) #if WASM_ENABLE_SIMD != 0 #if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0) || (type == VALUE_TYPE_V128 && stack_cell_num < 4) @@ -3945,14 +4384,9 @@ check_stack_top_values(uint8 *frame_ref, int32 stack_cell_num, uint8 type, return false; } - if ((type == VALUE_TYPE_I32 && *(frame_ref - 1) != REF_I32) - || (type == VALUE_TYPE_F32 && *(frame_ref - 1) != REF_F32) - || (type == VALUE_TYPE_I64 - && (*(frame_ref - 2) != REF_I64_1 - || *(frame_ref - 1) != REF_I64_2)) - || (type == VALUE_TYPE_F64 - && (*(frame_ref - 2) != REF_F64_1 - || *(frame_ref - 1) != REF_F64_2)) + if ((is_32bit_type(type) && *(frame_ref - 1) != type) + || (is_64bit_type(type) + && (*(frame_ref - 2) != type || *(frame_ref - 1) != type)) #if WASM_ENABLE_SIMD != 0 #if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0) || (type == VALUE_TYPE_V128 @@ -3962,10 +4396,10 @@ check_stack_top_values(uint8 *frame_ref, int32 stack_cell_num, uint8 type, || *(frame_ref - 1) != REF_V128_4)) #endif #endif - ) { + ) { set_error_buf_v(error_buf, error_buf_size, "%s%s%s", "type mismatch: expect ", - type_str[type - VALUE_TYPE_V128], + type2str(type), " but got other"); return false; } @@ -4077,20 +4511,14 @@ wasm_loader_push_frame_ref(WASMLoaderContext *ctx, uint8 type, *ctx->frame_ref++ = type; ctx->stack_cell_num++; - if (ctx->stack_cell_num > ctx->max_stack_cell_num) - ctx->max_stack_cell_num = ctx->stack_cell_num; - - if (type == VALUE_TYPE_I32 - || type == VALUE_TYPE_F32 - || type == VALUE_TYPE_ANY) - return true; + if (is_32bit_type(type) || type == VALUE_TYPE_ANY) + goto check_stack_and_return; if (!check_stack_push(ctx, error_buf, error_buf_size)) return false; + *ctx->frame_ref++ = type; ctx->stack_cell_num++; - if (ctx->stack_cell_num > ctx->max_stack_cell_num) - ctx->max_stack_cell_num = ctx->stack_cell_num; #if WASM_ENABLE_SIMD != 0 #if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0) @@ -4103,11 +4531,13 @@ wasm_loader_push_frame_ref(WASMLoaderContext *ctx, uint8 type, return false; *ctx->frame_ref++ = type; ctx->stack_cell_num++; - if (ctx->stack_cell_num > ctx->max_stack_cell_num) - ctx->max_stack_cell_num = ctx->stack_cell_num; } #endif #endif + +check_stack_and_return: + if (ctx->stack_cell_num > ctx->max_stack_cell_num) + ctx->max_stack_cell_num = ctx->stack_cell_num; return true; } @@ -4133,9 +4563,7 @@ wasm_loader_pop_frame_ref(WASMLoaderContext *ctx, uint8 type, ctx->frame_ref--; ctx->stack_cell_num--; - if (type == VALUE_TYPE_I32 - || type == VALUE_TYPE_F32 - || *ctx->frame_ref == VALUE_TYPE_ANY) + if (is_32bit_type(type) || *ctx->frame_ref == VALUE_TYPE_ANY) return true; ctx->frame_ref--; @@ -4480,8 +4908,7 @@ preserve_referenced_local(WASMLoaderContext *loader_ctx, uint8 opcode, if (loader_ctx->p_code_compiled) { bh_assert(preserved_offset != (int16)local_index); } - if (local_type == VALUE_TYPE_I32 - || local_type == VALUE_TYPE_F32) { + if (is_32bit_type(local_type)) { /* Only increase preserve offset in the second traversal */ if (loader_ctx->p_code_compiled) loader_ctx->preserved_local_offset++; @@ -4499,7 +4926,7 @@ preserve_referenced_local(WASMLoaderContext *loader_ctx, uint8 opcode, loader_ctx->frame_offset_bottom[i] = preserved_offset; } - if (cur_type == VALUE_TYPE_I32 || cur_type == VALUE_TYPE_F32) + if (is_32bit_type(cur_type)) i++; else i += 2; @@ -4535,7 +4962,7 @@ preserve_local_for_block(WASMLoaderContext *loader_ctx, uint8 opcode, return false; } - if (cur_type == VALUE_TYPE_I32 || cur_type == VALUE_TYPE_F32) { + if (is_32bit_type(cur_type)) { i++; } else { @@ -4696,7 +5123,7 @@ wasm_loader_push_frame_offset(WASMLoaderContext *ctx, uint8 type, ctx->max_dynamic_offset = ctx->dynamic_offset; } - if (type == VALUE_TYPE_I32 || type == VALUE_TYPE_F32) + if (is_32bit_type(type)) return true; if (ctx->p_code_compiled == NULL) { @@ -4735,7 +5162,7 @@ wasm_loader_pop_frame_offset(WASMLoaderContext *ctx, uint8 type, if (type == VALUE_TYPE_VOID) return true; - if (type == VALUE_TYPE_I32 || type == VALUE_TYPE_F32) { + if (is_32bit_type(type)) { /* Check the offset stack bottom to ensure the frame offset stack will not go underflow. But we don't thrown error and return true here, because the error msg should be @@ -4767,7 +5194,9 @@ wasm_loader_push_pop_frame_offset(WASMLoaderContext *ctx, uint8 pop_cnt, bool disable_emit, int16 operand_offset, char *error_buf, uint32 error_buf_size) { - for (int i = 0; i < pop_cnt; i++) { + uint8 i; + + for (i = 0; i < pop_cnt; i++) { if (!wasm_loader_pop_frame_offset(ctx, type_pop, error_buf, error_buf_size)) return false; } @@ -4832,21 +5261,25 @@ wasm_loader_get_const_offset(WASMLoaderContext *ctx, uint8 type, Const *c; for (c = (Const *)ctx->const_buf; (uint8*)c < ctx->const_buf + ctx->num_const * sizeof(Const); c ++) { + /* TODO: handle v128 type? */ if ((type == c->value_type) && ((type == VALUE_TYPE_I64 && *(int64*)value == c->value.i64) - || (type == VALUE_TYPE_I32 && *(int32*)value == c->value.i32) - || (type == VALUE_TYPE_F64 - && (0 == memcmp(value, &(c->value.f64), sizeof(float64)))) - || (type == VALUE_TYPE_F32 - && (0 == memcmp(value, &(c->value.f32), sizeof(float32)))))) { + || (type == VALUE_TYPE_I32 && *(int32*)value == c->value.i32) +#if WASM_ENABLE_REF_TYPES != 0 + || (type == VALUE_TYPE_FUNCREF && *(int32*)value == c->value.i32) + || (type == VALUE_TYPE_EXTERNREF && *(int32*)value == c->value.i32) +#endif + || (type == VALUE_TYPE_F64 + && (0 == memcmp(value, &(c->value.f64), sizeof(float64)))) + || (type == VALUE_TYPE_F32 + && (0 == memcmp(value, &(c->value.f32), sizeof(float32)))))) { operand_offset = c->slot_index; break; } - if (c->value_type == VALUE_TYPE_I64 - || c->value_type == VALUE_TYPE_F64) - operand_offset += 2; - else + if (is_32bit_type(c->value_type)) operand_offset += 1; + else + operand_offset += 2; } if ((uint8 *)c == ctx->const_buf + ctx->num_const * sizeof(Const)) { if ((uint8 *)c == ctx->const_buf + ctx->const_buf_size) { @@ -4878,13 +5311,20 @@ wasm_loader_get_const_offset(WASMLoaderContext *ctx, uint8 type, c->value.i32 = *(int32*)value; ctx->const_cell_num ++; break; +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_EXTERNREF: + case VALUE_TYPE_FUNCREF: + c->value.i32 = *(int32*)value; + ctx->const_cell_num ++; + break; +#endif default: break; } c->slot_index = operand_offset; ctx->num_const ++; LOG_OP("#### new const [%d]: %ld\n", - ctx->num_const, (int64)c->value.i64); + ctx->num_const, (int64)c->value.i64); } /* use negetive index for const */ operand_offset = -(operand_offset + 1); @@ -4910,67 +5350,16 @@ fail: PUSH_XXX(); only push the frame_offset stack, no emit */ -#define PUSH_I32() do { \ - if (!wasm_loader_push_frame_ref_offset(loader_ctx, VALUE_TYPE_I32, \ + +#define TEMPLATE_PUSH(Type) do { \ + if (!wasm_loader_push_frame_ref_offset(loader_ctx, VALUE_TYPE_##Type,\ disable_emit, operand_offset,\ error_buf, error_buf_size)) \ goto fail; \ } while (0) -#define PUSH_F32() do { \ - if (!wasm_loader_push_frame_ref_offset(loader_ctx, VALUE_TYPE_F32, \ - disable_emit, operand_offset,\ - error_buf, error_buf_size)) \ - goto fail; \ - } while (0) - -#define PUSH_I64() do { \ - if (!wasm_loader_push_frame_ref_offset(loader_ctx, VALUE_TYPE_I64, \ - disable_emit, operand_offset,\ - error_buf, error_buf_size)) \ - goto fail; \ - } while (0) - -#define PUSH_F64() do { \ - if (!wasm_loader_push_frame_ref_offset(loader_ctx, VALUE_TYPE_F64, \ - disable_emit, operand_offset,\ - error_buf, error_buf_size)) \ - goto fail; \ - } while (0) - -#define PUSH_V128() do { \ - if (!(wasm_loader_push_frame_ref_offset(loader_ctx, VALUE_TYPE_V128,\ - disable_emit, operand_offset,\ - error_buf, error_buf_size)))\ - goto fail; \ - } while (0) - -#define POP_I32() do { \ - if (!wasm_loader_pop_frame_ref_offset(loader_ctx, VALUE_TYPE_I32, \ - error_buf, error_buf_size)) \ - goto fail; \ - } while (0) - -#define POP_F32() do { \ - if (!wasm_loader_pop_frame_ref_offset(loader_ctx, VALUE_TYPE_F32, \ - error_buf, error_buf_size)) \ - goto fail; \ - } while (0) - -#define POP_I64() do { \ - if (!wasm_loader_pop_frame_ref_offset(loader_ctx, VALUE_TYPE_I64, \ - error_buf, error_buf_size)) \ - goto fail; \ - } while (0) - -#define POP_F64() do { \ - if (!wasm_loader_pop_frame_ref_offset(loader_ctx, VALUE_TYPE_F64, \ - error_buf, error_buf_size)) \ - goto fail; \ - } while (0) - -#define POP_V128() do { \ - if (!wasm_loader_pop_frame_ref_offset(loader_ctx, VALUE_TYPE_V128, \ +#define TEMPLATE_POP(Type) do { \ + if (!wasm_loader_pop_frame_ref_offset(loader_ctx, VALUE_TYPE_##Type,\ error_buf, error_buf_size)) \ goto fail; \ } while (0) @@ -5007,62 +5396,14 @@ fail: #else /* WASM_ENABLE_FAST_INTERP */ -#define PUSH_I32() do { \ - if (!(wasm_loader_push_frame_ref(loader_ctx, VALUE_TYPE_I32, \ +#define TEMPLATE_PUSH(Type) do { \ + if (!(wasm_loader_push_frame_ref(loader_ctx, VALUE_TYPE_##Type, \ error_buf, error_buf_size))) \ goto fail; \ } while (0) -#define PUSH_F32() do { \ - if (!(wasm_loader_push_frame_ref(loader_ctx, VALUE_TYPE_F32, \ - error_buf, error_buf_size))) \ - goto fail; \ - } while (0) - -#define PUSH_I64() do { \ - if (!(wasm_loader_push_frame_ref(loader_ctx, VALUE_TYPE_I64, \ - error_buf, error_buf_size))) \ - goto fail; \ - } while (0) - -#define PUSH_F64() do { \ - if (!(wasm_loader_push_frame_ref(loader_ctx, VALUE_TYPE_F64, \ - error_buf, error_buf_size))) \ - goto fail; \ - } while (0) - -#define PUSH_V128() do { \ - if (!(wasm_loader_push_frame_ref(loader_ctx, VALUE_TYPE_V128, \ - error_buf, error_buf_size))) \ - goto fail; \ - } while (0) - -#define POP_I32() do { \ - if (!(wasm_loader_pop_frame_ref(loader_ctx, VALUE_TYPE_I32, \ - error_buf, error_buf_size))) \ - goto fail; \ - } while (0) - -#define POP_F32() do { \ - if (!(wasm_loader_pop_frame_ref(loader_ctx, VALUE_TYPE_F32, \ - error_buf, error_buf_size))) \ - goto fail; \ - } while (0) - -#define POP_I64() do { \ - if (!(wasm_loader_pop_frame_ref(loader_ctx, VALUE_TYPE_I64, \ - error_buf, error_buf_size))) \ - goto fail; \ - } while (0) - -#define POP_F64() do { \ - if (!(wasm_loader_pop_frame_ref(loader_ctx, VALUE_TYPE_F64, \ - error_buf, error_buf_size))) \ - goto fail; \ - } while (0) - -#define POP_V128() do { \ - if (!(wasm_loader_pop_frame_ref(loader_ctx, VALUE_TYPE_V128, \ +#define TEMPLATE_POP(Type) do { \ + if (!(wasm_loader_pop_frame_ref(loader_ctx, VALUE_TYPE_##Type, \ error_buf, error_buf_size))) \ goto fail; \ } while (0) @@ -5083,6 +5424,22 @@ fail: } while (0) #endif /* WASM_ENABLE_FAST_INTERP */ +#define PUSH_I32() TEMPLATE_PUSH(I32) +#define PUSH_F32() TEMPLATE_PUSH(F32) +#define PUSH_I64() TEMPLATE_PUSH(I64) +#define PUSH_F64() TEMPLATE_PUSH(F64) +#define PUSH_V128() TEMPLATE_PUSH(V128) +#define PUSH_FUNCREF() TEMPLATE_PUSH(FUNCREF) +#define PUSH_EXTERNREF() TEMPLATE_PUSH(EXTERNREF) + +#define POP_I32() TEMPLATE_POP(I32) +#define POP_F32() TEMPLATE_POP(F32) +#define POP_I64() TEMPLATE_POP(I64) +#define POP_F64() TEMPLATE_POP(F64) +#define POP_V128() TEMPLATE_POP(V128) +#define POP_FUNCREF() TEMPLATE_POP(FUNCREF) +#define POP_EXTERNREF() TEMPLATE_POP(EXTERNREF) + #if WASM_ENABLE_FAST_INTERP != 0 static bool @@ -5433,17 +5790,6 @@ check_memory_align_equal(uint8 opcode, uint32 align, } #endif /* end of WASM_ENABLE_SHARED_MEMORY */ -static bool -is_value_type(uint8 type) -{ - return type == VALUE_TYPE_I32 || - type == VALUE_TYPE_I64 || - type == VALUE_TYPE_F32 || - type == VALUE_TYPE_F64 || - type == VALUE_TYPE_V128 || - type == VALUE_TYPE_VOID; -} - static bool wasm_loader_check_br(WASMLoaderContext *loader_ctx, uint32 depth, char *error_buf, uint32 error_buf_size) @@ -5741,8 +6087,57 @@ fail: } \ } while (0) +#if WASM_ENABLE_REF_TYPES != 0 static bool -wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, +get_table_elem_type(const WASMModule *module, + uint32 table_idx, uint8 *p_elem_type, + char *error_buf, uint32 error_buf_size) +{ + if (!check_table_index(module, table_idx, error_buf, error_buf_size)) { + return false; + } + + if (p_elem_type) { + if (table_idx < module->import_table_count) + *p_elem_type = module->import_tables[table_idx].u.table.elem_type; + else + *p_elem_type = module->tables[module->import_table_count + + table_idx].elem_type; + } + return true; +} + +static bool +get_table_seg_elem_type(const WASMModule *module, + uint32 table_seg_idx, uint8 *p_elem_type, + char *error_buf, uint32 error_buf_size) +{ + if (table_seg_idx >= module->table_seg_count) { +#if WASM_ENABLE_REF_TYPES != 0 + if (!wasm_get_ref_types_flag()) { + set_error_buf(error_buf, error_buf_size, "unknown table segment"); + } + else { + set_error_buf_v(error_buf, error_buf_size, + "unknown elem segment %u", table_seg_idx); + } +#else + set_error_buf(error_buf, error_buf_size, + "unknown table segment"); +#endif + return false; + } + + if (p_elem_type) { + *p_elem_type = module->table_segments[table_seg_idx].elem_type; + } + return true; +} +#endif + +static bool +wasm_loader_prepare_bytecode(WASMModule *module, + WASMFunction *func, uint32 cur_func_idx, char *error_buf, uint32 error_buf_size) { uint8 *p = func->code, *p_end = func->code + func->code_size, *p_org; @@ -5750,16 +6145,14 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, uint8 *param_types, *local_types, local_type, global_type; BlockType func_type; uint16 *local_offsets, local_offset; - uint32 count, i, local_idx, global_idx, u32, align, mem_offset; - int32 i32, i32_const = 0; + uint32 type_idx, func_idx, local_idx, global_idx, table_idx; + uint32 table_seg_idx, data_seg_idx, count, i, align, mem_offset; + int32 i32_const = 0; int64 i64; - uint8 opcode, u8; + uint8 opcode; bool return_value = false; WASMLoaderContext *loader_ctx; BranchBlock *frame_csp_tmp; -#if WASM_ENABLE_BULK_MEMORY != 0 - uint32 segment_index; -#endif #if WASM_ENABLE_FAST_INTERP != 0 uint8 *func_const_end, *func_const = NULL; int16 operand_offset; @@ -5845,7 +6238,7 @@ handle_op_block_and_loop: BlockType block_type; value_type = read_uint8(p); - if (is_value_type(value_type)) { + if (is_byte_a_type(value_type)) { /* If the first byte is one of these special values: * 0x40/0x7F/0x7E/0x7D/0x7C, take it as the type of * the single return value. */ @@ -5893,7 +6286,8 @@ handle_op_block_and_loop: #if WASM_ENABLE_FAST_INTERP != 0 if (opcode == WASM_OP_BLOCK) { skip_label(); - } else if (opcode == WASM_OP_LOOP) { + } + else if (opcode == WASM_OP_LOOP) { skip_label(); if (BLOCK_HAS_PARAM(block_type)) { /* Make sure params are in dynamic space */ @@ -5905,7 +6299,8 @@ handle_op_block_and_loop: } (loader_ctx->frame_csp - 1)->code_compiled = loader_ctx->p_code_compiled; - } else if (opcode == WASM_OP_IF) { + } + else if (opcode == WASM_OP_IF) { /* If block has parameters, we should make sure they are in * dynamic space. Otherwise, when else branch is missing, * the later opcode may consume incorrect operand offset. @@ -6182,7 +6577,6 @@ handle_op_block_and_loop: #endif { WASMType *func_type; - uint32 func_idx; int32 idx; read_leb_uint32(p, p_end, func_idx); @@ -6191,9 +6585,8 @@ handle_op_block_and_loop: emit_uint32(loader_ctx, func_idx); #endif - if (func_idx >= module->import_function_count + module->function_count) { - set_error_buf(error_buf, error_buf_size, - "unknown function"); + if (!check_function_index(module, func_idx, error_buf, + error_buf_size)) { goto fail; } @@ -6228,7 +6621,6 @@ handle_op_block_and_loop: #if WASM_ENABLE_TAIL_CALL != 0 } else { - char *type_str[] = { "v128", "f64", "f32", "i64", "i32" }; uint8 type; if (func_type->result_count != func->func_type->result_count) { set_error_buf_v(error_buf, error_buf_size, @@ -6242,7 +6634,7 @@ handle_op_block_and_loop: if (func_type->types[func_type->param_count + i] != type) { set_error_buf_v(error_buf, error_buf_size, "%s%s%s", "type mismatch: expect ", - type_str[type - VALUE_TYPE_V128], + type2str(type), " but got other"); goto fail; } @@ -6255,6 +6647,10 @@ handle_op_block_and_loop: break; } + /* + * if disable reference type: call_indirect typeidx, 0x00 + * if enable reference type: call_indirect typeidx, tableidx + */ case WASM_OP_CALL_INDIRECT: #if WASM_ENABLE_TAIL_CALL != 0 case WASM_OP_RETURN_CALL_INDIRECT: @@ -6262,31 +6658,36 @@ handle_op_block_and_loop: { int32 idx; WASMType *func_type; - uint32 type_idx; - if (module->table_count == 0 - && module->import_table_count == 0) { - set_error_buf(error_buf, error_buf_size, - "call indirect with unknown table"); + read_leb_uint32(p, p_end, type_idx); +#if WASM_ENABLE_REF_TYPES != 0 + if (!wasm_get_ref_types_flag()) { + CHECK_BUF(p, p_end, 1); + table_idx = read_uint8(p); + } + else { + read_leb_uint32(p, p_end, table_idx); + } + +#else + CHECK_BUF(p, p_end, 1); + table_idx = read_uint8(p); +#endif + if (!check_table_index(module, table_idx, error_buf, + error_buf_size)) { goto fail; } - read_leb_uint32(p, p_end, type_idx); #if WASM_ENABLE_FAST_INTERP != 0 + /* we need to emit before arguments */ #if WASM_ENABLE_TAIL_CALL != 0 emit_byte(loader_ctx, opcode); #endif - /* we need to emit func_idx before arguments */ emit_uint32(loader_ctx, type_idx); + emit_uint32(loader_ctx, table_idx); #endif - /* reserved byte 0x00 */ - if (*p++ != 0x00) { - set_error_buf(error_buf, error_buf_size, - "zero flag expected"); - goto fail; - } - + /* skip elem idx */ POP_I32(); if (type_idx >= module->type_count) { @@ -6318,7 +6719,6 @@ handle_op_block_and_loop: #if WASM_ENABLE_TAIL_CALL != 0 } else { - char *type_str[] = { "v128", "f64", "f32", "i64", "i32" }; uint8 type; if (func_type->result_count != func->func_type->result_count) { set_error_buf_v(error_buf, error_buf_size, @@ -6332,7 +6732,7 @@ handle_op_block_and_loop: if (func_type->types[func_type->param_count + i] != type) { set_error_buf_v(error_buf, error_buf_size, "%s%s%s", "type mismatch: expect ", - type_str[type - VALUE_TYPE_V128], + type2str(type), " but got other"); goto fail; } @@ -6362,7 +6762,12 @@ handle_op_block_and_loop: if (available_stack_cell > 0) { if (*(loader_ctx->frame_ref - 1) == REF_I32 - || *(loader_ctx->frame_ref - 1) == REF_F32) { + || *(loader_ctx->frame_ref - 1) == REF_F32 +#if WASM_ENABLE_REF_TYPES != 0 + || *(loader_ctx->frame_ref - 1) == REF_FUNCREF + || *(loader_ctx->frame_ref - 1) == REF_EXTERNREF +#endif + ) { loader_ctx->frame_ref--; loader_ctx->stack_cell_num--; #if WASM_ENABLE_FAST_INTERP != 0 @@ -6388,10 +6793,19 @@ handle_op_block_and_loop: loader_ctx->dynamic_offset -= 2; #endif } - else { /* V128 */ +#if WASM_ENABLE_SIMD != 0 +#if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0) + else if (*(loader_ctx->frame_ref - 1) == REF_V128_1) { loader_ctx->frame_ref -= 4; loader_ctx->stack_cell_num -= 4; } +#endif +#endif + else { + set_error_buf(error_buf, error_buf_size, + "type mismatch"); + goto fail; + } } else { #if WASM_ENABLE_FAST_INTERP != 0 @@ -6416,7 +6830,8 @@ handle_op_block_and_loop: if (available_stack_cell <= 0 && !cur_block->is_stack_polymorphic) { set_error_buf(error_buf, error_buf_size, - "type mismatch, opcode select was found " + "type mismatch or invalid result arity, " + "opcode select was found " "but stack was empty"); goto fail; } @@ -6462,24 +6877,30 @@ handle_op_block_and_loop: } #endif /* end of WASM_ENABLE_FAST_INTERP */ break; - default: - bh_assert(0); +#if WASM_ENABLE_SIMD != 0 +#if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0) + case REF_V128_4: break; +#endif /* (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0) */ +#endif /* WASM_ENABLE_SIMD != 0 */ + default: { + set_error_buf(error_buf, error_buf_size, + "type mismatch"); + goto fail; + } } ref_type = *(loader_ctx->frame_ref - 1); #if WASM_ENABLE_FAST_INTERP != 0 POP_OFFSET_TYPE(ref_type); -#endif POP_TYPE(ref_type); -#if WASM_ENABLE_FAST_INTERP != 0 POP_OFFSET_TYPE(ref_type); -#endif POP_TYPE(ref_type); -#if WASM_ENABLE_FAST_INTERP != 0 PUSH_OFFSET_TYPE(ref_type); -#endif PUSH_TYPE(ref_type); +#else + POP2_AND_PUSH(ref_type, ref_type); +#endif } else { #if WASM_ENABLE_FAST_INTERP != 0 @@ -6490,6 +6911,223 @@ handle_op_block_and_loop: break; } +#if WASM_ENABLE_REF_TYPES != 0 + case WASM_OP_SELECT_T: + { + uint8 vec_len, ref_type; + + if (!wasm_get_ref_types_flag()) { + goto unsupported_opcode; + } + + read_leb_uint32(p, p_end, vec_len); + if (!vec_len) { + set_error_buf(error_buf, error_buf_size, + "invalid result arity"); + goto fail; + } + + CHECK_BUF(p, p_end, 1); + ref_type = read_uint8(p); + if (!is_value_type(ref_type)) { + set_error_buf(error_buf, error_buf_size, + "unknown value type"); + goto fail; + } + + POP_I32(); + +#if WASM_ENABLE_FAST_INTERP != 0 + if (loader_ctx->p_code_compiled) { + uint8 opcode_tmp = WASM_OP_SELECT; + uint8 *p_code_compiled_tmp = + loader_ctx->p_code_compiled - 2; + + if (ref_type == VALUE_TYPE_V128) { +#if (WASM_ENABLE_SIMD == 0) \ + || ((WASM_ENABLE_WAMR_COMPILER == 0) && (WASM_ENABLE_JIT == 0)) + set_error_buf(error_buf, error_buf_size, + "SIMD v128 type isn't supported"); + goto fail; +#endif + } + else { + if (ref_type == VALUE_TYPE_F64 + || ref_type == VALUE_TYPE_I64) + opcode_tmp = WASM_OP_SELECT_64; +#if WASM_ENABLE_LABELS_AS_VALUES != 0 +#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS != 0 + *(void**)(p_code_compiled_tmp - sizeof(void*)) = + handle_table[opcode_tmp]; +#else + int32 offset = (int32) + ((uint8*)handle_table[opcode_tmp] + - (uint8*)handle_table[0]); + if (!(offset >= INT16_MIN && offset < INT16_MAX)) { + set_error_buf(error_buf, error_buf_size, + "pre-compiled label offset out of range"); + goto fail; + } + *(int16*)(p_code_compiled_tmp - sizeof(int16)) = + (int16)offset; +#endif /* end of WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS */ +#else /* else of WASM_ENABLE_LABELS_AS_VALUES */ +#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS != 0 + *(p_code_compiled_tmp - 1) = opcode_tmp; +#else + *(p_code_compiled_tmp - 2) = opcode_tmp; +#endif /* end of WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS */ +#endif /* end of WASM_ENABLE_LABELS_AS_VALUES */ + } + } +#endif /* WASM_ENABLE_FAST_INTERP != 0 */ + +#if WASM_ENABLE_FAST_INTERP != 0 + POP_OFFSET_TYPE(ref_type); + POP_TYPE(ref_type); + POP_OFFSET_TYPE(ref_type); + POP_TYPE(ref_type); + PUSH_OFFSET_TYPE(ref_type); + PUSH_TYPE(ref_type); +#else + POP2_AND_PUSH(ref_type, ref_type); +#endif /* WASM_ENABLE_FAST_INTERP != 0 */ + + (void)vec_len; + break; + } + + /* table.get x. tables[x]. [i32] -> [t] */ + /* table.set x. tables[x]. [i32 t] -> [] */ + case WASM_OP_TABLE_GET: + case WASM_OP_TABLE_SET: + { + uint8 decl_ref_type; + + if (!wasm_get_ref_types_flag()) { + goto unsupported_opcode; + } + + read_leb_uint32(p, p_end, table_idx); + if (!get_table_elem_type(module, table_idx, &decl_ref_type, + error_buf, error_buf_size)) + goto fail; + +#if WASM_ENABLE_FAST_INTERP != 0 + emit_uint32(loader_ctx, table_idx); +#endif + + if (opcode == WASM_OP_TABLE_GET) { + POP_I32(); +#if WASM_ENABLE_FAST_INTERP != 0 + PUSH_OFFSET_TYPE(decl_ref_type); +#endif + PUSH_TYPE(decl_ref_type); + } + else { +#if WASM_ENABLE_FAST_INTERP != 0 + POP_OFFSET_TYPE(decl_ref_type); +#endif + POP_TYPE(decl_ref_type); + POP_I32(); + } + break; + } + case WASM_OP_REF_NULL: + { + uint8 ref_type; + + if (!wasm_get_ref_types_flag()) { + goto unsupported_opcode; + } + + CHECK_BUF(p, p_end, 1); + ref_type = read_uint8(p); + if (ref_type != VALUE_TYPE_FUNCREF + && ref_type != VALUE_TYPE_EXTERNREF) { + set_error_buf(error_buf, error_buf_size, + "unknown value type"); + goto fail; + } +#if WASM_ENABLE_FAST_INTERP != 0 + PUSH_OFFSET_TYPE(ref_type); +#endif + PUSH_TYPE(ref_type); + break; + } + case WASM_OP_REF_IS_NULL: + { + if (!wasm_get_ref_types_flag()) { + goto unsupported_opcode; + } + +#if WASM_ENABLE_FAST_INTERP != 0 + if (!wasm_loader_pop_frame_ref_offset( + loader_ctx, VALUE_TYPE_FUNCREF, + error_buf, error_buf_size) + && !wasm_loader_pop_frame_ref_offset( + loader_ctx, VALUE_TYPE_EXTERNREF, + error_buf, error_buf_size)) { + goto fail; + } +#else + if (!wasm_loader_pop_frame_ref( + loader_ctx, VALUE_TYPE_FUNCREF, + error_buf, error_buf_size) + && !wasm_loader_pop_frame_ref( + loader_ctx, VALUE_TYPE_EXTERNREF, + error_buf, error_buf_size)) { + goto fail; + } +#endif + PUSH_I32(); + break; + } + case WASM_OP_REF_FUNC: + { + if (!wasm_get_ref_types_flag()) { + goto unsupported_opcode; + } + + read_leb_uint32(p, p_end, func_idx); + + if (!check_function_index(module, func_idx, error_buf, + error_buf_size)) { + goto fail; + } + + if (func_idx == cur_func_idx) { + WASMTableSeg *table_seg = module->table_segments; + bool func_declared = false; + uint32 j; + + /* Check whether current function is declared */ + for (i = 0; i < module->table_seg_count; i++, table_seg++) { + if (table_seg->elem_type == VALUE_TYPE_FUNCREF + && wasm_elem_is_declarative(table_seg->mode)) { + for (j =0; j < table_seg->function_count; j++) { + if (table_seg->func_indexes[j] == cur_func_idx) { + func_declared = true; + break; + } + } + } + } + if (!func_declared) { + set_error_buf(error_buf, error_buf_size, + "undeclared function reference"); + goto fail; + } + } + +#if WASM_ENABLE_FAST_INTERP != 0 + emit_uint32(loader_ctx, func_idx); +#endif + PUSH_FUNCREF(); + break; + } +#endif /* WASM_ENABLE_REF_TYPES */ + case WASM_OP_GET_LOCAL: { p_org = p - 1; @@ -6506,8 +7144,7 @@ handle_op_block_and_loop: #if (WASM_ENABLE_WAMR_COMPILER == 0) && (WASM_ENABLE_JIT == 0) if (local_offset < 0x80) { *p_org++ = EXT_OP_GET_LOCAL_FAST; - if (local_type == VALUE_TYPE_I32 - || local_type == VALUE_TYPE_F32) + if (is_32bit_type(local_type)) *p_org++ = (uint8)local_offset; else *p_org++ = (uint8)(local_offset | 0x80); @@ -6546,8 +7183,7 @@ handle_op_block_and_loop: loader_ctx->dynamic_offset -= 2; } else { - if (local_type == VALUE_TYPE_I32 - || local_type == VALUE_TYPE_F32) { + if (is_32bit_type(local_type)) { emit_label(EXT_OP_SET_LOCAL_FAST); emit_byte(loader_ctx, (uint8)local_offset); } @@ -6566,8 +7202,7 @@ handle_op_block_and_loop: #if (WASM_ENABLE_WAMR_COMPILER == 0) && (WASM_ENABLE_JIT == 0) if (local_offset < 0x80) { *p_org++ = EXT_OP_SET_LOCAL_FAST; - if (local_type == VALUE_TYPE_I32 - || local_type == VALUE_TYPE_F32) + if (is_32bit_type(local_type)) *p_org++ = (uint8)local_offset; else *p_org++ = (uint8)(local_offset | 0x80); @@ -6604,8 +7239,7 @@ handle_op_block_and_loop: if (local_offset < 256) { skip_label(); - if (local_type == VALUE_TYPE_I32 - || local_type == VALUE_TYPE_F32) { + if (is_32bit_type(local_type)) { emit_label(EXT_OP_TEE_LOCAL_FAST); emit_byte(loader_ctx, (uint8)local_offset); } @@ -6623,8 +7257,7 @@ handle_op_block_and_loop: #if (WASM_ENABLE_WAMR_COMPILER == 0) && (WASM_ENABLE_JIT == 0) if (local_offset < 0x80) { *p_org++ = EXT_OP_TEE_LOCAL_FAST; - if (local_type == VALUE_TYPE_I32 - || local_type == VALUE_TYPE_F32) + if (is_32bit_type(local_type)) *p_org++ = (uint8)local_offset; else *p_org++ = (uint8)(local_offset | 0x80); @@ -6842,8 +7475,13 @@ handle_op_block_and_loop: CHECK_MEMORY(); /* reserved byte 0x00 */ if (*p++ != 0x00) { +#if WASM_ENABLE_REF_TYPES != 0 + set_error_buf(error_buf, error_buf_size, + "zero byte expected"); +#else set_error_buf(error_buf, error_buf_size, "zero flag expected"); +#endif goto fail; } PUSH_I32(); @@ -6855,8 +7493,13 @@ handle_op_block_and_loop: CHECK_MEMORY(); /* reserved byte 0x00 */ if (*p++ != 0x00) { +#if WASM_ENABLE_REF_TYPES != 0 + set_error_buf(error_buf, error_buf_size, + "zero byte expected"); +#else set_error_buf(error_buf, error_buf_size, "zero flag expected"); +#endif goto fail; } POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32); @@ -7162,9 +7805,10 @@ handle_op_block_and_loop: break; #if WASM_ENABLE_BULK_MEMORY != 0 case WASM_OP_MEMORY_INIT: - read_leb_uint32(p, p_end, segment_index); + { + read_leb_uint32(p, p_end, data_seg_idx); #if WASM_ENABLE_FAST_INTERP != 0 - emit_uint32(loader_ctx, segment_index); + emit_uint32(loader_ctx, data_seg_idx); #endif if (module->import_memory_count == 0 && module->memory_count == 0) goto fail_unknown_memory; @@ -7172,9 +7816,9 @@ handle_op_block_and_loop: if (*p++ != 0x00) goto fail_zero_flag_expected; - if (segment_index >= module->data_seg_count) { - set_error_buf(error_buf, error_buf_size, - "unknown data segment"); + if (data_seg_idx >= module->data_seg_count) { + set_error_buf_v(error_buf, error_buf_size, + "unknown data segment %d", data_seg_idx); goto fail; } @@ -7185,12 +7829,14 @@ handle_op_block_and_loop: POP_I32(); POP_I32(); break; + } case WASM_OP_DATA_DROP: - read_leb_uint32(p, p_end, segment_index); + { + read_leb_uint32(p, p_end, data_seg_idx); #if WASM_ENABLE_FAST_INTERP != 0 - emit_uint32(loader_ctx, segment_index); + emit_uint32(loader_ctx, data_seg_idx); #endif - if (segment_index >= module->data_seg_count) { + if (data_seg_idx >= module->data_seg_count) { set_error_buf(error_buf, error_buf_size, "unknown data segment"); goto fail; @@ -7200,7 +7846,9 @@ handle_op_block_and_loop: goto fail_data_cnt_sec_require; break; + } case WASM_OP_MEMORY_COPY: + { /* both src and dst memory index should be 0 */ if (*(int16*)p != 0x0000) goto fail_zero_flag_expected; @@ -7213,7 +7861,9 @@ handle_op_block_and_loop: POP_I32(); POP_I32(); break; + } case WASM_OP_MEMORY_FILL: + { if (*p++ != 0x00) { goto fail_zero_flag_expected; } @@ -7238,8 +7888,155 @@ fail_data_cnt_sec_require: set_error_buf(error_buf, error_buf_size, "data count section required"); goto fail; - /* TODO: to support bulk table operation */ + } #endif /* WASM_ENABLE_BULK_MEMORY */ +#if WASM_ENABLE_REF_TYPES != 0 + case WASM_OP_TABLE_INIT: + { + uint8 seg_ref_type, tbl_ref_type; + + if (!wasm_get_ref_types_flag()) { + goto unsupported_opcode; + } + + read_leb_uint32(p, p_end, table_seg_idx); + read_leb_uint32(p, p_end, table_idx); + + if (!get_table_elem_type(module, table_idx, &tbl_ref_type, + error_buf, error_buf_size)) + goto fail; + + if (!get_table_seg_elem_type(module, table_seg_idx, + &seg_ref_type, error_buf, + error_buf_size)) + goto fail; + + if (seg_ref_type != tbl_ref_type) { + set_error_buf(error_buf, error_buf_size, + "type mismatch"); + goto fail; + } + +#if WASM_ENABLE_FAST_INTERP != 0 + emit_uint32(loader_ctx, table_seg_idx); + emit_uint32(loader_ctx, table_idx); +#endif + POP_I32(); + POP_I32(); + POP_I32(); + break; + } + case WASM_OP_ELEM_DROP: + { + if (!wasm_get_ref_types_flag()) { + goto unsupported_opcode; + } + + read_leb_uint32(p, p_end, table_seg_idx); + if (!get_table_seg_elem_type(module, table_seg_idx, NULL, + error_buf, error_buf_size)) + goto fail; +#if WASM_ENABLE_FAST_INTERP != 0 + emit_uint32(loader_ctx, table_seg_idx); +#endif + break; + } + case WASM_OP_TABLE_COPY: + { + uint8 src_ref_type, dst_ref_type; + uint32 src_tbl_idx, dst_tbl_idx; + + if (!wasm_get_ref_types_flag()) { + goto unsupported_opcode; + } + + read_leb_uint32(p, p_end, src_tbl_idx); + if (!get_table_elem_type(module, src_tbl_idx, &src_ref_type, + error_buf, error_buf_size)) + goto fail; + + read_leb_uint32(p, p_end, dst_tbl_idx); + if (!get_table_elem_type(module, dst_tbl_idx, &dst_ref_type, + error_buf, error_buf_size)) + goto fail; + + if (src_ref_type != dst_ref_type) { + set_error_buf(error_buf, error_buf_size, + "type mismatch"); + goto fail; + } + +#if WASM_ENABLE_FAST_INTERP != 0 + emit_uint32(loader_ctx, src_tbl_idx); + emit_uint32(loader_ctx, dst_tbl_idx); +#endif + POP_I32(); + POP_I32(); + POP_I32(); + break; + } + case WASM_OP_TABLE_SIZE: + { + if (!wasm_get_ref_types_flag()) { + goto unsupported_opcode; + } + + read_leb_uint32(p, p_end, table_idx); + /* TODO: shall we create a new function to check + table idx instead of using below function? */ + if (!get_table_elem_type(module, table_idx, NULL, + error_buf, error_buf_size)) + goto fail; + +#if WASM_ENABLE_FAST_INTERP != 0 + emit_uint32(loader_ctx, table_idx); +#endif + + PUSH_I32(); + break; + } + case WASM_OP_TABLE_GROW: + case WASM_OP_TABLE_FILL: + { + uint8 decl_ref_type; + + if (!wasm_get_ref_types_flag()) { + goto unsupported_opcode; + } + + read_leb_uint32(p, p_end, table_idx); + if (!get_table_elem_type(module, table_idx, + &decl_ref_type, error_buf, + error_buf_size)) + goto fail; + + if (opcode1 == WASM_OP_TABLE_GROW) { + if (table_idx < module->import_table_count) { + module->import_tables[table_idx] + .u.table.possible_grow = true; + } + else { + module->tables[table_idx - module->import_table_count] + .possible_grow = true; + } + } + +#if WASM_ENABLE_FAST_INTERP != 0 + emit_uint32(loader_ctx, table_idx); +#endif + + POP_I32(); +#if WASM_ENABLE_FAST_INTERP != 0 + POP_OFFSET_TYPE(decl_ref_type); +#endif + POP_TYPE(decl_ref_type); + if (opcode1 == WASM_OP_TABLE_GROW) + PUSH_I32(); + else + POP_I32(); + break; + } +#endif /* WASM_ENABLE_REF_TYPES */ default: set_error_buf_v(error_buf, error_buf_size, "%s %02x %02x", @@ -7770,6 +8567,9 @@ fail_data_cnt_sec_require: #endif /* end of WASM_ENABLE_SHARED_MEMORY */ default: +#if WASM_ENABLE_REF_TYPES != 0 +unsupported_opcode: +#endif set_error_buf_v(error_buf, error_buf_size, "%s %02x", "unsupported opcode", opcode); @@ -7807,7 +8607,8 @@ fail_data_cnt_sec_require: bh_memcpy_s(func_const, (uint32)(func_const_end - func_const), &(c->value.f64), (uint32)sizeof(int64)); func_const += sizeof(int64); - } else { + } + else { bh_memcpy_s(func_const, (uint32)(func_const_end - func_const), &(c->value.f32), (uint32)sizeof(int32)); func_const += sizeof(int32); @@ -7825,9 +8626,9 @@ fail_data_cnt_sec_require: fail: wasm_loader_ctx_destroy(loader_ctx); - (void)u8; - (void)u32; - (void)i32; + (void)table_idx; + (void)table_seg_idx; + (void)data_seg_idx; (void)i64; (void)local_offset; (void)p_org; @@ -7835,3 +8636,20 @@ fail: (void)align; return return_value; } + +#if WASM_ENABLE_REF_TYPES != 0 +static bool ref_types_flag = true; + +void +wasm_set_ref_types_flag(bool enable) +{ + ref_types_flag = enable; +} + +bool +wasm_get_ref_types_flag() +{ + return ref_types_flag; +} +#endif + diff --git a/core/iwasm/interpreter/wasm_loader.h b/core/iwasm/interpreter/wasm_loader.h index 0e9c48888..13daeaf65 100644 --- a/core/iwasm/interpreter/wasm_loader.h +++ b/core/iwasm/interpreter/wasm_loader.h @@ -70,6 +70,14 @@ wasm_loader_find_block_addr(BlockAddr *block_addr_cache, uint8 **p_else_addr, uint8 **p_end_addr); +#if WASM_ENABLE_REF_TYPES != 0 +void +wasm_set_ref_types_flag(bool enable); + +bool +wasm_get_ref_types_flag(); +#endif + #ifdef __cplusplus } #endif diff --git a/core/iwasm/interpreter/wasm_mini_loader.c b/core/iwasm/interpreter/wasm_mini_loader.c index b1854899a..cc2cd7119 100644 --- a/core/iwasm/interpreter/wasm_mini_loader.c +++ b/core/iwasm/interpreter/wasm_mini_loader.c @@ -38,6 +38,27 @@ set_error_buf(char *error_buf, uint32 error_buf_size, const char *string) #define skip_leb_uint32(p, p_end) skip_leb(p) #define skip_leb_int32(p, p_end) skip_leb(p) +static bool +is_32bit_type(uint8 type) +{ + if (type == VALUE_TYPE_I32 || type == VALUE_TYPE_F32 +#if WASM_ENABLE_REF_TYPES != 0 + || (wasm_get_ref_types_flag() + && (type == VALUE_TYPE_FUNCREF || type == VALUE_TYPE_EXTERNREF)) +#endif + ) + return true; + return false; +} + +static bool +is_64bit_type(uint8 type) +{ + if (type == VALUE_TYPE_I64 || type == VALUE_TYPE_F64) + return true; + return false; +} + static void read_leb(uint8 **p_buf, const uint8 *buf_end, uint32 maxbits, bool sign, uint64 *p_result, @@ -229,6 +250,35 @@ load_init_expr(const uint8 **p_buf, const uint8 *buf_end, for (i = 0; i < sizeof(float64); i++) *p_float++ = *p++; break; +#if WASM_ENABLE_REF_TYPES != 0 + case INIT_EXPR_TYPE_FUNCREF_CONST: + { + if (!wasm_get_ref_types_flag()) { + return false; + } + + bh_assert(type == VALUE_TYPE_FUNCREF); + read_leb_uint32(p, p_end, init_expr->u.ref_index); + break; + } + case INIT_EXPR_TYPE_REFNULL_CONST: + { + uint8 reftype; + + if (!wasm_get_ref_types_flag()) { + return false; + } + + CHECK_BUF(p, p_end, 1); + reftype = read_uint8(p); + + bh_assert(type == reftype); + + init_expr->u.ref_index = NULL_REF; + (void)reftype; + break; + } +#endif /* WASM_ENABLE_REF_TYPES != 0 */ /* get_global */ case INIT_EXPR_TYPE_GET_GLOBAL: read_leb_uint32(p, p_end, init_expr->u.global_index); @@ -319,6 +369,27 @@ load_type_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, return true; } +static void +adjust_table_max_size(uint32 init_size, uint32 max_size_flag, uint32 *max_size) +{ + uint32 default_max_size = + init_size * 2 > TABLE_MAX_SIZE ? init_size * 2 : TABLE_MAX_SIZE; + + if (max_size_flag) { + /* module defines the table limitation */ + bh_assert(init_size <= *max_size); + + if (init_size < *max_size) { + *max_size = + *max_size < default_max_size ? *max_size : default_max_size; + } + } + else { + /* partial defined table limitation, gives a default value */ + *max_size = default_max_size; + } +} + static bool load_function_import(const uint8 **p_buf, const uint8 *buf_end, const WASMModule *parent_module, @@ -370,24 +441,28 @@ load_table_import(const uint8 **p_buf, const uint8 *buf_end, char *error_buf, uint32 error_buf_size) { const uint8 *p = *p_buf, *p_end = buf_end; - uint32 declare_elem_type = 0; - uint32 declare_max_size_flag = 0; - uint32 declare_init_size = 0; - uint32 declare_max_size = 0; + uint32 declare_elem_type = 0, declare_max_size_flag = 0, + declare_init_size = 0, declare_max_size = 0; CHECK_BUF(p, p_end, 1); - /* 0x70 */ + /* 0x70 or 0x6F */ declare_elem_type = read_uint8(p); - bh_assert(TABLE_ELEM_TYPE_ANY_FUNC == declare_elem_type); + bh_assert(VALUE_TYPE_FUNCREF == declare_elem_type +#if WASM_ENABLE_REF_TYPES != 0 + || (wasm_get_ref_types_flag() && + VALUE_TYPE_EXTERNREF == declare_elem_type) +#endif + ); read_leb_uint32(p, p_end, declare_max_size_flag); read_leb_uint32(p, p_end, declare_init_size); if (declare_max_size_flag & 1) { read_leb_uint32(p, p_end, declare_max_size); bh_assert(table->init_size <= table->max_size); - } else { - declare_max_size = 0x10000; } + + adjust_table_max_size(declare_init_size, declare_max_size_flag, + &declare_max_size); *p_buf = p; bh_assert(!((declare_max_size_flag & 1) @@ -499,9 +574,14 @@ load_table(const uint8 **p_buf, const uint8 *buf_end, WASMTable *table, const uint8 *p = *p_buf, *p_end = buf_end, *p_org; CHECK_BUF(p, p_end, 1); - /* 0x70 */ + /* 0x70 or 0x6F */ table->elem_type = read_uint8(p); - bh_assert(TABLE_ELEM_TYPE_ANY_FUNC == table->elem_type); + bh_assert((VALUE_TYPE_FUNCREF == table->elem_type) +#if WASM_ENABLE_REF_TYPES != 0 + || (wasm_get_ref_types_flag() && + VALUE_TYPE_EXTERNREF == table->elem_type) +#endif + ); p_org = p; read_leb_uint32(p, p_end, table->flags); @@ -510,14 +590,13 @@ load_table(const uint8 **p_buf, const uint8 *buf_end, WASMTable *table, (void)p_org; read_leb_uint32(p, p_end, table->init_size); - if (table->flags == 0) { - table->max_size = 0x10000; - } - else if (table->flags == 1) { + if (table->flags == 1) { read_leb_uint32(p, p_end, table->max_size); bh_assert(table->init_size <= table->max_size); } + adjust_table_max_size(table->init_size, table->flags, &table->max_size); + *p_buf = p; return true; } @@ -631,7 +710,12 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, if (flags & 1) read_leb_uint32(p, p_end, u32); module->import_table_count++; - bh_assert(module->import_table_count <= 1); + bh_assert( +#if WASM_ENABLE_REF_TYPES != 0 + wasm_get_ref_types_flag() || +#endif + module->import_table_count <= 1); + break; case IMPORT_KIND_MEMORY: /* import memory */ @@ -903,7 +987,13 @@ load_function_section(const uint8 *buf, const uint8 *buf_end, CHECK_BUF(p_code, buf_code_end, 1); /* 0x7F/0x7E/0x7D/0x7C */ type = read_uint8(p_code); - bh_assert(type >= VALUE_TYPE_F64 && type <= VALUE_TYPE_I32); + bh_assert((type >= VALUE_TYPE_F64 && type <= VALUE_TYPE_I32) +#if WASM_ENABLE_REF_TYPES != 0 + || (wasm_get_ref_types_flag() + && (type == VALUE_TYPE_FUNCREF + || type == VALUE_TYPE_EXTERNREF)) +#endif + ); for (k = 0; k < sub_local_count; k++) { func->local_types[local_type_index++] = type; } @@ -927,6 +1017,16 @@ load_function_section(const uint8 *buf, const uint8 *buf_end, return true; } +static bool +check_function_index(const WASMModule *module, + uint32 function_index, + char *error_buf, + uint32 error_buf_size) +{ + return (function_index + < module->import_function_count + module->function_count); +} + static bool load_table_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, char *error_buf, uint32 error_buf_size) @@ -937,7 +1037,11 @@ load_table_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, WASMTable *table; read_leb_uint32(p, p_end, table_count); - bh_assert(module->import_table_count + table_count <= 1); + bh_assert( +#if WASM_ENABLE_REF_TYPES != 0 + wasm_get_ref_types_flag() || +#endif + module->import_table_count + table_count <= 1); if (table_count) { module->table_count = table_count; @@ -1036,6 +1140,12 @@ load_global_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, bh_assert(target_global_index < module->import_global_count); (void)target_global_index; } + else if (INIT_EXPR_TYPE_FUNCREF_CONST + == global->init_expr.init_expr_type) { + bh_assert(global->init_expr.u.ref_index + < module->import_function_count + + module->function_count); + } } } @@ -1121,12 +1231,133 @@ load_export_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, return true; } +static bool +check_table_index(const WASMModule *module, uint32 table_index, + char *error_buf, uint32 error_buf_size) +{ + if ( +#if WASM_ENABLE_REF_TYPES != 0 + !wasm_get_ref_types_flag() && +#endif + table_index != 0) { + return false; + } + + if (table_index >= module->import_table_count + module->table_count) { + return false; + } + return true; +} + +#if WASM_ENABLE_REF_TYPES != 0 +static bool +load_table_index(const uint8 **p_buf, const uint8 *buf_end, + WASMModule *module, uint32 *p_table_index, + char *error_buf, uint32 error_buf_size) +{ + const uint8 *p = *p_buf, *p_end = buf_end; + uint32 table_index; + + read_leb_uint32(p, p_end, table_index); + if (!check_table_index(module, table_index, error_buf, error_buf_size)) { + return false; + } + + *p_table_index = table_index; + *p_buf = p; + return true; +} + +static bool +load_elem_type(const uint8 **p_buf, const uint8 *buf_end, + uint32 *p_elem_type, bool elemkind_zero, + char *error_buf, uint32 error_buf_size) +{ + const uint8 *p = *p_buf, *p_end = buf_end; + uint8 elem_type; + + CHECK_BUF(p, p_end, 1); + elem_type = read_uint8(p); + if ((elemkind_zero && elem_type != 0) + || (!elemkind_zero && elem_type != VALUE_TYPE_FUNCREF + && elem_type != VALUE_TYPE_EXTERNREF)) { + set_error_buf(error_buf, error_buf_size, "invalid reference type"); + return false; + } + + if (elemkind_zero) + *p_elem_type = VALUE_TYPE_FUNCREF; + else + *p_elem_type = elem_type; + *p_buf = p; + + (void)p_end; + return true; +} +#endif /* WASM_ENABLE_REF_TYPES != 0*/ + +static bool +load_func_index_vec(const uint8 **p_buf, const uint8 *buf_end, + WASMModule *module, WASMTableSeg *table_segment, + bool use_init_expr, + char *error_buf, uint32 error_buf_size) +{ + const uint8 *p = *p_buf, *p_end = buf_end; + uint32 function_count, function_index = 0, i; + uint64 total_size; + + read_leb_uint32(p, p_end, function_count); + table_segment->function_count = function_count; + total_size = sizeof(uint32) * (uint64)function_count; + if (total_size > 0 + && !(table_segment->func_indexes = (uint32 *) + loader_malloc(total_size, error_buf, error_buf_size))) { + return false; + } + + for (i = 0; i < function_count; i++) { + InitializerExpression init_expr = { 0 }; + +#if WASM_ENABLE_REF_TYPES != 0 + if (!wasm_get_ref_types_flag()) { + read_leb_uint32(p, p_end, function_index); + } + else { + if (!use_init_expr) { + read_leb_uint32(p, p_end, function_index); + } + else { + if (!load_init_expr(&p, p_end, &init_expr, + table_segment->elem_type, error_buf, + error_buf_size)) + return false; + + function_index = init_expr.u.ref_index; + } + } +#else + read_leb_uint32(p, p_end, function_index); +#endif + + /* since we are using -1 to indicate ref.null */ + if (init_expr.init_expr_type != INIT_EXPR_TYPE_REFNULL_CONST + && !check_function_index(module, function_index, error_buf, + error_buf_size)) { + return false; + } + table_segment->func_indexes[i] = function_index; + } + + *p_buf = p; + return true; +} + static bool load_table_segment_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, char *error_buf, uint32 error_buf_size) { const uint8 *p = buf, *p_end = buf_end; - uint32 table_segment_count, i, j, table_index, function_count, function_index; + uint32 table_segment_count, i, table_index, function_count; uint64 total_size; WASMTableSeg *table_segment; @@ -1143,31 +1374,112 @@ load_table_segment_section(const uint8 *buf, const uint8 *buf_end, WASMModule *m table_segment = module->table_segments; for (i = 0; i < table_segment_count; i++, table_segment++) { bh_assert(p < p_end); - read_leb_uint32(p, p_end, table_index); - bh_assert(table_index < module->import_table_count - + module->table_count); - table_segment->table_index = table_index; +#if WASM_ENABLE_REF_TYPES != 0 + if (wasm_get_ref_types_flag()) { + read_leb_uint32(p, p_end, table_segment->mode); + /* last three bits */ + table_segment->mode = table_segment->mode & 0x07; + switch (table_segment->mode) { + /* elemkind/elemtype + active */ + case 0: + case 4: + table_segment->elem_type = VALUE_TYPE_FUNCREF; + table_segment->table_index = 0; - /* initialize expression */ - if (!load_init_expr(&p, p_end, &(table_segment->base_offset), - VALUE_TYPE_I32, error_buf, error_buf_size)) - return false; + if (!check_table_index(module, + table_segment->table_index, + error_buf, error_buf_size)) + return false; - read_leb_uint32(p, p_end, function_count); - table_segment->function_count = function_count; - total_size = sizeof(uint32) * (uint64)function_count; - if (total_size > 0 - && !(table_segment->func_indexes = (uint32 *) - loader_malloc(total_size, error_buf, error_buf_size))) { - return false; + if (!load_init_expr( + &p, p_end, &table_segment->base_offset, + VALUE_TYPE_I32, error_buf, error_buf_size)) + return false; + + if (!load_func_index_vec( + &p, p_end, module, table_segment, + table_segment->mode == 0 ? false : true, + error_buf, error_buf_size)) + return false; + break; + /* elemkind + passive/declarative */ + case 1: + case 3: + if (!load_elem_type(&p, p_end, + &table_segment->elem_type, true, + error_buf, error_buf_size)) + return false; + if (!load_func_index_vec(&p, p_end, module, + table_segment, false, + error_buf, error_buf_size)) + return false; + break; + /* elemkind/elemtype + table_idx + active */ + case 2: + case 6: + if (!load_table_index(&p, p_end, module, + &table_segment->table_index, + error_buf, error_buf_size)) + return false; + if (!load_init_expr( + &p, p_end, &table_segment->base_offset, + VALUE_TYPE_I32, error_buf, error_buf_size)) + return false; + if (!load_elem_type( + &p, p_end, &table_segment->elem_type, + table_segment->mode == 2 ? true : false, + error_buf, error_buf_size)) + return false; + if (!load_func_index_vec( + &p, p_end, module, table_segment, + table_segment->mode == 2 ? false : true, + error_buf, error_buf_size)) + return false; + break; + case 5: + case 7: + if (!load_elem_type(&p, p_end, + &table_segment->elem_type, false, + error_buf, error_buf_size)) + return false; + if (!load_func_index_vec(&p, p_end, module, + table_segment, true, + error_buf, error_buf_size)) + return false; + break; + default: + return false; + } } + else +#endif /* WASM_ENABLE_REF_TYPES != 0 */ + { + read_leb_uint32(p, p_end, table_index); + bh_assert(table_index + < module->import_table_count + module->table_count); - for (j = 0; j < function_count; j++) { - read_leb_uint32(p, p_end, function_index); - bh_assert(function_index < module->import_function_count - + module->function_count); - table_segment->func_indexes[j] = function_index; + table_segment->table_index = table_index; + + /* initialize expression */ + if (!load_init_expr(&p, p_end, &(table_segment->base_offset), + VALUE_TYPE_I32, error_buf, error_buf_size)) + return false; + + read_leb_uint32(p, p_end, function_count); + table_segment->function_count = function_count; + total_size = sizeof(uint32) * (uint64)function_count; + if (total_size > 0 + && !(table_segment->func_indexes = (uint32 *)loader_malloc( + total_size, error_buf, error_buf_size))) { + return false; + } + + if (!load_func_index_vec(&p, p_end, module, table_segment, + table_segment->mode == 0 ? false + : true, + error_buf, error_buf_size)) + return false; } } } @@ -1437,9 +1749,48 @@ load_user_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, return true; } +#if WASM_ENABLE_REF_TYPES != 0 static bool -wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, - char *error_buf, uint32 error_buf_size); +get_table_elem_type(const WASMModule *module, + uint32 table_idx, uint8 *p_elem_type, + char *error_buf, uint32 error_buf_size) +{ + if (!check_table_index(module, table_idx, error_buf, error_buf_size)) { + return false; + } + + if (p_elem_type) { + if (table_idx < module->import_table_count) + *p_elem_type = module->import_tables[table_idx].u.table.elem_type; + else + *p_elem_type = module->tables[module->import_table_count + + table_idx].elem_type; + } + return true; +} + +static bool +get_table_seg_elem_type(const WASMModule *module, + uint32 table_seg_idx, uint8 *p_elem_type, + char *error_buf, uint32 error_buf_size) +{ + if (table_seg_idx >= module->table_seg_count) { + return false; + } + + if (p_elem_type) { + *p_elem_type = module->table_segments[table_seg_idx].elem_type; + } + return true; +} +#endif + +static bool +wasm_loader_prepare_bytecode(WASMModule *module, + WASMFunction *func, + uint32 cur_func_idx, + char *error_buf, + uint32 error_buf_size); #if WASM_ENABLE_FAST_INTERP != 0 && WASM_ENABLE_LABELS_AS_VALUES != 0 void ** @@ -1738,7 +2089,7 @@ load_from_sections(WASMModule *module, WASMSection *sections, for (i = 0; i < module->function_count; i++) { WASMFunction *func = module->functions[i]; - if (!wasm_loader_prepare_bytecode(module, func, + if (!wasm_loader_prepare_bytecode(module, func, i, error_buf, error_buf_size)) { return false; } @@ -2236,7 +2587,46 @@ wasm_loader_find_block_addr(BlockAddr *block_addr_cache, case WASM_OP_DROP_64: case WASM_OP_SELECT_64: break; +#if WASM_ENABLE_REF_TYPES != 0 + case WASM_OP_SELECT_T: + if (!wasm_get_ref_types_flag()) { + return false; + } + skip_leb_uint32(p, p_end); /* vec length */ + CHECK_BUF(p, p_end, 1); + u8 = read_uint8(p); /* typeidx */ + break; + case WASM_OP_TABLE_GET: + case WASM_OP_TABLE_SET: + if (!wasm_get_ref_types_flag()) { + return false; + } + + skip_leb_uint32(p, p_end); /* table index */ + break; + case WASM_OP_REF_NULL: + if (!wasm_get_ref_types_flag()) { + return false; + } + + CHECK_BUF(p, p_end, 1); + u8 = read_uint8(p); /* type */ + break; + case WASM_OP_REF_IS_NULL: + if (!wasm_get_ref_types_flag()) { + return false; + } + + break; + case WASM_OP_REF_FUNC: + if (!wasm_get_ref_types_flag()) { + return false; + } + + skip_leb_uint32(p, p_end); /* func index */ + break; +#endif /* WASM_ENABLE_REF_TYPES */ case WASM_OP_GET_LOCAL: case WASM_OP_SET_LOCAL: case WASM_OP_TEE_LOCAL: @@ -2463,6 +2853,33 @@ wasm_loader_find_block_addr(BlockAddr *block_addr_cache, p++; break; #endif +#if WASM_ENABLE_REF_TYPES != 0 + case WASM_OP_TABLE_INIT: + case WASM_OP_TABLE_COPY: + if (!wasm_get_ref_types_flag()) { + return false; + } + /* tableidx */ + skip_leb_uint32(p, p_end); + /* elemidx */ + skip_leb_uint32(p, p_end); + break; + case WASM_OP_ELEM_DROP: + if (!wasm_get_ref_types_flag()) { + return false; + } + /* elemidx */ + skip_leb_uint32(p, p_end); + break; + case WASM_OP_TABLE_SIZE: + case WASM_OP_TABLE_GROW: + case WASM_OP_TABLE_FILL: + if (!wasm_get_ref_types_flag()) { + return false; + } + skip_leb_uint32(p, p_end); /* table idx */ + break; +#endif /* WASM_ENABLE_REF_TYPES */ default: bh_assert(0); break; @@ -2708,10 +3125,8 @@ static bool check_stack_top_values(uint8 *frame_ref, int32 stack_cell_num, uint8 type, char *error_buf, uint32 error_buf_size) { - bh_assert(!(((type == VALUE_TYPE_I32 || type == VALUE_TYPE_F32) - && stack_cell_num < 1) - || ((type == VALUE_TYPE_I64 || type == VALUE_TYPE_F64) - && stack_cell_num < 2))); + bh_assert(!((is_32bit_type(type) && stack_cell_num < 1) + || (is_64bit_type(type) && stack_cell_num < 2))); bh_assert(!((type == VALUE_TYPE_I32 && *(frame_ref - 1) != REF_I32) || (type == VALUE_TYPE_F32 && *(frame_ref - 1) != REF_F32) @@ -2831,9 +3246,7 @@ wasm_loader_push_frame_ref(WASMLoaderContext *ctx, uint8 type, if (ctx->stack_cell_num > ctx->max_stack_cell_num) ctx->max_stack_cell_num = ctx->stack_cell_num; - if (type == VALUE_TYPE_I32 - || type == VALUE_TYPE_F32 - || type == VALUE_TYPE_ANY) + if (is_32bit_type(type)) return true; if (!check_stack_push(ctx, error_buf, error_buf_size)) @@ -2867,9 +3280,7 @@ wasm_loader_pop_frame_ref(WASMLoaderContext *ctx, uint8 type, ctx->frame_ref--; ctx->stack_cell_num--; - if (type == VALUE_TYPE_I32 - || type == VALUE_TYPE_F32 - || *ctx->frame_ref == VALUE_TYPE_ANY) + if (is_32bit_type(type) || *ctx->frame_ref == VALUE_TYPE_ANY) return true; ctx->frame_ref--; @@ -3202,8 +3613,7 @@ preserve_referenced_local(WASMLoaderContext *loader_ctx, uint8 opcode, if (loader_ctx->p_code_compiled) { bh_assert(preserved_offset != (int16)local_index); } - if (local_type == VALUE_TYPE_I32 - || local_type == VALUE_TYPE_F32) { + if (is_32bit_type(local_type)) { /* Only increase preserve offset in the second traversal */ if (loader_ctx->p_code_compiled) loader_ctx->preserved_local_offset++; @@ -3221,7 +3631,7 @@ preserve_referenced_local(WASMLoaderContext *loader_ctx, uint8 opcode, loader_ctx->frame_offset_bottom[i] = preserved_offset; } - if (cur_type == VALUE_TYPE_I32 || cur_type == VALUE_TYPE_F32) + if (is_32bit_type(cur_type)) i++; else i += 2; @@ -3258,7 +3668,7 @@ preserve_local_for_block(WASMLoaderContext *loader_ctx, uint8 opcode, return false; } - if (cur_type == VALUE_TYPE_I32 || cur_type == VALUE_TYPE_F32) { + if (is_32bit_type(cur_type == VALUE_TYPE_I32)) { i++; } else { @@ -3420,7 +3830,7 @@ wasm_loader_push_frame_offset(WASMLoaderContext *ctx, uint8 type, ctx->max_dynamic_offset = ctx->dynamic_offset; } - if (type == VALUE_TYPE_I32 || type == VALUE_TYPE_F32) + if (is_32bit_type(type)) return true; if (ctx->p_code_compiled == NULL) { @@ -3459,7 +3869,7 @@ wasm_loader_pop_frame_offset(WASMLoaderContext *ctx, uint8 type, if (type == VALUE_TYPE_VOID) return true; - if (type == VALUE_TYPE_I32 || type == VALUE_TYPE_F32) { + if (is_32bit_type(type)) { /* Check the offset stack bottom to ensure the frame offset stack will not go underflow. But we don't thrown error and return true here, because the error msg should be @@ -3559,6 +3969,10 @@ wasm_loader_get_const_offset(WASMLoaderContext *ctx, uint8 type, if ((type == c->value_type) && ((type == VALUE_TYPE_I64 && *(int64*)value == c->value.i64) || (type == VALUE_TYPE_I32 && *(int32*)value == c->value.i32) +#if WASM_ENABLE_REF_TYPES != 0 + || (type == VALUE_TYPE_FUNCREF && *(int32*)value == c->value.i32) + || (type == VALUE_TYPE_EXTERNREF && *(int32*)value == c->value.i32) +#endif || (type == VALUE_TYPE_F64 && (0 == memcmp(value, &(c->value.f64), sizeof(float64)))) || (type == VALUE_TYPE_F32 @@ -3602,6 +4016,13 @@ wasm_loader_get_const_offset(WASMLoaderContext *ctx, uint8 type, c->value.i32 = *(int32*)value; ctx->const_cell_num ++; break; +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_EXTERNREF: + case VALUE_TYPE_FUNCREF: + c->value.i32 = *(int32*)value; + ctx->const_cell_num ++; + break; +#endif default: break; } @@ -3662,6 +4083,13 @@ fail: goto fail; \ } while (0) +#define PUSH_FUNCREF() do { \ + if (!wasm_loader_push_frame_ref_offset(loader_ctx, VALUE_TYPE_FUNCREF,\ + disable_emit, operand_offset,\ + error_buf, error_buf_size)) \ + goto fail; \ + } while (0) + #define POP_I32() do { \ if (!wasm_loader_pop_frame_ref_offset(loader_ctx, VALUE_TYPE_I32, \ error_buf, error_buf_size)) \ @@ -3742,6 +4170,12 @@ fail: goto fail; \ } while (0) +#define PUSH_FUNCREF() do { \ + if (!(wasm_loader_push_frame_ref(loader_ctx, VALUE_TYPE_FUNCREF,\ + error_buf, error_buf_size))) \ + goto fail; \ + } while (0) + #define POP_I32() do { \ if (!(wasm_loader_pop_frame_ref(loader_ctx, VALUE_TYPE_I32, \ error_buf, error_buf_size))) \ @@ -3766,6 +4200,12 @@ fail: goto fail; \ } while (0) +#define POP_FUNCREF() do { \ + if (!(wasm_loader_pop_frame_ref(loader_ctx, VALUE_TYPE_FUNCREF, \ + error_buf, error_buf_size))) \ + goto fail; \ + } while (0) + #define POP_AND_PUSH(type_pop, type_push) do { \ if (!(wasm_loader_push_pop_frame_ref(loader_ctx, 1, \ type_push, type_pop, \ @@ -3983,17 +4423,27 @@ fail: + module->memory_count > 0); \ } while (0) - static bool is_value_type(uint8 type) { - return type == VALUE_TYPE_I32 || - type == VALUE_TYPE_I64 || - type == VALUE_TYPE_F32 || - type == VALUE_TYPE_F64 || - type == VALUE_TYPE_VOID; + if (type == VALUE_TYPE_I32 || type == VALUE_TYPE_I64 + || type == VALUE_TYPE_F32 || type == VALUE_TYPE_F64 +#if WASM_ENABLE_REF_TYPES != 0 + || (wasm_get_ref_types_flag() + && (type == VALUE_TYPE_FUNCREF || type == VALUE_TYPE_EXTERNREF)) +#endif + ) + return true; + return false; } +static bool +is_byte_a_type(uint8 type) +{ + return is_value_type(type) || (type == VALUE_TYPE_VOID); +} + + static bool wasm_loader_check_br(WASMLoaderContext *loader_ctx, uint32 depth, char *error_buf, uint32 error_buf_size) @@ -4285,8 +4735,11 @@ fail: } while (0) static bool -wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, - char *error_buf, uint32 error_buf_size) +wasm_loader_prepare_bytecode(WASMModule *module, + WASMFunction *func, + uint32 cur_func_idx, + char *error_buf, + uint32 error_buf_size) { uint8 *p = func->code, *p_end = func->code + func->code_size, *p_org; uint32 param_count, local_count, global_count; @@ -4388,7 +4841,7 @@ handle_op_block_and_loop: BlockType block_type; value_type = read_uint8(p); - if (is_value_type(value_type)) { + if (is_byte_a_type(value_type)) { /* If the first byte is one of these special values: * 0x40/0x7F/0x7E/0x7D/0x7C, take it as the type of * the single return value. */ @@ -4432,7 +4885,8 @@ handle_op_block_and_loop: #if WASM_ENABLE_FAST_INTERP != 0 if (opcode == WASM_OP_BLOCK) { skip_label(); - } else if (opcode == WASM_OP_LOOP) { + } + else if (opcode == WASM_OP_LOOP) { skip_label(); if (BLOCK_HAS_PARAM(block_type)) { /* Make sure params are in dynamic space */ @@ -4444,7 +4898,8 @@ handle_op_block_and_loop: } (loader_ctx->frame_csp - 1)->code_compiled = loader_ctx->p_code_compiled; - } else if (opcode == WASM_OP_IF) { + } + else if (opcode == WASM_OP_IF) { /* If block has parameters, we should make sure they are in * dynamic space. Otherwise, when else branch is missing, * the later opcode may consume incorrect operand offset. @@ -4755,21 +5210,39 @@ handle_op_block_and_loop: { int32 idx; WASMType *func_type; - uint32 type_idx; + uint32 type_idx, table_idx; bh_assert(module->import_table_count + module->table_count > 0); read_leb_uint32(p, p_end, type_idx); + +#if WASM_ENABLE_REF_TYPES != 0 + if (!wasm_get_ref_types_flag()) { + CHECK_BUF(p, p_end, 1); + table_idx = read_uint8(p); + } + else { + read_leb_uint32(p, p_end, table_idx); + } + +#else + CHECK_BUF(p, p_end, 1); + table_idx = read_uint8(p); +#endif + if (!check_table_index(module, table_idx, error_buf, + error_buf_size)) { + goto fail; + } + + #if WASM_ENABLE_FAST_INTERP != 0 - /* we need to emit func_idx before arguments */ + /* we need to emit before arguments */ emit_uint32(loader_ctx, type_idx); + emit_uint32(loader_ctx, table_idx); #endif - /* reserved byte 0x00 */ - bh_assert(*p == 0x00); - p++; - + /* skip elem idx */ POP_I32(); bh_assert(type_idx < module->type_count); @@ -4936,6 +5409,216 @@ handle_op_block_and_loop: break; } +#if WASM_ENABLE_REF_TYPES != 0 + case WASM_OP_SELECT_T: + { + uint8 vec_len, ref_type; + + if (!wasm_get_ref_types_flag()) { + goto fail; + } + + read_leb_uint32(p, p_end, vec_len); + if (!vec_len) { + set_error_buf(error_buf, error_buf_size, + "invalid result arity"); + goto fail; + } + + CHECK_BUF(p, p_end, 1); + ref_type = read_uint8(p); + if (!is_value_type(ref_type)) { + set_error_buf(error_buf, error_buf_size, + "unknown value type"); + goto fail; + } + + POP_I32(); + +#if WASM_ENABLE_FAST_INTERP != 0 + if (loader_ctx->p_code_compiled) { + uint8 opcode_tmp = WASM_OP_SELECT; + uint8 *p_code_compiled_tmp = + loader_ctx->p_code_compiled - 2; + + if (ref_type == VALUE_TYPE_F64 + || ref_type == VALUE_TYPE_I64) + opcode_tmp = WASM_OP_SELECT_64; + +#if WASM_ENABLE_LABELS_AS_VALUES != 0 +#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS != 0 + *(void**)(p_code_compiled_tmp - sizeof(void*)) = + handle_table[opcode_tmp]; +#else + int32 offset = (int32) + ((uint8*)handle_table[opcode_tmp] + - (uint8*)handle_table[0]); + if (!(offset >= INT16_MIN && offset < INT16_MAX)) { + set_error_buf(error_buf, error_buf_size, + "pre-compiled label offset out of range"); + goto fail; + } + *(int16*)(p_code_compiled_tmp - sizeof(int16)) = + (int16)offset; +#endif /* end of WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS */ +#else /* else of WASM_ENABLE_LABELS_AS_VALUES */ +#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS != 0 + *(p_code_compiled_tmp - 1) = opcode_tmp; +#else + *(p_code_compiled_tmp - 2) = opcode_tmp; +#endif /* end of WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS */ +#endif /* end of WASM_ENABLE_LABELS_AS_VALUES */ + } +#endif /* WASM_ENABLE_FAST_INTERP != 0 */ + +#if WASM_ENABLE_FAST_INTERP != 0 + POP_OFFSET_TYPE(ref_type); + POP_TYPE(ref_type); + POP_OFFSET_TYPE(ref_type); + POP_TYPE(ref_type); + PUSH_OFFSET_TYPE(ref_type); + PUSH_TYPE(ref_type); +#else + POP2_AND_PUSH(ref_type, ref_type); +#endif /* WASM_ENABLE_FAST_INTERP != 0 */ + + (void)vec_len; + break; + } + + /* table.get x. tables[x]. [i32] -> [t] */ + /* table.set x. tables[x]. [i32 t] -> [] */ + case WASM_OP_TABLE_GET: + case WASM_OP_TABLE_SET: + { + uint8 decl_ref_type; + uint32 table_idx; + + if (!wasm_get_ref_types_flag()) { + goto fail;; + } + + read_leb_uint32(p, p_end, table_idx); + if (!get_table_elem_type(module, table_idx, &decl_ref_type, + error_buf, error_buf_size)) + goto fail; + +#if WASM_ENABLE_FAST_INTERP != 0 + emit_uint32(loader_ctx, table_idx); +#endif + + if (opcode == WASM_OP_TABLE_GET) { + POP_I32(); +#if WASM_ENABLE_FAST_INTERP != 0 + PUSH_OFFSET_TYPE(decl_ref_type); +#endif + PUSH_TYPE(decl_ref_type); + } + else { +#if WASM_ENABLE_FAST_INTERP != 0 + POP_OFFSET_TYPE(decl_ref_type); +#endif + POP_TYPE(decl_ref_type); + POP_I32(); + } + break; + } + case WASM_OP_REF_NULL: + { + uint8 ref_type; + + if (!wasm_get_ref_types_flag()) { + goto fail;; + } + + CHECK_BUF(p, p_end, 1); + ref_type = read_uint8(p); + if (ref_type != VALUE_TYPE_FUNCREF + && ref_type != VALUE_TYPE_EXTERNREF) { + set_error_buf(error_buf, error_buf_size, + "unknown value type"); + goto fail; + } +#if WASM_ENABLE_FAST_INTERP != 0 + PUSH_OFFSET_TYPE(ref_type); +#endif + PUSH_TYPE(ref_type); + break; + } + case WASM_OP_REF_IS_NULL: + { + if (!wasm_get_ref_types_flag()) { + goto fail;; + } + +#if WASM_ENABLE_FAST_INTERP != 0 + if (!wasm_loader_pop_frame_ref_offset( + loader_ctx, VALUE_TYPE_FUNCREF, + error_buf, error_buf_size) + && !wasm_loader_pop_frame_ref_offset( + loader_ctx, VALUE_TYPE_EXTERNREF, + error_buf, error_buf_size)) { + goto fail; + } +#else + if (!wasm_loader_pop_frame_ref( + loader_ctx, VALUE_TYPE_FUNCREF, + error_buf, error_buf_size) + && !wasm_loader_pop_frame_ref( + loader_ctx, VALUE_TYPE_EXTERNREF, + error_buf, error_buf_size)) { + goto fail; + } +#endif + PUSH_I32(); + break; + } + case WASM_OP_REF_FUNC: + { + uint32 func_idx = 0; + if (!wasm_get_ref_types_flag()) { + goto fail;; + } + + read_leb_uint32(p, p_end, func_idx); + + if (!check_function_index(module, func_idx, error_buf, + error_buf_size)) { + goto fail; + } + + if (func_idx == cur_func_idx) { + WASMTableSeg *table_seg = module->table_segments; + bool func_declared = false; + uint32 j; + + /* Check whether current function is declared */ + for (i = 0; i < module->table_seg_count; i++, table_seg++) { + if (table_seg->elem_type == VALUE_TYPE_FUNCREF + && wasm_elem_is_declarative(table_seg->mode)) { + for (j =0; j < table_seg->function_count; j++) { + if (table_seg->func_indexes[j] == cur_func_idx) { + func_declared = true; + break; + } + } + } + } + if (!func_declared) { + set_error_buf(error_buf, error_buf_size, + "undeclared function reference"); + goto fail; + } + } + +#if WASM_ENABLE_FAST_INTERP != 0 + emit_uint32(loader_ctx, func_idx); +#endif + PUSH_FUNCREF(); + break; + } +#endif /* WASM_ENABLE_REF_TYPES */ + case WASM_OP_GET_LOCAL: { p_org = p - 1; @@ -4952,8 +5635,7 @@ handle_op_block_and_loop: #if (WASM_ENABLE_WAMR_COMPILER == 0) && (WASM_ENABLE_JIT == 0) if (local_offset < 0x80) { *p_org++ = EXT_OP_GET_LOCAL_FAST; - if (local_type == VALUE_TYPE_I32 - || local_type == VALUE_TYPE_F32) + if (is_32bit_type(local_type)) *p_org++ = (uint8)local_offset; else *p_org++ = (uint8)(local_offset | 0x80); @@ -4992,8 +5674,7 @@ handle_op_block_and_loop: loader_ctx->dynamic_offset -= 2; } else { - if (local_type == VALUE_TYPE_I32 - || local_type == VALUE_TYPE_F32) { + if (is_32bit_type(local_type)) { emit_label(EXT_OP_SET_LOCAL_FAST); emit_byte(loader_ctx, (uint8)local_offset); } @@ -5012,8 +5693,7 @@ handle_op_block_and_loop: #if (WASM_ENABLE_WAMR_COMPILER == 0) && (WASM_ENABLE_JIT == 0) if (local_offset < 0x80) { *p_org++ = EXT_OP_SET_LOCAL_FAST; - if (local_type == VALUE_TYPE_I32 - || local_type == VALUE_TYPE_F32) + if (is_32bit_type(local_type)) *p_org++ = (uint8)local_offset; else *p_org++ = (uint8)(local_offset | 0x80); @@ -5050,8 +5730,7 @@ handle_op_block_and_loop: if (local_offset < 256) { skip_label(); - if (local_type == VALUE_TYPE_I32 - || local_type == VALUE_TYPE_F32) { + if (is_32bit_type(local_type)) { emit_label(EXT_OP_TEE_LOCAL_FAST); emit_byte(loader_ctx, (uint8)local_offset); } @@ -5069,8 +5748,7 @@ handle_op_block_and_loop: #if (WASM_ENABLE_WAMR_COMPILER == 0) && (WASM_ENABLE_JIT == 0) if (local_offset < 0x80) { *p_org++ = EXT_OP_TEE_LOCAL_FAST; - if (local_type == VALUE_TYPE_I32 - || local_type == VALUE_TYPE_F32) + if (is_32bit_type(local_type)) *p_org++ = (uint8)local_offset; else *p_org++ = (uint8)(local_offset | 0x80); @@ -5104,8 +5782,7 @@ handle_op_block_and_loop: } #endif #else /* else of WASM_ENABLE_FAST_INTERP */ - if (global_type == VALUE_TYPE_I64 - || global_type == VALUE_TYPE_F64) { + if (is_64bit_type(global_type)) { skip_label(); emit_label(WASM_OP_GET_GLOBAL_64); } @@ -5140,8 +5817,7 @@ handle_op_block_and_loop: #if WASM_ENABLE_FAST_INTERP == 0 #if (WASM_ENABLE_WAMR_COMPILER == 0) && (WASM_ENABLE_JIT == 0) - if (global_type == VALUE_TYPE_I64 - || global_type == VALUE_TYPE_F64) { + if (is_64bit_type(global_type)) { *p_org = WASM_OP_SET_GLOBAL_64; } else if (module->aux_stack_size > 0 @@ -5150,8 +5826,7 @@ handle_op_block_and_loop: } #endif #else /* else of WASM_ENABLE_FAST_INTERP */ - if (global_type == VALUE_TYPE_I64 - || global_type == VALUE_TYPE_F64) { + if (is_64bit_type(global_type)) { skip_label(); emit_label(WASM_OP_SET_GLOBAL_64); } @@ -5637,8 +6312,158 @@ handle_op_block_and_loop: POP_I32(); POP_I32(); break; - /* TODO: to support bulk table operation */ #endif /* WASM_ENABLE_BULK_MEMORY */ +#if WASM_ENABLE_REF_TYPES != 0 + case WASM_OP_TABLE_INIT: + { + uint8 seg_ref_type, tbl_ref_type; + uint32 table_seg_idx, table_idx; + + if (!wasm_get_ref_types_flag()) { + goto fail; + } + + read_leb_uint32(p, p_end, table_seg_idx); + read_leb_uint32(p, p_end, table_idx); + + if (!get_table_elem_type(module, table_idx, &tbl_ref_type, + error_buf, error_buf_size)) + goto fail; + + if (!get_table_seg_elem_type(module, table_seg_idx, + &seg_ref_type, error_buf, + error_buf_size)) + goto fail; + + if (seg_ref_type != tbl_ref_type) { + set_error_buf(error_buf, error_buf_size, + "type mismatch"); + goto fail; + } + +#if WASM_ENABLE_FAST_INTERP != 0 + emit_uint32(loader_ctx, table_seg_idx); + emit_uint32(loader_ctx, table_idx); +#endif + POP_I32(); + POP_I32(); + POP_I32(); + break; + } + case WASM_OP_ELEM_DROP: + { + uint32 table_seg_idx; + if (!wasm_get_ref_types_flag()) { + goto fail; + } + + read_leb_uint32(p, p_end, table_seg_idx); + if (!get_table_seg_elem_type(module, table_seg_idx, NULL, + error_buf, error_buf_size)) + goto fail; +#if WASM_ENABLE_FAST_INTERP != 0 + emit_uint32(loader_ctx, table_seg_idx); +#endif + break; + } + case WASM_OP_TABLE_COPY: + { + uint8 src_ref_type, dst_ref_type; + uint32 src_tbl_idx, dst_tbl_idx; + + if (!wasm_get_ref_types_flag()) { + goto fail; + } + + read_leb_uint32(p, p_end, src_tbl_idx); + if (!get_table_elem_type(module, src_tbl_idx, &src_ref_type, + error_buf, error_buf_size)) + goto fail; + + read_leb_uint32(p, p_end, dst_tbl_idx); + if (!get_table_elem_type(module, dst_tbl_idx, &dst_ref_type, + error_buf, error_buf_size)) + goto fail; + + if (src_ref_type != dst_ref_type) { + set_error_buf(error_buf, error_buf_size, + "type mismatch"); + goto fail; + } + +#if WASM_ENABLE_FAST_INTERP != 0 + emit_uint32(loader_ctx, src_tbl_idx); + emit_uint32(loader_ctx, dst_tbl_idx); +#endif + POP_I32(); + POP_I32(); + POP_I32(); + break; + } + case WASM_OP_TABLE_SIZE: + { + uint32 table_idx; + if (!wasm_get_ref_types_flag()) { + goto fail; + } + + read_leb_uint32(p, p_end, table_idx); + /* TODO: shall we create a new function to check + table idx instead of using below function? */ + if (!get_table_elem_type(module, table_idx, NULL, + error_buf, error_buf_size)) + goto fail; + +#if WASM_ENABLE_FAST_INTERP != 0 + emit_uint32(loader_ctx, table_idx); +#endif + + PUSH_I32(); + break; + } + case WASM_OP_TABLE_GROW: + case WASM_OP_TABLE_FILL: + { + uint8 decl_ref_type; + uint32 table_idx; + + if (!wasm_get_ref_types_flag()) { + goto fail; + } + + read_leb_uint32(p, p_end, table_idx); + if (!get_table_elem_type(module, table_idx, + &decl_ref_type, error_buf, + error_buf_size)) + goto fail; + + if (opcode1 == WASM_OP_TABLE_GROW) { + if (table_idx < module->import_table_count) { + module->import_tables[table_idx] + .u.table.possible_grow = true; + } + else { + module->tables[table_idx - module->import_table_count] + .possible_grow = true; + } + } + +#if WASM_ENABLE_FAST_INTERP != 0 + emit_uint32(loader_ctx, table_idx); +#endif + + POP_I32(); +#if WASM_ENABLE_FAST_INTERP != 0 + POP_OFFSET_TYPE(decl_ref_type); +#endif + POP_TYPE(decl_ref_type); + if (opcode1 == WASM_OP_TABLE_GROW) + PUSH_I32(); + else + POP_I32(); + break; + } +#endif /* WASM_ENABLE_REF_TYPES */ default: bh_assert(0); break; @@ -5815,7 +6640,8 @@ handle_op_block_and_loop: bh_memcpy_s(func_const, (uint32)(func_const_end - func_const), &(c->value.f64), (uint32)sizeof(int64)); func_const += sizeof(int64); - } else { + } + else { bh_memcpy_s(func_const, (uint32)(func_const_end - func_const), &(c->value.f32), (uint32)sizeof(int32)); func_const += sizeof(int32); @@ -5843,5 +6669,24 @@ fail: (void)p_org; (void)mem_offset; (void)align; +#if WASM_ENABLE_BULK_MEMORY != 0 + (void)segment_index; +#endif return return_value; } + +#if WASM_ENABLE_REF_TYPES != 0 +static bool ref_types_flag = true; + +void +wasm_set_ref_types_flag(bool enable) +{ + ref_types_flag = enable; +} + +bool +wasm_get_ref_types_flag() +{ + return ref_types_flag; +} +#endif diff --git a/core/iwasm/interpreter/wasm_opcode.h b/core/iwasm/interpreter/wasm_opcode.h index fa0fed74a..5f5508230 100644 --- a/core/iwasm/interpreter/wasm_opcode.h +++ b/core/iwasm/interpreter/wasm_opcode.h @@ -47,11 +47,11 @@ typedef enum WASMOpcode { /* parametric instructions */ WASM_OP_DROP = 0x1a, /* drop */ WASM_OP_SELECT = 0x1b, /* select */ + WASM_OP_SELECT_T = 0x1c, /* select t */ - WASM_OP_UNUSED_0x1c = 0x1c, - WASM_OP_UNUSED_0x1d = 0x1d, - WASM_OP_UNUSED_0x1e = 0x1e, - WASM_OP_UNUSED_0x1f = 0x1f, + WASM_OP_GET_GLOBAL_64 = 0x1d, + WASM_OP_SET_GLOBAL_64 = 0x1e, + WASM_OP_SET_GLOBAL_AUX_STACK = 0x1f, /* variable instructions */ WASM_OP_GET_LOCAL = 0x20, /* get_local */ @@ -60,9 +60,9 @@ typedef enum WASMOpcode { WASM_OP_GET_GLOBAL = 0x23, /* get_global */ WASM_OP_SET_GLOBAL = 0x24, /* set_global */ - WASM_OP_GET_GLOBAL_64 = 0x25, - WASM_OP_SET_GLOBAL_64 = 0x26, - WASM_OP_SET_GLOBAL_AUX_STACK = 0x27, + WASM_OP_TABLE_GET = 0x25, /* table.get */ + WASM_OP_TABLE_SET = 0x26, /* table.set */ + WASM_OP_UNUSED_0x27 = 0x27, /* memory instructions */ WASM_OP_I32_LOAD = 0x28, /* i32.load */ @@ -256,10 +256,16 @@ typedef enum WASMOpcode { EXT_OP_COPY_STACK_TOP = 0xcc, EXT_OP_COPY_STACK_TOP_I64 = 0xcd, EXT_OP_COPY_STACK_VALUES = 0xce, - EXT_OP_BLOCK = 0xcf, /* block with blocktype */ - EXT_OP_LOOP = 0xd0, /* loop with blocktype */ - EXT_OP_IF = 0xd1, /* if with blocktype */ - WASM_OP_IMPDEP = 0xd2, + + WASM_OP_IMPDEP = 0xcf, + + WASM_OP_REF_NULL = 0xd0, /* ref.null */ + WASM_OP_REF_IS_NULL = 0xd1, /* ref.is_null */ + WASM_OP_REF_FUNC = 0xd2, /* ref.func */ + + EXT_OP_BLOCK = 0xd3, /* block with blocktype */ + EXT_OP_LOOP = 0xd4, /* loop with blocktype */ + EXT_OP_IF = 0xd5, /* if with blocktype */ /* Post-MVP extend op prefix */ WASM_OP_MISC_PREFIX = 0xfc, @@ -276,15 +282,16 @@ typedef enum WASMMiscEXTOpcode { WASM_OP_I64_TRUNC_SAT_U_F32 = 0x05, WASM_OP_I64_TRUNC_SAT_S_F64 = 0x06, WASM_OP_I64_TRUNC_SAT_U_F64 = 0x07, -#if WASM_ENABLE_BULK_MEMORY != 0 WASM_OP_MEMORY_INIT = 0x08, WASM_OP_DATA_DROP = 0x09, WASM_OP_MEMORY_COPY = 0x0a, WASM_OP_MEMORY_FILL = 0x0b, WASM_OP_TABLE_INIT = 0x0c, WASM_OP_ELEM_DROP = 0x0d, - WASM_OP_TABLE_COPY = 0x0e -#endif + WASM_OP_TABLE_COPY = 0x0e, + WASM_OP_TABLE_GROW = 0x0f, + WASM_OP_TABLE_SIZE = 0x10, + WASM_OP_TABLE_FILL = 0x11, } WASMMiscEXTOpcode; typedef enum WASMSimdEXTOpcode { @@ -594,15 +601,6 @@ typedef enum WASMAtomicEXTOpcode { } #endif -/* Opcode prefix controlled by features */ -#if WASM_ENABLE_SHARED_MEMORY != 0 -#define DEF_ATOMIC_PREFIX_HANDLE(_name) \ - _name[WASM_OP_ATOMIC_PREFIX] = \ - HANDLE_OPCODE (WASM_OP_ATOMIC_PREFIX); /* 0xfe */ -#else -#define DEF_ATOMIC_PREFIX_HANDLE(_name) -#endif - /* * Macro used to generate computed goto tables for the C interpreter. */ @@ -638,18 +636,18 @@ static type _name[WASM_INSTRUCTION_NUM] = { \ HANDLE_OPCODE (WASM_OP_UNUSED_0x19), /* 0x19 */ \ HANDLE_OPCODE (WASM_OP_DROP), /* 0x1a */ \ HANDLE_OPCODE (WASM_OP_SELECT), /* 0x1b */ \ - HANDLE_OPCODE (WASM_OP_UNUSED_0x1c), /* 0x1c */ \ - HANDLE_OPCODE (WASM_OP_UNUSED_0x1d), /* 0x1d */ \ - HANDLE_OPCODE (WASM_OP_UNUSED_0x1e), /* 0x1e */ \ - HANDLE_OPCODE (WASM_OP_UNUSED_0x1f), /* 0x1f */ \ + HANDLE_OPCODE (WASM_OP_SELECT_T), /* 0x1c */ \ + HANDLE_OPCODE (WASM_OP_GET_GLOBAL_64), /* 0x1d */ \ + HANDLE_OPCODE (WASM_OP_SET_GLOBAL_64), /* 0x1e */ \ + HANDLE_OPCODE (WASM_OP_SET_GLOBAL_AUX_STACK), /* 0x1f */ \ HANDLE_OPCODE (WASM_OP_GET_LOCAL), /* 0x20 */ \ HANDLE_OPCODE (WASM_OP_SET_LOCAL), /* 0x21 */ \ HANDLE_OPCODE (WASM_OP_TEE_LOCAL), /* 0x22 */ \ HANDLE_OPCODE (WASM_OP_GET_GLOBAL), /* 0x23 */ \ HANDLE_OPCODE (WASM_OP_SET_GLOBAL), /* 0x24 */ \ - HANDLE_OPCODE (WASM_OP_GET_GLOBAL_64), /* 0x25 */ \ - HANDLE_OPCODE (WASM_OP_SET_GLOBAL_64), /* 0x26 */ \ - HANDLE_OPCODE (WASM_OP_SET_GLOBAL_AUX_STACK), /* 0x27 */ \ + HANDLE_OPCODE (WASM_OP_TABLE_GET), /* 0x25 */ \ + HANDLE_OPCODE (WASM_OP_TABLE_SET), /* 0x26 */ \ + HANDLE_OPCODE (WASM_OP_UNUSED_0x27), /* 0x27 */ \ HANDLE_OPCODE (WASM_OP_I32_LOAD), /* 0x28 */ \ HANDLE_OPCODE (WASM_OP_I64_LOAD), /* 0x29 */ \ HANDLE_OPCODE (WASM_OP_F32_LOAD), /* 0x2a */ \ @@ -817,14 +815,19 @@ static type _name[WASM_INSTRUCTION_NUM] = { \ HANDLE_OPCODE (EXT_OP_COPY_STACK_TOP), /* 0xcc */ \ HANDLE_OPCODE (EXT_OP_COPY_STACK_TOP_I64), /* 0xcd */ \ HANDLE_OPCODE (EXT_OP_COPY_STACK_VALUES), /* 0xce */ \ - HANDLE_OPCODE (EXT_OP_BLOCK), /* 0xcf */ \ - HANDLE_OPCODE (EXT_OP_LOOP), /* 0xd0 */ \ - HANDLE_OPCODE (EXT_OP_IF), /* 0xd1 */ \ - HANDLE_OPCODE (WASM_OP_IMPDEP), /* 0xd2 */ \ + HANDLE_OPCODE (WASM_OP_IMPDEP), /* 0xcf */ \ + HANDLE_OPCODE (WASM_OP_REF_NULL), /* 0xd0 */ \ + HANDLE_OPCODE (WASM_OP_REF_IS_NULL), /* 0xd1 */ \ + HANDLE_OPCODE (WASM_OP_REF_FUNC), /* 0xd2 */ \ + HANDLE_OPCODE (EXT_OP_BLOCK), /* 0xd3 */ \ + HANDLE_OPCODE (EXT_OP_LOOP), /* 0xd4 */ \ + HANDLE_OPCODE (EXT_OP_IF), /* 0xd5 */ \ }; \ do { \ _name[WASM_OP_MISC_PREFIX] = \ HANDLE_OPCODE (WASM_OP_MISC_PREFIX); /* 0xfc */ \ - DEF_ATOMIC_PREFIX_HANDLE(_name) \ + _name[WASM_OP_ATOMIC_PREFIX] = \ + HANDLE_OPCODE (WASM_OP_ATOMIC_PREFIX); /* 0xfe */ \ } while (0) #endif /* end of _WASM_OPCODE_H */ + diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index 360958cb0..aa4176fc9 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -499,9 +499,12 @@ tables_instantiate(const WASMModule *module, else #endif { - /* it is a built-in table */ - total_size = offsetof(WASMTableInstance, base_addr) - + sizeof(uint32) * (uint64)import->u.table.init_size; + /* it is a built-in table, every module has its own */ + total_size = offsetof(WASMTableInstance, base_addr); + total_size += + import->u.table.possible_grow + ? sizeof(uint32) * (uint64)import->u.table.max_size + : sizeof(uint32) * (uint64)import->u.table.init_size; } if (!(table = tables[table_index++] = runtime_malloc @@ -530,8 +533,15 @@ tables_instantiate(const WASMModule *module, /* instantiate tables from table section */ for (i = 0; i < module->table_count; i++) { - total_size = offsetof(WASMTableInstance, base_addr) + - sizeof(uint32) * (uint64)module->tables[i].init_size; + total_size = offsetof(WASMTableInstance, base_addr); +#if WASM_ENABLE_MULTI_MODULE != 0 + /* in case, a module which imports this table will grow it */ + total_size += sizeof(uint32) * (uint64)module->tables[i].max_size; +#else + total_size += module->tables[i].possible_grow + ? sizeof(uint32) * (uint64)module->tables[i].max_size + : sizeof(uint32) * (uint64)module->tables[i].init_size; +#endif if (!(table = tables[table_index++] = runtime_malloc (total_size, error_buf, error_buf_size))) { tables_deinstantiate(tables, table_count); @@ -764,6 +774,11 @@ globals_instantiate(const WASMModule *module, &(globals[init_expr->u.global_index].initial_value), sizeof(globals[init_expr->u.global_index].initial_value)); } +#if WASM_ENABLE_REF_TYPES != 0 + else if (init_expr->init_expr_type == INIT_EXPR_TYPE_REFNULL_CONST) { + global->initial_value.u32 = (uint32)NULL_REF; + } +#endif else { bh_memcpy_s(&(global->initial_value), sizeof(WASMValue), &(init_expr->u), sizeof(init_expr->u)); @@ -1216,6 +1231,10 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, switch (global->type) { case VALUE_TYPE_I32: case VALUE_TYPE_F32: +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_FUNCREF: + case VALUE_TYPE_EXTERNREF: +#endif *(int32*)global_data = global->initial_value.i32; global_data += sizeof(int32); break; @@ -1285,13 +1304,18 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, .initial_value.i32; } - /* check offset since length might negative */ + /* check offset */ base_offset = (uint32)data_seg->base_offset.u.i32; if (base_offset > memory_size) { LOG_DEBUG("base_offset(%d) > memory_size(%d)", base_offset, memory_size); +#if WASM_ENABLE_REF_TYPES != 0 + set_error_buf(error_buf, error_buf_size, + "out of bounds memory access"); +#else set_error_buf(error_buf, error_buf_size, "data segment does not fit"); +#endif goto fail; } @@ -1300,8 +1324,13 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, if (base_offset + length > memory_size) { LOG_DEBUG("base_offset(%d) + length(%d) > memory_size(%d)", base_offset, length, memory_size); +#if WASM_ENABLE_REF_TYPES != 0 + set_error_buf(error_buf, error_buf_size, + "out of bounds memory access"); +#else set_error_buf(error_buf, error_buf_size, "data segment does not fit"); +#endif goto fail; } @@ -1314,12 +1343,23 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, /* Initialize the table data with table segment section */ module_inst->default_table = module_inst->table_count ? module_inst->tables[0] : NULL; - for (i = 0; i < module->table_seg_count; i++) { + /* in case there is no table */ + for (i = 0; module_inst->table_count > 0 && i < module->table_seg_count; + i++) { WASMTableSeg *table_seg = module->table_segments + i; /* has check it in loader */ WASMTableInstance *table = module_inst->tables[table_seg->table_index]; bh_assert(table); +#if WASM_ENABLE_REF_TYPES != 0 + if (table->elem_type != VALUE_TYPE_FUNCREF + && table->elem_type != VALUE_TYPE_EXTERNREF) { + set_error_buf(error_buf, error_buf_size, + "elements segment does not fit"); + goto fail; + } +#endif + uint32 *table_data = (uint32 *)table->base_addr; #if WASM_ENABLE_MULTI_MODULE != 0 table_data = table->table_inst_linked @@ -1328,11 +1368,20 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, #endif bh_assert(table_data); - /* init vec(funcidx) */ - bh_assert(table_seg->base_offset.init_expr_type - == INIT_EXPR_TYPE_I32_CONST - || table_seg->base_offset.init_expr_type - == INIT_EXPR_TYPE_GET_GLOBAL); +#if WASM_ENABLE_REF_TYPES != 0 + if (!wasm_elem_is_active(table_seg->mode)) + continue; +#endif + + /* init vec(funcidx) or vec(expr) */ + bh_assert( + table_seg->base_offset.init_expr_type == INIT_EXPR_TYPE_I32_CONST + || table_seg->base_offset.init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL +#if WASM_ENABLE_REF_TYPES != 0 + || table_seg->base_offset.init_expr_type == INIT_EXPR_TYPE_FUNCREF_CONST + || table_seg->base_offset.init_expr_type == INIT_EXPR_TYPE_REFNULL_CONST +#endif + ); if (table_seg->base_offset.init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL) { @@ -1349,6 +1398,7 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, "elements segment does not fit"); goto fail; } + table_seg->base_offset.u.i32 = globals[table_seg->base_offset.u.global_index].initial_value.i32; } @@ -1357,8 +1407,13 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, if ((uint32)table_seg->base_offset.u.i32 > table->cur_size) { LOG_DEBUG("base_offset(%d) > table->cur_size(%d)", table_seg->base_offset.u.i32, table->cur_size); +#if WASM_ENABLE_REF_TYPES != 0 + set_error_buf(error_buf, error_buf_size, + "out of bounds table access"); +#else set_error_buf(error_buf, error_buf_size, "elements segment does not fit"); +#endif goto fail; } @@ -1367,8 +1422,13 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, if ((uint32)table_seg->base_offset.u.i32 + length > table->cur_size) { LOG_DEBUG("base_offset(%d) + length(%d)> table->cur_size(%d)", table_seg->base_offset.u.i32, length, table->cur_size); +#if WASM_ENABLE_REF_TYPES != 0 + set_error_buf(error_buf, error_buf_size, + "out of bounds table access"); +#else set_error_buf(error_buf, error_buf_size, "elements segment does not fit"); +#endif goto fail; } @@ -1510,6 +1570,10 @@ wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst) if (module_inst->global_data) wasm_runtime_free(module_inst->global_data); +#if WASM_ENABLE_REF_TYPES != 0 + wasm_externref_cleanup((WASMModuleInstanceCommon*)module_inst); +#endif + wasm_runtime_free(module_inst); } @@ -1616,8 +1680,16 @@ wasm_create_exec_env_and_call_function(WASMModuleInstance *module_inst, } #endif +#if WASM_ENABLE_REF_TYPES != 0 + wasm_runtime_prepare_call_function(exec_env, func); +#endif + ret = wasm_call_function(exec_env, func, argc, argv); +#if WASM_ENABLE_REF_TYPES != 0 + wasm_runtime_finalize_call_function(exec_env, func, ret, argv); +#endif + #if WASM_ENABLE_THREAD_MGR != 0 /* don't destroy the exec_env if it's searched from the cluster */ if (!existing_exec_env) @@ -2025,8 +2097,47 @@ wasm_enlarge_memory(WASMModuleInstance *module, uint32 inc_page_count) return true; } +#if WASM_ENABLE_REF_TYPES != 0 +bool +wasm_enlarge_table(WASMModuleInstance *module_inst, + uint32 table_idx, uint32 inc_entries, uint32 init_val) +{ + uint32 entry_count, *new_table_data_start, i; + WASMTableInstance *table_inst; + + if (!inc_entries) { + return true; + } + + bh_assert(table_idx < module_inst->table_count); + table_inst = wasm_get_table_inst(module_inst, table_idx); + if (!table_inst) { + return false; + } + + entry_count = table_inst->cur_size + inc_entries; + /* prevent from integer overflow */ + if (entry_count < table_inst->cur_size + || entry_count > table_inst->max_size) { + return false; + } + + /* fill in */ + new_table_data_start = + (uint32 *)((uint8 *)table_inst + offsetof(WASMTableInstance, base_addr)) + + table_inst->cur_size; + for (i = 0; i < inc_entries; ++i) { + new_table_data_start[i] = init_val; + } + + table_inst->cur_size = entry_count; + return true; +} +#endif /* WASM_ENABLE_REF_TYPES != 0 */ + bool wasm_call_indirect(WASMExecEnv *exec_env, + uint32_t tbl_idx, uint32_t element_indices, uint32_t argc, uint32_t argv[]) { @@ -2039,7 +2150,7 @@ wasm_call_indirect(WASMExecEnv *exec_env, (WASMModuleInstance*)exec_env->module_inst; bh_assert(module_inst); - table_inst = module_inst->default_table; + table_inst = module_inst->tables[tbl_idx]; if (!table_inst) { wasm_set_exception(module_inst, "unknown table"); goto got_exception; @@ -2055,7 +2166,7 @@ wasm_call_indirect(WASMExecEnv *exec_env, * to another module's table **/ function_indices = ((uint32_t*)table_inst->base_addr)[element_indices]; - if (function_indices == 0xFFFFFFFF) { + if (function_indices == NULL_REF) { wasm_set_exception(module_inst, "uninitialized element"); goto got_exception; } @@ -2247,8 +2358,16 @@ wasm_get_module_inst_mem_consumption(const WASMModuleInstance *module_inst, * module_inst->table_count; for (i = 0; i < module_inst->table_count; i++) { WASMTableInstance *table = module_inst->tables[i]; - size = offsetof(WASMTableInstance, base_addr) - + sizeof(uint32) * table->cur_size; +#if WASM_ENABLE_MULTI_MODULE != 0 + if (table->table_inst_linked) { + size = offsetof(WASMTableInstance, base_addr); + } + else +#endif + { + size = offsetof(WASMTableInstance, base_addr) + + sizeof(uint32) * table->cur_size; + } mem_conspn->tables_size += size; } diff --git a/core/iwasm/interpreter/wasm_runtime.h b/core/iwasm/interpreter/wasm_runtime.h index 3d7d47c6e..5f45f183c 100644 --- a/core/iwasm/interpreter/wasm_runtime.h +++ b/core/iwasm/interpreter/wasm_runtime.h @@ -60,7 +60,7 @@ struct WASMMemoryInstance { }; struct WASMTableInstance { - /* The element type, TABLE_ELEM_TYPE_ANY_FUNC currently */ + /* The element type, VALUE_TYPE_FUNCREF/EXTERNREF currently */ uint8 elem_type; /* Current size */ uint32 cur_size; @@ -376,6 +376,7 @@ wasm_enlarge_memory(WASMModuleInstance *module, uint32 inc_page_count); bool wasm_call_indirect(WASMExecEnv *exec_env, + uint32_t tbl_idx, uint32_t element_indices, uint32_t argc, uint32_t argv[]); @@ -397,6 +398,45 @@ void wasm_get_module_inst_mem_consumption(const WASMModuleInstance *module, WASMModuleInstMemConsumption *mem_conspn); +#if WASM_ENABLE_REF_TYPES != 0 +static inline bool +wasm_elem_is_active(uint32 mode) +{ + return (mode & 0x1) == 0x0; +} + +static inline bool +wasm_elem_is_passive(uint32 mode) +{ + return (mode & 0x1) == 0x1; +} + +static inline bool +wasm_elem_is_declarative(uint32 mode) +{ + return (mode & 0x3) == 0x3; +} + +bool +wasm_enlarge_table(WASMModuleInstance *module_inst, + uint32 table_idx, uint32 inc_entries, uint32 init_val); +#endif /* WASM_ENABLE_REF_TYPES != 0 */ + +static inline WASMTableInstance * +wasm_get_table_inst(const WASMModuleInstance *module_inst, + const uint32 tbl_idx) +{ + /* careful, it might be a table in another module */ + WASMTableInstance *tbl_inst = module_inst->tables[tbl_idx]; +#if WASM_ENABLE_MULTI_MODULE != 0 + if (tbl_inst->table_inst_linked) { + tbl_inst = tbl_inst->table_inst_linked; + } +#endif + bh_assert(tbl_inst); + return tbl_inst; +} + #if WASM_ENABLE_DUMP_CALL_STACK != 0 void wasm_interp_dump_call_stack(struct WASMExecEnv *exec_env); diff --git a/core/shared/utils/bh_hashmap.c b/core/shared/utils/bh_hashmap.c index f774546a9..7ed036019 100644 --- a/core/shared/utils/bh_hashmap.c +++ b/core/shared/utils/bh_hashmap.c @@ -307,7 +307,8 @@ bh_hash_map_get_elem_struct_size() } bool -bh_hash_map_traverse(HashMap *map, TraverseCallbackFunc callback) +bh_hash_map_traverse(HashMap *map, TraverseCallbackFunc callback, + void *user_data) { uint32 index; HashMapElem *elem, *next; @@ -325,7 +326,7 @@ bh_hash_map_traverse(HashMap *map, TraverseCallbackFunc callback) elem = map->elements[index]; while (elem) { next = elem->next; - callback(elem->key, elem->value); + callback(elem->key, elem->value, user_data); elem = next; } } diff --git a/core/shared/utils/bh_hashmap.h b/core/shared/utils/bh_hashmap.h index 8cb02300c..de4eefcfc 100644 --- a/core/shared/utils/bh_hashmap.h +++ b/core/shared/utils/bh_hashmap.h @@ -34,7 +34,7 @@ typedef void (*ValueDestroyFunc)(void *key); /* traverse callback function: auto called when traverse every hash element */ -typedef void (*TraverseCallbackFunc)(void *key, void *value); +typedef void (*TraverseCallbackFunc)(void *key, void *value, void *user_data); /** * Create a hash map. @@ -150,14 +150,16 @@ bh_hash_map_get_elem_struct_size(); * Traverse the hash map and call the callback function * * @param map the hash map to traverse - * @callback the function to be called for every element + * @param callback the function to be called for every element + * @param user_data the argument to be passed to the callback function * * @return true if success, false otherwise * Note: if the hash map has lock, the map will be locked during traverse, * keep the callback function as simple as possible. */ bool -bh_hash_map_traverse(HashMap *map, TraverseCallbackFunc callback); +bh_hash_map_traverse(HashMap *map, TraverseCallbackFunc callback, + void *user_data); #ifdef __cplusplus } diff --git a/doc/build_wamr.md b/doc/build_wamr.md index 3ea474289..f9692bb81 100644 --- a/doc/build_wamr.md +++ b/doc/build_wamr.md @@ -135,6 +135,9 @@ Currently we only profile the memory consumption of module, module_instance and > > and then use `cmake -DWAMR_BH_VPRINTF=my_vprintf ..` to pass the callback function, or add `BH_VPRINTF=my_vprintf` macro for the compiler, e.g. add line `add_defintions(-DBH_VPRINTF=my_vprintf)` in CMakeListst.txt. +#### **Enable reference types feature** +- **WAMR_BUILD_REF_TYPES**=1/0, default to disable if not set + **Combination of configurations:** We can combine the configurations. For example, if we want to disable interpreter, enable AOT and WASI, we can run command: diff --git a/doc/export_native_api.md b/doc/export_native_api.md index 8b21d4a12..e507c5c41 100644 --- a/doc/export_native_api.md +++ b/doc/export_native_api.md @@ -85,7 +85,7 @@ The function signature field in **NativeSymbol** structure is a string for descr Each letter in the "()" represents a parameter type, and the one following after ")" represents the return value type. The meaning of each letter: -- '**i**': i32 +- '**i**': i32 or externref (for externref, developer should use `wasm_externref_obj2ref()` to map host object to externref index firstly) - '**I**': i64 - '**f**': f32 - '**F**': f64 diff --git a/doc/ref_types.md b/doc/ref_types.md new file mode 100644 index 000000000..ed37411f3 --- /dev/null +++ b/doc/ref_types.md @@ -0,0 +1,22 @@ +# WAMR reference-types introduction + +WebAssembly [reference-types](https://github.com/WebAssembly/reference-types) proposal introduces the new type `externref` and makes it easier and more efficient to interoperate with host environment, allowing host references to be represented directly by type externref. And WASM modules can talk about host references directly, rather than requiring external glue code running in the host. + +WAMR implements the reference-types proposal, allowing developer to pass the host object to WASM application and then restore and access the host object in native lib. In WAMR internal, the external host object is represented as externref index with `uint32` type, developer must firstly map the host object of `void *` type to the externref index, and then pass the index to the function to called as the function's externref argument. + +Currently WAMR provides APIs as below: +```C +bool +wasm_externref_obj2ref(wasm_module_inst_t module_inst, + void *extern_obj, uint32_t *p_externref_idx); + +WASM_RUNTIME_API_EXTERN bool +wasm_externref_ref2obj(uint32_t externref_idx, void **p_extern_obj); + +WASM_RUNTIME_API_EXTERN bool +wasm_externref_retain(uint32 externref_idx); +``` + +The `wasm_externref_obj2ref()` API is used to map the host object to the externref index, and the `wasm_externref_ref2obj()` API is used to retrieve the original host object mapped. The `wasm_externref_retain()` API is to retain the host object if we don't want the object to be cleaned when it isn't used during externref object reclaim. + +Please ref to the [sample](../samples/ref-types) for more details. diff --git a/product-mini/platforms/linux/CMakeLists.txt b/product-mini/platforms/linux/CMakeLists.txt index cefb9bff5..231bd0720 100644 --- a/product-mini/platforms/linux/CMakeLists.txt +++ b/product-mini/platforms/linux/CMakeLists.txt @@ -85,6 +85,11 @@ if (NOT DEFINED WAMR_BUILD_SIMD) set (WAMR_BUILD_SIMD 1) endif () +if (NOT DEFINED WAMR_BUILD_REF_TYPES) + # Disable reference types by default + set (WAMR_BUILD_REF_TYPES 0) +endif () + if (COLLECT_CODE_COVERAGE EQUAL 1) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage") endif () diff --git a/samples/ref-types/CMakeLists.txt b/samples/ref-types/CMakeLists.txt new file mode 100644 index 000000000..38c1d4750 --- /dev/null +++ b/samples/ref-types/CMakeLists.txt @@ -0,0 +1,108 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required (VERSION 2.8) + +if (NOT WAMR_BUILD_PLATFORM STREQUAL "windows") + project(ref-types) +else() + project (ref-types C ASM) + enable_language (ASM_MASM) +endif() + +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Debug) +endif() + +################ runtime settings ################ +string (TOLOWER ${CMAKE_HOST_SYSTEM_NAME} WAMR_BUILD_PLATFORM) +if (APPLE) + add_definitions(-DBH_PLATFORM_DARWIN) +endif () + +# Resetdefault linker flags +set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") +set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") + +# WAMR features switch +set(WAMR_BUILD_TARGET "X86_64") + +if(NOT DEFINED WAMR_BUILD_INTERP) + set(WAMR_BUILD_INTERP 1) +endif() + +if(NOT DEFINED WAMR_BUILD_AOT) + set(WAMR_BUILD_AOT 0) +endif() + +if(NOT DEFINED WAMR_BUILD_JOT) + set(WAMR_BUILD_JIT 0) +endif() + +if(NOT DEFINED WAMR_BUILD_FAST_INTERP) + set(WAMR_BUILD_FAST_INTERP 1) +endif() + +if(NOT DEFINED WAMR_BUILD_LIBC_BUILTIN) + set(WAMR_BUILD_LIBC_BUILTIN 1) +endif() + +# Enable reference-types feature +set(WAMR_BUILD_REF_TYPES 1) + +if (NOT MSVC) + # compiling and linking flags + set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pie -fPIE") + if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang")) + set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") + endif () + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat -Wformat-security") + if (WAMR_BUILD_TARGET MATCHES "X86_.*" OR WAMR_BUILD_TARGET STREQUAL "AMD_64") + if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang")) + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mindirect-branch-register") + endif () + endif () +endif() +# build out vmlib +set(WAMR_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../..) +set(WAMRC ${WAMR_ROOT_DIR}/wamr-compiler/build/wamrc) +include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) + +add_library(vmlib STATIC ${WAMR_RUNTIME_LIB_SOURCE}) +if (MSVC) + target_compile_definitions(vmlib PRIVATE WASM_API_EXTERN=) +endif() + +################ application related ################ +## locate wat2wasm +find_program(WAT2WASM + wat2wasm + PATHS /opt/wabt/bin + REQUIRED +) + +if(NOT WAT2WASM) + message(SEND_ERROR "can not find wat2wasm") +endif() + +include (${SHARED_DIR}/utils/uncommon/shared_uncommon.cmake) + +add_executable(hello src/hello.c ${UNCOMMON_SHARED_SOURCE}) + +target_include_directories(hello PRIVATE ${UNCOMMON_SHARED_DIR}) + +target_link_libraries(hello vmlib -lpthread -lm) + +if (MSVC) + target_compile_definitions(hello PRIVATE WASM_API_EXTERN=) +endif() + +# wat to wasm +file(GLOB WAT_FILE src/hello.wat) +add_custom_target(hello_wasm ALL + COMMAND ${WAT2WASM} ${WAT_FILE} -o ${PROJECT_BINARY_DIR}/hello.wasm + DEPENDS ${WAT_FILE} + BYPRODUCTS ${PROJECT_BINARY_DIR}/hello.wasm + VERBATIM + SOURCES ${WAT_FILE} +) diff --git a/samples/ref-types/src/hello.c b/samples/ref-types/src/hello.c new file mode 100644 index 000000000..a5ec8eb44 --- /dev/null +++ b/samples/ref-types/src/hello.c @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "bh_platform.h" +#include "bh_read_file.h" +#include "wasm_export.h" + +#define USE_GLOBAL_HEAP_BUF 0 + +#if USE_GLOBAL_HEAP_BUF != 0 +static char global_heap_buf[10 * 1024 * 1024] = { 0 }; +#endif + +static int +test_write_wrapper(wasm_exec_env_t exec_env, + uint32 externref_idx_of_file, + const char *str, int len) +{ + FILE *file; + char buf[16]; + + printf("## retrieve file handle from externref index\n"); + if (!wasm_externref_ref2obj(externref_idx_of_file, (void **)&file)) { + printf("failed to get host object from externref index!\n"); + return -1; + } + + snprintf(buf, sizeof(buf), "%%%ds", len); + + printf("## write string to file: "); + printf(buf, str); + + return fprintf(file, buf, str); +} + +static NativeSymbol native_symbols[] = { + { "test_write", test_write_wrapper, "(i*~)i", NULL } +}; + +int +main(int argc, char *argv[]) +{ + char *wasm_file = "hello.wasm"; + uint8 *wasm_file_buf = NULL; + uint32 wasm_file_size, externref_idx; + uint32 stack_size = 16 * 1024, heap_size = 16 * 1024; + wasm_module_t wasm_module = NULL; + wasm_module_inst_t wasm_module_inst = NULL; + wasm_function_inst_t func_inst = NULL; + wasm_exec_env_t exec_env = NULL; + RuntimeInitArgs init_args; + char error_buf[128] = { 0 }; + const char *exce; + unsigned argv1[8]; +#if WASM_ENABLE_LOG != 0 + int log_verbose_level = 2; +#endif + FILE *file; + + memset(&init_args, 0, sizeof(RuntimeInitArgs)); + +#if USE_GLOBAL_HEAP_BUF != 0 + init_args.mem_alloc_type = Alloc_With_Pool; + init_args.mem_alloc_option.pool.heap_buf = global_heap_buf; + init_args.mem_alloc_option.pool.heap_size = sizeof(global_heap_buf); +#else + init_args.mem_alloc_type = Alloc_With_Allocator; + init_args.mem_alloc_option.allocator.malloc_func = malloc; + init_args.mem_alloc_option.allocator.realloc_func = realloc; + init_args.mem_alloc_option.allocator.free_func = free; +#endif + + init_args.n_native_symbols = sizeof(native_symbols) / sizeof(NativeSymbol); + init_args.native_module_name = "env"; + init_args.native_symbols = native_symbols; + + /* initialize runtime environment */ + if (!wasm_runtime_full_init(&init_args)) { + printf("Init runtime environment failed.\n"); + return -1; + } + +#if WASM_ENABLE_LOG != 0 + bh_log_set_verbose_level(log_verbose_level); +#endif + + /* load WASM byte buffer from WASM bin file */ + if (!(wasm_file_buf = + (uint8 *)bh_read_file_to_buffer(wasm_file, &wasm_file_size))) + goto fail1; + + /* load WASM module */ + if (!(wasm_module = wasm_runtime_load(wasm_file_buf, wasm_file_size, + error_buf, sizeof(error_buf)))) { + printf("%s\n", error_buf); + goto fail2; + } + + /* instantiate the module */ + if (!(wasm_module_inst = + wasm_runtime_instantiate(wasm_module, stack_size, heap_size, + error_buf, sizeof(error_buf)))) { + printf("%s\n", error_buf); + goto fail3; + } + + /* lookup function instance */ + if (!(func_inst = wasm_runtime_lookup_function(wasm_module_inst, + "test", NULL))) { + printf("%s\n", "lookup function test failed"); + goto fail4; + } + + if (!(exec_env = + wasm_runtime_create_exec_env(wasm_module_inst, stack_size))) { + printf("%s\n", "create exec env failed"); + goto fail4; + } + + printf("## open file test.txt\n"); + if (!(file = fopen("test.txt", "wb+"))) { + printf("%s\n", "open file text.txt failed"); + goto fail5; + } + + printf("## map file handle to externref index\n"); + if (!wasm_externref_obj2ref(wasm_module_inst, file, &externref_idx)) { + printf("%s\n", "map host object to externref index failed"); + goto fail6; + } + + printf("## call wasm function with externref index\n"); + argv1[0] = externref_idx; + wasm_runtime_call_wasm(exec_env, func_inst, 1, argv1); + + if ((exce = wasm_runtime_get_exception(wasm_module_inst))) { + printf("Exception: %s\n", exce); + } + +fail6: + fclose(file); + +fail5: + /* destroy exec env */ + wasm_runtime_destroy_exec_env(exec_env); + +fail4: + /* destroy the module instance */ + wasm_runtime_deinstantiate(wasm_module_inst); + +fail3: + /* unload the module */ + wasm_runtime_unload(wasm_module); + +fail2: + /* free the file buffer */ + wasm_runtime_free(wasm_file_buf); + +fail1: + /* destroy runtime environment */ + wasm_runtime_destroy(); + return 0; +} diff --git a/samples/ref-types/src/hello.wat b/samples/ref-types/src/hello.wat new file mode 100644 index 000000000..1a0f21db3 --- /dev/null +++ b/samples/ref-types/src/hello.wat @@ -0,0 +1,22 @@ +;; Copyright (C) 2019 Intel Corporation. All rights reserved. +;; SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +(module + ;; import test_write function which is implemented by host + (import "env" "test_write" + (func $test_write (param externref i32 i32) (result i32))) + + ;; memory with one page (64KiB). + (memory (export "memory") 1) + + (data (i32.const 0x8) "Hello, world!\n") + + ;; function that writes string to a given open file handle + (func (export "test") (param externref) + (local.get 0) + (i32.const 0x8) + (i32.const 14) + (call $test_write) + drop + ) +) diff --git a/wamr-compiler/CMakeLists.txt b/wamr-compiler/CMakeLists.txt index e47ce833d..440970cf5 100644 --- a/wamr-compiler/CMakeLists.txt +++ b/wamr-compiler/CMakeLists.txt @@ -31,6 +31,7 @@ add_definitions(-DWASM_ENABLE_SHARED_MEMORY=1) add_definitions(-DWASM_ENABLE_THREAD_MGR=1) add_definitions(-DWASM_ENABLE_TAIL_CALL=1) add_definitions(-DWASM_ENABLE_SIMD=1) +add_definitions(-DWASM_ENABLE_REF_TYPES=1) add_definitions(-DWASM_ENABLE_CUSTOM_NAME_SECTION=1) add_definitions(-DWASM_ENABLE_DUMP_CALL_STACK=1) add_definitions(-DWASM_ENABLE_PERF_PROFILING=1) @@ -90,6 +91,10 @@ if (NOT CMAKE_BUILD_TYPE) endif (NOT CMAKE_BUILD_TYPE) message ("-- CMAKE_BUILD_TYPE = " ${CMAKE_BUILD_TYPE}) +if (CMAKE_BUILD_TYPE STREQUAL "Debug") + add_definitions(-DBH_DEBUG=1) +endif () + # Enable LLVM set (LLVM_SRC_ROOT "${PROJECT_SOURCE_DIR}/../core/deps/llvm") if (WAMR_BUILD_PLATFORM STREQUAL "windows") diff --git a/wamr-compiler/main.c b/wamr-compiler/main.c index f552e9b2d..4ced209b0 100644 --- a/wamr-compiler/main.c +++ b/wamr-compiler/main.c @@ -9,6 +9,12 @@ #include "wasm_export.h" #include "aot_export.h" + +#if WASM_ENABLE_REF_TYPES != 0 +extern void +wasm_set_ref_types_flag(bool enable); +#endif + static int print_help() { @@ -47,6 +53,7 @@ print_help() printf(" currently 128-bit SIMD is only supported for x86-64 target,\n"); printf(" and by default it is enabled in x86-64 target and disabled\n"); printf(" in other targets\n"); + printf(" --enable-ref-types Enable the post-MVP reference types feature\n"); printf(" --disable-aux-stack-check Disable auxiliary stack overflow/underflow check\n"); printf(" --enable-dump-call-stack Enable stack trace feature\n"); printf(" --enable-perf-profiling Enable function performance profiling\n"); @@ -166,6 +173,9 @@ main(int argc, char *argv[]) else if (!strcmp(argv[0], "--disable-simd")) { option.enable_simd = false; } + else if (!strcmp(argv[0], "--enable-ref-types")) { + option.enable_ref_types = true; + } else if (!strcmp(argv[0], "--disable-aux-stack-check")) { option.enable_aux_stack_check = false; } @@ -187,6 +197,10 @@ main(int argc, char *argv[]) option.is_sgx_platform = true; } +#if WASM_ENABLE_REF_TYPES != 0 + wasm_set_ref_types_flag(option.enable_ref_types); +#endif + wasm_file_name = argv[0]; memset(&init_args, 0, sizeof(RuntimeInitArgs)); From 684d766e2b6b15b2abceeb80fb6d24d22baee930 Mon Sep 17 00:00:00 2001 From: Xu Jun <693788454@qq.com> Date: Mon, 19 Apr 2021 21:06:56 +0800 Subject: [PATCH 185/207] Refine aot call func procedure and fix zephyr timer overflow issue (#617) 1. Refine the aot call function procedure 2. fix timer integer overflow issue on zephyr platform 3. move wasm_exec_env_set_thread_info into lower layer --- core/config.h | 3 + core/iwasm/aot/aot_runtime.c | 74 +++------------- core/iwasm/common/wasm_runtime_common.c | 3 - core/iwasm/interpreter/wasm_runtime.c | 6 +- core/shared/platform/android/platform_init.c | 3 + .../platform/android/platform_internal.h | 8 +- .../platform/common/posix/posix_thread.c | 85 +++++++++++++++++-- core/shared/platform/darwin/platform_init.c | 3 + .../platform/darwin/platform_internal.h | 8 +- core/shared/platform/linux/platform_init.c | 3 + .../shared/platform/linux/platform_internal.h | 8 +- core/shared/platform/vxworks/platform_init.c | 3 + .../platform/vxworks/platform_internal.h | 8 +- core/shared/platform/zephyr/zephyr_time.c | 2 +- 14 files changed, 135 insertions(+), 82 deletions(-) diff --git a/core/config.h b/core/config.h index 878a42280..7f0c01789 100644 --- a/core/config.h +++ b/core/config.h @@ -267,6 +267,9 @@ stack overflow exception if the guard boudary is reached */ #define RESERVED_BYTES_TO_NATIVE_STACK_BOUNDARY (512) +/* Guard page count for stack overflow check with hardware trap */ +#define STACK_OVERFLOW_CHECK_GUARD_PAGE_COUNT 3 + /* Default wasm block address cache size and conflict list size */ #ifndef BLOCK_ADDR_CACHE_SIZE #define BLOCK_ADDR_CACHE_SIZE 64 diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index 139c0d034..0657804e6 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -1110,17 +1110,8 @@ aot_lookup_function(const AOTModuleInstance *module_inst, #ifdef OS_ENABLE_HW_BOUND_CHECK -#define STACK_OVERFLOW_CHECK_GUARD_PAGE_COUNT 3 - static os_thread_local_attribute WASMExecEnv *aot_exec_env = NULL; -static inline uint8 * -get_stack_min_addr(WASMExecEnv *exec_env, uint32 page_size) -{ - uintptr_t stack_bound = (uintptr_t)exec_env->native_stack_boundary; - return (uint8*)(stack_bound & ~(uintptr_t)(page_size -1 )); -} - static void aot_signal_handler(void *sig_addr) { @@ -1149,7 +1140,7 @@ aot_signal_handler(void *sig_addr) /* Get stack info of current thread */ page_size = os_getpagesize(); - stack_min_addr = get_stack_min_addr(aot_exec_env, page_size); + stack_min_addr = os_thread_get_stack_boundary(); if (memory_inst && (mapped_mem_start_addr <= (uint8*)sig_addr @@ -1182,27 +1173,6 @@ aot_signal_destroy() os_signal_destroy(); } -#if defined(__GNUC__) -__attribute__((no_sanitize_address)) static uint32 -#else -static uint32 -#endif -touch_pages(uint8 *stack_min_addr, uint32 page_size) -{ - uint8 sum = 0; - while (1) { - volatile uint8 *touch_addr = - (volatile uint8*)os_alloca(page_size / 2); - if (touch_addr < stack_min_addr + page_size) { - sum += *(stack_min_addr + page_size - 1); - break; - } - *touch_addr = 0; - sum += *touch_addr; - } - return sum; -} - static bool invoke_native_with_hw_bound_check(WASMExecEnv *exec_env, void *func_ptr, const WASMType *func_type, const char *signature, @@ -1211,10 +1181,9 @@ invoke_native_with_hw_bound_check(WASMExecEnv *exec_env, void *func_ptr, { AOTModuleInstance *module_inst = (AOTModuleInstance*)exec_env->module_inst; WASMExecEnv **p_aot_exec_env = &aot_exec_env; - WASMJmpBuf *jmpbuf_node, *jmpbuf_node_pop; + WASMJmpBuf jmpbuf_node = { 0 }, *jmpbuf_node_pop; uint32 page_size = os_getpagesize(); uint32 guard_page_count = STACK_OVERFLOW_CHECK_GUARD_PAGE_COUNT; - uint8 *stack_min_addr = get_stack_min_addr(exec_env, page_size); bool ret; /* Check native stack overflow firstly to ensure we have enough @@ -1226,33 +1195,17 @@ invoke_native_with_hw_bound_check(WASMExecEnv *exec_env, void *func_ptr, return false; } - if (aot_exec_env - && (aot_exec_env != exec_env)) { + if (aot_exec_env && (aot_exec_env != exec_env)) { aot_set_exception(module_inst, "invalid exec env"); return false; } - if (!exec_env->jmpbuf_stack_top) { - /* Touch each stack page to ensure that it has been mapped: the OS may - lazily grow the stack mapping as a guard page is hit. */ - (void)touch_pages(stack_min_addr, page_size); - /* First time to call aot function, protect one page */ - if (os_mprotect(stack_min_addr, page_size * guard_page_count, - MMAP_PROT_NONE) != 0) { - aot_set_exception(module_inst, "set protected page failed"); - return false; - } - } + os_thread_init_stack_guard_pages(); - if (!(jmpbuf_node = wasm_runtime_malloc(sizeof(WASMJmpBuf)))) { - aot_set_exception_with_id(module_inst, EXCE_OUT_OF_MEMORY); - return false; - } - - wasm_exec_env_push_jmpbuf(exec_env, jmpbuf_node); + wasm_exec_env_push_jmpbuf(exec_env, &jmpbuf_node); aot_exec_env = exec_env; - if (os_setjmp(jmpbuf_node->jmpbuf) == 0) { + if (os_setjmp(jmpbuf_node.jmpbuf) == 0) { ret = wasm_runtime_invoke_native(exec_env, func_ptr, func_type, signature, attachment, argv, argc, argv_ret); @@ -1263,12 +1216,8 @@ invoke_native_with_hw_bound_check(WASMExecEnv *exec_env, void *func_ptr, } jmpbuf_node_pop = wasm_exec_env_pop_jmpbuf(exec_env); - bh_assert(jmpbuf_node == jmpbuf_node_pop); - wasm_runtime_free(jmpbuf_node); + bh_assert(&jmpbuf_node == jmpbuf_node_pop); if (!exec_env->jmpbuf_stack_top) { - /* Unprotect the guard page when the nested call depth is zero */ - os_mprotect(stack_min_addr, page_size * guard_page_count, - MMAP_PROT_READ | MMAP_PROT_WRITE); *p_aot_exec_env = NULL; } os_sigreturn(); @@ -1293,6 +1242,9 @@ aot_call_function(WASMExecEnv *exec_env, uint32 ext_ret_count = result_count > 1 ? result_count - 1 : 0; bool ret; + /* set thread handle and stack boundary */ + wasm_exec_env_set_thread_info(exec_env); + if (ext_ret_count > 0) { uint32 cell_num = 0, i; uint8 *ext_ret_types = func_type->types + func_type->param_count + 1; @@ -1375,7 +1327,7 @@ aot_call_function(WASMExecEnv *exec_env, case VALUE_TYPE_V128: argv_ret += 4; break; -#endif - +#endif default: bh_assert(0); break; @@ -1436,8 +1388,6 @@ aot_create_exec_env_and_call_function(AOTModuleInstance *module_inst, return false; } - /* set thread handle and stack boundary */ - wasm_exec_env_set_thread_info(exec_env); #if WASM_ENABLE_THREAD_MGR != 0 } #endif @@ -2265,7 +2215,7 @@ aot_call_indirect(WASMExecEnv *exec_env, case VALUE_TYPE_V128: argv_ret += 4; break; -#endif - +#endif default: bh_assert(0); break; diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index 82f8a0f8c..8e122906c 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -1122,9 +1122,6 @@ wasm_runtime_call_wasm(WASMExecEnv *exec_env, return false; } - /* set thread handle and stack boundary */ - wasm_exec_env_set_thread_info(exec_env); - #if WASM_ENABLE_REF_TYPES != 0 wasm_runtime_prepare_call_function(exec_env, function); #endif diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index aa4176fc9..08c2bd241 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -1647,6 +1647,10 @@ wasm_call_function(WASMExecEnv *exec_env, unsigned argc, uint32 argv[]) { WASMModuleInstance *module_inst = (WASMModuleInstance*)exec_env->module_inst; + + /* set thread handle and stack boundary */ + wasm_exec_env_set_thread_info(exec_env); + wasm_interp_call_wasm(module_inst, exec_env, function, argc, argv); (void)clear_wasi_proc_exit_exception(module_inst); return !wasm_get_exception(module_inst) ? true : false; @@ -1674,8 +1678,6 @@ wasm_create_exec_env_and_call_function(WASMModuleInstance *module_inst, return false; } - /* set thread handle and stack boundary */ - wasm_exec_env_set_thread_info(exec_env); #if WASM_ENABLE_THREAD_MGR != 0 } #endif diff --git a/core/shared/platform/android/platform_init.c b/core/shared/platform/android/platform_init.c index 5353308c1..04b1e1545 100644 --- a/core/shared/platform/android/platform_init.c +++ b/core/shared/platform/android/platform_init.c @@ -20,6 +20,9 @@ bh_platform_init() void bh_platform_destroy() { +#ifdef OS_ENABLE_HW_BOUND_CHECK + os_thread_destroy_stack_guard_pages(); +#endif } int os_printf(const char *fmt, ...) diff --git a/core/shared/platform/android/platform_internal.h b/core/shared/platform/android/platform_internal.h index b8b99f16a..73cbffac3 100644 --- a/core/shared/platform/android/platform_internal.h +++ b/core/shared/platform/android/platform_internal.h @@ -56,6 +56,8 @@ typedef pthread_mutex_t korp_mutex; typedef pthread_cond_t korp_cond; typedef pthread_t korp_thread; +#define os_thread_local_attribute __thread + #if WASM_DISABLE_HW_BOUND_CHECK == 0 #if defined(BUILD_TARGET_X86_64) \ || defined(BUILD_TARGET_AMD_64) \ @@ -65,8 +67,6 @@ typedef pthread_t korp_thread; #define OS_ENABLE_HW_BOUND_CHECK -#define os_thread_local_attribute __thread - typedef jmp_buf korp_jmpbuf; #define os_setjmp setjmp @@ -75,6 +75,10 @@ typedef jmp_buf korp_jmpbuf; #define os_getpagesize getpagesize +bool os_thread_init_stack_guard_pages(); + +void os_thread_destroy_stack_guard_pages(); + typedef void (*os_signal_handler)(void *sig_addr); int os_signal_init(os_signal_handler handler); diff --git a/core/shared/platform/common/posix/posix_thread.c b/core/shared/platform/common/posix/posix_thread.c index 3580eca74..54b52c839 100644 --- a/core/shared/platform/common/posix/posix_thread.c +++ b/core/shared/platform/common/posix/posix_thread.c @@ -25,6 +25,9 @@ static void *os_thread_wrapper(void *arg) targ->stack = (void *)((uintptr_t)(&arg) & (uintptr_t)~0xfff); BH_FREE(targ); start_func(thread_arg); +#ifdef OS_ENABLE_HW_BOUND_CHECK + os_thread_destroy_stack_guard_pages(); +#endif return NULL; } @@ -239,22 +242,32 @@ int os_thread_detach(korp_tid thread) void os_thread_exit(void *retval) { +#ifdef OS_ENABLE_HW_BOUND_CHECK + os_thread_destroy_stack_guard_pages(); +#endif return pthread_exit(retval); } +static os_thread_local_attribute uint8 *thread_stack_boundary = NULL; + uint8 *os_thread_get_stack_boundary() { - pthread_t self = pthread_self(); + pthread_t self; #ifdef __linux__ pthread_attr_t attr; size_t guard_size; #endif uint8 *addr = NULL; - size_t stack_size; - int page_size = getpagesize(); - size_t max_stack_size = (size_t) - (APP_THREAD_STACK_SIZE_MAX + page_size - 1) - & ~(page_size - 1); + size_t stack_size, max_stack_size; + int page_size; + + if (thread_stack_boundary) + return thread_stack_boundary; + + page_size = getpagesize(); + self = pthread_self(); + max_stack_size = (size_t)(APP_THREAD_STACK_SIZE_MAX + page_size - 1) + & ~(page_size - 1); if (max_stack_size < APP_THREAD_STACK_SIZE_DEFAULT) max_stack_size = APP_THREAD_STACK_SIZE_DEFAULT; @@ -284,6 +297,7 @@ uint8 *os_thread_get_stack_boundary() } #endif + thread_stack_boundary = addr; return addr; } @@ -291,12 +305,71 @@ uint8 *os_thread_get_stack_boundary() #define SIG_ALT_STACK_SIZE (32 * 1024) +/* Whether the stack pages are touched and guard pages are set */ +static os_thread_local_attribute bool stack_guard_pages_inited = false; + /* The signal alternate stack base addr */ static uint8 *sigalt_stack_base_addr; /* The signal handler passed to os_signal_init() */ static os_signal_handler signal_handler; +#if defined(__GNUC__) +__attribute__((no_sanitize_address)) static uint32 +#else +static uint32 +#endif +touch_pages(uint8 *stack_min_addr, uint32 page_size) +{ + uint8 sum = 0; + while (1) { + volatile uint8 *touch_addr = + (volatile uint8*)os_alloca(page_size / 2); + if (touch_addr < stack_min_addr + page_size) { + sum += *(stack_min_addr + page_size - 1); + break; + } + *touch_addr = 0; + sum += *touch_addr; + } + return sum; +} + +bool +os_thread_init_stack_guard_pages() +{ + uint32 page_size = os_getpagesize(); + uint32 guard_page_count = STACK_OVERFLOW_CHECK_GUARD_PAGE_COUNT; + uint8 *stack_min_addr = os_thread_get_stack_boundary(); + + if (!stack_guard_pages_inited) { + /* Touch each stack page to ensure that it has been mapped: the OS + may lazily grow the stack mapping as a guard page is hit. */ + (void)touch_pages(stack_min_addr, page_size); + /* First time to call aot function, protect guard pages */ + if (os_mprotect(stack_min_addr, page_size * guard_page_count, + MMAP_PROT_NONE) != 0) { + return false; + } + stack_guard_pages_inited = true; + } + return true; +} + +void +os_thread_destroy_stack_guard_pages() +{ + if (stack_guard_pages_inited) { + uint32 page_size = os_getpagesize(); + uint32 guard_page_count = STACK_OVERFLOW_CHECK_GUARD_PAGE_COUNT; + uint8 *stack_min_addr = os_thread_get_stack_boundary(); + + os_mprotect(stack_min_addr, page_size * guard_page_count, + MMAP_PROT_READ | MMAP_PROT_WRITE); + stack_guard_pages_inited = false; + } +} + static void mask_signals(int how) { diff --git a/core/shared/platform/darwin/platform_init.c b/core/shared/platform/darwin/platform_init.c index 17aeb8baa..23cd00604 100644 --- a/core/shared/platform/darwin/platform_init.c +++ b/core/shared/platform/darwin/platform_init.c @@ -14,6 +14,9 @@ bh_platform_init() void bh_platform_destroy() { +#ifdef OS_ENABLE_HW_BOUND_CHECK + os_thread_destroy_stack_guard_pages(); +#endif } int diff --git a/core/shared/platform/darwin/platform_internal.h b/core/shared/platform/darwin/platform_internal.h index 75348df15..66596b07f 100644 --- a/core/shared/platform/darwin/platform_internal.h +++ b/core/shared/platform/darwin/platform_internal.h @@ -57,6 +57,8 @@ typedef pthread_mutex_t korp_mutex; typedef pthread_cond_t korp_cond; typedef pthread_t korp_thread; +#define os_thread_local_attribute __thread + #if WASM_DISABLE_HW_BOUND_CHECK == 0 #if defined(BUILD_TARGET_X86_64) \ || defined(BUILD_TARGET_AMD_64) \ @@ -66,8 +68,6 @@ typedef pthread_t korp_thread; #define OS_ENABLE_HW_BOUND_CHECK -#define os_thread_local_attribute __thread - typedef jmp_buf korp_jmpbuf; #define os_setjmp setjmp @@ -76,6 +76,10 @@ typedef jmp_buf korp_jmpbuf; #define os_getpagesize getpagesize +bool os_thread_init_stack_guard_pages(); + +void os_thread_destroy_stack_guard_pages(); + typedef void (*os_signal_handler)(void *sig_addr); int os_signal_init(os_signal_handler handler); diff --git a/core/shared/platform/linux/platform_init.c b/core/shared/platform/linux/platform_init.c index 17aeb8baa..23cd00604 100644 --- a/core/shared/platform/linux/platform_init.c +++ b/core/shared/platform/linux/platform_init.c @@ -14,6 +14,9 @@ bh_platform_init() void bh_platform_destroy() { +#ifdef OS_ENABLE_HW_BOUND_CHECK + os_thread_destroy_stack_guard_pages(); +#endif } int diff --git a/core/shared/platform/linux/platform_internal.h b/core/shared/platform/linux/platform_internal.h index 7a15f85e6..0154bdf5d 100644 --- a/core/shared/platform/linux/platform_internal.h +++ b/core/shared/platform/linux/platform_internal.h @@ -56,6 +56,8 @@ typedef pthread_mutex_t korp_mutex; typedef pthread_cond_t korp_cond; typedef pthread_t korp_thread; +#define os_thread_local_attribute __thread + #if WASM_DISABLE_HW_BOUND_CHECK == 0 #if defined(BUILD_TARGET_X86_64) \ || defined(BUILD_TARGET_AMD_64) \ @@ -65,8 +67,6 @@ typedef pthread_t korp_thread; #define OS_ENABLE_HW_BOUND_CHECK -#define os_thread_local_attribute __thread - typedef jmp_buf korp_jmpbuf; #define os_setjmp setjmp @@ -75,6 +75,10 @@ typedef jmp_buf korp_jmpbuf; #define os_getpagesize getpagesize +bool os_thread_init_stack_guard_pages(); + +void os_thread_destroy_stack_guard_pages(); + typedef void (*os_signal_handler)(void *sig_addr); int os_signal_init(os_signal_handler handler); diff --git a/core/shared/platform/vxworks/platform_init.c b/core/shared/platform/vxworks/platform_init.c index 17aeb8baa..23cd00604 100644 --- a/core/shared/platform/vxworks/platform_init.c +++ b/core/shared/platform/vxworks/platform_init.c @@ -14,6 +14,9 @@ bh_platform_init() void bh_platform_destroy() { +#ifdef OS_ENABLE_HW_BOUND_CHECK + os_thread_destroy_stack_guard_pages(); +#endif } int diff --git a/core/shared/platform/vxworks/platform_internal.h b/core/shared/platform/vxworks/platform_internal.h index a8479361e..254ad68a6 100644 --- a/core/shared/platform/vxworks/platform_internal.h +++ b/core/shared/platform/vxworks/platform_internal.h @@ -55,6 +55,8 @@ typedef pthread_mutex_t korp_mutex; typedef pthread_cond_t korp_cond; typedef pthread_t korp_thread; +#define os_thread_local_attribute __thread + #if WASM_DISABLE_HW_BOUND_CHECK == 0 #if defined(BUILD_TARGET_X86_64) \ || defined(BUILD_TARGET_AMD_64) \ @@ -64,8 +66,6 @@ typedef pthread_t korp_thread; #define OS_ENABLE_HW_BOUND_CHECK -#define os_thread_local_attribute __thread - typedef jmp_buf korp_jmpbuf; #define os_setjmp setjmp @@ -74,6 +74,10 @@ typedef jmp_buf korp_jmpbuf; #define os_getpagesize getpagesize +bool os_thread_init_stack_guard_pages(); + +void os_thread_destroy_stack_guard_pages(); + typedef void (*os_signal_handler)(void *sig_addr); int os_signal_init(os_signal_handler handler); diff --git a/core/shared/platform/zephyr/zephyr_time.c b/core/shared/platform/zephyr/zephyr_time.c index b6c03f586..6a9db0806 100644 --- a/core/shared/platform/zephyr/zephyr_time.c +++ b/core/shared/platform/zephyr/zephyr_time.c @@ -8,6 +8,6 @@ uint64 os_time_get_boot_microsecond() { - return k_uptime_get_32() * 1000; + return k_uptime_get() * 1000; } From a332a49a0dfcbb0acf2c71bfddbdd67f1f5bf0d5 Mon Sep 17 00:00:00 2001 From: Bao Haojun Date: Sun, 25 Apr 2021 19:12:49 +0800 Subject: [PATCH 186/207] Enable sample/simple for aarch64 (#616) Fixed a typo in aot_reloc_aarch64.c. Remove -m32 option in host tool CMakeLists.txt and change data type of structure fields to make host tool work in 64-bit. Signed-off-by: Bao Haojun --- core/iwasm/aot/arch/aot_reloc_aarch64.c | 3 +- .../simple/profiles/arm64-aot/toolchain.cmake | 36 +++++++++++++++++++ .../arm64-aot/wamr_config_simple.cmake | 10 ++++++ .../profiles/arm64-interp/toolchain.cmake | 36 +++++++++++++++++++ .../arm64-interp/wamr_config_simple.cmake | 10 ++++++ test-tools/host-tool/CMakeLists.txt | 5 --- test-tools/host-tool/src/transport.h | 2 +- 7 files changed, 94 insertions(+), 8 deletions(-) create mode 100644 samples/simple/profiles/arm64-aot/toolchain.cmake create mode 100644 samples/simple/profiles/arm64-aot/wamr_config_simple.cmake create mode 100644 samples/simple/profiles/arm64-interp/toolchain.cmake create mode 100644 samples/simple/profiles/arm64-interp/wamr_config_simple.cmake diff --git a/core/iwasm/aot/arch/aot_reloc_aarch64.c b/core/iwasm/aot/arch/aot_reloc_aarch64.c index 86ca6c696..91848086a 100644 --- a/core/iwasm/aot/arch/aot_reloc_aarch64.c +++ b/core/iwasm/aot/arch/aot_reloc_aarch64.c @@ -60,7 +60,7 @@ get_current_target(char *target_buf, uint32 target_buf_size) char *d = target_buf; /* Set to "aarch64v8" by default if sub version isn't specified */ - if (strcmp(s, "AARACH64") == 0) { + if (strcmp(s, "AARCH64") == 0) { s = BUILD_TARGET_AARCH64_DEFAULT; s_size = sizeof(BUILD_TARGET_AARCH64_DEFAULT); } @@ -385,4 +385,3 @@ overflow_check_fail: "target address out of range."); return false; } - diff --git a/samples/simple/profiles/arm64-aot/toolchain.cmake b/samples/simple/profiles/arm64-aot/toolchain.cmake new file mode 100644 index 000000000..6d674ce70 --- /dev/null +++ b/samples/simple/profiles/arm64-aot/toolchain.cmake @@ -0,0 +1,36 @@ +INCLUDE(CMakeForceCompiler) + +SET(CMAKE_SYSTEM_NAME Linux) # this one is important +SET(CMAKE_SYSTEM_VERSION 1) # this one not so much + +message(STATUS "*** ARM A7 toolchain file ***") +set(CMAKE_VERBOSE_MAKEFILE ON) + +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_GNU_SOURCE") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_GNU_SOURCE") + + +if (NOT $ENV{ARM_A7_COMPILER_DIR} STREQUAL "") + SET (toolchain_sdk_dir $ENV{ARM_A7_COMPILER_DIR}/) +endif () + +if (NOT $ENV{ARM_A7_SDKTARGETSYSROOT} STREQUAL "") + SET(SDKTARGETSYSROOT $ENV{ARM_A7_SDKTARGETSYSROOT}) +endif () + +message(STATUS "SDKTARGETSYSROOT=${SDKTARGETSYSROOT}") +message(STATUS "toolchain_sdk_dir=${toolchain_sdk_dir}") + +SET(CMAKE_C_COMPILER ${toolchain_sdk_dir}aarch64-linux-gnu-gcc) +SET(CMAKE_CXX_COMPILER ${toolchain_sdk_dir}aarch64-linux-gnu-g++) + + +# this is the file system root of the target +SET(CMAKE_FIND_ROOT_PATH ${SDKTARGETSYSROOT}) + +# search for programs in the build host directories +SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + +# for libraries and headers in the target directories +SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) diff --git a/samples/simple/profiles/arm64-aot/wamr_config_simple.cmake b/samples/simple/profiles/arm64-aot/wamr_config_simple.cmake new file mode 100644 index 000000000..81d8103ea --- /dev/null +++ b/samples/simple/profiles/arm64-aot/wamr_config_simple.cmake @@ -0,0 +1,10 @@ +set (WAMR_BUILD_PLATFORM "linux") +set (WAMR_BUILD_TARGET AARCH64) +set (WAMR_BUILD_INTERP 1) +set (WAMR_BUILD_AOT 1) +set (WAMR_BUILD_JIT 0) +set (WAMR_BUILD_SIMD 0) +set (WAMR_BUILD_LIBC_BUILTIN 1) +set (WAMR_BUILD_LIBC_WASI 0) +set (WAMR_BUILD_APP_FRAMEWORK 1) +set (WAMR_BUILD_APP_LIST WAMR_APP_BUILD_BASE WAMR_APP_BUILD_CONNECTION WAMR_APP_BUILD_SENSOR) diff --git a/samples/simple/profiles/arm64-interp/toolchain.cmake b/samples/simple/profiles/arm64-interp/toolchain.cmake new file mode 100644 index 000000000..6d674ce70 --- /dev/null +++ b/samples/simple/profiles/arm64-interp/toolchain.cmake @@ -0,0 +1,36 @@ +INCLUDE(CMakeForceCompiler) + +SET(CMAKE_SYSTEM_NAME Linux) # this one is important +SET(CMAKE_SYSTEM_VERSION 1) # this one not so much + +message(STATUS "*** ARM A7 toolchain file ***") +set(CMAKE_VERBOSE_MAKEFILE ON) + +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_GNU_SOURCE") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_GNU_SOURCE") + + +if (NOT $ENV{ARM_A7_COMPILER_DIR} STREQUAL "") + SET (toolchain_sdk_dir $ENV{ARM_A7_COMPILER_DIR}/) +endif () + +if (NOT $ENV{ARM_A7_SDKTARGETSYSROOT} STREQUAL "") + SET(SDKTARGETSYSROOT $ENV{ARM_A7_SDKTARGETSYSROOT}) +endif () + +message(STATUS "SDKTARGETSYSROOT=${SDKTARGETSYSROOT}") +message(STATUS "toolchain_sdk_dir=${toolchain_sdk_dir}") + +SET(CMAKE_C_COMPILER ${toolchain_sdk_dir}aarch64-linux-gnu-gcc) +SET(CMAKE_CXX_COMPILER ${toolchain_sdk_dir}aarch64-linux-gnu-g++) + + +# this is the file system root of the target +SET(CMAKE_FIND_ROOT_PATH ${SDKTARGETSYSROOT}) + +# search for programs in the build host directories +SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + +# for libraries and headers in the target directories +SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) diff --git a/samples/simple/profiles/arm64-interp/wamr_config_simple.cmake b/samples/simple/profiles/arm64-interp/wamr_config_simple.cmake new file mode 100644 index 000000000..804e71cba --- /dev/null +++ b/samples/simple/profiles/arm64-interp/wamr_config_simple.cmake @@ -0,0 +1,10 @@ +set (WAMR_BUILD_PLATFORM "linux") +set (WAMR_BUILD_TARGET AARCH64) +set (WAMR_BUILD_INTERP 1) +set (WAMR_BUILD_AOT 0) +set (WAMR_BUILD_JIT 0) +set (WAMR_BUILD_SIMD 0) +set (WAMR_BUILD_LIBC_BUILTIN 1) +set (WAMR_BUILD_LIBC_WASI 0) +set (WAMR_BUILD_APP_FRAMEWORK 1) +set (WAMR_BUILD_APP_LIST WAMR_APP_BUILD_BASE WAMR_APP_BUILD_CONNECTION WAMR_APP_BUILD_SENSOR) diff --git a/test-tools/host-tool/CMakeLists.txt b/test-tools/host-tool/CMakeLists.txt index 660c9a13e..9aedf7e63 100644 --- a/test-tools/host-tool/CMakeLists.txt +++ b/test-tools/host-tool/CMakeLists.txt @@ -34,11 +34,6 @@ include (${SHARED_DIR}/mem-alloc/mem_alloc.cmake) include (${CJSON_DIR}/cjson.cmake) include (${SHARED_DIR}/coap/lib_coap.cmake) -if (CMAKE_SIZEOF_VOID_P EQUAL 8) - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m32") - SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32") -endif () - add_definitions(-Wall -Wno-pointer-sign) include_directories( diff --git a/test-tools/host-tool/src/transport.h b/test-tools/host-tool/src/transport.h index 2d98c126b..ea180cf13 100644 --- a/test-tools/host-tool/src/transport.h +++ b/test-tools/host-tool/src/transport.h @@ -13,7 +13,7 @@ extern "C" { /* IMRT link message between host and WAMR */ typedef struct { unsigned short message_type; - unsigned long payload_size; + unsigned int payload_size; char *payload; } imrt_link_message_t; From eb29385963dade4ab845e1cdd7d0a523bd74e16d Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Tue, 27 Apr 2021 17:05:40 +0800 Subject: [PATCH 187/207] Implement more wasm-c-apis and enable Envoy integration (#622) Implement more wasm-c-api APIs to support Envoy integration: - sync up with latest c-api definition - change CMakeLists to export necessary headers and install the static library of iwasm - enable to export tables and memories - support memorytype and tabletype APIs - update wasm-c-api sampels - enable to export importtype APIs And refine bazel scripts for sample XNNPACK workload, add license headers for sample simple. Signed-off-by: Wenyong Huang --- CMakeLists.txt | 140 + core/iwasm/aot/aot_runtime.c | 27 +- core/iwasm/common/wasm_c_api.c | 2521 +++++++++++------ core/iwasm/common/wasm_c_api_internal.h | 27 +- core/iwasm/common/wasm_runtime_common.c | 247 +- core/iwasm/common/wasm_runtime_common.h | 32 + core/iwasm/include/wasm_c_api.h | 108 +- core/iwasm/interpreter/wasm_interp_classic.c | 10 - core/iwasm/interpreter/wasm_loader.c | 7 +- .../profiles/arm-interp/toolchain.cmake | 2 + .../arm-interp/wamr_config_simple.cmake | 2 + .../simple/profiles/arm64-aot/toolchain.cmake | 2 + .../arm64-aot/wamr_config_simple.cmake | 2 + .../profiles/arm64-interp/toolchain.cmake | 2 + .../arm64-interp/wamr_config_simple.cmake | 2 + .../host-aot/wamr_config_simple.cmake | 2 + .../host-interp/wamr_config_simple.cmake | 2 + samples/simple/src/iwasm_main.c | 4 + samples/simple/src/main.c | 5 + samples/wasm-c-api/CMakeLists.txt | 64 +- samples/wasm-c-api/src/LICENSE | 202 ++ samples/wasm-c-api/src/callback.c | 22 +- samples/wasm-c-api/src/global.c | 38 +- samples/wasm-c-api/src/hello.c | 39 +- samples/wasm-c-api/src/multi.c | 153 + samples/wasm-c-api/src/multi.wat | 7 + samples/wasm-c-api/src/reflect.c | 170 ++ samples/wasm-c-api/src/reflect.wat | 6 + samples/wasm-c-api/src/trap.c | 124 + samples/wasm-c-api/src/trap.wat | 5 + samples/workload/XNNPACK/CMakeLists.txt | 133 +- .../workload/XNNPACK/toolchain/BUILD.bazel | 30 - .../toolchain/emscripten_toolchain_config.bzl | 142 - samples/workload/XNNPACK/xnnpack.patch | 805 +----- samples/workload/docker/Dockerfile | 15 +- samples/workload/docker/docker_build.sh | 30 +- 36 files changed, 3190 insertions(+), 1939 deletions(-) create mode 100644 CMakeLists.txt create mode 100644 samples/wasm-c-api/src/LICENSE create mode 100644 samples/wasm-c-api/src/multi.c create mode 100644 samples/wasm-c-api/src/multi.wat create mode 100644 samples/wasm-c-api/src/reflect.c create mode 100644 samples/wasm-c-api/src/reflect.wat create mode 100644 samples/wasm-c-api/src/trap.c create mode 100644 samples/wasm-c-api/src/trap.wat delete mode 100644 samples/workload/XNNPACK/toolchain/BUILD.bazel delete mode 100644 samples/workload/XNNPACK/toolchain/emscripten_toolchain_config.bzl diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000..c3e4a1eae --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,140 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required (VERSION 2.8) + +project (iwasm) +# set (CMAKE_VERBOSE_MAKEFILE 1) + +set (WAMR_BUILD_PLATFORM "linux") + +# Reset default linker flags +set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") +set (CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") + +set (CMAKE_C_STANDARD 99) + +# Set WAMR_BUILD_TARGET, currently values supported: +# "X86_64", "AMD_64", "X86_32", "AARCH64[sub]", "ARM[sub]", "THUMB[sub]", +# "MIPS", "XTENSA", "RISCV64[sub]", "RISCV32[sub]" +if (NOT DEFINED WAMR_BUILD_TARGET) + if (CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") + set (WAMR_BUILD_TARGET "AARCH64") + elseif (CMAKE_SYSTEM_PROCESSOR STREQUAL "riscv64") + set (WAMR_BUILD_TARGET "RISCV64") + elseif (CMAKE_SIZEOF_VOID_P EQUAL 8) + # Build as X86_64 by default in 64-bit platform + set (WAMR_BUILD_TARGET "X86_64") + else () + # Build as X86_32 by default in 32-bit platform + set (WAMR_BUILD_TARGET "X86_32") + endif () +endif () + +if (NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Release) +endif () + +if (NOT DEFINED WAMR_BUILD_INTERP) + # Enable Interpreter by default + set (WAMR_BUILD_INTERP 1) +endif () + +if (NOT DEFINED WAMR_BUILD_AOT) + # Enable AOT by default. + set (WAMR_BUILD_AOT 1) +endif () + +if (NOT DEFINED WAMR_BUILD_JIT) + # Disable JIT by default. + set (WAMR_BUILD_JIT 0) +endif () + +if (NOT DEFINED WAMR_BUILD_LIBC_BUILTIN) + # Enable libc builtin support by default + set (WAMR_BUILD_LIBC_BUILTIN 1) +endif () + +if (NOT DEFINED WAMR_BUILD_LIBC_WASI) + # Enable libc wasi support by default + set (WAMR_BUILD_LIBC_WASI 1) +endif () + +if (NOT DEFINED WAMR_BUILD_FAST_INTERP) + # Enable fast interpreter + set (WAMR_BUILD_FAST_INTERP 1) +endif () + +if (NOT DEFINED WAMR_BUILD_MULTI_MODULE) + # Enable multiple modules + set (WAMR_BUILD_MULTI_MODULE 0) +endif () + +if (NOT DEFINED WAMR_BUILD_LIB_PTHREAD) + # Disable pthread library by default + set (WAMR_BUILD_LIB_PTHREAD 0) +endif () + +if (NOT DEFINED WAMR_BUILD_MINI_LOADER) + # Disable wasm mini loader by default + set (WAMR_BUILD_MINI_LOADER 0) +endif () + +if (NOT DEFINED WAMR_BUILD_SIMD) + # Enable SIMD by default + set (WAMR_BUILD_SIMD 1) +endif () + +if (NOT DEFINED WAMR_BUILD_REF_TYPES) + # Disable reference types by default + set (WAMR_BUILD_REF_TYPES 0) +endif () + +if (COLLECT_CODE_COVERAGE EQUAL 1) + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage") +endif () + +set (WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}) + +include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) +add_library(vmlib ${WAMR_RUNTIME_LIB_SOURCE}) + +set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections -pie -fPIE") + +set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat -Wformat-security") +# set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wconversion -Wsign-conversion") + +if (WAMR_BUILD_TARGET MATCHES "X86_.*" OR WAMR_BUILD_TARGET STREQUAL "AMD_64") + if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang")) + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mindirect-branch-register") + endif () +endif () + +# The following flags are to enhance security, but it may impact performance, +# we disable them by default. +#if (WAMR_BUILD_TARGET MATCHES "X86_.*" OR WAMR_BUILD_TARGET STREQUAL "AMD_64") +# set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ftrapv -D_FORTIFY_SOURCE=2") +#endif () +#set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fstack-protector-strong --param ssp-buffer-size=4") +#set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wl,-z,noexecstack,-z,relro,-z,now") + +include (${SHARED_DIR}/utils/uncommon/shared_uncommon.cmake) + +# STATIC LIBRARY +add_library(iwasm_static STATIC ${WAMR_RUNTIME_LIB_SOURCE}) +set_target_properties (iwasm_static PROPERTIES OUTPUT_NAME vmlib) + +install (TARGETS iwasm_static ARCHIVE DESTINATION lib) + +# SHARED LIBRARY +add_library (iwasm_shared SHARED ${WAMR_RUNTIME_LIB_SOURCE}) +set_target_properties (iwasm_shared PROPERTIES OUTPUT_NAME iwasm) +target_link_libraries (iwasm_shared ${LLVM_AVAILABLE_LIBS} ${UV_A_LIBS} -lm -ldl -lpthread) + +install (TARGETS iwasm_shared LIBRARY DESTINATION lib) + +# HEADERS +install (FILES + ${WAMR_ROOT_DIR}/core/iwasm/include/wasm_c_api.h + ${WAMR_ROOT_DIR}/core/iwasm/include/wasm_export.h + DESTINATION include) diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index 0657804e6..c23388975 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -784,11 +784,6 @@ create_export_funcs(AOTModuleInstance *module_inst, AOTModule *module, uint64 size; uint32 i, func_index, ftype_index; - for (i = 0; i < module->export_count; i++) { - if (exports[i].kind == EXPORT_KIND_FUNC) - module_inst->export_func_count++; - } - if (module_inst->export_func_count > 0) { /* Allocate memory */ size = sizeof(AOTFunctionInstance) @@ -829,6 +824,28 @@ static bool create_exports(AOTModuleInstance *module_inst, AOTModule *module, char *error_buf, uint32 error_buf_size) { + AOTExport *exports = module->exports; + uint32 i; + + for (i = 0; i < module->export_count; i++) { + switch (exports[i].kind) { + case EXPORT_KIND_FUNC: + module_inst->export_func_count++; + break; + case EXPORT_KIND_GLOBAL: + module_inst->export_global_count++; + break; + case EXPORT_KIND_TABLE: + module_inst->export_tab_count++; + break; + case EXPORT_KIND_MEMORY: + module_inst->export_mem_count++; + break; + default: + return false; + } + } + return create_export_funcs(module_inst, module, error_buf, error_buf_size); } diff --git a/core/iwasm/common/wasm_c_api.c b/core/iwasm/common/wasm_c_api.c index 5087c30b6..4e883153f 100644 --- a/core/iwasm/common/wasm_c_api.c +++ b/core/iwasm/common/wasm_c_api.c @@ -12,27 +12,47 @@ #include "aot_runtime.h" #endif -#define NOT_REACHED() bh_assert(!"should not be reached") +#define ASSERT_NOT_IMPLEMENTED() bh_assert(!"not implemented") typedef struct wasm_module_ex_t wasm_module_ex_t; -void +static void wasm_module_delete_internal(wasm_module_t *); -void +static void wasm_instance_delete_internal(wasm_instance_t *); +/* temporarily put stubs here */ +static wasm_store_t * +wasm_store_copy(const wasm_store_t *src) +{ + (void)src; + LOG_WARNING("in the stub of %s", __FUNCTION__); + return NULL; +} + +wasm_module_t * +wasm_module_copy(const wasm_module_t *src) +{ + (void)src; + LOG_WARNING("in the stub of %s", __FUNCTION__); + return NULL; +} + +wasm_instance_t * +wasm_instance_copy(const wasm_instance_t *src) +{ + (void)src; + LOG_WARNING("in the stub of %s", __FUNCTION__); + return NULL; +} + static void * malloc_internal(uint64 size) { void *mem = NULL; - if (size >= UINT32_MAX) { - return NULL; - } - - mem = wasm_runtime_malloc((uint32)size); - if (mem) { + if (size < UINT32_MAX && (mem = wasm_runtime_malloc((uint32)size))) { memset(mem, 0, size); } @@ -44,109 +64,170 @@ malloc_internal(uint64 size) wasm_runtime_free(p); \ } +/* clang-format off */ +#define RETURN_OBJ(obj, obj_del_func) \ + return obj; \ +failed: \ + obj_del_func(obj); \ + return NULL; + +#define RETURN_VOID(obj, obj_del_func) \ + return; \ +failed: \ + obj_del_func(obj); \ + return; +/* clang-format on */ + /* Vectors */ -#define INIT_VEC(vector_p, func_prefix, size) \ +#define INIT_VEC(vector_p, init_func, ...) \ do { \ if (!(vector_p = malloc_internal(sizeof(*(vector_p))))) { \ goto failed; \ } \ - func_prefix##_new_uninitialized(vector_p, size); \ - if (!(vector_p)->data) { \ + \ + init_func(vector_p, ##__VA_ARGS__); \ + if (vector_p->size && !vector_p->data) { \ + LOG_DEBUG("%s failed", #init_func); \ goto failed; \ } \ } while (false) -#define DEINIT_VEC(vector_p, delete_func) \ +#define DEINIT_VEC(vector_p, deinit_func) \ if ((vector_p)) { \ - if ((vector_p)->data) { \ - delete_func(vector_p); \ - } \ + deinit_func(vector_p); \ wasm_runtime_free(vector_p); \ vector_p = NULL; \ } -#define FREE_VEC_ELEMS(vec, del_func) \ - for (i = 0; i < (vec)->num_elems; ++i) { \ - del_func(*((vec)->data + i)); \ - *((vec)->data + i) = NULL; \ +#define WASM_DEFINE_VEC(name) \ + void wasm_##name##_vec_new_empty(own wasm_##name##_vec_t *out) \ + { \ + wasm_##name##_vec_new_uninitialized(out, 0); \ + } \ + void wasm_##name##_vec_new_uninitialized(own wasm_##name##_vec_t *out, \ + size_t size) \ + { \ + wasm_##name##_vec_new(out, size, NULL); \ } -static inline void -generic_vec_init_data(Vector *out, size_t num_of_elems, size_t size_of_elem) -{ - /* size 0 is meaningless for a elemment */ - if (!size_of_elem || !bh_vector_init(out, num_of_elems, size_of_elem)) { - out->data = NULL; - out->max_elems = 0; - out->num_elems = 0; - } - else { - memset(out->data, 0, num_of_elems * size_of_elem); - } -} - -void -wasm_byte_vec_new_uninitialized(wasm_byte_vec_t *out, size_t size) -{ - bh_assert(out); - generic_vec_init_data((Vector *)out, size, sizeof(wasm_byte_t)); -} - -void -wasm_byte_vec_copy(wasm_byte_vec_t *out, const wasm_byte_vec_t *src) -{ - uint32 len = 0; - - bh_assert(out && src); - - generic_vec_init_data((Vector *)out, src->size, sizeof(wasm_byte_t)); - if (!out->data) { - goto failed; +/* vectors with no ownership management of elements */ +#define WASM_DEFINE_VEC_PLAIN(name) \ + WASM_DEFINE_VEC(name) \ + void wasm_##name##_vec_new(own wasm_##name##_vec_t *out, size_t size, \ + own wasm_##name##_t const data[]) \ + { \ + bh_assert(out); \ + \ + memset(out, 0, sizeof(wasm_##name##_vec_t)); \ + \ + if (!size) { \ + return; \ + } \ + \ + if (!bh_vector_init((Vector *)out, size, sizeof(wasm_##name##_t))) { \ + LOG_DEBUG("bh_vector_init failed"); \ + goto failed; \ + } \ + \ + if (data) { \ + unsigned int size_in_bytes = 0; \ + size_in_bytes = size * sizeof(wasm_##name##_t); \ + bh_memcpy_s(out->data, size_in_bytes, data, size_in_bytes); \ + out->num_elems = size; \ + } \ + \ + RETURN_VOID(out, wasm_##name##_vec_delete) \ + } \ + void wasm_##name##_vec_copy(wasm_##name##_vec_t *out, \ + const wasm_##name##_vec_t *src) \ + { \ + wasm_##name##_vec_new(out, src->size, src->data); \ + } \ + void wasm_##name##_vec_delete(wasm_##name##_vec_t *v) \ + { \ + if (v) { \ + bh_vector_destroy((Vector *)v); \ + } \ } - /* integer overflow has been checked in generic_vec_init_data, - no need to check again */ - len = (uint32)(src->size * src->size_of_elem); - bh_memcpy_s(out->data, len, src->data, len); - out->num_elems = src->num_elems; - return; - -failed: - LOG_DEBUG("%s failed", __FUNCTION__); - wasm_byte_vec_delete(out); -} - -void -wasm_byte_vec_new(wasm_byte_vec_t *out, size_t size, const wasm_byte_t *data) -{ - uint32 size_in_bytes = 0; - - bh_assert(out && data); - - generic_vec_init_data((Vector *)out, size, sizeof(wasm_byte_t)); - if (!out->data) { - goto failed; +/* vectors that own their elements */ +#define WASM_DEFINE_VEC_OWN(name, elem_destroy_func) \ + WASM_DEFINE_VEC(name) \ + void wasm_##name##_vec_new(own wasm_##name##_vec_t *out, size_t size, \ + own wasm_##name##_t *const data[]) \ + { \ + bh_assert(out); \ + \ + memset(out, 0, sizeof(wasm_##name##_vec_t)); \ + \ + if (!size) { \ + return; \ + } \ + \ + if (!bh_vector_init((Vector *)out, size, \ + sizeof(wasm_##name##_t *))) { \ + LOG_DEBUG("bh_vector_init failed"); \ + goto failed; \ + } \ + \ + if (data) { \ + unsigned int size_in_bytes = 0; \ + size_in_bytes = size * sizeof(wasm_##name##_t *); \ + bh_memcpy_s(out->data, size_in_bytes, data, size_in_bytes); \ + out->num_elems = size; \ + } \ + \ + RETURN_VOID(out, wasm_##name##_vec_delete) \ + } \ + void wasm_##name##_vec_copy(own wasm_##name##_vec_t *out, \ + const wasm_##name##_vec_t *src) \ + { \ + size_t i = 0; \ + memset(out, 0, sizeof(Vector)); \ + \ + if (!src->size) { \ + return; \ + } \ + \ + if (!bh_vector_init((Vector *)out, src->size, \ + sizeof(wasm_##name##_t *))) { \ + LOG_DEBUG("bh_vector_init failed"); \ + goto failed; \ + } \ + \ + for (i = 0; i != src->num_elems; ++i) { \ + if (!(out->data[i] = wasm_##name##_copy(src->data[i]))) { \ + LOG_DEBUG("wasm_%s_copy failed", #name); \ + goto failed; \ + } \ + } \ + out->num_elems = src->num_elems; \ + \ + RETURN_VOID(out, wasm_##name##_vec_delete) \ + } \ + void wasm_##name##_vec_delete(wasm_##name##_vec_t *v) \ + { \ + size_t i = 0; \ + if (!v) { \ + return; \ + } \ + for (i = 0; i != v->num_elems; ++i) { \ + elem_destroy_func(*(v->data + i)); \ + } \ + bh_vector_destroy((Vector *)v); \ } - /* integer overflow has been checked in generic_vec_init_data, - no need to check again */ - size_in_bytes = (uint32)(size * sizeof(wasm_byte_t)); - bh_memcpy_s(out->data, size_in_bytes, data, size_in_bytes); - out->num_elems = size; - return; +WASM_DEFINE_VEC_PLAIN(byte) +WASM_DEFINE_VEC_PLAIN(val) -failed: - LOG_DEBUG("%s failed", __FUNCTION__); - wasm_byte_vec_delete(out); -} - -void -wasm_byte_vec_delete(wasm_byte_vec_t *byte_vec) -{ - if (byte_vec && byte_vec->data) { - bh_vector_destroy((Vector *)byte_vec); - } -} +WASM_DEFINE_VEC_OWN(valtype, wasm_valtype_delete) +WASM_DEFINE_VEC_OWN(functype, wasm_functype_delete) +WASM_DEFINE_VEC_OWN(exporttype, wasm_exporttype_delete) +WASM_DEFINE_VEC_OWN(importtype, wasm_importtype_delete) +WASM_DEFINE_VEC_OWN(store, wasm_store_delete) +WASM_DEFINE_VEC_OWN(module, wasm_module_delete_internal) +WASM_DEFINE_VEC_OWN(instance, wasm_instance_delete_internal) +WASM_DEFINE_VEC_OWN(extern, wasm_extern_delete) /* Runtime Environment */ static void @@ -161,9 +242,7 @@ wasm_engine_delete_internal(wasm_engine_t *engine) } static wasm_engine_t * -wasm_engine_new_internal(mem_alloc_type_t type, - const MemAllocOption *opts, - runtime_mode_e mode) +wasm_engine_new_internal(mem_alloc_type_t type, const MemAllocOption *opts) { wasm_engine_t *engine = NULL; /* init runtime */ @@ -188,6 +267,7 @@ wasm_engine_new_internal(mem_alloc_type_t type, } if (!wasm_runtime_full_init(&init_args)) { + LOG_DEBUG("wasm_runtime_full_init failed"); goto failed; } @@ -198,73 +278,52 @@ wasm_engine_new_internal(mem_alloc_type_t type, #endif /* create wasm_engine_t */ - engine = malloc_internal(sizeof(wasm_engine_t)); - if (!engine) { + if (!(engine = malloc_internal(sizeof(wasm_engine_t)))) { goto failed; } - /* set running mode */ - LOG_WARNING("running under mode %d", mode); - engine->mode = mode; - /* create wasm_store_vec_t */ - INIT_VEC(engine->stores, wasm_store_vec, 1); + INIT_VEC(engine->stores, wasm_store_vec_new_uninitialized, 1); - return engine; - -failed: - LOG_DEBUG("%s failed", __FUNCTION__); - wasm_engine_delete_internal(engine); - return NULL; + RETURN_OBJ(engine, wasm_engine_delete_internal) } /* global engine instance */ static wasm_engine_t *singleton_engine = NULL; -static inline runtime_mode_e -current_runtime_mode() +static inline bool +run_with_bytecode_module(const wasm_module_t *module) { - bh_assert(singleton_engine); - return singleton_engine->mode; + return Wasm_Module_Bytecode == (*module)->module_type; +} + +static inline bool +run_with_bytecode_module_inst(const WASMModuleInstanceCommon *inst_comm_rt) +{ + return Wasm_Module_Bytecode == inst_comm_rt->module_type; } wasm_engine_t * wasm_engine_new() { - runtime_mode_e mode = INTERP_MODE; -#if WASM_ENABLE_INTERP == 0 && WASM_ENABLE_AOT != 0 - mode = AOT_MODE; -#endif - - if (INTERP_MODE == mode) { -#if WASM_ENABLE_INTERP == 0 - bh_assert(!"does not support INTERP_MODE. Please recompile"); -#endif - } - else { -#if WASM_ENABLE_AOT == 0 - bh_assert(!"does not support AOT_MODE. Please recompile"); -#endif - } - if (!singleton_engine) { singleton_engine = - wasm_engine_new_internal(Alloc_With_System_Allocator, NULL, mode); + wasm_engine_new_internal(Alloc_With_System_Allocator, NULL); } return singleton_engine; } wasm_engine_t * wasm_engine_new_with_args(mem_alloc_type_t type, - const MemAllocOption *opts, - runtime_mode_e mode) + const MemAllocOption *opts) { if (!singleton_engine) { - singleton_engine = wasm_engine_new_internal(type, opts, mode); + singleton_engine = wasm_engine_new_internal(type, opts); } return singleton_engine; } +/* BE AWARE: will RESET the singleton */ void wasm_engine_delete(wasm_engine_t *engine) { @@ -281,36 +340,24 @@ wasm_store_new(wasm_engine_t *engine) bh_assert(engine && singleton_engine == engine); - /* always return the first store */ - if (bh_vector_size((Vector *)singleton_engine->stores) > 0) { - /* - * although it is a copy of the first store, but still point to - * the wasm_store_t - */ - if (!bh_vector_get((Vector *)singleton_engine->stores, 0, &store)) { - goto failed; - } - return store; - } - - store = malloc_internal(sizeof(wasm_store_t)); - if (!store) { - goto failed; + if (!(store = malloc_internal(sizeof(wasm_store_t)))) { + return NULL; } /* new a vector, and new its data */ - INIT_VEC(store->modules, wasm_module_vec, DEFAULT_VECTOR_INIT_LENGTH); - INIT_VEC(store->instances, wasm_instance_vec, DEFAULT_VECTOR_INIT_LENGTH); + INIT_VEC(store->modules, wasm_module_vec_new_uninitialized, + DEFAULT_VECTOR_INIT_LENGTH); + INIT_VEC(store->instances, wasm_instance_vec_new_uninitialized, + DEFAULT_VECTOR_INIT_LENGTH); /* append to a store list of engine */ if (!bh_vector_append((Vector *)singleton_engine->stores, &store)) { + LOG_DEBUG("bh_vector_append failed"); goto failed; } return store; - failed: - LOG_DEBUG("%s failed", __FUNCTION__); wasm_store_delete(store); return NULL; } @@ -318,82 +365,91 @@ failed: void wasm_store_delete(wasm_store_t *store) { - if (!store || singleton_engine->stores->num_elems == 0) { + size_t i, store_count; + + if (!store) { return; } + /* remove it from the list in the engine */ + store_count = bh_vector_size((Vector *)singleton_engine->stores); + for (i = 0; i != store_count; ++i) { + wasm_store_t *tmp; + + if (!bh_vector_get((Vector *)singleton_engine->stores, i, &tmp)) { + break; + } + + if (tmp == store) { + bh_vector_remove((Vector *)singleton_engine->stores, i, NULL); + break; + } + } + DEINIT_VEC(store->modules, wasm_module_vec_delete); DEINIT_VEC(store->instances, wasm_instance_vec_delete); - wasm_runtime_free(store); - bh_vector_remove((Vector *)singleton_engine->stores, 0, NULL); -} - -void -wasm_store_vec_new_uninitialized(wasm_store_vec_t *out, size_t size) -{ - bh_assert(out); - generic_vec_init_data((Vector *)out, size, sizeof(wasm_store_t *)); -} - -void -wasm_store_vec_delete(wasm_store_vec_t *store_vec) -{ - size_t i = 0; - if (!store_vec || !store_vec->data) { - return; - } - - FREE_VEC_ELEMS(store_vec, wasm_store_delete); - bh_vector_destroy((Vector *)store_vec); } static inline void check_engine_and_store(wasm_engine_t *engine, wasm_store_t *store) { /* remove it if we are supporting more than one store */ - bh_assert(engine && store && engine->stores->data[0] == store); + bh_assert(engine && store); } /* Type Representations */ -static wasm_valtype_t * -wasm_valtype_new_internal(uint8 val_type_rt) +static wasm_valkind_t +val_type_rt_2_valkind(uint8 val_type_rt) { switch (val_type_rt) { case VALUE_TYPE_I32: - return wasm_valtype_new_i32(); + return WASM_I32; case VALUE_TYPE_I64: - return wasm_valtype_new_i64(); + return WASM_I64; case VALUE_TYPE_F32: - return wasm_valtype_new_f32(); + return WASM_F32; case VALUE_TYPE_F64: - return wasm_valtype_new_f64(); + return WASM_F64; case VALUE_TYPE_ANY: - return wasm_valtype_new_anyref(); + return WASM_ANYREF; + case VALUE_TYPE_FUNCREF: + return WASM_FUNCREF; default: - return NULL; + LOG_WARNING("%s meets unsupported type: %d", __FUNCTION__, + val_type_rt); + return WASM_ANYREF; } } +static wasm_valtype_t * +wasm_valtype_new_internal(uint8 val_type_rt) +{ + return wasm_valtype_new(val_type_rt_2_valkind(val_type_rt)); +} + wasm_valtype_t * wasm_valtype_new(wasm_valkind_t kind) { - wasm_valtype_t *val_type = malloc_internal(sizeof(wasm_valtype_t)); - if (val_type) { - val_type->kind = kind; + wasm_valtype_t *val_type; + + if (!(val_type = malloc_internal(sizeof(wasm_valtype_t)))) { + return NULL; } + + val_type->kind = kind; + return val_type; } void wasm_valtype_delete(wasm_valtype_t *val_type) { - bh_assert(val_type); - wasm_runtime_free(val_type); + FREEIF(val_type); } wasm_valtype_t * -wasm_valtype_copy(wasm_valtype_t *src) +wasm_valtype_copy(const wasm_valtype_t *src) { bh_assert(src); return wasm_valtype_new(src->kind); @@ -420,218 +476,121 @@ wasm_valtype_same(const wasm_valtype_t *vt1, const wasm_valtype_t *vt2) return vt1->kind == vt2->kind; } -void -wasm_valtype_vec_new_uninitialized(wasm_valtype_vec_t *out, size_t size) -{ - bh_assert(out); - generic_vec_init_data((Vector *)out, size, sizeof(wasm_valtype_t *)); -} - -void -wasm_valtype_vec_new_empty(wasm_valtype_vec_t *out) -{ - bh_assert(out); - memset(out, 0, sizeof(wasm_valtype_vec_t)); -} - -void -wasm_valtype_vec_new(wasm_valtype_vec_t *out, - size_t size, - wasm_valtype_t *const data[]) -{ - uint32 size_in_bytes = 0; - bh_assert(out && data); - generic_vec_init_data((Vector *)out, size, sizeof(wasm_valtype_t *)); - if (!out->data) { - goto failed; - } - - /* integer overflow has been checked in generic_vec_init_data, - no need to check again */ - size_in_bytes = (uint32)(size * sizeof(wasm_valtype_t *)); - bh_memcpy_s(out->data, size_in_bytes, data, size_in_bytes); - out->num_elems = size; - return; - -failed: - LOG_DEBUG("%s failed", __FUNCTION__); - wasm_valtype_vec_delete(out); -} - -void -wasm_valtype_vec_copy(wasm_valtype_vec_t *out, const wasm_valtype_vec_t *src) -{ - size_t i = 0; - - bh_assert(out && src); - - generic_vec_init_data((Vector *)out, src->size, sizeof(wasm_valtype_t *)); - if (!out->data) { - goto failed; - } - - /* clone every wasm_valtype_t */ - for (i = 0; i < src->num_elems; i++) { - wasm_valtype_t *cloned = wasm_valtype_copy(*(src->data + i)); - if (!cloned) { - goto failed; - } - if (!bh_vector_append((Vector *)out, &cloned)) { - goto failed; - } - } - - return; - -failed: - LOG_DEBUG("%s failed", __FUNCTION__); - wasm_valtype_vec_delete(out); -} - -void -wasm_valtype_vec_delete(wasm_valtype_vec_t *val_type_vec) -{ - size_t i = 0; - if (!val_type_vec || !val_type_vec->data) { - return; - } - - FREE_VEC_ELEMS(val_type_vec, wasm_valtype_delete); - bh_vector_destroy((Vector *)val_type_vec); -} - static wasm_functype_t * wasm_functype_new_internal(WASMType *type_rt) { - wasm_functype_t *func_type = NULL; + wasm_functype_t *type = NULL; + wasm_valtype_t *param_type = NULL, *result_type = NULL; uint32 i = 0; bh_assert(type_rt); - func_type = malloc_internal(sizeof(wasm_functype_t)); - if (!func_type) { - goto failed; + if (!(type = malloc_internal(sizeof(wasm_functype_t)))) { + return NULL; } - /* WASMType->types[0 : type_rt->param_count) -> func_type->params */ - INIT_VEC(func_type->params, wasm_valtype_vec, type_rt->param_count); + type->extern_kind = WASM_EXTERN_FUNC; + + /* WASMType->types[0 : type_rt->param_count) -> type->params */ + INIT_VEC(type->params, wasm_valtype_vec_new_uninitialized, + type_rt->param_count); for (i = 0; i < type_rt->param_count; ++i) { - wasm_valtype_t *param_type = - wasm_valtype_new_internal(*(type_rt->types + i)); - if (!param_type) { + if (!(param_type = wasm_valtype_new_internal(*(type_rt->types + i)))) { goto failed; } - if (!bh_vector_append((Vector *)func_type->params, ¶m_type)) { + if (!bh_vector_append((Vector *)type->params, ¶m_type)) { + LOG_DEBUG("bh_vector_append failed"); goto failed; } } - /* WASMType->types[type_rt->param_count : type_rt->result_count) -> func_type->results */ - INIT_VEC(func_type->results, wasm_valtype_vec, type_rt->result_count); + /* WASMType->types[type_rt->param_count : type_rt->result_count) -> type->results */ + INIT_VEC(type->results, wasm_valtype_vec_new_uninitialized, + type_rt->result_count); for (i = 0; i < type_rt->result_count; ++i) { - wasm_valtype_t *result_type = - wasm_valtype_new_internal(*(type_rt->types + type_rt->param_count + i)); - if (!result_type) { + if (!(result_type = wasm_valtype_new_internal( + *(type_rt->types + type_rt->param_count + i)))) { goto failed; } - if (!bh_vector_append((Vector *)func_type->results, &result_type)) { + if (!bh_vector_append((Vector *)type->results, &result_type)) { + LOG_DEBUG("bh_vector_append failed"); goto failed; } } - return func_type; + return type; failed: - LOG_DEBUG("%s failed", __FUNCTION__); - wasm_functype_delete(func_type); + wasm_valtype_delete(param_type); + wasm_valtype_delete(result_type); + wasm_functype_delete(type); return NULL; } wasm_functype_t * -wasm_functype_new(wasm_valtype_vec_t *params, wasm_valtype_vec_t *results) +wasm_functype_new(own wasm_valtype_vec_t *params, + own wasm_valtype_vec_t *results) { - wasm_functype_t *func_type = NULL; + wasm_functype_t *type = NULL; bh_assert(params); bh_assert(results); - func_type = malloc_internal(sizeof(wasm_functype_t)); - if (!func_type) { + if (!(type = malloc_internal(sizeof(wasm_functype_t)))) { goto failed; } - func_type->extern_kind = WASM_EXTERN_FUNC; + type->extern_kind = WASM_EXTERN_FUNC; - func_type->params = malloc_internal(sizeof(wasm_valtype_vec_t)); - if (!func_type->params) { + /* take ownership */ + if (!(type->params = malloc_internal(sizeof(wasm_valtype_vec_t)))) { goto failed; } - - /* transfer ownership of contents of params and results */ - bh_memcpy_s(func_type->params, sizeof(wasm_valtype_vec_t), params, + bh_memcpy_s(type->params, sizeof(wasm_valtype_vec_t), params, sizeof(wasm_valtype_vec_t)); - func_type->results = malloc_internal(sizeof(wasm_valtype_vec_t)); - if (!func_type->results) { + if (!(type->results = malloc_internal(sizeof(wasm_valtype_vec_t)))) { goto failed; } - - bh_memcpy_s(func_type->results, sizeof(wasm_valtype_vec_t), results, + bh_memcpy_s(type->results, sizeof(wasm_valtype_vec_t), results, sizeof(wasm_valtype_vec_t)); - return func_type; + return type; failed: - LOG_DEBUG("%s failed", __FUNCTION__); - if (func_type) - FREEIF(func_type->params); - if (func_type) - FREEIF(func_type->results); - FREEIF(func_type); + wasm_functype_delete(type); return NULL; } wasm_functype_t * -wasm_functype_copy(wasm_functype_t *src) +wasm_functype_copy(const wasm_functype_t *src) { - wasm_functype_t *dst = NULL; + wasm_functype_t *functype; + wasm_valtype_vec_t params = { 0 }, results = { 0 }; bh_assert(src); - dst = malloc_internal(sizeof(wasm_functype_t)); - if (!dst) { + wasm_valtype_vec_copy(¶ms, src->params); + if (src->params->size && !params.data) { goto failed; } - dst->extern_kind = src->extern_kind; - - dst->params = malloc_internal(sizeof(wasm_valtype_vec_t)); - if (!dst->params) { + wasm_valtype_vec_copy(&results, src->results); + if (src->results->size && !results.data) { goto failed; } - wasm_valtype_vec_copy(dst->params, src->params); - if (!dst->params) { + if (!(functype = wasm_functype_new(¶ms, &results))) { goto failed; } - dst->results = malloc_internal(sizeof(wasm_valtype_vec_t)); - if (!dst->results) { - goto failed; - } - - wasm_valtype_vec_copy(dst->results, src->results); - if (!dst->results) { - goto failed; - } - - return dst; + return functype; failed: - LOG_DEBUG("%s failed", __FUNCTION__); - wasm_functype_delete(dst); + wasm_valtype_vec_delete(¶ms); + wasm_valtype_vec_delete(&results); return NULL; } @@ -642,17 +601,8 @@ wasm_functype_delete(wasm_functype_t *func_type) return; } - if (func_type->params) { - wasm_valtype_vec_delete(func_type->params); - wasm_runtime_free(func_type->params); - func_type->params = NULL; - } - - if (func_type->results) { - wasm_valtype_vec_delete(func_type->results); - wasm_runtime_free(func_type->results); - func_type->results = NULL; - } + DEINIT_VEC(func_type->params, wasm_valtype_vec_delete); + DEINIT_VEC(func_type->results, wasm_valtype_vec_delete); wasm_runtime_free(func_type); } @@ -672,51 +622,39 @@ wasm_functype_results(const wasm_functype_t *func_type) } wasm_globaltype_t * -wasm_globaltype_new(wasm_valtype_t *val_type, wasm_mutability_t mut) +wasm_globaltype_new(own wasm_valtype_t *val_type, wasm_mutability_t mut) { wasm_globaltype_t *global_type = NULL; bh_assert(val_type); - global_type = malloc_internal(sizeof(wasm_globaltype_t)); - if (!global_type) { - goto failed; + if (!(global_type = malloc_internal(sizeof(wasm_globaltype_t)))) { + return NULL; } + global_type->extern_kind = WASM_EXTERN_GLOBAL; global_type->val_type = val_type; global_type->mutability = mut; return global_type; - -failed: - LOG_DEBUG("%s failed", __FUNCTION__); - wasm_globaltype_delete(global_type); - return NULL; } wasm_globaltype_t * wasm_globaltype_new_internal(uint8 val_type_rt, bool is_mutable) { - wasm_globaltype_t *global_type = NULL; + wasm_globaltype_t *globaltype; + wasm_valtype_t *val_type; - global_type = malloc_internal(sizeof(wasm_globaltype_t)); - if (!global_type) { - goto failed; + if (!(val_type = wasm_valtype_new(val_type_rt_2_valkind(val_type_rt)))) { + return NULL; } - global_type->val_type = wasm_valtype_new_internal(val_type_rt); - if (!global_type->val_type) { - goto failed; + if (!(globaltype = wasm_globaltype_new( + val_type, is_mutable ? WASM_VAR : WASM_CONST))) { + wasm_valtype_delete(val_type); } - global_type->mutability = is_mutable ? WASM_VAR : WASM_CONST; - - return global_type; - -failed: - LOG_DEBUG("%s failed", __FUNCTION__); - wasm_globaltype_delete(global_type); - return NULL; + return globaltype; } void @@ -735,30 +673,22 @@ wasm_globaltype_delete(wasm_globaltype_t *global_type) } wasm_globaltype_t * -wasm_globaltype_copy(wasm_globaltype_t *src) +wasm_globaltype_copy(const wasm_globaltype_t *src) { - wasm_globaltype_t *dst = NULL; + wasm_globaltype_t *global_type; + wasm_valtype_t *val_type; bh_assert(src); - dst = malloc_internal(sizeof(wasm_globaltype_t)); - if (!dst) { - goto failed; + if (!(val_type = wasm_valtype_copy(src->val_type))) { + return NULL; } - dst->val_type = wasm_valtype_copy(src->val_type); - if (!dst->val_type) { - goto failed; + if (!(global_type = wasm_globaltype_new(val_type, src->mutability))) { + wasm_valtype_delete(val_type); } - dst->mutability = src->mutability; - - return dst; - -failed: - LOG_DEBUG("%s failed", __FUNCTION__); - wasm_globaltype_delete(dst); - return NULL; + return global_type; } const wasm_valtype_t * @@ -791,32 +721,434 @@ wasm_globaltype_same(const wasm_globaltype_t *gt1, || gt1->mutability == gt2->mutability; } -wasm_tabletype_t * -wasm_tabletype_new(wasm_valtype_t *val_type, const wasm_limits_t *limits) +static wasm_tabletype_t * +wasm_tabletype_new_internal(uint8 val_type_rt, + uint32 init_size, + uint32 max_size) { - return NULL; + wasm_tabletype_t *table_type; + wasm_limits_t limits = { init_size, max_size }; + wasm_valtype_t *val_type; + + if (!(val_type = wasm_valtype_new_internal(val_type_rt))) { + return NULL; + } + + if (!(table_type = wasm_tabletype_new(val_type, &limits))) { + wasm_valtype_delete(val_type); + } + + return table_type; +} + +wasm_tabletype_t * +wasm_tabletype_new(own wasm_valtype_t *val_type, const wasm_limits_t *limits) +{ + wasm_tabletype_t *table_type = NULL; + + bh_assert(val_type); + + if (!(table_type = malloc_internal(sizeof(wasm_tabletype_t)))) { + return NULL; + } + + table_type->extern_kind = WASM_EXTERN_TABLE; + table_type->val_type = val_type; + table_type->limits.min = limits->min; + table_type->limits.max = limits->max; + + return table_type; +} + +wasm_tabletype_t * +wasm_tabletype_copy(const wasm_tabletype_t *src) +{ + wasm_tabletype_t *table_type; + wasm_valtype_t *val_type; + + bh_assert(src); + + if (!(val_type = wasm_valtype_copy(src->val_type))) { + return NULL; + } + + if (!(table_type = wasm_tabletype_new(val_type, &src->limits))) { + wasm_valtype_delete(val_type); + } + + return table_type; } void wasm_tabletype_delete(wasm_tabletype_t *table_type) -{} +{ + if (!table_type) { + return; + } + + if (table_type->val_type) { + wasm_valtype_delete(table_type->val_type); + table_type->val_type = NULL; + } + + wasm_runtime_free(table_type); +} + +const wasm_valtype_t * +wasm_tabletype_element(const wasm_tabletype_t *table_type) +{ + bh_assert(table_type); + return table_type->val_type; +} + +const wasm_limits_t * +wasm_tabletype_limits(const wasm_tabletype_t *table_type) +{ + bh_assert(table_type); + return &(table_type->limits); +} + +static wasm_memorytype_t * +wasm_memorytype_new_internal(uint32 min_pages, uint32 max_pages) +{ + wasm_limits_t limits = { min_pages, max_pages }; + return wasm_memorytype_new(&limits); +} wasm_memorytype_t * wasm_memorytype_new(const wasm_limits_t *limits) { - return NULL; + wasm_memorytype_t *memory_type = NULL; + bh_assert(limits); + + if (!(memory_type = malloc_internal(sizeof(wasm_memorytype_t)))) { + return NULL; + } + + memory_type->extern_kind = WASM_EXTERN_MEMORY; + memory_type->limits.min = limits->min; + memory_type->limits.max = limits->max; + + return memory_type; +} + +wasm_memorytype_t * +wasm_memorytype_copy(const wasm_memorytype_t *src) +{ + bh_assert(src); + return wasm_memorytype_new(&src->limits); } void wasm_memorytype_delete(wasm_memorytype_t *memory_type) -{} +{ + FREEIF(memory_type); +} + +const wasm_limits_t * +wasm_memorytype_limits(const wasm_memorytype_t *memory_type) +{ + bh_assert(memory_type); + return &(memory_type->limits); +} + +wasm_externkind_t +wasm_externtype_kind(const wasm_externtype_t *extern_type) +{ + bh_assert(extern_type); + return extern_type->extern_kind; +} + +#define BASIC_FOUR_TYPE_LIST(V) \ + V(functype) \ + V(globaltype) \ + V(memorytype) \ + V(tabletype) + +#define WASM_EXTERNTYPE_AS_OTHERTYPE(name) \ + wasm_##name##_t *wasm_externtype_as_##name( \ + wasm_externtype_t *extern_type) \ + { \ + return (wasm_##name##_t *)extern_type; \ + } + +BASIC_FOUR_TYPE_LIST(WASM_EXTERNTYPE_AS_OTHERTYPE) +#undef WASM_EXTERNTYPE_AS_OTHERTYPE + +#define WASM_OTHERTYPE_AS_EXTERNTYPE(name) \ + wasm_externtype_t *wasm_##name##_as_externtype(wasm_##name##_t *other) \ + { \ + return (wasm_externtype_t *)other; \ + } + +BASIC_FOUR_TYPE_LIST(WASM_OTHERTYPE_AS_EXTERNTYPE) +#undef WASM_OTHERTYPE_AS_EXTERNTYPE + +#define WASM_EXTERNTYPE_AS_OTHERTYPE_CONST(name) \ + const wasm_##name##_t *wasm_externtype_as_##name##_const( \ + const wasm_externtype_t *extern_type) \ + { \ + return (const wasm_##name##_t *)extern_type; \ + } + +BASIC_FOUR_TYPE_LIST(WASM_EXTERNTYPE_AS_OTHERTYPE_CONST) +#undef WASM_EXTERNTYPE_AS_OTHERTYPE_CONST + +#define WASM_OTHERTYPE_AS_EXTERNTYPE_CONST(name) \ + const wasm_externtype_t *wasm_##name##_as_externtype_const( \ + const wasm_##name##_t *other) \ + { \ + return (const wasm_externtype_t *)other; \ + } + +BASIC_FOUR_TYPE_LIST(WASM_OTHERTYPE_AS_EXTERNTYPE_CONST) +#undef WASM_OTHERTYPE_AS_EXTERNTYPE_CONST + +wasm_externtype_t * +wasm_externtype_copy(const wasm_externtype_t *src) +{ + wasm_externtype_t *extern_type = NULL; + + bh_assert(src); + + switch (src->extern_kind) { +#define COPY_EXTERNTYPE(NAME, name) \ + case WASM_EXTERN_##NAME: \ + { \ + extern_type = wasm_##name##_as_externtype( \ + wasm_##name##_copy(wasm_externtype_as_##name##_const(src))); \ + break; \ + } + COPY_EXTERNTYPE(FUNC, functype) + COPY_EXTERNTYPE(GLOBAL, globaltype) + COPY_EXTERNTYPE(MEMORY, memorytype) + COPY_EXTERNTYPE(TABLE, tabletype) +#undef COPY_EXTERNTYPE + default: + LOG_WARNING("%s meets unsupported kind", __FUNCTION__, + src->extern_kind); + break; + } + return extern_type; +} + +void +wasm_externtype_delete(wasm_externtype_t *extern_type) +{ + if (!extern_type) { + return; + } + + switch (wasm_externtype_kind(extern_type)) { + case WASM_EXTERN_FUNC: + wasm_functype_delete(wasm_externtype_as_functype(extern_type)); + break; + case WASM_EXTERN_GLOBAL: + wasm_globaltype_delete(wasm_externtype_as_globaltype(extern_type)); + break; + case WASM_EXTERN_MEMORY: + wasm_memorytype_delete(wasm_externtype_as_memorytype(extern_type)); + break; + case WASM_EXTERN_TABLE: + wasm_tabletype_delete(wasm_externtype_as_tabletype(extern_type)); + break; + default: + LOG_WARNING("%s meets unsupported type", __FUNCTION__, + extern_type); + break; + } +} + +own wasm_importtype_t * +wasm_importtype_new(own wasm_byte_vec_t *module, + own wasm_byte_vec_t *name, + own wasm_externtype_t *extern_type) +{ + wasm_importtype_t *import_type = NULL; + + if (!(import_type = malloc_internal(sizeof(wasm_importtype_t)))) { + return NULL; + } + + /* take ownership */ + if (!(import_type->module_name = + malloc_internal(sizeof(wasm_byte_vec_t)))) { + goto failed; + } + bh_memcpy_s(import_type->module_name, sizeof(wasm_byte_vec_t), module, + sizeof(wasm_byte_vec_t)); + + if (!(import_type->name = malloc_internal(sizeof(wasm_byte_vec_t)))) { + goto failed; + } + bh_memcpy_s(import_type->name, sizeof(wasm_byte_vec_t), name, + sizeof(wasm_byte_vec_t)); + + import_type->extern_type = extern_type; + + return import_type; +failed: + wasm_importtype_delete(import_type); + return NULL; +} + +void +wasm_importtype_delete(own wasm_importtype_t *import_type) +{ + if (!import_type) { + return; + } + + DEINIT_VEC(import_type->module_name, wasm_byte_vec_delete); + DEINIT_VEC(import_type->name, wasm_byte_vec_delete); + wasm_externtype_delete(import_type->extern_type); + wasm_runtime_free(import_type); +} + +own wasm_importtype_t * +wasm_importtype_copy(const wasm_importtype_t *src) +{ + wasm_byte_vec_t module_name = { 0 }, name = { 0 }; + wasm_externtype_t *extern_type = NULL; + wasm_importtype_t *import_type = NULL; + + bh_assert(src); + + wasm_byte_vec_copy(&module_name, src->module_name); + if (src->module_name->size && !module_name.data) { + goto failed; + } + + wasm_byte_vec_copy(&name, src->name); + if (src->name->size && !name.data) { + goto failed; + } + + if (!(extern_type = wasm_externtype_copy(src->extern_type))) { + goto failed; + } + + if (!(import_type = + wasm_importtype_new(&module_name, &name, extern_type))) { + goto failed; + } + + return import_type; + +failed: + wasm_byte_vec_delete(&module_name); + wasm_byte_vec_delete(&name); + wasm_externtype_delete(extern_type); + wasm_importtype_delete(import_type); + return NULL; +} + +const wasm_byte_vec_t * +wasm_importtype_module(const wasm_importtype_t *import_type) +{ + bh_assert(import_type); + return import_type->module_name; +} + +const wasm_byte_vec_t * +wasm_importtype_name(const wasm_importtype_t *import_type) +{ + bh_assert(import_type); + return import_type->name; +} + +const wasm_externtype_t * +wasm_importtype_type(const wasm_importtype_t *import_type) +{ + bh_assert(import_type); + return import_type->extern_type; +} + +own wasm_exporttype_t * +wasm_exporttype_new(own wasm_byte_vec_t *name, + own wasm_externtype_t *extern_type) +{ + wasm_exporttype_t *export_type = NULL; + + if (!(export_type = malloc_internal(sizeof(wasm_exporttype_t)))) { + return NULL; + } + + if (!(export_type->name = malloc_internal(sizeof(wasm_byte_vec_t)))) { + wasm_exporttype_delete(export_type); + return NULL; + } + bh_memcpy_s(export_type->name, sizeof(wasm_byte_vec_t), name, + sizeof(wasm_byte_vec_t)); + + export_type->extern_type = extern_type; + + return export_type; +} + +wasm_exporttype_t * +wasm_exporttype_copy(const wasm_exporttype_t *src) +{ + wasm_exporttype_t *export_type; + wasm_byte_vec_t name = { 0 }; + wasm_externtype_t *extern_type = NULL; + + bh_assert(src); + + wasm_byte_vec_copy(&name, src->name); + if (src->name->size && !name.data) { + goto failed; + } + + if (!(extern_type = wasm_externtype_copy(src->extern_type))) { + goto failed; + } + + if (!(export_type = wasm_exporttype_new(&name, extern_type))) { + goto failed; + } + + return export_type; +failed: + wasm_byte_vec_delete(&name); + wasm_externtype_delete(extern_type); + return NULL; +} + +void +wasm_exporttype_delete(wasm_exporttype_t *export_type) +{ + if (!export_type) { + return; + } + + DEINIT_VEC(export_type->name, wasm_byte_vec_delete); + + wasm_externtype_delete(export_type->extern_type); + + wasm_runtime_free(export_type); +} + +const wasm_byte_vec_t * +wasm_exporttype_name(const wasm_exporttype_t *export_type) +{ + bh_assert(export_type); + return export_type->name; +} + +const wasm_externtype_t * +wasm_exporttype_type(const wasm_exporttype_t *export_type) +{ + bh_assert(export_type); + return export_type->extern_type; +} /* Runtime Objects */ void wasm_val_delete(wasm_val_t *v) { - /* do nothing */ + FREEIF(v); } void @@ -858,6 +1190,30 @@ wasm_val_same(const wasm_val_t *v1, const wasm_val_t *v2) return false; } +static wasm_trap_t * +wasm_trap_new_internal(const char *string) +{ + wasm_trap_t *trap; + + if (!(trap = malloc_internal(sizeof(wasm_trap_t)))) { + return NULL; + } + + if (!(trap->message = malloc_internal(sizeof(wasm_byte_vec_t)))) { + goto failed; + } + + wasm_name_new_from_string_nt(trap->message, string); + if (strlen(string) && !trap->message->data) { + goto failed; + } + + return trap; +failed: + wasm_trap_delete(trap); + return NULL; +} + wasm_trap_t * wasm_trap_new(wasm_store_t *store, const wasm_message_t *message) { @@ -865,18 +1221,13 @@ wasm_trap_new(wasm_store_t *store, const wasm_message_t *message) bh_assert(store && message); - trap = malloc_internal(sizeof(wasm_trap_t)); - if (!trap) { - goto failed; + if (!(trap = malloc_internal(sizeof(wasm_trap_t)))) { + return NULL; } - wasm_byte_vec_new(trap->message, message->num_elems, message->data); - if (!trap->message->data) { - goto failed; - } + INIT_VEC(trap->message, wasm_byte_vec_new, message->size, message->data); return trap; - failed: wasm_trap_delete(trap); return NULL; @@ -889,15 +1240,13 @@ wasm_trap_delete(wasm_trap_t *trap) return; } - if (trap->message) { - wasm_byte_vec_delete(trap->message); - } + DEINIT_VEC(trap->message, wasm_byte_vec_delete); wasm_runtime_free(trap); } void -wasm_trap_message(const wasm_trap_t *trap, wasm_message_t *out) +wasm_trap_message(const wasm_trap_t *trap, own wasm_message_t *out) { bh_assert(trap && out); wasm_byte_vec_copy(out, trap->message); @@ -920,12 +1269,19 @@ module_to_module_ext(wasm_module_t *module) return (wasm_module_ex_t *)module; } +#if WASM_ENABLE_INTERP != 0 +#define MODULE_INTERP(module) ((WASMModule *)(*module)) +#endif + +#if WASM_ENABLE_AOT != 0 +#define MODULE_AOT(module) ((AOTModule *)(*module)) +#endif + wasm_module_t * wasm_module_new(wasm_store_t *store, const wasm_byte_vec_t *binary) { char error[128] = { 0 }; wasm_module_ex_t *module_ex = NULL; - PackageType pkg_type = Package_Type_Unknown; check_engine_and_store(singleton_engine, store); bh_assert(binary && binary->data && binary->size); @@ -935,41 +1291,19 @@ wasm_module_new(wasm_store_t *store, const wasm_byte_vec_t *binary) return NULL; } - pkg_type = get_package_type((uint8 *)binary->data, (uint32)binary->size); - if (Package_Type_Unknown == pkg_type - || (Wasm_Module_Bytecode == pkg_type - && INTERP_MODE != current_runtime_mode()) - || (Wasm_Module_AoT == pkg_type - && INTERP_MODE == current_runtime_mode())) { - LOG_ERROR( - "current runtime mode %d doesn\'t support the package type %d", - current_runtime_mode(), pkg_type); - return NULL; - } - module_ex = malloc_internal(sizeof(wasm_module_ex_t)); if (!module_ex) { goto failed; } - module_ex->binary = malloc_internal(sizeof(wasm_byte_vec_t)); - if (!module_ex->binary) { - goto failed; - } + INIT_VEC(module_ex->binary, wasm_byte_vec_new, binary->size, binary->data); - wasm_byte_vec_copy(module_ex->binary, binary); - if (!module_ex->binary->data) { - goto failed; - } - - module_ex->module_comm_rt = - wasm_runtime_load((uint8 *)module_ex->binary->data, - (uint32)module_ex->binary->size, - error, (uint32)sizeof(error)); + module_ex->module_comm_rt = wasm_runtime_load( + (uint8 *)module_ex->binary->data, (uint32)module_ex->binary->size, error, + (uint32)sizeof(error)); if (!(module_ex->module_comm_rt)) { LOG_ERROR(error); - wasm_module_delete_internal(module_ext_to_module(module_ex)); - return NULL; + goto failed; } /* add it to a watching list in store */ @@ -985,7 +1319,7 @@ failed: return NULL; } -void +static void wasm_module_delete_internal(wasm_module_t *module) { wasm_module_ex_t *module_ex; @@ -994,11 +1328,7 @@ wasm_module_delete_internal(wasm_module_t *module) } module_ex = module_to_module_ext(module); - if (module_ex->binary) { - wasm_byte_vec_delete(module_ex->binary); - wasm_runtime_free(module_ex->binary); - module_ex->binary = NULL; - } + DEINIT_VEC(module_ex->binary, wasm_byte_vec_delete); if (module_ex->module_comm_rt) { wasm_runtime_unload(module_ex->module_comm_rt); @@ -1008,39 +1338,405 @@ wasm_module_delete_internal(wasm_module_t *module) wasm_runtime_free(module_ex); } -/* will release module when releasing the store */ void wasm_module_delete(wasm_module_t *module) { - /* pass */ + /* will release module when releasing the store */ } void -wasm_module_vec_new_uninitialized(wasm_module_vec_t *out, size_t size) +wasm_module_imports(const wasm_module_t *module, + own wasm_importtype_vec_t *out) { - generic_vec_init_data((Vector *)out, size, sizeof(wasm_module_t *)); -} + uint32 i, import_func_count, import_memory_count, import_global_count, + import_table_count, import_count; + wasm_byte_vec_t module_name = { 0 }, name = { 0 }; + wasm_externtype_t *extern_type = NULL; + wasm_importtype_t *import_type = NULL; -void -wasm_module_vec_delete(wasm_module_vec_t *module_vec) -{ - size_t i = 0; - if (!module_vec || !module_vec->data) { + bh_assert(out); + + if (run_with_bytecode_module(module)) { +#if WASM_ENABLE_INTERP != 0 + import_func_count = MODULE_INTERP(module)->import_function_count; + import_global_count = MODULE_INTERP(module)->import_global_count; + import_memory_count = MODULE_INTERP(module)->import_memory_count; + import_table_count = MODULE_INTERP(module)->import_table_count; +#endif + } + else { +#if WASM_ENABLE_AOT != 0 + import_func_count = MODULE_AOT(module)->import_func_count; + import_global_count = MODULE_AOT(module)->import_global_count; + import_memory_count = MODULE_AOT(module)->import_memory_count; + import_table_count = MODULE_AOT(module)->import_table_count; +#endif + } + + import_count = import_func_count + import_global_count + import_table_count + + import_memory_count; + wasm_importtype_vec_new_uninitialized(out, import_count); + if (import_count && !out->data) { return; } - FREE_VEC_ELEMS(module_vec, wasm_module_delete_internal); - bh_vector_destroy((Vector *)module_vec); + for (i = 0; i != import_count; ++i) { + char *module_name_rt, *field_name_rt; + + if (i < import_func_count) { + wasm_functype_t *type = NULL; + WASMType *type_rt; + + if (run_with_bytecode_module(module)) { +#if WASM_ENABLE_INTERP != 0 + WASMImport *import = + MODULE_INTERP(module)->import_functions + i; + module_name_rt = import->u.names.module_name; + field_name_rt = import->u.names.field_name; + type_rt = import->u.function.func_type; +#endif + } + else { +#if WASM_ENABLE_AOT != 0 + AOTImportFunc *import = MODULE_AOT(module)->import_funcs + i; + module_name_rt = import->module_name; + field_name_rt = import->func_name; + type_rt = import->func_type; +#endif + } + + if (!module_name_rt || !field_name_rt || !type_rt) { + continue; + } + + wasm_name_new_from_string_nt(&module_name, module_name_rt); + if (strlen(module_name_rt) && !module_name.data) { + goto failed; + } + + wasm_name_new_from_string_nt(&name, field_name_rt); + if (strlen(field_name_rt) && !name.data) { + goto failed; + } + + if (!(type = wasm_functype_new_internal(type_rt))) { + goto failed; + } + + extern_type = wasm_functype_as_externtype(type); + } + else if (i < import_func_count + import_global_count) { + wasm_globaltype_t *type = NULL; + uint8 val_type_rt = 0; + bool mutability_rt = 0; + + if (run_with_bytecode_module(module)) { +#if WASM_ENABLE_INTERP != 0 + WASMImport *import = MODULE_INTERP(module)->import_globals + + (i - import_func_count); + module_name_rt = import->u.names.module_name; + field_name_rt = import->u.names.field_name; + val_type_rt = import->u.global.type; + mutability_rt = import->u.global.is_mutable; +#endif + } + else { +#if WASM_ENABLE_AOT != 0 + AOTImportGlobal *import = + MODULE_AOT(module)->import_globals + (i - import_func_count); + module_name_rt = import->module_name; + field_name_rt = import->global_name; + val_type_rt = import->type; + mutability_rt = import->is_mutable; +#endif + } + + if (!module_name_rt || !field_name_rt) { + continue; + } + + if (!(type = wasm_globaltype_new_internal(val_type_rt, + mutability_rt))) { + goto failed; + } + + extern_type = wasm_globaltype_as_externtype(type); + } + else if (i < import_func_count + import_global_count + + import_memory_count) { + wasm_memorytype_t *type = NULL; + uint32 min_page = 0, max_page = 0; + + if (run_with_bytecode_module(module)) { +#if WASM_ENABLE_INTERP != 0 + WASMImport *import = + MODULE_INTERP(module)->import_memories + + (i - import_func_count - import_global_count); + module_name_rt = import->u.names.module_name; + field_name_rt = import->u.names.field_name; + min_page = import->u.memory.init_page_count; + max_page = import->u.memory.max_page_count; +#endif + } + else { +#if WASM_ENABLE_AOT != 0 + AOTImportMemory *import = + MODULE_AOT(module)->import_memories + + (i - import_func_count - import_global_count); + module_name_rt = import->module_name; + field_name_rt = import->memory_name; + min_page = import->mem_init_page_count; + max_page = import->mem_max_page_count; +#endif + } + + if (!module_name_rt || !field_name_rt) { + continue; + } + + wasm_name_new_from_string_nt(&module_name, module_name_rt); + if (strlen(module_name_rt) && !module_name.data) { + goto failed; + } + + wasm_name_new_from_string_nt(&name, field_name_rt); + if (strlen(field_name_rt) && !name.data) { + goto failed; + } + + if (!(type = wasm_memorytype_new_internal(min_page, max_page))) { + goto failed; + } + + extern_type = wasm_memorytype_as_externtype(type); + } + else { + wasm_tabletype_t *type = NULL; + uint8 elem_type_rt = 0; + uint32 min_size = 0, max_size = 0; + + if (run_with_bytecode_module(module)) { +#if WASM_ENABLE_INTERP != 0 + WASMImport *import = + MODULE_INTERP(module)->import_tables + + (i - import_func_count - import_global_count + - import_memory_count); + module_name_rt = import->u.names.module_name; + field_name_rt = import->u.names.field_name; + elem_type_rt = import->u.table.elem_type; + min_size = import->u.table.init_size; + max_size = import->u.table.max_size; +#endif + } + else { +#if WASM_ENABLE_AOT != 0 + AOTImportTable *import = + MODULE_AOT(module)->import_tables + + (i - import_func_count - import_global_count + - import_memory_count); + module_name_rt = import->module_name; + field_name_rt = import->table_name; + elem_type_rt = VALUE_TYPE_FUNCREF; + min_size = import->table_init_size; + max_size = import->table_max_size; +#endif + } + + if (!module_name_rt || !field_name_rt) { + continue; + } + + if (!(type = wasm_tabletype_new_internal(elem_type_rt, min_size, + max_size))) { + goto failed; + } + + extern_type = wasm_tabletype_as_externtype(type); + } + + if (!extern_type) { + continue; + } + + if (!(import_type = + wasm_importtype_new(&module_name, &name, extern_type))) { + goto failed; + } + + if (!bh_vector_append((Vector *)out, &import_type)) { + goto failed_importtype_new; + } + } + + return; + +failed: + wasm_byte_vec_delete(&module_name); + wasm_byte_vec_delete(&name); + wasm_externtype_delete(extern_type); +failed_importtype_new: + wasm_importtype_delete(import_type); + wasm_importtype_vec_delete(out); +} + +void +wasm_module_exports(const wasm_module_t *module, wasm_exporttype_vec_t *out) +{ + uint32 i, export_count; + wasm_byte_vec_t name = { 0 }; + wasm_externtype_t *extern_type = NULL; + wasm_exporttype_t *export_type = NULL; + + bh_assert(out); + + if (run_with_bytecode_module(module)) { +#if WASM_ENABLE_INTERP != 0 + export_count = MODULE_INTERP(module)->export_count; +#endif + } + else { +#if WASM_ENABLE_AOT != 0 + export_count = MODULE_AOT(module)->export_count; +#endif + } + + wasm_exporttype_vec_new_uninitialized(out, export_count); + if (export_count && !out->data) { + return; + } + + for (i = 0; i != export_count; i++) { + WASMExport *export = NULL; + if (run_with_bytecode_module(module)) { +#if WASM_ENABLE_INTERP != 0 + export = MODULE_INTERP(module)->exports + i; +#endif + } + else { +#if WASM_ENABLE_AOT != 0 + export = MODULE_AOT(module)->exports + i; +#endif + } + + if (!export) { + continue; + } + + /* byte* -> wasm_byte_vec_t */ + wasm_name_new_from_string_nt(&name, export->name); + if (strlen(export->name) && !name.data) { + goto failed; + } + + /* WASMExport -> (WASMType, (uint8, bool)) -> (wasm_functype_t, wasm_globaltype_t) -> wasm_externtype_t*/ + switch (export->kind) { + case EXPORT_KIND_FUNC: + { + wasm_functype_t *type = NULL; + WASMType *type_rt; + + if (!wasm_runtime_get_export_func_type(*module, export, + &type_rt)) { + goto failed; + } + + if (!(type = wasm_functype_new_internal(type_rt))) { + goto failed; + } + + extern_type = wasm_functype_as_externtype(type); + break; + } + case EXPORT_KIND_GLOBAL: + { + wasm_globaltype_t *type = NULL; + uint8 val_type_rt = 0; + bool mutability_rt = 0; + + if (!wasm_runtime_get_export_global_type( + *module, export, &val_type_rt, &mutability_rt)) { + goto failed; + } + + if (!(type = wasm_globaltype_new_internal(val_type_rt, + mutability_rt))) { + goto failed; + } + + extern_type = wasm_globaltype_as_externtype(type); + break; + } + case EXPORT_KIND_MEMORY: + { + wasm_memorytype_t *type = NULL; + uint32 min_page = 0, max_page = 0; + + if (!wasm_runtime_get_export_memory_type( + *module, export, &min_page, &max_page)) { + goto failed; + } + + if (!(type = + wasm_memorytype_new_internal(min_page, max_page))) { + goto failed; + } + + extern_type = wasm_memorytype_as_externtype(type); + break; + } + case EXPORT_KIND_TABLE: + { + wasm_tabletype_t *type = NULL; + uint8 elem_type_rt = 0; + uint32 min_size = 0, max_size = 0; + + if (!wasm_runtime_get_export_table_type( + *module, export, &elem_type_rt, &min_size, &max_size)) { + goto failed; + } + + if (!(type = wasm_tabletype_new_internal( + elem_type_rt, min_size, max_size))) { + goto failed; + } + + extern_type = wasm_tabletype_as_externtype(type); + break; + } + default: + { + LOG_WARNING("%s meets unsupported type", __FUNCTION__, + export->kind); + break; + } + } + + if (!(export_type = wasm_exporttype_new(&name, extern_type))) { + goto failed; + } + + if (!(bh_vector_append((Vector *)out, &export_type))) { + goto failed_exporttype_new; + } + } + + return; + +failed: + wasm_byte_vec_delete(&name); + wasm_externtype_delete(extern_type); +failed_exporttype_new: + wasm_exporttype_delete(export_type); + wasm_exporttype_vec_delete(out); } static uint32 argv_to_params(const uint64 *argv, const wasm_valtype_vec_t *param_defs, - wasm_val_t *out) + wasm_val_t out[]) { size_t i = 0; uint32 argc = 0; - void *argv_p = (void *)argv; for (i = 0; i < param_defs->num_elems; i++) { wasm_valtype_t *param_def = param_defs->data[i]; @@ -1048,30 +1744,27 @@ argv_to_params(const uint64 *argv, switch (param_def->kind) { case WASM_I32: param->kind = WASM_I32; - param->of.i32 = *(int32 *)argv_p; - argv_p = (uint32 *)argv_p + 1; + param->of.i32 = *(uint32 *)(argv + i); argc++; break; case WASM_I64: param->kind = WASM_I64; - param->of.i64 = *(int64 *)argv_p; - argv_p = (uint64 *)argv_p + 1; + param->of.i64 = *(uint64 *)(argv + i); argc++; break; case WASM_F32: param->kind = WASM_F32; - param->of.f32 = *(float32 *)argv_p; - argv_p = (float32 *)argv_p + 1; + param->of.f32 = *(float32 *)(argv + i); argc++; break; case WASM_F64: param->kind = WASM_F64; - param->of.f64 = *(float64 *)argv_p; - argv_p = (float64 *)argv_p + 1; + param->of.f64 = *(float64 *)(argv + i); argc++; break; default: - NOT_REACHED(); + LOG_WARNING("%s meets unsupported type: %d", __FUNCTION__, + param_def->kind); goto failed; } } @@ -1088,35 +1781,33 @@ results_to_argv(const wasm_val_t *results, { size_t i = 0; uint32 argc = 0; - void *argv_p = out; for (i = 0; i < result_defs->num_elems; ++i) { wasm_valtype_t *result_def = result_defs->data[i]; const wasm_val_t *result = results + i; switch (result_def->kind) { case WASM_I32: - *(int32 *)argv_p = result->of.i32; - argv_p = (uint32 *)argv_p + 1; + *(int32 *)(out + i) = result->of.i32; argc++; break; case WASM_I64: - *(int64 *)argv_p = result->of.i64; - argv_p = (uint64 *)argv_p + 1; + *(int64 *)(out + i) = result->of.i64; argc++; break; case WASM_F32: - *(float32 *)argv_p = result->of.f32; - argv_p = (float32 *)argv_p + 1; + *(float32 *)(out + i) = result->of.f32; argc++; break; case WASM_F64: - *(float64 *)argv_p = result->of.f64; - argv_p = (float64 *)argv_p + 1; + *(float64 *)(out + i) = result->of.f64; argc++; break; default: - NOT_REACHED(); + { + LOG_WARNING("%s meets unsupported kind", __FUNCTION__, + result_def->kind); goto failed; + } } } @@ -1125,6 +1816,7 @@ failed: return 0; } +static wasm_trap_t *cur_trap = NULL; static void native_func_trampoline(wasm_exec_env_t exec_env, uint64 *argv) { @@ -1148,8 +1840,8 @@ native_func_trampoline(wasm_exec_env_t exec_env, uint64 *argv) } /* argv -> const wasm_val_t params[] */ - if (!(argc = argv_to_params( - argv, wasm_functype_params(wasm_func_type(func)), params))) { + if (!(argc = argv_to_params(argv, wasm_functype_params(func->type), + params))) { goto failed; } } @@ -1173,15 +1865,16 @@ native_func_trampoline(wasm_exec_env_t exec_env, uint64 *argv) } if (trap) { - wasm_name_t *message = malloc_internal(sizeof(wasm_name_t)); - if (message) { - wasm_trap_message(trap, message); - if (message->data) { - LOG_WARNING("got a trap %s", message->data); - wasm_name_delete(message); - } - FREEIF(message); + wasm_byte_vec_t message = { 0 }; + wasm_trap_message(trap, &message); + if (message.data) { + LOG_WARNING("got a trap %s", message.data); + wasm_runtime_set_exception(exec_env->module_inst, + "call failed, meet a wasm_trap_t"); } + wasm_byte_vec_delete(&message); + + cur_trap = trap; } if (argv) { @@ -1192,7 +1885,7 @@ native_func_trampoline(wasm_exec_env_t exec_env, uint64 *argv) if (!trap && result_count) { /* wasm_val_t results[] -> argv */ if (!(argc = results_to_argv( - results, wasm_functype_results(wasm_func_type(func)), argv))) { + results, wasm_functype_results(func->type), argv))) { goto failed; } } @@ -1203,52 +1896,39 @@ failed: return; } -wasm_func_t * -wasm_func_new(wasm_store_t *store, - const wasm_functype_t *func_type, - wasm_func_callback_t callback) +static wasm_func_t * +wasm_func_new_basic(const wasm_functype_t *type, + wasm_func_callback_t func_callback) { wasm_func_t *func = NULL; + bh_assert(type); - check_engine_and_store(singleton_engine, store); - bh_assert(func_type); - - func = malloc_internal(sizeof(wasm_func_t)); - if (!func) { + if (!(func = malloc_internal(sizeof(wasm_func_t)))) { goto failed; } func->kind = WASM_EXTERN_FUNC; func->with_env = false; - func->u.cb = callback; + func->u.cb = func_callback; - func->func_type = wasm_functype_copy((wasm_functype_t *)func_type); - if (!func->func_type) { + if (!(func->type = wasm_functype_copy(type))) { goto failed; } - return func; - -failed: - LOG_DEBUG("%s failed", __FUNCTION__); - wasm_func_delete(func); - return NULL; + RETURN_OBJ(func, wasm_func_delete) } -wasm_func_t * -wasm_func_new_with_env(wasm_store_t *store, - const wasm_functype_t *func_type, - wasm_func_callback_with_env_t callback, - void *env, - void (*finalizer)(void *)) +static wasm_func_t * +wasm_func_new_with_env_basic(const wasm_functype_t *type, + wasm_func_callback_with_env_t callback, + void *env, + void (*finalizer)(void *)) { wasm_func_t *func = NULL; - check_engine_and_store(singleton_engine, store); - bh_assert(func_type); + bh_assert(type); - func = malloc_internal(sizeof(wasm_func_t)); - if (!func) { + if (!(func = malloc_internal(sizeof(wasm_func_t)))) { goto failed; } @@ -1258,17 +1938,31 @@ wasm_func_new_with_env(wasm_store_t *store, func->u.cb_env.env = env; func->u.cb_env.finalizer = finalizer; - func->func_type = wasm_functype_copy((wasm_functype_t *)func_type); - if (!func->func_type) { + if (!(func->type = wasm_functype_copy(type))) { goto failed; } - return func; + RETURN_OBJ(func, wasm_func_delete) +} -failed: - LOG_DEBUG("%s failed", __FUNCTION__); - wasm_func_delete(func); - return NULL; +wasm_func_t * +wasm_func_new(wasm_store_t *store, + const wasm_functype_t *type, + wasm_func_callback_t callback) +{ + check_engine_and_store(singleton_engine, store); + return wasm_func_new_basic(type, callback); +} + +wasm_func_t * +wasm_func_new_with_env(wasm_store_t *store, + const wasm_functype_t *type, + wasm_func_callback_with_env_t callback, + void *env, + void (*finalizer)(void *)) +{ + check_engine_and_store(singleton_engine, store); + return wasm_func_new_with_env_basic(type, callback, env, finalizer); } static wasm_func_t * @@ -1289,7 +1983,7 @@ wasm_func_new_internal(wasm_store_t *store, func->kind = WASM_EXTERN_FUNC; - if (INTERP_MODE == current_runtime_mode()) { + if (run_with_bytecode_module_inst(inst_comm_rt)) { #if WASM_ENABLE_INTERP != 0 bh_assert(func_idx_rt < ((WASMModuleInstance *)inst_comm_rt)->function_count); @@ -1303,11 +1997,17 @@ wasm_func_new_internal(wasm_store_t *store, else { #if WASM_ENABLE_AOT != 0 /* use same index to trace the function type in AOTFuncType **func_types */ - AOTModuleInstance *inst_aot = (AOTModuleInstance *)inst_comm_rt; - AOTFunctionInstance *func_aot = - (AOTFunctionInstance *)inst_aot->export_funcs.ptr + func_idx_rt; - type_rt = func_aot->is_import_func ? func_aot->u.func_import->func_type - : func_aot->u.func.func_type; + AOTModule *module_aot = + ((AOTModuleInstance *)inst_comm_rt)->aot_module.ptr; + if (func_idx_rt < module_aot->import_func_count) { + type_rt = (module_aot->import_funcs + func_idx_rt)->func_type; + } + else { + func_idx_rt -= module_aot->import_func_count; + type_rt = + module_aot + ->func_types[module_aot->func_type_indexes[func_idx_rt]]; + } #endif } @@ -1315,8 +2015,8 @@ wasm_func_new_internal(wasm_store_t *store, goto failed; } - func->func_type = wasm_functype_new_internal(type_rt); - if (!func->func_type) { + func->type = wasm_functype_new_internal(type_rt); + if (!func->type) { goto failed; } @@ -1340,9 +2040,9 @@ wasm_func_delete(wasm_func_t *func) return; } - if (func->func_type) { - wasm_functype_delete(func->func_type); - func->func_type = NULL; + if (func->type) { + wasm_functype_delete(func->type); + func->type = NULL; } if (func->with_env) { @@ -1356,49 +2056,32 @@ wasm_func_delete(wasm_func_t *func) wasm_runtime_free(func); } -wasm_func_t * +own wasm_func_t * wasm_func_copy(const wasm_func_t *func) { wasm_func_t *cloned = NULL; bh_assert(func); - cloned = malloc_internal(sizeof(wasm_func_t)); - if (!cloned) { + if (!(cloned = func->with_env + ? wasm_func_new_with_env_basic( + func->type, func->u.cb_env.cb, func->u.cb_env.env, + func->u.cb_env.finalizer) + : wasm_func_new_basic(func->type, func->u.cb))) { goto failed; } - cloned->kind = func->kind; - cloned->with_env = func->with_env; - if (cloned->with_env) { - cloned->u.cb_env.cb = func->u.cb_env.cb; - cloned->u.cb_env.env = func->u.cb_env.env; - cloned->u.cb_env.finalizer = func->u.cb_env.finalizer; - } - else { - cloned->u.cb = func->u.cb; - } - cloned->func_idx_rt = func->func_idx_rt; cloned->inst_comm_rt = func->inst_comm_rt; - cloned->func_type = wasm_functype_copy(func->func_type); - if (!cloned->func_type) { - goto failed; - } - return cloned; - -failed: - LOG_DEBUG("%s failed", __FUNCTION__); - wasm_func_delete(cloned); - return NULL; + RETURN_OBJ(cloned, wasm_func_delete) } -wasm_functype_t * +own wasm_functype_t * wasm_func_type(const wasm_func_t *func) { bh_assert(func); - return func->func_type; + return wasm_functype_copy(func->type); } static uint32 @@ -1479,27 +2162,36 @@ argv_to_results(const uint32 *results, switch (def->kind) { case WASM_I32: + { out->kind = WASM_I32; out->of.i32 = *(int32 *)result; result += 1; break; + } case WASM_I64: + { out->kind = WASM_I64; out->of.i64 = *(int64 *)result; result += 2; break; + } case WASM_F32: + { out->kind = WASM_F32; out->of.f32 = *(float32 *)result; result += 1; break; + } case WASM_F64: + { out->kind = WASM_F64; out->of.f64 = *(float64 *)result; result += 2; break; + } default: - LOG_DEBUG("unexpected parameter val type %d", def->kind); + LOG_WARNING("%s meets unsupported type: %d", __FUNCTION__, + def->kind); goto failed; } out++; @@ -1526,9 +2218,13 @@ wasm_func_call(const wasm_func_t *func, WASMFunctionInstanceCommon *func_comm_rt = NULL; size_t param_count, result_count, alloc_count; - bh_assert(func && func->func_type && func->inst_comm_rt); + bh_assert(func && func->type && func->inst_comm_rt); - if (INTERP_MODE == current_runtime_mode()) { + /* TODO: how to check whether its store still exists */ + + cur_trap = NULL; + + if (run_with_bytecode_module_inst(func->inst_comm_rt)) { #if WASM_ENABLE_INTERP != 0 func_comm_rt = ((WASMModuleInstance *)func->inst_comm_rt)->functions + func->func_idx_rt; @@ -1556,54 +2252,58 @@ wasm_func_call(const wasm_func_t *func, /* copy parametes */ if (param_count - && !(argc = params_to_argv(params, - wasm_functype_params(wasm_func_type(func)), - wasm_func_param_arity(func), argv))) { + && !(argc = params_to_argv(params, wasm_functype_params(func->type), + param_count, argv))) { goto failed; } if (!wasm_runtime_create_exec_env_and_call_wasm( func->inst_comm_rt, func_comm_rt, argc, argv)) { - LOG_DEBUG("wasm_runtime_create_exec_env_and_call_wasm failed"); - goto failed; + if (wasm_runtime_get_exception(func->inst_comm_rt)) { + LOG_DEBUG(wasm_runtime_get_exception(func->inst_comm_rt)); + goto failed; + } } /* copy results */ - if (result_count - && !(argc = argv_to_results( - argv, wasm_functype_results(wasm_func_type(func)), - wasm_func_result_arity(func), results))) { - goto failed; + if (result_count) { + if (!(argc = argv_to_results(argv, wasm_functype_results(func->type), + result_count, results))) { + goto failed; + } } FREEIF(argv); - /* should return trap */ return NULL; failed: - LOG_DEBUG("%s failed", __FUNCTION__); FREEIF(argv); - return NULL; + if (cur_trap) { + return cur_trap; + } + else { + if (wasm_runtime_get_exception(func->inst_comm_rt)) { + return wasm_trap_new_internal( + wasm_runtime_get_exception(func->inst_comm_rt)); + } + else { + return wasm_trap_new_internal("wasm_func_call failed"); + } + } } size_t wasm_func_param_arity(const wasm_func_t *func) { - bh_assert(func && func->func_type && func->func_type->params); - return func->func_type->params->num_elems; + bh_assert(func && func->type && func->type->params); + return func->type->params->num_elems; } size_t wasm_func_result_arity(const wasm_func_t *func) { - bh_assert(func && func->func_type && func->func_type->results); - return func->func_type->results->num_elems; -} - -wasm_extern_t * -wasm_func_as_extern(wasm_func_t *func) -{ - return (wasm_extern_t *)func; + bh_assert(func && func->type && func->type->results); + return func->type->results->num_elems; } wasm_global_t * @@ -1622,7 +2322,7 @@ wasm_global_new(wasm_store_t *store, } global->kind = WASM_EXTERN_GLOBAL; - global->type = wasm_globaltype_copy((wasm_globaltype_t *)global_type); + global->type = wasm_globaltype_copy(global_type); if (!global->type) { goto failed; } @@ -1657,7 +2357,7 @@ wasm_global_copy(const wasm_global_t *src) } global->kind = WASM_EXTERN_GLOBAL; - global->type = wasm_globaltype_copy((wasm_globaltype_t *)src->type); + global->type = wasm_globaltype_copy(src->type); if (!global->type) { goto failed; } @@ -1689,7 +2389,6 @@ wasm_global_delete(wasm_global_t *global) if (global->init) { wasm_val_delete(global->init); - wasm_runtime_free(global->init); global->init = NULL; } @@ -1908,7 +2607,7 @@ wasm_global_set(wasm_global_t *global, const wasm_val_t *v) { bh_assert(global && v); - if (INTERP_MODE == current_runtime_mode()) { + if (run_with_bytecode_module_inst(global->inst_comm_rt)) { #if WASM_ENABLE_INTERP != 0 (void)interp_global_set((WASMModuleInstance *)global->inst_comm_rt, global->global_idx_rt, v); @@ -1929,7 +2628,7 @@ wasm_global_get(const wasm_global_t *global, wasm_val_t *out) memset(out, 0, sizeof(wasm_val_t)); - if (INTERP_MODE == current_runtime_mode()) { + if (run_with_bytecode_module_inst(global->inst_comm_rt)) { #if WASM_ENABLE_INTERP != 0 (void)interp_global_get((WASMModuleInstance *)global->inst_comm_rt, global->global_idx_rt, out); @@ -1968,7 +2667,7 @@ wasm_global_new_internal(wasm_store_t *store, */ global->kind = WASM_EXTERN_GLOBAL; - if (INTERP_MODE == current_runtime_mode()) { + if (run_with_bytecode_module_inst(inst_comm_rt)) { #if WASM_ENABLE_INTERP != 0 WASMGlobalInstance *global_interp = ((WASMModuleInstance *)inst_comm_rt)->globals + global_idx_rt; @@ -2006,7 +2705,7 @@ wasm_global_new_internal(wasm_store_t *store, goto failed; } - if (INTERP_MODE == current_runtime_mode()) { + if (run_with_bytecode_module_inst(inst_comm_rt)) { #if WASM_ENABLE_INTERP != 0 interp_global_get((WASMModuleInstance *)inst_comm_rt, global_idx_rt, global->init); @@ -2034,22 +2733,255 @@ wasm_globaltype_t * wasm_global_type(const wasm_global_t *global) { bh_assert(global); - return global->type; + return wasm_globaltype_copy(global->type); } -wasm_extern_t * -wasm_global_as_extern(wasm_global_t *global) +static wasm_table_t * +wasm_table_new_basic(const wasm_tabletype_t *type) { - return (wasm_extern_t *)global; + wasm_table_t *table = NULL; + + bh_assert(type); + + if (!(table = malloc_internal(sizeof(wasm_table_t)))) { + goto failed; + } + + table->kind = WASM_EXTERN_TABLE; + + if (!(table->type = wasm_tabletype_copy(type))) { + goto failed; + } + + RETURN_OBJ(table, wasm_table_delete); +} + +static wasm_table_t * +wasm_table_new_internal(wasm_store_t *store, + uint16 table_idx_rt, + WASMModuleInstanceCommon *inst_comm_rt) +{ + wasm_table_t *table = NULL; + uint8 val_type_rt = 0; + uint32 init_size = 0, max_size = 0; + + check_engine_and_store(singleton_engine, store); + bh_assert(inst_comm_rt); + + if (!(table = malloc_internal(sizeof(wasm_table_t)))) { + goto failed; + } + + table->kind = WASM_EXTERN_TABLE; + + if (run_with_bytecode_module_inst(inst_comm_rt)) { +#if WASM_ENABLE_INTERP != 0 + WASMTableInstance *table_interp = + ((WASMModuleInstance *)inst_comm_rt)->tables[table_idx_rt]; + val_type_rt = table_interp->elem_type; + init_size = table_interp->cur_size; + max_size = table_interp->max_size; +#endif + } + else { +#if WASM_ENABLE_AOT != 0 + AOTModuleInstance *inst_aot = (AOTModuleInstance *)inst_comm_rt; + AOTModule *module_aot = (AOTModule *)inst_aot->aot_module.ptr; + + if (table_idx_rt < module_aot->import_table_count) { + AOTImportTable *table_aot = + module_aot->import_tables + table_idx_rt; + val_type_rt = VALUE_TYPE_FUNCREF; + init_size = table_aot->table_init_size; + max_size = table_aot->table_max_size; + } + else { + AOTTable *table_aot = + module_aot->tables + + (table_idx_rt - module_aot->import_table_count); + val_type_rt = VALUE_TYPE_FUNCREF; + init_size = table_aot->table_init_size; + max_size = table_aot->table_max_size; + } +#endif + } + + if (!(table->type = + wasm_tabletype_new_internal(val_type_rt, init_size, max_size))) { + goto failed; + } + + table->inst_comm_rt = inst_comm_rt; + table->table_idx_rt = table_idx_rt; + + RETURN_OBJ(table, wasm_table_delete); +} + +wasm_table_t * +wasm_table_new(wasm_store_t *store, + const wasm_tabletype_t *table_type, + wasm_ref_t *init) +{ + (void)init; + check_engine_and_store(singleton_engine, store); + return wasm_table_new_basic(table_type); +} + +wasm_table_t * +wasm_table_copy(const wasm_table_t *src) +{ + return wasm_table_new_basic(src->type); } void wasm_table_delete(wasm_table_t *table) -{} +{ + if (!table) { + return; + } + + if (table->type) { + wasm_tabletype_delete(table->type); + table->type = NULL; + } + + wasm_runtime_free(table); +} + +wasm_tabletype_t * +wasm_table_type(const wasm_table_t *table) +{ + bh_assert(table); + return wasm_tabletype_copy(table->type); +} + +static wasm_memory_t * +wasm_memory_new_basic(const wasm_memorytype_t *type) +{ + wasm_memory_t *memory = NULL; + + bh_assert(type); + + if (!(memory = malloc_internal(sizeof(wasm_memory_t)))) { + goto failed; + } + + memory->kind = WASM_EXTERN_MEMORY; + memory->type = wasm_memorytype_copy(type); + + RETURN_OBJ(memory, wasm_memory_delete) +} + +wasm_memory_t * +wasm_memory_new(wasm_store_t *store, const wasm_memorytype_t *type) +{ + check_engine_and_store(singleton_engine, store); + return wasm_memory_new_basic(type); +} + +wasm_memory_t * +wasm_memory_copy(const wasm_memory_t *src) +{ + wasm_memory_t *dst = NULL; + + bh_assert(src); + + if (!(dst = wasm_memory_new_basic(src->type))) { + goto failed; + } + + dst->memory_idx_rt = src->memory_idx_rt; + dst->inst_comm_rt = src->inst_comm_rt; + + RETURN_OBJ(dst, wasm_memory_delete) +} + +static wasm_memory_t * +wasm_memory_new_internal(wasm_store_t *store, + uint16 memory_idx_rt, + WASMModuleInstanceCommon *inst_comm_rt) +{ + wasm_memory_t *memory = NULL; + uint32 min_pages = 0, max_pages = 0; + + check_engine_and_store(singleton_engine, store); + bh_assert(inst_comm_rt); + + if (!(memory = malloc_internal(sizeof(wasm_memory_t)))) { + goto failed; + } + + memory->kind = WASM_EXTERN_MEMORY; + + if (run_with_bytecode_module_inst(inst_comm_rt)) { +#if WASM_ENABLE_INTERP != 0 + WASMMemoryInstance *memory_interp = + ((WASMModuleInstance *)inst_comm_rt)->memories[memory_idx_rt]; + min_pages = memory_interp->cur_page_count; + max_pages = memory_interp->max_page_count; +#endif + } + else { +#if WASM_ENABLE_AOT != 0 + AOTModuleInstance *inst_aot = (AOTModuleInstance *)inst_comm_rt; + AOTModule *module_aot = (AOTModule *)(inst_aot->aot_module.ptr); + + if (memory_idx_rt < module_aot->import_memory_count) { + min_pages = module_aot->import_memories->mem_init_page_count; + max_pages = module_aot->import_memories->mem_max_page_count; + } + else { + min_pages = module_aot->memories->mem_init_page_count; + max_pages = module_aot->memories->mem_max_page_count; + } +#endif + } + + if (!(memory->type = wasm_memorytype_new_internal(min_pages, max_pages))) { + goto failed; + } + + memory->inst_comm_rt = inst_comm_rt; + memory->memory_idx_rt = memory_idx_rt; + + RETURN_OBJ(memory, wasm_memory_delete); +} void wasm_memory_delete(wasm_memory_t *memory) -{} +{ + if (!memory) { + return; + } + + if (memory->type) { + wasm_memorytype_delete(memory->type); + memory->type = NULL; + } + + wasm_runtime_free(memory); +} + +wasm_memorytype_t * +wasm_memory_type(const wasm_memory_t *memory) +{ + bh_assert(memory); + return wasm_memorytype_copy(memory->type); +} + +byte_t * +wasm_memory_data(wasm_memory_t *memory) +{ + return (byte_t *)wasm_runtime_get_memory_data(memory->inst_comm_rt, + memory->memory_idx_rt); +} + +size_t +wasm_memory_data_size(const wasm_memory_t *memory) +{ + return wasm_runtime_get_memory_data_size(memory->inst_comm_rt, + memory->memory_idx_rt); +} #if WASM_ENABLE_INTERP != 0 static bool @@ -2068,8 +3000,12 @@ interp_link_func(const wasm_instance_t *inst, imported_func_interp = module_interp->import_functions + func_idx_rt; bh_assert(imported_func_interp); - cloned = wasm_func_copy(import); - if (!cloned || !bh_vector_append((Vector *)inst->imports, &cloned)) { + if (!(cloned = wasm_func_copy(import))) { + return false; + } + + if (!bh_vector_append((Vector *)inst->imports, &cloned)) { + wasm_func_delete(cloned); return false; } @@ -2127,22 +3063,6 @@ interp_link_global(const WASMModule *module_interp, return true; } -static bool -interp_link_memory(const WASMModule *module_interp, - uint16 memory_inst_index, - wasm_memory_t *import) -{ - return false; -} - -static bool -interp_link_table(const WASMModule *module_interp, - uint16 table_inst_index, - wasm_table_t *import) -{ - return false; -} - static uint32 interp_link(const wasm_instance_t *inst, const WASMModule *module_interp, @@ -2151,10 +3071,6 @@ interp_link(const wasm_instance_t *inst, uint32 i = 0; uint32 import_func_i = 0; uint32 import_global_i = 0; - uint32 import_table_i = 0; - uint32 import_memory_i = 0; - wasm_func_t *func = NULL; - wasm_global_t *global = NULL; bh_assert(inst && module_interp && imports); @@ -2164,40 +3080,35 @@ interp_link(const wasm_instance_t *inst, switch (import_rt->kind) { case IMPORT_KIND_FUNC: - func = wasm_extern_as_func(import); + { if (!interp_link_func(inst, module_interp, import_func_i++, - func)) { + wasm_extern_as_func(import))) { goto failed; } break; + } case IMPORT_KIND_GLOBAL: - global = wasm_extern_as_global(import); + { if (!interp_link_global(module_interp, import_global_i++, - global)) { + wasm_extern_as_global(import))) { goto failed; } break; + } case IMPORT_KIND_MEMORY: - if (!interp_link_memory(module_interp, import_memory_i++, - wasm_extern_as_memory(import))) { - goto failed; - }; - break; case IMPORT_KIND_TABLE: - if (!interp_link_table(module_interp, import_table_i++, - wasm_extern_as_table(import))) { - goto failed; - } + ASSERT_NOT_IMPLEMENTED(); break; default: - NOT_REACHED(); - break; + LOG_WARNING("%s meets unsupported kind: %d", __FUNCTION__, + import_rt->kind); + goto failed; } } - return module_interp->import_count; + return i; failed: LOG_DEBUG("%s failed", __FUNCTION__); @@ -2211,8 +3122,6 @@ interp_process_export(wasm_store_t *store, { WASMExport *exports = NULL; WASMExport *export = NULL; - wasm_func_t *func = NULL; - wasm_global_t *global = NULL; wasm_extern_t *external = NULL; uint32 export_cnt = 0; uint32 i = 0; @@ -2227,30 +3136,56 @@ interp_process_export(wasm_store_t *store, switch (export->kind) { case EXPORT_KIND_FUNC: - func = wasm_func_new_internal( - store, export->index, - (WASMModuleInstanceCommon *)inst_interp); - if (!func) { + { + wasm_func_t *func; + if (!(func = wasm_func_new_internal( + store, export->index, + (WASMModuleInstanceCommon *)inst_interp))) { goto failed; } external = wasm_func_as_extern(func); break; + } case EXPORT_KIND_GLOBAL: - global = wasm_global_new_internal( - store, export->index, - (WASMModuleInstanceCommon *)inst_interp); - if (!global) { + { + wasm_global_t *global; + if (!(global = wasm_global_new_internal( + store, export->index, + (WASMModuleInstanceCommon *)inst_interp))) { goto failed; } external = wasm_global_as_extern(global); break; - case EXPORT_KIND_MEMORY: + } case EXPORT_KIND_TABLE: - /* TODO: */ + { + wasm_table_t *table; + if (!(table = wasm_table_new_internal( + store, export->index, + (WASMModuleInstanceCommon *)inst_interp))) { + goto failed; + } + + external = wasm_table_as_extern(table); break; + } + case EXPORT_KIND_MEMORY: + { + wasm_memory_t *memory; + if (!(memory = wasm_memory_new_internal( + store, export->index, + (WASMModuleInstanceCommon *)inst_interp))) { + goto failed; + } + + external = wasm_memory_as_extern(memory); + break; + } default: + LOG_WARNING("%s meets unsupported kind: %d", __FUNCTION__, + export->kind); goto failed; } @@ -2262,7 +3197,7 @@ interp_process_export(wasm_store_t *store, return true; failed: - LOG_DEBUG("%s failed", __FUNCTION__); + wasm_extern_delete(external); return false; } #endif /* WASM_ENABLE_INTERP */ @@ -2282,13 +3217,12 @@ aot_link_func(const wasm_instance_t *inst, import_aot_func = module_aot->import_funcs + import_func_idx_rt; bh_assert(import_aot_func); - cloned = wasm_func_copy(import); - if (!cloned || !bh_vector_append((Vector *)inst->imports, &cloned)) { + if (!(cloned = wasm_func_copy(import))) { return false; } import_aot_func->call_conv_raw = true; - import_aot_func->attachment = wasm_func_copy(import); + import_aot_func->attachment = cloned; import_aot_func->func_ptr_linked = native_func_trampoline; import->func_idx_rt = import_func_idx_rt; @@ -2308,6 +3242,7 @@ aot_link_global(const AOTModule *module_aot, import_aot_global = module_aot->import_globals + global_idx_rt; bh_assert(import_aot_global); + //TODO: import->type ? val_type = wasm_globaltype_content(wasm_global_type(import)); bh_assert(val_type); @@ -2378,8 +3313,8 @@ aot_link(const wasm_instance_t *inst, break; case WASM_EXTERN_MEMORY: - break; case WASM_EXTERN_TABLE: + ASSERT_NOT_IMPLEMENTED(); break; default: goto failed; @@ -2398,8 +3333,7 @@ aot_process_export(wasm_store_t *store, const AOTModuleInstance *inst_aot, wasm_extern_vec_t *externals) { - uint32 i = 0; - uint32 export_func_i = 0; + uint32 i; wasm_extern_t *external = NULL; AOTModule *module_aot = NULL; @@ -2410,34 +3344,59 @@ aot_process_export(wasm_store_t *store, for (i = 0; i < module_aot->export_count; ++i) { AOTExport *export = module_aot->exports + i; - wasm_func_t *func = NULL; - wasm_global_t *global = NULL; switch (export->kind) { case EXPORT_KIND_FUNC: - func = - wasm_func_new_internal(store, export_func_i++, - (WASMModuleInstanceCommon *)inst_aot); - if (!func) { + { + wasm_func_t *func = NULL; + if (!(func = wasm_func_new_internal( + store, export->index, + (WASMModuleInstanceCommon *)inst_aot))) { goto failed; } external = wasm_func_as_extern(func); break; + } case EXPORT_KIND_GLOBAL: - global = wasm_global_new_internal( - store, export->index, (WASMModuleInstanceCommon *)inst_aot); - if (!global) { + { + wasm_global_t *global = NULL; + if (!(global = wasm_global_new_internal( + store, export->index, + (WASMModuleInstanceCommon *)inst_aot))) { goto failed; } external = wasm_global_as_extern(global); break; - case EXPORT_KIND_MEMORY: + } case EXPORT_KIND_TABLE: + { + wasm_table_t *table; + if (!(table = wasm_table_new_internal( + store, export->index, + (WASMModuleInstanceCommon *)inst_aot))) { + goto failed; + } + + external = wasm_table_as_extern(table); break; + } + case EXPORT_KIND_MEMORY: + { + wasm_memory_t *memory; + if (!(memory = wasm_memory_new_internal( + store, export->index, + (WASMModuleInstanceCommon *)inst_aot))) { + goto failed; + } + + external = wasm_memory_as_extern(memory); + break; + } default: - NOT_REACHED(); + LOG_WARNING("%s meets unsupported kind: %d", __FUNCTION__, + export->kind); goto failed; } @@ -2449,7 +3408,7 @@ aot_process_export(wasm_store_t *store, return true; failed: - LOG_DEBUG("%s failed", __FUNCTION__); + wasm_extern_delete(external); return false; } #endif /* WASM_ENABLE_AOT */ @@ -2458,7 +3417,7 @@ wasm_instance_t * wasm_instance_new(wasm_store_t *store, const wasm_module_t *module, const wasm_extern_t *const imports[], - wasm_trap_t **traps) + own wasm_trap_t **traps) { char error[128] = { 0 }; const uint32 stack_size = 16 * 1024; @@ -2477,18 +3436,19 @@ wasm_instance_new(wasm_store_t *store, /* link module and imports */ if (imports) { - if (INTERP_MODE == current_runtime_mode()) { + if (run_with_bytecode_module(module)) { #if WASM_ENABLE_INTERP != 0 - import_count = ((WASMModule *)*module)->import_count; - INIT_VEC(instance->imports, wasm_extern_vec, import_count); - if (!instance->imports) { - goto failed; - } + import_count = MODULE_INTERP(module)->import_count; + + INIT_VEC(instance->imports, wasm_extern_vec_new_uninitialized, + import_count); if (import_count) { - import_count = interp_link(instance, (WASMModule *)*module, - (wasm_extern_t **)imports); - if ((int32)import_count < 0) { + uint32 actual_link_import_count = interp_link( + instance, MODULE_INTERP(module), (wasm_extern_t **)imports); + /* make sure a complete import list */ + if ((int32)import_count < 0 + || import_count != actual_link_import_count) { goto failed; } } @@ -2496,17 +3456,16 @@ wasm_instance_new(wasm_store_t *store, } else { #if WASM_ENABLE_AOT != 0 - import_count = ((AOTModule *)*module)->import_func_count - + ((AOTModule *)*module)->import_global_count - + ((AOTModule *)*module)->import_memory_count - + ((AOTModule *)*module)->import_table_count; - INIT_VEC(instance->imports, wasm_extern_vec, import_count); - if (!instance->imports) { - goto failed; - } + import_count = MODULE_AOT(module)->import_func_count + + MODULE_AOT(module)->import_global_count + + MODULE_AOT(module)->import_memory_count + + MODULE_AOT(module)->import_table_count; + + INIT_VEC(instance->imports, wasm_extern_vec_new_uninitialized, + import_count); if (import_count) { - import_count = aot_link(instance, (AOTModule *)*module, + import_count = aot_link(instance, MODULE_AOT(module), (wasm_extern_t **)imports); if ((int32)import_count < 0) { goto failed; @@ -2523,8 +3482,8 @@ wasm_instance_new(wasm_store_t *store, goto failed; } - /* fill in inst */ - for (i = 0; i < (uint32)import_count; ++i) { + /* fill with inst */ + for (i = 0; imports && i < (uint32)import_count; ++i) { wasm_extern_t *import = (wasm_extern_t *)imports[i]; switch (import->kind) { case WASM_EXTERN_FUNC: @@ -2549,12 +3508,13 @@ wasm_instance_new(wasm_store_t *store, } /* build the exports list */ - if (INTERP_MODE == current_runtime_mode()) { + if (run_with_bytecode_module_inst(instance->inst_comm_rt)) { #if WASM_ENABLE_INTERP != 0 uint32 export_cnt = ((WASMModuleInstance *)instance->inst_comm_rt)->module->export_count; - INIT_VEC(instance->exports, wasm_extern_vec, export_cnt); + INIT_VEC(instance->exports, wasm_extern_vec_new_uninitialized, + export_cnt); if (!interp_process_export( store, (WASMModuleInstance *)instance->inst_comm_rt, @@ -2566,9 +3526,13 @@ wasm_instance_new(wasm_store_t *store, else { #if WASM_ENABLE_AOT != 0 uint32 export_cnt = - ((AOTModuleInstance *)instance->inst_comm_rt)->export_func_count; + ((AOTModuleInstance *)instance->inst_comm_rt)->export_func_count + + ((AOTModuleInstance *)instance->inst_comm_rt)->export_global_count + + ((AOTModuleInstance *)instance->inst_comm_rt)->export_tab_count + + ((AOTModuleInstance *)instance->inst_comm_rt)->export_mem_count; - INIT_VEC(instance->exports, wasm_extern_vec, export_cnt); + INIT_VEC(instance->exports, wasm_extern_vec_new_uninitialized, + export_cnt); if (!aot_process_export(store, (AOTModuleInstance *)instance->inst_comm_rt, @@ -2591,7 +3555,7 @@ failed: return NULL; } -void +static void wasm_instance_delete_internal(wasm_instance_t *instance) { if (!instance) { @@ -2608,58 +3572,46 @@ wasm_instance_delete_internal(wasm_instance_t *instance) wasm_runtime_free(instance); } -/* will release instance when releasing the store */ void wasm_instance_delete(wasm_instance_t *module) { - /* pass */ + /* will release instance when releasing the store */ } void -wasm_instance_exports(const wasm_instance_t *instance, wasm_extern_vec_t *out) +wasm_instance_exports(const wasm_instance_t *instance, + own wasm_extern_vec_t *out) { bh_assert(instance && out); wasm_extern_vec_copy(out, instance->exports); } -void -wasm_instance_vec_new_uninitialized(wasm_instance_vec_t *out, size_t size) -{ - generic_vec_init_data((Vector *)out, size, sizeof(wasm_instance_t *)); -} - -void -wasm_instance_vec_delete(wasm_instance_vec_t *instance_vec) -{ - size_t i = 0; - if (!instance_vec || !instance_vec->data) { - return; - } - - FREE_VEC_ELEMS(instance_vec, wasm_instance_delete_internal); - bh_vector_destroy((Vector *)instance_vec); -} - wasm_extern_t * wasm_extern_copy(const wasm_extern_t *src) { wasm_extern_t *dst = NULL; - wasm_func_t *func = NULL; - wasm_global_t *global = NULL; bh_assert(src); switch (wasm_extern_kind(src)) { case WASM_EXTERN_FUNC: - func = wasm_func_copy(wasm_extern_as_func_const(src)); - dst = wasm_func_as_extern(func); + dst = wasm_func_as_extern( + wasm_func_copy(wasm_extern_as_func_const(src))); break; case WASM_EXTERN_GLOBAL: - global = wasm_global_copy(wasm_extern_as_global_const(src)); - dst = wasm_global_as_extern(global); + dst = wasm_global_as_extern( + wasm_global_copy(wasm_extern_as_global_const(src))); break; case WASM_EXTERN_MEMORY: + dst = wasm_memory_as_extern( + wasm_memory_copy(wasm_extern_as_memory_const(src))); + break; case WASM_EXTERN_TABLE: + dst = wasm_table_as_extern( + wasm_table_copy(wasm_extern_as_table_const(src))); + break; default: + LOG_WARNING("%s meets unsupported kind: %d", __FUNCTION__, + src->kind); break; } @@ -2690,8 +3642,14 @@ wasm_extern_delete(wasm_extern_t *external) wasm_global_delete(wasm_extern_as_global(external)); break; case WASM_EXTERN_MEMORY: + wasm_memory_delete(wasm_extern_as_memory(external)); + break; case WASM_EXTERN_TABLE: + wasm_table_delete(wasm_extern_as_table(external)); + break; default: + LOG_WARNING("%s meets unsupported kind: %d", __FUNCTION__, + external->kind); break; } } @@ -2699,102 +3657,73 @@ wasm_extern_delete(wasm_extern_t *external) wasm_externkind_t wasm_extern_kind(const wasm_extern_t *extrenal) { - return (wasm_externkind_t)extrenal->kind; + return extrenal->kind; } -wasm_func_t * -wasm_extern_as_func(wasm_extern_t *external) +own wasm_externtype_t * +wasm_extern_type(const wasm_extern_t *external) { - return (wasm_func_t *)external; + switch (wasm_extern_kind(external)) { + case WASM_EXTERN_FUNC: + return wasm_functype_as_externtype( + wasm_func_type(wasm_extern_as_func_const(external))); + case WASM_EXTERN_GLOBAL: + return wasm_globaltype_as_externtype( + wasm_global_type(wasm_extern_as_global_const(external))); + case WASM_EXTERN_MEMORY: + return wasm_memorytype_as_externtype( + wasm_memory_type(wasm_extern_as_memory_const(external))); + case WASM_EXTERN_TABLE: + return wasm_tabletype_as_externtype( + wasm_table_type(wasm_extern_as_table_const(external))); + default: + LOG_WARNING("%s meets unsupported kind: %d", __FUNCTION__, + external->kind); + break; + } + return NULL; } -const wasm_func_t * -wasm_extern_as_func_const(const wasm_extern_t *external) -{ - return (const wasm_func_t *)external; -} +#define BASIC_FOUR_LIST(V) \ + V(func) \ + V(global) \ + V(memory) \ + V(table) -wasm_global_t * -wasm_extern_as_global(wasm_extern_t *external) -{ - return (wasm_global_t *)external; -} - -const wasm_global_t * -wasm_extern_as_global_const(const wasm_extern_t *external) -{ - return (const wasm_global_t *)external; -} - -wasm_memory_t * -wasm_extern_as_memory(wasm_extern_t *external) -{ - return (wasm_memory_t *)external; -} - -const wasm_memory_t * -wasm_extern_as_memory_const(const wasm_extern_t *external) -{ - return (const wasm_memory_t *)external; -} - -wasm_table_t * -wasm_extern_as_table(wasm_extern_t *external) -{ - return (wasm_table_t *)external; -} - -const wasm_table_t * -wasm_extern_as_table_const(const wasm_extern_t *external) -{ - return (const wasm_table_t *)external; -} - -void -wasm_extern_vec_copy(wasm_extern_vec_t *out, const wasm_extern_vec_t *src) -{ - size_t i = 0; - bh_assert(out && src); - - generic_vec_init_data((Vector *)out, src->size, sizeof(wasm_extern_t *)); - if (!out->data) { - goto failed; +#define WASM_EXTERN_AS_OTHER(name) \ + wasm_##name##_t *wasm_extern_as_##name(wasm_extern_t *external) \ + { \ + return (wasm_##name##_t *)external; \ } - for (i = 0; i < src->num_elems; ++i) { - wasm_extern_t *orig = *(src->data + i); - wasm_extern_t *cloned = wasm_extern_copy(orig); - if (!cloned) { - goto failed; - } +BASIC_FOUR_LIST(WASM_EXTERN_AS_OTHER) +#undef WASM_EXTERN_AS_OTHER - if (!bh_vector_append((Vector *)out, &cloned)) { - goto failed; - } +#define WASM_OTHER_AS_EXTERN(name) \ + wasm_extern_t *wasm_##name##_as_extern(wasm_##name##_t *other) \ + { \ + return (wasm_extern_t *)other; \ } - return; +BASIC_FOUR_LIST(WASM_OTHER_AS_EXTERN) +#undef WASM_OTHER_AS_EXTERN -failed: - LOG_DEBUG("%s failed", __FUNCTION__); - wasm_extern_vec_delete(out); - return; -} - -void -wasm_extern_vec_new_uninitialized(wasm_extern_vec_t *out, size_t size) -{ - generic_vec_init_data((Vector *)out, size, sizeof(wasm_extern_t *)); -} - -void -wasm_extern_vec_delete(wasm_extern_vec_t *extern_vec) -{ - size_t i = 0; - if (!extern_vec || !extern_vec->data) { - return; +#define WASM_EXTERN_AS_OTHER_CONST(name) \ + const wasm_##name##_t *wasm_extern_as_##name##_const( \ + const wasm_extern_t *external) \ + { \ + return (const wasm_##name##_t *)external; \ } - FREE_VEC_ELEMS(extern_vec, wasm_extern_delete); - bh_vector_destroy((Vector *)extern_vec); -} +BASIC_FOUR_LIST(WASM_EXTERN_AS_OTHER_CONST) +#undef WASM_EXTERN_AS_OTHER_CONST + +#define WASM_OTHER_AS_EXTERN_CONST(name) \ + const wasm_extern_t *wasm_##name##_as_extern_const( \ + const wasm_##name##_t *other) \ + { \ + return (const wasm_extern_t *)other; \ + } + +BASIC_FOUR_LIST(WASM_OTHER_AS_EXTERN_CONST) +#undef WASM_OTHER_AS_EXTERN_CONST diff --git a/core/iwasm/common/wasm_c_api_internal.h b/core/iwasm/common/wasm_c_api_internal.h index f2d5c65f8..b308968be 100644 --- a/core/iwasm/common/wasm_c_api_internal.h +++ b/core/iwasm/common/wasm_c_api_internal.h @@ -24,17 +24,9 @@ WASM_DECLARE_VEC(module, *) WASM_DECLARE_VEC(instance, *) /* Runtime Environment */ -typedef enum runtime_mode_e { - INTERP_MODE = 0, - JIT_MODE, - AOT_MODE -} runtime_mode_e; - struct wasm_engine_t { /* support one store for now */ wasm_store_vec_t *stores; - /* Interpreter by deault */ - runtime_mode_e mode; }; struct wasm_store_t { @@ -64,13 +56,13 @@ struct wasm_globaltype_t { struct wasm_tabletype_t { uint32 extern_kind; /* always be WASM_FUNCREF */ - wasm_valtype_t *type; - wasm_limits_t *limits; + wasm_valtype_t *val_type; + wasm_limits_t limits; }; struct wasm_memorytype_t { uint32 extern_kind; - wasm_limits_t *limits; + wasm_limits_t limits; }; struct wasm_externtype_t { @@ -78,16 +70,15 @@ struct wasm_externtype_t { uint8 data[1]; }; -struct wasm_import_type_t { - uint32 extern_kind; +struct wasm_importtype_t { wasm_name_t *module_name; wasm_name_t *name; + wasm_externtype_t *extern_type; }; -struct wasm_export_type_t { - uint32 extern_kind; - wasm_name_t *module_name; +struct wasm_exporttype_t { wasm_name_t *name; + wasm_externtype_t *extern_type; }; /* Runtime Objects */ @@ -104,7 +95,7 @@ struct wasm_func_t { wasm_name_t *name; uint16 kind; - wasm_functype_t *func_type; + wasm_functype_t *type; bool with_env; union { @@ -169,7 +160,7 @@ struct wasm_table_t { struct wasm_extern_t { wasm_name_t *module_name; wasm_name_t *name; - uint16 kind; + wasm_externkind_t kind; uint8 data[1]; }; diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index 8e122906c..5c6333604 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -454,14 +454,16 @@ wasm_runtime_destroy_registered_module_list() bh_list_remove(registered_module_list, reg_module); /* now, it is time to release every module in the runtime */ + if (reg_module->module->module_type == Wasm_Module_Bytecode) { #if WASM_ENABLE_INTERP != 0 - if (reg_module->module->module_type == Wasm_Module_Bytecode) wasm_unload((WASMModule *)reg_module->module); #endif + } + else { #if WASM_ENABLE_AOT != 0 - if (reg_module->module->module_type == Wasm_Module_AoT) aot_unload((AOTModule *)reg_module->module); #endif + } /* destroy the file buffer */ if (destroyer && reg_module->orig_file_buf) { @@ -4318,3 +4320,244 @@ wasm_runtime_dump_call_stack(WASMExecEnv *exec_env) } #endif /* end of WASM_ENABLE_DUMP_CALL_STACK */ +bool +wasm_runtime_get_export_func_type(const WASMModuleCommon *module_comm, + const WASMExport *export, + WASMType **out) +{ +#if WASM_ENABLE_INTERP != 0 + if (module_comm->module_type == Wasm_Module_Bytecode) { + WASMModule *module = (WASMModule *)module_comm; + + if (export->index < module->import_function_count) { + *out = + module->import_functions[export->index].u.function.func_type; + } + else { + *out = + module->functions[export->index - module->import_function_count] + ->func_type; + } + return true; + } +#endif + +#if WASM_ENABLE_AOT != 0 + if (module_comm->module_type == Wasm_Module_AoT) { + AOTModule *module = (AOTModule *)module_comm; + + if (export->index < module->import_func_count) { + *out = module->func_types[module->import_funcs[export->index] + .func_type_index]; + } + else { + *out = + module->func_types[module->func_type_indexes + [export->index - module->import_func_count]]; + } + return true; + } +#endif + return false; +} + +bool +wasm_runtime_get_export_global_type(const WASMModuleCommon *module_comm, + const WASMExport *export, + uint8 *out_val_type, + bool *out_mutability) +{ +#if WASM_ENABLE_INTERP != 0 + if (module_comm->module_type == Wasm_Module_Bytecode) { + WASMModule *module = (WASMModule *)module_comm; + + if (export->index < module->import_global_count) { + WASMGlobalImport *import_global = + &((module->import_globals + export->index)->u.global); + *out_val_type = import_global->type; + *out_mutability = import_global->is_mutable; + } + else { + WASMGlobal *global = + module->globals + (export->index - module->import_global_count); + *out_val_type = global->type; + *out_mutability = global->is_mutable; + } + return true; + } +#endif + +#if WASM_ENABLE_AOT != 0 + if (module_comm->module_type == Wasm_Module_AoT) { + AOTModule *module = (AOTModule *)module_comm; + + if (export->index < module->import_global_count) { + AOTImportGlobal *import_global = + module->import_globals + export->index; + *out_val_type = import_global->type; + *out_mutability = import_global->is_mutable; + } + else { + AOTGlobal *global = + module->globals + (export->index - module->import_global_count); + *out_val_type = global->type; + *out_mutability = global->is_mutable; + } + return true; + } +#endif + return false; +} + +bool +wasm_runtime_get_export_memory_type(const WASMModuleCommon *module_comm, + const WASMExport *export, + uint32 *out_min_page, + uint32 *out_max_page) +{ +#if WASM_ENABLE_INTERP != 0 + if (module_comm->module_type == Wasm_Module_Bytecode) { + WASMModule *module = (WASMModule *)module_comm; + + if (export->index < module->import_memory_count) { + WASMMemoryImport *import_memory = + &((module->import_memories + export->index)->u.memory); + *out_min_page = import_memory->init_page_count; + *out_max_page = import_memory->max_page_count; + } + else { + WASMMemory *memory = + module->memories + (export->index - module->import_memory_count); + *out_min_page = memory->init_page_count; + *out_max_page = memory->max_page_count; + } + return true; + } +#endif + +#if WASM_ENABLE_AOT != 0 + if (module_comm->module_type == Wasm_Module_AoT) { + AOTModule *module = (AOTModule *)module_comm; + + if (export->index < module->import_memory_count) { + AOTImportMemory *import_memory = + module->import_memories + export->index; + *out_min_page = import_memory->mem_init_page_count; + *out_max_page = import_memory->mem_max_page_count; + } + else { + AOTMemory *memory = + module->memories + (export->index - module->import_memory_count); + *out_min_page = memory->mem_init_page_count; + *out_max_page = memory->mem_max_page_count; + } + return true; + } +#endif + return false; +} + +bool +wasm_runtime_get_export_table_type(const WASMModuleCommon *module_comm, + const WASMExport *export, + uint8 *out_elem_type, + uint32 *out_min_size, + uint32 *out_max_size) +{ +#if WASM_ENABLE_INTERP != 0 + if (module_comm->module_type == Wasm_Module_Bytecode) { + WASMModule *module = (WASMModule *)module_comm; + + if (export->index < module->import_table_count) { + WASMTableImport *import_table = + &((module->import_tables + export->index)->u.table); + *out_elem_type = import_table->elem_type; + *out_min_size = import_table->init_size; + *out_max_size = import_table->max_size; + } + else { + WASMTable *table = + module->tables + (export->index - module->import_table_count); + *out_elem_type = table->elem_type; + *out_min_size = table->init_size; + *out_max_size = table->max_size; + } + return true; + } +#endif + +#if WASM_ENABLE_AOT != 0 + if (module_comm->module_type == Wasm_Module_AoT) { + AOTModule *module = (AOTModule *)module_comm; + + if (export->index < module->import_table_count) { + AOTImportTable *import_table = + module->import_tables + export->index; + *out_elem_type = VALUE_TYPE_FUNCREF; + *out_min_size = import_table->table_init_size; + *out_max_size = import_table->table_max_size; + } + else { + AOTTable *table = + module->tables + (export->index - module->import_table_count); + *out_elem_type = table->elem_type; + *out_min_size = table->table_init_size; + *out_max_size = table->table_max_size; + } + return true; + } +#endif + return false; +} + +uint8 * +wasm_runtime_get_memory_data(const WASMModuleInstanceCommon *module_inst_comm, + uint32 memory_inst_idx) +{ +#if WASM_ENABLE_INTERP != 0 + if (module_inst_comm->module_type == Wasm_Module_Bytecode) { + WASMModuleInstance *module_inst = + (WASMModuleInstance *)module_inst_comm; + WASMMemoryInstance *memory_inst = + module_inst->memories[memory_inst_idx]; + return memory_inst->memory_data; + } +#endif + +#if WASM_ENABLE_AOT != 0 + if (module_inst_comm->module_type == Wasm_Module_AoT) { + AOTModuleInstance *module_inst = (AOTModuleInstance *)module_inst_comm; + AOTMemoryInstance *memory_inst = + (AOTMemoryInstance*)module_inst->memories.ptr + memory_inst_idx; + return memory_inst->memory_data.ptr; + } +#endif + return NULL; +} + +uint32 +wasm_runtime_get_memory_data_size( + const WASMModuleInstanceCommon *module_inst_comm, + uint32 memory_inst_idx) +{ +#if WASM_ENABLE_INTERP != 0 + if (module_inst_comm->module_type == Wasm_Module_Bytecode) { + WASMModuleInstance *module_inst = + (WASMModuleInstance *)module_inst_comm; + WASMMemoryInstance *memory_inst = + module_inst->memories[memory_inst_idx]; + return memory_inst->cur_page_count * memory_inst->num_bytes_per_page; + } +#endif + +#if WASM_ENABLE_AOT != 0 + if (module_inst_comm->module_type == Wasm_Module_AoT) { + AOTModuleInstance *module_inst = (AOTModuleInstance *)module_inst_comm; + AOTMemoryInstance *memory_inst = + (AOTMemoryInstance*)module_inst->memories.ptr + memory_inst_idx; + return memory_inst->cur_page_count * memory_inst->num_bytes_per_page; + } +#endif + return 0; +} + diff --git a/core/iwasm/common/wasm_runtime_common.h b/core/iwasm/common/wasm_runtime_common.h index 01a0c21be..6be32fae1 100644 --- a/core/iwasm/common/wasm_runtime_common.h +++ b/core/iwasm/common/wasm_runtime_common.h @@ -744,6 +744,38 @@ wasm_runtime_finalize_call_function(WASMExecEnv *exec_env, bool ret, uint32 *argv); #endif +bool +wasm_runtime_get_export_func_type(const WASMModuleCommon *module_comm, + const WASMExport *export, + WASMType **out); + +bool +wasm_runtime_get_export_global_type(const WASMModuleCommon *module_comm, + const WASMExport *export, + uint8 *out_val_type, + bool *out_mutability); + +bool +wasm_runtime_get_export_memory_type(const WASMModuleCommon *module_comm, + const WASMExport *export, + uint32 *out_min_page, + uint32 *out_max_page); + +bool +wasm_runtime_get_export_table_type(const WASMModuleCommon *module_comm, + const WASMExport *export, + uint8 *out_elem_type, + uint32 *out_min_size, + uint32 *out_max_size); + +uint8 * +wasm_runtime_get_memory_data(const WASMModuleInstanceCommon *module_inst_comm, + uint32 memory_inst_idx); + +uint32 +wasm_runtime_get_memory_data_size(const WASMModuleInstanceCommon *module_inst_comm, + uint32 memory_inst_idx); + #ifdef __cplusplus } #endif diff --git a/core/iwasm/include/wasm_c_api.h b/core/iwasm/include/wasm_c_api.h index 6f1a9c519..88e514be0 100644 --- a/core/iwasm/include/wasm_c_api.h +++ b/core/iwasm/include/wasm_c_api.h @@ -29,15 +29,15 @@ extern "C" { // Auxiliaries // Machine types -#if (__STDC_VERSION__ > 199901L) -inline void assertions() { +#if (__STDC_VERSION__) > 199901L +inline void assertions(void) { static_assert(sizeof(float) == sizeof(uint32_t), "incompatible float type"); static_assert(sizeof(double) == sizeof(uint64_t), "incompatible double type"); static_assert(sizeof(intptr_t) == sizeof(uint32_t) || sizeof(intptr_t) == sizeof(uint64_t), "incompatible pointer type"); } -#endif /* __STDC_VERSION__ > 199901L */ +#endif typedef char byte_t; typedef float float32_t; @@ -79,7 +79,7 @@ typedef double float64_t; // Vectors // size: capacity // num_elems: current number of elements -// size_of_elem: size of one element +// size_of_elem: size of one elemen #define WASM_DECLARE_VEC(name, ptr_or_none) \ typedef struct wasm_##name##_vec_t { \ size_t size; \ @@ -115,6 +115,12 @@ typedef wasm_byte_vec_t wasm_name_t; static inline void wasm_name_new_from_string( own wasm_name_t* out, const char* s +) { + wasm_name_new(out, strlen(s), s); +} + +static inline void wasm_name_new_from_string_nt( + own wasm_name_t* out, const char* s ) { wasm_name_new(out, strlen(s) + 1, s); } @@ -123,11 +129,21 @@ static inline void wasm_name_new_from_string( /////////////////////////////////////////////////////////////////////////////// // Runtime Environment +// Configuration + +WASM_DECLARE_OWN(config) + +WASM_API_EXTERN own wasm_config_t* wasm_config_new(void); + +// Embedders may provide custom functions for manipulating configs. + + // Engine WASM_DECLARE_OWN(engine) -WASM_API_EXTERN own wasm_engine_t* wasm_engine_new(); +WASM_API_EXTERN own wasm_engine_t* wasm_engine_new(void); +WASM_API_EXTERN own wasm_engine_t* wasm_engine_new_with_config(own wasm_config_t*); // Store @@ -162,7 +178,7 @@ static const uint32_t wasm_limits_max_default = 0xffffffff; WASM_DECLARE_OWN(name) \ WASM_DECLARE_VEC(name, *) \ \ - WASM_API_EXTERN own wasm_##name##_t* wasm_##name##_copy(wasm_##name##_t*); + WASM_API_EXTERN own wasm_##name##_t* wasm_##name##_copy(const wasm_##name##_t*); // Value Types @@ -334,7 +350,12 @@ WASM_DECLARE_VEC(val, ) WASM_DECLARE_OWN(name) \ \ WASM_API_EXTERN own wasm_##name##_t* wasm_##name##_copy(const wasm_##name##_t*); \ - WASM_API_EXTERN bool wasm_##name##_same(const wasm_##name##_t*, const wasm_##name##_t*); + WASM_API_EXTERN bool wasm_##name##_same(const wasm_##name##_t*, const wasm_##name##_t*); \ + \ + WASM_API_EXTERN void* wasm_##name##_get_host_info(const wasm_##name##_t*); \ + WASM_API_EXTERN void wasm_##name##_set_host_info(wasm_##name##_t*, void*); \ + WASM_API_EXTERN void wasm_##name##_set_host_info_with_finalizer( \ + wasm_##name##_t*, void*, void (*)(void*)); #define WASM_DECLARE_REF(name) \ WASM_DECLARE_REF_BASE(name) \ @@ -354,17 +375,42 @@ WASM_DECLARE_VEC(val, ) WASM_DECLARE_REF_BASE(ref) + +// Frames + +WASM_DECLARE_OWN(frame) +WASM_DECLARE_VEC(frame, *) +WASM_API_EXTERN own wasm_frame_t* wasm_frame_copy(const wasm_frame_t*); + +WASM_API_EXTERN struct wasm_instance_t* wasm_frame_instance(const wasm_frame_t*); +WASM_API_EXTERN uint32_t wasm_frame_func_index(const wasm_frame_t*); +WASM_API_EXTERN size_t wasm_frame_func_offset(const wasm_frame_t*); +WASM_API_EXTERN size_t wasm_frame_module_offset(const wasm_frame_t*); + + // Traps typedef wasm_name_t wasm_message_t; // null terminated -WASM_DECLARE_REF_BASE(trap) +WASM_DECLARE_REF(trap) WASM_API_EXTERN own wasm_trap_t* wasm_trap_new(wasm_store_t* store, const wasm_message_t*); WASM_API_EXTERN void wasm_trap_message(const wasm_trap_t*, own wasm_message_t* out); +WASM_API_EXTERN own wasm_frame_t* wasm_trap_origin(const wasm_trap_t*); +WASM_API_EXTERN void wasm_trap_trace(const wasm_trap_t*, own wasm_frame_vec_t* out); + + +// Foreign Objects + +WASM_DECLARE_REF(foreign) + +WASM_API_EXTERN own wasm_foreign_t* wasm_foreign_new(wasm_store_t*); + // Modules +// WASM_DECLARE_SHARABLE_REF(module) + #ifndef WASM_MODULE_T_DEFINED #define WASM_MODULE_T_DEFINED struct WASMModuleCommon; @@ -374,12 +420,9 @@ typedef struct WASMModuleCommon *wasm_module_t; WASM_API_EXTERN own wasm_module_t* wasm_module_new( wasm_store_t*, const wasm_byte_vec_t* binary); -WASM_API_EXTERN bool wasm_module_validate(wasm_store_t*, const wasm_byte_vec_t* binary); - WASM_API_EXTERN void wasm_module_delete(own wasm_module_t*); -WASM_API_EXTERN own wasm_module_t* wasm_module_copy(const wasm_module_t*); -WASM_API_EXTERN bool wasm_module_same(const wasm_module_t*, const wasm_module_t*); +WASM_API_EXTERN bool wasm_module_validate(wasm_store_t*, const wasm_byte_vec_t* binary); WASM_API_EXTERN void wasm_module_imports(const wasm_module_t*, own wasm_importtype_vec_t* out); WASM_API_EXTERN void wasm_module_exports(const wasm_module_t*, own wasm_exporttype_vec_t* out); @@ -393,7 +436,7 @@ WASM_API_EXTERN own wasm_module_t* wasm_module_deserialize(wasm_store_t*, const WASM_DECLARE_REF(func) typedef own wasm_trap_t* (*wasm_func_callback_t)( - const wasm_val_t args[], wasm_val_t results[]); + const wasm_val_t args[], own wasm_val_t results[]); typedef own wasm_trap_t* (*wasm_func_callback_with_env_t)( void* env, const wasm_val_t args[], wasm_val_t results[]); @@ -413,7 +456,7 @@ WASM_API_EXTERN own wasm_trap_t* wasm_func_call( // Global Instances -WASM_DECLARE_REF_BASE(global) +WASM_DECLARE_REF(global) WASM_API_EXTERN own wasm_global_t* wasm_global_new( wasm_store_t*, const wasm_globaltype_t*, const wasm_val_t*); @@ -426,7 +469,7 @@ WASM_API_EXTERN void wasm_global_set(wasm_global_t*, const wasm_val_t*); // Table Instances -WASM_DECLARE_REF_BASE(table) +WASM_DECLARE_REF(table) typedef uint32_t wasm_table_size_t; @@ -444,7 +487,7 @@ WASM_API_EXTERN bool wasm_table_grow(wasm_table_t*, wasm_table_size_t delta, was // Memory Instances -WASM_DECLARE_REF_BASE(memory) +WASM_DECLARE_REF(memory) typedef uint32_t wasm_memory_pages_t; @@ -463,7 +506,7 @@ WASM_API_EXTERN bool wasm_memory_grow(wasm_memory_t*, wasm_memory_pages_t delta) // Externals -WASM_DECLARE_REF_BASE(extern) +WASM_DECLARE_REF(extern) WASM_DECLARE_VEC(extern, *) WASM_API_EXTERN wasm_externkind_t wasm_extern_kind(const wasm_extern_t*); @@ -492,10 +535,10 @@ WASM_API_EXTERN const wasm_memory_t* wasm_extern_as_memory_const(const wasm_exte // Module Instances -WASM_DECLARE_REF_BASE(instance) +WASM_DECLARE_REF(instance) WASM_API_EXTERN own wasm_instance_t* wasm_instance_new( - wasm_store_t*, const wasm_module_t*, const wasm_extern_t* const imports[], + wasm_store_t*, const wasm_module_t*, const wasm_extern_t *const imports[], own wasm_trap_t** ); @@ -505,32 +548,38 @@ WASM_API_EXTERN void wasm_instance_exports(const wasm_instance_t*, own wasm_exte /////////////////////////////////////////////////////////////////////////////// // Convenience +// Vectors + +#define WASM_EMPTY_VEC {0, NULL, 0, 0} +#define WASM_ARRAY_VEC(array) {sizeof(array)/sizeof(*(array)), array, sizeof(array)/sizeof(*(array)), sizeof(*(array))} + + // Value Type construction short-hands -static inline own wasm_valtype_t* wasm_valtype_new_i32() { +static inline own wasm_valtype_t* wasm_valtype_new_i32(void) { return wasm_valtype_new(WASM_I32); } -static inline own wasm_valtype_t* wasm_valtype_new_i64() { +static inline own wasm_valtype_t* wasm_valtype_new_i64(void) { return wasm_valtype_new(WASM_I64); } -static inline own wasm_valtype_t* wasm_valtype_new_f32() { +static inline own wasm_valtype_t* wasm_valtype_new_f32(void) { return wasm_valtype_new(WASM_F32); } -static inline own wasm_valtype_t* wasm_valtype_new_f64() { +static inline own wasm_valtype_t* wasm_valtype_new_f64(void) { return wasm_valtype_new(WASM_F64); } -static inline own wasm_valtype_t* wasm_valtype_new_anyref() { +static inline own wasm_valtype_t* wasm_valtype_new_anyref(void) { return wasm_valtype_new(WASM_ANYREF); } -static inline own wasm_valtype_t* wasm_valtype_new_funcref() { +static inline own wasm_valtype_t* wasm_valtype_new_funcref(void) { return wasm_valtype_new(WASM_FUNCREF); } // Function Types construction short-hands -static inline own wasm_functype_t* wasm_functype_new_0_0() { +static inline own wasm_functype_t* wasm_functype_new_0_0(void) { wasm_valtype_vec_t params, results; wasm_valtype_vec_new_empty(¶ms); wasm_valtype_vec_new_empty(&results); @@ -677,6 +726,13 @@ static inline void* wasm_val_ptr(const wasm_val_t* val) { #endif } +#define WASM_I32_VAL(i) {.kind = WASM_I32, .of = {.i32 = i}} +#define WASM_I64_VAL(i) {.kind = WASM_I64, .of = {.i64 = i}} +#define WASM_F32_VAL(z) {.kind = WASM_F32, .of = {.f32 = z}} +#define WASM_F64_VAL(z) {.kind = WASM_F64, .of = {.f64 = z}} +#define WASM_REF_VAL(r) {.kind = WASM_ANYREF, .of = {.ref = r}} +#define WASM_INIT_VAL {.kind = WASM_ANYREF, .of = {.ref = NULL}} + /////////////////////////////////////////////////////////////////////////////// diff --git a/core/iwasm/interpreter/wasm_interp_classic.c b/core/iwasm/interpreter/wasm_interp_classic.c index 3861376a5..3a0288808 100644 --- a/core/iwasm/interpreter/wasm_interp_classic.c +++ b/core/iwasm/interpreter/wasm_interp_classic.c @@ -3417,21 +3417,18 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, if (function->is_import_func) { #if WASM_ENABLE_MULTI_MODULE != 0 if (function->import_module_inst) { - LOG_DEBUG("it is a function of a sub module"); wasm_interp_call_func_import(module_inst, exec_env, function, frame); } else #endif { - LOG_DEBUG("it is an native function"); /* it is a native function */ wasm_interp_call_func_native(module_inst, exec_env, function, frame); } } else { - LOG_DEBUG("it is a function of the module itself"); wasm_interp_call_func_bytecode(module_inst, exec_env, function, frame); } @@ -3440,13 +3437,6 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, for (i = 0; i < function->ret_cell_num; i++) { argv[i] = *(frame->sp + i - function->ret_cell_num); } - - if (function->ret_cell_num) { - LOG_DEBUG("first return value argv[0]=%d", argv[0]); - } - else { - LOG_DEBUG("no return value"); - } } else { #if WASM_ENABLE_DUMP_CALL_STACK != 0 diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index c1af8a8fd..edcf15f44 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -377,7 +377,6 @@ const_str_list_insert(const uint8 *str, uint32 len, WASMModule *module, } if (node) { - LOG_DEBUG("reuse %s", node->str); return node->str; } @@ -703,7 +702,8 @@ wasm_loader_resolve_function(const char *module_name, module_reg = wasm_runtime_find_module_registered(module_name); if (!module_reg || module_reg->module_type != Wasm_Module_Bytecode) { - LOG_DEBUG("can not find a module named %s for function", module_name); + LOG_DEBUG("can not find a module named %s for function %s", + module_name, function_name); set_error_buf(error_buf, error_buf_size, "unknown import"); return NULL; } @@ -1722,8 +1722,6 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, /* 0x00/0x01/0x02/0x03 */ kind = read_uint8(p); - LOG_DEBUG("import #%d: (%s, %s), kind: %d", - i, sub_module_name, field_name, kind); switch (kind) { case IMPORT_KIND_FUNC: /* import function */ bh_assert(import_functions); @@ -2947,7 +2945,6 @@ load_from_sections(WASMModule *module, WASMSection *sections, while (section) { buf = section->section_body; buf_end = buf + section->section_body_size; - LOG_DEBUG("load section, type: %d", section->section_type); switch (section->section_type) { case SECTION_TYPE_USER: /* unsupported user section, ignore it. */ diff --git a/samples/simple/profiles/arm-interp/toolchain.cmake b/samples/simple/profiles/arm-interp/toolchain.cmake index 2bd47b420..604141d0a 100644 --- a/samples/simple/profiles/arm-interp/toolchain.cmake +++ b/samples/simple/profiles/arm-interp/toolchain.cmake @@ -1,3 +1,5 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception INCLUDE(CMakeForceCompiler) SET(CMAKE_SYSTEM_NAME Linux) # this one is important diff --git a/samples/simple/profiles/arm-interp/wamr_config_simple.cmake b/samples/simple/profiles/arm-interp/wamr_config_simple.cmake index db33d5f60..90bb2f8d1 100644 --- a/samples/simple/profiles/arm-interp/wamr_config_simple.cmake +++ b/samples/simple/profiles/arm-interp/wamr_config_simple.cmake @@ -1,3 +1,5 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception set (WAMR_BUILD_PLATFORM "linux") set (WAMR_BUILD_TARGET ARM) set (WAMR_BUILD_INTERP 1) diff --git a/samples/simple/profiles/arm64-aot/toolchain.cmake b/samples/simple/profiles/arm64-aot/toolchain.cmake index 6d674ce70..182504fea 100644 --- a/samples/simple/profiles/arm64-aot/toolchain.cmake +++ b/samples/simple/profiles/arm64-aot/toolchain.cmake @@ -1,3 +1,5 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception INCLUDE(CMakeForceCompiler) SET(CMAKE_SYSTEM_NAME Linux) # this one is important diff --git a/samples/simple/profiles/arm64-aot/wamr_config_simple.cmake b/samples/simple/profiles/arm64-aot/wamr_config_simple.cmake index 81d8103ea..7e6604885 100644 --- a/samples/simple/profiles/arm64-aot/wamr_config_simple.cmake +++ b/samples/simple/profiles/arm64-aot/wamr_config_simple.cmake @@ -1,3 +1,5 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception set (WAMR_BUILD_PLATFORM "linux") set (WAMR_BUILD_TARGET AARCH64) set (WAMR_BUILD_INTERP 1) diff --git a/samples/simple/profiles/arm64-interp/toolchain.cmake b/samples/simple/profiles/arm64-interp/toolchain.cmake index 6d674ce70..182504fea 100644 --- a/samples/simple/profiles/arm64-interp/toolchain.cmake +++ b/samples/simple/profiles/arm64-interp/toolchain.cmake @@ -1,3 +1,5 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception INCLUDE(CMakeForceCompiler) SET(CMAKE_SYSTEM_NAME Linux) # this one is important diff --git a/samples/simple/profiles/arm64-interp/wamr_config_simple.cmake b/samples/simple/profiles/arm64-interp/wamr_config_simple.cmake index 804e71cba..13fb9ac13 100644 --- a/samples/simple/profiles/arm64-interp/wamr_config_simple.cmake +++ b/samples/simple/profiles/arm64-interp/wamr_config_simple.cmake @@ -1,3 +1,5 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception set (WAMR_BUILD_PLATFORM "linux") set (WAMR_BUILD_TARGET AARCH64) set (WAMR_BUILD_INTERP 1) diff --git a/samples/simple/profiles/host-aot/wamr_config_simple.cmake b/samples/simple/profiles/host-aot/wamr_config_simple.cmake index a3317f037..1f8cf9f8f 100644 --- a/samples/simple/profiles/host-aot/wamr_config_simple.cmake +++ b/samples/simple/profiles/host-aot/wamr_config_simple.cmake @@ -1,3 +1,5 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception set (WAMR_BUILD_PLATFORM "linux") set (WAMR_BUILD_TARGET X86_64) set (WAMR_BUILD_INTERP 1) diff --git a/samples/simple/profiles/host-interp/wamr_config_simple.cmake b/samples/simple/profiles/host-interp/wamr_config_simple.cmake index a3317f037..1f8cf9f8f 100644 --- a/samples/simple/profiles/host-interp/wamr_config_simple.cmake +++ b/samples/simple/profiles/host-interp/wamr_config_simple.cmake @@ -1,3 +1,5 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception set (WAMR_BUILD_PLATFORM "linux") set (WAMR_BUILD_TARGET X86_64) set (WAMR_BUILD_INTERP 1) diff --git a/samples/simple/src/iwasm_main.c b/samples/simple/src/iwasm_main.c index 4d0a355fb..31d897ab9 100644 --- a/samples/simple/src/iwasm_main.c +++ b/samples/simple/src/iwasm_main.c @@ -1,3 +1,7 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ #ifndef CONNECTION_UART #include diff --git a/samples/simple/src/main.c b/samples/simple/src/main.c index 5bf24ce67..26de7eecd 100644 --- a/samples/simple/src/main.c +++ b/samples/simple/src/main.c @@ -1,3 +1,8 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + extern void iwasm_main(); int main(int argc, char *argv[]) { diff --git a/samples/wasm-c-api/CMakeLists.txt b/samples/wasm-c-api/CMakeLists.txt index 93235eaff..144bfa89c 100644 --- a/samples/wasm-c-api/CMakeLists.txt +++ b/samples/wasm-c-api/CMakeLists.txt @@ -31,10 +31,10 @@ if(NOT DEFINED WAMR_BUILD_INTERP) endif() if(NOT DEFINED WAMR_BUILD_AOT) - set(WAMR_BUILD_AOT 0) + set(WAMR_BUILD_AOT 1) endif() -if(NOT DEFINED WAMR_BUILD_JOT) +if(NOT DEFINED WAMR_BUILD_JIT) set(WAMR_BUILD_JIT 0) endif() @@ -43,7 +43,7 @@ set(WAMR_BUILD_LIBC_WASI 0) set(WAMR_BUILD_MULTI_MODULE 1) if(NOT DEFINED WAMR_BUILD_FAST_INTERP) - set(WAMR_BUILD_FAST_INTERP 0) + set(WAMR_BUILD_FAST_INTERP 1) endif() if (NOT MSVC) @@ -68,6 +68,7 @@ add_library(vmlib STATIC ${WAMR_RUNTIME_LIB_SOURCE}) if (MSVC) target_compile_definitions(vmlib PRIVATE WASM_API_EXTERN=) endif() +target_link_libraries (vmlib ${LLVM_AVAILABLE_LIBS} ${UV_A_LIBS} -lm -ldl -lpthread) ################################################ ################ application related ################ @@ -86,29 +87,54 @@ include (${SHARED_DIR}/utils/uncommon/shared_uncommon.cmake) set(MM_UTIL src/utils/multi_module_utils.c) # build executable for each .c -file(GLOB SOURCES src/*.c) -foreach(SRC ${SOURCES}) - get_filename_component(APPNAME ${SRC} NAME_WE) +set(EXAMPLES + hello + callback + global + reflect + trap + # multi # AOT/JIT return multiple values + # globalexportimport # AOT/JIT doesn't suppport MULTI_MODULE +) - add_executable(${APPNAME} ${SRC} ${UNCOMMON_SHARED_SOURCE} ${MM_UTIL}) - target_include_directories(${APPNAME} PRIVATE ${UNCOMMON_SHARED_DIR}) - target_link_libraries(${APPNAME} vmlib -lpthread -lm) +foreach(EX ${EXAMPLES}) + set(SRC ${CMAKE_CURRENT_LIST_DIR}/src/${EX}.c) + + add_executable(${EX} ${SRC} ${UNCOMMON_SHARED_SOURCE} ${MM_UTIL}) + target_include_directories(${EX} PRIVATE ${UNCOMMON_SHARED_DIR}) + target_link_libraries(${EX} vmlib -lpthread -lm) if (MSVC) - target_compile_definitions(${APPNAME} PRIVATE WASM_API_EXTERN=) + target_compile_definitions(${EX} PRIVATE WASM_API_EXTERN=) endif() endforeach() # wat to wasm -file(GLOB WAT_FILES src/*.wat) -foreach(WAT_FILE ${WAT_FILES}) - get_filename_component(WATNAME ${WAT_FILE} NAME_WE) +foreach(EX ${EXAMPLES}) + set(SRC ${CMAKE_CURRENT_LIST_DIR}/src/${EX}.wat) - add_custom_target(${WATNAME}_WASM ALL - COMMAND ${WAT2WASM} ${WAT_FILE} -o ${PROJECT_BINARY_DIR}/${WATNAME}.wasm - DEPENDS ${WAT_FILE} - BYPRODUCTS ${PROJECT_BINARY_DIR}/${WATNAME}.wasm + add_custom_target(${EX}_WASM ALL + COMMAND ${WAT2WASM} ${SRC} -o ${PROJECT_BINARY_DIR}/${EX}.wasm + DEPENDS ${SRC} + BYPRODUCTS ${PROJECT_BINARY_DIR}/${EX}.wasm VERBATIM - SOURCES ${WAT_FILE} + SOURCES ${SRC} ) endforeach() -################################################ + +if (CMAKE_BUILD_TYPE STREQUAL "Debug") + find_program(VALGRIND + valgrind + REQUIRED + ) + + if(VALGRIND) + foreach(EX ${EXAMPLES}) + add_custom_target(${EX}_LEAK_TEST + COMMAND ${VALGRIND} --tool=memcheck --leak-check=yes --show-reachable=yes ./${EX} + DEPENDS ${EX} ${EX}_WASM + VERBATIM + SOURCES ${EX} + ) + endforeach() + endif (VALGRIND) +endif (CMAKE_BUILD_TYPE STREQUAL "Debug") diff --git a/samples/wasm-c-api/src/LICENSE b/samples/wasm-c-api/src/LICENSE new file mode 100644 index 000000000..8f71f43fe --- /dev/null +++ b/samples/wasm-c-api/src/LICENSE @@ -0,0 +1,202 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/samples/wasm-c-api/src/callback.c b/samples/wasm-c-api/src/callback.c index 52349c330..ed0b60df5 100644 --- a/samples/wasm-c-api/src/callback.c +++ b/samples/wasm-c-api/src/callback.c @@ -4,14 +4,6 @@ #include #include "wasm_c_api.h" -#include "wasm_export.h" -#include "bh_platform.h" - -extern bool -reader(const char *module_name, uint8 **p_buffer, uint32 *p_size); - -extern void -destroyer(uint8 *buffer, uint32 size); #define own @@ -69,8 +61,6 @@ own wasm_trap_t* closure_callback( int main(int argc, const char* argv[]) { - wasm_runtime_set_module_reader(reader, destroyer); - // Initialize. printf("Initializing...\n"); wasm_engine_t* engine = wasm_engine_new(); @@ -78,11 +68,7 @@ int main(int argc, const char* argv[]) { // Load binary. printf("Loading binary...\n"); -#if WASM_ENABLE_AOT != 0 && WASM_ENABLE_INTERP == 0 - FILE* file = fopen("callback.aot", "rb"); -#else FILE* file = fopen("callback.wasm", "rb"); -#endif if (!file) { printf("> Error loading module!\n"); return 1; @@ -154,12 +140,8 @@ int main(int argc, const char* argv[]) { // Call. printf("Calling export...\n"); - wasm_val_t args[2]; - args[0].kind = WASM_I32; - args[0].of.i32 = 3; - args[1].kind = WASM_I32; - args[1].of.i32 = 4; - wasm_val_t results[1]; + wasm_val_t args[2] = { WASM_I32_VAL(3), WASM_I32_VAL(4) }; + wasm_val_t results[1] = { WASM_INIT_VAL }; if (wasm_func_call(run_func, args, results)) { printf("> Error calling function!\n"); return 1; diff --git a/samples/wasm-c-api/src/global.c b/samples/wasm-c-api/src/global.c index a7b5c16af..053fef710 100644 --- a/samples/wasm-c-api/src/global.c +++ b/samples/wasm-c-api/src/global.c @@ -4,14 +4,6 @@ #include #include "wasm_c_api.h" -#include "wasm_export.h" -#include "bh_platform.h" - -extern bool -reader(const char *module_name, uint8 **p_buffer, uint32 *p_size); - -extern void -destroyer(uint8 *buffer, uint32 size); #define own @@ -54,8 +46,6 @@ wasm_func_t* get_export_func(const wasm_extern_vec_t* exports, size_t i) { int main(int argc, const char* argv[]) { - wasm_runtime_set_module_reader(reader, destroyer); - // Initialize. printf("Initializing...\n"); wasm_engine_t* engine = wasm_engine_new(); @@ -63,11 +53,7 @@ int main(int argc, const char* argv[]) { // Load binary. printf("Loading binary...\n"); -#if WASM_ENABLE_AOT != 0 && WASM_ENABLE_INTERP == 0 - FILE* file = fopen("global.aot", "rb"); -#else FILE* file = fopen("global.wasm", "rb"); -#endif if (!file) { printf("> Error loading module!\n"); return 1; @@ -104,16 +90,16 @@ int main(int argc, const char* argv[]) { own wasm_globaltype_t* var_i64_type = wasm_globaltype_new( wasm_valtype_new(WASM_I64), WASM_VAR); - wasm_val_t val_f32_1 = {.kind = WASM_F32, .of = {.f32 = 1}}; + wasm_val_t val_f32_1 = WASM_F32_VAL(1); own wasm_global_t* const_f32_import = wasm_global_new(store, const_f32_type, &val_f32_1); - wasm_val_t val_i64_2 = {.kind = WASM_I64, .of = {.i64 = 2}}; + wasm_val_t val_i64_2 = WASM_I64_VAL(2); own wasm_global_t* const_i64_import = wasm_global_new(store, const_i64_type, &val_i64_2); - wasm_val_t val_f32_3 = {.kind = WASM_F32, .of = {.f32 = 3}}; + wasm_val_t val_f32_3 = WASM_F32_VAL(3); own wasm_global_t* var_f32_import = wasm_global_new(store, var_f32_type, &val_f32_3); - wasm_val_t val_i64_4 = {.kind = WASM_I64, .of = {.i64 = 4}}; + wasm_val_t val_i64_4 = WASM_I64_VAL(4); own wasm_global_t* var_i64_import = wasm_global_new(store, var_i64_type, &val_i64_4); @@ -189,13 +175,13 @@ int main(int argc, const char* argv[]) { check_call(get_var_i64_export, i64, 8); // Modify variables through API and check again. - wasm_val_t val33 = {.kind = WASM_F32, .of = {.f32 = 33}}; + wasm_val_t val33 = WASM_F32_VAL(33); wasm_global_set(var_f32_import, &val33); - wasm_val_t val34 = {.kind = WASM_I64, .of = {.i64 = 34}}; + wasm_val_t val34 = WASM_I64_VAL(34); wasm_global_set(var_i64_import, &val34); - wasm_val_t val37 = {.kind = WASM_F32, .of = {.f32 = 37}}; + wasm_val_t val37 = WASM_F32_VAL(37); wasm_global_set(var_f32_export, &val37); - wasm_val_t val38 = {.kind = WASM_I64, .of = {.i64 = 38}}; + wasm_val_t val38 = WASM_I64_VAL(38); wasm_global_set(var_i64_export, &val38); check_global(var_f32_import, f32, 33); @@ -209,13 +195,13 @@ int main(int argc, const char* argv[]) { check_call(get_var_i64_export, i64, 38); // Modify variables through calls and check again. - wasm_val_t args73[] = { {.kind = WASM_F32, .of = {.f32 = 73}} }; + wasm_val_t args73[] = { WASM_F32_VAL(73) }; wasm_func_call(set_var_f32_import, args73, NULL); - wasm_val_t args74[] = { {.kind = WASM_I64, .of = {.i64 = 74}} }; + wasm_val_t args74[] = { WASM_I64_VAL(74) }; wasm_func_call(set_var_i64_import, args74, NULL); - wasm_val_t args77[] = { {.kind = WASM_F32, .of = {.f32 = 77}} }; + wasm_val_t args77[] = { WASM_F32_VAL(77) }; wasm_func_call(set_var_f32_export, args77, NULL); - wasm_val_t args78[] = { {.kind = WASM_I64, .of = {.i64 = 78}} }; + wasm_val_t args78[] = { WASM_I64_VAL(78) }; wasm_func_call(set_var_i64_export, args78, NULL); check_global(var_f32_import, f32, 73); diff --git a/samples/wasm-c-api/src/hello.c b/samples/wasm-c-api/src/hello.c index db8281c36..1ea538b0d 100644 --- a/samples/wasm-c-api/src/hello.c +++ b/samples/wasm-c-api/src/hello.c @@ -4,14 +4,6 @@ #include #include "wasm_c_api.h" -#include "wasm_export.h" -#include "bh_platform.h" - -extern bool -reader(const char *module_name, uint8 **p_buffer, uint32 *p_size); - -extern void -destroyer(uint8 *buffer, uint32 size); #define own @@ -26,8 +18,6 @@ own wasm_trap_t* hello_callback( int main(int argc, const char* argv[]) { - wasm_runtime_set_module_reader(reader, destroyer); - // Initialize. printf("Initializing...\n"); wasm_engine_t* engine = wasm_engine_new(); @@ -35,11 +25,7 @@ int main(int argc, const char* argv[]) { // Load binary. printf("Loading binary...\n"); -#if WASM_ENABLE_AOT != 0 && WASM_ENABLE_INTERP == 0 - FILE* file = fopen("hello.aot", "rb"); -#else FILE* file = fopen("hello.wasm", "rb"); -#endif if (!file) { printf("> Error loading module!\n"); return 1; @@ -65,26 +51,15 @@ int main(int argc, const char* argv[]) { wasm_byte_vec_delete(&binary); - // Create external print functions. - printf("Creating callback...\n"); - own wasm_functype_t* hello_type = wasm_functype_new_0_0(); - own wasm_func_t* hello_func = - wasm_func_new(store, hello_type, hello_callback); - - wasm_functype_delete(hello_type); - // Instantiate. printf("Instantiating module...\n"); - const wasm_extern_t* imports[] = { wasm_func_as_extern(hello_func) }; own wasm_instance_t* instance = - wasm_instance_new(store, module, imports, NULL); + wasm_instance_new(store, module, NULL, NULL); if (!instance) { printf("> Error instantiating module!\n"); return 1; } - wasm_func_delete(hello_func); - // Extract export. printf("Extracting export...\n"); own wasm_extern_vec_t exports; @@ -93,22 +68,10 @@ int main(int argc, const char* argv[]) { printf("> Error accessing exports!\n"); return 1; } - const wasm_func_t* run_func = wasm_extern_as_func(exports.data[0]); - if (run_func == NULL) { - printf("> Error accessing export!\n"); - return 1; - } wasm_module_delete(module); wasm_instance_delete(instance); - // Call. - printf("Calling export...\n"); - if (wasm_func_call(run_func, NULL, NULL)) { - printf("> Error calling function!\n"); - return 1; - } - wasm_extern_vec_delete(&exports); // Shut down. diff --git a/samples/wasm-c-api/src/multi.c b/samples/wasm-c-api/src/multi.c new file mode 100644 index 000000000..8291ff9b5 --- /dev/null +++ b/samples/wasm-c-api/src/multi.c @@ -0,0 +1,153 @@ +#include +#include +#include +#include + +#include "wasm_c_api.h" + +#define own + +// A function to be called from Wasm code. +own wasm_trap_t* callback( + const wasm_val_t args[], wasm_val_t results[] +) { + printf("Calling back...\n> "); + printf("> %"PRIu32" %"PRIu64" %"PRIu64" %"PRIu32"\n", + args[0].of.i32, args[1].of.i64, + args[2].of.i64, args[3].of.i32); + printf("\n"); + + wasm_val_copy(&results[0], &args[3]); + wasm_val_copy(&results[1], &args[1]); + wasm_val_copy(&results[2], &args[2]); + wasm_val_copy(&results[3], &args[0]); + return NULL; +} + + +// A function closure. +own wasm_trap_t* closure_callback( + void* env, const wasm_val_t args[], wasm_val_t results[] +) { + int i = *(int*)env; + printf("Calling back closure...\n"); + printf("> %d\n", i); + + results[0].kind = WASM_I32; + results[0].of.i32 = (int32_t)i; + return NULL; +} + + +int main(int argc, const char* argv[]) { + // Initialize. + printf("Initializing...\n"); + wasm_engine_t* engine = wasm_engine_new(); + wasm_store_t* store = wasm_store_new(engine); + + // Load binary. + printf("Loading binary...\n"); + FILE* file = fopen("multi.wasm", "rb"); + if (!file) { + printf("> Error loading module!\n"); + return 1; + } + fseek(file, 0L, SEEK_END); + size_t file_size = ftell(file); + fseek(file, 0L, SEEK_SET); + wasm_byte_vec_t binary; + wasm_byte_vec_new_uninitialized(&binary, file_size); + if (fread(binary.data, file_size, 1, file) != 1) { + printf("> Error loading module!\n"); + return 1; + } + fclose(file); + + // Compile. + printf("Compiling module...\n"); + own wasm_module_t* module = wasm_module_new(store, &binary); + if (!module) { + printf("> Error compiling module!\n"); + return 1; + } + + wasm_byte_vec_delete(&binary); + + // Create external print functions. + printf("Creating callback...\n"); + wasm_valtype_t* types[4] = { + wasm_valtype_new_i32(), wasm_valtype_new_i64(), + wasm_valtype_new_i64(), wasm_valtype_new_i32() + }; + own wasm_valtype_vec_t tuple1, tuple2; + wasm_valtype_vec_new(&tuple1, 4, types); + wasm_valtype_vec_copy(&tuple2, &tuple1); + own wasm_functype_t* callback_type = wasm_functype_new(&tuple1, &tuple2); + own wasm_func_t* callback_func = + wasm_func_new(store, callback_type, callback); + + wasm_functype_delete(callback_type); + + // Instantiate. + printf("Instantiating module...\n"); + const wasm_extern_t* imports[] = { wasm_func_as_extern(callback_func) }; + own wasm_instance_t* instance = + wasm_instance_new(store, module, imports, NULL); + if (!instance) { + printf("> Error instantiating module!\n"); + return 1; + } + + wasm_func_delete(callback_func); + + // Extract export. + printf("Extracting export...\n"); + own wasm_extern_vec_t exports; + wasm_instance_exports(instance, &exports); + if (exports.size == 0) { + printf("> Error accessing exports!\n"); + return 1; + } + const wasm_func_t* run_func = wasm_extern_as_func(exports.data[0]); + if (run_func == NULL) { + printf("> Error accessing export!\n"); + return 1; + } + + wasm_module_delete(module); + wasm_instance_delete(instance); + + // Call. + printf("Calling export...\n"); + wasm_val_t args[4] = { + WASM_I32_VAL(1), WASM_I64_VAL(2), WASM_I64_VAL(3), WASM_I32_VAL(4) + }; + wasm_val_t results[4] = { + WASM_INIT_VAL, WASM_INIT_VAL, WASM_INIT_VAL, WASM_INIT_VAL + }; + if (wasm_func_call(run_func, args, results)) { + printf("> Error calling function!\n"); + return 1; + } + + wasm_extern_vec_delete(&exports); + + // Print result. + printf("Printing result...\n"); + printf("> %"PRIu32" %"PRIu64" %"PRIu64" %"PRIu32"\n", + results[0].of.i32, results[1].of.i64, results[2].of.i64, results[3].of.i32); + + assert(results[0].of.i32 == 1); + assert(results[1].of.i64 == 2); + assert(results[2].of.i64 == 3); + assert(results[3].of.i32 == 4); + + // Shut down. + printf("Shutting down...\n"); + wasm_store_delete(store); + wasm_engine_delete(engine); + + // All done. + printf("Done.\n"); + return 0; +} diff --git a/samples/wasm-c-api/src/multi.wat b/samples/wasm-c-api/src/multi.wat new file mode 100644 index 000000000..e7fb33112 --- /dev/null +++ b/samples/wasm-c-api/src/multi.wat @@ -0,0 +1,7 @@ +(module + (func $f (import "" "f") (param i32 i64 i64 i32) (result i32 i64 i64 i32)) + + (func $g (export "g") (param i32 i64 i64 i32) (result i32 i64 i64 i32) + (call $f (local.get 0) (local.get 2) (local.get 1) (local.get 3)) + ) +) diff --git a/samples/wasm-c-api/src/reflect.c b/samples/wasm-c-api/src/reflect.c new file mode 100644 index 000000000..f2e41869c --- /dev/null +++ b/samples/wasm-c-api/src/reflect.c @@ -0,0 +1,170 @@ +#include +#include +#include +#include + +#include "wasm_c_api.h" + +#define own + +void print_mutability(wasm_mutability_t mut) { + switch (mut) { + case WASM_VAR: printf("var"); break; + case WASM_CONST: printf("const"); break; + } +} + +void print_limits(const wasm_limits_t* limits) { + printf("%ud", limits->min); + if (limits->max < wasm_limits_max_default) printf(" %ud", limits->max); +} + +void print_valtype(const wasm_valtype_t* type) { + switch (wasm_valtype_kind(type)) { + case WASM_I32: printf("i32"); break; + case WASM_I64: printf("i64"); break; + case WASM_F32: printf("f32"); break; + case WASM_F64: printf("f64"); break; + case WASM_ANYREF: printf("anyref"); break; + case WASM_FUNCREF: printf("funcref"); break; + } +} + +void print_valtypes(const wasm_valtype_vec_t* types) { + bool first = true; + for (size_t i = 0; i < types->size; ++i) { + if (first) { + first = false; + } else { + printf(" "); + } + print_valtype(types->data[i]); + } +} + +void print_externtype(const wasm_externtype_t* type) { + switch (wasm_externtype_kind(type)) { + case WASM_EXTERN_FUNC: { + const wasm_functype_t* functype = + wasm_externtype_as_functype_const(type); + printf("func "); + print_valtypes(wasm_functype_params(functype)); + printf(" -> "); + print_valtypes(wasm_functype_results(functype)); + } break; + case WASM_EXTERN_GLOBAL: { + const wasm_globaltype_t* globaltype = + wasm_externtype_as_globaltype_const(type); + printf("global "); + print_mutability(wasm_globaltype_mutability(globaltype)); + printf(" "); + print_valtype(wasm_globaltype_content(globaltype)); + } break; + case WASM_EXTERN_TABLE: { + const wasm_tabletype_t* tabletype = + wasm_externtype_as_tabletype_const(type); + printf("table "); + print_limits(wasm_tabletype_limits(tabletype)); + printf(" "); + print_valtype(wasm_tabletype_element(tabletype)); + } break; + case WASM_EXTERN_MEMORY: { + const wasm_memorytype_t* memorytype = + wasm_externtype_as_memorytype_const(type); + printf("memory "); + print_limits(wasm_memorytype_limits(memorytype)); + } break; + } +} + +void print_name(const wasm_name_t* name) { + printf("\"%.*s\"", (int)name->size, name->data); +} + + +int main(int argc, const char* argv[]) { + // Initialize. + printf("Initializing...\n"); + wasm_engine_t* engine = wasm_engine_new(); + wasm_store_t* store = wasm_store_new(engine); + + // Load binary. + printf("Loading binary...\n"); + FILE* file = fopen("reflect.wasm", "rb"); + if (!file) { + printf("> Error loading module!\n"); + return 1; + } + fseek(file, 0L, SEEK_END); + size_t file_size = ftell(file); + fseek(file, 0L, SEEK_SET); + wasm_byte_vec_t binary; + wasm_byte_vec_new_uninitialized(&binary, file_size); + if (fread(binary.data, file_size, 1, file) != 1) { + printf("> Error loading module!\n"); + return 1; + } + fclose(file); + + // Compile. + printf("Compiling module...\n"); + own wasm_module_t* module = wasm_module_new(store, &binary); + if (!module) { + printf("> Error compiling module!\n"); + return 1; + } + + wasm_byte_vec_delete(&binary); + + // Instantiate. + printf("Instantiating module...\n"); + own wasm_instance_t* instance = + wasm_instance_new(store, module, NULL, NULL); + if (!instance) { + printf("> Error instantiating module!\n"); + return 1; + } + + // Extract export. + printf("Extracting export...\n"); + own wasm_exporttype_vec_t export_types; + own wasm_extern_vec_t exports; + wasm_module_exports(module, &export_types); + wasm_instance_exports(instance, &exports); + assert(exports.size == export_types.size); + + for (size_t i = 0; i < exports.size; ++i) { + assert(wasm_extern_kind(exports.data[i]) == + wasm_externtype_kind(wasm_exporttype_type(export_types.data[i]))); + printf("> export %zu ", i); + print_name(wasm_exporttype_name(export_types.data[i])); + printf("\n"); + printf(">> initial: "); + print_externtype(wasm_exporttype_type(export_types.data[i])); + printf("\n"); + printf(">> current: "); + own wasm_externtype_t* current = wasm_extern_type(exports.data[i]); + print_externtype(current); + wasm_externtype_delete(current); + printf("\n"); + if (wasm_extern_kind(exports.data[i]) == WASM_EXTERN_FUNC) { + wasm_func_t* func = wasm_extern_as_func(exports.data[i]); + printf(">> in-arity: %zu", wasm_func_param_arity(func)); + printf(", out-arity: %zu\n", wasm_func_result_arity(func)); + } + } + + wasm_module_delete(module); + wasm_instance_delete(instance); + wasm_extern_vec_delete(&exports); + wasm_exporttype_vec_delete(&export_types); + + // Shut down. + printf("Shutting down...\n"); + wasm_store_delete(store); + wasm_engine_delete(engine); + + // All done. + printf("Done.\n"); + return 0; +} diff --git a/samples/wasm-c-api/src/reflect.wat b/samples/wasm-c-api/src/reflect.wat new file mode 100644 index 000000000..261dfd3c3 --- /dev/null +++ b/samples/wasm-c-api/src/reflect.wat @@ -0,0 +1,6 @@ +(module + (func (export "func") (param i32 f64 f32) (result i32) (unreachable)) + (global (export "global") f64 (f64.const 0)) + (table (export "table") 0 50 anyfunc) + (memory (export "memory") 1) +) diff --git a/samples/wasm-c-api/src/trap.c b/samples/wasm-c-api/src/trap.c new file mode 100644 index 000000000..60ff0654b --- /dev/null +++ b/samples/wasm-c-api/src/trap.c @@ -0,0 +1,124 @@ +#include +#include +#include +#include + +#include "wasm_c_api.h" + +#define own + +// A function to be called from Wasm code. +own wasm_trap_t* fail_callback( + void* env, const wasm_val_t args[], wasm_val_t results[] +) { + printf("Calling back...\n"); + own wasm_name_t message; + wasm_name_new_from_string_nt(&message, "callback abort"); + own wasm_trap_t* trap = wasm_trap_new((wasm_store_t*)env, &message); + wasm_name_delete(&message); + return trap; +} + +int main(int argc, const char* argv[]) { + // Initialize. + printf("Initializing...\n"); + wasm_engine_t* engine = wasm_engine_new(); + wasm_store_t* store = wasm_store_new(engine); + + // Load binary. + printf("Loading binary...\n"); + FILE* file = fopen("trap.wasm", "rb"); + if (!file) { + printf("> Error loading module!\n"); + return 1; + } + fseek(file, 0L, SEEK_END); + size_t file_size = ftell(file); + fseek(file, 0L, SEEK_SET); + wasm_byte_vec_t binary; + wasm_byte_vec_new_uninitialized(&binary, file_size); + if (fread(binary.data, file_size, 1, file) != 1) { + printf("> Error loading module!\n"); + return 1; + } + fclose(file); + + // Compile. + printf("Compiling module...\n"); + own wasm_module_t* module = wasm_module_new(store, &binary); + if (!module) { + printf("> Error compiling module!\n"); + return 1; + } + + wasm_byte_vec_delete(&binary); + + // Create external print functions. + printf("Creating callback...\n"); + own wasm_functype_t* fail_type = + wasm_functype_new_0_1(wasm_valtype_new_i32()); + own wasm_func_t* fail_func = + wasm_func_new_with_env(store, fail_type, fail_callback, store, NULL); + + wasm_functype_delete(fail_type); + + // Instantiate. + printf("Instantiating module...\n"); + const wasm_extern_t* imports[] = { wasm_func_as_extern(fail_func) }; + own wasm_instance_t* instance = + wasm_instance_new(store, module, imports, NULL); + if (!instance) { + printf("> Error instantiating module!\n"); + return 1; + } + + wasm_func_delete(fail_func); + + // Extract export. + printf("Extracting exports...\n"); + own wasm_extern_vec_t exports; + wasm_instance_exports(instance, &exports); + if (exports.size < 2) { + printf("> Error accessing exports!\n"); + return 1; + } + + wasm_module_delete(module); + wasm_instance_delete(instance); + + // Call. + for (int i = 0; i < 2; ++i) { + const wasm_func_t* func = wasm_extern_as_func(exports.data[i]); + if (func == NULL) { + printf("> Error accessing export!\n"); + return 1; + } + + printf("Calling export %d...\n", i); + wasm_val_t results[1]; \ + own wasm_trap_t* trap = wasm_func_call(func, NULL, results); + if (!trap) { + printf("> Error calling function, expected trap!\n"); + return 1; + } + + printf("Printing message...\n"); + own wasm_name_t message; + wasm_trap_message(trap, &message); + printf("> %s\n", message.data); + + wasm_trap_delete(trap); + wasm_name_delete(&message); + } + + wasm_extern_vec_delete(&exports); + + // Shut down. + printf("Shutting down...\n"); + wasm_store_delete(store); + wasm_engine_delete(engine); + + // All done. + printf("Done.\n"); + return 0; +} diff --git a/samples/wasm-c-api/src/trap.wat b/samples/wasm-c-api/src/trap.wat new file mode 100644 index 000000000..dfd20fb12 --- /dev/null +++ b/samples/wasm-c-api/src/trap.wat @@ -0,0 +1,5 @@ +(module + (func $callback (import "" "callback") (result i32)) + (func (export "callback") (result i32) (call $callback)) + (func (export "unreachable") (result i32) (unreachable) (i32.const 1)) +) diff --git a/samples/workload/XNNPACK/CMakeLists.txt b/samples/workload/XNNPACK/CMakeLists.txt index 86a784cbb..3e00f20f5 100644 --- a/samples/workload/XNNPACK/CMakeLists.txt +++ b/samples/workload/XNNPACK/CMakeLists.txt @@ -20,85 +20,72 @@ include(ExternalProject) ExternalProject_Add(xnnpack PREFIX xnnpack GIT_REPOSITORY https://github.com/google/XNNPACK.git - GIT_TAG 2da0de89960b829c6fae74204a102db524e73047 + GIT_TAG master GIT_PROGRESS ON SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/xnnpack - UPDATE_COMMAND git checkout .bazelrc BUILD.bazel emscripten.bzl + UPDATE_COMMAND git checkout . && git apply ${CMAKE_CURRENT_SOURCE_DIR}/xnnpack.patch - && cmake -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/toolchain ${CMAKE_CURRENT_SOURCE_DIR}/xnnpack/toolchain - # replace string "$ENV{HOME}" with actual home directory - && sed -i "s|\$ENV{HOME}|$ENV{HOME}|g" ${CMAKE_CURRENT_SOURCE_DIR}/xnnpack/toolchain/emscripten_toolchain_config.bzl CONFIGURE_COMMAND "" BUILD_COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR}/xnnpack - && bazel build -c opt --sandbox_writable_path=$ENV{HOME} --config=emscripten_wasm - //:qs8_gemm_bench.wasm - //:qs8_requantization_bench.wasm - //:qu8_gemm_bench.wasm - //:qu8_requantization_bench.wasm - //:f16_igemm_bench.wasm - //:f16_gemm_bench.wasm - //:f16_spmm_bench.wasm - //:f32_igemm_bench.wasm - //:f16_relu_bench.wasm - //:f32_conv_hwc_bench.wasm - //:f32_conv_hwc2chw_bench.wasm - //:f16_dwconv_bench.wasm - //:f32_dwconv_bench.wasm - //:f32_dwconv2d_chw_bench.wasm - //:f32_gemm_bench.wasm - //:f32_hswish_bench.wasm - //:f32_raddexpminusmax_bench.wasm - //:f32_raddextexp_bench.wasm - //:f32_raddstoreexpminusmax_bench.wasm - //:f32_relu_bench.wasm - //:f32_rmax_bench.wasm - //:f32_sigmoid_bench.wasm - //:f32_spmm_bench.wasm - //:f32_softmax_bench.wasm - //:f32_vscaleexpminusmax_bench.wasm - //:f32_vscaleextexp_bench.wasm - //:f32_vsqrt_bench.wasm - //:f32_im2col_gemm_bench.wasm - //:rounding_bench.wasm - //:average_pooling_bench.wasm - //:bankers_rounding_bench.wasm - //:ceiling_bench.wasm - //:channel_shuffle_bench.wasm - //:convolution_bench.wasm - //:deconvolution_bench.wasm - //:floor_bench.wasm - //:global_average_pooling_bench.wasm - //:hardswish_bench.wasm - //:max_pooling_bench.wasm - //:sigmoid_bench.wasm - //:prelu_bench.wasm - //:softmax_bench.wasm - //:square_root_bench.wasm - //:truncation_bench.wasm - //:fp32_mobilenet_v1.wasm - //:fp16_mobilenet_v1.wasm - //:qs8_mobilenet_v1.wasm - //:qs8_mobilenet_v2.wasm - //:fp32_mobilenet_v2.wasm - //:fp16_mobilenet_v2.wasm - //:fp32_mobilenet_v3_large.wasm - //:fp16_mobilenet_v3_large.wasm - //:fp32_mobilenet_v3_small.wasm - //:fp16_mobilenet_v3_small.wasm - //:f32_dwconv_e2e_bench.wasm - //:f32_gemm_e2e_bench.wasm - //:end2end_bench.wasm - //:f32_exp_eval.wasm - //:f32_expminus_eval.wasm - //:f32_extexp_eval.wasm - //:f32_roundne_eval.wasm - //:f32_roundd_eval.wasm - //:f32_roundu_eval.wasm - //:f32_roundz_eval.wasm - //:f32_sigmoid_eval.wasm - //:f32_sqrt_eval.wasm + && bazel --output_user_root=build_user_output build -c opt --config=wasm + //:qs8_gemm_bench + //:qs8_requantization_bench + //:qu8_gemm_bench + //:qu8_requantization_bench + //:f16_igemm_bench + //:f16_gemm_bench + //:f16_spmm_bench + //:f32_igemm_bench + //:f16_relu_bench + //:f32_conv_hwc_bench + //:f32_conv_hwc2chw_bench + //:f16_dwconv_bench + //:f32_dwconv_bench + //:f32_dwconv2d_chw_bench + //:f32_gemm_bench + //:f32_hswish_bench + //:f32_raddexpminusmax_bench + //:f32_raddextexp_bench + //:f32_raddstoreexpminusmax_bench + //:f32_relu_bench + //:f32_rmax_bench + //:f32_sigmoid_bench + //:f32_spmm_bench + //:f32_softmax_bench + //:f32_velu_bench + //:f32_vscaleexpminusmax_bench + //:f32_vscaleextexp_bench + //:f32_vsqrt_bench + //:f32_im2col_gemm_bench + //:rounding_bench + //:average_pooling_bench + //:bankers_rounding_bench + //:ceiling_bench + //:channel_shuffle_bench + //:convolution_bench + //:deconvolution_bench + //:elu_bench + //:floor_bench + //:global_average_pooling_bench + //:hardswish_bench + //:max_pooling_bench + //:sigmoid_bench + //:prelu_bench + //:softmax_bench + //:square_root_bench + //:truncation_bench + //:f32_dwconv_e2e_bench + //:f32_gemm_e2e_bench + //:qs8_gemm_e2e_bench + //:end2end_bench + //:f32_exp_ulp_eval + //:f32_expminus_ulp_eval + //:f32_expm1minus_ulp_eval + //:f32_extexp_ulp_eval + //:f32_sigmoid_ulp_eval + //:f32_sqrt_ulp_eval #--sandbox_debug - INSTALL_COMMAND ${CMAKE_COMMAND} -E create_symlink + INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/xnnpack/bazel-out/wasm-opt/bin/ ${CMAKE_CURRENT_SOURCE_DIR}/build/wasm-opt ) diff --git a/samples/workload/XNNPACK/toolchain/BUILD.bazel b/samples/workload/XNNPACK/toolchain/BUILD.bazel deleted file mode 100644 index 9cf9b9693..000000000 --- a/samples/workload/XNNPACK/toolchain/BUILD.bazel +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright (C) 2019 Intel Corporation. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -package(default_visibility = ['//visibility:public']) - -load(":emscripten_toolchain_config.bzl", "emsdk_toolchain_config") - -cc_toolchain_suite( - name = "emscripten", - toolchains = { - "wasm": ":emsdk_toolchain", - }, -) - -filegroup(name = "empty") - -emsdk_toolchain_config(name = "emsdk_toolchain_config") - -cc_toolchain( - name = "emsdk_toolchain", - toolchain_identifier = "emsdk-toolchain", - toolchain_config = ":emsdk_toolchain_config", - all_files = ":empty", - compiler_files = ":empty", - dwp_files = ":empty", - linker_files = ":empty", - objcopy_files = ":empty", - strip_files = ":empty", - supports_param_files = 0, -) diff --git a/samples/workload/XNNPACK/toolchain/emscripten_toolchain_config.bzl b/samples/workload/XNNPACK/toolchain/emscripten_toolchain_config.bzl deleted file mode 100644 index d3e440590..000000000 --- a/samples/workload/XNNPACK/toolchain/emscripten_toolchain_config.bzl +++ /dev/null @@ -1,142 +0,0 @@ -# Copyright (C) 2019 Intel Corporation. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -load("@bazel_tools//tools/build_defs/cc:action_names.bzl", "ACTION_NAMES") -load( - "@bazel_tools//tools/cpp:cc_toolchain_config_lib.bzl", - "feature", - "flag_group", - "flag_set", - "tool_path", -) - -all_compile_actions = [ - ACTION_NAMES.c_compile, - ACTION_NAMES.cpp_compile, -] - -all_link_actions = [ - ACTION_NAMES.cpp_link_executable, - ACTION_NAMES.cpp_link_dynamic_library, - ACTION_NAMES.cpp_link_nodeps_dynamic_library, -] - -def _impl(ctx): - tool_paths = [ - tool_path( - name = "gcc", - path = "/opt/emsdk/upstream/emscripten/emcc", - ), - tool_path( - name = "ld", - path = "/opt/emsdk/upstream/emscripten/emcc", - ), - tool_path( - name = "ar", - path = "/opt/emsdk/upstream/emscripten/emar", - ), - tool_path( - name = "cpp", - path = "/opt/emsdk/upstream/emscripten/em++", - ), - tool_path( - name = "gcov", - path = "/bin/false", - ), - tool_path( - name = "nm", - path = "/bin/false", - ), - tool_path( - name = "objdump", - path = "/bin/false", - ), - tool_path( - name = "strip", - path = "/bin/false", - ), - ] - - features = [ # NEW - feature( - name = "default_compile_flags", - enabled = True, - flag_sets = [ - flag_set( - actions = all_compile_actions, - flag_groups = ([ - flag_group( - flags = [ - "-O3", - "-msimd128", - "-s", - "USE_PTHREADS=0", - "-s", - "ERROR_ON_UNDEFINED_SYMBOLS=0", - "-s", - "STANDALONE_WASM=1", - ], - ), - ]), - ), - ], - ), - feature( - name = "default_linker_flags", - enabled = True, - flag_sets = [ - flag_set( - actions = all_link_actions, - flag_groups = ([ - flag_group( - flags = [ - "-O3", - "-msimd128", - "-s", - "USE_PTHREADS=0", - "-s", - "ERROR_ON_UNDEFINED_SYMBOLS=0", - "-s", - "STANDALONE_WASM=1", - "-Wl,--export=__heap_base", - "-Wl,--export=__data_end", - "-Wl,--export=malloc", - "-Wl,--export=free", - ], - ), - ]), - ), - ], - ), - ] - - return cc_common.create_cc_toolchain_config_info( - ctx = ctx, - features = features, # NEW - cxx_builtin_include_directories = [ - "/opt/emsdk/upstream/emscripten/system/include", - "/opt/emsdk/upstream/emscripten/system/lib/libc/include", - "/opt/emsdk/upstream/emscripten/system/lib/libcxx/include", - "/opt/emsdk/upstream/emscripten/system/lib/libcxxabi/include", - "/opt/emsdk/upstream/emscripten/system/lib/libc/musl/arch/emscripten", - "/opt/emsdk/upstream/emscripten/system/include/compat", - "/opt/emsdk/upstream/emscripten/cache/sysroot/include", - "/opt/emsdk/upstream/lib/clang/13.0.0/include", - "$ENV{HOME}/.emscripten_cache/sysroot/include", - ], - toolchain_identifier = "wasm-emsdk", - host_system_name = "i686-unknown-linux-gnu", - target_system_name = "wasm32-unknown-emscripten", - target_cpu = "wasm32", - target_libc = "unknown", - compiler = "emsdk", - abi_version = "unknown", - abi_libc_version = "unknown", - tool_paths = tool_paths, - ) - -emsdk_toolchain_config = rule( - implementation = _impl, - attrs = {}, - provides = [CcToolchainConfigInfo], -) diff --git a/samples/workload/XNNPACK/xnnpack.patch b/samples/workload/XNNPACK/xnnpack.patch index b58cbc795..17dafbf2e 100644 --- a/samples/workload/XNNPACK/xnnpack.patch +++ b/samples/workload/XNNPACK/xnnpack.patch @@ -1,742 +1,137 @@ diff --git a/.bazelrc b/.bazelrc -index ea28201..ffd4ed4 100644 +index ec740f38..2c193244 100644 --- a/.bazelrc +++ b/.bazelrc -@@ -44,3 +44,7 @@ build:ios_arm64e --watchos_cpus=armv7k - build:ios_fat --config=ios - build:ios_fat --ios_multi_cpus=armv7,arm64 - build:ios_fat --watchos_cpus=armv7k +@@ -49,4 +49,10 @@ build:ios_fat --watchos_cpus=armv7k + build:macos --apple_platform_type=macos + + build:macos_arm64 --config=macos +-build:macos_arm64 --cpu=darwin_arm64 +\ No newline at end of file ++build:macos_arm64 --cpu=darwin_arm64 ++ ++build:wasm --copt=-msimd128 ++build:wasm --cpu=wasm ++build:wasm --crosstool_top=@emsdk//emscripten_toolchain:everything ++build:wasm --host_crosstool_top=@bazel_tools//tools/cpp:toolchain + -+# WASM configs -+build:emscripten_wasm --cpu=wasm -+build:emscripten_wasm --crosstool_top=//toolchain:emscripten diff --git a/BUILD.bazel b/BUILD.bazel -index d38ef1e..f261eb5 100644 +index ae4108bc..1c11fac2 100644 --- a/BUILD.bazel +++ b/BUILD.bazel -@@ -3228,13 +3228,19 @@ xnnpack_cc_library( - hdrs = INTERNAL_HDRS, - gcc_copts = xnnpack_gcc_std_copts(), - msvc_copts = xnnpack_msvc_std_copts(), -- wasm_srcs = WASM_UKERNELS, -- wasmsimd_srcs = WASM_UKERNELS + WASMSIMD_UKERNELS, -+ optimized_copts = [ -+ "-ffast-math", -+ ], -+ wasm_srcs = WASM_UKERNELS + WASMSIMD_UKERNELS + -+ PSIMD_FASTMATH_UKERNELS + PSIMD_ACCMATH_UKERNELS, -+ wasmsimd_srcs = WASM_UKERNELS + WASMSIMD_UKERNELS + -+ PSIMD_FASTMATH_UKERNELS + PSIMD_ACCMATH_UKERNELS, - deps = [ - ":tables", - "@FP16", - "@FXdiv", - "@pthreadpool", -+ "@psimd", - ], - ) - -@@ -3247,13 +3253,19 @@ xnnpack_cc_library( - ], - gcc_copts = xnnpack_gcc_std_copts(), - msvc_copts = xnnpack_msvc_std_copts(), -- wasm_srcs = WASM_UKERNELS, -- wasmsimd_srcs = WASM_UKERNELS + WASMSIMD_UKERNELS, -+ optimized_copts = [ -+ "-ffast-math", -+ ], -+ wasm_srcs = WASM_UKERNELS + WASMSIMD_UKERNELS + -+ PSIMD_FASTMATH_UKERNELS + PSIMD_ACCMATH_UKERNELS, -+ wasmsimd_srcs = WASM_UKERNELS + WASMSIMD_UKERNELS + -+ PSIMD_FASTMATH_UKERNELS + PSIMD_ACCMATH_UKERNELS, - deps = [ - ":tables", - "@FP16", - "@FXdiv", - "@pthreadpool", -+ "@psimd", - ], - ) - -@@ -4495,7 +4507,7 @@ xnnpack_cc_library( - ######################### Benchmarks for micro-kernels ######################### - - xnnpack_benchmark( -- name = "qs8_gemm_bench", -+ name = "qs8_gemm_bench.wasm", - srcs = [ - "bench/gemm.h", - "bench/qs8-gemm.cc", -@@ -4506,7 +4518,7 @@ xnnpack_benchmark( - ) - - xnnpack_benchmark( -- name = "qs8_requantization_bench", -+ name = "qs8_requantization_bench.wasm", - srcs = [ - "bench/qs8-requantization.cc", - "src/xnnpack/AlignedAllocator.h", -@@ -4516,7 +4528,7 @@ xnnpack_benchmark( - ) - - xnnpack_benchmark( -- name = "qu8_gemm_bench", -+ name = "qu8_gemm_bench.wasm", - srcs = [ - "bench/gemm.h", - "bench/qu8-gemm.cc", -@@ -4527,7 +4539,7 @@ xnnpack_benchmark( - ) - - xnnpack_benchmark( -- name = "qu8_requantization_bench", -+ name = "qu8_requantization_bench.wasm", - srcs = [ - "bench/qu8-requantization.cc", - "src/xnnpack/AlignedAllocator.h", -@@ -4537,11 +4549,11 @@ xnnpack_benchmark( - ) - - xnnpack_benchmark( -- name = "f16_igemm_bench", -+ name = "f16_igemm_bench.wasm", +@@ -5038,7 +5038,6 @@ xnnpack_benchmark( srcs = [ "bench/f16-igemm.cc", "bench/conv.h", - "bench/google/conv.h", -+ #"bench/google/conv.h", "src/xnnpack/AlignedAllocator.h", ] + MICROKERNEL_BENCHMARK_HDRS, deps = MICROKERNEL_BENCHMARK_DEPS + [ -@@ -4551,7 +4563,7 @@ xnnpack_benchmark( - ) - - xnnpack_benchmark( -- name = "f16_gemm_bench", -+ name = "f16_gemm_bench.wasm", - srcs = [ - "bench/f16-gemm.cc", - "bench/gemm.h", -@@ -4563,7 +4575,7 @@ xnnpack_benchmark( - ) - - xnnpack_benchmark( -- name = "f16_spmm_bench", -+ name = "f16_spmm_bench.wasm", - srcs = [ - "bench/f16-spmm.cc", - "bench/gemm.h", -@@ -4573,7 +4585,7 @@ xnnpack_benchmark( - ) - - xnnpack_benchmark( -- name = "f32_igemm_bench", -+ name = "f32_igemm_bench.wasm", - srcs = [ - "bench/f32-igemm.cc", - "bench/conv.h", -@@ -4586,7 +4598,7 @@ xnnpack_benchmark( - ) - - xnnpack_benchmark( -- name = "f16_relu_bench", -+ name = "f16_relu_bench.wasm", - srcs = [ - "bench/f16-relu.cc", - "src/xnnpack/AlignedAllocator.h", -@@ -4595,7 +4607,7 @@ xnnpack_benchmark( - ) - - xnnpack_benchmark( -- name = "f32_conv_hwc_bench", -+ name = "f32_conv_hwc_bench.wasm", - srcs = [ - "bench/f32-conv-hwc.cc", - "bench/dconv.h", -@@ -4607,7 +4619,7 @@ xnnpack_benchmark( - ) - - xnnpack_benchmark( -- name = "f32_conv_hwc2chw_bench", -+ name = "f32_conv_hwc2chw_bench.wasm", - srcs = [ - "bench/f32-conv-hwc2chw.cc", - "bench/dconv.h", -@@ -4619,11 +4631,11 @@ xnnpack_benchmark( - ) - - xnnpack_benchmark( -- name = "f16_dwconv_bench", -+ name = "f16_dwconv_bench.wasm", +@@ -5120,7 +5119,6 @@ xnnpack_benchmark( srcs = [ "bench/f16-dwconv.cc", "bench/dwconv.h", - "bench/google/dwconv.h", -+ #"bench/google/dwconv.h", "src/xnnpack/AlignedAllocator.h", ] + MICROKERNEL_BENCHMARK_HDRS, deps = MICROKERNEL_BENCHMARK_DEPS + [ -@@ -4633,7 +4645,7 @@ xnnpack_benchmark( - ) +diff --git a/WORKSPACE b/WORKSPACE +index 4fa1aa2f..86040d42 100644 +--- a/WORKSPACE ++++ b/WORKSPACE +@@ -89,3 +89,18 @@ android_ndk_repository(name = "androidndk") - xnnpack_benchmark( -- name = "f32_dwconv_bench", -+ name = "f32_dwconv_bench.wasm", - srcs = [ - "bench/f32-dwconv.cc", - "bench/dwconv.h", -@@ -4646,7 +4658,7 @@ xnnpack_benchmark( - ) + # Android SDK location and API is auto-detected from $ANDROID_HOME environment variable + android_sdk_repository(name = "androidsdk") ++ ++# emscripten library ++http_archive( ++ name = "emsdk", ++ strip_prefix = "emsdk-c1589b55641787d55d53e883852035beea9aec3f/bazel", ++ url = "https://github.com/emscripten-core/emsdk/archive/c1589b55641787d55d53e883852035beea9aec3f.tar.gz", ++ sha256 = "7a58a9996b113d3e0675df30b5f17e28aa47de2e684a844f05394fe2f6f12e8e", ++) ++ ++load("@emsdk//:deps.bzl", emsdk_deps = "deps") ++emsdk_deps() ++ ++load("@emsdk//:emscripten_deps.bzl", emsdk_emscripten_deps = "emscripten_deps") ++emsdk_emscripten_deps() ++ +diff --git a/build_defs.bzl b/build_defs.bzl +index 10345032..0e926fca 100644 +--- a/build_defs.bzl ++++ b/build_defs.bzl +@@ -1,6 +1,6 @@ + """Build definitions and rules for XNNPACK.""" - xnnpack_benchmark( -- name = "f32_dwconv2d_chw_bench", -+ name = "f32_dwconv2d_chw_bench.wasm", - srcs = [ - "bench/f32-dwconv2d-chw.cc", - "bench/dwconv.h", -@@ -4659,7 +4671,7 @@ xnnpack_benchmark( - ) +-load(":emscripten.bzl", "xnnpack_emscripten_benchmark_linkopts", "xnnpack_emscripten_deps", "xnnpack_emscripten_minimal_linkopts", "xnnpack_emscripten_test_linkopts") ++load(":emscripten.bzl", "xnnpack_emscripten_benchmark_linkopts", "xnnpack_emscripten_deps", "xnnpack_emscripten_minimal_linkopts", "xnnpack_emscripten_test_linkopts", "xnnpack_emscripten_benchmark_copts") - xnnpack_benchmark( -- name = "f32_gemm_bench", -+ name = "f32_gemm_bench.wasm", - srcs = [ - "bench/f32-gemm.cc", - "bench/gemm.h", -@@ -4670,7 +4682,7 @@ xnnpack_benchmark( - ) - - xnnpack_benchmark( -- name = "f32_hswish_bench", -+ name = "f32_hswish_bench.wasm", - srcs = [ - "bench/f32-hswish.cc", - "src/xnnpack/AlignedAllocator.h", -@@ -4679,7 +4691,7 @@ xnnpack_benchmark( - ) - - xnnpack_benchmark( -- name = "f32_raddexpminusmax_bench", -+ name = "f32_raddexpminusmax_bench.wasm", - srcs = [ - "bench/f32-raddexpminusmax.cc", - "src/xnnpack/AlignedAllocator.h", -@@ -4688,7 +4700,7 @@ xnnpack_benchmark( - ) - - xnnpack_benchmark( -- name = "f32_raddextexp_bench", -+ name = "f32_raddextexp_bench.wasm", - srcs = [ - "bench/f32-raddextexp.cc", - "src/xnnpack/AlignedAllocator.h", -@@ -4697,7 +4709,7 @@ xnnpack_benchmark( - ) - - xnnpack_benchmark( -- name = "f32_raddstoreexpminusmax_bench", -+ name = "f32_raddstoreexpminusmax_bench.wasm", - srcs = [ - "bench/f32-raddstoreexpminusmax.cc", - "src/xnnpack/AlignedAllocator.h", -@@ -4706,7 +4718,7 @@ xnnpack_benchmark( - ) - - xnnpack_benchmark( -- name = "f32_relu_bench", -+ name = "f32_relu_bench.wasm", - srcs = [ - "bench/f32-relu.cc", - "src/xnnpack/AlignedAllocator.h", -@@ -4715,7 +4727,7 @@ xnnpack_benchmark( - ) - - xnnpack_benchmark( -- name = "f32_rmax_bench", -+ name = "f32_rmax_bench.wasm", - srcs = [ - "bench/f32-rmax.cc", - "src/xnnpack/AlignedAllocator.h", -@@ -4724,7 +4736,7 @@ xnnpack_benchmark( - ) - - xnnpack_benchmark( -- name = "f32_sigmoid_bench", -+ name = "f32_sigmoid_bench.wasm", - srcs = [ - "bench/f32-sigmoid.cc", - "src/xnnpack/AlignedAllocator.h", -@@ -4733,7 +4745,7 @@ xnnpack_benchmark( - ) - - xnnpack_benchmark( -- name = "f32_spmm_bench", -+ name = "f32_spmm_bench.wasm", - srcs = [ - "bench/f32-spmm.cc", - "bench/gemm.h", -@@ -4743,7 +4755,7 @@ xnnpack_benchmark( - ) - - xnnpack_benchmark( -- name = "f32_softmax_bench", -+ name = "f32_softmax_bench.wasm", - srcs = [ - "bench/f32-softmax.cc", - ] + MICROKERNEL_BENCHMARK_HDRS, -@@ -4752,7 +4764,7 @@ xnnpack_benchmark( - ) - - xnnpack_benchmark( -- name = "f32_vscaleexpminusmax_bench", -+ name = "f32_vscaleexpminusmax_bench.wasm", - srcs = [ - "bench/f32-vscaleexpminusmax.cc", - "src/xnnpack/AlignedAllocator.h", -@@ -4761,7 +4773,7 @@ xnnpack_benchmark( - ) - - xnnpack_benchmark( -- name = "f32_vscaleextexp_bench", -+ name = "f32_vscaleextexp_bench.wasm", - srcs = [ - "bench/f32-vscaleextexp.cc", - "src/xnnpack/AlignedAllocator.h", -@@ -4770,7 +4782,7 @@ xnnpack_benchmark( - ) - - xnnpack_benchmark( -- name = "f32_vsqrt_bench", -+ name = "f32_vsqrt_bench.wasm", - srcs = [ - "bench/f32-vsqrt.cc", - "src/xnnpack/AlignedAllocator.h", -@@ -4779,7 +4791,7 @@ xnnpack_benchmark( - ) - - xnnpack_benchmark( -- name = "f32_im2col_gemm_bench", -+ name = "f32_im2col_gemm_bench.wasm", - srcs = [ - "bench/f32-im2col-gemm.cc", - "bench/conv.h", -@@ -4792,7 +4804,7 @@ xnnpack_benchmark( - ) - - xnnpack_benchmark( -- name = "rounding_bench", -+ name = "rounding_bench.wasm", - srcs = [ - "bench/rounding.cc", - "src/xnnpack/AlignedAllocator.h", -@@ -4804,7 +4816,7 @@ xnnpack_benchmark( - ########################### Benchmarks for operators ########################### - - xnnpack_benchmark( -- name = "average_pooling_bench", -+ name = "average_pooling_bench.wasm", - srcs = ["bench/average-pooling.cc"], - copts = xnnpack_optional_tflite_copts(), - tags = ["nowin32"], -@@ -4812,7 +4824,7 @@ xnnpack_benchmark( - ) - - xnnpack_benchmark( -- name = "bankers_rounding_bench", -+ name = "bankers_rounding_bench.wasm", - srcs = ["bench/bankers-rounding.cc"], - copts = xnnpack_optional_tflite_copts(), - tags = ["nowin32"], -@@ -4820,7 +4832,7 @@ xnnpack_benchmark( - ) - - xnnpack_benchmark( -- name = "ceiling_bench", -+ name = "ceiling_bench.wasm", - srcs = ["bench/ceiling.cc"], - copts = xnnpack_optional_tflite_copts(), - tags = ["nowin32"], -@@ -4828,13 +4840,13 @@ xnnpack_benchmark( - ) - - xnnpack_benchmark( -- name = "channel_shuffle_bench", -+ name = "channel_shuffle_bench.wasm", - srcs = ["bench/channel-shuffle.cc"], - deps = OPERATOR_BENCHMARK_DEPS, - ) - - xnnpack_benchmark( -- name = "convolution_bench", -+ name = "convolution_bench.wasm", - srcs = ["bench/convolution.cc"], - copts = xnnpack_optional_tflite_copts() + xnnpack_optional_armcl_copts(), - tags = ["nowin32"], -@@ -4842,7 +4854,7 @@ xnnpack_benchmark( - ) - - xnnpack_benchmark( -- name = "deconvolution_bench", -+ name = "deconvolution_bench.wasm", - srcs = ["bench/deconvolution.cc"], - copts = xnnpack_optional_tflite_copts(), - tags = ["nowin32"], -@@ -4850,7 +4862,7 @@ xnnpack_benchmark( - ) - - xnnpack_benchmark( -- name = "floor_bench", -+ name = "floor_bench.wasm", - srcs = ["bench/floor.cc"], - copts = xnnpack_optional_tflite_copts(), - tags = ["nowin32"], -@@ -4858,13 +4870,13 @@ xnnpack_benchmark( - ) - - xnnpack_benchmark( -- name = "global_average_pooling_bench", -+ name = "global_average_pooling_bench.wasm", - srcs = ["bench/global-average-pooling.cc"], - deps = OPERATOR_BENCHMARK_DEPS, - ) - - xnnpack_benchmark( -- name = "hardswish_bench", -+ name = "hardswish_bench.wasm", - srcs = ["bench/hardswish.cc"], - copts = xnnpack_optional_tflite_copts(), - tags = ["nowin32"], -@@ -4872,13 +4884,13 @@ xnnpack_benchmark( - ) - - xnnpack_benchmark( -- name = "max_pooling_bench", -+ name = "max_pooling_bench.wasm", - srcs = ["bench/max-pooling.cc"], - deps = OPERATOR_BENCHMARK_DEPS, - ) - - xnnpack_benchmark( -- name = "sigmoid_bench", -+ name = "sigmoid_bench.wasm", - srcs = ["bench/sigmoid.cc"], - copts = xnnpack_optional_tflite_copts(), - tags = ["nowin32"], -@@ -4886,7 +4898,7 @@ xnnpack_benchmark( - ) - - xnnpack_benchmark( -- name = "prelu_bench", -+ name = "prelu_bench.wasm", - srcs = ["bench/prelu.cc"], - copts = xnnpack_optional_tflite_copts(), - tags = ["nowin32"], -@@ -4894,7 +4906,7 @@ xnnpack_benchmark( - ) - - xnnpack_benchmark( -- name = "softmax_bench", -+ name = "softmax_bench.wasm", - srcs = ["bench/softmax.cc"], - copts = xnnpack_optional_tflite_copts(), - tags = ["nowin32"], -@@ -4902,7 +4914,7 @@ xnnpack_benchmark( - ) - - xnnpack_benchmark( -- name = "square_root_bench", -+ name = "square_root_bench.wasm", - srcs = ["bench/square-root.cc"], - copts = xnnpack_optional_tflite_copts(), - tags = ["nowin32"], -@@ -4910,7 +4922,7 @@ xnnpack_benchmark( - ) - - xnnpack_benchmark( -- name = "truncation_bench", -+ name = "truncation_bench.wasm", - srcs = ["bench/truncation.cc"], - deps = OPERATOR_BENCHMARK_DEPS, - ) -@@ -4918,7 +4930,7 @@ xnnpack_benchmark( - ############################# End-to-end benchmarks ############################ - - cc_library( -- name = "fp32_mobilenet_v1", -+ name = "fp32_mobilenet_v1.wasm", - srcs = ["models/fp32-mobilenet-v1.cc"], - hdrs = ["models/models.h"], - copts = xnnpack_std_cxxopts(), -@@ -4930,7 +4942,7 @@ cc_library( - ) - - cc_library( -- name = "fp16_mobilenet_v1", -+ name = "fp16_mobilenet_v1.wasm", - srcs = ["models/fp16-mobilenet-v1.cc"], - hdrs = ["models/models.h"], - copts = xnnpack_std_cxxopts(), -@@ -4943,7 +4955,7 @@ cc_library( - ) - - cc_library( -- name = "qs8_mobilenet_v1", -+ name = "qs8_mobilenet_v1.wasm", - srcs = ["models/qs8-mobilenet-v1.cc"], - hdrs = ["models/models.h"], - copts = xnnpack_std_cxxopts(), -@@ -4955,7 +4967,7 @@ cc_library( - ) - - cc_library( -- name = "qs8_mobilenet_v2", -+ name = "qs8_mobilenet_v2.wasm", - srcs = ["models/qs8-mobilenet-v2.cc"], - hdrs = ["models/models.h"], - copts = xnnpack_std_cxxopts(), -@@ -4967,7 +4979,7 @@ cc_library( - ) - - cc_library( -- name = "fp32_mobilenet_v2", -+ name = "fp32_mobilenet_v2.wasm", - srcs = ["models/fp32-mobilenet-v2.cc"], - hdrs = ["models/models.h"], - copts = xnnpack_std_cxxopts(), -@@ -4979,7 +4991,7 @@ cc_library( - ) - - cc_library( -- name = "fp16_mobilenet_v2", -+ name = "fp16_mobilenet_v2.wasm", - srcs = ["models/fp16-mobilenet-v2.cc"], - hdrs = ["models/models.h"], - copts = xnnpack_std_cxxopts(), -@@ -4992,7 +5004,7 @@ cc_library( - ) - - cc_library( -- name = "fp32_mobilenet_v3_large", -+ name = "fp32_mobilenet_v3_large.wasm", - srcs = ["models/fp32-mobilenet-v3-large.cc"], - hdrs = ["models/models.h"], - copts = xnnpack_std_cxxopts(), -@@ -5004,7 +5016,7 @@ cc_library( - ) - - cc_library( -- name = "fp16_mobilenet_v3_large", -+ name = "fp16_mobilenet_v3_large.wasm", - srcs = ["models/fp16-mobilenet-v3-large.cc"], - hdrs = ["models/models.h"], - copts = xnnpack_std_cxxopts(), -@@ -5017,7 +5029,7 @@ cc_library( - ) - - cc_library( -- name = "fp32_mobilenet_v3_small", -+ name = "fp32_mobilenet_v3_small.wasm", - srcs = ["models/fp32-mobilenet-v3-small.cc"], - hdrs = ["models/models.h"], - copts = xnnpack_std_cxxopts(), -@@ -5029,7 +5041,7 @@ cc_library( - ) - - cc_library( -- name = "fp16_mobilenet_v3_small", -+ name = "fp16_mobilenet_v3_small.wasm", - srcs = ["models/fp16-mobilenet-v3-small.cc"], - hdrs = ["models/models.h"], - copts = xnnpack_std_cxxopts(), -@@ -5042,51 +5054,51 @@ cc_library( - ) - - xnnpack_benchmark( -- name = "f32_dwconv_e2e_bench", -+ name = "f32_dwconv_e2e_bench.wasm", - srcs = [ - "bench/f32-dwconv-e2e.cc", - "bench/end2end.h", - ] + MICROKERNEL_BENCHMARK_HDRS, - deps = MICROKERNEL_BENCHMARK_DEPS + [ - ":XNNPACK", -- ":fp32_mobilenet_v1", -- ":fp32_mobilenet_v2", -- ":fp32_mobilenet_v3_large", -- ":fp32_mobilenet_v3_small", -+ ":fp32_mobilenet_v1.wasm", -+ ":fp32_mobilenet_v2.wasm", -+ ":fp32_mobilenet_v3_large.wasm", -+ ":fp32_mobilenet_v3_small.wasm", - ], - ) - - xnnpack_benchmark( -- name = "f32_gemm_e2e_bench", -+ name = "f32_gemm_e2e_bench.wasm", - srcs = [ - "bench/f32-gemm-e2e.cc", - "bench/end2end.h", - ] + MICROKERNEL_BENCHMARK_HDRS, - deps = MICROKERNEL_BENCHMARK_DEPS + [ - ":XNNPACK", -- ":fp32_mobilenet_v1", -- ":fp32_mobilenet_v2", -- ":fp32_mobilenet_v3_large", -- ":fp32_mobilenet_v3_small", -+ ":fp32_mobilenet_v1.wasm", -+ ":fp32_mobilenet_v2.wasm", -+ ":fp32_mobilenet_v3_large.wasm", -+ ":fp32_mobilenet_v3_small.wasm", - ], - ) - - xnnpack_benchmark( -- name = "end2end_bench", -+ name = "end2end_bench.wasm", - srcs = ["bench/end2end.cc"], - deps = [ - ":XNNPACK", - ":bench_utils", -- ":fp16_mobilenet_v1", -- ":fp16_mobilenet_v2", -- ":fp16_mobilenet_v3_large", -- ":fp16_mobilenet_v3_small", -- ":fp32_mobilenet_v1", -- ":fp32_mobilenet_v2", -- ":fp32_mobilenet_v3_large", -- ":fp32_mobilenet_v3_small", -- ":qs8_mobilenet_v1", -- ":qs8_mobilenet_v2", -+ ":fp16_mobilenet_v1.wasm", -+ ":fp16_mobilenet_v2.wasm", -+ ":fp16_mobilenet_v3_large.wasm", -+ ":fp16_mobilenet_v3_small.wasm", -+ ":fp32_mobilenet_v1.wasm", -+ ":fp32_mobilenet_v2.wasm", -+ ":fp32_mobilenet_v3_large.wasm", -+ ":fp32_mobilenet_v3_small.wasm", -+ ":qs8_mobilenet_v1.wasm", -+ ":qs8_mobilenet_v2.wasm", - "@pthreadpool", - ], - ) -@@ -5094,7 +5106,7 @@ xnnpack_benchmark( - #################### Accuracy evaluation for math functions #################### - - xnnpack_benchmark( -- name = "f32_exp_eval", -+ name = "f32_exp_eval.wasm", - srcs = [ - "eval/f32-exp.cc", - "src/xnnpack/AlignedAllocator.h", -@@ -5103,7 +5115,7 @@ xnnpack_benchmark( - ) - - xnnpack_benchmark( -- name = "f32_expminus_eval", -+ name = "f32_expminus_eval.wasm", - srcs = [ - "eval/f32-expminus.cc", - "src/xnnpack/AlignedAllocator.h", -@@ -5112,7 +5124,7 @@ xnnpack_benchmark( - ) - - xnnpack_benchmark( -- name = "f32_extexp_eval", -+ name = "f32_extexp_eval.wasm", - srcs = [ - "eval/f32-extexp.cc", - "src/xnnpack/AlignedAllocator.h", -@@ -5121,7 +5133,7 @@ xnnpack_benchmark( - ) - - xnnpack_unit_test( -- name = "f32_roundne_eval", -+ name = "f32_roundne_eval.wasm", - srcs = [ - "eval/f32-roundne.cc", - "src/xnnpack/AlignedAllocator.h", -@@ -5132,7 +5144,7 @@ xnnpack_unit_test( - ) - - xnnpack_unit_test( -- name = "f32_roundd_eval", -+ name = "f32_roundd_eval.wasm", - srcs = [ - "eval/f32-roundd.cc", - "src/xnnpack/AlignedAllocator.h", -@@ -5143,7 +5155,7 @@ xnnpack_unit_test( - ) - - xnnpack_unit_test( -- name = "f32_roundu_eval", -+ name = "f32_roundu_eval.wasm", - srcs = [ - "eval/f32-roundu.cc", - "src/xnnpack/AlignedAllocator.h", -@@ -5154,7 +5166,7 @@ xnnpack_unit_test( - ) - - xnnpack_unit_test( -- name = "f32_roundz_eval", -+ name = "f32_roundz_eval.wasm", - srcs = [ - "eval/f32-roundz.cc", - "src/xnnpack/AlignedAllocator.h", -@@ -5165,7 +5177,7 @@ xnnpack_unit_test( - ) - - xnnpack_benchmark( -- name = "f32_sigmoid_eval", -+ name = "f32_sigmoid_eval.wasm", - srcs = [ - "eval/f32-sigmoid.cc", - "src/xnnpack/AlignedAllocator.h", -@@ -5174,7 +5186,7 @@ xnnpack_benchmark( - ) - - xnnpack_benchmark( -- name = "f32_sqrt_eval", -+ name = "f32_sqrt_eval.wasm", - srcs = [ - "eval/f32-sqrt.cc", - "src/xnnpack/AlignedAllocator.h", + def xnnpack_visibility(): + """Visibility of :XNNPACK target. +@@ -424,10 +424,15 @@ def xnnpack_benchmark(name, srcs, copts = [], deps = [], tags = []): + ":windows_x86_64_mingw": ["-Wno-unused-function"], + ":windows_x86_64_msys": ["-Wno-unused-function"], + ":windows_x86_64": [], ++ ":emscripten": xnnpack_emscripten_benchmark_copts(), ++ ":emscripten_wasm": xnnpack_emscripten_benchmark_copts(), ++ ":emscripten_wasmsimd": xnnpack_emscripten_benchmark_copts(), + "//conditions:default": ["-Wno-unused-function"], + }) + copts, + linkopts = select({ + ":emscripten": xnnpack_emscripten_benchmark_linkopts(), ++ ":emscripten_wasm": xnnpack_emscripten_benchmark_linkopts(), ++ ":emscripten_wasmsimd": xnnpack_emscripten_benchmark_linkopts(), + ":windows_x86_64_mingw": ["-lshlwapi"], + ":windows_x86_64_msys": ["-lshlwapi"], + "//conditions:default": [], diff --git a/emscripten.bzl b/emscripten.bzl -index faad087..2b4763f 100644 +index 0a0caedf..d28afa30 100644 --- a/emscripten.bzl +++ b/emscripten.bzl -@@ -4,30 +4,25 @@ def xnnpack_emscripten_minimal_linkopts(): - """Minimal Emscripten-specific linkopts for binaries.""" - return [ - "-s ASSERTIONS=0", -- "-s ERROR_ON_UNDEFINED_SYMBOLS=1", -- "-s EXIT_RUNTIME=1", -+ "-s ERROR_ON_UNDEFINED_SYMBOLS=0", - ] - - def xnnpack_emscripten_test_linkopts(): - """Emscripten-specific linkopts for unit tests.""" - return [ - "-s ASSERTIONS=2", -- "-s ERROR_ON_UNDEFINED_SYMBOLS=1", -+ "-s ERROR_ON_UNDEFINED_SYMBOLS=0", - "-s DEMANGLE_SUPPORT=1", -- "-s EXIT_RUNTIME=1", - "-s ALLOW_MEMORY_GROWTH=1", -- "--pre-js $(location :preamble.js.lds)", - ] - - def xnnpack_emscripten_benchmark_linkopts(): +@@ -23,15 +23,28 @@ def xnnpack_emscripten_benchmark_linkopts(): """Emscripten-specific linkopts for benchmarks.""" return [ "-s ASSERTIONS=1", - "-s ERROR_ON_UNDEFINED_SYMBOLS=1", - "-s EXIT_RUNTIME=1", +- "-s ALLOW_MEMORY_GROWTH=1", + "-s ERROR_ON_UNDEFINED_SYMBOLS=0", - "-s ALLOW_MEMORY_GROWTH=1", - "-s TOTAL_MEMORY=268435456", # 256M ++ "-s ALLOW_MEMORY_GROWTH=0", + "-s TOTAL_MEMORY=436207616", # 416M - "--pre-js $(location :preamble.js.lds)", ++ "-s USE_PTHREADS=0", ++ "-s STANDALONE_WASM=1", ++ "-Wno-unused", ++ "-Wl,--export=__heap_base", ++ "-Wl,--export=__data_end", ++ "-Wl,--export=malloc", ++ "-Wl,--export=free", ] def xnnpack_emscripten_deps(): + """Emscripten-specific dependencies for unit tests and benchmarks.""" ++ return [] ++ ++def xnnpack_emscripten_benchmark_copts(): + return [ +- ":preamble.js.lds", ++ "-s ASSERTIONS=1", ++ "-s ERROR_ON_UNDEFINED_SYMBOLS=0", ++ "-s ALLOW_MEMORY_GROWTH=0", ++ "-s USE_PTHREADS=0", ++ "-s STANDALONE_WASM=1", ++ "-Wno-unused", + ] +diff --git a/third_party/cpuinfo.BUILD b/third_party/cpuinfo.BUILD +index 128d683e..f6c287c4 100644 +--- a/third_party/cpuinfo.BUILD ++++ b/third_party/cpuinfo.BUILD +@@ -343,5 +343,5 @@ config_setting( + + config_setting( + name = "emscripten", +- values = {"crosstool_top": "//toolchain:emscripten"}, ++ values = {"crosstool_top": "@emsdk//emscripten_toolchain:everything"}, + ) diff --git a/samples/workload/docker/Dockerfile b/samples/workload/docker/Dockerfile index 4c57c668b..9906920dd 100644 --- a/samples/workload/docker/Dockerfile +++ b/samples/workload/docker/Dockerfile @@ -17,7 +17,6 @@ ARG WASI_SDK_VER=12 ARG WABT_VER=1.0.20 ARG CMAKE_VER=3.16.2 ARG BINARYEN_VER=version_97 -ARG BAZEL_VER=3.7.0 # # install wasi-sdk @@ -66,13 +65,13 @@ RUN cd /opt \ && rm ${BINARYEN_FILE} \ && ln -sf /opt/binaryen-${BINARYEN_VER} /opt/binaryen -# # -# # install bazel -# ARG BAZEL_FILE=bazel-${BAZEL_VER}-installer-linux-x86_64.sh -# COPY ${BAZEL_FILE} /tmp -# RUN cd /tmp \ -# && chmod a+x ${BAZEL_FILE} \ -# && ./${BAZEL_FILE} +# +# install bazelisk +ARG BAZEL_FILE="bazelisk-linux-amd64" +COPY ${BAZEL_FILE} /opt/bazelisk/bin/bazelisk +RUN cd /opt/bazelisk/bin/ \ + && chmod a+x bazelisk \ + && ln -sf /opt/bazelisk/bin/bazelisk /usr/local/bin/bazel # # Clean up diff --git a/samples/workload/docker/docker_build.sh b/samples/workload/docker/docker_build.sh index ec502d55a..d4cb10a33 100755 --- a/samples/workload/docker/docker_build.sh +++ b/samples/workload/docker/docker_build.sh @@ -13,7 +13,7 @@ readonly WASI_SDK_VER=12 readonly WABT_VER=1.0.20 readonly CMAKE_VER=3.16.2 readonly BINARYEN_VER=version_97 -readonly BAZEL_VER=3.7.0 +readonly BAZELISK_VER=1.7.5 cd ${BUILD_CONTENT} || exit if [[ ! -f wasi-sdk-${WASI_SDK_VER}.0-linux.tar.gz ]]; then @@ -36,24 +36,22 @@ if [[ ! -f binaryen-${BINARYEN_VER}-x86_64-linux.tar.gz ]]; then wget https://github.com/WebAssembly/binaryen/releases/download/${BINARYEN_VER}/binaryen-${BINARYEN_VER}-x86_64-linux.tar.gz fi -if [[ ! -f bazel-${BAZEL_VER}-installer-linux-x86_64.sh ]]; then - wget https://github.com/bazelbuild/bazel/releases/download/${BAZEL_VER}/bazel-${BAZEL_VER}-installer-linux-x86_64.sh +if [[ ! -f bazelisk-linux-amd64.sh ]]; then + wget https://github.com/bazelbuild/bazelisk/releases/download/v${BAZELISK_VER}/bazelisk-linux-amd64 fi cd - > /dev/null || exit DOCKERFILE_PATH=$(dirname "$(realpath "$0")") docker build \ - --build-arg WASI_SDK_VER=${WASI_SDK_VER} \ - --build-arg WABT_VER=${WABT_VER} \ - --build-arg CMAKE_VER=${CMAKE_VER} \ - --build-arg BINARYEN_VER=${BINARYEN_VER} \ - --build-arg BAZEL_VER=${BAZEL_VER} \ - -t clang_env:0.1 -f "${DOCKERFILE_PATH}"/Dockerfile ${BUILD_CONTENT} - -docker run --rm -it \ - --name workload_w_clang \ - --mount type=bind,source="$(pwd)",target=/data/project \ - -w /data/project \ - clang_env:0.1 \ - /bin/bash -c /build.sh + --build-arg WASI_SDK_VER=${WASI_SDK_VER} \ + --build-arg WABT_VER=${WABT_VER} \ + --build-arg CMAKE_VER=${CMAKE_VER} \ + --build-arg BINARYEN_VER=${BINARYEN_VER} \ + -t clang_env:0.1 -f "${DOCKERFILE_PATH}"/Dockerfile ${BUILD_CONTENT} \ + && docker run --rm \ + --name workload_w_clang \ + --mount type=bind,source="$(pwd)",target=/data/project \ + -w /data/project \ + clang_env:0.1 \ + /bin/bash -c /build.sh From fa5f4fe94092753dd24cbe02031de40ed0c623bc Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Tue, 27 Apr 2021 17:18:27 +0800 Subject: [PATCH 188/207] Implement Windows boundary check with hardware trap (#623) --- build-scripts/config_common.cmake | 8 +- core/iwasm/aot/aot_loader.c | 54 ++++++- core/iwasm/aot/aot_runtime.c | 104 ++++++++++++- core/iwasm/aot/aot_runtime.h | 38 +++++ core/iwasm/aot/arch/aot_reloc_x86_64.c | 23 ++- core/iwasm/common/wasm_runtime_common.c | 6 +- .../libc-builtin/libc_builtin_wrapper.c | 8 + core/shared/platform/windows/platform_init.c | 13 ++ .../platform/windows/platform_internal.h | 36 ++++- .../windows/{posix_malloc.c => win_malloc.c} | 0 core/shared/platform/windows/win_memmap.c | 138 ++++++++++++------ core/shared/platform/windows/win_thread.c | 27 +++- wamr-compiler/CMakeLists.txt | 8 +- 13 files changed, 400 insertions(+), 63 deletions(-) rename core/shared/platform/windows/{posix_malloc.c => win_malloc.c} (100%) diff --git a/build-scripts/config_common.cmake b/build-scripts/config_common.cmake index 816471633..f6b8e51c0 100644 --- a/build-scripts/config_common.cmake +++ b/build-scripts/config_common.cmake @@ -52,9 +52,11 @@ endif () if (CMAKE_SIZEOF_VOID_P EQUAL 8) if (WAMR_BUILD_TARGET STREQUAL "X86_64" OR WAMR_BUILD_TARGET STREQUAL "AMD_64" OR WAMR_BUILD_TARGET MATCHES "AARCH64.*" OR WAMR_BUILD_TARGET MATCHES "RISCV64.*") - # Add -fPIC flag if build as 64-bit - set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC") - set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "${CMAKE_SHARED_LIBRARY_LINK_C_FLAGS} -fPIC") + if (NOT WAMR_BUILD_PLATFORM STREQUAL "windows") + # Add -fPIC flag if build as 64-bit + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC") + set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "${CMAKE_SHARED_LIBRARY_LINK_C_FLAGS} -fPIC") + endif () else () add_definitions (-m32) set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -m32") diff --git a/core/iwasm/aot/aot_loader.c b/core/iwasm/aot/aot_loader.c index eba9a9dfb..eed71b68c 100644 --- a/core/iwasm/aot/aot_loader.c +++ b/core/iwasm/aot/aot_loader.c @@ -1042,7 +1042,8 @@ load_object_data_sections(const uint8 **p_buf, const uint8 *buf_end, read_uint32(buf, buf_end, data_sections[i].size); /* Allocate memory for data */ - if (!(data_sections[i].data = + if (data_sections[i].size > 0 + && !(data_sections[i].data = os_mmap(NULL, data_sections[i].size, map_prot, map_flags))) { set_error_buf(error_buf, error_buf_size, "allocate memory failed"); @@ -1179,6 +1180,27 @@ load_function_section(const uint8 *buf, const uint8 *buf_end, const uint8 *p = buf, *p_end = buf_end; uint32 i; uint64 size, text_offset; +#if defined(OS_ENABLE_HW_BOUND_CHECK) && defined(BH_PLATFORM_WINDOWS) + RUNTIME_FUNCTION *rtl_func_table; + AOTUnwindInfo *unwind_info; + uint32 unwind_info_offset = module->code_size - sizeof(AOTUnwindInfo); + uint32 unwind_code_offset = unwind_info_offset - PLT_ITEM_SIZE; +#endif + +#if defined(OS_ENABLE_HW_BOUND_CHECK) && defined(BH_PLATFORM_WINDOWS) + unwind_info= (AOTUnwindInfo *)((uint8*)module->code + module->code_size + - sizeof(AOTUnwindInfo)); + unwind_info->Version = 1; + unwind_info->Flags = UNW_FLAG_EHANDLER; + *(uint32*)&unwind_info->UnwindCode[0] = unwind_code_offset; + + size = sizeof(RUNTIME_FUNCTION) * (uint64)module->func_count; + if (size > 0 + && !(rtl_func_table = module->rtl_func_table = + loader_malloc(size, error_buf, error_buf_size))) { + return false; + } +#endif size = sizeof(void*) * (uint64)module->func_count; if (size > 0 @@ -1205,9 +1227,31 @@ load_function_section(const uint8 *buf, const uint8 *buf_end, #if defined(BUILD_TARGET_THUMB) || defined(BUILD_TARGET_THUMB_VFP) /* bits[0] of thumb function address must be 1 */ module->func_ptrs[i] = (void*)((uintptr_t)module->func_ptrs[i] | 1); +#endif +#if defined(OS_ENABLE_HW_BOUND_CHECK) && defined(BH_PLATFORM_WINDOWS) + rtl_func_table[i].BeginAddress = (DWORD)text_offset; + if (i > 0) { + rtl_func_table[i].EndAddress = rtl_func_table[i - 1].BeginAddress; + } + rtl_func_table[i].UnwindInfoAddress = (DWORD)unwind_info_offset; #endif } +#if defined(OS_ENABLE_HW_BOUND_CHECK) && defined(BH_PLATFORM_WINDOWS) + if (module->func_count > 0) { + rtl_func_table[module->func_count - 1].EndAddress = + (DWORD)(module->code_size - get_plt_table_size()); + + if (!RtlAddFunctionTable(rtl_func_table, module->func_count, + (DWORD64)(uintptr_t)module->code)) { + set_error_buf(error_buf, error_buf_size, + "add dynamic function table failed"); + return false; + } + module->rtl_func_table_registered = true; + } +#endif + /* Set start function when function pointers are resolved */ if (module->start_func_index != (uint32)-1) { if (module->start_func_index >= module->import_func_count) @@ -2621,6 +2665,14 @@ aot_unload(AOTModule *module) } #endif +#if defined(OS_ENABLE_HW_BOUND_CHECK) && defined(BH_PLATFORM_WINDOWS) + if (module->rtl_func_table) { + if (module->rtl_func_table_registered) + RtlDeleteFunctionTable(module->rtl_func_table); + wasm_runtime_free(module->rtl_func_table); + } +#endif + if (module->data_sections) destroy_object_data_sections(module->data_sections, module->data_section_count); diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index c23388975..970e4e926 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -339,6 +339,11 @@ memories_deinstantiate(AOTModuleInstance *module_inst) #ifndef OS_ENABLE_HW_BOUND_CHECK wasm_runtime_free(memory_inst->memory_data.ptr); #else +#ifdef BH_PLATFORM_WINDOWS + os_mem_decommit(memory_inst->memory_data.ptr, + memory_inst->num_bytes_per_page + * memory_inst->cur_page_count); +#endif os_munmap((uint8*)memory_inst->memory_data.ptr, 8 * (uint64)BH_GB); #endif @@ -499,8 +504,19 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModule *module, return NULL; } +#ifdef BH_PLATFORM_WINDOWS + if (!os_mem_commit(p, total_size, MMAP_PROT_READ | MMAP_PROT_WRITE)) { + set_error_buf(error_buf, error_buf_size, "commit memory failed"); + os_munmap(mapped_mem, map_size); + return NULL; + } +#endif + if (os_mprotect(p, total_size, MMAP_PROT_READ | MMAP_PROT_WRITE) != 0) { set_error_buf(error_buf, error_buf_size, "mprotec memory failed"); +#ifdef BH_PLATFORM_WINDOWS + os_mem_decommit(p, total_size); +#endif os_munmap(mapped_mem, map_size); return NULL; } @@ -583,6 +599,10 @@ fail1: if (memory_inst->memory_data.ptr) wasm_runtime_free(memory_inst->memory_data.ptr); #else +#ifdef BH_PLATFORM_WINDOWS + if (memory_inst->memory_data.ptr) + os_mem_decommit(p, total_size); +#endif os_munmap(mapped_mem, map_size); #endif memory_inst->memory_data.ptr = NULL; @@ -1129,8 +1149,16 @@ aot_lookup_function(const AOTModuleInstance *module_inst, static os_thread_local_attribute WASMExecEnv *aot_exec_env = NULL; +#ifndef BH_PLATFORM_WINDOWS static void aot_signal_handler(void *sig_addr) +#else +EXCEPTION_DISPOSITION +aot_exception_handler(PEXCEPTION_RECORD ExceptionRecord, + ULONG64 EstablisherFrame, + PCONTEXT ContextRecord, + PDISPATCHER_CONTEXT DispatcherContext) +#endif { AOTModuleInstance *module_inst; AOTMemoryInstance *memory_inst; @@ -1140,11 +1168,18 @@ aot_signal_handler(void *sig_addr) uint8 *stack_min_addr; uint32 page_size; uint32 guard_page_count = STACK_OVERFLOW_CHECK_GUARD_PAGE_COUNT; +#ifdef BH_PLATFORM_WINDOWS + uint8 *sig_addr = (uint8*)ExceptionRecord->ExceptionInformation[1]; +#endif /* Check whether current thread is running aot function */ if (aot_exec_env && aot_exec_env->handle == os_self_thread() - && (jmpbuf_node = aot_exec_env->jmpbuf_stack_top)) { + && (jmpbuf_node = aot_exec_env->jmpbuf_stack_top) +#ifdef BH_PLATFORM_WINDOWS + && ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION +#endif + ) { /* Get mapped mem info of current instance */ module_inst = (AOTModuleInstance *)aot_exec_env->module_inst; /* Get the default memory instance */ @@ -1176,18 +1211,60 @@ aot_signal_handler(void *sig_addr) os_longjmp(jmpbuf_node->jmpbuf, 1); } } + +#ifdef BH_PLATFORM_WINDOWS + ContextRecord->Rip += 3; + return EXCEPTION_CONTINUE_SEARCH; + (void)EstablisherFrame; + (void)ContextRecord; + (void)DispatcherContext; +#endif } +#ifdef BH_PLATFORM_WINDOWS +static LONG +stack_overflow_handler(EXCEPTION_POINTERS *exce_info) +{ + AOTModuleInstance* module_inst; + WASMJmpBuf* jmpbuf_node; + + /* Check whether it is stack overflow exception and + current thread is running aot function */ + if (exce_info->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW + && aot_exec_env + && aot_exec_env->handle == os_self_thread() + && (jmpbuf_node = aot_exec_env->jmpbuf_stack_top)) { + /* Set stack overflow exception and let the aot func continue + to run, when the aot func returns, the caller will check + whether the exception is thrown and return to runtime, and + the damaged stack will be recovered by _resetstkoflw(). */ + module_inst = (AOTModuleInstance*)aot_exec_env->module_inst; + aot_set_exception_with_id(module_inst, EXCE_NATIVE_STACK_OVERFLOW); + return EXCEPTION_CONTINUE_EXECUTION; + } + return EXCEPTION_CONTINUE_SEARCH; +} +#endif + bool aot_signal_init() { +#ifndef BH_PLATFORM_WINDOWS return os_signal_init(aot_signal_handler) == 0 ? true : false; +#else + return AddVectoredExceptionHandler(1, stack_overflow_handler) + ? true : false; +#endif } void aot_signal_destroy() { +#ifndef BH_PLATFORM_WINDOWS os_signal_destroy(); +#else + RemoveVectoredExceptionHandler(stack_overflow_handler); +#endif } static bool @@ -1201,6 +1278,10 @@ invoke_native_with_hw_bound_check(WASMExecEnv *exec_env, void *func_ptr, WASMJmpBuf jmpbuf_node = { 0 }, *jmpbuf_node_pop; uint32 page_size = os_getpagesize(); uint32 guard_page_count = STACK_OVERFLOW_CHECK_GUARD_PAGE_COUNT; +#if BH_PLATFORM_WINDOWS + const char *exce; + int result; +#endif bool ret; /* Check native stack overflow firstly to ensure we have enough @@ -1226,6 +1307,15 @@ invoke_native_with_hw_bound_check(WASMExecEnv *exec_env, void *func_ptr, ret = wasm_runtime_invoke_native(exec_env, func_ptr, func_type, signature, attachment, argv, argc, argv_ret); +#ifdef BH_PLATFORM_WINDOWS + if ((exce = aot_get_exception(module_inst)) + && strstr(exce, "native stack overflow")) { + /* After a stack overflow, the stack was left + in a damaged state, let the CRT repair it */ + result = _resetstkoflw(); + bh_assert(result != 0); + } +#endif } else { /* Exception has been set in signal handler before calling longjmp */ @@ -1992,9 +2082,21 @@ aot_enlarge_memory(AOTModuleInstance *module_inst, uint32 inc_page_count) return false; } +#ifdef BH_PLATFORM_WINDOWS + if (!os_mem_commit(memory_inst->memory_data_end.ptr, + num_bytes_per_page * inc_page_count, + MMAP_PROT_READ | MMAP_PROT_WRITE)) { + return false; + } +#endif + if (os_mprotect(memory_inst->memory_data_end.ptr, num_bytes_per_page * inc_page_count, MMAP_PROT_READ | MMAP_PROT_WRITE) != 0) { +#ifdef BH_PLATFORM_WINDOWS + os_mem_decommit(memory_inst->memory_data_end.ptr, + num_bytes_per_page * inc_page_count); +#endif return false; } diff --git a/core/iwasm/aot/aot_runtime.h b/core/iwasm/aot/aot_runtime.h index f93e8f0c6..a81224353 100644 --- a/core/iwasm/aot/aot_runtime.h +++ b/core/iwasm/aot/aot_runtime.h @@ -88,6 +88,28 @@ typedef struct AOTFunctionInstance { } u; } AOTFunctionInstance; +#if defined(OS_ENABLE_HW_BOUND_CHECK) && defined(BH_PLATFORM_WINDOWS) +typedef struct AOTUnwindInfo { + uint8 Version : 3; + uint8 Flags : 5; + uint8 SizeOfProlog; + uint8 CountOfCodes; + uint8 FrameRegister : 4; + uint8 FrameOffset : 4; + struct { + struct { + uint8 CodeOffset; + uint8 UnwindOp : 4; + uint8 OpInfo : 4; + }; + uint16 FrameOffset; + } UnwindCode[1]; +} AOTUnwindInfo; + +/* size of mov instruction and jmp instruction */ +#define PLT_ITEM_SIZE 12 +#endif + typedef struct AOTModule { uint32 module_type; @@ -173,6 +195,14 @@ typedef struct AOTModule { uint32 float_plt_count; #endif +#if defined(OS_ENABLE_HW_BOUND_CHECK) && defined(BH_PLATFORM_WINDOWS) + /* dynamic function table to be added by RtlAddFunctionTable(), + used to unwind the call stack and register exception handler + for AOT functions */ + RUNTIME_FUNCTION *rtl_func_table; + bool rtl_func_table_registered; +#endif + /* data sections in AOT object file, including .data, .rodata * and .rodata.cstN. NULL for JIT mode. */ AOTObjectDataSection *data_sections; @@ -629,6 +659,14 @@ aot_signal_init(); void aot_signal_destroy(); + +#ifdef BH_PLATFORM_WINDOWS +EXCEPTION_DISPOSITION +aot_exception_handler(PEXCEPTION_RECORD ExceptionRecord, + ULONG64 EstablisherFrame, + PCONTEXT ContextRecord, + PDISPATCHER_CONTEXT DispatcherContext); +#endif #endif void diff --git a/core/iwasm/aot/arch/aot_reloc_x86_64.c b/core/iwasm/aot/arch/aot_reloc_x86_64.c index af090429d..6c61a60b4 100644 --- a/core/iwasm/aot/arch/aot_reloc_x86_64.c +++ b/core/iwasm/aot/arch/aot_reloc_x86_64.c @@ -61,15 +61,22 @@ get_plt_item_size() uint32 get_plt_table_size() { - return get_plt_item_size() * (sizeof(target_sym_map) / sizeof(SymbolMap)); + uint32 size = get_plt_item_size() + * (sizeof(target_sym_map) / sizeof(SymbolMap)); +#if defined(OS_ENABLE_HW_BOUND_CHECK) && defined(BH_PLATFORM_WINDOWS) + size += get_plt_item_size() + sizeof(AOTUnwindInfo); +#endif + return size; } void init_plt_table(uint8 *plt) { uint32 i, num = sizeof(target_sym_map) / sizeof(SymbolMap); + uint8 *p; + for (i = 0; i < num; i++) { - uint8 *p = plt; + p = plt; /* mov symbol_addr, rax */ *p++ = 0x48; *p++ = 0xB8; @@ -80,6 +87,18 @@ init_plt_table(uint8 *plt) *p++ = 0xE0; plt += get_plt_item_size(); } + +#if defined(OS_ENABLE_HW_BOUND_CHECK) && defined(BH_PLATFORM_WINDOWS) + p = plt; + /* mov exception_handler, rax */ + *p++ = 0x48; + *p++ = 0xB8; + *(uint64*)p = (uint64)(uintptr_t)aot_exception_handler; + p += sizeof(uint64); + /* jmp rax */ + *p++ = 0xFF; + *p++ = 0xE0; +#endif } static bool diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index 5c6333604..c96820608 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -2707,7 +2707,8 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, #if WASM_ENABLE_REF_TYPES != 0 case VALUE_TYPE_FUNCREF: { - if (strncasecmp(argv[i], "null", 4) == 0) { + if (strncmp(argv[i], "null", 4) == 0 + || strncmp(argv[i], "NULL", 4) == 0) { argv1[p++] = NULL_REF; } else { @@ -2717,7 +2718,8 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, } case VALUE_TYPE_EXTERNREF: { - if (strncasecmp(argv[i], "null", 4) == 0) { + if (strncmp(argv[i], "null", 4) == 0 + || strncmp(argv[i], "NULL", 4) == 0) { argv1[p++] = NULL_REF; } else { diff --git a/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c b/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c index b2701bcc8..382c7a6de 100644 --- a/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c +++ b/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c @@ -657,7 +657,11 @@ strcpy_wrapper(wasm_exec_env_t exec_env, char *dst, const char *src) if (!validate_native_addr(dst, len)) return 0; +#ifndef BH_PLATFORM_WINDOWS strncpy(dst, src, len); +#else + strncpy_s(dst, len, src, len); +#endif return addr_native_to_app(dst); } @@ -671,7 +675,11 @@ strncpy_wrapper(wasm_exec_env_t exec_env, if (!validate_native_addr(dst, size)) return 0; +#ifndef BH_PLATFORM_WINDOWS strncpy(dst, src, size); +#else + strncpy_s(dst, size, src, size); +#endif return addr_native_to_app(dst); } diff --git a/core/shared/platform/windows/platform_init.c b/core/shared/platform/windows/platform_init.c index 17aeb8baa..a723214b8 100644 --- a/core/shared/platform/windows/platform_init.c +++ b/core/shared/platform/windows/platform_init.c @@ -43,3 +43,16 @@ os_vprintf(const char *format, va_list ap) #endif } +unsigned +os_getpagesize() +{ + SYSTEM_INFO sys_info; + GetNativeSystemInfo(&sys_info); + return (unsigned)sys_info.dwPageSize; +} + +void +os_dcache_flush(void) +{ +} + diff --git a/core/shared/platform/windows/platform_internal.h b/core/shared/platform/windows/platform_internal.h index 877336be5..34da6fa39 100644 --- a/core/shared/platform/windows/platform_internal.h +++ b/core/shared/platform/windows/platform_internal.h @@ -23,6 +23,7 @@ #include #include #include +#include #include #ifdef __cplusplus @@ -49,13 +50,34 @@ typedef struct { unsigned int waiting_count; } korp_cond; -static inline size_t -getpagesize() -{ - SYSTEM_INFO S; - GetNativeSystemInfo(&S); - return S.dwPageSize; -} +unsigned os_getpagesize(); +void *os_mem_commit(void *ptr, size_t size, int flags); +void os_mem_decommit(void *ptr, size_t size); + +#define os_thread_local_attribute __declspec(thread) + +#if WASM_DISABLE_HW_BOUND_CHECK == 0 +#if defined(BUILD_TARGET_X86_64) \ + || defined(BUILD_TARGET_AMD_64) + +#include + +#define OS_ENABLE_HW_BOUND_CHECK + +typedef jmp_buf korp_jmpbuf; + +#define os_setjmp setjmp +#define os_longjmp longjmp + +bool os_thread_init_stack_guard_pages(); + +void os_thread_destroy_stack_guard_pages(); + +#define os_signal_unmask() (void)0 +#define os_sigreturn() (void)0 + +#endif /* end of BUILD_TARGET_X86_64/AMD_64 */ +#endif /* end of WASM_DISABLE_HW_BOUND_CHECK */ #ifdef __cplusplus } diff --git a/core/shared/platform/windows/posix_malloc.c b/core/shared/platform/windows/win_malloc.c similarity index 100% rename from core/shared/platform/windows/posix_malloc.c rename to core/shared/platform/windows/win_malloc.c diff --git a/core/shared/platform/windows/win_memmap.c b/core/shared/platform/windows/win_memmap.c index 1e7d7fd8e..4d45897df 100644 --- a/core/shared/platform/windows/win_memmap.c +++ b/core/shared/platform/windows/win_memmap.c @@ -5,81 +5,133 @@ #include "platform_api_vmcore.h" -void * os_mmap(void *hint, size_t size, int prot, int flags) +#define TRACE_MEMMAP 0 + +static DWORD +access_to_win32_flags(int prot) { - DWORD AllocType = MEM_RESERVE | MEM_COMMIT; - DWORD flProtect = PAGE_NOACCESS; + DWORD protect = PAGE_NOACCESS; + + if (prot & MMAP_PROT_EXEC) { + if (prot & MMAP_PROT_WRITE) + protect = PAGE_EXECUTE_READWRITE; + else + protect = PAGE_EXECUTE_READ; + } + else if (prot & MMAP_PROT_WRITE) { + protect = PAGE_READWRITE; + } + else if (prot & MMAP_PROT_READ) { + protect = PAGE_READONLY; + } + + return protect; +} + +void * +os_mmap(void *hint, size_t size, int prot, int flags) +{ + DWORD alloc_type = MEM_RESERVE; + DWORD protect; size_t request_size, page_size; void *addr; - page_size = getpagesize(); + page_size = os_getpagesize(); request_size = (size + page_size - 1) & ~(page_size - 1); if (request_size < size) /* integer overflow */ return NULL; - if (request_size == 0) - request_size = page_size; - - if (prot & MMAP_PROT_EXEC) { - if (prot & MMAP_PROT_WRITE) - flProtect = PAGE_EXECUTE_READWRITE; - else - flProtect = PAGE_EXECUTE_READ; + protect = access_to_win32_flags(prot); + if (protect != PAGE_NOACCESS) { + alloc_type |= MEM_COMMIT; } - else if (prot & MMAP_PROT_WRITE) - flProtect = PAGE_READWRITE; - else if (prot & MMAP_PROT_READ) - flProtect = PAGE_READONLY; + addr = VirtualAlloc((LPVOID)hint, request_size, alloc_type, protect); - addr = VirtualAlloc((LPVOID)hint, request_size, AllocType, - flProtect); +#if TRACE_MEMMAP != 0 + printf("Map memory, request_size: %zu, alloc_type: 0x%x, " + "protect: 0x%x, ret: %p\n", + request_size, alloc_type, protect, addr); +#endif return addr; } void os_munmap(void *addr, size_t size) { - size_t page_size = getpagesize(); + size_t page_size = os_getpagesize(); size_t request_size = (size + page_size - 1) & ~(page_size - 1); if (addr) { - if (VirtualFree(addr, 0, MEM_RELEASE) == 0) { - if (VirtualFree(addr, size, MEM_DECOMMIT) == 0) { - os_printf("os_munmap error addr:%p, size:0x%lx, errno:%d\n", - addr, request_size, errno); - } + if (!VirtualFree(addr, request_size, MEM_DECOMMIT)) { + printf("warning: os_munmap decommit pages failed, " + "addr: %p, request_size: %zu, errno: %d\n", + addr, request_size, errno); + return; + } + + if (!VirtualFree(addr, 0, MEM_RELEASE)) { + printf("warning: os_munmap release pages failed, " + "addr: %p, size: %zu, errno:%d\n", + addr, request_size, errno); } } +#if TRACE_MEMMAP != 0 + printf("Unmap memory, addr: %p, request_size: %zu\n", + addr, request_size); +#endif +} + +void * +os_mem_commit(void *addr, size_t size, int flags) +{ + DWORD protect = access_to_win32_flags(flags); + size_t page_size = os_getpagesize(); + size_t request_size = (size + page_size - 1) & ~(page_size - 1); + + if (!addr) + return NULL; + +#if TRACE_MEMMAP != 0 + printf("Commit memory, addr: %p, request_size: %zu, protect: 0x%x\n", + addr, request_size, protect); +#endif + return VirtualAlloc((LPVOID)addr, request_size, MEM_COMMIT, protect); +} + +void +os_mem_decommit(void *addr, size_t size) +{ + size_t page_size = os_getpagesize(); + size_t request_size = (size + page_size - 1) & ~(page_size - 1); + + if (!addr) + return; + +#if TRACE_MEMMAP != 0 + printf("Decommit memory, addr: %p, request_size: %zu\n", + addr, request_size); +#endif + VirtualFree((LPVOID)addr, request_size, MEM_DECOMMIT); } int os_mprotect(void *addr, size_t size, int prot) { - DWORD AllocType = MEM_RESERVE | MEM_COMMIT; - DWORD flProtect = PAGE_NOACCESS; + DWORD protect; + size_t page_size = os_getpagesize(); + size_t request_size = (size + page_size - 1) & ~(page_size - 1); if (!addr) return 0; - if (prot & MMAP_PROT_EXEC) { - if (prot & MMAP_PROT_WRITE) - flProtect = PAGE_EXECUTE_READWRITE; - else - flProtect = PAGE_EXECUTE_READ; - } - else if (prot & MMAP_PROT_WRITE) - flProtect = PAGE_READWRITE; - else if (prot & MMAP_PROT_READ) - flProtect = PAGE_READONLY; - - return VirtualProtect((LPVOID)addr, size, flProtect, NULL); + protect = access_to_win32_flags(prot); +#if TRACE_MEMMAP != 0 + printf("Mprotect memory, addr: %p, request_size: %zu, protect: 0x%x\n", + addr, request_size, protect); +#endif + return VirtualProtect((LPVOID)addr, request_size, protect, NULL); } -void -os_dcache_flush(void) -{ - -} diff --git a/core/shared/platform/windows/win_thread.c b/core/shared/platform/windows/win_thread.c index ed2b598e5..0ce313f45 100644 --- a/core/shared/platform/windows/win_thread.c +++ b/core/shared/platform/windows/win_thread.c @@ -149,7 +149,32 @@ void os_thread_exit(void *retval) { } +static os_thread_local_attribute uint8 *thread_stack_boundary = NULL; + uint8 *os_thread_get_stack_boundary() { - return NULL; + ULONG_PTR low_limit = 0, high_limit = 0; + uint32 page_size; + + if (thread_stack_boundary) + return thread_stack_boundary; + + page_size = os_getpagesize(); + GetCurrentThreadStackLimits(&low_limit, &high_limit); + /* 4 pages are set unaccessible by system, we reserved + one more page at least for safety */ + thread_stack_boundary = (uint8*)(uintptr_t)low_limit + page_size * 5; + return thread_stack_boundary; } + +bool +os_thread_init_stack_guard_pages() +{ + return true; +} + +void +os_thread_destroy_stack_guard_pages() +{ +} + diff --git a/wamr-compiler/CMakeLists.txt b/wamr-compiler/CMakeLists.txt index 440970cf5..c1c8c97f7 100644 --- a/wamr-compiler/CMakeLists.txt +++ b/wamr-compiler/CMakeLists.txt @@ -76,9 +76,11 @@ message ("-- Build as target ${WAMR_BUILD_TARGET}") if (CMAKE_SIZEOF_VOID_P EQUAL 8) if (WAMR_BUILD_TARGET STREQUAL "X86_64" OR WAMR_BUILD_TARGET STREQUAL "AMD_64" OR WAMR_BUILD_TARGET MATCHES "AARCH64.*") - # Add -fPIC flag if build as 64-bit - set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC") - set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "${CMAKE_SHARED_LIBRARY_LINK_C_FLAGS} -fPIC") + if (NOT WAMR_BUILD_PLATFORM STREQUAL "windows") + # Add -fPIC flag if build as 64-bit + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC") + set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "${CMAKE_SHARED_LIBRARY_LINK_C_FLAGS} -fPIC") + endif () else () add_definitions (-m32) set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -m32") From 9710d9325f426121cc1f2c62386a71d0c022d613 Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Fri, 30 Apr 2021 09:13:29 +0800 Subject: [PATCH 189/207] Fix wasm-c-api JIT mode issue and enable set LLVM_DIR in cmd line (#624) --- build-scripts/config_common.cmake | 16 +++++++++------- core/iwasm/common/wasm_c_api.c | 19 ++++++++++++------- samples/wasm-c-api/CMakeLists.txt | 4 ++-- 3 files changed, 23 insertions(+), 16 deletions(-) diff --git a/build-scripts/config_common.cmake b/build-scripts/config_common.cmake index f6b8e51c0..233174a1d 100644 --- a/build-scripts/config_common.cmake +++ b/build-scripts/config_common.cmake @@ -80,15 +80,17 @@ endif () if (WAMR_BUILD_JIT EQUAL 1) if (WAMR_BUILD_AOT EQUAL 1) add_definitions("-DWASM_ENABLE_JIT=1") - set (LLVM_SRC_ROOT "${WAMR_ROOT_DIR}/core/deps/llvm") - set (LLVM_BUILD_ROOT "${LLVM_SRC_ROOT}/build") - if (WAMR_BUILD_PLATFORM STREQUAL "windows") + if (NOT DEFINED LLVM_DIR) + set (LLVM_SRC_ROOT "${WAMR_ROOT_DIR}/core/deps/llvm") + set (LLVM_BUILD_ROOT "${LLVM_SRC_ROOT}/build") + if (WAMR_BUILD_PLATFORM STREQUAL "windows") set (LLVM_BUILD_ROOT "${LLVM_SRC_ROOT}/win32build") + endif () + if (NOT EXISTS "${LLVM_BUILD_ROOT}") + message (FATAL_ERROR "Cannot find LLVM dir: ${LLVM_BUILD_ROOT}") + endif () + set (CMAKE_PREFIX_PATH "${LLVM_BUILD_ROOT};${CMAKE_PREFIX_PATH}") endif () - if (NOT EXISTS "${LLVM_BUILD_ROOT}") - message (FATAL_ERROR "Cannot find LLVM dir: ${LLVM_BUILD_ROOT}") - endif () - set (CMAKE_PREFIX_PATH "${LLVM_BUILD_ROOT};${CMAKE_PREFIX_PATH}") find_package(LLVM REQUIRED CONFIG) include_directories(${LLVM_INCLUDE_DIRS}) add_definitions(${LLVM_DEFINITIONS}) diff --git a/core/iwasm/common/wasm_c_api.c b/core/iwasm/common/wasm_c_api.c index 4e883153f..cc5473a1c 100644 --- a/core/iwasm/common/wasm_c_api.c +++ b/core/iwasm/common/wasm_c_api.c @@ -1203,7 +1203,7 @@ wasm_trap_new_internal(const char *string) goto failed; } - wasm_name_new_from_string_nt(trap->message, string); + wasm_name_new_from_string(trap->message, string); if (strlen(string) && !trap->message->data) { goto failed; } @@ -1409,12 +1409,12 @@ wasm_module_imports(const wasm_module_t *module, continue; } - wasm_name_new_from_string_nt(&module_name, module_name_rt); + wasm_name_new_from_string(&module_name, module_name_rt); if (strlen(module_name_rt) && !module_name.data) { goto failed; } - wasm_name_new_from_string_nt(&name, field_name_rt); + wasm_name_new_from_string(&name, field_name_rt); if (strlen(field_name_rt) && !name.data) { goto failed; } @@ -1494,12 +1494,12 @@ wasm_module_imports(const wasm_module_t *module, continue; } - wasm_name_new_from_string_nt(&module_name, module_name_rt); + wasm_name_new_from_string(&module_name, module_name_rt); if (strlen(module_name_rt) && !module_name.data) { goto failed; } - wasm_name_new_from_string_nt(&name, field_name_rt); + wasm_name_new_from_string(&name, field_name_rt); if (strlen(field_name_rt) && !name.data) { goto failed; } @@ -1623,7 +1623,7 @@ wasm_module_exports(const wasm_module_t *module, wasm_exporttype_vec_t *out) } /* byte* -> wasm_byte_vec_t */ - wasm_name_new_from_string_nt(&name, export->name); + wasm_name_new_from_string(&name, export->name); if (strlen(export->name) && !name.data) { goto failed; } @@ -3221,6 +3221,11 @@ aot_link_func(const wasm_instance_t *inst, return false; } + if (!bh_vector_append((Vector *)inst->imports, &cloned)) { + wasm_func_delete(cloned); + return false; + } + import_aot_func->call_conv_raw = true; import_aot_func->attachment = cloned; import_aot_func->func_ptr_linked = native_func_trampoline; @@ -3243,7 +3248,7 @@ aot_link_global(const AOTModule *module_aot, bh_assert(import_aot_global); //TODO: import->type ? - val_type = wasm_globaltype_content(wasm_global_type(import)); + val_type = wasm_globaltype_content(import->type); bh_assert(val_type); switch (wasm_valtype_kind(val_type)) { diff --git a/samples/wasm-c-api/CMakeLists.txt b/samples/wasm-c-api/CMakeLists.txt index 144bfa89c..7e0e38d21 100644 --- a/samples/wasm-c-api/CMakeLists.txt +++ b/samples/wasm-c-api/CMakeLists.txt @@ -130,10 +130,10 @@ if (CMAKE_BUILD_TYPE STREQUAL "Debug") if(VALGRIND) foreach(EX ${EXAMPLES}) add_custom_target(${EX}_LEAK_TEST - COMMAND ${VALGRIND} --tool=memcheck --leak-check=yes --show-reachable=yes ./${EX} + COMMAND ${VALGRIND} --tool=memcheck --leak-check=yes ./${EX} DEPENDS ${EX} ${EX}_WASM VERBATIM - SOURCES ${EX} + COMMENT "run a leak check on ${EX}" ) endforeach() endif (VALGRIND) From 64b5459066797cd867f0280d3c56d8083b0cc7bc Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Tue, 11 May 2021 16:48:49 +0800 Subject: [PATCH 190/207] Implement Windows thread/mutex/cond APIs to support multi-thread (#627) Implement Windows thread/mutex/cond related APIs to support Windows multi-thread feature Change Windows HW boundary check implementation for multi-thread: change SEH to VEH Fix wasm-c-api issue of getting AOTFunctionInstance by index, fix wasm-c-api compile warnings Enable to build invokeNative_general.c with cmake variable Fix several issues in lib-pthread Disable two LLVM passes in multi-thread mode to reserve volatile semantic Update docker script and document to build iwasm with Docker image Signed-off-by: Wenyong Huang --- .gitignore | 5 +- Dockerfile | 21 - ci/Dockerfile | 18 + ci/build_wamr.sh | 24 + core/iwasm/aot/aot_loader.c | 4 +- core/iwasm/aot/aot_runtime.c | 86 +-- core/iwasm/aot/aot_runtime.h | 8 - core/iwasm/aot/arch/aot_reloc_x86_64.c | 2 +- core/iwasm/common/iwasm_common.cmake | 20 +- core/iwasm/common/wasm_c_api.c | 552 +++++++++++------ core/iwasm/common/wasm_exec_env.c | 9 - core/iwasm/common/wasm_memory.c | 230 -------- core/iwasm/compilation/aot_llvm.c | 8 +- .../lib-pthread/lib_pthread_wrapper.c | 46 +- .../libraries/thread-mgr/thread_manager.c | 12 +- .../platform/common/posix/posix_thread.c | 38 +- core/shared/platform/windows/platform_init.c | 9 +- .../platform/windows/platform_internal.h | 11 +- core/shared/platform/windows/win_thread.c | 553 ++++++++++++++---- doc/build_wamr.md | 15 +- product-mini/platforms/windows/main.c | 4 +- 21 files changed, 1022 insertions(+), 653 deletions(-) delete mode 100644 Dockerfile create mode 100644 ci/Dockerfile create mode 100755 ci/build_wamr.sh diff --git a/.gitignore b/.gitignore index 4e8eec854..f04648247 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ + .vs .vscode **/*build/ @@ -8,4 +9,6 @@ core/app-framework/wgl wamr-sdk/out/ wamr-sdk/runtime/build_runtime_sdk/ test-tools/host-tool/bin/ -product-mini/app-samples/hello-world/test.wasm \ No newline at end of file +product-mini/app-samples/hello-world/test.wasm + +build_out diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 993f11a28..000000000 --- a/Dockerfile +++ /dev/null @@ -1,21 +0,0 @@ -# Currently supports clang-8 compiler -# Using the "test.c" app from the README.md: -# clang-8 --target=wasm32 -O3 -Wl,--initial-memory=131072,--allow-undefined,--export=main,--no-threads,--strip-all,--no-entry -nostdlib -o test.wasm test.c -# Pay attention to spacing above! ^ -# iwasm test.wasm - -FROM ubuntu:latest - -RUN apt-get update && \ - apt-get -y upgrade && \ - apt-get install -y build-essential clang-8 cmake g++-multilib git lib32gcc-5-dev llvm-8 lld-8 nano - -WORKDIR /root - -RUN git clone https://github.com/intel/wasm-micro-runtime - -RUN cd wasm-micro-runtime/product-mini/platforms/linux/ && mkdir build && \ - cd build && cmake .. && make - -RUN cd /usr/bin && ln -s wasm-ld-8 wasm-ld -RUN cd /usr/bin && ln -s ~/wasm-micro-runtime/product-mini/platforms/linux/build/iwasm iwasm diff --git a/ci/Dockerfile b/ci/Dockerfile new file mode 100644 index 000000000..7c3bed58a --- /dev/null +++ b/ci/Dockerfile @@ -0,0 +1,18 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +FROM ubuntu:18.04 + +RUN apt update \ + && apt install -y apt-transport-https ca-certificates gnupg \ + software-properties-common wget lsb-release curl build-essential + +# +# CMAKE (https://apt.kitware.com/) +RUN wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | tee /etc/apt/trusted.gpg.d/kitware.gpg >/dev/null \ + && apt purge --auto-remove cmake \ + && apt-add-repository 'deb https://apt.kitware.com/ubuntu/ bionic main' \ + && apt update \ + && apt-get install -y kitware-archive-keyring \ + && rm /etc/apt/trusted.gpg.d/kitware.gpg \ + && apt-get install -y cmake diff --git a/ci/build_wamr.sh b/ci/build_wamr.sh new file mode 100755 index 000000000..9d02aba84 --- /dev/null +++ b/ci/build_wamr.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +docker build -t wamr_dev:0.1 -f Dockerfile . \ + && docker run --rm -it \ + --name wamr_building \ + --mount type=bind,src=$(realpath .)/..,dst=/source \ + --workdir /source \ + wamr_dev:0.1 \ + /bin/bash -c "\ + pushd product-mini/platforms/linux \ + && mkdir -p build \ + && pushd build \ + && rm -rf * \ + && cmake .. \ + && make \ + && popd \ + && popd \ + && echo 'Copying binary for image build' \ + && mkdir -p build_out \ + && rm build_out/* \ + && cp -f product-mini/platforms/linux/build/iwasm build_out/iwasm" diff --git a/core/iwasm/aot/aot_loader.c b/core/iwasm/aot/aot_loader.c index eed71b68c..5f21d1ff4 100644 --- a/core/iwasm/aot/aot_loader.c +++ b/core/iwasm/aot/aot_loader.c @@ -1191,7 +1191,7 @@ load_function_section(const uint8 *buf, const uint8 *buf_end, unwind_info= (AOTUnwindInfo *)((uint8*)module->code + module->code_size - sizeof(AOTUnwindInfo)); unwind_info->Version = 1; - unwind_info->Flags = UNW_FLAG_EHANDLER; + unwind_info->Flags = UNW_FLAG_NHANDLER; *(uint32*)&unwind_info->UnwindCode[0] = unwind_code_offset; size = sizeof(RUNTIME_FUNCTION) * (uint64)module->func_count; @@ -1231,7 +1231,7 @@ load_function_section(const uint8 *buf, const uint8 *buf_end, #if defined(OS_ENABLE_HW_BOUND_CHECK) && defined(BH_PLATFORM_WINDOWS) rtl_func_table[i].BeginAddress = (DWORD)text_offset; if (i > 0) { - rtl_func_table[i].EndAddress = rtl_func_table[i - 1].BeginAddress; + rtl_func_table[i - 1].EndAddress = rtl_func_table[i].BeginAddress; } rtl_func_table[i].UnwindInfoAddress = (DWORD)unwind_info_offset; #endif diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index 970e4e926..ea0cd9f1d 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -1152,13 +1152,6 @@ static os_thread_local_attribute WASMExecEnv *aot_exec_env = NULL; #ifndef BH_PLATFORM_WINDOWS static void aot_signal_handler(void *sig_addr) -#else -EXCEPTION_DISPOSITION -aot_exception_handler(PEXCEPTION_RECORD ExceptionRecord, - ULONG64 EstablisherFrame, - PCONTEXT ContextRecord, - PDISPATCHER_CONTEXT DispatcherContext) -#endif { AOTModuleInstance *module_inst; AOTMemoryInstance *memory_inst; @@ -1168,18 +1161,11 @@ aot_exception_handler(PEXCEPTION_RECORD ExceptionRecord, uint8 *stack_min_addr; uint32 page_size; uint32 guard_page_count = STACK_OVERFLOW_CHECK_GUARD_PAGE_COUNT; -#ifdef BH_PLATFORM_WINDOWS - uint8 *sig_addr = (uint8*)ExceptionRecord->ExceptionInformation[1]; -#endif /* Check whether current thread is running aot function */ if (aot_exec_env && aot_exec_env->handle == os_self_thread() - && (jmpbuf_node = aot_exec_env->jmpbuf_stack_top) -#ifdef BH_PLATFORM_WINDOWS - && ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION -#endif - ) { + && (jmpbuf_node = aot_exec_env->jmpbuf_stack_top)) { /* Get mapped mem info of current instance */ module_inst = (AOTModuleInstance *)aot_exec_env->module_inst; /* Get the default memory instance */ @@ -1211,40 +1197,58 @@ aot_exception_handler(PEXCEPTION_RECORD ExceptionRecord, os_longjmp(jmpbuf_node->jmpbuf, 1); } } - -#ifdef BH_PLATFORM_WINDOWS - ContextRecord->Rip += 3; - return EXCEPTION_CONTINUE_SEARCH; - (void)EstablisherFrame; - (void)ContextRecord; - (void)DispatcherContext; -#endif } - -#ifdef BH_PLATFORM_WINDOWS +#else /* else of BH_PLATFORM_WINDOWS */ static LONG -stack_overflow_handler(EXCEPTION_POINTERS *exce_info) +aot_exception_handler(EXCEPTION_POINTERS *exce_info) { - AOTModuleInstance* module_inst; - WASMJmpBuf* jmpbuf_node; + PEXCEPTION_RECORD ExceptionRecord = exce_info->ExceptionRecord; + uint8 *sig_addr = (uint8*)ExceptionRecord->ExceptionInformation[1]; + AOTModuleInstance *module_inst; + AOTMemoryInstance *memory_inst; + WASMJmpBuf *jmpbuf_node; + uint8 *mapped_mem_start_addr = NULL; + uint8 *mapped_mem_end_addr = NULL; + uint32 page_size = os_getpagesize(); - /* Check whether it is stack overflow exception and - current thread is running aot function */ - if (exce_info->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW - && aot_exec_env + if (aot_exec_env && aot_exec_env->handle == os_self_thread() && (jmpbuf_node = aot_exec_env->jmpbuf_stack_top)) { - /* Set stack overflow exception and let the aot func continue - to run, when the aot func returns, the caller will check - whether the exception is thrown and return to runtime, and - the damaged stack will be recovered by _resetstkoflw(). */ module_inst = (AOTModuleInstance*)aot_exec_env->module_inst; - aot_set_exception_with_id(module_inst, EXCE_NATIVE_STACK_OVERFLOW); - return EXCEPTION_CONTINUE_EXECUTION; + if (ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) { + /* Get the default memory instance */ + memory_inst = aot_get_default_memory(module_inst); + if (memory_inst) { + mapped_mem_start_addr = (uint8*)memory_inst->memory_data.ptr; + mapped_mem_end_addr = (uint8*)memory_inst->memory_data.ptr + + 8 * (uint64)BH_GB; + if (mapped_mem_start_addr <= (uint8*)sig_addr + && (uint8*)sig_addr < mapped_mem_end_addr) { + /* The address which causes segmentation fault is inside + aot instance's guard regions. + Set exception and let the aot func continue to run, when + the aot func returns, the caller will check whether the + exception is thrown and return to runtime. */ + aot_set_exception_with_id(module_inst, + EXCE_OUT_OF_BOUNDS_MEMORY_ACCESS); + /* Skip current instruction */ + exce_info->ContextRecord->Rip++; + return EXCEPTION_CONTINUE_EXECUTION; + } + } + } + else if (ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW) { + /* Set stack overflow exception and let the aot func continue + to run, when the aot func returns, the caller will check + whether the exception is thrown and return to runtime, and + the damaged stack will be recovered by _resetstkoflw(). */ + aot_set_exception_with_id(module_inst, EXCE_NATIVE_STACK_OVERFLOW); + return EXCEPTION_CONTINUE_EXECUTION; + } } return EXCEPTION_CONTINUE_SEARCH; } -#endif +#endif /* end of BH_PLATFORM_WINDOWS */ bool aot_signal_init() @@ -1252,7 +1256,7 @@ aot_signal_init() #ifndef BH_PLATFORM_WINDOWS return os_signal_init(aot_signal_handler) == 0 ? true : false; #else - return AddVectoredExceptionHandler(1, stack_overflow_handler) + return AddVectoredExceptionHandler(1, aot_exception_handler) ? true : false; #endif } @@ -1263,7 +1267,7 @@ aot_signal_destroy() #ifndef BH_PLATFORM_WINDOWS os_signal_destroy(); #else - RemoveVectoredExceptionHandler(stack_overflow_handler); + RemoveVectoredExceptionHandler(aot_exception_handler); #endif } diff --git a/core/iwasm/aot/aot_runtime.h b/core/iwasm/aot/aot_runtime.h index a81224353..4d4dc7b1f 100644 --- a/core/iwasm/aot/aot_runtime.h +++ b/core/iwasm/aot/aot_runtime.h @@ -659,14 +659,6 @@ aot_signal_init(); void aot_signal_destroy(); - -#ifdef BH_PLATFORM_WINDOWS -EXCEPTION_DISPOSITION -aot_exception_handler(PEXCEPTION_RECORD ExceptionRecord, - ULONG64 EstablisherFrame, - PCONTEXT ContextRecord, - PDISPATCHER_CONTEXT DispatcherContext); -#endif #endif void diff --git a/core/iwasm/aot/arch/aot_reloc_x86_64.c b/core/iwasm/aot/arch/aot_reloc_x86_64.c index 6c61a60b4..a04b6a6ee 100644 --- a/core/iwasm/aot/arch/aot_reloc_x86_64.c +++ b/core/iwasm/aot/arch/aot_reloc_x86_64.c @@ -93,7 +93,7 @@ init_plt_table(uint8 *plt) /* mov exception_handler, rax */ *p++ = 0x48; *p++ = 0xB8; - *(uint64*)p = (uint64)(uintptr_t)aot_exception_handler; + *(uint64*)p = 0;/*(uint64)(uintptr_t)aot_exception_handler;*/ p += sizeof(uint64); /* jmp rax */ *p++ = 0xFF; diff --git a/core/iwasm/common/iwasm_common.cmake b/core/iwasm/common/iwasm_common.cmake index 608f840bb..99c8c7e9f 100644 --- a/core/iwasm/common/iwasm_common.cmake +++ b/core/iwasm/common/iwasm_common.cmake @@ -10,7 +10,17 @@ add_definitions(-DBH_FREE=wasm_runtime_free) file (GLOB c_source_all ${IWASM_COMMON_DIR}/*.c) -if (WAMR_BUILD_TARGET STREQUAL "X86_64" OR WAMR_BUILD_TARGET STREQUAL "AMD_64") +if (WAMR_BUILD_INVOKE_NATIVE_GENERAL EQUAL 1) + # Use invokeNative C version instead of asm code version + # if WAMR_BUILD_INVOKE_NATIVE_GENERAL is explicitly set. + # Note: + # the maximum number of native arguments is limited to 20, + # and there are possible issues when passing arguments to + # native function for some cpus, e.g. int64 and double arguments + # in arm and mips need to be 8-bytes aligned, and some arguments + # of x86_64 are passed by registers but not stack + set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_general.c) +elseif (WAMR_BUILD_TARGET STREQUAL "X86_64" OR WAMR_BUILD_TARGET STREQUAL "AMD_64") if (NOT WAMR_BUILD_SIMD EQUAL 1) if (WAMR_BUILD_PLATFORM STREQUAL "windows") set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_em64.asm) @@ -60,14 +70,6 @@ elseif (WAMR_BUILD_TARGET STREQUAL "RISCV32" OR WAMR_BUILD_TARGET STREQUAL "RISC set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_riscv32_ilp32d.s) elseif (WAMR_BUILD_TARGET STREQUAL "RISCV32_ILP32") set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_riscv32_ilp32.s) -elseif (WAMR_BUILD_TARGET STREQUAL "GENERAL") - # Use invokeNative_general.c instead of assembly code, - # but the maximum number of native arguments is limited to 20, - # and there are possible issues when passing arguments to - # native function for some cpus, e.g. int64 and double arguments - # in arm and mips need to be 8-bytes aligned, and some arguments - # of x86_64 are passed by registers but not stack - set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_general.c) else () message (FATAL_ERROR "Build target isn't set") endif () diff --git a/core/iwasm/common/wasm_c_api.c b/core/iwasm/common/wasm_c_api.c index cc5473a1c..50b1ef678 100644 --- a/core/iwasm/common/wasm_c_api.c +++ b/core/iwasm/common/wasm_c_api.c @@ -116,7 +116,9 @@ failed: \ void wasm_##name##_vec_new(own wasm_##name##_vec_t *out, size_t size, \ own wasm_##name##_t const data[]) \ { \ - bh_assert(out); \ + if (!out) { \ + return; \ + } \ \ memset(out, 0, sizeof(wasm_##name##_vec_t)); \ \ @@ -156,7 +158,9 @@ failed: \ void wasm_##name##_vec_new(own wasm_##name##_vec_t *out, size_t size, \ own wasm_##name##_t *const data[]) \ { \ - bh_assert(out); \ + if (!out) { \ + return; \ + } \ \ memset(out, 0, sizeof(wasm_##name##_vec_t)); \ \ @@ -229,6 +233,28 @@ WASM_DEFINE_VEC_OWN(module, wasm_module_delete_internal) WASM_DEFINE_VEC_OWN(instance, wasm_instance_delete_internal) WASM_DEFINE_VEC_OWN(extern, wasm_extern_delete) +static inline bool +valid_module_type(uint32 module_type) +{ + bool result = false; + +#if WASM_ENABLE_INTERP != 0 + result = result || (module_type == Wasm_Module_Bytecode); +#endif + +#if WASM_ENABLE_AOT != 0 + result = result || (module_type == Wasm_Module_AoT); +#endif + + if (!result) { + LOG_VERBOSE( + "current building isn't compatiable with the module, may need " + "recompile"); + } + + return result; +} + /* Runtime Environment */ static void wasm_engine_delete_internal(wasm_engine_t *engine) @@ -250,10 +276,18 @@ wasm_engine_new_internal(mem_alloc_type_t type, const MemAllocOption *opts) init_args.mem_alloc_type = type; if (type == Alloc_With_Pool) { + if (!opts) { + return NULL; + } + init_args.mem_alloc_option.pool.heap_buf = opts->pool.heap_buf; init_args.mem_alloc_option.pool.heap_size = opts->pool.heap_size; } else if (type == Alloc_With_Allocator) { + if (!opts) { + return NULL; + } + init_args.mem_alloc_option.allocator.malloc_func = opts->allocator.malloc_func; init_args.mem_alloc_option.allocator.free_func = @@ -291,18 +325,6 @@ wasm_engine_new_internal(mem_alloc_type_t type, const MemAllocOption *opts) /* global engine instance */ static wasm_engine_t *singleton_engine = NULL; -static inline bool -run_with_bytecode_module(const wasm_module_t *module) -{ - return Wasm_Module_Bytecode == (*module)->module_type; -} - -static inline bool -run_with_bytecode_module_inst(const WASMModuleInstanceCommon *inst_comm_rt) -{ - return Wasm_Module_Bytecode == inst_comm_rt->module_type; -} - wasm_engine_t * wasm_engine_new() { @@ -314,8 +336,7 @@ wasm_engine_new() } wasm_engine_t * -wasm_engine_new_with_args(mem_alloc_type_t type, - const MemAllocOption *opts) +wasm_engine_new_with_args(mem_alloc_type_t type, const MemAllocOption *opts) { if (!singleton_engine) { singleton_engine = wasm_engine_new_internal(type, opts); @@ -338,7 +359,9 @@ wasm_store_new(wasm_engine_t *engine) { wasm_store_t *store = NULL; - bh_assert(engine && singleton_engine == engine); + if (!engine || singleton_engine != engine) { + return NULL; + } if (!(store = malloc_internal(sizeof(wasm_store_t)))) { return NULL; @@ -391,13 +414,6 @@ wasm_store_delete(wasm_store_t *store) wasm_runtime_free(store); } -static inline void -check_engine_and_store(wasm_engine_t *engine, wasm_store_t *store) -{ - /* remove it if we are supporting more than one store */ - bh_assert(engine && store); -} - /* Type Representations */ static wasm_valkind_t val_type_rt_2_valkind(uint8 val_type_rt) @@ -451,14 +467,20 @@ wasm_valtype_delete(wasm_valtype_t *val_type) wasm_valtype_t * wasm_valtype_copy(const wasm_valtype_t *src) { - bh_assert(src); + if (!src) { + return NULL; + } + return wasm_valtype_new(src->kind); } wasm_valkind_t wasm_valtype_kind(const wasm_valtype_t *val_type) { - bh_assert(val_type); + if (!val_type) { + return WASM_ANYREF; + } + return val_type->kind; } @@ -483,7 +505,9 @@ wasm_functype_new_internal(WASMType *type_rt) wasm_valtype_t *param_type = NULL, *result_type = NULL; uint32 i = 0; - bh_assert(type_rt); + if (!type_rt) { + return NULL; + } if (!(type = malloc_internal(sizeof(wasm_functype_t)))) { return NULL; @@ -535,8 +559,13 @@ wasm_functype_new(own wasm_valtype_vec_t *params, { wasm_functype_t *type = NULL; - bh_assert(params); - bh_assert(results); + if (!params) { + return NULL; + } + + if (!results) { + return NULL; + } if (!(type = malloc_internal(sizeof(wasm_functype_t)))) { goto failed; @@ -570,7 +599,9 @@ wasm_functype_copy(const wasm_functype_t *src) wasm_functype_t *functype; wasm_valtype_vec_t params = { 0 }, results = { 0 }; - bh_assert(src); + if (!src) { + return NULL; + } wasm_valtype_vec_copy(¶ms, src->params); if (src->params->size && !params.data) { @@ -610,14 +641,20 @@ wasm_functype_delete(wasm_functype_t *func_type) const wasm_valtype_vec_t * wasm_functype_params(const wasm_functype_t *func_type) { - bh_assert(func_type); + if (!func_type) { + return NULL; + } + return func_type->params; } const wasm_valtype_vec_t * wasm_functype_results(const wasm_functype_t *func_type) { - bh_assert(func_type); + if (!func_type) { + return NULL; + } + return func_type->results; } @@ -626,7 +663,9 @@ wasm_globaltype_new(own wasm_valtype_t *val_type, wasm_mutability_t mut) { wasm_globaltype_t *global_type = NULL; - bh_assert(val_type); + if (!val_type) { + return NULL; + } if (!(global_type = malloc_internal(sizeof(wasm_globaltype_t)))) { return NULL; @@ -678,7 +717,9 @@ wasm_globaltype_copy(const wasm_globaltype_t *src) wasm_globaltype_t *global_type; wasm_valtype_t *val_type; - bh_assert(src); + if (!src) { + return NULL; + } if (!(val_type = wasm_valtype_copy(src->val_type))) { return NULL; @@ -694,14 +735,20 @@ wasm_globaltype_copy(const wasm_globaltype_t *src) const wasm_valtype_t * wasm_globaltype_content(const wasm_globaltype_t *global_type) { - bh_assert(global_type); + if (!global_type) { + return NULL; + } + return global_type->val_type; } wasm_mutability_t wasm_globaltype_mutability(const wasm_globaltype_t *global_type) { - bh_assert(global_type); + if (!global_type) { + return false; + } + return global_type->mutability; } @@ -746,7 +793,9 @@ wasm_tabletype_new(own wasm_valtype_t *val_type, const wasm_limits_t *limits) { wasm_tabletype_t *table_type = NULL; - bh_assert(val_type); + if (!val_type) { + return NULL; + } if (!(table_type = malloc_internal(sizeof(wasm_tabletype_t)))) { return NULL; @@ -766,7 +815,9 @@ wasm_tabletype_copy(const wasm_tabletype_t *src) wasm_tabletype_t *table_type; wasm_valtype_t *val_type; - bh_assert(src); + if (!src) { + return NULL; + } if (!(val_type = wasm_valtype_copy(src->val_type))) { return NULL; @@ -797,14 +848,20 @@ wasm_tabletype_delete(wasm_tabletype_t *table_type) const wasm_valtype_t * wasm_tabletype_element(const wasm_tabletype_t *table_type) { - bh_assert(table_type); + if (!table_type) { + return NULL; + } + return table_type->val_type; } const wasm_limits_t * wasm_tabletype_limits(const wasm_tabletype_t *table_type) { - bh_assert(table_type); + if (!table_type) { + return NULL; + } + return &(table_type->limits); } @@ -819,7 +876,10 @@ wasm_memorytype_t * wasm_memorytype_new(const wasm_limits_t *limits) { wasm_memorytype_t *memory_type = NULL; - bh_assert(limits); + + if (!limits) { + return NULL; + } if (!(memory_type = malloc_internal(sizeof(wasm_memorytype_t)))) { return NULL; @@ -835,7 +895,10 @@ wasm_memorytype_new(const wasm_limits_t *limits) wasm_memorytype_t * wasm_memorytype_copy(const wasm_memorytype_t *src) { - bh_assert(src); + if (!src) { + return NULL; + } + return wasm_memorytype_new(&src->limits); } @@ -848,14 +911,20 @@ wasm_memorytype_delete(wasm_memorytype_t *memory_type) const wasm_limits_t * wasm_memorytype_limits(const wasm_memorytype_t *memory_type) { - bh_assert(memory_type); + if (!memory_type) { + return NULL; + } + return &(memory_type->limits); } wasm_externkind_t wasm_externtype_kind(const wasm_externtype_t *extern_type) { - bh_assert(extern_type); + if (!extern_type) { + return WASM_EXTERN_FUNC; + } + return extern_type->extern_kind; } @@ -909,7 +978,9 @@ wasm_externtype_copy(const wasm_externtype_t *src) { wasm_externtype_t *extern_type = NULL; - bh_assert(src); + if (!src) { + return NULL; + } switch (src->extern_kind) { #define COPY_EXTERNTYPE(NAME, name) \ @@ -960,8 +1031,8 @@ wasm_externtype_delete(wasm_externtype_t *extern_type) } own wasm_importtype_t * -wasm_importtype_new(own wasm_byte_vec_t *module, - own wasm_byte_vec_t *name, +wasm_importtype_new(own wasm_byte_vec_t *module_name, + own wasm_byte_vec_t *field_name, own wasm_externtype_t *extern_type) { wasm_importtype_t *import_type = NULL; @@ -975,13 +1046,13 @@ wasm_importtype_new(own wasm_byte_vec_t *module, malloc_internal(sizeof(wasm_byte_vec_t)))) { goto failed; } - bh_memcpy_s(import_type->module_name, sizeof(wasm_byte_vec_t), module, + bh_memcpy_s(import_type->module_name, sizeof(wasm_byte_vec_t), module_name, sizeof(wasm_byte_vec_t)); if (!(import_type->name = malloc_internal(sizeof(wasm_byte_vec_t)))) { goto failed; } - bh_memcpy_s(import_type->name, sizeof(wasm_byte_vec_t), name, + bh_memcpy_s(import_type->name, sizeof(wasm_byte_vec_t), field_name, sizeof(wasm_byte_vec_t)); import_type->extern_type = extern_type; @@ -1012,7 +1083,9 @@ wasm_importtype_copy(const wasm_importtype_t *src) wasm_externtype_t *extern_type = NULL; wasm_importtype_t *import_type = NULL; - bh_assert(src); + if (!src) { + return NULL; + } wasm_byte_vec_copy(&module_name, src->module_name); if (src->module_name->size && !module_name.data) { @@ -1046,21 +1119,30 @@ failed: const wasm_byte_vec_t * wasm_importtype_module(const wasm_importtype_t *import_type) { - bh_assert(import_type); + if (!import_type) { + return NULL; + } + return import_type->module_name; } const wasm_byte_vec_t * wasm_importtype_name(const wasm_importtype_t *import_type) { - bh_assert(import_type); + if (!import_type) { + return NULL; + } + return import_type->name; } const wasm_externtype_t * wasm_importtype_type(const wasm_importtype_t *import_type) { - bh_assert(import_type); + if (!import_type) { + return NULL; + } + return import_type->extern_type; } @@ -1093,7 +1175,9 @@ wasm_exporttype_copy(const wasm_exporttype_t *src) wasm_byte_vec_t name = { 0 }; wasm_externtype_t *extern_type = NULL; - bh_assert(src); + if (!src) { + return NULL; + } wasm_byte_vec_copy(&name, src->name); if (src->name->size && !name.data) { @@ -1132,14 +1216,18 @@ wasm_exporttype_delete(wasm_exporttype_t *export_type) const wasm_byte_vec_t * wasm_exporttype_name(const wasm_exporttype_t *export_type) { - bh_assert(export_type); + if (!export_type) { + return NULL; + } return export_type->name; } const wasm_externtype_t * wasm_exporttype_type(const wasm_exporttype_t *export_type) { - bh_assert(export_type); + if (!export_type) { + return NULL; + } return export_type->extern_type; } @@ -1154,7 +1242,10 @@ wasm_val_delete(wasm_val_t *v) void wasm_val_copy(wasm_val_t *out, const wasm_val_t *src) { - bh_assert(out && src); + if (!out || !src) { + return; + } + bh_memcpy_s(out, sizeof(wasm_val_t), src, sizeof(wasm_val_t)); } @@ -1219,7 +1310,9 @@ wasm_trap_new(wasm_store_t *store, const wasm_message_t *message) { wasm_trap_t *trap; - bh_assert(store && message); + if (!store || !message) { + return NULL; + } if (!(trap = malloc_internal(sizeof(wasm_trap_t)))) { return NULL; @@ -1248,7 +1341,10 @@ wasm_trap_delete(wasm_trap_t *trap) void wasm_trap_message(const wasm_trap_t *trap, own wasm_message_t *out) { - bh_assert(trap && out); + if (!trap || !out) { + return; + } + wasm_byte_vec_copy(out, trap->message); } @@ -1283,10 +1379,9 @@ wasm_module_new(wasm_store_t *store, const wasm_byte_vec_t *binary) char error[128] = { 0 }; wasm_module_ex_t *module_ex = NULL; - check_engine_and_store(singleton_engine, store); - bh_assert(binary && binary->data && binary->size); + bh_assert(singleton_engine); - if (binary->size > UINT32_MAX) { + if (!store || !binary || binary->size > UINT32_MAX) { LOG_ERROR("%s failed", __FUNCTION__); return NULL; } @@ -1348,30 +1443,34 @@ void wasm_module_imports(const wasm_module_t *module, own wasm_importtype_vec_t *out) { - uint32 i, import_func_count, import_memory_count, import_global_count, - import_table_count, import_count; + uint32 i, import_func_count = 0, import_memory_count = 0, + import_global_count = 0, import_table_count = 0, + import_count = 0; wasm_byte_vec_t module_name = { 0 }, name = { 0 }; wasm_externtype_t *extern_type = NULL; wasm_importtype_t *import_type = NULL; - bh_assert(out); + if (!module || !out || !valid_module_type((*module)->module_type)) { + return; + } - if (run_with_bytecode_module(module)) { #if WASM_ENABLE_INTERP != 0 + if ((*module)->module_type == Wasm_Module_Bytecode) { import_func_count = MODULE_INTERP(module)->import_function_count; import_global_count = MODULE_INTERP(module)->import_global_count; import_memory_count = MODULE_INTERP(module)->import_memory_count; import_table_count = MODULE_INTERP(module)->import_table_count; -#endif } - else { +#endif + #if WASM_ENABLE_AOT != 0 + if ((*module)->module_type == Wasm_Module_AoT) { import_func_count = MODULE_AOT(module)->import_func_count; import_global_count = MODULE_AOT(module)->import_global_count; import_memory_count = MODULE_AOT(module)->import_memory_count; import_table_count = MODULE_AOT(module)->import_table_count; -#endif } +#endif import_count = import_func_count + import_global_count + import_table_count + import_memory_count; @@ -1381,29 +1480,30 @@ wasm_module_imports(const wasm_module_t *module, } for (i = 0; i != import_count; ++i) { - char *module_name_rt, *field_name_rt; + char *module_name_rt = NULL, *field_name_rt = NULL; if (i < import_func_count) { wasm_functype_t *type = NULL; - WASMType *type_rt; + WASMType *type_rt = NULL; - if (run_with_bytecode_module(module)) { #if WASM_ENABLE_INTERP != 0 + if ((*module)->module_type == Wasm_Module_Bytecode) { WASMImport *import = MODULE_INTERP(module)->import_functions + i; module_name_rt = import->u.names.module_name; field_name_rt = import->u.names.field_name; type_rt = import->u.function.func_type; -#endif } - else { +#endif + #if WASM_ENABLE_AOT != 0 + if ((*module)->module_type == Wasm_Module_AoT) { AOTImportFunc *import = MODULE_AOT(module)->import_funcs + i; module_name_rt = import->module_name; field_name_rt = import->func_name; type_rt = import->func_type; -#endif } +#endif if (!module_name_rt || !field_name_rt || !type_rt) { continue; @@ -1430,26 +1530,27 @@ wasm_module_imports(const wasm_module_t *module, uint8 val_type_rt = 0; bool mutability_rt = 0; - if (run_with_bytecode_module(module)) { #if WASM_ENABLE_INTERP != 0 + if ((*module)->module_type == Wasm_Module_Bytecode) { WASMImport *import = MODULE_INTERP(module)->import_globals + (i - import_func_count); module_name_rt = import->u.names.module_name; field_name_rt = import->u.names.field_name; val_type_rt = import->u.global.type; mutability_rt = import->u.global.is_mutable; -#endif } - else { +#endif + #if WASM_ENABLE_AOT != 0 + if ((*module)->module_type == Wasm_Module_AoT) { AOTImportGlobal *import = MODULE_AOT(module)->import_globals + (i - import_func_count); module_name_rt = import->module_name; field_name_rt = import->global_name; val_type_rt = import->type; mutability_rt = import->is_mutable; -#endif } +#endif if (!module_name_rt || !field_name_rt) { continue; @@ -1467,8 +1568,8 @@ wasm_module_imports(const wasm_module_t *module, wasm_memorytype_t *type = NULL; uint32 min_page = 0, max_page = 0; - if (run_with_bytecode_module(module)) { #if WASM_ENABLE_INTERP != 0 + if ((*module)->module_type == Wasm_Module_Bytecode) { WASMImport *import = MODULE_INTERP(module)->import_memories + (i - import_func_count - import_global_count); @@ -1476,10 +1577,11 @@ wasm_module_imports(const wasm_module_t *module, field_name_rt = import->u.names.field_name; min_page = import->u.memory.init_page_count; max_page = import->u.memory.max_page_count; -#endif } - else { +#endif + #if WASM_ENABLE_AOT != 0 + if ((*module)->module_type == Wasm_Module_AoT) { AOTImportMemory *import = MODULE_AOT(module)->import_memories + (i - import_func_count - import_global_count); @@ -1487,8 +1589,8 @@ wasm_module_imports(const wasm_module_t *module, field_name_rt = import->memory_name; min_page = import->mem_init_page_count; max_page = import->mem_max_page_count; -#endif } +#endif if (!module_name_rt || !field_name_rt) { continue; @@ -1515,8 +1617,8 @@ wasm_module_imports(const wasm_module_t *module, uint8 elem_type_rt = 0; uint32 min_size = 0, max_size = 0; - if (run_with_bytecode_module(module)) { #if WASM_ENABLE_INTERP != 0 + if ((*module)->module_type == Wasm_Module_Bytecode) { WASMImport *import = MODULE_INTERP(module)->import_tables + (i - import_func_count - import_global_count @@ -1526,10 +1628,11 @@ wasm_module_imports(const wasm_module_t *module, elem_type_rt = import->u.table.elem_type; min_size = import->u.table.init_size; max_size = import->u.table.max_size; -#endif } - else { +#endif + #if WASM_ENABLE_AOT != 0 + if ((*module)->module_type == Wasm_Module_AoT) { AOTImportTable *import = MODULE_AOT(module)->import_tables + (i - import_func_count - import_global_count @@ -1539,8 +1642,8 @@ wasm_module_imports(const wasm_module_t *module, elem_type_rt = VALUE_TYPE_FUNCREF; min_size = import->table_init_size; max_size = import->table_max_size; -#endif } +#endif if (!module_name_rt || !field_name_rt) { continue; @@ -1582,23 +1685,26 @@ failed_importtype_new: void wasm_module_exports(const wasm_module_t *module, wasm_exporttype_vec_t *out) { - uint32 i, export_count; + uint32 i, export_count = 0; wasm_byte_vec_t name = { 0 }; wasm_externtype_t *extern_type = NULL; wasm_exporttype_t *export_type = NULL; - bh_assert(out); + if (!module || !out || !valid_module_type((*module)->module_type)) { + return; + } - if (run_with_bytecode_module(module)) { #if WASM_ENABLE_INTERP != 0 + if ((*module)->module_type == Wasm_Module_Bytecode) { export_count = MODULE_INTERP(module)->export_count; -#endif } - else { +#endif + #if WASM_ENABLE_AOT != 0 + if ((*module)->module_type == Wasm_Module_AoT) { export_count = MODULE_AOT(module)->export_count; -#endif } +#endif wasm_exporttype_vec_new_uninitialized(out, export_count); if (export_count && !out->data) { @@ -1607,16 +1713,16 @@ wasm_module_exports(const wasm_module_t *module, wasm_exporttype_vec_t *out) for (i = 0; i != export_count; i++) { WASMExport *export = NULL; - if (run_with_bytecode_module(module)) { #if WASM_ENABLE_INTERP != 0 + if ((*module)->module_type == Wasm_Module_Bytecode) { export = MODULE_INTERP(module)->exports + i; -#endif } - else { +#endif #if WASM_ENABLE_AOT != 0 + if ((*module)->module_type == Wasm_Module_AoT) { export = MODULE_AOT(module)->exports + i; -#endif } +#endif if (!export) { continue; @@ -1901,7 +2007,6 @@ wasm_func_new_basic(const wasm_functype_t *type, wasm_func_callback_t func_callback) { wasm_func_t *func = NULL; - bh_assert(type); if (!(func = malloc_internal(sizeof(wasm_func_t)))) { goto failed; @@ -1926,8 +2031,6 @@ wasm_func_new_with_env_basic(const wasm_functype_t *type, { wasm_func_t *func = NULL; - bh_assert(type); - if (!(func = malloc_internal(sizeof(wasm_func_t)))) { goto failed; } @@ -1950,7 +2053,7 @@ wasm_func_new(wasm_store_t *store, const wasm_functype_t *type, wasm_func_callback_t callback) { - check_engine_and_store(singleton_engine, store); + bh_assert(singleton_engine); return wasm_func_new_basic(type, callback); } @@ -1961,7 +2064,7 @@ wasm_func_new_with_env(wasm_store_t *store, void *env, void (*finalizer)(void *)) { - check_engine_and_store(singleton_engine, store); + bh_assert(singleton_engine); return wasm_func_new_with_env_basic(type, callback, env, finalizer); } @@ -1973,8 +2076,11 @@ wasm_func_new_internal(wasm_store_t *store, wasm_func_t *func = NULL; WASMType *type_rt = NULL; - check_engine_and_store(singleton_engine, store); - bh_assert(inst_comm_rt); + bh_assert(singleton_engine); + + if (!inst_comm_rt || !valid_module_type(inst_comm_rt->module_type)) { + return NULL; + } func = malloc_internal(sizeof(wasm_func_t)); if (!func) { @@ -1983,8 +2089,8 @@ wasm_func_new_internal(wasm_store_t *store, func->kind = WASM_EXTERN_FUNC; - if (run_with_bytecode_module_inst(inst_comm_rt)) { #if WASM_ENABLE_INTERP != 0 + if (inst_comm_rt->module_type == Wasm_Module_Bytecode) { bh_assert(func_idx_rt < ((WASMModuleInstance *)inst_comm_rt)->function_count); WASMFunctionInstance *func_interp = @@ -1992,10 +2098,11 @@ wasm_func_new_internal(wasm_store_t *store, type_rt = func_interp->is_import_func ? func_interp->u.func_import->func_type : func_interp->u.func->func_type; -#endif } - else { +#endif + #if WASM_ENABLE_AOT != 0 + if (inst_comm_rt->module_type == Wasm_Module_AoT) { /* use same index to trace the function type in AOTFuncType **func_types */ AOTModule *module_aot = ((AOTModuleInstance *)inst_comm_rt)->aot_module.ptr; @@ -2003,13 +2110,13 @@ wasm_func_new_internal(wasm_store_t *store, type_rt = (module_aot->import_funcs + func_idx_rt)->func_type; } else { - func_idx_rt -= module_aot->import_func_count; type_rt = module_aot - ->func_types[module_aot->func_type_indexes[func_idx_rt]]; + ->func_types[module_aot->func_type_indexes + [func_idx_rt - module_aot->import_func_count]]; } -#endif } +#endif if (!type_rt) { goto failed; @@ -2061,7 +2168,9 @@ wasm_func_copy(const wasm_func_t *func) { wasm_func_t *cloned = NULL; - bh_assert(func); + if (!func) { + return NULL; + } if (!(cloned = func->with_env ? wasm_func_new_with_env_basic( @@ -2080,7 +2189,9 @@ wasm_func_copy(const wasm_func_t *func) own wasm_functype_t * wasm_func_type(const wasm_func_t *func) { - bh_assert(func); + if (!func) { + return NULL; + } return wasm_functype_copy(func->type); } @@ -2218,25 +2329,41 @@ wasm_func_call(const wasm_func_t *func, WASMFunctionInstanceCommon *func_comm_rt = NULL; size_t param_count, result_count, alloc_count; - bh_assert(func && func->type && func->inst_comm_rt); - - /* TODO: how to check whether its store still exists */ + if (!func || !func->type || !func->inst_comm_rt + || !valid_module_type(func->inst_comm_rt->module_type)) { + return NULL; + } cur_trap = NULL; - if (run_with_bytecode_module_inst(func->inst_comm_rt)) { #if WASM_ENABLE_INTERP != 0 + if (func->inst_comm_rt->module_type == Wasm_Module_Bytecode) { func_comm_rt = ((WASMModuleInstance *)func->inst_comm_rt)->functions + func->func_idx_rt; -#endif } - else { +#endif + #if WASM_ENABLE_AOT != 0 + if (func->inst_comm_rt->module_type == Wasm_Module_AoT) { AOTModuleInstance *inst_aot = (AOTModuleInstance *)func->inst_comm_rt; - func_comm_rt = (AOTFunctionInstance *)inst_aot->export_funcs.ptr - + func->func_idx_rt; -#endif + AOTModule *module_aot = (AOTModule *)inst_aot->aot_module.ptr; + + uint32 export_i = 0, export_func_j = 0; + for (; export_i < module_aot->export_count; ++export_i) { + AOTExport *export = module_aot->exports + export_i; + if (export->kind == EXPORT_KIND_FUNC) { + if (export->index == func->func_idx_rt) { + func_comm_rt = + (AOTFunctionInstance *)inst_aot->export_funcs.ptr + + export_func_j; + break; + } + export_func_j++; + } + } } +#endif + if (!func_comm_rt) { goto failed; } @@ -2295,14 +2422,18 @@ failed: size_t wasm_func_param_arity(const wasm_func_t *func) { - bh_assert(func && func->type && func->type->params); + if (!func || !func->type || !func->type->params) { + return 0; + } return func->type->params->num_elems; } size_t wasm_func_result_arity(const wasm_func_t *func) { - bh_assert(func && func->type && func->type->results); + if (!func || !func->type || !func->type->results) { + return 0; + } return func->type->results->num_elems; } @@ -2313,8 +2444,7 @@ wasm_global_new(wasm_store_t *store, { wasm_global_t *global = NULL; - check_engine_and_store(singleton_engine, store); - bh_assert(store && global_type && init); + bh_assert(singleton_engine); global = malloc_internal(sizeof(wasm_global_t)); if (!global) { @@ -2349,7 +2479,9 @@ wasm_global_copy(const wasm_global_t *src) { wasm_global_t *global = NULL; - bh_assert(src); + if (!src) { + return NULL; + } global = malloc_internal(sizeof(wasm_global_t)); if (!global) { @@ -2605,41 +2737,47 @@ aot_global_get(const AOTModuleInstance *inst_aot, void wasm_global_set(wasm_global_t *global, const wasm_val_t *v) { - bh_assert(global && v); + if (!global || !v + || !valid_module_type(global->inst_comm_rt->module_type)) { + return; + } - if (run_with_bytecode_module_inst(global->inst_comm_rt)) { #if WASM_ENABLE_INTERP != 0 + if (global->inst_comm_rt->module_type == Wasm_Module_Bytecode) { (void)interp_global_set((WASMModuleInstance *)global->inst_comm_rt, global->global_idx_rt, v); -#endif } - else { +#endif #if WASM_ENABLE_AOT != 0 + if (global->inst_comm_rt->module_type == Wasm_Module_AoT) { (void)aot_global_set((AOTModuleInstance *)global->inst_comm_rt, global->global_idx_rt, v); -#endif } +#endif } void wasm_global_get(const wasm_global_t *global, wasm_val_t *out) { - bh_assert(global && out); + if (!global || !out + || !valid_module_type(global->inst_comm_rt->module_type)) { + return; + } memset(out, 0, sizeof(wasm_val_t)); - if (run_with_bytecode_module_inst(global->inst_comm_rt)) { #if WASM_ENABLE_INTERP != 0 + if (global->inst_comm_rt->module_type == Wasm_Module_Bytecode) { (void)interp_global_get((WASMModuleInstance *)global->inst_comm_rt, global->global_idx_rt, out); -#endif } - else { +#endif #if WASM_ENABLE_AOT != 0 + if (global->inst_comm_rt->module_type == Wasm_Module_AoT) { (void)aot_global_get((AOTModuleInstance *)global->inst_comm_rt, global->global_idx_rt, out); -#endif } +#endif bh_assert(global->init->kind == out->kind); } @@ -2653,8 +2791,11 @@ wasm_global_new_internal(wasm_store_t *store, uint8 val_type_rt = 0; bool is_mutable = 0; - check_engine_and_store(singleton_engine, store); - bh_assert(inst_comm_rt); + bh_assert(singleton_engine); + + if (!inst_comm_rt || !valid_module_type(inst_comm_rt->module_type)) { + return NULL; + } global = malloc_internal(sizeof(wasm_global_t)); if (!global) { @@ -2667,16 +2808,17 @@ wasm_global_new_internal(wasm_store_t *store, */ global->kind = WASM_EXTERN_GLOBAL; - if (run_with_bytecode_module_inst(inst_comm_rt)) { #if WASM_ENABLE_INTERP != 0 + if (inst_comm_rt->module_type == Wasm_Module_Bytecode) { WASMGlobalInstance *global_interp = ((WASMModuleInstance *)inst_comm_rt)->globals + global_idx_rt; val_type_rt = global_interp->type; is_mutable = global_interp->is_mutable; -#endif } - else { +#endif + #if WASM_ENABLE_AOT != 0 + if (inst_comm_rt->module_type == Wasm_Module_AoT) { AOTModuleInstance *inst_aot = (AOTModuleInstance *)inst_comm_rt; AOTModule *module_aot = inst_aot->aot_module.ptr; if (global_idx_rt < module_aot->import_global_count) { @@ -2692,8 +2834,8 @@ wasm_global_new_internal(wasm_store_t *store, val_type_rt = global_aot->type; is_mutable = global_aot->is_mutable; } -#endif } +#endif global->type = wasm_globaltype_new_internal(val_type_rt, is_mutable); if (!global->type) { @@ -2705,18 +2847,19 @@ wasm_global_new_internal(wasm_store_t *store, goto failed; } - if (run_with_bytecode_module_inst(inst_comm_rt)) { #if WASM_ENABLE_INTERP != 0 + if (inst_comm_rt->module_type == Wasm_Module_Bytecode) { interp_global_get((WASMModuleInstance *)inst_comm_rt, global_idx_rt, global->init); -#endif } - else { +#endif + #if WASM_ENABLE_AOT != 0 + if (inst_comm_rt->module_type == Wasm_Module_AoT) { aot_global_get((AOTModuleInstance *)inst_comm_rt, global_idx_rt, global->init); -#endif } +#endif global->inst_comm_rt = inst_comm_rt; global->global_idx_rt = global_idx_rt; @@ -2732,7 +2875,9 @@ failed: wasm_globaltype_t * wasm_global_type(const wasm_global_t *global) { - bh_assert(global); + if (!global) { + return NULL; + } return wasm_globaltype_copy(global->type); } @@ -2741,8 +2886,6 @@ wasm_table_new_basic(const wasm_tabletype_t *type) { wasm_table_t *table = NULL; - bh_assert(type); - if (!(table = malloc_internal(sizeof(wasm_table_t)))) { goto failed; } @@ -2765,8 +2908,11 @@ wasm_table_new_internal(wasm_store_t *store, uint8 val_type_rt = 0; uint32 init_size = 0, max_size = 0; - check_engine_and_store(singleton_engine, store); - bh_assert(inst_comm_rt); + bh_assert(singleton_engine); + + if (!inst_comm_rt || !valid_module_type(inst_comm_rt->module_type)) { + return NULL; + } if (!(table = malloc_internal(sizeof(wasm_table_t)))) { goto failed; @@ -2774,17 +2920,18 @@ wasm_table_new_internal(wasm_store_t *store, table->kind = WASM_EXTERN_TABLE; - if (run_with_bytecode_module_inst(inst_comm_rt)) { #if WASM_ENABLE_INTERP != 0 + if (inst_comm_rt->module_type == Wasm_Module_Bytecode) { WASMTableInstance *table_interp = ((WASMModuleInstance *)inst_comm_rt)->tables[table_idx_rt]; val_type_rt = table_interp->elem_type; init_size = table_interp->cur_size; max_size = table_interp->max_size; -#endif } - else { +#endif + #if WASM_ENABLE_AOT != 0 + if (inst_comm_rt->module_type == Wasm_Module_AoT) { AOTModuleInstance *inst_aot = (AOTModuleInstance *)inst_comm_rt; AOTModule *module_aot = (AOTModule *)inst_aot->aot_module.ptr; @@ -2803,8 +2950,8 @@ wasm_table_new_internal(wasm_store_t *store, init_size = table_aot->table_init_size; max_size = table_aot->table_max_size; } -#endif } +#endif if (!(table->type = wasm_tabletype_new_internal(val_type_rt, init_size, max_size))) { @@ -2823,7 +2970,7 @@ wasm_table_new(wasm_store_t *store, wasm_ref_t *init) { (void)init; - check_engine_and_store(singleton_engine, store); + bh_assert(singleton_engine); return wasm_table_new_basic(table_type); } @@ -2851,7 +2998,9 @@ wasm_table_delete(wasm_table_t *table) wasm_tabletype_t * wasm_table_type(const wasm_table_t *table) { - bh_assert(table); + if (!table) { + return NULL; + } return wasm_tabletype_copy(table->type); } @@ -2860,8 +3009,6 @@ wasm_memory_new_basic(const wasm_memorytype_t *type) { wasm_memory_t *memory = NULL; - bh_assert(type); - if (!(memory = malloc_internal(sizeof(wasm_memory_t)))) { goto failed; } @@ -2875,7 +3022,7 @@ wasm_memory_new_basic(const wasm_memorytype_t *type) wasm_memory_t * wasm_memory_new(wasm_store_t *store, const wasm_memorytype_t *type) { - check_engine_and_store(singleton_engine, store); + bh_assert(singleton_engine); return wasm_memory_new_basic(type); } @@ -2884,7 +3031,9 @@ wasm_memory_copy(const wasm_memory_t *src) { wasm_memory_t *dst = NULL; - bh_assert(src); + if (!src) { + return NULL; + } if (!(dst = wasm_memory_new_basic(src->type))) { goto failed; @@ -2904,8 +3053,11 @@ wasm_memory_new_internal(wasm_store_t *store, wasm_memory_t *memory = NULL; uint32 min_pages = 0, max_pages = 0; - check_engine_and_store(singleton_engine, store); - bh_assert(inst_comm_rt); + bh_assert(singleton_engine); + + if (!inst_comm_rt || !valid_module_type(inst_comm_rt->module_type)) { + return NULL; + } if (!(memory = malloc_internal(sizeof(wasm_memory_t)))) { goto failed; @@ -2913,16 +3065,17 @@ wasm_memory_new_internal(wasm_store_t *store, memory->kind = WASM_EXTERN_MEMORY; - if (run_with_bytecode_module_inst(inst_comm_rt)) { #if WASM_ENABLE_INTERP != 0 + if (inst_comm_rt->module_type == Wasm_Module_Bytecode) { WASMMemoryInstance *memory_interp = ((WASMModuleInstance *)inst_comm_rt)->memories[memory_idx_rt]; min_pages = memory_interp->cur_page_count; max_pages = memory_interp->max_page_count; -#endif } - else { +#endif + #if WASM_ENABLE_AOT != 0 + if (inst_comm_rt->module_type == Wasm_Module_AoT) { AOTModuleInstance *inst_aot = (AOTModuleInstance *)inst_comm_rt; AOTModule *module_aot = (AOTModule *)(inst_aot->aot_module.ptr); @@ -2934,8 +3087,8 @@ wasm_memory_new_internal(wasm_store_t *store, min_pages = module_aot->memories->mem_init_page_count; max_pages = module_aot->memories->mem_max_page_count; } -#endif } +#endif if (!(memory->type = wasm_memorytype_new_internal(min_pages, max_pages))) { goto failed; @@ -2965,7 +3118,10 @@ wasm_memory_delete(wasm_memory_t *memory) wasm_memorytype_t * wasm_memory_type(const wasm_memory_t *memory) { - bh_assert(memory); + if (!memory) { + return NULL; + } + return wasm_memorytype_copy(memory->type); } @@ -3405,6 +3561,15 @@ aot_process_export(wasm_store_t *store, goto failed; } + if (!(external->name = malloc_internal(sizeof(wasm_byte_vec_t)))) { + goto failed; + } + + wasm_name_new_from_string(external->name, export->name); + if (strlen(export->name) && !external->name->data) { + goto failed; + } + if (!bh_vector_append((Vector *)externals, &external)) { goto failed; } @@ -3432,7 +3597,11 @@ wasm_instance_new(wasm_store_t *store, uint32 i = 0; (void)traps; - check_engine_and_store(singleton_engine, store); + bh_assert(singleton_engine); + + if (!module || !valid_module_type((*module)->module_type)) { + return NULL; + } instance = malloc_internal(sizeof(wasm_instance_t)); if (!instance) { @@ -3441,8 +3610,8 @@ wasm_instance_new(wasm_store_t *store, /* link module and imports */ if (imports) { - if (run_with_bytecode_module(module)) { #if WASM_ENABLE_INTERP != 0 + if ((*module)->module_type == Wasm_Module_Bytecode) { import_count = MODULE_INTERP(module)->import_count; INIT_VEC(instance->imports, wasm_extern_vec_new_uninitialized, @@ -3457,10 +3626,11 @@ wasm_instance_new(wasm_store_t *store, goto failed; } } -#endif } - else { +#endif + #if WASM_ENABLE_AOT != 0 + if ((*module)->module_type == Wasm_Module_AoT) { import_count = MODULE_AOT(module)->import_func_count + MODULE_AOT(module)->import_global_count + MODULE_AOT(module)->import_memory_count @@ -3476,8 +3646,8 @@ wasm_instance_new(wasm_store_t *store, goto failed; } } -#endif } +#endif } instance->inst_comm_rt = wasm_runtime_instantiate( @@ -3513,8 +3683,8 @@ wasm_instance_new(wasm_store_t *store, } /* build the exports list */ - if (run_with_bytecode_module_inst(instance->inst_comm_rt)) { #if WASM_ENABLE_INTERP != 0 + if (instance->inst_comm_rt->module_type == Wasm_Module_Bytecode) { uint32 export_cnt = ((WASMModuleInstance *)instance->inst_comm_rt)->module->export_count; @@ -3526,10 +3696,11 @@ wasm_instance_new(wasm_store_t *store, instance->exports)) { goto failed; } -#endif } - else { +#endif + #if WASM_ENABLE_AOT != 0 + if (instance->inst_comm_rt->module_type == Wasm_Module_AoT) { uint32 export_cnt = ((AOTModuleInstance *)instance->inst_comm_rt)->export_func_count + ((AOTModuleInstance *)instance->inst_comm_rt)->export_global_count @@ -3544,8 +3715,8 @@ wasm_instance_new(wasm_store_t *store, instance->exports)) { goto failed; } -#endif } +#endif /* add it to a watching list in store */ if (!bh_vector_append((Vector *)store->instances, &instance)) { @@ -3587,7 +3758,9 @@ void wasm_instance_exports(const wasm_instance_t *instance, own wasm_extern_vec_t *out) { - bh_assert(instance && out); + if (!instance || !out) { + return; + } wasm_extern_vec_copy(out, instance->exports); } @@ -3595,7 +3768,10 @@ wasm_extern_t * wasm_extern_copy(const wasm_extern_t *src) { wasm_extern_t *dst = NULL; - bh_assert(src); + + if (!src) { + return NULL; + } switch (wasm_extern_kind(src)) { case WASM_EXTERN_FUNC: @@ -3639,6 +3815,12 @@ wasm_extern_delete(wasm_extern_t *external) return; } + if (external->name) { + wasm_byte_vec_delete(external->name); + wasm_runtime_free(external->name); + external->name = NULL; + } + switch (wasm_extern_kind(external)) { case WASM_EXTERN_FUNC: wasm_func_delete(wasm_extern_as_func(external)); @@ -3660,14 +3842,22 @@ wasm_extern_delete(wasm_extern_t *external) } wasm_externkind_t -wasm_extern_kind(const wasm_extern_t *extrenal) +wasm_extern_kind(const wasm_extern_t *external) { - return extrenal->kind; + if (!external) { + return WASM_ANYREF; + } + + return external->kind; } own wasm_externtype_t * wasm_extern_type(const wasm_extern_t *external) { + if (!external) { + return NULL; + } + switch (wasm_extern_kind(external)) { case WASM_EXTERN_FUNC: return wasm_functype_as_externtype( diff --git a/core/iwasm/common/wasm_exec_env.c b/core/iwasm/common/wasm_exec_env.c index 382efd7f8..d1c2cfe20 100644 --- a/core/iwasm/common/wasm_exec_env.c +++ b/core/iwasm/common/wasm_exec_env.c @@ -71,15 +71,6 @@ fail1: void wasm_exec_env_destroy_internal(WASMExecEnv *exec_env) { -#ifdef OS_ENABLE_HW_BOUND_CHECK - WASMJmpBuf *jmpbuf = exec_env->jmpbuf_stack_top; - WASMJmpBuf *jmpbuf_prev; - while (jmpbuf) { - jmpbuf_prev = jmpbuf->prev; - wasm_runtime_free(jmpbuf); - jmpbuf = jmpbuf_prev; - } -#endif #if WASM_ENABLE_THREAD_MGR != 0 os_mutex_destroy(&exec_env->wait_lock); os_cond_destroy(&exec_env->wait_cond); diff --git a/core/iwasm/common/wasm_memory.c b/core/iwasm/common/wasm_memory.c index 1d8faffbe..0b558cb51 100644 --- a/core/iwasm/common/wasm_memory.c +++ b/core/iwasm/common/wasm_memory.c @@ -7,33 +7,6 @@ #include "bh_platform.h" #include "mem_alloc.h" -#define BH_ENABLE_MEMORY_PROFILING 0 - -#if BH_ENABLE_MEMORY_PROFILING != 0 - -/* Memory profile data of a function */ -typedef struct memory_profile { - struct memory_profile *next; - const char *function_name; - const char *file_name; - int line_in_file; - int malloc_num; - int free_num; - int total_malloc; - int total_free; -} memory_profile_t; - -/* Memory in use which grows when BH_MALLOC was called - * and decreases when bh_free was called */ -static unsigned int memory_in_use = 0; - -/* Memory profile data list */ -static memory_profile_t *memory_profiles_list = NULL; - -/* Lock of the memory profile list */ -static korp_mutex profile_lock; -#endif /* end of BH_ENABLE_MEMORY_PROFILING */ - typedef enum Memory_Mode { MEMORY_MODE_UNKNOWN = 0, MEMORY_MODE_POOL, @@ -58,9 +31,6 @@ wasm_memory_init_with_pool(void *mem, unsigned int bytes) if (_allocator) { memory_mode = MEMORY_MODE_POOL; pool_allocator = _allocator; -#if BH_ENABLE_MEMORY_PROFILING != 0 - os_mutex_init(&profile_lock); -#endif global_pool_size = bytes; return true; } @@ -78,9 +48,6 @@ wasm_memory_init_with_allocator(void *_malloc_func, malloc_func = _malloc_func; realloc_func = _realloc_func; free_func = _free_func; -#if BH_ENABLE_MEMORY_PROFILING != 0 - os_mutex_init(&profile_lock); -#endif return true; } LOG_ERROR("Init memory with allocator (%p, %p, %p) failed.\n", @@ -108,9 +75,6 @@ wasm_runtime_memory_init(mem_alloc_type_t mem_alloc_type, void wasm_runtime_memory_destroy() { -#if BH_ENABLE_MEMORY_PROFILING != 0 - os_mutex_destroy(&profile_lock); -#endif if (memory_mode == MEMORY_MODE_POOL) mem_allocator_destroy(pool_allocator); memory_mode = MEMORY_MODE_UNKNOWN; @@ -201,197 +165,3 @@ wasm_runtime_free(void *ptr) { wasm_runtime_free_internal(ptr); } - -#if 0 -static uint64 total_malloc = 0; -static uint64 total_free = 0; - -void * -wasm_runtime_malloc(unsigned int size) -{ - void *ret = wasm_runtime_malloc_internal(size + 8); - - if (ret) { - total_malloc += size; - *(uint32 *)ret = size; - return (uint8 *)ret + 8; - } - else - return NULL; -} - -void * -wasm_runtime_realloc(void *ptr, unsigned int size) -{ - if (!ptr) - return wasm_runtime_malloc(size); - else { - uint8 *ptr_old = (uint8 *)ptr - 8; - uint32 size_old = *(uint32 *)ptr_old; - - ptr = wasm_runtime_realloc_internal(ptr_old, size + 8); - if (ptr) { - total_free += size_old; - total_malloc += size; - *(uint32 *)ptr = size; - return (uint8 *)ptr + 8; - } - return NULL; - } -} - -void -wasm_runtime_free(void *ptr) -{ - if (ptr) { - uint8 *ptr_old = (uint8 *)ptr - 8; - uint32 size_old = *(uint32 *)ptr_old; - - total_free += size_old; - wasm_runtime_free_internal(ptr_old); - } -} - -void dump_memory_usage() -{ - os_printf("Memory usage:\n"); - os_printf(" total malloc: %"PRIu64"\n", total_malloc); - os_printf(" total free: %"PRIu64"\n", total_free); -} -#endif - -#if BH_ENABLE_MEMORY_PROFILING != 0 -void -memory_profile_print(const char *file, int line, - const char *func, int alloc) -{ - os_printf("location:%s@%d:used:%d:contribution:%d\n", - func, line, memory_in_use, alloc); -} - -void * -wasm_runtime_malloc_profile(const char *file, int line, - const char *func, unsigned int size) -{ - void *p = wasm_runtime_malloc(size + 8); - - if (p) { - memory_profile_t *profile; - - os_mutex_lock(&profile_lock); - - profile = memory_profiles_list; - while (profile) { - if (strcmp(profile->function_name, func) == 0 - && strcmp(profile->file_name, file) == 0) { - break; - } - profile = profile->next; - } - - if (profile) { - profile->total_malloc += size;/* TODO: overflow check */ - profile->malloc_num++; - } else { - profile = wasm_runtime_malloc(sizeof(memory_profile_t)); - if (!profile) { - os_mutex_unlock(&profile_lock); - bh_memcpy_s(p, size + 8, &size, sizeof(size)); - return (char *)p + 8; - } - - memset(profile, 0, sizeof(memory_profile_t)); - profile->file_name = file; - profile->line_in_file = line; - profile->function_name = func; - profile->malloc_num = 1; - profile->total_malloc = size; - profile->next = memory_profiles_list; - memory_profiles_list = profile; - } - - os_mutex_unlock(&profile_lock); - - bh_memcpy_s(p, size + 8, &size, sizeof(size)); - memory_in_use += size; - - memory_profile_print(file, line, func, size); - - return (char *)p + 8; - } - - return NULL; -} - -void -wasm_runtime_free_profile(const char *file, int line, - const char *func, void *ptr) -{ - unsigned int size = *(unsigned int *)((char *)ptr - 8); - memory_profile_t *profile; - - wasm_runtime_free((char *)ptr - 8); - - if (memory_in_use >= size) - memory_in_use -= size; - - os_mutex_lock(&profile_lock); - - profile = memory_profiles_list; - while (profile) { - if (strcmp(profile->function_name, func) == 0 - && strcmp(profile->file_name, file) == 0) { - break; - } - profile = profile->next; - } - - if (profile) { - profile->total_free += size;/* TODO: overflow check */ - profile->free_num++; - } else { - profile = wasm_runtime_malloc(sizeof(memory_profile_t)); - if (!profile) { - os_mutex_unlock(&profile_lock); - return; - } - - memset(profile, 0, sizeof(memory_profile_t)); - profile->file_name = file; - profile->line_in_file = line; - profile->function_name = func; - profile->free_num = 1; - profile->total_free = size; - profile->next = memory_profiles_list; - memory_profiles_list = profile; - } - - os_mutex_unlock(&profile_lock); -} - -/** - * Summarize memory usage and print it out - * Can use awk to analyze the output like below: - * awk -F: '{print $2,$4,$6,$8,$9}' OFS="\t" ./out.txt | sort -n -r -k 1 - */ -void memory_usage_summarize() -{ - memory_profile_t *profile; - - os_mutex_lock(&profile_lock); - - profile = memory_profiles_list; - while (profile) { - os_printf("malloc:%d:malloc_num:%d:free:%d:free_num:%d:%s\n", - profile->total_malloc, - profile->malloc_num, - profile->total_free, - profile->free_num, - profile->function_name); - profile = profile->next; - } - - os_mutex_unlock(&profile_lock); -} -#endif /* end of BH_ENABLE_MEMORY_PROFILING */ - diff --git a/core/iwasm/compilation/aot_llvm.c b/core/iwasm/compilation/aot_llvm.c index 0784e87e9..d4d382a37 100644 --- a/core/iwasm/compilation/aot_llvm.c +++ b/core/iwasm/compilation/aot_llvm.c @@ -1542,8 +1542,12 @@ aot_create_comp_context(AOTCompData *comp_data, LLVMAddLoopUnswitchPass(comp_ctx->pass_mgr); LLVMAddInstructionCombiningPass(comp_ctx->pass_mgr); LLVMAddCFGSimplificationPass(comp_ctx->pass_mgr); - LLVMAddGVNPass(comp_ctx->pass_mgr); - LLVMAddLICMPass(comp_ctx->pass_mgr); + if (!option->enable_thread_mgr) { + /* These two passes may destroy the volatile semantics, + disable them when building as multi-thread mode */ + LLVMAddGVNPass(comp_ctx->pass_mgr); + LLVMAddLICMPass(comp_ctx->pass_mgr); + } LLVMAddLoopVectorizePass(comp_ctx->pass_mgr); LLVMAddSLPVectorizePass(comp_ctx->pass_mgr); LLVMAddInstructionCombiningPass(comp_ctx->pass_mgr); diff --git a/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c b/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c index 0dd1faa9a..2e80bf7f2 100644 --- a/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c +++ b/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c @@ -117,7 +117,7 @@ typedef struct { } ThreadRoutineArgs; static bh_list cluster_info_list; -static korp_mutex pthread_global_lock; +static korp_mutex thread_global_lock; static uint32 handle_id = 1; static void @@ -140,7 +140,7 @@ thread_info_destroy(void *node) { ThreadInfoNode *info_node = (ThreadInfoNode *)node; - pthread_mutex_lock(&pthread_global_lock); + os_mutex_lock(&thread_global_lock); if (info_node->type == T_MUTEX) { if (info_node->status != MUTEX_DESTROYED) os_mutex_destroy(info_node->u.mutex); @@ -152,18 +152,18 @@ thread_info_destroy(void *node) wasm_runtime_free(info_node->u.cond); } wasm_runtime_free(info_node); - pthread_mutex_unlock(&pthread_global_lock); + os_mutex_unlock(&thread_global_lock); } bool lib_pthread_init() { - if (0 != os_mutex_init(&pthread_global_lock)) + if (0 != os_mutex_init(&thread_global_lock)) return false; bh_list_init(&cluster_info_list); if (!wasm_cluster_register_destroy_callback( lib_pthread_destroy_callback)) { - os_mutex_destroy(&pthread_global_lock); + os_mutex_destroy(&thread_global_lock); return false; } return true; @@ -172,7 +172,7 @@ lib_pthread_init() void lib_pthread_destroy() { - os_mutex_destroy(&pthread_global_lock); + os_mutex_destroy(&thread_global_lock); } static ClusterInfoNode* @@ -180,17 +180,17 @@ get_cluster_info(WASMCluster *cluster) { ClusterInfoNode *node; - os_mutex_lock(&pthread_global_lock); + os_mutex_lock(&thread_global_lock); node = bh_list_first_elem(&cluster_info_list); while (node) { if (cluster == node->cluster) { - os_mutex_unlock(&pthread_global_lock); + os_mutex_unlock(&thread_global_lock); return node; } node = bh_list_elem_next(node); } - os_mutex_unlock(&pthread_global_lock); + os_mutex_unlock(&thread_global_lock); return NULL; } @@ -356,10 +356,10 @@ create_cluster_info(WASMCluster *cluster) wasm_runtime_free(node); return NULL; } - os_mutex_lock(&pthread_global_lock); + os_mutex_lock(&thread_global_lock); ret = bh_list_insert(&cluster_info_list, node); bh_assert(ret == BH_LIST_SUCCESS); - os_mutex_unlock(&pthread_global_lock); + os_mutex_unlock(&thread_global_lock); (void)ret; return node; @@ -375,10 +375,10 @@ destroy_cluster_info(WASMCluster *cluster) os_mutex_destroy(&node->key_data_list_lock); /* Remove from the cluster info list */ - os_mutex_lock(&pthread_global_lock); + os_mutex_lock(&thread_global_lock); bh_list_remove(&cluster_info_list, node); wasm_runtime_free(node); - os_mutex_unlock(&pthread_global_lock); + os_mutex_unlock(&thread_global_lock); return true; } return false; @@ -447,9 +447,9 @@ static uint32 allocate_handle() { uint32 id; - os_mutex_lock(&pthread_global_lock); + os_mutex_lock(&thread_global_lock); id = handle_id++; - os_mutex_unlock(&pthread_global_lock); + os_mutex_unlock(&thread_global_lock); return id; } @@ -504,8 +504,6 @@ pthread_start_routine(void *arg) /* routine exit, destroy instance */ wasm_runtime_deinstantiate_internal(module_inst, true); - info_node->status = THREAD_EXIT; - wasm_runtime_free(routine_args); /* if the thread is joinable, store the result in its info node, @@ -516,6 +514,14 @@ pthread_start_routine(void *arg) } else { info_node->u.ret = (void *)(uintptr_t)argv[0]; +#ifdef OS_ENABLE_HW_BOUND_CHECK + if (exec_env->suspend_flags.flags & 0x08) + /* argv[0] isn't set after longjmp(1) to + invoke_native_with_hw_bound_check */ + info_node->u.ret = exec_env->thread_ret_value; +#endif + /* Update node status after ret value was set */ + info_node->status = THREAD_EXIT; } return (void *)(uintptr_t)argv[0]; @@ -711,7 +717,7 @@ pthread_exit_wrapper(wasm_exec_env_t exec_env, int32 retval_offset) if (!args) return; -#ifdef OS_ENABLE_HW_BOUND_CHECK +#if defined(OS_ENABLE_HW_BOUND_CHECK) && !defined(BH_PLATFORM_WINDOWS) /* If hardware bound check enabled, don't deinstantiate module inst and thread info node here for AoT module, as they will be freed in pthread_start_routine */ @@ -726,13 +732,13 @@ pthread_exit_wrapper(wasm_exec_env_t exec_env, int32 retval_offset) /* routine exit, destroy instance */ wasm_runtime_deinstantiate_internal(module_inst, true); - args->info_node->status = THREAD_EXIT; - if (!args->info_node->joinable) { delete_thread_info_node(args->info_node); } else { args->info_node->u.ret = (void *)(uintptr_t)retval_offset; + /* Update node status after ret value was set */ + args->info_node->status = THREAD_EXIT; } wasm_runtime_free(args); diff --git a/core/iwasm/libraries/thread-mgr/thread_manager.c b/core/iwasm/libraries/thread-mgr/thread_manager.c index ea4edf826..c066f4aff 100644 --- a/core/iwasm/libraries/thread-mgr/thread_manager.c +++ b/core/iwasm/libraries/thread-mgr/thread_manager.c @@ -495,20 +495,18 @@ wasm_cluster_exit_thread(WASMExecEnv *exec_env, void *retval) #ifdef OS_ENABLE_HW_BOUND_CHECK if (exec_env->jmpbuf_stack_top) { - WASMJmpBuf *jmpbuf_node; - /* Store the return value in exec_env */ exec_env->thread_ret_value = retval; exec_env->suspend_flags.flags |= 0x08; - /* Free all jmpbuf_node except the last one */ +#ifndef BH_PLATFORM_WINDOWS + /* Pop all jmpbuf_node except the last one */ while (exec_env->jmpbuf_stack_top->prev) { - jmpbuf_node = wasm_exec_env_pop_jmpbuf(exec_env); - wasm_runtime_free(jmpbuf_node); + wasm_exec_env_pop_jmpbuf(exec_env); } - jmpbuf_node = exec_env->jmpbuf_stack_top; - os_longjmp(jmpbuf_node->jmpbuf, 1); + os_longjmp(exec_env->jmpbuf_stack_top->jmpbuf, 1); return; +#endif } #endif diff --git a/core/shared/platform/common/posix/posix_thread.c b/core/shared/platform/common/posix/posix_thread.c index 54b52c839..ab515f119 100644 --- a/core/shared/platform/common/posix/posix_thread.c +++ b/core/shared/platform/common/posix/posix_thread.c @@ -11,22 +11,30 @@ typedef struct { thread_start_routine_t start; - void* stack; - uint32 stack_size; void* arg; } thread_wrapper_arg; +#ifdef OS_ENABLE_HW_BOUND_CHECK +static int os_thread_signal_init(); +static void os_thread_signal_destroy(); +#endif + static void *os_thread_wrapper(void *arg) { - thread_wrapper_arg * targ = arg; + thread_wrapper_arg *targ = arg; thread_start_routine_t start_func = targ->start; void *thread_arg = targ->arg; - os_printf("THREAD CREATED %p\n", &targ); - targ->stack = (void *)((uintptr_t)(&arg) & (uintptr_t)~0xfff); + + os_printf("THREAD CREATED %p\n", pthread_self()); BH_FREE(targ); +#ifdef OS_ENABLE_HW_BOUND_CHECK + if (os_thread_signal_init() != 0) + return NULL; +#endif start_func(thread_arg); #ifdef OS_ENABLE_HW_BOUND_CHECK os_thread_destroy_stack_guard_pages(); + os_thread_signal_destroy(); #endif return NULL; } @@ -58,7 +66,6 @@ int os_thread_create_with_prio(korp_tid *tid, thread_start_routine_t start, targ->start = start; targ->arg = arg; - targ->stack_size = stack_size; if (pthread_create(tid, &tattr, os_thread_wrapper, targ) != 0) { pthread_attr_destroy(&tattr); @@ -244,6 +251,7 @@ void os_thread_exit(void *retval) { #ifdef OS_ENABLE_HW_BOUND_CHECK os_thread_destroy_stack_guard_pages(); + os_thread_signal_destroy(); #endif return pthread_exit(retval); } @@ -309,7 +317,7 @@ uint8 *os_thread_get_stack_boundary() static os_thread_local_attribute bool stack_guard_pages_inited = false; /* The signal alternate stack base addr */ -static uint8 *sigalt_stack_base_addr; +static os_thread_local_attribute uint8 *sigalt_stack_base_addr; /* The signal handler passed to os_signal_init() */ static os_signal_handler signal_handler; @@ -419,7 +427,7 @@ os_signal_init(os_signal_handler handler) uint32 map_size = SIG_ALT_STACK_SIZE; uint8 *map_addr; - /* Initialize memory for signal alternate stack */ + /* Initialize memory for signal alternate stack of current thread */ if (!(map_addr = os_mmap(NULL, map_size, MMAP_PROT_READ | MMAP_PROT_WRITE, MMAP_MAP_NONE))) { @@ -473,6 +481,20 @@ os_signal_destroy() os_munmap(sigalt_stack_base_addr, SIG_ALT_STACK_SIZE); } +static int +os_thread_signal_init() +{ + assert(signal_handler); + /* Use the global signal handler registered previously */ + return os_signal_init(signal_handler); +} + +static void +os_thread_signal_destroy() +{ + os_signal_destroy(); +} + void os_signal_unmask() { diff --git a/core/shared/platform/windows/platform_init.c b/core/shared/platform/windows/platform_init.c index a723214b8..bdb75f858 100644 --- a/core/shared/platform/windows/platform_init.c +++ b/core/shared/platform/windows/platform_init.c @@ -5,15 +5,22 @@ #include "platform_api_vmcore.h" +int +os_thread_sys_init(); + +void +os_thread_sys_destroy(); + int bh_platform_init() { - return 0; + return os_thread_sys_init(); } void bh_platform_destroy() { + os_thread_sys_destroy(); } int diff --git a/core/shared/platform/windows/platform_internal.h b/core/shared/platform/windows/platform_internal.h index 34da6fa39..055c19dc3 100644 --- a/core/shared/platform/windows/platform_internal.h +++ b/core/shared/platform/windows/platform_internal.h @@ -24,6 +24,7 @@ #include #include #include +#include #include #ifdef __cplusplus @@ -40,14 +41,16 @@ extern "C" { /* Default thread priority */ #define BH_THREAD_DEFAULT_PRIORITY 0 +typedef void *korp_thread; typedef void *korp_tid; typedef void *korp_mutex; typedef void *korp_sem; -typedef void *korp_thread; -typedef struct { - korp_sem s; - unsigned int waiting_count; +struct os_thread_wait_node; +typedef struct os_thread_wait_node *os_thread_wait_list; +typedef struct korp_cond { + korp_mutex wait_list_lock; + os_thread_wait_list thread_wait_list; } korp_cond; unsigned os_getpagesize(); diff --git a/core/shared/platform/windows/win_thread.c b/core/shared/platform/windows/win_thread.c index 0ce313f45..a4746019a 100644 --- a/core/shared/platform/windows/win_thread.c +++ b/core/shared/platform/windows/win_thread.c @@ -3,155 +3,499 @@ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception */ -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif #include "platform_api_vmcore.h" #include "platform_api_extension.h" -typedef struct { - thread_start_routine_t start; - void* stack; - uint32 stack_size; - void* arg; -} thread_wrapper_arg; +#define bh_assert(v) assert(v) -static void *os_thread_wrapper(void *arg) -{ - thread_wrapper_arg * targ = arg; - thread_start_routine_t start_func = targ->start; - void *thread_arg = targ->arg; - os_printf("THREAD CREATED %p\n", &targ); - targ->stack = (void *)((uintptr_t)(&arg) & (uintptr_t)~0xfff); - BH_FREE(targ); - start_func(thread_arg); - return NULL; -} +#define BH_SEM_COUNT_MAX 0xFFFF -int os_thread_create_with_prio(korp_tid *tid, thread_start_routine_t start, - void *arg, unsigned int stack_size, int prio) +struct os_thread_data; + +typedef struct os_thread_wait_node { + korp_sem sem; + void *retval; + os_thread_wait_list next; +} os_thread_wait_node; + +typedef struct os_thread_data { + /* Next thread data */ + struct os_thread_data *next; + /* Thread data of parent thread */ + struct os_thread_data *parent; + /* Thread Id */ + DWORD thread_id; + /* Thread start routine */ + thread_start_routine_t start_routine; + /* Thread start routine argument */ + void *arg; + /* Wait node of current thread */ + os_thread_wait_node wait_node; + /* Wait cond */ + korp_cond wait_cond; + /* Wait lock */ + korp_mutex wait_lock; + /* Waiting list of other threads who are joining this thread */ + os_thread_wait_list thread_wait_list; +} os_thread_data; + +static bool is_thread_sys_inited = false; + +/* Thread data of supervisor thread */ +static os_thread_data supervisor_thread_data; + +/* Thread data key */ +static DWORD thread_data_key; + +int os_sem_init(korp_sem* sem); +int os_sem_destroy(korp_sem* sem); +int os_sem_wait(korp_sem* sem); +int os_sem_reltimed_wait(korp_sem* sem, uint64 useconds); +int os_sem_signal(korp_sem* sem); + +int +os_thread_sys_init() { + if (is_thread_sys_inited) + return BHT_OK; + + if ((thread_data_key = TlsAlloc()) == TLS_OUT_OF_INDEXES) + return BHT_ERROR; + + /* Initialize supervisor thread data */ + memset(&supervisor_thread_data, 0, sizeof(os_thread_data)); + + supervisor_thread_data.thread_id = GetCurrentThreadId(); + + if (os_sem_init(&supervisor_thread_data.wait_node.sem) != BHT_OK) + goto fail1; + + if (os_mutex_init(&supervisor_thread_data.wait_lock) != BHT_OK) + goto fail2; + + if (os_cond_init(&supervisor_thread_data.wait_cond) != BHT_OK) + goto fail3; + + if (!TlsSetValue(thread_data_key, &supervisor_thread_data)) + goto fail4; + + is_thread_sys_inited = true; + return BHT_OK; + +fail4: + os_cond_destroy(&supervisor_thread_data.wait_cond); +fail3: + os_mutex_destroy(&supervisor_thread_data.wait_lock); +fail2: + os_sem_destroy(&supervisor_thread_data.wait_node.sem); +fail1: + TlsFree(thread_data_key); return BHT_ERROR; } -int os_thread_create(korp_tid *tid, thread_start_routine_t start, void *arg, - unsigned int stack_size) +void +os_thread_sys_destroy() +{ + if (is_thread_sys_inited) { + os_cond_destroy(&supervisor_thread_data.wait_cond); + os_mutex_destroy(&supervisor_thread_data.wait_lock); + os_sem_destroy(&supervisor_thread_data.wait_node.sem); + memset(&supervisor_thread_data, 0, sizeof(os_thread_data)); + TlsFree(thread_data_key); + thread_data_key = 0; + is_thread_sys_inited = false; + } +} + +static os_thread_data * +thread_data_current() +{ + return (os_thread_data *)TlsGetValue(thread_data_key); +} + +static void +os_thread_cleanup(void *retval) +{ + os_thread_data *thread_data = thread_data_current(); + + bh_assert(thread_data != NULL); + + os_mutex_lock(&thread_data->wait_lock); + if (thread_data->thread_wait_list) { + /* Signal each joining thread */ + os_thread_wait_list head = thread_data->thread_wait_list; + while (head) { + os_thread_wait_list next = head->next; + head->retval = retval; + os_sem_signal(&head->sem); + head = next; + } + thread_data->thread_wait_list = NULL; + } + os_mutex_unlock(&thread_data->wait_lock); + + /* Destroy resources */ + os_cond_destroy(&thread_data->wait_cond); + os_sem_destroy(&thread_data->wait_node.sem); + os_mutex_destroy(&thread_data->wait_lock); + BH_FREE(thread_data); +} + +static unsigned +os_thread_wrapper(void *arg) +{ + os_thread_data *thread_data = arg; + os_thread_data *parent = thread_data->parent; + void *retval; + bool result; + + os_printf("THREAD CREATED %p\n", thread_data); + + os_mutex_lock(&parent->wait_lock); + thread_data->thread_id = GetCurrentThreadId(); + result = TlsSetValue(thread_data_key, thread_data); + /* Notify parent thread */ + os_cond_signal(&parent->wait_cond); + os_mutex_unlock(&parent->wait_lock); + + if (!result) + return -1; + + retval = thread_data->start_routine(thread_data->arg); + + os_thread_cleanup(retval); + return 0; +} + +int +os_thread_create_with_prio(korp_tid *p_tid, thread_start_routine_t start, + void *arg, unsigned int stack_size, int prio) +{ + os_thread_data *parent = thread_data_current(); + os_thread_data *thread_data; + + if (!p_tid || !start) + return BHT_ERROR; + + if (stack_size < BH_APPLET_PRESERVED_STACK_SIZE) + stack_size = BH_APPLET_PRESERVED_STACK_SIZE; + + if (!(thread_data = BH_MALLOC(sizeof(os_thread_data)))) + return BHT_ERROR; + + memset(thread_data, 0, sizeof(os_thread_data)); + thread_data->parent = parent; + thread_data->start_routine = start; + thread_data->arg = arg; + + if (os_sem_init(&thread_data->wait_node.sem) != BHT_OK) + goto fail1; + + if (os_mutex_init(&thread_data->wait_lock) != BHT_OK) + goto fail2; + + if (os_cond_init(&thread_data->wait_cond) != BHT_OK) + goto fail3; + + os_mutex_lock(&parent->wait_lock); + if (!_beginthreadex(NULL, stack_size, + os_thread_wrapper, thread_data, + 0, NULL)) { + os_mutex_unlock(&parent->wait_lock); + goto fail4; + } + /* Wait for the thread routine to set thread_data's tid + and add thread_data to thread data list */ + os_cond_wait(&parent->wait_cond, &parent->wait_lock); + os_mutex_unlock(&parent->wait_lock); + + *p_tid = (korp_tid)thread_data; + return BHT_OK; + +fail4: + os_cond_destroy(&thread_data->wait_cond); +fail3: + os_mutex_destroy(&thread_data->wait_lock); +fail2: + os_sem_destroy(&thread_data->wait_node.sem); +fail1: + BH_FREE(thread_data); + return BHT_ERROR; +} + +int +os_thread_create(korp_tid *tid, thread_start_routine_t start, void *arg, + unsigned int stack_size) { return os_thread_create_with_prio(tid, start, arg, stack_size, BH_THREAD_DEFAULT_PRIORITY); } -korp_tid os_self_thread() +korp_tid +os_self_thread() { - return NULL; + return (korp_tid)TlsGetValue(thread_data_key); } -int os_mutex_init(korp_mutex *mutex) +int +os_thread_join(korp_tid thread, void **p_retval) { + os_thread_data *thread_data, *curr_thread_data; + + /* Get thread data of current thread */ + curr_thread_data = thread_data_current(); + curr_thread_data->wait_node.next = NULL; + + /* Get thread data of thread to join */ + thread_data = (os_thread_data *)thread; + bh_assert(thread_data); + + os_mutex_lock(&thread_data->wait_lock); + if (!thread_data->thread_wait_list) + thread_data->thread_wait_list = &curr_thread_data->wait_node; + else { + /* Add to end of waiting list */ + os_thread_wait_node *p = thread_data->thread_wait_list; + while (p->next) + p = p->next; + p->next = &curr_thread_data->wait_node; + } + os_mutex_unlock(&thread_data->wait_lock); + + /* Wait the sem */ + os_sem_wait(&curr_thread_data->wait_node.sem); + if (p_retval) + *p_retval = curr_thread_data->wait_node.retval; return BHT_OK; } -int os_recursive_mutex_init(korp_mutex *mutex) +int +os_thread_detach(korp_tid thread) { + /* Do nothing */ + return BHT_OK; + (void)thread; +} + +void +os_thread_exit(void *retval) +{ + os_thread_cleanup(retval); + _endthreadex(0); +} + +int +os_sem_init(korp_sem *sem) +{ + bh_assert(sem); + *sem = CreateSemaphore(NULL, 0, BH_SEM_COUNT_MAX, NULL); + return (*sem != NULL) ? BHT_OK : BHT_ERROR; +} + +int +os_sem_destroy(korp_sem *sem) +{ + bh_assert(sem); + CloseHandle(*sem); return BHT_OK; } -int os_mutex_destroy(korp_mutex *mutex) +int +os_sem_wait(korp_sem *sem) { + DWORD ret; + + bh_assert(sem); + + ret = WaitForSingleObject(*sem, INFINITE); + + if (ret == WAIT_OBJECT_0) + return BHT_OK; + else if(ret == WAIT_TIMEOUT) + return (int)WAIT_TIMEOUT; + else /* WAIT_FAILED or others */ + return BHT_ERROR; +} + +int +os_sem_reltimed_wait(korp_sem *sem, uint64 useconds) +{ + uint64 mseconds_64; + DWORD ret, mseconds; + + bh_assert(sem); + + if (useconds == BHT_WAIT_FOREVER) + mseconds = INFINITE; + else { + mseconds_64 = useconds / 1000; + + if (mseconds_64 < (uint64)(UINT32_MAX - 1)) { + mseconds = (uint32)mseconds_64; + } + else { + mseconds = UINT32_MAX - 1; + os_printf("Warning: os_sem_reltimed_wait exceeds limit, " + "set to max timeout instead\n"); + } + } + + ret = WaitForSingleObject(*sem, mseconds); + + if (ret == WAIT_OBJECT_0) + return BHT_OK; + else if(ret == WAIT_TIMEOUT) + return (int)WAIT_TIMEOUT; + else /* WAIT_FAILED or others */ + return BHT_ERROR; +} + +int +os_sem_signal(korp_sem *sem) +{ + bh_assert(sem); + return ReleaseSemaphore(*sem, 1, NULL) != FALSE + ? BHT_OK: BHT_ERROR; +} + +int +os_mutex_init(korp_mutex *mutex) +{ + bh_assert(mutex); + *mutex = CreateMutex(NULL, FALSE, NULL); + return (*mutex != NULL) ? BHT_OK : BHT_ERROR; +} + +int +os_recursive_mutex_init(korp_mutex *mutex) +{ + bh_assert(mutex); + *mutex = CreateMutex(NULL, FALSE, NULL); + return (*mutex != NULL) ? BHT_OK : BHT_ERROR; +} + +int +os_mutex_destroy(korp_mutex *mutex) +{ + assert(mutex); + return CloseHandle(*mutex) ? BHT_OK : BHT_ERROR; +} + +int +os_mutex_lock(korp_mutex *mutex) +{ + int ret; + + assert(mutex); + ret = WaitForSingleObject(*mutex, INFINITE); + return ret != WAIT_FAILED ? BHT_OK : BHT_ERROR; +} + +int +os_mutex_unlock(korp_mutex *mutex) +{ + bh_assert(mutex); + return ReleaseMutex(*mutex) ? BHT_OK : BHT_ERROR; +} + +int +os_cond_init(korp_cond *cond) +{ + bh_assert(cond); + if (os_mutex_init(&cond->wait_list_lock) != BHT_OK) + return BHT_ERROR; + + cond->thread_wait_list = NULL; return BHT_OK; } -int os_mutex_lock(korp_mutex *mutex) -{ - return BHT_ERROR; -} - -int os_mutex_unlock(korp_mutex *mutex) +int +os_cond_destroy(korp_cond *cond) { + bh_assert(cond); + os_mutex_destroy(&cond->wait_list_lock); return BHT_OK; } -int os_cond_init(korp_cond *cond) +static int +os_cond_wait_internal(korp_cond *cond, korp_mutex *mutex, + bool timed, uint64 useconds) { + os_thread_wait_node *node = &thread_data_current()->wait_node; + + node->next = NULL; + + bh_assert(cond); + bh_assert(mutex); + os_mutex_lock(&cond->wait_list_lock); + if (!cond->thread_wait_list) + cond->thread_wait_list = node; + else { + /* Add to end of wait list */ + os_thread_wait_node *p = cond->thread_wait_list; + while (p->next) + p = p->next; + p->next = node; + } + os_mutex_unlock(&cond->wait_list_lock); + + /* Unlock mutex, wait sem and lock mutex again */ + os_mutex_unlock(mutex); + if (timed) + os_sem_reltimed_wait(&node->sem, useconds); + else + os_sem_wait(&node->sem); + os_mutex_lock(mutex); + + /* Remove wait node from wait list */ + os_mutex_lock(&cond->wait_list_lock); + if (cond->thread_wait_list == node) + cond->thread_wait_list = node->next; + else { + /* Remove from the wait list */ + os_thread_wait_node *p = cond->thread_wait_list; + while (p->next != node) + p = p->next; + p->next = node->next; + } + os_mutex_unlock(&cond->wait_list_lock); + return BHT_OK; } -int os_cond_destroy(korp_cond *cond) +int +os_cond_wait(korp_cond *cond, korp_mutex *mutex) { - return BHT_OK; + return os_cond_wait_internal(cond, mutex, false, 0); } -int os_cond_wait(korp_cond *cond, korp_mutex *mutex) +int +os_cond_reltimedwait(korp_cond *cond, korp_mutex *mutex, uint64 useconds) { - return BHT_OK; -} - - -int gettimeofday(struct timeval * tp, struct timezone * tzp) -{ - /* Note: some broken versions only have 8 trailing zero's, - the correct epoch has 9 trailing zero's - This magic number is the number of 100 nanosecond intervals - since January 1, 1601 (UTC) until 00:00:00 January 1, 1970 */ - static const uint64_t EPOCH = ((uint64_t) 116444736000000000ULL); - - SYSTEMTIME system_time; - FILETIME file_time; - uint64_t time; - - GetSystemTime(&system_time); - SystemTimeToFileTime(&system_time, &file_time); - time = ((uint64_t)file_time.dwLowDateTime); - time += ((uint64_t)file_time.dwHighDateTime) << 32; - - tp->tv_sec = (long)((time - EPOCH) / 10000000L); - tp->tv_usec = (long)(system_time.wMilliseconds * 1000); - - return 0; -} - -static void msec_nsec_to_abstime(struct timespec *ts, int usec) -{ - struct timeval tv; - - gettimeofday(&tv, NULL); - - ts->tv_sec = (long int)(tv.tv_sec + usec / 1000000); - ts->tv_nsec = (long int)(tv.tv_usec * 1000 + (usec % 1000000) * 1000); - - if (ts->tv_nsec >= 1000000000L) { - ts->tv_sec++; - ts->tv_nsec -= 1000000000L; + if (useconds == BHT_WAIT_FOREVER) { + return os_cond_wait_internal(cond, mutex, false, 0); + } + else { + return os_cond_wait_internal(cond, mutex, true, useconds); } } -int os_cond_reltimedwait(korp_cond *cond, korp_mutex *mutex, uint64 useconds) +int +os_cond_signal(korp_cond *cond) { - return BHT_OK; -} + /* Signal the head wait node of wait list */ + os_mutex_lock(&cond->wait_list_lock); + if (cond->thread_wait_list) + os_sem_signal(&cond->thread_wait_list->sem); + os_mutex_unlock(&cond->wait_list_lock); -int os_cond_signal(korp_cond *cond) -{ return BHT_OK; } -int os_thread_join(korp_tid thread, void **value_ptr) -{ - return BHT_OK; -} - -int os_thread_detach(korp_tid thread) -{ - return BHT_OK; -} - -void os_thread_exit(void *retval) -{ -} - static os_thread_local_attribute uint8 *thread_stack_boundary = NULL; -uint8 *os_thread_get_stack_boundary() +uint8 * +os_thread_get_stack_boundary() { ULONG_PTR low_limit = 0, high_limit = 0; uint32 page_size; @@ -167,10 +511,21 @@ uint8 *os_thread_get_stack_boundary() return thread_stack_boundary; } +static os_thread_local_attribute bool stack_guard_pages_inited = false; + bool os_thread_init_stack_guard_pages() { - return true; + ULONG StackSizeInBytes = 16 * 1024; + bool ret; + + if (stack_guard_pages_inited) + return true; + + ret = SetThreadStackGuarantee(&StackSizeInBytes); + if (ret) + stack_guard_pages_inited = true; + return ret; } void diff --git a/doc/build_wamr.md b/doc/build_wamr.md index f9692bb81..0127f4d1b 100644 --- a/doc/build_wamr.md +++ b/doc/build_wamr.md @@ -448,14 +448,15 @@ Docker Make sure you have Docker installed on your machine: [macOS](https://docs.docker.com/docker-for-mac/install/), [Windows](https://docs.docker.com/docker-for-windows/install/) or [Linux](https://docs.docker.com/install/linux/docker-ce/ubuntu/). -Build the Docker image: +Build *iwasm* with the Docker image: ``` Bash -docker build --rm -f "Dockerfile" -t wamr:latest . +$ cd ci +$ ./build_wamr.sh +$ ls ../build_out/ ``` -Run the image in interactive mode: -``` Bash -docker run --rm -it wamr:latest -``` -You'll now enter the container at `/root`. +*build_wamr.sh* will generate *linux* compatible libraries ( libiwasm.so and +libvmlib.a ) and an executable binary (*iwasm*) and copy *iwasm* to +*build_out*. All original generated files are still under +*product-mini/platforms/linux/build*. \ No newline at end of file diff --git a/product-mini/platforms/windows/main.c b/product-mini/platforms/windows/main.c index 1e857283d..3a224d9cd 100644 --- a/product-mini/platforms/windows/main.c +++ b/product-mini/platforms/windows/main.c @@ -79,12 +79,12 @@ static char ** split_string(char *str, int *count) { char **res = NULL; - char *p; + char *p, *next_token; int idx = 0; /* split string and append tokens to 'res' */ do { - p = strtok(str, " "); + p = strtok_s(str, " ", &next_token); str = NULL; res = (char **)realloc(res, sizeof(char *) * (uint32)(idx + 1)); if (res == NULL) { From 17a216748574499bd3a5130e7e6a20b84fe76798 Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Thu, 13 May 2021 15:13:52 +0800 Subject: [PATCH 191/207] Fix wasm-c-api JIT issue and update makefile (#630) --- CMakeLists.txt | 1 - core/iwasm/aot/aot_runtime.c | 23 ++++++++++------------- core/iwasm/common/wasm_runtime_common.c | 4 ++-- 3 files changed, 12 insertions(+), 16 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c3e4a1eae..75951ebb8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -97,7 +97,6 @@ endif () set (WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}) include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) -add_library(vmlib ${WAMR_RUNTIME_LIB_SOURCE}) set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections -pie -fPIE") diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index ea0cd9f1d..6a2e61ad4 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -1483,25 +1483,24 @@ aot_create_exec_env_and_call_function(AOTModuleInstance *module_inst, AOTFunctionInstance *func, unsigned argc, uint32 argv[]) { - WASMExecEnv *exec_env; + WASMExecEnv *exec_env = NULL, *existing_exec_env = NULL; bool ret; #if WASM_ENABLE_THREAD_MGR != 0 - WASMExecEnv *existing_exec_env = NULL; - - if (!(existing_exec_env = exec_env = - wasm_clusters_search_exec_env( - (WASMModuleInstanceCommon*)module_inst))) { + existing_exec_env = exec_env = wasm_clusters_search_exec_env( + (WASMModuleInstanceCommon*)module_inst); +#elif defined(OS_ENABLE_HW_BOUND_CHECK) + existing_exec_env = exec_env = aot_exec_env; #endif - if (!(exec_env = wasm_exec_env_create((WASMModuleInstanceCommon*)module_inst, - module_inst->default_wasm_stack_size))) { + + if (!existing_exec_env) { + if (!(exec_env = + wasm_exec_env_create((WASMModuleInstanceCommon *)module_inst, + module_inst->default_wasm_stack_size))) { aot_set_exception(module_inst, "allocate memory failed"); return false; } - -#if WASM_ENABLE_THREAD_MGR != 0 } -#endif #if WASM_ENABLE_REF_TYPES != 0 wasm_runtime_prepare_call_function(exec_env, func); @@ -1513,10 +1512,8 @@ aot_create_exec_env_and_call_function(AOTModuleInstance *module_inst, wasm_runtime_finalize_call_function(exec_env, func, ret, argv); #endif -#if WASM_ENABLE_THREAD_MGR != 0 /* don't destroy the exec_env if it's searched from the cluster */ if (!existing_exec_env) -#endif wasm_exec_env_destroy(exec_env); return ret; diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index c96820608..a8863ca67 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -4530,7 +4530,7 @@ wasm_runtime_get_memory_data(const WASMModuleInstanceCommon *module_inst_comm, if (module_inst_comm->module_type == Wasm_Module_AoT) { AOTModuleInstance *module_inst = (AOTModuleInstance *)module_inst_comm; AOTMemoryInstance *memory_inst = - (AOTMemoryInstance*)module_inst->memories.ptr + memory_inst_idx; + ((AOTMemoryInstance**)module_inst->memories.ptr)[memory_inst_idx]; return memory_inst->memory_data.ptr; } #endif @@ -4556,7 +4556,7 @@ wasm_runtime_get_memory_data_size( if (module_inst_comm->module_type == Wasm_Module_AoT) { AOTModuleInstance *module_inst = (AOTModuleInstance *)module_inst_comm; AOTMemoryInstance *memory_inst = - (AOTMemoryInstance*)module_inst->memories.ptr + memory_inst_idx; + ((AOTMemoryInstance**)module_inst->memories.ptr)[memory_inst_idx]; return memory_inst->cur_page_count * memory_inst->num_bytes_per_page; } #endif From a14a4487bb8b493bf6c68d83b03f12028d16f58a Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Fri, 14 May 2021 11:13:12 +0800 Subject: [PATCH 192/207] Re-org thread env init/destroy for HW bound check (#631) And fix cmake_minimum_required() deprecation warning since envoy is using cmake 3.16 or higher version. --- CMakeLists.txt | 2 +- core/iwasm/aot/aot_runtime.c | 28 ++-- core/iwasm/common/wasm_c_api.c | 31 ++-- core/iwasm/common/wasm_runtime_common.c | 21 +++ core/iwasm/include/wasm_export.h | 21 +++ core/shared/platform/android/platform_init.c | 3 - .../platform/android/platform_internal.h | 10 +- .../platform/common/posix/posix_thread.c | 143 ++++++++++-------- core/shared/platform/darwin/platform_init.c | 3 - .../platform/darwin/platform_internal.h | 10 +- core/shared/platform/linux/platform_init.c | 3 - .../shared/platform/linux/platform_internal.h | 10 +- core/shared/platform/vxworks/platform_init.c | 3 - .../platform/vxworks/platform_internal.h | 10 +- .../platform/windows/platform_internal.h | 6 +- core/shared/platform/windows/win_thread.c | 27 +++- 16 files changed, 205 insertions(+), 126 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 75951ebb8..d77473e03 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ # Copyright (C) 2019 Intel Corporation. All rights reserved. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -cmake_minimum_required (VERSION 2.8) +cmake_minimum_required (VERSION 2.8...3.16) project (iwasm) # set (CMAKE_VERBOSE_MAKEFILE 1) diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index 6a2e61ad4..935016b6f 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -1254,21 +1254,26 @@ bool aot_signal_init() { #ifndef BH_PLATFORM_WINDOWS - return os_signal_init(aot_signal_handler) == 0 ? true : false; + return os_thread_signal_init(aot_signal_handler) == 0 ? true : false; #else - return AddVectoredExceptionHandler(1, aot_exception_handler) - ? true : false; + if (os_thread_signal_init() != 0) + return false; + + if (!AddVectoredExceptionHandler(1, aot_exception_handler)) { + os_thread_signal_destroy(); + return false; + } #endif + return true; } void aot_signal_destroy() { -#ifndef BH_PLATFORM_WINDOWS - os_signal_destroy(); -#else +#ifdef BH_PLATFORM_WINDOWS RemoveVectoredExceptionHandler(aot_exception_handler); #endif + os_thread_signal_destroy(); } static bool @@ -1302,7 +1307,10 @@ invoke_native_with_hw_bound_check(WASMExecEnv *exec_env, void *func_ptr, return false; } - os_thread_init_stack_guard_pages(); + if (!os_thread_signal_inited()) { + aot_set_exception(module_inst, "thread signal env not inited"); + return false; + } wasm_exec_env_push_jmpbuf(exec_env, &jmpbuf_node); @@ -1486,11 +1494,11 @@ aot_create_exec_env_and_call_function(AOTModuleInstance *module_inst, WASMExecEnv *exec_env = NULL, *existing_exec_env = NULL; bool ret; -#if WASM_ENABLE_THREAD_MGR != 0 +#if defined(OS_ENABLE_HW_BOUND_CHECK) + existing_exec_env = exec_env = aot_exec_env; +#elif WASM_ENABLE_THREAD_MGR != 0 existing_exec_env = exec_env = wasm_clusters_search_exec_env( (WASMModuleInstanceCommon*)module_inst); -#elif defined(OS_ENABLE_HW_BOUND_CHECK) - existing_exec_env = exec_env = aot_exec_env; #endif if (!existing_exec_env) { diff --git a/core/iwasm/common/wasm_c_api.c b/core/iwasm/common/wasm_c_api.c index 50b1ef678..db20479a8 100644 --- a/core/iwasm/common/wasm_c_api.c +++ b/core/iwasm/common/wasm_c_api.c @@ -363,7 +363,13 @@ wasm_store_new(wasm_engine_t *engine) return NULL; } + if (!wasm_runtime_init_thread_env()) { + LOG_ERROR("init thread environment failed"); + return NULL; + } + if (!(store = malloc_internal(sizeof(wasm_store_t)))) { + wasm_runtime_destroy_thread_env(); return NULL; } @@ -412,6 +418,8 @@ wasm_store_delete(wasm_store_t *store) DEINIT_VEC(store->modules, wasm_module_vec_delete); DEINIT_VEC(store->instances, wasm_instance_vec_delete); wasm_runtime_free(store); + + wasm_runtime_destroy_thread_env(); } /* Type Representations */ @@ -1376,7 +1384,7 @@ module_to_module_ext(wasm_module_t *module) wasm_module_t * wasm_module_new(wasm_store_t *store, const wasm_byte_vec_t *binary) { - char error[128] = { 0 }; + char error_buf[128] = { 0 }; wasm_module_ex_t *module_ex = NULL; bh_assert(singleton_engine); @@ -1393,11 +1401,12 @@ wasm_module_new(wasm_store_t *store, const wasm_byte_vec_t *binary) INIT_VEC(module_ex->binary, wasm_byte_vec_new, binary->size, binary->data); - module_ex->module_comm_rt = wasm_runtime_load( - (uint8 *)module_ex->binary->data, (uint32)module_ex->binary->size, error, - (uint32)sizeof(error)); + module_ex->module_comm_rt = + wasm_runtime_load((uint8 *)module_ex->binary->data, + (uint32)module_ex->binary->size, + error_buf, (uint32)sizeof(error_buf)); if (!(module_ex->module_comm_rt)) { - LOG_ERROR(error); + LOG_ERROR(error_buf); goto failed; } @@ -1418,6 +1427,7 @@ static void wasm_module_delete_internal(wasm_module_t *module) { wasm_module_ex_t *module_ex; + if (!module) { return; } @@ -1436,7 +1446,7 @@ wasm_module_delete_internal(wasm_module_t *module) void wasm_module_delete(wasm_module_t *module) { - /* will release module when releasing the store */ + /* the module will be released when releasing the store */ } void @@ -3589,7 +3599,7 @@ wasm_instance_new(wasm_store_t *store, const wasm_extern_t *const imports[], own wasm_trap_t **traps) { - char error[128] = { 0 }; + char error_buf[128] = { 0 }; const uint32 stack_size = 16 * 1024; const uint32 heap_size = 16 * 1024; uint32 import_count = 0; @@ -3650,10 +3660,11 @@ wasm_instance_new(wasm_store_t *store, #endif } - instance->inst_comm_rt = wasm_runtime_instantiate( - *module, stack_size, heap_size, error, sizeof(error)); + instance->inst_comm_rt = + wasm_runtime_instantiate(*module, stack_size, heap_size, + error_buf, sizeof(error_buf)); if (!instance->inst_comm_rt) { - LOG_ERROR(error); + LOG_ERROR(error_buf); goto failed; } diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index a8863ca67..761bca2fe 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -819,6 +819,27 @@ wasm_runtime_destroy_exec_env(WASMExecEnv *exec_env) wasm_exec_env_destroy(exec_env); } +bool +wasm_runtime_init_thread_env() +{ +#if WASM_ENABLE_AOT != 0 +#ifdef OS_ENABLE_HW_BOUND_CHECK + return aot_signal_init(); +#endif +#endif + return true; +} + +void +wasm_runtime_destroy_thread_env() +{ +#if WASM_ENABLE_AOT != 0 +#ifdef OS_ENABLE_HW_BOUND_CHECK + return aot_signal_destroy(); +#endif +#endif +} + #if (WASM_ENABLE_MEMORY_PROFILING != 0) || (WASM_ENABLE_MEMORY_TRACING != 0) void wasm_runtime_dump_module_mem_consumption(const WASMModuleCommon *module) diff --git a/core/iwasm/include/wasm_export.h b/core/iwasm/include/wasm_export.h index e20404bf0..32bbac4e3 100644 --- a/core/iwasm/include/wasm_export.h +++ b/core/iwasm/include/wasm_export.h @@ -392,6 +392,27 @@ wasm_runtime_create_exec_env(wasm_module_inst_t module_inst, WASM_RUNTIME_API_EXTERN void wasm_runtime_destroy_exec_env(wasm_exec_env_t exec_env); +/** + * Initialize thread environment. + * Note: + * If developer creates a child thread by himself to call the + * the wasm function in that thread, he should call this API + * firstly before calling the wasm function and then call + * wasm_runtime_destroy_thread_env() after calling the wasm + * function. If the thread is created from the runtime API, + * it is unnecessary to call these two APIs. + * + * @return true if success, false otherwise + */ +WASM_RUNTIME_API_EXTERN bool +wasm_runtime_init_thread_env(); + +/** + * Destroy thread environment + */ +WASM_RUNTIME_API_EXTERN void +wasm_runtime_destroy_thread_env(); + /** * Get WASM module instance from execution environment * diff --git a/core/shared/platform/android/platform_init.c b/core/shared/platform/android/platform_init.c index 04b1e1545..5353308c1 100644 --- a/core/shared/platform/android/platform_init.c +++ b/core/shared/platform/android/platform_init.c @@ -20,9 +20,6 @@ bh_platform_init() void bh_platform_destroy() { -#ifdef OS_ENABLE_HW_BOUND_CHECK - os_thread_destroy_stack_guard_pages(); -#endif } int os_printf(const char *fmt, ...) diff --git a/core/shared/platform/android/platform_internal.h b/core/shared/platform/android/platform_internal.h index 73cbffac3..82adc93ff 100644 --- a/core/shared/platform/android/platform_internal.h +++ b/core/shared/platform/android/platform_internal.h @@ -75,15 +75,13 @@ typedef jmp_buf korp_jmpbuf; #define os_getpagesize getpagesize -bool os_thread_init_stack_guard_pages(); - -void os_thread_destroy_stack_guard_pages(); - typedef void (*os_signal_handler)(void *sig_addr); -int os_signal_init(os_signal_handler handler); +int os_thread_signal_init(os_signal_handler handler); -void os_signal_destroy(); +void os_thread_signal_destroy(); + +bool os_thread_signal_inited(); void os_signal_unmask(); diff --git a/core/shared/platform/common/posix/posix_thread.c b/core/shared/platform/common/posix/posix_thread.c index ab515f119..f0b315d5b 100644 --- a/core/shared/platform/common/posix/posix_thread.c +++ b/core/shared/platform/common/posix/posix_thread.c @@ -11,12 +11,15 @@ typedef struct { thread_start_routine_t start; - void* arg; + void *arg; +#ifdef OS_ENABLE_HW_BOUND_CHECK + os_signal_handler signal_handler; +#endif } thread_wrapper_arg; #ifdef OS_ENABLE_HW_BOUND_CHECK -static int os_thread_signal_init(); -static void os_thread_signal_destroy(); +/* The signal handler passed to os_thread_signal_init() */ +static os_thread_local_attribute os_signal_handler signal_handler; #endif static void *os_thread_wrapper(void *arg) @@ -24,16 +27,18 @@ static void *os_thread_wrapper(void *arg) thread_wrapper_arg *targ = arg; thread_start_routine_t start_func = targ->start; void *thread_arg = targ->arg; +#ifdef OS_ENABLE_HW_BOUND_CHECK + os_signal_handler handler = targ->signal_handler; +#endif os_printf("THREAD CREATED %p\n", pthread_self()); BH_FREE(targ); #ifdef OS_ENABLE_HW_BOUND_CHECK - if (os_thread_signal_init() != 0) + if (os_thread_signal_init(handler) != 0) return NULL; #endif start_func(thread_arg); #ifdef OS_ENABLE_HW_BOUND_CHECK - os_thread_destroy_stack_guard_pages(); os_thread_signal_destroy(); #endif return NULL; @@ -66,6 +71,9 @@ int os_thread_create_with_prio(korp_tid *tid, thread_start_routine_t start, targ->start = start; targ->arg = arg; +#ifdef OS_ENABLE_HW_BOUND_CHECK + targ->signal_handler = signal_handler; +#endif if (pthread_create(tid, &tattr, os_thread_wrapper, targ) != 0) { pthread_attr_destroy(&tattr); @@ -250,7 +258,6 @@ int os_thread_detach(korp_tid thread) void os_thread_exit(void *retval) { #ifdef OS_ENABLE_HW_BOUND_CHECK - os_thread_destroy_stack_guard_pages(); os_thread_signal_destroy(); #endif return pthread_exit(retval); @@ -313,20 +320,25 @@ uint8 *os_thread_get_stack_boundary() #define SIG_ALT_STACK_SIZE (32 * 1024) -/* Whether the stack pages are touched and guard pages are set */ -static os_thread_local_attribute bool stack_guard_pages_inited = false; +/** + * Whether thread signal enviornment is initialized: + * the signal handler is registered, the stack pages are touched, + * the stack guard pages are set and signal alternate stack are set. + */ +static os_thread_local_attribute bool thread_signal_inited = false; /* The signal alternate stack base addr */ static os_thread_local_attribute uint8 *sigalt_stack_base_addr; -/* The signal handler passed to os_signal_init() */ -static os_signal_handler signal_handler; - -#if defined(__GNUC__) -__attribute__((no_sanitize_address)) static uint32 -#else -static uint32 +#if defined(__clang__) +#pragma clang optimize off #endif +#if defined(__GNUC__) +#pragma GCC push_options +#pragma GCC optimize("O0") +__attribute__((no_sanitize_address)) +#endif +static uint32 touch_pages(uint8 *stack_min_addr, uint32 page_size) { uint8 sum = 0; @@ -342,40 +354,40 @@ touch_pages(uint8 *stack_min_addr, uint32 page_size) } return sum; } +#if defined(__GNUC__) +#pragma GCC pop_options +#endif +#if defined(__clang__) +#pragma clang optimize on +#endif -bool -os_thread_init_stack_guard_pages() +static bool +init_stack_guard_pages() { uint32 page_size = os_getpagesize(); uint32 guard_page_count = STACK_OVERFLOW_CHECK_GUARD_PAGE_COUNT; uint8 *stack_min_addr = os_thread_get_stack_boundary(); - if (!stack_guard_pages_inited) { - /* Touch each stack page to ensure that it has been mapped: the OS - may lazily grow the stack mapping as a guard page is hit. */ - (void)touch_pages(stack_min_addr, page_size); - /* First time to call aot function, protect guard pages */ - if (os_mprotect(stack_min_addr, page_size * guard_page_count, - MMAP_PROT_NONE) != 0) { - return false; - } - stack_guard_pages_inited = true; + /* Touch each stack page to ensure that it has been mapped: the OS + may lazily grow the stack mapping as a guard page is hit. */ + (void)touch_pages(stack_min_addr, page_size); + /* First time to call aot function, protect guard pages */ + if (os_mprotect(stack_min_addr, page_size * guard_page_count, + MMAP_PROT_NONE) != 0) { + return false; } return true; } -void -os_thread_destroy_stack_guard_pages() +static void +destroy_stack_guard_pages() { - if (stack_guard_pages_inited) { - uint32 page_size = os_getpagesize(); - uint32 guard_page_count = STACK_OVERFLOW_CHECK_GUARD_PAGE_COUNT; - uint8 *stack_min_addr = os_thread_get_stack_boundary(); + uint32 page_size = os_getpagesize(); + uint32 guard_page_count = STACK_OVERFLOW_CHECK_GUARD_PAGE_COUNT; + uint8 *stack_min_addr = os_thread_get_stack_boundary(); - os_mprotect(stack_min_addr, page_size * guard_page_count, - MMAP_PROT_READ | MMAP_PROT_WRITE); - stack_guard_pages_inited = false; - } + os_mprotect(stack_min_addr, page_size * guard_page_count, + MMAP_PROT_READ | MMAP_PROT_WRITE); } static void @@ -419,20 +431,27 @@ signal_callback(int sig_num, siginfo_t *sig_info, void *sig_ucontext) } int -os_signal_init(os_signal_handler handler) +os_thread_signal_init(os_signal_handler handler) { - int ret = -1; struct sigaction sig_act; stack_t sigalt_stack_info; uint32 map_size = SIG_ALT_STACK_SIZE; uint8 *map_addr; + if (thread_signal_inited) + return 0; + + if (!init_stack_guard_pages()) { + os_printf("Failed to init stack guard pages\n"); + return -1; + } + /* Initialize memory for signal alternate stack of current thread */ if (!(map_addr = os_mmap(NULL, map_size, MMAP_PROT_READ | MMAP_PROT_WRITE, MMAP_MAP_NONE))) { os_printf("Failed to mmap memory for alternate stack\n"); - return -1; + goto fail1; } /* Initialize signal alternate stack */ @@ -440,38 +459,46 @@ os_signal_init(os_signal_handler handler) sigalt_stack_info.ss_sp = map_addr; sigalt_stack_info.ss_size = map_size; sigalt_stack_info.ss_flags = 0; - if ((ret = sigaltstack(&sigalt_stack_info, NULL)) != 0) { - goto fail1; + if (sigaltstack(&sigalt_stack_info, NULL) != 0) { + os_printf("Failed to init signal alternate stack\n"); + goto fail2; } /* Install signal hanlder */ sig_act.sa_sigaction = signal_callback; sig_act.sa_flags = SA_SIGINFO | SA_ONSTACK | SA_NODEFER; sigemptyset(&sig_act.sa_mask); - if ((ret = sigaction(SIGSEGV, &sig_act, NULL)) != 0 - || (ret = sigaction(SIGBUS, &sig_act, NULL)) != 0) { - goto fail2; + if (sigaction(SIGSEGV, &sig_act, NULL) != 0 + || sigaction(SIGBUS, &sig_act, NULL) != 0) { + os_printf("Failed to register signal handler\n"); + goto fail3; } sigalt_stack_base_addr = map_addr; signal_handler = handler; + thread_signal_inited = true; return 0; -fail2: +fail3: memset(&sigalt_stack_info, 0, sizeof(stack_t)); sigalt_stack_info.ss_flags = SS_DISABLE; sigalt_stack_info.ss_size = map_size; sigaltstack(&sigalt_stack_info, NULL); -fail1: +fail2: os_munmap(map_addr, map_size); - return ret; +fail1: + destroy_stack_guard_pages(); + return -1; } void -os_signal_destroy() +os_thread_signal_destroy() { stack_t sigalt_stack_info; + if (!thread_signal_inited) + return; + /* Disable signal alternate stack */ memset(&sigalt_stack_info, 0, sizeof(stack_t)); sigalt_stack_info.ss_flags = SS_DISABLE; @@ -479,20 +506,16 @@ os_signal_destroy() sigaltstack(&sigalt_stack_info, NULL); os_munmap(sigalt_stack_base_addr, SIG_ALT_STACK_SIZE); + + destroy_stack_guard_pages(); + + thread_signal_inited = false; } -static int -os_thread_signal_init() +bool +os_thread_signal_inited() { - assert(signal_handler); - /* Use the global signal handler registered previously */ - return os_signal_init(signal_handler); -} - -static void -os_thread_signal_destroy() -{ - os_signal_destroy(); + return thread_signal_inited; } void diff --git a/core/shared/platform/darwin/platform_init.c b/core/shared/platform/darwin/platform_init.c index 23cd00604..17aeb8baa 100644 --- a/core/shared/platform/darwin/platform_init.c +++ b/core/shared/platform/darwin/platform_init.c @@ -14,9 +14,6 @@ bh_platform_init() void bh_platform_destroy() { -#ifdef OS_ENABLE_HW_BOUND_CHECK - os_thread_destroy_stack_guard_pages(); -#endif } int diff --git a/core/shared/platform/darwin/platform_internal.h b/core/shared/platform/darwin/platform_internal.h index 66596b07f..d6ee41cda 100644 --- a/core/shared/platform/darwin/platform_internal.h +++ b/core/shared/platform/darwin/platform_internal.h @@ -76,15 +76,13 @@ typedef jmp_buf korp_jmpbuf; #define os_getpagesize getpagesize -bool os_thread_init_stack_guard_pages(); - -void os_thread_destroy_stack_guard_pages(); - typedef void (*os_signal_handler)(void *sig_addr); -int os_signal_init(os_signal_handler handler); +int os_thread_signal_init(os_signal_handler handler); -void os_signal_destroy(); +void os_thread_signal_destroy(); + +bool os_thread_signal_inited(); void os_signal_unmask(); diff --git a/core/shared/platform/linux/platform_init.c b/core/shared/platform/linux/platform_init.c index 23cd00604..17aeb8baa 100644 --- a/core/shared/platform/linux/platform_init.c +++ b/core/shared/platform/linux/platform_init.c @@ -14,9 +14,6 @@ bh_platform_init() void bh_platform_destroy() { -#ifdef OS_ENABLE_HW_BOUND_CHECK - os_thread_destroy_stack_guard_pages(); -#endif } int diff --git a/core/shared/platform/linux/platform_internal.h b/core/shared/platform/linux/platform_internal.h index 0154bdf5d..e2a52a6bb 100644 --- a/core/shared/platform/linux/platform_internal.h +++ b/core/shared/platform/linux/platform_internal.h @@ -75,15 +75,13 @@ typedef jmp_buf korp_jmpbuf; #define os_getpagesize getpagesize -bool os_thread_init_stack_guard_pages(); - -void os_thread_destroy_stack_guard_pages(); - typedef void (*os_signal_handler)(void *sig_addr); -int os_signal_init(os_signal_handler handler); +int os_thread_signal_init(os_signal_handler handler); -void os_signal_destroy(); +void os_thread_signal_destroy(); + +bool os_thread_signal_inited(); void os_signal_unmask(); diff --git a/core/shared/platform/vxworks/platform_init.c b/core/shared/platform/vxworks/platform_init.c index 23cd00604..17aeb8baa 100644 --- a/core/shared/platform/vxworks/platform_init.c +++ b/core/shared/platform/vxworks/platform_init.c @@ -14,9 +14,6 @@ bh_platform_init() void bh_platform_destroy() { -#ifdef OS_ENABLE_HW_BOUND_CHECK - os_thread_destroy_stack_guard_pages(); -#endif } int diff --git a/core/shared/platform/vxworks/platform_internal.h b/core/shared/platform/vxworks/platform_internal.h index 254ad68a6..56870b56e 100644 --- a/core/shared/platform/vxworks/platform_internal.h +++ b/core/shared/platform/vxworks/platform_internal.h @@ -74,15 +74,13 @@ typedef jmp_buf korp_jmpbuf; #define os_getpagesize getpagesize -bool os_thread_init_stack_guard_pages(); - -void os_thread_destroy_stack_guard_pages(); - typedef void (*os_signal_handler)(void *sig_addr); -int os_signal_init(os_signal_handler handler); +int os_thread_signal_init(os_signal_handler handler); -void os_signal_destroy(); +void os_thread_signal_destroy(); + +bool os_thread_signal_inited(); void os_signal_unmask(); diff --git a/core/shared/platform/windows/platform_internal.h b/core/shared/platform/windows/platform_internal.h index 055c19dc3..0b6d39638 100644 --- a/core/shared/platform/windows/platform_internal.h +++ b/core/shared/platform/windows/platform_internal.h @@ -72,9 +72,11 @@ typedef jmp_buf korp_jmpbuf; #define os_setjmp setjmp #define os_longjmp longjmp -bool os_thread_init_stack_guard_pages(); +int os_thread_signal_init(); -void os_thread_destroy_stack_guard_pages(); +void os_thread_signal_destroy(); + +bool os_thread_signal_inited(); #define os_signal_unmask() (void)0 #define os_sigreturn() (void)0 diff --git a/core/shared/platform/windows/win_thread.c b/core/shared/platform/windows/win_thread.c index a4746019a..86dc9fa31 100644 --- a/core/shared/platform/windows/win_thread.c +++ b/core/shared/platform/windows/win_thread.c @@ -154,6 +154,10 @@ os_thread_wrapper(void *arg) os_mutex_lock(&parent->wait_lock); thread_data->thread_id = GetCurrentThreadId(); result = TlsSetValue(thread_data_key, thread_data); +#ifdef OS_ENABLE_HW_BOUND_CHECK + if (result) + result = os_thread_signal_init() == 0 ? true : false; +#endif /* Notify parent thread */ os_cond_signal(&parent->wait_cond); os_mutex_unlock(&parent->wait_lock); @@ -511,25 +515,34 @@ os_thread_get_stack_boundary() return thread_stack_boundary; } -static os_thread_local_attribute bool stack_guard_pages_inited = false; +#ifdef OS_ENABLE_HW_BOUND_CHECK +static os_thread_local_attribute bool thread_signal_inited = false; -bool -os_thread_init_stack_guard_pages() +int +os_thread_signal_init() { ULONG StackSizeInBytes = 16 * 1024; bool ret; - if (stack_guard_pages_inited) + if (thread_signal_inited) return true; ret = SetThreadStackGuarantee(&StackSizeInBytes); if (ret) - stack_guard_pages_inited = true; - return ret; + thread_signal_inited = true; + return ret ? 0 : -1; } void -os_thread_destroy_stack_guard_pages() +os_thread_signal_destroy() { + /* Do nothing */ } +bool +os_thread_signal_inited() +{ + return thread_signal_inited; +} +#endif + From f637438e4e5c4d77247e32e66144ca2aa2fa7339 Mon Sep 17 00:00:00 2001 From: Xu Jun <693788454@qq.com> Date: Wed, 19 May 2021 14:57:31 +0800 Subject: [PATCH 193/207] Spread module custom data to all threads, enable libc-builtin float print (#633) --- build-scripts/config_common.cmake | 2 ++ core/iwasm/common/wasm_runtime_common.c | 15 ++++++++-- core/iwasm/common/wasm_runtime_common.h | 5 ++++ core/iwasm/include/wasm_export.h | 3 ++ core/iwasm/interpreter/wasm_loader.c | 2 +- core/iwasm/interpreter/wasm_mini_loader.c | 2 +- .../lib-pthread/lib_pthread_wrapper.c | 9 +++++- .../libc-builtin/libc_builtin_wrapper.c | 13 +++++++++ .../libraries/thread-mgr/thread_manager.c | 29 +++++++++++++++++++ .../libraries/thread-mgr/thread_manager.h | 4 +++ .../shared/platform/include/platform_common.h | 2 +- core/shared/platform/zephyr/zephyr_thread.c | 13 +++++---- 12 files changed, 88 insertions(+), 11 deletions(-) diff --git a/build-scripts/config_common.cmake b/build-scripts/config_common.cmake index 233174a1d..d34708c19 100644 --- a/build-scripts/config_common.cmake +++ b/build-scripts/config_common.cmake @@ -182,6 +182,8 @@ endif () if (WAMR_DISABLE_HW_BOUND_CHECK EQUAL 1) add_definitions (-DWASM_DISABLE_HW_BOUND_CHECK=1) message (" Hardware boundary check disabled") +else () + add_definitions (-DWASM_DISABLE_HW_BOUND_CHECK=0) endif () if (WAMR_BUILD_SIMD EQUAL 1) add_definitions (-DWASM_ENABLE_SIMD=1) diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index 761bca2fe..27f1f02eb 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -1438,8 +1438,8 @@ wasm_runtime_clear_exception(WASMModuleInstanceCommon *module_inst) } void -wasm_runtime_set_custom_data(WASMModuleInstanceCommon *module_inst, - void *custom_data) +wasm_runtime_set_custom_data_internal(WASMModuleInstanceCommon *module_inst, + void *custom_data) { #if WASM_ENABLE_INTERP != 0 if (module_inst->module_type == Wasm_Module_Bytecode) { @@ -1455,6 +1455,17 @@ wasm_runtime_set_custom_data(WASMModuleInstanceCommon *module_inst, #endif } +void +wasm_runtime_set_custom_data(WASMModuleInstanceCommon *module_inst, + void *custom_data) +{ +#if WASM_ENABLE_THREAD_MGR != 0 + wasm_cluster_spread_custom_data(module_inst, custom_data); +#else + wasm_runtime_set_custom_data_internal(module_inst, custom_data); +#endif +} + void* wasm_runtime_get_custom_data(WASMModuleInstanceCommon *module_inst) { diff --git a/core/iwasm/common/wasm_runtime_common.h b/core/iwasm/common/wasm_runtime_common.h index 6be32fae1..2ad46f744 100644 --- a/core/iwasm/common/wasm_runtime_common.h +++ b/core/iwasm/common/wasm_runtime_common.h @@ -490,6 +490,11 @@ wasm_runtime_get_exception(WASMModuleInstanceCommon *module); WASM_RUNTIME_API_EXTERN void wasm_runtime_clear_exception(WASMModuleInstanceCommon *module_inst); +/* Internal API */ +void +wasm_runtime_set_custom_data_internal(WASMModuleInstanceCommon *module_inst, + void *custom_data); + /* See wasm_export.h for description */ WASM_RUNTIME_API_EXTERN void wasm_runtime_set_custom_data(WASMModuleInstanceCommon *module_inst, diff --git a/core/iwasm/include/wasm_export.h b/core/iwasm/include/wasm_export.h index 32bbac4e3..b56e7b14d 100644 --- a/core/iwasm/include/wasm_export.h +++ b/core/iwasm/include/wasm_export.h @@ -554,6 +554,9 @@ wasm_runtime_clear_exception(wasm_module_inst_t module_inst); /** * Set custom data to WASM module instance. + * Note: + * If WAMR_BUILD_LIB_PTHREAD is enabled, this API + * will spread the custom data to all threads * * @param module_inst the WASM module instance * @param custom_data the custom data to be set diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index edcf15f44..7ab03fd2f 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -6152,7 +6152,7 @@ wasm_loader_prepare_bytecode(WASMModule *module, BranchBlock *frame_csp_tmp; #if WASM_ENABLE_FAST_INTERP != 0 uint8 *func_const_end, *func_const = NULL; - int16 operand_offset; + int16 operand_offset = 0; uint8 last_op = 0; bool disable_emit, preserve_local = false; float32 f32; diff --git a/core/iwasm/interpreter/wasm_mini_loader.c b/core/iwasm/interpreter/wasm_mini_loader.c index cc2cd7119..934068202 100644 --- a/core/iwasm/interpreter/wasm_mini_loader.c +++ b/core/iwasm/interpreter/wasm_mini_loader.c @@ -4758,7 +4758,7 @@ wasm_loader_prepare_bytecode(WASMModule *module, #endif #if WASM_ENABLE_FAST_INTERP != 0 uint8 *func_const_end, *func_const = NULL; - int16 operand_offset; + int16 operand_offset = 0; uint8 last_op = 0; bool disable_emit, preserve_local = false; float32 f32; diff --git a/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c b/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c index 2e80bf7f2..95634834f 100644 --- a/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c +++ b/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c @@ -535,13 +535,13 @@ pthread_create_wrapper(wasm_exec_env_t exec_env, void *arg) /* arguments buffer */ { wasm_module_t module = get_module(exec_env); + wasm_module_inst_t module_inst = get_module_inst(exec_env); wasm_module_inst_t new_module_inst = NULL; ThreadInfoNode *info_node = NULL; ThreadRoutineArgs *routine_args = NULL; uint32 thread_handle; int32 ret = -1; #if WASM_ENABLE_LIBC_WASI != 0 - wasm_module_inst_t module_inst = get_module_inst(exec_env); WASIContext *wasi_ctx = get_wasi_ctx(module_inst); #endif @@ -552,6 +552,13 @@ pthread_create_wrapper(wasm_exec_env_t exec_env, NULL, 0))) return -1; + if (module_inst) { + /* Set custom_data to new module instance */ + wasm_runtime_set_custom_data_internal( + new_module_inst, + wasm_runtime_get_custom_data(module_inst)); + } + #if WASM_ENABLE_LIBC_WASI != 0 if (wasi_ctx) wasm_runtime_set_wasi_ctx(new_module_inst, wasi_ctx); diff --git a/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c b/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c index 382c7a6de..57ba67cd9 100644 --- a/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c +++ b/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c @@ -361,6 +361,19 @@ handle_1_to_9: break; } + case 'f': { + float64 f64; + char buf[16], *s; + + CHECK_VA_ARG(ap, float64); + f64 = _va_arg(ap, float64); + snprintf(buf, sizeof(buf), "%f", f64); + s = buf; + while (*s) + out((int) (*s++), ctx); + break; + } + default: out((int) '%', ctx); out((int) *fmt, ctx); diff --git a/core/iwasm/libraries/thread-mgr/thread_manager.c b/core/iwasm/libraries/thread-mgr/thread_manager.c index c066f4aff..59330a847 100644 --- a/core/iwasm/libraries/thread-mgr/thread_manager.c +++ b/core/iwasm/libraries/thread-mgr/thread_manager.c @@ -328,6 +328,7 @@ WASMExecEnv * wasm_cluster_spawn_exec_env(WASMExecEnv *exec_env) { WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env); + wasm_module_inst_t module_inst = get_module_inst(exec_env); wasm_module_t module = wasm_exec_env_get_module(exec_env); wasm_module_inst_t new_module_inst; WASMExecEnv *new_exec_env; @@ -343,6 +344,13 @@ wasm_cluster_spawn_exec_env(WASMExecEnv *exec_env) return NULL; } + if (module_inst) { + /* Set custom_data to new module instance */ + wasm_runtime_set_custom_data_internal( + new_module_inst, + wasm_runtime_get_custom_data(module_inst)); + } + new_exec_env = wasm_exec_env_create_internal( new_module_inst, exec_env->wasm_stack_size); if (!new_exec_env) @@ -654,3 +662,24 @@ wasm_cluster_spread_exception(WASMExecEnv *exec_env) traverse_list(&cluster->exec_env_list, set_exception_visitor, exec_env); } + +static void +set_custom_data_visitor(void *node, void *user_data) +{ + WASMExecEnv *curr_exec_env = (WASMExecEnv *)node; + WASMModuleInstanceCommon *module_inst = get_module_inst(curr_exec_env); + + wasm_runtime_set_custom_data_internal(module_inst, user_data); +} + +void +wasm_cluster_spread_custom_data(WASMModuleInstanceCommon *module_inst, + void *custom_data) +{ + WASMExecEnv *exec_env = wasm_clusters_search_exec_env(module_inst); + WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env); + + traverse_list(&cluster->exec_env_list, + set_custom_data_visitor, + custom_data); +} diff --git a/core/iwasm/libraries/thread-mgr/thread_manager.h b/core/iwasm/libraries/thread-mgr/thread_manager.h index c43d0e644..392ebe4a7 100644 --- a/core/iwasm/libraries/thread-mgr/thread_manager.h +++ b/core/iwasm/libraries/thread-mgr/thread_manager.h @@ -118,6 +118,10 @@ wasm_cluster_spawn_exec_env(WASMExecEnv *exec_env); void wasm_cluster_destroy_spawned_exec_env(WASMExecEnv *exec_env); +void +wasm_cluster_spread_custom_data(WASMModuleInstanceCommon *module_inst, + void *custom_data); + #ifdef __cplusplus } #endif diff --git a/core/shared/platform/include/platform_common.h b/core/shared/platform/include/platform_common.h index 9cd5c2d8e..48bffe102 100644 --- a/core/shared/platform/include/platform_common.h +++ b/core/shared/platform/include/platform_common.h @@ -10,8 +10,8 @@ extern "C" { #endif -#include "../../../config.h" #include "platform_internal.h" +#include "../../../config.h" #define BH_MAX_THREAD 32 diff --git a/core/shared/platform/zephyr/zephyr_thread.c b/core/shared/platform/zephyr/zephyr_thread.c index 3244c6a99..932255195 100644 --- a/core/shared/platform/zephyr/zephyr_thread.c +++ b/core/shared/platform/zephyr/zephyr_thread.c @@ -231,7 +231,7 @@ int os_thread_create(korp_tid *p_tid, thread_start_routine_t start, void *arg, unsigned int stack_size) { return os_thread_create_with_prio(p_tid, start, arg, stack_size, - BH_THREAD_DEFAULT_PRIORITY); + BH_THREAD_DEFAULT_PRIORITY); } int os_thread_create_with_prio(korp_tid *p_tid, thread_start_routine_t start, @@ -253,6 +253,9 @@ int os_thread_create_with_prio(korp_tid *p_tid, thread_start_routine_t start, memset(tid, 0, sizeof(os_thread_obj)); + if (stack_size < APP_THREAD_STACK_SIZE_MIN) + stack_size = APP_THREAD_STACK_SIZE_MIN; + /* Create and initialize thread data */ thread_data_size = offsetof(os_thread_data, stack) + stack_size; if (!(thread_data = BH_MALLOC(thread_data_size))) { @@ -266,9 +269,9 @@ int os_thread_create_with_prio(korp_tid *p_tid, thread_start_routine_t start, thread_data->tid = tid; /* Create the thread */ - if (!((tid = k_thread_create(tid, (k_thread_stack_t *) thread_data->stack, - stack_size, os_thread_wrapper, start, arg, thread_data, prio, 0, - K_NO_WAIT)))) { + if (!((tid = k_thread_create(tid, (k_thread_stack_t *)thread_data->stack, + stack_size, os_thread_wrapper, start, arg, + thread_data, prio, 0, K_NO_WAIT)))) { BH_FREE(tid); BH_FREE(thread_data); return BHT_ERROR; @@ -285,7 +288,7 @@ int os_thread_create_with_prio(korp_tid *p_tid, thread_start_routine_t start, korp_tid os_self_thread() { - return (korp_tid) k_current_get(); + return (korp_tid)k_current_get(); } int os_thread_join(korp_tid thread, void **value_ptr) From 06769048ebf6340a6c7b98fb285f01c2ec6371d1 Mon Sep 17 00:00:00 2001 From: Till Schneidereit Date: Wed, 19 May 2021 13:59:23 +0200 Subject: [PATCH 194/207] Refer to BA security policy (#635) At a meeting last week, the Bytecode Alliance board resolved to introduce a [BA security policy](https://bytecodealliance.org/security), and apply it to some core projects to begin with, including WAMR. --- SECURITY.md | 28 +--------------------------- 1 file changed, 1 insertion(+), 27 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index 3513b9cb3..fa3398cde 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,29 +1,3 @@ # Security Policy -Building secure foundations for software development is at the core of what we do in the Bytecode Alliance. Contributions of external security researchers are a vital part of that. - -## Scope - -If you believe you've found a security issue in any website, service, or software owned or operated by the Bytecode Alliance, we encourage you to notify us. - -## How to Submit a Report - -To submit a vulnerability report to the Bytecode Alliance, please contact us at [security@bytecodealliance.org](mailto:security@bytecodealliance.org). Your submission will be reviewed and validated by a member of our security team. - -## Safe Harbor - -The Bytecode Alliance supports safe harbor for security researchers who: - -* Make a good faith effort to avoid privacy violations, destruction of data, and interruption or degradation of our services. -* Only interact with accounts you own or with explicit permission of the account holder. If you do encounter Personally Identifiable Information (PII) contact us immediately, do not proceed with access, and immediately purge any local information. -* Provide us with a reasonable amount of time to resolve vulnerabilities prior to any disclosure to the public or a third-party. - -We will consider activities conducted consistent with this policy to constitute "authorized" conduct and will not pursue civil action or initiate a complaint to law enforcement. We will help to the extent we can if legal action is initiated by a third party against you. - -Please submit a report to us before engaging in conduct that may be inconsistent with or unaddressed by this policy. - -## Preferences - -* Please provide detailed reports with reproducible steps and a clearly defined impact. -* Submit one vulnerability per report. -* Social engineering (e.g. phishing, vishing, smishing) is prohibited. +Please refer to the [Bytecode Alliance security policy](https://bytecodealliance.org/security) for details on how to report security issues in WebAssembly Micro Runtime, our disclosure policy, and how to receive notifications about security issues. From 1b3460694043b1f78cf91bad12e73550cbb7e0ff Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Wed, 26 May 2021 13:22:03 +0800 Subject: [PATCH 195/207] Move application entry APIs out of wasm_runtime_common.c (#639) And fix libc-builtin print float issue Add a list to track all third party components Fix compile error when MEMORY_TRACING is enabled Signed-off-by: Wenyong Huang --- ATTRIBUTIONS.md | 335 +-------- build-scripts/config_common.cmake | 6 +- core/iwasm/common/iwasm_common.cmake | 4 + core/iwasm/common/wasm_application.c | 672 ++++++++++++++++++ core/iwasm/common/wasm_runtime_common.c | 623 ---------------- .../libc-builtin/libc_builtin_wrapper.c | 2 + core/shared/mem-alloc/ems/ems_kfc.c | 22 +- doc/build_wamr.md | 6 + product-mini/platforms/alios-things/aos.mk | 1 + product-mini/platforms/esp-idf/sources.mk | 1 + product-mini/platforms/nuttx/wamr.mk | 1 + 11 files changed, 741 insertions(+), 932 deletions(-) create mode 100644 core/iwasm/common/wasm_application.c diff --git a/ATTRIBUTIONS.md b/ATTRIBUTIONS.md index 04b5fa25b..a2e76403a 100644 --- a/ATTRIBUTIONS.md +++ b/ATTRIBUTIONS.md @@ -2,329 +2,64 @@ WebAssembly Micro Runtime Attributions ====================================== WAMR project reused some components from other open source project: -- **wasmtime**: for the wasi libc implementation - **cJson**: used in the host_tool for remotely managing wasm applications - **contiki-ng**: for the coap protocol implementation - **freebsd libm**: used in core/shared/platform/alios/bh_math.c -- **littlevgl**: for the gui samples and wrapped the wasm graphic layer. +- **littlevgl**: for the gui samples and wrapped the wasm graphic layer +- **llvm**. for the AOT/JIT compilation +- **wasm-c-api**. to implement the C-APIs of wasm. using headers and sameples +- **wasmtime**: for the wasi libc implementation +- **zephyr**. for several platform specific examples -The WAMR fast interpreter is a clean room development. We would acknowledge the inspirations by [WASM3](https://github.com/wasm3/wasm3) open source project for the approach of pre-calculated oprand stack location. +The WAMR fast interpreter is a clean room development. We would acknowledge the inspirations by [WASM3](https://github.com/wasm3/wasm3) open source project for the approach of pre-calculated oprand stack location. + +| third party components | version number | latest release | vendor pages | CVE details | +| --- | --- | --- | --- | --- | +| cjson | 1.7.10 | 1.7.14 | https://github.com/DaveGamble/cJSON | https://www.cvedetails.com/vendor/19164/Cjson-Project.html | +| contiki-ng (er-coap) | unspecified | 3.0 | https://github.com/contiki-os/contiki | https://www.cvedetails.com/vendor/16528/Contiki-os.html | +| freebsd libm | unspecified | 13.0 | https://www.freebsd.org/ | https://www.cvedetails.com/vendor/6/Freebsd.html | +| littlevgl | 6.0.1 | 7.11.0 | https://lvgl.io/ | | +| llvm | 11.0.1 | 12.0.0 | https://llvm.org | https://www.cvedetails.com/vendor/13260/Llvm.html | +| wasm-c-api | ac9b509f4df86e40e56e9b01f3f49afab0100037 | c9d31284651b975f05ac27cee0bab1377560b87e | https://github.com/WebAssembly/wasm-c-api | | +| wasmtime | unspecified | v0.26.0 | https://github.com/bytecodealliance/wasmtime | | +| zephyr | unspecified | v2.5.0 | https://www.zephyrproject.org/ | https://www.cvedetails.com/vendor/19255/Zephyrproject.html | ## Licenses -### wasmtime - -``` - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - ---- LLVM Exceptions to the Apache 2.0 License ---- - -As an exception, if, as a result of your compiling your source code, portions -of this Software are embedded into an Object form of such source code, you -may redistribute such embedded portions in such Object form without complying -with the conditions of Sections 4(a), 4(b) and 4(d) of the License. - -In addition, if you combine or link compiled forms of this Software with -software that is licensed under the GPLv2 ("Combined Software") and if a -court of competent jurisdiction determines that the patent provision (Section -3), the indemnity provision (Section 9) or other Section of the License -conflicts with the conditions of the GPLv2, you may retroactively and -prospectively choose to deem waived or otherwise exclude such Section(s) of -the License, but only in their entirety and only with respect to the Combined -Software. -``` - ### cJson -``` -Copyright (c) 2009-2017 Dave Gamble and cJSON contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -``` +[LICENSE](./test-tools/host-tool/external/cJSON/LICENSE) ### contiki-ng -``` - - -Copyright (c) (Year), (Name of copyright holder) All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - - Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -``` +[LICENSE](./core/shared/coap/er-coap/LICENSE.md) ### freebsd libm -``` -Copyright 1992-2011 The FreeBSD Project. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - THIS SOFTWARE IS PROVIDED BY THE FREEBSD PROJECT ``AS IS'' AND ANY - EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FREEBSD PROJECT OR - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - The views and conclusions contained in the software and documentation - are those of the authors and should not be interpreted as representing - official policies, either expressed or implied, of the FreeBSD - Project. -``` +[COPYRIGHT](./core/shared/platform/common/math/COPYRIGHT) ### littlevgl -``` -MIT licence -Copyright (c) 2016 Gábor Kiss-Vámosi +[LICENCE](./samples/littlevgl/LICENCE.txt) -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: +[LICENSE](./core/deps/lvgl/LICENCE.txt) -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +### llvm -THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -``` +[LICENSE](./core/deps/llvm/llvm/LICENCE.txt) +### wasm-c-api +[LICENSE](./samples/wasm-c-api/src/LICENSE) +### wasmtime +[LICENSE](./core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/LICENSE) +[LICENSE](./core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/LICENSE) + +[LICENSE](./core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/LICENSE) + +### zephyr + +[LICENSE](./samples/gui/wasm-runtime-wgl/src/platform/zephyr/LICENSE) diff --git a/build-scripts/config_common.cmake b/build-scripts/config_common.cmake index d34708c19..68aad2588 100644 --- a/build-scripts/config_common.cmake +++ b/build-scripts/config_common.cmake @@ -219,6 +219,8 @@ else () message (" Reference types disabled") endif () if (DEFINED WAMR_BH_VPRINTF) - add_definitions (-DBH_VPRINTF=${WAMR_BH_VPRINTF}) + add_definitions (-DBH_VPRINTF=${WAMR_BH_VPRINTF}) +endif () +if (WAMR_DISABLE_APP_ENTRY EQUAL 1) + message (" WAMR application entry functions excluded") endif () - diff --git a/core/iwasm/common/iwasm_common.cmake b/core/iwasm/common/iwasm_common.cmake index 99c8c7e9f..7e9944fc0 100644 --- a/core/iwasm/common/iwasm_common.cmake +++ b/core/iwasm/common/iwasm_common.cmake @@ -10,6 +10,10 @@ add_definitions(-DBH_FREE=wasm_runtime_free) file (GLOB c_source_all ${IWASM_COMMON_DIR}/*.c) +if (WAMR_DISABLE_APP_ENTRY EQUAL 1) + list(REMOVE_ITEM c_source_all "${IWASM_COMMON_DIR}/wasm_application.c") +endif () + if (WAMR_BUILD_INVOKE_NATIVE_GENERAL EQUAL 1) # Use invokeNative C version instead of asm code version # if WAMR_BUILD_INVOKE_NATIVE_GENERAL is explicitly set. diff --git a/core/iwasm/common/wasm_application.c b/core/iwasm/common/wasm_application.c new file mode 100644 index 000000000..01ae4f9a7 --- /dev/null +++ b/core/iwasm/common/wasm_application.c @@ -0,0 +1,672 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "bh_platform.h" +#if WASM_ENABLE_INTERP != 0 +#include "../interpreter/wasm_runtime.h" +#endif +#if WASM_ENABLE_AOT != 0 +#include "../aot/aot_runtime.h" +#endif + +static void +set_error_buf(char *error_buf, uint32 error_buf_size, const char *string) +{ + if (error_buf != NULL) + snprintf(error_buf, error_buf_size, "%s", string); +} + +static void * +runtime_malloc(uint64 size, WASMModuleInstanceCommon *module_inst, + char *error_buf, uint32 error_buf_size) +{ + void *mem; + + if (size >= UINT32_MAX + || !(mem = wasm_runtime_malloc((uint32)size))) { + if (module_inst != NULL) { + wasm_runtime_set_exception(module_inst, + "allocate memory failed"); + } + else if (error_buf != NULL) { + set_error_buf(error_buf, error_buf_size, + "allocate memory failed"); + } + return NULL; + } + + memset(mem, 0, (uint32)size); + return mem; +} + +static union { + int a; + char b; +} __ue = { .a = 1 }; + +#define is_little_endian() (__ue.b == 1) + +/** + * Implementation of wasm_application_execute_main() + */ + +static WASMFunctionInstanceCommon* +resolve_function(const WASMModuleInstanceCommon *module_inst, + const char *name); + +static bool +check_main_func_type(const WASMType *type) +{ + if (!(type->param_count == 0 || type->param_count == 2) + ||type->result_count > 1) { + LOG_ERROR("WASM execute application failed: invalid main function type.\n"); + return false; + } + + if (type->param_count == 2 + && !(type->types[0] == VALUE_TYPE_I32 + && type->types[1] == VALUE_TYPE_I32)) { + LOG_ERROR("WASM execute application failed: invalid main function type.\n"); + return false; + } + + if (type->result_count + && type->types[type->param_count] != VALUE_TYPE_I32) { + LOG_ERROR("WASM execute application failed: invalid main function type.\n"); + return false; + } + + return true; +} + +bool +wasm_application_execute_main(WASMModuleInstanceCommon *module_inst, + int32 argc, char *argv[]) +{ + WASMFunctionInstanceCommon *func; + WASMType *func_type = NULL; + uint32 argc1 = 0, argv1[2] = { 0 }; + uint32 total_argv_size = 0; + uint64 total_size; + uint32 argv_buf_offset = 0; + int32 i; + char *argv_buf, *p, *p_end; + uint32 *argv_offsets, module_type; + bool ret, is_import_func = true; + +#if WASM_ENABLE_LIBC_WASI != 0 + if (wasm_runtime_is_wasi_mode(module_inst)) { + /* In wasi mode, we should call function named "_start" + which initializes the wasi envrionment and then calls + the actual main function. Directly call main function + may cause exception thrown. */ + if ((func = wasm_runtime_lookup_wasi_start_function(module_inst))) + return wasm_runtime_create_exec_env_and_call_wasm( + module_inst, func, 0, NULL); + /* if no start function is found, we execute + the main function as normal */ + } +#endif /* end of WASM_ENABLE_LIBC_WASI */ + + if (!(func = resolve_function(module_inst, "main")) + && !(func = resolve_function(module_inst, "__main_argc_argv")) + && !(func = resolve_function(module_inst, "_main"))) { + wasm_runtime_set_exception(module_inst, + "lookup main function failed"); + return false; + } + +#if WASM_ENABLE_INTERP != 0 + if (module_inst->module_type == Wasm_Module_Bytecode) { + is_import_func = ((WASMFunctionInstance*)func)->is_import_func; + } +#endif +#if WASM_ENABLE_AOT != 0 + if (module_inst->module_type == Wasm_Module_AoT) { + is_import_func = ((AOTFunctionInstance*)func)->is_import_func; + } +#endif + + if (is_import_func) { + wasm_runtime_set_exception(module_inst, + "lookup main function failed"); + return false; + } + + module_type = module_inst->module_type; + func_type = wasm_runtime_get_function_type(func, module_type); + + if (!func_type) { + LOG_ERROR("invalid module instance type"); + return false; + } + + if (!check_main_func_type(func_type)) { + wasm_runtime_set_exception(module_inst, + "invalid function type of main function"); + return false; + } + + if (func_type->param_count) { + for (i = 0; i < argc; i++) + total_argv_size += (uint32)(strlen(argv[i]) + 1); + total_argv_size = align_uint(total_argv_size, 4); + + total_size = (uint64)total_argv_size + sizeof(int32) * (uint64)argc; + + if (total_size >= UINT32_MAX + || !(argv_buf_offset = + wasm_runtime_module_malloc(module_inst, (uint32)total_size, + (void**)&argv_buf))) { + wasm_runtime_set_exception(module_inst, + "allocate memory failed"); + return false; + } + + p = argv_buf; + argv_offsets = (uint32*)(p + total_argv_size); + p_end = p + total_size; + + for (i = 0; i < argc; i++) { + bh_memcpy_s(p, (uint32)(p_end - p), argv[i], (uint32)(strlen(argv[i]) + 1)); + argv_offsets[i] = argv_buf_offset + (uint32)(p - argv_buf); + p += strlen(argv[i]) + 1; + } + + argc1 = 2; + argv1[0] = (uint32)argc; + argv1[1] = (uint32)wasm_runtime_addr_native_to_app(module_inst, argv_offsets); + } + + ret = wasm_runtime_create_exec_env_and_call_wasm(module_inst, func, + argc1, argv1); + if (argv_buf_offset) + wasm_runtime_module_free(module_inst, argv_buf_offset); + return ret; +} + +#if WASM_ENABLE_MULTI_MODULE != 0 +static WASMModuleInstance * +get_sub_module_inst(const WASMModuleInstance *parent_module_inst, + const char *sub_module_name) +{ + WASMSubModInstNode *node = + bh_list_first_elem(parent_module_inst->sub_module_inst_list); + + while (node && strcmp(node->module_name, sub_module_name)) { + node = bh_list_elem_next(node); + } + return node ? node->module_inst : NULL; +} + +static bool +parse_function_name(char *orig_function_name, char **p_module_name, + char **p_function_name) +{ + if (orig_function_name[0] != '$') { + *p_module_name = NULL; + *p_function_name = orig_function_name; + return true; + } + + /** + * $module_name$function_name\0 + * ===> + * module_name\0function_name\0 + * ===> + * module_name + * function_name + */ + char *p1 = orig_function_name; + char *p2 = strchr(p1 + 1, '$'); + if (!p2) { + LOG_DEBUG("can not parse the incoming function name"); + return false; + } + + *p_module_name = p1 + 1; + *p2 = '\0'; + *p_function_name = p2 + 1; + return strlen(*p_module_name) && strlen(*p_function_name); +} +#endif + +/** + * Implementation of wasm_application_execute_func() + */ + +static WASMFunctionInstanceCommon* +resolve_function(const WASMModuleInstanceCommon *module_inst, + const char *name) +{ + uint32 i = 0; + WASMFunctionInstanceCommon *ret = NULL; +#if WASM_ENABLE_MULTI_MODULE != 0 + WASMModuleInstance *sub_module_inst = NULL; + char *orig_name = NULL; + char *sub_module_name = NULL; + char *function_name = NULL; + uint32 length = (uint32)(strlen(name) + 1); + + orig_name = runtime_malloc(sizeof(char) * length, NULL, NULL, 0); + if (!orig_name) { + return NULL; + } + + strncpy(orig_name, name, length); + + if (!parse_function_name(orig_name, &sub_module_name, &function_name)) { + goto LEAVE; + } + + LOG_DEBUG("%s -> %s and %s", name, sub_module_name, function_name); + + if (sub_module_name) { + sub_module_inst = get_sub_module_inst( + (WASMModuleInstance *)module_inst, sub_module_name); + if (!sub_module_inst) { + LOG_DEBUG("can not find a sub module named %s", sub_module_name); + goto LEAVE; + } + } +#else + const char *function_name = name; +#endif + +#if WASM_ENABLE_INTERP != 0 + if (module_inst->module_type == Wasm_Module_Bytecode) { + WASMModuleInstance *wasm_inst = (WASMModuleInstance*)module_inst; + +#if WASM_ENABLE_MULTI_MODULE != 0 + wasm_inst = sub_module_inst ? sub_module_inst : wasm_inst; +#endif /* WASM_ENABLE_MULTI_MODULE */ + + for (i = 0; i < wasm_inst->export_func_count; i++) { + if (!strcmp(wasm_inst->export_functions[i].name, function_name)) { + ret = wasm_inst->export_functions[i].function; + break; + } + } + } +#endif /* WASM_ENABLE_INTERP */ + +#if WASM_ENABLE_AOT != 0 + if (module_inst->module_type == Wasm_Module_AoT) { + AOTModuleInstance *aot_inst = (AOTModuleInstance*)module_inst; + AOTFunctionInstance *export_funcs = (AOTFunctionInstance *) + aot_inst->export_funcs.ptr; + for (i = 0; i < aot_inst->export_func_count; i++) { + if (!strcmp(export_funcs[i].func_name, function_name)) { + ret = &export_funcs[i]; + break; + } + } + } +#endif + +#if WASM_ENABLE_MULTI_MODULE != 0 +LEAVE: + wasm_runtime_free(orig_name); +#endif + return ret; +} + +union ieee754_float { + float f; + + /* This is the IEEE 754 single-precision format. */ + union { + struct { + unsigned int negative:1; + unsigned int exponent:8; + unsigned int mantissa:23; + } ieee_big_endian; + struct { + unsigned int mantissa:23; + unsigned int exponent:8; + unsigned int negative:1; + } ieee_little_endian; + } ieee; +}; + +union ieee754_double { + double d; + + /* This is the IEEE 754 double-precision format. */ + union { + struct { + unsigned int negative:1; + unsigned int exponent:11; + /* Together these comprise the mantissa. */ + unsigned int mantissa0:20; + unsigned int mantissa1:32; + } ieee_big_endian; + + struct { + /* Together these comprise the mantissa. */ + unsigned int mantissa1:32; + unsigned int mantissa0:20; + unsigned int exponent:11; + unsigned int negative:1; + } ieee_little_endian; + } ieee; +}; + +bool +wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, + const char *name, int32 argc, char *argv[]) +{ + WASMFunctionInstanceCommon *func; + WASMType *type = NULL; + uint32 argc1, *argv1 = NULL, cell_num = 0, j, k = 0; + int32 i, p, module_type; + uint64 total_size; + const char *exception; + char buf[128]; + + bh_assert(argc >= 0); + LOG_DEBUG("call a function \"%s\" with %d arguments", name, argc); + func = resolve_function(module_inst, name); + + if (!func) { + snprintf(buf, sizeof(buf), "lookup function %s failed", name); + wasm_runtime_set_exception(module_inst, buf); + goto fail; + } + +#if WASM_ENABLE_INTERP != 0 + if (module_inst->module_type == Wasm_Module_Bytecode) { + WASMFunctionInstance *wasm_func = (WASMFunctionInstance*)func; + if (wasm_func->is_import_func +#if WASM_ENABLE_MULTI_MODULE != 0 + && !wasm_func->import_func_inst +#endif + ) { + snprintf(buf, sizeof(buf), "lookup function %s failed", name); + wasm_runtime_set_exception(module_inst, buf); + goto fail; + } + } +#endif + + module_type = module_inst->module_type; + type = wasm_runtime_get_function_type(func, module_type); + + if (!type) { + LOG_ERROR("invalid module instance type"); + return false; + } + + if (type->param_count != (uint32)argc) { + wasm_runtime_set_exception(module_inst, + "invalid input argument count"); + goto fail; + } + + argc1 = type->param_cell_num; + cell_num = (argc1 > type->ret_cell_num) ? argc1 : type->ret_cell_num; + + total_size = sizeof(uint32) * (uint64)(cell_num > 2 ? cell_num : 2); + if ((!(argv1 = runtime_malloc((uint32)total_size, module_inst, + NULL, 0)))) { + goto fail; + } + + /* Parse arguments */ + for (i = 0, p = 0; i < argc; i++) { + char *endptr = NULL; + bh_assert(argv[i] != NULL); + if (argv[i][0] == '\0') { + snprintf(buf, sizeof(buf), "invalid input argument %d", i); + wasm_runtime_set_exception(module_inst, buf); + goto fail; + } + switch (type->types[i]) { + case VALUE_TYPE_I32: + argv1[p++] = (uint32)strtoul(argv[i], &endptr, 0); + break; + case VALUE_TYPE_I64: + { + union { uint64 val; uint32 parts[2]; } u; + u.val = strtoull(argv[i], &endptr, 0); + argv1[p++] = u.parts[0]; + argv1[p++] = u.parts[1]; + break; + } + case VALUE_TYPE_F32: + { + float32 f32 = strtof(argv[i], &endptr); + if (isnan(f32)) { + if (argv[i][0] == '-') { + union ieee754_float u; + u.f = f32; + if (is_little_endian()) + u.ieee.ieee_little_endian.negative = 1; + else + u.ieee.ieee_big_endian.negative = 1; + memcpy(&f32, &u.f, sizeof(float)); + } + if (endptr[0] == ':') { + uint32 sig; + union ieee754_float u; + sig = (uint32)strtoul(endptr + 1, &endptr, 0); + u.f = f32; + if (is_little_endian()) + u.ieee.ieee_little_endian.mantissa = sig; + else + u.ieee.ieee_big_endian.mantissa = sig; + memcpy(&f32, &u.f, sizeof(float)); + } + } + memcpy(&argv1[p++], &f32, sizeof(float)); + break; + } + case VALUE_TYPE_F64: + { + union { float64 val; uint32 parts[2]; } u; + u.val = strtod(argv[i], &endptr); + if (isnan(u.val)) { + if (argv[i][0] == '-') { + union ieee754_double ud; + ud.d = u.val; + if (is_little_endian()) + ud.ieee.ieee_little_endian.negative = 1; + else + ud.ieee.ieee_big_endian.negative = 1; + memcpy(&u.val, &ud.d, sizeof(double)); + } + if (endptr[0] == ':') { + uint64 sig; + union ieee754_double ud; + sig = strtoull(endptr + 1, &endptr, 0); + ud.d = u.val; + if (is_little_endian()) { + ud.ieee.ieee_little_endian.mantissa0 = sig >> 32; + ud.ieee.ieee_little_endian.mantissa1 = (uint32)sig; + } + else { + ud.ieee.ieee_big_endian.mantissa0 = sig >> 32; + ud.ieee.ieee_big_endian.mantissa1 = (uint32)sig; + } + memcpy(&u.val, &ud.d, sizeof(double)); + } + } + argv1[p++] = u.parts[0]; + argv1[p++] = u.parts[1]; + break; + } +#if WASM_ENABLE_SIMD != 0 + case VALUE_TYPE_V128: + { + /* it likes 0x123\0x234 or 123\234 */ + /* retrive first i64 */ + *(uint64*)(argv1 + p) = strtoull(argv[i], &endptr, 0); + /* skip \ */ + endptr++; + /* retrive second i64 */ + *(uint64*)(argv1 + p + 2) = strtoull(endptr, &endptr, 0); + p += 4; + break; + } +#endif /* WASM_ENABLE_SIMD != 0 */ +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_FUNCREF: + { + if (strncmp(argv[i], "null", 4) == 0 + || strncmp(argv[i], "NULL", 4) == 0) { + argv1[p++] = NULL_REF; + } + else { + argv1[p++] = (uint32)strtoul(argv[i], &endptr, 0); + } + break; + } + case VALUE_TYPE_EXTERNREF: + { + if (strncmp(argv[i], "null", 4) == 0 + || strncmp(argv[i], "NULL", 4) == 0) { + argv1[p++] = NULL_REF; + } + else { + uint64 val = strtoull(argv[i], &endptr, 0); + void *extern_obj = (void *)(uintptr_t)val; + uint32 externref_idx; + + if (!wasm_externref_obj2ref(module_inst, extern_obj, + &externref_idx)) { + wasm_runtime_set_exception( + module_inst, "map extern object to ref failed"); + goto fail; + } + argv1[p++] = externref_idx; + } + break; + } +#endif /* WASM_ENABLE_REF_TYPES */ + default: + bh_assert(0); + break; + } + if (endptr && *endptr != '\0' && *endptr != '_') { + snprintf(buf, sizeof(buf), "invalid input argument %d: %s", + i, argv[i]); + wasm_runtime_set_exception(module_inst, buf); + goto fail; + } + } + bh_assert(p == (int32)argc1); + + wasm_runtime_set_exception(module_inst, NULL); + if (!wasm_runtime_create_exec_env_and_call_wasm(module_inst, func, + argc1, argv1)) { + goto fail; + } + + /* print return value */ + for (j = 0; j < type->result_count; j++) { + switch (type->types[type->param_count + j]) { + case VALUE_TYPE_I32: + { + os_printf("0x%x:i32", argv1[k]); + k++; + break; + } + case VALUE_TYPE_I64: + { + union { uint64 val; uint32 parts[2]; } u; + u.parts[0] = argv1[k]; + u.parts[1] = argv1[k + 1]; + k += 2; +#ifdef PRIx64 + os_printf("0x%"PRIx64":i64", u.val); +#else + char buf[16]; + if (sizeof(long) == 4) + snprintf(buf, sizeof(buf), "%s", "0x%llx:i64"); + else + snprintf(buf, sizeof(buf), "%s", "0x%lx:i64"); + os_printf(buf, u.val); +#endif + break; + } + case VALUE_TYPE_F32: + { + os_printf("%.7g:f32", *(float32*)(argv1 + k)); + k++; + break; + } + case VALUE_TYPE_F64: + { + union { float64 val; uint32 parts[2]; } u; + u.parts[0] = argv1[k]; + u.parts[1] = argv1[k + 1]; + k += 2; + os_printf("%.7g:f64", u.val); + break; + } +#if WASM_ENABLE_REF_TYPES + case VALUE_TYPE_FUNCREF: + { + if (argv1[k] != NULL_REF) + os_printf("%u:ref.func", argv1[k]); + else + os_printf("func:ref.null"); + k++; + break; + } + case VALUE_TYPE_EXTERNREF: + { + if (argv1[k] != NULL_REF) { + void *extern_obj = NULL; + bool ret = wasm_externref_ref2obj(argv1[k], &extern_obj); + bh_assert(ret); + (void)ret; + os_printf("%p:ref.extern", extern_obj); + } + else + os_printf("extern:ref.null"); + k++; + break; + } +#endif +#if WASM_ENABLE_SIMD != 0 + case VALUE_TYPE_V128: + { + uint64 *v = (uint64*)(argv1 + k); +#if defined(PRIx64) + os_printf("<0x%016"PRIx64" 0x%016"PRIx64">:v128", *v, *(v + 1)); +#else + if (4 == sizeof(long)) { + os_printf("<0x%016llx 0x%016llx>:v128", *v, *(v + 1)); + } + else { + os_printf("<0x%016lx 0x%016lx>:v128", *v, *(v + 1)); + } +#endif /* PRIx64 */ + k += 4; + break; + } +#endif /* WASM_ENABLE_SIMD != 0 */ + default: + bh_assert(0); + break; + } + if (j < (uint32)(type->result_count - 1)) + os_printf(","); + } + os_printf("\n"); + + wasm_runtime_free(argv1); + return true; + +fail: + if (argv1) + wasm_runtime_free(argv1); + + exception = wasm_runtime_get_exception(module_inst); + bh_assert(exception); + os_printf("%s\n", exception); + return false; +} \ No newline at end of file diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index 27f1f02eb..c4c7e778e 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -2266,312 +2266,6 @@ wasm_exec_env_get_module(WASMExecEnv *exec_env) return NULL; } -/** - * Implementation of wasm_application_execute_main() - */ - -static WASMFunctionInstanceCommon* -resolve_function(const WASMModuleInstanceCommon *module_inst, - const char *name); - -static bool -check_main_func_type(const WASMType *type) -{ - if (!(type->param_count == 0 || type->param_count == 2) - ||type->result_count > 1) { - LOG_ERROR("WASM execute application failed: invalid main function type.\n"); - return false; - } - - if (type->param_count == 2 - && !(type->types[0] == VALUE_TYPE_I32 - && type->types[1] == VALUE_TYPE_I32)) { - LOG_ERROR("WASM execute application failed: invalid main function type.\n"); - return false; - } - - if (type->result_count - && type->types[type->param_count] != VALUE_TYPE_I32) { - LOG_ERROR("WASM execute application failed: invalid main function type.\n"); - return false; - } - - return true; -} - -bool -wasm_application_execute_main(WASMModuleInstanceCommon *module_inst, - int32 argc, char *argv[]) -{ - WASMFunctionInstanceCommon *func; - WASMType *func_type = NULL; - uint32 argc1 = 0, argv1[2] = { 0 }; - uint32 total_argv_size = 0; - uint64 total_size; - uint32 argv_buf_offset = 0; - int32 i; - char *argv_buf, *p, *p_end; - uint32 *argv_offsets, module_type; - bool ret, is_import_func = true; - -#if WASM_ENABLE_LIBC_WASI != 0 - if (wasm_runtime_is_wasi_mode(module_inst)) { - /* In wasi mode, we should call function named "_start" - which initializes the wasi envrionment and then calls - the actual main function. Directly call main function - may cause exception thrown. */ - if ((func = wasm_runtime_lookup_wasi_start_function(module_inst))) - return wasm_runtime_create_exec_env_and_call_wasm( - module_inst, func, 0, NULL); - /* if no start function is found, we execute - the main function as normal */ - } -#endif /* end of WASM_ENABLE_LIBC_WASI */ - - if (!(func = resolve_function(module_inst, "main")) - && !(func = resolve_function(module_inst, "__main_argc_argv")) - && !(func = resolve_function(module_inst, "_main"))) { - wasm_runtime_set_exception(module_inst, - "lookup main function failed"); - return false; - } - -#if WASM_ENABLE_INTERP != 0 - if (module_inst->module_type == Wasm_Module_Bytecode) { - is_import_func = ((WASMFunctionInstance*)func)->is_import_func; - } -#endif -#if WASM_ENABLE_AOT != 0 - if (module_inst->module_type == Wasm_Module_AoT) { - is_import_func = ((AOTFunctionInstance*)func)->is_import_func; - } -#endif - - if (is_import_func) { - wasm_runtime_set_exception(module_inst, - "lookup main function failed"); - return false; - } - - module_type = module_inst->module_type; - func_type = wasm_runtime_get_function_type(func, module_type); - - if (!func_type) { - LOG_ERROR("invalid module instance type"); - return false; - } - - if (!check_main_func_type(func_type)) { - wasm_runtime_set_exception(module_inst, - "invalid function type of main function"); - return false; - } - - if (func_type->param_count) { - for (i = 0; i < argc; i++) - total_argv_size += (uint32)(strlen(argv[i]) + 1); - total_argv_size = align_uint(total_argv_size, 4); - - total_size = (uint64)total_argv_size + sizeof(int32) * (uint64)argc; - - if (total_size >= UINT32_MAX - || !(argv_buf_offset = - wasm_runtime_module_malloc(module_inst, (uint32)total_size, - (void**)&argv_buf))) { - wasm_runtime_set_exception(module_inst, - "allocate memory failed"); - return false; - } - - p = argv_buf; - argv_offsets = (uint32*)(p + total_argv_size); - p_end = p + total_size; - - for (i = 0; i < argc; i++) { - bh_memcpy_s(p, (uint32)(p_end - p), argv[i], (uint32)(strlen(argv[i]) + 1)); - argv_offsets[i] = argv_buf_offset + (uint32)(p - argv_buf); - p += strlen(argv[i]) + 1; - } - - argc1 = 2; - argv1[0] = (uint32)argc; - argv1[1] = (uint32)wasm_runtime_addr_native_to_app(module_inst, argv_offsets); - } - - ret = wasm_runtime_create_exec_env_and_call_wasm(module_inst, func, - argc1, argv1); - if (argv_buf_offset) - wasm_runtime_module_free(module_inst, argv_buf_offset); - return ret; -} - -#if WASM_ENABLE_MULTI_MODULE != 0 -static WASMModuleInstance * -get_sub_module_inst(const WASMModuleInstance *parent_module_inst, - const char *sub_module_name) -{ - WASMSubModInstNode *node = - bh_list_first_elem(parent_module_inst->sub_module_inst_list); - - while (node && strcmp(node->module_name, sub_module_name)) { - node = bh_list_elem_next(node); - } - return node ? node->module_inst : NULL; -} - -static bool -parse_function_name(char *orig_function_name, char **p_module_name, - char **p_function_name) -{ - if (orig_function_name[0] != '$') { - *p_module_name = NULL; - *p_function_name = orig_function_name; - return true; - } - - /** - * $module_name$function_name\0 - * ===> - * module_name\0function_name\0 - * ===> - * module_name - * function_name - */ - char *p1 = orig_function_name; - char *p2 = strchr(p1 + 1, '$'); - if (!p2) { - LOG_DEBUG("can not parse the incoming function name"); - return false; - } - - *p_module_name = p1 + 1; - *p2 = '\0'; - *p_function_name = p2 + 1; - return strlen(*p_module_name) && strlen(*p_function_name); -} -#endif - -/** - * Implementation of wasm_application_execute_func() - */ - -static WASMFunctionInstanceCommon* -resolve_function(const WASMModuleInstanceCommon *module_inst, - const char *name) -{ - uint32 i = 0; - WASMFunctionInstanceCommon *ret = NULL; -#if WASM_ENABLE_MULTI_MODULE != 0 - WASMModuleInstance *sub_module_inst = NULL; - char *orig_name = NULL; - char *sub_module_name = NULL; - char *function_name = NULL; - uint32 length = (uint32)(strlen(name) + 1); - - orig_name = runtime_malloc(sizeof(char) * length, NULL, NULL, 0); - if (!orig_name) { - return NULL; - } - - strncpy(orig_name, name, length); - - if (!parse_function_name(orig_name, &sub_module_name, &function_name)) { - goto LEAVE; - } - - LOG_DEBUG("%s -> %s and %s", name, sub_module_name, function_name); - - if (sub_module_name) { - sub_module_inst = get_sub_module_inst( - (WASMModuleInstance *)module_inst, sub_module_name); - if (!sub_module_inst) { - LOG_DEBUG("can not find a sub module named %s", sub_module_name); - goto LEAVE; - } - } -#else - const char *function_name = name; -#endif - -#if WASM_ENABLE_INTERP != 0 - if (module_inst->module_type == Wasm_Module_Bytecode) { - WASMModuleInstance *wasm_inst = (WASMModuleInstance*)module_inst; - -#if WASM_ENABLE_MULTI_MODULE != 0 - wasm_inst = sub_module_inst ? sub_module_inst : wasm_inst; -#endif /* WASM_ENABLE_MULTI_MODULE */ - - for (i = 0; i < wasm_inst->export_func_count; i++) { - if (!strcmp(wasm_inst->export_functions[i].name, function_name)) { - ret = wasm_inst->export_functions[i].function; - break; - } - } - } -#endif /* WASM_ENABLE_INTERP */ - -#if WASM_ENABLE_AOT != 0 - if (module_inst->module_type == Wasm_Module_AoT) { - AOTModuleInstance *aot_inst = (AOTModuleInstance*)module_inst; - AOTFunctionInstance *export_funcs = (AOTFunctionInstance *) - aot_inst->export_funcs.ptr; - for (i = 0; i < aot_inst->export_func_count; i++) { - if (!strcmp(export_funcs[i].func_name, function_name)) { - ret = &export_funcs[i]; - break; - } - } - } -#endif - -#if WASM_ENABLE_MULTI_MODULE != 0 -LEAVE: - wasm_runtime_free(orig_name); -#endif - return ret; -} - -union ieee754_float { - float f; - - /* This is the IEEE 754 single-precision format. */ - union { - struct { - unsigned int negative:1; - unsigned int exponent:8; - unsigned int mantissa:23; - } ieee_big_endian; - struct { - unsigned int mantissa:23; - unsigned int exponent:8; - unsigned int negative:1; - } ieee_little_endian; - } ieee; -}; - -union ieee754_double { - double d; - - /* This is the IEEE 754 double-precision format. */ - union { - struct { - unsigned int negative:1; - unsigned int exponent:11; - /* Together these comprise the mantissa. */ - unsigned int mantissa0:20; - unsigned int mantissa1:32; - } ieee_big_endian; - - struct { - /* Together these comprise the mantissa. */ - unsigned int mantissa1:32; - unsigned int mantissa0:20; - unsigned int exponent:11; - unsigned int negative:1; - } ieee_little_endian; - } ieee; -}; - static union { int a; char b; @@ -2579,323 +2273,6 @@ static union { #define is_little_endian() (__ue.b == 1) -bool -wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, - const char *name, int32 argc, char *argv[]) -{ - WASMFunctionInstanceCommon *func; - WASMType *type = NULL; - uint32 argc1, *argv1 = NULL, cell_num = 0, j, k = 0; - int32 i, p, module_type; - uint64 total_size; - const char *exception; - char buf[128]; - - bh_assert(argc >= 0); - LOG_DEBUG("call a function \"%s\" with %d arguments", name, argc); - func = resolve_function(module_inst, name); - - if (!func) { - snprintf(buf, sizeof(buf), "lookup function %s failed", name); - wasm_runtime_set_exception(module_inst, buf); - goto fail; - } - -#if WASM_ENABLE_INTERP != 0 - if (module_inst->module_type == Wasm_Module_Bytecode) { - WASMFunctionInstance *wasm_func = (WASMFunctionInstance*)func; - if (wasm_func->is_import_func -#if WASM_ENABLE_MULTI_MODULE != 0 - && !wasm_func->import_func_inst -#endif - ) { - snprintf(buf, sizeof(buf), "lookup function %s failed", name); - wasm_runtime_set_exception(module_inst, buf); - goto fail; - } - } -#endif - - module_type = module_inst->module_type; - type = wasm_runtime_get_function_type(func, module_type); - - if (!type) { - LOG_ERROR("invalid module instance type"); - return false; - } - - if (type->param_count != (uint32)argc) { - wasm_runtime_set_exception(module_inst, - "invalid input argument count"); - goto fail; - } - - argc1 = type->param_cell_num; - cell_num = (argc1 > type->ret_cell_num) ? argc1 : type->ret_cell_num; - - total_size = sizeof(uint32) * (uint64)(cell_num > 2 ? cell_num : 2); - if ((!(argv1 = runtime_malloc((uint32)total_size, module_inst, - NULL, 0)))) { - goto fail; - } - - /* Parse arguments */ - for (i = 0, p = 0; i < argc; i++) { - char *endptr = NULL; - bh_assert(argv[i] != NULL); - if (argv[i][0] == '\0') { - snprintf(buf, sizeof(buf), "invalid input argument %d", i); - wasm_runtime_set_exception(module_inst, buf); - goto fail; - } - switch (type->types[i]) { - case VALUE_TYPE_I32: - argv1[p++] = (uint32)strtoul(argv[i], &endptr, 0); - break; - case VALUE_TYPE_I64: - { - union { uint64 val; uint32 parts[2]; } u; - u.val = strtoull(argv[i], &endptr, 0); - argv1[p++] = u.parts[0]; - argv1[p++] = u.parts[1]; - break; - } - case VALUE_TYPE_F32: - { - float32 f32 = strtof(argv[i], &endptr); - if (isnan(f32)) { - if (argv[i][0] == '-') { - union ieee754_float u; - u.f = f32; - if (is_little_endian()) - u.ieee.ieee_little_endian.negative = 1; - else - u.ieee.ieee_big_endian.negative = 1; - memcpy(&f32, &u.f, sizeof(float)); - } - if (endptr[0] == ':') { - uint32 sig; - union ieee754_float u; - sig = (uint32)strtoul(endptr + 1, &endptr, 0); - u.f = f32; - if (is_little_endian()) - u.ieee.ieee_little_endian.mantissa = sig; - else - u.ieee.ieee_big_endian.mantissa = sig; - memcpy(&f32, &u.f, sizeof(float)); - } - } - memcpy(&argv1[p++], &f32, sizeof(float)); - break; - } - case VALUE_TYPE_F64: - { - union { float64 val; uint32 parts[2]; } u; - u.val = strtod(argv[i], &endptr); - if (isnan(u.val)) { - if (argv[i][0] == '-') { - union ieee754_double ud; - ud.d = u.val; - if (is_little_endian()) - ud.ieee.ieee_little_endian.negative = 1; - else - ud.ieee.ieee_big_endian.negative = 1; - memcpy(&u.val, &ud.d, sizeof(double)); - } - if (endptr[0] == ':') { - uint64 sig; - union ieee754_double ud; - sig = strtoull(endptr + 1, &endptr, 0); - ud.d = u.val; - if (is_little_endian()) { - ud.ieee.ieee_little_endian.mantissa0 = sig >> 32; - ud.ieee.ieee_little_endian.mantissa1 = (uint32)sig; - } - else { - ud.ieee.ieee_big_endian.mantissa0 = sig >> 32; - ud.ieee.ieee_big_endian.mantissa1 = (uint32)sig; - } - memcpy(&u.val, &ud.d, sizeof(double)); - } - } - argv1[p++] = u.parts[0]; - argv1[p++] = u.parts[1]; - break; - } -#if WASM_ENABLE_SIMD != 0 - case VALUE_TYPE_V128: - { - /* it likes 0x123\0x234 or 123\234 */ - /* retrive first i64 */ - *(uint64*)(argv1 + p) = strtoull(argv[i], &endptr, 0); - /* skip \ */ - endptr++; - /* retrive second i64 */ - *(uint64*)(argv1 + p + 2) = strtoull(endptr, &endptr, 0); - p += 4; - break; - } -#endif /* WASM_ENABLE_SIMD != 0 */ -#if WASM_ENABLE_REF_TYPES != 0 - case VALUE_TYPE_FUNCREF: - { - if (strncmp(argv[i], "null", 4) == 0 - || strncmp(argv[i], "NULL", 4) == 0) { - argv1[p++] = NULL_REF; - } - else { - argv1[p++] = (uint32)strtoul(argv[i], &endptr, 0); - } - break; - } - case VALUE_TYPE_EXTERNREF: - { - if (strncmp(argv[i], "null", 4) == 0 - || strncmp(argv[i], "NULL", 4) == 0) { - argv1[p++] = NULL_REF; - } - else { - uint64 val = strtoull(argv[i], &endptr, 0); - void *extern_obj = (void *)(uintptr_t)val; - uint32 externref_idx; - - if (!wasm_externref_obj2ref(module_inst, extern_obj, - &externref_idx)) { - wasm_runtime_set_exception( - module_inst, "map extern object to ref failed"); - goto fail; - } - argv1[p++] = externref_idx; - } - break; - } -#endif /* WASM_ENABLE_REF_TYPES */ - default: - bh_assert(0); - break; - } - if (endptr && *endptr != '\0' && *endptr != '_') { - snprintf(buf, sizeof(buf), "invalid input argument %d: %s", - i, argv[i]); - wasm_runtime_set_exception(module_inst, buf); - goto fail; - } - } - bh_assert(p == (int32)argc1); - - wasm_runtime_set_exception(module_inst, NULL); - if (!wasm_runtime_create_exec_env_and_call_wasm(module_inst, func, - argc1, argv1)) { - goto fail; - } - - /* print return value */ - for (j = 0; j < type->result_count; j++) { - switch (type->types[type->param_count + j]) { - case VALUE_TYPE_I32: - { - os_printf("0x%x:i32", argv1[k]); - k++; - break; - } - case VALUE_TYPE_I64: - { - union { uint64 val; uint32 parts[2]; } u; - u.parts[0] = argv1[k]; - u.parts[1] = argv1[k + 1]; - k += 2; -#ifdef PRIx64 - os_printf("0x%"PRIx64":i64", u.val); -#else - char buf[16]; - if (sizeof(long) == 4) - snprintf(buf, sizeof(buf), "%s", "0x%llx:i64"); - else - snprintf(buf, sizeof(buf), "%s", "0x%lx:i64"); - os_printf(buf, u.val); -#endif - break; - } - case VALUE_TYPE_F32: - { - os_printf("%.7g:f32", *(float32*)(argv1 + k)); - k++; - break; - } - case VALUE_TYPE_F64: - { - union { float64 val; uint32 parts[2]; } u; - u.parts[0] = argv1[k]; - u.parts[1] = argv1[k + 1]; - k += 2; - os_printf("%.7g:f64", u.val); - break; - } -#if WASM_ENABLE_REF_TYPES - case VALUE_TYPE_FUNCREF: - { - if (argv1[k] != NULL_REF) - os_printf("%u:ref.func", argv1[k]); - else - os_printf("func:ref.null"); - k++; - break; - } - case VALUE_TYPE_EXTERNREF: - { - if (argv1[k] != NULL_REF) { - void *extern_obj = NULL; - bool ret = wasm_externref_ref2obj(argv1[k], &extern_obj); - bh_assert(ret); - (void)ret; - os_printf("%p:ref.extern", extern_obj); - } - else - os_printf("extern:ref.null"); - k++; - break; - } -#endif -#if WASM_ENABLE_SIMD != 0 - case VALUE_TYPE_V128: - { - uint64 *v = (uint64*)(argv1 + k); -#if defined(PRIx64) - os_printf("<0x%016"PRIx64" 0x%016"PRIx64">:v128", *v, *(v + 1)); -#else - if (4 == sizeof(long)) { - os_printf("<0x%016llx 0x%016llx>:v128", *v, *(v + 1)); - } - else { - os_printf("<0x%016lx 0x%016lx>:v128", *v, *(v + 1)); - } -#endif /* PRIx64 */ - k += 4; - break; - } -#endif /* WASM_ENABLE_SIMD != 0 */ - default: - bh_assert(0); - break; - } - if (j < (uint32)(type->result_count - 1)) - os_printf(","); - } - os_printf("\n"); - - wasm_runtime_free(argv1); - return true; - -fail: - if (argv1) - wasm_runtime_free(argv1); - - exception = wasm_runtime_get_exception(module_inst); - bh_assert(exception); - os_printf("%s\n", exception); - return false; -} - bool wasm_runtime_register_natives(const char *module_name, NativeSymbol *native_symbols, diff --git a/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c b/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c index 57ba67cd9..cb21bac77 100644 --- a/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c +++ b/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c @@ -365,6 +365,8 @@ handle_1_to_9: float64 f64; char buf[16], *s; + /* Make 8-byte aligned */ + ap = (_va_list)(((uintptr_t)ap + 7) & ~(uintptr_t)7); CHECK_VA_ARG(ap, float64); f64 = _va_arg(ap, float64); snprintf(buf, sizeof(buf), "%f", f64); diff --git a/core/shared/mem-alloc/ems/ems_kfc.c b/core/shared/mem-alloc/ems/ems_kfc.c index 95664dc9a..905a4da27 100644 --- a/core/shared/mem-alloc/ems/ems_kfc.c +++ b/core/shared/mem-alloc/ems/ems_kfc.c @@ -46,13 +46,6 @@ gc_init_internal(gc_heap_t *heap, char *base_addr, gc_size_t heap_max_size) bh_assert(root->size <= HMU_FC_NORMAL_MAX_SIZE); -#if WASM_ENABLE_MEMORY_TRACING != 0 - os_printf("Heap created, total size: %u\n", buf_size); - os_printf(" heap struct size: %u\n", sizeof(gc_heap_t)); - os_printf(" actual heap size: %u\n", heap_max_size); - os_printf(" padding bytes: %u\n", - buf_size - sizeof(gc_heap_t) - heap_max_size); -#endif return heap; } @@ -74,6 +67,13 @@ gc_init_with_pool(char *buf, gc_size_t buf_size) base_addr = (char*) (((uintptr_t) base_addr + 7) & (uintptr_t)~7) + GC_HEAD_PADDING; heap_max_size = (uint32)(buf_end - base_addr) & (uint32)~7; +#if WASM_ENABLE_MEMORY_TRACING != 0 + os_printf("Heap created, total size: %u\n", buf_size); + os_printf(" heap struct size: %u\n", sizeof(gc_heap_t)); + os_printf(" actual heap size: %u\n", heap_max_size); + os_printf(" padding bytes: %u\n", + buf_size - sizeof(gc_heap_t) - heap_max_size); +#endif return gc_init_internal(heap, base_addr, heap_max_size); } @@ -110,6 +110,14 @@ gc_init_with_struct_and_pool(char *struct_buf, gc_size_t struct_buf_size, heap_max_size = (uint32)(pool_buf_end - base_addr) & (uint32)~7; +#if WASM_ENABLE_MEMORY_TRACING != 0 + os_printf("Heap created, total size: %u\n", + struct_buf_size + pool_buf_size); + os_printf(" heap struct size: %u\n", sizeof(gc_heap_t)); + os_printf(" actual heap size: %u\n", heap_max_size); + os_printf(" padding bytes: %u\n", + pool_buf_size - heap_max_size); +#endif return gc_init_internal(heap, base_addr, heap_max_size); } diff --git a/doc/build_wamr.md b/doc/build_wamr.md index 0127f4d1b..72eb1f16a 100644 --- a/doc/build_wamr.md +++ b/doc/build_wamr.md @@ -138,6 +138,12 @@ Currently we only profile the memory consumption of module, module_instance and #### **Enable reference types feature** - **WAMR_BUILD_REF_TYPES**=1/0, default to disable if not set +#### **Exclude WAMR application entry functions** +- **WAMR_DISABLE_APP_ENTRY**=1/0, default to disable if not set + +> Note: The WAMR application entry (`core/iwasm/common/wasm_application.c`) encapsulate some common process to instantiate, execute the wasm functions and print the results. Some platform related APIs are used in these functions, so you can enable this flag to exclude this file if your platform doesn't support those APIs. +> *Don't enable this flag if you are building `product-mini`* + **Combination of configurations:** We can combine the configurations. For example, if we want to disable interpreter, enable AOT and WASI, we can run command: diff --git a/product-mini/platforms/alios-things/aos.mk b/product-mini/platforms/alios-things/aos.mk index 4cdf95dda..09c636d68 100644 --- a/product-mini/platforms/alios-things/aos.mk +++ b/product-mini/platforms/alios-things/aos.mk @@ -94,6 +94,7 @@ $(NAME)_SOURCES := ${SHARED_ROOT}/platform/alios/alios_platform.c \ ${SHARED_ROOT}/utils/bh_vector.c \ ${SHARED_ROOT}/utils/runtime_timer.c \ ${IWASM_ROOT}/libraries/libc-builtin/libc_builtin_wrapper.c \ + ${IWASM_ROOT}/common/wasm_application.c \ ${IWASM_ROOT}/common/wasm_runtime_common.c \ ${IWASM_ROOT}/common/wasm_native.c \ ${IWASM_ROOT}/common/wasm_exec_env.c \ diff --git a/product-mini/platforms/esp-idf/sources.mk b/product-mini/platforms/esp-idf/sources.mk index c9e5ce0f8..cc5c4dcc1 100644 --- a/product-mini/platforms/esp-idf/sources.mk +++ b/product-mini/platforms/esp-idf/sources.mk @@ -41,6 +41,7 @@ override PROJECT_CSRC := $(PROJECT_CSRC) \ $(WAMR_SRC_ROOT)/core/shared/utils/bh_log.c \ $(WAMR_SRC_ROOT)/core/shared/utils/bh_vector.c \ $(WAMR_SRC_ROOT)/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c \ + $(WAMR_SRC_ROOT)/core/iwasm/common/wasm_application.c \ $(WAMR_SRC_ROOT)/core/iwasm/common/wasm_runtime_common.c \ $(WAMR_SRC_ROOT)/core/iwasm/common/wasm_exec_env.c \ $(WAMR_SRC_ROOT)/core/iwasm/common/wasm_native.c \ diff --git a/product-mini/platforms/nuttx/wamr.mk b/product-mini/platforms/nuttx/wamr.mk index 5fe31448a..9978553fe 100644 --- a/product-mini/platforms/nuttx/wamr.mk +++ b/product-mini/platforms/nuttx/wamr.mk @@ -180,6 +180,7 @@ CSRCS += nuttx_platform.c \ bh_read_file.c \ runtime_timer.c \ libc_builtin_wrapper.c \ + wasm_application.c \ wasm_runtime_common.c \ wasm_native.c \ wasm_exec_env.c \ From ba922b0d0d7cb875b9fa131960a0fd8e153c6628 Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Wed, 26 May 2021 20:57:30 +0800 Subject: [PATCH 196/207] Refine the wasm-c-api native func call process of aot mode (#640) --- core/iwasm/aot/aot_runtime.c | 212 +++++++++++++++++++-- core/iwasm/aot/aot_runtime.h | 8 +- core/iwasm/common/wasm_c_api.c | 66 ++++--- core/iwasm/common/wasm_c_api_internal.h | 1 + core/iwasm/common/wasm_runtime_common.c | 29 +++ core/iwasm/common/wasm_runtime_common.h | 6 + core/iwasm/compilation/aot.c | 1 + core/iwasm/compilation/aot.h | 2 + core/iwasm/compilation/aot_compiler.c | 100 ++++++++++ core/iwasm/compilation/aot_compiler.h | 10 + core/iwasm/compilation/aot_emit_aot_file.c | 66 +++++-- core/iwasm/include/aot_export.h | 5 + core/iwasm/interpreter/wasm_runtime.c | 15 ++ core/iwasm/interpreter/wasm_runtime.h | 5 + 14 files changed, 459 insertions(+), 67 deletions(-) diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index 935016b6f..bc0961def 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -13,6 +13,7 @@ #if WASM_ENABLE_THREAD_MGR != 0 #include "../libraries/thread-mgr/thread_manager.h" #endif +#include "../common/wasm_c_api_internal.h" static void set_error_buf(char *error_buf, uint32 error_buf_size, const char *string) @@ -1097,6 +1098,18 @@ fail: return NULL; } +bool +aot_create_exec_env_singleton(AOTModuleInstance *module_inst) +{ + WASMExecEnv *exec_env = + wasm_exec_env_create((WASMModuleInstanceCommon *)module_inst, + module_inst->default_wasm_stack_size); + if (exec_env) + module_inst->exec_env_singleton.ptr = exec_env; + + return exec_env ? true : false; +} + void aot_deinstantiate(AOTModuleInstance *module_inst, bool is_sub_inst) { @@ -1127,6 +1140,10 @@ aot_deinstantiate(AOTModuleInstance *module_inst, bool is_sub_inst) if (module_inst->func_type_indexes.ptr) wasm_runtime_free(module_inst->func_type_indexes.ptr); + if (module_inst->exec_env_singleton.ptr) + wasm_exec_env_destroy((WASMExecEnv *) + module_inst->exec_env_singleton.ptr); + wasm_runtime_free(module_inst); } @@ -1287,6 +1304,9 @@ invoke_native_with_hw_bound_check(WASMExecEnv *exec_env, void *func_ptr, WASMJmpBuf jmpbuf_node = { 0 }, *jmpbuf_node_pop; uint32 page_size = os_getpagesize(); uint32 guard_page_count = STACK_OVERFLOW_CHECK_GUARD_PAGE_COUNT; + uint16 param_count = func_type->param_count; + uint16 result_count = func_type->result_count; + const uint8 *types = func_type->types; #if BH_PLATFORM_WINDOWS const char *exce; int result; @@ -1316,9 +1336,31 @@ invoke_native_with_hw_bound_check(WASMExecEnv *exec_env, void *func_ptr, aot_exec_env = exec_env; if (os_setjmp(jmpbuf_node.jmpbuf) == 0) { - ret = wasm_runtime_invoke_native(exec_env, func_ptr, func_type, - signature, attachment, - argv, argc, argv_ret); + /* Quick call with func_ptr if the function signature is simple */ + if (!signature && param_count == 1 && types[0] == VALUE_TYPE_I32) { + if (result_count == 0) { + void (*NativeFunc)(WASMExecEnv*, uint32) = + (void (*)(WASMExecEnv*, uint32))func_ptr; + NativeFunc(exec_env, argv[0]); + ret = aot_get_exception(module_inst) ? false : true; + } + else if (result_count == 1 && types[param_count] == VALUE_TYPE_I32) { + uint32 (*NativeFunc)(WASMExecEnv*, uint32) = + (uint32 (*)(WASMExecEnv*, uint32))func_ptr; + argv_ret[0] = NativeFunc(exec_env, argv[0]); + ret = aot_get_exception(module_inst) ? false : true; + } + else { + ret = wasm_runtime_invoke_native(exec_env, func_ptr, func_type, + signature, attachment, + argv, argc, argv_ret); + } + } + else { + ret = wasm_runtime_invoke_native(exec_env, func_ptr, func_type, + signature, attachment, + argv, argc, argv_ret); + } #ifdef BH_PLATFORM_WINDOWS if ((exce = aot_get_exception(module_inst)) && strstr(exce, "native stack overflow")) { @@ -1339,8 +1381,10 @@ invoke_native_with_hw_bound_check(WASMExecEnv *exec_env, void *func_ptr, if (!exec_env->jmpbuf_stack_top) { *p_aot_exec_env = NULL; } - os_sigreturn(); - os_signal_unmask(); + if (!ret) { + os_sigreturn(); + os_signal_unmask(); + } (void)jmpbuf_node_pop; return ret; } @@ -2157,6 +2201,140 @@ aot_is_wasm_type_equal(AOTModuleInstance *module_inst, return wasm_type_equal(type1, type2); } +static inline bool +argv_to_params(wasm_val_t *out_params, const uint32 *argv, + AOTFuncType *func_type) +{ + wasm_val_t *param = out_params; + uint32 i = 0, *u32; + + for (i = 0; i < func_type->param_count; i++, param++) { + switch (func_type->types[i]) { + case VALUE_TYPE_I32: + param->kind = WASM_I32; + param->of.i32 = *argv++; + break; + case VALUE_TYPE_I64: + param->kind = WASM_I64; + u32 = (uint32*)¶m->of.i64; + u32[0] = *argv++; + u32[1] = *argv++; + break; + case VALUE_TYPE_F32: + param->kind = WASM_F32; + param->of.f32 = *(float32 *)argv++; + break; + case VALUE_TYPE_F64: + param->kind = WASM_F64; + u32 = (uint32*)¶m->of.i64; + u32[0] = *argv++; + u32[1] = *argv++; + break; + default: + return false; + } + } + + return true; +} + +static inline bool +results_to_argv(uint32 *out_argv, const wasm_val_t *results, + AOTFuncType *func_type) +{ + const wasm_val_t *result = results; + uint32 *argv = out_argv, *u32, i; + uint8 *result_types = func_type->types + func_type->param_count; + + for (i = 0; i < func_type->result_count; i++, result++) { + switch (result_types[i]) { + case VALUE_TYPE_I32: + case VALUE_TYPE_F32: + *(int32*)argv++ = result->of.i32; + break; + case VALUE_TYPE_I64: + case VALUE_TYPE_F64: + u32 = (uint32*)&result->of.i64; + *argv++ = u32[0]; + *argv++ = u32[1]; + break; + default: + return false; + } + } + + return true; +} + +static inline bool +invoke_wasm_c_api_native(AOTModuleInstance *module_inst, void *func_ptr, + AOTFuncType *func_type, uint32 argc, uint32 *argv, + bool with_env, void *wasm_c_api_env) +{ + wasm_val_t params_buf[16], results_buf[4]; + wasm_val_t *params = params_buf, *results = results_buf; + wasm_trap_t *trap = NULL; + bool ret = false; + char fmt[16]; + + if (func_type->param_count > 16 + && !(params = wasm_runtime_malloc(sizeof(wasm_val_t) + * func_type->param_count))) { + aot_set_exception_with_id(module_inst, EXCE_OUT_OF_MEMORY); + return false; + } + + if (!argv_to_params(params, argv, func_type)) { + aot_set_exception(module_inst, "unsupported param type"); + goto fail; + } + + if (!with_env) { + wasm_func_callback_t callback = (wasm_func_callback_t)func_ptr; + trap = callback(params, results); + } + else { + wasm_func_callback_with_env_t callback = + (wasm_func_callback_with_env_t)func_ptr; + trap = callback(wasm_c_api_env, params, results); + } + if (trap) { + if (trap->message->data) { + snprintf(fmt, sizeof(fmt), "%%%us", (uint32)trap->message->size); + snprintf(module_inst->cur_exception, + sizeof(module_inst->cur_exception), + fmt, trap->message->data); + } + else { + aot_set_exception(module_inst, + "native function throw unknown exception"); + } + wasm_trap_delete(trap); + goto fail; + } + + if (func_type->result_count > 4 + && !(results = wasm_runtime_malloc(sizeof(wasm_val_t) + * func_type->result_count))) { + aot_set_exception_with_id(module_inst, EXCE_OUT_OF_MEMORY); + goto fail; + } + + if (!results_to_argv(argv, results, func_type)) { + aot_set_exception(module_inst, "unsupported result type"); + goto fail; + } + + ret = true; + +fail: + if (params != params_buf) + wasm_runtime_free(params); + if (results != results_buf) + wasm_runtime_free(results); + return ret; +} + bool aot_invoke_native(WASMExecEnv *exec_env, uint32 func_idx, uint32 argc, uint32 *argv) @@ -2174,19 +2352,6 @@ aot_invoke_native(WASMExecEnv *exec_env, uint32 func_idx, void *attachment; char buf[128]; -#ifdef OS_ENABLE_HW_BOUND_CHECK - uint32 page_size = os_getpagesize(); - uint32 guard_page_count = STACK_OVERFLOW_CHECK_GUARD_PAGE_COUNT; - /* Check native stack overflow firstly to ensure we have enough - native stack to run the following codes before actually calling - the aot function in invokeNative function. */ - if ((uint8*)&module_inst < exec_env->native_stack_boundary - + page_size * (guard_page_count + 1)) { - aot_set_exception_with_id(module_inst, EXCE_NATIVE_STACK_OVERFLOW); - return false; - } -#endif - bh_assert(func_idx < aot_module->import_func_count); import_func = aot_module->import_funcs + func_idx; @@ -2198,14 +2363,21 @@ aot_invoke_native(WASMExecEnv *exec_env, uint32 func_idx, return false; } - signature = import_func->signature; attachment = import_func->attachment; - if (!import_func->call_conv_raw) { + if (import_func->call_conv_wasm_c_api) { + return invoke_wasm_c_api_native(module_inst, func_ptr, + func_type, argc, argv, + import_func->wasm_c_api_with_env, + attachment); + } + else if (!import_func->call_conv_raw) { + signature = import_func->signature; return wasm_runtime_invoke_native(exec_env, func_ptr, func_type, signature, attachment, argv, argc, argv); } else { + signature = import_func->signature; return wasm_runtime_invoke_native_raw(exec_env, func_ptr, func_type, signature, attachment, argv, argc, argv); diff --git a/core/iwasm/aot/aot_runtime.h b/core/iwasm/aot/aot_runtime.h index 4d4dc7b1f..237764b59 100644 --- a/core/iwasm/aot/aot_runtime.h +++ b/core/iwasm/aot/aot_runtime.h @@ -346,13 +346,15 @@ typedef struct AOTModuleInstance { /* function performance profiling info list */ AOTPointer func_perf_profilings; + AOTPointer exec_env_singleton; + /* others */ uint32 temp_ret; uint32 llvm_stack; uint32 default_wasm_stack_size; /* reserved */ - uint32 reserved[11]; + uint32 reserved[9]; /* * +------------------------------+ <-- memories.ptr @@ -522,6 +524,10 @@ bool aot_create_exec_env_and_call_function(AOTModuleInstance *module_inst, AOTFunctionInstance *function, unsigned argc, uint32 argv[]); + +bool +aot_create_exec_env_singleton(AOTModuleInstance *module_inst); + /** * Set AOT module instance exception with exception string * diff --git a/core/iwasm/common/wasm_c_api.c b/core/iwasm/common/wasm_c_api.c index db20479a8..c53388267 100644 --- a/core/iwasm/common/wasm_c_api.c +++ b/core/iwasm/common/wasm_c_api.c @@ -2335,14 +2335,12 @@ wasm_func_call(const wasm_func_t *func, /* a int64 or float64 parameter means 2 */ uint32 argc = 0; /* a parameter list and a return value list */ - uint32 *argv = NULL; + uint32 argv_buf[32], *argv = argv_buf; WASMFunctionInstanceCommon *func_comm_rt = NULL; + WASMExecEnv *exec_env = NULL; size_t param_count, result_count, alloc_count; - if (!func || !func->type || !func->inst_comm_rt - || !valid_module_type(func->inst_comm_rt->module_type)) { - return NULL; - } + bh_assert(func && func->type && func->inst_comm_rt); cur_trap = NULL; @@ -2355,20 +2353,23 @@ wasm_func_call(const wasm_func_t *func, #if WASM_ENABLE_AOT != 0 if (func->inst_comm_rt->module_type == Wasm_Module_AoT) { - AOTModuleInstance *inst_aot = (AOTModuleInstance *)func->inst_comm_rt; - AOTModule *module_aot = (AOTModule *)inst_aot->aot_module.ptr; + if (!(func_comm_rt = func->func_comm_rt)) { + AOTModuleInstance *inst_aot = (AOTModuleInstance *)func->inst_comm_rt; + AOTModule *module_aot = (AOTModule *)inst_aot->aot_module.ptr; + uint32 export_i = 0, export_func_j = 0; - uint32 export_i = 0, export_func_j = 0; - for (; export_i < module_aot->export_count; ++export_i) { - AOTExport *export = module_aot->exports + export_i; - if (export->kind == EXPORT_KIND_FUNC) { - if (export->index == func->func_idx_rt) { - func_comm_rt = - (AOTFunctionInstance *)inst_aot->export_funcs.ptr - + export_func_j; - break; + for (; export_i < module_aot->export_count; ++export_i) { + AOTExport *export = module_aot->exports + export_i; + if (export->kind == EXPORT_KIND_FUNC) { + if (export->index == func->func_idx_rt) { + func_comm_rt = + (AOTFunctionInstance *)inst_aot->export_funcs.ptr + + export_func_j; + ((wasm_func_t*)func)->func_comm_rt = func_comm_rt; + break; + } + export_func_j++; } - export_func_j++; } } } @@ -2381,7 +2382,7 @@ wasm_func_call(const wasm_func_t *func, param_count = wasm_func_param_arity(func); result_count = wasm_func_result_arity(func); alloc_count = (param_count > result_count) ? param_count : result_count; - if (alloc_count) { + if (alloc_count > sizeof(argv_buf)/sizeof(uint64)) { if (!(argv = malloc_internal(sizeof(uint64) * alloc_count))) { goto failed; } @@ -2394,8 +2395,12 @@ wasm_func_call(const wasm_func_t *func, goto failed; } - if (!wasm_runtime_create_exec_env_and_call_wasm( - func->inst_comm_rt, func_comm_rt, argc, argv)) { + exec_env = wasm_runtime_get_exec_env_singleton(func->inst_comm_rt); + if (!exec_env) { + goto failed; + } + + if (!wasm_runtime_call_wasm(exec_env, func_comm_rt, argc, argv)) { if (wasm_runtime_get_exception(func->inst_comm_rt)) { LOG_DEBUG(wasm_runtime_get_exception(func->inst_comm_rt)); goto failed; @@ -2410,11 +2415,13 @@ wasm_func_call(const wasm_func_t *func, } } - FREEIF(argv); + if (argv != argv_buf) + wasm_runtime_free(argv); return NULL; failed: - FREEIF(argv); + if (argv != argv_buf) + wasm_runtime_free(argv); if (cur_trap) { return cur_trap; } @@ -3392,9 +3399,14 @@ aot_link_func(const wasm_instance_t *inst, return false; } - import_aot_func->call_conv_raw = true; - import_aot_func->attachment = cloned; - import_aot_func->func_ptr_linked = native_func_trampoline; + import_aot_func->call_conv_wasm_c_api = true; + import_aot_func->wasm_c_api_with_env = import->with_env; + if (import->with_env) { + import_aot_func->func_ptr_linked = import->u.cb_env.cb; + import_aot_func->attachment = import->u.cb_env.env; + } + else + import_aot_func->func_ptr_linked = import->u.cb; import->func_idx_rt = import_func_idx_rt; return true; @@ -3668,6 +3680,10 @@ wasm_instance_new(wasm_store_t *store, goto failed; } + if (!wasm_runtime_create_exec_env_singleton(instance->inst_comm_rt)) { + goto failed; + } + /* fill with inst */ for (i = 0; imports && i < (uint32)import_count; ++i) { wasm_extern_t *import = (wasm_extern_t *)imports[i]; diff --git a/core/iwasm/common/wasm_c_api_internal.h b/core/iwasm/common/wasm_c_api_internal.h index b308968be..073eead86 100644 --- a/core/iwasm/common/wasm_c_api_internal.h +++ b/core/iwasm/common/wasm_c_api_internal.h @@ -112,6 +112,7 @@ struct wasm_func_t { */ uint16 func_idx_rt; WASMModuleInstanceCommon *inst_comm_rt; + WASMFunctionInstanceCommon *func_comm_rt; }; struct wasm_global_t { diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index c4c7e778e..1999dacb5 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -1397,6 +1397,35 @@ wasm_runtime_create_exec_env_and_call_wasm(WASMModuleInstanceCommon *module_inst return ret; } +bool +wasm_runtime_create_exec_env_singleton(WASMModuleInstanceCommon *module_inst) +{ +#if WASM_ENABLE_INTERP != 0 + if (module_inst->module_type == Wasm_Module_Bytecode) + return wasm_create_exec_env_singleton((WASMModuleInstance *)module_inst); +#endif +#if WASM_ENABLE_AOT != 0 + if (module_inst->module_type == Wasm_Module_AoT) + return aot_create_exec_env_singleton((AOTModuleInstance *)module_inst); +#endif + return false; +} + +WASMExecEnv * +wasm_runtime_get_exec_env_singleton(WASMModuleInstanceCommon *module_inst) +{ +#if WASM_ENABLE_INTERP != 0 + if (module_inst->module_type == Wasm_Module_Bytecode) + return ((WASMModuleInstance *)module_inst)->exec_env_singleton; +#endif +#if WASM_ENABLE_AOT != 0 + if (module_inst->module_type == Wasm_Module_AoT) + return (WASMExecEnv *) + ((AOTModuleInstance *)module_inst)->exec_env_singleton.ptr; +#endif + return NULL; +} + void wasm_runtime_set_exception(WASMModuleInstanceCommon *module_inst, const char *exception) diff --git a/core/iwasm/common/wasm_runtime_common.h b/core/iwasm/common/wasm_runtime_common.h index 2ad46f744..4ed886222 100644 --- a/core/iwasm/common/wasm_runtime_common.h +++ b/core/iwasm/common/wasm_runtime_common.h @@ -467,6 +467,12 @@ wasm_runtime_create_exec_env_and_call_wasm(WASMModuleInstanceCommon *module_inst WASMFunctionInstanceCommon *function, uint32 argc, uint32 argv[]); +bool +wasm_runtime_create_exec_env_singleton(WASMModuleInstanceCommon *module_inst); + +WASMExecEnv * +wasm_runtime_get_exec_env_singleton(WASMModuleInstanceCommon *module_inst); + /* See wasm_export.h for description */ WASM_RUNTIME_API_EXTERN bool wasm_application_execute_main(WASMModuleInstanceCommon *module_inst, diff --git a/core/iwasm/compilation/aot.c b/core/iwasm/compilation/aot.c index 1bb67f3f1..3ab580cc5 100644 --- a/core/iwasm/compilation/aot.c +++ b/core/iwasm/compilation/aot.c @@ -290,6 +290,7 @@ aot_create_import_funcs(const WASMModule *module) import_funcs[i].signature = import_func->signature; import_funcs[i].attachment = import_func->attachment; import_funcs[i].call_conv_raw = import_func->call_conv_raw; + import_funcs[i].call_conv_wasm_c_api = false; /* Resolve function type index */ for (j = 0; j < module->type_count; j++) if (import_func->func_type == module->types[j]) { diff --git a/core/iwasm/compilation/aot.h b/core/iwasm/compilation/aot.h index 015c84a7d..44f98cf1e 100644 --- a/core/iwasm/compilation/aot.h +++ b/core/iwasm/compilation/aot.h @@ -148,6 +148,8 @@ typedef struct AOTImportFunc { /* attachment */ void *attachment; bool call_conv_raw; + bool call_conv_wasm_c_api; + bool wasm_c_api_with_env; } AOTImportFunc; /** diff --git a/core/iwasm/compilation/aot_compiler.c b/core/iwasm/compilation/aot_compiler.c index 781e1f9fb..3232448ee 100644 --- a/core/iwasm/compilation/aot_compiler.c +++ b/core/iwasm/compilation/aot_compiler.c @@ -2130,3 +2130,103 @@ aot_emit_object_file(AOTCompContext *comp_ctx, char *file_name) return true; } +#if WASM_ENABLE_REF_TYPES != 0 +extern void +wasm_set_ref_types_flag(bool enable); +#endif + +uint8* +aot_compile_wasm_file(const uint8 *wasm_file_buf, uint32 wasm_file_size, + uint32 opt_level, uint32 size_level, + uint32 *p_aot_file_size) +{ + WASMModuleCommon *wasm_module = NULL; + AOTCompData *comp_data = NULL; + AOTCompContext *comp_ctx = NULL; + RuntimeInitArgs init_args; + AOTCompOption option = { 0 }; + uint8 *aot_file_buf = NULL; + uint32 aot_file_size; + char error_buf[128]; + + option.is_jit_mode = false; + option.opt_level = opt_level; + option.size_level = size_level; + option.output_format = AOT_FORMAT_FILE; + /* default value, enable or disable depends on the platform */ + option.bounds_checks = 2; + option.enable_simd = true; + option.enable_aux_stack_check = true; +#if WASM_ENABLE_BULK_MEMORY != 0 + option.enable_bulk_memory = true; +#endif +#if WASM_ENABLE_THREAD_MGR != 0 + option.enable_thread_mgr = true; +#endif +#if WASM_ENABLE_TAIL_CALL != 0 + option.enable_tail_call = true; +#endif +#if WASM_ENABLE_SIMD != 0 + option.enable_simd = true; +#endif +#if WASM_ENABLE_REF_TYPES != 0 + option.enable_ref_types = true; +#endif +#if (WASM_ENABLE_PERF_PROFILING != 0) || (WASM_ENABLE_DUMP_CALL_STACK != 0) + option.enable_aux_stack_frame = true; +#endif + +#if WASM_ENABLE_REF_TYPES != 0 + wasm_set_ref_types_flag(option.enable_ref_types); +#endif + + memset(&init_args, 0, sizeof(RuntimeInitArgs)); + + init_args.mem_alloc_type = Alloc_With_Allocator; + init_args.mem_alloc_option.allocator.malloc_func = malloc; + init_args.mem_alloc_option.allocator.realloc_func = realloc; + init_args.mem_alloc_option.allocator.free_func = free; + + /* load WASM module */ + if (!(wasm_module = (WASMModuleCommon*) + wasm_load(wasm_file_buf, wasm_file_size, + error_buf, sizeof(error_buf)))) { + os_printf("%s\n", error_buf); + aot_set_last_error(error_buf); + return NULL; + } + + if (!(comp_data = aot_create_comp_data((WASMModule*)wasm_module))) { + os_printf("%s\n", aot_get_last_error()); + goto fail1; + } + + if (!(comp_ctx = aot_create_comp_context(comp_data, &option))) { + os_printf("%s\n", aot_get_last_error()); + goto fail2; + } + + if (!aot_compile_wasm(comp_ctx)) { + os_printf("%s\n", aot_get_last_error()); + goto fail3; + } + + if (!(aot_file_buf = aot_emit_aot_file_buf(comp_ctx, comp_data, + &aot_file_size))) { + os_printf("%s\n", aot_get_last_error()); + goto fail3; + } + + *p_aot_file_size = aot_file_size; + +fail3: + /* Destroy compiler context */ + aot_destroy_comp_context(comp_ctx); +fail2: + /* Destroy compile data */ + aot_destroy_comp_data(comp_data); +fail1: + wasm_runtime_unload(wasm_module); + + return aot_file_buf; +} diff --git a/core/iwasm/compilation/aot_compiler.h b/core/iwasm/compilation/aot_compiler.h index 182e180db..feb2eaff4 100644 --- a/core/iwasm/compilation/aot_compiler.h +++ b/core/iwasm/compilation/aot_compiler.h @@ -368,9 +368,19 @@ aot_emit_aot_file(AOTCompContext *comp_ctx, AOTCompData *comp_data, const char *file_name); +uint8_t* +aot_emit_aot_file_buf(AOTCompContext *comp_ctx, + AOTCompData *comp_data, + uint32_t *p_aot_file_size); + bool aot_emit_object_file(AOTCompContext *comp_ctx, char *file_name); +uint8_t* +aot_compile_wasm_file(const uint8_t *wasm_file_buf, uint32_t wasm_file_size, + uint32_t opt_level, uint32_t size_level, + uint32_t *p_aot_file_size); + #ifdef __cplusplus } /* end of extern "C" */ #endif diff --git a/core/iwasm/compilation/aot_emit_aot_file.c b/core/iwasm/compilation/aot_emit_aot_file.c index 8102f846c..64c04e2a3 100644 --- a/core/iwasm/compilation/aot_emit_aot_file.c +++ b/core/iwasm/compilation/aot_emit_aot_file.c @@ -2208,20 +2208,17 @@ fail: return NULL; } -bool -aot_emit_aot_file(AOTCompContext *comp_ctx, AOTCompData *comp_data, - const char *file_name) +uint8* +aot_emit_aot_file_buf(AOTCompContext *comp_ctx, + AOTCompData *comp_data, + uint32 *p_aot_file_size) { AOTObjectData *obj_data = aot_obj_data_create(comp_ctx); uint8 *aot_file_buf, *buf, *buf_end; uint32 aot_file_size, offset = 0; - bool ret = false; - FILE *file; if (!obj_data) - return false; - - bh_print_time("Begin to emit AOT file"); + return NULL; aot_file_size = get_aot_file_size(comp_ctx, comp_data, obj_data); @@ -2251,25 +2248,52 @@ aot_emit_aot_file(AOTCompContext *comp_ctx, AOTCompData *comp_data, goto fail2; } - /* write buffer to file */ - if (!(file = fopen(file_name, "wb"))) { - aot_set_last_error("open or create aot file failed."); - goto fail2; - } - if (!fwrite(aot_file_buf, aot_file_size, 1, file)) { - aot_set_last_error("write to aot file failed."); - goto fail3; - } + *p_aot_file_size = aot_file_size; - ret = true; - -fail3: - fclose(file); + aot_obj_data_destroy(obj_data); + return aot_file_buf; fail2: wasm_runtime_free(aot_file_buf); fail1: aot_obj_data_destroy(obj_data); + return NULL; +} + +bool +aot_emit_aot_file(AOTCompContext *comp_ctx, AOTCompData *comp_data, + const char *file_name) +{ + uint8 *aot_file_buf; + uint32 aot_file_size; + bool ret = false; + FILE *file; + + bh_print_time("Begin to emit AOT file"); + + if (!(aot_file_buf = aot_emit_aot_file_buf(comp_ctx, comp_data, + &aot_file_size))) { + return false; + } + + /* write buffer to file */ + if (!(file = fopen(file_name, "wb"))) { + aot_set_last_error("open or create aot file failed."); + goto fail1; + } + if (!fwrite(aot_file_buf, aot_file_size, 1, file)) { + aot_set_last_error("write to aot file failed."); + goto fail2; + } + + ret = true; + +fail2: + fclose(file); + +fail1: + wasm_runtime_free(aot_file_buf); + return ret; } diff --git a/core/iwasm/include/aot_export.h b/core/iwasm/include/aot_export.h index 8adf663a3..d209044ce 100644 --- a/core/iwasm/include/aot_export.h +++ b/core/iwasm/include/aot_export.h @@ -77,6 +77,11 @@ aot_emit_aot_file(aot_comp_context_t comp_ctx, void aot_destroy_aot_file(uint8_t *aot_file); +uint8_t* +aot_compile_wasm_file(const uint8_t *wasm_file_buf, uint32_t wasm_file_size, + uint32_t opt_level, uint32_t size_level, + uint32_t *p_aot_file_size); + char* aot_get_last_error(); diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index 08c2bd241..d3874dfa7 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -1574,6 +1574,9 @@ wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst) wasm_externref_cleanup((WASMModuleInstanceCommon*)module_inst); #endif + if (module_inst->exec_env_singleton) + wasm_exec_env_destroy(module_inst->exec_env_singleton); + wasm_runtime_free(module_inst); } @@ -1701,6 +1704,18 @@ wasm_create_exec_env_and_call_function(WASMModuleInstance *module_inst, return ret; } +bool +wasm_create_exec_env_singleton(WASMModuleInstance *module_inst) +{ + WASMExecEnv *exec_env = + wasm_exec_env_create((WASMModuleInstanceCommon *)module_inst, + module_inst->default_wasm_stack_size); + if (exec_env) + module_inst->exec_env_singleton = exec_env; + + return exec_env ? true : false; +} + void wasm_set_exception(WASMModuleInstance *module_inst, const char *exception) diff --git a/core/iwasm/interpreter/wasm_runtime.h b/core/iwasm/interpreter/wasm_runtime.h index 5f45f183c..55c13c282 100644 --- a/core/iwasm/interpreter/wasm_runtime.h +++ b/core/iwasm/interpreter/wasm_runtime.h @@ -198,6 +198,8 @@ struct WASMModuleInstance { WASIContext *wasi_ctx; #endif + WASMExecEnv *exec_env_singleton; + uint32 temp_ret; uint32 llvm_stack; @@ -318,6 +320,9 @@ wasm_create_exec_env_and_call_function(WASMModuleInstance *module_inst, WASMFunctionInstance *function, unsigned argc, uint32 argv[]); +bool +wasm_create_exec_env_singleton(WASMModuleInstance *module_inst); + void wasm_set_exception(WASMModuleInstance *module, const char *exception); From 631838cfd9492fdd6d67eabc12f02a10014366c3 Mon Sep 17 00:00:00 2001 From: doujiang Date: Thu, 27 May 2021 13:22:35 +0800 Subject: [PATCH 197/207] fix wasm-c-api sample AOT mode. (#636) --- samples/wasm-c-api/CMakeLists.txt | 15 +++++++++++++++ samples/wasm-c-api/src/callback.c | 4 ++++ samples/wasm-c-api/src/global.c | 4 ++++ samples/wasm-c-api/src/hello.c | 4 ++++ samples/wasm-c-api/src/reflect.c | 4 ++++ samples/wasm-c-api/src/trap.c | 4 ++++ 6 files changed, 35 insertions(+) diff --git a/samples/wasm-c-api/CMakeLists.txt b/samples/wasm-c-api/CMakeLists.txt index 7e0e38d21..fa5094735 100644 --- a/samples/wasm-c-api/CMakeLists.txt +++ b/samples/wasm-c-api/CMakeLists.txt @@ -119,6 +119,21 @@ foreach(EX ${EXAMPLES}) VERBATIM SOURCES ${SRC} ) + + # generate .aot file + if(${WAMR_BUILD_AOT} EQUAL 1) + if(EXISTS ${WAMRC}) + add_custom_target(${EX}_AOT ALL + COMMAND ${WAMRC} -o ${PROJECT_BINARY_DIR}/${EX}.aot + ${PROJECT_BINARY_DIR}/${EX}.wasm + DEPENDS ${PROJECT_BINARY_DIR}/${EX}.wasm + BYPRODUCTS ${PROJECT_BINARY_DIR}/${EX}.aot + VERBATIM + SOURCES ${SRC} + COMMENT "generate a aot file ${PROJECT_BINARY_DIR}/${EX}.aot" + ) + endif() + endif() endforeach() if (CMAKE_BUILD_TYPE STREQUAL "Debug") diff --git a/samples/wasm-c-api/src/callback.c b/samples/wasm-c-api/src/callback.c index ed0b60df5..bd8d17ec0 100644 --- a/samples/wasm-c-api/src/callback.c +++ b/samples/wasm-c-api/src/callback.c @@ -68,7 +68,11 @@ int main(int argc, const char* argv[]) { // Load binary. printf("Loading binary...\n"); +#if WASM_ENABLE_AOT != 0 && WASM_ENABLE_INTERP == 0 + FILE* file = fopen("callback.aot", "rb"); +#else FILE* file = fopen("callback.wasm", "rb"); +#endif if (!file) { printf("> Error loading module!\n"); return 1; diff --git a/samples/wasm-c-api/src/global.c b/samples/wasm-c-api/src/global.c index 053fef710..b1747d680 100644 --- a/samples/wasm-c-api/src/global.c +++ b/samples/wasm-c-api/src/global.c @@ -53,7 +53,11 @@ int main(int argc, const char* argv[]) { // Load binary. printf("Loading binary...\n"); +#if WASM_ENABLE_AOT != 0 && WASM_ENABLE_INTERP == 0 + FILE* file = fopen("global.aot", "rb"); +#else FILE* file = fopen("global.wasm", "rb"); +#endif if (!file) { printf("> Error loading module!\n"); return 1; diff --git a/samples/wasm-c-api/src/hello.c b/samples/wasm-c-api/src/hello.c index 1ea538b0d..cc5aa53e8 100644 --- a/samples/wasm-c-api/src/hello.c +++ b/samples/wasm-c-api/src/hello.c @@ -25,7 +25,11 @@ int main(int argc, const char* argv[]) { // Load binary. printf("Loading binary...\n"); +#if WASM_ENABLE_AOT != 0 && WASM_ENABLE_INTERP == 0 + FILE* file = fopen("hello.aot", "rb"); +#else FILE* file = fopen("hello.wasm", "rb"); +#endif if (!file) { printf("> Error loading module!\n"); return 1; diff --git a/samples/wasm-c-api/src/reflect.c b/samples/wasm-c-api/src/reflect.c index f2e41869c..746613abe 100644 --- a/samples/wasm-c-api/src/reflect.c +++ b/samples/wasm-c-api/src/reflect.c @@ -90,7 +90,11 @@ int main(int argc, const char* argv[]) { // Load binary. printf("Loading binary...\n"); +#if WASM_ENABLE_AOT != 0 && WASM_ENABLE_INTERP == 0 + FILE* file = fopen("reflect.aot", "rb"); +#else FILE* file = fopen("reflect.wasm", "rb"); +#endif if (!file) { printf("> Error loading module!\n"); return 1; diff --git a/samples/wasm-c-api/src/trap.c b/samples/wasm-c-api/src/trap.c index 60ff0654b..3074df93f 100644 --- a/samples/wasm-c-api/src/trap.c +++ b/samples/wasm-c-api/src/trap.c @@ -27,7 +27,11 @@ int main(int argc, const char* argv[]) { // Load binary. printf("Loading binary...\n"); +#if WASM_ENABLE_AOT != 0 && WASM_ENABLE_INTERP == 0 + FILE* file = fopen("trap.aot", "rb"); +#else FILE* file = fopen("trap.wasm", "rb"); +#endif if (!file) { printf("> Error loading module!\n"); return 1; From 15dd6515395236d1edbdda2de5740613c781ce3d Mon Sep 17 00:00:00 2001 From: YAMAMOTO Takashi Date: Mon, 31 May 2021 10:56:47 +0900 Subject: [PATCH 198/207] Fix os_cond_timedwait and other issues for NuttX sim/macOS (#562) --- core/iwasm/interpreter/wasm_loader.c | 2 +- core/shared/mem-alloc/ems/ems_kfc.c | 2 +- .../shared/platform/common/posix/posix_thread.c | 17 ++++++++++++----- core/shared/platform/include/platform_common.h | 4 ++++ core/shared/platform/nuttx/platform_internal.h | 3 +++ product-mini/platforms/nuttx/wamr.mk | 2 +- 6 files changed, 22 insertions(+), 8 deletions(-) diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index 7ab03fd2f..57e46edf0 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -3618,7 +3618,7 @@ wasm_loader_find_block_addr(BlockAddr *block_addr_cache, uint32 block_nested_depth = 1, count, i, j, t; uint32 error_buf_size = sizeof(error_buf); uint8 opcode, u8; - BlockAddr block_stack[16] = { 0 }, *block; + BlockAddr block_stack[16] = {{0}}, *block; i = ((uintptr_t)start_addr) & (uintptr_t)(BLOCK_ADDR_CACHE_SIZE - 1); block = block_addr_cache + BLOCK_ADDR_CONFLICT_SIZE * i; diff --git a/core/shared/mem-alloc/ems/ems_kfc.c b/core/shared/mem-alloc/ems/ems_kfc.c index 905a4da27..c4f7195b8 100644 --- a/core/shared/mem-alloc/ems/ems_kfc.c +++ b/core/shared/mem-alloc/ems/ems_kfc.c @@ -92,7 +92,7 @@ gc_init_with_struct_and_pool(char *struct_buf, gc_size_t struct_buf_size, } if (struct_buf_size < sizeof(gc_handle_t)) { - os_printf("[GC_ERROR]heap init struct buf size (%u) < %u\n", + os_printf("[GC_ERROR]heap init struct buf size (%u) < %zu\n", struct_buf_size, sizeof(gc_handle_t)); return NULL; } diff --git a/core/shared/platform/common/posix/posix_thread.c b/core/shared/platform/common/posix/posix_thread.c index f0b315d5b..60a13fb61 100644 --- a/core/shared/platform/common/posix/posix_thread.c +++ b/core/shared/platform/common/posix/posix_thread.c @@ -31,7 +31,7 @@ static void *os_thread_wrapper(void *arg) os_signal_handler handler = targ->signal_handler; #endif - os_printf("THREAD CREATED %p\n", pthread_self()); + os_printf("THREAD CREATED %jx\n", (uintmax_t)(uintptr_t)pthread_self()); BH_FREE(targ); #ifdef OS_ENABLE_HW_BOUND_CHECK if (os_thread_signal_init(handler) != 0) @@ -184,17 +184,18 @@ int os_cond_wait(korp_cond *cond, korp_mutex *mutex) static void msec_nsec_to_abstime(struct timespec *ts, uint64 usec) { struct timeval tv; - long int tv_sec_new, tv_nsec_new; + time_t tv_sec_new; + long int tv_nsec_new; gettimeofday(&tv, NULL); - tv_sec_new = (long int)(tv.tv_sec + usec / 1000000); + tv_sec_new = (time_t)(tv.tv_sec + usec / 1000000); if (tv_sec_new >= tv.tv_sec) { ts->tv_sec = tv_sec_new; } else { /* integer overflow */ - ts->tv_sec = LONG_MAX; + ts->tv_sec = BH_TIME_T_MAX; os_printf("Warning: os_cond_reltimedwait exceeds limit, " "set to max timeout instead\n"); } @@ -211,7 +212,7 @@ static void msec_nsec_to_abstime(struct timespec *ts, uint64 usec) "set to max timeout instead\n"); } - if (ts->tv_nsec >= 1000000000L && ts->tv_sec < LONG_MAX) { + if (ts->tv_nsec >= 1000000000L && ts->tv_sec < BH_TIME_T_MAX) { ts->tv_sec++; ts->tv_nsec -= 1000000000L; } @@ -263,7 +264,9 @@ void os_thread_exit(void *retval) return pthread_exit(retval); } +#if defined(os_thread_local_attribute) static os_thread_local_attribute uint8 *thread_stack_boundary = NULL; +#endif uint8 *os_thread_get_stack_boundary() { @@ -276,8 +279,10 @@ uint8 *os_thread_get_stack_boundary() size_t stack_size, max_stack_size; int page_size; +#if defined(os_thread_local_attribute) if (thread_stack_boundary) return thread_stack_boundary; +#endif page_size = getpagesize(); self = pthread_self(); @@ -312,7 +317,9 @@ uint8 *os_thread_get_stack_boundary() } #endif +#if defined(os_thread_local_attribute) thread_stack_boundary = addr; +#endif return addr; } diff --git a/core/shared/platform/include/platform_common.h b/core/shared/platform/include/platform_common.h index 48bffe102..8a331d97c 100644 --- a/core/shared/platform/include/platform_common.h +++ b/core/shared/platform/include/platform_common.h @@ -33,6 +33,10 @@ extern "C" { #define BH_FREE os_free #endif +#ifndef BH_TIME_T_MAX +#define BH_TIME_T_MAX LONG_MAX +#endif + #if defined(_MSC_BUILD) #if defined(COMPILING_WASM_RUNTIME_API) __declspec(dllexport) void *BH_MALLOC(unsigned int size); diff --git a/core/shared/platform/nuttx/platform_internal.h b/core/shared/platform/nuttx/platform_internal.h index 77a18e8e9..2e476200f 100644 --- a/core/shared/platform/nuttx/platform_internal.h +++ b/core/shared/platform/nuttx/platform_internal.h @@ -40,6 +40,9 @@ typedef pthread_t korp_thread; #define os_printf printf #define os_vprintf vprintf +/* On NuttX, time_t is uint32_t */ +#define BH_TIME_T_MAX 0xffffffff + #ifdef __cplusplus } #endif diff --git a/product-mini/platforms/nuttx/wamr.mk b/product-mini/platforms/nuttx/wamr.mk index 9978553fe..8806d948e 100644 --- a/product-mini/platforms/nuttx/wamr.mk +++ b/product-mini/platforms/nuttx/wamr.mk @@ -23,7 +23,7 @@ WAMR_BUILD_TARGET := X86_64 endif ifeq ($(CONFIG_HOST_MACOS),y) # Note: invokeNative_em64.s needs BH_PLATFORM_DARWIN -CFLAGS += -DBH_PLATFORM_DARWIN +AFLAGS += -DBH_PLATFORM_DARWIN endif endif From af793385bfe797ee9b11b7e20b671d51012a3dcb Mon Sep 17 00:00:00 2001 From: Masayuki Ishikawa Date: Tue, 1 Jun 2021 15:23:20 +0900 Subject: [PATCH 199/207] product-mini/nuttx: Add support for ARMV7A (#643) Signed-off-by: Masayuki Ishikawa --- product-mini/platforms/nuttx/wamr.mk | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/product-mini/platforms/nuttx/wamr.mk b/product-mini/platforms/nuttx/wamr.mk index 8806d948e..4c71c5151 100644 --- a/product-mini/platforms/nuttx/wamr.mk +++ b/product-mini/platforms/nuttx/wamr.mk @@ -5,7 +5,9 @@ CORE_ROOT := wamr/core IWASM_ROOT := wamr/core/iwasm SHARED_ROOT := wamr/core/shared -ifeq ($(CONFIG_ARCH_ARMV7M),y) +ifeq ($(CONFIG_ARCH_ARMV7A),y) +WAMR_BUILD_TARGET := THUMBV7A +else ifeq ($(CONFIG_ARCH_ARMV7M),y) WAMR_BUILD_TARGET := THUMBV7EM else ifeq ($(CONFIG_ARCH_ARMV8M),y) WAMR_BUILD_TARGET := THUMBV8M From a5ffd656facddc3f0e413d598e2ab3ad5d1902f4 Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Tue, 1 Jun 2021 15:05:35 +0800 Subject: [PATCH 200/207] Fix wasm-c-api trap message format issue (#644) And fix two compile warnings. --- core/iwasm/aot/aot_runtime.c | 2 +- core/iwasm/common/wasm_runtime_common.c | 2 +- core/shared/platform/windows/win_thread.c | 2 +- samples/wasm-c-api/src/trap.c | 4 +++- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index bc0961def..dd05c94cb 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -2300,7 +2300,7 @@ invoke_wasm_c_api_native(AOTModuleInstance *module_inst, void *func_ptr, } if (trap) { if (trap->message->data) { - snprintf(fmt, sizeof(fmt), "%%%us", (uint32)trap->message->size); + snprintf(fmt, sizeof(fmt), "%%.%us", (uint32)trap->message->size); snprintf(module_inst->cur_exception, sizeof(module_inst->cur_exception), fmt, trap->message->data); diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index 1999dacb5..91ae8457f 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -835,7 +835,7 @@ wasm_runtime_destroy_thread_env() { #if WASM_ENABLE_AOT != 0 #ifdef OS_ENABLE_HW_BOUND_CHECK - return aot_signal_destroy(); + aot_signal_destroy(); #endif #endif } diff --git a/core/shared/platform/windows/win_thread.c b/core/shared/platform/windows/win_thread.c index 86dc9fa31..221214bdf 100644 --- a/core/shared/platform/windows/win_thread.c +++ b/core/shared/platform/windows/win_thread.c @@ -141,7 +141,7 @@ os_thread_cleanup(void *retval) BH_FREE(thread_data); } -static unsigned +static unsigned __stdcall os_thread_wrapper(void *arg) { os_thread_data *thread_data = arg; diff --git a/samples/wasm-c-api/src/trap.c b/samples/wasm-c-api/src/trap.c index 3074df93f..2829dd2e5 100644 --- a/samples/wasm-c-api/src/trap.c +++ b/samples/wasm-c-api/src/trap.c @@ -92,6 +92,7 @@ int main(int argc, const char* argv[]) { // Call. for (int i = 0; i < 2; ++i) { + char buf[32]; const wasm_func_t* func = wasm_extern_as_func(exports.data[i]); if (func == NULL) { printf("> Error accessing export!\n"); @@ -109,7 +110,8 @@ int main(int argc, const char* argv[]) { printf("Printing message...\n"); own wasm_name_t message; wasm_trap_message(trap, &message); - printf("> %s\n", message.data); + snprintf(buf, sizeof(buf), "> %%.%us\n", (unsigned)message.size); + printf(buf, message.data); wasm_trap_delete(trap); wasm_name_delete(&message); From 5d9597f06479023fe73ba6539352d2f788b962db Mon Sep 17 00:00:00 2001 From: Huang Qi <757509347@qq.com> Date: Mon, 7 Jun 2021 15:37:09 +0800 Subject: [PATCH 201/207] platform/nuttx: Support riscv based chips (#648) Signed-off-by: Huang Qi --- .../shared/platform/nuttx/platform_internal.h | 1 + product-mini/platforms/nuttx/wamr.mk | 34 ++++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/core/shared/platform/nuttx/platform_internal.h b/core/shared/platform/nuttx/platform_internal.h index 2e476200f..14e44ad4e 100644 --- a/core/shared/platform/nuttx/platform_internal.h +++ b/core/shared/platform/nuttx/platform_internal.h @@ -6,6 +6,7 @@ #ifndef _PLATFORM_INTERNAL_H #define _PLATFORM_INTERNAL_H +#include #include #include #include diff --git a/product-mini/platforms/nuttx/wamr.mk b/product-mini/platforms/nuttx/wamr.mk index 4c71c5151..03de0c7cb 100644 --- a/product-mini/platforms/nuttx/wamr.mk +++ b/product-mini/platforms/nuttx/wamr.mk @@ -17,6 +17,10 @@ else ifeq ($(CONFIG_ARCH_X86_64),y) WAMR_BUILD_TARGET := X86_64 else ifeq ($(CONFIG_ARCH_XTENSA),y) WAMR_BUILD_TARGET := XTENSA +else ifeq ($(CONFIG_ARCH_RV64GC),y) +WAMR_BUILD_TARGET := RISCV64 +else ifeq ($(CONFIG_ARCH_RV32IM),y) +WAMR_BUILD_TARGET := RISCV32 else ifeq ($(CONFIG_ARCH_SIM),y) ifeq ($(CONFIG_SIM_M32),y) WAMR_BUILD_TARGET := X86_32 @@ -62,8 +66,36 @@ else ifeq (${WAMR_BUILD_TARGET}, XTENSA) CFLAGS += -DBUILD_TARGET_XTENSA INVOKE_NATIVE := invokeNative_xtensa.s AOT_RELOC := aot_reloc_xtensa.c +else ifeq (${WAMR_BUILD_TARGET}, RISCV64) + +ifeq (${CONFIG_ARCH_FPU},y) + $(error riscv64 lp64f is unsupported) +else ifeq (${CONFIG_ARCH_DPFPU}, y) + CFLAGS += -DBUILD_TARGET_RISCV64_LP64D + INVOKE_NATIVE += invokeNative_riscv64_lp64d.s else - $(error Build target don't support) + CFLAGS += -DBUILD_TARGET_RISCV64_LP64 + INVOKE_NATIVE += invokeNative_riscv64_lp64.s +endif + + AOT_RELOC := + +else ifeq (${WAMR_BUILD_TARGET}, RISCV32) + +ifeq (${CONFIG_ARCH_FPU}, y) + $(error riscv32 ilp32f is unsupported) +else ifeq (${CONFIG_ARCH_DPFPU}, y) + CFLAGS += -DBUILD_TARGET_RISCV64_ILP32D + INVOKE_NATIVE += invokeNative_riscv32_ilp32d.s +else + CFLAGS += -DBUILD_TARGET_RISCV64_ILP32 + INVOKE_NATIVE += invokeNative_riscv32_ilp32.s +endif + + AOT_RELOC := + +else + $(error Build target is unsupported) endif ifeq (${CONFIG_INTERPRETERS_WAMR_LOG},y) From 1a4aa5ac2f659439a344c0ec7163b157c0e190ce Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Mon, 14 Jun 2021 08:58:32 +0800 Subject: [PATCH 202/207] Enable multi-thread for tensorflow sample, update wasm-c-api document (#651) --- .../lib-pthread/lib_pthread_wrapper.c | 33 ++++-- .../libraries/thread-mgr/thread_manager.c | 7 +- doc/pthread_library.md | 12 ++ doc/wasm_c_api.md | 110 +++++++++--------- samples/workload/tensorflow/README.md | 4 +- samples/workload/tensorflow/build.sh | 14 ++- samples/workload/tensorflow/tf_lite.patch | 8 +- 7 files changed, 115 insertions(+), 73 deletions(-) diff --git a/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c b/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c index 95634834f..0eaed87bc 100644 --- a/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c +++ b/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c @@ -542,24 +542,24 @@ pthread_create_wrapper(wasm_exec_env_t exec_env, uint32 thread_handle; int32 ret = -1; #if WASM_ENABLE_LIBC_WASI != 0 - WASIContext *wasi_ctx = get_wasi_ctx(module_inst); + WASIContext *wasi_ctx; #endif bh_assert(module); + bh_assert(module_inst); if (!(new_module_inst = wasm_runtime_instantiate_internal(module, true, 8192, 0, NULL, 0))) return -1; - if (module_inst) { - /* Set custom_data to new module instance */ - wasm_runtime_set_custom_data_internal( - new_module_inst, - wasm_runtime_get_custom_data(module_inst)); - } + /* Set custom_data to new module instance */ + wasm_runtime_set_custom_data_internal( + new_module_inst, + wasm_runtime_get_custom_data(module_inst)); #if WASM_ENABLE_LIBC_WASI != 0 + wasi_ctx = get_wasi_ctx(module_inst); if (wasi_ctx) wasm_runtime_set_wasi_ctx(new_module_inst, wasi_ctx); #endif @@ -628,7 +628,7 @@ pthread_join_wrapper(wasm_exec_env_t exec_env, uint32 thread, /* validate addr, we can use current thread's module instance here as the memory is shared */ - if (!validate_app_addr(retval_offset, sizeof(void *))) { + if (!validate_app_addr(retval_offset, sizeof(int32))) { /* Join failed, but we don't want to terminate all threads, do not spread exception here */ wasm_runtime_set_exception(module_inst, NULL); @@ -1046,6 +1046,22 @@ pthread_key_delete_wrapper(wasm_exec_env_t exec_env, int32 key) return 0; } +/* Currently the memory allocator doesn't support alloc specific aligned + space, we wrap posix_memalign to simply malloc memory */ +static int32 +posix_memalign_wrapper(wasm_exec_env_t exec_env, + void **memptr, int32 align, int32 size) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + void *p = NULL; + + *((int32 *)memptr) = module_malloc(size, (void**)&p); + if (!p) + return -1; + + return 0; +} + #define REG_NATIVE_FUNC(func_name, signature) \ { #func_name, func_name##_wrapper, signature, NULL } @@ -1069,6 +1085,7 @@ static NativeSymbol native_symbols_lib_pthread[] = { REG_NATIVE_FUNC(pthread_setspecific, "(ii)i"), REG_NATIVE_FUNC(pthread_getspecific, "(i)i"), REG_NATIVE_FUNC(pthread_key_delete, "(i)i"), + REG_NATIVE_FUNC(posix_memalign, "(*ii)i"), }; uint32 diff --git a/core/iwasm/libraries/thread-mgr/thread_manager.c b/core/iwasm/libraries/thread-mgr/thread_manager.c index 59330a847..4ee917a8f 100644 --- a/core/iwasm/libraries/thread-mgr/thread_manager.c +++ b/core/iwasm/libraries/thread-mgr/thread_manager.c @@ -659,6 +659,7 @@ void wasm_cluster_spread_exception(WASMExecEnv *exec_env) { WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env); + bh_assert(cluster); traverse_list(&cluster->exec_env_list, set_exception_visitor, exec_env); } @@ -677,7 +678,11 @@ wasm_cluster_spread_custom_data(WASMModuleInstanceCommon *module_inst, void *custom_data) { WASMExecEnv *exec_env = wasm_clusters_search_exec_env(module_inst); - WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env); + WASMCluster *cluster = NULL; + bh_assert(exec_env); + + cluster = wasm_exec_env_get_cluster(exec_env); + bh_assert(cluster); traverse_list(&cluster->exec_env_list, set_custom_data_visitor, diff --git a/doc/pthread_library.md b/doc/pthread_library.md index 882bb59de..b1de6b10f 100644 --- a/doc/pthread_library.md +++ b/doc/pthread_library.md @@ -78,6 +78,18 @@ Then build the program with this command: # -Wl,--no-check-features: the errno.o in wasi-sysroot is not compatible with pthread feature, pass this option to avoid errors ``` +**Build with EMCC** + +EMCC's `-pthread` option is not compatible with standalone mode, we need to pass `-mbulk-memory -matomics` to the compiler and `--shared-memory,--no-check-features` to linker manually + +``` bash +emcc -O3 -mbulk-memory -matomics -s MALLOC="none" \ + -Wl,--export=__data_end,--export=__heap_base \ + -Wl,--shared-memory,--no-check-features \ + -s ERROR_ON_UNDEFINED_SYMBOLS=0 \ + main.c -o test.wasm +``` + **Build AoT module** You can build the wasm module into AoT module with pthread support, please pass option `--enable-multi-thread` to wamrc: diff --git a/doc/wasm_c_api.md b/doc/wasm_c_api.md index 6d2278743..a23096e55 100644 --- a/doc/wasm_c_api.md +++ b/doc/wasm_c_api.md @@ -7,71 +7,69 @@ Every user should be familiar with *APIs* listed in all [examples][https://github.com/WebAssembly/wasm-c-api/tree/master/example] are very helpful for learning. -Currently, we support partial of *APIs* and are going to support the rest of +Currently, we support partial of APIs and are going to support the rest of them in next releases. -Supported APIs: +a summary of unsupported APIs + +- Configuration ``` c -/* wasm_bytevec_t APIs ... */ - -wasm_engine_t *wasm_engine_new(); -wasm_engine_t *wasm_engine_new_with_args(mem_alloc_type_t, const MemAllocOption*, runtime_mode_e); -void wasm_engine_delete(wasm_engine_t *); - -wasm_store_t *wasm_store_new(wasm_engine_t *); -void wasm_store_delete(wasm_store_t *); - -/* wasm_valtype_t APIs ... */ -/* wasm_valtype_vec_t APIs ... */ -/* wasm_functype_vec_t APIs ... */ -/* wasm_globaltype_vec_t APIs ... */ -/* wasm_val_t APIs ... */ -/* wasm_trap_t partial APIs ... */ - -wasm_module_t *wasm_module_new(wasm_store_t *, const wasm_byte_vec_t *); -void wasm_module_delete(wasm_module_t *); - -wasm_func_t *wasm_func_new(wasm_store_t *, const wasm_functype_t *, wasm_func_callback_t); -wasm_func_t *wasm_func_new_with_env(wasm_store_t *store, const wasm_functype_t *, wasm_func_callback_with_env_t, void *env, void (*finalizer)(void *)); -void wasm_func_delete(wasm_func_t *); -wasm_fucn_t *wasm_func_copy(const wasm_func_t *); -wasm_functype_t *wasm_func_type(const wasm_func_t *); -wasm_trap_t * wasm_func_call(const wasm_func_t *, const wasm_val_t params[], wasm_val_t results[]); -size_t wasm_func_param_arity(const wasm_func_t *); -size_t wasm_func_result_arity(const wasm_func_t *); - -wasm_global_t *wasm_global_new(wasm_store_t *, const wasm_globaltype_t *, const wasm_val_t *); -wasm_global_t * wasm_global_copy(const wasm_global_t *); -void wasm_global_delete(wasm_global_t *); -bool wasm_global_same(const wasm_global_t *, const wasm_global_t *); -void wasm_global_set(wasm_global_t *, const wasm_val_t *); -void wasm_global_get(const wasm_global_t *, wasm_val_t *out); -wasm_globaltype_t * wasm_global_type(const wasm_global_t *); - -wasm_instance_t *wasm_instance_new(wasm_store_t *, const wasm_module_t *, const wasm_extern_t *const imports[], wasm_trap_t **traps); -void wasm_instance_delete(wasm_instance_t *); -void wasm_instance_exports(const wasm_instance_t *, wasm_extern_vec_t *out); - -/* wasm_extern_t APIs */ +WASM_API_EXTERN own wasm_config_t* wasm_config_new(void); ``` -Unsupported APIs: +- References ``` c -/* wasm_tabletype_t APIs */ -/* wasm_memorytype_t APIs */ -/* wasm_externtype_t APIs */ -/* wasm_importtype_t APIs */ -/* wasm_exporttype_t APIs */ -/* wasm_ref_t APIs */ -/* wasm_shared_##name##_t APIs */ +WASM_API_EXTERN bool wasm_##name##_same(const wasm_##name##_t*, const wasm_##name##_t*); \ +WASM_API_EXTERN void* wasm_##name##_get_host_info(const wasm_##name##_t*); \ +WASM_API_EXTERN void wasm_##name##_set_host_info(wasm_##name##_t*, void*); \ +WASM_API_EXTERN void wasm_##name##_set_host_info_with_finalizer( \ +WASM_API_EXTERN wasm_ref_t* wasm_##name##_as_ref(wasm_##name##_t*); \ +WASM_API_EXTERN wasm_##name##_t* wasm_ref_as_##name(wasm_ref_t*); \ +WASM_API_EXTERN const wasm_ref_t* wasm_##name##_as_ref_const(const wasm_##name##_t*); \ +WASM_API_EXTERN const wasm_##name##_t* wasm_ref_as_##name##_const(const wasm_ref_t*); +WASM_API_EXTERN own wasm_shared_##name##_t* wasm_##name##_share(const wasm_##name##_t*); \ +WASM_API_EXTERN own wasm_##name##_t* wasm_##name##_obtain(wasm_store_t*, const wasm_shared_##name##_t*); +``` +- Frames + +``` c +WASM_API_EXTERN own wasm_frame_t* wasm_frame_copy(const wasm_frame_t*); +WASM_API_EXTERN struct wasm_instance_t* wasm_frame_instance(const wasm_frame_t*); +WASM_API_EXTERN uint32_t wasm_frame_func_index(const wasm_frame_t*); +WASM_API_EXTERN size_t wasm_frame_func_offset(const wasm_frame_t*); +WASM_API_EXTERN size_t wasm_frame_module_offset(const wasm_frame_t*); +WASM_API_EXTERN own wasm_frame_t* wasm_trap_origin(const wasm_trap_t*); +WASM_API_EXTERN void wasm_trap_trace(const wasm_trap_t*, own wasm_frame_vec_t* out); +``` + + Foreign Objects + +``` c +WASM_API_EXTERN own wasm_foreign_t* wasm_foreign_new(wasm_store_t*); +``` + +- Several Module APIs + +``` c WASM_API_EXTERN bool wasm_module_validate(wasm_store_t*, const wasm_byte_vec_t* binary); -WASM_API_EXTERN void wasm_module_imports(const wasm_module_t*, own wasm_importtype_vec_t* out); WASM_API_EXTERN void wasm_module_serialize(const wasm_module_t*, own wasm_byte_vec_t* out); -WASM_API_EXTERN own wasm_module_t* wasm_module_deserialize(wasm_store_t*, const wasm_byte_vec_t*); - -/* wasm_table_t APIs */ -/* wasm_memory_t APIs */ +WASM_API_EXTERN void wasm_module_serialize(const wasm_module_t*, own wasm_byte_vec_t* out); ``` + +- Table Operations APIs + +``` c +WASM_API_EXTERN own wasm_ref_t* wasm_table_get(const wasm_table_t*, wasm_table_size_t index); +WASM_API_EXTERN bool wasm_table_set(wasm_table_t*, wasm_table_size_t index, wasm_ref_t*); +WASM_API_EXTERN wasm_table_size_t wasm_table_size(const wasm_table_t*); +WASM_API_EXTERN bool wasm_table_grow(wasm_table_t*, wasm_table_size_t delta, wasm_ref_t* init); +``` + +- Memory Grow APIs + +``` c +WASM_API_EXTERN bool wasm_memory_grow(wasm_memory_t*, wasm_memory_pages_t delta); +``` \ No newline at end of file diff --git a/samples/workload/tensorflow/README.md b/samples/workload/tensorflow/README.md index 11fa28b8b..2aca871ad 100644 --- a/samples/workload/tensorflow/README.md +++ b/samples/workload/tensorflow/README.md @@ -17,7 +17,9 @@ Then run ./build.sh # for linux platform, or ./build.sh --sgx -# for linux-sgx platform +# for linux-sgx platform or +./build.sh --threads +# for multi-thread execution (on linux platform) ``` to build tensorflow and run it with iwasm, which basically contains the following steps: - hack emcc to delete some objects in libc.a diff --git a/samples/workload/tensorflow/build.sh b/samples/workload/tensorflow/build.sh index 80d2540d5..f3e686b71 100755 --- a/samples/workload/tensorflow/build.sh +++ b/samples/workload/tensorflow/build.sh @@ -1,10 +1,10 @@ +#!/bin/bash + # # Copyright (C) 2019 Intel Corporation. All rights reserved. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception # -#!/bin/bash - #################################### # build tensorflow-lite sample # #################################### @@ -99,6 +99,8 @@ WAMRC_CMD="$(pwd)/wamrc" cd ${OUT_DIR} if [[ $1 == '--sgx' ]]; then ${WAMRC_CMD} --enable-simd -sgx -o benchmark_model.aot benchmark_model.wasm +elif [[ $1 == '--threads' ]]; then + ${WAMRC_CMD} --enable-simd --enable-multi-thread -o benchmark_model.aot benchmark_model.wasm else ${WAMRC_CMD} --enable-simd -o benchmark_model.aot benchmark_model.wasm fi @@ -137,7 +139,13 @@ else IWASM_CMD="${WAMR_PLATFORM_DIR}/linux/build/iwasm" fi -${IWASM_CMD} --heap-size=10475860 \ +if [[ $1 == '--threads' ]]; then + ${IWASM_CMD} --heap-size=10475860 \ + ${OUT_DIR}/benchmark_model.aot --num_threads=4 \ + --graph=mobilenet_quant_v1_224.tflite --max_secs=300 +else + ${IWASM_CMD} --heap-size=10475860 \ ${OUT_DIR}/benchmark_model.aot \ --graph=mobilenet_quant_v1_224.tflite --max_secs=300 +fi diff --git a/samples/workload/tensorflow/tf_lite.patch b/samples/workload/tensorflow/tf_lite.patch index 4d510b1be..b6224d581 100644 --- a/samples/workload/tensorflow/tf_lite.patch +++ b/samples/workload/tensorflow/tf_lite.patch @@ -19,14 +19,14 @@ index c7ddff58440..ebfebaead35 100644 endif # ifeq ($(HOST_OS),$(TARGET)) endif -+CFLAGS+=-msimd128 -+CXXFLAGS+=-msimd128 ++CFLAGS+=-msimd128 -mbulk-memory -matomics ++CXXFLAGS+=-msimd128 -mbulk-memory -matomics + -+LIBFLAGS += -s TOTAL_STACK=1048576 \ ++LIBFLAGS += -s TOTAL_STACK=1048576 -s MALLOC="none" \ + -s INITIAL_MEMORY=16777216 \ + -s MAXIMUM_MEMORY=167772160 \ + -s ALLOW_MEMORY_GROWTH=1 \ -+ -Wl,--export=__data_end -Wl,--export=__heap_base \ ++ -Wl,--export=__data_end -Wl,--export=__heap_base,--shared-memory,--no-check-features \ + -s ERROR_ON_UNDEFINED_SYMBOLS=0 + # This library is the main target for this makefile. It will contain a minimal From 77c71e559aa40298e7b9f9a09e1319c31a9cfaca Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Wed, 16 Jun 2021 15:26:28 +0800 Subject: [PATCH 203/207] Add wasm-c-api nested function calls sample (#652) And enable to copy back the return value of wasm main function when calling wasm_application_execute_main, add license headers in wasm-c-api samples, fix several issues reported by klocwork. --- core/iwasm/common/wasm_application.c | 6 +- core/iwasm/include/wasm_export.h | 4 +- samples/spawn-thread/src/main.c | 20 +- samples/wasm-c-api/CMakeLists.txt | 3 +- samples/wasm-c-api/src/callback.c | 1 + samples/wasm-c-api/src/callback_chain.c | 267 ++++++++++++++++++ samples/wasm-c-api/src/callback_chain.wat | 32 +++ samples/wasm-c-api/src/global.c | 1 + .../wasm-c-api/src/globalexportimport-0.wat | 3 + .../wasm-c-api/src/globalexportimport-1.wat | 3 + samples/wasm-c-api/src/globalexportimport.c | 6 + samples/wasm-c-api/src/hello.c | 1 + samples/wasm-c-api/src/multi.c | 1 + samples/wasm-c-api/src/reflect.c | 17 ++ samples/wasm-c-api/src/trap.c | 1 + 15 files changed, 357 insertions(+), 9 deletions(-) create mode 100644 samples/wasm-c-api/src/callback_chain.c create mode 100644 samples/wasm-c-api/src/callback_chain.wat diff --git a/core/iwasm/common/wasm_application.c b/core/iwasm/common/wasm_application.c index 01ae4f9a7..b3e979fc9 100644 --- a/core/iwasm/common/wasm_application.c +++ b/core/iwasm/common/wasm_application.c @@ -182,6 +182,10 @@ wasm_application_execute_main(WASMModuleInstanceCommon *module_inst, ret = wasm_runtime_create_exec_env_and_call_wasm(module_inst, func, argc1, argv1); + if (ret && func_type->result_count > 0 && argc > 0 && argv) + /* copy the return value */ + *(int*)argv = (int)argv1[0]; + if (argv_buf_offset) wasm_runtime_module_free(module_inst, argv_buf_offset); return ret; @@ -669,4 +673,4 @@ fail: bh_assert(exception); os_printf("%s\n", exception); return false; -} \ No newline at end of file +} diff --git a/core/iwasm/include/wasm_export.h b/core/iwasm/include/wasm_export.h index b56e7b14d..a4394adb0 100644 --- a/core/iwasm/include/wasm_export.h +++ b/core/iwasm/include/wasm_export.h @@ -495,7 +495,9 @@ wasm_runtime_call_wasm_v(wasm_exec_env_t exec_env, * * @param module_inst the WASM module instance * @param argc the number of arguments - * @param argv the arguments array + * @param argv the arguments array, if the main function has return value, + * *(int*)argv stores the return value of the called main function after + * this function returns. * * @return true if the main function is called, false otherwise and exception * will be thrown, the caller can call wasm_runtime_get_exception to get diff --git a/samples/spawn-thread/src/main.c b/samples/spawn-thread/src/main.c index c1d150508..6df1042d4 100644 --- a/samples/spawn-thread/src/main.c +++ b/samples/spawn-thread/src/main.c @@ -26,6 +26,7 @@ void *thread(void* arg) func = wasm_runtime_lookup_function(module_inst, "sum", NULL); if (!func) { printf("failed to lookup function sum"); + return NULL; } argv[0] = thread_arg->start; argv[1] = thread_arg->length; @@ -49,6 +50,7 @@ void *wamr_thread_cb(wasm_exec_env_t exec_env, void *arg) func = wasm_runtime_lookup_function(module_inst, "sum", NULL); if (!func) { printf("failed to lookup function sum"); + return NULL; } argv[0] = thread_arg->start; argv[1] = thread_arg->length; @@ -66,7 +68,7 @@ int main(int argc, char *argv[]) { char *wasm_file = "wasm-apps/test.wasm"; uint8 *wasm_file_buf = NULL; - uint32 wasm_file_size, wasm_argv[2], i; + uint32 wasm_file_size, wasm_argv[2], i, threads_created; uint32 stack_size = 16 * 1024, heap_size = 16 * 1024; wasm_module_t wasm_module = NULL; wasm_module_inst_t wasm_module_inst = NULL; @@ -123,6 +125,7 @@ int main(int argc, char *argv[]) func = wasm_runtime_lookup_function(wasm_module_inst, "sum", NULL); if (!func) { printf("failed to lookup function sum"); + goto fail5; } wasm_argv[0] = 0; wasm_argv[1] = THREAD_NUM * 10; @@ -159,17 +162,20 @@ int main(int argc, char *argv[]) if (0 != pthread_create(&tid[i], NULL, thread, &thread_arg[i])) { printf("failed to create thread.\n"); + wasm_runtime_destroy_spawned_exec_env(new_exec_env); break; } } + threads_created = i; + sum = 0; memset(result, 0, sizeof(uint32) * THREAD_NUM); - for (i = 0; i < THREAD_NUM; i++) { + for (i = 0; i < threads_created; i++) { pthread_join(tid[i], (void **)&result[i]); sum += result[i]; /* destroy the spawned exec_env */ - if (thread_arg[0].exec_env) + if (thread_arg[i].exec_env) wasm_runtime_destroy_spawned_exec_env(thread_arg[i].exec_env); } @@ -191,15 +197,18 @@ int main(int argc, char *argv[]) } } + threads_created = i; + sum = 0; memset(result, 0, sizeof(uint32) * THREAD_NUM); - for (i = 0; i < THREAD_NUM; i++) { + for (i = 0; i < threads_created; i++) { wasm_runtime_join_thread(wasm_tid[i], (void**)&result[i]); sum += result[i]; /* No need to destroy the spawned exec_env */ } printf("[spwan_thread]sum result: %d\n", sum); +fail5: wasm_runtime_destroy_exec_env(exec_env); fail4: @@ -217,4 +226,5 @@ fail2: fail1: /* destroy runtime environment */ wasm_runtime_destroy(); -} \ No newline at end of file + return 0; +} diff --git a/samples/wasm-c-api/CMakeLists.txt b/samples/wasm-c-api/CMakeLists.txt index fa5094735..75dd80534 100644 --- a/samples/wasm-c-api/CMakeLists.txt +++ b/samples/wasm-c-api/CMakeLists.txt @@ -93,8 +93,7 @@ set(EXAMPLES global reflect trap - # multi # AOT/JIT return multiple values - # globalexportimport # AOT/JIT doesn't suppport MULTI_MODULE + callback_chain ) foreach(EX ${EXAMPLES}) diff --git a/samples/wasm-c-api/src/callback.c b/samples/wasm-c-api/src/callback.c index bd8d17ec0..e350edc64 100644 --- a/samples/wasm-c-api/src/callback.c +++ b/samples/wasm-c-api/src/callback.c @@ -84,6 +84,7 @@ int main(int argc, const char* argv[]) { wasm_byte_vec_new_uninitialized(&binary, file_size); if (fread(binary.data, file_size, 1, file) != 1) { printf("> Error loading module!\n"); + fclose(file); return 1; } fclose(file); diff --git a/samples/wasm-c-api/src/callback_chain.c b/samples/wasm-c-api/src/callback_chain.c new file mode 100644 index 000000000..d6f933ac4 --- /dev/null +++ b/samples/wasm-c-api/src/callback_chain.c @@ -0,0 +1,267 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include +#include +#include +#include + +#include "wasm_c_api.h" + +#define own + +static const byte_t * +get_memory_data(uint32_t offset, uint32_t length); + +static bool +call_wasm_function(uint32_t export_id, + const wasm_val_t *args, + wasm_val_t *results, + const char *name); + +/************************ IMPORTED FUNCTIONS **************************/ + +// (nil) -> i32 +#define FUNCTION_TYPE_NIL_I32 wasm_functype_new_0_1(wasm_valtype_new_i32()) +// (i32, i32) -> nil +#define FUNCTION_TYPE_I32X2_NIL \ + wasm_functype_new_1_1(wasm_valtype_new_i32(), wasm_valtype_new_i32()) + +/* IMPORT FUNCTION LIST */ +#define IMPORT_FUNCTION_LIST(V) \ + V(get_pairs, 0, FUNCTION_TYPE_NIL_I32) \ + V(log, 1, FUNCTION_TYPE_I32X2_NIL) + +/* EXPORT FUNCTION LIST */ +#define EXPORT_FUNCTION_LIST(V) \ + V(on_start) \ + V(on_stop) \ + V(malloc) \ + V(free) + +enum EXPORT_ITEM_NAME { +#define DEFINE_ENUM(name) e_##name, + EXPORT_FUNCTION_LIST(DEFINE_ENUM) +#undef DEFINE_ENUM + e_MEMORY, +}; + +#define DEFINE_FUNCTION(name) \ + wasm_trap_t *STUB_##name(const wasm_val_t args[], wasm_val_t results[]) + +#define DEFINE_EMPTY_FUNCTION(name) \ + DEFINE_FUNCTION(name) \ + { \ + printf("[WASM -> NATIVE] calling back %s\n", __FUNCTION__); \ + return NULL; \ + } +#undef DEFINE_EMPTY_FUNCTION + +DEFINE_FUNCTION(get_pairs) +{ + wasm_val_t ret[1] = { WASM_INIT_VAL }; + call_wasm_function(e_malloc, (wasm_val_t[]){ WASM_I32_VAL(24) }, ret, + "malloc"); + return NULL; +} + +DEFINE_FUNCTION(log) +{ + wasm_val_t offset = args[0]; + wasm_val_t length = args[1]; + const byte_t *data = NULL; + + printf("[WASM -> NATIVE] calling back %s\n", __FUNCTION__); + + if (offset.kind != WASM_I32 || length.kind != WASM_I32) { + printf("> Error value type!\n"); + } + + if (!(data = get_memory_data(offset.of.i32, length.of.i32))) { + return NULL; + } + + if (data[length.of.i32]) { + printf("> Error terminated character\n"); + return NULL; + } + + printf("[WASM_LOG] %s\n", data); + return NULL; +} + +static inline void +create_import_function_list(wasm_store_t *store, + const wasm_extern_t *import_function_list[]) +{ +#define IMPORT_FUNCTION_VARIABLE_NAME(name, ...) \ + own wasm_func_t *function_##name = NULL; + IMPORT_FUNCTION_LIST(IMPORT_FUNCTION_VARIABLE_NAME) +#undef IMPORT_FUNCTION_VARIABLE_NAME + +#define CREATE_WASM_FUNCTION(name, index, CREATE_FUNC_TYPE) \ + { \ + own wasm_functype_t *type = CREATE_FUNC_TYPE; \ + if (!(function_##name = wasm_func_new(store, type, STUB_##name))) { \ + printf("> Error creating new function\n"); \ + } \ + wasm_functype_delete(type); \ + } + IMPORT_FUNCTION_LIST(CREATE_WASM_FUNCTION) +#undef CREATE_WASM_FUNCTION + +#define ADD_TO_FUNCTION_LIST(name, index, ...) \ + import_function_list[index] = wasm_func_as_extern(function_##name); + IMPORT_FUNCTION_LIST(ADD_TO_FUNCTION_LIST) +#undef CREATE_IMPORT_FUNCTION +} + +/**********************************************************************/ +// all exportted wasm functions. check with "/opt/wabt/bin/wasm-objdump -x -j Export X.wasm" +// -1: memory +// 0-32: functions +static own wasm_extern_vec_t exports = { 0 }; + +static const byte_t * +get_memory_data(uint32_t offset, uint32_t length) +{ + wasm_memory_t *memory; + + if (!(memory = wasm_extern_as_memory(exports.data[e_MEMORY]))) { + return NULL; + } + + byte_t *base = wasm_memory_data(memory); + size_t size = wasm_memory_data_size(memory); + if (!base || offset + length > size) { + return NULL; + } + + printf("[NATIVE -> WASM] accessing the memory...\n"); + + return base + offset; +} + +static bool +call_wasm_function(uint32_t export_id, + const wasm_val_t *args, + wasm_val_t *results, + const char *name) +{ + const wasm_func_t *function; + wasm_trap_t *trap; + + printf("[NATIVE -> WASM] calling func %s...\n", name); + + if (!(function = wasm_extern_as_func(exports.data[export_id]))) { + printf("> Error get export function %u\n", export_id); + return false; + } + + if ((trap = wasm_func_call(function, args, results))) { + own wasm_message_t message = { 0 }; + wasm_trap_message(trap, &message); + + if (message.data) { + printf("> Error calling function %s\n", message.data); + } + else { + printf("> Error calling function"); + } + + wasm_name_delete(&message); + wasm_trap_delete(trap); + return false; + } + return true; +} + +int +main(int argc, const char *argv[]) +{ + // Initialize. + printf("Initializing...\n"); + wasm_engine_t *engine = wasm_engine_new(); + wasm_store_t *store = wasm_store_new(engine); + + // Load binary. + printf("Loading binary...\n"); + FILE *file = fopen("callback_chain.wasm", "rb"); + if (!file) { + printf("> Error loading module!\n"); + return 1; + } + fseek(file, 0L, SEEK_END); + size_t file_size = ftell(file); + fseek(file, 0L, SEEK_SET); + wasm_byte_vec_t binary; + wasm_byte_vec_new_uninitialized(&binary, file_size); + if (fread(binary.data, file_size, 1, file) != 1) { + printf("> Error loading module!\n"); + fclose(file); + return 1; + } + fclose(file); + + // Compile. + printf("Compiling module...\n"); + own wasm_module_t *module = wasm_module_new(store, &binary); + if (!module) { + printf("> Error compiling module!\n"); + return 1; + } + + wasm_byte_vec_delete(&binary); + + // Instantiate. + printf("Instantiating module...\n"); + const wasm_extern_t *imports[10] = { 0 }; + + // Create external functions. + printf("Creating callback...\n"); + create_import_function_list(store, imports); + + own wasm_instance_t *instance = + wasm_instance_new(store, module, imports, NULL); + if (!instance) { + printf("> Error instantiating module!\n"); + return 1; + } + + // Extract export. + printf("Extracting export...\n"); + wasm_instance_exports(instance, &exports); + if (!exports.size) { + printf("> Error accessing exports!\n"); + return 1; + } + + wasm_module_delete(module); + wasm_instance_delete(instance); + + // Call. + printf("Calling export...\n"); + + if (!call_wasm_function(e_on_start, NULL, NULL, "on_start")) { + printf("> Error calling on_start\n"); + return 1; + } + + if (!call_wasm_function(e_on_stop, NULL, NULL, "on_stop")) { + printf("> Error calling on_stop\n"); + return 1; + } + + wasm_extern_vec_delete(&exports); + + // Shut down. + printf("Shutting down...\n"); + wasm_store_delete(store); + wasm_engine_delete(engine); + + // All done. + printf("Done.\n"); + return 0; +} diff --git a/samples/wasm-c-api/src/callback_chain.wat b/samples/wasm-c-api/src/callback_chain.wat new file mode 100644 index 000000000..b29cf8a4e --- /dev/null +++ b/samples/wasm-c-api/src/callback_chain.wat @@ -0,0 +1,32 @@ +;; Copyright (C) 2019 Intel Corporation. All rights reserved. +;; SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +(module + (func $get_pairs (import "" "get_pairs") (result i32)) + (func $log (import"" "log") (param i32 i32)) + + (func $on_start (export "on_start") + (call $log (i32.const 0) (i32.const 9)) + (call $get_pairs) + (drop) + ) + + (func $on_stop (export "on_stop") + (call $log (i32.const 9) (i32.const 8)) + ) + + (func $malloc (export "malloc") (param i32) (result i32) + (call $log (i32.const 17) (i32.const 7)) + (i32.const 64) + ) + + (func $free(export "free") (param i32) + (call $log (i32.const 24) (i32.const 5)) + ) + + (memory (export "memory") 1) + (data (i32.const 0) "on_start") + (data (i32.const 9) "on_stop") + (data (i32.const 17) "malloc") + (data (i32.const 24) "free") +) \ No newline at end of file diff --git a/samples/wasm-c-api/src/global.c b/samples/wasm-c-api/src/global.c index b1747d680..5a3b3f4ce 100644 --- a/samples/wasm-c-api/src/global.c +++ b/samples/wasm-c-api/src/global.c @@ -69,6 +69,7 @@ int main(int argc, const char* argv[]) { wasm_byte_vec_new_uninitialized(&binary, file_size); if (fread(binary.data, file_size, 1, file) != 1) { printf("> Error loading module!\n"); + fclose(file); return 1; } fclose(file); diff --git a/samples/wasm-c-api/src/globalexportimport-0.wat b/samples/wasm-c-api/src/globalexportimport-0.wat index a3f072cf3..7ab897c73 100644 --- a/samples/wasm-c-api/src/globalexportimport-0.wat +++ b/samples/wasm-c-api/src/globalexportimport-0.wat @@ -1,3 +1,6 @@ +;; Copyright (C) 2019 Intel Corporation. All rights reserved. +;; SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + (module (global $mut_f32_export (export "var f32") (mut f32) (f32.const 7)) (func (export "get var f32 export") (result f32) (global.get $mut_f32_export)) diff --git a/samples/wasm-c-api/src/globalexportimport-1.wat b/samples/wasm-c-api/src/globalexportimport-1.wat index e0c608d3e..927e420d7 100644 --- a/samples/wasm-c-api/src/globalexportimport-1.wat +++ b/samples/wasm-c-api/src/globalexportimport-1.wat @@ -1,3 +1,6 @@ +;; Copyright (C) 2019 Intel Corporation. All rights reserved. +;; SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + (module (global $mut_f32_import (export "var f32") (import "globalexportimport-0" "var f32") (mut f32)) (func (export "get var f32 export") (import "globalexportimport-0" "get var f32 export") (result f32)) diff --git a/samples/wasm-c-api/src/globalexportimport.c b/samples/wasm-c-api/src/globalexportimport.c index 076b632eb..c8f58b499 100644 --- a/samples/wasm-c-api/src/globalexportimport.c +++ b/samples/wasm-c-api/src/globalexportimport.c @@ -1,3 +1,8 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + #include #include #include @@ -62,6 +67,7 @@ wasm_module_t * create_module_from_file(wasm_store_t* store, const char * filena wasm_byte_vec_new_uninitialized(&binary, file_size); if (fread(binary.data, file_size, 1, file) != 1) { printf("> Error loading module!\n"); + fclose(file); return NULL; } // Compile. diff --git a/samples/wasm-c-api/src/hello.c b/samples/wasm-c-api/src/hello.c index cc5aa53e8..72c7b2632 100644 --- a/samples/wasm-c-api/src/hello.c +++ b/samples/wasm-c-api/src/hello.c @@ -41,6 +41,7 @@ int main(int argc, const char* argv[]) { wasm_byte_vec_new_uninitialized(&binary, file_size); if (fread(binary.data, file_size, 1, file) != 1) { printf("> Error loading module!\n"); + fclose(file); return 1; } fclose(file); diff --git a/samples/wasm-c-api/src/multi.c b/samples/wasm-c-api/src/multi.c index 8291ff9b5..65c9afd43 100644 --- a/samples/wasm-c-api/src/multi.c +++ b/samples/wasm-c-api/src/multi.c @@ -59,6 +59,7 @@ int main(int argc, const char* argv[]) { wasm_byte_vec_new_uninitialized(&binary, file_size); if (fread(binary.data, file_size, 1, file) != 1) { printf("> Error loading module!\n"); + fclose(file); return 1; } fclose(file); diff --git a/samples/wasm-c-api/src/reflect.c b/samples/wasm-c-api/src/reflect.c index 746613abe..a90fa2aab 100644 --- a/samples/wasm-c-api/src/reflect.c +++ b/samples/wasm-c-api/src/reflect.c @@ -32,6 +32,12 @@ void print_valtype(const wasm_valtype_t* type) { void print_valtypes(const wasm_valtype_vec_t* types) { bool first = true; + + if (!types) { + printf("> Error print a NULL valtype\n"); + return; + } + for (size_t i = 0; i < types->size; ++i) { if (first) { first = false; @@ -43,6 +49,11 @@ void print_valtypes(const wasm_valtype_vec_t* types) { } void print_externtype(const wasm_externtype_t* type) { + if (!type) { + printf("> Error print a NULL externtype\n"); + return; + } + switch (wasm_externtype_kind(type)) { case WASM_EXTERN_FUNC: { const wasm_functype_t* functype = @@ -78,6 +89,11 @@ void print_externtype(const wasm_externtype_t* type) { } void print_name(const wasm_name_t* name) { + if (!name) { + printf("> Error print a NULL name\n"); + return; + } + printf("\"%.*s\"", (int)name->size, name->data); } @@ -106,6 +122,7 @@ int main(int argc, const char* argv[]) { wasm_byte_vec_new_uninitialized(&binary, file_size); if (fread(binary.data, file_size, 1, file) != 1) { printf("> Error loading module!\n"); + fclose(file); return 1; } fclose(file); diff --git a/samples/wasm-c-api/src/trap.c b/samples/wasm-c-api/src/trap.c index 2829dd2e5..e12141903 100644 --- a/samples/wasm-c-api/src/trap.c +++ b/samples/wasm-c-api/src/trap.c @@ -43,6 +43,7 @@ int main(int argc, const char* argv[]) { wasm_byte_vec_new_uninitialized(&binary, file_size); if (fread(binary.data, file_size, 1, file) != 1) { printf("> Error loading module!\n"); + fclose(file); return 1; } fclose(file); From 38c2ca63d0b8bb7ad94603a7faa7d708462dc84a Mon Sep 17 00:00:00 2001 From: LiFeng Date: Fri, 18 Jun 2021 12:45:34 +0800 Subject: [PATCH 204/207] sgx: fix the build warning (#653) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fix the warnings as below: App/App.cpp: In function ‘int wamr_pal_init(const wamr_pal_attr*)’: App/App.cpp:759:1: warning: control reaches end of non-void function [-Wreturn-type] 759 | } | ^ In file included from /usr/include/string.h:495, from App/App.cpp:9: In function ‘char* strncpy(char*, const char*, size_t)’, inlined from ‘int enclave_init(sgx_enclave_id_t*)’ at App/App.cpp:104:16: /usr/include/x86_64-linux-gnu/bits/string_fortified.h:106:34: warning: ‘char* __builtin___strncpy_chk(char*, const char*, long unsigned int, long unsigned int)’ specified bound depends on the length of the source argument [-Wstringop-overflow=] 106 | return __builtin___strncpy_chk (__dest, __src, __len, __bos (__dest)); | ~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ App/App.cpp: In function ‘int enclave_init(sgx_enclave_id_t*)’: App/App.cpp:102:16: note: length computed here 102 | (strlen(home_dir) + strlen("/") + sizeof(TOKEN_FILENAME) + 1) <= MAX_PATH) { | ~~~~~~^~~~~~~~~~ Signed-off-by: LiFeng --- product-mini/platforms/linux-sgx/enclave-sample/App/App.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/product-mini/platforms/linux-sgx/enclave-sample/App/App.cpp b/product-mini/platforms/linux-sgx/enclave-sample/App/App.cpp index e3c37a1fc..d15acbd39 100644 --- a/product-mini/platforms/linux-sgx/enclave-sample/App/App.cpp +++ b/product-mini/platforms/linux-sgx/enclave-sample/App/App.cpp @@ -97,11 +97,12 @@ enclave_init(sgx_enclave_id_t *p_eid) */ /* try to get the token saved in $HOME */ home_dir = getpwuid(getuid())->pw_dir; + size_t home_dir_len = home_dir ? strlen(home_dir) : 0; if (home_dir != NULL && - (strlen(home_dir) + strlen("/") + sizeof(TOKEN_FILENAME) + 1) <= MAX_PATH) { + home_dir_len <= MAX_PATH - 1 - sizeof(TOKEN_FILENAME) - strlen("/")) { /* compose the token path */ - strncpy(token_path, home_dir, strlen(home_dir)); + strncpy(token_path, home_dir, MAX_PATH); strncat(token_path, "/", strlen("/")); strncat(token_path, TOKEN_FILENAME, sizeof(TOKEN_FILENAME) + 1); } @@ -756,6 +757,7 @@ wamr_pal_init(const struct wamr_pal_attr *args) std::cout << "Fail to initialize enclave." << std::endl; return 1; } + return 0; } int From c6783ef258feb3339d401f14a784ebd599e63722 Mon Sep 17 00:00:00 2001 From: LiFeng Date: Tue, 22 Jun 2021 14:41:49 +0800 Subject: [PATCH 205/207] IO: support populate fds into WASM application (#655) Add new API wasm_runtime_set_wasi_args_ex to support populate stdio fds Signed-off-by: LiFeng --- core/iwasm/aot/aot_runtime.c | 3 ++ core/iwasm/common/wasm_runtime_common.c | 35 ++++++++++++++++--- core/iwasm/common/wasm_runtime_common.h | 9 +++++ core/iwasm/include/wasm_export.h | 8 +++++ core/iwasm/interpreter/wasm.h | 1 + core/iwasm/interpreter/wasm_runtime.c | 3 ++ .../linux-sgx/enclave-sample/App/App.cpp | 27 ++++++++++---- .../enclave-sample/Enclave/Enclave.cpp | 24 ++++++++----- 8 files changed, 90 insertions(+), 20 deletions(-) diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index dd05c94cb..484835df4 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -1036,6 +1036,9 @@ aot_instantiate(AOTModule *module, bool is_sub_inst, module->wasi_args.env_count, module->wasi_args.argv, module->wasi_args.argc, + module->wasi_args.stdio[0], + module->wasi_args.stdio[1], + module->wasi_args.stdio[2], error_buf, error_buf_size)) goto fail; } diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index 91ae8457f..535e7fd07 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -1793,12 +1793,14 @@ wasm_runtime_enlarge_memory(WASMModuleInstanceCommon *module, } #if WASM_ENABLE_LIBC_WASI != 0 + void -wasm_runtime_set_wasi_args(WASMModuleCommon *module, +wasm_runtime_set_wasi_args_ex(WASMModuleCommon *module, const char *dir_list[], uint32 dir_count, const char *map_dir_list[], uint32 map_dir_count, const char *env_list[], uint32 env_count, - char *argv[], int argc) + char *argv[], int argc, + int stdinfd, int stdoutfd, int stderrfd) { WASIArguments *wasi_args = NULL; @@ -1820,9 +1822,27 @@ wasm_runtime_set_wasi_args(WASMModuleCommon *module, wasi_args->env_count = env_count; wasi_args->argv = argv; wasi_args->argc = (uint32)argc; + wasi_args->stdio[0] = stdinfd; + wasi_args->stdio[1] = stdoutfd; + wasi_args->stdio[2] = stderrfd; } } +void +wasm_runtime_set_wasi_args(WASMModuleCommon *module, + const char *dir_list[], uint32 dir_count, + const char *map_dir_list[], uint32 map_dir_count, + const char *env_list[], uint32 env_count, + char *argv[], int argc) +{ + wasm_runtime_set_wasi_args_ex(module, + dir_list, dir_count, + map_dir_list, map_dir_count, + env_list, env_count, + argv, argc, + -1, -1, -1); +} + #if WASM_ENABLE_UVWASI == 0 bool wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, @@ -1830,6 +1850,7 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, const char *map_dir_list[], uint32 map_dir_count, const char *env[], uint32 env_count, char *argv[], uint32 argc, + int stdinfd, int stdoutfd, int stderrfd, char *error_buf, uint32 error_buf_size) { WASIContext *wasi_ctx; @@ -1951,9 +1972,9 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, argv_environ_inited = true; /* Prepopulate curfds with stdin, stdout, and stderr file descriptors. */ - if (!fd_table_insert_existing(curfds, 0, 0) - || !fd_table_insert_existing(curfds, 1, 1) - || !fd_table_insert_existing(curfds, 2, 2)) { + if (!fd_table_insert_existing(curfds, 0, (stdinfd != -1) ? stdinfd : 0) + || !fd_table_insert_existing(curfds, 1, (stdoutfd != -1) ? stdoutfd : 1) + || !fd_table_insert_existing(curfds, 2, (stderrfd != -1) ? stderrfd : 2)) { set_error_buf(error_buf, error_buf_size, "Init wasi environment failed: init fd table failed"); goto fail; @@ -2065,6 +2086,7 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, const char *map_dir_list[], uint32 map_dir_count, const char *env[], uint32 env_count, char *argv[], uint32 argc, + int stdinfd, int stdoutfd, int stderrfd, char *error_buf, uint32 error_buf_size) { uvwasi_t *uvwasi = NULL; @@ -2084,6 +2106,9 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, init_options.allocator = &uvwasi_allocator; init_options.argc = argc; init_options.argv = (const char **)argv; + init_options.in = (stdinfd != -1) ? (uvwasi_fd_t)stdinfd : init_options.in; + init_options.out = (stdoutfd != -1) ? (uvwasi_fd_t)stdoutfd : init_options.out; + init_options.err = (stderrfd != -1) ? (uvwasi_fd_t)stderrfd : init_options.err; if (dir_count > 0) { init_options.preopenc = dir_count; diff --git a/core/iwasm/common/wasm_runtime_common.h b/core/iwasm/common/wasm_runtime_common.h index 4ed886222..e8138bd25 100644 --- a/core/iwasm/common/wasm_runtime_common.h +++ b/core/iwasm/common/wasm_runtime_common.h @@ -630,6 +630,14 @@ wasm_exec_env_set_aux_stack(WASMExecEnv *exec_env, #endif #if WASM_ENABLE_LIBC_WASI != 0 +WASM_RUNTIME_API_EXTERN void +wasm_runtime_set_wasi_args_ex(WASMModuleCommon *module, + const char *dir_list[], uint32 dir_count, + const char *map_dir_list[], uint32 map_dir_count, + const char *env_list[], uint32 env_count, + char *argv[], int argc, + int stdinfd, int stdoutfd, int stderrfd); + /* See wasm_export.h for description */ WASM_RUNTIME_API_EXTERN void wasm_runtime_set_wasi_args(WASMModuleCommon *module, @@ -652,6 +660,7 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, const char *map_dir_list[], uint32 map_dir_count, const char *env[], uint32 env_count, char *argv[], uint32 argc, + int stdinfd, int stdoutfd, int stderrfd, char *error_buf, uint32 error_buf_size); void diff --git a/core/iwasm/include/wasm_export.h b/core/iwasm/include/wasm_export.h index a4394adb0..0fe46d61c 100644 --- a/core/iwasm/include/wasm_export.h +++ b/core/iwasm/include/wasm_export.h @@ -313,6 +313,14 @@ wasm_runtime_load_from_sections(wasm_section_list_t section_list, bool is_aot, WASM_RUNTIME_API_EXTERN void wasm_runtime_unload(wasm_module_t module); +WASM_RUNTIME_API_EXTERN void +wasm_runtime_set_wasi_args_ex(wasm_module_t module, + const char *dir_list[], uint32_t dir_count, + const char *map_dir_list[], uint32_t map_dir_count, + const char *env[], uint32_t env_count, + char *argv[], int argc, + int stdinfd, int stdoutfd, int stderrfd); + WASM_RUNTIME_API_EXTERN void wasm_runtime_set_wasi_args(wasm_module_t module, const char *dir_list[], uint32_t dir_count, diff --git a/core/iwasm/interpreter/wasm.h b/core/iwasm/interpreter/wasm.h index d99036e5e..02b712e85 100644 --- a/core/iwasm/interpreter/wasm.h +++ b/core/iwasm/interpreter/wasm.h @@ -305,6 +305,7 @@ typedef struct WASIArguments { uint32 env_count; char **argv; uint32 argc; + int stdio[3]; } WASIArguments; #endif diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index d3874dfa7..0b43f1895 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -1483,6 +1483,9 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, module->wasi_args.env_count, module->wasi_args.argv, module->wasi_args.argc, + module->wasi_args.stdio[0], + module->wasi_args.stdio[1], + module->wasi_args.stdio[2], error_buf, error_buf_size)) { goto fail; } diff --git a/product-mini/platforms/linux-sgx/enclave-sample/App/App.cpp b/product-mini/platforms/linux-sgx/enclave-sample/App/App.cpp index d15acbd39..14b8c415b 100644 --- a/product-mini/platforms/linux-sgx/enclave-sample/App/App.cpp +++ b/product-mini/platforms/linux-sgx/enclave-sample/App/App.cpp @@ -550,20 +550,24 @@ static bool set_wasi_args(void *wasm_module, const char **dir_list, uint32_t dir_list_size, const char **env_list, uint32_t env_list_size, + int stdinfd, int stdoutfd, int stderrfd, char **argv, uint32_t argc) { - uint64_t ecall_args[7]; + uint64_t ecall_args[10]; ecall_args[0] = (uint64_t)(uintptr_t)wasm_module; ecall_args[1] = (uint64_t)(uintptr_t)dir_list; ecall_args[2] = dir_list_size; ecall_args[3] = (uint64_t)(uintptr_t)env_list; ecall_args[4] = env_list_size; - ecall_args[5] = (uint64_t)(uintptr_t)argv; - ecall_args[6] = argc; + ecall_args[5] = stdinfd; + ecall_args[6] = stdoutfd; + ecall_args[7] = stderrfd; + ecall_args[8] = (uint64_t)(uintptr_t)argv; + ecall_args[9] = argc; if (SGX_SUCCESS != ecall_handle_command(g_eid, CMD_SET_WASI_ARGS, (uint8_t *)ecall_args, - sizeof(uint64_t) * 7)) { + sizeof(uint64_t) * 10)) { printf("Call ecall_handle_command() failed.\n"); } @@ -702,7 +706,7 @@ main(int argc, char *argv[]) /* Set wasi arguments */ if (!set_wasi_args(wasm_module, dir_list, dir_list_size, - env_list, env_list_size, argv, argc)) { + env_list, env_list_size, 0, 1, 2, argv, argc)) { printf("%s\n", "set wasi arguments failed.\n"); goto fail3; } @@ -773,6 +777,9 @@ wamr_pal_create_process(struct wamr_pal_create_process_args *args) uint32_t max_thread_num = 4; char *wasm_files[16]; void *wasm_module_inst[16]; + int stdinfd = -1; + int stdoutfd = -1; + int stderrfd = -1; int argc = 2; char *argv[argc] = { (char*)"./iwasm", (char *)args->argv[0] }; @@ -796,6 +803,12 @@ wamr_pal_create_process(struct wamr_pal_create_process_args *args) wasm_files[i] = (char *)args->argv[i]; } + if (args->stdio != NULL) { + stdinfd = args->stdio->stdin_fd; + stdoutfd = args->stdio->stdout_fd; + stderrfd = args->stdio->stderr_fd; + } + /* Init runtime */ if (!init_runtime(alloc_with_pool, max_thread_num)) { printf("Failed to init runtime\n"); @@ -834,7 +847,9 @@ wamr_pal_create_process(struct wamr_pal_create_process_args *args) /* Set wasi arguments */ if (!set_wasi_args(wasm_module, dir_list, dir_list_size, - env_list, env_list_size, argv, argc)) { + env_list, env_list_size, + stdinfd, stdoutfd, stderrfd, + argv, argc)) { printf("%s\n", "set wasi arguments failed.\n"); unload_module(wasm_module); free(wasm_file_buf); diff --git a/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.cpp b/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.cpp index ed9ca4182..15ce6c290 100644 --- a/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.cpp +++ b/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.cpp @@ -311,13 +311,16 @@ handle_cmd_set_wasi_args(uint64 *args, int32 argc) uint32 dir_list_size = *(uint32 *)args++; char **env_list = *(char ***)args++; uint32 env_list_size = *(uint32 *)args++; + int stdinfd = *(int *)args++; + int stdoutfd = *(int *)args++; + int stderrfd = *(int *)args++; char **wasi_argv = *(char ***)args++; char *p, *p1; uint32 wasi_argc = *(uint32 *)args++; uint64 total_size = 0; int32 i, str_len; - bh_assert(argc == 7); + bh_assert(argc == 10); total_size += sizeof(char *) * (uint64)dir_list_size + sizeof(char *) * (uint64)env_list_size @@ -382,14 +385,17 @@ handle_cmd_set_wasi_args(uint64 *args, int32 argc) p += sizeof(char *) * wasi_argc; } - wasm_runtime_set_wasi_args(enclave_module->module, - (const char **)enclave_module->wasi_dir_list, - dir_list_size, - NULL, 0, - (const char **)enclave_module->wasi_env_list, - env_list_size, - enclave_module->wasi_argv, - enclave_module->wasi_argc); + wasm_runtime_set_wasi_args_ex(enclave_module->module, + (const char **)enclave_module->wasi_dir_list, + dir_list_size, + NULL, 0, + (const char **)enclave_module->wasi_env_list, + env_list_size, + enclave_module->wasi_argv, + enclave_module->wasi_argc, + (stdinfd != -1) ? stdinfd : 0, + (stdoutfd != -1) ? stdoutfd : 1, + (stderrfd != -1) ? stderrfd : 2); *args_org = true; } From cba4c782735becf98f9aec9e60bd049e24620b85 Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Mon, 28 Jun 2021 11:59:49 +0800 Subject: [PATCH 206/207] Enable call wasm-c-api native func directly from interpreter (#656) And update loader error messages for latest spec cases, fix aot compiler build error based on latest LLVM code base. --- core/iwasm/aot/aot_runtime.c | 142 +----------- core/iwasm/common/wasm_c_api.c | 219 +++---------------- core/iwasm/common/wasm_runtime_common.c | 139 ++++++++++++ core/iwasm/common/wasm_runtime_common.h | 6 + core/iwasm/compilation/aot_llvm.c | 2 + core/iwasm/compilation/aot_llvm.h | 1 + core/iwasm/interpreter/wasm.h | 2 + core/iwasm/interpreter/wasm_interp_classic.c | 13 +- core/iwasm/interpreter/wasm_interp_fast.c | 13 +- core/iwasm/interpreter/wasm_loader.c | 24 +- samples/wasm-c-api/CMakeLists.txt | 20 +- samples/wasm-c-api/src/callback_chain.c | 6 +- samples/wasm-c-api/src/hello.c | 26 ++- 13 files changed, 249 insertions(+), 364 deletions(-) diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index 484835df4..90139788c 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -13,7 +13,6 @@ #if WASM_ENABLE_THREAD_MGR != 0 #include "../libraries/thread-mgr/thread_manager.h" #endif -#include "../common/wasm_c_api_internal.h" static void set_error_buf(char *error_buf, uint32 error_buf_size, const char *string) @@ -2204,140 +2203,6 @@ aot_is_wasm_type_equal(AOTModuleInstance *module_inst, return wasm_type_equal(type1, type2); } -static inline bool -argv_to_params(wasm_val_t *out_params, const uint32 *argv, - AOTFuncType *func_type) -{ - wasm_val_t *param = out_params; - uint32 i = 0, *u32; - - for (i = 0; i < func_type->param_count; i++, param++) { - switch (func_type->types[i]) { - case VALUE_TYPE_I32: - param->kind = WASM_I32; - param->of.i32 = *argv++; - break; - case VALUE_TYPE_I64: - param->kind = WASM_I64; - u32 = (uint32*)¶m->of.i64; - u32[0] = *argv++; - u32[1] = *argv++; - break; - case VALUE_TYPE_F32: - param->kind = WASM_F32; - param->of.f32 = *(float32 *)argv++; - break; - case VALUE_TYPE_F64: - param->kind = WASM_F64; - u32 = (uint32*)¶m->of.i64; - u32[0] = *argv++; - u32[1] = *argv++; - break; - default: - return false; - } - } - - return true; -} - -static inline bool -results_to_argv(uint32 *out_argv, const wasm_val_t *results, - AOTFuncType *func_type) -{ - const wasm_val_t *result = results; - uint32 *argv = out_argv, *u32, i; - uint8 *result_types = func_type->types + func_type->param_count; - - for (i = 0; i < func_type->result_count; i++, result++) { - switch (result_types[i]) { - case VALUE_TYPE_I32: - case VALUE_TYPE_F32: - *(int32*)argv++ = result->of.i32; - break; - case VALUE_TYPE_I64: - case VALUE_TYPE_F64: - u32 = (uint32*)&result->of.i64; - *argv++ = u32[0]; - *argv++ = u32[1]; - break; - default: - return false; - } - } - - return true; -} - -static inline bool -invoke_wasm_c_api_native(AOTModuleInstance *module_inst, void *func_ptr, - AOTFuncType *func_type, uint32 argc, uint32 *argv, - bool with_env, void *wasm_c_api_env) -{ - wasm_val_t params_buf[16], results_buf[4]; - wasm_val_t *params = params_buf, *results = results_buf; - wasm_trap_t *trap = NULL; - bool ret = false; - char fmt[16]; - - if (func_type->param_count > 16 - && !(params = wasm_runtime_malloc(sizeof(wasm_val_t) - * func_type->param_count))) { - aot_set_exception_with_id(module_inst, EXCE_OUT_OF_MEMORY); - return false; - } - - if (!argv_to_params(params, argv, func_type)) { - aot_set_exception(module_inst, "unsupported param type"); - goto fail; - } - - if (!with_env) { - wasm_func_callback_t callback = (wasm_func_callback_t)func_ptr; - trap = callback(params, results); - } - else { - wasm_func_callback_with_env_t callback = - (wasm_func_callback_with_env_t)func_ptr; - trap = callback(wasm_c_api_env, params, results); - } - if (trap) { - if (trap->message->data) { - snprintf(fmt, sizeof(fmt), "%%.%us", (uint32)trap->message->size); - snprintf(module_inst->cur_exception, - sizeof(module_inst->cur_exception), - fmt, trap->message->data); - } - else { - aot_set_exception(module_inst, - "native function throw unknown exception"); - } - wasm_trap_delete(trap); - goto fail; - } - - if (func_type->result_count > 4 - && !(results = wasm_runtime_malloc(sizeof(wasm_val_t) - * func_type->result_count))) { - aot_set_exception_with_id(module_inst, EXCE_OUT_OF_MEMORY); - goto fail; - } - - if (!results_to_argv(argv, results, func_type)) { - aot_set_exception(module_inst, "unsupported result type"); - goto fail; - } - - ret = true; - -fail: - if (params != params_buf) - wasm_runtime_free(params); - if (results != results_buf) - wasm_runtime_free(results); - return ret; -} - bool aot_invoke_native(WASMExecEnv *exec_env, uint32 func_idx, uint32 argc, uint32 *argv) @@ -2368,10 +2233,9 @@ aot_invoke_native(WASMExecEnv *exec_env, uint32 func_idx, attachment = import_func->attachment; if (import_func->call_conv_wasm_c_api) { - return invoke_wasm_c_api_native(module_inst, func_ptr, - func_type, argc, argv, - import_func->wasm_c_api_with_env, - attachment); + return wasm_runtime_invoke_c_api_native( + (WASMModuleInstanceCommon *)module_inst, func_ptr, func_type, argc, + argv, import_func->wasm_c_api_with_env, attachment); } else if (!import_func->call_conv_raw) { signature = import_func->signature; diff --git a/core/iwasm/common/wasm_c_api.c b/core/iwasm/common/wasm_c_api.c index c53388267..90d059e75 100644 --- a/core/iwasm/common/wasm_c_api.c +++ b/core/iwasm/common/wasm_c_api.c @@ -1401,10 +1401,9 @@ wasm_module_new(wasm_store_t *store, const wasm_byte_vec_t *binary) INIT_VEC(module_ex->binary, wasm_byte_vec_new, binary->size, binary->data); - module_ex->module_comm_rt = - wasm_runtime_load((uint8 *)module_ex->binary->data, - (uint32)module_ex->binary->size, - error_buf, (uint32)sizeof(error_buf)); + module_ex->module_comm_rt = wasm_runtime_load( + (uint8 *)module_ex->binary->data, (uint32)module_ex->binary->size, + error_buf, (uint32)sizeof(error_buf)); if (!(module_ex->module_comm_rt)) { LOG_ERROR(error_buf); goto failed; @@ -1846,172 +1845,6 @@ failed_exporttype_new: wasm_exporttype_vec_delete(out); } -static uint32 -argv_to_params(const uint64 *argv, - const wasm_valtype_vec_t *param_defs, - wasm_val_t out[]) -{ - size_t i = 0; - uint32 argc = 0; - - for (i = 0; i < param_defs->num_elems; i++) { - wasm_valtype_t *param_def = param_defs->data[i]; - wasm_val_t *param = out + i; - switch (param_def->kind) { - case WASM_I32: - param->kind = WASM_I32; - param->of.i32 = *(uint32 *)(argv + i); - argc++; - break; - case WASM_I64: - param->kind = WASM_I64; - param->of.i64 = *(uint64 *)(argv + i); - argc++; - break; - case WASM_F32: - param->kind = WASM_F32; - param->of.f32 = *(float32 *)(argv + i); - argc++; - break; - case WASM_F64: - param->kind = WASM_F64; - param->of.f64 = *(float64 *)(argv + i); - argc++; - break; - default: - LOG_WARNING("%s meets unsupported type: %d", __FUNCTION__, - param_def->kind); - goto failed; - } - } - - return argc; -failed: - return 0; -} - -static uint32 -results_to_argv(const wasm_val_t *results, - const wasm_valtype_vec_t *result_defs, - uint64 *out) -{ - size_t i = 0; - uint32 argc = 0; - - for (i = 0; i < result_defs->num_elems; ++i) { - wasm_valtype_t *result_def = result_defs->data[i]; - const wasm_val_t *result = results + i; - switch (result_def->kind) { - case WASM_I32: - *(int32 *)(out + i) = result->of.i32; - argc++; - break; - case WASM_I64: - *(int64 *)(out + i) = result->of.i64; - argc++; - break; - case WASM_F32: - *(float32 *)(out + i) = result->of.f32; - argc++; - break; - case WASM_F64: - *(float64 *)(out + i) = result->of.f64; - argc++; - break; - default: - { - LOG_WARNING("%s meets unsupported kind", __FUNCTION__, - result_def->kind); - goto failed; - } - } - } - - return argc; -failed: - return 0; -} - -static wasm_trap_t *cur_trap = NULL; -static void -native_func_trampoline(wasm_exec_env_t exec_env, uint64 *argv) -{ - wasm_val_t *params = NULL, *results = NULL; - uint32 argc = 0; - const wasm_func_t *func = NULL; - wasm_trap_t *trap = NULL; - size_t param_count, result_count; - - func = wasm_runtime_get_function_attachment(exec_env); - bh_assert(func); - - param_count = wasm_func_param_arity(func); - if (param_count) { - if (!argv) { - goto failed; - } - - if (!(params = malloc_internal(param_count * sizeof(wasm_val_t)))) { - goto failed; - } - - /* argv -> const wasm_val_t params[] */ - if (!(argc = argv_to_params(argv, wasm_functype_params(func->type), - params))) { - goto failed; - } - } - - result_count = wasm_func_result_arity(func); - if (result_count) { - if (!argv) { - goto failed; - } - - if (!(results = malloc_internal(result_count * sizeof(wasm_val_t)))) { - goto failed; - } - } - - if (func->with_env) { - trap = func->u.cb_env.cb(func->u.cb_env.env, params, results); - } - else { - trap = func->u.cb(params, results); - } - - if (trap) { - wasm_byte_vec_t message = { 0 }; - wasm_trap_message(trap, &message); - if (message.data) { - LOG_WARNING("got a trap %s", message.data); - wasm_runtime_set_exception(exec_env->module_inst, - "call failed, meet a wasm_trap_t"); - } - wasm_byte_vec_delete(&message); - - cur_trap = trap; - } - - if (argv) { - memset(argv, 0, wasm_func_param_arity(func) * sizeof(uint64)); - } - - /* there is no trap and there is return values */ - if (!trap && result_count) { - /* wasm_val_t results[] -> argv */ - if (!(argc = results_to_argv( - results, wasm_functype_results(func->type), argv))) { - goto failed; - } - } - -failed: - FREEIF(params); - FREEIF(results); - return; -} - static wasm_func_t * wasm_func_new_basic(const wasm_functype_t *type, wasm_func_callback_t func_callback) @@ -2342,8 +2175,6 @@ wasm_func_call(const wasm_func_t *func, bh_assert(func && func->type && func->inst_comm_rt); - cur_trap = NULL; - #if WASM_ENABLE_INTERP != 0 if (func->inst_comm_rt->module_type == Wasm_Module_Bytecode) { func_comm_rt = ((WASMModuleInstance *)func->inst_comm_rt)->functions @@ -2354,7 +2185,8 @@ wasm_func_call(const wasm_func_t *func, #if WASM_ENABLE_AOT != 0 if (func->inst_comm_rt->module_type == Wasm_Module_AoT) { if (!(func_comm_rt = func->func_comm_rt)) { - AOTModuleInstance *inst_aot = (AOTModuleInstance *)func->inst_comm_rt; + AOTModuleInstance *inst_aot = + (AOTModuleInstance *)func->inst_comm_rt; AOTModule *module_aot = (AOTModule *)inst_aot->aot_module.ptr; uint32 export_i = 0, export_func_j = 0; @@ -2363,9 +2195,9 @@ wasm_func_call(const wasm_func_t *func, if (export->kind == EXPORT_KIND_FUNC) { if (export->index == func->func_idx_rt) { func_comm_rt = - (AOTFunctionInstance *)inst_aot->export_funcs.ptr - + export_func_j; - ((wasm_func_t*)func)->func_comm_rt = func_comm_rt; + (AOTFunctionInstance *)inst_aot->export_funcs.ptr + + export_func_j; + ((wasm_func_t *)func)->func_comm_rt = func_comm_rt; break; } export_func_j++; @@ -2382,7 +2214,7 @@ wasm_func_call(const wasm_func_t *func, param_count = wasm_func_param_arity(func); result_count = wasm_func_result_arity(func); alloc_count = (param_count > result_count) ? param_count : result_count; - if (alloc_count > sizeof(argv_buf)/sizeof(uint64)) { + if (alloc_count > sizeof(argv_buf) / sizeof(uint64)) { if (!(argv = malloc_internal(sizeof(uint64) * alloc_count))) { goto failed; } @@ -2422,17 +2254,13 @@ wasm_func_call(const wasm_func_t *func, failed: if (argv != argv_buf) wasm_runtime_free(argv); - if (cur_trap) { - return cur_trap; + + if (wasm_runtime_get_exception(func->inst_comm_rt)) { + return wasm_trap_new_internal( + wasm_runtime_get_exception(func->inst_comm_rt)); } else { - if (wasm_runtime_get_exception(func->inst_comm_rt)) { - return wasm_trap_new_internal( - wasm_runtime_get_exception(func->inst_comm_rt)); - } - else { - return wasm_trap_new_internal("wasm_func_call failed"); - } + return wasm_trap_new_internal("wasm_func_call failed"); } } @@ -3182,10 +3010,16 @@ interp_link_func(const wasm_instance_t *inst, return false; } - /* add native_func_trampoline as a NativeSymbol */ - imported_func_interp->u.function.call_conv_raw = true; - imported_func_interp->u.function.attachment = cloned; - imported_func_interp->u.function.func_ptr_linked = native_func_trampoline; + imported_func_interp->u.function.call_conv_wasm_c_api = true; + imported_func_interp->u.function.wasm_c_api_with_env = import->with_env; + if (import->with_env) { + imported_func_interp->u.function.func_ptr_linked = import->u.cb_env.cb; + imported_func_interp->u.function.attachment = import->u.cb_env.env; + } + else { + imported_func_interp->u.function.func_ptr_linked = import->u.cb; + imported_func_interp->u.function.attachment = NULL; + } import->func_idx_rt = func_idx_rt; return true; @@ -3672,9 +3506,8 @@ wasm_instance_new(wasm_store_t *store, #endif } - instance->inst_comm_rt = - wasm_runtime_instantiate(*module, stack_size, heap_size, - error_buf, sizeof(error_buf)); + instance->inst_comm_rt = wasm_runtime_instantiate( + *module, stack_size, heap_size, error_buf, sizeof(error_buf)); if (!instance->inst_comm_rt) { LOG_ERROR(error_buf); goto failed; diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index 535e7fd07..64ab7ac87 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -21,6 +21,7 @@ #if WASM_ENABLE_SHARED_MEMORY != 0 #include "wasm_shared_memory.h" #endif +#include "../common/wasm_c_api_internal.h" #if WASM_ENABLE_MULTI_MODULE != 0 /* @@ -4026,3 +4027,141 @@ wasm_runtime_get_memory_data_size( return 0; } +static inline bool +argv_to_params(wasm_val_t *out_params, + const uint32 *argv, + WASMType *func_type) +{ + wasm_val_t *param = out_params; + uint32 i = 0, *u32; + + for (i = 0; i < func_type->param_count; i++, param++) { + switch (func_type->types[i]) { + case VALUE_TYPE_I32: + param->kind = WASM_I32; + param->of.i32 = *argv++; + break; + case VALUE_TYPE_I64: + param->kind = WASM_I64; + u32 = (uint32 *)¶m->of.i64; + u32[0] = *argv++; + u32[1] = *argv++; + break; + case VALUE_TYPE_F32: + param->kind = WASM_F32; + param->of.f32 = *(float32 *)argv++; + break; + case VALUE_TYPE_F64: + param->kind = WASM_F64; + u32 = (uint32 *)¶m->of.i64; + u32[0] = *argv++; + u32[1] = *argv++; + break; + default: + return false; + } + } + + return true; +} + +static inline bool +results_to_argv(uint32 *out_argv, + const wasm_val_t *results, + WASMType *func_type) +{ + const wasm_val_t *result = results; + uint32 *argv = out_argv, *u32, i; + uint8 *result_types = func_type->types + func_type->param_count; + + for (i = 0; i < func_type->result_count; i++, result++) { + switch (result_types[i]) { + case VALUE_TYPE_I32: + case VALUE_TYPE_F32: + *(int32 *)argv++ = result->of.i32; + break; + case VALUE_TYPE_I64: + case VALUE_TYPE_F64: + u32 = (uint32 *)&result->of.i64; + *argv++ = u32[0]; + *argv++ = u32[1]; + break; + default: + return false; + } + } + + return true; +} + +bool +wasm_runtime_invoke_c_api_native(WASMModuleInstanceCommon *module_inst, + void *func_ptr, WASMType *func_type, + uint32 argc, uint32 *argv, + bool with_env, void *wasm_c_api_env) +{ + wasm_val_t params_buf[16], results_buf[4]; + wasm_val_t *params = params_buf, *results = results_buf; + wasm_trap_t *trap = NULL; + bool ret = false; + + if (func_type->param_count > 16 + && !(params = wasm_runtime_malloc(sizeof(wasm_val_t) + * func_type->param_count))) { + wasm_runtime_set_exception(module_inst, "allocate memory failed"); + return false; + } + + if (!argv_to_params(params, argv, func_type)) { + wasm_runtime_set_exception(module_inst, "unsupported param type"); + goto fail; + } + + if (!with_env) { + wasm_func_callback_t callback = (wasm_func_callback_t)func_ptr; + trap = callback(params, results); + } + else { + wasm_func_callback_with_env_t callback = + (wasm_func_callback_with_env_t)func_ptr; + trap = callback(wasm_c_api_env, params, results); + } + + if (trap) { + if (trap->message->data) { + /* since trap->message->data does not end with '\0' */ + char trap_message[128] = { 0 }; + bh_memcpy_s( + trap_message, 127, trap->message->data, + (trap->message->size < 127 ? trap->message->size : 127)); + wasm_runtime_set_exception(module_inst, trap_message); + } + else { + wasm_runtime_set_exception( + module_inst, "native function throw unknown exception"); + } + wasm_trap_delete(trap); + goto fail; + } + + if (func_type->result_count > 4 + && !(results = wasm_runtime_malloc(sizeof(wasm_val_t) + * func_type->result_count))) { + wasm_runtime_set_exception(module_inst, "allocate memory failed"); + goto fail; + } + + if (!results_to_argv(argv, results, func_type)) { + wasm_runtime_set_exception(module_inst, "unsupported result type"); + goto fail; + } + + ret = true; + +fail: + if (params != params_buf) + wasm_runtime_free(params); + if (results != results_buf) + wasm_runtime_free(results); + return ret; +} diff --git a/core/iwasm/common/wasm_runtime_common.h b/core/iwasm/common/wasm_runtime_common.h index e8138bd25..83fd82dcc 100644 --- a/core/iwasm/common/wasm_runtime_common.h +++ b/core/iwasm/common/wasm_runtime_common.h @@ -796,6 +796,12 @@ uint32 wasm_runtime_get_memory_data_size(const WASMModuleInstanceCommon *module_inst_comm, uint32 memory_inst_idx); +bool +wasm_runtime_invoke_c_api_native(WASMModuleInstanceCommon *module_inst, + void *func_ptr, WASMType *func_type, + uint32 argc, uint32 *argv, + bool with_env, void *wasm_c_api_env); + #ifdef __cplusplus } #endif diff --git a/core/iwasm/compilation/aot_llvm.c b/core/iwasm/compilation/aot_llvm.c index d4d382a37..7966a5477 100644 --- a/core/iwasm/compilation/aot_llvm.c +++ b/core/iwasm/compilation/aot_llvm.c @@ -1534,7 +1534,9 @@ aot_create_comp_context(AOTCompData *comp_data, LLVMAddInstructionCombiningPass(comp_ctx->pass_mgr); LLVMAddCFGSimplificationPass(comp_ctx->pass_mgr); LLVMAddJumpThreadingPass(comp_ctx->pass_mgr); +#if LLVM_VERSION_MAJOR < 12 LLVMAddConstantPropagationPass(comp_ctx->pass_mgr); +#endif LLVMAddIndVarSimplifyPass(comp_ctx->pass_mgr); if (!option->is_jit_mode) { diff --git a/core/iwasm/compilation/aot_llvm.h b/core/iwasm/compilation/aot_llvm.h index 95d0e8f5c..0ed1c33d5 100644 --- a/core/iwasm/compilation/aot_llvm.h +++ b/core/iwasm/compilation/aot_llvm.h @@ -7,6 +7,7 @@ #define _AOT_LLVM_H_ #include "aot.h" +#include "llvm/Config/llvm-config.h" #include "llvm-c/Types.h" #include "llvm-c/Target.h" #include "llvm-c/Core.h" diff --git a/core/iwasm/interpreter/wasm.h b/core/iwasm/interpreter/wasm.h index 02b712e85..fedf3dd4e 100644 --- a/core/iwasm/interpreter/wasm.h +++ b/core/iwasm/interpreter/wasm.h @@ -186,6 +186,8 @@ typedef struct WASMFunctionImport { WASMModule *import_module; WASMFunction *import_func_linked; #endif + bool call_conv_wasm_c_api; + bool wasm_c_api_with_env; } WASMFunctionImport; typedef struct WASMGlobalImport { diff --git a/core/iwasm/interpreter/wasm_interp_classic.c b/core/iwasm/interpreter/wasm_interp_classic.c index 3a0288808..fdfa4b32f 100644 --- a/core/iwasm/interpreter/wasm_interp_classic.c +++ b/core/iwasm/interpreter/wasm_interp_classic.c @@ -753,7 +753,18 @@ wasm_interp_call_func_native(WASMModuleInstance *module_inst, return; } - if (!func_import->call_conv_raw) { + if (func_import->call_conv_wasm_c_api) { + ret = wasm_runtime_invoke_c_api_native( + (WASMModuleInstanceCommon *)module_inst, + func_import->func_ptr_linked, func_import->func_type, + cur_func->param_cell_num, frame->lp, + func_import->wasm_c_api_with_env, func_import->attachment); + if (ret) { + argv_ret[0] = frame->lp[0]; + argv_ret[1] = frame->lp[1]; + } + } + else if (!func_import->call_conv_raw) { ret = wasm_runtime_invoke_native(exec_env, func_import->func_ptr_linked, func_import->func_type, func_import->signature, func_import->attachment, diff --git a/core/iwasm/interpreter/wasm_interp_fast.c b/core/iwasm/interpreter/wasm_interp_fast.c index 786ba7b12..7c714ee96 100644 --- a/core/iwasm/interpreter/wasm_interp_fast.c +++ b/core/iwasm/interpreter/wasm_interp_fast.c @@ -826,7 +826,18 @@ wasm_interp_call_func_native(WASMModuleInstance *module_inst, return; } - if (!func_import->call_conv_raw) { + if (func_import->call_conv_wasm_c_api) { + ret = wasm_runtime_invoke_c_api_native( + (WASMModuleInstanceCommon *)module_inst, + func_import->func_ptr_linked, func_import->func_type, + cur_func->param_cell_num, frame->lp, + func_import->wasm_c_api_with_env, func_import->attachment); + if (ret) { + argv_ret[0] = frame->lp[0]; + argv_ret[1] = frame->lp[1]; + } + } + else if (!func_import->call_conv_raw) { ret = wasm_runtime_invoke_native(exec_env, func_import->func_ptr_linked, func_import->func_type, func_import->signature, func_import->attachment, diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index 57e46edf0..a3db0a2d0 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -2304,7 +2304,7 @@ check_table_index(const WASMModule *module, uint32 table_index, !wasm_get_ref_types_flag() && #endif table_index != 0) { - set_error_buf(error_buf, error_buf_size, "zero flag expected"); + set_error_buf(error_buf, error_buf_size, "zero byte expected"); return false; } @@ -7472,13 +7472,8 @@ handle_op_block_and_loop: CHECK_MEMORY(); /* reserved byte 0x00 */ if (*p++ != 0x00) { -#if WASM_ENABLE_REF_TYPES != 0 set_error_buf(error_buf, error_buf_size, "zero byte expected"); -#else - set_error_buf(error_buf, error_buf_size, - "zero flag expected"); -#endif goto fail; } PUSH_I32(); @@ -7490,13 +7485,8 @@ handle_op_block_and_loop: CHECK_MEMORY(); /* reserved byte 0x00 */ if (*p++ != 0x00) { -#if WASM_ENABLE_REF_TYPES != 0 set_error_buf(error_buf, error_buf_size, "zero byte expected"); -#else - set_error_buf(error_buf, error_buf_size, - "zero flag expected"); -#endif goto fail; } POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32); @@ -7811,7 +7801,7 @@ handle_op_block_and_loop: goto fail_unknown_memory; if (*p++ != 0x00) - goto fail_zero_flag_expected; + goto fail_zero_byte_expected; if (data_seg_idx >= module->data_seg_count) { set_error_buf_v(error_buf, error_buf_size, @@ -7848,7 +7838,7 @@ handle_op_block_and_loop: { /* both src and dst memory index should be 0 */ if (*(int16*)p != 0x0000) - goto fail_zero_flag_expected; + goto fail_zero_byte_expected; p += 2; if (module->import_memory_count == 0 && module->memory_count == 0) @@ -7862,7 +7852,7 @@ handle_op_block_and_loop: case WASM_OP_MEMORY_FILL: { if (*p++ != 0x00) { - goto fail_zero_flag_expected; + goto fail_zero_byte_expected; } if (module->import_memory_count == 0 && module->memory_count == 0) { goto fail_unknown_memory; @@ -7872,9 +7862,9 @@ handle_op_block_and_loop: POP_I32(); POP_I32(); break; -fail_zero_flag_expected: +fail_zero_byte_expected: set_error_buf(error_buf, error_buf_size, - "zero flag expected"); + "zero byte expected"); goto fail; fail_unknown_memory: @@ -8460,7 +8450,7 @@ fail_data_cnt_sec_require: /* reserved byte 0x00 */ if (*p++ != 0x00) { set_error_buf(error_buf, error_buf_size, - "zero flag expected"); + "zero byte expected"); goto fail; } break; diff --git a/samples/wasm-c-api/CMakeLists.txt b/samples/wasm-c-api/CMakeLists.txt index 75dd80534..334232e8d 100644 --- a/samples/wasm-c-api/CMakeLists.txt +++ b/samples/wasm-c-api/CMakeLists.txt @@ -105,32 +105,30 @@ foreach(EX ${EXAMPLES}) if (MSVC) target_compile_definitions(${EX} PRIVATE WASM_API_EXTERN=) endif() -endforeach() -# wat to wasm -foreach(EX ${EXAMPLES}) - set(SRC ${CMAKE_CURRENT_LIST_DIR}/src/${EX}.wat) + # wat to wasm + set(WAT ${CMAKE_CURRENT_LIST_DIR}/src/${EX}.wat) - add_custom_target(${EX}_WASM ALL - COMMAND ${WAT2WASM} ${SRC} -o ${PROJECT_BINARY_DIR}/${EX}.wasm - DEPENDS ${SRC} + add_custom_target(${EX}_WASM + COMMAND ${WAT2WASM} ${WAT} -o ${PROJECT_BINARY_DIR}/${EX}.wasm + DEPENDS ${WAT} BYPRODUCTS ${PROJECT_BINARY_DIR}/${EX}.wasm VERBATIM - SOURCES ${SRC} ) + add_dependencies(${EX} ${EX}_WASM) # generate .aot file if(${WAMR_BUILD_AOT} EQUAL 1) if(EXISTS ${WAMRC}) - add_custom_target(${EX}_AOT ALL + add_custom_target(${EX}_AOT COMMAND ${WAMRC} -o ${PROJECT_BINARY_DIR}/${EX}.aot ${PROJECT_BINARY_DIR}/${EX}.wasm - DEPENDS ${PROJECT_BINARY_DIR}/${EX}.wasm + DEPENDS ${EX}_WASM BYPRODUCTS ${PROJECT_BINARY_DIR}/${EX}.aot VERBATIM - SOURCES ${SRC} COMMENT "generate a aot file ${PROJECT_BINARY_DIR}/${EX}.aot" ) + add_dependencies(${EX} ${EX}_AOT) endif() endif() endforeach() diff --git a/samples/wasm-c-api/src/callback_chain.c b/samples/wasm-c-api/src/callback_chain.c index d6f933ac4..ab15d0823 100644 --- a/samples/wasm-c-api/src/callback_chain.c +++ b/samples/wasm-c-api/src/callback_chain.c @@ -83,7 +83,7 @@ DEFINE_FUNCTION(log) return NULL; } - if (data[length.of.i32]) { + if (data[length.of.i32 - 1]) { printf("> Error terminated character\n"); return NULL; } @@ -188,7 +188,11 @@ main(int argc, const char *argv[]) // Load binary. printf("Loading binary...\n"); +#if WASM_ENABLE_AOT != 0 && WASM_ENABLE_INTERP == 0 + FILE *file = fopen("callback_chain.aot", "rb"); +#else FILE *file = fopen("callback_chain.wasm", "rb"); +#endif if (!file) { printf("> Error loading module!\n"); return 1; diff --git a/samples/wasm-c-api/src/hello.c b/samples/wasm-c-api/src/hello.c index 72c7b2632..fde1b82d4 100644 --- a/samples/wasm-c-api/src/hello.c +++ b/samples/wasm-c-api/src/hello.c @@ -56,15 +56,26 @@ int main(int argc, const char* argv[]) { wasm_byte_vec_delete(&binary); + // Create external print functions. + printf("Creating callback...\n"); + own wasm_functype_t* hello_type = wasm_functype_new_0_0(); + own wasm_func_t* hello_func = + wasm_func_new(store, hello_type, hello_callback); + + wasm_functype_delete(hello_type); + // Instantiate. printf("Instantiating module...\n"); + const wasm_extern_t* imports[] = { wasm_func_as_extern(hello_func) }; own wasm_instance_t* instance = - wasm_instance_new(store, module, NULL, NULL); + wasm_instance_new(store, module, imports, NULL); if (!instance) { printf("> Error instantiating module!\n"); return 1; } + wasm_func_delete(hello_func); + // Extract export. printf("Extracting export...\n"); own wasm_extern_vec_t exports; @@ -74,9 +85,22 @@ int main(int argc, const char* argv[]) { return 1; } + const wasm_func_t* run_func = wasm_extern_as_func(exports.data[0]); + if (run_func == NULL) { + printf("> Error accessing export!\n"); + return 1; + } + wasm_module_delete(module); wasm_instance_delete(instance); + // Call. + printf("Calling export...\n"); + if (wasm_func_call(run_func, NULL, NULL)) { + printf("> Error calling function!\n"); + return 1; + } + wasm_extern_vec_delete(&exports); // Shut down. From e92fa8744caeeb36c22dc9a84ca801edc2d306e9 Mon Sep 17 00:00:00 2001 From: Wang Xin Date: Sun, 4 Jul 2021 15:04:25 +0800 Subject: [PATCH 207/207] Create TSC_Charter.md --- TSC_Charter.md | 177 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 177 insertions(+) create mode 100644 TSC_Charter.md diff --git a/TSC_Charter.md b/TSC_Charter.md new file mode 100644 index 000000000..e2e96d415 --- /dev/null +++ b/TSC_Charter.md @@ -0,0 +1,177 @@ +# Project Technical Steering Committee (PTSC) Charter + +## Section 1. Guiding Principle + +The WebAssembly Micro Runtime (WAMR) project is part of the + +Bytecode Alliance (BA) which operates transparently, openly, + +collaboratively, and ethically. Project proposals, timelines, and status + +must not merely be open, but also easily visible to outsiders. + +## Section 2. Project Governance under Bytecode Alliance + +Technical leadership for the WAMR projects within the Bytecode Alliance + +is delegated to the projects through the project charter. Though the BA TSC + +will not interfere with day-to-day discussions, votes or meetings of the PTSC, + +the BA TSC may request additional amendments to the PTSC charter when + +there is misalignment between the project charter and the BA mission and values. + + + +The PTSC structure described in this document may be overhauled as part of + +establishing a BA TSC in order to adhere to constraints or requirements that + +TSC will impose on project-level governance. + +## Section 3. Establishment of the PTSC + +PTSC memberships are not time-limited. There is no maximum size of the PTSC. +The size is expected to vary in order to ensure adequate coverage of important +areas of expertise, balanced with the ability to make decisions efficiently. +The PTSC must have at least four members. + +There is no specific set of requirements or qualifications for PTSC +membership beyond these rules. The PTSC may add additional members to the +PTSC by a standard PTSC motion and vote. A PTSC member may be removed from the +PTSC by voluntary resignation, by a standard PTSC motion, or in accordance to the +participation rules described below. + +Changes to PTSC membership should be posted in the agenda, and may be suggested +as any other agenda item. + +The PTSC may, at its discretion, invite any number of non-voting observers to +participate in the public portion of PTSC discussions and meetings. + +The PTSC shall meet regularly using tools that enable participation by the +community (e.g. weekly on a Zulip channel, or through any other +appropriate means selected by the PTSC ). The meeting shall be directed by +the PTSC Chairperson. Responsibility for directing individual meetings may be +delegated by the PTSC Chairperson to any other PTSC member. Minutes or an +appropriate recording shall be taken and made available to the community +through accessible public postings. + +PTSC members are expected to regularly participate in PTSC activities. + +In the case where an individual PTSC member -- within any three month period -- +attends fewer than 25% of the regularly scheduled meetings, does not +participate in PTSC discussions, *and* does not participate in PTSC votes, the +member shall be automatically removed from the PTSC. The member may be invited +to continue attending PTSC meetings as an observer. + +## Section 4. Responsibilities of the PTSC + +Subject to such policies as may be set by the BA TSC, the WAMR PTSC is +responsible for all technical development within the WAMR project, +including: + +* Setting release dates. +* Release quality standards. +* Technical direction. +* Project governance and process. +* GitHub repository hosting. +* Conduct guidelines. +* Maintaining the list of additional Collaborators. +* Development process and any coding standards. +* Mediating technical conflicts between Collaborators or Foundation +projects. + +The PTSC will define WAMR project’s release vehicles. + +## Section 5. WAMR Project Operations + +The PTSC will establish and maintain a development process for the WAMR +project. The development process will establish guidelines +for how the developers and community will operate. It will, for example, +establish appropriate timelines for PTSC review (e.g. agenda items must be +published at least a certain number of hours in advance of a PTSC +meeting). + +The PTSC and entire technical community will follow any processes as may +be specified by the Bytecode Alliance Board relating to the intake and license compliance +review of contributions, including the Bytecode Alliance IP Policy. + +## Section 6. Elections + +Leadership roles in the WAMR project will be peer elected +representatives of the community. + +For election of persons (such as the PTSC Chairperson), a multiple-candidate +method should be used, such as: + +* [Condorcet][] or +* [Single Transferable Vote][] + +Multiple-candidate methods may be reduced to simple election by plurality +when there are only two candidates for one position to be filled. No +election is required if there is only one candidate and no objections to +the candidate's election. Elections shall be done within the projects by +the Collaborators active in the project. + +The PTSC will elect from amongst voting PTSC members a PTSC Chairperson to +work on building an agenda for PTSC meetings. The PTSC shall hold annual + +elections to select a PTSC Chairperson; there are no limits on the number +of terms a PTSC Chairperson may serve. + +## Section 7. Voting + +For internal project decisions, Collaborators shall operate under Lazy +Consensus. The PTSC shall establish appropriate guidelines for +implementing Lazy Consensus (e.g. expected notification and review time +periods) within the development process. + +The PTSC follows a [Consensus Seeking][] decision making model. When an agenda +item has appeared to reach a consensus the moderator will ask "Does anyone +object?" as a final call for dissent from the consensus. + +If an agenda item cannot reach a consensus a PTSC member can call for +either a closing vote or a vote to table the issue to the next meeting. +The call for a vote must be seconded by a majority of the PTSC or else the +discussion will continue. + +For all votes, a simple majority of all PTSC members for, or against, the issue +wins. A PTSC member may choose to participate in any vote through abstention. + +## Section 8. Project Roles + +The WAMR git repository is maintained by the PTSC and +additional Collaborators who are added by the PTSC on an ongoing basis. + +Individuals making significant and valuable contributions, +“Contributor(s)”, are made Collaborators and given commit-access to the +project. These individuals are identified by the PTSC and their addition +as Collaborators is discussed during a PTSC meeting. Modifications of the +contents of the git repository are made on a collaborative basis as defined in +the development process. + +Collaborators may opt to elevate significant or controversial +modifications, or modifications that have not found consensus to the PTSC +for discussion by assigning the `tsc-agenda` tag to a pull request or +issue. The PTSC should serve as the final arbiter where required. The PTSC +will maintain and publish a list of current Collaborators, as +well as a development process guide for Collaborators and Contributors +looking to participate in the development effort. + +## Section 9. Definitions + +* **Contributors**: contribute code or other artifacts, but do not have +the right to commit to the code base. Contributors work with the +project’s Collaborators to have code committed to the code base. A +Contributor may be promoted to a Collaborator by the PTSC. Contributors should +rarely be encumbered by the PTSC. + +* **Project**: a technical collaboration effort, e.g. a subsystem, that +is organized through the project creation process and approved by the +PTSC. + +[Consensus Seeking]: https://en.wikipedia.org/wiki/Consensus-seeking_decision-making +[Condorcet]: https://en.wikipedia.org/wiki/Condorcet_method +[Single Transferable Vote]: https://en.wikipedia.org/wiki/Single_transferable_vote +