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

Merge branch main into gitbook

Wenyong Huang 3 лет назад
Родитель
Сommit
426b8f8a8c
100 измененных файлов с 4404 добавлено и 1222 удалено
  1. 40 19
      .devcontainer/Dockerfile
  2. 7 5
      .devcontainer/devcontainer.json
  3. 1 1
      .github/workflows/build_iwasm_release.yml
  4. 63 11
      .github/workflows/build_llvm_libraries.yml
  5. 3 0
      .github/workflows/build_wamr_vscode_ext.yml
  6. 1 1
      .github/workflows/coding_guidelines.yml
  7. 185 59
      .github/workflows/compilation_on_android_ubuntu.yml
  8. 63 32
      .github/workflows/compilation_on_macos.yml
  9. 14 2
      .github/workflows/compilation_on_nuttx.yml
  10. 49 32
      .github/workflows/compilation_on_sgx.yml
  11. 14 0
      .github/workflows/compilation_on_windows.yml
  12. 4 3
      .github/workflows/release_process.yml
  13. 13 4
      .github/workflows/spec_test_on_nuttx.yml
  14. 7 0
      .gitignore
  15. 17 11
      CMakeLists.txt
  16. 92 32
      build-scripts/build_llvm.py
  17. 15 0
      build-scripts/config_common.cmake
  18. 1 0
      build-scripts/requirements.txt
  19. 29 4
      build-scripts/runtime_lib.cmake
  20. 155 39
      core/app-framework/app-native-shared/attr_container.c
  21. 176 4
      core/app-framework/app-native-shared/bi-inc/attr_container.h
  22. 8 0
      core/app-mgr/app-manager/module_wasm_app.c
  23. 11 0
      core/config.h
  24. 3 0
      core/iwasm/aot/aot_loader.c
  25. 181 93
      core/iwasm/aot/aot_runtime.c
  26. 7 0
      core/iwasm/aot/aot_runtime.h
  27. 6 1
      core/iwasm/common/arch/invokeNative_ia32.s
  28. 2 22
      core/iwasm/common/wasm_application.c
  29. 219 208
      core/iwasm/common/wasm_c_api.c
  30. 13 2
      core/iwasm/common/wasm_exec_env.c
  31. 24 0
      core/iwasm/common/wasm_exec_env.h
  32. 62 2
      core/iwasm/common/wasm_memory.c
  33. 11 0
      core/iwasm/common/wasm_memory.h
  34. 37 4
      core/iwasm/common/wasm_native.c
  35. 269 17
      core/iwasm/common/wasm_runtime_common.c
  36. 50 21
      core/iwasm/common/wasm_runtime_common.h
  37. 136 34
      core/iwasm/common/wasm_shared_memory.c
  38. 5 0
      core/iwasm/common/wasm_shared_memory.h
  39. 1 0
      core/iwasm/compilation/aot.h
  40. 2 0
      core/iwasm/compilation/aot_compiler.c
  41. 1 0
      core/iwasm/compilation/aot_compiler.h
  42. 39 60
      core/iwasm/compilation/aot_emit_conversion.c
  43. 116 8
      core/iwasm/compilation/aot_emit_function.c
  44. 19 1
      core/iwasm/compilation/aot_emit_memory.c
  45. 4 0
      core/iwasm/compilation/aot_emit_memory.h
  46. 24 1
      core/iwasm/compilation/aot_llvm.c
  47. 5 0
      core/iwasm/compilation/aot_llvm.h
  48. 92 1
      core/iwasm/fast-jit/fe/jit_emit_memory.c
  49. 26 4
      core/iwasm/fast-jit/jit_codecache.c
  50. 15 3
      core/iwasm/fast-jit/jit_compiler.c
  51. 1 1
      core/iwasm/fast-jit/jit_frontend.c
  52. 2 0
      core/iwasm/fast-jit/jit_ir.c
  53. 4 0
      core/iwasm/fast-jit/jit_ir.h
  54. 11 3
      core/iwasm/fast-jit/jit_regalloc.c
  55. 1 0
      core/iwasm/include/aot_export.h
  56. 4 0
      core/iwasm/include/wasm_c_api.h
  57. 109 3
      core/iwasm/include/wasm_export.h
  58. 40 6
      core/iwasm/interpreter/wasm.h
  59. 138 149
      core/iwasm/interpreter/wasm_interp_classic.c
  60. 95 63
      core/iwasm/interpreter/wasm_interp_fast.c
  61. 45 20
      core/iwasm/interpreter/wasm_loader.c
  62. 21 10
      core/iwasm/interpreter/wasm_mini_loader.c
  63. 9 11
      core/iwasm/interpreter/wasm_opcode.h
  64. 392 190
      core/iwasm/interpreter/wasm_runtime.c
  65. 32 12
      core/iwasm/interpreter/wasm_runtime.h
  66. 45 13
      core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c
  67. 27 0
      core/iwasm/libraries/lib-socket/test/build.sh
  68. 49 0
      core/iwasm/libraries/lib-socket/test/nslookup.c
  69. 193 0
      core/iwasm/libraries/lib-socket/test/tcp_udp.c
  70. 12 0
      core/iwasm/libraries/lib-wasi-threads/lib_wasi_threads.cmake
  71. 181 0
      core/iwasm/libraries/lib-wasi-threads/lib_wasi_threads_wrapper.c
  72. 30 0
      core/iwasm/libraries/lib-wasi-threads/test/build.sh
  73. 122 0
      core/iwasm/libraries/lib-wasi-threads/test/common.h
  74. 128 0
      core/iwasm/libraries/lib-wasi-threads/test/create_threads_until_limit.c
  75. 70 0
      core/iwasm/libraries/lib-wasi-threads/test/global_atomic.c
  76. 78 0
      core/iwasm/libraries/lib-wasi-threads/test/global_lock.c
  77. 16 0
      core/iwasm/libraries/lib-wasi-threads/test/main_proc_exit_busy.c
  78. 3 0
      core/iwasm/libraries/lib-wasi-threads/test/main_proc_exit_busy.json
  79. 16 0
      core/iwasm/libraries/lib-wasi-threads/test/main_proc_exit_sleep.c
  80. 3 0
      core/iwasm/libraries/lib-wasi-threads/test/main_proc_exit_sleep.json
  81. 16 0
      core/iwasm/libraries/lib-wasi-threads/test/main_proc_exit_wait.c
  82. 3 0
      core/iwasm/libraries/lib-wasi-threads/test/main_proc_exit_wait.json
  83. 16 0
      core/iwasm/libraries/lib-wasi-threads/test/main_trap_busy.c
  84. 3 0
      core/iwasm/libraries/lib-wasi-threads/test/main_trap_busy.json
  85. 16 0
      core/iwasm/libraries/lib-wasi-threads/test/main_trap_sleep.c
  86. 3 0
      core/iwasm/libraries/lib-wasi-threads/test/main_trap_sleep.json
  87. 16 0
      core/iwasm/libraries/lib-wasi-threads/test/main_trap_wait.c
  88. 3 0
      core/iwasm/libraries/lib-wasi-threads/test/main_trap_wait.json
  89. 16 0
      core/iwasm/libraries/lib-wasi-threads/test/nonmain_proc_exit_busy.c
  90. 3 0
      core/iwasm/libraries/lib-wasi-threads/test/nonmain_proc_exit_busy.json
  91. 16 0
      core/iwasm/libraries/lib-wasi-threads/test/nonmain_proc_exit_sleep.c
  92. 3 0
      core/iwasm/libraries/lib-wasi-threads/test/nonmain_proc_exit_sleep.json
  93. 16 0
      core/iwasm/libraries/lib-wasi-threads/test/nonmain_proc_exit_wait.c
  94. 3 0
      core/iwasm/libraries/lib-wasi-threads/test/nonmain_proc_exit_wait.json
  95. 16 0
      core/iwasm/libraries/lib-wasi-threads/test/nonmain_trap_busy.c
  96. 3 0
      core/iwasm/libraries/lib-wasi-threads/test/nonmain_trap_busy.json
  97. 16 0
      core/iwasm/libraries/lib-wasi-threads/test/nonmain_trap_sleep.c
  98. 3 0
      core/iwasm/libraries/lib-wasi-threads/test/nonmain_trap_sleep.json
  99. 16 0
      core/iwasm/libraries/lib-wasi-threads/test/nonmain_trap_wait.c
  100. 3 0
      core/iwasm/libraries/lib-wasi-threads/test/nonmain_trap_wait.json

+ 40 - 19
.devcontainer/Dockerfile

@@ -12,7 +12,7 @@ ENV TZ=Asian/Shanghai
 # hadolint ignore=DL3008
 RUN apt-get update \
   && apt-get install -y apt-transport-https apt-utils build-essential \
-  ca-certificates curl g++-multilib git gnupg \
+  ca-certificates ccache curl g++-multilib git gnupg \
   libgcc-9-dev lib32gcc-9-dev lsb-release \
   ninja-build ocaml ocamlbuild python2.7 \
   software-properties-common tree tzdata \
@@ -20,6 +20,15 @@ RUN apt-get update \
   && apt-get clean -y \
   && rm -rf /var/lib/apt/lists/*
 
+#
+# binaryen
+ARG BINARYEN_VER=111
+WORKDIR /opt
+RUN wget -c --progress=dot:giga https://github.com/WebAssembly/binaryen/releases/download/version_${BINARYEN_VER}/binaryen-version_${BINARYEN_VER}-x86_64-linux.tar.gz \
+  && tar xf binaryen-version_${BINARYEN_VER}-x86_64-linux.tar.gz \
+  && ln -sf /opt/binaryen-version_111 /opt/binaryen \
+  && rm binaryen-version_${BINARYEN_VER}-x86_64-linux.tar.gz
+
 #
 # CMAKE (https://apt.kitware.com/)
 SHELL ["/bin/bash", "-o", "pipefail", "-c"]
@@ -31,25 +40,26 @@ RUN wget --progress=dot:giga -O - https://apt.kitware.com/keys/kitware-archive-l
   && apt-get install -y kitware-archive-keyring --no-install-recommends \
   && apt-get install -y cmake --no-install-recommends \
   && apt-get clean -y \
-  && rm -rf /var/lib/apt/lists/* 
+  && rm -rf /var/lib/apt/lists/*
 
 #
 # install emsdk
 WORKDIR /opt
 RUN git clone https://github.com/emscripten-core/emsdk.git
 
+ARG EMSDK_VER=3.0.0
 WORKDIR /opt/emsdk
 RUN  git pull \
-  && ./emsdk install 2.0.26 \
-  && ./emsdk activate 2.0.26 \
+  && ./emsdk install ${EMSDK_VER} \
+  && ./emsdk activate ${EMSDK_VER} \
   && echo "source /opt/emsdk/emsdk_env.sh" >> /root/.bashrc
 
 #
 # install wasi-sdk
-ARG WASI_SDK_VER=16
+ARG WASI_SDK_VER=19
 RUN wget -c --progress=dot:giga https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-${WASI_SDK_VER}/wasi-sdk-${WASI_SDK_VER}.0-linux.tar.gz -P /opt \
   && tar xf /opt/wasi-sdk-${WASI_SDK_VER}.0-linux.tar.gz -C /opt \
-  && ln -fs /opt/wasi-sdk-${WASI_SDK_VER}.0 /opt/wasi-sdk \
+  && ln -sf /opt/wasi-sdk-${WASI_SDK_VER}.0 /opt/wasi-sdk \
   && rm /opt/wasi-sdk-${WASI_SDK_VER}.0-linux.tar.gz
 
 #
@@ -57,29 +67,29 @@ RUN wget -c --progress=dot:giga https://github.com/WebAssembly/wasi-sdk/releases
 ARG WABT_VER=1.0.29
 RUN wget -c --progress=dot:giga https://github.com/WebAssembly/wabt/releases/download/${WABT_VER}/wabt-${WABT_VER}-ubuntu.tar.gz -P /opt \
   && tar xf /opt/wabt-${WABT_VER}-ubuntu.tar.gz -C /opt \
-  && ln -fs /opt/wabt-${WABT_VER} /opt/wabt \
+  && ln -sf /opt/wabt-${WABT_VER} /opt/wabt \
   && rm /opt/wabt-${WABT_VER}-ubuntu.tar.gz
 
 #
 # install bazelisk
 ARG BAZELISK_VER=1.12.0
-RUN mkdir /opt/bazelisk \ 
+RUN mkdir /opt/bazelisk \
   && wget -c --progress=dot:giga https://github.com/bazelbuild/bazelisk/releases/download/v${BAZELISK_VER}/bazelisk-linux-amd64 -P /opt/bazelisk \
   && chmod a+x /opt/bazelisk/bazelisk-linux-amd64 \
   && ln -fs /opt/bazelisk/bazelisk-linux-amd64 /opt/bazelisk/bazel
 
 #
 # install clang+llvm
+ARG LLVM_VER=14
+RUN apt-get purge -y clang-10 llvm-10 && apt autoremove -y
 WORKDIR /etc/apt/apt.conf.d
 RUN touch 99verfiy-peer.conf \
   && echo "Acquire { https::Verify-Peer false }" > 99verfiy-peer.conf
 
-WORKDIR /tmp 
+WORKDIR /tmp
 RUN wget --progress=dot:giga https://apt.llvm.org/llvm.sh \
   && chmod a+x ./llvm.sh \
-  && /tmp/llvm.sh 12 all \ 
-  && ln -sf /usr/bin/clang-format-12 /usr/bin/clang-format \
-  && rm -rf /tmp/*
+  && ./llvm.sh ${LLVM_VER} all
 
 #
 # [Optional]
@@ -96,17 +106,28 @@ RUN apt-get update \
 # Install required python packages
 # hadolint ignore=DL3013
 RUN python3 -m pip install --no-cache-dir --upgrade pip \
-  && pip3 install --no-cache-dir --user black nose pycparser pylint
+  && pip3 install --no-cache-dir black nose pycparser pylint
+
+#
+# Install github-cli. It doens't work as a feature of devcontainer.json
+RUN cd /tmp \
+  && wget https://github.com/cli/cli/releases/download/v2.20.2/gh_2.20.2_linux_amd64.deb \
+  && dpkg -i gh_2.20.2_linux_amd64.deb
 
-# set path, PS and clean up
-ENV PATH "/opt/bazelisk:/opt/clang-llvm/bin:${PATH}"
-RUN echo "export PATH=/opt/bazelisk:/opt/clang-llvm/bin:${PATH}" >> /root/.bashrc \
-  && printf "%s\n" "PS1='\n[ \u@wamr-dev-docker \W ]\n$ '" >> /root/.bashrc \
+#
+# Install NodeJS
+RUN curl -fsSL https://deb.nodesource.com/setup_19.x | bash -
+RUN apt-get install -y nodejs
+
+# set path
+ENV PATH="/opt/bazelisk:/usr/lib/llvm-${LLVM_VER}/bin:${PATH}"
+ENV CC=/usr/lib/llvm-${LLVM_VER}/bin/clang CXX=/usr/lib/llvm-${LLVM_VER}/bin/clang++
+RUN printf "%s\n" "PS1='\n[ \u@wamr-dev-docker \W ]\n$ '" >> /root/.bashrc \
   && apt-get autoremove -y \
   && apt-get clean -y \
   && rm -rf /var/lib/apt/lists/* \
   && rm -rf /tmp/*
 
 # set workdir when container run
-VOLUME /workspace
-WORKDIR /workspace
+VOLUME /workspaces
+WORKDIR /workspaces

+ 7 - 5
.devcontainer/devcontainer.json

@@ -1,6 +1,5 @@
 // Copyright (C) 2019 Intel Corporation.  All rights reserved.
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-
 // For format details, see https://aka.ms/vscode-remote/devcontainer.json or this file's README at:
 // https://github.com/microsoft/vscode-dev-containers/tree/v0.195.0/containers/cpp
 {
@@ -10,7 +9,12 @@
     // Update 'VARIANT' to pick an Debian / Ubuntu OS version: debian-11, debian-10, debian-9, ubuntu-21.04, ubuntu-20.04, ubuntu-18.04
     // Use Debian 11, Debian 9, Ubuntu 18.04 or Ubuntu 21.04 on local arm64/Apple Silicon
     "args": {
-      "VARIANT": "ubuntu-20.04"
+      "BINARYEN_VER": "111",
+      "EMSDK_VER": "3.0.0",
+      "LLVM_VER": "15",
+      "VARIANT": "ubuntu-20.04",
+      "WASI_SDK_VER": "19",
+      "WABT_VER": "1.0.31"
     }
   },
   "runArgs": [
@@ -27,12 +31,10 @@
       // Add the IDs of extensions you want installed when the container is created.
       "extensions": [
         "dtsvet.vscode-wasm",
-        "esbenp.prettier-vscode",
+        "llvm-vs-code-extensions.vscode-clangd",
         "ms-python.python",
         "ms-python.vscode-pylance",
         "ms-vscode.cmake-tools",
-        "ms-vscode.cpptools",
-        "twxs.cmake"
       ]
     }
   },

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

@@ -36,7 +36,7 @@ jobs:
       - name: generate iwasm binary release
         run: |
           cmake -S . -B build \
-            -DWAMR_BUILD_AOT=1 -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_JIT=0 \
+            -DWAMR_BUILD_AOT=1 -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_FAST_JIT=1 -DWAMR_BUILD_JIT=1 \
             -DWAMR_BUILD_CUSTOM_NAME_SECTION=0 \
             -DWAMR_BUILD_DEBUG_INTERP=0 \
             -DWAMR_BUILD_DEBUG_AOT=0 \

+ 63 - 11
.github/workflows/build_llvm_libraries.yml

@@ -5,23 +5,46 @@ name: Reusable workflow-build_llvm_libraries
 on:
   workflow_call:
     inputs:
-      runs-on:
+      os:
         required: true
         type: string
+      arch:
+        required: true
+        type: string
+    outputs:
+      cache_key:
+        description: "A cached key of LLVM libraries"
+        value: ${{ jobs.build_llvm_libraries.outputs.key}}
 
 jobs:
   build_llvm_libraries:
-    runs-on: ${{ matrix.os }}
-    strategy:
-      matrix:
-        os: ${{ fromJson(inputs.runs-on) }}
+    runs-on: ${{ inputs.os }}
+    outputs:
+      key: ${{ steps.create_lib_cache_key.outputs.key}}
 
     steps:
       - name: checkout
         uses: actions/checkout@v3
 
+      - name: install dependencies
+        run: /usr/bin/env python3 -m pip install -r requirements.txt
+        working-directory: build-scripts
+
+      - name: retrive the last commit ID
+        id: get_last_commit
+        run: echo "last_commit=$(GH_TOKEN=${{ secrets.GITHUB_TOKEN }} /usr/bin/env python3 ./build_llvm.py --llvm-ver)" >> $GITHUB_OUTPUT
+        working-directory: build-scripts
+
+      # Bump the prefix number to evict all previous caches and
+      # enforce a clean build, in the unlikely case that some
+      # weird build error occur and llvm/build becomes a potential
+      # suspect.
+      - name: form the cache key of libraries
+        id: create_lib_cache_key
+        run: echo "key=0-llvm-libraries-${{ inputs.os }}-${{ inputs.arch }}-${{ steps.get_last_commit.outputs.last_commit }}" >> $GITHUB_OUTPUT
+
       - name: Cache LLVM libraries
-        id: cache_llvm
+        id: retrieve_llvm_libs
         uses: actions/cache@v3
         with:
           path: |
@@ -30,10 +53,39 @@ jobs:
             ./core/deps/llvm/build/lib
             ./core/deps/llvm/build/libexec
             ./core/deps/llvm/build/share
-          key: ${{ matrix.os }}-build-llvm_libraries_ex
+          key: ${{ steps.create_lib_cache_key.outputs.key}}
+
+      - uses: actions/cache@v3
+        with:
+          path: ~/.ccache
+          key: 0-ccache-${{ inputs.os }}-${{ steps.get_last_commit.outputs.last_commit }}
+          restore-keys: |
+            0-ccache-${{ inputs.os }}
+        if: steps.retrieve_llvm_libs.outputs.cache-hit != 'true' && inputs.os == 'ubuntu-20.04'
+
+      - uses: actions/cache@v3
+        with:
+          path: ~/.cache/ccache
+          key: 0-ccache-${{ inputs.os }}-${{ steps.get_last_commit.outputs.last_commit }}
+          restore-keys: |
+            0-ccache-${{ inputs.os }}
+        if: steps.retrieve_llvm_libs.outputs.cache-hit != 'true' && inputs.os == 'ubuntu-22.04'
+
+      - run: sudo apt install -y ccache ninja-build
+        if: steps.retrieve_llvm_libs.outputs.cache-hit != 'true' && startsWith(inputs.os, 'ubuntu')
+
+      - uses: actions/cache@v3
+        with:
+          path: ~/Library/Caches/ccache
+          key: 0-ccache-${{ inputs.os }}-${{ steps.get_last_commit.outputs.last_commit }}
+          restore-keys: |
+            0-ccache-${{ inputs.os }}
+        if: steps.retrieve_llvm_libs.outputs.cache-hit != 'true' && startsWith(inputs.os, 'macos')
+
+      - run: brew install ccache ninja
+        if: steps.retrieve_llvm_libs.outputs.cache-hit != 'true' && startsWith(inputs.os, 'macos')
 
-      - name: Build llvm
-        id: build_llvm
-        if: ${{ steps.cache_llvm.outputs.cache-hit != 'true' }} 
-        run: /usr/bin/env python3 ./build_llvm.py --arch X86 WebAssembly
+      - name: Build LLVM libraries
+        if: steps.retrieve_llvm_libs.outputs.cache-hit != 'true'
+        run: /usr/bin/env python3 ./build_llvm.py --arch ${{ inputs.arch }}
         working-directory: build-scripts

+ 3 - 0
.github/workflows/build_wamr_vscode_ext.yml

@@ -32,11 +32,14 @@ jobs:
         working-directory: test-tools/wamr-ide/VSCode-Extension
 
       - name: generate wamr ide vscode extension
+        env: 
+          credentials: ${{ secrets.TOKEN }}
         run: |
           npm install -g vsce
           rm -rf node_modules
           npm install
           vsce package
+          vsce publish -p ${{ secrets.TOKEN }}
         working-directory: test-tools/wamr-ide/VSCode-Extension
 
       - name: compress the vscode extension

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

@@ -15,7 +15,7 @@ concurrency:
   cancel-in-progress: true
 
 jobs:
-  complinace_job:
+  compliance_job:
     runs-on: ubuntu-latest
     steps:
       - name: checkout

+ 185 - 59
.github/workflows/compilation_on_android_ubuntu.yml

@@ -53,33 +53,47 @@ env:
   FAST_JIT_BUILD_OPTIONS: "      -DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_FAST_JIT=1 -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_LAZY_JIT=0"
   LLVM_LAZY_JIT_BUILD_OPTIONS: " -DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_FAST_JIT=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=1"
   LLVM_EAGER_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_FAST_JIT=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=0"
-  # LLVM
-  LLVM_CACHE_SUFFIX: "build-llvm_libraries_ex"
+  MULTI_TIER_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_FAST_JIT=1 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=1"
   # For Spec Test
   DEFAULT_TEST_OPTIONS: "-s spec -b -P"
   MULTI_MODULES_TEST_OPTIONS: "-s spec -b -M -P"
   SIMD_TEST_OPTIONS: "-s spec -b -S -P"
   THREADS_TEST_OPTIONS: "-s spec -b -p -P"
   X86_32_TARGET_TEST_OPTIONS: "-m x86_32 -P"
+  WASI_TEST_OPTIONS: "-s wasi_certification -w"
 
 jobs:
-  build_llvm_libraries:
+  build_llvm_libraries_on_ubuntu_2004:
     uses: ./.github/workflows/build_llvm_libraries.yml
     with:
-      runs-on: "['ubuntu-20.04', 'ubuntu-22.04']"
+      os: "ubuntu-20.04"
+      arch: "X86"
+
+  build_llvm_libraries_on_ubuntu_2204:
+    uses: ./.github/workflows/build_llvm_libraries.yml
+    with:
+      os: "ubuntu-22.04"
+      arch: "X86"
 
   build_wamrc:
-    needs: [build_llvm_libraries]
+    needs:
+      [build_llvm_libraries_on_ubuntu_2004, build_llvm_libraries_on_ubuntu_2204]
     runs-on: ${{ matrix.os }}
     strategy:
       matrix:
-        os: [ubuntu-20.04, ubuntu-22.04]
+        include:
+          - os: ubuntu-20.04
+            llvm_cache_key: ${{ needs.build_llvm_libraries_on_ubuntu_2004.outputs.cache_key }}
+          - os: ubuntu-22.04
+            llvm_cache_key: ${{ needs.build_llvm_libraries_on_ubuntu_2204.outputs.cache_key }}
     steps:
       - name: checkout
         uses: actions/checkout@v3
 
+      # since jobs.id can't contain the dot character
+      # it is hard to use `format` to assemble the cache key
       - name: Get LLVM libraries
-        id: cache_llvm
+        id: retrieve_llvm_libs
         uses: actions/cache@v3
         with:
           path: |
@@ -88,10 +102,10 @@ jobs:
             ./core/deps/llvm/build/lib
             ./core/deps/llvm/build/libexec
             ./core/deps/llvm/build/share
-          key: ${{ matrix.os }}-${{ env.LLVM_CACHE_SUFFIX }}
+          key: ${{ matrix.llvm_cache_key }}
 
       - name: Quit if cache miss
-        if: steps.cache_llvm.outputs.cache-hit != 'true'
+        if: steps.retrieve_llvm_libs.outputs.cache-hit != 'true'
         run: echo "::error::can not get prebuilt llvm libraries" && exit 1
 
       - name: Build wamrc
@@ -102,7 +116,8 @@ jobs:
         working-directory: wamr-compiler
 
   build_iwasm:
-    needs: [build_llvm_libraries]
+    needs:
+      [build_llvm_libraries_on_ubuntu_2004, build_llvm_libraries_on_ubuntu_2204]
     runs-on: ${{ matrix.os }}
     strategy:
       matrix:
@@ -114,6 +129,7 @@ jobs:
             $FAST_JIT_BUILD_OPTIONS,
             $LLVM_LAZY_JIT_BUILD_OPTIONS,
             $LLVM_EAGER_JIT_BUILD_OPTIONS,
+            $MULTI_TIER_JIT_BUILD_OPTIONS,
           ]
         make_options_feature: [
             # Features
@@ -146,6 +162,8 @@ jobs:
             make_options_feature: "-DWAMR_BUILD_MULTI_MODULE=1"
           - make_options_run_mode: $LLVM_EAGER_JIT_BUILD_OPTIONS
             make_options_feature: "-DWAMR_BUILD_MULTI_MODULE=1"
+          - make_options_run_mode: $MULTI_TIER_JIT_BUILD_OPTIONS
+            make_options_feature: "-DWAMR_BUILD_MULTI_MODULE=1"
           # SIMD only on JIT/AOT mode
           - make_options_run_mode: $CLASSIC_INTERP_BUILD_OPTIONS
             make_options_feature: "-DWAMR_BUILD_SIMD=1"
@@ -162,6 +180,8 @@ jobs:
             make_options_feature: "-DWAMR_BUILD_DEBUG_INTERP=1"
           - make_options_run_mode: $LLVM_EAGER_JIT_BUILD_OPTIONS
             make_options_feature: "-DWAMR_BUILD_DEBUG_INTERP=1"
+          - make_options_run_mode: $MULTI_TIER_JIT_BUILD_OPTIONS
+            make_options_feature: "-DWAMR_BUILD_DEBUG_INTERP=1"
           # DEBUG_AOT only on JIT/AOT mode
           - make_options_run_mode: $CLASSIC_INTERP_BUILD_OPTIONS
             make_options_feature: "-DWAMR_BUILD_DEBUG_AOT=1"
@@ -174,6 +194,8 @@ jobs:
             make_options_feature: "-DWAMR_BUILD_DEBUG_AOT=1"
           - make_options_run_mode: $LLVM_EAGER_JIT_BUILD_OPTIONS
             make_options_feature: "-DWAMR_BUILD_DEBUG_AOT=1"
+          - make_options_run_mode: $MULTI_TIER_JIT_BUILD_OPTIONS
+            make_options_feature: "-DWAMR_BUILD_DEBUG_AOT=1"
           # MINI_LOADER only on INTERP mode
           - make_options_run_mode: $AOT_BUILD_OPTIONS
             make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1"
@@ -183,16 +205,28 @@ jobs:
             make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1"
           - make_options_run_mode: $LLVM_EAGER_JIT_BUILD_OPTIONS
             make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1"
-          # Fast-JIT mode doesn't support android(X86-32)
+          - make_options_run_mode: $MULTI_TIER_JIT_BUILD_OPTIONS
+            make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1"
+          # Fast-JIT and Multi-Tier-JIT mode don't support android(X86-32)
           - make_options_run_mode: $FAST_JIT_BUILD_OPTIONS
             platform: android
+          - make_options_run_mode: $MULTI_TIER_JIT_BUILD_OPTIONS
+            platform: android
+          # only test andorid on ubuntu latest
+          - os: ubuntu-20.04
+            platform: android
+        include:
+          - os: ubuntu-20.04
+            llvm_cache_key: ${{ needs.build_llvm_libraries_on_ubuntu_2004.outputs.cache_key }}
+          - os: ubuntu-22.04
+            llvm_cache_key: ${{ needs.build_llvm_libraries_on_ubuntu_2204.outputs.cache_key }}
     steps:
       - name: checkout
         uses: actions/checkout@v3
 
       # only download llvm cache when needed
       - name: Get LLVM libraries
-        id: cache_llvm
+        id: retrieve_llvm_libs
         if: endsWith(matrix.make_options_run_mode, '_JIT_BUILD_OPTIONS')
         uses: actions/cache@v3
         with:
@@ -202,10 +236,10 @@ jobs:
             ./core/deps/llvm/build/lib
             ./core/deps/llvm/build/libexec
             ./core/deps/llvm/build/share
-          key: ${{ matrix.os }}-${{ env.LLVM_CACHE_SUFFIX }}
+          key: ${{ matrix.llvm_cache_key }}
 
       - name: Quit if cache miss
-        if: endsWith(matrix.make_options_run_mode, '_JIT_BUILD_OPTIONS') && (steps.cache_llvm.outputs.cache-hit != 'true')
+        if: endsWith(matrix.make_options_run_mode, '_JIT_BUILD_OPTIONS') && (steps.retrieve_llvm_libs.outputs.cache-hit != 'true')
         run: echo "::error::can not get prebuilt llvm libraries" && exit 1
 
       - name: Build iwasm
@@ -216,7 +250,13 @@ jobs:
         working-directory: product-mini/platforms/${{ matrix.platform }}
 
   build_samples_wasm_c_api:
-    needs: [build_iwasm, build_llvm_libraries, build_wamrc]
+    needs:
+      [
+        build_iwasm,
+        build_llvm_libraries_on_ubuntu_2004,
+        build_llvm_libraries_on_ubuntu_2204,
+        build_wamrc,
+      ]
     runs-on: ${{ matrix.os }}
     strategy:
       matrix:
@@ -228,22 +268,28 @@ jobs:
             $FAST_JIT_BUILD_OPTIONS,
             $LLVM_LAZY_JIT_BUILD_OPTIONS,
             $LLVM_EAGER_JIT_BUILD_OPTIONS,
+            $MULTI_TIER_JIT_BUILD_OPTIONS,
           ]
         os: [ubuntu-20.04, ubuntu-22.04]
         wasi_sdk_release:
           [
-            "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk-12.0-linux.tar.gz",
+            "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-19/wasi-sdk-19.0-linux.tar.gz",
           ]
         wabt_release:
           [
-            "https://github.com/WebAssembly/wabt/releases/download/1.0.24/wabt-1.0.24-ubuntu.tar.gz",
+            "https://github.com/WebAssembly/wabt/releases/download/1.0.31/wabt-1.0.31-ubuntu.tar.gz",
           ]
+        include:
+          - os: ubuntu-20.04
+            llvm_cache_key: ${{ needs.build_llvm_libraries_on_ubuntu_2004.outputs.cache_key }}
+          - os: ubuntu-22.04
+            llvm_cache_key: ${{ needs.build_llvm_libraries_on_ubuntu_2204.outputs.cache_key }}
     steps:
       - name: checkout
         uses: actions/checkout@v3
 
       - name: Get LLVM libraries
-        id: cache_llvm
+        id: retrieve_llvm_libs
         if: (!endsWith(matrix.make_options, '_INTERP_BUILD_OPTIONS'))
         uses: actions/cache@v3
         with:
@@ -253,18 +299,18 @@ jobs:
             ./core/deps/llvm/build/lib
             ./core/deps/llvm/build/libexec
             ./core/deps/llvm/build/share
-          key: ${{ matrix.os }}-${{ env.LLVM_CACHE_SUFFIX }}
+          key: ${{ matrix.llvm_cache_key }}
 
       - name: Quit if cache miss
-        if: (!endsWith(matrix.make_options, '_INTERP_BUILD_OPTIONS')) && (steps.cache_llvm.outputs.cache-hit != 'true')
+        if: (!endsWith(matrix.make_options, '_INTERP_BUILD_OPTIONS')) && (steps.retrieve_llvm_libs.outputs.cache-hit != 'true')
         run: echo "::error::can not get prebuilt llvm libraries" && exit 1
 
       - name: download and install wabt
         run: |
           cd /opt
           sudo wget ${{ matrix.wabt_release }}
-          sudo tar -xzf wabt-1.0.24-*.tar.gz
-          sudo mv wabt-1.0.24 wabt
+          sudo tar -xzf wabt-1.0.31-*.tar.gz
+          sudo mv wabt-1.0.31 wabt
 
       - name: Build wamrc
         if: (!endsWith(matrix.make_options, '_INTERP_BUILD_OPTIONS'))
@@ -276,19 +322,9 @@ jobs:
 
       - name: Build Sample [wasm-c-api]
         run: |
-          mkdir build && cd build
-          cmake .. ${{ matrix.make_options }}
-          cmake --build . --config Release --parallel 4
-          ./callback
-          ./callback_chain
-          ./empty_imports
-          ./global
-          ./hello
-          ./hostref
-          ./memory
-          ./reflect
-          ./table
-          ./trap
+          cmake -S . -B build ${{ matrix.make_options }}
+          cmake --build build --config Release --parallel 4
+          ctest --test-dir build
         working-directory: samples/wasm-c-api
 
   build_samples_others:
@@ -297,14 +333,13 @@ jobs:
     strategy:
       matrix:
         os: [ubuntu-20.04, ubuntu-22.04]
-        wasi_sdk_release:
-          [
-            "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk-12.0-linux.tar.gz",
-          ]
-        wabt_release:
-          [
-            "https://github.com/WebAssembly/wabt/releases/download/1.0.24/wabt-1.0.24-ubuntu.tar.gz",
-          ]
+        include:
+          - os: ubuntu-20.04
+            wasi_sdk_release: "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-19/wasi-sdk-19.0-linux.tar.gz"
+            wabt_release: "https://github.com/WebAssembly/wabt/releases/download/1.0.31/wabt-1.0.31-ubuntu.tar.gz"
+          - os: ubuntu-22.04
+            wasi_sdk_release: "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-19/wasi-sdk-19.0-linux.tar.gz"
+            wabt_release: "https://github.com/WebAssembly/wabt/releases/download/1.0.31/wabt-1.0.31-ubuntu.tar.gz"
     steps:
       - name: checkout
         uses: actions/checkout@v3
@@ -313,15 +348,31 @@ jobs:
         run: |
           cd /opt
           sudo wget ${{ matrix.wasi_sdk_release }}
-          sudo tar -xzf wasi-sdk-12.0-*.tar.gz
-          sudo mv wasi-sdk-12.0 wasi-sdk
+          sudo tar -xzf wasi-sdk-*.tar.gz
+          sudo mv wasi-sdk-19.0 wasi-sdk
 
       - name: download and install wabt
         run: |
           cd /opt
           sudo wget ${{ matrix.wabt_release }}
-          sudo tar -xzf wabt-1.0.24-*.tar.gz
-          sudo mv wabt-1.0.24 wabt
+          sudo tar -xzf wabt-1.0.31-*.tar.gz
+          sudo mv wabt-1.0.31 wabt
+
+      - name: build wasi-libc (needed for wasi-threads)
+        run: |
+          mkdir wasi-libc
+          cd wasi-libc
+          git init
+          # "Rename thread_spawn import" commit on main branch
+          git fetch https://github.com/WebAssembly/wasi-libc \
+            8f5275796a82f8ecfd0833a4f3f444fa37ed4546
+          git checkout FETCH_HEAD
+          make -j \
+            AR=/opt/wasi-sdk/bin/llvm-ar \
+            NM=/opt/wasi-sdk/bin/llvm-nm \
+            CC=/opt/wasi-sdk/bin/clang \
+            THREAD_MODEL=posix
+        working-directory: core/deps
 
       - name: Build Sample [basic]
         run: |
@@ -376,20 +427,42 @@ jobs:
           exit $?
         working-directory: ./samples/simple
 
-  spec_test:
-    needs: [build_iwasm, build_llvm_libraries, build_wamrc]
+      - name: Build Sample [wasi-threads]
+        run: |
+          cd samples/wasi-threads
+          mkdir build && cd build
+          cmake -DWASI_SYSROOT=`pwd`/../../../core/deps/wasi-libc/sysroot ..
+          cmake --build . --config Release --parallel 4
+          ./iwasm wasm-apps/no_pthread.wasm
+
+  test:
+    needs: [build_iwasm, build_llvm_libraries_on_ubuntu_2004, build_wamrc]
     runs-on: ubuntu-20.04
     strategy:
       matrix:
         running_mode:
-          ["classic-interp", "fast-interp", "jit", "aot", "fast-jit"]
+          [
+            "classic-interp",
+            "fast-interp",
+            "jit",
+            "aot",
+            "fast-jit",
+            "multi-tier-jit",
+          ]
         test_option:
           [
             $DEFAULT_TEST_OPTIONS,
             $MULTI_MODULES_TEST_OPTIONS,
             $SIMD_TEST_OPTIONS,
             $THREADS_TEST_OPTIONS,
+            $WASI_TEST_OPTIONS,
           ]
+        wasi_sdk_release:
+          [
+            "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-19/wasi-sdk-19.0-linux.tar.gz",
+          ]
+        llvm_cache_key:
+          ["${{ needs.build_llvm_libraries_on_ubuntu_2004.outputs.cache_key }}"]
         exclude:
           # uncompatiable modes and features
           # classic-interp and fast-interp don't support simd
@@ -402,31 +475,68 @@ jobs:
             test_option: $MULTI_MODULES_TEST_OPTIONS
           - running_mode: "jit"
             test_option: $MULTI_MODULES_TEST_OPTIONS
-          # fast-jit is only tested on default mode, exclude other three
+          # fast-jit doesn't support multi module, simd, and threads
           - running_mode: "fast-jit"
             test_option: $MULTI_MODULES_TEST_OPTIONS
           - running_mode: "fast-jit"
             test_option: $SIMD_TEST_OPTIONS
           - running_mode: "fast-jit"
             test_option: $THREADS_TEST_OPTIONS
+          - running_mode: "fast-jit"
+            test_option: $WASI_TEST_OPTIONS
+          # multi-tier-jit doesn't support multi module, simd, and threads
+          - running_mode: "multi-tier-jit"
+            test_option: $MULTI_MODULES_TEST_OPTIONS
+          - running_mode: "multi-tier-jit"
+            test_option: $SIMD_TEST_OPTIONS
+          - running_mode: "multi-tier-jit"
+            test_option: $THREADS_TEST_OPTIONS
+          - running_mode: "multi-tier-jit"
+            test_option: $WASI_TEST_OPTIONS
     steps:
       - name: checkout
         uses: actions/checkout@v3
 
+      - name: download and install wasi-sdk
+        if: matrix.test_option == '$WASI_TEST_OPTIONS'
+        run: |
+          cd /opt
+          sudo wget ${{ matrix.wasi_sdk_release }}
+          sudo tar -xzf wasi-sdk-*.tar.gz
+          sudo mv wasi-sdk-19.0 wasi-sdk
+
+      - name: build wasi-libc (needed for wasi-threads)
+        if: matrix.test_option == '$WASI_TEST_OPTIONS'
+        run: |
+          mkdir wasi-libc
+          cd wasi-libc
+          git init
+          # "Rename thread_spawn import" commit on main branch
+          git fetch https://github.com/WebAssembly/wasi-libc \
+            8f5275796a82f8ecfd0833a4f3f444fa37ed4546
+          git checkout FETCH_HEAD
+          make \
+            AR=/opt/wasi-sdk/bin/llvm-ar \
+            NM=/opt/wasi-sdk/bin/llvm-nm \
+            CC=/opt/wasi-sdk/bin/clang \
+            THREAD_MODEL=posix
+        working-directory: core/deps
+
       - name: set env variable(if llvm are used)
-        if: matrix.running_mode == 'aot' || matrix.running_mode == 'jit'
+        if: matrix.running_mode == 'aot' || matrix.running_mode == 'jit' || matrix.running_mode == 'multi-tier-jit'
         run: echo "USE_LLVM=true" >> $GITHUB_ENV
 
       - name: set env variable(if x86_32 test needed)
         if: >
-          (matrix.test_option == '$DEFAULT_TEST_OPTIONS' || matrix.test_option == '$THREADS_TEST_OPTIONS')
-          && matrix.running_mode != 'fast-jit' && matrix.running_mode != 'jit'
+          (matrix.test_option == '$DEFAULT_TEST_OPTIONS' || matrix.test_option == '$THREADS_TEST_OPTIONS'
+           || matrix.test_option == '$WASI_TEST_OPTIONS')
+          && matrix.running_mode != 'fast-jit' && matrix.running_mode != 'jit' && matrix.running_mode != 'multi-tier-jit'
         run: echo "TEST_ON_X86_32=true" >> $GITHUB_ENV
 
       #only download llvm libraries in jit and aot mode
       - name: Get LLVM libraries
         if: env.USE_LLVM == 'true'
-        id: cache_llvm
+        id: retrieve_llvm_libs
         uses: actions/cache@v3
         with:
           path: |
@@ -435,13 +545,28 @@ jobs:
             ./core/deps/llvm/build/lib
             ./core/deps/llvm/build/libexec
             ./core/deps/llvm/build/share
-          key: ubuntu-20.04-${{ env.LLVM_CACHE_SUFFIX }}
+          key: ${{ matrix.llvm_cache_key }}
 
       - name: Quit if cache miss
-        if: env.USE_LLVM == 'true' && steps.cache_llvm.outputs.cache-hit != 'true'
+        if: env.USE_LLVM == 'true' && steps.retrieve_llvm_libs.outputs.cache-hit != 'true'
         run: echo "::error::can not get prebuilt llvm libraries" && exit 1
 
-      - name: run spec tests default and extra
+      - name: install jq JSON processor
+        if: matrix.running_mode == 'aot' && matrix.test_option == '$WASI_TEST_OPTIONS'
+        run: sudo apt-get update && sudo apt install -y jq
+
+      - name: Build WASI thread tests
+        if: matrix.test_option == '$WASI_TEST_OPTIONS'
+        run: WASI_SYSROOT=../../../../../core/deps/wasi-libc/sysroot bash build.sh
+        working-directory: ./core/iwasm/libraries/lib-wasi-threads/test/
+
+      - name: build socket api tests
+        if: matrix.test_option == '$WASI_TEST_OPTIONS'
+        run: WASI_SYSROOT=../../../../../core/deps/wasi-libc/sysroot bash build.sh
+        working-directory: ./core/iwasm/libraries/lib-socket/test/
+
+      - name: run tests
+        timeout-minutes: 10
         run: ./test_wamr.sh ${{ matrix.test_option }} -t ${{ matrix.running_mode }}
         working-directory: ./tests/wamr-test-suites
 
@@ -456,7 +581,8 @@ jobs:
           sudo apt-get update &&
           sudo apt install -y g++-multilib lib32gcc-9-dev
 
-      - name: run spec tests x86_32
+      - name: run tests x86_32
+        timeout-minutes: 10
         if: env.TEST_ON_X86_32 == 'true'
         run: ./test_wamr.sh ${{ env.X86_32_TARGET_TEST_OPTIONS }} ${{ matrix.test_option }} -t ${{ matrix.running_mode }}
         working-directory: ./tests/wamr-test-suites

+ 63 - 32
.github/workflows/compilation_on_macos.yml

@@ -51,26 +51,28 @@ env:
   FAST_INTERP_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=0 -DWAMR_BUILD_FAST_INTERP=1 -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_LAZY_JIT=0"
   LLVM_LAZY_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=1"
   LLVM_EAGER_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=0"
-  LLVM_CACHE_SUFFIX: "build-llvm_libraries_ex"
 
 jobs:
   build_llvm_libraries:
     uses: ./.github/workflows/build_llvm_libraries.yml
     with:
-      runs-on: "['macos-latest']"
+      os: "macos-latest"
+      arch: "X86"
 
   build_wamrc:
     needs: [build_llvm_libraries]
     runs-on: ${{ matrix.os }}
     strategy:
       matrix:
-        os: [macos-latest]
+        include:
+          - os: macos-latest
+            llvm_cache_key: ${{ needs.build_llvm_libraries.outputs.cache_key }}
     steps:
       - name: checkout
         uses: actions/checkout@v3
 
       - name: Get LLVM libraries
-        id: cache_llvm
+        id: retrieve_llvm_libs
         uses: actions/cache@v3
         with:
           path: |
@@ -79,10 +81,10 @@ jobs:
             ./core/deps/llvm/build/lib
             ./core/deps/llvm/build/libexec
             ./core/deps/llvm/build/share
-          key: ${{ matrix.os }}-${{ env.LLVM_CACHE_SUFFIX }}
+          key: ${{ matrix.llvm_cache_key }}
 
       - name: Quit if cache miss
-        if: steps.cache_llvm.outputs.cache-hit != 'true'
+        if: steps.retrieve_llvm_libs.outputs.cache-hit != 'true'
         run: echo "::error::can not get prebuilt llvm libraries" && exit 1
 
       - name: Build wamrc
@@ -166,13 +168,16 @@ jobs:
             make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1"
           - make_options_run_mode: $LLVM_EAGER_JIT_BUILD_OPTIONS
             make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1"
+        include:
+          - os: macos-latest
+            llvm_cache_key: ${{ needs.build_llvm_libraries.outputs.cache_key }}
     steps:
       - name: checkout
         uses: actions/checkout@v3
 
       # only download llvm cache when needed
       - name: Get LLVM libraries
-        id: cache_llvm
+        id: retrieve_llvm_libs
         if: endsWith(matrix.make_options_run_mode, '_JIT_BUILD_OPTIONS')
         uses: actions/cache@v3
         with:
@@ -182,10 +187,10 @@ jobs:
             ./core/deps/llvm/build/lib
             ./core/deps/llvm/build/libexec
             ./core/deps/llvm/build/share
-          key: ${{ matrix.os }}-${{ env.LLVM_CACHE_SUFFIX }}
+          key: ${{ matrix.llvm_cache_key }}
 
       - name: Quit if cache miss
-        if: endsWith(matrix.make_options_run_mode, '_JIT_BUILD_OPTIONS') && (steps.cache_llvm.outputs.cache-hit != 'true')
+        if: endsWith(matrix.make_options_run_mode, '_JIT_BUILD_OPTIONS') && (steps.retrieve_llvm_libs.outputs.cache-hit != 'true')
         run: echo "::error::can not get prebuilt llvm libraries" && exit 1
 
       - name: Build iwasm
@@ -210,8 +215,14 @@ jobs:
             #$AOT_BUILD_OPTIONS,
           ]
         os: [macos-latest]
-        wasi_sdk_release: ["https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk-12.0-macos.tar.gz"]
-        wabt_release: ["https://github.com/WebAssembly/wabt/releases/download/1.0.24/wabt-1.0.24-macos.tar.gz"]
+        wasi_sdk_release:
+          [
+            "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-19/wasi-sdk-19.0-macos.tar.gz",
+          ]
+        wabt_release:
+          [
+            "https://github.com/WebAssembly/wabt/releases/download/1.0.31/wabt-1.0.31-macos-12.tar.gz",
+          ]
     steps:
       - name: checkout
         uses: actions/checkout@v3
@@ -220,24 +231,14 @@ jobs:
         run: |
           cd /opt
           sudo wget ${{ matrix.wabt_release }}
-          sudo tar -xzf wabt-1.0.24-*.tar.gz
-          sudo mv wabt-1.0.24 wabt
+          sudo tar -xzf wabt-1.0.31-*.tar.gz
+          sudo mv wabt-1.0.31 wabt
 
       - name: Build Sample [wasm-c-api]
         run: |
-          mkdir build && cd build
-          cmake .. ${{ matrix.make_options }}
-          cmake --build . --config Release --parallel 4
-          ./callback
-          ./callback_chain
-          ./empty_imports
-          ./global
-          ./hello
-          ./hostref
-          ./memory
-          ./reflect
-          ./table
-          ./trap
+          cmake -S . -B build ${{ matrix.make_options }}
+          cmake --build build --config Release --parallel 4
+          ctest --test-dir build
         working-directory: samples/wasm-c-api
 
   build_samples_others:
@@ -246,8 +247,14 @@ jobs:
     strategy:
       matrix:
         os: [macos-latest]
-        wasi_sdk_release: ["https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk-12.0-macos.tar.gz"]
-        wabt_release: ["https://github.com/WebAssembly/wabt/releases/download/1.0.24/wabt-1.0.24-macos.tar.gz"]
+        wasi_sdk_release:
+          [
+            "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-19/wasi-sdk-19.0-macos.tar.gz",
+          ]
+        wabt_release:
+          [
+            "https://github.com/WebAssembly/wabt/releases/download/1.0.31/wabt-1.0.31-macos-12.tar.gz",
+          ]
     steps:
       - name: checkout
         uses: actions/checkout@v3
@@ -256,15 +263,31 @@ jobs:
         run: |
           cd /opt
           sudo wget ${{ matrix.wasi_sdk_release }}
-          sudo tar -xzf wasi-sdk-12.0-*.tar.gz
-          sudo mv wasi-sdk-12.0 wasi-sdk
+          sudo tar -xzf wasi-sdk-*.tar.gz
+          sudo mv wasi-sdk-19.0 wasi-sdk
 
       - name: download and install wabt
         run: |
           cd /opt
           sudo wget ${{ matrix.wabt_release }}
-          sudo tar -xzf wabt-1.0.24-*.tar.gz
-          sudo mv wabt-1.0.24 wabt
+          sudo tar -xzf wabt-1.0.31-*.tar.gz
+          sudo mv wabt-1.0.31 wabt
+
+      - name: build wasi-libc (needed for wasi-threads)
+        run: |
+          mkdir wasi-libc
+          cd wasi-libc
+          git init
+          # "Rename thread_spawn import" commit on main branch
+          git fetch https://github.com/WebAssembly/wasi-libc \
+            8f5275796a82f8ecfd0833a4f3f444fa37ed4546
+          git checkout FETCH_HEAD
+          make \
+            AR=/opt/wasi-sdk/bin/llvm-ar \
+            NM=/opt/wasi-sdk/bin/llvm-nm \
+            CC=/opt/wasi-sdk/bin/clang \
+            THREAD_MODEL=posix
+        working-directory: core/deps
 
       - name: Build Sample [basic]
         run: |
@@ -311,3 +334,11 @@ jobs:
           cmake ..
           cmake --build . --config Release --parallel 4
           ./hello
+
+      - name: Build Sample [wasi-threads]
+        run: |
+          cd samples/wasi-threads
+          mkdir build && cd build
+          cmake -DWASI_SYSROOT=`pwd`/../../../core/deps/wasi-libc/sysroot ..
+          cmake --build . --config Release --parallel 4
+          ./iwasm wasm-apps/no_pthread.wasm

+ 14 - 2
.github/workflows/compilation_on_nuttx.yml

@@ -45,6 +45,9 @@ concurrency:
   group: ${{ github.workflow }}-${{ github.ref }}
   cancel-in-progress: true
 
+env:
+  WASI_SDK_PATH: "/opt/wasi-sdk"
+
 jobs:
   build_iwasm_on_nuttx:
     runs-on: ubuntu-22.04
@@ -65,9 +68,12 @@ jobs:
           "boards/risc-v/k210/maix-bit/configs/nsh",
         ]
         wamr_config_option: [
-          "CONFIG_INTERPRETERS_WAMR=y\\nCONFIG_INTERPRETERS_WAMR_AOT=y\\nCONFIG_INTERPRETERS_WAMR_FAST=y\\nCONFIG_INTERPRETERS_WAMR_LIBC_BUILTIN=y\\n",
           "CONFIG_INTERPRETERS_WAMR=y\\nCONFIG_INTERPRETERS_WAMR_AOT=y\\nCONFIG_INTERPRETERS_WAMR_FAST=y\\n",
+          "CONFIG_INTERPRETERS_WAMR=y\\nCONFIG_INTERPRETERS_WAMR_AOT=y\\nCONFIG_INTERPRETERS_WAMR_FAST=y\\nCONFIG_INTERPRETERS_WAMR_LIBC_WASI=y\\n",
+          "CONFIG_INTERPRETERS_WAMR=y\\nCONFIG_INTERPRETERS_WAMR_AOT=y\\nCONFIG_INTERPRETERS_WAMR_FAST=y\\nCONFIG_INTERPRETERS_WAMR_LIBC_BUILTIN=y\\n",
           "CONFIG_INTERPRETERS_WAMR=y\\nCONFIG_INTERPRETERS_WAMR_AOT=y\\nCONFIG_INTERPRETERS_WAMR_CLASSIC=y\\n",
+          "CONFIG_INTERPRETERS_WAMR=y\\nCONFIG_INTERPRETERS_WAMR_AOT=y\\nCONFIG_INTERPRETERS_WAMR_CLASSIC=y\\nCONFIG_INTERPRETERS_WAMR_LIBC_WASI=y\\n",
+          "CONFIG_INTERPRETERS_WAMR=y\\nCONFIG_INTERPRETERS_WAMR_AOT=y\\nCONFIG_INTERPRETERS_WAMR_CLASSIC=y\\nCONFIG_INTERPRETERS_WAMR_LIBC_BUILTIN=y\\n",
           "CONFIG_INTERPRETERS_WAMR=y\\nCONFIG_INTERPRETERS_WAMR_AOT=y\\nCONFIG_INTERPRETERS_WAMR_LIBC_BUILTIN=y\\n",
           "CONFIG_INTERPRETERS_WAMR=y\\nCONFIG_INTERPRETERS_WAMR_AOT=y\\n",
           "CONFIG_INTERPRETERS_WAMR=y\\nCONFIG_INTERPRETERS_WAMR_FAST=y\\n",
@@ -92,6 +98,12 @@ jobs:
           tar xvf riscv.tar.gz
           echo "$PWD/riscv64-unknown-elf-toolchain-10.2.0-2020.12.8-x86_64-linux-ubuntu14/bin" >> $GITHUB_PATH
 
+      - name: Install WASI-SDK
+        run: |
+          curl -L https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-19/wasi-sdk-19.0-linux.tar.gz > wasi-sdk.tar.gz
+          tar xvf wasi-sdk.tar.gz
+          sudo mv wasi-sdk-* /opt/wasi-sdk
+
       - name: Checkout NuttX
         uses: actions/checkout@v3
         with:
@@ -112,7 +124,7 @@ jobs:
 
       - name: Enable WAMR for NuttX
         run: |
-          find nuttx/boards -name defconfig | xargs sed -i '$a\CONFIG_EOL_IS_LF=y\n${{ matrix.wamr_config_option }}'
+          find nuttx/boards -name defconfig | xargs sed -i '$a\CONFIG_EOL_IS_LF=y\nCONFIG_PSEUDOFS_SOFTLINKS=y\n${{ matrix.wamr_config_option }}'
           find nuttx/boards/sim -name defconfig | xargs sed -i '$a\CONFIG_LIBM=y\n'
 
       - name: Build

+ 49 - 32
.github/workflows/compilation_on_sgx.yml

@@ -51,13 +51,13 @@ env:
   FAST_INTERP_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=0 -DWAMR_BUILD_FAST_INTERP=1 -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_LAZY_JIT=0"
   LLVM_LAZY_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=1"
   LLVM_EAGER_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=0"
-  LLVM_CACHE_SUFFIX: "build-llvm_libraries_ex"
 
 jobs:
   build_llvm_libraries:
     uses: ./.github/workflows/build_llvm_libraries.yml
     with:
-      runs-on: "['ubuntu-20.04']"
+      os: "ubuntu-20.04"
+      arch: "X86"
 
   build_iwasm:
     runs-on: ${{ matrix.os }}
@@ -131,7 +131,9 @@ jobs:
     runs-on: ${{ matrix.os }}
     strategy:
       matrix:
-        os: [ubuntu-20.04]
+        include:
+          - os: ubuntu-20.04
+            llvm_cache_key: ${{ needs.build_llvm_libraries.outputs.cache_key }}
     steps:
       - name: install SGX SDK and necessary libraries
         run: |
@@ -150,7 +152,7 @@ jobs:
         uses: actions/checkout@v3
 
       - name: Get LLVM libraries
-        id: cache_llvm
+        id: retrieve_llvm_libs
         uses: actions/cache@v3
         with:
           path: |
@@ -159,10 +161,10 @@ jobs:
             ./core/deps/llvm/build/lib
             ./core/deps/llvm/build/libexec
             ./core/deps/llvm/build/share
-          key: ${{ matrix.os }}-${{ env.LLVM_CACHE_SUFFIX }}
+          key: ${{ matrix.llvm_cache_key }}
 
       - name: Quit if cache miss
-        if: steps.cache_llvm.outputs.cache-hit != 'true'
+        if: steps.retrieve_llvm_libs.outputs.cache-hit != 'true'
         run: echo "::error::can not get prebuilt llvm libraries" && exit 1
 
       - name: Build wamrc
@@ -189,11 +191,11 @@ jobs:
         os: [ubuntu-20.04]
         wasi_sdk_release:
           [
-            "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk-12.0-linux.tar.gz",
+            "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-19/wasi-sdk-19.0-linux.tar.gz",
           ]
         wabt_release:
           [
-            "https://github.com/WebAssembly/wabt/releases/download/1.0.24/wabt-1.0.24-ubuntu.tar.gz",
+            "https://github.com/WebAssembly/wabt/releases/download/1.0.31/wabt-1.0.31-ubuntu.tar.gz",
           ]
     steps:
       - name: checkout
@@ -203,8 +205,8 @@ jobs:
         run: |
           cd /opt
           sudo wget ${{ matrix.wabt_release }}
-          sudo tar -xzf wabt-1.0.24-*.tar.gz
-          sudo mv wabt-1.0.24 wabt
+          sudo tar -xzf wabt-1.0.31-*.tar.gz
+          sudo mv wabt-1.0.31 wabt
 
       - name: install SGX SDK and necessary libraries
         run: |
@@ -221,19 +223,9 @@ jobs:
 
       - name: Build Sample [wasm-c-api]
         run: |
-          mkdir build && cd build
-          cmake .. ${{ matrix.make_options }}
-          cmake --build . --config Release --parallel 4
-          ./callback
-          ./callback_chain
-          ./empty_imports
-          ./global
-          ./hello
-          ./hostref
-          ./memory
-          ./reflect
-          ./table
-          ./trap
+          cmake -S . -B build ${{ matrix.make_options }}
+          cmake --build build --config Release --parallel 4
+          ctest --test-dir build
         working-directory: samples/wasm-c-api
 
   build_samples_others:
@@ -244,11 +236,11 @@ jobs:
         os: [ubuntu-20.04]
         wasi_sdk_release:
           [
-            "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk-12.0-linux.tar.gz",
+            "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-19/wasi-sdk-19.0-linux.tar.gz",
           ]
         wabt_release:
           [
-            "https://github.com/WebAssembly/wabt/releases/download/1.0.24/wabt-1.0.24-ubuntu.tar.gz",
+            "https://github.com/WebAssembly/wabt/releases/download/1.0.31/wabt-1.0.31-ubuntu.tar.gz",
           ]
     steps:
       - name: checkout
@@ -258,15 +250,31 @@ jobs:
         run: |
           cd /opt
           sudo wget ${{ matrix.wasi_sdk_release }}
-          sudo tar -xzf wasi-sdk-12.0-*.tar.gz
-          sudo mv wasi-sdk-12.0 wasi-sdk
+          sudo tar -xzf wasi-sdk-*.tar.gz
+          sudo mv wasi-sdk-19.0 wasi-sdk
 
       - name: download and install wabt
         run: |
           cd /opt
           sudo wget ${{ matrix.wabt_release }}
-          sudo tar -xzf wabt-1.0.24-*.tar.gz
-          sudo mv wabt-1.0.24 wabt
+          sudo tar -xzf wabt-1.0.31-*.tar.gz
+          sudo mv wabt-1.0.31 wabt
+
+      - name: build wasi-libc (needed for wasi-threads)
+        run: |
+          mkdir wasi-libc
+          cd wasi-libc
+          git init
+          # "Rename thread_spawn import" commit on main branch
+          git fetch https://github.com/WebAssembly/wasi-libc \
+            8f5275796a82f8ecfd0833a4f3f444fa37ed4546
+          git checkout FETCH_HEAD
+          make \
+            AR=/opt/wasi-sdk/bin/llvm-ar \
+            NM=/opt/wasi-sdk/bin/llvm-nm \
+            CC=/opt/wasi-sdk/bin/clang \
+            THREAD_MODEL=posix
+        working-directory: core/deps
 
       - name: install SGX SDK and necessary libraries
         run: |
@@ -327,6 +335,14 @@ jobs:
           cmake --build . --config Release --parallel 4
           ./hello
 
+      - name: Build Sample [wasi-threads]
+        run: |
+          cd samples/wasi-threads
+          mkdir build && cd build
+          cmake -DWASI_SYSROOT=`pwd`/../../../core/deps/wasi-libc/sysroot ..
+          cmake --build . --config Release --parallel 4
+          ./iwasm wasm-apps/no_pthread.wasm
+
   spec_test_default:
     needs: [build_iwasm, build_llvm_libraries, build_wamrc]
     runs-on: ubuntu-20.04
@@ -334,6 +350,7 @@ jobs:
       matrix:
         running_mode: ["classic-interp", "fast-interp", "aot"]
         test_option: ["-x -p -s spec -b -P", "-x -p -s spec -S -b -P"]
+        llvm_cache_key: ["${{ needs.build_llvm_libraries.outputs.cache_key }}"]
         # classic-interp and fast-interp don't support simd
         exclude:
           - running_mode: "classic-interp"
@@ -347,7 +364,7 @@ jobs:
 
       - name: Get LLVM libraries
         if: matrix.running_mode == 'aot'
-        id: cache_llvm
+        id: retrieve_llvm_libs
         uses: actions/cache@v3
         with:
           path: |
@@ -356,10 +373,10 @@ jobs:
             ./core/deps/llvm/build/lib
             ./core/deps/llvm/build/libexec
             ./core/deps/llvm/build/share
-          key: ubuntu-20.04-${{ env.LLVM_CACHE_SUFFIX }}
+          key: ${{ matrix.llvm_cache_key }}
 
       - name: Quit if cache miss
-        if: matrix.running_mode == 'aot' && steps.cache_llvm.outputs.cache-hit != 'true'
+        if: matrix.running_mode == 'aot' && steps.retrieve_llvm_libs.outputs.cache-hit != 'true'
         run: echo "::error::can not get prebuilt llvm libraries" && exit 1
 
       - name: install SGX SDK and necessary libraries

+ 14 - 0
.github/workflows/compilation_on_windows.yml

@@ -118,3 +118,17 @@ jobs:
           cmake .. -DWAMR_BUILD_DEBUG_INTERP=1
           cmake --build . --config Release --parallel 4
           cd .. && rm -force -r build
+      - name: Build iwasm [lib pthread]
+        run: |
+          cd product-mini/platforms/windows
+          mkdir build && cd build
+          cmake .. -DWAMR_BUILD_LIB_PTHREAD=1
+          cmake --build . --config Release --parallel 4
+          cd .. && rm -force -r build
+      - name: Build iwasm [lib wasi-thread]
+        run: |
+          cd product-mini/platforms/windows
+          mkdir build && cd build
+          cmake .. -DWAMR_BUILD_LIB_WASI_THREADS=1
+          cmake --build . --config Release --parallel 4
+          cd .. && rm -force -r build

+ 4 - 3
.github/workflows/release_process.yml

@@ -123,7 +123,7 @@ jobs:
       runner: ubuntu-20.04
       upload_url: ${{ needs.create_release.outputs.upload_url }}
       ver_num: ${{ needs.create_tag.outputs.new_ver}}
-      wasi_sdk_url: https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk-12.0-linux.tar.gz
+      wasi_sdk_url: https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-19/wasi-sdk-19.0-linux.tar.gz
 
   release_wamr_sdk_on_ubuntu_2204:
     needs: [create_tag, create_release]
@@ -133,7 +133,7 @@ jobs:
       runner: ubuntu-22.04
       upload_url: ${{ needs.create_release.outputs.upload_url }}
       ver_num: ${{ needs.create_tag.outputs.new_ver}}
-      wasi_sdk_url: https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk-12.0-linux.tar.gz
+      wasi_sdk_url: https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-19/wasi-sdk-19.0-linux.tar.gz
 
   release_wamr_sdk_on_macos:
     needs: [create_tag, create_release]
@@ -143,13 +143,14 @@ jobs:
       runner: macos-latest
       upload_url: ${{ needs.create_release.outputs.upload_url }}
       ver_num: ${{ needs.create_tag.outputs.new_ver}}
-      wasi_sdk_url: https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk-12.0-macos.tar.gz
+      wasi_sdk_url: https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-19/wasi-sdk-19.0-macos.tar.gz
 
   #
   # vscode extension cross-platform
   release_wamr_ide_vscode_ext:
     needs: [create_tag, create_release]
     uses: ./.github/workflows/build_wamr_vscode_ext.yml
+    secrets: inherit
     with:
       upload_url: ${{ needs.create_release.outputs.upload_url }}
       ver_num: ${{ needs.create_tag.outputs.new_ver }}

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

@@ -11,12 +11,14 @@ on:
 
 env:
   LLVM_CACHE_SUFFIX: "build-llvm_libraries_ex"
+  WASI_SDK_PATH: "/opt/wasi-sdk"
 
 jobs:
   build_llvm_libraries:
     uses: ./.github/workflows/build_llvm_libraries.yml
     with:
-      runs-on: "['ubuntu-22.04']"
+      os: "ubuntu-22.04"
+      arch: "ARM RISCV AArch64"
 
   spec_test_on_qemu:
     runs-on: ${{ matrix.os }}
@@ -37,6 +39,7 @@ jobs:
           "-t aot",
           "-t aot -X"
         ]
+        llvm_cache_key: [ "${{ needs.build_llvm_libraries.outputs.cache_key }}" ]
     steps:
       - name: Install Utilities
         run: |
@@ -53,6 +56,12 @@ jobs:
           tar xvf riscv.tar.gz
           echo "$PWD/riscv64-unknown-elf-toolchain-10.2.0-2020.12.8-x86_64-linux-ubuntu14/bin" >> $GITHUB_PATH
 
+      - name: Install WASI-SDK
+        run: |
+          curl -L https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-19/wasi-sdk-19.0-linux.tar.gz > wasi-sdk.tar.gz
+          tar xvf wasi-sdk.tar.gz
+          sudo mv wasi-sdk-* /opt/wasi-sdk
+
       - name: Checkout NuttX
         uses: actions/checkout@v3
         with:
@@ -72,7 +81,7 @@ jobs:
           path: apps/interpreters/wamr/wamr
 
       - name: Get LLVM libraries
-        id: cache_llvm
+        id: retrieve_llvm_libs
         uses: actions/cache@v3
         with:
           path: |
@@ -81,10 +90,10 @@ jobs:
             ./core/deps/llvm/build/lib
             ./core/deps/llvm/build/libexec
             ./core/deps/llvm/build/share
-          key:  ${{ matrix.os }}-${{ env.LLVM_CACHE_SUFFIX }}
+          key: ${{ matrix.llvm_cache_key }}
 
       - name: Quit if cache miss
-        if: steps.cache_llvm.outputs.cache-hit != 'true'
+        if: steps.retrieve_llvm_libs.outputs.cache-hit != 'true'
         run: echo "::error::can not get prebuilt llvm libraries" && exit 1
 
       - name: Copy LLVM

+ 7 - 0
.gitignore

@@ -13,6 +13,8 @@
 core/deps/**
 core/shared/mem-alloc/tlsf
 core/app-framework/wgl
+core/iwasm/libraries/lib-wasi-threads/test/*.wasm
+core/iwasm/libraries/lib-socket/test/*.wasm
 
 wamr-sdk/out/
 wamr-sdk/runtime/build_runtime_sdk/
@@ -32,3 +34,8 @@ samples/socket-api/wasm-src/inc/pthread.h
 **/__pycache__
 
 tests/benchmarks/coremark/coremark*
+
+samples/workload/include/**
+!samples/workload/include/.gitkeep
+
+# core/iwasm/libraries/wasi-threads

+ 17 - 11
CMakeLists.txt

@@ -7,7 +7,9 @@ project (iwasm)
 
 set (CMAKE_VERBOSE_MAKEFILE OFF)
 
-string (TOLOWER ${CMAKE_HOST_SYSTEM_NAME} WAMR_BUILD_PLATFORM)
+if (NOT DEFINED WAMR_BUILD_PLATFORM)
+  string (TOLOWER ${CMAKE_HOST_SYSTEM_NAME} WAMR_BUILD_PLATFORM)
+endif ()
 
 # Reset default linker flags
 set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")
@@ -83,6 +85,11 @@ if (NOT DEFINED WAMR_BUILD_LIB_PTHREAD)
   set (WAMR_BUILD_LIB_PTHREAD 0)
 endif ()
 
+if (NOT DEFINED WAMR_BUILD_LIB_WASI_THREADS)
+  # Disable wasi threads library by default
+  set (WAMR_BUILD_LIB_WASI_THREADS 0)
+endif ()
+
 if (NOT DEFINED WAMR_BUILD_MINI_LOADER)
   # Disable wasm mini loader by default
   set (WAMR_BUILD_MINI_LOADER 0)
@@ -98,11 +105,6 @@ if (NOT DEFINED WAMR_BUILD_REF_TYPES)
   set (WAMR_BUILD_REF_TYPES 0)
 endif ()
 
-if (COLLECT_CODE_COVERAGE EQUAL 1)
-  set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage")
-  set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage")
-endif ()
-
 set (WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR})
 
 include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake)
@@ -130,23 +132,26 @@ include (${SHARED_DIR}/utils/uncommon/shared_uncommon.cmake)
 
 # STATIC LIBRARY
 add_library(iwasm_static STATIC ${WAMR_RUNTIME_LIB_SOURCE})
+set_target_properties (iwasm_static PROPERTIES OUTPUT_NAME vmlib)
+target_include_directories(iwasm_static INTERFACE ${WAMR_ROOT_DIR}/core/iwasm/include)
+target_link_libraries (iwasm_static INTERFACE ${LLVM_AVAILABLE_LIBS} ${UV_A_LIBS} -lm -ldl -lpthread)
 if (WAMR_BUILD_WASM_CACHE EQUAL 1)
-  target_link_libraries(iwasm_static PUBLIC boringssl_crypto)
+  target_link_libraries(iwasm_static INTERFACE boringssl_crypto)
 endif ()
-set_target_properties (iwasm_static PROPERTIES OUTPUT_NAME vmlib)
 
 install (TARGETS iwasm_static ARCHIVE DESTINATION lib)
 
 # SHARED LIBRARY
 add_library (iwasm_shared SHARED ${WAMR_RUNTIME_LIB_SOURCE})
 set_target_properties (iwasm_shared PROPERTIES OUTPUT_NAME iwasm)
-target_link_libraries (iwasm_shared ${LLVM_AVAILABLE_LIBS} ${UV_A_LIBS} -lm -ldl -lpthread)
+target_include_directories(iwasm_shared INTERFACE ${WAMR_ROOT_DIR}/core/iwasm/include)
+target_link_libraries (iwasm_shared INTERFACE ${LLVM_AVAILABLE_LIBS} ${UV_A_LIBS} -lm -ldl -lpthread)
 if (WAMR_BUILD_WASM_CACHE EQUAL 1)
-  target_link_libraries(iwasm_shared boringssl_crypto)
+  target_link_libraries(iwasm_shared INTERFACE boringssl_crypto)
 endif ()
 
 if (MINGW)
-target_link_libraries (iwasm_shared -lWs2_32)
+  target_link_libraries (iwasm_shared -lWs2_32)
 endif ()
 
 install (TARGETS iwasm_shared LIBRARY DESTINATION lib)
@@ -155,4 +160,5 @@ install (TARGETS iwasm_shared LIBRARY DESTINATION lib)
 install (FILES
     ${WAMR_ROOT_DIR}/core/iwasm/include/wasm_c_api.h
     ${WAMR_ROOT_DIR}/core/iwasm/include/wasm_export.h
+    ${WAMR_ROOT_DIR}/core/iwasm/include/lib_export.h
     DESTINATION include)

+ 92 - 32
build-scripts/build_llvm.py

@@ -7,6 +7,7 @@
 import argparse
 import os
 import pathlib
+import requests
 import shlex
 import shutil
 import subprocess
@@ -21,28 +22,44 @@ def clone_llvm(dst_dir, llvm_repo, llvm_branch):
     llvm_dir = dst_dir.joinpath("llvm").resolve()
 
     if not llvm_dir.exists():
-        print(f"Clone llvm to {llvm_dir} ...")
         GIT_CLONE_CMD = f"git clone --depth 1 --branch {llvm_branch} {llvm_repo} llvm"
+        print(GIT_CLONE_CMD)
         subprocess.check_output(shlex.split(GIT_CLONE_CMD), cwd=dst_dir)
-    else:
-        print(f"There is an LLVM local repo in {llvm_dir}, clean and keep using it")
 
     return llvm_dir
 
 
-def build_llvm(llvm_dir, platform, backends, projects):
+def query_llvm_version(llvm_info):
+    github_token = os.environ['GH_TOKEN']
+    owner_project = llvm_info['repo'].replace("https://github.com/", "").replace(".git", "")
+    url = f"https://api.github.com/repos/{owner_project}/commits/{llvm_info['branch']}"
+    headers = {
+        'Authorization': f"Bearer {github_token}"
+    }
+
+    try:
+        response = requests.request("GET", url, headers=headers, data={})
+        response.raise_for_status()
+    except requests.exceptions.HTTPError as error:
+        print (error) # for debugging purpose
+        return None
+
+    response = response.json()
+    return response['sha']
+
+
+def build_llvm(llvm_dir, platform, backends, projects, use_clang=False, extra_flags=''):
     LLVM_COMPILE_OPTIONS = [
         '-DCMAKE_BUILD_TYPE:STRING="Release"',
         "-DCMAKE_EXPORT_COMPILE_COMMANDS=ON",
         "-DLLVM_APPEND_VC_REV:BOOL=ON",
-        "-DLLVM_BUILD_BENCHMARKS:BOOL=OFF",
-        "-DLLVM_BUILD_DOCS:BOOL=OFF",
         "-DLLVM_BUILD_EXAMPLES:BOOL=OFF",
         "-DLLVM_BUILD_LLVM_DYLIB:BOOL=OFF",
         "-DLLVM_BUILD_TESTS:BOOL=OFF",
-        "-DLLVM_CCACHE_BUILD:BOOL=OFF",
+        "-DLLVM_CCACHE_BUILD:BOOL=ON",
         "-DLLVM_ENABLE_BINDINGS:BOOL=OFF",
         "-DLLVM_ENABLE_IDE:BOOL=OFF",
+        "-DLLVM_ENABLE_LIBEDIT=OFF",
         "-DLLVM_ENABLE_TERMINFO:BOOL=OFF",
         "-DLLVM_ENABLE_ZLIB:BOOL=OFF",
         "-DLLVM_INCLUDE_BENCHMARKS:BOOL=OFF",
@@ -54,6 +71,18 @@ def build_llvm(llvm_dir, platform, backends, projects):
         "-DLLVM_OPTIMIZED_TABLEGEN:BOOL=ON",
     ]
 
+    # use clang/clang++/lld. but macos doesn't support lld
+    if not sys.platform.startswith("darwin") and use_clang:
+        if shutil.which("clang") and shutil.which("clang++") and shutil.which("lld"):
+            os.environ["CC"] = "clang"
+            os.environ["CXX"] = "clang++"
+            LLVM_COMPILE_OPTIONS.append('-DLLVM_USE_LINKER:STRING="lld"')
+            print("Use the clang toolchain")
+        else:
+            print("Can not find clang, clang++ and lld, keep using the gcc toolchain")
+    else:
+        print("Use the gcc toolchain")
+
     LLVM_EXTRA_COMPILE_OPTIONS = {
         "arc": [
             '-DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD:STRING="ARC"',
@@ -99,8 +128,10 @@ def build_llvm(llvm_dir, platform, backends, projects):
 
     lib_llvm_core_library = build_dir.joinpath("lib/libLLVMCore.a").resolve()
     if lib_llvm_core_library.exists():
-        print(f"Please remove {build_dir} manually and try again")
-        return build_dir
+        print(
+            f"It has already been fully compiled. If want to a re-build, please remove {build_dir} manually and try again"
+        )
+        return None
 
     compile_options = " ".join(
         LLVM_COMPILE_OPTIONS
@@ -113,16 +144,17 @@ def build_llvm(llvm_dir, platform, backends, projects):
         + LLVM_INCLUDE_TOOLS_OPTION
     )
 
-    CONFIG_CMD = f"cmake {compile_options} ../llvm"
+    CONFIG_CMD = f"cmake {compile_options} {extra_flags} ../llvm"
     if "windows" == platform:
         if "mingw" in sysconfig.get_platform().lower():
             CONFIG_CMD += " -G'Unix Makefiles'"
         else:
             CONFIG_CMD += " -A x64"
-    print(f"{CONFIG_CMD}")
+    else:
+        CONFIG_CMD += " -G'Ninja'"
     subprocess.check_call(shlex.split(CONFIG_CMD), cwd=build_dir)
 
-    BUILD_CMD = f"cmake --build . --target package --parallel {os.cpu_count()}" + (
+    BUILD_CMD = "cmake --build . --target package" + (
         " --config Release" if "windows" == platform else ""
     )
     subprocess.check_call(shlex.split(BUILD_CMD), cwd=build_dir)
@@ -133,23 +165,25 @@ def build_llvm(llvm_dir, platform, backends, projects):
 def repackage_llvm(llvm_dir):
     build_dir = llvm_dir.joinpath("./build").resolve()
 
-    packs = [f for f in build_dir.glob("LLVM-13*.tar.gz")]
+    packs = [f for f in build_dir.glob("LLVM-*.tar.gz")]
     if len(packs) > 1:
-        raise Exception("Find more than one LLVM-13*.tar.gz")
+        raise Exception("Find more than one LLVM-*.tar.gz")
 
     if not packs:
         return
 
     llvm_package = packs[0].name
-    # mv build/LLVM-13.0.0*.gz .
+    # mv build/LLVM-*.gz .
     shutil.move(str(build_dir.joinpath(llvm_package).resolve()), str(llvm_dir))
     # rm -r build
     shutil.rmtree(str(build_dir))
     # mkdir build
     build_dir.mkdir()
-    # tar xf ./LLVM-13.0.0-*.tar.gz --strip-components=1 --directory=build
+    # tar xf ./LLVM-*.tar.gz --strip-components=1 --directory=build
     CMD = f"tar xf {llvm_dir.joinpath(llvm_package).resolve()} --strip-components=1 --directory={build_dir}"
     subprocess.check_call(shlex.split(CMD), cwd=llvm_dir)
+    # rm ./LLVM-1*.gz
+    os.remove(llvm_dir.joinpath(llvm_package).resolve())
 
 
 def main():
@@ -184,8 +218,23 @@ def main():
         choices=["clang", "lldb"],
         help="identify extra LLVM projects, separate by space, like '--project clang lldb'",
     )
+    parser.add_argument(
+        "--llvm-ver",
+        action="store_true",
+        help="return the version info of generated llvm libraries",
+    )
+    parser.add_argument(
+        "--use-clang",
+        action="store_true",
+        help="use clang instead of gcc",
+    )
+    parser.add_argument(
+        "--extra-cmake-flags",
+        type=str,
+        default="",
+        help="custom extra cmake flags",
+    )
     options = parser.parse_args()
-    print(f"options={options}")
 
     # if the "platform" is not identified in the command line option,
     # detect it
@@ -199,20 +248,21 @@ def main():
     else:
         platform = options.platform
 
-    print(f"========== Build LLVM for {platform} ==========\n")
-
     llvm_repo_and_branch = {
         "arc": {
             "repo": "https://github.com/llvm/llvm-project.git",
-            "branch": "release/13.x",
+            "repo_ssh": "git@github.com:llvm/llvm-project.git",
+            "branch": "release/15.x",
         },
         "xtensa": {
-            "repo": "https://github.com/espressif/llvm-project.git",
+            "repo": "https://github.com/espressif/llvm-project.git", 
+            "repo_ssh": "git@github.com:espressif/llvm-project.git",
             "branch": "xtensa_release_15.x",
         },
         "default": {
             "repo": "https://github.com/llvm/llvm-project.git",
-            "branch": "release/13.x",
+            "repo_ssh": "git@github.com:llvm/llvm-project.git",
+            "branch": "release/15.x",
         },
     }
 
@@ -225,19 +275,29 @@ def main():
     deps_dir = current_dir.joinpath("../core/deps").resolve()
 
     try:
-        print(f"==================== CLONE LLVM ====================")
         llvm_info = llvm_repo_and_branch.get(platform, llvm_repo_and_branch["default"])
-        llvm_dir = clone_llvm(deps_dir, llvm_info["repo"], llvm_info["branch"])
 
-        print()
-        print(f"==================== BUILD LLVM ====================")
-        build_llvm(llvm_dir, platform, options.arch, options.project)
-
-        print()
-        print(f"==================== PACKAGE LLVM ====================")
-        repackage_llvm(llvm_dir)
+        if options.llvm_ver:
+            commit_hash = query_llvm_version(llvm_info)
+            print(commit_hash)
+            return commit_hash is not None
+        
+        repo_addr = llvm_info["repo"]
+        if os.environ.get('USE_GIT_SSH') == "true":
+            repo_addr = llvm_info["repo_ssh"]
+        else:
+            print("To use ssh for git clone, run: export USE_GIT_SSH=true")
+        
+        llvm_dir = clone_llvm(deps_dir, repo_addr, llvm_info["branch"])
+        if (
+            build_llvm(
+                llvm_dir, platform, options.arch, options.project, options.use_clang,
+                options.extra_cmake_flags
+            )
+            is not None
+        ):
+            repackage_llvm(llvm_dir)
 
-        print()
         return True
     except subprocess.CalledProcessError:
         return False

+ 15 - 0
build-scripts/config_common.cmake

@@ -333,6 +333,11 @@ if (WAMR_BUILD_SGX_IPFS EQUAL 1)
 endif ()
 if (WAMR_BUILD_WASI_NN EQUAL 1)
   message ("     WASI-NN enabled")
+  add_definitions (-DWASM_ENABLE_WASI_NN=1)
+  if (WASI_NN_ENABLE_GPU EQUAL 1)
+      message ("     WASI-NN: GPU enabled")
+      add_definitions (-DWASI_NN_ENABLE_GPU=1)
+  endif ()
 endif ()
 if (WAMR_BUILD_ALLOC_WITH_USER_DATA EQUAL 1)
   add_definitions(-DWASM_MEM_ALLOC_WITH_USER_DATA=1)
@@ -341,3 +346,13 @@ if (WAMR_BUILD_WASM_CACHE EQUAL 1)
   add_definitions (-DWASM_ENABLE_WASM_CACHE=1)
   message ("     Wasm files cache enabled")
 endif ()
+if (WAMR_BUILD_GC_HEAP_VERIFY EQUAL 1)
+  add_definitions (-DWASM_ENABLE_GC_VERIFY=1)
+  message ("     GC heap verification enabled")
+endif ()
+if ("$ENV{COLLECT_CODE_COVERAGE}" STREQUAL "1" OR COLLECT_CODE_COVERAGE EQUAL 1)
+  set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage")
+  set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage")
+  add_definitions (-DCOLLECT_CODE_COVERAGE)
+  message ("     Collect code coverage enabled")
+endif ()

+ 1 - 0
build-scripts/requirements.txt

@@ -0,0 +1 @@
+requests==2.28.2

+ 29 - 4
build-scripts/runtime_lib.cmake

@@ -19,6 +19,11 @@ endif ()
 if (NOT DEFINED DEPS_DIR)
     set (DEPS_DIR ${WAMR_ROOT_DIR}/core/deps)
 endif ()
+if (NOT DEFINED SHARED_PLATFORM_CONFIG)
+    # CMake file for platform configuration. The PLATFORM_SHARED_SOURCE varable
+    # should point to a list of platform-specfic source files to compile.
+    set (SHARED_PLATFORM_CONFIG ${SHARED_DIR}/platform/${WAMR_BUILD_PLATFORM}/shared_platform.cmake)
+endif ()
 
 if (DEFINED EXTRA_SDK_INCLUDE_PATH)
     message(STATUS, "EXTRA_SDK_INCLUDE_PATH = ${EXTRA_SDK_INCLUDE_PATH} ")
@@ -96,10 +101,21 @@ if (WAMR_BUILD_LIB_PTHREAD_SEMAPHORE EQUAL 1)
 endif ()
 
 if (WAMR_BUILD_WASI_NN EQUAL 1)
-    execute_process(COMMAND ${WAMR_ROOT_DIR}/core/deps/install_tensorflow.sh
-                    RESULT_VARIABLE TENSORFLOW_RESULT
-    )
+    if (NOT EXISTS "${WAMR_ROOT_DIR}/core/deps/tensorflow-src")
+        execute_process(COMMAND ${WAMR_ROOT_DIR}/core/deps/install_tensorflow.sh
+                        RESULT_VARIABLE TENSORFLOW_RESULT
+        )
+    else ()
+        message("Tensorflow is already downloaded.")
+    endif()
     set(TENSORFLOW_SOURCE_DIR "${WAMR_ROOT_DIR}/core/deps/tensorflow-src")
+
+    if (WASI_NN_ENABLE_GPU EQUAL 1)
+        # Tensorflow specific:
+        # * https://www.tensorflow.org/lite/guide/build_cmake#available_options_to_build_tensorflow_lite
+        set (TFLITE_ENABLE_GPU ON)
+    endif ()
+
     include_directories (${CMAKE_CURRENT_BINARY_DIR}/flatbuffers/include)
     include_directories (${TENSORFLOW_SOURCE_DIR})
     add_subdirectory(
@@ -116,6 +132,14 @@ if (WAMR_BUILD_LIB_PTHREAD EQUAL 1)
     set (WAMR_BUILD_SHARED_MEMORY 1)
 endif ()
 
+if (WAMR_BUILD_LIB_WASI_THREADS EQUAL 1)
+    include (${IWASM_DIR}/libraries/lib-wasi-threads/lib_wasi_threads.cmake)
+    # Enable the dependent feature if lib wasi threads is enabled
+    set (WAMR_BUILD_THREAD_MGR 1)
+    set (WAMR_BUILD_BULK_MEMORY 1)
+    set (WAMR_BUILD_SHARED_MEMORY 1)
+endif ()
+
 if (WAMR_BUILD_DEBUG_INTERP EQUAL 1)
     set (WAMR_BUILD_THREAD_MGR 1)
     include (${IWASM_DIR}/libraries/debug-engine/debug_engine.cmake)
@@ -161,7 +185,7 @@ LIST (APPEND RUNTIME_LIB_HEADER_LIST ${header})
 
 enable_language (ASM)
 
-include (${SHARED_DIR}/platform/${WAMR_BUILD_PLATFORM}/shared_platform.cmake)
+include (${SHARED_PLATFORM_CONFIG})
 include (${SHARED_DIR}/mem-alloc/mem_alloc.cmake)
 include (${IWASM_DIR}/common/iwasm_common.cmake)
 include (${SHARED_DIR}/utils/shared_utils.cmake)
@@ -182,6 +206,7 @@ set (source_all
     ${WASM_APP_LIB_SOURCE_ALL}
     ${NATIVE_INTERFACE_SOURCE}
     ${APP_MGR_SOURCE}
+    ${LIB_WASI_THREADS_SOURCE}
     ${LIB_PTHREAD_SOURCE}
     ${THREAD_MGR_SOURCE}
     ${LIBC_EMCC_SOURCE}

+ 155 - 39
core/app-framework/app-native-shared/attr_container.c

@@ -7,11 +7,14 @@
 
 typedef union jvalue {
     bool z;
-    int8_t b;
-    uint16_t c;
-    int16_t s;
-    int32_t i;
-    int64_t j;
+    int8_t i8;
+    uint8_t u8;
+    int16_t i16;
+    uint16_t u16;
+    int32_t i32;
+    uint32_t u32;
+    int64_t i64;
+    uint64_t u64;
     float f;
     double d;
 } jvalue;
@@ -27,7 +30,9 @@ get_int16(const char *buf)
 static inline uint16_t
 get_uint16(const char *buf)
 {
-    return get_int16(buf);
+    uint16_t ret;
+    bh_memcpy_s(&ret, sizeof(uint16_t), buf, sizeof(uint16_t));
+    return ret;
 }
 
 static inline int32_t
@@ -41,7 +46,9 @@ get_int32(const char *buf)
 static inline uint32_t
 get_uint32(const char *buf)
 {
-    return get_int32(buf);
+    uint32_t ret;
+    bh_memcpy_s(&ret, sizeof(uint32_t), buf, sizeof(uint32_t));
+    return ret;
 }
 
 static inline int64_t
@@ -55,7 +62,9 @@ get_int64(const char *buf)
 static inline uint64_t
 get_uint64(const char *buf)
 {
-    return get_int64(buf);
+    uint64_t ret;
+    bh_memcpy_s(&ret, sizeof(uint64_t), buf, sizeof(uint64_t));
+    return ret;
 }
 
 static inline void
@@ -145,8 +154,8 @@ attr_container_get_attr_next(const char *curr_attr)
     p += sizeof(uint16_t) + get_uint16(p);
     type = *p++;
 
-    /* Short type to Boolean type */
-    if (type >= ATTR_TYPE_SHORT && type <= ATTR_TYPE_BOOLEAN) {
+    /* Byte type to Boolean type */
+    if (type >= ATTR_TYPE_BYTE && type <= ATTR_TYPE_BOOLEAN) {
         p += 1 << (type & 3);
         return p;
     }
@@ -342,7 +351,7 @@ attr_container_set_attr(attr_container_t **p_attr_cont, const char *key,
 
     /* key len + key + '\0' + type */
     attr_len = sizeof(uint16_t) + strlen(key) + 1 + 1;
-    if (type >= ATTR_TYPE_SHORT && type <= ATTR_TYPE_BOOLEAN)
+    if (type >= ATTR_TYPE_BYTE && type <= ATTR_TYPE_BOOLEAN)
         attr_len += 1 << (type & 3);
     else if (type == ATTR_TYPE_STRING)
         attr_len += sizeof(uint16_t) + value_length;
@@ -362,7 +371,7 @@ attr_container_set_attr(attr_container_t **p_attr_cont, const char *key,
     p += str_len;
 
     *p++ = type;
-    if (type >= ATTR_TYPE_SHORT && type <= ATTR_TYPE_BOOLEAN)
+    if (type >= ATTR_TYPE_BYTE && type <= ATTR_TYPE_BOOLEAN)
         bh_memcpy_s(p, 1 << (type & 3), value, 1 << (type & 3));
     else if (type == ATTR_TYPE_STRING) {
         set_uint16(p, value_length);
@@ -460,6 +469,14 @@ attr_container_set_short(attr_container_t **p_attr_cont, const char *key,
                                    2);
 }
 
+bool
+attr_container_set_int16(attr_container_t **p_attr_cont, const char *key,
+                         int16_t value)
+{
+    return attr_container_set_attr(p_attr_cont, key, ATTR_TYPE_INT16, &value,
+                                   2);
+}
+
 bool
 attr_container_set_int(attr_container_t **p_attr_cont, const char *key,
                        int value)
@@ -467,6 +484,22 @@ attr_container_set_int(attr_container_t **p_attr_cont, const char *key,
     return attr_container_set_attr(p_attr_cont, key, ATTR_TYPE_INT, &value, 4);
 }
 
+bool
+attr_container_set_int32(attr_container_t **p_attr_cont, const char *key,
+                         int32_t value)
+{
+    return attr_container_set_attr(p_attr_cont, key, ATTR_TYPE_INT32, &value,
+                                   4);
+}
+
+bool
+attr_container_set_uint32(attr_container_t **p_attr_cont, const char *key,
+                          uint32_t value)
+{
+    return attr_container_set_attr(p_attr_cont, key, ATTR_TYPE_UINT32, &value,
+                                   4);
+}
+
 bool
 attr_container_set_int64(attr_container_t **p_attr_cont, const char *key,
                          int64_t value)
@@ -475,6 +508,14 @@ attr_container_set_int64(attr_container_t **p_attr_cont, const char *key,
                                    8);
 }
 
+bool
+attr_container_set_uint64(attr_container_t **p_attr_cont, const char *key,
+                          uint64_t value)
+{
+    return attr_container_set_attr(p_attr_cont, key, ATTR_TYPE_UINT64, &value,
+                                   8);
+}
+
 bool
 attr_container_set_byte(attr_container_t **p_attr_cont, const char *key,
                         int8_t value)
@@ -482,6 +523,21 @@ attr_container_set_byte(attr_container_t **p_attr_cont, const char *key,
     return attr_container_set_attr(p_attr_cont, key, ATTR_TYPE_BYTE, &value, 1);
 }
 
+bool
+attr_container_set_int8(attr_container_t **p_attr_cont, const char *key,
+                        int8_t value)
+{
+    return attr_container_set_attr(p_attr_cont, key, ATTR_TYPE_INT8, &value, 1);
+}
+
+bool
+attr_container_set_uint8(attr_container_t **p_attr_cont, const char *key,
+                         uint8_t value)
+{
+    return attr_container_set_attr(p_attr_cont, key, ATTR_TYPE_UINT8, &value,
+                                   1);
+}
+
 bool
 attr_container_set_uint16(attr_container_t **p_attr_cont, const char *key,
                           uint16_t value)
@@ -552,7 +608,7 @@ attr_container_get_attr(const attr_container_t *attr_cont, const char *key)
 
     if (!(attr_addr = attr_container_find_attr(attr_cont, key))) {
         attr_container_printf("Get attribute failed: lookup key failed.\r\n");
-        return false;
+        return NULL;
     }
 
     /* key len + key + '\0' */
@@ -566,14 +622,17 @@ attr_container_get_attr(const attr_container_t *attr_cont, const char *key)
         uint8_t type;                                                        \
         if (!addr)                                                           \
             return 0;                                                        \
-        val.j = 0;                                                           \
+        val.i64 = 0;                                                         \
         type = *(uint8_t *)addr++;                                           \
         switch (type) {                                                      \
-            case ATTR_TYPE_SHORT:                                            \
-            case ATTR_TYPE_INT:                                              \
+            case ATTR_TYPE_BYTE:  /* = ATTR_TYPE_INT8 */                     \
+            case ATTR_TYPE_SHORT: /* = ATTR_TYPE_INT16 */                    \
+            case ATTR_TYPE_INT:   /* = ATTR_TYPE_INT32 */                    \
             case ATTR_TYPE_INT64:                                            \
-            case ATTR_TYPE_BYTE:                                             \
+            case ATTR_TYPE_UINT8:                                            \
             case ATTR_TYPE_UINT16:                                           \
+            case ATTR_TYPE_UINT32:                                           \
+            case ATTR_TYPE_UINT64:                                           \
             case ATTR_TYPE_FLOAT:                                            \
             case ATTR_TYPE_DOUBLE:                                           \
             case ATTR_TYPE_BOOLEAN:                                          \
@@ -608,31 +667,67 @@ attr_container_get_attr(const attr_container_t *attr_cont, const char *key)
 short
 attr_container_get_as_short(const attr_container_t *attr_cont, const char *key)
 {
-    TEMPLATE_ATTR_BUF_TO_VALUE(attr_cont, key, s);
+    TEMPLATE_ATTR_BUF_TO_VALUE(attr_cont, key, i16);
+}
+
+int16_t
+attr_container_get_as_int16(const attr_container_t *attr_cont, const char *key)
+{
+    return (int16_t)attr_container_get_as_short(attr_cont, key);
 }
 
 int
 attr_container_get_as_int(const attr_container_t *attr_cont, const char *key)
 {
-    TEMPLATE_ATTR_BUF_TO_VALUE(attr_cont, key, i);
+    TEMPLATE_ATTR_BUF_TO_VALUE(attr_cont, key, i32);
+}
+
+int32_t
+attr_container_get_as_int32(const attr_container_t *attr_cont, const char *key)
+{
+    return (int32_t)attr_container_get_as_int(attr_cont, key);
+}
+
+uint32_t
+attr_container_get_as_uint32(const attr_container_t *attr_cont, const char *key)
+{
+    return (uint32_t)attr_container_get_as_int(attr_cont, key);
 }
 
 int64_t
 attr_container_get_as_int64(const attr_container_t *attr_cont, const char *key)
 {
-    TEMPLATE_ATTR_BUF_TO_VALUE(attr_cont, key, j);
+    TEMPLATE_ATTR_BUF_TO_VALUE(attr_cont, key, i64);
+}
+
+uint64_t
+attr_container_get_as_uint64(const attr_container_t *attr_cont, const char *key)
+{
+    return (uint64_t)attr_container_get_as_int64(attr_cont, key);
 }
 
 int8_t
 attr_container_get_as_byte(const attr_container_t *attr_cont, const char *key)
 {
-    TEMPLATE_ATTR_BUF_TO_VALUE(attr_cont, key, b);
+    TEMPLATE_ATTR_BUF_TO_VALUE(attr_cont, key, i8);
+}
+
+int8_t
+attr_container_get_as_int8(const attr_container_t *attr_cont, const char *key)
+{
+    return attr_container_get_as_byte(attr_cont, key);
+}
+
+uint8_t
+attr_container_get_as_uint8(const attr_container_t *attr_cont, const char *key)
+{
+    return (uint8_t)attr_container_get_as_byte(attr_cont, key);
 }
 
 uint16_t
 attr_container_get_as_uint16(const attr_container_t *attr_cont, const char *key)
 {
-    TEMPLATE_ATTR_BUF_TO_VALUE(attr_cont, key, s);
+    return (uint16_t)attr_container_get_as_short(attr_cont, key);
 }
 
 float
@@ -671,11 +766,14 @@ attr_container_get_as_bytearray(const attr_container_t *attr_cont,
 
     type = *(uint8_t *)addr++;
     switch (type) {
-        case ATTR_TYPE_SHORT:
-        case ATTR_TYPE_INT:
+        case ATTR_TYPE_BYTE:  /* = ATTR_TYPE_INT8 */
+        case ATTR_TYPE_SHORT: /* = ATTR_TYPE_INT16 */
+        case ATTR_TYPE_INT:   /* = ATTR_TYPE_INT32 */
         case ATTR_TYPE_INT64:
-        case ATTR_TYPE_BYTE:
+        case ATTR_TYPE_UINT8:
         case ATTR_TYPE_UINT16:
+        case ATTR_TYPE_UINT32:
+        case ATTR_TYPE_UINT64:
         case ATTR_TYPE_FLOAT:
         case ATTR_TYPE_DOUBLE:
         case ATTR_TYPE_BOOLEAN:
@@ -807,34 +905,52 @@ attr_container_dump(const attr_container_t *attr_cont)
         attr_container_printf("  key: %s", key);
 
         switch (type) {
-            case ATTR_TYPE_SHORT:
-                bh_memcpy_s(&value.s, sizeof(int16_t), p, sizeof(int16_t));
+            case ATTR_TYPE_BYTE: /* = ATTR_TYPE_INT8 */
+                bh_memcpy_s(&value.i8, 1, p, 1);
+                attr_container_printf(", type: byte, value: 0x%x\n",
+                                      value.i8 & 0xFF);
+                p++;
+                break;
+            case ATTR_TYPE_SHORT: /* = ATTR_TYPE_INT16 */
+                bh_memcpy_s(&value.i16, sizeof(int16_t), p, sizeof(int16_t));
                 attr_container_printf(", type: short, value: 0x%x\n",
-                                      value.s & 0xFFFF);
+                                      value.i16 & 0xFFFF);
                 p += 2;
                 break;
-            case ATTR_TYPE_INT:
-                bh_memcpy_s(&value.i, sizeof(int32_t), p, sizeof(int32_t));
-                attr_container_printf(", type: int, value: 0x%x\n", value.i);
+            case ATTR_TYPE_INT: /* = ATTR_TYPE_INT32 */
+                bh_memcpy_s(&value.i32, sizeof(int32_t), p, sizeof(int32_t));
+                attr_container_printf(", type: int, value: 0x%x\n", value.i32);
                 p += 4;
                 break;
             case ATTR_TYPE_INT64:
-                bh_memcpy_s(&value.j, sizeof(uint64_t), p, sizeof(uint64_t));
+                bh_memcpy_s(&value.i64, sizeof(int64_t), p, sizeof(int64_t));
                 attr_container_printf(", type: int64, value: 0x%llx\n",
-                                      (long long unsigned int)(value.j));
+                                      (long long unsigned int)(value.i64));
                 p += 8;
                 break;
-            case ATTR_TYPE_BYTE:
-                bh_memcpy_s(&value.b, 1, p, 1);
-                attr_container_printf(", type: byte, value: 0x%x\n",
-                                      value.b & 0xFF);
+            case ATTR_TYPE_UINT8:
+                bh_memcpy_s(&value.u8, 1, p, 1);
+                attr_container_printf(", type: uint8, value: 0x%x\n", value.u8);
                 p++;
                 break;
             case ATTR_TYPE_UINT16:
-                bh_memcpy_s(&value.c, sizeof(uint16_t), p, sizeof(uint16_t));
-                attr_container_printf(", type: uint16, value: 0x%x\n", value.c);
+                bh_memcpy_s(&value.u16, sizeof(uint16_t), p, sizeof(uint16_t));
+                attr_container_printf(", type: uint16, value: 0x%x\n",
+                                      value.u16);
                 p += 2;
                 break;
+            case ATTR_TYPE_UINT32:
+                bh_memcpy_s(&value.u32, sizeof(uint32_t), p, sizeof(uint32_t));
+                attr_container_printf(", type: uint32, value: 0x%x\n",
+                                      value.u32);
+                p += 4;
+                break;
+            case ATTR_TYPE_UINT64:
+                bh_memcpy_s(&value.u64, sizeof(uint64_t), p, sizeof(uint64_t));
+                attr_container_printf(", type: int64, value: 0x%llx\n",
+                                      (long long unsigned int)(value.u64));
+                p += 8;
+                break;
             case ATTR_TYPE_FLOAT:
                 bh_memcpy_s(&value.f, sizeof(float), p, sizeof(float));
                 attr_container_printf(", type: float, value: %f\n", value.f);

+ 176 - 4
core/app-framework/app-native-shared/bi-inc/attr_container.h

@@ -20,13 +20,27 @@ extern "C" {
 
 /* Attribute type */
 enum {
-    ATTR_TYPE_BEGIN = 1,
-    ATTR_TYPE_SHORT = ATTR_TYPE_BEGIN,
+    ATTR_TYPE_BEGIN = 0,
+    ATTR_TYPE_BYTE = ATTR_TYPE_BEGIN,
+    ATTR_TYPE_INT8 = ATTR_TYPE_BYTE,
+    ATTR_TYPE_SHORT,
+    ATTR_TYPE_INT16 = ATTR_TYPE_SHORT,
     ATTR_TYPE_INT,
+    ATTR_TYPE_INT32 = ATTR_TYPE_INT,
     ATTR_TYPE_INT64,
-    ATTR_TYPE_BYTE,
+    ATTR_TYPE_UINT8,
     ATTR_TYPE_UINT16,
-    ATTR_TYPE_FLOAT,
+    ATTR_TYPE_UINT32,
+    ATTR_TYPE_UINT64,
+    /**
+     * Why ATTR_TYPE_FLOAT = 10?
+     * We determine the number of bytes that should be copied through 1<<(type &
+     * 3). ATTR_TYPE_BYTE = 0, so the number of bytes is 1 << 0  = 1.
+     * ATTR_TYPE_UINT64 = 7, so the number of bytes is 1 << 3 = 8.
+     * Since the float type takes up 4 bytes, ATTR_TYPE_FLOAT should be 10.
+     * Calculation: (1 << (10&3)) = (1 << 2) = 4
+     */
+    ATTR_TYPE_FLOAT = 10,
     ATTR_TYPE_DOUBLE,
     ATTR_TYPE_BOOLEAN,
     ATTR_TYPE_STRING,
@@ -89,6 +103,20 @@ bool
 attr_container_set_short(attr_container_t **p_attr_cont, const char *key,
                          short value);
 
+/**
+ * Set int16 attribute in attribute container
+ *
+ * @param p_attr_cont pointer to attribute container to set attribute, and
+ * return the new attribute container if it is re-created
+ * @param key the attribute key
+ * @param value the attribute value
+ *
+ * @return true if success, false otherwise
+ */
+bool
+attr_container_set_int16(attr_container_t **p_attr_cont, const char *key,
+                         int16_t value);
+
 /**
  * Set int attribute in attribute container
  *
@@ -103,6 +131,34 @@ bool
 attr_container_set_int(attr_container_t **p_attr_cont, const char *key,
                        int value);
 
+/**
+ * Set int32 attribute in attribute container
+ *
+ * @param p_attr_cont pointer to attribute container to set attribute, and
+ * return the new attribute container if it is re-created
+ * @param key the attribute key
+ * @param value the attribute value
+ *
+ * @return true if success, false otherwise
+ */
+bool
+attr_container_set_int32(attr_container_t **p_attr_cont, const char *key,
+                         int32_t value);
+
+/**
+ * Set uint32 attribute in attribute container
+ *
+ * @param p_attr_cont pointer to attribute container to set attribute, and
+ * return the new attribute container if it is re-created
+ * @param key the attribute key
+ * @param value the attribute value
+ *
+ * @return true if success, false otherwise
+ */
+bool
+attr_container_set_uint32(attr_container_t **p_attr_cont, const char *key,
+                          uint32_t value);
+
 /**
  * Set int64 attribute in attribute container
  *
@@ -117,6 +173,20 @@ bool
 attr_container_set_int64(attr_container_t **p_attr_cont, const char *key,
                          int64_t value);
 
+/**
+ * Set uint64 attribute in attribute container
+ *
+ * @param p_attr_cont pointer to attribute container to set attribute, and
+ * return the new attribute container if it is re-created
+ * @param key the attribute key
+ * @param value the attribute value
+ *
+ * @return true if success, false otherwise
+ */
+bool
+attr_container_set_uint64(attr_container_t **p_attr_cont, const char *key,
+                          uint64_t value);
+
 /**
  * Set byte attribute in attribute container
  *
@@ -131,6 +201,34 @@ bool
 attr_container_set_byte(attr_container_t **p_attr_cont, const char *key,
                         int8_t value);
 
+/**
+ * Set int8 attribute in attribute container
+ *
+ * @param p_attr_cont pointer to attribute container to set attribute, and
+ * return the new attribute container if it is re-created
+ * @param key the attribute key
+ * @param value the attribute value
+ *
+ * @return true if success, false otherwise
+ */
+bool
+attr_container_set_int8(attr_container_t **p_attr_cont, const char *key,
+                        int8_t value);
+
+/**
+ * Set uint8 attribute in attribute container
+ *
+ * @param p_attr_cont pointer to attribute container to set attribute, and
+ * return the new attribute container if it is re-created
+ * @param key the attribute key
+ * @param value the attribute value
+ *
+ * @return true if success, false otherwise
+ */
+bool
+attr_container_set_uint8(attr_container_t **p_attr_cont, const char *key,
+                         uint8_t value);
+
 /**
  * Set uint16 attribute in attribute container
  *
@@ -259,6 +357,18 @@ attr_container_contain_key(const attr_container_t *attr_cont, const char *key);
 short
 attr_container_get_as_short(const attr_container_t *attr_cont, const char *key);
 
+/**
+ * Get attribute from attribute container and return it as int16 value,
+ * return 0 if attribute isn't found in message.
+ *
+ * @param attr_cont the attribute container
+ * @param key the attribute key
+ *
+ * @return the short value of the attribute, 0 if key isn't found
+ */
+int16_t
+attr_container_get_as_int16(const attr_container_t *attr_cont, const char *key);
+
 /**
  * Get attribute from attribute container and return it as int value,
  * return 0 if attribute isn't found in message.
@@ -271,6 +381,31 @@ attr_container_get_as_short(const attr_container_t *attr_cont, const char *key);
 int
 attr_container_get_as_int(const attr_container_t *attr_cont, const char *key);
 
+/**
+ * Get attribute from attribute container and return it as int32 value,
+ * return 0 if attribute isn't found in message.
+ *
+ * @param attr_cont the attribute container
+ * @param key the attribute key
+ *
+ * @return the int value of the attribute, 0 if key isn't found
+ */
+int32_t
+attr_container_get_as_int32(const attr_container_t *attr_cont, const char *key);
+
+/**
+ * Get attribute from attribute container and return it as uint32 value,
+ * return 0 if attribute isn't found in message.
+ *
+ * @param attr_cont the attribute container
+ * @param key the attribute key
+ *
+ * @return the unsigned int value of the attribute, 0 if key isn't found
+ */
+uint32_t
+attr_container_get_as_uint32(const attr_container_t *attr_cont,
+                             const char *key);
+
 /**
  * Get attribute from attribute container and return it as int64 value,
  * return 0 if attribute isn't found in attribute container.
@@ -283,6 +418,19 @@ attr_container_get_as_int(const attr_container_t *attr_cont, const char *key);
 int64_t
 attr_container_get_as_int64(const attr_container_t *attr_cont, const char *key);
 
+/**
+ * Get attribute from attribute container and return it as uint64 value,
+ * return 0 if attribute isn't found in attribute container.
+ *
+ * @param attr_cont the attribute container
+ * @param key the attribute key
+ *
+ * @return the unsigned long value of the attribute, 0 if key isn't found
+ */
+uint64_t
+attr_container_get_as_uint64(const attr_container_t *attr_cont,
+                             const char *key);
+
 /**
  * Get attribute from attribute container and return it as byte value,
  * return 0 if attribute isn't found in attribute container.
@@ -295,6 +443,30 @@ attr_container_get_as_int64(const attr_container_t *attr_cont, const char *key);
 int8_t
 attr_container_get_as_byte(const attr_container_t *attr_cont, const char *key);
 
+/**
+ * Get attribute from attribute container and return it as int8 value,
+ * return 0 if attribute isn't found in attribute container.
+ *
+ * @param attr_cont the attribute container
+ * @param key the attribute key
+ *
+ * @return the byte value of the attribute, 0 if key isn't found
+ */
+int8_t
+attr_container_get_as_int8(const attr_container_t *attr_cont, const char *key);
+
+/**
+ * Get attribute from attribute container and return it as uint8 value,
+ * return 0 if attribute isn't found in attribute container.
+ *
+ * @param attr_cont the attribute container
+ * @param key the attribute key
+ *
+ * @return the uint8 value of the attribute, 0 if key isn't found
+ */
+uint8_t
+attr_container_get_as_uint8(const attr_container_t *attr_cont, const char *key);
+
 /**
  * Get attribute from attribute container and return it as uint16 value,
  * return 0 if attribute isn't found in attribute container.

+ 8 - 0
core/app-mgr/app-manager/module_wasm_app.c

@@ -993,6 +993,14 @@ wasm_app_module_uninstall(request_t *msg)
 
     app_manager_printf("Uninstall WASM app successful!\n");
 
+#ifdef COLLECT_CODE_COVERAGE
+    /* Exit app manager so as to collect code coverage data */
+    if (!strcmp(m_name, "__exit_app_manager__")) {
+        app_manager_printf("Exit app manager\n");
+        bh_queue_exit_loop_run(get_app_manager_queue());
+    }
+#endif
+
 #if VALGRIND_CHECK != 0
     bh_queue_exit_loop_run(get_app_manager_queue());
 #endif

+ 11 - 0
core/config.h

@@ -161,6 +161,17 @@
 #define WASM_ENABLE_LIB_PTHREAD_SEMAPHORE 0
 #endif
 
+#ifndef WASM_ENABLE_LIB_WASI_THREADS
+#define WASM_ENABLE_LIB_WASI_THREADS 0
+#endif
+
+#ifndef WASM_ENABLE_HEAP_AUX_STACK_ALLOCATION
+#define WASM_ENABLE_HEAP_AUX_STACK_ALLOCATION WASM_ENABLE_LIB_WASI_THREADS
+#elif WASM_ENABLE_HEAP_AUX_STACK_ALLOCATION == 0 \
+    && WASM_ENABLE_LIB_WASI_THREADS == 1
+#error "Heap aux stack allocation must be enabled for WASI threads"
+#endif
+
 #ifndef WASM_ENABLE_BASE_LIB
 #define WASM_ENABLE_BASE_LIB 0
 #endif

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

@@ -1226,7 +1226,10 @@ load_import_globals(const uint8 **p_buf, const uint8 *buf_end,
             }
             import_globals[i].global_data_linked =
                 tmp_global.global_data_linked;
+            import_globals[i].is_linked = true;
         }
+#else
+        import_globals[i].is_linked = false;
 #endif
 
         import_globals[i].size = wasm_value_type_size(import_globals[i].type);

+ 181 - 93
core/iwasm/aot/aot_runtime.c

@@ -30,6 +30,8 @@ bh_static_assert(offsetof(WASMExecEnv, aux_stack_boundary)
 bh_static_assert(offsetof(WASMExecEnv, aux_stack_bottom)
                  == 7 * sizeof(uintptr_t));
 bh_static_assert(offsetof(WASMExecEnv, native_symbol) == 8 * sizeof(uintptr_t));
+bh_static_assert(offsetof(WASMExecEnv, native_stack_top_min)
+                 == 9 * sizeof(uintptr_t));
 
 bh_static_assert(offsetof(AOTModuleInstance, memories) == 1 * sizeof(uint64));
 bh_static_assert(offsetof(AOTModuleInstance, func_ptrs) == 5 * sizeof(uint64));
@@ -899,82 +901,168 @@ create_exports(AOTModuleInstance *module_inst, AOTModule *module,
     return create_export_funcs(module_inst, module, error_buf, error_buf_size);
 }
 
-static bool
-clear_wasi_proc_exit_exception(AOTModuleInstance *module_inst)
-{
-#if WASM_ENABLE_LIBC_WASI != 0
-    const char *exception = aot_get_exception(module_inst);
-    if (exception && !strcmp(exception, "Exception: wasi proc exit")) {
-        /* The "wasi proc exit" exception is thrown by native lib to
-           let wasm app exit, which is a normal behavior, we clear
-           the exception here. */
-        aot_set_exception(module_inst, NULL);
-        return true;
-    }
-    return false;
-#else
-    return false;
-#endif
-}
-
-static bool
-execute_post_inst_function(AOTModuleInstance *module_inst)
+static AOTFunctionInstance *
+lookup_post_instantiate_func(AOTModuleInstance *module_inst,
+                             const char *func_name)
 {
-    AOTFunctionInstance *post_inst_func =
-        aot_lookup_function(module_inst, "__post_instantiate", "()");
+    AOTFunctionInstance *func;
+    AOTFuncType *func_type;
 
-    if (!post_inst_func)
+    if (!(func = aot_lookup_function(module_inst, func_name, NULL)))
         /* Not found */
-        return true;
+        return NULL;
+
+    func_type = func->u.func.func_type;
+    if (!(func_type->param_count == 0 && func_type->result_count == 0))
+        /* Not a valid function type, ignore it */
+        return NULL;
 
-    return aot_create_exec_env_and_call_function(module_inst, post_inst_func, 0,
-                                                 NULL);
+    return func;
 }
 
 static bool
-execute_start_function(AOTModuleInstance *module_inst)
+execute_post_instantiate_functions(AOTModuleInstance *module_inst,
+                                   bool is_sub_inst)
 {
     AOTModule *module = (AOTModule *)module_inst->module;
-    WASMExecEnv *exec_env;
-    typedef void (*F)(WASMExecEnv *);
-    union {
-        F f;
-        void *v;
-    } u;
-
-    if (!module->start_function)
+    AOTFunctionInstance *initialize_func = NULL;
+    AOTFunctionInstance *post_inst_func = NULL;
+    AOTFunctionInstance *call_ctors_func = NULL;
+#ifdef OS_ENABLE_HW_BOUND_CHECK
+    WASMModuleInstanceCommon *module_inst_main = NULL;
+    WASMExecEnv *exec_env_tls = NULL;
+#endif
+    WASMExecEnv *exec_env = NULL;
+    bool ret = false;
+
+#if WASM_ENABLE_LIBC_WASI != 0
+    /*
+     * WASI reactor instances may assume that _initialize will be called by
+     * the environment at most once, and that none of their other exports
+     * are accessed before that call.
+     */
+    if (!is_sub_inst && module->import_wasi_api) {
+        initialize_func =
+            lookup_post_instantiate_func(module_inst, "_initialize");
+    }
+#endif
+
+    /* Execute possible "__post_instantiate" function if wasm app is
+       compiled by emsdk's early version */
+    if (!is_sub_inst) {
+        post_inst_func =
+            lookup_post_instantiate_func(module_inst, "__post_instantiate");
+    }
+
+#if WASM_ENABLE_BULK_MEMORY != 0
+    /* Only execute the memory init function for main instance since
+       the data segments will be dropped once initialized */
+    if (!is_sub_inst
+#if WASM_ENABLE_LIBC_WASI != 0
+        && !module->import_wasi_api
+#endif
+    ) {
+        call_ctors_func =
+            lookup_post_instantiate_func(module_inst, "__wasm_call_ctors");
+    }
+#endif
+
+    if (!module->start_function && !initialize_func && !post_inst_func
+        && !call_ctors_func) {
+        /* No post instantiation functions to call */
         return true;
+    }
 
-    if (!(exec_env =
-              wasm_exec_env_create((WASMModuleInstanceCommon *)module_inst,
-                                   module_inst->default_wasm_stack_size))) {
+#ifdef OS_ENABLE_HW_BOUND_CHECK
+    if (is_sub_inst) {
+        exec_env = exec_env_tls = wasm_runtime_get_exec_env_tls();
+        if (exec_env_tls) {
+            /* Temporarily replace exec_env_tls's module inst to current
+               module inst to avoid checking failure when calling the
+               wasm functions, and ensure that the exec_env's module inst
+               is the correct one. */
+            module_inst_main = exec_env_tls->module_inst;
+            exec_env_tls->module_inst = (WASMModuleInstanceCommon *)module_inst;
+        }
+    }
+#endif
+    if (!exec_env
+        && !(exec_env =
+                 wasm_exec_env_create((WASMModuleInstanceCommon *)module_inst,
+                                      module_inst->default_wasm_stack_size))) {
         aot_set_exception(module_inst, "allocate memory failed");
         return false;
     }
 
-    u.v = module->start_function;
-    u.f(exec_env);
+    /* Execute start function for both main insance and sub instance */
+    if (module->start_function) {
+        AOTFunctionInstance start_func = { 0 };
+        uint32 func_type_idx;
+
+        start_func.func_name = "";
+        start_func.func_index = module->start_func_index;
+        start_func.is_import_func = false;
+        func_type_idx = module->func_type_indexes[module->start_func_index
+                                                  - module->import_func_count];
+        start_func.u.func.func_type = module->func_types[func_type_idx];
+        start_func.u.func.func_ptr = module->start_function;
+        if (!aot_call_function(exec_env, &start_func, 0, NULL)) {
+            goto fail;
+        }
+    }
+
+    if (initialize_func
+        && !aot_call_function(exec_env, initialize_func, 0, NULL)) {
+        goto fail;
+    }
 
+    if (post_inst_func
+        && !aot_call_function(exec_env, post_inst_func, 0, NULL)) {
+        goto fail;
+    }
+
+    if (call_ctors_func
+        && !aot_call_function(exec_env, call_ctors_func, 0, NULL)) {
+        goto fail;
+    }
+
+    ret = true;
+
+fail:
+#ifdef OS_ENABLE_HW_BOUND_CHECK
+    if (is_sub_inst && exec_env_tls) {
+        bh_assert(exec_env == exec_env_tls);
+        /* Restore the exec_env_tls's module inst */
+        exec_env_tls->module_inst = module_inst_main;
+    }
+    else
+        wasm_exec_env_destroy(exec_env);
+#else
     wasm_exec_env_destroy(exec_env);
-    (void)clear_wasi_proc_exit_exception(module_inst);
-    return !aot_get_exception(module_inst);
+#endif
+
+    return ret;
 }
 
-#if WASM_ENABLE_BULK_MEMORY != 0
 static bool
-execute_memory_init_function(AOTModuleInstance *module_inst)
+check_linked_symbol(AOTModule *module, char *error_buf, uint32 error_buf_size)
 {
-    AOTFunctionInstance *memory_init_func =
-        aot_lookup_function(module_inst, "__wasm_call_ctors", "()");
+    uint32 i;
 
-    if (!memory_init_func)
-        /* Not found */
-        return true;
+    /* init_func_ptrs() will go through import functions */
+
+    for (i = 0; i < module->import_global_count; i++) {
+        AOTImportGlobal *global = module->import_globals + i;
+        if (!global->is_linked) {
+            set_error_buf_v(error_buf, error_buf_size,
+                            "failed to link import global (%s, %s)",
+                            global->module_name, global->global_name);
+            return false;
+        }
+    }
 
-    return aot_create_exec_env_and_call_function(module_inst, memory_init_func,
-                                                 0, NULL);
+    return true;
 }
-#endif
 
 AOTModuleInstance *
 aot_instantiate(AOTModule *module, bool is_sub_inst, uint32 stack_size,
@@ -1059,6 +1147,9 @@ aot_instantiate(AOTModule *module, bool is_sub_inst, uint32 stack_size,
     if (!init_func_type_indexes(module_inst, module, error_buf, error_buf_size))
         goto fail;
 
+    if (!check_linked_symbol(module, error_buf, error_buf_size))
+        goto fail;
+
     if (!create_exports(module_inst, module, error_buf, error_buf_size))
         goto fail;
 
@@ -1079,6 +1170,17 @@ aot_instantiate(AOTModule *module, bool is_sub_inst, uint32 stack_size,
     }
 #endif
 
+#if WASM_ENABLE_WASI_NN != 0
+    if (!is_sub_inst) {
+        if (!(((AOTModuleInstanceExtra *)module_inst->e)->wasi_nn_ctx =
+                  wasi_nn_initialize())) {
+            set_error_buf(error_buf, error_buf_size,
+                          "wasi nn initialization failed");
+            goto fail;
+        }
+    }
+#endif
+
     /* Initialize the thread related data */
     if (stack_size == 0)
         stack_size = DEFAULT_WASM_STACK_SIZE;
@@ -1104,32 +1206,11 @@ aot_instantiate(AOTModule *module, bool is_sub_inst, uint32 stack_size,
     }
 #endif
 
-    /* Execute __post_instantiate function and start function*/
-    if (!execute_post_inst_function(module_inst)
-        || !execute_start_function(module_inst)) {
+    if (!execute_post_instantiate_functions(module_inst, is_sub_inst)) {
         set_error_buf(error_buf, error_buf_size, module_inst->cur_exception);
         goto fail;
     }
 
-#if WASM_ENABLE_BULK_MEMORY != 0
-#if WASM_ENABLE_LIBC_WASI != 0
-    if (!module->import_wasi_api) {
-#endif
-        /* Only execute the memory init function for main instance because
-            the data segments will be dropped once initialized.
-        */
-        if (!is_sub_inst) {
-            if (!execute_memory_init_function(module_inst)) {
-                set_error_buf(error_buf, error_buf_size,
-                              module_inst->cur_exception);
-                goto fail;
-            }
-        }
-#if WASM_ENABLE_LIBC_WASI != 0
-    }
-#endif
-#endif
-
 #if WASM_ENABLE_MEMORY_TRACING != 0
     wasm_runtime_dump_module_inst_mem_consumption(
         (WASMModuleInstanceCommon *)module_inst);
@@ -1145,6 +1226,15 @@ fail:
 void
 aot_deinstantiate(AOTModuleInstance *module_inst, bool is_sub_inst)
 {
+    if (module_inst->exec_env_singleton) {
+        /* wasm_exec_env_destroy will call
+           wasm_cluster_wait_for_all_except_self to wait for other
+           threads, so as to destroy their exec_envs and module
+           instances first, and avoid accessing the shared resources
+           of current module instance after it is deinstantiated. */
+        wasm_exec_env_destroy((WASMExecEnv *)module_inst->exec_env_singleton);
+    }
+
 #if WASM_ENABLE_LIBC_WASI != 0
     /* Destroy wasi resource before freeing app heap, since some fields of
        wasi contex are allocated from app heap, and if app heap is freed,
@@ -1183,13 +1273,19 @@ aot_deinstantiate(AOTModuleInstance *module_inst, bool is_sub_inst)
     if (module_inst->func_type_indexes)
         wasm_runtime_free(module_inst->func_type_indexes);
 
-    if (module_inst->exec_env_singleton)
-        wasm_exec_env_destroy((WASMExecEnv *)module_inst->exec_env_singleton);
-
     if (((AOTModuleInstanceExtra *)module_inst->e)->c_api_func_imports)
         wasm_runtime_free(
             ((AOTModuleInstanceExtra *)module_inst->e)->c_api_func_imports);
 
+#if WASM_ENABLE_WASI_NN != 0
+    if (!is_sub_inst) {
+        WASINNContext *wasi_nn_ctx =
+            ((AOTModuleInstanceExtra *)module_inst->e)->wasi_nn_ctx;
+        if (wasi_nn_ctx)
+            wasi_nn_destroy(wasi_nn_ctx);
+    }
+#endif
+
     wasm_runtime_free(module_inst);
 }
 
@@ -1233,6 +1329,7 @@ invoke_native_with_hw_bound_check(WASMExecEnv *exec_env, void *func_ptr,
     /* Check native stack overflow firstly to ensure we have enough
        native stack to run the following codes before actually calling
        the aot function in invokeNative function. */
+    RECORD_STACK_USAGE(exec_env, (uint8 *)&module_inst);
     if ((uint8 *)&module_inst < exec_env->native_stack_boundary
                                     + page_size * (guard_page_count + 1)) {
         aot_set_exception_with_id(module_inst, EXCE_NATIVE_STACK_OVERFLOW);
@@ -1384,13 +1481,6 @@ aot_call_function(WASMExecEnv *exec_env, AOTFunctionInstance *function,
         ret = invoke_native_internal(exec_env, function->u.func.func_ptr,
                                      func_type, NULL, NULL, argv1, argc, argv);
 
-        if (!ret || aot_get_exception(module_inst)) {
-            if (clear_wasi_proc_exit_exception(module_inst))
-                ret = true;
-            else
-                ret = false;
-        }
-
 #if WASM_ENABLE_DUMP_CALL_STACK != 0
         if (!ret) {
             if (aot_create_call_stack(exec_env)) {
@@ -1450,9 +1540,6 @@ aot_call_function(WASMExecEnv *exec_env, AOTFunctionInstance *function,
         ret = invoke_native_internal(exec_env, function->u.func.func_ptr,
                                      func_type, NULL, NULL, argv, argc, argv);
 
-        if (clear_wasi_proc_exit_exception(module_inst))
-            ret = true;
-
 #if WASM_ENABLE_DUMP_CALL_STACK != 0
         if (aot_get_exception(module_inst)) {
             if (aot_create_call_stack(exec_env)) {
@@ -1493,7 +1580,7 @@ aot_create_exec_env_and_call_function(AOTModuleInstance *module_inst,
         }
     }
 
-    ret = aot_call_function(exec_env, func, argc, argv);
+    ret = wasm_runtime_call_wasm(exec_env, func, argc, argv);
 
     /* don't destroy the exec_env if it isn't created in this function */
     if (!existing_exec_env)
@@ -1764,7 +1851,9 @@ aot_invoke_native(WASMExecEnv *exec_env, uint32 func_idx, uint32 argc,
     AOTModuleInstanceExtra *module_inst_extra =
         (AOTModuleInstanceExtra *)module_inst->e;
     CApiFuncImport *c_api_func_import =
-        module_inst_extra->c_api_func_imports + func_idx;
+        module_inst_extra->c_api_func_imports
+            ? module_inst_extra->c_api_func_imports + func_idx
+            : NULL;
     uint32 *func_type_indexes = module_inst->func_type_indexes;
     uint32 func_type_idx = func_type_indexes[func_idx];
     AOTFuncType *func_type = aot_module->func_types[func_type_idx];
@@ -1780,7 +1869,8 @@ aot_invoke_native(WASMExecEnv *exec_env, uint32 func_idx, uint32 argc,
 
     import_func = aot_module->import_funcs + func_idx;
     if (import_func->call_conv_wasm_c_api)
-        func_ptr = c_api_func_import->func_ptr_linked;
+        func_ptr =
+            c_api_func_import ? c_api_func_import->func_ptr_linked : NULL;
 
     if (!func_ptr) {
         snprintf(buf, sizeof(buf),
@@ -1839,6 +1929,7 @@ aot_call_indirect(WASMExecEnv *exec_env, uint32 tbl_idx, uint32 table_elem_idx,
        exec_env->native_stack_boundary must have been set, we don't set
        it again */
 
+    RECORD_STACK_USAGE(exec_env, (uint8 *)&module_inst);
     if ((uint8 *)&module_inst < exec_env->native_stack_boundary) {
         aot_set_exception_with_id(module_inst, EXCE_NATIVE_STACK_OVERFLOW);
         goto fail;
@@ -1980,9 +2071,6 @@ aot_call_indirect(WASMExecEnv *exec_env, uint32 tbl_idx, uint32 table_elem_idx,
     }
 
 fail:
-    if (clear_wasi_proc_exit_exception(module_inst))
-        return true;
-
 #ifdef OS_ENABLE_HW_BOUND_CHECK
     wasm_runtime_access_exce_check_guard_page();
 #endif

+ 7 - 0
core/iwasm/aot/aot_runtime.h

@@ -11,6 +11,10 @@
 #include "../interpreter/wasm_runtime.h"
 #include "../compilation/aot.h"
 
+#if WASM_ENABLE_WASI_NN != 0
+#include "../libraries/wasi-nn/src/wasi_nn_private.h"
+#endif
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -75,6 +79,9 @@ typedef struct AOTFunctionInstance {
 
 typedef struct AOTModuleInstanceExtra {
     CApiFuncImport *c_api_func_imports;
+#if WASM_ENABLE_WASI_NN != 0
+    WASINNContext *wasi_nn_ctx;
+#endif
 } AOTModuleInstanceExtra;
 
 #if defined(OS_ENABLE_HW_BOUND_CHECK) && defined(BH_PLATFORM_WINDOWS)

+ 6 - 1
core/iwasm/common/arch/invokeNative_ia32.s

@@ -16,9 +16,14 @@ _invokeNative:
     push    %ebp
     movl    %esp, %ebp
     movl    16(%ebp), %ecx          /* ecx = argc */
-    movl    12(%ebp), %edx          /* edx = argv */
+    leal    2(%ecx), %edx           /* edx = ecx + 2 (count return address and saved ebp) */
+    andl    $3, %edx                /* edx = edx % 4 */
+    jz   stack_aligned              /* if edx == 0, stack is already 16 bytes aligned */
+    leal    -16(%esp, %edx, 4), %esp /* esp = esp - 16 + edx * 4 */
+stack_aligned:
     test    %ecx, %ecx
     jz      skip_push_args          /* if ecx == 0, skip pushing arguments */
+    movl    12(%ebp), %edx          /* edx = argv */
     leal    -4(%edx,%ecx,4), %edx   /* edx = edx + ecx * 4 - 4 */
     subl    %esp, %edx              /* edx = edx - esp */
 1:

+ 2 - 22
core/iwasm/common/wasm_application.c

@@ -203,22 +203,12 @@ wasm_application_execute_main(WASMModuleInstanceCommon *module_inst, int32 argc,
                               char *argv[])
 {
     bool ret;
-#if WASM_ENABLE_THREAD_MGR != 0
-    WASMCluster *cluster;
-#endif
-#if WASM_ENABLE_THREAD_MGR != 0 || WASM_ENABLE_MEMORY_PROFILING != 0
+#if WASM_ENABLE_MEMORY_PROFILING != 0
     WASMExecEnv *exec_env;
 #endif
 
     ret = execute_main(module_inst, argc, argv);
 
-#if WASM_ENABLE_THREAD_MGR != 0
-    exec_env = wasm_runtime_get_exec_env_singleton(module_inst);
-    if (exec_env && (cluster = wasm_exec_env_get_cluster(exec_env))) {
-        wasm_cluster_wait_for_all_except_self(cluster, exec_env);
-    }
-#endif
-
 #if WASM_ENABLE_MEMORY_PROFILING != 0
     exec_env = wasm_runtime_get_exec_env_singleton(module_inst);
     if (exec_env) {
@@ -622,22 +612,12 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst,
                               const char *name, int32 argc, char *argv[])
 {
     bool ret;
-#if WASM_ENABLE_THREAD_MGR != 0
-    WASMCluster *cluster;
-#endif
-#if WASM_ENABLE_THREAD_MGR != 0 || WASM_ENABLE_MEMORY_PROFILING != 0
+#if WASM_ENABLE_MEMORY_PROFILING != 0
     WASMExecEnv *exec_env;
 #endif
 
     ret = execute_func(module_inst, name, argc, argv);
 
-#if WASM_ENABLE_THREAD_MGR != 0
-    exec_env = wasm_runtime_get_exec_env_singleton(module_inst);
-    if (exec_env && (cluster = wasm_exec_env_get_cluster(exec_env))) {
-        wasm_cluster_wait_for_all_except_self(cluster, exec_env);
-    }
-#endif
-
 #if WASM_ENABLE_MEMORY_PROFILING != 0
     exec_env = wasm_runtime_get_exec_env_singleton(module_inst);
     if (exec_env) {

+ 219 - 208
core/iwasm/common/wasm_c_api.c

@@ -276,7 +276,7 @@ WASM_DEFINE_VEC_OWN(store, wasm_store_delete)
 WASM_DEFINE_VEC_OWN(valtype, wasm_valtype_delete)
 
 #ifndef NDEBUG
-#if WAMR_BUILD_MEMORY_PROFILING != 0
+#if WASM_ENABLE_MEMORY_PROFILING != 0
 #define WASM_C_DUMP_PROC_MEM() LOG_PROC_MEM()
 #else
 #define WASM_C_DUMP_PROC_MEM() (void)0
@@ -398,7 +398,7 @@ wasm_engine_new_internal(mem_alloc_type_t type, const MemAllocOption *opts)
 }
 
 /* global engine instance */
-static wasm_engine_t *singleton_engine = NULL;
+static wasm_engine_t *singleton_engine;
 #ifdef os_thread_local_attribute
 /* categorize wasm_store_t as threads*/
 static os_thread_local_attribute unsigned thread_local_stores_num = 0;
@@ -1458,6 +1458,30 @@ wasm_importtype_type(const wasm_importtype_t *import_type)
     return import_type->extern_type;
 }
 
+bool
+wasm_importtype_is_linked(const wasm_importtype_t *import_type)
+{
+    if (!import_type)
+        return false;
+
+    const wasm_name_t *module_name = wasm_importtype_module(import_type);
+    const wasm_name_t *field_name = wasm_importtype_name(import_type);
+
+    switch (wasm_externtype_kind(wasm_importtype_type(import_type))) {
+        case WASM_EXTERN_FUNC:
+            return wasm_runtime_is_import_func_linked(module_name->data,
+                                                      field_name->data);
+        case WASM_EXTERN_GLOBAL:
+            return wasm_runtime_is_import_global_linked(module_name->data,
+                                                        field_name->data);
+        case WASM_EXTERN_MEMORY:
+        case WASM_EXTERN_TABLE:
+        default:
+            break;
+    }
+    return false;
+}
+
 own wasm_exporttype_t *
 wasm_exporttype_new(own wasm_byte_vec_t *name,
                     own wasm_externtype_t *extern_type)
@@ -1633,8 +1657,6 @@ wasm_val_to_rt_val(WASMModuleInstanceCommon *inst_comm_rt, uint8 val_type_rt,
             ret =
                 wasm_externref_obj2ref(inst_comm_rt, v->of.ref, (uint32 *)data);
             break;
-#else
-            (void)inst_comm_rt;
 #endif
         default:
             LOG_WARNING("unexpected value type %d", val_type_rt);
@@ -1642,6 +1664,7 @@ wasm_val_to_rt_val(WASMModuleInstanceCommon *inst_comm_rt, uint8 val_type_rt,
             break;
     }
 
+    (void)inst_comm_rt;
     return ret;
 }
 
@@ -2537,12 +2560,12 @@ wasm_module_imports(const wasm_module_t *module, own wasm_importtype_vec_t *out)
 
         bh_assert(extern_type);
 
-        wasm_name_new_from_string(&module_name, module_name_rt);
+        wasm_name_new_from_string_nt(&module_name, module_name_rt);
         if (strlen(module_name_rt) && !module_name.data) {
             goto failed;
         }
 
-        wasm_name_new_from_string(&name, field_name_rt);
+        wasm_name_new_from_string_nt(&name, field_name_rt);
         if (strlen(field_name_rt) && !name.data) {
             goto failed;
         }
@@ -2622,7 +2645,7 @@ wasm_module_exports(const wasm_module_t *module, wasm_exporttype_vec_t *out)
         }
 
         /* byte* -> wasm_byte_vec_t */
-        wasm_name_new_from_string(&name, export->name);
+        wasm_name_new_from_string_nt(&name, export->name);
         if (strlen(export->name) && !name.data) {
             goto failed;
         }
@@ -3008,6 +3031,20 @@ failed:
     return NULL;
 }
 
+static wasm_func_t *
+wasm_func_new_empty(wasm_store_t *store)
+{
+    wasm_func_t *func = NULL;
+
+    if (!(func = malloc_internal(sizeof(wasm_func_t))))
+        goto failed;
+
+    func->store = store;
+    func->kind = WASM_EXTERN_FUNC;
+
+    RETURN_OBJ(func, wasm_func_delete)
+}
+
 void
 wasm_func_delete(wasm_func_t *func)
 {
@@ -3211,7 +3248,8 @@ wasm_func_call(const wasm_func_t *func, const wasm_val_vec_t *params,
         wasm_name_t message = { 0 };
         wasm_trap_t *trap;
 
-        wasm_name_new_from_string(&message, "failed to call unlinked function");
+        wasm_name_new_from_string_nt(&message,
+                                     "failed to call unlinked function");
         trap = wasm_trap_new(func->store, &message);
         wasm_byte_vec_delete(&message);
 
@@ -3371,6 +3409,25 @@ failed:
     return NULL;
 }
 
+static wasm_global_t *
+wasm_global_new_empty(wasm_store_t *store)
+{
+    wasm_global_t *global = NULL;
+
+    global = malloc_internal(sizeof(wasm_global_t));
+    if (!global)
+        goto failed;
+
+    global->store = store;
+    global->kind = WASM_EXTERN_GLOBAL;
+
+    return global;
+failed:
+    LOG_DEBUG("%s failed", __FUNCTION__);
+    wasm_global_delete(global);
+    return NULL;
+}
+
 /* almost same with wasm_global_new */
 wasm_global_t *
 wasm_global_copy(const wasm_global_t *src)
@@ -4205,7 +4262,8 @@ wasm_memory_data_size(const wasm_memory_t *memory)
             (WASMModuleInstance *)module_inst_comm;
         WASMMemoryInstance *memory_inst =
             module_inst->memories[memory->memory_idx_rt];
-        return memory_inst->cur_page_count * memory_inst->num_bytes_per_page;
+        return (size_t)memory_inst->cur_page_count
+               * memory_inst->num_bytes_per_page;
     }
 #endif
 
@@ -4215,7 +4273,8 @@ wasm_memory_data_size(const wasm_memory_t *memory)
         AOTMemoryInstance *memory_inst =
             ((AOTMemoryInstance **)
                  module_inst->memories)[memory->memory_idx_rt];
-        return memory_inst->cur_page_count * memory_inst->num_bytes_per_page;
+        return (size_t)memory_inst->cur_page_count
+               * memory_inst->num_bytes_per_page;
     }
 #endif
 
@@ -4286,6 +4345,11 @@ interp_link_func(const wasm_instance_t *inst, const WASMModule *module_interp,
 
     imported_func_interp = module_interp->import_functions + func_idx_rt;
     bh_assert(imported_func_interp);
+    bh_assert(imported_func_interp->kind == IMPORT_KIND_FUNC);
+
+    /* it is a placeholder and let's skip it*/
+    if (!import->type)
+        return true;
 
     /* type comparison */
     if (!wasm_functype_same_internal(
@@ -4300,6 +4364,8 @@ interp_link_func(const wasm_instance_t *inst, const WASMModule *module_interp,
         imported_func_interp->u.function.func_ptr_linked = import->u.cb_env.cb;
     else
         imported_func_interp->u.function.func_ptr_linked = import->u.cb;
+    bh_assert(imported_func_interp->u.function.func_ptr_linked);
+
     import->func_idx_rt = func_idx_rt;
 
     (void)inst;
@@ -4318,12 +4384,19 @@ interp_link_global(const WASMModule *module_interp, uint16 global_idx_rt,
 
     imported_global_interp = module_interp->import_globals + global_idx_rt;
     bh_assert(imported_global_interp);
+    bh_assert(imported_global_interp->kind == IMPORT_KIND_GLOBAL);
+
+    /* it is a placeholder and let's skip it*/
+    if (!import->type)
+        return true;
 
+    /* type comparison */
     if (!cmp_val_kind_with_val_type(wasm_valtype_kind(import->type->val_type),
                                     imported_global_interp->u.global.type))
         return false;
 
     /* set init value */
+    bh_assert(import->init);
     switch (wasm_valtype_kind(import->type->val_type)) {
         case WASM_I32:
             imported_global_interp->u.global.global_data_linked.i32 =
@@ -4350,58 +4423,6 @@ interp_link_global(const WASMModule *module_interp, uint16 global_idx_rt,
     return true;
 }
 
-static bool
-interp_link(const wasm_instance_t *inst, const WASMModule *module_interp,
-            wasm_extern_t *imports[])
-{
-    uint32 i = 0;
-    uint32 import_func_i = 0;
-    uint32 import_global_i = 0;
-
-    bh_assert(inst && module_interp && imports);
-
-    for (i = 0; i < module_interp->import_count; ++i) {
-        wasm_extern_t *import = imports[i];
-        WASMImport *import_rt = module_interp->imports + i;
-
-        switch (import_rt->kind) {
-            case IMPORT_KIND_FUNC:
-            {
-                if (!interp_link_func(inst, module_interp, import_func_i,
-                                      wasm_extern_as_func(import))) {
-                    LOG_WARNING("link #%d function failed", import_func_i);
-                    goto failed;
-                }
-                import_func_i++;
-                break;
-            }
-            case IMPORT_KIND_GLOBAL:
-            {
-                if (!interp_link_global(module_interp, import_global_i,
-                                        wasm_extern_as_global(import))) {
-                    LOG_WARNING("link #%d global failed", import_global_i);
-                    goto failed;
-                }
-                import_global_i++;
-                break;
-            }
-            case IMPORT_KIND_MEMORY:
-            case IMPORT_KIND_TABLE:
-            default:
-                ASSERT_NOT_IMPLEMENTED();
-                LOG_WARNING("%s meets unsupported kind: %d", __FUNCTION__,
-                            import_rt->kind);
-                goto failed;
-        }
-    }
-
-    return true;
-
-failed:
-    LOG_DEBUG("%s failed", __FUNCTION__);
-    return false;
-}
-
 static bool
 interp_process_export(wasm_store_t *store,
                       const WASMModuleInstance *inst_interp,
@@ -4501,6 +4522,10 @@ aot_link_func(const wasm_instance_t *inst, const AOTModule *module_aot,
     import_aot_func = module_aot->import_funcs + import_func_idx_rt;
     bh_assert(import_aot_func);
 
+    /* it is a placeholder and let's skip it*/
+    if (!import->type)
+        return true;
+
     /* type comparison */
     if (!wasm_functype_same_internal(import->type, import_aot_func->func_type))
         return false;
@@ -4513,6 +4538,8 @@ aot_link_func(const wasm_instance_t *inst, const AOTModule *module_aot,
         import_aot_func->func_ptr_linked = import->u.cb_env.cb;
     else
         import_aot_func->func_ptr_linked = import->u.cb;
+    bh_assert(import_aot_func->func_ptr_linked);
+
     import->func_idx_rt = import_func_idx_rt;
 
     return true;
@@ -4530,6 +4557,10 @@ aot_link_global(const AOTModule *module_aot, uint16 global_idx_rt,
     import_aot_global = module_aot->import_globals + global_idx_rt;
     bh_assert(import_aot_global);
 
+    /* it is a placeholder and let's skip it*/
+    if (!import->type)
+        return true;
+
     val_type = wasm_globaltype_content(import->type);
     bh_assert(val_type);
 
@@ -4537,6 +4568,7 @@ aot_link_global(const AOTModule *module_aot, uint16 global_idx_rt,
                                     import_aot_global->type))
         return false;
 
+    bh_assert(import->init);
     switch (wasm_valtype_kind(val_type)) {
         case WASM_I32:
             import_aot_global->global_data_linked.i32 = import->init->of.i32;
@@ -4555,63 +4587,8 @@ aot_link_global(const AOTModule *module_aot, uint16 global_idx_rt,
     }
 
     import->global_idx_rt = global_idx_rt;
+    import_aot_global->is_linked = true;
     return true;
-
-failed:
-    LOG_DEBUG("%s failed", __FUNCTION__);
-    return false;
-}
-
-static bool
-aot_link(const wasm_instance_t *inst, const AOTModule *module_aot,
-         wasm_extern_t *imports[])
-{
-    uint32 i = 0;
-    uint32 import_func_i = 0;
-    uint32 import_global_i = 0;
-    wasm_extern_t *import = NULL;
-    wasm_func_t *func = NULL;
-    wasm_global_t *global = NULL;
-
-    bh_assert(inst && module_aot && imports);
-
-    while (import_func_i < module_aot->import_func_count
-           || import_global_i < module_aot->import_global_count) {
-        import = imports[i++];
-
-        bh_assert(import);
-
-        switch (wasm_extern_kind(import)) {
-            case WASM_EXTERN_FUNC:
-                bh_assert(import_func_i < module_aot->import_func_count);
-                func = wasm_extern_as_func((wasm_extern_t *)import);
-                if (!aot_link_func(inst, module_aot, import_func_i, func)) {
-                    LOG_WARNING("link #%d function failed", import_func_i);
-                    goto failed;
-                }
-                import_func_i++;
-
-                break;
-            case WASM_EXTERN_GLOBAL:
-                bh_assert(import_global_i < module_aot->import_global_count);
-                global = wasm_extern_as_global((wasm_extern_t *)import);
-                if (!aot_link_global(module_aot, import_global_i, global)) {
-                    LOG_WARNING("link #%d global failed", import_global_i);
-                    goto failed;
-                }
-                import_global_i++;
-
-                break;
-            case WASM_EXTERN_MEMORY:
-            case WASM_EXTERN_TABLE:
-            default:
-                ASSERT_NOT_IMPLEMENTED();
-                goto failed;
-        }
-    }
-
-    return true;
-
 failed:
     LOG_DEBUG("%s failed", __FUNCTION__);
     return false;
@@ -4692,7 +4669,7 @@ aot_process_export(wasm_store_t *store, const AOTModuleInstance *inst_aot,
             goto failed;
         }
 
-        wasm_name_new_from_string(external->name, export->name);
+        wasm_name_new_from_string_nt(external->name, export->name);
         if (strlen(export->name) && !external->name->data) {
             goto failed;
         }
@@ -4710,65 +4687,103 @@ failed:
 }
 #endif /* WASM_ENABLE_AOT */
 
-wasm_instance_t *
-wasm_instance_new(wasm_store_t *store, const wasm_module_t *module,
-                  const wasm_extern_vec_t *imports, own wasm_trap_t **trap)
-{
-    return wasm_instance_new_with_args(store, module, imports, trap,
-                                       KILOBYTE(32), KILOBYTE(32));
-}
-
 static bool
-compare_imports(const wasm_module_t *module, const wasm_extern_vec_t *imports)
+do_link(const wasm_instance_t *inst, const wasm_module_t *module,
+        const wasm_extern_vec_t *imports)
 {
-    unsigned import_func_count = 0;
-    unsigned import_global_count = 0;
-    unsigned import_memory_count = 0;
-    unsigned import_table_count = 0;
-    unsigned i = 0;
+    uint32 i, import_func_i, import_global_i;
 
-    for (i = 0; imports && i < imports->num_elems; i++) {
+    bh_assert(inst && module);
+
+    /* we have run a module_type check before. */
+
+    for (i = 0, import_func_i = 0, import_global_i = 0; i < imports->num_elems;
+         i++) {
         wasm_extern_t *import = imports->data[i];
+
+        if (!import) {
+            LOG_ERROR("imports[%d] is NULL and it is fatal\n", i);
+            goto failed;
+        }
+
         switch (wasm_extern_kind(import)) {
             case WASM_EXTERN_FUNC:
-                import_func_count++;
+            {
+                bool ret = false;
+#if WASM_ENABLE_INTERP != 0
+                if ((*module)->module_type == Wasm_Module_Bytecode) {
+                    ret = interp_link_func(inst, MODULE_INTERP(module),
+                                           import_func_i,
+                                           wasm_extern_as_func(import));
+                }
+#endif
+#if WASM_ENABLE_AOT != 0
+                if ((*module)->module_type == Wasm_Module_AoT) {
+                    ret = aot_link_func(inst, MODULE_AOT(module), import_func_i,
+                                        wasm_extern_as_func(import));
+                }
+#endif
+                if (!ret) {
+                    LOG_WARNING("link function  #%d failed", import_func_i);
+                    goto failed;
+                }
+
+                import_func_i++;
                 break;
+            }
             case WASM_EXTERN_GLOBAL:
-                import_global_count++;
+            {
+                bool ret = false;
+#if WASM_ENABLE_INTERP != 0
+                if ((*module)->module_type == Wasm_Module_Bytecode) {
+                    ret = interp_link_global(MODULE_INTERP(module),
+                                             import_global_i,
+                                             wasm_extern_as_global(import));
+                }
+#endif
+#if WASM_ENABLE_AOT != 0
+                if ((*module)->module_type == Wasm_Module_AoT) {
+                    ret = aot_link_global(MODULE_AOT(module), import_global_i,
+                                          wasm_extern_as_global(import));
+                }
+#endif
+                if (!ret) {
+                    LOG_WARNING("link global #%d failed", import_global_i);
+                    goto failed;
+                }
+
+                import_global_i++;
                 break;
+            }
             case WASM_EXTERN_MEMORY:
-                import_memory_count++;
-                break;
             case WASM_EXTERN_TABLE:
-                import_table_count++;
+            {
+                LOG_WARNING("doesn't support import memories and tables for "
+                            "now, ignore them");
                 break;
+            }
             default:
+            {
                 UNREACHABLE();
-                return false;
+                break;
+            }
         }
     }
 
-#if WASM_ENABLE_INTERP != 0
-    if ((*module)->module_type == Wasm_Module_Bytecode)
-        return import_func_count == MODULE_INTERP(module)->import_function_count
-               && import_global_count
-                      == MODULE_INTERP(module)->import_global_count
-               && import_memory_count
-                      == MODULE_INTERP(module)->import_memory_count
-               && import_table_count
-                      == MODULE_INTERP(module)->import_table_count;
-#endif
-#if WASM_ENABLE_AOT != 0
-    if ((*module)->module_type == Wasm_Module_AoT)
-        return import_func_count == MODULE_AOT(module)->import_func_count
-               && import_global_count == MODULE_AOT(module)->import_global_count
-               && import_memory_count == MODULE_AOT(module)->import_memory_count
-               && import_table_count == MODULE_AOT(module)->import_table_count;
-#endif
-
+    return true;
+failed:
+    LOG_DEBUG("%s failed", __FUNCTION__);
     return false;
 }
 
+wasm_instance_t *
+wasm_instance_new(wasm_store_t *store, const wasm_module_t *module,
+                  const wasm_extern_vec_t *imports, own wasm_trap_t **trap)
+{
+    return wasm_instance_new_with_args(store, module, imports, trap,
+                                       KILOBYTE(32), KILOBYTE(32));
+}
+
 wasm_instance_t *
 wasm_instance_new_with_args(wasm_store_t *store, const wasm_module_t *module,
                             const wasm_extern_vec_t *imports,
@@ -4778,7 +4793,6 @@ wasm_instance_new_with_args(wasm_store_t *store, const wasm_module_t *module,
     char sub_error_buf[128] = { 0 };
     char error_buf[256] = { 0 };
     wasm_instance_t *instance = NULL;
-    WASMModuleInstance *inst_rt;
     CApiFuncImport *func_import = NULL, **p_func_imports = NULL;
     uint32 i = 0, import_func_count = 0;
     uint64 total_size;
@@ -4789,11 +4803,9 @@ wasm_instance_new_with_args(wasm_store_t *store, const wasm_module_t *module,
     if (!module)
         return NULL;
 
-    if (!compare_imports(module, imports)) {
-        snprintf(sub_error_buf, sizeof(sub_error_buf),
-                 "Failed to match imports");
-        goto failed;
-    }
+    /*
+     * will do the check at the end of wasm_runtime_instantiate
+     */
 
     WASM_C_DUMP_PROC_MEM();
 
@@ -4804,43 +4816,17 @@ wasm_instance_new_with_args(wasm_store_t *store, const wasm_module_t *module,
         goto failed;
     }
 
-    /* link module and imports */
-    if (imports && imports->num_elems) {
-        bool link = false;
-#if WASM_ENABLE_INTERP != 0
-        if ((*module)->module_type == Wasm_Module_Bytecode) {
-            if (!interp_link(instance, MODULE_INTERP(module),
-                             (wasm_extern_t **)imports->data)) {
-                snprintf(sub_error_buf, sizeof(sub_error_buf),
-                         "Failed to validate imports");
-                goto failed;
-            }
-            link = true;
-        }
-#endif
-
-#if WASM_ENABLE_AOT != 0
-        if ((*module)->module_type == Wasm_Module_AoT) {
-            if (!aot_link(instance, MODULE_AOT(module),
-                          (wasm_extern_t **)imports->data)) {
-                snprintf(sub_error_buf, sizeof(sub_error_buf),
-                         "Failed to validate imports");
-                goto failed;
-            }
-            link = true;
-        }
-#endif
-
-        /*
-         * a wrong combination of module filetype and compilation flags
-         * also leads to below branch
-         */
-        if (!link) {
+    /* executes the instantiate-time linking if provided */
+    if (imports) {
+        if (!do_link(instance, module, imports)) {
             snprintf(sub_error_buf, sizeof(sub_error_buf),
-                     "Failed to verify import count");
+                     "Failed to validate imports");
             goto failed;
         }
     }
+    /*
+     * will do the linking result check at the end of wasm_runtime_instantiate
+     */
 
     instance->inst_comm_rt = wasm_runtime_instantiate(
         *module, stack_size, heap_size, sub_error_buf, sizeof(sub_error_buf));
@@ -4855,18 +4841,22 @@ wasm_instance_new_with_args(wasm_store_t *store, const wasm_module_t *module,
     }
 
     /* create the c-api func import list */
-    inst_rt = (WASMModuleInstance *)instance->inst_comm_rt;
 #if WASM_ENABLE_INTERP != 0
     if (instance->inst_comm_rt->module_type == Wasm_Module_Bytecode) {
-        p_func_imports = &inst_rt->e->c_api_func_imports;
-        import_func_count = inst_rt->module->import_function_count;
+        WASMModuleInstanceExtra *e =
+            ((WASMModuleInstance *)instance->inst_comm_rt)->e;
+        p_func_imports = &(e->c_api_func_imports);
+        import_func_count = MODULE_INTERP(module)->import_function_count;
     }
 #endif
 #if WASM_ENABLE_AOT != 0
     if (instance->inst_comm_rt->module_type == Wasm_Module_AoT) {
-        p_func_imports =
-            &((AOTModuleInstanceExtra *)inst_rt->e)->c_api_func_imports;
-        import_func_count = ((AOTModule *)inst_rt->module)->import_func_count;
+        AOTModuleInstanceExtra *e =
+            (AOTModuleInstanceExtra *)((AOTModuleInstance *)
+                                           instance->inst_comm_rt)
+                ->e;
+        p_func_imports = &(e->c_api_func_imports);
+        import_func_count = MODULE_AOT(module)->import_func_count;
     }
 #endif
     bh_assert(p_func_imports);
@@ -4879,16 +4869,21 @@ wasm_instance_new_with_args(wasm_store_t *store, const wasm_module_t *module,
         goto failed;
     }
 
-    /* fill in c-api func import list */
+    /* fill in module_inst->e->c_api_func_imports */
     for (i = 0; imports && i < imports->num_elems; i++) {
-        wasm_func_t *func_host;
-        wasm_extern_t *in;
+        wasm_func_t *func_host = NULL;
+        wasm_extern_t *in = imports->data[i];
+        bh_assert(in);
 
-        in = imports->data[i];
         if (wasm_extern_kind(in) != WASM_EXTERN_FUNC)
             continue;
 
         func_host = wasm_extern_as_func(in);
+        /* it is a placeholder and let's skip it*/
+        if (!func_host->type) {
+            func_import++;
+            continue;
+        }
 
         func_import->with_env_arg = func_host->with_env;
         if (func_host->with_env) {
@@ -4899,6 +4894,7 @@ wasm_instance_new_with_args(wasm_store_t *store, const wasm_module_t *module,
             func_import->func_ptr_linked = func_host->u.cb;
             func_import->env_arg = NULL;
         }
+        bh_assert(func_import->func_ptr_linked);
 
         func_import++;
     }
@@ -4906,6 +4902,8 @@ wasm_instance_new_with_args(wasm_store_t *store, const wasm_module_t *module,
     /* fill with inst */
     for (i = 0; imports && imports->data && i < imports->num_elems; ++i) {
         wasm_extern_t *import = imports->data[i];
+        bh_assert(import);
+
         switch (import->kind) {
             case WASM_EXTERN_FUNC:
                 wasm_extern_as_func(import)->inst_comm_rt =
@@ -5001,7 +4999,7 @@ failed:
              sub_error_buf);
     if (trap != NULL) {
         wasm_message_t message = { 0 };
-        wasm_name_new_from_string(&message, error_buf);
+        wasm_name_new_from_string_nt(&message, error_buf);
         *trap = wasm_trap_new(store, &message);
         wasm_byte_vec_delete(&message);
     }
@@ -5201,3 +5199,16 @@ BASIC_FOUR_LIST(WASM_EXTERN_AS_OTHER_CONST)
 
 BASIC_FOUR_LIST(WASM_OTHER_AS_EXTERN_CONST)
 #undef WASM_OTHER_AS_EXTERN_CONST
+
+wasm_extern_t *
+wasm_extern_new_empty(wasm_store_t *store, wasm_externkind_t extern_kind)
+{
+    if (extern_kind == WASM_EXTERN_FUNC)
+        return wasm_func_as_extern(wasm_func_new_empty(store));
+
+    if (extern_kind == WASM_EXTERN_GLOBAL)
+        return wasm_global_as_extern(wasm_global_new_empty(store));
+
+    LOG_ERROR("Don't support linking table and memory for now");
+    return NULL;
+}

+ 13 - 2
core/iwasm/common/wasm_exec_env.c

@@ -172,15 +172,18 @@ void
 wasm_exec_env_destroy(WASMExecEnv *exec_env)
 {
 #if WASM_ENABLE_THREAD_MGR != 0
-    /* Terminate all sub-threads */
+    /* Wait for all sub-threads */
     WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env);
     if (cluster) {
-        wasm_cluster_terminate_all_except_self(cluster, exec_env);
+        wasm_cluster_wait_for_all_except_self(cluster, exec_env);
 #if WASM_ENABLE_DEBUG_INTERP != 0
         /* Must fire exit event after other threads exits, otherwise
            the stopped thread will be overrided by other threads */
         wasm_cluster_thread_exited(exec_env);
 #endif
+        /* We have waited for other threads, this is the only alive thread, so
+         * we don't acquire cluster->lock because the cluster will be destroyed
+         * inside this function */
         wasm_cluster_del_exec_env(cluster, exec_env);
     }
 #endif /* end of WASM_ENABLE_THREAD_MGR */
@@ -205,9 +208,17 @@ void
 wasm_exec_env_set_thread_info(WASMExecEnv *exec_env)
 {
     uint8 *stack_boundary = os_thread_get_stack_boundary();
+
+#if WASM_ENABLE_THREAD_MGR != 0
+    os_mutex_lock(&exec_env->wait_lock);
+#endif
     exec_env->handle = os_self_thread();
     exec_env->native_stack_boundary =
         stack_boundary ? stack_boundary + WASM_STACK_GUARD_SIZE : NULL;
+    exec_env->native_stack_top_min = (void *)UINTPTR_MAX;
+#if WASM_ENABLE_THREAD_MGR != 0
+    os_mutex_unlock(&exec_env->wait_lock);
+#endif
 }
 
 #if WASM_ENABLE_THREAD_MGR != 0

+ 24 - 0
core/iwasm/common/wasm_exec_env.h

@@ -84,6 +84,12 @@ typedef struct WASMExecEnv {
     void **native_symbol;
 #endif
 
+    /*
+     * The lowest stack pointer value observed.
+     * Assumption: native stack grows to the lower address.
+     */
+    uint8 *native_stack_top_min;
+
 #if WASM_ENABLE_FAST_JIT != 0
     /**
      * Cache for
@@ -165,6 +171,17 @@ typedef struct WASMExecEnv {
     } wasm_stack;
 } WASMExecEnv;
 
+#if WASM_ENABLE_MEMORY_PROFILING != 0
+#define RECORD_STACK_USAGE(e, p)               \
+    do {                                       \
+        if ((e)->native_stack_top_min > (p)) { \
+            (e)->native_stack_top_min = (p);   \
+        }                                      \
+    } while (0)
+#else
+#define RECORD_STACK_USAGE(e, p) (void)0
+#endif
+
 WASMExecEnv *
 wasm_exec_env_create_internal(struct WASMModuleInstanceCommon *module_inst,
                               uint32 stack_size);
@@ -179,6 +196,13 @@ wasm_exec_env_create(struct WASMModuleInstanceCommon *module_inst,
 void
 wasm_exec_env_destroy(WASMExecEnv *exec_env);
 
+static inline bool
+wasm_exec_env_is_aux_stack_managed_by_runtime(WASMExecEnv *exec_env)
+{
+    return exec_env->aux_stack_boundary.boundary != 0
+           || exec_env->aux_stack_bottom.bottom != 0;
+}
+
 /**
  * Allocate a WASM frame from the WASM stack.
  *

+ 62 - 2
core/iwasm/common/wasm_memory.c

@@ -8,6 +8,10 @@
 #include "bh_platform.h"
 #include "mem_alloc.h"
 
+#if WASM_ENABLE_SHARED_MEMORY != 0
+#include "../common/wasm_shared_memory.h"
+#endif
+
 typedef enum Memory_Mode {
     MEMORY_MODE_UNKNOWN = 0,
     MEMORY_MODE_POOL,
@@ -506,7 +510,7 @@ wasm_get_default_memory(WASMModuleInstance *module_inst)
 
 #ifndef OS_ENABLE_HW_BOUND_CHECK
 bool
-wasm_enlarge_memory(WASMModuleInstance *module, uint32 inc_page_count)
+wasm_enlarge_memory_internal(WASMModuleInstance *module, uint32 inc_page_count)
 {
     WASMMemoryInstance *memory = wasm_get_default_memory(module);
     uint8 *memory_data_old, *memory_data_new, *heap_data_old;
@@ -624,7 +628,7 @@ wasm_enlarge_memory(WASMModuleInstance *module, uint32 inc_page_count)
 }
 #else
 bool
-wasm_enlarge_memory(WASMModuleInstance *module, uint32 inc_page_count)
+wasm_enlarge_memory_internal(WASMModuleInstance *module, uint32 inc_page_count)
 {
     WASMMemoryInstance *memory = wasm_get_default_memory(module);
     uint32 num_bytes_per_page, total_size_old;
@@ -697,3 +701,59 @@ wasm_enlarge_memory(WASMModuleInstance *module, uint32 inc_page_count)
     return true;
 }
 #endif /* end of OS_ENABLE_HW_BOUND_CHECK */
+
+bool
+wasm_enlarge_memory(WASMModuleInstance *module, uint32 inc_page_count)
+{
+    bool ret = false;
+
+#if WASM_ENABLE_SHARED_MEMORY != 0
+    WASMSharedMemNode *node =
+        wasm_module_get_shared_memory((WASMModuleCommon *)module->module);
+    if (node)
+        os_mutex_lock(&node->shared_mem_lock);
+#endif
+    ret = wasm_enlarge_memory_internal(module, inc_page_count);
+#if WASM_ENABLE_SHARED_MEMORY != 0
+    if (node)
+        os_mutex_unlock(&node->shared_mem_lock);
+#endif
+
+    return ret;
+}
+
+#if !defined(OS_ENABLE_HW_BOUND_CHECK)              \
+    || WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \
+    || WASM_ENABLE_BULK_MEMORY != 0
+uint32
+wasm_get_num_bytes_per_page(WASMMemoryInstance *memory, void *node)
+{
+    uint32 num_bytes_per_page;
+#if WASM_ENABLE_SHARED_MEMORY != 0
+    if (node)
+        os_mutex_lock(&((WASMSharedMemNode *)node)->shared_mem_lock);
+#endif
+    num_bytes_per_page = memory->num_bytes_per_page;
+#if WASM_ENABLE_SHARED_MEMORY != 0
+    if (node)
+        os_mutex_unlock(&((WASMSharedMemNode *)node)->shared_mem_lock);
+#endif
+    return num_bytes_per_page;
+}
+
+uint32
+wasm_get_linear_memory_size(WASMMemoryInstance *memory, void *node)
+{
+    uint32 linear_mem_size;
+#if WASM_ENABLE_SHARED_MEMORY != 0
+    if (node)
+        os_mutex_lock(&((WASMSharedMemNode *)node)->shared_mem_lock);
+#endif
+    linear_mem_size = memory->num_bytes_per_page * memory->cur_page_count;
+#if WASM_ENABLE_SHARED_MEMORY != 0
+    if (node)
+        os_mutex_unlock(&((WASMSharedMemNode *)node)->shared_mem_lock);
+#endif
+    return linear_mem_size;
+}
+#endif

+ 11 - 0
core/iwasm/common/wasm_memory.h

@@ -8,6 +8,7 @@
 
 #include "bh_common.h"
 #include "../include/wasm_export.h"
+#include "../interpreter/wasm_runtime.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -23,6 +24,16 @@ wasm_runtime_memory_destroy();
 unsigned
 wasm_runtime_memory_pool_size();
 
+#if !defined(OS_ENABLE_HW_BOUND_CHECK)              \
+    || WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \
+    || WASM_ENABLE_BULK_MEMORY != 0
+uint32
+wasm_get_num_bytes_per_page(WASMMemoryInstance *memory, void *node);
+
+uint32
+wasm_get_linear_memory_size(WASMMemoryInstance *memory, void *node);
+#endif
+
 #ifdef __cplusplus
 }
 #endif

+ 37 - 4
core/iwasm/common/wasm_native.c

@@ -53,6 +53,17 @@ uint32
 get_lib_pthread_export_apis(NativeSymbol **p_lib_pthread_apis);
 #endif
 
+#if WASM_ENABLE_LIB_WASI_THREADS != 0
+bool
+lib_wasi_threads_init(void);
+
+void
+lib_wasi_threads_destroy(void);
+
+uint32
+get_lib_wasi_threads_export_apis(NativeSymbol **p_lib_wasi_threads_apis);
+#endif
+
 uint32
 get_libc_emcc_export_apis(NativeSymbol **p_libc_emcc_apis);
 
@@ -239,6 +250,10 @@ lookup_symbol(NativeSymbol *native_symbols, uint32 n_native_symbols,
     return NULL;
 }
 
+/**
+ * allow func_type and all outputs, like p_signature, p_attachment and
+ * p_call_conv_raw to be NULL
+ */
 void *
 wasm_native_resolve_symbol(const char *module_name, const char *field_name,
                            const WASMType *func_type, const char **p_signature,
@@ -264,10 +279,13 @@ wasm_native_resolve_symbol(const char *module_name, const char *field_name,
         node = node_next;
     }
 
+    if (!p_signature || !p_attachment || !p_call_conv_raw)
+        return func_ptr;
+
     if (func_ptr) {
         if (signature && signature[0] != '\0') {
             /* signature is not empty, check its format */
-            if (!check_symbol_signature(func_type, signature)) {
+            if (!func_type || !check_symbol_signature(func_type, signature)) {
 #if WASM_ENABLE_WAMR_COMPILER == 0
                 /* Output warning except running aot compiler */
                 LOG_WARNING("failed to check signature '%s' and resolve "
@@ -383,7 +401,7 @@ wasm_native_init()
     || WASM_ENABLE_BASE_LIB != 0 || WASM_ENABLE_LIBC_EMCC != 0      \
     || WASM_ENABLE_LIB_RATS != 0 || WASM_ENABLE_WASI_NN != 0        \
     || WASM_ENABLE_APP_FRAMEWORK != 0 || WASM_ENABLE_LIBC_WASI != 0 \
-    || WASM_ENABLE_LIB_PTHREAD != 0
+    || WASM_ENABLE_LIB_PTHREAD != 0 || WASM_ENABLE_LIB_WASI_THREADS != 0
     NativeSymbol *native_symbols;
     uint32 n_native_symbols;
 #endif
@@ -438,6 +456,17 @@ wasm_native_init()
         goto fail;
 #endif
 
+#if WASM_ENABLE_LIB_WASI_THREADS != 0
+    if (!lib_wasi_threads_init())
+        goto fail;
+
+    n_native_symbols = get_lib_wasi_threads_export_apis(&native_symbols);
+    if (n_native_symbols > 0
+        && !wasm_native_register_natives("wasi", native_symbols,
+                                         n_native_symbols))
+        goto fail;
+#endif
+
 #if WASM_ENABLE_LIBC_EMCC != 0
     n_native_symbols = get_libc_emcc_export_apis(&native_symbols);
     if (n_native_symbols > 0
@@ -458,7 +487,7 @@ wasm_native_init()
     n_native_symbols = get_wasi_nn_export_apis(&native_symbols);
     if (!wasm_native_register_natives("wasi_nn", native_symbols,
                                       n_native_symbols))
-        return false;
+        goto fail;
 #endif
 
     return true;
@@ -466,7 +495,7 @@ wasm_native_init()
     || WASM_ENABLE_BASE_LIB != 0 || WASM_ENABLE_LIBC_EMCC != 0      \
     || WASM_ENABLE_LIB_RATS != 0 || WASM_ENABLE_WASI_NN != 0        \
     || WASM_ENABLE_APP_FRAMEWORK != 0 || WASM_ENABLE_LIBC_WASI != 0 \
-    || WASM_ENABLE_LIB_PTHREAD != 0
+    || WASM_ENABLE_LIB_PTHREAD != 0 || WASM_ENABLE_LIB_WASI_THREADS != 0
 fail:
     wasm_native_destroy();
     return false;
@@ -482,6 +511,10 @@ wasm_native_destroy()
     lib_pthread_destroy();
 #endif
 
+#if WASM_ENABLE_LIB_WASI_THREADS != 0
+    lib_wasi_threads_destroy();
+#endif
+
     node = g_native_symbols_list;
     while (node) {
         node_next = node->next;

+ 269 - 17
core/iwasm/common/wasm_runtime_common.c

@@ -7,6 +7,7 @@
 #include "bh_common.h"
 #include "bh_assert.h"
 #include "bh_log.h"
+#include "wasm_native.h"
 #include "wasm_runtime_common.h"
 #include "wasm_memory.h"
 #if WASM_ENABLE_INTERP != 0
@@ -128,6 +129,12 @@ runtime_malloc(uint64 size, WASMModuleInstanceCommon *module_inst,
 static JitCompOptions jit_options = { 0 };
 #endif
 
+#if WASM_ENABLE_JIT != 0
+static LLVMJITOptions llvm_jit_options = { 3, 3 };
+#endif
+
+static RunningMode runtime_running_mode = Mode_Default;
+
 #ifdef OS_ENABLE_HW_BOUND_CHECK
 /* The exec_env of thread local storage, set before calling function
    and used in signal handler, as we cannot get it from the argument
@@ -187,7 +194,7 @@ runtime_signal_handler(void *sig_addr)
         else if (exec_env_tls->exce_check_guard_page <= (uint8 *)sig_addr
                  && (uint8 *)sig_addr
                         < exec_env_tls->exce_check_guard_page + page_size) {
-            bh_assert(wasm_get_exception(module_inst));
+            bh_assert(wasm_copy_exception(module_inst, NULL));
             os_longjmp(jmpbuf_node->jmpbuf, 1);
         }
     }
@@ -243,7 +250,7 @@ runtime_exception_handler(EXCEPTION_POINTERS *exce_info)
             else if (exec_env_tls->exce_check_guard_page <= (uint8 *)sig_addr
                      && (uint8 *)sig_addr
                             < exec_env_tls->exce_check_guard_page + page_size) {
-                bh_assert(wasm_get_exception(module_inst));
+                bh_assert(wasm_copy_exception(module_inst, NULL));
                 if (module_inst->module_type == Wasm_Module_Bytecode) {
                     return EXCEPTION_CONTINUE_SEARCH;
                 }
@@ -514,6 +521,20 @@ wasm_runtime_destroy()
     wasm_runtime_memory_destroy();
 }
 
+RunningMode
+wasm_runtime_get_default_running_mode(void)
+{
+    return runtime_running_mode;
+}
+
+#if WASM_ENABLE_JIT != 0
+LLVMJITOptions
+wasm_runtime_get_llvm_jit_options(void)
+{
+    return llvm_jit_options;
+}
+#endif
+
 bool
 wasm_runtime_full_init(RuntimeInitArgs *init_args)
 {
@@ -521,10 +542,20 @@ wasm_runtime_full_init(RuntimeInitArgs *init_args)
                                   &init_args->mem_alloc_option))
         return false;
 
+    if (!wasm_runtime_set_default_running_mode(init_args->running_mode)) {
+        wasm_runtime_memory_destroy();
+        return false;
+    }
+
 #if WASM_ENABLE_FAST_JIT != 0
     jit_options.code_cache_size = init_args->fast_jit_code_cache_size;
 #endif
 
+#if WASM_ENABLE_JIT != 0
+    llvm_jit_options.size_level = init_args->llvm_jit_size_level;
+    llvm_jit_options.opt_level = init_args->llvm_jit_opt_level;
+#endif
+
     if (!wasm_runtime_env_init()) {
         wasm_runtime_memory_destroy();
         return false;
@@ -554,6 +585,47 @@ wasm_runtime_full_init(RuntimeInitArgs *init_args)
     return true;
 }
 
+bool
+wasm_runtime_is_running_mode_supported(RunningMode running_mode)
+{
+    if (running_mode == Mode_Default) {
+        return true;
+    }
+    else if (running_mode == Mode_Interp) {
+#if WASM_ENABLE_INTERP != 0
+        return true;
+#endif
+    }
+    else if (running_mode == Mode_Fast_JIT) {
+#if WASM_ENABLE_FAST_JIT != 0
+        return true;
+#endif
+    }
+    else if (running_mode == Mode_LLVM_JIT) {
+#if WASM_ENABLE_JIT != 0
+        return true;
+#endif
+    }
+    else if (running_mode == Mode_Multi_Tier_JIT) {
+#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \
+    && WASM_ENABLE_LAZY_JIT != 0
+        return true;
+#endif
+    }
+
+    return false;
+}
+
+bool
+wasm_runtime_set_default_running_mode(RunningMode running_mode)
+{
+    if (wasm_runtime_is_running_mode_supported(running_mode)) {
+        runtime_running_mode = running_mode;
+        return true;
+    }
+    return false;
+}
+
 PackageType
 get_package_type(const uint8 *buf, uint32 size)
 {
@@ -1171,6 +1243,41 @@ wasm_runtime_deinstantiate_internal(WASMModuleInstanceCommon *module_inst,
 #endif
 }
 
+bool
+wasm_runtime_set_running_mode(wasm_module_inst_t module_inst,
+                              RunningMode running_mode)
+{
+#if WASM_ENABLE_AOT != 0
+    if (module_inst->module_type == Wasm_Module_AoT)
+        return true;
+#endif
+
+#if WASM_ENABLE_INTERP != 0
+    if (module_inst->module_type == Wasm_Module_Bytecode) {
+        WASMModuleInstance *module_inst_interp =
+            (WASMModuleInstance *)module_inst;
+
+        return wasm_set_running_mode(module_inst_interp, running_mode);
+    }
+#endif
+
+    return false;
+}
+
+RunningMode
+wasm_runtime_get_running_mode(wasm_module_inst_t module_inst)
+{
+#if WASM_ENABLE_INTERP != 0
+    if (module_inst->module_type == Wasm_Module_Bytecode) {
+        WASMModuleInstance *module_inst_interp =
+            (WASMModuleInstance *)module_inst;
+        return module_inst_interp->e->running_mode;
+    }
+#endif
+
+    return Mode_Default;
+}
+
 void
 wasm_runtime_deinstantiate(WASMModuleInstanceCommon *module_inst)
 {
@@ -1399,6 +1506,22 @@ wasm_runtime_dump_mem_consumption(WASMExecEnv *exec_env)
     else
         os_printf("Total aux stack used: no enough info to profile\n");
 
+    /*
+     * Report the native stack usage estimation.
+     *
+     * Unlike the aux stack above, we report the amount unused
+     * because we don't know the stack "bottom".
+     *
+     * Note that this is just about what the runtime itself observed.
+     * It doesn't cover host func implementations, signal handlers, etc.
+     */
+    if (exec_env->native_stack_top_min != (void *)UINTPTR_MAX)
+        os_printf("Native stack left: %zd\n",
+                  exec_env->native_stack_top_min
+                      - exec_env->native_stack_boundary);
+    else
+        os_printf("Native stack left: no enough info to profile\n");
+
     os_printf("Total app heap used: %u\n", app_heap_peak_size);
 }
 #endif /* end of (WASM_ENABLE_MEMORY_PROFILING != 0) \
@@ -1743,6 +1866,33 @@ wasm_runtime_finalize_call_function(WASMExecEnv *exec_env,
 }
 #endif
 
+static bool
+clear_wasi_proc_exit_exception(WASMModuleInstanceCommon *module_inst_comm)
+{
+#if WASM_ENABLE_LIBC_WASI != 0
+    bool has_exception;
+    char exception[EXCEPTION_BUF_LEN];
+    WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm;
+
+    bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode
+              || module_inst_comm->module_type == Wasm_Module_AoT);
+
+    has_exception = wasm_copy_exception(module_inst, exception);
+    if (has_exception && !strcmp(exception, "Exception: wasi proc exit")) {
+        /* The "wasi proc exit" exception is thrown by native lib to
+           let wasm app exit, which is a normal behavior, we clear
+           the exception here. And just clear the exception of current
+           thread, don't call `wasm_set_exception(module_inst, NULL)`
+           which will clear the exception of all threads. */
+        module_inst->cur_exception[0] = '\0';
+        return true;
+    }
+    return false;
+#else
+    return false;
+#endif
+}
+
 bool
 wasm_runtime_call_wasm(WASMExecEnv *exec_env,
                        WASMFunctionInstanceCommon *function, uint32 argc,
@@ -1783,10 +1933,15 @@ wasm_runtime_call_wasm(WASMExecEnv *exec_env,
                                 param_argc, new_argv);
 #endif
     if (!ret) {
-        if (new_argv != argv) {
-            wasm_runtime_free(new_argv);
+        if (clear_wasi_proc_exit_exception(exec_env->module_inst)) {
+            ret = true;
+        }
+        else {
+            if (new_argv != argv) {
+                wasm_runtime_free(new_argv);
+            }
+            return false;
         }
-        return false;
     }
 
 #if WASM_ENABLE_REF_TYPES != 0
@@ -2150,11 +2305,41 @@ wasm_runtime_get_exec_env_singleton(WASMModuleInstanceCommon *module_inst_comm)
 void
 wasm_set_exception(WASMModuleInstance *module_inst, const char *exception)
 {
-    if (exception)
+    WASMExecEnv *exec_env = NULL;
+
+#if WASM_ENABLE_SHARED_MEMORY != 0
+    WASMSharedMemNode *node =
+        wasm_module_get_shared_memory((WASMModuleCommon *)module_inst->module);
+    if (node)
+        os_mutex_lock(&node->shared_mem_lock);
+#endif
+    if (exception) {
         snprintf(module_inst->cur_exception, sizeof(module_inst->cur_exception),
                  "Exception: %s", exception);
-    else
+    }
+    else {
         module_inst->cur_exception[0] = '\0';
+    }
+#if WASM_ENABLE_SHARED_MEMORY != 0
+    if (node)
+        os_mutex_unlock(&node->shared_mem_lock);
+#endif
+
+#if WASM_ENABLE_THREAD_MGR != 0
+    exec_env =
+        wasm_clusters_search_exec_env((WASMModuleInstanceCommon *)module_inst);
+    if (exec_env) {
+        wasm_cluster_spread_exception(exec_env, exception ? false : true);
+    }
+#if WASM_ENABLE_SHARED_MEMORY
+    if (exception) {
+        notify_stale_threads_on_exception(
+            (WASMModuleInstanceCommon *)module_inst);
+    }
+#endif
+#else
+    (void)exec_env;
+#endif
 }
 
 /* clang-format off */
@@ -2176,9 +2361,7 @@ static const char *exception_msgs[] = {
     "wasm auxiliary stack underflow", /* EXCE_AUX_STACK_UNDERFLOW */
     "out of bounds table access",     /* EXCE_OUT_OF_BOUNDS_TABLE_ACCESS */
     "wasm operand stack overflow",    /* EXCE_OPERAND_STACK_OVERFLOW */
-#if WASM_ENABLE_FAST_JIT != 0
     "failed to compile fast jit function", /* EXCE_FAILED_TO_COMPILE_FAST_JIT_FUNC */
-#endif
     "",                               /* EXCE_ALREADY_THROWN */
 };
 /* clang-format on */
@@ -2201,6 +2384,36 @@ wasm_get_exception(WASMModuleInstance *module_inst)
         return module_inst->cur_exception;
 }
 
+bool
+wasm_copy_exception(WASMModuleInstance *module_inst, char *exception_buf)
+{
+    bool has_exception = false;
+
+#if WASM_ENABLE_SHARED_MEMORY != 0
+    WASMSharedMemNode *node =
+        wasm_module_get_shared_memory((WASMModuleCommon *)module_inst->module);
+    if (node)
+        os_mutex_lock(&node->shared_mem_lock);
+#endif
+    if (module_inst->cur_exception[0] != '\0') {
+        /* NULL is passed if the caller is not interested in getting the
+         * exception content, but only in knowing if an exception has been
+         * raised
+         */
+        if (exception_buf != NULL)
+            bh_memcpy_s(exception_buf, sizeof(module_inst->cur_exception),
+                        module_inst->cur_exception,
+                        sizeof(module_inst->cur_exception));
+        has_exception = true;
+    }
+#if WASM_ENABLE_SHARED_MEMORY != 0
+    if (node)
+        os_mutex_unlock(&node->shared_mem_lock);
+#endif
+
+    return has_exception;
+}
+
 void
 wasm_runtime_set_exception(WASMModuleInstanceCommon *module_inst_comm,
                            const char *exception)
@@ -2222,6 +2435,17 @@ wasm_runtime_get_exception(WASMModuleInstanceCommon *module_inst_comm)
     return wasm_get_exception(module_inst);
 }
 
+bool
+wasm_runtime_copy_exception(WASMModuleInstanceCommon *module_inst_comm,
+                            char *exception_buf)
+{
+    WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm;
+
+    bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode
+              || module_inst_comm->module_type == Wasm_Module_AoT);
+    return wasm_copy_exception(module_inst, exception_buf);
+}
+
 void
 wasm_runtime_clear_exception(WASMModuleInstanceCommon *module_inst_comm)
 {
@@ -3145,7 +3369,7 @@ wasm_runtime_invoke_native_raw(WASMExecEnv *exec_env, void *func_ptr,
         }
     }
 
-    ret = !wasm_runtime_get_exception(module) ? true : false;
+    ret = !wasm_runtime_copy_exception(module, NULL);
 
 fail:
     if (argv1 != argv_buf)
@@ -3620,7 +3844,7 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr,
     }
     exec_env->attachment = NULL;
 
-    ret = !wasm_runtime_get_exception(module) ? true : false;
+    ret = !wasm_runtime_copy_exception(module, NULL);
 
 fail:
     if (argv1 != argv_buf)
@@ -3834,7 +4058,7 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr,
     }
     exec_env->attachment = NULL;
 
-    ret = !wasm_runtime_get_exception(module) ? true : false;
+    ret = !wasm_runtime_copy_exception(module, NULL);
 
 fail:
     if (argv1 != argv_buf)
@@ -4161,7 +4385,7 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr,
     }
     exec_env->attachment = NULL;
 
-    ret = !wasm_runtime_get_exception(module) ? true : false;
+    ret = !wasm_runtime_copy_exception(module, NULL);
 fail:
     if (argv1 != argv_buf)
         wasm_runtime_free(argv1);
@@ -4176,9 +4400,11 @@ fail:
                  || defined(BUILD_TARGET_RISCV64_LP64) */
 
 bool
-wasm_runtime_call_indirect(WASMExecEnv *exec_env, uint32 element_indices,
+wasm_runtime_call_indirect(WASMExecEnv *exec_env, uint32 element_index,
                            uint32 argc, uint32 argv[])
 {
+    bool ret = false;
+
     if (!wasm_runtime_exec_env_check(exec_env)) {
         LOG_ERROR("Invalid exec env stack info.");
         return false;
@@ -4190,13 +4416,18 @@ wasm_runtime_call_indirect(WASMExecEnv *exec_env, uint32 element_indices,
 
 #if WASM_ENABLE_INTERP != 0
     if (exec_env->module_inst->module_type == Wasm_Module_Bytecode)
-        return wasm_call_indirect(exec_env, 0, element_indices, argc, argv);
+        ret = wasm_call_indirect(exec_env, 0, element_index, argc, argv);
 #endif
 #if WASM_ENABLE_AOT != 0
     if (exec_env->module_inst->module_type == Wasm_Module_AoT)
-        return aot_call_indirect(exec_env, 0, element_indices, argc, argv);
+        ret = aot_call_indirect(exec_env, 0, element_index, argc, argv);
 #endif
-    return false;
+
+    if (!ret && clear_wasi_proc_exit_exception(exec_env->module_inst)) {
+        ret = true;
+    }
+
+    return ret;
 }
 
 static void
@@ -5155,3 +5386,24 @@ wasm_runtime_get_version(uint32_t *major, uint32_t *minor, uint32_t *patch)
     *minor = WAMR_VERSION_MINOR;
     *patch = WAMR_VERSION_PATCH;
 }
+
+bool
+wasm_runtime_is_import_func_linked(const char *module_name,
+                                   const char *func_name)
+{
+    return wasm_native_resolve_symbol(module_name, func_name, NULL, NULL, NULL,
+                                      NULL);
+}
+
+bool
+wasm_runtime_is_import_global_linked(const char *module_name,
+                                     const char *global_name)
+{
+#if WASM_ENABLE_LIBC_BUILTIN != 0
+    WASMGlobalImport global = { 0 };
+    return wasm_native_lookup_libc_builtin_global(module_name, global_name,
+                                                  &global);
+#else
+    return false;
+#endif
+}

+ 50 - 21
core/iwasm/common/wasm_runtime_common.h

@@ -25,6 +25,9 @@
 extern "C" {
 #endif
 
+/* Internal use for setting default running mode */
+#define Mode_Default 0
+
 #if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS != 0
 
 #define PUT_I64_TO_ADDR(addr, value)       \
@@ -413,6 +416,13 @@ typedef struct wasm_frame_t {
     const char *func_name_wp;
 } WASMCApiFrame;
 
+#ifdef WASM_ENABLE_JIT
+typedef struct LLVMJITOptions {
+    uint32 opt_level;
+    uint32 size_level;
+} LLVMJITOptions;
+#endif
+
 #ifdef OS_ENABLE_HW_BOUND_CHECK
 /* Signal info passing to interp/aot signal handler */
 typedef struct WASMSignalInfo {
@@ -437,10 +447,28 @@ wasm_runtime_get_exec_env_tls(void);
 WASM_RUNTIME_API_EXTERN bool
 wasm_runtime_init(void);
 
+/* Internal API */
+RunningMode
+wasm_runtime_get_default_running_mode(void);
+
+#if WASM_ENABLE_JIT != 0
+/* Internal API */
+LLVMJITOptions
+wasm_runtime_get_llvm_jit_options(void);
+#endif
+
 /* See wasm_export.h for description */
 WASM_RUNTIME_API_EXTERN bool
 wasm_runtime_full_init(RuntimeInitArgs *init_args);
 
+/* See wasm_export.h for description */
+WASM_RUNTIME_API_EXTERN bool
+wasm_runtime_is_running_mode_supported(RunningMode running_mode);
+
+/* See wasm_export.h for description */
+WASM_RUNTIME_API_EXTERN bool
+wasm_runtime_set_default_running_mode(RunningMode running_mode);
+
 /* See wasm_export.h for description */
 WASM_RUNTIME_API_EXTERN void
 wasm_runtime_destroy(void);
@@ -484,6 +512,15 @@ wasm_runtime_instantiate(WASMModuleCommon *module, uint32 stack_size,
                          uint32 heap_size, char *error_buf,
                          uint32 error_buf_size);
 
+/* See wasm_export.h for description */
+WASM_RUNTIME_API_EXTERN bool
+wasm_runtime_set_running_mode(wasm_module_inst_t module_inst,
+                              RunningMode running_mode);
+
+/* See wasm_export.h for description */
+WASM_RUNTIME_API_EXTERN RunningMode
+wasm_runtime_get_running_mode(wasm_module_inst_t module_inst);
+
 /* See wasm_export.h for description */
 WASM_RUNTIME_API_EXTERN void
 wasm_runtime_deinstantiate(WASMModuleInstanceCommon *module_inst);
@@ -578,6 +615,11 @@ wasm_runtime_call_wasm_v(WASMExecEnv *exec_env,
                          uint32 num_results, wasm_val_t *results,
                          uint32 num_args, ...);
 
+/* See wasm_export.h for description */
+WASM_RUNTIME_API_EXTERN bool
+wasm_runtime_call_indirect(WASMExecEnv *exec_env, uint32 element_index,
+                           uint32 argc, uint32 argv[]);
+
 #if WASM_ENABLE_DEBUG_INTERP != 0
 /* See wasm_export.h for description */
 WASM_RUNTIME_API_EXTERN uint32
@@ -589,27 +631,6 @@ WASM_RUNTIME_API_EXTERN uint32
 wasm_runtime_start_debug_instance(WASMExecEnv *exec_env);
 #endif
 
-/**
- * Call a function reference of a given WASM runtime instance with
- * arguments.
- *
- * @param exec_env the execution environment to call the function
- *   which must be created from wasm_create_exec_env()
- * @param element_indices the function ference indicies, usually
- *   prvovided by the caller of a registed native function
- * @param argc the number of arguments
- * @param argv the arguments.  If the function method has return value,
- *   the first (or first two in case 64-bit return value) element of
- *   argv stores the return value of the called WASM function after this
- *   function returns.
- *
- * @return true if success, false otherwise and exception will be thrown,
- *   the caller can call wasm_runtime_get_exception to get exception info.
- */
-bool
-wasm_runtime_call_indirect(WASMExecEnv *exec_env, uint32 element_indices,
-                           uint32 argc, uint32 argv[]);
-
 bool
 wasm_runtime_create_exec_env_singleton(WASMModuleInstanceCommon *module_inst);
 
@@ -956,6 +977,14 @@ void
 wasm_runtime_destroy_custom_sections(WASMCustomSection *section_list);
 #endif
 
+WASM_RUNTIME_API_EXTERN bool
+wasm_runtime_is_import_func_linked(const char *module_name,
+                                   const char *func_name);
+
+WASM_RUNTIME_API_EXTERN bool
+wasm_runtime_is_import_global_linked(const char *module_name,
+                                     const char *global_name);
+
 #ifdef __cplusplus
 }
 #endif

+ 136 - 34
core/iwasm/common/wasm_shared_memory.c

@@ -30,8 +30,14 @@ typedef struct AtomicWaitNode {
     korp_cond wait_cond;
 } AtomicWaitNode;
 
+typedef struct AtomicWaitAddressArgs {
+    uint32 index;
+    void **addr;
+} AtomicWaitAddressArgs;
+
 /* Atomic wait map */
 static HashMap *wait_map;
+static korp_mutex wait_map_lock;
 
 static uint32
 wait_address_hash(void *address);
@@ -47,11 +53,18 @@ wasm_shared_memory_init()
 {
     if (os_mutex_init(&shared_memory_list_lock) != 0)
         return false;
+
+    if (os_mutex_init(&wait_map_lock) != 0) {
+        os_mutex_destroy(&shared_memory_list_lock);
+        return false;
+    }
+
     /* wait map not exists, create new map */
     if (!(wait_map = bh_hash_map_create(32, true, (HashFunc)wait_address_hash,
                                         (KeyEqualFunc)wait_address_equal, NULL,
                                         destroy_wait_info))) {
         os_mutex_destroy(&shared_memory_list_lock);
+        os_mutex_destroy(&wait_map_lock);
         return false;
     }
 
@@ -62,6 +75,7 @@ void
 wasm_shared_memory_destroy()
 {
     os_mutex_destroy(&shared_memory_list_lock);
+    os_mutex_destroy(&wait_map_lock);
     if (wait_map) {
         bh_hash_map_destroy(wait_map);
     }
@@ -87,6 +101,61 @@ search_module(WASMModuleCommon *module)
     return NULL;
 }
 
+static void
+wait_map_address_count_callback(void *key, void *value,
+                                void *p_total_elem_count)
+{
+    *(uint32 *)p_total_elem_count = *(uint32 *)p_total_elem_count + 1;
+}
+
+static void
+create_list_of_waiter_addresses(void *key, void *value, void *user_data)
+{
+    AtomicWaitAddressArgs *data = (AtomicWaitAddressArgs *)user_data;
+    data->addr[data->index++] = key;
+}
+
+void
+notify_stale_threads_on_exception(WASMModuleInstanceCommon *module_inst)
+{
+    AtomicWaitAddressArgs args = { 0 };
+    uint32 i = 0, total_elem_count = 0;
+    uint64 total_elem_count_size = 0;
+
+    os_mutex_lock(&wait_map_lock); /* Make the two traversals atomic */
+
+    /* count number of addresses in wait_map */
+    bh_hash_map_traverse(wait_map, wait_map_address_count_callback,
+                         (void *)&total_elem_count);
+
+    if (!total_elem_count) {
+        os_mutex_unlock(&wait_map_lock);
+        return;
+    }
+
+    /* allocate memory */
+    total_elem_count_size = (uint64)sizeof(void *) * total_elem_count;
+    if (total_elem_count_size >= UINT32_MAX
+        || !(args.addr = wasm_runtime_malloc((uint32)total_elem_count_size))) {
+        LOG_ERROR(
+            "failed to allocate memory for list of atomic wait addresses");
+        os_mutex_unlock(&wait_map_lock);
+        return;
+    }
+
+    /* set values in list of addresses */
+    bh_hash_map_traverse(wait_map, create_list_of_waiter_addresses, &args);
+    os_mutex_unlock(&wait_map_lock);
+
+    /* notify */
+    for (i = 0; i < args.index; i++) {
+        wasm_runtime_atomic_notify(module_inst, args.addr[i], UINT32_MAX);
+    }
+
+    /* free memory allocated to args data */
+    wasm_runtime_free(args.addr);
+}
+
 WASMSharedMemNode *
 wasm_module_get_shared_memory(WASMModuleCommon *module)
 {
@@ -97,13 +166,13 @@ int32
 shared_memory_inc_reference(WASMModuleCommon *module)
 {
     WASMSharedMemNode *node = search_module(module);
+    uint32 ref_count = -1;
     if (node) {
         os_mutex_lock(&node->lock);
-        node->ref_count++;
+        ref_count = ++node->ref_count;
         os_mutex_unlock(&node->lock);
-        return node->ref_count;
     }
-    return -1;
+    return ref_count;
 }
 
 int32
@@ -120,6 +189,7 @@ shared_memory_dec_reference(WASMModuleCommon *module)
             bh_list_remove(shared_memory_list, node);
             os_mutex_unlock(&shared_memory_list_lock);
 
+            os_mutex_destroy(&node->shared_mem_lock);
             os_mutex_destroy(&node->lock);
             wasm_runtime_free(node);
         }
@@ -148,7 +218,14 @@ shared_memory_set_memory_inst(WASMModuleCommon *module,
     node->module = module;
     node->memory_inst = memory;
     node->ref_count = 1;
+
+    if (os_mutex_init(&node->shared_mem_lock) != 0) {
+        wasm_runtime_free(node);
+        return NULL;
+    }
+
     if (os_mutex_init(&node->lock) != 0) {
+        os_mutex_destroy(&node->shared_mem_lock);
         wasm_runtime_free(node);
         return NULL;
     }
@@ -208,9 +285,11 @@ notify_wait_list(bh_list *wait_list, uint32 count)
         bh_assert(node);
         next = bh_list_elem_next(node);
 
+        os_mutex_lock(&node->wait_lock);
         node->status = S_NOTIFIED;
         /* wakeup */
         os_cond_signal(&node->wait_cond);
+        os_mutex_unlock(&node->wait_lock);
 
         node = next;
     }
@@ -224,13 +303,13 @@ acquire_wait_info(void *address, bool create)
     AtomicWaitInfo *wait_info = NULL;
     bh_list_status ret;
 
-    os_mutex_lock(&shared_memory_list_lock);
+    os_mutex_lock(&wait_map_lock); /* Make find + insert atomic */
 
     if (address)
         wait_info = (AtomicWaitInfo *)bh_hash_map_find(wait_map, address);
 
     if (!create) {
-        os_mutex_unlock(&shared_memory_list_lock);
+        os_mutex_unlock(&wait_map_lock);
         return wait_info;
     }
 
@@ -257,7 +336,7 @@ acquire_wait_info(void *address, bool create)
         }
     }
 
-    os_mutex_unlock(&shared_memory_list_lock);
+    os_mutex_unlock(&wait_map_lock);
 
     bh_assert(wait_info);
     (void)ret;
@@ -270,7 +349,7 @@ fail2:
     wasm_runtime_free(wait_info);
 
 fail1:
-    os_mutex_unlock(&shared_memory_list_lock);
+    os_mutex_unlock(&wait_map_lock);
 
     return NULL;
 }
@@ -297,17 +376,16 @@ destroy_wait_info(void *wait_info)
     }
 }
 
-static void
-release_wait_info(HashMap *wait_map_, AtomicWaitInfo *wait_info, void *address)
+static bool
+map_remove_wait_info(HashMap *wait_map_, AtomicWaitInfo *wait_info,
+                     void *address)
 {
-    os_mutex_lock(&shared_memory_list_lock);
-
-    if (wait_info->wait_list->len == 0) {
-        bh_hash_map_remove(wait_map_, address, NULL, NULL);
-        destroy_wait_info(wait_info);
+    if (wait_info->wait_list->len > 0) {
+        return false;
     }
 
-    os_mutex_unlock(&shared_memory_list_lock);
+    bh_hash_map_remove(wait_map_, address, NULL, NULL);
+    return true;
 }
 
 uint32
@@ -317,11 +395,16 @@ wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address,
     WASMModuleInstance *module_inst = (WASMModuleInstance *)module;
     AtomicWaitInfo *wait_info;
     AtomicWaitNode *wait_node;
-    bool check_ret, is_timeout;
+    WASMSharedMemNode *node;
+    bool check_ret, is_timeout, no_wait, removed_from_map;
 
     bh_assert(module->module_type == Wasm_Module_Bytecode
               || module->module_type == Wasm_Module_AoT);
 
+    if (wasm_copy_exception(module_inst, NULL)) {
+        return -1;
+    }
+
     /* Currently we have only one memory instance */
     if (!module_inst->memories[0]->is_shared) {
         wasm_runtime_set_exception(module, "expected shared memory");
@@ -343,11 +426,13 @@ wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address,
         return -1;
     }
 
-    os_mutex_lock(&wait_info->wait_list_lock);
+    node = search_module((WASMModuleCommon *)module_inst->module);
+    os_mutex_lock(&node->shared_mem_lock);
+    no_wait = (!wait64 && *(uint32 *)address != (uint32)expect)
+              || (wait64 && *(uint64 *)address != expect);
+    os_mutex_unlock(&node->shared_mem_lock);
 
-    if ((!wait64 && *(uint32 *)address != (uint32)expect)
-        || (wait64 && *(uint64 *)address != expect)) {
-        os_mutex_unlock(&wait_info->wait_list_lock);
+    if (no_wait) {
         return 1;
     }
     else {
@@ -355,33 +440,29 @@ wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address,
 
         if (!(wait_node = wasm_runtime_malloc(sizeof(AtomicWaitNode)))) {
             wasm_runtime_set_exception(module, "failed to create wait node");
-            os_mutex_unlock(&wait_info->wait_list_lock);
             return -1;
         }
         memset(wait_node, 0, sizeof(AtomicWaitNode));
 
         if (0 != os_mutex_init(&wait_node->wait_lock)) {
             wasm_runtime_free(wait_node);
-            os_mutex_unlock(&wait_info->wait_list_lock);
             return -1;
         }
 
         if (0 != os_cond_init(&wait_node->wait_cond)) {
             os_mutex_destroy(&wait_node->wait_lock);
             wasm_runtime_free(wait_node);
-            os_mutex_unlock(&wait_info->wait_list_lock);
             return -1;
         }
 
         wait_node->status = S_WAITING;
-
+        os_mutex_lock(&wait_info->wait_list_lock);
         ret = bh_list_insert(wait_info->wait_list, wait_node);
+        os_mutex_unlock(&wait_info->wait_list_lock);
         bh_assert(ret == BH_LIST_SUCCESS);
         (void)ret;
     }
 
-    os_mutex_unlock(&wait_info->wait_list_lock);
-
     /* condition wait start */
     os_mutex_lock(&wait_node->wait_lock);
 
@@ -389,22 +470,27 @@ wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address,
                          timeout < 0 ? BHT_WAIT_FOREVER
                                      : (uint64)timeout / 1000);
 
+    is_timeout = wait_node->status == S_WAITING ? true : false;
     os_mutex_unlock(&wait_node->wait_lock);
 
-    /* Check the wait node status */
+    os_mutex_lock(&node->shared_mem_lock);
     os_mutex_lock(&wait_info->wait_list_lock);
+
     check_ret = is_wait_node_exists(wait_info->wait_list, wait_node);
     bh_assert(check_ret);
 
-    is_timeout = wait_node->status == S_WAITING ? true : false;
-
+    /* Remove wait node */
     bh_list_remove(wait_info->wait_list, wait_node);
     os_mutex_destroy(&wait_node->wait_lock);
     os_cond_destroy(&wait_node->wait_cond);
     wasm_runtime_free(wait_node);
-    os_mutex_unlock(&wait_info->wait_list_lock);
 
-    release_wait_info(wait_map, wait_info, address);
+    /* Release wait info if no wait nodes attached */
+    removed_from_map = map_remove_wait_info(wait_map, wait_info, address);
+    os_mutex_unlock(&wait_info->wait_list_lock);
+    if (removed_from_map)
+        destroy_wait_info(wait_info);
+    os_mutex_unlock(&node->shared_mem_lock);
 
     (void)check_ret;
     return is_timeout ? 2 : 0;
@@ -417,12 +503,22 @@ wasm_runtime_atomic_notify(WASMModuleInstanceCommon *module, void *address,
     WASMModuleInstance *module_inst = (WASMModuleInstance *)module;
     uint32 notify_result;
     AtomicWaitInfo *wait_info;
+    WASMSharedMemNode *node;
+    bool out_of_bounds;
 
     bh_assert(module->module_type == Wasm_Module_Bytecode
               || module->module_type == Wasm_Module_AoT);
 
-    if ((uint8 *)address < module_inst->memories[0]->memory_data
-        || (uint8 *)address + 4 > module_inst->memories[0]->memory_data_end) {
+    node = search_module((WASMModuleCommon *)module_inst->module);
+    if (node)
+        os_mutex_lock(&node->shared_mem_lock);
+    out_of_bounds =
+        ((uint8 *)address < module_inst->memories[0]->memory_data
+         || (uint8 *)address + 4 > module_inst->memories[0]->memory_data_end);
+
+    if (out_of_bounds) {
+        if (node)
+            os_mutex_unlock(&node->shared_mem_lock);
         wasm_runtime_set_exception(module, "out of bounds memory access");
         return -1;
     }
@@ -430,12 +526,18 @@ wasm_runtime_atomic_notify(WASMModuleInstanceCommon *module, void *address,
     wait_info = acquire_wait_info(address, false);
 
     /* Nobody wait on this address */
-    if (!wait_info)
+    if (!wait_info) {
+        if (node)
+            os_mutex_unlock(&node->shared_mem_lock);
         return 0;
+    }
 
     os_mutex_lock(&wait_info->wait_list_lock);
     notify_result = notify_wait_list(wait_info->wait_list, count);
     os_mutex_unlock(&wait_info->wait_list_lock);
 
+    if (node)
+        os_mutex_unlock(&node->shared_mem_lock);
+
     return notify_result;
 }

+ 5 - 0
core/iwasm/common/wasm_shared_memory.h

@@ -26,6 +26,8 @@ typedef struct WASMSharedMemNode {
     WASMModuleCommon *module;
     /* The memory information */
     WASMMemoryInstanceCommon *memory_inst;
+    /* Lock used for atomic operations */
+    korp_mutex shared_mem_lock;
 
     /* reference count */
     uint32 ref_count;
@@ -37,6 +39,9 @@ wasm_shared_memory_init();
 void
 wasm_shared_memory_destroy();
 
+void
+notify_stale_threads_on_exception(WASMModuleInstanceCommon *module);
+
 WASMSharedMemNode *
 wasm_module_get_shared_memory(WASMModuleCommon *module);
 

+ 1 - 0
core/iwasm/compilation/aot.h

@@ -149,6 +149,7 @@ typedef struct AOTImportGlobal {
     uint32 data_offset;
     /* global data after linked */
     WASMValue global_data_linked;
+    bool is_linked;
 } AOTImportGlobal;
 
 /**

+ 2 - 0
core/iwasm/compilation/aot_compiler.c

@@ -1240,6 +1240,8 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
                     case WASM_OP_ATOMIC_FENCE:
                         /* Skip memory index */
                         frame_ip++;
+                        if (!aot_compiler_op_atomic_fence(comp_ctx, func_ctx))
+                            return false;
                         break;
                     case WASM_OP_ATOMIC_I32_LOAD:
                         bytes = 4;

+ 1 - 0
core/iwasm/compilation/aot_compiler.h

@@ -259,6 +259,7 @@ check_type_compatible(uint8 src_type, uint8 dst_type)
 #define I32_SIX LLVM_CONST(i32_six)
 #define I32_SEVEN LLVM_CONST(i32_seven)
 #define I32_EIGHT LLVM_CONST(i32_eight)
+#define I32_NINE LLVM_CONST(i32_nine)
 #define I32_NEG_ONE LLVM_CONST(i32_neg_one)
 #define I64_NEG_ONE LLVM_CONST(i64_neg_one)
 #define I32_MIN LLVM_CONST(i32_min)

+ 39 - 60
core/iwasm/compilation/aot_emit_conversion.c

@@ -9,35 +9,47 @@
 #include "../aot/aot_intrinsic.h"
 #include "../aot/aot_runtime.h"
 
-static bool
-trunc_float_to_int(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
-                   LLVMValueRef operand, LLVMTypeRef src_type,
-                   LLVMTypeRef dest_type, LLVMValueRef min_value,
-                   LLVMValueRef max_value, char *name, bool sign)
+static LLVMValueRef
+call_fcmp_intrinsic(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
+                    enum AOTFloatCond cond, LLVMRealPredicate op,
+                    LLVMValueRef lhs, LLVMValueRef rhs, LLVMTypeRef src_type,
+                    const char *name)
 {
-    LLVMBasicBlockRef check_nan_succ, check_overflow_succ;
-    LLVMValueRef is_less, is_greater, res;
-
+    LLVMValueRef res = NULL;
     if (comp_ctx->disable_llvm_intrinsics
         && aot_intrinsic_check_capability(
             comp_ctx, src_type == F32_TYPE ? "f32_cmp" : "f64_cmp")) {
         LLVMTypeRef param_types[3];
-        LLVMValueRef opcond = LLVMConstInt(I32_TYPE, FLOAT_UNO, true);
+        LLVMValueRef opcond = LLVMConstInt(I32_TYPE, cond, true);
         param_types[0] = I32_TYPE;
         param_types[1] = src_type;
         param_types[2] = src_type;
         res = aot_call_llvm_intrinsic(
             comp_ctx, func_ctx, src_type == F32_TYPE ? "f32_cmp" : "f64_cmp",
-            I32_TYPE, param_types, 3, opcond, operand, operand);
+            I32_TYPE, param_types, 3, opcond, lhs, rhs);
         if (!res) {
             goto fail;
         }
         res = LLVMBuildIntCast(comp_ctx->builder, res, INT1_TYPE, "bit_cast");
     }
     else {
-        res = LLVMBuildFCmp(comp_ctx->builder, LLVMRealUNO, operand, operand,
-                            "fcmp_is_nan");
+        res = LLVMBuildFCmp(comp_ctx->builder, op, lhs, rhs, name);
     }
+fail:
+    return res;
+}
+
+static bool
+trunc_float_to_int(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
+                   LLVMValueRef operand, LLVMTypeRef src_type,
+                   LLVMTypeRef dest_type, LLVMValueRef min_value,
+                   LLVMValueRef max_value, char *name, bool sign)
+{
+    LLVMBasicBlockRef check_nan_succ, check_overflow_succ;
+    LLVMValueRef is_less, is_greater, res;
+
+    res = call_fcmp_intrinsic(comp_ctx, func_ctx, FLOAT_UNO, LLVMRealUNO,
+                              operand, operand, src_type, "fcmp_is_nan");
 
     if (!res) {
         aot_set_last_error("llvm build fcmp failed.");
@@ -58,54 +70,18 @@ trunc_float_to_int(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
                              check_nan_succ)))
         goto fail;
 
-    if (comp_ctx->disable_llvm_intrinsics
-        && aot_intrinsic_check_capability(
-            comp_ctx, src_type == F32_TYPE ? "f32_cmp" : "f64_cmp")) {
-        LLVMTypeRef param_types[3];
-        LLVMValueRef opcond = LLVMConstInt(I32_TYPE, FLOAT_LE, true);
-        param_types[0] = I32_TYPE;
-        param_types[1] = src_type;
-        param_types[2] = src_type;
-        is_less = aot_call_llvm_intrinsic(
-            comp_ctx, func_ctx, src_type == F32_TYPE ? "f32_cmp" : "f64_cmp",
-            I32_TYPE, param_types, 3, opcond, operand, min_value);
-        if (!is_less) {
-            goto fail;
-        }
-        is_less =
-            LLVMBuildIntCast(comp_ctx->builder, is_less, INT1_TYPE, "bit_cast");
-    }
-    else {
-        is_less = LLVMBuildFCmp(comp_ctx->builder, LLVMRealOLE, operand,
-                                min_value, "fcmp_min_value");
-    }
+    is_less =
+        call_fcmp_intrinsic(comp_ctx, func_ctx, FLOAT_LE, LLVMRealOLE, operand,
+                            min_value, src_type, "fcmp_min_value");
 
     if (!is_less) {
         aot_set_last_error("llvm build fcmp failed.");
         goto fail;
     }
 
-    if (comp_ctx->disable_llvm_intrinsics
-        && aot_intrinsic_check_capability(
-            comp_ctx, src_type == F32_TYPE ? "f32_cmp" : "f64_cmp")) {
-        LLVMTypeRef param_types[3];
-        LLVMValueRef opcond = LLVMConstInt(I32_TYPE, FLOAT_GE, true);
-        param_types[0] = I32_TYPE;
-        param_types[1] = src_type;
-        param_types[2] = src_type;
-        is_greater = aot_call_llvm_intrinsic(
-            comp_ctx, func_ctx, src_type == F32_TYPE ? "f32_cmp" : "f64_cmp",
-            I32_TYPE, param_types, 3, opcond, operand, max_value);
-        if (!is_greater) {
-            goto fail;
-        }
-        is_greater = LLVMBuildIntCast(comp_ctx->builder, is_greater, INT1_TYPE,
-                                      "bit_cast");
-    }
-    else {
-        is_greater = LLVMBuildFCmp(comp_ctx->builder, LLVMRealOGE, operand,
-                                   max_value, "fcmp_min_value");
-    }
+    is_greater =
+        call_fcmp_intrinsic(comp_ctx, func_ctx, FLOAT_GE, LLVMRealOGE, operand,
+                            max_value, src_type, "fcmp_min_value");
 
     if (!is_greater) {
         aot_set_last_error("llvm build fcmp failed.");
@@ -183,8 +159,9 @@ trunc_sat_float_to_int(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     LLVMValueRef zero = (dest_type == I32_TYPE) ? I32_ZERO : I64_ZERO;
     LLVMValueRef vmin, vmax;
 
-    if (!(res = LLVMBuildFCmp(comp_ctx->builder, LLVMRealUNO, operand, operand,
-                              "fcmp_is_nan"))) {
+    if (!(res =
+              call_fcmp_intrinsic(comp_ctx, func_ctx, FLOAT_UNO, LLVMRealUNO,
+                                  operand, operand, src_type, "fcmp_is_nan"))) {
         aot_set_last_error("llvm build fcmp failed.");
         goto fail;
     }
@@ -212,8 +189,9 @@ trunc_sat_float_to_int(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
 
     /* Start to translate check_nan_succ block */
     LLVMPositionBuilderAtEnd(comp_ctx->builder, check_nan_succ);
-    if (!(is_less = LLVMBuildFCmp(comp_ctx->builder, LLVMRealOLE, operand,
-                                  min_value, "fcmp_min_value"))) {
+    if (!(is_less = call_fcmp_intrinsic(comp_ctx, func_ctx, FLOAT_LE,
+                                        LLVMRealOLE, operand, min_value,
+                                        src_type, "fcmp_min_value"))) {
         aot_set_last_error("llvm build fcmp failed.");
         goto fail;
     }
@@ -232,8 +210,9 @@ trunc_sat_float_to_int(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
 
     /* Start to translate check_less_succ block */
     LLVMPositionBuilderAtEnd(comp_ctx->builder, check_less_succ);
-    if (!(is_greater = LLVMBuildFCmp(comp_ctx->builder, LLVMRealOGE, operand,
-                                     max_value, "fcmp_max_value"))) {
+    if (!(is_greater = call_fcmp_intrinsic(comp_ctx, func_ctx, FLOAT_GE,
+                                           LLVMRealOGE, operand, max_value,
+                                           src_type, "fcmp_max_value"))) {
         aot_set_last_error("llvm build fcmp failed.");
         goto fail;
     }

+ 116 - 8
core/iwasm/compilation/aot_emit_function.c

@@ -366,6 +366,87 @@ fail:
 #endif /* end of (WASM_ENABLE_DUMP_CALL_STACK != 0) \
                  || (WASM_ENABLE_PERF_PROFILING != 0) */
 
+static bool
+record_stack_usage(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
+                   uint32 callee_cell_num)
+{
+    LLVMBasicBlockRef block_curr = LLVMGetInsertBlock(comp_ctx->builder);
+    LLVMBasicBlockRef block_update;
+    LLVMBasicBlockRef block_after_update;
+    LLVMValueRef callee_local_size, new_sp, cmp;
+    LLVMValueRef native_stack_top_min;
+    LLVMTypeRef ptrdiff_type;
+    if (comp_ctx->pointer_size == sizeof(uint64_t)) {
+        ptrdiff_type = I64_TYPE;
+    }
+    else {
+        ptrdiff_type = I32_TYPE;
+    }
+
+    /*
+     * new_sp = last_alloca - callee_local_size;
+     * if (*native_stack_top_min_addr > new_sp) {
+     *    *native_stack_top_min_addr = new_sp;
+     * }
+     */
+
+    if (!(callee_local_size = LLVMConstInt(
+              ptrdiff_type, -(int64_t)callee_cell_num * 4, true))) {
+        aot_set_last_error("llvm build const failed.");
+        return false;
+    }
+    if (!(new_sp = LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE,
+                                         func_ctx->last_alloca,
+                                         &callee_local_size, 1, "new_sp"))) {
+        aot_set_last_error("llvm build gep failed");
+        return false;
+    }
+    if (!(native_stack_top_min = LLVMBuildLoad2(
+              comp_ctx->builder, OPQ_PTR_TYPE,
+              func_ctx->native_stack_top_min_addr, "native_stack_top_min"))) {
+        aot_set_last_error("llvm build load failed");
+        return false;
+    }
+    if (!(cmp = LLVMBuildICmp(comp_ctx->builder, LLVMIntULT, new_sp,
+                              native_stack_top_min, "cmp"))) {
+        aot_set_last_error("llvm build icmp failed.");
+        return false;
+    }
+
+    if (!(block_update = LLVMAppendBasicBlockInContext(
+              comp_ctx->context, func_ctx->func, "block_update"))) {
+        aot_set_last_error("llvm add basic block failed.");
+        return false;
+    }
+    if (!(block_after_update = LLVMAppendBasicBlockInContext(
+              comp_ctx->context, func_ctx->func, "block_after_update"))) {
+        aot_set_last_error("llvm add basic block failed.");
+        return false;
+    }
+    LLVMMoveBasicBlockAfter(block_update, block_curr);
+    LLVMMoveBasicBlockAfter(block_after_update, block_update);
+
+    if (!LLVMBuildCondBr(comp_ctx->builder, cmp, block_update,
+                         block_after_update)) {
+        aot_set_last_error("llvm build cond br failed.");
+        return false;
+    }
+
+    LLVMPositionBuilderAtEnd(comp_ctx->builder, block_update);
+    if (!LLVMBuildStore(comp_ctx->builder, new_sp,
+                        func_ctx->native_stack_top_min_addr)) {
+        aot_set_last_error("llvm build store failed");
+        return false;
+    }
+    if (!LLVMBuildBr(comp_ctx->builder, block_after_update)) {
+        aot_set_last_error("llvm build br failed.");
+        return false;
+    }
+
+    LLVMPositionBuilderAtEnd(comp_ctx->builder, block_after_update);
+    return true;
+}
+
 static bool
 check_stack_boundary(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
                      uint32 callee_cell_num)
@@ -409,6 +490,19 @@ check_stack_boundary(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     return true;
 }
 
+static bool
+check_stack(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
+            uint32 callee_cell_num)
+{
+    if (comp_ctx->enable_stack_estimation
+        && !record_stack_usage(comp_ctx, func_ctx, callee_cell_num))
+        return false;
+    if (comp_ctx->enable_stack_bound_check
+        && !check_stack_boundary(comp_ctx, func_ctx, callee_cell_num))
+        return false;
+    return true;
+}
+
 /**
  * Check whether the app address and its buffer are inside the linear memory,
  * if no, throw exception
@@ -852,8 +946,7 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
         callee_cell_num =
             aot_func->param_cell_num + aot_func->local_cell_num + 1;
 
-        if (comp_ctx->enable_stack_bound_check
-            && !check_stack_boundary(comp_ctx, func_ctx, callee_cell_num))
+        if (!check_stack(comp_ctx, func_ctx, callee_cell_num))
             goto fail;
 
 #if LLVM_VERSION_MAJOR >= 14
@@ -906,6 +999,14 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     }
 #endif
 
+#if WASM_ENABLE_THREAD_MGR != 0
+    /* Insert suspend check point */
+    if (comp_ctx->enable_thread_mgr) {
+        if (!check_suspend_flags(comp_ctx, func_ctx))
+            goto fail;
+    }
+#endif
+
     ret = true;
 fail:
     if (param_types)
@@ -1467,12 +1568,11 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     /* Translate call non-import block */
     LLVMPositionBuilderAtEnd(comp_ctx->builder, block_call_non_import);
 
-    if (comp_ctx->enable_stack_bound_check
-        && !check_stack_boundary(comp_ctx, func_ctx,
-                                 param_cell_num + ext_cell_num
-                                     + 1
-                                     /* Reserve some local variables */
-                                     + 16))
+    if (!check_stack(comp_ctx, func_ctx,
+                     param_cell_num + ext_cell_num
+                         + 1
+                         /* Reserve some local variables */
+                         + 16))
         goto fail;
 
     /* Load function pointer */
@@ -1553,6 +1653,14 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     }
 #endif
 
+#if WASM_ENABLE_THREAD_MGR != 0
+    /* Insert suspend check point */
+    if (comp_ctx->enable_thread_mgr) {
+        if (!check_suspend_flags(comp_ctx, func_ctx))
+            goto fail;
+    }
+#endif
+
     ret = true;
 
 fail:

+ 19 - 1
core/iwasm/compilation/aot_emit_memory.c

@@ -7,6 +7,7 @@
 #include "aot_emit_exception.h"
 #include "../aot/aot_runtime.h"
 #include "aot_intrinsic.h"
+#include "aot_emit_control.h"
 
 #define BUILD_ICMP(op, left, right, res, name)                                \
     do {                                                                      \
@@ -1344,7 +1345,7 @@ aot_compile_op_atomic_wait(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
         return false;
     }
 
-    BUILD_ICMP(LLVMIntSGT, ret_value, I32_ZERO, cmp, "atomic_wait_ret");
+    BUILD_ICMP(LLVMIntNE, ret_value, I32_NEG_ONE, cmp, "atomic_wait_ret");
 
     ADD_BASIC_BLOCK(wait_fail, "atomic_wait_fail");
     ADD_BASIC_BLOCK(wait_success, "wait_success");
@@ -1368,6 +1369,14 @@ aot_compile_op_atomic_wait(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
 
     PUSH_I32(ret_value);
 
+#if WASM_ENABLE_THREAD_MGR != 0
+    /* Insert suspend check point */
+    if (comp_ctx->enable_thread_mgr) {
+        if (!check_suspend_flags(comp_ctx, func_ctx))
+            return false;
+    }
+#endif
+
     return true;
 fail:
     return false;
@@ -1414,4 +1423,13 @@ fail:
     return false;
 }
 
+bool
+aot_compiler_op_atomic_fence(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
+{
+    return LLVMBuildFence(comp_ctx->builder,
+                          LLVMAtomicOrderingSequentiallyConsistent, false, "")
+               ? true
+               : false;
+}
+
 #endif /* end of WASM_ENABLE_SHARED_MEMORY */

+ 4 - 0
core/iwasm/compilation/aot_emit_memory.h

@@ -97,6 +97,10 @@ bool
 aot_compiler_op_atomic_notify(AOTCompContext *comp_ctx,
                               AOTFuncContext *func_ctx, uint32 align,
                               uint32 offset, uint32 bytes);
+
+bool
+aot_compiler_op_atomic_fence(AOTCompContext *comp_ctx,
+                             AOTFuncContext *func_ctx);
 #endif
 
 #ifdef __cplusplus

+ 24 - 1
core/iwasm/compilation/aot_llvm.c

@@ -286,6 +286,21 @@ create_native_stack_bound(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
     return true;
 }
 
+static bool
+create_native_stack_top_min(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
+{
+    LLVMValueRef offset = I32_NINE;
+
+    if (!(func_ctx->native_stack_top_min_addr = LLVMBuildInBoundsGEP2(
+              comp_ctx->builder, OPQ_PTR_TYPE, func_ctx->exec_env, &offset, 1,
+              "native_stack_top_min_addr"))) {
+        aot_set_last_error("llvm build in bounds gep failed");
+        return false;
+    }
+
+    return true;
+}
+
 static bool
 create_aux_stack_info(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
 {
@@ -434,7 +449,8 @@ create_local_variables(AOTCompData *comp_data, AOTCompContext *comp_ctx,
         }
     }
 
-    if (comp_ctx->enable_stack_bound_check) {
+    if (comp_ctx->enable_stack_bound_check
+        || comp_ctx->enable_stack_estimation) {
         if (aot_func_type->param_count + func->local_count > 0) {
             func_ctx->last_alloca = func_ctx->locals[aot_func_type->param_count
                                                      + func->local_count - 1];
@@ -963,6 +979,10 @@ aot_create_func_context(AOTCompData *comp_data, AOTCompContext *comp_ctx,
         && !create_native_stack_bound(comp_ctx, func_ctx)) {
         goto fail;
     }
+    if (comp_ctx->enable_stack_estimation
+        && !create_native_stack_top_min(comp_ctx, func_ctx)) {
+        goto fail;
+    }
 
     /* Get auxiliary stack info */
     if (wasm_func->has_op_set_global_aux_stack
@@ -1622,6 +1642,9 @@ aot_create_comp_context(AOTCompData *comp_data, aot_comp_option_t option)
     if (option->disable_llvm_lto)
         comp_ctx->disable_llvm_lto = true;
 
+    if (option->enable_stack_estimation)
+        comp_ctx->enable_stack_estimation = true;
+
     comp_ctx->opt_level = option->opt_level;
     comp_ctx->size_level = option->size_level;
 

+ 5 - 0
core/iwasm/compilation/aot_llvm.h

@@ -163,6 +163,7 @@ typedef struct AOTFuncContext {
     LLVMValueRef aot_inst;
     LLVMValueRef argv_buf;
     LLVMValueRef native_stack_bound;
+    LLVMValueRef native_stack_top_min_addr;
     LLVMValueRef aux_stack_bound;
     LLVMValueRef aux_stack_bottom;
     LLVMValueRef native_symbol;
@@ -313,6 +314,9 @@ typedef struct AOTCompContext {
     /* Native stack bounday Check */
     bool enable_stack_bound_check;
 
+    /* Native stack usage estimation */
+    bool enable_stack_estimation;
+
     /* 128-bit SIMD */
     bool enable_simd;
 
@@ -403,6 +407,7 @@ typedef struct AOTCompOption {
     bool enable_aux_stack_frame;
     bool disable_llvm_intrinsics;
     bool disable_llvm_lto;
+    bool enable_stack_estimation;
     uint32 opt_level;
     uint32 size_level;
     uint32 output_format;

+ 92 - 1
core/iwasm/fast-jit/fe/jit_emit_memory.c

@@ -135,7 +135,8 @@ check_and_seek(JitCompContext *cc, JitReg addr, uint32 offset, uint32 bytes)
 #ifndef OS_ENABLE_HW_BOUND_CHECK
     /* ---------- check ---------- */
     /* 1. shortcut if the memory size is 0 */
-    if (0 == cc->cur_wasm_module->memories[mem_idx].init_page_count) {
+    if (cc->cur_wasm_module->memories != NULL
+        && 0 == cc->cur_wasm_module->memories[mem_idx].init_page_count) {
         JitReg module_inst, cur_page_count;
         uint32 cur_page_count_offset =
             (uint32)offsetof(WASMModuleInstance, global_table_data.bytes)
@@ -176,6 +177,18 @@ fail:
     return 0;
 }
 
+#define CHECK_ALIGNMENT(maddr, memory_data, offset1)                   \
+    do {                                                               \
+        GEN_INSN(ADD, maddr, memory_data, offset1);                    \
+        JitReg align_mask = NEW_CONST(I64, ((uint64)1 << align) - 1);  \
+        JitReg AND_res = jit_cc_new_reg_I64(cc);                       \
+        GEN_INSN(AND, AND_res, maddr, align_mask);                     \
+        GEN_INSN(CMP, cc->cmp_reg, AND_res, NEW_CONST(I64, 0));        \
+        if (!jit_emit_exception(cc, EXCE_UNALIGNED_ATOMIC, JIT_OP_BNE, \
+                                cc->cmp_reg, NULL))                    \
+            goto fail;                                                 \
+    } while (0)
+
 bool
 jit_compile_op_i32_load(JitCompContext *cc, uint32 align, uint32 offset,
                         uint32 bytes, bool sign, bool atomic)
@@ -779,6 +792,51 @@ bool
 jit_compile_op_atomic_wait(JitCompContext *cc, uint8 op_type, uint32 align,
                            uint32 offset, uint32 bytes)
 {
+    bh_assert(op_type == VALUE_TYPE_I32 || op_type == VALUE_TYPE_I64);
+
+    // Pop atomic.wait arguments
+    JitReg timeout, expect, expect_64, addr;
+    POP_I64(timeout);
+    if (op_type == VALUE_TYPE_I32) {
+        POP_I32(expect);
+        expect_64 = jit_cc_new_reg_I64(cc);
+        GEN_INSN(I32TOI64, expect_64, expect);
+    }
+    else {
+        POP_I64(expect_64);
+    }
+    POP_I32(addr);
+
+    // Get referenced address and store it in `maddr`
+    JitReg memory_data = get_memory_data_reg(cc->jit_frame, 0);
+    JitReg offset1 = check_and_seek(cc, addr, offset, bytes);
+    if (!offset1)
+        goto fail;
+    JitReg maddr = jit_cc_new_reg_I64(cc);
+    CHECK_ALIGNMENT(maddr, memory_data, offset1);
+
+    // Prepare `wasm_runtime_atomic_wait` arguments
+    JitReg res = jit_cc_new_reg_I32(cc);
+    JitReg args[5] = { 0 };
+    args[0] = get_module_inst_reg(cc->jit_frame);
+    args[1] = maddr;
+    args[2] = expect_64;
+    args[3] = timeout;
+    args[4] = NEW_CONST(I32, false);
+
+    if (!jit_emit_callnative(cc, wasm_runtime_atomic_wait, res, args,
+                             sizeof(args) / sizeof(args[0])))
+        goto fail;
+
+    // Handle return code
+    GEN_INSN(CMP, cc->cmp_reg, res, NEW_CONST(I32, -1));
+    if (!jit_emit_exception(cc, EXCE_ALREADY_THROWN, JIT_OP_BEQ, cc->cmp_reg,
+                            NULL))
+        goto fail;
+
+    PUSH_I32(res);
+    return true;
+fail:
     return false;
 }
 
@@ -786,6 +844,39 @@ bool
 jit_compiler_op_atomic_notify(JitCompContext *cc, uint32 align, uint32 offset,
                               uint32 bytes)
 {
+    // Pop atomic.notify arguments
+    JitReg notify_count, addr;
+    POP_I32(notify_count);
+    POP_I32(addr);
+
+    // Get referenced address and store it in `maddr`
+    JitReg memory_data = get_memory_data_reg(cc->jit_frame, 0);
+    JitReg offset1 = check_and_seek(cc, addr, offset, bytes);
+    if (!offset1)
+        goto fail;
+    JitReg maddr = jit_cc_new_reg_I64(cc);
+    CHECK_ALIGNMENT(maddr, memory_data, offset1);
+
+    // Prepare `wasm_runtime_atomic_notify` arguments
+    JitReg res = jit_cc_new_reg_I32(cc);
+    JitReg args[3] = { 0 };
+    args[0] = get_module_inst_reg(cc->jit_frame);
+    args[1] = maddr;
+    args[2] = notify_count;
+
+    if (!jit_emit_callnative(cc, wasm_runtime_atomic_notify, res, args,
+                             sizeof(args) / sizeof(args[0])))
+        goto fail;
+
+    // Handle return code
+    GEN_INSN(CMP, cc->cmp_reg, res, NEW_CONST(I32, 0));
+    if (!jit_emit_exception(cc, EXCE_ALREADY_THROWN, JIT_OP_BLTS, cc->cmp_reg,
+                            NULL))
+        goto fail;
+
+    PUSH_I32(res);
+    return true;
+fail:
     return false;
 }
 #endif

+ 26 - 4
core/iwasm/fast-jit/jit_codecache.c

@@ -56,9 +56,31 @@ jit_code_cache_free(void *ptr)
 bool
 jit_pass_register_jitted_code(JitCompContext *cc)
 {
-    uint32 jit_func_idx =
-        cc->cur_wasm_func_idx - cc->cur_wasm_module->import_function_count;
-    cc->cur_wasm_module->fast_jit_func_ptrs[jit_func_idx] =
-        cc->cur_wasm_func->fast_jit_jitted_code = cc->jitted_addr_begin;
+    WASMModuleInstance *instance;
+    WASMModule *module = cc->cur_wasm_module;
+    WASMFunction *func = cc->cur_wasm_func;
+    uint32 jit_func_idx = cc->cur_wasm_func_idx - module->import_function_count;
+
+#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \
+    && WASM_ENABLE_LAZY_JIT != 0
+    os_mutex_lock(&module->instance_list_lock);
+#endif
+
+    module->fast_jit_func_ptrs[jit_func_idx] = func->fast_jit_jitted_code =
+        cc->jitted_addr_begin;
+
+#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \
+    && WASM_ENABLE_LAZY_JIT != 0
+    instance = module->instance_list;
+    while (instance) {
+        if (instance->e->running_mode == Mode_Fast_JIT)
+            instance->fast_jit_func_ptrs[jit_func_idx] = cc->jitted_addr_begin;
+        instance = instance->e->next;
+    }
+
+    os_mutex_unlock(&module->instance_list_lock);
+#else
+    (void)instance;
+#endif
     return true;
 }

+ 15 - 3
core/iwasm/fast-jit/jit_compiler.c

@@ -157,8 +157,16 @@ jit_compiler_compile(WASMModule *module, uint32 func_idx)
     /* Apply compiler passes */
     if (!apply_compiler_passes(cc) || jit_get_last_error(cc)) {
         last_error = jit_get_last_error(cc);
+
+#if WASM_ENABLE_CUSTOM_NAME_SECTION != 0
+        char *function_name = cc->cur_wasm_func->field_name;
+        os_printf("fast jit compilation failed: %s (function_name=%s)\n",
+                  last_error ? last_error : "unknown error", function_name);
+#else
         os_printf("fast jit compilation failed: %s\n",
                   last_error ? last_error : "unknown error");
+#endif
+
         goto fail;
     }
 
@@ -246,6 +254,8 @@ jit_compiler_set_call_to_fast_jit(WASMModule *module, uint32 func_idx)
 
     func_ptr = jit_codegen_compile_call_to_fast_jit(module, func_idx);
     if (func_ptr) {
+        uint32 i = func_idx - module->import_function_count;
+        module->functions[i]->call_to_fast_jit_from_llvm_jit = func_ptr;
         jit_compiler_set_llvm_jit_func_ptr(module, func_idx, func_ptr);
     }
 
@@ -259,12 +269,14 @@ jit_compiler_set_llvm_jit_func_ptr(WASMModule *module, uint32 func_idx,
     WASMModuleInstance *instance;
     uint32 i = func_idx - module->import_function_count;
 
-    module->functions[i]->llvm_jit_func_ptr = module->func_ptrs[i] = func_ptr;
-
     os_mutex_lock(&module->instance_list_lock);
+
+    module->func_ptrs[i] = func_ptr;
+
     instance = module->instance_list;
     while (instance) {
-        instance->func_ptrs[func_idx] = func_ptr;
+        if (instance->e->running_mode == Mode_Multi_Tier_JIT)
+            instance->func_ptrs[func_idx] = func_ptr;
         instance = instance->e->next;
     }
     os_mutex_unlock(&module->instance_list_lock);

+ 1 - 1
core/iwasm/fast-jit/jit_frontend.c

@@ -841,7 +841,7 @@ init_func_translation(JitCompContext *cc)
     cc->spill_cache_offset = wasm_interp_interp_frame_size(total_cell_num);
     /* Set spill cache size according to max local cell num, max stack cell
        num and virtual fixed register num */
-    cc->spill_cache_size = (max_locals + max_stacks) * 4 + sizeof(void *) * 5;
+    cc->spill_cache_size = (max_locals + max_stacks) * 4 + sizeof(void *) * 16;
     cc->total_frame_size = cc->spill_cache_offset + cc->spill_cache_size;
     cc->jitted_return_address_offset =
         offsetof(WASMInterpFrame, jitted_return_addr);

+ 2 - 0
core/iwasm/fast-jit/jit_ir.c

@@ -560,6 +560,7 @@ address_of_const(JitCompContext *cc, JitReg reg, unsigned size)
     unsigned no = jit_reg_no(reg);
     unsigned idx = no & ~_JIT_REG_CONST_IDX_FLAG;
 
+    bh_assert(kind < JIT_REG_KIND_L32);
     bh_assert(jit_reg_is_const_idx(reg) && idx < cc->_const_val._num[kind]);
 
     return cc->_const_val._value[kind] + size * idx;
@@ -572,6 +573,7 @@ next_of_const(JitCompContext *cc, JitReg reg)
     unsigned no = jit_reg_no(reg);
     unsigned idx = no & ~_JIT_REG_CONST_IDX_FLAG;
 
+    bh_assert(kind < JIT_REG_KIND_L32);
     bh_assert(jit_reg_is_const_idx(reg) && idx < cc->_const_val._num[kind]);
 
     return cc->_const_val._next[kind][idx];

+ 4 - 0
core/iwasm/fast-jit/jit_ir.h

@@ -1688,6 +1688,7 @@ jit_cc_is_hreg(JitCompContext *cc, JitReg reg)
     unsigned kind = jit_reg_kind(reg);
     unsigned no = jit_reg_no(reg);
     bh_assert(jit_reg_is_variable(reg));
+    bh_assert(kind < JIT_REG_KIND_L32);
     return no < cc->hreg_info->info[kind].num;
 }
 
@@ -1705,6 +1706,7 @@ jit_cc_is_hreg_fixed(JitCompContext *cc, JitReg reg)
     unsigned kind = jit_reg_kind(reg);
     unsigned no = jit_reg_no(reg);
     bh_assert(jit_cc_is_hreg(cc, reg));
+    bh_assert(kind < JIT_REG_KIND_L32);
     return !!cc->hreg_info->info[kind].fixed[no];
 }
 
@@ -1722,6 +1724,7 @@ jit_cc_is_hreg_caller_saved_native(JitCompContext *cc, JitReg reg)
     unsigned kind = jit_reg_kind(reg);
     unsigned no = jit_reg_no(reg);
     bh_assert(jit_cc_is_hreg(cc, reg));
+    bh_assert(kind < JIT_REG_KIND_L32);
     return !!cc->hreg_info->info[kind].caller_saved_native[no];
 }
 
@@ -1739,6 +1742,7 @@ jit_cc_is_hreg_caller_saved_jitted(JitCompContext *cc, JitReg reg)
     unsigned kind = jit_reg_kind(reg);
     unsigned no = jit_reg_no(reg);
     bh_assert(jit_cc_is_hreg(cc, reg));
+    bh_assert(kind < JIT_REG_KIND_L32);
     return !!cc->hreg_info->info[kind].caller_saved_jitted[no];
 }
 

+ 11 - 3
core/iwasm/fast-jit/jit_regalloc.c

@@ -156,6 +156,7 @@ rc_get_vr(RegallocContext *rc, JitReg vreg)
     unsigned no = jit_reg_no(vreg);
 
     bh_assert(jit_reg_is_variable(vreg));
+    bh_assert(kind < JIT_REG_KIND_L32);
 
     return &rc->vregs[kind][no];
 }
@@ -175,6 +176,7 @@ rc_get_hr(RegallocContext *rc, JitReg hreg)
     unsigned no = jit_reg_no(hreg);
 
     bh_assert(jit_reg_is_variable(hreg) && jit_cc_is_hreg(rc->cc, hreg));
+    bh_assert(kind < JIT_REG_KIND_L32);
 
     return &rc->hregs[kind][no];
 }
@@ -208,7 +210,9 @@ static unsigned
 get_reg_stride(JitReg reg)
 {
     static const uint8 strides[] = { 0, 1, 2, 1, 2, 2, 4, 8, 0 };
-    return strides[jit_reg_kind(reg)];
+    uint32 kind = jit_reg_kind(reg);
+    bh_assert(kind <= JIT_REG_KIND_L32);
+    return strides[kind];
 }
 
 /**
@@ -582,13 +586,17 @@ static JitReg
 allocate_hreg(RegallocContext *rc, JitReg vreg, JitInsn *insn, int distance)
 {
     const int kind = jit_reg_kind(vreg);
-    const HardReg *hregs = rc->hregs[kind];
-    const unsigned hreg_num = jit_cc_hreg_num(rc->cc, kind);
+    const HardReg *hregs;
+    unsigned hreg_num;
     JitReg hreg, vreg_to_reload = 0;
     int min_distance = distance, vr_distance;
     VirtualReg *vr = rc_get_vr(rc, vreg);
     unsigned i;
 
+    bh_assert(kind < JIT_REG_KIND_L32);
+    hregs = rc->hregs[kind];
+    hreg_num = jit_cc_hreg_num(rc->cc, kind);
+
     if (hreg_num == 0)
     /* Unsupported hard register kind.  */
     {

+ 1 - 0
core/iwasm/include/aot_export.h

@@ -55,6 +55,7 @@ typedef struct AOTCompOption {
     bool enable_aux_stack_frame;
     bool disable_llvm_intrinsics;
     bool disable_llvm_lto;
+    bool enable_stack_estimation;
     uint32_t opt_level;
     uint32_t size_level;
     uint32_t output_format;

+ 4 - 0
core/iwasm/include/wasm_c_api.h

@@ -354,6 +354,7 @@ WASM_API_EXTERN own wasm_importtype_t* wasm_importtype_new(
 WASM_API_EXTERN const wasm_name_t* wasm_importtype_module(const wasm_importtype_t*);
 WASM_API_EXTERN const wasm_name_t* wasm_importtype_name(const wasm_importtype_t*);
 WASM_API_EXTERN const wasm_externtype_t* wasm_importtype_type(const wasm_importtype_t*);
+WASM_API_EXTERN bool wasm_importtype_is_linked(const wasm_importtype_t*);
 
 
 // Export Types
@@ -797,6 +798,9 @@ static inline void* wasm_val_ptr(const wasm_val_t* val) {
 
 #define KILOBYTE(n) ((n) * 1024)
 
+// Create placeholders filled in `wasm_externvec_t* imports` for `wasm_instance_new()`
+WASM_API_EXTERN wasm_extern_t *wasm_extern_new_empty(wasm_store_t *,  wasm_externkind_t);
+
 ///////////////////////////////////////////////////////////////////////////////
 
 #undef own

+ 109 - 3
core/iwasm/include/wasm_export.h

@@ -131,6 +131,14 @@ typedef struct mem_alloc_info_t {
     uint32_t highmark_size;
 } mem_alloc_info_t;
 
+/* Running mode of runtime and module instance*/
+typedef enum RunningMode {
+    Mode_Interp = 1,
+    Mode_Fast_JIT,
+    Mode_LLVM_JIT,
+    Mode_Multi_Tier_JIT,
+} RunningMode;
+
 /* WASM runtime initialize arguments */
 typedef struct RuntimeInitArgs {
     mem_alloc_type_t mem_alloc_type;
@@ -152,6 +160,13 @@ typedef struct RuntimeInitArgs {
 
     /* Fast JIT code cache size */
     uint32_t fast_jit_code_cache_size;
+
+    /* Default running mode of the runtime */
+    RunningMode running_mode;
+
+    /* LLVM JIT opt and size level */
+    uint32_t llvm_jit_opt_level;
+    uint32_t llvm_jit_size_level;
 } RuntimeInitArgs;
 
 #ifndef WASM_VALKIND_T_DEFINED
@@ -195,9 +210,9 @@ WASM_RUNTIME_API_EXTERN bool
 wasm_runtime_init(void);
 
 /**
- * Initialize the WASM runtime environment, and also initialize
- * the memory allocator and register native symbols, which are specified
- * with init arguments
+ * Initialize the WASM runtime environment, WASM running mode,
+ * and also initialize the memory allocator and register native symbols,
+ * which are specified with init arguments
  *
  * @param init_args specifies the init arguments
  *
@@ -206,6 +221,28 @@ wasm_runtime_init(void);
 WASM_RUNTIME_API_EXTERN bool
 wasm_runtime_full_init(RuntimeInitArgs *init_args);
 
+/**
+ * Query whether a certain running mode is supported for the runtime
+ *
+ * @param running_mode the running mode to query
+ *
+ * @return true if this running mode is supported, false otherwise
+ */
+WASM_RUNTIME_API_EXTERN bool
+wasm_runtime_is_running_mode_supported(RunningMode running_mode);
+
+/**
+ * Set the default running mode for the runtime. It is inherited
+ * to set the running mode of a module instance when it is instantiated,
+ * and can be changed by calling wasm_runtime_set_running_mode
+ *
+ * @param running_mode the running mode to set
+ *
+ * @return true if success, false otherwise
+ */
+WASM_RUNTIME_API_EXTERN bool
+wasm_runtime_set_default_running_mode(RunningMode running_mode);
+
 /**
  * Destroy the WASM runtime environment.
  */
@@ -450,6 +487,34 @@ wasm_runtime_instantiate(const wasm_module_t module,
                          uint32_t stack_size, uint32_t heap_size,
                          char *error_buf, uint32_t error_buf_size);
 
+/**
+ * Set the running mode of a WASM module instance, override the
+ * default running mode of the runtime. Note that it only makes sense when
+ * the input is a wasm bytecode file: for the AOT file, runtime always runs
+ * it with AOT engine, and this function always returns true.
+ *
+ * @param module_inst the WASM module instance to set running mode
+ * @param running_mode the running mode to set
+ *
+ * @return true if success, false otherwise
+ */
+WASM_RUNTIME_API_EXTERN bool
+wasm_runtime_set_running_mode(wasm_module_inst_t module_inst,
+                              RunningMode running_mode);
+
+/**
+ * Get the running mode of a WASM module instance, if no running mode
+ * is explicitly set the default running mode of runtime will
+ * be used and returned. Note that it only makes sense when the input is a
+ * wasm bytecode file: for the AOT file, this function always returns 0.
+ *
+ * @param module_inst the WASM module instance to query for running mode
+ *
+ * @return the running mode this module instance currently use
+ */
+WASM_RUNTIME_API_EXTERN RunningMode
+wasm_runtime_get_running_mode(wasm_module_inst_t module_inst);
+
 /**
  * Deinstantiate a WASM module instance, destroy the resources.
  *
@@ -735,6 +800,31 @@ wasm_runtime_call_wasm_v(wasm_exec_env_t exec_env,
                          uint32_t num_results, wasm_val_t results[],
                          uint32_t num_args, ...);
 
+/**
+ * Call a function reference of a given WASM runtime instance with
+ * arguments.
+ *
+ * Note: this can be used to call a function which is not exported
+ * by the module explicitly. You might consider it as an abstraction
+ * violation.
+ *
+ * @param exec_env the execution environment to call the function
+ *   which must be created from wasm_create_exec_env()
+ * @param element_index the function reference index, usually
+ *   prvovided by the caller of a registed native function
+ * @param argc the number of arguments
+ * @param argv the arguments.  If the function method has return value,
+ *   the first (or first two in case 64-bit return value) element of
+ *   argv stores the return value of the called WASM function after this
+ *   function returns.
+ *
+ * @return true if success, false otherwise and exception will be thrown,
+ *   the caller can call wasm_runtime_get_exception to get exception info.
+ */
+WASM_RUNTIME_API_EXTERN bool
+wasm_runtime_call_indirect(wasm_exec_env_t exec_env, uint32_t element_index,
+                           uint32_t argc, uint32_t argv[]);
+
 /**
  * Find the unique main function from a WASM module instance
  * and execute that function.
@@ -1259,6 +1349,22 @@ wasm_runtime_get_custom_section(wasm_module_t const module_comm,
  */
 WASM_RUNTIME_API_EXTERN void
 wasm_runtime_get_version(uint32_t *major, uint32_t *minor, uint32_t *patch);
+
+/**
+ * Check whether an import func `(import <module_name> <func_name> (func ...))` is linked or not
+ * with runtime registered natvie functions
+ */
+WASM_RUNTIME_API_EXTERN bool
+wasm_runtime_is_import_func_linked(const char *module_name,
+                                   const char *func_name);
+
+/**
+ * Check whether an import global `(import <module_name> <global_name> (global ...))` is linked or not
+ * with runtime registered natvie globals
+ */
+WASM_RUNTIME_API_EXTERN bool
+wasm_runtime_is_import_global_linked(const char *module_name,
+                                     const char *global_name);
 /* clang-format on */
 
 #ifdef __cplusplus

+ 40 - 6
core/iwasm/interpreter/wasm.h

@@ -278,9 +278,14 @@ struct WASMFunction {
 #endif
 
 #if WASM_ENABLE_FAST_JIT != 0
+    /* The compiled fast jit jitted code block of this function */
     void *fast_jit_jitted_code;
 #if WASM_ENABLE_JIT != 0 && WASM_ENABLE_LAZY_JIT != 0
+    /* The compiled llvm jit func ptr of this function */
     void *llvm_jit_func_ptr;
+    /* Code block to call fast jit jitted code of this function
+       from the llvm jit jitted code */
+    void *call_to_fast_jit_from_llvm_jit;
 #endif
 #endif
 };
@@ -505,15 +510,14 @@ struct WASMModule {
     uint64 load_size;
 #endif
 
-#if WASM_ENABLE_DEBUG_INTERP != 0                    \
-    || (WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT \
+#if WASM_ENABLE_DEBUG_INTERP != 0                         \
+    || (WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \
         && WASM_ENABLE_LAZY_JIT != 0)
     /**
      * List of instances referred to this module. When source debugging
      * feature is enabled, the debugger may modify the code section of
      * the module, so we need to report a warning if user create several
-     * instances based on the same module. Sub instances created by
-     * lib-pthread or spawn API won't be added into the list.
+     * instances based on the same module.
      *
      * Also add the instance to the list for Fast JIT to LLVM JIT
      * tier-up, since we need to lazily update the LLVM func pointers
@@ -533,7 +537,22 @@ struct WASMModule {
 #endif
 
 #if WASM_ENABLE_FAST_JIT != 0
-    /* func pointers of Fast JITed (un-imported) functions */
+    /**
+     * func pointers of Fast JITed (un-imported) functions
+     * for non Multi-Tier JIT mode:
+     *   (1) when lazy jit is disabled, each pointer is set to the compiled
+     *       fast jit jitted code
+     *   (2) when lazy jit is enabled, each pointer is firstly inited as
+     *       jit_global->compile_fast_jit_and_then_call, and then set to the
+     *       compiled fast jit jitted code when it is called (the stub will
+     *       compile the jit function and then update itself)
+     * for Multi-Tier JIT mode:
+     *   each pointer is firstly inited as compile_fast_jit_and_then_call,
+     *   and then set to the compiled fast jit jitted code when it is called,
+     *   and when the llvm jit func ptr of the same function is compiled, it
+     *   will be set to call_to_llvm_jit_from_fast_jit of this function type
+     *   (tier-up from fast-jit to llvm-jit)
+     */
     void **fast_jit_func_ptrs;
     /* locks for Fast JIT lazy compilation */
     korp_mutex fast_jit_thread_locks[WASM_ORC_JIT_BACKEND_THREAD_NUM];
@@ -543,7 +562,16 @@ struct WASMModule {
 #if WASM_ENABLE_JIT != 0
     struct AOTCompData *comp_data;
     struct AOTCompContext *comp_ctx;
-    /* func pointers of LLVM JITed (un-imported) functions */
+    /**
+     * func pointers of LLVM JITed (un-imported) functions
+     * for non Multi-Tier JIT mode:
+     *   each pointer is set to the lookuped llvm jit func ptr, note that it
+     *   is a stub and will trigger the actual compilation when it is called
+     * for Multi-Tier JIT mode:
+     *   each pointer is inited as call_to_fast_jit code block, when the llvm
+     *   jit func ptr is actually compiled, it is set to the compiled llvm jit
+     *   func ptr
+     */
     void **func_ptrs;
     /* whether the func pointers are compiled */
     bool *func_ptrs_compiled;
@@ -568,6 +596,12 @@ struct WASMModule {
     korp_tid llvm_jit_init_thread;
     /* whether the llvm jit is initialized */
     bool llvm_jit_inited;
+    /* Whether to enable llvm jit compilation:
+       it is set to true only when there is a module instance starts to
+       run with running mode Mode_LLVM_JIT or Mode_Multi_Tier_JIT,
+       since no need to enable llvm jit compilation for Mode_Interp and
+       Mode_Fast_JIT, so as to improve performance for them */
+    bool enable_llvm_jit_compilation;
 #endif
 };
 

+ 138 - 149
core/iwasm/interpreter/wasm_interp_classic.c

@@ -8,6 +8,7 @@
 #include "wasm_runtime.h"
 #include "wasm_opcode.h"
 #include "wasm_loader.h"
+#include "wasm_memory.h"
 #include "../common/wasm_exec_env.h"
 #if WASM_ENABLE_SHARED_MEMORY != 0
 #include "../common/wasm_shared_memory.h"
@@ -696,28 +697,28 @@ trunc_f64_to_int(WASMModuleInstance *module, uint32 *frame_sp, float64 src_min,
             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);     \
             CHECK_ATOMIC_MEMORY_ACCESS();                            \
                                                                      \
-            os_mutex_lock(&module->e->mem_lock);                     \
+            os_mutex_lock(&node->shared_mem_lock);                   \
             readv = (uint32)(*(uint8 *)maddr);                       \
             *(uint8 *)maddr = (uint8)(readv op sval);                \
-            os_mutex_unlock(&module->e->mem_lock);                   \
+            os_mutex_unlock(&node->shared_mem_lock);                 \
         }                                                            \
         else if (opcode == WASM_OP_ATOMIC_RMW_I32_##OP_NAME##16_U) { \
             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);     \
             CHECK_ATOMIC_MEMORY_ACCESS();                            \
                                                                      \
-            os_mutex_lock(&module->e->mem_lock);                     \
+            os_mutex_lock(&node->shared_mem_lock);                   \
             readv = (uint32)LOAD_U16(maddr);                         \
             STORE_U16(maddr, (uint16)(readv op sval));               \
-            os_mutex_unlock(&module->e->mem_lock);                   \
+            os_mutex_unlock(&node->shared_mem_lock);                 \
         }                                                            \
         else {                                                       \
             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);     \
             CHECK_ATOMIC_MEMORY_ACCESS();                            \
                                                                      \
-            os_mutex_lock(&module->e->mem_lock);                     \
+            os_mutex_lock(&node->shared_mem_lock);                   \
             readv = LOAD_I32(maddr);                                 \
             STORE_U32(maddr, readv op sval);                         \
-            os_mutex_unlock(&module->e->mem_lock);                   \
+            os_mutex_unlock(&node->shared_mem_lock);                 \
         }                                                            \
         PUSH_I32(readv);                                             \
         break;                                                       \
@@ -736,39 +737,39 @@ trunc_f64_to_int(WASMModuleInstance *module, uint32 *frame_sp, float64 src_min,
             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);     \
             CHECK_ATOMIC_MEMORY_ACCESS();                            \
                                                                      \
-            os_mutex_lock(&module->e->mem_lock);                     \
+            os_mutex_lock(&node->shared_mem_lock);                   \
             readv = (uint64)(*(uint8 *)maddr);                       \
             *(uint8 *)maddr = (uint8)(readv op sval);                \
-            os_mutex_unlock(&module->e->mem_lock);                   \
+            os_mutex_unlock(&node->shared_mem_lock);                 \
         }                                                            \
         else if (opcode == WASM_OP_ATOMIC_RMW_I64_##OP_NAME##16_U) { \
             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);     \
             CHECK_ATOMIC_MEMORY_ACCESS();                            \
                                                                      \
-            os_mutex_lock(&module->e->mem_lock);                     \
+            os_mutex_lock(&node->shared_mem_lock);                   \
             readv = (uint64)LOAD_U16(maddr);                         \
             STORE_U16(maddr, (uint16)(readv op sval));               \
-            os_mutex_unlock(&module->e->mem_lock);                   \
+            os_mutex_unlock(&node->shared_mem_lock);                 \
         }                                                            \
         else if (opcode == WASM_OP_ATOMIC_RMW_I64_##OP_NAME##32_U) { \
             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);     \
             CHECK_ATOMIC_MEMORY_ACCESS();                            \
                                                                      \
-            os_mutex_lock(&module->e->mem_lock);                     \
+            os_mutex_lock(&node->shared_mem_lock);                   \
             readv = (uint64)LOAD_U32(maddr);                         \
             STORE_U32(maddr, (uint32)(readv op sval));               \
-            os_mutex_unlock(&module->e->mem_lock);                   \
+            os_mutex_unlock(&node->shared_mem_lock);                 \
         }                                                            \
         else {                                                       \
             uint64 op_result;                                        \
             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr);     \
             CHECK_ATOMIC_MEMORY_ACCESS();                            \
                                                                      \
-            os_mutex_lock(&module->e->mem_lock);                     \
+            os_mutex_lock(&node->shared_mem_lock);                   \
             readv = (uint64)LOAD_I64(maddr);                         \
             op_result = readv op sval;                               \
             STORE_I64(maddr, op_result);                             \
-            os_mutex_unlock(&module->e->mem_lock);                   \
+            os_mutex_unlock(&node->shared_mem_lock);                 \
         }                                                            \
         PUSH_I64(readv);                                             \
         break;                                                       \
@@ -891,7 +892,7 @@ wasm_interp_call_func_native(WASMModuleInstance *module_inst,
     if (!func_import->call_conv_wasm_c_api) {
         native_func_pointer = module_inst->import_func_ptrs[cur_func_index];
     }
-    else {
+    else if (module_inst->e->c_api_func_imports) {
         c_api_func_import = module_inst->e->c_api_func_imports + cur_func_index;
         native_func_pointer = c_api_func_import->func_ptr_linked;
     }
@@ -954,7 +955,7 @@ fast_jit_invoke_native(WASMExecEnv *exec_env, uint32 func_idx,
     WASMFunctionInstance *cur_func = module_inst->e->functions + func_idx;
 
     wasm_interp_call_func_native(module_inst, exec_env, cur_func, prev_frame);
-    return wasm_get_exception(module_inst) ? false : true;
+    return wasm_copy_exception(module_inst, NULL) ? false : true;
 }
 #endif
 
@@ -1023,7 +1024,7 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst,
     exec_env->module_inst = (WASMModuleInstanceCommon *)module_inst;
 
     /* transfer exception if it is thrown */
-    if (wasm_get_exception(sub_module_inst)) {
+    if (wasm_copy_exception(sub_module_inst, NULL)) {
         bh_memcpy_s(module_inst->cur_exception,
                     sizeof(module_inst->cur_exception),
                     sub_module_inst->cur_exception,
@@ -1036,21 +1037,25 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst,
 #if WASM_ENABLE_DEBUG_INTERP != 0
 #define CHECK_SUSPEND_FLAGS()                                          \
     do {                                                               \
+        os_mutex_lock(&exec_env->wait_lock);                           \
         if (IS_WAMR_TERM_SIG(exec_env->current_status->signal_flag)) { \
+            os_mutex_unlock(&exec_env->wait_lock);                     \
             return;                                                    \
         }                                                              \
         if (IS_WAMR_STOP_SIG(exec_env->current_status->signal_flag)) { \
             SYNC_ALL_TO_FRAME();                                       \
-            wasm_cluster_thread_stopped(exec_env);                     \
             wasm_cluster_thread_waiting_run(exec_env);                 \
         }                                                              \
+        os_mutex_unlock(&exec_env->wait_lock);                         \
     } while (0)
 #else
 #define CHECK_SUSPEND_FLAGS()                                             \
     do {                                                                  \
+        os_mutex_lock(&exec_env->wait_lock);                              \
         if (exec_env->suspend_flags.flags != 0) {                         \
             if (exec_env->suspend_flags.flags & 0x01) {                   \
                 /* terminate current thread */                            \
+                os_mutex_unlock(&exec_env->wait_lock);                    \
                 return;                                                   \
             }                                                             \
             while (exec_env->suspend_flags.flags & 0x02) {                \
@@ -1058,6 +1063,7 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst,
                 os_cond_wait(&exec_env->wait_cond, &exec_env->wait_lock); \
             }                                                             \
         }                                                                 \
+        os_mutex_unlock(&exec_env->wait_lock);                            \
     } while (0)
 #endif /* WASM_ENABLE_DEBUG_INTERP */
 #endif /* WASM_ENABLE_THREAD_MGR */
@@ -1077,7 +1083,6 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst,
                && exec_env->current_status->step_count++ == 1) {          \
             exec_env->current_status->step_count = 0;                     \
             SYNC_ALL_TO_FRAME();                                          \
-            wasm_cluster_thread_stopped(exec_env);                        \
             wasm_cluster_thread_waiting_run(exec_env);                    \
         }                                                                 \
         goto *handle_table[*frame_ip++];                                  \
@@ -1094,7 +1099,6 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst,
         && exec_env->current_status->step_count++ == 2) {          \
         exec_env->current_status->step_count = 0;                  \
         SYNC_ALL_TO_FRAME();                                       \
-        wasm_cluster_thread_stopped(exec_env);                     \
         wasm_cluster_thread_waiting_run(exec_env);                 \
     }                                                              \
     continue
@@ -1123,14 +1127,22 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                                WASMFunctionInstance *cur_func,
                                WASMInterpFrame *prev_frame)
 {
+#if WASM_ENABLE_SHARED_MEMORY != 0
+    WASMSharedMemNode *node =
+        wasm_module_get_shared_memory((WASMModuleCommon *)module->module);
+#else
+    void *node = NULL;
+#endif
+
     WASMMemoryInstance *memory = wasm_get_default_memory(module);
     uint8 *global_data = module->global_data;
 #if !defined(OS_ENABLE_HW_BOUND_CHECK)              \
     || WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \
     || WASM_ENABLE_BULK_MEMORY != 0
-    uint32 num_bytes_per_page = memory ? memory->num_bytes_per_page : 0;
+    uint32 num_bytes_per_page =
+        memory ? wasm_get_num_bytes_per_page(memory, node) : 0;
     uint32 linear_mem_size =
-        memory ? num_bytes_per_page * memory->cur_page_count : 0;
+        memory ? wasm_get_linear_memory_size(memory, node) : 0;
 #endif
     WASMType **wasm_types = module->module->types;
     WASMGlobalInstance *globals = module->e->globals, *global;
@@ -1365,7 +1377,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
 
             HANDLE_OP(EXT_OP_BR_TABLE_CACHE)
             {
-                BrTableCache *node =
+                BrTableCache *node_cache =
                     bh_list_first_elem(module->module->br_table_cache_list);
                 BrTableCache *node_next;
 
@@ -1374,13 +1386,13 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
 #endif
                 lidx = POP_I32();
 
-                while (node) {
-                    node_next = bh_list_elem_next(node);
-                    if (node->br_table_op_addr == frame_ip - 1) {
-                        depth = node->br_depths[lidx];
+                while (node_cache) {
+                    node_next = bh_list_elem_next(node_cache);
+                    if (node_cache->br_table_op_addr == frame_ip - 1) {
+                        depth = node_cache->br_depths[lidx];
                         goto label_pop_csp_n;
                     }
-                    node = node_next;
+                    node_cache = node_next;
                 }
                 bh_assert(0);
                 HANDLE_OP_END();
@@ -3420,6 +3432,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                         if (ret == (uint32)-1)
                             goto got_exception;
 
+#if WASM_ENABLE_THREAD_MGR != 0
+                        CHECK_SUSPEND_FLAGS();
+#endif
+
                         PUSH_I32(ret);
                         break;
                     }
@@ -3440,6 +3456,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                         if (ret == (uint32)-1)
                             goto got_exception;
 
+#if WASM_ENABLE_THREAD_MGR != 0
+                        CHECK_SUSPEND_FLAGS();
+#endif
+
                         PUSH_I32(ret);
                         break;
                     }
@@ -3447,6 +3467,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                     {
                         /* Skip the memory index */
                         frame_ip++;
+                        os_atomic_thread_fence(os_memory_order_release);
                         break;
                     }
 
@@ -3461,23 +3482,23 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                         if (opcode == WASM_OP_ATOMIC_I32_LOAD8_U) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS();
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             readv = (uint32)(*(uint8 *)maddr);
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         else if (opcode == WASM_OP_ATOMIC_I32_LOAD16_U) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS();
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             readv = (uint32)LOAD_U16(maddr);
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         else {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS();
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             readv = LOAD_I32(maddr);
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
 
                         PUSH_I32(readv);
@@ -3496,30 +3517,30 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                         if (opcode == WASM_OP_ATOMIC_I64_LOAD8_U) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS();
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             readv = (uint64)(*(uint8 *)maddr);
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         else if (opcode == WASM_OP_ATOMIC_I64_LOAD16_U) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS();
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             readv = (uint64)LOAD_U16(maddr);
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         else if (opcode == WASM_OP_ATOMIC_I64_LOAD32_U) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS();
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             readv = (uint64)LOAD_U32(maddr);
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         else {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS();
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             readv = LOAD_I64(maddr);
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
 
                         PUSH_I64(readv);
@@ -3538,23 +3559,23 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                         if (opcode == WASM_OP_ATOMIC_I32_STORE8) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS();
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             *(uint8 *)maddr = (uint8)sval;
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         else if (opcode == WASM_OP_ATOMIC_I32_STORE16) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS();
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             STORE_U16(maddr, (uint16)sval);
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         else {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS();
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             STORE_U32(maddr, frame_sp[1]);
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         break;
                     }
@@ -3572,31 +3593,31 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                         if (opcode == WASM_OP_ATOMIC_I64_STORE8) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS();
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             *(uint8 *)maddr = (uint8)sval;
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         else if (opcode == WASM_OP_ATOMIC_I64_STORE16) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS();
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             STORE_U16(maddr, (uint16)sval);
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         else if (opcode == WASM_OP_ATOMIC_I64_STORE32) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS();
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             STORE_U32(maddr, (uint32)sval);
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         else {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS();
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             PUT_I64_TO_ADDR((uint32 *)maddr,
                                             GET_I64_FROM_ADDR(frame_sp + 1));
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         break;
                     }
@@ -3616,32 +3637,32 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                             CHECK_ATOMIC_MEMORY_ACCESS();
 
                             expect = (uint8)expect;
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             readv = (uint32)(*(uint8 *)maddr);
                             if (readv == expect)
                                 *(uint8 *)maddr = (uint8)(sval);
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         else if (opcode == WASM_OP_ATOMIC_RMW_I32_CMPXCHG16_U) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS();
 
                             expect = (uint16)expect;
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             readv = (uint32)LOAD_U16(maddr);
                             if (readv == expect)
                                 STORE_U16(maddr, (uint16)(sval));
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         else {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS();
 
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             readv = LOAD_I32(maddr);
                             if (readv == expect)
                                 STORE_U32(maddr, sval);
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         PUSH_I32(readv);
                         break;
@@ -3662,44 +3683,44 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                             CHECK_ATOMIC_MEMORY_ACCESS();
 
                             expect = (uint8)expect;
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             readv = (uint64)(*(uint8 *)maddr);
                             if (readv == expect)
                                 *(uint8 *)maddr = (uint8)(sval);
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         else if (opcode == WASM_OP_ATOMIC_RMW_I64_CMPXCHG16_U) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS();
 
                             expect = (uint16)expect;
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             readv = (uint64)LOAD_U16(maddr);
                             if (readv == expect)
                                 STORE_U16(maddr, (uint16)(sval));
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         else if (opcode == WASM_OP_ATOMIC_RMW_I64_CMPXCHG32_U) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS();
 
                             expect = (uint32)expect;
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             readv = (uint64)LOAD_U32(maddr);
                             if (readv == expect)
                                 STORE_U32(maddr, (uint32)(sval));
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         else {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS();
 
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             readv = (uint64)LOAD_I64(maddr);
                             if (readv == expect) {
                                 STORE_I64(maddr, sval);
                             }
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         PUSH_I64(readv);
                         break;
@@ -3843,7 +3864,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
             if (memory)
                 linear_mem_size = num_bytes_per_page * memory->cur_page_count;
 #endif
-            if (wasm_get_exception(module))
+            if (wasm_copy_exception(module, NULL))
                 goto got_exception;
         }
         else {
@@ -3892,10 +3913,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
             PUSH_CSP(LABEL_TYPE_FUNCTION, 0, cell_num, frame_ip_end - 1);
 
             wasm_exec_env_set_cur_frame(exec_env, frame);
+        }
 #if WASM_ENABLE_THREAD_MGR != 0
-            CHECK_SUSPEND_FLAGS();
+        CHECK_SUSPEND_FLAGS();
 #endif
-        }
         HANDLE_OP_END();
     }
 
@@ -3986,7 +4007,8 @@ fast_jit_call_func_bytecode(WASMModuleInstance *module_inst,
         module_inst->fast_jit_func_ptrs[func_idx_non_import]);
     bh_assert(action == JIT_INTERP_ACTION_NORMAL
               || (action == JIT_INTERP_ACTION_THROWN
-                  && wasm_runtime_get_exception(exec_env->module_inst)));
+                  && wasm_copy_exception(
+                      (WASMModuleInstance *)exec_env->module_inst, NULL)));
 
     /* Get the return values form info.out.ret */
     if (func_type->result_count) {
@@ -4018,24 +4040,6 @@ fast_jit_call_func_bytecode(WASMModuleInstance *module_inst,
 #endif /* end of WASM_ENABLE_FAST_JIT != 0 */
 
 #if WASM_ENABLE_JIT != 0
-static bool
-clear_wasi_proc_exit_exception(WASMModuleInstance *module_inst)
-{
-#if WASM_ENABLE_LIBC_WASI != 0
-    const char *exception = wasm_get_exception(module_inst);
-    if (exception && !strcmp(exception, "Exception: wasi proc exit")) {
-        /* The "wasi proc exit" exception is thrown by native lib to
-           let wasm app exit, which is a normal behavior, we clear
-           the exception here. */
-        wasm_set_exception(module_inst, NULL);
-        return true;
-    }
-    return false;
-#else
-    return false;
-#endif
-}
-
 static bool
 llvm_jit_call_func_bytecode(WASMModuleInstance *module_inst,
                             WASMExecEnv *exec_env,
@@ -4095,14 +4099,6 @@ llvm_jit_call_func_bytecode(WASMModuleInstance *module_inst,
         ret = wasm_runtime_invoke_native(
             exec_env, module_inst->func_ptrs[func_idx], func_type, NULL, NULL,
             argv1, argc, argv);
-
-        if (!ret || wasm_get_exception(module_inst)) {
-            if (clear_wasi_proc_exit_exception(module_inst))
-                ret = true;
-            else
-                ret = false;
-        }
-
         if (!ret) {
             if (argv1 != argv1_buf)
                 wasm_runtime_free(argv1);
@@ -4147,10 +4143,7 @@ llvm_jit_call_func_bytecode(WASMModuleInstance *module_inst,
             exec_env, module_inst->func_ptrs[func_idx], func_type, NULL, NULL,
             argv, argc, argv);
 
-        if (clear_wasi_proc_exit_exception(module_inst))
-            ret = true;
-
-        return ret && !wasm_get_exception(module_inst) ? true : false;
+        return ret && !wasm_copy_exception(module_inst, NULL) ? true : false;
     }
 }
 #endif /* end of WASM_ENABLE_JIT != 0 */
@@ -4170,6 +4163,7 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env,
     unsigned frame_size = wasm_interp_interp_frame_size(all_cell_num);
     unsigned i;
     bool copy_argv_from_frame = true;
+    char exception[EXCEPTION_BUF_LEN];
 
     if (argc < function->param_cell_num) {
         char buf[128];
@@ -4182,6 +4176,7 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env,
     }
     argc = function->param_cell_num;
 
+    RECORD_STACK_USAGE(exec_env, (uint8 *)&prev_frame);
 #if !(defined(OS_ENABLE_HW_BOUND_CHECK) \
       && WASM_DISABLE_STACK_HW_BOUND_CHECK == 0)
     if ((uint8 *)&prev_frame < exec_env->native_stack_boundary) {
@@ -4226,58 +4221,51 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env,
         }
     }
     else {
-#if WASM_ENABLE_LAZY_JIT != 0
+        RunningMode running_mode =
+            wasm_runtime_get_running_mode((wasm_module_inst_t)module_inst);
 
-        /* Fast JIT to LLVM JIT tier-up is enabled */
-#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0
-        /* Fast JIT and LLVM JIT are both enabled, call llvm jit function
-           if it is compiled, else call fast jit function */
-        uint32 func_idx = (uint32)(function - module_inst->e->functions);
-        if (module_inst->module->func_ptrs_compiled
-                [func_idx - module_inst->module->import_function_count]) {
+        if (running_mode == Mode_Interp) {
+            wasm_interp_call_func_bytecode(module_inst, exec_env, function,
+                                           frame);
+        }
+#if WASM_ENABLE_FAST_JIT != 0
+        else if (running_mode == Mode_Fast_JIT) {
+            fast_jit_call_func_bytecode(module_inst, exec_env, function, frame);
+        }
+#endif
+#if WASM_ENABLE_JIT != 0
+        else if (running_mode == Mode_LLVM_JIT) {
             llvm_jit_call_func_bytecode(module_inst, exec_env, function, argc,
                                         argv);
             /* For llvm jit, the results have been stored in argv,
                no need to copy them from stack frame again */
             copy_argv_from_frame = false;
         }
-        else {
-            fast_jit_call_func_bytecode(module_inst, exec_env, function, frame);
-        }
-#elif WASM_ENABLE_JIT != 0
-        /* Only LLVM JIT is enabled */
-        llvm_jit_call_func_bytecode(module_inst, exec_env, function, argc,
-                                    argv);
-        /* For llvm jit, the results have been stored in argv,
-           no need to copy them from stack frame again */
-        copy_argv_from_frame = false;
-#elif WASM_ENABLE_FAST_JIT != 0
-        /* Only Fast JIT is enabled */
-        fast_jit_call_func_bytecode(module_inst, exec_env, function, frame);
-#else
-        /* Both Fast JIT and LLVM JIT are disabled */
-        wasm_interp_call_func_bytecode(module_inst, exec_env, function, frame);
 #endif
-
-#else /* else of WASM_ENABLE_LAZY_JIT != 0 */
-
-        /* Fast JIT to LLVM JIT tier-up is enabled */
-#if WASM_ENABLE_JIT != 0
-        /* LLVM JIT is enabled */
-        llvm_jit_call_func_bytecode(module_inst, exec_env, function, argc,
-                                    argv);
-        /* For llvm jit, the results have been stored in argv,
-           no need to copy them from stack frame again */
-        copy_argv_from_frame = false;
-#elif WASM_ENABLE_FAST_JIT != 0
-        /* Fast JIT is enabled */
-        fast_jit_call_func_bytecode(module_inst, exec_env, function, frame);
-#else
-        /* Both Fast JIT and LLVM JIT are disabled */
-        wasm_interp_call_func_bytecode(module_inst, exec_env, function, frame);
+#if WASM_ENABLE_LAZY_JIT != 0 && WASM_ENABLE_FAST_JIT != 0 \
+    && WASM_ENABLE_JIT != 0
+        else if (running_mode == Mode_Multi_Tier_JIT) {
+            /* Tier-up from Fast JIT to LLVM JIT, call llvm jit function
+               if it is compiled, else call fast jit function */
+            uint32 func_idx = (uint32)(function - module_inst->e->functions);
+            if (module_inst->module->func_ptrs_compiled
+                    [func_idx - module_inst->module->import_function_count]) {
+                llvm_jit_call_func_bytecode(module_inst, exec_env, function,
+                                            argc, argv);
+                /* For llvm jit, the results have been stored in argv,
+                   no need to copy them from stack frame again */
+                copy_argv_from_frame = false;
+            }
+            else {
+                fast_jit_call_func_bytecode(module_inst, exec_env, function,
+                                            frame);
+            }
+        }
 #endif
-
-#endif /* end of WASM_ENABLE_LAZY_JIT != 0 */
+        else {
+            /* There should always be a supported running mode selected */
+            bh_assert(0);
+        }
 
         (void)wasm_interp_call_func_bytecode;
 #if WASM_ENABLE_FAST_JIT != 0
@@ -4286,7 +4274,7 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env,
     }
 
     /* Output the return value to the caller */
-    if (!wasm_get_exception(module_inst)) {
+    if (!wasm_copy_exception(module_inst, NULL)) {
         if (copy_argv_from_frame) {
             for (i = 0; i < function->ret_cell_num; i++) {
                 argv[i] = *(frame->sp + i - function->ret_cell_num);
@@ -4299,7 +4287,8 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env,
             wasm_interp_dump_call_stack(exec_env, true, NULL, 0);
         }
 #endif
-        LOG_DEBUG("meet an exception %s", wasm_get_exception(module_inst));
+        wasm_copy_exception(module_inst, exception);
+        LOG_DEBUG("meet an exception %s", exception);
     }
 
     wasm_exec_env_set_cur_frame(exec_env, prev_frame);

+ 95 - 63
core/iwasm/interpreter/wasm_interp_fast.c

@@ -8,6 +8,7 @@
 #include "wasm_runtime.h"
 #include "wasm_opcode.h"
 #include "wasm_loader.h"
+#include "wasm_memory.h"
 #include "../common/wasm_exec_env.h"
 #if WASM_ENABLE_SHARED_MEMORY != 0
 #include "../common/wasm_shared_memory.h"
@@ -469,28 +470,28 @@ LOAD_PTR(void *addr)
             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);     \
             CHECK_ATOMIC_MEMORY_ACCESS(1);                           \
                                                                      \
-            os_mutex_lock(&module->e->mem_lock);                     \
+            os_mutex_lock(&node->shared_mem_lock);                   \
             readv = (uint32)(*(uint8 *)maddr);                       \
             *(uint8 *)maddr = (uint8)(readv op sval);                \
-            os_mutex_unlock(&module->e->mem_lock);                   \
+            os_mutex_unlock(&node->shared_mem_lock);                 \
         }                                                            \
         else if (opcode == WASM_OP_ATOMIC_RMW_I32_##OP_NAME##16_U) { \
             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);     \
             CHECK_ATOMIC_MEMORY_ACCESS(2);                           \
                                                                      \
-            os_mutex_lock(&module->e->mem_lock);                     \
+            os_mutex_lock(&node->shared_mem_lock);                   \
             readv = (uint32)LOAD_U16(maddr);                         \
             STORE_U16(maddr, (uint16)(readv op sval));               \
-            os_mutex_unlock(&module->e->mem_lock);                   \
+            os_mutex_unlock(&node->shared_mem_lock);                 \
         }                                                            \
         else {                                                       \
             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);     \
             CHECK_ATOMIC_MEMORY_ACCESS(4);                           \
                                                                      \
-            os_mutex_lock(&module->e->mem_lock);                     \
+            os_mutex_lock(&node->shared_mem_lock);                   \
             readv = LOAD_I32(maddr);                                 \
             STORE_U32(maddr, readv op sval);                         \
-            os_mutex_unlock(&module->e->mem_lock);                   \
+            os_mutex_unlock(&node->shared_mem_lock);                 \
         }                                                            \
         PUSH_I32(readv);                                             \
         break;                                                       \
@@ -509,39 +510,39 @@ LOAD_PTR(void *addr)
             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);     \
             CHECK_ATOMIC_MEMORY_ACCESS(1);                           \
                                                                      \
-            os_mutex_lock(&module->e->mem_lock);                     \
+            os_mutex_lock(&node->shared_mem_lock);                   \
             readv = (uint64)(*(uint8 *)maddr);                       \
             *(uint8 *)maddr = (uint8)(readv op sval);                \
-            os_mutex_unlock(&module->e->mem_lock);                   \
+            os_mutex_unlock(&node->shared_mem_lock);                 \
         }                                                            \
         else if (opcode == WASM_OP_ATOMIC_RMW_I64_##OP_NAME##16_U) { \
             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);     \
             CHECK_ATOMIC_MEMORY_ACCESS(2);                           \
                                                                      \
-            os_mutex_lock(&module->e->mem_lock);                     \
+            os_mutex_lock(&node->shared_mem_lock);                   \
             readv = (uint64)LOAD_U16(maddr);                         \
             STORE_U16(maddr, (uint16)(readv op sval));               \
-            os_mutex_unlock(&module->e->mem_lock);                   \
+            os_mutex_unlock(&node->shared_mem_lock);                 \
         }                                                            \
         else if (opcode == WASM_OP_ATOMIC_RMW_I64_##OP_NAME##32_U) { \
             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);     \
             CHECK_ATOMIC_MEMORY_ACCESS(4);                           \
                                                                      \
-            os_mutex_lock(&module->e->mem_lock);                     \
+            os_mutex_lock(&node->shared_mem_lock);                   \
             readv = (uint64)LOAD_U32(maddr);                         \
             STORE_U32(maddr, (uint32)(readv op sval));               \
-            os_mutex_unlock(&module->e->mem_lock);                   \
+            os_mutex_unlock(&node->shared_mem_lock);                 \
         }                                                            \
         else {                                                       \
             uint64 op_result;                                        \
             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr);     \
             CHECK_ATOMIC_MEMORY_ACCESS(8);                           \
                                                                      \
-            os_mutex_lock(&module->e->mem_lock);                     \
+            os_mutex_lock(&node->shared_mem_lock);                   \
             readv = (uint64)LOAD_I64(maddr);                         \
             op_result = readv op sval;                               \
             STORE_I64(maddr, op_result);                             \
-            os_mutex_unlock(&module->e->mem_lock);                   \
+            os_mutex_unlock(&node->shared_mem_lock);                 \
         }                                                            \
         PUSH_I64(readv);                                             \
         break;                                                       \
@@ -925,7 +926,7 @@ wasm_interp_call_func_native(WASMModuleInstance *module_inst,
     if (!func_import->call_conv_wasm_c_api) {
         native_func_pointer = module_inst->import_func_ptrs[cur_func_index];
     }
-    else {
+    else if (module_inst->e->c_api_func_imports) {
         c_api_func_import = module_inst->e->c_api_func_imports + cur_func_index;
         native_func_pointer = c_api_func_import->func_ptr_linked;
     }
@@ -1042,7 +1043,7 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst,
     exec_env->module_inst = (WASMModuleInstanceCommon *)module_inst;
 
     /* transfer exception if it is thrown */
-    if (wasm_get_exception(sub_module_inst)) {
+    if (wasm_copy_exception(sub_module_inst, NULL)) {
         bh_memcpy_s(module_inst->cur_exception,
                     sizeof(module_inst->cur_exception),
                     sub_module_inst->cur_exception,
@@ -1054,13 +1055,16 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst,
 #if WASM_ENABLE_THREAD_MGR != 0
 #define CHECK_SUSPEND_FLAGS()                           \
     do {                                                \
+        os_mutex_lock(&exec_env->wait_lock);            \
         if (exec_env->suspend_flags.flags != 0) {       \
             if (exec_env->suspend_flags.flags & 0x01) { \
                 /* terminate current thread */          \
+                os_mutex_unlock(&exec_env->wait_lock);  \
                 return;                                 \
             }                                           \
             /* TODO: support suspend and breakpoint */  \
         }                                               \
+        os_mutex_unlock(&exec_env->wait_lock);          \
     } while (0)
 #endif
 
@@ -1151,13 +1155,22 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                                WASMFunctionInstance *cur_func,
                                WASMInterpFrame *prev_frame)
 {
+#if WASM_ENABLE_SHARED_MEMORY != 0
+    WASMSharedMemNode *node =
+        wasm_module_get_shared_memory((WASMModuleCommon *)module->module);
+#else
+    void *node = NULL;
+#endif
+
     WASMMemoryInstance *memory = wasm_get_default_memory(module);
+
 #if !defined(OS_ENABLE_HW_BOUND_CHECK)              \
     || WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \
     || WASM_ENABLE_BULK_MEMORY != 0
-    uint32 num_bytes_per_page = memory ? memory->num_bytes_per_page : 0;
+    uint32 num_bytes_per_page =
+        memory ? wasm_get_num_bytes_per_page(memory, node) : 0;
     uint32 linear_mem_size =
-        memory ? num_bytes_per_page * memory->cur_page_count : 0;
+        memory ? wasm_get_linear_memory_size(memory, node) : 0;
 #endif
     uint8 *global_data = module->global_data;
     WASMGlobalInstance *globals = module->e ? module->e->globals : NULL;
@@ -3261,6 +3274,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                         if (ret == (uint32)-1)
                             goto got_exception;
 
+#if WASM_ENABLE_THREAD_MGR != 0
+                        CHECK_SUSPEND_FLAGS();
+#endif
+
                         PUSH_I32(ret);
                         break;
                     }
@@ -3281,9 +3298,18 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                         if (ret == (uint32)-1)
                             goto got_exception;
 
+#if WASM_ENABLE_THREAD_MGR != 0
+                        CHECK_SUSPEND_FLAGS();
+#endif
+
                         PUSH_I32(ret);
                         break;
                     }
+                    case WASM_OP_ATOMIC_FENCE:
+                    {
+                        os_atomic_thread_fence(os_memory_order_release);
+                        break;
+                    }
 
                     case WASM_OP_ATOMIC_I32_LOAD:
                     case WASM_OP_ATOMIC_I32_LOAD8_U:
@@ -3296,23 +3322,23 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                         if (opcode == WASM_OP_ATOMIC_I32_LOAD8_U) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS(1);
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             readv = (uint32)(*(uint8 *)maddr);
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         else if (opcode == WASM_OP_ATOMIC_I32_LOAD16_U) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS(2);
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             readv = (uint32)LOAD_U16(maddr);
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         else {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS(4);
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             readv = LOAD_I32(maddr);
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
 
                         PUSH_I32(readv);
@@ -3331,30 +3357,30 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                         if (opcode == WASM_OP_ATOMIC_I64_LOAD8_U) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS(1);
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             readv = (uint64)(*(uint8 *)maddr);
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         else if (opcode == WASM_OP_ATOMIC_I64_LOAD16_U) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS(2);
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             readv = (uint64)LOAD_U16(maddr);
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         else if (opcode == WASM_OP_ATOMIC_I64_LOAD32_U) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS(4);
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             readv = (uint64)LOAD_U32(maddr);
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         else {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS(8);
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             readv = LOAD_I64(maddr);
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
 
                         PUSH_I64(readv);
@@ -3372,23 +3398,23 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                         if (opcode == WASM_OP_ATOMIC_I32_STORE8) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS(1);
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             *(uint8 *)maddr = (uint8)sval;
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         else if (opcode == WASM_OP_ATOMIC_I32_STORE16) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS(2);
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             STORE_U16(maddr, (uint16)sval);
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         else {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS(4);
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             STORE_U32(maddr, sval);
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         break;
                     }
@@ -3406,30 +3432,30 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                         if (opcode == WASM_OP_ATOMIC_I64_STORE8) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS(1);
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             *(uint8 *)maddr = (uint8)sval;
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         else if (opcode == WASM_OP_ATOMIC_I64_STORE16) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS(2);
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             STORE_U16(maddr, (uint16)sval);
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         else if (opcode == WASM_OP_ATOMIC_I64_STORE32) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS(4);
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             STORE_U32(maddr, (uint32)sval);
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         else {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS(8);
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             STORE_I64(maddr, sval);
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         break;
                     }
@@ -3449,32 +3475,32 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                             CHECK_ATOMIC_MEMORY_ACCESS(1);
 
                             expect = (uint8)expect;
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             readv = (uint32)(*(uint8 *)maddr);
                             if (readv == expect)
                                 *(uint8 *)maddr = (uint8)(sval);
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         else if (opcode == WASM_OP_ATOMIC_RMW_I32_CMPXCHG16_U) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS(2);
 
                             expect = (uint16)expect;
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             readv = (uint32)LOAD_U16(maddr);
                             if (readv == expect)
                                 STORE_U16(maddr, (uint16)(sval));
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         else {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS(4);
 
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             readv = LOAD_I32(maddr);
                             if (readv == expect)
                                 STORE_U32(maddr, sval);
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         PUSH_I32(readv);
                         break;
@@ -3495,44 +3521,44 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                             CHECK_ATOMIC_MEMORY_ACCESS(1);
 
                             expect = (uint8)expect;
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             readv = (uint64)(*(uint8 *)maddr);
                             if (readv == expect)
                                 *(uint8 *)maddr = (uint8)(sval);
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         else if (opcode == WASM_OP_ATOMIC_RMW_I64_CMPXCHG16_U) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS(2);
 
                             expect = (uint16)expect;
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             readv = (uint64)LOAD_U16(maddr);
                             if (readv == expect)
                                 STORE_U16(maddr, (uint16)(sval));
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         else if (opcode == WASM_OP_ATOMIC_RMW_I64_CMPXCHG32_U) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS(4);
 
                             expect = (uint32)expect;
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             readv = (uint64)LOAD_U32(maddr);
                             if (readv == expect)
                                 STORE_U32(maddr, (uint32)(sval));
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         else {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS(8);
 
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             readv = (uint64)LOAD_I64(maddr);
                             if (readv == expect) {
                                 STORE_I64(maddr, sval);
                             }
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         PUSH_I64(readv);
                         break;
@@ -3781,7 +3807,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
             if (memory)
                 linear_mem_size = num_bytes_per_page * memory->cur_page_count;
 #endif
-            if (wasm_get_exception(module))
+            if (wasm_copy_exception(module, NULL))
                 goto got_exception;
         }
         else {
@@ -3821,6 +3847,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
 
             wasm_exec_env_set_cur_frame(exec_env, (WASMRuntimeFrame *)frame);
         }
+#if WASM_ENABLE_THREAD_MGR != 0
+        CHECK_SUSPEND_FLAGS();
+#endif
         HANDLE_OP_END();
     }
 
@@ -3889,6 +3918,7 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env,
     /* This frame won't be used by JITed code, so only allocate interp
        frame here.  */
     unsigned frame_size = wasm_interp_interp_frame_size(all_cell_num);
+    char exception[EXCEPTION_BUF_LEN];
 
     if (argc < function->param_cell_num) {
         char buf[128];
@@ -3901,6 +3931,7 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env,
     }
     argc = function->param_cell_num;
 
+    RECORD_STACK_USAGE(exec_env, (uint8 *)&prev_frame);
 #if !(defined(OS_ENABLE_HW_BOUND_CHECK) \
       && WASM_DISABLE_STACK_HW_BOUND_CHECK == 0)
     if ((uint8 *)&prev_frame < exec_env->native_stack_boundary) {
@@ -3953,7 +3984,7 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env,
     }
 
     /* Output the return value to the caller */
-    if (!wasm_get_exception(module_inst)) {
+    if (!wasm_copy_exception(module_inst, NULL)) {
         for (i = 0; i < function->ret_cell_num; i++)
             argv[i] = *(frame->lp + i);
     }
@@ -3963,7 +3994,8 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env,
             wasm_interp_dump_call_stack(exec_env, true, NULL, 0);
         }
 #endif
-        LOG_DEBUG("meet an exception %s", wasm_get_exception(module_inst));
+        wasm_copy_exception(module_inst, exception);
+        LOG_DEBUG("meet an exception %s", exception);
     }
 
     wasm_exec_env_set_cur_frame(exec_env, prev_frame);

+ 45 - 20
core/iwasm/interpreter/wasm_loader.c

@@ -1399,6 +1399,7 @@ load_global_import(const uint8 **p_buf, const uint8 *buf_end,
     WASMModule *sub_module = NULL;
     WASMGlobal *linked_global = NULL;
 #endif
+    bool ret = false;
 
     CHECK_BUF(p, p_end, 2);
     declare_type = read_uint8(p);
@@ -1411,15 +1412,16 @@ load_global_import(const uint8 **p_buf, const uint8 *buf_end,
     }
 
 #if WASM_ENABLE_LIBC_BUILTIN != 0
-    global->is_linked = wasm_native_lookup_libc_builtin_global(
-        sub_module_name, global_name, global);
-    if (global->is_linked) {
+    ret = wasm_native_lookup_libc_builtin_global(sub_module_name, global_name,
+                                                 global);
+    if (ret) {
         if (global->type != declare_type
             || global->is_mutable != declare_mutable) {
             set_error_buf(error_buf, error_buf_size,
                           "incompatible import type");
             return false;
         }
+        global->is_linked = true;
     }
 #endif
 #if WASM_ENABLE_MULTI_MODULE != 0
@@ -1449,6 +1451,7 @@ load_global_import(const uint8 **p_buf, const uint8 *buf_end,
     global->is_mutable = (declare_mutable == 1);
 
     (void)parent_module;
+    (void)ret;
     return true;
 fail:
     return false;
@@ -2989,6 +2992,7 @@ static bool
 init_llvm_jit_functions_stage1(WASMModule *module, char *error_buf,
                                uint32 error_buf_size)
 {
+    LLVMJITOptions llvm_jit_options = wasm_runtime_get_llvm_jit_options();
     AOTCompOption option = { 0 };
     char *aot_last_error;
     uint64 size;
@@ -3027,8 +3031,11 @@ init_llvm_jit_functions_stage1(WASMModule *module, char *error_buf,
     }
 
     option.is_jit_mode = true;
-    option.opt_level = 3;
-    option.size_level = 3;
+
+    llvm_jit_options = wasm_runtime_get_llvm_jit_options();
+    option.opt_level = llvm_jit_options.opt_level;
+    option.size_level = llvm_jit_options.size_level;
+
 #if WASM_ENABLE_BULK_MEMORY != 0
     option.enable_bulk_memory = true;
 #endif
@@ -3048,6 +3055,9 @@ init_llvm_jit_functions_stage1(WASMModule *module, char *error_buf,
 #if (WASM_ENABLE_PERF_PROFILING != 0) || (WASM_ENABLE_DUMP_CALL_STACK != 0)
     option.enable_aux_stack_frame = true;
 #endif
+#if WASM_ENABLE_MEMORY_PROFILING != 0
+    option.enable_stack_estimation = true;
+#endif
 
     module->comp_ctx = aot_create_comp_context(module->comp_data, &option);
     if (!module->comp_ctx) {
@@ -3109,6 +3119,8 @@ init_llvm_jit_functions_stage2(WASMModule *module, char *error_buf,
         module->func_ptrs[i] = (void *)func_addr;
 
 #if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_LAZY_JIT != 0
+        module->functions[i]->llvm_jit_func_ptr = (void *)func_addr;
+
         if (module->orcjit_stop_compiling)
             return false;
 #endif
@@ -3199,9 +3211,9 @@ orcjit_thread_callback(void *arg)
 
     /* Wait until init_llvm_jit_functions_stage2 finishes */
     os_mutex_lock(&module->tierup_wait_lock);
-    while (!module->llvm_jit_inited) {
+    while (!(module->llvm_jit_inited && module->enable_llvm_jit_compilation)) {
         os_cond_reltimedwait(&module->tierup_wait_cond,
-                             &module->tierup_wait_lock, 10);
+                             &module->tierup_wait_lock, 10000);
         if (module->orcjit_stop_compiling) {
             /* init_llvm_jit_functions_stage2 failed */
             os_mutex_unlock(&module->tierup_wait_lock);
@@ -3852,8 +3864,8 @@ create_module(char *error_buf, uint32 error_buf_size)
     bh_assert(ret == BH_LIST_SUCCESS);
 #endif
 
-#if WASM_ENABLE_DEBUG_INTERP != 0                    \
-    || (WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT \
+#if WASM_ENABLE_DEBUG_INTERP != 0                         \
+    || (WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \
         && WASM_ENABLE_LAZY_JIT != 0)
     if (os_mutex_init(&module->instance_list_lock) != 0) {
         set_error_buf(error_buf, error_buf_size,
@@ -4148,10 +4160,8 @@ check_wasi_abi_compatibility(const WASMModule *module,
 
     /* should have one at least */
     if (module->import_wasi_api && !start && !initialize) {
-        set_error_buf(
-            error_buf, error_buf_size,
-            "a module with WASI apis must be either a command or a reactor");
-        return false;
+        LOG_WARNING("warning: a module with WASI apis should be either "
+                    "a command or a reactor");
     }
 
     /*
@@ -4185,7 +4195,20 @@ check_wasi_abi_compatibility(const WASMModule *module,
 
     memory = wasm_loader_find_export(module, "", "memory", EXPORT_KIND_MEMORY,
                                      error_buf, error_buf_size);
-    if (!memory) {
+    if (!memory
+#if WASM_ENABLE_LIB_WASI_THREADS != 0
+        /*
+         * with wasi-threads, it's still an open question if a memory
+         * should be exported.
+         *
+         * https://github.com/WebAssembly/wasi-threads/issues/22
+         * https://github.com/WebAssembly/WASI/issues/502
+         *
+         * Note: this code assumes the number of memories is at most 1.
+         */
+        && module->import_memory_count == 0
+#endif
+    ) {
         set_error_buf(error_buf, error_buf_size,
                       "a module with WASI apis must export memory by default");
         return false;
@@ -4243,7 +4266,8 @@ wasm_loader_unload(WASMModule *module)
     if (!module)
         return;
 
-#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT && WASM_ENABLE_LAZY_JIT != 0
+#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \
+    && WASM_ENABLE_LAZY_JIT != 0
     module->orcjit_stop_compiling = true;
     if (module->llvm_jit_init_thread)
         os_thread_join(module->llvm_jit_init_thread, NULL);
@@ -4264,7 +4288,8 @@ wasm_loader_unload(WASMModule *module)
         aot_destroy_comp_data(module->comp_data);
 #endif
 
-#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT && WASM_ENABLE_LAZY_JIT != 0
+#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \
+    && WASM_ENABLE_LAZY_JIT != 0
     if (module->tierup_wait_lock_inited) {
         os_mutex_destroy(&module->tierup_wait_lock);
         os_cond_destroy(&module->tierup_wait_cond);
@@ -4299,9 +4324,9 @@ wasm_loader_unload(WASMModule *module)
                         module->functions[i]->fast_jit_jitted_code);
                 }
 #if WASM_ENABLE_JIT != 0 && WASM_ENABLE_LAZY_JIT != 0
-                if (module->functions[i]->llvm_jit_func_ptr) {
+                if (module->functions[i]->call_to_fast_jit_from_llvm_jit) {
                     jit_code_cache_free(
-                        module->functions[i]->llvm_jit_func_ptr);
+                        module->functions[i]->call_to_fast_jit_from_llvm_jit);
                 }
 #endif
 #endif
@@ -4393,8 +4418,8 @@ wasm_loader_unload(WASMModule *module)
     }
 #endif
 
-#if WASM_ENABLE_DEBUG_INTERP != 0                    \
-    || (WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT \
+#if WASM_ENABLE_DEBUG_INTERP != 0                         \
+    || (WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \
         && WASM_ENABLE_LAZY_JIT != 0)
     os_mutex_destroy(&module->instance_list_lock);
 #endif

+ 21 - 10
core/iwasm/interpreter/wasm_mini_loader.c

@@ -1835,6 +1835,7 @@ static bool
 init_llvm_jit_functions_stage1(WASMModule *module, char *error_buf,
                                uint32 error_buf_size)
 {
+    LLVMJITOptions llvm_jit_options = wasm_runtime_get_llvm_jit_options();
     AOTCompOption option = { 0 };
     char *aot_last_error;
     uint64 size;
@@ -1873,8 +1874,9 @@ init_llvm_jit_functions_stage1(WASMModule *module, char *error_buf,
     }
 
     option.is_jit_mode = true;
-    option.opt_level = 3;
-    option.size_level = 3;
+    option.opt_level = llvm_jit_options.opt_level;
+    option.size_level = llvm_jit_options.size_level;
+
 #if WASM_ENABLE_BULK_MEMORY != 0
     option.enable_bulk_memory = true;
 #endif
@@ -1894,6 +1896,9 @@ init_llvm_jit_functions_stage1(WASMModule *module, char *error_buf,
 #if (WASM_ENABLE_PERF_PROFILING != 0) || (WASM_ENABLE_DUMP_CALL_STACK != 0)
     option.enable_aux_stack_frame = true;
 #endif
+#if WASM_ENABLE_MEMORY_PROFILING != 0
+    option.enable_stack_estimation = true;
+#endif
 
     module->comp_ctx = aot_create_comp_context(module->comp_data, &option);
     if (!module->comp_ctx) {
@@ -1957,6 +1962,8 @@ init_llvm_jit_functions_stage2(WASMModule *module, char *error_buf,
         module->func_ptrs[i] = (void *)func_addr;
 
 #if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_LAZY_JIT != 0
+        module->functions[i]->llvm_jit_func_ptr = (void *)func_addr;
+
         if (module->orcjit_stop_compiling)
             return false;
 #endif
@@ -2047,9 +2054,9 @@ orcjit_thread_callback(void *arg)
 
     /* Wait until init_llvm_jit_functions_stage2 finishes */
     os_mutex_lock(&module->tierup_wait_lock);
-    while (!module->llvm_jit_inited) {
+    while (!(module->llvm_jit_inited && module->enable_llvm_jit_compilation)) {
         os_cond_reltimedwait(&module->tierup_wait_cond,
-                             &module->tierup_wait_lock, 10);
+                             &module->tierup_wait_lock, 10000);
         if (module->orcjit_stop_compiling) {
             /* init_llvm_jit_functions_stage2 failed */
             os_mutex_unlock(&module->tierup_wait_lock);
@@ -2718,7 +2725,8 @@ create_module(char *error_buf, uint32 error_buf_size)
     bh_assert(ret == BH_LIST_SUCCESS);
 #endif
 
-#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT && WASM_ENABLE_LAZY_JIT != 0
+#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \
+    && WASM_ENABLE_LAZY_JIT != 0
     if (os_mutex_init(&module->instance_list_lock) != 0) {
         set_error_buf(error_buf, error_buf_size,
                       "init instance list lock failed");
@@ -2939,7 +2947,8 @@ wasm_loader_unload(WASMModule *module)
     if (!module)
         return;
 
-#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT && WASM_ENABLE_LAZY_JIT != 0
+#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \
+    && WASM_ENABLE_LAZY_JIT != 0
     module->orcjit_stop_compiling = true;
     if (module->llvm_jit_init_thread)
         os_thread_join(module->llvm_jit_init_thread, NULL);
@@ -2960,7 +2969,8 @@ wasm_loader_unload(WASMModule *module)
         aot_destroy_comp_data(module->comp_data);
 #endif
 
-#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT && WASM_ENABLE_LAZY_JIT != 0
+#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \
+    && WASM_ENABLE_LAZY_JIT != 0
     if (module->tierup_wait_lock_inited) {
         os_mutex_destroy(&module->tierup_wait_lock);
         os_cond_destroy(&module->tierup_wait_cond);
@@ -2995,9 +3005,9 @@ wasm_loader_unload(WASMModule *module)
                         module->functions[i]->fast_jit_jitted_code);
                 }
 #if WASM_ENABLE_JIT != 0 && WASM_ENABLE_LAZY_JIT != 0
-                if (module->functions[i]->llvm_jit_func_ptr) {
+                if (module->functions[i]->call_to_fast_jit_from_llvm_jit) {
                     jit_code_cache_free(
-                        module->functions[i]->llvm_jit_func_ptr);
+                        module->functions[i]->call_to_fast_jit_from_llvm_jit);
                 }
 #endif
 #endif
@@ -3056,7 +3066,8 @@ wasm_loader_unload(WASMModule *module)
     }
 #endif
 
-#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT && WASM_ENABLE_LAZY_JIT != 0
+#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \
+    && WASM_ENABLE_LAZY_JIT != 0
     os_mutex_destroy(&module->instance_list_lock);
 #endif
 

+ 9 - 11
core/iwasm/interpreter/wasm_opcode.h

@@ -675,12 +675,14 @@ typedef enum WASMAtomicEXTOpcode {
 } WASMAtomicEXTOpcode;
 
 #if WASM_ENABLE_DEBUG_INTERP != 0
-#define DEF_DEBUG_BREAK_HANDLE(_name) \
-    _name[DEBUG_OP_BREAK] = HANDLE_OPCODE(DEBUG_OP_BREAK); /* 0xd7 */
+#define DEF_DEBUG_BREAK_HANDLE() \
+    [DEBUG_OP_BREAK] = HANDLE_OPCODE(DEBUG_OP_BREAK), /* 0xd7 */
 #else
-#define DEF_DEBUG_BREAK_HANDLE(_name)
+#define DEF_DEBUG_BREAK_HANDLE()
 #endif
 
+#define SET_GOTO_TABLE_ELEM(opcode) [opcode] = HANDLE_OPCODE(opcode)
+
 /*
  * Macro used to generate computed goto tables for the C interpreter.
  */
@@ -903,14 +905,10 @@ typedef enum WASMAtomicEXTOpcode {
         HANDLE_OPCODE(EXT_OP_LOOP),                  /* 0xd4 */ \
         HANDLE_OPCODE(EXT_OP_IF),                    /* 0xd5 */ \
         HANDLE_OPCODE(EXT_OP_BR_TABLE_CACHE),        /* 0xd6 */ \
-    };                                                          \
-    do {                                                        \
-        _name[WASM_OP_MISC_PREFIX] =                            \
-            HANDLE_OPCODE(WASM_OP_MISC_PREFIX); /* 0xfc */      \
-        _name[WASM_OP_ATOMIC_PREFIX] =                          \
-            HANDLE_OPCODE(WASM_OP_ATOMIC_PREFIX); /* 0xfe */    \
-        DEF_DEBUG_BREAK_HANDLE(_name)                           \
-    } while (0)
+        SET_GOTO_TABLE_ELEM(WASM_OP_MISC_PREFIX),    /* 0xfc */ \
+        SET_GOTO_TABLE_ELEM(WASM_OP_ATOMIC_PREFIX),  /* 0xfe */ \
+        DEF_DEBUG_BREAK_HANDLE()                                \
+    };
 
 #ifdef __cplusplus
 }

+ 392 - 190
core/iwasm/interpreter/wasm_runtime.c

@@ -737,13 +737,12 @@ functions_instantiate(const WASMModule *module, WASMModuleInstance *module_inst,
 
         function++;
     }
+    bh_assert((uint32)(function - functions) == function_count);
 
 #if WASM_ENABLE_FAST_JIT != 0
     module_inst->fast_jit_func_ptrs = module->fast_jit_func_ptrs;
 #endif
 
-    bh_assert((uint32)(function - functions) == function_count);
-    (void)module_inst;
     return functions;
 }
 
@@ -983,88 +982,138 @@ export_globals_instantiate(const WASMModule *module,
 }
 #endif
 
-#if WASM_ENABLE_LIBC_WASI != 0
-static bool
-execute_initialize_function(WASMModuleInstance *module_inst)
-{
-    WASMFunctionInstance *initialize =
-        wasm_lookup_function(module_inst, "_initialize", NULL);
-    return !initialize
-           || wasm_create_exec_env_and_call_function(module_inst, initialize, 0,
-                                                     NULL);
-}
-#endif
-
-static bool
-execute_post_inst_function(WASMModuleInstance *module_inst)
+static WASMFunctionInstance *
+lookup_post_instantiate_func(WASMModuleInstance *module_inst,
+                             const char *func_name)
 {
-    WASMFunctionInstance *post_inst_func = NULL;
-    WASMType *post_inst_func_type;
-    uint32 i;
-
-    for (i = 0; i < module_inst->export_func_count; i++)
-        if (!strcmp(module_inst->export_functions[i].name,
-                    "__post_instantiate")) {
-            post_inst_func = module_inst->export_functions[i].function;
-            break;
-        }
+    WASMFunctionInstance *func;
+    WASMType *func_type;
 
-    if (!post_inst_func)
+    if (!(func = wasm_lookup_function(module_inst, func_name, NULL)))
         /* Not found */
-        return true;
+        return NULL;
 
-    post_inst_func_type = post_inst_func->u.func->func_type;
-    if (post_inst_func_type->param_count != 0
-        || post_inst_func_type->result_count != 0)
+    func_type = func->u.func->func_type;
+    if (!(func_type->param_count == 0 && func_type->result_count == 0))
         /* Not a valid function type, ignore it */
-        return true;
+        return NULL;
 
-    return wasm_create_exec_env_and_call_function(module_inst, post_inst_func,
-                                                  0, NULL);
+    return func;
 }
 
-#if WASM_ENABLE_BULK_MEMORY != 0
 static bool
-execute_memory_init_function(WASMModuleInstance *module_inst)
+execute_post_instantiate_functions(WASMModuleInstance *module_inst,
+                                   bool is_sub_inst)
 {
-    WASMFunctionInstance *memory_init_func = NULL;
-    WASMType *memory_init_func_type;
-    uint32 i;
+    WASMFunctionInstance *start_func = module_inst->e->start_function;
+    WASMFunctionInstance *initialize_func = NULL;
+    WASMFunctionInstance *post_inst_func = NULL;
+    WASMFunctionInstance *call_ctors_func = NULL;
+#if WASM_ENABLE_LIBC_WASI != 0
+    WASMModule *module = module_inst->module;
+#endif
+#ifdef OS_ENABLE_HW_BOUND_CHECK
+    WASMModuleInstanceCommon *module_inst_main = NULL;
+    WASMExecEnv *exec_env_tls = NULL;
+#endif
+    WASMExecEnv *exec_env = NULL;
+    bool ret = false;
 
-    for (i = 0; i < module_inst->export_func_count; i++)
-        if (!strcmp(module_inst->export_functions[i].name,
-                    "__wasm_call_ctors")) {
-            memory_init_func = module_inst->export_functions[i].function;
-            break;
-        }
+#if WASM_ENABLE_LIBC_WASI != 0
+    /*
+     * WASI reactor instances may assume that _initialize will be called by
+     * the environment at most once, and that none of their other exports
+     * are accessed before that call.
+     */
+    if (!is_sub_inst && module->import_wasi_api) {
+        initialize_func =
+            lookup_post_instantiate_func(module_inst, "_initialize");
+    }
+#endif
 
-    if (!memory_init_func)
-        /* Not found */
-        return true;
+    /* Execute possible "__post_instantiate" function if wasm app is
+       compiled by emsdk's early version */
+    if (!is_sub_inst) {
+        post_inst_func =
+            lookup_post_instantiate_func(module_inst, "__post_instantiate");
+    }
 
-    memory_init_func_type = memory_init_func->u.func->func_type;
-    if (memory_init_func_type->param_count != 0
-        || memory_init_func_type->result_count != 0)
-        /* Not a valid function type, ignore it */
+#if WASM_ENABLE_BULK_MEMORY != 0
+    /* Only execute the memory init function for main instance since
+       the data segments will be dropped once initialized */
+    if (!is_sub_inst
+#if WASM_ENABLE_LIBC_WASI != 0
+        && !module->import_wasi_api
+#endif
+    ) {
+        call_ctors_func =
+            lookup_post_instantiate_func(module_inst, "__wasm_call_ctors");
+    }
+#endif
+
+    if (!start_func && !initialize_func && !post_inst_func
+        && !call_ctors_func) {
+        /* No post instantiation functions to call */
         return true;
+    }
 
-    return wasm_create_exec_env_and_call_function(module_inst, memory_init_func,
-                                                  0, NULL);
-}
-#endif
+#ifdef OS_ENABLE_HW_BOUND_CHECK
+    if (is_sub_inst) {
+        exec_env = exec_env_tls = wasm_runtime_get_exec_env_tls();
+        if (exec_env_tls) {
+            /* Temporarily replace exec_env_tls's module inst to current
+               module inst to avoid checking failure when calling the
+               wasm functions, and ensure that the exec_env's module inst
+               is the correct one. */
+            module_inst_main = exec_env_tls->module_inst;
+            exec_env_tls->module_inst = (WASMModuleInstanceCommon *)module_inst;
+        }
+    }
+#endif
+    if (!exec_env
+        && !(exec_env =
+                 wasm_exec_env_create((WASMModuleInstanceCommon *)module_inst,
+                                      module_inst->default_wasm_stack_size))) {
+        wasm_set_exception(module_inst, "allocate memory failed");
+        return false;
+    }
 
-static bool
-execute_start_function(WASMModuleInstance *module_inst)
-{
-    WASMFunctionInstance *func = module_inst->e->start_function;
+    /* Execute start function for both main insance and sub instance */
+    if (start_func && !wasm_call_function(exec_env, start_func, 0, NULL)) {
+        goto fail;
+    }
 
-    if (!func)
-        return true;
+    if (initialize_func
+        && !wasm_call_function(exec_env, initialize_func, 0, NULL)) {
+        goto fail;
+    }
 
-    bh_assert(!func->is_import_func && func->param_cell_num == 0
-              && func->ret_cell_num == 0);
+    if (post_inst_func
+        && !wasm_call_function(exec_env, post_inst_func, 0, NULL)) {
+        goto fail;
+    }
+
+    if (call_ctors_func
+        && !wasm_call_function(exec_env, call_ctors_func, 0, NULL)) {
+        goto fail;
+    }
+
+    ret = true;
+
+fail:
+#ifdef OS_ENABLE_HW_BOUND_CHECK
+    if (is_sub_inst && exec_env_tls) {
+        bh_assert(exec_env == exec_env_tls);
+        /* Restore the exec_env_tls's module inst */
+        exec_env_tls->module_inst = module_inst_main;
+    }
+    else
+        wasm_exec_env_destroy(exec_env);
+#else
+    wasm_exec_env_destroy(exec_env);
+#endif
 
-    return wasm_create_exec_env_and_call_function(module_inst, func, 0, NULL);
+    return ret;
 }
 
 static bool
@@ -1235,6 +1284,7 @@ check_linked_symbol(WASMModuleInstance *module_inst, char *error_buf,
 #if WASM_ENABLE_WAMR_COMPILER == 0
             LOG_WARNING("warning: failed to link import function (%s, %s)",
                         func->module_name, func->field_name);
+            /* will throw exception only if calling */
 #else
             /* do nothing to avoid confused message */
 #endif /* WASM_ENABLE_WAMR_COMPILER == 0 */
@@ -1250,8 +1300,10 @@ check_linked_symbol(WASMModuleInstance *module_inst, char *error_buf,
             return false;
 #else
 #if WASM_ENABLE_WAMR_COMPILER == 0
-            LOG_DEBUG("warning: failed to link import global (%s, %s)",
-                      global->module_name, global->field_name);
+            set_error_buf_v(error_buf, error_buf_size,
+                            "failed to link import global (%s, %s)",
+                            global->module_name, global->field_name);
+            return false;
 #else
             /* do nothing to avoid confused message */
 #endif /* WASM_ENABLE_WAMR_COMPILER == 0 */
@@ -1285,9 +1337,8 @@ init_func_ptrs(WASMModuleInstance *module_inst, WASMModule *module,
         *func_ptrs = import_func->func_ptr_linked;
     }
 
-    /* Set defined function pointers */
-    bh_memcpy_s(func_ptrs, sizeof(void *) * module->function_count,
-                module->func_ptrs, sizeof(void *) * module->function_count);
+    /* The defined function pointers will be set in
+       wasm_runtime_set_running_mode, no need to set them here */
     return true;
 }
 #endif /* end of WASM_ENABLE_JIT != 0 */
@@ -1333,6 +1384,173 @@ init_func_type_indexes(WASMModuleInstance *module_inst, char *error_buf,
 }
 #endif /* end of WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0 */
 
+static bool
+set_running_mode(WASMModuleInstance *module_inst, RunningMode running_mode,
+                 bool first_time_set)
+{
+    WASMModule *module = module_inst->module;
+
+    if (running_mode == Mode_Default) {
+#if WASM_ENABLE_FAST_JIT == 0 && WASM_ENABLE_JIT == 0
+        running_mode = Mode_Interp;
+#elif WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT == 0
+        running_mode = Mode_Fast_JIT;
+#elif WASM_ENABLE_FAST_JIT == 0 && WASM_ENABLE_JIT != 0
+        running_mode = Mode_LLVM_JIT;
+#else /* WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 */
+#if WASM_ENABLE_LAZY_JIT == 0
+        running_mode = Mode_LLVM_JIT;
+#else
+        running_mode = Mode_Multi_Tier_JIT;
+#endif
+#endif
+    }
+
+    if (!wasm_runtime_is_running_mode_supported(running_mode))
+        return false;
+
+#if !(WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \
+      && WASM_ENABLE_LAZY_JIT != 0) /* No possible multi-tier JIT */
+    module_inst->e->running_mode = running_mode;
+
+    if (running_mode == Mode_Interp) {
+        /* Do nothing for Mode_Interp */
+    }
+    else if (running_mode == Mode_Fast_JIT) {
+        /* Do nothing for Mode_Fast_JIT since
+           module_inst->fast_jit_func_ptrs is same as
+           module->fast_jit_func_ptrs */
+    }
+#if WASM_ENABLE_JIT != 0
+    else if (running_mode == Mode_LLVM_JIT) {
+        /* Set defined function pointers */
+        bh_memcpy_s(module_inst->func_ptrs + module->import_function_count,
+                    sizeof(void *) * module->function_count, module->func_ptrs,
+                    sizeof(void *) * module->function_count);
+    }
+#endif
+    else {
+        bh_assert(0);
+    }
+#else /* Possible multi-tier JIT */
+    os_mutex_lock(&module->instance_list_lock);
+
+    module_inst->e->running_mode = running_mode;
+
+    if (running_mode == Mode_Interp) {
+        /* Do nothing for Mode_Interp */
+    }
+#if WASM_ENABLE_FAST_JIT != 0
+    else if (running_mode == Mode_Fast_JIT) {
+        JitGlobals *jit_globals = jit_compiler_get_jit_globals();
+        uint32 i;
+
+        /* Allocate memory for fast_jit_func_ptrs if needed */
+        if (!module_inst->fast_jit_func_ptrs
+            || module_inst->fast_jit_func_ptrs == module->fast_jit_func_ptrs) {
+            uint64 total_size = (uint64)sizeof(void *) * module->function_count;
+            if (!(module_inst->fast_jit_func_ptrs =
+                      runtime_malloc(total_size, NULL, 0))) {
+                os_mutex_unlock(&module->instance_list_lock);
+                return false;
+            }
+        }
+
+        for (i = 0; i < module->function_count; i++) {
+            if (module->functions[i]->fast_jit_jitted_code) {
+                /* current fast jit function has been compiled */
+                module_inst->fast_jit_func_ptrs[i] =
+                    module->functions[i]->fast_jit_jitted_code;
+            }
+            else {
+                module_inst->fast_jit_func_ptrs[i] =
+                    jit_globals->compile_fast_jit_and_then_call;
+            }
+        }
+    }
+#endif
+#if WASM_ENABLE_JIT != 0
+    else if (running_mode == Mode_LLVM_JIT) {
+        void **llvm_jit_func_ptrs;
+        uint32 i;
+
+        /* Notify backend threads to start llvm jit compilation */
+        module->enable_llvm_jit_compilation = true;
+
+        /* Wait until llvm jit finishes initialization */
+        os_mutex_lock(&module->tierup_wait_lock);
+        while (!module->llvm_jit_inited) {
+            os_cond_reltimedwait(&module->tierup_wait_cond,
+                                 &module->tierup_wait_lock, 10);
+            if (module->orcjit_stop_compiling) {
+                /* init_llvm_jit_functions_stage2 failed */
+                os_mutex_unlock(&module->tierup_wait_lock);
+                os_mutex_unlock(&module->instance_list_lock);
+                return false;
+            }
+        }
+        os_mutex_unlock(&module->tierup_wait_lock);
+
+        llvm_jit_func_ptrs =
+            module_inst->func_ptrs + module->import_function_count;
+        for (i = 0; i < module->function_count; i++) {
+            llvm_jit_func_ptrs[i] = module->functions[i]->llvm_jit_func_ptr;
+        }
+    }
+#endif
+    else if (running_mode == Mode_Multi_Tier_JIT) {
+        /* Notify backend threads to start llvm jit compilation */
+        module->enable_llvm_jit_compilation = true;
+
+        /* Free fast_jit_func_ptrs if it is allocated before */
+        if (module_inst->fast_jit_func_ptrs
+            && module_inst->fast_jit_func_ptrs != module->fast_jit_func_ptrs) {
+            wasm_runtime_free(module_inst->fast_jit_func_ptrs);
+        }
+        module_inst->fast_jit_func_ptrs = module->fast_jit_func_ptrs;
+
+        /* Copy all llvm jit func ptrs from the module */
+        bh_memcpy_s(module_inst->func_ptrs + module->import_function_count,
+                    sizeof(void *) * module->function_count, module->func_ptrs,
+                    sizeof(void *) * module->function_count);
+    }
+    else {
+        bh_assert(0);
+    }
+
+    /* Add module instance into module's instance list if not added */
+    if (first_time_set) {
+        bool found = false;
+        WASMModuleInstance *node = module->instance_list;
+
+        while (node) {
+            if (node == module_inst) {
+                found = true;
+                break;
+            }
+            node = node->e->next;
+        }
+
+        if (!found) {
+            module_inst->e->next = module->instance_list;
+            module->instance_list = module_inst;
+        }
+    }
+
+    os_mutex_unlock(&module->instance_list_lock);
+#endif /* end of !(WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \
+                   && WASM_ENABLE_LAZY_JIT != 0) */
+
+    (void)module;
+    return true;
+}
+
+bool
+wasm_set_running_mode(WASMModuleInstance *module_inst, RunningMode running_mode)
+{
+    return set_running_mode(module_inst, running_mode, false);
+}
+
 /**
  * Instantiate module
  */
@@ -1419,15 +1637,6 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, uint32 stack_size,
     module_inst->e =
         (WASMModuleInstanceExtra *)((uint8 *)module_inst + extra_info_offset);
 
-#if WASM_ENABLE_SHARED_MEMORY != 0
-    if (os_mutex_init(&module_inst->e->mem_lock) != 0) {
-        set_error_buf(error_buf, error_buf_size,
-                      "create shared memory lock failed");
-        goto fail;
-    }
-    module_inst->e->mem_lock_inited = true;
-#endif
-
 #if WASM_ENABLE_MULTI_MODULE != 0
     module_inst->e->sub_module_inst_list =
         &module_inst->e->sub_module_inst_list_head;
@@ -1800,33 +2009,39 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, uint32 stack_size,
     }
 #endif
 
-#if WASM_ENABLE_DEBUG_INTERP != 0                         \
-    || (WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \
-        && WASM_ENABLE_LAZY_JIT != 0)
+#if WASM_ENABLE_WASI_NN != 0
+    if (!is_sub_inst) {
+        if (!(module_inst->e->wasi_nn_ctx = wasi_nn_initialize())) {
+            set_error_buf(error_buf, error_buf_size,
+                          "wasi nn initialization failed");
+            goto fail;
+        }
+    }
+#endif
+
+#if WASM_ENABLE_DEBUG_INTERP != 0
     if (!is_sub_inst) {
         /* Add module instance into module's instance list */
         os_mutex_lock(&module->instance_list_lock);
-#if WASM_ENABLE_DEBUG_INTERP != 0
         if (module->instance_list) {
             LOG_WARNING(
                 "warning: multiple instances referencing to the same module "
                 "may cause unexpected behaviour during debugging");
         }
-#endif
-#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \
-    && WASM_ENABLE_LAZY_JIT != 0
-        /* Copy llvm func ptrs again in case that they were updated
-           after the module instance was created */
-        bh_memcpy_s(module_inst->func_ptrs + module->import_function_count,
-                    sizeof(void *) * module->function_count, module->func_ptrs,
-                    sizeof(void *) * module->function_count);
-#endif
         module_inst->e->next = module->instance_list;
         module->instance_list = module_inst;
         os_mutex_unlock(&module->instance_list_lock);
     }
 #endif
 
+    /* Set running mode before executing wasm functions */
+    if (!set_running_mode(module_inst, wasm_runtime_get_default_running_mode(),
+                          true)) {
+        set_error_buf(error_buf, error_buf_size,
+                      "set instance running mode failed");
+        goto fail;
+    }
+
     if (module->start_function != (uint32)-1) {
         /* TODO: fix start function can be import function issue */
         if (module->start_function >= module->import_function_count)
@@ -1834,45 +2049,11 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, uint32 stack_size,
                 &module_inst->e->functions[module->start_function];
     }
 
-    if (
-#if WASM_ENABLE_LIBC_WASI != 0
-        /*
-         * reactor instances may assume that _initialize will be called by
-         * the environment at most once, and that none of their other
-         * exports are accessed before that call.
-         *
-         * let the loader decide how to act if there is no _initialize
-         * in a reactor
-         */
-        !execute_initialize_function(module_inst) ||
-#endif
-        /* Execute __post_instantiate function */
-        !execute_post_inst_function(module_inst)
-        /* Execute the function in "start" section */
-        || !execute_start_function(module_inst)) {
+    if (!execute_post_instantiate_functions(module_inst, is_sub_inst)) {
         set_error_buf(error_buf, error_buf_size, module_inst->cur_exception);
         goto fail;
     }
 
-#if WASM_ENABLE_BULK_MEMORY != 0
-#if WASM_ENABLE_LIBC_WASI != 0
-    if (!module->import_wasi_api) {
-#endif
-        /* Only execute the memory init function for main instance because
-            the data segments will be dropped once initialized.
-        */
-        if (!is_sub_inst) {
-            if (!execute_memory_init_function(module_inst)) {
-                set_error_buf(error_buf, error_buf_size,
-                              module_inst->cur_exception);
-                goto fail;
-            }
-        }
-#if WASM_ENABLE_LIBC_WASI != 0
-    }
-#endif
-#endif
-
 #if WASM_ENABLE_MEMORY_TRACING != 0
     wasm_runtime_dump_module_inst_mem_consumption(
         (WASMModuleInstanceCommon *)module_inst);
@@ -1892,11 +2073,57 @@ wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst)
     if (!module_inst)
         return;
 
+    if (module_inst->exec_env_singleton) {
+        /* wasm_exec_env_destroy will call
+           wasm_cluster_wait_for_all_except_self to wait for other
+           threads, so as to destroy their exec_envs and module
+           instances first, and avoid accessing the shared resources
+           of current module instance after it is deinstantiated. */
+        wasm_exec_env_destroy(module_inst->exec_env_singleton);
+    }
+
+#if WASM_ENABLE_DEBUG_INTERP != 0                         \
+    || (WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \
+        && WASM_ENABLE_LAZY_JIT != 0)
+    /* Remove instance from module's instance list before freeing
+       func_ptrs and fast_jit_func_ptrs of the instance, to avoid
+       accessing the freed memory in the jit backend compilation
+       threads */
+    if (!is_sub_inst) {
+        WASMModule *module = module_inst->module;
+        WASMModuleInstance *instance_prev = NULL, *instance;
+        os_mutex_lock(&module->instance_list_lock);
+
+        instance = module->instance_list;
+        while (instance) {
+            if (instance == module_inst) {
+                if (!instance_prev)
+                    module->instance_list = instance->e->next;
+                else
+                    instance_prev->e->next = instance->e->next;
+                break;
+            }
+            instance_prev = instance;
+            instance = instance->e->next;
+        }
+
+        os_mutex_unlock(&module->instance_list_lock);
+    }
+#endif
+
 #if WASM_ENABLE_JIT != 0
     if (module_inst->func_ptrs)
         wasm_runtime_free(module_inst->func_ptrs);
 #endif
 
+#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \
+    && WASM_ENABLE_LAZY_JIT != 0
+    if (module_inst->fast_jit_func_ptrs
+        && module_inst->fast_jit_func_ptrs
+               != module_inst->module->fast_jit_func_ptrs)
+        wasm_runtime_free(module_inst->fast_jit_func_ptrs);
+#endif
+
 #if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0
     if (module_inst->func_type_indexes)
         wasm_runtime_free(module_inst->func_type_indexes);
@@ -1937,9 +2164,6 @@ wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst)
     wasm_externref_cleanup((WASMModuleInstanceCommon *)module_inst);
 #endif
 
-    if (module_inst->exec_env_singleton)
-        wasm_exec_env_destroy(module_inst->exec_env_singleton);
-
 #if WASM_ENABLE_DUMP_CALL_STACK != 0
     if (module_inst->frames) {
         bh_vector_destroy(module_inst->frames);
@@ -1948,39 +2172,17 @@ wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst)
     }
 #endif
 
-#if WASM_ENABLE_DEBUG_INTERP != 0                         \
-    || (WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \
-        && WASM_ENABLE_LAZY_JIT != 0)
-    if (!is_sub_inst) {
-        WASMModule *module = module_inst->module;
-        WASMModuleInstance *instance_prev = NULL, *instance;
-        os_mutex_lock(&module->instance_list_lock);
-
-        instance = module->instance_list;
-        while (instance) {
-            if (instance == module_inst) {
-                if (!instance_prev)
-                    module->instance_list = instance->e->next;
-                else
-                    instance_prev->e->next = instance->e->next;
-                break;
-            }
-            instance_prev = instance;
-            instance = instance->e->next;
-        }
+    if (module_inst->e->c_api_func_imports)
+        wasm_runtime_free(module_inst->e->c_api_func_imports);
 
-        os_mutex_unlock(&module->instance_list_lock);
+#if WASM_ENABLE_WASI_NN != 0
+    if (!is_sub_inst) {
+        WASINNContext *wasi_nn_ctx = module_inst->e->wasi_nn_ctx;
+        if (wasi_nn_ctx)
+            wasi_nn_destroy(wasi_nn_ctx);
     }
 #endif
 
-#if WASM_ENABLE_SHARED_MEMORY != 0
-    if (module_inst->e->mem_lock_inited)
-        os_mutex_destroy(&module_inst->e->mem_lock);
-#endif
-
-    if (module_inst->e->c_api_func_imports)
-        wasm_runtime_free(module_inst->e->c_api_func_imports);
-
     wasm_runtime_free(module_inst);
 }
 
@@ -2030,24 +2232,6 @@ wasm_lookup_table(const WASMModuleInstance *module_inst, const char *name)
 }
 #endif
 
-static bool
-clear_wasi_proc_exit_exception(WASMModuleInstance *module_inst)
-{
-#if WASM_ENABLE_LIBC_WASI != 0
-    const char *exception = wasm_get_exception(module_inst);
-    if (exception && !strcmp(exception, "Exception: wasi proc exit")) {
-        /* The "wasi proc exit" exception is thrown by native lib to
-           let wasm app exit, which is a normal behavior, we clear
-           the exception here. */
-        wasm_set_exception(module_inst, NULL);
-        return true;
-    }
-    return false;
-#else
-    return false;
-#endif
-}
-
 #ifdef OS_ENABLE_HW_BOUND_CHECK
 
 static void
@@ -2063,14 +2247,16 @@ call_wasm_with_hw_bound_check(WASMModuleInstance *module_inst,
     WASMRuntimeFrame *prev_frame = wasm_exec_env_get_cur_frame(exec_env);
     uint8 *prev_top = exec_env->wasm_stack.s.top;
 #ifdef BH_PLATFORM_WINDOWS
-    const char *exce;
     int result;
+    bool has_exception;
+    char exception[EXCEPTION_BUF_LEN];
 #endif
     bool ret = true;
 
     /* Check native stack overflow firstly to ensure we have enough
        native stack to run the following codes before actually calling
        the aot function in invokeNative function. */
+    RECORD_STACK_USAGE(exec_env, (uint8 *)&exec_env_tls);
     if ((uint8 *)&exec_env_tls < exec_env->native_stack_boundary
                                      + page_size * (guard_page_count + 1)) {
         wasm_set_exception(module_inst, "native stack overflow");
@@ -2096,14 +2282,14 @@ call_wasm_with_hw_bound_check(WASMModuleInstance *module_inst,
 #else
         __try {
             wasm_interp_call_wasm(module_inst, exec_env, function, argc, argv);
-        } __except (wasm_get_exception(module_inst)
+        } __except (wasm_copy_exception(module_inst, NULL)
                         ? EXCEPTION_EXECUTE_HANDLER
                         : EXCEPTION_CONTINUE_SEARCH) {
             /* exception was thrown in wasm_exception_handler */
             ret = false;
         }
-        if ((exce = wasm_get_exception(module_inst))
-            && strstr(exce, "native stack overflow")) {
+        has_exception = wasm_copy_exception(module_inst, exception);
+        if (has_exception && strstr(exception, "native stack overflow")) {
             /* After a stack overflow, the stack was left
                in a damaged state, let the CRT repair it */
             result = _resetstkoflw();
@@ -2157,8 +2343,7 @@ wasm_call_function(WASMExecEnv *exec_env, WASMFunctionInstance *function,
     wasm_exec_env_set_thread_info(exec_env);
 
     interp_call_wasm(module_inst, exec_env, function, argc, argv);
-    (void)clear_wasi_proc_exit_exception(module_inst);
-    return !wasm_get_exception(module_inst) ? true : false;
+    return !wasm_copy_exception(module_inst, NULL);
 }
 
 bool
@@ -2185,7 +2370,7 @@ wasm_create_exec_env_and_call_function(WASMModuleInstance *module_inst,
         }
     }
 
-    ret = wasm_call_function(exec_env, func, argc, argv);
+    ret = wasm_runtime_call_wasm(exec_env, func, argc, argv);
 
     /* don't destroy the exec_env if it isn't created in this function */
     if (!existing_exec_env)
@@ -2331,6 +2516,12 @@ wasm_module_free(WASMModuleInstance *module_inst, uint32 ptr)
             return;
         }
 
+#if WASM_ENABLE_SHARED_MEMORY != 0
+        WASMSharedMemNode *node = wasm_module_get_shared_memory(
+            (WASMModuleCommon *)module_inst->module);
+        if (node)
+            os_mutex_lock(&node->shared_mem_lock);
+#endif
         addr = memory->memory_data + ptr;
 
         if (memory->heap_handle && memory->heap_data <= addr
@@ -2343,6 +2534,10 @@ wasm_module_free(WASMModuleInstance *module_inst, uint32 ptr)
             execute_free_function(module_inst, module_inst->e->free_function,
                                   ptr);
         }
+#if WASM_ENABLE_SHARED_MEMORY != 0
+        if (node)
+            os_mutex_unlock(&node->shared_mem_lock);
+#endif
     }
 }
 
@@ -2455,8 +2650,7 @@ call_indirect(WASMExecEnv *exec_env, uint32 tbl_idx, uint32 elem_idx,
 
     interp_call_wasm(module_inst, exec_env, func_inst, argc, argv);
 
-    (void)clear_wasi_proc_exit_exception(module_inst);
-    return !wasm_get_exception(module_inst) ? true : false;
+    return !wasm_copy_exception(module_inst, NULL);
 
 got_exception:
     return false;
@@ -2476,14 +2670,16 @@ wasm_set_aux_stack(WASMExecEnv *exec_env, uint32 start_offset, uint32 size)
     WASMModuleInstance *module_inst =
         (WASMModuleInstance *)exec_env->module_inst;
     uint32 stack_top_idx = module_inst->module->aux_stack_top_global_index;
+
+#if WASM_ENABLE_HEAP_AUX_STACK_ALLOCATION == 0
+    /* Check the aux stack space */
     uint32 data_end = module_inst->module->aux_data_end;
     uint32 stack_bottom = module_inst->module->aux_stack_bottom;
     bool is_stack_before_data = stack_bottom < data_end ? true : false;
-
-    /* Check the aux stack space, currently we don't allocate space in heap */
     if ((is_stack_before_data && (size > start_offset))
         || ((!is_stack_before_data) && (start_offset - data_end < size)))
         return false;
+#endif
 
     if (stack_top_idx != (uint32)-1) {
         /* The aux stack top is a wasm global,
@@ -2905,8 +3101,14 @@ llvm_jit_invoke_native(WASMExecEnv *exec_env, uint32 func_idx, uint32 argc,
 
     import_func = &module->import_functions[func_idx].u.function;
     if (import_func->call_conv_wasm_c_api) {
-        c_api_func_import = module_inst->e->c_api_func_imports + func_idx;
-        func_ptr = c_api_func_import->func_ptr_linked;
+        if (module_inst->e->c_api_func_imports) {
+            c_api_func_import = module_inst->e->c_api_func_imports + func_idx;
+            func_ptr = c_api_func_import->func_ptr_linked;
+        }
+        else {
+            c_api_func_import = NULL;
+            func_ptr = NULL;
+        }
     }
 
     if (!func_ptr) {

+ 32 - 12
core/iwasm/interpreter/wasm_runtime.h

@@ -11,10 +11,16 @@
 #include "../common/wasm_runtime_common.h"
 #include "../common/wasm_exec_env.h"
 
+#if WASM_ENABLE_WASI_NN != 0
+#include "../libraries/wasi-nn/src/wasi_nn_private.h"
+#endif
+
 #ifdef __cplusplus
 extern "C" {
 #endif
 
+#define EXCEPTION_BUF_LEN 128
+
 typedef struct WASMModuleInstance WASMModuleInstance;
 typedef struct WASMFunctionInstance WASMFunctionInstance;
 typedef struct WASMMemoryInstance WASMMemoryInstance;
@@ -59,9 +65,7 @@ typedef enum WASMExceptionID {
     EXCE_AUX_STACK_UNDERFLOW,
     EXCE_OUT_OF_BOUNDS_TABLE_ACCESS,
     EXCE_OPERAND_STACK_OVERFLOW,
-#if WASM_ENABLE_FAST_JIT != 0
     EXCE_FAILED_TO_COMPILE_FAST_JIT_FUNC,
-#endif
     EXCE_ALREADY_THROWN,
     EXCE_NUM,
 } WASMExceptionID;
@@ -219,12 +223,7 @@ typedef struct WASMModuleInstanceExtra {
     WASMFunctionInstance *retain_function;
 
     CApiFuncImport *c_api_func_imports;
-
-#if WASM_ENABLE_SHARED_MEMORY != 0
-    /* lock for shared memory atomic operations */
-    korp_mutex mem_lock;
-    bool mem_lock_inited;
-#endif
+    RunningMode running_mode;
 
 #if WASM_ENABLE_MULTI_MODULE != 0
     bh_list sub_module_inst_list_head;
@@ -237,11 +236,15 @@ typedef struct WASMModuleInstanceExtra {
     uint32 max_aux_stack_used;
 #endif
 
-#if WASM_ENABLE_DEBUG_INTERP != 0                    \
-    || (WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT \
+#if WASM_ENABLE_DEBUG_INTERP != 0                         \
+    || (WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \
         && WASM_ENABLE_LAZY_JIT != 0)
     WASMModuleInstance *next;
 #endif
+
+#if WASM_ENABLE_WASI_NN != 0
+    WASINNContext *wasi_nn_ctx;
+#endif
 } WASMModuleInstanceExtra;
 
 struct AOTFuncPerfProfInfo;
@@ -281,7 +284,7 @@ struct WASMModuleInstance {
     DefPointer(WASMExportTabInstance *, export_tables);
 
     /* The exception buffer of wasm interpreter for current thread. */
-    char cur_exception[128];
+    char cur_exception[EXCEPTION_BUF_LEN];
 
     /* The WASM module or AOT module, for AOTModuleInstance,
        it denotes `AOTModule *` */
@@ -298,7 +301,11 @@ struct WASMModuleInstance {
        not available in AOTModuleInstance */
     DefPointer(void **, import_func_ptrs);
     /* Array of function pointers to fast jit functions,
-       not available in AOTModuleInstance */
+       not available in AOTModuleInstance:
+       Only when the multi-tier JIT macros are all enabled and the running
+       mode of current module instance is set to Mode_Fast_JIT, runtime
+       will allocate new memory for it, otherwise it always points to the
+       module->fast_jit_func_ptrs */
     DefPointer(void **, fast_jit_func_ptrs);
     /* The custom data that can be set/get by wasm_{get|set}_custom_data */
     DefPointer(void *, custom_data);
@@ -402,6 +409,10 @@ wasm_dump_perf_profiling(const WASMModuleInstance *module_inst);
 void
 wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst);
 
+bool
+wasm_set_running_mode(WASMModuleInstance *module_inst,
+                      RunningMode running_mode);
+
 WASMFunctionInstance *
 wasm_lookup_function(const WASMModuleInstance *module_inst, const char *name,
                      const char *signature);
@@ -435,6 +446,15 @@ wasm_set_exception_with_id(WASMModuleInstance *module_inst, uint32 id);
 const char *
 wasm_get_exception(WASMModuleInstance *module);
 
+/**
+ * @brief Copy exception in buffer passed as parameter. Thread-safe version of
+ * `wasm_get_exception()`
+ * @note Buffer size must be no smaller than EXCEPTION_BUF_LEN
+ * @return true if exception found
+ */
+bool
+wasm_copy_exception(WASMModuleInstance *module_inst, char *exception_buf);
+
 uint32
 wasm_module_malloc(WASMModuleInstance *module_inst, uint32 size,
                    void **p_native_addr);

+ 45 - 13
core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c

@@ -46,10 +46,6 @@
     wasm_runtime_addr_native_to_app(module_inst, ptr)
 /* clang-format on */
 
-extern bool
-wasm_runtime_call_indirect(wasm_exec_env_t exec_env, uint32 element_indices,
-                           uint32 argc, uint32 argv[]);
-
 enum {
     T_THREAD,
     T_MUTEX,
@@ -494,7 +490,6 @@ pthread_start_routine(void *arg)
 {
     wasm_exec_env_t exec_env = (wasm_exec_env_t)arg;
     wasm_exec_env_t parent_exec_env;
-    wasm_module_inst_t module_inst = get_module_inst(exec_env);
     ThreadRoutineArgs *routine_args = exec_env->thread_arg;
     ThreadInfoNode *info_node = routine_args->info_node;
     uint32 argv[1];
@@ -504,7 +499,6 @@ pthread_start_routine(void *arg)
     info_node->exec_env = exec_env;
     info_node->u.thread = exec_env->handle;
     if (!append_thread_info_node(info_node)) {
-        wasm_runtime_deinstantiate_internal(module_inst, true);
         delete_thread_info_node(info_node);
         os_cond_signal(&parent_exec_env->wait_cond);
         os_mutex_unlock(&parent_exec_env->wait_lock);
@@ -520,16 +514,12 @@ pthread_start_routine(void *arg)
 
     if (!wasm_runtime_call_indirect(exec_env, routine_args->elem_index, 1,
                                     argv)) {
-        if (wasm_runtime_get_exception(module_inst))
-            wasm_cluster_spread_exception(exec_env);
+        /* Exception has already been spread during throwing */
     }
 
     /* destroy pthread key values */
     call_key_destructor(exec_env);
 
-    /* routine exit, destroy instance */
-    wasm_runtime_deinstantiate_internal(module_inst, true);
-
     wasm_runtime_free(routine_args);
 
     /* if the thread is joinable, store the result in its info node,
@@ -571,6 +561,7 @@ pthread_create_wrapper(wasm_exec_env_t exec_env,
 #if WASM_ENABLE_LIBC_WASI != 0
     WASIContext *wasi_ctx;
 #endif
+    CApiFuncImport **new_c_api_func_imports = NULL;
 
     bh_assert(module);
     bh_assert(module_inst);
@@ -603,6 +594,46 @@ pthread_create_wrapper(wasm_exec_env_t exec_env,
         wasm_runtime_set_wasi_ctx(new_module_inst, wasi_ctx);
 #endif
 
+    /* workaround about passing instantiate-linking information */
+    {
+        CApiFuncImport *c_api_func_imports;
+        uint32 import_func_count = 0;
+        uint32 size_in_bytes = 0;
+
+#if WASM_ENABLE_INTERP != 0
+        if (module_inst->module_type == Wasm_Module_Bytecode) {
+            new_c_api_func_imports = &(
+                ((WASMModuleInstance *)new_module_inst)->e->c_api_func_imports);
+            c_api_func_imports =
+                ((WASMModuleInstance *)module_inst)->e->c_api_func_imports;
+            import_func_count = ((WASMModule *)module)->import_function_count;
+        }
+#endif
+#if WASM_ENABLE_AOT != 0
+        if (module_inst->module_type == Wasm_Module_AoT) {
+            AOTModuleInstanceExtra *e =
+                (AOTModuleInstanceExtra *)((AOTModuleInstance *)new_module_inst)
+                    ->e;
+            new_c_api_func_imports = &(e->c_api_func_imports);
+
+            e = (AOTModuleInstanceExtra *)((AOTModuleInstance *)module_inst)->e;
+            c_api_func_imports = e->c_api_func_imports;
+
+            import_func_count = ((AOTModule *)module)->import_func_count;
+        }
+#endif
+
+        if (import_func_count != 0 && c_api_func_imports) {
+            size_in_bytes = sizeof(CApiFuncImport *) * import_func_count;
+            *new_c_api_func_imports = wasm_runtime_malloc(size_in_bytes);
+            if (!(*new_c_api_func_imports))
+                goto fail;
+
+            bh_memcpy_s(*new_c_api_func_imports, size_in_bytes,
+                        c_api_func_imports, size_in_bytes);
+        }
+    }
+
     if (!(info_node = wasm_runtime_malloc(sizeof(ThreadInfoNode))))
         goto fail;
 
@@ -623,8 +654,9 @@ pthread_create_wrapper(wasm_exec_env_t exec_env,
     routine_args->module_inst = new_module_inst;
 
     os_mutex_lock(&exec_env->wait_lock);
-    ret = wasm_cluster_create_thread(
-        exec_env, new_module_inst, pthread_start_routine, (void *)routine_args);
+    ret =
+        wasm_cluster_create_thread(exec_env, new_module_inst, true,
+                                   pthread_start_routine, (void *)routine_args);
     if (ret != 0) {
         os_mutex_unlock(&exec_env->wait_lock);
         goto fail;

+ 27 - 0
core/iwasm/libraries/lib-socket/test/build.sh

@@ -0,0 +1,27 @@
+#!/bin/bash
+
+# Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+set -ueo pipefail
+CC="${CC:=/opt/wasi-sdk/bin/clang}"
+files=("tcp_udp.c" "nslookup.c")
+WASI_SYSROOT=${WASI_SYSROOT:=~/dev/wasi-libc/sysroot}
+
+for file in "${files[@]}"
+do
+    echo $file
+    $CC \
+        --target=wasm32-wasi-threads \
+        -I../inc \
+        --sysroot $WASI_SYSROOT \
+        ../src/wasi/wasi_socket_ext.c -pthread -ftls-model=local-exec \
+        -Wl,--allow-undefined \
+        -Wl,--strip-all,--no-entry \
+        -Wl,--export=__heap_base \
+        -Wl,--export=__data_end \
+        -Wl,--shared-memory,--max-memory=10485760 \
+        -Wl,--export=malloc \
+        -Wl,--export=free \
+        -o "${file%.*}.wasm" "$file"
+done

+ 49 - 0
core/iwasm/libraries/lib-socket/test/nslookup.c

@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#include <assert.h>
+#include <string.h>
+#ifdef __wasi__
+#include <wasi/api.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <wasi_socket_ext.h>
+#else
+#include <netdb.h>
+#endif
+
+void
+test_nslookup(int af)
+{
+    struct addrinfo *res;
+    int count = 0;
+    struct addrinfo hints;
+    char *url = "google-public-dns-a.google.com";
+
+    memset(&hints, 0, sizeof(hints));
+    hints.ai_family = af;
+    hints.ai_socktype = SOCK_STREAM;
+    int ret = getaddrinfo(url, 0, &hints, &res);
+    assert(ret == 0);
+    struct addrinfo *address = res;
+    while (address) {
+        assert(address->ai_family == af);
+        assert(address->ai_socktype == SOCK_STREAM);
+        count++;
+        address = address->ai_next;
+    }
+
+    assert(count > 0);
+    freeaddrinfo(res);
+}
+
+int
+main()
+{
+    test_nslookup(AF_INET);  /* for ipv4 */
+    test_nslookup(AF_INET6); /* for ipv6 */
+
+    return 0;
+}

+ 193 - 0
core/iwasm/libraries/lib-socket/test/tcp_udp.c

@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+#include <unistd.h>
+#include <string.h>
+#include <assert.h>
+#ifdef __wasi__
+#include <wasi/api.h>
+#include <sys/socket.h>
+#include <wasi_socket_ext.h>
+#endif
+#include <arpa/inet.h>
+#include <pthread.h>
+#define SERVER_MSG "Message from server."
+#define PORT 8989
+pthread_mutex_t mut;
+pthread_cond_t cond;
+int server_init_complete = 0;
+char buffer[sizeof(SERVER_MSG) + 1];
+
+struct socket_info {
+    union {
+        struct sockaddr_in addr_ipv4;
+        struct sockaddr_in6 addr_ipv6;
+    } addr;
+    int sock;
+};
+
+struct thread_args {
+    int family;
+    int protocol;
+};
+
+struct socket_info
+init_socket_addr(int family, int protocol)
+{
+    int sock = socket(family, protocol, 0);
+    assert(sock != -1);
+
+    struct socket_info info;
+    if (family == AF_INET) {
+        struct sockaddr_in addr;
+        memset(&addr, 0, sizeof(addr));
+        addr.sin_family = AF_INET;
+        addr.sin_port = htons(PORT);
+        addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+        info.addr.addr_ipv4 = addr;
+    }
+    else if (family == AF_INET6) {
+        struct sockaddr_in6 addr;
+        memset(&addr, 0, sizeof(addr));
+        addr.sin6_family = AF_INET6;
+        addr.sin6_port = htons(PORT);
+        addr.sin6_addr = in6addr_loopback;
+        info.addr.addr_ipv6 = addr;
+    }
+    info.sock = sock;
+    return info;
+}
+
+void
+assert_thread_args(struct thread_args *args)
+{
+    assert(args->family == AF_INET || args->family == AF_INET6);
+    assert(args->protocol == SOCK_STREAM || args->protocol == SOCK_DGRAM);
+}
+
+void *
+server(void *arg)
+{
+    server_init_complete = 0;
+    struct thread_args *args = (struct thread_args *)arg;
+    assert_thread_args(args);
+
+    struct socket_info init_server_sock =
+        init_socket_addr(args->family, args->protocol);
+
+    int server_sock = init_server_sock.sock;
+    socklen_t addr_size;
+    struct sockaddr_storage client_addr;
+    strcpy(buffer, SERVER_MSG);
+
+    struct sockaddr *server_addr = (struct sockaddr *)&init_server_sock.addr;
+    int ret = bind(server_sock, server_addr,
+                   args->family == AF_INET ? sizeof(struct sockaddr_in)
+                                           : sizeof(struct sockaddr_in6));
+    assert(ret == 0);
+
+    (args->protocol == SOCK_STREAM) && listen(server_sock, 1);
+    pthread_mutex_lock(&mut);
+    server_init_complete = 1;
+    pthread_mutex_unlock(&mut);
+    pthread_cond_signal(&cond);
+
+    addr_size = sizeof(client_addr);
+    if (args->protocol == SOCK_STREAM) {
+        int client_sock =
+            accept(server_sock, (struct sockaddr *)&client_addr, &addr_size);
+        assert(client_sock >= 0);
+        sendto(client_sock, buffer, strlen(buffer), 0,
+               (struct sockaddr *)&client_addr, addr_size);
+
+        assert(close(client_sock) == 0);
+    }
+    else {
+        recvfrom(server_sock, buffer, sizeof(buffer), 0,
+                 (struct sockaddr *)&client_addr, &addr_size);
+        sendto(server_sock, buffer, strlen(buffer), 0,
+               (struct sockaddr *)&client_addr, addr_size);
+
+        assert(close(server_sock) == 0);
+    }
+
+    return NULL;
+}
+
+void *
+client(void *arg)
+{
+    struct thread_args *args = (struct thread_args *)arg;
+    assert_thread_args(args);
+
+    pthread_mutex_lock(&mut);
+
+    while (server_init_complete == 0) {
+        pthread_cond_wait(&cond, &mut);
+    }
+
+    struct socket_info init_client_sock =
+        init_socket_addr(args->family, args->protocol);
+    int sock = init_client_sock.sock;
+    pthread_mutex_unlock(&mut);
+
+    if (args->family == AF_INET) {
+        struct sockaddr_in addr = init_client_sock.addr.addr_ipv4;
+        if (args->protocol == SOCK_STREAM) {
+            assert(connect(sock, (struct sockaddr *)&addr, sizeof(addr)) != -1);
+        }
+        else {
+            assert(sendto(sock, buffer, strlen(buffer), 0,
+                          (struct sockaddr *)&addr, sizeof(addr))
+                   != -1);
+        }
+    }
+    else {
+        struct sockaddr_in6 addr = init_client_sock.addr.addr_ipv6;
+        if (args->protocol == SOCK_STREAM) {
+            assert(connect(sock, (struct sockaddr *)&addr, sizeof(addr)) != -1);
+        }
+        else {
+            assert(sendto(sock, buffer, strlen(buffer), 0,
+                          (struct sockaddr *)&addr, sizeof(addr))
+                   != -1);
+        }
+    }
+
+    recv(sock, buffer, sizeof(buffer), 0);
+    assert(strcmp(buffer, SERVER_MSG) == 0);
+    assert(close(sock) == 0);
+    return NULL;
+}
+
+void
+test_protocol(int family, int protocol)
+{
+    pthread_t server_thread, client_thread;
+    assert(pthread_cond_init(&cond, NULL) == 0);
+    assert(pthread_mutex_init(&mut, NULL) == 0);
+
+    struct thread_args args = { family, protocol };
+    assert(pthread_create(&server_thread, NULL, server, (void *)&args) == 0);
+    assert(pthread_create(&client_thread, NULL, client, (void *)&args) == 0);
+    assert(pthread_join(server_thread, NULL) == 0);
+    assert(pthread_join(client_thread, NULL) == 0);
+
+    assert(pthread_mutex_destroy(&mut) == 0);
+    assert(pthread_cond_destroy(&cond) == 0);
+}
+
+int
+main(int argc, char **argv)
+{
+    /* test tcp with ipv4 and ipv6 */
+    test_protocol(AF_INET, SOCK_STREAM);
+    test_protocol(AF_INET6, SOCK_STREAM);
+
+    /* test udp with ipv4 and ipv6 */
+    test_protocol(AF_INET, SOCK_DGRAM);
+    test_protocol(AF_INET6, SOCK_DGRAM);
+
+    return 0;
+}

+ 12 - 0
core/iwasm/libraries/lib-wasi-threads/lib_wasi_threads.cmake

@@ -0,0 +1,12 @@
+# Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+set (LIB_WASI_THREADS_DIR ${CMAKE_CURRENT_LIST_DIR})
+
+add_definitions (-DWASM_ENABLE_LIB_WASI_THREADS=1 -DWASM_ENABLE_HEAP_AUX_STACK_ALLOCATION=1)
+
+include_directories(${LIB_WASI_THREADS_DIR})
+
+set (LIB_WASI_THREADS_SOURCE
+    ${LIB_WASI_THREADS_DIR}/lib_wasi_threads_wrapper.c
+    ${LIB_WASI_THREADS_DIR}/tid_allocator.c)

+ 181 - 0
core/iwasm/libraries/lib-wasi-threads/lib_wasi_threads_wrapper.c

@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#include "bh_log.h"
+#include "thread_manager.h"
+#include "tid_allocator.h"
+
+#if WASM_ENABLE_INTERP != 0
+#include "wasm_runtime.h"
+#endif
+
+#if WASM_ENABLE_AOT != 0
+#include "aot_runtime.h"
+#endif
+
+static const char *THREAD_START_FUNCTION = "wasi_thread_start";
+static korp_mutex thread_id_lock;
+static TidAllocator tid_allocator;
+
+typedef struct {
+    /* app's entry function */
+    wasm_function_inst_t start_func;
+    /* arg of the app's entry function */
+    uint32 arg;
+    /* thread id passed to the app */
+    int32 thread_id;
+} ThreadStartArg;
+
+static int32
+allocate_thread_id()
+{
+    os_mutex_lock(&thread_id_lock);
+    int32 id = tid_allocator_get_tid(&tid_allocator);
+    os_mutex_unlock(&thread_id_lock);
+
+    return id;
+}
+
+void
+deallocate_thread_id(int32 thread_id)
+{
+    os_mutex_lock(&thread_id_lock);
+    tid_allocator_release_tid(&tid_allocator, thread_id);
+    os_mutex_unlock(&thread_id_lock);
+}
+
+static void *
+thread_start(void *arg)
+{
+    wasm_exec_env_t exec_env = (wasm_exec_env_t)arg;
+    ThreadStartArg *thread_arg = exec_env->thread_arg;
+    uint32 argv[2];
+
+    wasm_exec_env_set_thread_info(exec_env);
+    argv[0] = thread_arg->thread_id;
+    argv[1] = thread_arg->arg;
+
+    if (!wasm_runtime_call_wasm(exec_env, thread_arg->start_func, 2, argv)) {
+        /* Exception has already been spread during throwing */
+    }
+
+    // Routine exit
+    deallocate_thread_id(thread_arg->thread_id);
+    wasm_runtime_free(thread_arg);
+    exec_env->thread_arg = NULL;
+
+    return NULL;
+}
+
+static int32
+thread_spawn_wrapper(wasm_exec_env_t exec_env, uint32 start_arg)
+{
+    wasm_module_t module = wasm_exec_env_get_module(exec_env);
+    wasm_module_inst_t module_inst = get_module_inst(exec_env);
+    wasm_module_inst_t new_module_inst = NULL;
+    ThreadStartArg *thread_start_arg = NULL;
+    wasm_function_inst_t start_func;
+    int32 thread_id;
+    uint32 stack_size = 8192;
+    int32 ret = -1;
+#if WASM_ENABLE_LIBC_WASI != 0
+    WASIContext *wasi_ctx;
+#endif
+
+    bh_assert(module);
+    bh_assert(module_inst);
+
+    stack_size = ((WASMModuleInstance *)module_inst)->default_wasm_stack_size;
+
+    if (!(new_module_inst = wasm_runtime_instantiate_internal(
+              module, true, stack_size, 0, NULL, 0)))
+        return -1;
+
+    wasm_runtime_set_custom_data_internal(
+        new_module_inst, wasm_runtime_get_custom_data(module_inst));
+
+#if WASM_ENABLE_LIBC_WASI != 0
+    wasi_ctx = wasm_runtime_get_wasi_ctx(module_inst);
+    if (wasi_ctx)
+        wasm_runtime_set_wasi_ctx(new_module_inst, wasi_ctx);
+#endif
+
+    start_func = wasm_runtime_lookup_function(new_module_inst,
+                                              THREAD_START_FUNCTION, NULL);
+    if (!start_func) {
+        LOG_ERROR("Failed to find thread start function %s",
+                  THREAD_START_FUNCTION);
+        goto thread_preparation_fail;
+    }
+
+    if (!(thread_start_arg = wasm_runtime_malloc(sizeof(ThreadStartArg)))) {
+        LOG_ERROR("Runtime args allocation failed");
+        goto thread_preparation_fail;
+    }
+
+    thread_start_arg->thread_id = thread_id = allocate_thread_id();
+    if (thread_id < 0) {
+        LOG_ERROR("Failed to get thread identifier");
+        goto thread_preparation_fail;
+    }
+    thread_start_arg->arg = start_arg;
+    thread_start_arg->start_func = start_func;
+
+    ret = wasm_cluster_create_thread(exec_env, new_module_inst, false,
+                                     thread_start, thread_start_arg);
+    if (ret != 0) {
+        LOG_ERROR("Failed to spawn a new thread");
+        goto thread_spawn_fail;
+    }
+
+    return thread_id;
+
+thread_spawn_fail:
+    deallocate_thread_id(thread_id);
+
+thread_preparation_fail:
+    if (new_module_inst)
+        wasm_runtime_deinstantiate_internal(new_module_inst, true);
+    if (thread_start_arg)
+        wasm_runtime_free(thread_start_arg);
+
+    return -1;
+}
+
+/* clang-format off */
+#define REG_NATIVE_FUNC(name, func_name, signature) \
+    { name, func_name##_wrapper, signature, NULL }
+/* clang-format on */
+
+static NativeSymbol native_symbols_lib_wasi_threads[] = { REG_NATIVE_FUNC(
+    "thread-spawn", thread_spawn, "(i)i") };
+
+uint32
+get_lib_wasi_threads_export_apis(NativeSymbol **p_lib_wasi_threads_apis)
+{
+    *p_lib_wasi_threads_apis = native_symbols_lib_wasi_threads;
+    return sizeof(native_symbols_lib_wasi_threads) / sizeof(NativeSymbol);
+}
+
+bool
+lib_wasi_threads_init(void)
+{
+    if (0 != os_mutex_init(&thread_id_lock))
+        return false;
+
+    if (!tid_allocator_init(&tid_allocator)) {
+        os_mutex_destroy(&thread_id_lock);
+        return false;
+    }
+
+    return true;
+}
+
+void
+lib_wasi_threads_destroy(void)
+{
+    tid_allocator_deinit(&tid_allocator);
+    os_mutex_destroy(&thread_id_lock);
+}

+ 30 - 0
core/iwasm/libraries/lib-wasi-threads/test/build.sh

@@ -0,0 +1,30 @@
+#!/bin/bash
+
+#
+# Copyright (C) 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+#
+
+CC=${CC:=/opt/wasi-sdk/bin/clang}
+WASI_SYSROOT=${WASI_SYSROOT:=~/dev/wasi-libc/sysroot}
+WAMR_DIR=../../../../..
+
+for test_c in *.c; do
+    test_wasm="$(basename $test_c .c).wasm"
+
+    echo "Compiling $test_c to $test_wasm"
+    $CC \
+        --sysroot $WASI_SYSROOT \
+        -target wasm32-wasi-threads \
+        -pthread -ftls-model=local-exec \
+        -z stack-size=32768 \
+        -Wl,--export=__heap_base \
+        -Wl,--export=__data_end \
+        -Wl,--shared-memory,--max-memory=1966080 \
+        -Wl,--export=wasi_thread_start \
+        -Wl,--export=malloc \
+        -Wl,--export=free \
+        -I $WAMR_DIR/samples/wasi-threads/wasm-apps \
+        $WAMR_DIR/samples/wasi-threads/wasm-apps/wasi_thread_start.S \
+        $test_c -o $test_wasm
+done

+ 122 - 0
core/iwasm/libraries/lib-wasi-threads/test/common.h

@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2022 Amazon.com Inc. or its affiliates. All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <unistd.h>
+
+#include "wasi_thread_start.h"
+
+typedef enum {
+    BLOCKING_TASK_BUSY_WAIT,
+    BLOCKING_TASK_ATOMIC_WAIT,
+    BLOCKING_TASK_POLL_ONEOFF
+} blocking_task_type_t;
+
+/* Parameter to change test behavior */
+static bool termination_by_trap;
+static bool termination_in_main_thread;
+static blocking_task_type_t blocking_task_type;
+
+#define TIMEOUT_SECONDS 10ll
+#define NUM_THREADS 3
+static pthread_barrier_t barrier;
+
+typedef struct {
+    start_args_t base;
+    bool throw_exception;
+} shared_t;
+
+void
+run_long_task()
+{
+    if (blocking_task_type == BLOCKING_TASK_BUSY_WAIT) {
+        for (int i = 0; i < TIMEOUT_SECONDS; i++)
+            sleep(1);
+    }
+    else if (blocking_task_type == BLOCKING_TASK_ATOMIC_WAIT) {
+        __builtin_wasm_memory_atomic_wait32(
+            0, 0, TIMEOUT_SECONDS * 1000 * 1000 * 1000);
+    }
+    else {
+        sleep(TIMEOUT_SECONDS);
+    }
+}
+
+void
+start_job()
+{
+    /* Wait for all threads (including the main thread) to be ready */
+    pthread_barrier_wait(&barrier);
+    run_long_task(); /* Task to be interrupted */
+    assert(false && "Thread termination test failed");
+}
+
+void
+terminate_process()
+{
+    /* Wait for all threads (including the main thread) to be ready */
+    pthread_barrier_wait(&barrier);
+
+    if (termination_by_trap)
+        __builtin_trap();
+    else
+        __wasi_proc_exit(33);
+}
+
+void
+__wasi_thread_start_C(int thread_id, int *start_arg)
+{
+    shared_t *data = (shared_t *)start_arg;
+
+    if (data->throw_exception) {
+        terminate_process();
+    }
+    else {
+        start_job();
+    }
+}
+
+void
+test_termination(bool trap, bool main, blocking_task_type_t task_type)
+{
+    termination_by_trap = trap;
+    termination_in_main_thread = main;
+    blocking_task_type = task_type;
+
+    int thread_id = -1, i;
+    shared_t data[NUM_THREADS] = { 0 };
+    assert(pthread_barrier_init(&barrier, NULL, NUM_THREADS + 1) == 0
+           && "Failed to init barrier");
+
+    for (i = 0; i < NUM_THREADS; i++) {
+        /* No graceful memory free to simplify the test */
+        assert(start_args_init(&data[i].base)
+               && "Failed to allocate thread's stack");
+    }
+
+    /* Create a thread that forces termination through trap or `proc_exit` */
+    data[0].throw_exception = !termination_in_main_thread;
+    thread_id = __wasi_thread_spawn(&data[0]);
+    assert(thread_id > 0 && "Failed to create thread");
+
+    /* Create two additional threads to test exception propagation */
+    data[1].throw_exception = false;
+    thread_id = __wasi_thread_spawn(&data[1]);
+    assert(thread_id > 0 && "Failed to create thread");
+    data[2].throw_exception = false;
+    thread_id = __wasi_thread_spawn(&data[2]);
+    assert(thread_id > 0 && "Failed to create thread");
+
+    if (termination_in_main_thread) {
+        terminate_process();
+    }
+    else {
+        start_job();
+    }
+}

+ 128 - 0
core/iwasm/libraries/lib-wasi-threads/test/create_threads_until_limit.c

@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#ifndef __wasi__
+#error This example only compiles to WASM/WASI target
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <stdbool.h>
+
+#include "wasi_thread_start.h"
+
+enum CONSTANTS {
+    MAX_NUM_THREADS = 4, /* Should be the same as "--max-threads" */
+    NUM_RETRY = 5,
+    SECOND = 1000 * 1000 * 1000, /* 1 second */
+    TIMEOUT = 10LL * SECOND
+};
+
+int g_count = 0;
+
+typedef struct {
+    start_args_t base;
+    int th_ready;
+    int th_continue;
+    int th_done;
+    bool no_ops;
+} shared_t;
+
+void
+__wasi_thread_start_C(int thread_id, int *start_arg)
+{
+    shared_t *data = (shared_t *)start_arg;
+
+    if (data->no_ops) {
+        __builtin_wasm_memory_atomic_wait32(NULL, 0, 2 * SECOND);
+        return;
+    }
+
+    __atomic_store_n(&data->th_ready, 1, __ATOMIC_SEQ_CST);
+    __builtin_wasm_memory_atomic_notify(&data->th_ready, 1);
+
+    if (__builtin_wasm_memory_atomic_wait32(&data->th_continue, 0, TIMEOUT)
+        == 2) {
+        assert(false && "Wait should not time out");
+    }
+
+    __atomic_fetch_add(&g_count, 1, __ATOMIC_SEQ_CST);
+
+    __atomic_store_n(&data->th_done, 1, __ATOMIC_SEQ_CST);
+    __builtin_wasm_memory_atomic_notify(&data->th_done, 1);
+}
+
+int
+main(int argc, char **argv)
+{
+    shared_t data[MAX_NUM_THREADS] = { 0 };
+    int thread_ids[MAX_NUM_THREADS];
+
+    for (int i = 0; i < MAX_NUM_THREADS; i++) {
+        assert(start_args_init(&data[i].base));
+        thread_ids[i] = __wasi_thread_spawn(&data[i]);
+        printf("Thread created with id=%d\n", thread_ids[i]);
+        assert(thread_ids[i] > 0 && "Thread creation failed");
+
+        for (int j = 0; j < i; j++) {
+            assert(thread_ids[i] != thread_ids[j] && "Duplicated TIDs");
+        }
+
+        if (__builtin_wasm_memory_atomic_wait32(&data[i].th_ready, 0, TIMEOUT)
+            == 2) {
+            assert(false && "Wait should not time out");
+        }
+    }
+
+    printf("Attempt to create thread when not possible\n");
+    shared_t data_fail = { 0 };
+    assert(start_args_init(&data_fail.base));
+    int thread_id = __wasi_thread_spawn(&data_fail);
+    start_args_deinit(&data_fail.base);
+    assert(thread_id < 0 && "Thread creation should fail");
+
+    printf("Unlock created threads\n");
+    for (int i = 0; i < MAX_NUM_THREADS; i++) {
+        __atomic_store_n(&data[i].th_continue, 1, __ATOMIC_SEQ_CST);
+        __builtin_wasm_memory_atomic_notify(&data[i].th_continue, 1);
+    }
+
+    printf("Wait for threads to finish\n");
+    for (int i = 0; i < MAX_NUM_THREADS; i++) {
+        if (__builtin_wasm_memory_atomic_wait32(&data[i].th_done, 0, TIMEOUT)
+            == 2) {
+            assert(false && "Wait should not time out");
+        }
+
+        start_args_deinit(&data[i].base);
+    }
+
+    printf("Value of count after update: %d\n", g_count);
+    assert(g_count == (MAX_NUM_THREADS)
+           && "Global count not updated correctly");
+
+    /* --------------------------------------------------- */
+
+    printf("Create new threads without waiting from them to finish\n");
+    shared_t data_no_join[MAX_NUM_THREADS] = { 0 };
+    for (int i = 0; i < MAX_NUM_THREADS; i++) {
+        /* No graceful memory free to simplify the test */
+        assert(start_args_init(&data_no_join[i].base));
+        data_no_join[i].no_ops = true;
+
+        int thread_id = -1;
+        for (int j = 0; j < NUM_RETRY && thread_id < 0; j++) {
+            thread_id = __wasi_thread_spawn(&data_no_join[i]);
+            if (thread_id < 0)
+                __builtin_wasm_memory_atomic_wait32(NULL, 0, SECOND);
+        }
+
+        printf("Thread created with id=%d\n", thread_id);
+        assert(thread_id > 0 && "Thread creation should succeed");
+    }
+
+    return EXIT_SUCCESS;
+}

+ 70 - 0
core/iwasm/libraries/lib-wasi-threads/test/global_atomic.c

@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#ifndef __wasi__
+#error This example only compiles to WASM/WASI target
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <stdbool.h>
+
+#include "wasi_thread_start.h"
+
+enum CONSTANTS {
+    NUM_THREADS = 4,
+    NUM_ITER = 1000,
+    SECOND = 1000 * 1000 * 1000, /* 1 second */
+    TIMEOUT = 10LL * SECOND
+};
+
+int g_count = 0;
+
+typedef struct {
+    start_args_t base;
+    int th_done;
+} shared_t;
+
+void
+__wasi_thread_start_C(int thread_id, int *start_arg)
+{
+    shared_t *data = (shared_t *)start_arg;
+
+    for (int i = 0; i < NUM_ITER; i++)
+        __atomic_fetch_add(&g_count, 1, __ATOMIC_SEQ_CST);
+
+    __atomic_store_n(&data->th_done, 1, __ATOMIC_SEQ_CST);
+    __builtin_wasm_memory_atomic_notify(&data->th_done, 1);
+}
+
+int
+main(int argc, char **argv)
+{
+    shared_t data[NUM_THREADS] = { 0 };
+    int thread_ids[NUM_THREADS];
+
+    for (int i = 0; i < NUM_THREADS; i++) {
+        assert(start_args_init(&data[i].base));
+        thread_ids[i] = __wasi_thread_spawn(&data[i]);
+        assert(thread_ids[i] > 0 && "Thread creation failed");
+    }
+
+    printf("Wait for threads to finish\n");
+    for (int i = 0; i < NUM_THREADS; i++) {
+        if (__builtin_wasm_memory_atomic_wait32(&data[i].th_done, 0, TIMEOUT)
+            == 2) {
+            assert(false && "Wait should not time out");
+        }
+
+        start_args_deinit(&data[i].base);
+    }
+
+    printf("Value of count after update: %d\n", g_count);
+    assert(g_count == (NUM_THREADS * NUM_ITER)
+           && "Global count not updated correctly");
+
+    return EXIT_SUCCESS;
+}

+ 78 - 0
core/iwasm/libraries/lib-wasi-threads/test/global_lock.c

@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#ifndef __wasi__
+#error This example only compiles to WASM/WASI target
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <stdbool.h>
+#include <pthread.h>
+
+#include "wasi_thread_start.h"
+
+enum CONSTANTS {
+    NUM_THREADS = 4,
+    NUM_ITER = 200,
+    SECOND = 1000 * 1000 * 1000, /* 1 second */
+    TIMEOUT = 10LL * SECOND
+};
+
+pthread_mutex_t mutex;
+int g_count = 0;
+
+typedef struct {
+    start_args_t base;
+    int th_done;
+} shared_t;
+
+void
+__wasi_thread_start_C(int thread_id, int *start_arg)
+{
+    shared_t *data = (shared_t *)start_arg;
+
+    for (int i = 0; i < NUM_ITER; i++) {
+        pthread_mutex_lock(&mutex);
+        g_count++;
+        pthread_mutex_unlock(&mutex);
+    }
+
+    __atomic_store_n(&data->th_done, 1, __ATOMIC_SEQ_CST);
+    __builtin_wasm_memory_atomic_notify(&data->th_done, 1);
+}
+
+int
+main(int argc, char **argv)
+{
+    shared_t data[NUM_THREADS] = { 0 };
+    int thread_ids[NUM_THREADS];
+
+    assert(pthread_mutex_init(&mutex, NULL) == 0 && "Failed to init mutex");
+
+    for (int i = 0; i < NUM_THREADS; i++) {
+        assert(start_args_init(&data[i].base));
+        thread_ids[i] = __wasi_thread_spawn(&data[i]);
+        assert(thread_ids[i] > 0 && "Thread creation failed");
+    }
+
+    printf("Wait for threads to finish\n");
+    for (int i = 0; i < NUM_THREADS; i++) {
+        if (__builtin_wasm_memory_atomic_wait32(&data[i].th_done, 0, TIMEOUT)
+            == 2) {
+            assert(false && "Wait should not time out");
+        }
+
+        start_args_deinit(&data[i].base);
+    }
+
+    printf("Value of count after update: %d\n", g_count);
+    assert(g_count == (NUM_THREADS * NUM_ITER)
+           && "Global count not updated correctly");
+
+    assert(pthread_mutex_destroy(&mutex) == 0 && "Failed to destroy mutex");
+    return EXIT_SUCCESS;
+}

+ 16 - 0
core/iwasm/libraries/lib-wasi-threads/test/main_proc_exit_busy.c

@@ -0,0 +1,16 @@
+/*
+ * Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#ifndef __wasi__
+#error This example only compiles to WASM/WASI target
+#endif
+
+#include "common.h"
+
+int
+main(int argc, char **argv)
+{
+    test_termination(false, true, BLOCKING_TASK_BUSY_WAIT);
+}

+ 3 - 0
core/iwasm/libraries/lib-wasi-threads/test/main_proc_exit_busy.json

@@ -0,0 +1,3 @@
+{
+    "exit_code": 33
+}

+ 16 - 0
core/iwasm/libraries/lib-wasi-threads/test/main_proc_exit_sleep.c

@@ -0,0 +1,16 @@
+/*
+ * Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#ifndef __wasi__
+#error This example only compiles to WASM/WASI target
+#endif
+
+#include "common.h"
+
+int
+main(int argc, char **argv)
+{
+    test_termination(false, true, BLOCKING_TASK_POLL_ONEOFF);
+}

+ 3 - 0
core/iwasm/libraries/lib-wasi-threads/test/main_proc_exit_sleep.json

@@ -0,0 +1,3 @@
+{
+    "exit_code": 33
+}

+ 16 - 0
core/iwasm/libraries/lib-wasi-threads/test/main_proc_exit_wait.c

@@ -0,0 +1,16 @@
+/*
+ * Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#ifndef __wasi__
+#error This example only compiles to WASM/WASI target
+#endif
+
+#include "common.h"
+
+int
+main(int argc, char **argv)
+{
+    test_termination(false, true, BLOCKING_TASK_ATOMIC_WAIT);
+}

+ 3 - 0
core/iwasm/libraries/lib-wasi-threads/test/main_proc_exit_wait.json

@@ -0,0 +1,3 @@
+{
+    "exit_code": 33
+}

+ 16 - 0
core/iwasm/libraries/lib-wasi-threads/test/main_trap_busy.c

@@ -0,0 +1,16 @@
+/*
+ * Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#ifndef __wasi__
+#error This example only compiles to WASM/WASI target
+#endif
+
+#include "common.h"
+
+int
+main(int argc, char **argv)
+{
+    test_termination(true, true, BLOCKING_TASK_BUSY_WAIT);
+}

+ 3 - 0
core/iwasm/libraries/lib-wasi-threads/test/main_trap_busy.json

@@ -0,0 +1,3 @@
+{
+    "exit_code": 1
+}

+ 16 - 0
core/iwasm/libraries/lib-wasi-threads/test/main_trap_sleep.c

@@ -0,0 +1,16 @@
+/*
+ * Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#ifndef __wasi__
+#error This example only compiles to WASM/WASI target
+#endif
+
+#include "common.h"
+
+int
+main(int argc, char **argv)
+{
+    test_termination(true, true, BLOCKING_TASK_POLL_ONEOFF);
+}

+ 3 - 0
core/iwasm/libraries/lib-wasi-threads/test/main_trap_sleep.json

@@ -0,0 +1,3 @@
+{
+    "exit_code": 1
+}

+ 16 - 0
core/iwasm/libraries/lib-wasi-threads/test/main_trap_wait.c

@@ -0,0 +1,16 @@
+/*
+ * Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#ifndef __wasi__
+#error This example only compiles to WASM/WASI target
+#endif
+
+#include "common.h"
+
+int
+main(int argc, char **argv)
+{
+    test_termination(true, true, BLOCKING_TASK_ATOMIC_WAIT);
+}

+ 3 - 0
core/iwasm/libraries/lib-wasi-threads/test/main_trap_wait.json

@@ -0,0 +1,3 @@
+{
+    "exit_code": 1
+}

+ 16 - 0
core/iwasm/libraries/lib-wasi-threads/test/nonmain_proc_exit_busy.c

@@ -0,0 +1,16 @@
+/*
+ * Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#ifndef __wasi__
+#error This example only compiles to WASM/WASI target
+#endif
+
+#include "common.h"
+
+int
+main(int argc, char **argv)
+{
+    test_termination(false, false, BLOCKING_TASK_BUSY_WAIT);
+}

+ 3 - 0
core/iwasm/libraries/lib-wasi-threads/test/nonmain_proc_exit_busy.json

@@ -0,0 +1,3 @@
+{
+    "exit_code": 33
+}

+ 16 - 0
core/iwasm/libraries/lib-wasi-threads/test/nonmain_proc_exit_sleep.c

@@ -0,0 +1,16 @@
+/*
+ * Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#ifndef __wasi__
+#error This example only compiles to WASM/WASI target
+#endif
+
+#include "common.h"
+
+int
+main(int argc, char **argv)
+{
+    test_termination(false, false, BLOCKING_TASK_POLL_ONEOFF);
+}

+ 3 - 0
core/iwasm/libraries/lib-wasi-threads/test/nonmain_proc_exit_sleep.json

@@ -0,0 +1,3 @@
+{
+    "exit_code": 33
+}

+ 16 - 0
core/iwasm/libraries/lib-wasi-threads/test/nonmain_proc_exit_wait.c

@@ -0,0 +1,16 @@
+/*
+ * Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#ifndef __wasi__
+#error This example only compiles to WASM/WASI target
+#endif
+
+#include "common.h"
+
+int
+main(int argc, char **argv)
+{
+    test_termination(false, false, BLOCKING_TASK_ATOMIC_WAIT);
+}

+ 3 - 0
core/iwasm/libraries/lib-wasi-threads/test/nonmain_proc_exit_wait.json

@@ -0,0 +1,3 @@
+{
+    "exit_code": 33
+}

+ 16 - 0
core/iwasm/libraries/lib-wasi-threads/test/nonmain_trap_busy.c

@@ -0,0 +1,16 @@
+/*
+ * Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#ifndef __wasi__
+#error This example only compiles to WASM/WASI target
+#endif
+
+#include "common.h"
+
+int
+main(int argc, char **argv)
+{
+    test_termination(true, false, BLOCKING_TASK_BUSY_WAIT);
+}

+ 3 - 0
core/iwasm/libraries/lib-wasi-threads/test/nonmain_trap_busy.json

@@ -0,0 +1,3 @@
+{
+    "exit_code": 1
+}

+ 16 - 0
core/iwasm/libraries/lib-wasi-threads/test/nonmain_trap_sleep.c

@@ -0,0 +1,16 @@
+/*
+ * Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#ifndef __wasi__
+#error This example only compiles to WASM/WASI target
+#endif
+
+#include "common.h"
+
+int
+main(int argc, char **argv)
+{
+    test_termination(true, false, BLOCKING_TASK_POLL_ONEOFF);
+}

+ 3 - 0
core/iwasm/libraries/lib-wasi-threads/test/nonmain_trap_sleep.json

@@ -0,0 +1,3 @@
+{
+    "exit_code": 1
+}

+ 16 - 0
core/iwasm/libraries/lib-wasi-threads/test/nonmain_trap_wait.c

@@ -0,0 +1,16 @@
+/*
+ * Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#ifndef __wasi__
+#error This example only compiles to WASM/WASI target
+#endif
+
+#include "common.h"
+
+int
+main(int argc, char **argv)
+{
+    test_termination(true, false, BLOCKING_TASK_ATOMIC_WAIT);
+}

+ 3 - 0
core/iwasm/libraries/lib-wasi-threads/test/nonmain_trap_wait.json

@@ -0,0 +1,3 @@
+{
+    "exit_code": 1
+}

Некоторые файлы не были показаны из-за большого количества измененных файлов