mirror of
https://github.com/bytecodealliance/wasm-micro-runtime.git
synced 2025-05-08 20:56:13 +00:00
Enable call wasm-c-api native func directly from interpreter (#656)
And update loader error messages for latest spec cases, fix aot compiler build error based on latest LLVM code base.
This commit is contained in:
parent
c6783ef258
commit
cba4c78273
|
@ -13,7 +13,6 @@
|
||||||
#if WASM_ENABLE_THREAD_MGR != 0
|
#if WASM_ENABLE_THREAD_MGR != 0
|
||||||
#include "../libraries/thread-mgr/thread_manager.h"
|
#include "../libraries/thread-mgr/thread_manager.h"
|
||||||
#endif
|
#endif
|
||||||
#include "../common/wasm_c_api_internal.h"
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
set_error_buf(char *error_buf, uint32 error_buf_size, const char *string)
|
set_error_buf(char *error_buf, uint32 error_buf_size, const char *string)
|
||||||
|
@ -2204,140 +2203,6 @@ aot_is_wasm_type_equal(AOTModuleInstance *module_inst,
|
||||||
return wasm_type_equal(type1, type2);
|
return wasm_type_equal(type1, type2);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
|
||||||
argv_to_params(wasm_val_t *out_params, const uint32 *argv,
|
|
||||||
AOTFuncType *func_type)
|
|
||||||
{
|
|
||||||
wasm_val_t *param = out_params;
|
|
||||||
uint32 i = 0, *u32;
|
|
||||||
|
|
||||||
for (i = 0; i < func_type->param_count; i++, param++) {
|
|
||||||
switch (func_type->types[i]) {
|
|
||||||
case VALUE_TYPE_I32:
|
|
||||||
param->kind = WASM_I32;
|
|
||||||
param->of.i32 = *argv++;
|
|
||||||
break;
|
|
||||||
case VALUE_TYPE_I64:
|
|
||||||
param->kind = WASM_I64;
|
|
||||||
u32 = (uint32*)¶m->of.i64;
|
|
||||||
u32[0] = *argv++;
|
|
||||||
u32[1] = *argv++;
|
|
||||||
break;
|
|
||||||
case VALUE_TYPE_F32:
|
|
||||||
param->kind = WASM_F32;
|
|
||||||
param->of.f32 = *(float32 *)argv++;
|
|
||||||
break;
|
|
||||||
case VALUE_TYPE_F64:
|
|
||||||
param->kind = WASM_F64;
|
|
||||||
u32 = (uint32*)¶m->of.i64;
|
|
||||||
u32[0] = *argv++;
|
|
||||||
u32[1] = *argv++;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool
|
|
||||||
results_to_argv(uint32 *out_argv, const wasm_val_t *results,
|
|
||||||
AOTFuncType *func_type)
|
|
||||||
{
|
|
||||||
const wasm_val_t *result = results;
|
|
||||||
uint32 *argv = out_argv, *u32, i;
|
|
||||||
uint8 *result_types = func_type->types + func_type->param_count;
|
|
||||||
|
|
||||||
for (i = 0; i < func_type->result_count; i++, result++) {
|
|
||||||
switch (result_types[i]) {
|
|
||||||
case VALUE_TYPE_I32:
|
|
||||||
case VALUE_TYPE_F32:
|
|
||||||
*(int32*)argv++ = result->of.i32;
|
|
||||||
break;
|
|
||||||
case VALUE_TYPE_I64:
|
|
||||||
case VALUE_TYPE_F64:
|
|
||||||
u32 = (uint32*)&result->of.i64;
|
|
||||||
*argv++ = u32[0];
|
|
||||||
*argv++ = u32[1];
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool
|
|
||||||
invoke_wasm_c_api_native(AOTModuleInstance *module_inst, void *func_ptr,
|
|
||||||
AOTFuncType *func_type, 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 = params_buf, *results = results_buf;
|
|
||||||
wasm_trap_t *trap = NULL;
|
|
||||||
bool ret = false;
|
|
||||||
char fmt[16];
|
|
||||||
|
|
||||||
if (func_type->param_count > 16
|
|
||||||
&& !(params = wasm_runtime_malloc(sizeof(wasm_val_t)
|
|
||||||
* func_type->param_count))) {
|
|
||||||
aot_set_exception_with_id(module_inst, EXCE_OUT_OF_MEMORY);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!argv_to_params(params, argv, func_type)) {
|
|
||||||
aot_set_exception(module_inst, "unsupported param type");
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!with_env) {
|
|
||||||
wasm_func_callback_t callback = (wasm_func_callback_t)func_ptr;
|
|
||||||
trap = callback(params, results);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
wasm_func_callback_with_env_t callback =
|
|
||||||
(wasm_func_callback_with_env_t)func_ptr;
|
|
||||||
trap = callback(wasm_c_api_env, params, results);
|
|
||||||
}
|
|
||||||
if (trap) {
|
|
||||||
if (trap->message->data) {
|
|
||||||
snprintf(fmt, sizeof(fmt), "%%.%us", (uint32)trap->message->size);
|
|
||||||
snprintf(module_inst->cur_exception,
|
|
||||||
sizeof(module_inst->cur_exception),
|
|
||||||
fmt, trap->message->data);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
aot_set_exception(module_inst,
|
|
||||||
"native function throw unknown exception");
|
|
||||||
}
|
|
||||||
wasm_trap_delete(trap);
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (func_type->result_count > 4
|
|
||||||
&& !(results = wasm_runtime_malloc(sizeof(wasm_val_t)
|
|
||||||
* func_type->result_count))) {
|
|
||||||
aot_set_exception_with_id(module_inst, EXCE_OUT_OF_MEMORY);
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!results_to_argv(argv, results, func_type)) {
|
|
||||||
aot_set_exception(module_inst, "unsupported result type");
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = true;
|
|
||||||
|
|
||||||
fail:
|
|
||||||
if (params != params_buf)
|
|
||||||
wasm_runtime_free(params);
|
|
||||||
if (results != results_buf)
|
|
||||||
wasm_runtime_free(results);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
aot_invoke_native(WASMExecEnv *exec_env, uint32 func_idx,
|
aot_invoke_native(WASMExecEnv *exec_env, uint32 func_idx,
|
||||||
uint32 argc, uint32 *argv)
|
uint32 argc, uint32 *argv)
|
||||||
|
@ -2368,10 +2233,9 @@ aot_invoke_native(WASMExecEnv *exec_env, uint32 func_idx,
|
||||||
|
|
||||||
attachment = import_func->attachment;
|
attachment = import_func->attachment;
|
||||||
if (import_func->call_conv_wasm_c_api) {
|
if (import_func->call_conv_wasm_c_api) {
|
||||||
return invoke_wasm_c_api_native(module_inst, func_ptr,
|
return wasm_runtime_invoke_c_api_native(
|
||||||
func_type, argc, argv,
|
(WASMModuleInstanceCommon *)module_inst, func_ptr, func_type, argc,
|
||||||
import_func->wasm_c_api_with_env,
|
argv, import_func->wasm_c_api_with_env, attachment);
|
||||||
attachment);
|
|
||||||
}
|
}
|
||||||
else if (!import_func->call_conv_raw) {
|
else if (!import_func->call_conv_raw) {
|
||||||
signature = import_func->signature;
|
signature = import_func->signature;
|
||||||
|
|
|
@ -1401,10 +1401,9 @@ wasm_module_new(wasm_store_t *store, const wasm_byte_vec_t *binary)
|
||||||
|
|
||||||
INIT_VEC(module_ex->binary, wasm_byte_vec_new, binary->size, binary->data);
|
INIT_VEC(module_ex->binary, wasm_byte_vec_new, binary->size, binary->data);
|
||||||
|
|
||||||
module_ex->module_comm_rt =
|
module_ex->module_comm_rt = wasm_runtime_load(
|
||||||
wasm_runtime_load((uint8 *)module_ex->binary->data,
|
(uint8 *)module_ex->binary->data, (uint32)module_ex->binary->size,
|
||||||
(uint32)module_ex->binary->size,
|
error_buf, (uint32)sizeof(error_buf));
|
||||||
error_buf, (uint32)sizeof(error_buf));
|
|
||||||
if (!(module_ex->module_comm_rt)) {
|
if (!(module_ex->module_comm_rt)) {
|
||||||
LOG_ERROR(error_buf);
|
LOG_ERROR(error_buf);
|
||||||
goto failed;
|
goto failed;
|
||||||
|
@ -1846,172 +1845,6 @@ failed_exporttype_new:
|
||||||
wasm_exporttype_vec_delete(out);
|
wasm_exporttype_vec_delete(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32
|
|
||||||
argv_to_params(const uint64 *argv,
|
|
||||||
const wasm_valtype_vec_t *param_defs,
|
|
||||||
wasm_val_t out[])
|
|
||||||
{
|
|
||||||
size_t i = 0;
|
|
||||||
uint32 argc = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < param_defs->num_elems; i++) {
|
|
||||||
wasm_valtype_t *param_def = param_defs->data[i];
|
|
||||||
wasm_val_t *param = out + i;
|
|
||||||
switch (param_def->kind) {
|
|
||||||
case WASM_I32:
|
|
||||||
param->kind = WASM_I32;
|
|
||||||
param->of.i32 = *(uint32 *)(argv + i);
|
|
||||||
argc++;
|
|
||||||
break;
|
|
||||||
case WASM_I64:
|
|
||||||
param->kind = WASM_I64;
|
|
||||||
param->of.i64 = *(uint64 *)(argv + i);
|
|
||||||
argc++;
|
|
||||||
break;
|
|
||||||
case WASM_F32:
|
|
||||||
param->kind = WASM_F32;
|
|
||||||
param->of.f32 = *(float32 *)(argv + i);
|
|
||||||
argc++;
|
|
||||||
break;
|
|
||||||
case WASM_F64:
|
|
||||||
param->kind = WASM_F64;
|
|
||||||
param->of.f64 = *(float64 *)(argv + i);
|
|
||||||
argc++;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
LOG_WARNING("%s meets unsupported type: %d", __FUNCTION__,
|
|
||||||
param_def->kind);
|
|
||||||
goto failed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return argc;
|
|
||||||
failed:
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32
|
|
||||||
results_to_argv(const wasm_val_t *results,
|
|
||||||
const wasm_valtype_vec_t *result_defs,
|
|
||||||
uint64 *out)
|
|
||||||
{
|
|
||||||
size_t i = 0;
|
|
||||||
uint32 argc = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < result_defs->num_elems; ++i) {
|
|
||||||
wasm_valtype_t *result_def = result_defs->data[i];
|
|
||||||
const wasm_val_t *result = results + i;
|
|
||||||
switch (result_def->kind) {
|
|
||||||
case WASM_I32:
|
|
||||||
*(int32 *)(out + i) = result->of.i32;
|
|
||||||
argc++;
|
|
||||||
break;
|
|
||||||
case WASM_I64:
|
|
||||||
*(int64 *)(out + i) = result->of.i64;
|
|
||||||
argc++;
|
|
||||||
break;
|
|
||||||
case WASM_F32:
|
|
||||||
*(float32 *)(out + i) = result->of.f32;
|
|
||||||
argc++;
|
|
||||||
break;
|
|
||||||
case WASM_F64:
|
|
||||||
*(float64 *)(out + i) = result->of.f64;
|
|
||||||
argc++;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
LOG_WARNING("%s meets unsupported kind", __FUNCTION__,
|
|
||||||
result_def->kind);
|
|
||||||
goto failed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return argc;
|
|
||||||
failed:
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static wasm_trap_t *cur_trap = NULL;
|
|
||||||
static void
|
|
||||||
native_func_trampoline(wasm_exec_env_t exec_env, uint64 *argv)
|
|
||||||
{
|
|
||||||
wasm_val_t *params = NULL, *results = NULL;
|
|
||||||
uint32 argc = 0;
|
|
||||||
const wasm_func_t *func = NULL;
|
|
||||||
wasm_trap_t *trap = NULL;
|
|
||||||
size_t param_count, result_count;
|
|
||||||
|
|
||||||
func = wasm_runtime_get_function_attachment(exec_env);
|
|
||||||
bh_assert(func);
|
|
||||||
|
|
||||||
param_count = wasm_func_param_arity(func);
|
|
||||||
if (param_count) {
|
|
||||||
if (!argv) {
|
|
||||||
goto failed;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(params = malloc_internal(param_count * sizeof(wasm_val_t)))) {
|
|
||||||
goto failed;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* argv -> const wasm_val_t params[] */
|
|
||||||
if (!(argc = argv_to_params(argv, wasm_functype_params(func->type),
|
|
||||||
params))) {
|
|
||||||
goto failed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result_count = wasm_func_result_arity(func);
|
|
||||||
if (result_count) {
|
|
||||||
if (!argv) {
|
|
||||||
goto failed;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(results = malloc_internal(result_count * sizeof(wasm_val_t)))) {
|
|
||||||
goto failed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (func->with_env) {
|
|
||||||
trap = func->u.cb_env.cb(func->u.cb_env.env, params, results);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
trap = func->u.cb(params, results);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (trap) {
|
|
||||||
wasm_byte_vec_t message = { 0 };
|
|
||||||
wasm_trap_message(trap, &message);
|
|
||||||
if (message.data) {
|
|
||||||
LOG_WARNING("got a trap %s", message.data);
|
|
||||||
wasm_runtime_set_exception(exec_env->module_inst,
|
|
||||||
"call failed, meet a wasm_trap_t");
|
|
||||||
}
|
|
||||||
wasm_byte_vec_delete(&message);
|
|
||||||
|
|
||||||
cur_trap = trap;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (argv) {
|
|
||||||
memset(argv, 0, wasm_func_param_arity(func) * sizeof(uint64));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* there is no trap and there is return values */
|
|
||||||
if (!trap && result_count) {
|
|
||||||
/* wasm_val_t results[] -> argv */
|
|
||||||
if (!(argc = results_to_argv(
|
|
||||||
results, wasm_functype_results(func->type), argv))) {
|
|
||||||
goto failed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
failed:
|
|
||||||
FREEIF(params);
|
|
||||||
FREEIF(results);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
static wasm_func_t *
|
static wasm_func_t *
|
||||||
wasm_func_new_basic(const wasm_functype_t *type,
|
wasm_func_new_basic(const wasm_functype_t *type,
|
||||||
wasm_func_callback_t func_callback)
|
wasm_func_callback_t func_callback)
|
||||||
|
@ -2342,8 +2175,6 @@ wasm_func_call(const wasm_func_t *func,
|
||||||
|
|
||||||
bh_assert(func && func->type && func->inst_comm_rt);
|
bh_assert(func && func->type && func->inst_comm_rt);
|
||||||
|
|
||||||
cur_trap = NULL;
|
|
||||||
|
|
||||||
#if WASM_ENABLE_INTERP != 0
|
#if WASM_ENABLE_INTERP != 0
|
||||||
if (func->inst_comm_rt->module_type == Wasm_Module_Bytecode) {
|
if (func->inst_comm_rt->module_type == Wasm_Module_Bytecode) {
|
||||||
func_comm_rt = ((WASMModuleInstance *)func->inst_comm_rt)->functions
|
func_comm_rt = ((WASMModuleInstance *)func->inst_comm_rt)->functions
|
||||||
|
@ -2354,7 +2185,8 @@ wasm_func_call(const wasm_func_t *func,
|
||||||
#if WASM_ENABLE_AOT != 0
|
#if WASM_ENABLE_AOT != 0
|
||||||
if (func->inst_comm_rt->module_type == Wasm_Module_AoT) {
|
if (func->inst_comm_rt->module_type == Wasm_Module_AoT) {
|
||||||
if (!(func_comm_rt = func->func_comm_rt)) {
|
if (!(func_comm_rt = func->func_comm_rt)) {
|
||||||
AOTModuleInstance *inst_aot = (AOTModuleInstance *)func->inst_comm_rt;
|
AOTModuleInstance *inst_aot =
|
||||||
|
(AOTModuleInstance *)func->inst_comm_rt;
|
||||||
AOTModule *module_aot = (AOTModule *)inst_aot->aot_module.ptr;
|
AOTModule *module_aot = (AOTModule *)inst_aot->aot_module.ptr;
|
||||||
uint32 export_i = 0, export_func_j = 0;
|
uint32 export_i = 0, export_func_j = 0;
|
||||||
|
|
||||||
|
@ -2363,9 +2195,9 @@ wasm_func_call(const wasm_func_t *func,
|
||||||
if (export->kind == EXPORT_KIND_FUNC) {
|
if (export->kind == EXPORT_KIND_FUNC) {
|
||||||
if (export->index == func->func_idx_rt) {
|
if (export->index == func->func_idx_rt) {
|
||||||
func_comm_rt =
|
func_comm_rt =
|
||||||
(AOTFunctionInstance *)inst_aot->export_funcs.ptr
|
(AOTFunctionInstance *)inst_aot->export_funcs.ptr
|
||||||
+ export_func_j;
|
+ export_func_j;
|
||||||
((wasm_func_t*)func)->func_comm_rt = func_comm_rt;
|
((wasm_func_t *)func)->func_comm_rt = func_comm_rt;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
export_func_j++;
|
export_func_j++;
|
||||||
|
@ -2382,7 +2214,7 @@ wasm_func_call(const wasm_func_t *func,
|
||||||
param_count = wasm_func_param_arity(func);
|
param_count = wasm_func_param_arity(func);
|
||||||
result_count = wasm_func_result_arity(func);
|
result_count = wasm_func_result_arity(func);
|
||||||
alloc_count = (param_count > result_count) ? param_count : result_count;
|
alloc_count = (param_count > result_count) ? param_count : result_count;
|
||||||
if (alloc_count > sizeof(argv_buf)/sizeof(uint64)) {
|
if (alloc_count > sizeof(argv_buf) / sizeof(uint64)) {
|
||||||
if (!(argv = malloc_internal(sizeof(uint64) * alloc_count))) {
|
if (!(argv = malloc_internal(sizeof(uint64) * alloc_count))) {
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
|
@ -2422,17 +2254,13 @@ wasm_func_call(const wasm_func_t *func,
|
||||||
failed:
|
failed:
|
||||||
if (argv != argv_buf)
|
if (argv != argv_buf)
|
||||||
wasm_runtime_free(argv);
|
wasm_runtime_free(argv);
|
||||||
if (cur_trap) {
|
|
||||||
return cur_trap;
|
if (wasm_runtime_get_exception(func->inst_comm_rt)) {
|
||||||
|
return wasm_trap_new_internal(
|
||||||
|
wasm_runtime_get_exception(func->inst_comm_rt));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (wasm_runtime_get_exception(func->inst_comm_rt)) {
|
return wasm_trap_new_internal("wasm_func_call failed");
|
||||||
return wasm_trap_new_internal(
|
|
||||||
wasm_runtime_get_exception(func->inst_comm_rt));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return wasm_trap_new_internal("wasm_func_call failed");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3182,10 +3010,16 @@ interp_link_func(const wasm_instance_t *inst,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* add native_func_trampoline as a NativeSymbol */
|
imported_func_interp->u.function.call_conv_wasm_c_api = true;
|
||||||
imported_func_interp->u.function.call_conv_raw = true;
|
imported_func_interp->u.function.wasm_c_api_with_env = import->with_env;
|
||||||
imported_func_interp->u.function.attachment = cloned;
|
if (import->with_env) {
|
||||||
imported_func_interp->u.function.func_ptr_linked = native_func_trampoline;
|
imported_func_interp->u.function.func_ptr_linked = import->u.cb_env.cb;
|
||||||
|
imported_func_interp->u.function.attachment = import->u.cb_env.env;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
imported_func_interp->u.function.func_ptr_linked = import->u.cb;
|
||||||
|
imported_func_interp->u.function.attachment = NULL;
|
||||||
|
}
|
||||||
import->func_idx_rt = func_idx_rt;
|
import->func_idx_rt = func_idx_rt;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -3672,9 +3506,8 @@ wasm_instance_new(wasm_store_t *store,
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
instance->inst_comm_rt =
|
instance->inst_comm_rt = wasm_runtime_instantiate(
|
||||||
wasm_runtime_instantiate(*module, stack_size, heap_size,
|
*module, stack_size, heap_size, error_buf, sizeof(error_buf));
|
||||||
error_buf, sizeof(error_buf));
|
|
||||||
if (!instance->inst_comm_rt) {
|
if (!instance->inst_comm_rt) {
|
||||||
LOG_ERROR(error_buf);
|
LOG_ERROR(error_buf);
|
||||||
goto failed;
|
goto failed;
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||||
#include "wasm_shared_memory.h"
|
#include "wasm_shared_memory.h"
|
||||||
#endif
|
#endif
|
||||||
|
#include "../common/wasm_c_api_internal.h"
|
||||||
|
|
||||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||||
/*
|
/*
|
||||||
|
@ -4026,3 +4027,141 @@ wasm_runtime_get_memory_data_size(
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
argv_to_params(wasm_val_t *out_params,
|
||||||
|
const uint32 *argv,
|
||||||
|
WASMType *func_type)
|
||||||
|
{
|
||||||
|
wasm_val_t *param = out_params;
|
||||||
|
uint32 i = 0, *u32;
|
||||||
|
|
||||||
|
for (i = 0; i < func_type->param_count; i++, param++) {
|
||||||
|
switch (func_type->types[i]) {
|
||||||
|
case VALUE_TYPE_I32:
|
||||||
|
param->kind = WASM_I32;
|
||||||
|
param->of.i32 = *argv++;
|
||||||
|
break;
|
||||||
|
case VALUE_TYPE_I64:
|
||||||
|
param->kind = WASM_I64;
|
||||||
|
u32 = (uint32 *)¶m->of.i64;
|
||||||
|
u32[0] = *argv++;
|
||||||
|
u32[1] = *argv++;
|
||||||
|
break;
|
||||||
|
case VALUE_TYPE_F32:
|
||||||
|
param->kind = WASM_F32;
|
||||||
|
param->of.f32 = *(float32 *)argv++;
|
||||||
|
break;
|
||||||
|
case VALUE_TYPE_F64:
|
||||||
|
param->kind = WASM_F64;
|
||||||
|
u32 = (uint32 *)¶m->of.i64;
|
||||||
|
u32[0] = *argv++;
|
||||||
|
u32[1] = *argv++;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
results_to_argv(uint32 *out_argv,
|
||||||
|
const wasm_val_t *results,
|
||||||
|
WASMType *func_type)
|
||||||
|
{
|
||||||
|
const wasm_val_t *result = results;
|
||||||
|
uint32 *argv = out_argv, *u32, i;
|
||||||
|
uint8 *result_types = func_type->types + func_type->param_count;
|
||||||
|
|
||||||
|
for (i = 0; i < func_type->result_count; i++, result++) {
|
||||||
|
switch (result_types[i]) {
|
||||||
|
case VALUE_TYPE_I32:
|
||||||
|
case VALUE_TYPE_F32:
|
||||||
|
*(int32 *)argv++ = result->of.i32;
|
||||||
|
break;
|
||||||
|
case VALUE_TYPE_I64:
|
||||||
|
case VALUE_TYPE_F64:
|
||||||
|
u32 = (uint32 *)&result->of.i64;
|
||||||
|
*argv++ = u32[0];
|
||||||
|
*argv++ = u32[1];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
wasm_runtime_invoke_c_api_native(WASMModuleInstanceCommon *module_inst,
|
||||||
|
void *func_ptr, WASMType *func_type,
|
||||||
|
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 = params_buf, *results = results_buf;
|
||||||
|
wasm_trap_t *trap = NULL;
|
||||||
|
bool ret = false;
|
||||||
|
|
||||||
|
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 (!argv_to_params(params, argv, func_type)) {
|
||||||
|
wasm_runtime_set_exception(module_inst, "unsupported param type");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!with_env) {
|
||||||
|
wasm_func_callback_t callback = (wasm_func_callback_t)func_ptr;
|
||||||
|
trap = callback(params, results);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
wasm_func_callback_with_env_t callback =
|
||||||
|
(wasm_func_callback_with_env_t)func_ptr;
|
||||||
|
trap = callback(wasm_c_api_env, params, results);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (trap) {
|
||||||
|
if (trap->message->data) {
|
||||||
|
/* since trap->message->data does not end with '\0' */
|
||||||
|
char trap_message[128] = { 0 };
|
||||||
|
bh_memcpy_s(
|
||||||
|
trap_message, 127, trap->message->data,
|
||||||
|
(trap->message->size < 127 ? trap->message->size : 127));
|
||||||
|
wasm_runtime_set_exception(module_inst, trap_message);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
wasm_runtime_set_exception(
|
||||||
|
module_inst, "native function throw unknown exception");
|
||||||
|
}
|
||||||
|
wasm_trap_delete(trap);
|
||||||
|
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 (!results_to_argv(argv, results, func_type)) {
|
||||||
|
wasm_runtime_set_exception(module_inst, "unsupported result type");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
if (params != params_buf)
|
||||||
|
wasm_runtime_free(params);
|
||||||
|
if (results != results_buf)
|
||||||
|
wasm_runtime_free(results);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
|
@ -796,6 +796,12 @@ uint32
|
||||||
wasm_runtime_get_memory_data_size(const WASMModuleInstanceCommon *module_inst_comm,
|
wasm_runtime_get_memory_data_size(const WASMModuleInstanceCommon *module_inst_comm,
|
||||||
uint32 memory_inst_idx);
|
uint32 memory_inst_idx);
|
||||||
|
|
||||||
|
bool
|
||||||
|
wasm_runtime_invoke_c_api_native(WASMModuleInstanceCommon *module_inst,
|
||||||
|
void *func_ptr, WASMType *func_type,
|
||||||
|
uint32 argc, uint32 *argv,
|
||||||
|
bool with_env, void *wasm_c_api_env);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1534,7 +1534,9 @@ aot_create_comp_context(AOTCompData *comp_data,
|
||||||
LLVMAddInstructionCombiningPass(comp_ctx->pass_mgr);
|
LLVMAddInstructionCombiningPass(comp_ctx->pass_mgr);
|
||||||
LLVMAddCFGSimplificationPass(comp_ctx->pass_mgr);
|
LLVMAddCFGSimplificationPass(comp_ctx->pass_mgr);
|
||||||
LLVMAddJumpThreadingPass(comp_ctx->pass_mgr);
|
LLVMAddJumpThreadingPass(comp_ctx->pass_mgr);
|
||||||
|
#if LLVM_VERSION_MAJOR < 12
|
||||||
LLVMAddConstantPropagationPass(comp_ctx->pass_mgr);
|
LLVMAddConstantPropagationPass(comp_ctx->pass_mgr);
|
||||||
|
#endif
|
||||||
LLVMAddIndVarSimplifyPass(comp_ctx->pass_mgr);
|
LLVMAddIndVarSimplifyPass(comp_ctx->pass_mgr);
|
||||||
|
|
||||||
if (!option->is_jit_mode) {
|
if (!option->is_jit_mode) {
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#define _AOT_LLVM_H_
|
#define _AOT_LLVM_H_
|
||||||
|
|
||||||
#include "aot.h"
|
#include "aot.h"
|
||||||
|
#include "llvm/Config/llvm-config.h"
|
||||||
#include "llvm-c/Types.h"
|
#include "llvm-c/Types.h"
|
||||||
#include "llvm-c/Target.h"
|
#include "llvm-c/Target.h"
|
||||||
#include "llvm-c/Core.h"
|
#include "llvm-c/Core.h"
|
||||||
|
|
|
@ -186,6 +186,8 @@ typedef struct WASMFunctionImport {
|
||||||
WASMModule *import_module;
|
WASMModule *import_module;
|
||||||
WASMFunction *import_func_linked;
|
WASMFunction *import_func_linked;
|
||||||
#endif
|
#endif
|
||||||
|
bool call_conv_wasm_c_api;
|
||||||
|
bool wasm_c_api_with_env;
|
||||||
} WASMFunctionImport;
|
} WASMFunctionImport;
|
||||||
|
|
||||||
typedef struct WASMGlobalImport {
|
typedef struct WASMGlobalImport {
|
||||||
|
|
|
@ -753,7 +753,18 @@ wasm_interp_call_func_native(WASMModuleInstance *module_inst,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!func_import->call_conv_raw) {
|
if (func_import->call_conv_wasm_c_api) {
|
||||||
|
ret = wasm_runtime_invoke_c_api_native(
|
||||||
|
(WASMModuleInstanceCommon *)module_inst,
|
||||||
|
func_import->func_ptr_linked, func_import->func_type,
|
||||||
|
cur_func->param_cell_num, frame->lp,
|
||||||
|
func_import->wasm_c_api_with_env, func_import->attachment);
|
||||||
|
if (ret) {
|
||||||
|
argv_ret[0] = frame->lp[0];
|
||||||
|
argv_ret[1] = frame->lp[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!func_import->call_conv_raw) {
|
||||||
ret = wasm_runtime_invoke_native(exec_env, func_import->func_ptr_linked,
|
ret = wasm_runtime_invoke_native(exec_env, func_import->func_ptr_linked,
|
||||||
func_import->func_type, func_import->signature,
|
func_import->func_type, func_import->signature,
|
||||||
func_import->attachment,
|
func_import->attachment,
|
||||||
|
|
|
@ -826,7 +826,18 @@ wasm_interp_call_func_native(WASMModuleInstance *module_inst,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!func_import->call_conv_raw) {
|
if (func_import->call_conv_wasm_c_api) {
|
||||||
|
ret = wasm_runtime_invoke_c_api_native(
|
||||||
|
(WASMModuleInstanceCommon *)module_inst,
|
||||||
|
func_import->func_ptr_linked, func_import->func_type,
|
||||||
|
cur_func->param_cell_num, frame->lp,
|
||||||
|
func_import->wasm_c_api_with_env, func_import->attachment);
|
||||||
|
if (ret) {
|
||||||
|
argv_ret[0] = frame->lp[0];
|
||||||
|
argv_ret[1] = frame->lp[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!func_import->call_conv_raw) {
|
||||||
ret = wasm_runtime_invoke_native(exec_env, func_import->func_ptr_linked,
|
ret = wasm_runtime_invoke_native(exec_env, func_import->func_ptr_linked,
|
||||||
func_import->func_type, func_import->signature,
|
func_import->func_type, func_import->signature,
|
||||||
func_import->attachment,
|
func_import->attachment,
|
||||||
|
|
|
@ -2304,7 +2304,7 @@ check_table_index(const WASMModule *module, uint32 table_index,
|
||||||
!wasm_get_ref_types_flag() &&
|
!wasm_get_ref_types_flag() &&
|
||||||
#endif
|
#endif
|
||||||
table_index != 0) {
|
table_index != 0) {
|
||||||
set_error_buf(error_buf, error_buf_size, "zero flag expected");
|
set_error_buf(error_buf, error_buf_size, "zero byte expected");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7472,13 +7472,8 @@ handle_op_block_and_loop:
|
||||||
CHECK_MEMORY();
|
CHECK_MEMORY();
|
||||||
/* reserved byte 0x00 */
|
/* reserved byte 0x00 */
|
||||||
if (*p++ != 0x00) {
|
if (*p++ != 0x00) {
|
||||||
#if WASM_ENABLE_REF_TYPES != 0
|
|
||||||
set_error_buf(error_buf, error_buf_size,
|
set_error_buf(error_buf, error_buf_size,
|
||||||
"zero byte expected");
|
"zero byte expected");
|
||||||
#else
|
|
||||||
set_error_buf(error_buf, error_buf_size,
|
|
||||||
"zero flag expected");
|
|
||||||
#endif
|
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
PUSH_I32();
|
PUSH_I32();
|
||||||
|
@ -7490,13 +7485,8 @@ handle_op_block_and_loop:
|
||||||
CHECK_MEMORY();
|
CHECK_MEMORY();
|
||||||
/* reserved byte 0x00 */
|
/* reserved byte 0x00 */
|
||||||
if (*p++ != 0x00) {
|
if (*p++ != 0x00) {
|
||||||
#if WASM_ENABLE_REF_TYPES != 0
|
|
||||||
set_error_buf(error_buf, error_buf_size,
|
set_error_buf(error_buf, error_buf_size,
|
||||||
"zero byte expected");
|
"zero byte expected");
|
||||||
#else
|
|
||||||
set_error_buf(error_buf, error_buf_size,
|
|
||||||
"zero flag expected");
|
|
||||||
#endif
|
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32);
|
POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32);
|
||||||
|
@ -7811,7 +7801,7 @@ handle_op_block_and_loop:
|
||||||
goto fail_unknown_memory;
|
goto fail_unknown_memory;
|
||||||
|
|
||||||
if (*p++ != 0x00)
|
if (*p++ != 0x00)
|
||||||
goto fail_zero_flag_expected;
|
goto fail_zero_byte_expected;
|
||||||
|
|
||||||
if (data_seg_idx >= module->data_seg_count) {
|
if (data_seg_idx >= module->data_seg_count) {
|
||||||
set_error_buf_v(error_buf, error_buf_size,
|
set_error_buf_v(error_buf, error_buf_size,
|
||||||
|
@ -7848,7 +7838,7 @@ handle_op_block_and_loop:
|
||||||
{
|
{
|
||||||
/* both src and dst memory index should be 0 */
|
/* both src and dst memory index should be 0 */
|
||||||
if (*(int16*)p != 0x0000)
|
if (*(int16*)p != 0x0000)
|
||||||
goto fail_zero_flag_expected;
|
goto fail_zero_byte_expected;
|
||||||
p += 2;
|
p += 2;
|
||||||
|
|
||||||
if (module->import_memory_count == 0 && module->memory_count == 0)
|
if (module->import_memory_count == 0 && module->memory_count == 0)
|
||||||
|
@ -7862,7 +7852,7 @@ handle_op_block_and_loop:
|
||||||
case WASM_OP_MEMORY_FILL:
|
case WASM_OP_MEMORY_FILL:
|
||||||
{
|
{
|
||||||
if (*p++ != 0x00) {
|
if (*p++ != 0x00) {
|
||||||
goto fail_zero_flag_expected;
|
goto fail_zero_byte_expected;
|
||||||
}
|
}
|
||||||
if (module->import_memory_count == 0 && module->memory_count == 0) {
|
if (module->import_memory_count == 0 && module->memory_count == 0) {
|
||||||
goto fail_unknown_memory;
|
goto fail_unknown_memory;
|
||||||
|
@ -7872,9 +7862,9 @@ handle_op_block_and_loop:
|
||||||
POP_I32();
|
POP_I32();
|
||||||
POP_I32();
|
POP_I32();
|
||||||
break;
|
break;
|
||||||
fail_zero_flag_expected:
|
fail_zero_byte_expected:
|
||||||
set_error_buf(error_buf, error_buf_size,
|
set_error_buf(error_buf, error_buf_size,
|
||||||
"zero flag expected");
|
"zero byte expected");
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
fail_unknown_memory:
|
fail_unknown_memory:
|
||||||
|
@ -8460,7 +8450,7 @@ fail_data_cnt_sec_require:
|
||||||
/* reserved byte 0x00 */
|
/* reserved byte 0x00 */
|
||||||
if (*p++ != 0x00) {
|
if (*p++ != 0x00) {
|
||||||
set_error_buf(error_buf, error_buf_size,
|
set_error_buf(error_buf, error_buf_size,
|
||||||
"zero flag expected");
|
"zero byte expected");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -105,32 +105,30 @@ foreach(EX ${EXAMPLES})
|
||||||
if (MSVC)
|
if (MSVC)
|
||||||
target_compile_definitions(${EX} PRIVATE WASM_API_EXTERN=)
|
target_compile_definitions(${EX} PRIVATE WASM_API_EXTERN=)
|
||||||
endif()
|
endif()
|
||||||
endforeach()
|
|
||||||
|
|
||||||
# wat to wasm
|
# wat to wasm
|
||||||
foreach(EX ${EXAMPLES})
|
set(WAT ${CMAKE_CURRENT_LIST_DIR}/src/${EX}.wat)
|
||||||
set(SRC ${CMAKE_CURRENT_LIST_DIR}/src/${EX}.wat)
|
|
||||||
|
|
||||||
add_custom_target(${EX}_WASM ALL
|
add_custom_target(${EX}_WASM
|
||||||
COMMAND ${WAT2WASM} ${SRC} -o ${PROJECT_BINARY_DIR}/${EX}.wasm
|
COMMAND ${WAT2WASM} ${WAT} -o ${PROJECT_BINARY_DIR}/${EX}.wasm
|
||||||
DEPENDS ${SRC}
|
DEPENDS ${WAT}
|
||||||
BYPRODUCTS ${PROJECT_BINARY_DIR}/${EX}.wasm
|
BYPRODUCTS ${PROJECT_BINARY_DIR}/${EX}.wasm
|
||||||
VERBATIM
|
VERBATIM
|
||||||
SOURCES ${SRC}
|
|
||||||
)
|
)
|
||||||
|
add_dependencies(${EX} ${EX}_WASM)
|
||||||
|
|
||||||
# generate .aot file
|
# generate .aot file
|
||||||
if(${WAMR_BUILD_AOT} EQUAL 1)
|
if(${WAMR_BUILD_AOT} EQUAL 1)
|
||||||
if(EXISTS ${WAMRC})
|
if(EXISTS ${WAMRC})
|
||||||
add_custom_target(${EX}_AOT ALL
|
add_custom_target(${EX}_AOT
|
||||||
COMMAND ${WAMRC} -o ${PROJECT_BINARY_DIR}/${EX}.aot
|
COMMAND ${WAMRC} -o ${PROJECT_BINARY_DIR}/${EX}.aot
|
||||||
${PROJECT_BINARY_DIR}/${EX}.wasm
|
${PROJECT_BINARY_DIR}/${EX}.wasm
|
||||||
DEPENDS ${PROJECT_BINARY_DIR}/${EX}.wasm
|
DEPENDS ${EX}_WASM
|
||||||
BYPRODUCTS ${PROJECT_BINARY_DIR}/${EX}.aot
|
BYPRODUCTS ${PROJECT_BINARY_DIR}/${EX}.aot
|
||||||
VERBATIM
|
VERBATIM
|
||||||
SOURCES ${SRC}
|
|
||||||
COMMENT "generate a aot file ${PROJECT_BINARY_DIR}/${EX}.aot"
|
COMMENT "generate a aot file ${PROJECT_BINARY_DIR}/${EX}.aot"
|
||||||
)
|
)
|
||||||
|
add_dependencies(${EX} ${EX}_AOT)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
|
@ -83,7 +83,7 @@ DEFINE_FUNCTION(log)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data[length.of.i32]) {
|
if (data[length.of.i32 - 1]) {
|
||||||
printf("> Error terminated character\n");
|
printf("> Error terminated character\n");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -188,7 +188,11 @@ main(int argc, const char *argv[])
|
||||||
|
|
||||||
// Load binary.
|
// Load binary.
|
||||||
printf("Loading binary...\n");
|
printf("Loading binary...\n");
|
||||||
|
#if WASM_ENABLE_AOT != 0 && WASM_ENABLE_INTERP == 0
|
||||||
|
FILE *file = fopen("callback_chain.aot", "rb");
|
||||||
|
#else
|
||||||
FILE *file = fopen("callback_chain.wasm", "rb");
|
FILE *file = fopen("callback_chain.wasm", "rb");
|
||||||
|
#endif
|
||||||
if (!file) {
|
if (!file) {
|
||||||
printf("> Error loading module!\n");
|
printf("> Error loading module!\n");
|
||||||
return 1;
|
return 1;
|
||||||
|
|
|
@ -56,15 +56,26 @@ int main(int argc, const char* argv[]) {
|
||||||
|
|
||||||
wasm_byte_vec_delete(&binary);
|
wasm_byte_vec_delete(&binary);
|
||||||
|
|
||||||
|
// Create external print functions.
|
||||||
|
printf("Creating callback...\n");
|
||||||
|
own wasm_functype_t* hello_type = wasm_functype_new_0_0();
|
||||||
|
own wasm_func_t* hello_func =
|
||||||
|
wasm_func_new(store, hello_type, hello_callback);
|
||||||
|
|
||||||
|
wasm_functype_delete(hello_type);
|
||||||
|
|
||||||
// Instantiate.
|
// Instantiate.
|
||||||
printf("Instantiating module...\n");
|
printf("Instantiating module...\n");
|
||||||
|
const wasm_extern_t* imports[] = { wasm_func_as_extern(hello_func) };
|
||||||
own wasm_instance_t* instance =
|
own wasm_instance_t* instance =
|
||||||
wasm_instance_new(store, module, NULL, NULL);
|
wasm_instance_new(store, module, imports, NULL);
|
||||||
if (!instance) {
|
if (!instance) {
|
||||||
printf("> Error instantiating module!\n");
|
printf("> Error instantiating module!\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wasm_func_delete(hello_func);
|
||||||
|
|
||||||
// Extract export.
|
// Extract export.
|
||||||
printf("Extracting export...\n");
|
printf("Extracting export...\n");
|
||||||
own wasm_extern_vec_t exports;
|
own wasm_extern_vec_t exports;
|
||||||
|
@ -74,9 +85,22 @@ int main(int argc, const char* argv[]) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const wasm_func_t* run_func = wasm_extern_as_func(exports.data[0]);
|
||||||
|
if (run_func == NULL) {
|
||||||
|
printf("> Error accessing export!\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
wasm_module_delete(module);
|
wasm_module_delete(module);
|
||||||
wasm_instance_delete(instance);
|
wasm_instance_delete(instance);
|
||||||
|
|
||||||
|
// Call.
|
||||||
|
printf("Calling export...\n");
|
||||||
|
if (wasm_func_call(run_func, NULL, NULL)) {
|
||||||
|
printf("> Error calling function!\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
wasm_extern_vec_delete(&exports);
|
wasm_extern_vec_delete(&exports);
|
||||||
|
|
||||||
// Shut down.
|
// Shut down.
|
||||||
|
|
Loading…
Reference in New Issue
Block a user