diff --git a/.github/workflows/build_wamr_vscode_ext.yml b/.github/workflows/build_wamr_vscode_ext.yml index 322ba1c06..756215e60 100644 --- a/.github/workflows/build_wamr_vscode_ext.yml +++ b/.github/workflows/build_wamr_vscode_ext.yml @@ -20,10 +20,10 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Use Node.js 16.x + - name: Use Node.js 18.x uses: actions/setup-node@v4 with: - node-version: 16.x + node-version: 18.x - name: set vscode extension to correct version run: | @@ -33,7 +33,7 @@ jobs: - name: generate wamr ide vscode extension run: | - npm install -g vsce + npm install -g @vscode/vsce rm -rf node_modules npm install vsce package diff --git a/.github/workflows/compilation_on_nuttx.yml b/.github/workflows/compilation_on_nuttx.yml index 7a3c3067f..2f8014fac 100644 --- a/.github/workflows/compilation_on_nuttx.yml +++ b/.github/workflows/compilation_on_nuttx.yml @@ -68,18 +68,17 @@ jobs: # arm64 "boards/arm64/qemu/qemu-armv8a/configs/nsh", ] - wamr_config_option: [ - "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", - "CONFIG_INTERPRETERS_WAMR=y\\nCONFIG_INTERPRETERS_WAMR_CLASSIC=y\\n", - ] + + wamr_config_option: + - "CONFIG_INTERPRETERS_WAMR_AOT" + - "CONFIG_INTERPRETERS_WAMR_FAST" + - "CONFIG_INTERPRETERS_WAMR_CLASSIC" + - "CONFIG_INTERPRETERS_WAMR_AOT CONFIG_INTERPRETERS_WAMR_FAST" + - "CONFIG_INTERPRETERS_WAMR_AOT CONFIG_INTERPRETERS_WAMR_FAST CONFIG_INTERPRETERS_WAMR_LIBC_WASI" + - "CONFIG_INTERPRETERS_WAMR_AOT CONFIG_INTERPRETERS_WAMR_FAST CONFIG_INTERPRETERS_WAMR_LIBC_BUILTIN" + - "CONFIG_INTERPRETERS_WAMR_AOT CONFIG_INTERPRETERS_WAMR_CLASSIC" + - "CONFIG_INTERPRETERS_WAMR_AOT CONFIG_INTERPRETERS_WAMR_CLASSIC CONFIG_INTERPRETERS_WAMR_LIBC_WASI" + - "CONFIG_INTERPRETERS_WAMR_AOT CONFIG_INTERPRETERS_WAMR_CLASSIC CONFIG_INTERPRETERS_WAMR_LIBC_WASI" steps: - name: Checkout NuttX @@ -102,16 +101,22 @@ jobs: repository: ${{ github.repository }} path: apps/interpreters/wamr/wamr - - name: Enable WAMR for NuttX + - name: Configure WAMR + working-directory: nuttx run: | - find nuttx/boards -name defconfig | xargs sed -i '$a\CONFIG_EOL_IS_LF=y\n${{ matrix.wamr_config_option }}' - find nuttx/boards/sim -name defconfig | xargs sed -i '$a\CONFIG_LIBM=y\n' + tools/configure.sh ${{ matrix.nuttx_board_config }} + kconfig-tweak --enable CONFIG_PSEUDOFS_SOFTLINKS + kconfig-tweak --enable CONFIG_INTERPRETERS_WAMR + kconfig-tweak --enable CONFIG_INTERPRETERS_IWASM_TASK + kconfig-tweak --set-val CONFIG_INTERPRETERS_WAMR_PRIORITY 100 + kconfig-tweak --set-val CONFIG_INTERPRETERS_WAMR_STACKSIZE 8192 + for x in ${{ matrix.wamr_config_option }}; do + kconfig-tweak --enable $x + done - name: Build - run: | - cd nuttx - tools/configure.sh ${{ matrix.nuttx_board_config }} - make -j$(nproc) EXTRAFLAGS=-Werror + working-directory: nuttx + run: make -j$(nproc) EXTRAFLAGS=-Werror - name: Checkout Bloaty uses: actions/checkout@v3 diff --git a/.github/workflows/spec_test_on_nuttx.yml b/.github/workflows/spec_test_on_nuttx.yml index 1ae3bdf04..f2e59ba68 100644 --- a/.github/workflows/spec_test_on_nuttx.yml +++ b/.github/workflows/spec_test_on_nuttx.yml @@ -74,6 +74,11 @@ jobs: target: "riscv32", fpu_type: "none" }, + { + config: "boards/risc-v/qemu-rv/rv-virt/configs/nsh", + target: "riscv32_ilp32f", + fpu_type: "fp" + }, # { # config: "boards/risc-v/qemu-rv/rv-virt/configs/nsh", # target: "riscv32_ilp32d", diff --git a/ATTRIBUTIONS.md b/ATTRIBUTIONS.md index b6e556d2b..cba0e5c4b 100644 --- a/ATTRIBUTIONS.md +++ b/ATTRIBUTIONS.md @@ -16,7 +16,7 @@ WAMR project reused some components from other open source project: - **asmjit**: for the Fast JIT x86-64 codegen implementation - **zydis**: for the Fast JIT x86-64 codegen implementation - **NuttX ELF headers**: used in core/iwasm/aot/debug/elf_parser.c -- **Dhrystone**: for the test benchmakr dhrystone +- **Dhrystone**: for the test benchmark dhrystone The WAMR fast interpreter is a clean room development. We would acknowledge the inspirations by [WASM3](https://github.com/wasm3/wasm3) open source project for the approach of pre-calculated operand stack location. diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 988315ef2..e296cdf9e 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,3 +1,77 @@ +## WAMR-2.1.2 + +### Breaking Changes + - wasi-nn: Apply new architecture (#3692) + +### New Features + - [wasi-nn] Add a new wasi-nn backend openvino (#3603) + - Add APIs into wasm_c_api.h to summary wasm function execution duration (#3639) + - Add support for RISCV32 ILP32F (#3708) + +### Bug Fixes + - libc-builtin: Fix function prototype for wasm_runtime_module_realloc (#3702) + - Fix potential memory leak in insert_native_symbol (#3712) + - aot compiler: Fix NaN handling for opcode f32/f64.const in XIP mode (#3721) + - Fix table idx resolving in op call_indirect/return_call_indirect (#3726) + +### Enhancements + - Remove a few hardcoded spec test knowledge from the core library (#3648) + - Change log of import function to be consistent (#3656) + - libc-builtin: Fix a printf format (#3652) + - Set compile symbol visibility to hidden in cmake (#3655) + - wamrc: Add --mllvm= option (#3658) + - wamr-compiler: Avoid size-level tweak if target is specified (#3659) + - aot runtime: Add missing arm/thumb relocations (#3660) + - aot compiler: Enlarge AOTNativeSymbol->symbol (#3662) + - aot compiler: Bail out on too long native symbol names (#3663) + - Support more features for rt-thread (#3661) + - Zephyr User Mode Support (#3650) + - Set posix thread name for debug build (#3657) + - Add emscripten_sleep() wrapper to libc-emcc (#3669) + - Fix a compilation warning (#3682) + - wamrc: Add some help text for --size-level (#3689) + - Restore linux iwasm default visibility (#3691) + - posix_thread.c: Restore old signal alternate stack before thread exit (#3693) + - libc-wasi: Make rights of STDIN/STDOUT/STDERR fixed and overlook their access modes (#3694) + - [refactoring] Extract read leb to a separate file, share the code between loader and mini loader (#3701) + - debug-interp: Only add lock when signal_flag is SIG_SINGSTEP (#3704) + - Fix compilation warnings (#3707) + - Add missing headers in bh_atomic.h and aot_llvm_extra.cpp (#3715) + - Update std atomic check and simd compatibility check for arc compiler (#3716) + - aot compiler: Track non-0x00 tableindex as ref types use (#3695) + - compilation: Use the dedicated stack-sizes section only for AOT (#3732) + - riscv: Add missing relocation intrinsics for __fixdfsi/__ltdf2 (#3733) + +### Others + - Fix night run CI (#3640) + - spec-test-script/runtest.py: Don't assume the tmp dir path (#3632) + - wamr-test-suites: Remove dead code (wasi_test) (#3634) + - wamr-test-suites/test_wamr.sh: Add an option to specify wamrc binary (#3635) + - CI: Build llvm for xtensa (#3637) + - spec-test-script/runtest.py: Avoid specifying -v=0 unnecessarily (#3642) + - spec-test-script: Add xtensa case (#3643) + - spec-test-script/runtest.py: Move "--size-level=1" to common place for RISCV64 (#3644) + - spec-test-script/runtest.py: Use a shorter timeout when expected to fail (#3647) + - spec-test-script: Make case_last_words larger (#3651) + - spec-test-script/runtest.py: Reduce stack size for aot w/o gc (#3653) + - spec-test-script: Skip a few tests for xtensa qemu (#3664) + - spec-test-script: Use -mtext-section-literals for xtensa xip (#3666) + - spec_test_on_nuttx.yml: Add xtensa (#3665) + - spec_test_on_nuttx.yml: Enable xip (#3671) + - spec_test_on_nuttx.yml: Record more logs (#3670) + - spec_test_on_nuttx.yml: Replace sed with kconfig-tweak (#3672) + - spec_test_on_nuttx.yml: Retire CONFIG_EOL_IS_LF (#3676) + - spec-test-script/runtest.py: Use wamrc --xip option for xip (#3683) + - CI: Bump NuttX version to 12.6 (#3684) + - wamr-test-suites: Clean up generated tmp files after spec test (#3700) + - test_wamr.sh: Fix build wabt tool (#3703) + - NuttX: Retire CONFIG_ARCH_RV32IM and CONFIG_ARCH_RV64GC (#3717) + - runtest.py: Normallize option handling for XIP mode (#3722) + - CI: Enable XIP spectest for RISCV32 ILP32F (#3727) + - CI: Unify configuration stage for NuttX (#3725) + +--- + ## WAMR-2.1.1 ### Breaking Changes diff --git a/build-scripts/config_common.cmake b/build-scripts/config_common.cmake index 8a1002235..d4dd2c0d6 100644 --- a/build-scripts/config_common.cmake +++ b/build-scripts/config_common.cmake @@ -39,6 +39,8 @@ elseif (WAMR_BUILD_TARGET STREQUAL "RISCV64_LP64") add_definitions(-DBUILD_TARGET_RISCV64_LP64) elseif (WAMR_BUILD_TARGET STREQUAL "RISCV32" OR WAMR_BUILD_TARGET STREQUAL "RISCV32_ILP32D") add_definitions(-DBUILD_TARGET_RISCV32_ILP32D) +elseif (WAMR_BUILD_TARGET STREQUAL "RISCV32_ILP32F") + add_definitions(-DBUILD_TARGET_RISCV32_ILP32F) elseif (WAMR_BUILD_TARGET STREQUAL "RISCV32_ILP32") add_definitions(-DBUILD_TARGET_RISCV32_ILP32) elseif (WAMR_BUILD_TARGET STREQUAL "ARC") @@ -438,12 +440,13 @@ if (WAMR_BUILD_WASI_NN EQUAL 1) if (NOT WAMR_BUILD_WASI_NN_TFLITE EQUAL 1 AND NOT WAMR_BUILD_WASI_NN_OPENVINO EQUAL 1) message (FATAL_ERROR " Need to select a backend for WASI-NN") endif () + if (WAMR_BUILD_WASI_NN_TFLITE EQUAL 1) - message (" WASI-NN backend tflite enabled") + message (" WASI-NN: backend tflite enabled") add_definitions (-DWASM_ENABLE_WASI_NN_TFLITE) endif () if (WAMR_BUILD_WASI_NN_OPENVINO EQUAL 1) - message (" WASI-NN backend openvino enabled") + message (" WASI-NN: backend openvino enabled") add_definitions (-DWASM_ENABLE_WASI_NN_OPENVINO) endif () # Variant devices @@ -459,7 +462,7 @@ if (WAMR_BUILD_WASI_NN EQUAL 1) add_definitions (-DWASM_WASI_NN_EXTERNAL_DELEGATE_PATH="${WAMR_BUILD_WASI_NN_EXTERNAL_DELEGATE_PATH}") endif () if (WAMR_BUILD_WASI_EPHEMERAL_NN EQUAL 1) - message (" WASI-NN: WASI-Ephemeral-NN enabled") + message (" WASI-NN: use 'wasi_ephemeral_nn' instead of 'wasi-nn'") add_definitions (-DWASM_ENABLE_WASI_EPHEMERAL_NN=1) endif() endif () diff --git a/core/config.h b/core/config.h index 9fd540f32..7c783dd32 100644 --- a/core/config.h +++ b/core/config.h @@ -20,6 +20,7 @@ && !defined(BUILD_TARGET_RISCV64_LP64D) \ && !defined(BUILD_TARGET_RISCV64_LP64) \ && !defined(BUILD_TARGET_RISCV32_ILP32D) \ + && !defined(BUILD_TARGET_RISCV32_ILP32F) \ && !defined(BUILD_TARGET_RISCV32_ILP32) \ && !defined(BUILD_TARGET_ARC) /* clang-format on */ @@ -43,7 +44,11 @@ #define BUILD_TARGET_XTENSA #elif defined(__riscv) && (__riscv_xlen == 64) #define BUILD_TARGET_RISCV64_LP64D -#elif defined(__riscv) && (__riscv_xlen == 32) +#elif defined(__riscv) && (__riscv_xlen == 32) && !defined(__riscv_flen) +#define BUILD_TARGET_RISCV32_ILP32 +#elif defined(__riscv) && (__riscv_xlen == 32) && (__riscv_flen == 32) +#define BUILD_TARGET_RISCV32_ILP32F +#elif defined(__riscv) && (__riscv_xlen == 32) && (__riscv_flen == 64) #define BUILD_TARGET_RISCV32_ILP32D #elif defined(__arc__) #define BUILD_TARGET_ARC diff --git a/core/iwasm/aot/arch/aot_reloc_riscv.c b/core/iwasm/aot/arch/aot_reloc_riscv.c index 31830f780..b87bb2000 100644 --- a/core/iwasm/aot/arch/aot_reloc_riscv.c +++ b/core/iwasm/aot/arch/aot_reloc_riscv.c @@ -134,6 +134,7 @@ static SymbolMap target_sym_map[] = { REG_SYM(__eqdf2), REG_SYM(__extendsfdf2), REG_SYM(__fixdfdi), + REG_SYM(__fixdfsi), REG_SYM(__fixunsdfdi), REG_SYM(__fixunsdfsi), REG_SYM(__floatdidf), @@ -143,6 +144,7 @@ static SymbolMap target_sym_map[] = { REG_SYM(__gedf2), REG_SYM(__gtdf2), REG_SYM(__ledf2), + REG_SYM(__ltdf2), REG_SYM(__muldf3), REG_SYM(__nedf2), REG_SYM(__negdf2), diff --git a/core/iwasm/common/wasm_loader_common.c b/core/iwasm/common/wasm_loader_common.c index 179639fca..6dd31be2c 100644 --- a/core/iwasm/common/wasm_loader_common.c +++ b/core/iwasm/common/wasm_loader_common.c @@ -3,14 +3,15 @@ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception */ #include "wasm_loader_common.h" +#include "bh_leb128.h" #include "bh_log.h" #if WASM_ENABLE_GC != 0 #include "../common/gc/gc_type.h" #endif -static void -set_error_buf(char *error_buf, uint32 error_buf_size, const char *string, - bool is_aot) +void +wasm_loader_set_error_buf(char *error_buf, uint32 error_buf_size, + const char *string, bool is_aot) { if (error_buf != NULL) { snprintf(error_buf, error_buf_size, "%s module load failed: %s", @@ -29,30 +30,30 @@ wasm_memory_check_flags(const uint8 mem_flag, char *error_buf, if (mem_flag & SHARED_MEMORY_FLAG) { LOG_VERBOSE("shared memory flag was found, please enable shared " "memory, lib-pthread or lib-wasi-threads"); - set_error_buf(error_buf, error_buf_size, "invalid limits flags", - is_aot); + wasm_loader_set_error_buf(error_buf, error_buf_size, + "invalid limits flags", is_aot); return false; } #endif #if WASM_ENABLE_MEMORY64 == 0 if (mem_flag & MEMORY64_FLAG) { LOG_VERBOSE("memory64 flag was found, please enable memory64"); - set_error_buf(error_buf, error_buf_size, "invalid limits flags", - is_aot); + wasm_loader_set_error_buf(error_buf, error_buf_size, + "invalid limits flags", is_aot); return false; } #endif } if (mem_flag > MAX_PAGE_COUNT_FLAG + SHARED_MEMORY_FLAG + MEMORY64_FLAG) { - set_error_buf(error_buf, error_buf_size, "invalid limits flags", - is_aot); + wasm_loader_set_error_buf(error_buf, error_buf_size, + "invalid limits flags", is_aot); return false; } else if ((mem_flag & SHARED_MEMORY_FLAG) && !(mem_flag & MAX_PAGE_COUNT_FLAG)) { - set_error_buf(error_buf, error_buf_size, - "shared memory must have maximum", is_aot); + wasm_loader_set_error_buf(error_buf, error_buf_size, + "shared memory must have maximum", is_aot); return false; } @@ -130,3 +131,33 @@ is_indices_overflow(uint32 import, uint32 other, char *error_buf, return false; } + +bool +read_leb(uint8 **p_buf, const uint8 *buf_end, uint32 maxbits, bool sign, + uint64 *p_result, char *error_buf, uint32 error_buf_size) +{ + size_t offset = 0; + bh_leb_read_status_t status = + bh_leb_read(*p_buf, buf_end, maxbits, sign, p_result, &offset); + + switch (status) { + case BH_LEB_READ_SUCCESS: + *p_buf += offset; + return true; + case BH_LEB_READ_TOO_LONG: + wasm_loader_set_error_buf(error_buf, error_buf_size, + "integer representation too long", false); + return false; + case BH_LEB_READ_OVERFLOW: + wasm_loader_set_error_buf(error_buf, error_buf_size, + "integer too large", false); + return false; + case BH_LEB_READ_UNEXPECTED_END: + wasm_loader_set_error_buf(error_buf, error_buf_size, + "unexpected end", false); + return false; + default: + bh_assert(false); + return false; + } +} diff --git a/core/iwasm/common/wasm_loader_common.h b/core/iwasm/common/wasm_loader_common.h index 6bd0cf6c2..d574110ba 100644 --- a/core/iwasm/common/wasm_loader_common.h +++ b/core/iwasm/common/wasm_loader_common.h @@ -30,6 +30,14 @@ bool is_indices_overflow(uint32 import, uint32 other, char *error_buf, uint32 error_buf_size); +bool +read_leb(uint8 **p_buf, const uint8 *buf_end, uint32 maxbits, bool sign, + uint64 *p_result, char *error_buf, uint32 error_buf_size); + +void +wasm_loader_set_error_buf(char *error_buf, uint32 error_buf_size, + const char *string, bool is_aot); + #ifdef __cplusplus } #endif diff --git a/core/iwasm/common/wasm_native.c b/core/iwasm/common/wasm_native.c index cde40825e..9e8764a22 100644 --- a/core/iwasm/common/wasm_native.c +++ b/core/iwasm/common/wasm_native.c @@ -15,6 +15,9 @@ #if WASM_ENABLE_THREAD_MGR != 0 #include "../libraries/thread-mgr/thread_manager.h" #endif +#if WASM_ENABLE_WASI_NN != 0 || WASM_ENABLE_WASI_EPHEMERAL_NN != 0 +#include "wasi_nn_host.h" +#endif static NativeSymbolsList g_native_symbols_list = NULL; @@ -472,11 +475,12 @@ quick_aot_entry_init(); bool wasm_native_init() { -#if WASM_ENABLE_SPEC_TEST != 0 || WASM_ENABLE_LIBC_BUILTIN != 0 \ - || WASM_ENABLE_BASE_LIB != 0 || WASM_ENABLE_LIBC_EMCC != 0 \ - || WASM_ENABLE_LIB_RATS != 0 || WASM_ENABLE_WASI_NN != 0 \ - || WASM_ENABLE_APP_FRAMEWORK != 0 || WASM_ENABLE_LIBC_WASI != 0 \ - || WASM_ENABLE_LIB_PTHREAD != 0 || WASM_ENABLE_LIB_WASI_THREADS != 0 +#if WASM_ENABLE_SPEC_TEST != 0 || WASM_ENABLE_LIBC_BUILTIN != 0 \ + || WASM_ENABLE_BASE_LIB != 0 || WASM_ENABLE_LIBC_EMCC != 0 \ + || WASM_ENABLE_LIB_RATS != 0 || WASM_ENABLE_WASI_NN != 0 \ + || WASM_ENABLE_APP_FRAMEWORK != 0 || WASM_ENABLE_LIBC_WASI != 0 \ + || WASM_ENABLE_LIB_PTHREAD != 0 || WASM_ENABLE_LIB_WASI_THREADS != 0 \ + || WASM_ENABLE_WASI_NN != 0 || WASM_ENABLE_WASI_EPHEMERAL_NN != 0 NativeSymbol *native_symbols; uint32 n_native_symbols; #endif @@ -562,13 +566,30 @@ wasm_native_init() goto fail; #endif /* WASM_ENABLE_LIB_RATS */ +#if WASM_ENABLE_WASI_NN != 0 || WASM_ENABLE_WASI_EPHEMERAL_NN != 0 + if (!wasi_nn_initialize()) + goto fail; + + n_native_symbols = get_wasi_nn_export_apis(&native_symbols); + if (n_native_symbols > 0 + && !wasm_native_register_natives( +#if WASM_ENABLE_WASI_EPHEMERAL_NN != 0 + "wasi_ephemeral_nn", +#else + "wasi_nn", +#endif /* WASM_ENABLE_WASI_EPHEMERAL_NN != 0 */ + native_symbols, n_native_symbols)) + goto fail; +#endif /* WASM_ENABLE_WASI_NN != 0 || WASM_ENABLE_WASI_EPHEMERAL_NN != 0 */ + #if WASM_ENABLE_QUICK_AOT_ENTRY != 0 if (!quick_aot_entry_init()) { -#if WASM_ENABLE_SPEC_TEST != 0 || WASM_ENABLE_LIBC_BUILTIN != 0 \ - || WASM_ENABLE_BASE_LIB != 0 || WASM_ENABLE_LIBC_EMCC != 0 \ - || WASM_ENABLE_LIB_RATS != 0 || WASM_ENABLE_WASI_NN != 0 \ - || WASM_ENABLE_APP_FRAMEWORK != 0 || WASM_ENABLE_LIBC_WASI != 0 \ - || WASM_ENABLE_LIB_PTHREAD != 0 || WASM_ENABLE_LIB_WASI_THREADS != 0 +#if WASM_ENABLE_SPEC_TEST != 0 || WASM_ENABLE_LIBC_BUILTIN != 0 \ + || WASM_ENABLE_BASE_LIB != 0 || WASM_ENABLE_LIBC_EMCC != 0 \ + || WASM_ENABLE_LIB_RATS != 0 || WASM_ENABLE_WASI_NN != 0 \ + || WASM_ENABLE_APP_FRAMEWORK != 0 || WASM_ENABLE_LIBC_WASI != 0 \ + || WASM_ENABLE_LIB_PTHREAD != 0 || WASM_ENABLE_LIB_WASI_THREADS != 0 \ + || WASM_ENABLE_WASI_NN != 0 || WASM_ENABLE_WASI_EPHEMERAL_NN != 0 goto fail; #else return false; @@ -577,11 +598,12 @@ wasm_native_init() #endif return true; -#if WASM_ENABLE_SPEC_TEST != 0 || WASM_ENABLE_LIBC_BUILTIN != 0 \ - || WASM_ENABLE_BASE_LIB != 0 || WASM_ENABLE_LIBC_EMCC != 0 \ - || WASM_ENABLE_LIB_RATS != 0 || WASM_ENABLE_WASI_NN != 0 \ - || WASM_ENABLE_APP_FRAMEWORK != 0 || WASM_ENABLE_LIBC_WASI != 0 \ - || WASM_ENABLE_LIB_PTHREAD != 0 || WASM_ENABLE_LIB_WASI_THREADS != 0 +#if WASM_ENABLE_SPEC_TEST != 0 || WASM_ENABLE_LIBC_BUILTIN != 0 \ + || WASM_ENABLE_BASE_LIB != 0 || WASM_ENABLE_LIBC_EMCC != 0 \ + || WASM_ENABLE_LIB_RATS != 0 || WASM_ENABLE_WASI_NN != 0 \ + || WASM_ENABLE_APP_FRAMEWORK != 0 || WASM_ENABLE_LIBC_WASI != 0 \ + || WASM_ENABLE_LIB_PTHREAD != 0 || WASM_ENABLE_LIB_WASI_THREADS != 0 \ + || WASM_ENABLE_WASI_NN != 0 || WASM_ENABLE_WASI_EPHEMERAL_NN != 0 fail: wasm_native_destroy(); return false; @@ -599,6 +621,7 @@ wasm_native_destroy() g_wasi_context_key = NULL; } #endif + #if WASM_ENABLE_LIB_PTHREAD != 0 lib_pthread_destroy(); #endif @@ -607,6 +630,10 @@ wasm_native_destroy() lib_wasi_threads_destroy(); #endif +#if WASM_ENABLE_WASI_NN != 0 || WASM_ENABLE_WASI_EPHEMERAL_NN != 0 + wasi_nn_destroy(); +#endif + node = g_native_symbols_list; while (node) { node_next = node->next; diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index 8ed14ec40..f54ac4ab9 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -1417,12 +1417,39 @@ wasm_runtime_load_ex(uint8 *buf, uint32 size, const LoadArgs *args, char *error_buf, uint32 error_buf_size) { WASMModuleCommon *module_common = NULL; + uint32 package_type; + bool magic_header_detected = false; if (!args) { + set_error_buf(error_buf, error_buf_size, + "WASM module load failed: null load arguments"); return NULL; } - if (get_package_type(buf, size) == Wasm_Module_Bytecode) { + if (size < 4) { + set_error_buf(error_buf, error_buf_size, + "WASM module load failed: unexpected end"); + return NULL; + } + + package_type = get_package_type(buf, size); + if (package_type == Wasm_Module_Bytecode) { +#if WASM_ENABLE_INTERP != 0 + magic_header_detected = true; +#endif + } + else if (package_type == Wasm_Module_AoT) { +#if WASM_ENABLE_AOT != 0 + magic_header_detected = true; +#endif + } + if (!magic_header_detected) { + set_error_buf(error_buf, error_buf_size, + "WASM module load failed: magic header not detected"); + return NULL; + } + + if (package_type == Wasm_Module_Bytecode) { #if WASM_ENABLE_INTERP != 0 module_common = (WASMModuleCommon *)wasm_load(buf, size, @@ -1435,7 +1462,7 @@ wasm_runtime_load_ex(uint8 *buf, uint32 size, const LoadArgs *args, args->wasm_binary_freeable; #endif } - else if (get_package_type(buf, size) == Wasm_Module_AoT) { + else if (package_type == Wasm_Module_AoT) { #if WASM_ENABLE_AOT != 0 module_common = (WASMModuleCommon *)aot_load_from_aot_file( buf, size, args, error_buf, error_buf_size); @@ -1444,15 +1471,7 @@ wasm_runtime_load_ex(uint8 *buf, uint32 size, const LoadArgs *args, args->wasm_binary_freeable; #endif } - else { - if (size < 4) - set_error_buf(error_buf, error_buf_size, - "WASM module load failed: unexpected end"); - else - set_error_buf(error_buf, error_buf_size, - "WASM module load failed: magic header not detected"); - return NULL; - } + if (!module_common) { LOG_DEBUG("WASM module load failed"); return NULL; @@ -4718,9 +4737,13 @@ fail: * Implementation of wasm_runtime_invoke_native() */ -/* The invoke native implementation on ARM platform with VFP co-processor */ +/** + * The invoke native implementation on ARM platform with VFP co-processor, + * RISCV32 platform with/without FPU/DPFPU and ARC platform. + */ #if defined(BUILD_TARGET_ARM_VFP) || defined(BUILD_TARGET_THUMB_VFP) \ || defined(BUILD_TARGET_RISCV32_ILP32D) \ + || defined(BUILD_TARGET_RISCV32_ILP32F) \ || defined(BUILD_TARGET_RISCV32_ILP32) || defined(BUILD_TARGET_ARC) typedef void (*GenericFunctionPointer)(); void @@ -4821,7 +4844,8 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, #endif n_ints += 2; } -#if defined(BUILD_TARGET_RISCV32_ILP32) \ +#if defined(BUILD_TARGET_RISCV32_ILP32) \ + || defined(BUILD_TARGET_RISCV32_ILP32F) \ || defined(BUILD_TARGET_RISCV32_ILP32D) || defined(BUILD_TARGET_ARC) /* part in register, part in stack */ else if (n_ints == MAX_REG_INTS - 1) { @@ -4843,19 +4867,32 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, case VALUE_TYPE_F32: if (n_fps < MAX_REG_FLOATS) n_fps++; +#if defined(BUILD_TARGET_RISCV32_ILP32F) + else if (n_ints < MAX_REG_INTS) { + n_ints++; + } +#endif else n_stacks++; break; case VALUE_TYPE_F64: +#if defined(BUILD_TARGET_RISCV32_ILP32) \ + || defined(BUILD_TARGET_RISCV32_ILP32F) || defined(BUILD_TARGET_ARC) + if (n_ints < MAX_REG_INTS - 1) { + n_ints += 2; + } + else if (n_ints == MAX_REG_INTS - 1) { + n_ints++; + n_stacks++; + } +#endif +#if defined(BUILD_TARGET_ARM_VFP) || defined(BUILD_TARGET_THUMB_VFP) if (n_fps < MAX_REG_FLOATS - 1) { -#if !defined(BUILD_TARGET_RISCV32_ILP32) && !defined(BUILD_TARGET_ARC) /* 64-bit data must be 8 bytes aligned in arm */ if (n_fps & 1) n_fps++; -#endif n_fps += 2; } -#if defined(BUILD_TARGET_RISCV32_ILP32) || defined(BUILD_TARGET_ARC) else if (n_fps == MAX_REG_FLOATS - 1) { n_fps++; n_stacks++; @@ -4887,7 +4924,7 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, /* use int regs firstly if available */ if (n_ints & 1) n_ints++; - ints += 2; + n_ints += 2; } else { /* 64-bit data in stack must be 8 bytes aligned in riscv32 @@ -4911,7 +4948,8 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, n_stacks++; } -#if defined(BUILD_TARGET_ARM_VFP) || defined(BUILD_TARGET_THUMB_VFP) +#if defined(BUILD_TARGET_ARM_VFP) || defined(BUILD_TARGET_THUMB_VFP) \ + || defined(BUILD_TARGET_RISCV32_ILP32F) argc1 = MAX_REG_INTS + MAX_REG_FLOATS + n_stacks; #elif defined(BUILD_TARGET_RISCV32_ILP32) || defined(BUILD_TARGET_ARC) argc1 = MAX_REG_INTS + n_stacks; @@ -4928,7 +4966,8 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, } ints = argv1; -#if defined(BUILD_TARGET_ARM_VFP) || defined(BUILD_TARGET_THUMB_VFP) +#if defined(BUILD_TARGET_ARM_VFP) || defined(BUILD_TARGET_THUMB_VFP) \ + || defined(BUILD_TARGET_RISCV32_ILP32F) fps = ints + MAX_REG_INTS; stacks = fps + MAX_REG_FLOATS; #elif defined(BUILD_TARGET_RISCV32_ILP32) || defined(BUILD_TARGET_ARC) @@ -5018,7 +5057,8 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, ints[n_ints++] = *argv_src++; ints[n_ints++] = *argv_src++; } -#if defined(BUILD_TARGET_RISCV32_ILP32) \ +#if defined(BUILD_TARGET_RISCV32_ILP32) \ + || defined(BUILD_TARGET_RISCV32_ILP32F) \ || defined(BUILD_TARGET_RISCV32_ILP32D) || defined(BUILD_TARGET_ARC) else if (n_ints == MAX_REG_INTS - 1) { ints[n_ints++] = *argv_src++; @@ -5042,22 +5082,36 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, { if (n_fps < MAX_REG_FLOATS) *(float32 *)&fps[n_fps++] = *(float32 *)argv_src++; +#if defined(BUILD_TARGET_RISCV32_ILP32F) + else if (n_ints < MAX_REG_INTS) { + ints[n_ints++] = *argv_src++; + } +#endif else *(float32 *)&stacks[n_stacks++] = *(float32 *)argv_src++; break; } case VALUE_TYPE_F64: { +#if defined(BUILD_TARGET_RISCV32_ILP32) \ + || defined(BUILD_TARGET_RISCV32_ILP32F) || defined(BUILD_TARGET_ARC) + if (n_ints < MAX_REG_INTS - 1) { + ints[n_ints++] = *argv_src++; + ints[n_ints++] = *argv_src++; + } + else if (n_ints == MAX_REG_INTS - 1) { + ints[n_ints++] = *argv_src++; + stacks[n_stacks++] = *argv_src++; + } +#endif +#if defined(BUILD_TARGET_ARM_VFP) || defined(BUILD_TARGET_THUMB_VFP) if (n_fps < MAX_REG_FLOATS - 1) { -#if !defined(BUILD_TARGET_RISCV32_ILP32) && !defined(BUILD_TARGET_ARC) /* 64-bit data must be 8 bytes aligned in arm */ if (n_fps & 1) n_fps++; -#endif fps[n_fps++] = *argv_src++; fps[n_fps++] = *argv_src++; } -#if defined(BUILD_TARGET_RISCV32_ILP32) || defined(BUILD_TARGET_ARC) else if (n_fps == MAX_REG_FLOATS - 1) { fps[n_fps++] = *argv_src++; stacks[n_stacks++] = *argv_src++; @@ -5249,6 +5303,7 @@ fail: #endif /* end of defined(BUILD_TARGET_ARM_VFP) \ || defined(BUILD_TARGET_THUMB_VFP) \ || defined(BUILD_TARGET_RISCV32_ILP32D) \ + || defined(BUILD_TARGET_RISCV32_ILP32F) \ || defined(BUILD_TARGET_RISCV32_ILP32) \ || defined(BUILD_TARGET_ARC) */ diff --git a/core/iwasm/compilation/aot_emit_const.c b/core/iwasm/compilation/aot_emit_const.c index 5665b480b..64fa3ded1 100644 --- a/core/iwasm/compilation/aot_emit_const.c +++ b/core/iwasm/compilation/aot_emit_const.c @@ -68,23 +68,21 @@ aot_compile_op_f32_const(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, { LLVMValueRef alloca, value; - if (!isnan(f32_const)) { - if (comp_ctx->is_indirect_mode - && aot_intrinsic_check_capability(comp_ctx, "f32.const")) { - WASMValue wasm_value; - memcpy(&wasm_value.f32, &f32_const, sizeof(float32)); - value = aot_load_const_from_table(comp_ctx, func_ctx->native_symbol, - &wasm_value, VALUE_TYPE_F32); - if (!value) { - return false; - } - PUSH_F32(value); - } - else { - value = F32_CONST(f32_const); - CHECK_LLVM_CONST(value); - PUSH_F32(value); + if (comp_ctx->is_indirect_mode + && aot_intrinsic_check_capability(comp_ctx, "f32.const")) { + WASMValue wasm_value; + memcpy(&wasm_value.f32, &f32_const, sizeof(float32)); + value = aot_load_const_from_table(comp_ctx, func_ctx->native_symbol, + &wasm_value, VALUE_TYPE_F32); + if (!value) { + return false; } + PUSH_F32(value); + } + else if (!isnan(f32_const)) { + value = F32_CONST(f32_const); + CHECK_LLVM_CONST(value); + PUSH_F32(value); } else { int32 i32_const; @@ -123,23 +121,21 @@ aot_compile_op_f64_const(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, { LLVMValueRef alloca, value; - if (!isnan(f64_const)) { - if (comp_ctx->is_indirect_mode - && aot_intrinsic_check_capability(comp_ctx, "f64.const")) { - WASMValue wasm_value; - memcpy(&wasm_value.f64, &f64_const, sizeof(float64)); - value = aot_load_const_from_table(comp_ctx, func_ctx->native_symbol, - &wasm_value, VALUE_TYPE_F64); - if (!value) { - return false; - } - PUSH_F64(value); - } - else { - value = F64_CONST(f64_const); - CHECK_LLVM_CONST(value); - PUSH_F64(value); + if (comp_ctx->is_indirect_mode + && aot_intrinsic_check_capability(comp_ctx, "f64.const")) { + WASMValue wasm_value; + memcpy(&wasm_value.f64, &f64_const, sizeof(float64)); + value = aot_load_const_from_table(comp_ctx, func_ctx->native_symbol, + &wasm_value, VALUE_TYPE_F64); + if (!value) { + return false; } + PUSH_F64(value); + } + else if (!isnan(f64_const)) { + value = F64_CONST(f64_const); + CHECK_LLVM_CONST(value); + PUSH_F64(value); } else { int64 i64_const; diff --git a/core/iwasm/compilation/aot_llvm.c b/core/iwasm/compilation/aot_llvm.c index fcf291919..d738cfc0e 100644 --- a/core/iwasm/compilation/aot_llvm.c +++ b/core/iwasm/compilation/aot_llvm.c @@ -1690,7 +1690,15 @@ aot_create_stack_sizes(const AOTCompData *comp_data, AOTCompContext *comp_ctx) * avoid creating extra relocations in the precheck functions. */ LLVMSetLinkage(stack_sizes, LLVMInternalLinkage); - LLVMSetSection(stack_sizes, aot_stack_sizes_section_name); + /* + * for AOT, place it into a dedicated section for the convenience + * of the AOT file generation and symbol resolutions. + * + * for JIT, it doesn't matter. + */ + if (!comp_ctx->is_jit_mode) { + LLVMSetSection(stack_sizes, aot_stack_sizes_section_name); + } comp_ctx->stack_sizes_type = stack_sizes_type; comp_ctx->stack_sizes = stack_sizes; return true; @@ -3108,6 +3116,16 @@ aot_create_comp_context(const AOTCompData *comp_data, aot_comp_option_t option) goto fail; } + /* Return error if ref-types and GC are disabled by command line but + ref-types instructions are used */ + if (!option->enable_ref_types && !option->enable_gc + && wasm_module->is_ref_types_used) { + aot_set_last_error("ref-types instruction was found, " + "try removing --disable-ref-types option " + "or adding --enable-gc option."); + goto fail; + } + /* Disable features when they are not actually used */ if (!wasm_module->is_simd_used) { option->enable_simd = comp_ctx->enable_simd = false; @@ -3121,7 +3139,8 @@ aot_create_comp_context(const AOTCompData *comp_data, aot_comp_option_t option) #endif if (option->enable_simd && strcmp(comp_ctx->target_arch, "x86_64") != 0 - && strncmp(comp_ctx->target_arch, "aarch64", 7) != 0) { + && strncmp(comp_ctx->target_arch, "aarch64", 7) != 0 + && strcmp(comp_ctx->target_arch, "arc") != 0) { /* Disable simd if it isn't supported by target arch */ option->enable_simd = false; } @@ -3288,6 +3307,7 @@ insert_native_symbol(AOTCompContext *comp_ctx, const char *symbol, int32 idx) bh_assert(strlen(symbol) <= sizeof(sym->symbol)); ret = snprintf(sym->symbol, sizeof(sym->symbol), "%s", symbol); if (ret < 0 || ret + 1 > (int)sizeof(sym->symbol)) { + wasm_runtime_free(sym); aot_set_last_error_v("symbol name too long: %s", symbol); return false; } diff --git a/core/iwasm/compilation/aot_llvm_extra.cpp b/core/iwasm/compilation/aot_llvm_extra.cpp index fdd5517b9..e6770eb45 100644 --- a/core/iwasm/compilation/aot_llvm_extra.cpp +++ b/core/iwasm/compilation/aot_llvm_extra.cpp @@ -41,6 +41,9 @@ #include #include #include +#if LLVM_VERSION_MAJOR >= 17 +#include +#endif #include #include #include @@ -173,6 +176,9 @@ aot_check_simd_compatibility(const char *arch_c_str, const char *cpu_c_str) else if (targetArch == llvm::Triple::aarch64) { return subTargetInfo->checkFeatures("+neon"); } + else if (targetArch == llvm::Triple::arc) { + return true; + } else { return false; } diff --git a/core/iwasm/interpreter/wasm_interp_classic.c b/core/iwasm/interpreter/wasm_interp_classic.c index bd8a4eeb1..766d2f52f 100644 --- a/core/iwasm/interpreter/wasm_interp_classic.c +++ b/core/iwasm/interpreter/wasm_interp_classic.c @@ -1399,26 +1399,48 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst, #endif /* WASM_ENABLE_DEBUG_INTERP */ #endif /* WASM_ENABLE_THREAD_MGR */ +#if WASM_ENABLE_THREAD_MGR != 0 && WASM_ENABLE_DEBUG_INTERP != 0 +#if BH_ATOMIC_32_IS_ATOMIC != 0 +#define GET_SIGNAL_FLAG() \ + do { \ + signal_flag = \ + BH_ATOMIC_32_LOAD(exec_env->current_status->signal_flag); \ + } while (0) +#else +#define GET_SIGNAL_FLAG() \ + do { \ + os_mutex_lock(&exec_env->wait_lock); \ + signal_flag = exec_env->current_status->signal_flag; \ + os_mutex_unlock(&exec_env->wait_lock); \ + } while (0) +#endif +#endif + #if WASM_ENABLE_LABELS_AS_VALUES != 0 #define HANDLE_OP(opcode) HANDLE_##opcode: #define FETCH_OPCODE_AND_DISPATCH() goto *handle_table[*frame_ip++] #if WASM_ENABLE_THREAD_MGR != 0 && WASM_ENABLE_DEBUG_INTERP != 0 -#define HANDLE_OP_END() \ - do { \ - /* Record the current frame_ip, so when exception occurs, \ - debugger can know the exact opcode who caused the exception */ \ - frame_ip_orig = frame_ip; \ - os_mutex_lock(&exec_env->wait_lock); \ - while (exec_env->current_status->signal_flag == WAMR_SIG_SINGSTEP \ - && exec_env->current_status->step_count++ == 1) { \ - exec_env->current_status->step_count = 0; \ - SYNC_ALL_TO_FRAME(); \ - wasm_cluster_thread_waiting_run(exec_env); \ - } \ - os_mutex_unlock(&exec_env->wait_lock); \ - goto *handle_table[*frame_ip++]; \ +#define HANDLE_OP_END() \ + do { \ + /* Record the current frame_ip, so when exception occurs, \ + debugger can know the exact opcode who caused the exception */ \ + frame_ip_orig = frame_ip; \ + /* Atomic load the exec_env's signal_flag first, and then handle \ + more with lock if it is WAMR_SIG_SINGSTEP */ \ + GET_SIGNAL_FLAG(); \ + if (signal_flag == WAMR_SIG_SINGSTEP) { \ + os_mutex_lock(&exec_env->wait_lock); \ + while (exec_env->current_status->signal_flag == WAMR_SIG_SINGSTEP \ + && exec_env->current_status->step_count++ == 1) { \ + exec_env->current_status->step_count = 0; \ + SYNC_ALL_TO_FRAME(); \ + wasm_cluster_thread_waiting_run(exec_env); \ + } \ + os_mutex_unlock(&exec_env->wait_lock); \ + } \ + goto *handle_table[*frame_ip++]; \ } while (0) #else #define HANDLE_OP_END() FETCH_OPCODE_AND_DISPATCH() @@ -1427,16 +1449,24 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst, #else /* else of WASM_ENABLE_LABELS_AS_VALUES */ #define HANDLE_OP(opcode) case opcode: #if WASM_ENABLE_THREAD_MGR != 0 && WASM_ENABLE_DEBUG_INTERP != 0 -#define HANDLE_OP_END() \ - os_mutex_lock(&exec_env->wait_lock); \ - if (exec_env->current_status->signal_flag == WAMR_SIG_SINGSTEP \ - && exec_env->current_status->step_count++ == 1) { \ - exec_env->current_status->step_count = 0; \ - SYNC_ALL_TO_FRAME(); \ - wasm_cluster_thread_waiting_run(exec_env); \ - } \ - os_mutex_unlock(&exec_env->wait_lock); \ - continue +#define HANDLE_OP_END() \ + /* Record the current frame_ip, so when exception occurs, \ + debugger can know the exact opcode who caused the exception */ \ + frame_ip_orig = frame_ip; \ + /* Atomic load the exec_env's signal_flag first, and then handle \ + more with lock if it is WAMR_SIG_SINGSTEP */ \ + GET_SIGNAL_FLAG(); \ + if (signal_flag == WAMR_SIG_SINGSTEP) { \ + os_mutex_lock(&exec_env->wait_lock); \ + while (exec_env->current_status->signal_flag == WAMR_SIG_SINGSTEP \ + && exec_env->current_status->step_count++ == 1) { \ + exec_env->current_status->step_count = 0; \ + SYNC_ALL_TO_FRAME(); \ + wasm_cluster_thread_waiting_run(exec_env); \ + } \ + os_mutex_unlock(&exec_env->wait_lock); \ + } \ + continue; #else #define HANDLE_OP_END() continue #endif @@ -1545,6 +1575,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, debug_instance ? &debug_instance->watch_point_list_read : NULL; bh_list *watch_point_list_write = debug_instance ? &debug_instance->watch_point_list_write : NULL; +#if WASM_ENABLE_THREAD_MGR != 0 + uint32 signal_flag; +#endif #endif #if WASM_ENABLE_LABELS_AS_VALUES != 0 @@ -2248,8 +2281,15 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, bh_assert(tidx < module->module->type_count); cur_type = wasm_types[tidx]; + /* clang-format off */ +#if WASM_ENABLE_REF_TYPES != 0 || WASM_ENABLE_GC != 0 read_leb_uint32(frame_ip, frame_ip_end, tbl_idx); +#else + frame_ip++; + tbl_idx = 0; +#endif bh_assert(tbl_idx < module->table_count); + /* clang-format on */ tbl_inst = wasm_get_table_inst(module, tbl_idx); diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index 785b28980..0891598d1 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -56,10 +56,7 @@ has_module_memory64(WASMModule *module) static void set_error_buf(char *error_buf, uint32 error_buf_size, const char *string) { - if (error_buf != NULL) { - snprintf(error_buf, error_buf_size, "WASM module load failed: %s", - string); - } + wasm_loader_set_error_buf(error_buf, error_buf_size, string, false); } #if WASM_ENABLE_MEMORY64 != 0 @@ -131,82 +128,6 @@ check_buf1(const uint8 *buf, const uint8 *buf_end, uint32 length, #define skip_leb_int32(p, p_end) skip_leb(p) #define skip_leb_mem_offset(p, p_end) skip_leb(p) -static bool -read_leb(uint8 **p_buf, const uint8 *buf_end, uint32 maxbits, bool sign, - uint64 *p_result, char *error_buf, uint32 error_buf_size) -{ - const uint8 *buf = *p_buf; - uint64 result = 0; - uint32 shift = 0; - uint32 offset = 0, bcnt = 0; - uint64 byte; - - while (true) { - /* uN or SN must not exceed ceil(N/7) bytes */ - if (bcnt + 1 > (maxbits + 6) / 7) { - set_error_buf(error_buf, error_buf_size, - "integer representation too long"); - return false; - } - - CHECK_BUF(buf, buf_end, offset + 1); - byte = buf[offset]; - offset += 1; - result |= ((byte & 0x7f) << shift); - shift += 7; - bcnt += 1; - if ((byte & 0x80) == 0) { - break; - } - } - - if (!sign && maxbits == 32 && shift >= maxbits) { - /* The top bits set represent values > 32 bits */ - if (((uint8)byte) & 0xf0) - goto fail_integer_too_large; - } - else if (sign && maxbits == 32) { - if (shift < maxbits) { - /* Sign extend, second-highest bit is the sign bit */ - if ((uint8)byte & 0x40) - result |= (~((uint64)0)) << shift; - } - else { - /* The top bits should be a sign-extension of the sign bit */ - bool sign_bit_set = ((uint8)byte) & 0x8; - int top_bits = ((uint8)byte) & 0xf0; - if ((sign_bit_set && top_bits != 0x70) - || (!sign_bit_set && top_bits != 0)) - goto fail_integer_too_large; - } - } - else if (sign && maxbits == 64) { - if (shift < maxbits) { - /* Sign extend, second-highest bit is the sign bit */ - if ((uint8)byte & 0x40) - result |= (~((uint64)0)) << shift; - } - else { - /* The top bits should be a sign-extension of the sign bit */ - bool sign_bit_set = ((uint8)byte) & 0x1; - int top_bits = ((uint8)byte) & 0xfe; - - if ((sign_bit_set && top_bits != 0x7e) - || (!sign_bit_set && top_bits != 0)) - goto fail_integer_too_large; - } - } - - *p_buf += offset; - *p_result = result; - return true; - -fail_integer_too_large: - set_error_buf(error_buf, error_buf_size, "integer too large"); -fail: - return false; -} - #define read_uint8(p) TEMPLATE_READ_VALUE(uint8, p) #define read_uint32(p) TEMPLATE_READ_VALUE(uint32, p) @@ -7228,10 +7149,10 @@ wasm_loader_find_block_addr(WASMExecEnv *exec_env, BlockAddr *block_addr_cache, case WASM_OP_RETURN_CALL_INDIRECT: #endif skip_leb_uint32(p, p_end); /* typeidx */ -#if WASM_ENABLE_REF_TYPES == 0 && WASM_ENABLE_GC == 0 - u8 = read_uint8(p); /* 0x00 */ -#else +#if WASM_ENABLE_REF_TYPES != 0 || WASM_ENABLE_GC != 0 skip_leb_uint32(p, p_end); /* tableidx */ +#else + u8 = read_uint8(p); /* 0x00 */ #endif break; @@ -12083,6 +12004,16 @@ re_scan: read_leb_uint32(p, p_end, type_idx); #if WASM_ENABLE_REF_TYPES != 0 || WASM_ENABLE_GC != 0 +#if WASM_ENABLE_WAMR_COMPILER != 0 + if (p + 1 < p_end && *p != 0x00) { + /* + * Any non-0x00 byte requires the ref types proposal. + * This is different from checking the table_idx value + * since `0x80 0x00` etc. are all valid encodings of zero. + */ + module->is_ref_types_used = true; + } +#endif read_leb_uint32(p, p_end, table_idx); #else CHECK_BUF(p, p_end, 1); diff --git a/core/iwasm/interpreter/wasm_mini_loader.c b/core/iwasm/interpreter/wasm_mini_loader.c index 0012b84ae..0bb2f34eb 100644 --- a/core/iwasm/interpreter/wasm_mini_loader.c +++ b/core/iwasm/interpreter/wasm_mini_loader.c @@ -44,9 +44,7 @@ has_module_memory64(WASMModule *module) static void set_error_buf(char *error_buf, uint32 error_buf_size, const char *string) { - if (error_buf != NULL) - snprintf(error_buf, error_buf_size, "WASM module load failed: %s", - string); + wasm_loader_set_error_buf(error_buf, error_buf_size, string, false); } #define CHECK_BUF(buf, buf_end, length) \ @@ -95,71 +93,6 @@ is_byte_a_type(uint8 type) || (type == VALUE_TYPE_VOID); } -static void -read_leb(uint8 **p_buf, const uint8 *buf_end, uint32 maxbits, bool sign, - uint64 *p_result, char *error_buf, uint32 error_buf_size) -{ - const uint8 *buf = *p_buf; - uint64 result = 0; - uint32 shift = 0; - uint32 offset = 0, bcnt = 0; - uint64 byte; - - while (true) { - bh_assert(bcnt + 1 <= (maxbits + 6) / 7); - CHECK_BUF(buf, buf_end, offset + 1); - byte = buf[offset]; - offset += 1; - result |= ((byte & 0x7f) << shift); - shift += 7; - bcnt += 1; - if ((byte & 0x80) == 0) { - break; - } - } - - if (!sign && maxbits == 32 && shift >= maxbits) { - /* The top bits set represent values > 32 bits */ - bh_assert(!(((uint8)byte) & 0xf0)); - } - else if (sign && maxbits == 32) { - if (shift < maxbits) { - /* Sign extend, second-highest bit is the sign bit */ - if ((uint8)byte & 0x40) - result |= (~((uint64)0)) << shift; - } - else { - /* The top bits should be a sign-extension of the sign bit */ - bool sign_bit_set = ((uint8)byte) & 0x8; - int top_bits = ((uint8)byte) & 0xf0; - bh_assert(!((sign_bit_set && top_bits != 0x70) - || (!sign_bit_set && top_bits != 0))); - (void)top_bits; - (void)sign_bit_set; - } - } - else if (sign && maxbits == 64) { - if (shift < maxbits) { - /* Sign extend, second-highest bit is the sign bit */ - if ((uint8)byte & 0x40) - result |= (~((uint64)0)) << shift; - } - else { - /* The top bits should be a sign-extension of the sign bit */ - bool sign_bit_set = ((uint8)byte) & 0x1; - int top_bits = ((uint8)byte) & 0xfe; - - bh_assert(!((sign_bit_set && top_bits != 0x7e) - || (!sign_bit_set && top_bits != 0))); - (void)top_bits; - (void)sign_bit_set; - } - } - - *p_buf += offset; - *p_result = result; -} - #define read_uint8(p) TEMPLATE_READ_VALUE(uint8, p) #define read_uint32(p) TEMPLATE_READ_VALUE(uint32, p) #define read_bool(p) TEMPLATE_READ_VALUE(bool, p) @@ -3568,8 +3501,11 @@ wasm_loader_find_block_addr(WASMExecEnv *exec_env, BlockAddr *block_addr_cache, case WASM_OP_RETURN_CALL_INDIRECT: #endif skip_leb_uint32(p, p_end); /* typeidx */ - CHECK_BUF(p, p_end, 1); +#if WASM_ENABLE_REF_TYPES != 0 + skip_leb_uint32(p, p_end); /* tableidx */ +#else u8 = read_uint8(p); /* 0x00 */ +#endif break; #if WASM_ENABLE_EXCE_HANDLING != 0 diff --git a/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c b/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c index 8db888fe3..a68c07494 100644 --- a/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c +++ b/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c @@ -16,7 +16,7 @@ void wasm_runtime_set_exception(wasm_module_inst_t module, const char *exception); -uint32 +uint64 wasm_runtime_module_realloc(wasm_module_inst_t module, uint64 ptr, uint64 size, void **p_native_addr); @@ -683,9 +683,12 @@ calloc_wrapper(wasm_exec_env_t exec_env, uint32 nmemb, uint32 size) static uint32 realloc_wrapper(wasm_exec_env_t exec_env, uint32 ptr, uint32 new_size) { + uint64 ret_offset = 0; wasm_module_inst_t module_inst = get_module_inst(exec_env); - return wasm_runtime_module_realloc(module_inst, ptr, new_size, NULL); + ret_offset = wasm_runtime_module_realloc(module_inst, ptr, new_size, NULL); + bh_assert(ret_offset < UINT32_MAX); + return (uint32)ret_offset; } static void 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 627bbbb38..a313b9be5 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 @@ -459,8 +459,27 @@ fd_determine_type_rights(os_file_handle fd, __wasi_filetype_t *type, __wasi_rights_t *rights_inheriting) { struct __wasi_filestat_t buf; - __wasi_errno_t error = os_fstat(fd, &buf); + __wasi_errno_t error; + if (os_is_stdin_handle(fd)) { + *rights_base = RIGHTS_STDIN; + *rights_inheriting = RIGHTS_STDIN; + return __WASI_ESUCCESS; + } + + if (os_is_stdout_handle(fd)) { + *rights_base = RIGHTS_STDOUT; + *rights_inheriting = RIGHTS_STDOUT; + return __WASI_ESUCCESS; + } + + if (os_is_stderr_handle(fd)) { + *rights_base = RIGHTS_STDERR; + *rights_inheriting = RIGHTS_STDERR; + return __WASI_ESUCCESS; + } + + error = os_fstat(fd, &buf); if (error != __WASI_ESUCCESS) return error; diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/rights.h b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/rights.h index 4f5838159..41ff56f27 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/rights.h +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/rights.h @@ -47,6 +47,19 @@ #define RIGHTS_CHARACTER_DEVICE_BASE RIGHTS_ALL #define RIGHTS_CHARACTER_DEVICE_INHERITING RIGHTS_ALL +#define RIGHTS_STDIN \ + (__WASI_RIGHT_FD_ADVISE | __WASI_RIGHT_FD_FILESTAT_GET | \ + __WASI_RIGHT_FD_READ | __WASI_RIGHT_FD_WRITE | \ + __WASI_RIGHT_POLL_FD_READWRITE) + +#define RIGHTS_STDOUT \ + (__WASI_RIGHT_FD_ADVISE | __WASI_RIGHT_FD_DATASYNC | \ + __WASI_RIGHT_FD_FILESTAT_GET | __WASI_RIGHT_FD_SYNC | \ + __WASI_RIGHT_FD_READ | __WASI_RIGHT_FD_WRITE | \ + __WASI_RIGHT_POLL_FD_READWRITE) + +#define RIGHTS_STDERR RIGHTS_STDOUT + // Only allow directory operations on directories. Directories can only // yield file descriptors to other directories and files. #define RIGHTS_DIRECTORY_BASE \ diff --git a/core/iwasm/libraries/thread-mgr/thread_manager.h b/core/iwasm/libraries/thread-mgr/thread_manager.h index 0cbba888f..f5ca1eaed 100644 --- a/core/iwasm/libraries/thread-mgr/thread_manager.h +++ b/core/iwasm/libraries/thread-mgr/thread_manager.h @@ -184,9 +184,9 @@ wasm_cluster_is_thread_terminated(WASMExecEnv *exec_env); ((signo) == WAMR_SIG_STOP || (signo) == WAMR_SIG_TRAP) struct WASMCurrentEnvStatus { - uint64 signal_flag : 32; - uint64 step_count : 16; - uint64 running_status : 16; + uint32 signal_flag; + uint16 step_count; + uint16 running_status; }; WASMCurrentEnvStatus * diff --git a/core/iwasm/libraries/wasi-nn/cmake/Findtensorflow_lite.cmake b/core/iwasm/libraries/wasi-nn/cmake/Findtensorflow_lite.cmake index 59fdaf758..052dd9804 100644 --- a/core/iwasm/libraries/wasi-nn/cmake/Findtensorflow_lite.cmake +++ b/core/iwasm/libraries/wasi-nn/cmake/Findtensorflow_lite.cmake @@ -1,12 +1,13 @@ # Copyright (C) 2019 Intel Corporation. All rights reserved. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -find_library(TENSORFLOW_LITE - NAMES tensorflow-lite +find_library(TENSORFLOW_LITE + NAMES tensorflow-lite + HINTS ${CMAKE_CURRENT_BINARY_DIR}/tensorflow-lite + NO_DEFAULT_PATHS ) -if(NOT EXISTS ${TENSORFLOW_LITE}) +if(NOT TENSORFLOW_LITE) if(NOT EXISTS "${WAMR_ROOT_DIR}/core/deps/tensorflow-src") execute_process( COMMAND "${WAMR_ROOT_DIR}/core/deps/install_tensorflow.sh" @@ -32,11 +33,15 @@ if(NOT EXISTS ${TENSORFLOW_LITE}) "${TENSORFLOW_SOURCE_DIR}/tensorflow/lite" "${CMAKE_CURRENT_BINARY_DIR}/tensorflow-lite" EXCLUDE_FROM_ALL - ) - - set(TENSORFLOW_LITE_INCLUDE_DIR "${TENSORFLOW_SOURCE_DIR}") - set(FLATBUFFER_INCLUDE_DIR "${CMAKE_CURRENT_BINARY_DIR}/flatbuffers/include") - - include_directories(${TENSORFLOW_LITE_INCLUDE_DIR}) - include_directories(${FLATBUFFER_INCLUDE_DIR}) + ) +else () + message(STATUS "TensorFlow Lite library found: ${TENSORFLOW_LITE}") + set(TENSORFLOW_SOURCE_DIR "${WAMR_ROOT_DIR}/core/deps/tensorflow-src") endif() + +set(TENSORFLOW_LITE_INCLUDE_DIR "${TENSORFLOW_SOURCE_DIR}/tensorflow/lite") +set(FLATBUFFER_INCLUDE_DIR "${CMAKE_CURRENT_BINARY_DIR}/flatbuffers/include") + +include_directories(${TENSORFLOW_SOURCE_DIR}) +include_directories(${FLATBUFFER_INCLUDE_DIR}) +link_directories(${CMAKE_CURRENT_BINARY_DIR}/tensorflow-lite) diff --git a/core/iwasm/libraries/wasi-nn/cmake/wasi_nn.cmake b/core/iwasm/libraries/wasi-nn/cmake/wasi_nn.cmake index 49286f2f4..e2ad257e0 100644 --- a/core/iwasm/libraries/wasi-nn/cmake/wasi_nn.cmake +++ b/core/iwasm/libraries/wasi-nn/cmake/wasi_nn.cmake @@ -27,61 +27,48 @@ endif() # # wasi-nn general set(WASI_NN_ROOT ${CMAKE_CURRENT_LIST_DIR}/..) -add_library( - wasi-nn-general - SHARED - ${WASI_NN_ROOT}/src/wasi_nn.c - ${WASI_NN_ROOT}/src/utils/wasi_nn_app_native.c +set(WASI_NN_SOURCES + ${WASI_NN_ROOT}/src/wasi_nn.c + ${WASI_NN_ROOT}/src/utils/wasi_nn_app_native.c ) -target_include_directories( - wasi-nn-general - PUBLIC - ${WASI_NN_ROOT}/include - ${WASI_NN_ROOT}/src - ${WASI_NN_ROOT}/src/utils -) -target_link_libraries( - wasi-nn-general - PUBLIC - libiwasm -) -target_compile_definitions( - wasi-nn-general - PUBLIC - $<$:NN_LOG_LEVEL=0> - $<$:NN_LOG_LEVEL=2> +include_directories(${WASI_NN_ROOT}/include) +add_compile_definitions( + $<$:NN_LOG_LEVEL=0> + $<$:NN_LOG_LEVEL=2> ) # # wasi-nn backends - +# # - tflite if(WAMR_BUILD_WASI_NN_TFLITE EQUAL 1) add_library( - wasi-nn-tflite + wasi_nn_tflite SHARED ${WASI_NN_ROOT}/src/wasi_nn_tensorflowlite.cpp ) + target_link_libraries( - wasi-nn-tflite + wasi_nn_tflite PUBLIC + libiwasm tensorflow-lite - wasi-nn-general ) endif() # - openvino if(WAMR_BUILD_WASI_NN_OPENVINO EQUAL 1) add_library( - wasi-nn-openvino + wasi_nn_openvino SHARED ${WASI_NN_ROOT}/src/wasi_nn_openvino.c ) + target_link_libraries( - wasi-nn-openvino + wasi_nn_openvino PUBLIC + libiwasm openvino::runtime openvino::runtime::c - wasi-nn-general ) endif() \ No newline at end of file diff --git a/core/iwasm/libraries/wasi-nn/include/wasi_nn_host.h b/core/iwasm/libraries/wasi-nn/include/wasi_nn_host.h new file mode 100644 index 000000000..cb056915f --- /dev/null +++ b/core/iwasm/libraries/wasi-nn/include/wasi_nn_host.h @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef WASI_NN_HOST_H +#define WASI_NN_HOST_H + +#include "lib_export.h" + +uint32_t +get_wasi_nn_export_apis(NativeSymbol **p_native_symbols); + +bool +wasi_nn_initialize(); + +void +wasi_nn_destroy(); + +#endif /* WASI_NN_HOST_H */ \ No newline at end of file diff --git a/core/iwasm/libraries/wasi-nn/include/wasi_nn_types.h b/core/iwasm/libraries/wasi-nn/include/wasi_nn_types.h index 71c530ea5..d36f5977c 100644 --- a/core/iwasm/libraries/wasi-nn/include/wasi_nn_types.h +++ b/core/iwasm/libraries/wasi-nn/include/wasi_nn_types.h @@ -126,6 +126,7 @@ typedef enum { tensorflowlite, ggml, autodetect, + unknown_backend, } graph_encoding; // Define where the graph should be executed. @@ -161,9 +162,6 @@ typedef struct { BACKEND_DEINITIALIZE deinit; } api_function; -bool -wasi_nn_register_backend(api_function apis); - void wasi_nn_dump_tensor_dimension(tensor_dimensions *dim, int32_t output_len, char *output); diff --git a/core/iwasm/libraries/wasi-nn/src/wasi_nn.c b/core/iwasm/libraries/wasi-nn/src/wasi_nn.c index 2d987d3b4..0d56981fc 100644 --- a/core/iwasm/libraries/wasi-nn/src/wasi_nn.c +++ b/core/iwasm/libraries/wasi-nn/src/wasi_nn.c @@ -10,40 +10,37 @@ #include #include #include +#include #include "wasi_nn_private.h" -#include "wasi_nn_app_native.h" -#include "logger.h" +#include "utils/wasi_nn_app_native.h" +#include "utils/logger.h" #include "bh_platform.h" #include "wasi_nn_types.h" #include "wasm_export.h" #define HASHMAP_INITIAL_SIZE 20 +#define TFLITE_BACKEND_LIB "libwasi_nn_tflite.so" +#define OPENVINO_BACKEND_LIB "libwasi_nn_openvino.so" +#define LLAMACPP_BACKEND_LIB "libwasi_nn_llamacpp.so" /* Global variables */ -// if using `load_by_name`, there is no known `encoding` at the time of loading -// so, just keep one `api_function` is enough -static api_function lookup = { 0 }; +struct backends_api_functions { + void *backend_handle; + api_function functions; +} lookup[autodetect] = { 0 }; -#define call_wasi_nn_func(wasi_error, func, ...) \ - do { \ - if (lookup.func) { \ - wasi_error = lookup.func(__VA_ARGS__); \ - if (wasi_error != success) \ - NN_ERR_PRINTF("Error %s: %d", #func, wasi_error); \ - } \ - else { \ - NN_ERR_PRINTF("Error %s is not registered", #func); \ - wasi_error = unsupported_operation; \ - } \ +#define call_wasi_nn_func(backend_encoding, func, wasi_error, ...) \ + do { \ + wasi_error = lookup[backend_encoding].functions.func(__VA_ARGS__); \ + if (wasi_error != success) \ + NN_ERR_PRINTF("Error %s() -> %d", #func, wasi_error); \ } while (0) +/* HashMap utils */ static HashMap *hashmap; -static void -wasi_nn_ctx_destroy(WASINNContext *wasi_nn_ctx); - static uint32 hash_func(const void *key) { @@ -74,12 +71,51 @@ key_destroy_func(void *key1) /* key type is wasm_module_inst_t*. do nothing */ } +static void +wasi_nn_ctx_destroy(WASINNContext *wasi_nn_ctx) +{ + NN_DBG_PRINTF("[WASI NN] DEINIT..."); + + 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_model_loaded: %d", wasi_nn_ctx->is_model_loaded); + NN_DBG_PRINTF("-> current_encoding: %d", wasi_nn_ctx->backend); + + /* deinit() the backend */ + wasi_nn_error res; + call_wasi_nn_func(wasi_nn_ctx->backend, deinit, res, + wasi_nn_ctx->backend_ctx); + + wasm_runtime_free(wasi_nn_ctx); +} + static void value_destroy_func(void *value) { wasi_nn_ctx_destroy((WASINNContext *)value); } +bool +wasi_nn_initialize() +{ + NN_DBG_PRINTF("[WASI NN General] Initializing wasi-nn"); + + // hashmap { instance: wasi_nn_ctx } + hashmap = bh_hash_map_create(HASHMAP_INITIAL_SIZE, true, hash_func, + key_equal_func, key_destroy_func, + value_destroy_func); + if (hashmap == NULL) { + NN_ERR_PRINTF("Error while initializing hashmap"); + return false; + } + + return true; +} + static WASINNContext * wasi_nn_initialize_context() { @@ -91,34 +127,11 @@ wasi_nn_initialize_context() NN_ERR_PRINTF("Error when allocating memory for WASI-NN context"); return NULL; } - wasi_nn_ctx->is_model_loaded = false; - - /* only one backend can be registered */ - wasi_nn_error res; - call_wasi_nn_func(res, init, &wasi_nn_ctx->backend_ctx); - if (res != success) { - wasm_runtime_free(wasi_nn_ctx); - return NULL; - } + memset(wasi_nn_ctx, 0, sizeof(WASINNContext)); return wasi_nn_ctx; } -static bool -wasi_nn_initialize() -{ - NN_DBG_PRINTF("[WASI NN General] Initializing wasi-nn"); - // hashmap { instance: wasi_nn_ctx } - hashmap = bh_hash_map_create(HASHMAP_INITIAL_SIZE, true, hash_func, - key_equal_func, key_destroy_func, - value_destroy_func); - if (hashmap == NULL) { - NN_ERR_PRINTF("Error while initializing hashmap"); - return false; - } - return true; -} - /* Get wasi-nn context from module instance */ static WASINNContext * wasm_runtime_get_wasi_nn_ctx(wasm_module_inst_t instance) @@ -129,6 +142,7 @@ wasm_runtime_get_wasi_nn_ctx(wasm_module_inst_t instance) wasi_nn_ctx = wasi_nn_initialize_context(); if (wasi_nn_ctx == NULL) return NULL; + bool ok = bh_hash_map_insert(hashmap, (void *)instance, (void *)wasi_nn_ctx); if (!ok) { @@ -141,36 +155,31 @@ wasm_runtime_get_wasi_nn_ctx(wasm_module_inst_t instance) return wasi_nn_ctx; } -static void -wasi_nn_ctx_destroy(WASINNContext *wasi_nn_ctx) -{ - NN_DBG_PRINTF("[WASI NN] DEINIT..."); - - 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_model_loaded: %d", wasi_nn_ctx->is_model_loaded); - NN_DBG_PRINTF("-> current_encoding: %d", wasi_nn_ctx->current_encoding); - - /* only one backend can be registered */ - wasi_nn_error res; - call_wasi_nn_func(res, deinit, wasi_nn_ctx->backend_ctx); - - wasm_runtime_free(wasi_nn_ctx); -} - void wasi_nn_destroy() { // destroy hashmap will destroy keys and values bh_hash_map_destroy(hashmap); + + // close backends' libraries and registered functions + for (unsigned i = 0; i < sizeof(lookup) / sizeof(lookup[0]); i++) { + if (lookup[i].backend_handle) { + dlclose(lookup[i].backend_handle); + lookup[i].backend_handle = NULL; + } + + lookup[i].functions.init = NULL; + lookup[i].functions.deinit = NULL; + lookup[i].functions.load = NULL; + lookup[i].functions.load_by_name = NULL; + lookup[i].functions.init_execution_context = NULL; + lookup[i].functions.set_input = NULL; + lookup[i].functions.compute = NULL; + lookup[i].functions.get_output = NULL; + } } /* Utils */ - static wasi_nn_error is_model_initialized(WASINNContext *wasi_nn_ctx) { @@ -181,8 +190,169 @@ is_model_initialized(WASINNContext *wasi_nn_ctx) return success; } -/* WASI-NN implementation */ +/* + *TODO: choose a proper backend based on + * - hardware + * - model file format + * - on device ML framework + */ +static graph_encoding +choose_a_backend() +{ + void *handle; + handle = dlopen(LLAMACPP_BACKEND_LIB, RTLD_LAZY); + if (handle) { + NN_INFO_PRINTF("Using llama.cpp backend"); + dlclose(handle); + return ggml; + } + + handle = dlopen(OPENVINO_BACKEND_LIB, RTLD_LAZY); + if (handle) { + NN_INFO_PRINTF("Using openvino backend"); + dlclose(handle); + return openvino; + } + + handle = dlopen(TFLITE_BACKEND_LIB, RTLD_LAZY); + if (handle) { + NN_INFO_PRINTF("Using tflite backend"); + dlclose(handle); + return tensorflowlite; + } + + return unknown_backend; +} + +static bool +register_backend(void *handle, api_function *functions) +{ + BACKEND_INITIALIZE init = (BACKEND_INITIALIZE)dlsym(handle, "init_backend"); + if (!init) { + NN_WARN_PRINTF("init_backend() not found"); + return false; + } + functions->init = init; + + BACKEND_DEINITIALIZE deinit = + (BACKEND_DEINITIALIZE)dlsym(handle, "deinit_backend"); + if (!deinit) { + NN_WARN_PRINTF("deinit_backend() not found"); + return false; + } + functions->deinit = deinit; + + LOAD load = (LOAD)dlsym(handle, "load"); + if (!load) { + NN_WARN_PRINTF("load() not found"); + return false; + } + functions->load = load; + + LOAD_BY_NAME load_by_name = (LOAD_BY_NAME)dlsym(handle, "load_by_name"); + if (!load_by_name) { + NN_WARN_PRINTF("load_by_name() not found"); + return false; + } + functions->load_by_name = load_by_name; + + INIT_EXECUTION_CONTEXT init_execution_context = + (INIT_EXECUTION_CONTEXT)dlsym(handle, "init_execution_context"); + if (!init_execution_context) { + NN_WARN_PRINTF("init_execution_context() not found"); + return false; + } + functions->init_execution_context = init_execution_context; + + SET_INPUT set_input = (SET_INPUT)dlsym(handle, "set_input"); + if (!set_input) { + NN_WARN_PRINTF("set_input() not found"); + return false; + } + functions->set_input = set_input; + + COMPUTE compute = (COMPUTE)dlsym(handle, "compute"); + if (!compute) { + NN_WARN_PRINTF("compute() not found"); + return false; + } + functions->compute = compute; + + GET_OUTPUT get_output = (GET_OUTPUT)dlsym(handle, "get_output"); + if (!get_output) { + NN_WARN_PRINTF("get_output() not found"); + return false; + } + functions->get_output = get_output; + + return true; +} + +static bool +prepare_backend(const char *lib_name, struct backends_api_functions *backend) +{ + NN_DBG_PRINTF("[Native Register] prepare_backend %s", lib_name); + + void *handle; + handle = dlopen(lib_name, RTLD_LAZY); + if (!handle) { + NN_ERR_PRINTF("Error loading %s. %s", lib_name, dlerror()); + return false; + } + + if (!register_backend(handle, &(backend->functions))) { + NN_ERR_PRINTF("Error when registering functions of %s", lib_name); + dlclose(handle); + return false; + } + + backend->backend_handle = handle; + return true; +} + +static const char * +graph_encoding_to_backend_lib_name(graph_encoding encoding) +{ + switch (encoding) { + case openvino: + return OPENVINO_BACKEND_LIB; + case tensorflowlite: + return TFLITE_BACKEND_LIB; + case ggml: + return LLAMACPP_BACKEND_LIB; + default: + return NULL; + } +} + +static bool +detect_and_load_backend(graph_encoding backend_hint, + struct backends_api_functions *backends, + graph_encoding *loaded_backed) +{ + if (backend_hint >= autodetect) + return false; + + if (backend_hint == autodetect) + backend_hint = choose_a_backend(); + + /* if already loaded */ + if (lookup[backend_hint].backend_handle) { + *loaded_backed = backend_hint; + return true; + } + + *loaded_backed = backend_hint; + const char *backend_lib_name = + graph_encoding_to_backend_lib_name(backend_hint); + if (!backend_lib_name) + return false; + + return prepare_backend(backend_lib_name, backends + backend_hint); +} + +/* WASI-NN implementation */ #if WASM_ENABLE_WASI_EPHEMERAL_NN != 0 wasi_nn_error wasi_nn_load(wasm_exec_env_t exec_env, graph_builder_wasm *builder, @@ -222,13 +392,28 @@ wasi_nn_load(wasm_exec_env_t exec_env, graph_builder_array_wasm *builder, goto fail; } + graph_encoding loaded_backed = autodetect; + if (!detect_and_load_backend(encoding, lookup, &loaded_backed)) { + res = invalid_encoding; + NN_ERR_PRINTF("load backend failed"); + goto fail; + } + WASINNContext *wasi_nn_ctx = wasm_runtime_get_wasi_nn_ctx(instance); - call_wasi_nn_func(res, load, wasi_nn_ctx->backend_ctx, &builder_native, - encoding, target, g); + wasi_nn_ctx->backend = loaded_backed; + + /* init() the backend */ + call_wasi_nn_func(wasi_nn_ctx->backend, init, res, + &wasi_nn_ctx->backend_ctx); if (res != success) goto fail; - wasi_nn_ctx->current_encoding = encoding; + call_wasi_nn_func(wasi_nn_ctx->backend, load, res, wasi_nn_ctx->backend_ctx, + &builder_native, encoding, target, g); + if (res != success) + goto fail; + + wasi_nn_ctx->backend = loaded_backed; wasi_nn_ctx->is_model_loaded = true; fail: @@ -251,22 +436,37 @@ wasi_nn_load_by_name(wasm_exec_env_t exec_env, char *name, uint32_t name_len, } if (!wasm_runtime_validate_native_addr(instance, name, name_len)) { + NN_ERR_PRINTF("name is invalid"); return invalid_argument; } if (!wasm_runtime_validate_native_addr(instance, g, (uint64)sizeof(graph))) { + NN_ERR_PRINTF("graph is invalid"); return invalid_argument; } + graph_encoding loaded_backed = autodetect; + if (detect_and_load_backend(autodetect, lookup, &loaded_backed)) { + NN_ERR_PRINTF("load backend failed"); + return invalid_encoding; + } + WASINNContext *wasi_nn_ctx = wasm_runtime_get_wasi_nn_ctx(instance); wasi_nn_error res; - call_wasi_nn_func(res, load_by_name, wasi_nn_ctx->backend_ctx, name, - name_len, g); + + /* init() the backend */ + call_wasi_nn_func(wasi_nn_ctx->backend, init, res, + &wasi_nn_ctx->backend_ctx); if (res != success) return res; - wasi_nn_ctx->current_encoding = autodetect; + call_wasi_nn_func(wasi_nn_ctx->backend, load_by_name, res, + wasi_nn_ctx->backend_ctx, name, name_len, g); + if (res != success) + return res; + + wasi_nn_ctx->backend = loaded_backed; wasi_nn_ctx->is_model_loaded = true; return success; } @@ -294,8 +494,8 @@ wasi_nn_init_execution_context(wasm_exec_env_t exec_env, graph g, return invalid_argument; } - call_wasi_nn_func(res, init_execution_context, wasi_nn_ctx->backend_ctx, g, - ctx); + call_wasi_nn_func(wasi_nn_ctx->backend, init_execution_context, res, + wasi_nn_ctx->backend_ctx, g, ctx); return res; } @@ -322,7 +522,8 @@ wasi_nn_set_input(wasm_exec_env_t exec_env, graph_execution_context ctx, &input_tensor_native))) return res; - call_wasi_nn_func(res, set_input, wasi_nn_ctx->backend_ctx, ctx, index, + call_wasi_nn_func(wasi_nn_ctx->backend, set_input, res, + wasi_nn_ctx->backend_ctx, ctx, index, &input_tensor_native); // XXX: Free intermediate structure pointers if (input_tensor_native.dimensions) @@ -347,7 +548,8 @@ wasi_nn_compute(wasm_exec_env_t exec_env, graph_execution_context ctx) if (success != (res = is_model_initialized(wasi_nn_ctx))) return res; - call_wasi_nn_func(res, compute, wasi_nn_ctx->backend_ctx, ctx); + call_wasi_nn_func(wasi_nn_ctx->backend, compute, res, + wasi_nn_ctx->backend_ctx, ctx); return res; } @@ -383,12 +585,14 @@ wasi_nn_get_output(wasm_exec_env_t exec_env, graph_execution_context ctx, } #if WASM_ENABLE_WASI_EPHEMERAL_NN != 0 - call_wasi_nn_func(res, get_output, wasi_nn_ctx->backend_ctx, ctx, index, - output_tensor, &output_tensor_len); + call_wasi_nn_func(wasi_nn_ctx->backend, get_output, res, + wasi_nn_ctx->backend_ctx, ctx, index, output_tensor, + &output_tensor_len); *output_tensor_size = output_tensor_len; #else /* WASM_ENABLE_WASI_EPHEMERAL_NN == 0 */ - call_wasi_nn_func(res, get_output, wasi_nn_ctx->backend_ctx, ctx, index, - output_tensor, output_tensor_size); + call_wasi_nn_func(wasi_nn_ctx->backend, get_output, res, + wasi_nn_ctx->backend_ctx, ctx, index, output_tensor, + output_tensor_size); #endif /* WASM_ENABLE_WASI_EPHEMERAL_NN != 0 */ return res; } @@ -423,44 +627,3 @@ get_wasi_nn_export_apis(NativeSymbol **p_native_symbols) *p_native_symbols = native_symbols_wasi_nn; return sizeof(native_symbols_wasi_nn) / sizeof(NativeSymbol); } - -__attribute__((used)) uint32_t -get_native_lib(char **p_module_name, NativeSymbol **p_native_symbols) -{ - NN_DBG_PRINTF("[Native Register] get_native_lib"); - -#if WASM_ENABLE_WASI_EPHEMERAL_NN != 0 - *p_module_name = "wasi_ephemeral_nn"; -#else /* WASM_ENABLE_WASI_EPHEMERAL_NN == 0 */ - *p_module_name = "wasi_nn"; -#endif /* WASM_ENABLE_WASI_EPHEMERAL_NN != 0 */ - - return get_wasi_nn_export_apis(p_native_symbols); -} - -__attribute__((used)) int -init_native_lib() -{ - NN_DBG_PRINTF("[Native Register] init_native_lib"); - - if (!wasi_nn_initialize()) - return 1; - - return 0; -} - -__attribute__((used)) void -deinit_native_lib() -{ - NN_DBG_PRINTF("[Native Register] deinit_native_lib"); - - wasi_nn_destroy(); -} - -__attribute__((used)) bool -wasi_nn_register_backend(api_function apis) -{ - NN_DBG_PRINTF("[Native Register] wasi_nn_register_backend"); - lookup = apis; - return true; -} diff --git a/core/iwasm/libraries/wasi-nn/src/wasi_nn_openvino.c b/core/iwasm/libraries/wasi-nn/src/wasi_nn_openvino.c index 678673e8b..db2f91db0 100644 --- a/core/iwasm/libraries/wasi-nn/src/wasi_nn_openvino.c +++ b/core/iwasm/libraries/wasi-nn/src/wasi_nn_openvino.c @@ -5,7 +5,7 @@ #include "wasi_nn_types.h" #include "wasi_nn_openvino.h" -#include "logger.h" +#include "utils/logger.h" #include "bh_platform.h" #include "openvino/c/openvino.h" @@ -82,7 +82,7 @@ dump_ov_shape_t(const ov_shape_t *shape, int32_t output_len, char *output) static void print_model_input_output_info(ov_model_t *model) { - wasi_nn_error ov_error; + wasi_nn_error ov_error = success; char *friendly_name = NULL; size_t input_size = 0; ov_output_const_port_t *input_port = NULL; @@ -136,6 +136,7 @@ print_model_input_output_info(ov_model_t *model) output_port = NULL; } + ov_error = ov_error; fail: if (friendly_name) ov_free(friendly_name); @@ -157,16 +158,23 @@ wasi_nn_tensor_type_to_openvino_element_type(tensor_type wasi_nn_type) return F16; case fp32: return F32; +#if WASM_ENABLE_WASI_EPHEMERAL_NN != 0 case fp64: return F64; case bf16: return BF16; + case i64: + return I64; case u8: return U8; case i32: return I32; - case i64: - return I64; +#else + case up8: + return U8; + case ip32: + return I32; +#endif default: break; } @@ -178,7 +186,7 @@ wasi_nn_tensor_type_to_openvino_element_type(tensor_type wasi_nn_type) static wasi_nn_error uint32_array_to_int64_array(uint32_t array_size, uint32_t *src, int64_t **dst) { - *dst = malloc(array_size * sizeof(int64_t)); + *dst = os_malloc(array_size * sizeof(int64_t)); if (!(*dst)) return runtime_error; @@ -189,9 +197,9 @@ uint32_array_to_int64_array(uint32_t array_size, uint32_t *src, int64_t **dst) return success; } -wasi_nn_error -openvino_load(void *ctx, graph_builder_array *builder, graph_encoding encoding, - execution_target target, graph *g) +__attribute__((visibility("default"))) wasi_nn_error +load(void *ctx, graph_builder_array *builder, graph_encoding encoding, + execution_target target, graph *g) { OpenVINOContext *ov_ctx = (OpenVINOContext *)ctx; wasi_nn_error ret = unsupported_operation; @@ -227,7 +235,7 @@ openvino_load(void *ctx, graph_builder_array *builder, graph_encoding encoding, /* transfer weight to an ov tensor */ { - ov_ctx->weight_data = malloc(weight.size); + ov_ctx->weight_data = os_malloc(weight.size); if (!ov_ctx->weight_data) goto fail; memcpy(ov_ctx->weight_data, weight.buf, weight.size); @@ -255,9 +263,8 @@ fail: return ret; } -wasi_nn_error -openvino_load_by_name(void *ctx, const char *filename, uint32_t filename_len, - graph *g) +__attribute__((visibility("default"))) wasi_nn_error +load_by_name(void *ctx, const char *filename, uint32_t filename_len, graph *g) { OpenVINOContext *ov_ctx = (OpenVINOContext *)ctx; wasi_nn_error ret = unsupported_operation; @@ -270,16 +277,15 @@ fail: return ret; } -wasi_nn_error -openvino_init_execution_context(void *ctx, graph g, - graph_execution_context *exec_ctx) +__attribute__((visibility("default"))) wasi_nn_error +init_execution_context(void *ctx, graph g, graph_execution_context *exec_ctx) { return success; } -wasi_nn_error -openvino_set_input(void *ctx, graph_execution_context exec_ctx, uint32_t index, - tensor *wasi_nn_tensor) +__attribute__((visibility("default"))) wasi_nn_error +set_input(void *ctx, graph_execution_context exec_ctx, uint32_t index, + tensor *wasi_nn_tensor) { OpenVINOContext *ov_ctx = (OpenVINOContext *)ctx; wasi_nn_error ret = unsupported_operation; @@ -405,7 +411,7 @@ openvino_set_input(void *ctx, graph_execution_context exec_ctx, uint32_t index, fail: if (ov_dims) - free(ov_dims); + os_free(ov_dims); ov_shape_free(&input_shape); if (ppp) ov_preprocess_prepostprocessor_free(ppp); @@ -429,8 +435,8 @@ fail: return ret; } -wasi_nn_error -openvino_compute(void *ctx, graph_execution_context exec_ctx) +__attribute__((visibility("default"))) wasi_nn_error +compute(void *ctx, graph_execution_context exec_ctx) { OpenVINOContext *ov_ctx = (OpenVINOContext *)ctx; wasi_nn_error ret = unsupported_operation; @@ -441,9 +447,9 @@ fail: return ret; } -wasi_nn_error -openvino_get_output(void *ctx, graph_execution_context exec_ctx, uint32_t index, - tensor_data output_tensor, uint32_t *output_tensor_size) +__attribute__((visibility("default"))) wasi_nn_error +get_output(void *ctx, graph_execution_context exec_ctx, uint32_t index, + tensor_data output_tensor, uint32_t *output_tensor_size) { OpenVINOContext *ov_ctx = (OpenVINOContext *)ctx; wasi_nn_error ret = unsupported_operation; @@ -471,8 +477,8 @@ fail: return ret; } -wasi_nn_error -openvino_initialize(void **ctx) +__attribute__((visibility("default"))) wasi_nn_error +init_backend(void **ctx) { ov_version_t version; OpenVINOContext *ov_ctx = NULL; @@ -509,8 +515,8 @@ fail: return ret; } -wasi_nn_error -openvino_destroy(void *ctx) +__attribute__((visibility("default"))) wasi_nn_error +deinit_backend(void *ctx) { OpenVINOContext *ov_ctx = (OpenVINOContext *)ctx; @@ -518,7 +524,7 @@ openvino_destroy(void *ctx) return invalid_argument; if (ov_ctx->weight_data) - free(ov_ctx->weight_data); + os_free(ov_ctx->weight_data); if (ov_ctx->weights_tensor) ov_tensor_free(ov_ctx->weights_tensor); @@ -541,19 +547,3 @@ openvino_destroy(void *ctx) os_free(ov_ctx); return success; } - -__attribute__((constructor(200))) void -openvino_register_backend() -{ - api_function apis = { - .load = openvino_load, - .load_by_name = openvino_load_by_name, - .init_execution_context = openvino_init_execution_context, - .set_input = openvino_set_input, - .compute = openvino_compute, - .get_output = openvino_get_output, - .init = openvino_initialize, - .deinit = openvino_destroy, - }; - wasi_nn_register_backend(apis); -} \ No newline at end of file diff --git a/core/iwasm/libraries/wasi-nn/src/wasi_nn_openvino.h b/core/iwasm/libraries/wasi-nn/src/wasi_nn_openvino.h index 798c69a0d..ea03a226f 100644 --- a/core/iwasm/libraries/wasi-nn/src/wasi_nn_openvino.h +++ b/core/iwasm/libraries/wasi-nn/src/wasi_nn_openvino.h @@ -8,29 +8,28 @@ #include "wasi_nn_types.h" -wasi_nn_error -openvino_load(void *ctx, graph_builder_array *builder, graph_encoding encoding, - execution_target target, graph *g); +__attribute__((visibility("default"))) wasi_nn_error +load(void *ctx, graph_builder_array *builder, graph_encoding encoding, + execution_target target, graph *g); -wasi_nn_error -openvino_init_execution_context(void *ctx, graph g, - graph_execution_context *exec_ctx); +__attribute__((visibility("default"))) wasi_nn_error +init_execution_context(void *ctx, graph g, graph_execution_context *exec_ctx); -wasi_nn_error -openvino_set_input(void *ctx, graph_execution_context exec_ctx, uint32_t index, - tensor *input_tensor); +__attribute__((visibility("default"))) wasi_nn_error +set_input(void *ctx, graph_execution_context exec_ctx, uint32_t index, + tensor *input_tensor); -wasi_nn_error -openvino_compute(void *ctx, graph_execution_context exec_ctx); +__attribute__((visibility("default"))) wasi_nn_error +compute(void *ctx, graph_execution_context exec_ctx); -wasi_nn_error -openvino_get_output(void *ctx, graph_execution_context exec_ctx, uint32_t index, - tensor_data output_tensor, uint32_t *output_tensor_size); +__attribute__((visibility("default"))) wasi_nn_error +get_output(void *ctx, graph_execution_context exec_ctx, uint32_t index, + tensor_data output_tensor, uint32_t *output_tensor_size); -wasi_nn_error -openvino_initialize(void **ctx); +__attribute__((visibility("default"))) wasi_nn_error +init_backend(void **ctx); -wasi_nn_error -openvino_destroy(void *ctx); +__attribute__((visibility("default"))) wasi_nn_error +deinit_backend(void *ctx); #endif /* WASI_NN_OPENVINO_HPP */ \ No newline at end of file diff --git a/core/iwasm/libraries/wasi-nn/src/wasi_nn_private.h b/core/iwasm/libraries/wasi-nn/src/wasi_nn_private.h index df5080dea..bacae99ad 100644 --- a/core/iwasm/libraries/wasi-nn/src/wasi_nn_private.h +++ b/core/iwasm/libraries/wasi-nn/src/wasi_nn_private.h @@ -11,8 +11,7 @@ typedef struct { bool is_model_loaded; - // Optional - graph_encoding current_encoding; + graph_encoding backend; void *backend_ctx; } WASINNContext; 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 606aca243..6a3b5a47d 100644 --- a/core/iwasm/libraries/wasi-nn/src/wasi_nn_tensorflowlite.cpp +++ b/core/iwasm/libraries/wasi-nn/src/wasi_nn_tensorflowlite.cpp @@ -4,7 +4,7 @@ */ #include "wasi_nn_tensorflowlite.hpp" -#include "logger.h" +#include "utils/logger.h" #include "bh_platform.h" #include "wasi_nn_types.h" @@ -113,10 +113,9 @@ is_valid_graph_execution_context(TFLiteContext *tfl_ctx, } /* WASI-NN (tensorflow) implementation */ - -wasi_nn_error -tensorflowlite_load(void *tflite_ctx, graph_builder_array *builder, - graph_encoding encoding, execution_target target, graph *g) +__attribute__((visibility("default"))) wasi_nn_error +load(void *tflite_ctx, graph_builder_array *builder, graph_encoding encoding, + execution_target target, graph *g) { TFLiteContext *tfl_ctx = (TFLiteContext *)tflite_ctx; @@ -168,9 +167,9 @@ tensorflowlite_load(void *tflite_ctx, graph_builder_array *builder, return success; } -wasi_nn_error -tensorflowlite_load_by_name(void *tflite_ctx, const char *filename, - uint32_t filename_len, graph *g) +__attribute__((visibility("default"))) wasi_nn_error +load_by_name(void *tflite_ctx, const char *filename, uint32_t filename_len, + graph *g) { TFLiteContext *tfl_ctx = (TFLiteContext *)tflite_ctx; @@ -192,9 +191,8 @@ tensorflowlite_load_by_name(void *tflite_ctx, const char *filename, return success; } -wasi_nn_error -tensorflowlite_init_execution_context(void *tflite_ctx, graph g, - graph_execution_context *ctx) +__attribute__((visibility("default"))) wasi_nn_error +init_execution_context(void *tflite_ctx, graph g, graph_execution_context *ctx) { TFLiteContext *tfl_ctx = (TFLiteContext *)tflite_ctx; @@ -281,9 +279,9 @@ tensorflowlite_init_execution_context(void *tflite_ctx, graph g, return success; } -wasi_nn_error -tensorflowlite_set_input(void *tflite_ctx, graph_execution_context ctx, - uint32_t index, tensor *input_tensor) +__attribute__((visibility("default"))) wasi_nn_error +set_input(void *tflite_ctx, graph_execution_context ctx, uint32_t index, + tensor *input_tensor) { TFLiteContext *tfl_ctx = (TFLiteContext *)tflite_ctx; @@ -352,8 +350,8 @@ tensorflowlite_set_input(void *tflite_ctx, graph_execution_context ctx, return success; } -wasi_nn_error -tensorflowlite_compute(void *tflite_ctx, graph_execution_context ctx) +__attribute__((visibility("default"))) wasi_nn_error +compute(void *tflite_ctx, graph_execution_context ctx) { TFLiteContext *tfl_ctx = (TFLiteContext *)tflite_ctx; @@ -365,10 +363,9 @@ tensorflowlite_compute(void *tflite_ctx, graph_execution_context ctx) return success; } -wasi_nn_error -tensorflowlite_get_output(void *tflite_ctx, graph_execution_context ctx, - uint32_t index, tensor_data output_tensor, - uint32_t *output_tensor_size) +__attribute__((visibility("default"))) wasi_nn_error +get_output(void *tflite_ctx, graph_execution_context ctx, uint32_t index, + tensor_data output_tensor, uint32_t *output_tensor_size) { TFLiteContext *tfl_ctx = (TFLiteContext *)tflite_ctx; @@ -434,8 +431,8 @@ tensorflowlite_get_output(void *tflite_ctx, graph_execution_context ctx, return success; } -wasi_nn_error -tensorflowlite_initialize(void **tflite_ctx) +__attribute__((visibility("default"))) wasi_nn_error +init_backend(void **tflite_ctx) { TFLiteContext *tfl_ctx = new TFLiteContext(); if (tfl_ctx == NULL) { @@ -461,8 +458,8 @@ tensorflowlite_initialize(void **tflite_ctx) return success; } -wasi_nn_error -tensorflowlite_destroy(void *tflite_ctx) +__attribute__((visibility("default"))) wasi_nn_error +deinit_backend(void *tflite_ctx) { /* TensorFlow Lite memory is internally managed by tensorflow @@ -513,19 +510,3 @@ tensorflowlite_destroy(void *tflite_ctx) NN_DBG_PRINTF("Memory free'd."); return success; } - -__attribute__((constructor(200))) void -tflite_register_backend() -{ - api_function apis = { - .load = tensorflowlite_load, - .load_by_name = tensorflowlite_load_by_name, - .init_execution_context = tensorflowlite_init_execution_context, - .set_input = tensorflowlite_set_input, - .compute = tensorflowlite_compute, - .get_output = tensorflowlite_get_output, - .init = tensorflowlite_initialize, - .deinit = tensorflowlite_destroy, - }; - wasi_nn_register_backend(apis); -} \ No newline at end of file diff --git a/core/iwasm/libraries/wasi-nn/src/wasi_nn_tensorflowlite.hpp b/core/iwasm/libraries/wasi-nn/src/wasi_nn_tensorflowlite.hpp index 630e741c0..d6e04ab0e 100644 --- a/core/iwasm/libraries/wasi-nn/src/wasi_nn_tensorflowlite.hpp +++ b/core/iwasm/libraries/wasi-nn/src/wasi_nn_tensorflowlite.hpp @@ -12,31 +12,33 @@ extern "C" { #endif -wasi_nn_error -tensorflowlite_load(void *tflite_ctx, graph_builder_array *builder, - graph_encoding encoding, execution_target target, graph *g); +__attribute__((visibility("default"))) wasi_nn_error +load(void *tflite_ctx, graph_builder_array *builder, graph_encoding encoding, + execution_target target, graph *g); -wasi_nn_error -tensorflowlite_init_execution_context(void *tflite_ctx, graph g, - graph_execution_context *ctx); +__attribute__((visibility("default"))) wasi_nn_error +load_by_name(void *tflite_ctx, const char *filename, uint32_t filename_len, + graph *g); -wasi_nn_error -tensorflowlite_set_input(void *tflite_ctx, graph_execution_context ctx, - uint32_t index, tensor *input_tensor); +__attribute__((visibility("default"))) wasi_nn_error +init_execution_context(void *tflite_ctx, graph g, graph_execution_context *ctx); -wasi_nn_error -tensorflowlite_compute(void *tflite_ctx, graph_execution_context ctx); +__attribute__((visibility("default"))) wasi_nn_error +set_input(void *tflite_ctx, graph_execution_context ctx, uint32_t index, + tensor *input_tensor); -wasi_nn_error -tensorflowlite_get_output(void *tflite_ctx, graph_execution_context ctx, - uint32_t index, tensor_data output_tensor, - uint32_t *output_tensor_size); +__attribute__((visibility("default"))) wasi_nn_error +compute(void *tflite_ctx, graph_execution_context ctx); -wasi_nn_error -tensorflowlite_initialize(void **tflite_ctx); +__attribute__((visibility("default"))) wasi_nn_error +get_output(void *tflite_ctx, graph_execution_context ctx, uint32_t index, + tensor_data output_tensor, uint32_t *output_tensor_size); -wasi_nn_error -tensorflowlite_destroy(void *tflite_ctx); +__attribute__((visibility("default"))) wasi_nn_error +init_backend(void **tflite_ctx); + +__attribute__((visibility("default"))) wasi_nn_error +deinit_backend(void *tflite_ctx); #ifdef __cplusplus } diff --git a/core/iwasm/libraries/wasi-nn/test/Dockerfile.wasi-nn-smoke b/core/iwasm/libraries/wasi-nn/test/Dockerfile.wasi-nn-smoke index 4378ac395..261c77261 100644 --- a/core/iwasm/libraries/wasi-nn/test/Dockerfile.wasi-nn-smoke +++ b/core/iwasm/libraries/wasi-nn/test/Dockerfile.wasi-nn-smoke @@ -78,23 +78,22 @@ RUN cd openvino-mobilenet-raw \ && ./download_mobilenet.sh . \ && ls -l mobilenet.xml mobilenet.bin tensor-1x224x224x3-f32.bgr -# RUN apt update \ -# && apt install -y valgrind - # # iwasm. build from source WORKDIR /workspaces/wamr COPY . . WORKDIR /workspaces/wamr/product-mini/platforms/linux + RUN OpenVINO_DIR=/usr/lib/openvino-2023.2.0 \ cmake -S . -B build \ -DWAMR_BUILD_WASI_NN=1 -DWAMR_BUILD_WASI_EPHEMERAL_NN=1 \ -DWAMR_BUILD_WASI_NN_OPENVINO=1 -DWAMR_BUILD_WASI_NN_TFLITE=1 \ && cmake --build build -RUN ln -sf "$(realpath ./build/iwasm)" /usr/local/bin/iwasm -# +ENV PATH=/workspaces/wamr/product-mini/platforms/linux/build:${PATH} +ENV LD_LIBRARY_PATH=/workspaces/wamr/product-mini/platforms/linux/build + # add smoke test script COPY core/iwasm/libraries/wasi-nn/test/run_smoke_test.py / diff --git a/core/iwasm/libraries/wasi-nn/test/run_smoke_test.py b/core/iwasm/libraries/wasi-nn/test/run_smoke_test.py index 08b19624a..a62d9cb7a 100644 --- a/core/iwasm/libraries/wasi-nn/test/run_smoke_test.py +++ b/core/iwasm/libraries/wasi-nn/test/run_smoke_test.py @@ -163,7 +163,6 @@ def execute_tflite_birds_v1_image(iwasm_bin: str, wasmedge_bin: str, cwd: Path): iwasm_output = execute_tflite_birds_v1_image_once( iwasm_bin, [ - "--native-lib=/workspaces/wamr/product-mini/platforms/linux/build/libwasi-nn-tflite.so", "--map-dir=.:.", ], cwd, @@ -182,7 +181,6 @@ def execute_openvino_mobilenet_image(iwasm_bin: str, wasmedge_bin: str, cwd: Pat iwasm_output = execute_openvino_mobilenet_image_once( iwasm_bin, [ - "--native-lib=/workspaces/wamr/product-mini/platforms/linux/build/libwasi-nn-openvino.so", "--map-dir=.:.", ], cwd, @@ -201,7 +199,6 @@ def execute_openvino_mobilenet_raw(iwasm_bin: str, wasmedge_bin: str, cwd: Path) iwasm_output = execute_openvino_mobilenet_raw_once( iwasm_bin, [ - "--native-lib=/workspaces/wamr/product-mini/platforms/linux/build/libwasi-nn-openvino.so", "--map-dir=.:.", ], cwd, @@ -239,7 +236,6 @@ def execute_openvino_road_segmentation_adas( iwasm_output = execute_openvino_road_segmentation_adas_once( iwasm_bin, [ - "--native-lib=/workspaces/wamr/product-mini/platforms/linux/build/libwasi-nn-openvino.so", "--map-dir=.:.", ], cwd, diff --git a/core/shared/mem-alloc/ems/ems_gc.h b/core/shared/mem-alloc/ems/ems_gc.h index 59cc00285..ff65b4e7c 100644 --- a/core/shared/mem-alloc/ems/ems_gc.h +++ b/core/shared/mem-alloc/ems/ems_gc.h @@ -309,10 +309,10 @@ void wasm_runtime_set_wasm_object_extra_info_flag(gc_object_t obj, bool set); void -wasm_runtime_gc_prepare(); +wasm_runtime_gc_prepare(void *exec_env); void -wasm_runtime_gc_finalize(); +wasm_runtime_gc_finalize(void *exec_env); #endif /* end of WASM_ENABLE_GC != 0 */ #define GC_HEAP_STAT_SIZE (128 / 4) diff --git a/core/shared/platform/common/posix/posix_file.c b/core/shared/platform/common/posix/posix_file.c index e3aec9f4b..9ae0a03a2 100644 --- a/core/shared/platform/common/posix/posix_file.c +++ b/core/shared/platform/common/posix/posix_file.c @@ -54,6 +54,18 @@ #define CONFIG_HAS_O_SYNC #endif +#ifndef STDIN_FILENO +#define STDIN_FILENO 0 +#endif + +#ifndef STDOUT_FILENO +#define STDOUT_FILENO 1 +#endif + +#ifndef STDERR_FILENO +#define STDERR_FILENO 2 +#endif + // Converts a POSIX timespec to a WASI timestamp. static __wasi_timestamp_t convert_timespec(const struct timespec *ts) @@ -858,30 +870,39 @@ os_isatty(os_file_handle handle) #endif } +bool +os_is_stdin_handle(os_file_handle fd) +{ + return fd == STDIN_FILENO; +} + +bool +os_is_stdout_handle(os_file_handle fd) +{ + return fd == STDOUT_FILENO; +} + +bool +os_is_stderr_handle(os_file_handle fd) +{ + return fd == STDERR_FILENO; +} + os_file_handle os_convert_stdin_handle(os_raw_file_handle raw_stdin) { -#ifndef STDIN_FILENO -#define STDIN_FILENO 0 -#endif return raw_stdin >= 0 ? raw_stdin : STDIN_FILENO; } os_file_handle os_convert_stdout_handle(os_raw_file_handle raw_stdout) { -#ifndef STDOUT_FILENO -#define STDOUT_FILENO 1 -#endif return raw_stdout >= 0 ? raw_stdout : STDOUT_FILENO; } os_file_handle os_convert_stderr_handle(os_raw_file_handle raw_stderr) { -#ifndef STDERR_FILENO -#define STDERR_FILENO 2 -#endif return raw_stderr >= 0 ? raw_stderr : STDERR_FILENO; } diff --git a/core/shared/platform/common/posix/posix_thread.c b/core/shared/platform/common/posix/posix_thread.c index d35a7773c..5ec957e52 100644 --- a/core/shared/platform/common/posix/posix_thread.c +++ b/core/shared/platform/common/posix/posix_thread.c @@ -504,6 +504,8 @@ static os_thread_local_attribute bool thread_signal_inited = false; #if WASM_DISABLE_STACK_HW_BOUND_CHECK == 0 /* The signal alternate stack base addr */ static os_thread_local_attribute uint8 *sigalt_stack_base_addr; +/* The previous signal alternate stack */ +static os_thread_local_attribute stack_t prev_sigalt_stack; /* * ASAN is not designed to work with custom stack unwind or other low-level @@ -683,7 +685,9 @@ os_thread_signal_init(os_signal_handler handler) sigalt_stack_info.ss_sp = map_addr; sigalt_stack_info.ss_size = map_size; sigalt_stack_info.ss_flags = 0; - if (sigaltstack(&sigalt_stack_info, NULL) != 0) { + memset(&prev_sigalt_stack, 0, sizeof(stack_t)); + /* Set signal alternate stack and save the previous one */ + if (sigaltstack(&sigalt_stack_info, &prev_sigalt_stack) != 0) { os_printf("Failed to init signal alternate stack\n"); goto fail2; } @@ -729,19 +733,12 @@ fail1: void os_thread_signal_destroy() { -#if WASM_DISABLE_STACK_HW_BOUND_CHECK == 0 - stack_t sigalt_stack_info; -#endif - if (!thread_signal_inited) return; #if WASM_DISABLE_STACK_HW_BOUND_CHECK == 0 - /* Disable signal alternate stack */ - memset(&sigalt_stack_info, 0, sizeof(stack_t)); - sigalt_stack_info.ss_flags = SS_DISABLE; - sigalt_stack_info.ss_size = SIG_ALT_STACK_SIZE; - sigaltstack(&sigalt_stack_info, NULL); + /* Restore the previous signal alternate stack */ + sigaltstack(&prev_sigalt_stack, NULL); os_munmap(sigalt_stack_base_addr, SIG_ALT_STACK_SIZE); diff --git a/core/shared/platform/esp-idf/espidf_file.c b/core/shared/platform/esp-idf/espidf_file.c index ac7e58537..be50a2900 100644 --- a/core/shared/platform/esp-idf/espidf_file.c +++ b/core/shared/platform/esp-idf/espidf_file.c @@ -54,6 +54,18 @@ #define CONFIG_HAS_O_SYNC #endif +#ifndef STDIN_FILENO +#define STDIN_FILENO 0 +#endif + +#ifndef STDOUT_FILENO +#define STDOUT_FILENO 1 +#endif + +#ifndef STDERR_FILENO +#define STDERR_FILENO 2 +#endif + // Converts a POSIX timespec to a WASI timestamp. static __wasi_timestamp_t convert_timespec(const struct timespec *ts) @@ -858,30 +870,39 @@ os_isatty(os_file_handle handle) #endif } +bool +os_is_stdin_handle(os_file_handle fd) +{ + return fd == STDIN_FILENO; +} + +bool +os_is_stdout_handle(os_file_handle fd) +{ + return fd == STDOUT_FILENO; +} + +bool +os_is_stderr_handle(os_file_handle fd) +{ + return fd == STDERR_FILENO; +} + os_file_handle os_convert_stdin_handle(os_raw_file_handle raw_stdin) { -#ifndef STDIN_FILENO -#define STDIN_FILENO 0 -#endif return raw_stdin >= 0 ? raw_stdin : STDIN_FILENO; } os_file_handle os_convert_stdout_handle(os_raw_file_handle raw_stdout) { -#ifndef STDOUT_FILENO -#define STDOUT_FILENO 1 -#endif return raw_stdout >= 0 ? raw_stdout : STDOUT_FILENO; } os_file_handle os_convert_stderr_handle(os_raw_file_handle raw_stderr) { -#ifndef STDERR_FILENO -#define STDERR_FILENO 2 -#endif return raw_stderr >= 0 ? raw_stderr : STDERR_FILENO; } diff --git a/core/shared/platform/include/platform_api_extension.h b/core/shared/platform/include/platform_api_extension.h index 7c6120ba2..b1c3b4f4a 100644 --- a/core/shared/platform/include/platform_api_extension.h +++ b/core/shared/platform/include/platform_api_extension.h @@ -104,8 +104,9 @@ os_thread_exit(void *retval); #endif /* Clang's __GNUC_PREREQ macro has a different meaning than GCC one, - so we have to handle this case specially */ -#if defined(__clang__) + so we have to handle this case specially(except the CCAC compiler + provided by MetaWare, which doesn't support atomic operations) */ +#if defined(__clang__) && !defined(__CCAC__) /* 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) @@ -1502,6 +1503,33 @@ os_convert_stdout_handle(os_raw_file_handle raw_stdout); os_file_handle os_convert_stderr_handle(os_raw_file_handle raw_stderr); +/** + * + * @param fd a file handle + * + * @return true if it is stdin + */ +bool +os_is_stdin_handle(os_file_handle fd); + +/** + * + * @param fd a file handle + * + * @return true if it is stdout + */ +bool +os_is_stdout_handle(os_file_handle fd); + +/** + * + * @param fd a file handle + * + * @return true if it is stderr + */ +bool +os_is_stderr_handle(os_file_handle fd); + /** * Open a directory stream for the provided directory handle. The returned * directory stream will be positioned at the first entry in the directory. diff --git a/core/shared/platform/windows/win_file.c b/core/shared/platform/windows/win_file.c index 63dfb5b5f..408d0d00c 100644 --- a/core/shared/platform/windows/win_file.c +++ b/core/shared/platform/windows/win_file.c @@ -1540,6 +1540,24 @@ create_stdio_handle(HANDLE raw_stdio_handle, DWORD stdio) return stdio_handle; } +bool +os_is_stdin_handle(os_file_handle fd) +{ + return fd->raw.handle == GetStdHandle(STD_INPUT_HANDLE); +} + +bool +os_is_stdout_handle(os_file_handle fd) +{ + return fd->raw.handle == GetStdHandle(STD_OUTPUT_HANDLE); +} + +bool +os_is_stderr_handle(os_file_handle fd) +{ + return fd->raw.handle == GetStdHandle(STD_ERROR_HANDLE); +} + os_file_handle os_convert_stdin_handle(os_raw_file_handle raw_stdin) { diff --git a/core/shared/utils/bh_atomic.h b/core/shared/utils/bh_atomic.h index 4f7d9bc83..5148497f8 100644 --- a/core/shared/utils/bh_atomic.h +++ b/core/shared/utils/bh_atomic.h @@ -6,6 +6,7 @@ #ifndef _BH_ATOMIC_H #define _BH_ATOMIC_H +#include "bh_platform.h" #include "gnuc.h" #ifdef __cplusplus diff --git a/core/shared/utils/bh_leb128.c b/core/shared/utils/bh_leb128.c new file mode 100644 index 000000000..8e4b13dce --- /dev/null +++ b/core/shared/utils/bh_leb128.c @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "bh_leb128.h" + +bh_leb_read_status_t +bh_leb_read(const uint8 *buf, const uint8 *buf_end, uint32 maxbits, bool sign, + uint64 *p_result, size_t *p_offset) +{ + uint64 result = 0; + uint32 shift = 0; + uint32 offset = 0, bcnt = 0; + uint64 byte; + + while (true) { + /* uN or SN must not exceed ceil(N/7) bytes */ + if (bcnt + 1 > (maxbits + 6) / 7) { + return BH_LEB_READ_TOO_LONG; + } + + if ((uintptr_t)buf + offset + 1 < (uintptr_t)buf + || (uintptr_t)buf + offset + 1 > (uintptr_t)buf_end) { + return BH_LEB_READ_UNEXPECTED_END; + } + byte = buf[offset]; + offset += 1; + result |= ((byte & 0x7f) << shift); + shift += 7; + bcnt += 1; + if ((byte & 0x80) == 0) { + break; + } + } + + if (!sign && maxbits == 32 && shift >= maxbits) { + /* The top bits set represent values > 32 bits */ + if (((uint8)byte) & 0xf0) + return BH_LEB_READ_OVERFLOW; + } + else if (sign && maxbits == 32) { + if (shift < maxbits) { + /* Sign extend, second-highest bit is the sign bit */ + if ((uint8)byte & 0x40) + result |= (~((uint64)0)) << shift; + } + else { + /* The top bits should be a sign-extension of the sign bit */ + bool sign_bit_set = ((uint8)byte) & 0x8; + int top_bits = ((uint8)byte) & 0xf0; + if ((sign_bit_set && top_bits != 0x70) + || (!sign_bit_set && top_bits != 0)) + return BH_LEB_READ_OVERFLOW; + } + } + else if (sign && maxbits == 64) { + if (shift < maxbits) { + /* Sign extend, second-highest bit is the sign bit */ + if ((uint8)byte & 0x40) + result |= (~((uint64)0)) << shift; + } + else { + /* The top bits should be a sign-extension of the sign bit */ + bool sign_bit_set = ((uint8)byte) & 0x1; + int top_bits = ((uint8)byte) & 0xfe; + + if ((sign_bit_set && top_bits != 0x7e) + || (!sign_bit_set && top_bits != 0)) + return BH_LEB_READ_OVERFLOW; + } + } + + *p_offset = offset; + *p_result = result; + return BH_LEB_READ_SUCCESS; +} \ No newline at end of file diff --git a/core/shared/utils/bh_leb128.h b/core/shared/utils/bh_leb128.h new file mode 100644 index 000000000..ce73b4b88 --- /dev/null +++ b/core/shared/utils/bh_leb128.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _BH_LEB128_H +#define _BH_LEB128_H + +#include "bh_platform.h" + +typedef enum { + BH_LEB_READ_SUCCESS, + BH_LEB_READ_TOO_LONG, + BH_LEB_READ_OVERFLOW, + BH_LEB_READ_UNEXPECTED_END, +} bh_leb_read_status_t; + +#ifdef __cplusplus +extern "C" { +#endif + +bh_leb_read_status_t +bh_leb_read(const uint8 *buf, const uint8 *buf_end, uint32 maxbits, bool sign, + uint64 *p_result, size_t *p_offset); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/core/version.h b/core/version.h index a1626f83c..4e2cbaefc 100644 --- a/core/version.h +++ b/core/version.h @@ -7,5 +7,5 @@ #define _WAMR_VERSION_H_ #define WAMR_VERSION_MAJOR 2 #define WAMR_VERSION_MINOR 1 -#define WAMR_VERSION_PATCH 1 +#define WAMR_VERSION_PATCH 2 #endif diff --git a/doc/build_wamr.md b/doc/build_wamr.md index 181f32ca0..2adb17f6a 100644 --- a/doc/build_wamr.md +++ b/doc/build_wamr.md @@ -28,7 +28,7 @@ The script `runtime_lib.cmake` defines a number of variables for configuring the - For ARM and THUMB, the format is \\[\]\[_VFP], where \ is the ARM sub-architecture and the "_VFP" suffix means using VFP coprocessor registers s0-s15 (d0-d7) for passing arguments or returning results in standard procedure-call. Both \ and "_VFP" are optional, e.g. ARMV7, ARMV7_VFP, THUMBV7, THUMBV7_VFP and so on. - For AARCH64, the format is\[\], VFP is enabled by default. \ is optional, e.g. AARCH64, AARCH64V8, AARCH64V8.1 and so on. - For RISCV64, the format is \[_abi], where "_abi" is optional, currently the supported formats are RISCV64, RISCV64_LP64D and RISCV64_LP64: RISCV64 and RISCV64_LP64D are identical, using [LP64D](https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-cc.adoc#named-abis) as abi (LP64 with hardware floating-point calling convention for FLEN=64). And RISCV64_LP64 uses [LP64](https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-cc.adoc#named-abis) as abi (Integer calling-convention only, and hardware floating-point calling convention is not used). - - For RISCV32, the format is \[_abi], where "_abi" is optional, currently the supported formats are RISCV32, RISCV32_ILP32D and RISCV32_ILP32: RISCV32 and RISCV32_ILP32D are identical, using [ILP32D](https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-cc.adoc#named-abis) as abi (ILP32 with hardware floating-point calling convention for FLEN=64). And RISCV32_ILP32 uses [ILP32](https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-cc.adoc#named-abis) as abi (Integer calling-convention only, and hardware floating-point calling convention is not used). + - For RISCV32, the format is \[_abi], where "_abi" is optional, currently the supported formats are RISCV32, RISCV32_ILP32D, RISCV32_ILP32F and RISCV32_ILP32: RISCV32 and RISCV32_ILP32D are identical, using [ILP32D](https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-cc.adoc#named-abis) as abi (ILP32 with hardware floating-point calling convention for FLEN=64). RISCV32_ILP32F uses [ILP32F](https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-cc.adoc#named-abis) as abi (ILP32 with hardware floating-point calling convention for FLEN=32). And RISCV32_ILP32 uses [ILP32](https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-cc.adoc#named-abis) as abi (Integer calling-convention only, and hardware floating-point calling convention is not used). ```bash cmake -DWAMR_BUILD_PLATFORM=linux -DWAMR_BUILD_TARGET=ARM diff --git a/product-mini/platforms/alios-things/aos.mk b/product-mini/platforms/alios-things/aos.mk index 947a4a91a..7d98ca0b8 100644 --- a/product-mini/platforms/alios-things/aos.mk +++ b/product-mini/platforms/alios-things/aos.mk @@ -102,6 +102,7 @@ $(NAME)_SOURCES := ${SHARED_ROOT}/platform/alios/alios_platform.c \ ${SHARED_ROOT}/utils/bh_common.c \ ${SHARED_ROOT}/utils/bh_hashmap.c \ ${SHARED_ROOT}/utils/bh_list.c \ + ${SHARED_ROOT}/utils/bh_leb128.c \ ${SHARED_ROOT}/utils/bh_log.c \ ${SHARED_ROOT}/utils/bh_queue.c \ ${SHARED_ROOT}/utils/bh_vector.c \ diff --git a/product-mini/platforms/nuttx/CMakeLists.txt b/product-mini/platforms/nuttx/CMakeLists.txt index e9fe5a9e3..ac6c47b91 100644 --- a/product-mini/platforms/nuttx/CMakeLists.txt +++ b/product-mini/platforms/nuttx/CMakeLists.txt @@ -18,9 +18,9 @@ elseif(CONFIG_ARCH_X86_64) set(WAMR_BUILD_TARGET X86_64) elseif(CONFIG_ARCH_XTENSA) set(WAMR_BUILD_TARGET XTENSA) -elseif(CONFIG_ARCH_RV64GC OR CONFIG_ARCH_RV64) +elseif(CONFIG_ARCH_RV64) set(WAMR_BUILD_TARGET RISCV64) -elseif(CONFIG_ARCH_RV32IM OR CONFIG_ARCH_RV32) +elseif(CONFIG_ARCH_RV32) set(WAMR_BUILD_TARGET RISCV32) elseif(CONFIG_ARCH_SIM) if(CONFIG_SIM_M32 OR CONFIG_HOST_X86) diff --git a/product-mini/platforms/nuttx/wamr.mk b/product-mini/platforms/nuttx/wamr.mk index 75bd69bef..38553e863 100644 --- a/product-mini/platforms/nuttx/wamr.mk +++ b/product-mini/platforms/nuttx/wamr.mk @@ -21,12 +21,6 @@ else ifeq ($(CONFIG_ARCH_X86_64),y) WAMR_BUILD_TARGET := X86_64 else ifeq ($(CONFIG_ARCH_XTENSA),y) WAMR_BUILD_TARGET := XTENSA -# RV64GC and RV32IM used in older -# version NuttX -else ifeq ($(CONFIG_ARCH_RV64GC),y) -WAMR_BUILD_TARGET := RISCV64 -else ifeq ($(CONFIG_ARCH_RV32IM),y) -WAMR_BUILD_TARGET := RISCV32 else ifeq ($(CONFIG_ARCH_RV64),y) WAMR_BUILD_TARGET := RISCV64 else ifeq ($(CONFIG_ARCH_RV32),y) @@ -107,10 +101,10 @@ else ifeq (${WAMR_BUILD_TARGET}, RISCV32) ifeq (${CONFIG_ARCH_DPFPU},y) CFLAGS += -DBUILD_TARGET_RISCV32_ILP32D -else ifneq (${CONFIG_ARCH_FPU},y) - CFLAGS += -DBUILD_TARGET_RISCV32_ILP32 +else ifeq (${CONFIG_ARCH_FPU},y) + CFLAGS += -DBUILD_TARGET_RISCV32_ILP32F else - $(error riscv32 ilp32f is unsupported) + CFLAGS += -DBUILD_TARGET_RISCV32_ILP32 endif INVOKE_NATIVE += invokeNative_riscv.S @@ -441,6 +435,7 @@ CSRCS += nuttx_platform.c \ bh_common.c \ bh_hashmap.c \ bh_list.c \ + bh_leb128.c \ bh_log.c \ bh_queue.c \ bh_vector.c \ diff --git a/tests/unit/shared-utils/bh_leb128_test.cc b/tests/unit/shared-utils/bh_leb128_test.cc new file mode 100644 index 000000000..f53864646 --- /dev/null +++ b/tests/unit/shared-utils/bh_leb128_test.cc @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "bh_leb128.h" +#include "gtest/gtest.h" + +#include +#include + +template +void +run_read_leb_test(std::vector data, + bh_leb_read_status_t expected_status, T expected_value) +{ + size_t offset = 0; + uint64 value; + bh_leb_read_status_t status = + bh_leb_read(data.data(), data.data() + data.size(), sizeof(T) * 8, + std::is_signed::value, &value, &offset); + ASSERT_EQ(expected_status, status); + if (status == BH_LEB_READ_SUCCESS) { + ASSERT_EQ(data.size(), offset); + ASSERT_EQ(expected_value, (T)value); + } +} + +TEST(bh_leb128_test_suite, read_leb_u32) +{ + run_read_leb_test({ 0 }, BH_LEB_READ_SUCCESS, + 0); // min value + run_read_leb_test({ 2 }, BH_LEB_READ_SUCCESS, + 2); // single-byte value + run_read_leb_test({ 127 }, BH_LEB_READ_SUCCESS, + 127); // max single-byte value + run_read_leb_test({ 128, 1 }, BH_LEB_READ_SUCCESS, + 128); // min value with continuation bit + run_read_leb_test({ 160, 138, 32 }, BH_LEB_READ_SUCCESS, + 525600); // arbitrary value + run_read_leb_test({ 255, 255, 255, 255, 15 }, BH_LEB_READ_SUCCESS, + UINT32_MAX); // max value + run_read_leb_test({ 255, 255, 255, 255, 16 }, BH_LEB_READ_OVERFLOW, + UINT32_MAX); // overflow + run_read_leb_test({ 255, 255, 255, 255, 128 }, BH_LEB_READ_TOO_LONG, + 0); + run_read_leb_test({ 128 }, BH_LEB_READ_UNEXPECTED_END, 0); +} + +TEST(bh_leb128_test_suite, read_leb_i64) +{ + run_read_leb_test({ 184, 188, 195, 159, 237, 209, 128, 2 }, + BH_LEB_READ_SUCCESS, + 1128712371232312); // arbitrary value + run_read_leb_test( + { 128, 128, 128, 128, 128, 128, 128, 128, 128, 127 }, + BH_LEB_READ_SUCCESS, + (uint64)INT64_MIN); // min value + run_read_leb_test({ 255, 255, 255, 255, 255, 255, 255, 255, 255, 0 }, + BH_LEB_READ_SUCCESS, + INT64_MAX); // max value +} \ No newline at end of file diff --git a/tests/wamr-test-suites/spec-test-script/all.py b/tests/wamr-test-suites/spec-test-script/all.py index 1d4ed1b21..fcc5ff154 100644 --- a/tests/wamr-test-suites/spec-test-script/all.py +++ b/tests/wamr-test-suites/spec-test-script/all.py @@ -572,7 +572,8 @@ def main(): if options.parl_flag: # several cases might share the same workspace/tempfile at the same time # so, disable it while running parallelly - options.clean_up_flag = False + if options.multi_module_flag: + options.clean_up_flag = False options.verbose_flag = False start = time.time_ns() diff --git a/tests/wamr-test-suites/spec-test-script/runtest.py b/tests/wamr-test-suites/spec-test-script/runtest.py index d4bdaf273..291718b6e 100755 --- a/tests/wamr-test-suites/spec-test-script/runtest.py +++ b/tests/wamr-test-suites/spec-test-script/runtest.py @@ -62,6 +62,13 @@ aot_target_options_map = { "xtensa": ["--target=xtensa"], } +# AOT compilation options mapping for XIP mode +aot_target_options_map_xip = { + # avoid l32r relocations for xtensa + "xtensa": ["--mllvm=-mtext-section-literals"], + "riscv32_ilp32f": ["--enable-builtin-intrinsics=i64.common,f64.common,f32.const,f64.const,f64xi32,f64xi64,f64_promote_f32,f32_demote_f64"], +} + def debug(data): if debug_file: debug_file.write(data) @@ -1122,10 +1129,8 @@ def compile_wasm_to_aot(wasm_tempfile, aot_tempfile, runner, opts, r, output = ' if opts.xip: cmd.append("--xip") - - # avoid l32r relocations for xtensa - if opts.target == "xtensa": - cmd.append("--mllvm=-mtext-section-literals") + if test_target in aot_target_options_map_xip: + cmd += aot_target_options_map_xip[test_target] if opts.multi_thread: cmd.append("--enable-multi-thread") @@ -1307,6 +1312,12 @@ if __name__ == "__main__": wasm_tempfile = create_tmp_file(".wasm") if test_aot: aot_tempfile = create_tmp_file(".aot") + # could be potientially compiled to aot + # with the future following call test_assert_xxx, + # add them to temp_file_repo now even if no actual following file, + # it will be simple ignore during final deletion if not exist + prefix = wasm_tempfile.split(".wasm")[0] + temp_file_repo.append(prefix + ".aot") ret_code = 0 try: @@ -1429,6 +1440,12 @@ if __name__ == "__main__": if test_aot: r = compile_wasm_to_aot(temp_files[1], temp_files[2], True, opts, r) + # could be potientially compiled to aot + # with the future following call test_assert_xxx, + # add them to temp_file_repo now even if no actual following file, + # it will be simple ignore during final deletion if not exist + prefix = temp_files[1].split(".wasm")[0] + temp_file_repo.append(prefix + ".aot") try: assert_prompt(r, ['Compile success'], opts.start_timeout, False) except: diff --git a/tests/wamr-test-suites/test_wamr.sh b/tests/wamr-test-suites/test_wamr.sh index ee0dd7bbc..54e2ac1a7 100755 --- a/tests/wamr-test-suites/test_wamr.sh +++ b/tests/wamr-test-suites/test_wamr.sh @@ -409,12 +409,13 @@ function setup_wabt() git clone --recursive https://github.com/WebAssembly/wabt fi echo "upate wabt" - cd wabt - git fetch origin - git reset --hard origin/main - git checkout tags/${WABT_VERSION} -B ${WABT_VERSION} - cd .. - make -C wabt gcc-release -j 4 || exit 1 + cd wabt \ + && git fetch origin \ + && git reset --hard origin/main \ + && git checkout tags/${WABT_VERSION} -B ${WABT_VERSION} \ + && git submodule update --init \ + && cd .. \ + && make -C wabt gcc-release -j 4 || exit 1 fi } diff --git a/wamr-compiler/CMakeLists.txt b/wamr-compiler/CMakeLists.txt index 245b4a031..2ab0462b2 100644 --- a/wamr-compiler/CMakeLists.txt +++ b/wamr-compiler/CMakeLists.txt @@ -121,6 +121,8 @@ elseif (WAMR_BUILD_TARGET STREQUAL "RISCV64_LP64") add_definitions(-DBUILD_TARGET_RISCV64_LP64) elseif (WAMR_BUILD_TARGET STREQUAL "RISCV32" OR WAMR_BUILD_TARGET STREQUAL "RISCV32_ILP32D") add_definitions(-DBUILD_TARGET_RISCV32_ILP32D) +elseif (WAMR_BUILD_TARGET STREQUAL "RISCV32_ILP32F") + add_definitions(-DBUILD_TARGET_RISCV32_ILP32F) elseif (WAMR_BUILD_TARGET STREQUAL "RISCV32_ILP32") add_definitions(-DBUILD_TARGET_RISCV32_ILP32) else ()