Просмотр исходного кода

Merge pull request #3739 from bytecodealliance/main

Merge branch main into dev/merge_aot_data_text
Wenyong Huang 1 год назад
Родитель
Сommit
9423fee046
53 измененных файлов с 1231 добавлено и 641 удалено
  1. 3 3
      .github/workflows/build_wamr_vscode_ext.yml
  2. 24 19
      .github/workflows/compilation_on_nuttx.yml
  3. 5 0
      .github/workflows/spec_test_on_nuttx.yml
  4. 1 1
      ATTRIBUTIONS.md
  5. 74 0
      RELEASE_NOTES.md
  6. 6 3
      build-scripts/config_common.cmake
  7. 6 1
      core/config.h
  8. 2 0
      core/iwasm/aot/arch/aot_reloc_riscv.c
  9. 42 11
      core/iwasm/common/wasm_loader_common.c
  10. 8 0
      core/iwasm/common/wasm_loader_common.h
  11. 42 15
      core/iwasm/common/wasm_native.c
  12. 78 23
      core/iwasm/common/wasm_runtime_common.c
  13. 28 32
      core/iwasm/compilation/aot_emit_const.c
  14. 22 2
      core/iwasm/compilation/aot_llvm.c
  15. 6 0
      core/iwasm/compilation/aot_llvm_extra.cpp
  16. 63 23
      core/iwasm/interpreter/wasm_interp_classic.c
  17. 14 83
      core/iwasm/interpreter/wasm_loader.c
  18. 5 69
      core/iwasm/interpreter/wasm_mini_loader.c
  19. 5 2
      core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c
  20. 20 1
      core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c
  21. 13 0
      core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/rights.h
  22. 3 3
      core/iwasm/libraries/thread-mgr/thread_manager.h
  23. 15 10
      core/iwasm/libraries/wasi-nn/cmake/Findtensorflow_lite.cmake
  24. 16 29
      core/iwasm/libraries/wasi-nn/cmake/wasi_nn.cmake
  25. 20 0
      core/iwasm/libraries/wasi-nn/include/wasi_nn_host.h
  26. 1 3
      core/iwasm/libraries/wasi-nn/include/wasi_nn_types.h
  27. 282 119
      core/iwasm/libraries/wasi-nn/src/wasi_nn.c
  28. 35 45
      core/iwasm/libraries/wasi-nn/src/wasi_nn_openvino.c
  29. 17 18
      core/iwasm/libraries/wasi-nn/src/wasi_nn_openvino.h
  30. 1 2
      core/iwasm/libraries/wasi-nn/src/wasi_nn_private.h
  31. 21 40
      core/iwasm/libraries/wasi-nn/src/wasi_nn_tensorflowlite.cpp
  32. 21 19
      core/iwasm/libraries/wasi-nn/src/wasi_nn_tensorflowlite.hpp
  33. 4 5
      core/iwasm/libraries/wasi-nn/test/Dockerfile.wasi-nn-smoke
  34. 0 4
      core/iwasm/libraries/wasi-nn/test/run_smoke_test.py
  35. 2 2
      core/shared/mem-alloc/ems/ems_gc.h
  36. 30 9
      core/shared/platform/common/posix/posix_file.c
  37. 7 10
      core/shared/platform/common/posix/posix_thread.c
  38. 30 9
      core/shared/platform/esp-idf/espidf_file.c
  39. 30 2
      core/shared/platform/include/platform_api_extension.h
  40. 18 0
      core/shared/platform/windows/win_file.c
  41. 1 0
      core/shared/utils/bh_atomic.h
  42. 77 0
      core/shared/utils/bh_leb128.c
  43. 30 0
      core/shared/utils/bh_leb128.h
  44. 1 1
      core/version.h
  45. 1 1
      doc/build_wamr.md
  46. 1 0
      product-mini/platforms/alios-things/aos.mk
  47. 2 2
      product-mini/platforms/nuttx/CMakeLists.txt
  48. 4 9
      product-mini/platforms/nuttx/wamr.mk
  49. 62 0
      tests/unit/shared-utils/bh_leb128_test.cc
  50. 2 1
      tests/wamr-test-suites/spec-test-script/all.py
  51. 21 4
      tests/wamr-test-suites/spec-test-script/runtest.py
  52. 7 6
      tests/wamr-test-suites/test_wamr.sh
  53. 2 0
      wamr-compiler/CMakeLists.txt

+ 3 - 3
.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

+ 24 - 19
.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

+ 5 - 0
.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",

+ 1 - 1
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.
 

+ 74 - 0
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

+ 6 - 3
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 ()

+ 6 - 1
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

+ 2 - 0
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),

+ 42 - 11
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;
+    }
+}

+ 8 - 0
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

+ 42 - 15
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;

+ 78 - 23
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 (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 (get_package_type(buf, size) == Wasm_Module_Bytecode) {
+    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) */
 

+ 28 - 32
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;

+ 22 - 2
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;
     }

+ 6 - 0
core/iwasm/compilation/aot_llvm_extra.cpp

@@ -41,6 +41,9 @@
 #include <llvm/Target/CodeGenCWrappers.h>
 #include <llvm/Target/TargetMachine.h>
 #include <llvm/Target/TargetOptions.h>
+#if LLVM_VERSION_MAJOR >= 17
+#include <llvm/TargetParser/Triple.h>
+#endif
 #include <llvm/Transforms/Utils/LowerMemIntrinsics.h>
 #include <llvm/Transforms/Vectorize/LoopVectorize.h>
 #include <llvm/Transforms/Vectorize/LoadStoreVectorizer.h>
@@ -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;
     }

+ 63 - 23
core/iwasm/interpreter/wasm_interp_classic.c

@@ -1399,17 +1399,64 @@ 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;                                             \
+        /* 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()
+#endif
+
+#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()                                                   \
-    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;                                         \
+    /* 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) {          \
@@ -1418,25 +1465,8 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst,
             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()
-#endif
-
-#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
+    }                                                                     \
+    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);
 

+ 14 - 83
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);

+ 5 - 69
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

+ 5 - 2
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

+ 20 - 1
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;
 

+ 13 - 0
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                                          \

+ 3 - 3
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 *

+ 15 - 10
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
-  )  
+  )
+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}")
-  set(FLATBUFFER_INCLUDE_DIR "${CMAKE_CURRENT_BINARY_DIR}/flatbuffers/include")
+set(TENSORFLOW_LITE_INCLUDE_DIR "${TENSORFLOW_SOURCE_DIR}/tensorflow/lite")
+set(FLATBUFFER_INCLUDE_DIR "${CMAKE_CURRENT_BINARY_DIR}/flatbuffers/include")
 
-  include_directories(${TENSORFLOW_LITE_INCLUDE_DIR})
-  include_directories(${FLATBUFFER_INCLUDE_DIR})
-endif()
+include_directories(${TENSORFLOW_SOURCE_DIR})
+include_directories(${FLATBUFFER_INCLUDE_DIR})
+link_directories(${CMAKE_CURRENT_BINARY_DIR}/tensorflow-lite)

+ 16 - 29
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
-   $<$<CONFIG:Debug>:NN_LOG_LEVEL=0>
-   $<$<CONFIG:Release>:NN_LOG_LEVEL=2>
+include_directories(${WASI_NN_ROOT}/include)
+add_compile_definitions(
+  $<$<CONFIG:Debug>:NN_LOG_LEVEL=0>
+  $<$<CONFIG:Release>: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()

+ 20 - 0
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 */

+ 1 - 3
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);

+ 282 - 119
core/iwasm/libraries/wasi-nn/src/wasi_nn.c

@@ -10,40 +10,37 @@
 #include <errno.h>
 #include <string.h>
 #include <stdint.h>
+#include <dlfcn.h>
 
 #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 };
-
-#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;                   \
-        }                                                         \
+struct backends_api_functions {
+    void *backend_handle;
+    api_function functions;
+} lookup[autodetect] = { 0 };
+
+#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)
 {
@@ -75,39 +72,38 @@ key_destroy_func(void *key1)
 }
 
 static void
-value_destroy_func(void *value)
-{
-    wasi_nn_ctx_destroy((WASINNContext *)value);
-}
-
-static WASINNContext *
-wasi_nn_initialize_context()
+wasi_nn_ctx_destroy(WASINNContext *wasi_nn_ctx)
 {
-    NN_DBG_PRINTF("[WASI NN] INIT...");
+    NN_DBG_PRINTF("[WASI NN] DEINIT...");
 
-    WASINNContext *wasi_nn_ctx =
-        (WASINNContext *)wasm_runtime_malloc(sizeof(WASINNContext));
     if (wasi_nn_ctx == NULL) {
-        NN_ERR_PRINTF("Error when allocating memory for WASI-NN context");
-        return NULL;
+        NN_ERR_PRINTF(
+            "Error when deallocating memory. WASI-NN context is NULL");
+        return;
     }
-    wasi_nn_ctx->is_model_loaded = false;
+    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);
 
-    /* only one backend can be registered */
+    /* deinit() the backend */
     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;
-    }
+    call_wasi_nn_func(wasi_nn_ctx->backend, deinit, res,
+                      wasi_nn_ctx->backend_ctx);
 
-    return wasi_nn_ctx;
+    wasm_runtime_free(wasi_nn_ctx);
 }
 
-static bool
+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,
@@ -116,9 +112,26 @@ wasi_nn_initialize()
         NN_ERR_PRINTF("Error while initializing hashmap");
         return false;
     }
+
     return true;
 }
 
+static WASINNContext *
+wasi_nn_initialize_context()
+{
+    NN_DBG_PRINTF("[WASI NN] INIT...");
+
+    WASINNContext *wasi_nn_ctx =
+        (WASINNContext *)wasm_runtime_malloc(sizeof(WASINNContext));
+    if (wasi_nn_ctx == NULL) {
+        NN_ERR_PRINTF("Error when allocating memory for WASI-NN context");
+        return NULL;
+    }
+
+    memset(wasi_nn_ctx, 0, sizeof(WASINNContext));
+    return wasi_nn_ctx;
+}
+
 /* 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;
+
+    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->current_encoding = encoding;
+    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;
+
+    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->current_encoding = autodetect;
+    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;
-}

+ 35 - 45
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);
-}

+ 17 - 18
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 */

+ 1 - 2
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;
 

+ 21 - 40
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);
-}

+ 21 - 19
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
 }

+ 4 - 5
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 /
 

+ 0 - 4
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,

+ 2 - 2
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)

+ 30 - 9
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;
 }
 

+ 7 - 10
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);
 

+ 30 - 9
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;
 }
 

+ 30 - 2
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.

+ 18 - 0
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)
 {

+ 1 - 0
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

+ 77 - 0
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;
+}

+ 30 - 0
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

+ 1 - 1
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

+ 1 - 1
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 \<arch>\[\<sub-arch>]\[_VFP], where \<sub-arch> 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 \<sub-arch> and "_VFP" are optional, e.g. ARMV7, ARMV7_VFP, THUMBV7, THUMBV7_VFP and so on.
   - For AARCH64, the format is\<arch>[\<sub-arch>], VFP is enabled by default. \<sub-arch> is optional, e.g. AARCH64, AARCH64V8, AARCH64V8.1 and so on.
   - For RISCV64, the format is \<arch\>[_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 \<arch\>[_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 \<arch\>[_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

+ 1 - 0
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 \

+ 2 - 2
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)

+ 4 - 9
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 \

+ 62 - 0
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 <vector>
+#include <type_traits>
+
+template<typename T>
+void
+run_read_leb_test(std::vector<uint8_t> 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<T>::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<uint32>({ 0 }, BH_LEB_READ_SUCCESS,
+                              0); // min value
+    run_read_leb_test<uint32>({ 2 }, BH_LEB_READ_SUCCESS,
+                              2); // single-byte value
+    run_read_leb_test<uint32>({ 127 }, BH_LEB_READ_SUCCESS,
+                              127); // max single-byte value
+    run_read_leb_test<uint32>({ 128, 1 }, BH_LEB_READ_SUCCESS,
+                              128); // min value with continuation bit
+    run_read_leb_test<uint32>({ 160, 138, 32 }, BH_LEB_READ_SUCCESS,
+                              525600); // arbitrary value
+    run_read_leb_test<uint32>({ 255, 255, 255, 255, 15 }, BH_LEB_READ_SUCCESS,
+                              UINT32_MAX); // max value
+    run_read_leb_test<uint32>({ 255, 255, 255, 255, 16 }, BH_LEB_READ_OVERFLOW,
+                              UINT32_MAX); // overflow
+    run_read_leb_test<uint32>({ 255, 255, 255, 255, 128 }, BH_LEB_READ_TOO_LONG,
+                              0);
+    run_read_leb_test<uint32>({ 128 }, BH_LEB_READ_UNEXPECTED_END, 0);
+}
+
+TEST(bh_leb128_test_suite, read_leb_i64)
+{
+    run_read_leb_test<int64>({ 184, 188, 195, 159, 237, 209, 128, 2 },
+                             BH_LEB_READ_SUCCESS,
+                             1128712371232312); // arbitrary value
+    run_read_leb_test<int64>(
+        { 128, 128, 128, 128, 128, 128, 128, 128, 128, 127 },
+        BH_LEB_READ_SUCCESS,
+        (uint64)INT64_MIN); // min value
+    run_read_leb_test<int64>({ 255, 255, 255, 255, 255, 255, 255, 255, 255, 0 },
+                             BH_LEB_READ_SUCCESS,
+                             INT64_MAX); // max value
+}

+ 2 - 1
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()

+ 21 - 4
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:

+ 7 - 6
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
 }
 

+ 2 - 0
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 ()