From d2772c4153a5ca27b33df3e3d5f0aa4c804234a1 Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Wed, 22 Feb 2023 12:24:11 +0800 Subject: [PATCH] Re-org calling post instantiation functions (#1972) - Use execute_post_instantiate_functions to call start, _initialize, __post_instantiate, __wasm_call_ctors functions after instantiation - Always call start function for both main instance and sub instance - Only call _initialize and __post_instantiate for main instance - Only call ___wasm_call_ctors for main instance and when bulk memory is enabled and wasi import functions are not found - When hw bound check is enabled, use the existing exec_env_tls to call func for sub instance, and switch exec_env_tls's module inst to current module inst to avoid checking failure and using the wrong module inst --- core/iwasm/aot/aot_runtime.c | 217 ++++++++++++++---------- core/iwasm/interpreter/wasm_runtime.c | 235 ++++++++++++++------------ 2 files changed, 250 insertions(+), 202 deletions(-) diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index 6ab10490..5c56bb55 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -901,77 +901,149 @@ create_exports(AOTModuleInstance *module_inst, AOTModule *module, return create_export_funcs(module_inst, module, error_buf, error_buf_size); } -#if WASM_ENABLE_LIBC_WASI != 0 -static bool -execute_initialize_function(AOTModuleInstance *module_inst) +static AOTFunctionInstance * +lookup_post_instantiate_func(AOTModuleInstance *module_inst, + const char *func_name) { - AOTFunctionInstance *initialize = - aot_lookup_function(module_inst, "_initialize", NULL); + AOTFunctionInstance *func; + AOTFuncType *func_type; - return !initialize - || aot_create_exec_env_and_call_function(module_inst, initialize, 0, - NULL); -} -#endif - -static bool -execute_post_inst_function(AOTModuleInstance *module_inst) -{ - AOTFunctionInstance *post_inst_func = - aot_lookup_function(module_inst, "__post_instantiate", "()"); - - if (!post_inst_func) + if (!(func = aot_lookup_function(module_inst, func_name, NULL))) /* Not found */ - return true; + return NULL; - return aot_create_exec_env_and_call_function(module_inst, post_inst_func, 0, - NULL); + func_type = func->u.func.func_type; + if (!(func_type->param_count == 0 && func_type->result_count == 0)) + /* Not a valid function type, ignore it */ + return NULL; + + return func; } static bool -execute_start_function(AOTModuleInstance *module_inst) +execute_post_instantiate_functions(AOTModuleInstance *module_inst, + bool is_sub_inst) { AOTModule *module = (AOTModule *)module_inst->module; - WASMExecEnv *exec_env; - typedef void (*F)(WASMExecEnv *); - union { - F f; - void *v; - } u; + AOTFunctionInstance *initialize_func = NULL; + AOTFunctionInstance *post_inst_func = NULL; + AOTFunctionInstance *call_ctors_func = NULL; +#ifdef OS_ENABLE_HW_BOUND_CHECK + WASMModuleInstanceCommon *module_inst_main = NULL; + WASMExecEnv *exec_env_tls = NULL; +#endif + WASMExecEnv *exec_env = NULL; + bool ret = false; - if (!module->start_function) +#if WASM_ENABLE_LIBC_WASI != 0 + /* + * WASI reactor instances may assume that _initialize will be called by + * the environment at most once, and that none of their other exports + * are accessed before that call. + */ + if (!is_sub_inst && module->import_wasi_api) { + initialize_func = + lookup_post_instantiate_func(module_inst, "_initialize"); + } +#endif + + /* Execute possible "__post_instantiate" function if wasm app is + compiled by emsdk's early version */ + if (!is_sub_inst) { + post_inst_func = + lookup_post_instantiate_func(module_inst, "__post_instantiate"); + } + +#if WASM_ENABLE_BULK_MEMORY != 0 + /* Only execute the memory init function for main instance since + the data segments will be dropped once initialized */ + if (!is_sub_inst +#if WASM_ENABLE_LIBC_WASI != 0 + && !module->import_wasi_api +#endif + ) { + call_ctors_func = + lookup_post_instantiate_func(module_inst, "__wasm_call_ctors"); + } +#endif + + if (!module->start_function && !initialize_func && !post_inst_func + && !call_ctors_func) { + /* No post instantiation functions to call */ return true; + } - if (!(exec_env = - wasm_exec_env_create((WASMModuleInstanceCommon *)module_inst, - module_inst->default_wasm_stack_size))) { +#ifdef OS_ENABLE_HW_BOUND_CHECK + if (is_sub_inst) { + exec_env = exec_env_tls = wasm_runtime_get_exec_env_tls(); + if (exec_env_tls) { + /* Temporarily replace exec_env_tls's module inst to current + module inst to avoid checking failure when calling the + wasm functions, and ensure that the exec_env's module inst + is the correct one. */ + module_inst_main = exec_env_tls->module_inst; + exec_env_tls->module_inst = (WASMModuleInstanceCommon *)module_inst; + } + } +#endif + if (!exec_env + && !(exec_env = + wasm_exec_env_create((WASMModuleInstanceCommon *)module_inst, + module_inst->default_wasm_stack_size))) { aot_set_exception(module_inst, "allocate memory failed"); return false; } - u.v = module->start_function; - u.f(exec_env); + /* Execute start function for both main insance and sub instance */ + if (module->start_function) { + AOTFunctionInstance start_func = { 0 }; + uint32 func_type_idx; + start_func.func_name = ""; + start_func.func_index = module->start_func_index; + start_func.is_import_func = false; + func_type_idx = module->func_type_indexes[module->start_func_index + - module->import_func_count]; + start_func.u.func.func_type = module->func_types[func_type_idx]; + start_func.u.func.func_ptr = module->start_function; + if (!aot_call_function(exec_env, &start_func, 0, NULL)) { + goto fail; + } + } + + if (initialize_func + && !aot_call_function(exec_env, initialize_func, 0, NULL)) { + goto fail; + } + + if (post_inst_func + && !aot_call_function(exec_env, post_inst_func, 0, NULL)) { + goto fail; + } + + if (call_ctors_func + && !aot_call_function(exec_env, call_ctors_func, 0, NULL)) { + goto fail; + } + + ret = true; + +fail: +#ifdef OS_ENABLE_HW_BOUND_CHECK + if (is_sub_inst && exec_env_tls) { + bh_assert(exec_env == exec_env_tls); + /* Restore the exec_env_tls's module inst */ + exec_env_tls->module_inst = module_inst_main; + } + else + wasm_exec_env_destroy(exec_env); +#else wasm_exec_env_destroy(exec_env); - return !aot_get_exception(module_inst); -} - -#if WASM_ENABLE_BULK_MEMORY != 0 -static bool -execute_memory_init_function(AOTModuleInstance *module_inst) -{ - AOTFunctionInstance *memory_init_func = - aot_lookup_function(module_inst, "__wasm_call_ctors", "()"); - - if (!memory_init_func) - /* Not found */ - return true; - - return aot_create_exec_env_and_call_function(module_inst, memory_init_func, - 0, NULL); -} #endif + return ret; +} + static bool check_linked_symbol(AOTModule *module, char *error_buf, uint32 error_buf_size) { @@ -1134,48 +1206,11 @@ aot_instantiate(AOTModule *module, bool is_sub_inst, uint32 stack_size, } #endif - if (!is_sub_inst) { - if ( -#if WASM_ENABLE_LIBC_WASI != 0 - /* - * reactor instances may assume that _initialize will be called by - * the environment at most once, and that none of their other - * exports are accessed before that call. - * - * let the loader decide how to act if there is no _initialize - * in a reactor - */ - !execute_initialize_function(module_inst) || -#endif - /* Execute __post_instantiate function */ - !execute_post_inst_function(module_inst) - /* Execute the function in "start" section */ - || !execute_start_function(module_inst)) { - set_error_buf(error_buf, error_buf_size, - module_inst->cur_exception); - goto fail; - } + if (!execute_post_instantiate_functions(module_inst, is_sub_inst)) { + set_error_buf(error_buf, error_buf_size, module_inst->cur_exception); + goto fail; } -#if WASM_ENABLE_BULK_MEMORY != 0 -#if WASM_ENABLE_LIBC_WASI != 0 - if (!module->import_wasi_api) { -#endif - /* Only execute the memory init function for main instance because - the data segments will be dropped once initialized. - */ - if (!is_sub_inst) { - if (!execute_memory_init_function(module_inst)) { - set_error_buf(error_buf, error_buf_size, - module_inst->cur_exception); - goto fail; - } - } -#if WASM_ENABLE_LIBC_WASI != 0 - } -#endif -#endif - #if WASM_ENABLE_MEMORY_TRACING != 0 wasm_runtime_dump_module_inst_mem_consumption( (WASMModuleInstanceCommon *)module_inst); diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index 9f28c836..28de0017 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -982,88 +982,138 @@ export_globals_instantiate(const WASMModule *module, } #endif -#if WASM_ENABLE_LIBC_WASI != 0 -static bool -execute_initialize_function(WASMModuleInstance *module_inst) +static WASMFunctionInstance * +lookup_post_instantiate_func(WASMModuleInstance *module_inst, + const char *func_name) { - WASMFunctionInstance *initialize = - wasm_lookup_function(module_inst, "_initialize", NULL); - return !initialize - || wasm_create_exec_env_and_call_function(module_inst, initialize, 0, - NULL); + WASMFunctionInstance *func; + WASMType *func_type; + + if (!(func = wasm_lookup_function(module_inst, func_name, NULL))) + /* Not found */ + return NULL; + + func_type = func->u.func->func_type; + if (!(func_type->param_count == 0 && func_type->result_count == 0)) + /* Not a valid function type, ignore it */ + return NULL; + + return func; } + +static bool +execute_post_instantiate_functions(WASMModuleInstance *module_inst, + bool is_sub_inst) +{ + WASMFunctionInstance *start_func = module_inst->e->start_function; + WASMFunctionInstance *initialize_func = NULL; + WASMFunctionInstance *post_inst_func = NULL; + WASMFunctionInstance *call_ctors_func = NULL; +#if WASM_ENABLE_LIBC_WASI != 0 + WASMModule *module = module_inst->module; +#endif +#ifdef OS_ENABLE_HW_BOUND_CHECK + WASMModuleInstanceCommon *module_inst_main = NULL; + WASMExecEnv *exec_env_tls = NULL; +#endif + WASMExecEnv *exec_env = NULL; + bool ret = false; + +#if WASM_ENABLE_LIBC_WASI != 0 + /* + * WASI reactor instances may assume that _initialize will be called by + * the environment at most once, and that none of their other exports + * are accessed before that call. + */ + if (!is_sub_inst && module->import_wasi_api) { + initialize_func = + lookup_post_instantiate_func(module_inst, "_initialize"); + } #endif -static bool -execute_post_inst_function(WASMModuleInstance *module_inst) -{ - WASMFunctionInstance *post_inst_func = NULL; - WASMType *post_inst_func_type; - uint32 i; - - for (i = 0; i < module_inst->export_func_count; i++) - if (!strcmp(module_inst->export_functions[i].name, - "__post_instantiate")) { - post_inst_func = module_inst->export_functions[i].function; - break; - } - - if (!post_inst_func) - /* Not found */ - return true; - - post_inst_func_type = post_inst_func->u.func->func_type; - if (post_inst_func_type->param_count != 0 - || post_inst_func_type->result_count != 0) - /* Not a valid function type, ignore it */ - return true; - - return wasm_create_exec_env_and_call_function(module_inst, post_inst_func, - 0, NULL); -} + /* Execute possible "__post_instantiate" function if wasm app is + compiled by emsdk's early version */ + if (!is_sub_inst) { + post_inst_func = + lookup_post_instantiate_func(module_inst, "__post_instantiate"); + } #if WASM_ENABLE_BULK_MEMORY != 0 -static bool -execute_memory_init_function(WASMModuleInstance *module_inst) -{ - WASMFunctionInstance *memory_init_func = NULL; - WASMType *memory_init_func_type; - uint32 i; - - for (i = 0; i < module_inst->export_func_count; i++) - if (!strcmp(module_inst->export_functions[i].name, - "__wasm_call_ctors")) { - memory_init_func = module_inst->export_functions[i].function; - break; - } - - if (!memory_init_func) - /* Not found */ - return true; - - memory_init_func_type = memory_init_func->u.func->func_type; - if (memory_init_func_type->param_count != 0 - || memory_init_func_type->result_count != 0) - /* Not a valid function type, ignore it */ - return true; - - return wasm_create_exec_env_and_call_function(module_inst, memory_init_func, - 0, NULL); -} + /* Only execute the memory init function for main instance since + the data segments will be dropped once initialized */ + if (!is_sub_inst +#if WASM_ENABLE_LIBC_WASI != 0 + && !module->import_wasi_api +#endif + ) { + call_ctors_func = + lookup_post_instantiate_func(module_inst, "__wasm_call_ctors"); + } #endif -static bool -execute_start_function(WASMModuleInstance *module_inst) -{ - WASMFunctionInstance *func = module_inst->e->start_function; - - if (!func) + if (!start_func && !initialize_func && !post_inst_func + && !call_ctors_func) { + /* No post instantiation functions to call */ return true; + } - bh_assert(!func->is_import_func && func->param_cell_num == 0 - && func->ret_cell_num == 0); +#ifdef OS_ENABLE_HW_BOUND_CHECK + if (is_sub_inst) { + exec_env = exec_env_tls = wasm_runtime_get_exec_env_tls(); + if (exec_env_tls) { + /* Temporarily replace exec_env_tls's module inst to current + module inst to avoid checking failure when calling the + wasm functions, and ensure that the exec_env's module inst + is the correct one. */ + module_inst_main = exec_env_tls->module_inst; + exec_env_tls->module_inst = (WASMModuleInstanceCommon *)module_inst; + } + } +#endif + if (!exec_env + && !(exec_env = + wasm_exec_env_create((WASMModuleInstanceCommon *)module_inst, + module_inst->default_wasm_stack_size))) { + wasm_set_exception(module_inst, "allocate memory failed"); + return false; + } - return wasm_create_exec_env_and_call_function(module_inst, func, 0, NULL); + /* Execute start function for both main insance and sub instance */ + if (start_func && !wasm_call_function(exec_env, start_func, 0, NULL)) { + goto fail; + } + + if (initialize_func + && !wasm_call_function(exec_env, initialize_func, 0, NULL)) { + goto fail; + } + + if (post_inst_func + && !wasm_call_function(exec_env, post_inst_func, 0, NULL)) { + goto fail; + } + + if (call_ctors_func + && !wasm_call_function(exec_env, call_ctors_func, 0, NULL)) { + goto fail; + } + + ret = true; + +fail: +#ifdef OS_ENABLE_HW_BOUND_CHECK + if (is_sub_inst && exec_env_tls) { + bh_assert(exec_env == exec_env_tls); + /* Restore the exec_env_tls's module inst */ + exec_env_tls->module_inst = module_inst_main; + } + else + wasm_exec_env_destroy(exec_env); +#else + wasm_exec_env_destroy(exec_env); +#endif + + return ret; } static bool @@ -1999,48 +2049,11 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, uint32 stack_size, &module_inst->e->functions[module->start_function]; } - if (!is_sub_inst) { - if ( -#if WASM_ENABLE_LIBC_WASI != 0 - /* - * reactor instances may assume that _initialize will be called by - * the environment at most once, and that none of their other - * exports are accessed before that call. - * - * let the loader decide how to act if there is no _initialize - * in a reactor - */ - !execute_initialize_function(module_inst) || -#endif - /* Execute __post_instantiate function */ - !execute_post_inst_function(module_inst) - /* Execute the function in "start" section */ - || !execute_start_function(module_inst)) { - set_error_buf(error_buf, error_buf_size, - module_inst->cur_exception); - goto fail; - } + if (!execute_post_instantiate_functions(module_inst, is_sub_inst)) { + set_error_buf(error_buf, error_buf_size, module_inst->cur_exception); + goto fail; } -#if WASM_ENABLE_BULK_MEMORY != 0 -#if WASM_ENABLE_LIBC_WASI != 0 - if (!module->import_wasi_api) { -#endif - /* Only execute the memory init function for main instance because - the data segments will be dropped once initialized. - */ - if (!is_sub_inst) { - if (!execute_memory_init_function(module_inst)) { - set_error_buf(error_buf, error_buf_size, - module_inst->cur_exception); - goto fail; - } - } -#if WASM_ENABLE_LIBC_WASI != 0 - } -#endif -#endif - #if WASM_ENABLE_MEMORY_TRACING != 0 wasm_runtime_dump_module_inst_mem_consumption( (WASMModuleInstanceCommon *)module_inst);