From b0b8843719919616521545d4a9d09f6099bcd509 Mon Sep 17 00:00:00 2001 From: Enrico Loparco Date: Wed, 25 Jan 2023 02:53:40 +0100 Subject: [PATCH 01/33] Implement opcode atomic.wait and atomic.notify for Fast JIT (#1914) --- core/iwasm/fast-jit/fe/jit_emit_memory.c | 93 +++++++++++++++++++++++- core/iwasm/fast-jit/jit_compiler.c | 8 ++ 2 files changed, 100 insertions(+), 1 deletion(-) diff --git a/core/iwasm/fast-jit/fe/jit_emit_memory.c b/core/iwasm/fast-jit/fe/jit_emit_memory.c index 568766da..b71d98ba 100644 --- a/core/iwasm/fast-jit/fe/jit_emit_memory.c +++ b/core/iwasm/fast-jit/fe/jit_emit_memory.c @@ -135,7 +135,8 @@ check_and_seek(JitCompContext *cc, JitReg addr, uint32 offset, uint32 bytes) #ifndef OS_ENABLE_HW_BOUND_CHECK /* ---------- check ---------- */ /* 1. shortcut if the memory size is 0 */ - if (0 == cc->cur_wasm_module->memories[mem_idx].init_page_count) { + if (cc->cur_wasm_module->memories != NULL + && 0 == cc->cur_wasm_module->memories[mem_idx].init_page_count) { JitReg module_inst, cur_page_count; uint32 cur_page_count_offset = (uint32)offsetof(WASMModuleInstance, global_table_data.bytes) @@ -176,6 +177,18 @@ fail: return 0; } +#define CHECK_ALIGNMENT(maddr, memory_data, offset1) \ + do { \ + GEN_INSN(ADD, maddr, memory_data, offset1); \ + JitReg align_mask = NEW_CONST(I64, ((uint64)1 << align) - 1); \ + JitReg AND_res = jit_cc_new_reg_I64(cc); \ + GEN_INSN(AND, AND_res, maddr, align_mask); \ + GEN_INSN(CMP, cc->cmp_reg, AND_res, NEW_CONST(I64, 0)); \ + if (!jit_emit_exception(cc, EXCE_UNALIGNED_ATOMIC, JIT_OP_BNE, \ + cc->cmp_reg, NULL)) \ + goto fail; \ + } while (0) + bool jit_compile_op_i32_load(JitCompContext *cc, uint32 align, uint32 offset, uint32 bytes, bool sign, bool atomic) @@ -779,6 +792,51 @@ bool jit_compile_op_atomic_wait(JitCompContext *cc, uint8 op_type, uint32 align, uint32 offset, uint32 bytes) { + bh_assert(op_type == VALUE_TYPE_I32 || op_type == VALUE_TYPE_I64); + + // Pop atomic.wait arguments + JitReg timeout, expect, expect_64, addr; + POP_I64(timeout); + if (op_type == VALUE_TYPE_I32) { + POP_I32(expect); + expect_64 = jit_cc_new_reg_I64(cc); + GEN_INSN(I32TOI64, expect_64, expect); + } + else { + POP_I64(expect_64); + } + POP_I32(addr); + + // Get referenced address and store it in `maddr` + JitReg memory_data = get_memory_data_reg(cc->jit_frame, 0); + JitReg offset1 = check_and_seek(cc, addr, offset, bytes); + if (!offset1) + goto fail; + JitReg maddr = jit_cc_new_reg_I64(cc); + CHECK_ALIGNMENT(maddr, memory_data, offset1); + + // Prepare `wasm_runtime_atomic_wait` arguments + JitReg res = jit_cc_new_reg_I32(cc); + JitReg args[5] = { 0 }; + args[0] = get_module_inst_reg(cc->jit_frame); + args[1] = maddr; + args[2] = expect_64; + args[3] = timeout; + args[4] = NEW_CONST(I32, false); + + if (!jit_emit_callnative(cc, wasm_runtime_atomic_wait, res, args, + sizeof(args) / sizeof(args[0]))) + goto fail; + + // Handle return code + GEN_INSN(CMP, cc->cmp_reg, res, NEW_CONST(I32, -1)); + if (!jit_emit_exception(cc, EXCE_ALREADY_THROWN, JIT_OP_BEQ, cc->cmp_reg, + NULL)) + goto fail; + + PUSH_I32(res); + return true; +fail: return false; } @@ -786,6 +844,39 @@ bool jit_compiler_op_atomic_notify(JitCompContext *cc, uint32 align, uint32 offset, uint32 bytes) { + // Pop atomic.notify arguments + JitReg notify_count, addr; + POP_I32(notify_count); + POP_I32(addr); + + // Get referenced address and store it in `maddr` + JitReg memory_data = get_memory_data_reg(cc->jit_frame, 0); + JitReg offset1 = check_and_seek(cc, addr, offset, bytes); + if (!offset1) + goto fail; + JitReg maddr = jit_cc_new_reg_I64(cc); + CHECK_ALIGNMENT(maddr, memory_data, offset1); + + // Prepare `wasm_runtime_atomic_notify` arguments + JitReg res = jit_cc_new_reg_I32(cc); + JitReg args[3] = { 0 }; + args[0] = get_module_inst_reg(cc->jit_frame); + args[1] = maddr; + args[2] = notify_count; + + if (!jit_emit_callnative(cc, wasm_runtime_atomic_notify, res, args, + sizeof(args) / sizeof(args[0]))) + goto fail; + + // Handle return code + GEN_INSN(CMP, cc->cmp_reg, res, NEW_CONST(I32, 0)); + if (!jit_emit_exception(cc, EXCE_ALREADY_THROWN, JIT_OP_BLTS, cc->cmp_reg, + NULL)) + goto fail; + + PUSH_I32(res); + return true; +fail: return false; } #endif diff --git a/core/iwasm/fast-jit/jit_compiler.c b/core/iwasm/fast-jit/jit_compiler.c index 67dcb7b5..bba4566c 100644 --- a/core/iwasm/fast-jit/jit_compiler.c +++ b/core/iwasm/fast-jit/jit_compiler.c @@ -157,8 +157,16 @@ jit_compiler_compile(WASMModule *module, uint32 func_idx) /* Apply compiler passes */ if (!apply_compiler_passes(cc) || jit_get_last_error(cc)) { last_error = jit_get_last_error(cc); + +#if WASM_ENABLE_CUSTOM_NAME_SECTION != 0 + char *function_name = cc->cur_wasm_func->field_name; + os_printf("fast jit compilation failed: %s (function_name=%s)\n", + last_error ? last_error : "unknown error", function_name); +#else os_printf("fast jit compilation failed: %s\n", last_error ? last_error : "unknown error"); +#endif + goto fail; } From 965edff4dfe16d76e53751cc12052fae35d2db9b Mon Sep 17 00:00:00 2001 From: Patryk Date: Wed, 25 Jan 2023 04:07:25 +0100 Subject: [PATCH 02/33] Remove unused variable in handle_cmd_unload_module (#1913) --- .../platforms/linux-sgx/enclave-sample/Enclave/Enclave.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.cpp b/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.cpp index 7cb9c3f4..30274359 100644 --- a/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.cpp +++ b/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.cpp @@ -277,7 +277,6 @@ static void handle_cmd_unload_module(uint64 *args, uint32 argc) { EnclaveModule *enclave_module = *(EnclaveModule **)args++; - uint32 i; bh_assert(argc == 1); From 9eed6686dfcfb3ff0efbdde5506cc9889894d4b2 Mon Sep 17 00:00:00 2001 From: tonibofarull Date: Wed, 25 Jan 2023 11:32:40 +0100 Subject: [PATCH 03/33] Refactor WASI-NN to simplify the support for multiple frameworks (#1834) - Reorganize the library structure - Use the latest version of `wasi-nn` wit (Oct 25, 2022): https://github.com/WebAssembly/wasi-nn/blob/0f77c48ec195748990ff67928a4b3eef5f16c2de/wasi-nn.wit.md - Split logic that converts WASM structs to native structs in a separate file - Simplify addition of new frameworks --- build-scripts/runtime_lib.cmake | 10 +- core/iwasm/aot/aot_runtime.c | 20 ++ core/iwasm/aot/aot_runtime.h | 7 + core/iwasm/interpreter/wasm_runtime.c | 18 ++ core/iwasm/interpreter/wasm_runtime.h | 8 + core/iwasm/libraries/wasi-nn/.dockerignore | 1 - core/iwasm/libraries/wasi-nn/README.md | 10 +- core/iwasm/libraries/wasi-nn/logger.h | 55 ---- .../libraries/wasi-nn/src/utils/logger.h | 63 ++++ .../wasi-nn/src/utils/wasi_nn_app_native.c | 163 ++++++++++ .../wasi-nn/src/utils/wasi_nn_app_native.h | 51 +++ core/iwasm/libraries/wasi-nn/src/wasi_nn.c | 302 ++++++++++++++++++ .../libraries/wasi-nn/src/wasi_nn_private.h | 30 ++ .../wasi_nn_tensorflowlite.cpp} | 58 ++-- .../wasi-nn/src/wasi_nn_tensorflowlite.hpp | 41 +++ .../libraries/wasi-nn/test/.dockerignore | 1 + core/iwasm/libraries/wasi-nn/test/Dockerfile | 16 +- .../libraries/wasi-nn/test/test_tensorflow.c | 15 +- core/iwasm/libraries/wasi-nn/wasi_nn.cmake | 11 +- core/iwasm/libraries/wasi-nn/wasi_nn.h | 81 ++--- core/iwasm/libraries/wasi-nn/wasi_nn_common.h | 44 --- core/iwasm/libraries/wasi-nn/wasi_nn_native.c | 264 --------------- .../libraries/wasi-nn/wasi_nn_tensorflow.hpp | 40 --- core/iwasm/libraries/wasi-nn/wasi_nn_types.h | 106 ++++++ 24 files changed, 911 insertions(+), 504 deletions(-) delete mode 100644 core/iwasm/libraries/wasi-nn/.dockerignore delete mode 100644 core/iwasm/libraries/wasi-nn/logger.h create mode 100644 core/iwasm/libraries/wasi-nn/src/utils/logger.h create mode 100644 core/iwasm/libraries/wasi-nn/src/utils/wasi_nn_app_native.c create mode 100644 core/iwasm/libraries/wasi-nn/src/utils/wasi_nn_app_native.h create mode 100644 core/iwasm/libraries/wasi-nn/src/wasi_nn.c create mode 100644 core/iwasm/libraries/wasi-nn/src/wasi_nn_private.h rename core/iwasm/libraries/wasi-nn/{wasi_nn_tensorflow.cpp => src/wasi_nn_tensorflowlite.cpp} (76%) create mode 100644 core/iwasm/libraries/wasi-nn/src/wasi_nn_tensorflowlite.hpp create mode 100644 core/iwasm/libraries/wasi-nn/test/.dockerignore delete mode 100644 core/iwasm/libraries/wasi-nn/wasi_nn_common.h delete mode 100644 core/iwasm/libraries/wasi-nn/wasi_nn_native.c delete mode 100644 core/iwasm/libraries/wasi-nn/wasi_nn_tensorflow.hpp create mode 100644 core/iwasm/libraries/wasi-nn/wasi_nn_types.h diff --git a/build-scripts/runtime_lib.cmake b/build-scripts/runtime_lib.cmake index ac3f4144..1aea9591 100644 --- a/build-scripts/runtime_lib.cmake +++ b/build-scripts/runtime_lib.cmake @@ -96,9 +96,13 @@ if (WAMR_BUILD_LIB_PTHREAD_SEMAPHORE EQUAL 1) endif () if (WAMR_BUILD_WASI_NN EQUAL 1) - execute_process(COMMAND ${WAMR_ROOT_DIR}/core/deps/install_tensorflow.sh - RESULT_VARIABLE TENSORFLOW_RESULT - ) + if (NOT EXISTS "${WAMR_ROOT_DIR}/core/deps/tensorflow-src") + execute_process(COMMAND ${WAMR_ROOT_DIR}/core/deps/install_tensorflow.sh + RESULT_VARIABLE TENSORFLOW_RESULT + ) + else () + message("Tensorflow is already downloaded.") + endif() set(TENSORFLOW_SOURCE_DIR "${WAMR_ROOT_DIR}/core/deps/tensorflow-src") include_directories (${CMAKE_CURRENT_BINARY_DIR}/flatbuffers/include) include_directories (${TENSORFLOW_SOURCE_DIR}) diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index 5fa5438b..8ae33a47 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -1083,6 +1083,17 @@ aot_instantiate(AOTModule *module, bool is_sub_inst, uint32 stack_size, } #endif +#if WASM_ENABLE_WASI_NN != 0 + if (!is_sub_inst) { + if (!(((AOTModuleInstanceExtra *)module_inst->e)->wasi_nn_ctx = + wasi_nn_initialize())) { + set_error_buf(error_buf, error_buf_size, + "wasi nn initialization failed"); + goto fail; + } + } +#endif + /* Initialize the thread related data */ if (stack_size == 0) stack_size = DEFAULT_WASM_STACK_SIZE; @@ -1194,6 +1205,15 @@ aot_deinstantiate(AOTModuleInstance *module_inst, bool is_sub_inst) wasm_runtime_free( ((AOTModuleInstanceExtra *)module_inst->e)->c_api_func_imports); +#if WASM_ENABLE_WASI_NN != 0 + if (!is_sub_inst) { + WASINNContext *wasi_nn_ctx = + ((AOTModuleInstanceExtra *)module_inst->e)->wasi_nn_ctx; + if (wasi_nn_ctx) + wasi_nn_destroy(wasi_nn_ctx); + } +#endif + wasm_runtime_free(module_inst); } diff --git a/core/iwasm/aot/aot_runtime.h b/core/iwasm/aot/aot_runtime.h index a6371729..de12bdaa 100644 --- a/core/iwasm/aot/aot_runtime.h +++ b/core/iwasm/aot/aot_runtime.h @@ -11,6 +11,10 @@ #include "../interpreter/wasm_runtime.h" #include "../compilation/aot.h" +#if WASM_ENABLE_WASI_NN != 0 +#include "../libraries/wasi-nn/src/wasi_nn_private.h" +#endif + #ifdef __cplusplus extern "C" { #endif @@ -75,6 +79,9 @@ typedef struct AOTFunctionInstance { typedef struct AOTModuleInstanceExtra { CApiFuncImport *c_api_func_imports; +#if WASM_ENABLE_WASI_NN != 0 + WASINNContext *wasi_nn_ctx; +#endif } AOTModuleInstanceExtra; #if defined(OS_ENABLE_HW_BOUND_CHECK) && defined(BH_PLATFORM_WINDOWS) diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index 27b3c985..ff3f4f2f 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -1803,6 +1803,16 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, uint32 stack_size, } #endif +#if WASM_ENABLE_WASI_NN != 0 + if (!is_sub_inst) { + if (!(module_inst->e->wasi_nn_ctx = wasi_nn_initialize())) { + set_error_buf(error_buf, error_buf_size, + "wasi nn initialization failed"); + goto fail; + } + } +#endif + #if WASM_ENABLE_DEBUG_INTERP != 0 \ || (WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \ && WASM_ENABLE_LAZY_JIT != 0) @@ -1984,6 +1994,14 @@ wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst) if (module_inst->e->c_api_func_imports) wasm_runtime_free(module_inst->e->c_api_func_imports); +#if WASM_ENABLE_WASI_NN != 0 + if (!is_sub_inst) { + WASINNContext *wasi_nn_ctx = module_inst->e->wasi_nn_ctx; + if (wasi_nn_ctx) + wasi_nn_destroy(wasi_nn_ctx); + } +#endif + wasm_runtime_free(module_inst); } diff --git a/core/iwasm/interpreter/wasm_runtime.h b/core/iwasm/interpreter/wasm_runtime.h index 5bf09bb8..89c5bbee 100644 --- a/core/iwasm/interpreter/wasm_runtime.h +++ b/core/iwasm/interpreter/wasm_runtime.h @@ -11,6 +11,10 @@ #include "../common/wasm_runtime_common.h" #include "../common/wasm_exec_env.h" +#if WASM_ENABLE_WASI_NN != 0 +#include "../libraries/wasi-nn/src/wasi_nn_private.h" +#endif + #ifdef __cplusplus extern "C" { #endif @@ -242,6 +246,10 @@ typedef struct WASMModuleInstanceExtra { && WASM_ENABLE_LAZY_JIT != 0) WASMModuleInstance *next; #endif + +#if WASM_ENABLE_WASI_NN != 0 + WASINNContext *wasi_nn_ctx; +#endif } WASMModuleInstanceExtra; struct AOTFuncPerfProfInfo; diff --git a/core/iwasm/libraries/wasi-nn/.dockerignore b/core/iwasm/libraries/wasi-nn/.dockerignore deleted file mode 100644 index 0e2be498..00000000 --- a/core/iwasm/libraries/wasi-nn/.dockerignore +++ /dev/null @@ -1 +0,0 @@ -**/Dockerfile diff --git a/core/iwasm/libraries/wasi-nn/README.md b/core/iwasm/libraries/wasi-nn/README.md index 22ef13db..ed3fbd54 100644 --- a/core/iwasm/libraries/wasi-nn/README.md +++ b/core/iwasm/libraries/wasi-nn/README.md @@ -37,7 +37,11 @@ Tests: passed! ## What is missing -* Only 1 model at a time is supported. +Supported: + +* Only 1 WASM app at a time. +* Only 1 model at a time. * `graph` and `graph-execution-context` are ignored. -* Only `tensorflow` (lite) is supported. -* Only `cpu` is supported. +* Graph encoding: `tensorflowlite`. +* Execution target: `cpu`. +* Tensor type: `fp32`. diff --git a/core/iwasm/libraries/wasi-nn/logger.h b/core/iwasm/libraries/wasi-nn/logger.h deleted file mode 100644 index 25588eb6..00000000 --- a/core/iwasm/libraries/wasi-nn/logger.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2019 Intel Corporation. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - */ - -#ifndef WASI_NN_LOGGER_H -#define WASI_NN_LOGGER_H - -#include -#include - -#define __FILENAME__ \ - (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) - -/* Disable a level by removing the define */ -#define ENABLE_ERR_LOG -#define ENABLE_WARN_LOG -#define ENABLE_DBG_LOG -#define ENABLE_INFO_LOG - -// Definition of the levels -#ifdef ENABLE_ERR_LOG -#define NN_ERR_PRINTF(fmt, ...) \ - printf("[%s:%d] " fmt, __FILENAME__, __LINE__, ##__VA_ARGS__); \ - printf("\n"); \ - fflush(stdout) -#else -#define NN_ERR_PRINTF(fmt, ...) -#endif -#ifdef ENABLE_WARN_LOG -#define NN_WARN_PRINTF(fmt, ...) \ - printf("[%s:%d] " fmt, __FILENAME__, __LINE__, ##__VA_ARGS__); \ - printf("\n"); \ - fflush(stdout) -#else -#define NN_WARN_PRINTF(fmt, ...) -#endif -#ifdef ENABLE_DBG_LOG -#define NN_DBG_PRINTF(fmt, ...) \ - printf("[%s:%d] " fmt, __FILENAME__, __LINE__, ##__VA_ARGS__); \ - printf("\n"); \ - fflush(stdout) -#else -#define NN_DBG_PRINTF(fmt, ...) -#endif -#ifdef ENABLE_INFO_LOG -#define NN_INFO_PRINTF(fmt, ...) \ - printf("[%s:%d] " fmt, __FILENAME__, __LINE__, ##__VA_ARGS__); \ - printf("\n"); \ - fflush(stdout) -#else -#define NN_INFO_PRINTF(fmt, ...) -#endif - -#endif diff --git a/core/iwasm/libraries/wasi-nn/src/utils/logger.h b/core/iwasm/libraries/wasi-nn/src/utils/logger.h new file mode 100644 index 00000000..55128213 --- /dev/null +++ b/core/iwasm/libraries/wasi-nn/src/utils/logger.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef WASI_NN_LOGGER_H +#define WASI_NN_LOGGER_H + +#include +#include + +#define __FILENAME__ \ + (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) + +/* Disable a level by removing the define */ +#define ENABLE_ERR_LOG +#define ENABLE_WARN_LOG +#define ENABLE_DBG_LOG +#define ENABLE_INFO_LOG + +// Definition of the levels +#ifdef ENABLE_ERR_LOG +#define NN_ERR_PRINTF(fmt, ...) \ + do { \ + printf("[%s:%d] " fmt, __FILENAME__, __LINE__, ##__VA_ARGS__); \ + printf("\n"); \ + fflush(stdout); \ + } while (0) +#else +#define NN_ERR_PRINTF(fmt, ...) +#endif +#ifdef ENABLE_WARN_LOG +#define NN_WARN_PRINTF(fmt, ...) \ + do { \ + printf("[%s:%d] " fmt, __FILENAME__, __LINE__, ##__VA_ARGS__); \ + printf("\n"); \ + fflush(stdout); \ + } while (0) +#else +#define NN_WARN_PRINTF(fmt, ...) +#endif +#ifdef ENABLE_DBG_LOG +#define NN_DBG_PRINTF(fmt, ...) \ + do { \ + printf("[%s:%d] " fmt, __FILENAME__, __LINE__, ##__VA_ARGS__); \ + printf("\n"); \ + fflush(stdout); \ + } while (0) +#else +#define NN_DBG_PRINTF(fmt, ...) +#endif +#ifdef ENABLE_INFO_LOG +#define NN_INFO_PRINTF(fmt, ...) \ + do { \ + printf("[%s:%d] " fmt, __FILENAME__, __LINE__, ##__VA_ARGS__); \ + printf("\n"); \ + fflush(stdout); \ + } while (0) +#else +#define NN_INFO_PRINTF(fmt, ...) +#endif + +#endif diff --git a/core/iwasm/libraries/wasi-nn/src/utils/wasi_nn_app_native.c b/core/iwasm/libraries/wasi-nn/src/utils/wasi_nn_app_native.c new file mode 100644 index 00000000..fe04b657 --- /dev/null +++ b/core/iwasm/libraries/wasi-nn/src/utils/wasi_nn_app_native.c @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "wasi_nn_app_native.h" + +static error +graph_builder_app_native(wasm_module_inst_t instance, + graph_builder_wasm *builder_wasm, + graph_builder *builder) +{ + if (!wasm_runtime_validate_app_addr(instance, builder_wasm->buf_offset, + builder_wasm->size * sizeof(uint8_t))) { + NN_ERR_PRINTF("builder_wasm->buf_offset is invalid"); + return invalid_argument; + } + + builder->buf = (uint8_t *)wasm_runtime_addr_app_to_native( + instance, builder_wasm->buf_offset); + builder->size = builder_wasm->size; + return success; +} + +error +graph_builder_array_app_native(wasm_module_inst_t instance, + graph_builder_array_wasm *builder_array_wasm, + graph_builder_array *builder_array) +{ + if (!wasm_runtime_validate_native_addr(instance, builder_array_wasm, + sizeof(graph_builder_array_wasm))) { + NN_ERR_PRINTF("builder_array_wasm is invalid"); + return invalid_argument; + } + + NN_DBG_PRINTF("Graph builder array contains %d elements", + builder_array_wasm->size); + + if (!wasm_runtime_validate_app_addr( + instance, builder_array_wasm->buf_offset, + builder_array_wasm->size * sizeof(graph_builder_wasm))) { + NN_ERR_PRINTF("builder_array_wasm->buf_offset is invalid"); + return invalid_argument; + } + + graph_builder_wasm *builder_wasm = + (graph_builder_wasm *)wasm_runtime_addr_app_to_native( + instance, builder_array_wasm->buf_offset); + + graph_builder *builder = (graph_builder *)wasm_runtime_malloc( + builder_array_wasm->size * sizeof(graph_builder)); + if (builder == NULL) + return missing_memory; + + for (uint32_t i = 0; i < builder_array_wasm->size; ++i) { + error res; + if (success + != (res = graph_builder_app_native(instance, &builder_wasm[i], + &builder[i]))) { + wasm_runtime_free(builder); + return res; + } + + NN_DBG_PRINTF("Graph builder %d contains %d elements", i, + builder->size); + } + + builder_array->buf = builder; + builder_array->size = builder_array_wasm->size; + return success; +} + +static error +tensor_data_app_native(wasm_module_inst_t instance, uint32_t total_elements, + tensor_wasm *input_tensor_wasm, tensor_data *data) +{ + if (!wasm_runtime_validate_app_addr( + instance, input_tensor_wasm->data_offset, total_elements)) { + NN_ERR_PRINTF("input_tensor_wasm->data_offset is invalid"); + return invalid_argument; + } + *data = (tensor_data)wasm_runtime_addr_app_to_native( + instance, input_tensor_wasm->data_offset); + return success; +} + +static error +tensor_dimensions_app_native(wasm_module_inst_t instance, + tensor_wasm *input_tensor_wasm, + tensor_dimensions **dimensions) +{ + if (!wasm_runtime_validate_app_addr(instance, + input_tensor_wasm->dimensions_offset, + sizeof(tensor_dimensions_wasm))) { + NN_ERR_PRINTF("input_tensor_wasm->dimensions_offset is invalid"); + return invalid_argument; + } + + tensor_dimensions_wasm *dimensions_wasm = + (tensor_dimensions_wasm *)wasm_runtime_addr_app_to_native( + instance, input_tensor_wasm->dimensions_offset); + + if (!wasm_runtime_validate_app_addr(instance, dimensions_wasm->buf_offset, + sizeof(tensor_dimensions))) { + NN_ERR_PRINTF("dimensions_wasm->buf_offset is invalid"); + return invalid_argument; + } + + *dimensions = + (tensor_dimensions *)wasm_runtime_malloc(sizeof(tensor_dimensions)); + if (dimensions == NULL) + return missing_memory; + + (*dimensions)->size = dimensions_wasm->size; + (*dimensions)->buf = (uint32_t *)wasm_runtime_addr_app_to_native( + instance, dimensions_wasm->buf_offset); + + NN_DBG_PRINTF("Number of dimensions: %d", (*dimensions)->size); + return success; +} + +error +tensor_app_native(wasm_module_inst_t instance, tensor_wasm *input_tensor_wasm, + tensor *input_tensor) +{ + NN_DBG_PRINTF("Converting tensor_wasm to tensor"); + if (!wasm_runtime_validate_native_addr(instance, input_tensor_wasm, + sizeof(tensor_wasm))) { + NN_ERR_PRINTF("input_tensor_wasm is invalid"); + return invalid_argument; + } + + error res; + + tensor_dimensions *dimensions = NULL; + if (success + != (res = tensor_dimensions_app_native(instance, input_tensor_wasm, + &dimensions))) { + NN_ERR_PRINTF("error when parsing dimensions"); + return res; + } + + uint32_t total_elements = 1; + for (uint32_t i = 0; i < dimensions->size; ++i) { + total_elements *= dimensions->buf[i]; + NN_DBG_PRINTF("Dimension %d: %d", i, dimensions->buf[i]); + } + NN_DBG_PRINTF("Tensor type: %d", input_tensor_wasm->type); + NN_DBG_PRINTF("Total number of elements: %d", total_elements); + + tensor_data data = NULL; + if (success + != (res = tensor_data_app_native(instance, total_elements, + input_tensor_wasm, &data))) { + wasm_runtime_free(dimensions); + return res; + } + + input_tensor->type = input_tensor_wasm->type; + input_tensor->dimensions = dimensions; + input_tensor->data = data; + return success; +} diff --git a/core/iwasm/libraries/wasi-nn/src/utils/wasi_nn_app_native.h b/core/iwasm/libraries/wasi-nn/src/utils/wasi_nn_app_native.h new file mode 100644 index 00000000..15154bd3 --- /dev/null +++ b/core/iwasm/libraries/wasi-nn/src/utils/wasi_nn_app_native.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef WASI_NN_APP_NATIVE +#define WASI_NN_APP_NATIVE + +#include +#include +#include +#include +#include + +#include "wasi_nn.h" +#include "logger.h" + +#include "bh_platform.h" +#include "wasm_export.h" + +typedef struct { + uint32_t buf_offset; + uint32_t size; +} graph_builder_wasm; + +typedef struct { + uint32_t buf_offset; + uint32_t size; +} graph_builder_array_wasm; + +typedef struct { + uint32_t buf_offset; + uint32_t size; +} tensor_dimensions_wasm; + +typedef struct { + uint32_t dimensions_offset; + tensor_type type; + uint32_t data_offset; +} tensor_wasm; + +error +graph_builder_array_app_native(wasm_module_inst_t instance, + graph_builder_array_wasm *builder, + graph_builder_array *builder_native); + +error +tensor_app_native(wasm_module_inst_t instance, tensor_wasm *input_tensor, + tensor *input_tensor_native); + +#endif diff --git a/core/iwasm/libraries/wasi-nn/src/wasi_nn.c b/core/iwasm/libraries/wasi-nn/src/wasi_nn.c new file mode 100644 index 00000000..0176bbed --- /dev/null +++ b/core/iwasm/libraries/wasi-nn/src/wasi_nn.c @@ -0,0 +1,302 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include +#include +#include +#include +#include +#include + +#include "wasi_nn.h" +#include "wasi_nn_app_native.h" +#include "logger.h" +#include "wasi_nn_tensorflowlite.hpp" + +#include "bh_platform.h" +#include "wasm_export.h" +#include "wasm_runtime.h" +#include "aot_runtime.h" + +/* Definition of 'wasi_nn.h' structs in WASM app format (using offset) */ + +typedef error (*LOAD)(graph_builder_array *, graph_encoding, execution_target, + graph *); +typedef error (*INIT_EXECUTION_CONTEXT)(graph, graph_execution_context *); +typedef error (*SET_INPUT)(graph_execution_context, uint32_t, tensor *); +typedef error (*COMPUTE)(graph_execution_context); +typedef error (*GET_OUTPUT)(graph_execution_context, uint32_t, tensor_data, + uint32_t *); + +typedef struct { + LOAD load; + INIT_EXECUTION_CONTEXT init_execution_context; + SET_INPUT set_input; + COMPUTE compute; + GET_OUTPUT get_output; +} api_function; + +/* Global variables */ + +static api_function lookup[] = { + { NULL, NULL, NULL, NULL, NULL }, + { NULL, NULL, NULL, NULL, NULL }, + { NULL, NULL, NULL, NULL, NULL }, + { NULL, NULL, NULL, NULL, NULL }, + { tensorflowlite_load, tensorflowlite_init_execution_context, + tensorflowlite_set_input, tensorflowlite_compute, + tensorflowlite_get_output } +}; + +/* Utils */ + +static bool +is_encoding_implemented(graph_encoding encoding) +{ + return lookup[encoding].load && lookup[encoding].init_execution_context + && lookup[encoding].set_input && lookup[encoding].compute + && lookup[encoding].get_output; +} + +static error +is_model_initialized(WASINNContext *wasi_nn_ctx) +{ + if (!wasi_nn_ctx->is_initialized) { + NN_ERR_PRINTF("Model not initialized."); + return runtime_error; + } + return success; +} + +WASINNContext * +wasm_runtime_get_wasi_nn_ctx(wasm_module_inst_t instance) +{ + WASINNContext *wasi_nn_ctx = NULL; +#if WASM_ENABLE_INTERP != 0 + if (instance->module_type == Wasm_Module_Bytecode) { + NN_DBG_PRINTF("Getting ctx from WASM"); + WASMModuleInstance *module_inst = (WASMModuleInstance *)instance; + wasi_nn_ctx = ((WASMModuleInstanceExtra *)module_inst->e)->wasi_nn_ctx; + } +#endif +#if WASM_ENABLE_AOT != 0 + if (instance->module_type == Wasm_Module_AoT) { + NN_DBG_PRINTF("Getting ctx from AOT"); + AOTModuleInstance *module_inst = (AOTModuleInstance *)instance; + wasi_nn_ctx = ((AOTModuleInstanceExtra *)module_inst->e)->wasi_nn_ctx; + } +#endif + bh_assert(wasi_nn_ctx != NULL); + NN_DBG_PRINTF("Returning ctx"); + return wasi_nn_ctx; +} + +/* WASI-NN implementation */ + +error +wasi_nn_load(wasm_exec_env_t exec_env, graph_builder_array_wasm *builder, + graph_encoding encoding, execution_target target, graph *g) +{ + NN_DBG_PRINTF("Running wasi_nn_load [encoding=%d, target=%d]...", encoding, + target); + + if (!is_encoding_implemented(encoding)) { + NN_ERR_PRINTF("Encoding not supported."); + return invalid_encoding; + } + + wasm_module_inst_t instance = wasm_runtime_get_module_inst(exec_env); + bh_assert(instance); + + error res; + graph_builder_array builder_native = { 0 }; + if (success + != (res = graph_builder_array_app_native(instance, builder, + &builder_native))) + return res; + + if (!wasm_runtime_validate_native_addr(instance, g, sizeof(graph))) { + NN_ERR_PRINTF("graph is invalid"); + res = invalid_argument; + goto fail; + } + + res = lookup[encoding].load(&builder_native, encoding, target, g); + + NN_DBG_PRINTF("wasi_nn_load finished with status %d [graph=%d]", res, *g); + + WASINNContext *wasi_nn_ctx = wasm_runtime_get_wasi_nn_ctx(instance); + + wasi_nn_ctx->current_encoding = encoding; + wasi_nn_ctx->is_initialized = true; + +fail: + // XXX: Free intermediate structure pointers + if (builder_native.buf) + wasm_runtime_free(builder_native.buf); + + return res; +} + +error +wasi_nn_init_execution_context(wasm_exec_env_t exec_env, graph g, + graph_execution_context *ctx) +{ + NN_DBG_PRINTF("Running wasi_nn_init_execution_context [graph=%d]...", g); + + wasm_module_inst_t instance = wasm_runtime_get_module_inst(exec_env); + bh_assert(instance); + WASINNContext *wasi_nn_ctx = wasm_runtime_get_wasi_nn_ctx(instance); + + error res; + if (success != (res = is_model_initialized(wasi_nn_ctx))) + return res; + + if (!wasm_runtime_validate_native_addr(instance, ctx, + sizeof(graph_execution_context))) { + NN_ERR_PRINTF("ctx is invalid"); + return invalid_argument; + } + + res = lookup[wasi_nn_ctx->current_encoding].init_execution_context(g, ctx); + *ctx = g; + NN_DBG_PRINTF( + "wasi_nn_init_execution_context finished with status %d [ctx=%d]", res, + *ctx); + return res; +} + +error +wasi_nn_set_input(wasm_exec_env_t exec_env, graph_execution_context ctx, + uint32_t index, tensor_wasm *input_tensor) +{ + NN_DBG_PRINTF("Running wasi_nn_set_input [ctx=%d, index=%d]...", ctx, + index); + + wasm_module_inst_t instance = wasm_runtime_get_module_inst(exec_env); + bh_assert(instance); + WASINNContext *wasi_nn_ctx = wasm_runtime_get_wasi_nn_ctx(instance); + + error res; + if (success != (res = is_model_initialized(wasi_nn_ctx))) + return res; + + tensor input_tensor_native = { 0 }; + if (success + != (res = tensor_app_native(instance, input_tensor, + &input_tensor_native))) + return res; + + res = lookup[wasi_nn_ctx->current_encoding].set_input(ctx, index, + &input_tensor_native); + + // XXX: Free intermediate structure pointers + if (input_tensor_native.dimensions) + wasm_runtime_free(input_tensor_native.dimensions); + + NN_DBG_PRINTF("wasi_nn_set_input finished with status %d", res); + return res; +} + +error +wasi_nn_compute(wasm_exec_env_t exec_env, graph_execution_context ctx) +{ + NN_DBG_PRINTF("Running wasi_nn_compute [ctx=%d]...", ctx); + + wasm_module_inst_t instance = wasm_runtime_get_module_inst(exec_env); + bh_assert(instance); + WASINNContext *wasi_nn_ctx = wasm_runtime_get_wasi_nn_ctx(instance); + + error res; + if (success != (res = is_model_initialized(wasi_nn_ctx))) + return res; + + res = lookup[wasi_nn_ctx->current_encoding].compute(ctx); + NN_DBG_PRINTF("wasi_nn_compute finished with status %d", res); + return res; +} + +error +wasi_nn_get_output(wasm_exec_env_t exec_env, graph_execution_context ctx, + uint32_t index, tensor_data output_tensor, + uint32_t *output_tensor_size) +{ + NN_DBG_PRINTF("Running wasi_nn_get_output [ctx=%d, index=%d]...", ctx, + index); + + wasm_module_inst_t instance = wasm_runtime_get_module_inst(exec_env); + bh_assert(instance); + WASINNContext *wasi_nn_ctx = wasm_runtime_get_wasi_nn_ctx(instance); + + error res; + if (success != (res = is_model_initialized(wasi_nn_ctx))) + return res; + + if (!wasm_runtime_validate_native_addr(instance, output_tensor_size, + sizeof(uint32_t))) { + NN_ERR_PRINTF("output_tensor_size is invalid"); + return invalid_argument; + } + + res = lookup[wasi_nn_ctx->current_encoding].get_output( + ctx, index, output_tensor, output_tensor_size); + NN_DBG_PRINTF("wasi_nn_get_output finished with status %d [data_size=%d]", + res, *output_tensor_size); + return res; +} + +/* Non-exposed public functions */ + +WASINNContext * +wasi_nn_initialize() +{ + NN_DBG_PRINTF("Initializing wasi-nn"); + WASINNContext *wasi_nn_ctx = + (WASINNContext *)wasm_runtime_malloc(sizeof(WASINNContext)); + if (wasi_nn_ctx == NULL) { + NN_ERR_PRINTF("Error when allocating memory for WASI-NN context"); + return NULL; + } + wasi_nn_ctx->is_initialized = true; + wasi_nn_ctx->current_encoding = 3; + return wasi_nn_ctx; +} + +void +wasi_nn_destroy(WASINNContext *wasi_nn_ctx) +{ + if (wasi_nn_ctx == NULL) { + NN_ERR_PRINTF( + "Error when deallocating memory. WASI-NN context is NULL"); + return; + } + NN_DBG_PRINTF("Freeing wasi-nn"); + NN_DBG_PRINTF("-> is_initialized: %d", wasi_nn_ctx->is_initialized); + NN_DBG_PRINTF("-> current_encoding: %d", wasi_nn_ctx->current_encoding); + tensorflowlite_destroy(); + wasm_runtime_free(wasi_nn_ctx); +} + +/* Register WASI-NN in WAMR */ + +/* clang-format off */ +#define REG_NATIVE_FUNC(func_name, signature) \ + { #func_name, wasi_nn_##func_name, signature, NULL } +/* clang-format on */ + +static NativeSymbol native_symbols_wasi_nn[] = { + REG_NATIVE_FUNC(load, "(*ii*)i"), + REG_NATIVE_FUNC(init_execution_context, "(i*)i"), + REG_NATIVE_FUNC(set_input, "(ii*)i"), + REG_NATIVE_FUNC(compute, "(i)i"), + REG_NATIVE_FUNC(get_output, "(ii**)i"), +}; + +uint32_t +get_wasi_nn_export_apis(NativeSymbol **p_libc_wasi_apis) +{ + *p_libc_wasi_apis = native_symbols_wasi_nn; + return sizeof(native_symbols_wasi_nn) / sizeof(NativeSymbol); +} diff --git a/core/iwasm/libraries/wasi-nn/src/wasi_nn_private.h b/core/iwasm/libraries/wasi-nn/src/wasi_nn_private.h new file mode 100644 index 00000000..9571081b --- /dev/null +++ b/core/iwasm/libraries/wasi-nn/src/wasi_nn_private.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef WASI_NN_PRIVATE_H +#define WASI_NN_PRIVATE_H + +#include "wasi_nn_types.h" + +typedef struct { + bool is_initialized; + graph_encoding current_encoding; +} WASINNContext; + +/** + * @brief Initialize wasi-nn + * + */ +WASINNContext * +wasi_nn_initialize(); +/** + * @brief Destroy wasi-nn on app exists + * + */ + +void +wasi_nn_destroy(WASINNContext *wasi_nn_ctx); + +#endif diff --git a/core/iwasm/libraries/wasi-nn/wasi_nn_tensorflow.cpp b/core/iwasm/libraries/wasi-nn/src/wasi_nn_tensorflowlite.cpp similarity index 76% rename from core/iwasm/libraries/wasi-nn/wasi_nn_tensorflow.cpp rename to core/iwasm/libraries/wasi-nn/src/wasi_nn_tensorflowlite.cpp index 597b04dc..b795a7fe 100644 --- a/core/iwasm/libraries/wasi-nn/wasi_nn_tensorflow.cpp +++ b/core/iwasm/libraries/wasi-nn/src/wasi_nn_tensorflowlite.cpp @@ -3,8 +3,10 @@ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception */ -#include "wasi_nn_tensorflow.hpp" -#include "wasi_nn_common.h" +#include "wasi_nn.h" +#include "wasi_nn_tensorflowlite.hpp" +#include "logger.h" + #include "bh_common.h" #include "bh_platform.h" #include "platform_common.h" @@ -25,21 +27,21 @@ static char *model_pointer = NULL; /* WASI-NN (tensorflow) implementation */ error -tensorflow_load(graph_builder_array builder, graph_encoding encoding, - execution_target target, graph *graph) +tensorflowlite_load(graph_builder_array *builder, graph_encoding encoding, + execution_target target, graph *g) { if (model_pointer != NULL) { wasm_runtime_free(model_pointer); model_pointer = NULL; } - if (builder.size != 1) { + if (builder->size != 1) { NN_ERR_PRINTF("Unexpected builder format."); return invalid_argument; } - if (encoding != tensorflow) { - NN_ERR_PRINTF("Encoding is not tensorflow."); + if (encoding != tensorflowlite) { + NN_ERR_PRINTF("Encoding is not tensorflowlite."); return invalid_argument; } @@ -48,7 +50,7 @@ tensorflow_load(graph_builder_array builder, graph_encoding encoding, return invalid_argument; } - uint32_t size = builder.buf[0].size; + uint32_t size = builder->buf[0].size; model_pointer = (char *)wasm_runtime_malloc(size); if (model_pointer == NULL) { @@ -56,7 +58,7 @@ tensorflow_load(graph_builder_array builder, graph_encoding encoding, return missing_memory; } - bh_memcpy_s(model_pointer, size, builder.buf[0].buf, size); + bh_memcpy_s(model_pointer, size, builder->buf[0].buf, size); model = tflite::FlatBufferModel::BuildFromBuffer(model_pointer, size, NULL); if (model == NULL) { @@ -81,7 +83,7 @@ tensorflow_load(graph_builder_array builder, graph_encoding encoding, } error -tensorflow_init_execution_context(graph graph) +tensorflowlite_init_execution_context(graph g, graph_execution_context *ctx) { if (interpreter == NULL) { NN_ERR_PRINTF("Non-initialized interpreter."); @@ -92,8 +94,8 @@ tensorflow_init_execution_context(graph graph) } error -tensorflow_set_input(graph_execution_context ctx, uint32_t index, - tensor *input_tensor) +tensorflowlite_set_input(graph_execution_context ctx, uint32_t index, + tensor *input_tensor) { if (interpreter == NULL) { NN_ERR_PRINTF("Non-initialized interpreter."); @@ -113,11 +115,11 @@ tensorflow_set_input(graph_execution_context ctx, uint32_t index, } uint32_t model_tensor_size = 1; - for (int i = 0; i < (int)tensor->dims->size; ++i) + for (int i = 0; i < tensor->dims->size; ++i) model_tensor_size *= (uint32_t)tensor->dims->data[i]; uint32_t input_tensor_size = 1; - for (int i = 0; i < input_tensor->dimensions->size; i++) + for (uint32_t i = 0; i < input_tensor->dimensions->size; i++) input_tensor_size *= (uint32_t)input_tensor->dimensions->buf[i]; if (model_tensor_size != input_tensor_size) { @@ -136,7 +138,7 @@ tensorflow_set_input(graph_execution_context ctx, uint32_t index, } error -tensorflow_compute(graph_execution_context ctx) +tensorflowlite_compute(graph_execution_context ctx) { if (interpreter == NULL) { NN_ERR_PRINTF("Non-initialized interpreter."); @@ -147,8 +149,9 @@ tensorflow_compute(graph_execution_context ctx) } error -tensorflow_get_output(graph_execution_context context, uint32_t index, - tensor_data output_tensor, uint32_t *output_tensor_size) +tensorflowlite_get_output(graph_execution_context ctx, uint32_t index, + tensor_data output_tensor, + uint32_t *output_tensor_size) { if (interpreter == NULL) { NN_ERR_PRINTF("Non-initialized interpreter."); @@ -178,7 +181,7 @@ tensorflow_get_output(graph_execution_context context, uint32_t index, } float *tensor_f = interpreter->typed_output_tensor(index); - for (int i = 0; i < model_tensor_size; ++i) + for (uint32_t i = 0; i < model_tensor_size; ++i) NN_DBG_PRINTF("output: %f", tensor_f[i]); *output_tensor_size = model_tensor_size; @@ -186,3 +189,22 @@ tensorflow_get_output(graph_execution_context context, uint32_t index, model_tensor_size * sizeof(float)); return success; } + +void +tensorflowlite_destroy() +{ + /* + TensorFlow Lite memory is man + + Related issues: + * https://github.com/tensorflow/tensorflow/issues/15880 + */ + NN_DBG_PRINTF("Freeing memory."); + model.reset(nullptr); + model = NULL; + interpreter.reset(nullptr); + interpreter = NULL; + wasm_runtime_free(model_pointer); + model_pointer = NULL; + NN_DBG_PRINTF("Memory free'd."); +} diff --git a/core/iwasm/libraries/wasi-nn/src/wasi_nn_tensorflowlite.hpp b/core/iwasm/libraries/wasi-nn/src/wasi_nn_tensorflowlite.hpp new file mode 100644 index 00000000..32b29662 --- /dev/null +++ b/core/iwasm/libraries/wasi-nn/src/wasi_nn_tensorflowlite.hpp @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef WASI_NN_TENSORFLOWLITE_HPP +#define WASI_NN_TENSORFLOWLITE_HPP + +#include "wasi_nn.h" + +#ifdef __cplusplus +extern "C" { +#endif + +error +tensorflowlite_load(graph_builder_array *builder, graph_encoding encoding, + execution_target target, graph *g); + +error +tensorflowlite_init_execution_context(graph g, graph_execution_context *ctx); + +error +tensorflowlite_set_input(graph_execution_context ctx, uint32_t index, + tensor *input_tensor); + +error +tensorflowlite_compute(graph_execution_context ctx); + +error +tensorflowlite_get_output(graph_execution_context ctx, uint32_t index, + tensor_data output_tensor, + uint32_t *output_tensor_size); + +void +tensorflowlite_destroy(); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/core/iwasm/libraries/wasi-nn/test/.dockerignore b/core/iwasm/libraries/wasi-nn/test/.dockerignore new file mode 100644 index 00000000..94143827 --- /dev/null +++ b/core/iwasm/libraries/wasi-nn/test/.dockerignore @@ -0,0 +1 @@ +Dockerfile diff --git a/core/iwasm/libraries/wasi-nn/test/Dockerfile b/core/iwasm/libraries/wasi-nn/test/Dockerfile index a69b101b..cb6bfa02 100644 --- a/core/iwasm/libraries/wasi-nn/test/Dockerfile +++ b/core/iwasm/libraries/wasi-nn/test/Dockerfile @@ -8,18 +8,24 @@ ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update && apt-get install -y \ cmake build-essential git wget python3.10 python3-pip -RUN wget -q https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-14/wasi-sdk-14.0-linux.tar.gz && \ - tar xf wasi-sdk-*-linux.tar.gz -C /opt && rm -f wasi-sdk-*-linux.tar.gz && \ - mv /opt/wasi-sdk-14.0 /opt/wasi-sdk +ARG WASI_SDK_VER=16 +RUN wget -c --progress=dot:giga https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-${WASI_SDK_VER}/wasi-sdk-${WASI_SDK_VER}.0-linux.tar.gz -P /opt \ + && tar xf /opt/wasi-sdk-${WASI_SDK_VER}.0-linux.tar.gz -C /opt \ + && ln -fs /opt/wasi-sdk-${WASI_SDK_VER}.0 /opt/wasi-sdk \ + && rm /opt/wasi-sdk-${WASI_SDK_VER}.0-linux.tar.gz WORKDIR /home/wamr +COPY core/deps/install_tensorflow.sh core/deps/install_tensorflow.sh +RUN ./core/deps/install_tensorflow.sh + +COPY core/iwasm/libraries/wasi-nn/test/requirements.txt . +RUN pip3 install -r requirements.txt + COPY core core COPY build-scripts build-scripts COPY product-mini product-mini -RUN pip3 install -r core/iwasm/libraries/wasi-nn/test/requirements.txt - WORKDIR /home/wamr/core/iwasm/libraries/wasi-nn/test/build RUN cmake -DWAMR_BUILD_WASI_NN=1 .. diff --git a/core/iwasm/libraries/wasi-nn/test/test_tensorflow.c b/core/iwasm/libraries/wasi-nn/test/test_tensorflow.c index 0e5e6a98..f813b6bc 100755 --- a/core/iwasm/libraries/wasi-nn/test/test_tensorflow.c +++ b/core/iwasm/libraries/wasi-nn/test/test_tensorflow.c @@ -28,7 +28,7 @@ typedef struct { // WASI-NN wrappers error -wasm_load(char *model_name, graph *graph) +wasm_load(char *model_name, graph *g) { FILE *pFile = fopen(model_name, "r"); if (pFile == NULL) @@ -64,7 +64,7 @@ wasm_load(char *model_name, graph *graph) arr.buf[0].size = result; arr.buf[0].buf = buffer; - error res = load(&arr, tensorflow, cpu, graph); + error res = load(&arr, tensorflowlite, cpu, g); fclose(pFile); free(buffer); @@ -73,13 +73,13 @@ wasm_load(char *model_name, graph *graph) } error -wasm_init_execution_context(graph graph, graph_execution_context *ctx) +wasm_init_execution_context(graph g, graph_execution_context *ctx) { - return init_execution_context(graph, ctx); + return init_execution_context(g, ctx); } error -wasm_input(graph_execution_context ctx, float *input_tensor, uint32_t *dim) +wasm_set_input(graph_execution_context ctx, float *input_tensor, uint32_t *dim) { tensor_dimensions dims; dims.size = INPUT_TENSOR_DIMS; @@ -130,7 +130,7 @@ run_inference(float *input, uint32_t *input_size, uint32_t *output_size, exit(1); } - if (wasm_input(ctx, input, input_size) != success) { + if (wasm_set_input(ctx, input, input_size) != success) { fprintf(stderr, "Error when setting input tensor."); exit(1); } @@ -151,7 +151,7 @@ run_inference(float *input, uint32_t *input_size, uint32_t *output_size, *output_size = MAX_OUTPUT_TENSOR_SIZE - *output_size; if (wasm_get_output(ctx, i, &out_tensor[offset], output_size) != success) { - fprintf(stderr, "Error when getting input ."); + fprintf(stderr, "Error when getting output ."); exit(1); } @@ -295,7 +295,6 @@ main() test_mult_dimensions(); printf("################### Testing multiple outputs...\n"); test_mult_outputs(); - printf("Tests: passed!\n"); return 0; } diff --git a/core/iwasm/libraries/wasi-nn/wasi_nn.cmake b/core/iwasm/libraries/wasi-nn/wasi_nn.cmake index 6d34b5ef..d6fca891 100644 --- a/core/iwasm/libraries/wasi-nn/wasi_nn.cmake +++ b/core/iwasm/libraries/wasi-nn/wasi_nn.cmake @@ -5,6 +5,15 @@ set (WASI_NN_DIR ${CMAKE_CURRENT_LIST_DIR}) add_definitions (-DWASM_ENABLE_WASI_NN=1) -set (LIBC_WASI_NN_SOURCE ${WASI_NN_DIR}/wasi_nn_native.c ${WASI_NN_DIR}/wasi_nn_tensorflow.cpp) +include_directories (${WASI_NN_DIR}) +include_directories (${WASI_NN_DIR}/src) +include_directories (${WASI_NN_DIR}/src/utils) + +set ( + LIBC_WASI_NN_SOURCE + ${WASI_NN_DIR}/src/wasi_nn.c + ${WASI_NN_DIR}/src/wasi_nn_tensorflowlite.cpp + ${WASI_NN_DIR}/src/utils/wasi_nn_app_native.c +) set (TENSORFLOW_LIB tensorflow-lite) diff --git a/core/iwasm/libraries/wasi-nn/wasi_nn.h b/core/iwasm/libraries/wasi-nn/wasi_nn.h index 115ac928..2bf0a192 100644 --- a/core/iwasm/libraries/wasi-nn/wasi_nn.h +++ b/core/iwasm/libraries/wasi-nn/wasi_nn.h @@ -3,63 +3,17 @@ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception */ -#ifndef WASI_NN_WASM_H -#define WASI_NN_WASM_H - -#include "wasi_nn_common.h" - /** * Following definition from: - * [Aug 10th, 2022] - * https://github.com/WebAssembly/wasi-nn/blob/e5e1a6c31f424c7cd63026cd270e9746775675a0/wasi-nn.wit.md + * [Oct 25th, 2022] + * https://github.com/WebAssembly/wasi-nn/blob/0f77c48ec195748990ff67928a4b3eef5f16c2de/wasi-nn.wit.md */ -/* The graph initialization data. */ +#ifndef WASI_NN_H +#define WASI_NN_H -// This consists of an array of buffers because implementing backends may encode -// their graph IR in parts (e.g., OpenVINO stores its IR and weights -// separately). -typedef struct { - uint8_t *buf; - uint32_t size; -} graph_builder; - -typedef struct { - graph_builder *buf; - uint32_t size; -} graph_builder_array; - -/* The dimensions of a tensor. */ - -// The array length matches the tensor rank and each element in the array -// describes the size of each dimension. -typedef struct { - uint32_t *buf; - uint32_t size; -} tensor_dimensions; - -/* The tensor data. */ - -// Initially conceived as a sparse representation, each empty cell would be -// filled with zeros and the array length must match the product of all of the -// dimensions and the number of bytes in the type (e.g., a 2x2 tensor with -// 4-byte f32 elements would have a data array of length 16). Naturally, this -// representation requires some knowledge of how to lay out data in -// memory--e.g., using row-major ordering--and could perhaps be improved. -typedef uint8_t *tensor_data; - -/* A tensor. */ - -typedef struct { - // Describe the size of the tensor (e.g., 2x2x2x2 -> [2, 2, 2, 2]). To - // represent a tensor containing a single value, use `[1]` for the tensor - // dimensions. - tensor_dimensions *dimensions; - // Describe the type of element in the tensor (e.g., f32). - tensor_type type; - // Contains the tensor data. - tensor_data data; -} tensor; +#include +#include "wasi_nn_types.h" /** * @brief Load an opaque sequence of bytes to use for inference. @@ -67,25 +21,31 @@ typedef struct { * @param builder Model builder. * @param encoding Model encoding. * @param target Execution target. - * @param graph Graph. + * @param g Graph. * @return error Execution status. */ error load(graph_builder_array *builder, graph_encoding encoding, - execution_target target, graph *graph) - __attribute__((export_module("wasi_nn"))) + execution_target target, graph *g) __attribute__((import_module("wasi_nn"))); +/** + * INFERENCE + * + */ + +// Bind a `graph` to the input and output tensors for an inference. +typedef uint32_t graph_execution_context; + /** * @brief Create an execution instance of a loaded graph. * - * @param graph Graph. + * @param g Graph. * @param ctx Execution context. * @return error Execution status. */ error -init_execution_context(graph graph, graph_execution_context *ctx) - __attribute__((export_module("wasi_nn"))) +init_execution_context(graph g, graph_execution_context *ctx) __attribute__((import_module("wasi_nn"))); /** @@ -98,7 +58,6 @@ init_execution_context(graph graph, graph_execution_context *ctx) */ error set_input(graph_execution_context ctx, uint32_t index, tensor *tensor) - __attribute__((export_module("wasi_nn"))) __attribute__((import_module("wasi_nn"))); /** @@ -108,8 +67,7 @@ set_input(graph_execution_context ctx, uint32_t index, tensor *tensor) * @return error Execution status. */ error -compute(graph_execution_context ctx) __attribute__((export_module("wasi_nn"))) -__attribute__((import_module("wasi_nn"))); +compute(graph_execution_context ctx) __attribute__((import_module("wasi_nn"))); /** * @brief Extract the outputs after inference. @@ -126,7 +84,6 @@ __attribute__((import_module("wasi_nn"))); error get_output(graph_execution_context ctx, uint32_t index, tensor_data output_tensor, uint32_t *output_tensor_size) - __attribute__((export_module("wasi_nn"))) __attribute__((import_module("wasi_nn"))); #endif diff --git a/core/iwasm/libraries/wasi-nn/wasi_nn_common.h b/core/iwasm/libraries/wasi-nn/wasi_nn_common.h deleted file mode 100644 index 103185bd..00000000 --- a/core/iwasm/libraries/wasi-nn/wasi_nn_common.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2019 Intel Corporation. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - */ - -#ifndef WASI_NN_COMMON_H -#define WASI_NN_COMMON_H - -#include - -// The type of the elements in a tensor. -typedef enum { fp16 = 0, fp32, up8, ip32 } tensor_type; - -// Describes the encoding of the graph. This allows the API to be implemented by -// various backends that encode (i.e., serialize) their graph IR with different -// formats. -typedef enum { openvino = 0, onnx, tensorflow, pytorch } graph_encoding; - -// Define where the graph should be executed. -typedef enum { cpu = 0, gpu, tpu } execution_target; - -// Error codes returned by functions in this API. -typedef enum { - // No error occurred. - success = 0, - // Caller module passed an invalid argument. - invalid_argument, - // Invalid encoding. - invalid_encoding, - // Caller module is missing a memory export. - missing_memory, - // Device or resource busy. - busy, - // Runtime Error. - runtime_error, -} error; - -// An execution graph for performing inference (i.e., a model). -typedef uint32_t graph; - -// Bind a `graph` to the input and output tensors for an inference. -typedef uint32_t graph_execution_context; - -#endif diff --git a/core/iwasm/libraries/wasi-nn/wasi_nn_native.c b/core/iwasm/libraries/wasi-nn/wasi_nn_native.c deleted file mode 100644 index 333dd475..00000000 --- a/core/iwasm/libraries/wasi-nn/wasi_nn_native.c +++ /dev/null @@ -1,264 +0,0 @@ -/* - * Copyright (C) 2019 Intel Corporation. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - */ - -#include -#include -#include -#include -#include - -#include "wasi_nn_common.h" -#include "wasm_export.h" -#include "bh_platform.h" - -#include "wasi_nn.h" -#include "wasi_nn_tensorflow.hpp" -#include "logger.h" - -/* Definition of 'wasi_nn.h' structs in WASM app format (using offset) */ - -typedef struct { - uint32_t buf_offset; - uint32_t size; -} graph_builder_wasm; - -typedef struct { - uint32_t buf_offset; - uint32_t size; -} graph_builder_array_wasm; - -typedef struct { - uint32_t dimensions_offset; - tensor_type type; - uint32_t data_offset; -} tensor_wasm; - -typedef struct { - uint32_t buf_offset; - uint32_t size; -} tensor_dimensions_wasm; - -/* Global variables */ - -static uint8_t _is_initialized; -static graph_encoding _encoding; - -/* Utils */ - -static error -check_initialized() -{ - if (!_is_initialized) { - NN_ERR_PRINTF("Model not initialized."); - return invalid_argument; - } - if (_encoding != tensorflow) { - NN_ERR_PRINTF("Model encoding is not tensorflow."); - return invalid_argument; - } - return success; -} - -/* WASI-NN implementation */ - -error -wasi_nn_load(wasm_exec_env_t exec_env, graph_builder_array_wasm *builder, - graph_encoding encoding, execution_target target, graph *graph) -{ - NN_DBG_PRINTF("Running wasi_nn_load [encoding=%d, target=%d]...", encoding, - target); - - wasm_module_inst_t instance = wasm_runtime_get_module_inst(exec_env); - bh_assert(instance); - - if (!wasm_runtime_validate_native_addr(instance, builder, - sizeof(graph_builder_array_wasm))) - return invalid_argument; - - if (!wasm_runtime_validate_app_addr(instance, builder->buf_offset, - builder->size * sizeof(uint32_t))) - return invalid_argument; - - NN_DBG_PRINTF("Graph builder array contains %d elements", builder->size); - - graph_builder_wasm *gb_wasm = - (graph_builder_wasm *)wasm_runtime_addr_app_to_native( - instance, builder->buf_offset); - - graph_builder *gb_native = (graph_builder *)wasm_runtime_malloc( - builder->size * sizeof(graph_builder)); - if (gb_native == NULL) - return missing_memory; - - for (int i = 0; i < builder->size; ++i) { - if (!wasm_runtime_validate_app_addr(instance, gb_wasm[i].buf_offset, - gb_wasm[i].size - * sizeof(uint8_t))) { - wasm_runtime_free(gb_native); - return invalid_argument; - } - - gb_native[i].buf = (uint8_t *)wasm_runtime_addr_app_to_native( - instance, gb_wasm[i].buf_offset); - gb_native[i].size = gb_wasm[i].size; - - NN_DBG_PRINTF("Graph builder %d contains %d elements", i, - gb_wasm[i].size); - } - - graph_builder_array gba_native = { .buf = gb_native, - .size = builder->size }; - - if (!wasm_runtime_validate_native_addr(instance, graph, sizeof(graph))) { - wasm_runtime_free(gb_native); - return invalid_argument; - } - - switch (encoding) { - case tensorflow: - break; - default: - NN_ERR_PRINTF("Only tensorflow is supported."); - wasm_runtime_free(gb_native); - return invalid_argument; - } - - _encoding = encoding; - _is_initialized = 1; - - error res = tensorflow_load(gba_native, _encoding, target, graph); - NN_DBG_PRINTF("wasi_nn_load finished with status %d [graph=%d]", res, - *graph); - - wasm_runtime_free(gb_native); - return res; -} - -error -wasi_nn_init_execution_context(wasm_exec_env_t exec_env, graph graph, - graph_execution_context *ctx) -{ - NN_DBG_PRINTF("Running wasi_nn_init_execution_context [graph=%d]...", - graph); - error res; - if (success != (res = check_initialized())) - return res; - res = tensorflow_init_execution_context(graph); - *ctx = graph; - NN_DBG_PRINTF( - "wasi_nn_init_execution_context finished with status %d [ctx=%d]", res, - *ctx); - return res; -} - -error -wasi_nn_set_input(wasm_exec_env_t exec_env, graph_execution_context ctx, - uint32_t index, tensor_wasm *input_tensor) -{ - NN_DBG_PRINTF("Running wasi_nn_set_input [ctx=%d, index=%d]...", ctx, - index); - - error res; - if (success != (res = check_initialized())) - return res; - - wasm_module_inst_t instance = wasm_runtime_get_module_inst(exec_env); - bh_assert(instance); - - if (!wasm_runtime_validate_native_addr(instance, input_tensor, - sizeof(tensor_wasm))) - return invalid_argument; - - if (!wasm_runtime_validate_app_addr( - instance, input_tensor->dimensions_offset, sizeof(uint32_t))) - return invalid_argument; - - tensor_dimensions_wasm *dimensions_w = - (tensor_dimensions_wasm *)wasm_runtime_addr_app_to_native( - instance, input_tensor->dimensions_offset); - - if (!wasm_runtime_validate_app_addr(instance, dimensions_w->buf_offset, - dimensions_w->size * sizeof(uint32_t))) - return invalid_argument; - - tensor_dimensions dimensions = { - .buf = (uint32_t *)wasm_runtime_addr_app_to_native( - instance, dimensions_w->buf_offset), - .size = dimensions_w->size - }; - - NN_DBG_PRINTF("Number of dimensions: %d", dimensions.size); - int total_elements = 1; - for (int i = 0; i < dimensions.size; ++i) { - NN_DBG_PRINTF("Dimension %d: %d", i, dimensions.buf[i]); - total_elements *= dimensions.buf[i]; - } - NN_DBG_PRINTF("Tensor type: %d", input_tensor->type); - - if (!wasm_runtime_validate_app_addr(instance, input_tensor->data_offset, - total_elements)) - return invalid_argument; - - tensor tensor = { .type = input_tensor->type, - .dimensions = &dimensions, - .data = (uint8_t *)wasm_runtime_addr_app_to_native( - instance, input_tensor->data_offset) }; - - res = tensorflow_set_input(ctx, index, &tensor); - NN_DBG_PRINTF("wasi_nn_set_input finished with status %d", res); - return res; -} - -error -wasi_nn_compute(wasm_exec_env_t exec_env, graph_execution_context ctx) -{ - NN_DBG_PRINTF("Running wasi_nn_compute [ctx=%d]...", ctx); - error res; - if (success != (res = check_initialized())) - return res; - - res = tensorflow_compute(ctx); - NN_DBG_PRINTF("wasi_nn_compute finished with status %d", res); - return res; -} - -error -wasi_nn_get_output(wasm_exec_env_t exec_env, graph_execution_context ctx, - uint32_t index, tensor_data output_tensor, - uint32_t *output_tensor_size) -{ - NN_DBG_PRINTF("Running wasi_nn_get_output [ctx=%d, index=%d]...", ctx, - index); - error res; - if (success != (res = check_initialized())) - return res; - - res = tensorflow_get_output(ctx, index, output_tensor, output_tensor_size); - NN_DBG_PRINTF("wasi_nn_get_output finished with status %d [data_size=%d]", - res, *output_tensor_size); - return res; -} - -/* Register WASI-NN in WAMR */ - -/* clang-format off */ -#define REG_NATIVE_FUNC(func_name, signature) \ - { #func_name, wasi_nn_##func_name, signature, NULL } -/* clang-format on */ - -static NativeSymbol native_symbols_wasi_nn[] = { - REG_NATIVE_FUNC(load, "(*ii*)i"), - REG_NATIVE_FUNC(init_execution_context, "(i*)i"), - REG_NATIVE_FUNC(set_input, "(ii*)i"), - REG_NATIVE_FUNC(compute, "(i)i"), - REG_NATIVE_FUNC(get_output, "(ii**)i"), -}; - -uint32_t -get_wasi_nn_export_apis(NativeSymbol **p_libc_wasi_apis) -{ - *p_libc_wasi_apis = native_symbols_wasi_nn; - return sizeof(native_symbols_wasi_nn) / sizeof(NativeSymbol); -} diff --git a/core/iwasm/libraries/wasi-nn/wasi_nn_tensorflow.hpp b/core/iwasm/libraries/wasi-nn/wasi_nn_tensorflow.hpp deleted file mode 100644 index 46264c0b..00000000 --- a/core/iwasm/libraries/wasi-nn/wasi_nn_tensorflow.hpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2019 Intel Corporation. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - */ - -#ifndef WASI_NN_TENSORFLOW_HPP -#define WASI_NN_TENSORFLOW_HPP - -#include - -#include "wasi_nn.h" -#include "logger.h" - -#ifdef __cplusplus -extern "C" { -#endif - -error -tensorflow_load(graph_builder_array builder, graph_encoding encoding, - execution_target target, graph *graph); - -error -tensorflow_init_execution_context(graph graph); - -error -tensorflow_set_input(graph_execution_context ctx, uint32_t index, - tensor *input_tensor); - -error -tensorflow_compute(graph_execution_context ctx); - -error -tensorflow_get_output(graph_execution_context context, uint32_t index, - tensor_data output_tensor, uint32_t *output_tensor_size); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/core/iwasm/libraries/wasi-nn/wasi_nn_types.h b/core/iwasm/libraries/wasi-nn/wasi_nn_types.h new file mode 100644 index 00000000..a2cebe49 --- /dev/null +++ b/core/iwasm/libraries/wasi-nn/wasi_nn_types.h @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef WASI_NN_TYPES_H +#define WASI_NN_TYPES_H + +/** + * ERRORS + * + */ + +// Error codes returned by functions in this API. +typedef enum { + // No error occurred. + success = 0, + // Caller module passed an invalid argument. + invalid_argument, + // Invalid encoding. + invalid_encoding, + // Caller module is missing a memory export. + missing_memory, + // Device or resource busy. + busy, + // Runtime Error. + runtime_error, +} error; + +/** + * TENSOR + * + */ + +// The dimensions of a tensor. +// +// The array length matches the tensor rank and each element in the array +// describes the size of each dimension. +typedef struct { + uint32_t *buf; + uint32_t size; +} tensor_dimensions; + +// The type of the elements in a tensor. +typedef enum { fp16 = 0, fp32, up8, ip32 } tensor_type; + +// The tensor data. +// +// Initially conceived as a sparse representation, each empty cell would be +// filled with zeros and the array length must match the product of all of the +// dimensions and the number of bytes in the type (e.g., a 2x2 tensor with +// 4-byte f32 elements would have a data array of length 16). Naturally, this +// representation requires some knowledge of how to lay out data in +// memory--e.g., using row-major ordering--and could perhaps be improved. +typedef uint8_t *tensor_data; + +// A tensor. +typedef struct { + // Describe the size of the tensor (e.g., 2x2x2x2 -> [2, 2, 2, 2]). To + // represent a tensor containing a single value, use `[1]` for the tensor + // dimensions. + tensor_dimensions *dimensions; + // Describe the type of element in the tensor (e.g., f32). + tensor_type type; + // Contains the tensor data. + tensor_data data; +} tensor; + +/** + * GRAPH + * + */ + +// The graph initialization data. +// +// This consists of an array of buffers because implementing backends may encode +// their graph IR in parts (e.g., OpenVINO stores its IR and weights +// separately). +typedef struct { + uint8_t *buf; + uint32_t size; +} graph_builder; + +typedef struct { + graph_builder *buf; + uint32_t size; +} graph_builder_array; + +// An execution graph for performing inference (i.e., a model). +typedef uint32_t graph; + +// Describes the encoding of the graph. This allows the API to be implemented by +// various backends that encode (i.e., serialize) their graph IR with different +// formats. +typedef enum { + openvino = 0, + onnx, + tensorflow, + pytorch, + tensorflowlite +} graph_encoding; + +// Define where the graph should be executed. +typedef enum execution_target { cpu = 0, gpu, tpu } execution_target; + +#endif From 58316635d45f4a789437f5c922920587191bf40e Mon Sep 17 00:00:00 2001 From: Huang Qi Date: Sat, 28 Jan 2023 12:39:14 +0800 Subject: [PATCH 04/33] ci: Enable libc-wasi compilation test on NuttX (#1918) --- .github/workflows/compilation_on_nuttx.yml | 5 ++++- .../libc-wasi/sandboxed-system-primitives/src/posix.c | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/compilation_on_nuttx.yml b/.github/workflows/compilation_on_nuttx.yml index 7df9e87e..1bcc8d5c 100644 --- a/.github/workflows/compilation_on_nuttx.yml +++ b/.github/workflows/compilation_on_nuttx.yml @@ -65,9 +65,12 @@ jobs: "boards/risc-v/k210/maix-bit/configs/nsh", ] wamr_config_option: [ - "CONFIG_INTERPRETERS_WAMR=y\\nCONFIG_INTERPRETERS_WAMR_AOT=y\\nCONFIG_INTERPRETERS_WAMR_FAST=y\\nCONFIG_INTERPRETERS_WAMR_LIBC_BUILTIN=y\\n", "CONFIG_INTERPRETERS_WAMR=y\\nCONFIG_INTERPRETERS_WAMR_AOT=y\\nCONFIG_INTERPRETERS_WAMR_FAST=y\\n", + "CONFIG_INTERPRETERS_WAMR=y\\nCONFIG_INTERPRETERS_WAMR_AOT=y\\nCONFIG_INTERPRETERS_WAMR_FAST=y\\nCONFIG_INTERPRETERS_WAMR_LIBC_WASI=y\\n", + "CONFIG_INTERPRETERS_WAMR=y\\nCONFIG_INTERPRETERS_WAMR_AOT=y\\nCONFIG_INTERPRETERS_WAMR_FAST=y\\nCONFIG_INTERPRETERS_WAMR_LIBC_BUILTIN=y\\n", "CONFIG_INTERPRETERS_WAMR=y\\nCONFIG_INTERPRETERS_WAMR_AOT=y\\nCONFIG_INTERPRETERS_WAMR_CLASSIC=y\\n", + "CONFIG_INTERPRETERS_WAMR=y\\nCONFIG_INTERPRETERS_WAMR_AOT=y\\nCONFIG_INTERPRETERS_WAMR_CLASSIC=y\\nCONFIG_INTERPRETERS_WAMR_LIBC_WASI=y\\n", + "CONFIG_INTERPRETERS_WAMR=y\\nCONFIG_INTERPRETERS_WAMR_AOT=y\\nCONFIG_INTERPRETERS_WAMR_CLASSIC=y\\nCONFIG_INTERPRETERS_WAMR_LIBC_BUILTIN=y\\n", "CONFIG_INTERPRETERS_WAMR=y\\nCONFIG_INTERPRETERS_WAMR_AOT=y\\nCONFIG_INTERPRETERS_WAMR_LIBC_BUILTIN=y\\n", "CONFIG_INTERPRETERS_WAMR=y\\nCONFIG_INTERPRETERS_WAMR_AOT=y\\n", "CONFIG_INTERPRETERS_WAMR=y\\nCONFIG_INTERPRETERS_WAMR_FAST=y\\n", diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c index d8c57459..001c3b78 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c @@ -3226,6 +3226,7 @@ wasi_ssp_sock_get_reuse_port( #else errno = ENOTSUP; ret = BHT_ERROR; + optval = 0; #endif /* defined(SO_REUSEPORT) */ fd_object_release(fo); From 45c003e6e44c7e26578dec6fb6eeeee9449902b2 Mon Sep 17 00:00:00 2001 From: Wang Ning Date: Sun, 29 Jan 2023 09:41:03 +0800 Subject: [PATCH 05/33] Add docker images auto check and setup support for WAMR-IDE (#1882) 1. Add docker images auto check and setup support for WAMR-IDE 2. Fix bug that the code goes on when user skips install --- .../wamr-ide/VSCode-Extension/package.json | 2 +- .../VSCode-Extension/src/constants.ts | 7 + .../VSCode-Extension/src/extension.ts | 169 +++++++++++++----- .../src/utilities/dockerUtilities.ts | 125 +++++++++++++ .../src/utilities/lldbUtilities.ts | 19 +- 5 files changed, 268 insertions(+), 54 deletions(-) create mode 100644 test-tools/wamr-ide/VSCode-Extension/src/constants.ts create mode 100644 test-tools/wamr-ide/VSCode-Extension/src/utilities/dockerUtilities.ts diff --git a/test-tools/wamr-ide/VSCode-Extension/package.json b/test-tools/wamr-ide/VSCode-Extension/package.json index 9b67e3a1..71cc7487 100644 --- a/test-tools/wamr-ide/VSCode-Extension/package.json +++ b/test-tools/wamr-ide/VSCode-Extension/package.json @@ -6,7 +6,7 @@ }, "displayName": "WAMR-IDE", "description": "An Integrated Development Environment for WASM", - "version": "1.0.0", + "version": "1.1.2", "engines": { "vscode": "^1.59.0" }, diff --git a/test-tools/wamr-ide/VSCode-Extension/src/constants.ts b/test-tools/wamr-ide/VSCode-Extension/src/constants.ts new file mode 100644 index 00000000..cf8bb710 --- /dev/null +++ b/test-tools/wamr-ide/VSCode-Extension/src/constants.ts @@ -0,0 +1,7 @@ +export const enum SelectionOfPrompt { + skip = 'skip', + setUp = 'setup', +} +export const enum Status { + done = 'done', +} diff --git a/test-tools/wamr-ide/VSCode-Extension/src/extension.ts b/test-tools/wamr-ide/VSCode-Extension/src/extension.ts index 17dda949..9d979b7a 100644 --- a/test-tools/wamr-ide/VSCode-Extension/src/extension.ts +++ b/test-tools/wamr-ide/VSCode-Extension/src/extension.ts @@ -24,6 +24,13 @@ import { getWAMRExtensionVersion, } from './utilities/lldbUtilities'; +import { + checkIfDockerStarted, + checkIfDockerImagesExist, + promptSetupDockerImages, +} from './utilities/dockerUtilities'; +import { SelectionOfPrompt } from './constants'; + let wasmTaskProvider: WasmTaskProvider; let wasmDebugConfigProvider: WasmDebugConfigurationProvider; let currentPrjDir = ''; @@ -304,7 +311,7 @@ export async function activate(context: vscode.ExtensionContext) { const disposableBuild = vscode.commands.registerCommand( 'wamride.build', - () => { + async () => { if (!isWasmProject) { vscode.window.showErrorMessage('Build failed', { modal: true, @@ -313,6 +320,28 @@ export async function activate(context: vscode.ExtensionContext) { return; } + try { + /* check if docker images are ready before building */ + if ( + (await checkIfDockerStarted()) && + !(await checkIfDockerImagesExist(context)) + ) { + /**NOTE - if users select to skip install, + * we should return rather than continue + * the execution + */ + if ( + (await promptSetupDockerImages(context)) === + SelectionOfPrompt.skip + ) { + return; + } + } + } catch (e) { + vscode.window.showWarningMessage((e as Error).message); + return; + } + generateCMakeFile(includePathArr, excludeFileArr); /* destroy the wasm-toolchain-ctr if it exists */ vscode.commands @@ -382,10 +411,35 @@ export async function activate(context: vscode.ExtensionContext) { /* we should check again whether the user installed lldb, as this can be skipped during activation */ try { if (!isLLDBInstalled(context)) { - await promptInstallLLDB(context); + /**NOTE - if users select to skip install, + * we should return rather than continue + * the execution + */ + if ( + (await promptInstallLLDB(context)) === + SelectionOfPrompt.skip + ) { + return; + } + } + + if ( + (await checkIfDockerStarted()) && + !(await checkIfDockerImagesExist(context)) + ) { + /**NOTE - save as above lldb, should return if + * users select to skip set up + */ + if ( + (await promptSetupDockerImages(context)) === + SelectionOfPrompt.skip + ) { + return; + } } } catch (e) { vscode.window.showWarningMessage((e as Error).message); + return; } /* refuse to debug if build process failed */ @@ -461,48 +515,70 @@ export async function activate(context: vscode.ExtensionContext) { } ); - const disposableRun = vscode.commands.registerCommand('wamride.run', () => { - if (!isWasmProject) { - vscode.window.showErrorMessage('run failed', { - modal: true, - detail: 'Current project is not wasm project, please open wasm project and try again.', - }); - return; - } - - /* refuse to debug if build process failed */ - if (!checkIfBuildSuccess()) { - vscode.window.showErrorMessage('Debug failed', { - modal: true, - detail: 'Can not find WASM binary, please build WASM firstly.', - }); - return; - } - vscode.commands - .executeCommand( - 'workbench.action.tasks.runTask', - 'Destroy: Wasm-Container-Before-Run' - ) - .then(() => { - const disposableAft = vscode.tasks.onDidEndTaskProcess(e => { - if (e.execution.task.name === 'Wasm-Container-Before-Run') { - /* make sure that run wasm task will be executed after destroy task finish */ - vscode.commands - .executeCommand( - 'workbench.action.tasks.runTask', - 'Run: Wasm' - ) - .then(() => { - if (e.exitCode !== 0) { - disposableAft.dispose(); - return; - } - }); - disposableAft.dispose(); - } + const disposableRun = vscode.commands.registerCommand( + 'wamride.run', + async () => { + if (!isWasmProject) { + vscode.window.showErrorMessage('run failed', { + modal: true, + detail: 'Current project is not wasm project, please open wasm project and try again.', }); - }); - }); + return; + } + + try { + /* check if docker images are set up before building */ + if ( + (await checkIfDockerStarted()) && + !(await checkIfDockerImagesExist(context)) + ) { + await promptSetupDockerImages(context); + } + } catch (e) { + vscode.window.showWarningMessage((e as Error).message); + return; + } + + /* refuse to debug if build process failed */ + if (!checkIfBuildSuccess()) { + vscode.window.showErrorMessage('Debug failed', { + modal: true, + detail: 'Can not find WASM binary, please build WASM firstly.', + }); + return; + } + + vscode.commands + .executeCommand( + 'workbench.action.tasks.runTask', + 'Destroy: Wasm-Container-Before-Run' + ) + .then(() => { + const disposableAft = vscode.tasks.onDidEndTaskProcess( + e => { + if ( + e.execution.task.name === + 'Wasm-Container-Before-Run' + ) { + /* make sure that run wasm task will be executed when destroy task finish */ + vscode.commands + .executeCommand( + 'workbench.action.tasks.runTask', + 'Run: Wasm' + ) + .then(() => { + if (e.exitCode !== 0) { + disposableAft.dispose(); + return; + } + }); + disposableAft.dispose(); + } + } + ); + }); + } + ); const disposableToggleIncludePath = vscode.commands.registerCommand( 'wamride.build.toggleStateIncludePath', @@ -700,6 +776,13 @@ export async function activate(context: vscode.ExtensionContext) { if (!isLLDBInstalled(context)) { await promptInstallLLDB(context); } + + if ( + (await checkIfDockerStarted()) && + !(await checkIfDockerImagesExist(context)) + ) { + await promptSetupDockerImages(context); + } } catch (e) { vscode.window.showWarningMessage((e as Error).message); } diff --git a/test-tools/wamr-ide/VSCode-Extension/src/utilities/dockerUtilities.ts b/test-tools/wamr-ide/VSCode-Extension/src/utilities/dockerUtilities.ts new file mode 100644 index 00000000..0a749ba1 --- /dev/null +++ b/test-tools/wamr-ide/VSCode-Extension/src/utilities/dockerUtilities.ts @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +import * as vscode from 'vscode'; +import * as cp from 'child_process'; +import * as path from 'path'; +import * as fs from 'fs'; +import { getWAMRExtensionVersion } from './lldbUtilities'; +import { downloadFile, unzipFile } from './directoryUtilities'; +import { SelectionOfPrompt, Status } from '../constants'; + +const DOCKER_IMAGES_TEM_FOLDER_NAME = 'docker-resource'; + +type SelectionStatus = SelectionOfPrompt | Status; + +const execShell = (cmd: string) => + new Promise((resolve, reject) => { + cp.exec(cmd, (error, result) => { + if (error) { + return reject(error); + } + return resolve(result); + }); + }); + +export async function promptSetupDockerImages( + context: vscode.ExtensionContext +): Promise { + const extensionPath = context.extensionPath; + const response = await vscode.window.showWarningMessage( + 'Necessary docker images are not found. Setup now?', + SelectionOfPrompt.setUp, + SelectionOfPrompt.skip + ); + + if (response === SelectionOfPrompt.skip) { + return response; + } + + const downloadUrlArray = getDockerImagesDownloadUrl(context); + + const destinationFolder = path.resolve( + extensionPath, + 'resource', + DOCKER_IMAGES_TEM_FOLDER_NAME + ); + + if (!fs.existsSync(destinationFolder)) { + fs.mkdirSync(destinationFolder); + } + + vscode.window.showInformationMessage(`Downloading Docker Images...`); + + for (const url of downloadUrlArray) { + const imageZipName = path.basename(url); + const imageStorePath = path.join(destinationFolder, imageZipName); + await downloadFile(url, imageStorePath); + + /** + * extract docker image tar package to + * '${destinationFolder}' + */ + const dockerImageFile = await unzipFile(imageStorePath, filename => + path.join(destinationFolder, filename) + ); + /* give access before loading */ + dockerImageFile.forEach(file => fs.chmodSync(file, '0775')); + + /**NOTE - load docker image tar package to host + * right now there are just one file + * `docker-image-name.tar` inside so we can + * directly use files[0] here, should be modified + * if the package's files change + */ + await execShell(`docker load -i ${dockerImageFile[0]}`); + } + + /* remove the DOCKER_IMAGES_TEM_FOLDER */ + fs.rmSync(destinationFolder, { recursive: true, force: true }); + + vscode.window.showInformationMessage( + `Docker images are ready, please run '$docker images' to check.` + ); + + return Status.done; +} + +export async function checkIfDockerStarted(): Promise { + try { + await execShell('docker images'); + return true; + } catch (e) { + vscode.window.showWarningMessage((e as Error).message); + return false; + } +} + +export async function checkIfDockerImagesExist( + context: vscode.ExtensionContext +): Promise { + try { + /* the tag of images is equal to extension's version */ + const imageTag = getWAMRExtensionVersion(context); + await execShell( + `docker image inspect wasm-debug-server:${imageTag} wasm-toolchain:${imageTag}` + ); + return true; + } catch (e) { + return false; + } +} + +function getDockerImagesDownloadUrl( + context: vscode.ExtensionContext +): string[] { + const wamrVersion = getWAMRExtensionVersion(context); + const wamrReleaseUrl = `https://github.com/bytecodealliance/wasm-micro-runtime/releases/download/WAMR`; + + return [ + `${wamrReleaseUrl}-${wamrVersion}/wasm-debug-server-${wamrVersion}.zip`, + `${wamrReleaseUrl}-${wamrVersion}/wasm-toolchain-${wamrVersion}.zip`, + ]; +} diff --git a/test-tools/wamr-ide/VSCode-Extension/src/utilities/lldbUtilities.ts b/test-tools/wamr-ide/VSCode-Extension/src/utilities/lldbUtilities.ts index a1729ab9..210ad020 100644 --- a/test-tools/wamr-ide/VSCode-Extension/src/utilities/lldbUtilities.ts +++ b/test-tools/wamr-ide/VSCode-Extension/src/utilities/lldbUtilities.ts @@ -12,6 +12,7 @@ import { downloadFile, unzipFile, } from './directoryUtilities'; +import { SelectionOfPrompt, Status } from '../constants'; const LLDB_RESOURCE_DIR = 'resource/debug'; const LLDB_OS_DOWNLOAD_URL_SUFFIX_MAP: Partial< @@ -67,18 +68,17 @@ export function isLLDBInstalled(context: vscode.ExtensionContext): boolean { export async function promptInstallLLDB( context: vscode.ExtensionContext -): Promise { +): Promise { const extensionPath = context.extensionPath; - const setupPrompt = 'setup'; - const skipPrompt = 'skip'; + const response = await vscode.window.showWarningMessage( 'No LLDB instance found. Setup now?', - setupPrompt, - skipPrompt + SelectionOfPrompt.setUp, + SelectionOfPrompt.skip ); - if (response === skipPrompt) { - return; + if (response === SelectionOfPrompt.skip) { + return response; } const downloadUrl = getLLDBDownloadUrl(context); @@ -114,7 +114,6 @@ export async function promptInstallLLDB( ); // Remove the bundle.zip - fs.unlink(lldbZipPath, () => { - return; - }); + fs.unlinkSync(lldbZipPath); + return SelectionOfPrompt.setUp; } From 0435acdd432435e87b12178bfef0383f5c8036ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A4mes=20M=C3=A9n=C3=A9trey?= Date: Mon, 30 Jan 2023 01:24:12 +0100 Subject: [PATCH 06/33] SGX IPFS: Fix a segfault and support seeking beyond the end of files while using SEEK_CUR/SEEK_END (#1916) The current implementation throws a segmentation fault when padding files using a large range, because the writing operation overflows the source buffer, which was a single char. IPFS previously assumed that the offset for the seek operation was related to the start of the file (SEEK_SET). It now correctly checks the parameter 'whence' and computes the offset for SEEK_CUR (middle of the file) and SEEK_END (end of the file). --- core/shared/platform/linux-sgx/sgx_ipfs.c | 74 ++++++++++++++++++----- samples/file/wasm-app/main.c | 33 ++++++++-- 2 files changed, 89 insertions(+), 18 deletions(-) diff --git a/core/shared/platform/linux-sgx/sgx_ipfs.c b/core/shared/platform/linux-sgx/sgx_ipfs.c index 2b0a38ff..32268898 100644 --- a/core/shared/platform/linux-sgx/sgx_ipfs.c +++ b/core/shared/platform/linux-sgx/sgx_ipfs.c @@ -16,6 +16,11 @@ #define SGX_ERROR_FILE_LOWEST_ERROR_ID SGX_ERROR_FILE_BAD_STATUS #define SGX_ERROR_FILE_HIGHEST_ERROR_ID SGX_ERROR_FILE_CLOSE_FAILED +// Internal buffer filled with zeroes and used when extending the size of +// protected files. +#define ZEROES_PADDING_LENGTH 32 * 1024 +char zeroes_padding[ZEROES_PADDING_LENGTH] = { 0 }; + // The mapping between file descriptors and IPFS file pointers. static HashMap *ipfs_file_list; @@ -78,6 +83,27 @@ ipfs_file_destroy(void *sgx_file) sgx_fclose(sgx_file); } +// Writes a given number of zeroes in file at the current offset. +// The return value is zero if successful; otherwise non-zero. +static int +ipfs_write_zeroes(void *sgx_file, size_t len) +{ + int min_count; + + while (len > 0) { + min_count = len < ZEROES_PADDING_LENGTH ? len : ZEROES_PADDING_LENGTH; + + if (sgx_fwrite(zeroes_padding, 1, min_count, sgx_file) == 0) { + errno = convert_sgx_errno(sgx_ferror(sgx_file)); + return -1; + } + + len -= min_count; + } + + return 0; +} + int ipfs_init() { @@ -104,7 +130,7 @@ ipfs_posix_fallocate(int fd, off_t offset, size_t len) // The wrapper for fseek takes care of extending the file if sought beyond // the end - if (ipfs_lseek(fd, offset + len, SEEK_CUR) == -1) { + if (ipfs_lseek(fd, offset + len, SEEK_SET) == -1) { return errno; } @@ -354,7 +380,7 @@ ipfs_fflush(int fd) off_t ipfs_lseek(int fd, off_t offset, int nwhence) { - off_t new_offset; + off_t cursor_current_location; void *sgx_file = fd2file(fd); if (!sgx_file) { errno = EBADF; @@ -364,20 +390,20 @@ ipfs_lseek(int fd, off_t offset, int nwhence) // Optimization: if the offset is 0 and the whence is SEEK_CUR, // this is equivalent of a call to ftell. if (offset == 0 && nwhence == SEEK_CUR) { - int64_t ftell_result = (off_t)sgx_ftell(sgx_file); + cursor_current_location = (off_t)sgx_ftell(sgx_file); - if (ftell_result == -1) { + if (cursor_current_location == -1) { errno = convert_sgx_errno(sgx_ferror(sgx_file)); return -1; } - return ftell_result; + return cursor_current_location; } int fseek_result = sgx_fseek(sgx_file, offset, nwhence); if (fseek_result == 0) { - new_offset = (__wasi_filesize_t)sgx_ftell(sgx_file); + off_t new_offset = (off_t)sgx_ftell(sgx_file); if (new_offset == -1) { errno = convert_sgx_errno(sgx_ferror(sgx_file)); @@ -405,17 +431,39 @@ ipfs_lseek(int fd, off_t offset, int nwhence) // manually. // Assume the error is raised because the cursor is moved beyond the end - // of the file. Try to move the cursor at the end of the file. + // of the file. + + // If the whence is the current cursor location, retrieve it + if (nwhence == SEEK_CUR) { + cursor_current_location = (off_t)sgx_ftell(sgx_file); + } + + // Move the cursor at the end of the file if (sgx_fseek(sgx_file, 0, SEEK_END) == -1) { errno = convert_sgx_errno(sgx_ferror(sgx_file)); return -1; } + // Compute the number of zeroes to append. + int64_t number_of_zeroes; + switch (nwhence) { + case SEEK_SET: + number_of_zeroes = offset - sgx_ftell(sgx_file); + break; + case SEEK_END: + number_of_zeroes = offset; + break; + case SEEK_CUR: + number_of_zeroes = + cursor_current_location + offset - sgx_ftell(sgx_file); + break; + default: + errno = EINVAL; + return -1; + } + // Write the missing zeroes - char zero = 0; - int64_t number_of_zeroes = offset - sgx_ftell(sgx_file); - if (sgx_fwrite(&zero, 1, number_of_zeroes, sgx_file) == 0) { - errno = convert_sgx_errno(sgx_ferror(sgx_file)); + if (ipfs_write_zeroes(sgx_file, number_of_zeroes) != 0) { return -1; } @@ -468,9 +516,7 @@ ipfs_ftruncate(int fd, off_t len) // Increasing the size is equal to writing from the end of the file // with null bytes. - char null_byte = 0; - if (sgx_fwrite(&null_byte, 1, len - file_size, sgx_file) == 0) { - errno = convert_sgx_errno(sgx_ferror(sgx_file)); + if (ipfs_write_zeroes(sgx_file, len - file_size) != 0) { return -1; } diff --git a/samples/file/wasm-app/main.c b/samples/file/wasm-app/main.c index caf6436d..f4363475 100644 --- a/samples/file/wasm-app/main.c +++ b/samples/file/wasm-app/main.c @@ -18,7 +18,7 @@ #define WORLD_OFFSET 7 #define NAME_REPLACMENT "James" #define NAME_REPLACMENT_LEN (sizeof(NAME_REPLACMENT) - 1) -#define ADDITIONAL_SPACE 10 +#define ADDITIONAL_SPACE 1 * 1024 * 1024 int main(int argc, char **argv) @@ -100,7 +100,7 @@ main(int argc, char **argv) printf("[Test] Reading at specified offset passed.\n"); // Test: allocate more space to the file (posix_fallocate) - printf("Allocate more space to the file..\n"); + printf("Allocate more space to the file (posix_fallocate)..\n"); posix_fallocate(fileno(file), ftell(file), ADDITIONAL_SPACE); printf("File current offset: %ld\n", ftell(file)); printf("Moving to the end..\n"); @@ -110,8 +110,8 @@ main(int argc, char **argv) printf("[Test] Allocation or more space passed.\n"); // Test: allocate more space to the file (ftruncate) - printf("Extend the file size of 10 bytes using ftruncate..\n"); - ftruncate(fileno(file), ftell(file) + 10); + printf("Allocate more space to the file (ftruncate)..\n"); + ftruncate(fileno(file), ftell(file) + ADDITIONAL_SPACE); assert(ftell(file) == strlen(text) + ADDITIONAL_SPACE); printf("File current offset: %ld\n", ftell(file)); printf("Moving to the end..\n"); @@ -120,6 +120,31 @@ main(int argc, char **argv) assert(ftell(file) == strlen(text) + 2 * ADDITIONAL_SPACE); printf("[Test] Extension of the file size passed.\n"); + // Test: allocate more space to the file (fseek) + printf("Allocate more space to the file (fseek) from the start..\n"); + printf("File current offset: %ld\n", ftell(file)); + fseek(file, 3 * ADDITIONAL_SPACE, SEEK_SET); + printf("File current offset: %ld\n", ftell(file)); + assert(ftell(file) == 3 * ADDITIONAL_SPACE); + printf("[Test] Extension of the file size passed.\n"); + + // Test: allocate more space to the file (fseek) + printf("Allocate more space to the file (fseek) from the end..\n"); + printf("File current offset: %ld\n", ftell(file)); + fseek(file, ADDITIONAL_SPACE, SEEK_END); + printf("File current offset: %ld\n", ftell(file)); + assert(ftell(file) == 4 * ADDITIONAL_SPACE); + printf("[Test] Extension of the file size passed.\n"); + + // Test: allocate more space to the file (fseek) + printf("Allocate more space to the file (fseek) from the middle..\n"); + fseek(file, 3 * ADDITIONAL_SPACE, SEEK_SET); + printf("File current offset: %ld\n", ftell(file)); + fseek(file, 2 * ADDITIONAL_SPACE, SEEK_CUR); + printf("File current offset: %ld\n", ftell(file)); + assert(ftell(file) == 5 * ADDITIONAL_SPACE); + printf("[Test] Extension of the file size passed.\n"); + // Display some debug information printf("Getting the size of the file on disk..\n"); struct stat st; From 7d3b2a8773cc8b88ec6e661610c1d03772c4ceae Mon Sep 17 00:00:00 2001 From: YAMAMOTO Takashi Date: Wed, 1 Feb 2023 12:52:15 +0900 Subject: [PATCH 07/33] Make memory profiling show native stack usage (#1917) --- core/iwasm/aot/aot_runtime.c | 4 + core/iwasm/common/wasm_exec_env.c | 1 + core/iwasm/common/wasm_exec_env.h | 17 +++ core/iwasm/common/wasm_runtime_common.c | 16 +++ core/iwasm/compilation/aot_compiler.h | 1 + core/iwasm/compilation/aot_emit_function.c | 108 +++++++++++++++++-- core/iwasm/compilation/aot_llvm.c | 25 ++++- core/iwasm/compilation/aot_llvm.h | 5 + core/iwasm/include/aot_export.h | 1 + core/iwasm/interpreter/wasm_interp_classic.c | 1 + core/iwasm/interpreter/wasm_interp_fast.c | 1 + core/iwasm/interpreter/wasm_loader.c | 3 + core/iwasm/interpreter/wasm_mini_loader.c | 3 + core/iwasm/interpreter/wasm_runtime.c | 1 + wamr-compiler/main.c | 4 + 15 files changed, 182 insertions(+), 9 deletions(-) diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index 8ae33a47..0c94ef7c 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -30,6 +30,8 @@ bh_static_assert(offsetof(WASMExecEnv, aux_stack_boundary) bh_static_assert(offsetof(WASMExecEnv, aux_stack_bottom) == 7 * sizeof(uintptr_t)); bh_static_assert(offsetof(WASMExecEnv, native_symbol) == 8 * sizeof(uintptr_t)); +bh_static_assert(offsetof(WASMExecEnv, native_stack_top_min) + == 9 * sizeof(uintptr_t)); bh_static_assert(offsetof(AOTModuleInstance, memories) == 1 * sizeof(uint64)); bh_static_assert(offsetof(AOTModuleInstance, func_ptrs) == 5 * sizeof(uint64)); @@ -1257,6 +1259,7 @@ invoke_native_with_hw_bound_check(WASMExecEnv *exec_env, void *func_ptr, /* Check native stack overflow firstly to ensure we have enough native stack to run the following codes before actually calling the aot function in invokeNative function. */ + RECORD_STACK_USAGE(exec_env, (uint8 *)&module_inst); if ((uint8 *)&module_inst < exec_env->native_stack_boundary + page_size * (guard_page_count + 1)) { aot_set_exception_with_id(module_inst, EXCE_NATIVE_STACK_OVERFLOW); @@ -1856,6 +1859,7 @@ aot_call_indirect(WASMExecEnv *exec_env, uint32 tbl_idx, uint32 table_elem_idx, exec_env->native_stack_boundary must have been set, we don't set it again */ + RECORD_STACK_USAGE(exec_env, (uint8 *)&module_inst); if ((uint8 *)&module_inst < exec_env->native_stack_boundary) { aot_set_exception_with_id(module_inst, EXCE_NATIVE_STACK_OVERFLOW); goto fail; diff --git a/core/iwasm/common/wasm_exec_env.c b/core/iwasm/common/wasm_exec_env.c index 7939c759..9bd74d7d 100644 --- a/core/iwasm/common/wasm_exec_env.c +++ b/core/iwasm/common/wasm_exec_env.c @@ -211,6 +211,7 @@ wasm_exec_env_set_thread_info(WASMExecEnv *exec_env) exec_env->handle = os_self_thread(); exec_env->native_stack_boundary = stack_boundary ? stack_boundary + WASM_STACK_GUARD_SIZE : NULL; + exec_env->native_stack_top_min = (void *)UINTPTR_MAX; } #if WASM_ENABLE_THREAD_MGR != 0 diff --git a/core/iwasm/common/wasm_exec_env.h b/core/iwasm/common/wasm_exec_env.h index 39829207..1f139411 100644 --- a/core/iwasm/common/wasm_exec_env.h +++ b/core/iwasm/common/wasm_exec_env.h @@ -84,6 +84,12 @@ typedef struct WASMExecEnv { void **native_symbol; #endif + /* + * The lowest stack pointer value observed. + * Assumption: native stack grows to the lower address. + */ + uint8 *native_stack_top_min; + #if WASM_ENABLE_FAST_JIT != 0 /** * Cache for @@ -165,6 +171,17 @@ typedef struct WASMExecEnv { } wasm_stack; } WASMExecEnv; +#if WASM_ENABLE_MEMORY_PROFILING != 0 +#define RECORD_STACK_USAGE(e, p) \ + do { \ + if ((e)->native_stack_top_min > (p)) { \ + (e)->native_stack_top_min = (p); \ + } \ + } while (0) +#else +#define RECORD_STACK_USAGE(e, p) (void)0 +#endif + WASMExecEnv * wasm_exec_env_create_internal(struct WASMModuleInstanceCommon *module_inst, uint32 stack_size); diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index aed92edf..db35b01d 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -1399,6 +1399,22 @@ wasm_runtime_dump_mem_consumption(WASMExecEnv *exec_env) else os_printf("Total aux stack used: no enough info to profile\n"); + /* + * Report the native stack usage estimation. + * + * Unlike the aux stack above, we report the amount unused + * because we don't know the stack "bottom". + * + * Note that this is just about what the runtime itself observed. + * It doesn't cover host func implementations, signal handlers, etc. + */ + if (exec_env->native_stack_top_min != (void *)UINTPTR_MAX) + os_printf("Native stack left: %zd\n", + exec_env->native_stack_top_min + - exec_env->native_stack_boundary); + else + os_printf("Native stack left: no enough info to profile\n"); + os_printf("Total app heap used: %u\n", app_heap_peak_size); } #endif /* end of (WASM_ENABLE_MEMORY_PROFILING != 0) \ diff --git a/core/iwasm/compilation/aot_compiler.h b/core/iwasm/compilation/aot_compiler.h index d5e45f28..e6031ab8 100644 --- a/core/iwasm/compilation/aot_compiler.h +++ b/core/iwasm/compilation/aot_compiler.h @@ -259,6 +259,7 @@ check_type_compatible(uint8 src_type, uint8 dst_type) #define I32_SIX LLVM_CONST(i32_six) #define I32_SEVEN LLVM_CONST(i32_seven) #define I32_EIGHT LLVM_CONST(i32_eight) +#define I32_NINE LLVM_CONST(i32_nine) #define I32_NEG_ONE LLVM_CONST(i32_neg_one) #define I64_NEG_ONE LLVM_CONST(i64_neg_one) #define I32_MIN LLVM_CONST(i32_min) diff --git a/core/iwasm/compilation/aot_emit_function.c b/core/iwasm/compilation/aot_emit_function.c index d6a5a4ab..4ac62a9e 100644 --- a/core/iwasm/compilation/aot_emit_function.c +++ b/core/iwasm/compilation/aot_emit_function.c @@ -366,6 +366,87 @@ fail: #endif /* end of (WASM_ENABLE_DUMP_CALL_STACK != 0) \ || (WASM_ENABLE_PERF_PROFILING != 0) */ +static bool +record_stack_usage(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, + uint32 callee_cell_num) +{ + LLVMBasicBlockRef block_curr = LLVMGetInsertBlock(comp_ctx->builder); + LLVMBasicBlockRef block_update; + LLVMBasicBlockRef block_after_update; + LLVMValueRef callee_local_size, new_sp, cmp; + LLVMValueRef native_stack_top_min; + LLVMTypeRef ptrdiff_type; + if (comp_ctx->pointer_size == sizeof(uint64_t)) { + ptrdiff_type = I64_TYPE; + } + else { + ptrdiff_type = I32_TYPE; + } + + /* + * new_sp = last_alloca - callee_local_size; + * if (*native_stack_top_min_addr > new_sp) { + * *native_stack_top_min_addr = new_sp; + * } + */ + + if (!(callee_local_size = LLVMConstInt( + ptrdiff_type, -(int64_t)callee_cell_num * 4, true))) { + aot_set_last_error("llvm build const failed."); + return false; + } + if (!(new_sp = LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE, + func_ctx->last_alloca, + &callee_local_size, 1, "new_sp"))) { + aot_set_last_error("llvm build gep failed"); + return false; + } + if (!(native_stack_top_min = LLVMBuildLoad2( + comp_ctx->builder, OPQ_PTR_TYPE, + func_ctx->native_stack_top_min_addr, "native_stack_top_min"))) { + aot_set_last_error("llvm build load failed"); + return false; + } + if (!(cmp = LLVMBuildICmp(comp_ctx->builder, LLVMIntULT, new_sp, + native_stack_top_min, "cmp"))) { + aot_set_last_error("llvm build icmp failed."); + return false; + } + + if (!(block_update = LLVMAppendBasicBlockInContext( + comp_ctx->context, func_ctx->func, "block_update"))) { + aot_set_last_error("llvm add basic block failed."); + return false; + } + if (!(block_after_update = LLVMAppendBasicBlockInContext( + comp_ctx->context, func_ctx->func, "block_after_update"))) { + aot_set_last_error("llvm add basic block failed."); + return false; + } + LLVMMoveBasicBlockAfter(block_update, block_curr); + LLVMMoveBasicBlockAfter(block_after_update, block_update); + + if (!LLVMBuildCondBr(comp_ctx->builder, cmp, block_update, + block_after_update)) { + aot_set_last_error("llvm build cond br failed."); + return false; + } + + LLVMPositionBuilderAtEnd(comp_ctx->builder, block_update); + if (!LLVMBuildStore(comp_ctx->builder, new_sp, + func_ctx->native_stack_top_min_addr)) { + aot_set_last_error("llvm build store failed"); + return false; + } + if (!LLVMBuildBr(comp_ctx->builder, block_after_update)) { + aot_set_last_error("llvm build br failed."); + return false; + } + + LLVMPositionBuilderAtEnd(comp_ctx->builder, block_after_update); + return true; +} + static bool check_stack_boundary(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, uint32 callee_cell_num) @@ -409,6 +490,19 @@ check_stack_boundary(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, return true; } +static bool +check_stack(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, + uint32 callee_cell_num) +{ + if (comp_ctx->enable_stack_estimation + && !record_stack_usage(comp_ctx, func_ctx, callee_cell_num)) + return false; + if (comp_ctx->enable_stack_bound_check + && !check_stack_boundary(comp_ctx, func_ctx, callee_cell_num)) + return false; + return true; +} + /** * Check whether the app address and its buffer are inside the linear memory, * if no, throw exception @@ -852,8 +946,7 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, callee_cell_num = aot_func->param_cell_num + aot_func->local_cell_num + 1; - if (comp_ctx->enable_stack_bound_check - && !check_stack_boundary(comp_ctx, func_ctx, callee_cell_num)) + if (!check_stack(comp_ctx, func_ctx, callee_cell_num)) goto fail; #if LLVM_VERSION_MAJOR >= 14 @@ -1467,12 +1560,11 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, /* Translate call non-import block */ LLVMPositionBuilderAtEnd(comp_ctx->builder, block_call_non_import); - if (comp_ctx->enable_stack_bound_check - && !check_stack_boundary(comp_ctx, func_ctx, - param_cell_num + ext_cell_num - + 1 - /* Reserve some local variables */ - + 16)) + if (!check_stack(comp_ctx, func_ctx, + param_cell_num + ext_cell_num + + 1 + /* Reserve some local variables */ + + 16)) goto fail; /* Load function pointer */ diff --git a/core/iwasm/compilation/aot_llvm.c b/core/iwasm/compilation/aot_llvm.c index 889ab259..27550560 100644 --- a/core/iwasm/compilation/aot_llvm.c +++ b/core/iwasm/compilation/aot_llvm.c @@ -286,6 +286,21 @@ create_native_stack_bound(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) return true; } +static bool +create_native_stack_top_min(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) +{ + LLVMValueRef offset = I32_NINE; + + if (!(func_ctx->native_stack_top_min_addr = LLVMBuildInBoundsGEP2( + comp_ctx->builder, OPQ_PTR_TYPE, func_ctx->exec_env, &offset, 1, + "native_stack_top_min_addr"))) { + aot_set_last_error("llvm build in bounds gep failed"); + return false; + } + + return true; +} + static bool create_aux_stack_info(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) { @@ -434,7 +449,8 @@ create_local_variables(AOTCompData *comp_data, AOTCompContext *comp_ctx, } } - if (comp_ctx->enable_stack_bound_check) { + if (comp_ctx->enable_stack_bound_check + || comp_ctx->enable_stack_estimation) { if (aot_func_type->param_count + func->local_count > 0) { func_ctx->last_alloca = func_ctx->locals[aot_func_type->param_count + func->local_count - 1]; @@ -963,6 +979,10 @@ aot_create_func_context(AOTCompData *comp_data, AOTCompContext *comp_ctx, && !create_native_stack_bound(comp_ctx, func_ctx)) { goto fail; } + if (comp_ctx->enable_stack_estimation + && !create_native_stack_top_min(comp_ctx, func_ctx)) { + goto fail; + } /* Get auxiliary stack info */ if (wasm_func->has_op_set_global_aux_stack @@ -1622,6 +1642,9 @@ aot_create_comp_context(AOTCompData *comp_data, aot_comp_option_t option) if (option->disable_llvm_lto) comp_ctx->disable_llvm_lto = true; + if (option->enable_stack_estimation) + comp_ctx->enable_stack_estimation = true; + comp_ctx->opt_level = option->opt_level; comp_ctx->size_level = option->size_level; diff --git a/core/iwasm/compilation/aot_llvm.h b/core/iwasm/compilation/aot_llvm.h index 219f36e7..b982e808 100644 --- a/core/iwasm/compilation/aot_llvm.h +++ b/core/iwasm/compilation/aot_llvm.h @@ -163,6 +163,7 @@ typedef struct AOTFuncContext { LLVMValueRef aot_inst; LLVMValueRef argv_buf; LLVMValueRef native_stack_bound; + LLVMValueRef native_stack_top_min_addr; LLVMValueRef aux_stack_bound; LLVMValueRef aux_stack_bottom; LLVMValueRef native_symbol; @@ -313,6 +314,9 @@ typedef struct AOTCompContext { /* Native stack bounday Check */ bool enable_stack_bound_check; + /* Native stack usage estimation */ + bool enable_stack_estimation; + /* 128-bit SIMD */ bool enable_simd; @@ -403,6 +407,7 @@ typedef struct AOTCompOption { bool enable_aux_stack_frame; bool disable_llvm_intrinsics; bool disable_llvm_lto; + bool enable_stack_estimation; uint32 opt_level; uint32 size_level; uint32 output_format; diff --git a/core/iwasm/include/aot_export.h b/core/iwasm/include/aot_export.h index f8df168e..792a4baa 100644 --- a/core/iwasm/include/aot_export.h +++ b/core/iwasm/include/aot_export.h @@ -55,6 +55,7 @@ typedef struct AOTCompOption { bool enable_aux_stack_frame; bool disable_llvm_intrinsics; bool disable_llvm_lto; + bool enable_stack_estimation; uint32_t opt_level; uint32_t size_level; uint32_t output_format; diff --git a/core/iwasm/interpreter/wasm_interp_classic.c b/core/iwasm/interpreter/wasm_interp_classic.c index 3e16b380..3c43dcdc 100644 --- a/core/iwasm/interpreter/wasm_interp_classic.c +++ b/core/iwasm/interpreter/wasm_interp_classic.c @@ -4150,6 +4150,7 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env, } argc = function->param_cell_num; + RECORD_STACK_USAGE(exec_env, (uint8 *)&prev_frame); #if !(defined(OS_ENABLE_HW_BOUND_CHECK) \ && WASM_DISABLE_STACK_HW_BOUND_CHECK == 0) if ((uint8 *)&prev_frame < exec_env->native_stack_boundary) { diff --git a/core/iwasm/interpreter/wasm_interp_fast.c b/core/iwasm/interpreter/wasm_interp_fast.c index 0ea920f2..7209f7bd 100644 --- a/core/iwasm/interpreter/wasm_interp_fast.c +++ b/core/iwasm/interpreter/wasm_interp_fast.c @@ -3901,6 +3901,7 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env, } argc = function->param_cell_num; + RECORD_STACK_USAGE(exec_env, (uint8 *)&prev_frame); #if !(defined(OS_ENABLE_HW_BOUND_CHECK) \ && WASM_DISABLE_STACK_HW_BOUND_CHECK == 0) if ((uint8 *)&prev_frame < exec_env->native_stack_boundary) { diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index d0a10b86..f60f9efb 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -3048,6 +3048,9 @@ init_llvm_jit_functions_stage1(WASMModule *module, char *error_buf, #if (WASM_ENABLE_PERF_PROFILING != 0) || (WASM_ENABLE_DUMP_CALL_STACK != 0) option.enable_aux_stack_frame = true; #endif +#if WASM_ENABLE_MEMORY_PROFILING != 0 + option.enable_stack_estimation = true; +#endif module->comp_ctx = aot_create_comp_context(module->comp_data, &option); if (!module->comp_ctx) { diff --git a/core/iwasm/interpreter/wasm_mini_loader.c b/core/iwasm/interpreter/wasm_mini_loader.c index b1243a06..815dffa0 100644 --- a/core/iwasm/interpreter/wasm_mini_loader.c +++ b/core/iwasm/interpreter/wasm_mini_loader.c @@ -1894,6 +1894,9 @@ init_llvm_jit_functions_stage1(WASMModule *module, char *error_buf, #if (WASM_ENABLE_PERF_PROFILING != 0) || (WASM_ENABLE_DUMP_CALL_STACK != 0) option.enable_aux_stack_frame = true; #endif +#if WASM_ENABLE_MEMORY_PROFILING != 0 + option.enable_stack_estimation = true; +#endif module->comp_ctx = aot_create_comp_context(module->comp_data, &option); if (!module->comp_ctx) { diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index ff3f4f2f..baded7aa 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -2074,6 +2074,7 @@ call_wasm_with_hw_bound_check(WASMModuleInstance *module_inst, /* Check native stack overflow firstly to ensure we have enough native stack to run the following codes before actually calling the aot function in invokeNative function. */ + RECORD_STACK_USAGE(exec_env, (uint8 *)&exec_env_tls); if ((uint8 *)&exec_env_tls < exec_env->native_stack_boundary + page_size * (guard_page_count + 1)) { wasm_set_exception(module_inst, "native stack overflow"); diff --git a/wamr-compiler/main.c b/wamr-compiler/main.c index 28986e86..f185a17b 100644 --- a/wamr-compiler/main.c +++ b/wamr-compiler/main.c @@ -59,6 +59,7 @@ print_help() printf(" --disable-aux-stack-check Disable auxiliary stack overflow/underflow check\n"); printf(" --enable-dump-call-stack Enable stack trace feature\n"); printf(" --enable-perf-profiling Enable function performance profiling\n"); + printf(" --enable-memory-profiling Enable memory usage profiling\n"); printf(" --enable-indirect-mode Enalbe call function through symbol table but not direct call\n"); printf(" --disable-llvm-intrinsics Disable the LLVM built-in intrinsics\n"); printf(" --disable-llvm-lto Disable the LLVM link time optimization\n"); @@ -254,6 +255,9 @@ main(int argc, char *argv[]) else if (!strcmp(argv[0], "--enable-perf-profiling")) { option.enable_aux_stack_frame = true; } + else if (!strcmp(argv[0], "--enable-memory-profiling")) { + option.enable_stack_estimation = true; + } else if (!strcmp(argv[0], "--enable-indirect-mode")) { option.is_indirect_mode = true; } From fe3347d5d2d92c3a78d77c55877692bc07ac8888 Mon Sep 17 00:00:00 2001 From: HongxiaWangSSSS <103626902+HongxiaWangSSSS@users.noreply.github.com> Date: Wed, 1 Feb 2023 17:52:46 +0800 Subject: [PATCH 08/33] Fixed the undef error about WAMR_BUILD_MEMORY_PROFILING (#1926) --- core/iwasm/common/wasm_c_api.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/iwasm/common/wasm_c_api.c b/core/iwasm/common/wasm_c_api.c index 10398b26..2b29330a 100644 --- a/core/iwasm/common/wasm_c_api.c +++ b/core/iwasm/common/wasm_c_api.c @@ -276,7 +276,7 @@ WASM_DEFINE_VEC_OWN(store, wasm_store_delete) WASM_DEFINE_VEC_OWN(valtype, wasm_valtype_delete) #ifndef NDEBUG -#if WAMR_BUILD_MEMORY_PROFILING != 0 +#if WASM_ENABLE_MEMORY_PROFILING != 0 #define WASM_C_DUMP_PROC_MEM() LOG_PROC_MEM() #else #define WASM_C_DUMP_PROC_MEM() (void)0 From 1614ce12fa053d5915fb6d6b70cc234aa9a4b483 Mon Sep 17 00:00:00 2001 From: tonibofarull Date: Thu, 2 Feb 2023 01:09:46 +0100 Subject: [PATCH 09/33] wasi-nn: Enable GPU support (#1922) - Split logic in several dockers - runtime: wasi-nn-cpu and wasi-nn- Nvidia-gpu. - compilation: wasi-nn-compile. Prepare the testing wasm and generates the TFLites. - Implement GPU support for TFLite with Opencl. --- core/iwasm/libraries/wasi-nn/README.md | 55 +++++++++++++-- .../wasi-nn/src/wasi_nn_tensorflowlite.cpp | 28 +++++++- .../libraries/wasi-nn/test/.dockerignore | 1 - .../libraries/wasi-nn/test/CMakeLists.txt | 4 +- .../libraries/wasi-nn/test/Dockerfile.base | 22 ++++++ .../test/{Dockerfile => Dockerfile.compile} | 25 ++----- .../libraries/wasi-nn/test/Dockerfile.cpu | 8 +++ .../wasi-nn/test/Dockerfile.nvidia-gpu | 20 ++++++ core/iwasm/libraries/wasi-nn/test/build.sh | 2 +- .../libraries/wasi-nn/test/test_tensorflow.c | 69 ++++++++++++------- 10 files changed, 178 insertions(+), 56 deletions(-) delete mode 100644 core/iwasm/libraries/wasi-nn/test/.dockerignore create mode 100644 core/iwasm/libraries/wasi-nn/test/Dockerfile.base rename core/iwasm/libraries/wasi-nn/test/{Dockerfile => Dockerfile.compile} (54%) create mode 100644 core/iwasm/libraries/wasi-nn/test/Dockerfile.cpu create mode 100644 core/iwasm/libraries/wasi-nn/test/Dockerfile.nvidia-gpu mode change 100755 => 100644 core/iwasm/libraries/wasi-nn/test/test_tensorflow.c diff --git a/core/iwasm/libraries/wasi-nn/README.md b/core/iwasm/libraries/wasi-nn/README.md index ed3fbd54..efd8fbfc 100644 --- a/core/iwasm/libraries/wasi-nn/README.md +++ b/core/iwasm/libraries/wasi-nn/README.md @@ -17,24 +17,69 @@ By only including this file in your WASM application you will bind WASI-NN into To run the tests we assume that the current directory is the root of the repository. -1. Build the docker image, +### Build the runtime + +Build the runtime base image, ``` -docker build -t wasi-nn -f core/iwasm/libraries/wasi-nn/test/Dockerfile . +docker build -t wasi-nn-base -f core/iwasm/libraries/wasi-nn/test/Dockerfile.base . ``` -2. Run the container +Build the runtime image for your execution target type. + +`EXECUTION_TYPE` can be: +* `cpu` +* `nvidia-gpu` ``` -docker run wasi-nn +EXECUTION_TYPE=cpu +docker build -t wasi-nn-${EXECUTION_TYPE} -f core/iwasm/libraries/wasi-nn/test/Dockerfile.${EXECUTION_TYPE} . ``` + +### Build wasm app + +``` +docker build -t wasi-nn-compile -f core/iwasm/libraries/wasi-nn/test/Dockerfile.compile . +``` + +``` +docker run -v $PWD/core/iwasm/libraries/wasi-nn:/wasi-nn wasi-nn-compile +``` + + +### Run wasm app + If all the tests have run properly you will the the following message in the terminal, ``` Tests: passed! ``` +* CPU + +``` +docker run \ + -v $PWD/core/iwasm/libraries/wasi-nn/test:/assets wasi-nn-cpu \ + --dir=/assets \ + --env="TARGET=cpu" \ + /assets/test_tensorflow.wasm +``` + +* (NVIDIA) GPU + +``` +docker run \ + --runtime=nvidia \ + -v $PWD/core/iwasm/libraries/wasi-nn/test:/assets wasi-nn-nvidia-gpu \ + --dir=/assets \ + --env="TARGET=gpu" \ + /assets/test_tensorflow.wasm +``` + +Requirements: +* [NVIDIA docker](https://github.com/NVIDIA/nvidia-docker). + ## What is missing Supported: @@ -43,5 +88,5 @@ Supported: * Only 1 model at a time. * `graph` and `graph-execution-context` are ignored. * Graph encoding: `tensorflowlite`. -* Execution target: `cpu`. +* Execution target: `cpu` and `gpu`. * Tensor type: `fp32`. diff --git a/core/iwasm/libraries/wasi-nn/src/wasi_nn_tensorflowlite.cpp b/core/iwasm/libraries/wasi-nn/src/wasi_nn_tensorflowlite.cpp index b795a7fe..d40e2399 100644 --- a/core/iwasm/libraries/wasi-nn/src/wasi_nn_tensorflowlite.cpp +++ b/core/iwasm/libraries/wasi-nn/src/wasi_nn_tensorflowlite.cpp @@ -16,6 +16,7 @@ #include #include #include +#include /* Global variables */ @@ -45,8 +46,8 @@ tensorflowlite_load(graph_builder_array *builder, graph_encoding encoding, return invalid_argument; } - if (target != cpu) { - NN_ERR_PRINTF("Only CPU target is supported."); + if (target != cpu && target != gpu) { + NN_ERR_PRINTF("Only CPU and GPU target is supported."); return invalid_argument; } @@ -79,6 +80,29 @@ tensorflowlite_load(graph_builder_array *builder, graph_encoding encoding, return missing_memory; } + bool use_default = false; + switch (target) { + case gpu: + { + // https://www.tensorflow.org/lite/performance/gpu + auto options = TfLiteGpuDelegateOptionsV2Default(); + options.inference_preference = + TFLITE_GPU_INFERENCE_PREFERENCE_SUSTAINED_SPEED; + options.inference_priority1 = + TFLITE_GPU_INFERENCE_PRIORITY_MIN_LATENCY; + auto *delegate = TfLiteGpuDelegateV2Create(&options); + if (interpreter->ModifyGraphWithDelegate(delegate) != kTfLiteOk) { + NN_ERR_PRINTF("Error when enabling GPU delegate."); + use_default = true; + } + break; + } + default: + use_default = true; + } + if (use_default) + NN_WARN_PRINTF("Default encoding is CPU."); + return success; } diff --git a/core/iwasm/libraries/wasi-nn/test/.dockerignore b/core/iwasm/libraries/wasi-nn/test/.dockerignore deleted file mode 100644 index 94143827..00000000 --- a/core/iwasm/libraries/wasi-nn/test/.dockerignore +++ /dev/null @@ -1 +0,0 @@ -Dockerfile diff --git a/core/iwasm/libraries/wasi-nn/test/CMakeLists.txt b/core/iwasm/libraries/wasi-nn/test/CMakeLists.txt index 7951dec4..eff716bd 100644 --- a/core/iwasm/libraries/wasi-nn/test/CMakeLists.txt +++ b/core/iwasm/libraries/wasi-nn/test/CMakeLists.txt @@ -7,10 +7,10 @@ project (iwasm) set (CMAKE_VERBOSE_MAKEFILE OFF) # Reset default linker flags -set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") -set (CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") set (CMAKE_C_STANDARD 99) set (CMAKE_CXX_STANDARD 14) +set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") +set (CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") if (NOT DEFINED WAMR_BUILD_PLATFORM) set (WAMR_BUILD_PLATFORM "linux") diff --git a/core/iwasm/libraries/wasi-nn/test/Dockerfile.base b/core/iwasm/libraries/wasi-nn/test/Dockerfile.base new file mode 100644 index 00000000..769c5389 --- /dev/null +++ b/core/iwasm/libraries/wasi-nn/test/Dockerfile.base @@ -0,0 +1,22 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +FROM ubuntu:20.04 AS base + +ENV DEBIAN_FRONTEND=noninteractive + +RUN apt-get update && apt-get install -y \ + cmake build-essential git + +WORKDIR /home/wamr + +COPY . . + +WORKDIR /home/wamr/core/iwasm/libraries/wasi-nn/test/build + +RUN cmake \ + -DWAMR_BUILD_WASI_NN=1 \ + -DTFLITE_ENABLE_GPU=ON \ + .. + +RUN make -j $(grep -c ^processor /proc/cpuinfo) diff --git a/core/iwasm/libraries/wasi-nn/test/Dockerfile b/core/iwasm/libraries/wasi-nn/test/Dockerfile.compile similarity index 54% rename from core/iwasm/libraries/wasi-nn/test/Dockerfile rename to core/iwasm/libraries/wasi-nn/test/Dockerfile.compile index cb6bfa02..51a59707 100644 --- a/core/iwasm/libraries/wasi-nn/test/Dockerfile +++ b/core/iwasm/libraries/wasi-nn/test/Dockerfile.compile @@ -1,38 +1,23 @@ # Copyright (C) 2019 Intel Corporation. All rights reserved. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -FROM ubuntu:22.04 +FROM ubuntu:20.04 ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update && apt-get install -y \ cmake build-essential git wget python3.10 python3-pip -ARG WASI_SDK_VER=16 +ARG WASI_SDK_VER=19 RUN wget -c --progress=dot:giga https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-${WASI_SDK_VER}/wasi-sdk-${WASI_SDK_VER}.0-linux.tar.gz -P /opt \ && tar xf /opt/wasi-sdk-${WASI_SDK_VER}.0-linux.tar.gz -C /opt \ && ln -fs /opt/wasi-sdk-${WASI_SDK_VER}.0 /opt/wasi-sdk \ && rm /opt/wasi-sdk-${WASI_SDK_VER}.0-linux.tar.gz -WORKDIR /home/wamr - -COPY core/deps/install_tensorflow.sh core/deps/install_tensorflow.sh -RUN ./core/deps/install_tensorflow.sh +WORKDIR /wasi-nn/test COPY core/iwasm/libraries/wasi-nn/test/requirements.txt . -RUN pip3 install -r requirements.txt -COPY core core -COPY build-scripts build-scripts -COPY product-mini product-mini +RUN pip3 install -r requirements.txt && rm requirements.txt -WORKDIR /home/wamr/core/iwasm/libraries/wasi-nn/test/build - -RUN cmake -DWAMR_BUILD_WASI_NN=1 .. -RUN make -j $(grep -c ^processor /proc/cpuinfo) - -WORKDIR /home/wamr/core/iwasm/libraries/wasi-nn/test - -RUN ./build.sh - -ENTRYPOINT [ "./build/iwasm", "--dir=.", "test_tensorflow.wasm" ] +ENTRYPOINT [ "bash", "./build.sh" ] diff --git a/core/iwasm/libraries/wasi-nn/test/Dockerfile.cpu b/core/iwasm/libraries/wasi-nn/test/Dockerfile.cpu new file mode 100644 index 00000000..cec918cb --- /dev/null +++ b/core/iwasm/libraries/wasi-nn/test/Dockerfile.cpu @@ -0,0 +1,8 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +FROM ubuntu:20.04 + +COPY --from=wasi-nn-base /home/wamr/core/iwasm/libraries/wasi-nn/test/build/iwasm /run/iwasm + +ENTRYPOINT [ "/run/iwasm" ] diff --git a/core/iwasm/libraries/wasi-nn/test/Dockerfile.nvidia-gpu b/core/iwasm/libraries/wasi-nn/test/Dockerfile.nvidia-gpu new file mode 100644 index 00000000..3d876efb --- /dev/null +++ b/core/iwasm/libraries/wasi-nn/test/Dockerfile.nvidia-gpu @@ -0,0 +1,20 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +FROM nvidia/cuda:11.3.0-runtime-ubuntu20.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + ocl-icd-libopencl1 \ + ocl-icd-opencl-dev \ + clinfo && \ + rm -rf /var/lib/apt/lists/* + +RUN mkdir -p /etc/OpenCL/vendors && \ + echo "libnvidia-opencl.so.1" > /etc/OpenCL/vendors/nvidia.icd + +ENV NVIDIA_VISIBLE_DEVICES=all +ENV NVIDIA_DRIVER_CAPABILITIES=compute,utility + +COPY --from=wasi-nn-base /home/wamr/core/iwasm/libraries/wasi-nn/test/build/iwasm /run/iwasm + +ENTRYPOINT [ "/run/iwasm" ] diff --git a/core/iwasm/libraries/wasi-nn/test/build.sh b/core/iwasm/libraries/wasi-nn/test/build.sh index 4dc8d015..dbf2f2d6 100755 --- a/core/iwasm/libraries/wasi-nn/test/build.sh +++ b/core/iwasm/libraries/wasi-nn/test/build.sh @@ -7,7 +7,7 @@ -Wl,--allow-undefined \ -Wl,--strip-all,--no-entry \ --sysroot=/opt/wasi-sdk/share/wasi-sysroot \ - -I/home/wamr/core/iwasm/libraries/wasi-nn \ + -I.. \ -o test_tensorflow.wasm test_tensorflow.c # TFLite models to use in the tests diff --git a/core/iwasm/libraries/wasi-nn/test/test_tensorflow.c b/core/iwasm/libraries/wasi-nn/test/test_tensorflow.c old mode 100755 new mode 100644 index f813b6bc..46883d23 --- a/core/iwasm/libraries/wasi-nn/test/test_tensorflow.c +++ b/core/iwasm/libraries/wasi-nn/test/test_tensorflow.c @@ -28,7 +28,7 @@ typedef struct { // WASI-NN wrappers error -wasm_load(char *model_name, graph *g) +wasm_load(char *model_name, graph *g, execution_target target) { FILE *pFile = fopen(model_name, "r"); if (pFile == NULL) @@ -64,7 +64,7 @@ wasm_load(char *model_name, graph *g) arr.buf[0].size = result; arr.buf[0].buf = buffer; - error res = load(&arr, tensorflowlite, cpu, g); + error res = load(&arr, tensorflowlite, target, g); fclose(pFile); free(buffer); @@ -115,11 +115,12 @@ wasm_get_output(graph_execution_context ctx, uint32_t index, float *out_tensor, // Inference float * -run_inference(float *input, uint32_t *input_size, uint32_t *output_size, - char *model_name, uint32_t num_output_tensors) +run_inference(execution_target target, float *input, uint32_t *input_size, + uint32_t *output_size, char *model_name, + uint32_t num_output_tensors) { graph graph; - if (wasm_load(model_name, &graph) != success) { + if (wasm_load(model_name, &graph, target) != success) { fprintf(stderr, "Error when loading model."); exit(1); } @@ -185,14 +186,14 @@ create_input(int *dims) // TESTS void -test_sum() +test_sum(execution_target target) { int dims[] = { 1, 5, 5, 1 }; input_info input = create_input(dims); uint32_t output_size = 0; - float *output = run_inference(input.input_tensor, input.dim, &output_size, - "models/sum.tflite", 1); + float *output = run_inference(target, input.input_tensor, input.dim, + &output_size, "/assets/models/sum.tflite", 1); assert(output_size == 1); assert(fabs(output[0] - 300.0) < EPSILON); @@ -203,14 +204,14 @@ test_sum() } void -test_max() +test_max(execution_target target) { int dims[] = { 1, 5, 5, 1 }; input_info input = create_input(dims); uint32_t output_size = 0; - float *output = run_inference(input.input_tensor, input.dim, &output_size, - "models/max.tflite", 1); + float *output = run_inference(target, input.input_tensor, input.dim, + &output_size, "/assets/models/max.tflite", 1); assert(output_size == 1); assert(fabs(output[0] - 24.0) < EPSILON); @@ -222,14 +223,15 @@ test_max() } void -test_average() +test_average(execution_target target) { int dims[] = { 1, 5, 5, 1 }; input_info input = create_input(dims); uint32_t output_size = 0; - float *output = run_inference(input.input_tensor, input.dim, &output_size, - "models/average.tflite", 1); + float *output = + run_inference(target, input.input_tensor, input.dim, &output_size, + "/assets/models/average.tflite", 1); assert(output_size == 1); assert(fabs(output[0] - 12.0) < EPSILON); @@ -241,14 +243,15 @@ test_average() } void -test_mult_dimensions() +test_mult_dimensions(execution_target target) { int dims[] = { 1, 3, 3, 1 }; input_info input = create_input(dims); uint32_t output_size = 0; - float *output = run_inference(input.input_tensor, input.dim, &output_size, - "models/mult_dim.tflite", 1); + float *output = + run_inference(target, input.input_tensor, input.dim, &output_size, + "/assets/models/mult_dim.tflite", 1); assert(output_size == 9); for (int i = 0; i < 9; i++) @@ -260,14 +263,15 @@ test_mult_dimensions() } void -test_mult_outputs() +test_mult_outputs(execution_target target) { int dims[] = { 1, 4, 4, 1 }; input_info input = create_input(dims); uint32_t output_size = 0; - float *output = run_inference(input.input_tensor, input.dim, &output_size, - "models/mult_out.tflite", 2); + float *output = + run_inference(target, input.input_tensor, input.dim, &output_size, + "/assets/models/mult_out.tflite", 2); assert(output_size == 8); // first tensor check @@ -285,16 +289,31 @@ test_mult_outputs() int main() { + char *env = getenv("TARGET"); + if (env == NULL) { + printf("Usage:\n--env=\"TARGET=[cpu|gpu]\"\n"); + return 1; + } + execution_target target; + if (strcmp(env, "cpu") == 0) + target = cpu; + else if (strcmp(env, "gpu") == 0) + target = gpu; + else { + printf("Wrong target!"); + return 1; + } printf("################### Testing sum...\n"); - test_sum(); + test_sum(target); printf("################### Testing max...\n"); - test_max(); + test_max(target); printf("################### Testing average...\n"); - test_average(); + test_average(target); printf("################### Testing multiple dimensions...\n"); - test_mult_dimensions(); + test_mult_dimensions(target); printf("################### Testing multiple outputs...\n"); - test_mult_outputs(); + test_mult_outputs(target); + printf("Tests: passed!\n"); return 0; } From 27e7e160af54fe8a74620c4fbfacad480b5cb00c Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Thu, 2 Feb 2023 09:42:25 +0800 Subject: [PATCH 10/33] Upgrade toolkits (#1878) Upgrade the version of related toolkits: - upgrade llvm to 15.0 - upgrade wasi-sdk to 19.0 - upgrade emsdk to 3.1.28 - upgrade wabt to 1.0.31 - upgrade binaryen to 111 And upgrade the CI scripts, sample workload build scripts, Dockerfiles, and documents. --- .devcontainer/Dockerfile | 59 +++-- .devcontainer/devcontainer.json | 12 +- .github/workflows/build_llvm_libraries.yml | 70 +++++- .../compilation_on_android_ubuntu.yml | 123 +++++----- .github/workflows/compilation_on_macos.yml | 71 +++--- .github/workflows/compilation_on_sgx.yml | 57 +++-- .github/workflows/release_process.yml | 6 +- .github/workflows/spec_test_on_nuttx.yml | 10 +- .gitignore | 3 + build-scripts/build_llvm.py | 86 ++++--- doc/build_wasm_app.md | 4 +- samples/wasm-c-api/CMakeLists.txt | 27 +-- samples/wasm-c-api/README.md | 8 +- samples/workload/CMakeLists.txt | 116 ++++++++++ samples/workload/README.md | 29 +-- samples/workload/XNNPACK/CMakeLists.txt | 62 ++++- samples/workload/XNNPACK/README.md | 4 +- samples/workload/XNNPACK/build_workload.sh | 1 - samples/workload/XNNPACK/xnnpack.patch | 84 ++++--- samples/workload/bwa/CMakeLists.bwa_wasm.txt | 15 +- samples/workload/bwa/CMakeLists.txt | 43 +++- samples/workload/bwa/README.md | 4 +- samples/workload/bwa/build_workload.sh | 1 - samples/workload/cmake/FindBinaryen.cmake | 43 ++++ samples/workload/cmake/FindWASISDK.cmake | 38 ++++ samples/workload/cmake/preparation.cmake | 49 ---- samples/workload/docker/build_workload.sh | 33 --- samples/workload/include/.gitkeep | 0 samples/workload/meshoptimizer/CMakeLists.txt | 22 +- samples/workload/meshoptimizer/README.md | 4 +- .../workload/meshoptimizer/build_workload.sh | 1 - samples/workload/preparation.sh | 12 +- samples/workload/tensorflow/build.sh | 10 +- .../workload/wasm-av1/CMakeLists.avx_wasm.txt | 10 +- samples/workload/wasm-av1/CMakeLists.txt | 24 +- samples/workload/wasm-av1/README.md | 4 +- samples/workload/wasm-av1/build.sh | 4 +- samples/workload/wasm-av1/build_workload.sh | 1 - .../build-wasi-sdk/patches/wasi_libc.patch | 13 -- .../build-wasi-sdk/patches/wasi_sdk.patch | 15 -- .../collect_files.py} | 211 ++++++------------ .../wamr-ide/WASM-Toolchain/Docker/Dockerfile | 12 +- tests/wamr-test-suites/test_wamr.sh | 10 +- 43 files changed, 817 insertions(+), 594 deletions(-) create mode 100644 samples/workload/CMakeLists.txt delete mode 120000 samples/workload/XNNPACK/build_workload.sh delete mode 120000 samples/workload/bwa/build_workload.sh create mode 100644 samples/workload/cmake/FindBinaryen.cmake create mode 100644 samples/workload/cmake/FindWASISDK.cmake delete mode 100644 samples/workload/cmake/preparation.cmake delete mode 100755 samples/workload/docker/build_workload.sh create mode 100644 samples/workload/include/.gitkeep delete mode 120000 samples/workload/meshoptimizer/build_workload.sh delete mode 120000 samples/workload/wasm-av1/build_workload.sh delete mode 100644 test-tools/build-wasi-sdk/patches/wasi_libc.patch delete mode 100644 test-tools/build-wasi-sdk/patches/wasi_sdk.patch rename test-tools/{build-wasi-sdk/build_wasi_sdk.py => pick-up-emscripten-headers/collect_files.py} (50%) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 5ddba8f3..7ccfa246 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -12,7 +12,7 @@ ENV TZ=Asian/Shanghai # hadolint ignore=DL3008 RUN apt-get update \ && apt-get install -y apt-transport-https apt-utils build-essential \ - ca-certificates curl g++-multilib git gnupg \ + ca-certificates ccache curl g++-multilib git gnupg \ libgcc-9-dev lib32gcc-9-dev lsb-release \ ninja-build ocaml ocamlbuild python2.7 \ software-properties-common tree tzdata \ @@ -20,6 +20,15 @@ RUN apt-get update \ && apt-get clean -y \ && rm -rf /var/lib/apt/lists/* +# +# binaryen +ARG BINARYEN_VER=111 +WORKDIR /opt +RUN wget -c --progress=dot:giga https://github.com/WebAssembly/binaryen/releases/download/version_${BINARYEN_VER}/binaryen-version_${BINARYEN_VER}-x86_64-linux.tar.gz \ + && tar xf binaryen-version_${BINARYEN_VER}-x86_64-linux.tar.gz \ + && ln -sf /opt/binaryen-version_111 /opt/binaryen \ + && rm binaryen-version_${BINARYEN_VER}-x86_64-linux.tar.gz + # # CMAKE (https://apt.kitware.com/) SHELL ["/bin/bash", "-o", "pipefail", "-c"] @@ -31,25 +40,26 @@ RUN wget --progress=dot:giga -O - https://apt.kitware.com/keys/kitware-archive-l && apt-get install -y kitware-archive-keyring --no-install-recommends \ && apt-get install -y cmake --no-install-recommends \ && apt-get clean -y \ - && rm -rf /var/lib/apt/lists/* + && rm -rf /var/lib/apt/lists/* # # install emsdk WORKDIR /opt RUN git clone https://github.com/emscripten-core/emsdk.git +ARG EMSDK_VER=3.0.0 WORKDIR /opt/emsdk RUN git pull \ - && ./emsdk install 2.0.26 \ - && ./emsdk activate 2.0.26 \ + && ./emsdk install ${EMSDK_VER} \ + && ./emsdk activate ${EMSDK_VER} \ && echo "source /opt/emsdk/emsdk_env.sh" >> /root/.bashrc # # install wasi-sdk -ARG WASI_SDK_VER=16 +ARG WASI_SDK_VER=19 RUN wget -c --progress=dot:giga https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-${WASI_SDK_VER}/wasi-sdk-${WASI_SDK_VER}.0-linux.tar.gz -P /opt \ && tar xf /opt/wasi-sdk-${WASI_SDK_VER}.0-linux.tar.gz -C /opt \ - && ln -fs /opt/wasi-sdk-${WASI_SDK_VER}.0 /opt/wasi-sdk \ + && ln -sf /opt/wasi-sdk-${WASI_SDK_VER}.0 /opt/wasi-sdk \ && rm /opt/wasi-sdk-${WASI_SDK_VER}.0-linux.tar.gz # @@ -57,29 +67,29 @@ RUN wget -c --progress=dot:giga https://github.com/WebAssembly/wasi-sdk/releases ARG WABT_VER=1.0.29 RUN wget -c --progress=dot:giga https://github.com/WebAssembly/wabt/releases/download/${WABT_VER}/wabt-${WABT_VER}-ubuntu.tar.gz -P /opt \ && tar xf /opt/wabt-${WABT_VER}-ubuntu.tar.gz -C /opt \ - && ln -fs /opt/wabt-${WABT_VER} /opt/wabt \ + && ln -sf /opt/wabt-${WABT_VER} /opt/wabt \ && rm /opt/wabt-${WABT_VER}-ubuntu.tar.gz # # install bazelisk ARG BAZELISK_VER=1.12.0 -RUN mkdir /opt/bazelisk \ +RUN mkdir /opt/bazelisk \ && wget -c --progress=dot:giga https://github.com/bazelbuild/bazelisk/releases/download/v${BAZELISK_VER}/bazelisk-linux-amd64 -P /opt/bazelisk \ && chmod a+x /opt/bazelisk/bazelisk-linux-amd64 \ && ln -fs /opt/bazelisk/bazelisk-linux-amd64 /opt/bazelisk/bazel # # install clang+llvm +ARG LLVM_VER=14 +RUN apt-get purge -y clang-10 llvm-10 && apt autoremove -y WORKDIR /etc/apt/apt.conf.d RUN touch 99verfiy-peer.conf \ && echo "Acquire { https::Verify-Peer false }" > 99verfiy-peer.conf -WORKDIR /tmp +WORKDIR /tmp RUN wget --progress=dot:giga https://apt.llvm.org/llvm.sh \ && chmod a+x ./llvm.sh \ - && /tmp/llvm.sh 12 all \ - && ln -sf /usr/bin/clang-format-12 /usr/bin/clang-format \ - && rm -rf /tmp/* + && ./llvm.sh ${LLVM_VER} all # # [Optional] @@ -96,17 +106,28 @@ RUN apt-get update \ # Install required python packages # hadolint ignore=DL3013 RUN python3 -m pip install --no-cache-dir --upgrade pip \ - && pip3 install --no-cache-dir --user black nose pycparser pylint + && pip3 install --no-cache-dir black nose pycparser pylint -# set path, PS and clean up -ENV PATH "/opt/bazelisk:/opt/clang-llvm/bin:${PATH}" -RUN echo "export PATH=/opt/bazelisk:/opt/clang-llvm/bin:${PATH}" >> /root/.bashrc \ - && printf "%s\n" "PS1='\n[ \u@wamr-dev-docker \W ]\n$ '" >> /root/.bashrc \ +# +# Install github-cli. It doens't work as a feature of devcontainer.json +RUN cd /tmp \ + && wget https://github.com/cli/cli/releases/download/v2.20.2/gh_2.20.2_linux_amd64.deb \ + && dpkg -i gh_2.20.2_linux_amd64.deb + +# +# Install NodeJS +RUN curl -fsSL https://deb.nodesource.com/setup_19.x | bash - +RUN apt-get install -y nodejs + +# set path +ENV PATH="/opt/bazelisk:/usr/lib/llvm-${LLVM_VER}/bin:${PATH}" +ENV CC=/usr/lib/llvm-${LLVM_VER}/bin/clang CXX=/usr/lib/llvm-${LLVM_VER}/bin/clang++ +RUN printf "%s\n" "PS1='\n[ \u@wamr-dev-docker \W ]\n$ '" >> /root/.bashrc \ && apt-get autoremove -y \ && apt-get clean -y \ && rm -rf /var/lib/apt/lists/* \ && rm -rf /tmp/* # set workdir when container run -VOLUME /workspace -WORKDIR /workspace \ No newline at end of file +VOLUME /workspaces +WORKDIR /workspaces diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 976f5beb..24e1bdfd 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,6 +1,5 @@ // Copyright (C) 2019 Intel Corporation. All rights reserved. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - // For format details, see https://aka.ms/vscode-remote/devcontainer.json or this file's README at: // https://github.com/microsoft/vscode-dev-containers/tree/v0.195.0/containers/cpp { @@ -10,7 +9,12 @@ // Update 'VARIANT' to pick an Debian / Ubuntu OS version: debian-11, debian-10, debian-9, ubuntu-21.04, ubuntu-20.04, ubuntu-18.04 // Use Debian 11, Debian 9, Ubuntu 18.04 or Ubuntu 21.04 on local arm64/Apple Silicon "args": { - "VARIANT": "ubuntu-20.04" + "BINARYEN_VER": "111", + "EMSDK_VER": "3.0.0", + "LLVM_VER": "15", + "VARIANT": "ubuntu-20.04", + "WASI_SDK_VER": "19", + "WABT_VER": "1.0.31" } }, "runArgs": [ @@ -27,12 +31,10 @@ // Add the IDs of extensions you want installed when the container is created. "extensions": [ "dtsvet.vscode-wasm", - "esbenp.prettier-vscode", + "llvm-vs-code-extensions.vscode-clangd", "ms-python.python", "ms-python.vscode-pylance", "ms-vscode.cmake-tools", - "ms-vscode.cpptools", - "twxs.cmake" ] } }, diff --git a/.github/workflows/build_llvm_libraries.yml b/.github/workflows/build_llvm_libraries.yml index 6eaa2be7..b82b89e6 100644 --- a/.github/workflows/build_llvm_libraries.yml +++ b/.github/workflows/build_llvm_libraries.yml @@ -5,23 +5,42 @@ name: Reusable workflow-build_llvm_libraries on: workflow_call: inputs: - runs-on: + os: required: true type: string + arch: + required: true + type: string + outputs: + cache_key: + description: "A cached key of LLVM libraries" + value: ${{ jobs.build_llvm_libraries.outputs.key}} jobs: build_llvm_libraries: - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: ${{ fromJson(inputs.runs-on) }} + runs-on: ${{ inputs.os }} + outputs: + key: ${{ steps.create_lib_cache_key.outputs.key}} steps: - name: checkout uses: actions/checkout@v3 + - name: retrive the last commit ID + id: get_last_commit + run: echo "last_commit=$(/usr/bin/env python3 ./build_llvm.py --llvm-ver)" >> $GITHUB_OUTPUT + working-directory: build-scripts + + # Bump the prefix number to evict all previous caches and + # enforce a clean build, in the unlikely case that some + # weird build error occur and llvm/build becomes a potential + # suspect. + - name: form the cache key of libraries + id: create_lib_cache_key + run: echo "key=0-llvm-libraries-${{ inputs.os }}-${{ inputs.arch }}-${{ steps.get_last_commit.outputs.last_commit }}" >> $GITHUB_OUTPUT + - name: Cache LLVM libraries - id: cache_llvm + id: retrieve_llvm_libs uses: actions/cache@v3 with: path: | @@ -30,10 +49,39 @@ jobs: ./core/deps/llvm/build/lib ./core/deps/llvm/build/libexec ./core/deps/llvm/build/share - key: ${{ matrix.os }}-build-llvm_libraries_ex + key: ${{ steps.create_lib_cache_key.outputs.key}} - - name: Build llvm - id: build_llvm - if: ${{ steps.cache_llvm.outputs.cache-hit != 'true' }} - run: /usr/bin/env python3 ./build_llvm.py --arch X86 WebAssembly + - uses: actions/cache@v3 + with: + path: ~/.ccache + key: 0-ccache-${{ inputs.os }}-${{ steps.get_last_commit.outputs.last_commit }} + restore-keys: | + 0-ccache-${{ inputs.os }} + if: steps.retrieve_llvm_libs.outputs.cache-hit != 'true' && inputs.os == 'ubuntu-20.04' + + - uses: actions/cache@v3 + with: + path: ~/.cache/ccache + key: 0-ccache-${{ inputs.os }}-${{ steps.get_last_commit.outputs.last_commit }} + restore-keys: | + 0-ccache-${{ inputs.os }} + if: steps.retrieve_llvm_libs.outputs.cache-hit != 'true' && inputs.os == 'ubuntu-22.04' + + - run: sudo apt install -y ccache ninja-build + if: steps.retrieve_llvm_libs.outputs.cache-hit != 'true' && startsWith(inputs.os, 'ubuntu') + + - uses: actions/cache@v3 + with: + path: ~/Library/Caches/ccache + key: 0-ccache-${{ inputs.os }}-${{ steps.get_last_commit.outputs.last_commit }} + restore-keys: | + 0-ccache-${{ inputs.os }} + if: steps.retrieve_llvm_libs.outputs.cache-hit != 'true' && startsWith(inputs.os, 'macos') + + - run: brew install ccache ninja + if: steps.retrieve_llvm_libs.outputs.cache-hit != 'true' && startsWith(inputs.os, 'macos') + + - name: Build LLVM libraries + if: steps.retrieve_llvm_libs.outputs.cache-hit != 'true' + run: /usr/bin/env python3 ./build_llvm.py --arch ${{ inputs.arch }} working-directory: build-scripts diff --git a/.github/workflows/compilation_on_android_ubuntu.yml b/.github/workflows/compilation_on_android_ubuntu.yml index 6980e273..93528b14 100644 --- a/.github/workflows/compilation_on_android_ubuntu.yml +++ b/.github/workflows/compilation_on_android_ubuntu.yml @@ -53,8 +53,6 @@ env: FAST_JIT_BUILD_OPTIONS: " -DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_FAST_JIT=1 -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_LAZY_JIT=0" LLVM_LAZY_JIT_BUILD_OPTIONS: " -DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_FAST_JIT=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=1" LLVM_EAGER_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_FAST_JIT=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=0" - # LLVM - LLVM_CACHE_SUFFIX: "build-llvm_libraries_ex" # For Spec Test DEFAULT_TEST_OPTIONS: "-s spec -b -P" MULTI_MODULES_TEST_OPTIONS: "-s spec -b -M -P" @@ -64,23 +62,37 @@ env: WASI_TEST_OPTIONS: "-s wasi_certification" jobs: - build_llvm_libraries: + build_llvm_libraries_on_ubuntu_2004: uses: ./.github/workflows/build_llvm_libraries.yml with: - runs-on: "['ubuntu-20.04', 'ubuntu-22.04']" + os: "ubuntu-20.04" + arch: "X86" + + build_llvm_libraries_on_ubuntu_2204: + uses: ./.github/workflows/build_llvm_libraries.yml + with: + os: "ubuntu-22.04" + arch: "X86" build_wamrc: - needs: [build_llvm_libraries] + needs: + [build_llvm_libraries_on_ubuntu_2004, build_llvm_libraries_on_ubuntu_2204] runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-20.04, ubuntu-22.04] + include: + - os: ubuntu-20.04 + llvm_cache_key: ${{ needs.build_llvm_libraries_on_ubuntu_2004.outputs.cache_key }} + - os: ubuntu-22.04 + llvm_cache_key: ${{ needs.build_llvm_libraries_on_ubuntu_2204.outputs.cache_key }} steps: - name: checkout uses: actions/checkout@v3 + # since jobs.id can't contain the dot character + # it is hard to use `format` to assemble the cache key - name: Get LLVM libraries - id: cache_llvm + id: retrieve_llvm_libs uses: actions/cache@v3 with: path: | @@ -89,10 +101,10 @@ jobs: ./core/deps/llvm/build/lib ./core/deps/llvm/build/libexec ./core/deps/llvm/build/share - key: ${{ matrix.os }}-${{ env.LLVM_CACHE_SUFFIX }} + key: ${{ matrix.llvm_cache_key }} - name: Quit if cache miss - if: steps.cache_llvm.outputs.cache-hit != 'true' + if: steps.retrieve_llvm_libs.outputs.cache-hit != 'true' run: echo "::error::can not get prebuilt llvm libraries" && exit 1 - name: Build wamrc @@ -103,7 +115,8 @@ jobs: working-directory: wamr-compiler build_iwasm: - needs: [build_llvm_libraries] + needs: + [build_llvm_libraries_on_ubuntu_2004, build_llvm_libraries_on_ubuntu_2204] runs-on: ${{ matrix.os }} strategy: matrix: @@ -187,13 +200,21 @@ jobs: # Fast-JIT mode doesn't support android(X86-32) - make_options_run_mode: $FAST_JIT_BUILD_OPTIONS platform: android + # only test andorid on ubuntu latest + - os: ubuntu-20.04 + platform: android + include: + - os: ubuntu-20.04 + llvm_cache_key: ${{ needs.build_llvm_libraries_on_ubuntu_2004.outputs.cache_key }} + - os: ubuntu-22.04 + llvm_cache_key: ${{ needs.build_llvm_libraries_on_ubuntu_2204.outputs.cache_key }} steps: - name: checkout uses: actions/checkout@v3 # only download llvm cache when needed - name: Get LLVM libraries - id: cache_llvm + id: retrieve_llvm_libs if: endsWith(matrix.make_options_run_mode, '_JIT_BUILD_OPTIONS') uses: actions/cache@v3 with: @@ -203,10 +224,10 @@ jobs: ./core/deps/llvm/build/lib ./core/deps/llvm/build/libexec ./core/deps/llvm/build/share - key: ${{ matrix.os }}-${{ env.LLVM_CACHE_SUFFIX }} + key: ${{ matrix.llvm_cache_key }} - name: Quit if cache miss - if: endsWith(matrix.make_options_run_mode, '_JIT_BUILD_OPTIONS') && (steps.cache_llvm.outputs.cache-hit != 'true') + if: endsWith(matrix.make_options_run_mode, '_JIT_BUILD_OPTIONS') && (steps.retrieve_llvm_libs.outputs.cache-hit != 'true') run: echo "::error::can not get prebuilt llvm libraries" && exit 1 - name: Build iwasm @@ -217,7 +238,13 @@ jobs: working-directory: product-mini/platforms/${{ matrix.platform }} build_samples_wasm_c_api: - needs: [build_iwasm, build_llvm_libraries, build_wamrc] + needs: + [ + build_iwasm, + build_llvm_libraries_on_ubuntu_2004, + build_llvm_libraries_on_ubuntu_2204, + build_wamrc, + ] runs-on: ${{ matrix.os }} strategy: matrix: @@ -233,18 +260,23 @@ jobs: os: [ubuntu-20.04, ubuntu-22.04] wasi_sdk_release: [ - "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk-12.0-linux.tar.gz", + "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-19/wasi-sdk-19.0-linux.tar.gz", ] wabt_release: [ - "https://github.com/WebAssembly/wabt/releases/download/1.0.24/wabt-1.0.24-ubuntu.tar.gz", + "https://github.com/WebAssembly/wabt/releases/download/1.0.31/wabt-1.0.31-ubuntu.tar.gz", ] + include: + - os: ubuntu-20.04 + llvm_cache_key: ${{ needs.build_llvm_libraries_on_ubuntu_2004.outputs.cache_key }} + - os: ubuntu-22.04 + llvm_cache_key: ${{ needs.build_llvm_libraries_on_ubuntu_2204.outputs.cache_key }} steps: - name: checkout uses: actions/checkout@v3 - name: Get LLVM libraries - id: cache_llvm + id: retrieve_llvm_libs if: (!endsWith(matrix.make_options, '_INTERP_BUILD_OPTIONS')) uses: actions/cache@v3 with: @@ -254,18 +286,18 @@ jobs: ./core/deps/llvm/build/lib ./core/deps/llvm/build/libexec ./core/deps/llvm/build/share - key: ${{ matrix.os }}-${{ env.LLVM_CACHE_SUFFIX }} + key: ${{ matrix.llvm_cache_key }} - name: Quit if cache miss - if: (!endsWith(matrix.make_options, '_INTERP_BUILD_OPTIONS')) && (steps.cache_llvm.outputs.cache-hit != 'true') + if: (!endsWith(matrix.make_options, '_INTERP_BUILD_OPTIONS')) && (steps.retrieve_llvm_libs.outputs.cache-hit != 'true') run: echo "::error::can not get prebuilt llvm libraries" && exit 1 - name: download and install wabt run: | cd /opt sudo wget ${{ matrix.wabt_release }} - sudo tar -xzf wabt-1.0.24-*.tar.gz - sudo mv wabt-1.0.24 wabt + sudo tar -xzf wabt-1.0.31-*.tar.gz + sudo mv wabt-1.0.31 wabt - name: Build wamrc if: (!endsWith(matrix.make_options, '_INTERP_BUILD_OPTIONS')) @@ -277,19 +309,9 @@ jobs: - name: Build Sample [wasm-c-api] run: | - mkdir build && cd build - cmake .. ${{ matrix.make_options }} - cmake --build . --config Release --parallel 4 - ./callback - ./callback_chain - ./empty_imports - ./global - ./hello - ./hostref - ./memory - ./reflect - ./table - ./trap + cmake -S . -B build ${{ matrix.make_options }} + cmake --build build --config Release --parallel 4 + ctest --test-dir build working-directory: samples/wasm-c-api build_samples_others: @@ -298,14 +320,13 @@ jobs: strategy: matrix: os: [ubuntu-20.04, ubuntu-22.04] - wasi_sdk_release: - [ - "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk-12.0-linux.tar.gz", - ] - wabt_release: - [ - "https://github.com/WebAssembly/wabt/releases/download/1.0.24/wabt-1.0.24-ubuntu.tar.gz", - ] + include: + - os: ubuntu-20.04 + wasi_sdk_release: "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-19/wasi-sdk-19.0-linux.tar.gz" + wabt_release: "https://github.com/WebAssembly/wabt/releases/download/1.0.31/wabt-1.0.31-ubuntu.tar.gz" + - os: ubuntu-22.04 + wasi_sdk_release: "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-19/wasi-sdk-19.0-linux.tar.gz" + wabt_release: "https://github.com/WebAssembly/wabt/releases/download/1.0.31/wabt-1.0.31-ubuntu.tar.gz" steps: - name: checkout uses: actions/checkout@v3 @@ -314,15 +335,15 @@ jobs: run: | cd /opt sudo wget ${{ matrix.wasi_sdk_release }} - sudo tar -xzf wasi-sdk-12.0-*.tar.gz - sudo mv wasi-sdk-12.0 wasi-sdk + sudo tar -xzf wasi-sdk-*.tar.gz + sudo mv wasi-sdk-19.0 wasi-sdk - name: download and install wabt run: | cd /opt sudo wget ${{ matrix.wabt_release }} - sudo tar -xzf wabt-1.0.24-*.tar.gz - sudo mv wabt-1.0.24 wabt + sudo tar -xzf wabt-1.0.31-*.tar.gz + sudo mv wabt-1.0.31 wabt - name: Build Sample [basic] run: | @@ -378,7 +399,7 @@ jobs: working-directory: ./samples/simple test: - needs: [build_iwasm, build_llvm_libraries, build_wamrc] + needs: [build_iwasm, build_llvm_libraries_on_ubuntu_2004, build_wamrc] runs-on: ubuntu-20.04 strategy: matrix: @@ -392,6 +413,8 @@ jobs: $THREADS_TEST_OPTIONS, $WASI_TEST_OPTIONS, ] + llvm_cache_key: + ["${{ needs.build_llvm_libraries_on_ubuntu_2004.outputs.cache_key }}"] exclude: # uncompatiable modes and features # classic-interp and fast-interp don't support simd @@ -432,7 +455,7 @@ jobs: #only download llvm libraries in jit and aot mode - name: Get LLVM libraries if: env.USE_LLVM == 'true' - id: cache_llvm + id: retrieve_llvm_libs uses: actions/cache@v3 with: path: | @@ -441,10 +464,10 @@ jobs: ./core/deps/llvm/build/lib ./core/deps/llvm/build/libexec ./core/deps/llvm/build/share - key: ubuntu-20.04-${{ env.LLVM_CACHE_SUFFIX }} + key: ${{ matrix.llvm_cache_key }} - name: Quit if cache miss - if: env.USE_LLVM == 'true' && steps.cache_llvm.outputs.cache-hit != 'true' + if: env.USE_LLVM == 'true' && steps.retrieve_llvm_libs.outputs.cache-hit != 'true' run: echo "::error::can not get prebuilt llvm libraries" && exit 1 - name: run tests diff --git a/.github/workflows/compilation_on_macos.yml b/.github/workflows/compilation_on_macos.yml index 73ebec89..7ad395b2 100644 --- a/.github/workflows/compilation_on_macos.yml +++ b/.github/workflows/compilation_on_macos.yml @@ -51,26 +51,28 @@ env: FAST_INTERP_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=0 -DWAMR_BUILD_FAST_INTERP=1 -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_LAZY_JIT=0" LLVM_LAZY_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=1" LLVM_EAGER_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=0" - LLVM_CACHE_SUFFIX: "build-llvm_libraries_ex" jobs: build_llvm_libraries: uses: ./.github/workflows/build_llvm_libraries.yml with: - runs-on: "['macos-latest']" + os: "macos-latest" + arch: "X86" build_wamrc: needs: [build_llvm_libraries] runs-on: ${{ matrix.os }} strategy: matrix: - os: [macos-latest] + include: + - os: macos-latest + llvm_cache_key: ${{ needs.build_llvm_libraries.outputs.cache_key }} steps: - name: checkout uses: actions/checkout@v3 - name: Get LLVM libraries - id: cache_llvm + id: retrieve_llvm_libs uses: actions/cache@v3 with: path: | @@ -79,10 +81,10 @@ jobs: ./core/deps/llvm/build/lib ./core/deps/llvm/build/libexec ./core/deps/llvm/build/share - key: ${{ matrix.os }}-${{ env.LLVM_CACHE_SUFFIX }} + key: ${{ matrix.llvm_cache_key }} - name: Quit if cache miss - if: steps.cache_llvm.outputs.cache-hit != 'true' + if: steps.retrieve_llvm_libs.outputs.cache-hit != 'true' run: echo "::error::can not get prebuilt llvm libraries" && exit 1 - name: Build wamrc @@ -166,13 +168,16 @@ jobs: make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1" - make_options_run_mode: $LLVM_EAGER_JIT_BUILD_OPTIONS make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1" + include: + - os: macos-latest + llvm_cache_key: ${{ needs.build_llvm_libraries.outputs.cache_key }} steps: - name: checkout uses: actions/checkout@v3 # only download llvm cache when needed - name: Get LLVM libraries - id: cache_llvm + id: retrieve_llvm_libs if: endsWith(matrix.make_options_run_mode, '_JIT_BUILD_OPTIONS') uses: actions/cache@v3 with: @@ -182,10 +187,10 @@ jobs: ./core/deps/llvm/build/lib ./core/deps/llvm/build/libexec ./core/deps/llvm/build/share - key: ${{ matrix.os }}-${{ env.LLVM_CACHE_SUFFIX }} + key: ${{ matrix.llvm_cache_key }} - name: Quit if cache miss - if: endsWith(matrix.make_options_run_mode, '_JIT_BUILD_OPTIONS') && (steps.cache_llvm.outputs.cache-hit != 'true') + if: endsWith(matrix.make_options_run_mode, '_JIT_BUILD_OPTIONS') && (steps.retrieve_llvm_libs.outputs.cache-hit != 'true') run: echo "::error::can not get prebuilt llvm libraries" && exit 1 - name: Build iwasm @@ -210,8 +215,14 @@ jobs: #$AOT_BUILD_OPTIONS, ] os: [macos-latest] - wasi_sdk_release: ["https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk-12.0-macos.tar.gz"] - wabt_release: ["https://github.com/WebAssembly/wabt/releases/download/1.0.24/wabt-1.0.24-macos.tar.gz"] + wasi_sdk_release: + [ + "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-19/wasi-sdk-19.0-macos.tar.gz", + ] + wabt_release: + [ + "https://github.com/WebAssembly/wabt/releases/download/1.0.31/wabt-1.0.31-macos-12.tar.gz", + ] steps: - name: checkout uses: actions/checkout@v3 @@ -220,24 +231,14 @@ jobs: run: | cd /opt sudo wget ${{ matrix.wabt_release }} - sudo tar -xzf wabt-1.0.24-*.tar.gz - sudo mv wabt-1.0.24 wabt + sudo tar -xzf wabt-1.0.31-*.tar.gz + sudo mv wabt-1.0.31 wabt - name: Build Sample [wasm-c-api] run: | - mkdir build && cd build - cmake .. ${{ matrix.make_options }} - cmake --build . --config Release --parallel 4 - ./callback - ./callback_chain - ./empty_imports - ./global - ./hello - ./hostref - ./memory - ./reflect - ./table - ./trap + cmake -S . -B build ${{ matrix.make_options }} + cmake --build build --config Release --parallel 4 + ctest --test-dir build working-directory: samples/wasm-c-api build_samples_others: @@ -246,8 +247,14 @@ jobs: strategy: matrix: os: [macos-latest] - wasi_sdk_release: ["https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk-12.0-macos.tar.gz"] - wabt_release: ["https://github.com/WebAssembly/wabt/releases/download/1.0.24/wabt-1.0.24-macos.tar.gz"] + wasi_sdk_release: + [ + "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-19/wasi-sdk-19.0-macos.tar.gz", + ] + wabt_release: + [ + "https://github.com/WebAssembly/wabt/releases/download/1.0.31/wabt-1.0.31-macos-12.tar.gz", + ] steps: - name: checkout uses: actions/checkout@v3 @@ -256,15 +263,15 @@ jobs: run: | cd /opt sudo wget ${{ matrix.wasi_sdk_release }} - sudo tar -xzf wasi-sdk-12.0-*.tar.gz - sudo mv wasi-sdk-12.0 wasi-sdk + sudo tar -xzf wasi-sdk-*.tar.gz + sudo mv wasi-sdk-19.0 wasi-sdk - name: download and install wabt run: | cd /opt sudo wget ${{ matrix.wabt_release }} - sudo tar -xzf wabt-1.0.24-*.tar.gz - sudo mv wabt-1.0.24 wabt + sudo tar -xzf wabt-1.0.31-*.tar.gz + sudo mv wabt-1.0.31 wabt - name: Build Sample [basic] run: | diff --git a/.github/workflows/compilation_on_sgx.yml b/.github/workflows/compilation_on_sgx.yml index 70eeaec0..5975c262 100644 --- a/.github/workflows/compilation_on_sgx.yml +++ b/.github/workflows/compilation_on_sgx.yml @@ -51,13 +51,13 @@ env: FAST_INTERP_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=0 -DWAMR_BUILD_FAST_INTERP=1 -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_LAZY_JIT=0" LLVM_LAZY_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=1" LLVM_EAGER_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=0" - LLVM_CACHE_SUFFIX: "build-llvm_libraries_ex" jobs: build_llvm_libraries: uses: ./.github/workflows/build_llvm_libraries.yml with: - runs-on: "['ubuntu-20.04']" + os: "ubuntu-20.04" + arch: "X86" build_iwasm: runs-on: ${{ matrix.os }} @@ -131,7 +131,9 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-20.04] + include: + - os: ubuntu-20.04 + llvm_cache_key: ${{ needs.build_llvm_libraries.outputs.cache_key }} steps: - name: install SGX SDK and necessary libraries run: | @@ -150,7 +152,7 @@ jobs: uses: actions/checkout@v3 - name: Get LLVM libraries - id: cache_llvm + id: retrieve_llvm_libs uses: actions/cache@v3 with: path: | @@ -159,10 +161,10 @@ jobs: ./core/deps/llvm/build/lib ./core/deps/llvm/build/libexec ./core/deps/llvm/build/share - key: ${{ matrix.os }}-${{ env.LLVM_CACHE_SUFFIX }} + key: ${{ matrix.llvm_cache_key }} - name: Quit if cache miss - if: steps.cache_llvm.outputs.cache-hit != 'true' + if: steps.retrieve_llvm_libs.outputs.cache-hit != 'true' run: echo "::error::can not get prebuilt llvm libraries" && exit 1 - name: Build wamrc @@ -189,11 +191,11 @@ jobs: os: [ubuntu-20.04] wasi_sdk_release: [ - "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk-12.0-linux.tar.gz", + "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-19/wasi-sdk-19.0-linux.tar.gz", ] wabt_release: [ - "https://github.com/WebAssembly/wabt/releases/download/1.0.24/wabt-1.0.24-ubuntu.tar.gz", + "https://github.com/WebAssembly/wabt/releases/download/1.0.31/wabt-1.0.31-ubuntu.tar.gz", ] steps: - name: checkout @@ -203,8 +205,8 @@ jobs: run: | cd /opt sudo wget ${{ matrix.wabt_release }} - sudo tar -xzf wabt-1.0.24-*.tar.gz - sudo mv wabt-1.0.24 wabt + sudo tar -xzf wabt-1.0.31-*.tar.gz + sudo mv wabt-1.0.31 wabt - name: install SGX SDK and necessary libraries run: | @@ -221,19 +223,9 @@ jobs: - name: Build Sample [wasm-c-api] run: | - mkdir build && cd build - cmake .. ${{ matrix.make_options }} - cmake --build . --config Release --parallel 4 - ./callback - ./callback_chain - ./empty_imports - ./global - ./hello - ./hostref - ./memory - ./reflect - ./table - ./trap + cmake -S . -B build ${{ matrix.make_options }} + cmake --build build --config Release --parallel 4 + ctest --test-dir build working-directory: samples/wasm-c-api build_samples_others: @@ -244,11 +236,11 @@ jobs: os: [ubuntu-20.04] wasi_sdk_release: [ - "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk-12.0-linux.tar.gz", + "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-19/wasi-sdk-19.0-linux.tar.gz", ] wabt_release: [ - "https://github.com/WebAssembly/wabt/releases/download/1.0.24/wabt-1.0.24-ubuntu.tar.gz", + "https://github.com/WebAssembly/wabt/releases/download/1.0.31/wabt-1.0.31-ubuntu.tar.gz", ] steps: - name: checkout @@ -258,15 +250,15 @@ jobs: run: | cd /opt sudo wget ${{ matrix.wasi_sdk_release }} - sudo tar -xzf wasi-sdk-12.0-*.tar.gz - sudo mv wasi-sdk-12.0 wasi-sdk + sudo tar -xzf wasi-sdk-*.tar.gz + sudo mv wasi-sdk-19.0 wasi-sdk - name: download and install wabt run: | cd /opt sudo wget ${{ matrix.wabt_release }} - sudo tar -xzf wabt-1.0.24-*.tar.gz - sudo mv wabt-1.0.24 wabt + sudo tar -xzf wabt-1.0.31-*.tar.gz + sudo mv wabt-1.0.31 wabt - name: install SGX SDK and necessary libraries run: | @@ -334,6 +326,7 @@ jobs: matrix: running_mode: ["classic-interp", "fast-interp", "aot"] test_option: ["-x -p -s spec -b -P", "-x -p -s spec -S -b -P"] + llvm_cache_key: ["${{ needs.build_llvm_libraries.outputs.cache_key }}"] # classic-interp and fast-interp don't support simd exclude: - running_mode: "classic-interp" @@ -347,7 +340,7 @@ jobs: - name: Get LLVM libraries if: matrix.running_mode == 'aot' - id: cache_llvm + id: retrieve_llvm_libs uses: actions/cache@v3 with: path: | @@ -356,10 +349,10 @@ jobs: ./core/deps/llvm/build/lib ./core/deps/llvm/build/libexec ./core/deps/llvm/build/share - key: ubuntu-20.04-${{ env.LLVM_CACHE_SUFFIX }} + key: ${{ matrix.llvm_cache_key }} - name: Quit if cache miss - if: matrix.running_mode == 'aot' && steps.cache_llvm.outputs.cache-hit != 'true' + if: matrix.running_mode == 'aot' && steps.retrieve_llvm_libs.outputs.cache-hit != 'true' run: echo "::error::can not get prebuilt llvm libraries" && exit 1 - name: install SGX SDK and necessary libraries diff --git a/.github/workflows/release_process.yml b/.github/workflows/release_process.yml index 824a0823..88f595dd 100644 --- a/.github/workflows/release_process.yml +++ b/.github/workflows/release_process.yml @@ -123,7 +123,7 @@ jobs: runner: ubuntu-20.04 upload_url: ${{ needs.create_release.outputs.upload_url }} ver_num: ${{ needs.create_tag.outputs.new_ver}} - wasi_sdk_url: https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk-12.0-linux.tar.gz + wasi_sdk_url: https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-19/wasi-sdk-19.0-linux.tar.gz release_wamr_sdk_on_ubuntu_2204: needs: [create_tag, create_release] @@ -133,7 +133,7 @@ jobs: runner: ubuntu-22.04 upload_url: ${{ needs.create_release.outputs.upload_url }} ver_num: ${{ needs.create_tag.outputs.new_ver}} - wasi_sdk_url: https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk-12.0-linux.tar.gz + wasi_sdk_url: https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-19/wasi-sdk-19.0-linux.tar.gz release_wamr_sdk_on_macos: needs: [create_tag, create_release] @@ -143,7 +143,7 @@ jobs: runner: macos-latest upload_url: ${{ needs.create_release.outputs.upload_url }} ver_num: ${{ needs.create_tag.outputs.new_ver}} - wasi_sdk_url: https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk-12.0-macos.tar.gz + wasi_sdk_url: https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-19/wasi-sdk-19.0-macos.tar.gz # # vscode extension cross-platform diff --git a/.github/workflows/spec_test_on_nuttx.yml b/.github/workflows/spec_test_on_nuttx.yml index 03f99f73..bf39c140 100644 --- a/.github/workflows/spec_test_on_nuttx.yml +++ b/.github/workflows/spec_test_on_nuttx.yml @@ -16,7 +16,8 @@ jobs: build_llvm_libraries: uses: ./.github/workflows/build_llvm_libraries.yml with: - runs-on: "['ubuntu-22.04']" + os: "ubuntu-22.04" + arch: "ARM RISCV AArch64" spec_test_on_qemu: runs-on: ${{ matrix.os }} @@ -37,6 +38,7 @@ jobs: "-t aot", "-t aot -X" ] + llvm_cache_key: [ "${{ needs.build_llvm_libraries.outputs.cache_key }}" ] steps: - name: Install Utilities run: | @@ -72,7 +74,7 @@ jobs: path: apps/interpreters/wamr/wamr - name: Get LLVM libraries - id: cache_llvm + id: retrieve_llvm_libs uses: actions/cache@v3 with: path: | @@ -81,10 +83,10 @@ jobs: ./core/deps/llvm/build/lib ./core/deps/llvm/build/libexec ./core/deps/llvm/build/share - key: ${{ matrix.os }}-${{ env.LLVM_CACHE_SUFFIX }} + key: ${{ matrix.llvm_cache_key }} - name: Quit if cache miss - if: steps.cache_llvm.outputs.cache-hit != 'true' + if: steps.retrieve_llvm_libs.outputs.cache-hit != 'true' run: echo "::error::can not get prebuilt llvm libraries" && exit 1 - name: Copy LLVM diff --git a/.gitignore b/.gitignore index a7abd7c1..8b4dce9b 100644 --- a/.gitignore +++ b/.gitignore @@ -32,3 +32,6 @@ samples/socket-api/wasm-src/inc/pthread.h **/__pycache__ tests/benchmarks/coremark/coremark* + +samples/workload/include/** +!samples/workload/include/.gitkeep diff --git a/build-scripts/build_llvm.py b/build-scripts/build_llvm.py index bc0daf1f..dd211f30 100755 --- a/build-scripts/build_llvm.py +++ b/build-scripts/build_llvm.py @@ -21,28 +21,31 @@ def clone_llvm(dst_dir, llvm_repo, llvm_branch): llvm_dir = dst_dir.joinpath("llvm").resolve() if not llvm_dir.exists(): - print(f"Clone llvm to {llvm_dir} ...") GIT_CLONE_CMD = f"git clone --depth 1 --branch {llvm_branch} {llvm_repo} llvm" subprocess.check_output(shlex.split(GIT_CLONE_CMD), cwd=dst_dir) - else: - print(f"There is an LLVM local repo in {llvm_dir}, clean and keep using it") return llvm_dir -def build_llvm(llvm_dir, platform, backends, projects): +def query_llvm_version(llvm_dir): + GIT_LOG_CMD = f"git log --format=format:'%h' -1" + return subprocess.check_output( + shlex.split(GIT_LOG_CMD), cwd=llvm_dir, universal_newlines=True, text=True + ) + + +def build_llvm(llvm_dir, platform, backends, projects, use_clang=False): LLVM_COMPILE_OPTIONS = [ '-DCMAKE_BUILD_TYPE:STRING="Release"', "-DCMAKE_EXPORT_COMPILE_COMMANDS=ON", "-DLLVM_APPEND_VC_REV:BOOL=ON", - "-DLLVM_BUILD_BENCHMARKS:BOOL=OFF", - "-DLLVM_BUILD_DOCS:BOOL=OFF", "-DLLVM_BUILD_EXAMPLES:BOOL=OFF", "-DLLVM_BUILD_LLVM_DYLIB:BOOL=OFF", "-DLLVM_BUILD_TESTS:BOOL=OFF", - "-DLLVM_CCACHE_BUILD:BOOL=OFF", + "-DLLVM_CCACHE_BUILD:BOOL=ON", "-DLLVM_ENABLE_BINDINGS:BOOL=OFF", "-DLLVM_ENABLE_IDE:BOOL=OFF", + "-DLLVM_ENABLE_LIBEDIT=OFF", "-DLLVM_ENABLE_TERMINFO:BOOL=OFF", "-DLLVM_ENABLE_ZLIB:BOOL=OFF", "-DLLVM_INCLUDE_BENCHMARKS:BOOL=OFF", @@ -54,6 +57,18 @@ def build_llvm(llvm_dir, platform, backends, projects): "-DLLVM_OPTIMIZED_TABLEGEN:BOOL=ON", ] + # use clang/clang++/lld. but macos doesn't support lld + if not sys.platform.startswith("darwin") and use_clang: + if shutil.which("clang") and shutil.which("clang++") and shutil.which("lld"): + os.environ["CC"] = "clang" + os.environ["CXX"] = "clang++" + LLVM_COMPILE_OPTIONS.append('-DLLVM_USE_LINKER:STRING="lld"') + print("Use the clang toolchain") + else: + print("Can not find clang, clang++ and lld, keep using the gcc toolchain") + else: + print("Use the gcc toolchain") + LLVM_EXTRA_COMPILE_OPTIONS = { "arc": [ '-DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD:STRING="ARC"', @@ -99,8 +114,10 @@ def build_llvm(llvm_dir, platform, backends, projects): lib_llvm_core_library = build_dir.joinpath("lib/libLLVMCore.a").resolve() if lib_llvm_core_library.exists(): - print(f"Please remove {build_dir} manually and try again") - return build_dir + print( + f"It has already been fully compiled. If want to a re-build, please remove {build_dir} manually and try again" + ) + return None compile_options = " ".join( LLVM_COMPILE_OPTIONS @@ -119,10 +136,11 @@ def build_llvm(llvm_dir, platform, backends, projects): CONFIG_CMD += " -G'Unix Makefiles'" else: CONFIG_CMD += " -A x64" - print(f"{CONFIG_CMD}") + else: + CONFIG_CMD += " -G'Ninja'" subprocess.check_call(shlex.split(CONFIG_CMD), cwd=build_dir) - BUILD_CMD = f"cmake --build . --target package --parallel {os.cpu_count()}" + ( + BUILD_CMD = "cmake --build . --target package" + ( " --config Release" if "windows" == platform else "" ) subprocess.check_call(shlex.split(BUILD_CMD), cwd=build_dir) @@ -133,23 +151,25 @@ def build_llvm(llvm_dir, platform, backends, projects): def repackage_llvm(llvm_dir): build_dir = llvm_dir.joinpath("./build").resolve() - packs = [f for f in build_dir.glob("LLVM-13*.tar.gz")] + packs = [f for f in build_dir.glob("LLVM-*.tar.gz")] if len(packs) > 1: - raise Exception("Find more than one LLVM-13*.tar.gz") + raise Exception("Find more than one LLVM-*.tar.gz") if not packs: return llvm_package = packs[0].name - # mv build/LLVM-13.0.0*.gz . + # mv build/LLVM-*.gz . shutil.move(str(build_dir.joinpath(llvm_package).resolve()), str(llvm_dir)) # rm -r build shutil.rmtree(str(build_dir)) # mkdir build build_dir.mkdir() - # tar xf ./LLVM-13.0.0-*.tar.gz --strip-components=1 --directory=build + # tar xf ./LLVM-*.tar.gz --strip-components=1 --directory=build CMD = f"tar xf {llvm_dir.joinpath(llvm_package).resolve()} --strip-components=1 --directory={build_dir}" subprocess.check_call(shlex.split(CMD), cwd=llvm_dir) + # rm ./LLVM-1*.gz + os.remove(llvm_dir.joinpath(llvm_package).resolve()) def main(): @@ -184,8 +204,17 @@ def main(): choices=["clang", "lldb"], help="identify extra LLVM projects, separate by space, like '--project clang lldb'", ) + parser.add_argument( + "--llvm-ver", + action="store_true", + help="return the version info of generated llvm libraries", + ) + parser.add_argument( + "--use-clang", + action="store_true", + help="use clang instead of gcc", + ) options = parser.parse_args() - print(f"options={options}") # if the "platform" is not identified in the command line option, # detect it @@ -199,12 +228,10 @@ def main(): else: platform = options.platform - print(f"========== Build LLVM for {platform} ==========\n") - llvm_repo_and_branch = { "arc": { "repo": "https://github.com/llvm/llvm-project.git", - "branch": "release/13.x", + "branch": "release/15.x", }, "xtensa": { "repo": "https://github.com/espressif/llvm-project.git", @@ -212,7 +239,7 @@ def main(): }, "default": { "repo": "https://github.com/llvm/llvm-project.git", - "branch": "release/13.x", + "branch": "release/15.x", }, } @@ -225,19 +252,22 @@ def main(): deps_dir = current_dir.joinpath("../core/deps").resolve() try: - print(f"==================== CLONE LLVM ====================") llvm_info = llvm_repo_and_branch.get(platform, llvm_repo_and_branch["default"]) llvm_dir = clone_llvm(deps_dir, llvm_info["repo"], llvm_info["branch"]) - print() - print(f"==================== BUILD LLVM ====================") - build_llvm(llvm_dir, platform, options.arch, options.project) + if options.llvm_ver: + commit_hash = query_llvm_version(llvm_dir) + print(commit_hash) + return commit_hash is not None - print() - print(f"==================== PACKAGE LLVM ====================") - repackage_llvm(llvm_dir) + if ( + build_llvm( + llvm_dir, platform, options.arch, options.project, options.use_clang + ) + is not None + ): + repackage_llvm(llvm_dir) - print() return True except subprocess.CalledProcessError: return False diff --git a/doc/build_wasm_app.md b/doc/build_wasm_app.md index a10a1a4c..40f1b89d 100644 --- a/doc/build_wasm_app.md +++ b/doc/build_wasm_app.md @@ -3,12 +3,12 @@ Prepare WASM building environments ================================== -For C and C++, WASI-SDK version 12.0+ is the major tool supported by WAMR to build WASM applications. Also, we can use [Emscripten SDK (EMSDK)](https://github.com/emscripten-core/emsdk), but it is not recommended. And there are some other compilers such as the standard clang compiler, which might also work [here](./other_wasm_compilers.md). +For C and C++, WASI-SDK version 19.0+ is the major tool supported by WAMR to build WASM applications. Also, we can use [Emscripten SDK (EMSDK)](https://github.com/emscripten-core/emsdk), but it is not recommended. And there are some other compilers such as the standard clang compiler, which might also work [here](./other_wasm_compilers.md). To install WASI SDK, please download the [wasi-sdk release](https://github.com/CraneStation/wasi-sdk/releases) and extract the archive to default path `/opt/wasi-sdk`. The official *wasi-sdk release* doesn't fully support *latest 128-bit SIMD spec* yet. WAMR provides a script in [build-wasi-sdk](../test-tools/build-wasi-sdk/) to generate -another wasi-sdk with *llvm-13* from source code and installs it at *../test-tools/wasi-sdk*. If you plan to build WASM applications with *latest 128-bit SIMD*, please use it instead of the official release. +another wasi-sdk with *llvm-15* from source code and installs it at *../test-tools/wasi-sdk*. If you plan to build WASM applications with *latest 128-bit SIMD*, please use it instead of the official release. And [sample workloads](../samples/workload) are using the self-compiled wasi-sdk. diff --git a/samples/wasm-c-api/CMakeLists.txt b/samples/wasm-c-api/CMakeLists.txt index a6494624..e2be3b8f 100644 --- a/samples/wasm-c-api/CMakeLists.txt +++ b/samples/wasm-c-api/CMakeLists.txt @@ -136,26 +136,13 @@ include (${SHARED_DIR}/utils/uncommon/shared_uncommon.cmake) set(MM_UTIL src/utils/multi_module_utils.c) # build executable for each .c -set(EXAMPLES - callback - callback_chain - clone - empty_imports - global - hello - hostref - memory - reflect - table - threads - trap -) - -if(WAMR_BUILD_JIT AND WAMR_BUILD_LAZY_JIT) - if((${WAMR_BUILD_JIT} EQUAL 1) AND (${WAMR_BUILD_LAZY_JIT} EQUAL 1)) - list(APPEND EXAMPLES serialize) - endif() -endif() +list(APPEND EXAMPLES callback callback_chain empty_imports global hello hostref memory reflect table trap) +# FIXME enable both in the future +#list(APPEND EXAMPLES clone threads) +# FIXME +# if(WAMR_BUILD_JIT EQUAL 1 AND WAMR_BUILD_LAZY_JIT EQUAL 0) +# list(APPEND EXAMPLES serialize) +# endif() check_pie_supported() diff --git a/samples/wasm-c-api/README.md b/samples/wasm-c-api/README.md index 51b8642a..b2327670 100644 --- a/samples/wasm-c-api/README.md +++ b/samples/wasm-c-api/README.md @@ -4,9 +4,9 @@ Before staring, we need to download and intall [WABT](https://github.com/WebAsse ``` shell $ cd /opt -$ wget https://github.com/WebAssembly/wabt/releases/download/1.0.19/wabt-1.0.19-ubuntu.tar.gz -$ tar -xzf wabt-1.0.19-ubuntu.tar.gz -$ mv wabt-1.0.19 wabt +$ wget https://github.com/WebAssembly/wabt/releases/download/1.0.31/wabt-1.0.31-ubuntu.tar.gz +$ tar -xzf wabt-1.0.31-ubuntu.tar.gz +$ mv wabt-1.0.31 wabt ``` By default, all samples are compiled and run in "interpreter" mode. @@ -47,4 +47,4 @@ $ ./global $ ... $ ./callback $ ... -``` \ No newline at end of file +``` diff --git a/samples/workload/CMakeLists.txt b/samples/workload/CMakeLists.txt new file mode 100644 index 00000000..5e5dca28 --- /dev/null +++ b/samples/workload/CMakeLists.txt @@ -0,0 +1,116 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required (VERSION 3.14) + +project(wasm_workloads) + +####################################### +add_subdirectory(bwa) +add_subdirectory(meshoptimizer) +add_subdirectory(wasm-av1) + +####################################### +include(ExternalProject) + +################ iwasm ################ +ExternalProject_Add(iwasm + PREFIX + iwasm-build + BUILD_ALWAYS + YES + SOURCE_DIR + ${CMAKE_CURRENT_SOURCE_DIR}/../../product-mini/platforms/linux + CONFIGURE_COMMAND + ${CMAKE_COMMAND} -S ${CMAKE_CURRENT_SOURCE_DIR}/../../product-mini/platforms/linux -B build -DWAMR_BUILD_LIBC_EMCC=1 + BUILD_COMMAND + ${CMAKE_COMMAND} --build build + INSTALL_COMMAND + # FIXME: replace with --install + ${CMAKE_COMMAND} -E copy_if_different + ${CMAKE_CURRENT_BINARY_DIR}/iwasm-build/src/iwasm-build/build/iwasm + ${CMAKE_CURRENT_BINARY_DIR}/iwasm +) + +################ wamrc ################ +ExternalProject_Add(wamrc + PREFIX + wamrc-build + BUILD_ALWAYS + YES + SOURCE_DIR + ${CMAKE_CURRENT_SOURCE_DIR}/../../wamr-compiler + CONFIGURE_COMMAND + ${CMAKE_COMMAND} -S ${CMAKE_CURRENT_SOURCE_DIR}/../../wamr-compiler -B build + BUILD_COMMAND + ${CMAKE_COMMAND} --build build + INSTALL_COMMAND + # FIXME: replace with --install + ${CMAKE_COMMAND} -E copy_if_different + ${CMAKE_CURRENT_BINARY_DIR}/wamrc-build/src/wamrc-build/build/wamrc + ${CMAKE_CURRENT_BINARY_DIR}/wamrc +) + +################ .aot ################ +add_custom_target( + bwa_to_aot + ALL + DEPENDS + bwa wamrc + COMMAND + ./wamrc -o bwa.aot ./bwa/bwa.wasm + WORKING_DIRECTORY + ${CMAKE_CURRENT_BINARY_DIR} +) + +add_custom_target( + codecbench_to_aot + ALL + DEPENDS + codecbench wamrc + COMMAND + ./wamrc -o codecbench.aot ./meshoptimizer/codecbench.wasm + WORKING_DIRECTORY + ${CMAKE_CURRENT_BINARY_DIR} +) + +add_custom_target( + av1_to_aot + ALL + DEPENDS + av1 wamrc + COMMAND + ./wamrc -o testavx.aot ./wasm-av1/testavx.opt.wasm + WORKING_DIRECTORY + ${CMAKE_CURRENT_BINARY_DIR} +) + +################ smoking test ################ +include(CTest) + +add_test( + NAME + run_bwa + COMMAND + ./iwasm --dir=. ./bwa.aot index ./bwa/hs38DH-extra.fa + WORKING_DIRECTORY + ${CMAKE_CURRENT_BINARY_DIR} +) + +add_test( + NAME + run_codecbench + COMMAND + ./iwasm codecbench.aot + WORKING_DIRECTORY + ${CMAKE_CURRENT_BINARY_DIR} +) + +add_test( + NAME + run_av1 + COMMAND + ./iwasm --dir=. testavx.aot ./wasm-av1/elephants_dream_480p24.ivf + WORKING_DIRECTORY + ${CMAKE_CURRENT_BINARY_DIR} +) \ No newline at end of file diff --git a/samples/workload/README.md b/samples/workload/README.md index dd94e05c..0e6a3a41 100644 --- a/samples/workload/README.md +++ b/samples/workload/README.md @@ -1,41 +1,30 @@ -All workloads have similar requirment of software dependencies, including -**emsdk**, **wabt** and **binaryen** +All workloads have similar requirment of software dependencies, including **emsdk** and **binaryen** -> There might be slight differences when using MacOS and other Linux distro than Ubuntu. This document only target -Ubuntu 18.04 as example. +> There might be slight differences when using MacOS and other Linux distro than Ubuntu. This document targets +Ubuntu 20.04 as an example. ## Installation instructions -use [preparation.sh](./preparation.sh) to install all dependencies before compiling any workload. +use [preparation.sh](./preparation.sh) to install all dependencies before compiling any workload. Or use [*vscode DevContainer*](../../.devcontainer/) -for details, the script includes below steps: - -- **wabt**. Install - [latest release](https://github.com/WebAssembly/wabt/releases/download/1.0.23/wabt-1.0.23-ubuntu.tar.gz) - to */opt/wabt* - -``` bash -$ wget https://github.com/WebAssembly/wabt/releases/download/${WABT_VER}/${WABT_FILE} -$ tar zxf ${WABT_FILE} -C /opt -$ ln -sf /opt/wabt-${WABT_VER} /opt/wabt -``` +The script installs below software: - **emsdk**. Refer to [the guide](https://emscripten.org/docs/getting_started/downloads.html). Don't forget to activate emsdk and set up environment variables. Verify it with `echo ${EMSDK}`. Please be sure to install and activate the building - of 2.0.26 + of 3.0.0 ``` bash $ cd /opt $ git clone https://github.com/emscripten-core/emsdk.git $ cd emsdk $ git pull -$ ./emsdk install 2.0.26 -$ ./emsdk activate 2.0.26 +$ ./emsdk install 3.0.0 +$ ./emsdk activate 3.0.0 $ echo "source /opt/emsdk/emsdk_env.sh" >> "${HOME}"/.bashrc ``` - **binaryen**. Install - [latest release](https://github.com/WebAssembly/binaryen/releases/download/version_101/binaryen-version_101-x86_64-linux.tar.gz) + [latest release](https://github.com/WebAssembly/binaryen/releases/download/version_111/binaryen-version_111-x86_64-linux.tar.gz) to */opt/binaryen* ``` bash diff --git a/samples/workload/XNNPACK/CMakeLists.txt b/samples/workload/XNNPACK/CMakeLists.txt index 3f67367a..532544f9 100644 --- a/samples/workload/XNNPACK/CMakeLists.txt +++ b/samples/workload/XNNPACK/CMakeLists.txt @@ -15,8 +15,9 @@ ExternalProject_Add(xnnpack GIT_PROGRESS ON SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/xnnpack UPDATE_COMMAND git checkout . - && git reset --hard 4d738aef36872669e4bba05a4b259149ba8e62e1 - && cmake -E copy ${CMAKE_CURRENT_SOURCE_DIR}/benchmark.patch ${CMAKE_CURRENT_SOURCE_DIR}/xnnpack/third_party + && git reset --hard 4570a7151aa4f3e57eca14a575eeff6bb13e26be + && cmake -E copy ${CMAKE_CURRENT_SOURCE_DIR}/xnnpack/google3/third_party/XNNPACK/microkernels.bzl + ${CMAKE_CURRENT_SOURCE_DIR}/xnnpack/ && git apply ${CMAKE_CURRENT_SOURCE_DIR}/xnnpack.patch CONFIGURE_COMMAND "" # grep xnnpack_benchmark -A 1 BUILD.bazel \ @@ -24,70 +25,123 @@ ExternalProject_Add(xnnpack # | awk '{print $3}' \ # | sed -e 's/\"//g' -e 's/,//g' -e 's/^/\/\/:/g' BUILD_COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR}/xnnpack - && bazel --output_user_root=build_user_output build -c opt --config=wasm + && bazel --output_user_root=build-user-output build -c opt --config=wasm //:qs8_dwconv_bench.wasm + //:qs8_f32_vcvt_bench.wasm //:qs8_gemm_bench.wasm //:qs8_requantization_bench.wasm //:qs8_vadd_bench.wasm //:qs8_vaddc_bench.wasm + //:qs8_vcvt_bench.wasm + //:qs8_vlrelu_bench.wasm + //:qs8_vmul_bench.wasm + //:qs8_vmulc_bench.wasm + //:qu8_f32_vcvt_bench.wasm //:qu8_gemm_bench.wasm //:qu8_requantization_bench.wasm //:qu8_vadd_bench.wasm //:qu8_vaddc_bench.wasm + //:qu8_vcvt_bench.wasm + //:qu8_vlrelu_bench.wasm + //:qu8_vmul_bench.wasm + //:qu8_vmulc_bench.wasm + //:bf16_gemm_bench.wasm //:f16_igemm_bench.wasm //:f16_gemm_bench.wasm + //:f16_raddstoreexpminusmax_bench.wasm //:f16_spmm_bench.wasm - //:f16_vrelu_bench.wasm + //:f16_vsigmoid_bench.wasm + //:f16_f32_vcvt_bench.wasm //:f32_igemm_bench.wasm //:f32_conv_hwc_bench.wasm + //:f16_conv_hwc2chw_bench.wasm + //:f16_gavgpool_cw_bench.wasm + //:f32_gavgpool_cw_bench.wasm //:f32_conv_hwc2chw_bench.wasm //:f16_dwconv_bench.wasm //:f32_dwconv_bench.wasm //:f32_dwconv2d_chw_bench.wasm + //:f16_dwconv2d_chw_bench.wasm + //:f32_f16_vcvt_bench.wasm + //:xx_transpose_bench.wasm + //:x8_transpose_bench.wasm + //:x16_transpose_bench.wasm + //:x24_transpose_bench.wasm + //:x32_transpose_bench.wasm + //:x64_transpose_bench.wasm //:f32_gemm_bench.wasm + //:f32_qs8_vcvt_bench.wasm + //:f32_qu8_vcvt_bench.wasm //:f32_raddexpminusmax_bench.wasm //:f32_raddextexp_bench.wasm //:f32_raddstoreexpminusmax_bench.wasm //:f32_rmax_bench.wasm //:f32_spmm_bench.wasm //:f32_softmax_bench.wasm + //:f16_velu_bench.wasm //:f32_velu_bench.wasm //:f32_vhswish_bench.wasm + //:f32_vlrelu_bench.wasm //:f32_vrelu_bench.wasm //:f32_vscaleexpminusmax_bench.wasm //:f32_vscaleextexp_bench.wasm //:f32_vsigmoid_bench.wasm + //:f16_vsqrt_bench.wasm //:f32_vsqrt_bench.wasm //:f32_im2col_gemm_bench.wasm //:rounding_bench.wasm + //:s16_rmaxabs_bench.wasm + //:s16_window_bench.wasm + //:u32_filterbank_accumulate_bench.wasm + //:u32_filterbank_subtract_bench.wasm + //:u32_vlog_bench.wasm + //:u64_u32_vsqrtshift_bench.wasm + //:i16_vlshift_bench.wasm + //:cs16_vsquareabs_bench.wasm + //:cs16_bfly4_bench.wasm + //:cs16_fftr_bench.wasm + //:x8_lut_bench.wasm + //:abs_bench.wasm //:average_pooling_bench.wasm //:bankers_rounding_bench.wasm //:ceiling_bench.wasm //:channel_shuffle_bench.wasm + //:convert_bench.wasm //:convolution_bench.wasm //:deconvolution_bench.wasm //:elu_bench.wasm //:floor_bench.wasm //:global_average_pooling_bench.wasm //:hardswish_bench.wasm + //:leaky_relu_bench.wasm //:max_pooling_bench.wasm + //:negate_bench.wasm //:sigmoid_bench.wasm //:prelu_bench.wasm //:softmax_bench.wasm + //:square_bench.wasm //:square_root_bench.wasm //:truncation_bench.wasm + //:f16_gemm_e2e_bench.wasm //:f32_dwconv_e2e_bench.wasm //:f32_gemm_e2e_bench.wasm //:qs8_dwconv_e2e_bench.wasm //:qs8_gemm_e2e_bench.wasm + //:qu8_gemm_e2e_bench.wasm //:qu8_dwconv_e2e_bench.wasm //:end2end_bench.wasm + //:f16_exp_ulp_eval.wasm + //:f16_expminus_ulp_eval.wasm + //:f16_expm1minus_ulp_eval.wasm + //:f16_sigmoid_ulp_eval.wasm + //:f16_sqrt_ulp_eval.wasm //:f32_exp_ulp_eval.wasm //:f32_expminus_ulp_eval.wasm //:f32_expm1minus_ulp_eval.wasm //:f32_extexp_ulp_eval.wasm //:f32_sigmoid_ulp_eval.wasm //:f32_sqrt_ulp_eval.wasm + //:f32_tanh_ulp_eval.wasm INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/xnnpack/bazel-out/wasm-opt/bin/ ${CMAKE_BINARY_DIR}/wasm-opt diff --git a/samples/workload/XNNPACK/README.md b/samples/workload/XNNPACK/README.md index f6a20729..7984d9ce 100644 --- a/samples/workload/XNNPACK/README.md +++ b/samples/workload/XNNPACK/README.md @@ -24,7 +24,7 @@ Firstly please build iwasm with simd, libc-emcc and lib-pthread support: ``` bash $ cd /product-mini/platforms/linux/ $ mkdir build && cd build -$ cmake .. -DWAMR_BUILD_SIMD=1 -DWAMR_BUILD_LIBC_EMCC=1 -DWAMR_BUILD_LIB_PTHREAD=1 +$ cmake .. -DWAMR_BUILD_LIBC_EMCC=1 -DWAMR_BUILD_LIB_PTHREAD=1 $ make ``` @@ -42,7 +42,7 @@ Then compile wasm file to aot file and run: ``` shell $ cd /samples/workload/XNNPACK/xnnpack/bazel-bin -$ wamrc --enable-simd -o average_pooling_bench.aot average_pooling_bench.wasm (or other wasm files) +$ wamrc -o average_pooling_bench.aot average_pooling_bench.wasm (or other wasm files) $ iwasm average_pooling_bench.aot ``` diff --git a/samples/workload/XNNPACK/build_workload.sh b/samples/workload/XNNPACK/build_workload.sh deleted file mode 120000 index a31afa92..00000000 --- a/samples/workload/XNNPACK/build_workload.sh +++ /dev/null @@ -1 +0,0 @@ -../docker/build_workload.sh \ No newline at end of file diff --git a/samples/workload/XNNPACK/xnnpack.patch b/samples/workload/XNNPACK/xnnpack.patch index 7eed678b..f7d0a01d 100644 --- a/samples/workload/XNNPACK/xnnpack.patch +++ b/samples/workload/XNNPACK/xnnpack.patch @@ -1,8 +1,8 @@ diff --git a/.bazelrc b/.bazelrc -index ec740f38..29f9d56e 100644 +index 688279da1..376996885 100644 --- a/.bazelrc +++ b/.bazelrc -@@ -49,4 +49,9 @@ build:ios_fat --watchos_cpus=armv7k +@@ -53,4 +53,9 @@ build:ios_fat --watchos_cpus=armv7k build:macos --apple_platform_type=macos build:macos_arm64 --config=macos @@ -11,42 +11,26 @@ index ec740f38..29f9d56e 100644 +build:macos_arm64 --cpu=darwin_arm64 + +build:wasm --cpu=wasm -+build:wasm --copt=-msimd128 ++build:wasm --features=wasm_simd +build:wasm --crosstool_top=@emsdk//emscripten_toolchain:everything +build:wasm --host_crosstool_top=@bazel_tools//tools/cpp:toolchain -diff --git a/BUILD.bazel b/BUILD.bazel -index 3fc8139f..c893356d 100644 ---- a/BUILD.bazel -+++ b/BUILD.bazel -@@ -11988,7 +11988,6 @@ config_setting( - values = { - "crosstool_top": "@emsdk//emscripten_toolchain:everything", - "cpu": "wasm", -- "copt": "-msimd128", - "copt": "-mrelaxed-simd", - }, - ) diff --git a/WORKSPACE b/WORKSPACE -index c58e76b6..30934678 100644 +index cd8960ffa..5d3e685f4 100644 --- a/WORKSPACE +++ b/WORKSPACE -@@ -21,6 +21,7 @@ http_archive( - name = "com_google_benchmark", - strip_prefix = "benchmark-master", - urls = ["https://github.com/google/benchmark/archive/master.zip"], -+ patches = ["@//third_party:benchmark.patch"], - ) - - # FP16 library, used for half-precision conversions -@@ -84,6 +85,19 @@ http_archive( - ], +@@ -92,8 +92,25 @@ http_archive( + ], ) ++load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") +http_archive( -+ name = "emsdk", -+ strip_prefix = "emsdk-2.0.26/bazel", -+ url = "https://github.com/emscripten-core/emsdk/archive/refs/tags/2.0.26.tar.gz", -+ sha256 = "79e7166aa8eaae6e52cef1363b2d8db795d03684846066bc51f9dcf905dd58ad", ++ name = "emsdk", ++ # Use emsdk-3.0.0 since the larger version may: ++ # - compress the wasm file into a tar file but not directly generate wasm file ++ # - generate incomplete implementation of libc API, e.g. throw exception in getentropy ++ strip_prefix = "emsdk-3.0.0/bazel", ++ url = "https://github.com/emscripten-core/emsdk/archive/refs/tags/3.0.0.tar.gz", ++ sha256 = "a41dccfd15be9e85f923efaa0ac21943cbab77ec8d39e52f25eca1ec61a9ac9e" +) + +load("@emsdk//:deps.bzl", emsdk_deps = "deps") @@ -56,13 +40,17 @@ index c58e76b6..30934678 100644 +emsdk_emscripten_deps() + # Android NDK location and version is auto-detected from $ANDROID_NDK_HOME environment variable - android_ndk_repository(name = "androidndk") +-android_ndk_repository(name = "androidndk") ++#android_ndk_repository(name = "androidndk") + # Android SDK location and API is auto-detected from $ANDROID_HOME environment variable +-android_sdk_repository(name = "androidsdk") ++#android_sdk_repository(name = "androidsdk") diff --git a/build_defs.bzl b/build_defs.bzl -index fbadb400..e496b78d 100644 +index b8217a18d..da232966e 100644 --- a/build_defs.bzl +++ b/build_defs.bzl -@@ -430,7 +430,7 @@ def xnnpack_benchmark(name, srcs, copts = [], deps = [], tags = []): +@@ -380,7 +380,7 @@ def xnnpack_benchmark(name, srcs, copts = [], deps = [], tags = []): explicitly specified. """ native.cc_binary( @@ -72,7 +60,7 @@ index fbadb400..e496b78d 100644 copts = xnnpack_std_cxxopts() + [ "-Iinclude", diff --git a/emscripten.bzl b/emscripten.bzl -index 130d5f16..2696ad54 100644 +index f1557a7b1..7f964a094 100644 --- a/emscripten.bzl +++ b/emscripten.bzl @@ -25,12 +25,19 @@ def xnnpack_emscripten_benchmark_linkopts(): @@ -84,7 +72,7 @@ index 130d5f16..2696ad54 100644 - "-s EXIT_RUNTIME=1", + "-s ERROR_ON_UNDEFINED_SYMBOLS=0", "-s ALLOW_MEMORY_GROWTH=1", - "-s TOTAL_MEMORY=445644800", # 425M + "-s TOTAL_MEMORY=536870912", # 512M - "--pre-js $(location :preamble.js.lds)", + "-s USE_PTHREADS=0", + "-s STANDALONE_WASM=1", @@ -99,11 +87,33 @@ index 130d5f16..2696ad54 100644 ] def xnnpack_emscripten_deps(): +diff --git a/src/log.c b/src/log.c +index 5715f2f85..4b3e4261b 100644 +--- a/src/log.c ++++ b/src/log.c +@@ -55,7 +55,7 @@ + #endif + + #if XNN_LOG_TO_STDIO +-static void xnn_vlog(int output_handle, const char* prefix, size_t prefix_length, const char* format, va_list args) { ++void xnn_vlog(int output_handle, const char* prefix, size_t prefix_length, const char* format, va_list args) { + char stack_buffer[XNN_LOG_STACK_BUFFER_SIZE]; + char* heap_buffer = NULL; + char* out_buffer = &stack_buffer[0]; diff --git a/third_party/cpuinfo.BUILD b/third_party/cpuinfo.BUILD -index 128d683e..f6c287c4 100644 +index 1997f4e3a..5e03c43af 100644 --- a/third_party/cpuinfo.BUILD +++ b/third_party/cpuinfo.BUILD -@@ -343,5 +343,5 @@ config_setting( +@@ -150,7 +150,7 @@ cc_library( + "src/arm/midr.h", + ], + deps = [ +- "@clog", ++ "//deps/clog" + ], + ) + +@@ -352,5 +352,5 @@ config_setting( config_setting( name = "emscripten", diff --git a/samples/workload/bwa/CMakeLists.bwa_wasm.txt b/samples/workload/bwa/CMakeLists.bwa_wasm.txt index c68b942f..a8d1d882 100644 --- a/samples/workload/bwa/CMakeLists.bwa_wasm.txt +++ b/samples/workload/bwa/CMakeLists.bwa_wasm.txt @@ -1,11 +1,14 @@ # Copyright (C) 2019 Intel Corporation. All rights reserved. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -cmake_minimum_required (VERSION 3.0) +cmake_minimum_required (VERSION 3.14) project(bwa_wasm C) -include(${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/preparation.cmake) +list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../../cmake) + +################ dependencies ################ +find_package(Binaryen 111 REQUIRED) ################ LIBZ ################ set(LIBZ_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../libz) @@ -86,12 +89,6 @@ add_executable(${PROJECT_NAME} ${BWA_SOURCE}) set_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME bwa.wasm) -target_include_directories(${PROJECT_NAME} - PRIVATE - ${WASI_SDK_HOME}/share/wasi-sysroot/include/libc/musl - ${WASI_SDK_HOME}/share/wasi-sysroot/include/sse -) - target_compile_definitions(${PROJECT_NAME} PRIVATE USE_MALLOC_WRAPPERS @@ -117,7 +114,7 @@ target_link_libraries(${PROJECT_NAME} z_wasm wasi-emulated-process-clocks) add_custom_target(bwa_wasm_opt ALL COMMAND - ${WASM_OPT} -Oz --enable-simd -o bwa.opt.wasm bwa.wasm + ${Binaryen_WASM_OPT} -Oz --enable-simd -o bwa.opt.wasm bwa.wasm BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/bwa.opt.wasm WORKING_DIRECTORY diff --git a/samples/workload/bwa/CMakeLists.txt b/samples/workload/bwa/CMakeLists.txt index 7f7e3182..731dd4c7 100644 --- a/samples/workload/bwa/CMakeLists.txt +++ b/samples/workload/bwa/CMakeLists.txt @@ -1,11 +1,19 @@ # Copyright (C) 2019 Intel Corporation. All rights reserved. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -cmake_minimum_required (VERSION 2.8...3.16) +cmake_minimum_required (VERSION 3.14) project(bwa_wasm) -include(${CMAKE_CURRENT_SOURCE_DIR}/../cmake/preparation.cmake) +list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../cmake) + +################ dependencies ################ +find_package(Python3 REQUIRED) +find_package(WASISDK 16.0 REQUIRED) +execute_process( + COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_LIST_DIR}/../../../test-tools/pick-up-emscripten-headers/collect_files.py --install ../include --loglevel=ERROR + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} +) ####################################### include(ExternalProject) @@ -13,7 +21,7 @@ include(ExternalProject) ################ libz ################ ExternalProject_Add(libz_src GIT_REPOSITORY https://github.com/madler/zlib.git - GIT_TAG master + GIT_TAG 04f42ceca40f73e2978b50e93806c2a18c1281fc GIT_PROGRESS ON GIT_SHALLOW ON SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/libz @@ -27,7 +35,7 @@ ExternalProject_Add(libz_src ################ bwa ################ ExternalProject_Add(bwa GIT_REPOSITORY https://github.com/lh3/bwa.git - GIT_TAG master + GIT_TAG 139f68fc4c3747813783a488aef2adc86626b01b GIT_PROGRESS ON GIT_SHALLOW ON SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/bwa @@ -37,10 +45,29 @@ ExternalProject_Add(bwa && ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.bwa_wasm.txt CMakeLists.txt && git apply ../bwa.patch CONFIGURE_COMMAND ${CMAKE_COMMAND} - -DWASI_SDK_PREFIX=${WASI_SDK_HOME} - -DCMAKE_TOOLCHAIN_FILE=${WASI_SDK_HOME}/share/cmake/wasi-sdk.cmake - -DCMAKE_SYSROOT=${WASI_SDK_HOME}/share/wasi-sysroot + -DWASI_SDK_PREFIX=${WASISDK_HOME} + -DCMAKE_TOOLCHAIN_FILE=${WASISDK_TOOLCHAIN} + -DCMAKE_SYSROOT=${WASISDK_SYSROOT} + -DCMAKE_C_FLAGS=-isystem\ ${CMAKE_CURRENT_SOURCE_DIR}/../include/sse\ -isystem\ ${CMAKE_CURRENT_SOURCE_DIR}/../include/libc/musl ${CMAKE_CURRENT_SOURCE_DIR}/bwa BUILD_COMMAND make bwa_wasm_opt - INSTALL_COMMAND ${CMAKE_COMMAND} -E copy ./bwa.opt.wasm ${CMAKE_BINARY_DIR}/bwa.wasm + INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_if_different ./bwa.opt.wasm ${CMAKE_CURRENT_BINARY_DIR}/bwa.wasm ) + +################ bwa data ################ +ExternalProject_Add(bwa-kit + PREFIX bwa-kit + URL https://sourceforge.net/projects/bio-bwa/files/bwakit/bwakit-0.7.15_x64-linux.tar.bz2/download + URL_HASH SHA256=0a7b11971bc7916b68e9df35a364afe77cb3000df02ffb3a6fbd1aff9be5878c + DOWNLOAD_NAME bwakit-0.7.15_x64-linux.tar.bz2 + DOWNLOAD_EXTRACT_TIMESTAMP ON + DOWNLOAD_NO_EXTRACT OFF + DOWNLOAD_NO_PROGRESS ON + UPDATE_COMMAND "" + PATCH_COMMAND "" + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_if_different + ${CMAKE_CURRENT_BINARY_DIR}/bwa-kit/src/bwa-kit/resource-GRCh38/hs38DH-extra.fa + ${CMAKE_CURRENT_BINARY_DIR}/hs38DH-extra.fa +) \ No newline at end of file diff --git a/samples/workload/bwa/README.md b/samples/workload/bwa/README.md index e826bb61..a8fbe3e6 100644 --- a/samples/workload/bwa/README.md +++ b/samples/workload/bwa/README.md @@ -33,7 +33,7 @@ Firstly please build iwasm with simd support: ``` shell $ cd /product-mini/platforms/linux/ $ mkdir build && cd build -$ cmake .. -DWAMR_BUILD_SIMD=1 +$ cmake .. $ make ``` @@ -41,6 +41,6 @@ Then compile wasm file to aot file and run: ``` shell $ cd /samples/workload/bwa/build -$ /wamr-compiler/build/wamrc --enable-simd -o bwa.aot bwa.wasm +$ /wamr-compiler/build/wamrc -o bwa.aot bwa.wasm $ /product-mini/platforms/linux/iwasm --dir=. bwa.aot index hs38DH.fa ``` diff --git a/samples/workload/bwa/build_workload.sh b/samples/workload/bwa/build_workload.sh deleted file mode 120000 index a31afa92..00000000 --- a/samples/workload/bwa/build_workload.sh +++ /dev/null @@ -1 +0,0 @@ -../docker/build_workload.sh \ No newline at end of file diff --git a/samples/workload/cmake/FindBinaryen.cmake b/samples/workload/cmake/FindBinaryen.cmake new file mode 100644 index 00000000..b4a64786 --- /dev/null +++ b/samples/workload/cmake/FindBinaryen.cmake @@ -0,0 +1,43 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +# +# Output below variables: +# - Binaryen_HOME. the installation location +# + +include(CMakePrintHelpers) +include(FindPackageHandleStandardArgs) + +file(GLOB Binaryen_SEARCH_PATH "/opt/binaryen*") +find_path(Binaryen_HOME + NAMES bin/wasm-opt + PATHS ${Binaryen_SEARCH_PATH} + NO_CMAKE_FIND_ROOT_PATH + NO_SYSTEM_ENVIRONMENT_PATH + REQUIRED +) + +execute_process( + COMMAND ${Binaryen_HOME}/bin/wasm-opt --version + OUTPUT_VARIABLE WASM_OPT_OUTPUT + OUTPUT_STRIP_TRAILING_WHITESPACE +) + +string(REGEX MATCH version_[0-9]+ Binaryen_VERSION_tmp ${WASM_OPT_OUTPUT}) +string(REGEX MATCH [0-9]+ Binaryen_VERSION ${Binaryen_VERSION_tmp}) + +#cmake_print_variables(Binaryen_VERSION_tmp Binaryen_VERSION) + +find_package_handle_standard_args(Binaryen REQUIRED_VARS Binaryen_HOME VERSION_VAR Binaryen_VERSION) + +if(Binaryen_FOUND) + mark_as_advanced(Binaryen_SEARCH_PATH) + mark_as_advanced(Binaryen_VERSION_tmp) + mark_as_advanced(Binaryen_VERSION) + mark_as_advanced(WASM_OPT_OUTPUT) + + set(Binaryen_WASM_OPT ${Binaryen_HOME}/bin/wasm-opt) +else() + # TODO: install WASISDK +endif() diff --git a/samples/workload/cmake/FindWASISDK.cmake b/samples/workload/cmake/FindWASISDK.cmake new file mode 100644 index 00000000..fff8aea4 --- /dev/null +++ b/samples/workload/cmake/FindWASISDK.cmake @@ -0,0 +1,38 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +# +# Output below variables: +# - WASISDK_HOME. the installation location +# - WASISDK_SYSROOT. where wasi-sysroot is +# - WASISDK_TOOLCHAIN. where wasi-sdk.cmake is +# + +include(CMakePrintHelpers) +include(FindPackageHandleStandardArgs) + +file(GLOB WASISDK_SEARCH_PATH "/opt/wasi-sdk-*") +find_path(WASISDK_HOME + NAMES share/wasi-sysroot + PATHS ${WASISDK_SEARCH_PATH} + NO_CMAKE_FIND_ROOT_PATH + NO_SYSTEM_ENVIRONMENT_PATH + REQUIRED +) + +string(REGEX MATCH [0-9]+\.[0-9]+\.*[0-9]* WASISDK_VERSION ${WASISDK_HOME}) + +#cmake_print_variables(WASISDK_HOME WASISDK_VERSION) +find_package_handle_standard_args(WASISDK REQUIRED_VARS WASISDK_HOME VERSION_VAR WASISDK_VERSION) + +if(WASISDK_FOUND) + mark_as_advanced(WASISDK_SEARCH_PATH) + mark_as_advanced(WASISDK_VERSION) + + set(WASISDK_CC_COMMAND ${WASISDK_HOME}/bin/clang) + set(WASISDK_CXX_COMMAND ${WASISDK_HOME}/bin/clang++) + set(WASISDK_SYSROOT ${WASISDK_HOME}/share/wasi-sysroot) + set(WASISDK_TOOLCHAIN ${WASISDK_HOME}/share/cmake/wasi-sdk.cmake) +else() + # TODO: install WASISDK +endif() diff --git a/samples/workload/cmake/preparation.cmake b/samples/workload/cmake/preparation.cmake deleted file mode 100644 index 326943c8..00000000 --- a/samples/workload/cmake/preparation.cmake +++ /dev/null @@ -1,49 +0,0 @@ -# Copyright (C) 2019 Intel Corporation. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -####################################### -include(ExternalProject) - -file(REAL_PATH ../../.. WAMR_ROOT - BASE_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} -) - -find_path(WASI_SDK_PARENT - name wasi-sdk - PATHS ${WAMR_ROOT}/test-tools/ - NO_DEFAULT_PATH - NO_CMAKE_FIND_ROOT_PATH -) - -if(NOT WASI_SDK_PARENT) - message(FATAL_ERROR - "can not find 'wasi-sdk' under ${WAMR_ROOT}/test-tools, " - "please run ${WAMR_ROOT}/test-tools/build-wasi-sdk/build_wasi_sdk.py " - "to build wasi-sdk and try again" - ) -endif() - -set(WASI_SDK_HOME ${WASI_SDK_PARENT}/wasi-sdk) -message(CHECK_START "Detecting WASI-SDK at ${WASI_SDK_HOME}") -if(EXISTS "${WASI_SDK_HOME}/share/cmake/wasi-sdk.cmake") - message(CHECK_PASS "found") -else() - message(CHECK_FAIL "not found") -endif() - -################ BINARYEN ################ -find_program(WASM_OPT - NAMES wasm-opt - PATHS /opt/binaryen-version_101/bin /opt/binaryen/bin - NO_DEFAULT_PATH - NO_CMAKE_FIND_ROOT_PATH -) - -if(NOT WASM_OPT) - message(FATAL_ERROR - "can not find wasm-opt. " - "please download it from " - "https://github.com/WebAssembly/binaryen/releases/download/version_101/binaryen-version_101-x86_64-linux.tar.gz " - "and install it under /opt" - ) -endif() diff --git a/samples/workload/docker/build_workload.sh b/samples/workload/docker/build_workload.sh deleted file mode 100755 index 640cca97..00000000 --- a/samples/workload/docker/build_workload.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/env bash -# -# Copyright (C) 2019 Intel Corporation. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -# - -readonly SCRIPT_PATH=$(dirname "$(realpath "$0")") -readonly ROOT=$(realpath "${SCRIPT_PATH}"/../../../) -readonly CURRENT_PATH=$(pwd) -readonly CURRENT_RELATIVE_ROOT=$(realpath --relative-base ${ROOT} ${CURRENT_PATH}) -readonly VARIANT=$(lsb_release -c | awk '{print $2}') - -docker build \ - --build-arg VARIANT=${VARIANT} \ - --memory 4G --cpu-quota 50000 \ - -t wamr_dev_${VARIANT}:0.1 -f "${ROOT}"/.devcontainer/Dockerfile "${ROOT}"/.devcontainer && - docker run --rm -it \ - --memory 4G \ - --cpus ".5" \ - --name workload_build_env \ - --mount type=bind,source="${ROOT}",target=/workspace \ - wamr_dev_${VARIANT}:0.1 \ - /bin/bash -c "\ - pwd \ - && pushd ${CURRENT_RELATIVE_ROOT} \ - && rm -rf build \ - && mkdir build \ - && pushd build \ - && cmake .. \ - && cmake --build . --config Release \ - && popd \ - && popd \ - && echo 'Go and find out results under ${CURRENT_RELATIVE_ROOT}/build' " diff --git a/samples/workload/include/.gitkeep b/samples/workload/include/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/samples/workload/meshoptimizer/CMakeLists.txt b/samples/workload/meshoptimizer/CMakeLists.txt index 172de8d6..cb490f91 100644 --- a/samples/workload/meshoptimizer/CMakeLists.txt +++ b/samples/workload/meshoptimizer/CMakeLists.txt @@ -1,11 +1,19 @@ # Copyright (C) 2019 Intel Corporation. All rights reserved. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -cmake_minimum_required (VERSION 3.0) +cmake_minimum_required (VERSION 3.14) project(bench-meshoptimizer) -include(${CMAKE_CURRENT_SOURCE_DIR}/../cmake/preparation.cmake) +list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../cmake) + +################ dependencies ################ +find_package(Python3 REQUIRED) +find_package(WASISDK 16.0 REQUIRED) +execute_process( + COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_LIST_DIR}/../../../test-tools/pick-up-emscripten-headers/collect_files.py --install ../include --loglevel=ERROR + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} +) ################ MESHOPTIMIZER ################ include(ExternalProject) @@ -13,7 +21,7 @@ include(ExternalProject) ExternalProject_Add(codecbench PREFIX codecbench GIT_REPOSITORY https://github.com/zeux/meshoptimizer.git - GIT_TAG master + GIT_TAG f926b288264522e1b331a41b07ba40167f396913 GIT_SHALLOW ON GIT_PROGRESS ON SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/meshoptimizer @@ -21,10 +29,10 @@ ExternalProject_Add(codecbench && ${CMAKE_COMMAND} -E echo "Applying patch" && git apply ${CMAKE_CURRENT_SOURCE_DIR}/codecbench.patch CONFIGURE_COMMAND ${CMAKE_COMMAND} - -DWASI_SDK_PREFIX=${WASI_SDK_HOME} - -DCMAKE_TOOLCHAIN_FILE=${WASI_SDK_HOME}/share/cmake/wasi-sdk.cmake - -DCMAKE_SYSROOT=${WASI_SDK_HOME}/share/wasi-sysroot + -DWASI_SDK_PREFIX=${WASISDK_HOME} + -DCMAKE_TOOLCHAIN_FILE=${WASISDK_TOOLCHAIN} + -DCMAKE_SYSROOT=${WASISDK_SYSROOT} ${CMAKE_CURRENT_SOURCE_DIR}/meshoptimizer BUILD_COMMAND make codecbench - INSTALL_COMMAND ${CMAKE_COMMAND} -E copy ./codecbench.wasm ${CMAKE_BINARY_DIR}/codecbench.wasm + INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_if_different ./codecbench.wasm ${CMAKE_CURRENT_BINARY_DIR}/codecbench.wasm ) diff --git a/samples/workload/meshoptimizer/README.md b/samples/workload/meshoptimizer/README.md index ceefb572..466cd875 100644 --- a/samples/workload/meshoptimizer/README.md +++ b/samples/workload/meshoptimizer/README.md @@ -44,14 +44,14 @@ Firstly please build iwasm with simd support: ``` shell $ cd /product-mini/platforms/linux/ $ mkdir build && cd build -$ cmake .. -DWAMR_BUILD_SIMD=1 +$ cmake .. $ make ``` Then compile wasm file to aot file and run: ``` shell -$ /wamr-compiler/build/wamrc --enable-simd -o codecbench.aot codecbench.wasm +$ /wamr-compiler/build/wamrc -o codecbench.aot codecbench.wasm $ /product-mini/platforms/linux/build/iwasm codecbench.aot ``` diff --git a/samples/workload/meshoptimizer/build_workload.sh b/samples/workload/meshoptimizer/build_workload.sh deleted file mode 120000 index a31afa92..00000000 --- a/samples/workload/meshoptimizer/build_workload.sh +++ /dev/null @@ -1 +0,0 @@ -../docker/build_workload.sh \ No newline at end of file diff --git a/samples/workload/preparation.sh b/samples/workload/preparation.sh index 3f49f0cf..47b11ac5 100755 --- a/samples/workload/preparation.sh +++ b/samples/workload/preparation.sh @@ -5,13 +5,13 @@ # readonly BUILD_CONTENT="/tmp/build_content" -readonly WABT_VER=1.0.23 +readonly WABT_VER=1.0.31 readonly WABT_FILE="wabt-${WABT_VER}-ubuntu.tar.gz" -readonly CMAKE_VER=3.16.2 +readonly CMAKE_VER=3.25.1 readonly CMAKE_FILE="cmake-${CMAKE_VER}-Linux-x86_64.sh" -readonly BINARYEN_VER=version_101 +readonly BINARYEN_VER=version_111 readonly BINARYEN_FILE="binaryen-${BINARYEN_VER}-x86_64-linux.tar.gz" -readonly BAZEL_VER=3.7.0 +readonly BAZEL_VER=6.0.0 readonly BAZEL_FILE=bazel-${BAZEL_VER}-installer-linux-x86_64.sh function DEBUG() { @@ -57,8 +57,8 @@ function install_emsdk() { git clone https://github.com/emscripten-core/emsdk.git cd emsdk git pull - ./emsdk install 2.0.26 - ./emsdk activate 2.0.26 + ./emsdk install 3.1.28 + ./emsdk activate 3.1.28 echo "source /opt/emsdk/emsdk_env.sh" >> "${HOME}"/.bashrc } diff --git a/samples/workload/tensorflow/build.sh b/samples/workload/tensorflow/build.sh index 7289e617..d997113f 100755 --- a/samples/workload/tensorflow/build.sh +++ b/samples/workload/tensorflow/build.sh @@ -98,11 +98,11 @@ make WAMRC_CMD="$(pwd)/wamrc" cd ${OUT_DIR} if [[ $1 == '--sgx' ]]; then - ${WAMRC_CMD} --enable-simd -sgx -o benchmark_model.aot benchmark_model.wasm + ${WAMRC_CMD} -sgx -o benchmark_model.aot benchmark_model.wasm elif [[ $1 == '--threads' ]]; then - ${WAMRC_CMD} --enable-simd --enable-multi-thread -o benchmark_model.aot benchmark_model.wasm + ${WAMRC_CMD} --enable-multi-thread -o benchmark_model.aot benchmark_model.wasm else - ${WAMRC_CMD} --enable-simd -o benchmark_model.aot benchmark_model.wasm + ${WAMRC_CMD} -o benchmark_model.aot benchmark_model.wasm fi # 4. build iwasm with pthread and libc_emcc enable @@ -112,14 +112,14 @@ fi if [[ $1 == '--sgx' ]]; then cd ${WAMR_PLATFORM_DIR}/linux-sgx rm -fr build && mkdir build - cd build && cmake .. -DWAMR_BUILD_SIMD=1 -DWAMR_BUILD_LIB_PTHREAD=1 -DWAMR_BUILD_LIBC_EMCC=1 + cd build && cmake .. -DWAMR_BUILD_LIB_PTHREAD=1 -DWAMR_BUILD_LIBC_EMCC=1 make cd ../enclave-sample make else cd ${WAMR_PLATFORM_DIR}/linux rm -fr build && mkdir build - cd build && cmake .. -DWAMR_BUILD_SIMD=1 -DWAMR_BUILD_LIB_PTHREAD=1 -DWAMR_BUILD_LIBC_EMCC=1 + cd build && cmake .. -DWAMR_BUILD_LIB_PTHREAD=1 -DWAMR_BUILD_LIBC_EMCC=1 make fi diff --git a/samples/workload/wasm-av1/CMakeLists.avx_wasm.txt b/samples/workload/wasm-av1/CMakeLists.avx_wasm.txt index d1149612..409665b3 100644 --- a/samples/workload/wasm-av1/CMakeLists.avx_wasm.txt +++ b/samples/workload/wasm-av1/CMakeLists.avx_wasm.txt @@ -1,14 +1,14 @@ # Copyright (C) 2019 Intel Corporation. All rights reserved. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -cmake_minimum_required (VERSION 2.8...3.16) +cmake_minimum_required (VERSION 3.14) project(testavx) -include(${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/preparation.cmake) +list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../../cmake) -# a workaround to let aom find our non-public headers -include_directories(${WASI_SDK_HOME}/share/wasi-sysroot/include/libc/musl) +################ dependencies ################ +find_package(Binaryen 111 REQUIRED) ################ AOM ################ set(ENABLE_CCACHE ON) @@ -62,7 +62,7 @@ add_dependencies(${PROJECT_NAME} aom) add_custom_target(${PROJECT_NAME}_opt ALL COMMAND - ${WASM_OPT} -Oz --enable-simd -o ${PROJECT_NAME}.opt.wasm ${PROJECT_NAME}.wasm + ${Binaryen_WASM_OPT} -Oz --enable-simd -o ${PROJECT_NAME}.opt.wasm ${PROJECT_NAME}.wasm BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.opt.wasm WORKING_DIRECTORY diff --git a/samples/workload/wasm-av1/CMakeLists.txt b/samples/workload/wasm-av1/CMakeLists.txt index 8b1f0df0..6fea31ea 100644 --- a/samples/workload/wasm-av1/CMakeLists.txt +++ b/samples/workload/wasm-av1/CMakeLists.txt @@ -1,11 +1,19 @@ # Copyright (C) 2019 Intel Corporation. All rights reserved. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -cmake_minimum_required (VERSION 2.8...3.16) +cmake_minimum_required (VERSION 3.14) project(av1_wasm) -include(${CMAKE_CURRENT_SOURCE_DIR}/../cmake/preparation.cmake) +list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../cmake) + +################ dependencies ################ +find_package(Python3 REQUIRED) +find_package(WASISDK 16.0 REQUIRED) +execute_process( + COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_LIST_DIR}/../../../test-tools/pick-up-emscripten-headers/collect_files.py --install ../include --loglevel=ERROR + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} +) ####################################### include(ExternalProject) @@ -23,10 +31,14 @@ ExternalProject_Add(av1 && ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.avx_wasm.txt CMakeLists.txt && git apply ../av1-clang.patch CONFIGURE_COMMAND ${CMAKE_COMMAND} - -DWASI_SDK_PREFIX=${WASI_SDK_HOME} - -DCMAKE_TOOLCHAIN_FILE=${WASI_SDK_HOME}/share/cmake/wasi-sdk.cmake - -DCMAKE_SYSROOT=${WASI_SDK_HOME}/share/wasi-sysroot + -DWASI_SDK_PREFIX=${WASISDK_HOME} + -DCMAKE_TOOLCHAIN_FILE=${WASISDK_TOOLCHAIN} + -DCMAKE_SYSROOT=${WASISDK_SYSROOT} + -DCMAKE_C_FLAGS=-isystem\ ${CMAKE_CURRENT_SOURCE_DIR}/../include/sse\ -isystem\ ${CMAKE_CURRENT_SOURCE_DIR}/../include/libc/musl ${CMAKE_CURRENT_SOURCE_DIR}/av1 BUILD_COMMAND make testavx_opt - INSTALL_COMMAND ${CMAKE_COMMAND} -E copy testavx.opt.wasm ${CMAKE_CURRENT_BINARY_DIR}/testavx.wasm + INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_if_different + testavx.opt.wasm + ${CMAKE_CURRENT_SOURCE_DIR}/av1/third_party/samples/elephants_dream_480p24.ivf + ${CMAKE_CURRENT_BINARY_DIR} ) diff --git a/samples/workload/wasm-av1/README.md b/samples/workload/wasm-av1/README.md index e7a92f2a..2166fe6a 100644 --- a/samples/workload/wasm-av1/README.md +++ b/samples/workload/wasm-av1/README.md @@ -39,7 +39,7 @@ Firstly please build iwasm with simd support: ``` shell $ cd /product-mini/platforms/linux/ $ mkdir build && cd build -$ cmake .. -DWAMR_BUILD_SIMD=1 -DWAMR_BUILD_LIBC_EMCC=1 +$ cmake .. -DWAMR_BUILD_LIBC_EMCC=1 $ make ``` @@ -47,7 +47,7 @@ Then compile wasm file to aot file and run: ``` shell $ cd -$ /wamr-compiler/build/wamrc --enable-simd -o testavx.aot testavx.wasm +$ /wamr-compiler/build/wamrc -o testavx.aot testavx.wasm # copy sample data like /samples/workload/wasm-av1/av1/third_party/samples/elephants_dream_480p24.ivf # make sure you declare the access priority of the directory in which the sample data is $ /product-mini/platforms/linux/build/iwasm --dir=. testavx.aot elephants_dream_480p24.ivf diff --git a/samples/workload/wasm-av1/build.sh b/samples/workload/wasm-av1/build.sh index 7f82c6c5..efa17eca 100755 --- a/samples/workload/wasm-av1/build.sh +++ b/samples/workload/wasm-av1/build.sh @@ -85,12 +85,12 @@ cd build && cmake .. make # 3.2 compile wasm-av1.wasm to wasm-av1.aot cd ${OUT_DIR} -${WAMRC_CMD} --enable-simd -o testavx.aot testavx.wasm +${WAMRC_CMD} -o testavx.aot testavx.wasm # 4. build iwasm with pthread and libc_emcc enable cd ${WAMR_PLATFORM_DIR}/linux rm -fr build && mkdir build -cd build && cmake .. -DWAMR_BUILD_SIMD=1 -DWAMR_BUILD_LIB_PTHREAD=1 -DWAMR_BUILD_LIBC_EMCC=1 +cd build && cmake .. -DWAMR_BUILD_LIB_PTHREAD=1 -DWAMR_BUILD_LIBC_EMCC=1 make # 5. run wasm-av1 with iwasm diff --git a/samples/workload/wasm-av1/build_workload.sh b/samples/workload/wasm-av1/build_workload.sh deleted file mode 120000 index a31afa92..00000000 --- a/samples/workload/wasm-av1/build_workload.sh +++ /dev/null @@ -1 +0,0 @@ -../docker/build_workload.sh \ No newline at end of file diff --git a/test-tools/build-wasi-sdk/patches/wasi_libc.patch b/test-tools/build-wasi-sdk/patches/wasi_libc.patch deleted file mode 100644 index e236735b..00000000 --- a/test-tools/build-wasi-sdk/patches/wasi_libc.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/expected/wasm32-wasi/predefined-macros.txt b/expected/wasm32-wasi/predefined-macros.txt -index c1bb19e..954f3b5 100644 ---- a/expected/wasm32-wasi/predefined-macros.txt -+++ b/expected/wasm32-wasi/predefined-macros.txt -@@ -3002,6 +3002,8 @@ - #define __alignof_is_defined 1 - #define __bitop(x,i,o) ((x)[(i)/8] o (1<<(i)%8)) - #define __bool_true_false_are_defined 1 -+#define __clang_literal_encoding__ "UTF-8" -+#define __clang_wide_literal_encoding__ "UTF-32" - #define __inline inline - #define __restrict restrict - #define __tg_complex(fun,x) (__RETCAST_CX(x)( __FLTCX((x)+I) && __IS_FP(x) ? fun ## f (x) : __LDBLCX((x)+I) ? fun ## l (x) : fun(x) )) diff --git a/test-tools/build-wasi-sdk/patches/wasi_sdk.patch b/test-tools/build-wasi-sdk/patches/wasi_sdk.patch deleted file mode 100644 index 0fc4caee..00000000 --- a/test-tools/build-wasi-sdk/patches/wasi_sdk.patch +++ /dev/null @@ -1,15 +0,0 @@ -diff --git a/version.sh b/version.sh -index 8e7c44c..ff0d3ba 100755 ---- a/version.sh -+++ b/version.sh -@@ -1,5 +1,6 @@ - #!/usr/bin/env bash --set -e --GIT_DESCR=$(git describe --long --candidates=999 --match='wasi-sdk-*' --dirty='+m' --abbrev=12) --GIT_PACKAGE_VERSION=$(echo $GIT_DESCR | perl -ne 'if(/^wasi-sdk-(\d+)-(\d+)-g([0-9a-f]{7,12})([+]m)?$/) { if($2 == 0) { print "$1.$2$4" } else { print "$1.$2g$3$4" } exit } else { print "could not parse git description"; exit 1 }';) --echo $GIT_PACKAGE_VERSION -+#set -e -+#GIT_DESCR=$(git describe --long --candidates=999 --match='wasi-sdk-*' --dirty='+m' --abbrev=12) -+#GIT_PACKAGE_VERSION=$(echo $GIT_DESCR | perl -ne 'if(/^wasi-sdk-(\d+)-(\d+)-g([0-9a-f]{7,12})([+]m)?$/) { if($2 == 0) { print "$1.$2$4" } else { print "$1.$2g$3$4" } exit } else { print "could not parse git description"; exit 1 }';) -+#echo $GIT_PACKAGE_VERSION -+echo wasi-sdk-13-eng diff --git a/test-tools/build-wasi-sdk/build_wasi_sdk.py b/test-tools/pick-up-emscripten-headers/collect_files.py similarity index 50% rename from test-tools/build-wasi-sdk/build_wasi_sdk.py rename to test-tools/pick-up-emscripten-headers/collect_files.py index a87cdef6..7e832145 100755 --- a/test-tools/build-wasi-sdk/build_wasi_sdk.py +++ b/test-tools/pick-up-emscripten-headers/collect_files.py @@ -9,68 +9,35 @@ The script operates on such directories and files |-- core | `-- deps | |-- emscripten -| `-- wasi-sdk -| `-- src -| |-- llvm-project -| `-- wasi-libc +|-- samples +| `-- workloads +| |-- include `-- test-tools - |-- build-wasi-sdk - | |-- build_wasi_sdk.py - | |-- include - | `-- patches - `-- wasi-sdk - |-- bin - |-- lib - `-- share - `-- wasi-sysroot + |-- pick-up-emscripten_headers + | |-- collect_files.py """ +import argparse import hashlib import logging import os import pathlib -import shlex import shutil -import subprocess import sys import tarfile import tempfile import urllib import urllib.request -logger = logging.getLogger("build_wasi_sdk") +logger = logging.getLogger("pick-up-emscripten-headers") external_repos = { - "config": { - "sha256": "302e5e7f3c4996976c58efde8b2f28f71d51357e784330eeed738e129300dc33", - "store_dir": "core/deps/wasi-sdk/src/config", - "strip_prefix": "config-191bcb948f7191c36eefe634336f5fc5c0c4c2be", - "url": "https://git.savannah.gnu.org/cgit/config.git/snapshot/config-191bcb948f7191c36eefe634336f5fc5c0c4c2be.tar.gz", - }, "emscripten": { - "sha256": "0904a65379aea3ea94087b8c12985b2fee48599b473e3bef914fec2e3941532d", + "sha256": "c5524755b785d8f4b83eb3214fdd3ac4b2e1b1a4644df4c63f06e5968f48f90e", "store_dir": "core/deps/emscripten", - "strip_prefix": "emscripten-2.0.28", - "url": "https://github.com/emscripten-core/emscripten/archive/refs/tags/2.0.28.tar.gz", - }, - "llvm-project": { - "sha256": "dc5169e51919f2817d06615285e9da6a804f0f881dc55d6247baa25aed3cc143", - "store_dir": "core/deps/wasi-sdk/src/llvm-project", - "strip_prefix": "llvm-project-34ff6a75f58377f32a5046a29f55c4c0e58bee9e", - "url": "https://github.com/llvm/llvm-project/archive/34ff6a75f58377f32a5046a29f55c4c0e58bee9e.tar.gz", - }, - "wasi-sdk": { - "sha256": "fc4fdb0e97b915241f32209492a7d0fab42c24216f87c1d5d75f46f7c70a553d", - "store_dir": "core/deps/wasi-sdk", - "strip_prefix": "wasi-sdk-1a953299860bbcc198ad8c12a21d1b2e2f738355", - "url": "https://github.com/WebAssembly/wasi-sdk/archive/1a953299860bbcc198ad8c12a21d1b2e2f738355.tar.gz", - }, - "wasi-libc": { - "sha256": "f6316ca9479d3463eb1c4f6a1d1f659bf15f67cb3c1e2e83d9d11f188dccd864", - "store_dir": "core/deps/wasi-sdk/src/wasi-libc", - "strip_prefix": "wasi-libc-a78cd329aec717f149934d7362f57050c9401f60", - "url": "https://github.com/WebAssembly/wasi-libc/archive/a78cd329aec717f149934d7362f57050c9401f60.tar.gz", - }, + "strip_prefix": "emscripten-3.0.0", + "url": "https://github.com/emscripten-core/emscripten/archive/refs/tags/3.0.0.tar.gz", + } } # TOOD: can we use headers from wasi-libc and clang directly ? @@ -111,25 +78,25 @@ def unpack(tar_file, strip_prefix, dest_dir): with tempfile.TemporaryDirectory() as tmp: with tarfile.open(tar_file) as tar: logger.debug(f"extract to {tmp}") + def is_within_directory(directory, target): - + abs_directory = os.path.abspath(directory) abs_target = os.path.abspath(target) - + prefix = os.path.commonprefix([abs_directory, abs_target]) - + return prefix == abs_directory - + def safe_extract(tar, path=".", members=None, *, numeric_owner=False): - + for member in tar.getmembers(): member_path = os.path.join(path, member.name) if not is_within_directory(path, member_path): raise Exception("Attempted Path Traversal in Tar File") - - tar.extractall(path, members, numeric_owner=numeric_owner) - - + + tar.extractall(path, members, numeric_owner=numeric_owner) + safe_extract(tar, tmp) strip_prefix_dir = ( @@ -160,12 +127,12 @@ def download_repo(name, root): download_flag = store_dir.joinpath("DOWNLOADED") if store_dir.exists() and download_flag.exists(): logger.info( - f"keep using '{store_dir.relative_to(root)}'. Or to remove it and try again" + f"bypass downloading '{store_dir.relative_to(root)}'. Or to remove it and try again if needs a new release" ) return True # download only when the target is neither existed nor broken - download_dir = pathlib.Path("/tmp/build_wasi_sdk/") + download_dir = pathlib.Path("/tmp/pick-up-emscripten-headers/") download_dir.mkdir(exist_ok=True) tar_name = pathlib.Path(external_repos[name]["url"]).name @@ -192,104 +159,67 @@ def download_repo(name, root): download_flag.touch() # leave download files in /tmp + logger.info(f"Has downloaed and stored in {store_dir.relative_to(root)}") return True -def run_patch(patch_file, cwd): - if not patch_file.exists(): - logger.error(f"{patch_file} not found") +def collect_headers(root, install_location): + if not install_location.exists(): + logger.error(f"{install_location} does not found") return False - with open(patch_file, "r") as f: - try: - PATCH_DRY_RUN_CMD = "patch -f -p1 --dry-run" - if subprocess.check_call(shlex.split(PATCH_DRY_RUN_CMD), stdin=f, cwd=cwd): - logger.error(f"patch dry-run {cwd} failed") - return False + install_flag = install_location.joinpath("INSTALLED").resolve() + if install_flag.exists(): + logger.info( + f"bypass downloading '{install_location}'. Or to remove it and try again if needs a new one" + ) + return True - PATCH_CMD = "patch -f -p1" - f.seek(0) - if subprocess.check_call(shlex.split(PATCH_CMD), stdin=f, cwd=cwd): - logger.error(f"patch {cwd} failed") - return False - except subprocess.CalledProcessError: - logger.error(f"patch {cwd} failed") - return False - return True - - -def build_and_install_wasi_sdk(root): - store_dir = root.joinpath(f'{external_repos["wasi-sdk"]["store_dir"]}').resolve() - if not store_dir.exists(): - logger.error(f"{store_dir} does not found") + emscripten_home = root.joinpath( + f'{external_repos["emscripten"]["store_dir"]}' + ).resolve() + if not emscripten_home.exists(): + logger.error(f"{emscripten_home} does not found") return False - # patch wasi-libc and wasi-sdk - patch_flag = store_dir.joinpath("PATCHED") - if not patch_flag.exists(): - if not run_patch( - root.joinpath("test-tools/build-wasi-sdk/patches/wasi_libc.patch"), - store_dir.joinpath("src/wasi-libc"), - ): - return False - - if not run_patch( - root.joinpath("test-tools/build-wasi-sdk/patches/wasi_sdk.patch"), store_dir - ): - return False - - patch_flag.touch() - else: - logger.info("bypass the patch phase") - - # build - build_flag = store_dir.joinpath("BUILDED") - if not build_flag.exists(): - BUILD_CMD = "make build" - if subprocess.check_call(shlex.split(BUILD_CMD), cwd=store_dir): - logger.error(f"build wasi-sdk failed") - return False - - build_flag.touch() - else: - logger.info("bypass the build phase") - - # install - install_flag = store_dir.joinpath("INSTALLED") - binary_path = root.joinpath("test-tools").resolve() - if not install_flag.exists(): - shutil.copytree( - str(store_dir.joinpath("build/install/opt").resolve()), - str(binary_path), - dirs_exist_ok=True, - ) - - # install headers - emscripten_headers = ( - root.joinpath(external_repos["emscripten"]["store_dir"]) - .joinpath("system") - .resolve() - ) - wasi_sysroot_headers = binary_path.joinpath( - "wasi-sdk/share/wasi-sysroot/include" - ).resolve() - for (src, dst) in emscripten_headers_src_dst: - src = emscripten_headers.joinpath(src) - dst = wasi_sysroot_headers.joinpath(dst) - dst.parent.mkdir(parents=True, exist_ok=True) - shutil.copy(src, dst) - - install_flag.touch() - else: - logger.info("bypass the install phase") + emscripten_headers = emscripten_home.joinpath("system").resolve() + for (src, dst) in emscripten_headers_src_dst: + src = emscripten_headers.joinpath(src) + dst = install_location.joinpath(dst) + dst.parent.mkdir(parents=True, exist_ok=True) + shutil.copy(src, dst) + install_flag.touch() + logger.info(f"Has installed in {install_location}") return True def main(): + parser = argparse.ArgumentParser( + description="collect headers from emscripten for workload compilation" + ) + parser.add_argument( + "--install", + type=str, + required=True, + help="identify installation location", + ) + parser.add_argument( + "--loglevel", + type=str, + default="INFO", + choices=[ + "ERROR", + "WARNING", + "INFO", + ], + help="the logging level", + ) + options = parser.parse_args() + console = logging.StreamHandler() console.setFormatter(logging.Formatter("%(asctime)s - %(message)s")) - logger.setLevel(logging.INFO) + logger.setLevel(getattr(logging, options.loglevel)) logger.addHandler(console) logger.propagate = False @@ -305,12 +235,9 @@ def main(): if not download_repo(repo, root): return False - # build wasi_sdk and install - if not build_and_install_wasi_sdk(root): + if not collect_headers(root, pathlib.Path(options.install)): return False - # TODO install headers from emscripten - return True diff --git a/test-tools/wamr-ide/WASM-Toolchain/Docker/Dockerfile b/test-tools/wamr-ide/WASM-Toolchain/Docker/Dockerfile index f96a2261..6ca21094 100644 --- a/test-tools/wamr-ide/WASM-Toolchain/Docker/Dockerfile +++ b/test-tools/wamr-ide/WASM-Toolchain/Docker/Dockerfile @@ -25,17 +25,17 @@ RUN wget --progress=dot:giga https://github.com/Kitware/CMake/releases/download/ # - wamr-sdk ## - download wasi-sdk with wget and set up to /opt/wasi-sdk -RUN wget --progress=dot:giga https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-14/wasi-sdk-14.0-linux.tar.gz \ - && tar -zxvf wasi-sdk-14.0-linux.tar.gz \ - && mv wasi-sdk-14.0 /opt/wasi-sdk/ \ - && rm -f wasi-sdk-14.0-linux.tar.gz +RUN wget --progress=dot:giga https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-19/wasi-sdk-19.0-linux.tar.gz \ + && tar -zxvf wasi-sdk-*-linux.tar.gz \ + && mv wasi-sdk-19.0 /opt/wasi-sdk/ \ + && rm -f wasi-sdk-*-linux.tar.gz ## - clone wamr repo -RUN git clone -b main --depth=1 https://github.com/bytecodealliance/wasm-micro-runtime.git +RUN git clone -b main --depth=1 https://github.com/bytecodealliance/wasm-micro-runtime.git WORKDIR /root/wasm-micro-runtime/wamr-compiler RUN ./build_llvm.sh \ - && mkdir build + && mkdir build WORKDIR /root/wasm-micro-runtime/wamr-compiler/build RUN cmake .. \ diff --git a/tests/wamr-test-suites/test_wamr.sh b/tests/wamr-test-suites/test_wamr.sh index 00797b31..bc6df908 100755 --- a/tests/wamr-test-suites/test_wamr.sh +++ b/tests/wamr-test-suites/test_wamr.sh @@ -360,16 +360,16 @@ function spec_test() exit 1 ;; esac - if [ ! -f /tmp/wabt-1.0.29-${WABT_PLATFORM}.tar.gz ]; then + if [ ! -f /tmp/wabt-1.0.31-${WABT_PLATFORM}.tar.gz ]; then wget \ - https://github.com/WebAssembly/wabt/releases/download/1.0.29/wabt-1.0.29-${WABT_PLATFORM}.tar.gz \ + https://github.com/WebAssembly/wabt/releases/download/1.0.31/wabt-1.0.31-${WABT_PLATFORM}.tar.gz \ -P /tmp fi cd /tmp \ - && tar zxf wabt-1.0.29-${WABT_PLATFORM}.tar.gz \ + && tar zxf wabt-1.0.31-${WABT_PLATFORM}.tar.gz \ && mkdir -p ${WORK_DIR}/wabt/out/gcc/Release/ \ - && install wabt-1.0.29/bin/wa* ${WORK_DIR}/wabt/out/gcc/Release/ \ + && install wabt-1.0.31/bin/wa* ${WORK_DIR}/wabt/out/gcc/Release/ \ && cd - fi else @@ -429,7 +429,7 @@ function spec_test() fi # set the current running target - ARGS_FOR_SPEC_TEST+="-m ${TARGET} " + ARGS_FOR_SPEC_TEST+="-m ${TARGET} " # require warmc only in aot mode if [[ $1 == 'aot' ]]; then From edee2eb956d228a063cda38b29f222ed82d9e78e Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Thu, 2 Feb 2023 13:06:30 +0800 Subject: [PATCH 11/33] Loosen the wasi abi compatibility check in loader (#1932) Change an error to warning when checking wasi abi compatibility in loader, for rust case below: #[no_mangle] pub extern "C" fn main() { println!("foo"); } compile it with `cargo build --target wasm32-wasi`, a wasm file is generated with wasi apis imported and a "void main(void)" function exported. Other runtime e.g. wasmtime allows to load it and execute the main function with `--invoke` option. --- core/iwasm/interpreter/wasm_loader.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index f60f9efb..7235a39f 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -4151,10 +4151,8 @@ check_wasi_abi_compatibility(const WASMModule *module, /* should have one at least */ if (module->import_wasi_api && !start && !initialize) { - set_error_buf( - error_buf, error_buf_size, - "a module with WASI apis must be either a command or a reactor"); - return false; + LOG_WARNING("warning: a module with WASI apis should be either " + "a command or a reactor"); } /* From 7bb78dc260cb5465906731a0bb7192738b43b66c Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Thu, 2 Feb 2023 15:23:44 +0800 Subject: [PATCH 12/33] Remove fast jit macro in enum WASMExceptionID (#1933) The definitions `enum WASMExceptionID` in the compilation of wamrc and the compilation of Fast JIT are different, since the latter enables the Fast JIT macro while the former doesn't. This causes that the exception ID in AOT file generated by wamrc may be different from iwasm binary compiled with Fast JIT enabled, and may result in unexpected behavior. Remove the macro control to resolve it. --- core/iwasm/common/wasm_runtime_common.c | 2 -- core/iwasm/interpreter/wasm_runtime.h | 2 -- 2 files changed, 4 deletions(-) diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index db35b01d..0cd2af3f 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -2235,9 +2235,7 @@ static const char *exception_msgs[] = { "wasm auxiliary stack underflow", /* EXCE_AUX_STACK_UNDERFLOW */ "out of bounds table access", /* EXCE_OUT_OF_BOUNDS_TABLE_ACCESS */ "wasm operand stack overflow", /* EXCE_OPERAND_STACK_OVERFLOW */ -#if WASM_ENABLE_FAST_JIT != 0 "failed to compile fast jit function", /* EXCE_FAILED_TO_COMPILE_FAST_JIT_FUNC */ -#endif "", /* EXCE_ALREADY_THROWN */ }; /* clang-format on */ diff --git a/core/iwasm/interpreter/wasm_runtime.h b/core/iwasm/interpreter/wasm_runtime.h index 89c5bbee..3ede9bf4 100644 --- a/core/iwasm/interpreter/wasm_runtime.h +++ b/core/iwasm/interpreter/wasm_runtime.h @@ -63,9 +63,7 @@ typedef enum WASMExceptionID { EXCE_AUX_STACK_UNDERFLOW, EXCE_OUT_OF_BOUNDS_TABLE_ACCESS, EXCE_OPERAND_STACK_OVERFLOW, -#if WASM_ENABLE_FAST_JIT != 0 EXCE_FAILED_TO_COMPILE_FAST_JIT_FUNC, -#endif EXCE_ALREADY_THROWN, EXCE_NUM, } WASMExceptionID; From 40a14b51c5fd3c5b547995f1e06b11a29bbc14b2 Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Thu, 2 Feb 2023 18:16:01 +0800 Subject: [PATCH 13/33] Enable running mode control for runtime and module instance (#1923) Enable setting running mode when executing a wasm bytecode file - Four running modes are supported: interpreter, fast-jit, llvm-jit and multi-tier-jit - Add APIs to set/get the default running mode of the runtime - Add APIs to set/get the running mode of a wasm module instance - Add running mode options for iwasm command line tool And add size/opt level options for LLVM JIT --- core/iwasm/common/wasm_runtime_common.c | 106 ++++++++++ core/iwasm/common/wasm_runtime_common.h | 37 ++++ core/iwasm/fast-jit/jit_codecache.c | 30 ++- core/iwasm/fast-jit/jit_compiler.c | 10 +- core/iwasm/include/wasm_export.h | 71 ++++++- core/iwasm/interpreter/wasm.h | 42 +++- core/iwasm/interpreter/wasm_interp_classic.c | 79 ++++--- core/iwasm/interpreter/wasm_loader.c | 18 +- core/iwasm/interpreter/wasm_mini_loader.c | 16 +- core/iwasm/interpreter/wasm_runtime.c | 205 +++++++++++++++++-- core/iwasm/interpreter/wasm_runtime.h | 11 +- product-mini/platforms/posix/main.c | 80 ++++++++ product-mini/platforms/windows/main.c | 79 +++++++ 13 files changed, 696 insertions(+), 88 deletions(-) diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index 0cd2af3f..139c050a 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -128,6 +128,12 @@ runtime_malloc(uint64 size, WASMModuleInstanceCommon *module_inst, static JitCompOptions jit_options = { 0 }; #endif +#if WASM_ENABLE_JIT != 0 +static LLVMJITOptions llvm_jit_options = { 3, 3 }; +#endif + +static RunningMode runtime_running_mode = Mode_Default; + #ifdef OS_ENABLE_HW_BOUND_CHECK /* The exec_env of thread local storage, set before calling function and used in signal handler, as we cannot get it from the argument @@ -514,6 +520,20 @@ wasm_runtime_destroy() wasm_runtime_memory_destroy(); } +RunningMode +wasm_runtime_get_default_running_mode(void) +{ + return runtime_running_mode; +} + +#if WASM_ENABLE_JIT != 0 +LLVMJITOptions +wasm_runtime_get_llvm_jit_options(void) +{ + return llvm_jit_options; +} +#endif + bool wasm_runtime_full_init(RuntimeInitArgs *init_args) { @@ -521,10 +541,20 @@ wasm_runtime_full_init(RuntimeInitArgs *init_args) &init_args->mem_alloc_option)) return false; + if (!wasm_runtime_set_default_running_mode(init_args->running_mode)) { + wasm_runtime_memory_destroy(); + return false; + } + #if WASM_ENABLE_FAST_JIT != 0 jit_options.code_cache_size = init_args->fast_jit_code_cache_size; #endif +#if WASM_ENABLE_JIT != 0 + llvm_jit_options.size_level = init_args->llvm_jit_size_level; + llvm_jit_options.opt_level = init_args->llvm_jit_opt_level; +#endif + if (!wasm_runtime_env_init()) { wasm_runtime_memory_destroy(); return false; @@ -554,6 +584,47 @@ wasm_runtime_full_init(RuntimeInitArgs *init_args) return true; } +bool +wasm_runtime_is_running_mode_supported(RunningMode running_mode) +{ + if (running_mode == Mode_Default) { + return true; + } + else if (running_mode == Mode_Interp) { +#if WASM_ENABLE_INTERP != 0 + return true; +#endif + } + else if (running_mode == Mode_Fast_JIT) { +#if WASM_ENABLE_FAST_JIT != 0 + return true; +#endif + } + else if (running_mode == Mode_LLVM_JIT) { +#if WASM_ENABLE_JIT != 0 + return true; +#endif + } + else if (running_mode == Mode_Multi_Tier_JIT) { +#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \ + && WASM_ENABLE_LAZY_JIT != 0 + return true; +#endif + } + + return false; +} + +bool +wasm_runtime_set_default_running_mode(RunningMode running_mode) +{ + if (wasm_runtime_is_running_mode_supported(running_mode)) { + runtime_running_mode = running_mode; + return true; + } + return false; +} + PackageType get_package_type(const uint8 *buf, uint32 size) { @@ -1171,6 +1242,41 @@ wasm_runtime_deinstantiate_internal(WASMModuleInstanceCommon *module_inst, #endif } +bool +wasm_runtime_set_running_mode(wasm_module_inst_t module_inst, + RunningMode running_mode) +{ +#if WASM_ENABLE_AOT != 0 + if (module_inst->module_type == Wasm_Module_AoT) + return true; +#endif + +#if WASM_ENABLE_INTERP != 0 + if (module_inst->module_type == Wasm_Module_Bytecode) { + WASMModuleInstance *module_inst_interp = + (WASMModuleInstance *)module_inst; + + return wasm_set_running_mode(module_inst_interp, running_mode); + } +#endif + + return false; +} + +RunningMode +wasm_runtime_get_running_mode(wasm_module_inst_t module_inst) +{ +#if WASM_ENABLE_INTERP != 0 + if (module_inst->module_type == Wasm_Module_Bytecode) { + WASMModuleInstance *module_inst_interp = + (WASMModuleInstance *)module_inst; + return module_inst_interp->e->running_mode; + } +#endif + + return Mode_Default; +} + void wasm_runtime_deinstantiate(WASMModuleInstanceCommon *module_inst) { diff --git a/core/iwasm/common/wasm_runtime_common.h b/core/iwasm/common/wasm_runtime_common.h index 3e7f3725..a70c9fb6 100644 --- a/core/iwasm/common/wasm_runtime_common.h +++ b/core/iwasm/common/wasm_runtime_common.h @@ -25,6 +25,9 @@ extern "C" { #endif +/* Internal use for setting default running mode */ +#define Mode_Default 0 + #if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS != 0 #define PUT_I64_TO_ADDR(addr, value) \ @@ -413,6 +416,13 @@ typedef struct wasm_frame_t { const char *func_name_wp; } WASMCApiFrame; +#ifdef WASM_ENABLE_JIT +typedef struct LLVMJITOptions { + uint32 opt_level; + uint32 size_level; +} LLVMJITOptions; +#endif + #ifdef OS_ENABLE_HW_BOUND_CHECK /* Signal info passing to interp/aot signal handler */ typedef struct WASMSignalInfo { @@ -437,10 +447,28 @@ wasm_runtime_get_exec_env_tls(void); WASM_RUNTIME_API_EXTERN bool wasm_runtime_init(void); +/* Internal API */ +RunningMode +wasm_runtime_get_default_running_mode(void); + +#if WASM_ENABLE_JIT != 0 +/* Internal API */ +LLVMJITOptions +wasm_runtime_get_llvm_jit_options(void); +#endif + /* See wasm_export.h for description */ WASM_RUNTIME_API_EXTERN bool wasm_runtime_full_init(RuntimeInitArgs *init_args); +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN bool +wasm_runtime_is_running_mode_supported(RunningMode running_mode); + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN bool +wasm_runtime_set_default_running_mode(RunningMode running_mode); + /* See wasm_export.h for description */ WASM_RUNTIME_API_EXTERN void wasm_runtime_destroy(void); @@ -484,6 +512,15 @@ wasm_runtime_instantiate(WASMModuleCommon *module, uint32 stack_size, uint32 heap_size, char *error_buf, uint32 error_buf_size); +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN bool +wasm_runtime_set_running_mode(wasm_module_inst_t module_inst, + RunningMode running_mode); + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN RunningMode +wasm_runtime_get_running_mode(wasm_module_inst_t module_inst); + /* See wasm_export.h for description */ WASM_RUNTIME_API_EXTERN void wasm_runtime_deinstantiate(WASMModuleInstanceCommon *module_inst); diff --git a/core/iwasm/fast-jit/jit_codecache.c b/core/iwasm/fast-jit/jit_codecache.c index 66c2d033..73a034f3 100644 --- a/core/iwasm/fast-jit/jit_codecache.c +++ b/core/iwasm/fast-jit/jit_codecache.c @@ -56,9 +56,31 @@ jit_code_cache_free(void *ptr) bool jit_pass_register_jitted_code(JitCompContext *cc) { - uint32 jit_func_idx = - cc->cur_wasm_func_idx - cc->cur_wasm_module->import_function_count; - cc->cur_wasm_module->fast_jit_func_ptrs[jit_func_idx] = - cc->cur_wasm_func->fast_jit_jitted_code = cc->jitted_addr_begin; + WASMModuleInstance *instance; + WASMModule *module = cc->cur_wasm_module; + WASMFunction *func = cc->cur_wasm_func; + uint32 jit_func_idx = cc->cur_wasm_func_idx - module->import_function_count; + +#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \ + && WASM_ENABLE_LAZY_JIT != 0 + os_mutex_lock(&module->instance_list_lock); +#endif + + module->fast_jit_func_ptrs[jit_func_idx] = func->fast_jit_jitted_code = + cc->jitted_addr_begin; + +#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \ + && WASM_ENABLE_LAZY_JIT != 0 + instance = module->instance_list; + while (instance) { + if (instance->e->running_mode == Mode_Fast_JIT) + instance->fast_jit_func_ptrs[jit_func_idx] = cc->jitted_addr_begin; + instance = instance->e->next; + } + + os_mutex_unlock(&module->instance_list_lock); +#else + (void)instance; +#endif return true; } diff --git a/core/iwasm/fast-jit/jit_compiler.c b/core/iwasm/fast-jit/jit_compiler.c index bba4566c..958d0e98 100644 --- a/core/iwasm/fast-jit/jit_compiler.c +++ b/core/iwasm/fast-jit/jit_compiler.c @@ -254,6 +254,8 @@ jit_compiler_set_call_to_fast_jit(WASMModule *module, uint32 func_idx) func_ptr = jit_codegen_compile_call_to_fast_jit(module, func_idx); if (func_ptr) { + uint32 i = func_idx - module->import_function_count; + module->functions[i]->call_to_fast_jit_from_llvm_jit = func_ptr; jit_compiler_set_llvm_jit_func_ptr(module, func_idx, func_ptr); } @@ -267,12 +269,14 @@ jit_compiler_set_llvm_jit_func_ptr(WASMModule *module, uint32 func_idx, WASMModuleInstance *instance; uint32 i = func_idx - module->import_function_count; - module->functions[i]->llvm_jit_func_ptr = module->func_ptrs[i] = func_ptr; - os_mutex_lock(&module->instance_list_lock); + + module->func_ptrs[i] = func_ptr; + instance = module->instance_list; while (instance) { - instance->func_ptrs[func_idx] = func_ptr; + if (instance->e->running_mode == Mode_Multi_Tier_JIT) + instance->func_ptrs[func_idx] = func_ptr; instance = instance->e->next; } os_mutex_unlock(&module->instance_list_lock); diff --git a/core/iwasm/include/wasm_export.h b/core/iwasm/include/wasm_export.h index 2d5e8515..161a4905 100644 --- a/core/iwasm/include/wasm_export.h +++ b/core/iwasm/include/wasm_export.h @@ -131,6 +131,14 @@ typedef struct mem_alloc_info_t { uint32_t highmark_size; } mem_alloc_info_t; +/* Running mode of runtime and module instance*/ +typedef enum RunningMode { + Mode_Interp = 1, + Mode_Fast_JIT, + Mode_LLVM_JIT, + Mode_Multi_Tier_JIT, +} RunningMode; + /* WASM runtime initialize arguments */ typedef struct RuntimeInitArgs { mem_alloc_type_t mem_alloc_type; @@ -152,6 +160,13 @@ typedef struct RuntimeInitArgs { /* Fast JIT code cache size */ uint32_t fast_jit_code_cache_size; + + /* Default running mode of the runtime */ + RunningMode running_mode; + + /* LLVM JIT opt and size level */ + uint32_t llvm_jit_opt_level; + uint32_t llvm_jit_size_level; } RuntimeInitArgs; #ifndef WASM_VALKIND_T_DEFINED @@ -195,9 +210,9 @@ WASM_RUNTIME_API_EXTERN bool wasm_runtime_init(void); /** - * Initialize the WASM runtime environment, and also initialize - * the memory allocator and register native symbols, which are specified - * with init arguments + * Initialize the WASM runtime environment, WASM running mode, + * and also initialize the memory allocator and register native symbols, + * which are specified with init arguments * * @param init_args specifies the init arguments * @@ -206,6 +221,28 @@ wasm_runtime_init(void); WASM_RUNTIME_API_EXTERN bool wasm_runtime_full_init(RuntimeInitArgs *init_args); +/** + * Query whether a certain running mode is supported for the runtime + * + * @param running_mode the running mode to query + * + * @return true if this running mode is supported, false otherwise + */ +WASM_RUNTIME_API_EXTERN bool +wasm_runtime_is_running_mode_supported(RunningMode running_mode); + +/** + * Set the default running mode for the runtime. It is inherited + * to set the running mode of a module instance when it is instantiated, + * and can be changed by calling wasm_runtime_set_running_mode + * + * @param running_mode the running mode to set + * + * @return true if success, false otherwise + */ +WASM_RUNTIME_API_EXTERN bool +wasm_runtime_set_default_running_mode(RunningMode running_mode); + /** * Destroy the WASM runtime environment. */ @@ -450,6 +487,34 @@ wasm_runtime_instantiate(const wasm_module_t module, uint32_t stack_size, uint32_t heap_size, char *error_buf, uint32_t error_buf_size); +/** + * Set the running mode of a WASM module instance, override the + * default running mode of the runtime. Note that it only makes sense when + * the input is a wasm bytecode file: for the AOT file, runtime always runs + * it with AOT engine, and this function always returns true. + * + * @param module_inst the WASM module instance to set running mode + * @param running_mode the running mode to set + * + * @return true if success, false otherwise + */ +WASM_RUNTIME_API_EXTERN bool +wasm_runtime_set_running_mode(wasm_module_inst_t module_inst, + RunningMode running_mode); + +/** + * Get the running mode of a WASM module instance, if no running mode + * is explicitly set the default running mode of runtime will + * be used and returned. Note that it only makes sense when the input is a + * wasm bytecode file: for the AOT file, this function always returns 0. + * + * @param module_inst the WASM module instance to query for running mode + * + * @return the running mode this module instance currently use + */ +WASM_RUNTIME_API_EXTERN RunningMode +wasm_runtime_get_running_mode(wasm_module_inst_t module_inst); + /** * Deinstantiate a WASM module instance, destroy the resources. * diff --git a/core/iwasm/interpreter/wasm.h b/core/iwasm/interpreter/wasm.h index 7efa6d5f..c6aad29a 100644 --- a/core/iwasm/interpreter/wasm.h +++ b/core/iwasm/interpreter/wasm.h @@ -278,9 +278,14 @@ struct WASMFunction { #endif #if WASM_ENABLE_FAST_JIT != 0 + /* The compiled fast jit jitted code block of this function */ void *fast_jit_jitted_code; #if WASM_ENABLE_JIT != 0 && WASM_ENABLE_LAZY_JIT != 0 + /* The compiled llvm jit func ptr of this function */ void *llvm_jit_func_ptr; + /* Code block to call fast jit jitted code of this function + from the llvm jit jitted code */ + void *call_to_fast_jit_from_llvm_jit; #endif #endif }; @@ -512,8 +517,7 @@ struct WASMModule { * List of instances referred to this module. When source debugging * feature is enabled, the debugger may modify the code section of * the module, so we need to report a warning if user create several - * instances based on the same module. Sub instances created by - * lib-pthread or spawn API won't be added into the list. + * instances based on the same module. * * Also add the instance to the list for Fast JIT to LLVM JIT * tier-up, since we need to lazily update the LLVM func pointers @@ -533,7 +537,22 @@ struct WASMModule { #endif #if WASM_ENABLE_FAST_JIT != 0 - /* func pointers of Fast JITed (un-imported) functions */ + /** + * func pointers of Fast JITed (un-imported) functions + * for non Multi-Tier JIT mode: + * (1) when lazy jit is disabled, each pointer is set to the compiled + * fast jit jitted code + * (2) when lazy jit is enabled, each pointer is firstly inited as + * jit_global->compile_fast_jit_and_then_call, and then set to the + * compiled fast jit jitted code when it is called (the stub will + * compile the jit function and then update itself) + * for Multi-Tier JIT mode: + * each pointer is firstly inited as compile_fast_jit_and_then_call, + * and then set to the compiled fast jit jitted code when it is called, + * and when the llvm jit func ptr of the same function is compiled, it + * will be set to call_to_llvm_jit_from_fast_jit of this function type + * (tier-up from fast-jit to llvm-jit) + */ void **fast_jit_func_ptrs; /* locks for Fast JIT lazy compilation */ korp_mutex fast_jit_thread_locks[WASM_ORC_JIT_BACKEND_THREAD_NUM]; @@ -543,7 +562,16 @@ struct WASMModule { #if WASM_ENABLE_JIT != 0 struct AOTCompData *comp_data; struct AOTCompContext *comp_ctx; - /* func pointers of LLVM JITed (un-imported) functions */ + /** + * func pointers of LLVM JITed (un-imported) functions + * for non Multi-Tier JIT mode: + * each pointer is set to the lookuped llvm jit func ptr, note that it + * is a stub and will trigger the actual compilation when it is called + * for Multi-Tier JIT mode: + * each pointer is inited as call_to_fast_jit code block, when the llvm + * jit func ptr is actually compiled, it is set to the compiled llvm jit + * func ptr + */ void **func_ptrs; /* whether the func pointers are compiled */ bool *func_ptrs_compiled; @@ -568,6 +596,12 @@ struct WASMModule { korp_tid llvm_jit_init_thread; /* whether the llvm jit is initialized */ bool llvm_jit_inited; + /* Whether to enable llvm jit compilation: + it is set to true only when there is a module instance starts to + run with running mode Mode_LLVM_JIT or Mode_Multi_Tier_JIT, + since no need to enable llvm jit compilation for Mode_Interp and + Mode_Fast_JIT, so as to improve performance for them */ + bool enable_llvm_jit_compilation; #endif }; diff --git a/core/iwasm/interpreter/wasm_interp_classic.c b/core/iwasm/interpreter/wasm_interp_classic.c index 3c43dcdc..c8ef4f27 100644 --- a/core/iwasm/interpreter/wasm_interp_classic.c +++ b/core/iwasm/interpreter/wasm_interp_classic.c @@ -4195,58 +4195,51 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env, } } else { -#if WASM_ENABLE_LAZY_JIT != 0 + RunningMode running_mode = + wasm_runtime_get_running_mode((wasm_module_inst_t)module_inst); - /* Fast JIT to LLVM JIT tier-up is enabled */ -#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 - /* Fast JIT and LLVM JIT are both enabled, call llvm jit function - if it is compiled, else call fast jit function */ - uint32 func_idx = (uint32)(function - module_inst->e->functions); - if (module_inst->module->func_ptrs_compiled - [func_idx - module_inst->module->import_function_count]) { + if (running_mode == Mode_Interp) { + wasm_interp_call_func_bytecode(module_inst, exec_env, function, + frame); + } +#if WASM_ENABLE_FAST_JIT != 0 + else if (running_mode == Mode_Fast_JIT) { + fast_jit_call_func_bytecode(module_inst, exec_env, function, frame); + } +#endif +#if WASM_ENABLE_JIT != 0 + else if (running_mode == Mode_LLVM_JIT) { llvm_jit_call_func_bytecode(module_inst, exec_env, function, argc, argv); /* For llvm jit, the results have been stored in argv, no need to copy them from stack frame again */ copy_argv_from_frame = false; } - else { - fast_jit_call_func_bytecode(module_inst, exec_env, function, frame); +#endif +#if WASM_ENABLE_LAZY_JIT != 0 && WASM_ENABLE_FAST_JIT != 0 \ + && WASM_ENABLE_JIT != 0 + else if (running_mode == Mode_Multi_Tier_JIT) { + /* Tier-up from Fast JIT to LLVM JIT, call llvm jit function + if it is compiled, else call fast jit function */ + uint32 func_idx = (uint32)(function - module_inst->e->functions); + if (module_inst->module->func_ptrs_compiled + [func_idx - module_inst->module->import_function_count]) { + llvm_jit_call_func_bytecode(module_inst, exec_env, function, + argc, argv); + /* For llvm jit, the results have been stored in argv, + no need to copy them from stack frame again */ + copy_argv_from_frame = false; + } + else { + fast_jit_call_func_bytecode(module_inst, exec_env, function, + frame); + } } -#elif WASM_ENABLE_JIT != 0 - /* Only LLVM JIT is enabled */ - llvm_jit_call_func_bytecode(module_inst, exec_env, function, argc, - argv); - /* For llvm jit, the results have been stored in argv, - no need to copy them from stack frame again */ - copy_argv_from_frame = false; -#elif WASM_ENABLE_FAST_JIT != 0 - /* Only Fast JIT is enabled */ - fast_jit_call_func_bytecode(module_inst, exec_env, function, frame); -#else - /* Both Fast JIT and LLVM JIT are disabled */ - wasm_interp_call_func_bytecode(module_inst, exec_env, function, frame); #endif - -#else /* else of WASM_ENABLE_LAZY_JIT != 0 */ - - /* Fast JIT to LLVM JIT tier-up is enabled */ -#if WASM_ENABLE_JIT != 0 - /* LLVM JIT is enabled */ - llvm_jit_call_func_bytecode(module_inst, exec_env, function, argc, - argv); - /* For llvm jit, the results have been stored in argv, - no need to copy them from stack frame again */ - copy_argv_from_frame = false; -#elif WASM_ENABLE_FAST_JIT != 0 - /* Fast JIT is enabled */ - fast_jit_call_func_bytecode(module_inst, exec_env, function, frame); -#else - /* Both Fast JIT and LLVM JIT are disabled */ - wasm_interp_call_func_bytecode(module_inst, exec_env, function, frame); -#endif - -#endif /* end of WASM_ENABLE_LAZY_JIT != 0 */ + else { + /* There should always be a supported running mode selected */ + bh_assert(0); + } (void)wasm_interp_call_func_bytecode; #if WASM_ENABLE_FAST_JIT != 0 diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index 7235a39f..4c6c6aaa 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -2989,6 +2989,7 @@ static bool init_llvm_jit_functions_stage1(WASMModule *module, char *error_buf, uint32 error_buf_size) { + LLVMJITOptions llvm_jit_options = wasm_runtime_get_llvm_jit_options(); AOTCompOption option = { 0 }; char *aot_last_error; uint64 size; @@ -3027,8 +3028,11 @@ init_llvm_jit_functions_stage1(WASMModule *module, char *error_buf, } option.is_jit_mode = true; - option.opt_level = 3; - option.size_level = 3; + + llvm_jit_options = wasm_runtime_get_llvm_jit_options(); + option.opt_level = llvm_jit_options.opt_level; + option.size_level = llvm_jit_options.size_level; + #if WASM_ENABLE_BULK_MEMORY != 0 option.enable_bulk_memory = true; #endif @@ -3112,6 +3116,8 @@ init_llvm_jit_functions_stage2(WASMModule *module, char *error_buf, module->func_ptrs[i] = (void *)func_addr; #if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_LAZY_JIT != 0 + module->functions[i]->llvm_jit_func_ptr = (void *)func_addr; + if (module->orcjit_stop_compiling) return false; #endif @@ -3202,9 +3208,9 @@ orcjit_thread_callback(void *arg) /* Wait until init_llvm_jit_functions_stage2 finishes */ os_mutex_lock(&module->tierup_wait_lock); - while (!module->llvm_jit_inited) { + while (!(module->llvm_jit_inited && module->enable_llvm_jit_compilation)) { os_cond_reltimedwait(&module->tierup_wait_cond, - &module->tierup_wait_lock, 10); + &module->tierup_wait_lock, 10000); if (module->orcjit_stop_compiling) { /* init_llvm_jit_functions_stage2 failed */ os_mutex_unlock(&module->tierup_wait_lock); @@ -4300,9 +4306,9 @@ wasm_loader_unload(WASMModule *module) module->functions[i]->fast_jit_jitted_code); } #if WASM_ENABLE_JIT != 0 && WASM_ENABLE_LAZY_JIT != 0 - if (module->functions[i]->llvm_jit_func_ptr) { + if (module->functions[i]->call_to_fast_jit_from_llvm_jit) { jit_code_cache_free( - module->functions[i]->llvm_jit_func_ptr); + module->functions[i]->call_to_fast_jit_from_llvm_jit); } #endif #endif diff --git a/core/iwasm/interpreter/wasm_mini_loader.c b/core/iwasm/interpreter/wasm_mini_loader.c index 815dffa0..6a5d83ad 100644 --- a/core/iwasm/interpreter/wasm_mini_loader.c +++ b/core/iwasm/interpreter/wasm_mini_loader.c @@ -1835,6 +1835,7 @@ static bool init_llvm_jit_functions_stage1(WASMModule *module, char *error_buf, uint32 error_buf_size) { + LLVMJITOptions llvm_jit_options = wasm_runtime_get_llvm_jit_options(); AOTCompOption option = { 0 }; char *aot_last_error; uint64 size; @@ -1873,8 +1874,9 @@ init_llvm_jit_functions_stage1(WASMModule *module, char *error_buf, } option.is_jit_mode = true; - option.opt_level = 3; - option.size_level = 3; + option.opt_level = llvm_jit_options.opt_level; + option.size_level = llvm_jit_options.size_level; + #if WASM_ENABLE_BULK_MEMORY != 0 option.enable_bulk_memory = true; #endif @@ -1960,6 +1962,8 @@ init_llvm_jit_functions_stage2(WASMModule *module, char *error_buf, module->func_ptrs[i] = (void *)func_addr; #if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_LAZY_JIT != 0 + module->functions[i]->llvm_jit_func_ptr = (void *)func_addr; + if (module->orcjit_stop_compiling) return false; #endif @@ -2050,9 +2054,9 @@ orcjit_thread_callback(void *arg) /* Wait until init_llvm_jit_functions_stage2 finishes */ os_mutex_lock(&module->tierup_wait_lock); - while (!module->llvm_jit_inited) { + while (!(module->llvm_jit_inited && module->enable_llvm_jit_compilation)) { os_cond_reltimedwait(&module->tierup_wait_cond, - &module->tierup_wait_lock, 10); + &module->tierup_wait_lock, 10000); if (module->orcjit_stop_compiling) { /* init_llvm_jit_functions_stage2 failed */ os_mutex_unlock(&module->tierup_wait_lock); @@ -2998,9 +3002,9 @@ wasm_loader_unload(WASMModule *module) module->functions[i]->fast_jit_jitted_code); } #if WASM_ENABLE_JIT != 0 && WASM_ENABLE_LAZY_JIT != 0 - if (module->functions[i]->llvm_jit_func_ptr) { + if (module->functions[i]->call_to_fast_jit_from_llvm_jit) { jit_code_cache_free( - module->functions[i]->llvm_jit_func_ptr); + module->functions[i]->call_to_fast_jit_from_llvm_jit); } #endif #endif diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index baded7aa..45356207 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -737,13 +737,12 @@ functions_instantiate(const WASMModule *module, WASMModuleInstance *module_inst, function++; } + bh_assert((uint32)(function - functions) == function_count); #if WASM_ENABLE_FAST_JIT != 0 module_inst->fast_jit_func_ptrs = module->fast_jit_func_ptrs; #endif - bh_assert((uint32)(function - functions) == function_count); - (void)module_inst; return functions; } @@ -1288,9 +1287,8 @@ init_func_ptrs(WASMModuleInstance *module_inst, WASMModule *module, *func_ptrs = import_func->func_ptr_linked; } - /* Set defined function pointers */ - bh_memcpy_s(func_ptrs, sizeof(void *) * module->function_count, - module->func_ptrs, sizeof(void *) * module->function_count); + /* The defined function pointers will be set in + wasm_runtime_set_running_mode, no need to set them here */ return true; } #endif /* end of WASM_ENABLE_JIT != 0 */ @@ -1336,6 +1334,173 @@ init_func_type_indexes(WASMModuleInstance *module_inst, char *error_buf, } #endif /* end of WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0 */ +static bool +set_running_mode(WASMModuleInstance *module_inst, RunningMode running_mode, + bool first_time_set) +{ + WASMModule *module = module_inst->module; + + if (running_mode == Mode_Default) { +#if WASM_ENABLE_FAST_JIT == 0 && WASM_ENABLE_JIT == 0 + running_mode = Mode_Interp; +#elif WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT == 0 + running_mode = Mode_Fast_JIT; +#elif WASM_ENABLE_FAST_JIT == 0 && WASM_ENABLE_JIT != 0 + running_mode = Mode_LLVM_JIT; +#else /* WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 */ +#if WASM_ENABLE_LAZY_JIT == 0 + running_mode = Mode_LLVM_JIT; +#else + running_mode = Mode_Multi_Tier_JIT; +#endif +#endif + } + + if (!wasm_runtime_is_running_mode_supported(running_mode)) + return false; + +#if !(WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \ + && WASM_ENABLE_LAZY_JIT != 0) /* No possible multi-tier JIT */ + module_inst->e->running_mode = running_mode; + + if (running_mode == Mode_Interp) { + /* Do nothing for Mode_Interp */ + } + else if (running_mode == Mode_Fast_JIT) { + /* Do nothing for Mode_Fast_JIT since + module_inst->fast_jit_func_ptrs is same as + module->fast_jit_func_ptrs */ + } +#if WASM_ENABLE_JIT != 0 + else if (running_mode == Mode_LLVM_JIT) { + /* Set defined function pointers */ + bh_memcpy_s(module_inst->func_ptrs + module->import_function_count, + sizeof(void *) * module->function_count, module->func_ptrs, + sizeof(void *) * module->function_count); + } +#endif + else { + bh_assert(0); + } +#else /* Possible multi-tier JIT */ + os_mutex_lock(&module->instance_list_lock); + + module_inst->e->running_mode = running_mode; + + if (running_mode == Mode_Interp) { + /* Do nothing for Mode_Interp */ + } +#if WASM_ENABLE_FAST_JIT != 0 + else if (running_mode == Mode_Fast_JIT) { + JitGlobals *jit_globals = jit_compiler_get_jit_globals(); + uint32 i; + + /* Allocate memory for fast_jit_func_ptrs if needed */ + if (!module_inst->fast_jit_func_ptrs + || module_inst->fast_jit_func_ptrs == module->fast_jit_func_ptrs) { + uint64 total_size = (uint64)sizeof(void *) * module->function_count; + if (!(module_inst->fast_jit_func_ptrs = + runtime_malloc(total_size, NULL, 0))) { + os_mutex_unlock(&module->instance_list_lock); + return false; + } + } + + for (i = 0; i < module->function_count; i++) { + if (module->functions[i]->fast_jit_jitted_code) { + /* current fast jit function has been compiled */ + module_inst->fast_jit_func_ptrs[i] = + module->functions[i]->fast_jit_jitted_code; + } + else { + module_inst->fast_jit_func_ptrs[i] = + jit_globals->compile_fast_jit_and_then_call; + } + } + } +#endif +#if WASM_ENABLE_JIT != 0 + else if (running_mode == Mode_LLVM_JIT) { + void **llvm_jit_func_ptrs; + uint32 i; + + /* Notify backend threads to start llvm jit compilation */ + module->enable_llvm_jit_compilation = true; + + /* Wait until llvm jit finishes initialization */ + os_mutex_lock(&module->tierup_wait_lock); + while (!module->llvm_jit_inited) { + os_cond_reltimedwait(&module->tierup_wait_cond, + &module->tierup_wait_lock, 10); + if (module->orcjit_stop_compiling) { + /* init_llvm_jit_functions_stage2 failed */ + os_mutex_unlock(&module->tierup_wait_lock); + os_mutex_unlock(&module->instance_list_lock); + return false; + } + } + os_mutex_unlock(&module->tierup_wait_lock); + + llvm_jit_func_ptrs = + module_inst->func_ptrs + module->import_function_count; + for (i = 0; i < module->function_count; i++) { + llvm_jit_func_ptrs[i] = module->functions[i]->llvm_jit_func_ptr; + } + } +#endif + else if (running_mode == Mode_Multi_Tier_JIT) { + /* Notify backend threads to start llvm jit compilation */ + module->enable_llvm_jit_compilation = true; + + /* Free fast_jit_func_ptrs if it is allocated before */ + if (module_inst->fast_jit_func_ptrs + && module_inst->fast_jit_func_ptrs != module->fast_jit_func_ptrs) { + wasm_runtime_free(module_inst->fast_jit_func_ptrs); + } + module_inst->fast_jit_func_ptrs = module->fast_jit_func_ptrs; + + /* Copy all llvm jit func ptrs from the module */ + bh_memcpy_s(module_inst->func_ptrs + module->import_function_count, + sizeof(void *) * module->function_count, module->func_ptrs, + sizeof(void *) * module->function_count); + } + else { + bh_assert(0); + } + + /* Add module instance into module's instance list if not added */ + if (first_time_set) { + bool found = false; + WASMModuleInstance *node = module->instance_list; + + while (node) { + if (node == module_inst) { + found = true; + break; + } + node = node->e->next; + } + + if (!found) { + module_inst->e->next = module->instance_list; + module->instance_list = module_inst; + } + } + + os_mutex_unlock(&module->instance_list_lock); +#endif /* end of !(WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \ + && WASM_ENABLE_LAZY_JIT != 0) */ + + (void)module; + return true; +} + +bool +wasm_set_running_mode(WASMModuleInstance *module_inst, RunningMode running_mode) +{ + return set_running_mode(module_inst, running_mode, false); +} + /** * Instantiate module */ @@ -1813,33 +1978,29 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, uint32 stack_size, } #endif -#if WASM_ENABLE_DEBUG_INTERP != 0 \ - || (WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \ - && WASM_ENABLE_LAZY_JIT != 0) +#if WASM_ENABLE_DEBUG_INTERP != 0 if (!is_sub_inst) { /* Add module instance into module's instance list */ os_mutex_lock(&module->instance_list_lock); -#if WASM_ENABLE_DEBUG_INTERP != 0 if (module->instance_list) { LOG_WARNING( "warning: multiple instances referencing to the same module " "may cause unexpected behaviour during debugging"); } -#endif -#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \ - && WASM_ENABLE_LAZY_JIT != 0 - /* Copy llvm func ptrs again in case that they were updated - after the module instance was created */ - bh_memcpy_s(module_inst->func_ptrs + module->import_function_count, - sizeof(void *) * module->function_count, module->func_ptrs, - sizeof(void *) * module->function_count); -#endif module_inst->e->next = module->instance_list; module->instance_list = module_inst; os_mutex_unlock(&module->instance_list_lock); } #endif + /* Set running mode before executing wasm functions */ + if (!set_running_mode(module_inst, wasm_runtime_get_default_running_mode(), + true)) { + set_error_buf(error_buf, error_buf_size, + "set instance running mode failed"); + goto fail; + } + if (module->start_function != (uint32)-1) { /* TODO: fix start function can be import function issue */ if (module->start_function >= module->import_function_count) @@ -1910,6 +2071,14 @@ wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst) wasm_runtime_free(module_inst->func_ptrs); #endif +#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \ + && WASM_ENABLE_LAZY_JIT != 0 + if (module_inst->fast_jit_func_ptrs + && module_inst->fast_jit_func_ptrs + != module_inst->module->fast_jit_func_ptrs) + wasm_runtime_free(module_inst->fast_jit_func_ptrs); +#endif + #if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0 if (module_inst->func_type_indexes) wasm_runtime_free(module_inst->func_type_indexes); diff --git a/core/iwasm/interpreter/wasm_runtime.h b/core/iwasm/interpreter/wasm_runtime.h index 3ede9bf4..38d2cc4b 100644 --- a/core/iwasm/interpreter/wasm_runtime.h +++ b/core/iwasm/interpreter/wasm_runtime.h @@ -221,6 +221,7 @@ typedef struct WASMModuleInstanceExtra { WASMFunctionInstance *retain_function; CApiFuncImport *c_api_func_imports; + RunningMode running_mode; #if WASM_ENABLE_SHARED_MEMORY != 0 /* lock for shared memory atomic operations */ @@ -304,7 +305,11 @@ struct WASMModuleInstance { not available in AOTModuleInstance */ DefPointer(void **, import_func_ptrs); /* Array of function pointers to fast jit functions, - not available in AOTModuleInstance */ + not available in AOTModuleInstance: + Only when the multi-tier JIT macros are all enabled and the running + mode of current module instance is set to Mode_Fast_JIT, runtime + will allocate new memory for it, otherwise it always points to the + module->fast_jit_func_ptrs */ DefPointer(void **, fast_jit_func_ptrs); /* The custom data that can be set/get by wasm_{get|set}_custom_data */ DefPointer(void *, custom_data); @@ -408,6 +413,10 @@ wasm_dump_perf_profiling(const WASMModuleInstance *module_inst); void wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst); +bool +wasm_set_running_mode(WASMModuleInstance *module_inst, + RunningMode running_mode); + WASMFunctionInstance * wasm_lookup_function(const WASMModuleInstance *module_inst, const char *name, const char *signature); diff --git a/product-mini/platforms/posix/main.c b/product-mini/platforms/posix/main.c index e04745c6..7e5bf9e6 100644 --- a/product-mini/platforms/posix/main.c +++ b/product-mini/platforms/posix/main.c @@ -32,12 +32,28 @@ print_help() #if WASM_ENABLE_LOG != 0 printf(" -v=n Set log verbose level (0 to 5, default is 2) larger\n" " level with more log\n"); +#endif +#if WASM_ENABLE_INTERP != 0 + printf(" --interp Run the wasm app with interpreter mode\n"); +#endif +#if WASM_ENABLE_FAST_JIT != 0 + printf(" --fast-jit Run the wasm app with fast jit mode\n"); +#endif +#if WASM_ENABLE_JIT != 0 + printf(" --llvm-jit Run the wasm app with llvm jit mode\n"); +#endif +#if WASM_ENABLE_JIT != 0 && WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_LAZY_JIT != 0 + printf(" --multi-tier-jit Run the wasm app with multi-tier jit mode\n"); #endif printf(" --stack-size=n Set maximum stack size in bytes, default is 64 KB\n"); printf(" --heap-size=n Set maximum heap size in bytes, default is 16 KB\n"); #if WASM_ENABLE_FAST_JIT != 0 printf(" --jit-codecache-size=n Set fast jit maximum code cache size in bytes,\n"); printf(" default is %u KB\n", FAST_JIT_DEFAULT_CODE_CACHE_SIZE / 1024); +#endif +#if WASM_ENABLE_JIT != 0 + printf(" --llvm-jit-size-level=n Set LLVM JIT size level, default is 3\n"); + printf(" --llvm-jit-opt-level=n Set LLVM JIT optimization level, default is 3\n"); #endif printf(" --repl Start a very simple REPL (read-eval-print-loop) mode\n" " that runs commands in the form of \"FUNC ARG...\"\n"); @@ -347,9 +363,14 @@ main(int argc, char *argv[]) uint32 stack_size = 64 * 1024, heap_size = 16 * 1024; #if WASM_ENABLE_FAST_JIT != 0 uint32 jit_code_cache_size = FAST_JIT_DEFAULT_CODE_CACHE_SIZE; +#endif +#if WASM_ENABLE_JIT != 0 + uint32 llvm_jit_size_level = 3; + uint32 llvm_jit_opt_level = 3; #endif wasm_module_t wasm_module = NULL; wasm_module_inst_t wasm_module_inst = NULL; + RunningMode running_mode = 0; RuntimeInitArgs init_args; char error_buf[128] = { 0 }; #if WASM_ENABLE_LOG != 0 @@ -387,6 +408,27 @@ main(int argc, char *argv[]) } func_name = argv[0]; } +#if WASM_ENABLE_INTERP != 0 + else if (!strcmp(argv[0], "--interp")) { + running_mode = Mode_Interp; + } +#endif +#if WASM_ENABLE_FAST_JIT != 0 + else if (!strcmp(argv[0], "--fast-jit")) { + running_mode = Mode_Fast_JIT; + } +#endif +#if WASM_ENABLE_JIT != 0 + else if (!strcmp(argv[0], "--llvm-jit")) { + running_mode = Mode_LLVM_JIT; + } +#endif +#if WASM_ENABLE_JIT != 0 && WASM_ENABLE_FAST_JIT != 0 \ + && WASM_ENABLE_LAZY_JIT != 0 + else if (!strcmp(argv[0], "--multi-tier-jit")) { + running_mode = Mode_Multi_Tier_JIT; + } +#endif #if WASM_ENABLE_LOG != 0 else if (!strncmp(argv[0], "-v=", 3)) { log_verbose_level = atoi(argv[0] + 3); @@ -414,6 +456,38 @@ main(int argc, char *argv[]) jit_code_cache_size = atoi(argv[0] + 21); } #endif +#if WASM_ENABLE_JIT != 0 + else if (!strncmp(argv[0], "--llvm-jit-size-level=", 22)) { + if (argv[0][22] == '\0') + return print_help(); + llvm_jit_size_level = atoi(argv[0] + 22); + if (llvm_jit_size_level < 1) { + printf("LLVM JIT size level shouldn't be smaller than 1, " + "setting it to 1\n"); + llvm_jit_size_level = 1; + } + else if (llvm_jit_size_level > 3) { + printf("LLVM JIT size level shouldn't be greater than 3, " + "setting it to 3\n"); + llvm_jit_size_level = 3; + } + } + else if (!strncmp(argv[0], "--llvm-jit-opt-level=", 21)) { + if (argv[0][21] == '\0') + return print_help(); + llvm_jit_opt_level = atoi(argv[0] + 21); + if (llvm_jit_opt_level < 1) { + printf("LLVM JIT opt level shouldn't be smaller than 1, " + "setting it to 1\n"); + llvm_jit_opt_level = 1; + } + else if (llvm_jit_opt_level > 3) { + printf("LLVM JIT opt level shouldn't be greater than 3, " + "setting it to 3\n"); + llvm_jit_opt_level = 3; + } + } +#endif #if WASM_ENABLE_LIBC_WASI != 0 else if (!strncmp(argv[0], "--dir=", 6)) { if (argv[0][6] == '\0') @@ -539,6 +613,7 @@ main(int argc, char *argv[]) memset(&init_args, 0, sizeof(RuntimeInitArgs)); + init_args.running_mode = running_mode; #if WASM_ENABLE_GLOBAL_HEAP_POOL != 0 init_args.mem_alloc_type = Alloc_With_Pool; init_args.mem_alloc_option.pool.heap_buf = global_heap_buf; @@ -554,6 +629,11 @@ main(int argc, char *argv[]) init_args.fast_jit_code_cache_size = jit_code_cache_size; #endif +#if WASM_ENABLE_JIT != 0 + init_args.llvm_jit_size_level = llvm_jit_size_level; + init_args.llvm_jit_opt_level = llvm_jit_opt_level; +#endif + #if WASM_ENABLE_DEBUG_INTERP != 0 init_args.instance_port = instance_port; if (ip_addr) diff --git a/product-mini/platforms/windows/main.c b/product-mini/platforms/windows/main.c index 14c25596..9171d26d 100644 --- a/product-mini/platforms/windows/main.c +++ b/product-mini/platforms/windows/main.c @@ -26,9 +26,25 @@ print_help() #if WASM_ENABLE_LOG != 0 printf(" -v=n Set log verbose level (0 to 5, default is 2) larger\n" " level with more log\n"); +#endif +#if WASM_ENABLE_INTERP != 0 + printf(" --interp Run the wasm app with interpreter mode\n"); +#endif +#if WASM_ENABLE_FAST_JIT != 0 + printf(" --fast-jit Run the wasm app with fast jit mode\n"); +#endif +#if WASM_ENABLE_JIT != 0 + printf(" --llvm-jit Run the wasm app with llvm jit mode\n"); +#endif +#if WASM_ENABLE_JIT != 0 && WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_LAZY_JIT != 0 + printf(" --multi-tier-jit Run the wasm app with multi-tier jit mode\n"); #endif printf(" --stack-size=n Set maximum stack size in bytes, default is 64 KB\n"); printf(" --heap-size=n Set maximum heap size in bytes, default is 16 KB\n"); +#if WASM_ENABLE_JIT != 0 + printf(" --llvm-jit-size-level=n Set LLVM JIT size level, default is 3\n"); + printf(" --llvm-jit-opt-level=n Set LLVM JIT optimization level, default is 3\n"); +#endif printf(" --repl Start a very simple REPL (read-eval-print-loop) mode\n" " that runs commands in the form of `FUNC ARG...`\n"); #if WASM_ENABLE_LIBC_WASI != 0 @@ -228,8 +244,13 @@ main(int argc, char *argv[]) uint8 *wasm_file_buf = NULL; uint32 wasm_file_size; uint32 stack_size = 64 * 1024, heap_size = 16 * 1024; +#if WASM_ENABLE_JIT != 0 + uint32 llvm_jit_size_level = 3; + uint32 llvm_jit_opt_level = 3; +#endif wasm_module_t wasm_module = NULL; wasm_module_inst_t wasm_module_inst = NULL; + RunningMode running_mode = 0; RuntimeInitArgs init_args; char error_buf[128] = { 0 }; #if WASM_ENABLE_LOG != 0 @@ -257,6 +278,26 @@ main(int argc, char *argv[]) } func_name = argv[0]; } +#if WASM_ENABLE_INTERP != 0 + else if (!strcmp(argv[0], "--interp")) { + running_mode = Mode_Interp; + } +#endif +#if WASM_ENABLE_FAST_JIT != 0 + else if (!strcmp(argv[0], "--fast-jit")) { + running_mode = Mode_Fast_JIT; + } +#endif +#if WASM_ENABLE_JIT != 0 + else if (!strcmp(argv[0], "--llvm-jit")) { + running_mode = Mode_LLVM_JIT; + } +#endif +#if WASM_ENABLE_JIT != 0 && WASM_ENABLE_FAST_JIT != 0 + else if (!strcmp(argv[0], "--multi-tier-jit")) { + running_mode = Mode_Multi_Tier_JIT; + } +#endif #if WASM_ENABLE_LOG != 0 else if (!strncmp(argv[0], "-v=", 3)) { log_verbose_level = atoi(argv[0] + 3); @@ -277,6 +318,38 @@ main(int argc, char *argv[]) return print_help(); heap_size = atoi(argv[0] + 12); } +#if WASM_ENABLE_JIT != 0 + else if (!strncmp(argv[0], "--llvm-jit-size-level=", 22)) { + if (argv[0][22] == '\0') + return print_help(); + llvm_jit_size_level = atoi(argv[0] + 22); + if (llvm_jit_size_level < 1) { + printf("LLVM JIT size level shouldn't be smaller than 1, " + "setting it to 1\n"); + llvm_jit_size_level = 1; + } + else if (llvm_jit_size_level > 3) { + printf("LLVM JIT size level shouldn't be greater than 3, " + "setting it to 3\n"); + llvm_jit_size_level = 3; + } + } + else if (!strncmp(argv[0], "--llvm-jit-opt-level=", 21)) { + if (argv[0][21] == '\0') + return print_help(); + llvm_jit_opt_level = atoi(argv[0] + 21); + if (llvm_jit_opt_level < 1) { + printf("LLVM JIT opt level shouldn't be smaller than 1, " + "setting it to 1\n"); + llvm_jit_opt_level = 1; + } + else if (llvm_jit_opt_level > 3) { + printf("LLVM JIT opt level shouldn't be greater than 3, " + "setting it to 3\n"); + llvm_jit_opt_level = 3; + } + } +#endif #if WASM_ENABLE_LIBC_WASI != 0 else if (!strncmp(argv[0], "--dir=", 6)) { if (argv[0][6] == '\0') @@ -357,6 +430,7 @@ main(int argc, char *argv[]) memset(&init_args, 0, sizeof(RuntimeInitArgs)); + init_args.running_mode = running_mode; #if WASM_ENABLE_GLOBAL_HEAP_POOL != 0 init_args.mem_alloc_type = Alloc_With_Pool; init_args.mem_alloc_option.pool.heap_buf = global_heap_buf; @@ -368,6 +442,11 @@ main(int argc, char *argv[]) init_args.mem_alloc_option.allocator.free_func = free; #endif +#if WASM_ENABLE_JIT != 0 + init_args.llvm_jit_size_level = llvm_jit_size_level; + init_args.llvm_jit_opt_level = llvm_jit_opt_level; +#endif + #if WASM_ENABLE_DEBUG_INTERP != 0 init_args.instance_port = instance_port; if (ip_addr) From 17f3375d530c394536379fc0e0247847ad756de9 Mon Sep 17 00:00:00 2001 From: Marcin Kolny Date: Thu, 2 Feb 2023 11:34:20 +0000 Subject: [PATCH 14/33] Enable gcc-4.8 compilation (#1928) --- .../sandboxed-system-primitives/src/gnuc.h | 14 +++++++ .../src/numeric_limits.h | 42 ------------------- .../sandboxed-system-primitives/src/posix.c | 4 +- .../src/refcount.h | 37 ++++++++++++++++ .../src/ssp_config.h | 16 ++++++- 5 files changed, 66 insertions(+), 47 deletions(-) create mode 100644 core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/gnuc.h delete mode 100644 core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/numeric_limits.h diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/gnuc.h b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/gnuc.h new file mode 100644 index 00000000..70000ae0 --- /dev/null +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/gnuc.h @@ -0,0 +1,14 @@ +/* + * Copyright (C) 2023 Amazon.com, Inc. or its affiliates. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#if !defined(__GNUC_PREREQ) && (defined(__GNUC__) || defined(__GNUG__)) \ + && !defined(__clang__) && defined(__GNUC_MINOR__) +/* Depending on the platform the macro is defined in sys/features.h or + features.h Given the macro is simple, we re-implement it here instead of + dealing with two different paths. + */ +#define __GNUC_PREREQ(maj, min) \ + ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) +#endif diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/numeric_limits.h b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/numeric_limits.h deleted file mode 100644 index 233f3733..00000000 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/numeric_limits.h +++ /dev/null @@ -1,42 +0,0 @@ -// Part of the Wasmtime Project, under the Apache License v2.0 with LLVM -// Exceptions. See -// https://github.com/bytecodealliance/wasmtime/blob/main/LICENSE for license -// information. -// -// Significant parts of this file are derived from cloudabi-utils. See -// https://github.com/bytecodealliance/wasmtime/blob/main/lib/wasi/sandboxed-system-primitives/src/LICENSE -// for license information. -// -// The upstream file contains the following copyright notice: -// -// Copyright (c) 2015 Nuxi, https://nuxi.nl/ - -#ifndef COMMON_LIMITS_H -#define COMMON_LIMITS_H - -#define NUMERIC_MIN(t) \ - _Generic((t)0, char \ - : CHAR_MIN, signed char \ - : SCHAR_MIN, unsigned char : 0, short \ - : SHRT_MIN, unsigned short : 0, int \ - : INT_MIN, unsigned int : 0, long \ - : LONG_MIN, unsigned long : 0, long long \ - : LLONG_MIN, unsigned long long : 0, default \ - : (void)0) - -#define NUMERIC_MAX(t) \ - _Generic((t)0, char \ - : CHAR_MAX, signed char \ - : SCHAR_MAX, unsigned char \ - : UCHAR_MAX, short \ - : SHRT_MAX, unsigned short \ - : USHRT_MAX, int \ - : INT_MAX, unsigned int \ - : UINT_MAX, long \ - : LONG_MAX, unsigned long \ - : ULONG_MAX, long long \ - : LLONG_MAX, unsigned long long \ - : ULLONG_MAX, default \ - : (void)0) - -#endif diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c index 001c3b78..36fe1be6 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c @@ -15,7 +15,6 @@ #include "bh_platform.h" #include "wasmtime_ssp.h" #include "locking.h" -#include "numeric_limits.h" #include "posix.h" #include "random.h" #include "refcount.h" @@ -2257,8 +2256,7 @@ convert_timestamp(__wasi_timestamp_t in, struct timespec *out) in /= 1000000000; // Clamp to the maximum in case it would overflow our system's time_t. - out->tv_sec = - (time_t)in < NUMERIC_MAX(time_t) ? (time_t)in : NUMERIC_MAX(time_t); + out->tv_sec = (time_t)in < BH_TIME_T_MAX ? (time_t)in : BH_TIME_T_MAX; } // Converts the provided timestamps and flags to a set of arguments for diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/refcount.h b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/refcount.h index ac348ebb..03b4b87a 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/refcount.h +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/refcount.h @@ -16,6 +16,7 @@ #include "bh_platform.h" #include "locking.h" +#include "gnuc.h" #define PRODUCES(...) LOCKS_SHARED(__VA_ARGS__) NO_LOCK_ANALYSIS #define CONSUMES(...) UNLOCKS(__VA_ARGS__) NO_LOCK_ANALYSIS @@ -95,6 +96,42 @@ refcount_release(struct refcount *r) return old == 1; } +#elif defined(__GNUC_PREREQ) + +#if __GNUC_PREREQ(4, 7) + +struct refcount { + unsigned int count; +}; + +/* Initialize the reference counter. */ +static inline void +refcount_init(struct refcount *r, unsigned int count) +{ + __atomic_store_n(&r->count, count, __ATOMIC_SEQ_CST); +} + +/* Increment the reference counter. */ +static inline void +refcount_acquire(struct refcount *r) +{ + __atomic_fetch_add(&r->count, 1, __ATOMIC_ACQUIRE); +} + +/* Decrement the reference counter, returning whether the reference + dropped to zero. */ +static inline bool +refcount_release(struct refcount *r) +{ + int old = (int)__atomic_fetch_sub(&r->count, 1, __ATOMIC_RELEASE); + bh_assert(old != 0 && "Reference count becoming negative"); + return old == 1; +} + +#else /* else of __GNUC_PREREQ (4.7) */ +#error "Reference counter isn't implemented" +#endif /* end of __GNUC_PREREQ (4.7) */ + #else /* else of CONFIG_HAS_STD_ATOMIC */ #error "Reference counter isn't implemented" #endif /* end of CONFIG_HAS_STD_ATOMIC */ diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/ssp_config.h b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/ssp_config.h index 68b0faf3..64bf8043 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/ssp_config.h +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/ssp_config.h @@ -14,6 +14,7 @@ #ifndef SSP_CONFIG_H #define SSP_CONFIG_H +#include "gnuc.h" #include #if defined(__FreeBSD__) || defined(__APPLE__) \ @@ -107,10 +108,21 @@ #endif #if !defined(BH_PLATFORM_LINUX_SGX) +#if defined(__GNUC_PREREQ) +/* Even though older versions of GCC support C11, atomics were +not implemented until 4.9. See +https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58016 */ +#if __GNUC_PREREQ(4, 9) #define CONFIG_HAS_STD_ATOMIC 1 -#else +#else /* else of __GNUC_PREREQ(4, 9) */ #define CONFIG_HAS_STD_ATOMIC 0 -#endif +#endif /* end of __GNUC_PREREQ(4, 9) */ +#else /* else of defined(__GNUC_PREREQ) */ +#define CONFIG_HAS_STD_ATOMIC 1 +#endif /* end of defined(__GNUC_PREREQ) */ +#else /* else of !defined(BH_PLATFORM_LINUX_SGX) */ +#define CONFIG_HAS_STD_ATOMIC 0 +#endif /* end of !defined(BH_PLATFORM_LINUX_SGX) */ #if !defined(__NuttX__) #define CONFIG_HAS_D_INO 1 From c3e9b66b2ac7f09d1f7cd5c318a969123a5c9119 Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Fri, 3 Feb 2023 11:15:03 +0800 Subject: [PATCH 15/33] Fix jit memory overwritten after instance deinstantiate (#1936) When de-instantiating the wasm module instance, remove it from the module's instance list before freeing func_ptrs and fast_jit_func_ptrs of the instance, to avoid accessing these freed memory in the JIT backend compilation threads. --- core/iwasm/interpreter/wasm_runtime.c | 54 ++++++++++++++------------- 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index 45356207..eabdea68 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -2066,6 +2066,35 @@ wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst) if (!module_inst) return; +#if WASM_ENABLE_DEBUG_INTERP != 0 \ + || (WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \ + && WASM_ENABLE_LAZY_JIT != 0) + /* Remove instance from module's instance list before freeing + func_ptrs and fast_jit_func_ptrs of the instance, to avoid + accessing the freed memory in the jit backend compilation + threads */ + if (!is_sub_inst) { + WASMModule *module = module_inst->module; + WASMModuleInstance *instance_prev = NULL, *instance; + os_mutex_lock(&module->instance_list_lock); + + instance = module->instance_list; + while (instance) { + if (instance == module_inst) { + if (!instance_prev) + module->instance_list = instance->e->next; + else + instance_prev->e->next = instance->e->next; + break; + } + instance_prev = instance; + instance = instance->e->next; + } + + os_mutex_unlock(&module->instance_list_lock); + } +#endif + #if WASM_ENABLE_JIT != 0 if (module_inst->func_ptrs) wasm_runtime_free(module_inst->func_ptrs); @@ -2130,31 +2159,6 @@ wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst) } #endif -#if WASM_ENABLE_DEBUG_INTERP != 0 \ - || (WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \ - && WASM_ENABLE_LAZY_JIT != 0) - if (!is_sub_inst) { - WASMModule *module = module_inst->module; - WASMModuleInstance *instance_prev = NULL, *instance; - os_mutex_lock(&module->instance_list_lock); - - instance = module->instance_list; - while (instance) { - if (instance == module_inst) { - if (!instance_prev) - module->instance_list = instance->e->next; - else - instance_prev->e->next = instance->e->next; - break; - } - instance_prev = instance; - instance = instance->e->next; - } - - os_mutex_unlock(&module->instance_list_lock); - } -#endif - #if WASM_ENABLE_SHARED_MEMORY != 0 if (module_inst->e->mem_lock_inited) os_mutex_destroy(&module_inst->e->mem_lock); From 42ced88424d9e04bb3d82ace53f5d8e73aa91768 Mon Sep 17 00:00:00 2001 From: Enrico Loparco Date: Mon, 6 Feb 2023 02:07:00 +0100 Subject: [PATCH 16/33] Fix stack alignment issue on ia32 (#1934) The stack of Unix-like (GCC) system should be aligned on 16-byte boundary according to the x86-32 ABI specification. --- core/iwasm/common/arch/invokeNative_ia32.s | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/core/iwasm/common/arch/invokeNative_ia32.s b/core/iwasm/common/arch/invokeNative_ia32.s index 0056a53e..de1c1a5e 100644 --- a/core/iwasm/common/arch/invokeNative_ia32.s +++ b/core/iwasm/common/arch/invokeNative_ia32.s @@ -16,9 +16,14 @@ _invokeNative: push %ebp movl %esp, %ebp movl 16(%ebp), %ecx /* ecx = argc */ - movl 12(%ebp), %edx /* edx = argv */ + leal 2(%ecx), %edx /* edx = ecx + 2 (count return address and saved ebp) */ + andl $3, %edx /* edx = edx % 4 */ + jz stack_aligned /* if edx == 0, stack is already 16 bytes aligned */ + leal -16(%esp, %edx, 4), %esp /* esp = esp - 16 + edx * 4 */ +stack_aligned: test %ecx, %ecx jz skip_push_args /* if ecx == 0, skip pushing arguments */ + movl 12(%ebp), %edx /* edx = argv */ leal -4(%edx,%ecx,4), %edx /* edx = edx + ecx * 4 - 4 */ subl %esp, %edx /* edx = edx - esp */ 1: From 2c8375ee67964a4ef99dde2faa1c5225051adca0 Mon Sep 17 00:00:00 2001 From: Huang Qi Date: Mon, 6 Feb 2023 11:04:28 +0800 Subject: [PATCH 17/33] wamr-test-suites: Save .wasm/.aot file to the report dir if test failed (#1937) --- .../wamr-test-suites/spec-test-script/all.py | 20 +++++++++++++++++-- .../spec-test-script/runtest.py | 9 ++++++++- tests/wamr-test-suites/test_wamr.sh | 5 ++++- 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/tests/wamr-test-suites/spec-test-script/all.py b/tests/wamr-test-suites/spec-test-script/all.py index 04883520..7b29bcba 100644 --- a/tests/wamr-test-suites/spec-test-script/all.py +++ b/tests/wamr-test-suites/spec-test-script/all.py @@ -111,6 +111,7 @@ def test_case( verbose_flag=True, qemu_flag=False, qemu_firmware='', + log='', ): case_path = pathlib.Path(case_path).resolve() case_name = case_path.stem @@ -170,6 +171,10 @@ def test_case( if not clean_up_flag: CMD.append("--no_cleanup") + if log != '': + CMD.append("--log-dir") + CMD.append(log) + CMD.append(case_path) print(f"============> run {case_name} ", end="") with subprocess.Popen( @@ -228,7 +233,8 @@ def test_suite( verbose_flag=True, parl_flag=False, qemu_flag=False, - qemu_firmware='' + qemu_firmware='', + log='', ): suite_path = pathlib.Path(SPEC_TEST_DIR).resolve() if not suite_path.exists(): @@ -264,6 +270,7 @@ def test_suite( verbose_flag, qemu_flag, qemu_firmware, + log, ], ) @@ -299,6 +306,7 @@ def test_suite( verbose_flag, qemu_flag, qemu_firmware, + log, ) successful_case += 1 except Exception as e: @@ -393,6 +401,12 @@ def main(): dest="qemu_firmware", help="Firmware required by qemu", ) + parser.add_argument( + "--log", + default='', + dest="log", + help="Log directory", + ) parser.add_argument( "--quiet", action="store_false", @@ -435,6 +449,7 @@ def main(): options.parl_flag, options.qemu_flag, options.qemu_firmware, + options.log, ) end = time.time_ns() print( @@ -455,7 +470,8 @@ def main(): options.clean_up_flag, options.verbose_flag, options.qemu_flag, - options.qemu_firmware + options.qemu_firmware, + options.log ) else: ret = True diff --git a/tests/wamr-test-suites/spec-test-script/runtest.py b/tests/wamr-test-suites/spec-test-script/runtest.py index a61f03b1..ef887c79 100755 --- a/tests/wamr-test-suites/spec-test-script/runtest.py +++ b/tests/wamr-test-suites/spec-test-script/runtest.py @@ -200,6 +200,8 @@ parser.add_argument('--no-pty', action='store_true', help="Use direct pipes instead of pseudo-tty") parser.add_argument('--log-file', type=str, help="Write messages to the named file in addition the screen") +parser.add_argument('--log-dir', type=str, + help="The log directory to save the case file if test failed") parser.add_argument('--debug-file', type=str, help="Write all test interaction the named file") @@ -1092,6 +1094,7 @@ def test_assert_with_exception(form, wast_tempfile, wasm_tempfile, aot_tempfile, if __name__ == "__main__": opts = parser.parse_args(sys.argv[1:]) + print('Input param :',opts) if opts.aot: test_aot = True # default x86_64 @@ -1271,12 +1274,16 @@ if __name__ == "__main__": print("THE FINAL EXCEPTION IS {}".format(e)) ret_code = 101 + shutil.copyfile(wasm_tempfile, os.path.join(opts.log_dir, os.path.basename(wasm_tempfile))) + if opts.aot or opts.xip: + shutil.copyfile(aot_tempfile, os.path.join(opts.log_dir,os.path.basename(aot_tempfile))) if "indirect-mode" in str(e): compile_wasm_to_aot(wasm_tempfile, aot_tempfile, None, opts, None, "object") + shutil.copyfile(aot_tempfile, os.path.join(opts.log_dir,os.path.basename(aot_tempfile)+'.o')) subprocess.check_call(["llvm-objdump", "-r", aot_tempfile]) compile_wasm_to_aot(wasm_tempfile, aot_tempfile, None, opts, None, "ir") - subprocess.check_call(["cat", aot_tempfile]) + shutil.copyfile(aot_tempfile, os.path.join(opts.log_dir,os.path.basename(aot_tempfile)+".ir")) else: ret_code = 0 diff --git a/tests/wamr-test-suites/test_wamr.sh b/tests/wamr-test-suites/test_wamr.sh index bc6df908..342b3b93 100755 --- a/tests/wamr-test-suites/test_wamr.sh +++ b/tests/wamr-test-suites/test_wamr.sh @@ -442,9 +442,12 @@ function spec_test() if [[ ${ENABLE_QEMU} == 1 ]]; then ARGS_FOR_SPEC_TEST+="--qemu " - ARGS_FOR_SPEC_TEST+="--qemu-firmware ${QEMU_FIRMWARE}" + ARGS_FOR_SPEC_TEST+="--qemu-firmware ${QEMU_FIRMWARE} " fi + # set log directory + ARGS_FOR_SPEC_TEST+="--log ${REPORT_DIR}" + cd ${WORK_DIR} echo "python3 ./all.py ${ARGS_FOR_SPEC_TEST} | tee -a ${REPORT_DIR}/spec_test_report.txt" python3 ./all.py ${ARGS_FOR_SPEC_TEST} | tee -a ${REPORT_DIR}/spec_test_report.txt From e2c754f0a6369ea693ba3d348902354fc32557da Mon Sep 17 00:00:00 2001 From: Marcin Kolny Date: Mon, 6 Feb 2023 11:08:45 +0000 Subject: [PATCH 18/33] Fix data race when terminating or waiting for a thread (#1924) There is a possibility that while iterating through a list of threads, the threads finish by themselves, making a list of exec_env invalid. --- .../libraries/thread-mgr/thread_manager.c | 92 +++++++++++++++---- 1 file changed, 74 insertions(+), 18 deletions(-) diff --git a/core/iwasm/libraries/thread-mgr/thread_manager.c b/core/iwasm/libraries/thread-mgr/thread_manager.c index ec984cbc..de478a21 100644 --- a/core/iwasm/libraries/thread-mgr/thread_manager.c +++ b/core/iwasm/libraries/thread-mgr/thread_manager.c @@ -76,6 +76,58 @@ traverse_list(bh_list *l, list_visitor visitor, void *user_data) } } +/* Assumes cluster->lock is locked */ +static bool +safe_traverse_exec_env_list(WASMCluster *cluster, list_visitor visitor, + void *user_data) +{ + Vector proc_nodes; + void *node; + bool ret = true; + + if (!bh_vector_init(&proc_nodes, cluster->exec_env_list.len, sizeof(void *), + false)) { + ret = false; + goto final; + } + + node = bh_list_first_elem(&cluster->exec_env_list); + + while (node) { + bool already_processed = false; + void *proc_node; + for (size_t i = 0; i < bh_vector_size(&proc_nodes); i++) { + if (!bh_vector_get(&proc_nodes, i, &proc_node)) { + ret = false; + goto final; + } + if (proc_node == node) { + already_processed = true; + break; + } + } + if (already_processed) { + node = bh_list_elem_next(node); + continue; + } + + os_mutex_unlock(&cluster->lock); + visitor(node, user_data); + os_mutex_lock(&cluster->lock); + if (!bh_vector_append(&proc_nodes, &node)) { + ret = false; + goto final; + } + + node = bh_list_first_elem(&cluster->exec_env_list); + } + +final: + bh_vector_destroy(&proc_nodes); + + return ret; +} + /* The caller must lock cluster->lock */ static bool allocate_aux_stack(WASMCluster *cluster, uint32 *start, uint32 *size) @@ -299,7 +351,6 @@ wasm_cluster_del_exec_env(WASMCluster *cluster, WASMExecEnv *exec_env) os_mutex_unlock(&cluster->debug_inst->wait_lock); } #endif - if (bh_list_remove(&cluster->exec_env_list, exec_env) != 0) ret = false; @@ -724,16 +775,22 @@ wasm_cluster_join_thread(WASMExecEnv *exec_env, void **ret_val) korp_tid handle; os_mutex_lock(&cluster_list_lock); + os_mutex_lock(&exec_env->cluster->lock); + if (!clusters_have_exec_env(exec_env) || exec_env->thread_is_detached) { /* Invalid thread, thread has exited or thread has been detached */ if (ret_val) *ret_val = NULL; + os_mutex_unlock(&exec_env->cluster->lock); os_mutex_unlock(&cluster_list_lock); return 0; } exec_env->wait_count++; handle = exec_env->handle; + + os_mutex_unlock(&exec_env->cluster->lock); os_mutex_unlock(&cluster_list_lock); + return os_thread_join(handle, ret_val); } @@ -816,15 +873,22 @@ int32 wasm_cluster_cancel_thread(WASMExecEnv *exec_env) { os_mutex_lock(&cluster_list_lock); + os_mutex_lock(&exec_env->cluster->lock); + + if (!exec_env->cluster) { + goto final; + } if (!clusters_have_exec_env(exec_env)) { /* Invalid thread or the thread has exited */ - os_mutex_unlock(&cluster_list_lock); - return 0; + goto final; } - os_mutex_unlock(&cluster_list_lock); set_thread_cancel_flags(exec_env); +final: + os_mutex_unlock(&exec_env->cluster->lock); + os_mutex_unlock(&cluster_list_lock); + return 0; } @@ -846,11 +910,9 @@ wasm_cluster_terminate_all(WASMCluster *cluster) { os_mutex_lock(&cluster->lock); cluster->processing = true; - os_mutex_unlock(&cluster->lock); - traverse_list(&cluster->exec_env_list, terminate_thread_visitor, NULL); + safe_traverse_exec_env_list(cluster, terminate_thread_visitor, NULL); - os_mutex_lock(&cluster->lock); cluster->processing = false; os_mutex_unlock(&cluster->lock); } @@ -861,12 +923,10 @@ wasm_cluster_terminate_all_except_self(WASMCluster *cluster, { os_mutex_lock(&cluster->lock); cluster->processing = true; - os_mutex_unlock(&cluster->lock); - traverse_list(&cluster->exec_env_list, terminate_thread_visitor, - (void *)exec_env); + safe_traverse_exec_env_list(cluster, terminate_thread_visitor, + (void *)exec_env); - os_mutex_lock(&cluster->lock); cluster->processing = false; os_mutex_unlock(&cluster->lock); } @@ -888,11 +948,9 @@ wams_cluster_wait_for_all(WASMCluster *cluster) { os_mutex_lock(&cluster->lock); cluster->processing = true; - os_mutex_unlock(&cluster->lock); - traverse_list(&cluster->exec_env_list, wait_for_thread_visitor, NULL); + safe_traverse_exec_env_list(cluster, wait_for_thread_visitor, NULL); - os_mutex_lock(&cluster->lock); cluster->processing = false; os_mutex_unlock(&cluster->lock); } @@ -903,12 +961,10 @@ wasm_cluster_wait_for_all_except_self(WASMCluster *cluster, { os_mutex_lock(&cluster->lock); cluster->processing = true; - os_mutex_unlock(&cluster->lock); - traverse_list(&cluster->exec_env_list, wait_for_thread_visitor, - (void *)exec_env); + safe_traverse_exec_env_list(cluster, wait_for_thread_visitor, + (void *)exec_env); - os_mutex_lock(&cluster->lock); cluster->processing = false; os_mutex_unlock(&cluster->lock); } From 8ed66876962f8814fc92812a038b392191483f59 Mon Sep 17 00:00:00 2001 From: Huang Qi Date: Tue, 7 Feb 2023 12:42:59 +0800 Subject: [PATCH 19/33] Fix CI compilation error on nuttx (#1940) --- .github/workflows/compilation_on_nuttx.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/compilation_on_nuttx.yml b/.github/workflows/compilation_on_nuttx.yml index 1bcc8d5c..c587c041 100644 --- a/.github/workflows/compilation_on_nuttx.yml +++ b/.github/workflows/compilation_on_nuttx.yml @@ -115,7 +115,7 @@ jobs: - name: Enable WAMR for NuttX run: | - find nuttx/boards -name defconfig | xargs sed -i '$a\CONFIG_EOL_IS_LF=y\n${{ matrix.wamr_config_option }}' + find nuttx/boards -name defconfig | xargs sed -i '$a\CONFIG_EOL_IS_LF=y\nCONFIG_PSEUDOFS_SOFTLINKS=y\n${{ matrix.wamr_config_option }}' find nuttx/boards/sim -name defconfig | xargs sed -i '$a\CONFIG_LIBM=y\n' - name: Build From f3c1ad486438fa9c0b664fde99e5f9d1092dcb4c Mon Sep 17 00:00:00 2001 From: Hritik Gupta Date: Tue, 7 Feb 2023 12:56:23 +0000 Subject: [PATCH 20/33] Fix terminating stale threads on trap/proc_exit (#1929) This is to terminate suspended threads in case an atomic wait occurs with a huge or indefinite (-1) timeout, followed by a proc exit or trap. --- core/iwasm/common/wasm_runtime_common.c | 6 +++ core/iwasm/common/wasm_shared_memory.c | 56 +++++++++++++++++++++++++ core/iwasm/common/wasm_shared_memory.h | 3 ++ 3 files changed, 65 insertions(+) diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index 139c050a..8662af1c 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -2317,6 +2317,12 @@ wasm_set_exception(WASMModuleInstance *module_inst, const char *exception) if (exec_env) { wasm_cluster_spread_exception(exec_env, exception ? false : true); } +#if WASM_ENABLE_SHARED_MEMORY + if (exception) { + notify_stale_threads_on_exception( + (WASMModuleInstanceCommon *)module_inst); + } +#endif #else (void)exec_env; #endif diff --git a/core/iwasm/common/wasm_shared_memory.c b/core/iwasm/common/wasm_shared_memory.c index b2b63de5..19b81f1b 100644 --- a/core/iwasm/common/wasm_shared_memory.c +++ b/core/iwasm/common/wasm_shared_memory.c @@ -30,6 +30,11 @@ typedef struct AtomicWaitNode { korp_cond wait_cond; } AtomicWaitNode; +typedef struct AtomicWaitAddressArgs { + uint32 index; + void **addr; +} AtomicWaitAddressArgs; + /* Atomic wait map */ static HashMap *wait_map; @@ -87,6 +92,53 @@ search_module(WASMModuleCommon *module) return NULL; } +static void +wait_map_address_count_callback(void *key, void *value, + void *p_total_elem_count) +{ + *(uint32 *)p_total_elem_count = *(uint32 *)p_total_elem_count + 1; +} + +static void +create_list_of_waiter_addresses(void *key, void *value, void *user_data) +{ + AtomicWaitAddressArgs *data = (AtomicWaitAddressArgs *)user_data; + data->addr[data->index++] = key; +} + +void +notify_stale_threads_on_exception(WASMModuleInstanceCommon *module_inst) +{ + AtomicWaitAddressArgs args = { 0 }; + uint32 i = 0, total_elem_count = 0; + + os_mutex_lock(&shared_memory_list_lock); + + /* count number of addresses in wait_map */ + bh_hash_map_traverse(wait_map, wait_map_address_count_callback, + (void *)&total_elem_count); + + /* allocate memory */ + if (!(args.addr = wasm_runtime_malloc(sizeof(void *) * total_elem_count))) { + LOG_ERROR( + "failed to allocate memory for list of atomic wait addresses"); + os_mutex_unlock(&shared_memory_list_lock); + return; + } + + /* set values in list of addresses */ + bh_hash_map_traverse(wait_map, create_list_of_waiter_addresses, &args); + os_mutex_unlock(&shared_memory_list_lock); + + /* notify */ + for (i = 0; i < args.index; i++) { + wasm_runtime_atomic_notify(module_inst, args.addr[i], UINT32_MAX); + } + + /* free memory allocated to args data */ + wasm_runtime_free(args.addr); +} + WASMSharedMemNode * wasm_module_get_shared_memory(WASMModuleCommon *module) { @@ -322,6 +374,10 @@ wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address, bh_assert(module->module_type == Wasm_Module_Bytecode || module->module_type == Wasm_Module_AoT); + if (wasm_get_exception(module_inst)) { + return -1; + } + /* Currently we have only one memory instance */ if (!module_inst->memories[0]->is_shared) { wasm_runtime_set_exception(module, "expected shared memory"); diff --git a/core/iwasm/common/wasm_shared_memory.h b/core/iwasm/common/wasm_shared_memory.h index bc6f8945..5cd6e0fc 100644 --- a/core/iwasm/common/wasm_shared_memory.h +++ b/core/iwasm/common/wasm_shared_memory.h @@ -37,6 +37,9 @@ wasm_shared_memory_init(); void wasm_shared_memory_destroy(); +void +notify_stale_threads_on_exception(WASMModuleInstanceCommon *module); + WASMSharedMemNode * wasm_module_get_shared_memory(WASMModuleCommon *module); From 251e63f3eccfe82c67618ac17f2d1f4b8f00afa1 Mon Sep 17 00:00:00 2001 From: Marcin Kolny Date: Tue, 7 Feb 2023 14:10:59 +0000 Subject: [PATCH 21/33] Enable specifying out-of-source platform configuration cmake file (#1941) Resolve #1935, enable specifying out-of-source platform folder with `cmake .. -DWAMR_BUILD_PLATFORM=new-os -DSHARED_PLATFORM_CONFIG=/path/to/new-os/shared_platform.cmake` --- build-scripts/runtime_lib.cmake | 7 ++++++- doc/port_wamr.md | 25 +++++++++++++++++-------- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/build-scripts/runtime_lib.cmake b/build-scripts/runtime_lib.cmake index 1aea9591..e90a6c4a 100644 --- a/build-scripts/runtime_lib.cmake +++ b/build-scripts/runtime_lib.cmake @@ -19,6 +19,11 @@ endif () if (NOT DEFINED DEPS_DIR) set (DEPS_DIR ${WAMR_ROOT_DIR}/core/deps) endif () +if (NOT DEFINED SHARED_PLATFORM_CONFIG) + # CMake file for platform configuration. The PLATFORM_SHARED_SOURCE varable + # should point to a list of platform-specfic source files to compile. + set (SHARED_PLATFORM_CONFIG ${SHARED_DIR}/platform/${WAMR_BUILD_PLATFORM}/shared_platform.cmake) +endif () if (DEFINED EXTRA_SDK_INCLUDE_PATH) message(STATUS, "EXTRA_SDK_INCLUDE_PATH = ${EXTRA_SDK_INCLUDE_PATH} ") @@ -165,7 +170,7 @@ LIST (APPEND RUNTIME_LIB_HEADER_LIST ${header}) enable_language (ASM) -include (${SHARED_DIR}/platform/${WAMR_BUILD_PLATFORM}/shared_platform.cmake) +include (${SHARED_PLATFORM_CONFIG}) include (${SHARED_DIR}/mem-alloc/mem_alloc.cmake) include (${IWASM_DIR}/common/iwasm_common.cmake) include (${SHARED_DIR}/utils/shared_utils.cmake) diff --git a/doc/port_wamr.md b/doc/port_wamr.md index 44ac50ec..7899ff31 100644 --- a/doc/port_wamr.md +++ b/doc/port_wamr.md @@ -10,9 +10,13 @@ This document describes how to port WAMR to a new platform "**new-os**" # Step 1: Implement platform API layer ------------------------- -Firstly create the folder **`core/shared/platform/new-os`** for platform API layer implementations. In the folder you just created, you must provide the following files: +Firstly create the folder for platform API layer implementations: +* for common platforms, create a folder in **`core/shared/platform/new-os`** in WAMR repository folder, so the implementation can be upstreamed +* for platforms that are internal and its implementation shouldn't be published, it's recommended to create a folder outside of the WAMR repository folder (e.g. have separate repository for platform API layer implementation) -- `platform_internal.h`: It can be used for any platform specific definitions such as macros, data types and internal APIs. +In the folder you just created, you must provide the following files: + +- `platform_internal.h`: It can be used for any platform-specific definitions such as macros, data types and internal APIs. - `shared_platform.cmake`: the cmake file will be included by the building script. It is recommended to add a definition for your platform: @@ -20,29 +24,29 @@ Firstly create the folder **`core/shared/platform/new-os`** for platform API lay add_definitions(-DBH_PLATFORM_YOUR_NAME) ``` -Then go to implement the APIs defined in following header files for the platform abstraction layer: +Then go to implement the APIs defined in the following header files for the platform abstraction layer: -- [`platform_api_vmcore.h`](../core/shared/platform/include/platform_api_vmcore.h): mandatory for building mini-product (vmcore only). Part of APIs are needed only for Ahead of Time compilation support. +- [`platform_api_vmcore.h`](../core/shared/platform/include/platform_api_vmcore.h): mandatory for building mini-product (vmcore only). Part of the APIs is needed only for Ahead of Time compilation support. - [`platform_api_extension.h`](../core/shared/platform/include/platform_api_extension.h): mandatory for app-mgr and app-framework. Given that the app-mgr and app-framework are not required for your target platform, you won't have to implement the API defined in the `platform_api_extension.h`. **common/posix:** -There is posix based implementation of the platform API located in the `platform/common/posix` folder. You can include it if your platform support posix API. refer to platform linux implementation. +There is posix based implementation of the platform API located in the `platform/common/posix` folder. You can include it if your platform supports posix API. refer to platform linux implementation. **common/math:** -Some platforms such as ZephyrOS don't provide math functions e.g. sqrt, fabs and isnan, then you should include source files under the folder `platform/common/math`. +Some platforms such as ZephyrOS don't provide math functions e.g. sqrt, fabs and isnan, then you should include source files under the folder `platform/common/math`. # Step 2: Create the mini product for the platform ------------------------- -You can build a mini WAMR product which is only the vmcore for you platform. Normally you need to implement the main function which loads a WASM file and run it with the WASM runtime. You don't have to do this step if there is no mini-product need for your platform porting. +You can build a mini WAMR product which is only the vmcore for your platform. Normally you need to implement the main function which loads a WASM file and run it with the WASM runtime. You don't have to do this step if there is no mini-product need for your platform porting. @@ -55,9 +59,14 @@ You should set cmake variable `WAMR_BUILD_PLATFORM` to your platform name while ``` mkdir build cd build -cmake .. -DWAMR_BUILD_PLATFORM=new-os +cmake .. -DWAMR_BUILD_PLATFORM=new-os ``` +For platform implementations that are outside of the WAMR repository (e.g. internal platforms), you also need to provide `SHARED_PLATFORM_CONFIG` path: + +``` +cmake .. -DWAMR_BUILD_PLATFORM=new-os -DSHARED_PLATFORM_CONFIG=/path/to/new-os/shared_platform.cmake +``` Refer to [build_wamr.md](./build_wamr.md) for the building configurations and parameters. From 3586911333847d7264e90f2e2c610e3826cf545e Mon Sep 17 00:00:00 2001 From: Hritik Gupta Date: Wed, 8 Feb 2023 19:25:35 +0000 Subject: [PATCH 22/33] Fix minor typos in coding guidelines workflow (#1943) --- .../{codeing_guildelines.yml => coding_guidelines.yml} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename .github/workflows/{codeing_guildelines.yml => coding_guidelines.yml} (97%) diff --git a/.github/workflows/codeing_guildelines.yml b/.github/workflows/coding_guidelines.yml similarity index 97% rename from .github/workflows/codeing_guildelines.yml rename to .github/workflows/coding_guidelines.yml index bc66436c..259e84fe 100644 --- a/.github/workflows/codeing_guildelines.yml +++ b/.github/workflows/coding_guidelines.yml @@ -15,7 +15,7 @@ concurrency: cancel-in-progress: true jobs: - complinace_job: + compliance_job: runs-on: ubuntu-latest steps: - name: checkout From 3d44f11d195f4ca76c371a39e597b0e768318183 Mon Sep 17 00:00:00 2001 From: Hritik Gupta Date: Wed, 8 Feb 2023 23:49:07 +0000 Subject: [PATCH 23/33] Add gh api call for fetching llvm version (#1942) Fixes #1877 --- .github/workflows/build_llvm_libraries.yml | 6 ++++- build-scripts/build_llvm.py | 29 ++++++++++++++++------ build-scripts/requirements.txt | 1 + 3 files changed, 27 insertions(+), 9 deletions(-) create mode 100644 build-scripts/requirements.txt diff --git a/.github/workflows/build_llvm_libraries.yml b/.github/workflows/build_llvm_libraries.yml index b82b89e6..7ef1dd63 100644 --- a/.github/workflows/build_llvm_libraries.yml +++ b/.github/workflows/build_llvm_libraries.yml @@ -26,9 +26,13 @@ jobs: - name: checkout uses: actions/checkout@v3 + - name: install dependencies + run: /usr/bin/env python3 -m pip install -r requirements.txt + working-directory: build-scripts + - name: retrive the last commit ID id: get_last_commit - run: echo "last_commit=$(/usr/bin/env python3 ./build_llvm.py --llvm-ver)" >> $GITHUB_OUTPUT + run: echo "last_commit=$(GH_TOKEN=${{ secrets.GITHUB_TOKEN }} /usr/bin/env python3 ./build_llvm.py --llvm-ver)" >> $GITHUB_OUTPUT working-directory: build-scripts # Bump the prefix number to evict all previous caches and diff --git a/build-scripts/build_llvm.py b/build-scripts/build_llvm.py index dd211f30..1531895c 100755 --- a/build-scripts/build_llvm.py +++ b/build-scripts/build_llvm.py @@ -7,6 +7,7 @@ import argparse import os import pathlib +import requests import shlex import shutil import subprocess @@ -27,11 +28,23 @@ def clone_llvm(dst_dir, llvm_repo, llvm_branch): return llvm_dir -def query_llvm_version(llvm_dir): - GIT_LOG_CMD = f"git log --format=format:'%h' -1" - return subprocess.check_output( - shlex.split(GIT_LOG_CMD), cwd=llvm_dir, universal_newlines=True, text=True - ) +def query_llvm_version(llvm_info): + github_token = os.environ['GH_TOKEN'] + owner_project = llvm_info['repo'].replace("https://github.com/", "").replace(".git", "") + url = f"https://api.github.com/repos/{owner_project}/commits/{llvm_info['branch']}" + headers = { + 'Authorization': f"Bearer {github_token}" + } + + try: + response = requests.request("GET", url, headers=headers, data={}) + response.raise_for_status() + except requests.exceptions.HTTPError as error: + print (error) # for debugging purpose + return None + + response = response.json() + return response['sha'] def build_llvm(llvm_dir, platform, backends, projects, use_clang=False): @@ -253,13 +266,13 @@ def main(): try: llvm_info = llvm_repo_and_branch.get(platform, llvm_repo_and_branch["default"]) - llvm_dir = clone_llvm(deps_dir, llvm_info["repo"], llvm_info["branch"]) if options.llvm_ver: - commit_hash = query_llvm_version(llvm_dir) + commit_hash = query_llvm_version(llvm_info) print(commit_hash) return commit_hash is not None - + + llvm_dir = clone_llvm(deps_dir, llvm_info["repo"], llvm_info["branch"]) if ( build_llvm( llvm_dir, platform, options.arch, options.project, options.use_clang diff --git a/build-scripts/requirements.txt b/build-scripts/requirements.txt new file mode 100644 index 00000000..bf0d9d41 --- /dev/null +++ b/build-scripts/requirements.txt @@ -0,0 +1 @@ +requests==2.28.2 \ No newline at end of file From 89c11c5361c09eef02f99c7d929542554fb1f1cd Mon Sep 17 00:00:00 2001 From: Patrick Cook <114708437+cookpate@users.noreply.github.com> Date: Wed, 8 Feb 2023 17:34:26 -0800 Subject: [PATCH 24/33] Fix explicit casts and types in espidf_socket.c (#1945) In the esp-idf platform, Xtensa GCC 8.4.0 reported incompatible pointer warnings when building with the lwip component. Berkeley (POSIX) sockets uses composition in combination with type punning to handle many protocol families, including IPv4 & IPv6. The type punning just has to be made explicit with pointer casts from `sockaddr_in` for IPv4 to the generic `sockaddr`. --- core/shared/platform/esp-idf/espidf_socket.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/shared/platform/esp-idf/espidf_socket.c b/core/shared/platform/esp-idf/espidf_socket.c index 37e412b2..9f441b71 100644 --- a/core/shared/platform/esp-idf/espidf_socket.c +++ b/core/shared/platform/esp-idf/espidf_socket.c @@ -77,7 +77,7 @@ os_socket_bind(bh_socket_t socket, const char *host, int *port) } socklen = sizeof(addr); - if (getsockname(socket, (void *)&addr, &socklen) == -1) { + if (getsockname(socket, (struct sockaddr *)&addr, &socklen) == -1) { goto fail; } @@ -120,7 +120,7 @@ os_socket_accept(bh_socket_t server_sock, bh_socket_t *sock, void *addr, unsigned int *addrlen) { struct sockaddr addr_tmp; - unsigned int len = sizeof(struct sockaddr); + socklen_t len = sizeof(struct sockaddr); *sock = accept(server_sock, (struct sockaddr *)&addr_tmp, &len); @@ -205,7 +205,7 @@ os_socket_addr_remote(bh_socket_t socket, bh_sockaddr_t *sockaddr) struct sockaddr_in addr; socklen_t addr_len = sizeof(addr); - if (getpeername(socket, &addr, &addr_len) == -1) { + if (getpeername(socket, (struct sockaddr *)&addr, &addr_len) == -1) { return BHT_ERROR; } @@ -219,7 +219,7 @@ os_socket_addr_local(bh_socket_t socket, bh_sockaddr_t *sockaddr) struct sockaddr_in addr; socklen_t addr_len = sizeof(addr); - if (getsockname(socket, &addr, &addr_len) == -1) { + if (getsockname(socket, (struct sockaddr *)&addr, &addr_len) == -1) { return BHT_ERROR; } From 427abf02c81071c5d3d31efacf09db22662dd82c Mon Sep 17 00:00:00 2001 From: ocfox Date: Mon, 13 Feb 2023 13:55:50 +0800 Subject: [PATCH 25/33] Fix potential integer overflow issue in wasm-c-api (#1954) Fix potential integer overflow issue in wasm-c-api reported by CodeQL --- core/iwasm/common/wasm_c_api.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/iwasm/common/wasm_c_api.c b/core/iwasm/common/wasm_c_api.c index 2b29330a..325f231d 100644 --- a/core/iwasm/common/wasm_c_api.c +++ b/core/iwasm/common/wasm_c_api.c @@ -4205,7 +4205,8 @@ wasm_memory_data_size(const wasm_memory_t *memory) (WASMModuleInstance *)module_inst_comm; WASMMemoryInstance *memory_inst = module_inst->memories[memory->memory_idx_rt]; - return memory_inst->cur_page_count * memory_inst->num_bytes_per_page; + return (size_t)memory_inst->cur_page_count + * memory_inst->num_bytes_per_page; } #endif @@ -4215,7 +4216,8 @@ wasm_memory_data_size(const wasm_memory_t *memory) AOTMemoryInstance *memory_inst = ((AOTMemoryInstance **) module_inst->memories)[memory->memory_idx_rt]; - return memory_inst->cur_page_count * memory_inst->num_bytes_per_page; + return (size_t)memory_inst->cur_page_count + * memory_inst->num_bytes_per_page; } #endif From 3698f2279b43bfa33a364a70174b67a990ca5c35 Mon Sep 17 00:00:00 2001 From: "liang.he" Date: Mon, 13 Feb 2023 15:06:04 +0800 Subject: [PATCH 26/33] Improve wasm-c-api instantiation-time linking (#1902) Add APIs to help prepare the imports for the wasm-c-api `wasm_instance_new`: - wasm_importtype_is_linked - wasm_runtime_is_import_func_linked - wasm_runtime_is_import_global_linked - wasm_extern_new_empty For wasm-c-api, developer may use `wasm_module_imports` to get the import types info, check whether an import func/global is linked with the above API, and ignore the linking of an import func/global with `wasm_extern_new_empty`. Sample `wasm-c-api-import` is added and document is updated. --- core/iwasm/common/wasm_c_api.c | 439 +++++++++--------- core/iwasm/common/wasm_native.c | 9 +- core/iwasm/common/wasm_runtime_common.c | 22 + core/iwasm/common/wasm_runtime_common.h | 8 + core/iwasm/include/wasm_c_api.h | 4 + core/iwasm/include/wasm_export.h | 16 + core/iwasm/interpreter/wasm_loader.c | 9 +- .../lib-pthread/lib_pthread_wrapper.c | 41 ++ samples/wasm-c-api-imports/.gitignore | 2 + samples/wasm-c-api-imports/CMakeLists.txt | 169 +++++++ samples/wasm-c-api-imports/README.md | 174 +++++++ .../wasm-c-api-imports/host/CMakeLists.txt | 12 + samples/wasm-c-api-imports/host/example1.c | 204 ++++++++ .../wasm-c-api-imports/wasm/CMakeLists.txt | 47 ++ samples/wasm-c-api-imports/wasm/inc/.gitkeep | 0 samples/wasm-c-api-imports/wasm/send_recv.c | 231 +++++++++ 16 files changed, 1168 insertions(+), 219 deletions(-) create mode 100644 samples/wasm-c-api-imports/.gitignore create mode 100644 samples/wasm-c-api-imports/CMakeLists.txt create mode 100644 samples/wasm-c-api-imports/README.md create mode 100644 samples/wasm-c-api-imports/host/CMakeLists.txt create mode 100644 samples/wasm-c-api-imports/host/example1.c create mode 100644 samples/wasm-c-api-imports/wasm/CMakeLists.txt create mode 100644 samples/wasm-c-api-imports/wasm/inc/.gitkeep create mode 100644 samples/wasm-c-api-imports/wasm/send_recv.c diff --git a/core/iwasm/common/wasm_c_api.c b/core/iwasm/common/wasm_c_api.c index 325f231d..d3c8ea1e 100644 --- a/core/iwasm/common/wasm_c_api.c +++ b/core/iwasm/common/wasm_c_api.c @@ -398,7 +398,7 @@ wasm_engine_new_internal(mem_alloc_type_t type, const MemAllocOption *opts) } /* global engine instance */ -static wasm_engine_t *singleton_engine = NULL; +static wasm_engine_t *singleton_engine; #ifdef os_thread_local_attribute /* categorize wasm_store_t as threads*/ static os_thread_local_attribute unsigned thread_local_stores_num = 0; @@ -1458,6 +1458,30 @@ wasm_importtype_type(const wasm_importtype_t *import_type) return import_type->extern_type; } +bool +wasm_importtype_is_linked(const wasm_importtype_t *import_type) +{ + if (!import_type) + return false; + + const wasm_name_t *module_name = wasm_importtype_module(import_type); + const wasm_name_t *field_name = wasm_importtype_name(import_type); + + switch (wasm_externtype_kind(wasm_importtype_type(import_type))) { + case WASM_EXTERN_FUNC: + return wasm_runtime_is_import_func_linked(module_name->data, + field_name->data); + case WASM_EXTERN_GLOBAL: + return wasm_runtime_is_import_global_linked(module_name->data, + field_name->data); + case WASM_EXTERN_MEMORY: + case WASM_EXTERN_TABLE: + default: + break; + } + return false; +} + own wasm_exporttype_t * wasm_exporttype_new(own wasm_byte_vec_t *name, own wasm_externtype_t *extern_type) @@ -2537,12 +2561,12 @@ wasm_module_imports(const wasm_module_t *module, own wasm_importtype_vec_t *out) bh_assert(extern_type); - wasm_name_new_from_string(&module_name, module_name_rt); + wasm_name_new_from_string_nt(&module_name, module_name_rt); if (strlen(module_name_rt) && !module_name.data) { goto failed; } - wasm_name_new_from_string(&name, field_name_rt); + wasm_name_new_from_string_nt(&name, field_name_rt); if (strlen(field_name_rt) && !name.data) { goto failed; } @@ -2622,7 +2646,7 @@ wasm_module_exports(const wasm_module_t *module, wasm_exporttype_vec_t *out) } /* byte* -> wasm_byte_vec_t */ - wasm_name_new_from_string(&name, export->name); + wasm_name_new_from_string_nt(&name, export->name); if (strlen(export->name) && !name.data) { goto failed; } @@ -3008,6 +3032,20 @@ failed: return NULL; } +static wasm_func_t * +wasm_func_new_empty(wasm_store_t *store) +{ + wasm_func_t *func = NULL; + + if (!(func = malloc_internal(sizeof(wasm_func_t)))) + goto failed; + + func->store = store; + func->kind = WASM_EXTERN_FUNC; + + RETURN_OBJ(func, wasm_func_delete) +} + void wasm_func_delete(wasm_func_t *func) { @@ -3211,7 +3249,8 @@ wasm_func_call(const wasm_func_t *func, const wasm_val_vec_t *params, wasm_name_t message = { 0 }; wasm_trap_t *trap; - wasm_name_new_from_string(&message, "failed to call unlinked function"); + wasm_name_new_from_string_nt(&message, + "failed to call unlinked function"); trap = wasm_trap_new(func->store, &message); wasm_byte_vec_delete(&message); @@ -3371,6 +3410,25 @@ failed: return NULL; } +static wasm_global_t * +wasm_global_new_empty(wasm_store_t *store) +{ + wasm_global_t *global = NULL; + + global = malloc_internal(sizeof(wasm_global_t)); + if (!global) + goto failed; + + global->store = store; + global->kind = WASM_EXTERN_GLOBAL; + + return global; +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + wasm_global_delete(global); + return NULL; +} + /* almost same with wasm_global_new */ wasm_global_t * wasm_global_copy(const wasm_global_t *src) @@ -4288,6 +4346,11 @@ interp_link_func(const wasm_instance_t *inst, const WASMModule *module_interp, imported_func_interp = module_interp->import_functions + func_idx_rt; bh_assert(imported_func_interp); + bh_assert(imported_func_interp->kind == IMPORT_KIND_FUNC); + + /* it is a placeholder and let's skip it*/ + if (!import->type) + return true; /* type comparison */ if (!wasm_functype_same_internal( @@ -4302,6 +4365,8 @@ interp_link_func(const wasm_instance_t *inst, const WASMModule *module_interp, imported_func_interp->u.function.func_ptr_linked = import->u.cb_env.cb; else imported_func_interp->u.function.func_ptr_linked = import->u.cb; + bh_assert(imported_func_interp->u.function.func_ptr_linked); + import->func_idx_rt = func_idx_rt; (void)inst; @@ -4320,12 +4385,19 @@ interp_link_global(const WASMModule *module_interp, uint16 global_idx_rt, imported_global_interp = module_interp->import_globals + global_idx_rt; bh_assert(imported_global_interp); + bh_assert(imported_global_interp->kind == IMPORT_KIND_GLOBAL); + /* it is a placeholder and let's skip it*/ + if (!import->type) + return true; + + /* type comparison */ if (!cmp_val_kind_with_val_type(wasm_valtype_kind(import->type->val_type), imported_global_interp->u.global.type)) return false; /* set init value */ + bh_assert(import->init); switch (wasm_valtype_kind(import->type->val_type)) { case WASM_I32: imported_global_interp->u.global.global_data_linked.i32 = @@ -4352,58 +4424,6 @@ interp_link_global(const WASMModule *module_interp, uint16 global_idx_rt, return true; } -static bool -interp_link(const wasm_instance_t *inst, const WASMModule *module_interp, - wasm_extern_t *imports[]) -{ - uint32 i = 0; - uint32 import_func_i = 0; - uint32 import_global_i = 0; - - bh_assert(inst && module_interp && imports); - - for (i = 0; i < module_interp->import_count; ++i) { - wasm_extern_t *import = imports[i]; - WASMImport *import_rt = module_interp->imports + i; - - switch (import_rt->kind) { - case IMPORT_KIND_FUNC: - { - if (!interp_link_func(inst, module_interp, import_func_i, - wasm_extern_as_func(import))) { - LOG_WARNING("link #%d function failed", import_func_i); - goto failed; - } - import_func_i++; - break; - } - case IMPORT_KIND_GLOBAL: - { - if (!interp_link_global(module_interp, import_global_i, - wasm_extern_as_global(import))) { - LOG_WARNING("link #%d global failed", import_global_i); - goto failed; - } - import_global_i++; - break; - } - case IMPORT_KIND_MEMORY: - case IMPORT_KIND_TABLE: - default: - ASSERT_NOT_IMPLEMENTED(); - LOG_WARNING("%s meets unsupported kind: %d", __FUNCTION__, - import_rt->kind); - goto failed; - } - } - - return true; - -failed: - LOG_DEBUG("%s failed", __FUNCTION__); - return false; -} - static bool interp_process_export(wasm_store_t *store, const WASMModuleInstance *inst_interp, @@ -4503,6 +4523,10 @@ aot_link_func(const wasm_instance_t *inst, const AOTModule *module_aot, import_aot_func = module_aot->import_funcs + import_func_idx_rt; bh_assert(import_aot_func); + /* it is a placeholder and let's skip it*/ + if (!import->type) + return true; + /* type comparison */ if (!wasm_functype_same_internal(import->type, import_aot_func->func_type)) return false; @@ -4515,6 +4539,8 @@ aot_link_func(const wasm_instance_t *inst, const AOTModule *module_aot, import_aot_func->func_ptr_linked = import->u.cb_env.cb; else import_aot_func->func_ptr_linked = import->u.cb; + bh_assert(import_aot_func->func_ptr_linked); + import->func_idx_rt = import_func_idx_rt; return true; @@ -4532,6 +4558,10 @@ aot_link_global(const AOTModule *module_aot, uint16 global_idx_rt, import_aot_global = module_aot->import_globals + global_idx_rt; bh_assert(import_aot_global); + /* it is a placeholder and let's skip it*/ + if (!import->type) + return true; + val_type = wasm_globaltype_content(import->type); bh_assert(val_type); @@ -4539,6 +4569,7 @@ aot_link_global(const AOTModule *module_aot, uint16 global_idx_rt, import_aot_global->type)) return false; + bh_assert(import->init); switch (wasm_valtype_kind(val_type)) { case WASM_I32: import_aot_global->global_data_linked.i32 = import->init->of.i32; @@ -4559,62 +4590,6 @@ aot_link_global(const AOTModule *module_aot, uint16 global_idx_rt, import->global_idx_rt = global_idx_rt; import_aot_global->is_linked = true; return true; - -failed: - LOG_DEBUG("%s failed", __FUNCTION__); - return false; -} - -static bool -aot_link(const wasm_instance_t *inst, const AOTModule *module_aot, - wasm_extern_t *imports[]) -{ - uint32 i = 0; - uint32 import_func_i = 0; - uint32 import_global_i = 0; - wasm_extern_t *import = NULL; - wasm_func_t *func = NULL; - wasm_global_t *global = NULL; - - bh_assert(inst && module_aot && imports); - - while (import_func_i < module_aot->import_func_count - || import_global_i < module_aot->import_global_count) { - import = imports[i++]; - - bh_assert(import); - - switch (wasm_extern_kind(import)) { - case WASM_EXTERN_FUNC: - bh_assert(import_func_i < module_aot->import_func_count); - func = wasm_extern_as_func((wasm_extern_t *)import); - if (!aot_link_func(inst, module_aot, import_func_i, func)) { - LOG_WARNING("link #%d function failed", import_func_i); - goto failed; - } - import_func_i++; - - break; - case WASM_EXTERN_GLOBAL: - bh_assert(import_global_i < module_aot->import_global_count); - global = wasm_extern_as_global((wasm_extern_t *)import); - if (!aot_link_global(module_aot, import_global_i, global)) { - LOG_WARNING("link #%d global failed", import_global_i); - goto failed; - } - import_global_i++; - - break; - case WASM_EXTERN_MEMORY: - case WASM_EXTERN_TABLE: - default: - ASSERT_NOT_IMPLEMENTED(); - goto failed; - } - } - - return true; - failed: LOG_DEBUG("%s failed", __FUNCTION__); return false; @@ -4695,7 +4670,7 @@ aot_process_export(wasm_store_t *store, const AOTModuleInstance *inst_aot, goto failed; } - wasm_name_new_from_string(external->name, export->name); + wasm_name_new_from_string_nt(external->name, export->name); if (strlen(export->name) && !external->name->data) { goto failed; } @@ -4713,6 +4688,95 @@ failed: } #endif /* WASM_ENABLE_AOT */ +static bool +do_link(const wasm_instance_t *inst, const wasm_module_t *module, + const wasm_extern_vec_t *imports) +{ + uint32 i, import_func_i, import_global_i; + + bh_assert(inst && module); + + /* we have run a module_type check before. */ + + for (i = 0, import_func_i = 0, import_global_i = 0; i < imports->num_elems; + i++) { + wasm_extern_t *import = imports->data[i]; + + if (!import) { + LOG_ERROR("imports[%d] is NULL and it is fatal\n", i); + goto failed; + } + + switch (wasm_extern_kind(import)) { + case WASM_EXTERN_FUNC: + { + bool ret = false; +#if WASM_ENABLE_INTERP != 0 + if ((*module)->module_type == Wasm_Module_Bytecode) { + ret = interp_link_func(inst, MODULE_INTERP(module), + import_func_i, + wasm_extern_as_func(import)); + } +#endif +#if WASM_ENABLE_AOT != 0 + if ((*module)->module_type == Wasm_Module_AoT) { + ret = aot_link_func(inst, MODULE_AOT(module), import_func_i, + wasm_extern_as_func(import)); + } +#endif + if (!ret) { + LOG_WARNING("link function #%d failed", import_func_i); + goto failed; + } + + import_func_i++; + break; + } + case WASM_EXTERN_GLOBAL: + { + bool ret = false; +#if WASM_ENABLE_INTERP != 0 + if ((*module)->module_type == Wasm_Module_Bytecode) { + ret = interp_link_global(MODULE_INTERP(module), + import_global_i, + wasm_extern_as_global(import)); + } +#endif +#if WASM_ENABLE_AOT != 0 + if ((*module)->module_type == Wasm_Module_AoT) { + ret = aot_link_global(MODULE_AOT(module), import_global_i, + wasm_extern_as_global(import)); + } +#endif + if (!ret) { + LOG_WARNING("link global #%d failed", import_global_i); + goto failed; + } + + import_global_i++; + break; + } + case WASM_EXTERN_MEMORY: + case WASM_EXTERN_TABLE: + { + LOG_WARNING("doesn't support import memories and tables for " + "now, ignore them"); + break; + } + default: + { + UNREACHABLE(); + break; + } + } + } + + return true; +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + return false; +} + wasm_instance_t * wasm_instance_new(wasm_store_t *store, const wasm_module_t *module, const wasm_extern_vec_t *imports, own wasm_trap_t **trap) @@ -4721,57 +4785,6 @@ wasm_instance_new(wasm_store_t *store, const wasm_module_t *module, KILOBYTE(32), KILOBYTE(32)); } -static bool -compare_imports(const wasm_module_t *module, const wasm_extern_vec_t *imports) -{ - unsigned import_func_count = 0; - unsigned import_global_count = 0; - unsigned import_memory_count = 0; - unsigned import_table_count = 0; - unsigned i = 0; - - for (i = 0; imports && i < imports->num_elems; i++) { - wasm_extern_t *import = imports->data[i]; - switch (wasm_extern_kind(import)) { - case WASM_EXTERN_FUNC: - import_func_count++; - break; - case WASM_EXTERN_GLOBAL: - import_global_count++; - break; - case WASM_EXTERN_MEMORY: - import_memory_count++; - break; - case WASM_EXTERN_TABLE: - import_table_count++; - break; - default: - UNREACHABLE(); - return false; - } - } - -#if WASM_ENABLE_INTERP != 0 - if ((*module)->module_type == Wasm_Module_Bytecode) - return import_func_count == MODULE_INTERP(module)->import_function_count - && import_global_count - == MODULE_INTERP(module)->import_global_count - && import_memory_count - == MODULE_INTERP(module)->import_memory_count - && import_table_count - == MODULE_INTERP(module)->import_table_count; -#endif -#if WASM_ENABLE_AOT != 0 - if ((*module)->module_type == Wasm_Module_AoT) - return import_func_count == MODULE_AOT(module)->import_func_count - && import_global_count == MODULE_AOT(module)->import_global_count - && import_memory_count == MODULE_AOT(module)->import_memory_count - && import_table_count == MODULE_AOT(module)->import_table_count; -#endif - - return false; -} - wasm_instance_t * wasm_instance_new_with_args(wasm_store_t *store, const wasm_module_t *module, const wasm_extern_vec_t *imports, @@ -4781,7 +4794,6 @@ wasm_instance_new_with_args(wasm_store_t *store, const wasm_module_t *module, char sub_error_buf[128] = { 0 }; char error_buf[256] = { 0 }; wasm_instance_t *instance = NULL; - WASMModuleInstance *inst_rt; CApiFuncImport *func_import = NULL, **p_func_imports = NULL; uint32 i = 0, import_func_count = 0; uint64 total_size; @@ -4792,11 +4804,9 @@ wasm_instance_new_with_args(wasm_store_t *store, const wasm_module_t *module, if (!module) return NULL; - if (!compare_imports(module, imports)) { - snprintf(sub_error_buf, sizeof(sub_error_buf), - "Failed to match imports"); - goto failed; - } + /* + * will do the check at the end of wasm_runtime_instantiate + */ WASM_C_DUMP_PROC_MEM(); @@ -4807,43 +4817,17 @@ wasm_instance_new_with_args(wasm_store_t *store, const wasm_module_t *module, goto failed; } - /* link module and imports */ - if (imports && imports->num_elems) { - bool link = false; -#if WASM_ENABLE_INTERP != 0 - if ((*module)->module_type == Wasm_Module_Bytecode) { - if (!interp_link(instance, MODULE_INTERP(module), - (wasm_extern_t **)imports->data)) { - snprintf(sub_error_buf, sizeof(sub_error_buf), - "Failed to validate imports"); - goto failed; - } - link = true; - } -#endif - -#if WASM_ENABLE_AOT != 0 - if ((*module)->module_type == Wasm_Module_AoT) { - if (!aot_link(instance, MODULE_AOT(module), - (wasm_extern_t **)imports->data)) { - snprintf(sub_error_buf, sizeof(sub_error_buf), - "Failed to validate imports"); - goto failed; - } - link = true; - } -#endif - - /* - * a wrong combination of module filetype and compilation flags - * also leads to below branch - */ - if (!link) { + /* executes the instantiate-time linking if provided */ + if (imports) { + if (!do_link(instance, module, imports)) { snprintf(sub_error_buf, sizeof(sub_error_buf), - "Failed to verify import count"); + "Failed to validate imports"); goto failed; } } + /* + * will do the linking result check at the end of wasm_runtime_instantiate + */ instance->inst_comm_rt = wasm_runtime_instantiate( *module, stack_size, heap_size, sub_error_buf, sizeof(sub_error_buf)); @@ -4858,18 +4842,22 @@ wasm_instance_new_with_args(wasm_store_t *store, const wasm_module_t *module, } /* create the c-api func import list */ - inst_rt = (WASMModuleInstance *)instance->inst_comm_rt; #if WASM_ENABLE_INTERP != 0 if (instance->inst_comm_rt->module_type == Wasm_Module_Bytecode) { - p_func_imports = &inst_rt->e->c_api_func_imports; - import_func_count = inst_rt->module->import_function_count; + WASMModuleInstanceExtra *e = + ((WASMModuleInstance *)instance->inst_comm_rt)->e; + p_func_imports = &(e->c_api_func_imports); + import_func_count = MODULE_INTERP(module)->import_function_count; } #endif #if WASM_ENABLE_AOT != 0 if (instance->inst_comm_rt->module_type == Wasm_Module_AoT) { - p_func_imports = - &((AOTModuleInstanceExtra *)inst_rt->e)->c_api_func_imports; - import_func_count = ((AOTModule *)inst_rt->module)->import_func_count; + AOTModuleInstanceExtra *e = + (AOTModuleInstanceExtra *)((AOTModuleInstance *) + instance->inst_comm_rt) + ->e; + p_func_imports = &(e->c_api_func_imports); + import_func_count = MODULE_AOT(module)->import_func_count; } #endif bh_assert(p_func_imports); @@ -4882,16 +4870,21 @@ wasm_instance_new_with_args(wasm_store_t *store, const wasm_module_t *module, goto failed; } - /* fill in c-api func import list */ + /* fill in module_inst->e->c_api_func_imports */ for (i = 0; imports && i < imports->num_elems; i++) { - wasm_func_t *func_host; - wasm_extern_t *in; + wasm_func_t *func_host = NULL; + wasm_extern_t *in = imports->data[i]; + bh_assert(in); - in = imports->data[i]; if (wasm_extern_kind(in) != WASM_EXTERN_FUNC) continue; func_host = wasm_extern_as_func(in); + /* it is a placeholder and let's skip it*/ + if (!func_host->type) { + func_import++; + continue; + } func_import->with_env_arg = func_host->with_env; if (func_host->with_env) { @@ -4902,6 +4895,7 @@ wasm_instance_new_with_args(wasm_store_t *store, const wasm_module_t *module, func_import->func_ptr_linked = func_host->u.cb; func_import->env_arg = NULL; } + bh_assert(func_import->func_ptr_linked); func_import++; } @@ -4909,6 +4903,8 @@ wasm_instance_new_with_args(wasm_store_t *store, const wasm_module_t *module, /* fill with inst */ for (i = 0; imports && imports->data && i < imports->num_elems; ++i) { wasm_extern_t *import = imports->data[i]; + bh_assert(import); + switch (import->kind) { case WASM_EXTERN_FUNC: wasm_extern_as_func(import)->inst_comm_rt = @@ -5004,7 +5000,7 @@ failed: sub_error_buf); if (trap != NULL) { wasm_message_t message = { 0 }; - wasm_name_new_from_string(&message, error_buf); + wasm_name_new_from_string_nt(&message, error_buf); *trap = wasm_trap_new(store, &message); wasm_byte_vec_delete(&message); } @@ -5204,3 +5200,16 @@ BASIC_FOUR_LIST(WASM_EXTERN_AS_OTHER_CONST) BASIC_FOUR_LIST(WASM_OTHER_AS_EXTERN_CONST) #undef WASM_OTHER_AS_EXTERN_CONST + +wasm_extern_t * +wasm_extern_new_empty(wasm_store_t *store, wasm_externkind_t extern_kind) +{ + if (extern_kind == WASM_EXTERN_FUNC) + return wasm_func_as_extern(wasm_func_new_empty(store)); + + if (extern_kind == WASM_EXTERN_GLOBAL) + return wasm_global_as_extern(wasm_global_new_empty(store)); + + LOG_ERROR("Don't support linking table and memory for now"); + return NULL; +} diff --git a/core/iwasm/common/wasm_native.c b/core/iwasm/common/wasm_native.c index 0fa59627..8fe014ea 100644 --- a/core/iwasm/common/wasm_native.c +++ b/core/iwasm/common/wasm_native.c @@ -239,6 +239,10 @@ lookup_symbol(NativeSymbol *native_symbols, uint32 n_native_symbols, return NULL; } +/** + * allow func_type and all outputs, like p_signature, p_attachment and + * p_call_conv_raw to be NULL + */ void * wasm_native_resolve_symbol(const char *module_name, const char *field_name, const WASMType *func_type, const char **p_signature, @@ -264,10 +268,13 @@ wasm_native_resolve_symbol(const char *module_name, const char *field_name, node = node_next; } + if (!p_signature || !p_attachment || !p_call_conv_raw) + return func_ptr; + if (func_ptr) { if (signature && signature[0] != '\0') { /* signature is not empty, check its format */ - if (!check_symbol_signature(func_type, signature)) { + if (!func_type || !check_symbol_signature(func_type, signature)) { #if WASM_ENABLE_WAMR_COMPILER == 0 /* Output warning except running aot compiler */ LOG_WARNING("failed to check signature '%s' and resolve " diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index 8662af1c..c820de7b 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -7,6 +7,7 @@ #include "bh_common.h" #include "bh_assert.h" #include "bh_log.h" +#include "wasm_native.h" #include "wasm_runtime_common.h" #include "wasm_memory.h" #if WASM_ENABLE_INTERP != 0 @@ -5331,3 +5332,24 @@ wasm_runtime_get_version(uint32_t *major, uint32_t *minor, uint32_t *patch) *minor = WAMR_VERSION_MINOR; *patch = WAMR_VERSION_PATCH; } + +bool +wasm_runtime_is_import_func_linked(const char *module_name, + const char *func_name) +{ + return wasm_native_resolve_symbol(module_name, func_name, NULL, NULL, NULL, + NULL); +} + +bool +wasm_runtime_is_import_global_linked(const char *module_name, + const char *global_name) +{ +#if WASM_ENABLE_LIBC_BUILTIN != 0 + WASMGlobalImport global = { 0 }; + return wasm_native_lookup_libc_builtin_global(module_name, global_name, + &global); +#else + return false; +#endif +} diff --git a/core/iwasm/common/wasm_runtime_common.h b/core/iwasm/common/wasm_runtime_common.h index a70c9fb6..e01f91ab 100644 --- a/core/iwasm/common/wasm_runtime_common.h +++ b/core/iwasm/common/wasm_runtime_common.h @@ -993,6 +993,14 @@ void wasm_runtime_destroy_custom_sections(WASMCustomSection *section_list); #endif +WASM_RUNTIME_API_EXTERN bool +wasm_runtime_is_import_func_linked(const char *module_name, + const char *func_name); + +WASM_RUNTIME_API_EXTERN bool +wasm_runtime_is_import_global_linked(const char *module_name, + const char *global_name); + #ifdef __cplusplus } #endif diff --git a/core/iwasm/include/wasm_c_api.h b/core/iwasm/include/wasm_c_api.h index 85fcd186..324a43bd 100644 --- a/core/iwasm/include/wasm_c_api.h +++ b/core/iwasm/include/wasm_c_api.h @@ -354,6 +354,7 @@ WASM_API_EXTERN own wasm_importtype_t* wasm_importtype_new( WASM_API_EXTERN const wasm_name_t* wasm_importtype_module(const wasm_importtype_t*); WASM_API_EXTERN const wasm_name_t* wasm_importtype_name(const wasm_importtype_t*); WASM_API_EXTERN const wasm_externtype_t* wasm_importtype_type(const wasm_importtype_t*); +WASM_API_EXTERN bool wasm_importtype_is_linked(const wasm_importtype_t*); // Export Types @@ -797,6 +798,9 @@ static inline void* wasm_val_ptr(const wasm_val_t* val) { #define KILOBYTE(n) ((n) * 1024) +// Create placeholders filled in `wasm_externvec_t* imports` for `wasm_instance_new()` +WASM_API_EXTERN wasm_extern_t *wasm_extern_new_empty(wasm_store_t *, wasm_externkind_t); + /////////////////////////////////////////////////////////////////////////////// #undef own diff --git a/core/iwasm/include/wasm_export.h b/core/iwasm/include/wasm_export.h index 161a4905..3bb5f873 100644 --- a/core/iwasm/include/wasm_export.h +++ b/core/iwasm/include/wasm_export.h @@ -1324,6 +1324,22 @@ wasm_runtime_get_custom_section(wasm_module_t const module_comm, */ WASM_RUNTIME_API_EXTERN void wasm_runtime_get_version(uint32_t *major, uint32_t *minor, uint32_t *patch); + +/** + * Check whether an import func `(import (func ...))` is linked or not + * with runtime registered natvie functions + */ +WASM_RUNTIME_API_EXTERN bool +wasm_runtime_is_import_func_linked(const char *module_name, + const char *func_name); + +/** + * Check whether an import global `(import (global ...))` is linked or not + * with runtime registered natvie globals + */ +WASM_RUNTIME_API_EXTERN bool +wasm_runtime_is_import_global_linked(const char *module_name, + const char *global_name); /* clang-format on */ #ifdef __cplusplus diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index 4c6c6aaa..5a9fcbfb 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -1399,6 +1399,7 @@ load_global_import(const uint8 **p_buf, const uint8 *buf_end, WASMModule *sub_module = NULL; WASMGlobal *linked_global = NULL; #endif + bool ret = false; CHECK_BUF(p, p_end, 2); declare_type = read_uint8(p); @@ -1411,15 +1412,16 @@ load_global_import(const uint8 **p_buf, const uint8 *buf_end, } #if WASM_ENABLE_LIBC_BUILTIN != 0 - global->is_linked = wasm_native_lookup_libc_builtin_global( - sub_module_name, global_name, global); - if (global->is_linked) { + ret = wasm_native_lookup_libc_builtin_global(sub_module_name, global_name, + global); + if (ret) { if (global->type != declare_type || global->is_mutable != declare_mutable) { set_error_buf(error_buf, error_buf_size, "incompatible import type"); return false; } + global->is_linked = true; } #endif #if WASM_ENABLE_MULTI_MODULE != 0 @@ -1449,6 +1451,7 @@ load_global_import(const uint8 **p_buf, const uint8 *buf_end, global->is_mutable = (declare_mutable == 1); (void)parent_module; + (void)ret; return true; fail: return false; diff --git a/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c b/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c index 3bf3269b..4f8cc059 100644 --- a/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c +++ b/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c @@ -570,6 +570,7 @@ pthread_create_wrapper(wasm_exec_env_t exec_env, #if WASM_ENABLE_LIBC_WASI != 0 WASIContext *wasi_ctx; #endif + CApiFuncImport **new_c_api_func_imports = NULL; bh_assert(module); bh_assert(module_inst); @@ -602,6 +603,46 @@ pthread_create_wrapper(wasm_exec_env_t exec_env, wasm_runtime_set_wasi_ctx(new_module_inst, wasi_ctx); #endif + /* workaround about passing instantiate-linking information */ + { + CApiFuncImport *c_api_func_imports; + uint32 import_func_count = 0; + uint32 size_in_bytes = 0; + +#if WASM_ENABLE_INTERP != 0 + if (module_inst->module_type == Wasm_Module_Bytecode) { + new_c_api_func_imports = &( + ((WASMModuleInstance *)new_module_inst)->e->c_api_func_imports); + c_api_func_imports = + ((WASMModuleInstance *)module_inst)->e->c_api_func_imports; + import_func_count = ((WASMModule *)module)->import_function_count; + } +#endif +#if WASM_ENABLE_AOT != 0 + if (module_inst->module_type == Wasm_Module_AoT) { + AOTModuleInstanceExtra *e = + (AOTModuleInstanceExtra *)((AOTModuleInstance *)new_module_inst) + ->e; + new_c_api_func_imports = &(e->c_api_func_imports); + + e = (AOTModuleInstanceExtra *)((AOTModuleInstance *)module_inst)->e; + c_api_func_imports = e->c_api_func_imports; + + import_func_count = ((AOTModule *)module)->import_func_count; + } +#endif + + if (import_func_count != 0 && c_api_func_imports) { + size_in_bytes = sizeof(CApiFuncImport *) * import_func_count; + *new_c_api_func_imports = wasm_runtime_malloc(size_in_bytes); + if (!(*new_c_api_func_imports)) + goto fail; + + bh_memcpy_s(*new_c_api_func_imports, size_in_bytes, + c_api_func_imports, size_in_bytes); + } + } + if (!(info_node = wasm_runtime_malloc(sizeof(ThreadInfoNode)))) goto fail; diff --git a/samples/wasm-c-api-imports/.gitignore b/samples/wasm-c-api-imports/.gitignore new file mode 100644 index 00000000..ab998a6e --- /dev/null +++ b/samples/wasm-c-api-imports/.gitignore @@ -0,0 +1,2 @@ +/wasm/inc/** +!/wasm/inc/.* diff --git a/samples/wasm-c-api-imports/CMakeLists.txt b/samples/wasm-c-api-imports/CMakeLists.txt new file mode 100644 index 00000000..7d65c9b2 --- /dev/null +++ b/samples/wasm-c-api-imports/CMakeLists.txt @@ -0,0 +1,169 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required(VERSION 3.14) +project(how-to-deal-with-import) + +include(CMakePrintHelpers) +include(CTest) +include(ExternalProject) +include(FetchContent) + +# +# dependencies +# +set(WAMR_ROOT ${CMAKE_CURRENT_LIST_DIR}/../../) +# wasm required headers +execute_process( + COMMAND ${CMAKE_COMMAND} -E copy_if_different + ${WARM_ROOT}/${WAMR_ROOT}/wamr-sdk/app/libc-builtin-sysroot/include/pthread.h + ${CMAKE_CURRENT_LIST_DIR}/wasm/inc +) + +# vmlib +################ runtime settings ################ +string (TOLOWER ${CMAKE_HOST_SYSTEM_NAME} WAMR_BUILD_PLATFORM) +if (APPLE) + add_definitions(-DBH_PLATFORM_DARWIN) +endif () + +# Resetdefault linker flags +set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") +set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") + +# WAMR features switch + +# Set WAMR_BUILD_TARGET, currently values supported: +# "X86_64", "AMD_64", "X86_32", "AARCH64[sub]", "ARM[sub]", "THUMB[sub]", +# "MIPS", "XTENSA", "RISCV64[sub]", "RISCV32[sub]" +if (NOT DEFINED WAMR_BUILD_TARGET) + if (CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm64|aarch64)") + set (WAMR_BUILD_TARGET "AARCH64") + elseif (CMAKE_SYSTEM_PROCESSOR STREQUAL "riscv64") + set (WAMR_BUILD_TARGET "RISCV64") + elseif (CMAKE_SIZEOF_VOID_P EQUAL 8) + # Build as X86_64 by default in 64-bit platform + set (WAMR_BUILD_TARGET "X86_64") + elseif (CMAKE_SIZEOF_VOID_P EQUAL 4) + # Build as X86_32 by default in 32-bit platform + set (WAMR_BUILD_TARGET "X86_32") + else () + message(SEND_ERROR "Unsupported build target platform!") + endif () +endif () + +if (NOT CMAKE_BUILD_TYPE) + set (CMAKE_BUILD_TYPE Release) +endif () + +set(WAMR_BUILD_AOT 1) +set(WAMR_BUILD_INTERP 0) +set(WAMR_BUILD_JIT 0) + +set(WAMR_BUILD_FAST_INTERP 1) +set(WAMR_BUILD_LIB_PTHREAD 1) +set(WAMR_BUILD_LIBC_BUILTIN 1) +set(WAMR_BUILD_LIBC_WASI 1) +set(WAMR_BUILD_SIMD 0) + +# compiling and linking flags +if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang")) + set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") +endif () +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat -Wformat-security") + +# build out vmlib +set(WAMR_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../..) +include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) + +add_library(vmlib ${WAMR_RUNTIME_LIB_SOURCE}) +target_link_libraries(vmlib INTERFACE dl m pthread) +if(WAMR_BUILD_AOT EQUAL 1) + target_compile_definitions(vmlib INTERFACE -DWASM_ENABLE_AOT=1) +else() + target_compile_definitions(vmlib INTERFACE -DWASM_ENABLE_AOT=0) +endif() + +if(WAMR_BUILD_INTERP EQUAL 1) + target_compile_definitions(vmlib INTERFACE -DWASM_ENABLE_INTERP=1) +else() + target_compile_definitions(vmlib INTERFACE -DWASM_ENABLE_INTERP=0) +endif() + +if(CMAKE_BUILD_TYPE STREQUAL "Debug") + # ASAN + UBSAN + target_compile_options(vmlib INTERFACE -fsanitize=address,undefined) + target_link_options(vmlib INTERFACE -fsanitize=address,undefined) +endif() + +# # MSAN +# target_compile_options(vmlib INTERFACE -fsanitize=memory -fno-optimize-sibling-calls -fsanitize-memory-track-origins=2 -fno-omit-frame-pointer) +# target_link_options(vmlib INTERFACE -fsanitize=memory) + +# wamrc +if(WAMR_BUILD_AOT EQUAL 1 AND WAMR_BUILD_INTERP EQUAL 0) + ExternalProject_Add(wamrc + PREFIX wamrc-build + SOURCE_DIR ${WAMR_ROOT}/wamr-compiler + CONFIGURE_COMMAND ${CMAKE_COMMAND} -S ${WAMR_ROOT}/wamr-compiler -B build + BUILD_COMMAND ${CMAKE_COMMAND} --build build --target wamrc + INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_if_different build/wamrc ${CMAKE_CURRENT_BINARY_DIR}/wamrc + ) +endif() + +# +# host +add_subdirectory(host) +add_custom_target( + install_host ALL + COMMAND ${CMAKE_COMMAND} -E copy_if_different ./host/example1 . + DEPENDS example1 + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} +) + +# TODO: replace it with a find_package() +set(WASI_SDK_DIR /opt/wasi-sdk-19.0/) +set(WASI_TOOLCHAIN_FILE ${WASI_SDK_DIR}/share/cmake/wasi-sdk.cmake) +set(WASI_SYS_ROOT ${WASI_SDK_DIR}/share/wasi-sysroot) + +# +# wasm +if(WAMR_BUILD_AOT EQUAL 1 AND WAMR_BUILD_INTERP EQUAL 0) + ExternalProject_Add(wasm + PREFIX wasm-build + DEPENDS wamrc + BUILD_ALWAYS TRUE + SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/wasm + CONFIGURE_COMMAND ${CMAKE_COMMAND} -S ${CMAKE_CURRENT_LIST_DIR}/wasm -B build + -DWASI_SDK_PREFIX=${WASI_SDK_DIR} + -DCMAKE_TOOLCHAIN_FILE=${WASI_TOOLCHAIN_FILE} + -DCMAKE_SYSROOT=${WASI_SYS_ROOT} + -DWASM_TO_AOT=ON + -DWAMRC_PATH=${CMAKE_CURRENT_BINARY_DIR}/wamrc + -DSOCKET_WASI_CMAKE=${WAMR_ROOT}/core/iwasm/libraries/lib-socket/lib_socket_wasi.cmake + BUILD_COMMAND ${CMAKE_COMMAND} --build build + INSTALL_COMMAND ${CMAKE_COMMAND} --install build --prefix ${CMAKE_CURRENT_BINARY_DIR} + ) +else() + ExternalProject_Add(wasm + PREFIX wasm-build + BUILD_ALWAYS TRUE + SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/wasm + CONFIGURE_COMMAND ${CMAKE_COMMAND} -S ${CMAKE_CURRENT_LIST_DIR}/wasm -B build + -DWASI_SDK_PREFIX=${WASI_SDK_DIR} + -DCMAKE_TOOLCHAIN_FILE=${WASI_TOOLCHAIN_FILE} + -DCMAKE_SYSROOT=${WASI_SYS_ROOT} + -DSOCKET_WASI_CMAKE=${WAMR_ROOT}/core/iwasm/libraries/lib-socket/lib_socket_wasi.cmake + BUILD_COMMAND ${CMAKE_COMMAND} --build build + INSTALL_COMMAND ${CMAKE_COMMAND} --install build --prefix ${CMAKE_CURRENT_BINARY_DIR} + ) +endif() + +# +# Test +# +add_test( + NAME run_example1 + COMMAND ./example1 + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} +) diff --git a/samples/wasm-c-api-imports/README.md b/samples/wasm-c-api-imports/README.md new file mode 100644 index 00000000..9b61a6e7 --- /dev/null +++ b/samples/wasm-c-api-imports/README.md @@ -0,0 +1,174 @@ +# How to create `imports` for wasm_instance_new() properly + +It's always been asked how to create `wasm_extern_vec_t *imports` for +`wasm_instance_new()`? + +```c +WASM_API_EXTERN own wasm_instance_t* wasm_instance_new( + wasm_store_t*, const wasm_module_t*, const wasm_extern_vec_t *imports, + own wasm_trap_t** trap +); +``` + +`wasm_extern_vec_t *imports` is required to match the requirement of _the +import section_ of a .wasm. + +```bash +$ /opt/wabt-1.0.31/bin/wasm-objdump -j Import -x .wasm + +Section Details: + +Import[27]: + - func[0] sig=2 <- env.pthread_mutex_lock + - func[1] sig=2 <- env.pthread_mutex_unlock + - func[2] sig=2 <- env.pthread_cond_signal + - func[3] sig=3 <- env.log + ... + - func[11] sig=4 <__imported_wasi_snapshot_preview1_sock_bind> <- wasi_snapshot_preview1.sock_bind + - func[12] sig=4 <__imported_wasi_snapshot_preview1_sock_connect> <- wasi_snapshot_preview1.sock_connect + - func[13] sig=4 <__imported_wasi_snapshot_preview1_sock_listen> <- wasi_snapshot_preview1.sock_listen + - func[14] sig=5 <__imported_wasi_snapshot_preview1_sock_open> <- wasi_snapshot_preview1.sock_open + - func[15] sig=4 <__imported_wasi_snapshot_preview1_sock_addr_remote> <- wasi_snapshot_preview1.sock_addr_remote + - func[16] sig=4 <__imported_wasi_snapshot_preview1_args_get> <- wasi_snapshot_preview1.args_get + - func[17] sig=4 <__imported_wasi_snapshot_preview1_args_sizes_get> <- wasi_snapshot_preview1.args_sizes_get + ... +``` + +Developers should fill in _imports_ with enough host functions and make sure +there are no linking problems during instantiation. + +```bash +TODO: linking warnings +``` + +## A natural way + +One natural answer is "to create a list which matches every item in _the import +section_" of the .wasm. Since developers can see the section details of +a .wasm by tools like _wasm-objdump_, the answer is doable. Most of the time, +if they also prepare Wasm modules, developers have full control over import +requirements, and they only need to take a look at the order of _the import +section_. + +Yes, _the order_. A proper `wasm_extern_vec_t *imports` includes two things: + +1. how many `wasm_extern_t` +2. and order of those + +Because there is no "name information" in a `wasm_extern_t`. The only way is let +`wasm_instance_new()` to tell which item in _the import section_ of a .wasm +should match any item in `wasm_extern_vec_t *imports` is based on **_index_**. + +The algorithm is quite straightforward. The first one of _the import section_ matches +`wasm_extern_vec_t *imports->data[0] `. The second one matches `wasm_extern_vec_t *imports->data[1]`. +And so on. + +So the order of `wasm_extern_vec_t *imports` becomes quite a burden. It requires +developers always checking _the import section_ visually. + +Until here, the natural way is still workable although involving some handy work. +Right? + +## A blocker + +Sorry, the situation changes a lot when driving wasm32-wasi Wasm modules with +wasm-c-api. + +As you know, WASI provides _a set of crossing-platform standard libraries_ for +Wasm modules, and leaves some _interfaces_ for native platform-dependent supports. +Those _interfaces_ are those import items with the module name `wasi_snapshot_preview1` +in a Wasm module. + +It seems not economical to let developers provide their version of host +implementations of the `wasi_snapshot_preview1.XXX` functions. All those support +should be packed into a common library and shared in different Wasm modules. +Like a [cargo WASI](https://github.com/bytecodealliance/cargo-wasi). + +WAMR chooses to integrate the WASI support library in the runtime to reduce +developers' compilation work. It brings developers a new thing of a proper +`wasm_extern_vec_t *imports` that developers should avoid overwriting those items +of _the import section_ of a Wasm module that will be provided by the runtime. It +also not economical to code for those functions. + +Using module names as a filter seems to be a simple way. But some private +additional c/c++ libraries are supported in WAMR. Those supporting will bring +more import items that don't use `wasi_snapshot_preview1` as module names but are still +covered by the WASM runtime. Like `env.pthread_`. Plus, [the native lib registeration](https://github.com/bytecodealliance/wasm-micro-runtime/blob/main/doc/export_native_api.md) +provides another possible way to fill in the requirement of _the import section_. + +Let's take summarize. A proper `wasm_extern_vec_t *imports` should include: + +1. provides all necessary host implementations for items in _the import section_ +2. should not override runtime provided implementation or covered by native + registrations. functinal or econmical. +3. keep them in a right order + +## A recommendation + +The recommendation is: + +- use `wasm_module_imports()` to build the order +- use `wasm_importtype_is_linked()` to avoid overwriting + +[wasm-c-api-imports](.) is a simple showcase of how to do that. + +First, let's take a look at the Wasm module. [send_recv](./wasm/send_recv.c) +uses both standard WASI and WAMR_BUILD_LIB_PTHREAD supporting. Plus a private +native function `host_log`. + +So, `wasm_extern_vec_t *imports` should only include the host implementation of +`host_log` and avoid WASI related(`wasm-c-api-imports.XXX`) and pthread related(`env.pthread_XXX`). + +[Here is how to do](./host/example1.c): + +- get import types with `wasm_module_imports(0)`. it contains name information + +```c + wasm_importtype_vec_t importtypes = { 0 }; + wasm_module_imports(module, &importtypes); +``` + +- traversal import types. The final `wasm_importvec_t *imports` should have the + same order with `wasm_importtype_vec_t` + +```c + for (unsigned i = 0; i < importtypes.num_elems; i++) +``` + +- use `wasm_importtype_is_linked()` to avoid those covered by the runtime and + registered natives. A little tip is use "wasm_extern_new_empty()" to create + a placeholder. + +```c + /* use wasm_extern_new_empty() to create a placeholder */ + if (wasm_importtype_is_linked(importtype)) { + externs[i] = wasm_extern_new_empty( + store, wasm_externtype_kind(wasm_importtype_type(importtype))); + continue; + } +``` + +- use `wasm_importtype_module()` to get the module name, use `wasm_importtype_name()` + to get the field name. + +```c + const wasm_name_t *module_name = + wasm_importtype_module(importtypes.data[i]); + const wasm_name_t *field_name = + wasm_importtype_name(importtypes.data[i]); +``` + +- fill in `wasm_externvec_t *imports` dynamically and programmatically. + +```c + if (strncmp(module_name->data, "env", strlen("env")) == 0 + && strncmp(field_name->data, "log", strlen("log")) == 0) { + wasm_functype_t *log_type = wasm_functype_new_2_0( + wasm_valtype_new_i64(), wasm_valtype_new_i32()); + wasm_func_t *log_func = wasm_func_new(store, log_type, host_logs); + wasm_functype_delete(log_type); + + externs[i] = wasm_func_as_extern(log_func); + } + } +``` diff --git a/samples/wasm-c-api-imports/host/CMakeLists.txt b/samples/wasm-c-api-imports/host/CMakeLists.txt new file mode 100644 index 00000000..e2636f09 --- /dev/null +++ b/samples/wasm-c-api-imports/host/CMakeLists.txt @@ -0,0 +1,12 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required(VERSION 3.14) +project(host) + +set(CMAKE_BUILD_TYPE Debug) + +# +# host +add_executable(example1 ./example1.c) +target_link_libraries(example1 vmlib) diff --git a/samples/wasm-c-api-imports/host/example1.c b/samples/wasm-c-api-imports/host/example1.c new file mode 100644 index 00000000..ccf574d7 --- /dev/null +++ b/samples/wasm-c-api-imports/host/example1.c @@ -0,0 +1,204 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include +#include +#include "wasm_c_api.h" +#include "wasm_export.h" + +static wasm_trap_t * +host_logs(const wasm_val_vec_t *args, wasm_val_vec_t *results) +{ + return NULL; +} + +static bool +build_imports(wasm_store_t *store, const wasm_module_t *module, + wasm_extern_vec_t *out) +{ + wasm_importtype_vec_t importtypes = { 0 }; + wasm_module_imports(module, &importtypes); + + wasm_extern_t *externs[32] = { 0 }; + + for (unsigned i = 0; i < importtypes.num_elems; i++) { + wasm_importtype_t *importtype = importtypes.data[i]; + + /* use wasm_extern_new_empty() to create a placeholder */ + if (wasm_importtype_is_linked(importtype)) { + externs[i] = wasm_extern_new_empty( + store, wasm_externtype_kind(wasm_importtype_type(importtype))); + continue; + } + + const wasm_name_t *module_name = + wasm_importtype_module(importtypes.data[i]); + const wasm_name_t *field_name = + wasm_importtype_name(importtypes.data[i]); + + if (strncmp(module_name->data, "env", strlen("env")) == 0 + && strncmp(field_name->data, "log", strlen("log")) == 0) { + wasm_functype_t *log_type = wasm_functype_new_2_0( + wasm_valtype_new_i64(), wasm_valtype_new_i32()); + wasm_func_t *log_func = wasm_func_new(store, log_type, host_logs); + wasm_functype_delete(log_type); + + externs[i] = wasm_func_as_extern(log_func); + } + } + + wasm_extern_vec_new(out, importtypes.num_elems, externs); + wasm_importtype_vec_delete(&importtypes); + return true; +} + +int +main() +{ + int main_ret = EXIT_FAILURE; + + // Initialize. + printf("Initializing...\n"); + wasm_engine_t *engine = wasm_engine_new(); + if (!engine) + goto quit; + + wasm_store_t *store = wasm_store_new(engine); + if (!store) + goto delete_engine; + + // Load binary. + printf("Loading binary...\n"); +#if WASM_ENABLE_AOT != 0 && WASM_ENABLE_INTERP == 0 + FILE *file = fopen("send_recv.aot", "rb"); + printf("> Load .aot\n"); +#else + FILE *file = fopen("send_recv.wasm", "rb"); + printf("> Load .wasm\n"); +#endif + if (!file) { + printf("> Error loading module!\n"); + goto delete_store; + } + + int ret = fseek(file, 0L, SEEK_END); + if (ret == -1) { + printf("> Error loading module!\n"); + goto close_file; + } + + long file_size = ftell(file); + if (file_size == -1) { + printf("> Error loading module!\n"); + goto close_file; + } + + ret = fseek(file, 0L, SEEK_SET); + if (ret == -1) { + printf("> Error loading module!\n"); + goto close_file; + } + + 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"); + goto delete_binary; + } + + // Compile. + printf("Compiling module...\n"); + wasm_module_t *module = wasm_module_new(store, &binary); + if (!module) { + printf("> Error compiling module!\n"); + goto delete_binary; + } + + // Set Wasi Context + const char *addr_pool[1] = { "127.0.0.1" }; + wasm_runtime_set_wasi_addr_pool(*module, addr_pool, 1); + + // Instantiate. + printf("Instantiating module...\n"); + wasm_extern_vec_t imports = { 0 }; + ret = build_imports(store, module, &imports); + if (!ret) { + printf("> Error building imports!\n"); + goto delete_module; + } + + wasm_instance_t *instance = + wasm_instance_new(store, module, &imports, NULL); + if (!instance) { + printf("> Error instantiating module!\n"); + goto delete_imports; + } + + // Extract export. + printf("Extracting export...\n"); + wasm_extern_vec_t exports; + wasm_instance_exports(instance, &exports); + if (exports.size == 0) { + printf("> Error accessing exports!\n"); + goto delete_instance; + } + + /** + * should use information from wasm_module_exports to avoid hard coding "1" + */ + const wasm_func_t *start_func = wasm_extern_as_func(exports.data[1]); + if (start_func == NULL) { + printf("> Error accessing export!\n"); + goto delete_exports; + } + + // Call. "_start(nil) -> i32" + printf("Calling _start ...\n"); + wasm_val_t rs[1] = { WASM_I32_VAL(0) }; + wasm_val_vec_t args = WASM_EMPTY_VEC; + wasm_val_vec_t results = WASM_ARRAY_VEC(rs); + wasm_trap_t *trap = wasm_func_call(start_func, &args, &results); + if (trap) { + wasm_name_t message = { 0 }; + wasm_trap_message(trap, &message); + + printf("> Error calling function! %s\n", message.data); + + wasm_name_delete(&message); + wasm_trap_delete(trap); + goto delete_exports; + } + + // Print result. + printf("Printing result...\n"); + printf("> %u\n", rs[0].of.i32); + + // Shut down. + printf("Shutting down...\n"); + + // All done. + printf("Done.\n"); + main_ret = EXIT_SUCCESS; + +delete_exports: + wasm_extern_vec_delete(&exports); +delete_instance: + wasm_instance_delete(instance); +delete_imports: + wasm_extern_vec_delete(&imports); +delete_module: + wasm_module_delete(module); +delete_binary: + wasm_byte_vec_delete(&binary); +close_file: + fclose(file); +delete_store: + wasm_store_delete(store); +delete_engine: + wasm_engine_delete(engine); +quit: + return main_ret; +} \ No newline at end of file diff --git a/samples/wasm-c-api-imports/wasm/CMakeLists.txt b/samples/wasm-c-api-imports/wasm/CMakeLists.txt new file mode 100644 index 00000000..6b2743cb --- /dev/null +++ b/samples/wasm-c-api-imports/wasm/CMakeLists.txt @@ -0,0 +1,47 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required (VERSION 3.14) +project(wasm_modules) + +if(NOT SOCKET_WASI_CMAKE) + message(FATAL_ERROR "Require SOCKET_WASI_CMAKE") +endif() + +option(WASM_TO_AOT "transfer wasm to aot" OFF) +if(WASM_TO_AOT AND NOT WAMRC_PATH) + message(FATAL_ERROR "Require WAMRC_PATH when WASM_TO_AOT is ON") +endif() + +# +# c -> wasm +include(${SOCKET_WASI_CMAKE}) +add_executable(send_recv ${CMAKE_CURRENT_LIST_DIR}/send_recv.c) +set_target_properties(send_recv PROPERTIES SUFFIX .wasm) +target_include_directories(send_recv PUBLIC ${CMAKE_CURRENT_LIST_DIR}/inc) +target_link_libraries(send_recv socket_wasi_ext) +target_link_options(send_recv PRIVATE + LINKER:--export=__heap_base + LINKER:--export=__data_end + LINKER:--shared-memory,--max-memory=196608 + LINKER:--no-check-features + LINKER:--allow-undefined +) + +if(WASM_TO_AOT) + # wasm -> aot + add_custom_target(send_recv_aot ALL + COMMAND pwd && ${WAMRC_PATH} --enable-multi-thread -o ./send_recv.aot ./send_recv.wasm + DEPENDS send_recv + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + ) +endif() + +# +# install +if(WASM_TO_AOT) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/send_recv.aot DESTINATION . ) +else() + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/send_recv.wasm DESTINATION . ) +endif() + diff --git a/samples/wasm-c-api-imports/wasm/inc/.gitkeep b/samples/wasm-c-api-imports/wasm/inc/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/samples/wasm-c-api-imports/wasm/send_recv.c b/samples/wasm-c-api-imports/wasm/send_recv.c new file mode 100644 index 00000000..72e1a672 --- /dev/null +++ b/samples/wasm-c-api-imports/wasm/send_recv.c @@ -0,0 +1,231 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef __wasi__ +#include +#include "pthread.h" +#else +#include +#endif + +static pthread_mutex_t lock = { 0 }; +static pthread_cond_t cond = { 0 }; +static bool server_is_ready = false; + +#ifdef __wasi__ +__attribute__((import_name("log"))) extern void +host_log(uint64_t message, uint32_t length); +#endif + +static void +local_printf(const char *formatter, ...) +{ + char buffer[128] = { 0 }; + va_list args; + + va_start(args, formatter); + vsnprintf(buffer, 128, formatter, args); + va_end(args); + +#ifdef __wasi__ + host_log((uint64_t)(void *)buffer, strlen(buffer)); +#endif + printf("--> %s", buffer); +} + +void * +run_as_server(void *arg) +{ + int sock = -1, on = 1; + struct sockaddr_in addr = { 0 }; + int addrlen = 0; + int new_sock = -1; + char *buf[] = { + "The stars shine down", "It brings us light", "Light comes down", + "To make us paths", "It watches us", "And mourns for us", + }; + struct iovec iov[] = { + { .iov_base = buf[0], .iov_len = strlen(buf[0]) + 1 }, + { .iov_base = buf[1], .iov_len = strlen(buf[1]) + 1 }, + { .iov_base = buf[2], .iov_len = strlen(buf[2]) + 1 }, + { .iov_base = buf[3], .iov_len = strlen(buf[3]) + 1 }, + { .iov_base = buf[4], .iov_len = strlen(buf[4]) + 1 }, + { .iov_base = buf[5], .iov_len = strlen(buf[5]) + 1 }, + }; + struct msghdr msg = { .msg_iov = iov, .msg_iovlen = 6 }; + ssize_t send_len = 0; + + pthread_mutex_lock(&lock); + sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock < 0) { + pthread_mutex_unlock(&lock); + perror("Create a socket failed"); + return NULL; + } + +#ifndef __wasi__ + if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on))) { + pthread_mutex_unlock(&lock); + perror("Setsockopt failed"); + goto fail1; + } +#endif + + /* 0.0.0.0:1234 */ + addr.sin_family = AF_INET; + addr.sin_port = htons(1234); + addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + + addrlen = sizeof(addr); + if (bind(sock, (struct sockaddr *)&addr, addrlen) < 0) { + pthread_mutex_unlock(&lock); + perror("Bind failed"); + goto fail1; + } + + if (listen(sock, 0) < 0) { + pthread_mutex_unlock(&lock); + perror("Listen failed"); + goto fail1; + } + + server_is_ready = true; + pthread_cond_signal(&cond); + pthread_mutex_unlock(&lock); + + local_printf("Server is online ... \n"); + + new_sock = accept(sock, (struct sockaddr *)&addr, (socklen_t *)&addrlen); + if (new_sock < 0) { + perror("Accept failed"); + goto fail1; + } + + local_printf("Start sending. \n"); + send_len = sendmsg(new_sock, &msg, 0); + if (send_len < 0) { + perror("Sendmsg failed"); + goto fail2; + } + local_printf("Send %ld bytes successfully!\n", send_len); + +fail2: + close(new_sock); +fail1: + shutdown(sock, SHUT_RD); + close(sock); + return NULL; +} + +void * +run_as_client(void *arg) +{ + int sock = -1; + struct sockaddr_in addr = { 0 }; + /* buf of server is 106 bytes */ + char buf[110] = { 0 }; + struct iovec iov = { .iov_base = buf, .iov_len = sizeof(buf) }; + struct msghdr msg = { .msg_iov = &iov, .msg_iovlen = 1 }; + ssize_t recv_len = 0; + + pthread_mutex_lock(&lock); + while (false == server_is_ready) { + pthread_cond_wait(&cond, &lock); + } + pthread_mutex_unlock(&lock); + + local_printf("Client is running...\n"); + sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock < 0) { + perror("Create a socket failed"); + return NULL; + } + + /* 127.0.0.1:1234 */ + addr.sin_family = AF_INET; + addr.sin_port = htons(1234); + addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + + if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + perror("Connect failed"); + goto fail; + } + + local_printf("Start receiving. \n"); + recv_len = recvmsg(sock, &msg, 0); + if (recv_len < 0) { + perror("Recvmsg failed"); + goto fail; + } + + local_printf("Receive %ld bytes successlly!\n", recv_len); + assert(recv_len == 106); + + local_printf("Data:\n"); + char *s = msg.msg_iov->iov_base; + while (strlen(s) > 0) { + local_printf(" %s\n", s); + s += strlen(s) + 1; + } + +fail: + shutdown(sock, SHUT_RD); + close(sock); + return NULL; +} + +int +main(int argc, char *argv[]) +{ + pthread_t cs[2] = { 0 }; + uint8_t i = 0; + int ret = EXIT_SUCCESS; + + if (pthread_mutex_init(&lock, NULL)) { + perror("Initialize mutex failed"); + ret = EXIT_FAILURE; + goto RETURN; + } + + if (pthread_cond_init(&cond, NULL)) { + perror("Initialize condition failed"); + ret = EXIT_FAILURE; + goto DESTROY_MUTEX; + } + + if (pthread_create(&cs[0], NULL, run_as_server, NULL)) { + perror("Create a server thread failed"); + ret = EXIT_FAILURE; + goto DESTROY_COND; + } + + if (pthread_create(&cs[1], NULL, run_as_client, NULL)) { + perror("Create a client thread failed"); + ret = EXIT_FAILURE; + goto DESTROY_COND; + } + + for (i = 0; i < 2; i++) { + pthread_join(cs[i], NULL); + } + +DESTROY_COND: + pthread_cond_destroy(&cond); +DESTROY_MUTEX: + pthread_mutex_destroy(&lock); +RETURN: + return ret; +} From 531771eb11e5fdab4b76f0089f6bc75d35bb6e35 Mon Sep 17 00:00:00 2001 From: Xu Jun <693788454@qq.com> Date: Mon, 13 Feb 2023 16:23:24 +0800 Subject: [PATCH 27/33] Don't terminate other threads when create thread failed (#1955) --- core/iwasm/libraries/thread-mgr/thread_manager.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/iwasm/libraries/thread-mgr/thread_manager.c b/core/iwasm/libraries/thread-mgr/thread_manager.c index de478a21..8d55cdff 100644 --- a/core/iwasm/libraries/thread-mgr/thread_manager.c +++ b/core/iwasm/libraries/thread-mgr/thread_manager.c @@ -484,7 +484,7 @@ fail4: /* free the allocated aux stack space */ free_aux_stack(cluster, aux_stack_start); fail3: - wasm_exec_env_destroy(new_exec_env); + wasm_exec_env_destroy_internal(new_exec_env); fail2: wasm_runtime_deinstantiate_internal(new_module_inst, true); fail1: @@ -605,7 +605,7 @@ fail3: /* free the allocated aux stack space */ free_aux_stack(cluster, aux_stack_start); fail2: - wasm_exec_env_destroy(new_exec_env); + wasm_exec_env_destroy_internal(new_exec_env); fail1: os_mutex_unlock(&cluster->lock); From fd487fbe991677ca1bc5511ad5ee8b28e1791cfd Mon Sep 17 00:00:00 2001 From: TianlongLiang <111852609+TianlongLiang@users.noreply.github.com> Date: Tue, 14 Feb 2023 11:19:52 +0800 Subject: [PATCH 28/33] CI: Enable Multi-tier JIT by default for released iwasm binary (#1957) --- .github/workflows/build_iwasm_release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_iwasm_release.yml b/.github/workflows/build_iwasm_release.yml index 9a47c6c4..557a81fc 100644 --- a/.github/workflows/build_iwasm_release.yml +++ b/.github/workflows/build_iwasm_release.yml @@ -36,7 +36,7 @@ jobs: - name: generate iwasm binary release run: | cmake -S . -B build \ - -DWAMR_BUILD_AOT=1 -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_JIT=0 \ + -DWAMR_BUILD_AOT=1 -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_FAST_JIT=1 -DWAMR_BUILD_JIT=1 \ -DWAMR_BUILD_CUSTOM_NAME_SECTION=0 \ -DWAMR_BUILD_DEBUG_INTERP=0 \ -DWAMR_BUILD_DEBUG_AOT=0 \ From 1c17665f68e118cd9c6bc9b8782f1d0cda5994c9 Mon Sep 17 00:00:00 2001 From: Charles Liu Date: Tue, 14 Feb 2023 18:28:00 +0800 Subject: [PATCH 29/33] Fix libc-wasi build failure when using clang (#1950) Resolves #1949 --- .../sandboxed-system-primitives/src/ssp_config.h | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/ssp_config.h b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/ssp_config.h index 64bf8043..d5babd02 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/ssp_config.h +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/ssp_config.h @@ -108,7 +108,17 @@ #endif #if !defined(BH_PLATFORM_LINUX_SGX) -#if defined(__GNUC_PREREQ) +/* Clang's __GNUC_PREREQ macro has a different meaning than GCC one, +so we have to handle this case specially */ +#if defined(__clang__) +/* Clang provides stdatomic.h since 3.6.0 +See https://releases.llvm.org/3.6.0/tools/clang/docs/ReleaseNotes.html */ +#if __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 6) +#define CONFIG_HAS_STD_ATOMIC 1 +#else +#define CONFIG_HAS_STD_ATOMIC 0 +#endif +#elif defined(__GNUC_PREREQ) /* Even though older versions of GCC support C11, atomics were not implemented until 4.9. See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58016 */ From 216dc43ab4fc32d9e2b106bbfe3ed460f1e0271c Mon Sep 17 00:00:00 2001 From: Enrico Loparco Date: Thu, 16 Feb 2023 04:54:19 +0100 Subject: [PATCH 30/33] Use shared memory lock for threads generated from same module (#1960) Multiple threads generated from the same module should use the same lock to protect the atomic operations. Before this PR, each thread used a different lock to protect atomic operations (e.g. atomic add), making the lock ineffective. Fix #1958. --- core/iwasm/common/wasm_shared_memory.c | 8 ++ core/iwasm/common/wasm_shared_memory.h | 2 + core/iwasm/interpreter/wasm.h | 4 +- core/iwasm/interpreter/wasm_interp_classic.c | 117 +++++++++--------- core/iwasm/interpreter/wasm_interp_fast.c | 117 +++++++++--------- core/iwasm/interpreter/wasm_loader.c | 14 ++- core/iwasm/interpreter/wasm_mini_loader.c | 12 +- core/iwasm/interpreter/wasm_runtime.c | 14 --- core/iwasm/interpreter/wasm_runtime.h | 10 +- samples/multi-thread/wasm-apps/CMakeLists.txt | 3 + .../wasm-apps/main_global_atomic.c | 48 +++++++ 11 files changed, 203 insertions(+), 146 deletions(-) create mode 100644 samples/multi-thread/wasm-apps/main_global_atomic.c diff --git a/core/iwasm/common/wasm_shared_memory.c b/core/iwasm/common/wasm_shared_memory.c index 19b81f1b..6112b1ba 100644 --- a/core/iwasm/common/wasm_shared_memory.c +++ b/core/iwasm/common/wasm_shared_memory.c @@ -172,6 +172,7 @@ shared_memory_dec_reference(WASMModuleCommon *module) bh_list_remove(shared_memory_list, node); os_mutex_unlock(&shared_memory_list_lock); + os_mutex_destroy(&node->shared_mem_lock); os_mutex_destroy(&node->lock); wasm_runtime_free(node); } @@ -200,7 +201,14 @@ shared_memory_set_memory_inst(WASMModuleCommon *module, node->module = module; node->memory_inst = memory; node->ref_count = 1; + + if (os_mutex_init(&node->shared_mem_lock) != 0) { + wasm_runtime_free(node); + return NULL; + } + if (os_mutex_init(&node->lock) != 0) { + os_mutex_destroy(&node->shared_mem_lock); wasm_runtime_free(node); return NULL; } diff --git a/core/iwasm/common/wasm_shared_memory.h b/core/iwasm/common/wasm_shared_memory.h index 5cd6e0fc..98683f32 100644 --- a/core/iwasm/common/wasm_shared_memory.h +++ b/core/iwasm/common/wasm_shared_memory.h @@ -26,6 +26,8 @@ typedef struct WASMSharedMemNode { WASMModuleCommon *module; /* The memory information */ WASMMemoryInstanceCommon *memory_inst; + /* Lock used for atomic operations */ + korp_mutex shared_mem_lock; /* reference count */ uint32 ref_count; diff --git a/core/iwasm/interpreter/wasm.h b/core/iwasm/interpreter/wasm.h index c6aad29a..e6d02c3f 100644 --- a/core/iwasm/interpreter/wasm.h +++ b/core/iwasm/interpreter/wasm.h @@ -510,8 +510,8 @@ struct WASMModule { uint64 load_size; #endif -#if WASM_ENABLE_DEBUG_INTERP != 0 \ - || (WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT \ +#if WASM_ENABLE_DEBUG_INTERP != 0 \ + || (WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \ && WASM_ENABLE_LAZY_JIT != 0) /** * List of instances referred to this module. When source debugging diff --git a/core/iwasm/interpreter/wasm_interp_classic.c b/core/iwasm/interpreter/wasm_interp_classic.c index c8ef4f27..d8985713 100644 --- a/core/iwasm/interpreter/wasm_interp_classic.c +++ b/core/iwasm/interpreter/wasm_interp_classic.c @@ -696,28 +696,28 @@ trunc_f64_to_int(WASMModuleInstance *module, uint32 *frame_sp, float64 src_min, CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr); \ CHECK_ATOMIC_MEMORY_ACCESS(); \ \ - os_mutex_lock(&module->e->mem_lock); \ + os_mutex_lock(&node->shared_mem_lock); \ readv = (uint32)(*(uint8 *)maddr); \ *(uint8 *)maddr = (uint8)(readv op sval); \ - os_mutex_unlock(&module->e->mem_lock); \ + os_mutex_unlock(&node->shared_mem_lock); \ } \ else if (opcode == WASM_OP_ATOMIC_RMW_I32_##OP_NAME##16_U) { \ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); \ CHECK_ATOMIC_MEMORY_ACCESS(); \ \ - os_mutex_lock(&module->e->mem_lock); \ + os_mutex_lock(&node->shared_mem_lock); \ readv = (uint32)LOAD_U16(maddr); \ STORE_U16(maddr, (uint16)(readv op sval)); \ - os_mutex_unlock(&module->e->mem_lock); \ + os_mutex_unlock(&node->shared_mem_lock); \ } \ else { \ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); \ CHECK_ATOMIC_MEMORY_ACCESS(); \ \ - os_mutex_lock(&module->e->mem_lock); \ + os_mutex_lock(&node->shared_mem_lock); \ readv = LOAD_I32(maddr); \ STORE_U32(maddr, readv op sval); \ - os_mutex_unlock(&module->e->mem_lock); \ + os_mutex_unlock(&node->shared_mem_lock); \ } \ PUSH_I32(readv); \ break; \ @@ -736,39 +736,39 @@ trunc_f64_to_int(WASMModuleInstance *module, uint32 *frame_sp, float64 src_min, CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr); \ CHECK_ATOMIC_MEMORY_ACCESS(); \ \ - os_mutex_lock(&module->e->mem_lock); \ + os_mutex_lock(&node->shared_mem_lock); \ readv = (uint64)(*(uint8 *)maddr); \ *(uint8 *)maddr = (uint8)(readv op sval); \ - os_mutex_unlock(&module->e->mem_lock); \ + os_mutex_unlock(&node->shared_mem_lock); \ } \ else if (opcode == WASM_OP_ATOMIC_RMW_I64_##OP_NAME##16_U) { \ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); \ CHECK_ATOMIC_MEMORY_ACCESS(); \ \ - os_mutex_lock(&module->e->mem_lock); \ + os_mutex_lock(&node->shared_mem_lock); \ readv = (uint64)LOAD_U16(maddr); \ STORE_U16(maddr, (uint16)(readv op sval)); \ - os_mutex_unlock(&module->e->mem_lock); \ + os_mutex_unlock(&node->shared_mem_lock); \ } \ else if (opcode == WASM_OP_ATOMIC_RMW_I64_##OP_NAME##32_U) { \ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); \ CHECK_ATOMIC_MEMORY_ACCESS(); \ \ - os_mutex_lock(&module->e->mem_lock); \ + os_mutex_lock(&node->shared_mem_lock); \ readv = (uint64)LOAD_U32(maddr); \ STORE_U32(maddr, (uint32)(readv op sval)); \ - os_mutex_unlock(&module->e->mem_lock); \ + os_mutex_unlock(&node->shared_mem_lock); \ } \ else { \ uint64 op_result; \ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr); \ CHECK_ATOMIC_MEMORY_ACCESS(); \ \ - os_mutex_lock(&module->e->mem_lock); \ + os_mutex_lock(&node->shared_mem_lock); \ readv = (uint64)LOAD_I64(maddr); \ op_result = readv op sval; \ STORE_I64(maddr, op_result); \ - os_mutex_unlock(&module->e->mem_lock); \ + os_mutex_unlock(&node->shared_mem_lock); \ } \ PUSH_I64(readv); \ break; \ @@ -1151,6 +1151,11 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, uint32 cache_index, type_index, param_cell_num, cell_num; uint8 value_type; +#if WASM_ENABLE_SHARED_MEMORY != 0 + WASMSharedMemNode *node = + wasm_module_get_shared_memory((WASMModuleCommon *)module->module); +#endif + #if WASM_ENABLE_DEBUG_INTERP != 0 uint8 *frame_ip_orig = NULL; WASMDebugInstance *debug_instance = wasm_exec_env_get_instance(exec_env); @@ -3458,23 +3463,23 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, if (opcode == WASM_OP_ATOMIC_I32_LOAD8_U) { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr); CHECK_ATOMIC_MEMORY_ACCESS(); - os_mutex_lock(&module->e->mem_lock); + os_mutex_lock(&node->shared_mem_lock); readv = (uint32)(*(uint8 *)maddr); - os_mutex_unlock(&module->e->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } else if (opcode == WASM_OP_ATOMIC_I32_LOAD16_U) { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); CHECK_ATOMIC_MEMORY_ACCESS(); - os_mutex_lock(&module->e->mem_lock); + os_mutex_lock(&node->shared_mem_lock); readv = (uint32)LOAD_U16(maddr); - os_mutex_unlock(&module->e->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } else { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); CHECK_ATOMIC_MEMORY_ACCESS(); - os_mutex_lock(&module->e->mem_lock); + os_mutex_lock(&node->shared_mem_lock); readv = LOAD_I32(maddr); - os_mutex_unlock(&module->e->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } PUSH_I32(readv); @@ -3493,30 +3498,30 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, if (opcode == WASM_OP_ATOMIC_I64_LOAD8_U) { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr); CHECK_ATOMIC_MEMORY_ACCESS(); - os_mutex_lock(&module->e->mem_lock); + os_mutex_lock(&node->shared_mem_lock); readv = (uint64)(*(uint8 *)maddr); - os_mutex_unlock(&module->e->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } else if (opcode == WASM_OP_ATOMIC_I64_LOAD16_U) { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); CHECK_ATOMIC_MEMORY_ACCESS(); - os_mutex_lock(&module->e->mem_lock); + os_mutex_lock(&node->shared_mem_lock); readv = (uint64)LOAD_U16(maddr); - os_mutex_unlock(&module->e->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } else if (opcode == WASM_OP_ATOMIC_I64_LOAD32_U) { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); CHECK_ATOMIC_MEMORY_ACCESS(); - os_mutex_lock(&module->e->mem_lock); + os_mutex_lock(&node->shared_mem_lock); readv = (uint64)LOAD_U32(maddr); - os_mutex_unlock(&module->e->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } else { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr); CHECK_ATOMIC_MEMORY_ACCESS(); - os_mutex_lock(&module->e->mem_lock); + os_mutex_lock(&node->shared_mem_lock); readv = LOAD_I64(maddr); - os_mutex_unlock(&module->e->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } PUSH_I64(readv); @@ -3535,23 +3540,23 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, if (opcode == WASM_OP_ATOMIC_I32_STORE8) { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr); CHECK_ATOMIC_MEMORY_ACCESS(); - os_mutex_lock(&module->e->mem_lock); + os_mutex_lock(&node->shared_mem_lock); *(uint8 *)maddr = (uint8)sval; - os_mutex_unlock(&module->e->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } else if (opcode == WASM_OP_ATOMIC_I32_STORE16) { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); CHECK_ATOMIC_MEMORY_ACCESS(); - os_mutex_lock(&module->e->mem_lock); + os_mutex_lock(&node->shared_mem_lock); STORE_U16(maddr, (uint16)sval); - os_mutex_unlock(&module->e->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } else { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); CHECK_ATOMIC_MEMORY_ACCESS(); - os_mutex_lock(&module->e->mem_lock); + os_mutex_lock(&node->shared_mem_lock); STORE_U32(maddr, frame_sp[1]); - os_mutex_unlock(&module->e->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } break; } @@ -3569,31 +3574,31 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, if (opcode == WASM_OP_ATOMIC_I64_STORE8) { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr); CHECK_ATOMIC_MEMORY_ACCESS(); - os_mutex_lock(&module->e->mem_lock); + os_mutex_lock(&node->shared_mem_lock); *(uint8 *)maddr = (uint8)sval; - os_mutex_unlock(&module->e->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } else if (opcode == WASM_OP_ATOMIC_I64_STORE16) { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); CHECK_ATOMIC_MEMORY_ACCESS(); - os_mutex_lock(&module->e->mem_lock); + os_mutex_lock(&node->shared_mem_lock); STORE_U16(maddr, (uint16)sval); - os_mutex_unlock(&module->e->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } else if (opcode == WASM_OP_ATOMIC_I64_STORE32) { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); CHECK_ATOMIC_MEMORY_ACCESS(); - os_mutex_lock(&module->e->mem_lock); + os_mutex_lock(&node->shared_mem_lock); STORE_U32(maddr, (uint32)sval); - os_mutex_unlock(&module->e->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } else { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr); CHECK_ATOMIC_MEMORY_ACCESS(); - os_mutex_lock(&module->e->mem_lock); + os_mutex_lock(&node->shared_mem_lock); PUT_I64_TO_ADDR((uint32 *)maddr, GET_I64_FROM_ADDR(frame_sp + 1)); - os_mutex_unlock(&module->e->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } break; } @@ -3613,32 +3618,32 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, CHECK_ATOMIC_MEMORY_ACCESS(); expect = (uint8)expect; - os_mutex_lock(&module->e->mem_lock); + os_mutex_lock(&node->shared_mem_lock); readv = (uint32)(*(uint8 *)maddr); if (readv == expect) *(uint8 *)maddr = (uint8)(sval); - os_mutex_unlock(&module->e->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } else if (opcode == WASM_OP_ATOMIC_RMW_I32_CMPXCHG16_U) { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); CHECK_ATOMIC_MEMORY_ACCESS(); expect = (uint16)expect; - os_mutex_lock(&module->e->mem_lock); + os_mutex_lock(&node->shared_mem_lock); readv = (uint32)LOAD_U16(maddr); if (readv == expect) STORE_U16(maddr, (uint16)(sval)); - os_mutex_unlock(&module->e->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } else { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); CHECK_ATOMIC_MEMORY_ACCESS(); - os_mutex_lock(&module->e->mem_lock); + os_mutex_lock(&node->shared_mem_lock); readv = LOAD_I32(maddr); if (readv == expect) STORE_U32(maddr, sval); - os_mutex_unlock(&module->e->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } PUSH_I32(readv); break; @@ -3659,44 +3664,44 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, CHECK_ATOMIC_MEMORY_ACCESS(); expect = (uint8)expect; - os_mutex_lock(&module->e->mem_lock); + os_mutex_lock(&node->shared_mem_lock); readv = (uint64)(*(uint8 *)maddr); if (readv == expect) *(uint8 *)maddr = (uint8)(sval); - os_mutex_unlock(&module->e->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } else if (opcode == WASM_OP_ATOMIC_RMW_I64_CMPXCHG16_U) { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); CHECK_ATOMIC_MEMORY_ACCESS(); expect = (uint16)expect; - os_mutex_lock(&module->e->mem_lock); + os_mutex_lock(&node->shared_mem_lock); readv = (uint64)LOAD_U16(maddr); if (readv == expect) STORE_U16(maddr, (uint16)(sval)); - os_mutex_unlock(&module->e->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } else if (opcode == WASM_OP_ATOMIC_RMW_I64_CMPXCHG32_U) { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); CHECK_ATOMIC_MEMORY_ACCESS(); expect = (uint32)expect; - os_mutex_lock(&module->e->mem_lock); + os_mutex_lock(&node->shared_mem_lock); readv = (uint64)LOAD_U32(maddr); if (readv == expect) STORE_U32(maddr, (uint32)(sval)); - os_mutex_unlock(&module->e->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } else { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr); CHECK_ATOMIC_MEMORY_ACCESS(); - os_mutex_lock(&module->e->mem_lock); + os_mutex_lock(&node->shared_mem_lock); readv = (uint64)LOAD_I64(maddr); if (readv == expect) { STORE_I64(maddr, sval); } - os_mutex_unlock(&module->e->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } PUSH_I64(readv); break; diff --git a/core/iwasm/interpreter/wasm_interp_fast.c b/core/iwasm/interpreter/wasm_interp_fast.c index 7209f7bd..be924646 100644 --- a/core/iwasm/interpreter/wasm_interp_fast.c +++ b/core/iwasm/interpreter/wasm_interp_fast.c @@ -469,28 +469,28 @@ LOAD_PTR(void *addr) CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr); \ CHECK_ATOMIC_MEMORY_ACCESS(1); \ \ - os_mutex_lock(&module->e->mem_lock); \ + os_mutex_lock(&node->shared_mem_lock); \ readv = (uint32)(*(uint8 *)maddr); \ *(uint8 *)maddr = (uint8)(readv op sval); \ - os_mutex_unlock(&module->e->mem_lock); \ + os_mutex_unlock(&node->shared_mem_lock); \ } \ else if (opcode == WASM_OP_ATOMIC_RMW_I32_##OP_NAME##16_U) { \ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); \ CHECK_ATOMIC_MEMORY_ACCESS(2); \ \ - os_mutex_lock(&module->e->mem_lock); \ + os_mutex_lock(&node->shared_mem_lock); \ readv = (uint32)LOAD_U16(maddr); \ STORE_U16(maddr, (uint16)(readv op sval)); \ - os_mutex_unlock(&module->e->mem_lock); \ + os_mutex_unlock(&node->shared_mem_lock); \ } \ else { \ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); \ CHECK_ATOMIC_MEMORY_ACCESS(4); \ \ - os_mutex_lock(&module->e->mem_lock); \ + os_mutex_lock(&node->shared_mem_lock); \ readv = LOAD_I32(maddr); \ STORE_U32(maddr, readv op sval); \ - os_mutex_unlock(&module->e->mem_lock); \ + os_mutex_unlock(&node->shared_mem_lock); \ } \ PUSH_I32(readv); \ break; \ @@ -509,39 +509,39 @@ LOAD_PTR(void *addr) CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr); \ CHECK_ATOMIC_MEMORY_ACCESS(1); \ \ - os_mutex_lock(&module->e->mem_lock); \ + os_mutex_lock(&node->shared_mem_lock); \ readv = (uint64)(*(uint8 *)maddr); \ *(uint8 *)maddr = (uint8)(readv op sval); \ - os_mutex_unlock(&module->e->mem_lock); \ + os_mutex_unlock(&node->shared_mem_lock); \ } \ else if (opcode == WASM_OP_ATOMIC_RMW_I64_##OP_NAME##16_U) { \ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); \ CHECK_ATOMIC_MEMORY_ACCESS(2); \ \ - os_mutex_lock(&module->e->mem_lock); \ + os_mutex_lock(&node->shared_mem_lock); \ readv = (uint64)LOAD_U16(maddr); \ STORE_U16(maddr, (uint16)(readv op sval)); \ - os_mutex_unlock(&module->e->mem_lock); \ + os_mutex_unlock(&node->shared_mem_lock); \ } \ else if (opcode == WASM_OP_ATOMIC_RMW_I64_##OP_NAME##32_U) { \ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); \ CHECK_ATOMIC_MEMORY_ACCESS(4); \ \ - os_mutex_lock(&module->e->mem_lock); \ + os_mutex_lock(&node->shared_mem_lock); \ readv = (uint64)LOAD_U32(maddr); \ STORE_U32(maddr, (uint32)(readv op sval)); \ - os_mutex_unlock(&module->e->mem_lock); \ + os_mutex_unlock(&node->shared_mem_lock); \ } \ else { \ uint64 op_result; \ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr); \ CHECK_ATOMIC_MEMORY_ACCESS(8); \ \ - os_mutex_lock(&module->e->mem_lock); \ + os_mutex_lock(&node->shared_mem_lock); \ readv = (uint64)LOAD_I64(maddr); \ op_result = readv op sval; \ STORE_I64(maddr, op_result); \ - os_mutex_unlock(&module->e->mem_lock); \ + os_mutex_unlock(&node->shared_mem_lock); \ } \ PUSH_I64(readv); \ break; \ @@ -1183,6 +1183,11 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, uint32 local_idx, local_offset, global_idx; uint8 opcode, local_type, *global_addr; +#if WASM_ENABLE_SHARED_MEMORY != 0 + WASMSharedMemNode *node = + wasm_module_get_shared_memory((WASMModuleCommon *)module->module); +#endif + #if WASM_ENABLE_LABELS_AS_VALUES != 0 #define HANDLE_OPCODE(op) &&HANDLE_##op DEFINE_GOTO_TABLE(const void *, handle_table); @@ -3296,23 +3301,23 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, if (opcode == WASM_OP_ATOMIC_I32_LOAD8_U) { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr); CHECK_ATOMIC_MEMORY_ACCESS(1); - os_mutex_lock(&module->e->mem_lock); + os_mutex_lock(&node->shared_mem_lock); readv = (uint32)(*(uint8 *)maddr); - os_mutex_unlock(&module->e->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } else if (opcode == WASM_OP_ATOMIC_I32_LOAD16_U) { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); CHECK_ATOMIC_MEMORY_ACCESS(2); - os_mutex_lock(&module->e->mem_lock); + os_mutex_lock(&node->shared_mem_lock); readv = (uint32)LOAD_U16(maddr); - os_mutex_unlock(&module->e->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } else { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); CHECK_ATOMIC_MEMORY_ACCESS(4); - os_mutex_lock(&module->e->mem_lock); + os_mutex_lock(&node->shared_mem_lock); readv = LOAD_I32(maddr); - os_mutex_unlock(&module->e->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } PUSH_I32(readv); @@ -3331,30 +3336,30 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, if (opcode == WASM_OP_ATOMIC_I64_LOAD8_U) { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr); CHECK_ATOMIC_MEMORY_ACCESS(1); - os_mutex_lock(&module->e->mem_lock); + os_mutex_lock(&node->shared_mem_lock); readv = (uint64)(*(uint8 *)maddr); - os_mutex_unlock(&module->e->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } else if (opcode == WASM_OP_ATOMIC_I64_LOAD16_U) { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); CHECK_ATOMIC_MEMORY_ACCESS(2); - os_mutex_lock(&module->e->mem_lock); + os_mutex_lock(&node->shared_mem_lock); readv = (uint64)LOAD_U16(maddr); - os_mutex_unlock(&module->e->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } else if (opcode == WASM_OP_ATOMIC_I64_LOAD32_U) { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); CHECK_ATOMIC_MEMORY_ACCESS(4); - os_mutex_lock(&module->e->mem_lock); + os_mutex_lock(&node->shared_mem_lock); readv = (uint64)LOAD_U32(maddr); - os_mutex_unlock(&module->e->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } else { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr); CHECK_ATOMIC_MEMORY_ACCESS(8); - os_mutex_lock(&module->e->mem_lock); + os_mutex_lock(&node->shared_mem_lock); readv = LOAD_I64(maddr); - os_mutex_unlock(&module->e->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } PUSH_I64(readv); @@ -3372,23 +3377,23 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, if (opcode == WASM_OP_ATOMIC_I32_STORE8) { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr); CHECK_ATOMIC_MEMORY_ACCESS(1); - os_mutex_lock(&module->e->mem_lock); + os_mutex_lock(&node->shared_mem_lock); *(uint8 *)maddr = (uint8)sval; - os_mutex_unlock(&module->e->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } else if (opcode == WASM_OP_ATOMIC_I32_STORE16) { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); CHECK_ATOMIC_MEMORY_ACCESS(2); - os_mutex_lock(&module->e->mem_lock); + os_mutex_lock(&node->shared_mem_lock); STORE_U16(maddr, (uint16)sval); - os_mutex_unlock(&module->e->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } else { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); CHECK_ATOMIC_MEMORY_ACCESS(4); - os_mutex_lock(&module->e->mem_lock); + os_mutex_lock(&node->shared_mem_lock); STORE_U32(maddr, sval); - os_mutex_unlock(&module->e->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } break; } @@ -3406,30 +3411,30 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, if (opcode == WASM_OP_ATOMIC_I64_STORE8) { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr); CHECK_ATOMIC_MEMORY_ACCESS(1); - os_mutex_lock(&module->e->mem_lock); + os_mutex_lock(&node->shared_mem_lock); *(uint8 *)maddr = (uint8)sval; - os_mutex_unlock(&module->e->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } else if (opcode == WASM_OP_ATOMIC_I64_STORE16) { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); CHECK_ATOMIC_MEMORY_ACCESS(2); - os_mutex_lock(&module->e->mem_lock); + os_mutex_lock(&node->shared_mem_lock); STORE_U16(maddr, (uint16)sval); - os_mutex_unlock(&module->e->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } else if (opcode == WASM_OP_ATOMIC_I64_STORE32) { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); CHECK_ATOMIC_MEMORY_ACCESS(4); - os_mutex_lock(&module->e->mem_lock); + os_mutex_lock(&node->shared_mem_lock); STORE_U32(maddr, (uint32)sval); - os_mutex_unlock(&module->e->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } else { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr); CHECK_ATOMIC_MEMORY_ACCESS(8); - os_mutex_lock(&module->e->mem_lock); + os_mutex_lock(&node->shared_mem_lock); STORE_I64(maddr, sval); - os_mutex_unlock(&module->e->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } break; } @@ -3449,32 +3454,32 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, CHECK_ATOMIC_MEMORY_ACCESS(1); expect = (uint8)expect; - os_mutex_lock(&module->e->mem_lock); + os_mutex_lock(&node->shared_mem_lock); readv = (uint32)(*(uint8 *)maddr); if (readv == expect) *(uint8 *)maddr = (uint8)(sval); - os_mutex_unlock(&module->e->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } else if (opcode == WASM_OP_ATOMIC_RMW_I32_CMPXCHG16_U) { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); CHECK_ATOMIC_MEMORY_ACCESS(2); expect = (uint16)expect; - os_mutex_lock(&module->e->mem_lock); + os_mutex_lock(&node->shared_mem_lock); readv = (uint32)LOAD_U16(maddr); if (readv == expect) STORE_U16(maddr, (uint16)(sval)); - os_mutex_unlock(&module->e->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } else { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); CHECK_ATOMIC_MEMORY_ACCESS(4); - os_mutex_lock(&module->e->mem_lock); + os_mutex_lock(&node->shared_mem_lock); readv = LOAD_I32(maddr); if (readv == expect) STORE_U32(maddr, sval); - os_mutex_unlock(&module->e->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } PUSH_I32(readv); break; @@ -3495,44 +3500,44 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, CHECK_ATOMIC_MEMORY_ACCESS(1); expect = (uint8)expect; - os_mutex_lock(&module->e->mem_lock); + os_mutex_lock(&node->shared_mem_lock); readv = (uint64)(*(uint8 *)maddr); if (readv == expect) *(uint8 *)maddr = (uint8)(sval); - os_mutex_unlock(&module->e->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } else if (opcode == WASM_OP_ATOMIC_RMW_I64_CMPXCHG16_U) { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); CHECK_ATOMIC_MEMORY_ACCESS(2); expect = (uint16)expect; - os_mutex_lock(&module->e->mem_lock); + os_mutex_lock(&node->shared_mem_lock); readv = (uint64)LOAD_U16(maddr); if (readv == expect) STORE_U16(maddr, (uint16)(sval)); - os_mutex_unlock(&module->e->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } else if (opcode == WASM_OP_ATOMIC_RMW_I64_CMPXCHG32_U) { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); CHECK_ATOMIC_MEMORY_ACCESS(4); expect = (uint32)expect; - os_mutex_lock(&module->e->mem_lock); + os_mutex_lock(&node->shared_mem_lock); readv = (uint64)LOAD_U32(maddr); if (readv == expect) STORE_U32(maddr, (uint32)(sval)); - os_mutex_unlock(&module->e->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } else { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr); CHECK_ATOMIC_MEMORY_ACCESS(8); - os_mutex_lock(&module->e->mem_lock); + os_mutex_lock(&node->shared_mem_lock); readv = (uint64)LOAD_I64(maddr); if (readv == expect) { STORE_I64(maddr, sval); } - os_mutex_unlock(&module->e->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } PUSH_I64(readv); break; diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index 5a9fcbfb..d69c0e07 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -3864,8 +3864,8 @@ create_module(char *error_buf, uint32 error_buf_size) bh_assert(ret == BH_LIST_SUCCESS); #endif -#if WASM_ENABLE_DEBUG_INTERP != 0 \ - || (WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT \ +#if WASM_ENABLE_DEBUG_INTERP != 0 \ + || (WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \ && WASM_ENABLE_LAZY_JIT != 0) if (os_mutex_init(&module->instance_list_lock) != 0) { set_error_buf(error_buf, error_buf_size, @@ -4253,7 +4253,8 @@ wasm_loader_unload(WASMModule *module) if (!module) return; -#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT && WASM_ENABLE_LAZY_JIT != 0 +#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \ + && WASM_ENABLE_LAZY_JIT != 0 module->orcjit_stop_compiling = true; if (module->llvm_jit_init_thread) os_thread_join(module->llvm_jit_init_thread, NULL); @@ -4274,7 +4275,8 @@ wasm_loader_unload(WASMModule *module) aot_destroy_comp_data(module->comp_data); #endif -#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT && WASM_ENABLE_LAZY_JIT != 0 +#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \ + && WASM_ENABLE_LAZY_JIT != 0 if (module->tierup_wait_lock_inited) { os_mutex_destroy(&module->tierup_wait_lock); os_cond_destroy(&module->tierup_wait_cond); @@ -4403,8 +4405,8 @@ wasm_loader_unload(WASMModule *module) } #endif -#if WASM_ENABLE_DEBUG_INTERP != 0 \ - || (WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT \ +#if WASM_ENABLE_DEBUG_INTERP != 0 \ + || (WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \ && WASM_ENABLE_LAZY_JIT != 0) os_mutex_destroy(&module->instance_list_lock); #endif diff --git a/core/iwasm/interpreter/wasm_mini_loader.c b/core/iwasm/interpreter/wasm_mini_loader.c index 6a5d83ad..92be851f 100644 --- a/core/iwasm/interpreter/wasm_mini_loader.c +++ b/core/iwasm/interpreter/wasm_mini_loader.c @@ -2725,7 +2725,8 @@ create_module(char *error_buf, uint32 error_buf_size) bh_assert(ret == BH_LIST_SUCCESS); #endif -#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT && WASM_ENABLE_LAZY_JIT != 0 +#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \ + && WASM_ENABLE_LAZY_JIT != 0 if (os_mutex_init(&module->instance_list_lock) != 0) { set_error_buf(error_buf, error_buf_size, "init instance list lock failed"); @@ -2946,7 +2947,8 @@ wasm_loader_unload(WASMModule *module) if (!module) return; -#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT && WASM_ENABLE_LAZY_JIT != 0 +#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \ + && WASM_ENABLE_LAZY_JIT != 0 module->orcjit_stop_compiling = true; if (module->llvm_jit_init_thread) os_thread_join(module->llvm_jit_init_thread, NULL); @@ -2967,7 +2969,8 @@ wasm_loader_unload(WASMModule *module) aot_destroy_comp_data(module->comp_data); #endif -#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT && WASM_ENABLE_LAZY_JIT != 0 +#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \ + && WASM_ENABLE_LAZY_JIT != 0 if (module->tierup_wait_lock_inited) { os_mutex_destroy(&module->tierup_wait_lock); os_cond_destroy(&module->tierup_wait_cond); @@ -3063,7 +3066,8 @@ wasm_loader_unload(WASMModule *module) } #endif -#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT && WASM_ENABLE_LAZY_JIT != 0 +#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \ + && WASM_ENABLE_LAZY_JIT != 0 os_mutex_destroy(&module->instance_list_lock); #endif diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index eabdea68..31b0d1ff 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -1587,15 +1587,6 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, uint32 stack_size, module_inst->e = (WASMModuleInstanceExtra *)((uint8 *)module_inst + extra_info_offset); -#if WASM_ENABLE_SHARED_MEMORY != 0 - if (os_mutex_init(&module_inst->e->mem_lock) != 0) { - set_error_buf(error_buf, error_buf_size, - "create shared memory lock failed"); - goto fail; - } - module_inst->e->mem_lock_inited = true; -#endif - #if WASM_ENABLE_MULTI_MODULE != 0 module_inst->e->sub_module_inst_list = &module_inst->e->sub_module_inst_list_head; @@ -2159,11 +2150,6 @@ wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst) } #endif -#if WASM_ENABLE_SHARED_MEMORY != 0 - if (module_inst->e->mem_lock_inited) - os_mutex_destroy(&module_inst->e->mem_lock); -#endif - if (module_inst->e->c_api_func_imports) wasm_runtime_free(module_inst->e->c_api_func_imports); diff --git a/core/iwasm/interpreter/wasm_runtime.h b/core/iwasm/interpreter/wasm_runtime.h index 38d2cc4b..bf231ad6 100644 --- a/core/iwasm/interpreter/wasm_runtime.h +++ b/core/iwasm/interpreter/wasm_runtime.h @@ -223,12 +223,6 @@ typedef struct WASMModuleInstanceExtra { CApiFuncImport *c_api_func_imports; RunningMode running_mode; -#if WASM_ENABLE_SHARED_MEMORY != 0 - /* lock for shared memory atomic operations */ - korp_mutex mem_lock; - bool mem_lock_inited; -#endif - #if WASM_ENABLE_MULTI_MODULE != 0 bh_list sub_module_inst_list_head; bh_list *sub_module_inst_list; @@ -240,8 +234,8 @@ typedef struct WASMModuleInstanceExtra { uint32 max_aux_stack_used; #endif -#if WASM_ENABLE_DEBUG_INTERP != 0 \ - || (WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT \ +#if WASM_ENABLE_DEBUG_INTERP != 0 \ + || (WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \ && WASM_ENABLE_LAZY_JIT != 0) WASMModuleInstance *next; #endif diff --git a/samples/multi-thread/wasm-apps/CMakeLists.txt b/samples/multi-thread/wasm-apps/CMakeLists.txt index ec8f7eef..d7352e42 100644 --- a/samples/multi-thread/wasm-apps/CMakeLists.txt +++ b/samples/multi-thread/wasm-apps/CMakeLists.txt @@ -41,3 +41,6 @@ target_link_libraries(test.wasm) add_executable(main_thread_exception.wasm main_thread_exception.c) target_link_libraries(main_thread_exception.wasm) + +add_executable(main_global_atomic.wasm main_global_atomic.c) +target_link_libraries(main_global_atomic.wasm) \ No newline at end of file diff --git a/samples/multi-thread/wasm-apps/main_global_atomic.c b/samples/multi-thread/wasm-apps/main_global_atomic.c new file mode 100644 index 00000000..dafbea88 --- /dev/null +++ b/samples/multi-thread/wasm-apps/main_global_atomic.c @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include +#include + +#define MAX_NUM_THREADS 4 +#define NUM_ITER 1000 + +int g_count = 0; + +static void * +thread(void *arg) +{ + for (int i = 0; i < NUM_ITER; i++) { + __atomic_fetch_add(&g_count, 1, __ATOMIC_SEQ_CST); + } + + return NULL; +} + +int +main(int argc, char **argv) +{ + pthread_t tids[MAX_NUM_THREADS]; + + for (int i = 0; i < MAX_NUM_THREADS; i++) { + if (pthread_create(&tids[i], NULL, thread, NULL) != 0) { + printf("Thread creation failed\n"); + } + } + + for (int i = 0; i < MAX_NUM_THREADS; i++) { + if (pthread_join(tids[i], NULL) != 0) { + printf("Thread join failed\n"); + } + } + + printf("Value of counter after update: %d (expected=%d)\n", g_count, + MAX_NUM_THREADS * NUM_ITER); + if (g_count != MAX_NUM_THREADS * NUM_ITER) { + __builtin_trap(); + } + + return -1; +} \ No newline at end of file From f60c3c61118d3eae9a15697ff0e37bbe995b3faa Mon Sep 17 00:00:00 2001 From: TianlongLiang <111852609+TianlongLiang@users.noreply.github.com> Date: Thu, 16 Feb 2023 14:16:41 +0800 Subject: [PATCH 31/33] Add Multi-tier JIT tests in Ubuntu CI (#1964) --- .../compilation_on_android_ubuntu.yml | 37 ++++++++++++++++--- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/.github/workflows/compilation_on_android_ubuntu.yml b/.github/workflows/compilation_on_android_ubuntu.yml index 93528b14..289e56dd 100644 --- a/.github/workflows/compilation_on_android_ubuntu.yml +++ b/.github/workflows/compilation_on_android_ubuntu.yml @@ -53,6 +53,7 @@ env: FAST_JIT_BUILD_OPTIONS: " -DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_FAST_JIT=1 -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_LAZY_JIT=0" LLVM_LAZY_JIT_BUILD_OPTIONS: " -DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_FAST_JIT=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=1" LLVM_EAGER_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_FAST_JIT=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=0" + MULTI_TIER_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_FAST_JIT=1 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=1" # For Spec Test DEFAULT_TEST_OPTIONS: "-s spec -b -P" MULTI_MODULES_TEST_OPTIONS: "-s spec -b -M -P" @@ -128,6 +129,7 @@ jobs: $FAST_JIT_BUILD_OPTIONS, $LLVM_LAZY_JIT_BUILD_OPTIONS, $LLVM_EAGER_JIT_BUILD_OPTIONS, + $MULTI_TIER_JIT_BUILD_OPTIONS, ] make_options_feature: [ # Features @@ -160,6 +162,8 @@ jobs: make_options_feature: "-DWAMR_BUILD_MULTI_MODULE=1" - make_options_run_mode: $LLVM_EAGER_JIT_BUILD_OPTIONS make_options_feature: "-DWAMR_BUILD_MULTI_MODULE=1" + - make_options_run_mode: $MULTI_TIER_JIT_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_MULTI_MODULE=1" # SIMD only on JIT/AOT mode - make_options_run_mode: $CLASSIC_INTERP_BUILD_OPTIONS make_options_feature: "-DWAMR_BUILD_SIMD=1" @@ -176,6 +180,8 @@ jobs: make_options_feature: "-DWAMR_BUILD_DEBUG_INTERP=1" - make_options_run_mode: $LLVM_EAGER_JIT_BUILD_OPTIONS make_options_feature: "-DWAMR_BUILD_DEBUG_INTERP=1" + - make_options_run_mode: $MULTI_TIER_JIT_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_DEBUG_INTERP=1" # DEBUG_AOT only on JIT/AOT mode - make_options_run_mode: $CLASSIC_INTERP_BUILD_OPTIONS make_options_feature: "-DWAMR_BUILD_DEBUG_AOT=1" @@ -188,6 +194,8 @@ jobs: make_options_feature: "-DWAMR_BUILD_DEBUG_AOT=1" - make_options_run_mode: $LLVM_EAGER_JIT_BUILD_OPTIONS make_options_feature: "-DWAMR_BUILD_DEBUG_AOT=1" + - make_options_run_mode: $MULTI_TIER_JIT_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_DEBUG_AOT=1" # MINI_LOADER only on INTERP mode - make_options_run_mode: $AOT_BUILD_OPTIONS make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1" @@ -197,9 +205,13 @@ jobs: make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1" - make_options_run_mode: $LLVM_EAGER_JIT_BUILD_OPTIONS make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1" - # Fast-JIT mode doesn't support android(X86-32) + - make_options_run_mode: $MULTI_TIER_JIT_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1" + # Fast-JIT and Multi-Tier-JIT mode don't support android(X86-32) - make_options_run_mode: $FAST_JIT_BUILD_OPTIONS platform: android + - make_options_run_mode: $MULTI_TIER_JIT_BUILD_OPTIONS + platform: android # only test andorid on ubuntu latest - os: ubuntu-20.04 platform: android @@ -256,6 +268,7 @@ jobs: $FAST_JIT_BUILD_OPTIONS, $LLVM_LAZY_JIT_BUILD_OPTIONS, $LLVM_EAGER_JIT_BUILD_OPTIONS, + $MULTI_TIER_JIT_BUILD_OPTIONS, ] os: [ubuntu-20.04, ubuntu-22.04] wasi_sdk_release: @@ -404,7 +417,14 @@ jobs: strategy: matrix: running_mode: - ["classic-interp", "fast-interp", "jit", "aot", "fast-jit"] + [ + "classic-interp", + "fast-interp", + "jit", + "aot", + "fast-jit", + "multi-tier-jit", + ] test_option: [ $DEFAULT_TEST_OPTIONS, @@ -430,26 +450,33 @@ jobs: test_option: $WASI_TEST_OPTIONS - running_mode: "jit" test_option: $MULTI_MODULES_TEST_OPTIONS - # fast-jit is only tested on default mode, exclude other three + # fast-jit doesn't support multi module, simd, and threads - running_mode: "fast-jit" test_option: $MULTI_MODULES_TEST_OPTIONS - running_mode: "fast-jit" test_option: $SIMD_TEST_OPTIONS - running_mode: "fast-jit" test_option: $THREADS_TEST_OPTIONS + # multi-tier-jit doesn't support multi module, simd, and threads + - running_mode: "multi-tier-jit" + test_option: $MULTI_MODULES_TEST_OPTIONS + - running_mode: "multi-tier-jit" + test_option: $SIMD_TEST_OPTIONS + - running_mode: "multi-tier-jit" + test_option: $THREADS_TEST_OPTIONS steps: - name: checkout uses: actions/checkout@v3 - name: set env variable(if llvm are used) - if: matrix.running_mode == 'aot' || matrix.running_mode == 'jit' + if: matrix.running_mode == 'aot' || matrix.running_mode == 'jit' || matrix.running_mode == 'multi-tier-jit' run: echo "USE_LLVM=true" >> $GITHUB_ENV - name: set env variable(if x86_32 test needed) if: > (matrix.test_option == '$DEFAULT_TEST_OPTIONS' || matrix.test_option == '$THREADS_TEST_OPTIONS' || matrix.test_option == '$WASI_TEST_OPTIONS') - && matrix.running_mode != 'fast-jit' && matrix.running_mode != 'jit' + && matrix.running_mode != 'fast-jit' && matrix.running_mode != 'jit' && matrix.running_mode != 'multi-tier-jit' run: echo "TEST_ON_X86_32=true" >> $GITHUB_ENV #only download llvm libraries in jit and aot mode From 3cc132e8fc322314a845b3c885b04ca7eb87690d Mon Sep 17 00:00:00 2001 From: tonibofarull Date: Thu, 16 Feb 2023 08:21:28 +0100 Subject: [PATCH 32/33] Add WAMR API bindings in Python (#1959) Before adding the new bindings: 1. Moved wasm-c-api in a subfolder wasmcapi in the package. 2. Adapted the tests to be able to run in this new structure. New: 1. Added the WAMR API in another folder wamrapi in the same level as wasm-c-api. 2. Created an OOP proposal. 3. Added an example using this proposal. --- language-bindings/python/MANIFEST.in | 1 + language-bindings/python/README.md | 35 +- language-bindings/python/setup.py | 31 +- language-bindings/python/src/wamr/__init__.py | 0 .../python/src/wamr/libs/.placeholder | 0 .../python/src/wamr/wamrapi/__init__.py | 0 .../python/src/wamr/wamrapi/iwasm.py | 1779 +++++++++++++++++ .../python/src/wamr/wamrapi/wamr.py | 123 ++ .../{wamr => src/wamr/wasmcapi}/__init__.py | 0 .../{wamr => src/wamr/wasmcapi}/binding.py | 0 .../python/{wamr => src/wamr/wasmcapi}/ffi.py | 4 +- language-bindings/python/utils/create_lib.sh | 17 + language-bindings/python/wamr-api/README.md | 25 + .../python/wamr-api/requirements.txt | 1 + .../python/wamr-api/samples/compile.sh | 11 + .../python/wamr-api/samples/main.py | 22 + .../python/wamr-api/samples/sum.c | 12 + language-bindings/python/wasm-c-api/README.md | 7 + .../python/{ => wasm-c-api}/docs/design.md | 0 .../docs/images/python_package_life_cycle.png | Bin .../{ => wasm-c-api}/docs/setup_dev_env.md | 0 .../python/{ => wasm-c-api}/requirements.txt | 0 .../python/{ => wasm-c-api}/samples/hello.wat | 0 .../{ => wasm-c-api}/samples/hello_oop.py | 0 .../samples/hello_procedural.py | 2 +- .../python/{ => wasm-c-api}/tests/__init__.py | 0 .../python/{ => wasm-c-api}/tests/context.py | 0 .../{ => wasm-c-api}/tests/test_advanced.py | 2 +- .../{ => wasm-c-api}/tests/test_basic.py | 2 +- .../python/{ => wasm-c-api}/utils/bindgen.py | 8 +- 30 files changed, 2054 insertions(+), 28 deletions(-) create mode 100644 language-bindings/python/MANIFEST.in create mode 100644 language-bindings/python/src/wamr/__init__.py create mode 100644 language-bindings/python/src/wamr/libs/.placeholder create mode 100644 language-bindings/python/src/wamr/wamrapi/__init__.py create mode 100644 language-bindings/python/src/wamr/wamrapi/iwasm.py create mode 100644 language-bindings/python/src/wamr/wamrapi/wamr.py rename language-bindings/python/{wamr => src/wamr/wasmcapi}/__init__.py (100%) rename language-bindings/python/{wamr => src/wamr/wasmcapi}/binding.py (100%) rename language-bindings/python/{wamr => src/wamr/wasmcapi}/ffi.py (99%) create mode 100755 language-bindings/python/utils/create_lib.sh create mode 100644 language-bindings/python/wamr-api/README.md create mode 100644 language-bindings/python/wamr-api/requirements.txt create mode 100644 language-bindings/python/wamr-api/samples/compile.sh create mode 100644 language-bindings/python/wamr-api/samples/main.py create mode 100644 language-bindings/python/wamr-api/samples/sum.c create mode 100644 language-bindings/python/wasm-c-api/README.md rename language-bindings/python/{ => wasm-c-api}/docs/design.md (100%) rename language-bindings/python/{ => wasm-c-api}/docs/images/python_package_life_cycle.png (100%) rename language-bindings/python/{ => wasm-c-api}/docs/setup_dev_env.md (100%) rename language-bindings/python/{ => wasm-c-api}/requirements.txt (100%) rename language-bindings/python/{ => wasm-c-api}/samples/hello.wat (100%) rename language-bindings/python/{ => wasm-c-api}/samples/hello_oop.py (100%) rename language-bindings/python/{ => wasm-c-api}/samples/hello_procedural.py (98%) rename language-bindings/python/{ => wasm-c-api}/tests/__init__.py (100%) rename language-bindings/python/{ => wasm-c-api}/tests/context.py (100%) rename language-bindings/python/{ => wasm-c-api}/tests/test_advanced.py (99%) rename language-bindings/python/{ => wasm-c-api}/tests/test_basic.py (99%) rename language-bindings/python/{ => wasm-c-api}/utils/bindgen.py (98%) diff --git a/language-bindings/python/MANIFEST.in b/language-bindings/python/MANIFEST.in new file mode 100644 index 00000000..9b0c0893 --- /dev/null +++ b/language-bindings/python/MANIFEST.in @@ -0,0 +1 @@ +include src/wamr/libs/* diff --git a/language-bindings/python/README.md b/language-bindings/python/README.md index 2698a059..9e504a9c 100644 --- a/language-bindings/python/README.md +++ b/language-bindings/python/README.md @@ -1,31 +1,34 @@ # wamr-python +The WAMR Python package contains a set of high-level bindings for WAMR API and WASM-C-API. + ## Installation -### Installing from the source code - -Installing from local source tree is in _development mode_. The package appears to be installed but still is editable from the source tree. +To Install from local source tree in _development mode_ run the following command, ```bash -$ python -m pip install -e /path/to/wamr-root/binding/python +python -m pip install -e . ``` +In this mode the package appears to be installed but still is editable from the source tree. + ## Usage -```python -import wamr.ffi as ffi +From the same package you can use two set of APIs. + +To use the WAMR API you can import the symbols as follows, + +```py +from wamr.wamrapi.wamr import Engine, Module, Instance, ExecEnv ``` -### Preparation +In the order hand, to use the WASM-C-API, -The binding will load the shared library _libiwasm.so_ from the WAMR repo. So before running the binding, you need to build the library yourself. +```py +import wamr.wasmcapi.ffi as ffi +``` -The default compile options are good enough. +For more information: -Please be aware that `wasm_frame_xxx` and `wasm_trap_xxx` only work well when enabling `WAMR_BUILD_DUMP_CALL_STACK`. - -### Examples - -There is a [simple example](./samples/hello_procedural.py) to show how to use bindings. Actually, the python binding follows C-APIs. There it should be easy if be familiar with _programming with wasm-c-api_. - -Unit test cases under _./tests_ could be another but more complete references. +* [WAMR API](./wamr_api) +* [WASM-C-API](./wasm_c_api) diff --git a/language-bindings/python/setup.py b/language-bindings/python/setup.py index c7868187..bf0ba53e 100755 --- a/language-bindings/python/setup.py +++ b/language-bindings/python/setup.py @@ -8,7 +8,28 @@ # pylint: disable=missing-function-docstring # pylint: disable=missing-module-docstring -from setuptools import setup, find_packages +import pathlib +from setuptools import setup +from setuptools.command.develop import develop +from setuptools.command.install import install +from subprocess import check_call + + +def build_library(): + cur_path = pathlib.Path(__file__).parent + check_call(f"{cur_path}/utils/create_lib.sh".split()) + +class PreDevelopCommand(develop): + """Pre-installation for development mode.""" + def run(self): + build_library() + develop.run(self) + +class PreInstallCommand(install): + """Pre-installation for installation mode.""" + def run(self): + build_library() + install.run(self) with open("README.md") as f: @@ -24,7 +45,11 @@ setup( long_description=readme, author="The WAMR Project Developers", author_email="hello@bytecodealliance.org", - url="https://github.com/bytecodealliance/wamr-python", + url="https://github.com/bytecodealliance/wasm-micro-runtime", license=license, - packages=["wamr"], + include_package_data=True, + cmdclass={ + 'develop': PreDevelopCommand, + 'install': PreInstallCommand, + }, ) diff --git a/language-bindings/python/src/wamr/__init__.py b/language-bindings/python/src/wamr/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/language-bindings/python/src/wamr/libs/.placeholder b/language-bindings/python/src/wamr/libs/.placeholder new file mode 100644 index 00000000..e69de29b diff --git a/language-bindings/python/src/wamr/wamrapi/__init__.py b/language-bindings/python/src/wamr/wamrapi/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/language-bindings/python/src/wamr/wamrapi/iwasm.py b/language-bindings/python/src/wamr/wamrapi/iwasm.py new file mode 100644 index 00000000..df3ab81d --- /dev/null +++ b/language-bindings/python/src/wamr/wamrapi/iwasm.py @@ -0,0 +1,1779 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +r"""Wrapper for wasm_export.h + +Generated with: +ctypesgen ../../../../core/iwasm/include/wasm_export.h -l ../libs/libiwasm.so -o iwasm.py + +Do not modify this file. +""" + +__docformat__ = "restructuredtext" + +# Begin preamble for Python + +import ctypes +import sys +from ctypes import * # noqa: F401, F403 + +_int_types = (ctypes.c_int16, ctypes.c_int32) +if hasattr(ctypes, "c_int64"): + # Some builds of ctypes apparently do not have ctypes.c_int64 + # defined; it's a pretty good bet that these builds do not + # have 64-bit pointers. + _int_types += (ctypes.c_int64,) +for t in _int_types: + if ctypes.sizeof(t) == ctypes.sizeof(ctypes.c_size_t): + c_ptrdiff_t = t +del t +del _int_types + + + +class UserString: + def __init__(self, seq): + if isinstance(seq, bytes): + self.data = seq + elif isinstance(seq, UserString): + self.data = seq.data[:] + else: + self.data = str(seq).encode() + + def __bytes__(self): + return self.data + + def __str__(self): + return self.data.decode() + + def __repr__(self): + return repr(self.data) + + def __int__(self): + return int(self.data.decode()) + + def __long__(self): + return int(self.data.decode()) + + def __float__(self): + return float(self.data.decode()) + + def __complex__(self): + return complex(self.data.decode()) + + def __hash__(self): + return hash(self.data) + + def __le__(self, string): + if isinstance(string, UserString): + return self.data <= string.data + else: + return self.data <= string + + def __lt__(self, string): + if isinstance(string, UserString): + return self.data < string.data + else: + return self.data < string + + def __ge__(self, string): + if isinstance(string, UserString): + return self.data >= string.data + else: + return self.data >= string + + def __gt__(self, string): + if isinstance(string, UserString): + return self.data > string.data + else: + return self.data > string + + def __eq__(self, string): + if isinstance(string, UserString): + return self.data == string.data + else: + return self.data == string + + def __ne__(self, string): + if isinstance(string, UserString): + return self.data != string.data + else: + return self.data != string + + def __contains__(self, char): + return char in self.data + + def __len__(self): + return len(self.data) + + def __getitem__(self, index): + return self.__class__(self.data[index]) + + def __getslice__(self, start, end): + start = max(start, 0) + end = max(end, 0) + return self.__class__(self.data[start:end]) + + def __add__(self, other): + if isinstance(other, UserString): + return self.__class__(self.data + other.data) + elif isinstance(other, bytes): + return self.__class__(self.data + other) + else: + return self.__class__(self.data + str(other).encode()) + + def __radd__(self, other): + if isinstance(other, bytes): + return self.__class__(other + self.data) + else: + return self.__class__(str(other).encode() + self.data) + + def __mul__(self, n): + return self.__class__(self.data * n) + + __rmul__ = __mul__ + + def __mod__(self, args): + return self.__class__(self.data % args) + + # the following methods are defined in alphabetical order: + def capitalize(self): + return self.__class__(self.data.capitalize()) + + def center(self, width, *args): + return self.__class__(self.data.center(width, *args)) + + def count(self, sub, start=0, end=sys.maxsize): + return self.data.count(sub, start, end) + + def decode(self, encoding=None, errors=None): # XXX improve this? + if encoding: + if errors: + return self.__class__(self.data.decode(encoding, errors)) + else: + return self.__class__(self.data.decode(encoding)) + else: + return self.__class__(self.data.decode()) + + def encode(self, encoding=None, errors=None): # XXX improve this? + if encoding: + if errors: + return self.__class__(self.data.encode(encoding, errors)) + else: + return self.__class__(self.data.encode(encoding)) + else: + return self.__class__(self.data.encode()) + + def endswith(self, suffix, start=0, end=sys.maxsize): + return self.data.endswith(suffix, start, end) + + def expandtabs(self, tabsize=8): + return self.__class__(self.data.expandtabs(tabsize)) + + def find(self, sub, start=0, end=sys.maxsize): + return self.data.find(sub, start, end) + + def index(self, sub, start=0, end=sys.maxsize): + return self.data.index(sub, start, end) + + def isalpha(self): + return self.data.isalpha() + + def isalnum(self): + return self.data.isalnum() + + def isdecimal(self): + return self.data.isdecimal() + + def isdigit(self): + return self.data.isdigit() + + def islower(self): + return self.data.islower() + + def isnumeric(self): + return self.data.isnumeric() + + def isspace(self): + return self.data.isspace() + + def istitle(self): + return self.data.istitle() + + def isupper(self): + return self.data.isupper() + + def join(self, seq): + return self.data.join(seq) + + def ljust(self, width, *args): + return self.__class__(self.data.ljust(width, *args)) + + def lower(self): + return self.__class__(self.data.lower()) + + def lstrip(self, chars=None): + return self.__class__(self.data.lstrip(chars)) + + def partition(self, sep): + return self.data.partition(sep) + + def replace(self, old, new, maxsplit=-1): + return self.__class__(self.data.replace(old, new, maxsplit)) + + def rfind(self, sub, start=0, end=sys.maxsize): + return self.data.rfind(sub, start, end) + + def rindex(self, sub, start=0, end=sys.maxsize): + return self.data.rindex(sub, start, end) + + def rjust(self, width, *args): + return self.__class__(self.data.rjust(width, *args)) + + def rpartition(self, sep): + return self.data.rpartition(sep) + + def rstrip(self, chars=None): + return self.__class__(self.data.rstrip(chars)) + + def split(self, sep=None, maxsplit=-1): + return self.data.split(sep, maxsplit) + + def rsplit(self, sep=None, maxsplit=-1): + return self.data.rsplit(sep, maxsplit) + + def splitlines(self, keepends=0): + return self.data.splitlines(keepends) + + def startswith(self, prefix, start=0, end=sys.maxsize): + return self.data.startswith(prefix, start, end) + + def strip(self, chars=None): + return self.__class__(self.data.strip(chars)) + + def swapcase(self): + return self.__class__(self.data.swapcase()) + + def title(self): + return self.__class__(self.data.title()) + + def translate(self, *args): + return self.__class__(self.data.translate(*args)) + + def upper(self): + return self.__class__(self.data.upper()) + + def zfill(self, width): + return self.__class__(self.data.zfill(width)) + + +class MutableString(UserString): + """mutable string objects + + Python strings are immutable objects. This has the advantage, that + strings may be used as dictionary keys. If this property isn't needed + and you insist on changing string values in place instead, you may cheat + and use MutableString. + + But the purpose of this class is an educational one: to prevent + people from inventing their own mutable string class derived + from UserString and than forget thereby to remove (override) the + __hash__ method inherited from UserString. This would lead to + errors that would be very hard to track down. + + A faster and better solution is to rewrite your program using lists.""" + + def __init__(self, string=""): + self.data = string + + def __hash__(self): + raise TypeError("unhashable type (it is mutable)") + + def __setitem__(self, index, sub): + if index < 0: + index += len(self.data) + if index < 0 or index >= len(self.data): + raise IndexError + self.data = self.data[:index] + sub + self.data[index + 1 :] + + def __delitem__(self, index): + if index < 0: + index += len(self.data) + if index < 0 or index >= len(self.data): + raise IndexError + self.data = self.data[:index] + self.data[index + 1 :] + + def __setslice__(self, start, end, sub): + start = max(start, 0) + end = max(end, 0) + if isinstance(sub, UserString): + self.data = self.data[:start] + sub.data + self.data[end:] + elif isinstance(sub, bytes): + self.data = self.data[:start] + sub + self.data[end:] + else: + self.data = self.data[:start] + str(sub).encode() + self.data[end:] + + def __delslice__(self, start, end): + start = max(start, 0) + end = max(end, 0) + self.data = self.data[:start] + self.data[end:] + + def immutable(self): + return UserString(self.data) + + def __iadd__(self, other): + if isinstance(other, UserString): + self.data += other.data + elif isinstance(other, bytes): + self.data += other + else: + self.data += str(other).encode() + return self + + def __imul__(self, n): + self.data *= n + return self + + +class String(MutableString, ctypes.Union): + + _fields_ = [("raw", ctypes.POINTER(ctypes.c_char)), ("data", ctypes.c_char_p)] + + def __init__(self, obj=b""): + if isinstance(obj, (bytes, UserString)): + self.data = bytes(obj) + else: + self.raw = obj + + def __len__(self): + return self.data and len(self.data) or 0 + + def from_param(cls, obj): + # Convert None or 0 + if obj is None or obj == 0: + return cls(ctypes.POINTER(ctypes.c_char)()) + + # Convert from String + elif isinstance(obj, String): + return obj + + # Convert from bytes + elif isinstance(obj, bytes): + return cls(obj) + + # Convert from str + elif isinstance(obj, str): + return cls(obj.encode()) + + # Convert from c_char_p + elif isinstance(obj, ctypes.c_char_p): + return obj + + # Convert from POINTER(ctypes.c_char) + elif isinstance(obj, ctypes.POINTER(ctypes.c_char)): + return obj + + # Convert from raw pointer + elif isinstance(obj, int): + return cls(ctypes.cast(obj, ctypes.POINTER(ctypes.c_char))) + + # Convert from ctypes.c_char array + elif isinstance(obj, ctypes.c_char * len(obj)): + return obj + + # Convert from object + else: + return String.from_param(obj._as_parameter_) + + from_param = classmethod(from_param) + + +def ReturnString(obj, func=None, arguments=None): + return String.from_param(obj) + + +# As of ctypes 1.0, ctypes does not support custom error-checking +# functions on callbacks, nor does it support custom datatypes on +# callbacks, so we must ensure that all callbacks return +# primitive datatypes. +# +# Non-primitive return values wrapped with UNCHECKED won't be +# typechecked, and will be converted to ctypes.c_void_p. +def UNCHECKED(type): + if hasattr(type, "_type_") and isinstance(type._type_, str) and type._type_ != "P": + return type + else: + return ctypes.c_void_p + + +# ctypes doesn't have direct support for variadic functions, so we have to write +# our own wrapper class +class _variadic_function(object): + def __init__(self, func, restype, argtypes, errcheck): + self.func = func + self.func.restype = restype + self.argtypes = argtypes + if errcheck: + self.func.errcheck = errcheck + + def _as_parameter_(self): + # So we can pass this variadic function as a function pointer + return self.func + + def __call__(self, *args): + fixed_args = [] + i = 0 + for argtype in self.argtypes: + # Typecheck what we can + fixed_args.append(argtype.from_param(args[i])) + i += 1 + return self.func(*fixed_args + list(args[i:])) + + +def ord_if_char(value): + """ + Simple helper used for casts to simple builtin types: if the argument is a + string type, it will be converted to it's ordinal value. + + This function will raise an exception if the argument is string with more + than one characters. + """ + return ord(value) if (isinstance(value, bytes) or isinstance(value, str)) else value + +# End preamble + +_libs = {} +_libdirs = [] + +# Begin loader + +""" +Load libraries - appropriately for all our supported platforms +""" +# ---------------------------------------------------------------------------- +# Copyright (c) 2008 David James +# Copyright (c) 2006-2008 Alex Holkner +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of pyglet nor the names of its +# contributors may be used to endorse or promote products +# derived from this software without specific prior written +# permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# ---------------------------------------------------------------------------- + +import ctypes +import ctypes.util +import glob +import os.path +import platform +import re +import sys + + +def _environ_path(name): + """Split an environment variable into a path-like list elements""" + if name in os.environ: + return os.environ[name].split(":") + return [] + + +class LibraryLoader: + """ + A base class For loading of libraries ;-) + Subclasses load libraries for specific platforms. + """ + + # library names formatted specifically for platforms + name_formats = ["%s"] + + class Lookup: + """Looking up calling conventions for a platform""" + + mode = ctypes.DEFAULT_MODE + + def __init__(self, path): + super(LibraryLoader.Lookup, self).__init__() + self.access = dict(cdecl=ctypes.CDLL(path, self.mode)) + + def get(self, name, calling_convention="cdecl"): + """Return the given name according to the selected calling convention""" + if calling_convention not in self.access: + raise LookupError( + "Unknown calling convention '{}' for function '{}'".format( + calling_convention, name + ) + ) + return getattr(self.access[calling_convention], name) + + def has(self, name, calling_convention="cdecl"): + """Return True if this given calling convention finds the given 'name'""" + if calling_convention not in self.access: + return False + return hasattr(self.access[calling_convention], name) + + def __getattr__(self, name): + return getattr(self.access["cdecl"], name) + + def __init__(self): + self.other_dirs = [] + + def __call__(self, libname): + """Given the name of a library, load it.""" + paths = self.getpaths(libname) + + for path in paths: + # noinspection PyBroadException + try: + return self.Lookup(path) + except Exception: # pylint: disable=broad-except + pass + + raise ImportError("Could not load %s." % libname) + + def getpaths(self, libname): + """Return a list of paths where the library might be found.""" + if os.path.isabs(libname): + yield libname + else: + # search through a prioritized series of locations for the library + + # we first search any specific directories identified by user + for dir_i in self.other_dirs: + for fmt in self.name_formats: + # dir_i should be absolute already + yield os.path.join(dir_i, fmt % libname) + + # check if this code is even stored in a physical file + try: + this_file = __file__ + except NameError: + this_file = None + + # then we search the directory where the generated python interface is stored + if this_file is not None: + for fmt in self.name_formats: + yield os.path.abspath(os.path.join(os.path.dirname(__file__), fmt % libname)) + + # now, use the ctypes tools to try to find the library + for fmt in self.name_formats: + path = ctypes.util.find_library(fmt % libname) + if path: + yield path + + # then we search all paths identified as platform-specific lib paths + for path in self.getplatformpaths(libname): + yield path + + # Finally, we'll try the users current working directory + for fmt in self.name_formats: + yield os.path.abspath(os.path.join(os.path.curdir, fmt % libname)) + + def getplatformpaths(self, _libname): # pylint: disable=no-self-use + """Return all the library paths available in this platform""" + return [] + + +# Darwin (Mac OS X) + + +class DarwinLibraryLoader(LibraryLoader): + """Library loader for MacOS""" + + name_formats = [ + "lib%s.dylib", + "lib%s.so", + "lib%s.bundle", + "%s.dylib", + "%s.so", + "%s.bundle", + "%s", + ] + + class Lookup(LibraryLoader.Lookup): + """ + Looking up library files for this platform (Darwin aka MacOS) + """ + + # Darwin requires dlopen to be called with mode RTLD_GLOBAL instead + # of the default RTLD_LOCAL. Without this, you end up with + # libraries not being loadable, resulting in "Symbol not found" + # errors + mode = ctypes.RTLD_GLOBAL + + def getplatformpaths(self, libname): + if os.path.pathsep in libname: + names = [libname] + else: + names = [fmt % libname for fmt in self.name_formats] + + for directory in self.getdirs(libname): + for name in names: + yield os.path.join(directory, name) + + @staticmethod + def getdirs(libname): + """Implements the dylib search as specified in Apple documentation: + + http://developer.apple.com/documentation/DeveloperTools/Conceptual/ + DynamicLibraries/Articles/DynamicLibraryUsageGuidelines.html + + Before commencing the standard search, the method first checks + the bundle's ``Frameworks`` directory if the application is running + within a bundle (OS X .app). + """ + + dyld_fallback_library_path = _environ_path("DYLD_FALLBACK_LIBRARY_PATH") + if not dyld_fallback_library_path: + dyld_fallback_library_path = [ + os.path.expanduser("~/lib"), + "/usr/local/lib", + "/usr/lib", + ] + + dirs = [] + + if "/" in libname: + dirs.extend(_environ_path("DYLD_LIBRARY_PATH")) + else: + dirs.extend(_environ_path("LD_LIBRARY_PATH")) + dirs.extend(_environ_path("DYLD_LIBRARY_PATH")) + dirs.extend(_environ_path("LD_RUN_PATH")) + + if hasattr(sys, "frozen") and getattr(sys, "frozen") == "macosx_app": + dirs.append(os.path.join(os.environ["RESOURCEPATH"], "..", "Frameworks")) + + dirs.extend(dyld_fallback_library_path) + + return dirs + + +# Posix + + +class PosixLibraryLoader(LibraryLoader): + """Library loader for POSIX-like systems (including Linux)""" + + _ld_so_cache = None + + _include = re.compile(r"^\s*include\s+(?P.*)") + + name_formats = ["lib%s.so", "%s.so", "%s"] + + class _Directories(dict): + """Deal with directories""" + + def __init__(self): + dict.__init__(self) + self.order = 0 + + def add(self, directory): + """Add a directory to our current set of directories""" + if len(directory) > 1: + directory = directory.rstrip(os.path.sep) + # only adds and updates order if exists and not already in set + if not os.path.exists(directory): + return + order = self.setdefault(directory, self.order) + if order == self.order: + self.order += 1 + + def extend(self, directories): + """Add a list of directories to our set""" + for a_dir in directories: + self.add(a_dir) + + def ordered(self): + """Sort the list of directories""" + return (i[0] for i in sorted(self.items(), key=lambda d: d[1])) + + def _get_ld_so_conf_dirs(self, conf, dirs): + """ + Recursive function to help parse all ld.so.conf files, including proper + handling of the `include` directive. + """ + + try: + with open(conf) as fileobj: + for dirname in fileobj: + dirname = dirname.strip() + if not dirname: + continue + + match = self._include.match(dirname) + if not match: + dirs.add(dirname) + else: + for dir2 in glob.glob(match.group("pattern")): + self._get_ld_so_conf_dirs(dir2, dirs) + except IOError: + pass + + def _create_ld_so_cache(self): + # Recreate search path followed by ld.so. This is going to be + # slow to build, and incorrect (ld.so uses ld.so.cache, which may + # not be up-to-date). Used only as fallback for distros without + # /sbin/ldconfig. + # + # We assume the DT_RPATH and DT_RUNPATH binary sections are omitted. + + directories = self._Directories() + for name in ( + "LD_LIBRARY_PATH", + "SHLIB_PATH", # HP-UX + "LIBPATH", # OS/2, AIX + "LIBRARY_PATH", # BE/OS + ): + if name in os.environ: + directories.extend(os.environ[name].split(os.pathsep)) + + self._get_ld_so_conf_dirs("/etc/ld.so.conf", directories) + + bitage = platform.architecture()[0] + + unix_lib_dirs_list = [] + if bitage.startswith("64"): + # prefer 64 bit if that is our arch + unix_lib_dirs_list += ["/lib64", "/usr/lib64"] + + # must include standard libs, since those paths are also used by 64 bit + # installs + unix_lib_dirs_list += ["/lib", "/usr/lib"] + if sys.platform.startswith("linux"): + # Try and support multiarch work in Ubuntu + # https://wiki.ubuntu.com/MultiarchSpec + if bitage.startswith("32"): + # Assume Intel/AMD x86 compat + unix_lib_dirs_list += ["/lib/i386-linux-gnu", "/usr/lib/i386-linux-gnu"] + elif bitage.startswith("64"): + # Assume Intel/AMD x86 compatible + unix_lib_dirs_list += [ + "/lib/x86_64-linux-gnu", + "/usr/lib/x86_64-linux-gnu", + ] + else: + # guess... + unix_lib_dirs_list += glob.glob("/lib/*linux-gnu") + directories.extend(unix_lib_dirs_list) + + cache = {} + lib_re = re.compile(r"lib(.*)\.s[ol]") + # ext_re = re.compile(r"\.s[ol]$") + for our_dir in directories.ordered(): + try: + for path in glob.glob("%s/*.s[ol]*" % our_dir): + file = os.path.basename(path) + + # Index by filename + cache_i = cache.setdefault(file, set()) + cache_i.add(path) + + # Index by library name + match = lib_re.match(file) + if match: + library = match.group(1) + cache_i = cache.setdefault(library, set()) + cache_i.add(path) + except OSError: + pass + + self._ld_so_cache = cache + + def getplatformpaths(self, libname): + if self._ld_so_cache is None: + self._create_ld_so_cache() + + result = self._ld_so_cache.get(libname, set()) + for i in result: + # we iterate through all found paths for library, since we may have + # actually found multiple architectures or other library types that + # may not load + yield i + + +# Windows + + +class WindowsLibraryLoader(LibraryLoader): + """Library loader for Microsoft Windows""" + + name_formats = ["%s.dll", "lib%s.dll", "%slib.dll", "%s"] + + class Lookup(LibraryLoader.Lookup): + """Lookup class for Windows libraries...""" + + def __init__(self, path): + super(WindowsLibraryLoader.Lookup, self).__init__(path) + self.access["stdcall"] = ctypes.windll.LoadLibrary(path) + + +# Platform switching + +# If your value of sys.platform does not appear in this dict, please contact +# the Ctypesgen maintainers. + +loaderclass = { + "darwin": DarwinLibraryLoader, + "cygwin": WindowsLibraryLoader, + "win32": WindowsLibraryLoader, + "msys": WindowsLibraryLoader, +} + +load_library = loaderclass.get(sys.platform, PosixLibraryLoader)() + + +def add_library_search_dirs(other_dirs): + """ + Add libraries to search paths. + If library paths are relative, convert them to absolute with respect to this + file's directory + """ + for path in other_dirs: + if not os.path.isabs(path): + path = os.path.abspath(path) + load_library.other_dirs.append(path) + + +del loaderclass + +# End loader + +add_library_search_dirs([]) + +# Begin libraries +_libs["../libs/libiwasm.so"] = load_library("../libs/libiwasm.so") + +# 1 libraries +# End libraries + +# No modules + +__uint8_t = c_ubyte# /usr/include/x86_64-linux-gnu/bits/types.h: 38 + +__uint32_t = c_uint# /usr/include/x86_64-linux-gnu/bits/types.h: 42 + +uint8_t = __uint8_t# /usr/include/x86_64-linux-gnu/bits/stdint-uintn.h: 24 + +uint32_t = __uint32_t# /usr/include/x86_64-linux-gnu/bits/stdint-uintn.h: 26 + +uintptr_t = c_ulong# /usr/include/stdint.h: 90 + +# wasm-micro-runtime/core/iwasm/include/lib_export.h: 22 +class struct_NativeSymbol(Structure): + pass + +struct_NativeSymbol.__slots__ = [ + 'symbol', + 'func_ptr', + 'signature', + 'attachment', +] +struct_NativeSymbol._fields_ = [ + ('symbol', String), + ('func_ptr', POINTER(None)), + ('signature', String), + ('attachment', POINTER(None)), +] + +NativeSymbol = struct_NativeSymbol# wasm-micro-runtime/core/iwasm/include/lib_export.h: 22 + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 62 +class struct_WASMModuleCommon(Structure): + pass + +wasm_module_t = POINTER(struct_WASMModuleCommon)# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 63 + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 67 +class struct_WASMModuleInstanceCommon(Structure): + pass + +wasm_module_inst_t = POINTER(struct_WASMModuleInstanceCommon)# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 68 + +WASMFunctionInstanceCommon = None# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 71 + +wasm_function_inst_t = POINTER(WASMFunctionInstanceCommon)# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 72 + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 75 +class struct_wasm_section_t(Structure): + pass + +struct_wasm_section_t.__slots__ = [ + 'next', + 'section_type', + 'section_body', + 'section_body_size', +] +struct_wasm_section_t._fields_ = [ + ('next', POINTER(struct_wasm_section_t)), + ('section_type', c_int), + ('section_body', POINTER(uint8_t)), + ('section_body_size', uint32_t), +] + +wasm_section_t = struct_wasm_section_t# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 83 + +aot_section_t = struct_wasm_section_t# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 83 + +wasm_section_list_t = POINTER(struct_wasm_section_t)# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 83 + +aot_section_list_t = POINTER(struct_wasm_section_t)# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 83 + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 86 +class struct_WASMExecEnv(Structure): + pass + +wasm_exec_env_t = POINTER(struct_WASMExecEnv)# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 87 + +enum_anon_2 = c_int# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 94 + +Wasm_Module_Bytecode = 0# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 94 + +Wasm_Module_AoT = (Wasm_Module_Bytecode + 1)# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 94 + +Package_Type_Unknown = 0xFFFF# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 94 + +package_type_t = enum_anon_2# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 94 + +enum_anon_3 = c_int# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 108 + +Alloc_With_Pool = 0# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 108 + +Alloc_With_Allocator = (Alloc_With_Pool + 1)# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 108 + +Alloc_With_System_Allocator = (Alloc_With_Allocator + 1)# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 108 + +mem_alloc_type_t = enum_anon_3# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 108 + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 112 +class struct_anon_4(Structure): + pass + +struct_anon_4.__slots__ = [ + 'heap_buf', + 'heap_size', +] +struct_anon_4._fields_ = [ + ('heap_buf', POINTER(None)), + ('heap_size', uint32_t), +] + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 116 +class struct_anon_5(Structure): + pass + +struct_anon_5.__slots__ = [ + 'malloc_func', + 'realloc_func', + 'free_func', + 'user_data', +] +struct_anon_5._fields_ = [ + ('malloc_func', POINTER(None)), + ('realloc_func', POINTER(None)), + ('free_func', POINTER(None)), + ('user_data', POINTER(None)), +] + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 124 +class union_MemAllocOption(Union): + pass + +union_MemAllocOption.__slots__ = [ + 'pool', + 'allocator', +] +union_MemAllocOption._fields_ = [ + ('pool', struct_anon_4), + ('allocator', struct_anon_5), +] + +MemAllocOption = union_MemAllocOption# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 124 + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 132 +class struct_mem_alloc_info_t(Structure): + pass + +struct_mem_alloc_info_t.__slots__ = [ + 'total_size', + 'total_free_size', + 'highmark_size', +] +struct_mem_alloc_info_t._fields_ = [ + ('total_size', uint32_t), + ('total_free_size', uint32_t), + ('highmark_size', uint32_t), +] + +mem_alloc_info_t = struct_mem_alloc_info_t# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 132 + +enum_RunningMode = c_int# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 140 + +Mode_Interp = 1# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 140 + +Mode_Fast_JIT = (Mode_Interp + 1)# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 140 + +Mode_LLVM_JIT = (Mode_Fast_JIT + 1)# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 140 + +Mode_Multi_Tier_JIT = (Mode_LLVM_JIT + 1)# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 140 + +RunningMode = enum_RunningMode# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 140 + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 170 +class struct_RuntimeInitArgs(Structure): + pass + +struct_RuntimeInitArgs.__slots__ = [ + 'mem_alloc_type', + 'mem_alloc_option', + 'native_module_name', + 'native_symbols', + 'n_native_symbols', + 'max_thread_num', + 'ip_addr', + 'unused', + 'instance_port', + 'fast_jit_code_cache_size', + 'running_mode', + 'llvm_jit_opt_level', + 'llvm_jit_size_level', +] +struct_RuntimeInitArgs._fields_ = [ + ('mem_alloc_type', mem_alloc_type_t), + ('mem_alloc_option', MemAllocOption), + ('native_module_name', String), + ('native_symbols', POINTER(NativeSymbol)), + ('n_native_symbols', uint32_t), + ('max_thread_num', uint32_t), + ('ip_addr', c_char * int(128)), + ('unused', c_int), + ('instance_port', c_int), + ('fast_jit_code_cache_size', uint32_t), + ('running_mode', RunningMode), + ('llvm_jit_opt_level', uint32_t), + ('llvm_jit_size_level', uint32_t), +] + +RuntimeInitArgs = struct_RuntimeInitArgs# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 170 + +wasm_valkind_t = uint8_t# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 174 + +enum_wasm_valkind_enum = c_int# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 175 + +WASM_I32 = 0# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 175 + +WASM_I64 = (WASM_I32 + 1)# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 175 + +WASM_F32 = (WASM_I64 + 1)# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 175 + +WASM_F64 = (WASM_F32 + 1)# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 175 + +WASM_ANYREF = 128# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 175 + +WASM_FUNCREF = (WASM_ANYREF + 1)# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 175 + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 190 +class union_anon_6(Union): + pass + +union_anon_6.__slots__ = [ + 'i32', + 'i64', + 'f32', + 'f64', + 'foreign', +] +union_anon_6._fields_ = [ + ('i32', c_int32), + ('i64', c_int64), + ('f32', c_float), + ('f64', c_double), + ('foreign', uintptr_t), +] + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 199 +class struct_wasm_val_t(Structure): + pass + +struct_wasm_val_t.__slots__ = [ + 'kind', + 'of', +] +struct_wasm_val_t._fields_ = [ + ('kind', wasm_valkind_t), + ('of', union_anon_6), +] + +wasm_val_t = struct_wasm_val_t# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 199 + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 210 +if _libs["../libs/libiwasm.so"].has("wasm_runtime_init", "cdecl"): + wasm_runtime_init = _libs["../libs/libiwasm.so"].get("wasm_runtime_init", "cdecl") + wasm_runtime_init.argtypes = [] + wasm_runtime_init.restype = c_bool + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 222 +if _libs["../libs/libiwasm.so"].has("wasm_runtime_full_init", "cdecl"): + wasm_runtime_full_init = _libs["../libs/libiwasm.so"].get("wasm_runtime_full_init", "cdecl") + wasm_runtime_full_init.argtypes = [POINTER(RuntimeInitArgs)] + wasm_runtime_full_init.restype = c_bool + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 232 +for _lib in _libs.values(): + if not _lib.has("wasm_runtime_is_running_mode_supported", "cdecl"): + continue + wasm_runtime_is_running_mode_supported = _lib.get("wasm_runtime_is_running_mode_supported", "cdecl") + wasm_runtime_is_running_mode_supported.argtypes = [RunningMode] + wasm_runtime_is_running_mode_supported.restype = c_bool + break + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 244 +for _lib in _libs.values(): + if not _lib.has("wasm_runtime_set_default_running_mode", "cdecl"): + continue + wasm_runtime_set_default_running_mode = _lib.get("wasm_runtime_set_default_running_mode", "cdecl") + wasm_runtime_set_default_running_mode.argtypes = [RunningMode] + wasm_runtime_set_default_running_mode.restype = c_bool + break + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 250 +if _libs["../libs/libiwasm.so"].has("wasm_runtime_destroy", "cdecl"): + wasm_runtime_destroy = _libs["../libs/libiwasm.so"].get("wasm_runtime_destroy", "cdecl") + wasm_runtime_destroy.argtypes = [] + wasm_runtime_destroy.restype = None + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 259 +if _libs["../libs/libiwasm.so"].has("wasm_runtime_malloc", "cdecl"): + wasm_runtime_malloc = _libs["../libs/libiwasm.so"].get("wasm_runtime_malloc", "cdecl") + wasm_runtime_malloc.argtypes = [c_uint] + wasm_runtime_malloc.restype = POINTER(c_ubyte) + wasm_runtime_malloc.errcheck = lambda v,*a : cast(v, c_void_p) + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 270 +if _libs["../libs/libiwasm.so"].has("wasm_runtime_realloc", "cdecl"): + wasm_runtime_realloc = _libs["../libs/libiwasm.so"].get("wasm_runtime_realloc", "cdecl") + wasm_runtime_realloc.argtypes = [POINTER(None), c_uint] + wasm_runtime_realloc.restype = POINTER(c_ubyte) + wasm_runtime_realloc.errcheck = lambda v,*a : cast(v, c_void_p) + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 277 +if _libs["../libs/libiwasm.so"].has("wasm_runtime_free", "cdecl"): + wasm_runtime_free = _libs["../libs/libiwasm.so"].get("wasm_runtime_free", "cdecl") + wasm_runtime_free.argtypes = [POINTER(None)] + wasm_runtime_free.restype = None + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 283 +if _libs["../libs/libiwasm.so"].has("wasm_runtime_get_mem_alloc_info", "cdecl"): + wasm_runtime_get_mem_alloc_info = _libs["../libs/libiwasm.so"].get("wasm_runtime_get_mem_alloc_info", "cdecl") + wasm_runtime_get_mem_alloc_info.argtypes = [POINTER(mem_alloc_info_t)] + wasm_runtime_get_mem_alloc_info.restype = c_bool + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 294 +if _libs["../libs/libiwasm.so"].has("get_package_type", "cdecl"): + get_package_type = _libs["../libs/libiwasm.so"].get("get_package_type", "cdecl") + get_package_type.argtypes = [POINTER(uint8_t), uint32_t] + get_package_type.restype = package_type_t + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 305 +if _libs["../libs/libiwasm.so"].has("wasm_runtime_is_xip_file", "cdecl"): + wasm_runtime_is_xip_file = _libs["../libs/libiwasm.so"].get("wasm_runtime_is_xip_file", "cdecl") + wasm_runtime_is_xip_file.argtypes = [POINTER(uint8_t), uint32_t] + wasm_runtime_is_xip_file.restype = c_bool + +module_reader = CFUNCTYPE(UNCHECKED(c_bool), String, POINTER(POINTER(uint8_t)), POINTER(uint32_t))# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 310 + +module_destroyer = CFUNCTYPE(UNCHECKED(None), POINTER(uint8_t), uint32_t)# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 316 + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 325 +for _lib in _libs.values(): + if not _lib.has("wasm_runtime_set_module_reader", "cdecl"): + continue + wasm_runtime_set_module_reader = _lib.get("wasm_runtime_set_module_reader", "cdecl") + wasm_runtime_set_module_reader.argtypes = [module_reader, module_destroyer] + wasm_runtime_set_module_reader.restype = None + break + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 339 +for _lib in _libs.values(): + if not _lib.has("wasm_runtime_register_module", "cdecl"): + continue + wasm_runtime_register_module = _lib.get("wasm_runtime_register_module", "cdecl") + wasm_runtime_register_module.argtypes = [String, wasm_module_t, String, uint32_t] + wasm_runtime_register_module.restype = c_bool + break + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 351 +for _lib in _libs.values(): + if not _lib.has("wasm_runtime_find_module_registered", "cdecl"): + continue + wasm_runtime_find_module_registered = _lib.get("wasm_runtime_find_module_registered", "cdecl") + wasm_runtime_find_module_registered.argtypes = [String] + wasm_runtime_find_module_registered.restype = wasm_module_t + break + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 375 +if _libs["../libs/libiwasm.so"].has("wasm_runtime_load", "cdecl"): + wasm_runtime_load = _libs["../libs/libiwasm.so"].get("wasm_runtime_load", "cdecl") + wasm_runtime_load.argtypes = [POINTER(uint8_t), uint32_t, String, uint32_t] + wasm_runtime_load.restype = wasm_module_t + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 389 +if _libs["../libs/libiwasm.so"].has("wasm_runtime_load_from_sections", "cdecl"): + wasm_runtime_load_from_sections = _libs["../libs/libiwasm.so"].get("wasm_runtime_load_from_sections", "cdecl") + wasm_runtime_load_from_sections.argtypes = [wasm_section_list_t, c_bool, String, uint32_t] + wasm_runtime_load_from_sections.restype = wasm_module_t + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 398 +if _libs["../libs/libiwasm.so"].has("wasm_runtime_unload", "cdecl"): + wasm_runtime_unload = _libs["../libs/libiwasm.so"].get("wasm_runtime_unload", "cdecl") + wasm_runtime_unload.argtypes = [wasm_module_t] + wasm_runtime_unload.restype = None + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 408 +for _lib in _libs.values(): + if not _lib.has("wasm_runtime_get_module_hash", "cdecl"): + continue + wasm_runtime_get_module_hash = _lib.get("wasm_runtime_get_module_hash", "cdecl") + wasm_runtime_get_module_hash.argtypes = [wasm_module_t] + if sizeof(c_int) == sizeof(c_void_p): + wasm_runtime_get_module_hash.restype = ReturnString + else: + wasm_runtime_get_module_hash.restype = String + wasm_runtime_get_module_hash.errcheck = ReturnString + break + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 438 +if _libs["../libs/libiwasm.so"].has("wasm_runtime_set_wasi_args_ex", "cdecl"): + wasm_runtime_set_wasi_args_ex = _libs["../libs/libiwasm.so"].get("wasm_runtime_set_wasi_args_ex", "cdecl") + wasm_runtime_set_wasi_args_ex.argtypes = [wasm_module_t, POINTER(POINTER(c_char)), uint32_t, POINTER(POINTER(c_char)), uint32_t, POINTER(POINTER(c_char)), uint32_t, POINTER(POINTER(c_char)), c_int, c_int, c_int, c_int] + wasm_runtime_set_wasi_args_ex.restype = None + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 452 +if _libs["../libs/libiwasm.so"].has("wasm_runtime_set_wasi_args", "cdecl"): + wasm_runtime_set_wasi_args = _libs["../libs/libiwasm.so"].get("wasm_runtime_set_wasi_args", "cdecl") + wasm_runtime_set_wasi_args.argtypes = [wasm_module_t, POINTER(POINTER(c_char)), uint32_t, POINTER(POINTER(c_char)), uint32_t, POINTER(POINTER(c_char)), uint32_t, POINTER(POINTER(c_char)), c_int] + wasm_runtime_set_wasi_args.restype = None + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 459 +if _libs["../libs/libiwasm.so"].has("wasm_runtime_set_wasi_addr_pool", "cdecl"): + wasm_runtime_set_wasi_addr_pool = _libs["../libs/libiwasm.so"].get("wasm_runtime_set_wasi_addr_pool", "cdecl") + wasm_runtime_set_wasi_addr_pool.argtypes = [wasm_module_t, POINTER(POINTER(c_char)), uint32_t] + wasm_runtime_set_wasi_addr_pool.restype = None + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 463 +if _libs["../libs/libiwasm.so"].has("wasm_runtime_set_wasi_ns_lookup_pool", "cdecl"): + wasm_runtime_set_wasi_ns_lookup_pool = _libs["../libs/libiwasm.so"].get("wasm_runtime_set_wasi_ns_lookup_pool", "cdecl") + wasm_runtime_set_wasi_ns_lookup_pool.argtypes = [wasm_module_t, POINTER(POINTER(c_char)), uint32_t] + wasm_runtime_set_wasi_ns_lookup_pool.restype = None + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 486 +if _libs["../libs/libiwasm.so"].has("wasm_runtime_instantiate", "cdecl"): + wasm_runtime_instantiate = _libs["../libs/libiwasm.so"].get("wasm_runtime_instantiate", "cdecl") + wasm_runtime_instantiate.argtypes = [wasm_module_t, uint32_t, uint32_t, String, uint32_t] + wasm_runtime_instantiate.restype = wasm_module_inst_t + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 502 +for _lib in _libs.values(): + if not _lib.has("wasm_runtime_set_running_mode", "cdecl"): + continue + wasm_runtime_set_running_mode = _lib.get("wasm_runtime_set_running_mode", "cdecl") + wasm_runtime_set_running_mode.argtypes = [wasm_module_inst_t, RunningMode] + wasm_runtime_set_running_mode.restype = c_bool + break + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 516 +for _lib in _libs.values(): + if not _lib.has("wasm_runtime_get_running_mode", "cdecl"): + continue + wasm_runtime_get_running_mode = _lib.get("wasm_runtime_get_running_mode", "cdecl") + wasm_runtime_get_running_mode.argtypes = [wasm_module_inst_t] + wasm_runtime_get_running_mode.restype = RunningMode + break + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 524 +if _libs["../libs/libiwasm.so"].has("wasm_runtime_deinstantiate", "cdecl"): + wasm_runtime_deinstantiate = _libs["../libs/libiwasm.so"].get("wasm_runtime_deinstantiate", "cdecl") + wasm_runtime_deinstantiate.argtypes = [wasm_module_inst_t] + wasm_runtime_deinstantiate.restype = None + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 534 +if _libs["../libs/libiwasm.so"].has("wasm_runtime_get_module", "cdecl"): + wasm_runtime_get_module = _libs["../libs/libiwasm.so"].get("wasm_runtime_get_module", "cdecl") + wasm_runtime_get_module.argtypes = [wasm_module_inst_t] + wasm_runtime_get_module.restype = wasm_module_t + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 537 +if _libs["../libs/libiwasm.so"].has("wasm_runtime_is_wasi_mode", "cdecl"): + wasm_runtime_is_wasi_mode = _libs["../libs/libiwasm.so"].get("wasm_runtime_is_wasi_mode", "cdecl") + wasm_runtime_is_wasi_mode.argtypes = [wasm_module_inst_t] + wasm_runtime_is_wasi_mode.restype = c_bool + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 540 +if _libs["../libs/libiwasm.so"].has("wasm_runtime_lookup_wasi_start_function", "cdecl"): + wasm_runtime_lookup_wasi_start_function = _libs["../libs/libiwasm.so"].get("wasm_runtime_lookup_wasi_start_function", "cdecl") + wasm_runtime_lookup_wasi_start_function.argtypes = [wasm_module_inst_t] + wasm_runtime_lookup_wasi_start_function.restype = wasm_function_inst_t + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 552 +if _libs["../libs/libiwasm.so"].has("wasm_runtime_get_wasi_exit_code", "cdecl"): + wasm_runtime_get_wasi_exit_code = _libs["../libs/libiwasm.so"].get("wasm_runtime_get_wasi_exit_code", "cdecl") + wasm_runtime_get_wasi_exit_code.argtypes = [wasm_module_inst_t] + wasm_runtime_get_wasi_exit_code.restype = uint32_t + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 564 +if _libs["../libs/libiwasm.so"].has("wasm_runtime_lookup_function", "cdecl"): + wasm_runtime_lookup_function = _libs["../libs/libiwasm.so"].get("wasm_runtime_lookup_function", "cdecl") + wasm_runtime_lookup_function.argtypes = [wasm_module_inst_t, String, String] + wasm_runtime_lookup_function.restype = wasm_function_inst_t + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 576 +if _libs["../libs/libiwasm.so"].has("wasm_func_get_param_count", "cdecl"): + wasm_func_get_param_count = _libs["../libs/libiwasm.so"].get("wasm_func_get_param_count", "cdecl") + wasm_func_get_param_count.argtypes = [wasm_function_inst_t, wasm_module_inst_t] + wasm_func_get_param_count.restype = uint32_t + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 588 +if _libs["../libs/libiwasm.so"].has("wasm_func_get_result_count", "cdecl"): + wasm_func_get_result_count = _libs["../libs/libiwasm.so"].get("wasm_func_get_result_count", "cdecl") + wasm_func_get_result_count.argtypes = [wasm_function_inst_t, wasm_module_inst_t] + wasm_func_get_result_count.restype = uint32_t + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 599 +if _libs["../libs/libiwasm.so"].has("wasm_func_get_param_types", "cdecl"): + wasm_func_get_param_types = _libs["../libs/libiwasm.so"].get("wasm_func_get_param_types", "cdecl") + wasm_func_get_param_types.argtypes = [wasm_function_inst_t, wasm_module_inst_t, POINTER(wasm_valkind_t)] + wasm_func_get_param_types.restype = None + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 611 +if _libs["../libs/libiwasm.so"].has("wasm_func_get_result_types", "cdecl"): + wasm_func_get_result_types = _libs["../libs/libiwasm.so"].get("wasm_func_get_result_types", "cdecl") + wasm_func_get_result_types.argtypes = [wasm_function_inst_t, wasm_module_inst_t, POINTER(wasm_valkind_t)] + wasm_func_get_result_types.restype = None + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 625 +if _libs["../libs/libiwasm.so"].has("wasm_runtime_create_exec_env", "cdecl"): + wasm_runtime_create_exec_env = _libs["../libs/libiwasm.so"].get("wasm_runtime_create_exec_env", "cdecl") + wasm_runtime_create_exec_env.argtypes = [wasm_module_inst_t, uint32_t] + wasm_runtime_create_exec_env.restype = wasm_exec_env_t + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 634 +if _libs["../libs/libiwasm.so"].has("wasm_runtime_destroy_exec_env", "cdecl"): + wasm_runtime_destroy_exec_env = _libs["../libs/libiwasm.so"].get("wasm_runtime_destroy_exec_env", "cdecl") + wasm_runtime_destroy_exec_env.argtypes = [wasm_exec_env_t] + wasm_runtime_destroy_exec_env.restype = None + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 651 +if _libs["../libs/libiwasm.so"].has("wasm_runtime_get_exec_env_singleton", "cdecl"): + wasm_runtime_get_exec_env_singleton = _libs["../libs/libiwasm.so"].get("wasm_runtime_get_exec_env_singleton", "cdecl") + wasm_runtime_get_exec_env_singleton.argtypes = [wasm_module_inst_t] + wasm_runtime_get_exec_env_singleton.restype = wasm_exec_env_t + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 674 +for _lib in _libs.values(): + if not _lib.has("wasm_runtime_start_debug_instance_with_port", "cdecl"): + continue + wasm_runtime_start_debug_instance_with_port = _lib.get("wasm_runtime_start_debug_instance_with_port", "cdecl") + wasm_runtime_start_debug_instance_with_port.argtypes = [wasm_exec_env_t, c_int32] + wasm_runtime_start_debug_instance_with_port.restype = uint32_t + break + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 680 +for _lib in _libs.values(): + if not _lib.has("wasm_runtime_start_debug_instance", "cdecl"): + continue + wasm_runtime_start_debug_instance = _lib.get("wasm_runtime_start_debug_instance", "cdecl") + wasm_runtime_start_debug_instance.argtypes = [wasm_exec_env_t] + wasm_runtime_start_debug_instance.restype = uint32_t + break + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 695 +if _libs["../libs/libiwasm.so"].has("wasm_runtime_init_thread_env", "cdecl"): + wasm_runtime_init_thread_env = _libs["../libs/libiwasm.so"].get("wasm_runtime_init_thread_env", "cdecl") + wasm_runtime_init_thread_env.argtypes = [] + wasm_runtime_init_thread_env.restype = c_bool + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 701 +if _libs["../libs/libiwasm.so"].has("wasm_runtime_destroy_thread_env", "cdecl"): + wasm_runtime_destroy_thread_env = _libs["../libs/libiwasm.so"].get("wasm_runtime_destroy_thread_env", "cdecl") + wasm_runtime_destroy_thread_env.argtypes = [] + wasm_runtime_destroy_thread_env.restype = None + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 707 +if _libs["../libs/libiwasm.so"].has("wasm_runtime_thread_env_inited", "cdecl"): + wasm_runtime_thread_env_inited = _libs["../libs/libiwasm.so"].get("wasm_runtime_thread_env_inited", "cdecl") + wasm_runtime_thread_env_inited.argtypes = [] + wasm_runtime_thread_env_inited.restype = c_bool + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 717 +if _libs["../libs/libiwasm.so"].has("wasm_runtime_get_module_inst", "cdecl"): + wasm_runtime_get_module_inst = _libs["../libs/libiwasm.so"].get("wasm_runtime_get_module_inst", "cdecl") + wasm_runtime_get_module_inst.argtypes = [wasm_exec_env_t] + wasm_runtime_get_module_inst.restype = wasm_module_inst_t + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 731 +if _libs["../libs/libiwasm.so"].has("wasm_runtime_set_module_inst", "cdecl"): + wasm_runtime_set_module_inst = _libs["../libs/libiwasm.so"].get("wasm_runtime_set_module_inst", "cdecl") + wasm_runtime_set_module_inst.argtypes = [wasm_exec_env_t, wasm_module_inst_t] + wasm_runtime_set_module_inst.restype = None + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 755 +if _libs["../libs/libiwasm.so"].has("wasm_runtime_call_wasm", "cdecl"): + wasm_runtime_call_wasm = _libs["../libs/libiwasm.so"].get("wasm_runtime_call_wasm", "cdecl") + wasm_runtime_call_wasm.argtypes = [wasm_exec_env_t, wasm_function_inst_t, uint32_t, POINTER(uint32_t)] + wasm_runtime_call_wasm.restype = c_bool + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 776 +if _libs["../libs/libiwasm.so"].has("wasm_runtime_call_wasm_a", "cdecl"): + wasm_runtime_call_wasm_a = _libs["../libs/libiwasm.so"].get("wasm_runtime_call_wasm_a", "cdecl") + wasm_runtime_call_wasm_a.argtypes = [wasm_exec_env_t, wasm_function_inst_t, uint32_t, POINTER(wasm_val_t), uint32_t, POINTER(wasm_val_t)] + wasm_runtime_call_wasm_a.restype = c_bool + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 798 +if _libs["../libs/libiwasm.so"].has("wasm_runtime_call_wasm_v", "cdecl"): + _func = _libs["../libs/libiwasm.so"].get("wasm_runtime_call_wasm_v", "cdecl") + _restype = c_bool + _errcheck = None + _argtypes = [wasm_exec_env_t, wasm_function_inst_t, uint32_t, POINTER(wasm_val_t), uint32_t] + wasm_runtime_call_wasm_v = _variadic_function(_func,_restype,_argtypes,_errcheck) + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 818 +if _libs["../libs/libiwasm.so"].has("wasm_application_execute_main", "cdecl"): + wasm_application_execute_main = _libs["../libs/libiwasm.so"].get("wasm_application_execute_main", "cdecl") + wasm_application_execute_main.argtypes = [wasm_module_inst_t, c_int32, POINTER(POINTER(c_char))] + wasm_application_execute_main.restype = c_bool + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 837 +if _libs["../libs/libiwasm.so"].has("wasm_application_execute_func", "cdecl"): + wasm_application_execute_func = _libs["../libs/libiwasm.so"].get("wasm_application_execute_func", "cdecl") + wasm_application_execute_func.argtypes = [wasm_module_inst_t, String, c_int32, POINTER(POINTER(c_char))] + wasm_application_execute_func.restype = c_bool + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 846 +if _libs["../libs/libiwasm.so"].has("wasm_runtime_get_exception", "cdecl"): + wasm_runtime_get_exception = _libs["../libs/libiwasm.so"].get("wasm_runtime_get_exception", "cdecl") + wasm_runtime_get_exception.argtypes = [wasm_module_inst_t] + wasm_runtime_get_exception.restype = c_char_p + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 857 +if _libs["../libs/libiwasm.so"].has("wasm_runtime_set_exception", "cdecl"): + wasm_runtime_set_exception = _libs["../libs/libiwasm.so"].get("wasm_runtime_set_exception", "cdecl") + wasm_runtime_set_exception.argtypes = [wasm_module_inst_t, String] + wasm_runtime_set_exception.restype = None + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 866 +if _libs["../libs/libiwasm.so"].has("wasm_runtime_clear_exception", "cdecl"): + wasm_runtime_clear_exception = _libs["../libs/libiwasm.so"].get("wasm_runtime_clear_exception", "cdecl") + wasm_runtime_clear_exception.argtypes = [wasm_module_inst_t] + wasm_runtime_clear_exception.restype = None + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 878 +if _libs["../libs/libiwasm.so"].has("wasm_runtime_set_custom_data", "cdecl"): + wasm_runtime_set_custom_data = _libs["../libs/libiwasm.so"].get("wasm_runtime_set_custom_data", "cdecl") + wasm_runtime_set_custom_data.argtypes = [wasm_module_inst_t, POINTER(None)] + wasm_runtime_set_custom_data.restype = None + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 887 +if _libs["../libs/libiwasm.so"].has("wasm_runtime_get_custom_data", "cdecl"): + wasm_runtime_get_custom_data = _libs["../libs/libiwasm.so"].get("wasm_runtime_get_custom_data", "cdecl") + wasm_runtime_get_custom_data.argtypes = [wasm_module_inst_t] + wasm_runtime_get_custom_data.restype = POINTER(c_ubyte) + wasm_runtime_get_custom_data.errcheck = lambda v,*a : cast(v, c_void_p) + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 910 +if _libs["../libs/libiwasm.so"].has("wasm_runtime_module_malloc", "cdecl"): + wasm_runtime_module_malloc = _libs["../libs/libiwasm.so"].get("wasm_runtime_module_malloc", "cdecl") + wasm_runtime_module_malloc.argtypes = [wasm_module_inst_t, uint32_t, POINTER(POINTER(None))] + wasm_runtime_module_malloc.restype = uint32_t + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 920 +if _libs["../libs/libiwasm.so"].has("wasm_runtime_module_free", "cdecl"): + wasm_runtime_module_free = _libs["../libs/libiwasm.so"].get("wasm_runtime_module_free", "cdecl") + wasm_runtime_module_free.argtypes = [wasm_module_inst_t, uint32_t] + wasm_runtime_module_free.restype = None + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 936 +if _libs["../libs/libiwasm.so"].has("wasm_runtime_module_dup_data", "cdecl"): + wasm_runtime_module_dup_data = _libs["../libs/libiwasm.so"].get("wasm_runtime_module_dup_data", "cdecl") + wasm_runtime_module_dup_data.argtypes = [wasm_module_inst_t, String, uint32_t] + wasm_runtime_module_dup_data.restype = uint32_t + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 951 +if _libs["../libs/libiwasm.so"].has("wasm_runtime_validate_app_addr", "cdecl"): + wasm_runtime_validate_app_addr = _libs["../libs/libiwasm.so"].get("wasm_runtime_validate_app_addr", "cdecl") + wasm_runtime_validate_app_addr.argtypes = [wasm_module_inst_t, uint32_t, uint32_t] + wasm_runtime_validate_app_addr.restype = c_bool + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 973 +if _libs["../libs/libiwasm.so"].has("wasm_runtime_validate_app_str_addr", "cdecl"): + wasm_runtime_validate_app_str_addr = _libs["../libs/libiwasm.so"].get("wasm_runtime_validate_app_str_addr", "cdecl") + wasm_runtime_validate_app_str_addr.argtypes = [wasm_module_inst_t, uint32_t] + wasm_runtime_validate_app_str_addr.restype = c_bool + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 989 +if _libs["../libs/libiwasm.so"].has("wasm_runtime_validate_native_addr", "cdecl"): + wasm_runtime_validate_native_addr = _libs["../libs/libiwasm.so"].get("wasm_runtime_validate_native_addr", "cdecl") + wasm_runtime_validate_native_addr.argtypes = [wasm_module_inst_t, POINTER(None), uint32_t] + wasm_runtime_validate_native_addr.restype = c_bool + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 1004 +if _libs["../libs/libiwasm.so"].has("wasm_runtime_addr_app_to_native", "cdecl"): + wasm_runtime_addr_app_to_native = _libs["../libs/libiwasm.so"].get("wasm_runtime_addr_app_to_native", "cdecl") + wasm_runtime_addr_app_to_native.argtypes = [wasm_module_inst_t, uint32_t] + wasm_runtime_addr_app_to_native.restype = POINTER(c_ubyte) + wasm_runtime_addr_app_to_native.errcheck = lambda v,*a : cast(v, c_void_p) + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 1017 +if _libs["../libs/libiwasm.so"].has("wasm_runtime_addr_native_to_app", "cdecl"): + wasm_runtime_addr_native_to_app = _libs["../libs/libiwasm.so"].get("wasm_runtime_addr_native_to_app", "cdecl") + wasm_runtime_addr_native_to_app.argtypes = [wasm_module_inst_t, POINTER(None)] + wasm_runtime_addr_native_to_app.restype = uint32_t + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 1031 +if _libs["../libs/libiwasm.so"].has("wasm_runtime_get_app_addr_range", "cdecl"): + wasm_runtime_get_app_addr_range = _libs["../libs/libiwasm.so"].get("wasm_runtime_get_app_addr_range", "cdecl") + wasm_runtime_get_app_addr_range.argtypes = [wasm_module_inst_t, uint32_t, POINTER(uint32_t), POINTER(uint32_t)] + wasm_runtime_get_app_addr_range.restype = c_bool + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 1050 +if _libs["../libs/libiwasm.so"].has("wasm_runtime_get_native_addr_range", "cdecl"): + wasm_runtime_get_native_addr_range = _libs["../libs/libiwasm.so"].get("wasm_runtime_get_native_addr_range", "cdecl") + wasm_runtime_get_native_addr_range.argtypes = [wasm_module_inst_t, POINTER(uint8_t), POINTER(POINTER(uint8_t)), POINTER(POINTER(uint8_t))] + wasm_runtime_get_native_addr_range.restype = c_bool + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 1089 +if _libs["../libs/libiwasm.so"].has("wasm_runtime_register_natives", "cdecl"): + wasm_runtime_register_natives = _libs["../libs/libiwasm.so"].get("wasm_runtime_register_natives", "cdecl") + wasm_runtime_register_natives.argtypes = [String, POINTER(NativeSymbol), uint32_t] + wasm_runtime_register_natives.restype = c_bool + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 1104 +if _libs["../libs/libiwasm.so"].has("wasm_runtime_register_natives_raw", "cdecl"): + wasm_runtime_register_natives_raw = _libs["../libs/libiwasm.so"].get("wasm_runtime_register_natives_raw", "cdecl") + wasm_runtime_register_natives_raw.argtypes = [String, POINTER(NativeSymbol), uint32_t] + wasm_runtime_register_natives_raw.restype = c_bool + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 1123 +if _libs["../libs/libiwasm.so"].has("wasm_runtime_unregister_natives", "cdecl"): + wasm_runtime_unregister_natives = _libs["../libs/libiwasm.so"].get("wasm_runtime_unregister_natives", "cdecl") + wasm_runtime_unregister_natives.argtypes = [String, POINTER(NativeSymbol)] + wasm_runtime_unregister_natives.restype = c_bool + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 1133 +if _libs["../libs/libiwasm.so"].has("wasm_runtime_get_function_attachment", "cdecl"): + wasm_runtime_get_function_attachment = _libs["../libs/libiwasm.so"].get("wasm_runtime_get_function_attachment", "cdecl") + wasm_runtime_get_function_attachment.argtypes = [wasm_exec_env_t] + wasm_runtime_get_function_attachment.restype = POINTER(c_ubyte) + wasm_runtime_get_function_attachment.errcheck = lambda v,*a : cast(v, c_void_p) + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 1143 +if _libs["../libs/libiwasm.so"].has("wasm_runtime_set_user_data", "cdecl"): + wasm_runtime_set_user_data = _libs["../libs/libiwasm.so"].get("wasm_runtime_set_user_data", "cdecl") + wasm_runtime_set_user_data.argtypes = [wasm_exec_env_t, POINTER(None)] + wasm_runtime_set_user_data.restype = None + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 1152 +if _libs["../libs/libiwasm.so"].has("wasm_runtime_get_user_data", "cdecl"): + wasm_runtime_get_user_data = _libs["../libs/libiwasm.so"].get("wasm_runtime_get_user_data", "cdecl") + wasm_runtime_get_user_data.argtypes = [wasm_exec_env_t] + wasm_runtime_get_user_data.restype = POINTER(c_ubyte) + wasm_runtime_get_user_data.errcheck = lambda v,*a : cast(v, c_void_p) + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 1165 +for _lib in _libs.values(): + if not _lib.has("wasm_runtime_dump_mem_consumption", "cdecl"): + continue + wasm_runtime_dump_mem_consumption = _lib.get("wasm_runtime_dump_mem_consumption", "cdecl") + wasm_runtime_dump_mem_consumption.argtypes = [wasm_exec_env_t] + wasm_runtime_dump_mem_consumption.restype = None + break + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 1173 +for _lib in _libs.values(): + if not _lib.has("wasm_runtime_dump_perf_profiling", "cdecl"): + continue + wasm_runtime_dump_perf_profiling = _lib.get("wasm_runtime_dump_perf_profiling", "cdecl") + wasm_runtime_dump_perf_profiling.argtypes = [wasm_module_inst_t] + wasm_runtime_dump_perf_profiling.restype = None + break + +wasm_thread_callback_t = CFUNCTYPE(UNCHECKED(POINTER(c_ubyte)), wasm_exec_env_t, POINTER(None))# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 1176 + +wasm_thread_t = uintptr_t# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 1178 + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 1186 +for _lib in _libs.values(): + if not _lib.has("wasm_runtime_set_max_thread_num", "cdecl"): + continue + wasm_runtime_set_max_thread_num = _lib.get("wasm_runtime_set_max_thread_num", "cdecl") + wasm_runtime_set_max_thread_num.argtypes = [uint32_t] + wasm_runtime_set_max_thread_num.restype = None + break + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 1197 +for _lib in _libs.values(): + if not _lib.has("wasm_runtime_spawn_exec_env", "cdecl"): + continue + wasm_runtime_spawn_exec_env = _lib.get("wasm_runtime_spawn_exec_env", "cdecl") + wasm_runtime_spawn_exec_env.argtypes = [wasm_exec_env_t] + wasm_runtime_spawn_exec_env.restype = wasm_exec_env_t + break + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 1205 +for _lib in _libs.values(): + if not _lib.has("wasm_runtime_destroy_spawned_exec_env", "cdecl"): + continue + wasm_runtime_destroy_spawned_exec_env = _lib.get("wasm_runtime_destroy_spawned_exec_env", "cdecl") + wasm_runtime_destroy_spawned_exec_env.argtypes = [wasm_exec_env_t] + wasm_runtime_destroy_spawned_exec_env.restype = None + break + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 1218 +for _lib in _libs.values(): + if not _lib.has("wasm_runtime_spawn_thread", "cdecl"): + continue + wasm_runtime_spawn_thread = _lib.get("wasm_runtime_spawn_thread", "cdecl") + wasm_runtime_spawn_thread.argtypes = [wasm_exec_env_t, POINTER(wasm_thread_t), wasm_thread_callback_t, POINTER(None)] + wasm_runtime_spawn_thread.restype = c_int32 + break + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 1230 +for _lib in _libs.values(): + if not _lib.has("wasm_runtime_join_thread", "cdecl"): + continue + wasm_runtime_join_thread = _lib.get("wasm_runtime_join_thread", "cdecl") + wasm_runtime_join_thread.argtypes = [wasm_thread_t, POINTER(POINTER(None))] + wasm_runtime_join_thread.restype = c_int32 + break + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 1244 +for _lib in _libs.values(): + if not _lib.has("wasm_externref_obj2ref", "cdecl"): + continue + wasm_externref_obj2ref = _lib.get("wasm_externref_obj2ref", "cdecl") + wasm_externref_obj2ref.argtypes = [wasm_module_inst_t, POINTER(None), POINTER(uint32_t)] + wasm_externref_obj2ref.restype = c_bool + break + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 1257 +for _lib in _libs.values(): + if not _lib.has("wasm_externref_ref2obj", "cdecl"): + continue + wasm_externref_ref2obj = _lib.get("wasm_externref_ref2obj", "cdecl") + wasm_externref_ref2obj.argtypes = [uint32_t, POINTER(POINTER(None))] + wasm_externref_ref2obj.restype = c_bool + break + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 1269 +for _lib in _libs.values(): + if not _lib.has("wasm_externref_retain", "cdecl"): + continue + wasm_externref_retain = _lib.get("wasm_externref_retain", "cdecl") + wasm_externref_retain.argtypes = [uint32_t] + wasm_externref_retain.restype = c_bool + break + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 1277 +for _lib in _libs.values(): + if not _lib.has("wasm_runtime_dump_call_stack", "cdecl"): + continue + wasm_runtime_dump_call_stack = _lib.get("wasm_runtime_dump_call_stack", "cdecl") + wasm_runtime_dump_call_stack.argtypes = [wasm_exec_env_t] + wasm_runtime_dump_call_stack.restype = None + break + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 1288 +for _lib in _libs.values(): + if not _lib.has("wasm_runtime_get_call_stack_buf_size", "cdecl"): + continue + wasm_runtime_get_call_stack_buf_size = _lib.get("wasm_runtime_get_call_stack_buf_size", "cdecl") + wasm_runtime_get_call_stack_buf_size.argtypes = [wasm_exec_env_t] + wasm_runtime_get_call_stack_buf_size.restype = uint32_t + break + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 1304 +for _lib in _libs.values(): + if not _lib.has("wasm_runtime_dump_call_stack_to_buf", "cdecl"): + continue + wasm_runtime_dump_call_stack_to_buf = _lib.get("wasm_runtime_dump_call_stack_to_buf", "cdecl") + wasm_runtime_dump_call_stack_to_buf.argtypes = [wasm_exec_env_t, String, uint32_t] + wasm_runtime_dump_call_stack_to_buf.restype = uint32_t + break + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 1317 +for _lib in _libs.values(): + if not _lib.has("wasm_runtime_get_custom_section", "cdecl"): + continue + wasm_runtime_get_custom_section = _lib.get("wasm_runtime_get_custom_section", "cdecl") + wasm_runtime_get_custom_section.argtypes = [wasm_module_t, String, POINTER(uint32_t)] + wasm_runtime_get_custom_section.restype = POINTER(uint8_t) + break + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 1326 +if _libs["../libs/libiwasm.so"].has("wasm_runtime_get_version", "cdecl"): + wasm_runtime_get_version = _libs["../libs/libiwasm.so"].get("wasm_runtime_get_version", "cdecl") + wasm_runtime_get_version.argtypes = [POINTER(uint32_t), POINTER(uint32_t), POINTER(uint32_t)] + wasm_runtime_get_version.restype = None + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 1333 +for _lib in _libs.values(): + if not _lib.has("wasm_runtime_is_import_func_linked", "cdecl"): + continue + wasm_runtime_is_import_func_linked = _lib.get("wasm_runtime_is_import_func_linked", "cdecl") + wasm_runtime_is_import_func_linked.argtypes = [String, String] + wasm_runtime_is_import_func_linked.restype = c_bool + break + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 1341 +for _lib in _libs.values(): + if not _lib.has("wasm_runtime_is_import_global_linked", "cdecl"): + continue + wasm_runtime_is_import_global_linked = _lib.get("wasm_runtime_is_import_global_linked", "cdecl") + wasm_runtime_is_import_global_linked.argtypes = [String, String] + wasm_runtime_is_import_global_linked.restype = c_bool + break + +# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 31 +def get_module_inst(exec_env): + return (wasm_runtime_get_module_inst (exec_env)) + +WASMModuleCommon = struct_WASMModuleCommon# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 62 + +WASMModuleInstanceCommon = struct_WASMModuleInstanceCommon# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 67 + +wasm_section_t = struct_wasm_section_t# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 75 + +WASMExecEnv = struct_WASMExecEnv# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 86 + +MemAllocOption = union_MemAllocOption# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 124 + +mem_alloc_info_t = struct_mem_alloc_info_t# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 132 + +RuntimeInitArgs = struct_RuntimeInitArgs# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 170 + +wasm_val_t = struct_wasm_val_t# wasm-micro-runtime/core/iwasm/include/wasm_export.h: 199 + +# No inserted files + +# No prefix-stripping + diff --git a/language-bindings/python/src/wamr/wamrapi/wamr.py b/language-bindings/python/src/wamr/wamrapi/wamr.py new file mode 100644 index 00000000..e8d496c3 --- /dev/null +++ b/language-bindings/python/src/wamr/wamrapi/wamr.py @@ -0,0 +1,123 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +from ctypes import Array +from ctypes import c_char +from ctypes import c_uint +from ctypes import c_uint8 +from ctypes import c_void_p +from ctypes import cast +from ctypes import create_string_buffer +from ctypes import POINTER +from ctypes import pointer + +from wamr.wamrapi.iwasm import Alloc_With_Pool +from wamr.wamrapi.iwasm import RuntimeInitArgs +from wamr.wamrapi.iwasm import wasm_exec_env_t +from wamr.wamrapi.iwasm import wasm_function_inst_t +from wamr.wamrapi.iwasm import wasm_module_inst_t +from wamr.wamrapi.iwasm import wasm_module_t +from wamr.wamrapi.iwasm import wasm_runtime_call_wasm +from wamr.wamrapi.iwasm import wasm_runtime_create_exec_env +from wamr.wamrapi.iwasm import wasm_runtime_deinstantiate +from wamr.wamrapi.iwasm import wasm_runtime_destroy +from wamr.wamrapi.iwasm import wasm_runtime_destroy_exec_env +from wamr.wamrapi.iwasm import wasm_runtime_full_init +from wamr.wamrapi.iwasm import wasm_runtime_instantiate +from wamr.wamrapi.iwasm import wasm_runtime_load +from wamr.wamrapi.iwasm import wasm_runtime_lookup_function +from wamr.wamrapi.iwasm import wasm_runtime_unload + + +class Engine: + def __init__(self): + self.init_args = self._get_init_args() + wasm_runtime_full_init(pointer(self.init_args)) + + def __del__(self): + print("deleting Engine") + wasm_runtime_destroy() + + def _get_init_args(self, heap_size: int = 1024 * 512) -> RuntimeInitArgs: + init_args = RuntimeInitArgs() + init_args.mem_alloc_type = Alloc_With_Pool + init_args.mem_alloc_option.pool.heap_buf = cast( + (c_char * heap_size)(), c_void_p + ) + init_args.mem_alloc_option.pool.heap_size = heap_size + return init_args + + +class Module: + __create_key = object() + + @classmethod + def from_file(cls, engine: Engine, fp: str) -> "Module": + return Module(cls.__create_key, engine, fp) + + def __init__(self, create_key: object, engine: Engine, fp: str) -> None: + assert ( + create_key == Module.__create_key + ), "Module objects must be created using Module.from_file" + self.engine = engine + self.module, self.file_data = self._create_module(fp) + + def __del__(self): + print("deleting Module") + wasm_runtime_unload(self.module) + + def _create_module(self, fp: str) -> tuple[wasm_module_t, Array[c_uint]]: + with open(fp, "rb") as f: + data = f.read() + data = (c_uint8 * len(data))(*data) + + error_buf = create_string_buffer(128) + module = wasm_runtime_load(data, len(data), error_buf, len(error_buf)) + if not module: + raise Exception("Error while creating module") + return module, data + + +class Instance: + def __init__(self, module: Module, stack_size: int = 65536, heap_size: int = 16384): + self.module = module + self.module_inst = self._create_module_inst(module, stack_size, heap_size) + + def __del__(self): + print("deleting Instance") + wasm_runtime_deinstantiate(self.module_inst) + + def lookup_function(self, name: str): + func = wasm_runtime_lookup_function(self.module_inst, name, None) + if not func: + raise Exception("Error while looking-up function") + return func + + def _create_module_inst(self, module: Module, stack_size: int, heap_size: int) -> wasm_module_inst_t: + error_buf = create_string_buffer(128) + module_inst = wasm_runtime_instantiate( + module.module, stack_size, heap_size, error_buf, len(error_buf) + ) + if not module_inst: + raise Exception("Error while creating module instance") + return module_inst + + +class ExecEnv: + def __init__(self, module_inst: Instance, stack_size: int = 65536): + self.module_inst = module_inst + self.exec_env = self._create_exec_env(module_inst, stack_size) + + def __del__(self): + print("deleting ExecEnv") + wasm_runtime_destroy_exec_env(self.exec_env) + + def call(self, func: wasm_function_inst_t, argc: int, argv: "POINTER[c_uint]"): + if not wasm_runtime_call_wasm(self.exec_env, func, argc, argv): + raise Exception("Error while calling function") + + def _create_exec_env(self, module_inst: Instance, stack_size: int) -> wasm_exec_env_t: + exec_env = wasm_runtime_create_exec_env(module_inst.module_inst, stack_size) + if not exec_env: + raise Exception("Error while creating execution environment") + return exec_env diff --git a/language-bindings/python/wamr/__init__.py b/language-bindings/python/src/wamr/wasmcapi/__init__.py similarity index 100% rename from language-bindings/python/wamr/__init__.py rename to language-bindings/python/src/wamr/wasmcapi/__init__.py diff --git a/language-bindings/python/wamr/binding.py b/language-bindings/python/src/wamr/wasmcapi/binding.py similarity index 100% rename from language-bindings/python/wamr/binding.py rename to language-bindings/python/src/wamr/wasmcapi/binding.py diff --git a/language-bindings/python/wamr/ffi.py b/language-bindings/python/src/wamr/wasmcapi/ffi.py similarity index 99% rename from language-bindings/python/wamr/ffi.py rename to language-bindings/python/src/wamr/wasmcapi/ffi.py index a29b607c..18b6bc90 100644 --- a/language-bindings/python/wamr/ffi.py +++ b/language-bindings/python/src/wamr/wasmcapi/ffi.py @@ -36,8 +36,8 @@ current_file = Path(__file__) if current_file.is_symlink(): current_file = Path(os.readlink(current_file)) current_dir = current_file.parent.resolve() -root_dir = current_dir.parent.parent.parent.parent.resolve() -wamr_dir = root_dir.joinpath("wasm-micro-runtime").resolve() +root_dir = current_dir.parents[4].resolve() +wamr_dir = root_dir.resolve() if not wamr_dir.exists(): raise RuntimeError(f"not found the repo of wasm-micro-runtime under {root_dir}") diff --git a/language-bindings/python/utils/create_lib.sh b/language-bindings/python/utils/create_lib.sh new file mode 100755 index 00000000..56e829e3 --- /dev/null +++ b/language-bindings/python/utils/create_lib.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +CUR_DIR=$(cd $(dirname $0) && pwd -P) +ROOT_DIR=${CUR_DIR}/../../.. + +WAMR_BUILD_PLATFORM=${WAMR_BUILD_PLATFORM:-"linux"} + +cd ${ROOT_DIR}/product-mini/platforms/${WAMR_BUILD_PLATFORM} + +mkdir -p build && cd build +cmake .. +make -j + +cp libiwasm.so ${CUR_DIR}/../src/wamr/libs diff --git a/language-bindings/python/wamr-api/README.md b/language-bindings/python/wamr-api/README.md new file mode 100644 index 00000000..eb89b421 --- /dev/null +++ b/language-bindings/python/wamr-api/README.md @@ -0,0 +1,25 @@ +# WARM API + +## Examples + +Copy in `language-bindings/python/wamr/libs` the library `libiwasm` generated from `product-mini/platforms`. + +There is a [simple example](./samples/main.py) to show how to use bindings. + +``` +python samples/main.py +``` + +## Update WAMR API bindings + +Install requirements, + +``` +pip install -r requirements.txt +``` + +Run the following command, + +```sh +ctypesgen ../../../../core/iwasm/include/wasm_export.h -l ../libs/libiwasm.so -o iwasm.py +``` diff --git a/language-bindings/python/wamr-api/requirements.txt b/language-bindings/python/wamr-api/requirements.txt new file mode 100644 index 00000000..923575a4 --- /dev/null +++ b/language-bindings/python/wamr-api/requirements.txt @@ -0,0 +1 @@ +ctypesgen==1.1.1 \ No newline at end of file diff --git a/language-bindings/python/wamr-api/samples/compile.sh b/language-bindings/python/wamr-api/samples/compile.sh new file mode 100644 index 00000000..637b919c --- /dev/null +++ b/language-bindings/python/wamr-api/samples/compile.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +/opt/wasi-sdk/bin/clang \ + -O0 -z stack-size=4096 -Wl,--initial-memory=65536 \ + -Wl,--strip-all,--no-entry -nostdlib \ + -Wl,--export=sum\ + -Wl,--allow-undefined \ + -o test.wasm sum.c diff --git a/language-bindings/python/wamr-api/samples/main.py b/language-bindings/python/wamr-api/samples/main.py new file mode 100644 index 00000000..525aab81 --- /dev/null +++ b/language-bindings/python/wamr-api/samples/main.py @@ -0,0 +1,22 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +from wamr.wamrapi.wamr import Engine, Module, Instance, ExecEnv +from ctypes import c_uint +import pathlib + +def main(): + engine = Engine() + module = Module.from_file(engine, pathlib.Path(__file__).parent / "sum.wasm") + module_inst = Instance(module) + exec_env = ExecEnv(module_inst) + + func = module_inst.lookup_function("sum") + + argv = (c_uint * 2)(*[10, 11]) + exec_env.call(func, len(argv), argv) + print(argv[0]) + + +if __name__ == "__main__": + main() diff --git a/language-bindings/python/wamr-api/samples/sum.c b/language-bindings/python/wamr-api/samples/sum.c new file mode 100644 index 00000000..586c5bc6 --- /dev/null +++ b/language-bindings/python/wamr-api/samples/sum.c @@ -0,0 +1,12 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include + +int +sum(int a, int b) +{ + return a + b; +} diff --git a/language-bindings/python/wasm-c-api/README.md b/language-bindings/python/wasm-c-api/README.md new file mode 100644 index 00000000..1684afa5 --- /dev/null +++ b/language-bindings/python/wasm-c-api/README.md @@ -0,0 +1,7 @@ +# WASM-C-API + +## Examples + +There is a [simple example](./samples/hello_procedural.py) to show how to use bindings. Actually, the python binding follows C-APIs. There it should be easy if be familiar with _programming with wasm-c-api_. + +Unit test cases under _./tests_ could be another but more complete references. diff --git a/language-bindings/python/docs/design.md b/language-bindings/python/wasm-c-api/docs/design.md similarity index 100% rename from language-bindings/python/docs/design.md rename to language-bindings/python/wasm-c-api/docs/design.md diff --git a/language-bindings/python/docs/images/python_package_life_cycle.png b/language-bindings/python/wasm-c-api/docs/images/python_package_life_cycle.png similarity index 100% rename from language-bindings/python/docs/images/python_package_life_cycle.png rename to language-bindings/python/wasm-c-api/docs/images/python_package_life_cycle.png diff --git a/language-bindings/python/docs/setup_dev_env.md b/language-bindings/python/wasm-c-api/docs/setup_dev_env.md similarity index 100% rename from language-bindings/python/docs/setup_dev_env.md rename to language-bindings/python/wasm-c-api/docs/setup_dev_env.md diff --git a/language-bindings/python/requirements.txt b/language-bindings/python/wasm-c-api/requirements.txt similarity index 100% rename from language-bindings/python/requirements.txt rename to language-bindings/python/wasm-c-api/requirements.txt diff --git a/language-bindings/python/samples/hello.wat b/language-bindings/python/wasm-c-api/samples/hello.wat similarity index 100% rename from language-bindings/python/samples/hello.wat rename to language-bindings/python/wasm-c-api/samples/hello.wat diff --git a/language-bindings/python/samples/hello_oop.py b/language-bindings/python/wasm-c-api/samples/hello_oop.py similarity index 100% rename from language-bindings/python/samples/hello_oop.py rename to language-bindings/python/wasm-c-api/samples/hello_oop.py diff --git a/language-bindings/python/samples/hello_procedural.py b/language-bindings/python/wasm-c-api/samples/hello_procedural.py similarity index 98% rename from language-bindings/python/samples/hello_procedural.py rename to language-bindings/python/wasm-c-api/samples/hello_procedural.py index ed3002d5..5924423b 100644 --- a/language-bindings/python/samples/hello_procedural.py +++ b/language-bindings/python/wasm-c-api/samples/hello_procedural.py @@ -5,7 +5,7 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception # import ctypes -import wamr.ffi as ffi +import wamr.wasmcapi.ffi as ffi WAMS_BINARY_CONTENT = ( b"\x00asm\x01\x00\x00\x00\x01\x84\x80\x80\x80\x00\x01`\x00\x00\x02\x8a\x80" diff --git a/language-bindings/python/tests/__init__.py b/language-bindings/python/wasm-c-api/tests/__init__.py similarity index 100% rename from language-bindings/python/tests/__init__.py rename to language-bindings/python/wasm-c-api/tests/__init__.py diff --git a/language-bindings/python/tests/context.py b/language-bindings/python/wasm-c-api/tests/context.py similarity index 100% rename from language-bindings/python/tests/context.py rename to language-bindings/python/wasm-c-api/tests/context.py diff --git a/language-bindings/python/tests/test_advanced.py b/language-bindings/python/wasm-c-api/tests/test_advanced.py similarity index 99% rename from language-bindings/python/tests/test_advanced.py rename to language-bindings/python/wasm-c-api/tests/test_advanced.py index ad074f2b..2e1c285e 100644 --- a/language-bindings/python/tests/test_advanced.py +++ b/language-bindings/python/wasm-c-api/tests/test_advanced.py @@ -12,7 +12,7 @@ import ctypes as c import math import unittest -import wamr.ffi as ffi +import wamr.wasmcapi.ffi as ffi # It is a module likes: diff --git a/language-bindings/python/tests/test_basic.py b/language-bindings/python/wasm-c-api/tests/test_basic.py similarity index 99% rename from language-bindings/python/tests/test_basic.py rename to language-bindings/python/wasm-c-api/tests/test_basic.py index 556162bd..632ad512 100644 --- a/language-bindings/python/tests/test_basic.py +++ b/language-bindings/python/wasm-c-api/tests/test_basic.py @@ -12,7 +12,7 @@ import ctypes as c import unittest from venv import create -from wamr.ffi import * +from wamr.wasmcapi.ffi import * # It is a module likes: # (module diff --git a/language-bindings/python/utils/bindgen.py b/language-bindings/python/wasm-c-api/utils/bindgen.py similarity index 98% rename from language-bindings/python/utils/bindgen.py rename to language-bindings/python/wasm-c-api/utils/bindgen.py index 6371ca65..a505404d 100644 --- a/language-bindings/python/utils/bindgen.py +++ b/language-bindings/python/wasm-c-api/utils/bindgen.py @@ -21,7 +21,7 @@ import sys from pycparser import c_ast, parse_file WASM_C_API_HEADER = "core/iwasm/include/wasm_c_api.h" -BINDING_PATH = "wamr/binding.py" +BINDING_PATH = "language-bindings/python/wamr/wasmcapi/binding.py" # 4 spaces as default indent INDENT = " " @@ -314,7 +314,7 @@ class Visitor(c_ast.NodeVisitor): def preflight_check(workspace): - wamr_repo = workspace.joinpath("wasm-micro-runtime") + wamr_repo = workspace file_check_list = [ wamr_repo.exists(), wamr_repo.joinpath(WASM_C_API_HEADER).exists(), @@ -369,12 +369,12 @@ def main(): current_file = pathlib.Path(os.readlink(current_file)) current_dir = current_file.parent.resolve() - root_dir = current_dir.joinpath("..").resolve() + root_dir = current_dir.joinpath("../../../..").resolve() if not preflight_check(root_dir): return False - wamr_repo = root_dir.joinpath("wasm-micro-runtime") + wamr_repo = root_dir binding_file_path = root_dir.joinpath(BINDING_PATH) with open(binding_file_path, "wt", encoding="utf-8") as binding_file: binding_file.write(do_parse(wamr_repo)) From 50650e463404063570d4f17ae7774f7abd921ea4 Mon Sep 17 00:00:00 2001 From: Hritik Gupta Date: Thu, 16 Feb 2023 13:03:33 +0000 Subject: [PATCH 33/33] Modify poll_oneoff in libc-wasi to make it interruptible (#1951) --- core/iwasm/common/wasm_shared_memory.c | 10 +- .../libraries/libc-wasi/libc_wasi_wrapper.c | 110 ++++++++++++++++-- 2 files changed, 112 insertions(+), 8 deletions(-) diff --git a/core/iwasm/common/wasm_shared_memory.c b/core/iwasm/common/wasm_shared_memory.c index 6112b1ba..3a9c1f59 100644 --- a/core/iwasm/common/wasm_shared_memory.c +++ b/core/iwasm/common/wasm_shared_memory.c @@ -111,6 +111,7 @@ notify_stale_threads_on_exception(WASMModuleInstanceCommon *module_inst) { AtomicWaitAddressArgs args = { 0 }; uint32 i = 0, total_elem_count = 0; + uint64 total_elem_count_size = 0; os_mutex_lock(&shared_memory_list_lock); @@ -118,8 +119,15 @@ notify_stale_threads_on_exception(WASMModuleInstanceCommon *module_inst) bh_hash_map_traverse(wait_map, wait_map_address_count_callback, (void *)&total_elem_count); + if (!total_elem_count) { + os_mutex_unlock(&shared_memory_list_lock); + return; + } + /* allocate memory */ - if (!(args.addr = wasm_runtime_malloc(sizeof(void *) * total_elem_count))) { + total_elem_count_size = (uint64)sizeof(void *) * total_elem_count; + if (total_elem_count_size >= UINT32_MAX + || !(args.addr = wasm_runtime_malloc((uint32)total_elem_count_size))) { LOG_ERROR( "failed to allocate memory for list of atomic wait addresses"); os_mutex_unlock(&shared_memory_list_lock); diff --git a/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c b/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c index a6a448b5..815fa5aa 100644 --- a/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c +++ b/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c @@ -63,6 +63,12 @@ typedef struct WASIContext { wasi_ctx_t wasm_runtime_get_wasi_ctx(wasm_module_inst_t module_inst); +static inline size_t +min(size_t a, size_t b) +{ + return a > b ? b : a; +} + static inline struct fd_table * wasi_ctx_get_curfds(wasm_module_inst_t module_inst, wasi_ctx_t wasi_ctx) { @@ -951,6 +957,97 @@ wasi_path_remove_directory(wasm_exec_env_t exec_env, wasi_fd_t fd, return wasmtime_ssp_path_remove_directory(curfds, fd, path, path_len); } +#if WASM_ENABLE_THREAD_MGR != 0 +static __wasi_timestamp_t +get_timeout_for_poll_oneoff(const wasi_subscription_t *in, + uint32 nsubscriptions) +{ + __wasi_timestamp_t timeout = (__wasi_timestamp_t)-1; + uint32 i = 0; + + for (i = 0; i < nsubscriptions; ++i) { + const __wasi_subscription_t *s = &in[i]; + if (s->u.type == __WASI_EVENTTYPE_CLOCK + && (s->u.u.clock.flags & __WASI_SUBSCRIPTION_CLOCK_ABSTIME) == 0) { + timeout = min(timeout, s->u.u.clock.timeout); + } + } + return timeout; +} + +static void +update_clock_subscription_data(wasi_subscription_t *in, uint32 nsubscriptions, + const wasi_timestamp_t new_timeout) +{ + uint32 i = 0; + for (i = 0; i < nsubscriptions; ++i) { + __wasi_subscription_t *s = &in[i]; + if (s->u.type == __WASI_EVENTTYPE_CLOCK) { + s->u.u.clock.timeout = new_timeout; + } + } +} + +static wasi_errno_t +execute_interruptible_poll_oneoff(wasm_module_inst_t module_inst, +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + const __wasi_subscription_t *in, + __wasi_event_t *out, size_t nsubscriptions, + size_t *nevents) +{ + if (nsubscriptions == 0) { + *nevents = 0; + return __WASI_ESUCCESS; + } + + wasi_errno_t err; + __wasi_timestamp_t elapsed = 0; + + const __wasi_timestamp_t timeout = get_timeout_for_poll_oneoff( + in, nsubscriptions), + time_quant = 1e9; + const uint64 size_to_copy = + nsubscriptions * (uint64)sizeof(wasi_subscription_t); + __wasi_subscription_t *in_copy = NULL; + + if (size_to_copy >= UINT32_MAX + || !(in_copy = (__wasi_subscription_t *)wasm_runtime_malloc( + (uint32)size_to_copy))) { + return __WASI_ENOMEM; + } + + bh_memcpy_s(in_copy, size_to_copy, in, size_to_copy); + + while (timeout == (__wasi_timestamp_t)-1 || elapsed <= timeout) { + elapsed += time_quant; + + /* update timeout for clock subscription events */ + update_clock_subscription_data(in_copy, nsubscriptions, + min(time_quant, timeout - elapsed)); + err = wasmtime_ssp_poll_oneoff(curfds, in_copy, out, nsubscriptions, + nevents); + if (err) { + wasm_runtime_free(in_copy); + return err; + } + + if (wasm_runtime_get_exception(module_inst) || *nevents > 0) { + wasm_runtime_free(in_copy); + + if (*nevents) { + return __WASI_ESUCCESS; + } + return EINTR; + } + } + + wasm_runtime_free(in_copy); + return __WASI_ESUCCESS; +} +#endif + static wasi_errno_t wasi_poll_oneoff(wasm_exec_env_t exec_env, const wasi_subscription_t *in, wasi_event_t *out, uint32 nsubscriptions, uint32 *nevents_app) @@ -958,7 +1055,7 @@ wasi_poll_oneoff(wasm_exec_env_t exec_env, const wasi_subscription_t *in, wasm_module_inst_t module_inst = get_module_inst(exec_env); wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); - size_t nevents; + size_t nevents = 0; wasi_errno_t err; if (!wasi_ctx) @@ -969,7 +1066,12 @@ wasi_poll_oneoff(wasm_exec_env_t exec_env, const wasi_subscription_t *in, || !validate_native_addr(nevents_app, sizeof(uint32))) return (wasi_errno_t)-1; +#if WASM_ENABLE_THREAD_MGR == 0 err = wasmtime_ssp_poll_oneoff(curfds, in, out, nsubscriptions, &nevents); +#else + err = execute_interruptible_poll_oneoff(module_inst, curfds, in, out, + nsubscriptions, &nevents); +#endif if (err) return err; @@ -1861,12 +1963,6 @@ allocate_iovec_app_buffer(wasm_module_inst_t module_inst, return __WASI_ESUCCESS; } -static inline size_t -min(size_t a, size_t b) -{ - return a > b ? b : a; -} - static wasi_errno_t copy_buffer_to_iovec_app(wasm_module_inst_t module_inst, uint8 *buf_begin, uint32 buf_size, iovec_app_t *data, uint32 data_len,