Browse Source

Merge branch main into dev/gc_refactor

Wenyong Huang 1 year ago
parent
commit
71b6bdfa88
52 changed files with 2045 additions and 293 deletions
  1. 1 1
      .github/workflows/build_docker_images.yml
  2. 2 2
      .github/workflows/build_iwasm_release.yml
  3. 5 5
      .github/workflows/build_llvm_libraries.yml
  4. 2 2
      .github/workflows/build_wamr_lldb.yml
  5. 1 1
      .github/workflows/build_wamr_sdk.yml
  6. 1 1
      .github/workflows/build_wamr_vscode_ext.yml
  7. 2 2
      .github/workflows/build_wamrc.yml
  8. 1 1
      .github/workflows/coding_guidelines.yml
  9. 12 12
      .github/workflows/compilation_on_android_ubuntu.yml
  10. 6 6
      .github/workflows/compilation_on_macos.yml
  11. 3 3
      .github/workflows/compilation_on_nuttx.yml
  12. 5 5
      .github/workflows/compilation_on_sgx.yml
  13. 2 2
      .github/workflows/compilation_on_windows.yml
  14. 1 1
      .github/workflows/create_tag.yml
  15. 1 1
      .github/workflows/hadolint_dockerfiles.yml
  16. 10 10
      .github/workflows/nightly_run.yml
  17. 1 1
      .github/workflows/release_process.yml
  18. 1 1
      .github/workflows/reuse_latest_release_binaries.yml
  19. 4 4
      .github/workflows/spec_test_on_nuttx.yml
  20. 76 0
      RELEASE_NOTES.md
  21. 5 0
      build-scripts/config_common.cmake
  22. 8 0
      core/config.h
  23. 4 0
      core/iwasm/aot/aot_loader.c
  24. 3 2
      core/iwasm/aot/aot_runtime.c
  25. 1 1
      core/iwasm/common/wasm_application.c
  26. 14 8
      core/iwasm/common/wasm_c_api.c
  27. 5 1
      core/iwasm/common/wasm_runtime_common.c
  28. 16 5
      core/iwasm/compilation/aot_compiler.c
  29. 0 6
      core/iwasm/compilation/aot_llvm.c
  30. 1 1
      core/iwasm/compilation/aot_llvm_extra2.cpp
  31. 1 1
      core/iwasm/compilation/aot_llvm_extra2.h
  32. 9 4
      core/iwasm/fast-jit/jit_frontend.c
  33. 67 0
      core/iwasm/interpreter/wasm.h
  34. 8 0
      core/iwasm/interpreter/wasm_interp.h
  35. 520 12
      core/iwasm/interpreter/wasm_interp_classic.c
  36. 24 8
      core/iwasm/interpreter/wasm_interp_fast.c
  37. 699 74
      core/iwasm/interpreter/wasm_loader.c
  38. 106 75
      core/iwasm/interpreter/wasm_mini_loader.c
  39. 17 14
      core/iwasm/interpreter/wasm_opcode.h
  40. 181 2
      core/iwasm/interpreter/wasm_runtime.c
  41. 49 0
      core/iwasm/interpreter/wasm_runtime.h
  42. 1 1
      core/shared/platform/common/freertos/freertos_thread.c
  43. 1 0
      core/shared/platform/common/posix/posix_memmap.c
  44. 4 0
      core/shared/platform/common/posix/posix_thread.c
  45. 1 1
      core/version.h
  46. 1 1
      doc/multi_module.md
  47. 8 0
      product-mini/platforms/nuttx/wamr.mk
  48. 36 2
      tests/wamr-test-suites/spec-test-script/all.py
  49. 20 0
      tests/wamr-test-suites/spec-test-script/exception_handling.patch
  50. 50 0
      tests/wamr-test-suites/spec-test-script/runtest.py
  51. 36 2
      tests/wamr-test-suites/test_wamr.sh
  52. 12 11
      wamr-compiler/CMakeLists.txt

+ 1 - 1
.github/workflows/build_docker_images.yml

@@ -21,7 +21,7 @@ jobs:
 
     steps:
       - name: Checkout repository
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
 
       - name: Build and save Docker image(wasm-debug-server:${{ inputs.ver_num }}) to tar file
         run: |

+ 2 - 2
.github/workflows/build_iwasm_release.yml

@@ -35,11 +35,11 @@ jobs:
   build:
     runs-on: ${{ inputs.runner }}
     steps:
-      - uses: actions/checkout@v3
+      - uses: actions/checkout@v4
 
       - name: get cached LLVM libraries
         id: retrieve_llvm_libs
-        uses: actions/cache@v3
+        uses: actions/cache@v4
         with:
           path: |
             ./core/deps/llvm/build/bin

+ 5 - 5
.github/workflows/build_llvm_libraries.yml

@@ -31,7 +31,7 @@ jobs:
 
     steps:
       - name: checkout
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
 
       - name: install dependencies
         run: /usr/bin/env python3 -m pip install -r requirements.txt
@@ -52,7 +52,7 @@ jobs:
 
       - name: Cache LLVM libraries
         id: retrieve_llvm_libs
-        uses: actions/cache@v3
+        uses: actions/cache@v4
         with:
           path: |
             ./core/deps/llvm/build/bin
@@ -62,7 +62,7 @@ jobs:
             ./core/deps/llvm/build/share
           key: ${{ steps.create_lib_cache_key.outputs.key}}
 
-      - uses: actions/cache@v3
+      - uses: actions/cache@v4
         with:
           path: ~/.ccache
           key: 0-ccache-${{ inputs.os }}-${{ steps.get_last_commit.outputs.last_commit }}
@@ -70,7 +70,7 @@ jobs:
             0-ccache-${{ inputs.os }}
         if: steps.retrieve_llvm_libs.outputs.cache-hit != 'true' && inputs.os == 'ubuntu-20.04'
 
-      - uses: actions/cache@v3
+      - uses: actions/cache@v4
         with:
           path: ~/.cache/ccache
           key: 0-ccache-${{ inputs.os }}-${{ steps.get_last_commit.outputs.last_commit }}
@@ -82,7 +82,7 @@ jobs:
       - run: sudo apt install -y ccache ninja-build
         if: steps.retrieve_llvm_libs.outputs.cache-hit != 'true' && startsWith(inputs.os, 'ubuntu') && inputs.container_image == ''
 
-      - uses: actions/cache@v3
+      - uses: actions/cache@v4
         with:
           path: ~/Library/Caches/ccache
           key: 0-ccache-${{ inputs.os }}-${{ steps.get_last_commit.outputs.last_commit }}

+ 2 - 2
.github/workflows/build_wamr_lldb.yml

@@ -47,7 +47,7 @@ jobs:
       PYTHON_UBUNTU_STANDALONE_BUILD: https://github.com/indygreg/python-build-standalone/releases/download/20230507/cpython-3.10.11+20230507-x86_64-unknown-linux-gnu-install_only.tar.gz
       PYTHON_MACOS_STANDALONE_BUILD: https://github.com/indygreg/python-build-standalone/releases/download/20230507/cpython-3.10.11+20230507-x86_64-apple-darwin-install_only.tar.gz
     steps:
-      - uses: actions/checkout@v3
+      - uses: actions/checkout@v4
 
       - name: download and install wasi-sdk
         run: |
@@ -60,7 +60,7 @@ jobs:
 
       - name: Cache build
         id: lldb_build_cache
-        uses: actions/cache@v3
+        uses: actions/cache@v4
         with:
           path: |
             ./core/deps/llvm-project/build/bin

+ 1 - 1
.github/workflows/build_wamr_sdk.yml

@@ -35,7 +35,7 @@ jobs:
   build:
     runs-on: ${{ inputs.runner }}
     steps:
-      - uses: actions/checkout@v3
+      - uses: actions/checkout@v4
 
       - name: download and install wasi-sdk
         run: |

+ 1 - 1
.github/workflows/build_wamr_vscode_ext.yml

@@ -18,7 +18,7 @@ jobs:
   build:
     runs-on: ubuntu-22.04
     steps:
-      - uses: actions/checkout@v3
+      - uses: actions/checkout@v4
 
       - name: Use Node.js 16.x
         uses: actions/setup-node@v3

+ 2 - 2
.github/workflows/build_wamrc.yml

@@ -35,11 +35,11 @@ jobs:
   build:
     runs-on: ${{ inputs.runner }}
     steps:
-      - uses: actions/checkout@v3
+      - uses: actions/checkout@v4
 
       - name: get cached LLVM libraries
         id: retrieve_llvm_libs
-        uses: actions/cache@v3
+        uses: actions/cache@v4
         with:
           path: |
             ./core/deps/llvm/build/bin

+ 1 - 1
.github/workflows/coding_guidelines.yml

@@ -19,7 +19,7 @@ jobs:
     runs-on: ubuntu-20.04
     steps:
       - name: checkout
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
         with:
           fetch-depth: 0
 

+ 12 - 12
.github/workflows/compilation_on_android_ubuntu.yml

@@ -86,13 +86,13 @@ jobs:
             llvm_cache_key: ${{ needs.build_llvm_libraries_on_ubuntu_2204.outputs.cache_key }}
     steps:
       - name: checkout
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
 
       # since jobs.id can't contain the dot character
       # it is hard to use `format` to assemble the cache key
       - name: Get LLVM libraries
         id: retrieve_llvm_libs
-        uses: actions/cache@v3
+        uses: actions/cache@v4
         with:
           path: |
             ./core/deps/llvm/build/bin
@@ -215,13 +215,13 @@ jobs:
             llvm_cache_key: ${{ needs.build_llvm_libraries_on_ubuntu_2204.outputs.cache_key }}
     steps:
       - name: checkout
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
 
       # only download llvm cache when needed
       - name: Get LLVM libraries
         id: retrieve_llvm_libs
         if: endsWith(matrix.make_options_run_mode, '_JIT_BUILD_OPTIONS')
-        uses: actions/cache@v3
+        uses: actions/cache@v4
         with:
           path: |
             ./core/deps/llvm/build/bin
@@ -286,12 +286,12 @@ jobs:
 
     steps:
       - name: checkout
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
 
       - name: Get LLVM libraries
         id: retrieve_llvm_libs
         if: (!endsWith(matrix.make_options, '_INTERP_BUILD_OPTIONS'))
-        uses: actions/cache@v3
+        uses: actions/cache@v4
         with:
           path: |
             ./core/deps/llvm/build/bin
@@ -352,7 +352,7 @@ jobs:
             llvm_cache_key: ${{ needs.build_llvm_libraries_on_ubuntu_2204.outputs.cache_key }}
     steps:
       - name: checkout
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
 
       - name: download and install wasi-sdk
         run: |
@@ -369,7 +369,7 @@ jobs:
           sudo mv wabt-1.0.31 wabt
       - name: Get LLVM libraries
         id: retrieve_llvm_libs
-        uses: actions/cache@v3
+        uses: actions/cache@v4
         with:
           path: |
             ./core/deps/llvm/build/bin
@@ -527,7 +527,7 @@ jobs:
             test_option: $GC_TEST_OPTIONS
     steps:
       - name: checkout
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
 
       - name: Set-up OCaml
         uses: ocaml/setup-ocaml@v2
@@ -572,7 +572,7 @@ jobs:
       - name: Get LLVM libraries
         if: env.USE_LLVM == 'true'
         id: retrieve_llvm_libs
-        uses: actions/cache@v3
+        uses: actions/cache@v4
         with:
           path: |
             ./core/deps/llvm/build/bin
@@ -651,7 +651,7 @@ jobs:
 
     steps:
       - name: checkout
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
 
       - name: install dependencies
         run: |
@@ -670,7 +670,7 @@ jobs:
 
       - name: Cache LLDB
         id: cache-lldb
-        uses: actions/cache@v3
+        uses: actions/cache@v4
         env:
           cache-name: cache-lldb-vscode
         with:

+ 6 - 6
.github/workflows/compilation_on_macos.yml

@@ -71,11 +71,11 @@ jobs:
             llvm_cache_key: ${{ needs.build_llvm_libraries.outputs.cache_key }}
     steps:
       - name: checkout
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
 
       - name: Get LLVM libraries
         id: retrieve_llvm_libs
-        uses: actions/cache@v3
+        uses: actions/cache@v4
         with:
           path: |
             ./core/deps/llvm/build/bin
@@ -174,13 +174,13 @@ jobs:
             llvm_cache_key: ${{ needs.build_llvm_libraries.outputs.cache_key }}
     steps:
       - name: checkout
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
 
       # only download llvm cache when needed
       - name: Get LLVM libraries
         id: retrieve_llvm_libs
         if: endsWith(matrix.make_options_run_mode, '_JIT_BUILD_OPTIONS')
-        uses: actions/cache@v3
+        uses: actions/cache@v4
         with:
           path: |
             ./core/deps/llvm/build/bin
@@ -226,7 +226,7 @@ jobs:
           ]
     steps:
       - name: checkout
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
 
       - name: download and install wabt
         run: |
@@ -258,7 +258,7 @@ jobs:
           ]
     steps:
       - name: checkout
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
 
       - name: download and install wasi-sdk
         run: |

+ 3 - 3
.github/workflows/compilation_on_nuttx.yml

@@ -87,21 +87,21 @@ jobs:
 
     steps:
       - name: Checkout NuttX
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
         with:
           repository: apache/incubator-nuttx
           ref: releases/12.4
           path: nuttx
 
       - name: Checkout NuttX Apps
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
         with:
           repository: apache/incubator-nuttx-apps
           ref: releases/12.4
           path: apps
 
       - name: Checkout WAMR
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
         with:
           repository: ${{ github.repository }}
           path: apps/interpreters/wamr/wamr

+ 5 - 5
.github/workflows/compilation_on_sgx.yml

@@ -120,7 +120,7 @@ jobs:
           source /opt/intel/sgxsdk/environment
 
       - name: checkout
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
 
       - name: Build iwasm
         run: |
@@ -166,7 +166,7 @@ jobs:
 
     steps:
       - name: checkout
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
 
       - name: download and install wasi-sdk
         run: |
@@ -222,7 +222,7 @@ jobs:
       - name: Get LLVM libraries
         if: matrix.iwasm_make_options_run_mode == '$AOT_BUILD_OPTIONS'
         id: retrieve_llvm_libs
-        uses: actions/cache@v3
+        uses: actions/cache@v4
         with:
           path: |
             ./core/deps/llvm/build/bin
@@ -291,12 +291,12 @@ jobs:
 
     steps:
       - name: checkout
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
 
       - name: Get LLVM libraries
         if: matrix.running_mode == 'aot'
         id: retrieve_llvm_libs
-        uses: actions/cache@v3
+        uses: actions/cache@v4
         with:
           path: |
             ./core/deps/llvm/build/bin

+ 2 - 2
.github/workflows/compilation_on_windows.yml

@@ -74,7 +74,7 @@ jobs:
           "-DWAMR_BUILD_LIBC_UVWASI=0 -DWAMR_BUILD_LIBC_WASI=1"
         ]
     steps:
-      - uses: actions/checkout@v3
+      - uses: actions/checkout@v4
 
       - name: clone uvwasi library
         if: ${{ !contains(matrix.build_options, '-DWAMR_BUILD_LIBC_UVWASI=0') }}
@@ -108,7 +108,7 @@ jobs:
           ]
     steps:
       - name: checkout
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
 
       - name: download and install wasi-sdk
         if: matrix.test_option == '$WASI_TEST_OPTIONS'

+ 1 - 1
.github/workflows/create_tag.yml

@@ -24,7 +24,7 @@ jobs:
       new_tag: ${{ steps.preparation.outputs.new_tag }}
 
     steps:
-      - uses: actions/checkout@v3
+      - uses: actions/checkout@v4
         # Full git history is needed to get a proper list of commits and tags
         with:
           fetch-depth: 0

+ 1 - 1
.github/workflows/hadolint_dockerfiles.yml

@@ -34,7 +34,7 @@ jobs:
 
     steps:
       - name: Checkout repository
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
 
       # on default, hadolint will fail on warnings and errors
       - name: Run hadolint on dockerfiles

+ 10 - 10
.github/workflows/nightly_run.yml

@@ -68,13 +68,13 @@ jobs:
             llvm_cache_key: ${{ needs.build_llvm_libraries_on_ubuntu_2004.outputs.cache_key }}  
     steps:
       - name: checkout
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
 
       # since jobs.id can't contain the dot character
       # it is hard to use `format` to assemble the cache key
       - name: Get LLVM libraries
         id: retrieve_llvm_libs
-        uses: actions/cache@v3
+        uses: actions/cache@v4
         with:
           path: |
             ./core/deps/llvm/build/bin
@@ -199,13 +199,13 @@ jobs:
 
     steps:
       - name: checkout
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
 
       # only download llvm cache when needed
       - name: Get LLVM libraries
         id: retrieve_llvm_libs
         if: endsWith(matrix.make_options_run_mode, '_JIT_BUILD_OPTIONS')
-        uses: actions/cache@v3
+        uses: actions/cache@v4
         with:
           path: |
             ./core/deps/llvm/build/bin
@@ -347,12 +347,12 @@ jobs:
             sanitizer: asan
     steps:
       - name: checkout
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
 
       - name: Get LLVM libraries
         id: retrieve_llvm_libs
         if: (!endsWith(matrix.make_options, '_INTERP_BUILD_OPTIONS'))
-        uses: actions/cache@v3
+        uses: actions/cache@v4
         with:
           path: |
             ./core/deps/llvm/build/bin
@@ -414,7 +414,7 @@ jobs:
             llvm_cache_key: ${{ needs.build_llvm_libraries_on_ubuntu_2004.outputs.cache_key }}
     steps:
       - name: checkout
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
 
       - name: download and install wasi-sdk
         run: |
@@ -431,7 +431,7 @@ jobs:
 
       - name: Get LLVM libraries
         id: retrieve_llvm_libs
-        uses: actions/cache@v3
+        uses: actions/cache@v4
         with:
           path: |
             ./core/deps/llvm/build/bin
@@ -601,7 +601,7 @@ jobs:
             test_option: $SIMD_TEST_OPTIONS
     steps:
       - name: checkout
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
 
       - name: download and install wasi-sdk
         if: matrix.test_option == '$WASI_TEST_OPTIONS'
@@ -639,7 +639,7 @@ jobs:
       - name: Get LLVM libraries
         if: env.USE_LLVM == 'true'
         id: retrieve_llvm_libs
-        uses: actions/cache@v3
+        uses: actions/cache@v4
         with:
           path: |
             ./core/deps/llvm/build/bin

+ 1 - 1
.github/workflows/release_process.yml

@@ -28,7 +28,7 @@ jobs:
     outputs:
       upload_url: ${{ steps.create_release.outputs.upload_url }}
     steps:
-      - uses: actions/checkout@v3
+      - uses: actions/checkout@v4
 
       - name: prepare the release note
         run: |

+ 1 - 1
.github/workflows/reuse_latest_release_binaries.yml

@@ -28,7 +28,7 @@ jobs:
     outputs:
       result: ${{ steps.try_reuse.outputs.result }}
     steps:
-      - uses: actions/checkout@v3
+      - uses: actions/checkout@v4
         # Full git history is needed to get a proper list of commits and tags
         with:
           fetch-depth: 0

+ 4 - 4
.github/workflows/spec_test_on_nuttx.yml

@@ -107,21 +107,21 @@ jobs:
 
     steps:
       - name: Checkout NuttX
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
         with:
           repository: apache/incubator-nuttx
           ref: releases/12.4
           path: nuttx
 
       - name: Checkout NuttX Apps
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
         with:
           repository: apache/incubator-nuttx-apps
           ref: releases/12.4
           path: apps
 
       - name: Checkout WAMR
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
         with:
           repository: ${{ github.repository }}
           path: apps/interpreters/wamr/wamr
@@ -129,7 +129,7 @@ jobs:
       - name: Get LLVM libraries
         if: contains(matrix.wamr_test_option.mode, 'aot')
         id: retrieve_llvm_libs
-        uses: actions/cache@v3
+        uses: actions/cache@v4
         with:
           path: |
             ./core/deps/llvm/build/bin

+ 76 - 0
RELEASE_NOTES.md

@@ -1,3 +1,79 @@
+## WAMR-1.3.2
+
+### Breaking Changes
+
+### New Features
+- Implement Exception Handling for classic interpreter (#3096)
+  - Use `cmake -DWAMR_BUILD_EXCE_HANDLING=1/0` option to enable/disable
+    the feature, and by default it is disabled
+  - It is still in highly experimental stage
+
+### Bug Fixes
+- Fix build errors when initializing wasm_val_t values with macros (#3007)
+- fix(wasm-c-api): Do not clone stack frames if there's no trap (#3008)
+- classic-interp: Handle SIMD opcode when JIT is enabled (#3046)
+- fast-interp: Fix dynamic offset error issue in else branch (#3058)
+- wasm_cluster_destroy_spawned_exec_env: Avoid "invalid exec env" trap (#3068)
+- thread-mgr: Fix locking problems around aux stack allocation (#3073)
+- cosmopolitan: Update compiler and update platform_internal.h (#3079)
+- wasi: Apply wasm_runtime_begin_blocking_op to poll as well (#3080)
+- Fix memory/table segment checks in memory.init/table.init (#3081)
+- perf profiling: Adjust the calculation of execution time (#3089)
+- aot: Fix LLVMSetTailCallKind check (#3099)
+- fast-interp: Fix stack recovery for else branch (#3100)
+- fast-interp: Fix frame_offset pop order (#3101)
+- Fix AOT compilation on MacOS (#3102)
+- fast-interp: Fix block with parameter in polymorphic stack issue (#3112)
+- Fix read and validation of misc/simd/atomic sub opcodes (#3115)
+
+### Enhancements
+- Clear compilation warning and dead code (#3002)
+- aot debug: Try to use a bit more appropriate file names (#3000)
+- Increase default app thread stack size (#3010)
+- Rename rwlock_init to avoid conflict (#3016)
+- nuttx: Use larger alignment for os_mmap and comment why (#3017)
+- Allow using mmap for shared memory if hw bound check is disabled (#3029)
+- Don't redefine D_INO if already defined (#3036)
+- Enhancements on wasm function execution time statistic (#2985)
+- wamr-compiler: Fix non-x86{_64} host builds (#3037)
+- Disable quick aot entry for interp and fast-jit (#3039)
+- nuttx: Add option to enable quick aot entry (#3040)
+- Set CONFIG_HAS_CAP_ENTER to support posix file api for freertos (#3041)
+- Revert "Enable MAP_32BIT for macOS (#2992)" (#3032)
+- Enable quick aot entry when hw bound check is disabled (#3044)
+- Do not inherit WASM_SUSPEND_FLAG_BLOCKING from the parent thread (#3051)
+- wasm_runtime_begin_blocking_op: A comment about usage expectation (#3056)
+- Check arguments before calling bh_hash_map_find (#3055)
+- Fix aot large model (--size-level=0) with LLVM 18 (#3057)
+- Add flag to control Winsocket initialization (#3060)
+- nuttx: If STACK_GUARD_SIZE is not set, leave it to config.h (#2927)
+- Enhance setting write gs base with cmake variable (#3066)
+- aot_reloc_x86_64.c: Suggest to try --size-level=0 as well (#3067)
+- Fix some issues reported by CodeQL (#3064)
+- Remove a lot of "unused parameter" warnings (#3075)
+- Forward log and log level to custom bh_log callback (#3070)
+- Fix inconsistent code style in aot_loader.c (#3082)
+- freertos: Thread exit more common (#3094)
+- Fix windows build error and compilation warnings (#3095)
+
+### Others
+- Fix nightly-run CI failure (#3014)
+- Build samples in debug mode (#3019)
+- Remove deprecated tests in language-bindings python (#3018)
+- Avoid unused thread_id warning and recompile multi-module sample (#3033)
+- samples/terminate: Add a sample to demonstrate wasm_runtime_terminate (#3043)
+- Bump NuttX version to 12.4.x in CI (#3047)
+- perf_tune.md: Add refine the calling processes between host and wasm (#3065)
+- build_wamr.md: Update the document (#3074)
+- Fix download link for wasi-sdk (#3077)
+- README.md: Fix typo tunning to tuning (#3078)
+- Update outdated reference link in multi_module.md (#3092)
+- Add comments to suppress warning from clang-tidy (#3088)
+- CI: Update version of checkout to suppress warnings (#3093)
+- test_wamr.sh: Allow using test script on different platforms (#3098)
+
+---
+
 ## WAMR-1.3.1
 
 ### Breaking Changes

+ 5 - 0
build-scripts/config_common.cmake

@@ -375,6 +375,11 @@ if (WAMR_BUILD_PERF_PROFILING EQUAL 1 OR
     add_definitions (-DWASM_ENABLE_JIT_STACK_FRAME=1)
   endif ()
 endif ()
+if (WAMR_BUILD_EXCE_HANDLING EQUAL 1)
+  add_definitions (-DWASM_ENABLE_EXCE_HANDLING=1)
+  add_definitions (-DWASM_ENABLE_TAGS=1)
+  message ("     Exception Handling enabled")
+endif ()
 if (DEFINED WAMR_BH_VPRINTF)
   add_definitions (-DBH_VPRINTF=${WAMR_BH_VPRINTF})
 endif ()

+ 8 - 0
core/config.h

@@ -503,6 +503,14 @@
 #define GC_RTTOBJ_MAP_SIZE_DEFAULT 64
 #endif
 
+#ifndef WASM_ENABLE_EXCE_HANDLING
+#define WASM_ENABLE_EXCE_HANDLING 0
+#endif
+
+#ifndef WASM_ENABLE_TAGS
+#define WASM_ENABLE_TAGS 0
+#endif
+
 #ifndef WASM_ENABLE_SGX_IPFS
 #define WASM_ENABLE_SGX_IPFS 0
 #endif

+ 4 - 0
core/iwasm/aot/aot_loader.c

@@ -214,6 +214,8 @@ GET_U16_FROM_ADDR(const uint8 *p)
         p += sizeof(type);                              \
     } while (0)
 
+/* NOLINTBEGIN, disable lint for this region with clang-tidy */
+
 #define read_byte_array(p, p_end, addr, len) \
     do {                                     \
         CHECK_BUF(p, p_end, len);            \
@@ -236,6 +238,8 @@ GET_U16_FROM_ADDR(const uint8 *p)
 #define read_uint32(p, p_end, res) TEMPLATE_READ(p, p_end, res, uint32)
 #define read_uint64(p, p_end, res) TEMPLATE_READ(p, p_end, res, uint64)
 
+/* NOLINTEND */
+
 /* Legal values for bin_type */
 #define BIN_TYPE_ELF32L 0 /* 32-bit little endian */
 #define BIN_TYPE_ELF32B 1 /* 32-bit big endian */

+ 3 - 2
core/iwasm/aot/aot_runtime.c

@@ -2090,7 +2090,7 @@ invoke_native_with_hw_bound_check(WASMExecEnv *exec_env, void *func_ptr,
     (void)jmpbuf_node_pop;
     return ret;
 }
-#define invoke_native_internal invoke_native_with_hw_bound_check
+#define invoke_native_internal invoke_native_with_hw_bound_check /* NOLINT */
 #else /* else of OS_ENABLE_HW_BOUND_CHECK */
 static inline bool
 invoke_native_internal(WASMExecEnv *exec_env, void *func_ptr,
@@ -4653,7 +4653,8 @@ aot_frame_traverse_gc_rootset(WASMExecEnv *exec_env, void *heap)
 
         /* stack ref flags */
         uint8 *frame_ref = frame->frame_ref;
-        for (i = local_ref_flag_cell_num; i < frame->sp - frame->lp; i++) {
+        for (i = local_ref_flag_cell_num; i < (uint32)(frame->sp - frame->lp);
+             i++) {
             if (frame_ref[i]) {
                 gc_obj = GET_REF_FROM_ADDR(frame->lp + i);
                 if (wasm_obj_is_created_from_heap(gc_obj)) {

+ 1 - 1
core/iwasm/common/wasm_application.c

@@ -55,7 +55,7 @@ static union {
     char b;
 } __ue = { .a = 1 };
 
-#define is_little_endian() (__ue.b == 1)
+#define is_little_endian() (__ue.b == 1) /* NOLINT */
 
 /**
  * Implementation of wasm_application_execute_main()

+ 14 - 8
core/iwasm/common/wasm_c_api.c

@@ -1934,8 +1934,8 @@ wasm_frame_vec_clone_internal(Vector *src, Vector *out)
         return;
     }
 
-    bh_memcpy_s(out->data, src->num_elems * sizeof(WASMCApiFrame), src->data,
-                src->num_elems * sizeof(WASMCApiFrame));
+    bh_memcpy_s(out->data, (uint32)(src->num_elems * sizeof(WASMCApiFrame)),
+                src->data, (uint32)(src->num_elems * sizeof(WASMCApiFrame)));
     out->num_elems = src->num_elems;
 }
 
@@ -2972,8 +2972,10 @@ wasm_func_new_basic(wasm_store_t *store, const wasm_functype_t *type,
     if (!(func->type = wasm_functype_copy(type))) {
         goto failed;
     }
-    func->param_count = func->type->params->num_elems;
-    func->result_count = func->type->results->num_elems;
+    /* func type's param_count and result_count were checked in
+       loader and are no larger than UINT16_MAX */
+    func->param_count = (uint16)func->type->params->num_elems;
+    func->result_count = (uint16)func->type->results->num_elems;
 
     RETURN_OBJ(func, wasm_func_delete)
 }
@@ -3004,8 +3006,10 @@ wasm_func_new_with_env_basic(wasm_store_t *store, const wasm_functype_t *type,
     if (!(func->type = wasm_functype_copy(type))) {
         goto failed;
     }
-    func->param_count = func->type->params->num_elems;
-    func->result_count = func->type->results->num_elems;
+    /* func type's param_count and result_count were checked in
+       loader and are no larger than UINT16_MAX */
+    func->param_count = (uint16)func->type->params->num_elems;
+    func->result_count = (uint16)func->type->results->num_elems;
 
     RETURN_OBJ(func, wasm_func_delete)
 }
@@ -3095,8 +3099,10 @@ wasm_func_new_internal(wasm_store_t *store, uint16 func_idx_rt,
     if (!func->type) {
         goto failed;
     }
-    func->param_count = func->type->params->num_elems;
-    func->result_count = func->type->results->num_elems;
+    /* func type's param_count and result_count were checked in
+       loader and are no larger than UINT16_MAX */
+    func->param_count = (uint16)func->type->params->num_elems;
+    func->result_count = (uint16)func->type->results->num_elems;
 
     /* will add name information when processing "exports" */
     func->store = store;

+ 5 - 1
core/iwasm/common/wasm_runtime_common.c

@@ -804,6 +804,7 @@ align_ptr(const uint8 *p, uint32 b)
             return false;                                    \
     } while (0)
 
+/* NOLINTNEXTLINE */
 #define read_uint16(p, p_end, res)                 \
     do {                                           \
         p = (uint8 *)align_ptr(p, sizeof(uint16)); \
@@ -812,6 +813,7 @@ align_ptr(const uint8 *p, uint32 b)
         p += sizeof(uint16);                       \
     } while (0)
 
+/* NOLINTNEXTLINE */
 #define read_uint32(p, p_end, res)                 \
     do {                                           \
         p = (uint8 *)align_ptr(p, sizeof(uint32)); \
@@ -3593,7 +3595,7 @@ static union {
     char b;
 } __ue = { .a = 1 };
 
-#define is_little_endian() (__ue.b == 1)
+#define is_little_endian() (__ue.b == 1) /* NOLINT */
 
 bool
 wasm_runtime_register_natives(const char *module_name,
@@ -4653,6 +4655,7 @@ typedef int64 (*Int64FuncPtr)(GenericFunctionPointer, uint64 *, uint64);
 typedef int32 (*Int32FuncPtr)(GenericFunctionPointer, uint64 *, uint64);
 typedef void (*VoidFuncPtr)(GenericFunctionPointer, uint64 *, uint64);
 
+/* NOLINTBEGIN */
 static volatile Float64FuncPtr invokeNative_Float64 =
     (Float64FuncPtr)(uintptr_t)invokeNative;
 static volatile Float32FuncPtr invokeNative_Float32 =
@@ -4668,6 +4671,7 @@ static volatile VoidFuncPtr invokeNative_Void =
 typedef v128 (*V128FuncPtr)(GenericFunctionPointer, uint64 *, uint64);
 static V128FuncPtr invokeNative_V128 = (V128FuncPtr)(uintptr_t)invokeNative;
 #endif
+/* NOLINTEND */
 
 #if defined(_WIN32) || defined(_WIN32_)
 #define MAX_REG_FLOATS 4

+ 16 - 5
core/iwasm/compilation/aot_compiler.c

@@ -2361,7 +2361,9 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
                 uint32 opcode1;
 
                 read_leb_uint32(frame_ip, frame_ip_end, opcode1);
-                opcode = (uint32)opcode1;
+                /* opcode1 was checked in loader and is no larger than
+                   UINT8_MAX */
+                opcode = (uint8)opcode1;
 
 #if WASM_ENABLE_BULK_MEMORY != 0
                 if (WASM_OP_MEMORY_INIT <= opcode
@@ -2522,10 +2524,13 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
             case WASM_OP_ATOMIC_PREFIX:
             {
                 uint8 bin_op, op_type;
+                uint32 opcode1;
+
+                read_leb_uint32(frame_ip, frame_ip_end, opcode1);
+                /* opcode1 was checked in loader and is no larger than
+                   UINT8_MAX */
+                opcode = (uint8)opcode1;
 
-                if (frame_ip < frame_ip_end) {
-                    opcode = *frame_ip++;
-                }
                 if (opcode != WASM_OP_ATOMIC_FENCE) {
                     read_leb_uint32(frame_ip, frame_ip_end, align);
                     read_leb_uint32(frame_ip, frame_ip_end, offset);
@@ -2675,11 +2680,17 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
 #if WASM_ENABLE_SIMD != 0
             case WASM_OP_SIMD_PREFIX:
             {
+                uint32 opcode1;
+
                 if (!comp_ctx->enable_simd) {
                     goto unsupport_simd;
                 }
 
-                opcode = *frame_ip++;
+                read_leb_uint32(frame_ip, frame_ip_end, opcode1);
+                /* opcode1 was checked in loader and is no larger than
+                   UINT8_MAX */
+                opcode = (uint8)opcode1;
+
                 /* follow the order of enum WASMSimdEXTOpcode in
                    wasm_opcode.h */
                 switch (opcode) {

+ 0 - 6
core/iwasm/compilation/aot_llvm.c

@@ -551,18 +551,12 @@ aot_add_precheck_function(AOTCompContext *comp_ctx, LLVMModuleRef module,
     }
     wasm_runtime_free(params);
     params = NULL;
-
-#if LLVM_VERSION_MAJOR < 17
     if (aot_target_precheck_can_use_musttail(comp_ctx)) {
         LLVMSetTailCallKind(retval, LLVMTailCallKindMustTail);
     }
     else {
         LLVMSetTailCallKind(retval, LLVMTailCallKindTail);
     }
-#else
-    LLVMSetTailCall(retval, true);
-#endif
-
     if (ret_type == VOID_TYPE) {
         if (!LLVMBuildRetVoid(b)) {
             goto fail;

+ 1 - 1
core/iwasm/compilation/aot_llvm_extra2.cpp

@@ -163,7 +163,7 @@ LLVMCreateTargetMachineWithOpts(LLVMTargetRef ctarget, const char *triple,
 }
 
 /* https://reviews.llvm.org/D153107 */
-#if LLVM_VERSION_MAJOR < 17
+#if LLVM_VERSION_MAJOR < 18
 using namespace llvm;
 
 LLVMTailCallKind

+ 1 - 1
core/iwasm/compilation/aot_llvm_extra2.h

@@ -17,7 +17,7 @@ LLVMCreateTargetMachineWithOpts(LLVMTargetRef ctarget, const char *triple,
                                 const char *StackUsageOutput);
 
 /* https://reviews.llvm.org/D153107 */
-#if LLVM_VERSION_MAJOR < 17
+#if LLVM_VERSION_MAJOR < 18
 typedef enum {
     LLVMTailCallKindNone = 0,
     LLVMTailCallKindTail = 1,

+ 9 - 4
core/iwasm/fast-jit/jit_frontend.c

@@ -2258,7 +2258,9 @@ jit_compile_func(JitCompContext *cc)
                 uint32 opcode1;
 
                 read_leb_uint32(frame_ip, frame_ip_end, opcode1);
-                opcode = (uint32)opcode1;
+                /* opcode1 was checked in loader and is no larger than
+                   UINT8_MAX */
+                opcode = (uint8)opcode1;
 
                 switch (opcode) {
                     case WASM_OP_I32_TRUNC_SAT_S_F32:
@@ -2397,10 +2399,13 @@ jit_compile_func(JitCompContext *cc)
             case WASM_OP_ATOMIC_PREFIX:
             {
                 uint8 bin_op, op_type;
+                uint32 opcode1;
+
+                read_leb_uint32(frame_ip, frame_ip_end, opcode1);
+                /* opcode1 was checked in loader and is no larger than
+                   UINT8_MAX */
+                opcode = (uint8)opcode1;
 
-                if (frame_ip < frame_ip_end) {
-                    opcode = *frame_ip++;
-                }
                 if (opcode != WASM_OP_ATOMIC_FENCE) {
                     read_leb_uint32(frame_ip, frame_ip_end, align);
                     read_leb_uint32(frame_ip, frame_ip_end, offset);

+ 67 - 0
core/iwasm/interpreter/wasm.h

@@ -138,6 +138,9 @@ typedef void *table_elem_type_t;
 #if WASM_ENABLE_BULK_MEMORY != 0
 #define SECTION_TYPE_DATACOUNT 12
 #endif
+#if WASM_ENABLE_TAGS != 0
+#define SECTION_TYPE_TAG 13
+#endif
 #if WASM_ENABLE_STRINGREF != 0
 #define SECTION_TYPE_STRINGREF 14
 #endif
@@ -150,16 +153,27 @@ typedef void *table_elem_type_t;
 #define IMPORT_KIND_TABLE 1
 #define IMPORT_KIND_MEMORY 2
 #define IMPORT_KIND_GLOBAL 3
+#if WASM_ENABLE_TAGS != 0
+#define IMPORT_KIND_TAG 4
+#endif
 
 #define EXPORT_KIND_FUNC 0
 #define EXPORT_KIND_TABLE 1
 #define EXPORT_KIND_MEMORY 2
 #define EXPORT_KIND_GLOBAL 3
+#if WASM_ENABLE_TAGS != 0
+#define EXPORT_KIND_TAG 4
+#endif
 
 #define LABEL_TYPE_BLOCK 0
 #define LABEL_TYPE_LOOP 1
 #define LABEL_TYPE_IF 2
 #define LABEL_TYPE_FUNCTION 3
+#if WASM_ENABLE_EXCE_HANDLING != 0
+#define LABEL_TYPE_TRY 4
+#define LABEL_TYPE_CATCH 5
+#define LABEL_TYPE_CATCH_ALL 6
+#endif
 
 #define WASM_TYPE_FUNC 0
 #define WASM_TYPE_STRUCT 1
@@ -179,6 +193,9 @@ typedef void *table_elem_type_t;
 typedef struct WASMModule WASMModule;
 typedef struct WASMFunction WASMFunction;
 typedef struct WASMGlobal WASMGlobal;
+#if WASM_ENABLE_TAGS != 0
+typedef struct WASMTag WASMTag;
+#endif
 
 #ifndef WASM_VALUE_DEFINED
 #define WASM_VALUE_DEFINED
@@ -526,6 +543,24 @@ typedef struct WASMFunctionImport {
 #endif
 } WASMFunctionImport;
 
+#if WASM_ENABLE_TAGS != 0
+typedef struct WASMTagImport {
+    char *module_name;
+    char *field_name;
+    uint8 attribute; /* the type of the tag (numerical) */
+    uint32 type;     /* the type of the catch function (numerical)*/
+    WASMType *tag_type;
+    void *tag_ptr_linked;
+
+#if WASM_ENABLE_MULTI_MODULE != 0
+    /* imported tag  pointer after linked */
+    WASMModule *import_module;
+    WASMTag *import_tag_linked;
+    uint32 import_tag_index_linked;
+#endif
+} WASMTagImport;
+#endif
+
 typedef struct WASMGlobalImport {
     char *module_name;
     char *field_name;
@@ -555,6 +590,9 @@ typedef struct WASMImport {
         WASMFunctionImport function;
         WASMTableImport table;
         WASMMemoryImport memory;
+#if WASM_ENABLE_TAGS != 0
+        WASMTagImport tag;
+#endif
         WASMGlobalImport global;
         struct {
             char *module_name;
@@ -602,6 +640,10 @@ struct WASMFunction {
     uint32 type_idx;
 #endif
 
+#if WASM_ENABLE_EXCE_HANDLING != 0
+    uint32 exception_handler_count;
+#endif
+
 #if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0 \
     || WASM_ENABLE_WAMR_COMPILER != 0
     /* Whether function has opcode memory.grow */
@@ -631,6 +673,14 @@ struct WASMFunction {
 #endif
 };
 
+#if WASM_ENABLE_TAGS != 0
+struct WASMTag {
+    uint8 attribute; /* the attribute property of the tag (expected to be 0) */
+    uint32 type; /* the type of the tag (expected valid inden in type table) */
+    WASMType *tag_type;
+};
+#endif
+
 struct WASMGlobal {
     uint8 type;
     bool is_mutable;
@@ -763,6 +813,9 @@ struct WASMModule {
     uint32 function_count;
     uint32 table_count;
     uint32 memory_count;
+#if WASM_ENABLE_TAGS != 0
+    uint32 tag_count;
+#endif
     uint32 global_count;
     uint32 export_count;
     uint32 table_seg_count;
@@ -783,11 +836,17 @@ struct WASMModule {
     uint32 import_function_count;
     uint32 import_table_count;
     uint32 import_memory_count;
+#if WASM_ENABLE_TAGS != 0
+    uint32 import_tag_count;
+#endif
     uint32 import_global_count;
 
     WASMImport *import_functions;
     WASMImport *import_tables;
     WASMImport *import_memories;
+#if WASM_ENABLE_TAGS != 0
+    WASMImport *import_tags;
+#endif
     WASMImport *import_globals;
 
     WASMType **types;
@@ -795,6 +854,9 @@ struct WASMModule {
     WASMFunction **functions;
     WASMTable *tables;
     WASMMemory *memories;
+#if WASM_ENABLE_TAGS != 0
+    WASMTag **tags;
+#endif
     WASMGlobal *globals;
     WASMExport *exports;
     WASMTableSeg *table_segments;
@@ -1007,6 +1069,11 @@ typedef struct WASMBranchBlock {
     uint8 *target_addr;
     uint32 *frame_sp;
     uint32 cell_num;
+#if WASM_ENABLE_EXCE_HANDLING != 0
+    /* in exception handling, label_type needs to be stored to lookup exception
+     * handlers */
+    uint8 label_type;
+#endif
 } WASMBranchBlock;
 
 /**

+ 8 - 0
core/iwasm/interpreter/wasm_interp.h

@@ -34,6 +34,14 @@ typedef struct WASMInterpFrame {
     uint64 time_started;
 #endif
 
+#if WASM_ENABLE_EXCE_HANDLING != 0
+    /* set to true if the callee returns an exception rather than
+     * result values on the stack
+     */
+    bool exception_raised;
+    uint32 tag_index;
+#endif
+
 #if WASM_ENABLE_FAST_INTERP != 0
     /* Return offset of the first return value of current frame,
        the callee will put return values here continuously */

+ 520 - 12
core/iwasm/interpreter/wasm_interp_classic.c

@@ -413,6 +413,8 @@ wasm_interp_get_frame_ref(WASMInterpFrame *frame)
 #define CLEAR_FRAME_REF(p, n) (void)0
 #endif /* end of WASM_ENABLE_GC != 0 */
 
+#define skip_leb(p) while (*p++ & 0x80)
+
 #define PUSH_I32(value)                        \
     do {                                       \
         *(int32 *)frame_sp++ = (int32)(value); \
@@ -463,10 +465,19 @@ wasm_interp_get_frame_ref(WASMInterpFrame *frame)
     } while (0)
 #endif
 
+/* in exception handling, label_type needs to be stored to lookup exception
+ * handlers */
+
+#if WASM_ENABLE_EXCE_HANDLING != 0
+#define SET_LABEL_TYPE(_label_type) frame_csp->label_type = _label_type
+#else
+#define SET_LABEL_TYPE(_label_type) (void)0
+#endif
+
 #define PUSH_CSP(_label_type, param_cell_num, cell_num, _target_addr) \
     do {                                                              \
         bh_assert(frame_csp < frame->csp_boundary);                   \
-        /* frame_csp->label_type = _label_type; */                    \
+        SET_LABEL_TYPE(_label_type);                                  \
         frame_csp->cell_num = cell_num;                               \
         frame_csp->begin_addr = frame_ip;                             \
         frame_csp->target_addr = _target_addr;                        \
@@ -532,6 +543,18 @@ wasm_interp_get_frame_ref(WASMInterpFrame *frame)
         CLEAR_FRAME_REF(frame_sp, n); \
     } while (0)
 
+#if WASM_ENABLE_EXCE_HANDLING != 0
+/* unwind the CSP to a given label and optionally modify the labeltype  */
+#define UNWIND_CSP(N, T)                                                   \
+    do {                                                                   \
+        /* unwind to function frame  */                                    \
+        frame_csp -= N;                                                    \
+        /* drop handlers and values pushd in try block */                  \
+        frame_sp = (frame_csp - 1)->frame_sp;                              \
+        (frame_csp - 1)->label_type = T ? T : (frame_csp - 1)->label_type; \
+    } while (0)
+#endif
+
 #define SYNC_ALL_TO_FRAME()     \
     do {                        \
         frame->sp = frame_sp;   \
@@ -1384,6 +1407,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
     uint32 local_idx, local_offset, global_idx;
     uint8 local_type, *global_addr;
     uint32 cache_index, type_index, param_cell_num, cell_num;
+#if WASM_ENABLE_EXCE_HANDLING != 0
+    int32_t exception_tag_index;
+#endif
     uint8 value_type;
 #if !defined(OS_ENABLE_HW_BOUND_CHECK) \
     || WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0
@@ -1441,6 +1467,389 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
 
             HANDLE_OP(WASM_OP_NOP) { HANDLE_OP_END(); }
 
+#if WASM_ENABLE_EXCE_HANDLING != 0
+            HANDLE_OP(WASM_OP_RETHROW)
+            {
+                int32_t relative_depth;
+                read_leb_int32(frame_ip, frame_ip_end, relative_depth);
+
+                /* No frame found with exception handler; validation should
+                 * catch it */
+                bh_assert(frame_csp >= frame->csp_bottom + relative_depth);
+
+                /* go up the frame stack */
+                WASMBranchBlock *tgtframe = (frame_csp - 1) - relative_depth;
+
+                bh_assert(tgtframe->label_type == LABEL_TYPE_CATCH
+                          || tgtframe->label_type == LABEL_TYPE_CATCH_ALL);
+
+                /* tgtframe points to the frame containing a thrown
+                 * exception */
+
+                uint32 *tgtframe_sp = tgtframe->frame_sp;
+
+                /* frame sp of tgtframe points to catched exception */
+                exception_tag_index = *((uint32 *)tgtframe_sp);
+                tgtframe_sp++;
+
+                /* get tag type */
+                uint8 tag_type_index =
+                    module->module->tags[exception_tag_index]->type;
+                uint32 cell_num_to_copy =
+                    wasm_types[tag_type_index]->param_cell_num;
+
+                /* move exception parameters (if there are any) onto top
+                 * of stack */
+                if (cell_num_to_copy > 0) {
+                    word_copy(frame_sp, tgtframe_sp - cell_num_to_copy,
+                              cell_num_to_copy);
+                }
+
+                frame_sp += cell_num_to_copy;
+                goto find_a_catch_handler;
+            }
+
+            HANDLE_OP(WASM_OP_THROW)
+            {
+                read_leb_int32(frame_ip, frame_ip_end, exception_tag_index);
+
+            /* landing pad for the rethrow ? */
+            find_a_catch_handler:
+            {
+                WASMType *tag_type = NULL;
+                uint32 cell_num_to_copy = 0;
+                if (IS_INVALID_TAGINDEX(exception_tag_index)) {
+                    /*
+                     * invalid exception index,
+                     * generated if a submodule throws an exception
+                     * that has not been imported here
+                     *
+                     * This should result in a branch to the CATCH_ALL block,
+                     * if there is one
+                     */
+                    tag_type = NULL;
+                    cell_num_to_copy = 0;
+                }
+                else {
+                    if (module->e->tags[exception_tag_index].is_import_tag) {
+                        tag_type = module->e->tags[exception_tag_index]
+                                       .u.tag_import->tag_type;
+                    }
+                    else {
+                        tag_type = module->e->tags[exception_tag_index]
+                                       .u.tag->tag_type;
+                    }
+                    cell_num_to_copy = tag_type->param_cell_num;
+                }
+
+                /* browse through frame stack */
+                uint32 relative_depth = 0;
+                do {
+                    POP_CSP_CHECK_OVERFLOW(relative_depth - 1);
+                    WASMBranchBlock *tgtframe = frame_csp - relative_depth - 1;
+
+                    switch (tgtframe->label_type) {
+                        case LABEL_TYPE_BLOCK:
+                        case LABEL_TYPE_IF:
+                        case LABEL_TYPE_LOOP:
+                        case LABEL_TYPE_CATCH:
+                        case LABEL_TYPE_CATCH_ALL:
+                            /*
+                             * skip that blocks in search
+                             * BLOCK, IF and LOOP do not contain handlers and
+                             * cannot catch exceptions.
+                             * blocks marked as CATCH or
+                             * CATCH_ALL did already caugth an exception and can
+                             * only be a target for RETHROW, but cannot catch an
+                             * exception again
+                             */
+                            break;
+                        case LABEL_TYPE_TRY:
+                        {
+                            uint32 handler_number = 0;
+                            uint8 **handlers = (uint8 **)tgtframe->frame_sp;
+                            uint8 *handler = NULL;
+                            while ((handler = handlers[handler_number]) != 0) {
+                                uint8 handler_opcode = *handler;
+                                uint8 *target_addr =
+                                    handler
+                                    + 1; /* first instruction or leb-immediate
+                                            behind the handler opcode */
+                                switch (handler_opcode) {
+                                    case WASM_OP_CATCH:
+                                    {
+                                        int32 lookup_index = 0;
+                                        /* read the tag_index and advance
+                                         * target_addr to the first instruction
+                                         * in the block */
+                                        read_leb_int32(target_addr, 0,
+                                                       lookup_index);
+
+                                        if (exception_tag_index
+                                            == lookup_index) {
+                                            /* set ip */
+                                            frame_ip = target_addr;
+                                            /* save frame_sp (points to
+                                             * exception values) */
+                                            uint32 *frame_sp_old = frame_sp;
+
+                                            UNWIND_CSP(relative_depth,
+                                                       LABEL_TYPE_CATCH);
+
+                                            /* push exception_tag_index and
+                                             * exception values for rethrow */
+                                            PUSH_I32(exception_tag_index);
+                                            if (cell_num_to_copy > 0) {
+                                                word_copy(
+                                                    frame_sp,
+                                                    frame_sp_old
+                                                        - cell_num_to_copy,
+                                                    cell_num_to_copy);
+                                                frame_sp += cell_num_to_copy;
+                                                /* push exception values for
+                                                 * catch
+                                                 */
+                                                word_copy(
+                                                    frame_sp,
+                                                    frame_sp_old
+                                                        - cell_num_to_copy,
+                                                    cell_num_to_copy);
+                                                frame_sp += cell_num_to_copy;
+                                            }
+
+                                            /* advance to handler */
+                                            HANDLE_OP_END();
+                                        }
+                                        break;
+                                    }
+                                    case WASM_OP_DELEGATE:
+                                    {
+                                        int32 lookup_depth = 0;
+                                        /* read the depth */
+                                        read_leb_int32(target_addr, 0,
+                                                       lookup_depth);
+
+                                        /* save frame_sp (points to exception
+                                         * values) */
+                                        uint32 *frame_sp_old = frame_sp;
+
+                                        UNWIND_CSP(relative_depth,
+                                                   LABEL_TYPE_CATCH);
+
+                                        /* leave the block (the delegate is
+                                         * technically not inside the frame) */
+                                        frame_csp--;
+
+                                        /* unwind to delegated frame */
+                                        frame_csp -= lookup_depth;
+
+                                        /* push exception values for catch */
+                                        if (cell_num_to_copy > 0) {
+                                            word_copy(frame_sp,
+                                                      frame_sp_old
+                                                          - cell_num_to_copy,
+                                                      cell_num_to_copy);
+                                            frame_sp += cell_num_to_copy;
+                                        }
+
+                                        /* tag_index is already stored in
+                                         * exception_tag_index */
+                                        goto find_a_catch_handler;
+                                    }
+                                    case WASM_OP_CATCH_ALL:
+                                    {
+                                        /* no immediate */
+                                        /* save frame_sp (points to exception
+                                         * values) */
+                                        uint32 *frame_sp_old = frame_sp;
+                                        /* set ip */
+                                        frame_ip = target_addr;
+
+                                        UNWIND_CSP(relative_depth,
+                                                   LABEL_TYPE_CATCH_ALL);
+
+                                        /* push exception_tag_index and
+                                         * exception values for rethrow */
+                                        PUSH_I32(exception_tag_index);
+                                        if (cell_num_to_copy > 0) {
+                                            word_copy(frame_sp,
+                                                      frame_sp_old
+                                                          - cell_num_to_copy,
+                                                      cell_num_to_copy);
+                                            frame_sp += cell_num_to_copy;
+                                        }
+                                        /* catch_all has no exception values */
+
+                                        /* advance to handler */
+                                        HANDLE_OP_END();
+                                    }
+                                    default:
+                                        wasm_set_exception(
+                                            module, "WASM_OP_THROW found "
+                                                    "unexpected handler type");
+                                        goto got_exception;
+                                }
+                                handler_number++;
+                            }
+                            /* exception not catched in this frame */
+                            break;
+                        }
+                        case LABEL_TYPE_FUNCTION:
+                        {
+                            /* save frame_sp (points to exception values) */
+                            uint32 *frame_sp_old = frame_sp;
+
+                            UNWIND_CSP(relative_depth, LABEL_TYPE_FUNCTION);
+                            /* push exception values for catch
+                             * The values are copied to the CALLER FRAME
+                             * (prev_frame->sp) same behvior ad WASM_OP_RETURN
+                             */
+                            if (cell_num_to_copy > 0) {
+                                word_copy(prev_frame->sp,
+                                          frame_sp_old - cell_num_to_copy,
+                                          cell_num_to_copy);
+                                prev_frame->sp += cell_num_to_copy;
+                            }
+                            *((int32 *)(prev_frame->sp)) = exception_tag_index;
+                            prev_frame->sp++;
+
+                            /* mark frame as raised exception */
+                            wasm_set_exception(module,
+                                               "uncaught wasm exception");
+
+                            /* end of function, treat as WASM_OP_RETURN */
+                            goto return_func;
+                        }
+                        default:
+                            wasm_set_exception(
+                                module,
+                                "unexpected or invalid label in THROW or "
+                                "RETHROW when searching a catch handler");
+                            goto got_exception;
+                    }
+
+                    relative_depth++;
+
+                } while (1);
+            }
+
+                /* something went wrong. normally, we should always find the
+                 * func label. if not, stop the interpreter */
+                wasm_set_exception(
+                    module, "WASM_OP_THROW hit the bottom of the frame stack");
+                goto got_exception;
+            }
+
+            HANDLE_OP(EXT_OP_TRY)
+            {
+                /* read the blocktype */
+                read_leb_uint32(frame_ip, frame_ip_end, type_index);
+                param_cell_num = wasm_types[type_index]->param_cell_num;
+                cell_num = wasm_types[type_index]->ret_cell_num;
+                goto handle_op_try;
+            }
+
+            HANDLE_OP(WASM_OP_TRY)
+            {
+                value_type = *frame_ip++;
+                param_cell_num = 0;
+                cell_num = wasm_value_type_cell_num(value_type);
+
+            handle_op_try:
+
+                cache_index = ((uintptr_t)frame_ip)
+                              & (uintptr_t)(BLOCK_ADDR_CACHE_SIZE - 1);
+                cache_items = exec_env->block_addr_cache[cache_index];
+                if (cache_items[0].start_addr == frame_ip) {
+                    cache_items[0].start_addr = 0;
+                }
+                if (cache_items[1].start_addr == frame_ip) {
+                    cache_items[1].start_addr = 0;
+                }
+
+                /* start at the first opcode following the try and its blocktype
+                 */
+                uint8 *lookup_cursor = frame_ip;
+                uint8 handler_opcode = WASM_OP_UNREACHABLE;
+
+                /* target_addr filled in when END or DELEGATE is found */
+                PUSH_CSP(LABEL_TYPE_TRY, param_cell_num, cell_num, 0);
+
+                /* reset to begin of block */
+                lookup_cursor = frame_ip;
+                do {
+                    /* lookup the next CATCH, CATCH_ALL or END for this TRY */
+                    if (!wasm_loader_find_block_addr(
+                            exec_env, (BlockAddr *)exec_env->block_addr_cache,
+                            lookup_cursor, (uint8 *)-1, LABEL_TYPE_TRY,
+                            &else_addr, &end_addr)) {
+                        /* something went wrong */
+                        wasm_set_exception(module, "find block address failed");
+                        goto got_exception;
+                    }
+
+                    /* place cursor for continuation past opcode */
+                    lookup_cursor = end_addr + 1;
+
+                    /* end_addr points to CATCH, CATCH_ALL, DELEGATE or END */
+                    handler_opcode = *end_addr;
+                    switch (handler_opcode) {
+                        case WASM_OP_CATCH:
+                            skip_leb(lookup_cursor); /* skip tag_index */
+                            PUSH_I64(end_addr);
+                            break;
+                        case WASM_OP_CATCH_ALL:
+                            PUSH_I64(end_addr);
+                            break;
+                        case WASM_OP_DELEGATE:
+                            skip_leb(lookup_cursor); /* skip depth */
+                            PUSH_I64(end_addr);
+                            /* patch target_addr */
+                            (frame_csp - 1)->target_addr = lookup_cursor;
+                            break;
+                        case WASM_OP_END:
+                            PUSH_I64(0);
+                            /* patch target_addr */
+                            (frame_csp - 1)->target_addr = end_addr;
+                            break;
+                        default:
+                            /* something went wrong */
+                            wasm_set_exception(module,
+                                               "find block address returned an "
+                                               "unexpected opcode");
+                            goto got_exception;
+                    }
+                    /* ... search until the returned address is the END of the
+                     * TRY block */
+                } while (handler_opcode != WASM_OP_END
+                         && handler_opcode != WASM_OP_DELEGATE);
+                /* handler setup on stack complete */
+
+                HANDLE_OP_END();
+            }
+            HANDLE_OP(WASM_OP_CATCH)
+            {
+                /* skip the tag_index */
+                skip_leb(frame_ip);
+                /* leave the frame */
+                POP_CSP_N(0);
+                HANDLE_OP_END();
+            }
+            HANDLE_OP(WASM_OP_CATCH_ALL)
+            {
+                /* leave the frame */
+                POP_CSP_N(0);
+                HANDLE_OP_END();
+            }
+            HANDLE_OP(WASM_OP_DELEGATE)
+            {
+                /* skip the delegate depth */
+                skip_leb(frame_ip);
+                /* leave the frame like WASM_OP_END */
+                POP_CSP();
+                HANDLE_OP_END();
+            }
+#endif /* end of WASM_ENABLE_EXCE_HANDLING != 0 */
             HANDLE_OP(EXT_OP_BLOCK)
             {
                 read_leb_uint32(frame_ip, frame_ip_end, type_index);
@@ -4954,6 +5363,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                 uint32 opcode1;
 
                 read_leb_uint32(frame_ip, frame_ip_end, opcode1);
+                /* opcode1 was checked in loader and is no larger than
+                   UINT8_MAX */
                 opcode = (uint8)opcode1;
 
                 switch (opcode) {
@@ -5318,9 +5729,13 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
 #if WASM_ENABLE_SHARED_MEMORY != 0
             HANDLE_OP(WASM_OP_ATOMIC_PREFIX)
             {
-                uint32 offset = 0, align, addr;
+                uint32 offset = 0, align = 0, addr;
+                uint32 opcode1;
 
-                opcode = *frame_ip++;
+                read_leb_uint32(frame_ip, frame_ip_end, opcode1);
+                /* opcode1 was checked in loader and is no larger than
+                   UINT8_MAX */
+                opcode = (uint8)opcode1;
 
                 if (opcode != WASM_OP_ATOMIC_FENCE) {
                     read_leb_uint32(frame_ip, frame_ip_end, align);
@@ -5698,10 +6113,6 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
 #endif
 
 #if WASM_ENABLE_LABELS_AS_VALUES != 0
-        HANDLE_OP(WASM_OP_UNUSED_0x06)
-        HANDLE_OP(WASM_OP_UNUSED_0x07)
-        HANDLE_OP(WASM_OP_UNUSED_0x08)
-        HANDLE_OP(WASM_OP_UNUSED_0x09)
         HANDLE_OP(WASM_OP_UNUSED_0x0a)
 #if WASM_ENABLE_TAIL_CALL == 0
         HANDLE_OP(WASM_OP_RETURN_CALL)
@@ -5727,6 +6138,15 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
         HANDLE_OP(WASM_OP_BR_ON_NON_NULL)
         HANDLE_OP(WASM_OP_GC_PREFIX)
 #endif
+#if WASM_ENABLE_EXCE_HANDLING == 0
+        HANDLE_OP(WASM_OP_TRY)
+        HANDLE_OP(WASM_OP_CATCH)
+        HANDLE_OP(WASM_OP_THROW)
+        HANDLE_OP(WASM_OP_RETHROW)
+        HANDLE_OP(WASM_OP_DELEGATE)
+        HANDLE_OP(WASM_OP_CATCH_ALL)
+        HANDLE_OP(EXT_OP_TRY)
+#endif
 #if WASM_ENABLE_JIT != 0 && WASM_ENABLE_SIMD != 0
         /* SIMD isn't supported by interpreter, but when JIT is
            enabled, `iwasm --interp <wasm_file>` may be run to
@@ -5735,8 +6155,6 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
 #endif
         HANDLE_OP(WASM_OP_UNUSED_0x16)
         HANDLE_OP(WASM_OP_UNUSED_0x17)
-        HANDLE_OP(WASM_OP_UNUSED_0x18)
-        HANDLE_OP(WASM_OP_UNUSED_0x19)
         HANDLE_OP(WASM_OP_UNUSED_0x27)
         /* Used by fast interpreter */
         HANDLE_OP(EXT_OP_SET_LOCAL_FAST_I64)
@@ -5787,9 +6205,53 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
             if (cur_func->import_func_inst) {
                 wasm_interp_call_func_import(module, exec_env, cur_func,
                                              prev_frame);
+#if WASM_ENABLE_EXCE_HANDLING != 0
+                char uncaught_exception[128] = { 0 };
+                bool has_exception =
+                    wasm_copy_exception(module, uncaught_exception);
+                if (has_exception
+                    && strstr(uncaught_exception, "uncaught wasm exception")) {
+                    /* fix framesp */
+                    UPDATE_ALL_FROM_FRAME();
+
+                    uint32 import_exception;
+                    /* initialize imported exception index to be invalid */
+                    SET_INVALID_TAGINDEX(import_exception);
+
+                    /* pull external exception */
+                    uint32 ext_exception = POP_I32();
+
+                    /* external function came back with an exception or trap */
+                    /* lookup exception in import tags */
+                    WASMTagInstance *tag = module->e->tags;
+                    for (uint32 t = 0; t < module->module->import_tag_count;
+                         tag++, t++) {
+
+                        /* compare the module and the external index with the
+                         * imort tag data */
+                        if ((cur_func->u.func_import->import_module
+                             == tag->u.tag_import->import_module)
+                            && (ext_exception
+                                == tag->u.tag_import
+                                       ->import_tag_index_linked)) {
+                            /* set the import_exception to the import tag */
+                            import_exception = t;
+                            break;
+                        }
+                    }
+                    /*
+                     * excange the thrown exception (index valid in submodule)
+                     * with the imported exception index (valid in this module)
+                     * if the module did not import the exception,
+                     * that results in a "INVALID_TAGINDEX", that triggers
+                     * an CATCH_ALL block, if there is one.
+                     */
+                    PUSH_I32(import_exception);
+                }
+#endif /* end of WASM_ENABLE_EXCE_HANDLING != 0 */
             }
             else
-#endif
+#endif /* end of WASM_ENABLE_MULTI_MODULE != 0 */
             {
                 wasm_interp_call_func_native(module, exec_env, cur_func,
                                              prev_frame);
@@ -5807,14 +6269,51 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
             if (memory)
                 linear_mem_size = get_linear_mem_size();
 #endif
-            if (wasm_copy_exception(module, NULL))
+            if (wasm_copy_exception(module, NULL)) {
+#if WASM_ENABLE_EXCE_HANDLING != 0
+                /* the caller raised an exception */
+                char uncaught_exception[128] = { 0 };
+                bool has_exception =
+                    wasm_copy_exception(module, uncaught_exception);
+
+                /* libc_builtin signaled a "exception thrown by stdc++" trap */
+                if (has_exception
+                    && strstr(uncaught_exception,
+                              "exception thrown by stdc++")) {
+                    wasm_set_exception(module, NULL);
+
+                    /* setup internal c++ rethrow */
+                    exception_tag_index = 0;
+                    goto find_a_catch_handler;
+                }
+
+                /* when throw hits the end of a function it signalles with a
+                 * "uncaught wasm exception" trap */
+                if (has_exception
+                    && strstr(uncaught_exception, "uncaught wasm exception")) {
+                    wasm_set_exception(module, NULL);
+                    exception_tag_index = POP_I32();
+
+                    /* rethrow the exception into that frame */
+                    goto find_a_catch_handler;
+                }
+#endif /* WASM_ENABLE_EXCE_HANDLING != 0 */
                 goto got_exception;
+            }
         }
         else {
             WASMFunction *cur_wasm_func = cur_func->u.func;
             WASMFuncType *func_type;
             uint32 cell_num_of_local_stack;
 
+#if WASM_ENABLE_EXCE_HANDLING != 0
+            /* account for exception handlers */
+            /* bundle them here */
+            uint32 eh_size =
+                cur_wasm_func->exception_handler_count * sizeof(uint8 *);
+            cur_wasm_func->max_stack_cell_num += eh_size;
+#endif
+
             func_type = cur_wasm_func->func_type;
 
             cell_num_of_local_stack = cur_func->param_cell_num
@@ -5827,6 +6326,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
             /* area of frame_ref */
             all_cell_num += (cell_num_of_local_stack + 3) / 4;
 #endif
+
             /* param_cell_num, local_cell_num, max_stack_cell_num and
                max_block_num are all no larger than UINT16_MAX (checked
                in loader), all_cell_num must be smaller than 1MB */
@@ -5885,11 +6385,19 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
         FREE_FRAME(exec_env, frame);
         wasm_exec_env_set_cur_frame(exec_env, prev_frame);
 
-        if (!prev_frame->ip)
+        if (!prev_frame->ip) {
             /* Called from native. */
             return;
+        }
 
         RECOVER_CONTEXT(prev_frame);
+#if WASM_ENABLE_EXCE_HANDLING != 0
+        if (wasm_get_exception(module)) {
+            wasm_set_exception(module, NULL);
+            exception_tag_index = POP_I32();
+            goto find_a_catch_handler;
+        }
+#endif
         HANDLE_OP_END();
     }
 

+ 24 - 8
core/iwasm/interpreter/wasm_interp_fast.c

@@ -1752,6 +1752,20 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                 goto call_func_from_interp;
             }
 
+#if WASM_ENABLE_EXCE_HANDLING != 0
+            HANDLE_OP(WASM_OP_TRY)
+            HANDLE_OP(WASM_OP_CATCH)
+            HANDLE_OP(WASM_OP_THROW)
+            HANDLE_OP(WASM_OP_RETHROW)
+            HANDLE_OP(WASM_OP_DELEGATE)
+            HANDLE_OP(WASM_OP_CATCH_ALL)
+            HANDLE_OP(EXT_OP_TRY)
+            {
+                wasm_set_exception(module, "unsupported opcode");
+                goto got_exception;
+            }
+#endif
+
             /* parametric instructions */
             HANDLE_OP(WASM_OP_SELECT)
             {
@@ -5650,10 +5664,6 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
 #endif
 
 #if WASM_ENABLE_LABELS_AS_VALUES != 0
-        HANDLE_OP(WASM_OP_UNUSED_0x06)
-        HANDLE_OP(WASM_OP_UNUSED_0x07)
-        HANDLE_OP(WASM_OP_UNUSED_0x08)
-        HANDLE_OP(WASM_OP_UNUSED_0x09)
         HANDLE_OP(WASM_OP_UNUSED_0x0a)
 #if WASM_ENABLE_TAIL_CALL == 0
         HANDLE_OP(WASM_OP_RETURN_CALL)
@@ -5672,8 +5682,6 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
 #if WASM_ENABLE_GC == 0
         /* SELECT_T is converted to SELECT or SELECT_64 */
         HANDLE_OP(WASM_OP_SELECT_T)
-#endif
-#if WASM_ENABLE_GC == 0
         HANDLE_OP(WASM_OP_CALL_REF)
         HANDLE_OP(WASM_OP_RETURN_CALL_REF)
         HANDLE_OP(WASM_OP_REF_EQ)
@@ -5681,11 +5689,19 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
         HANDLE_OP(WASM_OP_BR_ON_NULL)
         HANDLE_OP(WASM_OP_BR_ON_NON_NULL)
         HANDLE_OP(WASM_OP_GC_PREFIX)
+#endif
+#if WASM_ENABLE_EXCE_HANDLING == 0
+        /* if exception handling is disabled, these opcodes issue a trap */
+        HANDLE_OP(WASM_OP_TRY)
+        HANDLE_OP(WASM_OP_CATCH)
+        HANDLE_OP(WASM_OP_THROW)
+        HANDLE_OP(WASM_OP_RETHROW)
+        HANDLE_OP(WASM_OP_DELEGATE)
+        HANDLE_OP(WASM_OP_CATCH_ALL)
+        HANDLE_OP(EXT_OP_TRY)
 #endif
         HANDLE_OP(WASM_OP_UNUSED_0x16)
         HANDLE_OP(WASM_OP_UNUSED_0x17)
-        HANDLE_OP(WASM_OP_UNUSED_0x18)
-        HANDLE_OP(WASM_OP_UNUSED_0x19)
         HANDLE_OP(WASM_OP_UNUSED_0x27)
         /* optimized op code */
         HANDLE_OP(WASM_OP_F32_STORE)

File diff suppressed because it is too large
+ 699 - 74
core/iwasm/interpreter/wasm_loader.c


+ 106 - 75
core/iwasm/interpreter/wasm_mini_loader.c

@@ -3507,6 +3507,17 @@ wasm_loader_find_block_addr(WASMExecEnv *exec_env, BlockAddr *block_addr_cache,
                 u8 = read_uint8(p); /* 0x00 */
                 break;
 
+#if WASM_ENABLE_EXCE_HANDLING != 0
+            case WASM_OP_TRY:
+            case WASM_OP_CATCH:
+            case WASM_OP_THROW:
+            case WASM_OP_RETHROW:
+            case WASM_OP_DELEGATE:
+            case WASM_OP_CATCH_ALL:
+                /* TODO */
+                return false;
+#endif
+
             case WASM_OP_DROP:
             case WASM_OP_SELECT:
             case WASM_OP_DROP_64:
@@ -3729,8 +3740,11 @@ wasm_loader_find_block_addr(WASMExecEnv *exec_env, BlockAddr *block_addr_cache,
                 uint32 opcode1;
 
                 read_leb_uint32(p, p_end, opcode1);
+                /* opcode1 was checked in wasm_loader_prepare_bytecode and
+                   is no larger than UINT8_MAX */
+                opcode = (uint8)opcode1;
 
-                switch (opcode1) {
+                switch (opcode) {
                     case WASM_OP_I32_TRUNC_SAT_S_F32:
                     case WASM_OP_I32_TRUNC_SAT_U_F32:
                     case WASM_OP_I32_TRUNC_SAT_S_F64:
@@ -3786,8 +3800,14 @@ wasm_loader_find_block_addr(WASMExecEnv *exec_env, BlockAddr *block_addr_cache,
 #if WASM_ENABLE_SHARED_MEMORY != 0
             case WASM_OP_ATOMIC_PREFIX:
             {
-                /* atomic_op (1 u8) + memarg (2 u32_leb) */
-                opcode = read_uint8(p);
+                uint32 opcode1;
+
+                /* atomic_op (u32_leb) + memarg (2 u32_leb) */
+                read_leb_uint32(p, p_end, opcode1);
+                /* opcode1 was checked in wasm_loader_prepare_bytecode and
+                   is no larger than UINT8_MAX */
+                opcode = (uint8)opcode1;
+
                 if (opcode != WASM_OP_ATOMIC_FENCE) {
                     skip_leb_uint32(p, p_end); /* align */
                     skip_leb_uint32(p, p_end); /* offset */
@@ -3851,6 +3871,8 @@ typedef struct BranchBlock {
     /* This is used to store available param num for if/else branch, so the else
      * opcode can know how many parameters should be copied to the stack */
     uint32 available_param_num;
+    /* This is used to recover dynamic offset for else branch */
+    uint16 start_dynamic_offset;
 #endif
 
     /* Indicate the operand stack is in polymorphic state.
@@ -5577,18 +5599,15 @@ fail:
  * 1) POP original parameter out;
  * 2) Push and copy original values to dynamic space.
  * The copy instruction format:
- *   Part a: available param count
+ *   Part a: param count
  *   Part b: all param total cell num
  *   Part c: each param's cell_num, src offset and dst offset
  *   Part d: each param's src offset
  *   Part e: each param's dst offset
- * Note: if the stack is in polymorphic state, the actual copied parameters may
- * be fewer than the defined number in block type
  */
 static bool
 copy_params_to_dynamic_space(WASMLoaderContext *loader_ctx, bool is_if_block,
-                             uint32 *p_available_param_count, char *error_buf,
-                             uint32 error_buf_size)
+                             char *error_buf, uint32 error_buf_size)
 {
     bool ret = false;
     int16 *frame_offset = NULL;
@@ -5600,91 +5619,72 @@ copy_params_to_dynamic_space(WASMLoaderContext *loader_ctx, bool is_if_block,
     BlockType *block_type = &block->block_type;
     WASMFuncType *wasm_type = block_type->u.type;
     uint32 param_count = block_type->u.type->param_count;
-    uint32 available_param_count = 0;
     int16 condition_offset = 0;
     bool disable_emit = false;
     int16 operand_offset = 0;
-    uint64 size;
-
-    if (is_if_block)
-        condition_offset = *loader_ctx->frame_offset;
-
-    /* POP original parameter out */
-    for (i = 0; i < param_count; i++) {
-        int32 available_stack_cell =
-            (int32)(loader_ctx->stack_cell_num - block->stack_cell_num);
 
-        if (available_stack_cell <= 0 && block->is_stack_polymorphic)
-            break;
-
-        POP_OFFSET_TYPE(wasm_type->types[param_count - i - 1]);
-        wasm_loader_emit_backspace(loader_ctx, sizeof(int16));
-    }
-    available_param_count = i;
-
-    size =
-        (uint64)available_param_count * (sizeof(*cells) + sizeof(*src_offsets));
+    uint64 size = (uint64)param_count * (sizeof(*cells) + sizeof(*src_offsets));
+    bh_assert(size > 0);
 
     /* For if block, we also need copy the condition operand offset. */
     if (is_if_block)
         size += sizeof(*cells) + sizeof(*src_offsets);
 
     /* Allocate memory for the emit data */
-    if ((size > 0)
-        && !(emit_data = loader_malloc(size, error_buf, error_buf_size)))
+    if (!(emit_data = loader_malloc(size, error_buf, error_buf_size)))
         return false;
 
     cells = emit_data;
     src_offsets = (int16 *)(cells + param_count);
 
+    if (is_if_block)
+        condition_offset = *loader_ctx->frame_offset;
+
+    /* POP original parameter out */
+    for (i = 0; i < param_count; i++) {
+        POP_OFFSET_TYPE(wasm_type->types[param_count - i - 1]);
+        wasm_loader_emit_backspace(loader_ctx, sizeof(int16));
+    }
     frame_offset = loader_ctx->frame_offset;
 
     /* Get each param's cell num and src offset */
-    for (i = 0; i < available_param_count; i++) {
+    for (i = 0; i < param_count; i++) {
         cell = (uint8)wasm_value_type_cell_num(wasm_type->types[i]);
         cells[i] = cell;
         src_offsets[i] = *frame_offset;
         frame_offset += cell;
     }
-
     /* emit copy instruction */
     emit_label(EXT_OP_COPY_STACK_VALUES);
     /* Part a) */
-    emit_uint32(loader_ctx, is_if_block ? available_param_count + 1
-                                        : available_param_count);
+    emit_uint32(loader_ctx, is_if_block ? param_count + 1 : param_count);
     /* Part b) */
     emit_uint32(loader_ctx, is_if_block ? wasm_type->param_cell_num + 1
                                         : wasm_type->param_cell_num);
     /* Part c) */
-    for (i = 0; i < available_param_count; i++)
+    for (i = 0; i < param_count; i++)
         emit_byte(loader_ctx, cells[i]);
     if (is_if_block)
         emit_byte(loader_ctx, 1);
 
     /* Part d) */
-    for (i = 0; i < available_param_count; i++)
+    for (i = 0; i < param_count; i++)
         emit_operand(loader_ctx, src_offsets[i]);
     if (is_if_block)
         emit_operand(loader_ctx, condition_offset);
 
     /* Part e) */
     /* Push to dynamic space. The push will emit the dst offset. */
-    for (i = 0; i < available_param_count; i++)
+    for (i = 0; i < param_count; i++)
         PUSH_OFFSET_TYPE(wasm_type->types[i]);
     if (is_if_block)
         PUSH_OFFSET_TYPE(VALUE_TYPE_I32);
 
-    if (p_available_param_count) {
-        *p_available_param_count = available_param_count;
-    }
-
     ret = true;
 
 fail:
     /* Free the emit data */
-    if (emit_data) {
-        wasm_runtime_free(emit_data);
-    }
+    wasm_runtime_free(emit_data);
 
     return ret;
 }
@@ -5886,6 +5886,7 @@ re_scan:
 
                     BranchBlock *cur_block = loader_ctx->frame_csp - 1;
 #if WASM_ENABLE_FAST_INTERP != 0
+                    uint32 cell_num;
                     available_params = block_type.u.type->param_count;
 #endif
                     for (i = 0; i < block_type.u.type->param_count; i++) {
@@ -5903,6 +5904,13 @@ re_scan:
 
                         POP_TYPE(
                             wasm_type->types[wasm_type->param_count - i - 1]);
+#if WASM_ENABLE_FAST_INTERP != 0
+                        /* decrease the frame_offset pointer accordingly to keep
+                         * consistent with frame_ref stack */
+                        cell_num = wasm_value_type_cell_num(
+                            wasm_type->types[wasm_type->param_count - i - 1]);
+                        loader_ctx->frame_offset -= cell_num;
+#endif
                     }
                 }
 
@@ -5912,12 +5920,26 @@ re_scan:
                 /* Pass parameters to block */
                 if (BLOCK_HAS_PARAM(block_type)) {
                     for (i = 0; i < block_type.u.type->param_count; i++) {
-                        PUSH_TYPE(block_type.u.type->types[i]);
 #if WASM_ENABLE_FAST_INTERP != 0
+                        uint32 cell_num = wasm_value_type_cell_num(
+                            block_type.u.type->types[i]);
                         if (i >= available_params) {
-                            PUSH_OFFSET_TYPE(block_type.u.type->types[i]);
+                            /* If there isn't enough data on stack, push a dummy
+                             * offset to keep the stack consistent with
+                             * frame_ref.
+                             * Since the stack is already in polymorphic state,
+                             * the opcode will not be executed, so the dummy
+                             * offset won't cause any error */
+                            *loader_ctx->frame_offset++ = 0;
+                            if (cell_num > 1) {
+                                *loader_ctx->frame_offset++ = 0;
+                            }
+                        }
+                        else {
+                            loader_ctx->frame_offset += cell_num;
                         }
 #endif
+                        PUSH_TYPE(block_type.u.type->types[i]);
                     }
                 }
 
@@ -5926,9 +5948,8 @@ re_scan:
                     skip_label();
                     if (BLOCK_HAS_PARAM(block_type)) {
                         /* Make sure params are in dynamic space */
-                        if (!copy_params_to_dynamic_space(loader_ctx, false,
-                                                          NULL, error_buf,
-                                                          error_buf_size))
+                        if (!copy_params_to_dynamic_space(
+                                loader_ctx, false, error_buf, error_buf_size))
                             goto fail;
                     }
                     if (opcode == WASM_OP_LOOP) {
@@ -5955,17 +5976,21 @@ re_scan:
                      * recover them before entering else branch.
                      *
                      */
-                    if (if_condition_available && BLOCK_HAS_PARAM(block_type)) {
+                    if (BLOCK_HAS_PARAM(block_type)) {
                         uint64 size;
 
-                        /* skip the if condition operand offset */
-                        wasm_loader_emit_backspace(loader_ctx, sizeof(int16));
+                        /* In polymorphic state, there may be no if condition on
+                         * the stack, so the offset may not emitted */
+                        if (if_condition_available) {
+                            /* skip the if condition operand offset */
+                            wasm_loader_emit_backspace(loader_ctx,
+                                                       sizeof(int16));
+                        }
                         /* skip the if label */
                         skip_label();
                         /* Emit a copy instruction */
                         if (!copy_params_to_dynamic_space(
-                                loader_ctx, true, &block->available_param_num,
-                                error_buf, error_buf_size))
+                                loader_ctx, true, error_buf, error_buf_size))
                             goto fail;
 
                         /* Emit the if instruction */
@@ -5986,9 +6011,8 @@ re_scan:
                                         - size / sizeof(int16),
                                     (uint32)size);
                     }
-                    else {
-                        block->available_param_num = 0;
-                    }
+
+                    block->start_dynamic_offset = loader_ctx->dynamic_offset;
 
                     emit_empty_label_addr_and_frame_ip(PATCH_ELSE);
                     emit_empty_label_addr_and_frame_ip(PATCH_END);
@@ -6032,21 +6056,13 @@ re_scan:
 
 #if WASM_ENABLE_FAST_INTERP != 0
                 /* Recover top param_count values of frame_offset stack */
-                if (block->available_param_num) {
+                if (BLOCK_HAS_PARAM((block_type))) {
                     uint32 size;
-                    size = sizeof(int16) * block->available_param_num;
+                    size = sizeof(int16) * block_type.u.type->param_cell_num;
                     bh_memcpy_s(loader_ctx->frame_offset, size,
                                 block->param_frame_offsets, size);
                     loader_ctx->frame_offset += (size / sizeof(int16));
-
-                    /* recover dynamic offset */
-                    for (i = 0; i < block->available_param_num; i++) {
-                        if (block->param_frame_offsets[i]
-                            >= loader_ctx->dynamic_offset) {
-                            loader_ctx->dynamic_offset =
-                                block->param_frame_offsets[i] + 1;
-                        }
-                    }
+                    loader_ctx->dynamic_offset = block->start_dynamic_offset;
                 }
 #endif
 
@@ -6226,11 +6242,11 @@ re_scan:
                      idx--) {
                     ret_type = *(func->func_type->types
                                  + func->func_type->param_count + idx);
-                    POP_TYPE(ret_type);
 #if WASM_ENABLE_FAST_INTERP != 0
                     /* emit the offset after return opcode */
                     POP_OFFSET_TYPE(ret_type);
 #endif
+                    POP_TYPE(ret_type);
                 }
 
                 RESET_STACK();
@@ -6269,10 +6285,10 @@ re_scan:
                 if (func_type->param_count > 0) {
                     for (idx = (int32)(func_type->param_count - 1); idx >= 0;
                          idx--) {
-                        POP_TYPE(func_type->types[idx]);
 #if WASM_ENABLE_FAST_INTERP != 0
                         POP_OFFSET_TYPE(func_type->types[idx]);
 #endif
+                        POP_TYPE(func_type->types[idx]);
                     }
                 }
 
@@ -6350,10 +6366,10 @@ re_scan:
                 if (func_type->param_count > 0) {
                     for (idx = (int32)(func_type->param_count - 1); idx >= 0;
                          idx--) {
-                        POP_TYPE(func_type->types[idx]);
 #if WASM_ENABLE_FAST_INTERP != 0
                         POP_OFFSET_TYPE(func_type->types[idx]);
 #endif
+                        POP_TYPE(func_type->types[idx]);
                     }
                 }
 
@@ -6391,6 +6407,18 @@ re_scan:
                 break;
             }
 
+#if WASM_ENABLE_EXCE_HANDLING != 0
+            case WASM_OP_TRY:
+            case WASM_OP_CATCH:
+            case WASM_OP_THROW:
+            case WASM_OP_RETHROW:
+            case WASM_OP_DELEGATE:
+            case WASM_OP_CATCH_ALL:
+                /* TODO */
+                set_error_buf(error_buf, error_buf_size, "unsupported opcode");
+                goto fail;
+#endif
+
             case WASM_OP_DROP:
             {
                 BranchBlock *cur_block = loader_ctx->frame_csp - 1;
@@ -7664,11 +7692,14 @@ re_scan:
 #if WASM_ENABLE_SHARED_MEMORY != 0
             case WASM_OP_ATOMIC_PREFIX:
             {
-                opcode = read_uint8(p);
+                uint32 opcode1;
+
+                read_leb_uint32(p, p_end, opcode1);
+
 #if WASM_ENABLE_FAST_INTERP != 0
-                emit_byte(loader_ctx, opcode);
+                emit_byte(loader_ctx, opcode1);
 #endif
-                if (opcode != WASM_OP_ATOMIC_FENCE) {
+                if (opcode1 != WASM_OP_ATOMIC_FENCE) {
                     CHECK_MEMORY();
                     read_leb_uint32(p, p_end, align);      /* align */
                     read_leb_uint32(p, p_end, mem_offset); /* offset */
@@ -7679,7 +7710,7 @@ re_scan:
 #if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0
                 func->has_memory_operations = true;
 #endif
-                switch (opcode) {
+                switch (opcode1) {
                     case WASM_OP_ATOMIC_NOTIFY:
                         POP2_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32);
                         break;

+ 17 - 14
core/iwasm/interpreter/wasm_opcode.h

@@ -20,11 +20,10 @@ typedef enum WASMOpcode {
     WASM_OP_LOOP = 0x03,        /* loop */
     WASM_OP_IF = 0x04,          /* if */
     WASM_OP_ELSE = 0x05,        /* else */
-
-    WASM_OP_UNUSED_0x06 = 0x06,
-    WASM_OP_UNUSED_0x07 = 0x07,
-    WASM_OP_UNUSED_0x08 = 0x08,
-    WASM_OP_UNUSED_0x09 = 0x09,
+    WASM_OP_TRY = 0x06,         /* try */
+    WASM_OP_CATCH = 0x07,       /* catch* */
+    WASM_OP_THROW = 0x08,       /* throw of a try catch */
+    WASM_OP_RETHROW = 0x09,     /* rethrow of a try catch */
     WASM_OP_UNUSED_0x0a = 0x0a,
 
     WASM_OP_END = 0x0b,                  /* end */
@@ -41,8 +40,9 @@ typedef enum WASMOpcode {
 
     WASM_OP_UNUSED_0x16 = 0x16,
     WASM_OP_UNUSED_0x17 = 0x17,
-    WASM_OP_UNUSED_0x18 = 0x18,
-    WASM_OP_UNUSED_0x19 = 0x19,
+
+    WASM_OP_DELEGATE = 0x18,  /* delegate block of the try catch*/
+    WASM_OP_CATCH_ALL = 0x19, /* a catch_all handler in a try block */
 
     /* parametric instructions */
     WASM_OP_DROP = 0x1a,     /* drop */
@@ -272,8 +272,10 @@ typedef enum WASMOpcode {
     EXT_OP_IF = 0xd9,             /* if with blocktype */
     EXT_OP_BR_TABLE_CACHE = 0xda, /* br_table from cache */
 
+    EXT_OP_TRY = 0xdb, /* try block with blocktype */
+
 #if WASM_ENABLE_DEBUG_INTERP != 0
-    DEBUG_OP_BREAK = 0xdb, /* debug break point */
+    DEBUG_OP_BREAK = 0xdc, /* debug break point */
 #endif
 
     /* Post-MVP extend op prefix */
@@ -800,10 +802,10 @@ typedef enum WASMAtomicEXTOpcode {
         HANDLE_OPCODE(WASM_OP_LOOP),                 /* 0x03 */ \
         HANDLE_OPCODE(WASM_OP_IF),                   /* 0x04 */ \
         HANDLE_OPCODE(WASM_OP_ELSE),                 /* 0x05 */ \
-        HANDLE_OPCODE(WASM_OP_UNUSED_0x06),          /* 0x06 */ \
-        HANDLE_OPCODE(WASM_OP_UNUSED_0x07),          /* 0x07 */ \
-        HANDLE_OPCODE(WASM_OP_UNUSED_0x08),          /* 0x08 */ \
-        HANDLE_OPCODE(WASM_OP_UNUSED_0x09),          /* 0x09 */ \
+        HANDLE_OPCODE(WASM_OP_TRY),                  /* 0x06 */ \
+        HANDLE_OPCODE(WASM_OP_CATCH),                /* 0x07 */ \
+        HANDLE_OPCODE(WASM_OP_THROW),                /* 0x08 */ \
+        HANDLE_OPCODE(WASM_OP_RETHROW),              /* 0x09 */ \
         HANDLE_OPCODE(WASM_OP_UNUSED_0x0a),          /* 0x0a */ \
         HANDLE_OPCODE(WASM_OP_END),                  /* 0x0b */ \
         HANDLE_OPCODE(WASM_OP_BR),                   /* 0x0c */ \
@@ -818,8 +820,8 @@ typedef enum WASMAtomicEXTOpcode {
         HANDLE_OPCODE(WASM_OP_RETURN_CALL_REF),      /* 0x15 */ \
         HANDLE_OPCODE(WASM_OP_UNUSED_0x16),          /* 0x16 */ \
         HANDLE_OPCODE(WASM_OP_UNUSED_0x17),          /* 0x17 */ \
-        HANDLE_OPCODE(WASM_OP_UNUSED_0x18),          /* 0x18 */ \
-        HANDLE_OPCODE(WASM_OP_UNUSED_0x19),          /* 0x19 */ \
+        HANDLE_OPCODE(WASM_OP_DELEGATE),             /* 0x18 */ \
+        HANDLE_OPCODE(WASM_OP_CATCH_ALL),            /* 0x19 */ \
         HANDLE_OPCODE(WASM_OP_DROP),                 /* 0x1a */ \
         HANDLE_OPCODE(WASM_OP_SELECT),               /* 0x1b */ \
         HANDLE_OPCODE(WASM_OP_SELECT_T),             /* 0x1c */ \
@@ -1013,6 +1015,7 @@ typedef enum WASMAtomicEXTOpcode {
         HANDLE_OPCODE(EXT_OP_LOOP),                  /* 0xd8 */ \
         HANDLE_OPCODE(EXT_OP_IF),                    /* 0xd9 */ \
         HANDLE_OPCODE(EXT_OP_BR_TABLE_CACHE),        /* 0xda */ \
+        HANDLE_OPCODE(EXT_OP_TRY),                   /* 0xdb */ \
         SET_GOTO_TABLE_ELEM(WASM_OP_GC_PREFIX),      /* 0xfb */ \
         SET_GOTO_TABLE_ELEM(WASM_OP_MISC_PREFIX),    /* 0xfc */ \
         SET_GOTO_TABLE_SIMD_PREFIX_ELEM()            /* 0xfd */ \

+ 181 - 2
core/iwasm/interpreter/wasm_runtime.c

@@ -765,6 +765,101 @@ functions_instantiate(const WASMModule *module, WASMModuleInstance *module_inst,
     return functions;
 }
 
+#if WASM_ENABLE_TAGS != 0
+/**
+ * Destroy tags instances.
+ */
+static void
+tags_deinstantiate(WASMTagInstance *tags, void **import_tag_ptrs)
+{
+    if (tags) {
+        wasm_runtime_free(tags);
+    }
+    if (import_tag_ptrs) {
+        wasm_runtime_free(import_tag_ptrs);
+    }
+}
+
+/**
+ * Instantiate tags in a module.
+ */
+static WASMTagInstance *
+tags_instantiate(const WASMModule *module, WASMModuleInstance *module_inst,
+                 char *error_buf, uint32 error_buf_size)
+{
+    WASMImport *import;
+    uint32 i, tag_count = module->import_tag_count + module->tag_count;
+    uint64 total_size = sizeof(WASMTagInstance) * (uint64)tag_count;
+    WASMTagInstance *tags, *tag;
+
+    if (!(tags = runtime_malloc(total_size, error_buf, error_buf_size))) {
+        return NULL;
+    }
+
+    total_size = sizeof(void *) * (uint64)module->import_tag_count;
+    if (total_size > 0
+        && !(module_inst->e->import_tag_ptrs =
+                 runtime_malloc(total_size, error_buf, error_buf_size))) {
+        wasm_runtime_free(tags);
+        return NULL;
+    }
+
+    /* instantiate tags from import section */
+    tag = tags;
+    import = module->import_tags;
+    for (i = 0; i < module->import_tag_count; i++, import++) {
+        tag->is_import_tag = true;
+        tag->u.tag_import = &import->u.tag;
+        tag->type = import->u.tag.type;
+        tag->attribute = import->u.tag.attribute;
+#if WASM_ENABLE_MULTI_MODULE != 0
+        if (import->u.tag.import_module) {
+            if (!(tag->import_module_inst = get_sub_module_inst(
+                      module_inst, import->u.tag.import_module))) {
+                set_error_buf(error_buf, error_buf_size, "unknown tag");
+                goto fail;
+            }
+
+            if (!(tag->import_tag_inst =
+                      wasm_lookup_tag(tag->import_module_inst,
+                                      import->u.tag.field_name, NULL))) {
+                set_error_buf(error_buf, error_buf_size, "unknown tag");
+                goto fail;
+            }
+
+            /* Copy the imported tag to current instance */
+            module_inst->e->import_tag_ptrs[i] =
+                tag->u.tag_import->import_tag_linked;
+        }
+#endif
+        tag++;
+    }
+
+    /* instantiate tags from tag section */
+    for (i = 0; i < module->tag_count; i++) {
+        tag->is_import_tag = false;
+        tag->type = module->tags[i]->type;
+        tag->u.tag = module->tags[i];
+
+#if WASM_ENABLE_FAST_INTERP != 0
+        /* tag->const_cell_num = function->u.func->const_cell_num; */
+#endif
+        tag++;
+    }
+    bh_assert((uint32)(tag - tags) == tag_count);
+
+    return tags;
+
+#if WASM_ENABLE_MULTI_MODULE != 0
+fail:
+    tags_deinstantiate(tags, module_inst->e->import_tag_ptrs);
+    /* clean up */
+    module_inst->e->import_tag_ptrs = NULL;
+    return NULL;
+#endif
+}
+#endif /* end of WASM_ENABLE_TAGS != 0 */
+
 /**
  * Destroy global instances.
  */
@@ -1091,6 +1186,52 @@ export_functions_instantiate(const WASMModule *module,
     return export_funcs;
 }
 
+#if WASM_ENABLE_TAGS != 0
+/**
+ * Destroy export function instances.
+ */
+static void
+export_tags_deinstantiate(WASMExportTagInstance *tags)
+{
+    if (tags)
+        wasm_runtime_free(tags);
+}
+
+/**
+ * Instantiate export functions in a module.
+ */
+static WASMExportTagInstance *
+export_tags_instantiate(const WASMModule *module,
+                        WASMModuleInstance *module_inst,
+                        uint32 export_tag_count, char *error_buf,
+                        uint32 error_buf_size)
+{
+    WASMExportTagInstance *export_tags, *export_tag;
+    WASMExport *export = module->exports;
+    uint32 i;
+    uint64 total_size =
+        sizeof(WASMExportTagInstance) * (uint64)export_tag_count;
+
+    if (!(export_tag = export_tags =
+              runtime_malloc(total_size, error_buf, error_buf_size))) {
+        return NULL;
+    }
+
+    for (i = 0; i < module->export_count; i++, export ++)
+        if (export->kind == EXPORT_KIND_TAG) {
+            export_tag->name = export->name;
+
+            bh_assert(module_inst->e->tags);
+
+            export_tag->tag = &module_inst->e->tags[export->index];
+            export_tag++;
+        }
+
+    bh_assert((uint32)(export_tag - export_tags) == export_tag_count);
+    return export_tags;
+}
+#endif /* end of WASM_ENABLE_TAGS != 0 */
+
 #if WASM_ENABLE_MULTI_MODULE != 0
 static void
 export_globals_deinstantiate(WASMExportGlobInstance *globals)
@@ -2030,6 +2171,9 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent,
     module_inst->table_count = module->import_table_count + module->table_count;
     module_inst->e->function_count =
         module->import_function_count + module->function_count;
+#if WASM_ENABLE_TAGS != 0
+    module_inst->e->tag_count = module->import_tag_count + module->tag_count;
+#endif
 
     /* export */
     module_inst->export_func_count = get_export_count(module, EXPORT_KIND_FUNC);
@@ -2038,11 +2182,15 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent,
         get_export_count(module, EXPORT_KIND_TABLE);
     module_inst->export_memory_count =
         get_export_count(module, EXPORT_KIND_MEMORY);
+#if WASM_ENABLE_TAGS != 0
+    module_inst->e->export_tag_count =
+        get_export_count(module, EXPORT_KIND_TAG);
+#endif
     module_inst->export_global_count =
         get_export_count(module, EXPORT_KIND_GLOBAL);
 #endif
 
-    /* Instantiate memories/tables/functions */
+    /* Instantiate memories/tables/functions/tags */
     if ((module_inst->memory_count > 0
          && !(module_inst->memories =
                   memories_instantiate(module, module_inst, parent, heap_size,
@@ -2058,6 +2206,15 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent,
             && !(module_inst->export_functions = export_functions_instantiate(
                      module, module_inst, module_inst->export_func_count,
                      error_buf, error_buf_size)))
+#if WASM_ENABLE_TAGS != 0
+        || (module_inst->e->tag_count > 0
+            && !(module_inst->e->tags = tags_instantiate(
+                     module, module_inst, error_buf, error_buf_size)))
+        || (module_inst->e->export_tag_count > 0
+            && !(module_inst->e->export_tags = export_tags_instantiate(
+                     module, module_inst, module_inst->e->export_tag_count,
+                     error_buf, error_buf_size)))
+#endif
 #if WASM_ENABLE_MULTI_MODULE != 0
         || (module_inst->export_global_count > 0
             && !(module_inst->export_globals = export_globals_instantiate(
@@ -2075,7 +2232,6 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent,
     ) {
         goto fail;
     }
-
     if (global_count > 0) {
         /* Initialize the global data */
         global_data = module_inst->global_data;
@@ -2832,8 +2988,16 @@ wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst)
     tables_deinstantiate(module_inst);
     functions_deinstantiate(module_inst->e->functions,
                             module_inst->e->function_count);
+#if WASM_ENABLE_TAGS != 0
+    tags_deinstantiate(module_inst->e->tags, module_inst->e->import_tag_ptrs);
+#endif
+
     globals_deinstantiate(module_inst->e->globals);
     export_functions_deinstantiate(module_inst->export_functions);
+#if WASM_ENABLE_TAGS != 0
+    export_tags_deinstantiate(module_inst->e->export_tags);
+#endif
+
 #if WASM_ENABLE_MULTI_MODULE != 0
     export_globals_deinstantiate(module_inst->export_globals);
 #endif
@@ -2923,6 +3087,21 @@ wasm_lookup_table(const WASMModuleInstance *module_inst, const char *name)
     (void)module_inst->export_tables;
     return module_inst->tables[0];
 }
+
+#if WASM_ENABLE_TAGS != 0
+WASMTagInstance *
+wasm_lookup_tag(const WASMModuleInstance *module_inst, const char *name,
+                const char *signature)
+{
+    uint32 i;
+    for (i = 0; i < module_inst->e->export_tag_count; i++)
+        if (!strcmp(module_inst->e->export_tags[i].name, name))
+            return module_inst->e->export_tags[i].tag;
+    (void)signature;
+    return NULL;
+}
+#endif
+
 #endif
 
 #ifdef OS_ENABLE_HW_BOUND_CHECK

+ 49 - 0
core/iwasm/interpreter/wasm_runtime.h

@@ -28,6 +28,9 @@ typedef struct WASMFunctionInstance WASMFunctionInstance;
 typedef struct WASMMemoryInstance WASMMemoryInstance;
 typedef struct WASMTableInstance WASMTableInstance;
 typedef struct WASMGlobalInstance WASMGlobalInstance;
+#if WASM_ENABLE_TAGS != 0
+typedef struct WASMTagInstance WASMTagInstance;
+#endif
 
 /**
  * When LLVM JIT, WAMR compiler or AOT is enabled, we should ensure that
@@ -226,6 +229,30 @@ struct WASMFunctionInstance {
 #endif
 };
 
+#if WASM_ENABLE_TAGS != 0
+struct WASMTagInstance {
+    bool is_import_tag;
+    /* tag attribute */
+    uint8 attribute;
+    /* tag type index */
+    uint32 type;
+    union {
+        WASMTagImport *tag_import;
+        WASMTag *tag;
+    } u;
+
+#if WASM_ENABLE_MULTI_MODULE != 0
+    WASMModuleInstance *import_module_inst;
+    WASMTagInstance *import_tag_inst;
+#endif
+};
+#endif
+
+#if WASM_ENABLE_EXCE_HANDLING != 0
+#define INVALID_TAGINDEX ((uint32)0xFFFFFFFF)
+#define SET_INVALID_TAGINDEX(tag) (tag = INVALID_TAGINDEX)
+#define IS_INVALID_TAGINDEX(tag) ((tag & INVALID_TAGINDEX) == INVALID_TAGINDEX)
+#endif
 typedef struct WASMExportFuncInstance {
     char *name;
     WASMFunctionInstance *function;
@@ -246,6 +273,13 @@ typedef struct WASMExportMemInstance {
     WASMMemoryInstance *memory;
 } WASMExportMemInstance;
 
+#if WASM_ENABLE_TAGS != 0
+typedef struct WASMExportTagInstance {
+    char *name;
+    WASMTagInstance *tag;
+} WASMExportTagInstance;
+#endif
+
 /* wasm-c-api import function info */
 typedef struct CApiFuncImport {
     /* host func pointer after linked */
@@ -305,6 +339,14 @@ typedef struct WASMModuleInstanceExtra {
     WASMTableInstance **table_insts_linked;
 #endif
 
+#if WASM_ENABLE_TAGS != 0
+    uint32 tag_count;
+    uint32 export_tag_count;
+    WASMTagInstance *tags;
+    WASMExportTagInstance *export_tags;
+    void **import_tag_ptrs;
+#endif
+
 #if WASM_ENABLE_MEMORY_PROFILING != 0
     uint32 max_aux_stack_used;
 #endif
@@ -503,6 +545,13 @@ wasm_lookup_memory(const WASMModuleInstance *module_inst, const char *name);
 
 WASMTableInstance *
 wasm_lookup_table(const WASMModuleInstance *module_inst, const char *name);
+
+#if WASM_ENABLE_TAGS != 0
+WASMTagInstance *
+wasm_lookup_tag(const WASMModuleInstance *module_inst, const char *name,
+                const char *signature);
+#endif
+
 #endif
 
 bool

+ 1 - 1
core/shared/platform/common/freertos/freertos_thread.c

@@ -204,7 +204,7 @@ os_thread_wrapper(void *arg)
     thread_data_list_add(thread_data);
 
     thread_data->start_routine(thread_data->arg);
-    os_thread_cleanup();
+    os_thread_exit(NULL);
 }
 
 int

+ 1 - 0
core/shared/platform/common/posix/posix_memmap.c

@@ -7,6 +7,7 @@
 
 #if defined(__APPLE__) || defined(__MACH__)
 #include <libkern/OSCacheControl.h>
+#include <TargetConditionals.h>
 #endif
 
 #ifndef BH_ENABLE_TRACE_MMAP

+ 4 - 0
core/shared/platform/common/posix/posix_thread.c

@@ -9,6 +9,10 @@
 #include "platform_api_vmcore.h"
 #include "platform_api_extension.h"
 
+#if defined(__APPLE__) || defined(__MACH__)
+#include <TargetConditionals.h>
+#endif
+
 typedef struct {
     thread_start_routine_t start;
     void *arg;

+ 1 - 1
core/version.h

@@ -7,5 +7,5 @@
 #define _WAMR_VERSION_H_
 #define WAMR_VERSION_MAJOR 1
 #define WAMR_VERSION_MINOR 3
-#define WAMR_VERSION_PATCH 1
+#define WAMR_VERSION_PATCH 2
 #endif

+ 1 - 1
doc/multi_module.md

@@ -6,7 +6,7 @@ WAMR loads all dependencies recursively according to the _import section_ of a m
 
 > WAMR only implements the load-time dynamic linking. Please refer to [dynamic linking](https://webassembly.org/docs/dynamic-linking/) for more details.
 
-WAMR follows [WASI Command/Reactor Model](https://github.com/WebAssembly/WASI/blob/main/design/application-abi.md#current-unstable-abi). The WASI model separates modules into commands and reactors. A Command is the main module that requires exports of reactors(submodules).
+WAMR follows [WASI Command/Reactor Model](https://github.com/WebAssembly/WASI/blob/main/legacy/application-abi.md#current-unstable-abi). The WASI model separates modules into commands and reactors. A Command is the main module that requires exports of reactors(submodules).
 
 if `WASM_ENABLE_LIBC_WASI` is enabled, any module imports a WASI APIs, like `(import "wasi_snapshot_preview1" "XXX")`, should follow restrictions of the _WASI application ABI_:
 

+ 8 - 0
product-mini/platforms/nuttx/wamr.mk

@@ -393,6 +393,14 @@ else
 CFLAGS += -DWASM_ENABLE_TAIL_CALL=0
 endif
 
+ifeq ($(CONFIG_INTERPRETERS_WAMR_ENABLE_EXCE_HANDLING),y)
+CFLAGS += -DWASM_ENABLE_EXCE_HANDLING=1
+CFLAGS += -DWASM_ENABLE_TAGS=1
+else
+CFLAGS += -DWASM_ENABLE_EXCE_HANDLING=0
+CFLAGS += -DWASM_ENABLE_TAGS=0
+endif
+
 CFLAGS += -Wno-strict-prototypes -Wno-shadow -Wno-unused-variable
 CFLAGS += -Wno-int-conversion -Wno-implicit-function-declaration
 

+ 36 - 2
tests/wamr-test-suites/spec-test-script/all.py

@@ -47,6 +47,7 @@ IWASM_CMD = get_iwasm_cmd(PLATFORM_NAME)
 IWASM_SGX_CMD = "../../../product-mini/platforms/linux-sgx/enclave-sample/iwasm"
 IWASM_QEMU_CMD = "iwasm"
 SPEC_TEST_DIR = "spec/test/core"
+EXCE_HANDLING_DIR = "exception-handling/test/core"
 WAST2WASM_CMD = exe_file_path("./wabt/out/gcc/Release/wat2wasm")
 SPEC_INTERPRETER_CMD = "spec/interpreter/wasm"
 WAMRC_CMD = "../../../wamr-compiler/build/wamrc"
@@ -78,8 +79,10 @@ def ignore_the_case(
     simd_flag=False,
     gc_flag=False,
     xip_flag=False,
+    eh_flag=False,
     qemu_flag=False,
 ):
+
     if case_name in ["comments", "inline-module", "names"]:
         return True
 
@@ -126,7 +129,7 @@ def ignore_the_case(
     return False
 
 
-def preflight_check(aot_flag):
+def preflight_check(aot_flag, eh_flag):
     if not pathlib.Path(SPEC_TEST_DIR).resolve().exists():
         print(f"Can not find {SPEC_TEST_DIR}")
         return False
@@ -139,6 +142,10 @@ def preflight_check(aot_flag):
         print(f"Can not find {WAMRC_CMD}")
         return False
 
+    if eh_flag and not pathlib.Path(EXCE_HANDLING_DIR).resolve().exists():
+        print(f"Can not find {EXCE_HANDLING_DIR}")
+        return False
+
     return True
 
 
@@ -151,6 +158,7 @@ def test_case(
     multi_thread_flag=False,
     simd_flag=False,
     xip_flag=False,
+    eh_flag=False,
     clean_up_flag=True,
     verbose_flag=True,
     gc_flag=False,
@@ -195,6 +203,9 @@ def test_case(
     if xip_flag:
         CMD.append("--xip")
 
+    if eh_flag:
+        CMD.append("--eh")
+
     if qemu_flag:
         CMD.append("--qemu")
         CMD.append("--qemu-firmware")
@@ -268,6 +279,7 @@ def test_suite(
     multi_thread_flag=False,
     simd_flag=False,
     xip_flag=False,
+    eh_flag=False,
     clean_up_flag=True,
     verbose_flag=True,
     gc_flag=False,
@@ -291,6 +303,15 @@ def test_suite(
         gc_case_list = sorted(suite_path.glob("gc/*.wast"))
         case_list.extend(gc_case_list)
 
+    if eh_flag:
+        eh_path = pathlib.Path(EXCE_HANDLING_DIR).resolve()
+        if not eh_path.exists():
+            print(f"can not find spec test cases at {eh_path}")
+            return False
+        eh_case_list = sorted(eh_path.glob("*.wast"))
+        eh_case_list_include = [test for test in eh_case_list if test.stem in ["throw", "tag", "try_catch", "rethrow", "try_delegate"]]
+        case_list.extend(eh_case_list_include)
+
     # ignore based on command line options
     filtered_case_list = []
     for case_path in case_list:
@@ -305,6 +326,7 @@ def test_suite(
             simd_flag,
             gc_flag,
             xip_flag,
+            eh_flag,
             qemu_flag,
         ):
             filtered_case_list.append(case_path)
@@ -331,6 +353,7 @@ def test_suite(
                         multi_thread_flag,
                         simd_flag,
                         xip_flag,
+                        eh_flag,
                         clean_up_flag,
                         verbose_flag,
                         gc_flag,
@@ -369,6 +392,7 @@ def test_suite(
                     multi_thread_flag,
                     simd_flag,
                     xip_flag,
+                    eh_flag,
                     clean_up_flag,
                     verbose_flag,
                     gc_flag,
@@ -428,6 +452,14 @@ def main():
         dest="xip_flag",
         help="Running with the XIP feature",
     )
+    # added to support WASM_ENABLE_EXCE_HANDLING
+    parser.add_argument(
+        "-e",
+        action="store_true",
+        default=False,
+        dest="eh_flag",
+        help="Running with the exception-handling feature",
+    )
     parser.add_argument(
         "-t",
         action="store_true",
@@ -508,7 +540,7 @@ def main():
     if options.target == "x86_32":
         options.target = "i386"
 
-    if not preflight_check(options.aot_flag):
+    if not preflight_check(options.aot_flag, options.eh_flag):
         return False
 
     if not options.cases:
@@ -527,6 +559,7 @@ def main():
             options.multi_thread_flag,
             options.simd_flag,
             options.xip_flag,
+            options.eh_flag,
             options.clean_up_flag,
             options.verbose_flag,
             options.gc_flag,
@@ -552,6 +585,7 @@ def main():
                     options.multi_thread_flag,
                     options.simd_flag,
                     options.xip_flag,
+                    options.eh_flag,
                     options.clean_up_flag,
                     options.verbose_flag,
                     options.gc_flag,

+ 20 - 0
tests/wamr-test-suites/spec-test-script/exception_handling.patch

@@ -0,0 +1,20 @@
+diff --git a/test/core/try_catch.wast b/test/core/try_catch.wast
+index 2a0e9ff6..f243489d 100644
+--- a/test/core/try_catch.wast
++++ b/test/core/try_catch.wast
+@@ -203,7 +203,6 @@
+ 
+ (assert_return (invoke "catch-param-i32" (i32.const 5)) (i32.const 5))
+ 
+-(assert_return (invoke "catch-imported") (i32.const 2))
+ 
+ (assert_return (invoke "catchless-try" (i32.const 0)) (i32.const 0))
+ (assert_return (invoke "catchless-try" (i32.const 1)) (i32.const 1))
+@@ -231,7 +230,6 @@
+   )
+ )
+ 
+-(assert_return (invoke "imported-mismatch") (i32.const 3))
+ 
+ (assert_malformed
+   (module quote "(module (func (catch_all)))")

+ 50 - 0
tests/wamr-test-suites/spec-test-script/runtest.py

@@ -301,6 +301,9 @@ parser.add_argument('--simd', default=False, action='store_true',
 parser.add_argument('--xip', default=False, action='store_true',
         help="Enable XIP")
 
+parser.add_argument('--eh', default=False, action='store_true',
+        help="Enable Exception Handling")
+
 parser.add_argument('--multi-module', default=False, action='store_true',
         help="Enable Multi-thread")
 
@@ -762,6 +765,13 @@ def test_assert(r, opts, mode, cmd, expected):
         if o.find(e) >= 0 or e.find(o) >= 0:
             return True
 
+    # wasm-exception thrown out of function call, not a trap
+    if mode=='wasmexception':
+        o = re.sub('^Exception: ', '', out)
+        e = re.sub('^Exception: ', '', expected)
+        if o.find(e) >= 0 or e.find(o) >= 0:
+            return True
+
     ## 0x9:i32,-0x1:i32 -> ['0x9:i32', '-0x1:i32']
     expected_list = re.split(',', expected)
     out_list = re.split(',', out)
@@ -989,6 +999,42 @@ def test_assert_exhaustion(r,opts,form):
     expected = "Exception: %s\n" % m.group(3)
     test_assert(r, opts, "exhaustion", "%s %s" % (func, " ".join(args)), expected)
 
+
+# added to support WASM_ENABLE_EXCE_HANDLING
+def test_assert_wasmexception(r,opts,form):
+    # params
+
+    # ^
+    #     \(assert_exception\s+
+    #         \(invoke\s+"([^"]+)"\s+
+    #            (\(.*\))\s*
+    #            ()
+    #         \)\s*
+    #     \)\s*
+    # $
+    m = re.search('^\(assert_exception\s+\(invoke\s+"([^"]+)"\s+(\(.*\))\s*\)\s*\)\s*$', form)
+    if not m:
+        # no params
+
+        # ^
+        #       \(assert_exception\s+
+        #           \(invoke\s+"([^"]+)"\s*
+        #               ()
+        #           \)\s*
+        #       \)\s*
+        # $
+        m = re.search('^\(assert_exception\s+\(invoke\s+"([^"]+)"\s*()\)\s*\)\s*$', form)
+    if not m:
+        raise Exception("unparsed assert_exception: '%s'" % form)
+    func = m.group(1) # function name
+    if m.group(2) == '': # arguments
+        args = []
+    else:
+        args = [re.split(' +', v)[1] for v in re.split("\)\s*\(", m.group(2)[1:-1])]
+
+    expected = "Exception: uncaught wasm exception\n"
+    test_assert(r, opts, "wasmexception", "%s %s" % (func, " ".join(args)), expected)
+
 def do_invoke(r, opts, form):
     # params
     m = re.search('^\(invoke\s+"([^"]+)"\s+(\(.*\))\s*\)\s*$', form)
@@ -1027,6 +1073,8 @@ def compile_wast_to_wasm(form, wast_tempfile, wasm_tempfile, opts):
     # default arguments
     if opts.gc:
         cmd = [opts.wast2wasm, "-u", "-d", wast_tempfile, "-o", wasm_tempfile]
+    elif opts.eh:
+        cmd = [opts.wast2wasm, "--enable-thread", "--no-check", "--enable-exceptions", "--enable-tail-call", wast_tempfile, "-o", wasm_tempfile ]
     else:
         cmd = [opts.wast2wasm, "--enable-thread", "--no-check",
                wast_tempfile, "-o", wasm_tempfile ]
@@ -1243,6 +1291,8 @@ if __name__ == "__main__":
                 test_assert_with_exception(form, wast_tempfile, wasm_tempfile, aot_tempfile if test_aot else None, opts, r)
             elif re.match("^\(assert_exhaustion\\b.*", form):
                 test_assert_exhaustion(r, opts, form)
+            elif re.match("^\(assert_exception\\b.*", form):
+                test_assert_wasmexception(r, opts, form)
             elif re.match("^\(assert_unlinkable\\b.*", form):
                 test_assert_with_exception(form, wast_tempfile, wasm_tempfile, aot_tempfile if test_aot else None, opts, r, False)
             elif re.match("^\(assert_malformed\\b.*", form):

+ 36 - 2
tests/wamr-test-suites/test_wamr.sh

@@ -24,6 +24,7 @@ function help()
     echo "-S enable SIMD feature"
     echo "-G enable GC feature"
     echo "-X enable XIP feature"
+    echo "-e enable exception handling"
     echo "-x test SGX"
     echo "-w enable WASI threads"
     echo "-b use the wabt binary release package instead of compiling from the source code"
@@ -50,6 +51,7 @@ COLLECT_CODE_COVERAGE=0
 ENABLE_SIMD=0
 ENABLE_GC=0
 ENABLE_XIP=0
+ENABLE_EH=0
 ENABLE_DEBUG_VERSION=0
 ENABLE_GC_HEAP_VERIFY=0
 #unit test case arrary
@@ -70,7 +72,7 @@ WASI_TESTSUITE_COMMIT="ee807fc551978490bf1c277059aabfa1e589a6c2"
 TARGET_LIST=("AARCH64" "AARCH64_VFP" "ARMV7" "ARMV7_VFP" "THUMBV7" "THUMBV7_VFP" \
              "RISCV32" "RISCV32_ILP32F" "RISCV32_ILP32D" "RISCV64" "RISCV64_LP64F" "RISCV64_LP64D")
 
-while getopts ":s:cabgvt:m:MCpSXxwPGQF:j:T:" opt
+while getopts ":s:cabgvt:m:MCpSXexwPGQF:j:T:" opt
 do
     OPT_PARSED="TRUE"
     case $opt in
@@ -119,7 +121,7 @@ do
         ;;
         m)
         echo "set compile target of wamr" ${OPTARG}
-        TARGET=${OPTARG^^} # set target to uppercase if input x86_32 or x86_64 --> X86_32 and X86_64
+        TARGET=$(echo "$OPTARG" | tr '[a-z]' '[A-Z]') # set target to uppercase if input x86_32 or x86_64 --> X86_32 and X86_64
         ;;
         w)
         echo "enable WASI threads"
@@ -145,6 +147,10 @@ do
         echo "enable XIP feature"
         ENABLE_XIP=1
         ;;
+        e)
+        echo "enable exception handling feature"
+        ENABLE_EH=1
+        ;;
         x)
         echo "test SGX"
         SGX_OPT="--sgx"
@@ -425,6 +431,26 @@ function spec_test()
         git apply ../../spec-test-script/thread_proposal_fix_atomic_case.patch
     fi
 
+    if [ ${ENABLE_EH} == 1 ]; then
+        echo "checkout exception-handling test cases"
+        popd
+        if [ ! -d "exception-handling" ];then
+            echo "exception-handling not exist, clone it from github"
+            git clone -b master --single-branch https://github.com/WebAssembly/exception-handling 
+        fi
+        pushd exception-handling
+
+        # restore and clean everything
+        git reset --hard 51c721661b671bb7dc4b3a3acb9e079b49778d36
+        
+        if [[ ${ENABLE_MULTI_MODULE} == 0 ]]; then
+            git apply ../../spec-test-script/exception_handling.patch
+        fi
+        
+        popd
+        echo $(pwd)
+    fi
+
     # update GC cases
     if [[ ${ENABLE_GC} == 1 ]]; then
         echo "checkout spec for GC proposal"
@@ -469,6 +495,10 @@ function spec_test()
         fi
     fi
 
+    if [[ 1 == ${ENABLE_EH} ]]; then
+        ARGS_FOR_SPEC_TEST+="-e "
+    fi
+
     # sgx only enable in interp mode and aot mode
     if [[ ${SGX_OPT} == "--sgx" ]];then
         if [[ $1 == 'classic-interp' || $1 == 'fast-interp' || $1 == 'aot' || $1 == 'fast-jit' ]]; then
@@ -831,6 +861,10 @@ function trigger()
         EXTRA_COMPILE_FLAGS+=" -DWAMR_BUILD_LIB_WASI_THREADS=1"
     fi
 
+    if [[ ${ENABLE_EH} == 1 ]]; then
+        EXTRA_COMPILE_FLAGS+=" -DWAMR_BUILD_EXCE_HANDLING=1"
+        EXTRA_COMPILE_FLAGS+=" -DWAMR_BUILD_TAIL_CALL=1"
+    fi
     echo "SANITIZER IS" $WAMR_BUILD_SANITIZER
 
     if [[ "$WAMR_BUILD_SANITIZER" == "ubsan" ]]; then

+ 12 - 11
wamr-compiler/CMakeLists.txt

@@ -65,30 +65,31 @@ if (DEFINED WAMR_BUILD_AOT_FUNC_PREFIX)
 endif ()
 
 if (NOT WAMR_BUILD_TARGET)
-  if (CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "x86_64")
+  string(TOLOWER "${CMAKE_HOST_SYSTEM_PROCESSOR}" HOST_SYSTEM_PROCESSOR)
+  if (${HOST_SYSTEM_PROCESSOR} STREQUAL "x86_64")
     set (WAMR_BUILD_TARGET "X86_64")
-  elseif (CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "i686")
+  elseif (${HOST_SYSTEM_PROCESSOR} STREQUAL "i686")
     set (WAMR_BUILD_TARGET "X86_32")
-  elseif (CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "amd64")
+  elseif (${HOST_SYSTEM_PROCESSOR} STREQUAL "amd64")
     set (WAMR_BUILD_TARGET "AMD_64")
-  elseif (CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "aarch64"
-          OR CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "arm64")
+  elseif (${HOST_SYSTEM_PROCESSOR} STREQUAL "aarch64"
+          OR ${HOST_SYSTEM_PROCESSOR} STREQUAL "arm64")
     set (WAMR_BUILD_TARGET "AARCH64")
-  elseif (CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "arm.*")
+  elseif (${HOST_SYSTEM_PROCESSOR} MATCHES "arm.*")
     message(STATUS "Assuming ${CMAKE_HOST_SYSTEM_PROCESSOR} as ARM_32")
     set (WAMR_BUILD_TARGET "ARM_32")
-  elseif (CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "mips")
+  elseif (${HOST_SYSTEM_PROCESSOR} STREQUAL "mips")
     set (WAMR_BUILD_TARGET "MIPS_32")
-  elseif (CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "xtensa")
+  elseif (${HOST_SYSTEM_PROCESSOR} STREQUAL "xtensa")
     set (WAMR_BUILD_TARGET "XTENSA_32")
-  elseif (CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "riscv64")
+  elseif (${HOST_SYSTEM_PROCESSOR} STREQUAL "riscv64")
     set (WAMR_BUILD_TARGET "RISCV64")
-  elseif (CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "riscv")
+  elseif (${HOST_SYSTEM_PROCESSOR} STREQUAL "riscv")
     message(STATUS "Assuming ${CMAKE_HOST_SYSTEM_PROCESSOR} as RISCV32")
     set (WAMR_BUILD_TARGET "RISCV32")
   else ()
     message (FATAL_ERROR "Unsupported CMAKE_HOST_SYSTEM_PROCESSOR "
-    "${CMAKE_HOST_SYSTEM_PROCESSOR}")
+	                 "${CMAKE_HOST_SYSTEM_PROCESSOR}")
   endif()
 
   if (WAMR_BUILD_PLATFORM STREQUAL "windows")

Some files were not shown because too many files changed in this diff