Skip to content

Commit

Permalink
Add two apis for wasm function call (#375)
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
qinxk-inter authored Sep 8, 2020
1 parent 2135bad commit 5418e09
Show file tree
Hide file tree
Showing 5 changed files with 359 additions and 3 deletions.
221 changes: 221 additions & 0 deletions core/iwasm/common/wasm_runtime_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -863,6 +863,227 @@ wasm_runtime_call_wasm(WASMExecEnv *exec_env,
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
wasm_runtime_create_exec_env_and_call_wasm(WASMModuleInstanceCommon *module_inst,
WASMFunctionInstanceCommon *function,
Expand Down
12 changes: 12 additions & 0 deletions core/iwasm/common/wasm_runtime_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,18 @@ wasm_runtime_call_wasm(WASMExecEnv *exec_env,
WASMFunctionInstanceCommon *function,
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
* arguments.
Expand Down
6 changes: 6 additions & 0 deletions core/iwasm/include/wasm_c_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,8 @@ static const uint32_t wasm_limits_max_default = 0xffffffff;

WASM_DECLARE_TYPE(valtype)

#ifndef WASM_VALKIND_T_DEFINED
#define WASM_VALKIND_T_DEFINED
typedef uint8_t wasm_valkind_t;
enum wasm_valkind_enum {
WASM_I32,
Expand All @@ -174,6 +176,7 @@ enum wasm_valkind_enum {
WASM_ANYREF = 128,
WASM_FUNCREF,
};
#endif

WASM_API_EXTERN own wasm_valtype_t* wasm_valtype_new(wasm_valkind_t);

Expand Down Expand Up @@ -299,6 +302,8 @@ WASM_API_EXTERN const wasm_externtype_t* wasm_exporttype_type(const wasm_exportt

// Values

#ifndef WASM_VAL_T_DEFINED
#define WASM_VAL_T_DEFINED
struct wasm_ref_t;

typedef struct wasm_val_t {
Expand All @@ -311,6 +316,7 @@ typedef struct wasm_val_t {
struct wasm_ref_t* ref;
} of;
} wasm_val_t;
#endif

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*);
Expand Down
73 changes: 73 additions & 0 deletions core/iwasm/include/wasm_export.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,35 @@ typedef struct RuntimeInitArgs {
uint32_t max_thread_num;
} 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
* the memory allocator with system allocator, which calls os_malloc
Expand Down Expand Up @@ -385,6 +414,50 @@ wasm_runtime_call_wasm(wasm_exec_env_t exec_env,
wasm_function_inst_t function,
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
* and execute that function.
Expand Down
Loading

0 comments on commit 5418e09

Please sign in to comment.