|
|
@@ -0,0 +1,2836 @@
|
|
|
+#include "bh_common.h"
|
|
|
+#include "bh_assert.h"
|
|
|
+#include "bh_log.h"
|
|
|
+#include "wasm_multimodules_program.h"
|
|
|
+#if WASM_ENABLE_INTERP != 0
|
|
|
+#include "../interpreter/wasm_runtime.h"
|
|
|
+#endif
|
|
|
+#if WASM_ENABLE_AOT != 0
|
|
|
+#include "../aot/aot_runtime.h"
|
|
|
+#endif
|
|
|
+
|
|
|
+#define RUNTIME_CONST_STR_POOL_INIT_SIZE 128
|
|
|
+#define RUNTIME_NAME_MODULE_MAP_INIT_SIZE 32
|
|
|
+#define PROGRAM_NAME_MODULE_INST_INIT_SIZE 16
|
|
|
+#define PROGRAM_INST_IDX_VECTOR_INIT_SIZE 64
|
|
|
+#define PROGRAM_INST_ID_HMAP_INIT_SIZE 32
|
|
|
+#define PROGRAM_INST_ID_TOP_BOUNARY MAX_INST_ID
|
|
|
+
|
|
|
+static WASMRuntime * g_runtime = NULL;
|
|
|
+
|
|
|
+inline static uint32
|
|
|
+inst_id_hash(void * node)
|
|
|
+{
|
|
|
+ uint32 h = ((uintptr_t)node) & (PROGRAM_INST_ID_HMAP_INIT_SIZE - 1);
|
|
|
+
|
|
|
+ return h;
|
|
|
+}
|
|
|
+
|
|
|
+inline static bool
|
|
|
+inst_id_equal(void * node1, void * node2)
|
|
|
+{
|
|
|
+ return ((uintptr_t)node1 == (uintptr_t)node2);
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+set_error_buf(char *error_buf, uint32 error_buf_size, const char *string)
|
|
|
+{
|
|
|
+ if (error_buf != NULL)
|
|
|
+ snprintf(error_buf, error_buf_size, "%s", string);
|
|
|
+}
|
|
|
+
|
|
|
+#if WASM_ENABLE_DYNAMIC_LINKING != 0
|
|
|
+static void
|
|
|
+set_error_buf_v(char *error_buf, uint32 error_buf_size,
|
|
|
+ const char *format, ...)
|
|
|
+{
|
|
|
+ va_list args;
|
|
|
+ char buf[128];
|
|
|
+
|
|
|
+ if (error_buf != NULL) {
|
|
|
+ va_start(args, format);
|
|
|
+ vsnprintf(buf, sizeof(buf), format, args);
|
|
|
+ va_end(args);
|
|
|
+ snprintf(error_buf, error_buf_size,
|
|
|
+ "WASM module instantiate failed: %s", buf);
|
|
|
+ }
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
+static void *
|
|
|
+runtime_malloc(uint64 size, char *error_buf, uint32 error_buf_size)
|
|
|
+{
|
|
|
+ void *mem;
|
|
|
+
|
|
|
+ if (size >= UINT32_MAX
|
|
|
+ || !(mem = wasm_runtime_malloc((uint32)size))) {
|
|
|
+ set_error_buf(error_buf, error_buf_size,
|
|
|
+ "allocate memory failed");
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ memset(mem, 0, (uint32)size);
|
|
|
+ return mem;
|
|
|
+}
|
|
|
+
|
|
|
+inline static WASMModuleInstanceCommon *
|
|
|
+dylib_entries_map_find(const ConstStrDescription * key, HashMap *map)
|
|
|
+{
|
|
|
+ return bh_hash_map_find(map, (void*)key);
|
|
|
+}
|
|
|
+
|
|
|
+inline static bool
|
|
|
+dylib_entries_map_insert(const ConstStrDescription * key,
|
|
|
+ const WASMModuleInstanceCommon * module_inst,
|
|
|
+ HashMap *map)
|
|
|
+{
|
|
|
+ //char *value;
|
|
|
+ //ConstStrDescription * key = NULL;
|
|
|
+
|
|
|
+ //if ((bh_hash_map_find(map, (void*)tmp_key))) {
|
|
|
+ // return true;
|
|
|
+ //}
|
|
|
+
|
|
|
+ //if (!(key = runtime_malloc(sizeof(ConstStrDescription),
|
|
|
+ // NULL, 0))) {
|
|
|
+ // return false;
|
|
|
+ //}
|
|
|
+
|
|
|
+ //bh_memcpy_s(key, sizeof(ConstStrDescription), tmp_key, sizeof(ConstStrDescription));
|
|
|
+
|
|
|
+ if (!bh_hash_map_insert_with_dup(map, (void*)key, (void*)module_inst)) {
|
|
|
+ // wasm_runtime_free(key);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+void
|
|
|
+wasm_runtime_set_module_reader(const module_reader reader_cb,
|
|
|
+ const module_destroyer destroyer_cb)
|
|
|
+{
|
|
|
+ g_runtime->reader = (void*)reader_cb;
|
|
|
+ g_runtime->destroyer = (void*)destroyer_cb;
|
|
|
+}
|
|
|
+
|
|
|
+module_reader
|
|
|
+wasm_runtime_get_module_reader()
|
|
|
+{
|
|
|
+ return (module_reader)g_runtime->reader;
|
|
|
+}
|
|
|
+
|
|
|
+module_destroyer
|
|
|
+wasm_runtime_get_module_destroyer()
|
|
|
+{
|
|
|
+ return (module_destroyer)g_runtime->destroyer;
|
|
|
+}
|
|
|
+
|
|
|
+bool
|
|
|
+init_const_string_index_array(WASMRuntime * runtime)
|
|
|
+{
|
|
|
+ ConstStrDescription * key = NULL;
|
|
|
+ const char * c_str = NULL;
|
|
|
+ uint32 index_array_size = WAMR_CSP_SYMBOLS_end;
|
|
|
+ uint32 i = 0;
|
|
|
+
|
|
|
+ runtime->global_const_str_index_array =
|
|
|
+ wasm_runtime_malloc(sizeof(ConstStrDescription) * index_array_size);
|
|
|
+ if (!runtime->global_const_str_index_array) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ memset(runtime->global_const_str_index_array, 0, sizeof(ConstStrDescription) * index_array_size);
|
|
|
+
|
|
|
+ c_str = wasm_init_symbols;
|
|
|
+ for (i = 0; i < WAMR_CSP_SYMBOLS_end; i ++) {
|
|
|
+ key = &runtime->global_const_str_index_array[i];
|
|
|
+
|
|
|
+ key->len = strlen(c_str);
|
|
|
+ key->str = c_str;
|
|
|
+ key->hash = 0;
|
|
|
+ key->is_sys_symbol = true;
|
|
|
+
|
|
|
+ if (!bh_hash_map_insert_with_dup(runtime->global_const_str_pool, key, (void*)key))
|
|
|
+ return false;
|
|
|
+
|
|
|
+ c_str += (strlen(c_str) + 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ runtime->csp_free_index = i;
|
|
|
+ runtime->csp_strings_count = i;
|
|
|
+ runtime->csp_size = index_array_size;
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+bool
|
|
|
+wasm_runtime_is_system_symbol(WASMRuntime * runtime, const ConstStrDescription * key)
|
|
|
+{
|
|
|
+ if (key >= &runtime->global_const_str_index_array[0] &&
|
|
|
+ key <= &runtime->global_const_str_index_array[WAMR_CSP_SYMBOLS_end - 1])
|
|
|
+ return true;
|
|
|
+
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+bool
|
|
|
+wasm_runtime_is_memop_symbol(WASMRuntime * runtime, const ConstStrDescription * key)
|
|
|
+{
|
|
|
+ if (key == CONST_STR_POOL_DESC(runtime, WAMR_CSP_malloc) ||
|
|
|
+ key == CONST_STR_POOL_DESC(runtime, WAMR_CSP_free) ||
|
|
|
+ key == CONST_STR_POOL_DESC(runtime, WAMR_CSP_realloc))
|
|
|
+ return true;
|
|
|
+
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+uint32
|
|
|
+wasm_runtime_get_syssymbol_id(WASMRuntime * runtime, const ConstStrDescription * key)
|
|
|
+{
|
|
|
+ return (uint32)(key - runtime->global_const_str_index_array);
|
|
|
+}
|
|
|
+
|
|
|
+WASMModuleCommon *
|
|
|
+wasm_runtime_get_module_by_name(WASMRuntime * runtime, const ConstStrDescription * module_name)
|
|
|
+{
|
|
|
+ WASMModuleCommon * module = NULL;
|
|
|
+ module = bh_hash_map_find(runtime->all_loaded_modules, (void*)module_name);
|
|
|
+ return module;
|
|
|
+}
|
|
|
+
|
|
|
+bool
|
|
|
+wasm_runtime_const_str_pool_init(WASMRuntime * runtime)
|
|
|
+{
|
|
|
+ if (!runtime)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ runtime->global_const_str_pool =
|
|
|
+ bh_hash_map_create(RUNTIME_CONST_STR_POOL_INIT_SIZE,
|
|
|
+ false,
|
|
|
+ (HashFunc)const_str_hash,
|
|
|
+ (KeyEqualFunc)const_str_equal,
|
|
|
+ (ValueDestroyFunc)const_str_destroy_key,
|
|
|
+ NULL);
|
|
|
+
|
|
|
+ if (!runtime->global_const_str_pool)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ if (!init_const_string_index_array(runtime)) {
|
|
|
+ bh_hash_map_destroy(runtime->global_const_str_pool);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+void
|
|
|
+wasm_runtime_const_str_pool_destroy(WASMRuntime * runtime)
|
|
|
+{
|
|
|
+ if (!runtime)
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (runtime->global_const_str_pool)
|
|
|
+ bh_hash_map_destroy(runtime->global_const_str_pool);
|
|
|
+
|
|
|
+ if (runtime->global_const_str_index_array)
|
|
|
+ wasm_runtime_free(runtime->global_const_str_index_array);
|
|
|
+
|
|
|
+ runtime->global_const_str_pool = NULL;
|
|
|
+ runtime->global_const_str_index_array = NULL;
|
|
|
+ runtime->csp_size = 0;
|
|
|
+ runtime->csp_free_index = 0;
|
|
|
+ runtime->csp_strings_count = 0;
|
|
|
+}
|
|
|
+
|
|
|
+uint32
|
|
|
+records_const_string_index(WASMRuntime * runtime,
|
|
|
+ const ConstStrDescription * csp_desc)
|
|
|
+{
|
|
|
+#if 0
|
|
|
+ uint32 ret_index = 0;
|
|
|
+ uint32 new_size = 0;
|
|
|
+
|
|
|
+ if (runtime->csp_strings_count >= runtime->csp_size) {
|
|
|
+ new_size = (runtime->csp_size * 3) / 2;
|
|
|
+ runtime->global_const_str_index_array =
|
|
|
+ wasm_runtime_realloc(runtime->global_const_str_index_array,
|
|
|
+ sizeof(ConstStrDescription*) * new_size);
|
|
|
+
|
|
|
+ if (!runtime->global_const_str_index_array)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ runtime->csp_size = new_size;
|
|
|
+ }
|
|
|
+
|
|
|
+ bh_assert(runtime->csp_strings_count < runtime->csp_size);
|
|
|
+
|
|
|
+ ret_index = runtime->csp_free_index;
|
|
|
+ runtime->global_const_str_index_array[ret_index] = (ConstStrDescription *)csp_desc;
|
|
|
+ runtime->csp_strings_count ++;
|
|
|
+ runtime->csp_free_index ++ ;
|
|
|
+
|
|
|
+ return ret_index;
|
|
|
+#endif
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static bool
|
|
|
+check_utf8_str(const uint8* str, uint32 len)
|
|
|
+{
|
|
|
+ /* The valid ranges are taken from page 125, below link
|
|
|
+ https://www.unicode.org/versions/Unicode9.0.0/ch03.pdf */
|
|
|
+ const uint8 *p = str, *p_end = str + len;
|
|
|
+ uint8 chr;
|
|
|
+
|
|
|
+ while (p < p_end) {
|
|
|
+ chr = *p;
|
|
|
+ if (chr < 0x80) {
|
|
|
+ p++;
|
|
|
+ }
|
|
|
+ else if (chr >= 0xC2 && chr <= 0xDF && p + 1 < p_end) {
|
|
|
+ if (p[1] < 0x80 || p[1] > 0xBF) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ p += 2;
|
|
|
+ }
|
|
|
+ else if (chr >= 0xE0 && chr <= 0xEF && p + 2 < p_end) {
|
|
|
+ if (chr == 0xE0) {
|
|
|
+ if (p[1] < 0xA0 || p[1] > 0xBF
|
|
|
+ || p[2] < 0x80 || p[2] > 0xBF) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else if (chr == 0xED) {
|
|
|
+ if (p[1] < 0x80 || p[1] > 0x9F
|
|
|
+ || p[2] < 0x80 || p[2] > 0xBF) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else if (chr >= 0xE1 && chr <= 0xEF) {
|
|
|
+ if (p[1] < 0x80 || p[1] > 0xBF
|
|
|
+ || p[2] < 0x80 || p[2] > 0xBF) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ p += 3;
|
|
|
+ }
|
|
|
+ else if (chr >= 0xF0 && chr <= 0xF4 && p + 3 < p_end) {
|
|
|
+ if (chr == 0xF0) {
|
|
|
+ if (p[1] < 0x90 || p[1] > 0xBF
|
|
|
+ || p[2] < 0x80 || p[2] > 0xBF
|
|
|
+ || p[3] < 0x80 || p[3] > 0xBF) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else if (chr >= 0xF1 && chr <= 0xF3) {
|
|
|
+ if (p[1] < 0x80 || p[1] > 0xBF
|
|
|
+ || p[2] < 0x80 || p[2] > 0xBF
|
|
|
+ || p[3] < 0x80 || p[3] > 0xBF) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else if (chr == 0xF4) {
|
|
|
+ if (p[1] < 0x80 || p[1] > 0x8F
|
|
|
+ || p[2] < 0x80 || p[2] > 0xBF
|
|
|
+ || p[3] < 0x80 || p[3] > 0xBF) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ p += 4;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return (p == p_end);
|
|
|
+}
|
|
|
+
|
|
|
+const ConstStrDescription *
|
|
|
+wasm_runtime_records_const_filename_string(WASMRuntime * runtime,
|
|
|
+ const char * str, const uint32 len,
|
|
|
+ char* error_buf, uint32 error_buf_size)
|
|
|
+{
|
|
|
+ int no_postfix_len = len;
|
|
|
+
|
|
|
+ for (int i = len - 1; i >= 0; i --) {
|
|
|
+ if (str[i] == '.') {
|
|
|
+ no_postfix_len = i;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!no_postfix_len)
|
|
|
+ no_postfix_len = len;
|
|
|
+
|
|
|
+ return wasm_runtime_records_const_string(runtime, str, no_postfix_len,
|
|
|
+ error_buf, error_buf_size);
|
|
|
+}
|
|
|
+
|
|
|
+const ConstStrDescription *
|
|
|
+wasm_runtime_records_const_string(WASMRuntime * runtime,
|
|
|
+ const char * str, const uint32 len,
|
|
|
+ char* error_buf, uint32 error_buf_size)
|
|
|
+{
|
|
|
+ HashMap * pool = NULL;
|
|
|
+ char *c_str, *value;
|
|
|
+ ConstStrDescription temp_key;
|
|
|
+ ConstStrDescription * key = NULL;
|
|
|
+ uint32 req_size = 0;
|
|
|
+
|
|
|
+ if (!runtime)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ pool = runtime->global_const_str_pool;
|
|
|
+ if (!pool)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ if (!check_utf8_str((const uint8 *)str, len)) {
|
|
|
+ set_error_buf(error_buf, error_buf_size,
|
|
|
+ "invalid UTF-8 encoding");
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ bh_assert(len < (UINT_MAX/2));
|
|
|
+ temp_key.str = (void*)str;
|
|
|
+ temp_key.is_sys_symbol = false;
|
|
|
+ temp_key.len = len;
|
|
|
+ temp_key.hash = 0;
|
|
|
+
|
|
|
+ if ((value = bh_hash_map_find(pool, &temp_key))) {
|
|
|
+ return (ConstStrDescription *)value;
|
|
|
+ }
|
|
|
+
|
|
|
+ req_size = sizeof(ConstStrDescription) + (uint32)len + 1;
|
|
|
+
|
|
|
+ if (!(key = runtime_malloc(req_size, error_buf, error_buf_size))) {
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ memset(key, 0, req_size);
|
|
|
+
|
|
|
+ //c_str = key->data;
|
|
|
+ c_str = (char*)(key + 1);
|
|
|
+ bh_memcpy_s(c_str, (uint32)(len + 1), str, (uint32)len);
|
|
|
+
|
|
|
+ key->str = c_str;
|
|
|
+ key->len = len;
|
|
|
+ key->hash = temp_key.hash;
|
|
|
+ key->is_sys_symbol = false;
|
|
|
+
|
|
|
+ if (!bh_hash_map_insert(pool, key, key)) {
|
|
|
+ set_error_buf(error_buf, error_buf_size,
|
|
|
+ "failed to insert string to hash map");
|
|
|
+ wasm_runtime_free(key);
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ return key;
|
|
|
+}
|
|
|
+
|
|
|
+WASMRuntime *
|
|
|
+wasm_runtime_get_runtime()
|
|
|
+{
|
|
|
+ return g_runtime;
|
|
|
+}
|
|
|
+
|
|
|
+bool
|
|
|
+wasm_runtime_runtime_init(bool standalone, bool auto_ext_name)
|
|
|
+{
|
|
|
+ if (g_runtime)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ WASMRuntime * runtime = NULL;
|
|
|
+ runtime = wasm_runtime_malloc(sizeof(WASMRuntime));
|
|
|
+ if (!runtime)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ memset(runtime, 0, sizeof(WASMRuntime));
|
|
|
+
|
|
|
+ runtime->config.need_load_dependencies = !standalone;
|
|
|
+ runtime->config.auto_update_extension = auto_ext_name;
|
|
|
+#if WASM_ENABLE_DYNAMIC_LINKING != 0
|
|
|
+ runtime->cur_loading_program = NULL;
|
|
|
+#endif
|
|
|
+ runtime->reader = NULL;
|
|
|
+ runtime->destroyer = NULL;
|
|
|
+ runtime->all_loaded_modules = NULL;
|
|
|
+
|
|
|
+ if (!standalone) {
|
|
|
+ runtime->all_loaded_modules =
|
|
|
+ bh_hash_map_create(RUNTIME_NAME_MODULE_MAP_INIT_SIZE,
|
|
|
+ false,
|
|
|
+ (HashFunc)const_str_hash,
|
|
|
+ (KeyEqualFunc)const_str_equal,
|
|
|
+ NULL,
|
|
|
+ (ValueDestroyFunc)const_str_destroy_module);
|
|
|
+ if (!runtime->all_loaded_modules) {
|
|
|
+ wasm_runtime_free(runtime);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!wasm_runtime_const_str_pool_init(runtime)) {
|
|
|
+ wasm_runtime_runtime_destroy();
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ g_runtime = runtime;
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+void
|
|
|
+wasm_runtime_runtime_destroy()
|
|
|
+{
|
|
|
+ if (!g_runtime)
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (g_runtime->all_loaded_modules)
|
|
|
+ bh_hash_map_destroy(g_runtime->all_loaded_modules);
|
|
|
+
|
|
|
+ wasm_runtime_const_str_pool_destroy(g_runtime);
|
|
|
+
|
|
|
+ wasm_runtime_free(g_runtime);
|
|
|
+ g_runtime = NULL;
|
|
|
+}
|
|
|
+
|
|
|
+// shared module means built with -Wl,--shared.
|
|
|
+// dependency module means opened explicitly or implicitly by other module.
|
|
|
+// root module means the first module instantiated by a program.
|
|
|
+bool
|
|
|
+wasm_runtime_is_shared_module(const WASMModuleCommon * module)
|
|
|
+{
|
|
|
+ WASMDylinkSection * dylink_section = NULL;
|
|
|
+
|
|
|
+ if (module->module_type == Wasm_Module_Bytecode) {
|
|
|
+ dylink_section = ((WASMModule*)module)->dylink_section;
|
|
|
+ } else {
|
|
|
+#if WASM_ENABLE_AOT != 0
|
|
|
+ dylink_section = ((AOTModule*)module)->dylink_section;
|
|
|
+#endif
|
|
|
+ }
|
|
|
+
|
|
|
+ if (dylink_section)
|
|
|
+ return true;
|
|
|
+
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+bool
|
|
|
+wasm_runtime_is_shared_module_instance(const WASMModuleInstanceCommon * module_inst)
|
|
|
+{
|
|
|
+ WASMDylinkSection * dylink_section = NULL;
|
|
|
+
|
|
|
+ if (module_inst->module_type == Wasm_Module_Bytecode) {
|
|
|
+ WASMModule * module = (WASMModule *)(((WASMModuleInstance*)module_inst)->module);
|
|
|
+ dylink_section = (module)->dylink_section;
|
|
|
+ } else {
|
|
|
+#if WASM_ENABLE_AOT != 0
|
|
|
+ AOTModule * module = (AOTModule*)(((AOTModuleInstance*)module_inst)->aot_module.ptr);
|
|
|
+ dylink_section = (module)->dylink_section;
|
|
|
+#endif
|
|
|
+ }
|
|
|
+
|
|
|
+ if (dylink_section)
|
|
|
+ return true;
|
|
|
+
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+#if WASM_ENABLE_DYNAMIC_LINKING != 0
|
|
|
+inline bool
|
|
|
+wasm_program_is_root_module(const WASMModuleInstanceCommon * module_inst)
|
|
|
+{
|
|
|
+ const WASMModuleInstanceHead * module_inst_head = (WASMModuleInstanceHead *)module_inst;
|
|
|
+ if (module_inst_head->program) {
|
|
|
+ if (module_inst_head->program->root_module_inst)
|
|
|
+ return module_inst_head->program->root_module_inst == module_inst;
|
|
|
+ else
|
|
|
+ return true;
|
|
|
+ } else
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+inline WASMModuleInstanceCommon *
|
|
|
+wasm_program_get_root_module_from_inst(const WASMModuleInstanceCommon * module_inst)
|
|
|
+{
|
|
|
+ WASMProgramInstance * program = ((WASMModuleInstanceHead*)module_inst)->program;
|
|
|
+ if (!program)
|
|
|
+ return (WASMModuleInstanceCommon *)module_inst;
|
|
|
+
|
|
|
+ return program->root_module_inst;
|
|
|
+}
|
|
|
+
|
|
|
+inline WASMModuleInstanceCommon *
|
|
|
+wasm_program_get_root_module(const WASMProgramInstance * program)
|
|
|
+{
|
|
|
+ return program->root_module_inst;
|
|
|
+}
|
|
|
+
|
|
|
+inline void
|
|
|
+wasm_program_set_root_module(WASMProgramInstance * program, const WASMModuleInstanceCommon * module_inst)
|
|
|
+{
|
|
|
+ program->root_module_inst = (WASMModuleInstanceCommon*)module_inst;
|
|
|
+}
|
|
|
+
|
|
|
+bool
|
|
|
+wasm_program_validate_mode_compatiability(WASMProgramInstance * program)
|
|
|
+{
|
|
|
+ WASMRuntime * runtime = program->runtime;
|
|
|
+ WASMModuleInstanceCommon * root_module_inst = program->root_module_inst;
|
|
|
+ const char * symbol_name = NULL;
|
|
|
+ bool malloc_exist = false;
|
|
|
+ bool free_exist = false;
|
|
|
+ bool realloc_exist = false;
|
|
|
+ bool export_sp_exist = false;
|
|
|
+ WASMModuleInstance * wasm_module_inst = NULL;
|
|
|
+#if WASM_ENABLE_AOT != 0
|
|
|
+ AOTModuleInstance * aot_module_inst = NULL;
|
|
|
+#endif
|
|
|
+
|
|
|
+ if (root_module_inst->module_type == Wasm_Module_Bytecode) {
|
|
|
+ wasm_module_inst = (WASMModuleInstance *)root_module_inst;
|
|
|
+
|
|
|
+ for (uint32 i = 0; i < wasm_module_inst->export_func_count; i ++) {
|
|
|
+ symbol_name = wasm_module_inst->export_functions[i].name;
|
|
|
+ if (symbol_name) {
|
|
|
+ if (!strcmp(symbol_name, CONST_STR_POOL_STR(runtime, WAMR_CSP_malloc)))
|
|
|
+ malloc_exist = true;
|
|
|
+ else if (!strcmp(symbol_name, CONST_STR_POOL_STR(runtime, WAMR_CSP_free)))
|
|
|
+ free_exist = true;
|
|
|
+ else if (!strcmp(symbol_name, CONST_STR_POOL_STR(runtime, WAMR_CSP_realloc)))
|
|
|
+ realloc_exist = true;
|
|
|
+
|
|
|
+ if (program->config.root_is_AS_module) {
|
|
|
+ if (!strcmp(symbol_name, CONST_STR_POOL_STR(runtime, WAMR_CSP___alloc)))
|
|
|
+ malloc_exist = true;
|
|
|
+ else if (!strcmp(symbol_name, CONST_STR_POOL_STR(runtime, WAMR_CSP___free)))
|
|
|
+ free_exist = true;
|
|
|
+ else if (!strcmp(symbol_name, CONST_STR_POOL_STR(runtime, WAMR_CSP___realloc)))
|
|
|
+ realloc_exist = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (malloc_exist && free_exist && realloc_exist)
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ for (uint32 i = 0; i < wasm_module_inst->export_glob_count; i++) {
|
|
|
+ symbol_name = wasm_module_inst->export_globals[i].name;
|
|
|
+ if (!program->config.root_is_AS_module) {
|
|
|
+ if (!strcmp(symbol_name, CONST_STR_POOL_STR(runtime, WAMR_CSP_var_stack_pointer)))
|
|
|
+ export_sp_exist = true;
|
|
|
+ } else {
|
|
|
+ if (!strcmp(symbol_name, CONST_STR_POOL_STR(runtime, WAMR_CSP_var_user_stack_pointer)))
|
|
|
+ export_sp_exist = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (export_sp_exist)
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ } else {
|
|
|
+#if WASM_ENABLE_AOT != 0
|
|
|
+ aot_module_inst = (AOTModuleInstance *)root_module_inst;
|
|
|
+ AOTModule * aot_module = (AOTModule*)(aot_module_inst->aot_module.ptr);
|
|
|
+ uint32 export_func_count = aot_module->export_func_count;
|
|
|
+ uint32 exports_count = aot_module->export_count;
|
|
|
+
|
|
|
+ AOTExportFunctionInstance * export_funcs = aot_module_inst->export_funcs.ptr;
|
|
|
+
|
|
|
+ for (uint32 i = 0; i < export_func_count; i ++) {
|
|
|
+ symbol_name = export_funcs[i].func_name;
|
|
|
+ if (symbol_name) {
|
|
|
+ if (!strcmp(symbol_name, CONST_STR_POOL_STR(runtime, WAMR_CSP_malloc)))
|
|
|
+ malloc_exist = true;
|
|
|
+ else if (!strcmp(symbol_name, CONST_STR_POOL_STR(runtime, WAMR_CSP_free)))
|
|
|
+ free_exist = true;
|
|
|
+ else if (!strcmp(symbol_name, CONST_STR_POOL_STR(runtime, WAMR_CSP_realloc)))
|
|
|
+ realloc_exist = true;
|
|
|
+
|
|
|
+ if (program->config.root_is_AS_module) {
|
|
|
+ if (!strcmp(symbol_name, CONST_STR_POOL_STR(runtime, WAMR_CSP___alloc)))
|
|
|
+ malloc_exist = true;
|
|
|
+ else if (!strcmp(symbol_name, CONST_STR_POOL_STR(runtime, WAMR_CSP___free)))
|
|
|
+ free_exist = true;
|
|
|
+ else if (!strcmp(symbol_name, CONST_STR_POOL_STR(runtime, WAMR_CSP___realloc)))
|
|
|
+ realloc_exist = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (malloc_exist && free_exist && realloc_exist)
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ for (uint32 i = 0; i < exports_count; i++) {
|
|
|
+ if (aot_module->exports[i].kind != EXPORT_KIND_GLOBAL)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ symbol_name = aot_module->exports[i].name;
|
|
|
+ if (!program->config.root_is_AS_module) {
|
|
|
+ if (!strcmp(symbol_name, CONST_STR_POOL_STR(runtime, WAMR_CSP_var_stack_pointer)))
|
|
|
+ export_sp_exist = true;
|
|
|
+ } else {
|
|
|
+ if (!strcmp(symbol_name, CONST_STR_POOL_STR(runtime, WAMR_CSP_var_user_stack_pointer)))
|
|
|
+ export_sp_exist = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (export_sp_exist)
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+#endif
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ if (program->config.import_memop_mode == FROM_ROOT) {
|
|
|
+ if (!malloc_exist || !free_exist || !realloc_exist) {
|
|
|
+ LOG_WARNING("Select memory from root module, but not found the functions exported:");
|
|
|
+ if (!malloc_exist)
|
|
|
+ LOG_WARNING("malloc");
|
|
|
+ if (!free_exist)
|
|
|
+ LOG_WARNING("free");
|
|
|
+ if (!realloc_exist)
|
|
|
+ LOG_WARNING("realloc");
|
|
|
+
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if (malloc_exist || free_exist || realloc_exist) {
|
|
|
+ LOG_WARNING("Select memory from VM, but found memory functions exported:");
|
|
|
+ if (malloc_exist)
|
|
|
+ LOG_WARNING("malloc");
|
|
|
+ if (free_exist)
|
|
|
+ LOG_WARNING("free");
|
|
|
+ if (realloc_exist)
|
|
|
+ LOG_WARNING("realloc");
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!export_sp_exist) {
|
|
|
+ LOG_WARNING("Can't find global __stack_pointer exported, link error might happen.");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+WASMProgramInstance *
|
|
|
+wasm_runtime_create_program_internal(char * error_buf, uint32 error_buf_size, uint32 dlopen_mode)
|
|
|
+{
|
|
|
+ WASMProgramInstance * program = NULL;
|
|
|
+ if (!(program = runtime_malloc(sizeof(WASMProgramInstance), error_buf, error_buf_size)))
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ program->clean_all = false;
|
|
|
+ program->config.binding_mode = LAZY_BINDING; // currently always lazy binding, ignore user setting
|
|
|
+ program->config.import_memop_mode = (dlopen_mode & MEM_ALLOCATOR_MASK) ? FROM_ROOT: FROM_BUILTIN_LIBC;
|
|
|
+ program->config.use_tbl_as_cache = (dlopen_mode & USE_TBL_AS_CACHE_MASK);
|
|
|
+ program->config.root_is_AS_module = (dlopen_mode & ROOT_IS_AS_MODULE_MASK);
|
|
|
+ program->config.use_resolve_cache = false; // currently alwasy false, no optimiation implemented.
|
|
|
+
|
|
|
+ program->runtime = wasm_runtime_get_runtime();
|
|
|
+ // bh_list_init(&program->loading_modules_list);
|
|
|
+
|
|
|
+ program->resolving_cache = runtime_malloc(sizeof(wasm_resolving_cache_entry) * PROGRAM_RESOLVING_CACHE_LINE_LEN * PROGRAM_RESOLVING_CACHE_LINE_COUNT,
|
|
|
+ error_buf, error_buf_size);
|
|
|
+ if (!program->resolving_cache) {
|
|
|
+ wasm_runtime_free(program);
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ // create a local map to record dependencies.
|
|
|
+ // hash map is not responsible to reclaim the key
|
|
|
+ // they are allocated/free by const string pool.
|
|
|
+ program->global_modules_inst_name_hmap =
|
|
|
+ bh_hash_map_create(PROGRAM_NAME_MODULE_INST_INIT_SIZE,
|
|
|
+ false,
|
|
|
+ (HashFunc)const_str_hash,
|
|
|
+ (KeyEqualFunc)const_str_equal,
|
|
|
+ NULL,
|
|
|
+ (ValueDestroyFunc)const_str_destroy_module_inst);
|
|
|
+ if (!program->global_modules_inst_name_hmap) {
|
|
|
+ wasm_runtime_free(program->resolving_cache);
|
|
|
+ wasm_runtime_free(program);
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ program->global_modules_inst_id_hmap =
|
|
|
+ bh_hash_map_create(PROGRAM_INST_ID_HMAP_INIT_SIZE,
|
|
|
+ false,
|
|
|
+ (HashFunc)inst_id_hash,
|
|
|
+ (KeyEqualFunc)inst_id_equal,
|
|
|
+ NULL,
|
|
|
+ NULL);
|
|
|
+ if (!program->global_modules_inst_id_hmap) {
|
|
|
+ bh_hash_map_destroy(program->global_modules_inst_name_hmap);
|
|
|
+ wasm_runtime_free(program->resolving_cache);
|
|
|
+ wasm_runtime_free(program);
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+ // index 0 is reserved for error handling.
|
|
|
+ program->next_free_inst_id = 1;
|
|
|
+ program->builtin_libc_funcs = NULL;
|
|
|
+ program->builtin_libc_funcs_count = 0;
|
|
|
+ program->builtin_libc_funcs_size = 0;
|
|
|
+
|
|
|
+ program->exception_inst = NULL;
|
|
|
+ program->error_buf = error_buf;
|
|
|
+ program->error_buf_size = error_buf_size;
|
|
|
+
|
|
|
+ return program;
|
|
|
+}
|
|
|
+
|
|
|
+void
|
|
|
+wasm_program_remove_module_inst_from_name_hmap(WASMProgramInstance * program, WASMModuleInstance * module_inst)
|
|
|
+{
|
|
|
+ bh_hash_map_remove(program->global_modules_inst_name_hmap, (void*)module_inst->module->module_name, NULL, NULL);
|
|
|
+}
|
|
|
+
|
|
|
+void
|
|
|
+wasm_program_cache_resolve_result(WASMProgramInstance * program, int32 id, void * result_func, void * module_inst)
|
|
|
+{
|
|
|
+ wasm_resolving_cache_entry * cache_line = NULL;
|
|
|
+ wasm_resolving_cache_entry * p_empty_entry = NULL;
|
|
|
+ int32 index = id & (PROGRAM_RESOLVING_CACHE_LINE_COUNT - 1);
|
|
|
+ if (!program)
|
|
|
+ return;
|
|
|
+
|
|
|
+ cache_line = program->resolving_cache + (PROGRAM_RESOLVING_CACHE_LINE_LEN * index);
|
|
|
+
|
|
|
+ if (!cache_line[0].func_inst) {
|
|
|
+ p_empty_entry = &cache_line[0];
|
|
|
+ } else if (!cache_line[1].func_inst)
|
|
|
+ p_empty_entry = &cache_line[1];
|
|
|
+ else
|
|
|
+ p_empty_entry = &cache_line[0];
|
|
|
+
|
|
|
+ p_empty_entry->index = id;
|
|
|
+ p_empty_entry->func_inst = result_func;
|
|
|
+#if WASM_ENABLE_AOT != 0
|
|
|
+ p_empty_entry->module_inst = module_inst;
|
|
|
+#endif
|
|
|
+}
|
|
|
+
|
|
|
+void *
|
|
|
+wasm_program_lookup_cached_resolving_func(WASMProgramInstance * program, int32 id)
|
|
|
+{
|
|
|
+ wasm_resolving_cache_entry * cache_line = NULL;
|
|
|
+ int32 index = id & (PROGRAM_RESOLVING_CACHE_LINE_COUNT - 1);
|
|
|
+
|
|
|
+ if (!program)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ cache_line = program->resolving_cache + (PROGRAM_RESOLVING_CACHE_LINE_LEN * index);
|
|
|
+
|
|
|
+ if (cache_line[0].index == id)
|
|
|
+ return cache_line[0].func_inst;
|
|
|
+ else if (cache_line[1].index == id)
|
|
|
+ return cache_line[1].func_inst;
|
|
|
+
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
+void
|
|
|
+wasm_program_invalidate_cached_wasm_func(WASMProgramInstance * program, wasm_module_inst_t module_inst)
|
|
|
+{
|
|
|
+ if (!program)
|
|
|
+ return;
|
|
|
+
|
|
|
+ wasm_resolving_cache_entry * cache_entry = program->resolving_cache;
|
|
|
+ if (!module_inst)
|
|
|
+ return;
|
|
|
+
|
|
|
+ for (int i = 0; i < PROGRAM_RESOLVING_CACHE_LINE_LEN * PROGRAM_RESOLVING_CACHE_LINE_COUNT; i ++) {
|
|
|
+ WASMFunctionInstance * func_inst = cache_entry[i].func_inst;
|
|
|
+ if (!func_inst)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ if ((wasm_module_inst_t)func_inst->module_inst != module_inst)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ memset(&cache_entry[i], 0, sizeof(wasm_resolving_cache_entry));
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+uint32
|
|
|
+wasm_program_create_dlopen_session(WASMProgramInstance * program, WASMModuleInstanceCommon * module_inst)
|
|
|
+{
|
|
|
+ WASMModuleInstanceHead * module_inst_head = (WASMModuleInstanceHead *)module_inst;
|
|
|
+ module_inst_head->exp_ref_cnt ++;
|
|
|
+
|
|
|
+ //if (module_inst->module_type == Wasm_Module_Bytecode) {
|
|
|
+ // WASMModuleInstance * wasm_module_inst = (WASMModuleInstance *)module_inst;
|
|
|
+ // printf("module %s, exp ref = %d, imp ref = %d\n", wasm_module_inst->module->module_name->str,
|
|
|
+ // wasm_module_inst->exp_ref_cnt, wasm_module_inst->imp_ref_cnt);
|
|
|
+ //} else {
|
|
|
+ // AOTModuleInstance * aot_module_inst = (AOTModuleInstance *)module_inst;
|
|
|
+ // printf("module %s, exp ref = %d, imp ref = %d\n", ((AOTModule*)(aot_module_inst->aot_module.ptr))->module_name->str,
|
|
|
+ // aot_module_inst->exp_ref_cnt, aot_module_inst->imp_ref_cnt);
|
|
|
+ //}
|
|
|
+
|
|
|
+ return module_inst_head->inst_id;
|
|
|
+}
|
|
|
+
|
|
|
+WASMModuleInstanceCommon *
|
|
|
+wasm_program_destroy_dlopen_session(WASMProgramInstance * program, uint32 inst_id)
|
|
|
+{
|
|
|
+ WASMModuleInstanceCommon * module_inst = wasm_program_get_module_inst_by_id(program, inst_id);
|
|
|
+ WASMModuleInstanceHead * module_inst_head = (WASMModuleInstanceHead *)module_inst;
|
|
|
+ if (!module_inst)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ if (module_inst_head->exp_ref_cnt > 0)
|
|
|
+ module_inst_head->exp_ref_cnt -- ;
|
|
|
+
|
|
|
+ //if (module_inst->module_type == Wasm_Module_Bytecode)
|
|
|
+ // printf("module %s, exp ref = %d, imp ref = %d\n", ((WASMModuleInstance*)module_inst)->module->module_name->str,
|
|
|
+ // module_inst_head->exp_ref_cnt, module_inst_head->imp_ref_cnt);
|
|
|
+ //else
|
|
|
+ // printf("module %s, exp ref = %d, imp ref = %d\n", ((AOTModule*)((AOTModuleInstance*)module_inst)->aot_module.ptr)->module_name->str,
|
|
|
+ // module_inst_head->exp_ref_cnt, module_inst_head->imp_ref_cnt);
|
|
|
+
|
|
|
+ return module_inst;
|
|
|
+}
|
|
|
+
|
|
|
+uint32
|
|
|
+wasm_program_alloc_module_instance_id(WASMProgramInstance * program, WASMModuleInstanceCommon * module_inst)
|
|
|
+{
|
|
|
+ uint32 id = 0;
|
|
|
+ void * p = NULL;
|
|
|
+ WASMModuleInstanceHead * module_inst_head = (WASMModuleInstanceHead *)module_inst;
|
|
|
+
|
|
|
+ id = program->next_free_inst_id;
|
|
|
+
|
|
|
+ p = (void*)(uintptr_t)id;
|
|
|
+
|
|
|
+ while (bh_hash_map_find(program->global_modules_inst_id_hmap, p)) {
|
|
|
+ id ++;
|
|
|
+ if (id == PROGRAM_INST_ID_TOP_BOUNARY)
|
|
|
+ id = 2;
|
|
|
+ p = (void*)(uintptr_t)id;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!bh_hash_map_insert(program->global_modules_inst_id_hmap, p, (void*)module_inst))
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ program->next_free_inst_id = id + 1;
|
|
|
+ if (program->next_free_inst_id == PROGRAM_INST_ID_TOP_BOUNARY)
|
|
|
+ program->next_free_inst_id = 2;
|
|
|
+
|
|
|
+ module_inst_head->inst_id = id;
|
|
|
+
|
|
|
+ return id;
|
|
|
+}
|
|
|
+
|
|
|
+void
|
|
|
+wasm_program_free_module_instance_id(WASMProgramInstance * program, uint32 inst_id)
|
|
|
+{
|
|
|
+ void * key = (void*)(uintptr_t)inst_id;
|
|
|
+ bh_hash_map_remove(program->global_modules_inst_id_hmap, key, NULL, NULL);
|
|
|
+}
|
|
|
+
|
|
|
+WASMModuleInstanceCommon *
|
|
|
+wasm_program_get_module_inst_by_id(WASMProgramInstance * program, uint32 inst_idx)
|
|
|
+{
|
|
|
+ WASMModuleInstanceCommon * module_inst = NULL;
|
|
|
+ void * key = (void*)(uintptr_t)inst_idx;
|
|
|
+
|
|
|
+ module_inst = bh_hash_map_find(program->global_modules_inst_id_hmap, key);
|
|
|
+ if (!module_inst) {
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ return module_inst;
|
|
|
+}
|
|
|
+
|
|
|
+WASMModuleInstanceCommon *
|
|
|
+wasm_program_get_module_inst_by_name(WASMProgramInstance * program, const ConstStrDescription * module_name)
|
|
|
+{
|
|
|
+ WASMModuleInstanceCommon * module_inst = NULL;
|
|
|
+ if (module_name == CONST_STR_POOL_DESC(program->runtime, WAMR_CSP_env))
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ module_inst = bh_hash_map_find(program->global_modules_inst_name_hmap, (void*)module_name);
|
|
|
+ return module_inst;
|
|
|
+}
|
|
|
+
|
|
|
+WASMModuleInstanceCommon *
|
|
|
+wasm_program_get_dep_module_inst_by_name(WASMModuleInstanceCommon * caller_module_inst, const ConstStrDescription * module_name)
|
|
|
+{
|
|
|
+ WASMModuleInstanceCommon * module_inst = NULL;
|
|
|
+ WASMModuleInstanceHead * caller_module_inst_head = (WASMModuleInstanceHead *)caller_module_inst;
|
|
|
+
|
|
|
+ if (module_name == CONST_STR_POOL_DESC(caller_module_inst_head->runtime, WAMR_CSP_env))
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ if (caller_module_inst->module_type == Wasm_Module_Bytecode)
|
|
|
+ module_inst = bh_hash_map_find(
|
|
|
+ caller_module_inst_head->local_implicit_dependency_modules_name_hmap,
|
|
|
+ (void*)module_name);
|
|
|
+ else {
|
|
|
+ module_inst = bh_hash_map_find(
|
|
|
+ caller_module_inst_head->local_implicit_dependency_modules_name_hmap,
|
|
|
+ (void*)module_name);
|
|
|
+ }
|
|
|
+ return module_inst;
|
|
|
+}
|
|
|
+
|
|
|
+bool
|
|
|
+wasm_program_insert_module_inst_by_name(WASMProgramInstance * program,
|
|
|
+ WASMModuleInstanceCommon * module_inst,
|
|
|
+ const ConstStrDescription * module_name)
|
|
|
+{
|
|
|
+ return bh_hash_map_insert_with_dup(program->global_modules_inst_name_hmap,
|
|
|
+ (void*)module_name,
|
|
|
+ (void*)module_inst);
|
|
|
+}
|
|
|
+
|
|
|
+#if WASM_ENABLE_LIBC_BUILTIN != 0
|
|
|
+static void
|
|
|
+wasm_program_destroy_internal_libc_module(WASMProgramInstance * program);
|
|
|
+#endif
|
|
|
+
|
|
|
+void
|
|
|
+wasm_runtime_destroy_program_internal(WASMProgramInstance * program)
|
|
|
+{
|
|
|
+ program->clean_all = true;
|
|
|
+
|
|
|
+#if WASM_ENABLE_LIBC_BUILTIN != 0
|
|
|
+ wasm_program_destroy_internal_libc_module(program);
|
|
|
+#endif
|
|
|
+
|
|
|
+ if (program->resolving_cache)
|
|
|
+ wasm_runtime_free(program->resolving_cache);
|
|
|
+
|
|
|
+ if (program->global_modules_inst_name_hmap)
|
|
|
+ bh_hash_map_destroy(program->global_modules_inst_name_hmap);
|
|
|
+
|
|
|
+ if (program->global_modules_inst_id_hmap)
|
|
|
+ bh_hash_map_destroy(program->global_modules_inst_id_hmap);
|
|
|
+
|
|
|
+ wasm_runtime_free(program);
|
|
|
+}
|
|
|
+
|
|
|
+const ConstStrDescription *
|
|
|
+upgrade_module_extension(const WASMRuntime *runtime,
|
|
|
+ const ConstStrDescription * key_module_name,
|
|
|
+ const package_type_t expected_module_type,
|
|
|
+ char * error_buf,
|
|
|
+ uint32 error_buf_size)
|
|
|
+{
|
|
|
+ uint32 offset = 0, new_name_len = 0;
|
|
|
+ const ConstStrDescription * key_new_module_name = NULL;
|
|
|
+ char * extension_name = NULL, *new_module_name = NULL;
|
|
|
+
|
|
|
+ if (!runtime->config.auto_update_extension)
|
|
|
+ return key_module_name;
|
|
|
+
|
|
|
+ offset = key_module_name->len;
|
|
|
+ extension_name = strrchr(key_module_name->str, '.');
|
|
|
+ if (!extension_name)
|
|
|
+ return key_module_name;
|
|
|
+
|
|
|
+ offset = extension_name - key_module_name->str;
|
|
|
+
|
|
|
+ new_name_len = offset + sizeof(".wasm") + 1;
|
|
|
+
|
|
|
+ new_module_name = (char*)wasm_runtime_malloc(new_name_len);
|
|
|
+ memset(new_module_name, 0, new_name_len);
|
|
|
+ memcpy(new_module_name, key_module_name->str, offset);
|
|
|
+
|
|
|
+ if (expected_module_type == Wasm_Module_Bytecode)
|
|
|
+ strncat(new_module_name, ".wasm", new_name_len);
|
|
|
+ else
|
|
|
+ strncat(new_module_name, ".aot", new_name_len);
|
|
|
+
|
|
|
+ key_new_module_name = wasm_runtime_records_const_string((WASMRuntime*)runtime, new_module_name,
|
|
|
+ strlen(new_module_name), error_buf, error_buf_size);
|
|
|
+
|
|
|
+ wasm_runtime_free(new_module_name);
|
|
|
+
|
|
|
+ return key_new_module_name;
|
|
|
+}
|
|
|
+
|
|
|
+static WASMModuleCommon *
|
|
|
+load_dependency_module(const WASMRuntime *runtime,
|
|
|
+ const ConstStrDescription * key,
|
|
|
+ const package_type_t expected_module_type,
|
|
|
+ char * error_buf,
|
|
|
+ uint32 error_buf_size)
|
|
|
+{
|
|
|
+ WASMModuleCommon * new_module = NULL;
|
|
|
+ // bh_list * new_modules_list = NULL;
|
|
|
+ const module_reader reader = wasm_runtime_get_module_reader();
|
|
|
+ const module_destroyer destroyer = wasm_runtime_get_module_destroyer();
|
|
|
+ // LoadingModuleElem * loading_module_elem = NULL;
|
|
|
+
|
|
|
+ if (!reader || !destroyer) {
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ // check if already loaded
|
|
|
+ new_module = bh_hash_map_find(runtime->all_loaded_modules, (void*)key);
|
|
|
+ if (new_module &&
|
|
|
+ new_module->module_type == expected_module_type) {
|
|
|
+
|
|
|
+ if (!wasm_runtime_is_shared_module(new_module))
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ return new_module;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (new_module &&
|
|
|
+ new_module->module_type != expected_module_type) {
|
|
|
+
|
|
|
+ return NULL; //currently, VM won't replace the extension automatically on user's behalf
|
|
|
+
|
|
|
+ //key = upgrade_module_extension(runtime, key, expected_module_type, error_buf, error_buf_size);
|
|
|
+
|
|
|
+ //new_module = bh_hash_map_find(runtime->all_loaded_modules, (void*)key);
|
|
|
+ //if (new_module &&
|
|
|
+ // new_module->module_type == expected_module_type) {
|
|
|
+ // return new_module;
|
|
|
+ //}
|
|
|
+ }
|
|
|
+
|
|
|
+ bh_assert(!new_module);
|
|
|
+
|
|
|
+ if (!(new_module = load_dependency_module_internal(reader, destroyer, key->str,
|
|
|
+ key->len, expected_module_type, error_buf, error_buf_size))) {
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (new_module->module_type == Wasm_Module_Bytecode)
|
|
|
+ ((WASMModule*)new_module)->module_name = key;
|
|
|
+ else
|
|
|
+ ((AOTModule*)new_module)->module_name = key;
|
|
|
+
|
|
|
+ if (!bh_hash_map_insert(runtime->all_loaded_modules, (void*)key, new_module)) {
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new_module;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Return export function count in module export section.
|
|
|
+ */
|
|
|
+static uint32
|
|
|
+get_export_count_by_kind(const WASMModuleCommon *module, const uint8 kind)
|
|
|
+{
|
|
|
+ uint32 count = 0;
|
|
|
+ if (module->module_type == Wasm_Module_Bytecode) {
|
|
|
+ WASMExport *export = ((WASMModule*)module)->exports;
|
|
|
+
|
|
|
+ for (uint32 i = 0; i < ((WASMModule*)module)->export_count; i++, export++) {
|
|
|
+ if (export->kind == kind)
|
|
|
+ count ++;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ AOTExport * export = ((AOTModule*)module)->exports;
|
|
|
+
|
|
|
+ for (uint32 i = 0; i < ((AOTModule*)module)->export_count; i++, export++) {
|
|
|
+ if (export->kind == kind)
|
|
|
+ count ++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return count;
|
|
|
+}
|
|
|
+
|
|
|
+WASMModuleCommon *
|
|
|
+load_explicit_dependency_module(const WASMModuleInstanceCommon *parent_module,
|
|
|
+ const ConstStrDescription * key)
|
|
|
+{
|
|
|
+ WASMModuleInstanceHead * parent_module_inst_head = (WASMModuleInstanceHead *)parent_module;
|
|
|
+ WASMRuntime * runtime = parent_module_inst_head->runtime;
|
|
|
+ WASMProgramInstance * program = parent_module_inst_head->program;
|
|
|
+
|
|
|
+ // all new loaded modules will be recorded into program, so that
|
|
|
+ // can be easy to instantiate them later.
|
|
|
+ runtime->cur_loading_program = program;
|
|
|
+
|
|
|
+ return load_dependency_module(runtime, key,
|
|
|
+ parent_module_inst_head->module_type,
|
|
|
+ program->error_buf,
|
|
|
+ program->error_buf_size);
|
|
|
+}
|
|
|
+
|
|
|
+WASMModuleCommon *
|
|
|
+load_implicit_dependency_module(const WASMModuleCommon *parent_module,
|
|
|
+ const ConstStrDescription * key,
|
|
|
+ char * error_buf,
|
|
|
+ uint32 error_buf_size)
|
|
|
+{
|
|
|
+ WASMRuntime * runtime = NULL;
|
|
|
+ if (parent_module->module_type == Wasm_Module_Bytecode)
|
|
|
+ runtime = ((WASMModule*)parent_module)->runtime;
|
|
|
+ else {
|
|
|
+ runtime = ((AOTModule*)parent_module)->runtime;
|
|
|
+ key = upgrade_module_extension(runtime, key, Wasm_Module_AoT, error_buf, error_buf_size);
|
|
|
+ }
|
|
|
+
|
|
|
+ return load_dependency_module(runtime, key, parent_module->module_type, error_buf, error_buf_size);
|
|
|
+}
|
|
|
+
|
|
|
+void
|
|
|
+decrement_ref_module_inst_callback(ConstStrDescription * key, void * value, void * user_data)
|
|
|
+{
|
|
|
+ ConstStrDescription ** unused_module_list = (ConstStrDescription **)user_data;
|
|
|
+ WASMModuleInstanceCommon * module_inst = (WASMModuleInstanceCommon *)value;
|
|
|
+ WASMModuleInstanceHead * module_inst_head = (WASMModuleInstanceHead *)module_inst;
|
|
|
+ const ConstStrDescription * module_name = NULL;
|
|
|
+
|
|
|
+ if (module_inst_head && module_inst_head->imp_ref_cnt ) {
|
|
|
+ module_inst_head->imp_ref_cnt --;
|
|
|
+ if (module_inst_head->module_type == Wasm_Module_Bytecode) {
|
|
|
+ module_name = ((WASMModuleInstance*)module_inst)->module->module_name;
|
|
|
+ } else {
|
|
|
+ module_name = ((AOTModule*)((AOTModuleInstance*)module_inst)->aot_module.ptr)->module_name;
|
|
|
+ }
|
|
|
+ (void)module_name;
|
|
|
+ //printf("module %s, exp ref = %d, imp ref = %d\n",
|
|
|
+ // module_name->str,
|
|
|
+ // module_inst_head->exp_ref_cnt,
|
|
|
+ // module_inst_head->imp_ref_cnt);
|
|
|
+ if (!module_inst_head->imp_ref_cnt) {
|
|
|
+ if (!(*unused_module_list)) {
|
|
|
+ *unused_module_list = key;
|
|
|
+ } else {
|
|
|
+ (*unused_module_list)->next = key;
|
|
|
+ (*unused_module_list) = key;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void
|
|
|
+wasm_program_close_dependencies(wasm_module_inst_t module_inst,
|
|
|
+ uint32 inst_id)
|
|
|
+{
|
|
|
+ WASMModuleInstance * caller_module_inst = (WASMModuleInstance*)module_inst;
|
|
|
+ WASMProgramInstance * program = caller_module_inst->program;
|
|
|
+ WASMModuleInstanceCommon * callee_module_inst = NULL, * iter_module_inst = NULL;
|
|
|
+ WASMModuleInstanceHead * callee_module_inst_head = NULL, *iter_module_inst_head = NULL;
|
|
|
+ HashMap * implicit_dep_hmap = NULL;
|
|
|
+ const ConstStrDescription * list_end = NULL, * list_head = NULL,
|
|
|
+ * cur_processing_node = NULL;
|
|
|
+ ConstStrDescription * key = NULL;
|
|
|
+ const ConstStrDescription *module_name = NULL;
|
|
|
+ void * p = NULL;
|
|
|
+
|
|
|
+ if (!program)
|
|
|
+ return;
|
|
|
+
|
|
|
+ callee_module_inst = wasm_program_destroy_dlopen_session(program, inst_id);
|
|
|
+ callee_module_inst_head = (WASMModuleInstanceHead *)callee_module_inst;
|
|
|
+
|
|
|
+ if (!callee_module_inst)
|
|
|
+ return;
|
|
|
+
|
|
|
+ // a FIFO list stores the modules on which no modules depends implicitly.
|
|
|
+ // implement a breath first ref count update.
|
|
|
+ if (!callee_module_inst_head->exp_ref_cnt &&
|
|
|
+ !callee_module_inst_head->imp_ref_cnt) {
|
|
|
+ implicit_dep_hmap = callee_module_inst_head->local_implicit_dependency_modules_name_hmap;
|
|
|
+ if (callee_module_inst_head->module_type == Wasm_Module_Bytecode) {
|
|
|
+ module_name = ((WASMModuleInstance*)callee_module_inst)->module->module_name;
|
|
|
+ } else {
|
|
|
+ module_name = ((AOTModule*)((AOTModuleInstance*)callee_module_inst)->aot_module.ptr)->module_name;
|
|
|
+ }
|
|
|
+ //printf("************** possible to clear deps of %s ***********************\n",
|
|
|
+ // module_name->str);
|
|
|
+ list_head = list_end = module_name;
|
|
|
+ if (implicit_dep_hmap) {
|
|
|
+ //list_head = list_end = module_name;
|
|
|
+
|
|
|
+ // handle current module's dependency
|
|
|
+ bh_hash_map_traverse(implicit_dep_hmap,
|
|
|
+ (TraverseCallbackFunc)decrement_ref_module_inst_callback, &list_end);
|
|
|
+ }
|
|
|
+
|
|
|
+ // we have handle the callee module, so start from its deps in the following loop.
|
|
|
+ cur_processing_node = list_head->next;
|
|
|
+
|
|
|
+ // handle dependencies's deps recursively
|
|
|
+ while (cur_processing_node) {
|
|
|
+ key = (ConstStrDescription*)cur_processing_node;
|
|
|
+
|
|
|
+ iter_module_inst = bh_hash_map_find(program->global_modules_inst_name_hmap, (void*)key);
|
|
|
+ iter_module_inst_head = (WASMModuleInstanceHead*)iter_module_inst;
|
|
|
+ if (iter_module_inst_head) {
|
|
|
+ bh_assert(iter_module_inst_head->imp_ref_cnt == 0);
|
|
|
+ if (iter_module_inst_head->local_implicit_dependency_modules_name_hmap)
|
|
|
+ bh_hash_map_traverse(iter_module_inst_head->local_implicit_dependency_modules_name_hmap,
|
|
|
+ (TraverseCallbackFunc)decrement_ref_module_inst_callback, &list_end);
|
|
|
+ }
|
|
|
+
|
|
|
+ cur_processing_node = cur_processing_node->next;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // remove the modules which both exp_ref and imp_ref are zero.
|
|
|
+ // Note: currently, we don't handle cycle-dependency case, it's responsible for application user.
|
|
|
+ cur_processing_node = list_head;
|
|
|
+ while(cur_processing_node) {
|
|
|
+ key = (ConstStrDescription*)cur_processing_node;
|
|
|
+
|
|
|
+ iter_module_inst = bh_hash_map_find(program->global_modules_inst_name_hmap, (void*)key);
|
|
|
+ iter_module_inst_head = (WASMModuleInstanceHead*)iter_module_inst;
|
|
|
+ if (iter_module_inst_head && !iter_module_inst_head->exp_ref_cnt) {
|
|
|
+ p = (void*)(uintptr_t)iter_module_inst_head->inst_id;
|
|
|
+ bh_hash_map_remove(program->global_modules_inst_id_hmap,
|
|
|
+ p,
|
|
|
+ NULL,
|
|
|
+ NULL);
|
|
|
+ bh_hash_map_remove(program->global_modules_inst_name_hmap, (void*)key, NULL, NULL);
|
|
|
+ if (iter_module_inst_head->module_type == Wasm_Module_Bytecode) {
|
|
|
+ module_name = ((WASMModuleInstance*)iter_module_inst)->module->module_name;
|
|
|
+ } else {
|
|
|
+ module_name = ((AOTModule*)((AOTModuleInstance*)iter_module_inst)->aot_module.ptr)->module_name;
|
|
|
+ }
|
|
|
+ //printf("module %s deinstantiating\n", module_name->str);
|
|
|
+
|
|
|
+ // wasm_program_free_module_instance_id(program, iter_module_inst->inst_id);
|
|
|
+ // wasm_program_remove_module_inst_from_name_hmap(program, iter_module_inst);
|
|
|
+ wasm_program_invalidate_cached_wasm_func(program, (wasm_module_inst_t)iter_module_inst);
|
|
|
+ wasm_runtime_module_free(program->root_module_inst, iter_module_inst_head->init_globals.actual_memory_base);
|
|
|
+ wasm_runtime_deinstantiate((wasm_module_inst_t)iter_module_inst);
|
|
|
+ }
|
|
|
+
|
|
|
+ cur_processing_node = cur_processing_node->next;
|
|
|
+ // unlink current working list
|
|
|
+ key->next = NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+// Note: it will be implemented as thread-safe.
|
|
|
+// only one thread could open a dependency wasm and its dependency per time.
|
|
|
+// will add contention protection (lock/mutex etc) later.
|
|
|
+uint32
|
|
|
+wasm_program_open_dependencies(wasm_module_inst_t module_inst,
|
|
|
+ const char * path)
|
|
|
+{
|
|
|
+ WASMModuleInstanceHead * module_inst_head = (WASMModuleInstanceHead *)module_inst;
|
|
|
+ WASMProgramInstance * program_inst = module_inst_head->program;
|
|
|
+ WASMRuntime * runtime = module_inst_head->runtime;
|
|
|
+ WASMModuleInstanceCommon * callee_module_inst = NULL;
|
|
|
+
|
|
|
+ if (!program_inst)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ callee_module_inst = wasm_program_open_dependencies_general(runtime,
|
|
|
+ program_inst,
|
|
|
+ module_inst,
|
|
|
+ path);
|
|
|
+
|
|
|
+ if (!callee_module_inst)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ if (callee_module_inst == module_inst)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ return wasm_program_create_dlopen_session(program_inst, callee_module_inst);
|
|
|
+}
|
|
|
+
|
|
|
+WASMModuleInstanceCommon *
|
|
|
+wasm_program_instantiate_dependencies(WASMRuntime * runtime,
|
|
|
+ WASMProgramInstance * program_inst,
|
|
|
+ WASMModuleInstanceCommon * caller_module_inst,
|
|
|
+ WASMModuleCommon * module)
|
|
|
+{
|
|
|
+ WASMModuleInstanceCommon * new_module_inst = NULL;
|
|
|
+ WASMModuleInstanceCommon *root_module_inst = NULL;
|
|
|
+ WASMModule * wasm_module = (WASMModule*)module;
|
|
|
+ AOTModule * aot_module = (AOTModule*)module;
|
|
|
+ DependencyModuleInitGlobals init_globals;
|
|
|
+ int32 init_size = 0, export_func_count = 0, stack_size = 0;
|
|
|
+ uint32 offset = 0;
|
|
|
+ void * native_addr = NULL;
|
|
|
+ bool is_aot = !(module->module_type == Wasm_Module_Bytecode);
|
|
|
+
|
|
|
+ root_module_inst = program_inst->root_module_inst;
|
|
|
+
|
|
|
+ if (!is_aot && !wasm_module->dylink_section) {
|
|
|
+ set_error_buf_v(program_inst->error_buf, program_inst->error_buf_size,
|
|
|
+ "%s isn't a valid shared wasm module.\n", wasm_module->module_name->str);
|
|
|
+ return NULL;
|
|
|
+ } else if (is_aot && !aot_module->dylink_section) {
|
|
|
+ set_error_buf_v(program_inst->error_buf, program_inst->error_buf_size,
|
|
|
+ "%s isn't a valid shared wasm module.\n", aot_module->module_name->str);
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (root_module_inst->module_type == Wasm_Module_Bytecode)
|
|
|
+ stack_size = ((WASMModuleInstance*)root_module_inst)->default_wasm_stack_size;
|
|
|
+ else
|
|
|
+ stack_size = ((AOTModuleInstance*)root_module_inst)->default_wasm_stack_size;
|
|
|
+
|
|
|
+ memset(&init_globals, 0, sizeof(DependencyModuleInitGlobals));
|
|
|
+
|
|
|
+ // lazy instantiation
|
|
|
+ // the idea is to load all dependencies first (so we can check if all of them exist),
|
|
|
+ // but only instantiate the first one, and other modules will be instantiated as needed.
|
|
|
+
|
|
|
+ export_func_count = get_export_count_by_kind(module, EXPORT_KIND_FUNC);
|
|
|
+
|
|
|
+ // allocate init mem space for dependency module
|
|
|
+ if (!is_aot) {
|
|
|
+ if (!wasm_module->dylink_section->table_alignment)
|
|
|
+ wasm_module->dylink_section->table_alignment = 1;
|
|
|
+
|
|
|
+ init_size = wasm_module->dylink_section->table_size + export_func_count;
|
|
|
+ init_size += wasm_module->dylink_section->table_alignment - 1;
|
|
|
+
|
|
|
+ // will calcuate it by instance id
|
|
|
+ init_globals.table_alignment = wasm_module->dylink_section->table_alignment;
|
|
|
+
|
|
|
+ if (!wasm_module->dylink_section->memory_alignment)
|
|
|
+ wasm_module->dylink_section->memory_alignment = 1;
|
|
|
+
|
|
|
+ bh_assert(wasm_module->dylink_section->memory_alignment > 0);
|
|
|
+ } else {
|
|
|
+ if (!aot_module->dylink_section->table_alignment)
|
|
|
+ aot_module->dylink_section->table_alignment = 1;
|
|
|
+
|
|
|
+ init_size = aot_module->dylink_section->table_size + export_func_count;
|
|
|
+ init_size += aot_module->dylink_section->table_alignment - 1;
|
|
|
+
|
|
|
+ // will calcuate it by instance id
|
|
|
+ init_globals.table_alignment = aot_module->dylink_section->table_alignment;
|
|
|
+
|
|
|
+ if (!aot_module->dylink_section->memory_alignment)
|
|
|
+ aot_module->dylink_section->memory_alignment = 1;
|
|
|
+
|
|
|
+ bh_assert(aot_module->dylink_section->memory_alignment > 0);
|
|
|
+ }
|
|
|
+
|
|
|
+ bh_assert(init_size <= TABLE_SPACE_SLOT_SIZE);
|
|
|
+ init_globals.table_size = init_size;
|
|
|
+ init_globals.table_base = 0;
|
|
|
+
|
|
|
+ // assumpt stack_pointer is the first global.
|
|
|
+ // if root module is opened by dlopen, global[0] should be __stack_pointer
|
|
|
+ // else if root module is a library module, its global[0] is also __stack_pointer
|
|
|
+ if (caller_module_inst->module_type == Wasm_Module_Bytecode) {
|
|
|
+ //bh_assert(((WASMModuleInstance*)caller_module_inst)->globals[0].is_mutable == true &&
|
|
|
+ // ((WASMModuleInstance*)caller_module_inst)->globals[0].type == VALUE_TYPE_I32);
|
|
|
+ } else {
|
|
|
+ AOTModule * root_aot_module = (AOTModule*)((AOTModuleInstance*)caller_module_inst)->aot_module.ptr;
|
|
|
+ (void)root_aot_module;
|
|
|
+ if (root_aot_module->dylink_section)
|
|
|
+ bh_assert(root_aot_module->import_globals[0].is_mutable == true &&
|
|
|
+ root_aot_module->import_globals[0].type == VALUE_TYPE_I32);
|
|
|
+ //else
|
|
|
+ // bh_assert(root_aot_module->globals[0].is_mutable == true &&
|
|
|
+ // root_aot_module->globals[0].type == VALUE_TYPE_I32);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!is_aot) {
|
|
|
+ init_size = wasm_module->dylink_section->memory_size + wasm_module->dylink_section->memory_alignment - 1;
|
|
|
+
|
|
|
+ offset = wasm_runtime_module_malloc((wasm_module_inst_t)root_module_inst,
|
|
|
+ init_size, &native_addr);
|
|
|
+ if (!offset)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ init_globals.actual_memory_base = offset;
|
|
|
+
|
|
|
+ init_globals.memory_base = (offset + wasm_module->dylink_section->memory_alignment - 1) &
|
|
|
+ (~(wasm_module->dylink_section->memory_alignment - 1));
|
|
|
+
|
|
|
+ new_module_inst = (WASMModuleInstanceCommon*)wasm_instantiate_dependency((WASMModule*)module, program_inst,
|
|
|
+ stack_size, &init_globals);
|
|
|
+ } else {
|
|
|
+ init_size = aot_module->dylink_section->memory_size + aot_module->dylink_section->memory_alignment - 1;
|
|
|
+ offset = wasm_runtime_module_malloc((wasm_module_inst_t)root_module_inst,
|
|
|
+ init_size, &native_addr);
|
|
|
+ if (!offset)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ init_globals.actual_memory_base = offset;
|
|
|
+
|
|
|
+ init_globals.memory_base = (offset + aot_module->dylink_section->memory_alignment - 1) &
|
|
|
+ (~(aot_module->dylink_section->memory_alignment - 1));
|
|
|
+
|
|
|
+ new_module_inst = (WASMModuleInstanceCommon*)aot_instantiate_dependency((AOTModule*)module, program_inst,
|
|
|
+ stack_size, &init_globals);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!new_module_inst)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ return new_module_inst;
|
|
|
+}
|
|
|
+
|
|
|
+WASMModuleInstanceCommon *
|
|
|
+wasm_program_open_dependencies_general(WASMRuntime * runtime,
|
|
|
+ WASMProgramInstance * program_inst,
|
|
|
+ WASMModuleInstanceCommon * caller_module_inst,
|
|
|
+ const char * path)
|
|
|
+{
|
|
|
+ const ConstStrDescription * key = NULL;
|
|
|
+ WASMModuleCommon * new_module = NULL;
|
|
|
+ WASMModuleInstanceCommon *root_module_inst = NULL, *new_module_inst = NULL;
|
|
|
+ // bh_list loading_modules_list;
|
|
|
+ //LoadingModuleElem * elem = NULL;
|
|
|
+
|
|
|
+ root_module_inst = program_inst->root_module_inst;
|
|
|
+
|
|
|
+ // records string into const string pool
|
|
|
+ key = wasm_runtime_records_const_string(
|
|
|
+ runtime, path,
|
|
|
+ strlen(path),
|
|
|
+ program_inst->error_buf,
|
|
|
+ program_inst->error_buf_size);
|
|
|
+ if (!key) {
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ // check if opened by the current program.
|
|
|
+ new_module_inst = dylib_entries_map_find(key, program_inst->global_modules_inst_name_hmap);
|
|
|
+ if (new_module_inst) {
|
|
|
+ if (new_module_inst->module_type != caller_module_inst->module_type)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ if (!wasm_runtime_is_shared_module_instance(new_module_inst)) {
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new_module_inst;
|
|
|
+ }
|
|
|
+
|
|
|
+ // start to load all dependency modules.
|
|
|
+ new_module = load_explicit_dependency_module(root_module_inst, key);
|
|
|
+
|
|
|
+ if (!new_module)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ // currently only supports wasm->wasm, aot->aot
|
|
|
+ if (new_module->module_type != caller_module_inst->module_type)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ if (!wasm_runtime_is_shared_module(new_module)) {
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ // can exit the program lock scope from here.
|
|
|
+
|
|
|
+ new_module_inst = (WASMModuleInstanceCommon*)wasm_program_instantiate_dependencies(
|
|
|
+ runtime, program_inst, (WASMModuleInstanceCommon*)caller_module_inst, new_module);
|
|
|
+ if (!new_module_inst)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ if (!dylib_entries_map_insert(key, new_module_inst,
|
|
|
+ program_inst->global_modules_inst_name_hmap))
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ return new_module_inst;
|
|
|
+}
|
|
|
+
|
|
|
+uint32
|
|
|
+wasm_program_lookup_symbol_from_module(wasm_module_inst_t caller_module,
|
|
|
+ uint32 inst_id, const char * symbol)
|
|
|
+{
|
|
|
+ WASMModuleInstanceHead * caller_module_inst_head = (WASMModuleInstanceHead *)caller_module;
|
|
|
+ WASMModuleInstanceCommon * callee_module_inst = NULL;
|
|
|
+ WASMModuleInstance * wasm_inst = NULL;
|
|
|
+ AOTModuleInstance * aot_inst = NULL;
|
|
|
+ AOTModule * aot_module = NULL;
|
|
|
+ uint32 table_slot = 0, i = 0;
|
|
|
+ void * key = NULL;
|
|
|
+
|
|
|
+ if (!caller_module_inst_head->program)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ key = (void*)(uintptr_t)inst_id;
|
|
|
+
|
|
|
+ callee_module_inst = bh_hash_map_find(caller_module_inst_head->program->global_modules_inst_id_hmap, key);
|
|
|
+ if (!callee_module_inst)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ if (callee_module_inst->module_type == Wasm_Module_Bytecode) {
|
|
|
+ wasm_inst = (WASMModuleInstance *)callee_module_inst;
|
|
|
+
|
|
|
+ for (i = 0; i < wasm_inst->export_func_count; i++) {
|
|
|
+ if (!strcmp(wasm_inst->export_functions[i].name, symbol)) {
|
|
|
+ table_slot = i;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (i == wasm_inst->export_func_count)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ table_slot += (wasm_inst->inst_id *
|
|
|
+ TABLE_SPACE_SLOT_SIZE) - wasm_inst->export_func_count;
|
|
|
+ } else {
|
|
|
+ aot_inst = (AOTModuleInstance *)callee_module_inst;
|
|
|
+ aot_module = (AOTModule*)aot_inst->aot_module.ptr;
|
|
|
+
|
|
|
+ for (i = 0; i < aot_module->export_func_count; i++) {
|
|
|
+ if (!strcmp(((AOTExportFunctionInstance*)aot_inst->export_funcs.ptr)[i].func_name, symbol)) {
|
|
|
+ table_slot = i;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (i == aot_module->export_func_count)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ table_slot += (aot_inst->inst_id *
|
|
|
+ TABLE_SPACE_SLOT_SIZE) - aot_module->export_func_count;
|
|
|
+ }
|
|
|
+
|
|
|
+ return table_slot;
|
|
|
+}
|
|
|
+
|
|
|
+bool
|
|
|
+wasm_program_resolve_aot_function(WASMProgramInstance * program,
|
|
|
+ AOTModuleInstance * resolve_module_inst,
|
|
|
+ AOTModuleInstance ** p_callee_module_inst,
|
|
|
+ uint32 import_func_id)
|
|
|
+{
|
|
|
+ WASMRuntime * runtime = resolve_module_inst->runtime;
|
|
|
+ const ConstStrDescription * module_name = NULL, * func_name = NULL;
|
|
|
+ AOTModule * module = resolve_module_inst->aot_module.ptr;
|
|
|
+ AOTModule * callee_module = NULL;
|
|
|
+ AOTImportFunc * import_func = &module->import_funcs[import_func_id];
|
|
|
+ AOTFuncType * cur_type = NULL, *cur_func_type = NULL;
|
|
|
+ AOTModuleInstance *caller_module_inst = resolve_module_inst, *callee_module_inst = NULL;
|
|
|
+ AOTExportFunctionInstance * export_funcs = NULL, *callee_function_inst = NULL;
|
|
|
+ uint32 i = 0;
|
|
|
+ bool resolve_memop_func = false;
|
|
|
+
|
|
|
+ cur_type = import_func->func_type;
|
|
|
+
|
|
|
+ while(1) {
|
|
|
+ resolve_memop_func = false;
|
|
|
+ module_name = import_func->module_name;
|
|
|
+ func_name = import_func->func_name;
|
|
|
+
|
|
|
+ if (module_name == CONST_STR_POOL_DESC(runtime, WAMR_CSP_env) &&
|
|
|
+ (program->config.import_memop_mode != FROM_ROOT ||
|
|
|
+ !wasm_runtime_is_memop_symbol(runtime, func_name))) {
|
|
|
+ *p_callee_module_inst = caller_module_inst;
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (module_name == CONST_STR_POOL_DESC(runtime, WAMR_CSP_env)) {
|
|
|
+ resolve_memop_func = true;
|
|
|
+ bh_assert(caller_module_inst != (AOTModuleInstance*)program->root_module_inst);
|
|
|
+ callee_module_inst = (AOTModuleInstance*)program->root_module_inst;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!callee_module_inst) {
|
|
|
+ module_name = upgrade_module_extension(runtime,
|
|
|
+ module_name, Wasm_Module_AoT, program->error_buf, program->error_buf_size);
|
|
|
+
|
|
|
+ callee_module_inst = (AOTModuleInstance*)wasm_program_get_module_inst_by_name(program, module_name);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!callee_module_inst) {
|
|
|
+ callee_module = (AOTModule*)wasm_runtime_get_module_by_name(runtime, module_name);
|
|
|
+
|
|
|
+ if (!callee_module) {
|
|
|
+ aot_set_exception_with_id(caller_module_inst, EXEC_CALL_UNLINKED_MODULE);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ callee_module_inst = (AOTModuleInstance*)wasm_program_instantiate_dependencies(runtime,
|
|
|
+ program, (WASMModuleInstanceCommon*)caller_module_inst, (WASMModuleCommon*)callee_module);
|
|
|
+
|
|
|
+ if (!callee_module_inst) {
|
|
|
+ aot_set_exception_with_id(caller_module_inst, EXEC_CALL_UNLINKED_MODULE);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!bh_hash_map_insert_with_dup(program->global_modules_inst_name_hmap,
|
|
|
+ (void*)module_name, (void*)callee_module_inst)) {
|
|
|
+ aot_set_exception_with_id(caller_module_inst, EXEC_CALL_UNLINKED_MODULE);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!resolve_memop_func) {
|
|
|
+ if (!caller_module_inst->local_implicit_dependency_modules_name_hmap) {
|
|
|
+ caller_module_inst->local_implicit_dependency_modules_name_hmap =
|
|
|
+ bh_hash_map_create(8, false,
|
|
|
+ (HashFunc)const_str_hash,
|
|
|
+ (KeyEqualFunc)const_str_equal,
|
|
|
+ NULL,
|
|
|
+ NULL);
|
|
|
+ if (!caller_module_inst->local_implicit_dependency_modules_name_hmap) {
|
|
|
+ aot_set_exception_with_id(caller_module_inst, EXEC_CALL_UNLINKED_MODULE);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!bh_hash_map_insert(caller_module_inst->local_implicit_dependency_modules_name_hmap,
|
|
|
+ (void*)module_name, (void*)callee_module_inst)) {
|
|
|
+ aot_set_exception_with_id(caller_module_inst, EXEC_CALL_UNLINKED_MODULE);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ callee_module_inst->imp_ref_cnt ++;
|
|
|
+ } else {
|
|
|
+ if (!bh_hash_map_find(caller_module_inst->local_implicit_dependency_modules_name_hmap,
|
|
|
+ (void*)module_name)) {
|
|
|
+ if (!bh_hash_map_insert(caller_module_inst->local_implicit_dependency_modules_name_hmap,
|
|
|
+ (void*)module_name, (void*)callee_module_inst)) {
|
|
|
+ aot_set_exception_with_id(caller_module_inst, EXEC_CALL_UNLINKED_MODULE);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ callee_module_inst->imp_ref_cnt ++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //printf("module %s, exp ref = %d, imp ref = %d\n",
|
|
|
+ // module_name->str,
|
|
|
+ // callee_module_inst->exp_ref_cnt,
|
|
|
+ // callee_module_inst->imp_ref_cnt);
|
|
|
+
|
|
|
+ export_funcs = (AOTExportFunctionInstance*)callee_module_inst->export_funcs.ptr;
|
|
|
+ if (!callee_module)
|
|
|
+ callee_module = (AOTModule*)callee_module_inst->aot_module.ptr;
|
|
|
+
|
|
|
+ for (i = 0; i < callee_module->export_func_count; i++) {
|
|
|
+ if (!strcmp(export_funcs[i].func_name, import_func->func_name->str)) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (i == callee_module->export_func_count) {
|
|
|
+ aot_set_exception_with_id(caller_module_inst, EXCE_CALL_UNLINKED_IMPORT_FUNC);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ callee_function_inst = &export_funcs[i];
|
|
|
+
|
|
|
+ if (callee_function_inst->is_import_func)
|
|
|
+ cur_func_type = callee_function_inst->u.func_import->func_type;
|
|
|
+ else
|
|
|
+ cur_func_type = callee_function_inst->u.func.func_type;
|
|
|
+ if (!wasm_type_equal(cur_type, cur_func_type)) {
|
|
|
+ aot_set_exception_with_id(caller_module_inst, EXCE_INVALID_FUNCTION_TYPE_INDEX);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!callee_function_inst->is_import_func)
|
|
|
+ break;
|
|
|
+
|
|
|
+ if (callee_function_inst->u.func_import->func_ptr_linked)
|
|
|
+ break;
|
|
|
+
|
|
|
+ caller_module_inst = callee_module_inst;
|
|
|
+ import_func = callee_function_inst->u.func_import;
|
|
|
+ }
|
|
|
+
|
|
|
+ ((void**)resolve_module_inst->func_ptrs.ptr)[import_func_id] = callee_function_inst->u.func.func_ptr;
|
|
|
+ *p_callee_module_inst = callee_module_inst;
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+// TODO: the resolve algorithm need to improved to update the resolving result for other intermediate modules.
|
|
|
+static bool
|
|
|
+wasm_program_resolve_wasm_function(WASMProgramInstance * program,
|
|
|
+ WASMModuleInstance * caller_module_inst,
|
|
|
+ WASMFunctionInstance * import_func)
|
|
|
+{
|
|
|
+ WASMModule * callee_module = NULL;
|
|
|
+ const ConstStrDescription * module_name = NULL, *func_name = NULL;
|
|
|
+ WASMModuleInstance * callee_module_inst = NULL;
|
|
|
+ WASMFunctionInstance * callee_function_inst = NULL;
|
|
|
+ WASMRuntime * runtime = caller_module_inst->runtime;
|
|
|
+ WASMType *cur_type = NULL, *cur_func_type = NULL;
|
|
|
+ bool resolve_memop_func = false;
|
|
|
+
|
|
|
+ uint32 i = 0;
|
|
|
+ if (!import_func->is_import_func)
|
|
|
+ return true;
|
|
|
+
|
|
|
+ callee_function_inst = import_func;
|
|
|
+ cur_type = callee_function_inst->u.func_import->func_type;
|
|
|
+
|
|
|
+ while (1) {
|
|
|
+ resolve_memop_func = false;
|
|
|
+ module_name = callee_function_inst->u.func_import->module_name;
|
|
|
+ func_name = callee_function_inst->u.func_import->field_name;
|
|
|
+ if (module_name == CONST_STR_POOL_DESC(runtime, WAMR_CSP_env) &&
|
|
|
+ (program->config.import_memop_mode != FROM_ROOT ||
|
|
|
+ !wasm_runtime_is_memop_symbol(runtime, func_name))) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (module_name == CONST_STR_POOL_DESC(runtime, WAMR_CSP_env)) {
|
|
|
+ resolve_memop_func = true;
|
|
|
+ bh_assert(caller_module_inst != (WASMModuleInstance*)program->root_module_inst);
|
|
|
+ callee_module_inst = (WASMModuleInstance*)program->root_module_inst;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!callee_module_inst)
|
|
|
+ callee_module_inst = (WASMModuleInstance*)wasm_program_get_module_inst_by_name(program, module_name);
|
|
|
+
|
|
|
+ if (!callee_module_inst) {
|
|
|
+ callee_module = (WASMModule*)wasm_runtime_get_module_by_name(runtime, module_name);
|
|
|
+ if (!callee_module)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ callee_module_inst = (WASMModuleInstance*)wasm_program_instantiate_dependencies(runtime,
|
|
|
+ program, (WASMModuleInstanceCommon*)caller_module_inst, (WASMModuleCommon*)callee_module);
|
|
|
+
|
|
|
+ if (!callee_module_inst)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ if (!bh_hash_map_insert_with_dup(program->global_modules_inst_name_hmap,
|
|
|
+ (void*)module_name, (void*)callee_module_inst))
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!resolve_memop_func) {
|
|
|
+ if (!caller_module_inst->local_implicit_dependency_modules_name_hmap) {
|
|
|
+ caller_module_inst->local_implicit_dependency_modules_name_hmap =
|
|
|
+ bh_hash_map_create(8, false,
|
|
|
+ (HashFunc)const_str_hash,
|
|
|
+ (KeyEqualFunc)const_str_equal,
|
|
|
+ NULL,
|
|
|
+ NULL);
|
|
|
+ if (!caller_module_inst->local_implicit_dependency_modules_name_hmap)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ if (!bh_hash_map_insert(caller_module_inst->local_implicit_dependency_modules_name_hmap,
|
|
|
+ (void*)module_name, (void*)callee_module_inst))
|
|
|
+ return false;
|
|
|
+
|
|
|
+ callee_module_inst->imp_ref_cnt ++;
|
|
|
+ } else {
|
|
|
+ if (!bh_hash_map_find(caller_module_inst->local_implicit_dependency_modules_name_hmap,
|
|
|
+ (void*)module_name)) {
|
|
|
+ if (!bh_hash_map_insert(caller_module_inst->local_implicit_dependency_modules_name_hmap,
|
|
|
+ (void*)module_name, (void*)callee_module_inst))
|
|
|
+ return false;
|
|
|
+
|
|
|
+ callee_module_inst->imp_ref_cnt ++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //printf("module %s, exp ref = %d, imp ref = %d\n",
|
|
|
+ // callee_module_inst->module->module_name->str,
|
|
|
+ // callee_module_inst->exp_ref_cnt,
|
|
|
+ // callee_module_inst->imp_ref_cnt);
|
|
|
+#if 0
|
|
|
+ if (program->config.root_is_AS_module) {
|
|
|
+ if (func_name == CONST_STR_POOL_DESC(runtime, WAMR_CSP_malloc))
|
|
|
+ func_name = CONST_STR_POOL_DESC(runtime, WAMR_CSP___alloc);
|
|
|
+ else if (func_name == CONST_STR_POOL_DESC(runtime, WAMR_CSP_free))
|
|
|
+ func_name = CONST_STR_POOL_DESC(runtime, WAMR_CSP___free);
|
|
|
+ else if (func_name == CONST_STR_POOL_DESC(runtime, WAMR_CSP_realloc))
|
|
|
+ func_name = CONST_STR_POOL_DESC(runtime, WAMR_CSP___realloc);
|
|
|
+ }
|
|
|
+#endif
|
|
|
+ for (i = 0; i < callee_module_inst->export_func_count; i++) {
|
|
|
+ if (!strcmp(callee_module_inst->export_functions[i].name, func_name->str)) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (i == callee_module_inst->export_func_count) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ callee_function_inst = callee_module_inst->export_functions[i].function;
|
|
|
+
|
|
|
+ if (callee_function_inst->is_import_func)
|
|
|
+ cur_func_type = callee_function_inst->u.func_import->func_type;
|
|
|
+ else
|
|
|
+ cur_func_type = callee_function_inst->u.func->func_type;
|
|
|
+ if (!wasm_type_equal(cur_type, cur_func_type)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!callee_function_inst->is_import_func)
|
|
|
+ break;
|
|
|
+
|
|
|
+ if (callee_function_inst->u.func_import->func_ptr_linked)
|
|
|
+ break;
|
|
|
+
|
|
|
+ caller_module_inst = callee_module_inst;
|
|
|
+ }
|
|
|
+
|
|
|
+ import_func->import_module_inst = callee_module_inst;
|
|
|
+ import_func->import_func_inst = callee_function_inst;
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+bool
|
|
|
+wasm_program_resolve_op_call(WASMProgramInstance * program,
|
|
|
+ WASMModuleInstance * caller_module_inst,
|
|
|
+ WASMModuleInstance ** p_callee_module_inst,
|
|
|
+ WASMFunctionInstance ** p_call_func)
|
|
|
+{
|
|
|
+ WASMModuleInstance * callee_module_inst = NULL;
|
|
|
+ WASMFunctionInstance * call_func = *p_call_func;
|
|
|
+
|
|
|
+ // lazy link, resolve the import function.
|
|
|
+ if (program &&
|
|
|
+ //caller_module_inst != (WASMModuleInstance*)program->root_module_inst &&
|
|
|
+ call_func->is_import_func &&
|
|
|
+ !call_func->u.func_import->func_ptr_linked) {
|
|
|
+
|
|
|
+ if (!call_func->import_module_inst &&
|
|
|
+ !call_func->import_func_inst) {
|
|
|
+ if (program->config.binding_mode != LAZY_BINDING) {
|
|
|
+ wasm_set_exception(caller_module_inst, "uninitialized import function.");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!wasm_program_resolve_wasm_function(program, caller_module_inst, call_func)) {
|
|
|
+ char buf[128];
|
|
|
+ snprintf(buf, sizeof(buf),
|
|
|
+ "failed to call unlinked import function (%s, %s)",
|
|
|
+ (char*)call_func->u.func_import->module_name->str,
|
|
|
+ (char*)call_func->u.func_import->field_name->str);
|
|
|
+ wasm_set_exception(caller_module_inst, buf);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ callee_module_inst = call_func->import_module_inst;
|
|
|
+ call_func = call_func->import_func_inst;
|
|
|
+
|
|
|
+ *p_callee_module_inst = callee_module_inst;
|
|
|
+ *p_call_func = call_func;
|
|
|
+ }
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+uint32
|
|
|
+wasm_program_alloc_table_space_by_size(uint32 inst_id,
|
|
|
+ uint32 needed_size)
|
|
|
+{
|
|
|
+ uint32 table_space_start = 0;
|
|
|
+
|
|
|
+ bh_assert(needed_size <= TABLE_SPACE_SLOT_SIZE);
|
|
|
+ table_space_start = ((inst_id - 1)<< TABLE_SPACE_BITS_LEN);
|
|
|
+
|
|
|
+ return table_space_start;
|
|
|
+}
|
|
|
+
|
|
|
+uint32
|
|
|
+wasm_program_alloc_table_space_by_table(WASMModuleInstance * module_inst,
|
|
|
+ WASMTableInstance * table)
|
|
|
+{
|
|
|
+ uint32 needed_size = table->max_size;
|
|
|
+ uint32 inst_id = module_inst->inst_id;
|
|
|
+
|
|
|
+ return wasm_program_alloc_table_space_by_size(inst_id, needed_size);
|
|
|
+}
|
|
|
+
|
|
|
+#if WASM_ENABLE_LIBC_BUILTIN != 0
|
|
|
+uint32
|
|
|
+get_libc_builtin_export_apis(NativeSymbol **p_libc_builtin_apis);
|
|
|
+
|
|
|
+#define BUILTIN_FUNC_ALLOC_STEP 4
|
|
|
+// create an internal libc module, but not create func instance until link GOT.func global
|
|
|
+static int
|
|
|
+wasm_program_link_internal_builtin_libc_func(WASMProgramInstance * program, const ConstStrDescription * func_name)
|
|
|
+{
|
|
|
+ WASMRuntime * runtime = program->runtime;
|
|
|
+ WASMFunctionInstance ** functions = (WASMFunctionInstance**)program->builtin_libc_funcs, *linked_func = NULL;
|
|
|
+ WASMFunctionImport * func_import = NULL;
|
|
|
+ NativeSymbol * native_symbols = NULL;
|
|
|
+ uint32 i = 0, func_id = 0, func_offset = 0;
|
|
|
+ int32 ret_id = -1;
|
|
|
+ uint32 libc_funcs_count = get_libc_builtin_export_apis(&native_symbols);
|
|
|
+
|
|
|
+ (void)(libc_funcs_count);
|
|
|
+
|
|
|
+ if (!functions) {
|
|
|
+ functions = wasm_runtime_malloc(sizeof(WASMFunctionInstance *) * BUILTIN_FUNC_ALLOC_STEP);
|
|
|
+ if (!functions)
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ program->builtin_libc_funcs = (void**)functions;
|
|
|
+ program->builtin_libc_funcs_size = BUILTIN_FUNC_ALLOC_STEP;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (i = 0; i < program->builtin_libc_funcs_count; i ++) {
|
|
|
+ if (func_name == functions[i]->u.func_import->field_name)
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (i < program->builtin_libc_funcs_count) {
|
|
|
+ return i;
|
|
|
+ }
|
|
|
+
|
|
|
+ func_id = wasm_runtime_get_syssymbol_id(runtime, func_name);
|
|
|
+ if (func_id < WAMR_CSP_iprintf ||
|
|
|
+ func_id > WAMR_CSP_dlclose)
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ func_import = wasm_runtime_malloc(sizeof(WASMFunctionImport));
|
|
|
+ if (!func_import)
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ linked_func = wasm_runtime_malloc(sizeof(WASMFunctionInstance));
|
|
|
+ if (!linked_func) {
|
|
|
+ wasm_runtime_free(func_import);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ memset(func_import, 0, sizeof(WASMFunctionImport));
|
|
|
+ memset(linked_func, 0, sizeof(WASMFunctionInstance));
|
|
|
+
|
|
|
+ func_offset = func_id - WAMR_CSP_iprintf;
|
|
|
+
|
|
|
+ bh_assert(func_name == native_symbols[func_offset].u.symbol);
|
|
|
+ func_import->module_name = CONST_STR_POOL_DESC(runtime, WAMR_CSP_env);
|
|
|
+ func_import->field_name = func_name;
|
|
|
+ func_import->signature = native_symbols[func_offset].signature;
|
|
|
+ func_import->func_type = NULL;
|
|
|
+ func_import->attachment = native_symbols[func_offset].attachment;
|
|
|
+ func_import->call_conv_raw = false;
|
|
|
+ func_import->call_conv_wasm_c_api = false;
|
|
|
+ func_import->wasm_c_api_with_env = false;
|
|
|
+ func_import->func_ptr_linked = native_symbols[func_offset].func_ptr;
|
|
|
+
|
|
|
+ linked_func->is_import_func = true;
|
|
|
+ linked_func->func_type = NULL;
|
|
|
+ linked_func->local_count = 0;
|
|
|
+ linked_func->local_cell_num = 0;
|
|
|
+#if WASM_ENABLE_FAST_INTERP != 0
|
|
|
+ linked_func->const_cell_num = 0;
|
|
|
+#endif
|
|
|
+ linked_func->local_offsets = 0;
|
|
|
+ linked_func->local_types = NULL;
|
|
|
+ linked_func->u.func_import = func_import;
|
|
|
+
|
|
|
+ if ((program->builtin_libc_funcs_count + 1) > program->builtin_libc_funcs_size) {
|
|
|
+ functions = wasm_runtime_realloc(functions,
|
|
|
+ sizeof(WASMFunctionInstance *) * (program->builtin_libc_funcs_size + BUILTIN_FUNC_ALLOC_STEP));
|
|
|
+ if (!functions) {
|
|
|
+ wasm_runtime_free(func_import);
|
|
|
+ wasm_runtime_free(linked_func);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ program->builtin_libc_funcs_size += BUILTIN_FUNC_ALLOC_STEP;
|
|
|
+ program->builtin_libc_funcs = (void**)functions;
|
|
|
+ }
|
|
|
+
|
|
|
+ functions[program->builtin_libc_funcs_count] = linked_func;
|
|
|
+
|
|
|
+ ret_id = program->builtin_libc_funcs_count;
|
|
|
+ program->builtin_libc_funcs_count ++;
|
|
|
+ return ret_id;
|
|
|
+}
|
|
|
+
|
|
|
+#if WASM_ENABLE_AOT != 0
|
|
|
+static int
|
|
|
+wasm_program_link_aot_internal_builtin_libc_func(WASMProgramInstance * program, const ConstStrDescription * func_name)
|
|
|
+{
|
|
|
+ WASMRuntime * runtime = program->runtime;
|
|
|
+ AOTExportFunctionInstance ** functions = (AOTExportFunctionInstance **)program->builtin_libc_funcs, *linked_func = NULL;
|
|
|
+ AOTImportFunc * func_import = NULL;
|
|
|
+ NativeSymbol * native_symbols = NULL;
|
|
|
+ uint32 i = 0, func_id = 0, func_offset = 0;
|
|
|
+ int32 ret_id = -1;
|
|
|
+ uint32 libc_funcs_count = get_libc_builtin_export_apis(&native_symbols);
|
|
|
+
|
|
|
+ (void)(libc_funcs_count);
|
|
|
+
|
|
|
+ if (!functions) {
|
|
|
+ functions = wasm_runtime_malloc(sizeof(AOTExportFunctionInstance *) * BUILTIN_FUNC_ALLOC_STEP);
|
|
|
+ if (!functions)
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ program->builtin_libc_funcs = (void**)functions;
|
|
|
+ program->builtin_libc_funcs_size = BUILTIN_FUNC_ALLOC_STEP;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (i = 0; i < program->builtin_libc_funcs_count; i ++) {
|
|
|
+ if (func_name == functions[i]->u.func_import->func_name)
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (i < program->builtin_libc_funcs_count) {
|
|
|
+ return i;
|
|
|
+ }
|
|
|
+
|
|
|
+ func_id = wasm_runtime_get_syssymbol_id(runtime, func_name);
|
|
|
+ if (func_id < WAMR_CSP_iprintf ||
|
|
|
+ func_id > WAMR_CSP_dlclose)
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ func_import = wasm_runtime_malloc(sizeof(AOTImportFunc));
|
|
|
+ if (!func_import)
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ linked_func = wasm_runtime_malloc(sizeof(AOTExportFunctionInstance));
|
|
|
+ if (!linked_func) {
|
|
|
+ wasm_runtime_free(func_import);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ memset(func_import, 0, sizeof(AOTImportFunc));
|
|
|
+ memset(linked_func, 0, sizeof(AOTExportFunctionInstance));
|
|
|
+
|
|
|
+ func_offset = func_id - WAMR_CSP_iprintf;
|
|
|
+
|
|
|
+ bh_assert(func_name == native_symbols[func_offset].u.symbol);
|
|
|
+ func_import->module_name = CONST_STR_POOL_DESC(runtime, WAMR_CSP_env);
|
|
|
+ func_import->func_name = func_name;
|
|
|
+ func_import->signature = native_symbols[func_offset].signature;
|
|
|
+ func_import->func_type = NULL;
|
|
|
+ func_import->func_type_index = 0;
|
|
|
+ func_import->attachment = native_symbols[func_offset].attachment;
|
|
|
+ func_import->call_conv_raw = false;
|
|
|
+ func_import->call_conv_wasm_c_api = false;
|
|
|
+ func_import->wasm_c_api_with_env = false;
|
|
|
+ func_import->func_ptr_linked = native_symbols[func_offset].func_ptr;
|
|
|
+
|
|
|
+ linked_func->is_import_func = true;
|
|
|
+ linked_func->u.func_import = func_import;
|
|
|
+ linked_func->func_index = 0;
|
|
|
+
|
|
|
+ if ((program->builtin_libc_funcs_count + 1) > program->builtin_libc_funcs_size) {
|
|
|
+ functions = wasm_runtime_realloc(functions,
|
|
|
+ sizeof(WASMFunctionInstance *) * (program->builtin_libc_funcs_size + BUILTIN_FUNC_ALLOC_STEP));
|
|
|
+ if (!functions) {
|
|
|
+ wasm_runtime_free(func_import);
|
|
|
+ wasm_runtime_free(linked_func);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ program->builtin_libc_funcs_size += BUILTIN_FUNC_ALLOC_STEP;
|
|
|
+ program->builtin_libc_funcs = (void**)functions;
|
|
|
+ }
|
|
|
+
|
|
|
+ functions[program->builtin_libc_funcs_count] = linked_func;
|
|
|
+
|
|
|
+ ret_id = program->builtin_libc_funcs_count;
|
|
|
+ program->builtin_libc_funcs_count ++;
|
|
|
+ return ret_id;
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
+#undef BUILTIN_FUNC_ALLOC_STEP
|
|
|
+
|
|
|
+static void
|
|
|
+wasm_program_destroy_internal_libc_module(WASMProgramInstance * program)
|
|
|
+{
|
|
|
+ if (!program->builtin_libc_funcs)
|
|
|
+ return;
|
|
|
+
|
|
|
+ for(uint32 i = 0; i < program->builtin_libc_funcs_count; i++) {
|
|
|
+ if (!program->builtin_libc_funcs[i])
|
|
|
+ continue;
|
|
|
+
|
|
|
+ //WASMFunctionImport * func_import = program->builtin_libc_funcs[i]->u.func_import;
|
|
|
+ //if (func_import)
|
|
|
+ // wasm_runtime_free(func_import);
|
|
|
+
|
|
|
+ wasm_runtime_free(program->builtin_libc_funcs[i]);
|
|
|
+ }
|
|
|
+ wasm_runtime_free(program->builtin_libc_funcs);
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
+
|
|
|
+bool
|
|
|
+wasm_program_link_sp_wasm_globals(WASMProgramInstance * program,
|
|
|
+ WASMGlobalInstance * global,
|
|
|
+ const ConstStrDescription * field_name)
|
|
|
+{
|
|
|
+ WASMRuntime * runtime = program->runtime;
|
|
|
+ WASMModuleInstance * root_module_inst = (WASMModuleInstance *)program->root_module_inst;
|
|
|
+ WASMGlobalInstance * export_global = NULL;
|
|
|
+ (void)runtime;
|
|
|
+
|
|
|
+ for (uint32 i = 0; i < root_module_inst->export_glob_count; i++) {
|
|
|
+ if (!program->config.root_is_AS_module) {
|
|
|
+ if (!strcmp(root_module_inst->export_globals[i].name, field_name->str)) {
|
|
|
+ export_global = root_module_inst->export_globals[i].global;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if (!strcmp(root_module_inst->export_globals[i].name, CONST_STR_POOL_STR(runtime, WAMR_CSP_var_user_stack_pointer))) {
|
|
|
+ export_global = root_module_inst->export_globals[i].global;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!export_global)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ if (export_global->type != global->type ||
|
|
|
+ export_global->is_mutable != global->is_mutable)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ // global->data_offset = root_module_inst->globals->data_offset;
|
|
|
+ if (export_global->is_mutable)
|
|
|
+ global->data = export_global->data;
|
|
|
+ else {
|
|
|
+ global->data = (uint8*)&root_module_inst->init_globals.stack_pointer;
|
|
|
+ }
|
|
|
+
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+#if WASM_ENABLE_AOT != 0
|
|
|
+bool
|
|
|
+wasm_program_link_sp_aot_globals(WASMProgramInstance * program,
|
|
|
+ uint8 * p_global_data,
|
|
|
+ const ConstStrDescription * global_name)
|
|
|
+{
|
|
|
+ WASMRuntime * runtime = program->runtime;
|
|
|
+ AOTModuleInstance * root_module_inst = (AOTModuleInstance *)program->root_module_inst;
|
|
|
+ AOTModule * root_module = (AOTModule *)root_module_inst->aot_module.ptr;
|
|
|
+ uint32 global_id = 0, global_offset = 0;
|
|
|
+ uint8 * p_data = NULL;
|
|
|
+
|
|
|
+ if (root_module->export_sp_global_id >= root_module->export_count)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ if (!program->config.root_is_AS_module) {
|
|
|
+ if (strcmp(root_module->exports[root_module->export_sp_global_id].name, global_name->str)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if (strcmp(root_module->exports[root_module->export_sp_global_id].name, CONST_STR_POOL_STR(runtime, WAMR_CSP_var_user_stack_pointer))) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ global_id = root_module->exports[root_module->export_sp_global_id].index;
|
|
|
+
|
|
|
+ global_offset = root_module->globals[global_id].data_offset;
|
|
|
+
|
|
|
+ p_data = (uint8*)root_module_inst->global_data.ptr + global_offset;
|
|
|
+
|
|
|
+#if __WORDSIZE == 32
|
|
|
+ if (root_module->dylink_section)
|
|
|
+ *(uint32*)p_global_data = *(uint32*)p_data;
|
|
|
+ else
|
|
|
+ *(uint32*)p_global_data = (uintptr_t)p_data;
|
|
|
+#else
|
|
|
+ if (root_module->dylink_section)
|
|
|
+ *(uint64*)p_global_data = *(uint64*)p_data;
|
|
|
+ else
|
|
|
+ *(uint64*)p_global_data = (uintptr_t)p_data;
|
|
|
+#endif
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+bool
|
|
|
+wasm_program_link_aot_got_globals(WASMProgramInstance * program,
|
|
|
+ AOTModuleInstance * module_inst,
|
|
|
+ uint8 * p_global_data,
|
|
|
+ const ConstStrDescription * field_name)
|
|
|
+{
|
|
|
+ WASMRuntime * runtime = program->runtime;
|
|
|
+ AOTModuleInstance * root_module_inst = NULL;
|
|
|
+ AOTModule * root_module = NULL;
|
|
|
+ bool is_sys_symbol = wasm_runtime_is_system_symbol(runtime, field_name);
|
|
|
+ bool is_memop_symbol = wasm_runtime_is_memop_symbol(runtime, field_name);
|
|
|
+ int32 import_func_id = -1;
|
|
|
+ uint32 i = 0;
|
|
|
+
|
|
|
+ if (is_sys_symbol &&
|
|
|
+ (!is_memop_symbol ||
|
|
|
+ program->config.import_memop_mode == FROM_BUILTIN_LIBC)) {
|
|
|
+#if WASM_ENABLE_LIBC_BUILTIN != 0
|
|
|
+ import_func_id = wasm_program_link_aot_internal_builtin_libc_func(program, field_name);
|
|
|
+ if (import_func_id < 0) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ *(uint32*)p_global_data = import_func_id + TABLE_SPACE_FOR_BUILTIN_LIBC;
|
|
|
+ return true;
|
|
|
+#else
|
|
|
+ return false;
|
|
|
+#endif
|
|
|
+ }
|
|
|
+
|
|
|
+ if (is_memop_symbol) {
|
|
|
+ bh_assert(program->config.import_memop_mode == FROM_ROOT);
|
|
|
+ root_module_inst = (AOTModuleInstance*)program->root_module_inst;
|
|
|
+ root_module = (AOTModule*)root_module_inst->aot_module.ptr;
|
|
|
+
|
|
|
+ AOTExportFunctionInstance * export_funcs = (AOTExportFunctionInstance *)root_module_inst->export_funcs.ptr;
|
|
|
+
|
|
|
+ for (i = 0; i < root_module->export_func_count; i++) {
|
|
|
+ if (!strcmp(export_funcs[i].func_name, field_name->str)) {
|
|
|
+ import_func_id = (int32)i;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (import_func_id == -1)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ import_func_id += TABLE_SPACE_SLOT_SIZE - root_module->export_func_count;
|
|
|
+ *(uint32*)p_global_data = import_func_id;
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ // not sys symbol
|
|
|
+ // other module's export
|
|
|
+ return false;
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
+
|
|
|
+bool
|
|
|
+wasm_program_link_got_globals(WASMProgramInstance * program,
|
|
|
+ WASMModuleInstance * module_inst,
|
|
|
+ WASMGlobalInstance * global,
|
|
|
+ const ConstStrDescription * field_name)
|
|
|
+{
|
|
|
+ WASMRuntime * runtime = program->runtime;
|
|
|
+// WASMModule * wasm_module = module_inst->module;
|
|
|
+// uint32 import_func_count = wasm_module->import_function_count;
|
|
|
+ int32 import_func_id = -1;
|
|
|
+ uint32 i = 0;
|
|
|
+ WASMModuleInstance * root_module_inst = NULL;
|
|
|
+ bool is_sys_symbol = wasm_runtime_is_system_symbol(runtime, field_name);
|
|
|
+ bool is_memop_symbol = wasm_runtime_is_memop_symbol(runtime, field_name);
|
|
|
+
|
|
|
+ if (is_sys_symbol &&
|
|
|
+ (!is_memop_symbol ||
|
|
|
+ program->config.import_memop_mode == FROM_BUILTIN_LIBC)) {
|
|
|
+#if WASM_ENABLE_LIBC_BUILTIN != 0
|
|
|
+ import_func_id = wasm_program_link_internal_builtin_libc_func(program, field_name);
|
|
|
+ if (import_func_id < 0) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ global->initial_value.u32 = import_func_id + TABLE_SPACE_FOR_BUILTIN_LIBC;
|
|
|
+ return true;
|
|
|
+#else
|
|
|
+ return false;
|
|
|
+#endif
|
|
|
+ }
|
|
|
+
|
|
|
+ if (is_memop_symbol) {
|
|
|
+ bh_assert(program->config.import_memop_mode == FROM_ROOT);
|
|
|
+ root_module_inst = (WASMModuleInstance*)program->root_module_inst;
|
|
|
+#if 0
|
|
|
+ if (program->config.root_is_AS_module) {
|
|
|
+ if (field_name == CONST_STR_POOL_DESC(runtime, WAMR_CSP_malloc))
|
|
|
+ field_name = CONST_STR_POOL_DESC(runtime, WAMR_CSP___alloc);
|
|
|
+ else if (field_name == CONST_STR_POOL_DESC(runtime, WAMR_CSP_free))
|
|
|
+ field_name = CONST_STR_POOL_DESC(runtime, WAMR_CSP___free);
|
|
|
+ else if (field_name == CONST_STR_POOL_DESC(runtime, WAMR_CSP_realloc))
|
|
|
+ field_name = CONST_STR_POOL_DESC(runtime, WAMR_CSP___realloc);
|
|
|
+ }
|
|
|
+#endif
|
|
|
+ for (i = 0; i < root_module_inst->export_func_count; i++) {
|
|
|
+ if (!strcmp(root_module_inst->export_functions[i].name, field_name->str)) {
|
|
|
+ import_func_id = (int32)i;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (import_func_id == -1)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ import_func_id += TABLE_SPACE_SLOT_SIZE - root_module_inst->export_func_count;
|
|
|
+ global->initial_value.u32 = import_func_id;
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ // not sys symbol
|
|
|
+ // other module's export
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+bool
|
|
|
+check_symbol_signature(const WASMType *type, const char *signature);
|
|
|
+
|
|
|
+bool
|
|
|
+wasm_program_resolve_op_call_indirect(WASMProgramInstance * program,
|
|
|
+ WASMModuleInstance * module_inst,
|
|
|
+ uint32 tbl_idx,
|
|
|
+ int32 tbl_slot_id,
|
|
|
+ WASMType * func_type,
|
|
|
+ WASMModuleInstance ** p_callee_module_inst,
|
|
|
+ WASMFunctionInstance ** p_call_func)
|
|
|
+{
|
|
|
+ uint32 inst_idx = 0, fidx = 0, export_func_id = 0;
|
|
|
+ WASMModuleInstance * callee_module_inst = NULL;
|
|
|
+ WASMFunctionInstance * call_func = NULL;
|
|
|
+ WASMTableInstance * tbl_inst = NULL;
|
|
|
+ WASMType * cur_func_type = NULL;
|
|
|
+ int32 origin_slot_id = 0;
|
|
|
+ bool is_local_func = true;
|
|
|
+
|
|
|
+ if (tbl_slot_id < 0) {
|
|
|
+ wasm_set_exception(module_inst, "undefined element");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ inst_idx = (tbl_slot_id >> TABLE_SPACE_BITS_LEN) + 1;
|
|
|
+ origin_slot_id = tbl_slot_id;
|
|
|
+
|
|
|
+ if (program) {
|
|
|
+ // set --enable-dlopen
|
|
|
+ if (inst_idx == module_inst->inst_id) { // call self-module
|
|
|
+ callee_module_inst = module_inst;
|
|
|
+
|
|
|
+ tbl_slot_id -= (inst_idx - 1) * TABLE_SPACE_SLOT_SIZE;
|
|
|
+ tbl_inst = wasm_get_table_inst(callee_module_inst, tbl_idx);
|
|
|
+ } else if (inst_idx == BUILTIN_LIBC_INST_ID) { // call libc function pointer
|
|
|
+ is_local_func = false;
|
|
|
+ fidx = tbl_slot_id - (inst_idx - 1) * TABLE_SPACE_SLOT_SIZE;
|
|
|
+ if (fidx >= program->builtin_libc_funcs_count) {
|
|
|
+ wasm_set_exception(module_inst, "undefined element");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ call_func = program->builtin_libc_funcs[fidx];
|
|
|
+ if (!call_func) {
|
|
|
+ wasm_set_exception(module_inst, "undefined element");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (call_func->u.func_import->func_type) {
|
|
|
+ if (!wasm_type_equal(func_type, call_func->u.func_import->func_type)) {
|
|
|
+ wasm_set_exception(module_inst, "indirect call type mismatch");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if (!check_symbol_signature(func_type, call_func->u.func_import->signature))
|
|
|
+ return false;
|
|
|
+
|
|
|
+ call_func->u.func_import->func_type = func_type;
|
|
|
+ call_func->func_type = func_type;
|
|
|
+ }
|
|
|
+
|
|
|
+ callee_module_inst = module_inst;
|
|
|
+ *p_callee_module_inst = callee_module_inst;
|
|
|
+ *p_call_func = call_func;
|
|
|
+
|
|
|
+ wasm_program_cache_resolve_result(program, origin_slot_id, call_func, callee_module_inst);
|
|
|
+ return true;
|
|
|
+ } else if (inst_idx > 1) { // call dependency module
|
|
|
+ // call export function by non root module
|
|
|
+ callee_module_inst = (WASMModuleInstance*)wasm_program_get_module_inst_by_id(program, inst_idx);
|
|
|
+ if (!callee_module_inst) {
|
|
|
+ wasm_set_exception(module_inst, "undefined element");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ bh_assert(callee_module_inst->module->dylink_section);
|
|
|
+
|
|
|
+ tbl_slot_id -= (inst_idx - 1) * TABLE_SPACE_SLOT_SIZE;
|
|
|
+ if (program->config.use_tbl_as_cache) {
|
|
|
+ //if (tbl_slot_id >= (int32)callee_module_inst->module->dylink_section->table_size) {
|
|
|
+ tbl_slot_id -= TABLE_SPACE_SLOT_SIZE - callee_module_inst->default_table->max_size;
|
|
|
+
|
|
|
+ if ((uint32)tbl_slot_id < (callee_module_inst->default_table->max_size -
|
|
|
+ callee_module_inst->export_func_count)) {
|
|
|
+ wasm_set_exception(module_inst, "wrong export function id");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ //}
|
|
|
+
|
|
|
+ tbl_inst = wasm_get_table_inst(callee_module_inst, tbl_idx);
|
|
|
+ } else {
|
|
|
+ is_local_func = false;
|
|
|
+ tbl_slot_id = callee_module_inst->export_func_count - (TABLE_SPACE_SLOT_SIZE - tbl_slot_id);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // call root module
|
|
|
+ if (!tbl_slot_id) {
|
|
|
+ wasm_set_exception(module_inst, "uninitialized element");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ callee_module_inst = (WASMModuleInstance*)program->root_module_inst;
|
|
|
+
|
|
|
+ if (callee_module_inst->module->dylink_section &&
|
|
|
+ program->config.use_tbl_as_cache) {
|
|
|
+ tbl_inst = wasm_get_table_inst(callee_module_inst, tbl_idx);
|
|
|
+
|
|
|
+ bh_assert(program->config.import_memop_mode != FROM_ROOT);
|
|
|
+ if (tbl_slot_id > ((int32)callee_module_inst->module->dylink_section->table_size)) {
|
|
|
+ tbl_slot_id -= TABLE_SPACE_SLOT_SIZE - callee_module_inst->default_table->max_size;
|
|
|
+ }
|
|
|
+ } else if (program->config.import_memop_mode == FROM_ROOT ||
|
|
|
+ !program->config.use_tbl_as_cache) {
|
|
|
+ is_local_func = false;
|
|
|
+ tbl_slot_id = callee_module_inst->export_func_count - (TABLE_SPACE_SLOT_SIZE - tbl_slot_id);
|
|
|
+ } else {
|
|
|
+ wasm_set_exception(module_inst, "root module is not shared module");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ callee_module_inst = module_inst;
|
|
|
+ tbl_inst = wasm_get_table_inst(callee_module_inst, tbl_idx);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!tbl_inst) { // func not in table
|
|
|
+ if (!callee_module_inst->export_functions[tbl_slot_id].function) {
|
|
|
+ wasm_set_exception(module_inst, "uninitialized element");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ fidx = (callee_module_inst->export_functions[tbl_slot_id].function -
|
|
|
+ callee_module_inst->functions);
|
|
|
+ } else {
|
|
|
+ if (tbl_slot_id < 0 ||
|
|
|
+ (tbl_slot_id >= (int32)tbl_inst->cur_size
|
|
|
+ )) {
|
|
|
+ wasm_set_exception(module_inst, "undefined element");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ fidx = ((uint32*)tbl_inst->base_addr)[tbl_slot_id];
|
|
|
+ }
|
|
|
+
|
|
|
+ if (fidx == (uint32)-1) {
|
|
|
+ if (!program) {
|
|
|
+ wasm_set_exception(module_inst, "uninitialized element");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (inst_idx < 1) {
|
|
|
+ wasm_set_exception(module_inst, "uninitialized element");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (callee_module_inst->module->dylink_section) {
|
|
|
+ if (tbl_slot_id < (int32)(tbl_inst->cur_size - callee_module_inst->export_func_count)) {
|
|
|
+ wasm_set_exception(module_inst, "uninitialized element");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ } else if (tbl_slot_id < (int32)tbl_inst->cur_size) {
|
|
|
+ wasm_set_exception(module_inst, "uninitialized element");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (program->config.binding_mode != LAZY_BINDING) {
|
|
|
+ wasm_set_exception(module_inst, "uninitialized element");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ export_func_id = tbl_slot_id - (callee_module_inst->default_table->max_size -
|
|
|
+ callee_module_inst->export_func_count);
|
|
|
+
|
|
|
+ if (!callee_module_inst->export_functions[export_func_id].function) {
|
|
|
+ wasm_set_exception(module_inst, "uninitialized element");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // lazy link
|
|
|
+ fidx = (callee_module_inst->export_functions[export_func_id].function -
|
|
|
+ callee_module_inst->functions);
|
|
|
+ ((uint32*)tbl_inst->base_addr)[tbl_slot_id] = fidx;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (fidx >= callee_module_inst->function_count) {
|
|
|
+ wasm_set_exception(module_inst, "unknown function");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* always call module own functions */
|
|
|
+ call_func = callee_module_inst->functions + fidx;
|
|
|
+ cur_func_type = call_func->func_type;
|
|
|
+
|
|
|
+ if (!wasm_type_equal(func_type, cur_func_type)) {
|
|
|
+ wasm_set_exception(module_inst, "indirect call type mismatch");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ *p_callee_module_inst = callee_module_inst;
|
|
|
+ *p_call_func = call_func;
|
|
|
+
|
|
|
+ if (!is_local_func) {
|
|
|
+ wasm_program_cache_resolve_result(program, origin_slot_id, call_func, callee_module_inst);
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+#if WASM_ENABLE_AOT != 0
|
|
|
+bool
|
|
|
+wasm_program_resolve_aot_op_call_indirect(WASMExecEnv *exec_env,
|
|
|
+ WASMProgramInstance * program,
|
|
|
+ AOTModuleInstance * module_inst,
|
|
|
+ uint32 tbl_idx,
|
|
|
+ int32 table_elem_idx,
|
|
|
+ uint32 expected_type_idx,
|
|
|
+ AOTFuncType * expected_func_type,
|
|
|
+ AOTModuleInstance ** p_callee_module_inst,
|
|
|
+ AOTModule ** p_callee_module,
|
|
|
+ uint32 * p_call_func_index,
|
|
|
+ AOTImportFunc ** p_import_func)
|
|
|
+{
|
|
|
+ AOTModuleInstance * callee_module_inst = NULL;
|
|
|
+ AOTModule* callee_module = NULL;
|
|
|
+ AOTModule *aot_module = (AOTModule*)module_inst->aot_module.ptr;
|
|
|
+ AOTExportFunctionInstance * export_funcs = NULL, *call_func = NULL;
|
|
|
+ AOTFuncType * func_type = NULL;
|
|
|
+ AOTTableInstance *tbl_inst = NULL;
|
|
|
+ uint32 inst_id = 0, export_func_id, local_table_elem_cnt;
|
|
|
+ uint32 func_idx = 0, func_type_idx;
|
|
|
+ void **func_ptrs = NULL, *func_ptr = NULL;
|
|
|
+ AOTImportFunc *import_func = NULL;
|
|
|
+ uint32 *func_type_indexes = NULL;
|
|
|
+ char buf[96];
|
|
|
+ int32 origin_elem_idx = table_elem_idx;
|
|
|
+
|
|
|
+ if (table_elem_idx < 0) {
|
|
|
+ aot_set_exception_with_id(module_inst, EXCE_UNDEFINED_ELEMENT);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ inst_id = (table_elem_idx >> TABLE_SPACE_BITS_LEN) + 1;
|
|
|
+ if (program) {
|
|
|
+ if (inst_id == module_inst->inst_id) {
|
|
|
+ callee_module_inst = module_inst;
|
|
|
+ callee_module = (AOTModule*)callee_module_inst->aot_module.ptr;
|
|
|
+
|
|
|
+ table_elem_idx -= (inst_id - 1) * TABLE_SPACE_SLOT_SIZE;
|
|
|
+ tbl_inst = aot_get_table_inst(callee_module_inst, tbl_idx);
|
|
|
+ } else if (inst_id == BUILTIN_LIBC_INST_ID) { // call libc function pointer
|
|
|
+ //is_intable_func = false;
|
|
|
+
|
|
|
+ func_idx = table_elem_idx - (inst_id - 1) * TABLE_SPACE_SLOT_SIZE;
|
|
|
+ if (func_idx >= program->builtin_libc_funcs_count) {
|
|
|
+ aot_set_exception_with_id(module_inst, EXCE_UNDEFINED_ELEMENT);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ call_func = program->builtin_libc_funcs[func_idx];
|
|
|
+ if (!call_func) {
|
|
|
+ aot_set_exception_with_id(module_inst, EXCE_UNDEFINED_ELEMENT);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (call_func->u.func_import->func_type) {
|
|
|
+ if (!wasm_type_equal(expected_func_type, call_func->u.func_import->func_type)) {
|
|
|
+ aot_set_exception(module_inst, "indirect call type mismatch");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if (!check_symbol_signature(expected_func_type, call_func->u.func_import->signature))
|
|
|
+ return false;
|
|
|
+
|
|
|
+ call_func->u.func_import->func_type = expected_func_type;
|
|
|
+ }
|
|
|
+
|
|
|
+ callee_module_inst = module_inst;
|
|
|
+ *p_callee_module_inst = callee_module_inst;
|
|
|
+ *p_call_func_index = 0;
|
|
|
+ *p_import_func = call_func->u.func_import;
|
|
|
+
|
|
|
+ wasm_program_cache_resolve_result(program, origin_elem_idx, (*p_import_func)->func_ptr_linked, callee_module_inst);
|
|
|
+
|
|
|
+ return true;
|
|
|
+ } else if (inst_id > 1) {
|
|
|
+ callee_module_inst = (AOTModuleInstance*)wasm_program_get_module_inst_by_id(program, inst_id);
|
|
|
+ if (!callee_module_inst) {
|
|
|
+ aot_set_exception_with_id(module_inst, EXCE_UNDEFINED_ELEMENT);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ callee_module = (AOTModule*)callee_module_inst->aot_module.ptr;
|
|
|
+
|
|
|
+ table_elem_idx -= (inst_id - 1) * TABLE_SPACE_SLOT_SIZE;
|
|
|
+
|
|
|
+ if (program->config.use_tbl_as_cache) {
|
|
|
+ tbl_inst = aot_get_table_inst(callee_module_inst, tbl_idx);
|
|
|
+ bh_assert(tbl_inst);
|
|
|
+
|
|
|
+ local_table_elem_cnt = (uint32)callee_module->dylink_section->table_size;
|
|
|
+ if (wasm_program_is_root_module((WASMModuleInstanceCommon*)callee_module_inst))
|
|
|
+ local_table_elem_cnt ++;
|
|
|
+
|
|
|
+ if ((uint32)table_elem_idx >= local_table_elem_cnt) {
|
|
|
+ table_elem_idx -= TABLE_SPACE_SLOT_SIZE - tbl_inst->max_size;
|
|
|
+
|
|
|
+ if ((uint32)table_elem_idx < (tbl_inst->max_size -
|
|
|
+ callee_module->export_func_count)) {
|
|
|
+ aot_set_exception_with_id(module_inst, EXCE_UNDEFINED_ELEMENT);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ table_elem_idx = callee_module->export_func_count - (TABLE_SPACE_SLOT_SIZE - table_elem_idx);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if (!table_elem_idx) {
|
|
|
+ aot_set_exception_with_id(module_inst, EXCE_UNINITIALIZED_ELEMENT);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ callee_module_inst = (AOTModuleInstance*)program->root_module_inst;
|
|
|
+ callee_module = (AOTModule*)callee_module_inst->aot_module.ptr;
|
|
|
+ if (callee_module->dylink_section &&
|
|
|
+ program->config.use_tbl_as_cache) {
|
|
|
+ tbl_inst = aot_get_table_inst(callee_module_inst, tbl_idx);
|
|
|
+ if ((uint32)table_elem_idx > callee_module->dylink_section->table_size) {
|
|
|
+ table_elem_idx -= TABLE_SPACE_SLOT_SIZE - tbl_inst->max_size;
|
|
|
+ }
|
|
|
+ } else if (program->config.import_memop_mode == FROM_ROOT ||
|
|
|
+ !program->config.use_tbl_as_cache) {
|
|
|
+ table_elem_idx = callee_module->export_func_count - (TABLE_SPACE_SLOT_SIZE - table_elem_idx);
|
|
|
+ } else {
|
|
|
+ aot_set_exception(module_inst, "root module is not shared module");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ callee_module_inst = module_inst;
|
|
|
+ callee_module = aot_module;
|
|
|
+
|
|
|
+ /* this function is called from native code, so exec_env->handle and
|
|
|
+ exec_env->native_stack_boundary must have been set, we don't set
|
|
|
+ it again */
|
|
|
+
|
|
|
+ if ((uint8*)&callee_module_inst < exec_env->native_stack_boundary) {
|
|
|
+ aot_set_exception_with_id(module_inst, EXCE_NATIVE_STACK_OVERFLOW);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ tbl_inst = aot_get_table_inst(callee_module_inst, tbl_idx);
|
|
|
+ bh_assert(tbl_inst);
|
|
|
+
|
|
|
+ if ((uint32)table_elem_idx >= tbl_inst->cur_size) {
|
|
|
+ aot_set_exception_with_id(callee_module_inst, EXCE_UNDEFINED_ELEMENT);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!tbl_inst) {
|
|
|
+ export_funcs = (AOTExportFunctionInstance*)callee_module_inst->export_funcs.ptr;
|
|
|
+
|
|
|
+ func_idx = export_funcs[table_elem_idx].func_index;
|
|
|
+ } else {
|
|
|
+ if (table_elem_idx < 0 ||
|
|
|
+ table_elem_idx >= (int32)tbl_inst->cur_size) {
|
|
|
+ aot_set_exception_with_id(callee_module_inst, EXCE_UNDEFINED_ELEMENT);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ bh_assert( ((uint32*)tbl_inst->data + table_elem_idx) < (uint32*)callee_module_inst->global_table_data_end.ptr);
|
|
|
+ func_idx = ((uint32*)tbl_inst->data)[table_elem_idx];
|
|
|
+ }
|
|
|
+
|
|
|
+ if (func_idx == (uint32)-1) {
|
|
|
+ if (!program) {
|
|
|
+ aot_set_exception_with_id(module_inst, EXCE_UNINITIALIZED_ELEMENT);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (inst_id < 1) {
|
|
|
+ aot_set_exception_with_id(module_inst, EXCE_UNINITIALIZED_ELEMENT);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (callee_module->dylink_section) {
|
|
|
+ if ((uint32)table_elem_idx < (tbl_inst->cur_size - callee_module->export_func_count)) {
|
|
|
+ aot_set_exception_with_id(module_inst, EXCE_UNINITIALIZED_ELEMENT);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ } else if ((uint32)table_elem_idx < tbl_inst->cur_size) {
|
|
|
+ aot_set_exception_with_id(module_inst, EXCE_UNINITIALIZED_ELEMENT);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (program->config.binding_mode != LAZY_BINDING) {
|
|
|
+ aot_set_exception_with_id(module_inst, EXCE_UNINITIALIZED_ELEMENT);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ export_func_id = table_elem_idx - (tbl_inst->max_size -
|
|
|
+ callee_module->export_func_count);
|
|
|
+
|
|
|
+ export_funcs = (AOTExportFunctionInstance*)callee_module_inst->export_funcs.ptr;
|
|
|
+
|
|
|
+ if (export_func_id >= callee_module->export_func_count) {
|
|
|
+ aot_set_exception_with_id(module_inst, EXCE_UNDEFINED_ELEMENT);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // lazy link
|
|
|
+ func_idx = export_funcs[export_func_id].func_index;
|
|
|
+ ((uint32*)tbl_inst->data)[table_elem_idx] = func_idx;
|
|
|
+ }
|
|
|
+
|
|
|
+ // aot_module = (AOTModule*)callee_module_inst->aot_module.ptr;
|
|
|
+ func_ptrs = (void**)callee_module_inst->func_ptrs.ptr;
|
|
|
+ func_type_indexes = (uint32*)callee_module_inst->func_type_indexes.ptr;
|
|
|
+
|
|
|
+ func_type_idx = func_type_indexes[func_idx];
|
|
|
+ func_type = callee_module->func_types[func_type_idx];
|
|
|
+
|
|
|
+ if (!(func_ptr = func_ptrs[func_idx])) {
|
|
|
+ bh_assert(func_idx < callee_module->import_func_count);
|
|
|
+ import_func = callee_module->import_funcs + func_idx;
|
|
|
+ snprintf(buf, sizeof(buf),
|
|
|
+ "failed to call unlinked import function (%s, %s)",
|
|
|
+ import_func->module_name->str, import_func->func_name->str);
|
|
|
+ aot_set_exception(module_inst, buf);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (module_inst->inst_id == callee_module_inst->inst_id && expected_type_idx != func_type_idx) {
|
|
|
+ aot_set_exception_with_id(module_inst, EXCE_INVALID_FUNCTION_TYPE_INDEX);
|
|
|
+ return false;
|
|
|
+ } else if (module_inst->inst_id != callee_module_inst->inst_id) {
|
|
|
+ if (!wasm_type_equal(expected_func_type, func_type)) {
|
|
|
+ aot_set_exception_with_id(module_inst, EXCE_INVALID_FUNCTION_TYPE_INDEX);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ *p_callee_module_inst = callee_module_inst;
|
|
|
+ *p_callee_module = callee_module;
|
|
|
+ *p_call_func_index = func_idx;
|
|
|
+ *p_import_func = NULL;
|
|
|
+
|
|
|
+ wasm_program_cache_resolve_result(program, origin_elem_idx,
|
|
|
+ ((void**)(*p_callee_module_inst)->func_ptrs.ptr)[func_idx],
|
|
|
+ callee_module_inst);
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+#if WASM_ENABLE_LIBC_BUILTIN != 0
|
|
|
+uint32
|
|
|
+wasm_program_get_ctype_tolower_mem(WASMModuleInstanceCommon * module_inst)
|
|
|
+{
|
|
|
+ WASMProgramInstance * program = ((WASMModuleInstanceHead*)module_inst)->program;
|
|
|
+
|
|
|
+ if (!program)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ return program->ctype_tolower_loc_space;
|
|
|
+}
|
|
|
+
|
|
|
+void
|
|
|
+wasm_program_set_ctype_tolower_mem(WASMModuleInstanceCommon * module_inst, uint32 addr)
|
|
|
+{
|
|
|
+ WASMProgramInstance * program = ((WASMModuleInstanceHead*)module_inst)->program;
|
|
|
+
|
|
|
+ if (!program)
|
|
|
+ return;
|
|
|
+
|
|
|
+ program->ctype_tolower_loc_space = addr;
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
+#endif
|
|
|
+
|
|
|
+#endif
|