From 260d36a62da58aa8d59fbad61db678d938ab529f Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Wed, 19 Jan 2022 11:25:08 +0800 Subject: [PATCH] Refactor externref related APIs of reference types feature (#971) Currently when calling wasm_runtime_call_wasm() to invoke wasm function with externref type argument from runtime embedder, developer needs to use wasm_externref_obj2ref() to convert externref obj into an internal ref index firstly, which is not convenient to developer. To align with GC feature in which all the references passed to wasm_runtime_call_wasm() can be object pointers directly, we change the interface of wasm_runtime_call_wasm() to allow to pass object pointer directly for the externref argument, and refactor the related codes, update the related samples and the document. --- core/iwasm/aot/aot_loader.c | 1 + core/iwasm/aot/aot_runtime.c | 10 +- core/iwasm/common/wasm_application.c | 110 +++- core/iwasm/common/wasm_c_api.c | 252 ++++---- core/iwasm/common/wasm_c_api_internal.h | 1 - core/iwasm/common/wasm_exec_env.h | 4 - core/iwasm/common/wasm_native.c | 39 +- core/iwasm/common/wasm_runtime_common.c | 598 +++++++++++++++--- core/iwasm/common/wasm_runtime_common.h | 15 - core/iwasm/compilation/aot.h | 1 + core/iwasm/compilation/aot_emit_aot_file.c | 1 + core/iwasm/include/wasm_export.h | 6 +- core/iwasm/interpreter/wasm.h | 13 + core/iwasm/interpreter/wasm_runtime.c | 19 +- .../platform/windows/platform_internal.h | 3 + doc/export_native_api.md | 3 +- doc/ref_types.md | 19 +- samples/ref-types/CMakeLists.txt | 2 +- samples/ref-types/src/hello.c | 240 +++++-- samples/ref-types/src/hello.wat | 48 +- samples/wasm-c-api/src/callback.c | 20 +- samples/wasm-c-api/src/callback_chain.c | 16 +- samples/wasm-c-api/src/global.c | 46 +- samples/wasm-c-api/src/hello.c | 10 +- samples/wasm-c-api/src/hostref.c | 122 ++-- samples/wasm-c-api/src/memory.c | 45 +- samples/wasm-c-api/src/multi.c | 41 +- samples/wasm-c-api/src/reflect.c | 19 +- samples/wasm-c-api/src/table.c | 28 +- samples/wasm-c-api/src/trap.c | 11 +- 30 files changed, 1148 insertions(+), 595 deletions(-) diff --git a/core/iwasm/aot/aot_loader.c b/core/iwasm/aot/aot_loader.c index f5dc8225..bac3b476 100644 --- a/core/iwasm/aot/aot_loader.c +++ b/core/iwasm/aot/aot_loader.c @@ -854,6 +854,7 @@ load_import_table_list(const uint8 **p_buf, const uint8 *buf_end, /* keep sync with aot_emit_table_info() aot_emit_aot_file */ for (i = 0; i < module->import_table_count; i++, import_table++) { + read_uint32(buf, buf_end, import_table->elem_type); read_uint32(buf, buf_end, import_table->table_init_size); read_uint32(buf, buf_end, import_table->table_max_size); read_uint32(buf, buf_end, possible_grow); diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index 26512e22..6a78e1dc 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -85,7 +85,7 @@ init_global_data(uint8 *global_data, uint8 type, WASMValue *initial_value) switch (type) { case VALUE_TYPE_I32: case VALUE_TYPE_F32: -#if WASM_ENABLE_REF_TYPES +#if WASM_ENABLE_REF_TYPES != 0 case VALUE_TYPE_FUNCREF: case VALUE_TYPE_EXTERNREF: #endif @@ -1572,16 +1572,8 @@ aot_create_exec_env_and_call_function(AOTModuleInstance *module_inst, } } -#if WASM_ENABLE_REF_TYPES != 0 - wasm_runtime_prepare_call_function(exec_env, func); -#endif - ret = aot_call_function(exec_env, func, argc, argv); -#if WASM_ENABLE_REF_TYPES != 0 - wasm_runtime_finalize_call_function(exec_env, func, ret, argv); -#endif - /* don't destroy the exec_env if it's searched from the cluster */ if (!existing_exec_env) wasm_exec_env_destroy(exec_env); diff --git a/core/iwasm/common/wasm_application.c b/core/iwasm/common/wasm_application.c index 3555c9aa..fcbeb30e 100644 --- a/core/iwasm/common/wasm_application.c +++ b/core/iwasm/common/wasm_application.c @@ -82,6 +82,7 @@ wasm_application_execute_main(WASMModuleInstanceCommon *module_inst, int32 argc, { WASMFunctionInstanceCommon *func; WASMType *func_type = NULL; + WASMExecEnv *exec_env = NULL; uint32 argc1 = 0, argv1[2] = { 0 }; uint32 total_argv_size = 0; uint64 total_size; @@ -91,14 +92,20 @@ wasm_application_execute_main(WASMModuleInstanceCommon *module_inst, int32 argc, uint32 *argv_offsets, module_type; bool ret, is_import_func = true; + exec_env = wasm_runtime_get_exec_env_singleton(module_inst); + if (!exec_env) { + wasm_runtime_set_exception(module_inst, + "create singleton exec_env failed"); + return false; + } + #if WASM_ENABLE_LIBC_WASI != 0 /* In wasi mode, we should call the function named "_start" which initializes the wasi envrionment and then calls the actual main function. Directly calling main function may cause exception thrown. */ if ((func = wasm_runtime_lookup_wasi_start_function(module_inst))) { - return wasm_runtime_create_exec_env_and_call_wasm(module_inst, func, 0, - NULL); + return wasm_runtime_call_wasm(exec_env, func, 0, NULL); } #endif /* end of WASM_ENABLE_LIBC_WASI */ @@ -179,8 +186,7 @@ wasm_application_execute_main(WASMModuleInstanceCommon *module_inst, int32 argc, (uint32)wasm_runtime_addr_native_to_app(module_inst, argv_offsets); } - ret = wasm_runtime_create_exec_env_and_call_wasm(module_inst, func, argc1, - argv1); + ret = wasm_runtime_call_wasm(exec_env, func, argc1, argv1); if (ret && func_type->result_count > 0 && argc > 0 && argv) /* copy the return value */ *(int *)argv = (int)argv1[0]; @@ -345,7 +351,11 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, WASMFunctionInstanceCommon *target_func; WASMModuleInstanceCommon *target_inst; WASMType *type = NULL; + WASMExecEnv *exec_env = NULL; uint32 argc1, *argv1 = NULL, cell_num = 0, j, k = 0; +#if WASM_ENABLE_REF_TYPES != 0 + uint32 param_size_in_double_world = 0, result_size_in_double_world = 0; +#endif int32 i, p, module_type; uint64 total_size; const char *exception; @@ -373,8 +383,23 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, goto fail; } +#if WASM_ENABLE_REF_TYPES != 0 + for (i = 0; i < type->param_count; i++) { + param_size_in_double_world += + wasm_value_type_cell_num_outside(type->types[i]); + } + for (i = 0; i < type->result_count; i++) { + result_size_in_double_world += wasm_value_type_cell_num_outside( + type->types[type->param_count + i]); + } + argc1 = param_size_in_double_world; + cell_num = (param_size_in_double_world >= result_size_in_double_world) + ? param_size_in_double_world + : result_size_in_double_world; +#else argc1 = type->param_cell_num; cell_num = (argc1 > type->ret_cell_num) ? argc1 : type->ret_cell_num; +#endif total_size = sizeof(uint32) * (uint64)(cell_num > 2 ? cell_num : 2); if ((!(argv1 = runtime_malloc((uint32)total_size, target_inst, NULL, 0)))) { @@ -487,9 +512,8 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, #if WASM_ENABLE_REF_TYPES != 0 case VALUE_TYPE_FUNCREF: { - if (strncmp(argv[i], "null", 4) == 0 - || strncmp(argv[i], "NULL", 4) == 0) { - argv1[p++] = NULL_REF; + if (strncasecmp(argv[i], "null", 4) == 0) { + argv1[p++] = (uint32)-1; } else { argv1[p++] = (uint32)strtoul(argv[i], &endptr, 0); @@ -498,23 +522,27 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, } case VALUE_TYPE_EXTERNREF: { - if (strncmp(argv[i], "null", 4) == 0 - || strncmp(argv[i], "NULL", 4) == 0) { - argv1[p++] = NULL_REF; +#if UINTPTR_MAX == UINT32_MAX + if (strncasecmp(argv[i], "null", 4) == 0) { + argv1[p++] = (uint32)-1; } else { - uint64 val = strtoull(argv[i], &endptr, 0); - void *extern_obj = (void *)(uintptr_t)val; - uint32 externref_idx; - - if (!wasm_externref_obj2ref(target_inst, extern_obj, - &externref_idx)) { - wasm_runtime_set_exception( - module_inst, "map extern object to ref failed"); - goto fail; - } - argv1[p++] = externref_idx; + argv1[p++] = strtoul(argv[i], &endptr, 0); } +#else + union { + uintptr_t val; + uint32 parts[2]; + } u; + if (strncasecmp(argv[i], "null", 4) == 0) { + u.val = (uintptr_t)-1LL; + } + else { + u.val = strtoull(argv[i], &endptr, 0); + } + argv1[p++] = u.parts[0]; + argv1[p++] = u.parts[1]; +#endif break; } #endif /* WASM_ENABLE_REF_TYPES */ @@ -529,11 +557,20 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, goto fail; } } - bh_assert(p == (int32)argc1); wasm_runtime_set_exception(module_inst, NULL); - if (!wasm_runtime_create_exec_env_and_call_wasm(target_inst, target_func, - argc1, argv1)) { +#if WASM_ENABLE_REF_TYPES == 0 + bh_assert(p == (int32)argc1); +#endif + + exec_env = wasm_runtime_get_exec_env_singleton(module_inst); + if (!exec_env) { + wasm_runtime_set_exception(module_inst, + "create singleton exec_env failed"); + goto fail; + } + + if (!wasm_runtime_call_wasm(exec_env, target_func, argc1, argv1)) { goto fail; } @@ -576,7 +613,7 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, os_printf("%.7g:f64", u.val); break; } -#if WASM_ENABLE_REF_TYPES +#if WASM_ENABLE_REF_TYPES != 0 case VALUE_TYPE_FUNCREF: { if (argv1[k] != NULL_REF) @@ -588,16 +625,25 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, } case VALUE_TYPE_EXTERNREF: { - if (argv1[k] != NULL_REF) { - void *extern_obj = NULL; - bool ret = wasm_externref_ref2obj(argv1[k], &extern_obj); - bh_assert(ret); - (void)ret; - os_printf("%p:ref.extern", extern_obj); - } +#if UINTPTR_MAX == UINT32_MAX + if (argv1[k] != 0 && argv1[k] != (uint32)-1) + os_printf("%p:ref.extern", (void *)argv1[k]); else os_printf("extern:ref.null"); k++; +#else + union { + uintptr_t val; + uint32 parts[2]; + } u; + u.parts[0] = argv1[k]; + u.parts[1] = argv1[k + 1]; + k += 2; + if (u.val && u.val != (uintptr_t)-1LL) + os_printf("%p:ref.extern", (void *)u.val); + else + os_printf("extern:ref.null"); +#endif break; } #endif diff --git a/core/iwasm/common/wasm_c_api.c b/core/iwasm/common/wasm_c_api.c index 9bffeb66..fb799de1 100644 --- a/core/iwasm/common/wasm_c_api.c +++ b/core/iwasm/common/wasm_c_api.c @@ -1235,9 +1235,8 @@ wasm_exporttype_type(const wasm_exporttype_t *export_type) void wasm_val_delete(wasm_val_t *v) { - if (v) { + if (v) wasm_runtime_free(v); - } } void @@ -1562,19 +1561,13 @@ wasm_trap_new_internal(WASMModuleInstanceCommon *inst_comm_rt, #if WASM_ENABLE_INTERP != 0 if (inst_comm_rt->module_type == Wasm_Module_Bytecode) { - if (!(error_info = - wasm_get_exception((WASMModuleInstance *)inst_comm_rt))) { - return NULL; - } + error_info = wasm_get_exception((WASMModuleInstance *)inst_comm_rt); } #endif #if WASM_ENABLE_AOT != 0 if (inst_comm_rt->module_type == Wasm_Module_AoT) { - if (!(error_info = - aot_get_exception((AOTModuleInstance *)inst_comm_rt))) { - return NULL; - } + error_info = aot_get_exception((AOTModuleInstance *)inst_comm_rt); } #endif @@ -2160,7 +2153,7 @@ wasm_module_imports(const wasm_module_t *module, own wasm_importtype_vec_t *out) - import_memory_count); module_name_rt = import->module_name; field_name_rt = import->table_name; - elem_type_rt = VALUE_TYPE_FUNCREF; + elem_type_rt = import->elem_type; min_size = import->table_init_size; max_size = import->table_max_size; } @@ -2563,151 +2556,127 @@ wasm_func_type(const wasm_func_t *func) return wasm_functype_copy(func->type); } -static uint32 -params_to_argv(WASMModuleInstanceCommon *inst_comm_rt, const wasm_val_t *params, - const wasm_valtype_vec_t *param_defs, size_t param_arity, - uint32 *out) +static bool +params_to_argv(const wasm_val_vec_t *params, + const wasm_valtype_vec_t *param_defs, uint32 *argv, + uint32 *ptr_argc) { size_t i = 0; - uint32 argc = 0; - const wasm_val_t *param = NULL; - if (!param_arity) { - return 0; + if (!param_defs->num_elems) { + return true; } - bh_assert(params && param_defs && out); - bh_assert(param_defs->num_elems == param_arity); + if (!params || !params->num_elems || !params->size || !params->data) { + return false; + } - for (i = 0; out && i < param_arity; ++i) { - param = params + i; + *ptr_argc = 0; + for (i = 0; i < param_defs->num_elems; ++i) { + const wasm_val_t *param = params->data + i; bh_assert((*(param_defs->data + i))->kind == param->kind); switch (param->kind) { case WASM_I32: - *(int32 *)out = param->of.i32; - out += 1; - argc += 1; + *(int32 *)argv = param->of.i32; + argv += 1; + *ptr_argc += 1; break; case WASM_I64: - *(int64 *)out = param->of.i64; - out += 2; - argc += 2; + *(int64 *)argv = param->of.i64; + argv += 2; + *ptr_argc += 2; break; case WASM_F32: - *(float32 *)out = param->of.f32; - out += 1; - argc += 1; + *(float32 *)argv = param->of.f32; + argv += 1; + *ptr_argc += 1; break; case WASM_F64: - *(float64 *)out = param->of.f64; - out += 2; - argc += 2; + *(float64 *)argv = param->of.f64; + argv += 2; + *ptr_argc += 2; break; #if WASM_ENABLE_REF_TYPES != 0 case WASM_ANYREF: - if (!wasm_externref_obj2ref(inst_comm_rt, param->of.ref, out)) { - goto failed; - } - - out += 1; - argc += 1; + *(uintptr_t *)argv = (uintptr_t)param->of.ref; + argv += sizeof(uintptr_t) / sizeof(uint32); + *ptr_argc += 1; break; #endif default: LOG_WARNING("unexpected parameter val type %d", param->kind); - goto failed; + return false; } } - return argc; - -failed: - LOG_DEBUG("%s failed", __FUNCTION__); - return 0; + return true; } -static uint32 -argv_to_results(const uint32 *results, const wasm_valtype_vec_t *result_defs, - size_t result_arity, wasm_val_t *out) +static bool +argv_to_results(const uint32 *argv, const wasm_valtype_vec_t *result_defs, + wasm_val_vec_t *results) { - size_t i = 0; - uint32 argc = 0; - const uint32 *result = results; - const wasm_valtype_t *def = NULL; + size_t i = 0, argv_i = 0; + wasm_val_t *result; - if (!result_arity) { - return 0; + if (!result_defs->num_elems) { + return true; } - bh_assert(results && result_defs && out); - bh_assert(result_arity == result_defs->num_elems); + if (!results || !results->num_elems || !results->size || !results->data) { + return false; + } - for (i = 0; out && i < result_arity; i++) { - def = *(result_defs->data + i); - - switch (def->kind) { + for (i = 0, result = results->data, argv_i = 0; i < result_defs->num_elems; + i++, result++) { + switch (result_defs->data[i]->kind) { case WASM_I32: { - out->kind = WASM_I32; - out->of.i32 = *(int32 *)result; - result += 1; + result->kind = WASM_I32; + result->of.i32 = *(int32 *)(argv + argv_i); + argv_i += 1; break; } case WASM_I64: { - out->kind = WASM_I64; - out->of.i64 = *(int64 *)result; - result += 2; + result->kind = WASM_I64; + result->of.i64 = *(int64 *)(argv + argv_i); + argv_i += 2; break; } case WASM_F32: { - out->kind = WASM_F32; - out->of.f32 = *(float32 *)result; - result += 1; + result->kind = WASM_F32; + result->of.f32 = *(float32 *)(argv + argv_i); + argv_i += 1; break; } case WASM_F64: { - out->kind = WASM_F64; - out->of.f64 = *(float64 *)result; - result += 2; + result->kind = WASM_F64; + result->of.f64 = *(float64 *)(argv + argv_i); + argv_i += 2; break; } #if WASM_ENABLE_REF_TYPES != 0 case WASM_ANYREF: { - out->kind = WASM_ANYREF; - - if (NULL_REF == *(uint32 *)result) { - out->of.ref = NULL; - } - else { - if (!wasm_externref_ref2obj(*(uint32 *)result, - (void **)&out->of.ref)) { - goto failed; - } - } - - result += 1; + result->kind = WASM_ANYREF; + result->of.ref = + (struct wasm_ref_t *)(*(uintptr_t *)(argv + argv_i)); + argv_i += sizeof(uintptr_t) / sizeof(uint32); break; } #endif default: LOG_WARNING("%s meets unsupported type: %d", __FUNCTION__, - def->kind); - goto failed; + result_defs->data[i]->kind); + return false; } - out++; - argc++; } - return argc; - -failed: - LOG_DEBUG("%s failed", __FUNCTION__); - return 0; + return true; } wasm_trap_t * @@ -2718,7 +2687,7 @@ wasm_func_call(const wasm_func_t *func, const wasm_val_vec_t *params, /* a int64 or float64 parameter means 2 */ uint32 argc = 0; /* a parameter list and a return value list */ - uint32 argv_buf[32], *argv = argv_buf; + uint32 argv_buf[32] = { 0 }, *argv = argv_buf; WASMFunctionInstanceCommon *func_comm_rt = NULL; WASMExecEnv *exec_env = NULL; size_t param_count, result_count, alloc_count; @@ -2776,10 +2745,8 @@ wasm_func_call(const wasm_func_t *func, const wasm_val_vec_t *params, /* copy parametes */ if (param_count - && (!params - || !(argc = params_to_argv(func->inst_comm_rt, params->data, - wasm_functype_params(func->type), - param_count, argv)))) { + && !params_to_argv(params, wasm_functype_params(func->type), argv, + &argc)) { goto failed; } @@ -2798,9 +2765,8 @@ wasm_func_call(const wasm_func_t *func, const wasm_val_vec_t *params, /* copy results */ if (result_count) { - if (!results - || !(argc = argv_to_results(argv, wasm_functype_results(func->type), - result_count, results->data))) { + if (!argv_to_results(argv, wasm_functype_results(func->type), + results)) { goto failed; } results->num_elems = result_count; @@ -3265,7 +3231,7 @@ wasm_table_new_internal(wasm_store_t *store, uint16 table_idx_rt, if (table_idx_rt < module_aot->import_table_count) { AOTImportTable *table_aot = module_aot->import_tables + table_idx_rt; - val_type_rt = VALUE_TYPE_FUNCREF; + val_type_rt = table_aot->elem_type; init_size = table_aot->table_init_size; max_size = table_aot->table_max_size; } @@ -3273,7 +3239,7 @@ wasm_table_new_internal(wasm_store_t *store, uint16 table_idx_rt, AOTTable *table_aot = module_aot->tables + (table_idx_rt - module_aot->import_table_count); - val_type_rt = VALUE_TYPE_FUNCREF; + val_type_rt = table_aot->elem_type; init_size = table_aot->table_init_size; max_size = table_aot->table_max_size; } @@ -3360,13 +3326,12 @@ wasm_table_type(const wasm_table_t *table) own wasm_ref_t * wasm_table_get(const wasm_table_t *table, wasm_table_size_t index) { - uint32 func_idx_rt = NULL_REF; + uint32 ref_idx = NULL_REF; if (!table) { return NULL; } - /* index -> func_idx_rt */ #if WASM_ENABLE_INTERP != 0 if (table->inst_comm_rt->module_type == Wasm_Module_Bytecode) { WASMTableInstance *table_interp = @@ -3375,7 +3340,7 @@ wasm_table_get(const wasm_table_t *table, wasm_table_size_t index) if (index >= table_interp->cur_size) { return NULL; } - func_idx_rt = ((uint32 *)table_interp->base_addr)[index]; + ref_idx = ((uint32 *)table_interp->base_addr)[index]; } #endif @@ -3387,7 +3352,7 @@ wasm_table_get(const wasm_table_t *table, wasm_table_size_t index) if (index >= table_aot->cur_size) { return NULL; } - func_idx_rt = table_aot->data[index]; + ref_idx = table_aot->data[index]; } #endif @@ -3395,35 +3360,48 @@ wasm_table_get(const wasm_table_t *table, wasm_table_size_t index) * a wrong combination of module filetype and compilation flags * also leads to below branch */ - if (func_idx_rt == NULL_REF) { + if (ref_idx == NULL_REF) { return NULL; } - return wasm_ref_new_internal(table->store, WASM_REF_func, func_idx_rt, - table->inst_comm_rt); +#if WASM_ENABLE_REF_TYPES != 0 + if (table->type->val_type->kind == WASM_ANYREF) { + void *externref_obj; + if (!wasm_externref_ref2obj(ref_idx, &externref_obj)) { + return NULL; + } + + return externref_obj; + } + else +#endif + { + return wasm_ref_new_internal(table->store, WASM_REF_func, ref_idx, + table->inst_comm_rt); + } } bool wasm_table_set(wasm_table_t *table, wasm_table_size_t index, - own wasm_ref_t *func_ref) + own wasm_ref_t *ref) { - uint32 *p_func_idx_rt = NULL; - uint32 function_count = 0, ref_idx_rt = NULL_REF; + uint32 *p_ref_idx = NULL; + uint32 function_count = 0; if (!table) { return false; } - if (func_ref && func_ref->kind != WASM_REF_func) { + if (ref +#if WASM_ENABLE_REF_TYPES != 0 + && !(WASM_REF_foreign == ref->kind + && WASM_ANYREF == table->type->val_type->kind) +#endif + && !(WASM_REF_func == ref->kind + && WASM_FUNCREF == table->type->val_type->kind)) { return false; } - if (func_ref) { - ref_idx_rt = func_ref->ref_idx_rt; - wasm_ref_delete(func_ref); - } - - /* index -> *p_func_idx_rt */ #if WASM_ENABLE_INTERP != 0 if (table->inst_comm_rt->module_type == Wasm_Module_Bytecode) { WASMTableInstance *table_interp = @@ -3434,7 +3412,7 @@ wasm_table_set(wasm_table_t *table, wasm_table_size_t index, return false; } - p_func_idx_rt = ((uint32 *)table_interp->base_addr) + index; + p_ref_idx = ((uint32 *)table_interp->base_addr) + index; function_count = ((WASMModuleInstance *)table->inst_comm_rt)->function_count; } @@ -3451,7 +3429,7 @@ wasm_table_set(wasm_table_t *table, wasm_table_size_t index, return false; } - p_func_idx_rt = table_aot->data + index; + p_ref_idx = table_aot->data + index; function_count = module_aot->func_count; } #endif @@ -3460,17 +3438,31 @@ wasm_table_set(wasm_table_t *table, wasm_table_size_t index, * a wrong combination of module filetype and compilation flags * leads to below branch */ - if (!p_func_idx_rt) { + if (!p_ref_idx) { return false; } - if (NULL_REF != ref_idx_rt) { - if (ref_idx_rt >= function_count) { - return false; +#if WASM_ENABLE_REF_TYPES != 0 + if (table->type->val_type->kind == WASM_ANYREF) { + return wasm_externref_obj2ref(table->inst_comm_rt, ref, p_ref_idx); + } + else +#endif + { + if (ref) { + if (NULL_REF != ref->ref_idx_rt) { + if (ref->ref_idx_rt >= function_count) { + return false; + } + } + *p_ref_idx = ref->ref_idx_rt; + wasm_ref_delete(ref); + } + else { + *p_ref_idx = NULL_REF; } } - *p_func_idx_rt = ref_idx_rt; return true; } diff --git a/core/iwasm/common/wasm_c_api_internal.h b/core/iwasm/common/wasm_c_api_internal.h index 919d1524..d80bd0d6 100644 --- a/core/iwasm/common/wasm_c_api_internal.h +++ b/core/iwasm/common/wasm_c_api_internal.h @@ -56,7 +56,6 @@ struct wasm_globaltype_t { struct wasm_tabletype_t { uint32 extern_kind; - /* always be WASM_FUNCREF */ wasm_valtype_t *val_type; wasm_limits_t limits; }; diff --git a/core/iwasm/common/wasm_exec_env.h b/core/iwasm/common/wasm_exec_env.h index 86ad1c3e..b3e2a052 100644 --- a/core/iwasm/common/wasm_exec_env.h +++ b/core/iwasm/common/wasm_exec_env.h @@ -125,10 +125,6 @@ typedef struct WASMExecEnv { WASMJmpBuf *jmpbuf_stack_top; #endif -#if WASM_ENABLE_REF_TYPES != 0 - uint16 nested_calling_depth; -#endif - #if WASM_ENABLE_MEMORY_PROFILING != 0 uint32 max_wasm_stack_used; #endif diff --git a/core/iwasm/common/wasm_native.c b/core/iwasm/common/wasm_native.c index 15cb0e5c..bbef1def 100644 --- a/core/iwasm/common/wasm_native.c +++ b/core/iwasm/common/wasm_native.c @@ -53,11 +53,30 @@ get_lib_pthread_export_apis(NativeSymbol **p_lib_pthread_apis); uint32 get_libc_emcc_export_apis(NativeSymbol **p_libc_emcc_apis); +static bool +compare_type_with_signautre(uint8 type, const char signature) +{ + const char num_sig_map[] = { 'F', 'f', 'I', 'i' }; + + if (VALUE_TYPE_F64 <= type && type <= VALUE_TYPE_I32 + && signature == num_sig_map[type - VALUE_TYPE_F64]) { + return true; + } + +#if WASM_ENABLE_REF_TYPES != 0 + if ('r' == signature && type == VALUE_TYPE_EXTERNREF) + return true; +#endif + + /* TODO: a v128 parameter */ + return false; +} + static bool check_symbol_signature(const WASMType *type, const char *signature) { const char *p = signature, *p_end; - char sig_map[] = { 'F', 'f', 'I', 'i' }, sig; + char sig; uint32 i = 0; if (!p || strlen(p) < 2) @@ -74,16 +93,12 @@ check_symbol_signature(const WASMType *type, const char *signature) for (i = 0; i < type->param_count; i++) { sig = *p++; - if ((type->types[i] >= VALUE_TYPE_F64 - && type->types[i] <= VALUE_TYPE_I32 - && sig == sig_map[type->types[i] - VALUE_TYPE_F64]) -#if WASM_ENABLE_REF_TYPES != 0 - || (sig == 'i' && type->types[i] == VALUE_TYPE_EXTERNREF) -#endif - ) - /* normal parameter */ + + /* a f64/f32/i64/i32/externref parameter */ + if (compare_type_with_signautre(type->types[i], sig)) continue; + /* a pointer/string paramter */ if (type->types[i] != VALUE_TYPE_I32) /* pointer and string must be i32 type */ return false; @@ -112,8 +127,12 @@ check_symbol_signature(const WASMType *type, const char *signature) if (type->result_count) { if (p >= p_end) return false; - if (*p++ != sig_map[type->types[i] - VALUE_TYPE_F64]) + + /* result types includes: f64,f32,i64,i32,externref */ + if (!compare_type_with_signautre(type->types[i], *p)) return false; + + p++; } if (*p != '\0') diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index be13d05c..79668cc1 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -1199,46 +1199,163 @@ wasm_runtime_lookup_function(WASMModuleInstanceCommon *const module_inst, } #if WASM_ENABLE_REF_TYPES != 0 -static void -wasm_runtime_reclaim_externref(WASMExecEnv *exec_env, - WASMFunctionInstanceCommon *function, - uint32 *argv) +/* (uintptr_t)externref -> (uint32_t)index */ +/* argv -> *ret_argv */ +static bool +wasm_runtime_prepare_call_function(WASMExecEnv *exec_env, + WASMFunctionInstanceCommon *function, + uint32 *argv, uint32 argc, uint32 **ret_argv, + uint32 *ret_argc_param, + uint32 *ret_argc_result) { - uint32 i = 0, cell_num = 0; + uint32 *new_argv = NULL, argv_i = 0, new_argv_i = 0, param_i = 0, + result_i = 0; + bool need_param_transform = false, need_result_transform = false; + uint64 size = 0; WASMType *func_type = wasm_runtime_get_function_type( function, exec_env->module_inst->module_type); + + bh_assert(func_type); + + *ret_argc_param = func_type->param_cell_num; + *ret_argc_result = func_type->ret_cell_num; + for (param_i = 0; param_i < func_type->param_count; param_i++) { + if (VALUE_TYPE_EXTERNREF == func_type->types[param_i]) { + need_param_transform = true; + } + } + + for (result_i = 0; result_i < func_type->result_count; result_i++) { + if (VALUE_TYPE_EXTERNREF + == func_type->types[func_type->param_count + result_i]) { + need_result_transform = true; + } + } + + if (!need_param_transform && !need_result_transform) { + *ret_argv = argv; + return true; + } + + if (func_type->param_cell_num >= func_type->ret_cell_num) { + size = sizeof(uint32) * func_type->param_cell_num; + } + else { + size = sizeof(uint32) * func_type->ret_cell_num; + } + + if (!(new_argv = runtime_malloc(size, exec_env->module_inst, NULL, 0))) { + return false; + } + + if (!need_param_transform) { + bh_memcpy_s(new_argv, size, argv, size); + } + else { + for (param_i = 0; param_i < func_type->param_count && argv_i < argc + && new_argv_i < func_type->param_cell_num; + param_i++) { + uint8 param_type = func_type->types[param_i]; + if (VALUE_TYPE_EXTERNREF == param_type) { + void *externref_obj; + uint32 externref_index; + +#if UINTPTR_MAX == UINT32_MAX + externref_obj = (void *)argv[argv_i]; +#else + union { + uintptr_t val; + uint32 parts[2]; + } u; + + u.parts[0] = argv[argv_i]; + u.parts[1] = argv[argv_i + 1]; + externref_obj = (void *)u.val; +#endif + if (!wasm_externref_obj2ref(exec_env->module_inst, + externref_obj, &externref_index)) { + wasm_runtime_free(new_argv); + return false; + } + + new_argv[new_argv_i] = externref_index; + argv_i += sizeof(uintptr_t) / sizeof(uint32); + new_argv_i++; + } + else { + uint16 param_cell_num = wasm_value_type_cell_num(param_type); + uint32 param_size = sizeof(uint32) * param_cell_num; + bh_memcpy_s(new_argv + new_argv_i, param_size, argv + argv_i, + param_size); + argv_i += param_cell_num; + new_argv_i += param_cell_num; + } + } + } + + *ret_argv = new_argv; + return true; +} + +/* (uintptr_t)externref <- (uint32_t)index */ +/* argv <- new_argv */ +static bool +wasm_runtime_finalize_call_function(WASMExecEnv *exec_env, + WASMFunctionInstanceCommon *function, + uint32 *argv, uint32 argc, uint32 *ret_argv) +{ + uint32 argv_i = 0, result_i = 0, ret_argv_i = 0; + WASMType *func_type; + + bh_assert(argv && ret_argv); + + if (argv == ret_argv) { + return true; + } + + func_type = wasm_runtime_get_function_type( + function, exec_env->module_inst->module_type); bh_assert(func_type); - while (i < func_type->result_count) { - uint8 result_type = func_type->types[func_type->param_count + i]; - if (result_type == VALUE_TYPE_EXTERNREF && argv[i] != NULL_REF) { - /* Retain the externref returned to runtime embedder */ - (void)wasm_externref_retain(argv[i]); + for (result_i = 0; result_i < func_type->result_count && argv_i < argc; + result_i++) { + uint8 result_type = func_type->types[func_type->param_count + result_i]; + if (result_type == VALUE_TYPE_EXTERNREF) { + void *externref_obj; +#if UINTPTR_MAX != UINT32_MAX + union { + uintptr_t val; + uint32 parts[2]; + } u; +#endif + + if (!wasm_externref_ref2obj(argv[argv_i], &externref_obj)) { + wasm_runtime_free(argv); + return false; + } + +#if UINTPTR_MAX == UINT32_MAX + ret_argv[ret_argv_i] = (uintptr_t)externref_obj; +#else + u.val = (uintptr_t)externref_obj; + ret_argv[ret_argv_i] = u.parts[0]; + ret_argv[ret_argv_i + 1] = u.parts[1]; +#endif + argv_i += 1; + ret_argv_i += sizeof(uintptr_t) / sizeof(uint32); + } + else { + uint16 result_cell_num = wasm_value_type_cell_num(result_type); + uint32 result_size = sizeof(uint32) * result_cell_num; + bh_memcpy_s(ret_argv + ret_argv_i, result_size, argv + argv_i, + result_size); + argv_i += result_cell_num; + ret_argv_i += result_cell_num; } - - cell_num += wasm_value_type_cell_num(result_type); - i++; } - wasm_externref_reclaim(exec_env->module_inst); -} - -void -wasm_runtime_prepare_call_function(WASMExecEnv *exec_env, - WASMFunctionInstanceCommon *function) -{ - exec_env->nested_calling_depth++; -} - -void -wasm_runtime_finalize_call_function(WASMExecEnv *exec_env, - WASMFunctionInstanceCommon *function, - bool ret, uint32 *argv) -{ - exec_env->nested_calling_depth--; - if (!exec_env->nested_calling_depth && ret) { - wasm_runtime_reclaim_externref(exec_env, function, argv); - } + wasm_runtime_free(argv); + return true; } #endif @@ -1248,6 +1365,10 @@ wasm_runtime_call_wasm(WASMExecEnv *exec_env, uint32 argv[]) { bool ret = false; + uint32 *new_argv = NULL, param_argc; +#if WASM_ENABLE_REF_TYPES != 0 + uint32 result_argc = 0; +#endif if (!wasm_runtime_exec_env_check(exec_env)) { LOG_ERROR("Invalid exec env stack info."); @@ -1255,34 +1376,53 @@ wasm_runtime_call_wasm(WASMExecEnv *exec_env, } #if WASM_ENABLE_REF_TYPES != 0 - wasm_runtime_prepare_call_function(exec_env, function); + if (!wasm_runtime_prepare_call_function(exec_env, function, argv, argc, + &new_argv, ¶m_argc, + &result_argc)) { + wasm_runtime_set_exception(exec_env->module_inst, + "the arguments conversion is failed"); + return false; + } +#else + new_argv = argv; + param_argc = argc; #endif #if WASM_ENABLE_INTERP != 0 if (exec_env->module_inst->module_type == Wasm_Module_Bytecode) ret = wasm_call_function(exec_env, (WASMFunctionInstance *)function, - argc, argv); + param_argc, new_argv); #endif #if WASM_ENABLE_AOT != 0 if (exec_env->module_inst->module_type == Wasm_Module_AoT) - ret = aot_call_function(exec_env, (AOTFunctionInstance *)function, argc, - argv); + ret = aot_call_function(exec_env, (AOTFunctionInstance *)function, + param_argc, new_argv); #endif + if (!ret) { + if (new_argv != argv) { + wasm_runtime_free(new_argv); + } + return false; + } #if WASM_ENABLE_REF_TYPES != 0 - wasm_runtime_finalize_call_function(exec_env, function, ret, argv); + if (!wasm_runtime_finalize_call_function(exec_env, function, new_argv, + result_argc, argv)) { + wasm_runtime_set_exception(exec_env->module_inst, + "the result conversion is failed"); + return false; + } #endif return ret; } -static uint32 -parse_args_to_uint32_array(WASMType *type, uint32 num_args, wasm_val_t *args, - uint32 *out_argv) +static void +parse_args_to_uint32_array(WASMType *type, wasm_val_t *args, uint32 *out_argv) { uint32 i, p; - for (i = 0, p = 0; i < num_args; i++) { + for (i = 0, p = 0; i < type->param_count; i++) { switch (args[i].kind) { case WASM_I32: out_argv[p++] = args[i].of.i32; @@ -1319,16 +1459,38 @@ parse_args_to_uint32_array(WASMType *type, uint32 num_args, wasm_val_t *args, out_argv[p++] = u.parts[1]; break; } +#if WASM_ENABLE_REF_TYPES != 0 + case WASM_FUNCREF: + { + out_argv[p++] = args[i].of.i32; + break; + } + case WASM_ANYREF: + { +#if UINTPTR_MAX == UINT32_MAX + out_argv[p++] = args[i].of.foreign; +#else + union { + uintptr_t val; + uint32 parts[2]; + } u; + + u.val = (uintptr_t)args[i].of.foreign; + out_argv[p++] = u.parts[0]; + out_argv[p++] = u.parts[1]; +#endif + break; + } +#endif default: bh_assert(0); break; } } - return p; } -static uint32 -parse_uint32_array_to_results(WASMType *type, uint32 argc, uint32 *argv, +static void +parse_uint32_array_to_results(WASMType *type, uint32 *argv, wasm_val_t *out_results) { uint32 i, p; @@ -1374,13 +1536,36 @@ parse_uint32_array_to_results(WASMType *type, uint32 argc, uint32 *argv, out_results[i].of.f64 = u.val; break; } +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_FUNCREF: + { + out_results[i].kind = WASM_I32; + out_results[i].of.i32 = (int32)argv[p++]; + break; + } + case VALUE_TYPE_EXTERNREF: + { +#if UINTPTR_MAX == UINT32_MAX + out_results[i].kind = WASM_ANYREF; + out_results[i].of.foreign = (uintptr_t)argv[p++]; +#else + union { + uintptr_t val; + uint32 parts[2]; + } u; + u.parts[0] = argv[p++]; + u.parts[1] = argv[p++]; + out_results[i].kind = WASM_ANYREF; + out_results[i].of.foreign = u.val; +#endif + break; + } +#endif default: bh_assert(0); break; } } - bh_assert(argc == p); - return type->result_count; } bool @@ -1389,7 +1574,10 @@ wasm_runtime_call_wasm_a(WASMExecEnv *exec_env, uint32 num_results, wasm_val_t results[], uint32 num_args, wasm_val_t args[]) { - uint32 argc, *argv, ret_num, cell_num, total_size, module_type; + uint32 argc, *argv, cell_num, total_size, module_type; +#if WASM_ENABLE_REF_TYPES != 0 + uint32 i, param_size_in_double_world = 0, result_size_in_double_world = 0; +#endif WASMType *type; bool ret = false; @@ -1402,8 +1590,23 @@ wasm_runtime_call_wasm_a(WASMExecEnv *exec_env, goto fail1; } +#if WASM_ENABLE_REF_TYPES != 0 + for (i = 0; i < type->param_count; i++) { + param_size_in_double_world += + wasm_value_type_cell_num_outside(type->types[i]); + } + for (i = 0; i < type->result_count; i++) { + result_size_in_double_world += wasm_value_type_cell_num_outside( + type->types[type->param_count + i]); + } + argc = param_size_in_double_world; + cell_num = (argc >= result_size_in_double_world) + ? argc + : result_size_in_double_world; +#else argc = type->param_cell_num; cell_num = (argc > type->ret_cell_num) ? argc : type->ret_cell_num; +#endif if (num_results != type->result_count) { LOG_ERROR( @@ -1425,14 +1628,11 @@ wasm_runtime_call_wasm_a(WASMExecEnv *exec_env, goto fail1; } - argc = parse_args_to_uint32_array(type, num_args, args, argv); - if (!(ret = wasm_runtime_call_wasm(exec_env, function, argc, argv))) + parse_args_to_uint32_array(type, args, argv); + if (!(ret = wasm_runtime_call_wasm(exec_env, function, num_args, argv))) goto fail2; - ret_num = - parse_uint32_array_to_results(type, type->ret_cell_num, argv, results); - bh_assert(ret_num == num_results); - (void)ret_num; + parse_uint32_array_to_results(type, argv, results); fail2: wasm_runtime_free(argv); @@ -1492,6 +1692,20 @@ wasm_runtime_call_wasm_v(WASMExecEnv *exec_env, args[i].kind = WASM_F64; args[i].of.f64 = va_arg(vargs, float64); break; +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_FUNCREF: + { + args[i].kind = WASM_FUNCREF; + args[i].of.i32 = va_arg(vargs, uint32); + break; + } + case VALUE_TYPE_EXTERNREF: + { + args[i].kind = WASM_ANYREF; + args[i].of.foreign = va_arg(vargs, uintptr_t); + break; + } +#endif default: bh_assert(0); break; @@ -1547,13 +1761,21 @@ WASMExecEnv * wasm_runtime_get_exec_env_singleton(WASMModuleInstanceCommon *module_inst) { #if WASM_ENABLE_INTERP != 0 - if (module_inst->module_type == Wasm_Module_Bytecode) + if (module_inst->module_type == Wasm_Module_Bytecode) { + if (!((WASMModuleInstance *)module_inst)->exec_env_singleton) { + wasm_create_exec_env_singleton((WASMModuleInstance *)module_inst); + } return ((WASMModuleInstance *)module_inst)->exec_env_singleton; + } #endif #if WASM_ENABLE_AOT != 0 - if (module_inst->module_type == Wasm_Module_AoT) + if (module_inst->module_type == Wasm_Module_AoT) { + if (!((AOTModuleInstance *)module_inst)->exec_env_singleton.ptr) { + aot_create_exec_env_singleton((AOTModuleInstance *)module_inst); + } return (WASMExecEnv *)((AOTModuleInstance *)module_inst) ->exec_env_singleton.ptr; + } #endif return NULL; } @@ -2497,6 +2719,9 @@ wasm_runtime_invoke_native_raw(WASMExecEnv *exec_env, void *func_ptr, for (i = 0; i < func_type->param_count; i++, argv_dst++) { switch (func_type->types[i]) { case VALUE_TYPE_I32: +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_FUNCREF: +#endif { *(uint32 *)argv_dst = arg_i32 = *argv_src++; if (signature) { @@ -2540,10 +2765,19 @@ wasm_runtime_invoke_native_raw(WASMExecEnv *exec_env, void *func_ptr, *(float32 *)argv_dst = *(float32 *)argv_src++; break; #if WASM_ENABLE_REF_TYPES != 0 - case VALUE_TYPE_FUNCREF: case VALUE_TYPE_EXTERNREF: - *(uint32 *)argv_dst = *argv_src++; + { + uint32 externref_idx = *argv_src++; + + void *externref_obj; + + if (!wasm_externref_ref2obj(externref_idx, &externref_obj)) + goto fail; + + bh_memcpy_s(argv_dst, sizeof(uintptr_t), argv_src, + sizeof(uintptr_t)); break; + } #endif default: bh_assert(0); @@ -2560,7 +2794,6 @@ wasm_runtime_invoke_native_raw(WASMExecEnv *exec_env, void *func_ptr, case VALUE_TYPE_I32: #if WASM_ENABLE_REF_TYPES != 0 case VALUE_TYPE_FUNCREF: - case VALUE_TYPE_EXTERNREF: #endif argv_ret[0] = *(uint32 *)argv1; break; @@ -2572,6 +2805,23 @@ wasm_runtime_invoke_native_raw(WASMExecEnv *exec_env, void *func_ptr, bh_memcpy_s(argv_ret, sizeof(uint32) * 2, argv1, sizeof(uint64)); break; +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_EXTERNREF: + { + uint32 externref_idx; + uint64 externref_obj; + + bh_memcpy_s(&externref_obj, sizeof(uint64), argv1, + sizeof(uint64)); + + if (!wasm_externref_obj2ref(exec_env->module_inst, + (void *)(uintptr_t)externref_obj, + &externref_idx)) + goto fail; + argv_ret[0] = externref_idx; + break; + } +#endif default: bh_assert(0); break; @@ -2634,6 +2884,9 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, uint32 result_count = func_type->result_count; uint32 ext_ret_count = result_count > 1 ? result_count - 1 : 0; bool ret = false; +#if WASM_ENABLE_REF_TYPES != 0 + bool is_aot_func = (NULL == signature); +#endif #if !defined(BUILD_TARGET_RISCV32_ILP32) && !defined(BUILD_TARGET_ARC) uint32 *fps; int n_fps = 0; @@ -2792,6 +3045,9 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, for (i = 0; i < func_type->param_count; i++) { switch (func_type->types[i]) { case VALUE_TYPE_I32: +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_FUNCREF: +#endif { arg_i32 = *argv_src++; @@ -2829,17 +3085,6 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, stacks[n_stacks++] = arg_i32; break; } -#if WASM_ENABLE_REF_TYPES != 0 - case VALUE_TYPE_FUNCREF: - case VALUE_TYPE_EXTERNREF: - { - if (n_ints < MAX_REG_INTS) - ints[n_ints++] = *argv_src++; - else - stacks[n_stacks++] = *argv_src++; - break; - } -#endif case VALUE_TYPE_I64: { if (n_ints < MAX_REG_INTS - 1) { @@ -2959,6 +3204,31 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, break; } #endif /* BUILD_TARGET_RISCV32_ILP32D */ +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_EXTERNREF: + { + uint32 externref_idx = *argv_src++; + + if (is_aot_func) { + if (n_ints < MAX_REG_INTS) + ints[n_ints++] = externref_idx; + else + stacks[n_stacks++] = externref_idx; + } + else { + void *externref_obj; + + if (!wasm_externref_ref2obj(externref_idx, &externref_obj)) + goto fail; + + if (n_ints < MAX_REG_INTS) + ints[n_ints++] = (uintptr_t)externref_obj; + else + stacks[n_stacks++] = (uintptr_t)externref_obj; + } + break; + } +#endif default: bh_assert(0); break; @@ -2982,7 +3252,6 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, case VALUE_TYPE_I32: #if WASM_ENABLE_REF_TYPES != 0 case VALUE_TYPE_FUNCREF: - case VALUE_TYPE_EXTERNREF: #endif argv_ret[0] = (uint32)invokeNative_Int32(func_ptr, argv1, n_stacks); @@ -2999,6 +3268,30 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, PUT_F64_TO_ADDR( argv_ret, invokeNative_Float64(func_ptr, argv1, n_stacks)); break; +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_EXTERNREF: + { + if (is_aot_func) { + uint32 externref_idx = + (uint32)invokeNative_Int32(func_ptr, argv1, argc1); + argv_ret[0] = externref_idx; + } + else { + uint32 externref_idx; + void *externref_obj; + + externref_obj = (void *)(uintptr_t)invokeNative_Int32( + func_ptr, argv1, argc1); + + if (!wasm_externref_obj2ref(exec_env->module_inst, + externref_obj, &externref_idx)) + goto fail; + + argv_ret[0] = externref_idx; + } + break; + } +#endif default: bh_assert(0); break; @@ -3060,6 +3353,9 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, uint32 ext_ret_count = result_count > 1 ? result_count - 1 : 0; uint64 size; bool ret = false; +#if WASM_ENABLE_REF_TYPES != 0 + bool is_aot_func = (NULL == signature); +#endif #if defined(BUILD_TARGET_X86_32) argc1 = argc + ext_ret_count + 2; @@ -3083,6 +3379,9 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, for (i = 0; i < func_type->param_count; i++) { switch (func_type->types[i]) { case VALUE_TYPE_I32: +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_FUNCREF: +#endif { arg_i32 = *argv++; @@ -3129,12 +3428,26 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, argv1[j++] = *argv++; break; case VALUE_TYPE_F32: -#if WASM_ENABLE_REF_TYPES != 0 - case VALUE_TYPE_FUNCREF: - case VALUE_TYPE_EXTERNREF: -#endif argv1[j++] = *argv++; break; +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_EXTERNREF: + { + uint32 externref_idx = *argv++; + if (is_aot_func) { + argv1[j++] = externref_idx; + } + else { + void *externref_obj; + + if (!wasm_externref_ref2obj(externref_idx, &externref_obj)) + goto fail; + + argv1[j++] = (uintptr_t)externref_obj; + } + break; + } +#endif default: bh_assert(0); break; @@ -3154,7 +3467,6 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, case VALUE_TYPE_I32: #if WASM_ENABLE_REF_TYPES != 0 case VALUE_TYPE_FUNCREF: - case VALUE_TYPE_EXTERNREF: #endif argv_ret[0] = (uint32)invokeNative_Int32(func_ptr, argv1, argc1); @@ -3171,6 +3483,26 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, PUT_F64_TO_ADDR(argv_ret, invokeNative_Float64(func_ptr, argv1, argc1)); break; +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_EXTERNREF: + { + if (is_aot_func) { + uint32 externref_idx = + (uint32)invokeNative_Int32(func_ptr, argv1, argc1); + argv_ret[0] = externref_idx; + } + else { + void *externref_obj = (void *)(uintptr_t)invokeNative_Int32( + func_ptr, argv1, argc1); + uint32 externref_idx; + if (!wasm_externref_obj2ref(exec_env->module_inst, + externref_obj, &externref_idx)) + goto fail; + argv_ret[0] = externref_idx; + } + break; + } +#endif default: bh_assert(0); break; @@ -3281,12 +3613,16 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, uint32 *argv_ret) { WASMModuleInstanceCommon *module = wasm_runtime_get_module_inst(exec_env); - uint64 argv_buf[32], *argv1 = argv_buf, *ints, *stacks, size, arg_i64; + uint64 argv_buf[32] = { 0 }, *argv1 = argv_buf, *ints, *stacks, size, + arg_i64; uint32 *argv_src = argv, i, argc1, n_ints = 0, n_stacks = 0; uint32 arg_i32, ptr_len; uint32 result_count = func_type->result_count; uint32 ext_ret_count = result_count > 1 ? result_count - 1 : 0; bool ret = false; +#if WASM_ENABLE_REF_TYPES != 0 + bool is_aot_func = (NULL == signature); +#endif #ifndef BUILD_TARGET_RISCV64_LP64 #if WASM_ENABLE_SIMD == 0 uint64 *fps; @@ -3336,6 +3672,9 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, for (i = 0; i < func_type->param_count; i++) { switch (func_type->types[i]) { case VALUE_TYPE_I32: +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_FUNCREF: +#endif { arg_i32 = *argv_src++; arg_i64 = arg_i32; @@ -3397,13 +3736,28 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, argv_src += 2; break; #if WASM_ENABLE_REF_TYPES != 0 - case VALUE_TYPE_FUNCREF: case VALUE_TYPE_EXTERNREF: - if (n_ints < MAX_REG_INTS) - ints[n_ints++] = *argv_src++; - else - stacks[n_stacks++] = *argv_src++; + { + uint32 externref_idx = *argv_src++; + if (is_aot_func) { + if (n_ints < MAX_REG_INTS) + ints[n_ints++] = externref_idx; + else + stacks[n_stacks++] = externref_idx; + } + else { + void *externref_obj; + + if (!wasm_externref_ref2obj(externref_idx, &externref_obj)) + goto fail; + + if (n_ints < MAX_REG_INTS) + ints[n_ints++] = (uintptr_t)externref_obj; + else + stacks[n_stacks++] = (uintptr_t)externref_obj; + } break; + } #endif #if WASM_ENABLE_SIMD != 0 case VALUE_TYPE_V128: @@ -3442,7 +3796,6 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, case VALUE_TYPE_I32: #if WASM_ENABLE_REF_TYPES != 0 case VALUE_TYPE_FUNCREF: - case VALUE_TYPE_EXTERNREF: #endif argv_ret[0] = (uint32)invokeNative_Int32(func_ptr, argv1, n_stacks); @@ -3459,6 +3812,26 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, PUT_F64_TO_ADDR( argv_ret, invokeNative_Float64(func_ptr, argv1, n_stacks)); break; +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_EXTERNREF: + { + if (is_aot_func) { + argv_ret[0] = invokeNative_Int32(func_ptr, argv1, n_stacks); + } + else { + uint32 externref_idx; + void *externref_obj = (void *)(uintptr_t)invokeNative_Int64( + func_ptr, argv1, n_stacks); + + if (!wasm_externref_obj2ref(exec_env->module_inst, + externref_obj, &externref_idx)) + goto fail; + + argv_ret[0] = externref_idx; + } + break; + } +#endif #if WASM_ENABLE_SIMD != 0 case VALUE_TYPE_V128: *(v128 *)argv_ret = @@ -3709,10 +4082,24 @@ bool wasm_externref_obj2ref(WASMModuleInstanceCommon *module_inst, void *extern_obj, uint32 *p_externref_idx) { - LookupExtObj_UserData lookup_user_data; + LookupExtObj_UserData lookup_user_data = { 0 }; ExternRefMapNode *node; uint32 externref_idx; + /* + * to catch a parameter from `wasm_application_execute_func`, + * which represents a string 'null' + */ +#if UINTPTR_MAX == UINT32_MAX + if ((uint32)-1 == (uintptr_t)extern_obj) { +#else + if ((uint64)-1LL == (uintptr_t)extern_obj) { +#endif + *p_externref_idx = NULL_REF; + return true; + } + + /* in a wrapper, extern_obj could be any value */ lookup_user_data.node.extern_obj = extern_obj; lookup_user_data.node.module_inst = module_inst; lookup_user_data.found = false; @@ -3764,8 +4151,10 @@ wasm_externref_ref2obj(uint32 externref_idx, void **p_extern_obj) { ExternRefMapNode *node; + /* catch a `ref.null` vairable */ if (externref_idx == NULL_REF) { - return false; + *p_extern_obj = NULL; + return true; } os_mutex_lock(&externref_lock); @@ -4170,14 +4559,9 @@ argv_to_params(wasm_val_t *out_params, const uint32 *argv, WASMType *func_type) case VALUE_TYPE_EXTERNREF: param->kind = WASM_ANYREF; - if (NULL_REF == *argv) { - param->of.ref = NULL; - } - else { - if (!wasm_externref_ref2obj(*argv, - (void **)¶m->of.ref)) { - return false; - } + if (!wasm_externref_ref2obj(*argv, + (void **)¶m->of.foreign)) { + return false; } argv++; @@ -4213,8 +4597,8 @@ results_to_argv(WASMModuleInstanceCommon *module_inst, uint32 *out_argv, break; #if WASM_ENABLE_REF_TYPES != 0 case VALUE_TYPE_EXTERNREF: - if (!wasm_externref_obj2ref(module_inst, result->of.ref, - argv)) { + if (!wasm_externref_obj2ref(module_inst, + (void *)result->of.foreign, argv)) { return false; } argv++; @@ -4234,17 +4618,19 @@ wasm_runtime_invoke_c_api_native(WASMModuleInstanceCommon *module_inst, uint32 argc, uint32 *argv, bool with_env, void *wasm_c_api_env) { - wasm_val_t params_buf[16], results_buf[4]; + wasm_val_t params_buf[16] = { 0 }, results_buf[4] = { 0 }; wasm_val_t *params = params_buf, *results = results_buf; wasm_trap_t *trap = NULL; bool ret = false; wasm_val_vec_t params_vec, results_vec; - if (func_type->param_count > 16 - && !(params = wasm_runtime_malloc(sizeof(wasm_val_t) - * func_type->param_count))) { - wasm_runtime_set_exception(module_inst, "allocate memory failed"); - return false; + if (func_type->param_count > 16) { + if (!(params = + runtime_malloc(sizeof(wasm_val_t) * func_type->param_count, + module_inst, NULL, 0))) { + wasm_runtime_set_exception(module_inst, "allocate memory failed"); + return false; + } } if (!argv_to_params(params, argv, func_type)) { @@ -4252,11 +4638,13 @@ wasm_runtime_invoke_c_api_native(WASMModuleInstanceCommon *module_inst, goto fail; } - if (func_type->result_count > 4 - && !(results = wasm_runtime_malloc(sizeof(wasm_val_t) - * func_type->result_count))) { - wasm_runtime_set_exception(module_inst, "allocate memory failed"); - goto fail; + if (func_type->result_count > 4) { + if (!(results = + runtime_malloc(sizeof(wasm_val_t) * func_type->result_count, + module_inst, NULL, 0))) { + wasm_runtime_set_exception(module_inst, "allocate memory failed"); + goto fail; + } } params_vec.data = params; diff --git a/core/iwasm/common/wasm_runtime_common.h b/core/iwasm/common/wasm_runtime_common.h index c84463aa..ce188c8d 100644 --- a/core/iwasm/common/wasm_runtime_common.h +++ b/core/iwasm/common/wasm_runtime_common.h @@ -525,11 +525,6 @@ bool wasm_runtime_call_indirect(WASMExecEnv *exec_env, uint32 element_indices, uint32 argc, uint32 argv[]); -bool -wasm_runtime_create_exec_env_and_call_wasm( - WASMModuleInstanceCommon *module_inst, WASMFunctionInstanceCommon *function, - uint32 argc, uint32 argv[]); - bool wasm_runtime_create_exec_env_singleton(WASMModuleInstanceCommon *module_inst); @@ -813,16 +808,6 @@ wasm_runtime_dump_module_inst_mem_consumption( void wasm_runtime_dump_exec_env_mem_consumption(const WASMExecEnv *exec_env); -#if WASM_ENABLE_REF_TYPES != 0 -void -wasm_runtime_prepare_call_function(WASMExecEnv *exec_env, - WASMFunctionInstanceCommon *function); -void -wasm_runtime_finalize_call_function(WASMExecEnv *exec_env, - WASMFunctionInstanceCommon *function, - bool ret, uint32 *argv); -#endif - bool wasm_runtime_get_export_func_type(const WASMModuleCommon *module_comm, const WASMExport *export_, WASMType **out); diff --git a/core/iwasm/compilation/aot.h b/core/iwasm/compilation/aot.h index 3254eaf2..78dc78e2 100644 --- a/core/iwasm/compilation/aot.h +++ b/core/iwasm/compilation/aot.h @@ -96,6 +96,7 @@ typedef struct AOTMemInitData { typedef struct AOTImportTable { char *module_name; char *table_name; + uint32 elem_type; uint32 table_flags; uint32 table_init_size; uint32 table_max_size; diff --git a/core/iwasm/compilation/aot_emit_aot_file.c b/core/iwasm/compilation/aot_emit_aot_file.c index f36f526a..e19cfaa1 100644 --- a/core/iwasm/compilation/aot_emit_aot_file.c +++ b/core/iwasm/compilation/aot_emit_aot_file.c @@ -1398,6 +1398,7 @@ aot_emit_table_info(uint8 *buf, uint8 *buf_end, uint32 *p_offset, * EMIT_STR(comp_data->import_tables[i].module_name ); * EMIT_STR(comp_data->import_tables[i].table_name); */ + EMIT_U32(comp_data->import_tables[i].elem_type); EMIT_U32(comp_data->import_tables[i].table_init_size); EMIT_U32(comp_data->import_tables[i].table_max_size); EMIT_U32(comp_data->import_tables[i].possible_grow & 0x000000FF); diff --git a/core/iwasm/include/wasm_export.h b/core/iwasm/include/wasm_export.h index 6b669534..5a6d4e8d 100644 --- a/core/iwasm/include/wasm_export.h +++ b/core/iwasm/include/wasm_export.h @@ -155,16 +155,17 @@ enum wasm_valkind_enum { #ifndef WASM_VAL_T_DEFINED #define WASM_VAL_T_DEFINED -struct wasm_ref_t; typedef struct wasm_val_t { wasm_valkind_t kind; union { + /* also represent a function index */ int32_t i32; int64_t i64; float f32; double f64; - struct wasm_ref_t *ref; + /* represent a foreign object, aka externref in .wat */ + uintptr_t foreign; } of; } wasm_val_t; #endif @@ -790,6 +791,7 @@ wasm_runtime_get_native_addr_range(wasm_module_inst_t module_inst, * 'I': the parameter is i64 type * 'f': the parameter is f32 type * 'F': the parameter is f64 type + * 'r': the parameter is externref type, it should be a uintptr_t in host * '*': the parameter is a pointer (i32 in WASM), and runtime will * auto check its boundary before calling the native function. * If it is followed by '~', the checked length of the pointer diff --git a/core/iwasm/interpreter/wasm.h b/core/iwasm/interpreter/wasm.h index 6db1a705..9160350b 100644 --- a/core/iwasm/interpreter/wasm.h +++ b/core/iwasm/interpreter/wasm.h @@ -544,6 +544,19 @@ wasm_get_cell_num(const uint8 *types, uint32 type_count) return cell_num; } +#if WASM_ENABLE_REF_TYPES != 0 +inline static uint16 +wasm_value_type_cell_num_outside(uint8 value_type) +{ + if (VALUE_TYPE_EXTERNREF == value_type) { + return sizeof(uintptr_t) / sizeof(uint32); + } + else { + return wasm_value_type_cell_num(value_type); + } +} +#endif + inline static bool wasm_type_equal(const WASMType *type1, const WASMType *type2) { diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index 2de827c8..0a5ba3dc 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -1748,16 +1748,8 @@ wasm_create_exec_env_and_call_function(WASMModuleInstance *module_inst, } #endif -#if WASM_ENABLE_REF_TYPES != 0 - wasm_runtime_prepare_call_function(exec_env, func); -#endif - ret = wasm_call_function(exec_env, func, argc, argv); -#if WASM_ENABLE_REF_TYPES != 0 - wasm_runtime_finalize_call_function(exec_env, func, ret, argv); -#endif - #if WASM_ENABLE_THREAD_MGR != 0 /* don't destroy the exec_env if it's searched from the cluster */ if (!existing_exec_env) @@ -1770,9 +1762,14 @@ wasm_create_exec_env_and_call_function(WASMModuleInstance *module_inst, bool wasm_create_exec_env_singleton(WASMModuleInstance *module_inst) { - WASMExecEnv *exec_env = - wasm_exec_env_create((WASMModuleInstanceCommon *)module_inst, - module_inst->default_wasm_stack_size); + WASMExecEnv *exec_env = NULL; + + if (module_inst->exec_env_singleton) { + return true; + } + + exec_env = wasm_exec_env_create((WASMModuleInstanceCommon *)module_inst, + module_inst->default_wasm_stack_size); if (exec_env) module_inst->exec_env_singleton = exec_env; diff --git a/core/shared/platform/windows/platform_internal.h b/core/shared/platform/windows/platform_internal.h index db942416..5c50f9e3 100644 --- a/core/shared/platform/windows/platform_internal.h +++ b/core/shared/platform/windows/platform_internal.h @@ -74,6 +74,9 @@ os_mem_decommit(void *ptr, size_t size); #define os_thread_local_attribute __declspec(thread) +#define strncasecmp _strnicmp +#define strcasecmp _stricmp + #if WASM_DISABLE_HW_BOUND_CHECK == 0 #if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64) diff --git a/doc/export_native_api.md b/doc/export_native_api.md index e507c5c4..fba83d3e 100644 --- a/doc/export_native_api.md +++ b/doc/export_native_api.md @@ -85,10 +85,11 @@ The function signature field in **NativeSymbol** structure is a string for descr Each letter in the "()" represents a parameter type, and the one following after ")" represents the return value type. The meaning of each letter: -- '**i**': i32 or externref (for externref, developer should use `wasm_externref_obj2ref()` to map host object to externref index firstly) +- '**i**': i32 - '**I**': i64 - '**f**': f32 - '**F**': f64 +- '**r**': externref (has to be the value of a `uintptr_t` variable) - '**\***': the parameter is a buffer address in WASM application - '**~**': the parameter is the byte length of WASM buffer as referred by preceding argument "\*". It must follow after '*', otherwise, registration will fail - '**$**': the parameter is a string in WASM application diff --git a/doc/ref_types.md b/doc/ref_types.md index ed37411f..7fefa999 100644 --- a/doc/ref_types.md +++ b/doc/ref_types.md @@ -1,22 +1,9 @@ # WAMR reference-types introduction -WebAssembly [reference-types](https://github.com/WebAssembly/reference-types) proposal introduces the new type `externref` and makes it easier and more efficient to interoperate with host environment, allowing host references to be represented directly by type externref. And WASM modules can talk about host references directly, rather than requiring external glue code running in the host. +WebAssembly [reference-types](https://github.com/WebAssembly/reference-types) proposal introduces two new types `funcref` and `externref`. With `externref`, It is easier and more efficient to interoperate with host environment. Host references are able to be represented directly by type `externref`. -WAMR implements the reference-types proposal, allowing developer to pass the host object to WASM application and then restore and access the host object in native lib. In WAMR internal, the external host object is represented as externref index with `uint32` type, developer must firstly map the host object of `void *` type to the externref index, and then pass the index to the function to called as the function's externref argument. +WAMR has implemented the reference-types proposal. WAMR allows a native method to pass a host object to a WASM application as an `externref` parameter or receives a host object from a WASM application as an `externref` result. Internally, WAMR won't try to parse or dereference `externref`. It is an opaque type. -Currently WAMR provides APIs as below: -```C -bool -wasm_externref_obj2ref(wasm_module_inst_t module_inst, - void *extern_obj, uint32_t *p_externref_idx); - -WASM_RUNTIME_API_EXTERN bool -wasm_externref_ref2obj(uint32_t externref_idx, void **p_extern_obj); - -WASM_RUNTIME_API_EXTERN bool -wasm_externref_retain(uint32 externref_idx); -``` - -The `wasm_externref_obj2ref()` API is used to map the host object to the externref index, and the `wasm_externref_ref2obj()` API is used to retrieve the original host object mapped. The `wasm_externref_retain()` API is to retain the host object if we don't want the object to be cleaned when it isn't used during externref object reclaim. +The restriction of using `externref` in a native method is the host object has to be the value of a `unintptr_t` variable. In other words, it takes **8 bytes** on 64-bit machine and **4 bytes** on 32-bit machines. Please keep that in mind especially when calling `wasm_runtime_call_wasm`. Please ref to the [sample](../samples/ref-types) for more details. diff --git a/samples/ref-types/CMakeLists.txt b/samples/ref-types/CMakeLists.txt index b3dd722b..229afd3c 100644 --- a/samples/ref-types/CMakeLists.txt +++ b/samples/ref-types/CMakeLists.txt @@ -116,7 +116,7 @@ endif() # wat to wasm file(GLOB WAT_FILE src/hello.wat) add_custom_target(hello_wasm ALL - COMMAND ${WAT2WASM} ${WAT_FILE} -o ${PROJECT_BINARY_DIR}/hello.wasm + COMMAND ${WAT2WASM} ${WAT_FILE} --enable-reference-types -o ${PROJECT_BINARY_DIR}/hello.wasm DEPENDS ${WAT_FILE} BYPRODUCTS ${PROJECT_BINARY_DIR}/hello.wasm VERBATIM diff --git a/samples/ref-types/src/hello.c b/samples/ref-types/src/hello.c index b353c990..024d026b 100644 --- a/samples/ref-types/src/hello.c +++ b/samples/ref-types/src/hello.c @@ -13,52 +13,170 @@ static char global_heap_buf[10 * 1024 * 1024] = { 0 }; #endif -static int -test_write_wrapper(wasm_exec_env_t exec_env, uint32 externref_idx_of_file, - const char *str, int len) +static uintptr_t global_objects[10] = { 0 }; + +int32 +local_cmp_externref(wasm_exec_env_t exec_env, uintptr_t externref_a, + uintptr_t externref_b) { - FILE *file; - char buf[16]; + return externref_a == externref_b; +} - printf("## retrieve file handle from externref index\n"); - if (!wasm_externref_ref2obj(externref_idx_of_file, (void **)&file)) { - printf("failed to get host object from externref index!\n"); - return -1; - } - - snprintf(buf, sizeof(buf), "%%%ds", len); - - printf("## write string to file: "); - printf(buf, str); - - return fprintf(file, buf, str); +int32 +local_chk_externref(wasm_exec_env_t exec_env, int32 index, uintptr_t externref) +{ + return externref == global_objects[index]; } /* clang-format off */ static NativeSymbol native_symbols[] = { - { "test_write", test_write_wrapper, "(i*~)i", NULL } + { "native-cmp-externref", local_cmp_externref, "(II)i", NULL }, + { "native-chk-externref", local_chk_externref, "(iI)i", NULL }, }; /* clang-format on */ +static inline void +local_set_externref(int32 index, uintptr_t externref) +{ + global_objects[index] = externref; +} + +static WASMFunctionInstanceCommon *wasm_set_externref_ptr; +static WASMFunctionInstanceCommon *wasm_get_externref_ptr; +static WASMFunctionInstanceCommon *wasm_cmp_externref_ptr; + +static bool +wasm_set_externref(wasm_exec_env_t exec_env, wasm_module_inst_t inst, + int32 index, uintptr_t externref) +{ + union { + uintptr_t val; + uint32 parts[2]; + } u; + uint32 argv[3] = { 0 }; + + if (!exec_env || !wasm_set_externref_ptr) { + return false; + } + + u.val = externref; + argv[0] = index; + argv[1] = u.parts[0]; + argv[2] = u.parts[1]; + if (!wasm_runtime_call_wasm(exec_env, wasm_set_externref_ptr, 2, argv)) { + const char *exception; + if ((exception = wasm_runtime_get_exception(inst))) { + printf("Exception: %s\n", exception); + } + return false; + } + + return true; +} + +static bool +wasm_get_externref(wasm_exec_env_t exec_env, wasm_module_inst_t inst, + int32 index, uintptr_t *ret_externref) +{ + wasm_val_t results[1] = { 0 }; + + if (!exec_env || !wasm_get_externref_ptr || !ret_externref) { + return false; + } + + if (!wasm_runtime_call_wasm_v(exec_env, wasm_get_externref_ptr, 1, results, + 1, index)) { + const char *exception; + if ((exception = wasm_runtime_get_exception(inst))) { + printf("Exception: %s\n", exception); + } + return false; + } + + if (WASM_ANYREF != results[0].kind) { + return false; + } + + *ret_externref = results[0].of.foreign; + return true; +} + +static bool +wasm_cmp_externref(wasm_exec_env_t exec_env, wasm_module_inst_t inst, + int32 index, uintptr_t externref, int32 *ret_result) +{ + wasm_val_t results[1] = { 0 }; + wasm_val_t arguments[2] = { + { .kind = WASM_I32, .of.i32 = index }, + { .kind = WASM_ANYREF, .of.foreign = externref }, + }; + + if (!exec_env || !wasm_cmp_externref_ptr || !ret_result) { + return false; + } + + if (!wasm_runtime_call_wasm_a(exec_env, wasm_cmp_externref_ptr, 1, results, + 2, arguments)) { + const char *exception; + if ((exception = wasm_runtime_get_exception(inst))) { + printf("Exception: %s\n", exception); + } + return false; + } + + if (results[0].kind != WASM_I32) { + return false; + } + + *ret_result = results[0].of.i32; + return true; +} + +static bool +set_and_cmp(wasm_exec_env_t exec_env, wasm_module_inst_t inst, int32 i, + uintptr_t externref) +{ + int32 cmp_result = 0; + uintptr_t wasm_externref = 0; + + wasm_set_externref(exec_env, inst, i, externref); + local_set_externref(i, externref); + + wasm_get_externref(exec_env, inst, 0, &wasm_externref); + if (!local_chk_externref(exec_env, 0, wasm_externref)) { + printf("#%d, In host language world Wasm Externref 0x%lx Vs. Native " + "Externref 0x%lx FAILED\n", + i, wasm_externref, externref); + return false; + } + + if (!wasm_cmp_externref(exec_env, inst, i, global_objects[i], &cmp_result) + || !cmp_result) { + printf("#%d, In Wasm world Native Externref 0x%lx Vs, Wasm Externref " + "FAILED\n", + i, global_objects[i]); + return false; + } + + return true; +} + int main(int argc, char *argv[]) { char *wasm_file = "hello.wasm"; uint8 *wasm_file_buf = NULL; - uint32 wasm_file_size, externref_idx; + uint32 wasm_file_size; uint32 stack_size = 16 * 1024, heap_size = 16 * 1024; wasm_module_t wasm_module = NULL; wasm_module_inst_t wasm_module_inst = NULL; - wasm_function_inst_t func_inst = NULL; wasm_exec_env_t exec_env = NULL; RuntimeInitArgs init_args; char error_buf[128] = { 0 }; - const char *exce; - unsigned argv1[8]; #if WASM_ENABLE_LOG != 0 int log_verbose_level = 2; #endif - FILE *file; + const uint64 big_number = 0x123456789abc; memset(&init_args, 0, sizeof(RuntimeInitArgs)); @@ -90,13 +208,13 @@ 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 fail; /* load WASM module */ 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 fail; } /* instantiate the module */ @@ -104,62 +222,66 @@ main(int argc, char *argv[]) wasm_runtime_instantiate(wasm_module, stack_size, heap_size, error_buf, sizeof(error_buf)))) { printf("%s\n", error_buf); - goto fail3; - } - - /* lookup function instance */ - if (!(func_inst = - wasm_runtime_lookup_function(wasm_module_inst, "test", NULL))) { - printf("%s\n", "lookup function test failed"); - goto fail4; + goto fail; } + /* create an execution env */ if (!(exec_env = wasm_runtime_create_exec_env(wasm_module_inst, stack_size))) { printf("%s\n", "create exec env failed"); - goto fail4; + goto fail; } - printf("## open file test.txt\n"); - if (!(file = fopen("test.txt", "wb+"))) { - printf("%s\n", "open file text.txt failed"); - goto fail5; + /* lookup function instance */ + if (!(wasm_cmp_externref_ptr = wasm_runtime_lookup_function( + wasm_module_inst, "cmp-externref", NULL))) { + printf("%s\n", "lookup function cmp-externref failed"); + goto fail; } - printf("## map file handle to externref index\n"); - if (!wasm_externref_obj2ref(wasm_module_inst, file, &externref_idx)) { - printf("%s\n", "map host object to externref index failed"); - goto fail6; + if (!(wasm_get_externref_ptr = wasm_runtime_lookup_function( + wasm_module_inst, "get-externref", NULL))) { + printf("%s\n", "lookup function get-externref failed"); + goto fail; } - printf("## call wasm function with externref index\n"); - argv1[0] = externref_idx; - wasm_runtime_call_wasm(exec_env, func_inst, 1, argv1); - - if ((exce = wasm_runtime_get_exception(wasm_module_inst))) { - printf("Exception: %s\n", exce); + if (!(wasm_set_externref_ptr = wasm_runtime_lookup_function( + wasm_module_inst, "set-externref", NULL))) { + printf("%s\n", "lookup function set-externref failed"); + goto fail; } -fail6: - fclose(file); + /* test with NULL */ + if (!set_and_cmp(exec_env, wasm_module_inst, 0, 0) + || !set_and_cmp(exec_env, wasm_module_inst, 1, big_number + 1) + || !set_and_cmp(exec_env, wasm_module_inst, 2, big_number + 2) + || !set_and_cmp(exec_env, wasm_module_inst, 3, big_number + 3)) { + goto fail; + } -fail5: + printf("GREAT! PASS ALL CHKs\n"); + +fail: /* destroy exec env */ - wasm_runtime_destroy_exec_env(exec_env); + if (exec_env) { + wasm_runtime_destroy_exec_env(exec_env); + } -fail4: /* destroy the module instance */ - wasm_runtime_deinstantiate(wasm_module_inst); + if (wasm_module_inst) { + wasm_runtime_deinstantiate(wasm_module_inst); + } -fail3: /* unload the module */ - wasm_runtime_unload(wasm_module); + if (wasm_module) { + wasm_runtime_unload(wasm_module); + } -fail2: /* free the file buffer */ - wasm_runtime_free(wasm_file_buf); + if (wasm_file_buf) { + wasm_runtime_free(wasm_file_buf); + } -fail1: /* destroy runtime environment */ wasm_runtime_destroy(); return 0; diff --git a/samples/ref-types/src/hello.wat b/samples/ref-types/src/hello.wat index 1a0f21db..3c2d2f96 100644 --- a/samples/ref-types/src/hello.wat +++ b/samples/ref-types/src/hello.wat @@ -2,21 +2,43 @@ ;; SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception (module - ;; import test_write function which is implemented by host - (import "env" "test_write" - (func $test_write (param externref i32 i32) (result i32))) + (type $t0 (func (param i32 externref) (result i32))) - ;; memory with one page (64KiB). - (memory (export "memory") 1) + (import "env" "native-cmp-externref" + (func $native-cmp-externref (param externref externref) (result i32)) + ) - (data (i32.const 0x8) "Hello, world!\n") + (import "env" "native-chk-externref" + (func $native-chk-externref (param i32 externref) (result i32)) + ) - ;; function that writes string to a given open file handle - (func (export "test") (param externref) - (local.get 0) - (i32.const 0x8) - (i32.const 14) - (call $test_write) - drop + (table $t1 8 8 externref) + (table $t2 funcref + (elem + $native-cmp-externref + $native-chk-externref + ) + ) + + (func (export "set-externref") (param $i i32) (param $r externref) + (table.set $t1 (local.get $i) (local.get $r)) + ) + + (func (export "get-externref") (param $i i32) (result externref) + (table.get $t1 (local.get $i)) + ) + + (func (export "cmp-externref") (param $i i32) (param $r externref) (result i32) + (table.get $t1 (local.get $i)) + (local.get $r) + (call $native-cmp-externref) + ) + + (func (export "chk-externref") (param $i i32) (param $r externref) (result i32) + (call_indirect $t2 (type $t0) + (local.get $i) + (local.get $r) + (i32.const 1) + ) ) ) diff --git a/samples/wasm-c-api/src/callback.c b/samples/wasm-c-api/src/callback.c index b62d7289..fc6c109d 100644 --- a/samples/wasm-c-api/src/callback.c +++ b/samples/wasm-c-api/src/callback.c @@ -35,7 +35,7 @@ void wasm_val_print(wasm_val_t val) { // A function to be called from Wasm code. own wasm_trap_t* print_callback( - const wasm_val_vec_t *args, wasm_val_vec_t *results + const wasm_val_vec_t* args, wasm_val_vec_t* results ) { printf("Calling back...\n> "); wasm_val_print(args->data[0]); @@ -48,7 +48,7 @@ own wasm_trap_t* print_callback( // A function closure. own wasm_trap_t* closure_callback( - void* env, const wasm_val_vec_t *args, wasm_val_vec_t *results + void* env, const wasm_val_vec_t* args, wasm_val_vec_t* results ) { int i = *(int*)env; printf("Calling back closure...\n"); @@ -113,11 +113,10 @@ int main(int argc, const char* argv[]) { // Instantiate. printf("Instantiating module...\n"); - - wasm_extern_vec_t imports; - wasm_extern_vec_new(&imports, 2, (wasm_extern_t *[]) { + wasm_extern_t* externs[] = { wasm_func_as_extern(print_func), wasm_func_as_extern(closure_func) - }); + }; + wasm_extern_vec_t imports = WASM_ARRAY_VEC(externs); own wasm_instance_t* instance = wasm_instance_new(store, module, &imports, NULL); if (!instance) { @@ -147,9 +146,10 @@ int main(int argc, const char* argv[]) { // Call. printf("Calling export...\n"); - wasm_val_vec_t args, results; - wasm_val_vec_new(&args, 2, (wasm_val_t[]){ WASM_I32_VAL(3), WASM_I32_VAL(4) }); - wasm_val_vec_new(&results, 1, (wasm_val_t[]) { WASM_INIT_VAL }); + wasm_val_t as[2] = { WASM_I32_VAL(3), WASM_I32_VAL(4) }; + wasm_val_t rs[1] = { WASM_INIT_VAL }; + wasm_val_vec_t args = WASM_ARRAY_VEC(as); + wasm_val_vec_t results = WASM_ARRAY_VEC(rs); if (wasm_func_call(run_func, &args, &results)) { printf("> Error calling function!\n"); return 1; @@ -159,7 +159,7 @@ int main(int argc, const char* argv[]) { // Print result. printf("Printing result...\n"); - printf("> %u\n", results.data[0].of.i32); + printf("> %u\n", rs[0].of.i32); // Shut down. printf("Shutting down...\n"); diff --git a/samples/wasm-c-api/src/callback_chain.c b/samples/wasm-c-api/src/callback_chain.c index 1b5f1b59..64f42d96 100644 --- a/samples/wasm-c-api/src/callback_chain.c +++ b/samples/wasm-c-api/src/callback_chain.c @@ -61,10 +61,7 @@ enum EXPORT_ITEM_NAME { DEFINE_FUNCTION(get_pairs) { - wasm_val_vec_t arg, ret; - wasm_val_vec_new(&ret, 1, (wasm_val_t []){ WASM_INIT_VAL }); - wasm_val_vec_new(&arg, 1, (wasm_val_t []){ WASM_I32_VAL(24) }); - call_wasm_function(e_malloc, &arg, &ret, "malloc"); + call_wasm_function(e_malloc, args, results, "malloc"); return NULL; } @@ -204,9 +201,6 @@ main(int argc, const char *argv[]) IMPORT_FUNCTION_LIST(IMPORT_FUNCTION_VARIABLE_NAME) #undef IMPORT_FUNCTION_VARIABLE_NAME - wasm_extern_vec_t imports; - wasm_extern_vec_new_uninitialized(&imports, 10); - #define CREATE_WASM_FUNCTION(name, index, CREATE_FUNC_TYPE) \ { \ own wasm_functype_t *type = CREATE_FUNC_TYPE; \ @@ -219,13 +213,13 @@ main(int argc, const char *argv[]) IMPORT_FUNCTION_LIST(CREATE_WASM_FUNCTION) #undef CREATE_WASM_FUNCTION + wasm_extern_t *fs[10] = {0}; #define ADD_TO_FUNCTION_LIST(name, index, ...) \ - imports.data[index] = wasm_func_as_extern(function_##name); \ - imports.num_elems += 1; + fs[index] = wasm_func_as_extern(function_##name); IMPORT_FUNCTION_LIST(ADD_TO_FUNCTION_LIST) -#undef CREATE_IMPORT_FUNCTION - +#undef ADD_TO_FUNCTION_LIST + wasm_extern_vec_t imports = WASM_ARRAY_VEC(fs); own wasm_instance_t *instance = wasm_instance_new(store, module, &imports, NULL); if (!instance) { diff --git a/samples/wasm-c-api/src/global.c b/samples/wasm-c-api/src/global.c index dab1bb49..f16af9cc 100644 --- a/samples/wasm-c-api/src/global.c +++ b/samples/wasm-c-api/src/global.c @@ -39,10 +39,11 @@ wasm_func_t* get_export_func(const wasm_extern_vec_t* exports, size_t i) { #define check_call(func, type, expected) \ { \ - wasm_val_vec_t results; \ - wasm_val_vec_new_uninitialized(&results, 1); \ - wasm_func_call(func, NULL, &results); \ - check(results.data[0], type, expected); \ + wasm_val_t vs[1]; \ + wasm_val_vec_t args = WASM_EMPTY_VEC; \ + wasm_val_vec_t results = WASM_ARRAY_VEC(vs); \ + wasm_func_call(func, &args, &results); \ + check(vs[0], type, expected); \ } @@ -116,19 +117,13 @@ int main(int argc, const char* argv[]) { // Instantiate. printf("Instantiating module...\n"); - /*const wasm_extern_t* imports1[] = { + wasm_extern_t* externs[] = { wasm_global_as_extern(const_f32_import), wasm_global_as_extern(const_i64_import), wasm_global_as_extern(var_f32_import), wasm_global_as_extern(var_i64_import) - };*/ - wasm_extern_vec_t imports; - wasm_extern_vec_new(&imports, 4, (wasm_extern_t* []) { - wasm_global_as_extern(const_f32_import), - wasm_global_as_extern(const_i64_import), - wasm_global_as_extern(var_f32_import), - wasm_global_as_extern(var_i64_import) - }); + }; + wasm_extern_vec_t imports = WASM_ARRAY_VEC(externs); own wasm_instance_t* instance = wasm_instance_new(store, module, &imports, NULL); if (!instance) { @@ -208,18 +203,19 @@ int main(int argc, const char* argv[]) { check_call(get_var_i64_export, i64, 38); // Modify variables through calls and check again. - wasm_val_vec_t args73; - wasm_val_vec_new(&args73, 1, (wasm_val_t []){ WASM_F32_VAL(73) }); - wasm_func_call(set_var_f32_import, &args73, NULL); - wasm_val_vec_t args74; - wasm_val_vec_new(&args74, 1, (wasm_val_t []){ WASM_I64_VAL(74) }); - wasm_func_call(set_var_i64_import, &args74, NULL); - wasm_val_vec_t args77; - wasm_val_vec_new(&args77, 1, (wasm_val_t []){ WASM_F32_VAL(77) }); - wasm_func_call(set_var_f32_export, &args77, NULL); - wasm_val_vec_t args78; - wasm_val_vec_new(&args78, 1, (wasm_val_t []){ WASM_I64_VAL(78) }); - wasm_func_call(set_var_i64_export, &args78, NULL); + wasm_val_vec_t res = WASM_EMPTY_VEC; + wasm_val_t vs73[] = { WASM_F32_VAL(73) }; + wasm_val_vec_t args73 = WASM_ARRAY_VEC(vs73); + wasm_func_call(set_var_f32_import, &args73, &res); + wasm_val_t vs74[] = { WASM_I64_VAL(74) }; + wasm_val_vec_t args74 = WASM_ARRAY_VEC(vs74); + wasm_func_call(set_var_i64_import, &args74, &res); + wasm_val_t vs77[] = { WASM_F32_VAL(77) }; + wasm_val_vec_t args77 = WASM_ARRAY_VEC(vs77); + wasm_func_call(set_var_f32_export, &args77, &res); + wasm_val_t vs78[] = { WASM_I64_VAL(78) }; + wasm_val_vec_t args78 = WASM_ARRAY_VEC(vs78); + wasm_func_call(set_var_i64_export, &args78, &res); check_global(var_f32_import, f32, 73); check_global(var_i64_import, i64, 74); diff --git a/samples/wasm-c-api/src/hello.c b/samples/wasm-c-api/src/hello.c index 9a6834b5..6b566447 100644 --- a/samples/wasm-c-api/src/hello.c +++ b/samples/wasm-c-api/src/hello.c @@ -66,9 +66,8 @@ int main(int argc, const char* argv[]) { // Instantiate. printf("Instantiating module...\n"); - wasm_extern_vec_t imports; - wasm_extern_vec_new(&imports, 1, (wasm_extern_t* []) { wasm_func_as_extern(hello_func) }); - + wasm_extern_t* externs[] = { wasm_func_as_extern(hello_func) }; + wasm_extern_vec_t imports = WASM_ARRAY_VEC(externs); own wasm_instance_t* instance = wasm_instance_new(store, module, &imports, NULL); if (!instance) { @@ -98,7 +97,9 @@ int main(int argc, const char* argv[]) { // Call. printf("Calling export...\n"); - if (wasm_func_call(run_func, NULL, NULL)) { + wasm_val_vec_t args = WASM_EMPTY_VEC; + wasm_val_vec_t results = WASM_EMPTY_VEC; + if (wasm_func_call(run_func, &args, &results)) { printf("> Error calling function!\n"); return 1; } @@ -114,4 +115,3 @@ int main(int argc, const char* argv[]) { printf("Done.\n"); return 0; } - diff --git a/samples/wasm-c-api/src/hostref.c b/samples/wasm-c-api/src/hostref.c index d802c2b6..211f0cff 100644 --- a/samples/wasm-c-api/src/hostref.c +++ b/samples/wasm-c-api/src/hostref.c @@ -47,21 +47,23 @@ wasm_table_t* get_export_table(const wasm_extern_vec_t* exports, size_t i) { own wasm_ref_t* call_v_r(const wasm_func_t* func) { printf("call_v_r... "); fflush(stdout); - wasm_val_vec_t rs; - wasm_val_vec_new_uninitialized(&rs, 1); - if (wasm_func_call(func, NULL, &rs)) { + wasm_val_t rs[] = { WASM_INIT_VAL }; + wasm_val_vec_t args = WASM_EMPTY_VEC; + wasm_val_vec_t results = WASM_ARRAY_VEC(rs); + if (wasm_func_call(func, &args, &results)) { printf("> Error calling function!\n"); exit(1); } printf("okay\n"); - return rs.data[0].of.ref; + return rs[0].of.ref; } void call_r_v(const wasm_func_t* func, wasm_ref_t* ref) { printf("call_r_v... "); fflush(stdout); - wasm_val_vec_t vs; - wasm_val_vec_new(&vs, 1, (wasm_val_t []){ WASM_REF_VAL(ref) }); - if (wasm_func_call(func, &vs, NULL)) { + wasm_val_t vs[1] = { WASM_REF_VAL(ref) }; + wasm_val_vec_t args = WASM_ARRAY_VEC(vs); + wasm_val_vec_t results = WASM_EMPTY_VEC; + if (wasm_func_call(func, &args, &results)) { printf("> Error calling function!\n"); exit(1); } @@ -70,22 +72,24 @@ void call_r_v(const wasm_func_t* func, wasm_ref_t* ref) { own wasm_ref_t* call_r_r(const wasm_func_t* func, wasm_ref_t* ref) { printf("call_r_r... "); fflush(stdout); - wasm_val_vec_t vs, rs; - wasm_val_vec_new(&vs, 1, (wasm_val_t []){ WASM_REF_VAL(ref) }); - wasm_val_vec_new_uninitialized(&rs, 1); - if (wasm_func_call(func, &vs, &rs)) { + wasm_val_t vs[1] = { WASM_REF_VAL(ref) }; + wasm_val_t rs[1] = { WASM_INIT_VAL }; + wasm_val_vec_t args = WASM_ARRAY_VEC(vs); + wasm_val_vec_t results = WASM_ARRAY_VEC(rs); + if (wasm_func_call(func, &args, &results)) { printf("> Error calling function!\n"); exit(1); } printf("okay\n"); - return rs.data[0].of.ref; + return rs[0].of.ref; } void call_ir_v(const wasm_func_t* func, int32_t i, wasm_ref_t* ref) { printf("call_ir_v... "); fflush(stdout); - wasm_val_vec_t vs; - wasm_val_vec_new(&vs, 2, (wasm_val_t []){ WASM_I32_VAL(i), WASM_REF_VAL(ref) }); - if (wasm_func_call(func, &vs, NULL)) { + wasm_val_t vs[2] = { WASM_I32_VAL(i), WASM_REF_VAL(ref) }; + wasm_val_vec_t args = WASM_ARRAY_VEC(vs); + wasm_val_vec_t results = WASM_EMPTY_VEC; + if (wasm_func_call(func, &args, &results)) { printf("> Error calling function!\n"); exit(1); } @@ -94,31 +98,30 @@ void call_ir_v(const wasm_func_t* func, int32_t i, wasm_ref_t* ref) { own wasm_ref_t* call_i_r(const wasm_func_t* func, int32_t i) { printf("call_i_r... "); fflush(stdout); - wasm_val_vec_t vs, rs; - wasm_val_vec_new(&vs, 1, (wasm_val_t []){ WASM_I32_VAL(i) }); - wasm_val_vec_new_uninitialized(&rs, 1); - if (wasm_func_call(func, &vs, &rs)) { + wasm_val_t vs[1] = { WASM_I32_VAL(i) }; + wasm_val_t rs[1] = { WASM_INIT_VAL }; + wasm_val_vec_t args = WASM_ARRAY_VEC(vs); + wasm_val_vec_t results = WASM_ARRAY_VEC(rs); + if (wasm_func_call(func, &args, &results)) { printf("> Error calling function!\n"); exit(1); } printf("okay\n"); - return rs.data[0].of.ref; + return rs[0].of.ref; } -void -check(own wasm_ref_t *actual, const wasm_ref_t *expected, bool release_ref) -{ - if (actual != expected - && !(actual && expected && wasm_ref_same(actual, expected))) { - printf("> Error reading reference, expected %p, got %p\n", - expected ? wasm_ref_get_host_info(expected) : NULL, - actual ? wasm_ref_get_host_info(actual) : NULL); - exit(1); - } - if (release_ref && actual) - wasm_ref_delete(actual); +void check(own wasm_ref_t* actual, const wasm_ref_t* expected) { + if (actual != expected && + !(actual && expected && wasm_ref_same(actual, expected))) { + printf("> Error reading reference, expected %p, got %p\n", + expected ? wasm_ref_get_host_info(expected) : NULL, + actual ? wasm_ref_get_host_info(actual) : NULL); + exit(1); + } + // if (actual) wasm_ref_delete(actual); } + int main(int argc, const char* argv[]) { // Initialize. printf("Initializing...\n"); @@ -169,8 +172,8 @@ int main(int argc, const char* argv[]) { // Instantiate. printf("Instantiating module...\n"); - wasm_extern_vec_t imports; - wasm_extern_vec_new(&imports, 1, (wasm_extern_t* []) { wasm_func_as_extern(callback_func) }); + wasm_extern_t* externs[] = { wasm_func_as_extern(callback_func) }; + wasm_extern_vec_t imports = WASM_ARRAY_VEC(externs); own wasm_instance_t* instance = wasm_instance_new(store, module, &imports, NULL); if (!instance) { @@ -204,54 +207,61 @@ int main(int argc, const char* argv[]) { wasm_ref_set_host_info(host2, (void*)2); // Some sanity checks. - check(NULL, NULL, true); - check(wasm_ref_copy(host1), host1, true); - check(wasm_ref_copy(host2), host2, true); + check(NULL, NULL); + wasm_ref_t *host1_cp = wasm_ref_copy(host1); + wasm_ref_t *host2_cp = wasm_ref_copy(host2); + check(host1_cp, host1); + check(host2_cp, host2); + wasm_ref_delete(host1_cp); + wasm_ref_delete(host2_cp); own wasm_val_t val; val.kind = WASM_ANYREF; val.of.ref = wasm_ref_copy(host1); - check(wasm_ref_copy(val.of.ref), host1, true); - own wasm_ref_t* ref = val.of.ref; - check(wasm_ref_copy(ref), host1, true); + wasm_ref_t *ref_cp = wasm_ref_copy(val.of.ref); + check(ref_cp, host1); + check(val.of.ref, host1); wasm_ref_delete(val.of.ref); + wasm_ref_delete(ref_cp); // Interact. printf("Accessing global...\n"); - check(call_v_r(global_get), NULL, false); + check(call_v_r(global_get), NULL); call_r_v(global_set, host1); - check(call_v_r(global_get), host1, false); + check(call_v_r(global_get), host1); call_r_v(global_set, host2); - check(call_v_r(global_get), host2, false); + check(call_v_r(global_get), host2); call_r_v(global_set, NULL); - check(call_v_r(global_get), NULL, false); + check(call_v_r(global_get), NULL); wasm_global_get(global, &val); assert(val.kind == WASM_ANYREF); - check(val.of.ref, NULL, false); + assert(val.of.ref == NULL); val.of.ref = host2; wasm_global_set(global, &val); - check(call_v_r(global_get), host2, false); wasm_global_get(global, &val); assert(val.kind == WASM_ANYREF); - check(val.of.ref, host2, false); + assert(val.of.ref == host2); printf("Accessing table...\n"); - check(call_i_r(table_get, 0), NULL, false); - check(call_i_r(table_get, 1), NULL, false); + check(call_i_r(table_get, 0), NULL); + check(call_i_r(table_get, 1), NULL); call_ir_v(table_set, 0, host1); call_ir_v(table_set, 1, host2); - check(call_i_r(table_get, 0), host1, false); - check(call_i_r(table_get, 1), host2, false); + check(call_i_r(table_get, 0), host1); + check(call_i_r(table_get, 1), host2); call_ir_v(table_set, 0, NULL); - check(call_i_r(table_get, 0), NULL, false); + check(call_i_r(table_get, 0), NULL); - check(wasm_table_get(table, 2), NULL, false); + check(wasm_table_get(table, 2), NULL); + wasm_table_set(table, 2, host1); + check(call_i_r(table_get, 2), host1); + check(wasm_table_get(table, 2), host1); printf("Accessing function...\n"); - check(call_r_r(func_call, NULL), NULL, false); - check(call_r_r(func_call, host1), host1, false); - check(call_r_r(func_call, host2), host2, false); + check(call_r_r(func_call, NULL), NULL); + check(call_r_r(func_call, host1), host1); + check(call_r_r(func_call, host2), host2); wasm_ref_delete(host1); wasm_ref_delete(host2); diff --git a/samples/wasm-c-api/src/memory.c b/samples/wasm-c-api/src/memory.c index a6c17654..62ebe3cf 100644 --- a/samples/wasm-c-api/src/memory.c +++ b/samples/wasm-c-api/src/memory.c @@ -33,13 +33,10 @@ void check(bool success) { } void check_call(wasm_func_t* func, int i, wasm_val_t args[], int32_t expected) { - wasm_val_vec_t args_vec; - wasm_val_vec_t results_vec; - if (args) - wasm_val_vec_new(&args_vec, i, args); - wasm_val_vec_new(&results_vec, 1, (wasm_val_t []){ WASM_INIT_VAL }); - if (wasm_func_call(func, args ? &args_vec : NULL, &results_vec) - || results_vec.data[0].of.i32 != expected) { + wasm_val_t r[] = {WASM_INIT_VAL}; + wasm_val_vec_t args_ = {i, args, i, sizeof(wasm_val_t)}; + wasm_val_vec_t results = WASM_ARRAY_VEC(r); + if (wasm_func_call(func, &args_, &results) || r[0].of.i32 != expected) { printf("> Error on result\n"); exit(1); } @@ -60,9 +57,9 @@ void check_call2(wasm_func_t* func, int32_t arg1, int32_t arg2, int32_t expected } void check_ok(wasm_func_t* func, int i, wasm_val_t args[]) { - wasm_val_vec_t args_vec; - wasm_val_vec_new(&args_vec, i, args); - if (wasm_func_call(func, &args_vec, NULL)) { + wasm_val_vec_t args_ = {i, args, i, sizeof(wasm_val_t)}; + wasm_val_vec_t results = WASM_EMPTY_VEC; + if (wasm_func_call(func, &args_, &results)) { printf("> Error on result, expected empty\n"); exit(1); } @@ -74,10 +71,10 @@ void check_ok2(wasm_func_t* func, int32_t arg1, int32_t arg2) { } void check_trap(wasm_func_t* func, int i, wasm_val_t args[]) { - wasm_val_vec_t args_vec, results_vec; - wasm_val_vec_new(&args_vec, i, args); - wasm_val_vec_new(&results_vec, 1, (wasm_val_t []){ WASM_INIT_VAL }); - own wasm_trap_t* trap = wasm_func_call(func, &args_vec, &results_vec); + wasm_val_t r[] = {WASM_INIT_VAL}; + wasm_val_vec_t args_ = {i, args, i, sizeof(wasm_val_t)}; + wasm_val_vec_t results = WASM_ARRAY_VEC(r); + own wasm_trap_t* trap = wasm_func_call(func, &args_, &results); if (! trap) { printf("> Error on result, expected trap\n"); exit(1); @@ -137,8 +134,9 @@ int main(int argc, const char* argv[]) { // Instantiate. printf("Instantiating module...\n"); - own wasm_instance_t* instance = - wasm_instance_new_with_args(store, module, NULL, NULL, KILOBYTE(8), 0); + wasm_extern_vec_t imports = WASM_EMPTY_VEC; + own wasm_instance_t *instance = wasm_instance_new_with_args( + store, module, &imports, NULL, KILOBYTE(32), 0); if (!instance) { printf("> Error instantiating module!\n"); return 1; @@ -156,15 +154,6 @@ int main(int argc, const char* argv[]) { wasm_module_delete(module); - if (!memory || !wasm_memory_data(memory)) { - printf("> Error getting memory!\n"); - wasm_extern_vec_delete(&exports); - wasm_instance_delete(instance); - wasm_store_delete(store); - wasm_engine_delete(engine); - return 1; - } - // Try cloning. own wasm_memory_t* copy = wasm_memory_copy(memory); assert(wasm_memory_same(memory, copy)); @@ -172,13 +161,13 @@ int main(int argc, const char* argv[]) { // Check initial memory. printf("Checking memory...\n"); - check(wasm_memory_size(memory) >= 2); - check(wasm_memory_data_size(memory) >= 0x20000); + check(wasm_memory_size(memory) == 2); + check(wasm_memory_data_size(memory) == 0x20000); check(wasm_memory_data(memory)[0] == 0); check(wasm_memory_data(memory)[0x1000] == 1); check(wasm_memory_data(memory)[0x1003] == 4); - (void)size_func; + check_call0(size_func, 2); check_call1(load_func, 0, 0); check_call1(load_func, 0x1000, 1); check_call1(load_func, 0x1003, 4); diff --git a/samples/wasm-c-api/src/multi.c b/samples/wasm-c-api/src/multi.c index c4599640..92ef0eea 100644 --- a/samples/wasm-c-api/src/multi.c +++ b/samples/wasm-c-api/src/multi.c @@ -9,7 +9,7 @@ // A function to be called from Wasm code. own wasm_trap_t* callback( - const wasm_val_vec_t *args, wasm_val_vec_t *results + const wasm_val_vec_t* args, wasm_val_vec_t* results ) { printf("Calling back...\n> "); printf("> %"PRIu32" %"PRIu64" %"PRIu64" %"PRIu32"\n", @@ -27,14 +27,14 @@ own wasm_trap_t* callback( // A function closure. own wasm_trap_t* closure_callback( - void* env, const wasm_val_t args[], wasm_val_t results[] + void* env, const wasm_val_vec_t* args, wasm_val_vec_t* results ) { int i = *(int*)env; printf("Calling back closure...\n"); printf("> %d\n", i); - results[0].kind = WASM_I32; - results[0].of.i32 = (int32_t)i; + results->data[0].kind = WASM_I32; + results->data[0].of.i32 = (int32_t)i; return NULL; } @@ -47,7 +47,11 @@ int main(int argc, const char* argv[]) { // Load binary. printf("Loading binary...\n"); +#if WASM_ENABLE_AOT != 0 && WASM_ENABLE_INTERP == 0 + FILE* file = fopen("multi.aot", "rb"); +#else FILE* file = fopen("multi.wasm", "rb"); +#endif if (!file) { printf("> Error loading module!\n"); return 1; @@ -91,8 +95,8 @@ int main(int argc, const char* argv[]) { // Instantiate. printf("Instantiating module...\n"); - wasm_extern_vec_t imports; - wasm_extern_vec_new(&imports, 1, (wasm_extern_t *[]) { wasm_func_as_extern(callback_func) }); + wasm_extern_t* externs[] = { wasm_func_as_extern(callback_func) }; + wasm_extern_vec_t imports = WASM_ARRAY_VEC(externs); own wasm_instance_t* instance = wasm_instance_new(store, module, &imports, NULL); if (!instance) { @@ -121,13 +125,14 @@ int main(int argc, const char* argv[]) { // Call. printf("Calling export...\n"); - wasm_val_vec_t args, results; - wasm_val_vec_new(&args, 4, (wasm_val_t []){ - WASM_I32_VAL(1), WASM_I64_VAL(2), WASM_I64_VAL(3), WASM_I32_VAL(4) - }); - wasm_val_vec_new(&results, 4, (wasm_val_t []) { - WASM_INIT_VAL, WASM_INIT_VAL, WASM_INIT_VAL, WASM_INIT_VAL - }); + wasm_val_t vals[4] = { + WASM_I32_VAL(1), WASM_I64_VAL(2), WASM_I64_VAL(3), WASM_I32_VAL(4) + }; + wasm_val_t res[4] = { + WASM_INIT_VAL, WASM_INIT_VAL, WASM_INIT_VAL, WASM_INIT_VAL + }; + wasm_val_vec_t args = WASM_ARRAY_VEC(vals); + wasm_val_vec_t results = WASM_ARRAY_VEC(res); if (wasm_func_call(run_func, &args, &results)) { printf("> Error calling function!\n"); return 1; @@ -138,12 +143,12 @@ int main(int argc, const char* argv[]) { // Print result. printf("Printing result...\n"); printf("> %"PRIu32" %"PRIu64" %"PRIu64" %"PRIu32"\n", - results.data[0].of.i32, results.data[1].of.i64, results.data[2].of.i64, results.data[3].of.i32); + res[0].of.i32, res[1].of.i64, res[2].of.i64, res[3].of.i32); - assert(results.data[0].of.i32 == 1); - assert(results.data[1].of.i64 == 2); - assert(results.data[2].of.i64 == 3); - assert(results.data[3].of.i32 == 4); + assert(res[0].of.i32 == 4); + assert(res[1].of.i64 == 3); + assert(res[2].of.i64 == 2); + assert(res[3].of.i32 == 1); // Shut down. printf("Shutting down...\n"); diff --git a/samples/wasm-c-api/src/reflect.c b/samples/wasm-c-api/src/reflect.c index a90fa2aa..915163b9 100644 --- a/samples/wasm-c-api/src/reflect.c +++ b/samples/wasm-c-api/src/reflect.c @@ -32,12 +32,6 @@ void print_valtype(const wasm_valtype_t* type) { void print_valtypes(const wasm_valtype_vec_t* types) { bool first = true; - - if (!types) { - printf("> Error print a NULL valtype\n"); - return; - } - for (size_t i = 0; i < types->size; ++i) { if (first) { first = false; @@ -49,11 +43,6 @@ void print_valtypes(const wasm_valtype_vec_t* types) { } void print_externtype(const wasm_externtype_t* type) { - if (!type) { - printf("> Error print a NULL externtype\n"); - return; - } - switch (wasm_externtype_kind(type)) { case WASM_EXTERN_FUNC: { const wasm_functype_t* functype = @@ -89,11 +78,6 @@ void print_externtype(const wasm_externtype_t* type) { } void print_name(const wasm_name_t* name) { - if (!name) { - printf("> Error print a NULL name\n"); - return; - } - printf("\"%.*s\"", (int)name->size, name->data); } @@ -139,8 +123,9 @@ int main(int argc, const char* argv[]) { // Instantiate. printf("Instantiating module...\n"); + wasm_extern_vec_t imports = WASM_EMPTY_VEC; own wasm_instance_t* instance = - wasm_instance_new(store, module, NULL, NULL); + wasm_instance_new(store, module, &imports, NULL); if (!instance) { printf("> Error instantiating module!\n"); return 1; diff --git a/samples/wasm-c-api/src/table.c b/samples/wasm-c-api/src/table.c index 942f281c..739385e9 100644 --- a/samples/wasm-c-api/src/table.c +++ b/samples/wasm-c-api/src/table.c @@ -49,19 +49,21 @@ void check_table(wasm_table_t* table, int32_t i, bool expect_set) { } void check_call(wasm_func_t* func, int32_t arg1, int32_t arg2, int32_t expected) { - wasm_val_vec_t args, results; - wasm_val_vec_new(&args, 2, (wasm_val_t []){ WASM_I32_VAL(arg1), WASM_I32_VAL(arg2) }); - wasm_val_vec_new(&results, 1, (wasm_val_t []){ WASM_INIT_VAL }); - if (wasm_func_call(func, &args, &results) || results.data[0].of.i32 != expected) { + wasm_val_t vs[2] = { WASM_I32_VAL(arg1), WASM_I32_VAL(arg2) }; + wasm_val_t r[1] = { WASM_INIT_VAL }; + wasm_val_vec_t args = WASM_ARRAY_VEC(vs); + wasm_val_vec_t results = WASM_ARRAY_VEC(r); + if (wasm_func_call(func, &args, &results) || r[0].of.i32 != expected) { printf("> Error on result\n"); exit(1); } } void check_trap(wasm_func_t* func, int32_t arg1, int32_t arg2) { - wasm_val_vec_t args, results; - wasm_val_vec_new(&args, 2, (wasm_val_t []){ WASM_I32_VAL(arg1), WASM_I32_VAL(arg2) }); - wasm_val_vec_new(&results, 1, (wasm_val_t []){ WASM_INIT_VAL }); + wasm_val_t vs[2] = { WASM_I32_VAL(arg1), WASM_I32_VAL(arg2) }; + wasm_val_t r[1] = { WASM_INIT_VAL }; + wasm_val_vec_t args = WASM_ARRAY_VEC(vs); + wasm_val_vec_t results = WASM_ARRAY_VEC(r); own wasm_trap_t* trap = wasm_func_call(func, &args, &results); if (! trap) { printf("> Error on result, expected trap\n"); @@ -112,8 +114,9 @@ int main(int argc, const char* argv[]) { // Instantiate. printf("Instantiating module...\n"); - own wasm_instance_t *instance = - wasm_instance_new(store, module, NULL, NULL); + wasm_extern_vec_t imports = WASM_EMPTY_VEC; + own wasm_instance_t* instance = + wasm_instance_new(store, module, &imports, NULL); if (!instance) { printf("> Error instantiating module!\n"); return 1; @@ -134,6 +137,7 @@ int main(int argc, const char* argv[]) { // Create external function. printf("Creating callback...\n"); own wasm_functype_t* neg_type = wasm_functype_new_1_1(wasm_valtype_new_i32(), wasm_valtype_new_i32()); + own wasm_func_t* h = wasm_func_new(store, neg_type, neg_callback); wasm_functype_delete(neg_type); @@ -155,7 +159,9 @@ int main(int argc, const char* argv[]) { printf("Mutating table...\n"); check(wasm_table_set(table, 0, wasm_func_as_ref(g))); check(wasm_table_set(table, 1, NULL)); - check(! wasm_table_set(table, 2, wasm_func_as_ref(f))); + wasm_ref_t *ref_f = wasm_func_as_ref(f); + check(! wasm_table_set(table, 2, ref_f)); + wasm_ref_delete(ref_f); check_table(table, 0, true); check_table(table, 1, false); check_call(call_indirect, 7, 0, 666); @@ -165,6 +171,8 @@ int main(int argc, const char* argv[]) { // Grow table. // DO NOT SUPPORT printf("Bypass Growing table...\n"); + + wasm_func_delete(h); wasm_extern_vec_delete(&exports); wasm_instance_delete(instance); diff --git a/samples/wasm-c-api/src/trap.c b/samples/wasm-c-api/src/trap.c index 16dc2e0c..5feb9511 100644 --- a/samples/wasm-c-api/src/trap.c +++ b/samples/wasm-c-api/src/trap.c @@ -80,8 +80,8 @@ int main(int argc, const char* argv[]) { // Instantiate. printf("Instantiating module...\n"); - wasm_extern_vec_t imports; - wasm_extern_vec_new(&imports, 1, (wasm_extern_t* []) { wasm_func_as_extern(fail_func) }); + wasm_extern_t* externs[] = { wasm_func_as_extern(fail_func) }; + wasm_extern_vec_t imports = WASM_ARRAY_VEC(externs); own wasm_instance_t* instance = wasm_instance_new(store, module, &imports, NULL); if (!instance) { @@ -112,10 +112,9 @@ int main(int argc, const char* argv[]) { } printf("Calling export %d...\n", i); - - wasm_val_vec_t results; - wasm_val_vec_new_uninitialized(&results, 1); - own wasm_trap_t* trap = wasm_func_call(func, NULL, &results); + wasm_val_vec_t args = WASM_EMPTY_VEC; + wasm_val_vec_t results = WASM_EMPTY_VEC; + own wasm_trap_t* trap = wasm_func_call(func, &args, &results); if (!trap) { printf("> Error calling function, expected trap!\n"); return 1;