From d856af6c33591815ab4c890f0606bc99ee8135ad Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Tue, 18 Jan 2022 14:35:35 +0800 Subject: [PATCH 01/32] Specify a commit ID for XNNPACK workload (#966) XNNPACK code base is updating quickly, we specify a commit ID for it so as to build XNNPACK workload successfully. --- samples/workload/XNNPACK/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/samples/workload/XNNPACK/CMakeLists.txt b/samples/workload/XNNPACK/CMakeLists.txt index 054d326997..1be0332682 100644 --- a/samples/workload/XNNPACK/CMakeLists.txt +++ b/samples/workload/XNNPACK/CMakeLists.txt @@ -15,6 +15,7 @@ ExternalProject_Add(xnnpack GIT_PROGRESS ON SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/xnnpack UPDATE_COMMAND git checkout . + && git reset --hard 4d738aef36872669e4bba05a4b259149ba8e62e1 && cmake -E copy ${CMAKE_CURRENT_SOURCE_DIR}/benchmark.patch ${CMAKE_CURRENT_SOURCE_DIR}/xnnpack/third_party && git apply ${CMAKE_CURRENT_SOURCE_DIR}/xnnpack.patch CONFIGURE_COMMAND "" From 2c743dbd5188df68c649554c58eb06dda1a592eb Mon Sep 17 00:00:00 2001 From: Huang Qi Date: Wed, 19 Jan 2022 08:55:59 +0800 Subject: [PATCH 02/32] Add log info for heap and stack like wasm loader in aot loader (#968) Add log info for heap and stack like wasm loader in aot loader Signed-off-by: Huang Qi Change-Id: I349848d75f1a26cde29217c14cfb6e779c976a8b --- core/iwasm/aot/aot_runtime.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index 4ff63d465d..26512e22ab 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -460,6 +460,8 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModule *module, 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(" data offset: %u, stack size: %d", module->aux_data_end, + module->aux_stack_size); LOG_VERBOSE(" heap offset: %u, heap size: %d\n", heap_offset, heap_size); total_size = (uint64)num_bytes_per_page * init_page_count; From 260d36a62da58aa8d59fbad61db678d938ab529f Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Wed, 19 Jan 2022 11:25:08 +0800 Subject: [PATCH 03/32] Refactor externref related APIs of reference types feature (#971) Currently when calling wasm_runtime_call_wasm() to invoke wasm function with externref type argument from runtime embedder, developer needs to use wasm_externref_obj2ref() to convert externref obj into an internal ref index firstly, which is not convenient to developer. To align with GC feature in which all the references passed to wasm_runtime_call_wasm() can be object pointers directly, we change the interface of wasm_runtime_call_wasm() to allow to pass object pointer directly for the externref argument, and refactor the related codes, update the related samples and the document. --- core/iwasm/aot/aot_loader.c | 1 + core/iwasm/aot/aot_runtime.c | 10 +- core/iwasm/common/wasm_application.c | 110 +++- core/iwasm/common/wasm_c_api.c | 252 ++++---- core/iwasm/common/wasm_c_api_internal.h | 1 - core/iwasm/common/wasm_exec_env.h | 4 - core/iwasm/common/wasm_native.c | 39 +- core/iwasm/common/wasm_runtime_common.c | 582 +++++++++++++++--- core/iwasm/common/wasm_runtime_common.h | 15 - core/iwasm/compilation/aot.h | 1 + core/iwasm/compilation/aot_emit_aot_file.c | 1 + core/iwasm/include/wasm_export.h | 6 +- core/iwasm/interpreter/wasm.h | 13 + core/iwasm/interpreter/wasm_runtime.c | 19 +- .../platform/windows/platform_internal.h | 3 + doc/export_native_api.md | 3 +- doc/ref_types.md | 19 +- samples/ref-types/CMakeLists.txt | 2 +- samples/ref-types/src/hello.c | 238 +++++-- samples/ref-types/src/hello.wat | 54 +- samples/wasm-c-api/src/callback.c | 20 +- samples/wasm-c-api/src/callback_chain.c | 16 +- samples/wasm-c-api/src/global.c | 46 +- samples/wasm-c-api/src/hello.c | 10 +- samples/wasm-c-api/src/hostref.c | 122 ++-- samples/wasm-c-api/src/memory.c | 45 +- samples/wasm-c-api/src/multi.c | 41 +- samples/wasm-c-api/src/reflect.c | 19 +- samples/wasm-c-api/src/table.c | 28 +- samples/wasm-c-api/src/trap.c | 11 +- 30 files changed, 1142 insertions(+), 589 deletions(-) diff --git a/core/iwasm/aot/aot_loader.c b/core/iwasm/aot/aot_loader.c index f5dc822557..bac3b476b9 100644 --- a/core/iwasm/aot/aot_loader.c +++ b/core/iwasm/aot/aot_loader.c @@ -854,6 +854,7 @@ load_import_table_list(const uint8 **p_buf, const uint8 *buf_end, /* 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->elem_type); 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); diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index 26512e22ab..6a78e1dc97 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -85,7 +85,7 @@ init_global_data(uint8 *global_data, uint8 type, WASMValue *initial_value) switch (type) { case VALUE_TYPE_I32: case VALUE_TYPE_F32: -#if WASM_ENABLE_REF_TYPES +#if WASM_ENABLE_REF_TYPES != 0 case VALUE_TYPE_FUNCREF: case VALUE_TYPE_EXTERNREF: #endif @@ -1572,16 +1572,8 @@ aot_create_exec_env_and_call_function(AOTModuleInstance *module_inst, } } -#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 - /* don't destroy the exec_env if it's searched from the cluster */ if (!existing_exec_env) wasm_exec_env_destroy(exec_env); diff --git a/core/iwasm/common/wasm_application.c b/core/iwasm/common/wasm_application.c index 3555c9aab8..fcbeb30e29 100644 --- a/core/iwasm/common/wasm_application.c +++ b/core/iwasm/common/wasm_application.c @@ -82,6 +82,7 @@ wasm_application_execute_main(WASMModuleInstanceCommon *module_inst, int32 argc, { WASMFunctionInstanceCommon *func; WASMType *func_type = NULL; + WASMExecEnv *exec_env = NULL; uint32 argc1 = 0, argv1[2] = { 0 }; uint32 total_argv_size = 0; uint64 total_size; @@ -91,14 +92,20 @@ wasm_application_execute_main(WASMModuleInstanceCommon *module_inst, int32 argc, uint32 *argv_offsets, module_type; bool ret, is_import_func = true; + exec_env = wasm_runtime_get_exec_env_singleton(module_inst); + if (!exec_env) { + wasm_runtime_set_exception(module_inst, + "create singleton exec_env failed"); + return false; + } + #if WASM_ENABLE_LIBC_WASI != 0 /* In wasi mode, we should call the function named "_start" which initializes the wasi envrionment and then calls the actual main function. Directly calling 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); + return wasm_runtime_call_wasm(exec_env, func, 0, NULL); } #endif /* end of WASM_ENABLE_LIBC_WASI */ @@ -179,8 +186,7 @@ wasm_application_execute_main(WASMModuleInstanceCommon *module_inst, int32 argc, (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); + ret = wasm_runtime_call_wasm(exec_env, func, argc1, argv1); if (ret && func_type->result_count > 0 && argc > 0 && argv) /* copy the return value */ *(int *)argv = (int)argv1[0]; @@ -345,7 +351,11 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, WASMFunctionInstanceCommon *target_func; WASMModuleInstanceCommon *target_inst; WASMType *type = NULL; + WASMExecEnv *exec_env = NULL; uint32 argc1, *argv1 = NULL, cell_num = 0, j, k = 0; +#if WASM_ENABLE_REF_TYPES != 0 + uint32 param_size_in_double_world = 0, result_size_in_double_world = 0; +#endif int32 i, p, module_type; uint64 total_size; const char *exception; @@ -373,8 +383,23 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, goto fail; } +#if WASM_ENABLE_REF_TYPES != 0 + for (i = 0; i < type->param_count; i++) { + param_size_in_double_world += + wasm_value_type_cell_num_outside(type->types[i]); + } + for (i = 0; i < type->result_count; i++) { + result_size_in_double_world += wasm_value_type_cell_num_outside( + type->types[type->param_count + i]); + } + argc1 = param_size_in_double_world; + cell_num = (param_size_in_double_world >= result_size_in_double_world) + ? param_size_in_double_world + : result_size_in_double_world; +#else argc1 = type->param_cell_num; cell_num = (argc1 > type->ret_cell_num) ? argc1 : type->ret_cell_num; +#endif total_size = sizeof(uint32) * (uint64)(cell_num > 2 ? cell_num : 2); if ((!(argv1 = runtime_malloc((uint32)total_size, target_inst, NULL, 0)))) { @@ -487,9 +512,8 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, #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; + if (strncasecmp(argv[i], "null", 4) == 0) { + argv1[p++] = (uint32)-1; } else { argv1[p++] = (uint32)strtoul(argv[i], &endptr, 0); @@ -498,23 +522,27 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, } case VALUE_TYPE_EXTERNREF: { - if (strncmp(argv[i], "null", 4) == 0 - || strncmp(argv[i], "NULL", 4) == 0) { - argv1[p++] = NULL_REF; +#if UINTPTR_MAX == UINT32_MAX + if (strncasecmp(argv[i], "null", 4) == 0) { + argv1[p++] = (uint32)-1; } else { - uint64 val = strtoull(argv[i], &endptr, 0); - void *extern_obj = (void *)(uintptr_t)val; - uint32 externref_idx; - - if (!wasm_externref_obj2ref(target_inst, extern_obj, - &externref_idx)) { - wasm_runtime_set_exception( - module_inst, "map extern object to ref failed"); - goto fail; - } - argv1[p++] = externref_idx; + argv1[p++] = strtoul(argv[i], &endptr, 0); + } +#else + union { + uintptr_t val; + uint32 parts[2]; + } u; + if (strncasecmp(argv[i], "null", 4) == 0) { + u.val = (uintptr_t)-1LL; + } + else { + u.val = strtoull(argv[i], &endptr, 0); } + argv1[p++] = u.parts[0]; + argv1[p++] = u.parts[1]; +#endif break; } #endif /* WASM_ENABLE_REF_TYPES */ @@ -529,11 +557,20 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, goto fail; } } - bh_assert(p == (int32)argc1); wasm_runtime_set_exception(module_inst, NULL); - if (!wasm_runtime_create_exec_env_and_call_wasm(target_inst, target_func, - argc1, argv1)) { +#if WASM_ENABLE_REF_TYPES == 0 + bh_assert(p == (int32)argc1); +#endif + + exec_env = wasm_runtime_get_exec_env_singleton(module_inst); + if (!exec_env) { + wasm_runtime_set_exception(module_inst, + "create singleton exec_env failed"); + goto fail; + } + + if (!wasm_runtime_call_wasm(exec_env, target_func, argc1, argv1)) { goto fail; } @@ -576,7 +613,7 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, os_printf("%.7g:f64", u.val); break; } -#if WASM_ENABLE_REF_TYPES +#if WASM_ENABLE_REF_TYPES != 0 case VALUE_TYPE_FUNCREF: { if (argv1[k] != NULL_REF) @@ -588,16 +625,25 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, } 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); - } +#if UINTPTR_MAX == UINT32_MAX + if (argv1[k] != 0 && argv1[k] != (uint32)-1) + os_printf("%p:ref.extern", (void *)argv1[k]); else os_printf("extern:ref.null"); k++; +#else + union { + uintptr_t val; + uint32 parts[2]; + } u; + u.parts[0] = argv1[k]; + u.parts[1] = argv1[k + 1]; + k += 2; + if (u.val && u.val != (uintptr_t)-1LL) + os_printf("%p:ref.extern", (void *)u.val); + else + os_printf("extern:ref.null"); +#endif break; } #endif diff --git a/core/iwasm/common/wasm_c_api.c b/core/iwasm/common/wasm_c_api.c index 9bffeb6620..fb799de19d 100644 --- a/core/iwasm/common/wasm_c_api.c +++ b/core/iwasm/common/wasm_c_api.c @@ -1235,9 +1235,8 @@ wasm_exporttype_type(const wasm_exporttype_t *export_type) void wasm_val_delete(wasm_val_t *v) { - if (v) { + if (v) wasm_runtime_free(v); - } } void @@ -1562,19 +1561,13 @@ wasm_trap_new_internal(WASMModuleInstanceCommon *inst_comm_rt, #if WASM_ENABLE_INTERP != 0 if (inst_comm_rt->module_type == Wasm_Module_Bytecode) { - if (!(error_info = - wasm_get_exception((WASMModuleInstance *)inst_comm_rt))) { - return NULL; - } + error_info = wasm_get_exception((WASMModuleInstance *)inst_comm_rt); } #endif #if WASM_ENABLE_AOT != 0 if (inst_comm_rt->module_type == Wasm_Module_AoT) { - if (!(error_info = - aot_get_exception((AOTModuleInstance *)inst_comm_rt))) { - return NULL; - } + error_info = aot_get_exception((AOTModuleInstance *)inst_comm_rt); } #endif @@ -2160,7 +2153,7 @@ wasm_module_imports(const wasm_module_t *module, own wasm_importtype_vec_t *out) - import_memory_count); module_name_rt = import->module_name; field_name_rt = import->table_name; - elem_type_rt = VALUE_TYPE_FUNCREF; + elem_type_rt = import->elem_type; min_size = import->table_init_size; max_size = import->table_max_size; } @@ -2563,151 +2556,127 @@ wasm_func_type(const wasm_func_t *func) return wasm_functype_copy(func->type); } -static uint32 -params_to_argv(WASMModuleInstanceCommon *inst_comm_rt, const wasm_val_t *params, - const wasm_valtype_vec_t *param_defs, size_t param_arity, - uint32 *out) +static bool +params_to_argv(const wasm_val_vec_t *params, + const wasm_valtype_vec_t *param_defs, uint32 *argv, + uint32 *ptr_argc) { size_t i = 0; - uint32 argc = 0; - const wasm_val_t *param = NULL; - if (!param_arity) { - return 0; + if (!param_defs->num_elems) { + return true; } - bh_assert(params && param_defs && out); - bh_assert(param_defs->num_elems == param_arity); + if (!params || !params->num_elems || !params->size || !params->data) { + return false; + } - for (i = 0; out && i < param_arity; ++i) { - param = params + i; + *ptr_argc = 0; + for (i = 0; i < param_defs->num_elems; ++i) { + const wasm_val_t *param = params->data + 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; + *(int32 *)argv = param->of.i32; + argv += 1; + *ptr_argc += 1; break; case WASM_I64: - *(int64 *)out = param->of.i64; - out += 2; - argc += 2; + *(int64 *)argv = param->of.i64; + argv += 2; + *ptr_argc += 2; break; case WASM_F32: - *(float32 *)out = param->of.f32; - out += 1; - argc += 1; + *(float32 *)argv = param->of.f32; + argv += 1; + *ptr_argc += 1; break; case WASM_F64: - *(float64 *)out = param->of.f64; - out += 2; - argc += 2; + *(float64 *)argv = param->of.f64; + argv += 2; + *ptr_argc += 2; break; #if WASM_ENABLE_REF_TYPES != 0 case WASM_ANYREF: - if (!wasm_externref_obj2ref(inst_comm_rt, param->of.ref, out)) { - goto failed; - } - - out += 1; - argc += 1; + *(uintptr_t *)argv = (uintptr_t)param->of.ref; + argv += sizeof(uintptr_t) / sizeof(uint32); + *ptr_argc += 1; break; #endif default: LOG_WARNING("unexpected parameter val type %d", param->kind); - goto failed; + return false; } } - return argc; - -failed: - LOG_DEBUG("%s failed", __FUNCTION__); - return 0; + return true; } -static uint32 -argv_to_results(const uint32 *results, const wasm_valtype_vec_t *result_defs, - size_t result_arity, wasm_val_t *out) +static bool +argv_to_results(const uint32 *argv, const wasm_valtype_vec_t *result_defs, + wasm_val_vec_t *results) { - size_t i = 0; - uint32 argc = 0; - const uint32 *result = results; - const wasm_valtype_t *def = NULL; + size_t i = 0, argv_i = 0; + wasm_val_t *result; - if (!result_arity) { - return 0; + if (!result_defs->num_elems) { + return true; } - 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); + if (!results || !results->num_elems || !results->size || !results->data) { + return false; + } - switch (def->kind) { + for (i = 0, result = results->data, argv_i = 0; i < result_defs->num_elems; + i++, result++) { + switch (result_defs->data[i]->kind) { case WASM_I32: { - out->kind = WASM_I32; - out->of.i32 = *(int32 *)result; - result += 1; + result->kind = WASM_I32; + result->of.i32 = *(int32 *)(argv + argv_i); + argv_i += 1; break; } case WASM_I64: { - out->kind = WASM_I64; - out->of.i64 = *(int64 *)result; - result += 2; + result->kind = WASM_I64; + result->of.i64 = *(int64 *)(argv + argv_i); + argv_i += 2; break; } case WASM_F32: { - out->kind = WASM_F32; - out->of.f32 = *(float32 *)result; - result += 1; + result->kind = WASM_F32; + result->of.f32 = *(float32 *)(argv + argv_i); + argv_i += 1; break; } case WASM_F64: { - out->kind = WASM_F64; - out->of.f64 = *(float64 *)result; - result += 2; + result->kind = WASM_F64; + result->of.f64 = *(float64 *)(argv + argv_i); + argv_i += 2; break; } #if WASM_ENABLE_REF_TYPES != 0 case WASM_ANYREF: { - out->kind = WASM_ANYREF; - - if (NULL_REF == *(uint32 *)result) { - out->of.ref = NULL; - } - else { - if (!wasm_externref_ref2obj(*(uint32 *)result, - (void **)&out->of.ref)) { - goto failed; - } - } - - result += 1; + result->kind = WASM_ANYREF; + result->of.ref = + (struct wasm_ref_t *)(*(uintptr_t *)(argv + argv_i)); + argv_i += sizeof(uintptr_t) / sizeof(uint32); break; } #endif default: LOG_WARNING("%s meets unsupported type: %d", __FUNCTION__, - def->kind); - goto failed; + result_defs->data[i]->kind); + return false; } - out++; - argc++; } - return argc; - -failed: - LOG_DEBUG("%s failed", __FUNCTION__); - return 0; + return true; } wasm_trap_t * @@ -2718,7 +2687,7 @@ wasm_func_call(const wasm_func_t *func, const wasm_val_vec_t *params, /* a int64 or float64 parameter means 2 */ uint32 argc = 0; /* a parameter list and a return value list */ - uint32 argv_buf[32], *argv = argv_buf; + uint32 argv_buf[32] = { 0 }, *argv = argv_buf; WASMFunctionInstanceCommon *func_comm_rt = NULL; WASMExecEnv *exec_env = NULL; size_t param_count, result_count, alloc_count; @@ -2776,10 +2745,8 @@ wasm_func_call(const wasm_func_t *func, const wasm_val_vec_t *params, /* copy parametes */ if (param_count - && (!params - || !(argc = params_to_argv(func->inst_comm_rt, params->data, - wasm_functype_params(func->type), - param_count, argv)))) { + && !params_to_argv(params, wasm_functype_params(func->type), argv, + &argc)) { goto failed; } @@ -2798,9 +2765,8 @@ wasm_func_call(const wasm_func_t *func, const wasm_val_vec_t *params, /* copy results */ if (result_count) { - if (!results - || !(argc = argv_to_results(argv, wasm_functype_results(func->type), - result_count, results->data))) { + if (!argv_to_results(argv, wasm_functype_results(func->type), + results)) { goto failed; } results->num_elems = result_count; @@ -3265,7 +3231,7 @@ wasm_table_new_internal(wasm_store_t *store, uint16 table_idx_rt, 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; + val_type_rt = table_aot->elem_type; init_size = table_aot->table_init_size; max_size = table_aot->table_max_size; } @@ -3273,7 +3239,7 @@ wasm_table_new_internal(wasm_store_t *store, uint16 table_idx_rt, AOTTable *table_aot = module_aot->tables + (table_idx_rt - module_aot->import_table_count); - val_type_rt = VALUE_TYPE_FUNCREF; + val_type_rt = table_aot->elem_type; init_size = table_aot->table_init_size; max_size = table_aot->table_max_size; } @@ -3360,13 +3326,12 @@ wasm_table_type(const wasm_table_t *table) own wasm_ref_t * wasm_table_get(const wasm_table_t *table, wasm_table_size_t index) { - uint32 func_idx_rt = NULL_REF; + uint32 ref_idx = NULL_REF; if (!table) { return NULL; } - /* index -> func_idx_rt */ #if WASM_ENABLE_INTERP != 0 if (table->inst_comm_rt->module_type == Wasm_Module_Bytecode) { WASMTableInstance *table_interp = @@ -3375,7 +3340,7 @@ wasm_table_get(const wasm_table_t *table, wasm_table_size_t index) if (index >= table_interp->cur_size) { return NULL; } - func_idx_rt = ((uint32 *)table_interp->base_addr)[index]; + ref_idx = ((uint32 *)table_interp->base_addr)[index]; } #endif @@ -3387,7 +3352,7 @@ wasm_table_get(const wasm_table_t *table, wasm_table_size_t index) if (index >= table_aot->cur_size) { return NULL; } - func_idx_rt = table_aot->data[index]; + ref_idx = table_aot->data[index]; } #endif @@ -3395,35 +3360,48 @@ wasm_table_get(const wasm_table_t *table, wasm_table_size_t index) * a wrong combination of module filetype and compilation flags * also leads to below branch */ - if (func_idx_rt == NULL_REF) { + if (ref_idx == NULL_REF) { return NULL; } - return wasm_ref_new_internal(table->store, WASM_REF_func, func_idx_rt, - table->inst_comm_rt); +#if WASM_ENABLE_REF_TYPES != 0 + if (table->type->val_type->kind == WASM_ANYREF) { + void *externref_obj; + if (!wasm_externref_ref2obj(ref_idx, &externref_obj)) { + return NULL; + } + + return externref_obj; + } + else +#endif + { + return wasm_ref_new_internal(table->store, WASM_REF_func, ref_idx, + table->inst_comm_rt); + } } bool wasm_table_set(wasm_table_t *table, wasm_table_size_t index, - own wasm_ref_t *func_ref) + own wasm_ref_t *ref) { - uint32 *p_func_idx_rt = NULL; - uint32 function_count = 0, ref_idx_rt = NULL_REF; + uint32 *p_ref_idx = NULL; + uint32 function_count = 0; if (!table) { return false; } - if (func_ref && func_ref->kind != WASM_REF_func) { + if (ref +#if WASM_ENABLE_REF_TYPES != 0 + && !(WASM_REF_foreign == ref->kind + && WASM_ANYREF == table->type->val_type->kind) +#endif + && !(WASM_REF_func == ref->kind + && WASM_FUNCREF == table->type->val_type->kind)) { return false; } - if (func_ref) { - ref_idx_rt = func_ref->ref_idx_rt; - wasm_ref_delete(func_ref); - } - - /* index -> *p_func_idx_rt */ #if WASM_ENABLE_INTERP != 0 if (table->inst_comm_rt->module_type == Wasm_Module_Bytecode) { WASMTableInstance *table_interp = @@ -3434,7 +3412,7 @@ wasm_table_set(wasm_table_t *table, wasm_table_size_t index, return false; } - p_func_idx_rt = ((uint32 *)table_interp->base_addr) + index; + p_ref_idx = ((uint32 *)table_interp->base_addr) + index; function_count = ((WASMModuleInstance *)table->inst_comm_rt)->function_count; } @@ -3451,7 +3429,7 @@ wasm_table_set(wasm_table_t *table, wasm_table_size_t index, return false; } - p_func_idx_rt = table_aot->data + index; + p_ref_idx = table_aot->data + index; function_count = module_aot->func_count; } #endif @@ -3460,17 +3438,31 @@ wasm_table_set(wasm_table_t *table, wasm_table_size_t index, * a wrong combination of module filetype and compilation flags * leads to below branch */ - if (!p_func_idx_rt) { + if (!p_ref_idx) { return false; } - if (NULL_REF != ref_idx_rt) { - if (ref_idx_rt >= function_count) { - return false; +#if WASM_ENABLE_REF_TYPES != 0 + if (table->type->val_type->kind == WASM_ANYREF) { + return wasm_externref_obj2ref(table->inst_comm_rt, ref, p_ref_idx); + } + else +#endif + { + if (ref) { + if (NULL_REF != ref->ref_idx_rt) { + if (ref->ref_idx_rt >= function_count) { + return false; + } + } + *p_ref_idx = ref->ref_idx_rt; + wasm_ref_delete(ref); + } + else { + *p_ref_idx = NULL_REF; } } - *p_func_idx_rt = ref_idx_rt; return true; } diff --git a/core/iwasm/common/wasm_c_api_internal.h b/core/iwasm/common/wasm_c_api_internal.h index 919d1524fc..d80bd0d680 100644 --- a/core/iwasm/common/wasm_c_api_internal.h +++ b/core/iwasm/common/wasm_c_api_internal.h @@ -56,7 +56,6 @@ struct wasm_globaltype_t { struct wasm_tabletype_t { uint32 extern_kind; - /* always be WASM_FUNCREF */ wasm_valtype_t *val_type; wasm_limits_t limits; }; diff --git a/core/iwasm/common/wasm_exec_env.h b/core/iwasm/common/wasm_exec_env.h index 86ad1c3e1b..b3e2a0524f 100644 --- a/core/iwasm/common/wasm_exec_env.h +++ b/core/iwasm/common/wasm_exec_env.h @@ -125,10 +125,6 @@ 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 15cb0e5c61..bbef1def46 100644 --- a/core/iwasm/common/wasm_native.c +++ b/core/iwasm/common/wasm_native.c @@ -53,11 +53,30 @@ get_lib_pthread_export_apis(NativeSymbol **p_lib_pthread_apis); uint32 get_libc_emcc_export_apis(NativeSymbol **p_libc_emcc_apis); +static bool +compare_type_with_signautre(uint8 type, const char signature) +{ + const char num_sig_map[] = { 'F', 'f', 'I', 'i' }; + + if (VALUE_TYPE_F64 <= type && type <= VALUE_TYPE_I32 + && signature == num_sig_map[type - VALUE_TYPE_F64]) { + return true; + } + +#if WASM_ENABLE_REF_TYPES != 0 + if ('r' == signature && type == VALUE_TYPE_EXTERNREF) + return true; +#endif + + /* TODO: a v128 parameter */ + return false; +} + static bool check_symbol_signature(const WASMType *type, const char *signature) { const char *p = signature, *p_end; - char sig_map[] = { 'F', 'f', 'I', 'i' }, sig; + char sig; uint32 i = 0; if (!p || strlen(p) < 2) @@ -74,16 +93,12 @@ check_symbol_signature(const WASMType *type, const char *signature) for (i = 0; i < type->param_count; i++) { sig = *p++; - 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 */ + + /* a f64/f32/i64/i32/externref parameter */ + if (compare_type_with_signautre(type->types[i], sig)) continue; + /* a pointer/string paramter */ if (type->types[i] != VALUE_TYPE_I32) /* pointer and string must be i32 type */ return false; @@ -112,8 +127,12 @@ check_symbol_signature(const WASMType *type, const char *signature) if (type->result_count) { if (p >= p_end) return false; - if (*p++ != sig_map[type->types[i] - VALUE_TYPE_F64]) + + /* result types includes: f64,f32,i64,i32,externref */ + if (!compare_type_with_signautre(type->types[i], *p)) return false; + + p++; } if (*p != '\0') diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index be13d05c02..79668cc1e9 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -1199,46 +1199,163 @@ wasm_runtime_lookup_function(WASMModuleInstanceCommon *const module_inst, } #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; +/* (uintptr_t)externref -> (uint32_t)index */ +/* argv -> *ret_argv */ +static bool +wasm_runtime_prepare_call_function(WASMExecEnv *exec_env, + WASMFunctionInstanceCommon *function, + uint32 *argv, uint32 argc, uint32 **ret_argv, + uint32 *ret_argc_param, + uint32 *ret_argc_result) +{ + uint32 *new_argv = NULL, argv_i = 0, new_argv_i = 0, param_i = 0, + result_i = 0; + bool need_param_transform = false, need_result_transform = false; + uint64 size = 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]); + *ret_argc_param = func_type->param_cell_num; + *ret_argc_result = func_type->ret_cell_num; + for (param_i = 0; param_i < func_type->param_count; param_i++) { + if (VALUE_TYPE_EXTERNREF == func_type->types[param_i]) { + need_param_transform = true; } + } - cell_num += wasm_value_type_cell_num(result_type); - i++; + for (result_i = 0; result_i < func_type->result_count; result_i++) { + if (VALUE_TYPE_EXTERNREF + == func_type->types[func_type->param_count + result_i]) { + need_result_transform = true; + } } - wasm_externref_reclaim(exec_env->module_inst); -} + if (!need_param_transform && !need_result_transform) { + *ret_argv = argv; + return true; + } -void -wasm_runtime_prepare_call_function(WASMExecEnv *exec_env, - WASMFunctionInstanceCommon *function) -{ - exec_env->nested_calling_depth++; + if (func_type->param_cell_num >= func_type->ret_cell_num) { + size = sizeof(uint32) * func_type->param_cell_num; + } + else { + size = sizeof(uint32) * func_type->ret_cell_num; + } + + if (!(new_argv = runtime_malloc(size, exec_env->module_inst, NULL, 0))) { + return false; + } + + if (!need_param_transform) { + bh_memcpy_s(new_argv, size, argv, size); + } + else { + for (param_i = 0; param_i < func_type->param_count && argv_i < argc + && new_argv_i < func_type->param_cell_num; + param_i++) { + uint8 param_type = func_type->types[param_i]; + if (VALUE_TYPE_EXTERNREF == param_type) { + void *externref_obj; + uint32 externref_index; + +#if UINTPTR_MAX == UINT32_MAX + externref_obj = (void *)argv[argv_i]; +#else + union { + uintptr_t val; + uint32 parts[2]; + } u; + + u.parts[0] = argv[argv_i]; + u.parts[1] = argv[argv_i + 1]; + externref_obj = (void *)u.val; +#endif + if (!wasm_externref_obj2ref(exec_env->module_inst, + externref_obj, &externref_index)) { + wasm_runtime_free(new_argv); + return false; + } + + new_argv[new_argv_i] = externref_index; + argv_i += sizeof(uintptr_t) / sizeof(uint32); + new_argv_i++; + } + else { + uint16 param_cell_num = wasm_value_type_cell_num(param_type); + uint32 param_size = sizeof(uint32) * param_cell_num; + bh_memcpy_s(new_argv + new_argv_i, param_size, argv + argv_i, + param_size); + argv_i += param_cell_num; + new_argv_i += param_cell_num; + } + } + } + + *ret_argv = new_argv; + return true; } -void +/* (uintptr_t)externref <- (uint32_t)index */ +/* argv <- new_argv */ +static bool wasm_runtime_finalize_call_function(WASMExecEnv *exec_env, WASMFunctionInstanceCommon *function, - bool ret, uint32 *argv) + uint32 *argv, uint32 argc, uint32 *ret_argv) { - exec_env->nested_calling_depth--; - if (!exec_env->nested_calling_depth && ret) { - wasm_runtime_reclaim_externref(exec_env, function, argv); + uint32 argv_i = 0, result_i = 0, ret_argv_i = 0; + WASMType *func_type; + + bh_assert(argv && ret_argv); + + if (argv == ret_argv) { + return true; + } + + func_type = wasm_runtime_get_function_type( + function, exec_env->module_inst->module_type); + bh_assert(func_type); + + for (result_i = 0; result_i < func_type->result_count && argv_i < argc; + result_i++) { + uint8 result_type = func_type->types[func_type->param_count + result_i]; + if (result_type == VALUE_TYPE_EXTERNREF) { + void *externref_obj; +#if UINTPTR_MAX != UINT32_MAX + union { + uintptr_t val; + uint32 parts[2]; + } u; +#endif + + if (!wasm_externref_ref2obj(argv[argv_i], &externref_obj)) { + wasm_runtime_free(argv); + return false; + } + +#if UINTPTR_MAX == UINT32_MAX + ret_argv[ret_argv_i] = (uintptr_t)externref_obj; +#else + u.val = (uintptr_t)externref_obj; + ret_argv[ret_argv_i] = u.parts[0]; + ret_argv[ret_argv_i + 1] = u.parts[1]; +#endif + argv_i += 1; + ret_argv_i += sizeof(uintptr_t) / sizeof(uint32); + } + else { + uint16 result_cell_num = wasm_value_type_cell_num(result_type); + uint32 result_size = sizeof(uint32) * result_cell_num; + bh_memcpy_s(ret_argv + ret_argv_i, result_size, argv + argv_i, + result_size); + argv_i += result_cell_num; + ret_argv_i += result_cell_num; + } } + + wasm_runtime_free(argv); + return true; } #endif @@ -1248,6 +1365,10 @@ wasm_runtime_call_wasm(WASMExecEnv *exec_env, uint32 argv[]) { bool ret = false; + uint32 *new_argv = NULL, param_argc; +#if WASM_ENABLE_REF_TYPES != 0 + uint32 result_argc = 0; +#endif if (!wasm_runtime_exec_env_check(exec_env)) { LOG_ERROR("Invalid exec env stack info."); @@ -1255,34 +1376,53 @@ wasm_runtime_call_wasm(WASMExecEnv *exec_env, } #if WASM_ENABLE_REF_TYPES != 0 - wasm_runtime_prepare_call_function(exec_env, function); + if (!wasm_runtime_prepare_call_function(exec_env, function, argv, argc, + &new_argv, ¶m_argc, + &result_argc)) { + wasm_runtime_set_exception(exec_env->module_inst, + "the arguments conversion is failed"); + return false; + } +#else + new_argv = argv; + param_argc = argc; #endif #if WASM_ENABLE_INTERP != 0 if (exec_env->module_inst->module_type == Wasm_Module_Bytecode) ret = wasm_call_function(exec_env, (WASMFunctionInstance *)function, - argc, argv); + param_argc, new_argv); #endif #if WASM_ENABLE_AOT != 0 if (exec_env->module_inst->module_type == Wasm_Module_AoT) - ret = aot_call_function(exec_env, (AOTFunctionInstance *)function, argc, - argv); + ret = aot_call_function(exec_env, (AOTFunctionInstance *)function, + param_argc, new_argv); #endif + if (!ret) { + if (new_argv != argv) { + wasm_runtime_free(new_argv); + } + return false; + } #if WASM_ENABLE_REF_TYPES != 0 - wasm_runtime_finalize_call_function(exec_env, function, ret, argv); + if (!wasm_runtime_finalize_call_function(exec_env, function, new_argv, + result_argc, argv)) { + wasm_runtime_set_exception(exec_env->module_inst, + "the result conversion is failed"); + return false; + } #endif return ret; } -static uint32 -parse_args_to_uint32_array(WASMType *type, uint32 num_args, wasm_val_t *args, - uint32 *out_argv) +static void +parse_args_to_uint32_array(WASMType *type, wasm_val_t *args, uint32 *out_argv) { uint32 i, p; - for (i = 0, p = 0; i < num_args; i++) { + for (i = 0, p = 0; i < type->param_count; i++) { switch (args[i].kind) { case WASM_I32: out_argv[p++] = args[i].of.i32; @@ -1319,16 +1459,38 @@ parse_args_to_uint32_array(WASMType *type, uint32 num_args, wasm_val_t *args, out_argv[p++] = u.parts[1]; break; } +#if WASM_ENABLE_REF_TYPES != 0 + case WASM_FUNCREF: + { + out_argv[p++] = args[i].of.i32; + break; + } + case WASM_ANYREF: + { +#if UINTPTR_MAX == UINT32_MAX + out_argv[p++] = args[i].of.foreign; +#else + union { + uintptr_t val; + uint32 parts[2]; + } u; + + u.val = (uintptr_t)args[i].of.foreign; + out_argv[p++] = u.parts[0]; + out_argv[p++] = u.parts[1]; +#endif + break; + } +#endif default: bh_assert(0); break; } } - return p; } -static uint32 -parse_uint32_array_to_results(WASMType *type, uint32 argc, uint32 *argv, +static void +parse_uint32_array_to_results(WASMType *type, uint32 *argv, wasm_val_t *out_results) { uint32 i, p; @@ -1374,13 +1536,36 @@ parse_uint32_array_to_results(WASMType *type, uint32 argc, uint32 *argv, out_results[i].of.f64 = u.val; break; } +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_FUNCREF: + { + out_results[i].kind = WASM_I32; + out_results[i].of.i32 = (int32)argv[p++]; + break; + } + case VALUE_TYPE_EXTERNREF: + { +#if UINTPTR_MAX == UINT32_MAX + out_results[i].kind = WASM_ANYREF; + out_results[i].of.foreign = (uintptr_t)argv[p++]; +#else + union { + uintptr_t val; + uint32 parts[2]; + } u; + u.parts[0] = argv[p++]; + u.parts[1] = argv[p++]; + out_results[i].kind = WASM_ANYREF; + out_results[i].of.foreign = u.val; +#endif + break; + } +#endif default: bh_assert(0); break; } } - bh_assert(argc == p); - return type->result_count; } bool @@ -1389,7 +1574,10 @@ 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, module_type; + uint32 argc, *argv, cell_num, total_size, module_type; +#if WASM_ENABLE_REF_TYPES != 0 + uint32 i, param_size_in_double_world = 0, result_size_in_double_world = 0; +#endif WASMType *type; bool ret = false; @@ -1402,8 +1590,23 @@ wasm_runtime_call_wasm_a(WASMExecEnv *exec_env, goto fail1; } +#if WASM_ENABLE_REF_TYPES != 0 + for (i = 0; i < type->param_count; i++) { + param_size_in_double_world += + wasm_value_type_cell_num_outside(type->types[i]); + } + for (i = 0; i < type->result_count; i++) { + result_size_in_double_world += wasm_value_type_cell_num_outside( + type->types[type->param_count + i]); + } + argc = param_size_in_double_world; + cell_num = (argc >= result_size_in_double_world) + ? argc + : result_size_in_double_world; +#else argc = type->param_cell_num; cell_num = (argc > type->ret_cell_num) ? argc : type->ret_cell_num; +#endif if (num_results != type->result_count) { LOG_ERROR( @@ -1425,14 +1628,11 @@ wasm_runtime_call_wasm_a(WASMExecEnv *exec_env, goto fail1; } - argc = parse_args_to_uint32_array(type, num_args, args, argv); - if (!(ret = wasm_runtime_call_wasm(exec_env, function, argc, argv))) + parse_args_to_uint32_array(type, args, argv); + if (!(ret = wasm_runtime_call_wasm(exec_env, function, num_args, argv))) goto fail2; - ret_num = - parse_uint32_array_to_results(type, type->ret_cell_num, argv, results); - bh_assert(ret_num == num_results); - (void)ret_num; + parse_uint32_array_to_results(type, argv, results); fail2: wasm_runtime_free(argv); @@ -1492,6 +1692,20 @@ wasm_runtime_call_wasm_v(WASMExecEnv *exec_env, args[i].kind = WASM_F64; args[i].of.f64 = va_arg(vargs, float64); break; +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_FUNCREF: + { + args[i].kind = WASM_FUNCREF; + args[i].of.i32 = va_arg(vargs, uint32); + break; + } + case VALUE_TYPE_EXTERNREF: + { + args[i].kind = WASM_ANYREF; + args[i].of.foreign = va_arg(vargs, uintptr_t); + break; + } +#endif default: bh_assert(0); break; @@ -1547,13 +1761,21 @@ WASMExecEnv * wasm_runtime_get_exec_env_singleton(WASMModuleInstanceCommon *module_inst) { #if WASM_ENABLE_INTERP != 0 - if (module_inst->module_type == Wasm_Module_Bytecode) + if (module_inst->module_type == Wasm_Module_Bytecode) { + if (!((WASMModuleInstance *)module_inst)->exec_env_singleton) { + wasm_create_exec_env_singleton((WASMModuleInstance *)module_inst); + } return ((WASMModuleInstance *)module_inst)->exec_env_singleton; + } #endif #if WASM_ENABLE_AOT != 0 - if (module_inst->module_type == Wasm_Module_AoT) + if (module_inst->module_type == Wasm_Module_AoT) { + if (!((AOTModuleInstance *)module_inst)->exec_env_singleton.ptr) { + aot_create_exec_env_singleton((AOTModuleInstance *)module_inst); + } return (WASMExecEnv *)((AOTModuleInstance *)module_inst) ->exec_env_singleton.ptr; + } #endif return NULL; } @@ -2497,6 +2719,9 @@ wasm_runtime_invoke_native_raw(WASMExecEnv *exec_env, void *func_ptr, for (i = 0; i < func_type->param_count; i++, argv_dst++) { switch (func_type->types[i]) { case VALUE_TYPE_I32: +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_FUNCREF: +#endif { *(uint32 *)argv_dst = arg_i32 = *argv_src++; if (signature) { @@ -2540,10 +2765,19 @@ wasm_runtime_invoke_native_raw(WASMExecEnv *exec_env, void *func_ptr, *(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++; + { + uint32 externref_idx = *argv_src++; + + void *externref_obj; + + if (!wasm_externref_ref2obj(externref_idx, &externref_obj)) + goto fail; + + bh_memcpy_s(argv_dst, sizeof(uintptr_t), argv_src, + sizeof(uintptr_t)); break; + } #endif default: bh_assert(0); @@ -2560,7 +2794,6 @@ wasm_runtime_invoke_native_raw(WASMExecEnv *exec_env, void *func_ptr, 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; @@ -2572,6 +2805,23 @@ wasm_runtime_invoke_native_raw(WASMExecEnv *exec_env, void *func_ptr, bh_memcpy_s(argv_ret, sizeof(uint32) * 2, argv1, sizeof(uint64)); break; +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_EXTERNREF: + { + uint32 externref_idx; + uint64 externref_obj; + + bh_memcpy_s(&externref_obj, sizeof(uint64), argv1, + sizeof(uint64)); + + if (!wasm_externref_obj2ref(exec_env->module_inst, + (void *)(uintptr_t)externref_obj, + &externref_idx)) + goto fail; + argv_ret[0] = externref_idx; + break; + } +#endif default: bh_assert(0); break; @@ -2634,6 +2884,9 @@ 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; +#if WASM_ENABLE_REF_TYPES != 0 + bool is_aot_func = (NULL == signature); +#endif #if !defined(BUILD_TARGET_RISCV32_ILP32) && !defined(BUILD_TARGET_ARC) uint32 *fps; int n_fps = 0; @@ -2792,6 +3045,9 @@ 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: +#endif { arg_i32 = *argv_src++; @@ -2829,17 +3085,6 @@ 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) { @@ -2959,6 +3204,31 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, break; } #endif /* BUILD_TARGET_RISCV32_ILP32D */ +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_EXTERNREF: + { + uint32 externref_idx = *argv_src++; + + if (is_aot_func) { + if (n_ints < MAX_REG_INTS) + ints[n_ints++] = externref_idx; + else + stacks[n_stacks++] = externref_idx; + } + else { + void *externref_obj; + + if (!wasm_externref_ref2obj(externref_idx, &externref_obj)) + goto fail; + + if (n_ints < MAX_REG_INTS) + ints[n_ints++] = (uintptr_t)externref_obj; + else + stacks[n_stacks++] = (uintptr_t)externref_obj; + } + break; + } +#endif default: bh_assert(0); break; @@ -2982,7 +3252,6 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, 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); @@ -2999,6 +3268,30 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, PUT_F64_TO_ADDR( argv_ret, invokeNative_Float64(func_ptr, argv1, n_stacks)); break; +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_EXTERNREF: + { + if (is_aot_func) { + uint32 externref_idx = + (uint32)invokeNative_Int32(func_ptr, argv1, argc1); + argv_ret[0] = externref_idx; + } + else { + uint32 externref_idx; + void *externref_obj; + + externref_obj = (void *)(uintptr_t)invokeNative_Int32( + func_ptr, argv1, argc1); + + if (!wasm_externref_obj2ref(exec_env->module_inst, + externref_obj, &externref_idx)) + goto fail; + + argv_ret[0] = externref_idx; + } + break; + } +#endif default: bh_assert(0); break; @@ -3060,6 +3353,9 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, uint32 ext_ret_count = result_count > 1 ? result_count - 1 : 0; uint64 size; bool ret = false; +#if WASM_ENABLE_REF_TYPES != 0 + bool is_aot_func = (NULL == signature); +#endif #if defined(BUILD_TARGET_X86_32) argc1 = argc + ext_ret_count + 2; @@ -3083,6 +3379,9 @@ 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: +#endif { arg_i32 = *argv++; @@ -3129,12 +3428,26 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, argv1[j++] = *argv++; break; case VALUE_TYPE_F32: + argv1[j++] = *argv++; + break; #if WASM_ENABLE_REF_TYPES != 0 - case VALUE_TYPE_FUNCREF: case VALUE_TYPE_EXTERNREF: -#endif - argv1[j++] = *argv++; + { + uint32 externref_idx = *argv++; + if (is_aot_func) { + argv1[j++] = externref_idx; + } + else { + void *externref_obj; + + if (!wasm_externref_ref2obj(externref_idx, &externref_obj)) + goto fail; + + argv1[j++] = (uintptr_t)externref_obj; + } break; + } +#endif default: bh_assert(0); break; @@ -3154,7 +3467,6 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, 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); @@ -3171,6 +3483,26 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, PUT_F64_TO_ADDR(argv_ret, invokeNative_Float64(func_ptr, argv1, argc1)); break; +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_EXTERNREF: + { + if (is_aot_func) { + uint32 externref_idx = + (uint32)invokeNative_Int32(func_ptr, argv1, argc1); + argv_ret[0] = externref_idx; + } + else { + void *externref_obj = (void *)(uintptr_t)invokeNative_Int32( + func_ptr, argv1, argc1); + uint32 externref_idx; + if (!wasm_externref_obj2ref(exec_env->module_inst, + externref_obj, &externref_idx)) + goto fail; + argv_ret[0] = externref_idx; + } + break; + } +#endif default: bh_assert(0); break; @@ -3281,12 +3613,16 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, uint32 *argv_ret) { WASMModuleInstanceCommon *module = wasm_runtime_get_module_inst(exec_env); - uint64 argv_buf[32], *argv1 = argv_buf, *ints, *stacks, size, arg_i64; + uint64 argv_buf[32] = { 0 }, *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_REF_TYPES != 0 + bool is_aot_func = (NULL == signature); +#endif #ifndef BUILD_TARGET_RISCV64_LP64 #if WASM_ENABLE_SIMD == 0 uint64 *fps; @@ -3336,6 +3672,9 @@ 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: +#endif { arg_i32 = *argv_src++; arg_i64 = arg_i32; @@ -3397,13 +3736,28 @@ 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++; + { + uint32 externref_idx = *argv_src++; + if (is_aot_func) { + if (n_ints < MAX_REG_INTS) + ints[n_ints++] = externref_idx; + else + stacks[n_stacks++] = externref_idx; + } + else { + void *externref_obj; + + if (!wasm_externref_ref2obj(externref_idx, &externref_obj)) + goto fail; + + if (n_ints < MAX_REG_INTS) + ints[n_ints++] = (uintptr_t)externref_obj; + else + stacks[n_stacks++] = (uintptr_t)externref_obj; + } break; + } #endif #if WASM_ENABLE_SIMD != 0 case VALUE_TYPE_V128: @@ -3442,7 +3796,6 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, 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); @@ -3459,6 +3812,26 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, PUT_F64_TO_ADDR( argv_ret, invokeNative_Float64(func_ptr, argv1, n_stacks)); break; +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_EXTERNREF: + { + if (is_aot_func) { + argv_ret[0] = invokeNative_Int32(func_ptr, argv1, n_stacks); + } + else { + uint32 externref_idx; + void *externref_obj = (void *)(uintptr_t)invokeNative_Int64( + func_ptr, argv1, n_stacks); + + if (!wasm_externref_obj2ref(exec_env->module_inst, + externref_obj, &externref_idx)) + goto fail; + + argv_ret[0] = externref_idx; + } + break; + } +#endif #if WASM_ENABLE_SIMD != 0 case VALUE_TYPE_V128: *(v128 *)argv_ret = @@ -3709,10 +4082,24 @@ bool wasm_externref_obj2ref(WASMModuleInstanceCommon *module_inst, void *extern_obj, uint32 *p_externref_idx) { - LookupExtObj_UserData lookup_user_data; + LookupExtObj_UserData lookup_user_data = { 0 }; ExternRefMapNode *node; uint32 externref_idx; + /* + * to catch a parameter from `wasm_application_execute_func`, + * which represents a string 'null' + */ +#if UINTPTR_MAX == UINT32_MAX + if ((uint32)-1 == (uintptr_t)extern_obj) { +#else + if ((uint64)-1LL == (uintptr_t)extern_obj) { +#endif + *p_externref_idx = NULL_REF; + return true; + } + + /* in a wrapper, extern_obj could be any value */ lookup_user_data.node.extern_obj = extern_obj; lookup_user_data.node.module_inst = module_inst; lookup_user_data.found = false; @@ -3764,8 +4151,10 @@ wasm_externref_ref2obj(uint32 externref_idx, void **p_extern_obj) { ExternRefMapNode *node; + /* catch a `ref.null` vairable */ if (externref_idx == NULL_REF) { - return false; + *p_extern_obj = NULL; + return true; } os_mutex_lock(&externref_lock); @@ -4170,14 +4559,9 @@ argv_to_params(wasm_val_t *out_params, const uint32 *argv, WASMType *func_type) case VALUE_TYPE_EXTERNREF: param->kind = WASM_ANYREF; - if (NULL_REF == *argv) { - param->of.ref = NULL; - } - else { - if (!wasm_externref_ref2obj(*argv, - (void **)¶m->of.ref)) { - return false; - } + if (!wasm_externref_ref2obj(*argv, + (void **)¶m->of.foreign)) { + return false; } argv++; @@ -4213,8 +4597,8 @@ results_to_argv(WASMModuleInstanceCommon *module_inst, uint32 *out_argv, break; #if WASM_ENABLE_REF_TYPES != 0 case VALUE_TYPE_EXTERNREF: - if (!wasm_externref_obj2ref(module_inst, result->of.ref, - argv)) { + if (!wasm_externref_obj2ref(module_inst, + (void *)result->of.foreign, argv)) { return false; } argv++; @@ -4234,17 +4618,19 @@ wasm_runtime_invoke_c_api_native(WASMModuleInstanceCommon *module_inst, 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_buf[16] = { 0 }, results_buf[4] = { 0 }; wasm_val_t *params = params_buf, *results = results_buf; wasm_trap_t *trap = NULL; bool ret = false; wasm_val_vec_t params_vec, results_vec; - 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 (func_type->param_count > 16) { + if (!(params = + runtime_malloc(sizeof(wasm_val_t) * func_type->param_count, + module_inst, NULL, 0))) { + wasm_runtime_set_exception(module_inst, "allocate memory failed"); + return false; + } } if (!argv_to_params(params, argv, func_type)) { @@ -4252,11 +4638,13 @@ wasm_runtime_invoke_c_api_native(WASMModuleInstanceCommon *module_inst, 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 (func_type->result_count > 4) { + if (!(results = + runtime_malloc(sizeof(wasm_val_t) * func_type->result_count, + module_inst, NULL, 0))) { + wasm_runtime_set_exception(module_inst, "allocate memory failed"); + goto fail; + } } params_vec.data = params; diff --git a/core/iwasm/common/wasm_runtime_common.h b/core/iwasm/common/wasm_runtime_common.h index c84463aa20..ce188c8d18 100644 --- a/core/iwasm/common/wasm_runtime_common.h +++ b/core/iwasm/common/wasm_runtime_common.h @@ -525,11 +525,6 @@ bool wasm_runtime_call_indirect(WASMExecEnv *exec_env, uint32 element_indices, uint32 argc, uint32 argv[]); -bool -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); @@ -813,16 +808,6 @@ wasm_runtime_dump_module_inst_mem_consumption( 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 - bool wasm_runtime_get_export_func_type(const WASMModuleCommon *module_comm, const WASMExport *export_, WASMType **out); diff --git a/core/iwasm/compilation/aot.h b/core/iwasm/compilation/aot.h index 3254eaf2cd..78dc78e203 100644 --- a/core/iwasm/compilation/aot.h +++ b/core/iwasm/compilation/aot.h @@ -96,6 +96,7 @@ typedef struct AOTMemInitData { typedef struct AOTImportTable { char *module_name; char *table_name; + uint32 elem_type; uint32 table_flags; uint32 table_init_size; uint32 table_max_size; diff --git a/core/iwasm/compilation/aot_emit_aot_file.c b/core/iwasm/compilation/aot_emit_aot_file.c index f36f526af9..e19cfaa185 100644 --- a/core/iwasm/compilation/aot_emit_aot_file.c +++ b/core/iwasm/compilation/aot_emit_aot_file.c @@ -1398,6 +1398,7 @@ aot_emit_table_info(uint8 *buf, uint8 *buf_end, uint32 *p_offset, * 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].elem_type); 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); diff --git a/core/iwasm/include/wasm_export.h b/core/iwasm/include/wasm_export.h index 6b66953407..5a6d4e8dff 100644 --- a/core/iwasm/include/wasm_export.h +++ b/core/iwasm/include/wasm_export.h @@ -155,16 +155,17 @@ enum wasm_valkind_enum { #ifndef WASM_VAL_T_DEFINED #define WASM_VAL_T_DEFINED -struct wasm_ref_t; typedef struct wasm_val_t { wasm_valkind_t kind; union { + /* also represent a function index */ int32_t i32; int64_t i64; float f32; double f64; - struct wasm_ref_t *ref; + /* represent a foreign object, aka externref in .wat */ + uintptr_t foreign; } of; } wasm_val_t; #endif @@ -790,6 +791,7 @@ wasm_runtime_get_native_addr_range(wasm_module_inst_t module_inst, * 'I': the parameter is i64 type * 'f': the parameter is f32 type * 'F': the parameter is f64 type + * 'r': the parameter is externref type, it should be a uintptr_t in host * '*': the parameter is a pointer (i32 in WASM), and runtime will * auto check its boundary before calling the native function. * If it is followed by '~', the checked length of the pointer diff --git a/core/iwasm/interpreter/wasm.h b/core/iwasm/interpreter/wasm.h index 6db1a70557..9160350bef 100644 --- a/core/iwasm/interpreter/wasm.h +++ b/core/iwasm/interpreter/wasm.h @@ -544,6 +544,19 @@ wasm_get_cell_num(const uint8 *types, uint32 type_count) return cell_num; } +#if WASM_ENABLE_REF_TYPES != 0 +inline static uint16 +wasm_value_type_cell_num_outside(uint8 value_type) +{ + if (VALUE_TYPE_EXTERNREF == value_type) { + return sizeof(uintptr_t) / sizeof(uint32); + } + else { + return wasm_value_type_cell_num(value_type); + } +} +#endif + inline static bool wasm_type_equal(const WASMType *type1, const WASMType *type2) { diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index 2de827c802..0a5ba3dc63 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -1748,16 +1748,8 @@ 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) @@ -1770,9 +1762,14 @@ wasm_create_exec_env_and_call_function(WASMModuleInstance *module_inst, 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); + WASMExecEnv *exec_env = NULL; + + if (module_inst->exec_env_singleton) { + return true; + } + + 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; diff --git a/core/shared/platform/windows/platform_internal.h b/core/shared/platform/windows/platform_internal.h index db94241630..5c50f9e30e 100644 --- a/core/shared/platform/windows/platform_internal.h +++ b/core/shared/platform/windows/platform_internal.h @@ -74,6 +74,9 @@ os_mem_decommit(void *ptr, size_t size); #define os_thread_local_attribute __declspec(thread) +#define strncasecmp _strnicmp +#define strcasecmp _stricmp + #if WASM_DISABLE_HW_BOUND_CHECK == 0 #if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64) diff --git a/doc/export_native_api.md b/doc/export_native_api.md index e507c5c41e..fba83d3ea8 100644 --- a/doc/export_native_api.md +++ b/doc/export_native_api.md @@ -85,10 +85,11 @@ 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 or externref (for externref, developer should use `wasm_externref_obj2ref()` to map host object to externref index firstly) +- '**i**': i32 - '**I**': i64 - '**f**': f32 - '**F**': f64 +- '**r**': externref (has to be the value of a `uintptr_t` variable) - '**\***': the parameter is a buffer address in WASM application - '**~**': the parameter is the byte length of WASM buffer as referred by preceding argument "\*". It must follow after '*', otherwise, registration will fail - '**$**': the parameter is a string in WASM application diff --git a/doc/ref_types.md b/doc/ref_types.md index ed37411f3c..7fefa999d5 100644 --- a/doc/ref_types.md +++ b/doc/ref_types.md @@ -1,22 +1,9 @@ # 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. +WebAssembly [reference-types](https://github.com/WebAssembly/reference-types) proposal introduces two new types `funcref` and `externref`. With `externref`, It is easier and more efficient to interoperate with host environment. Host references are able to be represented directly by type `externref`. -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. +WAMR has implemented the reference-types proposal. WAMR allows a native method to pass a host object to a WASM application as an `externref` parameter or receives a host object from a WASM application as an `externref` result. Internally, WAMR won't try to parse or dereference `externref`. It is an opaque type. -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. +The restriction of using `externref` in a native method is the host object has to be the value of a `unintptr_t` variable. In other words, it takes **8 bytes** on 64-bit machine and **4 bytes** on 32-bit machines. Please keep that in mind especially when calling `wasm_runtime_call_wasm`. Please ref to the [sample](../samples/ref-types) for more details. diff --git a/samples/ref-types/CMakeLists.txt b/samples/ref-types/CMakeLists.txt index b3dd722b6f..229afd3c43 100644 --- a/samples/ref-types/CMakeLists.txt +++ b/samples/ref-types/CMakeLists.txt @@ -116,7 +116,7 @@ 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 + COMMAND ${WAT2WASM} ${WAT_FILE} --enable-reference-types -o ${PROJECT_BINARY_DIR}/hello.wasm DEPENDS ${WAT_FILE} BYPRODUCTS ${PROJECT_BINARY_DIR}/hello.wasm VERBATIM diff --git a/samples/ref-types/src/hello.c b/samples/ref-types/src/hello.c index b353c9901b..024d026b86 100644 --- a/samples/ref-types/src/hello.c +++ b/samples/ref-types/src/hello.c @@ -13,52 +13,170 @@ 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; - } +static uintptr_t global_objects[10] = { 0 }; - snprintf(buf, sizeof(buf), "%%%ds", len); - - printf("## write string to file: "); - printf(buf, str); +int32 +local_cmp_externref(wasm_exec_env_t exec_env, uintptr_t externref_a, + uintptr_t externref_b) +{ + return externref_a == externref_b; +} - return fprintf(file, buf, str); +int32 +local_chk_externref(wasm_exec_env_t exec_env, int32 index, uintptr_t externref) +{ + return externref == global_objects[index]; } /* clang-format off */ static NativeSymbol native_symbols[] = { - { "test_write", test_write_wrapper, "(i*~)i", NULL } + { "native-cmp-externref", local_cmp_externref, "(II)i", NULL }, + { "native-chk-externref", local_chk_externref, "(iI)i", NULL }, }; /* clang-format on */ +static inline void +local_set_externref(int32 index, uintptr_t externref) +{ + global_objects[index] = externref; +} + +static WASMFunctionInstanceCommon *wasm_set_externref_ptr; +static WASMFunctionInstanceCommon *wasm_get_externref_ptr; +static WASMFunctionInstanceCommon *wasm_cmp_externref_ptr; + +static bool +wasm_set_externref(wasm_exec_env_t exec_env, wasm_module_inst_t inst, + int32 index, uintptr_t externref) +{ + union { + uintptr_t val; + uint32 parts[2]; + } u; + uint32 argv[3] = { 0 }; + + if (!exec_env || !wasm_set_externref_ptr) { + return false; + } + + u.val = externref; + argv[0] = index; + argv[1] = u.parts[0]; + argv[2] = u.parts[1]; + if (!wasm_runtime_call_wasm(exec_env, wasm_set_externref_ptr, 2, argv)) { + const char *exception; + if ((exception = wasm_runtime_get_exception(inst))) { + printf("Exception: %s\n", exception); + } + return false; + } + + return true; +} + +static bool +wasm_get_externref(wasm_exec_env_t exec_env, wasm_module_inst_t inst, + int32 index, uintptr_t *ret_externref) +{ + wasm_val_t results[1] = { 0 }; + + if (!exec_env || !wasm_get_externref_ptr || !ret_externref) { + return false; + } + + if (!wasm_runtime_call_wasm_v(exec_env, wasm_get_externref_ptr, 1, results, + 1, index)) { + const char *exception; + if ((exception = wasm_runtime_get_exception(inst))) { + printf("Exception: %s\n", exception); + } + return false; + } + + if (WASM_ANYREF != results[0].kind) { + return false; + } + + *ret_externref = results[0].of.foreign; + return true; +} + +static bool +wasm_cmp_externref(wasm_exec_env_t exec_env, wasm_module_inst_t inst, + int32 index, uintptr_t externref, int32 *ret_result) +{ + wasm_val_t results[1] = { 0 }; + wasm_val_t arguments[2] = { + { .kind = WASM_I32, .of.i32 = index }, + { .kind = WASM_ANYREF, .of.foreign = externref }, + }; + + if (!exec_env || !wasm_cmp_externref_ptr || !ret_result) { + return false; + } + + if (!wasm_runtime_call_wasm_a(exec_env, wasm_cmp_externref_ptr, 1, results, + 2, arguments)) { + const char *exception; + if ((exception = wasm_runtime_get_exception(inst))) { + printf("Exception: %s\n", exception); + } + return false; + } + + if (results[0].kind != WASM_I32) { + return false; + } + + *ret_result = results[0].of.i32; + return true; +} + +static bool +set_and_cmp(wasm_exec_env_t exec_env, wasm_module_inst_t inst, int32 i, + uintptr_t externref) +{ + int32 cmp_result = 0; + uintptr_t wasm_externref = 0; + + wasm_set_externref(exec_env, inst, i, externref); + local_set_externref(i, externref); + + wasm_get_externref(exec_env, inst, 0, &wasm_externref); + if (!local_chk_externref(exec_env, 0, wasm_externref)) { + printf("#%d, In host language world Wasm Externref 0x%lx Vs. Native " + "Externref 0x%lx FAILED\n", + i, wasm_externref, externref); + return false; + } + + if (!wasm_cmp_externref(exec_env, inst, i, global_objects[i], &cmp_result) + || !cmp_result) { + printf("#%d, In Wasm world Native Externref 0x%lx Vs, Wasm Externref " + "FAILED\n", + i, global_objects[i]); + return false; + } + + return true; +} + int main(int argc, char *argv[]) { char *wasm_file = "hello.wasm"; uint8 *wasm_file_buf = NULL; - uint32 wasm_file_size, externref_idx; + 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; - 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; + const uint64 big_number = 0x123456789abc; memset(&init_args, 0, sizeof(RuntimeInitArgs)); @@ -90,13 +208,13 @@ main(int argc, char *argv[]) /* 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; + goto fail; /* 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; + goto fail; } /* instantiate the module */ @@ -104,62 +222,66 @@ main(int argc, char *argv[]) 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; + goto fail; } + /* create an execution env */ if (!(exec_env = wasm_runtime_create_exec_env(wasm_module_inst, stack_size))) { printf("%s\n", "create exec env failed"); - goto fail4; + goto fail; } - printf("## open file test.txt\n"); - if (!(file = fopen("test.txt", "wb+"))) { - printf("%s\n", "open file text.txt failed"); - goto fail5; + /* lookup function instance */ + if (!(wasm_cmp_externref_ptr = wasm_runtime_lookup_function( + wasm_module_inst, "cmp-externref", NULL))) { + printf("%s\n", "lookup function cmp-externref failed"); + goto fail; } - 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; + if (!(wasm_get_externref_ptr = wasm_runtime_lookup_function( + wasm_module_inst, "get-externref", NULL))) { + printf("%s\n", "lookup function get-externref failed"); + goto fail; } - printf("## call wasm function with externref index\n"); - argv1[0] = externref_idx; - wasm_runtime_call_wasm(exec_env, func_inst, 1, argv1); + if (!(wasm_set_externref_ptr = wasm_runtime_lookup_function( + wasm_module_inst, "set-externref", NULL))) { + printf("%s\n", "lookup function set-externref failed"); + goto fail; + } - if ((exce = wasm_runtime_get_exception(wasm_module_inst))) { - printf("Exception: %s\n", exce); + /* test with NULL */ + if (!set_and_cmp(exec_env, wasm_module_inst, 0, 0) + || !set_and_cmp(exec_env, wasm_module_inst, 1, big_number + 1) + || !set_and_cmp(exec_env, wasm_module_inst, 2, big_number + 2) + || !set_and_cmp(exec_env, wasm_module_inst, 3, big_number + 3)) { + goto fail; } -fail6: - fclose(file); + printf("GREAT! PASS ALL CHKs\n"); -fail5: +fail: /* destroy exec env */ - wasm_runtime_destroy_exec_env(exec_env); + if (exec_env) { + wasm_runtime_destroy_exec_env(exec_env); + } -fail4: /* destroy the module instance */ - wasm_runtime_deinstantiate(wasm_module_inst); + if (wasm_module_inst) { + wasm_runtime_deinstantiate(wasm_module_inst); + } -fail3: /* unload the module */ - wasm_runtime_unload(wasm_module); + if (wasm_module) { + wasm_runtime_unload(wasm_module); + } -fail2: /* free the file buffer */ - wasm_runtime_free(wasm_file_buf); + if (wasm_file_buf) { + 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 index 1a0f21db3c..3c2d2f96de 100644 --- a/samples/ref-types/src/hello.wat +++ b/samples/ref-types/src/hello.wat @@ -2,21 +2,43 @@ ;; 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 + (type $t0 (func (param i32 externref) (result i32))) + + (import "env" "native-cmp-externref" + (func $native-cmp-externref (param externref externref) (result i32)) + ) + + (import "env" "native-chk-externref" + (func $native-chk-externref (param i32 externref) (result i32)) + ) + + (table $t1 8 8 externref) + (table $t2 funcref + (elem + $native-cmp-externref + $native-chk-externref + ) + ) + + (func (export "set-externref") (param $i i32) (param $r externref) + (table.set $t1 (local.get $i) (local.get $r)) + ) + + (func (export "get-externref") (param $i i32) (result externref) + (table.get $t1 (local.get $i)) + ) + + (func (export "cmp-externref") (param $i i32) (param $r externref) (result i32) + (table.get $t1 (local.get $i)) + (local.get $r) + (call $native-cmp-externref) + ) + + (func (export "chk-externref") (param $i i32) (param $r externref) (result i32) + (call_indirect $t2 (type $t0) + (local.get $i) + (local.get $r) + (i32.const 1) + ) ) ) diff --git a/samples/wasm-c-api/src/callback.c b/samples/wasm-c-api/src/callback.c index b62d72894d..fc6c109db5 100644 --- a/samples/wasm-c-api/src/callback.c +++ b/samples/wasm-c-api/src/callback.c @@ -35,7 +35,7 @@ void wasm_val_print(wasm_val_t val) { // A function to be called from Wasm code. own wasm_trap_t* print_callback( - const wasm_val_vec_t *args, wasm_val_vec_t *results + const wasm_val_vec_t* args, wasm_val_vec_t* results ) { printf("Calling back...\n> "); wasm_val_print(args->data[0]); @@ -48,7 +48,7 @@ own wasm_trap_t* print_callback( // A function closure. own wasm_trap_t* closure_callback( - void* env, const wasm_val_vec_t *args, wasm_val_vec_t *results + void* env, const wasm_val_vec_t* args, wasm_val_vec_t* results ) { int i = *(int*)env; printf("Calling back closure...\n"); @@ -113,11 +113,10 @@ int main(int argc, const char* argv[]) { // Instantiate. printf("Instantiating module...\n"); - - wasm_extern_vec_t imports; - wasm_extern_vec_new(&imports, 2, (wasm_extern_t *[]) { + wasm_extern_t* externs[] = { wasm_func_as_extern(print_func), wasm_func_as_extern(closure_func) - }); + }; + wasm_extern_vec_t imports = WASM_ARRAY_VEC(externs); own wasm_instance_t* instance = wasm_instance_new(store, module, &imports, NULL); if (!instance) { @@ -147,9 +146,10 @@ int main(int argc, const char* argv[]) { // Call. printf("Calling export...\n"); - wasm_val_vec_t args, results; - wasm_val_vec_new(&args, 2, (wasm_val_t[]){ WASM_I32_VAL(3), WASM_I32_VAL(4) }); - wasm_val_vec_new(&results, 1, (wasm_val_t[]) { WASM_INIT_VAL }); + wasm_val_t as[2] = { WASM_I32_VAL(3), WASM_I32_VAL(4) }; + wasm_val_t rs[1] = { WASM_INIT_VAL }; + wasm_val_vec_t args = WASM_ARRAY_VEC(as); + wasm_val_vec_t results = WASM_ARRAY_VEC(rs); if (wasm_func_call(run_func, &args, &results)) { printf("> Error calling function!\n"); return 1; @@ -159,7 +159,7 @@ int main(int argc, const char* argv[]) { // Print result. printf("Printing result...\n"); - printf("> %u\n", results.data[0].of.i32); + printf("> %u\n", rs[0].of.i32); // Shut down. printf("Shutting down...\n"); diff --git a/samples/wasm-c-api/src/callback_chain.c b/samples/wasm-c-api/src/callback_chain.c index 1b5f1b5941..64f42d960d 100644 --- a/samples/wasm-c-api/src/callback_chain.c +++ b/samples/wasm-c-api/src/callback_chain.c @@ -61,10 +61,7 @@ enum EXPORT_ITEM_NAME { DEFINE_FUNCTION(get_pairs) { - wasm_val_vec_t arg, ret; - wasm_val_vec_new(&ret, 1, (wasm_val_t []){ WASM_INIT_VAL }); - wasm_val_vec_new(&arg, 1, (wasm_val_t []){ WASM_I32_VAL(24) }); - call_wasm_function(e_malloc, &arg, &ret, "malloc"); + call_wasm_function(e_malloc, args, results, "malloc"); return NULL; } @@ -204,9 +201,6 @@ main(int argc, const char *argv[]) IMPORT_FUNCTION_LIST(IMPORT_FUNCTION_VARIABLE_NAME) #undef IMPORT_FUNCTION_VARIABLE_NAME - wasm_extern_vec_t imports; - wasm_extern_vec_new_uninitialized(&imports, 10); - #define CREATE_WASM_FUNCTION(name, index, CREATE_FUNC_TYPE) \ { \ own wasm_functype_t *type = CREATE_FUNC_TYPE; \ @@ -219,13 +213,13 @@ main(int argc, const char *argv[]) IMPORT_FUNCTION_LIST(CREATE_WASM_FUNCTION) #undef CREATE_WASM_FUNCTION + wasm_extern_t *fs[10] = {0}; #define ADD_TO_FUNCTION_LIST(name, index, ...) \ - imports.data[index] = wasm_func_as_extern(function_##name); \ - imports.num_elems += 1; + fs[index] = wasm_func_as_extern(function_##name); IMPORT_FUNCTION_LIST(ADD_TO_FUNCTION_LIST) -#undef CREATE_IMPORT_FUNCTION - +#undef ADD_TO_FUNCTION_LIST + wasm_extern_vec_t imports = WASM_ARRAY_VEC(fs); own wasm_instance_t *instance = wasm_instance_new(store, module, &imports, NULL); if (!instance) { diff --git a/samples/wasm-c-api/src/global.c b/samples/wasm-c-api/src/global.c index dab1bb49af..f16af9cc90 100644 --- a/samples/wasm-c-api/src/global.c +++ b/samples/wasm-c-api/src/global.c @@ -39,10 +39,11 @@ wasm_func_t* get_export_func(const wasm_extern_vec_t* exports, size_t i) { #define check_call(func, type, expected) \ { \ - wasm_val_vec_t results; \ - wasm_val_vec_new_uninitialized(&results, 1); \ - wasm_func_call(func, NULL, &results); \ - check(results.data[0], type, expected); \ + wasm_val_t vs[1]; \ + wasm_val_vec_t args = WASM_EMPTY_VEC; \ + wasm_val_vec_t results = WASM_ARRAY_VEC(vs); \ + wasm_func_call(func, &args, &results); \ + check(vs[0], type, expected); \ } @@ -116,19 +117,13 @@ int main(int argc, const char* argv[]) { // Instantiate. printf("Instantiating module...\n"); - /*const wasm_extern_t* imports1[] = { + wasm_extern_t* externs[] = { 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) - };*/ - wasm_extern_vec_t imports; - wasm_extern_vec_new(&imports, 4, (wasm_extern_t* []) { - 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) - }); + }; + wasm_extern_vec_t imports = WASM_ARRAY_VEC(externs); own wasm_instance_t* instance = wasm_instance_new(store, module, &imports, NULL); if (!instance) { @@ -208,18 +203,19 @@ int main(int argc, const char* argv[]) { check_call(get_var_i64_export, i64, 38); // Modify variables through calls and check again. - wasm_val_vec_t args73; - wasm_val_vec_new(&args73, 1, (wasm_val_t []){ WASM_F32_VAL(73) }); - wasm_func_call(set_var_f32_import, &args73, NULL); - wasm_val_vec_t args74; - wasm_val_vec_new(&args74, 1, (wasm_val_t []){ WASM_I64_VAL(74) }); - wasm_func_call(set_var_i64_import, &args74, NULL); - wasm_val_vec_t args77; - wasm_val_vec_new(&args77, 1, (wasm_val_t []){ WASM_F32_VAL(77) }); - wasm_func_call(set_var_f32_export, &args77, NULL); - wasm_val_vec_t args78; - wasm_val_vec_new(&args78, 1, (wasm_val_t []){ WASM_I64_VAL(78) }); - wasm_func_call(set_var_i64_export, &args78, NULL); + wasm_val_vec_t res = WASM_EMPTY_VEC; + wasm_val_t vs73[] = { WASM_F32_VAL(73) }; + wasm_val_vec_t args73 = WASM_ARRAY_VEC(vs73); + wasm_func_call(set_var_f32_import, &args73, &res); + wasm_val_t vs74[] = { WASM_I64_VAL(74) }; + wasm_val_vec_t args74 = WASM_ARRAY_VEC(vs74); + wasm_func_call(set_var_i64_import, &args74, &res); + wasm_val_t vs77[] = { WASM_F32_VAL(77) }; + wasm_val_vec_t args77 = WASM_ARRAY_VEC(vs77); + wasm_func_call(set_var_f32_export, &args77, &res); + wasm_val_t vs78[] = { WASM_I64_VAL(78) }; + wasm_val_vec_t args78 = WASM_ARRAY_VEC(vs78); + wasm_func_call(set_var_i64_export, &args78, &res); check_global(var_f32_import, f32, 73); check_global(var_i64_import, i64, 74); diff --git a/samples/wasm-c-api/src/hello.c b/samples/wasm-c-api/src/hello.c index 9a6834b56f..6b566447b3 100644 --- a/samples/wasm-c-api/src/hello.c +++ b/samples/wasm-c-api/src/hello.c @@ -66,9 +66,8 @@ int main(int argc, const char* argv[]) { // Instantiate. printf("Instantiating module...\n"); - wasm_extern_vec_t imports; - wasm_extern_vec_new(&imports, 1, (wasm_extern_t* []) { wasm_func_as_extern(hello_func) }); - + wasm_extern_t* externs[] = { wasm_func_as_extern(hello_func) }; + wasm_extern_vec_t imports = WASM_ARRAY_VEC(externs); own wasm_instance_t* instance = wasm_instance_new(store, module, &imports, NULL); if (!instance) { @@ -98,7 +97,9 @@ int main(int argc, const char* argv[]) { // Call. printf("Calling export...\n"); - if (wasm_func_call(run_func, NULL, NULL)) { + wasm_val_vec_t args = WASM_EMPTY_VEC; + wasm_val_vec_t results = WASM_EMPTY_VEC; + if (wasm_func_call(run_func, &args, &results)) { printf("> Error calling function!\n"); return 1; } @@ -114,4 +115,3 @@ int main(int argc, const char* argv[]) { printf("Done.\n"); return 0; } - diff --git a/samples/wasm-c-api/src/hostref.c b/samples/wasm-c-api/src/hostref.c index d802c2b661..211f0cffd0 100644 --- a/samples/wasm-c-api/src/hostref.c +++ b/samples/wasm-c-api/src/hostref.c @@ -47,21 +47,23 @@ wasm_table_t* get_export_table(const wasm_extern_vec_t* exports, size_t i) { own wasm_ref_t* call_v_r(const wasm_func_t* func) { printf("call_v_r... "); fflush(stdout); - wasm_val_vec_t rs; - wasm_val_vec_new_uninitialized(&rs, 1); - if (wasm_func_call(func, NULL, &rs)) { + wasm_val_t rs[] = { WASM_INIT_VAL }; + wasm_val_vec_t args = WASM_EMPTY_VEC; + wasm_val_vec_t results = WASM_ARRAY_VEC(rs); + if (wasm_func_call(func, &args, &results)) { printf("> Error calling function!\n"); exit(1); } printf("okay\n"); - return rs.data[0].of.ref; + return rs[0].of.ref; } void call_r_v(const wasm_func_t* func, wasm_ref_t* ref) { printf("call_r_v... "); fflush(stdout); - wasm_val_vec_t vs; - wasm_val_vec_new(&vs, 1, (wasm_val_t []){ WASM_REF_VAL(ref) }); - if (wasm_func_call(func, &vs, NULL)) { + wasm_val_t vs[1] = { WASM_REF_VAL(ref) }; + wasm_val_vec_t args = WASM_ARRAY_VEC(vs); + wasm_val_vec_t results = WASM_EMPTY_VEC; + if (wasm_func_call(func, &args, &results)) { printf("> Error calling function!\n"); exit(1); } @@ -70,22 +72,24 @@ void call_r_v(const wasm_func_t* func, wasm_ref_t* ref) { own wasm_ref_t* call_r_r(const wasm_func_t* func, wasm_ref_t* ref) { printf("call_r_r... "); fflush(stdout); - wasm_val_vec_t vs, rs; - wasm_val_vec_new(&vs, 1, (wasm_val_t []){ WASM_REF_VAL(ref) }); - wasm_val_vec_new_uninitialized(&rs, 1); - if (wasm_func_call(func, &vs, &rs)) { + wasm_val_t vs[1] = { WASM_REF_VAL(ref) }; + wasm_val_t rs[1] = { WASM_INIT_VAL }; + wasm_val_vec_t args = WASM_ARRAY_VEC(vs); + wasm_val_vec_t results = WASM_ARRAY_VEC(rs); + if (wasm_func_call(func, &args, &results)) { printf("> Error calling function!\n"); exit(1); } printf("okay\n"); - return rs.data[0].of.ref; + return rs[0].of.ref; } void call_ir_v(const wasm_func_t* func, int32_t i, wasm_ref_t* ref) { printf("call_ir_v... "); fflush(stdout); - wasm_val_vec_t vs; - wasm_val_vec_new(&vs, 2, (wasm_val_t []){ WASM_I32_VAL(i), WASM_REF_VAL(ref) }); - if (wasm_func_call(func, &vs, NULL)) { + wasm_val_t vs[2] = { WASM_I32_VAL(i), WASM_REF_VAL(ref) }; + wasm_val_vec_t args = WASM_ARRAY_VEC(vs); + wasm_val_vec_t results = WASM_EMPTY_VEC; + if (wasm_func_call(func, &args, &results)) { printf("> Error calling function!\n"); exit(1); } @@ -94,31 +98,30 @@ void call_ir_v(const wasm_func_t* func, int32_t i, wasm_ref_t* ref) { own wasm_ref_t* call_i_r(const wasm_func_t* func, int32_t i) { printf("call_i_r... "); fflush(stdout); - wasm_val_vec_t vs, rs; - wasm_val_vec_new(&vs, 1, (wasm_val_t []){ WASM_I32_VAL(i) }); - wasm_val_vec_new_uninitialized(&rs, 1); - if (wasm_func_call(func, &vs, &rs)) { + wasm_val_t vs[1] = { WASM_I32_VAL(i) }; + wasm_val_t rs[1] = { WASM_INIT_VAL }; + wasm_val_vec_t args = WASM_ARRAY_VEC(vs); + wasm_val_vec_t results = WASM_ARRAY_VEC(rs); + if (wasm_func_call(func, &args, &results)) { printf("> Error calling function!\n"); exit(1); } printf("okay\n"); - return rs.data[0].of.ref; + return rs[0].of.ref; } -void -check(own wasm_ref_t *actual, const wasm_ref_t *expected, bool release_ref) -{ - if (actual != expected - && !(actual && expected && wasm_ref_same(actual, expected))) { - printf("> Error reading reference, expected %p, got %p\n", - expected ? wasm_ref_get_host_info(expected) : NULL, - actual ? wasm_ref_get_host_info(actual) : NULL); - exit(1); - } - if (release_ref && actual) - wasm_ref_delete(actual); +void check(own wasm_ref_t* actual, const wasm_ref_t* expected) { + if (actual != expected && + !(actual && expected && wasm_ref_same(actual, expected))) { + printf("> Error reading reference, expected %p, got %p\n", + expected ? wasm_ref_get_host_info(expected) : NULL, + actual ? wasm_ref_get_host_info(actual) : NULL); + exit(1); + } + // if (actual) wasm_ref_delete(actual); } + int main(int argc, const char* argv[]) { // Initialize. printf("Initializing...\n"); @@ -169,8 +172,8 @@ int main(int argc, const char* argv[]) { // Instantiate. printf("Instantiating module...\n"); - wasm_extern_vec_t imports; - wasm_extern_vec_new(&imports, 1, (wasm_extern_t* []) { wasm_func_as_extern(callback_func) }); + wasm_extern_t* externs[] = { wasm_func_as_extern(callback_func) }; + wasm_extern_vec_t imports = WASM_ARRAY_VEC(externs); own wasm_instance_t* instance = wasm_instance_new(store, module, &imports, NULL); if (!instance) { @@ -204,54 +207,61 @@ int main(int argc, const char* argv[]) { wasm_ref_set_host_info(host2, (void*)2); // Some sanity checks. - check(NULL, NULL, true); - check(wasm_ref_copy(host1), host1, true); - check(wasm_ref_copy(host2), host2, true); + check(NULL, NULL); + wasm_ref_t *host1_cp = wasm_ref_copy(host1); + wasm_ref_t *host2_cp = wasm_ref_copy(host2); + check(host1_cp, host1); + check(host2_cp, host2); + wasm_ref_delete(host1_cp); + wasm_ref_delete(host2_cp); own wasm_val_t val; val.kind = WASM_ANYREF; val.of.ref = wasm_ref_copy(host1); - check(wasm_ref_copy(val.of.ref), host1, true); - own wasm_ref_t* ref = val.of.ref; - check(wasm_ref_copy(ref), host1, true); + wasm_ref_t *ref_cp = wasm_ref_copy(val.of.ref); + check(ref_cp, host1); + check(val.of.ref, host1); wasm_ref_delete(val.of.ref); + wasm_ref_delete(ref_cp); // Interact. printf("Accessing global...\n"); - check(call_v_r(global_get), NULL, false); + check(call_v_r(global_get), NULL); call_r_v(global_set, host1); - check(call_v_r(global_get), host1, false); + check(call_v_r(global_get), host1); call_r_v(global_set, host2); - check(call_v_r(global_get), host2, false); + check(call_v_r(global_get), host2); call_r_v(global_set, NULL); - check(call_v_r(global_get), NULL, false); + check(call_v_r(global_get), NULL); wasm_global_get(global, &val); assert(val.kind == WASM_ANYREF); - check(val.of.ref, NULL, false); + assert(val.of.ref == NULL); val.of.ref = host2; wasm_global_set(global, &val); - check(call_v_r(global_get), host2, false); wasm_global_get(global, &val); assert(val.kind == WASM_ANYREF); - check(val.of.ref, host2, false); + assert(val.of.ref == host2); printf("Accessing table...\n"); - check(call_i_r(table_get, 0), NULL, false); - check(call_i_r(table_get, 1), NULL, false); + check(call_i_r(table_get, 0), NULL); + check(call_i_r(table_get, 1), NULL); call_ir_v(table_set, 0, host1); call_ir_v(table_set, 1, host2); - check(call_i_r(table_get, 0), host1, false); - check(call_i_r(table_get, 1), host2, false); + check(call_i_r(table_get, 0), host1); + check(call_i_r(table_get, 1), host2); call_ir_v(table_set, 0, NULL); - check(call_i_r(table_get, 0), NULL, false); + check(call_i_r(table_get, 0), NULL); - check(wasm_table_get(table, 2), NULL, false); + check(wasm_table_get(table, 2), NULL); + wasm_table_set(table, 2, host1); + check(call_i_r(table_get, 2), host1); + check(wasm_table_get(table, 2), host1); printf("Accessing function...\n"); - check(call_r_r(func_call, NULL), NULL, false); - check(call_r_r(func_call, host1), host1, false); - check(call_r_r(func_call, host2), host2, false); + check(call_r_r(func_call, NULL), NULL); + check(call_r_r(func_call, host1), host1); + check(call_r_r(func_call, host2), host2); wasm_ref_delete(host1); wasm_ref_delete(host2); diff --git a/samples/wasm-c-api/src/memory.c b/samples/wasm-c-api/src/memory.c index a6c17654ff..62ebe3cf1e 100644 --- a/samples/wasm-c-api/src/memory.c +++ b/samples/wasm-c-api/src/memory.c @@ -33,13 +33,10 @@ void check(bool success) { } void check_call(wasm_func_t* func, int i, wasm_val_t args[], int32_t expected) { - wasm_val_vec_t args_vec; - wasm_val_vec_t results_vec; - if (args) - wasm_val_vec_new(&args_vec, i, args); - wasm_val_vec_new(&results_vec, 1, (wasm_val_t []){ WASM_INIT_VAL }); - if (wasm_func_call(func, args ? &args_vec : NULL, &results_vec) - || results_vec.data[0].of.i32 != expected) { + wasm_val_t r[] = {WASM_INIT_VAL}; + wasm_val_vec_t args_ = {i, args, i, sizeof(wasm_val_t)}; + wasm_val_vec_t results = WASM_ARRAY_VEC(r); + if (wasm_func_call(func, &args_, &results) || r[0].of.i32 != expected) { printf("> Error on result\n"); exit(1); } @@ -60,9 +57,9 @@ void check_call2(wasm_func_t* func, int32_t arg1, int32_t arg2, int32_t expected } void check_ok(wasm_func_t* func, int i, wasm_val_t args[]) { - wasm_val_vec_t args_vec; - wasm_val_vec_new(&args_vec, i, args); - if (wasm_func_call(func, &args_vec, NULL)) { + wasm_val_vec_t args_ = {i, args, i, sizeof(wasm_val_t)}; + wasm_val_vec_t results = WASM_EMPTY_VEC; + if (wasm_func_call(func, &args_, &results)) { printf("> Error on result, expected empty\n"); exit(1); } @@ -74,10 +71,10 @@ void check_ok2(wasm_func_t* func, int32_t arg1, int32_t arg2) { } void check_trap(wasm_func_t* func, int i, wasm_val_t args[]) { - wasm_val_vec_t args_vec, results_vec; - wasm_val_vec_new(&args_vec, i, args); - wasm_val_vec_new(&results_vec, 1, (wasm_val_t []){ WASM_INIT_VAL }); - own wasm_trap_t* trap = wasm_func_call(func, &args_vec, &results_vec); + wasm_val_t r[] = {WASM_INIT_VAL}; + wasm_val_vec_t args_ = {i, args, i, sizeof(wasm_val_t)}; + wasm_val_vec_t results = WASM_ARRAY_VEC(r); + own wasm_trap_t* trap = wasm_func_call(func, &args_, &results); if (! trap) { printf("> Error on result, expected trap\n"); exit(1); @@ -137,8 +134,9 @@ int main(int argc, const char* argv[]) { // Instantiate. printf("Instantiating module...\n"); - own wasm_instance_t* instance = - wasm_instance_new_with_args(store, module, NULL, NULL, KILOBYTE(8), 0); + wasm_extern_vec_t imports = WASM_EMPTY_VEC; + own wasm_instance_t *instance = wasm_instance_new_with_args( + store, module, &imports, NULL, KILOBYTE(32), 0); if (!instance) { printf("> Error instantiating module!\n"); return 1; @@ -156,15 +154,6 @@ int main(int argc, const char* argv[]) { wasm_module_delete(module); - if (!memory || !wasm_memory_data(memory)) { - printf("> Error getting memory!\n"); - wasm_extern_vec_delete(&exports); - wasm_instance_delete(instance); - wasm_store_delete(store); - wasm_engine_delete(engine); - return 1; - } - // Try cloning. own wasm_memory_t* copy = wasm_memory_copy(memory); assert(wasm_memory_same(memory, copy)); @@ -172,13 +161,13 @@ int main(int argc, const char* argv[]) { // Check initial memory. printf("Checking memory...\n"); - check(wasm_memory_size(memory) >= 2); - check(wasm_memory_data_size(memory) >= 0x20000); + check(wasm_memory_size(memory) == 2); + check(wasm_memory_data_size(memory) == 0x20000); check(wasm_memory_data(memory)[0] == 0); check(wasm_memory_data(memory)[0x1000] == 1); check(wasm_memory_data(memory)[0x1003] == 4); - (void)size_func; + check_call0(size_func, 2); check_call1(load_func, 0, 0); check_call1(load_func, 0x1000, 1); check_call1(load_func, 0x1003, 4); diff --git a/samples/wasm-c-api/src/multi.c b/samples/wasm-c-api/src/multi.c index c4599640a5..92ef0eea77 100644 --- a/samples/wasm-c-api/src/multi.c +++ b/samples/wasm-c-api/src/multi.c @@ -9,7 +9,7 @@ // A function to be called from Wasm code. own wasm_trap_t* callback( - const wasm_val_vec_t *args, wasm_val_vec_t *results + const wasm_val_vec_t* args, wasm_val_vec_t* results ) { printf("Calling back...\n> "); printf("> %"PRIu32" %"PRIu64" %"PRIu64" %"PRIu32"\n", @@ -27,14 +27,14 @@ own wasm_trap_t* callback( // A function closure. own wasm_trap_t* closure_callback( - void* env, const wasm_val_t args[], wasm_val_t results[] + void* env, const wasm_val_vec_t* args, wasm_val_vec_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; + results->data[0].kind = WASM_I32; + results->data[0].of.i32 = (int32_t)i; return NULL; } @@ -47,7 +47,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("multi.aot", "rb"); +#else FILE* file = fopen("multi.wasm", "rb"); +#endif if (!file) { printf("> Error loading module!\n"); return 1; @@ -91,8 +95,8 @@ int main(int argc, const char* argv[]) { // Instantiate. printf("Instantiating module...\n"); - wasm_extern_vec_t imports; - wasm_extern_vec_new(&imports, 1, (wasm_extern_t *[]) { wasm_func_as_extern(callback_func) }); + wasm_extern_t* externs[] = { wasm_func_as_extern(callback_func) }; + wasm_extern_vec_t imports = WASM_ARRAY_VEC(externs); own wasm_instance_t* instance = wasm_instance_new(store, module, &imports, NULL); if (!instance) { @@ -121,13 +125,14 @@ int main(int argc, const char* argv[]) { // Call. printf("Calling export...\n"); - wasm_val_vec_t args, results; - wasm_val_vec_new(&args, 4, (wasm_val_t []){ - WASM_I32_VAL(1), WASM_I64_VAL(2), WASM_I64_VAL(3), WASM_I32_VAL(4) - }); - wasm_val_vec_new(&results, 4, (wasm_val_t []) { - WASM_INIT_VAL, WASM_INIT_VAL, WASM_INIT_VAL, WASM_INIT_VAL - }); + wasm_val_t vals[4] = { + WASM_I32_VAL(1), WASM_I64_VAL(2), WASM_I64_VAL(3), WASM_I32_VAL(4) + }; + wasm_val_t res[4] = { + WASM_INIT_VAL, WASM_INIT_VAL, WASM_INIT_VAL, WASM_INIT_VAL + }; + wasm_val_vec_t args = WASM_ARRAY_VEC(vals); + wasm_val_vec_t results = WASM_ARRAY_VEC(res); if (wasm_func_call(run_func, &args, &results)) { printf("> Error calling function!\n"); return 1; @@ -138,12 +143,12 @@ int main(int argc, const char* argv[]) { // Print result. printf("Printing result...\n"); printf("> %"PRIu32" %"PRIu64" %"PRIu64" %"PRIu32"\n", - results.data[0].of.i32, results.data[1].of.i64, results.data[2].of.i64, results.data[3].of.i32); + res[0].of.i32, res[1].of.i64, res[2].of.i64, res[3].of.i32); - assert(results.data[0].of.i32 == 1); - assert(results.data[1].of.i64 == 2); - assert(results.data[2].of.i64 == 3); - assert(results.data[3].of.i32 == 4); + assert(res[0].of.i32 == 4); + assert(res[1].of.i64 == 3); + assert(res[2].of.i64 == 2); + assert(res[3].of.i32 == 1); // Shut down. printf("Shutting down...\n"); diff --git a/samples/wasm-c-api/src/reflect.c b/samples/wasm-c-api/src/reflect.c index a90fa2aabf..915163b983 100644 --- a/samples/wasm-c-api/src/reflect.c +++ b/samples/wasm-c-api/src/reflect.c @@ -32,12 +32,6 @@ 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; @@ -49,11 +43,6 @@ 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 = @@ -89,11 +78,6 @@ 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); } @@ -139,8 +123,9 @@ int main(int argc, const char* argv[]) { // Instantiate. printf("Instantiating module...\n"); + wasm_extern_vec_t imports = WASM_EMPTY_VEC; 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; diff --git a/samples/wasm-c-api/src/table.c b/samples/wasm-c-api/src/table.c index 942f281cfc..739385e938 100644 --- a/samples/wasm-c-api/src/table.c +++ b/samples/wasm-c-api/src/table.c @@ -49,19 +49,21 @@ void check_table(wasm_table_t* table, int32_t i, bool expect_set) { } void check_call(wasm_func_t* func, int32_t arg1, int32_t arg2, int32_t expected) { - wasm_val_vec_t args, results; - wasm_val_vec_new(&args, 2, (wasm_val_t []){ WASM_I32_VAL(arg1), WASM_I32_VAL(arg2) }); - wasm_val_vec_new(&results, 1, (wasm_val_t []){ WASM_INIT_VAL }); - if (wasm_func_call(func, &args, &results) || results.data[0].of.i32 != expected) { + wasm_val_t vs[2] = { WASM_I32_VAL(arg1), WASM_I32_VAL(arg2) }; + wasm_val_t r[1] = { WASM_INIT_VAL }; + wasm_val_vec_t args = WASM_ARRAY_VEC(vs); + wasm_val_vec_t results = WASM_ARRAY_VEC(r); + if (wasm_func_call(func, &args, &results) || r[0].of.i32 != expected) { printf("> Error on result\n"); exit(1); } } void check_trap(wasm_func_t* func, int32_t arg1, int32_t arg2) { - wasm_val_vec_t args, results; - wasm_val_vec_new(&args, 2, (wasm_val_t []){ WASM_I32_VAL(arg1), WASM_I32_VAL(arg2) }); - wasm_val_vec_new(&results, 1, (wasm_val_t []){ WASM_INIT_VAL }); + wasm_val_t vs[2] = { WASM_I32_VAL(arg1), WASM_I32_VAL(arg2) }; + wasm_val_t r[1] = { WASM_INIT_VAL }; + wasm_val_vec_t args = WASM_ARRAY_VEC(vs); + wasm_val_vec_t results = WASM_ARRAY_VEC(r); own wasm_trap_t* trap = wasm_func_call(func, &args, &results); if (! trap) { printf("> Error on result, expected trap\n"); @@ -112,8 +114,9 @@ int main(int argc, const char* argv[]) { // Instantiate. printf("Instantiating module...\n"); - own wasm_instance_t *instance = - wasm_instance_new(store, module, NULL, NULL); + wasm_extern_vec_t imports = WASM_EMPTY_VEC; + own wasm_instance_t* instance = + wasm_instance_new(store, module, &imports, NULL); if (!instance) { printf("> Error instantiating module!\n"); return 1; @@ -134,6 +137,7 @@ int main(int argc, const char* argv[]) { // Create external function. printf("Creating callback...\n"); own wasm_functype_t* neg_type = wasm_functype_new_1_1(wasm_valtype_new_i32(), wasm_valtype_new_i32()); + own wasm_func_t* h = wasm_func_new(store, neg_type, neg_callback); wasm_functype_delete(neg_type); @@ -155,7 +159,9 @@ int main(int argc, const char* argv[]) { printf("Mutating table...\n"); check(wasm_table_set(table, 0, wasm_func_as_ref(g))); check(wasm_table_set(table, 1, NULL)); - check(! wasm_table_set(table, 2, wasm_func_as_ref(f))); + wasm_ref_t *ref_f = wasm_func_as_ref(f); + check(! wasm_table_set(table, 2, ref_f)); + wasm_ref_delete(ref_f); check_table(table, 0, true); check_table(table, 1, false); check_call(call_indirect, 7, 0, 666); @@ -165,6 +171,8 @@ int main(int argc, const char* argv[]) { // Grow table. // DO NOT SUPPORT printf("Bypass Growing table...\n"); + + wasm_func_delete(h); wasm_extern_vec_delete(&exports); wasm_instance_delete(instance); diff --git a/samples/wasm-c-api/src/trap.c b/samples/wasm-c-api/src/trap.c index 16dc2e0c34..5feb9511da 100644 --- a/samples/wasm-c-api/src/trap.c +++ b/samples/wasm-c-api/src/trap.c @@ -80,8 +80,8 @@ int main(int argc, const char* argv[]) { // Instantiate. printf("Instantiating module...\n"); - wasm_extern_vec_t imports; - wasm_extern_vec_new(&imports, 1, (wasm_extern_t* []) { wasm_func_as_extern(fail_func) }); + wasm_extern_t* externs[] = { wasm_func_as_extern(fail_func) }; + wasm_extern_vec_t imports = WASM_ARRAY_VEC(externs); own wasm_instance_t* instance = wasm_instance_new(store, module, &imports, NULL); if (!instance) { @@ -112,10 +112,9 @@ int main(int argc, const char* argv[]) { } printf("Calling export %d...\n", i); - - wasm_val_vec_t results; - wasm_val_vec_new_uninitialized(&results, 1); - own wasm_trap_t* trap = wasm_func_call(func, NULL, &results); + wasm_val_vec_t args = WASM_EMPTY_VEC; + wasm_val_vec_t results = WASM_EMPTY_VEC; + own wasm_trap_t* trap = wasm_func_call(func, &args, &results); if (!trap) { printf("> Error calling function, expected trap!\n"); return 1; From 7636d86a767366fd5bb81def89c2f650b66fea83 Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Thu, 20 Jan 2022 18:40:13 +0800 Subject: [PATCH 04/32] Refactor Orc JIT to enable lazy compilation (#974) Refactor LLVM Orc JIT to actually enable the lazy compilation and speedup the launching process: https://llvm.org/docs/ORCv2.html#laziness Main modifications: - Create LLVM module for each wasm function, wrap it with thread safe module so that the modules can be compiled parallelly - Lookup function from aot module instance's func_ptrs but not directly call the function to decouple the module relationship - Compile the function when it is first called and hasn't been compiled - Create threads to pre-compile the WASM functions parallelly when loading - Set Lazy JIT as default, update document and build/test scripts --- .../compilation_on_android_ubuntu_macos.yml | 26 +- .github/workflows/compilation_on_sgx.yml | 6 +- build-scripts/config_common.cmake | 9 +- core/config.h | 4 + core/iwasm/aot/aot_loader.c | 184 +++++++--- core/iwasm/aot/aot_runtime.c | 20 + core/iwasm/common/wasm_c_api.c | 10 +- core/iwasm/common/wasm_runtime_common.c | 2 +- core/iwasm/compilation/aot_compiler.c | 76 +++- core/iwasm/compilation/aot_compiler.h | 4 +- core/iwasm/compilation/aot_emit_aot_file.c | 4 + core/iwasm/compilation/aot_emit_exception.c | 4 +- core/iwasm/compilation/aot_emit_function.c | 176 ++++++++- core/iwasm/compilation/aot_emit_memory.c | 124 ++++--- core/iwasm/compilation/aot_llvm.c | 342 ++++++++++++------ core/iwasm/compilation/aot_llvm.h | 41 ++- core/iwasm/compilation/aot_llvm_extra.cpp | 62 ++++ core/iwasm/compilation/aot_llvm_lazyjit.cpp | 120 ------ core/iwasm/compilation/aot_llvm_lazyjit.h | 72 ---- .../platform/common/posix/posix_thread.c | 2 + core/shared/platform/esp-idf/espidf_thread.c | 2 + core/shared/platform/linux-sgx/sgx_thread.c | 3 + core/shared/platform/windows/win_thread.c | 2 + doc/build_wamr.md | 12 +- product-mini/platforms/android/build_jit.sh | 2 +- product-mini/platforms/darwin/build_jit.sh | 2 +- product-mini/platforms/linux/build_jit.sh | 6 +- 27 files changed, 857 insertions(+), 460 deletions(-) delete mode 100644 core/iwasm/compilation/aot_llvm_lazyjit.cpp delete mode 100644 core/iwasm/compilation/aot_llvm_lazyjit.h diff --git a/.github/workflows/compilation_on_android_ubuntu_macos.yml b/.github/workflows/compilation_on_android_ubuntu_macos.yml index fd8fddc3e6..627ea74608 100644 --- a/.github/workflows/compilation_on_android_ubuntu_macos.yml +++ b/.github/workflows/compilation_on_android_ubuntu_macos.yml @@ -31,8 +31,8 @@ env: AOT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_LAZY_JIT=0" CLASSIC_INTERP_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=0 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_LAZY_JIT=0" FAST_INTERP_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=0 -DWAMR_BUILD_FAST_INTERP=1 -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_LAZY_JIT=0" - JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=0" LAZY_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=1" + MC_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=0" LLVM_CACHE_SUFFIX: "build-llvm_libraries_ex" jobs: @@ -193,8 +193,8 @@ jobs: # Running mode $CLASSIC_INTERP_BUILD_OPTIONS, $FAST_INTERP_BUILD_OPTIONS, - $JIT_BUILD_OPTIONS, $LAZY_JIT_BUILD_OPTIONS, + $MC_JIT_BUILD_OPTIONS, $AOT_BUILD_OPTIONS, ] make_options_feature: [ @@ -232,11 +232,11 @@ jobs: make_options_feature: "-DWAMR_BUILD_DEBUG_AOT=1" # uncompatiable mode and feature # MULTI_MODULE only on INTERP mode - - make_options_run_mode: $JIT_BUILD_OPTIONS + - make_options_run_mode: $LAZY_JIT_BUILD_OPTIONS make_options_feature: "-DWAMR_BUILD_MULTI_MODULE=1" - make_options_run_mode: $AOT_BUILD_OPTIONS make_options_feature: "-DWAMR_BUILD_MULTI_MODULE=1" - - make_options_run_mode: $LAZY_JIT_BUILD_OPTIONS + - make_options_run_mode: $MC_JIT_BUILD_OPTIONS make_options_feature: "-DWAMR_BUILD_MULTI_MODULE=1" # SIMD only on JIT/AOT mode - make_options_run_mode: $CLASSIC_INTERP_BUILD_OPTIONS @@ -246,10 +246,10 @@ jobs: # DEBUG_INTERP only on CLASSIC INTERP mode - make_options_run_mode: $AOT_BUILD_OPTIONS make_options_feature: "-DWAMR_BUILD_DEBUG_INTERP=1" - - make_options_run_mode: $JIT_BUILD_OPTIONS - make_options_feature: "-DWAMR_BUILD_DEBUG_INTERP=1" - make_options_run_mode: $LAZY_JIT_BUILD_OPTIONS make_options_feature: "-DWAMR_BUILD_DEBUG_INTERP=1" + - make_options_run_mode: $MC_JIT_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_DEBUG_INTERP=1" - make_options_run_mode: $FAST_INTERP_BUILD_OPTIONS make_options_feature: "-DWAMR_BUILD_DEBUG_INTERP=1" # DEBUG_AOT only on JIT/AOT mode @@ -258,17 +258,17 @@ jobs: - make_options_run_mode: $FAST_INTERP_BUILD_OPTIONS make_options_feature: "-DWAMR_BUILD_DEBUG_AOT=1" # TODO: DEBUG_AOT on JIT - - make_options_run_mode: $JIT_BUILD_OPTIONS - make_options_feature: "-DWAMR_BUILD_DEBUG_AOT=1" - make_options_run_mode: $LAZY_JIT_BUILD_OPTIONS make_options_feature: "-DWAMR_BUILD_DEBUG_AOT=1" + - make_options_run_mode: $MC_JIT_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_DEBUG_AOT=1" # MINI_LOADER only on INTERP mode - make_options_run_mode: $AOT_BUILD_OPTIONS make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1" - - make_options_run_mode: $JIT_BUILD_OPTIONS - make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1" - make_options_run_mode: $LAZY_JIT_BUILD_OPTIONS make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1" + - make_options_run_mode: $MC_JIT_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1" include: - os: ubuntu-18.04 light: ${{ needs.check_repo.outputs.traffic_light_on_ubuntu_1804 }} @@ -318,8 +318,8 @@ jobs: # Running mode $CLASSIC_INTERP_BUILD_OPTIONS, $FAST_INTERP_BUILD_OPTIONS, - $JIT_BUILD_OPTIONS, $LAZY_JIT_BUILD_OPTIONS, + $MC_JIT_BUILD_OPTIONS, $AOT_BUILD_OPTIONS, ] os: [ubuntu-18.04, ubuntu-20.04, macos-latest] @@ -339,11 +339,11 @@ jobs: exclude: # TODO: a .aot compatiable problem - os: macos-latest - make_options: $JIT_BUILD_OPTIONS + make_options: $LAZY_JIT_BUILD_OPTIONS - os: macos-latest make_options: $AOT_BUILD_OPTIONS - os: macos-latest - make_options: $LAZY_JIT_BUILD_OPTIONS + make_options: $MC_JIT_BUILD_OPTIONS steps: - name: light status run: echo "matrix.os=${{ matrix.os }}, light=${{ matrix.light }}" diff --git a/.github/workflows/compilation_on_sgx.yml b/.github/workflows/compilation_on_sgx.yml index f1ad8d92b8..3289fa3feb 100644 --- a/.github/workflows/compilation_on_sgx.yml +++ b/.github/workflows/compilation_on_sgx.yml @@ -31,8 +31,8 @@ env: AOT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_LAZY_JIT=0" CLASSIC_INTERP_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=0 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_LAZY_JIT=0" FAST_INTERP_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=0 -DWAMR_BUILD_FAST_INTERP=1 -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_LAZY_JIT=0" - JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=0" LAZY_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=1" + MC_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=0" LLVM_CACHE_SUFFIX: "build-llvm_libraries_ex" jobs: @@ -116,8 +116,8 @@ jobs: $CLASSIC_INTERP_BUILD_OPTIONS, $FAST_INTERP_BUILD_OPTIONS, # doesn't support - # $JIT_BUILD_OPTIONS, # $LAZY_JIT_BUILD_OPTIONS, + # $MC_JIT_BUILD_OPTIONS, $AOT_BUILD_OPTIONS, ] make_options_feature: [ @@ -208,8 +208,8 @@ jobs: $CLASSIC_INTERP_BUILD_OPTIONS, $FAST_INTERP_BUILD_OPTIONS, # doesn't support - #$JIT_BUILD_OPTIONS, #$LAZY_JIT_BUILD_OPTIONS, + #$MC_JIT_BUILD_OPTIONS, #$AOT_BUILD_OPTIONS, ] os: [ubuntu-20.04] diff --git a/build-scripts/config_common.cmake b/build-scripts/config_common.cmake index 02ae865cd7..ba44ceee6a 100644 --- a/build-scripts/config_common.cmake +++ b/build-scripts/config_common.cmake @@ -87,7 +87,9 @@ endif () if (WAMR_BUILD_JIT EQUAL 1) if (WAMR_BUILD_AOT EQUAL 1) add_definitions("-DWASM_ENABLE_JIT=1") - if (WAMR_BUILD_LAZY_JIT EQUAL 1) + if (NOT WAMR_BUILD_LAZY_JIT EQUAL 0) + # Enable Lazy JIT by default + set (WAMR_BUILD_LAZY_JIT 1) add_definitions("-DWASM_ENABLE_LAZY_JIT=1") endif () if (NOT DEFINED LLVM_DIR) @@ -128,11 +130,10 @@ else () message (" WAMR AOT disabled") endif () if (WAMR_BUILD_JIT EQUAL 1) - message (" WAMR JIT enabled") if (WAMR_BUILD_LAZY_JIT EQUAL 1) - message (" WAMR LazyJIT enabled") + message (" WAMR Lazy JIT enabled") else () - message (" WAMR LazyJIT disabled") + message (" WAMR MC JIT enabled") endif () else () message (" WAMR JIT disabled") diff --git a/core/config.h b/core/config.h index dc11876bb9..065af251b2 100644 --- a/core/config.h +++ b/core/config.h @@ -81,6 +81,10 @@ #define WASM_ENABLE_LAZY_JIT 0 #endif +#ifndef WASM_LAZY_JIT_COMPILE_THREAD_NUM +#define WASM_LAZY_JIT_COMPILE_THREAD_NUM 4 +#endif + #if (WASM_ENABLE_AOT == 0) && (WASM_ENABLE_JIT != 0) /* LazyJIT or MCJIT can only be enabled when AOT is enabled */ #undef WASM_ENABLE_JIT diff --git a/core/iwasm/aot/aot_loader.c b/core/iwasm/aot/aot_loader.c index bac3b476b9..b64f98b373 100644 --- a/core/iwasm/aot/aot_loader.c +++ b/core/iwasm/aot/aot_loader.c @@ -2760,6 +2760,90 @@ aot_load_from_aot_file(const uint8 *buf, uint32 size, char *error_buf, } #if WASM_ENABLE_JIT != 0 +#if WASM_ENABLE_LAZY_JIT != 0 +/* Orc JIT thread arguments */ +typedef struct OrcJitThreadArg { + AOTCompData *comp_data; + AOTCompContext *comp_ctx; + AOTModule *module; + int32 group_idx; + int32 group_stride; +} OrcJitThreadArg; + +static bool orcjit_stop_compiling = false; +static korp_tid orcjit_threads[WASM_LAZY_JIT_COMPILE_THREAD_NUM]; +static OrcJitThreadArg orcjit_thread_args[WASM_LAZY_JIT_COMPILE_THREAD_NUM]; + +static void * +orcjit_thread_callback(void *arg) +{ + LLVMErrorRef error; + LLVMOrcJITTargetAddress func_addr = 0; + OrcJitThreadArg *thread_arg = (OrcJitThreadArg *)arg; + AOTCompData *comp_data = thread_arg->comp_data; + AOTCompContext *comp_ctx = thread_arg->comp_ctx; + AOTModule *module = thread_arg->module; + char func_name[32]; + int32 i; + + /* Compile wasm functions of this group */ + for (i = thread_arg->group_idx; i < (int32)comp_data->func_count; + i += thread_arg->group_stride) { + if (!module->func_ptrs[i]) { + snprintf(func_name, sizeof(func_name), "%s%d", AOT_FUNC_PREFIX, i); + if ((error = LLVMOrcLLJITLookup(comp_ctx->orc_lazyjit, &func_addr, + func_name))) { + char *err_msg = LLVMGetErrorMessage(error); + os_printf("failed to compile orc jit function: %s", err_msg); + LLVMDisposeErrorMessage(err_msg); + break; + } + /** + * No need to lock the func_ptr[func_idx] here as it is basic + * data type, the load/store for it can be finished by one cpu + * instruction, and there can be only one cpu instruction + * loading/storing at the same time. + */ + module->func_ptrs[i] = (void *)func_addr; + } + if (orcjit_stop_compiling) { + break; + } + } + + /* Try to compile functions that haven't been compiled by other threads */ + for (i = (int32)comp_data->func_count - 1; i > 0; i--) { + if (orcjit_stop_compiling) { + break; + } + if (!module->func_ptrs[i]) { + snprintf(func_name, sizeof(func_name), "%s%d", AOT_FUNC_PREFIX, i); + if ((error = LLVMOrcLLJITLookup(comp_ctx->orc_lazyjit, &func_addr, + func_name))) { + char *err_msg = LLVMGetErrorMessage(error); + os_printf("failed to compile orc jit function: %s", err_msg); + LLVMDisposeErrorMessage(err_msg); + break; + } + module->func_ptrs[i] = (void *)func_addr; + } + } + + return NULL; +} + +static void +orcjit_stop_compile_threads() +{ + uint32 i; + + orcjit_stop_compiling = true; + for (i = 0; i < WASM_LAZY_JIT_COMPILE_THREAD_NUM; i++) { + os_thread_join(orcjit_threads[i], NULL); + } +} +#endif + static AOTModule * aot_load_from_comp_data(AOTCompData *comp_data, AOTCompContext *comp_ctx, char *error_buf, uint32 error_buf_size) @@ -2769,13 +2853,6 @@ aot_load_from_comp_data(AOTCompData *comp_data, AOTCompContext *comp_ctx, char func_name[32]; AOTModule *module; -#if WASM_ENABLE_LAZY_JIT != 0 - LLVMOrcThreadSafeModuleRef ts_module; - LLVMOrcJITDylibRef main_dylib; - LLVMErrorRef error; - LLVMOrcJITTargetAddress func_addr = 0; -#endif - /* Allocate memory for module */ if (!(module = loader_malloc(sizeof(AOTModule), error_buf, error_buf_size))) { @@ -2839,44 +2916,28 @@ aot_load_from_comp_data(AOTCompData *comp_data, AOTCompContext *comp_ctx, } #if WASM_ENABLE_LAZY_JIT != 0 - bh_assert(comp_ctx->lazy_orcjit); - - main_dylib = LLVMOrcLLLazyJITGetMainJITDylib(comp_ctx->lazy_orcjit); - if (!main_dylib) { - set_error_buf(error_buf, error_buf_size, - "failed to get dynmaic library reference"); - goto fail3; - } + /* Create threads to compile the wasm functions */ + for (i = 0; i < WASM_LAZY_JIT_COMPILE_THREAD_NUM; i++) { + orcjit_thread_args[i].comp_data = comp_data; + orcjit_thread_args[i].comp_ctx = comp_ctx; + orcjit_thread_args[i].module = module; + orcjit_thread_args[i].group_idx = (int32)i; + orcjit_thread_args[i].group_stride = WASM_LAZY_JIT_COMPILE_THREAD_NUM; + if (os_thread_create(&orcjit_threads[i], orcjit_thread_callback, + (void *)&orcjit_thread_args[i], + APP_THREAD_STACK_SIZE_DEFAULT) + != 0) { + uint32 j; - ts_module = LLVMOrcCreateNewThreadSafeModule(comp_ctx->module, - comp_ctx->ts_context); - if (!ts_module) { - set_error_buf(error_buf, error_buf_size, - "failed to create thread safe module"); - goto fail3; - } - - if ((error = LLVMOrcLLLazyJITAddLLVMIRModule(comp_ctx->lazy_orcjit, - main_dylib, ts_module))) { - /* - * If adding the ThreadSafeModule fails then we need to clean it up - * ourselves. If adding it succeeds the JIT will manage the memory. - */ - aot_handle_llvm_errmsg(error_buf, error_buf_size, - "failed to addIRModule: ", error); - goto fail4; - } - - for (i = 0; i < comp_data->func_count; i++) { - snprintf(func_name, sizeof(func_name), "%s%d", AOT_FUNC_PREFIX, i); - if ((error = LLVMOrcLLLazyJITLookup(comp_ctx->lazy_orcjit, &func_addr, - func_name))) { - aot_handle_llvm_errmsg(error_buf, error_buf_size, - "cannot lookup: ", error); + set_error_buf(error_buf, error_buf_size, + "create orcjit compile thread failed"); + /* Terminate the threads created */ + orcjit_stop_compiling = true; + for (j = 0; j < i; j++) { + os_thread_join(orcjit_threads[j], NULL); + } goto fail3; } - module->func_ptrs[i] = (void *)func_addr; - func_addr = 0; } #else /* Resolve function addresses */ @@ -2897,7 +2958,7 @@ aot_load_from_comp_data(AOTCompData *comp_data, AOTCompContext *comp_ctx, if (size > 0 && !(module->func_type_indexes = loader_malloc(size, error_buf, error_buf_size))) { - goto fail3; + goto fail4; } for (i = 0; i < comp_data->func_count; i++) module->func_type_indexes[i] = comp_data->funcs[i]->func_type_index; @@ -2911,6 +2972,29 @@ aot_load_from_comp_data(AOTCompData *comp_data, AOTCompContext *comp_ctx, < 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) { +#if WASM_ENABLE_LAZY_JIT != 0 + if (!module->func_ptrs[comp_data->start_func_index + - module->import_func_count]) { + LLVMErrorRef error; + LLVMOrcJITTargetAddress func_addr = 0; + + snprintf(func_name, sizeof(func_name), "%s%d", AOT_FUNC_PREFIX, + comp_data->start_func_index + - module->import_func_count); + if ((error = LLVMOrcLLJITLookup(comp_ctx->orc_lazyjit, + &func_addr, func_name))) { + char *err_msg = LLVMGetErrorMessage(error); + set_error_buf_v(error_buf, error_buf_size, + "failed to compile orc jit function: %s", + err_msg); + LLVMDisposeErrorMessage(err_msg); + goto fail5; + } + module->func_ptrs[comp_data->start_func_index + - module->import_func_count] = + (void *)func_addr; + } +#endif module->start_function = module->func_ptrs[comp_data->start_func_index - module->import_func_count]; @@ -2945,10 +3029,16 @@ aot_load_from_comp_data(AOTCompData *comp_data, AOTCompContext *comp_ctx, return module; #if WASM_ENABLE_LAZY_JIT != 0 -fail4: - LLVMOrcDisposeThreadSafeModule(ts_module); +fail5: + if (module->func_type_indexes) + wasm_runtime_free(module->func_type_indexes); #endif +fail4: +#if WASM_ENABLE_LAZY_JIT != 0 + /* Terminate all threads before free module->func_ptrs */ + orcjit_stop_compile_threads(); +#endif fail3: if (module->func_ptrs) wasm_runtime_free(module->func_ptrs); @@ -3034,6 +3124,10 @@ void aot_unload(AOTModule *module) { #if WASM_ENABLE_JIT != 0 +#if WASM_ENABLE_LAZY_JIT != 0 + orcjit_stop_compile_threads(); +#endif + if (module->comp_data) aot_destroy_comp_data(module->comp_data); diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index 6a78e1dc97..baa5ce7bc9 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -1419,6 +1419,17 @@ aot_call_function(WASMExecEnv *exec_env, AOTFunctionInstance *function, } argc = func_type->param_cell_num; +#if WASM_ENABLE_LAZY_JIT != 0 + if (!function->u.func.func_ptr) { + AOTModule *aot_module = (AOTModule *)module_inst->aot_module.ptr; + if (!(function->u.func.func_ptr = + aot_lookup_orcjit_func(aot_module->comp_ctx->orc_lazyjit, + module_inst, function->func_index))) { + return false; + } + } +#endif + /* set thread handle and stack boundary */ wasm_exec_env_set_thread_info(exec_env); @@ -2300,6 +2311,15 @@ aot_call_indirect(WASMExecEnv *exec_env, uint32 tbl_idx, uint32 table_elem_idx, func_type_idx = func_type_indexes[func_idx]; func_type = aot_module->func_types[func_type_idx]; +#if WASM_ENABLE_LAZY_JIT != 0 + if (func_idx >= aot_module->import_func_count && !func_ptrs[func_idx]) { + if (!(func_ptr = aot_lookup_orcjit_func( + aot_module->comp_ctx->orc_lazyjit, module_inst, func_idx))) { + return false; + } + } +#endif + if (!(func_ptr = func_ptrs[func_idx])) { bh_assert(func_idx < aot_module->import_func_count); import_func = aot_module->import_funcs + func_idx; diff --git a/core/iwasm/common/wasm_c_api.c b/core/iwasm/common/wasm_c_api.c index fb799de19d..a77f43c8d6 100644 --- a/core/iwasm/common/wasm_c_api.c +++ b/core/iwasm/common/wasm_c_api.c @@ -232,7 +232,7 @@ WASM_DEFINE_VEC_OWN(store, wasm_store_delete) WASM_DEFINE_VEC_OWN(valtype, wasm_valtype_delete) /* conflicting declaration between aot_export.h and aot.h */ -#if WASM_ENABLE_AOT != 0 && WASM_ENABLE_JIT != 0 +#if WASM_ENABLE_AOT != 0 && WASM_ENABLE_JIT != 0 && WASM_ENABLE_LAZY_JIT == 0 bool aot_compile_wasm_file_init(); @@ -266,7 +266,7 @@ wasm_engine_delete_internal(wasm_engine_t *engine) wasm_runtime_free(engine); } -#if WASM_ENABLE_AOT != 0 && WASM_ENABLE_JIT != 0 +#if WASM_ENABLE_AOT != 0 && WASM_ENABLE_JIT != 0 && WASM_ENABLE_LAZY_JIT == 0 aot_compile_wasm_file_destroy(); #endif @@ -317,7 +317,7 @@ wasm_engine_new_internal(mem_alloc_type_t type, const MemAllocOption *opts) bh_log_set_verbose_level(3); #endif -#if WASM_ENABLE_AOT != 0 && WASM_ENABLE_JIT != 0 +#if WASM_ENABLE_AOT != 0 && WASM_ENABLE_JIT != 0 && WASM_ENABLE_LAZY_JIT == 0 if (!aot_compile_wasm_file_init()) { goto failed; } @@ -1820,7 +1820,7 @@ wasm_module_new(wasm_store_t *store, const wasm_byte_vec_t *binary) char error_buf[128] = { 0 }; wasm_module_ex_t *module_ex = NULL; PackageType pkg_type; -#if WASM_ENABLE_AOT != 0 && WASM_ENABLE_JIT != 0 +#if WASM_ENABLE_AOT != 0 && WASM_ENABLE_JIT != 0 && WASM_ENABLE_LAZY_JIT == 0 uint8 *aot_file_buf = NULL; uint32 aot_file_size; #endif @@ -1858,7 +1858,7 @@ 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); -#if WASM_ENABLE_AOT != 0 && WASM_ENABLE_JIT != 0 +#if WASM_ENABLE_AOT != 0 && WASM_ENABLE_JIT != 0 && WASM_ENABLE_LAZY_JIT == 0 if (Wasm_Module_Bytecode == pkg_type) { if (!(aot_file_buf = aot_compile_wasm_file( (uint8 *)module_ex->binary->data, diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index 79668cc1e9..9208b6d708 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -1307,7 +1307,7 @@ wasm_runtime_finalize_call_function(WASMExecEnv *exec_env, uint32 argv_i = 0, result_i = 0, ret_argv_i = 0; WASMType *func_type; - bh_assert(argv && ret_argv); + bh_assert((argv && ret_argv) || (argc == 0)); if (argv == ret_argv) { return true; diff --git a/core/iwasm/compilation/aot_compiler.c b/core/iwasm/compilation/aot_compiler.c index 14543885a0..2807fef2fd 100644 --- a/core/iwasm/compilation/aot_compiler.c +++ b/core/iwasm/compilation/aot_compiler.c @@ -2576,6 +2576,11 @@ aot_compile_wasm(AOTCompContext *comp_ctx) char *msg = NULL; bool ret; uint32 i; +#if WASM_ENABLE_LAZY_JIT != 0 + LLVMErrorRef err; + LLVMOrcJITDylibRef orc_main_dylib; + LLVMOrcThreadSafeModuleRef orc_thread_safe_module; +#endif if (!aot_validate_wasm(comp_ctx)) { return false; @@ -2607,6 +2612,7 @@ aot_compile_wasm(AOTCompContext *comp_ctx) bh_print_time("Begin to verify LLVM module"); +#if WASM_ENABLE_LAZY_JIT == 0 ret = LLVMVerifyModule(comp_ctx->module, LLVMPrintMessageAction, &msg); if (!ret && msg) { if (msg[0] != '\0') { @@ -2616,17 +2622,39 @@ aot_compile_wasm(AOTCompContext *comp_ctx) } LLVMDisposeMessage(msg); } +#else + for (i = 0; i < comp_ctx->func_ctx_count; i++) { + ret = LLVMVerifyModule(comp_ctx->modules[i], LLVMPrintMessageAction, + &msg); + if (!ret && msg) { + if (msg[0] != '\0') { + aot_set_last_error(msg); + LLVMDisposeMessage(msg); + return false; + } + LLVMDisposeMessage(msg); + } + } +#endif bh_print_time("Begin to run function optimization passes"); /* Run function pass manager */ if (comp_ctx->optimize) { +#if WASM_ENABLE_LAZY_JIT == 0 LLVMInitializeFunctionPassManager(comp_ctx->pass_mgr); - for (i = 0; i < comp_ctx->func_ctx_count; i++) + for (i = 0; i < comp_ctx->func_ctx_count; i++) { LLVMRunFunctionPassManager(comp_ctx->pass_mgr, comp_ctx->func_ctxes[i]->func); + } +#else + for (i = 0; i < comp_ctx->func_ctx_count; i++) { + LLVMRunPassManager(comp_ctx->pass_mgr, comp_ctx->modules[i]); + } +#endif /* end of WASM_ENABLE_LAZY_JIT */ } +#if WASM_ENABLE_LAZY_JIT == 0 /* Run common pass manager */ if (comp_ctx->optimize && !comp_ctx->is_jit_mode && !comp_ctx->disable_llvm_lto) { @@ -2656,6 +2684,7 @@ aot_compile_wasm(AOTCompContext *comp_ctx) LLVMDisposePassManager(common_pass_mgr); LLVMPassManagerBuilderDispose(pass_mgr_builder); } +#endif if (comp_ctx->optimize && comp_ctx->is_indirect_mode) { LLVMPassManagerRef common_pass_mgr = NULL; @@ -2673,14 +2702,58 @@ aot_compile_wasm(AOTCompContext *comp_ctx) if (aot_require_lower_switch_pass(comp_ctx)) LLVMAddLowerSwitchPass(common_pass_mgr); +#if WASM_ENABLE_LAZY_JIT == 0 LLVMRunPassManager(common_pass_mgr, comp_ctx->module); +#else + for (i = 0; i < comp_ctx->func_ctx_count; i++) + LLVMRunPassManager(common_pass_mgr, comp_ctx->modules[i]); +#endif LLVMDisposePassManager(common_pass_mgr); } +#if 0 +#if WASM_ENABLE_LAZY_JIT == 0 + LLVMDumpModule(comp_ctx->module); +#else + for (i = 0; i < comp_ctx->func_ctx_count; i++) { + LLVMDumpModule(comp_ctx->modules[i]); + os_printf("\n"); + } +#endif +#endif + +#if WASM_ENABLE_LAZY_JIT != 0 + orc_main_dylib = LLVMOrcLLJITGetMainJITDylib(comp_ctx->orc_lazyjit); + if (!orc_main_dylib) { + aot_set_last_error("failed to get orc jit main dynmaic library"); + return false; + } + + for (i = 0; i < comp_ctx->func_ctx_count; i++) { + orc_thread_safe_module = LLVMOrcCreateNewThreadSafeModule( + comp_ctx->modules[i], comp_ctx->orc_thread_safe_context); + if (!orc_thread_safe_module) { + aot_set_last_error("failed to create thread safe module"); + return false; + } + + if ((err = LLVMOrcLLJITAddLLVMIRModule(comp_ctx->orc_lazyjit, + orc_main_dylib, + orc_thread_safe_module))) { + /* If adding the ThreadSafeModule fails then we need to clean it up + by ourselves, otherwise the orc jit will manage the memory. */ + LLVMOrcDisposeThreadSafeModule(orc_thread_safe_module); + aot_handle_llvm_errmsg("failed to addIRModule", err); + return false; + } + } +#endif + return true; } +#if WASM_ENABLE_LAZY_JIT == 0 bool aot_emit_llvm_file(AOTCompContext *comp_ctx, const char *file_name) { @@ -2928,3 +3001,4 @@ aot_compile_wasm_file(const uint8 *wasm_file_buf, uint32 wasm_file_size, return aot_file_buf; } +#endif /* end of WASM_ENABLE_LAZY_JIT == 0 */ diff --git a/core/iwasm/compilation/aot_compiler.h b/core/iwasm/compilation/aot_compiler.h index 7177de2979..8637b6d82a 100644 --- a/core/iwasm/compilation/aot_compiler.h +++ b/core/iwasm/compilation/aot_compiler.h @@ -345,8 +345,8 @@ check_type_compatible(uint8 src_type, uint8 dst_type) 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, \ + if (!(func = LLVMGetNamedFunction(func_ctx->module, func_name)) \ + && !(func = LLVMAddFunction(func_ctx->module, func_name, \ func_type))) { \ aot_set_last_error("llvm add function failed."); \ goto fail; \ diff --git a/core/iwasm/compilation/aot_emit_aot_file.c b/core/iwasm/compilation/aot_emit_aot_file.c index e19cfaa185..d0b1d74a0a 100644 --- a/core/iwasm/compilation/aot_emit_aot_file.c +++ b/core/iwasm/compilation/aot_emit_aot_file.c @@ -6,6 +6,8 @@ #include "aot_compiler.h" #include "../aot/aot_runtime.h" +#if WASM_ENABLE_LAZY_JIT == 0 + #define PUT_U64_TO_ADDR(addr, value) \ do { \ union { \ @@ -2804,3 +2806,5 @@ aot_emit_aot_file(AOTCompContext *comp_ctx, AOTCompData *comp_data, return ret; } + +#endif /* end of WASM_ENABLE_JIT */ diff --git a/core/iwasm/compilation/aot_emit_exception.c b/core/iwasm/compilation/aot_emit_exception.c index 9bc46be041..1ec606b476 100644 --- a/core/iwasm/compilation/aot_emit_exception.c +++ b/core/iwasm/compilation/aot_emit_exception.c @@ -83,9 +83,9 @@ aot_emit_exception(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } else { /* Create LLVM function with external function pointer */ - if (!(func = LLVMGetNamedFunction(comp_ctx->module, + if (!(func = LLVMGetNamedFunction(func_ctx->module, "aot_set_exception_with_id")) - && !(func = LLVMAddFunction(comp_ctx->module, + && !(func = LLVMAddFunction(func_ctx->module, "aot_set_exception_with_id", func_type))) { aot_set_last_error("add LLVM function failed."); diff --git a/core/iwasm/compilation/aot_emit_function.c b/core/iwasm/compilation/aot_emit_function.c index fe43d6bce3..c5f1379cdd 100644 --- a/core/iwasm/compilation/aot_emit_function.c +++ b/core/iwasm/compilation/aot_emit_function.c @@ -184,9 +184,9 @@ call_aot_invoke_native_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } } else { - if (!(func = LLVMGetNamedFunction(comp_ctx->module, func_name)) + if (!(func = LLVMGetNamedFunction(func_ctx->module, func_name)) && !(func = - LLVMAddFunction(comp_ctx->module, func_name, func_type))) { + LLVMAddFunction(func_ctx->module, func_name, func_type))) { aot_set_last_error("add LLVM function failed."); return false; } @@ -266,6 +266,130 @@ call_aot_invoke_native_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, return true; } +#if WASM_ENABLE_LAZY_JIT != 0 +static bool +lookup_orcjit_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, + LLVMValueRef func_idx, LLVMValueRef *p_func) +{ + LLVMBasicBlockRef block_curr, block_resolve_func, block_func_resolved; + LLVMValueRef param_values[3], func, value, func_ptr, cmp, phi; + LLVMTypeRef param_types[3], ret_type, func_type, func_ptr_type; + + block_curr = LLVMGetInsertBlock(comp_ctx->builder); + + if (!(block_resolve_func = LLVMAppendBasicBlockInContext( + comp_ctx->context, func_ctx->func, "resolve_func"))) { + aot_set_last_error("llvm add basic block failed."); + return false; + } + if (!(block_func_resolved = LLVMAppendBasicBlockInContext( + comp_ctx->context, func_ctx->func, "func_resolved"))) { + aot_set_last_error("llvm add basic block failed."); + return false; + } + LLVMMoveBasicBlockAfter(block_resolve_func, block_curr); + LLVMMoveBasicBlockAfter(block_func_resolved, block_resolve_func); + + LLVMPositionBuilderAtEnd(comp_ctx->builder, block_func_resolved); + if (!(phi = LLVMBuildPhi(comp_ctx->builder, INT8_PTR_TYPE, "phi"))) { + aot_set_last_error("llvm build phi failed."); + return false; + } + + LLVMPositionBuilderAtEnd(comp_ctx->builder, block_curr); + + /* 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."); + return false; + } + + if (!(func = LLVMBuildLoad(comp_ctx->builder, func_ptr, "func_ptr"))) { + aot_set_last_error("llvm build load failed."); + return false; + } + + /* If func ptr is NULL, call aot_lookup_orcjit_func to resolve it */ + if (!(cmp = LLVMBuildIsNull(comp_ctx->builder, func, "cmp"))) { + aot_set_last_error("llvm build is null failed"); + return false; + } + + /* Create condition br */ + if (!LLVMBuildCondBr(comp_ctx->builder, cmp, block_resolve_func, + block_func_resolved)) { + aot_set_last_error("llvm build cond br failed."); + return false; + } + LLVMAddIncoming(phi, &func, &block_curr, 1); + + LLVMPositionBuilderAtEnd(comp_ctx->builder, block_resolve_func); + + param_types[0] = INT8_PTR_TYPE; + param_types[1] = comp_ctx->aot_inst_type; + param_types[2] = I32_TYPE; + ret_type = INT8_PTR_TYPE; + + if (!(func_type = LLVMFunctionType(ret_type, param_types, 3, false)) + || !(func_ptr_type = LLVMPointerType(func_type, 0))) { + aot_set_last_error("llvm add function type failed."); + return false; + } + + if (!(value = I64_CONST((uint64)(uintptr_t)aot_lookup_orcjit_func)) + || !(func = LLVMConstIntToPtr(value, func_ptr_type))) { + aot_set_last_error("create LLVM value failed."); + return false; + } + + param_values[0] = I64_CONST((uintptr_t)comp_ctx->orc_lazyjit); + if (!param_values[0]) { + aot_set_last_error("llvm build const failed."); + return false; + } + if (!(param_values[0] = + LLVMConstIntToPtr(param_values[0], INT8_PTR_TYPE))) { + aot_set_last_error("llvm build bit cast failed."); + return false; + } + + param_values[1] = func_ctx->aot_inst; + + param_values[2] = func_idx; + if (!param_values[2]) { + aot_set_last_error("llvm build const failed."); + return false; + } + + /* Call the function */ + if (!(func = LLVMBuildCall(comp_ctx->builder, func, param_values, 3, + "call_orcjit_lookup"))) { + aot_set_last_error("LLVM build call failed."); + return false; + } + + /* Check whether exception was thrown when looking up func */ + if (!check_exception_thrown(comp_ctx, func_ctx)) { + return false; + } + + block_curr = LLVMGetInsertBlock(comp_ctx->builder); + LLVMAddIncoming(phi, &func, &block_curr, 1); + + if (!LLVMBuildBr(comp_ctx->builder, block_func_resolved)) { + aot_set_last_error("llvm build br failed."); + return false; + } + + LLVMPositionBuilderAtEnd(comp_ctx->builder, block_func_resolved); + + *p_func = phi; + return true; +} +#endif + #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, @@ -579,8 +703,45 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } } else { +#if WASM_ENABLE_LAZY_JIT == 0 func = func_ctxes[func_idx - import_func_count]->func; +#else + if (func_ctxes[func_idx - import_func_count] == func_ctx) { + /* recursive call */ + func = func_ctx->func; + } + else { + LLVMTypeRef func_ptr_type; + LLVMValueRef func_idx_const = I32_CONST(func_idx); + + if (!func_idx_const) { + aot_set_last_error("llvm build const failed."); + goto fail; + } + + /* For LAZY JIT, each function belongs to its own module, + we call aot_lookup_orcjit_func to get the func pointer */ + if (!lookup_orcjit_func(comp_ctx, func_ctx, func_idx_const, + &func)) { + goto fail; + } + + if (!(func_ptr_type = LLVMPointerType( + func_ctxes[func_idx - import_func_count]->func_type, + 0))) { + aot_set_last_error("construct func ptr type failed."); + goto fail; + } + + if (!(func = LLVMBuildBitCast(comp_ctx->builder, func, + func_ptr_type, "aot_func"))) { + aot_set_last_error("llvm bit cast failed."); + goto fail; + } + } +#endif } + 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; @@ -704,9 +865,9 @@ call_aot_call_indirect_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } } else { - if (!(func = LLVMGetNamedFunction(comp_ctx->module, func_name)) + if (!(func = LLVMGetNamedFunction(func_ctx->module, func_name)) && !(func = - LLVMAddFunction(comp_ctx->module, func_name, func_type))) { + LLVMAddFunction(func_ctx->module, func_name, func_type))) { aot_set_last_error("add LLVM function failed."); return false; } @@ -1197,6 +1358,7 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, + 16)) goto fail; +#if WASM_ENABLE_LAZY_JIT == 0 /* Load function pointer */ if (!(func_ptr = LLVMBuildInBoundsGEP(comp_ctx->builder, func_ctx->func_ptrs, @@ -1209,6 +1371,12 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, aot_set_last_error("llvm build load failed."); goto fail; } +#else + /* For LAZY JIT, each function belongs to its own module, + we call aot_lookup_orcjit_func to get the func pointer */ + if (!lookup_orcjit_func(comp_ctx, func_ctx, func_idx, &func_ptr)) + goto fail; +#endif if (!(llvm_func_type = LLVMFunctionType(ret_type, param_types, total_param_count, false)) diff --git a/core/iwasm/compilation/aot_emit_memory.c b/core/iwasm/compilation/aot_emit_memory.c index 2c2cc99688..f1c62fd597 100644 --- a/core/iwasm/compilation/aot_emit_memory.c +++ b/core/iwasm/compilation/aot_emit_memory.c @@ -709,9 +709,9 @@ aot_compile_op_memory_grow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) else { char *func_name = "aot_enlarge_memory"; /* AOT mode, delcare the function */ - if (!(func = LLVMGetNamedFunction(comp_ctx->module, func_name)) + if (!(func = LLVMGetNamedFunction(func_ctx->module, func_name)) && !(func = - LLVMAddFunction(comp_ctx->module, func_name, func_type))) { + LLVMAddFunction(func_ctx->module, func_name, func_type))) { aot_set_last_error("llvm add function failed."); return false; } @@ -941,6 +941,7 @@ bool aot_compile_op_memory_copy(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) { LLVMValueRef src, dst, src_addr, dst_addr, len, res; + bool call_aot_memmove = false; POP_I32(len); POP_I32(src); @@ -952,29 +953,23 @@ aot_compile_op_memory_copy(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) if (!(dst_addr = check_bulk_memory_overflow(comp_ctx, func_ctx, dst, len))) return false; - if (comp_ctx->is_indirect_mode) { +#if WASM_ENABLE_LAZY_JIT != 0 + call_aot_memmove = true; +#endif + if (comp_ctx->is_indirect_mode) + call_aot_memmove = true; + + if (call_aot_memmove) { LLVMTypeRef param_types[3], ret_type, func_type, func_ptr_type; LLVMValueRef func, params[3]; +#if WASM_ENABLE_LAZY_JIT == 0 int32 func_idx; +#endif - if (!(dst_addr = - LLVMBuildBitCast(comp_ctx->builder, dst_addr, INT32_PTR_TYPE, - "memmove dst addr cast type"))) { - aot_set_last_error("llvm cast memmove dst addr type failed."); - return false; - } - - if (!(src_addr = - LLVMBuildBitCast(comp_ctx->builder, src_addr, INT32_PTR_TYPE, - "memmove src addr cast type"))) { - aot_set_last_error("llvm cast memmove src addr type failed."); - return false; - } - - param_types[0] = INT32_PTR_TYPE; - param_types[1] = INT32_PTR_TYPE; + param_types[0] = INT8_PTR_TYPE; + param_types[1] = INT8_PTR_TYPE; param_types[2] = I32_TYPE; - ret_type = INT32_PTR_TYPE; + ret_type = INT8_PTR_TYPE; if (!(func_type = LLVMFunctionType(ret_type, param_types, 3, false))) { aot_set_last_error("create LLVM function type failed."); @@ -986,6 +981,7 @@ aot_compile_op_memory_copy(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) return false; } +#if WASM_ENABLE_LAZY_JIT == 0 func_idx = aot_get_native_symbol_index(comp_ctx, "memmove"); if (func_idx < 0) { return false; @@ -994,12 +990,19 @@ aot_compile_op_memory_copy(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) func_ptr_type, func_idx))) { return false; } +#else + if (!(func = I64_CONST((uint64)(uintptr_t)aot_memmove)) + || !(func = LLVMConstIntToPtr(func, func_ptr_type))) { + aot_set_last_error("create LLVM value failed."); + return false; + } +#endif params[0] = dst_addr; params[1] = src_addr; params[2] = len; if (!(res = LLVMBuildCall(comp_ctx->builder, func, params, 3, - "call memmove"))) { + "call_memmove"))) { aot_set_last_error("llvm build memmove failed."); return false; } @@ -1021,6 +1024,8 @@ bool aot_compile_op_memory_fill(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) { LLVMValueRef val, dst, dst_addr, len, res; + LLVMTypeRef param_types[3], ret_type, func_type, func_ptr_type; + LLVMValueRef func, params[3]; POP_I32(len); POP_I32(val); @@ -1029,64 +1034,57 @@ aot_compile_op_memory_fill(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) if (!(dst_addr = check_bulk_memory_overflow(comp_ctx, func_ctx, dst, len))) return false; - if (!(val = LLVMBuildIntCast2(comp_ctx->builder, val, INT8_TYPE, true, - "mem_set_value"))) { - aot_set_last_error("llvm build int cast2 failed."); + param_types[0] = INT8_PTR_TYPE; + param_types[1] = I32_TYPE; + param_types[2] = I32_TYPE; + ret_type = INT8_PTR_TYPE; + + if (!(func_type = LLVMFunctionType(ret_type, param_types, 3, false))) { + aot_set_last_error("create LLVM function type failed."); return false; } - if (comp_ctx->is_indirect_mode) { - LLVMTypeRef param_types[3], ret_type, func_type, func_ptr_type; - LLVMValueRef func, params[3]; - int32 func_idx; - - if (!(dst_addr = - LLVMBuildBitCast(comp_ctx->builder, dst_addr, INT32_PTR_TYPE, - "memset dst addr cast type"))) { - aot_set_last_error("llvm cast memset dst addr type failed."); - return false; - } - - param_types[0] = INT32_PTR_TYPE; - param_types[1] = INT8_TYPE; - param_types[2] = I32_TYPE; - ret_type = INT32_PTR_TYPE; - - if (!(func_type = LLVMFunctionType(ret_type, param_types, 3, false))) { - aot_set_last_error("create LLVM function type failed."); - return false; - } + if (!(func_ptr_type = LLVMPointerType(func_type, 0))) { + aot_set_last_error("create LLVM function pointer type failed."); + return false; + } - if (!(func_ptr_type = LLVMPointerType(func_type, 0))) { - aot_set_last_error("create LLVM function pointer type failed."); + if (comp_ctx->is_jit_mode) { + if (!(func = I64_CONST((uint64)(uintptr_t)aot_memset)) + || !(func = LLVMConstIntToPtr(func, func_ptr_type))) { + aot_set_last_error("create LLVM value failed."); return false; } - - func_idx = aot_get_native_symbol_index(comp_ctx, "memset"); - if (func_idx < 0) { + } + else if (comp_ctx->is_indirect_mode) { + int32 func_index; + func_index = aot_get_native_symbol_index(comp_ctx, "memset"); + if (func_index < 0) { return false; } if (!(func = aot_get_func_from_table(comp_ctx, func_ctx->native_symbol, - func_ptr_type, func_idx))) { - return false; - } - - params[0] = dst_addr; - params[1] = val; - params[2] = len; - if (!(res = LLVMBuildCall(comp_ctx->builder, func, params, 3, - "call memset"))) { - aot_set_last_error("llvm build memset failed."); + func_ptr_type, func_index))) { return false; } } else { - if (!(res = - LLVMBuildMemSet(comp_ctx->builder, dst_addr, val, len, 1))) { - aot_set_last_error("llvm build memset failed."); + if (!(func = LLVMGetNamedFunction(func_ctx->module, "memset")) + && !(func = + LLVMAddFunction(func_ctx->module, "memset", func_type))) { + aot_set_last_error("llvm add function failed."); return false; } } + + params[0] = dst_addr; + params[1] = val; + params[2] = len; + if (!(res = LLVMBuildCall(comp_ctx->builder, func, params, 3, + "call_memset"))) { + aot_set_last_error("llvm build memset failed."); + return false; + } + return true; fail: return false; diff --git a/core/iwasm/compilation/aot_llvm.c b/core/iwasm/compilation/aot_llvm.c index 33c7179a29..c126dcdd4b 100644 --- a/core/iwasm/compilation/aot_llvm.c +++ b/core/iwasm/compilation/aot_llvm.c @@ -41,8 +41,9 @@ wasm_type_to_llvm_type(AOTLLVMTypes *llvm_types, uint8 wasm_type) * Add LLVM function */ static LLVMValueRef -aot_add_llvm_func(AOTCompContext *comp_ctx, AOTFuncType *aot_func_type, - uint32 func_index, LLVMTypeRef *p_func_type) +aot_add_llvm_func(AOTCompContext *comp_ctx, LLVMModuleRef module, + AOTFuncType *aot_func_type, uint32 func_index, + LLVMTypeRef *p_func_type) { LLVMValueRef func = NULL; LLVMTypeRef *param_types, ret_type, func_type; @@ -97,7 +98,7 @@ aot_add_llvm_func(AOTCompContext *comp_ctx, AOTFuncType *aot_func_type, /* Add LLVM function */ snprintf(func_name, sizeof(func_name), "%s%d", AOT_FUNC_PREFIX, func_index); - if (!(func = LLVMAddFunction(comp_ctx->module, func_name, func_type))) { + if (!(func = LLVMAddFunction(module, func_name, func_type))) { aot_set_last_error("add LLVM function failed."); goto fail; } @@ -616,9 +617,16 @@ aot_create_func_context(AOTCompData *comp_data, AOTCompContext *comp_ctx, memset(func_ctx, 0, (uint32)size); func_ctx->aot_func = func; +#if WASM_ENABLE_LAZY_JIT == 0 + func_ctx->module = comp_ctx->module; +#else + func_ctx->module = comp_ctx->modules[func_index]; +#endif + /* Add LLVM function */ - if (!(func_ctx->func = aot_add_llvm_func(comp_ctx, aot_func_type, - func_index, &func_ctx->func_type))) + if (!(func_ctx->func = + aot_add_llvm_func(comp_ctx, func_ctx->module, aot_func_type, + func_index, &func_ctx->func_type))) goto fail; /* Create function's first AOTBlock */ @@ -1214,152 +1222,211 @@ LLVMAddPromoteMemoryToRegisterPass(LLVMPassManagerRef PM); #if WASM_ENABLE_LAZY_JIT != 0 void -aot_handle_llvm_errmsg(char *error_buf, uint32 error_buf_size, - const char *string, LLVMErrorRef error) +aot_handle_llvm_errmsg(const char *string, LLVMErrorRef err) { - char *err_msg = LLVMGetErrorMessage(error); - if (error_buf != NULL) { - snprintf(error_buf, error_buf_size, "%s: %s", string, err_msg); - } + char *err_msg = LLVMGetErrorMessage(err); + aot_set_last_error_v("%s: %s", string, err_msg); LLVMDisposeErrorMessage(err_msg); } static bool -llvm_orcjit_create(AOTCompContext *comp_ctx) +orc_lazyjit_create(AOTCompContext *comp_ctx, uint32 func_count) { + uint32 i; char *err_msg = NULL; char *cpu = NULL; char *features = NULL; char *llvm_triple = NULL; - char buf[128] = { 0 }; - - LLVMErrorRef error; + char func_name[32] = { 0 }; + LLVMErrorRef err; LLVMTargetRef llvm_targetref = NULL; - LLVMTargetMachineRef tm_opt = NULL; - LLVMTargetMachineRef tm_opt2 = NULL; - LLVMOrcLLLazyJITRef lazy_orcjit = NULL; - LLVMOrcJITTargetMachineBuilderRef tm_builder = NULL; - LLVMOrcLLLazyJITBuilderRef lazy_orcjit_builder = NULL; -#if LLVM_VERSION_MAJOR < 12 - LLVMOrcJITDylibDefinitionGeneratorRef main_gen = NULL; -#else - LLVMOrcDefinitionGeneratorRef main_gen = NULL; -#endif + LLVMTargetMachineRef target_machine_for_orcjit = NULL; + LLVMOrcLLJITRef orc_lazyjit = NULL; + LLVMOrcJITTargetMachineBuilderRef target_machine_builder = NULL; + LLVMOrcLLJITBuilderRef orc_lazyjit_builder = NULL; + LLVMOrcMaterializationUnitRef orc_material_unit = NULL; + LLVMOrcExecutionSessionRef orc_execution_session = NULL; + LLVMOrcLazyCallThroughManagerRef orc_call_through_mgr = NULL; + LLVMOrcIndirectStubsManagerRef orc_indirect_stub_mgr = NULL; + LLVMOrcCSymbolAliasMapPair *orc_symbol_map_pairs = NULL; llvm_triple = LLVMGetDefaultTargetTriple(); if (llvm_triple == NULL) { - snprintf(buf, sizeof(buf), "failed to get default target triple."); + aot_set_last_error("failed to get default target triple."); goto fail; } if (LLVMGetTargetFromTriple(llvm_triple, &llvm_targetref, &err_msg) != 0) { - snprintf(buf, sizeof(buf), - "failed to get target reference from triple %s.", err_msg); + aot_set_last_error_v("failed to get llvm target from triple %s.", + err_msg); LLVMDisposeMessage(err_msg); goto fail; } if (!LLVMTargetHasJIT(llvm_targetref)) { - snprintf(buf, sizeof(buf), "unspported JIT on this platform."); + aot_set_last_error("unspported JIT on this platform."); goto fail; } cpu = LLVMGetHostCPUName(); if (cpu == NULL) { - snprintf(buf, sizeof(buf), "failed to get host cpu information."); + aot_set_last_error("failed to get host cpu information."); goto fail; } features = LLVMGetHostCPUFeatures(); if (features == NULL) { - snprintf(buf, sizeof(buf), "failed to get host cpu features."); + aot_set_last_error("failed to get host cpu features."); goto fail; } LOG_VERBOSE("LLVM ORCJIT detected CPU \"%s\", with features \"%s\"\n", cpu, features); - tm_opt = LLVMCreateTargetMachine(llvm_targetref, llvm_triple, cpu, features, - LLVMCodeGenLevelAggressive, - LLVMRelocDefault, LLVMCodeModelJITDefault); - if (!tm_opt) { - snprintf(buf, sizeof(buf), "failed to create target machine."); + comp_ctx->target_machine = LLVMCreateTargetMachine( + llvm_targetref, llvm_triple, cpu, features, LLVMCodeGenLevelDefault, + LLVMRelocDefault, LLVMCodeModelJITDefault); + if (!comp_ctx->target_machine) { + aot_set_last_error("failed to create target machine."); goto fail; } - tm_opt2 = LLVMCreateTargetMachine( - llvm_targetref, llvm_triple, cpu, features, LLVMCodeGenLevelAggressive, + target_machine_for_orcjit = LLVMCreateTargetMachine( + llvm_targetref, llvm_triple, cpu, features, LLVMCodeGenLevelDefault, LLVMRelocDefault, LLVMCodeModelJITDefault); - if (!tm_opt2) { - snprintf(buf, sizeof(buf), "failed to create target machine2."); + if (!target_machine_for_orcjit) { + aot_set_last_error("failed to create target machine."); goto fail; } - /* if success, it will dispose tm_opt2 memory. */ - tm_builder = LLVMOrcJITTargetMachineBuilderCreateFromTargetMachine(tm_opt2); - if (!tm_builder) { - snprintf(buf, sizeof(buf), "failed to create target machine builder."); + target_machine_builder = + LLVMOrcJITTargetMachineBuilderCreateFromTargetMachine( + target_machine_for_orcjit); + if (!target_machine_builder) { + aot_set_last_error("failed to create target machine builder."); goto fail; } - tm_opt2 = NULL; + /* The target_machine_for_orcjit has been disposed before + LLVMOrcJITTargetMachineBuilderCreateFromTargetMachine() returns */ + target_machine_for_orcjit = NULL; - lazy_orcjit_builder = LLVMOrcCreateLLLazyJITBuilder(); - if (!lazy_orcjit_builder) { - snprintf(buf, sizeof(buf), "failed to create lazy jit builder."); + orc_lazyjit_builder = LLVMOrcCreateLLJITBuilder(); + if (!orc_lazyjit_builder) { + aot_set_last_error("failed to create lazy jit builder."); goto fail; } - - LLVMOrcLLLazyJITBuilderSetJITTargetMachineBuilder(lazy_orcjit_builder, - tm_builder); - - /* if success, it will dispose lazy_orcjit_builder memory */ - error = LLVMOrcCreateLLLazyJIT(&lazy_orcjit, lazy_orcjit_builder); - if (error) { - aot_handle_llvm_errmsg(buf, sizeof(buf), - "failed to create llvm lazy orcjit instance", - error); + LLVMOrcLLJITBuilderSetNumCompileThreads(orc_lazyjit_builder, + WASM_LAZY_JIT_COMPILE_THREAD_NUM); + LLVMOrcLLJITBuilderSetJITTargetMachineBuilder(orc_lazyjit_builder, + target_machine_builder); + /* Should not dispose of the JITTargetMachineBuilder after calling + LLVMOrcLLJITBuilderSetJITTargetMachineBuilder() */ + target_machine_builder = NULL; + + err = LLVMOrcCreateLLJIT(&orc_lazyjit, orc_lazyjit_builder); + if (err) { + aot_handle_llvm_errmsg("failed to create llvm lazy orcjit instance", + err); goto fail; } - lazy_orcjit_builder = NULL; + /* The orc_lazyjit_builder is managed by orc_lazyjit after calling + LLVMOrcCreateLLJIT(), here we should not dispose it again */ + orc_lazyjit_builder = NULL; - error = LLVMOrcCreateDynamicLibrarySearchGeneratorForProcess( - &main_gen, LLVMOrcLLLazyJITGetGlobalPrefix(lazy_orcjit), 0, NULL); - if (error) { - aot_handle_llvm_errmsg( - buf, sizeof(buf), - "failed to create dynmaic library search generator", error); - goto fail; + if (func_count > 0) { + orc_execution_session = LLVMOrcLLJITGetExecutionSession(orc_lazyjit); + if (!orc_execution_session) { + aot_set_last_error("failed to get orc execution session"); + goto fail; + } + + err = LLVMOrcCreateLocalLazyCallThroughManager( + llvm_triple, orc_execution_session, 0, &orc_call_through_mgr); + if (err) { + aot_handle_llvm_errmsg("failed to create orc call through manager", + err); + goto fail; + } + + orc_indirect_stub_mgr = + LLVMOrcCreateLocalIndirectStubsManager(llvm_triple); + if (!orc_indirect_stub_mgr) { + aot_set_last_error("failed to create orc indirect stub manager"); + goto fail; + } + + if (!(orc_symbol_map_pairs = wasm_runtime_malloc( + sizeof(LLVMOrcCSymbolAliasMapPair) * func_count))) { + aot_set_last_error("failed to allocate memory"); + goto fail; + } + memset(orc_symbol_map_pairs, 0, + sizeof(LLVMOrcCSymbolAliasMapPair) * func_count); + + for (i = 0; i < func_count; i++) { + snprintf(func_name, sizeof(func_name), "orcjit_%s%d", + AOT_FUNC_PREFIX, i); + orc_symbol_map_pairs[i].Name = + LLVMOrcExecutionSessionIntern(orc_execution_session, func_name); + snprintf(func_name, sizeof(func_name), "%s%d", AOT_FUNC_PREFIX, i); + orc_symbol_map_pairs[i].Entry.Name = + LLVMOrcExecutionSessionIntern(orc_execution_session, func_name); + orc_symbol_map_pairs[i].Entry.Flags.GenericFlags = + LLVMJITSymbolGenericFlagsExported + | LLVMJITSymbolGenericFlagsCallable; + orc_symbol_map_pairs[i].Entry.Flags.TargetFlags = + LLVMJITSymbolGenericFlagsExported + | LLVMJITSymbolGenericFlagsCallable; + + if (!orc_symbol_map_pairs[i].Name + || !orc_symbol_map_pairs[i].Entry.Name) { + aot_set_last_error("failed to allocate memory"); + goto fail; + } + } + + orc_material_unit = + LLVMOrcLazyReexports(orc_call_through_mgr, orc_indirect_stub_mgr, + LLVMOrcLLJITGetMainJITDylib(orc_lazyjit), + orc_symbol_map_pairs, func_count); + if (!orc_material_unit) { + aot_set_last_error("failed to orc re-exports"); + goto fail; + } } - LLVMOrcJITDylibAddGenerator(LLVMOrcLLLazyJITGetMainJITDylib(lazy_orcjit), - main_gen); + comp_ctx->orc_lazyjit = orc_lazyjit; + comp_ctx->orc_material_unit = orc_material_unit; + comp_ctx->orc_symbol_map_pairs = orc_symbol_map_pairs; + comp_ctx->orc_call_through_mgr = orc_call_through_mgr; + comp_ctx->orc_indirect_stub_mgr = orc_indirect_stub_mgr; - comp_ctx->lazy_orcjit = lazy_orcjit; - comp_ctx->target_machine = tm_opt; - comp_ctx->tm_builder = tm_builder; LLVMDisposeMessage(llvm_triple); LLVMDisposeMessage(cpu); LLVMDisposeMessage(features); return true; fail: - if (lazy_orcjit) - LLVMOrcDisposeLLLazyJIT(lazy_orcjit); - if (tm_builder) - LLVMOrcDisposeJITTargetMachineBuilder(tm_builder); - if (lazy_orcjit_builder) - LLVMOrcDisposeLLLazyJITBuilder(lazy_orcjit_builder); - if (tm_opt2) - LLVMDisposeTargetMachine(tm_opt2); - if (tm_opt) - LLVMDisposeTargetMachine(tm_opt); + if (orc_symbol_map_pairs) + wasm_runtime_free(orc_symbol_map_pairs); + if (orc_call_through_mgr) + LLVMOrcDisposeLazyCallThroughManager(orc_call_through_mgr); + if (orc_indirect_stub_mgr) + LLVMOrcDisposeIndirectStubsManager(orc_indirect_stub_mgr); + if (orc_lazyjit) + LLVMOrcDisposeLLJIT(orc_lazyjit); + if (target_machine_builder) + LLVMOrcDisposeJITTargetMachineBuilder(target_machine_builder); + if (orc_lazyjit_builder) + LLVMOrcDisposeLLJITBuilder(orc_lazyjit_builder); + if (target_machine_for_orcjit) + LLVMDisposeTargetMachine(target_machine_for_orcjit); if (features) LLVMDisposeMessage(features); if (cpu) LLVMDisposeMessage(cpu); if (llvm_triple) LLVMDisposeMessage(llvm_triple); - aot_set_last_error(buf); return false; } #endif /* WASM_ENABLE_LAZY_JIT != 0 */ @@ -1371,7 +1438,6 @@ aot_create_comp_context(AOTCompData *comp_data, aot_comp_option_t option) #if WASM_ENABLE_LAZY_JIT == 0 struct LLVMMCJITCompilerOptions jit_options; #endif - LLVMTargetRef target; char *triple = NULL, *triple_norm, *arch, *abi; char *cpu = NULL, *features, buf[128]; @@ -1379,7 +1445,7 @@ aot_create_comp_context(AOTCompData *comp_data, aot_comp_option_t option) char *err = NULL, *fp_round = "round.tonearest", *fp_exce = "fpexcept.strict"; char triple_buf[32] = { 0 }, features_buf[128] = { 0 }; - uint32 opt_level, size_level; + uint32 opt_level, size_level, i; LLVMCodeModel code_model; LLVMTargetDataRef target_data_ref; @@ -1408,14 +1474,17 @@ aot_create_comp_context(AOTCompData *comp_data, aot_comp_option_t option) /* Create LLVM context, module and builder */ #if WASM_ENABLE_LAZY_JIT != 0 - comp_ctx->ts_context = LLVMOrcCreateNewThreadSafeContext(); - if (!comp_ctx->ts_context) { + comp_ctx->orc_thread_safe_context = LLVMOrcCreateNewThreadSafeContext(); + if (!comp_ctx->orc_thread_safe_context) { aot_set_last_error("create LLVM ThreadSafeContext failed."); - return NULL; + goto fail; } - /* Get a reference to the underlying LLVMContext */ - if (!(comp_ctx->context = - LLVMOrcThreadSafeContextGetContext(comp_ctx->ts_context))) { + + /* Get a reference to the underlying LLVMContext, note: + different from non LAZY JIT mode, no need to dispose this context, + if will be disposed when the thread safe context is disposed */ + if (!(comp_ctx->context = LLVMOrcThreadSafeContextGetContext( + comp_ctx->orc_thread_safe_context))) { aot_set_last_error("get context from LLVM ThreadSafeContext failed."); goto fail; } @@ -1431,17 +1500,41 @@ aot_create_comp_context(AOTCompData *comp_data, aot_comp_option_t option) goto fail; } +#if WASM_ENABLE_LAZY_JIT == 0 if (!(comp_ctx->module = LLVMModuleCreateWithNameInContext( "WASM Module", comp_ctx->context))) { aot_set_last_error("create LLVM module failed."); goto fail; } +#else + if (comp_data->func_count > 0) { + if (!(comp_ctx->modules = wasm_runtime_malloc( + sizeof(LLVMModuleRef) * comp_data->func_count))) { + aot_set_last_error("allocate memory failed."); + goto fail; + } + memset(comp_ctx->modules, 0, + sizeof(LLVMModuleRef) * comp_data->func_count); + for (i = 0; i < comp_data->func_count; i++) { + char module_name[32]; + snprintf(module_name, sizeof(module_name), "WASM Module %d", i); + /* Create individual modules for each aot function, note: + different from non LAZY JIT mode, no need to dispose them, + they will be disposed when the thread safe context is disposed */ + if (!(comp_ctx->modules[i] = LLVMModuleCreateWithNameInContext( + module_name, comp_ctx->context))) { + aot_set_last_error("create LLVM module failed."); + goto fail; + } + } + } +#endif if (BH_LIST_ERROR == bh_list_init(&comp_ctx->native_symbols)) { goto fail; } -#if WASM_ENABLE_DEBUG_AOT != 0 +#if WASM_ENABLE_DEBUG_AOT != 0 && WASM_ENABLE_LAZY_JIT == 0 if (!(comp_ctx->debug_builder = LLVMCreateDIBuilder(comp_ctx->module))) { aot_set_last_error("create LLVM Debug Infor builder failed."); goto fail; @@ -1497,10 +1590,11 @@ aot_create_comp_context(AOTCompData *comp_data, aot_comp_option_t option) if (option->is_jit_mode) { char *triple_jit = NULL; + comp_ctx->is_jit_mode = true; + #if WASM_ENABLE_LAZY_JIT != 0 - /* Create LLLazyJIT Instance */ - if (!llvm_orcjit_create(comp_ctx)) { - aot_set_last_error("create LLVM Lazy JIT Compiler failed."); + /* Create LLJIT Instance */ + if (!orc_lazyjit_create(comp_ctx, comp_data->func_count)) { goto fail; } @@ -1524,7 +1618,6 @@ aot_create_comp_context(AOTCompData *comp_data, aot_comp_option_t option) comp_ctx->target_machine = LLVMGetExecutionEngineTargetMachine(comp_ctx->exec_engine); #endif - comp_ctx->is_jit_mode = true; #ifndef OS_ENABLE_HW_BOUND_CHECK comp_ctx->enable_bound_check = true; @@ -1533,8 +1626,8 @@ aot_create_comp_context(AOTCompData *comp_data, aot_comp_option_t option) #endif #if WASM_ENABLE_LAZY_JIT != 0 - if (!(triple_jit = (char *)LLVMOrcLLLazyJITGetTripleString( - comp_ctx->lazy_orcjit))) { + if (!(triple_jit = + (char *)LLVMOrcLLJITGetTripleString(comp_ctx->orc_lazyjit))) { aot_set_last_error("can not get triple from the target machine"); goto fail; } @@ -1768,9 +1861,17 @@ aot_create_comp_context(AOTCompData *comp_data, aot_comp_option_t option) aot_set_last_error("create metadata string failed."); goto fail; } +#if WASM_ENABLE_LAZY_JIT == 0 LLVMAddModuleFlag(comp_ctx->module, LLVMModuleFlagBehaviorError, "target-abi", strlen("target-abi"), meta_target_abi); +#else + for (i = 0; i < comp_data->func_count; i++) { + LLVMAddModuleFlag(comp_ctx->modules[i], + LLVMModuleFlagBehaviorError, "target-abi", + strlen("target-abi"), meta_target_abi); + } +#endif if (!strcmp(abi, "lp64d") || !strcmp(abi, "ilp32d")) { if (features) { @@ -1878,7 +1979,9 @@ aot_create_comp_context(AOTCompData *comp_data, aot_comp_option_t option) goto fail; } +#if WASM_ENABLE_LAZY_JIT == 0 LLVMSetTarget(comp_ctx->module, triple_norm); +#endif } if (option->enable_simd && strcmp(comp_ctx->target_arch, "x86_64") != 0 @@ -1921,11 +2024,18 @@ aot_create_comp_context(AOTCompData *comp_data, aot_comp_option_t option) if (option->output_format == AOT_LLVMIR_UNOPT_FILE) comp_ctx->optimize = false; +#if WASM_ENABLE_LAZY_JIT == 0 if (!(comp_ctx->pass_mgr = LLVMCreateFunctionPassManagerForModule(comp_ctx->module))) { aot_set_last_error("create LLVM pass manager failed."); goto fail; } +#else + if (!(comp_ctx->pass_mgr = LLVMCreatePassManager())) { + aot_set_last_error("create LLVM pass manager failed."); + goto fail; + } +#endif LLVMAddPromoteMemoryToRegisterPass(comp_ctx->pass_mgr); LLVMAddInstructionCombiningPass(comp_ctx->pass_mgr); @@ -2012,6 +2122,7 @@ aot_create_comp_context(AOTCompData *comp_data, aot_comp_option_t option) if (!ret) aot_destroy_comp_context(comp_ctx); + (void)i; return ret; } @@ -2022,25 +2133,42 @@ aot_destroy_comp_context(AOTCompContext *comp_ctx) return; if (comp_ctx->pass_mgr) { +#if WASM_ENABLE_LAZY_JIT == 0 LLVMFinalizeFunctionPassManager(comp_ctx->pass_mgr); +#endif LLVMDisposePassManager(comp_ctx->pass_mgr); } #if WASM_ENABLE_LAZY_JIT != 0 - if (comp_ctx->target_machine && comp_ctx->is_jit_mode) + if (comp_ctx->orc_symbol_map_pairs) + wasm_runtime_free(comp_ctx->orc_symbol_map_pairs); + + if (comp_ctx->orc_call_through_mgr) + LLVMOrcDisposeLazyCallThroughManager(comp_ctx->orc_call_through_mgr); + + if (comp_ctx->orc_indirect_stub_mgr) + LLVMOrcDisposeIndirectStubsManager(comp_ctx->orc_indirect_stub_mgr); + + if (comp_ctx->orc_material_unit) + LLVMOrcDisposeMaterializationUnit(comp_ctx->orc_material_unit); + + if (comp_ctx->target_machine) LLVMDisposeTargetMachine(comp_ctx->target_machine); if (comp_ctx->builder) LLVMDisposeBuilder(comp_ctx->builder); - if (comp_ctx->lazy_orcjit) - LLVMOrcDisposeLLLazyJIT(comp_ctx->lazy_orcjit); + if (comp_ctx->orc_lazyjit) + LLVMOrcDisposeLLJIT(comp_ctx->orc_lazyjit); + + if (comp_ctx->orc_thread_safe_context) + LLVMOrcDisposeThreadSafeContext(comp_ctx->orc_thread_safe_context); - if (comp_ctx->ts_context) - LLVMOrcDisposeThreadSafeContext(comp_ctx->ts_context); + if (comp_ctx->modules) + wasm_runtime_free(comp_ctx->modules); - if (comp_ctx->tm_builder) - LLVMOrcDisposeJITTargetMachineBuilder(comp_ctx->tm_builder); + /* Note: don't dispose comp_ctx->context and comp_ctx->modules[i] as + they are disposed when disposing the thread safe context */ LLVMShutdown(); #else @@ -2237,7 +2365,7 @@ aot_block_stack_destroy(AOTBlockStack *stack) while (block) { p = block->next; aot_value_stack_destroy(&block->value_stack); - wasm_runtime_free(block); + aot_block_destroy(block); block = p; } } @@ -2433,7 +2561,7 @@ __call_llvm_intrinsic(const AOTCompContext *comp_ctx, } else { /* Declare llvm intrinsic function if necessary */ - if (!(func = LLVMGetNamedFunction(comp_ctx->module, name))) { + if (!(func = LLVMGetNamedFunction(func_ctx->module, name))) { if (!(func_type = LLVMFunctionType(ret_type, param_types, (uint32)param_count, false))) { aot_set_last_error( @@ -2441,7 +2569,7 @@ __call_llvm_intrinsic(const AOTCompContext *comp_ctx, return NULL; } - if (!(func = LLVMAddFunction(comp_ctx->module, name, func_type))) { + if (!(func = LLVMAddFunction(func_ctx->module, name, func_type))) { aot_set_last_error("add LLVM intrinsic function failed."); return NULL; } diff --git a/core/iwasm/compilation/aot_llvm.h b/core/iwasm/compilation/aot_llvm.h index f43df2b300..82f4b0dcba 100644 --- a/core/iwasm/compilation/aot_llvm.h +++ b/core/iwasm/compilation/aot_llvm.h @@ -20,11 +20,14 @@ #include "llvm-c/Transforms/PassManagerBuilder.h" #if WASM_ENABLE_LAZY_JIT != 0 -#include "aot_llvm_lazyjit.h" #include "llvm-c/Orc.h" #include "llvm-c/Error.h" -#include "llvm-c/Initialization.h" #include "llvm-c/Support.h" +#include "llvm-c/Initialization.h" +#include "llvm-c/TargetMachine.h" +#if LLVM_VERSION_MAJOR >= 12 +#include "llvm-c/LLJIT.h" +#endif #endif #if WASM_ENABLE_DEBUG_AOT != 0 #include "llvm-c/DebugInfo.h" @@ -128,6 +131,9 @@ typedef struct AOTFuncContext { AOTFunc *aot_func; LLVMValueRef func; LLVMTypeRef func_type; + /* LLVM module for this function, note that in LAZY JIT mode, + each aot function belongs to an individual module */ + LLVMModuleRef module; AOTBlockStack block_stack; LLVMValueRef exec_env; @@ -249,7 +255,12 @@ typedef struct AOTCompContext { /* LLVM variables required to emit LLVM IR */ LLVMContextRef context; +#if WASM_ENABLE_LAZY_JIT == 0 + /* Create one module only for non LAZY JIT mode, + for LAZY JIT mode, modules are created, each + aot function has its own module */ LLVMModuleRef module; +#endif LLVMBuilderRef builder; #if WASM_ENABLE_DEBUG_AOT LLVMDIBuilderRef debug_builder; @@ -266,12 +277,18 @@ typedef struct AOTCompContext { /* LLVM execution engine required by JIT */ #if WASM_ENABLE_LAZY_JIT != 0 - LLVMOrcLLLazyJITRef lazy_orcjit; - LLVMOrcThreadSafeContextRef ts_context; - LLVMOrcJITTargetMachineBuilderRef tm_builder; + LLVMOrcLLJITRef orc_lazyjit; + LLVMOrcMaterializationUnitRef orc_material_unit; + LLVMOrcLazyCallThroughManagerRef orc_call_through_mgr; + LLVMOrcIndirectStubsManagerRef orc_indirect_stub_mgr; + LLVMOrcCSymbolAliasMapPairs orc_symbol_map_pairs; + LLVMOrcThreadSafeContextRef orc_thread_safe_context; + /* Each aot function has its own module */ + LLVMModuleRef *modules; #else LLVMExecutionEngineRef exec_engine; #endif + bool is_jit_mode; /* AOT indirect mode flag & symbol list */ @@ -453,9 +470,19 @@ void aot_add_expand_memory_op_pass(LLVMPassManagerRef pass); #if WASM_ENABLE_LAZY_JIT != 0 +LLVMOrcJITTargetMachineBuilderRef +LLVMOrcJITTargetMachineBuilderCreateFromTargetMachine(LLVMTargetMachineRef TM); + void -aot_handle_llvm_errmsg(char *error_buf, uint32 error_buf_size, - const char *string, LLVMErrorRef error); +LLVMOrcLLJITBuilderSetNumCompileThreads(LLVMOrcLLJITBuilderRef orcjit_builder, + unsigned num_compile_threads); + +void +aot_handle_llvm_errmsg(const char *string, LLVMErrorRef err); + +void * +aot_lookup_orcjit_func(LLVMOrcLLJITRef orc_lazyjit, void *module_inst, + uint32 func_idx); #endif #ifdef __cplusplus diff --git a/core/iwasm/compilation/aot_llvm_extra.cpp b/core/iwasm/compilation/aot_llvm_extra.cpp index c6a059c60a..f3aaf4ec89 100644 --- a/core/iwasm/compilation/aot_llvm_extra.cpp +++ b/core/iwasm/compilation/aot_llvm_extra.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -30,8 +31,12 @@ #include #include #include +#if WASM_ENABLE_LAZY_JIT != 0 +#include "../aot/aot_runtime.h" +#endif using namespace llvm; +using namespace llvm::orc; extern "C" LLVMBool WAMRCreateMCJITCompilerForModule(LLVMExecutionEngineRef *OutJIT, @@ -262,6 +267,63 @@ aot_check_simd_compatibility(const char *arch_c_str, const char *cpu_c_str) #endif /* WASM_ENABLE_SIMD */ } +#if LLVM_VERSION_MAJOR < 12 +LLVMOrcJITTargetMachineBuilderRef +LLVMOrcJITTargetMachineBuilderFromTargetMachine(LLVMTargetMachineRef TM); + +LLVMOrcJITTargetMachineBuilderRef +LLVMOrcJITTargetMachineBuilderCreateFromTargetMachine(LLVMTargetMachineRef TM) +{ + return LLVMOrcJITTargetMachineBuilderFromTargetMachine(TM); +} +#endif + +#if WASM_ENABLE_LAZY_JIT != 0 + +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(LLJITBuilder, LLVMOrcLLJITBuilderRef) + +void +LLVMOrcLLJITBuilderSetNumCompileThreads(LLVMOrcLLJITBuilderRef orcjit_builder, + unsigned num_compile_threads) +{ + unwrap(orcjit_builder)->setNumCompileThreads(num_compile_threads); +} + +void * +aot_lookup_orcjit_func(LLVMOrcLLJITRef orc_lazyjit, void *module_inst, + uint32 func_idx) +{ + char func_name[32], buf[128], *err_msg = NULL; + LLVMErrorRef error; + LLVMOrcJITTargetAddress func_addr = 0; + AOTModuleInstance *aot_inst = (AOTModuleInstance *)module_inst; + AOTModule *aot_module = (AOTModule *)aot_inst->aot_module.ptr; + void **func_ptrs = (void **)aot_inst->func_ptrs.ptr; + + /** + * No need to lock the func_ptr[func_idx] here as it is basic + * data type, the load/store for it can be finished by one cpu + * instruction, and there can be only one cpu instruction + * loading/storing at the same time. + */ + if (func_ptrs[func_idx]) + return func_ptrs[func_idx]; + + snprintf(func_name, sizeof(func_name), "%s%d", AOT_FUNC_PREFIX, + func_idx - aot_module->import_func_count); + if ((error = LLVMOrcLLJITLookup(orc_lazyjit, &func_addr, func_name))) { + err_msg = LLVMGetErrorMessage(error); + snprintf(buf, sizeof(buf), "failed to lookup orcjit function: %s", + err_msg); + aot_set_exception(aot_inst, buf); + LLVMDisposeErrorMessage(err_msg); + return NULL; + } + func_ptrs[func_idx] = (void *)func_addr; + return (void *)func_addr; +} +#endif + void aot_func_disable_tce(LLVMValueRef func) { diff --git a/core/iwasm/compilation/aot_llvm_lazyjit.cpp b/core/iwasm/compilation/aot_llvm_lazyjit.cpp deleted file mode 100644 index 858fbd2abb..0000000000 --- a/core/iwasm/compilation/aot_llvm_lazyjit.cpp +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (C) 2019 Intel Corporation. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - */ - -#include "aot_llvm_lazyjit.h" - -LLVMOrcJITTargetMachineBuilderRef -LLVMOrcJITTargetMachineBuilderFromTargetMachine(LLVMTargetMachineRef TM); - -LLVMOrcLLJITBuilderRef -LLVMOrcCreateLLJITBuilder(void); - -void -LLVMOrcDisposeLLJITBuilder(LLVMOrcLLJITBuilderRef Builder); - -LLVMErrorRef -LLVMOrcCreateLLJIT(LLVMOrcLLJITRef *Result, LLVMOrcLLJITBuilderRef Builder); - -LLVMErrorRef -LLVMOrcDisposeLLJIT(LLVMOrcLLJITRef J); - -LLVMOrcJITDylibRef -LLVMOrcLLJITGetMainJITDylib(LLVMOrcLLJITRef J); - -const char * -LLVMOrcLLJITGetTripleString(LLVMOrcLLJITRef J); - -char -LLVMOrcLLJITGetGlobalPrefix(LLVMOrcLLJITRef J); - -LLVMErrorRef -LLVMOrcLLJITAddLLVMIRModule(LLVMOrcLLJITRef J, LLVMOrcJITDylibRef JD, - LLVMOrcThreadSafeModuleRef TSM); - -LLVMErrorRef -LLVMOrcLLJITLookup(LLVMOrcLLJITRef J, LLVMOrcJITTargetAddress *Result, - const char *Name); - -const char * -LLVMOrcLLJITGetTripleString(LLVMOrcLLJITRef J); - -void -LLVMOrcLLJITBuilderSetJITTargetMachineBuilder( - LLVMOrcLLJITBuilderRef Builder, LLVMOrcJITTargetMachineBuilderRef JTMB); - -char -LLVMOrcLLJITGetGlobalPrefix(LLVMOrcLLJITRef J); - -#if LLVM_VERSION_MAJOR < 12 -LLVMOrcJITTargetMachineBuilderRef -LLVMOrcJITTargetMachineBuilderCreateFromTargetMachine(LLVMTargetMachineRef TM) -{ - return LLVMOrcJITTargetMachineBuilderFromTargetMachine(TM); -} -#endif - -LLVMOrcJITDylibRef -LLVMOrcLLLazyJITGetMainJITDylib(LLVMOrcLLLazyJITRef J) -{ - return LLVMOrcLLJITGetMainJITDylib(J); -} - -LLVMOrcLLLazyJITBuilderRef -LLVMOrcCreateLLLazyJITBuilder(void) -{ - return LLVMOrcCreateLLJITBuilder(); -} - -void -LLVMOrcDisposeLLLazyJITBuilder(LLVMOrcLLLazyJITBuilderRef Builder) -{ - return LLVMOrcDisposeLLJITBuilder(Builder); -} - -LLVMErrorRef -LLVMOrcCreateLLLazyJIT(LLVMOrcLLLazyJITRef *Result, - LLVMOrcLLLazyJITBuilderRef Builder) -{ - return LLVMOrcCreateLLJIT(Result, Builder); -} - -LLVMErrorRef -LLVMOrcDisposeLLLazyJIT(LLVMOrcLLLazyJITRef J) -{ - return LLVMOrcDisposeLLJIT(J); -} - -LLVMErrorRef -LLVMOrcLLLazyJITAddLLVMIRModule(LLVMOrcLLLazyJITRef J, LLVMOrcJITDylibRef JD, - LLVMOrcThreadSafeModuleRef TSM) -{ - return LLVMOrcLLJITAddLLVMIRModule(J, JD, TSM); -} - -LLVMErrorRef -LLVMOrcLLLazyJITLookup(LLVMOrcLLLazyJITRef J, LLVMOrcJITTargetAddress *Result, - const char *Name) -{ - return LLVMOrcLLJITLookup(J, Result, Name); -} - -const char * -LLVMOrcLLLazyJITGetTripleString(LLVMOrcLLLazyJITRef J) -{ - return LLVMOrcLLJITGetTripleString(J); -} - -void -LLVMOrcLLLazyJITBuilderSetJITTargetMachineBuilder( - LLVMOrcLLLazyJITBuilderRef Builder, LLVMOrcJITTargetMachineBuilderRef JTMB) -{ - return LLVMOrcLLJITBuilderSetJITTargetMachineBuilder(Builder, JTMB); -} - -char -LLVMOrcLLLazyJITGetGlobalPrefix(LLVMOrcLLLazyJITRef J) -{ - return LLVMOrcLLJITGetGlobalPrefix(J); -} diff --git a/core/iwasm/compilation/aot_llvm_lazyjit.h b/core/iwasm/compilation/aot_llvm_lazyjit.h deleted file mode 100644 index adb4b02209..0000000000 --- a/core/iwasm/compilation/aot_llvm_lazyjit.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2019 Intel Corporation. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - */ - -#ifndef AOT_LLVM_LAZYJIT_H -#define AOT_LLVM_LAZYJIT_H - -#include "llvm-c/Error.h" -#include "llvm-c/Orc.h" -#include "llvm-c/TargetMachine.h" -#include "llvm-c/Types.h" -#if LLVM_VERSION_MAJOR >= 12 -#include "llvm-c/LLJIT.h" -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -typedef LLVMOrcLLJITBuilderRef LLVMOrcLLLazyJITBuilderRef; - -typedef LLVMOrcLLJITRef LLVMOrcLLLazyJITRef; - -LLVMOrcJITTargetMachineBuilderRef -LLVMOrcJITTargetMachineBuilderCreateFromTargetMachine(LLVMTargetMachineRef TM); - -LLVMOrcLLLazyJITBuilderRef -LLVMOrcCreateLLLazyJITBuilder(void); - -void -LLVMOrcDisposeLLLazyJITBuilder(LLVMOrcLLLazyJITBuilderRef Builder); - -LLVMErrorRef -LLVMOrcCreateLLLazyJIT(LLVMOrcLLLazyJITRef *Result, - LLVMOrcLLLazyJITBuilderRef Builder); - -LLVMErrorRef -LLVMOrcDisposeLLLazyJIT(LLVMOrcLLLazyJITRef J); - -LLVMOrcJITDylibRef -LLVMOrcLLLazyJITGetMainJITDylib(LLVMOrcLLLazyJITRef J); - -const char * -LLVMOrcLLLazyJITGetTripleString(LLVMOrcLLLazyJITRef J); - -char -LLVMOrcLLLazyJITGetGlobalPrefix(LLVMOrcLLLazyJITRef J); - -LLVMErrorRef -LLVMOrcLLLazyJITAddLLVMIRModule(LLVMOrcLLLazyJITRef J, LLVMOrcJITDylibRef JD, - LLVMOrcThreadSafeModuleRef TSM); - -LLVMErrorRef -LLVMOrcLLLazyJITLookup(LLVMOrcLLLazyJITRef J, LLVMOrcJITTargetAddress *Result, - const char *Name); - -const char * -LLVMOrcLLLazyJITGetTripleString(LLVMOrcLLLazyJITRef J); - -void -LLVMOrcLLLazyJITBuilderSetJITTargetMachineBuilder( - LLVMOrcLLLazyJITBuilderRef Builder, LLVMOrcJITTargetMachineBuilderRef JTMB); - -char -LLVMOrcLLLazyJITGetGlobalPrefix(LLVMOrcLLLazyJITRef J); - -#ifdef __cplusplus -} -#endif - -#endif /* end of AOT_LLVM_LAZYJIT_H */ diff --git a/core/shared/platform/common/posix/posix_thread.c b/core/shared/platform/common/posix/posix_thread.c index 4a20c10a08..0ae231c1be 100644 --- a/core/shared/platform/common/posix/posix_thread.c +++ b/core/shared/platform/common/posix/posix_thread.c @@ -32,7 +32,9 @@ os_thread_wrapper(void *arg) os_signal_handler handler = targ->signal_handler; #endif +#if 0 os_printf("THREAD CREATED %jx\n", (uintmax_t)(uintptr_t)pthread_self()); +#endif BH_FREE(targ); #ifdef OS_ENABLE_HW_BOUND_CHECK if (os_thread_signal_init(handler) != 0) diff --git a/core/shared/platform/esp-idf/espidf_thread.c b/core/shared/platform/esp-idf/espidf_thread.c index efdb1e8d2c..c8d7a829d4 100644 --- a/core/shared/platform/esp-idf/espidf_thread.c +++ b/core/shared/platform/esp-idf/espidf_thread.c @@ -22,7 +22,9 @@ os_thread_wrapper(void *arg) thread_start_routine_t start_func = targ->start; void *thread_arg = targ->arg; +#if 0 os_printf("THREAD CREATED %jx\n", (uintmax_t)(uintptr_t)pthread_self()); +#endif BH_FREE(targ); start_func(thread_arg); return NULL; diff --git a/core/shared/platform/linux-sgx/sgx_thread.c b/core/shared/platform/linux-sgx/sgx_thread.c index 34405a1030..fbf407be06 100644 --- a/core/shared/platform/linux-sgx/sgx_thread.c +++ b/core/shared/platform/linux-sgx/sgx_thread.c @@ -18,7 +18,10 @@ os_thread_wrapper(void *arg) thread_wrapper_arg *targ = arg; thread_start_routine_t start_func = targ->start; void *thread_arg = targ->arg; + +#if 0 os_printf("THREAD CREATED %p\n", &targ); +#endif BH_FREE(targ); start_func(thread_arg); return NULL; diff --git a/core/shared/platform/windows/win_thread.c b/core/shared/platform/windows/win_thread.c index 408784d544..73b04dfa01 100644 --- a/core/shared/platform/windows/win_thread.c +++ b/core/shared/platform/windows/win_thread.c @@ -164,7 +164,9 @@ static unsigned __stdcall os_thread_wrapper(void *arg) void *retval; bool result; +#if 0 os_printf("THREAD CREATED %p\n", thread_data); +#endif os_mutex_lock(&parent->wait_lock); thread_data->thread_id = GetCurrentThreadId(); diff --git a/doc/build_wamr.md b/doc/build_wamr.md index 3ec5e327e7..ff6edf9f44 100644 --- a/doc/build_wamr.md +++ b/doc/build_wamr.md @@ -41,7 +41,7 @@ cmake -DWAMR_BUILD_PLATFORM=linux -DWAMR_BUILD_TARGET=ARM - **WAMR_BUILD_AOT**=1/0, default to enable if not set - **WAMR_BUILD_JIT**=1/0, default to disable if not set -- **WAMR_BUILD_LAZY_JIT**=1/0, default to disable if not set +- **WAMR_BUILD_LAZY_JIT**=1/0, whether to use Lazy JIT mode or not when *WAMR_BUILD_JIT* is set, default to enable if not set #### **Configure LIBC** @@ -206,7 +206,7 @@ make ``` -By default in Linux, the interpreter, AOT and WASI are enabled, and JIT and LazyJIT are disabled. +By default in Linux, the interpreter, AOT and WASI are enabled, and JIT is disabled. And the build target is set to X86_64 or X86_32 depending on the platform's bitwidth. To enable WASM JIT, firstly we should build LLVM: @@ -225,10 +225,10 @@ cmake .. -DWAMR_BUILD_JIT=1 make ``` -Moreover, pass arguments `-DWAMR_BUILD_JIT=1` and `-DWAMR_BUILD_LAZY_JIT=1` together to cmake to enable WASM Lazy JIT. -If Lazy JIT is enabled, then jit function bodies in the module will not be compiled until they are first called, -so compile time reduces significantly. - +By default, the Lazy JIT is enabled to speedup the lanuching process and reduce the JIT compilation time +by creating threads to compile the WASM functions parallely, and for the main thread, the functions in the +module will not be compiled until they are firstly called and haven't been compiled by the compilation threads. +To disable it, please pass argument `-DWAMR_BUILD_LAZY_JIT=0` to cmake. Linux SGX (Intel Software Guard Extension) ------------------------- diff --git a/product-mini/platforms/android/build_jit.sh b/product-mini/platforms/android/build_jit.sh index 908d1560c3..ffa440e95c 100755 --- a/product-mini/platforms/android/build_jit.sh +++ b/product-mini/platforms/android/build_jit.sh @@ -6,5 +6,5 @@ rm -fr build && mkdir build cd build cmake .. -DWAMR_BUILD_JIT=1 -make +make -j ${nroc} cd .. diff --git a/product-mini/platforms/darwin/build_jit.sh b/product-mini/platforms/darwin/build_jit.sh index 908d1560c3..a7d5591079 100755 --- a/product-mini/platforms/darwin/build_jit.sh +++ b/product-mini/platforms/darwin/build_jit.sh @@ -6,5 +6,5 @@ rm -fr build && mkdir build cd build cmake .. -DWAMR_BUILD_JIT=1 -make +make -j ${nproc} cd .. diff --git a/product-mini/platforms/linux/build_jit.sh b/product-mini/platforms/linux/build_jit.sh index 8cfdb73693..f794a37c8a 100755 --- a/product-mini/platforms/linux/build_jit.sh +++ b/product-mini/platforms/linux/build_jit.sh @@ -5,8 +5,8 @@ rm -fr build && mkdir build cd build -# Build With LazyJIT -# cmake .. -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=1 +# By default LazyJIT is enabled, to disable it: +# cmake .. -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=0 cmake .. -DWAMR_BUILD_JIT=1 -make +make -j ${nproc} cd .. From 5631a2aa18c38a48e4108bcc5f2a216f077fd4f0 Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Mon, 24 Jan 2022 11:10:37 +0800 Subject: [PATCH 05/32] Use LLVM new pass manager for wamrc (#978) Use LLVM new pass manager for wamrc to replace the legacy pass manger, so as to gain better performance and reduce the compilation time. Reference links: - https://llvm.org/docs/NewPassManager.html - https://blog.llvm.org/posts/2021-03-26-the-new-pass-manager And add an option to use the legacy pm mode when building wamrc: cmake .. -DWAMR_BUILD_LLVM_LEGACY_PM=1 For JIT mode, keep it unchanged as it only runs several function passes and using new pass manager will increase the compilation time. And refactor the codes of applying LLVM passes. --- build-scripts/config_common.cmake | 4 +- core/config.h | 8 + core/iwasm/common/wasm_c_api.c | 61 +-- core/iwasm/compilation/aot_compiler.c | 539 +++++++++------------ core/iwasm/compilation/aot_emit_aot_file.c | 3 +- core/iwasm/compilation/aot_llvm.c | 49 -- core/iwasm/compilation/aot_llvm.h | 6 +- core/iwasm/compilation/aot_llvm_extra.cpp | 152 +++++- core/iwasm/include/aot_export.h | 11 - wamr-compiler/CMakeLists.txt | 4 + 10 files changed, 390 insertions(+), 447 deletions(-) diff --git a/build-scripts/config_common.cmake b/build-scripts/config_common.cmake index ba44ceee6a..19d12b6a43 100644 --- a/build-scripts/config_common.cmake +++ b/build-scripts/config_common.cmake @@ -131,9 +131,9 @@ else () endif () if (WAMR_BUILD_JIT EQUAL 1) if (WAMR_BUILD_LAZY_JIT EQUAL 1) - message (" WAMR Lazy JIT enabled") + message (" WAMR LLVM Orc Lazy JIT enabled") else () - message (" WAMR MC JIT enabled") + message (" WAMR LLVM MC JIT enabled") endif () else () message (" WAMR JIT disabled") diff --git a/core/config.h b/core/config.h index 065af251b2..cd3a0eef2d 100644 --- a/core/config.h +++ b/core/config.h @@ -98,6 +98,14 @@ #define WASM_ENABLE_WAMR_COMPILER 0 #endif +#if WASM_ENABLE_WAMR_COMPILER != 0 +#ifndef WASM_ENABLE_LLVM_LEGACY_PM +/* Whether to use LLVM legacy pass manager when building wamrc, + by default it is disabled and LLVM new pass manager is used */ +#define WASM_ENABLE_LLVM_LEGACY_PM 0 +#endif +#endif + #ifndef WASM_ENABLE_LIBC_BUILTIN #define WASM_ENABLE_LIBC_BUILTIN 0 #endif diff --git a/core/iwasm/common/wasm_c_api.c b/core/iwasm/common/wasm_c_api.c index a77f43c8d6..660cdaf05c 100644 --- a/core/iwasm/common/wasm_c_api.c +++ b/core/iwasm/common/wasm_c_api.c @@ -231,20 +231,6 @@ WASM_DEFINE_VEC_OWN(module, wasm_module_delete_internal) WASM_DEFINE_VEC_OWN(store, wasm_store_delete) WASM_DEFINE_VEC_OWN(valtype, wasm_valtype_delete) -/* conflicting declaration between aot_export.h and aot.h */ -#if WASM_ENABLE_AOT != 0 && WASM_ENABLE_JIT != 0 && WASM_ENABLE_LAZY_JIT == 0 -bool -aot_compile_wasm_file_init(); - -void -aot_compile_wasm_file_destroy(); - -uint8 * -aot_compile_wasm_file(const uint8 *wasm_file_buf, uint32 wasm_file_size, - uint32 opt_level, uint32 size_level, char *error_buf, - uint32 error_buf_size, uint32 *p_aot_file_size); -#endif - /* Runtime Environment */ own wasm_config_t * wasm_config_new(void) @@ -266,10 +252,6 @@ wasm_engine_delete_internal(wasm_engine_t *engine) wasm_runtime_free(engine); } -#if WASM_ENABLE_AOT != 0 && WASM_ENABLE_JIT != 0 && WASM_ENABLE_LAZY_JIT == 0 - aot_compile_wasm_file_destroy(); -#endif - wasm_runtime_destroy(); } @@ -317,12 +299,6 @@ wasm_engine_new_internal(mem_alloc_type_t type, const MemAllocOption *opts) bh_log_set_verbose_level(3); #endif -#if WASM_ENABLE_AOT != 0 && WASM_ENABLE_JIT != 0 && WASM_ENABLE_LAZY_JIT == 0 - if (!aot_compile_wasm_file_init()) { - goto failed; - } -#endif - /* create wasm_engine_t */ if (!(engine = malloc_internal(sizeof(wasm_engine_t)))) { goto failed; @@ -1820,10 +1796,6 @@ wasm_module_new(wasm_store_t *store, const wasm_byte_vec_t *binary) char error_buf[128] = { 0 }; wasm_module_ex_t *module_ex = NULL; PackageType pkg_type; -#if WASM_ENABLE_AOT != 0 && WASM_ENABLE_JIT != 0 && WASM_ENABLE_LAZY_JIT == 0 - uint8 *aot_file_buf = NULL; - uint32 aot_file_size; -#endif bh_assert(singleton_engine); @@ -1858,33 +1830,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); -#if WASM_ENABLE_AOT != 0 && WASM_ENABLE_JIT != 0 && WASM_ENABLE_LAZY_JIT == 0 - if (Wasm_Module_Bytecode == pkg_type) { - if (!(aot_file_buf = aot_compile_wasm_file( - (uint8 *)module_ex->binary->data, - (uint32)module_ex->binary->size, 3, 3, error_buf, - (uint32)sizeof(error_buf), &aot_file_size))) { - LOG_ERROR(error_buf); - goto failed; - } - - if (!(module_ex->module_comm_rt = - wasm_runtime_load(aot_file_buf, aot_file_size, error_buf, - (uint32)sizeof(error_buf)))) { - LOG_ERROR(error_buf); - goto failed; - } - } - else -#endif - { - 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; - } + 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; } /* add it to a watching list in store */ diff --git a/core/iwasm/compilation/aot_compiler.c b/core/iwasm/compilation/aot_compiler.c index 2807fef2fd..c4dac553a4 100644 --- a/core/iwasm/compilation/aot_compiler.c +++ b/core/iwasm/compilation/aot_compiler.c @@ -2537,6 +2537,145 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index) return false; } +static bool +veriy_module(AOTCompContext *comp_ctx) +{ + char *msg = NULL; + bool ret; + +#if WASM_ENABLE_LAZY_JIT == 0 + ret = LLVMVerifyModule(comp_ctx->module, LLVMPrintMessageAction, &msg); + if (!ret && msg) { + if (msg[0] != '\0') { + aot_set_last_error(msg); + LLVMDisposeMessage(msg); + return false; + } + LLVMDisposeMessage(msg); + } +#else + uint32 i; + + for (i = 0; i < comp_ctx->func_ctx_count; i++) { + ret = LLVMVerifyModule(comp_ctx->modules[i], LLVMPrintMessageAction, + &msg); + if (!ret && msg) { + if (msg[0] != '\0') { + aot_set_last_error(msg); + LLVMDisposeMessage(msg); + return false; + } + LLVMDisposeMessage(msg); + } + } +#endif + + return true; +} + +static bool +apply_func_passes(AOTCompContext *comp_ctx) +{ + LLVMPassManagerRef pass_mgr; + uint32 i; + +#if WASM_ENABLE_LAZY_JIT == 0 + pass_mgr = LLVMCreateFunctionPassManagerForModule(comp_ctx->module); +#else + pass_mgr = LLVMCreatePassManager(); +#endif + + if (!pass_mgr) { + aot_set_last_error("create LLVM pass manager failed."); + return false; + } + + LLVMAddPromoteMemoryToRegisterPass(pass_mgr); + LLVMAddInstructionCombiningPass(pass_mgr); + LLVMAddCFGSimplificationPass(pass_mgr); + LLVMAddJumpThreadingPass(pass_mgr); +#if LLVM_VERSION_MAJOR < 12 + LLVMAddConstantPropagationPass(pass_mgr); +#endif + LLVMAddIndVarSimplifyPass(pass_mgr); + + if (!comp_ctx->is_jit_mode) { + /* Put Vectorize passes before GVN/LICM passes as the former + might gain more performance improvement and the latter might + break the optimizations for the former */ + LLVMAddLoopVectorizePass(pass_mgr); + LLVMAddSLPVectorizePass(pass_mgr); + LLVMAddLoopRotatePass(pass_mgr); + LLVMAddLoopUnswitchPass(pass_mgr); + LLVMAddInstructionCombiningPass(pass_mgr); + LLVMAddCFGSimplificationPass(pass_mgr); + if (!comp_ctx->enable_thread_mgr) { + /* These two passes may destroy the volatile semantics, + disable them when building as multi-thread mode */ + LLVMAddGVNPass(pass_mgr); + LLVMAddLICMPass(pass_mgr); + LLVMAddInstructionCombiningPass(pass_mgr); + LLVMAddCFGSimplificationPass(pass_mgr); + } + } + +#if WASM_ENABLE_LAZY_JIT == 0 + LLVMInitializeFunctionPassManager(pass_mgr); + for (i = 0; i < comp_ctx->func_ctx_count; i++) { + LLVMRunFunctionPassManager(pass_mgr, comp_ctx->func_ctxes[i]->func); + } + LLVMFinalizeFunctionPassManager(pass_mgr); +#else + for (i = 0; i < comp_ctx->func_ctx_count; i++) { + LLVMRunPassManager(pass_mgr, comp_ctx->modules[i]); + } +#endif + + LLVMDisposePassManager(pass_mgr); + return true; +} + +#if WASM_ENABLE_LLVM_LEGACY_PM != 0 +static bool +apply_lto_passes(AOTCompContext *comp_ctx) +{ + LLVMPassManagerRef common_pass_mgr; + LLVMPassManagerBuilderRef pass_mgr_builder; +#if WASM_ENABLE_LAZY_JIT != 0 + uint32 i; +#endif + + if (!(common_pass_mgr = LLVMCreatePassManager())) { + aot_set_last_error("create LLVM pass manager failed"); + return false; + } + + if (!(pass_mgr_builder = LLVMPassManagerBuilderCreate())) { + aot_set_last_error("create LLVM pass manager builder failed"); + LLVMDisposePassManager(common_pass_mgr); + return false; + } + + LLVMPassManagerBuilderSetOptLevel(pass_mgr_builder, comp_ctx->opt_level); + LLVMPassManagerBuilderPopulateModulePassManager(pass_mgr_builder, + common_pass_mgr); + LLVMPassManagerBuilderPopulateLTOPassManager(pass_mgr_builder, + common_pass_mgr, true, true); + +#if WASM_ENABLE_LAZY_JIT == 0 + LLVMRunPassManager(common_pass_mgr, comp_ctx->module); +#else + for (i = 0; i < comp_ctx->func_ctx_count; i++) { + LLVMRunPassManager(common_pass_mgr, comp_ctx->modules[i]); + } +#endif + + LLVMDisposePassManager(common_pass_mgr); + LLVMPassManagerBuilderDispose(pass_mgr_builder); + return true; +} +#endif + /* Check whether the target supports hardware atomic instructions */ static bool aot_require_lower_atomic_pass(AOTCompContext *comp_ctx) @@ -2570,11 +2709,42 @@ aot_require_lower_switch_pass(AOTCompContext *comp_ctx) return ret; } +static bool +apply_passes_for_indirect_mode(AOTCompContext *comp_ctx) +{ + LLVMPassManagerRef common_pass_mgr; +#if WASM_ENABLE_LAZY_JIT != 0 + uint32 i; +#endif + + if (!(common_pass_mgr = LLVMCreatePassManager())) { + aot_set_last_error("create pass manager failed"); + return false; + } + + aot_add_expand_memory_op_pass(common_pass_mgr); + + if (aot_require_lower_atomic_pass(comp_ctx)) + LLVMAddLowerAtomicPass(common_pass_mgr); + + if (aot_require_lower_switch_pass(comp_ctx)) + LLVMAddLowerSwitchPass(common_pass_mgr); + +#if WASM_ENABLE_LAZY_JIT == 0 + LLVMRunPassManager(common_pass_mgr, comp_ctx->module); +#else + for (i = 0; i < comp_ctx->func_ctx_count; i++) { + LLVMRunPassManager(common_pass_mgr, comp_ctx->modules[i]); + } +#endif + + LLVMDisposePassManager(common_pass_mgr); + return true; +} + bool aot_compile_wasm(AOTCompContext *comp_ctx) { - char *msg = NULL; - bool ret; uint32 i; #if WASM_ENABLE_LAZY_JIT != 0 LLVMErrorRef err; @@ -2587,142 +2757,60 @@ aot_compile_wasm(AOTCompContext *comp_ctx) } bh_print_time("Begin to compile WASM bytecode to LLVM IR"); - - for (i = 0; i < comp_ctx->func_ctx_count; i++) + for (i = 0; i < comp_ctx->func_ctx_count; i++) { if (!aot_compile_func(comp_ctx, i)) { -#if 0 - LLVMDumpModule(comp_ctx->module); - char *err; - LLVMTargetMachineEmitToFile(comp_ctx->target_machine, - comp_ctx->module, "./test.o", - LLVMObjectFile, &err); -#endif return false; } - -#if 0 - LLVMDumpModule(comp_ctx->module); - /* Clear error no, LLVMDumpModule may set errno */ - errno = 0; -#endif + } #if WASM_ENABLE_DEBUG_AOT != 0 LLVMDIBuilderFinalize(comp_ctx->debug_builder); #endif bh_print_time("Begin to verify LLVM module"); - -#if WASM_ENABLE_LAZY_JIT == 0 - ret = LLVMVerifyModule(comp_ctx->module, LLVMPrintMessageAction, &msg); - if (!ret && msg) { - if (msg[0] != '\0') { - aot_set_last_error(msg); - LLVMDisposeMessage(msg); - return false; - } - LLVMDisposeMessage(msg); - } -#else - for (i = 0; i < comp_ctx->func_ctx_count; i++) { - ret = LLVMVerifyModule(comp_ctx->modules[i], LLVMPrintMessageAction, - &msg); - if (!ret && msg) { - if (msg[0] != '\0') { - aot_set_last_error(msg); - LLVMDisposeMessage(msg); - return false; - } - LLVMDisposeMessage(msg); - } + if (!veriy_module(comp_ctx)) { + return false; } -#endif - - bh_print_time("Begin to run function optimization passes"); - /* Run function pass manager */ if (comp_ctx->optimize) { -#if WASM_ENABLE_LAZY_JIT == 0 - LLVMInitializeFunctionPassManager(comp_ctx->pass_mgr); - for (i = 0; i < comp_ctx->func_ctx_count; i++) { - LLVMRunFunctionPassManager(comp_ctx->pass_mgr, - comp_ctx->func_ctxes[i]->func); + if (comp_ctx->is_jit_mode) { + /* Only run func passes for JIT mode */ + bh_print_time("Begin to run func optimization passes"); + if (!apply_func_passes(comp_ctx)) { + return false; + } } + else { +#if WASM_ENABLE_LLVM_LEGACY_PM == 0 + /* Run llvm new pass manager for AOT compiler if llvm + legacy pass manager isn't used */ + bh_print_time("Begin to run llvm optimization passes"); + aot_apply_llvm_new_pass_manager(comp_ctx); #else - for (i = 0; i < comp_ctx->func_ctx_count; i++) { - LLVMRunPassManager(comp_ctx->pass_mgr, comp_ctx->modules[i]); - } -#endif /* end of WASM_ENABLE_LAZY_JIT */ - } - -#if WASM_ENABLE_LAZY_JIT == 0 - /* Run common pass manager */ - if (comp_ctx->optimize && !comp_ctx->is_jit_mode - && !comp_ctx->disable_llvm_lto) { - LLVMPassManagerRef common_pass_mgr = NULL; - LLVMPassManagerBuilderRef pass_mgr_builder = NULL; - - if (!(common_pass_mgr = LLVMCreatePassManager())) { - aot_set_last_error("create pass manager failed"); - return false; - } - - if (!(pass_mgr_builder = LLVMPassManagerBuilderCreate())) { - aot_set_last_error("create pass manager builder failed"); - LLVMDisposePassManager(common_pass_mgr); - return false; - } - - LLVMPassManagerBuilderSetOptLevel(pass_mgr_builder, - comp_ctx->opt_level); - LLVMPassManagerBuilderPopulateModulePassManager(pass_mgr_builder, - common_pass_mgr); - LLVMPassManagerBuilderPopulateLTOPassManager( - pass_mgr_builder, common_pass_mgr, true, true); - - LLVMRunPassManager(common_pass_mgr, comp_ctx->module); - - LLVMDisposePassManager(common_pass_mgr); - LLVMPassManagerBuilderDispose(pass_mgr_builder); - } + /* Run func passes and lto passes for AOT compiler if llvm + legacy pass manager is used */ + bh_print_time("Begin to run func optimization passes"); + if (!apply_func_passes(comp_ctx)) { + return false; + } + if (!comp_ctx->disable_llvm_lto) { + bh_print_time("Begin to run lto optimization passes"); + if (!apply_lto_passes(comp_ctx)) { + return false; + } + } #endif - - if (comp_ctx->optimize && comp_ctx->is_indirect_mode) { - LLVMPassManagerRef common_pass_mgr = NULL; - - if (!(common_pass_mgr = LLVMCreatePassManager())) { - aot_set_last_error("create pass manager failed"); - return false; + /* Run passes for AOT indirect mode */ + if (comp_ctx->is_indirect_mode) { + bh_print_time("Begin to run optimization passes " + "for indirect mode"); + if (!apply_passes_for_indirect_mode(comp_ctx)) { + return false; + } + } } - - aot_add_expand_memory_op_pass(common_pass_mgr); - - if (aot_require_lower_atomic_pass(comp_ctx)) - LLVMAddLowerAtomicPass(common_pass_mgr); - - if (aot_require_lower_switch_pass(comp_ctx)) - LLVMAddLowerSwitchPass(common_pass_mgr); - -#if WASM_ENABLE_LAZY_JIT == 0 - LLVMRunPassManager(common_pass_mgr, comp_ctx->module); -#else - for (i = 0; i < comp_ctx->func_ctx_count; i++) - LLVMRunPassManager(common_pass_mgr, comp_ctx->modules[i]); -#endif - - LLVMDisposePassManager(common_pass_mgr); } -#if 0 -#if WASM_ENABLE_LAZY_JIT == 0 - LLVMDumpModule(comp_ctx->module); -#else - for (i = 0; i < comp_ctx->func_ctx_count; i++) { - LLVMDumpModule(comp_ctx->modules[i]); - os_printf("\n"); - } -#endif -#endif - #if WASM_ENABLE_LAZY_JIT != 0 orc_main_dylib = LLVMOrcLLJITGetMainJITDylib(comp_ctx->orc_lazyjit); if (!orc_main_dylib) { @@ -2750,6 +2838,16 @@ aot_compile_wasm(AOTCompContext *comp_ctx) } #endif +#if 0 +#if WASM_ENABLE_LAZY_JIT == 0 + LLVMDumpModule(comp_ctx->module); +#else + for (i = 0; i < comp_ctx->func_ctx_count; i++) { + LLVMDumpModule(comp_ctx->modules[i]); + os_printf("\n"); + } +#endif +#endif return true; } @@ -2800,205 +2898,4 @@ aot_emit_object_file(AOTCompContext *comp_ctx, char *file_name) return true; } - -typedef struct AOTFileMap { - uint8 *wasm_file_buf; - uint32 wasm_file_size; - uint8 *aot_file_buf; - uint32 aot_file_size; - struct AOTFileMap *next; -} AOTFileMap; - -static bool aot_compile_wasm_file_inited = false; -static AOTFileMap *aot_file_maps = NULL; -static korp_mutex aot_file_map_lock; - -bool -aot_compile_wasm_file_init() -{ - if (aot_compile_wasm_file_inited) { - return true; - } - - if (BHT_OK != os_mutex_init(&aot_file_map_lock)) { - return false; - } - - aot_file_maps = NULL; - aot_compile_wasm_file_inited = true; - return true; -} - -void -aot_compile_wasm_file_destroy() -{ - AOTFileMap *file_map = aot_file_maps, *file_map_next; - - if (!aot_compile_wasm_file_inited) { - return; - } - - while (file_map) { - file_map_next = file_map->next; - - wasm_runtime_free(file_map->wasm_file_buf); - wasm_runtime_free(file_map->aot_file_buf); - wasm_runtime_free(file_map); - - file_map = file_map_next; - } - - aot_file_maps = NULL; - os_mutex_destroy(&aot_file_map_lock); - aot_compile_wasm_file_inited = false; -} - -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, "WASM module load failed: %s", - string); - } -} - -uint8 * -aot_compile_wasm_file(const uint8 *wasm_file_buf, uint32 wasm_file_size, - uint32 opt_level, uint32 size_level, char *error_buf, - uint32 error_buf_size, uint32 *p_aot_file_size) -{ - WASMModule *wasm_module = NULL; - AOTCompData *comp_data = NULL; - AOTCompContext *comp_ctx = NULL; - RuntimeInitArgs init_args; - AOTCompOption option = { 0 }; - AOTFileMap *file_map = NULL, *file_map_next; - uint8 *wasm_file_buf_cloned = NULL; - uint8 *aot_file_buf = NULL; - uint32 aot_file_size; - - 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_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 - - 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; - - os_mutex_lock(&aot_file_map_lock); - - /* lookup the file maps */ - file_map = aot_file_maps; - while (file_map) { - file_map_next = file_map->next; - - if (wasm_file_size == file_map->wasm_file_size - && memcmp(wasm_file_buf, file_map->wasm_file_buf, wasm_file_size) - == 0) { - os_mutex_unlock(&aot_file_map_lock); - /* found */ - *p_aot_file_size = file_map->aot_file_size; - return file_map->aot_file_buf; - } - - file_map = file_map_next; - } - - /* not found, initialize file map and clone wasm file */ - if (!(file_map = wasm_runtime_malloc(sizeof(AOTFileMap))) - || !(wasm_file_buf_cloned = wasm_runtime_malloc(wasm_file_size))) { - set_error_buf(error_buf, error_buf_size, "allocate memory failed"); - goto fail1; - } - - bh_memcpy_s(wasm_file_buf_cloned, wasm_file_size, wasm_file_buf, - wasm_file_size); - memset(file_map, 0, sizeof(AOTFileMap)); - file_map->wasm_file_buf = wasm_file_buf_cloned; - file_map->wasm_file_size = wasm_file_size; - - /* load WASM module */ - if (!(wasm_module = wasm_load(wasm_file_buf, wasm_file_size, error_buf, - sizeof(error_buf)))) { - goto fail1; - } - - if (!(comp_data = aot_create_comp_data(wasm_module))) { - set_error_buf(error_buf, error_buf_size, aot_get_last_error()); - goto fail2; - } - - if (!(comp_ctx = aot_create_comp_context(comp_data, &option))) { - set_error_buf(error_buf, error_buf_size, aot_get_last_error()); - goto fail3; - } - - if (!aot_compile_wasm(comp_ctx)) { - set_error_buf(error_buf, error_buf_size, aot_get_last_error()); - goto fail4; - } - - if (!(aot_file_buf = - aot_emit_aot_file_buf(comp_ctx, comp_data, &aot_file_size))) { - set_error_buf(error_buf, error_buf_size, aot_get_last_error()); - goto fail4; - } - - file_map->aot_file_buf = aot_file_buf; - file_map->aot_file_size = aot_file_size; - - if (!aot_file_maps) - aot_file_maps = file_map; - else { - file_map->next = aot_file_maps; - aot_file_maps = file_map; - } - - *p_aot_file_size = aot_file_size; - -fail4: - /* Destroy compiler context */ - aot_destroy_comp_context(comp_ctx); -fail3: - /* Destroy compile data */ - aot_destroy_comp_data(comp_data); -fail2: - wasm_unload(wasm_module); -fail1: - if (!aot_file_buf) { - if (wasm_file_buf_cloned) - wasm_runtime_free(wasm_file_buf_cloned); - if (file_map) - wasm_runtime_free(file_map); - } - - os_mutex_unlock(&aot_file_map_lock); - - return aot_file_buf; -} #endif /* end of WASM_ENABLE_LAZY_JIT == 0 */ diff --git a/core/iwasm/compilation/aot_emit_aot_file.c b/core/iwasm/compilation/aot_emit_aot_file.c index d0b1d74a0a..7b98482ec8 100644 --- a/core/iwasm/compilation/aot_emit_aot_file.c +++ b/core/iwasm/compilation/aot_emit_aot_file.c @@ -2806,5 +2806,4 @@ aot_emit_aot_file(AOTCompContext *comp_ctx, AOTCompData *comp_data, return ret; } - -#endif /* end of WASM_ENABLE_JIT */ +#endif /* end of WASM_ENABLE_LAZY_JIT == 0 */ diff --git a/core/iwasm/compilation/aot_llvm.c b/core/iwasm/compilation/aot_llvm.c index c126dcdd4b..f9e03f9c5b 100644 --- a/core/iwasm/compilation/aot_llvm.c +++ b/core/iwasm/compilation/aot_llvm.c @@ -2024,48 +2024,6 @@ aot_create_comp_context(AOTCompData *comp_data, aot_comp_option_t option) if (option->output_format == AOT_LLVMIR_UNOPT_FILE) comp_ctx->optimize = false; -#if WASM_ENABLE_LAZY_JIT == 0 - if (!(comp_ctx->pass_mgr = - LLVMCreateFunctionPassManagerForModule(comp_ctx->module))) { - aot_set_last_error("create LLVM pass manager failed."); - goto fail; - } -#else - if (!(comp_ctx->pass_mgr = LLVMCreatePassManager())) { - aot_set_last_error("create LLVM pass manager failed."); - goto fail; - } -#endif - - LLVMAddPromoteMemoryToRegisterPass(comp_ctx->pass_mgr); - 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) { - /* Put Vectorize passes before GVN/LICM passes as the former - might gain more performance improvement and the latter might - break the optimizations for the former */ - LLVMAddLoopVectorizePass(comp_ctx->pass_mgr); - LLVMAddSLPVectorizePass(comp_ctx->pass_mgr); - LLVMAddLoopRotatePass(comp_ctx->pass_mgr); - LLVMAddLoopUnswitchPass(comp_ctx->pass_mgr); - LLVMAddInstructionCombiningPass(comp_ctx->pass_mgr); - LLVMAddCFGSimplificationPass(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); - LLVMAddInstructionCombiningPass(comp_ctx->pass_mgr); - LLVMAddCFGSimplificationPass(comp_ctx->pass_mgr); - } - } - /* Create metadata for llvm float experimental constrained intrinsics */ if (!(comp_ctx->fp_rounding_mode = LLVMMDStringInContext( comp_ctx->context, fp_round, (uint32)strlen(fp_round))) @@ -2132,13 +2090,6 @@ aot_destroy_comp_context(AOTCompContext *comp_ctx) if (!comp_ctx) return; - if (comp_ctx->pass_mgr) { -#if WASM_ENABLE_LAZY_JIT == 0 - LLVMFinalizeFunctionPassManager(comp_ctx->pass_mgr); -#endif - LLVMDisposePassManager(comp_ctx->pass_mgr); - } - #if WASM_ENABLE_LAZY_JIT != 0 if (comp_ctx->orc_symbol_map_pairs) wasm_runtime_free(comp_ctx->orc_symbol_map_pairs); diff --git a/core/iwasm/compilation/aot_llvm.h b/core/iwasm/compilation/aot_llvm.h index 82f4b0dcba..1cb8d3b754 100644 --- a/core/iwasm/compilation/aot_llvm.h +++ b/core/iwasm/compilation/aot_llvm.h @@ -331,9 +331,6 @@ typedef struct AOTCompContext { uint32 opt_level; uint32 size_level; - /* LLVM pass manager to optimize the JITed code */ - LLVMPassManagerRef pass_mgr; - /* LLVM floating-point rounding mode metadata */ LLVMValueRef fp_rounding_mode; @@ -469,6 +466,9 @@ aot_check_simd_compatibility(const char *arch_c_str, const char *cpu_c_str); void aot_add_expand_memory_op_pass(LLVMPassManagerRef pass); +void +aot_apply_llvm_new_pass_manager(AOTCompContext *comp_ctx); + #if WASM_ENABLE_LAZY_JIT != 0 LLVMOrcJITTargetMachineBuilderRef LLVMOrcJITTargetMachineBuilderCreateFromTargetMachine(LLVMTargetMachineRef TM); diff --git a/core/iwasm/compilation/aot_llvm_extra.cpp b/core/iwasm/compilation/aot_llvm_extra.cpp index f3aaf4ec89..45aeb9cdd2 100644 --- a/core/iwasm/compilation/aot_llvm_extra.cpp +++ b/core/iwasm/compilation/aot_llvm_extra.cpp @@ -30,29 +30,55 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if LLVM_VERSION_MAJOR >= 12 +#include +#endif #include #if WASM_ENABLE_LAZY_JIT != 0 #include "../aot/aot_runtime.h" #endif +#include "aot_llvm.h" + using namespace llvm; using namespace llvm::orc; -extern "C" LLVMBool +extern "C" { + +LLVMBool WAMRCreateMCJITCompilerForModule(LLVMExecutionEngineRef *OutJIT, LLVMModuleRef M, LLVMMCJITCompilerOptions *PassedOptions, size_t SizeOfPassedOptions, char **OutError); -extern "C" bool +bool aot_check_simd_compatibility(const char *arch_c_str, const char *cpu_c_str); -extern "C" void +void aot_add_expand_memory_op_pass(LLVMPassManagerRef pass); -extern "C" void +void aot_func_disable_tce(LLVMValueRef func); +void +aot_apply_llvm_new_pass_manager(AOTCompContext *comp_ctx); +} + +static TargetMachine * +unwrap(LLVMTargetMachineRef P) +{ + return reinterpret_cast(P); +} + LLVMBool WAMRCreateMCJITCompilerForModule(LLVMExecutionEngineRef *OutJIT, LLVMModuleRef M, @@ -334,3 +360,121 @@ aot_func_disable_tce(LLVMValueRef func) "disable-tail-calls", "true"); F->setAttributes(Attrs); } + +void +aot_apply_llvm_new_pass_manager(AOTCompContext *comp_ctx) +{ + Module *M; + TargetMachine *TM = unwrap(comp_ctx->target_machine); + bool disable_llvm_lto = false; + + LoopAnalysisManager LAM; + FunctionAnalysisManager FAM; + CGSCCAnalysisManager CGAM; + ModuleAnalysisManager MAM; + + PipelineTuningOptions PTO; + PTO.LoopVectorization = true; + PTO.SLPVectorization = true; + PTO.LoopUnrolling = true; + +#if LLVM_VERSION_MAJOR == 12 + PassBuilder PB(false, TM, PTO); +#else + PassBuilder PB(TM, PTO); +#endif + + // Register the target library analysis directly and give it a + // customized preset TLI. + std::unique_ptr TLII( + new TargetLibraryInfoImpl(Triple(TM->getTargetTriple()))); + FAM.registerPass([&] { return TargetLibraryAnalysis(*TLII); }); + + // Register the AA manager first so that our version is the one used. + AAManager AA = PB.buildDefaultAAPipeline(); + FAM.registerPass([&] { return std::move(AA); }); + + // Register all the basic analyses with the managers. + PB.registerModuleAnalyses(MAM); + PB.registerCGSCCAnalyses(CGAM); + PB.registerFunctionAnalyses(FAM); + PB.registerLoopAnalyses(LAM); + PB.crossRegisterProxies(LAM, FAM, CGAM, MAM); + + ModulePassManager MPM; + + PassBuilder::OptimizationLevel OL; + + switch (comp_ctx->opt_level) { + case 0: + OL = PassBuilder::OptimizationLevel::O0; + break; + case 1: + OL = PassBuilder::OptimizationLevel::O1; + break; + case 2: + OL = PassBuilder::OptimizationLevel::O2; + break; + case 3: + default: + OL = PassBuilder::OptimizationLevel::O3; + break; + } + + if (comp_ctx->disable_llvm_lto) { + disable_llvm_lto = true; + } +#if WASM_ENABLE_SPEC_TEST != 0 + disable_llvm_lto = true; +#endif + + if (disable_llvm_lto) { + uint32 i; + + for (i = 0; i < comp_ctx->func_ctx_count; i++) { + aot_func_disable_tce(comp_ctx->func_ctxes[i]->func); + } + } + + if (comp_ctx->is_jit_mode) { + /* Apply normal pipeline for JIT mode, without + Vectorize related passes, without LTO */ + MPM.addPass(PB.buildPerModuleDefaultPipeline(OL)); + } + else { + FunctionPassManager FPM; + + /* Apply Vectorize related passes for AOT mode */ + FPM.addPass(LoopVectorizePass()); + FPM.addPass(SLPVectorizerPass()); + FPM.addPass(LoadStoreVectorizerPass()); + + /* + FPM.addPass(createFunctionToLoopPassAdaptor(LICMPass())); + FPM.addPass(createFunctionToLoopPassAdaptor(LoopRotatePass())); + FPM.addPass(createFunctionToLoopPassAdaptor(SimpleLoopUnswitchPass())); + */ + + MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); + + if (!disable_llvm_lto) { + /* Apply LTO for AOT mode */ + MPM.addPass(PB.buildLTODefaultPipeline(OL, NULL)); + } + else { + MPM.addPass(PB.buildPerModuleDefaultPipeline(OL)); + } + } + +#if WASM_ENABLE_LAZY_JIT == 0 + M = unwrap(comp_ctx->module); + MPM.run(*M, MAM); +#else + uint32 i; + + for (i = 0; i < comp_ctx->func_ctx_count; i++) { + M = unwrap(comp_ctx->modules[i]); + MPM.run(*M, MAM); + } +#endif +} diff --git a/core/iwasm/include/aot_export.h b/core/iwasm/include/aot_export.h index d71f945f5d..e0ee896681 100644 --- a/core/iwasm/include/aot_export.h +++ b/core/iwasm/include/aot_export.h @@ -83,17 +83,6 @@ aot_emit_aot_file(aot_comp_context_t comp_ctx, aot_comp_data_t comp_data, void aot_destroy_aot_file(uint8_t *aot_file); -bool -aot_compile_wasm_file_init(); - -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, char *error_buf, - uint32_t error_buf_size, uint32_t *p_aot_file_size); - -void -aot_compile_wasm_file_destroy(); - char * aot_get_last_error(); diff --git a/wamr-compiler/CMakeLists.txt b/wamr-compiler/CMakeLists.txt index 8d943d97e6..edec4c7a52 100644 --- a/wamr-compiler/CMakeLists.txt +++ b/wamr-compiler/CMakeLists.txt @@ -36,6 +36,10 @@ add_definitions(-DWASM_ENABLE_CUSTOM_NAME_SECTION=1) add_definitions(-DWASM_ENABLE_DUMP_CALL_STACK=1) add_definitions(-DWASM_ENABLE_PERF_PROFILING=1) +if (WAMR_BUILD_LLVM_LEGACY_PM EQUAL 1) + add_definitions(-DWASM_ENABLE_LLVM_LEGACY_PM=1) +endif() + # Set WAMR_BUILD_TARGET, currently values supported: # "X86_64", "AMD_64", "X86_32", "ARM_32", "MIPS_32", "XTENSA_32" if (NOT WAMR_BUILD_TARGET) From 90a0057d330cd5cad26cd1013192f0a94d95d781 Mon Sep 17 00:00:00 2001 From: Xu Jun <693788454@qq.com> Date: Tue, 25 Jan 2022 09:28:02 +0800 Subject: [PATCH 06/32] Implement pthread_cond_broadcast wrapper for lib-pthread (#982) Implement pthread_cond_broadcast wrapper for lib-pthread - support pthread_cond_broadcast wrapper for posix/linux-sgx/windows - update document for building multi-thread wasm app with emcc --- .../lib-pthread/lib_pthread_wrapper.c | 19 ++++++ .../platform/common/posix/posix_thread.c | 11 ++++ .../platform/include/platform_api_extension.h | 10 +++ core/shared/platform/linux-sgx/sgx_thread.c | 13 ++++ core/shared/platform/windows/win_thread.c | 18 ++++++ doc/pthread_library.md | 11 ++++ .../libc-builtin-sysroot/include/pthread.h | 64 +++++++++++++------ 7 files changed, 125 insertions(+), 21 deletions(-) diff --git a/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c b/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c index 3f636863a5..90b603942f 100644 --- a/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c +++ b/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c @@ -718,6 +718,13 @@ pthread_self_wrapper(wasm_exec_env_t exec_env) return args->info_node->handle; } +/* emcc use __pthread_self rather than pthread_self */ +static int32 +__pthread_self_wrapper(wasm_exec_env_t exec_env) +{ + return pthread_self_wrapper(exec_env); +} + static void pthread_exit_wrapper(wasm_exec_env_t exec_env, int32 retval_offset) { @@ -926,6 +933,16 @@ pthread_cond_signal_wrapper(wasm_exec_env_t exec_env, uint32 *cond) return os_cond_signal(info_node->u.cond); } +static int32 +pthread_cond_broadcast_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_broadcast(info_node->u.cond); +} + static int32 pthread_cond_destroy_wrapper(wasm_exec_env_t exec_env, uint32 *cond) { @@ -1079,6 +1096,7 @@ static NativeSymbol native_symbols_lib_pthread[] = { REG_NATIVE_FUNC(pthread_detach, "(i)i"), REG_NATIVE_FUNC(pthread_cancel, "(i)i"), REG_NATIVE_FUNC(pthread_self, "()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"), @@ -1088,6 +1106,7 @@ static NativeSymbol native_symbols_lib_pthread[] = { 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_broadcast, "(*)i"), REG_NATIVE_FUNC(pthread_cond_destroy, "(*)i"), REG_NATIVE_FUNC(pthread_key_create, "(*i)i"), REG_NATIVE_FUNC(pthread_setspecific, "(ii)i"), diff --git a/core/shared/platform/common/posix/posix_thread.c b/core/shared/platform/common/posix/posix_thread.c index 0ae231c1be..298390364e 100644 --- a/core/shared/platform/common/posix/posix_thread.c +++ b/core/shared/platform/common/posix/posix_thread.c @@ -262,6 +262,17 @@ os_cond_signal(korp_cond *cond) return BHT_OK; } +int +os_cond_broadcast(korp_cond *cond) +{ + assert(cond); + + if (pthread_cond_broadcast(cond) != BHT_OK) + return BHT_ERROR; + + return BHT_OK; +} + int os_thread_join(korp_tid thread, void **value_ptr) { diff --git a/core/shared/platform/include/platform_api_extension.h b/core/shared/platform/include/platform_api_extension.h index 5a7e825cb8..cd3c7e95af 100644 --- a/core/shared/platform/include/platform_api_extension.h +++ b/core/shared/platform/include/platform_api_extension.h @@ -179,6 +179,16 @@ os_cond_reltimedwait(korp_cond *cond, korp_mutex *mutex, uint64 useconds); int os_cond_signal(korp_cond *cond); +/** + * Broadcast the condition variable + * + * @param cond condition variable + * + * @return 0 if success + */ +int +os_cond_broadcast(korp_cond *cond); + /**************************************************** * Section 2 * * Socket support * diff --git a/core/shared/platform/linux-sgx/sgx_thread.c b/core/shared/platform/linux-sgx/sgx_thread.c index fbf407be06..1cb2f5d09a 100644 --- a/core/shared/platform/linux-sgx/sgx_thread.c +++ b/core/shared/platform/linux-sgx/sgx_thread.c @@ -164,6 +164,19 @@ os_cond_signal(korp_cond *cond) return BHT_OK; } +int +os_cond_broadcast(korp_cond *cond) +{ +#ifndef SGX_DISABLE_PTHREAD + assert(cond); + + if (pthread_cond_broadcast(cond) != BHT_OK) + return BHT_ERROR; + +#endif + return BHT_OK; +} + int os_thread_join(korp_tid thread, void **value_ptr) { diff --git a/core/shared/platform/windows/win_thread.c b/core/shared/platform/windows/win_thread.c index 73b04dfa01..0cfc5dfb51 100644 --- a/core/shared/platform/windows/win_thread.c +++ b/core/shared/platform/windows/win_thread.c @@ -567,6 +567,24 @@ os_cond_signal(korp_cond *cond) return BHT_OK; } +int +os_cond_broadcast(korp_cond *cond) +{ + /* Signal all of the wait node of wait list */ + os_mutex_lock(&cond->wait_list_lock); + if (cond->thread_wait_list) { + os_thread_wait_node *p = cond->thread_wait_list; + while (p) { + os_sem_signal(&p->sem); + p = p->next; + } + } + + os_mutex_unlock(&cond->wait_list_lock); + + return BHT_OK; +} + static os_thread_local_attribute uint8 *thread_stack_boundary = NULL; static ULONG diff --git a/doc/pthread_library.md b/doc/pthread_library.md index b1de6b10ff..cf79214efa 100644 --- a/doc/pthread_library.md +++ b/doc/pthread_library.md @@ -80,8 +80,17 @@ Then build the program with this command: **Build with EMCC** +> Note: This document is based on `emcc 2.0.26`, other version may not work with these commands + 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 +EMCC provides some empty implementation for pthread related APIs, we need to remove them from emcc's libc. +``` bash +cd ${emsdk_dir}/upstream/emscripten/cache/sysroot/lib/wasm32-emscripten +emar d libc.a library_pthread_stub.o +emranlib libc.a +``` + ``` bash emcc -O3 -mbulk-memory -matomics -s MALLOC="none" \ -Wl,--export=__data_end,--export=__heap_base \ @@ -166,6 +175,8 @@ int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, int pthread_cond_signal(pthread_cond_t *cond); +int pthread_cond_broadcast(pthread_cond_t *cond); + int pthread_cond_destroy(pthread_cond_t *cond); /* Pthread key APIs */ diff --git a/wamr-sdk/app/libc-builtin-sysroot/include/pthread.h b/wamr-sdk/app/libc-builtin-sysroot/include/pthread.h index 71b7fce8c4..10b3978e9b 100644 --- a/wamr-sdk/app/libc-builtin-sysroot/include/pthread.h +++ b/wamr-sdk/app/libc-builtin-sysroot/include/pthread.h @@ -19,48 +19,70 @@ typedef unsigned int pthread_cond_t; typedef unsigned int pthread_key_t; /* Thread APIs */ -int pthread_create(pthread_t *thread, const void *attr, - void *(*start_routine) (void *), void *arg); +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_join(pthread_t thread, void **retval); -int pthread_detach(pthread_t thread); +int +pthread_detach(pthread_t thread); -int pthread_cancel(pthread_t thread); +int +pthread_cancel(pthread_t thread); -pthread_t pthread_self(void); +pthread_t +pthread_self(void); -void pthread_exit(void *retval); +void +pthread_exit(void *retval); /* Mutex APIs */ -int pthread_mutex_init(pthread_mutex_t *mutex, const void *attr); +int +pthread_mutex_init(pthread_mutex_t *mutex, const void *attr); -int pthread_mutex_lock(pthread_mutex_t *mutex); +int +pthread_mutex_lock(pthread_mutex_t *mutex); -int pthread_mutex_unlock(pthread_mutex_t *mutex); +int +pthread_mutex_unlock(pthread_mutex_t *mutex); -int pthread_mutex_destroy(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_init(pthread_cond_t *cond, const void *attr); -int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); +int +pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); -int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, - uint64_t useconds); +int +pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, + uint64_t useconds); -int pthread_cond_signal(pthread_cond_t *cond); +int +pthread_cond_signal(pthread_cond_t *cond); -int pthread_cond_destroy(pthread_cond_t *cond); +int +pthread_cond_broadcast(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_key_create(pthread_key_t *key, void (*destructor)(void *)); -int pthread_setspecific(pthread_key_t key, const void *value); +int +pthread_setspecific(pthread_key_t key, const void *value); -void *pthread_getspecific(pthread_key_t key); +void * +pthread_getspecific(pthread_key_t key); -int pthread_key_delete(pthread_key_t key); +int +pthread_key_delete(pthread_key_t key); #ifdef __cplusplus } From d925369a1fff663e08f0810a6180228f4fb79d7c Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Tue, 25 Jan 2022 10:10:12 +0800 Subject: [PATCH 07/32] Implement WAMR-IDE with vscode extension (#943) Implement WAMR-IDE with vscode extension to enable developing WebAssembly applications with coding, building, running and debugging support. Support both Linux and Windows, and only support putting all the tools in a docker image, e.g. wasi-sdk, wamrc, iwasm and so on. Co-authored-by: Wang Ning --- .gitignore | 2 + .../wamr-ide/Media/Config_building_target.png | Bin 0 -> 12887 bytes test-tools/wamr-ide/Media/build_folder.png | Bin 0 -> 10729 bytes test-tools/wamr-ide/Media/build_terminal.png | Bin 0 -> 109341 bytes .../Media/change_workspace_dialog.png | Bin 0 -> 9410 bytes .../wamr-ide/Media/compilation_config.png | Bin 0 -> 36218 bytes .../wamr-ide/Media/compilation_config_2.png | Bin 0 -> 22681 bytes test-tools/wamr-ide/Media/debug.png | Bin 0 -> 54813 bytes .../wamr-ide/Media/decoration_for_files.png | Bin 0 -> 3348 bytes .../wamr-ide/Media/install_from_vsix.png | Bin 0 -> 53293 bytes .../wamr-ide/Media/new_project_page.png | Bin 0 -> 7630 bytes .../wamr-ide/Media/open_project_page.png | Bin 0 -> 2239 bytes .../wamr-ide/Media/project_template.png | Bin 0 -> 8564 bytes .../wamr-ide/Media/right_click_menus_1.png | Bin 0 -> 30639 bytes .../wamr-ide/Media/right_click_menus_2.png | Bin 0 -> 32933 bytes test-tools/wamr-ide/Media/run.png | Bin 0 -> 8209 bytes .../wamr-ide/Media/save_configuration.png | Bin 0 -> 3618 bytes .../Media/set_up_workspace_message.png | Bin 0 -> 4629 bytes .../wamr-ide/Media/wamr_ide_main_menu.png | Bin 0 -> 21514 bytes test-tools/wamr-ide/README.md | 178 ++++++ .../wamr-ide/VSCode-Extension/.eslintrc.json | 24 + .../wamr-ide/VSCode-Extension/.gitignore | 7 + .../VSCode-Extension/.prettierrc.json | 12 + .../VSCode-Extension/.vscode/extensions.json | 5 + .../VSCode-Extension/.vscode/launch.json | 15 + .../VSCode-Extension/.vscode/tasks.json | 20 + .../wamr-ide/VSCode-Extension/.vscodeignore | 12 + .../wamr-ide/VSCode-Extension/README.md | 25 + .../wamr-ide/VSCode-Extension/package.json | 238 +++++++ .../VSCode-Extension/resource/debug/README.md | 11 + .../resource/scripts/CMakeLists.txt | 40 ++ .../resource/scripts/boot_debugger_server.bat | 14 + .../resource/scripts/boot_debugger_server.sh | 14 + .../resource/scripts/build.bat | 14 + .../resource/scripts/build.sh | 19 + .../resource/scripts/project.cmake | 17 + .../VSCode-Extension/resource/scripts/run.bat | 13 + .../VSCode-Extension/resource/scripts/run.sh | 12 + .../resource/webview/css/style.css | 70 ++ .../resource/webview/js/configbuildtarget.js | 28 + .../resource/webview/js/newproj.js | 37 ++ .../webview/page/configBuildTarget.html | 63 ++ .../resource/webview/page/newProject.html | 55 ++ .../src/debug/debugConfigurationProvider.ts | 65 ++ .../src/explorer/decorationProvider.ts | 88 +++ .../VSCode-Extension/src/extension.ts | 597 ++++++++++++++++++ .../VSCode-Extension/src/taskProvider.ts | 153 +++++ .../src/utilities/directoryUtilities.ts | 83 +++ .../VSCode-Extension/src/utilities/getUri.ts | 14 + .../src/view/NewProjectPanel.ts | 253 ++++++++ .../src/view/TargetConfigPanel.ts | 260 ++++++++ .../wamr-ide/VSCode-Extension/tsconfig.json | 21 + .../Docker/Dockerfile | 32 + .../WASM-Source-Debug-Server/Docker/README.md | 15 + .../Docker/build_docker_image.bat | 8 + .../Docker/build_docker_image.sh | 8 + .../Docker/resource/debug.sh | 6 + .../Docker/resource/run.sh | 6 + .../Docker/.dockerignore | 4 + .../WASM-Toolchain-Provider/Docker/Dockerfile | 63 ++ .../WASM-Toolchain-Provider/Docker/README.md | 71 +++ .../Docker/build_docker_image.bat | 12 + .../Docker/build_docker_image.sh | 10 + .../Docker/resource/build_wasm.sh | 24 + .../Docker/run_container.bat | 16 + .../Docker/run_container.sh | 15 + 66 files changed, 2769 insertions(+) create mode 100644 test-tools/wamr-ide/Media/Config_building_target.png create mode 100644 test-tools/wamr-ide/Media/build_folder.png create mode 100644 test-tools/wamr-ide/Media/build_terminal.png create mode 100644 test-tools/wamr-ide/Media/change_workspace_dialog.png create mode 100644 test-tools/wamr-ide/Media/compilation_config.png create mode 100644 test-tools/wamr-ide/Media/compilation_config_2.png create mode 100644 test-tools/wamr-ide/Media/debug.png create mode 100644 test-tools/wamr-ide/Media/decoration_for_files.png create mode 100644 test-tools/wamr-ide/Media/install_from_vsix.png create mode 100644 test-tools/wamr-ide/Media/new_project_page.png create mode 100644 test-tools/wamr-ide/Media/open_project_page.png create mode 100644 test-tools/wamr-ide/Media/project_template.png create mode 100644 test-tools/wamr-ide/Media/right_click_menus_1.png create mode 100644 test-tools/wamr-ide/Media/right_click_menus_2.png create mode 100644 test-tools/wamr-ide/Media/run.png create mode 100644 test-tools/wamr-ide/Media/save_configuration.png create mode 100644 test-tools/wamr-ide/Media/set_up_workspace_message.png create mode 100644 test-tools/wamr-ide/Media/wamr_ide_main_menu.png create mode 100644 test-tools/wamr-ide/README.md create mode 100644 test-tools/wamr-ide/VSCode-Extension/.eslintrc.json create mode 100644 test-tools/wamr-ide/VSCode-Extension/.gitignore create mode 100644 test-tools/wamr-ide/VSCode-Extension/.prettierrc.json create mode 100644 test-tools/wamr-ide/VSCode-Extension/.vscode/extensions.json create mode 100644 test-tools/wamr-ide/VSCode-Extension/.vscode/launch.json create mode 100644 test-tools/wamr-ide/VSCode-Extension/.vscode/tasks.json create mode 100644 test-tools/wamr-ide/VSCode-Extension/.vscodeignore create mode 100644 test-tools/wamr-ide/VSCode-Extension/README.md create mode 100644 test-tools/wamr-ide/VSCode-Extension/package.json create mode 100644 test-tools/wamr-ide/VSCode-Extension/resource/debug/README.md create mode 100644 test-tools/wamr-ide/VSCode-Extension/resource/scripts/CMakeLists.txt create mode 100644 test-tools/wamr-ide/VSCode-Extension/resource/scripts/boot_debugger_server.bat create mode 100644 test-tools/wamr-ide/VSCode-Extension/resource/scripts/boot_debugger_server.sh create mode 100644 test-tools/wamr-ide/VSCode-Extension/resource/scripts/build.bat create mode 100644 test-tools/wamr-ide/VSCode-Extension/resource/scripts/build.sh create mode 100644 test-tools/wamr-ide/VSCode-Extension/resource/scripts/project.cmake create mode 100644 test-tools/wamr-ide/VSCode-Extension/resource/scripts/run.bat create mode 100644 test-tools/wamr-ide/VSCode-Extension/resource/scripts/run.sh create mode 100644 test-tools/wamr-ide/VSCode-Extension/resource/webview/css/style.css create mode 100644 test-tools/wamr-ide/VSCode-Extension/resource/webview/js/configbuildtarget.js create mode 100644 test-tools/wamr-ide/VSCode-Extension/resource/webview/js/newproj.js create mode 100644 test-tools/wamr-ide/VSCode-Extension/resource/webview/page/configBuildTarget.html create mode 100644 test-tools/wamr-ide/VSCode-Extension/resource/webview/page/newProject.html create mode 100644 test-tools/wamr-ide/VSCode-Extension/src/debug/debugConfigurationProvider.ts create mode 100644 test-tools/wamr-ide/VSCode-Extension/src/explorer/decorationProvider.ts create mode 100644 test-tools/wamr-ide/VSCode-Extension/src/extension.ts create mode 100644 test-tools/wamr-ide/VSCode-Extension/src/taskProvider.ts create mode 100644 test-tools/wamr-ide/VSCode-Extension/src/utilities/directoryUtilities.ts create mode 100644 test-tools/wamr-ide/VSCode-Extension/src/utilities/getUri.ts create mode 100644 test-tools/wamr-ide/VSCode-Extension/src/view/NewProjectPanel.ts create mode 100644 test-tools/wamr-ide/VSCode-Extension/src/view/TargetConfigPanel.ts create mode 100644 test-tools/wamr-ide/VSCode-Extension/tsconfig.json create mode 100644 test-tools/wamr-ide/WASM-Source-Debug-Server/Docker/Dockerfile create mode 100644 test-tools/wamr-ide/WASM-Source-Debug-Server/Docker/README.md create mode 100644 test-tools/wamr-ide/WASM-Source-Debug-Server/Docker/build_docker_image.bat create mode 100644 test-tools/wamr-ide/WASM-Source-Debug-Server/Docker/build_docker_image.sh create mode 100644 test-tools/wamr-ide/WASM-Source-Debug-Server/Docker/resource/debug.sh create mode 100644 test-tools/wamr-ide/WASM-Source-Debug-Server/Docker/resource/run.sh create mode 100644 test-tools/wamr-ide/WASM-Toolchain-Provider/Docker/.dockerignore create mode 100644 test-tools/wamr-ide/WASM-Toolchain-Provider/Docker/Dockerfile create mode 100644 test-tools/wamr-ide/WASM-Toolchain-Provider/Docker/README.md create mode 100644 test-tools/wamr-ide/WASM-Toolchain-Provider/Docker/build_docker_image.bat create mode 100644 test-tools/wamr-ide/WASM-Toolchain-Provider/Docker/build_docker_image.sh create mode 100644 test-tools/wamr-ide/WASM-Toolchain-Provider/Docker/resource/build_wasm.sh create mode 100644 test-tools/wamr-ide/WASM-Toolchain-Provider/Docker/run_container.bat create mode 100644 test-tools/wamr-ide/WASM-Toolchain-Provider/Docker/run_container.sh diff --git a/.gitignore b/.gitignore index fbd9b8e315..fa9e051332 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,5 @@ product-mini/platforms/linux-sgx/enclave-sample/iwasm build_out tests/wamr-test-suites/workspace + +!/test-tools/wamr-ide/VSCode-Extension/.vscode \ No newline at end of file diff --git a/test-tools/wamr-ide/Media/Config_building_target.png b/test-tools/wamr-ide/Media/Config_building_target.png new file mode 100644 index 0000000000000000000000000000000000000000..a1270007fda138dc28ea687ac4ecbcbee11e9072 GIT binary patch literal 12887 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 QUjSZOYI^r7?mi9vKXlfai~s-t literal 0 HcmV?d00001 diff --git a/test-tools/wamr-ide/Media/change_workspace_dialog.png b/test-tools/wamr-ide/Media/change_workspace_dialog.png new file mode 100644 index 0000000000000000000000000000000000000000..9f6a61428e4de3a77f4f01be3d8a7ce62c6bb292 GIT binary patch literal 9410 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 s@Wq^mdKI;Vst0COB6xc~qF literal 0 HcmV?d00001 diff --git a/test-tools/wamr-ide/Media/compilation_config_2.png b/test-tools/wamr-ide/Media/compilation_config_2.png new file mode 100644 index 0000000000000000000000000000000000000000..c16bb09ec344905b8f57342c96fbdc83cf9303de GIT binary patch literal 22681 zcmbrlbx>PT+xCmQ6ev)jK#NO(;$Dioy9Cz+Ei^b3r??a-ZpFP2q@h58;%7byXP9Z-m zIB3W-#;B35$Umr_I*KwVwPP=Lkp~zK((2MEC=H4D_g0w5V_bJ7V^0(mqMm;r)PA>e zTND%{Ze=-XJs)#K?v0_IVaMN93u|(;A*N7txttdmR1B}IpG!ZpOVLiMz_Ux@!0yG> z;*}=Bep^)ZUI3>z;d5kDAC1kj(8-EM0O%*|B+3Bv?`}%IJ3Ib(+Lw9)Y3=uqLlYXFu6H^gFL*>;zSeJV{`|@P zbUz*}c}TpzL)%s9@_S*8?mjLLvns~h^=jQ=?uTt=};CkGX@->&6-_ z=y|_*7o7g@o8wlguOQn$RhdPp+Fduh-X*JpPgFCvnV>Fve|rsws7F}mV}O7o_nX&I z*AJb2cbx&lHHC@`3wM$&glitb&)V@^iCR>9-aWy3XM=-nW?sm6%V*S&&O7yR6-A-U zuP9jDYh3npVg@&teo(J!v0TZK1LflX&!Zm!UM(rFf++8AsK_kIox8@rzRy)9M;Y=t zw(Q(7>mmKLi`ArxSq5veq837_(kjzxz{}8;@0Jll#lB5^YQtGK%Oka%YIz&!5w3~70Q#^rD zy-1nJW^$I(#ZUqS@FU0NP1YxUFB5ZUA1kBwV%jV>Z$S+N;HNS-1D5B(P|N6IzL(lC zk&0NRw{n3|Bi0!OksUU8Sp+Eh9DI7A{x#^>@=3xC`3U#0SXvc<3YFv&*8( zv`QH@aiV}v@y%2x%>07Ozh5k#xj+xlxPX-6NmjqsM;OWgo;}POO(QKLW}%hwGV-s? zy5lV4!N1aoJ8z+XBb;r7Ue7;0-Hbooi!Y~S;ZO{o+kWC&I}eAViA*blC{X}Yu*%!oALi;OT>i4s^L%W;Nnxfp}_zDx#!}9 zijdE6hrWu|MQ*_V&x16oqGiG4n2c2}-uM9`{9KA;TIpxK)Jw)t{MgIfsW0JYp5MO? zOJU%1ZPR~XqZ_v47APC?TRnAhHz(;T@Iw3^~c;$!AMeO+;?pX%0BdHfXPn} z%B6yDmO2DI5jS-jh0(QA;2#0SoU4i$4UDdUMM9&tv&|bi(1`e!bM}~=Ikdopv*bWv zY3EC~&ZU>dq0AWrKf1S@ZNaw7K%=GkOfBOl-S4H5`!BoNclf*dy7SATPUvRvoWeEA z^k1*WJPQ(}w$*?VADIjUQ2^u;#-wY}(*J6b{uw8GW#SABt->0k=PdR9q(LL(_(m)s z-ISxfi}PM!y7sR^GR>mA1!j`xGY%icK;h0lpZt%^@m{Qaqa+7RsFw-#viL+EbYL{> zEsE4)_anilq2ZlNd4H-}nfmb!`QM82ie=EE>04TAqTcj+Q+27=_4GexmK;8jrt1W5 zzs#ca-D#+4#<$>LNl0jv^rCK(?{pI1OPq3JVdV>p-nE~xbIxi;NjY-Q&k}SE(@pw9Pc=&ebV32$a*OHt{bt7@XxlCX$@Bi(eNC4HSKrwqO@YNmC#4HA=jNI z8Upew{yV&DvevXYI1xteT99dAxW?gA^J6~y&F)5qR>PFj?OeUnoCtoIH0AfIXB{zz zqdDNU&WK%(W`|a8F=V&BR9&+=4Yv!nxzd-hq?cYUHVt=h9g_o{oW<($OIKyFuDF;( zp8-`rWZmtVT$iHiL9@EAu6=FZ04arDDW-*HMlj6aMYz1GkY8(Zf4xXdM$r<|njEss z_El)PtSyz~FqQi`A|1^wU6fU49?MJgr+jzIXF4L5d6EU}Pm2bJ&x*L@cSZozndEc{ zZw~l=nCrfW(&rt)BjEBYcFxn>H>c;ct9-;A{QVfgH+5uJvkX$?q66N8+;GgD=G@LV zPnHN|;2lh`u7755!mm@GTK1Oq_$)`Ud`1nzmPN6fD5hFYQwo@-k#C_yOfL=MTn$o8 zIlV3&mRJ1)uzV891h?hVXbkE>WyXgbGcMm9sG{o-^eY@;o@bq&E|4U$hX&nHRgRgdzoK-I7R2!A27jxxwXdCX2qIRJ|LY>55()~?2L-*{n#%H=*T5Y|kG-u@` zGX^mSaBww@TZ}T3*Qf-r<{cI=J%(%Y@nX8$#j*_mgc^uZe*F%X#;fj7UPQJVzT;de zKPjMAPuZ=30g-q_s{k{*eQ}rSb{b42VJB#|;(3m?XhABWtV`*SpMjH0B+Z5@p&oM^RST%y%>bReBDT8oPFGqgv z%=7xsfGN}IZymFGnBgYdrZ2gFX=DegiY{nhlVLGI*m79NZfl7SBGinQunv-`JA=W+ zman~SQ298Qq{Jl$13%CxfhZ@A$o{lYz9H%Gm;+LlV*0;5w|zTXyX%BrFZ&~U8F;BY z;r6N!5W!G;^CiNM8)|cap#_azwDx2S^Z(AGb0U?`B}n^{06$kq#OUvkF*C5{$ z`ZJ8ek!Sze*14|}44Bw8%Kv)InipGel*UiugnkW$LueWcn};Dn$M)D?tt#BDa34Yv zUqus?12CkYl_ACKGYk)o|HA>_24vs#8}0SpXQFFArC}afB?~4~;T5Ztg1$H+33j3p&9X1NXW);BV_Pi2ic~uW$7Fk-G&ra^34!Hd$$c` z4ckiI6s1Fk5AnA>i(pu~`Mtr_X7x~1z9Mogg8XLC`BYTtXWl&v@C#E?5=#0OZb-dy zRSlO~#4bepb>uz9B^I(n(a<$#go11B>y1!Mf!R_X_pi^jp*W$fG__8)?$jYwrt}ii zfpcYeC$c9DIO`N6?g)e>f<9K6@ffu|6iw&xr%h@Kx8Q@Tv?%v=FNrvsVa$g#O3szRpf*2 z=bB$D_&wRyW!d9SSNqd~gZn8A@(l*mN2b;YGRCWH0yd+CAOW5!Yf6Q*BRyY8to2zzW zO?Ho$(AHt)p}Y^KyRij335%50S2SOTeLI$ae0)8uJ9OokO@r6Hy|CKuS_QZk2=Aqg z`t7#9Q#M-kcRg)CwsA2ihYBuOX6QXvyGc1e3D;-K$PusJ^1;V58R!~47P~i5y9x_T)qh7;YOLA{&23R@(RD|ntG44*Bu4zV0ONvtZC#lO9sXr z{;)7oNHsA1LOn3PNZc}88#dqcBnpJR96SD$CWP}w#?bca7k! z0<(SsSp8nbBIsdoIP_E?2s26)A+*8^ocJT;-(b%z)%jugf|zw+Ei$jOVnH}yHzFBq z<#P7`lU*WN3m_#mJm$3h3_rPnP`YtkQeB#@e$TKFb{M44Cd3pQ}N5)>hE2KUuZ!1h#O?7B$ zklAf-6LVh&W-JGVyBOav@$r1vWvDP5I+}a=IP7Uy%kxfzWwIF`PJ4ef7<<*JHpI5_ zts~f2*w-%LQ=o10L2%I7@1u+(Nfk~uqssJiD0=KqT?9eXFPDOdWk8v1yfO6gWLTeS;c znqH;vI968hrCo{|-J5LGB*;*98;gY3xwT&h2Afi;$>QRfj@4{J{B^G?3n7???|Yst zxM=e}^)b%{;a`=VDOl*KcXZ`{E@een>R#kod}S!j*QD)VhcNGOhh% zdvU!-<|L)!?iLlfNave6BOT}lZCbv7!-4r08Cmn`ebDT(Y(;kawYO)j+k8Y%{qhuzs-lTPZi%MiVIBR>~5!x~|Ku4EDW-HJlK~1klXg;k^8vSs`CG z&#thczM07{*~#?l6hGTtppVtPU&XQGDKt&-n+%?#_x11LZ|*_fb{Xbj^gV6j8=_Z# zc3D&DSD}&?$E2E4J;a=rc<@og{qS+DAyxJ@kFv@`i&jGkT%SV-L7$B=uJD)M2TSq% zs^j`W$$=_2Ed{1nL2mMX!f!CPeWw@qpV>tP3{F@JJ!du zX4einLP0w#t`&n&o0*=g{D2_cMwz{0wzJnBlaxLy4Sn!mS?(Kn?1`IhzOGjCssc~u zoh?Lrza!$U?q|2Rp2yOSvVZZ6+t1UTI85=Z>An>ab!g_jaw|UdVK}Q+v{6TtsW+_A z3H=Pqi`OSFR^%TJD{&3?wQmFm>frAQjzR`sH!t&XTEX@GxR)p>EnZMD-6Z`Q7XJ3? zH8<;s<{ndfkzs#YUsT;?x=+cy>lQCEu?!*@XX=}z(=4lE$_xeXa$L@0CO0$#-0D;* zgT5Y6-6z$eNqmv7xnkuZygE7CE`*c&HJ`l=crsh!RwsOL# zIq*19q8l5Vas9ycm#;HMYyVI(YIj7OjvC)eH3BPd05O&?oZwnQkV@= z9?6zVEjju)v^daIuI+t?PZm2Zpg~y6w&EZz>MJF^h)J z=Hc4cf1|P)0IJuAZmTib4#DlJ!V_mKsrOPw;;PSs{32Z6gjIlz^}iStVSlUxnrOz}F5OB!0$HH?6r?UyU z>&V52;?aq2hIcMhb1cqOyXCvfbP^F1YsQt!Tl*?mO@s>`2_LxMrZ$24;oPwLt|Rc# zGtnY7mzKsO0vAg=W-s-Z%SKq4a98(Ut-6y4Te_A+FcqG>v(C+5`Q^>oyB5UkXBDiS z;E*sw7Q&Wc!7z9&06Gh%R456mTt&3Yd$hpy`5?%{Ju849b`NFnuBWvPKc?Gil?L;$ISj*NcQCI1}o3Xp&KaVmXSvIbur-mOlo1P?)|qFhhGbxKL%rM zT8ecFOtQo+Rykvbn$8qfv%Z8ueo6&b`wxRb>Y7+0*7i4aBIBcbYjepkj`;b=(h15G ze1Y9T6g=0TQljPlnT8##92-XbyYcUv->?e@ptehBc1M`y`{aC)-h&n85o|Y^`W%+= z_gHLJ5!a|x47&v4nS$}DOSu?UQ>7!>k+FyM91Z5Ja>_1I!_jS`{lwZ?|Lt}89(A6a zGRk6C-Cakw9WFlMg`zJa#*feW^XJ{l82-b-_lmvbbQ(q|G;+6RJl|+>Blp%DWggDn zDbYx@`^(jv#!6ECiB{Cf==SXk=c-xF^RUa<0>AdF%%7`UeqmeAqR9Ofl*%^x6Qm+P z^t-{~ShUr5%C$IiWK9o|#iE0L`MmG63K1m^q6GR@?gs=Lm74e>WaI@)6z1Jvt1N-#OPX3)TV(8E;hYU0P)<0{cVGDgH^zdBKo2A ztZtcqVP9pa-0STrTQrNcyKik~m$d4J&B@%_O|3eYA&V)~5j(Gt{hTv6Q$A~+yGS>s z#SBa({GH{`(7OaJ)oNdrlxf-z7Z9lR{kH9hL^=F4)6L6NBLYnz{wCnfg&KKA8PQ$jCdTIfue|lajPvYmD!IzV=PJ<(bWh zEzy+&da<6HvC+dDr1c!57K}>(S;fRLP8fW)z=;NM>F+r#Gi65%zC*59UUlXUYt?;+ z;F)+cxC_X1`uY2R0BYpqJn$*(`C=cHCe{C$OAS2#l}B(y(I}9SRTk_O#m26uMyjT_Yw~52v{%%DA{Po8Y)>V|_x_at*d`6)alf3{PIcU+|roWe^6h%?-Y zYMpJ5k2T8k)RhBYMz!JC&e>QXrhW=G&);)T+(p76(Vm_a+7f~sq;Y1?qod3V*sc?* z-XlyDc1cVtCezEJPR}lTBq95>1uLG2oqe;-aOvgjy;7YYOToLl{Hto0OKsf@L3SP_ zBxh%ar)NhR+=3z)lFC+AP)yoJrH&L?4%;Tx!5fnNJVO3Z*5CROBE>&bZ8pqYWBtX7XdIKi!noDA#d zPT?pb>nCth?sr6ki00rL!mvD;T(21ruAYcf=MuvgaG(vP(DK7%v7Hh5k^C$0L&Y!e z$6mu!*>Q_mM=*87+RGaDZx5`8yAji2uUF^w@n&Vx7v2Wz~tPzDK>bbzyhhu6yN;`tBYYs zQr^-*XR_A#Fu1nE>N4{3XrR`7oe^jot*%DDt7WkO@w0h$;Mp@uR{3k0vtpE7g|y52 zT~m&mDDaw#Q%iOKm74clDUY(NLcm(4cEQNl;jiDcppIo5m9U zG2aYm*51Dg+Pfhu=5?uCp?8Sl-g{g`iY`-O;oPsUh8L_>Ys`Sp;RBYg(e-TwKR$^f z?3*4lq5ka-^4`Rr6~7d}1B8?@4Ef20hjpr>TU60c^zzg)`^WL$>gKXqKQyfzAIHb` zWm~j-8Hq~C(0iG%rKwOz!2HV>(-$@>TX|FD;CEL2NTg$50Zuc2_js!av|RB~oC7bj zX24epSCvvQL#Q2Vv9roZwK!UY64i*LqAVtO$S@b+|LGVM3DF#4Z-2I znf5S-JI$~0qU;rbX}!Jf1K_Nkeo@9(DM`j~@l3u(0Q5Z&b#Q_ELOjT%wGiC4WS27^{zr7vXLU^al$g{OPRHEP^=VJJHsQosBy5Kx3BR@}cs_<~^ zc!zS(cl3ix3tNlNxspk9;yK}O_~CQ+K$jM)t3Ib?dG;kOC{>LVQKwIv`Dz|>C<_HT zapW~mUHk2D!Qt<_TX3W|X9l&rIn;_qp*CeFiu8!YW%MspylZ@a(D8x4%|Eo6lFHtb zTTt>BJ)O|^JhhKH9WJmQfB97p{i9}-pcM>k2om-X?ypz`mDom{Oc3-pBf6y>EV&`k z@o7-+QdYU}>$^K10A04OLEWs7b9}mESw4$vIpFrqrkyN|9iK=vT z$<7nrtUlbv+5ElDUGL@vZkWhQA#&1v5mUiTZ>+M)1)B@-AL-i{N?7{sEH; zDh5^~bZ6luhJ0qIR-FJgLl$!bL|x?8jnLEotsV{0TirW$*dRg9Pz`g$2G3(9$8&*B*tw7r4#?o493u)qHw`KE}^o3!s<~H~c3eHSx z^jAn-a|Zsc4`+U;8VMII+vuRaygNN>p7wFj5t$F^W;jslvwg-pit;%@Vf#=$9~s@> zw=R$Rrf4>h^k%jyKvzQ8_X2GTsDUuQ)+VR*KRiNPI@zOeN#Fg2PRYLwf_rG8B4`lfr z$+1RBvHD6HZ__cHoU*2Cb=p1}j%x}eNRQ9ARvtmp;Do9_1H29{P_DWQcijB@I^tq@ zaRXy!NgAYyGa>DNLzy6{bTawb=JF+S)Ssrj)~0ZRBbhJHGX z=LIcT-}#u$aIe1;F@@sUIfj^|rv9zd5|M=-rmDsRuaMM$_+wtQny8WYgP_{cq;nx? z3!+N)MgKA@tyC02@$qT&I@m$mFPy|`@#-|0!`U$P9|vH83ALd>OK@jjADl)dOc zdB?9F%A=`y_sLRC@FyN8|Y7p^762HMI4488E{?#h}Fs^JY#IDPNE?Q>ilF zZ0dVK>Hh4&i~pt))*CYZ`urrBU?wNn-SC>bHEWHzicmG6%|oF zGPh59Ueo8ZT(q^gIJq5br;E5ByHv^mygvx^s*y`^bXyAfY`$9YTx*HW~vr1Dnt*| z#A&f;CnCB_^|!-+b75m#L*7s1(GtfRw@ip{tRJaS2!CBoeQj#hu zGo+Eeg4f=GF{~|*fc@gh{@>-)2(PCb9MaV}$EEPZOf#VF{vb-8{^~7x@ zpc22%F20Qqo^~|&cJ!OWsU+1Va@8NA17XVUm43P=i(CtChVOQ%FrAGi2EDtPLGi(i zUx!Or4qCEhzf+pdad$Bb*nFNbPt#9U168lTL1ux-6rp5)q|hG=p~1hK8K8;fi!?ay z{_r8ho(s<$9)t^#Eqb>v%*+ShG-zBIpJB&d`yxGu^5uo-7Fda@nYw|VTK=$lNDWu; z(&EBh5Ej+5Nr`j6>)%yz>OzJZh_Suu=DWn!|6q3y!GD(_1=o@YSr*c}iYQad+IBk9 zovKFNx=qdaowj&QUfVA$p&^z?5h_CVe;4z$%kN=~IM#&a0O)_VJZdc{82z6UASj{_ z^@<<loRy?7*bK~^vDiQ_&B5lv>+-0Su)l@tn(cI zE?EQmc2|3|PZ=b7&z!pwm!=ukb#1ZEV&>Bs#(S6d!#Ui_VJ?IM*Eky6IyA<1 z@PR*Mq{2())$s)HbQ)v*UE~c7l78cP%-q%#v;$Z~aWRH>W;gALn!1&{r9rOr11p{2 zcbz1P!1cZmMrW6mN1u0I%FBoF*R$JsVYBWm^d($U-?*b(u)L#qV6i|JN5jU%O(5*Q z>>3vGKKI+V=wkdC)Z&ho6GQESoCZq437cR}|940<%2K?gNIg#wl;!|zjkf3sJg0e8 z3=oP${CP10re}5U{A)bIzul_KWNre`-q94cxDWc)m}Sad23R|K;M{0w3#5qpZAz{h z_b>f;WyN&Wk~RtZu7Ks&U1W41Gvbtyhk!(_mXLqx{ofcH?M-mSUwpScbHS#RS1yFI zOnGMiNc5m>5jp}HLR=S(%cyP$53NA3HJ6&z)tSV>$TJCEUeWV={rK0Hi;KVu;He7d z@p1Y6^XjT;^(E&&l(_YhsIMjum(jC7$WVF%-xrjyrl5Pfj?;sNIZl}=$)2YM6pGYx z2#IjG2TkpzvF?LcCBGm6QQ$ktZil{B*xEYx1@fNAaWmjp9;7Yc6+w??E#7m#S-Wcm;WJpfA&LcvPza$e~qyegS zO)f6uYO5`O;5CW+3HWRJy!X_{#JRe^{9U2E%Xpkxj+yp`SJVnjmv=ctp7 z;a%|$>BS|jXWO5^^!D!^wsofIXRgA0PP<1+NH4#v){NW?92t=AQKy`!b+&|Z%MyH` zLhv!sP?duhTnlv?cjnxXRfch3_Vf4CPPR$UIbVr2J@cb33gcMY`8ChvBP8?GnQt3( zhx!~!6)9Rk?R3g zCadzFdQi9{xnT7-up33hlySs|-)TbnN0$*^a}ug!kjgQKWba{4cWw2d6vxxE;iLI? zw$)8QaT$%69(h3?UD-XUK90XYR=- zYGy^*Y|2*b$g4h)E(b(>Fjod|PiWsZ=JKROLYgMrU-?p30o@F1!>4(MmIYU|(aNOL z9@Z3s3>%V9GOms&^2QO==9o>*{(;_RV=DBMjPEA6m*XI>M{JQUZj}nnOVSS+PO!|@ z%>usa`GBj+2KtEa^~K;eA-hM1Q)mfbK6@gr$;i|7G=n|$vxYge-oT4bOAc|N(Hjar z`w-I)SJ8C%i7mBQjJ7k}#5%7E&E`KnqElP>BUo3`ac^QHIur0<$Q0kS1LImI6xE#b+N^jWtS$c z+2R&cHh`AY<6>a@9zqj!+54?*YhsSr2w&e)XjFPks~jLncT|_K>!KfM(kZkQ<}3ki z8W!gJrqU##8jiC-gLygKd=jdJQW_0y<%E`=Wd$nvO?P%9*W`bacZ#k@#urussu zj{~7;=fh24C;`ZLNMr6dS`i~|Bm3dcv}P*cgsWOQ?UI7P8-_AT9Z#0SQoyTy5nnmR zgTV>U9XtrZsN;Wg<&uEwV#Ustx3%eLZMnfWo4*$yT)4W$C}%Ma48F652}1Q(@3HT( zR!dgUp^)#a=*Z02>+SE0&;80&-%{A9g?~K^uMrRJHO}NAEybZXti!@pQKpLKRRWO* zW7|oS+yORre3OG9%1cjc>r-TYD_FzIFh|)>o}+7V{n%qVm+&|BXwXvp6waJQ1LBlO zR`X+=L0WH3$@E9dP6~m|+atIVp6>;V)JJid2}zo?XQ>gcV*@)T=yJrrwjndH1jwv= z-Ni&X&?@`P7}aYzrChJvb-Dv@7kALmRNuyB4~Y^fJjDkF1|D0jb7Rh-$HT^*YumWw zt=T^uZsA-Y`iRBH>qcEr4T$JNC0N!PJR_8}V$+0fd^0xltSbA;1r4GaqM6th1pSx3 zicNt33=WfWn`R9pcEJ%iPlRZucB3HcS>|(Td(o=Kv3Eg{@Q-5U%j~kC*rp&>4!)13Q94U! z!jqX3d=LXCTl-=yIq#+0?O#dhLXJil5RkAIR2M5~I-<7``$|E6Ms8o=K4T|lESv&# zEBdMtuf%$~O?)-r%-2n$8UoNj>P?$;M@s2uHUX)^F7@nO96*@szihh!YX&J!k;(V} zNu0L6hYnk}=+B+J_P)~Fss+CvSVki5*ac?G8&=)D&+^!qNgDVpZrXqL`fm57424bU zCImseOOkhM_Xni^7JB(eiOsXyv(N}^wdhrMyUrjK8PlzPauVftkr#9;sC$Ttj4a2$ zRFjsCqIe}1fyS?eXNtB{?Pc|-#k@lOKWi7tPFm*2M~L2jby&jBpo({~>Urr*d-TUP zr)D`iUeLrvc5?38?$;xJs3B9CLmjUlCjuR47;T%v3n~a1lxH7iyR|YY2Q&^W{bb(= zK+GX(X~oSwYCLwLKZAu!N^&`)xnc>T@iwtH5*!KZwjzs?nTUjmLKNiT7g`x7=&?54 z>E41>3W?wB_S0xd-zLV=_hoeFbe|-2_u2Ih*N=y!w_jFo85f?dMbHcC_h?WXQvGl# z1T+6*+3+$h)r>f0XH6|=0v2SSG^Y*_%(LR%gRn-#{7KnQdeQ1-P0e7N*%<2T7g4yO#hOru_LTQ_~z5?&1Bm z9Dqj)e;;M|nVL$(Eo&5u<)sh{&^GC1hux^AlgLl$uiP3U8yd8m2%)vC8g%=-^k@M4(z+)WOkq!wHs zQcXLO>KTfhj^=)-psH7Z9@Q-J&AlGuM*RxRAQM>lAnl`aG{*eRO1i4(hF0!6BALya z-i0CpwpQp$-uFTlq4KP)tyDRUgrqGV1fK<7&f523pX?vt@&9=7pc&4^{gH5DSPs^bB6)76T7whz(WtN7FZ6cv}~ zC@f$?I)u|TJO(5BU4nSB253ycE#gl4{mQkS(Tzf6U2Hya6IMp2u_XLti!mL&+x<$- z+6gVTh|p$bDyt)6Si(PS+#S_$Por&yz-Y$RabjxvE{>Y&MJaqa51^LuY0HVasjt#R zdD%00rg0cElQ&`l$d^Md^>p}04^c{ibi8TyuF`|+g?d+mcW)8ja=k(45xuGe&w9Cbxk zlqqX{VX(v9;a&@^;o_oAjZfd23iMSyts+qUDpNc@?n;C9eCs@T0y3W$!peNBsa_K< zc5$UG*#9>t{mhebd*-lhj~vcdSnV3_{P7B;LWdPt324S(aSS)(^AO-#Y*i`Lip&G0 z;W(A{H#SsSpF7(7)+1mWz?>RD`Q~=@Mlc`Sb~r`3AR$y(>%j&M~7DlQF(B0mf~(5MZjqeR8d24z;Zz zcY$sY8F}$fu!$-D=D&h&~4c ztKWrWB8v=&Y%5Gp-;Z)>ubYy*pcY0M<02s6HfqFNOvw|)DFafjbj*a_Zb#zXDsc%K zBK|4@$9i2LoSC*G)QBlXv9KQ*i+C!3BDxRpW(J(|4K8hw5(;U1p685v(xrJg8}3XK z_xJs(KZQp`@Ud^8_#)7nd_#l;k7M7U3N9ql{roRfH0T5NIWT+{*vG=CIC1D$1XZMo zz|NCUh4*qaM!x89FF8b7b@gw~e`bBruZ%lK=8Kl<5^9D&=?5-~2t`aRyo9_7GiaB2 zSTmat33P*O=3R$t?KzwJ^$!(T6RwZRGqZ1V+oEgJXt;loOw?+}3$RA>-Hu!kLfyaG z-WIa2JAF2L3%do@)hLg@3{QoKD;5%{jn*u|)Wnb;oPp>M^h|yaQv_P6a$of%cfH8v zQbpZ0Wz3vw^;0@HO%TBRx&6P~1Q=cClvf@~jmZr6%;}qp#k6VehZZlpfUaAOJa-j! zS*a_jElmirMy7qp>M6j* z)2ospk7@Uu&pIEGMxrJxUVL7g|6GpLNTC0^bLgwNPyh8r>FQq<@c1P&*+}IV8xuIT zW4%aF*Yj*1qZ7^Jt=9oMRfiSdi1*Nh5)t8Dpre~arZ%0>FG7J=j9v>EouP74Ny>f{ zK1%xTJ2<0&(vHQHpHg#%Z<(CUgKlqQ37MD5v1QG1`?8|1hp`7i{RtU)ql8vHzUony z?{Avek!jL_AHeIrr1XPp{&~bOL!5$a5~{P=CN`<(lmJGrc!(|pN#0H<>m7aj=;E6l ziyz!x0x3Pv@VIk)zh-tN>h|2gx7N9oSS59lI0GX5pau7*3EQqS{_bdD%=;PgwKs9Q zY-2(p@u0mH)h-r-5B=#YBdAB2PrjFrbo>}_V1G6cgOQgq#?ae9tLVrd%lg8VunOz2 zVzh_T>1jpyOc>M<@5e$BxU9dDFpX&FBn)0!lQe*e}NOxuc~0;qc|+RiX7d)@Q49b%#;uV6R~&N%RyB zMJUSvyYwy<4YBD6ebLF-<`#4{mpO!S1qlB^yvn%fMSRtORsOr7%;@m@z9xYK{=^2d zz8$P{p_m;Umr7zH(k7t$4&`QKOS<@VK)5!mp%*cKGW@0yr| zZ=APIkge{IPbcvuSZhOf$77MuV%jtIsx)iMyFty(1bp*k+N@8f7`;t<-0uC z{iDGyrSW==PSzZ%!ZSWX%%>_?UlJ-BpB(Z-B!JHHuX z%VAhGsA@q_G31$))ZGldzvyR`6n`?*p5mwe8@stRtE!Se5fZTV9vbM4{T$E4f%QVy z>Z9BAqf|)c5T~I>UG_!~^8U?@Xpe}?Q3b-QU;KWR6tE@cBZsI*^j zmOFM_mG#H;_B8IaV|!6E4hg>O=jyvNO7-2R=(}}lWJNNA3QbdGyWoBMPb+vXQsfzB zhfP?hLA3~#E812cqMv?h#!d{>OH=9T<)_jQ+}yMuZ5G~cFbeGH#_}T~9a8dF6vc-B z_Ms5MRnP3FaFYBGF`6`&ECR1`OwVw3#9dJ(5BslNW2vl#705oqI5(ognV zP?riZX8K%F_Nyw;u#i9!^iG*MzE-?QU0`(lvUYt)7H zlQxGo!R2$&IwK6ra^77GJiASoY1}aT8N3J!aM6fv2dkS(I2A4q|ECrs9FFO;>Vf~) zL!Nc~ILE*GjJ;xQDvL+C7qqd{3*%9qua~;TkH}AdUcGM-wlud2RL24Vp?8Zzj>W8;0*LN& z5K`RWPtc!&7?t4y>Q!=hR=&?;=D(dz#)@fOx=fCg>&{TS{GNLo zw1QdyM)gHhx;?PWaI04ij9{9h^APWuv(#P;h&?*g=1RY$p8QwI(7eq5;F5x-*zS$umnqGC=16d`WCYn0 zncRWZ{-=K|RfLJVEx<>g%>D7+EX9@s*751TVXw+t1y`^zJEM(V)?&Hq07gpwd;z@> z=W3OT#ZoGl&ZiHH;Hhf%y5$@Egxp7krPPoI*7|Y)yd8yd9&@TCtJ_m5m+Fxrf1f&e zQAMZe&1zMF|nWaWNFRAFR)!7u0*oTYU*Xqk1$@tyKNzZWe=&cFAc zw+?_u;*I;=tB!U_mvsAdhc<|R6*nh?u6C<}v2e^3j0Z6GM>h?^_?mTRAo^qq>e@*L9fb_#lb&7g|`nPLuYZ;FLYFV1sIIf{gb(N#s`h$eK;==jq51 z+9F4Y3BRvAs_LSI-TOSE}mjkA!6bi5>|o%pjNij~zSd^oFqy~;*7(X0H3PD$pc*qJ4cX&_x6h;ld`7nH>;*v!JRM> z!ZIMNhtt~dXS1^Yvrg-i&_Cqap0g${J#&s8Gn>0%a0uxkb0n(XbU!l3U55Q%Wt?|Z z6VLzk5s)g~?NR=+Vg9u3PO+=dX-is1?2t}bDs13lXH@6c4uaHvor7ex_1Npq2J)I)kyXoVF!x~Qpwy;>x~dWDQ8$CKR=gsv8B2%%n>e_ez1%2y2Bq_LdbNb(nF?xXmggKW!(@g%RY!k zKf!hi>YkiCmOt3R1*2pS_mbKZP%Wu`nuyok2Kd^;3y0q^I*A%p<}BA@Zh4nA1+)s? zabU}tl!j|rtzMW&=F`(Zw=43+P*ghmS=$zf3_ukdUJ~CMjxTERB?hJ2wPJP2dco%g zi`U{m*t?dQ7_Tjt+SHN4D})IlpWbY-60I=D<~L zI{(4LsE<^6U+V&e>wAq6y6dgqf5uVvJU;Rj;FgQEYHPzbVJtrAN5;@)k*ZWO~z4V5_a zm8@?LN{XL0EPkHy-Q_UO(hE8Lcxp*naJ5AF*`L0UuAtw#EaY6i|13TS7>btuJQq=N z*76lpXm4MY1eYfhoBsGu*EfiP7qLBm>}hj{^8F$Hn)|NIelYO`CUQE-(;2(YiXZ8L zQiF@tx)Xa$(L;}u>xC7u?!!VAIy1oPrks0K%4pQsKvSv+b?R9R_}*gLi};$m~IL**pK104xlvmH^ zKPN~X`rC@JNbWBNwnjsCcNR-|#IUF}v#lQaRHm(M`!J36ftvt#SSP}4iE<3C2sO3e zj!`**bkH37jj=Vv|MGin%aF#F^AwzrRuRzvX^CD_1#Wl-aWrIO!E0i$MX#Bw{?>h$TX2IS z^A>hn_ye0nWtnFmwf~h+SV*O*XAG;IraDHyQKamOVDHjrvgu!kx*5Hp8sJrrx`S0r zPnNQxI9%>5&KPH|_I1(__x|&_%6HyaHuQk`Rh_K6NRi5WqVYiJ>44e!XtHvUDKl2_ zltoADP3YGk93=K+pi#|2r=h#)S>mPVcU)}4S~TjSAB-=Xor~-mn|cKr^7ZLtD5I=@ zn6}ytNb?HvEC3V5Ufme`*q3UQw%~|k%cq{1@p|Pkv-`R88)VK#QEjePfIGc&BRc*n z9UpghF{qQ&y`p}>tNw(2s!d`#O!+`y+I(DHQ393+DPzV%e(LgnluJUe?rr_>BY_+3 zrp8sG(MjXb^e8&vbpZDKGdBwEWi^TL`IO0ax!*p#`(dZD3gbr#?teGc4kx$PYDo<4 zL!~YvRp0znWl2CC`(0)Y46_~di3?nA{8(R`^cB9JR4bvfePTSm@DghHX#5+O5AlV4DA3agO zVN&6s#=o`Rse<)7dH+AKCmlJKwGSYECPUR-$%(l&#JeV)K2xqZ$oexFQKKw#MLay^ z!t>i=W=|DfXa!Ey>`)&I zjW#MDCp*S=@)>CEqc6T}KPS;)kXuP5K7p^#By~KbI@WL5m`9Q)518Ad!d#%ULT_%b z3N;1u+PpE}#)=pXTx+;b1!wo+S9E-Z`_{mV6_$6gi_6D)RF zI1r>^D%N+s>$jTgA@_SQz9sNjg7d=P$90O|mDwe2)_SJMvH!owa^bJ4MHXQUkg)%W zQw}ahS(>%L?EsnL7(8gwK+F(WDipczU$-mMcSU(^pwmu+Pfp%|()RN{uC+w5lq6Cv zqTu;AfkTXi=ls{W@Df_z6vN|4l^@phCoi3DUZQZ76%X8Yl(#2{5$F)TU`MllXWE59&P_!%KALUJ?ege~%)9Wh8{Bw0F3{LTY7d4X+y5-LjWa$k5rtQ0Tts?h=20Xg7YgeA#fzk-DPyVi1Gwqaq z9+}U=c|GJ#!%6OxA{)=g4<8>rro%*)eLI$Yc)&|jk^R%Q839Vzv`XTyT5lv?BE#_2 znZGbadjyq^$+k_oq92R`;Q4D@62IgRnFx!K7z2ossJuO{p)I+_6>l|5d1}5ZBU2Zx#gq)BZy{~MtGH*+@n9f}fQ&L@M=rp-#Dm~9rLf0Z z$At)*v(8RPNbY4_8{Lm;RrMb%=b}^9ha)(J3PL6QgBK9Z5vgxpj#561AAL9OKIlWY zhm=-fZ6Gk)EimoE1UUnDE1T%}F;U@#IK<0Y>H_C!uagJK>@%$gwMgNg2gYxXLODFB zQ<@lOiCO%x3s?Qn{HnrhAH%~2osdc<&kxSHeqMLKmxs0Ab^MZ<1V5)WoS)Y{yiJ~2 zkqe*h7N%oAH&2dGU7LPG-wuCFL?|em!Up#aJTo>mq-AR5;N?D4^fEJW_0*p`DVyMb zIEn2H8oLg*ybU)+9LnyN0~OOCDi%{J}tyjW7z9ldM!seU_y_wDdH20Ug!rL%M* zqoHW<`VaC6mRhBjd!QCI+6`~UsTRk7su>U3n=XpeT=hxAMBZ@c_6;$umDEp>29wOX zrQUJql*}`O8wV*Yt5&QxbO(BE_D4xSu59F0*AH9_6n9_)t1szaO9f}My}}lDt_xk+ zw|8eFC~8NA?&KXB>IaPE1jxO&RX|$CSiaYK$sW73wjpdo#L%n|X%V=1EyQStyFS^q zCzn7ncF!3?VC$DfH1Vn^Ij3un+ zvh3f{|0_yq6M2=5B^QN%6b_Y~o^(67qqT0=I~*$S-{${%?iC1|+M~$vD2Yv&=s*0* z3kjGmNA@Iwhhc2~njcT44aea01*%i@}#JK^QJ=soeVGn*&7&~Z1FoX^g3g@xCw zQ9j&4cd9NO-RN21JUf%mA)a;95Qn6yAr#X+4HR!;UrJ5}nzS3b4@ozhDCtjy1NiLs z^IYd>E)}%TB7@smOsIMGmryQ=8PD>wN&*i()0Tesh|JaLf>l)}#{k%hJ0Z{<{wZB) zM_c_w#v|?)I-=z7hEyz)DDs5I3c^r~p!!cpQJz`X)m2CxG<@2`Ctj0B z24W!Y1LXyV=&F4MD`})-faSRp$j3SbY|9BzPU|Vi2IRD0ZaV^Cc>2eOP^~stKTVk< z`japxwhbB3HcQOd(RE42pKXETJq2sCOC}1M9LAW~+y^gFJ@SiOOhLMDW-FQsvE#7C^w;!}4mI!UU3(O}id#EFx=k3FLZX(2EiZsO5Q2#db9 z-JBKFP74R6Qb|IMy}ppd=e2iGkLT?PgPkWbAm)bP*u@AiDsuq^l~){Ykw)>N9y2$ zqZU~NJ9HFxWcCC0dJ-z;T}>W8h|N35P?nqc)hXvJN6Z<)-b9lr0U3c^d>{pZ69aS1 z;_+~2;FgJz=HchEEE*v}DsZe%c1h#kTI+JElg14z3eS$Rai4XMSL2juY)JrK@stz- zM*M*zQl3*tNJtK9CFR%}ph=j0nW{{_*=j=Kl;tpi>=-XG|^Lu7Mm?%D>F1rDhzdkB`_Ubv`!6Fkh-8lovU)iTT9(8L z$+zdbVdm;sJ$x$%p4cb&N(GdHCVElYclsuvRejodPQPp$3iPai=qIz`0VK52L*qD+ zTcurZR>CGG)SN3zb|03FZOnHEhmFq(ZC2Mm?fAr zUe7}m!R{V$vzb3l)9v+aDp{6!=98(iiODM!Jv*o>n%K)26}(r>@ZTtKN+CBBcK)U) z*)kE~2hKg3h?RLJd~P{Cl71Lix<$D0JM4J{)Ry}|cgl?2COj<1UsLuZNMCj0Mj!Q* z5aVHR`24JSFrftjQ6wNN3HZ+jw6I6)AeM>$UzQalt)+h$|DJvi2|eE$AaYwJbq_sD z9x-Aki>bH8;F^r&+RiVwuFUt|L+Y%4KE|_3_&v3LIzyQ^lrR41jV%lg*d7yo^ftwp z-XK%%d18>ANBLq0V z8I2_PYJbQ+roLg}ZVv1q)PH-NK!o-MoCe|Ar$X5v>5+!?!dBqqz+Xv5&VCr2dlj}| znswm6t^1qTf93km4@C~kW3{~QpNRh3i3{K%m0^2l^PmHyjo0YP{$^F77wE7@`mo@w z&G}V_J?Jvi6zjjuw_Da9j|A;fKDf(-=LZ*Hpw{|pO>=I>9n0+z60Y>`L;M}{sogvf zpi8X6R1vx z(4>SC5a}hf&>?gPX(#IY`^Nj7@7(|HxZ~VC29TYx_F8MtIoF)eoa1rF_P1IiGe3R;X;_Te=s%b!tHo?I)E-RM zLx%Gs)9$>wrr#Z79m}f~^@>gQ8gDi?%W*n3>}j@h*RQ<%dg+jpi8pMPS@7!V&!1l& z-i&$tWNF?QJ{PN@-m5$by??+{+g880HjvkzkHo6LyveEETrQHF2z^pW8*C|qN`PT% z7D$DiupR$*Xuvek84A?ackweP}-=cqMr?eOTFxC^6!B}-KR$q%)8KVxRm)DsrH*70Y3@h-o`)IIX{`2?Exf!k3(h& z-FhYwpq1n~{S0{zw9l5r=4k!rVpOG#P3c7Y*w03I+4Dw zQ*M2)`!(xAQ6}*Y39y_cHRh9DJ-gat4l^?LL-|a04(j8{KlPMOR!V2=0ij5emDLdS zyX*ms9BjXs#%j~urpSk+30p7*Kqc>RPy^9Hj4;)ZBUZaidE02Qe@TPo2RzRpz0!(- zdBNVUi~|i9Yar}z8&Nrrs_T|vfi6?*cHT?(sL#pYn5pJddq7Ps;L$AT`}m+F?7i(` zNU8J+LgI6*!!)?!+&3wVi5hgL-f&nEajiN5ytUesg(Y0a@1{KgOG-C9Vsw&P6}Kdf z5_NulANi1ZL>=ASBBJg!ZigQp?%d^4cv>%(&L40OL8>Yir6y{RQ)a_HEF5!EROEpC z%Nn8(04?v~N(z1zLCV^>d$v73%lgXcwB^)OF5{H=Cq2~Vb=K|JuhrEctLUtHB>RsA zOCoC6iqQVRk`VX))K7LC+C)32LH7Flt6EDB&!6CI?z8u_H<9c1*M@EsBw8sbw*Khp zzBBr(9ri4kKxKo{9#r?{uzJ)eeU!I|bJjjs@@|SRNXOxH3_F zj2qrw{h8svy9fl{uqixzsShv?ww6dcwEpp0zwNX9e;0a7<1D(bUCBX;bhw1yMo`5U zJ5T}Sbrl`tC2pY2quyj}V`Wd(7a?@9VOGrc;st^3+9R;dj8M(CY8P4vy9`gBX`e-# zG+w)0(y4d;`m;{mJ#b5WNntl%K~$@#y8eSGfCt&YbShuLBy)G+wq00n;aX}IcJ%Sc zcBhL+ox|-{dOvf9Hx}$a5R?sk2m=A)RmP52eJkbHXlp7WbudJ!e-VQ~*x=X@_2Mbs)f<5&)a-j_hZY!=sCi0`(u$R*nhv9jVGq0|@nh68 zz+MfK`AG@u3vX?xIuE$fv2St?LI}%6w$*aC2rU>+P7^V`!W*S^Yaz>P@s_Z-MV-zG zo`dbusWj!|$kOwsx?&?K2 z@r`>MYz>j2VFvzSH5&IMMt%HW{>|np!Zj0OW2LC5INTIEx%ChpV)N9yn`Gn8=tU~P*Y9w3wKdJw= z`N-KX)RwjhoOqidopv&HXW_}n6y2;%`tGpvOCFsZs9_LD<8k)}?;iZ?79g=hd7>&j*}9X7J}+ zrR$24m-%yrU(`VWSOp`bz*LS~w{P>X^uz0!2H`d>*z*qH4k*=z^6tHO;<>Uw2X@YL z-!D0-ar=QNU6AcocuOrTc(y-_%D53M^@td$3+qeX^M`73;a(_Zk-}tk39WdxJP(a6 zhWcabp_LQlRMV&mxhE>9B zIkt!N%y;vbs;8WpiCwJ2uLbH}qVF<40_Ld(F?_~IOnYJG6Y`~t& zIQ77(&zpn6Jnn8+_vXS7-G9SV5zSK1604w`3n8T*mPDB8_&%)L)ZFeiG(II!b#+HI zeY#b~LHOFuuc&q6)BSNJW5hJriM*6=p+m%NmWP zI-6CtQpAt!crJozA=n^*U)NF1Dn?D&4r@Y?fyjS zDEHsa*Ddl;ie0D_;VR|!Bb6H9^{4}rEW?rib1Ea%I)JOQ?adjRx|sQ*XpW=P-tI-c zFGOI9um!=_$;MJFMfx;(ZQ7ZXKHGw+Rvm(Yz~x9;40-SU!LP9Sx&?=n^&vIzXYgBG zn>^?4C~w5QtV42EH*jqr>4pE!Qh$f-)l$DYZ`<$DI1-ckzoW7l%E1&e|LkL)~cb z?ui@*LBGScCL*&Wmd%JWuirPpx*cssEO|(l7N4J$sFQH20Xmn(PWTl_7Swc<7CIO| z>*9s2Y2=?g+8L)_nsUwjWYg^`png>CWgmUL6sG8G@+1|1+2*gv0-t;0`djAF!mk+9 zl%ianwC2NdlxXq!j>!^2EzqAf3N1blPTF6fjK*FF>j8=S*#89Qc7Zf3Qe zqa4MZVuZ;%_5RNQeiamf?}O{hm{{=W_R7$n`S;SFupo#5KLI!#{|9v1K&bsecAxX* zEJrc_UZH*PtdJFPq#Vyl99r3oSc>TnWHr4XWF>Nxdq)I}hf zws3e#u)-mf*~;|*tOD%FQfr|y-;nR^@BWyWS|S)do0ac0H>3V1o`SLZAB9bHGxYEY zy26NIS?S4fJ%66!(0bdE_}Y{I_RIEFv`6uHebrN|*ph|gw?}O|uaO2!2|Aw{>WLRYQ`>_BlT0U}_2Rplrt>R}${t123%AW5XXlhA^PXwO3==>TJR{oPS~ zO3l&?*A!CCb3blj&r#mCop+Uvn=i|MzqL*Elr-OJ%bQ@sj+kFnr+#Z90nZu_I~$SP zrF*vUpwHgdh=2;fdkf!Tm|}_i9nvULQvFfeB56{Bqo^s%WZ=Y*3B>jxybN7OrbXSuu)~FE%fiM4=IkeOLHtH3=_$4s<*x5(NB}EZ+`MbnP+am@r{!PPIN6eYEi_3*Ib02}SLcgbbTnH&w zx6^kl{pXK|Oi7|>^v^q%mOR|ZwUk*J2;u;pU8R(4#C(po?Id?aobR1_>~`HhV2>%9 ze;S>3a&^4IzUwKt2o=iKF*(12ZtSzq6WA|!KCR<5K)0445s^t{(?WM0j)Y#X~ zALoxnh1i8wZ=?KI>4fhrwgaIHv;f3J`aN}>$a+tUYd z1~z-^|2@hwNZfY?3ve$7fJZyw#46;BB-+~F!juEo$nv^r1HfQ0`co4r_giUEsn0D{ zE+x}hn99qGJbkkRXW+6w28-4)Heyb=vJO~_cNFXkXeXH%dMxx;m`t)M8m)v|*BqgJ|j=|uRlJidaVtf4} z>E%0{lV{z6&oKHSRep=7Bk?87()3W%bpnhkIW|M{6$G1ZZ=JP+Xjy!n67`N21^#Y0 zj-gH6{b@5jc3k(jer#Lthy5+D&9Ydg{+Y@-$G@IdC|r4m3#Rp_Stbk1 z@$!=O7RfR&Y%$C!#<8B#OHx{t)C=|?*9HjYJ+(7(ZgyeLyWbnISTw7Rw^orS7~JNR zxYtyg>6;_xyYkCZbCV19XYgB@$0&oSBT$6c*o&)}jQ1~P$Q4!CU=bTiIzHFHa?`!p z!ZnSwy;GJ~m&Q%CJt`MB@y8eGdt%~#G_Ohnr2}-Y7T0sWU#0$F{WG_Y#89CZifS7G zRJyX~dhLLGBK9%lJzKUT@94=@H1NvrbuVN{A8~AKv$~i?v~F`P$iv_f@r7G5t-1E6GqV>ha^p zq@`5BWt)|6Ey;LlCF=x`q+$ELQ|~sdVZz%+W+N=r-q!wOq1f5WfCk$_lw_ zS=jrtsd@HCOhpcsOD7h9QbT=YkuZ=Oii~E`eTOSgJNrR>GZ!nTV8iNdRka=Lz#>q^?xFMpO?>a=t-AV5Q_Mt z+gRmH!+YA?sy5e>%1Rf4cOS0Q1?V%HK<_dzdoOhNzY76#3n56P2@*!(iGUwSKz=!Y z(NW_9N8M@q6sRYKi*;784A5S$4A`q^Rko9SbZ;!MrnoA9#EoU@l^zzDVN-bK4hoQ* z6?skYNN+>dCG_v87RH4p2}wy32k;V$2MMw+Lxm6yv7z8PYeGiODx8oB)g9{Fk_``~Cp=^4!2)8^+JKk4Mkn;=n|z8jKnz7e}0Y`OuU zZYL*xcbx!**fqb*PsH+4*_&zFzjg1oRi$h;mqj(n*?yN`?MZk-N|#l)*?$jWo6Y1? z#Z@dCB`RoXhek(7n?zj}ZiK`3jeBzq?oM$hUhhVbG=p(fJE*>w(6epc+Ej;-{-L}_ zy;lVL*t;kFL=}h1^)dEmJ-QVu1Ha?Y`5whdRpg^z*}A$n{PKpUZfw&u>LG34;N}W* z>xy2<^x$R7|3UqBWI~B)8&R3>Mg(MK77TM--_I~VcU7J-NuYLkILH-V zve1!(UWG!7E{v6^EB`@U^Fh($P+WZ%S0@ywtzX=gPD)UgC-hX{@3%M4R$&`aBjK>* z9*PJB&PB1YnK_aa3~AtEUTKg^I)10OGd1!f9A)BN7;EojLLWbaD8pL@bcgSru?IL( zY=3>7@xztaWu_B;?F@R<)ND6^F^6k`Y6cP0Qn1 zgYMvj#G|poUDGFG`@zJej^zubOe8h7ty3Z>KTn(oO8w{Hck74Fwh!s#GFQF^4vkz@ zuFy5HfKk&M7BI02T$~rzR#si46o!sGuNl{Pbq{qxp_Uaqf8|4bF%Gq_#?wr|(J;Vw zM!KT5D|&0JN28{=&|{Etnrgd-*`j$%1-_*5P7{B(F;)3e<5WCA?8=pC@cX)F{VXTn zXJy?J-^%yU4Z@LW#+^r_~;Qs5A=iHjib$9#e58Yz=FOW zxZtE2=U2e;Nb!Aj>#-Qu6o=_-j@jAsMh;-^t2;up3FRi}y^E)hY+7U!CMZYe^ zB#EA)d<4F;9F5kr2zaH4njKCy=8}ZE8DDFz8$i9z0MxSQ02os5WqTP7MaD0QfX`bZiviszH+3M{RZlYeq zv+GI)R>41ijSr9SMwcu^cQ@ViFFG;dO@4+GD(VQjM$WP?Q10)DJHW|4nj zV!?xF7*@g9gZ0>Wpxn?2wGfaLa^#sGZlpp4Jich1gV+f4`DRBn6kbFlPeBB&Yzu2- z?A!MmXb#zdw;=N>Xu(_NcRZ4t-6Ybmk6NY*ccRtA;W|kjWR+G3?7zJE=v|W~fl#jx z4pw!v+rwPU3Y!V90<^ndrSA9VXL>KIcz_H8p7Co`CDdK^MXR z@_TvG4AfwIR*-L3x7h3G3`{| zuQ$jV$>LG6dx-DVPVZ*Efp?tW-{>yl^C&!_o(l|B#SB8N`f80{N|F!frRB;JCv?*qvgRiwKTgx#A=`|6P3o?&pAcYaA{ zwG15!r|Z51P}iJ%p0;^=SaEZLLT2;=n#eD!hFaUGr@?H>z0ED z`1aU>_0kV_7;eB@F8*`L;>61;gY+xO;$KZUquWF5N5ic%!({V6@1-~FU+i_@tpvnJ zOA`I{L2wOio1osUDm#fC)n*@DiS#hEw64lbx-!^vGTo4GYvbNM%h=cGHtvGc-oaGY z$Q2U8@EwTd*{U}KaQLx*+qk!C<*L&+V?n{^yGZ0V2{N^wz;^Y6xiat>Xeh!AV}Ck# zyQ0a{jWq&l-wWl*T30c^xAI!{i&o9^Q~jeAeX{b-H>g)JGY_f|t>8UYu4d-Xf%r+$ zSi`*)=6nw4)1d54B0!A%NRd`E?0T6&{MoZoQQ1F0uRH!UE9{ekc$NE4W}-&_>0hV8 zhZ#`z1m?Mh8RD;6wGfxQ_L+#rF9m1iDUvfbS{ z1)9LIK%M4b97bcn;TnuG8gaqNL(RoCN`i(se~p~-xZe{;t=SO_h3(t+{%U2-f=nF# zn%|0Eo$|+3-PS|v5G02()bl%s_pu~N2Z0hGcf%^r>2zd#Xb)_gO zCKV{M+^qPu$n?{7&<0tp%5JAQEr03$+G_}QQfY7`cWw>Mfwl67Icm0->Zf+Rt28+P z6#(Lcw)T8I?jL=@^~oEoS8pN|kK0Z2vp~;fjPLlEW-5xdeV6W9o~)@{b|a4rioJwD z`GK(4L!(pM5TzgW7Lm|$zn{k@eU2m=;Xzf>hyY1HzSCIKz9S0rj-w>9_(;xe9~Ym9 zE>E)FwE{k>uB-~KT*h!2ihLwTmp#l+1aM7YlLoHeb#WU-mVsY&ntUL065t3XUzCMf*_Tl+Lxtppb~tw4ROP-xVRX<(DXy+W0q+M1*-FRU8bXPw_o zsOwVcZwfh`%9rXJC4DZ^WnALpRM@vq{z;Y-y0Wt z?;iGnaS{+8V5i`;XOZ`9fCy$O!}Dy;6M*bE}k;O zVkfERGhi8VrN4SL+L}@{l?y*rKaO3e1|I7&tInwk{4^Td^4vZsskH7y%(}{kf#fKf z$;4!<-&xDVSAM{ej?Z^5zOtcHZBf%3_fkoWx4@6z(lnm*9q6^Dy05~W4dw$@_#gc` zWyi4LOlJu4bB$jprTf-FlKF0QT^4R&=I2y23BRao=xsmBMc#RS&yA0xOv=tPxtpHp zq^_iZL@CNfQw~CI$5uERqihR#mk<-%B_)c^zp91v?g+fU5wfe!ZQlQLco;h3MfG2M zr=DCJRC}LOjE9Ye5p=Ezqv5*sCG!KNrC;8nj&6H4l$tsVwZr@$!z8*)1}sO*ogG`N zw~tB6#}qn%M7>XkA5Y_p0B|9~6V7yeelo9!`_)Q1@D5bUd+K};2!gyX9NLgYX%H#B zA_{3K2G70;ETN4L1}#T5gmMHSAVuA=+kP@?mZSOV-aox8Aa|Z4)}pEaixQ?&=Jj>r zl2)0+GqRJHXAx>E%fr1^*8(1BY^F-R^~62QvV8vhcaaLqw}j@^@U+h(qC>oJkE*@! zB~RMS5?E%@0Omj?j1^Zkj-Symo$7Zk0x(`Sf(NK(r*6%Kx9td zHSV_hqxR1rMt^0GKW5zw-{b^gZDQ*f%V%jFaTy7$>p?fzk@w%M#~V%j$@g=LBu z&P7UjDcD{bG_;_VUST3eYc&&CnK^bnkB1p{UCYl+T{~GZsas~G%2@4-U7{@Csa%OS{5XAr z&lihu`*-m?8({k8{pMcWpu1kdXqlar#v^y=*@!*Ir@c!HW*>^vM~%i$m#YZ16_c%j z#V!N%5}2lrwd6xhOVfjCx0tH>+(``(Yhem^tGA3A(uo}-H z3*5ZD>Y(ZJ&3+rTZv~(FIl4MqE+l7lhdmtNlIZAK29b~efOjUpoDx|%$<7AKtRM!0 z!8?mX9zk})O5|^}U{FPnZ;yOS+qU6Rp~)!A!0a7LA7-6F>8>Vy@fM>tkDNFCtiq7( zl)AVBucryYwRh$0Qt8HoTU%lR0}X4I=rbVrFs_xTA7iu$;zE3j@l7QO^e!@>h~c!% zVv7$j*ubo?ye<8dxFEdddCC5Jur3epjzyfBA6L`bt4~0%X&-D*4D&p}e2gyhveMF@ zVSbG;wcm{stV(tBXxxEw7@er(y<$^csyrwTP3g#;Q(~+JH=pn zu<92P85i3$0TRgi75a`D`>1O1qW?@BU|mFMh&o{s7Y;D|R=05IC(r^{h*PwsWe%|q zbcTX)GtJVd^&KF7qhV@zyu2xpD=vYpDXqw*K~)}N@Ew~@Z|}Yy=Mk8$;Ym z?`F3RIbAT9L}_~iA(|A&3k3_jE_5k`&g9`Bm^aFa4)vJ*R!3AMqL595mKq03^VH_# zTvmEj^`1#+o_OqESq&{Oio@3cKu^B(q-@dsrDoB7pKM8Bv^4z)_=gH1^VOQ0{S$!s zpDk8eg9|KLmxY_*Sy_~sv@=J1`WjSMBg(s+4%BR5E7EInNH_leWMSD4R?h8%ke`zk z4vCUej5}7U6I|&MU@7BfNJ91Gl< zG4dW9vN@f52VY36@h#vCDfb**>)k6JnT_OslsO8nE3eXVR*DM)`F{)E>jtDJFV`ex z>Xo@(jF4Gf^gWdd@#_Epw}a3|2hxXc72+TrR)+;2PDzed9=5Z+aSzzdv+PNC-5Qdq z+ML8z7B_q!;uUn2x%d-x+7EQr!=!R9al>OiEMO&lK|HBwCSr>?7KmynA3Dk>$#~9f z#ew|<>VE~zKEfx(B^7N5+38X~^=9{&Avlr+1Ss2wYX@$5F*WHcg8P;(9c68+Lca@M zD&>)(p)*_bEeU%52vXA#jL;ql+j8`-regPssL>@VpX+Fq-a^-bw1YgukmXTFaGDyK z%xWaz@$}6};Xyc;dac7GKqba?E9@20JWqhUz@Y@{C3&@H>w+z&6i&S=Ha%EtK5p*a z3tX!mSMEB`!Dxl3D_m~LGwu#@{_z=+R;9D?ax;91`;RiINBU0tiIg9ew?B zDz12JHj-D)3mb`7wAaX1nij*4vMav=nNJr!8U1j9JA+1>a?<|*PwgoHi-SL|zhBrU zO{J}63k?>;Z|dSlW?PuMR+RQA%Q3pJquF$9(KUXLN#`?7$n97jp!(qB?a7kP)S<)a z=I=GzT#?jTs;$baDMA6mkD;fPGV9w)c@4Eyv)=1r1av7Y%=PX$IexPh#c})pI=9f zLs0pxoS4SOP3|xoy(R}i8nrgRM7u@?iB#SHC7%oI~!hwWjDmIe3Tl*S?Z72m!JR`s;gef3uyF_y9 z#rMO7Y@^A@%Q+o7+^|g@Fg8w(!SMs}7e6^fW=XMzN4&VZ6 zNN-=TSkm}RezaxQ+zZ_!*+6IrU~to`Vt@KMewH;oq>PByxJ zJGyiZ&*otnWBIwKU3=8t(*BsJ`yc4k5^vOanf<(2R36$iA%NNR)cFZ_3k-7J#=jSZ z=Y2B>M0MLc3tewIO{-tVYC@XCmy{~Q$O|9EhQeC-S=>(F@r%EwnQt28=)GNOT6ulw zd;XFV^}+5ktXR4wjJp1fwcC8}!N_A#rA!!=HT`V)NjzHKfiyc&^A0QU8uA_S#p9r| zSh;F@)Tn(3I&8IVIgU&p50SkzDpTY2b^(o&;^kHuHcDQtq%<8hUB@&XdiHpglG zQY;Uk_h4ULE!i$+xH&QsQ4=Cbqxt$vG|60H*Zf_T6BA3LY-1o)Ty#Edmq%6$hkJF( z{*{x*l@ODUh9D_o;U&kTowmv-TQ8hrk|?UeuWbOIayFTgpyu8aOLG(4ZgIoS@th*4 z8Vv$2RG#zka|z?_3sUL(1f)1z3=({>^oyLB%TxY)*LXomccV%oe_|7z*5kxwmUPmc z9tbbnfGZ60HF$dB@C~Y7D8l4tUn4(7yiUm^xNUdQ>;T=rVH6)yW|P<8nr6Q>*L}gP zyEjQXqjJ`(VHvFig&6kA8;7wNgF^Co%q)_=H=B?N53f3$Ij`dPqi$p}E4a@t^V3_| zT1Q7s$NmDoMfD2XrXAw2WL>FQv_~}}V>>&(Vw6o%&7Vo54g1dHELKD;_;b;wb&Z7hvP%itCKgp)6ctn2%CW>&^D{>f*x=B z*kiQJnn_hRF1k0?R_yBvesU4)ZGA9e8DQQt);QIA&Ooii^OKu%WW9O~;ecAcdW)bc zpW8sh;rC$&9%Wgn0_oo`7;hNNQF#WUXgUP6LDp;X z)&@d;r_t+QCS209EI(|mae)yOsWsKUvrSO2DpIa_0!7^Gfo(6QQ@5Fk@yB;Zja`PI z6LFYrS%URGrpd%lPt|uR?=489m|V^!NPSb@Sf1#}3Q^Dq-2G88=HxPDP%zK{RGKP; zmxXdJYyh#t!vUZBOnh0iym5kD*Oi`)u760|3WK^qp%B)>svj<&HXA1!8UR5>Ti$?% zz>#5Ej`PvqT8)lQtM#{A_>53<{xu@#2PVQugdvog++Y;+b$p`uDOTbBDu7Z6d^pf}CE-jGhl!V6EfA*`Ywrh;rv0kuNcAb1o zZCqYa(37d%R(;U9Hub^9Ttm*Cb+s&LSW)`nGOQd`j?M9f_|#@`Apm?$L1)|KYmTP6 z`3~##3O;-J1z7JlPl)8xbz8A!j;;76T&k`u^``0m>n~!$P>bQdhuL_o-3)~iG|#SP zo}Tn;eHtBxarJb^ID!B+E%E0lC52KDKbyU=ed_ncaaiF7GOc8u0iQ`a0IMCb60%OR zGrR}n1Wx;~5TacQf{5Z52@1C(`PZ(4A6eNNs&D&?fs>5c5g1vH}|b)D*um!@qA~~H z>l_#s1IiCnI<>|23p$IEkvpW5i?$VjEJFKQ>X}-iv=`$M6xTIQSFk_5fnKmxkZ-6k zDdLs2sotjSV8ge<_m z;xc}ji0OzJgj0#HIz29kp(=bL?y)3TcfFJAr;KYFg7!7^)GS6z)Xnhpv2K@G9-9Te8`sBcY_vs%r{NR-;%ITV8r;K4XWSzenlA_ z2UF4{357Z|a14Z@a~~{NKeL&vT*HsaH~dH!pWCfc2j2_c72|&NTu_}A)TVDu zz*1_1U|V=U^SQn0C3K7j$!1z!Rzv;+XSsI=7njBvSK6AwNC(?wnp70m7vn?f57fst zEeUhGTIym_z6;X6##F)XqWahs%lqPj&b(On$u4iDL7xeH{rIDDpZ{8JPpd5gJf2#p zXq<7jNZ@oVJkgVR_oo=Q3!Ct38imDTzT7lAmpOg?hT|FGHhA2k^}M5~W%0G8(ZiMY z(4w^IvB#KTX%*_+=x`N6VHWV{0Oi=qS_V*!0GT;UnDV0!d~ljCYXPeCP^oYM`uilt znXU7Jj?!zRso0vMMR(D4UJDBq8RA6B&q-4?Su9ET)}oAb{U=9rJa7X~wtVPDm|#`H zL8#dp3IyPJe4jhuH6VRMD{^yOL%933N3F%rTF|7`V9O@5G>BG%r*@(WO4?SNXeh>X z2hioz>SIPTZby|!SLYB5gql(ba;No6khx+Y$@*dX@maq+rt?c^+R>SKN$!Z-KA`)C zS#r-9?a#JVpvY=NG`EB4?SXx^7+r2C&9VrPwx~G>ekD1j%92s6reu^})%VV=yQyyj zkbXt_+*;KYSh>yu11wkchPm2aev5s}I$8@=tft4<4<~B*!$UG;%gS;;dRs1ij-6gW zU#r`BOjtPx^5e7sYfR@e-WO7uySew0H7+aJzLILUPVS9YoX-^`RuNIe_4b{RP0#iR zcz|%>_*0#TiD;UGtv_QjqQ3%kDOJ$y*`KG^yk(5FDNWoDeQ-?+ zfFR^H^1{KzOd$nVL|vexBN(i^J}~5uwK6Cm&7~SNkp2GYw0zKA!nhyFIaW zH#v@#kgmf`V?Djh2CzCcl)4urvm%GS((tjLK&YdV)yu0OIPT20e{E4uJrtbvt@MYB zkV_B<3?A-Z9`ff$@kF}*+bbeL8>no)c_m{f$e17hIAzXs~;+@lox`iu<+_=g1T+=L{PYfVX z=38%y<`N{Z5Fzo}^tlMgU2+xE^p*6{X?cgRlWA76^abh5tQr%mdDV=p>FD{$(qZj& z0Oq~)hci{H;(_{>DFsR=1!_Ll&pvfBgohEGoxV*Ko99d-DE`weU6mJ{M&ptrMl!=@ zxEG{`1Sr-4XWQCBy;+*QaDr~6XS0+q9P#cJgSFm+@WC;!z0c>Ya=5&{$lN81*6+Vy zyYP}P{AQHfSi}ZqqVi@JU&`LrPIi`kWnp^h8M=mP0$F?P-qHiCDo1s(MM}Unb_2HS z0g_}|QQ;;OJRE*8s=EK60kQ{4#!eQU4f}-LE~F2J{0i<}9#j)(>WAY}J(Z|Og~P+F zy0mPkG{Q1;KyO-wyNZ+H7hyE};Q2eAL;lzs0~Y7kwXf7CLrxkqgjXvNOEt!mEAaFd z0eB5)Ko76?iFUTbt)FuY(t83^pdGWeZ^{=ql}FZnB!h^ei`nk&`Nbb{9lIwzw_P3+ z_6X4641T&6ncuO-1VQ4)YM*FR1FEZ1%P@P6ZO}9z2@@NXp_x236tA9Dyta-8rW}l( z-s>H2)b@D}%9NGfx;>rRvjFV4L!%K0zW-3Gv;=l7YFa?I72(|ESs@I58Zkjc8{^VzqKgaQmJ#QDeU?)L#th?CzIgRqqgx42UtvL1bydn278 zxL!Ev6*BU`Ax6ofrWlV7Srw&4?T+8&0TWs!Hw;eoSXD*TQV7Knix-FE8BnB33{|K& zx1ji7yZ2n4jf~8puf*gk6 z_wh%rJo3O6tp{6k(6z))7=Ri!>PxY!Um(Jlx(7qFhkdX1^9tT$3_7`hP^R`({QMG$ z*jINQS^12=>mm(PKUqUdV;JRV?tKY;!crwXVQ&U8R`DaoZHtA)@bT4&ss3@u!NhBP z(?J`n(uIo?B}-6q(j^;4;mwelF=z!~XmoZj!KAXvby!rFnrSuYv%ZR*LeP2k z$4$5iNOJQO-Dyt$iK+l4mvI?GMhGRGJp#D*-r33B**a?<(% zEv>o*;=HCtIQ4tazauf+M(;KRw=F3W7J*06wzdgbG{*fOUTNlaTB!>O@E9w9_zFrq zNDF%nW48#{2_TnzsJF~h${{W3Vz`f|$KIy(LnG@l(IGOPeRjB{<7#W`V-Ya3;R0E^ z?vds08qbXcw4-D_+DN_?!-2#=%zXcECJv3bT5L(+;+RUyl&c3yOhO2~AG%bhWEFMK zPQqcLUZmw8w1jbt@Rul&ASM8=Eqw*?y9vi68^{?8M-9U9{DE12NebJo@-Hm{^d~D+ zA!!=W9+S8$f1f&M>o{NSm6VIli`0f+v`~rpujY>|2wVZW?vpjXS3LYPZEXE;JjCL? zy*;a`)V;Qoe+AIN(ZlG8n|Xpejv!@oEe4MTgJHoIVC)aWzXS^*LkZy)IGDJ*`$4s8 zC5g9yt$ht$?52SoABLa;AXXc(JRU&ZKMWnl0NdXLJ+skKRS05GQr1{FeiROL+gJ_q z_kmB?E%39@L>QhR#vKEwWqSh3H1g*87Hoa^cyy);8hn=ix3m~}jw1?D^?0uyemh^~ z|FBY3Y0Lm}37X60GPP8L4_v5#r!|EHF6MNcs^@OfZ%3F-D< z8Z4ubrd%n_5e#5Mx=gNb4UG@LY$VQ}{fFm$vNOsHM^H$RuzoWSj;J;8Rq z4;+{7Bz>E+sm*vK+sfxKoOMzBO6VkRwfr_{f8%GK>3poR@@+|*=_9a}&jY)oC48RD^S zxyo7XCPH&19n)%lprPA@l^VCZNv^68Up*u#nENx!knKC=?h+{>*f-^__EsLnK|E@NGug zsiFG&J@P{nflsURTT)mW^&IGZ^X1O;U8|pa^lFH^Gl!Pg-}m5+zZuA}6!ms^1^x4k zwOdC*Np-0#_EzpwlMR5DV;m99H7xwa6Qq2p0aaG()znzqf1FPzC-Y$1QX%;-*U!In zYq!Pv`S-<=&aA8kuR?Hgp1T@!eOD(&Jt#Y7`^)jFcXUX#Arsbj&uU9&jL15Jg7&XH zeQ__4;%xlSk`yE5OS!-CJ{X~RUH8G1IpfaBUVF4#TWYj(-6HU*-gl>aC+HME1`DV1 zJh28IKREN)CdvZ^SiO|3sDElJbXRo3a?}hq&%N7F>b1C+z021cG5q>6V5_KpbqQ_8 zgc{&Fa;rwQh0Nssi7GMjszWKmz z`z~wR;~O+CWNh2Wg*ueFhL=6GKv8&9F8xG$g0c+H+>3O8iy~Py=b>UD`FdaYz2B!6 zX%0<@eKy$MWE;1$m~Nny61Ko49p|0uwiV+keM*(J1&mrZGO0J1-A@l@i*V#NhxySC z-i-QA*q>*w$9}a!IOjqj6#}Sh*HCa~-T$y~?bM^QKxk>5a zG@IRiwP$AajiYde>pFm;VbuBn|1fQ8%r}$NElg1dg^%{JcZbf+D8luB1Bz)zaurm% zeyi`aLeZ(I%>G`{~KswUUmzw%c$f12YdeQIr@f210lEMb`<9C z;8)On@Mw>}9=hQ zHn}-DCkH>M1^hH&m6<>ku6+4p((d8148pRq{fMspr<>Egz4t9|T>l=+{et^+iAHrX@cvK5sXSs{DN%qV2< z9c5=Gy3b4R_vilJzvKA+j{E-e``>lQmDlU_d_K?faXuc8^L!PA+uGUDb8s`U#&&LW zA8yUc_?`XUxp3>&E%={1`Vu>z(}vx9prJ9CB4`$s7cO@WII-F5k3n|oy^(#~LKXc9 zQ@@F+g;vD=0e(lQ|Gh|-o-$8v&yRSsi6XXRjyntOngtKXAK{BFtZ4uI_9d)!K6R=) zk$Z7*(PWUAL2|6hfpH0XsNOw){`_!rTE4f!W^|-T@3Kw_UflG+K!As>owYR-2IAdK zE^BcK{I0SZ8Ts0`*pm8~7?y9CSWra7-ny7v@7PT*;pXD*p5^27h$8;=)kj3qN>Wl% zM~BS;7+tGQMpIcccTs~nPdcgCfktPoh=l-%__UQTv$a$0dxQBtyc z{8;uqJO}<(23lJ0J(w91_v%&A@b_rv<(DsM5<+#YZESWl(NaI!+%qtEW#JQuW~3ru z#rcp>6xNFDHMe{$EMZiEOt7peT|8d3%WLVUx=E$}nmX9dMml{hCARGMMCa>vf9?Nh z&otI5VH8D{wqSkuiBLy#OrLG?V?4wBqwu0%Rw-lGQgkN-pNfR|jo}AN!okH!hKKWR zoFtF8Pw)L68%UgAAS5K@BribTs(JG&K0e5qi<>)^UX!&{L*!GW7js}&h;9ioHkNrq zmRZDp%3p^C4T8*gmZ7M48pSDAW~!&BXNjRwQ$ozWD`n{tR#D|Rryt$%68yd93m2*{ z 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