Add wasm-c-api nested function calls sample (#652)

And enable to copy back the return value of wasm main function when calling wasm_application_execute_main, add license headers in wasm-c-api samples, fix several issues reported by klocwork.
This commit is contained in:
Wenyong Huang 2021-06-16 15:26:28 +08:00 committed by GitHub
parent 1a4aa5ac2f
commit 77c71e559a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 357 additions and 9 deletions

View File

@ -182,6 +182,10 @@ wasm_application_execute_main(WASMModuleInstanceCommon *module_inst,
ret = wasm_runtime_create_exec_env_and_call_wasm(module_inst, func, ret = wasm_runtime_create_exec_env_and_call_wasm(module_inst, func,
argc1, argv1); argc1, argv1);
if (ret && func_type->result_count > 0 && argc > 0 && argv)
/* copy the return value */
*(int*)argv = (int)argv1[0];
if (argv_buf_offset) if (argv_buf_offset)
wasm_runtime_module_free(module_inst, argv_buf_offset); wasm_runtime_module_free(module_inst, argv_buf_offset);
return ret; return ret;
@ -669,4 +673,4 @@ fail:
bh_assert(exception); bh_assert(exception);
os_printf("%s\n", exception); os_printf("%s\n", exception);
return false; return false;
} }

View File

@ -495,7 +495,9 @@ wasm_runtime_call_wasm_v(wasm_exec_env_t exec_env,
* *
* @param module_inst the WASM module instance * @param module_inst the WASM module instance
* @param argc the number of arguments * @param argc the number of arguments
* @param argv the arguments array * @param argv the arguments array, if the main function has return value,
* *(int*)argv stores the return value of the called main function after
* this function returns.
* *
* @return true if the main function is called, false otherwise and exception * @return true if the main function is called, false otherwise and exception
* will be thrown, the caller can call wasm_runtime_get_exception to get * will be thrown, the caller can call wasm_runtime_get_exception to get

View File

@ -26,6 +26,7 @@ void *thread(void* arg)
func = wasm_runtime_lookup_function(module_inst, "sum", NULL); func = wasm_runtime_lookup_function(module_inst, "sum", NULL);
if (!func) { if (!func) {
printf("failed to lookup function sum"); printf("failed to lookup function sum");
return NULL;
} }
argv[0] = thread_arg->start; argv[0] = thread_arg->start;
argv[1] = thread_arg->length; argv[1] = thread_arg->length;
@ -49,6 +50,7 @@ void *wamr_thread_cb(wasm_exec_env_t exec_env, void *arg)
func = wasm_runtime_lookup_function(module_inst, "sum", NULL); func = wasm_runtime_lookup_function(module_inst, "sum", NULL);
if (!func) { if (!func) {
printf("failed to lookup function sum"); printf("failed to lookup function sum");
return NULL;
} }
argv[0] = thread_arg->start; argv[0] = thread_arg->start;
argv[1] = thread_arg->length; argv[1] = thread_arg->length;
@ -66,7 +68,7 @@ int main(int argc, char *argv[])
{ {
char *wasm_file = "wasm-apps/test.wasm"; char *wasm_file = "wasm-apps/test.wasm";
uint8 *wasm_file_buf = NULL; uint8 *wasm_file_buf = NULL;
uint32 wasm_file_size, wasm_argv[2], i; uint32 wasm_file_size, wasm_argv[2], i, threads_created;
uint32 stack_size = 16 * 1024, heap_size = 16 * 1024; uint32 stack_size = 16 * 1024, heap_size = 16 * 1024;
wasm_module_t wasm_module = NULL; wasm_module_t wasm_module = NULL;
wasm_module_inst_t wasm_module_inst = NULL; wasm_module_inst_t wasm_module_inst = NULL;
@ -123,6 +125,7 @@ int main(int argc, char *argv[])
func = wasm_runtime_lookup_function(wasm_module_inst, "sum", NULL); func = wasm_runtime_lookup_function(wasm_module_inst, "sum", NULL);
if (!func) { if (!func) {
printf("failed to lookup function sum"); printf("failed to lookup function sum");
goto fail5;
} }
wasm_argv[0] = 0; wasm_argv[0] = 0;
wasm_argv[1] = THREAD_NUM * 10; wasm_argv[1] = THREAD_NUM * 10;
@ -159,17 +162,20 @@ int main(int argc, char *argv[])
if (0 != pthread_create(&tid[i], NULL, thread, &thread_arg[i])) { if (0 != pthread_create(&tid[i], NULL, thread, &thread_arg[i])) {
printf("failed to create thread.\n"); printf("failed to create thread.\n");
wasm_runtime_destroy_spawned_exec_env(new_exec_env);
break; break;
} }
} }
threads_created = i;
sum = 0; sum = 0;
memset(result, 0, sizeof(uint32) * THREAD_NUM); memset(result, 0, sizeof(uint32) * THREAD_NUM);
for (i = 0; i < THREAD_NUM; i++) { for (i = 0; i < threads_created; i++) {
pthread_join(tid[i], (void **)&result[i]); pthread_join(tid[i], (void **)&result[i]);
sum += result[i]; sum += result[i];
/* destroy the spawned exec_env */ /* destroy the spawned exec_env */
if (thread_arg[0].exec_env) if (thread_arg[i].exec_env)
wasm_runtime_destroy_spawned_exec_env(thread_arg[i].exec_env); wasm_runtime_destroy_spawned_exec_env(thread_arg[i].exec_env);
} }
@ -191,15 +197,18 @@ int main(int argc, char *argv[])
} }
} }
threads_created = i;
sum = 0; sum = 0;
memset(result, 0, sizeof(uint32) * THREAD_NUM); memset(result, 0, sizeof(uint32) * THREAD_NUM);
for (i = 0; i < THREAD_NUM; i++) { for (i = 0; i < threads_created; i++) {
wasm_runtime_join_thread(wasm_tid[i], (void**)&result[i]); wasm_runtime_join_thread(wasm_tid[i], (void**)&result[i]);
sum += result[i]; sum += result[i];
/* No need to destroy the spawned exec_env */ /* No need to destroy the spawned exec_env */
} }
printf("[spwan_thread]sum result: %d\n", sum); printf("[spwan_thread]sum result: %d\n", sum);
fail5:
wasm_runtime_destroy_exec_env(exec_env); wasm_runtime_destroy_exec_env(exec_env);
fail4: fail4:
@ -217,4 +226,5 @@ fail2:
fail1: fail1:
/* destroy runtime environment */ /* destroy runtime environment */
wasm_runtime_destroy(); wasm_runtime_destroy();
} return 0;
}

View File

@ -93,8 +93,7 @@ set(EXAMPLES
global global
reflect reflect
trap trap
# multi # AOT/JIT return multiple values callback_chain
# globalexportimport # AOT/JIT doesn't suppport MULTI_MODULE
) )
foreach(EX ${EXAMPLES}) foreach(EX ${EXAMPLES})

View File

@ -84,6 +84,7 @@ int main(int argc, const char* argv[]) {
wasm_byte_vec_new_uninitialized(&binary, file_size); wasm_byte_vec_new_uninitialized(&binary, file_size);
if (fread(binary.data, file_size, 1, file) != 1) { if (fread(binary.data, file_size, 1, file) != 1) {
printf("> Error loading module!\n"); printf("> Error loading module!\n");
fclose(file);
return 1; return 1;
} }
fclose(file); fclose(file);

View File

@ -0,0 +1,267 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include "wasm_c_api.h"
#define own
static const byte_t *
get_memory_data(uint32_t offset, uint32_t length);
static bool
call_wasm_function(uint32_t export_id,
const wasm_val_t *args,
wasm_val_t *results,
const char *name);
/************************ IMPORTED FUNCTIONS **************************/
// (nil) -> i32
#define FUNCTION_TYPE_NIL_I32 wasm_functype_new_0_1(wasm_valtype_new_i32())
// (i32, i32) -> nil
#define FUNCTION_TYPE_I32X2_NIL \
wasm_functype_new_1_1(wasm_valtype_new_i32(), wasm_valtype_new_i32())
/* IMPORT FUNCTION LIST */
#define IMPORT_FUNCTION_LIST(V) \
V(get_pairs, 0, FUNCTION_TYPE_NIL_I32) \
V(log, 1, FUNCTION_TYPE_I32X2_NIL)
/* EXPORT FUNCTION LIST */
#define EXPORT_FUNCTION_LIST(V) \
V(on_start) \
V(on_stop) \
V(malloc) \
V(free)
enum EXPORT_ITEM_NAME {
#define DEFINE_ENUM(name) e_##name,
EXPORT_FUNCTION_LIST(DEFINE_ENUM)
#undef DEFINE_ENUM
e_MEMORY,
};
#define DEFINE_FUNCTION(name) \
wasm_trap_t *STUB_##name(const wasm_val_t args[], wasm_val_t results[])
#define DEFINE_EMPTY_FUNCTION(name) \
DEFINE_FUNCTION(name) \
{ \
printf("[WASM -> NATIVE] calling back %s\n", __FUNCTION__); \
return NULL; \
}
#undef DEFINE_EMPTY_FUNCTION
DEFINE_FUNCTION(get_pairs)
{
wasm_val_t ret[1] = { WASM_INIT_VAL };
call_wasm_function(e_malloc, (wasm_val_t[]){ WASM_I32_VAL(24) }, ret,
"malloc");
return NULL;
}
DEFINE_FUNCTION(log)
{
wasm_val_t offset = args[0];
wasm_val_t length = args[1];
const byte_t *data = NULL;
printf("[WASM -> NATIVE] calling back %s\n", __FUNCTION__);
if (offset.kind != WASM_I32 || length.kind != WASM_I32) {
printf("> Error value type!\n");
}
if (!(data = get_memory_data(offset.of.i32, length.of.i32))) {
return NULL;
}
if (data[length.of.i32]) {
printf("> Error terminated character\n");
return NULL;
}
printf("[WASM_LOG] %s\n", data);
return NULL;
}
static inline void
create_import_function_list(wasm_store_t *store,
const wasm_extern_t *import_function_list[])
{
#define IMPORT_FUNCTION_VARIABLE_NAME(name, ...) \
own wasm_func_t *function_##name = NULL;
IMPORT_FUNCTION_LIST(IMPORT_FUNCTION_VARIABLE_NAME)
#undef IMPORT_FUNCTION_VARIABLE_NAME
#define CREATE_WASM_FUNCTION(name, index, CREATE_FUNC_TYPE) \
{ \
own wasm_functype_t *type = CREATE_FUNC_TYPE; \
if (!(function_##name = wasm_func_new(store, type, STUB_##name))) { \
printf("> Error creating new function\n"); \
} \
wasm_functype_delete(type); \
}
IMPORT_FUNCTION_LIST(CREATE_WASM_FUNCTION)
#undef CREATE_WASM_FUNCTION
#define ADD_TO_FUNCTION_LIST(name, index, ...) \
import_function_list[index] = wasm_func_as_extern(function_##name);
IMPORT_FUNCTION_LIST(ADD_TO_FUNCTION_LIST)
#undef CREATE_IMPORT_FUNCTION
}
/**********************************************************************/
// all exportted wasm functions. check with "/opt/wabt/bin/wasm-objdump -x -j Export X.wasm"
// -1: memory
// 0-32: functions
static own wasm_extern_vec_t exports = { 0 };
static const byte_t *
get_memory_data(uint32_t offset, uint32_t length)
{
wasm_memory_t *memory;
if (!(memory = wasm_extern_as_memory(exports.data[e_MEMORY]))) {
return NULL;
}
byte_t *base = wasm_memory_data(memory);
size_t size = wasm_memory_data_size(memory);
if (!base || offset + length > size) {
return NULL;
}
printf("[NATIVE -> WASM] accessing the memory...\n");
return base + offset;
}
static bool
call_wasm_function(uint32_t export_id,
const wasm_val_t *args,
wasm_val_t *results,
const char *name)
{
const wasm_func_t *function;
wasm_trap_t *trap;
printf("[NATIVE -> WASM] calling func %s...\n", name);
if (!(function = wasm_extern_as_func(exports.data[export_id]))) {
printf("> Error get export function %u\n", export_id);
return false;
}
if ((trap = wasm_func_call(function, args, results))) {
own wasm_message_t message = { 0 };
wasm_trap_message(trap, &message);
if (message.data) {
printf("> Error calling function %s\n", message.data);
}
else {
printf("> Error calling function");
}
wasm_name_delete(&message);
wasm_trap_delete(trap);
return false;
}
return true;
}
int
main(int argc, const char *argv[])
{
// Initialize.
printf("Initializing...\n");
wasm_engine_t *engine = wasm_engine_new();
wasm_store_t *store = wasm_store_new(engine);
// Load binary.
printf("Loading binary...\n");
FILE *file = fopen("callback_chain.wasm", "rb");
if (!file) {
printf("> Error loading module!\n");
return 1;
}
fseek(file, 0L, SEEK_END);
size_t file_size = ftell(file);
fseek(file, 0L, SEEK_SET);
wasm_byte_vec_t binary;
wasm_byte_vec_new_uninitialized(&binary, file_size);
if (fread(binary.data, file_size, 1, file) != 1) {
printf("> Error loading module!\n");
fclose(file);
return 1;
}
fclose(file);
// Compile.
printf("Compiling module...\n");
own wasm_module_t *module = wasm_module_new(store, &binary);
if (!module) {
printf("> Error compiling module!\n");
return 1;
}
wasm_byte_vec_delete(&binary);
// Instantiate.
printf("Instantiating module...\n");
const wasm_extern_t *imports[10] = { 0 };
// Create external functions.
printf("Creating callback...\n");
create_import_function_list(store, imports);
own wasm_instance_t *instance =
wasm_instance_new(store, module, imports, NULL);
if (!instance) {
printf("> Error instantiating module!\n");
return 1;
}
// Extract export.
printf("Extracting export...\n");
wasm_instance_exports(instance, &exports);
if (!exports.size) {
printf("> Error accessing exports!\n");
return 1;
}
wasm_module_delete(module);
wasm_instance_delete(instance);
// Call.
printf("Calling export...\n");
if (!call_wasm_function(e_on_start, NULL, NULL, "on_start")) {
printf("> Error calling on_start\n");
return 1;
}
if (!call_wasm_function(e_on_stop, NULL, NULL, "on_stop")) {
printf("> Error calling on_stop\n");
return 1;
}
wasm_extern_vec_delete(&exports);
// Shut down.
printf("Shutting down...\n");
wasm_store_delete(store);
wasm_engine_delete(engine);
// All done.
printf("Done.\n");
return 0;
}

View File

@ -0,0 +1,32 @@
;; Copyright (C) 2019 Intel Corporation. All rights reserved.
;; SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
(module
(func $get_pairs (import "" "get_pairs") (result i32))
(func $log (import"" "log") (param i32 i32))
(func $on_start (export "on_start")
(call $log (i32.const 0) (i32.const 9))
(call $get_pairs)
(drop)
)
(func $on_stop (export "on_stop")
(call $log (i32.const 9) (i32.const 8))
)
(func $malloc (export "malloc") (param i32) (result i32)
(call $log (i32.const 17) (i32.const 7))
(i32.const 64)
)
(func $free(export "free") (param i32)
(call $log (i32.const 24) (i32.const 5))
)
(memory (export "memory") 1)
(data (i32.const 0) "on_start")
(data (i32.const 9) "on_stop")
(data (i32.const 17) "malloc")
(data (i32.const 24) "free")
)

View File

@ -69,6 +69,7 @@ int main(int argc, const char* argv[]) {
wasm_byte_vec_new_uninitialized(&binary, file_size); wasm_byte_vec_new_uninitialized(&binary, file_size);
if (fread(binary.data, file_size, 1, file) != 1) { if (fread(binary.data, file_size, 1, file) != 1) {
printf("> Error loading module!\n"); printf("> Error loading module!\n");
fclose(file);
return 1; return 1;
} }
fclose(file); fclose(file);

View File

@ -1,3 +1,6 @@
;; Copyright (C) 2019 Intel Corporation. All rights reserved.
;; SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
(module (module
(global $mut_f32_export (export "var f32") (mut f32) (f32.const 7)) (global $mut_f32_export (export "var f32") (mut f32) (f32.const 7))
(func (export "get var f32 export") (result f32) (global.get $mut_f32_export)) (func (export "get var f32 export") (result f32) (global.get $mut_f32_export))

View File

@ -1,3 +1,6 @@
;; Copyright (C) 2019 Intel Corporation. All rights reserved.
;; SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
(module (module
(global $mut_f32_import (export "var f32") (import "globalexportimport-0" "var f32") (mut f32)) (global $mut_f32_import (export "var f32") (import "globalexportimport-0" "var f32") (mut f32))
(func (export "get var f32 export") (import "globalexportimport-0" "get var f32 export") (result f32)) (func (export "get var f32 export") (import "globalexportimport-0" "get var f32 export") (result f32))

View File

@ -1,3 +1,8 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -62,6 +67,7 @@ wasm_module_t * create_module_from_file(wasm_store_t* store, const char * filena
wasm_byte_vec_new_uninitialized(&binary, file_size); wasm_byte_vec_new_uninitialized(&binary, file_size);
if (fread(binary.data, file_size, 1, file) != 1) { if (fread(binary.data, file_size, 1, file) != 1) {
printf("> Error loading module!\n"); printf("> Error loading module!\n");
fclose(file);
return NULL; return NULL;
} }
// Compile. // Compile.

View File

@ -41,6 +41,7 @@ int main(int argc, const char* argv[]) {
wasm_byte_vec_new_uninitialized(&binary, file_size); wasm_byte_vec_new_uninitialized(&binary, file_size);
if (fread(binary.data, file_size, 1, file) != 1) { if (fread(binary.data, file_size, 1, file) != 1) {
printf("> Error loading module!\n"); printf("> Error loading module!\n");
fclose(file);
return 1; return 1;
} }
fclose(file); fclose(file);

View File

@ -59,6 +59,7 @@ int main(int argc, const char* argv[]) {
wasm_byte_vec_new_uninitialized(&binary, file_size); wasm_byte_vec_new_uninitialized(&binary, file_size);
if (fread(binary.data, file_size, 1, file) != 1) { if (fread(binary.data, file_size, 1, file) != 1) {
printf("> Error loading module!\n"); printf("> Error loading module!\n");
fclose(file);
return 1; return 1;
} }
fclose(file); fclose(file);

View File

@ -32,6 +32,12 @@ void print_valtype(const wasm_valtype_t* type) {
void print_valtypes(const wasm_valtype_vec_t* types) { void print_valtypes(const wasm_valtype_vec_t* types) {
bool first = true; bool first = true;
if (!types) {
printf("> Error print a NULL valtype\n");
return;
}
for (size_t i = 0; i < types->size; ++i) { for (size_t i = 0; i < types->size; ++i) {
if (first) { if (first) {
first = false; first = false;
@ -43,6 +49,11 @@ void print_valtypes(const wasm_valtype_vec_t* types) {
} }
void print_externtype(const wasm_externtype_t* type) { void print_externtype(const wasm_externtype_t* type) {
if (!type) {
printf("> Error print a NULL externtype\n");
return;
}
switch (wasm_externtype_kind(type)) { switch (wasm_externtype_kind(type)) {
case WASM_EXTERN_FUNC: { case WASM_EXTERN_FUNC: {
const wasm_functype_t* functype = const wasm_functype_t* functype =
@ -78,6 +89,11 @@ void print_externtype(const wasm_externtype_t* type) {
} }
void print_name(const wasm_name_t* name) { 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); printf("\"%.*s\"", (int)name->size, name->data);
} }
@ -106,6 +122,7 @@ int main(int argc, const char* argv[]) {
wasm_byte_vec_new_uninitialized(&binary, file_size); wasm_byte_vec_new_uninitialized(&binary, file_size);
if (fread(binary.data, file_size, 1, file) != 1) { if (fread(binary.data, file_size, 1, file) != 1) {
printf("> Error loading module!\n"); printf("> Error loading module!\n");
fclose(file);
return 1; return 1;
} }
fclose(file); fclose(file);

View File

@ -43,6 +43,7 @@ int main(int argc, const char* argv[]) {
wasm_byte_vec_new_uninitialized(&binary, file_size); wasm_byte_vec_new_uninitialized(&binary, file_size);
if (fread(binary.data, file_size, 1, file) != 1) { if (fread(binary.data, file_size, 1, file) != 1) {
printf("> Error loading module!\n"); printf("> Error loading module!\n");
fclose(file);
return 1; return 1;
} }
fclose(file); fclose(file);