Browse Source

[instantiation linking] Optimize aot func inst list (#4018)

liang.he 11 tháng trước cách đây
mục cha
commit
918b364bbe

+ 3 - 3
core/iwasm/aot/aot_loader.c

@@ -668,7 +668,7 @@ load_native_symbol_section(const uint8 *buf, const uint8 *buf_end,
             goto fail;
         }
 
-        for (i = cnt - 1; i >= 0; i--) {
+        for (i = (int32)cnt - 1; i >= 0; i--) {
             read_string(p, p_end, symbol);
             if (!strlen(symbol))
                 continue;
@@ -3840,7 +3840,7 @@ load_relocation_section(const uint8 *buf, const uint8 *buf_end,
         /* The layout is: literal size + literal + code (with plt table) */
         uint8 *mmap_addr = module->literal - sizeof(uint32);
         uint32 total_size =
-            sizeof(uint32) + module->literal_size + module->code_size;
+            (uint32)sizeof(uint32) + module->literal_size + module->code_size;
         os_mprotect(mmap_addr, total_size, map_prot);
     }
 
@@ -4529,7 +4529,7 @@ aot_unload(AOTModule *module)
         /* The layout is: literal size + literal + code (with plt table) */
         uint8 *mmap_addr = module->literal - sizeof(uint32);
         uint32 total_size =
-            sizeof(uint32) + module->literal_size + module->code_size;
+            (uint32)sizeof(uint32) + module->literal_size + module->code_size;
         os_munmap(mmap_addr, total_size);
     }
 

+ 330 - 183
core/iwasm/aot/aot_runtime.c

@@ -127,6 +127,28 @@ runtime_malloc(uint64 size, char *error_buf, uint32 error_buf_size)
     return mem;
 }
 
+#if WASM_ENABLE_MULTI_MODULE != 0
+static AOTModuleInstance *
+get_sub_module_inst(const AOTModuleInstance *parent_module_inst,
+                    const AOTModule *sub_module)
+{
+    bh_list *sub_module_inst_list = parent_module_inst->e->sub_module_inst_list;
+    WASMSubModInstNode *node = bh_list_first_elem(sub_module_inst_list);
+
+    AOTModuleInstance *inst = (AOTModuleInstance *)node->module_inst;
+    while (node && sub_module != (AOTModule *)inst->module) {
+        node = bh_list_elem_next(node);
+        inst = (AOTModuleInstance *)node->module_inst;
+    }
+
+    if (!node) {
+        LOG_DEBUG("fail to find sub module instance");
+    }
+
+    return node ? inst : NULL;
+}
+#endif
+
 #if WASM_ENABLE_AOT_STACK_FRAME != 0
 static bool
 is_tiny_frame(WASMExecEnv *exec_env)
@@ -760,6 +782,107 @@ fail:
     return NULL;
 }
 
+static AOTFunctionInstance *
+import_functions_instantiate(AOTModuleInstance *module_inst, AOTModule *module,
+                             const WASMExternInstance *imports,
+                             uint32 import_count, char *error_buf,
+                             uint32 error_buf_size)
+{
+    uint64 total_size = sizeof(AOTFunctionInstance) * module->import_func_count;
+
+    AOTFunctionInstance *functions =
+        runtime_malloc(total_size, error_buf, error_buf_size);
+    if (!functions) {
+        return NULL;
+    }
+
+    AOTFunctionInstance *function = functions;
+    for (uint32 i = 0; i < module->import_func_count; i++, function++) {
+        function->is_import_func = true;
+        function->func_index = i;
+
+        AOTImportFunc *import = module->import_funcs + i;
+        /*TODO: use name section content? */
+        function->func_name = import->func_name;
+        function->u.func_import = import;
+
+#if WASM_ENABLE_MULTI_MODULE != 0
+        if (import->import_module) {
+            /* from other .wasm */
+            function->import_module_inst =
+                get_sub_module_inst(module_inst, import->import_module);
+            if (!function->import_module_inst) {
+                set_error_buf_v(error_buf, error_buf_size,
+                                "unknown import module \"%s\"",
+                                import->module_name);
+                goto fail;
+            }
+
+            function->import_func_inst = aot_lookup_function(
+                function->import_module_inst, import->func_name);
+            if (!function->import_func_inst) {
+                set_error_buf_v(error_buf, error_buf_size,
+                                "unknown import function \"%s\"",
+                                import->func_name);
+                goto fail;
+            }
+        }
+
+        /* from c_api (loading) */
+        function->call_conv_wasm_c_api = import->call_conv_wasm_c_api;
+#else
+        const WASMExternInstance *extern_inst =
+            wasm_runtime_get_extern_instance(imports, import_count,
+                                             WASM_IMPORT_EXPORT_KIND_FUNC, i);
+        if (!extern_inst) {
+            LOG_DEBUG("no import function(%s, %s) from imports list, might "
+                      "provided by wasm_native",
+                      import->module_name, import->func_name);
+            /* so it's from wasm_native */
+            continue;
+        }
+
+        /* if extern_inst is about a wasm function from other .wasm */
+        AOTFunctionInstance *extern_inst_func =
+            (AOTFunctionInstance *)extern_inst->u.function;
+        if (!extern_inst_func) {
+            LOG_DEBUG("empty extern_inst_func for import function(%s, %s)",
+                      "might provided by wasm_native", import->module_name,
+                      import->func_name);
+            /* so it's from wasm_native */
+            continue;
+        }
+
+        bh_assert(extern_inst_func->is_import_func);
+
+        /* don't allow wrong matchment */
+        if (strcmp(import->func_name, extern_inst->field_name)) {
+            LOG_ERROR(
+                "mismatched import memory name: expect \"%s\", got \"%s\"",
+                import->func_name, extern_inst->field_name);
+            goto fail;
+        }
+
+        /* from other .wasm */
+        function->import_module_inst = extern_inst_func->import_module_inst;
+        function->import_func_inst = extern_inst_func->import_func_inst;
+
+        /* from c_api (instantiation)*/
+        function->call_conv_wasm_c_api = extern_inst_func->call_conv_wasm_c_api;
+        /* TODO: for now, let c_api finish this. Will move it to wasm_runtime
+         * later */
+        /*module_inst->c_api_func_imports[i] =
+         * extern_inst_func->import_func_c_api;*/
+
+#endif
+    }
+
+    return functions;
+fail:
+    wasm_runtime_free(functions);
+    return NULL;
+}
+
 /**
  * Destroy table instances.
  */
@@ -1602,6 +1725,7 @@ aot_destroy_memory(AOTMemoryInstance *memory)
 
 static bool
 init_func_ptrs(AOTModuleInstance *module_inst, AOTModule *module,
+               const WASMExternInstance *imports, uint32 import_count,
                char *error_buf, uint32 error_buf_size)
 {
     uint32 i;
@@ -1621,12 +1745,32 @@ init_func_ptrs(AOTModuleInstance *module_inst, AOTModule *module,
     /* Set import function pointers */
     func_ptrs = (void **)module_inst->func_ptrs;
     for (i = 0; i < module->import_func_count; i++, func_ptrs++) {
-        *func_ptrs = (void *)module->import_funcs[i].func_ptr_linked;
-        if (!*func_ptrs) {
-            const char *module_name = module->import_funcs[i].module_name;
-            const char *field_name = module->import_funcs[i].func_name;
-            LOG_WARNING("warning: failed to link import function (%s, %s)",
-                        module_name, field_name);
+        AOTFunctionInstance *func =
+            aot_locate_import_function_instance(module_inst, i);
+        bh_assert(func->is_import_func);
+
+        if (func->call_conv_wasm_c_api) {
+            /* when execution, goes to invoke_native() and use
+             * c_api_func_imports*/
+            continue;
+        }
+
+        if (func->import_module_inst) {
+            /* when execution, goes to invoke_native() and switch to another
+             * .wasm */
+            continue;
+        }
+
+        AOTImportFunc *import_func = func->u.func_import;
+
+        LOG_DEBUG("use wasm_native linked functions for (%s,%s)",
+                  import_func->module_name, import_func->func_name);
+
+        *func_ptrs = import_func->func_ptr_linked;
+
+        if (!func_ptrs) {
+            LOG_WARNING("warning: failed to link import function (%s,%s)",
+                        import_func->module_name, import_func->func_name);
         }
     }
 
@@ -1697,69 +1841,16 @@ unlock_and_return:
     return func_inst;
 }
 
+/*TODO: */
 AOTFunctionInstance *
 aot_get_function_instance(AOTModuleInstance *module_inst, uint32 func_idx)
 {
-    AOTModule *module = (AOTModule *)module_inst->module;
     AOTModuleInstanceExtra *extra = (AOTModuleInstanceExtra *)module_inst->e;
-    AOTFunctionInstance *func_inst;
+    AOTFunctionInstance *import_functions = extra->import_functions;
 
-    /* lookup from export functions first */
-    if ((func_inst = aot_lookup_function_with_idx(module_inst, func_idx)))
-        return func_inst;
+    bh_assert(import_functions);
 
-    exception_lock(module_inst);
-
-    /* allocate functions array if needed */
-    if (!extra->functions) {
-        uint64 func_count =
-            ((uint64)module->import_func_count + module->func_count);
-        uint64 total_size = func_count * (uint64)sizeof(AOTFunctionInstance *);
-
-        if ((func_count == 0)
-            || !(extra->functions = runtime_malloc(total_size, NULL, 0))) {
-            exception_unlock(module_inst);
-            return NULL;
-        }
-
-        extra->function_count = (uint32)func_count;
-    }
-
-    /* instantiate function if needed */
-    bh_assert(func_idx < extra->function_count);
-    if (!extra->functions[func_idx]) {
-        AOTFunctionInstance *function = (AOTFunctionInstance *)runtime_malloc(
-            sizeof(AOTFunctionInstance), NULL, 0);
-        if (!function) {
-            exception_unlock(module_inst);
-            return NULL;
-        }
-
-        if (func_idx < module->import_func_count) {
-            /* instantiate function from import section */
-            function->is_import_func = true;
-            function->func_name = module->import_funcs[func_idx].func_name;
-            function->func_index = func_idx;
-            function->u.func_import = &module->import_funcs[func_idx];
-        }
-        else {
-            /* instantiate non-import function */
-            uint32 ftype_index =
-                module->func_type_indexes[func_idx - module->import_func_count];
-            function->is_import_func = false;
-            function->func_index = func_idx;
-            function->u.func.func_type =
-                (AOTFuncType *)module->types[ftype_index];
-            function->u.func.func_ptr =
-                module->func_ptrs[func_idx - module->import_func_count];
-        }
-
-        extra->functions[func_idx] = function;
-    }
-
-    exception_unlock(module_inst);
-
-    return extra->functions[func_idx];
+    return import_functions + func_idx;
 }
 
 static bool
@@ -1799,6 +1890,7 @@ cmp_func_inst(const void *a, const void *b)
     return strcmp(func_inst1->func_name, func_inst2->func_name);
 }
 
+/* TODO: Can I reuse the AOTFunctionInstance ?*/
 static bool
 create_export_funcs(AOTModuleInstance *module_inst, AOTModule *module,
                     char *error_buf, uint32 error_buf_size)
@@ -1818,26 +1910,33 @@ create_export_funcs(AOTModuleInstance *module_inst, AOTModule *module,
         module_inst->export_functions = (void *)export_func;
 
         for (i = 0; i < module->export_count; i++) {
-            if (exports[i].kind == EXPORT_KIND_FUNC) {
-                export_func->func_name = exports[i].name;
-                export_func->func_index = exports[i].index;
-                if (export_func->func_index < module->import_func_count) {
-                    export_func->is_import_func = true;
-                    export_func->u.func_import =
-                        &module->import_funcs[export_func->func_index];
-                }
-                else {
-                    export_func->is_import_func = false;
-                    func_index =
-                        export_func->func_index - module->import_func_count;
-                    ftype_index = module->func_type_indexes[func_index];
-                    export_func->u.func.func_type =
-                        (AOTFuncType *)module->types[ftype_index];
-                    export_func->u.func.func_ptr =
-                        module->func_ptrs[func_index];
-                }
-                export_func++;
+            if (exports[i].kind != EXPORT_KIND_FUNC) {
+                continue;
+            }
+
+            export_func->func_index = exports[i].index;
+
+            if (export_func->func_index < module->import_func_count) {
+                AOTFunctionInstance *import_func =
+                    aot_locate_import_function_instance(
+                        module_inst, export_func->func_index);
+                *export_func = *import_func;
             }
+            else {
+                export_func->is_import_func = false;
+
+                func_index =
+                    export_func->func_index - module->import_func_count;
+                ftype_index = module->func_type_indexes[func_index];
+                export_func->u.func.func_type =
+                    (AOTFuncType *)module->types[ftype_index];
+
+                export_func->u.func.func_ptr = module->func_ptrs[func_index];
+            }
+
+            /* always use export names */
+            export_func->func_name = exports[i].name;
+            export_func++;
         }
 
         qsort(module_inst->export_functions, module_inst->export_func_count,
@@ -1938,7 +2037,7 @@ lookup_post_instantiate_func(AOTModuleInstance *module_inst,
 
 static bool
 execute_post_instantiate_functions(AOTModuleInstance *module_inst,
-                                   bool is_sub_inst, WASMExecEnv *exec_env_main)
+                                   bool is_spawned, WASMExecEnv *exec_env_main)
 {
     AOTModule *module = (AOTModule *)module_inst->module;
     AOTFunctionInstance *initialize_func = NULL;
@@ -1957,7 +2056,7 @@ execute_post_instantiate_functions(AOTModuleInstance *module_inst,
      * the environment at most once, and that none of their other exports
      * are accessed before that call.
      */
-    if (!is_sub_inst && module->import_wasi_api) {
+    if (!is_spawned && module->import_wasi_api) {
         initialize_func =
             lookup_post_instantiate_func(module_inst, "_initialize");
     }
@@ -1965,7 +2064,7 @@ execute_post_instantiate_functions(AOTModuleInstance *module_inst,
 
     /* Execute possible "__post_instantiate" function if wasm app is
        compiled by emsdk's early version */
-    if (!is_sub_inst) {
+    if (!is_spawned) {
         post_inst_func =
             lookup_post_instantiate_func(module_inst, "__post_instantiate");
     }
@@ -1973,7 +2072,7 @@ execute_post_instantiate_functions(AOTModuleInstance *module_inst,
 #if WASM_ENABLE_BULK_MEMORY != 0
     /* Only execute the memory init function for main instance since
        the data segments will be dropped once initialized */
-    if (!is_sub_inst
+    if (!is_spawned
 #if WASM_ENABLE_LIBC_WASI != 0
         && !module->import_wasi_api
 #endif
@@ -1989,7 +2088,7 @@ execute_post_instantiate_functions(AOTModuleInstance *module_inst,
         return true;
     }
 
-    if (is_sub_inst) {
+    if (is_spawned) {
         bh_assert(exec_env_main);
 #ifdef OS_ENABLE_HW_BOUND_CHECK
         /* May come from pthread_create_wrapper, thread_spawn_wrapper and
@@ -2082,7 +2181,7 @@ execute_post_instantiate_functions(AOTModuleInstance *module_inst,
     ret = true;
 
 fail:
-    if (is_sub_inst) {
+    if (is_spawned) {
         /* Restore the parent exec_env's module inst */
         wasm_exec_env_restore_module_inst(exec_env_main, module_inst_main);
     }
@@ -2116,7 +2215,7 @@ aot_instantiate(AOTModule *module, AOTModuleInstance *parent,
     uint64 total_size, table_size = 0;
     uint8 *p;
     uint32 i, extra_info_offset;
-    const bool is_sub_inst = parent != NULL;
+    const bool is_spawned = parent != NULL;
 #if WASM_ENABLE_MULTI_MODULE != 0
     bool ret = false;
 #endif
@@ -2183,7 +2282,7 @@ aot_instantiate(AOTModule *module, AOTModuleInstance *parent,
 #if WASM_ENABLE_GC != 0
     /* Initialize gc heap first since it may be used when initializing
        globals and others */
-    if (!is_sub_inst) {
+    if (!is_spawned) {
         uint32 gc_heap_size = wasm_runtime_get_gc_heap_size_default();
 
         if (gc_heap_size < GC_HEAP_SIZE_MIN)
@@ -2205,16 +2304,6 @@ aot_instantiate(AOTModule *module, AOTModuleInstance *parent,
 
 #if WASM_ENABLE_MULTI_MODULE != 0
     extra->sub_module_inst_list = &extra->sub_module_inst_list_head;
-
-    /* Allocate memory for import_func_module_insts*/
-    if (module->import_func_count > 0
-        && !(extra->import_func_module_insts =
-                 runtime_malloc((uint64)module->import_func_count
-                                    * sizeof(WASMModuleInstanceCommon *),
-                                error_buf, error_buf_size))) {
-        goto fail;
-    }
-
     ret = wasm_runtime_sub_module_instantiate(
         (WASMModuleCommon *)module, (WASMModuleInstanceCommon *)module_inst,
         stack_size, heap_size, max_memory_pages, error_buf, error_buf_size);
@@ -2300,15 +2389,25 @@ aot_instantiate(AOTModule *module, AOTModuleInstance *parent,
                               imports, import_count, error_buf, error_buf_size))
         goto fail;
 
+    extra->function_count = module->import_func_count + module->func_count;
+    if (extra->function_count > 0) {
+        extra->import_functions = import_functions_instantiate(
+            module_inst, module, imports, import_count, error_buf,
+            error_buf_size);
+        if (!extra->import_functions)
+            goto fail;
+    }
+
     /* Initialize function pointers */
-    if (!init_func_ptrs(module_inst, module, error_buf, error_buf_size))
+    if (!init_func_ptrs(module_inst, module, imports, import_count, error_buf,
+                        error_buf_size))
         goto fail;
 
     if (!create_exports(module_inst, module, error_buf, error_buf_size))
         goto fail;
 
 #if WASM_ENABLE_LIBC_WASI != 0
-    if (!is_sub_inst) {
+    if (!is_spawned) {
         if (!wasm_runtime_init_wasi(
                 (WASMModuleInstanceCommon *)module_inst,
                 module->wasi_args.dir_list, module->wasi_args.dir_count,
@@ -2504,7 +2603,7 @@ aot_instantiate(AOTModule *module, AOTModuleInstance *parent,
     }
 #endif
 
-    if (!execute_post_instantiate_functions(module_inst, is_sub_inst,
+    if (!execute_post_instantiate_functions(module_inst, is_spawned,
                                             exec_env_main)) {
         set_error_buf(error_buf, error_buf_size, module_inst->cur_exception);
         goto fail;
@@ -2518,7 +2617,7 @@ aot_instantiate(AOTModule *module, AOTModuleInstance *parent,
     return module_inst;
 
 fail:
-    aot_deinstantiate(module_inst, is_sub_inst);
+    aot_deinstantiate(module_inst, is_spawned);
     return NULL;
 }
 
@@ -2546,7 +2645,7 @@ destroy_c_api_frames(Vector *frames)
 #endif
 
 void
-aot_deinstantiate(AOTModuleInstance *module_inst, bool is_sub_inst)
+aot_deinstantiate(AOTModuleInstance *module_inst, bool is_spawned)
 {
     AOTModuleInstanceExtra *extra = (AOTModuleInstanceExtra *)module_inst->e;
     WASMModuleInstanceExtraCommon *common = &extra->common;
@@ -2572,13 +2671,6 @@ aot_deinstantiate(AOTModuleInstance *module_inst, bool is_sub_inst)
     }
 #endif
 
-#if WASM_ENABLE_MULTI_MODULE != 0
-    wasm_runtime_sub_module_deinstantiate(
-        (WASMModuleInstanceCommon *)module_inst);
-    if (extra->import_func_module_insts)
-        wasm_runtime_free(extra->import_func_module_insts);
-#endif
-
     tables_deinstantiate(module_inst);
 
     if (module_inst->memories)
@@ -2599,14 +2691,8 @@ aot_deinstantiate(AOTModuleInstance *module_inst, bool is_sub_inst)
     if (module_inst->export_tables)
         wasm_runtime_free(module_inst->export_tables);
 
-    if (extra->functions) {
-        uint32 func_idx;
-        for (func_idx = 0; func_idx < extra->function_count; ++func_idx) {
-            if (extra->functions[func_idx]) {
-                wasm_runtime_free(extra->functions[func_idx]);
-            }
-        }
-        wasm_runtime_free(extra->functions);
+    if (extra->import_functions) {
+        wasm_runtime_free(extra->import_functions);
     }
 
     if (extra->globals) {
@@ -2623,7 +2709,7 @@ aot_deinstantiate(AOTModuleInstance *module_inst, bool is_sub_inst)
         wasm_runtime_free(module_inst->c_api_func_imports);
 
 #if WASM_ENABLE_GC != 0
-    if (!is_sub_inst) {
+    if (!is_spawned) {
         if (common->gc_heap_handle)
             mem_allocator_destroy(common->gc_heap_handle);
         if (common->gc_heap_pool)
@@ -2631,7 +2717,7 @@ aot_deinstantiate(AOTModuleInstance *module_inst, bool is_sub_inst)
     }
 #endif
 
-    if (!is_sub_inst) {
+    if (!is_spawned) {
         wasm_native_call_context_dtors((WASMModuleInstanceCommon *)module_inst);
     }
 
@@ -2798,11 +2884,17 @@ aot_call_function(WASMExecEnv *exec_env, AOTFunctionInstance *function,
     uint32 result_count = func_type->result_count;
     uint32 ext_ret_count = result_count > 1 ? result_count - 1 : 0;
     bool ret;
-    void *func_ptr = function->is_import_func
-                         ? function->u.func_import->func_ptr_linked
-                         : function->u.func.func_ptr;
     void *attachment = NULL;
+
+    /* init_func_ptrs() has already copied func_ptr_linked value */
+    void *func_ptr =
+        aot_get_function_pointer(module_inst, function->func_index);
+
 #if WASM_ENABLE_MULTI_MODULE != 0
+    /*
+     * TODO: this searching for sub_module_inst
+     * should have been done during loading)
+     */
     bh_list *sub_module_list_node = NULL;
     const char *sub_inst_name = NULL;
     const char *func_name = function->u.func_import->module_name;
@@ -2836,6 +2928,10 @@ aot_call_function(WASMExecEnv *exec_env, AOTFunctionInstance *function,
         snprintf(buf, sizeof(buf),
                  "invalid argument count %u, must be no smaller than %u", argc,
                  func_type->param_cell_num);
+        /*
+         * TODO: might need to roll back to the original module_inst
+         * if has been changed to sub module instance
+         */
         aot_set_exception(module_inst, buf);
         return false;
     }
@@ -3446,15 +3542,11 @@ aot_invoke_native(WASMExecEnv *exec_env, uint32 func_idx, uint32 argc,
     AOTModuleInstance *module_inst =
         (AOTModuleInstance *)wasm_runtime_get_module_inst(exec_env);
     AOTModule *aot_module = (AOTModule *)module_inst->module;
-    CApiFuncImport *c_api_func_import =
-        module_inst->c_api_func_imports
-            ? module_inst->c_api_func_imports + func_idx
-            : NULL;
+    CApiFuncImport *c_api_func_import = NULL;
     uint32 *func_type_indexes = module_inst->func_type_indexes;
     uint32 func_type_idx = func_type_indexes[func_idx];
     AOTFuncType *func_type = (AOTFuncType *)aot_module->types[func_type_idx];
-    void **func_ptrs = module_inst->func_ptrs;
-    void *func_ptr = func_ptrs[func_idx];
+    void *func_ptr = NULL;
     AOTImportFunc *import_func;
     const char *signature;
     void *attachment;
@@ -3463,10 +3555,8 @@ aot_invoke_native(WASMExecEnv *exec_env, uint32 func_idx, uint32 argc,
     bh_assert(func_idx < aot_module->import_func_count);
 
     import_func = aot_module->import_funcs + func_idx;
-    if (import_func->call_conv_wasm_c_api)
-        func_ptr =
-            c_api_func_import ? c_api_func_import->func_ptr_linked : NULL;
 
+    func_ptr = aot_get_function_pointer(module_inst, func_idx);
     if (!func_ptr) {
         snprintf(buf, sizeof(buf),
                  "failed to call unlinked import function (%s, %s)",
@@ -3475,25 +3565,42 @@ aot_invoke_native(WASMExecEnv *exec_env, uint32 func_idx, uint32 argc,
         goto fail;
     }
 
-    attachment = import_func->attachment;
-    if (import_func->call_conv_wasm_c_api) {
+    AOTFunctionInstance *func_inst =
+        aot_locate_import_function_instance(module_inst, func_idx);
+    if (func_inst->call_conv_wasm_c_api) {
+        /* from c_api */
+        c_api_func_import = module_inst->c_api_func_imports
+                                ? module_inst->c_api_func_imports + func_idx
+                                : NULL;
+        if (!c_api_func_import) {
+            LOG_ERROR("c_api_func_imports should be set in c_api");
+            goto fail;
+        }
         ret = wasm_runtime_invoke_c_api_native(
             (WASMModuleInstanceCommon *)module_inst, func_ptr, func_type, argc,
             argv, c_api_func_import->with_env_arg, c_api_func_import->env_arg);
     }
-    else if (!import_func->call_conv_raw) {
+    else if (func_inst->call_conv_raw) {
+        /* from wasm_native raw */
         signature = import_func->signature;
-#if WASM_ENABLE_MULTI_MODULE != 0
-        WASMModuleInstanceCommon *sub_inst = NULL;
-        if ((sub_inst = ((AOTModuleInstanceExtra *)module_inst->e)
-                            ->import_func_module_insts[func_idx])) {
-            exec_env = wasm_runtime_get_exec_env_singleton(sub_inst);
-        }
-        if (exec_env == NULL) {
-            wasm_runtime_set_exception((WASMModuleInstanceCommon *)module_inst,
-                                       "create singleton exec_env failed");
-            goto fail;
+        attachment = import_func->attachment;
+        ret = wasm_runtime_invoke_native_raw(exec_env, func_ptr, func_type,
+                                             signature, attachment, argv, argc,
+                                             argv);
+    }
+    else {
+        if (func_inst->import_module_inst) {
+            /* from other .wasm. switch */
+            exec_env = wasm_runtime_get_exec_env_singleton(
+                (WASMModuleInstanceCommon *)func_inst->import_module_inst);
+            if (exec_env == NULL) {
+                wasm_runtime_set_exception(
+                    (WASMModuleInstanceCommon *)module_inst,
+                    "create singleton exec_env failed");
+                goto fail;
+            }
         }
+
 #if WASM_ENABLE_AOT_STACK_FRAME != 0
         void *prev_frame = get_top_frame(exec_env);
 
@@ -3501,11 +3608,15 @@ aot_invoke_native(WASMExecEnv *exec_env, uint32 func_idx, uint32 argc,
             goto fail;
         }
 #endif
-#endif /* WASM_ENABLE_MULTI_MODULE != 0 */
+
+        /* from wasm_native */
+        signature = import_func->signature;
+        attachment = import_func->attachment;
         ret =
             wasm_runtime_invoke_native(exec_env, func_ptr, func_type, signature,
                                        attachment, argv, argc, argv);
-#if WASM_ENABLE_MULTI_MODULE != 0 && WASM_ENABLE_AOT_STACK_FRAME != 0
+
+#if WASM_ENABLE_AOT_STACK_FRAME != 0
         /* Free all frames allocated, note that some frames
            may be allocated in AOT code and haven't been
            freed if exception occurred */
@@ -3513,12 +3624,6 @@ aot_invoke_native(WASMExecEnv *exec_env, uint32 func_idx, uint32 argc,
             aot_free_frame(exec_env);
 #endif
     }
-    else {
-        signature = import_func->signature;
-        ret = wasm_runtime_invoke_native_raw(exec_env, func_ptr, func_type,
-                                             signature, attachment, argv, argc,
-                                             argv);
-    }
 
 fail:
 #ifdef OS_ENABLE_HW_BOUND_CHECK
@@ -4055,7 +4160,7 @@ aot_table_init(AOTModuleInstance *module_inst, uint32 tbl_idx,
         return;
     }
 
-    if (!length) {
+    if (!length || !tbl_seg_init_values) {
         return;
     }
 
@@ -5699,43 +5804,62 @@ aot_resolve_function(const AOTModule *module, const char *function_name,
 bool
 aot_resolve_import_func(AOTModule *module, AOTImportFunc *import_func)
 {
-#if WASM_ENABLE_MULTI_MODULE != 0
-    char error_buf[128];
-    AOTModule *sub_module = NULL;
-#endif
-
+    /* from wasm_native */
     import_func->func_ptr_linked = wasm_native_resolve_symbol(
         import_func->module_name, import_func->func_name,
         import_func->func_type, &import_func->signature,
         &import_func->attachment, &import_func->call_conv_raw);
 
+    if (import_func->func_ptr_linked) {
+        return true;
+    }
+
 #if WASM_ENABLE_MULTI_MODULE != 0
-    if (!import_func->func_ptr_linked) {
-        if (!wasm_runtime_is_built_in_module(import_func->module_name)) {
-            sub_module = (AOTModule *)wasm_runtime_load_depended_module(
-                (WASMModuleCommon *)module, import_func->module_name, error_buf,
-                sizeof(error_buf));
-            if (!sub_module) {
-                LOG_WARNING("Failed to load sub module: %s", error_buf);
-            }
-            if (!sub_module)
-                import_func->func_ptr_linked = aot_resolve_function_ex(
-                    import_func->module_name, import_func->func_name,
-                    import_func->func_type, error_buf, sizeof(error_buf));
-            else
-                import_func->func_ptr_linked = aot_resolve_function(
-                    sub_module, import_func->func_name, import_func->func_type,
-                    error_buf, sizeof(error_buf));
-            if (!import_func->func_ptr_linked) {
-                LOG_WARNING("Failed to link function: %s", error_buf);
-            }
-        }
+    if (!import_func->module_name) {
+        LOG_VERBOSE(
+            "does't have module name for function %s. host should provide link",
+            import_func->func_name);
+        return false;
     }
+
+    /* from other .wasms' export functions */
+    char error_buf[128];
+    AOTModule *sub_module = (AOTModule *)wasm_runtime_load_depended_module(
+        (WASMModuleCommon *)module, import_func->module_name, error_buf,
+        sizeof(error_buf));
+
+    if (!sub_module) {
+        LOG_DEBUG("failed to load sub module: %s", error_buf);
+        // /*
+        //  * TOOD: seems aot_resolve_function_ex()'s only purpose is use
+        //  * wasm_runtime_find_module_registered() again, after
+        //  * wasm_runtime_load_depended_module() called.
+        //  */
+        // import_func->func_ptr_linked = aot_resolve_function_ex(
+        //     import_func->module_name, import_func->func_name,
+        //     import_func->func_type, error_buf, sizeof(error_buf));
+        return false;
+    }
+
+    import_func->func_ptr_linked = aot_resolve_function(
+        sub_module, import_func->func_name, import_func->func_type, error_buf,
+        sizeof(error_buf));
+    if (import_func->func_ptr_linked) {
+        import_func->import_module = sub_module;
+        return true;
+    }
+
+    LOG_WARNING("failed to link function (%s, %s): %s",
+                import_func->module_name, import_func->func_name, error_buf);
 #else
     (void)module;
 #endif
 
-    return import_func->func_ptr_linked != NULL;
+    LOG_DEBUG("can't resolve import function %s durning loading. wait for "
+              "instantiation linking",
+              import_func->func_name);
+
+    return false;
 }
 
 #if WASM_ENABLE_LIB_WASI_THREADS != 0 || WASM_ENABLE_THREAD_MGR != 0
@@ -5894,4 +6018,27 @@ aot_destroy_global(AOTGlobalInstance *global)
         return;
 
     wasm_runtime_free(global);
-}
+}
+
+AOTFunctionInstance *
+aot_create_function_empty(const AOTModule *module)
+{
+    /*TODO: might remove tailed AOTImportFunc */
+    AOTFunctionInstance *function = runtime_malloc(
+        sizeof(AOTFunctionInstance) + sizeof(AOTImportFunc), NULL, 0);
+    if (!function) {
+        return NULL;
+    }
+
+    function->u.func_import = (AOTImportFunc *)(function + 1);
+    return function;
+}
+
+void
+aot_destroy_function(AOTFunctionInstance *function)
+{
+    if (!function)
+        return;
+
+    wasm_runtime_free(function);
+}

+ 109 - 6
core/iwasm/aot/aot_runtime.h

@@ -105,14 +105,25 @@ typedef struct AOTFunctionInstance {
     char *func_name;
     uint32 func_index;
     bool is_import_func;
+
     union {
         struct {
             AOTFuncType *func_type;
-            /* function pointer linked */
             void *func_ptr;
         } func;
+        /* setup by wasm_native */
         AOTImportFunc *func_import;
     } u;
+
+    /* from other .wasm */
+    AOTModuleInstance *import_module_inst;
+    struct AOTFunctionInstance *import_func_inst;
+    /* copy it from AOTImportFunc */
+    bool call_conv_raw;
+    /* write it from wasm_c_api */
+    bool call_conv_wasm_c_api;
+    /* AOTModuleInstance collects it to form c_api_func_imports */
+    CApiFuncImport import_func_c_api;
 } AOTFunctionInstance;
 
 /* Map of a function index to the element ith in
@@ -143,13 +154,15 @@ typedef struct AOTModuleInstanceExtra {
      * created only when first time used.
      */
     ExportFuncMap *export_func_maps;
-    AOTFunctionInstance **functions;
+    AOTFunctionInstance *import_functions;
     uint32 function_count;
 
 #if WASM_ENABLE_MULTI_MODULE != 0
     bh_list sub_module_inst_list_head;
     bh_list *sub_module_inst_list;
-    WASMModuleInstanceCommon **import_func_module_insts;
+
+    /*TODO: remove*/
+    // WASMModuleInstanceCommon **import_func_module_insts;
 #endif
 
 #if WASM_ENABLE_SHARED_HEAP != 0
@@ -225,7 +238,7 @@ typedef struct AOTModule {
 
     /* function info */
     uint32 func_count;
-    /* func pointers of AOTed (un-imported) functions */
+    /* func pointers of AOTed (imported + local) functions */
     void **func_ptrs;
     /* func type indexes of AOTed (un-imported) functions */
     uint32 *func_type_indexes;
@@ -505,6 +518,67 @@ aot_locate_table_elems(const AOTModule *module, AOTTableInstance *table,
     return table->elems;
 }
 
+static inline AOTFunctionInstance *
+aot_locate_import_function_instance(const AOTModuleInstance *inst,
+                                    uint32 func_idx)
+{
+    AOTModule *module = (AOTModule *)inst->module;
+    if (func_idx >= module->import_func_count) {
+        LOG_ERROR("You can only locate import function instance by func_idx "
+                  "with this function.");
+        bh_assert(0);
+        return NULL;
+    }
+
+    AOTModuleInstanceExtra *e = (AOTModuleInstanceExtra *)inst->e;
+    AOTFunctionInstance *func = e->import_functions + func_idx;
+    bh_assert(func && "func is NULL");
+    return func;
+}
+
+static inline void *
+aot_get_function_pointer(const AOTModuleInstance *module_inst, uint32 func_idx)
+{
+    void **func_ptrs = module_inst->func_ptrs;
+    void *func_ptr = NULL;
+
+    AOTModule *module = (AOTModule *)module_inst->module;
+    if (func_idx < module->import_func_count) {
+        const AOTFunctionInstance *func_inst =
+            aot_locate_import_function_instance(module_inst, func_idx);
+
+        if (func_inst->call_conv_wasm_c_api) {
+            CApiFuncImport *c_api_func_import =
+                module_inst->c_api_func_imports
+                    ? module_inst->c_api_func_imports + func_idx
+                    : NULL;
+            func_ptr =
+                c_api_func_import ? c_api_func_import->func_ptr_linked : NULL;
+        }
+        else if (func_inst->call_conv_raw) {
+            func_ptr = func_ptrs[func_idx];
+        }
+        else {
+            if (func_inst->import_module_inst) {
+                /* from other module */
+                uint32 funx_idx_of_import_func =
+                    func_inst->import_func_inst->func_index;
+                func_ptr = func_inst->import_module_inst
+                               ->func_ptrs[funx_idx_of_import_func];
+            }
+            else {
+                /* from host APIs, like wasm_export.h, in the future */
+                func_ptr = func_ptrs[func_idx];
+            }
+        }
+    }
+    else {
+        func_ptr = func_ptrs[func_idx];
+    }
+
+    return func_ptr;
+}
+
 /**
  * Load a AOT module from aot file buffer
  * @param buf the byte buffer which contains the AOT file data
@@ -575,10 +649,10 @@ aot_instantiate(AOTModule *module, AOTModuleInstance *parent,
  * Deinstantiate a AOT module instance, destroy the resources.
  *
  * @param module_inst the AOT module instance to destroy
- * @param is_sub_inst the flag of sub instance
+ * @param is_spawned the flag of sub instance
  */
 void
-aot_deinstantiate(AOTModuleInstance *module_inst, bool is_sub_inst);
+aot_deinstantiate(AOTModuleInstance *module_inst, bool is_spawned);
 
 AOTMemoryInstance *
 aot_create_memory(const AOTModule *module, const AOTMemoryType *type);
@@ -932,6 +1006,35 @@ aot_set_global_value(AOTGlobalInstance *global, const WASMValue *value);
 void
 aot_destroy_global(AOTGlobalInstance *global);
 
+AOTFunctionInstance *
+aot_create_function_empty(const AOTModule *module);
+
+void
+aot_destroy_function(AOTFunctionInstance *function);
+
+static inline void
+aot_function_import_from_wasm(AOTFunctionInstance *func,
+                              AOTModuleInstance *dep_inst,
+                              AOTFunctionInstance *dep_func)
+{
+    func->import_module_inst = dep_inst;
+    func->import_func_inst = dep_func;
+}
+
+static inline void
+aot_function_import_from_c_api(AOTFunctionInstance *func,
+                               CApiFuncImport *c_api_func_import)
+{
+    func->import_func_c_api = *c_api_func_import;
+}
+
+/*might be unused*/
+static inline void
+aot_function_import_from_native(AOTFunctionInstance *func, void *callback)
+{
+    func->u.func_import->func_ptr_linked = callback;
+}
+
 #ifdef __cplusplus
 } /* end of extern "C" */
 #endif

+ 138 - 46
core/iwasm/common/wasm_c_api.c

@@ -744,27 +744,6 @@ wasm_store_delete(wasm_store_t *store)
 }
 
 /* Type Representations */
-static inline wasm_valkind_t
-val_type_rt_2_valkind(uint8 val_type_rt)
-{
-    switch (val_type_rt) {
-#define WAMR_VAL_TYPE_2_WASM_VAL_KIND(name) \
-    case VALUE_TYPE_##name:                 \
-        return WASM_##name;
-
-        WAMR_VAL_TYPE_2_WASM_VAL_KIND(I32)
-        WAMR_VAL_TYPE_2_WASM_VAL_KIND(I64)
-        WAMR_VAL_TYPE_2_WASM_VAL_KIND(F32)
-        WAMR_VAL_TYPE_2_WASM_VAL_KIND(F64)
-        WAMR_VAL_TYPE_2_WASM_VAL_KIND(V128)
-        WAMR_VAL_TYPE_2_WASM_VAL_KIND(FUNCREF)
-#undef WAMR_VAL_TYPE_2_WASM_VAL_KIND
-
-        default:
-            return WASM_EXTERNREF;
-    }
-}
-
 static wasm_valtype_t *
 wasm_valtype_new_internal(uint8 val_type_rt)
 {
@@ -970,6 +949,7 @@ wasm_functype_results(const wasm_functype_t *func_type)
     return func_type->results;
 }
 
+#if WASM_ENABLE_MULTI_MODULE != 0
 static bool
 cmp_val_kind_with_val_type(wasm_valkind_t v_k, uint8 v_t)
 {
@@ -1012,6 +992,7 @@ wasm_functype_same_internal(const wasm_functype_t *type,
 
     return true;
 }
+#endif /* WASM_ENABLE_MULTI_MODULE != 0 */
 
 wasm_globaltype_t *
 wasm_globaltype_new(own wasm_valtype_t *val_type, wasm_mutability_t mut)
@@ -3104,7 +3085,7 @@ wasm_func_new_with_env(wasm_store_t *store, const wasm_functype_t *type,
 }
 
 wasm_func_t *
-wasm_func_new_internal(wasm_store_t *store, uint16 func_idx_rt,
+wasm_func_new_internal(wasm_store_t *store, uint32 func_idx_rt,
                        WASMModuleInstanceCommon *inst_comm_rt)
 {
     wasm_func_t *func = NULL;
@@ -3605,47 +3586,42 @@ wasm_global_delete(wasm_global_t *global)
 
 #if WASM_ENABLE_INTERP != 0
 static bool
-interp_global_set(const WASMModuleInstance *inst_interp, uint16 global_idx_rt,
+interp_global_set(const WASMModuleInstance *inst_interp, uint32 global_idx_rt,
                   const wasm_val_t *v)
 {
     const WASMGlobalInstance *global_interp =
         inst_interp->e->globals + global_idx_rt;
     uint8 val_type_rt = global_interp->type;
-#if WASM_ENABLE_MULTI_MODULE != 0
-    uint8 *data = global_interp->import_global_inst
+
+    uint8 *data = global_interp->import_module_inst
                       ? global_interp->import_module_inst->global_data
                             + global_interp->import_global_inst->data_offset
                       : inst_interp->global_data + global_interp->data_offset;
-#else
-    uint8 *data = inst_interp->global_data + global_interp->data_offset;
-#endif
 
     return wasm_val_to_rt_val((WASMModuleInstanceCommon *)inst_interp,
                               val_type_rt, v, data);
 }
 
 static bool
-interp_global_get(const WASMModuleInstance *inst_interp, uint16 global_idx_rt,
+interp_global_get(const WASMModuleInstance *inst_interp, uint32 global_idx_rt,
                   wasm_val_t *out)
 {
     WASMGlobalInstance *global_interp = inst_interp->e->globals + global_idx_rt;
     uint8 val_type_rt = global_interp->type;
-#if WASM_ENABLE_MULTI_MODULE != 0
-    uint8 *data = global_interp->import_global_inst
+
+    uint8 *data = global_interp->import_module_inst
                       ? global_interp->import_module_inst->global_data
                             + global_interp->import_global_inst->data_offset
                       : inst_interp->global_data + global_interp->data_offset;
-#else
-    uint8 *data = inst_interp->global_data + global_interp->data_offset;
-#endif
 
     return rt_val_to_wasm_val(data, val_type_rt, out);
 }
 #endif
 
 #if WASM_ENABLE_AOT != 0
+/*TODO: get_global_addr() */
 static bool
-aot_global_set(const AOTModuleInstance *inst_aot, uint16 global_idx_rt,
+aot_global_set(const AOTModuleInstance *inst_aot, uint32 global_idx_rt,
                const wasm_val_t *v)
 {
     AOTModule *module_aot = (AOTModule *)inst_aot->module;
@@ -3672,7 +3648,7 @@ aot_global_set(const AOTModuleInstance *inst_aot, uint16 global_idx_rt,
 }
 
 static bool
-aot_global_get(const AOTModuleInstance *inst_aot, uint16 global_idx_rt,
+aot_global_get(const AOTModuleInstance *inst_aot, uint32 global_idx_rt,
                wasm_val_t *out)
 {
     AOTModule *module_aot = (AOTModule *)inst_aot->module;
@@ -3765,7 +3741,7 @@ wasm_global_get(const wasm_global_t *global, wasm_val_t *out)
 }
 
 wasm_global_t *
-wasm_global_new_internal(wasm_store_t *store, uint16 global_idx_rt,
+wasm_global_new_internal(wasm_store_t *store, uint32 global_idx_rt,
                          WASMModuleInstanceCommon *inst_comm_rt)
 {
     wasm_global_t *global = NULL;
@@ -3892,7 +3868,7 @@ wasm_table_new_basic(wasm_store_t *store, const wasm_tabletype_t *type)
 }
 
 wasm_table_t *
-wasm_table_new_internal(wasm_store_t *store, uint16 table_idx_rt,
+wasm_table_new_internal(wasm_store_t *store, uint32 table_idx_rt,
                         WASMModuleInstanceCommon *inst_comm_rt)
 {
     wasm_table_t *table = NULL;
@@ -4272,7 +4248,7 @@ wasm_memory_copy(const wasm_memory_t *src)
 }
 
 wasm_memory_t *
-wasm_memory_new_internal(wasm_store_t *store, uint16 memory_idx_rt,
+wasm_memory_new_internal(wasm_store_t *store, uint32 memory_idx_rt,
                          WASMModuleInstanceCommon *inst_comm_rt)
 {
     wasm_memory_t *memory = NULL;
@@ -4488,9 +4464,10 @@ wasm_memory_grow(wasm_memory_t *memory, wasm_memory_pages_t delta)
 }
 
 #if WASM_ENABLE_INTERP != 0
+#if WASM_ENABLE_MULTI_MODULE != 0
 static bool
 interp_link_func(const wasm_instance_t *inst, const WASMModule *module_interp,
-                 uint16 func_idx_rt, wasm_func_t *import)
+                 uint32 func_idx_rt, wasm_func_t *import)
 {
     WASMImport *imported_func_interp = NULL;
 
@@ -4512,6 +4489,8 @@ interp_link_func(const wasm_instance_t *inst, const WASMModule *module_interp,
         return false;
 
     imported_func_interp->u.function.call_conv_wasm_c_api = true;
+
+    /*TODO: we can avoid this step */
     /* only set func_ptr_linked to avoid unlink warning during instantiation,
        func_ptr_linked, with_env and env will be stored in module instance's
        c_api_func_imports later and used when calling import function */
@@ -4528,7 +4507,7 @@ interp_link_func(const wasm_instance_t *inst, const WASMModule *module_interp,
 }
 
 static bool
-interp_link_global(const WASMModule *module_interp, uint16 global_idx_rt,
+interp_link_global(const WASMModule *module_interp, uint32 global_idx_rt,
                    wasm_global_t *import)
 {
     WASMImport *imported_global_interp = NULL;
@@ -4578,6 +4557,7 @@ interp_link_global(const WASMModule *module_interp, uint16 global_idx_rt,
     imported_global_interp->u.global.is_linked = true;
     return true;
 }
+#endif /* WASM_ENABLE_MULTI_MODULE != 0 */
 
 static bool
 interp_process_export(wasm_store_t *store,
@@ -4667,6 +4647,7 @@ failed:
 #endif /* WASM_ENABLE_INTERP */
 
 #if WASM_ENABLE_AOT != 0
+#if WASM_ENABLE_MULTI_MODULE != 0
 static bool
 aot_link_func(const wasm_instance_t *inst, const AOTModule *module_aot,
               uint32 import_func_idx_rt, wasm_func_t *import)
@@ -4702,7 +4683,7 @@ aot_link_func(const wasm_instance_t *inst, const AOTModule *module_aot,
 }
 
 static bool
-aot_link_global(const AOTModule *module_aot, uint16 global_idx_rt,
+aot_link_global(const AOTModule *module_aot, uint32 global_idx_rt,
                 wasm_global_t *import)
 {
     AOTImportGlobal *import_aot_global = NULL;
@@ -4749,6 +4730,7 @@ failed:
     LOG_DEBUG("%s failed", __FUNCTION__);
     return false;
 }
+#endif /* WASM_ENABLE_MULTI_MODULE != 0*/
 
 static bool
 aot_process_export(wasm_store_t *store, const AOTModuleInstance *inst_aot,
@@ -4843,6 +4825,7 @@ failed:
 }
 #endif /* WASM_ENABLE_AOT */
 
+#if WASM_ENABLE_MULTI_MODULE != 0
 static bool
 do_link(const wasm_instance_t *inst, const wasm_module_t *module,
         const wasm_extern_vec_t *imports)
@@ -4931,6 +4914,7 @@ failed:
     LOG_DEBUG("%s failed", __FUNCTION__);
     return false;
 }
+#endif /* WASM_ENABLE_MULTI_MODULE != 0 */
 
 wasm_instance_t *
 wasm_instance_new(wasm_store_t *store, const wasm_module_t *module,
@@ -4953,6 +4937,70 @@ wasm_instance_new_with_args(wasm_store_t *store, const wasm_module_t *module,
                                           &inst_args);
 }
 
+bool
+wasm_instance_create_import_list(const wasm_module_t *module,
+                                 const wasm_extern_vec_t *imports_src,
+                                 WASMExternInstance **imports_dst,
+                                 uint32 *imports_dst_count)
+{
+    *imports_dst = NULL;
+    *imports_dst_count = 0;
+
+    if (!imports_src) {
+        LOG_VERBOSE("doesn't provide imports\n");
+        *imports_dst_count = 0;
+        return true;
+    }
+
+    wasm_importtype_vec_t import_types = { 0 };
+    wasm_module_imports(module, &import_types);
+
+    if (import_types.num_elems == 0) {
+        LOG_VERBOSE("module has no imports\n");
+        return true;
+    }
+
+    if (import_types.num_elems > imports_src->num_elems) {
+        LOG_ERROR("module has %d imports but only %d provided. Placeholders "
+                  "are even allowed.\n",
+                  import_types.num_elems, imports_src->num_elems);
+        return false;
+    }
+
+    *imports_dst = malloc_internal((uint64)sizeof(WASMExternInstance)
+                                   * imports_src->num_elems);
+    if (!*imports_dst) {
+        return false;
+    }
+
+    *imports_dst_count = (uint32)imports_src->num_elems;
+
+    uint32 i = 0;
+    WASMExternInstance *import_out = *imports_dst;
+    for (; i < imports_src->num_elems; i++, import_out++) {
+        wasm_importtype_t *import_type = import_types.data[i];
+        wasm_extern_t *import_in = imports_src->data[i];
+
+        if (!import_in) {
+            LOG_VERBOSE("imports[%d] is NULL and wasm_native may provide it\n",
+                        i);
+            continue;
+        }
+
+        if (!extern_t_to_WASMExternInstance(module, import_in, import_type,
+                                            import_out)) {
+            wasm_runtime_destroy_imports(*module, *imports_dst);
+            wasm_runtime_free(*imports_dst);
+
+            *imports_dst = NULL;
+            *imports_dst_count = 0;
+            return false;
+        }
+    }
+
+    return true;
+}
+
 wasm_instance_t *
 wasm_instance_new_with_args_ex(wasm_store_t *store, const wasm_module_t *module,
                                const wasm_extern_vec_t *imports,
@@ -4985,7 +5033,33 @@ wasm_instance_new_with_args_ex(wasm_store_t *store, const wasm_module_t *module,
         goto failed;
     }
 
-    /* executes the instantiate-time linking if provided */
+#if WASM_ENABLE_MULTI_MODULE == 0
+    /* do instantiation-linking */
+    struct WASMExternInstance *imports_out = NULL;
+    uint32 imports_out_count = 0;
+    if (!wasm_instance_create_import_list(module, imports, &imports_out,
+                                          &imports_out_count)) {
+        snprintf(sub_error_buf, sizeof(sub_error_buf),
+                 "Failed to create import list");
+        goto failed;
+    }
+
+    InstantiationArgs inst_args_w_imports = *inst_args;
+    inst_args_w_imports.imports = imports_out;
+    inst_args_w_imports.import_count = imports_out_count;
+
+    /*
+     * will do the linking result check at the end of
+     * wasm_runtime_instantiate
+     */
+    instance->inst_comm_rt = wasm_runtime_instantiate_ex(
+        *module, &inst_args_w_imports, sub_error_buf, sizeof(sub_error_buf));
+    if (!instance->inst_comm_rt) {
+        goto failed;
+    }
+    wasm_runtime_destroy_imports(*module, imports_out);
+#else
+    /* do loading-linking */
     if (imports) {
         if (!do_link(instance, module, imports)) {
             snprintf(sub_error_buf, sizeof(sub_error_buf),
@@ -4993,15 +5067,17 @@ wasm_instance_new_with_args_ex(wasm_store_t *store, const wasm_module_t *module,
             goto failed;
         }
     }
+
     /*
-     * will do the linking result check at the end of wasm_runtime_instantiate
+     * will do the linking result check at the end of
+     * wasm_runtime_instantiate
      */
-
     instance->inst_comm_rt = wasm_runtime_instantiate_ex(
         *module, inst_args, sub_error_buf, sizeof(sub_error_buf));
     if (!instance->inst_comm_rt) {
         goto failed;
     }
+#endif
 
     if (!wasm_runtime_create_exec_env_singleton(instance->inst_comm_rt)) {
         snprintf(sub_error_buf, sizeof(sub_error_buf),
@@ -5066,28 +5142,44 @@ wasm_instance_new_with_args_ex(wasm_store_t *store, const wasm_module_t *module,
         func_import++;
     }
 
-    /* fill with inst */
+    /* fill with inst and index in space(X) */
+    uint32 function_idx_rt = 0;
+    uint32 global_idx_rt = 0;
+    uint32 memory_idx_rt = 0;
+    uint32 table_idx_rt = 0;
     for (i = 0; imports && imports->data && i < imports->num_elems; ++i) {
         wasm_extern_t *import = imports->data[i];
         bh_assert(import);
 
         switch (import->kind) {
             case WASM_EXTERN_FUNC:
+            {
                 wasm_extern_as_func(import)->inst_comm_rt =
                     instance->inst_comm_rt;
+                wasm_extern_as_func(import)->func_idx_rt = function_idx_rt++;
                 break;
+            }
             case WASM_EXTERN_GLOBAL:
+            {
                 wasm_extern_as_global(import)->inst_comm_rt =
                     instance->inst_comm_rt;
+                wasm_extern_as_global(import)->global_idx_rt = global_idx_rt++;
                 break;
+            }
             case WASM_EXTERN_MEMORY:
+            {
                 wasm_extern_as_memory(import)->inst_comm_rt =
                     instance->inst_comm_rt;
+                wasm_extern_as_memory(import)->memory_idx_rt = memory_idx_rt++;
                 break;
+            }
             case WASM_EXTERN_TABLE:
+            {
                 wasm_extern_as_table(import)->inst_comm_rt =
                     instance->inst_comm_rt;
+                wasm_extern_as_table(import)->table_idx_rt = table_idx_rt++;
                 break;
+            }
             default:
                 snprintf(sub_error_buf, sizeof(sub_error_buf),
                          "Unknown import kind");

+ 31 - 9
core/iwasm/common/wasm_c_api_internal.h

@@ -70,7 +70,7 @@ struct wasm_memorytype_t {
 };
 
 struct wasm_externtype_t {
-    uint32 extern_kind;
+    wasm_externkind_t extern_kind;
     /* reserved space */
     uint8 data[1];
 };
@@ -146,7 +146,7 @@ struct wasm_func_t {
      * an index in both functions runtime instance lists
      * of interpreter mode and aot mode
      */
-    uint16 func_idx_rt;
+    uint32 func_idx_rt;
     WASMModuleInstanceCommon *inst_comm_rt;
     WASMFunctionInstanceCommon *func_comm_rt;
 };
@@ -164,7 +164,7 @@ struct wasm_global_t {
      * an index in both global runtime instance lists
      * of interpreter mode and aot mode
      */
-    uint16 global_idx_rt;
+    uint32 global_idx_rt;
     WASMModuleInstanceCommon *inst_comm_rt;
 };
 
@@ -180,7 +180,7 @@ struct wasm_memory_t {
      * an index in both memory runtime instance lists
      * of interpreter mode and aot mode
      */
-    uint16 memory_idx_rt;
+    uint32 memory_idx_rt;
     WASMModuleInstanceCommon *inst_comm_rt;
 };
 
@@ -196,7 +196,7 @@ struct wasm_table_t {
      * an index in both table runtime instance lists
      * of interpreter mode and aot mode
      */
-    uint16 table_idx_rt;
+    uint32 table_idx_rt;
     WASMModuleInstanceCommon *inst_comm_rt;
 };
 
@@ -226,21 +226,43 @@ wasm_foreign_new_internal(wasm_store_t *store, uint32 foreign_idx_rt,
                           WASMModuleInstanceCommon *inst_comm_rt);
 
 wasm_func_t *
-wasm_func_new_internal(wasm_store_t *store, uint16 func_idx_rt,
+wasm_func_new_internal(wasm_store_t *store, uint32 func_idx_rt,
                        WASMModuleInstanceCommon *inst_comm_rt);
 
 wasm_global_t *
-wasm_global_new_internal(wasm_store_t *store, uint16 global_idx_rt,
+wasm_global_new_internal(wasm_store_t *store, uint32 global_idx_rt,
                          WASMModuleInstanceCommon *inst_comm_rt);
 
 wasm_memory_t *
-wasm_memory_new_internal(wasm_store_t *store, uint16 memory_idx_rt,
+wasm_memory_new_internal(wasm_store_t *store, uint32 memory_idx_rt,
                          WASMModuleInstanceCommon *inst_comm_rt);
 
 wasm_table_t *
-wasm_table_new_internal(wasm_store_t *store, uint16 table_idx_rt,
+wasm_table_new_internal(wasm_store_t *store, uint32 table_idx_rt,
                         WASMModuleInstanceCommon *inst_comm_rt);
 
 void
 wasm_frame_vec_clone_internal(Vector *src, Vector *out);
+
+/* type conversions */
+wasm_valkind_t
+val_type_rt_2_valkind(uint8 val_type_rt);
+
+bool
+valkind_to_WASMValueType(wasm_valkind_t src, uint8 *dst);
+
+wasm_import_export_kind_t
+externkind_to_import_export_kind(wasm_externkind_t src);
+
+bool
+globaltype_to_WASMGlobalType(wasm_globaltype_t *src, WASMGlobalType *dst);
+
+bool
+val_to_WASMValue(wasm_val_t *src, WASMValue *dst);
+
+bool
+extern_t_to_WASMExternInstance(const wasm_module_t *module, wasm_extern_t *src,
+                               wasm_importtype_t *type,
+                               WASMExternInstance *dst);
+
 #endif /* _WASM_C_API_INTERNAL_H */

+ 196 - 0
core/iwasm/common/wasm_c_api_type_conv.c

@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2019 Intel Corporation.  All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#include "bh_log.h"
+#include "wasm_c_api_internal.h"
+#include "wasm_export.h"
+#include "wasm_runtime_common.h"
+
+/* wasm_export.h types -> wasm_c_api.h types*/
+
+wasm_valkind_t
+val_type_rt_2_valkind(uint8 val_type_rt)
+{
+    switch (val_type_rt) {
+#define WAMR_VAL_TYPE_2_WASM_VAL_KIND(name) \
+    case VALUE_TYPE_##name:                 \
+        return WASM_##name;
+
+        WAMR_VAL_TYPE_2_WASM_VAL_KIND(I32)
+        WAMR_VAL_TYPE_2_WASM_VAL_KIND(I64)
+        WAMR_VAL_TYPE_2_WASM_VAL_KIND(F32)
+        WAMR_VAL_TYPE_2_WASM_VAL_KIND(F64)
+        WAMR_VAL_TYPE_2_WASM_VAL_KIND(V128)
+        WAMR_VAL_TYPE_2_WASM_VAL_KIND(FUNCREF)
+#undef WAMR_VAL_TYPE_2_WASM_VAL_KIND
+
+        default:
+            return WASM_EXTERNREF;
+    }
+}
+
+/* wasm_c_api.h types -> wasm_export.h types*/
+bool
+valkind_to_WASMValueType(wasm_valkind_t src, uint8 *dst)
+{
+    switch (src) {
+#define WASM_VAL_KIND_2_WAMR_VAL_TYPE(name) \
+    case WASM_##name:                       \
+    {                                       \
+        *dst = VALUE_TYPE_##name;           \
+        return true;                        \
+    }
+
+        WASM_VAL_KIND_2_WAMR_VAL_TYPE(I32)
+        WASM_VAL_KIND_2_WAMR_VAL_TYPE(I64)
+        WASM_VAL_KIND_2_WAMR_VAL_TYPE(F32)
+        WASM_VAL_KIND_2_WAMR_VAL_TYPE(F64)
+        WASM_VAL_KIND_2_WAMR_VAL_TYPE(V128)
+        WASM_VAL_KIND_2_WAMR_VAL_TYPE(FUNCREF)
+#undef WASM_VAL_KIND_2_WAMR_VAL_TYPE
+
+        default:
+        {
+            bh_assert(0);
+            return false;
+        }
+    }
+}
+
+wasm_import_export_kind_t
+externkind_to_import_export_kind(wasm_externkind_t src)
+{
+    if (src == WASM_EXTERN_FUNC) {
+        return WASM_IMPORT_EXPORT_KIND_FUNC;
+    }
+    else if (src == WASM_EXTERN_GLOBAL) {
+        return WASM_IMPORT_EXPORT_KIND_GLOBAL;
+    }
+    else if (src == WASM_EXTERN_TABLE) {
+        return WASM_IMPORT_EXPORT_KIND_TABLE;
+    }
+    else if (src == WASM_EXTERN_MEMORY) {
+        return WASM_IMPORT_EXPORT_KIND_MEMORY;
+    }
+    else {
+        bh_assert(0);
+        LOG_ERROR("Invalid wasm_externkind_t value. Can't convert to "
+                  "wasm_import_export_kind_t");
+        return 0;
+    }
+}
+
+bool
+globaltype_to_WASMGlobalType(wasm_globaltype_t *src, WASMGlobalType *dst)
+{
+    if (!valkind_to_WASMValueType(src->val_type->kind, &dst->val_type)) {
+        return false;
+    }
+
+    dst->is_mutable = src->mutability == WASM_VAR ? WASM_VAR : WASM_CONST;
+    return true;
+}
+
+bool
+func_to_CApiFuncImport(wasm_func_t *src, CApiFuncImport *dst)
+{
+    dst->func_ptr_linked =
+        src->with_env ? (void *)src->u.cb_env.cb : (void *)src->u.cb;
+    dst->with_env_arg = src->with_env;
+    dst->env_arg = src->u.cb_env.env;
+    return true;
+}
+
+bool
+extern_t_to_WASMExternInstance(const wasm_module_t *module, wasm_extern_t *src,
+                               wasm_importtype_t *type, WASMExternInstance *dst)
+{
+    dst->module_name = wasm_importtype_module(type)->data;
+    dst->field_name = wasm_importtype_name(type)->data;
+
+    dst->kind = externkind_to_import_export_kind(wasm_extern_kind(src));
+
+    switch (wasm_extern_kind(src)) {
+        case WASM_EXTERN_FUNC:
+        {
+            wasm_func_t *function_in = wasm_extern_as_func(src);
+
+            CApiFuncImport c_api_info = { 0 };
+            func_to_CApiFuncImport(function_in, &c_api_info);
+
+            dst->u.function =
+                wasm_runtime_create_function_c_api(*module, &c_api_info);
+            if (!dst->u.function) {
+                return false;
+            }
+
+            break;
+        }
+        case WASM_EXTERN_GLOBAL:
+        {
+            wasm_global_t *global_in = wasm_extern_as_global(src);
+
+            WASMGlobalType global_type = { 0 };
+            if (!globaltype_to_WASMGlobalType(wasm_global_type(global_in),
+                                              &global_type)) {
+                return false;
+            }
+
+            dst->u.global = wasm_runtime_create_global_internal(*module, NULL,
+                                                                &global_type);
+            if (!dst->u.global) {
+                return false;
+            }
+
+            /* set init value */
+            switch (global_in->init->kind) {
+                case WASM_I32:
+                {
+                    WASMValue val = { .i32 = global_in->init->of.i32 };
+                    wasm_runtime_set_global_value(*module, dst->u.global, &val);
+                    break;
+                }
+                case WASM_I64:
+                {
+                    WASMValue val = { .i64 = global_in->init->of.i64 };
+                    wasm_runtime_set_global_value(*module, dst->u.global, &val);
+                    break;
+                }
+                case WASM_F32:
+                {
+                    WASMValue val = { .f32 = global_in->init->of.f32 };
+                    wasm_runtime_set_global_value(*module, dst->u.global, &val);
+                    break;
+                }
+                case WASM_F64:
+                {
+                    WASMValue val = { .f64 = global_in->init->of.f64 };
+                    wasm_runtime_set_global_value(*module, dst->u.global, &val);
+                    break;
+                }
+                default:
+                {
+                    return false;
+                }
+            }
+
+            break;
+        }
+        case WASM_EXTERN_MEMORY:
+        {
+            break;
+        }
+        case WASM_EXTERN_TABLE:
+        {
+            break;
+        }
+        default:
+        {
+            return false;
+        }
+    }
+
+    return true;
+}

+ 2 - 1
core/iwasm/common/wasm_loader_common.c

@@ -51,9 +51,10 @@ check_memory64_flags_consistency(WASMModule *module, char *error_buf,
 #endif
 
 bool
-wasm_memory_check_flags(const uint8 mem_flag, char *error_buf,
+wasm_memory_check_flags(const uint32 mem_flag_w, char *error_buf,
                         uint32 error_buf_size, bool is_aot)
 {
+    uint8 mem_flag = (uint8)(mem_flag_w & 0xFF);
     /* Check whether certain features indicated by mem_flag are enabled in
      * runtime */
     if (mem_flag > MAX_PAGE_COUNT_FLAG) {

+ 1 - 1
core/iwasm/common/wasm_loader_common.h

@@ -22,7 +22,7 @@ check_memory64_flags_consistency(WASMModule *module, char *error_buf,
 #endif
 
 bool
-wasm_memory_check_flags(const uint8 mem_flag, char *error_buf,
+wasm_memory_check_flags(const uint32 mem_flag, char *error_buf,
                         uint32 error_buf_size, bool is_aot);
 
 bool

+ 144 - 39
core/iwasm/common/wasm_runtime_common.c

@@ -1681,17 +1681,17 @@ wasm_runtime_instantiate_ex(WASMModuleCommon *module,
 
 void
 wasm_runtime_deinstantiate_internal(WASMModuleInstanceCommon *module_inst,
-                                    bool is_sub_inst)
+                                    bool is_spawned)
 {
 #if WASM_ENABLE_INTERP != 0
     if (module_inst->module_type == Wasm_Module_Bytecode) {
-        wasm_deinstantiate((WASMModuleInstance *)module_inst, is_sub_inst);
+        wasm_deinstantiate((WASMModuleInstance *)module_inst, is_spawned);
         return;
     }
 #endif
 #if WASM_ENABLE_AOT != 0
     if (module_inst->module_type == Wasm_Module_AoT) {
-        aot_deinstantiate((AOTModuleInstance *)module_inst, is_sub_inst);
+        aot_deinstantiate((AOTModuleInstance *)module_inst, is_spawned);
         return;
     }
 #endif
@@ -7562,8 +7562,12 @@ wasm_runtime_sub_module_instantiate(WASMModuleCommon *module,
             bh_list_first_elem(((WASMModule *)module)->import_module_list);
     }
 #endif
+    if (!sub_module_inst_list) {
+        LOG_ERROR("unknown module type %d", module->module_type);
+        return false;
+    }
+
     while (sub_module_list_node) {
-        WASMSubModInstNode *sub_module_inst_list_node = NULL;
         WASMModuleCommon *sub_module = sub_module_list_node->module;
         WASMModuleInstanceCommon *sub_module_inst = NULL;
         sub_module_inst = wasm_runtime_instantiate_internal(
@@ -7576,8 +7580,10 @@ wasm_runtime_sub_module_instantiate(WASMModuleCommon *module,
                       sub_module_list_node->module_name);
             return false;
         }
-        sub_module_inst_list_node = loader_malloc(sizeof(WASMSubModInstNode),
-                                                  error_buf, error_buf_size);
+
+        WASMSubModInstNode *sub_module_inst_list_node = loader_malloc(
+            sizeof(WASMSubModInstNode), error_buf, error_buf_size);
+
         if (!sub_module_inst_list_node) {
             LOG_DEBUG("Malloc WASMSubModInstNode failed, SZ: %zu",
                       sizeof(WASMSubModInstNode));
@@ -7585,36 +7591,10 @@ wasm_runtime_sub_module_instantiate(WASMModuleCommon *module,
                 wasm_runtime_deinstantiate_internal(sub_module_inst, false);
             return false;
         }
-        sub_module_inst_list_node->module_inst =
-            (WASMModuleInstance *)sub_module_inst;
+        sub_module_inst_list_node->module_inst = sub_module_inst;
         sub_module_inst_list_node->module_name =
             sub_module_list_node->module_name;
 
-#if WASM_ENABLE_AOT != 0
-        if (module_inst->module_type == Wasm_Module_AoT) {
-            AOTModuleInstance *aot_module_inst =
-                (AOTModuleInstance *)module_inst;
-            AOTModule *aot_module = (AOTModule *)module;
-            AOTModuleInstanceExtra *aot_extra =
-                (AOTModuleInstanceExtra *)aot_module_inst->e;
-            uint32 i;
-            AOTImportFunc *import_func;
-            for (i = 0; i < aot_module->import_func_count; i++) {
-                if (aot_extra->import_func_module_insts[i])
-                    continue;
-
-                import_func = &aot_module->import_funcs[i];
-                if (strcmp(sub_module_inst_list_node->module_name,
-                           import_func->module_name)
-                    == 0) {
-                    aot_extra->import_func_module_insts[i] =
-                        (WASMModuleInstanceCommon *)
-                            sub_module_inst_list_node->module_inst;
-                }
-            }
-        }
-#endif
-
         bh_list_status ret =
             bh_list_insert(sub_module_inst_list, sub_module_inst_list_node);
         bh_assert(BH_LIST_SUCCESS == ret);
@@ -8089,7 +8069,11 @@ wasm_runtime_destroy_extern_inst(WASMModuleCommon *module,
     if (!extern_inst)
         return;
 
-    if (extern_inst->kind == WASM_IMPORT_EXPORT_KIND_MEMORY) {
+    if (extern_inst->kind == WASM_IMPORT_EXPORT_KIND_FUNC) {
+        wasm_runtime_destroy_function(module, extern_inst->u.function);
+        extern_inst->u.function = NULL;
+    }
+    else if (extern_inst->kind == WASM_IMPORT_EXPORT_KIND_MEMORY) {
         wasm_runtime_destroy_memory(module, extern_inst->u.memory);
         extern_inst->u.memory = NULL;
     }
@@ -8111,24 +8095,145 @@ wasm_runtime_destroy_extern_inst(WASMModuleCommon *module,
     extern_inst->field_name = NULL;
 }
 
-#if WASM_ENABLE_SPEC_TEST != 0 || WASM_ENABLE_WASI_TEST != 0
+WASMFunctionInstanceCommon *
+wasm_runtime_create_function_wasm(struct WASMModuleCommon *const module,
+                                  WASMModuleInstanceCommon *dep_inst,
+                                  WASMFunctionInstanceCommon *dep_func)
+{
+#if WASM_ENABLE_INTERP != 0
+    if (module->module_type == Wasm_Module_Bytecode) {
+        WASMFunctionInstance *func_empty =
+            wasm_create_function_empty((const WASMModule *)module);
+        func_empty->is_import_func = true;
+
+        func_empty->import_module_inst = (WASMModuleInstance *)dep_inst;
+        func_empty->import_func_inst = (WASMFunctionInstance *)dep_func;
+        return (WASMFunctionInstanceCommon *)func_empty;
+    }
+#endif
+
+#if WASM_ENABLE_AOT != 0
+    if (module->module_type == Wasm_Module_AoT) {
+        bh_assert(false && "not supported yet");
+    }
+#endif
+
+    LOG_ERROR("create function failed, invalid module type %d",
+              module->module_type);
+    return NULL;
+}
+
+WASMFunctionInstanceCommon *
+wasm_runtime_create_function_c_api(struct WASMModuleCommon *const module,
+                                   CApiFuncImport *c_api_info)
+{
+#if WASM_ENABLE_INTERP != 0
+    if (module->module_type == Wasm_Module_Bytecode) {
+        WASMFunctionInstance *func_empty =
+            wasm_create_function_empty((const WASMModule *)module);
+        func_empty->is_import_func = true;
+
+        func_empty->import_func_c_api = *c_api_info;
+        func_empty->call_conv_wasm_c_api = true;
+        return (WASMFunctionInstanceCommon *)func_empty;
+    }
+#endif
+
+#if WASM_ENABLE_AOT != 0
+    if (module->module_type == Wasm_Module_AoT) {
+        AOTFunctionInstance *func_empty =
+            aot_create_function_empty((const AOTModule *)module);
+        func_empty->is_import_func = true;
+
+        func_empty->import_func_c_api = *c_api_info;
+        func_empty->call_conv_wasm_c_api = true;
+        return (AOTFunctionInstance *)func_empty;
+    }
+#endif
+
+    LOG_ERROR("create function failed, invalid module type %d",
+              module->module_type);
+    return NULL;
+}
+
+/*might be unused*/
+WASMFunctionInstanceCommon *
+wasm_runtime_create_function_native(struct WASMModuleCommon *const module,
+                                    void *callback)
+{
+#if WASM_ENABLE_INTERP != 0
+    if (module->module_type == Wasm_Module_Bytecode) {
+        WASMFunctionInstance *func_empty =
+            wasm_create_function_empty((const WASMModule *)module);
+        func_empty->is_import_func = true;
+
+        func_empty->u.func_import->func_ptr_linked = callback;
+        /*TBC: ?*/
+        func_empty->call_conv_raw = false;
+
+        return (WASMFunctionInstanceCommon *)func_empty;
+    }
+#endif
+
+#if WASM_ENABLE_AOT != 0
+    if (module->module_type == Wasm_Module_AoT) {
+        bh_assert(false && "not supported yet");
+    }
+#endif
+
+    LOG_ERROR("create function failed, invalid module type %d",
+              module->module_type);
+    return NULL;
+}
+
+WASMFunctionInstanceCommon *
+wasm_runtime_create_function(struct WASMModuleCommon *const module,
+                             struct WASMFuncType *const type, void *callback)
+{
+    bh_assert(false && "unimplemented");
+    return NULL;
+}
+
+void
+wasm_runtime_destroy_function(struct WASMModuleCommon *const module,
+                              WASMFunctionInstanceCommon *func)
+{
+#if WASM_ENABLE_INTERP != 0
+    if (module->module_type == Wasm_Module_Bytecode) {
+        wasm_destroy_function(func);
+        return;
+    }
+#endif
+
+#if WASM_ENABLE_AOT != 0
+    if (module->module_type == Wasm_Module_AoT) {
+        bh_assert(false && "not supported yet");
+        // aot_destroy_function(func);
+        return;
+    }
+#endif
+
+    LOG_ERROR("destroy function failed, invalid module type %d",
+              module->module_type);
+    return;
+}
+
 /*
  * Be aware that it will remove all items in the list, regardless of whether
  * they were created by the runtime (for built-ins) or by users.
  */
-static void
+void
 wasm_runtime_destroy_imports(WASMModuleCommon *module,
                              WASMExternInstance *extern_inst_list)
 {
     if (!module || !extern_inst_list)
         return;
 
-    for (int32 i = 0, import_count = wasm_runtime_get_import_count(module);
-         i < import_count; i++) {
+    int32 import_count = wasm_runtime_get_import_count(module);
+    for (int32 i = 0; i < import_count; i++) {
         wasm_runtime_destroy_extern_inst(module, extern_inst_list + i);
     }
 }
-#endif /* WASM_ENABLE_SPEC_TEST != 0 || WASM_ENABLE_WASI_TEST != 0 */
 
 bool
 wasm_runtime_create_imports_with_builtin(WASMModuleCommon *module,

+ 26 - 4
core/iwasm/common/wasm_runtime_common.h

@@ -504,6 +504,25 @@ wasm_runtime_set_exec_env_tls(WASMExecEnv *exec_env);
 /* Get exec_env of thread local storage */
 WASMExecEnv *
 wasm_runtime_get_exec_env_tls(void);
+#endif /* OS_ENABLE_HW_BOUND_CHECK */
+
+/* wasm-c-api import function info */
+typedef struct CApiFuncImport {
+    /* host func pointer after linked */
+    void *func_ptr_linked;
+    /* whether the host func has env argument */
+    bool with_env_arg;
+    /* the env argument of the host func */
+    void *env_arg;
+} CApiFuncImport;
+
+#if WASM_ENABLE_MULTI_MODULE != 0
+typedef struct WASMSubModInstNode {
+    bh_list_link l;
+    /* point to a string pool */
+    const char *module_name;
+    WASMModuleInstanceCommon *module_inst;
+} WASMSubModInstNode;
 #endif
 
 /* See wasm_export.h for description */
@@ -582,7 +601,7 @@ wasm_runtime_instantiate_internal(WASMModuleCommon *module,
 /* Internal API */
 void
 wasm_runtime_deinstantiate_internal(WASMModuleInstanceCommon *module_inst,
-                                    bool is_sub_inst);
+                                    bool is_spawned);
 
 /* See wasm_export.h for description */
 WASM_RUNTIME_API_EXTERN WASMModuleInstanceCommon *
@@ -1164,12 +1183,11 @@ wasm_runtime_invoke_c_api_native(WASMModuleInstanceCommon *module_inst,
                                  uint32 argc, uint32 *argv, bool with_env,
                                  void *wasm_c_api_env);
 
-struct CApiFuncImport;
 /* A quick version of wasm_runtime_invoke_c_api_native to directly invoke
    wasm-c-api import function from jitted code to improve performance */
 bool
 wasm_runtime_quick_invoke_c_api_native(WASMModuleInstanceCommon *module_inst,
-                                       struct CApiFuncImport *c_api_import,
+                                       CApiFuncImport *c_api_import,
                                        wasm_val_t *params, uint32 param_count,
                                        wasm_val_t *results,
                                        uint32 result_count);
@@ -1240,9 +1258,13 @@ wasm_runtime_set_global_value(wasm_module_t const module,
                               wasm_global_inst_t global, WASMValue *value);
 
 struct WASMTableInstance *
-wasm_runtime_create_table_internal(WASMModuleCommon *const module,
+wasm_runtime_create_table_internal(const wasm_module_t module,
                                    WASMTableType *const type);
 
+wasm_function_inst_t
+wasm_runtime_create_function_c_api(const wasm_module_t module,
+                                   CApiFuncImport *c_api_info);
+
 #ifdef __cplusplus
 }
 #endif

+ 2 - 0
core/iwasm/compilation/aot.c

@@ -478,7 +478,9 @@ aot_create_import_funcs(const WASMModule *module)
         import_funcs[i].signature = import_func->signature;
         import_funcs[i].attachment = import_func->attachment;
         import_funcs[i].call_conv_raw = import_func->call_conv_raw;
+#if WASM_ENABLE_MULTI_MODULE != 0
         import_funcs[i].call_conv_wasm_c_api = false;
+#endif
         /* Resolve function type index */
         for (j = 0; j < module->type_count; j++)
             if (import_func->func_type == (WASMFuncType *)module->types[j]) {

+ 11 - 1
core/iwasm/compilation/aot.h

@@ -51,6 +51,9 @@ typedef WASMMemoryType AOTMemoryType;
 typedef WASMTableType AOTTableType;
 typedef WASMTable AOTTable;
 
+struct AOTModule;
+struct AOTFunc;
+
 #if WASM_ENABLE_DEBUG_AOT != 0
 typedef void *dwarf_extractor_handle_t;
 #endif
@@ -191,14 +194,21 @@ typedef struct AOTImportFunc {
     AOTFuncType *func_type;
     uint32 func_type_index;
     /* function pointer after linked */
+
     void *func_ptr_linked;
     /* signature from registered native symbols */
     const char *signature;
     /* attachment */
     void *attachment;
+
+    /* via wasm_native */
     bool call_conv_raw;
+#if WASM_ENABLE_MULTI_MODULE != 0
+    /* by loading-link */
     bool call_conv_wasm_c_api;
-    bool wasm_c_api_with_env;
+    struct AOTModule *import_module;
+    struct AOTFunc *import_func_linked;
+#endif
 } AOTImportFunc;
 
 /**

+ 1 - 1
core/iwasm/compilation/aot_llvm.c

@@ -1934,7 +1934,7 @@ aot_create_func_contexts(const AOTCompData *comp_data, AOTCompContext *comp_ctx)
 
     memset(func_ctxes, 0, size);
 
-    /* Create each function context */
+    /* Create each function(non-import) context */
     for (i = 0; i < comp_data->func_count; i++) {
         AOTFunc *func = comp_data->funcs[i];
         if (!(func_ctxes[i] =

+ 7 - 0
core/iwasm/fast-jit/fe/jit_emit_function.c

@@ -246,7 +246,14 @@ jit_compile_op_call(JitCompContext *cc, uint32 func_idx, bool tail_call)
 
         /* Call fast_jit_invoke_native in some cases */
         if (!func_import->func_ptr_linked /* import func hasn't been linked */
+#if WASM_ENABLE_MULTI_MODULE != 0
             || func_import->call_conv_wasm_c_api /* linked by wasm_c_api */
+#else
+        /*
+         * TODO: can't decide if it is conv_c_api now
+         * but we didn't setup func_ptr_linked, too
+         */
+#endif
             || func_import->call_conv_raw /* registered as raw mode */
             || func_type->param_count >= 5 /* registered as normal mode, but
                                               jit_emit_callnative only supports

+ 2 - 1
core/iwasm/include/wasm_c_api.h

@@ -194,12 +194,13 @@ struct wasm_config_t {
 
 #ifndef INSTANTIATION_ARGS_OPTION_DEFINED
 #define INSTANTIATION_ARGS_OPTION_DEFINED
+struct WASMExternInstance;
 /* WASM module instantiation arguments */
 typedef struct InstantiationArgs {
     uint32_t default_stack_size;
     uint32_t host_managed_heap_size;
     uint32_t max_memory_pages;
-    const struct WasmExternInstance *imports;
+    const struct WASMExternInstance * imports;
     uint32_t import_count;
 } InstantiationArgs;
 #endif /* INSTANTIATION_ARGS_OPTION_DEFINED */

+ 14 - 1
core/iwasm/include/wasm_export.h

@@ -296,11 +296,12 @@ typedef struct WASMExternInstance {
         wasm_memory_inst_t memory;
         wasm_table_inst_t table;
         wasm_global_inst_t global;
+        wasm_function_inst_t function;
     } u;
 
     /*
      * to handle imports properly,
-     * especially for wasm_global_inst_t and wasm_func_inst_t
+     * especially for wasm_global_inst_t and wasm_function_inst_t
      */
     wasm_module_inst_t dep_inst;
 } WASMExternInstance, *wasm_extern_inst_t;
@@ -2378,6 +2379,14 @@ wasm_runtime_create_table(const wasm_module_t module,
 WASM_RUNTIME_API_EXTERN void
 wasm_runtime_destroy_table(const wasm_module_t module, wasm_table_inst_t table);
 
+WASM_RUNTIME_API_EXTERN wasm_function_inst_t
+wasm_runtime_create_function(const wasm_module_t module,
+                             const wasm_func_type_t type, void *callback);
+
+WASM_RUNTIME_API_EXTERN void
+wasm_runtime_destroy_function(const wasm_module_t module,
+                              wasm_function_inst_t func);
+
 /*TODO: take me out when have a linker */
 WASM_RUNTIME_API_EXTERN wasm_module_inst_t
 wasm_runtime_instantiate_with_builtin_linker(wasm_module_t module,
@@ -2394,6 +2403,10 @@ wasm_runtime_create_imports_with_builtin(wasm_module_t module,
                                          wasm_extern_inst_t out,
                                          uint32_t out_len);
 
+WASM_RUNTIME_API_EXTERN void
+wasm_runtime_destroy_imports(wasm_module_t module,
+                             wasm_extern_inst_t extern_inst_list);
+
 #ifdef __cplusplus
 }
 #endif

+ 5 - 2
core/iwasm/interpreter/wasm.h

@@ -563,7 +563,7 @@ typedef struct WASMFunctionImport {
     char *field_name;
     /* function type */
     WASMFuncType *func_type;
-    /* native function pointer after linked */
+    /* from wasm_native */
     void *func_ptr_linked;
     /* signature from registered native symbols */
     const char *signature;
@@ -573,9 +573,12 @@ typedef struct WASMFunctionImport {
     /* the type index of this function's func_type */
     uint32 type_idx;
 #endif
+
+    /* via wasm_native */
     bool call_conv_raw;
-    bool call_conv_wasm_c_api;
 #if WASM_ENABLE_MULTI_MODULE != 0
+    /* by loading-link */
+    bool call_conv_wasm_c_api;
     WASMModule *import_module;
     WASMFunction *import_func_linked;
 #endif

+ 16 - 18
core/iwasm/interpreter/wasm_interp_classic.c

@@ -1268,7 +1268,9 @@ wasm_interp_call_func_native(WASMModuleInstance *module_inst,
 
     cur_func_index = (uint32)(cur_func - module_inst->e->functions);
     bh_assert(cur_func_index < module_inst->module->import_function_count);
-    if (!func_import->call_conv_wasm_c_api) {
+
+    if (!cur_func->call_conv_wasm_c_api) {
+        /*TODO: use func_ptrs instead */
         native_func_pointer = module_inst->import_func_ptrs[cur_func_index];
     }
     else if (module_inst->c_api_func_imports) {
@@ -1284,7 +1286,7 @@ wasm_interp_call_func_native(WASMModuleInstance *module_inst,
         return;
     }
 
-    if (func_import->call_conv_wasm_c_api) {
+    if (cur_func->call_conv_wasm_c_api) {
         ret = wasm_runtime_invoke_c_api_native(
             (WASMModuleInstanceCommon *)module_inst, native_func_pointer,
             func_import->func_type, cur_func->param_cell_num, frame->lp,
@@ -1294,14 +1296,14 @@ wasm_interp_call_func_native(WASMModuleInstance *module_inst,
             argv_ret[1] = frame->lp[1];
         }
     }
-    else if (!func_import->call_conv_raw) {
-        ret = wasm_runtime_invoke_native(
+    else if (cur_func->call_conv_raw) {
+        ret = wasm_runtime_invoke_native_raw(
             exec_env, native_func_pointer, func_import->func_type,
             func_import->signature, func_import->attachment, frame->lp,
             cur_func->param_cell_num, argv_ret);
     }
     else {
-        ret = wasm_runtime_invoke_native_raw(
+        ret = wasm_runtime_invoke_native(
             exec_env, native_func_pointer, func_import->func_type,
             func_import->signature, func_import->attachment, frame->lp,
             cur_func->param_cell_num, argv_ret);
@@ -1354,7 +1356,6 @@ fast_jit_invoke_native(WASMExecEnv *exec_env, uint32 func_idx,
 }
 #endif
 
-#if WASM_ENABLE_MULTI_MODULE != 0
 static void
 wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                                WASMExecEnv *exec_env,
@@ -1392,8 +1393,10 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst,
         return;
     }
 
-    /* Switch exec_env but keep using the same one by replacing necessary
-     * variables */
+    /*
+     * Switch the WASMExecEnv while retaining the same content
+     * by updating the necessary variables
+     */
     sub_module_exec_env = wasm_runtime_get_exec_env_singleton(
         (WASMModuleInstanceCommon *)sub_module_inst);
     if (!sub_module_exec_env) {
@@ -1426,7 +1429,6 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst,
     wasm_exec_env_restore_module_inst(exec_env,
                                       (WASMModuleInstanceCommon *)module_inst);
 }
-#endif
 
 #if WASM_ENABLE_THREAD_MGR != 0
 #if WASM_ENABLE_DEBUG_INTERP != 0
@@ -6637,8 +6639,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
     call_func_from_entry:
     {
         if (cur_func->is_import_func) {
-#if WASM_ENABLE_MULTI_MODULE != 0
-            if (cur_func->import_func_inst) {
+            if (cur_func->import_module_inst) {
+                /* from other .wasm */
                 wasm_interp_call_func_import(module, exec_env, cur_func,
                                              prev_frame);
 #if WASM_ENABLE_TAIL_CALL != 0 || WASM_ENABLE_GC != 0
@@ -6698,9 +6700,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                 }
 #endif /* end of WASM_ENABLE_EXCE_HANDLING != 0 */
             }
-            else
-#endif /* end of WASM_ENABLE_MULTI_MODULE != 0 */
-            {
+            else {
+                /* from wasm_native or c_api */
                 wasm_interp_call_func_native(module, exec_env, cur_func,
                                              prev_frame);
 #if WASM_ENABLE_TAIL_CALL != 0 || WASM_ENABLE_GC != 0
@@ -7485,14 +7486,11 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env,
 #endif
 
     if (function->is_import_func) {
-#if WASM_ENABLE_MULTI_MODULE != 0
         if (function->import_module_inst) {
             wasm_interp_call_func_import(module_inst, exec_env, function,
                                          frame);
         }
-        else
-#endif
-        {
+        else {
             /* it is a native function */
             wasm_interp_call_func_native(module_inst, exec_env, function,
                                          frame);

+ 8 - 11
core/iwasm/interpreter/wasm_interp_fast.c

@@ -1209,7 +1209,9 @@ wasm_interp_call_func_native(WASMModuleInstance *module_inst,
 
     cur_func_index = (uint32)(cur_func - module_inst->e->functions);
     bh_assert(cur_func_index < module_inst->module->import_function_count);
-    if (!func_import->call_conv_wasm_c_api) {
+
+    if (!cur_func->call_conv_wasm_c_api) {
+        /*TODO: use func_ptrs instead */
         native_func_pointer = module_inst->import_func_ptrs[cur_func_index];
     }
     else if (module_inst->c_api_func_imports) {
@@ -1226,7 +1228,7 @@ wasm_interp_call_func_native(WASMModuleInstance *module_inst,
         return;
     }
 
-    if (func_import->call_conv_wasm_c_api) {
+    if (cur_func->call_conv_wasm_c_api) {
         ret = wasm_runtime_invoke_c_api_native(
             (WASMModuleInstanceCommon *)module_inst, native_func_pointer,
             func_import->func_type, cur_func->param_cell_num, frame->lp,
@@ -1236,14 +1238,14 @@ wasm_interp_call_func_native(WASMModuleInstance *module_inst,
             argv_ret[1] = frame->lp[1];
         }
     }
-    else if (!func_import->call_conv_raw) {
-        ret = wasm_runtime_invoke_native(
+    else if (cur_func->call_conv_raw) {
+        ret = wasm_runtime_invoke_native_raw(
             exec_env, native_func_pointer, func_import->func_type,
             func_import->signature, func_import->attachment, frame->lp,
             cur_func->param_cell_num, argv_ret);
     }
     else {
-        ret = wasm_runtime_invoke_native_raw(
+        ret = wasm_runtime_invoke_native(
             exec_env, native_func_pointer, func_import->func_type,
             func_import->signature, func_import->attachment, frame->lp,
             cur_func->param_cell_num, argv_ret);
@@ -1278,7 +1280,6 @@ wasm_interp_call_func_native(WASMModuleInstance *module_inst,
     wasm_exec_env_set_cur_frame(exec_env, prev_frame);
 }
 
-#if WASM_ENABLE_MULTI_MODULE != 0
 static void
 wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                                WASMExecEnv *exec_env,
@@ -1350,7 +1351,6 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst,
     wasm_exec_env_restore_module_inst(exec_env,
                                       (WASMModuleInstanceCommon *)module_inst);
 }
-#endif
 
 #if WASM_ENABLE_THREAD_MGR != 0
 #define CHECK_SUSPEND_FLAGS()                               \
@@ -6253,15 +6253,12 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env,
 #endif
 
     if (function->is_import_func) {
-#if WASM_ENABLE_MULTI_MODULE != 0
         if (function->import_module_inst) {
             LOG_DEBUG("it is a function of a sub module");
             wasm_interp_call_func_import(module_inst, exec_env, function,
                                          frame);
         }
-        else
-#endif
-        {
+        else {
             LOG_DEBUG("it is an native function");
             wasm_interp_call_func_native(module_inst, exec_env, function,
                                          frame);

+ 249 - 94
core/iwasm/interpreter/wasm_runtime.c

@@ -90,12 +90,14 @@ wasm_resolve_symbols(WASMModule *module)
     uint32 idx;
     for (idx = 0; idx < module->import_function_count; ++idx) {
         WASMFunctionImport *import = &module->import_functions[idx].u.function;
-        bool linked = import->func_ptr_linked;
+        /* by wasm_native */
+        bool linked = import->func_ptr_linked != NULL;
+
 #if WASM_ENABLE_MULTI_MODULE != 0
-        if (import->import_func_linked) {
-            linked = true;
-        }
+        /* by loading-linking */
+        linked = import->import_func_linked != NULL;
 #endif
+
         if (!linked && !wasm_resolve_import_func(module, import)) {
             ret = false;
         }
@@ -162,10 +164,7 @@ wasm_resolve_function(const char *module_name, const char *function_name,
 bool
 wasm_resolve_import_func(const WASMModule *module, WASMFunctionImport *function)
 {
-#if WASM_ENABLE_MULTI_MODULE != 0
-    char error_buf[128];
-    WASMModule *sub_module = NULL;
-#endif
+    /* from wasm_native functions */
     function->func_ptr_linked = wasm_native_resolve_symbol(
         function->module_name, function->field_name, function->func_type,
         &function->signature, &function->attachment, &function->call_conv_raw);
@@ -175,29 +174,41 @@ wasm_resolve_import_func(const WASMModule *module, WASMFunctionImport *function)
     }
 
 #if WASM_ENABLE_MULTI_MODULE != 0
-    if (!wasm_runtime_is_built_in_module(function->module_name)) {
-        sub_module = (WASMModule *)wasm_runtime_load_depended_module(
-            (WASMModuleCommon *)module, function->module_name, error_buf,
-            sizeof(error_buf));
-        if (!sub_module) {
-            LOG_WARNING("failed to load sub module: %s", error_buf);
-            return false;
-        }
+    if (!function->module_name) {
+        LOG_VERBOSE(
+            "does't have module name for function %s. host should provide link",
+            function->field_name);
+        return false;
     }
+
+    /* from other .wasms' export functions */
+    char error_buf[128];
+    WASMModule *sub_module = (WASMModule *)wasm_runtime_load_depended_module(
+        (WASMModuleCommon *)module, function->module_name, error_buf,
+        sizeof(error_buf));
+    if (!sub_module) {
+        LOG_WARNING("failed to load sub module: %s", error_buf);
+        return false;
+    }
+
     function->import_func_linked = wasm_resolve_function(
         function->module_name, function->field_name, function->func_type,
         error_buf, sizeof(error_buf));
-
     if (function->import_func_linked) {
         function->import_module = sub_module;
         return true;
     }
-    else {
-        LOG_WARNING("failed to link function (%s, %s): %s",
-                    function->module_name, function->field_name, error_buf);
-    }
+
+    LOG_WARNING("failed to link function (%s, %s): %s", function->module_name,
+                function->field_name, error_buf);
+#else
+    (void)module;
 #endif
 
+    LOG_DEBUG("can't resolve import function %s durning loading. wait for "
+              "instantiation linking",
+              function->field_name);
+
     return false;
 }
 
@@ -223,10 +234,17 @@ get_sub_module_inst(const WASMModuleInstance *parent_module_inst,
     bh_list *sub_module_inst_list = parent_module_inst->e->sub_module_inst_list;
     WASMSubModInstNode *node = bh_list_first_elem(sub_module_inst_list);
 
-    while (node && sub_module != node->module_inst->module) {
+    WASMModuleInstance *inst = (WASMModuleInstance *)node->module_inst;
+    while (node && sub_module != inst->module) {
         node = bh_list_elem_next(node);
+        inst = (WASMModuleInstance *)node->module_inst;
     }
-    return node ? node->module_inst : NULL;
+
+    if (!node) {
+        LOG_DEBUG("fail to find sub module instance");
+    }
+
+    return node ? inst : NULL;
 }
 #endif
 
@@ -976,8 +994,11 @@ functions_deinstantiate(WASMFunctionInstance *functions)
  * Instantiate functions in a module.
  */
 static WASMFunctionInstance *
-functions_instantiate(const WASMModule *module, WASMModuleInstance *module_inst,
-                      char *error_buf, uint32 error_buf_size)
+import_functions_instantiate(const WASMModule *module,
+                             WASMModuleInstance *module_inst,
+                             const WASMExternInstance *imports,
+                             uint32 import_count, char *error_buf,
+                             uint32 error_buf_size)
 {
     WASMImport *import;
     uint32 i,
@@ -990,6 +1011,7 @@ functions_instantiate(const WASMModule *module, WASMModuleInstance *module_inst,
     }
 
     total_size = sizeof(void *) * (uint64)module->import_function_count;
+    /*TODO: remove me if all goes to func_ptrs*/
     if (total_size > 0
         && !(module_inst->import_func_ptrs =
                  runtime_malloc(total_size, error_buf, error_buf_size))) {
@@ -1000,36 +1022,97 @@ functions_instantiate(const WASMModule *module, WASMModuleInstance *module_inst,
     /* instantiate functions from import section */
     function = functions;
     import = module->import_functions;
-    for (i = 0; i < module->import_function_count; i++, import++) {
+    for (i = 0; i < module->import_function_count; i++, import++, function++) {
         function->is_import_func = true;
 
+        WASMFunctionImport *import_func_type = &(import->u.function);
+        function->u.func_import = import_func_type;
+        function->param_cell_num = import_func_type->func_type->param_cell_num;
+        function->ret_cell_num = import_func_type->func_type->ret_cell_num;
+        function->param_count =
+            (uint16)import_func_type->func_type->param_count;
+        function->param_types = import_func_type->func_type->types;
+        function->local_cell_num = 0;
+        function->local_count = 0;
+        function->local_types = NULL;
+        /* copy value from module to inst */
+        function->call_conv_raw = import_func_type->call_conv_raw;
+
 #if WASM_ENABLE_MULTI_MODULE != 0
         if (import->u.function.import_module) {
+            /* from other .wasm */
             function->import_module_inst = get_sub_module_inst(
                 module_inst, import->u.function.import_module);
-
-            if (function->import_module_inst) {
-                function->import_func_inst =
-                    wasm_lookup_function(function->import_module_inst,
-                                         import->u.function.field_name);
+            if (!function->import_module_inst) {
+                set_error_buf_v(error_buf, error_buf_size,
+                                "unknown import module \"%s\"",
+                                import->u.function.module_name);
+                return NULL;
             }
+
+            function->import_func_inst = wasm_lookup_function(
+                function->import_module_inst, import->u.function.field_name);
         }
-#endif /* WASM_ENABLE_MULTI_MODULE */
-        function->u.func_import = &import->u.function;
-        function->param_cell_num = import->u.function.func_type->param_cell_num;
-        function->ret_cell_num = import->u.function.func_type->ret_cell_num;
-        function->param_count =
-            (uint16)function->u.func_import->func_type->param_count;
-        function->param_types = function->u.func_import->func_type->types;
-        function->local_cell_num = 0;
-        function->local_count = 0;
-        function->local_types = NULL;
 
-        /* Copy the function pointer to current instance */
-        module_inst->import_func_ptrs[i] =
-            function->u.func_import->func_ptr_linked;
+        /* from c_api (loading)*/
+        function->call_conv_wasm_c_api = import_func_type->call_conv_wasm_c_api;
 
-        function++;
+        /* from wasm_native and c_api */
+        module_inst->import_func_ptrs[i] = import_func_type->func_ptr_linked;
+#else
+        const WASMExternInstance *extern_inst =
+            wasm_runtime_get_extern_instance(imports, import_count,
+                                             WASM_IMPORT_EXPORT_KIND_FUNC, i);
+        if (!extern_inst) {
+            LOG_DEBUG("no import function(%s, %s) from imports list, might "
+                      "provied by wasm_native",
+                      import_func_type->module_name,
+                      import_func_type->field_name);
+            /* so it's from wasm_native */
+            module_inst->import_func_ptrs[i] =
+                import_func_type->func_ptr_linked;
+            continue;
+        }
+
+        /* if extern_inst is about a wasm function from other .wasm */
+        WASMFunctionInstance *extern_inst_func =
+            (WASMFunctionInstance *)extern_inst->u.function;
+        if (!extern_inst_func) {
+            LOG_DEBUG("empty extern_inst_func for import function(%s, %s)",
+                      "might provided by wasm_native",
+                      import_func_type->module_name,
+                      import_func_type->field_name);
+            /* so it's from wasm_native */
+            module_inst->import_func_ptrs[i] =
+                import_func_type->func_ptr_linked;
+            continue;
+        }
+
+        bh_assert(extern_inst_func->is_import_func);
+
+        /* don't allow wrong matchment */
+        if (strcmp(import_func_type->field_name, extern_inst->field_name)) {
+            LOG_ERROR(
+                "mismatched import memory name: expect \"%s\", got \"%s\"",
+                import_func_type->field_name, extern_inst->field_name);
+            return NULL;
+        }
+
+        /* from other .wasm */
+        function->import_module_inst = extern_inst_func->import_module_inst;
+        function->import_func_inst = extern_inst_func->import_func_inst;
+
+        /* from c_api (instantiation)*/
+        function->call_conv_wasm_c_api = extern_inst_func->call_conv_wasm_c_api;
+        /* TODO: for now, let c_api finish this. Will move it to wasm_runtime
+         * later */
+        /*module_inst->c_api_func_imports[i] =
+         * extern_inst_func->import_func_c_api;*/
+
+        /* from wasm_native */
+        module_inst->import_func_ptrs[i] =
+            extern_inst_func->u.func_import->func_ptr_linked;
+#endif
     }
 
     /* instantiate functions from function section */
@@ -1786,7 +1869,7 @@ lookup_post_instantiate_func(WASMModuleInstance *module_inst,
 
 static bool
 execute_post_instantiate_functions(WASMModuleInstance *module_inst,
-                                   bool is_sub_inst, WASMExecEnv *exec_env_main)
+                                   bool is_spawned, WASMExecEnv *exec_env_main)
 {
     WASMFunctionInstance *start_func = module_inst->e->start_function;
     WASMFunctionInstance *initialize_func = NULL;
@@ -1808,7 +1891,7 @@ execute_post_instantiate_functions(WASMModuleInstance *module_inst,
      * the environment at most once, and that none of their other exports
      * are accessed before that call.
      */
-    if (!is_sub_inst && module->import_wasi_api) {
+    if (!is_spawned && module->import_wasi_api) {
         initialize_func =
             lookup_post_instantiate_func(module_inst, "_initialize");
     }
@@ -1816,7 +1899,7 @@ execute_post_instantiate_functions(WASMModuleInstance *module_inst,
 
     /* Execute possible "__post_instantiate" function if wasm app is
        compiled by emsdk's early version */
-    if (!is_sub_inst) {
+    if (!is_spawned) {
         post_inst_func =
             lookup_post_instantiate_func(module_inst, "__post_instantiate");
     }
@@ -1824,7 +1907,7 @@ execute_post_instantiate_functions(WASMModuleInstance *module_inst,
 #if WASM_ENABLE_BULK_MEMORY != 0
     /* Only execute the memory init function for main instance since
        the data segments will be dropped once initialized */
-    if (!is_sub_inst
+    if (!is_spawned
 #if WASM_ENABLE_LIBC_WASI != 0
         && !module->import_wasi_api
 #endif
@@ -1840,7 +1923,7 @@ execute_post_instantiate_functions(WASMModuleInstance *module_inst,
         return true;
     }
 
-    if (is_sub_inst) {
+    if (is_spawned) {
         bh_assert(exec_env_main);
 #ifdef OS_ENABLE_HW_BOUND_CHECK
         /* May come from pthread_create_wrapper, thread_spawn_wrapper and
@@ -1915,7 +1998,7 @@ execute_post_instantiate_functions(WASMModuleInstance *module_inst,
     ret = true;
 
 fail:
-    if (is_sub_inst) {
+    if (is_spawned) {
         /* Restore the parent exec_env's module inst */
         wasm_exec_env_restore_module_inst(exec_env_main, module_inst_main);
     }
@@ -2125,13 +2208,11 @@ check_linked_symbol(WASMModuleInstance *module_inst, char *error_buf,
     uint32 i;
 
     for (i = 0; i < module->import_function_count; i++) {
-        WASMFunctionImport *func =
-            &((module->import_functions + i)->u.function);
-        if (!func->func_ptr_linked
-#if WASM_ENABLE_MULTI_MODULE != 0
-            && !func->import_func_linked
-#endif
-        ) {
+        void *func_ptr_linked = module_inst->import_func_ptrs[i];
+        if (!func_ptr_linked) {
+            WASMFunctionImport *func =
+                &((module->import_functions + i)->u.function);
+
             LOG_WARNING("warning: failed to link import function (%s, %s)",
                         func->module_name, func->field_name);
         }
@@ -2199,6 +2280,7 @@ check_linked_symbol(WASMModuleInstance *module_inst, char *error_buf,
 #if WASM_ENABLE_JIT != 0
 static bool
 init_func_ptrs(WASMModuleInstance *module_inst, WASMModule *module,
+               const WASMExternInstance *imports, uint32 import_count,
                char *error_buf, uint32 error_buf_size)
 {
     uint32 i;
@@ -2213,10 +2295,29 @@ init_func_ptrs(WASMModuleInstance *module_inst, WASMModule *module,
 
     /* Set import function pointers */
     for (i = 0; i < module->import_function_count; i++, func_ptrs++) {
-        WASMFunctionImport *import_func =
-            &module->import_functions[i].u.function;
-        /* TODO: handle multi module */
+        WASMFunctionInstance *func =
+            wasm_locate_function_instance(module_inst, i);
+        bh_assert(func->is_import_func);
+
+        if (func->call_conv_wasm_c_api) {
+            /* when execution, goes to invoke_native() and use
+             * c_api_func_imports*/
+            continue;
+        }
+
+        if (func->import_module_inst) {
+            /* when execution, goes to invoke_native() and switch to another
+             * .wasm */
+            continue;
+        }
+
+        WASMFunctionImport *import_func = func->u.func_import;
+
+        LOG_DEBUG("use wasm_native linked functions for (%s,%s)",
+                  import_func->module_name, import_func->field_name);
+
         *func_ptrs = import_func->func_ptr_linked;
+        bh_assert(*func_ptrs);
     }
 
     /* The defined function pointers will be set in
@@ -2592,7 +2693,7 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent,
 #if WASM_ENABLE_MULTI_MODULE != 0
     bool ret = false;
 #endif
-    const bool is_sub_inst = parent != NULL;
+    const bool is_spawned = parent != NULL;
 
     if (!module)
         return NULL;
@@ -2714,7 +2815,7 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent,
 #endif
 
 #if WASM_ENABLE_GC != 0
-    if (!is_sub_inst) {
+    if (!is_spawned) {
         uint32 gc_heap_size = wasm_runtime_get_gc_heap_size_default();
 
         if (gc_heap_size < GC_HEAP_SIZE_MIN)
@@ -2804,8 +2905,9 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent,
                      module, module_inst, first_table, imports, import_count,
                      error_buf, error_buf_size)))
         || (module_inst->e->function_count > 0
-            && !(module_inst->e->functions = functions_instantiate(
-                     module, module_inst, error_buf, error_buf_size)))
+            && !(module_inst->e->functions = import_functions_instantiate(
+                     module, module_inst, imports, import_count, error_buf,
+                     error_buf_size)))
         || (module_inst->export_func_count > 0
             && !(module_inst->export_functions = export_functions_instantiate(
                      module, module_inst, module_inst->export_func_count,
@@ -2833,7 +2935,8 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent,
 #endif
 #if WASM_ENABLE_JIT != 0
         || (module_inst->e->function_count > 0
-            && !init_func_ptrs(module_inst, module, error_buf, error_buf_size))
+            && !init_func_ptrs(module_inst, module, imports, import_count,
+                               error_buf, error_buf_size))
 #endif
 #if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0
         || (module_inst->e->function_count > 0
@@ -2958,7 +3061,7 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent,
         if (data_seg->is_passive)
             continue;
 #endif
-        if (is_sub_inst)
+        if (is_spawned)
             /* Ignore setting memory init data if the memory has been
                initialized */
             continue;
@@ -3471,7 +3574,7 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent,
 
 #if WASM_ENABLE_LIBC_WASI != 0
     /* The sub-instance will get the wasi_ctx from main-instance */
-    if (!is_sub_inst) {
+    if (!is_spawned) {
         if (!wasm_runtime_init_wasi(
                 (WASMModuleInstanceCommon *)module_inst,
                 module->wasi_args.dir_list, module->wasi_args.dir_count,
@@ -3489,7 +3592,7 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent,
 #endif
 
 #if WASM_ENABLE_DEBUG_INTERP != 0
-    if (!is_sub_inst) {
+    if (!is_spawned) {
         /* Add module instance into module's instance list */
         os_mutex_lock(&module->instance_list_lock);
         if (module->instance_list) {
@@ -3518,7 +3621,7 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent,
                 &module_inst->e->functions[module->start_function];
     }
 
-    if (!execute_post_instantiate_functions(module_inst, is_sub_inst,
+    if (!execute_post_instantiate_functions(module_inst, is_spawned,
                                             exec_env_main)) {
         set_error_buf(error_buf, error_buf_size, module_inst->cur_exception);
         goto fail;
@@ -3561,7 +3664,7 @@ destroy_c_api_frames(Vector *frames)
 #endif
 
 void
-wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst)
+wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_spawned)
 {
     if (!module_inst)
         return;
@@ -3659,7 +3762,7 @@ wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst)
 #endif
 
 #if WASM_ENABLE_GC != 0
-    if (!is_sub_inst) {
+    if (!is_spawned) {
         if (module_inst->e->common.gc_heap_handle)
             mem_allocator_destroy(module_inst->e->common.gc_heap_handle);
         if (module_inst->e->common.gc_heap_pool)
@@ -3678,7 +3781,7 @@ wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst)
     if (module_inst->c_api_func_imports)
         wasm_runtime_free(module_inst->c_api_func_imports);
 
-    if (!is_sub_inst) {
+    if (!is_spawned) {
         wasm_native_call_context_dtors((WASMModuleInstanceCommon *)module_inst);
     }
 
@@ -4648,14 +4751,14 @@ wasm_interp_dump_call_stack(struct WASMExecEnv *exec_env, bool print, char *buf,
             /* function name not exported, print number instead */
             if (frame.func_name_wp == NULL) {
                 line_length =
-                    snprintf(line_buf, sizeof(line_buf),
-                             "#%02" PRIu32 ": 0x%04x - $f%" PRIu32 "\n", n,
-                             frame.func_offset, frame.func_index);
+                    (uint32)snprintf(line_buf, sizeof(line_buf),
+                                     "#%02" PRIu32 ": 0x%04x - $f%" PRIu32 "\n",
+                                     n, frame.func_offset, frame.func_index);
             }
             else {
-                line_length = snprintf(line_buf, sizeof(line_buf),
-                                       "#%02" PRIu32 ": 0x%04x - %s\n", n,
-                                       frame.func_offset, frame.func_name_wp);
+                line_length = (uint32)snprintf(
+                    line_buf, sizeof(line_buf), "#%02" PRIu32 ": 0x%04x - %s\n",
+                    n, frame.func_offset, frame.func_name_wp);
             }
         }
 
@@ -4762,19 +4865,33 @@ llvm_jit_invoke_native(WASMExecEnv *exec_env, uint32 func_idx, uint32 argc,
     func_type_indexes = module_inst->func_type_indexes;
     func_type_idx = func_type_indexes[func_idx];
     func_type = (WASMFuncType *)module->types[func_type_idx];
-    func_ptr = module_inst->func_ptrs[func_idx];
 
     bh_assert(func_idx < module->import_function_count);
 
     import_func = &module->import_functions[func_idx].u.function;
-    if (import_func->call_conv_wasm_c_api) {
-        if (module_inst->c_api_func_imports) {
-            c_api_func_import = module_inst->c_api_func_imports + func_idx;
-            func_ptr = c_api_func_import->func_ptr_linked;
+
+    WASMFunctionInstance *func_inst =
+        wasm_locate_function_instance(module_inst, func_idx);
+
+    if (func_inst->call_conv_wasm_c_api) {
+        c_api_func_import = module_inst->c_api_func_imports
+                                ? module_inst->c_api_func_imports + func_idx
+                                : NULL;
+        func_ptr =
+            c_api_func_import ? c_api_func_import->func_ptr_linked : NULL;
+    }
+    else if (func_inst->call_conv_raw) {
+        func_ptr = module_inst->func_ptrs[func_idx];
+    }
+    else {
+        if (func_inst->import_module_inst) {
+            uint32 funx_idx_of_import_func = wasm_calc_function_index(
+                func_inst->import_module_inst, func_inst->import_func_inst);
+            func_ptr = func_inst->import_module_inst
+                           ->func_ptrs[funx_idx_of_import_func];
         }
         else {
-            c_api_func_import = NULL;
-            func_ptr = NULL;
+            func_ptr = module_inst->func_ptrs[func_idx];
         }
     }
 
@@ -4787,23 +4904,38 @@ llvm_jit_invoke_native(WASMExecEnv *exec_env, uint32 func_idx, uint32 argc,
     }
 
     attachment = import_func->attachment;
-    if (import_func->call_conv_wasm_c_api) {
+    if (func_inst->call_conv_wasm_c_api) {
+        /* from wasm_c_api */
         ret = wasm_runtime_invoke_c_api_native(
             (WASMModuleInstanceCommon *)module_inst, func_ptr, func_type, argc,
             argv, c_api_func_import->with_env_arg, c_api_func_import->env_arg);
     }
-    else if (!import_func->call_conv_raw) {
-        signature = import_func->signature;
-        ret =
-            wasm_runtime_invoke_native(exec_env, func_ptr, func_type, signature,
-                                       attachment, argv, argc, argv);
-    }
-    else {
+    else if (func_inst->call_conv_raw) {
+        /* from wasm_native raw */
         signature = import_func->signature;
         ret = wasm_runtime_invoke_native_raw(exec_env, func_ptr, func_type,
                                              signature, attachment, argv, argc,
                                              argv);
     }
+    else {
+        if (func_inst->import_module_inst) {
+            /* from other .wasm. switch */
+            exec_env = wasm_runtime_get_exec_env_singleton(
+                (WASMModuleInstanceCommon *)func_inst->import_module_inst);
+            if (!exec_env) {
+                wasm_runtime_set_exception(
+                    (WASMModuleInstanceCommon *)module_inst,
+                    "create singleton exec_env failed");
+                goto fail;
+            }
+        }
+
+        /* from wasm_native */
+        signature = import_func->signature;
+        ret =
+            wasm_runtime_invoke_native(exec_env, func_ptr, func_type, signature,
+                                       attachment, argv, argc, argv);
+    }
 
 fail:
 #ifdef OS_ENABLE_HW_BOUND_CHECK
@@ -5424,6 +5556,7 @@ wasm_destroy_table(WASMTableInstance *table)
     wasm_runtime_free(table);
 }
 
+/*TODO: add init_value */
 WASMGlobalInstance *
 wasm_create_global(const WASMModule *module, WASMModuleInstance *dep_inst,
                    WASMGlobalType *type)
@@ -5455,4 +5588,26 @@ wasm_destroy_global(WASMGlobalInstance *global)
         return;
 
     wasm_runtime_free(global);
+}
+
+WASMFunctionInstance *
+wasm_create_function_empty(const WASMModule *module)
+{
+    WASMFunctionInstance *function = runtime_malloc(
+        sizeof(WASMFunctionInstance) + sizeof(WASMFunctionImport), NULL, 0);
+    if (!function) {
+        return NULL;
+    }
+
+    function->u.func_import = (WASMFunctionImport *)(function + 1);
+    return function;
+}
+
+void
+wasm_destroy_function(WASMFunctionInstance *function)
+{
+    if (!function)
+        return;
+
+    wasm_runtime_free(function);
 }

+ 63 - 22
core/iwasm/interpreter/wasm_runtime.h

@@ -233,14 +233,24 @@ struct WASMFunctionInstance {
     uint8 *param_types;
     /* local types, NULL for import function */
     uint8 *local_types;
+
     union {
+        /* setup by wasm_native */
         WASMFunctionImport *func_import;
+        /* local bytecode */
         WASMFunction *func;
     } u;
-#if WASM_ENABLE_MULTI_MODULE != 0
+
+    /* from other .wasm */
     WASMModuleInstance *import_module_inst;
     WASMFunctionInstance *import_func_inst;
-#endif
+    /* copy it from WASMFunctionImport */
+    bool call_conv_raw;
+    /* write it from wasm_c_api */
+    bool call_conv_wasm_c_api;
+    /* WASMModuleInstance collects it to form c_api_func_imports */
+    CApiFuncImport import_func_c_api;
+
 #if WASM_ENABLE_PERF_PROFILING != 0
     /* total execution time */
     uint64 total_exec_time;
@@ -302,16 +312,6 @@ typedef struct WASMExportTagInstance {
 } WASMExportTagInstance;
 #endif
 
-/* wasm-c-api import function info */
-typedef struct CApiFuncImport {
-    /* host func pointer after linked */
-    void *func_ptr_linked;
-    /* whether the host func has env argument */
-    bool with_env_arg;
-    /* the env argument of the host func */
-    void *env_arg;
-} CApiFuncImport;
-
 /* The common part of WASMModuleInstanceExtra and AOTModuleInstanceExtra */
 typedef struct WASMModuleInstanceExtraCommon {
 #if WASM_ENABLE_MODULE_INST_CONTEXT != 0
@@ -436,6 +436,10 @@ struct WASMModuleInstance {
     DefPointer(WASMModule *, module);
 
     DefPointer(WASMExecEnv *, exec_env_singleton);
+    /*
+     * TODO: is able to be removed.
+     * interp and fast-jit can use func_ptrs instead of this.
+     */
     /* Array of function pointers to import functions,
        not available in AOTModuleInstance */
     DefPointer(void **, import_func_ptrs);
@@ -485,15 +489,6 @@ struct WASMModuleInstance {
 struct WASMInterpFrame;
 typedef struct WASMInterpFrame WASMRuntimeFrame;
 
-#if WASM_ENABLE_MULTI_MODULE != 0
-typedef struct WASMSubModInstNode {
-    bh_list_link l;
-    /* point to a string pool */
-    const char *module_name;
-    WASMModuleInstance *module_inst;
-} WASMSubModInstNode;
-#endif
-
 /**
  * Return the code block of a function.
  *
@@ -546,6 +541,23 @@ wasm_locate_table_elems(const WASMModule *module, WASMTableInstance *table,
     return table->elems;
 }
 
+static inline WASMFunctionInstance *
+wasm_locate_function_instance(const WASMModuleInstance *module_inst,
+                              uint32 func_idx)
+{
+    WASMModuleInstanceExtra *e = (WASMModuleInstanceExtra *)module_inst->e;
+    WASMFunctionInstance *func = e->functions + func_idx;
+    return func;
+}
+
+static inline uint32
+wasm_calc_function_index(const WASMModuleInstance *module_inst,
+                         const WASMFunctionInstance *func)
+{
+    return (uint32)(func
+                    - ((WASMModuleInstanceExtra *)module_inst->e)->functions);
+}
+
 static inline uint32
 wasm_get_tbl_data_slots(const WASMTableType *table_type,
                         const WASMTableImport *import_type)
@@ -624,7 +636,7 @@ wasm_get_wasm_func_exec_time(const WASMModuleInstance *inst,
                              const char *func_name);
 
 void
-wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst);
+wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_spawned);
 
 bool
 wasm_set_running_mode(WASMModuleInstance *module_inst,
@@ -988,6 +1000,35 @@ wasm_set_global_value(WASMGlobalInstance *global, const WASMValue *value);
 void
 wasm_destroy_global(WASMGlobalInstance *global);
 
+WASMFunctionInstance *
+wasm_create_function_empty(const WASMModule *module);
+
+void
+wasm_destroy_function(WASMFunctionInstance *function);
+
+static inline void
+wasm_function_import_from_wasm(WASMFunctionInstance *func,
+                               WASMModuleInstance *dep_inst,
+                               WASMFunctionInstance *dep_func)
+{
+    func->import_module_inst = dep_inst;
+    func->import_func_inst = dep_func;
+}
+
+static inline void
+wasm_function_import_from_c_api(WASMFunctionInstance *func,
+                                CApiFuncImport *c_api_func_import)
+{
+    func->import_func_c_api = *c_api_func_import;
+}
+
+/*might be unused*/
+static inline void
+wasm_function_import_from_native(WASMFunctionInstance *func, void *callback)
+{
+    func->u.func_import->func_ptr_linked = callback;
+}
+
 #ifdef __cplusplus
 }
 #endif

+ 4 - 0
core/iwasm/libraries/libc-builtin/builtin_wrapper.h

@@ -12,6 +12,10 @@
 /*************************************
  * Functions
  *************************************/
+/* clang-format off */
+#define REG_NATIVE_FUNC(func_name, signature) \
+    { #func_name, func_name##_wrapper, signature, NULL }
+/* clang-format on */
 
 /*************************************
  * Globals

+ 7 - 0
core/iwasm/libraries/libc-builtin/spec_test_builtin_wrapper.c

@@ -138,6 +138,13 @@ wasm_runtime_create_extern_inst_for_spec_test(wasm_module_t module,
     if (!module || !import_type || !out)
         return false;
 
+    if (import_type->kind == WASM_IMPORT_EXPORT_KIND_FUNC) {
+        /* Let wasm_native inject wrappers into WASMFunctionImport */
+        LOG_DEBUG("skip import(%s,%s) kind %d", import_type->module_name,
+                  import_type->name, import_type->kind);
+        return true;
+    }
+
     LOG_DEBUG("create import(%s,%s) kind %d", import_type->module_name,
               import_type->name, import_type->kind);