From 77c71e559aa40298e7b9f9a09e1319c31a9cfaca Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Wed, 16 Jun 2021 15:26:28 +0800 Subject: [PATCH] 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. --- core/iwasm/common/wasm_application.c | 6 +- core/iwasm/include/wasm_export.h | 4 +- samples/spawn-thread/src/main.c | 20 +- samples/wasm-c-api/CMakeLists.txt | 3 +- samples/wasm-c-api/src/callback.c | 1 + samples/wasm-c-api/src/callback_chain.c | 267 ++++++++++++++++++ samples/wasm-c-api/src/callback_chain.wat | 32 +++ samples/wasm-c-api/src/global.c | 1 + .../wasm-c-api/src/globalexportimport-0.wat | 3 + .../wasm-c-api/src/globalexportimport-1.wat | 3 + samples/wasm-c-api/src/globalexportimport.c | 6 + samples/wasm-c-api/src/hello.c | 1 + samples/wasm-c-api/src/multi.c | 1 + samples/wasm-c-api/src/reflect.c | 17 ++ samples/wasm-c-api/src/trap.c | 1 + 15 files changed, 357 insertions(+), 9 deletions(-) create mode 100644 samples/wasm-c-api/src/callback_chain.c create mode 100644 samples/wasm-c-api/src/callback_chain.wat diff --git a/core/iwasm/common/wasm_application.c b/core/iwasm/common/wasm_application.c index 01ae4f9a..b3e979fc 100644 --- a/core/iwasm/common/wasm_application.c +++ b/core/iwasm/common/wasm_application.c @@ -182,6 +182,10 @@ wasm_application_execute_main(WASMModuleInstanceCommon *module_inst, ret = wasm_runtime_create_exec_env_and_call_wasm(module_inst, func, 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) wasm_runtime_module_free(module_inst, argv_buf_offset); return ret; @@ -669,4 +673,4 @@ fail: bh_assert(exception); os_printf("%s\n", exception); return false; -} \ No newline at end of file +} diff --git a/core/iwasm/include/wasm_export.h b/core/iwasm/include/wasm_export.h index b56e7b14..a4394adb 100644 --- a/core/iwasm/include/wasm_export.h +++ b/core/iwasm/include/wasm_export.h @@ -495,7 +495,9 @@ wasm_runtime_call_wasm_v(wasm_exec_env_t exec_env, * * @param module_inst the WASM module instance * @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 * will be thrown, the caller can call wasm_runtime_get_exception to get diff --git a/samples/spawn-thread/src/main.c b/samples/spawn-thread/src/main.c index c1d15050..6df1042d 100644 --- a/samples/spawn-thread/src/main.c +++ b/samples/spawn-thread/src/main.c @@ -26,6 +26,7 @@ void *thread(void* arg) func = wasm_runtime_lookup_function(module_inst, "sum", NULL); if (!func) { printf("failed to lookup function sum"); + return NULL; } argv[0] = thread_arg->start; 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); if (!func) { printf("failed to lookup function sum"); + return NULL; } argv[0] = thread_arg->start; argv[1] = thread_arg->length; @@ -66,7 +68,7 @@ int main(int argc, char *argv[]) { char *wasm_file = "wasm-apps/test.wasm"; 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; wasm_module_t wasm_module = 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); if (!func) { printf("failed to lookup function sum"); + goto fail5; } wasm_argv[0] = 0; 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])) { printf("failed to create thread.\n"); + wasm_runtime_destroy_spawned_exec_env(new_exec_env); break; } } + threads_created = i; + sum = 0; 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]); sum += result[i]; /* 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); } @@ -191,15 +197,18 @@ int main(int argc, char *argv[]) } } + threads_created = i; + sum = 0; 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]); sum += result[i]; /* No need to destroy the spawned exec_env */ } printf("[spwan_thread]sum result: %d\n", sum); +fail5: wasm_runtime_destroy_exec_env(exec_env); fail4: @@ -217,4 +226,5 @@ fail2: fail1: /* destroy runtime environment */ wasm_runtime_destroy(); -} \ No newline at end of file + return 0; +} diff --git a/samples/wasm-c-api/CMakeLists.txt b/samples/wasm-c-api/CMakeLists.txt index fa509473..75dd8053 100644 --- a/samples/wasm-c-api/CMakeLists.txt +++ b/samples/wasm-c-api/CMakeLists.txt @@ -93,8 +93,7 @@ set(EXAMPLES global reflect trap - # multi # AOT/JIT return multiple values - # globalexportimport # AOT/JIT doesn't suppport MULTI_MODULE + callback_chain ) foreach(EX ${EXAMPLES}) diff --git a/samples/wasm-c-api/src/callback.c b/samples/wasm-c-api/src/callback.c index bd8d17ec..e350edc6 100644 --- a/samples/wasm-c-api/src/callback.c +++ b/samples/wasm-c-api/src/callback.c @@ -84,6 +84,7 @@ int main(int argc, const char* argv[]) { 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); diff --git a/samples/wasm-c-api/src/callback_chain.c b/samples/wasm-c-api/src/callback_chain.c new file mode 100644 index 00000000..d6f933ac --- /dev/null +++ b/samples/wasm-c-api/src/callback_chain.c @@ -0,0 +1,267 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include +#include +#include +#include + +#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; +} diff --git a/samples/wasm-c-api/src/callback_chain.wat b/samples/wasm-c-api/src/callback_chain.wat new file mode 100644 index 00000000..b29cf8a4 --- /dev/null +++ b/samples/wasm-c-api/src/callback_chain.wat @@ -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") +) \ No newline at end of file diff --git a/samples/wasm-c-api/src/global.c b/samples/wasm-c-api/src/global.c index b1747d68..5a3b3f4c 100644 --- a/samples/wasm-c-api/src/global.c +++ b/samples/wasm-c-api/src/global.c @@ -69,6 +69,7 @@ int main(int argc, const char* argv[]) { 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); diff --git a/samples/wasm-c-api/src/globalexportimport-0.wat b/samples/wasm-c-api/src/globalexportimport-0.wat index a3f072cf..7ab897c7 100644 --- a/samples/wasm-c-api/src/globalexportimport-0.wat +++ b/samples/wasm-c-api/src/globalexportimport-0.wat @@ -1,3 +1,6 @@ +;; Copyright (C) 2019 Intel Corporation. All rights reserved. +;; SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + (module (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)) diff --git a/samples/wasm-c-api/src/globalexportimport-1.wat b/samples/wasm-c-api/src/globalexportimport-1.wat index e0c608d3..927e420d 100644 --- a/samples/wasm-c-api/src/globalexportimport-1.wat +++ b/samples/wasm-c-api/src/globalexportimport-1.wat @@ -1,3 +1,6 @@ +;; Copyright (C) 2019 Intel Corporation. All rights reserved. +;; SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + (module (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)) diff --git a/samples/wasm-c-api/src/globalexportimport.c b/samples/wasm-c-api/src/globalexportimport.c index 076b632e..c8f58b49 100644 --- a/samples/wasm-c-api/src/globalexportimport.c +++ b/samples/wasm-c-api/src/globalexportimport.c @@ -1,3 +1,8 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + #include #include #include @@ -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); if (fread(binary.data, file_size, 1, file) != 1) { printf("> Error loading module!\n"); + fclose(file); return NULL; } // Compile. diff --git a/samples/wasm-c-api/src/hello.c b/samples/wasm-c-api/src/hello.c index cc5aa53e..72c7b263 100644 --- a/samples/wasm-c-api/src/hello.c +++ b/samples/wasm-c-api/src/hello.c @@ -41,6 +41,7 @@ int main(int argc, const char* argv[]) { 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); diff --git a/samples/wasm-c-api/src/multi.c b/samples/wasm-c-api/src/multi.c index 8291ff9b..65c9afd4 100644 --- a/samples/wasm-c-api/src/multi.c +++ b/samples/wasm-c-api/src/multi.c @@ -59,6 +59,7 @@ int main(int argc, const char* argv[]) { 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); diff --git a/samples/wasm-c-api/src/reflect.c b/samples/wasm-c-api/src/reflect.c index 746613ab..a90fa2aa 100644 --- a/samples/wasm-c-api/src/reflect.c +++ b/samples/wasm-c-api/src/reflect.c @@ -32,6 +32,12 @@ 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; @@ -43,6 +49,11 @@ 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 = @@ -78,6 +89,11 @@ 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); } @@ -106,6 +122,7 @@ int main(int argc, const char* argv[]) { 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); diff --git a/samples/wasm-c-api/src/trap.c b/samples/wasm-c-api/src/trap.c index 2829dd2e..e1214190 100644 --- a/samples/wasm-c-api/src/trap.c +++ b/samples/wasm-c-api/src/trap.c @@ -43,6 +43,7 @@ int main(int argc, const char* argv[]) { 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);