Эх сурвалжийг харах

[instantiation linking] create and import WASMMemoryInstance for interp (#3845)

APIs to create and import WASMMemoryInstance for Interp

- add a demo (sample/linking/raw) for APIs test
- new APIs for instances of spawned threads to build imports list from parents'
liang.he 1 жил өмнө
parent
commit
e030350bd7

+ 4 - 3
.gitignore

@@ -21,9 +21,10 @@ core/iwasm/libraries/lib-wasi-threads/test/*.wasm
 core/iwasm/libraries/lib-socket/test/*.wasm
 
 product-mini/app-samples/hello-world/test.wasm
-product-mini/platforms/linux-sgx/enclave-sample/App/
-product-mini/platforms/linux-sgx/enclave-sample/Enclave/
-product-mini/platforms/linux-sgx/enclave-sample/iwasm
+product-mini/platforms/linux-sgx/enclave-sample/App/*.o
+product-mini/platforms/linux-sgx/enclave-sample/Enclave/*.o
+product-mini/platforms/linux-sgx/enclave-sample/
+!product-mini/platforms/linux-sgx/enclave-sample/Makefile*
 
 build_out
 tests/wamr-test-suites/workspace

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

@@ -3384,7 +3384,7 @@ wasm_func_call(const wasm_func_t *func, const wasm_val_vec_t *params,
             AOTModuleInstance *inst_aot =
                 (AOTModuleInstance *)func->inst_comm_rt;
             AOTModule *module_aot = (AOTModule *)inst_aot->module;
-            uint32 export_i = 0, export_func_j = 0;
+            uint32 export_i = 0;
 
             for (; export_i < module_aot->export_count; ++export_i) {
                 AOTExport *export = module_aot->exports + export_i;
@@ -3395,7 +3395,6 @@ wasm_func_call(const wasm_func_t *func, const wasm_val_vec_t *params,
                         ((wasm_func_t *)func)->func_comm_rt = func_comm_rt;
                         break;
                     }
-                    export_func_j++;
                 }
             }
         }

+ 42 - 0
core/iwasm/common/wasm_memory.c

@@ -1535,6 +1535,48 @@ wasm_enlarge_memory_with_idx(WASMModuleInstance *module, uint32 inc_page_count,
     return ret;
 }
 
+WASMMemoryInstance *
+wasm_runtime_create_memory(WASMModuleCommon *module, WASMMemoryType *type)
+{
+    if (!module)
+        return NULL;
+
+#if WASM_ENABLE_INTERP != 0
+    if (module->module_type == Wasm_Module_Bytecode)
+        return wasm_create_memory((WASMModule *)module, type);
+#endif
+
+#if WASM_ENABLE_AOT != 0
+    if (module->module_type == Wasm_Module_AoT)
+        bh_assert(false && "Unsupported operation");
+#endif
+
+    LOG_ERROR("create memory failed, invalid module type");
+    return NULL;
+}
+
+void
+wasm_runtime_destroy_memory(WASMModuleCommon *const module,
+                            WASMMemoryInstance *memory)
+{
+    if (!module)
+        return;
+
+#if WASM_ENABLE_INTERP != 0
+    if (module->module_type == Wasm_Module_Bytecode) {
+        wasm_destroy_memory(memory);
+        return;
+    }
+#endif
+
+#if WASM_ENABLE_AOT != 0
+    if (module->module_type == Wasm_Module_AoT)
+        bh_assert(false && "Unsupported operation");
+#endif
+
+    LOG_ERROR("destroy memory failed, invalid module type");
+}
+
 WASMMemoryInstance *
 wasm_runtime_lookup_memory(WASMModuleInstanceCommon *module_inst,
                            const char *name)

+ 211 - 7
core/iwasm/common/wasm_runtime_common.c

@@ -1351,6 +1351,7 @@ wasm_runtime_destroy_loading_module_list()
 }
 #endif /* WASM_ENABLE_MULTI_MODULE */
 
+/*TODO: may need to merge with wasm_native. Even do more classification work */
 bool
 wasm_runtime_is_built_in_module(const char *module_name)
 {
@@ -1360,7 +1361,7 @@ wasm_runtime_is_built_in_module(const char *module_name)
             || !strcmp("spectest", module_name)
 #endif
 #if WASM_ENABLE_WASI_TEST != 0
-            || !strcmp("foo", module_name)
+            || !strcmp("foo", module_name) || !strncmp("wasi", module_name, 4)
 #endif
             || !strcmp("", module_name));
 }
@@ -1622,13 +1623,16 @@ wasm_runtime_instantiate_internal(WASMModuleCommon *module,
                                   WASMModuleInstanceCommon *parent,
                                   WASMExecEnv *exec_env_main, uint32 stack_size,
                                   uint32 heap_size, uint32 max_memory_pages,
-                                  char *error_buf, uint32 error_buf_size)
+                                  const WASMExternInstance *imports,
+                                  uint32 import_count, char *error_buf,
+                                  uint32 error_buf_size)
 {
 #if WASM_ENABLE_INTERP != 0
     if (module->module_type == Wasm_Module_Bytecode)
         return (WASMModuleInstanceCommon *)wasm_instantiate(
             (WASMModule *)module, (WASMModuleInstance *)parent, exec_env_main,
-            stack_size, heap_size, max_memory_pages, error_buf, error_buf_size);
+            stack_size, heap_size, max_memory_pages, imports, import_count,
+            error_buf, error_buf_size);
 #endif
 #if WASM_ENABLE_AOT != 0
     if (module->module_type == Wasm_Module_AoT)
@@ -1647,8 +1651,11 @@ wasm_runtime_instantiate(WASMModuleCommon *module, uint32 stack_size,
                          uint32 error_buf_size)
 {
     return wasm_runtime_instantiate_internal(module, NULL, NULL, stack_size,
-                                             heap_size, 0, error_buf,
-                                             error_buf_size);
+                                             heap_size,
+                                             0,    // max_memory_pages
+                                             NULL, // imports
+                                             0,    // import_count
+                                             error_buf, error_buf_size);
 }
 
 WASMModuleInstanceCommon *
@@ -1658,8 +1665,8 @@ wasm_runtime_instantiate_ex(WASMModuleCommon *module,
 {
     return wasm_runtime_instantiate_internal(
         module, NULL, NULL, args->default_stack_size,
-        args->host_managed_heap_size, args->max_memory_pages, error_buf,
-        error_buf_size);
+        args->host_managed_heap_size, args->max_memory_pages, args->imports,
+        args->import_count, error_buf, error_buf_size);
 }
 
 void
@@ -7474,6 +7481,8 @@ wasm_runtime_sub_module_instantiate(WASMModuleCommon *module,
         WASMModuleInstanceCommon *sub_module_inst = NULL;
         sub_module_inst = wasm_runtime_instantiate_internal(
             sub_module, NULL, NULL, stack_size, heap_size, max_memory_pages,
+            NULL, // imports
+            0,    // import_count
             error_buf, error_buf_size);
         if (!sub_module_inst) {
             LOG_DEBUG("instantiate %s failed",
@@ -7739,3 +7748,198 @@ wasm_runtime_is_underlying_binary_freeable(WASMModuleCommon *const module)
 
     return true;
 }
+
+/*TODO: take us(below) out when have a linker */
+bool
+wasm_runtime_create_extern_inst(WASMModuleCommon *module,
+                                wasm_import_t import_type,
+                                WASMExternInstance *out)
+{
+    if (!out)
+        return false;
+
+    LOG_DEBUG("create import(%s,%s) kind %d", import_type.module_name,
+              import_type.name, import_type.kind);
+
+    out->module_name = import_type.module_name;
+    out->field_name = import_type.name;
+    out->kind = import_type.kind;
+
+    if (import_type.kind == WASM_IMPORT_EXPORT_KIND_MEMORY) {
+        out->u.memory =
+            wasm_runtime_create_memory(module, import_type.u.memory_type);
+        if (!out->u.memory) {
+            LOG_ERROR("create memory failed\n");
+            return false;
+        }
+    }
+    else {
+        LOG_DEBUG("unimplemented import(%s,%s) kind %d",
+                  import_type.module_name, import_type.name, import_type.kind);
+    }
+
+    return true;
+}
+
+void
+wasm_runtime_destroy_extern_inst(WASMModuleCommon *module,
+                                 WASMExternInstance *extern_inst)
+{
+    if (!extern_inst)
+        return;
+
+    if (extern_inst->kind == WASM_IMPORT_EXPORT_KIND_MEMORY) {
+        wasm_runtime_destroy_memory(module, extern_inst->u.memory);
+        extern_inst->u.memory = NULL;
+    }
+    else {
+        LOG_DEBUG("unimplemented import(%s,%s) kind %d",
+                  extern_inst->module_name, extern_inst->field_name,
+                  extern_inst->kind);
+    }
+
+    extern_inst->module_name = NULL;
+    extern_inst->field_name = NULL;
+}
+
+/*
+ * willn't take the ownership of new_extern_inst
+ * take the ownership of the content of new_extern_inst
+ */
+bool
+wasm_runtime_overwirte_imports(WASMModuleCommon *module,
+                               WASMExternInstance *orig_extern_inst_list,
+                               WASMExternInstance *new_extern_inst, int32 index)
+{
+    // argument check
+    if (!module || !orig_extern_inst_list || !new_extern_inst) {
+        return false;
+    }
+
+    // check index with the import count of the module
+    if (index < 0 || index >= wasm_runtime_get_import_count(module)) {
+        return false;
+    }
+
+    // get the targeted extern_inst. allow to be NULL
+    WASMExternInstance *old_extern_inst = orig_extern_inst_list + index;
+
+    // release the targeted extern_inst if not NULL
+    wasm_runtime_destroy_extern_inst(module, old_extern_inst);
+
+    // overwrite the targeted extern_inst
+    bh_memcpy_s(old_extern_inst, sizeof(WASMExternInstance), new_extern_inst,
+                sizeof(WASMExternInstance));
+    return true;
+}
+
+/*
+ * 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.
+ */
+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++) {
+        wasm_runtime_destroy_extern_inst(module, extern_inst_list + i);
+    }
+
+    wasm_runtime_free(extern_inst_list);
+}
+
+WASMExternInstance *
+wasm_runtime_create_imports(WASMModuleCommon *module,
+                            bool (*module_name_filter)(const char *))
+{
+    int32 import_count = wasm_runtime_get_import_count(module);
+    WASMExternInstance *imports = NULL;
+
+    if (import_count == 0)
+        return NULL;
+
+    imports = runtime_malloc(sizeof(WASMExternInstance) * import_count,
+                             NULL, // module_inst
+                             NULL, 0);
+    if (!imports) {
+        LOG_ERROR("allocate memory failed");
+        return NULL;
+    }
+
+    for (int32 i = 0; i < import_count; i++) {
+        wasm_import_t import_type = { 0 };
+        wasm_runtime_get_import_type(module, i, &import_type);
+
+        if (module_name_filter
+            && !module_name_filter(import_type.module_name)) {
+            LOG_DEBUG("skip import(%s,%s)", import_type.module_name,
+                      import_type.name);
+            continue;
+        }
+
+        WASMExternInstance *extern_instance = imports + i;
+        if (!wasm_runtime_create_extern_inst(module, import_type,
+                                             extern_instance)) {
+            wasm_runtime_destroy_imports(module, imports);
+            LOG_ERROR("create import failed");
+            return NULL;
+        }
+    }
+
+    return imports;
+}
+
+WASMExternInstance *
+wasm_runtime_create_imports_with_builtin(WASMModuleCommon *module)
+{
+    LOG_DEBUG("create imports with builtin");
+    return wasm_runtime_create_imports(module, wasm_runtime_is_built_in_module);
+}
+
+#if WASM_ENABLE_LIB_WASI_THREADS != 0 || WASM_ENABLE_THREAD_MGR != 0
+/*
+ * The function is used to create a new WASMExternInstance list
+ * for a spawned thread.
+ */
+int32
+wasm_runtime_inherit_imports(WASMModuleCommon *module,
+                             WASMModuleInstanceCommon *inst,
+                             WASMExternInstance *out, int32 out_len)
+{
+#if WASM_ENABLE_INTERP != 0
+    if (module->module_type == Wasm_Module_Bytecode) {
+        return wasm_inherit_imports((WASMModule *)module,
+                                    (WASMModuleInstance *)inst, out, out_len);
+    }
+#endif
+#if WASM_ENABLE_AOT != 0
+    if (module->module_type == Wasm_Module_AoT) {
+        bh_assert(false && "Unsupported operation");
+    }
+#endif
+    LOG_ERROR("inherit imports failed, invalid module type");
+    return 0;
+}
+
+void
+wasm_runtime_disinherit_imports(WASMModuleCommon *module,
+                                WASMExternInstance *imports, int32 import_count)
+{
+#if WASM_ENABLE_INTERP != 0
+    if (module->module_type == Wasm_Module_Bytecode) {
+        wasm_disinherit_imports((WASMModule *)module, imports, import_count);
+        return;
+    }
+#endif
+#if WASM_ENABLE_AOT != 0
+    if (module->module_type == Wasm_Module_AoT) {
+        bh_assert(false && "Unsupported operation");
+    }
+#endif
+    LOG_ERROR("disinherit imports failed, invalid module type");
+}
+#endif /* WASM_ENABLE_LIB_WASI_THREADS != 0 || WASM_ENABLE_THREAD_MGR != 0 */

+ 19 - 1
core/iwasm/common/wasm_runtime_common.h

@@ -575,7 +575,9 @@ wasm_runtime_instantiate_internal(WASMModuleCommon *module,
                                   WASMModuleInstanceCommon *parent,
                                   WASMExecEnv *exec_env_main, uint32 stack_size,
                                   uint32 heap_size, uint32 max_memory_pages,
-                                  char *error_buf, uint32 error_buf_size);
+                                  const WASMExternInstance *imports,
+                                  uint32 import_count, char *error_buf,
+                                  uint32 error_buf_size);
 
 /* Internal API */
 void
@@ -1215,6 +1217,22 @@ void
 wasm_runtime_set_linux_perf(bool flag);
 #endif
 
+#if WASM_ENABLE_LIB_WASI_THREADS != 0 || WASM_ENABLE_THREAD_MGR != 0
+/*
+ * The function is used to create a new WASMExternInstance list
+ * for a spawned thread.
+ */
+int32
+wasm_runtime_inherit_imports(WASMModuleCommon *module,
+                             WASMModuleInstanceCommon *inst,
+                             WASMExternInstance *out, int32 out_len);
+
+void
+wasm_runtime_disinherit_imports(WASMModuleCommon *module,
+                                WASMExternInstance *imports,
+                                int32 import_count);
+#endif
+
 #ifdef __cplusplus
 }
 #endif

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

@@ -199,6 +199,8 @@ typedef struct InstantiationArgs {
     uint32_t default_stack_size;
     uint32_t host_managed_heap_size;
     uint32_t max_memory_pages;
+    const struct WasmExternInstance *imports;
+    uint32_t import_count;
 } InstantiationArgs;
 #endif /* INSTANTIATION_ARGS_OPTION_DEFINED */
 

+ 44 - 0
core/iwasm/include/wasm_export.h

@@ -264,6 +264,15 @@ typedef struct LoadArgs {
 } LoadArgs;
 #endif /* LOAD_ARGS_OPTION_DEFINED */
 
+typedef struct WASMExternInstance {
+    const char *module_name;
+    const char *field_name;
+    wasm_import_export_kind_t kind;
+    union {
+        wasm_memory_inst_t memory;
+    } u;
+} WASMExternInstance, *wasm_extern_inst_t;
+
 #ifndef INSTANTIATION_ARGS_OPTION_DEFINED
 #define INSTANTIATION_ARGS_OPTION_DEFINED
 /* WASM module instantiation arguments */
@@ -271,6 +280,8 @@ typedef struct InstantiationArgs {
     uint32_t default_stack_size;
     uint32_t host_managed_heap_size;
     uint32_t max_memory_pages;
+    const wasm_extern_inst_t imports;
+    uint32_t import_count;
 } InstantiationArgs;
 #endif /* INSTANTIATION_ARGS_OPTION_DEFINED */
 
@@ -961,6 +972,25 @@ WASM_RUNTIME_API_EXTERN void
 wasm_runtime_set_module_inst(wasm_exec_env_t exec_env,
                              const wasm_module_inst_t module_inst);
 
+/**
+ * Create a memory instance.
+ * don't have a app heap
+ *
+ * @return The created memory instance if successful, NULL otherwise
+ */
+WASM_RUNTIME_API_EXTERN wasm_memory_inst_t
+wasm_runtime_create_memory(const wasm_module_t module,
+                           const wasm_memory_type_t type);
+
+/**
+ * @brief Destroy a memory instance
+ *
+ * @param memory_inst The memory instance to destroy
+ */
+WASM_RUNTIME_API_EXTERN void
+wasm_runtime_destroy_memory(const wasm_module_t module,
+                            wasm_memory_inst_t memory_inst);
+
 /**
  * @brief Lookup a memory instance by name
  *
@@ -2300,6 +2330,20 @@ wasm_runtime_shared_heap_malloc(wasm_module_inst_t module_inst, uint64_t size,
 WASM_RUNTIME_API_EXTERN void
 wasm_runtime_shared_heap_free(wasm_module_inst_t module_inst, uint64_t ptr);
 
+/*TODO: take me out when have a linker */
+/**
+ * @return NULL if failed and if there is no import
+ */
+WASM_RUNTIME_API_EXTERN wasm_extern_inst_t
+wasm_runtime_create_imports_with_builtin(wasm_module_t module);
+
+WASM_RUNTIME_API_EXTERN void
+wasm_runtime_destroy_imports(wasm_module_t module, wasm_extern_inst_t imports);
+
+WASM_RUNTIME_API_EXTERN wasm_extern_inst_t
+wasm_runtime_create_imports(wasm_module_t module,
+                            bool (*module_name_filter)(const char *));
+
 #ifdef __cplusplus
 }
 #endif

+ 1 - 27
core/iwasm/interpreter/wasm_loader.c

@@ -6580,7 +6580,7 @@ check_wasi_abi_compatibility(const WASMModule *module,
      */
     /* clang-format on */
 
-    WASMExport *initialize = NULL, *memory = NULL, *start = NULL;
+    WASMExport *initialize = NULL, *start = NULL;
     uint32 import_function_count = module->import_function_count;
     WASMFuncType *func_type;
 
@@ -6655,32 +6655,6 @@ check_wasi_abi_compatibility(const WASMModule *module,
     }
 #endif
 
-    /*
-     * it is ok a reactor acts as a main module,
-     * so skip the check about (with `_initialize`)
-     */
-
-    memory = wasm_loader_find_export(module, "", "memory", EXPORT_KIND_MEMORY,
-                                     error_buf, error_buf_size);
-    if (!memory
-#if WASM_ENABLE_LIB_WASI_THREADS != 0
-        /*
-         * with wasi-threads, it's still an open question if a memory
-         * should be exported.
-         *
-         * https://github.com/WebAssembly/wasi-threads/issues/22
-         * https://github.com/WebAssembly/WASI/issues/502
-         *
-         * Note: this code assumes the number of memories is at most 1.
-         */
-        && module->import_memory_count == 0
-#endif
-    ) {
-        set_error_buf(error_buf, error_buf_size,
-                      "a module with WASI apis must export memory by default");
-        return false;
-    }
-
     return true;
 }
 #endif

+ 343 - 113
core/iwasm/interpreter/wasm_runtime.c

@@ -233,74 +233,89 @@ get_sub_module_inst(const WASMModuleInstance *parent_module_inst,
 /**
  * Destroy memory instances.
  */
+
+static void
+memory_deinstantiate(WASMMemoryInstance *memory)
+{
+    if (!memory)
+        return;
+
+#if WASM_ENABLE_SHARED_MEMORY != 0
+    if (shared_memory_is_shared(memory)) {
+        uint32 ref_count = shared_memory_dec_reference(memory);
+        /* if the reference count is not zero,
+            don't free the memory */
+        if (ref_count > 0)
+            return;
+    }
+#endif
+
+    if (memory->heap_handle) {
+        mem_allocator_destroy(memory->heap_handle);
+        wasm_runtime_free(memory->heap_handle);
+        memory->heap_handle = NULL;
+    }
+
+    if (memory->memory_data) {
+        wasm_deallocate_linear_memory(memory);
+        memory->memory_data = NULL;
+    }
+}
+
 static void
 memories_deinstantiate(WASMModuleInstance *module_inst,
                        WASMMemoryInstance **memories, uint32 count)
 {
-    uint32 i;
-    if (memories) {
-        for (i = 0; i < count; i++) {
-            if (memories[i]) {
+    WASMModule *module = module_inst->module;
+
+    if (!memories)
+        return;
+
+    /*
+     * If created by host or linker, import memories should also be released by
+     * host or linker
+     */
+    for (uint32 i = 0; i < count; i++) {
+        if (i < module->import_memory_count
 #if WASM_ENABLE_MULTI_MODULE != 0
-                WASMModule *module = module_inst->module;
-                if (i < module->import_memory_count
-                    && module->import_memories[i].u.memory.import_module) {
-                    continue;
-                }
+            && module->import_memories[i].u.memory.import_module
 #endif
-#if WASM_ENABLE_SHARED_MEMORY != 0
-                if (shared_memory_is_shared(memories[i])) {
-                    uint32 ref_count = shared_memory_dec_reference(memories[i]);
-                    /* if the reference count is not zero,
-                        don't free the memory */
-                    if (ref_count > 0)
-                        continue;
-                }
-#endif
-                if (memories[i]->heap_handle) {
-                    mem_allocator_destroy(memories[i]->heap_handle);
-                    wasm_runtime_free(memories[i]->heap_handle);
-                    memories[i]->heap_handle = NULL;
-                }
-                if (memories[i]->memory_data) {
-                    wasm_deallocate_linear_memory(memories[i]);
-                }
-            }
+        ) {
+            continue;
         }
-        wasm_runtime_free(memories);
+
+        memory_deinstantiate(memories[i]);
     }
+
+    wasm_runtime_free(memories);
     (void)module_inst;
 }
 
 static WASMMemoryInstance *
-memory_instantiate(WASMModuleInstance *module_inst, WASMModuleInstance *parent,
-                   WASMMemoryInstance *memory, uint32 memory_idx,
-                   uint32 num_bytes_per_page, uint32 init_page_count,
-                   uint32 max_page_count, uint32 heap_size, uint32 flags,
-                   char *error_buf, uint32 error_buf_size)
+memory_instantiate(const WASMModule *module, WASMModuleInstance *parent,
+                   WASMMemoryInstance *memory,
+                   WASMMemoryInstance *parent_memory, uint32 num_bytes_per_page,
+                   uint32 init_page_count, uint32 max_page_count,
+                   uint32 heap_size, uint32 flags,
+                   uint8 *aux_heap_base_global_data, char *error_buf,
+                   uint32 error_buf_size)
 {
-    WASMModule *module = module_inst->module;
-    uint32 inc_page_count, global_idx, default_max_page;
-    uint32 bytes_of_last_page, bytes_to_page_end;
-    uint64 aux_heap_base,
-        heap_offset = (uint64)num_bytes_per_page * init_page_count;
-    uint64 memory_data_size, max_memory_data_size;
-    uint8 *global_addr;
-
     bool is_shared_memory = false;
 #if WASM_ENABLE_SHARED_MEMORY != 0
     is_shared_memory = flags & SHARED_MEMORY_FLAG ? true : false;
 
+    bh_assert(memory != NULL);
+
     /* shared memory */
     if (is_shared_memory && parent != NULL) {
-        bh_assert(parent->memory_count > memory_idx);
-        memory = parent->memories[memory_idx];
+        bh_assert(parent->memory_count > 0);
+        memory = parent_memory;
         shared_memory_inc_reference(memory);
         return memory;
     }
 #else
     (void)parent;
-    (void)memory_idx;
+    (void)parent_memory;
     (void)flags;
 #endif /* end of WASM_ENABLE_SHARED_MEMORY */
 
@@ -309,13 +324,12 @@ memory_instantiate(WASMModuleInstance *module_inst, WASMModuleInstance *parent,
         memory->is_memory64 = 1;
     }
 #endif
-    default_max_page =
-        memory->is_memory64 ? DEFAULT_MEM64_MAX_PAGES : DEFAULT_MAX_PAGES;
 
-    /* The app heap should be in the default memory */
-    if (memory_idx == 0) {
-        if (heap_size > 0 && module_inst->module->malloc_function != (uint32)-1
-            && module_inst->module->free_function != (uint32)-1) {
+    /* adjust heap_size, heap_offset and num_bytes_per_page */
+    uint64 heap_offset = (uint64)num_bytes_per_page * init_page_count;
+    {
+        if (heap_size > 0 && module->malloc_function != (uint32)-1
+            && module->free_function != (uint32)-1) {
             /* Disable app heap, use malloc/free function exported
                by wasm app to allocate/free memory instead */
             heap_size = 0;
@@ -345,6 +359,7 @@ memory_instantiate(WASMModuleInstance *module_inst, WASMModuleInstance *parent,
             }
         }
         else if (heap_size > 0) {
+            uint32 inc_page_count = 0;
             if (init_page_count == max_page_count && init_page_count == 0) {
                 /* If the memory data size is always 0, we resize it to
                    one page for app heap */
@@ -356,11 +371,12 @@ memory_instantiate(WASMModuleInstance *module_inst, WASMModuleInstance *parent,
                      && module->aux_heap_base
                             < (uint64)num_bytes_per_page * init_page_count) {
                 /* Insert app heap before __heap_base */
-                aux_heap_base = module->aux_heap_base;
-                bytes_of_last_page = aux_heap_base % num_bytes_per_page;
+                uint64 aux_heap_base = module->aux_heap_base;
+                uint32 bytes_of_last_page = aux_heap_base % num_bytes_per_page;
                 if (bytes_of_last_page == 0)
                     bytes_of_last_page = num_bytes_per_page;
-                bytes_to_page_end = num_bytes_per_page - bytes_of_last_page;
+                uint32 bytes_to_page_end =
+                    num_bytes_per_page - bytes_of_last_page;
                 inc_page_count =
                     (heap_size - bytes_to_page_end + num_bytes_per_page - 1)
                     / num_bytes_per_page;
@@ -377,21 +393,24 @@ memory_instantiate(WASMModuleInstance *module_inst, WASMModuleInstance *parent,
                 }
 
                 /* Adjust __heap_base global value */
-                global_idx = module->aux_heap_base_global_index;
-                bh_assert(module_inst->e->globals
-                          && global_idx < module_inst->e->global_count);
-                global_addr = module_inst->global_data
-                              + module_inst->e->globals[global_idx].data_offset;
+                if (aux_heap_base_global_data == NULL) {
+                    set_error_buf(
+                        error_buf, error_buf_size,
+                        "auxiliary heap base global data should not be NULL");
+                    return NULL;
+                }
+
 #if WASM_ENABLE_MEMORY64 != 0
                 if (memory->is_memory64) {
                     /* For memory64, the global value should be i64 */
-                    *(uint64 *)global_addr = aux_heap_base;
+                    *(uint64 *)aux_heap_base_global_data = aux_heap_base;
                 }
                 else
 #endif
                 {
                     /* For memory32, the global value should be i32 */
-                    *(uint32 *)global_addr = (uint32)aux_heap_base;
+                    *(uint32 *)aux_heap_base_global_data =
+                        (uint32)aux_heap_base;
                 }
                 LOG_VERBOSE("Reset __heap_base global to %" PRIu64,
                             aux_heap_base);
@@ -405,6 +424,10 @@ memory_instantiate(WASMModuleInstance *module_inst, WASMModuleInstance *parent,
                 if (heap_size > 0)
                     heap_size -= 1 * BH_KB;
             }
+
+            uint32 default_max_page = memory->is_memory64
+                                          ? DEFAULT_MEM64_MAX_PAGES
+                                          : DEFAULT_MAX_PAGES;
             init_page_count += inc_page_count;
             max_page_count += inc_page_count;
             if (init_page_count > default_max_page) {
@@ -422,17 +445,18 @@ memory_instantiate(WASMModuleInstance *module_inst, WASMModuleInstance *parent,
     LOG_VERBOSE("Memory instantiate:");
     LOG_VERBOSE("  page bytes: %u, init pages: %u, max pages: %u",
                 num_bytes_per_page, init_page_count, max_page_count);
-    if (memory_idx == 0)
-        LOG_VERBOSE("  heap offset: %" PRIu64 ", heap size: %u\n", heap_offset,
-                    heap_size);
 
-    max_memory_data_size = (uint64)num_bytes_per_page * max_page_count;
-    bh_assert(max_memory_data_size
-              <= GET_MAX_LINEAR_MEMORY_SIZE(memory->is_memory64));
-    (void)max_memory_data_size;
-
-    bh_assert(memory != NULL);
+#ifndef NDEBUG
+    {
+        uint64 max_memory_data_size =
+            (uint64)num_bytes_per_page * max_page_count;
+        bh_assert(max_memory_data_size
+                  <= GET_MAX_LINEAR_MEMORY_SIZE(memory->is_memory64));
+        (void)max_memory_data_size;
+    }
+#endif
 
+    uint64 memory_data_size = 0;
     if (wasm_allocate_linear_memory(&memory->memory_data, is_shared_memory,
                                     memory->is_memory64, num_bytes_per_page,
                                     init_page_count, max_page_count,
@@ -448,21 +472,24 @@ memory_instantiate(WASMModuleInstance *module_inst, WASMModuleInstance *parent,
     memory->cur_page_count = init_page_count;
     memory->max_page_count = max_page_count;
     memory->memory_data_size = memory_data_size;
-
-    if (memory_idx == 0) {
-        memory->heap_data = memory->memory_data + heap_offset;
-        memory->heap_data_end = memory->heap_data + heap_size;
-        memory->memory_data_end = memory->memory_data + memory_data_size;
-    }
+    memory->heap_data = memory->memory_data + heap_offset;
+    memory->heap_data_end = memory->heap_data + heap_size;
+    memory->memory_data_end = memory->memory_data + memory->memory_data_size;
 
     /* Initialize heap */
-    if (memory_idx == 0 && heap_size > 0) {
+    if (heap_size > 0) {
+        LOG_VERBOSE("  heap offset: %" PRIu64 ", heap size: %u\n", heap_offset,
+                    heap_size);
+
         uint32 heap_struct_size = mem_allocator_get_heap_struct_size();
 
         if (!(memory->heap_handle = runtime_malloc(
                   (uint64)heap_struct_size, error_buf, error_buf_size))) {
+            set_error_buf(error_buf, error_buf_size,
+                          "allocate app heap failed");
             goto fail1;
         }
+
         if (!mem_allocator_create_with_struct_and_pool(
                 memory->heap_handle, heap_struct_size, memory->heap_data,
                 heap_size)) {
@@ -486,11 +513,14 @@ memory_instantiate(WASMModuleInstance *module_inst, WASMModuleInstance *parent,
     return memory;
 
 fail2:
-    if (memory_idx == 0 && heap_size > 0)
+    if (heap_size > 0) {
         wasm_runtime_free(memory->heap_handle);
+        memory->heap_handle = NULL;
+    }
 fail1:
-    if (memory->memory_data)
+    if (memory->memory_data) {
         wasm_deallocate_linear_memory(memory);
+    }
 
     return NULL;
 }
@@ -501,10 +531,9 @@ fail1:
 static WASMMemoryInstance **
 memories_instantiate(const WASMModule *module, WASMModuleInstance *module_inst,
                      WASMModuleInstance *parent, uint32 heap_size,
-                     uint32 max_memory_pages, char *error_buf,
-                     uint32 error_buf_size)
+                     uint32 max_memory_pages, uint8 *aux_heap_base_global_data,
+                     char *error_buf, uint32 error_buf_size)
 {
-    WASMImport *import;
     uint32 mem_index = 0, i,
            memory_count = module->import_memory_count + module->memory_count;
     uint64 total_size;
@@ -519,18 +548,10 @@ memories_instantiate(const WASMModule *module, WASMModuleInstance *module_inst,
     memory = module_inst->global_table_data.memory_instances;
 
     /* instantiate memories from import section */
-    import = module->import_memories;
-    for (i = 0; i < module->import_memory_count; i++, import++, memory++) {
-        uint32 num_bytes_per_page =
-            import->u.memory.mem_type.num_bytes_per_page;
-        uint32 init_page_count = import->u.memory.mem_type.init_page_count;
-        uint32 max_page_count = wasm_runtime_get_max_mem(
-            max_memory_pages, import->u.memory.mem_type.init_page_count,
-            import->u.memory.mem_type.max_page_count);
-        uint32 flags = import->u.memory.mem_type.flags;
-        uint32 actual_heap_size = heap_size;
-
 #if WASM_ENABLE_MULTI_MODULE != 0
+    WASMImport *import = module->import_memories;
+    for (i = 0; i < module->import_memory_count; i++, import++, memory++) {
+        // TODO: ? make sure import->u.memory.import_module is set properly
         if (import->u.memory.import_module != NULL) {
             WASMModuleInstance *module_inst_linked;
 
@@ -548,13 +569,24 @@ memories_instantiate(const WASMModule *module, WASMModuleInstance *module_inst,
                 return NULL;
             }
         }
-        else
-#endif
-        {
+        else {
+            // TODO: Although it is for inherited memory, it misses a situation
+            // where the memory is imported from host or other modules
+            uint32 num_bytes_per_page =
+                import->u.memory.mem_type.num_bytes_per_page;
+            uint32 init_page_count = import->u.memory.mem_type.init_page_count;
+            uint32 max_page_count = wasm_runtime_get_max_mem(
+                max_memory_pages, import->u.memory.mem_type.init_page_count,
+                import->u.memory.mem_type.max_page_count);
+            uint32 flags = import->u.memory.mem_type.flags;
+
             if (!(memories[mem_index] = memory_instantiate(
-                      module_inst, parent, memory, mem_index,
+                      module, parent, memory,
+                      parent ? parent->memories[mem_index] : NULL,
                       num_bytes_per_page, init_page_count, max_page_count,
-                      actual_heap_size, flags, error_buf, error_buf_size))) {
+                      /* only inst->memories[0] will have an app heap */
+                      mem_index == 0 ? heap_size : 0, flags,
+                      aux_heap_base_global_data, error_buf, error_buf_size))) {
                 memories_deinstantiate(module_inst, memories, memory_count);
                 return NULL;
             }
@@ -562,17 +594,29 @@ memories_instantiate(const WASMModule *module, WASMModuleInstance *module_inst,
         }
     }
 
+    bh_assert(mem_index == module->import_memory_count);
+    bh_assert(memory
+              == module_inst->global_table_data.memory_instances
+                     + module->import_memory_count);
+#else
+    mem_index = module->import_memory_count;
+    memory = module_inst->global_table_data.memory_instances
+             + module->import_memory_count;
+#endif /* WASM_ENABLE_MULTI_MODULE != 0 */
+
     /* instantiate memories from memory section */
     for (i = 0; i < module->memory_count; i++, memory++) {
         uint32 max_page_count = wasm_runtime_get_max_mem(
             max_memory_pages, module->memories[i].init_page_count,
             module->memories[i].max_page_count);
         if (!(memories[mem_index] = memory_instantiate(
-                  module_inst, parent, memory, mem_index,
+                  module, parent, memory,
+                  parent ? parent->memories[mem_index] : NULL,
                   module->memories[i].num_bytes_per_page,
                   module->memories[i].init_page_count, max_page_count,
-                  heap_size, module->memories[i].flags, error_buf,
-                  error_buf_size))) {
+                  /* only inst->memories[0] will have a app heap */
+                  mem_index == 0 ? heap_size : 0, module->memories[i].flags,
+                  aux_heap_base_global_data, error_buf, error_buf_size))) {
             memories_deinstantiate(module_inst, memories, memory_count);
             return NULL;
         }
@@ -584,6 +628,50 @@ memories_instantiate(const WASMModule *module, WASMModuleInstance *module_inst,
     return memories;
 }
 
+WASMMemoryInstance *
+wasm_create_memory(const WASMModule *module, const WASMMemoryType *type)
+{
+    WASMMemoryInstance *memory = NULL;
+    char error_buf[64] = { 0 };
+
+    memory = runtime_malloc(sizeof(WASMMemoryInstance), error_buf,
+                            sizeof(error_buf));
+    if (!memory) {
+        LOG_ERROR("Failed to create WASMMemoryInstance: %s", error_buf);
+        return NULL;
+    }
+
+    /*
+     * use provided max_page_count of type instead of adjusting with
+     * wasm_runtime_get_max_mem()
+     */
+    if (!memory_instantiate(module,
+                            NULL, // parent
+                            memory,
+                            NULL, // parent_memory
+                            type->num_bytes_per_page, type->init_page_count,
+                            type->max_page_count,
+                            0, // no heap_size from host side
+                            type->flags,
+                            NULL, // aux_heap_base_global_data
+                            error_buf, sizeof(error_buf))) {
+        wasm_runtime_free(memory);
+        return NULL;
+    }
+
+    return memory;
+}
+
+void
+wasm_destroy_memory(WASMMemoryInstance *memory)
+{
+    if (!memory)
+        return;
+
+    memory_deinstantiate(memory);
+    wasm_runtime_free(memory);
+}
+
 /**
  * Destroy table instances.
  */
@@ -1879,6 +1967,12 @@ execute_free_function(WASMModuleInstance *module_inst, WASMExecEnv *exec_env,
     return ret;
 }
 
+/*
+ * all imported WASMXXXInstance shall be linked and NOT NULL
+ *
+ * TODO: not sure if MULTI_MODULE can be used under the same conditions
+ * for checking.
+ */
 static bool
 check_linked_symbol(WASMModuleInstance *module_inst, char *error_buf,
                     uint32 error_buf_size)
@@ -1932,16 +2026,19 @@ check_linked_symbol(WASMModuleInstance *module_inst, char *error_buf,
     }
 
     for (i = 0; i < module->import_memory_count; i++) {
-        WASMMemoryImport *memory = &((module->import_memories + i)->u.memory);
-
-        if (!wasm_runtime_is_built_in_module(memory->module_name)
+        WASMMemoryImport *type = &((module->import_memories + i)->u.memory);
+        WASMMemoryInstance *memory = module_inst->memories[i];
+        if (
 #if WASM_ENABLE_MULTI_MODULE != 0
-            && !memory->import_memory_linked
+            !wasm_runtime_is_built_in_module(type->module_name)
+            && !type->import_memory_linked
+#else
+            !memory
 #endif
         ) {
             set_error_buf_v(error_buf, error_buf_size,
                             "failed to link import memory (%s, %s)",
-                            memory->module_name, memory->field_name);
+                            type->module_name, type->field_name);
             return false;
         }
     }
@@ -2340,8 +2437,9 @@ wasm_set_running_mode(WASMModuleInstance *module_inst, RunningMode running_mode)
 WASMModuleInstance *
 wasm_instantiate(WASMModule *module, WASMModuleInstance *parent,
                  WASMExecEnv *exec_env_main, uint32 stack_size,
-                 uint32 heap_size, uint32 max_memory_pages, char *error_buf,
-                 uint32 error_buf_size)
+                 uint32 heap_size, uint32 max_memory_pages,
+                 const WASMExternInstance *imports, uint32 import_count,
+                 char *error_buf, uint32 error_buf_size)
 {
     WASMModuleInstance *module_inst;
     WASMGlobalInstance *globals = NULL, *global;
@@ -2362,6 +2460,18 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent,
     if (!module)
         return NULL;
 
+#if WASM_ENABLE_MULTI_MODULE == 0
+    if (module->import_count > 0 && !imports) {
+        /*
+         * TODO: might be too strict
+         * might wasm_runtime_create_imports_with_builtin() here by default
+         */
+        set_error_buf(error_buf, error_buf_size,
+                      "argument imports is NULL while module has imports");
+        // return NULL;
+    }
+#endif
+
     /* Check the heap size */
     heap_size = align_uint(heap_size, 8);
     if (heap_size > APP_HEAP_SIZE_MAX)
@@ -2502,6 +2612,10 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent,
 #endif
 
     /* Instantiate global firstly to get the mutable data size */
+    /*
+     * memory_instantiate() might change the value of __heap_base
+     * so, globals_instantiate() has to be called firstly
+     */
     global_count = module->import_global_count + module->global_count;
     if (global_count
         && !(globals = globals_instantiate(module, module_inst, error_buf,
@@ -2527,11 +2641,8 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent,
 
     /* export */
     module_inst->export_func_count = get_export_count(module, EXPORT_KIND_FUNC);
-#if WASM_ENABLE_MULTI_MEMORY != 0
     module_inst->export_memory_count =
         get_export_count(module, EXPORT_KIND_MEMORY);
-#endif
-#if WASM_ENABLE_MULTI_MODULE != 0
     module_inst->export_table_count =
         get_export_count(module, EXPORT_KIND_TABLE);
 #if WASM_ENABLE_TAGS != 0
@@ -2540,13 +2651,22 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent,
 #endif
     module_inst->export_global_count =
         get_export_count(module, EXPORT_KIND_GLOBAL);
-#endif
+
+    /* __heap_base */
+    uint8 *aux_heap_base_global_data = NULL;
+    if (module_inst->e->globals
+        && module->aux_heap_base_global_index < module->global_count) {
+        aux_heap_base_global_data =
+            module_inst->global_data
+            + module_inst->e->globals[module->aux_heap_base_global_index]
+                  .data_offset;
+    }
 
     /* Instantiate memories/tables/functions/tags */
     if ((module_inst->memory_count > 0
          && !(module_inst->memories = memories_instantiate(
                   module, module_inst, parent, heap_size, max_memory_pages,
-                  error_buf, error_buf_size)))
+                  aux_heap_base_global_data, error_buf, error_buf_size)))
         || (module_inst->table_count > 0
             && !(module_inst->tables =
                      tables_instantiate(module, module_inst, first_table,
@@ -2590,6 +2710,36 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent,
     ) {
         goto fail;
     }
+
+#if WASM_ENABLE_MULTI_MODULE == 0
+    /* imports */
+    /*
+     * const WASMExternInstance *imports should have the same order
+     * with import section content in .wasm.
+     */
+    {
+        uint32 import_memory_index = 0;
+        uint32 import_index = 0;
+        for (; import_index < import_count; import_index++) {
+            /* TODO: remove me if the entire instantiation linking feature is
+             * complete */
+            if (imports == NULL)
+                break;
+
+            const WASMExternInstance *import = imports + import_index;
+            if (import->kind == WASM_IMPORT_EXPORT_KIND_MEMORY) {
+                if (import_memory_index >= module->import_memory_count) {
+                    LOG_ERROR("provided import memory not match requirement");
+                    goto fail;
+                }
+
+                module_inst->memories[import_memory_index] = import->u.memory;
+                import_memory_index++;
+            }
+        }
+    }
+#endif
+
     if (global_count > 0) {
         /* Initialize the global data */
         global_data = module_inst->global_data;
@@ -3366,9 +3516,10 @@ wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst)
         (WASMModuleInstanceCommon *)module_inst);
 #endif
 
-    if (module_inst->memory_count > 0)
+    if (module_inst->memory_count > 0) {
         memories_deinstantiate(module_inst, module_inst->memories,
                                module_inst->memory_count);
+    }
 
     if (module_inst->import_func_ptrs) {
         wasm_runtime_free(module_inst->import_func_ptrs);
@@ -5032,3 +5183,82 @@ wasm_get_module_name(WASMModule *module)
 {
     return module->name;
 }
+
+#if WASM_ENABLE_LIB_WASI_THREADS != 0 || WASM_ENABLE_THREAD_MGR != 0
+/*
+ * The function is used to create a new WASMExternInstance list
+ * for a spawned thread.
+ */
+int32
+wasm_inherit_imports(WASMModule *module, WASMModuleInstance *inst,
+                     WASMExternInstance *out, int32 out_len)
+{
+    if (!module || !inst || !out)
+        return -1;
+
+    int32 spawned_import_count = module->import_count;
+    if (spawned_import_count > out_len) {
+        LOG_WARNING("The number of imported functions is more than the "
+                    "length of provided buffer ");
+        return -1;
+    }
+
+    for (int32 i = 0, import_memory_index = 0; i < spawned_import_count; i++) {
+        wasm_import_t import_type = { 0 };
+
+        wasm_runtime_get_import_type((WASMModuleCommon *)module, i,
+                                     &import_type);
+
+        out[i].module_name = import_type.module_name;
+        out[i].field_name = import_type.name;
+        out[i].kind = import_type.kind;
+
+        if (import_type.kind == WASM_IMPORT_EXPORT_KIND_MEMORY) {
+            out[i].u.memory = inst->memories[import_memory_index];
+#if WASM_ENABLE_SHARED_MEMORY != 0
+            shared_memory_inc_reference(inst->memories[import_memory_index]);
+#endif
+            import_memory_index++;
+        }
+        else {
+            LOG_WARNING("for spawned, inherit() import(%s,%s) kind %d",
+                        import_type.module_name, import_type.name,
+                        import_type.kind);
+        }
+    }
+
+    return 0;
+}
+
+void
+wasm_disinherit_imports(WASMModule *module, WASMExternInstance *imports,
+                        int32 import_count)
+{
+    if (!module || !imports)
+        return;
+
+    int32 spawned_import_count = module->import_count;
+    if (spawned_import_count > import_count) {
+        LOG_WARNING("The number of imported functions is more than the "
+                    "length of provided buffer ");
+        return;
+    }
+
+    for (int32 i = 0; i < import_count; i++) {
+        WASMExternInstance *import = imports + i;
+
+        if (import->kind == WASM_IMPORT_EXPORT_KIND_MEMORY) {
+            if (!import->u.memory)
+                continue;
+
+#if WASM_ENABLE_SHARED_MEMORY != 0
+            shared_memory_dec_reference(import->u.memory);
+#endif
+        }
+        else {
+            LOG_WARNING("for spawned, disinherit() import(%s,%s) kind %d",
+                        import->module_name, import->field_name, import->kind);
+        }
+    }
+}
+#endif /* WASM_ENABLE_LIB_WASI_THREADS != 0 || WASM_ENABLE_THREAD_MGR != 0 */

+ 19 - 3
core/iwasm/interpreter/wasm_runtime.h

@@ -546,8 +546,9 @@ wasm_resolve_import_func(const WASMModule *module,
 WASMModuleInstance *
 wasm_instantiate(WASMModule *module, WASMModuleInstance *parent,
                  WASMExecEnv *exec_env_main, uint32 stack_size,
-                 uint32 heap_size, uint32 max_memory_pages, char *error_buf,
-                 uint32 error_buf_size);
+                 uint32 heap_size, uint32 max_memory_pages,
+                 const WASMExternInstance *imports, uint32 import_count,
+                 char *error_buf, uint32 error_buf_size);
 
 void
 wasm_dump_perf_profiling(const WASMModuleInstance *module_inst);
@@ -566,6 +567,9 @@ bool
 wasm_set_running_mode(WASMModuleInstance *module_inst,
                       RunningMode running_mode);
 
+WASMMemoryInstance *
+wasm_create_memory(const WASMModule *module, const WASMMemoryType *type);
+
 WASMFunctionInstance *
 wasm_lookup_function(const WASMModuleInstance *module_inst, const char *name);
 
@@ -584,8 +588,10 @@ WASMTagInstance *
 wasm_lookup_tag(const WASMModuleInstance *module_inst, const char *name,
                 const char *signature);
 #endif
+#endif /* WASM_ENABLE_MULTI_MODULE != 0 */
 
-#endif
+void
+wasm_destroy_memory(WASMMemoryInstance *memory);
 
 bool
 wasm_call_function(WASMExecEnv *exec_env, WASMFunctionInstance *function,
@@ -889,6 +895,16 @@ wasm_set_module_name(WASMModule *module, const char *name, char *error_buf,
 const char *
 wasm_get_module_name(WASMModule *module);
 
+#if WASM_ENABLE_LIB_WASI_THREADS != 0 || WASM_ENABLE_THREAD_MGR != 0
+int32
+wasm_inherit_imports(WASMModule *module, WASMModuleInstance *inst,
+                     WASMExternInstance *out, int32 out_len);
+
+void
+wasm_disinherit_imports(WASMModule *module, WASMExternInstance *imports,
+                        int32 import_count);
+#endif /* WASM_ENABLE_LIB_WASI_THREADS != 0 || WASM_ENABLE_THREAD_MGR != 0 */
+
 #ifdef __cplusplus
 }
 #endif

+ 34 - 2
core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c

@@ -561,6 +561,8 @@ pthread_create_wrapper(wasm_exec_env_t exec_env,
     uint32 aux_stack_size;
     uint64 aux_stack_start = 0;
     int32 ret = -1;
+    int32 spawned_import_count = ((WASMModule *)module)->import_count;
+    WASMExternInstance *spawned_imports = NULL;
 
     bh_assert(module);
     bh_assert(module_inst);
@@ -579,9 +581,31 @@ pthread_create_wrapper(wasm_exec_env_t exec_env,
     }
 #endif
 
+    /*
+     * build a imports list(WASMExternInstance[]) from parent's imports
+     */
+    spawned_imports =
+        wasm_runtime_malloc(sizeof(WASMExternInstance) * spawned_import_count);
+    if (spawned_imports == NULL) {
+        LOG_ERROR("Failed to allocate memory for imports");
+        goto fail;
+    }
+
+    ret = wasm_runtime_inherit_imports(module, module_inst, spawned_imports,
+                                       spawned_import_count);
+    if (ret != 0) {
+        LOG_ERROR("Failed to inherit imports");
+        goto fail;
+    }
+
     if (!(new_module_inst = wasm_runtime_instantiate_internal(
-              module, module_inst, exec_env, stack_size, 0, 0, NULL, 0)))
-        return -1;
+              module, module_inst, exec_env, stack_size,
+              0,                    // heap_size
+              0,                    // max_memory_pages
+              spawned_imports,      // imports
+              spawned_import_count, // import_count
+              NULL, 0)))
+        goto fail;
 
     /* Set custom_data to new module instance */
     wasm_runtime_set_custom_data_internal(
@@ -641,9 +665,17 @@ pthread_create_wrapper(wasm_exec_env_t exec_env,
     if (thread)
         *thread = thread_handle;
 
+    wasm_runtime_disinherit_imports(module, spawned_imports,
+                                    spawned_import_count);
+    wasm_runtime_free(spawned_imports);
     return 0;
 
 fail:
+    if (spawned_imports) {
+        wasm_runtime_disinherit_imports(module, spawned_imports,
+                                        spawned_import_count);
+        wasm_runtime_free(spawned_imports);
+    }
     if (new_module_inst)
         wasm_runtime_deinstantiate_internal(new_module_inst, true);
     if (info_node)

+ 37 - 4
core/iwasm/libraries/lib-wasi-threads/lib_wasi_threads_wrapper.c

@@ -77,18 +77,45 @@ thread_spawn_wrapper(wasm_exec_env_t exec_env, uint32 start_arg)
     wasm_module_inst_t new_module_inst = NULL;
     ThreadStartArg *thread_start_arg = NULL;
     wasm_function_inst_t start_func;
-    int32 thread_id;
+    int32 thread_id = -1;
     uint32 stack_size = 8192;
     int32 ret = -1;
+    int32 spawned_import_count = ((WASMModule *)module)->import_count;
+    WASMExternInstance *spawned_imports = NULL;
 
     bh_assert(module);
     bh_assert(module_inst);
 
     stack_size = ((WASMModuleInstance *)module_inst)->default_wasm_stack_size;
 
-    if (!(new_module_inst = wasm_runtime_instantiate_internal(
-              module, module_inst, exec_env, stack_size, 0, 0, NULL, 0)))
+    /*
+     * build a imports list(WASMExternInstance[]) from parent's imports
+     */
+    spawned_imports =
+        wasm_runtime_malloc(sizeof(WASMExternInstance) * spawned_import_count);
+    if (spawned_imports == NULL) {
+        LOG_ERROR("Failed to allocate memory for imports");
         return -1;
+    }
+
+    ret = wasm_runtime_inherit_imports(module, module_inst, spawned_imports,
+                                       spawned_import_count);
+    if (ret != 0) {
+        LOG_ERROR("Failed to inherit imports");
+        goto free_imports;
+    }
+
+    new_module_inst = wasm_runtime_instantiate_internal(
+        module, module_inst, exec_env, stack_size,
+        0,                    // heap_size
+        0,                    // max_memory_pages
+        spawned_imports,      // imports
+        spawned_import_count, // import_count
+        NULL, 0);
+    if (new_module_inst == NULL) {
+        LOG_ERROR("Failed to instantiate new module");
+        goto free_imports;
+    }
 
     wasm_runtime_set_custom_data_internal(
         new_module_inst, wasm_runtime_get_custom_data(module_inst));
@@ -126,16 +153,22 @@ thread_spawn_wrapper(wasm_exec_env_t exec_env, uint32 start_arg)
         goto thread_spawn_fail;
     }
 
+    wasm_runtime_disinherit_imports(module, spawned_imports,
+                                    spawned_import_count);
+    wasm_runtime_free(spawned_imports);
     return thread_id;
 
 thread_spawn_fail:
     deallocate_thread_id(thread_id);
-
 thread_preparation_fail:
     if (new_module_inst)
         wasm_runtime_deinstantiate_internal(new_module_inst, true);
     if (thread_start_arg)
         wasm_runtime_free(thread_start_arg);
+free_imports:
+    wasm_runtime_disinherit_imports(module, spawned_imports,
+                                    spawned_import_count);
+    wasm_runtime_free(spawned_imports);
 
     return -1;
 }

+ 36 - 2
core/iwasm/libraries/thread-mgr/thread_manager.c

@@ -500,16 +500,42 @@ wasm_cluster_spawn_exec_env(WASMExecEnv *exec_env)
     uint32 aux_stack_size;
     uint64 aux_stack_start;
     uint32 stack_size = 8192;
+    int32 ret = -1;
+    int32 spawned_import_count = 0;
+    WASMExternInstance *spawned_imports = NULL;
 
     if (!module_inst || !(module = wasm_exec_env_get_module(exec_env))) {
         return NULL;
     }
 
-    if (!(new_module_inst = wasm_runtime_instantiate_internal(
-              module, module_inst, exec_env, stack_size, 0, 0, NULL, 0))) {
+    /*
+     * build a imports list(WASMExternInstance[]) from parent's imports
+     */
+    spawned_import_count = ((WASMModule *)module)->import_count;
+    spawned_imports =
+        wasm_runtime_malloc(sizeof(WASMExternInstance) * spawned_import_count);
+    if (spawned_imports == NULL) {
+        LOG_ERROR("Failed to allocate memory for imports");
         return NULL;
     }
 
+    ret = wasm_runtime_inherit_imports(module, module_inst, spawned_imports,
+                                       spawned_import_count);
+    if (ret != 0) {
+        LOG_ERROR("Failed to inherit imports");
+        goto release_imports;
+    }
+
+    if (!(new_module_inst = wasm_runtime_instantiate_internal(
+              module, module_inst, exec_env, stack_size,
+              0,                    // heap_size
+              0,                    // max_memory_pages
+              spawned_imports,      // imports
+              spawned_import_count, // import_count
+              NULL, 0))) {
+        goto disinherit_imports;
+    }
+
     /* Set custom_data to new module instance */
     wasm_runtime_set_custom_data_internal(
         new_module_inst, wasm_runtime_get_custom_data(module_inst));
@@ -570,6 +596,9 @@ wasm_cluster_spawn_exec_env(WASMExecEnv *exec_env)
 
     os_mutex_unlock(&cluster->lock);
 
+    wasm_runtime_disinherit_imports(module, spawned_imports,
+                                    spawned_import_count);
+    wasm_runtime_free(spawned_imports);
     return new_exec_env;
 
 fail3:
@@ -580,6 +609,11 @@ fail2:
     wasm_cluster_free_aux_stack(exec_env, aux_stack_start);
 fail1:
     wasm_runtime_deinstantiate_internal(new_module_inst, true);
+disinherit_imports:
+    wasm_runtime_disinherit_imports(module, spawned_imports,
+                                    spawned_import_count);
+release_imports:
+    wasm_runtime_free(spawned_imports);
 
     return NULL;
 }

+ 85 - 3
product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.cpp

@@ -377,17 +377,56 @@ handle_cmd_instantiate_module(uint64 *args, uint32 argc)
 
     bh_assert(argc == 5);
 
+    *(void **)args_org = NULL;
+
     if (!runtime_inited) {
-        *(void **)args_org = NULL;
         return;
     }
 
+#if WASM_ENABLE_MULTI_MODULE == 0
+    {
+        int32_t import_count =
+            wasm_runtime_get_import_count(enclave_module->module);
+        WASMExternInstance *imports = NULL;
+
+#if WASM_ENABLE_SPEC_TEST != 0 || WASM_ENABLE_WASI_TEST != 0 \
+    || WASM_ENABLE_LIBC_BUILTIN != 0 || WASM_ENABLE_LIBC_WASI != 0
+        imports =
+            wasm_runtime_create_imports_with_builtin(enclave_module->module);
+#endif
+        if (import_count > 0 && imports == NULL) {
+            LOG_WARNING("Need to provide necessary imported objects");
+            return;
+        }
+
+        InstantiationArgs inst_args = {
+            .default_stack_size = stack_size,
+            .host_managed_heap_size = heap_size,
+            .max_memory_pages = 0,
+            .imports = imports,
+            .import_count = (uint32_t)import_count,
+        };
+
+        module_inst = wasm_runtime_instantiate_ex(
+            enclave_module->module, &inst_args, error_buf, error_buf_size);
+        if (!module_inst) {
+            wasm_runtime_destroy_imports(enclave_module->module, imports);
+            return;
+        }
+
+        /*
+         * FIXME: how to relese imports.
+         * if there will be spawned thread, need to release when the thread is
+         * done.
+         */
+    }
+#else  /* WASM_ENABLE_MULTI_MODULE == 0 */
     if (!(module_inst =
               wasm_runtime_instantiate(enclave_module->module, stack_size,
                                        heap_size, error_buf, error_buf_size))) {
-        *(void **)args_org = NULL;
         return;
     }
+#endif /* WASM_ENABLE_MULTI_MODULE == 0 */
 
     *(wasm_module_inst_t *)args_org = module_inst;
 
@@ -763,6 +802,11 @@ ecall_iwasm_main(uint8_t *wasm_file_buf, uint32_t wasm_file_size)
     RuntimeInitArgs init_args;
     char error_buf[128];
     const char *exception;
+    uint32 stack_size = 16 * 1024;
+    uint32 heap_size = 16 * 1024;
+#if WASM_ENABLE_MULTI_MODULE == 0
+    WASMExternInstance *imports = NULL;
+#endif
 
     /* avoid duplicated init */
     if (runtime_inited) {
@@ -797,13 +841,45 @@ ecall_iwasm_main(uint8_t *wasm_file_buf, uint32_t wasm_file_size)
     }
 
     /* instantiate the module */
+#if WASM_ENABLE_MULTI_MODULE == 0
+    {
+        int32_t import_count = wasm_runtime_get_import_count(wasm_module);
+
+#if WASM_ENABLE_SPEC_TEST != 0 || WASM_ENABLE_WASI_TEST != 0 \
+    || WASM_ENABLE_LIBC_BUILTIN != 0 || WASM_ENABLE_LIBC_WASI != 0
+        imports = wasm_runtime_create_imports_with_builtin(wasm_module);
+#endif
+        if (import_count > 0 && imports == NULL) {
+            enclave_print("Need to provide necessary imported objects");
+            enclave_print("\n");
+            goto fail2;
+        }
+
+        InstantiationArgs inst_args = {
+            .default_stack_size = stack_size,
+            .host_managed_heap_size = heap_size,
+            .max_memory_pages = 0,
+            .imports = imports,
+            .import_count = (uint32_t)import_count,
+        };
+
+        wasm_module_inst = wasm_runtime_instantiate_ex(
+            wasm_module, &inst_args, error_buf, sizeof(error_buf));
+        if (!wasm_module_inst) {
+            enclave_print(error_buf);
+            enclave_print("\n");
+            goto fail3;
+        }
+    }
+#else  /* WASM_ENABLE_MULTI_MODULE == 0 */
     if (!(wasm_module_inst =
-              wasm_runtime_instantiate(wasm_module, 16 * 1024, 16 * 1024,
+              wasm_runtime_instantiate(wasm_module, stack_size, heap_size,
                                        error_buf, sizeof(error_buf)))) {
         enclave_print(error_buf);
         enclave_print("\n");
         goto fail2;
     }
+#endif /* WASM_ENABLE_MULTI_MODULE == 0 */
 
     /* execute the main function of wasm app */
     wasm_application_execute_main(wasm_module_inst, 0, NULL);
@@ -815,6 +891,12 @@ ecall_iwasm_main(uint8_t *wasm_file_buf, uint32_t wasm_file_size)
     /* destroy the module instance */
     wasm_runtime_deinstantiate(wasm_module_inst);
 
+#if WASM_ENABLE_MULTI_MODULE == 0
+fail3:
+    /* destory imports */
+    wasm_runtime_destroy_imports(wasm_module, imports);
+#endif /* WASM_ENABLE_MULTI_MODULE == 0*/
+
 fail2:
     /* unload the module */
     wasm_runtime_unload(wasm_module);

+ 44 - 8
product-mini/platforms/posix/main.c

@@ -885,7 +885,7 @@ main(int argc, char *argv[])
     /* load WASM byte buffer from WASM bin file */
     if (!(wasm_file_buf =
               (uint8 *)bh_read_file_to_buffer(wasm_file, &wasm_file_size)))
-        goto fail1;
+        goto unregister_native;
 
 #if WASM_ENABLE_AOT != 0
     if (wasm_runtime_is_xip_file(wasm_file_buf, wasm_file_size)) {
@@ -898,7 +898,7 @@ main(int argc, char *argv[])
                                          map_flags, os_get_invalid_handle()))) {
             printf("mmap memory failed\n");
             wasm_runtime_free(wasm_file_buf);
-            goto fail1;
+            goto unregister_native;
         }
 
 #if (WASM_MEM_DUAL_BUS_MIRROR != 0)
@@ -925,7 +925,7 @@ main(int argc, char *argv[])
     if (!(wasm_module = wasm_runtime_load(wasm_file_buf, wasm_file_size,
                                           error_buf, sizeof(error_buf)))) {
         printf("%s\n", error_buf);
-        goto fail2;
+        goto unmap_file;
     }
 
 #if WASM_ENABLE_DYNAMIC_AOT_DEBUG != 0
@@ -933,7 +933,7 @@ main(int argc, char *argv[])
                                       sizeof(error_buf))) {
         printf("set aot module name failed in dynamic aot debug mode, %s\n",
                error_buf);
-        goto fail3;
+        goto unload_module;
     }
 #endif
 
@@ -942,12 +942,42 @@ main(int argc, char *argv[])
 #endif
 
     /* instantiate the module */
+#if WASM_ENABLE_MULTI_MODULE == 0
+    int32_t import_count = wasm_runtime_get_import_count(wasm_module);
+    WASMExternInstance *imports = NULL;
+
+#if WASM_ENABLE_SPEC_TEST != 0 || WASM_ENABLE_WASI_TEST != 0 \
+    || WASM_ENABLE_LIBC_BUILTIN != 0 || WASM_ENABLE_LIBC_WASI != 0
+    imports = wasm_runtime_create_imports_with_builtin(wasm_module);
+#endif
+
+    if (import_count > 0 && imports == NULL) {
+        printf("Need to provide %" PRId32 " imported objects:\n", import_count);
+        goto unload_module;
+    }
+
+    InstantiationArgs inst_args = {
+        .default_stack_size = stack_size,
+        .host_managed_heap_size = heap_size,
+        .max_memory_pages = 0,
+        .imports = imports,
+        .import_count = import_count,
+    };
+
+    wasm_module_inst = wasm_runtime_instantiate_ex(
+        wasm_module, &inst_args, error_buf, sizeof(error_buf));
+    if (!wasm_module_inst) {
+        printf("%s\n", error_buf);
+        goto destroy_imports;
+    }
+#else
     if (!(wasm_module_inst =
               wasm_runtime_instantiate(wasm_module, stack_size, heap_size,
                                        error_buf, sizeof(error_buf)))) {
         printf("%s\n", error_buf);
-        goto fail3;
+        goto unload_module;
     }
+#endif /* WASM_ENABLE_MULTI_MODULE == 0 */
 
 #if WASM_CONFIGURABLE_BOUNDS_CHECKS != 0
     if (disable_bounds_checks) {
@@ -1037,21 +1067,27 @@ fail5:
 #if WASM_ENABLE_DEBUG_INTERP != 0
 fail4:
 #endif
+
     /* destroy the module instance */
     wasm_runtime_deinstantiate(wasm_module_inst);
 
-fail3:
+#if WASM_ENABLE_MULTI_MODULE == 0
+destroy_imports:
+    wasm_runtime_destroy_imports(wasm_module, imports);
+#endif
+
+unload_module:
     /* unload the module */
     wasm_runtime_unload(wasm_module);
 
-fail2:
+unmap_file:
     /* free the file buffer */
     if (!is_xip_file)
         wasm_runtime_free(wasm_file_buf);
     else
         os_munmap(wasm_file_buf, wasm_file_size);
 
-fail1:
+unregister_native:
 #if BH_HAS_DLFCN
     /* unload the native libraries */
     unregister_and_unload_native_libs(native_lib_loaded_count,

+ 37 - 3
product-mini/platforms/windows/main.c

@@ -540,12 +540,41 @@ main(int argc, char *argv[])
 #endif
 
     /* instantiate the module */
+#if WASM_ENABLE_MULTI_MODULE == 0
+    int32_t import_count = wasm_runtime_get_import_count(wasm_module);
+    WASMExternInstance *imports = NULL;
+
+#if WASM_ENABLE_SPEC_TEST != 0 || WASM_ENABLE_WASI_TEST != 0 \
+    || WASM_ENABLE_LIBC_BUILTIN != 0 || WASM_ENABLE_LIBC_WASI != 0
+    imports = wasm_runtime_create_imports_with_builtin(wasm_module);
+#endif
+    if (import_count > 0 && imports == NULL) {
+        printf("Need to provide %d imported objects:\n", import_count);
+        goto fail3;
+    }
+
+    InstantiationArgs inst_args = {
+        .default_stack_size = stack_size,
+        .host_managed_heap_size = heap_size,
+        .max_memory_pages = 0,
+        .imports = imports,
+        .import_count = import_count,
+    };
+
+    wasm_module_inst = wasm_runtime_instantiate_ex(
+        wasm_module, &inst_args, error_buf, sizeof(error_buf));
+    if (!wasm_module_inst) {
+        printf("%s\n", error_buf);
+        goto fail4;
+    }
+#else
     if (!(wasm_module_inst =
               wasm_runtime_instantiate(wasm_module, stack_size, heap_size,
                                        error_buf, sizeof(error_buf)))) {
         printf("%s\n", error_buf);
         goto fail3;
     }
+#endif /* WASM_ENABLE_MULTI_MODULE == 0 */
 
 #if WASM_ENABLE_DEBUG_INTERP != 0
     if (ip_addr != NULL) {
@@ -554,12 +583,12 @@ main(int argc, char *argv[])
         uint32_t debug_port;
         if (exec_env == NULL) {
             printf("%s\n", wasm_runtime_get_exception(wasm_module_inst));
-            goto fail4;
+            goto fail5;
         }
         debug_port = wasm_runtime_start_debug_instance(exec_env);
         if (debug_port == 0) {
             printf("Failed to start debug instance\n");
-            goto fail4;
+            goto fail5;
         }
     }
 #endif
@@ -595,11 +624,16 @@ main(int argc, char *argv[])
         printf("%s\n", exception);
 
 #if WASM_ENABLE_DEBUG_INTERP != 0
-fail4:
+fail5:
 #endif
     /* destroy the module instance */
     wasm_runtime_deinstantiate(wasm_module_inst);
 
+#if WASM_ENABLE_MULTI_MODULE == 0
+fail4:
+    wasm_runtime_destroy_imports(wasm_module, imports);
+#endif
+
 fail3:
     /* unload the module */
     wasm_runtime_unload(wasm_module);

+ 38 - 1
samples/file/src/main.c

@@ -18,7 +18,7 @@ int
 main(int argc, char *argv_main[])
 {
     static char global_heap_buf[512 * 1024];
-    char *buffer, error_buf[128];
+    char *buffer, error_buf[128] = { 0 };
     const char *wasm_path = NULL, *wasi_dir = NULL;
     int opt, main_result = 1;
 
@@ -27,6 +27,10 @@ main(int argc, char *argv_main[])
     wasm_exec_env_t exec_env = NULL;
     uint32 buf_size, stack_size = 8092, heap_size = 8092;
 
+#if WASM_ENABLE_MULTI_MODULE == 0
+    WASMExternInstance *imports = NULL;
+#endif
+
     RuntimeInitArgs init_args;
     memset(&init_args, 0, sizeof(RuntimeInitArgs));
 
@@ -76,8 +80,37 @@ main(int argc, char *argv_main[])
     wasm_runtime_set_wasi_args_ex(module, &wasi_dir, 1, NULL, 0, NULL, 0, NULL,
                                   0, 0, 1, 2);
 
+#if WASM_ENABLE_MULTI_MODULE == 0
+    int32_t import_count = wasm_runtime_get_import_count(module);
+
+#if WASM_ENABLE_SPEC_TEST != 0 || WASM_ENABLE_WASI_TEST != 0 \
+    || WASM_ENABLE_LIBC_BUILTIN != 0 || WASM_ENABLE_LIBC_WASI != 0
+    imports = wasm_runtime_create_imports_with_builtin(module);
+#endif
+
+    if (import_count > 0 && imports == NULL) {
+        printf("Need to provide %" PRId32 " imported objects:\n", import_count);
+        goto fail;
+    }
+
+    InstantiationArgs inst_args = {
+        .default_stack_size = stack_size,
+        .host_managed_heap_size = heap_size,
+        .max_memory_pages = 0,
+        .imports = imports,
+        .import_count = import_count,
+    };
+
+    module_inst = wasm_runtime_instantiate_ex(module, &inst_args, error_buf,
+                                              sizeof(error_buf));
+    if (!module_inst) {
+        printf("%s\n", error_buf);
+        goto fail;
+    }
+#else
     module_inst = wasm_runtime_instantiate(module, stack_size, heap_size,
                                            error_buf, sizeof(error_buf));
+#endif
 
     if (!module_inst) {
         printf("Instantiate wasm module failed. error: %s\n", error_buf);
@@ -104,6 +137,10 @@ fail:
         wasm_runtime_destroy_exec_env(exec_env);
     if (module_inst)
         wasm_runtime_deinstantiate(module_inst);
+#if WASM_ENABLE_MULTI_MODULE == 0
+    if (imports)
+        wasm_runtime_destroy_imports(module, imports);
+#endif
     if (module)
         wasm_runtime_unload(module);
     if (buffer)

+ 51 - 0
samples/linking/CMakeLists.txt

@@ -0,0 +1,51 @@
+# Copyright (C) 2019 Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+cmake_minimum_required(VERSION 3.14)
+project(linking_samples)
+
+set(CMAKE_BUILD_TYPE Debug)
+
+list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
+find_package(WASISDK REQUIRED)
+
+################  runtime settings  ################
+string (TOLOWER ${CMAKE_HOST_SYSTEM_NAME} WAMR_BUILD_PLATFORM)
+include(CheckPIESupported)
+
+# AOT and JIT byd default
+set(WAMR_BUILD_AOT 0)
+set(WAMR_BUILD_INTERP 1)
+set(WAMR_BUILD_JIT 0)
+# wasm32-wasi
+set(WAMR_BUILD_LIBC_BUILTIN 0)
+set(WAMR_BUILD_LIBC_WASI 1)
+# mvp
+set(WAMR_BUILD_BULK_MEMORY 1)
+set(WAMR_BUILD_REF_TYPES 1)
+set(WAMR_BUILD_SIMD 1)
+set(WAMR_BUILD_TAIL_CALL 1)
+set(WAMR_BUILD_THREAD_MGR 0)
+set(WAMR_BUILD_LIB_WASI_THREADS 0)
+
+# vmlib
+set(WAMR_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../..)
+include(${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake)
+add_library(vmlib SHARED ${WAMR_RUNTIME_LIB_SOURCE})
+target_include_directories(vmlib INTERFACE ${WAMR_ROOT_DIR}/core/iwasm/include)
+target_link_libraries (vmlib ${LLVM_AVAILABLE_LIBS} -lm -ldl)
+
+################  samples  ################
+add_subdirectory(raw)
+
+################ wasm and/or aot ################
+include(ExternalProject)
+ExternalProject_Add(wasm
+  SOURCE_DIR        "${CMAKE_CURRENT_SOURCE_DIR}/wasm"
+  CONFIGURE_COMMAND ${CMAKE_COMMAND} -S ${CMAKE_CURRENT_SOURCE_DIR}/wasm -B build
+                      -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
+                      -DCMAKE_TOOLCHAIN_FILE=${WASISDK_TOOLCHAIN}
+  BUILD_COMMAND     ${CMAKE_COMMAND} --build build
+  INSTALL_COMMAND   ${CMAKE_COMMAND} --install build --prefix ${CMAKE_CURRENT_BINARY_DIR}
+  EXCLUDE_FROM_ALL  NO
+)

+ 23 - 0
samples/linking/cmake/FindWASISDK.cmake

@@ -0,0 +1,23 @@
+# Copyright (C) 2019 Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+include(FindPackageHandleStandardArgs)
+
+file(GLOB WASISDK_SEARCH_PATH "/opt/wasi-sdk-*")
+find_path(WASISDK_HOME
+  NAMES share/wasi-sysroot
+  PATHS ${WASISDK_SEARCH_PATH}
+  NO_DEFAULT_PATH
+  REQUIRED
+)
+
+string(REGEX MATCH [0-9]+\.[0-9]+\.*[0-9]* WASISDK_VERSION ${WASISDK_HOME})
+
+find_package_handle_standard_args(WASISDK REQUIRED_VARS WASISDK_HOME VERSION_VAR WASISDK_VERSION)
+
+if(WASISDK_FOUND)
+  set(WASISDK_CC_COMMAND  ${WASISDK_HOME}/bin/clang)
+  set(WASISDK_CXX_COMMAND ${WASISDK_HOME}/bin/clang++)
+  set(WASISDK_TOOLCHAIN   ${WASISDK_HOME}/share/cmake/wasi-sdk.cmake)
+  set(WASISDK_SYSROOT     ${WASISDK_HOME}/share/wasi-sysroot)
+endif()

+ 21 - 0
samples/linking/lib/CMakeLists.txt

@@ -0,0 +1,21 @@
+# Copyright (C) 2019 Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+# compilation options
+set(WAMR_BUILD_INTERP 1)
+set(WAMR_BUILD_AOT 1)
+set(WAMR_BUILD_LIBC_BUILTIN 0)
+set(WAMR_BUILD_LIBC_WASI 1)
+
+string(TOLOWER ${CMAKE_HOST_SYSTEM_NAME} WAMR_BUILD_PLATFORM)
+set(WAMR_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../../..)
+include(${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake)
+add_library(vmlib ${WAMR_RUNTIME_LIB_SOURCE})
+
+# # workaround for missing headers
+include(${WAMR_ROOT_DIR}/core/shared/utils/uncommon/shared_uncommon.cmake)
+
+get_property(WAMR_INCLUDE_PATHS_OUT DIRECTORY PROPERTY INCLUDE_DIRECTORIES)
+include(CMakePrintHelpers)
+set(WAMR_INCLUDE_PATHS ${WAMR_INCLUDE_PATHS_OUT} PARENT_SCOPE)
+cmake_print_variables(WAMR_INCLUDE_PATHS_OUT)

+ 6 - 0
samples/linking/raw/CMakeLists.txt

@@ -0,0 +1,6 @@
+# Copyright (C) 2019 Intel Corporation.  All rights reserved.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+include (${SHARED_DIR}/utils/uncommon/shared_uncommon.cmake)
+add_executable(raw main.c ${UNCOMMON_SHARED_SOURCE})
+target_link_libraries(raw PRIVATE vmlib)

+ 119 - 0
samples/linking/raw/main.c

@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2019 Intel Corporation.  All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+#include "wasm_export.h"
+#include "bh_read_file.h"
+
+int
+main(int argc, char *argv_main[])
+{
+    int exit_code = EXIT_FAILURE;
+
+    /* runtime */
+    if (!wasm_runtime_init()) {
+        printf("Init runtime failed.\n");
+        return EXIT_FAILURE;
+    }
+
+    wasm_runtime_set_log_level(WASM_LOG_LEVEL_VERBOSE);
+
+    /* wasm module file */
+    char *buffer;
+    uint32 buf_size;
+    buffer = bh_read_file_to_buffer("import_memory.wasm", &buf_size);
+    if (!buffer) {
+        printf("Open wasm file failed.\n");
+        goto destroy_runtime;
+    }
+
+    /* wasm module */
+    char error_buf[128];
+    wasm_module_t module = wasm_runtime_load((uint8 *)buffer, buf_size,
+                                             error_buf, sizeof(error_buf));
+    if (!module) {
+        printf("Load wasm file failed: %s\n", error_buf);
+        goto release_file_buffer;
+    }
+
+    /* import type */
+    int32_t import_count = wasm_runtime_get_import_count(module);
+    wasm_import_t import_type = { 0 };
+    int32_t import_memory_index = -1;
+    for (int i = 0; i < import_count; i++) {
+        wasm_runtime_get_import_type(module, i, &import_type);
+        if (import_type.kind == WASM_IMPORT_EXPORT_KIND_MEMORY) {
+            import_memory_index = i;
+            break;
+        }
+    }
+
+    if (import_memory_index == -1) {
+        printf("No memory import found.\n");
+        goto unload_module;
+    }
+
+    /* host memory */
+    wasm_memory_type_t memory_type = import_type.u.memory_type;
+    wasm_memory_inst_t memory = wasm_runtime_create_memory(module, memory_type);
+    if (!memory) {
+        printf("Create memory failed.\n");
+        goto unload_module;
+    }
+
+    /* import list */
+    WASMExternInstance import_list[10] = { 0 };
+    import_list[import_memory_index].module_name = "env";
+    import_list[import_memory_index].field_name = "memory";
+    import_list[import_memory_index].kind = WASM_IMPORT_EXPORT_KIND_MEMORY;
+    import_list[import_memory_index].u.memory = memory;
+
+    /* wasm instance */
+    InstantiationArgs inst_args = {
+        .imports = import_list,
+        .import_count = 10,
+    };
+    wasm_module_inst_t inst = wasm_runtime_instantiate_ex(
+        module, &inst_args, error_buf, sizeof(error_buf));
+    if (!inst) {
+        printf("Instantiate wasm file failed: %s\n", error_buf);
+        goto destroy_memory;
+    }
+
+    /* export function */
+    wasm_function_inst_t func =
+        wasm_runtime_lookup_function(inst, "goodhart_law");
+    if (!func) {
+        printf("The function goodhart_law is not found.\n");
+        goto destroy_inst;
+    }
+
+    wasm_exec_env_t exec_env = wasm_runtime_create_exec_env(inst, 8192);
+    if (!exec_env) {
+        printf("Create wasm execution environment failed.\n");
+        goto destroy_inst;
+    }
+
+    if (!wasm_runtime_call_wasm(exec_env, func, 0, NULL)) {
+        printf("call wasm function goodhart_law failed. %s\n",
+               wasm_runtime_get_exception(inst));
+        goto destroy_exec_env;
+    }
+
+    exit_code = EXIT_SUCCESS;
+
+destroy_exec_env:
+    wasm_runtime_destroy_exec_env(exec_env);
+destroy_inst:
+    wasm_runtime_deinstantiate(inst);
+destroy_memory:
+    wasm_runtime_destroy_memory(module, memory);
+unload_module:
+    wasm_runtime_unload(module);
+release_file_buffer:
+    wasm_runtime_free(buffer);
+destroy_runtime:
+    wasm_runtime_destroy();
+
+    return exit_code;
+}

+ 18 - 0
samples/linking/wasm/CMakeLists.txt

@@ -0,0 +1,18 @@
+# Copyright (C) 2019 Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+cmake_minimum_required (VERSION 3.14)
+
+project(linking_samples_wasm)
+
+add_executable(import_memory import_memory.c)
+target_link_options(import_memory
+  PRIVATE
+    LINKER:--import-memory
+    # (memory 3 5) for test
+    LINKER:--initial-memory=196608
+    LINKER:--max-memory=327680
+    LINKER:--initial-heap=65536
+)
+set_target_properties(import_memory PROPERTIES SUFFIX .wasm)
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/import_memory.wasm DESTINATION .)

+ 83 - 0
samples/linking/wasm/import_memory.c

@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2019 Intel Corporation.  All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+#include <assert.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct Buffer {
+    int size;
+    char *data;
+};
+
+struct Buffer *
+new_buffer(int size)
+{
+    struct Buffer *buffer = calloc(1, sizeof(struct Buffer));
+    if (!buffer) {
+        return NULL;
+    }
+
+    buffer->size = size;
+    buffer->data = calloc(1, size);
+    if (!buffer->data) {
+        free(buffer);
+        return NULL;
+    }
+
+    return buffer;
+}
+
+void
+release_buffer(struct Buffer *buffer)
+{
+    buffer->size = 0;
+    free(buffer->data);
+    free(buffer);
+}
+
+__attribute__((export_name("goodhart_law"))) void
+goodhart_law()
+{
+    struct Buffer *buffer = new_buffer(64);
+    assert(buffer);
+
+    snprintf(buffer->data, 60, "%s",
+             "When a measure becomes a target, it ceases to be a good measure");
+    assert(buffer->data[10] == 's');
+
+    release_buffer(buffer);
+
+    printf("-> pass basic\n");
+    fflush(stdout);
+
+    // alloc a huge buffer
+    struct Buffer *huge_buffer = new_buffer(60000);
+    assert(huge_buffer->data != NULL);
+
+    memset(huge_buffer->data, 0xEE, 60000);
+    assert((uint8_t)(huge_buffer->data[50000]) == 0xEE);
+
+    release_buffer(huge_buffer);
+
+    printf("-> pass huge allocations\n");
+    fflush(stdout);
+
+    int ret = __builtin_wasm_memory_grow(0, 1);
+    // sync with the value assigned by `--initial-memory`
+    assert(ret == 3);
+
+    printf("-> pass manually memory.grow\n");
+    fflush(stdout);
+}
+
+int
+main()
+{
+    goodhart_law();
+    return EXIT_SUCCESS;
+}

+ 30 - 8
tests/wamr-test-suites/spec-test-script/all.py

@@ -28,11 +28,13 @@ To run a single GC case case:
     --aot-compiler wamrc --gc spec/test/core/xxx.wast
 """
 
+
 def exe_file_path(base_path: str) -> str:
     if platform.system().lower() == "windows":
         base_path += ".exe"
     return base_path
 
+
 def get_iwasm_cmd(platform: str) -> str:
     build_path = "../../../product-mini/platforms/" + platform + "/build/"
     exe_name = "iwasm"
@@ -42,6 +44,7 @@ def get_iwasm_cmd(platform: str) -> str:
 
     return exe_file_path(build_path + exe_name)
 
+
 PLATFORM_NAME = platform.uname().system.lower()
 IWASM_CMD = get_iwasm_cmd(PLATFORM_NAME)
 IWASM_SGX_CMD = "../../../product-mini/platforms/linux-sgx/enclave-sample/iwasm"
@@ -69,6 +72,7 @@ AVAILABLE_TARGETS = [
     "XTENSA",
 ]
 
+
 def ignore_the_case(
     case_name,
     target,
@@ -84,11 +88,23 @@ def ignore_the_case(
     eh_flag=False,
     qemu_flag=False,
 ):
-
     if case_name in ["comments", "inline-module", "names"]:
         return True
 
-    if not multi_module_flag and case_name in ["imports", "linking", "simd_linking"]:
+    if not multi_module_flag and case_name in [
+        "imports",
+        "linking",
+        "simd_linking",
+        # from multi-memory
+        "imports0",
+        "imports1",
+        "imports2",
+        "imports4",
+        "linking0",
+        "linking1",
+        "linking2",
+        "linking3",
+    ]:
         return True
 
     # Note: x87 doesn't preserve sNaN and makes some relevant tests fail.
@@ -96,7 +112,7 @@ def ignore_the_case(
         return True
 
     # esp32s3 qemu doesn't have PSRAM emulation
-    if qemu_flag and target == 'xtensa' and case_name in ["memory_size"]:
+    if qemu_flag and target == "xtensa" and case_name in ["memory_size"]:
         return True
 
     if gc_flag:
@@ -170,7 +186,7 @@ def test_case(
     qemu_flag=False,
     qemu_firmware="",
     log="",
-    no_pty=False
+    no_pty=False,
 ):
     CMD = [sys.executable, "runtest.py"]
     CMD.append("--wast2wasm")
@@ -238,6 +254,7 @@ def test_case(
     CMD.append(str(case_path))
     # print(f"============> use {' '.join(CMD)}")
     print(f"============> run {case_name} ", end="")
+
     with subprocess.Popen(
         CMD,
         bufsize=1,
@@ -319,7 +336,11 @@ def test_suite(
 
     if eh_flag:
         eh_case_list = sorted(suite_path.glob("*.wast"))
-        eh_case_list_include = [test for test in eh_case_list if test.stem in ["throw", "tag", "try_catch", "rethrow", "try_delegate"]]
+        eh_case_list_include = [
+            test
+            for test in eh_case_list
+            if test.stem in ["throw", "tag", "try_catch", "rethrow", "try_delegate"]
+        ]
         case_list.extend(eh_case_list_include)
 
     if multi_memory_flag:
@@ -573,8 +594,9 @@ def main():
         nargs="*",
         help=f"Specify all wanted cases. If not the script will go through all cases under {SPEC_TEST_DIR}",
     )
-    parser.add_argument('--no-pty', action='store_true',
-        help="Use direct pipes instead of pseudo-tty")
+    parser.add_argument(
+        "--no-pty", action="store_true", help="Use direct pipes instead of pseudo-tty"
+    )
 
     options = parser.parse_args()
 
@@ -616,7 +638,7 @@ def main():
             options.qemu_flag,
             options.qemu_firmware,
             options.log,
-            options.no_pty
+            options.no_pty,
         )
         end = time.time_ns()
         print(