Browse Source

Improve wasm-c-api instantiation-time linking (#1902)

Add APIs to help prepare the imports for the wasm-c-api `wasm_instance_new`:
- wasm_importtype_is_linked
- wasm_runtime_is_import_func_linked
- wasm_runtime_is_import_global_linked
- wasm_extern_new_empty

For wasm-c-api, developer may use `wasm_module_imports` to get the import
types info, check whether an import func/global is linked with the above API,
and ignore the linking of an import func/global with `wasm_extern_new_empty`.

Sample `wasm-c-api-import` is added and document is updated.
liang.he 3 years ago
parent
commit
3698f2279b

+ 212 - 203
core/iwasm/common/wasm_c_api.c

@@ -398,7 +398,7 @@ wasm_engine_new_internal(mem_alloc_type_t type, const MemAllocOption *opts)
 }
 
 /* global engine instance */
-static wasm_engine_t *singleton_engine = NULL;
+static wasm_engine_t *singleton_engine;
 #ifdef os_thread_local_attribute
 /* categorize wasm_store_t as threads*/
 static os_thread_local_attribute unsigned thread_local_stores_num = 0;
@@ -1458,6 +1458,30 @@ wasm_importtype_type(const wasm_importtype_t *import_type)
     return import_type->extern_type;
 }
 
+bool
+wasm_importtype_is_linked(const wasm_importtype_t *import_type)
+{
+    if (!import_type)
+        return false;
+
+    const wasm_name_t *module_name = wasm_importtype_module(import_type);
+    const wasm_name_t *field_name = wasm_importtype_name(import_type);
+
+    switch (wasm_externtype_kind(wasm_importtype_type(import_type))) {
+        case WASM_EXTERN_FUNC:
+            return wasm_runtime_is_import_func_linked(module_name->data,
+                                                      field_name->data);
+        case WASM_EXTERN_GLOBAL:
+            return wasm_runtime_is_import_global_linked(module_name->data,
+                                                        field_name->data);
+        case WASM_EXTERN_MEMORY:
+        case WASM_EXTERN_TABLE:
+        default:
+            break;
+    }
+    return false;
+}
+
 own wasm_exporttype_t *
 wasm_exporttype_new(own wasm_byte_vec_t *name,
                     own wasm_externtype_t *extern_type)
@@ -2537,12 +2561,12 @@ wasm_module_imports(const wasm_module_t *module, own wasm_importtype_vec_t *out)
 
         bh_assert(extern_type);
 
-        wasm_name_new_from_string(&module_name, module_name_rt);
+        wasm_name_new_from_string_nt(&module_name, module_name_rt);
         if (strlen(module_name_rt) && !module_name.data) {
             goto failed;
         }
 
-        wasm_name_new_from_string(&name, field_name_rt);
+        wasm_name_new_from_string_nt(&name, field_name_rt);
         if (strlen(field_name_rt) && !name.data) {
             goto failed;
         }
@@ -2622,7 +2646,7 @@ wasm_module_exports(const wasm_module_t *module, wasm_exporttype_vec_t *out)
         }
 
         /* byte* -> wasm_byte_vec_t */
-        wasm_name_new_from_string(&name, export->name);
+        wasm_name_new_from_string_nt(&name, export->name);
         if (strlen(export->name) && !name.data) {
             goto failed;
         }
@@ -3008,6 +3032,20 @@ failed:
     return NULL;
 }
 
+static wasm_func_t *
+wasm_func_new_empty(wasm_store_t *store)
+{
+    wasm_func_t *func = NULL;
+
+    if (!(func = malloc_internal(sizeof(wasm_func_t))))
+        goto failed;
+
+    func->store = store;
+    func->kind = WASM_EXTERN_FUNC;
+
+    RETURN_OBJ(func, wasm_func_delete)
+}
+
 void
 wasm_func_delete(wasm_func_t *func)
 {
@@ -3211,7 +3249,8 @@ wasm_func_call(const wasm_func_t *func, const wasm_val_vec_t *params,
         wasm_name_t message = { 0 };
         wasm_trap_t *trap;
 
-        wasm_name_new_from_string(&message, "failed to call unlinked function");
+        wasm_name_new_from_string_nt(&message,
+                                     "failed to call unlinked function");
         trap = wasm_trap_new(func->store, &message);
         wasm_byte_vec_delete(&message);
 
@@ -3371,6 +3410,25 @@ failed:
     return NULL;
 }
 
+static wasm_global_t *
+wasm_global_new_empty(wasm_store_t *store)
+{
+    wasm_global_t *global = NULL;
+
+    global = malloc_internal(sizeof(wasm_global_t));
+    if (!global)
+        goto failed;
+
+    global->store = store;
+    global->kind = WASM_EXTERN_GLOBAL;
+
+    return global;
+failed:
+    LOG_DEBUG("%s failed", __FUNCTION__);
+    wasm_global_delete(global);
+    return NULL;
+}
+
 /* almost same with wasm_global_new */
 wasm_global_t *
 wasm_global_copy(const wasm_global_t *src)
@@ -4288,6 +4346,11 @@ interp_link_func(const wasm_instance_t *inst, const WASMModule *module_interp,
 
     imported_func_interp = module_interp->import_functions + func_idx_rt;
     bh_assert(imported_func_interp);
+    bh_assert(imported_func_interp->kind == IMPORT_KIND_FUNC);
+
+    /* it is a placeholder and let's skip it*/
+    if (!import->type)
+        return true;
 
     /* type comparison */
     if (!wasm_functype_same_internal(
@@ -4302,6 +4365,8 @@ interp_link_func(const wasm_instance_t *inst, const WASMModule *module_interp,
         imported_func_interp->u.function.func_ptr_linked = import->u.cb_env.cb;
     else
         imported_func_interp->u.function.func_ptr_linked = import->u.cb;
+    bh_assert(imported_func_interp->u.function.func_ptr_linked);
+
     import->func_idx_rt = func_idx_rt;
 
     (void)inst;
@@ -4320,12 +4385,19 @@ interp_link_global(const WASMModule *module_interp, uint16 global_idx_rt,
 
     imported_global_interp = module_interp->import_globals + global_idx_rt;
     bh_assert(imported_global_interp);
+    bh_assert(imported_global_interp->kind == IMPORT_KIND_GLOBAL);
 
+    /* it is a placeholder and let's skip it*/
+    if (!import->type)
+        return true;
+
+    /* type comparison */
     if (!cmp_val_kind_with_val_type(wasm_valtype_kind(import->type->val_type),
                                     imported_global_interp->u.global.type))
         return false;
 
     /* set init value */
+    bh_assert(import->init);
     switch (wasm_valtype_kind(import->type->val_type)) {
         case WASM_I32:
             imported_global_interp->u.global.global_data_linked.i32 =
@@ -4352,58 +4424,6 @@ interp_link_global(const WASMModule *module_interp, uint16 global_idx_rt,
     return true;
 }
 
-static bool
-interp_link(const wasm_instance_t *inst, const WASMModule *module_interp,
-            wasm_extern_t *imports[])
-{
-    uint32 i = 0;
-    uint32 import_func_i = 0;
-    uint32 import_global_i = 0;
-
-    bh_assert(inst && module_interp && imports);
-
-    for (i = 0; i < module_interp->import_count; ++i) {
-        wasm_extern_t *import = imports[i];
-        WASMImport *import_rt = module_interp->imports + i;
-
-        switch (import_rt->kind) {
-            case IMPORT_KIND_FUNC:
-            {
-                if (!interp_link_func(inst, module_interp, import_func_i,
-                                      wasm_extern_as_func(import))) {
-                    LOG_WARNING("link #%d function failed", import_func_i);
-                    goto failed;
-                }
-                import_func_i++;
-                break;
-            }
-            case IMPORT_KIND_GLOBAL:
-            {
-                if (!interp_link_global(module_interp, import_global_i,
-                                        wasm_extern_as_global(import))) {
-                    LOG_WARNING("link #%d global failed", import_global_i);
-                    goto failed;
-                }
-                import_global_i++;
-                break;
-            }
-            case IMPORT_KIND_MEMORY:
-            case IMPORT_KIND_TABLE:
-            default:
-                ASSERT_NOT_IMPLEMENTED();
-                LOG_WARNING("%s meets unsupported kind: %d", __FUNCTION__,
-                            import_rt->kind);
-                goto failed;
-        }
-    }
-
-    return true;
-
-failed:
-    LOG_DEBUG("%s failed", __FUNCTION__);
-    return false;
-}
-
 static bool
 interp_process_export(wasm_store_t *store,
                       const WASMModuleInstance *inst_interp,
@@ -4503,6 +4523,10 @@ aot_link_func(const wasm_instance_t *inst, const AOTModule *module_aot,
     import_aot_func = module_aot->import_funcs + import_func_idx_rt;
     bh_assert(import_aot_func);
 
+    /* it is a placeholder and let's skip it*/
+    if (!import->type)
+        return true;
+
     /* type comparison */
     if (!wasm_functype_same_internal(import->type, import_aot_func->func_type))
         return false;
@@ -4515,6 +4539,8 @@ aot_link_func(const wasm_instance_t *inst, const AOTModule *module_aot,
         import_aot_func->func_ptr_linked = import->u.cb_env.cb;
     else
         import_aot_func->func_ptr_linked = import->u.cb;
+    bh_assert(import_aot_func->func_ptr_linked);
+
     import->func_idx_rt = import_func_idx_rt;
 
     return true;
@@ -4532,6 +4558,10 @@ aot_link_global(const AOTModule *module_aot, uint16 global_idx_rt,
     import_aot_global = module_aot->import_globals + global_idx_rt;
     bh_assert(import_aot_global);
 
+    /* it is a placeholder and let's skip it*/
+    if (!import->type)
+        return true;
+
     val_type = wasm_globaltype_content(import->type);
     bh_assert(val_type);
 
@@ -4539,6 +4569,7 @@ aot_link_global(const AOTModule *module_aot, uint16 global_idx_rt,
                                     import_aot_global->type))
         return false;
 
+    bh_assert(import->init);
     switch (wasm_valtype_kind(val_type)) {
         case WASM_I32:
             import_aot_global->global_data_linked.i32 = import->init->of.i32;
@@ -4559,62 +4590,6 @@ aot_link_global(const AOTModule *module_aot, uint16 global_idx_rt,
     import->global_idx_rt = global_idx_rt;
     import_aot_global->is_linked = true;
     return true;
-
-failed:
-    LOG_DEBUG("%s failed", __FUNCTION__);
-    return false;
-}
-
-static bool
-aot_link(const wasm_instance_t *inst, const AOTModule *module_aot,
-         wasm_extern_t *imports[])
-{
-    uint32 i = 0;
-    uint32 import_func_i = 0;
-    uint32 import_global_i = 0;
-    wasm_extern_t *import = NULL;
-    wasm_func_t *func = NULL;
-    wasm_global_t *global = NULL;
-
-    bh_assert(inst && module_aot && imports);
-
-    while (import_func_i < module_aot->import_func_count
-           || import_global_i < module_aot->import_global_count) {
-        import = imports[i++];
-
-        bh_assert(import);
-
-        switch (wasm_extern_kind(import)) {
-            case WASM_EXTERN_FUNC:
-                bh_assert(import_func_i < module_aot->import_func_count);
-                func = wasm_extern_as_func((wasm_extern_t *)import);
-                if (!aot_link_func(inst, module_aot, import_func_i, func)) {
-                    LOG_WARNING("link #%d function failed", import_func_i);
-                    goto failed;
-                }
-                import_func_i++;
-
-                break;
-            case WASM_EXTERN_GLOBAL:
-                bh_assert(import_global_i < module_aot->import_global_count);
-                global = wasm_extern_as_global((wasm_extern_t *)import);
-                if (!aot_link_global(module_aot, import_global_i, global)) {
-                    LOG_WARNING("link #%d global failed", import_global_i);
-                    goto failed;
-                }
-                import_global_i++;
-
-                break;
-            case WASM_EXTERN_MEMORY:
-            case WASM_EXTERN_TABLE:
-            default:
-                ASSERT_NOT_IMPLEMENTED();
-                goto failed;
-        }
-    }
-
-    return true;
-
 failed:
     LOG_DEBUG("%s failed", __FUNCTION__);
     return false;
@@ -4695,7 +4670,7 @@ aot_process_export(wasm_store_t *store, const AOTModuleInstance *inst_aot,
             goto failed;
         }
 
-        wasm_name_new_from_string(external->name, export->name);
+        wasm_name_new_from_string_nt(external->name, export->name);
         if (strlen(export->name) && !external->name->data) {
             goto failed;
         }
@@ -4713,65 +4688,103 @@ failed:
 }
 #endif /* WASM_ENABLE_AOT */
 
-wasm_instance_t *
-wasm_instance_new(wasm_store_t *store, const wasm_module_t *module,
-                  const wasm_extern_vec_t *imports, own wasm_trap_t **trap)
-{
-    return wasm_instance_new_with_args(store, module, imports, trap,
-                                       KILOBYTE(32), KILOBYTE(32));
-}
-
 static bool
-compare_imports(const wasm_module_t *module, const wasm_extern_vec_t *imports)
+do_link(const wasm_instance_t *inst, const wasm_module_t *module,
+        const wasm_extern_vec_t *imports)
 {
-    unsigned import_func_count = 0;
-    unsigned import_global_count = 0;
-    unsigned import_memory_count = 0;
-    unsigned import_table_count = 0;
-    unsigned i = 0;
+    uint32 i, import_func_i, import_global_i;
 
-    for (i = 0; imports && i < imports->num_elems; i++) {
+    bh_assert(inst && module);
+
+    /* we have run a module_type check before. */
+
+    for (i = 0, import_func_i = 0, import_global_i = 0; i < imports->num_elems;
+         i++) {
         wasm_extern_t *import = imports->data[i];
+
+        if (!import) {
+            LOG_ERROR("imports[%d] is NULL and it is fatal\n", i);
+            goto failed;
+        }
+
         switch (wasm_extern_kind(import)) {
             case WASM_EXTERN_FUNC:
-                import_func_count++;
+            {
+                bool ret = false;
+#if WASM_ENABLE_INTERP != 0
+                if ((*module)->module_type == Wasm_Module_Bytecode) {
+                    ret = interp_link_func(inst, MODULE_INTERP(module),
+                                           import_func_i,
+                                           wasm_extern_as_func(import));
+                }
+#endif
+#if WASM_ENABLE_AOT != 0
+                if ((*module)->module_type == Wasm_Module_AoT) {
+                    ret = aot_link_func(inst, MODULE_AOT(module), import_func_i,
+                                        wasm_extern_as_func(import));
+                }
+#endif
+                if (!ret) {
+                    LOG_WARNING("link function  #%d failed", import_func_i);
+                    goto failed;
+                }
+
+                import_func_i++;
                 break;
+            }
             case WASM_EXTERN_GLOBAL:
-                import_global_count++;
+            {
+                bool ret = false;
+#if WASM_ENABLE_INTERP != 0
+                if ((*module)->module_type == Wasm_Module_Bytecode) {
+                    ret = interp_link_global(MODULE_INTERP(module),
+                                             import_global_i,
+                                             wasm_extern_as_global(import));
+                }
+#endif
+#if WASM_ENABLE_AOT != 0
+                if ((*module)->module_type == Wasm_Module_AoT) {
+                    ret = aot_link_global(MODULE_AOT(module), import_global_i,
+                                          wasm_extern_as_global(import));
+                }
+#endif
+                if (!ret) {
+                    LOG_WARNING("link global #%d failed", import_global_i);
+                    goto failed;
+                }
+
+                import_global_i++;
                 break;
+            }
             case WASM_EXTERN_MEMORY:
-                import_memory_count++;
-                break;
             case WASM_EXTERN_TABLE:
-                import_table_count++;
+            {
+                LOG_WARNING("doesn't support import memories and tables for "
+                            "now, ignore them");
                 break;
+            }
             default:
+            {
                 UNREACHABLE();
-                return false;
+                break;
+            }
         }
     }
 
-#if WASM_ENABLE_INTERP != 0
-    if ((*module)->module_type == Wasm_Module_Bytecode)
-        return import_func_count == MODULE_INTERP(module)->import_function_count
-               && import_global_count
-                      == MODULE_INTERP(module)->import_global_count
-               && import_memory_count
-                      == MODULE_INTERP(module)->import_memory_count
-               && import_table_count
-                      == MODULE_INTERP(module)->import_table_count;
-#endif
-#if WASM_ENABLE_AOT != 0
-    if ((*module)->module_type == Wasm_Module_AoT)
-        return import_func_count == MODULE_AOT(module)->import_func_count
-               && import_global_count == MODULE_AOT(module)->import_global_count
-               && import_memory_count == MODULE_AOT(module)->import_memory_count
-               && import_table_count == MODULE_AOT(module)->import_table_count;
-#endif
-
+    return true;
+failed:
+    LOG_DEBUG("%s failed", __FUNCTION__);
     return false;
 }
 
+wasm_instance_t *
+wasm_instance_new(wasm_store_t *store, const wasm_module_t *module,
+                  const wasm_extern_vec_t *imports, own wasm_trap_t **trap)
+{
+    return wasm_instance_new_with_args(store, module, imports, trap,
+                                       KILOBYTE(32), KILOBYTE(32));
+}
+
 wasm_instance_t *
 wasm_instance_new_with_args(wasm_store_t *store, const wasm_module_t *module,
                             const wasm_extern_vec_t *imports,
@@ -4781,7 +4794,6 @@ wasm_instance_new_with_args(wasm_store_t *store, const wasm_module_t *module,
     char sub_error_buf[128] = { 0 };
     char error_buf[256] = { 0 };
     wasm_instance_t *instance = NULL;
-    WASMModuleInstance *inst_rt;
     CApiFuncImport *func_import = NULL, **p_func_imports = NULL;
     uint32 i = 0, import_func_count = 0;
     uint64 total_size;
@@ -4792,11 +4804,9 @@ wasm_instance_new_with_args(wasm_store_t *store, const wasm_module_t *module,
     if (!module)
         return NULL;
 
-    if (!compare_imports(module, imports)) {
-        snprintf(sub_error_buf, sizeof(sub_error_buf),
-                 "Failed to match imports");
-        goto failed;
-    }
+    /*
+     * will do the check at the end of wasm_runtime_instantiate
+     */
 
     WASM_C_DUMP_PROC_MEM();
 
@@ -4807,43 +4817,17 @@ wasm_instance_new_with_args(wasm_store_t *store, const wasm_module_t *module,
         goto failed;
     }
 
-    /* link module and imports */
-    if (imports && imports->num_elems) {
-        bool link = false;
-#if WASM_ENABLE_INTERP != 0
-        if ((*module)->module_type == Wasm_Module_Bytecode) {
-            if (!interp_link(instance, MODULE_INTERP(module),
-                             (wasm_extern_t **)imports->data)) {
-                snprintf(sub_error_buf, sizeof(sub_error_buf),
-                         "Failed to validate imports");
-                goto failed;
-            }
-            link = true;
-        }
-#endif
-
-#if WASM_ENABLE_AOT != 0
-        if ((*module)->module_type == Wasm_Module_AoT) {
-            if (!aot_link(instance, MODULE_AOT(module),
-                          (wasm_extern_t **)imports->data)) {
-                snprintf(sub_error_buf, sizeof(sub_error_buf),
-                         "Failed to validate imports");
-                goto failed;
-            }
-            link = true;
-        }
-#endif
-
-        /*
-         * a wrong combination of module filetype and compilation flags
-         * also leads to below branch
-         */
-        if (!link) {
+    /* executes the instantiate-time linking if provided */
+    if (imports) {
+        if (!do_link(instance, module, imports)) {
             snprintf(sub_error_buf, sizeof(sub_error_buf),
-                     "Failed to verify import count");
+                     "Failed to validate imports");
             goto failed;
         }
     }
+    /*
+     * will do the linking result check at the end of wasm_runtime_instantiate
+     */
 
     instance->inst_comm_rt = wasm_runtime_instantiate(
         *module, stack_size, heap_size, sub_error_buf, sizeof(sub_error_buf));
@@ -4858,18 +4842,22 @@ wasm_instance_new_with_args(wasm_store_t *store, const wasm_module_t *module,
     }
 
     /* create the c-api func import list */
-    inst_rt = (WASMModuleInstance *)instance->inst_comm_rt;
 #if WASM_ENABLE_INTERP != 0
     if (instance->inst_comm_rt->module_type == Wasm_Module_Bytecode) {
-        p_func_imports = &inst_rt->e->c_api_func_imports;
-        import_func_count = inst_rt->module->import_function_count;
+        WASMModuleInstanceExtra *e =
+            ((WASMModuleInstance *)instance->inst_comm_rt)->e;
+        p_func_imports = &(e->c_api_func_imports);
+        import_func_count = MODULE_INTERP(module)->import_function_count;
     }
 #endif
 #if WASM_ENABLE_AOT != 0
     if (instance->inst_comm_rt->module_type == Wasm_Module_AoT) {
-        p_func_imports =
-            &((AOTModuleInstanceExtra *)inst_rt->e)->c_api_func_imports;
-        import_func_count = ((AOTModule *)inst_rt->module)->import_func_count;
+        AOTModuleInstanceExtra *e =
+            (AOTModuleInstanceExtra *)((AOTModuleInstance *)
+                                           instance->inst_comm_rt)
+                ->e;
+        p_func_imports = &(e->c_api_func_imports);
+        import_func_count = MODULE_AOT(module)->import_func_count;
     }
 #endif
     bh_assert(p_func_imports);
@@ -4882,16 +4870,21 @@ wasm_instance_new_with_args(wasm_store_t *store, const wasm_module_t *module,
         goto failed;
     }
 
-    /* fill in c-api func import list */
+    /* fill in module_inst->e->c_api_func_imports */
     for (i = 0; imports && i < imports->num_elems; i++) {
-        wasm_func_t *func_host;
-        wasm_extern_t *in;
+        wasm_func_t *func_host = NULL;
+        wasm_extern_t *in = imports->data[i];
+        bh_assert(in);
 
-        in = imports->data[i];
         if (wasm_extern_kind(in) != WASM_EXTERN_FUNC)
             continue;
 
         func_host = wasm_extern_as_func(in);
+        /* it is a placeholder and let's skip it*/
+        if (!func_host->type) {
+            func_import++;
+            continue;
+        }
 
         func_import->with_env_arg = func_host->with_env;
         if (func_host->with_env) {
@@ -4902,6 +4895,7 @@ wasm_instance_new_with_args(wasm_store_t *store, const wasm_module_t *module,
             func_import->func_ptr_linked = func_host->u.cb;
             func_import->env_arg = NULL;
         }
+        bh_assert(func_import->func_ptr_linked);
 
         func_import++;
     }
@@ -4909,6 +4903,8 @@ wasm_instance_new_with_args(wasm_store_t *store, const wasm_module_t *module,
     /* fill with inst */
     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 =
@@ -5004,7 +5000,7 @@ failed:
              sub_error_buf);
     if (trap != NULL) {
         wasm_message_t message = { 0 };
-        wasm_name_new_from_string(&message, error_buf);
+        wasm_name_new_from_string_nt(&message, error_buf);
         *trap = wasm_trap_new(store, &message);
         wasm_byte_vec_delete(&message);
     }
@@ -5204,3 +5200,16 @@ BASIC_FOUR_LIST(WASM_EXTERN_AS_OTHER_CONST)
 
 BASIC_FOUR_LIST(WASM_OTHER_AS_EXTERN_CONST)
 #undef WASM_OTHER_AS_EXTERN_CONST
+
+wasm_extern_t *
+wasm_extern_new_empty(wasm_store_t *store, wasm_externkind_t extern_kind)
+{
+    if (extern_kind == WASM_EXTERN_FUNC)
+        return wasm_func_as_extern(wasm_func_new_empty(store));
+
+    if (extern_kind == WASM_EXTERN_GLOBAL)
+        return wasm_global_as_extern(wasm_global_new_empty(store));
+
+    LOG_ERROR("Don't support linking table and memory for now");
+    return NULL;
+}

+ 8 - 1
core/iwasm/common/wasm_native.c

@@ -239,6 +239,10 @@ lookup_symbol(NativeSymbol *native_symbols, uint32 n_native_symbols,
     return NULL;
 }
 
+/**
+ * allow func_type and all outputs, like p_signature, p_attachment and
+ * p_call_conv_raw to be NULL
+ */
 void *
 wasm_native_resolve_symbol(const char *module_name, const char *field_name,
                            const WASMType *func_type, const char **p_signature,
@@ -264,10 +268,13 @@ wasm_native_resolve_symbol(const char *module_name, const char *field_name,
         node = node_next;
     }
 
+    if (!p_signature || !p_attachment || !p_call_conv_raw)
+        return func_ptr;
+
     if (func_ptr) {
         if (signature && signature[0] != '\0') {
             /* signature is not empty, check its format */
-            if (!check_symbol_signature(func_type, signature)) {
+            if (!func_type || !check_symbol_signature(func_type, signature)) {
 #if WASM_ENABLE_WAMR_COMPILER == 0
                 /* Output warning except running aot compiler */
                 LOG_WARNING("failed to check signature '%s' and resolve "

+ 22 - 0
core/iwasm/common/wasm_runtime_common.c

@@ -7,6 +7,7 @@
 #include "bh_common.h"
 #include "bh_assert.h"
 #include "bh_log.h"
+#include "wasm_native.h"
 #include "wasm_runtime_common.h"
 #include "wasm_memory.h"
 #if WASM_ENABLE_INTERP != 0
@@ -5331,3 +5332,24 @@ wasm_runtime_get_version(uint32_t *major, uint32_t *minor, uint32_t *patch)
     *minor = WAMR_VERSION_MINOR;
     *patch = WAMR_VERSION_PATCH;
 }
+
+bool
+wasm_runtime_is_import_func_linked(const char *module_name,
+                                   const char *func_name)
+{
+    return wasm_native_resolve_symbol(module_name, func_name, NULL, NULL, NULL,
+                                      NULL);
+}
+
+bool
+wasm_runtime_is_import_global_linked(const char *module_name,
+                                     const char *global_name)
+{
+#if WASM_ENABLE_LIBC_BUILTIN != 0
+    WASMGlobalImport global = { 0 };
+    return wasm_native_lookup_libc_builtin_global(module_name, global_name,
+                                                  &global);
+#else
+    return false;
+#endif
+}

+ 8 - 0
core/iwasm/common/wasm_runtime_common.h

@@ -993,6 +993,14 @@ void
 wasm_runtime_destroy_custom_sections(WASMCustomSection *section_list);
 #endif
 
+WASM_RUNTIME_API_EXTERN bool
+wasm_runtime_is_import_func_linked(const char *module_name,
+                                   const char *func_name);
+
+WASM_RUNTIME_API_EXTERN bool
+wasm_runtime_is_import_global_linked(const char *module_name,
+                                     const char *global_name);
+
 #ifdef __cplusplus
 }
 #endif

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

@@ -354,6 +354,7 @@ WASM_API_EXTERN own wasm_importtype_t* wasm_importtype_new(
 WASM_API_EXTERN const wasm_name_t* wasm_importtype_module(const wasm_importtype_t*);
 WASM_API_EXTERN const wasm_name_t* wasm_importtype_name(const wasm_importtype_t*);
 WASM_API_EXTERN const wasm_externtype_t* wasm_importtype_type(const wasm_importtype_t*);
+WASM_API_EXTERN bool wasm_importtype_is_linked(const wasm_importtype_t*);
 
 
 // Export Types
@@ -797,6 +798,9 @@ static inline void* wasm_val_ptr(const wasm_val_t* val) {
 
 #define KILOBYTE(n) ((n) * 1024)
 
+// Create placeholders filled in `wasm_externvec_t* imports` for `wasm_instance_new()`
+WASM_API_EXTERN wasm_extern_t *wasm_extern_new_empty(wasm_store_t *,  wasm_externkind_t);
+
 ///////////////////////////////////////////////////////////////////////////////
 
 #undef own

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

@@ -1324,6 +1324,22 @@ wasm_runtime_get_custom_section(wasm_module_t const module_comm,
  */
 WASM_RUNTIME_API_EXTERN void
 wasm_runtime_get_version(uint32_t *major, uint32_t *minor, uint32_t *patch);
+
+/**
+ * Check whether an import func `(import <module_name> <func_name> (func ...))` is linked or not
+ * with runtime registered natvie functions
+ */
+WASM_RUNTIME_API_EXTERN bool
+wasm_runtime_is_import_func_linked(const char *module_name,
+                                   const char *func_name);
+
+/**
+ * Check whether an import global `(import <module_name> <global_name> (global ...))` is linked or not
+ * with runtime registered natvie globals
+ */
+WASM_RUNTIME_API_EXTERN bool
+wasm_runtime_is_import_global_linked(const char *module_name,
+                                     const char *global_name);
 /* clang-format on */
 
 #ifdef __cplusplus

+ 6 - 3
core/iwasm/interpreter/wasm_loader.c

@@ -1399,6 +1399,7 @@ load_global_import(const uint8 **p_buf, const uint8 *buf_end,
     WASMModule *sub_module = NULL;
     WASMGlobal *linked_global = NULL;
 #endif
+    bool ret = false;
 
     CHECK_BUF(p, p_end, 2);
     declare_type = read_uint8(p);
@@ -1411,15 +1412,16 @@ load_global_import(const uint8 **p_buf, const uint8 *buf_end,
     }
 
 #if WASM_ENABLE_LIBC_BUILTIN != 0
-    global->is_linked = wasm_native_lookup_libc_builtin_global(
-        sub_module_name, global_name, global);
-    if (global->is_linked) {
+    ret = wasm_native_lookup_libc_builtin_global(sub_module_name, global_name,
+                                                 global);
+    if (ret) {
         if (global->type != declare_type
             || global->is_mutable != declare_mutable) {
             set_error_buf(error_buf, error_buf_size,
                           "incompatible import type");
             return false;
         }
+        global->is_linked = true;
     }
 #endif
 #if WASM_ENABLE_MULTI_MODULE != 0
@@ -1449,6 +1451,7 @@ load_global_import(const uint8 **p_buf, const uint8 *buf_end,
     global->is_mutable = (declare_mutable == 1);
 
     (void)parent_module;
+    (void)ret;
     return true;
 fail:
     return false;

+ 41 - 0
core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c

@@ -570,6 +570,7 @@ pthread_create_wrapper(wasm_exec_env_t exec_env,
 #if WASM_ENABLE_LIBC_WASI != 0
     WASIContext *wasi_ctx;
 #endif
+    CApiFuncImport **new_c_api_func_imports = NULL;
 
     bh_assert(module);
     bh_assert(module_inst);
@@ -602,6 +603,46 @@ pthread_create_wrapper(wasm_exec_env_t exec_env,
         wasm_runtime_set_wasi_ctx(new_module_inst, wasi_ctx);
 #endif
 
+    /* workaround about passing instantiate-linking information */
+    {
+        CApiFuncImport *c_api_func_imports;
+        uint32 import_func_count = 0;
+        uint32 size_in_bytes = 0;
+
+#if WASM_ENABLE_INTERP != 0
+        if (module_inst->module_type == Wasm_Module_Bytecode) {
+            new_c_api_func_imports = &(
+                ((WASMModuleInstance *)new_module_inst)->e->c_api_func_imports);
+            c_api_func_imports =
+                ((WASMModuleInstance *)module_inst)->e->c_api_func_imports;
+            import_func_count = ((WASMModule *)module)->import_function_count;
+        }
+#endif
+#if WASM_ENABLE_AOT != 0
+        if (module_inst->module_type == Wasm_Module_AoT) {
+            AOTModuleInstanceExtra *e =
+                (AOTModuleInstanceExtra *)((AOTModuleInstance *)new_module_inst)
+                    ->e;
+            new_c_api_func_imports = &(e->c_api_func_imports);
+
+            e = (AOTModuleInstanceExtra *)((AOTModuleInstance *)module_inst)->e;
+            c_api_func_imports = e->c_api_func_imports;
+
+            import_func_count = ((AOTModule *)module)->import_func_count;
+        }
+#endif
+
+        if (import_func_count != 0 && c_api_func_imports) {
+            size_in_bytes = sizeof(CApiFuncImport *) * import_func_count;
+            *new_c_api_func_imports = wasm_runtime_malloc(size_in_bytes);
+            if (!(*new_c_api_func_imports))
+                goto fail;
+
+            bh_memcpy_s(*new_c_api_func_imports, size_in_bytes,
+                        c_api_func_imports, size_in_bytes);
+        }
+    }
+
     if (!(info_node = wasm_runtime_malloc(sizeof(ThreadInfoNode))))
         goto fail;
 

+ 2 - 0
samples/wasm-c-api-imports/.gitignore

@@ -0,0 +1,2 @@
+/wasm/inc/**
+!/wasm/inc/.*

+ 169 - 0
samples/wasm-c-api-imports/CMakeLists.txt

@@ -0,0 +1,169 @@
+# Copyright (C) 2019 Intel Corporation.  All rights reserved.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+cmake_minimum_required(VERSION 3.14)
+project(how-to-deal-with-import)
+
+include(CMakePrintHelpers)
+include(CTest)
+include(ExternalProject)
+include(FetchContent)
+
+#
+# dependencies
+#
+set(WAMR_ROOT ${CMAKE_CURRENT_LIST_DIR}/../../)
+# wasm required headers
+execute_process(
+  COMMAND ${CMAKE_COMMAND} -E copy_if_different
+              ${WARM_ROOT}/${WAMR_ROOT}/wamr-sdk/app/libc-builtin-sysroot/include/pthread.h
+              ${CMAKE_CURRENT_LIST_DIR}/wasm/inc
+)
+
+# vmlib
+################  runtime settings  ################
+string (TOLOWER ${CMAKE_HOST_SYSTEM_NAME} WAMR_BUILD_PLATFORM)
+if (APPLE)
+  add_definitions(-DBH_PLATFORM_DARWIN)
+endif ()
+
+# Resetdefault linker flags
+set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")
+set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "")
+
+# WAMR features switch
+
+# Set WAMR_BUILD_TARGET, currently values supported:
+# "X86_64", "AMD_64", "X86_32", "AARCH64[sub]", "ARM[sub]", "THUMB[sub]",
+# "MIPS", "XTENSA", "RISCV64[sub]", "RISCV32[sub]"
+if (NOT DEFINED WAMR_BUILD_TARGET)
+  if (CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm64|aarch64)")
+    set (WAMR_BUILD_TARGET "AARCH64")
+  elseif (CMAKE_SYSTEM_PROCESSOR STREQUAL "riscv64")
+    set (WAMR_BUILD_TARGET "RISCV64")
+  elseif (CMAKE_SIZEOF_VOID_P EQUAL 8)
+    # Build as X86_64 by default in 64-bit platform
+    set (WAMR_BUILD_TARGET "X86_64")
+  elseif (CMAKE_SIZEOF_VOID_P EQUAL 4)
+    # Build as X86_32 by default in 32-bit platform
+    set (WAMR_BUILD_TARGET "X86_32")
+  else ()
+    message(SEND_ERROR "Unsupported build target platform!")
+  endif ()
+endif ()
+
+if (NOT CMAKE_BUILD_TYPE)
+  set (CMAKE_BUILD_TYPE Release)
+endif ()
+
+set(WAMR_BUILD_AOT 1)
+set(WAMR_BUILD_INTERP 0)
+set(WAMR_BUILD_JIT 0)
+
+set(WAMR_BUILD_FAST_INTERP 1)
+set(WAMR_BUILD_LIB_PTHREAD 1)
+set(WAMR_BUILD_LIBC_BUILTIN 1)
+set(WAMR_BUILD_LIBC_WASI 1)
+set(WAMR_BUILD_SIMD 0)
+
+# compiling and linking flags
+if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang"))
+  set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections")
+endif ()
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat -Wformat-security")
+
+# build out vmlib
+set(WAMR_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../..)
+include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake)
+
+add_library(vmlib ${WAMR_RUNTIME_LIB_SOURCE})
+target_link_libraries(vmlib INTERFACE dl m pthread)
+if(WAMR_BUILD_AOT EQUAL 1)
+  target_compile_definitions(vmlib INTERFACE -DWASM_ENABLE_AOT=1)
+else()
+  target_compile_definitions(vmlib INTERFACE -DWASM_ENABLE_AOT=0)
+endif()
+
+if(WAMR_BUILD_INTERP EQUAL 1)
+  target_compile_definitions(vmlib INTERFACE -DWASM_ENABLE_INTERP=1)
+else()
+  target_compile_definitions(vmlib INTERFACE -DWASM_ENABLE_INTERP=0)
+endif()
+
+if(CMAKE_BUILD_TYPE STREQUAL "Debug")
+  # ASAN + UBSAN
+  target_compile_options(vmlib INTERFACE -fsanitize=address,undefined)
+  target_link_options(vmlib INTERFACE -fsanitize=address,undefined)
+endif()
+
+# # MSAN
+# target_compile_options(vmlib INTERFACE -fsanitize=memory -fno-optimize-sibling-calls -fsanitize-memory-track-origins=2 -fno-omit-frame-pointer)
+# target_link_options(vmlib INTERFACE -fsanitize=memory)
+
+# wamrc
+if(WAMR_BUILD_AOT EQUAL 1 AND WAMR_BUILD_INTERP EQUAL 0)
+  ExternalProject_Add(wamrc
+    PREFIX            wamrc-build
+    SOURCE_DIR        ${WAMR_ROOT}/wamr-compiler
+    CONFIGURE_COMMAND ${CMAKE_COMMAND} -S ${WAMR_ROOT}/wamr-compiler -B build
+    BUILD_COMMAND     ${CMAKE_COMMAND} --build build --target wamrc
+    INSTALL_COMMAND   ${CMAKE_COMMAND} -E copy_if_different build/wamrc ${CMAKE_CURRENT_BINARY_DIR}/wamrc
+  )
+endif()
+
+#
+# host
+add_subdirectory(host)
+add_custom_target(
+  install_host ALL
+  COMMAND ${CMAKE_COMMAND} -E copy_if_different ./host/example1 .
+  DEPENDS example1
+  WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+)
+
+# TODO: replace it with a find_package()
+set(WASI_SDK_DIR /opt/wasi-sdk-19.0/)
+set(WASI_TOOLCHAIN_FILE ${WASI_SDK_DIR}/share/cmake/wasi-sdk.cmake)
+set(WASI_SYS_ROOT ${WASI_SDK_DIR}/share/wasi-sysroot)
+
+#
+# wasm
+if(WAMR_BUILD_AOT EQUAL 1 AND WAMR_BUILD_INTERP EQUAL 0)
+  ExternalProject_Add(wasm
+    PREFIX            wasm-build
+    DEPENDS           wamrc
+    BUILD_ALWAYS      TRUE
+    SOURCE_DIR        ${CMAKE_CURRENT_LIST_DIR}/wasm
+    CONFIGURE_COMMAND ${CMAKE_COMMAND} -S ${CMAKE_CURRENT_LIST_DIR}/wasm -B build
+                        -DWASI_SDK_PREFIX=${WASI_SDK_DIR}
+                        -DCMAKE_TOOLCHAIN_FILE=${WASI_TOOLCHAIN_FILE}
+                        -DCMAKE_SYSROOT=${WASI_SYS_ROOT}
+                        -DWASM_TO_AOT=ON
+                        -DWAMRC_PATH=${CMAKE_CURRENT_BINARY_DIR}/wamrc
+                        -DSOCKET_WASI_CMAKE=${WAMR_ROOT}/core/iwasm/libraries/lib-socket/lib_socket_wasi.cmake
+    BUILD_COMMAND     ${CMAKE_COMMAND} --build build
+    INSTALL_COMMAND   ${CMAKE_COMMAND} --install build --prefix ${CMAKE_CURRENT_BINARY_DIR}
+  )
+else()
+  ExternalProject_Add(wasm
+    PREFIX            wasm-build
+    BUILD_ALWAYS      TRUE
+    SOURCE_DIR        ${CMAKE_CURRENT_LIST_DIR}/wasm
+    CONFIGURE_COMMAND ${CMAKE_COMMAND} -S ${CMAKE_CURRENT_LIST_DIR}/wasm -B build
+                        -DWASI_SDK_PREFIX=${WASI_SDK_DIR}
+                        -DCMAKE_TOOLCHAIN_FILE=${WASI_TOOLCHAIN_FILE}
+                        -DCMAKE_SYSROOT=${WASI_SYS_ROOT}
+                        -DSOCKET_WASI_CMAKE=${WAMR_ROOT}/core/iwasm/libraries/lib-socket/lib_socket_wasi.cmake
+    BUILD_COMMAND     ${CMAKE_COMMAND} --build build
+    INSTALL_COMMAND   ${CMAKE_COMMAND} --install build --prefix ${CMAKE_CURRENT_BINARY_DIR}
+  )
+endif()
+
+#
+# Test
+#
+add_test(
+  NAME run_example1
+  COMMAND ./example1
+  WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+)

+ 174 - 0
samples/wasm-c-api-imports/README.md

@@ -0,0 +1,174 @@
+# How to create `imports` for wasm_instance_new() properly
+
+It's always been asked how to create `wasm_extern_vec_t *imports` for
+`wasm_instance_new()`?
+
+```c
+WASM_API_EXTERN own wasm_instance_t* wasm_instance_new(
+  wasm_store_t*, const wasm_module_t*, const wasm_extern_vec_t *imports,
+  own wasm_trap_t** trap
+);
+```
+
+`wasm_extern_vec_t *imports` is required to match the requirement of _the
+import section_ of a .wasm.
+
+```bash
+$ /opt/wabt-1.0.31/bin/wasm-objdump -j Import -x <some_example>.wasm
+
+Section Details:
+
+Import[27]:
+ - func[0] sig=2 <pthread_mutex_lock> <- env.pthread_mutex_lock
+ - func[1] sig=2 <pthread_mutex_unlock> <- env.pthread_mutex_unlock
+ - func[2] sig=2 <pthread_cond_signal> <- env.pthread_cond_signal
+ - func[3] sig=3 <host_log> <- env.log
+ ...
+ - func[11] sig=4 <__imported_wasi_snapshot_preview1_sock_bind> <- wasi_snapshot_preview1.sock_bind
+ - func[12] sig=4 <__imported_wasi_snapshot_preview1_sock_connect> <- wasi_snapshot_preview1.sock_connect
+ - func[13] sig=4 <__imported_wasi_snapshot_preview1_sock_listen> <- wasi_snapshot_preview1.sock_listen
+ - func[14] sig=5 <__imported_wasi_snapshot_preview1_sock_open> <- wasi_snapshot_preview1.sock_open
+ - func[15] sig=4 <__imported_wasi_snapshot_preview1_sock_addr_remote> <- wasi_snapshot_preview1.sock_addr_remote
+ - func[16] sig=4 <__imported_wasi_snapshot_preview1_args_get> <- wasi_snapshot_preview1.args_get
+ - func[17] sig=4 <__imported_wasi_snapshot_preview1_args_sizes_get> <- wasi_snapshot_preview1.args_sizes_get
+ ...
+```
+
+Developers should fill in _imports_ with enough host functions and make sure
+there are no linking problems during instantiation.
+
+```bash
+TODO: linking warnings
+```
+
+## A natural way
+
+One natural answer is "to create a list which matches every item in _the import
+section_" of the .wasm. Since developers can see the section details of
+a .wasm by tools like _wasm-objdump_, the answer is doable. Most of the time,
+if they also prepare Wasm modules, developers have full control over import
+requirements, and they only need to take a look at the order of _the import
+section_.
+
+Yes, _the order_. A proper `wasm_extern_vec_t *imports` includes two things:
+
+1. how many `wasm_extern_t`
+2. and order of those
+
+Because there is no "name information" in a `wasm_extern_t`. The only way is let
+`wasm_instance_new()` to tell which item in _the import section_ of a .wasm
+should match any item in `wasm_extern_vec_t *imports` is based on **_index_**.
+
+The algorithm is quite straightforward. The first one of _the import section_ matches
+`wasm_extern_vec_t *imports->data[0] `. The second one matches `wasm_extern_vec_t *imports->data[1]`.
+And so on.
+
+So the order of `wasm_extern_vec_t *imports` becomes quite a burden. It requires
+developers always checking _the import section_ visually.
+
+Until here, the natural way is still workable although involving some handy work.
+Right?
+
+## A blocker
+
+Sorry, the situation changes a lot when driving wasm32-wasi Wasm modules with
+wasm-c-api.
+
+As you know, WASI provides _a set of crossing-platform standard libraries_ for
+Wasm modules, and leaves some _interfaces_ for native platform-dependent supports.
+Those _interfaces_ are those import items with the module name `wasi_snapshot_preview1`
+in a Wasm module.
+
+It seems not economical to let developers provide their version of host
+implementations of the `wasi_snapshot_preview1.XXX` functions. All those support
+should be packed into a common library and shared in different Wasm modules.
+Like a [cargo WASI](https://github.com/bytecodealliance/cargo-wasi).
+
+WAMR chooses to integrate the WASI support library in the runtime to reduce
+developers' compilation work. It brings developers a new thing of a proper
+`wasm_extern_vec_t *imports` that developers should avoid overwriting those items
+of _the import section_ of a Wasm module that will be provided by the runtime. It
+also not economical to code for those functions.
+
+Using module names as a filter seems to be a simple way. But some private
+additional c/c++ libraries are supported in WAMR. Those supporting will bring
+more import items that don't use `wasi_snapshot_preview1` as module names but are still
+covered by the WASM runtime. Like `env.pthread_`. Plus, [the native lib registeration](https://github.com/bytecodealliance/wasm-micro-runtime/blob/main/doc/export_native_api.md)
+provides another possible way to fill in the requirement of _the import section_.
+
+Let's take summarize. A proper `wasm_extern_vec_t *imports` should include:
+
+1. provides all necessary host implementations for items in _the import section_
+2. should not override runtime provided implementation or covered by native
+   registrations. functinal or econmical.
+3. keep them in a right order
+
+## A recommendation
+
+The recommendation is:
+
+- use `wasm_module_imports()` to build the order
+- use `wasm_importtype_is_linked()` to avoid overwriting
+
+[wasm-c-api-imports](.) is a simple showcase of how to do that.
+
+First, let's take a look at the Wasm module. [send_recv](./wasm/send_recv.c)
+uses both standard WASI and WAMR_BUILD_LIB_PTHREAD supporting. Plus a private
+native function `host_log`.
+
+So, `wasm_extern_vec_t *imports` should only include the host implementation of
+`host_log` and avoid WASI related(`wasm-c-api-imports.XXX`) and pthread related(`env.pthread_XXX`).
+
+[Here is how to do](./host/example1.c):
+
+- get import types with `wasm_module_imports(0)`. it contains name information
+
+```c
+  wasm_importtype_vec_t importtypes = { 0 };
+  wasm_module_imports(module, &importtypes);
+```
+
+- traversal import types. The final `wasm_importvec_t *imports` should have the
+  same order with `wasm_importtype_vec_t`
+
+```c
+  for (unsigned i = 0; i < importtypes.num_elems; i++)
+```
+
+- use `wasm_importtype_is_linked()` to avoid those covered by the runtime and
+  registered natives. A little tip is use "wasm_extern_new_empty()" to create
+  a placeholder.
+
+```c
+    /* use wasm_extern_new_empty() to create a placeholder */
+    if (wasm_importtype_is_linked(importtype)) {
+        externs[i] = wasm_extern_new_empty(
+            store, wasm_externtype_kind(wasm_importtype_type(importtype)));
+        continue;
+    }
+```
+
+- use `wasm_importtype_module()` to get the module name, use `wasm_importtype_name()`
+  to get the field name.
+
+```c
+      const wasm_name_t *module_name =
+          wasm_importtype_module(importtypes.data[i]);
+      const wasm_name_t *field_name =
+          wasm_importtype_name(importtypes.data[i]);
+```
+
+- fill in `wasm_externvec_t *imports` dynamically and programmatically.
+
+```c
+      if (strncmp(module_name->data, "env", strlen("env")) == 0
+          && strncmp(field_name->data, "log", strlen("log")) == 0) {
+          wasm_functype_t *log_type = wasm_functype_new_2_0(
+              wasm_valtype_new_i64(), wasm_valtype_new_i32());
+          wasm_func_t *log_func = wasm_func_new(store, log_type, host_logs);
+          wasm_functype_delete(log_type);
+
+          externs[i] = wasm_func_as_extern(log_func);
+      }
+  }
+```

+ 12 - 0
samples/wasm-c-api-imports/host/CMakeLists.txt

@@ -0,0 +1,12 @@
+# Copyright (C) 2019 Intel Corporation.  All rights reserved.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+cmake_minimum_required(VERSION 3.14)
+project(host)
+
+set(CMAKE_BUILD_TYPE Debug)
+
+#
+# host
+add_executable(example1 ./example1.c)
+target_link_libraries(example1 vmlib)

+ 204 - 0
samples/wasm-c-api-imports/host/example1.c

@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2019 Intel Corporation.  All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "wasm_c_api.h"
+#include "wasm_export.h"
+
+static wasm_trap_t *
+host_logs(const wasm_val_vec_t *args, wasm_val_vec_t *results)
+{
+    return NULL;
+}
+
+static bool
+build_imports(wasm_store_t *store, const wasm_module_t *module,
+              wasm_extern_vec_t *out)
+{
+    wasm_importtype_vec_t importtypes = { 0 };
+    wasm_module_imports(module, &importtypes);
+
+    wasm_extern_t *externs[32] = { 0 };
+
+    for (unsigned i = 0; i < importtypes.num_elems; i++) {
+        wasm_importtype_t *importtype = importtypes.data[i];
+
+        /* use wasm_extern_new_empty() to create a placeholder */
+        if (wasm_importtype_is_linked(importtype)) {
+            externs[i] = wasm_extern_new_empty(
+                store, wasm_externtype_kind(wasm_importtype_type(importtype)));
+            continue;
+        }
+
+        const wasm_name_t *module_name =
+            wasm_importtype_module(importtypes.data[i]);
+        const wasm_name_t *field_name =
+            wasm_importtype_name(importtypes.data[i]);
+
+        if (strncmp(module_name->data, "env", strlen("env")) == 0
+            && strncmp(field_name->data, "log", strlen("log")) == 0) {
+            wasm_functype_t *log_type = wasm_functype_new_2_0(
+                wasm_valtype_new_i64(), wasm_valtype_new_i32());
+            wasm_func_t *log_func = wasm_func_new(store, log_type, host_logs);
+            wasm_functype_delete(log_type);
+
+            externs[i] = wasm_func_as_extern(log_func);
+        }
+    }
+
+    wasm_extern_vec_new(out, importtypes.num_elems, externs);
+    wasm_importtype_vec_delete(&importtypes);
+    return true;
+}
+
+int
+main()
+{
+    int main_ret = EXIT_FAILURE;
+
+    // Initialize.
+    printf("Initializing...\n");
+    wasm_engine_t *engine = wasm_engine_new();
+    if (!engine)
+        goto quit;
+
+    wasm_store_t *store = wasm_store_new(engine);
+    if (!store)
+        goto delete_engine;
+
+    // Load binary.
+    printf("Loading binary...\n");
+#if WASM_ENABLE_AOT != 0 && WASM_ENABLE_INTERP == 0
+    FILE *file = fopen("send_recv.aot", "rb");
+    printf("> Load .aot\n");
+#else
+    FILE *file = fopen("send_recv.wasm", "rb");
+    printf("> Load .wasm\n");
+#endif
+    if (!file) {
+        printf("> Error loading module!\n");
+        goto delete_store;
+    }
+
+    int ret = fseek(file, 0L, SEEK_END);
+    if (ret == -1) {
+        printf("> Error loading module!\n");
+        goto close_file;
+    }
+
+    long file_size = ftell(file);
+    if (file_size == -1) {
+        printf("> Error loading module!\n");
+        goto close_file;
+    }
+
+    ret = fseek(file, 0L, SEEK_SET);
+    if (ret == -1) {
+        printf("> Error loading module!\n");
+        goto close_file;
+    }
+
+    wasm_byte_vec_t binary;
+    wasm_byte_vec_new_uninitialized(&binary, file_size);
+
+    if (fread(binary.data, file_size, 1, file) != 1) {
+        printf("> Error loading module!\n");
+        goto delete_binary;
+    }
+
+    // Compile.
+    printf("Compiling module...\n");
+    wasm_module_t *module = wasm_module_new(store, &binary);
+    if (!module) {
+        printf("> Error compiling module!\n");
+        goto delete_binary;
+    }
+
+    // Set Wasi Context
+    const char *addr_pool[1] = { "127.0.0.1" };
+    wasm_runtime_set_wasi_addr_pool(*module, addr_pool, 1);
+
+    // Instantiate.
+    printf("Instantiating module...\n");
+    wasm_extern_vec_t imports = { 0 };
+    ret = build_imports(store, module, &imports);
+    if (!ret) {
+        printf("> Error building imports!\n");
+        goto delete_module;
+    }
+
+    wasm_instance_t *instance =
+        wasm_instance_new(store, module, &imports, NULL);
+    if (!instance) {
+        printf("> Error instantiating module!\n");
+        goto delete_imports;
+    }
+
+    // Extract export.
+    printf("Extracting export...\n");
+    wasm_extern_vec_t exports;
+    wasm_instance_exports(instance, &exports);
+    if (exports.size == 0) {
+        printf("> Error accessing exports!\n");
+        goto delete_instance;
+    }
+
+    /**
+     * should use information from wasm_module_exports to avoid hard coding "1"
+     */
+    const wasm_func_t *start_func = wasm_extern_as_func(exports.data[1]);
+    if (start_func == NULL) {
+        printf("> Error accessing export!\n");
+        goto delete_exports;
+    }
+
+    // Call. "_start(nil) -> i32"
+    printf("Calling _start ...\n");
+    wasm_val_t rs[1] = { WASM_I32_VAL(0) };
+    wasm_val_vec_t args = WASM_EMPTY_VEC;
+    wasm_val_vec_t results = WASM_ARRAY_VEC(rs);
+    wasm_trap_t *trap = wasm_func_call(start_func, &args, &results);
+    if (trap) {
+        wasm_name_t message = { 0 };
+        wasm_trap_message(trap, &message);
+
+        printf("> Error calling function! %s\n", message.data);
+
+        wasm_name_delete(&message);
+        wasm_trap_delete(trap);
+        goto delete_exports;
+    }
+
+    // Print result.
+    printf("Printing result...\n");
+    printf("> %u\n", rs[0].of.i32);
+
+    // Shut down.
+    printf("Shutting down...\n");
+
+    // All done.
+    printf("Done.\n");
+    main_ret = EXIT_SUCCESS;
+
+delete_exports:
+    wasm_extern_vec_delete(&exports);
+delete_instance:
+    wasm_instance_delete(instance);
+delete_imports:
+    wasm_extern_vec_delete(&imports);
+delete_module:
+    wasm_module_delete(module);
+delete_binary:
+    wasm_byte_vec_delete(&binary);
+close_file:
+    fclose(file);
+delete_store:
+    wasm_store_delete(store);
+delete_engine:
+    wasm_engine_delete(engine);
+quit:
+    return main_ret;
+}

+ 47 - 0
samples/wasm-c-api-imports/wasm/CMakeLists.txt

@@ -0,0 +1,47 @@
+# Copyright (C) 2019 Intel Corporation.  All rights reserved.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+cmake_minimum_required (VERSION 3.14)
+project(wasm_modules)
+
+if(NOT SOCKET_WASI_CMAKE)
+  message(FATAL_ERROR "Require SOCKET_WASI_CMAKE")
+endif()
+
+option(WASM_TO_AOT "transfer wasm to aot" OFF)
+if(WASM_TO_AOT AND NOT WAMRC_PATH)
+  message(FATAL_ERROR "Require WAMRC_PATH when WASM_TO_AOT is ON")
+endif()
+
+#
+# c -> wasm
+include(${SOCKET_WASI_CMAKE})
+add_executable(send_recv ${CMAKE_CURRENT_LIST_DIR}/send_recv.c)
+set_target_properties(send_recv PROPERTIES SUFFIX .wasm)
+target_include_directories(send_recv PUBLIC ${CMAKE_CURRENT_LIST_DIR}/inc)
+target_link_libraries(send_recv socket_wasi_ext)
+target_link_options(send_recv PRIVATE
+  LINKER:--export=__heap_base
+  LINKER:--export=__data_end
+  LINKER:--shared-memory,--max-memory=196608
+  LINKER:--no-check-features
+  LINKER:--allow-undefined
+)
+
+if(WASM_TO_AOT)
+  # wasm -> aot
+  add_custom_target(send_recv_aot ALL
+    COMMAND pwd && ${WAMRC_PATH} --enable-multi-thread -o ./send_recv.aot ./send_recv.wasm
+    DEPENDS send_recv
+    WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+  )
+endif()
+
+#
+# install
+if(WASM_TO_AOT)
+  install(FILES ${CMAKE_CURRENT_BINARY_DIR}/send_recv.aot DESTINATION . )
+else()
+  install(FILES ${CMAKE_CURRENT_BINARY_DIR}/send_recv.wasm DESTINATION . )
+endif()
+

+ 0 - 0
samples/wasm-c-api-imports/wasm/inc/.gitkeep


+ 231 - 0
samples/wasm-c-api-imports/wasm/send_recv.c

@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2019 Intel Corporation.  All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#include <arpa/inet.h>
+#include <assert.h>
+#include <netinet/in.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#ifdef __wasi__
+#include <wasi_socket_ext.h>
+#include "pthread.h"
+#else
+#include <pthread.h>
+#endif
+
+static pthread_mutex_t lock = { 0 };
+static pthread_cond_t cond = { 0 };
+static bool server_is_ready = false;
+
+#ifdef __wasi__
+__attribute__((import_name("log"))) extern void
+host_log(uint64_t message, uint32_t length);
+#endif
+
+static void
+local_printf(const char *formatter, ...)
+{
+    char buffer[128] = { 0 };
+    va_list args;
+
+    va_start(args, formatter);
+    vsnprintf(buffer, 128, formatter, args);
+    va_end(args);
+
+#ifdef __wasi__
+    host_log((uint64_t)(void *)buffer, strlen(buffer));
+#endif
+    printf("--> %s", buffer);
+}
+
+void *
+run_as_server(void *arg)
+{
+    int sock = -1, on = 1;
+    struct sockaddr_in addr = { 0 };
+    int addrlen = 0;
+    int new_sock = -1;
+    char *buf[] = {
+        "The stars shine down", "It brings us light", "Light comes down",
+        "To make us paths",     "It watches us",      "And mourns for us",
+    };
+    struct iovec iov[] = {
+        { .iov_base = buf[0], .iov_len = strlen(buf[0]) + 1 },
+        { .iov_base = buf[1], .iov_len = strlen(buf[1]) + 1 },
+        { .iov_base = buf[2], .iov_len = strlen(buf[2]) + 1 },
+        { .iov_base = buf[3], .iov_len = strlen(buf[3]) + 1 },
+        { .iov_base = buf[4], .iov_len = strlen(buf[4]) + 1 },
+        { .iov_base = buf[5], .iov_len = strlen(buf[5]) + 1 },
+    };
+    struct msghdr msg = { .msg_iov = iov, .msg_iovlen = 6 };
+    ssize_t send_len = 0;
+
+    pthread_mutex_lock(&lock);
+    sock = socket(AF_INET, SOCK_STREAM, 0);
+    if (sock < 0) {
+        pthread_mutex_unlock(&lock);
+        perror("Create a socket failed");
+        return NULL;
+    }
+
+#ifndef __wasi__
+    if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on))) {
+        pthread_mutex_unlock(&lock);
+        perror("Setsockopt failed");
+        goto fail1;
+    }
+#endif
+
+    /* 0.0.0.0:1234 */
+    addr.sin_family = AF_INET;
+    addr.sin_port = htons(1234);
+    addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+    addrlen = sizeof(addr);
+    if (bind(sock, (struct sockaddr *)&addr, addrlen) < 0) {
+        pthread_mutex_unlock(&lock);
+        perror("Bind failed");
+        goto fail1;
+    }
+
+    if (listen(sock, 0) < 0) {
+        pthread_mutex_unlock(&lock);
+        perror("Listen failed");
+        goto fail1;
+    }
+
+    server_is_ready = true;
+    pthread_cond_signal(&cond);
+    pthread_mutex_unlock(&lock);
+
+    local_printf("Server is online ... \n");
+
+    new_sock = accept(sock, (struct sockaddr *)&addr, (socklen_t *)&addrlen);
+    if (new_sock < 0) {
+        perror("Accept failed");
+        goto fail1;
+    }
+
+    local_printf("Start sending. \n");
+    send_len = sendmsg(new_sock, &msg, 0);
+    if (send_len < 0) {
+        perror("Sendmsg failed");
+        goto fail2;
+    }
+    local_printf("Send %ld bytes successfully!\n", send_len);
+
+fail2:
+    close(new_sock);
+fail1:
+    shutdown(sock, SHUT_RD);
+    close(sock);
+    return NULL;
+}
+
+void *
+run_as_client(void *arg)
+{
+    int sock = -1;
+    struct sockaddr_in addr = { 0 };
+    /* buf of server is 106 bytes */
+    char buf[110] = { 0 };
+    struct iovec iov = { .iov_base = buf, .iov_len = sizeof(buf) };
+    struct msghdr msg = { .msg_iov = &iov, .msg_iovlen = 1 };
+    ssize_t recv_len = 0;
+
+    pthread_mutex_lock(&lock);
+    while (false == server_is_ready) {
+        pthread_cond_wait(&cond, &lock);
+    }
+    pthread_mutex_unlock(&lock);
+
+    local_printf("Client is running...\n");
+    sock = socket(AF_INET, SOCK_STREAM, 0);
+    if (sock < 0) {
+        perror("Create a socket failed");
+        return NULL;
+    }
+
+    /* 127.0.0.1:1234 */
+    addr.sin_family = AF_INET;
+    addr.sin_port = htons(1234);
+    addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+    if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+        perror("Connect failed");
+        goto fail;
+    }
+
+    local_printf("Start receiving. \n");
+    recv_len = recvmsg(sock, &msg, 0);
+    if (recv_len < 0) {
+        perror("Recvmsg failed");
+        goto fail;
+    }
+
+    local_printf("Receive %ld bytes successlly!\n", recv_len);
+    assert(recv_len == 106);
+
+    local_printf("Data:\n");
+    char *s = msg.msg_iov->iov_base;
+    while (strlen(s) > 0) {
+        local_printf("  %s\n", s);
+        s += strlen(s) + 1;
+    }
+
+fail:
+    shutdown(sock, SHUT_RD);
+    close(sock);
+    return NULL;
+}
+
+int
+main(int argc, char *argv[])
+{
+    pthread_t cs[2] = { 0 };
+    uint8_t i = 0;
+    int ret = EXIT_SUCCESS;
+
+    if (pthread_mutex_init(&lock, NULL)) {
+        perror("Initialize mutex failed");
+        ret = EXIT_FAILURE;
+        goto RETURN;
+    }
+
+    if (pthread_cond_init(&cond, NULL)) {
+        perror("Initialize condition failed");
+        ret = EXIT_FAILURE;
+        goto DESTROY_MUTEX;
+    }
+
+    if (pthread_create(&cs[0], NULL, run_as_server, NULL)) {
+        perror("Create a server thread failed");
+        ret = EXIT_FAILURE;
+        goto DESTROY_COND;
+    }
+
+    if (pthread_create(&cs[1], NULL, run_as_client, NULL)) {
+        perror("Create a client thread failed");
+        ret = EXIT_FAILURE;
+        goto DESTROY_COND;
+    }
+
+    for (i = 0; i < 2; i++) {
+        pthread_join(cs[i], NULL);
+    }
+
+DESTROY_COND:
+    pthread_cond_destroy(&cond);
+DESTROY_MUTEX:
+    pthread_mutex_destroy(&lock);
+RETURN:
+    return ret;
+}