Kaynağa Gözat

Merge branch main into gitbook

Wenyong Huang 3 yıl önce
ebeveyn
işleme
426b8f8a8c
100 değiştirilmiş dosya ile 4404 ekleme ve 1222 silme
  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
 # hadolint ignore=DL3008
 RUN apt-get update \
 RUN apt-get update \
   && apt-get install -y apt-transport-https apt-utils build-essential \
   && 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 \
   libgcc-9-dev lib32gcc-9-dev lsb-release \
   ninja-build ocaml ocamlbuild python2.7 \
   ninja-build ocaml ocamlbuild python2.7 \
   software-properties-common tree tzdata \
   software-properties-common tree tzdata \
@@ -20,6 +20,15 @@ RUN apt-get update \
   && apt-get clean -y \
   && apt-get clean -y \
   && rm -rf /var/lib/apt/lists/*
   && 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/)
 # CMAKE (https://apt.kitware.com/)
 SHELL ["/bin/bash", "-o", "pipefail", "-c"]
 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 kitware-archive-keyring --no-install-recommends \
   && apt-get install -y cmake --no-install-recommends \
   && apt-get install -y cmake --no-install-recommends \
   && apt-get clean -y \
   && apt-get clean -y \
-  && rm -rf /var/lib/apt/lists/* 
+  && rm -rf /var/lib/apt/lists/*
 
 
 #
 #
 # install emsdk
 # install emsdk
 WORKDIR /opt
 WORKDIR /opt
 RUN git clone https://github.com/emscripten-core/emsdk.git
 RUN git clone https://github.com/emscripten-core/emsdk.git
 
 
+ARG EMSDK_VER=3.0.0
 WORKDIR /opt/emsdk
 WORKDIR /opt/emsdk
 RUN  git pull \
 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
   && echo "source /opt/emsdk/emsdk_env.sh" >> /root/.bashrc
 
 
 #
 #
 # install wasi-sdk
 # 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 \
 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 \
   && 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
   && 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
 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 \
 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 \
   && 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
   && rm /opt/wabt-${WABT_VER}-ubuntu.tar.gz
 
 
 #
 #
 # install bazelisk
 # install bazelisk
 ARG BAZELISK_VER=1.12.0
 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 \
   && 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 \
   && chmod a+x /opt/bazelisk/bazelisk-linux-amd64 \
   && ln -fs /opt/bazelisk/bazelisk-linux-amd64 /opt/bazelisk/bazel
   && ln -fs /opt/bazelisk/bazelisk-linux-amd64 /opt/bazelisk/bazel
 
 
 #
 #
 # install clang+llvm
 # 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
 WORKDIR /etc/apt/apt.conf.d
 RUN touch 99verfiy-peer.conf \
 RUN touch 99verfiy-peer.conf \
   && echo "Acquire { https::Verify-Peer false }" > 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 \
 RUN wget --progress=dot:giga https://apt.llvm.org/llvm.sh \
   && chmod a+x ./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]
 # [Optional]
@@ -96,17 +106,28 @@ RUN apt-get update \
 # Install required python packages
 # Install required python packages
 # hadolint ignore=DL3013
 # hadolint ignore=DL3013
 RUN python3 -m pip install --no-cache-dir --upgrade pip \
 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 autoremove -y \
   && apt-get clean -y \
   && apt-get clean -y \
   && rm -rf /var/lib/apt/lists/* \
   && rm -rf /var/lib/apt/lists/* \
   && rm -rf /tmp/*
   && rm -rf /tmp/*
 
 
 # set workdir when container run
 # 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.
 // Copyright (C) 2019 Intel Corporation.  All rights reserved.
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 // 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:
 // 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
 // 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
     // 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
     // Use Debian 11, Debian 9, Ubuntu 18.04 or Ubuntu 21.04 on local arm64/Apple Silicon
     "args": {
     "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": [
   "runArgs": [
@@ -27,12 +31,10 @@
       // Add the IDs of extensions you want installed when the container is created.
       // Add the IDs of extensions you want installed when the container is created.
       "extensions": [
       "extensions": [
         "dtsvet.vscode-wasm",
         "dtsvet.vscode-wasm",
-        "esbenp.prettier-vscode",
+        "llvm-vs-code-extensions.vscode-clangd",
         "ms-python.python",
         "ms-python.python",
         "ms-python.vscode-pylance",
         "ms-python.vscode-pylance",
         "ms-vscode.cmake-tools",
         "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
       - name: generate iwasm binary release
         run: |
         run: |
           cmake -S . -B build \
           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_CUSTOM_NAME_SECTION=0 \
             -DWAMR_BUILD_DEBUG_INTERP=0 \
             -DWAMR_BUILD_DEBUG_INTERP=0 \
             -DWAMR_BUILD_DEBUG_AOT=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:
 on:
   workflow_call:
   workflow_call:
     inputs:
     inputs:
-      runs-on:
+      os:
         required: true
         required: true
         type: string
         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:
 jobs:
   build_llvm_libraries:
   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:
     steps:
       - name: checkout
       - name: checkout
         uses: actions/checkout@v3
         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
       - name: Cache LLVM libraries
-        id: cache_llvm
+        id: retrieve_llvm_libs
         uses: actions/cache@v3
         uses: actions/cache@v3
         with:
         with:
           path: |
           path: |
@@ -30,10 +53,39 @@ jobs:
             ./core/deps/llvm/build/lib
             ./core/deps/llvm/build/lib
             ./core/deps/llvm/build/libexec
             ./core/deps/llvm/build/libexec
             ./core/deps/llvm/build/share
             ./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
         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
         working-directory: test-tools/wamr-ide/VSCode-Extension
 
 
       - name: generate wamr ide vscode extension
       - name: generate wamr ide vscode extension
+        env: 
+          credentials: ${{ secrets.TOKEN }}
         run: |
         run: |
           npm install -g vsce
           npm install -g vsce
           rm -rf node_modules
           rm -rf node_modules
           npm install
           npm install
           vsce package
           vsce package
+          vsce publish -p ${{ secrets.TOKEN }}
         working-directory: test-tools/wamr-ide/VSCode-Extension
         working-directory: test-tools/wamr-ide/VSCode-Extension
 
 
       - name: compress the 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
   cancel-in-progress: true
 
 
 jobs:
 jobs:
-  complinace_job:
+  compliance_job:
     runs-on: ubuntu-latest
     runs-on: ubuntu-latest
     steps:
     steps:
       - name: checkout
       - 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"
   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_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_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
   # For Spec Test
   DEFAULT_TEST_OPTIONS: "-s spec -b -P"
   DEFAULT_TEST_OPTIONS: "-s spec -b -P"
   MULTI_MODULES_TEST_OPTIONS: "-s spec -b -M -P"
   MULTI_MODULES_TEST_OPTIONS: "-s spec -b -M -P"
   SIMD_TEST_OPTIONS: "-s spec -b -S -P"
   SIMD_TEST_OPTIONS: "-s spec -b -S -P"
   THREADS_TEST_OPTIONS: "-s spec -b -p -P"
   THREADS_TEST_OPTIONS: "-s spec -b -p -P"
   X86_32_TARGET_TEST_OPTIONS: "-m x86_32 -P"
   X86_32_TARGET_TEST_OPTIONS: "-m x86_32 -P"
+  WASI_TEST_OPTIONS: "-s wasi_certification -w"
 
 
 jobs:
 jobs:
-  build_llvm_libraries:
+  build_llvm_libraries_on_ubuntu_2004:
     uses: ./.github/workflows/build_llvm_libraries.yml
     uses: ./.github/workflows/build_llvm_libraries.yml
     with:
     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:
   build_wamrc:
-    needs: [build_llvm_libraries]
+    needs:
+      [build_llvm_libraries_on_ubuntu_2004, build_llvm_libraries_on_ubuntu_2204]
     runs-on: ${{ matrix.os }}
     runs-on: ${{ matrix.os }}
     strategy:
     strategy:
       matrix:
       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:
     steps:
       - name: checkout
       - name: checkout
         uses: actions/checkout@v3
         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
       - name: Get LLVM libraries
-        id: cache_llvm
+        id: retrieve_llvm_libs
         uses: actions/cache@v3
         uses: actions/cache@v3
         with:
         with:
           path: |
           path: |
@@ -88,10 +102,10 @@ jobs:
             ./core/deps/llvm/build/lib
             ./core/deps/llvm/build/lib
             ./core/deps/llvm/build/libexec
             ./core/deps/llvm/build/libexec
             ./core/deps/llvm/build/share
             ./core/deps/llvm/build/share
-          key: ${{ matrix.os }}-${{ env.LLVM_CACHE_SUFFIX }}
+          key: ${{ matrix.llvm_cache_key }}
 
 
       - name: Quit if cache miss
       - 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
         run: echo "::error::can not get prebuilt llvm libraries" && exit 1
 
 
       - name: Build wamrc
       - name: Build wamrc
@@ -102,7 +116,8 @@ jobs:
         working-directory: wamr-compiler
         working-directory: wamr-compiler
 
 
   build_iwasm:
   build_iwasm:
-    needs: [build_llvm_libraries]
+    needs:
+      [build_llvm_libraries_on_ubuntu_2004, build_llvm_libraries_on_ubuntu_2204]
     runs-on: ${{ matrix.os }}
     runs-on: ${{ matrix.os }}
     strategy:
     strategy:
       matrix:
       matrix:
@@ -114,6 +129,7 @@ jobs:
             $FAST_JIT_BUILD_OPTIONS,
             $FAST_JIT_BUILD_OPTIONS,
             $LLVM_LAZY_JIT_BUILD_OPTIONS,
             $LLVM_LAZY_JIT_BUILD_OPTIONS,
             $LLVM_EAGER_JIT_BUILD_OPTIONS,
             $LLVM_EAGER_JIT_BUILD_OPTIONS,
+            $MULTI_TIER_JIT_BUILD_OPTIONS,
           ]
           ]
         make_options_feature: [
         make_options_feature: [
             # Features
             # Features
@@ -146,6 +162,8 @@ jobs:
             make_options_feature: "-DWAMR_BUILD_MULTI_MODULE=1"
             make_options_feature: "-DWAMR_BUILD_MULTI_MODULE=1"
           - make_options_run_mode: $LLVM_EAGER_JIT_BUILD_OPTIONS
           - make_options_run_mode: $LLVM_EAGER_JIT_BUILD_OPTIONS
             make_options_feature: "-DWAMR_BUILD_MULTI_MODULE=1"
             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
           # SIMD only on JIT/AOT mode
           - make_options_run_mode: $CLASSIC_INTERP_BUILD_OPTIONS
           - make_options_run_mode: $CLASSIC_INTERP_BUILD_OPTIONS
             make_options_feature: "-DWAMR_BUILD_SIMD=1"
             make_options_feature: "-DWAMR_BUILD_SIMD=1"
@@ -162,6 +180,8 @@ jobs:
             make_options_feature: "-DWAMR_BUILD_DEBUG_INTERP=1"
             make_options_feature: "-DWAMR_BUILD_DEBUG_INTERP=1"
           - make_options_run_mode: $LLVM_EAGER_JIT_BUILD_OPTIONS
           - make_options_run_mode: $LLVM_EAGER_JIT_BUILD_OPTIONS
             make_options_feature: "-DWAMR_BUILD_DEBUG_INTERP=1"
             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
           # DEBUG_AOT only on JIT/AOT mode
           - make_options_run_mode: $CLASSIC_INTERP_BUILD_OPTIONS
           - make_options_run_mode: $CLASSIC_INTERP_BUILD_OPTIONS
             make_options_feature: "-DWAMR_BUILD_DEBUG_AOT=1"
             make_options_feature: "-DWAMR_BUILD_DEBUG_AOT=1"
@@ -174,6 +194,8 @@ jobs:
             make_options_feature: "-DWAMR_BUILD_DEBUG_AOT=1"
             make_options_feature: "-DWAMR_BUILD_DEBUG_AOT=1"
           - make_options_run_mode: $LLVM_EAGER_JIT_BUILD_OPTIONS
           - make_options_run_mode: $LLVM_EAGER_JIT_BUILD_OPTIONS
             make_options_feature: "-DWAMR_BUILD_DEBUG_AOT=1"
             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
           # MINI_LOADER only on INTERP mode
           - make_options_run_mode: $AOT_BUILD_OPTIONS
           - make_options_run_mode: $AOT_BUILD_OPTIONS
             make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1"
             make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1"
@@ -183,16 +205,28 @@ jobs:
             make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1"
             make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1"
           - make_options_run_mode: $LLVM_EAGER_JIT_BUILD_OPTIONS
           - make_options_run_mode: $LLVM_EAGER_JIT_BUILD_OPTIONS
             make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1"
             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
           - make_options_run_mode: $FAST_JIT_BUILD_OPTIONS
             platform: android
             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:
     steps:
       - name: checkout
       - name: checkout
         uses: actions/checkout@v3
         uses: actions/checkout@v3
 
 
       # only download llvm cache when needed
       # only download llvm cache when needed
       - name: Get LLVM libraries
       - name: Get LLVM libraries
-        id: cache_llvm
+        id: retrieve_llvm_libs
         if: endsWith(matrix.make_options_run_mode, '_JIT_BUILD_OPTIONS')
         if: endsWith(matrix.make_options_run_mode, '_JIT_BUILD_OPTIONS')
         uses: actions/cache@v3
         uses: actions/cache@v3
         with:
         with:
@@ -202,10 +236,10 @@ jobs:
             ./core/deps/llvm/build/lib
             ./core/deps/llvm/build/lib
             ./core/deps/llvm/build/libexec
             ./core/deps/llvm/build/libexec
             ./core/deps/llvm/build/share
             ./core/deps/llvm/build/share
-          key: ${{ matrix.os }}-${{ env.LLVM_CACHE_SUFFIX }}
+          key: ${{ matrix.llvm_cache_key }}
 
 
       - name: Quit if cache miss
       - 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
         run: echo "::error::can not get prebuilt llvm libraries" && exit 1
 
 
       - name: Build iwasm
       - name: Build iwasm
@@ -216,7 +250,13 @@ jobs:
         working-directory: product-mini/platforms/${{ matrix.platform }}
         working-directory: product-mini/platforms/${{ matrix.platform }}
 
 
   build_samples_wasm_c_api:
   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 }}
     runs-on: ${{ matrix.os }}
     strategy:
     strategy:
       matrix:
       matrix:
@@ -228,22 +268,28 @@ jobs:
             $FAST_JIT_BUILD_OPTIONS,
             $FAST_JIT_BUILD_OPTIONS,
             $LLVM_LAZY_JIT_BUILD_OPTIONS,
             $LLVM_LAZY_JIT_BUILD_OPTIONS,
             $LLVM_EAGER_JIT_BUILD_OPTIONS,
             $LLVM_EAGER_JIT_BUILD_OPTIONS,
+            $MULTI_TIER_JIT_BUILD_OPTIONS,
           ]
           ]
         os: [ubuntu-20.04, ubuntu-22.04]
         os: [ubuntu-20.04, ubuntu-22.04]
         wasi_sdk_release:
         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:
         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:
     steps:
       - name: checkout
       - name: checkout
         uses: actions/checkout@v3
         uses: actions/checkout@v3
 
 
       - name: Get LLVM libraries
       - name: Get LLVM libraries
-        id: cache_llvm
+        id: retrieve_llvm_libs
         if: (!endsWith(matrix.make_options, '_INTERP_BUILD_OPTIONS'))
         if: (!endsWith(matrix.make_options, '_INTERP_BUILD_OPTIONS'))
         uses: actions/cache@v3
         uses: actions/cache@v3
         with:
         with:
@@ -253,18 +299,18 @@ jobs:
             ./core/deps/llvm/build/lib
             ./core/deps/llvm/build/lib
             ./core/deps/llvm/build/libexec
             ./core/deps/llvm/build/libexec
             ./core/deps/llvm/build/share
             ./core/deps/llvm/build/share
-          key: ${{ matrix.os }}-${{ env.LLVM_CACHE_SUFFIX }}
+          key: ${{ matrix.llvm_cache_key }}
 
 
       - name: Quit if cache miss
       - 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
         run: echo "::error::can not get prebuilt llvm libraries" && exit 1
 
 
       - name: download and install wabt
       - name: download and install wabt
         run: |
         run: |
           cd /opt
           cd /opt
           sudo wget ${{ matrix.wabt_release }}
           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
       - name: Build wamrc
         if: (!endsWith(matrix.make_options, '_INTERP_BUILD_OPTIONS'))
         if: (!endsWith(matrix.make_options, '_INTERP_BUILD_OPTIONS'))
@@ -276,19 +322,9 @@ jobs:
 
 
       - name: Build Sample [wasm-c-api]
       - name: Build Sample [wasm-c-api]
         run: |
         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
         working-directory: samples/wasm-c-api
 
 
   build_samples_others:
   build_samples_others:
@@ -297,14 +333,13 @@ jobs:
     strategy:
     strategy:
       matrix:
       matrix:
         os: [ubuntu-20.04, ubuntu-22.04]
         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:
     steps:
       - name: checkout
       - name: checkout
         uses: actions/checkout@v3
         uses: actions/checkout@v3
@@ -313,15 +348,31 @@ jobs:
         run: |
         run: |
           cd /opt
           cd /opt
           sudo wget ${{ matrix.wasi_sdk_release }}
           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
       - name: download and install wabt
         run: |
         run: |
           cd /opt
           cd /opt
           sudo wget ${{ matrix.wabt_release }}
           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]
       - name: Build Sample [basic]
         run: |
         run: |
@@ -376,20 +427,42 @@ jobs:
           exit $?
           exit $?
         working-directory: ./samples/simple
         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
     runs-on: ubuntu-20.04
     strategy:
     strategy:
       matrix:
       matrix:
         running_mode:
         running_mode:
-          ["classic-interp", "fast-interp", "jit", "aot", "fast-jit"]
+          [
+            "classic-interp",
+            "fast-interp",
+            "jit",
+            "aot",
+            "fast-jit",
+            "multi-tier-jit",
+          ]
         test_option:
         test_option:
           [
           [
             $DEFAULT_TEST_OPTIONS,
             $DEFAULT_TEST_OPTIONS,
             $MULTI_MODULES_TEST_OPTIONS,
             $MULTI_MODULES_TEST_OPTIONS,
             $SIMD_TEST_OPTIONS,
             $SIMD_TEST_OPTIONS,
             $THREADS_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:
         exclude:
           # uncompatiable modes and features
           # uncompatiable modes and features
           # classic-interp and fast-interp don't support simd
           # classic-interp and fast-interp don't support simd
@@ -402,31 +475,68 @@ jobs:
             test_option: $MULTI_MODULES_TEST_OPTIONS
             test_option: $MULTI_MODULES_TEST_OPTIONS
           - running_mode: "jit"
           - running_mode: "jit"
             test_option: $MULTI_MODULES_TEST_OPTIONS
             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"
           - running_mode: "fast-jit"
             test_option: $MULTI_MODULES_TEST_OPTIONS
             test_option: $MULTI_MODULES_TEST_OPTIONS
           - running_mode: "fast-jit"
           - running_mode: "fast-jit"
             test_option: $SIMD_TEST_OPTIONS
             test_option: $SIMD_TEST_OPTIONS
           - running_mode: "fast-jit"
           - running_mode: "fast-jit"
             test_option: $THREADS_TEST_OPTIONS
             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:
     steps:
       - name: checkout
       - name: checkout
         uses: actions/checkout@v3
         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)
       - 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
         run: echo "USE_LLVM=true" >> $GITHUB_ENV
 
 
       - name: set env variable(if x86_32 test needed)
       - name: set env variable(if x86_32 test needed)
         if: >
         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
         run: echo "TEST_ON_X86_32=true" >> $GITHUB_ENV
 
 
       #only download llvm libraries in jit and aot mode
       #only download llvm libraries in jit and aot mode
       - name: Get LLVM libraries
       - name: Get LLVM libraries
         if: env.USE_LLVM == 'true'
         if: env.USE_LLVM == 'true'
-        id: cache_llvm
+        id: retrieve_llvm_libs
         uses: actions/cache@v3
         uses: actions/cache@v3
         with:
         with:
           path: |
           path: |
@@ -435,13 +545,28 @@ jobs:
             ./core/deps/llvm/build/lib
             ./core/deps/llvm/build/lib
             ./core/deps/llvm/build/libexec
             ./core/deps/llvm/build/libexec
             ./core/deps/llvm/build/share
             ./core/deps/llvm/build/share
-          key: ubuntu-20.04-${{ env.LLVM_CACHE_SUFFIX }}
+          key: ${{ matrix.llvm_cache_key }}
 
 
       - name: Quit if cache miss
       - 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
         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 }}
         run: ./test_wamr.sh ${{ matrix.test_option }} -t ${{ matrix.running_mode }}
         working-directory: ./tests/wamr-test-suites
         working-directory: ./tests/wamr-test-suites
 
 
@@ -456,7 +581,8 @@ jobs:
           sudo apt-get update &&
           sudo apt-get update &&
           sudo apt install -y g++-multilib lib32gcc-9-dev
           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'
         if: env.TEST_ON_X86_32 == 'true'
         run: ./test_wamr.sh ${{ env.X86_32_TARGET_TEST_OPTIONS }} ${{ matrix.test_option }} -t ${{ matrix.running_mode }}
         run: ./test_wamr.sh ${{ env.X86_32_TARGET_TEST_OPTIONS }} ${{ matrix.test_option }} -t ${{ matrix.running_mode }}
         working-directory: ./tests/wamr-test-suites
         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"
   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_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_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:
 jobs:
   build_llvm_libraries:
   build_llvm_libraries:
     uses: ./.github/workflows/build_llvm_libraries.yml
     uses: ./.github/workflows/build_llvm_libraries.yml
     with:
     with:
-      runs-on: "['macos-latest']"
+      os: "macos-latest"
+      arch: "X86"
 
 
   build_wamrc:
   build_wamrc:
     needs: [build_llvm_libraries]
     needs: [build_llvm_libraries]
     runs-on: ${{ matrix.os }}
     runs-on: ${{ matrix.os }}
     strategy:
     strategy:
       matrix:
       matrix:
-        os: [macos-latest]
+        include:
+          - os: macos-latest
+            llvm_cache_key: ${{ needs.build_llvm_libraries.outputs.cache_key }}
     steps:
     steps:
       - name: checkout
       - name: checkout
         uses: actions/checkout@v3
         uses: actions/checkout@v3
 
 
       - name: Get LLVM libraries
       - name: Get LLVM libraries
-        id: cache_llvm
+        id: retrieve_llvm_libs
         uses: actions/cache@v3
         uses: actions/cache@v3
         with:
         with:
           path: |
           path: |
@@ -79,10 +81,10 @@ jobs:
             ./core/deps/llvm/build/lib
             ./core/deps/llvm/build/lib
             ./core/deps/llvm/build/libexec
             ./core/deps/llvm/build/libexec
             ./core/deps/llvm/build/share
             ./core/deps/llvm/build/share
-          key: ${{ matrix.os }}-${{ env.LLVM_CACHE_SUFFIX }}
+          key: ${{ matrix.llvm_cache_key }}
 
 
       - name: Quit if cache miss
       - 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
         run: echo "::error::can not get prebuilt llvm libraries" && exit 1
 
 
       - name: Build wamrc
       - name: Build wamrc
@@ -166,13 +168,16 @@ jobs:
             make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1"
             make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1"
           - make_options_run_mode: $LLVM_EAGER_JIT_BUILD_OPTIONS
           - make_options_run_mode: $LLVM_EAGER_JIT_BUILD_OPTIONS
             make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1"
             make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1"
+        include:
+          - os: macos-latest
+            llvm_cache_key: ${{ needs.build_llvm_libraries.outputs.cache_key }}
     steps:
     steps:
       - name: checkout
       - name: checkout
         uses: actions/checkout@v3
         uses: actions/checkout@v3
 
 
       # only download llvm cache when needed
       # only download llvm cache when needed
       - name: Get LLVM libraries
       - name: Get LLVM libraries
-        id: cache_llvm
+        id: retrieve_llvm_libs
         if: endsWith(matrix.make_options_run_mode, '_JIT_BUILD_OPTIONS')
         if: endsWith(matrix.make_options_run_mode, '_JIT_BUILD_OPTIONS')
         uses: actions/cache@v3
         uses: actions/cache@v3
         with:
         with:
@@ -182,10 +187,10 @@ jobs:
             ./core/deps/llvm/build/lib
             ./core/deps/llvm/build/lib
             ./core/deps/llvm/build/libexec
             ./core/deps/llvm/build/libexec
             ./core/deps/llvm/build/share
             ./core/deps/llvm/build/share
-          key: ${{ matrix.os }}-${{ env.LLVM_CACHE_SUFFIX }}
+          key: ${{ matrix.llvm_cache_key }}
 
 
       - name: Quit if cache miss
       - 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
         run: echo "::error::can not get prebuilt llvm libraries" && exit 1
 
 
       - name: Build iwasm
       - name: Build iwasm
@@ -210,8 +215,14 @@ jobs:
             #$AOT_BUILD_OPTIONS,
             #$AOT_BUILD_OPTIONS,
           ]
           ]
         os: [macos-latest]
         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:
     steps:
       - name: checkout
       - name: checkout
         uses: actions/checkout@v3
         uses: actions/checkout@v3
@@ -220,24 +231,14 @@ jobs:
         run: |
         run: |
           cd /opt
           cd /opt
           sudo wget ${{ matrix.wabt_release }}
           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]
       - name: Build Sample [wasm-c-api]
         run: |
         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
         working-directory: samples/wasm-c-api
 
 
   build_samples_others:
   build_samples_others:
@@ -246,8 +247,14 @@ jobs:
     strategy:
     strategy:
       matrix:
       matrix:
         os: [macos-latest]
         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:
     steps:
       - name: checkout
       - name: checkout
         uses: actions/checkout@v3
         uses: actions/checkout@v3
@@ -256,15 +263,31 @@ jobs:
         run: |
         run: |
           cd /opt
           cd /opt
           sudo wget ${{ matrix.wasi_sdk_release }}
           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
       - name: download and install wabt
         run: |
         run: |
           cd /opt
           cd /opt
           sudo wget ${{ matrix.wabt_release }}
           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]
       - name: Build Sample [basic]
         run: |
         run: |
@@ -311,3 +334,11 @@ jobs:
           cmake ..
           cmake ..
           cmake --build . --config Release --parallel 4
           cmake --build . --config Release --parallel 4
           ./hello
           ./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 }}
   group: ${{ github.workflow }}-${{ github.ref }}
   cancel-in-progress: true
   cancel-in-progress: true
 
 
+env:
+  WASI_SDK_PATH: "/opt/wasi-sdk"
+
 jobs:
 jobs:
   build_iwasm_on_nuttx:
   build_iwasm_on_nuttx:
     runs-on: ubuntu-22.04
     runs-on: ubuntu-22.04
@@ -65,9 +68,12 @@ jobs:
           "boards/risc-v/k210/maix-bit/configs/nsh",
           "boards/risc-v/k210/maix-bit/configs/nsh",
         ]
         ]
         wamr_config_option: [
         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\\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\\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\\nCONFIG_INTERPRETERS_WAMR_LIBC_BUILTIN=y\\n",
           "CONFIG_INTERPRETERS_WAMR=y\\nCONFIG_INTERPRETERS_WAMR_AOT=y\\n",
           "CONFIG_INTERPRETERS_WAMR=y\\nCONFIG_INTERPRETERS_WAMR_AOT=y\\n",
           "CONFIG_INTERPRETERS_WAMR=y\\nCONFIG_INTERPRETERS_WAMR_FAST=y\\n",
           "CONFIG_INTERPRETERS_WAMR=y\\nCONFIG_INTERPRETERS_WAMR_FAST=y\\n",
@@ -92,6 +98,12 @@ jobs:
           tar xvf riscv.tar.gz
           tar xvf riscv.tar.gz
           echo "$PWD/riscv64-unknown-elf-toolchain-10.2.0-2020.12.8-x86_64-linux-ubuntu14/bin" >> $GITHUB_PATH
           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
       - name: Checkout NuttX
         uses: actions/checkout@v3
         uses: actions/checkout@v3
         with:
         with:
@@ -112,7 +124,7 @@ jobs:
 
 
       - name: Enable WAMR for NuttX
       - name: Enable WAMR for NuttX
         run: |
         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'
           find nuttx/boards/sim -name defconfig | xargs sed -i '$a\CONFIG_LIBM=y\n'
 
 
       - name: Build
       - 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"
   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_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_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:
 jobs:
   build_llvm_libraries:
   build_llvm_libraries:
     uses: ./.github/workflows/build_llvm_libraries.yml
     uses: ./.github/workflows/build_llvm_libraries.yml
     with:
     with:
-      runs-on: "['ubuntu-20.04']"
+      os: "ubuntu-20.04"
+      arch: "X86"
 
 
   build_iwasm:
   build_iwasm:
     runs-on: ${{ matrix.os }}
     runs-on: ${{ matrix.os }}
@@ -131,7 +131,9 @@ jobs:
     runs-on: ${{ matrix.os }}
     runs-on: ${{ matrix.os }}
     strategy:
     strategy:
       matrix:
       matrix:
-        os: [ubuntu-20.04]
+        include:
+          - os: ubuntu-20.04
+            llvm_cache_key: ${{ needs.build_llvm_libraries.outputs.cache_key }}
     steps:
     steps:
       - name: install SGX SDK and necessary libraries
       - name: install SGX SDK and necessary libraries
         run: |
         run: |
@@ -150,7 +152,7 @@ jobs:
         uses: actions/checkout@v3
         uses: actions/checkout@v3
 
 
       - name: Get LLVM libraries
       - name: Get LLVM libraries
-        id: cache_llvm
+        id: retrieve_llvm_libs
         uses: actions/cache@v3
         uses: actions/cache@v3
         with:
         with:
           path: |
           path: |
@@ -159,10 +161,10 @@ jobs:
             ./core/deps/llvm/build/lib
             ./core/deps/llvm/build/lib
             ./core/deps/llvm/build/libexec
             ./core/deps/llvm/build/libexec
             ./core/deps/llvm/build/share
             ./core/deps/llvm/build/share
-          key: ${{ matrix.os }}-${{ env.LLVM_CACHE_SUFFIX }}
+          key: ${{ matrix.llvm_cache_key }}
 
 
       - name: Quit if cache miss
       - 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
         run: echo "::error::can not get prebuilt llvm libraries" && exit 1
 
 
       - name: Build wamrc
       - name: Build wamrc
@@ -189,11 +191,11 @@ jobs:
         os: [ubuntu-20.04]
         os: [ubuntu-20.04]
         wasi_sdk_release:
         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:
         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:
     steps:
       - name: checkout
       - name: checkout
@@ -203,8 +205,8 @@ jobs:
         run: |
         run: |
           cd /opt
           cd /opt
           sudo wget ${{ matrix.wabt_release }}
           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
       - name: install SGX SDK and necessary libraries
         run: |
         run: |
@@ -221,19 +223,9 @@ jobs:
 
 
       - name: Build Sample [wasm-c-api]
       - name: Build Sample [wasm-c-api]
         run: |
         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
         working-directory: samples/wasm-c-api
 
 
   build_samples_others:
   build_samples_others:
@@ -244,11 +236,11 @@ jobs:
         os: [ubuntu-20.04]
         os: [ubuntu-20.04]
         wasi_sdk_release:
         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:
         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:
     steps:
       - name: checkout
       - name: checkout
@@ -258,15 +250,31 @@ jobs:
         run: |
         run: |
           cd /opt
           cd /opt
           sudo wget ${{ matrix.wasi_sdk_release }}
           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
       - name: download and install wabt
         run: |
         run: |
           cd /opt
           cd /opt
           sudo wget ${{ matrix.wabt_release }}
           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
       - name: install SGX SDK and necessary libraries
         run: |
         run: |
@@ -327,6 +335,14 @@ jobs:
           cmake --build . --config Release --parallel 4
           cmake --build . --config Release --parallel 4
           ./hello
           ./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:
   spec_test_default:
     needs: [build_iwasm, build_llvm_libraries, build_wamrc]
     needs: [build_iwasm, build_llvm_libraries, build_wamrc]
     runs-on: ubuntu-20.04
     runs-on: ubuntu-20.04
@@ -334,6 +350,7 @@ jobs:
       matrix:
       matrix:
         running_mode: ["classic-interp", "fast-interp", "aot"]
         running_mode: ["classic-interp", "fast-interp", "aot"]
         test_option: ["-x -p -s spec -b -P", "-x -p -s spec -S -b -P"]
         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
         # classic-interp and fast-interp don't support simd
         exclude:
         exclude:
           - running_mode: "classic-interp"
           - running_mode: "classic-interp"
@@ -347,7 +364,7 @@ jobs:
 
 
       - name: Get LLVM libraries
       - name: Get LLVM libraries
         if: matrix.running_mode == 'aot'
         if: matrix.running_mode == 'aot'
-        id: cache_llvm
+        id: retrieve_llvm_libs
         uses: actions/cache@v3
         uses: actions/cache@v3
         with:
         with:
           path: |
           path: |
@@ -356,10 +373,10 @@ jobs:
             ./core/deps/llvm/build/lib
             ./core/deps/llvm/build/lib
             ./core/deps/llvm/build/libexec
             ./core/deps/llvm/build/libexec
             ./core/deps/llvm/build/share
             ./core/deps/llvm/build/share
-          key: ubuntu-20.04-${{ env.LLVM_CACHE_SUFFIX }}
+          key: ${{ matrix.llvm_cache_key }}
 
 
       - name: Quit if cache miss
       - 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
         run: echo "::error::can not get prebuilt llvm libraries" && exit 1
 
 
       - name: install SGX SDK and necessary libraries
       - 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 .. -DWAMR_BUILD_DEBUG_INTERP=1
           cmake --build . --config Release --parallel 4
           cmake --build . --config Release --parallel 4
           cd .. && rm -force -r build
           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
       runner: ubuntu-20.04
       upload_url: ${{ needs.create_release.outputs.upload_url }}
       upload_url: ${{ needs.create_release.outputs.upload_url }}
       ver_num: ${{ needs.create_tag.outputs.new_ver}}
       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:
   release_wamr_sdk_on_ubuntu_2204:
     needs: [create_tag, create_release]
     needs: [create_tag, create_release]
@@ -133,7 +133,7 @@ jobs:
       runner: ubuntu-22.04
       runner: ubuntu-22.04
       upload_url: ${{ needs.create_release.outputs.upload_url }}
       upload_url: ${{ needs.create_release.outputs.upload_url }}
       ver_num: ${{ needs.create_tag.outputs.new_ver}}
       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:
   release_wamr_sdk_on_macos:
     needs: [create_tag, create_release]
     needs: [create_tag, create_release]
@@ -143,13 +143,14 @@ jobs:
       runner: macos-latest
       runner: macos-latest
       upload_url: ${{ needs.create_release.outputs.upload_url }}
       upload_url: ${{ needs.create_release.outputs.upload_url }}
       ver_num: ${{ needs.create_tag.outputs.new_ver}}
       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
   # vscode extension cross-platform
   release_wamr_ide_vscode_ext:
   release_wamr_ide_vscode_ext:
     needs: [create_tag, create_release]
     needs: [create_tag, create_release]
     uses: ./.github/workflows/build_wamr_vscode_ext.yml
     uses: ./.github/workflows/build_wamr_vscode_ext.yml
+    secrets: inherit
     with:
     with:
       upload_url: ${{ needs.create_release.outputs.upload_url }}
       upload_url: ${{ needs.create_release.outputs.upload_url }}
       ver_num: ${{ needs.create_tag.outputs.new_ver }}
       ver_num: ${{ needs.create_tag.outputs.new_ver }}

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

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

+ 7 - 0
.gitignore

@@ -13,6 +13,8 @@
 core/deps/**
 core/deps/**
 core/shared/mem-alloc/tlsf
 core/shared/mem-alloc/tlsf
 core/app-framework/wgl
 core/app-framework/wgl
+core/iwasm/libraries/lib-wasi-threads/test/*.wasm
+core/iwasm/libraries/lib-socket/test/*.wasm
 
 
 wamr-sdk/out/
 wamr-sdk/out/
 wamr-sdk/runtime/build_runtime_sdk/
 wamr-sdk/runtime/build_runtime_sdk/
@@ -32,3 +34,8 @@ samples/socket-api/wasm-src/inc/pthread.h
 **/__pycache__
 **/__pycache__
 
 
 tests/benchmarks/coremark/coremark*
 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)
 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
 # Reset default linker flags
 set (CMAKE_SHARED_LIBRARY_LINK_C_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)
   set (WAMR_BUILD_LIB_PTHREAD 0)
 endif ()
 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)
 if (NOT DEFINED WAMR_BUILD_MINI_LOADER)
   # Disable wasm mini loader by default
   # Disable wasm mini loader by default
   set (WAMR_BUILD_MINI_LOADER 0)
   set (WAMR_BUILD_MINI_LOADER 0)
@@ -98,11 +105,6 @@ if (NOT DEFINED WAMR_BUILD_REF_TYPES)
   set (WAMR_BUILD_REF_TYPES 0)
   set (WAMR_BUILD_REF_TYPES 0)
 endif ()
 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})
 set (WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR})
 
 
 include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake)
 include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake)
@@ -130,23 +132,26 @@ include (${SHARED_DIR}/utils/uncommon/shared_uncommon.cmake)
 
 
 # STATIC LIBRARY
 # STATIC LIBRARY
 add_library(iwasm_static STATIC ${WAMR_RUNTIME_LIB_SOURCE})
 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)
 if (WAMR_BUILD_WASM_CACHE EQUAL 1)
-  target_link_libraries(iwasm_static PUBLIC boringssl_crypto)
+  target_link_libraries(iwasm_static INTERFACE boringssl_crypto)
 endif ()
 endif ()
-set_target_properties (iwasm_static PROPERTIES OUTPUT_NAME vmlib)
 
 
 install (TARGETS iwasm_static ARCHIVE DESTINATION lib)
 install (TARGETS iwasm_static ARCHIVE DESTINATION lib)
 
 
 # SHARED LIBRARY
 # SHARED LIBRARY
 add_library (iwasm_shared SHARED ${WAMR_RUNTIME_LIB_SOURCE})
 add_library (iwasm_shared SHARED ${WAMR_RUNTIME_LIB_SOURCE})
 set_target_properties (iwasm_shared PROPERTIES OUTPUT_NAME iwasm)
 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)
 if (WAMR_BUILD_WASM_CACHE EQUAL 1)
-  target_link_libraries(iwasm_shared boringssl_crypto)
+  target_link_libraries(iwasm_shared INTERFACE boringssl_crypto)
 endif ()
 endif ()
 
 
 if (MINGW)
 if (MINGW)
-target_link_libraries (iwasm_shared -lWs2_32)
+  target_link_libraries (iwasm_shared -lWs2_32)
 endif ()
 endif ()
 
 
 install (TARGETS iwasm_shared LIBRARY DESTINATION lib)
 install (TARGETS iwasm_shared LIBRARY DESTINATION lib)
@@ -155,4 +160,5 @@ install (TARGETS iwasm_shared LIBRARY DESTINATION lib)
 install (FILES
 install (FILES
     ${WAMR_ROOT_DIR}/core/iwasm/include/wasm_c_api.h
     ${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/wasm_export.h
+    ${WAMR_ROOT_DIR}/core/iwasm/include/lib_export.h
     DESTINATION include)
     DESTINATION include)

+ 92 - 32
build-scripts/build_llvm.py

@@ -7,6 +7,7 @@
 import argparse
 import argparse
 import os
 import os
 import pathlib
 import pathlib
+import requests
 import shlex
 import shlex
 import shutil
 import shutil
 import subprocess
 import subprocess
@@ -21,28 +22,44 @@ def clone_llvm(dst_dir, llvm_repo, llvm_branch):
     llvm_dir = dst_dir.joinpath("llvm").resolve()
     llvm_dir = dst_dir.joinpath("llvm").resolve()
 
 
     if not llvm_dir.exists():
     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"
         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)
         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
     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 = [
     LLVM_COMPILE_OPTIONS = [
         '-DCMAKE_BUILD_TYPE:STRING="Release"',
         '-DCMAKE_BUILD_TYPE:STRING="Release"',
         "-DCMAKE_EXPORT_COMPILE_COMMANDS=ON",
         "-DCMAKE_EXPORT_COMPILE_COMMANDS=ON",
         "-DLLVM_APPEND_VC_REV:BOOL=ON",
         "-DLLVM_APPEND_VC_REV:BOOL=ON",
-        "-DLLVM_BUILD_BENCHMARKS:BOOL=OFF",
-        "-DLLVM_BUILD_DOCS:BOOL=OFF",
         "-DLLVM_BUILD_EXAMPLES:BOOL=OFF",
         "-DLLVM_BUILD_EXAMPLES:BOOL=OFF",
         "-DLLVM_BUILD_LLVM_DYLIB:BOOL=OFF",
         "-DLLVM_BUILD_LLVM_DYLIB:BOOL=OFF",
         "-DLLVM_BUILD_TESTS:BOOL=OFF",
         "-DLLVM_BUILD_TESTS:BOOL=OFF",
-        "-DLLVM_CCACHE_BUILD:BOOL=OFF",
+        "-DLLVM_CCACHE_BUILD:BOOL=ON",
         "-DLLVM_ENABLE_BINDINGS:BOOL=OFF",
         "-DLLVM_ENABLE_BINDINGS:BOOL=OFF",
         "-DLLVM_ENABLE_IDE:BOOL=OFF",
         "-DLLVM_ENABLE_IDE:BOOL=OFF",
+        "-DLLVM_ENABLE_LIBEDIT=OFF",
         "-DLLVM_ENABLE_TERMINFO:BOOL=OFF",
         "-DLLVM_ENABLE_TERMINFO:BOOL=OFF",
         "-DLLVM_ENABLE_ZLIB:BOOL=OFF",
         "-DLLVM_ENABLE_ZLIB:BOOL=OFF",
         "-DLLVM_INCLUDE_BENCHMARKS:BOOL=OFF",
         "-DLLVM_INCLUDE_BENCHMARKS:BOOL=OFF",
@@ -54,6 +71,18 @@ def build_llvm(llvm_dir, platform, backends, projects):
         "-DLLVM_OPTIMIZED_TABLEGEN:BOOL=ON",
         "-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 = {
     LLVM_EXTRA_COMPILE_OPTIONS = {
         "arc": [
         "arc": [
             '-DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD:STRING="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()
     lib_llvm_core_library = build_dir.joinpath("lib/libLLVMCore.a").resolve()
     if lib_llvm_core_library.exists():
     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(
     compile_options = " ".join(
         LLVM_COMPILE_OPTIONS
         LLVM_COMPILE_OPTIONS
@@ -113,16 +144,17 @@ def build_llvm(llvm_dir, platform, backends, projects):
         + LLVM_INCLUDE_TOOLS_OPTION
         + LLVM_INCLUDE_TOOLS_OPTION
     )
     )
 
 
-    CONFIG_CMD = f"cmake {compile_options} ../llvm"
+    CONFIG_CMD = f"cmake {compile_options} {extra_flags} ../llvm"
     if "windows" == platform:
     if "windows" == platform:
         if "mingw" in sysconfig.get_platform().lower():
         if "mingw" in sysconfig.get_platform().lower():
             CONFIG_CMD += " -G'Unix Makefiles'"
             CONFIG_CMD += " -G'Unix Makefiles'"
         else:
         else:
             CONFIG_CMD += " -A x64"
             CONFIG_CMD += " -A x64"
-    print(f"{CONFIG_CMD}")
+    else:
+        CONFIG_CMD += " -G'Ninja'"
     subprocess.check_call(shlex.split(CONFIG_CMD), cwd=build_dir)
     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 ""
         " --config Release" if "windows" == platform else ""
     )
     )
     subprocess.check_call(shlex.split(BUILD_CMD), cwd=build_dir)
     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):
 def repackage_llvm(llvm_dir):
     build_dir = llvm_dir.joinpath("./build").resolve()
     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:
     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:
     if not packs:
         return
         return
 
 
     llvm_package = packs[0].name
     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))
     shutil.move(str(build_dir.joinpath(llvm_package).resolve()), str(llvm_dir))
     # rm -r build
     # rm -r build
     shutil.rmtree(str(build_dir))
     shutil.rmtree(str(build_dir))
     # mkdir build
     # mkdir build
     build_dir.mkdir()
     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}"
     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)
     subprocess.check_call(shlex.split(CMD), cwd=llvm_dir)
+    # rm ./LLVM-1*.gz
+    os.remove(llvm_dir.joinpath(llvm_package).resolve())
 
 
 
 
 def main():
 def main():
@@ -184,8 +218,23 @@ def main():
         choices=["clang", "lldb"],
         choices=["clang", "lldb"],
         help="identify extra LLVM projects, separate by space, like '--project 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()
     options = parser.parse_args()
-    print(f"options={options}")
 
 
     # if the "platform" is not identified in the command line option,
     # if the "platform" is not identified in the command line option,
     # detect it
     # detect it
@@ -199,20 +248,21 @@ def main():
     else:
     else:
         platform = options.platform
         platform = options.platform
 
 
-    print(f"========== Build LLVM for {platform} ==========\n")
-
     llvm_repo_and_branch = {
     llvm_repo_and_branch = {
         "arc": {
         "arc": {
             "repo": "https://github.com/llvm/llvm-project.git",
             "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": {
         "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",
             "branch": "xtensa_release_15.x",
         },
         },
         "default": {
         "default": {
             "repo": "https://github.com/llvm/llvm-project.git",
             "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()
     deps_dir = current_dir.joinpath("../core/deps").resolve()
 
 
     try:
     try:
-        print(f"==================== CLONE LLVM ====================")
         llvm_info = llvm_repo_and_branch.get(platform, llvm_repo_and_branch["default"])
         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
         return True
     except subprocess.CalledProcessError:
     except subprocess.CalledProcessError:
         return False
         return False

+ 15 - 0
build-scripts/config_common.cmake

@@ -333,6 +333,11 @@ if (WAMR_BUILD_SGX_IPFS EQUAL 1)
 endif ()
 endif ()
 if (WAMR_BUILD_WASI_NN EQUAL 1)
 if (WAMR_BUILD_WASI_NN EQUAL 1)
   message ("     WASI-NN enabled")
   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 ()
 endif ()
 if (WAMR_BUILD_ALLOC_WITH_USER_DATA EQUAL 1)
 if (WAMR_BUILD_ALLOC_WITH_USER_DATA EQUAL 1)
   add_definitions(-DWASM_MEM_ALLOC_WITH_USER_DATA=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)
   add_definitions (-DWASM_ENABLE_WASM_CACHE=1)
   message ("     Wasm files cache enabled")
   message ("     Wasm files cache enabled")
 endif ()
 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)
 if (NOT DEFINED DEPS_DIR)
     set (DEPS_DIR ${WAMR_ROOT_DIR}/core/deps)
     set (DEPS_DIR ${WAMR_ROOT_DIR}/core/deps)
 endif ()
 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)
 if (DEFINED EXTRA_SDK_INCLUDE_PATH)
     message(STATUS, "EXTRA_SDK_INCLUDE_PATH = ${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 ()
 endif ()
 
 
 if (WAMR_BUILD_WASI_NN EQUAL 1)
 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")
     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 (${CMAKE_CURRENT_BINARY_DIR}/flatbuffers/include)
     include_directories (${TENSORFLOW_SOURCE_DIR})
     include_directories (${TENSORFLOW_SOURCE_DIR})
     add_subdirectory(
     add_subdirectory(
@@ -116,6 +132,14 @@ if (WAMR_BUILD_LIB_PTHREAD EQUAL 1)
     set (WAMR_BUILD_SHARED_MEMORY 1)
     set (WAMR_BUILD_SHARED_MEMORY 1)
 endif ()
 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)
 if (WAMR_BUILD_DEBUG_INTERP EQUAL 1)
     set (WAMR_BUILD_THREAD_MGR 1)
     set (WAMR_BUILD_THREAD_MGR 1)
     include (${IWASM_DIR}/libraries/debug-engine/debug_engine.cmake)
     include (${IWASM_DIR}/libraries/debug-engine/debug_engine.cmake)
@@ -161,7 +185,7 @@ LIST (APPEND RUNTIME_LIB_HEADER_LIST ${header})
 
 
 enable_language (ASM)
 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 (${SHARED_DIR}/mem-alloc/mem_alloc.cmake)
 include (${IWASM_DIR}/common/iwasm_common.cmake)
 include (${IWASM_DIR}/common/iwasm_common.cmake)
 include (${SHARED_DIR}/utils/shared_utils.cmake)
 include (${SHARED_DIR}/utils/shared_utils.cmake)
@@ -182,6 +206,7 @@ set (source_all
     ${WASM_APP_LIB_SOURCE_ALL}
     ${WASM_APP_LIB_SOURCE_ALL}
     ${NATIVE_INTERFACE_SOURCE}
     ${NATIVE_INTERFACE_SOURCE}
     ${APP_MGR_SOURCE}
     ${APP_MGR_SOURCE}
+    ${LIB_WASI_THREADS_SOURCE}
     ${LIB_PTHREAD_SOURCE}
     ${LIB_PTHREAD_SOURCE}
     ${THREAD_MGR_SOURCE}
     ${THREAD_MGR_SOURCE}
     ${LIBC_EMCC_SOURCE}
     ${LIBC_EMCC_SOURCE}

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

@@ -7,11 +7,14 @@
 
 
 typedef union jvalue {
 typedef union jvalue {
     bool z;
     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;
     float f;
     double d;
     double d;
 } jvalue;
 } jvalue;
@@ -27,7 +30,9 @@ get_int16(const char *buf)
 static inline uint16_t
 static inline uint16_t
 get_uint16(const char *buf)
 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
 static inline int32_t
@@ -41,7 +46,9 @@ get_int32(const char *buf)
 static inline uint32_t
 static inline uint32_t
 get_uint32(const char *buf)
 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
 static inline int64_t
@@ -55,7 +62,9 @@ get_int64(const char *buf)
 static inline uint64_t
 static inline uint64_t
 get_uint64(const char *buf)
 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
 static inline void
@@ -145,8 +154,8 @@ attr_container_get_attr_next(const char *curr_attr)
     p += sizeof(uint16_t) + get_uint16(p);
     p += sizeof(uint16_t) + get_uint16(p);
     type = *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);
         p += 1 << (type & 3);
         return p;
         return p;
     }
     }
@@ -342,7 +351,7 @@ attr_container_set_attr(attr_container_t **p_attr_cont, const char *key,
 
 
     /* key len + key + '\0' + type */
     /* key len + key + '\0' + type */
     attr_len = sizeof(uint16_t) + strlen(key) + 1 + 1;
     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);
         attr_len += 1 << (type & 3);
     else if (type == ATTR_TYPE_STRING)
     else if (type == ATTR_TYPE_STRING)
         attr_len += sizeof(uint16_t) + value_length;
         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 += str_len;
 
 
     *p++ = type;
     *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));
         bh_memcpy_s(p, 1 << (type & 3), value, 1 << (type & 3));
     else if (type == ATTR_TYPE_STRING) {
     else if (type == ATTR_TYPE_STRING) {
         set_uint16(p, value_length);
         set_uint16(p, value_length);
@@ -460,6 +469,14 @@ attr_container_set_short(attr_container_t **p_attr_cont, const char *key,
                                    2);
                                    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
 bool
 attr_container_set_int(attr_container_t **p_attr_cont, const char *key,
 attr_container_set_int(attr_container_t **p_attr_cont, const char *key,
                        int value)
                        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);
     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
 bool
 attr_container_set_int64(attr_container_t **p_attr_cont, const char *key,
 attr_container_set_int64(attr_container_t **p_attr_cont, const char *key,
                          int64_t value)
                          int64_t value)
@@ -475,6 +508,14 @@ attr_container_set_int64(attr_container_t **p_attr_cont, const char *key,
                                    8);
                                    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
 bool
 attr_container_set_byte(attr_container_t **p_attr_cont, const char *key,
 attr_container_set_byte(attr_container_t **p_attr_cont, const char *key,
                         int8_t value)
                         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);
     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
 bool
 attr_container_set_uint16(attr_container_t **p_attr_cont, const char *key,
 attr_container_set_uint16(attr_container_t **p_attr_cont, const char *key,
                           uint16_t value)
                           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))) {
     if (!(attr_addr = attr_container_find_attr(attr_cont, key))) {
         attr_container_printf("Get attribute failed: lookup key failed.\r\n");
         attr_container_printf("Get attribute failed: lookup key failed.\r\n");
-        return false;
+        return NULL;
     }
     }
 
 
     /* key len + key + '\0' */
     /* key len + key + '\0' */
@@ -566,14 +622,17 @@ attr_container_get_attr(const attr_container_t *attr_cont, const char *key)
         uint8_t type;                                                        \
         uint8_t type;                                                        \
         if (!addr)                                                           \
         if (!addr)                                                           \
             return 0;                                                        \
             return 0;                                                        \
-        val.j = 0;                                                           \
+        val.i64 = 0;                                                         \
         type = *(uint8_t *)addr++;                                           \
         type = *(uint8_t *)addr++;                                           \
         switch (type) {                                                      \
         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_INT64:                                            \
-            case ATTR_TYPE_BYTE:                                             \
+            case ATTR_TYPE_UINT8:                                            \
             case ATTR_TYPE_UINT16:                                           \
             case ATTR_TYPE_UINT16:                                           \
+            case ATTR_TYPE_UINT32:                                           \
+            case ATTR_TYPE_UINT64:                                           \
             case ATTR_TYPE_FLOAT:                                            \
             case ATTR_TYPE_FLOAT:                                            \
             case ATTR_TYPE_DOUBLE:                                           \
             case ATTR_TYPE_DOUBLE:                                           \
             case ATTR_TYPE_BOOLEAN:                                          \
             case ATTR_TYPE_BOOLEAN:                                          \
@@ -608,31 +667,67 @@ attr_container_get_attr(const attr_container_t *attr_cont, const char *key)
 short
 short
 attr_container_get_as_short(const attr_container_t *attr_cont, const char *key)
 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
 int
 attr_container_get_as_int(const attr_container_t *attr_cont, const char *key)
 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
 int64_t
 attr_container_get_as_int64(const attr_container_t *attr_cont, const char *key)
 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
 int8_t
 attr_container_get_as_byte(const attr_container_t *attr_cont, const char *key)
 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
 uint16_t
 attr_container_get_as_uint16(const attr_container_t *attr_cont, const char *key)
 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
 float
@@ -671,11 +766,14 @@ attr_container_get_as_bytearray(const attr_container_t *attr_cont,
 
 
     type = *(uint8_t *)addr++;
     type = *(uint8_t *)addr++;
     switch (type) {
     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_INT64:
-        case ATTR_TYPE_BYTE:
+        case ATTR_TYPE_UINT8:
         case ATTR_TYPE_UINT16:
         case ATTR_TYPE_UINT16:
+        case ATTR_TYPE_UINT32:
+        case ATTR_TYPE_UINT64:
         case ATTR_TYPE_FLOAT:
         case ATTR_TYPE_FLOAT:
         case ATTR_TYPE_DOUBLE:
         case ATTR_TYPE_DOUBLE:
         case ATTR_TYPE_BOOLEAN:
         case ATTR_TYPE_BOOLEAN:
@@ -807,34 +905,52 @@ attr_container_dump(const attr_container_t *attr_cont)
         attr_container_printf("  key: %s", key);
         attr_container_printf("  key: %s", key);
 
 
         switch (type) {
         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",
                 attr_container_printf(", type: short, value: 0x%x\n",
-                                      value.s & 0xFFFF);
+                                      value.i16 & 0xFFFF);
                 p += 2;
                 p += 2;
                 break;
                 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;
                 p += 4;
                 break;
                 break;
             case ATTR_TYPE_INT64:
             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",
                 attr_container_printf(", type: int64, value: 0x%llx\n",
-                                      (long long unsigned int)(value.j));
+                                      (long long unsigned int)(value.i64));
                 p += 8;
                 p += 8;
                 break;
                 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++;
                 p++;
                 break;
                 break;
             case ATTR_TYPE_UINT16:
             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;
                 p += 2;
                 break;
                 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:
             case ATTR_TYPE_FLOAT:
                 bh_memcpy_s(&value.f, sizeof(float), p, sizeof(float));
                 bh_memcpy_s(&value.f, sizeof(float), p, sizeof(float));
                 attr_container_printf(", type: float, value: %f\n", value.f);
                 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 */
 /* Attribute type */
 enum {
 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_INT,
+    ATTR_TYPE_INT32 = ATTR_TYPE_INT,
     ATTR_TYPE_INT64,
     ATTR_TYPE_INT64,
-    ATTR_TYPE_BYTE,
+    ATTR_TYPE_UINT8,
     ATTR_TYPE_UINT16,
     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_DOUBLE,
     ATTR_TYPE_BOOLEAN,
     ATTR_TYPE_BOOLEAN,
     ATTR_TYPE_STRING,
     ATTR_TYPE_STRING,
@@ -89,6 +103,20 @@ bool
 attr_container_set_short(attr_container_t **p_attr_cont, const char *key,
 attr_container_set_short(attr_container_t **p_attr_cont, const char *key,
                          short value);
                          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
  * Set int attribute in attribute container
  *
  *
@@ -103,6 +131,34 @@ bool
 attr_container_set_int(attr_container_t **p_attr_cont, const char *key,
 attr_container_set_int(attr_container_t **p_attr_cont, const char *key,
                        int value);
                        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
  * Set int64 attribute in attribute container
  *
  *
@@ -117,6 +173,20 @@ bool
 attr_container_set_int64(attr_container_t **p_attr_cont, const char *key,
 attr_container_set_int64(attr_container_t **p_attr_cont, const char *key,
                          int64_t value);
                          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
  * Set byte attribute in attribute container
  *
  *
@@ -131,6 +201,34 @@ bool
 attr_container_set_byte(attr_container_t **p_attr_cont, const char *key,
 attr_container_set_byte(attr_container_t **p_attr_cont, const char *key,
                         int8_t value);
                         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
  * Set uint16 attribute in attribute container
  *
  *
@@ -259,6 +357,18 @@ attr_container_contain_key(const attr_container_t *attr_cont, const char *key);
 short
 short
 attr_container_get_as_short(const attr_container_t *attr_cont, const char *key);
 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,
  * Get attribute from attribute container and return it as int value,
  * return 0 if attribute isn't found in message.
  * 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
 int
 attr_container_get_as_int(const attr_container_t *attr_cont, const char *key);
 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,
  * Get attribute from attribute container and return it as int64 value,
  * return 0 if attribute isn't found in attribute container.
  * 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
 int64_t
 attr_container_get_as_int64(const attr_container_t *attr_cont, const char *key);
 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,
  * Get attribute from attribute container and return it as byte value,
  * return 0 if attribute isn't found in attribute container.
  * 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
 int8_t
 attr_container_get_as_byte(const attr_container_t *attr_cont, const char *key);
 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,
  * Get attribute from attribute container and return it as uint16 value,
  * return 0 if attribute isn't found in attribute container.
  * 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");
     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
 #if VALGRIND_CHECK != 0
     bh_queue_exit_loop_run(get_app_manager_queue());
     bh_queue_exit_loop_run(get_app_manager_queue());
 #endif
 #endif

+ 11 - 0
core/config.h

@@ -161,6 +161,17 @@
 #define WASM_ENABLE_LIB_PTHREAD_SEMAPHORE 0
 #define WASM_ENABLE_LIB_PTHREAD_SEMAPHORE 0
 #endif
 #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
 #ifndef WASM_ENABLE_BASE_LIB
 #define WASM_ENABLE_BASE_LIB 0
 #define WASM_ENABLE_BASE_LIB 0
 #endif
 #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 =
             import_globals[i].global_data_linked =
                 tmp_global.global_data_linked;
                 tmp_global.global_data_linked;
+            import_globals[i].is_linked = true;
         }
         }
+#else
+        import_globals[i].is_linked = false;
 #endif
 #endif
 
 
         import_globals[i].size = wasm_value_type_size(import_globals[i].type);
         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)
 bh_static_assert(offsetof(WASMExecEnv, aux_stack_bottom)
                  == 7 * sizeof(uintptr_t));
                  == 7 * sizeof(uintptr_t));
 bh_static_assert(offsetof(WASMExecEnv, native_symbol) == 8 * 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, memories) == 1 * sizeof(uint64));
 bh_static_assert(offsetof(AOTModuleInstance, func_ptrs) == 5 * 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);
     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 */
         /* 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
 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;
     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;
         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");
         aot_set_exception(module_inst, "allocate memory failed");
         return false;
         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);
     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
 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 *
 AOTModuleInstance *
 aot_instantiate(AOTModule *module, bool is_sub_inst, uint32 stack_size,
 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))
     if (!init_func_type_indexes(module_inst, module, error_buf, error_buf_size))
         goto fail;
         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))
     if (!create_exports(module_inst, module, error_buf, error_buf_size))
         goto fail;
         goto fail;
 
 
@@ -1079,6 +1170,17 @@ aot_instantiate(AOTModule *module, bool is_sub_inst, uint32 stack_size,
     }
     }
 #endif
 #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 */
     /* Initialize the thread related data */
     if (stack_size == 0)
     if (stack_size == 0)
         stack_size = DEFAULT_WASM_STACK_SIZE;
         stack_size = DEFAULT_WASM_STACK_SIZE;
@@ -1104,32 +1206,11 @@ aot_instantiate(AOTModule *module, bool is_sub_inst, uint32 stack_size,
     }
     }
 #endif
 #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);
         set_error_buf(error_buf, error_buf_size, module_inst->cur_exception);
         goto fail;
         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
 #if WASM_ENABLE_MEMORY_TRACING != 0
     wasm_runtime_dump_module_inst_mem_consumption(
     wasm_runtime_dump_module_inst_mem_consumption(
         (WASMModuleInstanceCommon *)module_inst);
         (WASMModuleInstanceCommon *)module_inst);
@@ -1145,6 +1226,15 @@ fail:
 void
 void
 aot_deinstantiate(AOTModuleInstance *module_inst, bool is_sub_inst)
 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
 #if WASM_ENABLE_LIBC_WASI != 0
     /* Destroy wasi resource before freeing app heap, since some fields of
     /* Destroy wasi resource before freeing app heap, since some fields of
        wasi contex are allocated from app heap, and if app heap is freed,
        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)
     if (module_inst->func_type_indexes)
         wasm_runtime_free(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)
     if (((AOTModuleInstanceExtra *)module_inst->e)->c_api_func_imports)
         wasm_runtime_free(
         wasm_runtime_free(
             ((AOTModuleInstanceExtra *)module_inst->e)->c_api_func_imports);
             ((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);
     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
     /* Check native stack overflow firstly to ensure we have enough
        native stack to run the following codes before actually calling
        native stack to run the following codes before actually calling
        the aot function in invokeNative function. */
        the aot function in invokeNative function. */
+    RECORD_STACK_USAGE(exec_env, (uint8 *)&module_inst);
     if ((uint8 *)&module_inst < exec_env->native_stack_boundary
     if ((uint8 *)&module_inst < exec_env->native_stack_boundary
                                     + page_size * (guard_page_count + 1)) {
                                     + page_size * (guard_page_count + 1)) {
         aot_set_exception_with_id(module_inst, EXCE_NATIVE_STACK_OVERFLOW);
         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,
         ret = invoke_native_internal(exec_env, function->u.func.func_ptr,
                                      func_type, NULL, NULL, argv1, argc, argv);
                                      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 WASM_ENABLE_DUMP_CALL_STACK != 0
         if (!ret) {
         if (!ret) {
             if (aot_create_call_stack(exec_env)) {
             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,
         ret = invoke_native_internal(exec_env, function->u.func.func_ptr,
                                      func_type, NULL, NULL, argv, argc, argv);
                                      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 WASM_ENABLE_DUMP_CALL_STACK != 0
         if (aot_get_exception(module_inst)) {
         if (aot_get_exception(module_inst)) {
             if (aot_create_call_stack(exec_env)) {
             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 */
     /* don't destroy the exec_env if it isn't created in this function */
     if (!existing_exec_env)
     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_extra =
         (AOTModuleInstanceExtra *)module_inst->e;
         (AOTModuleInstanceExtra *)module_inst->e;
     CApiFuncImport *c_api_func_import =
     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_indexes = module_inst->func_type_indexes;
     uint32 func_type_idx = func_type_indexes[func_idx];
     uint32 func_type_idx = func_type_indexes[func_idx];
     AOTFuncType *func_type = aot_module->func_types[func_type_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;
     import_func = aot_module->import_funcs + func_idx;
     if (import_func->call_conv_wasm_c_api)
     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) {
     if (!func_ptr) {
         snprintf(buf, sizeof(buf),
         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
        exec_env->native_stack_boundary must have been set, we don't set
        it again */
        it again */
 
 
+    RECORD_STACK_USAGE(exec_env, (uint8 *)&module_inst);
     if ((uint8 *)&module_inst < exec_env->native_stack_boundary) {
     if ((uint8 *)&module_inst < exec_env->native_stack_boundary) {
         aot_set_exception_with_id(module_inst, EXCE_NATIVE_STACK_OVERFLOW);
         aot_set_exception_with_id(module_inst, EXCE_NATIVE_STACK_OVERFLOW);
         goto fail;
         goto fail;
@@ -1980,9 +2071,6 @@ aot_call_indirect(WASMExecEnv *exec_env, uint32 tbl_idx, uint32 table_elem_idx,
     }
     }
 
 
 fail:
 fail:
-    if (clear_wasi_proc_exit_exception(module_inst))
-        return true;
-
 #ifdef OS_ENABLE_HW_BOUND_CHECK
 #ifdef OS_ENABLE_HW_BOUND_CHECK
     wasm_runtime_access_exce_check_guard_page();
     wasm_runtime_access_exce_check_guard_page();
 #endif
 #endif

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

@@ -11,6 +11,10 @@
 #include "../interpreter/wasm_runtime.h"
 #include "../interpreter/wasm_runtime.h"
 #include "../compilation/aot.h"
 #include "../compilation/aot.h"
 
 
+#if WASM_ENABLE_WASI_NN != 0
+#include "../libraries/wasi-nn/src/wasi_nn_private.h"
+#endif
+
 #ifdef __cplusplus
 #ifdef __cplusplus
 extern "C" {
 extern "C" {
 #endif
 #endif
@@ -75,6 +79,9 @@ typedef struct AOTFunctionInstance {
 
 
 typedef struct AOTModuleInstanceExtra {
 typedef struct AOTModuleInstanceExtra {
     CApiFuncImport *c_api_func_imports;
     CApiFuncImport *c_api_func_imports;
+#if WASM_ENABLE_WASI_NN != 0
+    WASINNContext *wasi_nn_ctx;
+#endif
 } AOTModuleInstanceExtra;
 } AOTModuleInstanceExtra;
 
 
 #if defined(OS_ENABLE_HW_BOUND_CHECK) && defined(BH_PLATFORM_WINDOWS)
 #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
     push    %ebp
     movl    %esp, %ebp
     movl    %esp, %ebp
     movl    16(%ebp), %ecx          /* ecx = argc */
     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
     test    %ecx, %ecx
     jz      skip_push_args          /* if ecx == 0, skip pushing arguments */
     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 */
     leal    -4(%edx,%ecx,4), %edx   /* edx = edx + ecx * 4 - 4 */
     subl    %esp, %edx              /* edx = edx - esp */
     subl    %esp, %edx              /* edx = edx - esp */
 1:
 1:

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

@@ -203,22 +203,12 @@ wasm_application_execute_main(WASMModuleInstanceCommon *module_inst, int32 argc,
                               char *argv[])
                               char *argv[])
 {
 {
     bool ret;
     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;
     WASMExecEnv *exec_env;
 #endif
 #endif
 
 
     ret = execute_main(module_inst, argc, argv);
     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
 #if WASM_ENABLE_MEMORY_PROFILING != 0
     exec_env = wasm_runtime_get_exec_env_singleton(module_inst);
     exec_env = wasm_runtime_get_exec_env_singleton(module_inst);
     if (exec_env) {
     if (exec_env) {
@@ -622,22 +612,12 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst,
                               const char *name, int32 argc, char *argv[])
                               const char *name, int32 argc, char *argv[])
 {
 {
     bool ret;
     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;
     WASMExecEnv *exec_env;
 #endif
 #endif
 
 
     ret = execute_func(module_inst, name, argc, argv);
     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
 #if WASM_ENABLE_MEMORY_PROFILING != 0
     exec_env = wasm_runtime_get_exec_env_singleton(module_inst);
     exec_env = wasm_runtime_get_exec_env_singleton(module_inst);
     if (exec_env) {
     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)
 WASM_DEFINE_VEC_OWN(valtype, wasm_valtype_delete)
 
 
 #ifndef NDEBUG
 #ifndef NDEBUG
-#if WAMR_BUILD_MEMORY_PROFILING != 0
+#if WASM_ENABLE_MEMORY_PROFILING != 0
 #define WASM_C_DUMP_PROC_MEM() LOG_PROC_MEM()
 #define WASM_C_DUMP_PROC_MEM() LOG_PROC_MEM()
 #else
 #else
 #define WASM_C_DUMP_PROC_MEM() (void)0
 #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 */
 /* global engine instance */
-static wasm_engine_t *singleton_engine = NULL;
+static wasm_engine_t *singleton_engine;
 #ifdef os_thread_local_attribute
 #ifdef os_thread_local_attribute
 /* categorize wasm_store_t as threads*/
 /* categorize wasm_store_t as threads*/
 static os_thread_local_attribute unsigned thread_local_stores_num = 0;
 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;
     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 *
 own wasm_exporttype_t *
 wasm_exporttype_new(own wasm_byte_vec_t *name,
 wasm_exporttype_new(own wasm_byte_vec_t *name,
                     own wasm_externtype_t *extern_type)
                     own wasm_externtype_t *extern_type)
@@ -1633,8 +1657,6 @@ wasm_val_to_rt_val(WASMModuleInstanceCommon *inst_comm_rt, uint8 val_type_rt,
             ret =
             ret =
                 wasm_externref_obj2ref(inst_comm_rt, v->of.ref, (uint32 *)data);
                 wasm_externref_obj2ref(inst_comm_rt, v->of.ref, (uint32 *)data);
             break;
             break;
-#else
-            (void)inst_comm_rt;
 #endif
 #endif
         default:
         default:
             LOG_WARNING("unexpected value type %d", val_type_rt);
             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;
             break;
     }
     }
 
 
+    (void)inst_comm_rt;
     return ret;
     return ret;
 }
 }
 
 
@@ -2537,12 +2560,12 @@ wasm_module_imports(const wasm_module_t *module, own wasm_importtype_vec_t *out)
 
 
         bh_assert(extern_type);
         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) {
         if (strlen(module_name_rt) && !module_name.data) {
             goto failed;
             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) {
         if (strlen(field_name_rt) && !name.data) {
             goto failed;
             goto failed;
         }
         }
@@ -2622,7 +2645,7 @@ wasm_module_exports(const wasm_module_t *module, wasm_exporttype_vec_t *out)
         }
         }
 
 
         /* byte* -> wasm_byte_vec_t */
         /* 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) {
         if (strlen(export->name) && !name.data) {
             goto failed;
             goto failed;
         }
         }
@@ -3008,6 +3031,20 @@ failed:
     return NULL;
     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
 void
 wasm_func_delete(wasm_func_t *func)
 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_name_t message = { 0 };
         wasm_trap_t *trap;
         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);
         trap = wasm_trap_new(func->store, &message);
         wasm_byte_vec_delete(&message);
         wasm_byte_vec_delete(&message);
 
 
@@ -3371,6 +3409,25 @@ failed:
     return NULL;
     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 */
 /* almost same with wasm_global_new */
 wasm_global_t *
 wasm_global_t *
 wasm_global_copy(const wasm_global_t *src)
 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;
             (WASMModuleInstance *)module_inst_comm;
         WASMMemoryInstance *memory_inst =
         WASMMemoryInstance *memory_inst =
             module_inst->memories[memory->memory_idx_rt];
             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
 #endif
 
 
@@ -4215,7 +4273,8 @@ wasm_memory_data_size(const wasm_memory_t *memory)
         AOTMemoryInstance *memory_inst =
         AOTMemoryInstance *memory_inst =
             ((AOTMemoryInstance **)
             ((AOTMemoryInstance **)
                  module_inst->memories)[memory->memory_idx_rt];
                  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
 #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;
     imported_func_interp = module_interp->import_functions + func_idx_rt;
     bh_assert(imported_func_interp);
     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 */
     /* type comparison */
     if (!wasm_functype_same_internal(
     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;
         imported_func_interp->u.function.func_ptr_linked = import->u.cb_env.cb;
     else
     else
         imported_func_interp->u.function.func_ptr_linked = import->u.cb;
         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;
     import->func_idx_rt = func_idx_rt;
 
 
     (void)inst;
     (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;
     imported_global_interp = module_interp->import_globals + global_idx_rt;
     bh_assert(imported_global_interp);
     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),
     if (!cmp_val_kind_with_val_type(wasm_valtype_kind(import->type->val_type),
                                     imported_global_interp->u.global.type))
                                     imported_global_interp->u.global.type))
         return false;
         return false;
 
 
     /* set init value */
     /* set init value */
+    bh_assert(import->init);
     switch (wasm_valtype_kind(import->type->val_type)) {
     switch (wasm_valtype_kind(import->type->val_type)) {
         case WASM_I32:
         case WASM_I32:
             imported_global_interp->u.global.global_data_linked.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;
     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
 static bool
 interp_process_export(wasm_store_t *store,
 interp_process_export(wasm_store_t *store,
                       const WASMModuleInstance *inst_interp,
                       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;
     import_aot_func = module_aot->import_funcs + import_func_idx_rt;
     bh_assert(import_aot_func);
     bh_assert(import_aot_func);
 
 
+    /* it is a placeholder and let's skip it*/
+    if (!import->type)
+        return true;
+
     /* type comparison */
     /* type comparison */
     if (!wasm_functype_same_internal(import->type, import_aot_func->func_type))
     if (!wasm_functype_same_internal(import->type, import_aot_func->func_type))
         return false;
         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;
         import_aot_func->func_ptr_linked = import->u.cb_env.cb;
     else
     else
         import_aot_func->func_ptr_linked = import->u.cb;
         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;
     import->func_idx_rt = import_func_idx_rt;
 
 
     return true;
     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;
     import_aot_global = module_aot->import_globals + global_idx_rt;
     bh_assert(import_aot_global);
     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);
     val_type = wasm_globaltype_content(import->type);
     bh_assert(val_type);
     bh_assert(val_type);
 
 
@@ -4537,6 +4568,7 @@ aot_link_global(const AOTModule *module_aot, uint16 global_idx_rt,
                                     import_aot_global->type))
                                     import_aot_global->type))
         return false;
         return false;
 
 
+    bh_assert(import->init);
     switch (wasm_valtype_kind(val_type)) {
     switch (wasm_valtype_kind(val_type)) {
         case WASM_I32:
         case WASM_I32:
             import_aot_global->global_data_linked.i32 = import->init->of.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->global_idx_rt = global_idx_rt;
+    import_aot_global->is_linked = true;
     return 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:
 failed:
     LOG_DEBUG("%s failed", __FUNCTION__);
     LOG_DEBUG("%s failed", __FUNCTION__);
     return false;
     return false;
@@ -4692,7 +4669,7 @@ aot_process_export(wasm_store_t *store, const AOTModuleInstance *inst_aot,
             goto failed;
             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) {
         if (strlen(export->name) && !external->name->data) {
             goto failed;
             goto failed;
         }
         }
@@ -4710,65 +4687,103 @@ failed:
 }
 }
 #endif /* WASM_ENABLE_AOT */
 #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
 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];
         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)) {
         switch (wasm_extern_kind(import)) {
             case WASM_EXTERN_FUNC:
             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;
                 break;
+            }
             case WASM_EXTERN_GLOBAL:
             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;
                 break;
+            }
             case WASM_EXTERN_MEMORY:
             case WASM_EXTERN_MEMORY:
-                import_memory_count++;
-                break;
             case WASM_EXTERN_TABLE:
             case WASM_EXTERN_TABLE:
-                import_table_count++;
+            {
+                LOG_WARNING("doesn't support import memories and tables for "
+                            "now, ignore them");
                 break;
                 break;
+            }
             default:
             default:
+            {
                 UNREACHABLE();
                 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;
     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_t *
 wasm_instance_new_with_args(wasm_store_t *store, const wasm_module_t *module,
 wasm_instance_new_with_args(wasm_store_t *store, const wasm_module_t *module,
                             const wasm_extern_vec_t *imports,
                             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 sub_error_buf[128] = { 0 };
     char error_buf[256] = { 0 };
     char error_buf[256] = { 0 };
     wasm_instance_t *instance = NULL;
     wasm_instance_t *instance = NULL;
-    WASMModuleInstance *inst_rt;
     CApiFuncImport *func_import = NULL, **p_func_imports = NULL;
     CApiFuncImport *func_import = NULL, **p_func_imports = NULL;
     uint32 i = 0, import_func_count = 0;
     uint32 i = 0, import_func_count = 0;
     uint64 total_size;
     uint64 total_size;
@@ -4789,11 +4803,9 @@ wasm_instance_new_with_args(wasm_store_t *store, const wasm_module_t *module,
     if (!module)
     if (!module)
         return NULL;
         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();
     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;
         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),
             snprintf(sub_error_buf, sizeof(sub_error_buf),
-                     "Failed to verify import count");
+                     "Failed to validate imports");
             goto failed;
             goto failed;
         }
         }
     }
     }
+    /*
+     * will do the linking result check at the end of wasm_runtime_instantiate
+     */
 
 
     instance->inst_comm_rt = wasm_runtime_instantiate(
     instance->inst_comm_rt = wasm_runtime_instantiate(
         *module, stack_size, heap_size, sub_error_buf, sizeof(sub_error_buf));
         *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 */
     /* create the c-api func import list */
-    inst_rt = (WASMModuleInstance *)instance->inst_comm_rt;
 #if WASM_ENABLE_INTERP != 0
 #if WASM_ENABLE_INTERP != 0
     if (instance->inst_comm_rt->module_type == Wasm_Module_Bytecode) {
     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
 #endif
 #if WASM_ENABLE_AOT != 0
 #if WASM_ENABLE_AOT != 0
     if (instance->inst_comm_rt->module_type == Wasm_Module_AoT) {
     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
 #endif
     bh_assert(p_func_imports);
     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;
         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++) {
     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)
         if (wasm_extern_kind(in) != WASM_EXTERN_FUNC)
             continue;
             continue;
 
 
         func_host = wasm_extern_as_func(in);
         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;
         func_import->with_env_arg = func_host->with_env;
         if (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->func_ptr_linked = func_host->u.cb;
             func_import->env_arg = NULL;
             func_import->env_arg = NULL;
         }
         }
+        bh_assert(func_import->func_ptr_linked);
 
 
         func_import++;
         func_import++;
     }
     }
@@ -4906,6 +4902,8 @@ wasm_instance_new_with_args(wasm_store_t *store, const wasm_module_t *module,
     /* fill with inst */
     /* fill with inst */
     for (i = 0; imports && imports->data && i < imports->num_elems; ++i) {
     for (i = 0; imports && imports->data && i < imports->num_elems; ++i) {
         wasm_extern_t *import = imports->data[i];
         wasm_extern_t *import = imports->data[i];
+        bh_assert(import);
+
         switch (import->kind) {
         switch (import->kind) {
             case WASM_EXTERN_FUNC:
             case WASM_EXTERN_FUNC:
                 wasm_extern_as_func(import)->inst_comm_rt =
                 wasm_extern_as_func(import)->inst_comm_rt =
@@ -5001,7 +4999,7 @@ failed:
              sub_error_buf);
              sub_error_buf);
     if (trap != NULL) {
     if (trap != NULL) {
         wasm_message_t message = { 0 };
         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);
         *trap = wasm_trap_new(store, &message);
         wasm_byte_vec_delete(&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)
 BASIC_FOUR_LIST(WASM_OTHER_AS_EXTERN_CONST)
 #undef 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)
 wasm_exec_env_destroy(WASMExecEnv *exec_env)
 {
 {
 #if WASM_ENABLE_THREAD_MGR != 0
 #if WASM_ENABLE_THREAD_MGR != 0
-    /* Terminate all sub-threads */
+    /* Wait for all sub-threads */
     WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env);
     WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env);
     if (cluster) {
     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
 #if WASM_ENABLE_DEBUG_INTERP != 0
         /* Must fire exit event after other threads exits, otherwise
         /* Must fire exit event after other threads exits, otherwise
            the stopped thread will be overrided by other threads */
            the stopped thread will be overrided by other threads */
         wasm_cluster_thread_exited(exec_env);
         wasm_cluster_thread_exited(exec_env);
 #endif
 #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);
         wasm_cluster_del_exec_env(cluster, exec_env);
     }
     }
 #endif /* end of WASM_ENABLE_THREAD_MGR */
 #endif /* end of WASM_ENABLE_THREAD_MGR */
@@ -205,9 +208,17 @@ void
 wasm_exec_env_set_thread_info(WASMExecEnv *exec_env)
 wasm_exec_env_set_thread_info(WASMExecEnv *exec_env)
 {
 {
     uint8 *stack_boundary = os_thread_get_stack_boundary();
     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->handle = os_self_thread();
     exec_env->native_stack_boundary =
     exec_env->native_stack_boundary =
         stack_boundary ? stack_boundary + WASM_STACK_GUARD_SIZE : NULL;
         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
 #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;
     void **native_symbol;
 #endif
 #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
 #if WASM_ENABLE_FAST_JIT != 0
     /**
     /**
      * Cache for
      * Cache for
@@ -165,6 +171,17 @@ typedef struct WASMExecEnv {
     } wasm_stack;
     } wasm_stack;
 } WASMExecEnv;
 } 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 *
 WASMExecEnv *
 wasm_exec_env_create_internal(struct WASMModuleInstanceCommon *module_inst,
 wasm_exec_env_create_internal(struct WASMModuleInstanceCommon *module_inst,
                               uint32 stack_size);
                               uint32 stack_size);
@@ -179,6 +196,13 @@ wasm_exec_env_create(struct WASMModuleInstanceCommon *module_inst,
 void
 void
 wasm_exec_env_destroy(WASMExecEnv *exec_env);
 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.
  * 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 "bh_platform.h"
 #include "mem_alloc.h"
 #include "mem_alloc.h"
 
 
+#if WASM_ENABLE_SHARED_MEMORY != 0
+#include "../common/wasm_shared_memory.h"
+#endif
+
 typedef enum Memory_Mode {
 typedef enum Memory_Mode {
     MEMORY_MODE_UNKNOWN = 0,
     MEMORY_MODE_UNKNOWN = 0,
     MEMORY_MODE_POOL,
     MEMORY_MODE_POOL,
@@ -506,7 +510,7 @@ wasm_get_default_memory(WASMModuleInstance *module_inst)
 
 
 #ifndef OS_ENABLE_HW_BOUND_CHECK
 #ifndef OS_ENABLE_HW_BOUND_CHECK
 bool
 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);
     WASMMemoryInstance *memory = wasm_get_default_memory(module);
     uint8 *memory_data_old, *memory_data_new, *heap_data_old;
     uint8 *memory_data_old, *memory_data_new, *heap_data_old;
@@ -624,7 +628,7 @@ wasm_enlarge_memory(WASMModuleInstance *module, uint32 inc_page_count)
 }
 }
 #else
 #else
 bool
 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);
     WASMMemoryInstance *memory = wasm_get_default_memory(module);
     uint32 num_bytes_per_page, total_size_old;
     uint32 num_bytes_per_page, total_size_old;
@@ -697,3 +701,59 @@ wasm_enlarge_memory(WASMModuleInstance *module, uint32 inc_page_count)
     return true;
     return true;
 }
 }
 #endif /* end of OS_ENABLE_HW_BOUND_CHECK */
 #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 "bh_common.h"
 #include "../include/wasm_export.h"
 #include "../include/wasm_export.h"
+#include "../interpreter/wasm_runtime.h"
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 extern "C" {
 extern "C" {
@@ -23,6 +24,16 @@ wasm_runtime_memory_destroy();
 unsigned
 unsigned
 wasm_runtime_memory_pool_size();
 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
 #ifdef __cplusplus
 }
 }
 #endif
 #endif

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

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

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

@@ -7,6 +7,7 @@
 #include "bh_common.h"
 #include "bh_common.h"
 #include "bh_assert.h"
 #include "bh_assert.h"
 #include "bh_log.h"
 #include "bh_log.h"
+#include "wasm_native.h"
 #include "wasm_runtime_common.h"
 #include "wasm_runtime_common.h"
 #include "wasm_memory.h"
 #include "wasm_memory.h"
 #if WASM_ENABLE_INTERP != 0
 #if WASM_ENABLE_INTERP != 0
@@ -128,6 +129,12 @@ runtime_malloc(uint64 size, WASMModuleInstanceCommon *module_inst,
 static JitCompOptions jit_options = { 0 };
 static JitCompOptions jit_options = { 0 };
 #endif
 #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
 #ifdef OS_ENABLE_HW_BOUND_CHECK
 /* The exec_env of thread local storage, set before calling function
 /* The exec_env of thread local storage, set before calling function
    and used in signal handler, as we cannot get it from the argument
    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
         else if (exec_env_tls->exce_check_guard_page <= (uint8 *)sig_addr
                  && (uint8 *)sig_addr
                  && (uint8 *)sig_addr
                         < exec_env_tls->exce_check_guard_page + page_size) {
                         < 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);
             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
             else if (exec_env_tls->exce_check_guard_page <= (uint8 *)sig_addr
                      && (uint8 *)sig_addr
                      && (uint8 *)sig_addr
                             < exec_env_tls->exce_check_guard_page + page_size) {
                             < 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) {
                 if (module_inst->module_type == Wasm_Module_Bytecode) {
                     return EXCEPTION_CONTINUE_SEARCH;
                     return EXCEPTION_CONTINUE_SEARCH;
                 }
                 }
@@ -514,6 +521,20 @@ wasm_runtime_destroy()
     wasm_runtime_memory_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
 bool
 wasm_runtime_full_init(RuntimeInitArgs *init_args)
 wasm_runtime_full_init(RuntimeInitArgs *init_args)
 {
 {
@@ -521,10 +542,20 @@ wasm_runtime_full_init(RuntimeInitArgs *init_args)
                                   &init_args->mem_alloc_option))
                                   &init_args->mem_alloc_option))
         return false;
         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
 #if WASM_ENABLE_FAST_JIT != 0
     jit_options.code_cache_size = init_args->fast_jit_code_cache_size;
     jit_options.code_cache_size = init_args->fast_jit_code_cache_size;
 #endif
 #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()) {
     if (!wasm_runtime_env_init()) {
         wasm_runtime_memory_destroy();
         wasm_runtime_memory_destroy();
         return false;
         return false;
@@ -554,6 +585,47 @@ wasm_runtime_full_init(RuntimeInitArgs *init_args)
     return true;
     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
 PackageType
 get_package_type(const uint8 *buf, uint32 size)
 get_package_type(const uint8 *buf, uint32 size)
 {
 {
@@ -1171,6 +1243,41 @@ wasm_runtime_deinstantiate_internal(WASMModuleInstanceCommon *module_inst,
 #endif
 #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
 void
 wasm_runtime_deinstantiate(WASMModuleInstanceCommon *module_inst)
 wasm_runtime_deinstantiate(WASMModuleInstanceCommon *module_inst)
 {
 {
@@ -1399,6 +1506,22 @@ wasm_runtime_dump_mem_consumption(WASMExecEnv *exec_env)
     else
     else
         os_printf("Total aux stack used: no enough info to profile\n");
         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);
     os_printf("Total app heap used: %u\n", app_heap_peak_size);
 }
 }
 #endif /* end of (WASM_ENABLE_MEMORY_PROFILING != 0) \
 #endif /* end of (WASM_ENABLE_MEMORY_PROFILING != 0) \
@@ -1743,6 +1866,33 @@ wasm_runtime_finalize_call_function(WASMExecEnv *exec_env,
 }
 }
 #endif
 #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
 bool
 wasm_runtime_call_wasm(WASMExecEnv *exec_env,
 wasm_runtime_call_wasm(WASMExecEnv *exec_env,
                        WASMFunctionInstanceCommon *function, uint32 argc,
                        WASMFunctionInstanceCommon *function, uint32 argc,
@@ -1783,10 +1933,15 @@ wasm_runtime_call_wasm(WASMExecEnv *exec_env,
                                 param_argc, new_argv);
                                 param_argc, new_argv);
 #endif
 #endif
     if (!ret) {
     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
 #if WASM_ENABLE_REF_TYPES != 0
@@ -2150,11 +2305,41 @@ wasm_runtime_get_exec_env_singleton(WASMModuleInstanceCommon *module_inst_comm)
 void
 void
 wasm_set_exception(WASMModuleInstance *module_inst, const char *exception)
 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),
         snprintf(module_inst->cur_exception, sizeof(module_inst->cur_exception),
                  "Exception: %s", exception);
                  "Exception: %s", exception);
-    else
+    }
+    else {
         module_inst->cur_exception[0] = '\0';
         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 */
 /* clang-format off */
@@ -2176,9 +2361,7 @@ static const char *exception_msgs[] = {
     "wasm auxiliary stack underflow", /* EXCE_AUX_STACK_UNDERFLOW */
     "wasm auxiliary stack underflow", /* EXCE_AUX_STACK_UNDERFLOW */
     "out of bounds table access",     /* EXCE_OUT_OF_BOUNDS_TABLE_ACCESS */
     "out of bounds table access",     /* EXCE_OUT_OF_BOUNDS_TABLE_ACCESS */
     "wasm operand stack overflow",    /* EXCE_OPERAND_STACK_OVERFLOW */
     "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 */
     "failed to compile fast jit function", /* EXCE_FAILED_TO_COMPILE_FAST_JIT_FUNC */
-#endif
     "",                               /* EXCE_ALREADY_THROWN */
     "",                               /* EXCE_ALREADY_THROWN */
 };
 };
 /* clang-format on */
 /* clang-format on */
@@ -2201,6 +2384,36 @@ wasm_get_exception(WASMModuleInstance *module_inst)
         return module_inst->cur_exception;
         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
 void
 wasm_runtime_set_exception(WASMModuleInstanceCommon *module_inst_comm,
 wasm_runtime_set_exception(WASMModuleInstanceCommon *module_inst_comm,
                            const char *exception)
                            const char *exception)
@@ -2222,6 +2435,17 @@ wasm_runtime_get_exception(WASMModuleInstanceCommon *module_inst_comm)
     return wasm_get_exception(module_inst);
     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
 void
 wasm_runtime_clear_exception(WASMModuleInstanceCommon *module_inst_comm)
 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:
 fail:
     if (argv1 != argv_buf)
     if (argv1 != argv_buf)
@@ -3620,7 +3844,7 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr,
     }
     }
     exec_env->attachment = NULL;
     exec_env->attachment = NULL;
 
 
-    ret = !wasm_runtime_get_exception(module) ? true : false;
+    ret = !wasm_runtime_copy_exception(module, NULL);
 
 
 fail:
 fail:
     if (argv1 != argv_buf)
     if (argv1 != argv_buf)
@@ -3834,7 +4058,7 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr,
     }
     }
     exec_env->attachment = NULL;
     exec_env->attachment = NULL;
 
 
-    ret = !wasm_runtime_get_exception(module) ? true : false;
+    ret = !wasm_runtime_copy_exception(module, NULL);
 
 
 fail:
 fail:
     if (argv1 != argv_buf)
     if (argv1 != argv_buf)
@@ -4161,7 +4385,7 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr,
     }
     }
     exec_env->attachment = NULL;
     exec_env->attachment = NULL;
 
 
-    ret = !wasm_runtime_get_exception(module) ? true : false;
+    ret = !wasm_runtime_copy_exception(module, NULL);
 fail:
 fail:
     if (argv1 != argv_buf)
     if (argv1 != argv_buf)
         wasm_runtime_free(argv1);
         wasm_runtime_free(argv1);
@@ -4176,9 +4400,11 @@ fail:
                  || defined(BUILD_TARGET_RISCV64_LP64) */
                  || defined(BUILD_TARGET_RISCV64_LP64) */
 
 
 bool
 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[])
                            uint32 argc, uint32 argv[])
 {
 {
+    bool ret = false;
+
     if (!wasm_runtime_exec_env_check(exec_env)) {
     if (!wasm_runtime_exec_env_check(exec_env)) {
         LOG_ERROR("Invalid exec env stack info.");
         LOG_ERROR("Invalid exec env stack info.");
         return false;
         return false;
@@ -4190,13 +4416,18 @@ wasm_runtime_call_indirect(WASMExecEnv *exec_env, uint32 element_indices,
 
 
 #if WASM_ENABLE_INTERP != 0
 #if WASM_ENABLE_INTERP != 0
     if (exec_env->module_inst->module_type == Wasm_Module_Bytecode)
     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
 #endif
 #if WASM_ENABLE_AOT != 0
 #if WASM_ENABLE_AOT != 0
     if (exec_env->module_inst->module_type == Wasm_Module_AoT)
     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
 #endif
-    return false;
+
+    if (!ret && clear_wasi_proc_exit_exception(exec_env->module_inst)) {
+        ret = true;
+    }
+
+    return ret;
 }
 }
 
 
 static void
 static void
@@ -5155,3 +5386,24 @@ wasm_runtime_get_version(uint32_t *major, uint32_t *minor, uint32_t *patch)
     *minor = WAMR_VERSION_MINOR;
     *minor = WAMR_VERSION_MINOR;
     *patch = WAMR_VERSION_PATCH;
     *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" {
 extern "C" {
 #endif
 #endif
 
 
+/* Internal use for setting default running mode */
+#define Mode_Default 0
+
 #if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS != 0
 #if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS != 0
 
 
 #define PUT_I64_TO_ADDR(addr, value)       \
 #define PUT_I64_TO_ADDR(addr, value)       \
@@ -413,6 +416,13 @@ typedef struct wasm_frame_t {
     const char *func_name_wp;
     const char *func_name_wp;
 } WASMCApiFrame;
 } WASMCApiFrame;
 
 
+#ifdef WASM_ENABLE_JIT
+typedef struct LLVMJITOptions {
+    uint32 opt_level;
+    uint32 size_level;
+} LLVMJITOptions;
+#endif
+
 #ifdef OS_ENABLE_HW_BOUND_CHECK
 #ifdef OS_ENABLE_HW_BOUND_CHECK
 /* Signal info passing to interp/aot signal handler */
 /* Signal info passing to interp/aot signal handler */
 typedef struct WASMSignalInfo {
 typedef struct WASMSignalInfo {
@@ -437,10 +447,28 @@ wasm_runtime_get_exec_env_tls(void);
 WASM_RUNTIME_API_EXTERN bool
 WASM_RUNTIME_API_EXTERN bool
 wasm_runtime_init(void);
 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 */
 /* See wasm_export.h for description */
 WASM_RUNTIME_API_EXTERN bool
 WASM_RUNTIME_API_EXTERN bool
 wasm_runtime_full_init(RuntimeInitArgs *init_args);
 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 */
 /* See wasm_export.h for description */
 WASM_RUNTIME_API_EXTERN void
 WASM_RUNTIME_API_EXTERN void
 wasm_runtime_destroy(void);
 wasm_runtime_destroy(void);
@@ -484,6 +512,15 @@ wasm_runtime_instantiate(WASMModuleCommon *module, uint32 stack_size,
                          uint32 heap_size, char *error_buf,
                          uint32 heap_size, char *error_buf,
                          uint32 error_buf_size);
                          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 */
 /* See wasm_export.h for description */
 WASM_RUNTIME_API_EXTERN void
 WASM_RUNTIME_API_EXTERN void
 wasm_runtime_deinstantiate(WASMModuleInstanceCommon *module_inst);
 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_results, wasm_val_t *results,
                          uint32 num_args, ...);
                          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
 #if WASM_ENABLE_DEBUG_INTERP != 0
 /* See wasm_export.h for description */
 /* See wasm_export.h for description */
 WASM_RUNTIME_API_EXTERN uint32
 WASM_RUNTIME_API_EXTERN uint32
@@ -589,27 +631,6 @@ WASM_RUNTIME_API_EXTERN uint32
 wasm_runtime_start_debug_instance(WASMExecEnv *exec_env);
 wasm_runtime_start_debug_instance(WASMExecEnv *exec_env);
 #endif
 #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
 bool
 wasm_runtime_create_exec_env_singleton(WASMModuleInstanceCommon *module_inst);
 wasm_runtime_create_exec_env_singleton(WASMModuleInstanceCommon *module_inst);
 
 
@@ -956,6 +977,14 @@ void
 wasm_runtime_destroy_custom_sections(WASMCustomSection *section_list);
 wasm_runtime_destroy_custom_sections(WASMCustomSection *section_list);
 #endif
 #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
 #ifdef __cplusplus
 }
 }
 #endif
 #endif

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

@@ -30,8 +30,14 @@ typedef struct AtomicWaitNode {
     korp_cond wait_cond;
     korp_cond wait_cond;
 } AtomicWaitNode;
 } AtomicWaitNode;
 
 
+typedef struct AtomicWaitAddressArgs {
+    uint32 index;
+    void **addr;
+} AtomicWaitAddressArgs;
+
 /* Atomic wait map */
 /* Atomic wait map */
 static HashMap *wait_map;
 static HashMap *wait_map;
+static korp_mutex wait_map_lock;
 
 
 static uint32
 static uint32
 wait_address_hash(void *address);
 wait_address_hash(void *address);
@@ -47,11 +53,18 @@ wasm_shared_memory_init()
 {
 {
     if (os_mutex_init(&shared_memory_list_lock) != 0)
     if (os_mutex_init(&shared_memory_list_lock) != 0)
         return false;
         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 */
     /* wait map not exists, create new map */
     if (!(wait_map = bh_hash_map_create(32, true, (HashFunc)wait_address_hash,
     if (!(wait_map = bh_hash_map_create(32, true, (HashFunc)wait_address_hash,
                                         (KeyEqualFunc)wait_address_equal, NULL,
                                         (KeyEqualFunc)wait_address_equal, NULL,
                                         destroy_wait_info))) {
                                         destroy_wait_info))) {
         os_mutex_destroy(&shared_memory_list_lock);
         os_mutex_destroy(&shared_memory_list_lock);
+        os_mutex_destroy(&wait_map_lock);
         return false;
         return false;
     }
     }
 
 
@@ -62,6 +75,7 @@ void
 wasm_shared_memory_destroy()
 wasm_shared_memory_destroy()
 {
 {
     os_mutex_destroy(&shared_memory_list_lock);
     os_mutex_destroy(&shared_memory_list_lock);
+    os_mutex_destroy(&wait_map_lock);
     if (wait_map) {
     if (wait_map) {
         bh_hash_map_destroy(wait_map);
         bh_hash_map_destroy(wait_map);
     }
     }
@@ -87,6 +101,61 @@ search_module(WASMModuleCommon *module)
     return NULL;
     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 *
 WASMSharedMemNode *
 wasm_module_get_shared_memory(WASMModuleCommon *module)
 wasm_module_get_shared_memory(WASMModuleCommon *module)
 {
 {
@@ -97,13 +166,13 @@ int32
 shared_memory_inc_reference(WASMModuleCommon *module)
 shared_memory_inc_reference(WASMModuleCommon *module)
 {
 {
     WASMSharedMemNode *node = search_module(module);
     WASMSharedMemNode *node = search_module(module);
+    uint32 ref_count = -1;
     if (node) {
     if (node) {
         os_mutex_lock(&node->lock);
         os_mutex_lock(&node->lock);
-        node->ref_count++;
+        ref_count = ++node->ref_count;
         os_mutex_unlock(&node->lock);
         os_mutex_unlock(&node->lock);
-        return node->ref_count;
     }
     }
-    return -1;
+    return ref_count;
 }
 }
 
 
 int32
 int32
@@ -120,6 +189,7 @@ shared_memory_dec_reference(WASMModuleCommon *module)
             bh_list_remove(shared_memory_list, node);
             bh_list_remove(shared_memory_list, node);
             os_mutex_unlock(&shared_memory_list_lock);
             os_mutex_unlock(&shared_memory_list_lock);
 
 
+            os_mutex_destroy(&node->shared_mem_lock);
             os_mutex_destroy(&node->lock);
             os_mutex_destroy(&node->lock);
             wasm_runtime_free(node);
             wasm_runtime_free(node);
         }
         }
@@ -148,7 +218,14 @@ shared_memory_set_memory_inst(WASMModuleCommon *module,
     node->module = module;
     node->module = module;
     node->memory_inst = memory;
     node->memory_inst = memory;
     node->ref_count = 1;
     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) {
     if (os_mutex_init(&node->lock) != 0) {
+        os_mutex_destroy(&node->shared_mem_lock);
         wasm_runtime_free(node);
         wasm_runtime_free(node);
         return NULL;
         return NULL;
     }
     }
@@ -208,9 +285,11 @@ notify_wait_list(bh_list *wait_list, uint32 count)
         bh_assert(node);
         bh_assert(node);
         next = bh_list_elem_next(node);
         next = bh_list_elem_next(node);
 
 
+        os_mutex_lock(&node->wait_lock);
         node->status = S_NOTIFIED;
         node->status = S_NOTIFIED;
         /* wakeup */
         /* wakeup */
         os_cond_signal(&node->wait_cond);
         os_cond_signal(&node->wait_cond);
+        os_mutex_unlock(&node->wait_lock);
 
 
         node = next;
         node = next;
     }
     }
@@ -224,13 +303,13 @@ acquire_wait_info(void *address, bool create)
     AtomicWaitInfo *wait_info = NULL;
     AtomicWaitInfo *wait_info = NULL;
     bh_list_status ret;
     bh_list_status ret;
 
 
-    os_mutex_lock(&shared_memory_list_lock);
+    os_mutex_lock(&wait_map_lock); /* Make find + insert atomic */
 
 
     if (address)
     if (address)
         wait_info = (AtomicWaitInfo *)bh_hash_map_find(wait_map, address);
         wait_info = (AtomicWaitInfo *)bh_hash_map_find(wait_map, address);
 
 
     if (!create) {
     if (!create) {
-        os_mutex_unlock(&shared_memory_list_lock);
+        os_mutex_unlock(&wait_map_lock);
         return wait_info;
         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);
     bh_assert(wait_info);
     (void)ret;
     (void)ret;
@@ -270,7 +349,7 @@ fail2:
     wasm_runtime_free(wait_info);
     wasm_runtime_free(wait_info);
 
 
 fail1:
 fail1:
-    os_mutex_unlock(&shared_memory_list_lock);
+    os_mutex_unlock(&wait_map_lock);
 
 
     return NULL;
     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
 uint32
@@ -317,11 +395,16 @@ wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address,
     WASMModuleInstance *module_inst = (WASMModuleInstance *)module;
     WASMModuleInstance *module_inst = (WASMModuleInstance *)module;
     AtomicWaitInfo *wait_info;
     AtomicWaitInfo *wait_info;
     AtomicWaitNode *wait_node;
     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
     bh_assert(module->module_type == Wasm_Module_Bytecode
               || module->module_type == Wasm_Module_AoT);
               || module->module_type == Wasm_Module_AoT);
 
 
+    if (wasm_copy_exception(module_inst, NULL)) {
+        return -1;
+    }
+
     /* Currently we have only one memory instance */
     /* Currently we have only one memory instance */
     if (!module_inst->memories[0]->is_shared) {
     if (!module_inst->memories[0]->is_shared) {
         wasm_runtime_set_exception(module, "expected shared memory");
         wasm_runtime_set_exception(module, "expected shared memory");
@@ -343,11 +426,13 @@ wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address,
         return -1;
         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;
         return 1;
     }
     }
     else {
     else {
@@ -355,33 +440,29 @@ wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address,
 
 
         if (!(wait_node = wasm_runtime_malloc(sizeof(AtomicWaitNode)))) {
         if (!(wait_node = wasm_runtime_malloc(sizeof(AtomicWaitNode)))) {
             wasm_runtime_set_exception(module, "failed to create wait node");
             wasm_runtime_set_exception(module, "failed to create wait node");
-            os_mutex_unlock(&wait_info->wait_list_lock);
             return -1;
             return -1;
         }
         }
         memset(wait_node, 0, sizeof(AtomicWaitNode));
         memset(wait_node, 0, sizeof(AtomicWaitNode));
 
 
         if (0 != os_mutex_init(&wait_node->wait_lock)) {
         if (0 != os_mutex_init(&wait_node->wait_lock)) {
             wasm_runtime_free(wait_node);
             wasm_runtime_free(wait_node);
-            os_mutex_unlock(&wait_info->wait_list_lock);
             return -1;
             return -1;
         }
         }
 
 
         if (0 != os_cond_init(&wait_node->wait_cond)) {
         if (0 != os_cond_init(&wait_node->wait_cond)) {
             os_mutex_destroy(&wait_node->wait_lock);
             os_mutex_destroy(&wait_node->wait_lock);
             wasm_runtime_free(wait_node);
             wasm_runtime_free(wait_node);
-            os_mutex_unlock(&wait_info->wait_list_lock);
             return -1;
             return -1;
         }
         }
 
 
         wait_node->status = S_WAITING;
         wait_node->status = S_WAITING;
-
+        os_mutex_lock(&wait_info->wait_list_lock);
         ret = bh_list_insert(wait_info->wait_list, wait_node);
         ret = bh_list_insert(wait_info->wait_list, wait_node);
+        os_mutex_unlock(&wait_info->wait_list_lock);
         bh_assert(ret == BH_LIST_SUCCESS);
         bh_assert(ret == BH_LIST_SUCCESS);
         (void)ret;
         (void)ret;
     }
     }
 
 
-    os_mutex_unlock(&wait_info->wait_list_lock);
-
     /* condition wait start */
     /* condition wait start */
     os_mutex_lock(&wait_node->wait_lock);
     os_mutex_lock(&wait_node->wait_lock);
 
 
@@ -389,22 +470,27 @@ wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address,
                          timeout < 0 ? BHT_WAIT_FOREVER
                          timeout < 0 ? BHT_WAIT_FOREVER
                                      : (uint64)timeout / 1000);
                                      : (uint64)timeout / 1000);
 
 
+    is_timeout = wait_node->status == S_WAITING ? true : false;
     os_mutex_unlock(&wait_node->wait_lock);
     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);
     os_mutex_lock(&wait_info->wait_list_lock);
+
     check_ret = is_wait_node_exists(wait_info->wait_list, wait_node);
     check_ret = is_wait_node_exists(wait_info->wait_list, wait_node);
     bh_assert(check_ret);
     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);
     bh_list_remove(wait_info->wait_list, wait_node);
     os_mutex_destroy(&wait_node->wait_lock);
     os_mutex_destroy(&wait_node->wait_lock);
     os_cond_destroy(&wait_node->wait_cond);
     os_cond_destroy(&wait_node->wait_cond);
     wasm_runtime_free(wait_node);
     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;
     (void)check_ret;
     return is_timeout ? 2 : 0;
     return is_timeout ? 2 : 0;
@@ -417,12 +503,22 @@ wasm_runtime_atomic_notify(WASMModuleInstanceCommon *module, void *address,
     WASMModuleInstance *module_inst = (WASMModuleInstance *)module;
     WASMModuleInstance *module_inst = (WASMModuleInstance *)module;
     uint32 notify_result;
     uint32 notify_result;
     AtomicWaitInfo *wait_info;
     AtomicWaitInfo *wait_info;
+    WASMSharedMemNode *node;
+    bool out_of_bounds;
 
 
     bh_assert(module->module_type == Wasm_Module_Bytecode
     bh_assert(module->module_type == Wasm_Module_Bytecode
               || module->module_type == Wasm_Module_AoT);
               || 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");
         wasm_runtime_set_exception(module, "out of bounds memory access");
         return -1;
         return -1;
     }
     }
@@ -430,12 +526,18 @@ wasm_runtime_atomic_notify(WASMModuleInstanceCommon *module, void *address,
     wait_info = acquire_wait_info(address, false);
     wait_info = acquire_wait_info(address, false);
 
 
     /* Nobody wait on this address */
     /* Nobody wait on this address */
-    if (!wait_info)
+    if (!wait_info) {
+        if (node)
+            os_mutex_unlock(&node->shared_mem_lock);
         return 0;
         return 0;
+    }
 
 
     os_mutex_lock(&wait_info->wait_list_lock);
     os_mutex_lock(&wait_info->wait_list_lock);
     notify_result = notify_wait_list(wait_info->wait_list, count);
     notify_result = notify_wait_list(wait_info->wait_list, count);
     os_mutex_unlock(&wait_info->wait_list_lock);
     os_mutex_unlock(&wait_info->wait_list_lock);
 
 
+    if (node)
+        os_mutex_unlock(&node->shared_mem_lock);
+
     return notify_result;
     return notify_result;
 }
 }

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

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

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

@@ -149,6 +149,7 @@ typedef struct AOTImportGlobal {
     uint32 data_offset;
     uint32 data_offset;
     /* global data after linked */
     /* global data after linked */
     WASMValue global_data_linked;
     WASMValue global_data_linked;
+    bool is_linked;
 } AOTImportGlobal;
 } 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:
                     case WASM_OP_ATOMIC_FENCE:
                         /* Skip memory index */
                         /* Skip memory index */
                         frame_ip++;
                         frame_ip++;
+                        if (!aot_compiler_op_atomic_fence(comp_ctx, func_ctx))
+                            return false;
                         break;
                         break;
                     case WASM_OP_ATOMIC_I32_LOAD:
                     case WASM_OP_ATOMIC_I32_LOAD:
                         bytes = 4;
                         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_SIX LLVM_CONST(i32_six)
 #define I32_SEVEN LLVM_CONST(i32_seven)
 #define I32_SEVEN LLVM_CONST(i32_seven)
 #define I32_EIGHT LLVM_CONST(i32_eight)
 #define I32_EIGHT LLVM_CONST(i32_eight)
+#define I32_NINE LLVM_CONST(i32_nine)
 #define I32_NEG_ONE LLVM_CONST(i32_neg_one)
 #define I32_NEG_ONE LLVM_CONST(i32_neg_one)
 #define I64_NEG_ONE LLVM_CONST(i64_neg_one)
 #define I64_NEG_ONE LLVM_CONST(i64_neg_one)
 #define I32_MIN LLVM_CONST(i32_min)
 #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_intrinsic.h"
 #include "../aot/aot_runtime.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
     if (comp_ctx->disable_llvm_intrinsics
         && aot_intrinsic_check_capability(
         && aot_intrinsic_check_capability(
             comp_ctx, src_type == F32_TYPE ? "f32_cmp" : "f64_cmp")) {
             comp_ctx, src_type == F32_TYPE ? "f32_cmp" : "f64_cmp")) {
         LLVMTypeRef param_types[3];
         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[0] = I32_TYPE;
         param_types[1] = src_type;
         param_types[1] = src_type;
         param_types[2] = src_type;
         param_types[2] = src_type;
         res = aot_call_llvm_intrinsic(
         res = aot_call_llvm_intrinsic(
             comp_ctx, func_ctx, src_type == F32_TYPE ? "f32_cmp" : "f64_cmp",
             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) {
         if (!res) {
             goto fail;
             goto fail;
         }
         }
         res = LLVMBuildIntCast(comp_ctx->builder, res, INT1_TYPE, "bit_cast");
         res = LLVMBuildIntCast(comp_ctx->builder, res, INT1_TYPE, "bit_cast");
     }
     }
     else {
     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) {
     if (!res) {
         aot_set_last_error("llvm build fcmp failed.");
         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)))
                              check_nan_succ)))
         goto fail;
         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) {
     if (!is_less) {
         aot_set_last_error("llvm build fcmp failed.");
         aot_set_last_error("llvm build fcmp failed.");
         goto fail;
         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) {
     if (!is_greater) {
         aot_set_last_error("llvm build fcmp failed.");
         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 zero = (dest_type == I32_TYPE) ? I32_ZERO : I64_ZERO;
     LLVMValueRef vmin, vmax;
     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.");
         aot_set_last_error("llvm build fcmp failed.");
         goto fail;
         goto fail;
     }
     }
@@ -212,8 +189,9 @@ trunc_sat_float_to_int(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
 
 
     /* Start to translate check_nan_succ block */
     /* Start to translate check_nan_succ block */
     LLVMPositionBuilderAtEnd(comp_ctx->builder, check_nan_succ);
     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.");
         aot_set_last_error("llvm build fcmp failed.");
         goto fail;
         goto fail;
     }
     }
@@ -232,8 +210,9 @@ trunc_sat_float_to_int(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
 
 
     /* Start to translate check_less_succ block */
     /* Start to translate check_less_succ block */
     LLVMPositionBuilderAtEnd(comp_ctx->builder, check_less_succ);
     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.");
         aot_set_last_error("llvm build fcmp failed.");
         goto fail;
         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) \
 #endif /* end of (WASM_ENABLE_DUMP_CALL_STACK != 0) \
                  || (WASM_ENABLE_PERF_PROFILING != 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
 static bool
 check_stack_boundary(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
 check_stack_boundary(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
                      uint32 callee_cell_num)
                      uint32 callee_cell_num)
@@ -409,6 +490,19 @@ check_stack_boundary(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     return true;
     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,
  * Check whether the app address and its buffer are inside the linear memory,
  * if no, throw exception
  * if no, throw exception
@@ -852,8 +946,7 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
         callee_cell_num =
         callee_cell_num =
             aot_func->param_cell_num + aot_func->local_cell_num + 1;
             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;
             goto fail;
 
 
 #if LLVM_VERSION_MAJOR >= 14
 #if LLVM_VERSION_MAJOR >= 14
@@ -906,6 +999,14 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     }
     }
 #endif
 #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;
     ret = true;
 fail:
 fail:
     if (param_types)
     if (param_types)
@@ -1467,12 +1568,11 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     /* Translate call non-import block */
     /* Translate call non-import block */
     LLVMPositionBuilderAtEnd(comp_ctx->builder, block_call_non_import);
     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;
         goto fail;
 
 
     /* Load function pointer */
     /* Load function pointer */
@@ -1553,6 +1653,14 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     }
     }
 #endif
 #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;
     ret = true;
 
 
 fail:
 fail:

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

@@ -7,6 +7,7 @@
 #include "aot_emit_exception.h"
 #include "aot_emit_exception.h"
 #include "../aot/aot_runtime.h"
 #include "../aot/aot_runtime.h"
 #include "aot_intrinsic.h"
 #include "aot_intrinsic.h"
+#include "aot_emit_control.h"
 
 
 #define BUILD_ICMP(op, left, right, res, name)                                \
 #define BUILD_ICMP(op, left, right, res, name)                                \
     do {                                                                      \
     do {                                                                      \
@@ -1344,7 +1345,7 @@ aot_compile_op_atomic_wait(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
         return false;
         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_fail, "atomic_wait_fail");
     ADD_BASIC_BLOCK(wait_success, "wait_success");
     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);
     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;
     return true;
 fail:
 fail:
     return false;
     return false;
@@ -1414,4 +1423,13 @@ fail:
     return false;
     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 */
 #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,
 aot_compiler_op_atomic_notify(AOTCompContext *comp_ctx,
                               AOTFuncContext *func_ctx, uint32 align,
                               AOTFuncContext *func_ctx, uint32 align,
                               uint32 offset, uint32 bytes);
                               uint32 offset, uint32 bytes);
+
+bool
+aot_compiler_op_atomic_fence(AOTCompContext *comp_ctx,
+                             AOTFuncContext *func_ctx);
 #endif
 #endif
 
 
 #ifdef __cplusplus
 #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;
     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
 static bool
 create_aux_stack_info(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
 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) {
         if (aot_func_type->param_count + func->local_count > 0) {
             func_ctx->last_alloca = func_ctx->locals[aot_func_type->param_count
             func_ctx->last_alloca = func_ctx->locals[aot_func_type->param_count
                                                      + func->local_count - 1];
                                                      + 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)) {
         && !create_native_stack_bound(comp_ctx, func_ctx)) {
         goto fail;
         goto fail;
     }
     }
+    if (comp_ctx->enable_stack_estimation
+        && !create_native_stack_top_min(comp_ctx, func_ctx)) {
+        goto fail;
+    }
 
 
     /* Get auxiliary stack info */
     /* Get auxiliary stack info */
     if (wasm_func->has_op_set_global_aux_stack
     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)
     if (option->disable_llvm_lto)
         comp_ctx->disable_llvm_lto = true;
         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->opt_level = option->opt_level;
     comp_ctx->size_level = option->size_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 aot_inst;
     LLVMValueRef argv_buf;
     LLVMValueRef argv_buf;
     LLVMValueRef native_stack_bound;
     LLVMValueRef native_stack_bound;
+    LLVMValueRef native_stack_top_min_addr;
     LLVMValueRef aux_stack_bound;
     LLVMValueRef aux_stack_bound;
     LLVMValueRef aux_stack_bottom;
     LLVMValueRef aux_stack_bottom;
     LLVMValueRef native_symbol;
     LLVMValueRef native_symbol;
@@ -313,6 +314,9 @@ typedef struct AOTCompContext {
     /* Native stack bounday Check */
     /* Native stack bounday Check */
     bool enable_stack_bound_check;
     bool enable_stack_bound_check;
 
 
+    /* Native stack usage estimation */
+    bool enable_stack_estimation;
+
     /* 128-bit SIMD */
     /* 128-bit SIMD */
     bool enable_simd;
     bool enable_simd;
 
 
@@ -403,6 +407,7 @@ typedef struct AOTCompOption {
     bool enable_aux_stack_frame;
     bool enable_aux_stack_frame;
     bool disable_llvm_intrinsics;
     bool disable_llvm_intrinsics;
     bool disable_llvm_lto;
     bool disable_llvm_lto;
+    bool enable_stack_estimation;
     uint32 opt_level;
     uint32 opt_level;
     uint32 size_level;
     uint32 size_level;
     uint32 output_format;
     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
 #ifndef OS_ENABLE_HW_BOUND_CHECK
     /* ---------- check ---------- */
     /* ---------- check ---------- */
     /* 1. shortcut if the memory size is 0 */
     /* 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;
         JitReg module_inst, cur_page_count;
         uint32 cur_page_count_offset =
         uint32 cur_page_count_offset =
             (uint32)offsetof(WASMModuleInstance, global_table_data.bytes)
             (uint32)offsetof(WASMModuleInstance, global_table_data.bytes)
@@ -176,6 +177,18 @@ fail:
     return 0;
     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
 bool
 jit_compile_op_i32_load(JitCompContext *cc, uint32 align, uint32 offset,
 jit_compile_op_i32_load(JitCompContext *cc, uint32 align, uint32 offset,
                         uint32 bytes, bool sign, bool atomic)
                         uint32 bytes, bool sign, bool atomic)
@@ -779,6 +792,51 @@ bool
 jit_compile_op_atomic_wait(JitCompContext *cc, uint8 op_type, uint32 align,
 jit_compile_op_atomic_wait(JitCompContext *cc, uint8 op_type, uint32 align,
                            uint32 offset, uint32 bytes)
                            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;
     return false;
 }
 }
 
 
@@ -786,6 +844,39 @@ bool
 jit_compiler_op_atomic_notify(JitCompContext *cc, uint32 align, uint32 offset,
 jit_compiler_op_atomic_notify(JitCompContext *cc, uint32 align, uint32 offset,
                               uint32 bytes)
                               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;
     return false;
 }
 }
 #endif
 #endif

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

@@ -56,9 +56,31 @@ jit_code_cache_free(void *ptr)
 bool
 bool
 jit_pass_register_jitted_code(JitCompContext *cc)
 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;
     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 */
     /* Apply compiler passes */
     if (!apply_compiler_passes(cc) || jit_get_last_error(cc)) {
     if (!apply_compiler_passes(cc) || jit_get_last_error(cc)) {
         last_error = 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",
         os_printf("fast jit compilation failed: %s\n",
                   last_error ? last_error : "unknown error");
                   last_error ? last_error : "unknown error");
+#endif
+
         goto fail;
         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);
     func_ptr = jit_codegen_compile_call_to_fast_jit(module, func_idx);
     if (func_ptr) {
     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);
         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;
     WASMModuleInstance *instance;
     uint32 i = func_idx - module->import_function_count;
     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);
     os_mutex_lock(&module->instance_list_lock);
+
+    module->func_ptrs[i] = func_ptr;
+
     instance = module->instance_list;
     instance = module->instance_list;
     while (instance) {
     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;
         instance = instance->e->next;
     }
     }
     os_mutex_unlock(&module->instance_list_lock);
     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);
     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
     /* Set spill cache size according to max local cell num, max stack cell
        num and virtual fixed register num */
        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->total_frame_size = cc->spill_cache_offset + cc->spill_cache_size;
     cc->jitted_return_address_offset =
     cc->jitted_return_address_offset =
         offsetof(WASMInterpFrame, jitted_return_addr);
         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 no = jit_reg_no(reg);
     unsigned idx = no & ~_JIT_REG_CONST_IDX_FLAG;
     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]);
     bh_assert(jit_reg_is_const_idx(reg) && idx < cc->_const_val._num[kind]);
 
 
     return cc->_const_val._value[kind] + size * idx;
     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 no = jit_reg_no(reg);
     unsigned idx = no & ~_JIT_REG_CONST_IDX_FLAG;
     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]);
     bh_assert(jit_reg_is_const_idx(reg) && idx < cc->_const_val._num[kind]);
 
 
     return cc->_const_val._next[kind][idx];
     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 kind = jit_reg_kind(reg);
     unsigned no = jit_reg_no(reg);
     unsigned no = jit_reg_no(reg);
     bh_assert(jit_reg_is_variable(reg));
     bh_assert(jit_reg_is_variable(reg));
+    bh_assert(kind < JIT_REG_KIND_L32);
     return no < cc->hreg_info->info[kind].num;
     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 kind = jit_reg_kind(reg);
     unsigned no = jit_reg_no(reg);
     unsigned no = jit_reg_no(reg);
     bh_assert(jit_cc_is_hreg(cc, reg));
     bh_assert(jit_cc_is_hreg(cc, reg));
+    bh_assert(kind < JIT_REG_KIND_L32);
     return !!cc->hreg_info->info[kind].fixed[no];
     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 kind = jit_reg_kind(reg);
     unsigned no = jit_reg_no(reg);
     unsigned no = jit_reg_no(reg);
     bh_assert(jit_cc_is_hreg(cc, 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];
     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 kind = jit_reg_kind(reg);
     unsigned no = jit_reg_no(reg);
     unsigned no = jit_reg_no(reg);
     bh_assert(jit_cc_is_hreg(cc, 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];
     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);
     unsigned no = jit_reg_no(vreg);
 
 
     bh_assert(jit_reg_is_variable(vreg));
     bh_assert(jit_reg_is_variable(vreg));
+    bh_assert(kind < JIT_REG_KIND_L32);
 
 
     return &rc->vregs[kind][no];
     return &rc->vregs[kind][no];
 }
 }
@@ -175,6 +176,7 @@ rc_get_hr(RegallocContext *rc, JitReg hreg)
     unsigned no = jit_reg_no(hreg);
     unsigned no = jit_reg_no(hreg);
 
 
     bh_assert(jit_reg_is_variable(hreg) && jit_cc_is_hreg(rc->cc, 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];
     return &rc->hregs[kind][no];
 }
 }
@@ -208,7 +210,9 @@ static unsigned
 get_reg_stride(JitReg reg)
 get_reg_stride(JitReg reg)
 {
 {
     static const uint8 strides[] = { 0, 1, 2, 1, 2, 2, 4, 8, 0 };
     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)
 allocate_hreg(RegallocContext *rc, JitReg vreg, JitInsn *insn, int distance)
 {
 {
     const int kind = jit_reg_kind(vreg);
     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;
     JitReg hreg, vreg_to_reload = 0;
     int min_distance = distance, vr_distance;
     int min_distance = distance, vr_distance;
     VirtualReg *vr = rc_get_vr(rc, vreg);
     VirtualReg *vr = rc_get_vr(rc, vreg);
     unsigned i;
     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)
     if (hreg_num == 0)
     /* Unsupported hard register kind.  */
     /* 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 enable_aux_stack_frame;
     bool disable_llvm_intrinsics;
     bool disable_llvm_intrinsics;
     bool disable_llvm_lto;
     bool disable_llvm_lto;
+    bool enable_stack_estimation;
     uint32_t opt_level;
     uint32_t opt_level;
     uint32_t size_level;
     uint32_t size_level;
     uint32_t output_format;
     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_module(const wasm_importtype_t*);
 WASM_API_EXTERN const wasm_name_t* wasm_importtype_name(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 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
 // Export Types
@@ -797,6 +798,9 @@ static inline void* wasm_val_ptr(const wasm_val_t* val) {
 
 
 #define KILOBYTE(n) ((n) * 1024)
 #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
 #undef own

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

@@ -131,6 +131,14 @@ typedef struct mem_alloc_info_t {
     uint32_t highmark_size;
     uint32_t highmark_size;
 } mem_alloc_info_t;
 } 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 */
 /* WASM runtime initialize arguments */
 typedef struct RuntimeInitArgs {
 typedef struct RuntimeInitArgs {
     mem_alloc_type_t mem_alloc_type;
     mem_alloc_type_t mem_alloc_type;
@@ -152,6 +160,13 @@ typedef struct RuntimeInitArgs {
 
 
     /* Fast JIT code cache size */
     /* Fast JIT code cache size */
     uint32_t 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;
 } RuntimeInitArgs;
 
 
 #ifndef WASM_VALKIND_T_DEFINED
 #ifndef WASM_VALKIND_T_DEFINED
@@ -195,9 +210,9 @@ WASM_RUNTIME_API_EXTERN bool
 wasm_runtime_init(void);
 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
  * @param init_args specifies the init arguments
  *
  *
@@ -206,6 +221,28 @@ wasm_runtime_init(void);
 WASM_RUNTIME_API_EXTERN bool
 WASM_RUNTIME_API_EXTERN bool
 wasm_runtime_full_init(RuntimeInitArgs *init_args);
 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.
  * 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,
                          uint32_t stack_size, uint32_t heap_size,
                          char *error_buf, uint32_t error_buf_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.
  * 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_results, wasm_val_t results[],
                          uint32_t num_args, ...);
                          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
  * Find the unique main function from a WASM module instance
  * and execute that function.
  * 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_API_EXTERN void
 wasm_runtime_get_version(uint32_t *major, uint32_t *minor, uint32_t *patch);
 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 */
 /* clang-format on */
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus

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

@@ -278,9 +278,14 @@ struct WASMFunction {
 #endif
 #endif
 
 
 #if WASM_ENABLE_FAST_JIT != 0
 #if WASM_ENABLE_FAST_JIT != 0
+    /* The compiled fast jit jitted code block of this function */
     void *fast_jit_jitted_code;
     void *fast_jit_jitted_code;
 #if WASM_ENABLE_JIT != 0 && WASM_ENABLE_LAZY_JIT != 0
 #if WASM_ENABLE_JIT != 0 && WASM_ENABLE_LAZY_JIT != 0
+    /* The compiled llvm jit func ptr of this function */
     void *llvm_jit_func_ptr;
     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
 #endif
 #endif
 };
 };
@@ -505,15 +510,14 @@ struct WASMModule {
     uint64 load_size;
     uint64 load_size;
 #endif
 #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)
         && WASM_ENABLE_LAZY_JIT != 0)
     /**
     /**
      * List of instances referred to this module. When source debugging
      * List of instances referred to this module. When source debugging
      * feature is enabled, the debugger may modify the code section of
      * feature is enabled, the debugger may modify the code section of
      * the module, so we need to report a warning if user create several
      * 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
      * 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
      * tier-up, since we need to lazily update the LLVM func pointers
@@ -533,7 +537,22 @@ struct WASMModule {
 #endif
 #endif
 
 
 #if WASM_ENABLE_FAST_JIT != 0
 #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;
     void **fast_jit_func_ptrs;
     /* locks for Fast JIT lazy compilation */
     /* locks for Fast JIT lazy compilation */
     korp_mutex fast_jit_thread_locks[WASM_ORC_JIT_BACKEND_THREAD_NUM];
     korp_mutex fast_jit_thread_locks[WASM_ORC_JIT_BACKEND_THREAD_NUM];
@@ -543,7 +562,16 @@ struct WASMModule {
 #if WASM_ENABLE_JIT != 0
 #if WASM_ENABLE_JIT != 0
     struct AOTCompData *comp_data;
     struct AOTCompData *comp_data;
     struct AOTCompContext *comp_ctx;
     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;
     void **func_ptrs;
     /* whether the func pointers are compiled */
     /* whether the func pointers are compiled */
     bool *func_ptrs_compiled;
     bool *func_ptrs_compiled;
@@ -568,6 +596,12 @@ struct WASMModule {
     korp_tid llvm_jit_init_thread;
     korp_tid llvm_jit_init_thread;
     /* whether the llvm jit is initialized */
     /* whether the llvm jit is initialized */
     bool llvm_jit_inited;
     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
 #endif
 };
 };
 
 

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

@@ -8,6 +8,7 @@
 #include "wasm_runtime.h"
 #include "wasm_runtime.h"
 #include "wasm_opcode.h"
 #include "wasm_opcode.h"
 #include "wasm_loader.h"
 #include "wasm_loader.h"
+#include "wasm_memory.h"
 #include "../common/wasm_exec_env.h"
 #include "../common/wasm_exec_env.h"
 #if WASM_ENABLE_SHARED_MEMORY != 0
 #if WASM_ENABLE_SHARED_MEMORY != 0
 #include "../common/wasm_shared_memory.h"
 #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_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);     \
             CHECK_ATOMIC_MEMORY_ACCESS();                            \
             CHECK_ATOMIC_MEMORY_ACCESS();                            \
                                                                      \
                                                                      \
-            os_mutex_lock(&module->e->mem_lock);                     \
+            os_mutex_lock(&node->shared_mem_lock);                   \
             readv = (uint32)(*(uint8 *)maddr);                       \
             readv = (uint32)(*(uint8 *)maddr);                       \
             *(uint8 *)maddr = (uint8)(readv op sval);                \
             *(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) { \
         else if (opcode == WASM_OP_ATOMIC_RMW_I32_##OP_NAME##16_U) { \
             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);     \
             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);     \
             CHECK_ATOMIC_MEMORY_ACCESS();                            \
             CHECK_ATOMIC_MEMORY_ACCESS();                            \
                                                                      \
                                                                      \
-            os_mutex_lock(&module->e->mem_lock);                     \
+            os_mutex_lock(&node->shared_mem_lock);                   \
             readv = (uint32)LOAD_U16(maddr);                         \
             readv = (uint32)LOAD_U16(maddr);                         \
             STORE_U16(maddr, (uint16)(readv op sval));               \
             STORE_U16(maddr, (uint16)(readv op sval));               \
-            os_mutex_unlock(&module->e->mem_lock);                   \
+            os_mutex_unlock(&node->shared_mem_lock);                 \
         }                                                            \
         }                                                            \
         else {                                                       \
         else {                                                       \
             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);     \
             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);     \
             CHECK_ATOMIC_MEMORY_ACCESS();                            \
             CHECK_ATOMIC_MEMORY_ACCESS();                            \
                                                                      \
                                                                      \
-            os_mutex_lock(&module->e->mem_lock);                     \
+            os_mutex_lock(&node->shared_mem_lock);                   \
             readv = LOAD_I32(maddr);                                 \
             readv = LOAD_I32(maddr);                                 \
             STORE_U32(maddr, readv op sval);                         \
             STORE_U32(maddr, readv op sval);                         \
-            os_mutex_unlock(&module->e->mem_lock);                   \
+            os_mutex_unlock(&node->shared_mem_lock);                 \
         }                                                            \
         }                                                            \
         PUSH_I32(readv);                                             \
         PUSH_I32(readv);                                             \
         break;                                                       \
         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_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);     \
             CHECK_ATOMIC_MEMORY_ACCESS();                            \
             CHECK_ATOMIC_MEMORY_ACCESS();                            \
                                                                      \
                                                                      \
-            os_mutex_lock(&module->e->mem_lock);                     \
+            os_mutex_lock(&node->shared_mem_lock);                   \
             readv = (uint64)(*(uint8 *)maddr);                       \
             readv = (uint64)(*(uint8 *)maddr);                       \
             *(uint8 *)maddr = (uint8)(readv op sval);                \
             *(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) { \
         else if (opcode == WASM_OP_ATOMIC_RMW_I64_##OP_NAME##16_U) { \
             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);     \
             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);     \
             CHECK_ATOMIC_MEMORY_ACCESS();                            \
             CHECK_ATOMIC_MEMORY_ACCESS();                            \
                                                                      \
                                                                      \
-            os_mutex_lock(&module->e->mem_lock);                     \
+            os_mutex_lock(&node->shared_mem_lock);                   \
             readv = (uint64)LOAD_U16(maddr);                         \
             readv = (uint64)LOAD_U16(maddr);                         \
             STORE_U16(maddr, (uint16)(readv op sval));               \
             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) { \
         else if (opcode == WASM_OP_ATOMIC_RMW_I64_##OP_NAME##32_U) { \
             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);     \
             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);     \
             CHECK_ATOMIC_MEMORY_ACCESS();                            \
             CHECK_ATOMIC_MEMORY_ACCESS();                            \
                                                                      \
                                                                      \
-            os_mutex_lock(&module->e->mem_lock);                     \
+            os_mutex_lock(&node->shared_mem_lock);                   \
             readv = (uint64)LOAD_U32(maddr);                         \
             readv = (uint64)LOAD_U32(maddr);                         \
             STORE_U32(maddr, (uint32)(readv op sval));               \
             STORE_U32(maddr, (uint32)(readv op sval));               \
-            os_mutex_unlock(&module->e->mem_lock);                   \
+            os_mutex_unlock(&node->shared_mem_lock);                 \
         }                                                            \
         }                                                            \
         else {                                                       \
         else {                                                       \
             uint64 op_result;                                        \
             uint64 op_result;                                        \
             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr);     \
             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr);     \
             CHECK_ATOMIC_MEMORY_ACCESS();                            \
             CHECK_ATOMIC_MEMORY_ACCESS();                            \
                                                                      \
                                                                      \
-            os_mutex_lock(&module->e->mem_lock);                     \
+            os_mutex_lock(&node->shared_mem_lock);                   \
             readv = (uint64)LOAD_I64(maddr);                         \
             readv = (uint64)LOAD_I64(maddr);                         \
             op_result = readv op sval;                               \
             op_result = readv op sval;                               \
             STORE_I64(maddr, op_result);                             \
             STORE_I64(maddr, op_result);                             \
-            os_mutex_unlock(&module->e->mem_lock);                   \
+            os_mutex_unlock(&node->shared_mem_lock);                 \
         }                                                            \
         }                                                            \
         PUSH_I64(readv);                                             \
         PUSH_I64(readv);                                             \
         break;                                                       \
         break;                                                       \
@@ -891,7 +892,7 @@ wasm_interp_call_func_native(WASMModuleInstance *module_inst,
     if (!func_import->call_conv_wasm_c_api) {
     if (!func_import->call_conv_wasm_c_api) {
         native_func_pointer = module_inst->import_func_ptrs[cur_func_index];
         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;
         c_api_func_import = module_inst->e->c_api_func_imports + cur_func_index;
         native_func_pointer = c_api_func_import->func_ptr_linked;
         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;
     WASMFunctionInstance *cur_func = module_inst->e->functions + func_idx;
 
 
     wasm_interp_call_func_native(module_inst, exec_env, cur_func, prev_frame);
     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
 #endif
 
 
@@ -1023,7 +1024,7 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst,
     exec_env->module_inst = (WASMModuleInstanceCommon *)module_inst;
     exec_env->module_inst = (WASMModuleInstanceCommon *)module_inst;
 
 
     /* transfer exception if it is thrown */
     /* 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,
         bh_memcpy_s(module_inst->cur_exception,
                     sizeof(module_inst->cur_exception),
                     sizeof(module_inst->cur_exception),
                     sub_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
 #if WASM_ENABLE_DEBUG_INTERP != 0
 #define CHECK_SUSPEND_FLAGS()                                          \
 #define CHECK_SUSPEND_FLAGS()                                          \
     do {                                                               \
     do {                                                               \
+        os_mutex_lock(&exec_env->wait_lock);                           \
         if (IS_WAMR_TERM_SIG(exec_env->current_status->signal_flag)) { \
         if (IS_WAMR_TERM_SIG(exec_env->current_status->signal_flag)) { \
+            os_mutex_unlock(&exec_env->wait_lock);                     \
             return;                                                    \
             return;                                                    \
         }                                                              \
         }                                                              \
         if (IS_WAMR_STOP_SIG(exec_env->current_status->signal_flag)) { \
         if (IS_WAMR_STOP_SIG(exec_env->current_status->signal_flag)) { \
             SYNC_ALL_TO_FRAME();                                       \
             SYNC_ALL_TO_FRAME();                                       \
-            wasm_cluster_thread_stopped(exec_env);                     \
             wasm_cluster_thread_waiting_run(exec_env);                 \
             wasm_cluster_thread_waiting_run(exec_env);                 \
         }                                                              \
         }                                                              \
+        os_mutex_unlock(&exec_env->wait_lock);                         \
     } while (0)
     } while (0)
 #else
 #else
 #define CHECK_SUSPEND_FLAGS()                                             \
 #define CHECK_SUSPEND_FLAGS()                                             \
     do {                                                                  \
     do {                                                                  \
+        os_mutex_lock(&exec_env->wait_lock);                              \
         if (exec_env->suspend_flags.flags != 0) {                         \
         if (exec_env->suspend_flags.flags != 0) {                         \
             if (exec_env->suspend_flags.flags & 0x01) {                   \
             if (exec_env->suspend_flags.flags & 0x01) {                   \
                 /* terminate current thread */                            \
                 /* terminate current thread */                            \
+                os_mutex_unlock(&exec_env->wait_lock);                    \
                 return;                                                   \
                 return;                                                   \
             }                                                             \
             }                                                             \
             while (exec_env->suspend_flags.flags & 0x02) {                \
             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_cond_wait(&exec_env->wait_cond, &exec_env->wait_lock); \
             }                                                             \
             }                                                             \
         }                                                                 \
         }                                                                 \
+        os_mutex_unlock(&exec_env->wait_lock);                            \
     } while (0)
     } while (0)
 #endif /* WASM_ENABLE_DEBUG_INTERP */
 #endif /* WASM_ENABLE_DEBUG_INTERP */
 #endif /* WASM_ENABLE_THREAD_MGR */
 #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++ == 1) {          \
             exec_env->current_status->step_count = 0;                     \
             exec_env->current_status->step_count = 0;                     \
             SYNC_ALL_TO_FRAME();                                          \
             SYNC_ALL_TO_FRAME();                                          \
-            wasm_cluster_thread_stopped(exec_env);                        \
             wasm_cluster_thread_waiting_run(exec_env);                    \
             wasm_cluster_thread_waiting_run(exec_env);                    \
         }                                                                 \
         }                                                                 \
         goto *handle_table[*frame_ip++];                                  \
         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++ == 2) {          \
         exec_env->current_status->step_count = 0;                  \
         exec_env->current_status->step_count = 0;                  \
         SYNC_ALL_TO_FRAME();                                       \
         SYNC_ALL_TO_FRAME();                                       \
-        wasm_cluster_thread_stopped(exec_env);                     \
         wasm_cluster_thread_waiting_run(exec_env);                 \
         wasm_cluster_thread_waiting_run(exec_env);                 \
     }                                                              \
     }                                                              \
     continue
     continue
@@ -1123,14 +1127,22 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                                WASMFunctionInstance *cur_func,
                                WASMFunctionInstance *cur_func,
                                WASMInterpFrame *prev_frame)
                                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);
     WASMMemoryInstance *memory = wasm_get_default_memory(module);
     uint8 *global_data = module->global_data;
     uint8 *global_data = module->global_data;
 #if !defined(OS_ENABLE_HW_BOUND_CHECK)              \
 #if !defined(OS_ENABLE_HW_BOUND_CHECK)              \
     || WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \
     || WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \
     || WASM_ENABLE_BULK_MEMORY != 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 =
     uint32 linear_mem_size =
-        memory ? num_bytes_per_page * memory->cur_page_count : 0;
+        memory ? wasm_get_linear_memory_size(memory, node) : 0;
 #endif
 #endif
     WASMType **wasm_types = module->module->types;
     WASMType **wasm_types = module->module->types;
     WASMGlobalInstance *globals = module->e->globals, *global;
     WASMGlobalInstance *globals = module->e->globals, *global;
@@ -1365,7 +1377,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
 
 
             HANDLE_OP(EXT_OP_BR_TABLE_CACHE)
             HANDLE_OP(EXT_OP_BR_TABLE_CACHE)
             {
             {
-                BrTableCache *node =
+                BrTableCache *node_cache =
                     bh_list_first_elem(module->module->br_table_cache_list);
                     bh_list_first_elem(module->module->br_table_cache_list);
                 BrTableCache *node_next;
                 BrTableCache *node_next;
 
 
@@ -1374,13 +1386,13 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
 #endif
 #endif
                 lidx = POP_I32();
                 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;
                         goto label_pop_csp_n;
                     }
                     }
-                    node = node_next;
+                    node_cache = node_next;
                 }
                 }
                 bh_assert(0);
                 bh_assert(0);
                 HANDLE_OP_END();
                 HANDLE_OP_END();
@@ -3420,6 +3432,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                         if (ret == (uint32)-1)
                         if (ret == (uint32)-1)
                             goto got_exception;
                             goto got_exception;
 
 
+#if WASM_ENABLE_THREAD_MGR != 0
+                        CHECK_SUSPEND_FLAGS();
+#endif
+
                         PUSH_I32(ret);
                         PUSH_I32(ret);
                         break;
                         break;
                     }
                     }
@@ -3440,6 +3456,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                         if (ret == (uint32)-1)
                         if (ret == (uint32)-1)
                             goto got_exception;
                             goto got_exception;
 
 
+#if WASM_ENABLE_THREAD_MGR != 0
+                        CHECK_SUSPEND_FLAGS();
+#endif
+
                         PUSH_I32(ret);
                         PUSH_I32(ret);
                         break;
                         break;
                     }
                     }
@@ -3447,6 +3467,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                     {
                     {
                         /* Skip the memory index */
                         /* Skip the memory index */
                         frame_ip++;
                         frame_ip++;
+                        os_atomic_thread_fence(os_memory_order_release);
                         break;
                         break;
                     }
                     }
 
 
@@ -3461,23 +3482,23 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                         if (opcode == WASM_OP_ATOMIC_I32_LOAD8_U) {
                         if (opcode == WASM_OP_ATOMIC_I32_LOAD8_U) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS();
                             CHECK_ATOMIC_MEMORY_ACCESS();
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             readv = (uint32)(*(uint8 *)maddr);
                             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) {
                         else if (opcode == WASM_OP_ATOMIC_I32_LOAD16_U) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS();
                             CHECK_ATOMIC_MEMORY_ACCESS();
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             readv = (uint32)LOAD_U16(maddr);
                             readv = (uint32)LOAD_U16(maddr);
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         }
                         else {
                         else {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS();
                             CHECK_ATOMIC_MEMORY_ACCESS();
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             readv = LOAD_I32(maddr);
                             readv = LOAD_I32(maddr);
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         }
 
 
                         PUSH_I32(readv);
                         PUSH_I32(readv);
@@ -3496,30 +3517,30 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                         if (opcode == WASM_OP_ATOMIC_I64_LOAD8_U) {
                         if (opcode == WASM_OP_ATOMIC_I64_LOAD8_U) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS();
                             CHECK_ATOMIC_MEMORY_ACCESS();
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             readv = (uint64)(*(uint8 *)maddr);
                             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) {
                         else if (opcode == WASM_OP_ATOMIC_I64_LOAD16_U) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS();
                             CHECK_ATOMIC_MEMORY_ACCESS();
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             readv = (uint64)LOAD_U16(maddr);
                             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) {
                         else if (opcode == WASM_OP_ATOMIC_I64_LOAD32_U) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS();
                             CHECK_ATOMIC_MEMORY_ACCESS();
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             readv = (uint64)LOAD_U32(maddr);
                             readv = (uint64)LOAD_U32(maddr);
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         }
                         else {
                         else {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr);
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS();
                             CHECK_ATOMIC_MEMORY_ACCESS();
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             readv = LOAD_I64(maddr);
                             readv = LOAD_I64(maddr);
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         }
 
 
                         PUSH_I64(readv);
                         PUSH_I64(readv);
@@ -3538,23 +3559,23 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                         if (opcode == WASM_OP_ATOMIC_I32_STORE8) {
                         if (opcode == WASM_OP_ATOMIC_I32_STORE8) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS();
                             CHECK_ATOMIC_MEMORY_ACCESS();
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             *(uint8 *)maddr = (uint8)sval;
                             *(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) {
                         else if (opcode == WASM_OP_ATOMIC_I32_STORE16) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS();
                             CHECK_ATOMIC_MEMORY_ACCESS();
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             STORE_U16(maddr, (uint16)sval);
                             STORE_U16(maddr, (uint16)sval);
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         }
                         else {
                         else {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS();
                             CHECK_ATOMIC_MEMORY_ACCESS();
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             STORE_U32(maddr, frame_sp[1]);
                             STORE_U32(maddr, frame_sp[1]);
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         }
                         break;
                         break;
                     }
                     }
@@ -3572,31 +3593,31 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                         if (opcode == WASM_OP_ATOMIC_I64_STORE8) {
                         if (opcode == WASM_OP_ATOMIC_I64_STORE8) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS();
                             CHECK_ATOMIC_MEMORY_ACCESS();
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             *(uint8 *)maddr = (uint8)sval;
                             *(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) {
                         else if (opcode == WASM_OP_ATOMIC_I64_STORE16) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS();
                             CHECK_ATOMIC_MEMORY_ACCESS();
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             STORE_U16(maddr, (uint16)sval);
                             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) {
                         else if (opcode == WASM_OP_ATOMIC_I64_STORE32) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS();
                             CHECK_ATOMIC_MEMORY_ACCESS();
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             STORE_U32(maddr, (uint32)sval);
                             STORE_U32(maddr, (uint32)sval);
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         }
                         else {
                         else {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr);
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS();
                             CHECK_ATOMIC_MEMORY_ACCESS();
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             PUT_I64_TO_ADDR((uint32 *)maddr,
                             PUT_I64_TO_ADDR((uint32 *)maddr,
                                             GET_I64_FROM_ADDR(frame_sp + 1));
                                             GET_I64_FROM_ADDR(frame_sp + 1));
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         }
                         break;
                         break;
                     }
                     }
@@ -3616,32 +3637,32 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                             CHECK_ATOMIC_MEMORY_ACCESS();
                             CHECK_ATOMIC_MEMORY_ACCESS();
 
 
                             expect = (uint8)expect;
                             expect = (uint8)expect;
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             readv = (uint32)(*(uint8 *)maddr);
                             readv = (uint32)(*(uint8 *)maddr);
                             if (readv == expect)
                             if (readv == expect)
                                 *(uint8 *)maddr = (uint8)(sval);
                                 *(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) {
                         else if (opcode == WASM_OP_ATOMIC_RMW_I32_CMPXCHG16_U) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS();
                             CHECK_ATOMIC_MEMORY_ACCESS();
 
 
                             expect = (uint16)expect;
                             expect = (uint16)expect;
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             readv = (uint32)LOAD_U16(maddr);
                             readv = (uint32)LOAD_U16(maddr);
                             if (readv == expect)
                             if (readv == expect)
                                 STORE_U16(maddr, (uint16)(sval));
                                 STORE_U16(maddr, (uint16)(sval));
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         }
                         else {
                         else {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS();
                             CHECK_ATOMIC_MEMORY_ACCESS();
 
 
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             readv = LOAD_I32(maddr);
                             readv = LOAD_I32(maddr);
                             if (readv == expect)
                             if (readv == expect)
                                 STORE_U32(maddr, sval);
                                 STORE_U32(maddr, sval);
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         }
                         PUSH_I32(readv);
                         PUSH_I32(readv);
                         break;
                         break;
@@ -3662,44 +3683,44 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                             CHECK_ATOMIC_MEMORY_ACCESS();
                             CHECK_ATOMIC_MEMORY_ACCESS();
 
 
                             expect = (uint8)expect;
                             expect = (uint8)expect;
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             readv = (uint64)(*(uint8 *)maddr);
                             readv = (uint64)(*(uint8 *)maddr);
                             if (readv == expect)
                             if (readv == expect)
                                 *(uint8 *)maddr = (uint8)(sval);
                                 *(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) {
                         else if (opcode == WASM_OP_ATOMIC_RMW_I64_CMPXCHG16_U) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS();
                             CHECK_ATOMIC_MEMORY_ACCESS();
 
 
                             expect = (uint16)expect;
                             expect = (uint16)expect;
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             readv = (uint64)LOAD_U16(maddr);
                             readv = (uint64)LOAD_U16(maddr);
                             if (readv == expect)
                             if (readv == expect)
                                 STORE_U16(maddr, (uint16)(sval));
                                 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) {
                         else if (opcode == WASM_OP_ATOMIC_RMW_I64_CMPXCHG32_U) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS();
                             CHECK_ATOMIC_MEMORY_ACCESS();
 
 
                             expect = (uint32)expect;
                             expect = (uint32)expect;
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             readv = (uint64)LOAD_U32(maddr);
                             readv = (uint64)LOAD_U32(maddr);
                             if (readv == expect)
                             if (readv == expect)
                                 STORE_U32(maddr, (uint32)(sval));
                                 STORE_U32(maddr, (uint32)(sval));
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         }
                         else {
                         else {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr);
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS();
                             CHECK_ATOMIC_MEMORY_ACCESS();
 
 
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             readv = (uint64)LOAD_I64(maddr);
                             readv = (uint64)LOAD_I64(maddr);
                             if (readv == expect) {
                             if (readv == expect) {
                                 STORE_I64(maddr, sval);
                                 STORE_I64(maddr, sval);
                             }
                             }
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         }
                         PUSH_I64(readv);
                         PUSH_I64(readv);
                         break;
                         break;
@@ -3843,7 +3864,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
             if (memory)
             if (memory)
                 linear_mem_size = num_bytes_per_page * memory->cur_page_count;
                 linear_mem_size = num_bytes_per_page * memory->cur_page_count;
 #endif
 #endif
-            if (wasm_get_exception(module))
+            if (wasm_copy_exception(module, NULL))
                 goto got_exception;
                 goto got_exception;
         }
         }
         else {
         else {
@@ -3892,10 +3913,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
             PUSH_CSP(LABEL_TYPE_FUNCTION, 0, cell_num, frame_ip_end - 1);
             PUSH_CSP(LABEL_TYPE_FUNCTION, 0, cell_num, frame_ip_end - 1);
 
 
             wasm_exec_env_set_cur_frame(exec_env, frame);
             wasm_exec_env_set_cur_frame(exec_env, frame);
+        }
 #if WASM_ENABLE_THREAD_MGR != 0
 #if WASM_ENABLE_THREAD_MGR != 0
-            CHECK_SUSPEND_FLAGS();
+        CHECK_SUSPEND_FLAGS();
 #endif
 #endif
-        }
         HANDLE_OP_END();
         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]);
         module_inst->fast_jit_func_ptrs[func_idx_non_import]);
     bh_assert(action == JIT_INTERP_ACTION_NORMAL
     bh_assert(action == JIT_INTERP_ACTION_NORMAL
               || (action == JIT_INTERP_ACTION_THROWN
               || (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 */
     /* Get the return values form info.out.ret */
     if (func_type->result_count) {
     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 */
 #endif /* end of WASM_ENABLE_FAST_JIT != 0 */
 
 
 #if WASM_ENABLE_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
 static bool
 llvm_jit_call_func_bytecode(WASMModuleInstance *module_inst,
 llvm_jit_call_func_bytecode(WASMModuleInstance *module_inst,
                             WASMExecEnv *exec_env,
                             WASMExecEnv *exec_env,
@@ -4095,14 +4099,6 @@ llvm_jit_call_func_bytecode(WASMModuleInstance *module_inst,
         ret = wasm_runtime_invoke_native(
         ret = wasm_runtime_invoke_native(
             exec_env, module_inst->func_ptrs[func_idx], func_type, NULL, NULL,
             exec_env, module_inst->func_ptrs[func_idx], func_type, NULL, NULL,
             argv1, argc, argv);
             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 (!ret) {
             if (argv1 != argv1_buf)
             if (argv1 != argv1_buf)
                 wasm_runtime_free(argv1);
                 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,
             exec_env, module_inst->func_ptrs[func_idx], func_type, NULL, NULL,
             argv, argc, argv);
             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 */
 #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 frame_size = wasm_interp_interp_frame_size(all_cell_num);
     unsigned i;
     unsigned i;
     bool copy_argv_from_frame = true;
     bool copy_argv_from_frame = true;
+    char exception[EXCEPTION_BUF_LEN];
 
 
     if (argc < function->param_cell_num) {
     if (argc < function->param_cell_num) {
         char buf[128];
         char buf[128];
@@ -4182,6 +4176,7 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env,
     }
     }
     argc = function->param_cell_num;
     argc = function->param_cell_num;
 
 
+    RECORD_STACK_USAGE(exec_env, (uint8 *)&prev_frame);
 #if !(defined(OS_ENABLE_HW_BOUND_CHECK) \
 #if !(defined(OS_ENABLE_HW_BOUND_CHECK) \
       && WASM_DISABLE_STACK_HW_BOUND_CHECK == 0)
       && WASM_DISABLE_STACK_HW_BOUND_CHECK == 0)
     if ((uint8 *)&prev_frame < exec_env->native_stack_boundary) {
     if ((uint8 *)&prev_frame < exec_env->native_stack_boundary) {
@@ -4226,58 +4221,51 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env,
         }
         }
     }
     }
     else {
     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,
             llvm_jit_call_func_bytecode(module_inst, exec_env, function, argc,
                                         argv);
                                         argv);
             /* For llvm jit, the results have been stored in argv,
             /* For llvm jit, the results have been stored in argv,
                no need to copy them from stack frame again */
                no need to copy them from stack frame again */
             copy_argv_from_frame = false;
             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
 #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
-
-#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;
         (void)wasm_interp_call_func_bytecode;
 #if WASM_ENABLE_FAST_JIT != 0
 #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 */
     /* 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) {
         if (copy_argv_from_frame) {
             for (i = 0; i < function->ret_cell_num; i++) {
             for (i = 0; i < function->ret_cell_num; i++) {
                 argv[i] = *(frame->sp + i - function->ret_cell_num);
                 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);
             wasm_interp_dump_call_stack(exec_env, true, NULL, 0);
         }
         }
 #endif
 #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);
     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_runtime.h"
 #include "wasm_opcode.h"
 #include "wasm_opcode.h"
 #include "wasm_loader.h"
 #include "wasm_loader.h"
+#include "wasm_memory.h"
 #include "../common/wasm_exec_env.h"
 #include "../common/wasm_exec_env.h"
 #if WASM_ENABLE_SHARED_MEMORY != 0
 #if WASM_ENABLE_SHARED_MEMORY != 0
 #include "../common/wasm_shared_memory.h"
 #include "../common/wasm_shared_memory.h"
@@ -469,28 +470,28 @@ LOAD_PTR(void *addr)
             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);     \
             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);     \
             CHECK_ATOMIC_MEMORY_ACCESS(1);                           \
             CHECK_ATOMIC_MEMORY_ACCESS(1);                           \
                                                                      \
                                                                      \
-            os_mutex_lock(&module->e->mem_lock);                     \
+            os_mutex_lock(&node->shared_mem_lock);                   \
             readv = (uint32)(*(uint8 *)maddr);                       \
             readv = (uint32)(*(uint8 *)maddr);                       \
             *(uint8 *)maddr = (uint8)(readv op sval);                \
             *(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) { \
         else if (opcode == WASM_OP_ATOMIC_RMW_I32_##OP_NAME##16_U) { \
             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);     \
             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);     \
             CHECK_ATOMIC_MEMORY_ACCESS(2);                           \
             CHECK_ATOMIC_MEMORY_ACCESS(2);                           \
                                                                      \
                                                                      \
-            os_mutex_lock(&module->e->mem_lock);                     \
+            os_mutex_lock(&node->shared_mem_lock);                   \
             readv = (uint32)LOAD_U16(maddr);                         \
             readv = (uint32)LOAD_U16(maddr);                         \
             STORE_U16(maddr, (uint16)(readv op sval));               \
             STORE_U16(maddr, (uint16)(readv op sval));               \
-            os_mutex_unlock(&module->e->mem_lock);                   \
+            os_mutex_unlock(&node->shared_mem_lock);                 \
         }                                                            \
         }                                                            \
         else {                                                       \
         else {                                                       \
             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);     \
             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);     \
             CHECK_ATOMIC_MEMORY_ACCESS(4);                           \
             CHECK_ATOMIC_MEMORY_ACCESS(4);                           \
                                                                      \
                                                                      \
-            os_mutex_lock(&module->e->mem_lock);                     \
+            os_mutex_lock(&node->shared_mem_lock);                   \
             readv = LOAD_I32(maddr);                                 \
             readv = LOAD_I32(maddr);                                 \
             STORE_U32(maddr, readv op sval);                         \
             STORE_U32(maddr, readv op sval);                         \
-            os_mutex_unlock(&module->e->mem_lock);                   \
+            os_mutex_unlock(&node->shared_mem_lock);                 \
         }                                                            \
         }                                                            \
         PUSH_I32(readv);                                             \
         PUSH_I32(readv);                                             \
         break;                                                       \
         break;                                                       \
@@ -509,39 +510,39 @@ LOAD_PTR(void *addr)
             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);     \
             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);     \
             CHECK_ATOMIC_MEMORY_ACCESS(1);                           \
             CHECK_ATOMIC_MEMORY_ACCESS(1);                           \
                                                                      \
                                                                      \
-            os_mutex_lock(&module->e->mem_lock);                     \
+            os_mutex_lock(&node->shared_mem_lock);                   \
             readv = (uint64)(*(uint8 *)maddr);                       \
             readv = (uint64)(*(uint8 *)maddr);                       \
             *(uint8 *)maddr = (uint8)(readv op sval);                \
             *(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) { \
         else if (opcode == WASM_OP_ATOMIC_RMW_I64_##OP_NAME##16_U) { \
             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);     \
             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);     \
             CHECK_ATOMIC_MEMORY_ACCESS(2);                           \
             CHECK_ATOMIC_MEMORY_ACCESS(2);                           \
                                                                      \
                                                                      \
-            os_mutex_lock(&module->e->mem_lock);                     \
+            os_mutex_lock(&node->shared_mem_lock);                   \
             readv = (uint64)LOAD_U16(maddr);                         \
             readv = (uint64)LOAD_U16(maddr);                         \
             STORE_U16(maddr, (uint16)(readv op sval));               \
             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) { \
         else if (opcode == WASM_OP_ATOMIC_RMW_I64_##OP_NAME##32_U) { \
             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);     \
             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);     \
             CHECK_ATOMIC_MEMORY_ACCESS(4);                           \
             CHECK_ATOMIC_MEMORY_ACCESS(4);                           \
                                                                      \
                                                                      \
-            os_mutex_lock(&module->e->mem_lock);                     \
+            os_mutex_lock(&node->shared_mem_lock);                   \
             readv = (uint64)LOAD_U32(maddr);                         \
             readv = (uint64)LOAD_U32(maddr);                         \
             STORE_U32(maddr, (uint32)(readv op sval));               \
             STORE_U32(maddr, (uint32)(readv op sval));               \
-            os_mutex_unlock(&module->e->mem_lock);                   \
+            os_mutex_unlock(&node->shared_mem_lock);                 \
         }                                                            \
         }                                                            \
         else {                                                       \
         else {                                                       \
             uint64 op_result;                                        \
             uint64 op_result;                                        \
             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr);     \
             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr);     \
             CHECK_ATOMIC_MEMORY_ACCESS(8);                           \
             CHECK_ATOMIC_MEMORY_ACCESS(8);                           \
                                                                      \
                                                                      \
-            os_mutex_lock(&module->e->mem_lock);                     \
+            os_mutex_lock(&node->shared_mem_lock);                   \
             readv = (uint64)LOAD_I64(maddr);                         \
             readv = (uint64)LOAD_I64(maddr);                         \
             op_result = readv op sval;                               \
             op_result = readv op sval;                               \
             STORE_I64(maddr, op_result);                             \
             STORE_I64(maddr, op_result);                             \
-            os_mutex_unlock(&module->e->mem_lock);                   \
+            os_mutex_unlock(&node->shared_mem_lock);                 \
         }                                                            \
         }                                                            \
         PUSH_I64(readv);                                             \
         PUSH_I64(readv);                                             \
         break;                                                       \
         break;                                                       \
@@ -925,7 +926,7 @@ wasm_interp_call_func_native(WASMModuleInstance *module_inst,
     if (!func_import->call_conv_wasm_c_api) {
     if (!func_import->call_conv_wasm_c_api) {
         native_func_pointer = module_inst->import_func_ptrs[cur_func_index];
         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;
         c_api_func_import = module_inst->e->c_api_func_imports + cur_func_index;
         native_func_pointer = c_api_func_import->func_ptr_linked;
         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;
     exec_env->module_inst = (WASMModuleInstanceCommon *)module_inst;
 
 
     /* transfer exception if it is thrown */
     /* 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,
         bh_memcpy_s(module_inst->cur_exception,
                     sizeof(module_inst->cur_exception),
                     sizeof(module_inst->cur_exception),
                     sub_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
 #if WASM_ENABLE_THREAD_MGR != 0
 #define CHECK_SUSPEND_FLAGS()                           \
 #define CHECK_SUSPEND_FLAGS()                           \
     do {                                                \
     do {                                                \
+        os_mutex_lock(&exec_env->wait_lock);            \
         if (exec_env->suspend_flags.flags != 0) {       \
         if (exec_env->suspend_flags.flags != 0) {       \
             if (exec_env->suspend_flags.flags & 0x01) { \
             if (exec_env->suspend_flags.flags & 0x01) { \
                 /* terminate current thread */          \
                 /* terminate current thread */          \
+                os_mutex_unlock(&exec_env->wait_lock);  \
                 return;                                 \
                 return;                                 \
             }                                           \
             }                                           \
             /* TODO: support suspend and breakpoint */  \
             /* TODO: support suspend and breakpoint */  \
         }                                               \
         }                                               \
+        os_mutex_unlock(&exec_env->wait_lock);          \
     } while (0)
     } while (0)
 #endif
 #endif
 
 
@@ -1151,13 +1155,22 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                                WASMFunctionInstance *cur_func,
                                WASMFunctionInstance *cur_func,
                                WASMInterpFrame *prev_frame)
                                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);
     WASMMemoryInstance *memory = wasm_get_default_memory(module);
+
 #if !defined(OS_ENABLE_HW_BOUND_CHECK)              \
 #if !defined(OS_ENABLE_HW_BOUND_CHECK)              \
     || WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \
     || WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \
     || WASM_ENABLE_BULK_MEMORY != 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 =
     uint32 linear_mem_size =
-        memory ? num_bytes_per_page * memory->cur_page_count : 0;
+        memory ? wasm_get_linear_memory_size(memory, node) : 0;
 #endif
 #endif
     uint8 *global_data = module->global_data;
     uint8 *global_data = module->global_data;
     WASMGlobalInstance *globals = module->e ? module->e->globals : NULL;
     WASMGlobalInstance *globals = module->e ? module->e->globals : NULL;
@@ -3261,6 +3274,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                         if (ret == (uint32)-1)
                         if (ret == (uint32)-1)
                             goto got_exception;
                             goto got_exception;
 
 
+#if WASM_ENABLE_THREAD_MGR != 0
+                        CHECK_SUSPEND_FLAGS();
+#endif
+
                         PUSH_I32(ret);
                         PUSH_I32(ret);
                         break;
                         break;
                     }
                     }
@@ -3281,9 +3298,18 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                         if (ret == (uint32)-1)
                         if (ret == (uint32)-1)
                             goto got_exception;
                             goto got_exception;
 
 
+#if WASM_ENABLE_THREAD_MGR != 0
+                        CHECK_SUSPEND_FLAGS();
+#endif
+
                         PUSH_I32(ret);
                         PUSH_I32(ret);
                         break;
                         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_LOAD:
                     case WASM_OP_ATOMIC_I32_LOAD8_U:
                     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) {
                         if (opcode == WASM_OP_ATOMIC_I32_LOAD8_U) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS(1);
                             CHECK_ATOMIC_MEMORY_ACCESS(1);
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             readv = (uint32)(*(uint8 *)maddr);
                             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) {
                         else if (opcode == WASM_OP_ATOMIC_I32_LOAD16_U) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS(2);
                             CHECK_ATOMIC_MEMORY_ACCESS(2);
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             readv = (uint32)LOAD_U16(maddr);
                             readv = (uint32)LOAD_U16(maddr);
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         }
                         else {
                         else {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS(4);
                             CHECK_ATOMIC_MEMORY_ACCESS(4);
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             readv = LOAD_I32(maddr);
                             readv = LOAD_I32(maddr);
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         }
 
 
                         PUSH_I32(readv);
                         PUSH_I32(readv);
@@ -3331,30 +3357,30 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                         if (opcode == WASM_OP_ATOMIC_I64_LOAD8_U) {
                         if (opcode == WASM_OP_ATOMIC_I64_LOAD8_U) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS(1);
                             CHECK_ATOMIC_MEMORY_ACCESS(1);
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             readv = (uint64)(*(uint8 *)maddr);
                             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) {
                         else if (opcode == WASM_OP_ATOMIC_I64_LOAD16_U) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS(2);
                             CHECK_ATOMIC_MEMORY_ACCESS(2);
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             readv = (uint64)LOAD_U16(maddr);
                             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) {
                         else if (opcode == WASM_OP_ATOMIC_I64_LOAD32_U) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS(4);
                             CHECK_ATOMIC_MEMORY_ACCESS(4);
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             readv = (uint64)LOAD_U32(maddr);
                             readv = (uint64)LOAD_U32(maddr);
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         }
                         else {
                         else {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr);
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS(8);
                             CHECK_ATOMIC_MEMORY_ACCESS(8);
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             readv = LOAD_I64(maddr);
                             readv = LOAD_I64(maddr);
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         }
 
 
                         PUSH_I64(readv);
                         PUSH_I64(readv);
@@ -3372,23 +3398,23 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                         if (opcode == WASM_OP_ATOMIC_I32_STORE8) {
                         if (opcode == WASM_OP_ATOMIC_I32_STORE8) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS(1);
                             CHECK_ATOMIC_MEMORY_ACCESS(1);
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             *(uint8 *)maddr = (uint8)sval;
                             *(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) {
                         else if (opcode == WASM_OP_ATOMIC_I32_STORE16) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS(2);
                             CHECK_ATOMIC_MEMORY_ACCESS(2);
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             STORE_U16(maddr, (uint16)sval);
                             STORE_U16(maddr, (uint16)sval);
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         }
                         else {
                         else {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS(4);
                             CHECK_ATOMIC_MEMORY_ACCESS(4);
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             STORE_U32(maddr, sval);
                             STORE_U32(maddr, sval);
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         }
                         break;
                         break;
                     }
                     }
@@ -3406,30 +3432,30 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                         if (opcode == WASM_OP_ATOMIC_I64_STORE8) {
                         if (opcode == WASM_OP_ATOMIC_I64_STORE8) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS(1);
                             CHECK_ATOMIC_MEMORY_ACCESS(1);
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             *(uint8 *)maddr = (uint8)sval;
                             *(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) {
                         else if (opcode == WASM_OP_ATOMIC_I64_STORE16) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS(2);
                             CHECK_ATOMIC_MEMORY_ACCESS(2);
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             STORE_U16(maddr, (uint16)sval);
                             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) {
                         else if (opcode == WASM_OP_ATOMIC_I64_STORE32) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS(4);
                             CHECK_ATOMIC_MEMORY_ACCESS(4);
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             STORE_U32(maddr, (uint32)sval);
                             STORE_U32(maddr, (uint32)sval);
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         }
                         else {
                         else {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr);
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS(8);
                             CHECK_ATOMIC_MEMORY_ACCESS(8);
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             STORE_I64(maddr, sval);
                             STORE_I64(maddr, sval);
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         }
                         break;
                         break;
                     }
                     }
@@ -3449,32 +3475,32 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                             CHECK_ATOMIC_MEMORY_ACCESS(1);
                             CHECK_ATOMIC_MEMORY_ACCESS(1);
 
 
                             expect = (uint8)expect;
                             expect = (uint8)expect;
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             readv = (uint32)(*(uint8 *)maddr);
                             readv = (uint32)(*(uint8 *)maddr);
                             if (readv == expect)
                             if (readv == expect)
                                 *(uint8 *)maddr = (uint8)(sval);
                                 *(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) {
                         else if (opcode == WASM_OP_ATOMIC_RMW_I32_CMPXCHG16_U) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS(2);
                             CHECK_ATOMIC_MEMORY_ACCESS(2);
 
 
                             expect = (uint16)expect;
                             expect = (uint16)expect;
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             readv = (uint32)LOAD_U16(maddr);
                             readv = (uint32)LOAD_U16(maddr);
                             if (readv == expect)
                             if (readv == expect)
                                 STORE_U16(maddr, (uint16)(sval));
                                 STORE_U16(maddr, (uint16)(sval));
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         }
                         else {
                         else {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS(4);
                             CHECK_ATOMIC_MEMORY_ACCESS(4);
 
 
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             readv = LOAD_I32(maddr);
                             readv = LOAD_I32(maddr);
                             if (readv == expect)
                             if (readv == expect)
                                 STORE_U32(maddr, sval);
                                 STORE_U32(maddr, sval);
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         }
                         PUSH_I32(readv);
                         PUSH_I32(readv);
                         break;
                         break;
@@ -3495,44 +3521,44 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                             CHECK_ATOMIC_MEMORY_ACCESS(1);
                             CHECK_ATOMIC_MEMORY_ACCESS(1);
 
 
                             expect = (uint8)expect;
                             expect = (uint8)expect;
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             readv = (uint64)(*(uint8 *)maddr);
                             readv = (uint64)(*(uint8 *)maddr);
                             if (readv == expect)
                             if (readv == expect)
                                 *(uint8 *)maddr = (uint8)(sval);
                                 *(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) {
                         else if (opcode == WASM_OP_ATOMIC_RMW_I64_CMPXCHG16_U) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS(2);
                             CHECK_ATOMIC_MEMORY_ACCESS(2);
 
 
                             expect = (uint16)expect;
                             expect = (uint16)expect;
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             readv = (uint64)LOAD_U16(maddr);
                             readv = (uint64)LOAD_U16(maddr);
                             if (readv == expect)
                             if (readv == expect)
                                 STORE_U16(maddr, (uint16)(sval));
                                 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) {
                         else if (opcode == WASM_OP_ATOMIC_RMW_I64_CMPXCHG32_U) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS(4);
                             CHECK_ATOMIC_MEMORY_ACCESS(4);
 
 
                             expect = (uint32)expect;
                             expect = (uint32)expect;
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             readv = (uint64)LOAD_U32(maddr);
                             readv = (uint64)LOAD_U32(maddr);
                             if (readv == expect)
                             if (readv == expect)
                                 STORE_U32(maddr, (uint32)(sval));
                                 STORE_U32(maddr, (uint32)(sval));
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         }
                         else {
                         else {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr);
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS(8);
                             CHECK_ATOMIC_MEMORY_ACCESS(8);
 
 
-                            os_mutex_lock(&module->e->mem_lock);
+                            os_mutex_lock(&node->shared_mem_lock);
                             readv = (uint64)LOAD_I64(maddr);
                             readv = (uint64)LOAD_I64(maddr);
                             if (readv == expect) {
                             if (readv == expect) {
                                 STORE_I64(maddr, sval);
                                 STORE_I64(maddr, sval);
                             }
                             }
-                            os_mutex_unlock(&module->e->mem_lock);
+                            os_mutex_unlock(&node->shared_mem_lock);
                         }
                         }
                         PUSH_I64(readv);
                         PUSH_I64(readv);
                         break;
                         break;
@@ -3781,7 +3807,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
             if (memory)
             if (memory)
                 linear_mem_size = num_bytes_per_page * memory->cur_page_count;
                 linear_mem_size = num_bytes_per_page * memory->cur_page_count;
 #endif
 #endif
-            if (wasm_get_exception(module))
+            if (wasm_copy_exception(module, NULL))
                 goto got_exception;
                 goto got_exception;
         }
         }
         else {
         else {
@@ -3821,6 +3847,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
 
 
             wasm_exec_env_set_cur_frame(exec_env, (WASMRuntimeFrame *)frame);
             wasm_exec_env_set_cur_frame(exec_env, (WASMRuntimeFrame *)frame);
         }
         }
+#if WASM_ENABLE_THREAD_MGR != 0
+        CHECK_SUSPEND_FLAGS();
+#endif
         HANDLE_OP_END();
         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
     /* This frame won't be used by JITed code, so only allocate interp
        frame here.  */
        frame here.  */
     unsigned frame_size = wasm_interp_interp_frame_size(all_cell_num);
     unsigned frame_size = wasm_interp_interp_frame_size(all_cell_num);
+    char exception[EXCEPTION_BUF_LEN];
 
 
     if (argc < function->param_cell_num) {
     if (argc < function->param_cell_num) {
         char buf[128];
         char buf[128];
@@ -3901,6 +3931,7 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env,
     }
     }
     argc = function->param_cell_num;
     argc = function->param_cell_num;
 
 
+    RECORD_STACK_USAGE(exec_env, (uint8 *)&prev_frame);
 #if !(defined(OS_ENABLE_HW_BOUND_CHECK) \
 #if !(defined(OS_ENABLE_HW_BOUND_CHECK) \
       && WASM_DISABLE_STACK_HW_BOUND_CHECK == 0)
       && WASM_DISABLE_STACK_HW_BOUND_CHECK == 0)
     if ((uint8 *)&prev_frame < exec_env->native_stack_boundary) {
     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 */
     /* 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++)
         for (i = 0; i < function->ret_cell_num; i++)
             argv[i] = *(frame->lp + 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);
             wasm_interp_dump_call_stack(exec_env, true, NULL, 0);
         }
         }
 #endif
 #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);
     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;
     WASMModule *sub_module = NULL;
     WASMGlobal *linked_global = NULL;
     WASMGlobal *linked_global = NULL;
 #endif
 #endif
+    bool ret = false;
 
 
     CHECK_BUF(p, p_end, 2);
     CHECK_BUF(p, p_end, 2);
     declare_type = read_uint8(p);
     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
 #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
         if (global->type != declare_type
             || global->is_mutable != declare_mutable) {
             || global->is_mutable != declare_mutable) {
             set_error_buf(error_buf, error_buf_size,
             set_error_buf(error_buf, error_buf_size,
                           "incompatible import type");
                           "incompatible import type");
             return false;
             return false;
         }
         }
+        global->is_linked = true;
     }
     }
 #endif
 #endif
 #if WASM_ENABLE_MULTI_MODULE != 0
 #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);
     global->is_mutable = (declare_mutable == 1);
 
 
     (void)parent_module;
     (void)parent_module;
+    (void)ret;
     return true;
     return true;
 fail:
 fail:
     return false;
     return false;
@@ -2989,6 +2992,7 @@ static bool
 init_llvm_jit_functions_stage1(WASMModule *module, char *error_buf,
 init_llvm_jit_functions_stage1(WASMModule *module, char *error_buf,
                                uint32 error_buf_size)
                                uint32 error_buf_size)
 {
 {
+    LLVMJITOptions llvm_jit_options = wasm_runtime_get_llvm_jit_options();
     AOTCompOption option = { 0 };
     AOTCompOption option = { 0 };
     char *aot_last_error;
     char *aot_last_error;
     uint64 size;
     uint64 size;
@@ -3027,8 +3031,11 @@ init_llvm_jit_functions_stage1(WASMModule *module, char *error_buf,
     }
     }
 
 
     option.is_jit_mode = true;
     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
 #if WASM_ENABLE_BULK_MEMORY != 0
     option.enable_bulk_memory = true;
     option.enable_bulk_memory = true;
 #endif
 #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)
 #if (WASM_ENABLE_PERF_PROFILING != 0) || (WASM_ENABLE_DUMP_CALL_STACK != 0)
     option.enable_aux_stack_frame = true;
     option.enable_aux_stack_frame = true;
 #endif
 #endif
+#if WASM_ENABLE_MEMORY_PROFILING != 0
+    option.enable_stack_estimation = true;
+#endif
 
 
     module->comp_ctx = aot_create_comp_context(module->comp_data, &option);
     module->comp_ctx = aot_create_comp_context(module->comp_data, &option);
     if (!module->comp_ctx) {
     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;
         module->func_ptrs[i] = (void *)func_addr;
 
 
 #if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_LAZY_JIT != 0
 #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)
         if (module->orcjit_stop_compiling)
             return false;
             return false;
 #endif
 #endif
@@ -3199,9 +3211,9 @@ orcjit_thread_callback(void *arg)
 
 
     /* Wait until init_llvm_jit_functions_stage2 finishes */
     /* Wait until init_llvm_jit_functions_stage2 finishes */
     os_mutex_lock(&module->tierup_wait_lock);
     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,
         os_cond_reltimedwait(&module->tierup_wait_cond,
-                             &module->tierup_wait_lock, 10);
+                             &module->tierup_wait_lock, 10000);
         if (module->orcjit_stop_compiling) {
         if (module->orcjit_stop_compiling) {
             /* init_llvm_jit_functions_stage2 failed */
             /* init_llvm_jit_functions_stage2 failed */
             os_mutex_unlock(&module->tierup_wait_lock);
             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);
     bh_assert(ret == BH_LIST_SUCCESS);
 #endif
 #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)
         && WASM_ENABLE_LAZY_JIT != 0)
     if (os_mutex_init(&module->instance_list_lock) != 0) {
     if (os_mutex_init(&module->instance_list_lock) != 0) {
         set_error_buf(error_buf, error_buf_size,
         set_error_buf(error_buf, error_buf_size,
@@ -4148,10 +4160,8 @@ check_wasi_abi_compatibility(const WASMModule *module,
 
 
     /* should have one at least */
     /* should have one at least */
     if (module->import_wasi_api && !start && !initialize) {
     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,
     memory = wasm_loader_find_export(module, "", "memory", EXPORT_KIND_MEMORY,
                                      error_buf, error_buf_size);
                                      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,
         set_error_buf(error_buf, error_buf_size,
                       "a module with WASI apis must export memory by default");
                       "a module with WASI apis must export memory by default");
         return false;
         return false;
@@ -4243,7 +4266,8 @@ wasm_loader_unload(WASMModule *module)
     if (!module)
     if (!module)
         return;
         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;
     module->orcjit_stop_compiling = true;
     if (module->llvm_jit_init_thread)
     if (module->llvm_jit_init_thread)
         os_thread_join(module->llvm_jit_init_thread, NULL);
         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);
         aot_destroy_comp_data(module->comp_data);
 #endif
 #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) {
     if (module->tierup_wait_lock_inited) {
         os_mutex_destroy(&module->tierup_wait_lock);
         os_mutex_destroy(&module->tierup_wait_lock);
         os_cond_destroy(&module->tierup_wait_cond);
         os_cond_destroy(&module->tierup_wait_cond);
@@ -4299,9 +4324,9 @@ wasm_loader_unload(WASMModule *module)
                         module->functions[i]->fast_jit_jitted_code);
                         module->functions[i]->fast_jit_jitted_code);
                 }
                 }
 #if WASM_ENABLE_JIT != 0 && WASM_ENABLE_LAZY_JIT != 0
 #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(
                     jit_code_cache_free(
-                        module->functions[i]->llvm_jit_func_ptr);
+                        module->functions[i]->call_to_fast_jit_from_llvm_jit);
                 }
                 }
 #endif
 #endif
 #endif
 #endif
@@ -4393,8 +4418,8 @@ wasm_loader_unload(WASMModule *module)
     }
     }
 #endif
 #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)
         && WASM_ENABLE_LAZY_JIT != 0)
     os_mutex_destroy(&module->instance_list_lock);
     os_mutex_destroy(&module->instance_list_lock);
 #endif
 #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,
 init_llvm_jit_functions_stage1(WASMModule *module, char *error_buf,
                                uint32 error_buf_size)
                                uint32 error_buf_size)
 {
 {
+    LLVMJITOptions llvm_jit_options = wasm_runtime_get_llvm_jit_options();
     AOTCompOption option = { 0 };
     AOTCompOption option = { 0 };
     char *aot_last_error;
     char *aot_last_error;
     uint64 size;
     uint64 size;
@@ -1873,8 +1874,9 @@ init_llvm_jit_functions_stage1(WASMModule *module, char *error_buf,
     }
     }
 
 
     option.is_jit_mode = true;
     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
 #if WASM_ENABLE_BULK_MEMORY != 0
     option.enable_bulk_memory = true;
     option.enable_bulk_memory = true;
 #endif
 #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)
 #if (WASM_ENABLE_PERF_PROFILING != 0) || (WASM_ENABLE_DUMP_CALL_STACK != 0)
     option.enable_aux_stack_frame = true;
     option.enable_aux_stack_frame = true;
 #endif
 #endif
+#if WASM_ENABLE_MEMORY_PROFILING != 0
+    option.enable_stack_estimation = true;
+#endif
 
 
     module->comp_ctx = aot_create_comp_context(module->comp_data, &option);
     module->comp_ctx = aot_create_comp_context(module->comp_data, &option);
     if (!module->comp_ctx) {
     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;
         module->func_ptrs[i] = (void *)func_addr;
 
 
 #if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_LAZY_JIT != 0
 #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)
         if (module->orcjit_stop_compiling)
             return false;
             return false;
 #endif
 #endif
@@ -2047,9 +2054,9 @@ orcjit_thread_callback(void *arg)
 
 
     /* Wait until init_llvm_jit_functions_stage2 finishes */
     /* Wait until init_llvm_jit_functions_stage2 finishes */
     os_mutex_lock(&module->tierup_wait_lock);
     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,
         os_cond_reltimedwait(&module->tierup_wait_cond,
-                             &module->tierup_wait_lock, 10);
+                             &module->tierup_wait_lock, 10000);
         if (module->orcjit_stop_compiling) {
         if (module->orcjit_stop_compiling) {
             /* init_llvm_jit_functions_stage2 failed */
             /* init_llvm_jit_functions_stage2 failed */
             os_mutex_unlock(&module->tierup_wait_lock);
             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);
     bh_assert(ret == BH_LIST_SUCCESS);
 #endif
 #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) {
     if (os_mutex_init(&module->instance_list_lock) != 0) {
         set_error_buf(error_buf, error_buf_size,
         set_error_buf(error_buf, error_buf_size,
                       "init instance list lock failed");
                       "init instance list lock failed");
@@ -2939,7 +2947,8 @@ wasm_loader_unload(WASMModule *module)
     if (!module)
     if (!module)
         return;
         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;
     module->orcjit_stop_compiling = true;
     if (module->llvm_jit_init_thread)
     if (module->llvm_jit_init_thread)
         os_thread_join(module->llvm_jit_init_thread, NULL);
         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);
         aot_destroy_comp_data(module->comp_data);
 #endif
 #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) {
     if (module->tierup_wait_lock_inited) {
         os_mutex_destroy(&module->tierup_wait_lock);
         os_mutex_destroy(&module->tierup_wait_lock);
         os_cond_destroy(&module->tierup_wait_cond);
         os_cond_destroy(&module->tierup_wait_cond);
@@ -2995,9 +3005,9 @@ wasm_loader_unload(WASMModule *module)
                         module->functions[i]->fast_jit_jitted_code);
                         module->functions[i]->fast_jit_jitted_code);
                 }
                 }
 #if WASM_ENABLE_JIT != 0 && WASM_ENABLE_LAZY_JIT != 0
 #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(
                     jit_code_cache_free(
-                        module->functions[i]->llvm_jit_func_ptr);
+                        module->functions[i]->call_to_fast_jit_from_llvm_jit);
                 }
                 }
 #endif
 #endif
 #endif
 #endif
@@ -3056,7 +3066,8 @@ wasm_loader_unload(WASMModule *module)
     }
     }
 #endif
 #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);
     os_mutex_destroy(&module->instance_list_lock);
 #endif
 #endif
 
 

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

@@ -675,12 +675,14 @@ typedef enum WASMAtomicEXTOpcode {
 } WASMAtomicEXTOpcode;
 } WASMAtomicEXTOpcode;
 
 
 #if WASM_ENABLE_DEBUG_INTERP != 0
 #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
 #else
-#define DEF_DEBUG_BREAK_HANDLE(_name)
+#define DEF_DEBUG_BREAK_HANDLE()
 #endif
 #endif
 
 
+#define SET_GOTO_TABLE_ELEM(opcode) [opcode] = HANDLE_OPCODE(opcode)
+
 /*
 /*
  * Macro used to generate computed goto tables for the C interpreter.
  * 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_LOOP),                  /* 0xd4 */ \
         HANDLE_OPCODE(EXT_OP_IF),                    /* 0xd5 */ \
         HANDLE_OPCODE(EXT_OP_IF),                    /* 0xd5 */ \
         HANDLE_OPCODE(EXT_OP_BR_TABLE_CACHE),        /* 0xd6 */ \
         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
 #ifdef __cplusplus
 }
 }

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

@@ -737,13 +737,12 @@ functions_instantiate(const WASMModule *module, WASMModuleInstance *module_inst,
 
 
         function++;
         function++;
     }
     }
+    bh_assert((uint32)(function - functions) == function_count);
 
 
 #if WASM_ENABLE_FAST_JIT != 0
 #if WASM_ENABLE_FAST_JIT != 0
     module_inst->fast_jit_func_ptrs = module->fast_jit_func_ptrs;
     module_inst->fast_jit_func_ptrs = module->fast_jit_func_ptrs;
 #endif
 #endif
 
 
-    bh_assert((uint32)(function - functions) == function_count);
-    (void)module_inst;
     return functions;
     return functions;
 }
 }
 
 
@@ -983,88 +982,138 @@ export_globals_instantiate(const WASMModule *module,
 }
 }
 #endif
 #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 */
         /* 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 */
         /* 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
 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 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
 static bool
@@ -1235,6 +1284,7 @@ check_linked_symbol(WASMModuleInstance *module_inst, char *error_buf,
 #if WASM_ENABLE_WAMR_COMPILER == 0
 #if WASM_ENABLE_WAMR_COMPILER == 0
             LOG_WARNING("warning: failed to link import function (%s, %s)",
             LOG_WARNING("warning: failed to link import function (%s, %s)",
                         func->module_name, func->field_name);
                         func->module_name, func->field_name);
+            /* will throw exception only if calling */
 #else
 #else
             /* do nothing to avoid confused message */
             /* do nothing to avoid confused message */
 #endif /* WASM_ENABLE_WAMR_COMPILER == 0 */
 #endif /* WASM_ENABLE_WAMR_COMPILER == 0 */
@@ -1250,8 +1300,10 @@ check_linked_symbol(WASMModuleInstance *module_inst, char *error_buf,
             return false;
             return false;
 #else
 #else
 #if WASM_ENABLE_WAMR_COMPILER == 0
 #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
 #else
             /* do nothing to avoid confused message */
             /* do nothing to avoid confused message */
 #endif /* WASM_ENABLE_WAMR_COMPILER == 0 */
 #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;
         *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;
     return true;
 }
 }
 #endif /* end of WASM_ENABLE_JIT != 0 */
 #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 */
 #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
  * Instantiate module
  */
  */
@@ -1419,15 +1637,6 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, uint32 stack_size,
     module_inst->e =
     module_inst->e =
         (WASMModuleInstanceExtra *)((uint8 *)module_inst + extra_info_offset);
         (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
 #if WASM_ENABLE_MULTI_MODULE != 0
     module_inst->e->sub_module_inst_list =
     module_inst->e->sub_module_inst_list =
         &module_inst->e->sub_module_inst_list_head;
         &module_inst->e->sub_module_inst_list_head;
@@ -1800,33 +2009,39 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, uint32 stack_size,
     }
     }
 #endif
 #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) {
     if (!is_sub_inst) {
         /* Add module instance into module's instance list */
         /* Add module instance into module's instance list */
         os_mutex_lock(&module->instance_list_lock);
         os_mutex_lock(&module->instance_list_lock);
-#if WASM_ENABLE_DEBUG_INTERP != 0
         if (module->instance_list) {
         if (module->instance_list) {
             LOG_WARNING(
             LOG_WARNING(
                 "warning: multiple instances referencing to the same module "
                 "warning: multiple instances referencing to the same module "
                 "may cause unexpected behaviour during debugging");
                 "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_inst->e->next = module->instance_list;
         module->instance_list = module_inst;
         module->instance_list = module_inst;
         os_mutex_unlock(&module->instance_list_lock);
         os_mutex_unlock(&module->instance_list_lock);
     }
     }
 #endif
 #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) {
     if (module->start_function != (uint32)-1) {
         /* TODO: fix start function can be import function issue */
         /* TODO: fix start function can be import function issue */
         if (module->start_function >= module->import_function_count)
         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];
                 &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);
         set_error_buf(error_buf, error_buf_size, module_inst->cur_exception);
         goto fail;
         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
 #if WASM_ENABLE_MEMORY_TRACING != 0
     wasm_runtime_dump_module_inst_mem_consumption(
     wasm_runtime_dump_module_inst_mem_consumption(
         (WASMModuleInstanceCommon *)module_inst);
         (WASMModuleInstanceCommon *)module_inst);
@@ -1892,11 +2073,57 @@ wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst)
     if (!module_inst)
     if (!module_inst)
         return;
         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 WASM_ENABLE_JIT != 0
     if (module_inst->func_ptrs)
     if (module_inst->func_ptrs)
         wasm_runtime_free(module_inst->func_ptrs);
         wasm_runtime_free(module_inst->func_ptrs);
 #endif
 #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 WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0
     if (module_inst->func_type_indexes)
     if (module_inst->func_type_indexes)
         wasm_runtime_free(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);
     wasm_externref_cleanup((WASMModuleInstanceCommon *)module_inst);
 #endif
 #endif
 
 
-    if (module_inst->exec_env_singleton)
-        wasm_exec_env_destroy(module_inst->exec_env_singleton);
-
 #if WASM_ENABLE_DUMP_CALL_STACK != 0
 #if WASM_ENABLE_DUMP_CALL_STACK != 0
     if (module_inst->frames) {
     if (module_inst->frames) {
         bh_vector_destroy(module_inst->frames);
         bh_vector_destroy(module_inst->frames);
@@ -1948,39 +2172,17 @@ wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst)
     }
     }
 #endif
 #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
 #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);
     wasm_runtime_free(module_inst);
 }
 }
 
 
@@ -2030,24 +2232,6 @@ wasm_lookup_table(const WASMModuleInstance *module_inst, const char *name)
 }
 }
 #endif
 #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
 #ifdef OS_ENABLE_HW_BOUND_CHECK
 
 
 static void
 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);
     WASMRuntimeFrame *prev_frame = wasm_exec_env_get_cur_frame(exec_env);
     uint8 *prev_top = exec_env->wasm_stack.s.top;
     uint8 *prev_top = exec_env->wasm_stack.s.top;
 #ifdef BH_PLATFORM_WINDOWS
 #ifdef BH_PLATFORM_WINDOWS
-    const char *exce;
     int result;
     int result;
+    bool has_exception;
+    char exception[EXCEPTION_BUF_LEN];
 #endif
 #endif
     bool ret = true;
     bool ret = true;
 
 
     /* Check native stack overflow firstly to ensure we have enough
     /* Check native stack overflow firstly to ensure we have enough
        native stack to run the following codes before actually calling
        native stack to run the following codes before actually calling
        the aot function in invokeNative function. */
        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
     if ((uint8 *)&exec_env_tls < exec_env->native_stack_boundary
                                      + page_size * (guard_page_count + 1)) {
                                      + page_size * (guard_page_count + 1)) {
         wasm_set_exception(module_inst, "native stack overflow");
         wasm_set_exception(module_inst, "native stack overflow");
@@ -2096,14 +2282,14 @@ call_wasm_with_hw_bound_check(WASMModuleInstance *module_inst,
 #else
 #else
         __try {
         __try {
             wasm_interp_call_wasm(module_inst, exec_env, function, argc, argv);
             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_EXECUTE_HANDLER
                         : EXCEPTION_CONTINUE_SEARCH) {
                         : EXCEPTION_CONTINUE_SEARCH) {
             /* exception was thrown in wasm_exception_handler */
             /* exception was thrown in wasm_exception_handler */
             ret = false;
             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
             /* After a stack overflow, the stack was left
                in a damaged state, let the CRT repair it */
                in a damaged state, let the CRT repair it */
             result = _resetstkoflw();
             result = _resetstkoflw();
@@ -2157,8 +2343,7 @@ wasm_call_function(WASMExecEnv *exec_env, WASMFunctionInstance *function,
     wasm_exec_env_set_thread_info(exec_env);
     wasm_exec_env_set_thread_info(exec_env);
 
 
     interp_call_wasm(module_inst, exec_env, function, argc, argv);
     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
 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 */
     /* don't destroy the exec_env if it isn't created in this function */
     if (!existing_exec_env)
     if (!existing_exec_env)
@@ -2331,6 +2516,12 @@ wasm_module_free(WASMModuleInstance *module_inst, uint32 ptr)
             return;
             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;
         addr = memory->memory_data + ptr;
 
 
         if (memory->heap_handle && memory->heap_data <= addr
         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,
             execute_free_function(module_inst, module_inst->e->free_function,
                                   ptr);
                                   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);
     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:
 got_exception:
     return false;
     return false;
@@ -2476,14 +2670,16 @@ wasm_set_aux_stack(WASMExecEnv *exec_env, uint32 start_offset, uint32 size)
     WASMModuleInstance *module_inst =
     WASMModuleInstance *module_inst =
         (WASMModuleInstance *)exec_env->module_inst;
         (WASMModuleInstance *)exec_env->module_inst;
     uint32 stack_top_idx = module_inst->module->aux_stack_top_global_index;
     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 data_end = module_inst->module->aux_data_end;
     uint32 stack_bottom = module_inst->module->aux_stack_bottom;
     uint32 stack_bottom = module_inst->module->aux_stack_bottom;
     bool is_stack_before_data = stack_bottom < data_end ? true : false;
     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))
     if ((is_stack_before_data && (size > start_offset))
         || ((!is_stack_before_data) && (start_offset - data_end < size)))
         || ((!is_stack_before_data) && (start_offset - data_end < size)))
         return false;
         return false;
+#endif
 
 
     if (stack_top_idx != (uint32)-1) {
     if (stack_top_idx != (uint32)-1) {
         /* The aux stack top is a wasm global,
         /* 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;
     import_func = &module->import_functions[func_idx].u.function;
     if (import_func->call_conv_wasm_c_api) {
     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) {
     if (!func_ptr) {

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

@@ -11,10 +11,16 @@
 #include "../common/wasm_runtime_common.h"
 #include "../common/wasm_runtime_common.h"
 #include "../common/wasm_exec_env.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
 #ifdef __cplusplus
 extern "C" {
 extern "C" {
 #endif
 #endif
 
 
+#define EXCEPTION_BUF_LEN 128
+
 typedef struct WASMModuleInstance WASMModuleInstance;
 typedef struct WASMModuleInstance WASMModuleInstance;
 typedef struct WASMFunctionInstance WASMFunctionInstance;
 typedef struct WASMFunctionInstance WASMFunctionInstance;
 typedef struct WASMMemoryInstance WASMMemoryInstance;
 typedef struct WASMMemoryInstance WASMMemoryInstance;
@@ -59,9 +65,7 @@ typedef enum WASMExceptionID {
     EXCE_AUX_STACK_UNDERFLOW,
     EXCE_AUX_STACK_UNDERFLOW,
     EXCE_OUT_OF_BOUNDS_TABLE_ACCESS,
     EXCE_OUT_OF_BOUNDS_TABLE_ACCESS,
     EXCE_OPERAND_STACK_OVERFLOW,
     EXCE_OPERAND_STACK_OVERFLOW,
-#if WASM_ENABLE_FAST_JIT != 0
     EXCE_FAILED_TO_COMPILE_FAST_JIT_FUNC,
     EXCE_FAILED_TO_COMPILE_FAST_JIT_FUNC,
-#endif
     EXCE_ALREADY_THROWN,
     EXCE_ALREADY_THROWN,
     EXCE_NUM,
     EXCE_NUM,
 } WASMExceptionID;
 } WASMExceptionID;
@@ -219,12 +223,7 @@ typedef struct WASMModuleInstanceExtra {
     WASMFunctionInstance *retain_function;
     WASMFunctionInstance *retain_function;
 
 
     CApiFuncImport *c_api_func_imports;
     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
 #if WASM_ENABLE_MULTI_MODULE != 0
     bh_list sub_module_inst_list_head;
     bh_list sub_module_inst_list_head;
@@ -237,11 +236,15 @@ typedef struct WASMModuleInstanceExtra {
     uint32 max_aux_stack_used;
     uint32 max_aux_stack_used;
 #endif
 #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)
         && WASM_ENABLE_LAZY_JIT != 0)
     WASMModuleInstance *next;
     WASMModuleInstance *next;
 #endif
 #endif
+
+#if WASM_ENABLE_WASI_NN != 0
+    WASINNContext *wasi_nn_ctx;
+#endif
 } WASMModuleInstanceExtra;
 } WASMModuleInstanceExtra;
 
 
 struct AOTFuncPerfProfInfo;
 struct AOTFuncPerfProfInfo;
@@ -281,7 +284,7 @@ struct WASMModuleInstance {
     DefPointer(WASMExportTabInstance *, export_tables);
     DefPointer(WASMExportTabInstance *, export_tables);
 
 
     /* The exception buffer of wasm interpreter for current thread. */
     /* 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,
     /* The WASM module or AOT module, for AOTModuleInstance,
        it denotes `AOTModule *` */
        it denotes `AOTModule *` */
@@ -298,7 +301,11 @@ struct WASMModuleInstance {
        not available in AOTModuleInstance */
        not available in AOTModuleInstance */
     DefPointer(void **, import_func_ptrs);
     DefPointer(void **, import_func_ptrs);
     /* Array of function pointers to fast jit functions,
     /* 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);
     DefPointer(void **, fast_jit_func_ptrs);
     /* The custom data that can be set/get by wasm_{get|set}_custom_data */
     /* The custom data that can be set/get by wasm_{get|set}_custom_data */
     DefPointer(void *, custom_data);
     DefPointer(void *, custom_data);
@@ -402,6 +409,10 @@ wasm_dump_perf_profiling(const WASMModuleInstance *module_inst);
 void
 void
 wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst);
 wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst);
 
 
+bool
+wasm_set_running_mode(WASMModuleInstance *module_inst,
+                      RunningMode running_mode);
+
 WASMFunctionInstance *
 WASMFunctionInstance *
 wasm_lookup_function(const WASMModuleInstance *module_inst, const char *name,
 wasm_lookup_function(const WASMModuleInstance *module_inst, const char *name,
                      const char *signature);
                      const char *signature);
@@ -435,6 +446,15 @@ wasm_set_exception_with_id(WASMModuleInstance *module_inst, uint32 id);
 const char *
 const char *
 wasm_get_exception(WASMModuleInstance *module);
 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
 uint32
 wasm_module_malloc(WASMModuleInstance *module_inst, uint32 size,
 wasm_module_malloc(WASMModuleInstance *module_inst, uint32 size,
                    void **p_native_addr);
                    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)
     wasm_runtime_addr_native_to_app(module_inst, ptr)
 /* clang-format on */
 /* clang-format on */
 
 
-extern bool
-wasm_runtime_call_indirect(wasm_exec_env_t exec_env, uint32 element_indices,
-                           uint32 argc, uint32 argv[]);
-
 enum {
 enum {
     T_THREAD,
     T_THREAD,
     T_MUTEX,
     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 exec_env = (wasm_exec_env_t)arg;
     wasm_exec_env_t parent_exec_env;
     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;
     ThreadRoutineArgs *routine_args = exec_env->thread_arg;
     ThreadInfoNode *info_node = routine_args->info_node;
     ThreadInfoNode *info_node = routine_args->info_node;
     uint32 argv[1];
     uint32 argv[1];
@@ -504,7 +499,6 @@ pthread_start_routine(void *arg)
     info_node->exec_env = exec_env;
     info_node->exec_env = exec_env;
     info_node->u.thread = exec_env->handle;
     info_node->u.thread = exec_env->handle;
     if (!append_thread_info_node(info_node)) {
     if (!append_thread_info_node(info_node)) {
-        wasm_runtime_deinstantiate_internal(module_inst, true);
         delete_thread_info_node(info_node);
         delete_thread_info_node(info_node);
         os_cond_signal(&parent_exec_env->wait_cond);
         os_cond_signal(&parent_exec_env->wait_cond);
         os_mutex_unlock(&parent_exec_env->wait_lock);
         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,
     if (!wasm_runtime_call_indirect(exec_env, routine_args->elem_index, 1,
                                     argv)) {
                                     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 */
     /* destroy pthread key values */
     call_key_destructor(exec_env);
     call_key_destructor(exec_env);
 
 
-    /* routine exit, destroy instance */
-    wasm_runtime_deinstantiate_internal(module_inst, true);
-
     wasm_runtime_free(routine_args);
     wasm_runtime_free(routine_args);
 
 
     /* if the thread is joinable, store the result in its info node,
     /* 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
 #if WASM_ENABLE_LIBC_WASI != 0
     WASIContext *wasi_ctx;
     WASIContext *wasi_ctx;
 #endif
 #endif
+    CApiFuncImport **new_c_api_func_imports = NULL;
 
 
     bh_assert(module);
     bh_assert(module);
     bh_assert(module_inst);
     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);
         wasm_runtime_set_wasi_ctx(new_module_inst, wasi_ctx);
 #endif
 #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))))
     if (!(info_node = wasm_runtime_malloc(sizeof(ThreadInfoNode))))
         goto fail;
         goto fail;
 
 
@@ -623,8 +654,9 @@ pthread_create_wrapper(wasm_exec_env_t exec_env,
     routine_args->module_inst = new_module_inst;
     routine_args->module_inst = new_module_inst;
 
 
     os_mutex_lock(&exec_env->wait_lock);
     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) {
     if (ret != 0) {
         os_mutex_unlock(&exec_env->wait_lock);
         os_mutex_unlock(&exec_env->wait_lock);
         goto fail;
         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
+}

Bu fark içinde çok fazla dosya değişikliği olduğu için bazı dosyalar gösterilmiyor