mirror of
https://github.com/bytecodealliance/wasm-micro-runtime.git
synced 2025-05-08 20:56:13 +00:00
Add two apis for wasm function call (#375)
Add below two apis: bool wasm_runtime_call_wasm_a(WASMExecEnv *exec_env, WASMFunctionInstanceCommon *function, uint32 num_results, wasm_val_t results[], uint32 num_args, wasm_val_t args[]) bool wasm_runtime_call_wasm_v(WASMExecEnv *exec_env, WASMFunctionInstanceCommon *function, uint32 num_results, wasm_val_t results[], uint32 num_args, ...) Signed-off-by: Xiaokang Qin <xiaokang.qxk@antgroup.com>
This commit is contained in:
parent
2135badc54
commit
5418e09712
|
@ -863,6 +863,227 @@ wasm_runtime_call_wasm(WASMExecEnv *exec_env,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint32
|
||||||
|
parse_args_to_uint32_array(WASMType *type,
|
||||||
|
uint32 num_args, wasm_val_t *args,
|
||||||
|
uint32 *out_argv)
|
||||||
|
{
|
||||||
|
int i, p;
|
||||||
|
|
||||||
|
for (i = 0, p = 0; i < num_args; i++) {
|
||||||
|
switch (args[i].kind) {
|
||||||
|
case WASM_I32:
|
||||||
|
out_argv[p++] = args[i].of.i32;
|
||||||
|
break;
|
||||||
|
case WASM_I64:
|
||||||
|
{
|
||||||
|
union { uint64 val; uint32 parts[2]; } u;
|
||||||
|
u.val = args[i].of.i64;
|
||||||
|
out_argv[p++] = u.parts[0];
|
||||||
|
out_argv[p++] = u.parts[1];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WASM_F32:
|
||||||
|
{
|
||||||
|
union { float32 val; uint32 part; } u;
|
||||||
|
u.val = args[i].of.f32;
|
||||||
|
out_argv[p++] = u.part;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WASM_F64:
|
||||||
|
{
|
||||||
|
union { float64 val; uint32 parts[2]; } u;
|
||||||
|
u.val = args[i].of.f64;
|
||||||
|
out_argv[p++] = u.parts[0];
|
||||||
|
out_argv[p++] = u.parts[1];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
bh_assert(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32
|
||||||
|
parse_uint32_array_to_results(WASMType *type,
|
||||||
|
uint32 argc, uint32 *argv,
|
||||||
|
wasm_val_t *out_results)
|
||||||
|
{
|
||||||
|
int i, p;
|
||||||
|
|
||||||
|
for (i = 0, p = 0; i < type->result_count; i++) {
|
||||||
|
switch (type->types[type->param_count + i]) {
|
||||||
|
case VALUE_TYPE_I32:
|
||||||
|
out_results[i].kind = WASM_I32;
|
||||||
|
out_results[i].of.i32 = *(int32 *)argv[p++];
|
||||||
|
break;
|
||||||
|
case VALUE_TYPE_I64:
|
||||||
|
{
|
||||||
|
union { uint64 val; uint32 parts[2]; } u;
|
||||||
|
u.parts[0] = argv[p++];
|
||||||
|
u.parts[1] = argv[p++];
|
||||||
|
out_results[i].kind = WASM_I64;
|
||||||
|
out_results[i].of.i64 = u.val;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case VALUE_TYPE_F32:
|
||||||
|
{
|
||||||
|
union { float32 val; uint32 part; } u;
|
||||||
|
u.part = argv[p++];
|
||||||
|
out_results[i].kind = WASM_F32;
|
||||||
|
out_results[i].of.f32 = u.val;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case VALUE_TYPE_F64:
|
||||||
|
{
|
||||||
|
union { float64 val; uint32 parts[2]; } u;
|
||||||
|
u.parts[0] = argv[p++];
|
||||||
|
u.parts[1] = argv[p++];
|
||||||
|
out_results[i].kind = WASM_F64;
|
||||||
|
out_results[i].of.f64 = u.val;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
bh_assert(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bh_assert(argc == p);
|
||||||
|
return type->result_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
wasm_runtime_call_wasm_a(WASMExecEnv *exec_env,
|
||||||
|
WASMFunctionInstanceCommon *function,
|
||||||
|
uint32 num_results, wasm_val_t results[],
|
||||||
|
uint32 num_args, wasm_val_t args[])
|
||||||
|
{
|
||||||
|
uint32 argc, *argv, ret_num, cell_num, total_size;
|
||||||
|
bool ret = false;
|
||||||
|
WASMType *type = NULL;
|
||||||
|
|
||||||
|
#if WASM_ENABLE_INTERP != 0
|
||||||
|
if (exec_env->module_inst->module_type == Wasm_Module_Bytecode) {
|
||||||
|
WASMFunctionInstance *wasm_func = (WASMFunctionInstance*)function;
|
||||||
|
type = wasm_func->u.func->func_type;
|
||||||
|
argc = wasm_func->param_cell_num;
|
||||||
|
cell_num = argc > wasm_func->ret_cell_num ?
|
||||||
|
argc : wasm_func->ret_cell_num;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if WASM_ENABLE_AOT != 0
|
||||||
|
if (exec_env->module_inst->module_type == Wasm_Module_AoT) {
|
||||||
|
type = ((AOTFunctionInstance*)function)->u.func.func_type;
|
||||||
|
argc = type->param_cell_num;
|
||||||
|
cell_num = argc > type->ret_cell_num ?
|
||||||
|
argc : type->ret_cell_num;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (!type) {
|
||||||
|
LOG_ERROR("Function type get failed, WAMR Interpreter and AOT must be enabled at least one.");
|
||||||
|
goto fail1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (num_results != type->result_count) {
|
||||||
|
LOG_ERROR("The result value number does not match the function declaration.");
|
||||||
|
goto fail1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (num_args != type->param_count) {
|
||||||
|
LOG_ERROR("The argument value number does not match the function declaration.");
|
||||||
|
goto fail1;
|
||||||
|
}
|
||||||
|
|
||||||
|
total_size = sizeof(uint32) * (uint64)(cell_num > 2 ? cell_num : 2);
|
||||||
|
if (!(argv = runtime_malloc((uint32)total_size, exec_env->module_inst, NULL, 0))) {
|
||||||
|
wasm_runtime_set_exception(exec_env->module_inst, "allocate memory failed");
|
||||||
|
goto fail1;
|
||||||
|
}
|
||||||
|
|
||||||
|
argc = parse_args_to_uint32_array(type, num_args, args, argv);
|
||||||
|
if (!(ret = wasm_runtime_call_wasm(exec_env, function, argc, argv)))
|
||||||
|
goto fail2;
|
||||||
|
|
||||||
|
ret_num = parse_uint32_array_to_results(type, type->ret_cell_num, argv, results);
|
||||||
|
bh_assert(ret_num == num_results);
|
||||||
|
|
||||||
|
fail2:
|
||||||
|
wasm_runtime_free(argv);
|
||||||
|
fail1:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
wasm_runtime_call_wasm_v(WASMExecEnv *exec_env,
|
||||||
|
WASMFunctionInstanceCommon *function,
|
||||||
|
uint32 num_results, wasm_val_t results[],
|
||||||
|
uint32 num_args, ...)
|
||||||
|
{
|
||||||
|
wasm_val_t *args = NULL;
|
||||||
|
WASMType *type = NULL;
|
||||||
|
bool ret = false;
|
||||||
|
int i = 0;
|
||||||
|
va_list vargs;
|
||||||
|
|
||||||
|
#if WASM_ENABLE_INTERP != 0
|
||||||
|
if (exec_env->module_inst->module_type == Wasm_Module_Bytecode) {
|
||||||
|
WASMFunctionInstance *wasm_func = (WASMFunctionInstance*)function;
|
||||||
|
type = wasm_func->u.func->func_type;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if WASM_ENABLE_AOT != 0
|
||||||
|
if (exec_env->module_inst->module_type == Wasm_Module_AoT) {
|
||||||
|
type = ((AOTFunctionInstance*)function)->u.func.func_type;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (!type) {
|
||||||
|
LOG_ERROR("Function type get failed, WAMR Interpreter and AOT must be enabled at least one.");
|
||||||
|
goto fail1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (num_args != type->param_count) {
|
||||||
|
LOG_ERROR("The argument value number does not match the function declaration.");
|
||||||
|
goto fail1;
|
||||||
|
}
|
||||||
|
if (!(args = runtime_malloc(sizeof(wasm_val_t) * num_args, NULL, NULL, 0))) {
|
||||||
|
wasm_runtime_set_exception(exec_env->module_inst, "allocate memory failed");
|
||||||
|
goto fail1;
|
||||||
|
}
|
||||||
|
|
||||||
|
va_start(vargs, num_args);
|
||||||
|
for (i = 0; i < num_args; i++) {
|
||||||
|
switch (type->types[i]) {
|
||||||
|
case VALUE_TYPE_I32:
|
||||||
|
args[i].kind = WASM_I32;
|
||||||
|
args[i].of.i32 = va_arg(vargs, uint32);
|
||||||
|
break;
|
||||||
|
case VALUE_TYPE_I64:
|
||||||
|
args[i].kind = WASM_I64;
|
||||||
|
args[i].of.i64 = va_arg(vargs, uint64);
|
||||||
|
break;
|
||||||
|
case VALUE_TYPE_F32:
|
||||||
|
args[i].kind = WASM_F32;
|
||||||
|
args[i].of.f32 = (float32)va_arg(vargs, float64);
|
||||||
|
break;
|
||||||
|
case VALUE_TYPE_F64:
|
||||||
|
args[i].kind = WASM_F64;
|
||||||
|
args[i].of.f64 = va_arg(vargs, float64);;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
bh_assert(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
va_end(vargs);
|
||||||
|
ret = wasm_runtime_call_wasm_a(exec_env, function, num_results, results, num_args, args);
|
||||||
|
wasm_runtime_free(args);
|
||||||
|
|
||||||
|
fail1:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
wasm_runtime_create_exec_env_and_call_wasm(WASMModuleInstanceCommon *module_inst,
|
wasm_runtime_create_exec_env_and_call_wasm(WASMModuleInstanceCommon *module_inst,
|
||||||
WASMFunctionInstanceCommon *function,
|
WASMFunctionInstanceCommon *function,
|
||||||
|
|
|
@ -167,6 +167,18 @@ wasm_runtime_call_wasm(WASMExecEnv *exec_env,
|
||||||
WASMFunctionInstanceCommon *function,
|
WASMFunctionInstanceCommon *function,
|
||||||
uint32 argc, uint32 argv[]);
|
uint32 argc, uint32 argv[]);
|
||||||
|
|
||||||
|
bool
|
||||||
|
wasm_runtime_call_wasm_a(WASMExecEnv *exec_env,
|
||||||
|
WASMFunctionInstanceCommon *function,
|
||||||
|
uint32 num_results, wasm_val_t *results,
|
||||||
|
uint32 num_args, wasm_val_t *args);
|
||||||
|
|
||||||
|
bool
|
||||||
|
wasm_runtime_call_wasm_v(WASMExecEnv *exec_env,
|
||||||
|
WASMFunctionInstanceCommon *function,
|
||||||
|
uint32 num_results, wasm_val_t *results,
|
||||||
|
uint32 num_args, ...);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Call a function reference of a given WASM runtime instance with
|
* Call a function reference of a given WASM runtime instance with
|
||||||
* arguments.
|
* arguments.
|
||||||
|
|
|
@ -165,6 +165,8 @@ static const uint32_t wasm_limits_max_default = 0xffffffff;
|
||||||
|
|
||||||
WASM_DECLARE_TYPE(valtype)
|
WASM_DECLARE_TYPE(valtype)
|
||||||
|
|
||||||
|
#ifndef WASM_VALKIND_T_DEFINED
|
||||||
|
#define WASM_VALKIND_T_DEFINED
|
||||||
typedef uint8_t wasm_valkind_t;
|
typedef uint8_t wasm_valkind_t;
|
||||||
enum wasm_valkind_enum {
|
enum wasm_valkind_enum {
|
||||||
WASM_I32,
|
WASM_I32,
|
||||||
|
@ -174,6 +176,7 @@ enum wasm_valkind_enum {
|
||||||
WASM_ANYREF = 128,
|
WASM_ANYREF = 128,
|
||||||
WASM_FUNCREF,
|
WASM_FUNCREF,
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
WASM_API_EXTERN own wasm_valtype_t* wasm_valtype_new(wasm_valkind_t);
|
WASM_API_EXTERN own wasm_valtype_t* wasm_valtype_new(wasm_valkind_t);
|
||||||
|
|
||||||
|
@ -299,6 +302,8 @@ WASM_API_EXTERN const wasm_externtype_t* wasm_exporttype_type(const wasm_exportt
|
||||||
|
|
||||||
// Values
|
// Values
|
||||||
|
|
||||||
|
#ifndef WASM_VAL_T_DEFINED
|
||||||
|
#define WASM_VAL_T_DEFINED
|
||||||
struct wasm_ref_t;
|
struct wasm_ref_t;
|
||||||
|
|
||||||
typedef struct wasm_val_t {
|
typedef struct wasm_val_t {
|
||||||
|
@ -311,6 +316,7 @@ typedef struct wasm_val_t {
|
||||||
struct wasm_ref_t* ref;
|
struct wasm_ref_t* ref;
|
||||||
} of;
|
} of;
|
||||||
} wasm_val_t;
|
} wasm_val_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
WASM_API_EXTERN void wasm_val_delete(own wasm_val_t* v);
|
WASM_API_EXTERN void wasm_val_delete(own wasm_val_t* v);
|
||||||
WASM_API_EXTERN void wasm_val_copy(own wasm_val_t* out, const wasm_val_t*);
|
WASM_API_EXTERN void wasm_val_copy(own wasm_val_t* out, const wasm_val_t*);
|
||||||
|
|
|
@ -120,6 +120,35 @@ typedef struct RuntimeInitArgs {
|
||||||
uint32_t max_thread_num;
|
uint32_t max_thread_num;
|
||||||
} RuntimeInitArgs;
|
} RuntimeInitArgs;
|
||||||
|
|
||||||
|
#ifndef WASM_VALKIND_T_DEFINED
|
||||||
|
#define WASM_VALKIND_T_DEFINED
|
||||||
|
typedef uint8_t wasm_valkind_t;
|
||||||
|
enum wasm_valkind_enum {
|
||||||
|
WASM_I32,
|
||||||
|
WASM_I64,
|
||||||
|
WASM_F32,
|
||||||
|
WASM_F64,
|
||||||
|
WASM_ANYREF = 128,
|
||||||
|
WASM_FUNCREF,
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef WASM_VAL_T_DEFINED
|
||||||
|
#define WASM_VAL_T_DEFINED
|
||||||
|
struct wasm_ref_t;
|
||||||
|
|
||||||
|
typedef struct wasm_val_t {
|
||||||
|
wasm_valkind_t kind;
|
||||||
|
union {
|
||||||
|
int32_t i32;
|
||||||
|
int64_t i64;
|
||||||
|
float f32;
|
||||||
|
double f64;
|
||||||
|
struct wasm_ref_t* ref;
|
||||||
|
} of;
|
||||||
|
} wasm_val_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the WASM runtime environment, and also initialize
|
* Initialize the WASM runtime environment, and also initialize
|
||||||
* the memory allocator with system allocator, which calls os_malloc
|
* the memory allocator with system allocator, which calls os_malloc
|
||||||
|
@ -385,6 +414,50 @@ wasm_runtime_call_wasm(wasm_exec_env_t exec_env,
|
||||||
wasm_function_inst_t function,
|
wasm_function_inst_t function,
|
||||||
uint32_t argc, uint32_t argv[]);
|
uint32_t argc, uint32_t argv[]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call the given WASM function of a WASM module instance with
|
||||||
|
* provided results space and arguments (bytecode and AoT).
|
||||||
|
*
|
||||||
|
* @param exec_env the execution environment to call the function,
|
||||||
|
* which must be created from wasm_create_exec_env()
|
||||||
|
* @param function the function to call
|
||||||
|
* @param num_results the number of results
|
||||||
|
* @param results the pre-alloced pointer to get the results
|
||||||
|
* @param num_args the number of arguments
|
||||||
|
* @param args the arguments
|
||||||
|
*
|
||||||
|
* @return true if success, false otherwise and exception will be thrown,
|
||||||
|
* the caller can call wasm_runtime_get_exception to get the exception
|
||||||
|
* info.
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
wasm_runtime_call_wasm_a(wasm_exec_env_t exec_env,
|
||||||
|
wasm_function_inst_t function,
|
||||||
|
uint32_t num_results, wasm_val_t results[],
|
||||||
|
uint32_t num_args, wasm_val_t *args);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call the given WASM function of a WASM module instance with
|
||||||
|
* provided results space and variant arguments (bytecode and AoT).
|
||||||
|
*
|
||||||
|
* @param exec_env the execution environment to call the function,
|
||||||
|
* which must be created from wasm_create_exec_env()
|
||||||
|
* @param function the function to call
|
||||||
|
* @param num_results the number of results
|
||||||
|
* @param results the pre-alloced pointer to get the results
|
||||||
|
* @param num_args the number of arguments
|
||||||
|
* @param ... the variant arguments
|
||||||
|
*
|
||||||
|
* @return true if success, false otherwise and exception will be thrown,
|
||||||
|
* the caller can call wasm_runtime_get_exception to get the exception
|
||||||
|
* info.
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
wasm_runtime_call_wasm_v(wasm_exec_env_t exec_env,
|
||||||
|
wasm_function_inst_t function,
|
||||||
|
uint32_t num_results, wasm_val_t results[],
|
||||||
|
uint32_t num_args, ...);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find the unique main function from a WASM module instance
|
* Find the unique main function from a WASM module instance
|
||||||
* and execute that function.
|
* and execute that function.
|
||||||
|
|
|
@ -71,17 +71,23 @@ if (!wasm_runtime_full_init(&init_args)) {
|
||||||
|
|
||||||
## Native calls WASM functions and passes parameters
|
## Native calls WASM functions and passes parameters
|
||||||
|
|
||||||
After a module is instantiated, the runtime native can lookup WASM functions by the names and call them.
|
After a module is instantiated, the runtime embedder can lookup the target WASM function by name, and create execution environment to call the function.
|
||||||
|
|
||||||
```c
|
```c
|
||||||
unit32 argv[2];
|
|
||||||
|
|
||||||
/* lookup a WASM function by its name
|
/* lookup a WASM function by its name
|
||||||
The function signature can NULL here */
|
The function signature can NULL here */
|
||||||
func = wasm_runtime_lookup_function(module_inst, "fib", NULL);
|
func = wasm_runtime_lookup_function(module_inst, "fib", NULL);
|
||||||
|
|
||||||
/* creat an execution environment to execute the WASM functions */
|
/* creat an execution environment to execute the WASM functions */
|
||||||
exec_env = wasm_runtime_create_exec_env(module_inst, stack_size);
|
exec_env = wasm_runtime_create_exec_env(module_inst, stack_size);
|
||||||
|
```
|
||||||
|
|
||||||
|
There are several ways to call WASM function:
|
||||||
|
|
||||||
|
1. Function call with parameters in an array of 32 bits elements and size:
|
||||||
|
|
||||||
|
```c
|
||||||
|
unit32 argv[2];
|
||||||
|
|
||||||
/* arguments are always transferred in 32-bit element */
|
/* arguments are always transferred in 32-bit element */
|
||||||
argv[0] = 8;
|
argv[0] = 8;
|
||||||
|
@ -129,6 +135,44 @@ The parameters are transferred in an array of 32 bits elements. For parameters t
|
||||||
memcpy(&ret, &argv[0], sizeof(ret));
|
memcpy(&ret, &argv[0], sizeof(ret));
|
||||||
```
|
```
|
||||||
|
|
||||||
|
2. Function call with results and arguments both in `wasm_val_t` struct and size:
|
||||||
|
|
||||||
|
```c
|
||||||
|
unit32 num_args = 1, num_results = 1;
|
||||||
|
wasm_val_t args[1], results[1];
|
||||||
|
|
||||||
|
/* set the argument type and value */
|
||||||
|
args[0].kind = WASM_I32;
|
||||||
|
args[0].of.i32 = 8;
|
||||||
|
|
||||||
|
/* call the WASM function */
|
||||||
|
if (wasm_runtime_call_wasm_a(exec_env, func, num_results, results, num_args, args)) {
|
||||||
|
/* the return value is stored in results */
|
||||||
|
printf("fib function return: %d\n", results[0].of.i32);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* exception is thrown if call fails */
|
||||||
|
printf("%s\n", wasm_runtime_get_exception(module_inst));
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Function call with variant argument support:
|
||||||
|
|
||||||
|
```c
|
||||||
|
unit32 num_args = 1, num_results = 1;
|
||||||
|
wasm_val_t results[1];
|
||||||
|
|
||||||
|
/* call the WASM function */
|
||||||
|
if (wasm_runtime_call_wasm_v(exec_env, func, 1, results, 1, 8)) {
|
||||||
|
/* the return value is stored in results */
|
||||||
|
printf("fib function return: %d\n", results[0].of.i32);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* exception is thrown if call fails */
|
||||||
|
printf("%s\n", wasm_runtime_get_exception(module_inst));
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Pass buffer to WASM function
|
## Pass buffer to WASM function
|
||||||
|
|
||||||
If we need to transfer a buffer to WASM function, we can pass the buffer address through a parameter. **Attention**: The sandbox will forbid the WASM code to access outside memory, we must **allocate the buffer from WASM instance's own memory space and pass the buffer address in instance's space (not the runtime native address)**.
|
If we need to transfer a buffer to WASM function, we can pass the buffer address through a parameter. **Attention**: The sandbox will forbid the WASM code to access outside memory, we must **allocate the buffer from WASM instance's own memory space and pass the buffer address in instance's space (not the runtime native address)**.
|
||||||
|
|
Loading…
Reference in New Issue
Block a user