Browse Source

Merge pull request #2426 from bytecodealliance/main

Merge branch main into dev/wasi-libc-windows
Wenyong Huang 2 years ago
parent
commit
a07d8160f9
66 changed files with 2273 additions and 1396 deletions
  1. 47 31
      .devcontainer/Dockerfile
  2. 13 10
      .devcontainer/devcontainer.json
  3. 2 2
      .github/workflows/compilation_on_android_ubuntu.yml
  4. 47 0
      .github/workflows/hadolint_dockerfiles.yml
  5. 2 2
      .github/workflows/nightly_run.yml
  6. 2 2
      ATTRIBUTIONS.md
  7. 11 0
      core/config.h
  8. 12 0
      core/iwasm/aot/aot_loader.c
  9. 36 62
      core/iwasm/aot/aot_runtime.c
  10. 4 4
      core/iwasm/aot/aot_runtime.h
  11. 14 18
      core/iwasm/aot/arch/aot_reloc_riscv.c
  12. 19 1
      core/iwasm/aot/arch/aot_reloc_xtensa.c
  13. 3 9
      core/iwasm/common/wasm_exec_env.h
  14. 5 43
      core/iwasm/common/wasm_memory.c
  15. 0 10
      core/iwasm/common/wasm_memory.h
  16. 15 18
      core/iwasm/common/wasm_runtime_common.c
  17. 2 1
      core/iwasm/common/wasm_runtime_common.h
  18. 84 113
      core/iwasm/common/wasm_shared_memory.c
  19. 12 32
      core/iwasm/common/wasm_shared_memory.h
  20. 48 0
      core/iwasm/common/wasm_suspend_flags.h
  21. 2 2
      core/iwasm/compilation/aot.h
  22. 1 1
      core/iwasm/compilation/aot_compiler.c
  23. 40 41
      core/iwasm/compilation/aot_llvm_extra.cpp
  24. 16 16
      core/iwasm/compilation/debug/dwarf_extractor.cpp
  25. 2 2
      core/iwasm/compilation/debug/dwarf_extractor.h
  26. 21 20
      core/iwasm/fast-jit/fe/jit_emit_table.c
  27. 2 2
      core/iwasm/include/aot_export.h
  28. 18 1
      core/iwasm/interpreter/wasm.h
  29. 103 94
      core/iwasm/interpreter/wasm_interp_classic.c
  30. 85 84
      core/iwasm/interpreter/wasm_interp_fast.c
  31. 7 5
      core/iwasm/interpreter/wasm_loader.c
  32. 2 1
      core/iwasm/interpreter/wasm_mini_loader.c
  33. 44 63
      core/iwasm/interpreter/wasm_runtime.c
  34. 3 2
      core/iwasm/interpreter/wasm_runtime.h
  35. 13 6
      core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c
  36. 1 0
      core/iwasm/libraries/lib-socket/test/nslookup.c
  37. 112 113
      core/iwasm/libraries/lib-socket/test/tcp_udp.c
  38. 1 1
      core/iwasm/libraries/lib-wasi-threads/lib_wasi_threads_wrapper.c
  39. 4 1
      core/iwasm/libraries/lib-wasi-threads/test/build.sh
  40. 3 0
      core/iwasm/libraries/lib-wasi-threads/test/manifest.json
  41. 5 0
      core/iwasm/libraries/lib-wasi-threads/test/skip.json
  42. 114 0
      core/iwasm/libraries/lib-wasi-threads/test/spawn_stress_test.c
  43. 1 1
      core/iwasm/libraries/libc-uvwasi/libc_uvwasi.cmake
  44. 24 20
      core/iwasm/libraries/thread-mgr/thread_manager.c
  45. 68 5
      core/shared/platform/esp-idf/espidf_memmap.c
  46. 6 0
      core/shared/platform/esp-idf/shared_platform.cmake
  47. 5 0
      core/shared/platform/include/platform_api_vmcore.h
  48. 79 2
      core/shared/platform/nuttx/nuttx_platform.c
  49. 123 0
      core/shared/utils/bh_atomic.h
  50. 0 0
      core/shared/utils/gnuc.h
  51. 44 43
      doc/embed_wamr.md
  52. 38 0
      doc/embed_wamr_spawn_api.md
  53. 3 1
      product-mini/platforms/esp-idf/build_and_run.sh
  54. 7 1
      product-mini/platforms/esp-idf/main/main.c
  55. 64 0
      product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.cpp
  56. 6 0
      product-mini/platforms/nuttx/wamr.mk
  57. 20 0
      samples/bh_atomic/CMakeLists.txt
  58. 42 0
      samples/bh_atomic/main.c
  59. 183 132
      samples/workload/XNNPACK/CMakeLists.txt
  60. 21 20
      samples/workload/XNNPACK/README.md
  61. 95 98
      samples/workload/XNNPACK/xnnpack.patch
  62. 334 160
      test-tools/host-tool/external/cJSON/cJSON.c
  63. 94 65
      test-tools/host-tool/external/cJSON/cJSON.h
  64. 0 20
      tests/wamr-test-suites/spec-test-script/ignore_cases.patch
  65. 1 1
      tests/wamr-test-suites/test_wamr.sh
  66. 38 14
      tests/wamr-test-suites/wasi-test-script/run_wasi_tests.sh

+ 47 - 31
.devcontainer/Dockerfile

@@ -1,20 +1,21 @@
 # Copyright (C) 2019 Intel Corporation.  All rights reserved.
 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 
-# See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.195.0/containers/cpp/.devcontainer/base.Dockerfile
-# [Choice] Debian / Ubuntu version (use Debian 11/9, Ubuntu 18.04/21.04 on local arm64/Apple Silicon): debian-11, debian-10, debian-9, ubuntu-21.04, ubuntu-20.04, ubuntu-18.04
-ARG VARIANT=ubuntu-20.04
-FROM mcr.microsoft.com/vscode/devcontainers/cpp:0-${VARIANT}
+# See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.245.2/containers/cpp/.devcontainer/base.Dockerfile
+# [Choice] Debian / Ubuntu version (use Debian 12/11/9, Ubuntu 18.04/21.04 on local arm64/Apple Silicon): debian-12, debian-11, debian-10, debian-9, ubuntu-21.04, ubuntu-20.04, ubuntu-18.04
+ARG VARIANT=debian-12
+FROM mcr.microsoft.com/vscode/devcontainers/cpp:${VARIANT}
 
 ARG DEBIAN_FRONTEND=noninteractive
 ENV TZ=Asian/Shanghai
 
 # hadolint ignore=DL3008
 RUN apt-get update \
+  && apt-get upgrade -y \
   && apt-get install -y apt-transport-https apt-utils build-essential \
-  ca-certificates ccache curl g++-multilib git gnupg \
-  libgcc-9-dev lib32gcc-9-dev lsb-release \
-  ninja-build ocaml ocamlbuild python2.7 \
+  ca-certificates ccache cmake curl g++-multilib git gnupg \
+  libgcc-12-dev lib32gcc-12-dev lsb-release \
+  ninja-build ocaml ocamlbuild \
   software-properties-common tree tzdata \
   unzip valgrind vim wget zip --no-install-recommends \
   && apt-get clean -y \
@@ -22,32 +23,32 @@ RUN apt-get update \
 
 #
 # binaryen
-ARG BINARYEN_VER=111
+ARG BINARYEN_VER=114
 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 \
+  && ln -sf /opt/binaryen-version_${BINARYEN_VER} /opt/binaryen \
   && rm binaryen-version_${BINARYEN_VER}-x86_64-linux.tar.gz
 
 #
 # CMAKE (https://apt.kitware.com/)
 SHELL ["/bin/bash", "-o", "pipefail", "-c"]
 # hadolint ignore=DL3008
-RUN wget --progress=dot:giga -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | tee /usr/share/keyrings/kitware-archive-keyring.gpg > /dev/null \
-  && echo 'deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ bionic main' | tee /etc/apt/sources.list.d/kitware.list >/dev/null \
-  && apt-get update \
-  && rm /usr/share/keyrings/kitware-archive-keyring.gpg \
-  && apt-get install -y kitware-archive-keyring --no-install-recommends \
-  && apt-get install -y cmake --no-install-recommends \
-  && apt-get clean -y \
-  && rm -rf /var/lib/apt/lists/*
+ARG CMAKE_VER=3.27.0
+RUN wget https://github.com/Kitware/CMake/releases/download/v${CMAKE_VER}/cmake-${CMAKE_VER}-Linux-x86_64.sh \
+      -q -O /tmp/cmake-install.sh \
+      && chmod u+x /tmp/cmake-install.sh \
+      && mkdir /opt/cmake-${CMAKE_VER} \
+      && /tmp/cmake-install.sh --skip-license --prefix=/opt/cmake-${CMAKE_VER} \
+      && rm /tmp/cmake-install.sh \
+      && ln -s /opt/cmake-${CMAKE_VER}/bin/* /usr/local/bin
 
 #
 # install emsdk
 WORKDIR /opt
 RUN git clone https://github.com/emscripten-core/emsdk.git
 
-ARG EMSDK_VER=3.0.0
+ARG EMSDK_VER=3.1.43
 WORKDIR /opt/emsdk
 RUN  git pull \
   && ./emsdk install ${EMSDK_VER} \
@@ -56,7 +57,7 @@ RUN  git pull \
 
 #
 # install wasi-sdk
-ARG WASI_SDK_VER=19
+ARG WASI_SDK_VER=20
 RUN wget -c --progress=dot:giga https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-${WASI_SDK_VER}/wasi-sdk-${WASI_SDK_VER}.0-linux.tar.gz -P /opt \
   && tar xf /opt/wasi-sdk-${WASI_SDK_VER}.0-linux.tar.gz -C /opt \
   && ln -sf /opt/wasi-sdk-${WASI_SDK_VER}.0 /opt/wasi-sdk \
@@ -64,7 +65,7 @@ RUN wget -c --progress=dot:giga https://github.com/WebAssembly/wasi-sdk/releases
 
 #
 #install wabt
-ARG WABT_VER=1.0.29
+ARG WABT_VER=1.0.33
 RUN wget -c --progress=dot:giga https://github.com/WebAssembly/wabt/releases/download/${WABT_VER}/wabt-${WABT_VER}-ubuntu.tar.gz -P /opt \
   && tar xf /opt/wabt-${WABT_VER}-ubuntu.tar.gz -C /opt \
   && ln -sf /opt/wabt-${WABT_VER} /opt/wabt \
@@ -72,7 +73,7 @@ RUN wget -c --progress=dot:giga https://github.com/WebAssembly/wabt/releases/dow
 
 #
 # install bazelisk
-ARG BAZELISK_VER=1.12.0
+ARG BAZELISK_VER=1.17.0
 RUN mkdir /opt/bazelisk \
   && wget -c --progress=dot:giga https://github.com/bazelbuild/bazelisk/releases/download/v${BAZELISK_VER}/bazelisk-linux-amd64 -P /opt/bazelisk \
   && chmod a+x /opt/bazelisk/bazelisk-linux-amd64 \
@@ -80,16 +81,30 @@ RUN mkdir /opt/bazelisk \
 
 #
 # install clang+llvm
-ARG LLVM_VER=14
-RUN apt-get purge -y clang-10 llvm-10 && apt-get autoremove -y
+ARG LLVM_VER=16
+RUN apt-get purge -y clang-14 llvm-14 && apt-get autoremove -y
 WORKDIR /etc/apt/apt.conf.d
 RUN touch 99verfiy-peer.conf \
   && echo "Acquire { https::Verify-Peer false }" > 99verfiy-peer.conf
 
 WORKDIR /tmp
-RUN wget --progress=dot:giga https://apt.llvm.org/llvm.sh \
-  && chmod a+x ./llvm.sh \
-  && ./llvm.sh ${LLVM_VER} all
+#RUN wget --progress=dot:giga https://apt.llvm.org/llvm.sh \
+#  && chmod a+x ./llvm.sh \
+#  && ./llvm.sh ${LLVM_VER} all
+
+# Workaround due to https://github.com/llvm/llvm-project/issues/62475
+# hadolint ignore=DL3008
+RUN set -ex \
+    && echo "deb http://apt.llvm.org/bookworm/ llvm-toolchain-bookworm-${LLVM_VER} main" > /etc/apt/sources.list.d/apt.llvm.org.list \
+    && wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc \
+    && apt-get update \
+    && apt-get install -y \
+    clang-${LLVM_VER} lldb-${LLVM_VER} lld-${LLVM_VER} clangd-${LLVM_VER} clang-tidy-${LLVM_VER} clang-format-${LLVM_VER} clang-tools-${LLVM_VER} \
+    llvm-${LLVM_VER}-dev lld-${LLVM_VER} lldb-${LLVM_VER} llvm-${LLVM_VER}-tools libomp-${LLVM_VER}-dev libc++-${LLVM_VER}-dev libc++abi-${LLVM_VER}-dev \
+    libclang-common-${LLVM_VER}-dev libclang-${LLVM_VER}-dev libclang-cpp${LLVM_VER}-dev libunwind-${LLVM_VER}-dev \
+    libclang-rt-${LLVM_VER}-dev libpolly-${LLVM_VER}-dev --no-install-recommends \
+    && apt-get clean -y \
+    && rm -rf /var/lib/apt/lists/*
 
 #
 # [Optional]
@@ -105,18 +120,19 @@ RUN apt-get update \
 #
 # Install required python packages
 # hadolint ignore=DL3013
-RUN python3 -m pip install --no-cache-dir --upgrade pip \
-  && pip3 install --no-cache-dir black nose pycparser pylint
+RUN python3 -m pip install --no-cache-dir --break-system-packages --upgrade pip \
+  && pip3 install --no-cache-dir --break-system-packages black nose pycparser pylint
 
 #
 # Install github-cli. It doens't work as a feature of devcontainer.json
+ARG GH_CLI_VER=2.32.0
 WORKDIR /tmp
-RUN wget -q 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
+RUN wget -q https://github.com/cli/cli/releases/download/v${GH_CLI_VER}/gh_${GH_CLI_VER}_linux_amd64.deb \
+  && dpkg -i gh_${GH_CLI_VER}_linux_amd64.deb
 
 #
 # Install NodeJS
-RUN wget -qO- https://deb.nodesource.com/setup_19.x | bash -
+RUN wget -qO- https://deb.nodesource.com/setup_20.x | bash -
 # hadolint ignore=DL3008
 RUN apt-get install -y nodejs --no-install-recommends
 

+ 13 - 10
.devcontainer/devcontainer.json

@@ -1,20 +1,23 @@
 // Copyright (C) 2019 Intel Corporation.  All rights reserved.
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 // For format details, see https://aka.ms/vscode-remote/devcontainer.json or this file's README at:
-// https://github.com/microsoft/vscode-dev-containers/tree/v0.195.0/containers/cpp
+// https://github.com/microsoft/vscode-dev-containers/tree/v0.245.2/containers/cpp
 {
   "name": "WAMR-Dev",
   "build": {
     "dockerfile": "Dockerfile",
-    // 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
+    // Update 'VARIANT' to pick an Debian / Ubuntu OS version: debian-12, debian-11, debian-10, debian-9, ubuntu-21.04, ubuntu-20.04, ubuntu-18.04
+    // Use Debian 12, Debian 11, Debian 9, Ubuntu 18.04 or Ubuntu 21.04 on local arm64/Apple Silicon
     "args": {
-      "BINARYEN_VER": "111",
-      "EMSDK_VER": "3.0.0",
-      "LLVM_VER": "15",
-      "VARIANT": "ubuntu-20.04",
-      "WASI_SDK_VER": "19",
-      "WABT_VER": "1.0.31"
+      "BINARYEN_VER": "114",
+      "BAZELISK_VER": "1.17.0",
+      "CMAKE_VER": "3.27.0",
+      "EMSDK_VER": "3.1.43",
+      "GH_CLI_VER": "2.32.0",
+      "LLVM_VER": "16",
+      "VARIANT": "debian-12",
+      "WASI_SDK_VER": "20",
+      "WABT_VER": "1.0.33"
     }
   },
   "runArgs": [
@@ -34,7 +37,7 @@
         "llvm-vs-code-extensions.vscode-clangd",
         "ms-python.python",
         "ms-python.vscode-pylance",
-        "ms-vscode.cmake-tools",
+        "ms-vscode.cmake-tools"
       ]
     }
   },

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

@@ -527,7 +527,7 @@ jobs:
         working-directory: ./core/iwasm/libraries/lib-socket/test/
 
       - name: run tests
-        timeout-minutes: 10
+        timeout-minutes: 20
         run: ./test_wamr.sh ${{ matrix.test_option }} -t ${{ matrix.running_mode }}
         working-directory: ./tests/wamr-test-suites
 
@@ -543,7 +543,7 @@ jobs:
           sudo apt install -y g++-multilib lib32gcc-9-dev
 
       - name: run tests x86_32
-        timeout-minutes: 10
+        timeout-minutes: 20
         if: env.TEST_ON_X86_32 == 'true'
         run: ./test_wamr.sh ${{ env.X86_32_TARGET_TEST_OPTIONS }} ${{ matrix.test_option }} -t ${{ matrix.running_mode }}
         working-directory: ./tests/wamr-test-suites

+ 47 - 0
.github/workflows/hadolint_dockerfiles.yml

@@ -0,0 +1,47 @@
+# Copyright (C) 2019 Intel Corporation.  All rights reserved.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+name: hadolint dockerfiles
+
+on:
+  # will be triggered on PR events
+  pull_request:
+    types:
+      - opened
+      - synchronize
+    paths:
+      - "**/Dockerfile*"
+      - ".github/workflows/hadolint_dockerfiles.yml"
+  push:
+    branches:
+      - main
+      - "dev/**"
+    paths:
+      - "**/Dockerfile*"
+      - ".github/workflows/hadolint_dockerfiles.yml"
+  # allow to be triggered manually
+  workflow_dispatch:
+
+# Cancel any in-flight jobs for the same PR/branch so there's only one active
+# at a time
+concurrency:
+  group: ${{ github.workflow }}-${{ github.ref }}
+  cancel-in-progress: true
+
+jobs:
+  run-hadolint-on-dockerfiles:
+    runs-on: ubuntu-22.04
+
+    steps:
+      - name: Checkout repository
+        uses: actions/checkout@v3
+
+      # on default, hadolint will fail on warnings and errors
+      - name: Run hadolint on dockerfiles
+        run: |
+          docker pull hadolint/hadolint:latest-debian
+          find . -name "*Dockerfile*" | while read dockerfile; do
+            echo "run hadolint on $dockerfile:"
+            docker run --rm -i hadolint/hadolint:latest-debian hadolint - <"$dockerfile"
+            echo "successful"
+          done

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

@@ -595,7 +595,7 @@ jobs:
         working-directory: ./core/iwasm/libraries/lib-socket/test/
 
       - name: run tests
-        timeout-minutes: 10
+        timeout-minutes: 20
         run: ./test_wamr.sh ${{ matrix.test_option }} -t ${{ matrix.running_mode }}
         working-directory: ./tests/wamr-test-suites
 
@@ -611,7 +611,7 @@ jobs:
           sudo apt install -y g++-multilib lib32gcc-9-dev
 
       - name: run tests x86_32
-        timeout-minutes: 10
+        timeout-minutes: 20
         if: env.TEST_ON_X86_32 == 'true'
         run: ./test_wamr.sh ${{ env.X86_32_TARGET_TEST_OPTIONS }} ${{ matrix.test_option }} -t ${{ matrix.running_mode }}
         working-directory: ./tests/wamr-test-suites

+ 2 - 2
ATTRIBUTIONS.md

@@ -22,7 +22,7 @@ The WAMR fast interpreter is a clean room development. We would acknowledge the
 
 |  third party components | version number | latest release | vendor pages | CVE details |
 | --- | --- | --- | --- | --- |
-| cjson | 1.7.10 | 1.7.14 | https://github.com/DaveGamble/cJSON | https://www.cvedetails.com/vendor/19164/Cjson-Project.html |
+| cjson | 1.7.16 | 1.7.16 | https://github.com/DaveGamble/cJSON | https://www.cvedetails.com/vendor/19164/Cjson-Project.html |
 | contiki-ng (er-coap) | unspecified | 3.0 | https://github.com/contiki-os/contiki | https://www.cvedetails.com/vendor/16528/Contiki-os.html |
 | freebsd libm | unspecified | 13.0 | https://www.freebsd.org/ | https://www.cvedetails.com/vendor/6/Freebsd.html |
 | LVGL | 6.0.1 | 7.11.0 | https://lvgl.io/ | |
@@ -31,7 +31,7 @@ The WAMR fast interpreter is a clean room development. We would acknowledge the
 | wasmtime | unspecified | v0.26.0 | https://github.com/bytecodealliance/wasmtime | |
 | zephyr | unspecified | v2.5.0 | https://www.zephyrproject.org/ | https://www.cvedetails.com/vendor/19255/Zephyrproject.html |
 | WebAssembly debugging patch for LLDB | unspecified | unspecified | https://reviews.llvm.org/D78801 | |
-| libuv | v1.42.0 | v1.44.1 | https://github.com/libuv/libuv | https://www.cvedetails.com/vendor/15402/Libuv-Project.html |
+| libuv | v1.46.0 | v1.46.0 | https://github.com/libuv/libuv | https://www.cvedetails.com/vendor/15402/Libuv-Project.html |
 | uvwasi | unspecified | v0.0.12 | https://github.com/nodejs/uvwasi | |
 | asmjit | unspecified | unspecified | https://github.com/asmjit/asmjit | |
 | zydis | unspecified | e14a07895136182a5b53e181eec3b1c6e0b434de | https://github.com/zyantific/zydis | |

+ 11 - 0
core/config.h

@@ -461,4 +461,15 @@
 #define WASM_CONFIGURABLE_BOUNDS_CHECKS 0
 #endif
 
+/* Some chip cannot support external ram with rwx attr at the same time,
+   it has to map it into 2 spaces of idbus and dbus, code in dbus can be
+   read/written and read/executed in ibus. so there are 2 steps to execute
+   the code, first, copy&do relocaiton in dbus space, and second execute
+   it in ibus space, since in the 2 spaces the contents are the same,
+   so we call it bus mirror.
+ */
+#ifndef WASM_MEM_DUAL_BUS_MIRROR
+#define WASM_MEM_DUAL_BUS_MIRROR 0
+#endif
+
 #endif /* end of _CONFIG_H_ */

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

@@ -3013,6 +3013,9 @@ create_sections(AOTModule *module, const uint8 *buf, uint32 size,
     uint32 section_size;
     uint64 total_size;
     uint8 *aot_text;
+#if (WASM_MEM_DUAL_BUS_MIRROR != 0)
+    uint8 *mirrored_text;
+#endif
 
     if (!resolve_execute_mode(buf, size, &is_indirect_mode, error_buf,
                               error_buf_size)) {
@@ -3071,8 +3074,17 @@ create_sections(AOTModule *module, const uint8 *buf, uint32 size,
                     bh_assert((uintptr_t)aot_text < INT32_MAX);
 #endif
 #endif
+
+#if (WASM_MEM_DUAL_BUS_MIRROR != 0)
+                    mirrored_text = os_get_dbus_mirror(aot_text);
+                    bh_assert(mirrored_text != NULL);
+                    bh_memcpy_s(mirrored_text, (uint32)total_size,
+                                section->section_body, (uint32)section_size);
+                    os_dcache_flush();
+#else
                     bh_memcpy_s(aot_text, (uint32)total_size,
                                 section->section_body, (uint32)section_size);
+#endif
                     section->section_body = aot_text;
                     destroy_aot_text = true;
 

+ 36 - 62
core/iwasm/aot/aot_runtime.c

@@ -339,11 +339,8 @@ memories_deinstantiate(AOTModuleInstance *module_inst)
         memory_inst = module_inst->memories[i];
         if (memory_inst) {
 #if WASM_ENABLE_SHARED_MEMORY != 0
-            if (memory_inst->is_shared) {
-                int32 ref_count = shared_memory_dec_reference(
-                    (WASMModuleCommon *)module_inst->module);
-                bh_assert(ref_count >= 0);
-
+            if (shared_memory_is_shared(memory_inst)) {
+                uint32 ref_count = shared_memory_dec_reference(memory_inst);
                 /* if the reference count is not zero,
                     don't free the memory */
                 if (ref_count > 0)
@@ -373,9 +370,10 @@ memories_deinstantiate(AOTModuleInstance *module_inst)
 }
 
 static AOTMemoryInstance *
-memory_instantiate(AOTModuleInstance *module_inst, AOTModule *module,
-                   AOTMemoryInstance *memory_inst, AOTMemory *memory,
-                   uint32 heap_size, char *error_buf, uint32 error_buf_size)
+memory_instantiate(AOTModuleInstance *module_inst, AOTModuleInstance *parent,
+                   AOTModule *module, AOTMemoryInstance *memory_inst,
+                   AOTMemory *memory, uint32 memory_idx, uint32 heap_size,
+                   char *error_buf, uint32 error_buf_size)
 {
     void *heap_handle;
     uint32 num_bytes_per_page = memory->num_bytes_per_page;
@@ -396,23 +394,13 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModule *module,
     bool is_shared_memory = memory->memory_flags & 0x02 ? true : false;
 
     /* Shared memory */
-    if (is_shared_memory) {
+    if (is_shared_memory && parent != NULL) {
         AOTMemoryInstance *shared_memory_instance;
-        WASMSharedMemNode *node =
-            wasm_module_get_shared_memory((WASMModuleCommon *)module);
-        /* If the memory of this module has been instantiated,
-            return the memory instance directly */
-        if (node) {
-            uint32 ref_count;
-            ref_count = shared_memory_inc_reference((WASMModuleCommon *)module);
-            bh_assert(ref_count > 0);
-            shared_memory_instance =
-                (AOTMemoryInstance *)shared_memory_get_memory_inst(node);
-            bh_assert(shared_memory_instance);
-
-            (void)ref_count;
-            return shared_memory_instance;
-        }
+        bh_assert(memory_idx == 0);
+        bh_assert(parent->memory_count > memory_idx);
+        shared_memory_instance = parent->memories[memory_idx];
+        shared_memory_inc_reference(shared_memory_instance);
+        return shared_memory_instance;
     }
 #endif
 
@@ -609,23 +597,12 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModule *module,
 
 #if WASM_ENABLE_SHARED_MEMORY != 0
     if (is_shared_memory) {
-        memory_inst->is_shared = true;
-        if (!shared_memory_set_memory_inst(
-                (WASMModuleCommon *)module,
-                (WASMMemoryInstanceCommon *)memory_inst)) {
-            set_error_buf(error_buf, error_buf_size, "allocate memory failed");
-            goto fail3;
-        }
+        memory_inst->ref_count = 1;
     }
 #endif
 
     return memory_inst;
 
-#if WASM_ENABLE_SHARED_MEMORY != 0
-fail3:
-    if (heap_size > 0)
-        mem_allocator_destroy(memory_inst->heap_handle);
-#endif
 fail2:
     if (heap_size > 0)
         wasm_runtime_free(memory_inst->heap_handle);
@@ -654,8 +631,9 @@ aot_get_default_memory(AOTModuleInstance *module_inst)
 }
 
 static bool
-memories_instantiate(AOTModuleInstance *module_inst, AOTModule *module,
-                     uint32 heap_size, char *error_buf, uint32 error_buf_size)
+memories_instantiate(AOTModuleInstance *module_inst, AOTModuleInstance *parent,
+                     AOTModule *module, uint32 heap_size, char *error_buf,
+                     uint32 error_buf_size)
 {
     uint32 global_index, global_data_offset, base_offset, length;
     uint32 i, memory_count = module->memory_count;
@@ -672,8 +650,8 @@ memories_instantiate(AOTModuleInstance *module_inst, AOTModule *module,
 
     memories = module_inst->global_table_data.memory_instances;
     for (i = 0; i < memory_count; i++, memories++) {
-        memory_inst = memory_instantiate(module_inst, module, memories,
-                                         &module->memories[i], heap_size,
+        memory_inst = memory_instantiate(module_inst, parent, module, memories,
+                                         &module->memories[i], i, heap_size,
                                          error_buf, error_buf_size);
         if (!memory_inst) {
             return false;
@@ -1100,9 +1078,9 @@ check_linked_symbol(AOTModule *module, char *error_buf, uint32 error_buf_size)
 }
 
 AOTModuleInstance *
-aot_instantiate(AOTModule *module, bool is_sub_inst, WASMExecEnv *exec_env_main,
-                uint32 stack_size, uint32 heap_size, char *error_buf,
-                uint32 error_buf_size)
+aot_instantiate(AOTModule *module, AOTModuleInstance *parent,
+                WASMExecEnv *exec_env_main, uint32 stack_size, uint32 heap_size,
+                char *error_buf, uint32 error_buf_size)
 {
     AOTModuleInstance *module_inst;
     const uint32 module_inst_struct_size =
@@ -1112,6 +1090,7 @@ aot_instantiate(AOTModule *module, bool is_sub_inst, WASMExecEnv *exec_env_main,
     uint64 total_size, table_size = 0;
     uint8 *p;
     uint32 i, extra_info_offset;
+    const bool is_sub_inst = parent != NULL;
 
     /* Check heap size */
     heap_size = align_uint(heap_size, 8);
@@ -1171,7 +1150,7 @@ aot_instantiate(AOTModule *module, bool is_sub_inst, WASMExecEnv *exec_env_main,
         goto fail;
 
     /* Initialize memory space */
-    if (!memories_instantiate(module_inst, module, heap_size, error_buf,
+    if (!memories_instantiate(module_inst, parent, module, heap_size, error_buf,
                               error_buf_size))
         goto fail;
 
@@ -1264,16 +1243,6 @@ aot_deinstantiate(AOTModuleInstance *module_inst, bool is_sub_inst)
         wasm_exec_env_destroy((WASMExecEnv *)module_inst->exec_env_singleton);
     }
 
-#if WASM_ENABLE_LIBC_WASI != 0
-    /* Destroy wasi resource before freeing app heap, since some fields of
-       wasi contex are allocated from app heap, and if app heap is freed,
-       these fields will be set to NULL, we cannot free their internal data
-       which may allocated from global heap. */
-    /* Only destroy wasi ctx in the main module instance */
-    if (!is_sub_inst)
-        wasm_runtime_destroy_wasi((WASMModuleInstanceCommon *)module_inst);
-#endif
-
 #if WASM_ENABLE_PERF_PROFILING != 0
     if (module_inst->func_perf_profilings)
         wasm_runtime_free(module_inst->func_perf_profilings);
@@ -1306,10 +1275,14 @@ aot_deinstantiate(AOTModuleInstance *module_inst, bool is_sub_inst)
         wasm_runtime_free(
             ((AOTModuleInstanceExtra *)module_inst->e)->c_api_func_imports);
 
+    if (!is_sub_inst) {
+#if WASM_ENABLE_LIBC_WASI != 0
+        wasm_runtime_destroy_wasi((WASMModuleInstanceCommon *)module_inst);
+#endif
 #if WASM_ENABLE_WASI_NN != 0
-    if (!is_sub_inst)
         wasi_nn_destroy(module_inst);
 #endif
+    }
 
     wasm_runtime_free(module_inst);
 }
@@ -2489,13 +2462,13 @@ aot_table_init(AOTModuleInstance *module_inst, uint32 tbl_idx,
     tbl_seg = module->table_init_data_list[tbl_seg_idx];
     bh_assert(tbl_seg);
 
-    if (!length) {
+    if (offset_len_out_of_bounds(src_offset, length, tbl_seg->func_index_count)
+        || offset_len_out_of_bounds(dst_offset, length, tbl_inst->cur_size)) {
+        aot_set_exception_with_id(module_inst, EXCE_OUT_OF_BOUNDS_TABLE_ACCESS);
         return;
     }
 
-    if (length + src_offset > tbl_seg->func_index_count
-        || dst_offset + length > tbl_inst->cur_size) {
-        aot_set_exception_with_id(module_inst, EXCE_OUT_OF_BOUNDS_TABLE_ACCESS);
+    if (!length) {
         return;
     }
 
@@ -2528,8 +2501,9 @@ aot_table_copy(AOTModuleInstance *module_inst, uint32 src_tbl_idx,
     dst_tbl_inst = module_inst->tables[dst_tbl_idx];
     bh_assert(dst_tbl_inst);
 
-    if ((uint64)dst_offset + length > dst_tbl_inst->cur_size
-        || (uint64)src_offset + length > src_tbl_inst->cur_size) {
+    if (offset_len_out_of_bounds(dst_offset, length, dst_tbl_inst->cur_size)
+        || offset_len_out_of_bounds(src_offset, length,
+                                    src_tbl_inst->cur_size)) {
         aot_set_exception_with_id(module_inst, EXCE_OUT_OF_BOUNDS_TABLE_ACCESS);
         return;
     }
@@ -2554,7 +2528,7 @@ aot_table_fill(AOTModuleInstance *module_inst, uint32 tbl_idx, uint32 length,
     tbl_inst = module_inst->tables[tbl_idx];
     bh_assert(tbl_inst);
 
-    if (data_offset + length > tbl_inst->cur_size) {
+    if (offset_len_out_of_bounds(data_offset, length, tbl_inst->cur_size)) {
         aot_set_exception_with_id(module_inst, EXCE_OUT_OF_BOUNDS_TABLE_ACCESS);
         return;
     }

+ 4 - 4
core/iwasm/aot/aot_runtime.h

@@ -406,7 +406,7 @@ aot_unload(AOTModule *module);
  * Instantiate a AOT module.
  *
  * @param module the AOT module to instantiate
- * @param is_sub_inst the flag of sub instance
+ * @param parent the parent module instance
  * @param heap_size the default heap size of the module instance, a heap will
  *        be created besides the app memory space. Both wasm app and native
  *        function can allocate memory from the heap. If heap_size is 0, the
@@ -417,9 +417,9 @@ aot_unload(AOTModule *module);
  * @return return the instantiated AOT module instance, NULL if failed
  */
 AOTModuleInstance *
-aot_instantiate(AOTModule *module, bool is_sub_inst, WASMExecEnv *exec_env_main,
-                uint32 stack_size, uint32 heap_size, char *error_buf,
-                uint32 error_buf_size);
+aot_instantiate(AOTModule *module, AOTModuleInstance *parent,
+                WASMExecEnv *exec_env_main, uint32 stack_size, uint32 heap_size,
+                char *error_buf, uint32 error_buf_size);
 
 /**
  * Deinstantiate a AOT module instance, destroy the resources.

+ 14 - 18
core/iwasm/aot/arch/aot_reloc_riscv.c

@@ -78,6 +78,13 @@ static SymbolMap target_sym_map[] = {
     REG_SYM(__addsf3),
     REG_SYM(__divdf3),
     REG_SYM(__divsf3),
+    REG_SYM(__eqdf2),
+    REG_SYM(__eqsf2),
+    REG_SYM(__extendsfdf2),
+    REG_SYM(__fixunsdfdi),
+    REG_SYM(__fixunsdfsi),
+    REG_SYM(__fixunssfdi),
+    REG_SYM(__fixunssfsi),
     REG_SYM(__gedf2),
     REG_SYM(__gesf2),
     REG_SYM(__gtdf2),
@@ -89,44 +96,33 @@ static SymbolMap target_sym_map[] = {
     REG_SYM(__muldf3),
     REG_SYM(__nedf2),
     REG_SYM(__nesf2),
-    REG_SYM(__eqsf2),
-    REG_SYM(__eqdf2),
-    REG_SYM(__extendsfdf2),
-    REG_SYM(__fixunsdfdi),
-    REG_SYM(__fixunsdfsi),
-    REG_SYM(__fixunssfsi),
     REG_SYM(__subdf3),
     REG_SYM(__subsf3),
     REG_SYM(__truncdfsf2),
     REG_SYM(__unorddf2),
     REG_SYM(__unordsf2),
-#endif
-    REG_SYM(__divdi3),
-    REG_SYM(__divsi3),
 #if __riscv_xlen == 32
     REG_SYM(__fixdfdi),
     REG_SYM(__fixdfsi),
     REG_SYM(__fixsfdi),
     REG_SYM(__fixsfsi),
-#endif
-    REG_SYM(__fixunssfdi),
-#if __riscv_xlen == 32
     REG_SYM(__floatdidf),
     REG_SYM(__floatdisf),
-    REG_SYM(__floatsisf),
     REG_SYM(__floatsidf),
+    REG_SYM(__floatsisf),
     REG_SYM(__floatundidf),
     REG_SYM(__floatundisf),
-    REG_SYM(__floatunsisf),
     REG_SYM(__floatunsidf),
+    REG_SYM(__floatunsisf),
+    REG_SYM(__mulsf3),
+    REG_SYM(__mulsi3),
+#endif
 #endif
+    REG_SYM(__divdi3),
+    REG_SYM(__divsi3),
     REG_SYM(__moddi3),
     REG_SYM(__modsi3),
     REG_SYM(__muldi3),
-#if __riscv_xlen == 32
-    REG_SYM(__mulsf3),
-    REG_SYM(__mulsi3),
-#endif
     REG_SYM(__udivdi3),
     REG_SYM(__udivsi3),
     REG_SYM(__umoddi3),

+ 19 - 1
core/iwasm/aot/arch/aot_reloc_xtensa.c

@@ -43,6 +43,11 @@ void __floatdidf();
 void __divsf3();
 void __fixdfdi();
 void __floatundidf();
+void __fixsfdi();
+void __fixunssfdi();
+void __fixunsdfdi();
+void __floatdisf();
+void __floatundisf();
 
 
 static SymbolMap target_sym_map[] = {
@@ -85,6 +90,11 @@ static SymbolMap target_sym_map[] = {
     REG_SYM(__divsf3),
     REG_SYM(__fixdfdi),
     REG_SYM(__floatundidf),
+    REG_SYM(__fixsfdi),
+    REG_SYM(__fixunssfdi),
+    REG_SYM(__fixunsdfdi),
+    REG_SYM(__floatdisf),
+    REG_SYM(__floatundisf),
 };
 /* clang-format on */
 
@@ -207,6 +217,10 @@ apply_relocation(AOTModule *module, uint8 *target_section_addr,
         case R_XTENSA_32:
         {
             uint8 *insn_addr = target_section_addr + reloc_offset;
+#if (WASM_MEM_DUAL_BUS_MIRROR != 0)
+            insn_addr = os_get_dbus_mirror((void *)insn_addr);
+            bh_assert(insn_addr != NULL);
+#endif
             int32 initial_addend;
             /* (S + A) */
             if ((intptr_t)insn_addr & 3) {
@@ -265,6 +279,11 @@ apply_relocation(AOTModule *module, uint8 *target_section_addr,
                 return false;
             }
 
+#if (WASM_MEM_DUAL_BUS_MIRROR != 0)
+            insn_addr = os_get_dbus_mirror((void *)insn_addr);
+            bh_assert(insn_addr != NULL);
+            l32r_insn = (l32r_insn_t *)insn_addr;
+#endif
             imm16 = (int16)(relative_offset >> 2);
 
             /* write back the imm16 to the l32r instruction */
@@ -285,7 +304,6 @@ apply_relocation(AOTModule *module, uint8 *target_section_addr,
 #if __GNUC__ >= 9
 #pragma GCC diagnostic pop
 #endif
-
             break;
         }
 

+ 3 - 9
core/iwasm/common/wasm_exec_env.h

@@ -7,6 +7,7 @@
 #define _WASM_EXEC_ENV_H
 
 #include "bh_assert.h"
+#include "wasm_suspend_flags.h"
 #if WASM_ENABLE_INTERP != 0
 #include "../interpreter/wasm.h"
 #endif
@@ -57,15 +58,8 @@ typedef struct WASMExecEnv {
        exception. */
     uint8 *native_stack_boundary;
 
-    /* Used to terminate or suspend current thread
-        bit 0: need to terminate
-        bit 1: need to suspend
-        bit 2: need to go into breakpoint
-        bit 3: return from pthread_exit */
-    union {
-        uint32 flags;
-        uintptr_t __padding__;
-    } suspend_flags;
+    /* Used to terminate or suspend current thread */
+    WASMSuspendFlags suspend_flags;
 
     /* Auxiliary stack boundary */
     union {

+ 5 - 43
core/iwasm/common/wasm_memory.c

@@ -608,7 +608,7 @@ wasm_enlarge_memory_internal(WASMModuleInstance *module, uint32 inc_page_count)
     }
 
 #if WASM_ENABLE_SHARED_MEMORY != 0
-    if (memory->is_shared) {
+    if (shared_memory_is_shared(memory)) {
         memory->num_bytes_per_page = num_bytes_per_page;
         memory->cur_page_count = total_page_count;
         memory->max_page_count = max_page_count;
@@ -769,52 +769,14 @@ 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);
+    if (module->memory_count > 0)
+        shared_memory_lock(module->memories[0]);
 #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);
+    if (module->memory_count > 0)
+        shared_memory_unlock(module->memories[0]);
 #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

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

@@ -24,16 +24,6 @@ wasm_runtime_memory_destroy();
 unsigned
 wasm_runtime_memory_pool_size();
 
-#if !defined(OS_ENABLE_HW_BOUND_CHECK)              \
-    || WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \
-    || WASM_ENABLE_BULK_MEMORY != 0
-uint32
-wasm_get_num_bytes_per_page(WASMMemoryInstance *memory, void *node);
-
-uint32
-wasm_get_linear_memory_size(WASMMemoryInstance *memory, void *node);
-#endif
-
 #ifdef __cplusplus
 }
 #endif

+ 15 - 18
core/iwasm/common/wasm_runtime_common.c

@@ -1196,7 +1196,8 @@ wasm_runtime_unload(WASMModuleCommon *module)
 }
 
 WASMModuleInstanceCommon *
-wasm_runtime_instantiate_internal(WASMModuleCommon *module, bool is_sub_inst,
+wasm_runtime_instantiate_internal(WASMModuleCommon *module,
+                                  WASMModuleInstanceCommon *parent,
                                   WASMExecEnv *exec_env_main, uint32 stack_size,
                                   uint32 heap_size, char *error_buf,
                                   uint32 error_buf_size)
@@ -1204,14 +1205,14 @@ wasm_runtime_instantiate_internal(WASMModuleCommon *module, bool is_sub_inst,
 #if WASM_ENABLE_INTERP != 0
     if (module->module_type == Wasm_Module_Bytecode)
         return (WASMModuleInstanceCommon *)wasm_instantiate(
-            (WASMModule *)module, is_sub_inst, exec_env_main, stack_size,
-            heap_size, error_buf, error_buf_size);
+            (WASMModule *)module, (WASMModuleInstance *)parent, exec_env_main,
+            stack_size, heap_size, error_buf, error_buf_size);
 #endif
 #if WASM_ENABLE_AOT != 0
     if (module->module_type == Wasm_Module_AoT)
         return (WASMModuleInstanceCommon *)aot_instantiate(
-            (AOTModule *)module, is_sub_inst, exec_env_main, stack_size,
-            heap_size, error_buf, error_buf_size);
+            (AOTModule *)module, (AOTModuleInstance *)parent, exec_env_main,
+            stack_size, heap_size, error_buf, error_buf_size);
 #endif
     set_error_buf(error_buf, error_buf_size,
                   "Instantiate module failed, invalid module type");
@@ -1224,7 +1225,7 @@ wasm_runtime_instantiate(WASMModuleCommon *module, uint32 stack_size,
                          uint32 error_buf_size)
 {
     return wasm_runtime_instantiate_internal(
-        module, false, NULL, stack_size, heap_size, error_buf, error_buf_size);
+        module, NULL, NULL, stack_size, heap_size, error_buf, error_buf_size);
 }
 
 void
@@ -2310,10 +2311,8 @@ wasm_set_exception(WASMModuleInstance *module_inst, const char *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);
+    if (module_inst->memory_count > 0)
+        shared_memory_lock(module_inst->memories[0]);
 #endif
     if (exception) {
         snprintf(module_inst->cur_exception, sizeof(module_inst->cur_exception),
@@ -2323,8 +2322,8 @@ wasm_set_exception(WASMModuleInstance *module_inst, const char *exception)
         module_inst->cur_exception[0] = '\0';
     }
 #if WASM_ENABLE_SHARED_MEMORY != 0
-    if (node)
-        os_mutex_unlock(&node->shared_mem_lock);
+    if (module_inst->memory_count > 0)
+        shared_memory_unlock(module_inst->memories[0]);
 #endif
 
 #if WASM_ENABLE_THREAD_MGR != 0
@@ -2386,10 +2385,8 @@ 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);
+    if (module_inst->memory_count > 0)
+        shared_memory_lock(module_inst->memories[0]);
 #endif
     if (module_inst->cur_exception[0] != '\0') {
         /* NULL is passed if the caller is not interested in getting the
@@ -2403,8 +2400,8 @@ wasm_copy_exception(WASMModuleInstance *module_inst, char *exception_buf)
         has_exception = true;
     }
 #if WASM_ENABLE_SHARED_MEMORY != 0
-    if (node)
-        os_mutex_unlock(&node->shared_mem_lock);
+    if (module_inst->memory_count > 0)
+        shared_memory_unlock(module_inst->memories[0]);
 #endif
 
     return has_exception;

+ 2 - 1
core/iwasm/common/wasm_runtime_common.h

@@ -498,7 +498,8 @@ wasm_runtime_unload(WASMModuleCommon *module);
 
 /* Internal API */
 WASMModuleInstanceCommon *
-wasm_runtime_instantiate_internal(WASMModuleCommon *module, bool is_sub_inst,
+wasm_runtime_instantiate_internal(WASMModuleCommon *module,
+                                  WASMModuleInstanceCommon *parent,
                                   WASMExecEnv *exec_env_main, uint32 stack_size,
                                   uint32 heap_size, char *error_buf,
                                   uint32 error_buf_size);

+ 84 - 113
core/iwasm/common/wasm_shared_memory.c

@@ -9,9 +9,16 @@
 #include "../libraries/thread-mgr/thread_manager.h"
 #endif
 
-static bh_list shared_memory_list_head;
-static bh_list *const shared_memory_list = &shared_memory_list_head;
-static korp_mutex shared_memory_list_lock;
+/*
+ * Note: this lock can be per memory.
+ *
+ * For now, just use a global because:
+ * - it's a bit cumbersome to extend WASMMemoryInstance w/o breaking
+ *   the AOT ABI.
+ * - If you care performance, it's better to make the interpreters
+ *   use atomic ops.
+ */
+static korp_mutex _shared_memory_lock;
 
 /* clang-format off */
 enum {
@@ -48,17 +55,15 @@ destroy_wait_info(void *wait_info);
 bool
 wasm_shared_memory_init()
 {
-    if (os_mutex_init(&shared_memory_list_lock) != 0)
+    if (os_mutex_init(&_shared_memory_lock) != 0)
         return false;
-
     /* wait map not exists, create new map */
     if (!(wait_map = bh_hash_map_create(32, true, (HashFunc)wait_address_hash,
                                         (KeyEqualFunc)wait_address_equal, NULL,
                                         destroy_wait_info))) {
-        os_mutex_destroy(&shared_memory_list_lock);
+        os_mutex_destroy(&_shared_memory_lock);
         return false;
     }
-
     return true;
 }
 
@@ -66,110 +71,79 @@ void
 wasm_shared_memory_destroy()
 {
     bh_hash_map_destroy(wait_map);
-    os_mutex_destroy(&shared_memory_list_lock);
+    os_mutex_destroy(&_shared_memory_lock);
 }
 
-static WASMSharedMemNode *
-search_module(WASMModuleCommon *module)
+uint32
+shared_memory_inc_reference(WASMMemoryInstance *memory)
 {
-    WASMSharedMemNode *node;
-
-    os_mutex_lock(&shared_memory_list_lock);
-    node = bh_list_first_elem(shared_memory_list);
-
-    while (node) {
-        if (module == node->module) {
-            os_mutex_unlock(&shared_memory_list_lock);
-            return node;
-        }
-        node = bh_list_elem_next(node);
-    }
-
-    os_mutex_unlock(&shared_memory_list_lock);
-    return NULL;
+    bh_assert(shared_memory_is_shared(memory));
+    uint32 old;
+#if BH_ATOMIC_32_IS_ATOMIC == 0
+    os_mutex_lock(&_shared_memory_lock);
+#endif
+    old = BH_ATOMIC_32_FETCH_ADD(memory->ref_count, 1);
+#if BH_ATOMIC_32_IS_ATOMIC == 0
+    os_mutex_unlock(&_shared_memory_lock);
+#endif
+    bh_assert(old >= 1);
+    bh_assert(old < UINT32_MAX);
+    return old + 1;
 }
 
-WASMSharedMemNode *
-wasm_module_get_shared_memory(WASMModuleCommon *module)
+uint32
+shared_memory_dec_reference(WASMMemoryInstance *memory)
 {
-    return search_module(module);
+    bh_assert(shared_memory_is_shared(memory));
+    uint32 old;
+#if BH_ATOMIC_32_IS_ATOMIC == 0
+    os_mutex_lock(&_shared_memory_lock);
+#endif
+    old = BH_ATOMIC_32_FETCH_SUB(memory->ref_count, 1);
+#if BH_ATOMIC_32_IS_ATOMIC == 0
+    os_mutex_unlock(&_shared_memory_lock);
+#endif
+    bh_assert(old > 0);
+    return old - 1;
 }
 
-int32
-shared_memory_inc_reference(WASMModuleCommon *module)
+bool
+shared_memory_is_shared(WASMMemoryInstance *memory)
 {
-    WASMSharedMemNode *node = search_module(module);
-    uint32 ref_count = -1;
-    if (node) {
-        os_mutex_lock(&node->lock);
-        ref_count = ++node->ref_count;
-        os_mutex_unlock(&node->lock);
-    }
-    return ref_count;
+    uint32 old;
+#if BH_ATOMIC_32_IS_ATOMIC == 0
+    os_mutex_lock(&_shared_memory_lock);
+#endif
+    old = BH_ATOMIC_32_LOAD(memory->ref_count);
+#if BH_ATOMIC_32_IS_ATOMIC == 0
+    os_mutex_unlock(&_shared_memory_lock);
+#endif
+    return old > 0;
 }
 
-int32
-shared_memory_dec_reference(WASMModuleCommon *module)
+static korp_mutex *
+shared_memory_get_lock_pointer(WASMMemoryInstance *memory)
 {
-    WASMSharedMemNode *node = search_module(module);
-    uint32 ref_count = 0;
-    if (node) {
-        os_mutex_lock(&node->lock);
-        ref_count = --node->ref_count;
-        os_mutex_unlock(&node->lock);
-        if (ref_count == 0) {
-            os_mutex_lock(&shared_memory_list_lock);
-            bh_list_remove(shared_memory_list, node);
-            os_mutex_unlock(&shared_memory_list_lock);
-
-            os_mutex_destroy(&node->shared_mem_lock);
-            os_mutex_destroy(&node->lock);
-            wasm_runtime_free(node);
-        }
-        return ref_count;
-    }
-
-    return -1;
+    bh_assert(memory != NULL);
+    return &_shared_memory_lock;
 }
 
-WASMMemoryInstanceCommon *
-shared_memory_get_memory_inst(WASMSharedMemNode *node)
+void
+shared_memory_lock(WASMMemoryInstance *memory)
 {
-    return node->memory_inst;
+    /*
+     * Note: exception logic is currently abusing this lock.
+     * cf. https://github.com/bytecodealliance/wasm-micro-runtime/issues/2407
+     */
+    bh_assert(memory != NULL);
+    os_mutex_lock(&_shared_memory_lock);
 }
 
-WASMSharedMemNode *
-shared_memory_set_memory_inst(WASMModuleCommon *module,
-                              WASMMemoryInstanceCommon *memory)
+void
+shared_memory_unlock(WASMMemoryInstance *memory)
 {
-    WASMSharedMemNode *node;
-    bh_list_status ret;
-
-    if (!(node = wasm_runtime_malloc(sizeof(WASMSharedMemNode))))
-        return NULL;
-
-    node->module = module;
-    node->memory_inst = memory;
-    node->ref_count = 1;
-
-    if (os_mutex_init(&node->shared_mem_lock) != 0) {
-        wasm_runtime_free(node);
-        return NULL;
-    }
-
-    if (os_mutex_init(&node->lock) != 0) {
-        os_mutex_destroy(&node->shared_mem_lock);
-        wasm_runtime_free(node);
-        return NULL;
-    }
-
-    os_mutex_lock(&shared_memory_list_lock);
-    ret = bh_list_insert(shared_memory_list, node);
-    bh_assert(ret == BH_LIST_SUCCESS);
-    os_mutex_unlock(&shared_memory_list_lock);
-
-    (void)ret;
-    return node;
+    bh_assert(memory != NULL);
+    os_mutex_unlock(&_shared_memory_lock);
 }
 
 /* Atomics wait && notify APIs */
@@ -307,7 +281,7 @@ wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address,
     WASMModuleInstance *module_inst = (WASMModuleInstance *)module;
     AtomicWaitInfo *wait_info;
     AtomicWaitNode *wait_node;
-    WASMSharedMemNode *node;
+    korp_mutex *lock;
 #if WASM_ENABLE_THREAD_MGR != 0
     WASMExecEnv *exec_env;
 #endif
@@ -322,7 +296,7 @@ wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address,
     }
 
     /* Currently we have only one memory instance */
-    if (!module_inst->memories[0]->is_shared) {
+    if (!shared_memory_is_shared(module_inst->memories[0])) {
         wasm_runtime_set_exception(module, "expected shared memory");
         return -1;
     }
@@ -340,30 +314,29 @@ wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address,
     bh_assert(exec_env);
 #endif
 
-    node = search_module((WASMModuleCommon *)module_inst->module);
-    bh_assert(node);
+    lock = shared_memory_get_lock_pointer(module_inst->memories[0]);
 
     /* Lock the shared_mem_lock for the whole atomic wait process,
        and use it to os_cond_reltimedwait */
-    os_mutex_lock(&node->shared_mem_lock);
+    os_mutex_lock(lock);
 
     no_wait = (!wait64 && *(uint32 *)address != (uint32)expect)
               || (wait64 && *(uint64 *)address != expect);
 
     if (no_wait) {
-        os_mutex_unlock(&node->shared_mem_lock);
+        os_mutex_unlock(lock);
         return 1;
     }
 
     if (!(wait_node = wasm_runtime_malloc(sizeof(AtomicWaitNode)))) {
-        os_mutex_unlock(&node->shared_mem_lock);
+        os_mutex_unlock(lock);
         wasm_runtime_set_exception(module, "failed to create wait node");
         return -1;
     }
     memset(wait_node, 0, sizeof(AtomicWaitNode));
 
     if (0 != os_cond_init(&wait_node->wait_cond)) {
-        os_mutex_unlock(&node->shared_mem_lock);
+        os_mutex_unlock(lock);
         wasm_runtime_free(wait_node);
         wasm_runtime_set_exception(module, "failed to init wait cond");
         return -1;
@@ -375,7 +348,7 @@ wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address,
     wait_info = acquire_wait_info(address, wait_node);
 
     if (!wait_info) {
-        os_mutex_unlock(&node->shared_mem_lock);
+        os_mutex_unlock(lock);
         os_cond_destroy(&wait_node->wait_cond);
         wasm_runtime_free(wait_node);
         wasm_runtime_set_exception(module, "failed to acquire wait_info");
@@ -390,7 +363,7 @@ wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address,
         if (timeout < 0) {
             /* wait forever until it is notified or terminatied
                here we keep waiting and checking every second */
-            os_cond_reltimedwait(&wait_node->wait_cond, &node->shared_mem_lock,
+            os_cond_reltimedwait(&wait_node->wait_cond, lock,
                                  (uint64)timeout_1sec);
             if (wait_node->status == S_NOTIFIED /* notified by atomic.notify */
 #if WASM_ENABLE_THREAD_MGR != 0
@@ -404,8 +377,7 @@ wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address,
         else {
             timeout_wait =
                 timeout_left < timeout_1sec ? timeout_left : timeout_1sec;
-            os_cond_reltimedwait(&wait_node->wait_cond, &node->shared_mem_lock,
-                                 timeout_wait);
+            os_cond_reltimedwait(&wait_node->wait_cond, lock, timeout_wait);
             if (wait_node->status == S_NOTIFIED /* notified by atomic.notify */
                 || timeout_left <= timeout_wait /* time out */
 #if WASM_ENABLE_THREAD_MGR != 0
@@ -433,7 +405,7 @@ wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address,
     /* Release wait info if no wait nodes are attached */
     map_try_release_wait_info(wait_map, wait_info, address);
 
-    os_mutex_unlock(&node->shared_mem_lock);
+    os_mutex_unlock(lock);
 
     return is_timeout ? 2 : 0;
 }
@@ -445,7 +417,7 @@ wasm_runtime_atomic_notify(WASMModuleInstanceCommon *module, void *address,
     WASMModuleInstance *module_inst = (WASMModuleInstance *)module;
     uint32 notify_result;
     AtomicWaitInfo *wait_info;
-    WASMSharedMemNode *node;
+    korp_mutex *lock;
     bool out_of_bounds;
 
     bh_assert(module->module_type == Wasm_Module_Bytecode
@@ -461,31 +433,30 @@ wasm_runtime_atomic_notify(WASMModuleInstanceCommon *module, void *address,
     }
 
     /* Currently we have only one memory instance */
-    if (!module_inst->memories[0]->is_shared) {
+    if (!shared_memory_is_shared(module_inst->memories[0])) {
         /* Always return 0 for ushared linear memory since there is
            no way to create a waiter on it */
         return 0;
     }
 
-    node = search_module((WASMModuleCommon *)module_inst->module);
-    bh_assert(node);
+    lock = shared_memory_get_lock_pointer(module_inst->memories[0]);
 
     /* Lock the shared_mem_lock for the whole atomic notify process,
        and use it to os_cond_signal */
-    os_mutex_lock(&node->shared_mem_lock);
+    os_mutex_lock(lock);
 
     wait_info = acquire_wait_info(address, NULL);
 
     /* Nobody wait on this address */
     if (!wait_info) {
-        os_mutex_unlock(&node->shared_mem_lock);
+        os_mutex_unlock(lock);
         return 0;
     }
 
     /* Notify each wait node in the wait list */
     notify_result = notify_wait_list(wait_info->wait_list, count);
 
-    os_mutex_unlock(&node->shared_mem_lock);
+    os_mutex_unlock(lock);
 
     return notify_result;
 }

+ 12 - 32
core/iwasm/common/wasm_shared_memory.h

@@ -7,53 +7,33 @@
 #define _WASM_SHARED_MEMORY_H
 
 #include "bh_common.h"
-#if WASM_ENABLE_INTERP != 0
-#include "wasm_runtime.h"
-#endif
-#if WASM_ENABLE_AOT != 0
-#include "aot_runtime.h"
-#endif
+#include "../interpreter/wasm_runtime.h"
+#include "wasm_runtime_common.h"
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-typedef struct WASMSharedMemNode {
-    bh_list_link l;
-    /* Lock */
-    korp_mutex lock;
-    /* The module reference */
-    WASMModuleCommon *module;
-    /* The memory information */
-    WASMMemoryInstanceCommon *memory_inst;
-    /* Lock used for atomic operations */
-    korp_mutex shared_mem_lock;
-
-    /* reference count */
-    uint32 ref_count;
-} WASMSharedMemNode;
-
 bool
 wasm_shared_memory_init();
 
 void
 wasm_shared_memory_destroy();
 
-WASMSharedMemNode *
-wasm_module_get_shared_memory(WASMModuleCommon *module);
+uint32
+shared_memory_inc_reference(WASMMemoryInstance *memory);
 
-int32
-shared_memory_inc_reference(WASMModuleCommon *module);
+uint32
+shared_memory_dec_reference(WASMMemoryInstance *memory);
 
-int32
-shared_memory_dec_reference(WASMModuleCommon *module);
+bool
+shared_memory_is_shared(WASMMemoryInstance *memory);
 
-WASMMemoryInstanceCommon *
-shared_memory_get_memory_inst(WASMSharedMemNode *node);
+void
+shared_memory_lock(WASMMemoryInstance *memory);
 
-WASMSharedMemNode *
-shared_memory_set_memory_inst(WASMModuleCommon *module,
-                              WASMMemoryInstanceCommon *memory);
+void
+shared_memory_unlock(WASMMemoryInstance *memory);
 
 uint32
 wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address,

+ 48 - 0
core/iwasm/common/wasm_suspend_flags.h

@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2023 Amazon Inc.  All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#ifndef _WASM_SUSPEND_FLAGS_H
+#define _WASM_SUSPEND_FLAGS_H
+
+#include "bh_atomic.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Need to terminate */
+#define WASM_SUSPEND_FLAG_TERMINATE 0x1
+/* Need to suspend */
+#define WASM_SUSPEND_FLAG_SUSPEND 0x2
+/* Need to go into breakpoint */
+#define WASM_SUSPEND_FLAG_BREAKPOINT 0x4
+/* Return from pthread_exit */
+#define WASM_SUSPEND_FLAG_EXIT 0x8
+
+typedef union WASMSuspendFlags {
+    bh_atomic_32_t flags;
+    uintptr_t __padding__;
+} WASMSuspendFlags;
+
+#define WASM_SUSPEND_FLAGS_IS_ATOMIC BH_ATOMIC_32_IS_ATOMIC
+#define WASM_SUSPEND_FLAGS_GET(s_flags) BH_ATOMIC_32_LOAD(s_flags.flags)
+#define WASM_SUSPEND_FLAGS_FETCH_OR(s_flags, val) \
+    BH_ATOMIC_32_FETCH_OR(s_flags.flags, val)
+#define WASM_SUSPEND_FLAGS_FETCH_AND(s_flags, val) \
+    BH_ATOMIC_32_FETCH_AND(s_flags.flags, val)
+
+#if WASM_SUSPEND_FLAGS_IS_ATOMIC != 0
+#define WASM_SUSPEND_FLAGS_LOCK(lock) (void)0
+#define WASM_SUSPEND_FLAGS_UNLOCK(lock) (void)0
+#else /* else of WASM_SUSPEND_FLAGS_IS_ATOMIC */
+#define WASM_SUSPEND_FLAGS_LOCK(lock) os_mutex_lock(&lock)
+#define WASM_SUSPEND_FLAGS_UNLOCK(lock) os_mutex_unlock(&lock);
+#endif /* WASM_SUSPEND_FLAGS_IS_ATOMIC */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* end of _WASM_SUSPEND_FLAGS_H */

+ 2 - 2
core/iwasm/compilation/aot.h

@@ -43,7 +43,7 @@ typedef WASMType AOTFuncType;
 typedef WASMExport AOTExport;
 
 #if WASM_ENABLE_DEBUG_AOT != 0
-typedef void *dwar_extractor_handle_t;
+typedef void *dwarf_extractor_handle_t;
 #endif
 
 typedef enum AOTIntCond {
@@ -285,7 +285,7 @@ typedef struct AOTCompData {
 
     WASMModule *wasm_module;
 #if WASM_ENABLE_DEBUG_AOT != 0
-    dwar_extractor_handle_t extractor;
+    dwarf_extractor_handle_t extractor;
 #endif
 } AOTCompData;
 

+ 1 - 1
core/iwasm/compilation/aot_compiler.c

@@ -2696,7 +2696,7 @@ aot_compile_wasm(AOTCompContext *comp_ctx)
         if (comp_ctx->stack_sizes != NULL) {
             LLVMOrcJITTargetAddress addr;
             if ((err = LLVMOrcLLLazyJITLookup(comp_ctx->orc_jit, &addr,
-                                              aot_stack_sizes_name))) {
+                                              aot_stack_sizes_alias_name))) {
                 aot_handle_llvm_errmsg("failed to look up stack_sizes", err);
                 return false;
             }

+ 40 - 41
core/iwasm/compilation/aot_llvm_extra.cpp

@@ -82,43 +82,40 @@ class ExpandMemoryOpPass : public PassInfoMixin<ExpandMemoryOpPass>
 PreservedAnalyses
 ExpandMemoryOpPass::run(Function &F, FunctionAnalysisManager &AM)
 {
-    Intrinsic::ID ID = F.getIntrinsicID();
-    bool Changed = false;
-
-    for (auto I = F.user_begin(), E = F.user_end(); I != E;) {
-        Instruction *Inst = cast<Instruction>(*I);
-        ++I;
-
-        switch (ID) {
-            case Intrinsic::memcpy:
-            {
-                auto *Memcpy = cast<MemCpyInst>(Inst);
-                Function *ParentFunc = Memcpy->getParent()->getParent();
-                const TargetTransformInfo &TTI =
-                    AM.getResult<TargetIRAnalysis>(*ParentFunc);
-                expandMemCpyAsLoop(Memcpy, TTI);
-                Memcpy->eraseFromParent();
-                Changed = true;
-                break;
+    SmallVector<MemIntrinsic *, 16> MemCalls;
+
+    /* Iterate over all instructions in the function, looking for memcpy,
+     * memmove, and memset.  When we find one, expand it into a loop. */
+
+    for (auto &BB : F) {
+        for (auto &Inst : BB) {
+            if (auto *Memcpy = dyn_cast_or_null<MemCpyInst>(&Inst)) {
+                MemCalls.push_back(Memcpy);
             }
-            case Intrinsic::memmove:
-            {
-                auto *Memmove = cast<MemMoveInst>(Inst);
-                expandMemMoveAsLoop(Memmove);
-                Memmove->eraseFromParent();
-                Changed = true;
-                break;
+            else if (auto *Memmove = dyn_cast_or_null<MemMoveInst>(&Inst)) {
+                MemCalls.push_back(Memmove);
             }
-            case Intrinsic::memset:
-            {
-                auto *Memset = cast<MemSetInst>(Inst);
-                expandMemSetAsLoop(Memset);
-                Memset->eraseFromParent();
-                Changed = true;
-                break;
+            else if (auto *Memset = dyn_cast_or_null<MemSetInst>(&Inst)) {
+                MemCalls.push_back(Memset);
             }
-            default:
-                break;
+        }
+    }
+
+    for (MemIntrinsic *MemCall : MemCalls) {
+        if (MemCpyInst *Memcpy = dyn_cast<MemCpyInst>(MemCall)) {
+            Function *ParentFunc = Memcpy->getParent()->getParent();
+            const TargetTransformInfo &TTI =
+                AM.getResult<TargetIRAnalysis>(*ParentFunc);
+            expandMemCpyAsLoop(Memcpy, TTI);
+            Memcpy->eraseFromParent();
+        }
+        else if (MemMoveInst *Memmove = dyn_cast<MemMoveInst>(MemCall)) {
+            expandMemMoveAsLoop(Memmove);
+            Memmove->eraseFromParent();
+        }
+        else if (MemSetInst *Memset = dyn_cast<MemSetInst>(MemCall)) {
+            expandMemSetAsLoop(Memset);
+            Memset->eraseFromParent();
         }
     }
 
@@ -297,13 +294,6 @@ aot_apply_llvm_new_pass_manager(AOTCompContext *comp_ctx, LLVMModuleRef module)
         FPM.addPass(SLPVectorizerPass());
         FPM.addPass(LoadStoreVectorizerPass());
 
-        /* Run specific passes for AOT indirect mode in last since general
-           optimization may create some intrinsic function calls like
-           llvm.memset, so let's remove these function calls here. */
-        if (comp_ctx->is_indirect_mode) {
-            FPM.addPass(ExpandMemoryOpPass());
-        }
-
         if (comp_ctx->enable_llvm_pgo || comp_ctx->use_prof_file) {
             /* LICM pass: loop invariant code motion, attempting to remove
                as much code from the body of a loop as possible. Experiments
@@ -341,6 +331,15 @@ aot_apply_llvm_new_pass_manager(AOTCompContext *comp_ctx, LLVMModuleRef module)
         else {
             MPM.addPass(PB.buildPerModuleDefaultPipeline(OL));
         }
+
+        /* Run specific passes for AOT indirect mode in last since general
+            optimization may create some intrinsic function calls like
+            llvm.memset, so let's remove these function calls here. */
+        if (comp_ctx->is_indirect_mode) {
+            FunctionPassManager FPM1;
+            FPM1.addPass(ExpandMemoryOpPass());
+            MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM1)));
+        }
     }
 
     MPM.run(*M, MAM);

+ 16 - 16
core/iwasm/compilation/debug/dwarf_extractor.cpp

@@ -28,25 +28,25 @@
 
 using namespace lldb;
 
-typedef struct dwar_extractor {
+typedef struct dwarf_extractor {
     SBDebugger debugger;
     SBTarget target;
     SBModule module;
 
-} dwar_extractor;
+} dwarf_extractor;
 
-#define TO_HANDLE(extractor) (dwar_extractor_handle_t)(extractor)
+#define TO_HANDLE(extractor) (dwarf_extractor_handle_t)(extractor)
 
-#define TO_EXTACTOR(handle) (dwar_extractor *)(handle)
+#define TO_EXTACTOR(handle) (dwarf_extractor *)(handle)
 
 static bool is_debugger_initialized;
 
-dwar_extractor_handle_t
+dwarf_extractor_handle_t
 create_dwarf_extractor(AOTCompData *comp_data, char *file_name)
 {
     char *arch = NULL;
     char *platform = NULL;
-    dwar_extractor *extractor = NULL;
+    dwarf_extractor *extractor = NULL;
 
     //__attribute__((constructor)) may be better?
     if (!is_debugger_initialized) {
@@ -61,7 +61,7 @@ create_dwarf_extractor(AOTCompData *comp_data, char *file_name)
     SBError error;
     SBFileSpec exe_file_spec(file_name, true);
 
-    if (!(extractor = new dwar_extractor())) {
+    if (!(extractor = new dwarf_extractor())) {
         LOG_ERROR("Create Dwarf Extractor error: failed to allocate memory");
         goto fail3;
     }
@@ -101,9 +101,9 @@ fail3:
 }
 
 void
-destroy_dwarf_extractor(dwar_extractor_handle_t handle)
+destroy_dwarf_extractor(dwarf_extractor_handle_t handle)
 {
-    dwar_extractor *extractor = TO_EXTACTOR(handle);
+    dwarf_extractor *extractor = TO_EXTACTOR(handle);
     if (!extractor)
         return;
     extractor->debugger.DeleteTarget(extractor->target);
@@ -116,7 +116,7 @@ destroy_dwarf_extractor(dwar_extractor_handle_t handle)
 LLVMMetadataRef
 dwarf_gen_file_info(const AOTCompContext *comp_ctx)
 {
-    dwar_extractor *extractor;
+    dwarf_extractor *extractor;
     int units_number;
     LLVMMetadataRef file_info = NULL;
     const char *file_name;
@@ -193,7 +193,7 @@ dwarf_gen_mock_vm_info(AOTCompContext *comp_ctx)
 LLVMMetadataRef
 dwarf_gen_comp_unit_info(const AOTCompContext *comp_ctx)
 {
-    dwar_extractor *extractor;
+    dwarf_extractor *extractor;
     int units_number;
     LLVMMetadataRef comp_unit = NULL;
 
@@ -292,7 +292,7 @@ lldb_function_to_function_dbi(const AOTCompContext *comp_ctx,
     SBTypeList function_args = function.GetType().GetFunctionArgumentTypes();
     SBType return_type = function.GetType().GetFunctionReturnType();
     const size_t num_function_args = function_args.GetSize();
-    dwar_extractor *extractor;
+    dwarf_extractor *extractor;
 
     if (!(extractor = TO_EXTACTOR(comp_ctx->comp_data->extractor)))
         return NULL;
@@ -393,7 +393,7 @@ dwarf_gen_func_info(const AOTCompContext *comp_ctx,
                     const AOTFuncContext *func_ctx)
 {
     LLVMMetadataRef func_info = NULL;
-    dwar_extractor *extractor;
+    dwarf_extractor *extractor;
     uint64_t vm_offset;
     AOTFunc *func = func_ctx->aot_func;
 
@@ -423,7 +423,7 @@ dwarf_get_func_name(const AOTCompContext *comp_ctx,
                     const AOTFuncContext *func_ctx, char *name, int len)
 {
     LLVMMetadataRef func_info = NULL;
-    dwar_extractor *extractor;
+    dwarf_extractor *extractor;
     uint64_t vm_offset;
     AOTFunc *func = func_ctx->aot_func;
 
@@ -454,7 +454,7 @@ dwarf_gen_location(const AOTCompContext *comp_ctx,
                    const AOTFuncContext *func_ctx, uint64_t vm_offset)
 {
     LLVMMetadataRef location_info = NULL;
-    dwar_extractor *extractor;
+    dwarf_extractor *extractor;
     AOTFunc *func = func_ctx->aot_func;
 
     if (!(extractor = TO_EXTACTOR(comp_ctx->comp_data->extractor)))
@@ -493,7 +493,7 @@ dwarf_gen_func_ret_location(const AOTCompContext *comp_ctx,
                             const AOTFuncContext *func_ctx)
 {
     LLVMMetadataRef func_info = NULL;
-    dwar_extractor *extractor;
+    dwarf_extractor *extractor;
     uint64_t vm_offset;
     AOTFunc *func = func_ctx->aot_func;
     LLVMMetadataRef location_info = NULL;

+ 2 - 2
core/iwasm/compilation/debug/dwarf_extractor.h

@@ -18,7 +18,7 @@ typedef unsigned int LLDBLangType;
 
 struct AOTCompData;
 typedef struct AOTCompData *aot_comp_data_t;
-typedef void *dwar_extractor_handle_t;
+typedef void *dwarf_extractor_handle_t;
 
 struct AOTCompContext;
 typedef struct AOTCompContext AOTCompContext;
@@ -26,7 +26,7 @@ typedef struct AOTCompContext AOTCompContext;
 struct AOTFuncContext;
 
 typedef struct AOTFuncContext AOTFuncContext;
-dwar_extractor_handle_t
+dwarf_extractor_handle_t
 create_dwarf_extractor(aot_comp_data_t comp_data, char *file_name);
 
 LLVMMetadataRef

+ 21 - 20
core/iwasm/fast-jit/fe/jit_emit_table.c

@@ -88,27 +88,28 @@ fail:
 
 static int
 wasm_init_table(WASMModuleInstance *inst, uint32 tbl_idx, uint32 elem_idx,
-                uint32 dst, uint32 len, uint32 src)
+                uint32 dst_offset, uint32 len, uint32 src_offset)
 {
     WASMTableInstance *tbl;
     uint32 tbl_sz;
     WASMTableSeg *elem;
     uint32 elem_len;
 
-    tbl = inst->tables[tbl_idx];
-    tbl_sz = tbl->cur_size;
-    if (dst > tbl_sz || tbl_sz - dst < len)
-        goto out_of_bounds;
-
     elem = inst->module->table_segments + elem_idx;
     elem_len = elem->function_count;
-    if (src > elem_len || elem_len - src < len)
+    if (offset_len_out_of_bounds(src_offset, len, elem_len))
+        goto out_of_bounds;
+
+    tbl = inst->tables[tbl_idx];
+    tbl_sz = tbl->cur_size;
+    if (offset_len_out_of_bounds(dst_offset, len, tbl_sz))
         goto out_of_bounds;
 
     bh_memcpy_s((uint8 *)tbl + offsetof(WASMTableInstance, elems)
-                    + dst * sizeof(uint32),
-                (uint32)((tbl_sz - dst) * sizeof(uint32)),
-                elem->func_indexes + src, (uint32)(len * sizeof(uint32)));
+                    + dst_offset * sizeof(uint32),
+                (uint32)((tbl_sz - dst_offset) * sizeof(uint32)),
+                elem->func_indexes + src_offset,
+                (uint32)(len * sizeof(uint32)));
 
     return 0;
 out_of_bounds:
@@ -157,14 +158,14 @@ wasm_copy_table(WASMModuleInstance *inst, uint32 src_tbl_idx,
     WASMTableInstance *src_tbl, *dst_tbl;
     uint32 src_tbl_sz, dst_tbl_sz;
 
-    src_tbl = inst->tables[src_tbl_idx];
-    src_tbl_sz = src_tbl->cur_size;
-    if (src_offset > src_tbl_sz || src_tbl_sz - src_offset < len)
-        goto out_of_bounds;
-
     dst_tbl = inst->tables[dst_tbl_idx];
     dst_tbl_sz = dst_tbl->cur_size;
-    if (dst_offset > dst_tbl_sz || dst_tbl_sz - dst_offset < len)
+    if (offset_len_out_of_bounds(dst_offset, len, dst_tbl_sz))
+        goto out_of_bounds;
+
+    src_tbl = inst->tables[src_tbl_idx];
+    src_tbl_sz = src_tbl->cur_size;
+    if (offset_len_out_of_bounds(src_offset, len, src_tbl_sz))
         goto out_of_bounds;
 
     bh_memmove_s((uint8 *)dst_tbl + offsetof(WASMTableInstance, elems)
@@ -263,7 +264,7 @@ fail:
 }
 
 static int
-wasm_fill_table(WASMModuleInstance *inst, uint32 tbl_idx, uint32 dst,
+wasm_fill_table(WASMModuleInstance *inst, uint32 tbl_idx, uint32 dst_offset,
                 uint32 val, uint32 len)
 {
     WASMTableInstance *tbl;
@@ -272,11 +273,11 @@ wasm_fill_table(WASMModuleInstance *inst, uint32 tbl_idx, uint32 dst,
     tbl = inst->tables[tbl_idx];
     tbl_sz = tbl->cur_size;
 
-    if (dst > tbl_sz || tbl_sz - dst < len)
+    if (offset_len_out_of_bounds(dst_offset, len, tbl_sz))
         goto out_of_bounds;
 
-    for (; len != 0; dst++, len--) {
-        tbl->elems[dst] = val;
+    for (; len != 0; dst_offset++, len--) {
+        tbl->elems[dst_offset] = val;
     }
 
     return 0;

+ 2 - 2
core/iwasm/include/aot_export.h

@@ -26,8 +26,8 @@ void
 aot_destroy_comp_data(aot_comp_data_t comp_data);
 
 #if WASM_ENABLE_DEBUG_AOT != 0
-typedef void *dwar_extractor_handle_t;
-dwar_extractor_handle_t
+typedef void *dwarf_extractor_handle_t;
+dwarf_extractor_handle_t
 create_dwarf_extractor(aot_comp_data_t comp_data, char *file_name);
 #endif
 

+ 18 - 1
core/iwasm/interpreter/wasm.h

@@ -627,7 +627,6 @@ typedef struct WASMBranchBlock {
     uint32 cell_num;
 } WASMBranchBlock;
 
-/* Execution environment, e.g. stack info */
 /**
  * Align an unsigned value on a alignment boundary.
  *
@@ -643,6 +642,24 @@ align_uint(unsigned v, unsigned b)
     return (v + m) & ~m;
 }
 
+/**
+ * Check whether a piece of data is out of range
+ *
+ * @param offset the offset that the data starts
+ * @param len the length of the data
+ * @param max_size the maximum size of the data range
+ *
+ * @return true if out of range, false otherwise
+ */
+inline static bool
+offset_len_out_of_bounds(uint32 offset, uint32 len, uint32 max_size)
+{
+    if (offset + len < offset /* integer overflow */
+        || offset + len > max_size)
+        return true;
+    return false;
+}
+
 /**
  * Return the hash value of c string.
  */

+ 103 - 94
core/iwasm/interpreter/wasm_interp_classic.c

@@ -710,28 +710,28 @@ trunc_f64_to_int(WASMModuleInstance *module, uint32 *frame_sp, float64 src_min,
             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);     \
             CHECK_ATOMIC_MEMORY_ACCESS();                            \
                                                                      \
-            os_mutex_lock(&node->shared_mem_lock);                   \
+            shared_memory_lock(memory);                              \
             readv = (uint32)(*(uint8 *)maddr);                       \
             *(uint8 *)maddr = (uint8)(readv op sval);                \
-            os_mutex_unlock(&node->shared_mem_lock);                 \
+            shared_memory_unlock(memory);                            \
         }                                                            \
         else if (opcode == WASM_OP_ATOMIC_RMW_I32_##OP_NAME##16_U) { \
             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);     \
             CHECK_ATOMIC_MEMORY_ACCESS();                            \
                                                                      \
-            os_mutex_lock(&node->shared_mem_lock);                   \
+            shared_memory_lock(memory);                              \
             readv = (uint32)LOAD_U16(maddr);                         \
             STORE_U16(maddr, (uint16)(readv op sval));               \
-            os_mutex_unlock(&node->shared_mem_lock);                 \
+            shared_memory_unlock(memory);                            \
         }                                                            \
         else {                                                       \
             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);     \
             CHECK_ATOMIC_MEMORY_ACCESS();                            \
                                                                      \
-            os_mutex_lock(&node->shared_mem_lock);                   \
+            shared_memory_lock(memory);                              \
             readv = LOAD_I32(maddr);                                 \
             STORE_U32(maddr, readv op sval);                         \
-            os_mutex_unlock(&node->shared_mem_lock);                 \
+            shared_memory_unlock(memory);                            \
         }                                                            \
         PUSH_I32(readv);                                             \
         break;                                                       \
@@ -750,39 +750,39 @@ trunc_f64_to_int(WASMModuleInstance *module, uint32 *frame_sp, float64 src_min,
             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);     \
             CHECK_ATOMIC_MEMORY_ACCESS();                            \
                                                                      \
-            os_mutex_lock(&node->shared_mem_lock);                   \
+            shared_memory_lock(memory);                              \
             readv = (uint64)(*(uint8 *)maddr);                       \
             *(uint8 *)maddr = (uint8)(readv op sval);                \
-            os_mutex_unlock(&node->shared_mem_lock);                 \
+            shared_memory_unlock(memory);                            \
         }                                                            \
         else if (opcode == WASM_OP_ATOMIC_RMW_I64_##OP_NAME##16_U) { \
             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);     \
             CHECK_ATOMIC_MEMORY_ACCESS();                            \
                                                                      \
-            os_mutex_lock(&node->shared_mem_lock);                   \
+            shared_memory_lock(memory);                              \
             readv = (uint64)LOAD_U16(maddr);                         \
             STORE_U16(maddr, (uint16)(readv op sval));               \
-            os_mutex_unlock(&node->shared_mem_lock);                 \
+            shared_memory_unlock(memory);                            \
         }                                                            \
         else if (opcode == WASM_OP_ATOMIC_RMW_I64_##OP_NAME##32_U) { \
             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);     \
             CHECK_ATOMIC_MEMORY_ACCESS();                            \
                                                                      \
-            os_mutex_lock(&node->shared_mem_lock);                   \
+            shared_memory_lock(memory);                              \
             readv = (uint64)LOAD_U32(maddr);                         \
             STORE_U32(maddr, (uint32)(readv op sval));               \
-            os_mutex_unlock(&node->shared_mem_lock);                 \
+            shared_memory_unlock(memory);                            \
         }                                                            \
         else {                                                       \
             uint64 op_result;                                        \
             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr);     \
             CHECK_ATOMIC_MEMORY_ACCESS();                            \
                                                                      \
-            os_mutex_lock(&node->shared_mem_lock);                   \
+            shared_memory_lock(memory);                              \
             readv = (uint64)LOAD_I64(maddr);                         \
             op_result = readv op sval;                               \
             STORE_I64(maddr, op_result);                             \
-            os_mutex_unlock(&node->shared_mem_lock);                 \
+            shared_memory_unlock(memory);                            \
         }                                                            \
         PUSH_I64(readv);                                             \
         break;                                                       \
@@ -1062,21 +1062,33 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst,
         os_mutex_unlock(&exec_env->wait_lock);                         \
     } while (0)
 #else
-#define CHECK_SUSPEND_FLAGS()                                             \
-    do {                                                                  \
-        os_mutex_lock(&exec_env->wait_lock);                              \
-        if (exec_env->suspend_flags.flags != 0) {                         \
-            if (exec_env->suspend_flags.flags & 0x01) {                   \
-                /* terminate current thread */                            \
-                os_mutex_unlock(&exec_env->wait_lock);                    \
-                return;                                                   \
-            }                                                             \
-            while (exec_env->suspend_flags.flags & 0x02) {                \
-                /* suspend current thread */                              \
-                os_cond_wait(&exec_env->wait_cond, &exec_env->wait_lock); \
-            }                                                             \
-        }                                                                 \
-        os_mutex_unlock(&exec_env->wait_lock);                            \
+#if WASM_SUSPEND_FLAGS_IS_ATOMIC != 0
+/* The lock is only needed when the suspend_flags is atomic; otherwise
+   the lock is already taken at the time when SUSPENSION_LOCK() is called. */
+#define SUSPENSION_LOCK() os_mutex_lock(&exec_env->wait_lock);
+#define SUSPENSION_UNLOCK() os_mutex_unlock(&exec_env->wait_lock);
+#else
+#define SUSPENSION_LOCK()
+#define SUSPENSION_UNLOCK()
+#endif
+
+#define CHECK_SUSPEND_FLAGS()                                         \
+    do {                                                              \
+        WASM_SUSPEND_FLAGS_LOCK(exec_env->wait_lock);                 \
+        if (WASM_SUSPEND_FLAGS_GET(exec_env->suspend_flags)           \
+            & WASM_SUSPEND_FLAG_TERMINATE) {                          \
+            /* terminate current thread */                            \
+            WASM_SUSPEND_FLAGS_UNLOCK(exec_env->wait_lock);           \
+            return;                                                   \
+        }                                                             \
+        while (WASM_SUSPEND_FLAGS_GET(exec_env->suspend_flags)        \
+               & WASM_SUSPEND_FLAG_SUSPEND) {                         \
+            /* suspend current thread */                              \
+            SUSPENSION_LOCK()                                         \
+            os_cond_wait(&exec_env->wait_cond, &exec_env->wait_lock); \
+            SUSPENSION_UNLOCK()                                       \
+        }                                                             \
+        WASM_SUSPEND_FLAGS_UNLOCK(exec_env->wait_lock);               \
     } while (0)
 #endif /* WASM_ENABLE_DEBUG_INTERP */
 #endif /* WASM_ENABLE_THREAD_MGR */
@@ -1144,10 +1156,6 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                                WASMFunctionInstance *cur_func,
                                WASMInterpFrame *prev_frame)
 {
-#if WASM_ENABLE_SHARED_MEMORY != 0
-    WASMSharedMemNode *node =
-        wasm_module_get_shared_memory((WASMModuleCommon *)module->module);
-#endif
     WASMMemoryInstance *memory = wasm_get_default_memory(module);
 #if !defined(OS_ENABLE_HW_BOUND_CHECK)              \
     || WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \
@@ -3235,7 +3243,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                     case WASM_OP_TABLE_INIT:
                     {
                         uint32 tbl_idx, elem_idx;
-                        uint64 n, s, d;
+                        uint32 n, s, d;
                         WASMTableInstance *tbl_inst;
 
                         read_leb_uint32(frame_ip, frame_ip_end, elem_idx);
@@ -3250,20 +3258,21 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                         s = (uint32)POP_I32();
                         d = (uint32)POP_I32();
 
-                        /* TODO: what if the element is not passive? */
-
-                        if (!n) {
-                            break;
-                        }
-
-                        if (n + s > module->module->table_segments[elem_idx]
-                                        .function_count
-                            || d + n > tbl_inst->cur_size) {
+                        if (offset_len_out_of_bounds(
+                                s, n,
+                                module->module->table_segments[elem_idx]
+                                    .function_count)
+                            || offset_len_out_of_bounds(d, n,
+                                                        tbl_inst->cur_size)) {
                             wasm_set_exception(module,
                                                "out of bounds table access");
                             goto got_exception;
                         }
 
+                        if (!n) {
+                            break;
+                        }
+
                         if (module->module->table_segments[elem_idx]
                                 .is_dropped) {
                             wasm_set_exception(module,
@@ -3304,7 +3313,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                     case WASM_OP_TABLE_COPY:
                     {
                         uint32 src_tbl_idx, dst_tbl_idx;
-                        uint64 n, s, d;
+                        uint32 n, s, d;
                         WASMTableInstance *src_tbl_inst, *dst_tbl_inst;
 
                         read_leb_uint32(frame_ip, frame_ip_end, dst_tbl_idx);
@@ -3321,8 +3330,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                         s = (uint32)POP_I32();
                         d = (uint32)POP_I32();
 
-                        if (d + n > dst_tbl_inst->cur_size
-                            || s + n > src_tbl_inst->cur_size) {
+                        if (offset_len_out_of_bounds(d, n,
+                                                     dst_tbl_inst->cur_size)
+                            || offset_len_out_of_bounds(
+                                s, n, src_tbl_inst->cur_size)) {
                             wasm_set_exception(module,
                                                "out of bounds table access");
                             goto got_exception;
@@ -3392,11 +3403,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                         fill_val = POP_I32();
                         i = POP_I32();
 
-                        /* TODO: what if the element is not passive? */
-                        /* TODO: what if the element is dropped? */
-
-                        if (i + n > tbl_inst->cur_size) {
-                            /* TODO: verify warning content */
+                        if (offset_len_out_of_bounds(i, n,
+                                                     tbl_inst->cur_size)) {
                             wasm_set_exception(module,
                                                "out of bounds table access");
                             goto got_exception;
@@ -3514,23 +3522,23 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                         if (opcode == WASM_OP_ATOMIC_I32_LOAD8_U) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS();
-                            os_mutex_lock(&node->shared_mem_lock);
+                            shared_memory_lock(memory);
                             readv = (uint32)(*(uint8 *)maddr);
-                            os_mutex_unlock(&node->shared_mem_lock);
+                            shared_memory_unlock(memory);
                         }
                         else if (opcode == WASM_OP_ATOMIC_I32_LOAD16_U) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS();
-                            os_mutex_lock(&node->shared_mem_lock);
+                            shared_memory_lock(memory);
                             readv = (uint32)LOAD_U16(maddr);
-                            os_mutex_unlock(&node->shared_mem_lock);
+                            shared_memory_unlock(memory);
                         }
                         else {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS();
-                            os_mutex_lock(&node->shared_mem_lock);
+                            shared_memory_lock(memory);
                             readv = LOAD_I32(maddr);
-                            os_mutex_unlock(&node->shared_mem_lock);
+                            shared_memory_unlock(memory);
                         }
 
                         PUSH_I32(readv);
@@ -3549,30 +3557,30 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                         if (opcode == WASM_OP_ATOMIC_I64_LOAD8_U) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS();
-                            os_mutex_lock(&node->shared_mem_lock);
+                            shared_memory_lock(memory);
                             readv = (uint64)(*(uint8 *)maddr);
-                            os_mutex_unlock(&node->shared_mem_lock);
+                            shared_memory_unlock(memory);
                         }
                         else if (opcode == WASM_OP_ATOMIC_I64_LOAD16_U) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS();
-                            os_mutex_lock(&node->shared_mem_lock);
+                            shared_memory_lock(memory);
                             readv = (uint64)LOAD_U16(maddr);
-                            os_mutex_unlock(&node->shared_mem_lock);
+                            shared_memory_unlock(memory);
                         }
                         else if (opcode == WASM_OP_ATOMIC_I64_LOAD32_U) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS();
-                            os_mutex_lock(&node->shared_mem_lock);
+                            shared_memory_lock(memory);
                             readv = (uint64)LOAD_U32(maddr);
-                            os_mutex_unlock(&node->shared_mem_lock);
+                            shared_memory_unlock(memory);
                         }
                         else {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS();
-                            os_mutex_lock(&node->shared_mem_lock);
+                            shared_memory_lock(memory);
                             readv = LOAD_I64(maddr);
-                            os_mutex_unlock(&node->shared_mem_lock);
+                            shared_memory_unlock(memory);
                         }
 
                         PUSH_I64(readv);
@@ -3591,23 +3599,23 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                         if (opcode == WASM_OP_ATOMIC_I32_STORE8) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS();
-                            os_mutex_lock(&node->shared_mem_lock);
+                            shared_memory_lock(memory);
                             *(uint8 *)maddr = (uint8)sval;
-                            os_mutex_unlock(&node->shared_mem_lock);
+                            shared_memory_unlock(memory);
                         }
                         else if (opcode == WASM_OP_ATOMIC_I32_STORE16) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS();
-                            os_mutex_lock(&node->shared_mem_lock);
+                            shared_memory_lock(memory);
                             STORE_U16(maddr, (uint16)sval);
-                            os_mutex_unlock(&node->shared_mem_lock);
+                            shared_memory_unlock(memory);
                         }
                         else {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS();
-                            os_mutex_lock(&node->shared_mem_lock);
+                            shared_memory_lock(memory);
                             STORE_U32(maddr, sval);
-                            os_mutex_unlock(&node->shared_mem_lock);
+                            shared_memory_unlock(memory);
                         }
                         break;
                     }
@@ -3625,30 +3633,30 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                         if (opcode == WASM_OP_ATOMIC_I64_STORE8) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS();
-                            os_mutex_lock(&node->shared_mem_lock);
+                            shared_memory_lock(memory);
                             *(uint8 *)maddr = (uint8)sval;
-                            os_mutex_unlock(&node->shared_mem_lock);
+                            shared_memory_unlock(memory);
                         }
                         else if (opcode == WASM_OP_ATOMIC_I64_STORE16) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS();
-                            os_mutex_lock(&node->shared_mem_lock);
+                            shared_memory_lock(memory);
                             STORE_U16(maddr, (uint16)sval);
-                            os_mutex_unlock(&node->shared_mem_lock);
+                            shared_memory_unlock(memory);
                         }
                         else if (opcode == WASM_OP_ATOMIC_I64_STORE32) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS();
-                            os_mutex_lock(&node->shared_mem_lock);
+                            shared_memory_lock(memory);
                             STORE_U32(maddr, (uint32)sval);
-                            os_mutex_unlock(&node->shared_mem_lock);
+                            shared_memory_unlock(memory);
                         }
                         else {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS();
-                            os_mutex_lock(&node->shared_mem_lock);
+                            shared_memory_lock(memory);
                             PUT_I64_TO_ADDR((uint32 *)maddr, sval);
-                            os_mutex_unlock(&node->shared_mem_lock);
+                            shared_memory_unlock(memory);
                         }
                         break;
                     }
@@ -3668,32 +3676,32 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                             CHECK_ATOMIC_MEMORY_ACCESS();
 
                             expect = (uint8)expect;
-                            os_mutex_lock(&node->shared_mem_lock);
+                            shared_memory_lock(memory);
                             readv = (uint32)(*(uint8 *)maddr);
                             if (readv == expect)
                                 *(uint8 *)maddr = (uint8)(sval);
-                            os_mutex_unlock(&node->shared_mem_lock);
+                            shared_memory_unlock(memory);
                         }
                         else if (opcode == WASM_OP_ATOMIC_RMW_I32_CMPXCHG16_U) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS();
 
                             expect = (uint16)expect;
-                            os_mutex_lock(&node->shared_mem_lock);
+                            shared_memory_lock(memory);
                             readv = (uint32)LOAD_U16(maddr);
                             if (readv == expect)
                                 STORE_U16(maddr, (uint16)(sval));
-                            os_mutex_unlock(&node->shared_mem_lock);
+                            shared_memory_unlock(memory);
                         }
                         else {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS();
 
-                            os_mutex_lock(&node->shared_mem_lock);
+                            shared_memory_lock(memory);
                             readv = LOAD_I32(maddr);
                             if (readv == expect)
                                 STORE_U32(maddr, sval);
-                            os_mutex_unlock(&node->shared_mem_lock);
+                            shared_memory_unlock(memory);
                         }
                         PUSH_I32(readv);
                         break;
@@ -3714,43 +3722,43 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                             CHECK_ATOMIC_MEMORY_ACCESS();
 
                             expect = (uint8)expect;
-                            os_mutex_lock(&node->shared_mem_lock);
+                            shared_memory_lock(memory);
                             readv = (uint64)(*(uint8 *)maddr);
                             if (readv == expect)
                                 *(uint8 *)maddr = (uint8)(sval);
-                            os_mutex_unlock(&node->shared_mem_lock);
+                            shared_memory_unlock(memory);
                         }
                         else if (opcode == WASM_OP_ATOMIC_RMW_I64_CMPXCHG16_U) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS();
 
                             expect = (uint16)expect;
-                            os_mutex_lock(&node->shared_mem_lock);
+                            shared_memory_lock(memory);
                             readv = (uint64)LOAD_U16(maddr);
                             if (readv == expect)
                                 STORE_U16(maddr, (uint16)(sval));
-                            os_mutex_unlock(&node->shared_mem_lock);
+                            shared_memory_unlock(memory);
                         }
                         else if (opcode == WASM_OP_ATOMIC_RMW_I64_CMPXCHG32_U) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS();
 
                             expect = (uint32)expect;
-                            os_mutex_lock(&node->shared_mem_lock);
+                            shared_memory_lock(memory);
                             readv = (uint64)LOAD_U32(maddr);
                             if (readv == expect)
                                 STORE_U32(maddr, (uint32)(sval));
-                            os_mutex_unlock(&node->shared_mem_lock);
+                            shared_memory_unlock(memory);
                         }
                         else {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS();
 
-                            os_mutex_lock(&node->shared_mem_lock);
+                            shared_memory_lock(memory);
                             readv = (uint64)LOAD_I64(maddr);
                             if (readv == expect)
                                 STORE_I64(maddr, sval);
-                            os_mutex_unlock(&node->shared_mem_lock);
+                            shared_memory_unlock(memory);
                         }
                         PUSH_I64(readv);
                         break;
@@ -3783,7 +3791,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
             HANDLE_OP(DEBUG_OP_BREAK)
             {
                 wasm_cluster_thread_send_signal(exec_env, WAMR_SIG_TRAP);
-                exec_env->suspend_flags.flags |= 2;
+                WASM_SUSPEND_FLAGS_FETCH_OR(exec_env->suspend_flags,
+                                            WASM_SUSPEND_FLAG_SUSPEND);
                 frame_ip--;
                 SYNC_ALL_TO_FRAME();
                 CHECK_SUSPEND_FLAGS();

+ 85 - 84
core/iwasm/interpreter/wasm_interp_fast.c

@@ -482,28 +482,28 @@ LOAD_PTR(void *addr)
             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);     \
             CHECK_ATOMIC_MEMORY_ACCESS(1);                           \
                                                                      \
-            os_mutex_lock(&node->shared_mem_lock);                   \
+            shared_memory_lock(memory);                              \
             readv = (uint32)(*(uint8 *)maddr);                       \
             *(uint8 *)maddr = (uint8)(readv op sval);                \
-            os_mutex_unlock(&node->shared_mem_lock);                 \
+            shared_memory_unlock(memory);                            \
         }                                                            \
         else if (opcode == WASM_OP_ATOMIC_RMW_I32_##OP_NAME##16_U) { \
             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);     \
             CHECK_ATOMIC_MEMORY_ACCESS(2);                           \
                                                                      \
-            os_mutex_lock(&node->shared_mem_lock);                   \
+            shared_memory_lock(memory);                              \
             readv = (uint32)LOAD_U16(maddr);                         \
             STORE_U16(maddr, (uint16)(readv op sval));               \
-            os_mutex_unlock(&node->shared_mem_lock);                 \
+            shared_memory_unlock(memory);                            \
         }                                                            \
         else {                                                       \
             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);     \
             CHECK_ATOMIC_MEMORY_ACCESS(4);                           \
                                                                      \
-            os_mutex_lock(&node->shared_mem_lock);                   \
+            shared_memory_lock(memory);                              \
             readv = LOAD_I32(maddr);                                 \
             STORE_U32(maddr, readv op sval);                         \
-            os_mutex_unlock(&node->shared_mem_lock);                 \
+            shared_memory_unlock(memory);                            \
         }                                                            \
         PUSH_I32(readv);                                             \
         break;                                                       \
@@ -522,39 +522,39 @@ LOAD_PTR(void *addr)
             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);     \
             CHECK_ATOMIC_MEMORY_ACCESS(1);                           \
                                                                      \
-            os_mutex_lock(&node->shared_mem_lock);                   \
+            shared_memory_lock(memory);                              \
             readv = (uint64)(*(uint8 *)maddr);                       \
             *(uint8 *)maddr = (uint8)(readv op sval);                \
-            os_mutex_unlock(&node->shared_mem_lock);                 \
+            shared_memory_unlock(memory);                            \
         }                                                            \
         else if (opcode == WASM_OP_ATOMIC_RMW_I64_##OP_NAME##16_U) { \
             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);     \
             CHECK_ATOMIC_MEMORY_ACCESS(2);                           \
                                                                      \
-            os_mutex_lock(&node->shared_mem_lock);                   \
+            shared_memory_lock(memory);                              \
             readv = (uint64)LOAD_U16(maddr);                         \
             STORE_U16(maddr, (uint16)(readv op sval));               \
-            os_mutex_unlock(&node->shared_mem_lock);                 \
+            shared_memory_unlock(memory);                            \
         }                                                            \
         else if (opcode == WASM_OP_ATOMIC_RMW_I64_##OP_NAME##32_U) { \
             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);     \
             CHECK_ATOMIC_MEMORY_ACCESS(4);                           \
                                                                      \
-            os_mutex_lock(&node->shared_mem_lock);                   \
+            shared_memory_lock(memory);                              \
             readv = (uint64)LOAD_U32(maddr);                         \
             STORE_U32(maddr, (uint32)(readv op sval));               \
-            os_mutex_unlock(&node->shared_mem_lock);                 \
+            shared_memory_unlock(memory);                            \
         }                                                            \
         else {                                                       \
             uint64 op_result;                                        \
             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr);     \
             CHECK_ATOMIC_MEMORY_ACCESS(8);                           \
                                                                      \
-            os_mutex_lock(&node->shared_mem_lock);                   \
+            shared_memory_lock(memory);                              \
             readv = (uint64)LOAD_I64(maddr);                         \
             op_result = readv op sval;                               \
             STORE_I64(maddr, op_result);                             \
-            os_mutex_unlock(&node->shared_mem_lock);                 \
+            shared_memory_unlock(memory);                            \
         }                                                            \
         PUSH_I64(readv);                                             \
         break;                                                       \
@@ -1065,18 +1065,17 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst,
 #endif
 
 #if WASM_ENABLE_THREAD_MGR != 0
-#define CHECK_SUSPEND_FLAGS()                           \
-    do {                                                \
-        os_mutex_lock(&exec_env->wait_lock);            \
-        if (exec_env->suspend_flags.flags != 0) {       \
-            if (exec_env->suspend_flags.flags & 0x01) { \
-                /* terminate current thread */          \
-                os_mutex_unlock(&exec_env->wait_lock);  \
-                return;                                 \
-            }                                           \
-            /* TODO: support suspend and breakpoint */  \
-        }                                               \
-        os_mutex_unlock(&exec_env->wait_lock);          \
+#define CHECK_SUSPEND_FLAGS()                               \
+    do {                                                    \
+        WASM_SUSPEND_FLAGS_LOCK(exec_env->wait_lock);       \
+        if (WASM_SUSPEND_FLAGS_GET(exec_env->suspend_flags) \
+            & WASM_SUSPEND_FLAG_TERMINATE) {                \
+            /* terminate current thread */                  \
+            WASM_SUSPEND_FLAGS_UNLOCK(exec_env->wait_lock); \
+            return;                                         \
+        }                                                   \
+        /* TODO: support suspend and breakpoint */          \
+        WASM_SUSPEND_FLAGS_UNLOCK(exec_env->wait_lock);     \
     } while (0)
 #endif
 
@@ -1167,10 +1166,6 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                                WASMFunctionInstance *cur_func,
                                WASMInterpFrame *prev_frame)
 {
-#if WASM_ENABLE_SHARED_MEMORY != 0
-    WASMSharedMemNode *node =
-        wasm_module_get_shared_memory((WASMModuleCommon *)module->module);
-#endif
     WASMMemoryInstance *memory = wasm_get_default_memory(module);
 #if !defined(OS_ENABLE_HW_BOUND_CHECK)              \
     || WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \
@@ -3079,7 +3074,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                     case WASM_OP_TABLE_INIT:
                     {
                         uint32 tbl_idx, elem_idx;
-                        uint64 n, s, d;
+                        uint32 n, s, d;
                         WASMTableInstance *tbl_inst;
 
                         elem_idx = read_uint32(frame_ip);
@@ -3094,18 +3089,21 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                         s = (uint32)POP_I32();
                         d = (uint32)POP_I32();
 
-                        if (!n) {
-                            break;
-                        }
-
-                        if (n + s > module->module->table_segments[elem_idx]
-                                        .function_count
-                            || d + n > tbl_inst->cur_size) {
+                        if (offset_len_out_of_bounds(
+                                s, n,
+                                module->module->table_segments[elem_idx]
+                                    .function_count)
+                            || offset_len_out_of_bounds(d, n,
+                                                        tbl_inst->cur_size)) {
                             wasm_set_exception(module,
                                                "out of bounds table access");
                             goto got_exception;
                         }
 
+                        if (!n) {
+                            break;
+                        }
+
                         if (module->module->table_segments[elem_idx]
                                 .is_dropped) {
                             wasm_set_exception(module,
@@ -3144,7 +3142,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                     case WASM_OP_TABLE_COPY:
                     {
                         uint32 src_tbl_idx, dst_tbl_idx;
-                        uint64 n, s, d;
+                        uint32 n, s, d;
                         WASMTableInstance *src_tbl_inst, *dst_tbl_inst;
 
                         dst_tbl_idx = read_uint32(frame_ip);
@@ -3161,8 +3159,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                         s = (uint32)POP_I32();
                         d = (uint32)POP_I32();
 
-                        if (d + n > dst_tbl_inst->cur_size
-                            || s + n > src_tbl_inst->cur_size) {
+                        if (offset_len_out_of_bounds(d, n,
+                                                     dst_tbl_inst->cur_size)
+                            || offset_len_out_of_bounds(
+                                s, n, src_tbl_inst->cur_size)) {
                             wasm_set_exception(module,
                                                "out of bounds table access");
                             goto got_exception;
@@ -3233,7 +3233,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                         fill_val = POP_I32();
                         i = POP_I32();
 
-                        if (i + n > tbl_inst->cur_size) {
+                        if (offset_len_out_of_bounds(i, n,
+                                                     tbl_inst->cur_size)) {
                             wasm_set_exception(module,
                                                "out of bounds table access");
                             goto got_exception;
@@ -3348,23 +3349,23 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                         if (opcode == WASM_OP_ATOMIC_I32_LOAD8_U) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS(1);
-                            os_mutex_lock(&node->shared_mem_lock);
+                            shared_memory_lock(memory);
                             readv = (uint32)(*(uint8 *)maddr);
-                            os_mutex_unlock(&node->shared_mem_lock);
+                            shared_memory_unlock(memory);
                         }
                         else if (opcode == WASM_OP_ATOMIC_I32_LOAD16_U) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS(2);
-                            os_mutex_lock(&node->shared_mem_lock);
+                            shared_memory_lock(memory);
                             readv = (uint32)LOAD_U16(maddr);
-                            os_mutex_unlock(&node->shared_mem_lock);
+                            shared_memory_unlock(memory);
                         }
                         else {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS(4);
-                            os_mutex_lock(&node->shared_mem_lock);
+                            shared_memory_lock(memory);
                             readv = LOAD_I32(maddr);
-                            os_mutex_unlock(&node->shared_mem_lock);
+                            shared_memory_unlock(memory);
                         }
 
                         PUSH_I32(readv);
@@ -3383,30 +3384,30 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                         if (opcode == WASM_OP_ATOMIC_I64_LOAD8_U) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS(1);
-                            os_mutex_lock(&node->shared_mem_lock);
+                            shared_memory_lock(memory);
                             readv = (uint64)(*(uint8 *)maddr);
-                            os_mutex_unlock(&node->shared_mem_lock);
+                            shared_memory_unlock(memory);
                         }
                         else if (opcode == WASM_OP_ATOMIC_I64_LOAD16_U) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS(2);
-                            os_mutex_lock(&node->shared_mem_lock);
+                            shared_memory_lock(memory);
                             readv = (uint64)LOAD_U16(maddr);
-                            os_mutex_unlock(&node->shared_mem_lock);
+                            shared_memory_unlock(memory);
                         }
                         else if (opcode == WASM_OP_ATOMIC_I64_LOAD32_U) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS(4);
-                            os_mutex_lock(&node->shared_mem_lock);
+                            shared_memory_lock(memory);
                             readv = (uint64)LOAD_U32(maddr);
-                            os_mutex_unlock(&node->shared_mem_lock);
+                            shared_memory_unlock(memory);
                         }
                         else {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS(8);
-                            os_mutex_lock(&node->shared_mem_lock);
+                            shared_memory_lock(memory);
                             readv = LOAD_I64(maddr);
-                            os_mutex_unlock(&node->shared_mem_lock);
+                            shared_memory_unlock(memory);
                         }
 
                         PUSH_I64(readv);
@@ -3424,23 +3425,23 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                         if (opcode == WASM_OP_ATOMIC_I32_STORE8) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS(1);
-                            os_mutex_lock(&node->shared_mem_lock);
+                            shared_memory_lock(memory);
                             *(uint8 *)maddr = (uint8)sval;
-                            os_mutex_unlock(&node->shared_mem_lock);
+                            shared_memory_unlock(memory);
                         }
                         else if (opcode == WASM_OP_ATOMIC_I32_STORE16) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS(2);
-                            os_mutex_lock(&node->shared_mem_lock);
+                            shared_memory_lock(memory);
                             STORE_U16(maddr, (uint16)sval);
-                            os_mutex_unlock(&node->shared_mem_lock);
+                            shared_memory_unlock(memory);
                         }
                         else {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS(4);
-                            os_mutex_lock(&node->shared_mem_lock);
+                            shared_memory_lock(memory);
                             STORE_U32(maddr, sval);
-                            os_mutex_unlock(&node->shared_mem_lock);
+                            shared_memory_unlock(memory);
                         }
                         break;
                     }
@@ -3458,30 +3459,30 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                         if (opcode == WASM_OP_ATOMIC_I64_STORE8) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS(1);
-                            os_mutex_lock(&node->shared_mem_lock);
+                            shared_memory_lock(memory);
                             *(uint8 *)maddr = (uint8)sval;
-                            os_mutex_unlock(&node->shared_mem_lock);
+                            shared_memory_unlock(memory);
                         }
                         else if (opcode == WASM_OP_ATOMIC_I64_STORE16) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS(2);
-                            os_mutex_lock(&node->shared_mem_lock);
+                            shared_memory_lock(memory);
                             STORE_U16(maddr, (uint16)sval);
-                            os_mutex_unlock(&node->shared_mem_lock);
+                            shared_memory_unlock(memory);
                         }
                         else if (opcode == WASM_OP_ATOMIC_I64_STORE32) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS(4);
-                            os_mutex_lock(&node->shared_mem_lock);
+                            shared_memory_lock(memory);
                             STORE_U32(maddr, (uint32)sval);
-                            os_mutex_unlock(&node->shared_mem_lock);
+                            shared_memory_unlock(memory);
                         }
                         else {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS(8);
-                            os_mutex_lock(&node->shared_mem_lock);
+                            shared_memory_lock(memory);
                             STORE_I64(maddr, sval);
-                            os_mutex_unlock(&node->shared_mem_lock);
+                            shared_memory_unlock(memory);
                         }
                         break;
                     }
@@ -3501,32 +3502,32 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                             CHECK_ATOMIC_MEMORY_ACCESS(1);
 
                             expect = (uint8)expect;
-                            os_mutex_lock(&node->shared_mem_lock);
+                            shared_memory_lock(memory);
                             readv = (uint32)(*(uint8 *)maddr);
                             if (readv == expect)
                                 *(uint8 *)maddr = (uint8)(sval);
-                            os_mutex_unlock(&node->shared_mem_lock);
+                            shared_memory_unlock(memory);
                         }
                         else if (opcode == WASM_OP_ATOMIC_RMW_I32_CMPXCHG16_U) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS(2);
 
                             expect = (uint16)expect;
-                            os_mutex_lock(&node->shared_mem_lock);
+                            shared_memory_lock(memory);
                             readv = (uint32)LOAD_U16(maddr);
                             if (readv == expect)
                                 STORE_U16(maddr, (uint16)(sval));
-                            os_mutex_unlock(&node->shared_mem_lock);
+                            shared_memory_unlock(memory);
                         }
                         else {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS(4);
 
-                            os_mutex_lock(&node->shared_mem_lock);
+                            shared_memory_lock(memory);
                             readv = LOAD_I32(maddr);
                             if (readv == expect)
                                 STORE_U32(maddr, sval);
-                            os_mutex_unlock(&node->shared_mem_lock);
+                            shared_memory_unlock(memory);
                         }
                         PUSH_I32(readv);
                         break;
@@ -3547,43 +3548,43 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                             CHECK_ATOMIC_MEMORY_ACCESS(1);
 
                             expect = (uint8)expect;
-                            os_mutex_lock(&node->shared_mem_lock);
+                            shared_memory_lock(memory);
                             readv = (uint64)(*(uint8 *)maddr);
                             if (readv == expect)
                                 *(uint8 *)maddr = (uint8)(sval);
-                            os_mutex_unlock(&node->shared_mem_lock);
+                            shared_memory_unlock(memory);
                         }
                         else if (opcode == WASM_OP_ATOMIC_RMW_I64_CMPXCHG16_U) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS(2);
 
                             expect = (uint16)expect;
-                            os_mutex_lock(&node->shared_mem_lock);
+                            shared_memory_lock(memory);
                             readv = (uint64)LOAD_U16(maddr);
                             if (readv == expect)
                                 STORE_U16(maddr, (uint16)(sval));
-                            os_mutex_unlock(&node->shared_mem_lock);
+                            shared_memory_unlock(memory);
                         }
                         else if (opcode == WASM_OP_ATOMIC_RMW_I64_CMPXCHG32_U) {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS(4);
 
                             expect = (uint32)expect;
-                            os_mutex_lock(&node->shared_mem_lock);
+                            shared_memory_lock(memory);
                             readv = (uint64)LOAD_U32(maddr);
                             if (readv == expect)
                                 STORE_U32(maddr, (uint32)(sval));
-                            os_mutex_unlock(&node->shared_mem_lock);
+                            shared_memory_unlock(memory);
                         }
                         else {
                             CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr);
                             CHECK_ATOMIC_MEMORY_ACCESS(8);
 
-                            os_mutex_lock(&node->shared_mem_lock);
+                            shared_memory_lock(memory);
                             readv = (uint64)LOAD_I64(maddr);
                             if (readv == expect)
                                 STORE_I64(maddr, sval);
-                            os_mutex_unlock(&node->shared_mem_lock);
+                            shared_memory_unlock(memory);
                         }
                         PUSH_I64(readv);
                         break;

+ 7 - 5
core/iwasm/interpreter/wasm_loader.c

@@ -7014,6 +7014,7 @@ static bool
 copy_params_to_dynamic_space(WASMLoaderContext *loader_ctx, bool is_if_block,
                              char *error_buf, uint32 error_buf_size)
 {
+    bool ret = false;
     int16 *frame_offset = NULL;
     uint8 *cells = NULL, cell;
     int16 *src_offsets = NULL;
@@ -7084,13 +7085,13 @@ copy_params_to_dynamic_space(WASMLoaderContext *loader_ctx, bool is_if_block,
     if (is_if_block)
         PUSH_OFFSET_TYPE(VALUE_TYPE_I32);
 
+    ret = true;
+
+fail:
     /* Free the emit data */
     wasm_runtime_free(emit_data);
 
-    return true;
-
-fail:
-    return false;
+    return ret;
 }
 #endif
 
@@ -8065,7 +8066,8 @@ re_scan:
                 uint8 vec_len, ref_type;
 
                 read_leb_uint32(p, p_end, vec_len);
-                if (!vec_len) {
+                if (vec_len != 1) {
+                    /* typed select must have exactly one result */
                     set_error_buf(error_buf, error_buf_size,
                                   "invalid result arity");
                     goto fail;

+ 2 - 1
core/iwasm/interpreter/wasm_mini_loader.c

@@ -6235,7 +6235,8 @@ re_scan:
                 uint8 vec_len, ref_type;
 
                 read_leb_uint32(p, p_end, vec_len);
-                if (!vec_len) {
+                if (vec_len != 1) {
+                    /* typed select must have exactly one result */
                     set_error_buf(error_buf, error_buf_size,
                                   "invalid result arity");
                     goto fail;

+ 44 - 63
core/iwasm/interpreter/wasm_runtime.c

@@ -122,11 +122,8 @@ memories_deinstantiate(WASMModuleInstance *module_inst,
                 }
 #endif
 #if WASM_ENABLE_SHARED_MEMORY != 0
-                if (memories[i]->is_shared) {
-                    int32 ref_count = shared_memory_dec_reference(
-                        (WASMModuleCommon *)module_inst->module);
-                    bh_assert(ref_count >= 0);
-
+                if (shared_memory_is_shared(memories[i])) {
+                    uint32 ref_count = shared_memory_dec_reference(memories[i]);
                     /* if the reference count is not zero,
                         don't free the memory */
                     if (ref_count > 0)
@@ -159,7 +156,8 @@ memories_deinstantiate(WASMModuleInstance *module_inst,
 }
 
 static WASMMemoryInstance *
-memory_instantiate(WASMModuleInstance *module_inst, WASMMemoryInstance *memory,
+memory_instantiate(WASMModuleInstance *module_inst, WASMModuleInstance *parent,
+                   WASMMemoryInstance *memory, uint32 memory_idx,
                    uint32 num_bytes_per_page, uint32 init_page_count,
                    uint32 max_page_count, uint32 heap_size, uint32 flags,
                    char *error_buf, uint32 error_buf_size)
@@ -180,22 +178,11 @@ memory_instantiate(WASMModuleInstance *module_inst, WASMMemoryInstance *memory,
     bool is_shared_memory = flags & 0x02 ? true : false;
 
     /* shared memory */
-    if (is_shared_memory) {
-        WASMSharedMemNode *node = wasm_module_get_shared_memory(
-            (WASMModuleCommon *)module_inst->module);
-        /* If the memory of this module has been instantiated,
-            return the memory instance directly */
-        if (node) {
-            uint32 ref_count;
-            ref_count = shared_memory_inc_reference(
-                (WASMModuleCommon *)module_inst->module);
-            bh_assert(ref_count > 0);
-            memory = (WASMMemoryInstance *)shared_memory_get_memory_inst(node);
-            bh_assert(memory);
-
-            (void)ref_count;
-            return memory;
-        }
+    if (is_shared_memory && parent != NULL) {
+        bh_assert(parent->memory_count > memory_idx);
+        memory = parent->memories[memory_idx];
+        shared_memory_inc_reference(memory);
+        return memory;
     }
 #endif /* end of WASM_ENABLE_SHARED_MEMORY */
 
@@ -388,24 +375,13 @@ memory_instantiate(WASMModuleInstance *module_inst, WASMMemoryInstance *memory,
 
 #if WASM_ENABLE_SHARED_MEMORY != 0
     if (is_shared_memory) {
-        memory->is_shared = true;
-        if (!shared_memory_set_memory_inst(
-                (WASMModuleCommon *)module_inst->module,
-                (WASMMemoryInstanceCommon *)memory)) {
-            set_error_buf(error_buf, error_buf_size, "allocate memory failed");
-            goto fail4;
-        }
+        memory->ref_count = 1;
     }
 #endif
 
     LOG_VERBOSE("Memory instantiate success.");
     return memory;
 
-#if WASM_ENABLE_SHARED_MEMORY != 0
-fail4:
-    if (heap_size > 0)
-        mem_allocator_destroy(memory->heap_handle);
-#endif
 fail3:
     if (heap_size > 0)
         wasm_runtime_free(memory->heap_handle);
@@ -428,7 +404,8 @@ fail1:
  */
 static WASMMemoryInstance **
 memories_instantiate(const WASMModule *module, WASMModuleInstance *module_inst,
-                     uint32 heap_size, char *error_buf, uint32 error_buf_size)
+                     WASMModuleInstance *parent, uint32 heap_size,
+                     char *error_buf, uint32 error_buf_size)
 {
     WASMImport *import;
     uint32 mem_index = 0, i,
@@ -474,26 +451,29 @@ memories_instantiate(const WASMModule *module, WASMModuleInstance *module_inst,
         else
 #endif
         {
-            if (!(memories[mem_index++] = memory_instantiate(
-                      module_inst, memory, num_bytes_per_page, init_page_count,
-                      max_page_count, actual_heap_size, flags, error_buf,
-                      error_buf_size))) {
+            if (!(memories[mem_index] = memory_instantiate(
+                      module_inst, parent, memory, mem_index,
+                      num_bytes_per_page, init_page_count, max_page_count,
+                      actual_heap_size, flags, error_buf, error_buf_size))) {
                 memories_deinstantiate(module_inst, memories, memory_count);
                 return NULL;
             }
+            mem_index++;
         }
     }
 
     /* instantiate memories from memory section */
     for (i = 0; i < module->memory_count; i++, memory++) {
-        if (!(memories[mem_index++] = memory_instantiate(
-                  module_inst, memory, module->memories[i].num_bytes_per_page,
+        if (!(memories[mem_index] = memory_instantiate(
+                  module_inst, parent, memory, mem_index,
+                  module->memories[i].num_bytes_per_page,
                   module->memories[i].init_page_count,
                   module->memories[i].max_page_count, heap_size,
                   module->memories[i].flags, error_buf, error_buf_size))) {
             memories_deinstantiate(module_inst, memories, memory_count);
             return NULL;
         }
+        mem_index++;
     }
 
     bh_assert(mem_index == memory_count);
@@ -1104,10 +1084,14 @@ execute_post_instantiate_functions(WASMModuleInstance *module_inst,
         goto fail;
     }
 
+#if WASM_ENABLE_LIBC_WASI != 0
     if (initialize_func
         && !wasm_call_function(exec_env, initialize_func, 0, NULL)) {
         goto fail;
     }
+#else
+    (void)initialize_func;
+#endif
 
     if (post_inst_func
         && !wasm_call_function(exec_env, post_inst_func, 0, NULL)) {
@@ -1297,7 +1281,7 @@ sub_module_instantiate(WASMModule *module, WASMModuleInstance *module_inst,
         WASMModuleInstance *sub_module_inst = NULL;
 
         sub_module_inst =
-            wasm_instantiate(sub_module, false, NULL, stack_size, heap_size,
+            wasm_instantiate(sub_module, NULL, NULL, stack_size, heap_size,
                              error_buf, error_buf_size);
         if (!sub_module_inst) {
             LOG_DEBUG("instantiate %s failed",
@@ -1642,7 +1626,7 @@ wasm_set_running_mode(WASMModuleInstance *module_inst, RunningMode running_mode)
  * Instantiate module
  */
 WASMModuleInstance *
-wasm_instantiate(WASMModule *module, bool is_sub_inst,
+wasm_instantiate(WASMModule *module, WASMModuleInstance *parent,
                  WASMExecEnv *exec_env_main, uint32 stack_size,
                  uint32 heap_size, char *error_buf, uint32 error_buf_size)
 {
@@ -1659,6 +1643,7 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst,
 #if WASM_ENABLE_MULTI_MODULE != 0
     bool ret = false;
 #endif
+    const bool is_sub_inst = parent != NULL;
 
     if (!module)
         return NULL;
@@ -1777,8 +1762,9 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst,
 
     /* Instantiate memories/tables/functions */
     if ((module_inst->memory_count > 0
-         && !(module_inst->memories = memories_instantiate(
-                  module, module_inst, heap_size, error_buf, error_buf_size)))
+         && !(module_inst->memories =
+                  memories_instantiate(module, module_inst, parent, heap_size,
+                                       error_buf, error_buf_size)))
         || (module_inst->table_count > 0
             && !(module_inst->tables =
                      tables_instantiate(module, module_inst, first_table,
@@ -2212,16 +2198,6 @@ wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst)
     sub_module_deinstantiate(module_inst);
 #endif
 
-#if WASM_ENABLE_LIBC_WASI != 0
-    /* Destroy wasi resource before freeing app heap, since some fields of
-       wasi contex are allocated from app heap, and if app heap is freed,
-       these fields will be set to NULL, we cannot free their internal data
-       which may allocated from global heap. */
-    /* Only destroy wasi ctx in the main module instance */
-    if (!is_sub_inst)
-        wasm_runtime_destroy_wasi((WASMModuleInstanceCommon *)module_inst);
-#endif
-
     if (module_inst->memory_count > 0)
         memories_deinstantiate(module_inst, module_inst->memories,
                                module_inst->memory_count);
@@ -2254,10 +2230,14 @@ wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst)
     if (module_inst->e->c_api_func_imports)
         wasm_runtime_free(module_inst->e->c_api_func_imports);
 
+    if (!is_sub_inst) {
+#if WASM_ENABLE_LIBC_WASI != 0
+        wasm_runtime_destroy_wasi((WASMModuleInstanceCommon *)module_inst);
+#endif
 #if WASM_ENABLE_WASI_NN != 0
-    if (!is_sub_inst)
         wasi_nn_destroy(module_inst);
 #endif
+    }
 
     wasm_runtime_free(module_inst);
 }
@@ -3297,13 +3277,13 @@ llvm_jit_table_init(WASMModuleInstance *module_inst, uint32 tbl_idx,
     bh_assert(tbl_inst);
     bh_assert(tbl_seg);
 
-    if (!length) {
+    if (offset_len_out_of_bounds(src_offset, length, tbl_seg->function_count)
+        || offset_len_out_of_bounds(dst_offset, length, tbl_inst->cur_size)) {
+        jit_set_exception_with_id(module_inst, EXCE_OUT_OF_BOUNDS_TABLE_ACCESS);
         return;
     }
 
-    if (length + src_offset > tbl_seg->function_count
-        || dst_offset + length > tbl_inst->cur_size) {
-        jit_set_exception_with_id(module_inst, EXCE_OUT_OF_BOUNDS_TABLE_ACCESS);
+    if (!length) {
         return;
     }
 
@@ -3345,8 +3325,9 @@ llvm_jit_table_copy(WASMModuleInstance *module_inst, uint32 src_tbl_idx,
     bh_assert(src_tbl_inst);
     bh_assert(dst_tbl_inst);
 
-    if ((uint64)dst_offset + length > dst_tbl_inst->cur_size
-        || (uint64)src_offset + length > src_tbl_inst->cur_size) {
+    if (offset_len_out_of_bounds(dst_offset, length, dst_tbl_inst->cur_size)
+        || offset_len_out_of_bounds(src_offset, length,
+                                    src_tbl_inst->cur_size)) {
         jit_set_exception_with_id(module_inst, EXCE_OUT_OF_BOUNDS_TABLE_ACCESS);
         return;
     }
@@ -3378,7 +3359,7 @@ llvm_jit_table_fill(WASMModuleInstance *module_inst, uint32 tbl_idx,
     tbl_inst = wasm_get_table_inst(module_inst, tbl_idx);
     bh_assert(tbl_inst);
 
-    if (data_offset + length > tbl_inst->cur_size) {
+    if (offset_len_out_of_bounds(data_offset, length, tbl_inst->cur_size)) {
         jit_set_exception_with_id(module_inst, EXCE_OUT_OF_BOUNDS_TABLE_ACCESS);
         return;
     }

+ 3 - 2
core/iwasm/interpreter/wasm_runtime.h

@@ -7,6 +7,7 @@
 #define _WASM_RUNTIME_H
 
 #include "wasm.h"
+#include "bh_atomic.h"
 #include "bh_hashmap.h"
 #include "../common/wasm_runtime_common.h"
 #include "../common/wasm_exec_env.h"
@@ -79,7 +80,7 @@ struct WASMMemoryInstance {
     /* Module type */
     uint32 module_type;
     /* Shared memory flag */
-    bool is_shared;
+    bh_atomic_32_t ref_count; /* 0: non-shared, > 0: reference count */
 
     /* Number bytes per page */
     uint32 num_bytes_per_page;
@@ -400,7 +401,7 @@ void
 wasm_unload(WASMModule *module);
 
 WASMModuleInstance *
-wasm_instantiate(WASMModule *module, bool is_sub_inst,
+wasm_instantiate(WASMModule *module, WASMModuleInstance *parent,
                  WASMExecEnv *exec_env_main, uint32 stack_size,
                  uint32 heap_size, char *error_buf, uint32 error_buf_size);
 

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

@@ -531,7 +531,8 @@ pthread_start_routine(void *arg)
     else {
         info_node->u.ret = (void *)(uintptr_t)argv[0];
 #ifdef OS_ENABLE_HW_BOUND_CHECK
-        if (exec_env->suspend_flags.flags & 0x08)
+        if (WASM_SUSPEND_FLAGS_GET(exec_env->suspend_flags)
+            & WASM_SUSPEND_FLAG_EXIT)
             /* argv[0] isn't set after longjmp(1) to
                invoke_native_with_hw_bound_check */
             info_node->u.ret = exec_env->thread_ret_value;
@@ -580,7 +581,7 @@ pthread_create_wrapper(wasm_exec_env_t exec_env,
 #endif
 
     if (!(new_module_inst = wasm_runtime_instantiate_internal(
-              module, true, exec_env, stack_size, 0, NULL, 0)))
+              module, module_inst, exec_env, stack_size, 0, NULL, 0)))
         return -1;
 
     /* Set custom_data to new module instance */
@@ -690,6 +691,14 @@ pthread_join_wrapper(wasm_exec_env_t exec_env, uint32 thread,
         bh_assert(node->joinable);
         join_ret = 0;
         ret = node->u.ret;
+
+        /* The target thread changes the node's status before calling
+           wasm_cluster_exit_thread to exit, so here its resources may
+           haven't been destroyed yet, we wait enough time to ensure that
+           they are actually destroyed to avoid unexpected behavior. */
+        os_mutex_lock(&exec_env->wait_lock);
+        os_cond_reltimedwait(&exec_env->wait_cond, &exec_env->wait_lock, 1000);
+        os_mutex_unlock(&exec_env->wait_lock);
     }
 
     if (retval_offset != 0)
@@ -757,7 +766,6 @@ __pthread_self_wrapper(wasm_exec_env_t exec_env)
 static void
 pthread_exit_wrapper(wasm_exec_env_t exec_env, int32 retval_offset)
 {
-    wasm_module_inst_t module_inst = get_module_inst(exec_env);
     ThreadRoutineArgs *args = get_thread_arg(exec_env);
     /* Currently exit main thread is not allowed */
     if (!args)
@@ -775,9 +783,6 @@ pthread_exit_wrapper(wasm_exec_env_t exec_env, int32 retval_offset)
     /* destroy pthread key values */
     call_key_destructor(exec_env);
 
-    /* routine exit, destroy instance */
-    wasm_runtime_deinstantiate_internal(module_inst, true);
-
     if (!args->info_node->joinable) {
         delete_thread_info_node(args->info_node);
     }
@@ -789,6 +794,8 @@ pthread_exit_wrapper(wasm_exec_env_t exec_env, int32 retval_offset)
 
     wasm_runtime_free(args);
 
+    /* Don't destroy exec_env->module_inst in this functuntion since
+       it will be destroyed in wasm_cluster_exit_thread */
     wasm_cluster_exit_thread(exec_env, (void *)(uintptr_t)retval_offset);
 }
 

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

@@ -46,6 +46,7 @@ test_nslookup_mt(void *params)
 {
     int *af = (int *)params;
     test_nslookup(*af);
+    return NULL;
 }
 
 int

+ 112 - 113
core/iwasm/libraries/lib-socket/test/tcp_udp.c

@@ -5,6 +5,8 @@
 #include <unistd.h>
 #include <string.h>
 #include <assert.h>
+#include <errno.h>
+#include <time.h>
 #ifdef __wasi__
 #include <wasi/api.h>
 #include <sys/socket.h>
@@ -12,105 +14,123 @@
 #endif
 #include <arpa/inet.h>
 #include <pthread.h>
+#include <stdio.h>
+
 #define SERVER_MSG "Message from server."
 #define PORT 8989
-pthread_mutex_t mut;
-pthread_cond_t cond;
+
+pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
+pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
+
 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;
+typedef struct {
+    struct sockaddr_storage addr;
+    socklen_t addr_len;
     int sock;
-};
-
-struct thread_args {
-    int family;
     int protocol;
-};
+} socket_info_t;
+
+void
+wait_for_server(int wait_time_seconds)
+{
+    int res = 0;
+    struct timespec ts;
+    clock_gettime(CLOCK_REALTIME, &ts);
+    ts.tv_sec += wait_time_seconds;
+
+    pthread_mutex_lock(&mut);
+    while (server_init_complete == 0) {
+        res = pthread_cond_timedwait(&cond, &mut, &ts);
+        if (res == ETIMEDOUT)
+            break;
+    }
+    pthread_mutex_unlock(&mut);
+
+    assert(res == 0);
+}
 
-struct socket_info
+void
+notify_server_started()
+{
+    pthread_mutex_lock(&mut);
+    server_init_complete = 1;
+    pthread_cond_signal(&cond);
+    pthread_mutex_unlock(&mut);
+}
+
+socket_info_t
 init_socket_addr(int family, int protocol)
 {
-    int sock = socket(family, protocol, 0);
-    assert(sock != -1);
+    socket_info_t info;
+
+    info.sock = socket(family, protocol, 0);
+    assert(info.sock != -1);
+    info.protocol = protocol;
+
+    memset(&info.addr, 0, sizeof(info.addr));
 
-    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;
+        struct sockaddr_in *addr = (struct sockaddr_in *)&info.addr;
+        addr->sin_family = AF_INET;
+        addr->sin_port = htons(PORT);
+        addr->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+        info.addr_len = sizeof(struct sockaddr_in);
     }
     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;
+        struct sockaddr_in6 *addr = (struct sockaddr_in6 *)&info.addr;
+        addr->sin6_family = AF_INET6;
+        addr->sin6_port = htons(PORT);
+        addr->sin6_addr = in6addr_loopback;
+        info.addr_len = sizeof(struct sockaddr_in6);
     }
-    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);
+    return info;
 }
 
 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;
+    char buffer[sizeof(SERVER_MSG) + 1] = { 0 };
     struct sockaddr_storage client_addr;
-    strcpy(buffer, SERVER_MSG);
+    socket_info_t *info = (socket_info_t *)arg;
+    struct sockaddr *server_addr = (struct sockaddr *)&info->addr;
+    int server_sock = info->sock;
 
-    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);
+    int optval = 1;
+    assert(setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, &optval,
+                      sizeof(optval))
+           == 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);
+    assert(bind(server_sock, server_addr, info->addr_len) == 0);
+
+    if (info->protocol == SOCK_STREAM)
+        listen(server_sock, 1);
+    notify_server_started();
 
-    addr_size = sizeof(client_addr);
-    if (args->protocol == SOCK_STREAM) {
+    socklen_t addr_size = info->addr_len;
+    if (info->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);
+        assert(recv(client_sock, buffer, sizeof(buffer), 0) > 0);
+        strcpy(buffer, SERVER_MSG);
+        assert(send(client_sock, buffer, sizeof(buffer), 0) > 0);
+        assert(recv(client_sock, buffer, sizeof(buffer), 0) > 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);
+        assert(recvfrom(server_sock, buffer, sizeof(buffer), 0,
+                        (struct sockaddr *)&client_addr, &addr_size)
+               > 0);
+        strcpy(buffer, SERVER_MSG);
+        assert(sendto(server_sock, buffer, strlen(buffer), 0,
+                      (struct sockaddr *)&client_addr, addr_size)
+               > 0);
+        assert(recvfrom(server_sock, buffer, sizeof(buffer), 0,
+                        (struct sockaddr *)&client_addr, &addr_size)
+               > 0);
     }
+    assert(close(server_sock) == 0);
 
     return NULL;
 }
@@ -118,46 +138,23 @@ server(void *arg)
 void *
 client(void *arg)
 {
-    struct thread_args *args = (struct thread_args *)arg;
-    assert_thread_args(args);
-
-    pthread_mutex_lock(&mut);
+    char buffer[sizeof(SERVER_MSG) + 1];
+    socket_info_t *info = (socket_info_t *)arg;
+    int sock = info->sock;
+    struct sockaddr *addr = (struct sockaddr *)&info->addr;
 
-    while (server_init_complete == 0) {
-        pthread_cond_wait(&cond, &mut);
-    }
+    wait_for_server(1);
 
-    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);
-        }
+    if (info->protocol == SOCK_STREAM) {
+        assert(connect(sock, addr, info->addr_len) != -1);
     }
 
-    recv(sock, buffer, sizeof(buffer), 0);
-    assert(strcmp(buffer, SERVER_MSG) == 0);
+    assert(sendto(sock, "open", strlen("open"), 0, addr, info->addr_len) > 0);
+    assert(recv(sock, buffer, sizeof(buffer), 0) > 0);
+    assert(strncmp(buffer, SERVER_MSG, strlen(SERVER_MSG)) == 0);
+    assert(sendto(sock, "close", sizeof("close"), 0, addr, info->addr_len) > 0);
     assert(close(sock) == 0);
+
     return NULL;
 }
 
@@ -165,17 +162,19 @@ 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);
+    socket_info_t server_info = init_socket_addr(family, protocol);
+    socket_info_t client_info = init_socket_addr(family, protocol);
+
+    printf("Testing address family: %d protocol: %d\n", family, protocol);
+
+    server_init_complete = 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_create(&server_thread, NULL, server, (void *)&server_info)
+           == 0);
+    assert(pthread_create(&client_thread, NULL, client, (void *)&client_info)
+           == 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
@@ -190,4 +189,4 @@ main(int argc, char **argv)
     test_protocol(AF_INET6, SOCK_DGRAM);
 
     return 0;
-}
+}

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

@@ -90,7 +90,7 @@ thread_spawn_wrapper(wasm_exec_env_t exec_env, uint32 start_arg)
     stack_size = ((WASMModuleInstance *)module_inst)->default_wasm_stack_size;
 
     if (!(new_module_inst = wasm_runtime_instantiate_internal(
-              module, true, exec_env, stack_size, 0, NULL, 0)))
+              module, module_inst, exec_env, stack_size, 0, NULL, 0)))
         return -1;
 
     wasm_runtime_set_custom_data_internal(

+ 4 - 1
core/iwasm/libraries/lib-wasi-threads/test/build.sh

@@ -9,10 +9,13 @@ set -eo pipefail
 CC=${CC:=/opt/wasi-sdk/bin/clang}
 WAMR_DIR=../../../../..
 
+# Stress tests names
+thread_start_file_exclusions=("spawn_stress_test.wasm" "linear_memory_size_update.wasm")
+
 for test_c in *.c; do
     test_wasm="$(basename $test_c .c).wasm"
 
-    if [ $test_wasm = "linear_memory_size_update.wasm" ]; then
+    if [[ " ${thread_start_file_exclusions[@]} " =~ " ${test_wasm} " ]] ; then
         thread_start_file=""
     else
         thread_start_file=$WAMR_DIR/samples/wasi-threads/wasm-apps/wasi_thread_start.S

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

@@ -0,0 +1,3 @@
+{
+    "name": "lib-wasi-threads tests"
+}

+ 5 - 0
core/iwasm/libraries/lib-wasi-threads/test/skip.json

@@ -0,0 +1,5 @@
+{
+    "lib-wasi-threads tests": {
+        "spawn_stress_test": "Stress tests are incompatible with the other part and executed differently"
+    }
+}

+ 114 - 0
core/iwasm/libraries/lib-wasi-threads/test/spawn_stress_test.c

@@ -0,0 +1,114 @@
+/*
+ * 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 <assert.h>
+#include <errno.h>
+#include <math.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+enum CONSTANTS {
+    NUM_ITER = 100000,
+    NUM_RETRY = 5,
+    MAX_NUM_THREADS = 8,
+};
+
+unsigned prime_numbers_count = 0;
+
+bool
+is_prime(unsigned int num)
+{
+    for (unsigned int i = 2; i <= (unsigned int)(sqrt(num)); ++i) {
+        if (num % i == 0) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+void *
+check_if_prime(void *value)
+{
+    unsigned int *num = (unsigned int *)(value);
+    usleep(10000);
+    if (is_prime(*num)) {
+        __atomic_fetch_add(&prime_numbers_count, 1, __ATOMIC_SEQ_CST);
+    }
+    return NULL;
+}
+
+unsigned int
+validate()
+{
+    unsigned int counter = 0;
+    for (unsigned int i = 2; i <= NUM_ITER; ++i) {
+        counter += is_prime(i);
+    }
+
+    return counter;
+}
+
+void
+spawn_thread(pthread_t *thread, unsigned int *arg)
+{
+    int status_code = -1;
+    for (int tries = 0; status_code != 0 && tries < NUM_RETRY; ++tries) {
+        status_code = pthread_create(thread, NULL, &check_if_prime, arg);
+        assert(status_code == 0 || status_code == EAGAIN);
+        if (status_code == EAGAIN) {
+            usleep(2000);
+        }
+    }
+
+    assert(status_code == 0 && "Thread creation should succeed");
+}
+
+int
+main(int argc, char **argv)
+{
+    pthread_t threads[MAX_NUM_THREADS];
+    unsigned int args[MAX_NUM_THREADS];
+    double percentage = 0.1;
+
+    for (unsigned int factorised_number = 2; factorised_number < NUM_ITER;
+         ++factorised_number) {
+        if (factorised_number > NUM_ITER * percentage) {
+            fprintf(stderr, "Stress test is %d%% finished\n",
+                    (unsigned int)(percentage * 100));
+            percentage += 0.1;
+        }
+
+        unsigned int thread_num = factorised_number % MAX_NUM_THREADS;
+        if (threads[thread_num] != 0) {
+            assert(pthread_join(threads[thread_num], NULL) == 0);
+        }
+
+        args[thread_num] = factorised_number;
+
+        usleep(2000);
+        spawn_thread(&threads[thread_num], &args[thread_num]);
+        assert(threads[thread_num] != 0);
+    }
+
+    for (int i = 0; i < MAX_NUM_THREADS; ++i) {
+        assert(threads[i] == 0 || pthread_join(threads[i], NULL) == 0);
+    }
+
+    // Check the test results
+    assert(
+        prime_numbers_count == validate()
+        && "Answer mismatch between tested code and reference implementation");
+
+    fprintf(stderr, "Stress test finished successfully\n");
+    return 0;
+}

+ 1 - 1
core/iwasm/libraries/libc-uvwasi/libc_uvwasi.cmake

@@ -3,7 +3,7 @@
 
 set (LIBC_WASI_DIR ${CMAKE_CURRENT_LIST_DIR})
 
-set (LIBUV_VERSION v1.44.2)
+set (LIBUV_VERSION v1.46.0)
 
 add_definitions (-DWASM_ENABLE_LIBC_WASI=1 -DWASM_ENABLE_UVWASI=1)
 

+ 24 - 20
core/iwasm/libraries/thread-mgr/thread_manager.c

@@ -509,7 +509,7 @@ wasm_cluster_spawn_exec_env(WASMExecEnv *exec_env)
 #endif
 
     if (!(new_module_inst = wasm_runtime_instantiate_internal(
-              module, true, exec_env, stack_size, 0, NULL, 0))) {
+              module, module_inst, exec_env, stack_size, 0, NULL, 0))) {
         goto fail1;
     }
 
@@ -606,7 +606,8 @@ thread_manager_start_routine(void *arg)
 
 #ifdef OS_ENABLE_HW_BOUND_CHECK
     os_mutex_lock(&exec_env->wait_lock);
-    if (exec_env->suspend_flags.flags & 0x08)
+    if (WASM_SUSPEND_FLAGS_GET(exec_env->suspend_flags)
+        & WASM_SUSPEND_FLAG_EXIT)
         ret = exec_env->thread_ret_value;
     os_mutex_unlock(&exec_env->wait_lock);
 #endif
@@ -993,7 +994,9 @@ wasm_cluster_exit_thread(WASMExecEnv *exec_env, void *retval)
     if (exec_env->jmpbuf_stack_top) {
         /* Store the return value in exec_env */
         exec_env->thread_ret_value = retval;
-        exec_env->suspend_flags.flags |= 0x08;
+
+        WASM_SUSPEND_FLAGS_FETCH_OR(exec_env->suspend_flags,
+                                    WASM_SUSPEND_FLAG_EXIT);
 
 #ifndef BH_PLATFORM_WINDOWS
         /* Pop all jmpbuf_node except the last one */
@@ -1055,7 +1058,8 @@ set_thread_cancel_flags(WASMExecEnv *exec_env)
 #if WASM_ENABLE_DEBUG_INTERP != 0
     wasm_cluster_thread_send_signal(exec_env, WAMR_SIG_TERM);
 #endif
-    exec_env->suspend_flags.flags |= 0x01;
+    WASM_SUSPEND_FLAGS_FETCH_OR(exec_env->suspend_flags,
+                                WASM_SUSPEND_FLAG_TERMINATE);
 
     os_mutex_unlock(&exec_env->wait_lock);
 }
@@ -1178,7 +1182,8 @@ void
 wasm_cluster_suspend_thread(WASMExecEnv *exec_env)
 {
     /* Set the suspend flag */
-    exec_env->suspend_flags.flags |= 0x02;
+    WASM_SUSPEND_FLAGS_FETCH_OR(exec_env->suspend_flags,
+                                WASM_SUSPEND_FLAG_SUSPEND);
 }
 
 static void
@@ -1214,7 +1219,8 @@ wasm_cluster_suspend_all_except_self(WASMCluster *cluster,
 void
 wasm_cluster_resume_thread(WASMExecEnv *exec_env)
 {
-    exec_env->suspend_flags.flags &= ~0x02;
+    WASM_SUSPEND_FLAGS_FETCH_AND(exec_env->suspend_flags,
+                                 ~WASM_SUSPEND_FLAG_SUSPEND);
     os_cond_signal(&exec_env->wait_cond);
 }
 
@@ -1248,10 +1254,8 @@ set_exception_visitor(void *node, void *user_data)
 
         /* Only spread non "wasi proc exit" exception */
 #if WASM_ENABLE_SHARED_MEMORY != 0
-        WASMSharedMemNode *shared_mem_node = wasm_module_get_shared_memory(
-            (WASMModuleCommon *)curr_wasm_inst->module);
-        if (shared_mem_node)
-            os_mutex_lock(&shared_mem_node->shared_mem_lock);
+        if (curr_wasm_inst->memory_count > 0)
+            shared_memory_lock(curr_wasm_inst->memories[0]);
 #endif
         if (!strstr(wasm_inst->cur_exception, "wasi proc exit")) {
             bh_memcpy_s(curr_wasm_inst->cur_exception,
@@ -1260,8 +1264,8 @@ set_exception_visitor(void *node, void *user_data)
                         sizeof(wasm_inst->cur_exception));
         }
 #if WASM_ENABLE_SHARED_MEMORY != 0
-        if (shared_mem_node)
-            os_mutex_unlock(&shared_mem_node->shared_mem_lock);
+        if (curr_wasm_inst->memory_count > 0)
+            shared_memory_unlock(curr_wasm_inst->memories[0]);
 #endif
 
         /* Terminate the thread so it can exit from dead loops */
@@ -1280,15 +1284,13 @@ clear_exception_visitor(void *node, void *user_data)
             (WASMModuleInstance *)get_module_inst(curr_exec_env);
 
 #if WASM_ENABLE_SHARED_MEMORY != 0
-        WASMSharedMemNode *shared_mem_node = wasm_module_get_shared_memory(
-            (WASMModuleCommon *)curr_wasm_inst->module);
-        if (shared_mem_node)
-            os_mutex_lock(&shared_mem_node->shared_mem_lock);
+        if (curr_wasm_inst->memory_count > 0)
+            shared_memory_lock(curr_wasm_inst->memories[0]);
 #endif
         curr_wasm_inst->cur_exception[0] = '\0';
 #if WASM_ENABLE_SHARED_MEMORY != 0
-        if (shared_mem_node)
-            os_mutex_unlock(&shared_mem_node->shared_mem_lock);
+        if (curr_wasm_inst->memory_count > 0)
+            shared_memory_unlock(curr_wasm_inst->memories[0]);
 #endif
     }
 }
@@ -1343,8 +1345,10 @@ bool
 wasm_cluster_is_thread_terminated(WASMExecEnv *exec_env)
 {
     os_mutex_lock(&exec_env->wait_lock);
-    bool is_thread_terminated =
-        (exec_env->suspend_flags.flags & 0x01) ? true : false;
+    bool is_thread_terminated = (WASM_SUSPEND_FLAGS_GET(exec_env->suspend_flags)
+                                 & WASM_SUSPEND_FLAG_TERMINATE)
+                                    ? true
+                                    : false;
     os_mutex_unlock(&exec_env->wait_lock);
 
     return is_thread_terminated;

+ 68 - 5
core/shared/platform/esp-idf/espidf_memmap.c

@@ -5,16 +5,34 @@
 
 #include "platform_api_vmcore.h"
 #include "platform_api_extension.h"
+#if (WASM_MEM_DUAL_BUS_MIRROR != 0)
+#include "soc/mmu.h"
+#include "rom/cache.h"
+
+#define MEM_DUAL_BUS_OFFSET (IRAM0_CACHE_ADDRESS_LOW - DRAM0_CACHE_ADDRESS_LOW)
+
+#define in_ibus_ext(addr)                      \
+    (((uint32)addr >= IRAM0_CACHE_ADDRESS_LOW) \
+     && ((uint32)addr < IRAM0_CACHE_ADDRESS_HIGH))
+
+static portMUX_TYPE s_spinlock = portMUX_INITIALIZER_UNLOCKED;
+#endif
 
 void *
 os_mmap(void *hint, size_t size, int prot, int flags)
 {
     if (prot & MMAP_PROT_EXEC) {
+#if (WASM_MEM_DUAL_BUS_MIRROR != 0)
+        uint32_t mem_caps = MALLOC_CAP_SPIRAM;
+#else
+        uint32_t mem_caps = MALLOC_CAP_EXEC;
+#endif
+
         // Memory allocation with MALLOC_CAP_EXEC will return 4-byte aligned
         // Reserve extra 4 byte to fixup alignment and size for the pointer to
         // the originally allocated address
         void *buf_origin =
-            heap_caps_malloc(size + 4 + sizeof(uintptr_t), MALLOC_CAP_EXEC);
+            heap_caps_malloc(size + 4 + sizeof(uintptr_t), mem_caps);
         if (!buf_origin) {
             return NULL;
         }
@@ -25,19 +43,35 @@ os_mmap(void *hint, size_t size, int prot, int flags)
 
         uintptr_t *addr_field = buf_fixed - sizeof(uintptr_t);
         *addr_field = (uintptr_t)buf_origin;
+#if (WASM_MEM_DUAL_BUS_MIRROR != 0)
+        return buf_fixed + MEM_DUAL_BUS_OFFSET;
+#else
         return buf_fixed;
+#endif
     }
     else {
-        return os_malloc(size);
+#if (WASM_MEM_DUAL_BUS_MIRROR != 0)
+        uint32_t mem_caps = MALLOC_CAP_SPIRAM;
+#else
+        uint32_t mem_caps = MALLOC_CAP_8BIT;
+#endif
+        return heap_caps_malloc(size, mem_caps);
     }
 }
 
 void
 os_munmap(void *addr, size_t size)
 {
+    char *ptr = (char *)addr;
+
+#if (WASM_MEM_DUAL_BUS_MIRROR != 0)
+    if (in_ibus_ext(ptr)) {
+        ptr -= MEM_DUAL_BUS_OFFSET;
+    }
+#endif
     // We don't need special handling of the executable allocations
     // here, free() of esp-idf handles it properly
-    return os_free(addr);
+    return os_free(ptr);
 }
 
 int
@@ -47,5 +81,34 @@ os_mprotect(void *addr, size_t size, int prot)
 }
 
 void
-os_dcache_flush()
-{}
+#if (WASM_MEM_DUAL_BUS_MIRROR != 0)
+    IRAM_ATTR
+#endif
+    os_dcache_flush()
+{
+#if (WASM_MEM_DUAL_BUS_MIRROR != 0)
+    uint32_t preload;
+    extern void Cache_WriteBack_All(void);
+
+    portENTER_CRITICAL(&s_spinlock);
+
+    Cache_WriteBack_All();
+    preload = Cache_Disable_ICache();
+    Cache_Enable_ICache(preload);
+
+    portEXIT_CRITICAL(&s_spinlock);
+#endif
+}
+
+#if (WASM_MEM_DUAL_BUS_MIRROR != 0)
+void *
+os_get_dbus_mirror(void *ibus)
+{
+    if (in_ibus_ext(ibus)) {
+        return (void *)((char *)ibus - MEM_DUAL_BUS_OFFSET);
+    }
+    else {
+        return ibus;
+    }
+}
+#endif

+ 6 - 0
core/shared/platform/esp-idf/shared_platform.cmake

@@ -11,3 +11,9 @@ include_directories(${PLATFORM_SHARED_DIR}/../include)
 file (GLOB_RECURSE source_all ${PLATFORM_SHARED_DIR}/*.c)
 
 set (PLATFORM_SHARED_SOURCE ${source_all} ${PLATFORM_COMMON_MATH_SOURCE})
+
+# If enable PSRAM of ESP32-S3, it had better to put AOT into PSRAM, so that
+# users can use SRAM to for Wi-Fi/BLE and peripheral driver.
+if(CONFIG_ESP32S3_SPIRAM_SUPPORT)
+    add_definitions(-DWASM_MEM_DUAL_BUS_MIRROR=1)
+endif()

+ 5 - 0
core/shared/platform/include/platform_api_vmcore.h

@@ -129,6 +129,11 @@ os_munmap(void *addr, size_t size);
 int
 os_mprotect(void *addr, size_t size, int prot);
 
+#if (WASM_MEM_DUAL_BUS_MIRROR != 0)
+void *
+os_get_dbus_mirror(void *ibus);
+#endif
+
 /**
  * Flush cpu data cache, in some CPUs, after applying relocation to the
  * AOT code, the code may haven't been written back to the cpu data cache,

+ 79 - 2
core/shared/platform/nuttx/nuttx_platform.c

@@ -10,6 +10,46 @@
 #include <nuttx/arch.h>
 #endif
 
+#if defined(CONFIG_ARCH_CHIP_ESP32S3)
+/*
+ * TODO: Move these methods below the operating system level
+ */
+#define MEM_DUAL_BUS_OFFSET (0x42000000 - 0x3C000000)
+#define IRAM0_CACHE_ADDRESS_LOW 0x42000000
+#define IRAM0_CACHE_ADDRESS_HIGH 0x44000000
+#define IRAM_ATTR locate_data(".iram1")
+
+#define in_ibus_ext(addr)                      \
+    (((uint32)addr >= IRAM0_CACHE_ADDRESS_LOW) \
+     && ((uint32)addr < IRAM0_CACHE_ADDRESS_HIGH))
+void IRAM_ATTR
+bus_sync(void)
+{
+    extern void cache_writeback_all(void);
+    extern uint32_t Cache_Disable_ICache(void);
+    extern void Cache_Enable_ICache(uint32_t autoload);
+
+    irqstate_t flags;
+    uint32_t preload;
+
+    flags = enter_critical_section();
+
+    cache_writeback_all();
+    preload = Cache_Disable_ICache();
+    Cache_Enable_ICache(preload);
+
+    leave_critical_section(flags);
+}
+#else
+#define MEM_DUAL_BUS_OFFSET (0)
+#define IRAM0_CACHE_ADDRESS_LOW (0)
+#define IRAM0_CACHE_ADDRESS_HIGH (0)
+#define in_ibus_ext(addr) (0)
+static void
+bus_sync(void)
+{}
+#endif
+
 int
 bh_platform_init()
 {
@@ -47,6 +87,10 @@ os_dumps_proc_mem_info(char *out, unsigned int size)
 void *
 os_mmap(void *hint, size_t size, int prot, int flags)
 {
+#if (WASM_MEM_DUAL_BUS_MIRROR != 0)
+    void *i_addr, *d_addr;
+#endif
+
 #if defined(CONFIG_ARCH_USE_TEXT_HEAP)
     if ((prot & MMAP_PROT_EXEC) != 0) {
         return up_textheap_memalign(sizeof(void *), size);
@@ -55,6 +99,17 @@ os_mmap(void *hint, size_t size, int prot, int flags)
 
     if ((uint64)size >= UINT32_MAX)
         return NULL;
+
+#if (WASM_MEM_DUAL_BUS_MIRROR != 0)
+    if ((prot & MMAP_PROT_EXEC) != 0) {
+        d_addr = malloc((uint32)size);
+        if (d_addr == NULL) {
+            return NULL;
+        }
+        i_addr = (void *)((uint8 *)d_addr + MEM_DUAL_BUS_OFFSET);
+        return in_ibus_ext(i_addr) ? i_addr : d_addr;
+    }
+#endif
     return malloc((uint32)size);
 }
 
@@ -67,7 +122,14 @@ os_munmap(void *addr, size_t size)
         return;
     }
 #endif
-    return free(addr);
+
+#if (WASM_MEM_DUAL_BUS_MIRROR != 0)
+    if (in_ibus_ext(addr)) {
+        free((void *)((uint8 *)addr - MEM_DUAL_BUS_OFFSET));
+        return;
+    }
+#endif
+    free(addr);
 }
 
 int
@@ -78,7 +140,22 @@ os_mprotect(void *addr, size_t size, int prot)
 
 void
 os_dcache_flush()
-{}
+{
+    bus_sync();
+}
+
+#if (WASM_MEM_DUAL_BUS_MIRROR != 0)
+void *
+os_get_dbus_mirror(void *ibus)
+{
+    if (in_ibus_ext(ibus)) {
+        return (void *)((uint8 *)ibus - MEM_DUAL_BUS_OFFSET);
+    }
+    else {
+        return ibus;
+    }
+}
+#endif
 
 /* If AT_FDCWD is provided, maybe we have openat family */
 #if !defined(AT_FDCWD)

+ 123 - 0
core/shared/utils/bh_atomic.h

@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2023 Amazon Inc.  All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#ifndef _BH_ATOMIC_H
+#define _BH_ATOMIC_H
+
+#include "gnuc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Why don't we use C11 stdatomics here?
+ *
+ * Unlike C11 stdatomics,
+ *
+ * - bh_atomic_xxx_t is guaranteed to have the same size as the base type.
+ *   Thus more friendly to our AOT conventions.
+ *
+ * - It's available for C++.
+ *   Although C++23 will have C-compatible stdatomics.h, it isn't widely
+ *   available yet.
+ */
+
+/*
+ * Note about BH_ATOMIC_32_IS_ATOMIC
+ *
+ * If BH_ATOMIC_32_IS_ATOMIC == 0, BH_ATOMIC_xxx operations defined below
+ * are not really atomic and require an external lock.
+ *
+ * Expected usage is:
+ *
+ *     bh_atomic_32_t var = 0;
+ *     uint32 old;
+ * #if BH_ATOMIC_32_IS_ATOMIC == 0
+ *     lock(&some_lock);
+ * #endif
+ *     old = BH_ATOMIC_32_FETCH_AND(var, 1);
+ * #if BH_ATOMIC_32_IS_ATOMIC == 0
+ *     unlock(&some_lock);
+ * #endif
+ */
+
+typedef uint32 bh_atomic_32_t;
+
+#if defined(__GNUC_PREREQ)
+#if __GNUC_PREREQ(4, 7)
+#define CLANG_GCC_HAS_ATOMIC_BUILTIN
+#endif
+#elif defined(__clang__)
+#if __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 0)
+#define CLANG_GCC_HAS_ATOMIC_BUILTIN
+#endif
+#endif
+
+#if defined(CLANG_GCC_HAS_ATOMIC_BUILTIN)
+#define BH_ATOMIC_32_IS_ATOMIC 1
+#define BH_ATOMIC_32_LOAD(v) __atomic_load_n(&(v), __ATOMIC_SEQ_CST)
+#define BH_ATOMIC_32_FETCH_OR(v, val) \
+    __atomic_fetch_or(&(v), (val), __ATOMIC_SEQ_CST)
+#define BH_ATOMIC_32_FETCH_AND(v, val) \
+    __atomic_fetch_and(&(v), (val), __ATOMIC_SEQ_CST)
+#define BH_ATOMIC_32_FETCH_ADD(v, val) \
+    __atomic_fetch_add(&(v), (val), __ATOMIC_SEQ_CST)
+#define BH_ATOMIC_32_FETCH_SUB(v, val) \
+    __atomic_fetch_sub(&(v), (val), __ATOMIC_SEQ_CST)
+#else /* else of defined(CLANG_GCC_HAS_ATOMIC_BUILTIN) */
+#define BH_ATOMIC_32_LOAD(v) (v)
+#define BH_ATOMIC_32_FETCH_OR(v, val) nonatomic_32_fetch_or(&(v), val)
+#define BH_ATOMIC_32_FETCH_AND(v, val) nonatomic_32_fetch_and(&(v), val)
+#define BH_ATOMIC_32_FETCH_ADD(v, val) nonatomic_32_fetch_add(&(v), val)
+#define BH_ATOMIC_32_FETCH_SUB(v, val) nonatomic_32_fetch_sub(&(v), val)
+
+static inline uint32
+nonatomic_32_fetch_or(bh_atomic_32_t *p, uint32 val)
+{
+    uint32 old = *p;
+    *p |= val;
+    return old;
+}
+
+static inline uint32
+nonatomic_32_fetch_and(bh_atomic_32_t *p, uint32 val)
+{
+    uint32 old = *p;
+    *p &= val;
+    return old;
+}
+
+static inline uint32
+nonatomic_32_fetch_add(bh_atomic_32_t *p, uint32 val)
+{
+    uint32 old = *p;
+    *p += val;
+    return old;
+}
+
+static inline uint32
+nonatomic_32_fetch_sub(bh_atomic_32_t *p, uint32 val)
+{
+    uint32 old = *p;
+    *p -= val;
+    return old;
+}
+
+/* The flag can be defined by the user if the platform
+   supports atomic access to uint32 aligned memory. */
+#ifdef WASM_UINT32_IS_ATOMIC
+#define BH_ATOMIC_32_IS_ATOMIC 1
+#else /* else of WASM_UINT32_IS_ATOMIC */
+#define BH_ATOMIC_32_IS_ATOMIC 0
+#endif /* WASM_UINT32_IS_ATOMIC */
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* end of _BH_ATOMIC_H */

+ 0 - 0
core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/gnuc.h → core/shared/utils/gnuc.h


+ 44 - 43
doc/embed_wamr.md

@@ -258,68 +258,69 @@ We can't pass structure data or class objects through the pointer since the memo
 
 ## Execute wasm functions in multiple threads
 
-The `exec_env` is not thread safety, it will cause unexpected behavior if the same `exec_env` is used in multiple threads. However, we've provided two ways to execute wasm functions concurrently:
+It isn't safe to use an `exec_env` object in multiple threads concurrently.
+To run a multi-threaded application, you basically need a separate `exec_env`
+for each threads.
 
-- You can use `pthread` APIs in your wasm application, see [pthread library](./pthread_library.md) for more details.
+### Approaches to manage `exec_env` objects and threads
 
-- The `spawn exec_env` and `spawn thread` APIs are available, you can use these APIs to manage the threads in native:
+WAMR supports two approaches to manage `exec_env` and threads as described
+below.  While they are not exclusive, you usually only need to use one of
+them.
 
-  *spawn exec_env:*
+#### Make your WASM application manage threads
 
-  `spawn exec_env` API spawns a `new_exec_env` base on the original `exec_env`, use can use it in other threads:
+  You can make your WASM application spawn threads by itself,
+  typically using `pthread` APIs like `pthread_create`.
+  See [pthread library](./pthread_library.md) and
+  [pthread implementations](./pthread_impls.md) for more details.
+  In this case, WAMR manages `exec_env` for the spawned threads.
 
-  ```C
-  new_exec_env = wasm_runtime_spawn_exec_env(exec_env);
+#### Make your embedder manage threads
+
+  The `spawn exec_env` and `spawn thread` APIs are available for the embedder.
+  You can use these APIs to manage the threads.
+  See [Thread related embedder API](./embed_wamr_spawn_api.md) for details.
+
+### Other notes about threads
 
-    /* Then you can use new_exec_env in your new thread */
-    module_inst = wasm_runtime_get_module_inst(new_exec_env);
-    func_inst = wasm_runtime_lookup_function(module_inst, ...);
-    wasm_runtime_call_wasm(new_exec_env, func_inst, ...);
+* You can manage the maximum number of threads
 
-  /* you need to use this API to manually destroy the spawned exec_env */
-  wasm_runtime_destroy_spawned_exec_env(new_exec_env);
+  ```C
+  init_args.max_thread_num = THREAD_NUM;
+  /* If this init argument is not set, the default maximum thread number is 4 */
   ```
 
-  *spawn thread:*
+* To share memory among threads, you need to build your WASM application with shared memory
 
-  You can also use `spawn thread` API to avoid manually manage the spawned exec_env:
+  For example, it can be done with `--shared-memory` and `-pthread`.
 
-  ```C
-  wasm_thread_t wasm_tid;
-  void *wamr_thread_cb(wasm_exec_env_t exec_env, void *arg)
-  {
-    module_inst = wasm_runtime_get_module_inst(exec_env);
-    func_inst = wasm_runtime_lookup_function(module_inst, ...);
-    wasm_runtime_call_wasm(exec_env, func_inst, ...);
-  }
-  wasm_runtime_spawn_thread(exec_env, &wasm_tid, wamr_thread_cb, NULL);
-  /* Use wasm_runtime_join_thread to join the spawned thread */
-  wasm_runtime_join_thread(wasm_tid, NULL);
+  ```bash
+    /opt/wasi-sdk/bin/clang -o test.wasm test.c -nostdlib -pthread    \
+      -Wl,--shared-memory,--max-memory=131072                         \
+      -Wl,--no-entry,--export=__heap_base,--export=__data_end         \
+      -Wl,--export=__wasm_call_ctors,--export=${your_func_name}
   ```
 
-**Note1: You can manage the maximum number of threads can be created:**
+* The corresponding threading feature should be enabled while building the runtime
 
-```C
-init_args.max_thread_num = THREAD_NUM;
-/* If this init argument is not set, the default maximum thread number is 4 */
-```
+  - WAMR lib-pthread (legacy)
 
-**Note2: The wasm application should be built with `--shared-memory` and `-pthread` enabled:**
+    ```bash
+    cmake .. -DWAMR_BUILD_LIB_PTHREAD=1
+    ```
 
-```bash
-  /opt/wasi-sdk/bin/clang -o test.wasm test.c -nostdlib -pthread    \
-    -Wl,--shared-memory,--max-memory=131072                         \
-    -Wl,--no-entry,--export=__heap_base,--export=__data_end         \
-    -Wl,--export=__wasm_call_ctors,--export=${your_func_name}
-```
+  - wasi-threads
 
-  **Note3: The pthread library feature should be enabled while building the runtime:**
+    ```bash
+    cmake .. -DWAMR_BUILD_LIB_WASI_THREADS=1
+    ```
 
-  ```bash
-  cmake .. -DWAMR_BUILD_LIB_PTHREAD=1
-  ```
+  - `wasm_runtime_spawn_exec_env` and `wasm_runtime_spawn_thread`
 
-[Here](../samples/spawn-thread) is a sample to show how to use these APIs.
+    ```bash
+    cmake .. -DWAMR_BUILD_THREAD_MGR=1 -DWAMR_BUILD_SHARED_MEMORY=1
+    ```
 
 ## The deinitialization procedure
 

+ 38 - 0
doc/embed_wamr_spawn_api.md

@@ -0,0 +1,38 @@
+# Thread related embedder API
+
+This document explains `wasm_runtime_spawn_exec_env` and
+`wasm_runtime_spawn_thread`.
+[Here](../samples/spawn-thread) is a sample to show how to use these APIs.
+
+  * spawn exec_env
+
+    `spawn exec_env` API creates a new `exec_env` based on the original `exec_env`. You can use it in other threads. It's up to the embedder how to manage host threads to run the new `exec_env`.
+
+    ```C
+    new_exec_env = wasm_runtime_spawn_exec_env(exec_env);
+
+      /* Then you can use new_exec_env in your new thread */
+      module_inst = wasm_runtime_get_module_inst(new_exec_env);
+      func_inst = wasm_runtime_lookup_function(module_inst, ...);
+      wasm_runtime_call_wasm(new_exec_env, func_inst, ...);
+
+    /* you need to use this API to manually destroy the spawned exec_env */
+    wasm_runtime_destroy_spawned_exec_env(new_exec_env);
+    ```
+
+  * spawn thread
+
+    Alternatively, you can use `spawn thread` API to avoid managing the extra exec_env and the corresponding host thread manually:
+
+    ```C
+    wasm_thread_t wasm_tid;
+    void *wamr_thread_cb(wasm_exec_env_t exec_env, void *arg)
+    {
+      module_inst = wasm_runtime_get_module_inst(exec_env);
+      func_inst = wasm_runtime_lookup_function(module_inst, ...);
+      wasm_runtime_call_wasm(exec_env, func_inst, ...);
+    }
+    wasm_runtime_spawn_thread(exec_env, &wasm_tid, wamr_thread_cb, NULL);
+    /* Use wasm_runtime_join_thread to join the spawned thread */
+    wasm_runtime_join_thread(wasm_tid, NULL);
+    ```

+ 3 - 1
product-mini/platforms/esp-idf/build_and_run.sh

@@ -5,14 +5,16 @@
 
 ESP32_TARGET="esp32"
 ESP32C3_TARGET="esp32c3"
+ESP32S3_TARGET="esp32s3"
 
 usage ()
 {
         echo "USAGE:"
-        echo "$0 $ESP32_TARGET|$ESP32C3_TARGET"
+        echo "$0 $ESP32_TARGET|$ESP32C3_TARGET|$ESP32S3_TARGET"
         echo "Example:"
         echo "        $0 $ESP32_TARGET"
         echo "        $0 $ESP32C3_TARGET"
+        echo "        $0 $ESP32S3_TARGET"
         exit 1
 }
 

+ 7 - 1
product-mini/platforms/esp-idf/main/main.c

@@ -12,6 +12,12 @@
 
 #include "esp_log.h"
 
+#ifdef CONFIG_IDF_TARGET_ESP32S3
+#define IWASM_MAIN_STACK_SIZE 5120
+#else
+#define IWASM_MAIN_STACK_SIZE 4096
+#endif
+
 #define LOG_TAG "wamr"
 
 static void *
@@ -146,7 +152,7 @@ app_main(void)
     pthread_attr_t tattr;
     pthread_attr_init(&tattr);
     pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_JOINABLE);
-    pthread_attr_setstacksize(&tattr, 4096);
+    pthread_attr_setstacksize(&tattr, IWASM_MAIN_STACK_SIZE);
 
     res = pthread_create(&t, &tattr, iwasm_main, (void *)NULL);
     assert(res == 0);

+ 64 - 0
product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.cpp

@@ -92,6 +92,8 @@ set_error_buf(char *error_buf, uint32 error_buf_size, const char *string)
         snprintf(error_buf, error_buf_size, "%s", string);
 }
 
+static bool runtime_inited = false;
+
 static void
 handle_cmd_init_runtime(uint64 *args, uint32 argc)
 {
@@ -100,6 +102,12 @@ handle_cmd_init_runtime(uint64 *args, uint32 argc)
 
     bh_assert(argc == 1);
 
+    /* avoid duplicated init */
+    if (runtime_inited) {
+        args[0] = false;
+        return;
+    }
+
     os_set_print_function(enclave_print);
 
     max_thread_num = (uint32)args[0];
@@ -122,6 +130,7 @@ handle_cmd_init_runtime(uint64 *args, uint32 argc)
         return;
     }
 
+    runtime_inited = true;
     args[0] = true;
 
     LOG_VERBOSE("Init runtime environment success.\n");
@@ -130,7 +139,11 @@ handle_cmd_init_runtime(uint64 *args, uint32 argc)
 static void
 handle_cmd_destroy_runtime()
 {
+    if (!runtime_inited)
+        return;
+
     wasm_runtime_destroy();
+    runtime_inited = false;
 
     LOG_VERBOSE("Destroy runtime success.\n");
 }
@@ -214,6 +227,11 @@ handle_cmd_load_module(uint64 *args, uint32 argc)
 
     bh_assert(argc == 4);
 
+    if (!runtime_inited) {
+        *(void **)args_org = NULL;
+        return;
+    }
+
     if (!is_xip_file((uint8 *)wasm_file, wasm_file_size)) {
         if (total_size >= UINT32_MAX
             || !(enclave_module = (EnclaveModule *)wasm_runtime_malloc(
@@ -284,6 +302,10 @@ handle_cmd_unload_module(uint64 *args, uint32 argc)
 
     bh_assert(argc == 1);
 
+    if (!runtime_inited) {
+        return;
+    }
+
 #if WASM_ENABLE_LIB_RATS != 0
     /* Remove enclave module from enclave module list */
     os_mutex_lock(&enclave_module_list_lock);
@@ -354,6 +376,11 @@ handle_cmd_instantiate_module(uint64 *args, uint32 argc)
 
     bh_assert(argc == 5);
 
+    if (!runtime_inited) {
+        *(void **)args_org = NULL;
+        return;
+    }
+
     if (!(module_inst =
               wasm_runtime_instantiate(enclave_module->module, stack_size,
                                        heap_size, error_buf, error_buf_size))) {
@@ -373,6 +400,10 @@ handle_cmd_deinstantiate_module(uint64 *args, uint32 argc)
 
     bh_assert(argc == 1);
 
+    if (!runtime_inited) {
+        return;
+    }
+
     wasm_runtime_deinstantiate(module_inst);
 
     LOG_VERBOSE("Deinstantiate module success.\n");
@@ -389,6 +420,11 @@ handle_cmd_get_exception(uint64 *args, uint32 argc)
 
     bh_assert(argc == 3);
 
+    if (!runtime_inited) {
+        args_org[0] = false;
+        return;
+    }
+
     if ((exception1 = wasm_runtime_get_exception(module_inst))) {
         snprintf(exception, exception_size, "%s", exception1);
         args_org[0] = true;
@@ -410,6 +446,10 @@ handle_cmd_exec_app_main(uint64 *args, int32 argc)
     bh_assert(argc >= 3);
     bh_assert(app_argc >= 1);
 
+    if (!runtime_inited) {
+        return;
+    }
+
     total_size = sizeof(char *) * (app_argc > 2 ? (uint64)app_argc : 2);
 
     if (total_size >= UINT32_MAX
@@ -439,6 +479,10 @@ handle_cmd_exec_app_func(uint64 *args, int32 argc)
 
     bh_assert(argc == app_argc + 3);
 
+    if (!runtime_inited) {
+        return;
+    }
+
     total_size = sizeof(char *) * (app_argc > 2 ? (uint64)app_argc : 2);
 
     if (total_size >= UINT32_MAX
@@ -488,6 +532,11 @@ handle_cmd_set_wasi_args(uint64 *args, int32 argc)
 
     bh_assert(argc == 10);
 
+    if (!runtime_inited) {
+        *args_org = false;
+        return;
+    }
+
     total_size += sizeof(char *) * (uint64)dir_list_size
                   + sizeof(char *) * (uint64)env_list_size
                   + sizeof(char *) * (uint64)addr_pool_list_size
@@ -610,6 +659,11 @@ handle_cmd_get_pgo_prof_buf_size(uint64 *args, int32 argc)
 
     bh_assert(argc == 1);
 
+    if (!runtime_inited) {
+        args[0] = 0;
+        return;
+    }
+
     buf_len = wasm_runtime_get_pgo_prof_data_size(module_inst);
     args[0] = buf_len;
 }
@@ -625,6 +679,11 @@ handle_cmd_get_pro_prof_buf_data(uint64 *args, int32 argc)
 
     bh_assert(argc == 3);
 
+    if (!runtime_inited) {
+        args_org[0] = 0;
+        return;
+    }
+
     bytes_dumped =
         wasm_runtime_dump_pgo_prof_data_to_buf(module_inst, buf, len);
     args_org[0] = bytes_dumped;
@@ -704,6 +763,11 @@ ecall_iwasm_main(uint8_t *wasm_file_buf, uint32_t wasm_file_size)
     char error_buf[128];
     const char *exception;
 
+    /* avoid duplicated init */
+    if (runtime_inited) {
+        return;
+    }
+
     os_set_print_function(enclave_print);
 
     memset(&init_args, 0, sizeof(RuntimeInitArgs));

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

@@ -141,6 +141,12 @@ else
 CFLAGS += -DWASM_ENABLE_WORD_ALIGN_READ=0
 endif
 
+ifeq ($(CONFIG_INTERPRETERS_WAMR_MEM_DUAL_BUS_MIRROR),y)
+CFLAGS += -DWASM_MEM_DUAL_BUS_MIRROR=1
+else
+CFLAGS += -DWASM_MEM_DUAL_BUS_MIRROR=0
+endif
+
 ifeq ($(CONFIG_INTERPRETERS_WAMR_FAST), y)
 CFLAGS += -DWASM_ENABLE_FAST_INTERP=1
 CFLAGS += -DWASM_ENABLE_INTERP=1

+ 20 - 0
samples/bh_atomic/CMakeLists.txt

@@ -0,0 +1,20 @@
+# Copyright (C) 2023 Midokura Japan KK.  All rights reserved.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+cmake_minimum_required(VERSION 3.0)
+project(bh_atomic)
+
+string (TOLOWER ${CMAKE_HOST_SYSTEM_NAME} WAMR_BUILD_PLATFORM)
+if(APPLE)
+  add_definitions(-DBH_PLATFORM_DARWIN)
+endif()
+
+set(WAMR_BUILD_INTERP 1)
+set(WAMR_BUILD_LIBC_BUILTIN 0)
+
+set(WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../..)
+include(${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake)
+
+add_executable(bh_atomic main.c)
+
+target_link_libraries(bh_atomic)

+ 42 - 0
samples/bh_atomic/main.c

@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2023 Midokura Japan KK.  All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#include <assert.h>
+
+#include "bh_platform.h"
+#include "bh_atomic.h"
+
+int
+main(int argc, char **argv)
+{
+    bh_atomic_32_t v;
+    uint32 o;
+
+    v = 0x00ff00ff;
+    o = BH_ATOMIC_32_LOAD(v);
+    assert(o == 0x00ff00ff);
+
+    v = 0x00ff00ff;
+    o = BH_ATOMIC_32_FETCH_OR(v, 0xffff0000);
+    assert(o == 0x00ff00ff);
+    assert(v == 0xffff00ff);
+
+    v = 0x00ff00ff;
+    o = BH_ATOMIC_32_FETCH_AND(v, 0xffff0000);
+    assert(o == 0x00ff00ff);
+    assert(v == 0x00ff0000);
+
+    v = 0x00ff00ff;
+    o = BH_ATOMIC_32_FETCH_ADD(v, 0x10101);
+    assert(o == 0x00ff00ff);
+    assert(v == 0x00ff00ff + 0x10101);
+
+    v = 0x00ff00ff;
+    o = BH_ATOMIC_32_FETCH_SUB(v, 0x10101);
+    assert(o == 0x00ff00ff);
+    assert(v == 0x00ff00ff - 0x10101);
+
+    return 0;
+}

+ 183 - 132
samples/workload/XNNPACK/CMakeLists.txt

@@ -1,147 +1,198 @@
 # Copyright (C) 2019 Intel Corporation. All rights reserved.
 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 
-cmake_minimum_required (VERSION 3.0)
+cmake_minimum_required (VERSION 3.14)
 
 project(xnnpack_wasm)
 
 ################  EMCC ################
 include(ExternalProject)
 
-ExternalProject_Add(xnnpack
+# grep xnnpack_benchmark -A 1 BUILD.bazel \
+#   | grep "name =" \
+#   | awk '{print $3}' \
+#   | sed -e 's/\"//g; s/,//g; s/^/\"/g; s/$/\"/g'
+list(APPEND NATIVE_BENCHMARKS
+  "qs8_dwconv_bench"
+  "qs8_f32_vcvt_bench"
+  "qs8_gemm_bench"
+  "qs8_requantization_bench"
+  "qs8_vadd_bench"
+  "qs8_vaddc_bench"
+  "qs8_vcvt_bench"
+  "qs16_qs8_vcvt_bench"
+  "qs8_vlrelu_bench"
+  "qs8_vmul_bench"
+  "qs8_vmulc_bench"
+  "qu8_f32_vcvt_bench"
+  "qu8_gemm_bench"
+  "qu8_requantization_bench"
+  "qu8_vadd_bench"
+  "qu8_vaddc_bench"
+  "qu8_vcvt_bench"
+  "qu8_vlrelu_bench"
+  "qu8_vmul_bench"
+  "qu8_vmulc_bench"
+  "bf16_gemm_bench"
+  "f16_f32acc_igemm_bench"
+  "f16_igemm_bench"
+  "f16_f32acc_gemm_bench"
+  "f16_gemm_bench"
+  "f16_raddstoreexpminusmax_bench"
+  "f16_spmm_bench"
+  "f16_vsigmoid_bench"
+  "f16_vtanh_bench"
+  "f16_f32_vcvt_bench"
+  "f32_igemm_bench"
+  "f32_conv_hwc_bench"
+  "f16_conv_hwc2chw_bench"
+  "f16_gavgpool_cw_bench"
+  "f32_gavgpool_cw_bench"
+  "f32_conv_hwc2chw_bench"
+  "f16_dwconv_bench"
+  "f32_dwconv_bench"
+  "f32_dwconv2d_chw_bench"
+  "f16_dwconv2d_chw_bench"
+  "f32_f16_vcvt_bench"
+  "xx_transpose_bench"
+  "x8_transpose_bench"
+  "x16_transpose_bench"
+  "x24_transpose_bench"
+  "x32_transpose_bench"
+  "x64_transpose_bench"
+  "f32_bgemm_bench"
+  "f32_gemm_bench"
+  "f32_qs8_vcvt_bench"
+  "f32_qu8_vcvt_bench"
+  "f32_raddexpminusmax_bench"
+  "f32_raddextexp_bench"
+  "f32_raddstoreexpminusmax_bench"
+  "f32_rmax_bench"
+  "f32_spmm_bench"
+  "f32_softmax_bench"
+  "f16_velu_bench"
+  "f32_velu_bench"
+  "f32_vhswish_bench"
+  "f32_vlrelu_bench"
+  "f32_vrelu_bench"
+  "f32_vscaleexpminusmax_bench"
+  "f32_vscaleextexp_bench"
+  "f32_vsigmoid_bench"
+  "f16_vsqrt_bench"
+  "f32_vsqrt_bench"
+  "f32_vtanh_bench"
+  "f32_im2col_gemm_bench"
+  "rounding_bench"
+  "s16_rmaxabs_bench"
+  "s16_window_bench"
+  "u32_filterbank_accumulate_bench"
+  "u32_filterbank_subtract_bench"
+  "u32_vlog_bench"
+  "u64_u32_vsqrtshift_bench"
+  "i16_vlshift_bench"
+  "cs16_vsquareabs_bench"
+  "cs16_bfly4_bench"
+  "cs16_fftr_bench"
+  "x8_lut_bench"
+  "x32_packw_bench"
+  "x16_packw_bench"
+  "abs_bench"
+  "average_pooling_bench"
+  "bankers_rounding_bench"
+  "ceiling_bench"
+  "channel_shuffle_bench"
+  "convert_bench"
+  "convolution_bench"
+  "deconvolution_bench"
+  "elu_bench"
+  "floor_bench"
+  "global_average_pooling_bench"
+  "hardswish_bench"
+  "leaky_relu_bench"
+  "max_pooling_bench"
+  "negate_bench"
+  "prelu_bench"
+  "sigmoid_bench"
+  "softmax_bench"
+  "square_bench"
+  "square_root_bench"
+  "tanh_bench"
+  "truncation_bench"
+  "f16_dwconv_e2e_bench"
+  "f16_gemm_e2e_bench"
+  "f32_dwconv_e2e_bench"
+  "f32_gemm_e2e_bench"
+  "qs8_dwconv_e2e_bench"
+  "qs8_gemm_e2e_bench"
+  "qu8_gemm_e2e_bench"
+  "qu8_dwconv_e2e_bench"
+  "end2end_bench"
+  "f16_exp_ulp_eval"
+  "f16_expminus_ulp_eval"
+  "f16_expm1minus_ulp_eval"
+  "f16_sigmoid_ulp_eval"
+  "f16_sqrt_ulp_eval"
+  "f16_tanh_ulp_eval"
+  "f32_exp_ulp_eval"
+  "f32_expminus_ulp_eval"
+  "f32_expm1minus_ulp_eval"
+  "f32_extexp_ulp_eval"
+  "f32_sigmoid_ulp_eval"
+  "f32_sqrt_ulp_eval"
+  "f32_tanh_ulp_eval"
+)
+
+# Only Download
+ExternalProject_Add(xnnpack-download
     PREFIX xnnpack
     GIT_REPOSITORY https://github.com/google/XNNPACK.git
-    GIT_TAG        4570a7151aa4f3e57eca14a575eeff6bb13e26be
+    GIT_TAG        b9d4073a6913891ce9cbd8965c8d506075d2a45a
     GIT_PROGRESS   ON
     SOURCE_DIR     ${CMAKE_CURRENT_SOURCE_DIR}/xnnpack
-    UPDATE_COMMAND git restore .
-                   && cmake -E copy ${CMAKE_CURRENT_SOURCE_DIR}/xnnpack/google3/third_party/XNNPACK/microkernels.bzl
-                      ${CMAKE_CURRENT_SOURCE_DIR}/xnnpack/
-                   && git apply ${CMAKE_CURRENT_SOURCE_DIR}/xnnpack.patch
+    UPDATE_COMMAND ""
+    PATCH_COMMAND git apply ${CMAKE_CURRENT_SOURCE_DIR}/xnnpack.patch
     CONFIGURE_COMMAND ""
-    # grep xnnpack_benchmark -A 1 BUILD.bazel \
-    #   | grep "name =" \
-    #   | awk '{print $3}' \
-    #   | sed -e 's/\"//g' -e 's/,//g' -e 's/^/\/\/:/g'
-    BUILD_COMMAND  cd ${CMAKE_CURRENT_SOURCE_DIR}/xnnpack
-                   && bazel --output_user_root=build-user-output build -c opt --config=wasm
-                       //:qs8_dwconv_bench.wasm
-                       //:qs8_f32_vcvt_bench.wasm
-                       //:qs8_gemm_bench.wasm
-                       //:qs8_requantization_bench.wasm
-                       //:qs8_vadd_bench.wasm
-                       //:qs8_vaddc_bench.wasm
-                       //:qs8_vcvt_bench.wasm
-                       //:qs8_vlrelu_bench.wasm
-                       //:qs8_vmul_bench.wasm
-                       //:qs8_vmulc_bench.wasm
-                       //:qu8_f32_vcvt_bench.wasm
-                       //:qu8_gemm_bench.wasm
-                       //:qu8_requantization_bench.wasm
-                       //:qu8_vadd_bench.wasm
-                       //:qu8_vaddc_bench.wasm
-                       //:qu8_vcvt_bench.wasm
-                       //:qu8_vlrelu_bench.wasm
-                       //:qu8_vmul_bench.wasm
-                       //:qu8_vmulc_bench.wasm
-                       //:bf16_gemm_bench.wasm
-                       //:f16_igemm_bench.wasm
-                       //:f16_gemm_bench.wasm
-                       //:f16_raddstoreexpminusmax_bench.wasm
-                       //:f16_spmm_bench.wasm
-                       //:f16_vsigmoid_bench.wasm
-                       //:f16_f32_vcvt_bench.wasm
-                       //:f32_igemm_bench.wasm
-                       //:f32_conv_hwc_bench.wasm
-                       //:f16_conv_hwc2chw_bench.wasm
-                       //:f16_gavgpool_cw_bench.wasm
-                       //:f32_gavgpool_cw_bench.wasm
-                       //:f32_conv_hwc2chw_bench.wasm
-                       //:f16_dwconv_bench.wasm
-                       //:f32_dwconv_bench.wasm
-                       //:f32_dwconv2d_chw_bench.wasm
-                       //:f16_dwconv2d_chw_bench.wasm
-                       //:f32_f16_vcvt_bench.wasm
-                       //:xx_transpose_bench.wasm
-                       //:x8_transpose_bench.wasm
-                       //:x16_transpose_bench.wasm
-                       //:x24_transpose_bench.wasm
-                       //:x32_transpose_bench.wasm
-                       //:x64_transpose_bench.wasm
-                       //:f32_gemm_bench.wasm
-                       //:f32_qs8_vcvt_bench.wasm
-                       //:f32_qu8_vcvt_bench.wasm
-                       //:f32_raddexpminusmax_bench.wasm
-                       //:f32_raddextexp_bench.wasm
-                       //:f32_raddstoreexpminusmax_bench.wasm
-                       //:f32_rmax_bench.wasm
-                       //:f32_spmm_bench.wasm
-                       //:f32_softmax_bench.wasm
-                       //:f16_velu_bench.wasm
-                       //:f32_velu_bench.wasm
-                       //:f32_vhswish_bench.wasm
-                       //:f32_vlrelu_bench.wasm
-                       //:f32_vrelu_bench.wasm
-                       //:f32_vscaleexpminusmax_bench.wasm
-                       //:f32_vscaleextexp_bench.wasm
-                       //:f32_vsigmoid_bench.wasm
-                       //:f16_vsqrt_bench.wasm
-                       //:f32_vsqrt_bench.wasm
-                       //:f32_im2col_gemm_bench.wasm
-                       //:rounding_bench.wasm
-                       //:s16_rmaxabs_bench.wasm
-                       //:s16_window_bench.wasm
-                       //:u32_filterbank_accumulate_bench.wasm
-                       //:u32_filterbank_subtract_bench.wasm
-                       //:u32_vlog_bench.wasm
-                       //:u64_u32_vsqrtshift_bench.wasm
-                       //:i16_vlshift_bench.wasm
-                       //:cs16_vsquareabs_bench.wasm
-                       //:cs16_bfly4_bench.wasm
-                       //:cs16_fftr_bench.wasm
-                       //:x8_lut_bench.wasm
-                       //:abs_bench.wasm
-                       //:average_pooling_bench.wasm
-                       //:bankers_rounding_bench.wasm
-                       //:ceiling_bench.wasm
-                       //:channel_shuffle_bench.wasm
-                       //:convert_bench.wasm
-                       //:convolution_bench.wasm
-                       //:deconvolution_bench.wasm
-                       //:elu_bench.wasm
-                       //:floor_bench.wasm
-                       //:global_average_pooling_bench.wasm
-                       //:hardswish_bench.wasm
-                       //:leaky_relu_bench.wasm
-                       //:max_pooling_bench.wasm
-                       //:negate_bench.wasm
-                       //:sigmoid_bench.wasm
-                       //:prelu_bench.wasm
-                       //:softmax_bench.wasm
-                       //:square_bench.wasm
-                       //:square_root_bench.wasm
-                       //:truncation_bench.wasm
-                       //:f16_gemm_e2e_bench.wasm
-                       //:f32_dwconv_e2e_bench.wasm
-                       //:f32_gemm_e2e_bench.wasm
-                       //:qs8_dwconv_e2e_bench.wasm
-                       //:qs8_gemm_e2e_bench.wasm
-                       //:qu8_gemm_e2e_bench.wasm
-                       //:qu8_dwconv_e2e_bench.wasm
-                       //:end2end_bench.wasm
-                       //:f16_exp_ulp_eval.wasm
-                       //:f16_expminus_ulp_eval.wasm
-                       //:f16_expm1minus_ulp_eval.wasm
-                       //:f16_sigmoid_ulp_eval.wasm
-                       //:f16_sqrt_ulp_eval.wasm
-                       //:f32_exp_ulp_eval.wasm
-                       //:f32_expminus_ulp_eval.wasm
-                       //:f32_expm1minus_ulp_eval.wasm
-                       //:f32_extexp_ulp_eval.wasm
-                       //:f32_sigmoid_ulp_eval.wasm
-                       //:f32_sqrt_ulp_eval.wasm
-                       //:f32_tanh_ulp_eval.wasm
-    INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_directory
-                      ${CMAKE_CURRENT_SOURCE_DIR}/xnnpack/bazel-out/wasm-opt/bin/
-                      ${CMAKE_BINARY_DIR}/wasm-opt
+    BUILD_COMMAND ""
+    INSTALL_COMMAND ""
+    TEST_COMMAND ""
 )
+
+set(WAMRC "${CMAKE_CURRENT_SOURCE_DIR}/../../../wamr-compiler/build/wamrc")
+if(EXISTS ${WAMRC})
+  message("-- Will generate .aot")
+else()
+  message("Will generate .wasm")
+endif()
+
+foreach(BENCHMARK IN LISTS NATIVE_BENCHMARKS)
+  string(CONCAT WASM_BENCHMARK "//:" ${BENCHMARK} "-wasm")
+  string(CONCAT WASM_OUTPUT ${BENCHMARK} ".wasm")
+
+  add_custom_command(
+    OUTPUT ${WASM_OUTPUT}
+    COMMAND bazel --output_user_root=build-user-output build -c opt --config=wasm ${WASM_BENCHMARK}
+              && ${CMAKE_COMMAND} -E copy_if_different ./bazel-bin/${WASM_OUTPUT} ${CMAKE_CURRENT_BINARY_DIR}/${WASM_OUTPUT}
+    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/xnnpack
+    DEPENDS xnnpack-download
+    COMMENT "Generating ${WASM_OUTPUT} ..."
+  )
+
+  set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_CLEAN_FILES ${CMAKE_CURRENT_BINARY_DIR}/${WASM_OUTPUT})
+
+  if(EXISTS ${WAMRC})
+    string(CONCAT AOT_OUTPUT ${BENCHMARK} ".aot")
+
+    add_custom_command(
+      OUTPUT ${AOT_OUTPUT}
+      COMMAND ${WAMRC} -o ${AOT_OUTPUT} ${WASM_OUTPUT}
+      WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+      DEPENDS ${WASM_OUTPUT}
+      COMMENT "Generating ${AOT_OUTPUT} ..."
+    )
+
+    add_custom_target(${BENCHMARK} ALL DEPENDS ${AOT_OUTPUT})
+  else()
+    add_custom_target(${BENCHMARK} ALL DEPENDS ${WASM_OUTPUT})
+  endif()
+endforeach()
+

+ 21 - 20
samples/workload/XNNPACK/README.md

@@ -9,17 +9,29 @@ please refer to [installation instructions](../README.md).
 
 ## Build XNNPACK
 
-```bash
-cd <wamr-dir>/samples/workload/XNNPACK
-mkdir build
-cd build
+please build wamrc:
+
+``` bash
+cd <wamr-dir>/wamr-compiler
+./build_llvm.sh
+mkdir build && cd build
 cmake ..
+make
+```
+
+And then build xnnpack standalone wasm files
+
+```bash
+$ cd <wamr-dir>/samples/workload/XNNPACK
+$ cmake -S . -B build
+$ cmake --build build
 ```
-The wasm files are generated under folder samples/workload/XNNPACK/xnnpack/bazel-bin.
+
+Generated .wasm(and .aot) files are under *samples/workload/XNNPACK/build*.
 
 ## Run benchmarks
 
-Firstly please build iwasm with simd, libc-emcc and lib-pthread support:
+Firstly please build iwasm with simd, libc-emcc and lib-pthread supporting:
 
 ``` bash
 $ cd <wamr-dir>/product-mini/platforms/linux/
@@ -28,21 +40,10 @@ $ cmake .. -DWAMR_BUILD_LIBC_EMCC=1 -DWAMR_BUILD_LIB_PTHREAD=1
 $ make
 ```
 
-And please build wamrc:
-
-``` bash
-cd <wamr-dir>/wamr-compiler
-./build_llvm.sh
-mkdir build && cd build
-cmake ..
-make
-```
-
-Then compile wasm file to aot file and run:
+Then run:
 
 ``` shell
-$ cd <wamr-dir>/samples/workload/XNNPACK/xnnpack/bazel-bin
-$ wamrc -o average_pooling_bench.aot average_pooling_bench.wasm  (or other wasm files)
-$ iwasm average_pooling_bench.aot
+$ cd <wamr-dir>/samples/workload/XNNPACK/build
+$ iwasm average_pooling_bench.aot # (or other aot files)
 ```
 

+ 95 - 98
samples/workload/XNNPACK/xnnpack.patch

@@ -1,141 +1,138 @@
 diff --git a/.bazelrc b/.bazelrc
-index 688279da1..376996885 100644
+index fcaff1063..e61d53337 100644
 --- a/.bazelrc
 +++ b/.bazelrc
-@@ -53,4 +53,9 @@ build:ios_fat --watchos_cpus=armv7k
- build:macos --apple_platform_type=macos
+@@ -1,6 +1,7 @@
+ # Basic build settings
+ build --jobs 128
+ build --cxxopt='-std=gnu++14'
++build --incompatible_enable_cc_toolchain_resolution
+ 
+ # Sets the default Apple platform to macOS.
+ build --apple_platform_type=macos
+@@ -55,3 +56,10 @@ build:macos --apple_platform_type=macos
  
  build:macos_arm64 --config=macos
--build:macos_arm64 --cpu=darwin_arm64
-\ No newline at end of file
-+build:macos_arm64 --cpu=darwin_arm64
+ build:macos_arm64 --cpu=darwin_arm64
 +
++# Emscripten configs
++build:wasm --copt="-Wno-unused"
++build:wasm --copt="-Wno-unused-function"
++build:wasm --copt="-Wno-unused-but-set-variable"
 +build:wasm --cpu=wasm
 +build:wasm --features=wasm_simd
-+build:wasm --crosstool_top=@emsdk//emscripten_toolchain:everything
-+build:wasm --host_crosstool_top=@bazel_tools//tools/cpp:toolchain
 diff --git a/WORKSPACE b/WORKSPACE
-index cd8960ffa..787e03ca8 100644
+index 2e568088b..3961371ca 100644
 --- a/WORKSPACE
 +++ b/WORKSPACE
-@@ -29,8 +29,9 @@ http_archive(
- # Google Benchmark library, used in micro-benchmarks.
- http_archive(
-     name = "com_google_benchmark",
--    strip_prefix = "benchmark-main",
--    urls = ["https://github.com/google/benchmark/archive/main.zip"],
-+    sha256 = "1ba14374fddcd9623f126b1a60945e4deac4cdc4fb25a5f25e7f779e36f2db52",
-+    strip_prefix = "benchmark-d2a8a4ee41b923876c034afb939c4fc03598e622",
-+    urls = ["https://github.com/google/benchmark/archive/d2a8a4ee41b923876c034afb939c4fc03598e622.zip"],
+@@ -83,7 +83,23 @@ http_archive(
  )
  
- # FP16 library, used for half-precision conversions
-@@ -92,8 +93,25 @@ http_archive(
-     ],
- )
+ # Android NDK location and version is auto-detected from $ANDROID_NDK_HOME environment variable
+-android_ndk_repository(name = "androidndk")
++# android_ndk_repository(name = "androidndk")
  
-+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
+ # Android SDK location and API is auto-detected from $ANDROID_HOME environment variable
+-android_sdk_repository(name = "androidsdk")
++# android_sdk_repository(name = "androidsdk")
++
 +http_archive(
 +    name = "emsdk",
-+    # Use emsdk-3.0.0 since the larger version may:
-+    #   - compress the wasm file into a tar file but not directly generate wasm file
-+    #   - generate incomplete implementation of libc API, e.g. throw exception in getentropy
-+    strip_prefix = "emsdk-3.0.0/bazel",
-+    url = "https://github.com/emscripten-core/emsdk/archive/refs/tags/3.0.0.tar.gz",
-+    sha256 = "a41dccfd15be9e85f923efaa0ac21943cbab77ec8d39e52f25eca1ec61a9ac9e"
++    sha256 = "5fa6f5eb45a4d50264610c4c9e1c155535359b63bfaad69b4e5101d16c1e7e32",
++    strip_prefix = "emsdk-a896e3d066448b3530dbcaa48869fafefd738f57/bazel",
++    url = "https://github.com/emscripten-core/emsdk/archive/a896e3d066448b3530dbcaa48869fafefd738f57.tar.gz",
 +)
 +
 +load("@emsdk//:deps.bzl", emsdk_deps = "deps")
 +emsdk_deps()
 +
 +load("@emsdk//:emscripten_deps.bzl", emsdk_emscripten_deps = "emscripten_deps")
-+emsdk_emscripten_deps()
++emsdk_emscripten_deps(emscripten_version = "3.1.44")
 +
- # Android NDK location and version is auto-detected from $ANDROID_NDK_HOME environment variable
--android_ndk_repository(name = "androidndk")
-+#android_ndk_repository(name = "androidndk")
++load("@emsdk//:toolchains.bzl", "register_emscripten_toolchains")
++register_emscripten_toolchains()
+diff --git a/bench/utils.cc b/bench/utils.cc
+index 3b32503a7..656845336 100644
+--- a/bench/utils.cc
++++ b/bench/utils.cc
+@@ -456,3 +456,13 @@ CodeMemoryHelper::~CodeMemoryHelper() {
  
- # Android SDK location and API is auto-detected from $ANDROID_HOME environment variable
--android_sdk_repository(name = "androidsdk")
-+#android_sdk_repository(name = "androidsdk")
+ }  // namespace utils
+ }  // namespace benchmark
++
++
++extern "C"
++__attribute__((import_module("env"), import_name("getentropy"))) int import_getentropy(void* buffer, size_t length);
++
++extern "C"
++int getentropy(void* buffer, size_t length)
++{
++  return import_getentropy(buffer, length);
++}
 diff --git a/build_defs.bzl b/build_defs.bzl
-index b8217a18d..6f2d1675e 100644
+index 01b436eb7..2738fd50a 100644
 --- a/build_defs.bzl
 +++ b/build_defs.bzl
-@@ -380,7 +380,7 @@ def xnnpack_benchmark(name, srcs, copts = [], deps = [], tags = []):
-             explicitly specified.
-     """
-     native.cc_binary(
--        name = name,
-+        name = name + ".wasm",
-         srcs = srcs,
-         copts = xnnpack_std_cxxopts() + [
-             "-Iinclude",
-@@ -405,5 +405,5 @@ def xnnpack_benchmark(name, srcs, copts = [], deps = [], tags = []):
+@@ -1,6 +1,7 @@
+ """Build definitions and rules for XNNPACK."""
+ 
+-load(":emscripten.bzl", "xnnpack_emscripten_benchmark_linkopts", "xnnpack_emscripten_deps", "xnnpack_emscripten_minimal_linkopts", "xnnpack_emscripten_test_linkopts")
++load(":emscripten.bzl", "xnnpack_emscripten_benchmark_linkopts", "xnnpack_emscripten_deps", "xnnpack_emscripten_minimal_linkopts", "xnnpack_emscripten_test_linkopts", "xnnpack_emscripten_standalone_benchmark_linkopts")
++load("@emsdk//emscripten_toolchain:wasm_rules.bzl", "wasm_cc_binary")
+ 
+ def xnnpack_visibility():
+     """Visibility of :XNNPACK target.
+@@ -393,7 +394,8 @@ def xnnpack_benchmark(name, srcs, copts = [], deps = [], tags = []):
+             "//conditions:default": ["-Wno-unused-function"],
+         }) + copts,
+         linkopts = select({
+-            ":emscripten": xnnpack_emscripten_benchmark_linkopts(),
++            ":emscripten": xnnpack_emscripten_standalone_benchmark_linkopts(),
++            ":emscripten_wasmsimd": xnnpack_emscripten_standalone_benchmark_linkopts(),
+             ":windows_x86_64_mingw": ["-lshlwapi"],
+             ":windows_x86_64_msys": ["-lshlwapi"],
+             "//conditions:default": [],
+@@ -405,5 +407,16 @@ def xnnpack_benchmark(name, srcs, copts = [], deps = [], tags = []):
              ":emscripten": xnnpack_emscripten_deps(),
              "//conditions:default": [],
          }),
 -	tags = tags,
-+	    tags = tags,
++        tags = tags,
++    )
++
++    wasm_cc_binary(
++        name = name + "-wasm",
++        cc_target = ":" + name,
++        threads = "off",
++        simd = True,
++        standalone= True,
++        outputs = [
++            name + ".wasm",
++        ]
      )
 diff --git a/emscripten.bzl b/emscripten.bzl
-index f1557a7b1..7f964a094 100644
+index f1557a7b1..a3c4f93b9 100644
 --- a/emscripten.bzl
 +++ b/emscripten.bzl
-@@ -25,12 +25,19 @@ def xnnpack_emscripten_benchmark_linkopts():
-     """Emscripten-specific linkopts for benchmarks."""
-     return [
-         "-s ASSERTIONS=1",
--        "-s ENVIRONMENT=node,shell,web",
--        "-s ERROR_ON_UNDEFINED_SYMBOLS=1",
--        "-s EXIT_RUNTIME=1",
+@@ -33,6 +33,21 @@ def xnnpack_emscripten_benchmark_linkopts():
+         "--pre-js $(location :preamble.js.lds)",
+     ]
+ 
++def xnnpack_emscripten_standalone_benchmark_linkopts():
++    return [
++        "-s ASSERTIONS=1",
 +        "-s ERROR_ON_UNDEFINED_SYMBOLS=0",
-         "-s ALLOW_MEMORY_GROWTH=1",
-         "-s TOTAL_MEMORY=536870912",  # 512M
--        "--pre-js $(location :preamble.js.lds)",
++        "-s ALLOW_MEMORY_GROWTH=1",
++        "-s TOTAL_MEMORY=536870912",  # 512M
 +        "-s USE_PTHREADS=0",
 +        "-s STANDALONE_WASM=1",
-+        "-Wno-unused",
-+        "-Wno-unused-variable",
-+        "-Wno-unused-command-line-argument",
 +        "-Wl,--export=__heap_base",
 +        "-Wl,--export=__data_end",
 +        "-Wl,--export=malloc",
 +        "-Wl,--export=free",
-+        "--oformat=wasm",
-     ]
- 
++    ]
++
++
  def xnnpack_emscripten_deps():
-diff --git a/src/log.c b/src/log.c
-index 5715f2f85..4b3e4261b 100644
---- a/src/log.c
-+++ b/src/log.c
-@@ -55,7 +55,7 @@
- #endif
- 
- #if XNN_LOG_TO_STDIO
--static void xnn_vlog(int output_handle, const char* prefix, size_t prefix_length, const char* format, va_list args) {
-+void xnn_vlog(int output_handle, const char* prefix, size_t prefix_length, const char* format, va_list args) {
-   char stack_buffer[XNN_LOG_STACK_BUFFER_SIZE];
-   char* heap_buffer = NULL;
-   char* out_buffer = &stack_buffer[0];
-diff --git a/third_party/cpuinfo.BUILD b/third_party/cpuinfo.BUILD
-index 1997f4e3a..5e03c43af 100644
---- a/third_party/cpuinfo.BUILD
-+++ b/third_party/cpuinfo.BUILD
-@@ -150,7 +150,7 @@ cc_library(
-         "src/arm/midr.h",
-     ],
-     deps = [
--        "@clog",
-+        "//deps/clog"
-     ],
- )
- 
-@@ -352,5 +352,5 @@ config_setting(
- 
- config_setting(
-     name = "emscripten",
--    values = {"crosstool_top": "//toolchain:emscripten"},
-+    values = {"crosstool_top": "@emsdk//emscripten_toolchain:everything"},
- )
+     """Emscripten-specific dependencies for unit tests and benchmarks."""
+     return [

+ 334 - 160
test-tools/host-tool/external/cJSON/cJSON.c

@@ -1,24 +1,24 @@
 /*
- Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
- */
+  Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
+
+  Permission is hereby granted, free of charge, to any person obtaining a copy
+  of this software and associated documentation files (the "Software"), to deal
+  in the Software without restriction, including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included in
+  all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+  THE SOFTWARE.
+*/
 
 /* cJSON */
 /* JSON parser in C. */
@@ -43,6 +43,7 @@
 #include <stdlib.h>
 #include <limits.h>
 #include <ctype.h>
+#include <float.h>
 
 #ifdef ENABLE_LOCALES
 #include <locale.h>
@@ -58,9 +59,33 @@
 #include "cJSON.h"
 
 /* define our own boolean type */
+#ifdef true
+#undef true
+#endif
 #define true ((cJSON_bool)1)
+
+#ifdef false
+#undef false
+#endif
 #define false ((cJSON_bool)0)
 
+/* define isnan and isinf for ANSI C, if in C99 or above, isnan and isinf has
+ * been defined in math.h */
+#ifndef isinf
+#define isinf(d) (isnan((d - d)) && !isnan(d))
+#endif
+#ifndef isnan
+#define isnan(d) (d != d)
+#endif
+
+#ifndef NAN
+#ifdef _WIN32
+#define NAN sqrt(-1.0)
+#else
+#define NAN 0.0 / 0.0
+#endif
+#endif
+
 typedef struct {
     const unsigned char *json;
     size_t position;
@@ -72,7 +97,7 @@ CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void)
     return (const char *)(global_error.json + global_error.position);
 }
 
-CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item)
+CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON *const item)
 {
     if (!cJSON_IsString(item)) {
         return NULL;
@@ -81,18 +106,27 @@ CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item)
     return item->valuestring;
 }
 
+CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON *const item)
+{
+    if (!cJSON_IsNumber(item)) {
+        return (double)NAN;
+    }
+
+    return item->valuedouble;
+}
+
 /* This is a safeguard to prevent copy-pasters from using incompatible C and
  * header files */
 #if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) \
-    || (CJSON_VERSION_PATCH != 10)
+    || (CJSON_VERSION_PATCH != 16)
 #error cJSON.h and cJSON.c have different versions. Make sure that both have the same.
 #endif
 
 CJSON_PUBLIC(const char *) cJSON_Version(void)
 {
     static char version[15];
-    snprintf(version, sizeof(version), "%i.%i.%i", CJSON_VERSION_MAJOR,
-             CJSON_VERSION_MINOR, CJSON_VERSION_PATCH);
+    sprintf(version, "%i.%i.%i", CJSON_VERSION_MAJOR, CJSON_VERSION_MINOR,
+            CJSON_VERSION_PATCH);
 
     return version;
 }
@@ -127,8 +161,8 @@ typedef struct internal_hooks {
 } internal_hooks;
 
 #if defined(_MSC_VER)
-/* work around MSVC error C2322: '...' address of dillimport '...'
-   is not static */
+/* work around MSVC error C2322: '...' address of dllimport '...' is not static
+ */
 static void *CJSON_CDECL
 internal_malloc(size_t size)
 {
@@ -150,13 +184,11 @@ internal_realloc(void *pointer, size_t size)
 #define internal_realloc realloc
 #endif
 
-/* clang-format off */
-static internal_hooks global_hooks = {
-    internal_malloc,
-    internal_free,
-    internal_realloc
-};
-/* clang-format on */
+/* strlen of character literals resolved at compile time */
+#define static_strlen(string_literal) (sizeof(string_literal) - sizeof(""))
+
+static internal_hooks global_hooks = { internal_malloc, internal_free,
+                                       internal_realloc };
 
 static unsigned char *
 cJSON_strdup(const unsigned char *string, const internal_hooks *const hooks)
@@ -271,8 +303,8 @@ typedef struct {
 /* get a pointer to the buffer at the position */
 #define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset)
 
-/* Parse the input text to generate a number, and populate the result
-   into item. */
+/* Parse the input text to generate a number, and populate the result into item.
+ */
 static cJSON_bool
 parse_number(cJSON *const item, parse_buffer *const input_buffer)
 {
@@ -287,9 +319,8 @@ parse_number(cJSON *const item, parse_buffer *const input_buffer)
     }
 
     /* copy the number into a temporary buffer and replace '.' with the decimal
-     * point of the current locale (for strtod)
-     * This also takes care of '\0' not necessarily being available for marking
-     * the end of the input */
+     * point of the current locale (for strtod) This also takes care of '\0' not
+     * necessarily being available for marking the end of the input */
     for (i = 0; (i < (sizeof(number_c_string) - 1))
                 && can_access_at_index(input_buffer, i);
          i++) {
@@ -363,6 +394,32 @@ CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number)
     return object->valuedouble = number;
 }
 
+CJSON_PUBLIC(char *)
+cJSON_SetValuestring(cJSON *object, const char *valuestring)
+{
+    char *copy = NULL;
+    /* if object's type is not cJSON_String or is cJSON_IsReference, it should
+     * not set valuestring */
+    if (!(object->type & cJSON_String) || (object->type & cJSON_IsReference)) {
+        return NULL;
+    }
+    if (strlen(valuestring) <= strlen(object->valuestring)) {
+        strcpy(object->valuestring, valuestring);
+        return object->valuestring;
+    }
+    copy =
+        (char *)cJSON_strdup((const unsigned char *)valuestring, &global_hooks);
+    if (copy == NULL) {
+        return NULL;
+    }
+    if (object->valuestring != NULL) {
+        cJSON_free(object->valuestring);
+    }
+    object->valuestring = copy;
+
+    return copy;
+}
+
 typedef struct {
     unsigned char *buffer;
     size_t length;
@@ -438,9 +495,8 @@ ensure(printbuffer *const p, size_t needed)
 
             return NULL;
         }
-        if (newbuffer) {
-            memcpy(newbuffer, p->buffer, p->offset + 1);
-        }
+
+        memcpy(newbuffer, p->buffer, p->offset + 1);
         p->hooks.deallocate(p->buffer);
     }
     p->length = newsize;
@@ -463,6 +519,14 @@ update_offset(printbuffer *const buffer)
     buffer->offset += strlen((const char *)buffer_pointer);
 }
 
+/* securely comparison of floating-point variables */
+static cJSON_bool
+compare_double(double a, double b)
+{
+    double maxVal = fabs(a) > fabs(b) ? fabs(a) : fabs(b);
+    return (fabs(a - b) <= maxVal * DBL_EPSILON);
+}
+
 /* Render the number nicely from the given item into a string. */
 static cJSON_bool
 print_number(const cJSON *const item, printbuffer *const output_buffer)
@@ -471,35 +535,37 @@ print_number(const cJSON *const item, printbuffer *const output_buffer)
     double d = item->valuedouble;
     int length = 0;
     size_t i = 0;
-    unsigned char
-        number_buffer[26]; /* temporary buffer to print the number into */
+    unsigned char number_buffer[26] = {
+        0
+    }; /* temporary buffer to print the number into */
     unsigned char decimal_point = get_decimal_point();
-    double test;
+    double test = 0.0;
 
     if (output_buffer == NULL) {
         return false;
     }
 
     /* This checks for NaN and Infinity */
-    if ((d * 0) != 0) {
-        length = snprintf((char *)number_buffer, sizeof(number_buffer), "null");
+    if (isnan(d) || isinf(d)) {
+        length = sprintf((char *)number_buffer, "null");
+    }
+    else if (d == (double)item->valueint) {
+        length = sprintf((char *)number_buffer, "%d", item->valueint);
     }
     else {
         /* Try 15 decimal places of precision to avoid nonsignificant nonzero
          * digits */
-        length =
-            snprintf((char *)number_buffer, sizeof(number_buffer), "%1.15g", d);
+        length = sprintf((char *)number_buffer, "%1.15g", d);
 
         /* Check whether the original double can be recovered */
         if ((sscanf((char *)number_buffer, "%lg", &test) != 1)
-            || ((double)test != d)) {
+            || !compare_double((double)test, d)) {
             /* If not, print with 17 decimal places of precision */
-            length = snprintf((char *)number_buffer, sizeof(number_buffer),
-                              "%1.17g", d);
+            length = sprintf((char *)number_buffer, "%1.17g", d);
         }
     }
 
-    /* snprintf failed or buffer overrun occured */
+    /* sprintf failed or buffer overrun occurred */
     if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1))) {
         return false;
     }
@@ -709,8 +775,7 @@ parse_string(cJSON *const item, parse_buffer *const input_buffer)
         if (((size_t)(input_end - input_buffer->content)
              >= input_buffer->length)
             || (*input_end != '\"')) {
-            goto fail;
-            /* string ended unexpectedly */
+            goto fail; /* string ended unexpectedly */
         }
 
         /* This is at most how much we need for the output */
@@ -719,8 +784,7 @@ parse_string(cJSON *const item, parse_buffer *const input_buffer)
         output = (unsigned char *)input_buffer->hooks.allocate(allocation_length
                                                                + sizeof(""));
         if (output == NULL) {
-            goto fail;
-            /* allocation failure */
+            goto fail; /* allocation failure */
         }
     }
 
@@ -759,7 +823,7 @@ parse_string(cJSON *const item, parse_buffer *const input_buffer)
                     *output_pointer++ = input_pointer[1];
                     break;
 
-                    /* UTF-16 literal */
+                /* UTF-16 literal */
                 case 'u':
                     sequence_length = utf16_literal_to_utf8(
                         input_pointer, input_end, &output_pointer);
@@ -805,7 +869,7 @@ print_string_ptr(const unsigned char *const input,
                  printbuffer *const output_buffer)
 {
     const unsigned char *input_pointer = NULL;
-    unsigned char *output = NULL, *output_end;
+    unsigned char *output = NULL;
     unsigned char *output_pointer = NULL;
     size_t output_length = 0;
     /* numbers of additional characters needed for escaping */
@@ -853,7 +917,6 @@ print_string_ptr(const unsigned char *const input,
     if (output == NULL) {
         return false;
     }
-    output_end = output + output_length + sizeof("\"\"");
 
     /* no characters have to be escaped */
     if (escape_characters == 0) {
@@ -902,9 +965,7 @@ print_string_ptr(const unsigned char *const input,
                     break;
                 default:
                     /* escape and print as unicode codepoint */
-                    snprintf((char *)output_pointer,
-                             output_end - output_pointer, "u%04x",
-                             *input_pointer);
+                    sprintf((char *)output_pointer, "u%04x", *input_pointer);
                     output_pointer += 4;
                     break;
             }
@@ -945,6 +1006,10 @@ buffer_skip_whitespace(parse_buffer *const buffer)
         return NULL;
     }
 
+    if (cannot_access_at_index(buffer, 0)) {
+        return buffer;
+    }
+
     while (can_access_at_index(buffer, 0)
            && (buffer_at_offset(buffer)[0] <= 32)) {
         buffer->offset++;
@@ -975,10 +1040,28 @@ skip_utf8_bom(parse_buffer *const buffer)
     return buffer;
 }
 
-/* Parse an object - create a new root, and populate. */
 CJSON_PUBLIC(cJSON *)
 cJSON_ParseWithOpts(const char *value, const char **return_parse_end,
                     cJSON_bool require_null_terminated)
+{
+    size_t buffer_length;
+
+    if (NULL == value) {
+        return NULL;
+    }
+
+    /* Adding null character size due to require_null_terminated. */
+    buffer_length = strlen(value) + sizeof("");
+
+    return cJSON_ParseWithLengthOpts(value, buffer_length, return_parse_end,
+                                     require_null_terminated);
+}
+
+/* Parse an object - create a new root, and populate. */
+CJSON_PUBLIC(cJSON *)
+cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length,
+                          const char **return_parse_end,
+                          cJSON_bool require_null_terminated)
 {
     parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } };
     cJSON *item = NULL;
@@ -987,12 +1070,12 @@ cJSON_ParseWithOpts(const char *value, const char **return_parse_end,
     global_error.json = NULL;
     global_error.position = 0;
 
-    if (value == NULL) {
+    if (value == NULL || 0 == buffer_length) {
         goto fail;
     }
 
     buffer.content = (const unsigned char *)value;
-    buffer.length = strlen((const char *)value) + sizeof("");
+    buffer.length = buffer_length;
     buffer.offset = 0;
     buffer.hooks = global_hooks;
 
@@ -1056,7 +1139,13 @@ CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value)
     return cJSON_ParseWithOpts(value, 0, 0);
 }
 
-#define cjson_min(a, b) ((a < b) ? a : b)
+CJSON_PUBLIC(cJSON *)
+cJSON_ParseWithLength(const char *value, size_t buffer_length)
+{
+    return cJSON_ParseWithLengthOpts(value, buffer_length, 0, 0);
+}
+
+#define cjson_min(a, b) (((a) < (b)) ? (a) : (b))
 
 static unsigned char *
 print(const cJSON *const item, cJSON_bool format,
@@ -1113,6 +1202,10 @@ fail:
         hooks->deallocate(buffer->buffer);
     }
 
+    if (printed != NULL) {
+        hooks->deallocate(printed);
+    }
+
     return NULL;
 }
 
@@ -1156,20 +1249,20 @@ cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt)
 }
 
 CJSON_PUBLIC(cJSON_bool)
-cJSON_PrintPreallocated(cJSON *item, char *buf, const int len,
-                        const cJSON_bool fmt)
+cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length,
+                        const cJSON_bool format)
 {
     printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } };
 
-    if ((len < 0) || (buf == NULL)) {
+    if ((length < 0) || (buffer == NULL)) {
         return false;
     }
 
-    p.buffer = (unsigned char *)buf;
-    p.length = (size_t)len;
+    p.buffer = (unsigned char *)buffer;
+    p.length = (size_t)length;
     p.offset = 0;
     p.noalloc = true;
-    p.format = fmt;
+    p.format = format;
     p.hooks = global_hooks;
 
     return print_value(item, &p);
@@ -1341,8 +1434,7 @@ parse_array(cJSON *const item, parse_buffer *const input_buffer)
         /* allocate next item */
         cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks));
         if (new_item == NULL) {
-            goto fail;
-            /* allocation failure */
+            goto fail; /* allocation failure */
         }
 
         /* attach next item to list */
@@ -1361,8 +1453,7 @@ parse_array(cJSON *const item, parse_buffer *const input_buffer)
         input_buffer->offset++;
         buffer_skip_whitespace(input_buffer);
         if (!parse_value(current_item, input_buffer)) {
-            goto fail;
-            /* failed to parse value */
+            goto fail; /* failed to parse value */
         }
         buffer_skip_whitespace(input_buffer);
     } while (can_access_at_index(input_buffer, 0)
@@ -1370,13 +1461,16 @@ parse_array(cJSON *const item, parse_buffer *const input_buffer)
 
     if (cannot_access_at_index(input_buffer, 0)
         || buffer_at_offset(input_buffer)[0] != ']') {
-        goto fail;
-        /* expected end of array */
+        goto fail; /* expected end of array */
     }
 
 success:
     input_buffer->depth--;
 
+    if (head != NULL) {
+        head->prev = current_item;
+    }
+
     item->type = cJSON_Array;
     item->child = head;
 
@@ -1461,16 +1555,14 @@ parse_object(cJSON *const item, parse_buffer *const input_buffer)
 
     if (cannot_access_at_index(input_buffer, 0)
         || (buffer_at_offset(input_buffer)[0] != '{')) {
-        goto fail;
-        /* not an object */
+        goto fail; /* not an object */
     }
 
     input_buffer->offset++;
     buffer_skip_whitespace(input_buffer);
     if (can_access_at_index(input_buffer, 0)
         && (buffer_at_offset(input_buffer)[0] == '}')) {
-        goto success;
-        /* empty object */
+        goto success; /* empty object */
     }
 
     /* check if we skipped to the end of the buffer */
@@ -1486,8 +1578,7 @@ parse_object(cJSON *const item, parse_buffer *const input_buffer)
         /* allocate next item */
         cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks));
         if (new_item == NULL) {
-            goto fail;
-            /* allocation failure */
+            goto fail; /* allocation failure */
         }
 
         /* attach next item to list */
@@ -1506,8 +1597,7 @@ parse_object(cJSON *const item, parse_buffer *const input_buffer)
         input_buffer->offset++;
         buffer_skip_whitespace(input_buffer);
         if (!parse_string(current_item, input_buffer)) {
-            goto fail;
-            /* faile to parse name */
+            goto fail; /* failed to parse name */
         }
         buffer_skip_whitespace(input_buffer);
 
@@ -1517,16 +1607,14 @@ parse_object(cJSON *const item, parse_buffer *const input_buffer)
 
         if (cannot_access_at_index(input_buffer, 0)
             || (buffer_at_offset(input_buffer)[0] != ':')) {
-            goto fail;
-            /* invalid object */
+            goto fail; /* invalid object */
         }
 
         /* parse the value */
         input_buffer->offset++;
         buffer_skip_whitespace(input_buffer);
         if (!parse_value(current_item, input_buffer)) {
-            goto fail;
-            /* failed to parse value */
+            goto fail; /* failed to parse value */
         }
         buffer_skip_whitespace(input_buffer);
     } while (can_access_at_index(input_buffer, 0)
@@ -1534,13 +1622,16 @@ parse_object(cJSON *const item, parse_buffer *const input_buffer)
 
     if (cannot_access_at_index(input_buffer, 0)
         || (buffer_at_offset(input_buffer)[0] != '}')) {
-        goto fail;
-        /* expected end of object */
+        goto fail; /* expected end of object */
     }
 
 success:
     input_buffer->depth--;
 
+    if (head != NULL) {
+        head->prev = current_item;
+    }
+
     item->type = cJSON_Object;
     item->child = head;
 
@@ -1792,22 +1883,26 @@ add_item_to_array(cJSON *array, cJSON *item)
 {
     cJSON *child = NULL;
 
-    if ((item == NULL) || (array == NULL)) {
+    if ((item == NULL) || (array == NULL) || (array == item)) {
         return false;
     }
 
     child = array->child;
-
+    /*
+     * To find the last item in array quickly, we use prev in array
+     */
     if (child == NULL) {
         /* list is empty, start new one */
         array->child = item;
+        item->prev = item;
+        item->next = NULL;
     }
     else {
         /* append to the end */
-        while (child->next) {
-            child = child->next;
+        if (child->prev) {
+            suffix_object(child->prev, item);
+            array->child->prev = item;
         }
-        suffix_object(child, item);
     }
 
     return true;
@@ -1847,7 +1942,8 @@ add_item_to_object(cJSON *const object, const char *const string,
     char *new_key = NULL;
     int new_type = cJSON_Invalid;
 
-    if ((object == NULL) || (string == NULL) || (item == NULL)) {
+    if ((object == NULL) || (string == NULL) || (item == NULL)
+        || (object == item)) {
         return false;
     }
 
@@ -2028,7 +2124,7 @@ cJSON_DetachItemViaPointer(cJSON *parent, cJSON *const item)
         return NULL;
     }
 
-    if (item->prev != NULL) {
+    if (item != parent->child) {
         /* not the first element */
         item->prev->next = item->next;
     }
@@ -2041,6 +2137,11 @@ cJSON_DetachItemViaPointer(cJSON *parent, cJSON *const item)
         /* first element */
         parent->child = item->next;
     }
+    else if (item->next == NULL) {
+        /* last element */
+        parent->child->prev = item->prev;
+    }
+
     /* make sure the detached item doesn't point anywhere anymore */
     item->prev = NULL;
     item->next = NULL;
@@ -2121,7 +2222,8 @@ CJSON_PUBLIC(cJSON_bool)
 cJSON_ReplaceItemViaPointer(cJSON *const parent, cJSON *const item,
                             cJSON *replacement)
 {
-    if ((parent == NULL) || (replacement == NULL) || (item == NULL)) {
+    if ((parent == NULL) || (parent->child == NULL) || (replacement == NULL)
+        || (item == NULL)) {
         return false;
     }
 
@@ -2135,12 +2237,24 @@ cJSON_ReplaceItemViaPointer(cJSON *const parent, cJSON *const item,
     if (replacement->next != NULL) {
         replacement->next->prev = replacement;
     }
-    if (replacement->prev != NULL) {
-        replacement->prev->next = replacement;
-    }
     if (parent->child == item) {
+        if (parent->child->prev == parent->child) {
+            replacement->prev = replacement;
+        }
         parent->child = replacement;
     }
+    else { /*
+            * To find the last item in array quickly, we use prev in array.
+            * We can't modify the last item's next pointer where this item was
+            * the parent's child
+            */
+        if (replacement->prev != NULL) {
+            replacement->prev->next = replacement;
+        }
+        if (replacement->next == NULL) {
+            parent->child->prev = replacement;
+        }
+    }
 
     item->next = NULL;
     item->prev = NULL;
@@ -2149,15 +2263,15 @@ cJSON_ReplaceItemViaPointer(cJSON *const parent, cJSON *const item,
     return true;
 }
 
-CJSON_PUBLIC(void)
+CJSON_PUBLIC(cJSON_bool)
 cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem)
 {
     if (which < 0) {
-        return;
+        return false;
     }
 
-    cJSON_ReplaceItemViaPointer(array, get_array_item(array, (size_t)which),
-                                newitem);
+    return cJSON_ReplaceItemViaPointer(
+        array, get_array_item(array, (size_t)which), newitem);
 }
 
 static cJSON_bool
@@ -2175,25 +2289,27 @@ replace_item_in_object(cJSON *object, const char *string, cJSON *replacement,
     }
     replacement->string =
         (char *)cJSON_strdup((const unsigned char *)string, &global_hooks);
+    if (replacement->string == NULL) {
+        return false;
+    }
+
     replacement->type &= ~cJSON_StringIsConst;
 
-    cJSON_ReplaceItemViaPointer(
+    return cJSON_ReplaceItemViaPointer(
         object, get_object_item(object, string, case_sensitive), replacement);
-
-    return true;
 }
 
-CJSON_PUBLIC(void)
+CJSON_PUBLIC(cJSON_bool)
 cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem)
 {
-    replace_item_in_object(object, string, newitem, false);
+    return replace_item_in_object(object, string, newitem, false);
 }
 
-CJSON_PUBLIC(void)
+CJSON_PUBLIC(cJSON_bool)
 cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string,
                                        cJSON *newitem)
 {
-    replace_item_in_object(object, string, newitem, true);
+    return replace_item_in_object(object, string, newitem, true);
 }
 
 /* Create basic types: */
@@ -2227,11 +2343,11 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void)
     return item;
 }
 
-CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool b)
+CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean)
 {
     cJSON *item = cJSON_New_Item(&global_hooks);
     if (item) {
-        item->type = b ? cJSON_True : cJSON_False;
+        item->type = boolean ? cJSON_True : cJSON_False;
     }
 
     return item;
@@ -2357,6 +2473,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count)
     }
 
     a = cJSON_CreateArray();
+
     for (i = 0; a && (i < (size_t)count); i++) {
         n = cJSON_CreateNumber(numbers[i]);
         if (!n) {
@@ -2372,6 +2489,10 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count)
         p = n;
     }
 
+    if (a && a->child) {
+        a->child->prev = n;
+    }
+
     return a;
 }
 
@@ -2403,6 +2524,10 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count)
         p = n;
     }
 
+    if (a && a->child) {
+        a->child->prev = n;
+    }
+
     return a;
 }
 
@@ -2434,10 +2559,15 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count)
         p = n;
     }
 
+    if (a && a->child) {
+        a->child->prev = n;
+    }
+
     return a;
 }
 
-CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count)
+CJSON_PUBLIC(cJSON *)
+cJSON_CreateStringArray(const char *const *strings, int count)
 {
     size_t i = 0;
     cJSON *n = NULL;
@@ -2465,6 +2595,10 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count)
         p = n;
     }
 
+    if (a && a->child) {
+        a->child->prev = n;
+    }
+
     return a;
 }
 
@@ -2532,6 +2666,9 @@ CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse)
         }
         child = child->next;
     }
+    if (newitem && newitem->child) {
+        newitem->child->prev = newchild;
+    }
 
     return newitem;
 
@@ -2543,55 +2680,93 @@ fail:
     return NULL;
 }
 
-CJSON_PUBLIC(void) cJSON_Minify(char *json)
+static void
+skip_oneline_comment(char **input)
 {
-    unsigned char *into = (unsigned char *)json;
+    *input += static_strlen("//");
 
-    if (json == NULL) {
-        return;
+    for (; (*input)[0] != '\0'; ++(*input)) {
+        if ((*input)[0] == '\n') {
+            *input += static_strlen("\n");
+            return;
+        }
     }
+}
 
-    while (*json) {
-        if (*json == ' ') {
-            json++;
-        }
-        else if (*json == '\t') {
-            /* Whitespace characters. */
-            json++;
-        }
-        else if (*json == '\r') {
-            json++;
+static void
+skip_multiline_comment(char **input)
+{
+    *input += static_strlen("/*");
+
+    for (; (*input)[0] != '\0'; ++(*input)) {
+        if (((*input)[0] == '*') && ((*input)[1] == '/')) {
+            *input += static_strlen("*/");
+            return;
         }
-        else if (*json == '\n') {
-            json++;
+    }
+}
+
+static void
+minify_string(char **input, char **output)
+{
+    (*output)[0] = (*input)[0];
+    *input += static_strlen("\"");
+    *output += static_strlen("\"");
+
+    for (; (*input)[0] != '\0'; (void)++(*input), ++(*output)) {
+        (*output)[0] = (*input)[0];
+
+        if ((*input)[0] == '\"') {
+            (*output)[0] = '\"';
+            *input += static_strlen("\"");
+            *output += static_strlen("\"");
+            return;
         }
-        else if ((*json == '/') && (json[1] == '/')) {
-            /* double-slash comments, to end of line. */
-            while (*json && (*json != '\n')) {
-                json++;
-            }
+        else if (((*input)[0] == '\\') && ((*input)[1] == '\"')) {
+            (*output)[1] = (*input)[1];
+            *input += static_strlen("\"");
+            *output += static_strlen("\"");
         }
-        else if ((*json == '/') && (json[1] == '*')) {
-            /* multiline comments. */
-            while (*json && !((*json == '*') && (json[1] == '/'))) {
+    }
+}
+
+CJSON_PUBLIC(void) cJSON_Minify(char *json)
+{
+    char *into = json;
+
+    if (json == NULL) {
+        return;
+    }
+
+    while (json[0] != '\0') {
+        switch (json[0]) {
+            case ' ':
+            case '\t':
+            case '\r':
+            case '\n':
                 json++;
-            }
-            json += 2;
-        }
-        else if (*json == '\"') {
-            /* string literals, which are \" sensitive. */
-            *into++ = (unsigned char)*json++;
-            while (*json && (*json != '\"')) {
-                if (*json == '\\') {
-                    *into++ = (unsigned char)*json++;
+                break;
+
+            case '/':
+                if (json[1] == '/') {
+                    skip_oneline_comment(&json);
                 }
-                *into++ = (unsigned char)*json++;
-            }
-            *into++ = (unsigned char)*json++;
-        }
-        else {
-            /* All other characters. */
-            *into++ = (unsigned char)*json++;
+                else if (json[1] == '*') {
+                    skip_multiline_comment(&json);
+                }
+                else {
+                    json++;
+                }
+                break;
+
+            case '\"':
+                minify_string(&json, (char **)&into);
+                break;
+
+            default:
+                into[0] = json[0];
+                json++;
+                into++;
         }
     }
 
@@ -2692,8 +2867,7 @@ CJSON_PUBLIC(cJSON_bool)
 cJSON_Compare(const cJSON *const a, const cJSON *const b,
               const cJSON_bool case_sensitive)
 {
-    if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF))
-        || cJSON_IsInvalid(a)) {
+    if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF))) {
         return false;
     }
 
@@ -2726,7 +2900,7 @@ cJSON_Compare(const cJSON *const a, const cJSON *const b,
             return true;
 
         case cJSON_Number:
-            if (a->valuedouble == b->valuedouble) {
+            if (compare_double(a->valuedouble, b->valuedouble)) {
                 return true;
             }
             return false;

+ 94 - 65
test-tools/host-tool/external/cJSON/cJSON.h

@@ -1,24 +1,24 @@
 /*
- Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
- */
+  Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
+
+  Permission is hereby granted, free of charge, to any person obtaining a copy
+  of this software and associated documentation files (the "Software"), to deal
+  in the Software without restriction, including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included in
+  all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+  THE SOFTWARE.
+*/
 
 #ifndef cJSON__h
 #define cJSON__h
@@ -35,30 +35,34 @@ extern "C" {
 
 #ifdef __WINDOWS__
 
-/**
- * When compiling for windows, we specify a specific calling convention to avoid
- * issues where we are being called from a project with a different default
- * calling convention. For windows you have 3 define options:
- *   CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever
- *                        dllexport symbols
- *   CJSON_EXPORT_SYMBOLS - Define this on library build when you want to
- *                          dllexport symbols (default)
- *   CJSON_IMPORT_SYMBOLS - Define this if you  want to dllimport symbol
- *
- * For *nix builds that support visibility attribute, you can define similar
- * behavior by setting default visibility to hidden by adding
- *   -fvisibility=hidden (for gcc)
- * or
- *   -xldscope=hidden (for sun cc)
- * to CFLAGS, then using the CJSON_API_VISIBILITY flag to "export" the same
- * symbols the way CJSON_EXPORT_SYMBOLS does
- */
+/* When compiling for windows, we specify a specific calling convention to avoid
+issues where we are being called from a project with a different default calling
+convention.  For windows you have 3 define options:
+
+CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever
+dllexport symbols CJSON_EXPORT_SYMBOLS - Define this on library build when you
+want to dllexport symbols (default) CJSON_IMPORT_SYMBOLS - Define this if you
+want to dllimport symbol
+
+For *nix builds that support visibility attribute, you can define similar
+behavior by
+
+setting default visibility to hidden by adding
+-fvisibility=hidden (for gcc)
+or
+-xldscope=hidden (for sun cc)
+to CFLAGS
+
+then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way
+CJSON_EXPORT_SYMBOLS does
+
+*/
 
 #define CJSON_CDECL __cdecl
 #define CJSON_STDCALL __stdcall
 
 /* export symbols by default, this is necessary for copy pasting the C and
-   header file */
+ * header file */
 #if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) \
     && !defined(CJSON_EXPORT_SYMBOLS)
 #define CJSON_EXPORT_SYMBOLS
@@ -86,7 +90,7 @@ extern "C" {
 /* project version */
 #define CJSON_VERSION_MAJOR 1
 #define CJSON_VERSION_MINOR 7
-#define CJSON_VERSION_PATCH 10
+#define CJSON_VERSION_PATCH 16
 
 #include <stddef.h>
 
@@ -107,11 +111,11 @@ extern "C" {
 /* The cJSON structure: */
 typedef struct cJSON {
     /* next/prev allow you to walk array/object chains. Alternatively, use
-       GetArraySize/GetArrayItem/GetObjectItem */
+     * GetArraySize/GetArrayItem/GetObjectItem */
     struct cJSON *next;
     struct cJSON *prev;
     /* An array or object item will have a child pointer pointing to a chain of
-       the items in the array/object. */
+     * the items in the array/object. */
     struct cJSON *child;
 
     /* The type of the item, as above. */
@@ -125,7 +129,7 @@ typedef struct cJSON {
     double valuedouble;
 
     /* The item's name string, if this item is the child of, or is in the list
-       of subitems of an object. */
+     * of subitems of an object. */
     char *string;
 } cJSON;
 
@@ -140,7 +144,7 @@ typedef struct cJSON_Hooks {
 typedef int cJSON_bool;
 
 /* Limits how deeply nested arrays/objects can be before cJSON rejects to parse
-   them. This is to prevent stack overflows. */
+ * them. This is to prevent stack overflows. */
 #ifndef CJSON_NESTING_LIMIT
 #define CJSON_NESTING_LIMIT 1000
 #endif
@@ -159,6 +163,8 @@ CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks *hooks);
 /* Supply a block of JSON, and this returns a cJSON object you can interrogate.
  */
 CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);
+CJSON_PUBLIC(cJSON *)
+cJSON_ParseWithLength(const char *value, size_t buffer_length);
 /* ParseWithOpts allows you to require (and check) that the JSON is null
  * terminated, and to retrieve the pointer to the final byte parsed. */
 /* If you supply a ptr in return_parse_end and parsing fails, then
@@ -167,6 +173,10 @@ CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);
 CJSON_PUBLIC(cJSON *)
 cJSON_ParseWithOpts(const char *value, const char **return_parse_end,
                     cJSON_bool require_null_terminated);
+CJSON_PUBLIC(cJSON *)
+cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length,
+                          const char **return_parse_end,
+                          cJSON_bool require_null_terminated);
 
 /* Render a cJSON entity to text for transfer/storage. */
 CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item);
@@ -185,7 +195,7 @@ CJSON_PUBLIC(cJSON_bool)
 cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length,
                         const cJSON_bool format);
 /* Delete a cJSON entity and all subentities. */
-CJSON_PUBLIC(void) cJSON_Delete(cJSON *c);
+CJSON_PUBLIC(void) cJSON_Delete(cJSON *item);
 
 /* Returns the number of items in an array (or object). */
 CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array);
@@ -205,8 +215,9 @@ cJSON_HasObjectItem(const cJSON *object, const char *string);
  * when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
 CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void);
 
-/* Check if the item is a string and return its valuestring */
-CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item);
+/* Check item type and return its value */
+CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON *const item);
+CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON *const item);
 
 /* These functions check the type of an item */
 CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON *const item);
@@ -233,18 +244,21 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void);
 CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void);
 
 /* Create a string where valuestring references a string so
-   it will not be freed by cJSON_Delete */
+ * it will not be freed by cJSON_Delete */
 CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string);
-/* Create an object/arrray that only references it's elements so
-   they will not be freed by cJSON_Delete */
+/* Create an object/array that only references it's elements so
+ * they will not be freed by cJSON_Delete */
 CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child);
 CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child);
 
-/* These utilities create an Array of count items. */
+/* These utilities create an Array of count items.
+ * The parameter count cannot be greater than the number of elements in the
+ * number array, otherwise array access will be out of bounds.*/
 CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count);
 CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count);
 CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count);
-CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count);
+CJSON_PUBLIC(cJSON *)
+cJSON_CreateStringArray(const char *const *strings, int count);
 
 /* Append item to the specified array/object. */
 CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item);
@@ -264,7 +278,7 @@ cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
 CJSON_PUBLIC(cJSON_bool)
 cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);
 
-/* Remove/Detatch items from Arrays/Objects. */
+/* Remove/Detach items from Arrays/Objects. */
 CJSON_PUBLIC(cJSON *)
 cJSON_DetachItemViaPointer(cJSON *parent, cJSON *const item);
 CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which);
@@ -286,32 +300,35 @@ cJSON_InsertItemInArray(
 CJSON_PUBLIC(cJSON_bool)
 cJSON_ReplaceItemViaPointer(cJSON *const parent, cJSON *const item,
                             cJSON *replacement);
-CJSON_PUBLIC(void)
+CJSON_PUBLIC(cJSON_bool)
 cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);
-CJSON_PUBLIC(void)
+CJSON_PUBLIC(cJSON_bool)
 cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem);
-CJSON_PUBLIC(void)
+CJSON_PUBLIC(cJSON_bool)
 cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string,
                                        cJSON *newitem);
 
 /* Duplicate a cJSON item */
 CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse);
 /* Duplicate will create a new, identical cJSON item to the one you pass, in new
- memory that will need to be released. With recurse!=0, it will duplicate any
- children connected to the item. The item->next and ->prev pointers are always
- zero on return from Duplicate. */
+ * memory that will need to be released. With recurse!=0, it will duplicate any
+ * children connected to the item. The item->next and ->prev pointers are always
+ * zero on return from Duplicate. */
 /* Recursively compare two cJSON items for equality. If either a or b is NULL or
- * invalid, they will be considered unequal.
- * case_sensitive determines if object keys are treated case sensitive (1) or
- * case insensitive (0) */
+ * invalid, they will be considered unequal. case_sensitive determines if object
+ * keys are treated case sensitive (1) or case insensitive (0) */
 CJSON_PUBLIC(cJSON_bool)
 cJSON_Compare(const cJSON *const a, const cJSON *const b,
               const cJSON_bool case_sensitive);
 
+/* Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from
+ * strings. The input pointer json cannot point to a read-only address area,
+ * such as a string constant, but should point to a readable and writable
+ * address area. */
 CJSON_PUBLIC(void) cJSON_Minify(char *json);
 
 /* Helper functions for creating and adding items to an object at the same time.
-   They return the added item or NULL on failure. */
+ * They return the added item or NULL on failure. */
 CJSON_PUBLIC(cJSON *)
 cJSON_AddNullToObject(cJSON *const object, const char *const name);
 CJSON_PUBLIC(cJSON *)
@@ -336,7 +353,7 @@ CJSON_PUBLIC(cJSON *)
 cJSON_AddArrayToObject(cJSON *const object, const char *const name);
 
 /* When assigning an integer value, it needs to be propagated to valuedouble
-   too. */
+ * too. */
 #define cJSON_SetIntValue(object, number)                             \
     ((object) ? (object)->valueint = (object)->valuedouble = (number) \
               : (number))
@@ -345,6 +362,18 @@ CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number);
 #define cJSON_SetNumberValue(object, number)                          \
     ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) \
                       : (number))
+/* Change the valuestring of a cJSON_String object, only takes effect when type
+ * of object is cJSON_String */
+CJSON_PUBLIC(char *)
+cJSON_SetValuestring(cJSON *object, const char *valuestring);
+
+/* If the object is not a boolean type this does nothing and returns
+ * cJSON_Invalid else it returns the new type*/
+#define cJSON_SetBoolValue(object, boolValue)                                \
+    ((object != NULL && ((object)->type & (cJSON_False | cJSON_True)))       \
+         ? (object)->type = ((object)->type & (~(cJSON_False | cJSON_True))) \
+                            | ((boolValue) ? cJSON_True : cJSON_False)       \
+         : cJSON_Invalid)
 
 /* Macro for iterating over an array or object */
 #define cJSON_ArrayForEach(element, array)                                   \
@@ -352,7 +381,7 @@ CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number);
          element = element->next)
 
 /* malloc/free objects using the malloc/free functions that have been set with
-   cJSON_InitHooks */
+ * cJSON_InitHooks */
 CJSON_PUBLIC(void *) cJSON_malloc(size_t size);
 CJSON_PUBLIC(void) cJSON_free(void *object);
 

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

@@ -343,26 +343,6 @@ index adb5cb7..590f626 100644
    (func $g (param $x i32) (result i32)
      (i32.add (local.get $x) (i32.const 1))
    )
-diff --git a/test/core/select.wast b/test/core/select.wast
-index 046e6fe..b677023 100644
---- a/test/core/select.wast
-+++ b/test/core/select.wast
-@@ -324,6 +324,7 @@
-   (module (func $arity-0 (select (result) (nop) (nop) (i32.const 1))))
-   "invalid result arity"
- )
-+(;
- (assert_invalid
-   (module (func $arity-2 (result i32 i32)
-     (select (result i32 i32)
-@@ -334,6 +335,7 @@
-   ))
-   "invalid result arity"
- )
-+;)
- 
- 
- (assert_invalid
 diff --git a/test/core/table_copy.wast b/test/core/table_copy.wast
 index 380e84e..f37e745 100644
 --- a/test/core/table_copy.wast

+ 1 - 1
tests/wamr-test-suites/test_wamr.sh

@@ -824,7 +824,7 @@ function trigger()
                 collect_coverage llvm-jit
 
                 echo "work in orc jit lazy compilation mode"
-                BUILD_FLAGS="$ORC_EAGER_JIT_COMPILE_FLAGS $EXTRA_COMPILE_FLAGS"
+                BUILD_FLAGS="$ORC_LAZY_JIT_COMPILE_FLAGS $EXTRA_COMPILE_FLAGS"
                 build_iwasm_with_cfg $BUILD_FLAGS
                 for suite in "${TEST_CASE_ARR[@]}"; do
                     $suite"_test" jit

+ 38 - 14
tests/wamr-test-suites/wasi-test-script/run_wasi_tests.sh

@@ -11,7 +11,10 @@ readonly TARGET=$2
 readonly WORK_DIR=$PWD
 readonly PLATFORM=$(uname -s | tr A-Z a-z)
 readonly WAMR_DIR="${WORK_DIR}/../../../.."
-readonly IWASM_CMD="${WORK_DIR}/../../../../product-mini/platforms/${PLATFORM}/build/iwasm"
+readonly IWASM_CMD="${WORK_DIR}/../../../../product-mini/platforms/${PLATFORM}/build/iwasm \
+    --allow-resolve=google-public-dns-a.google.com \
+    --addr-pool=::1/128,127.0.0.1/32"
+readonly IWASM_CMD_STRESS="${IWASM_CMD} --max-threads=8"
 readonly WAMRC_CMD="${WORK_DIR}/../../../../wamr-compiler/build/wamrc"
 readonly C_TESTS="tests/c/testsuite/"
 readonly ASSEMBLYSCRIPT_TESTS="tests/assemblyscript/testsuite/"
@@ -22,6 +25,11 @@ readonly LIB_SOCKET_TESTS="${WAMR_DIR}/core/iwasm/libraries/lib-socket/test/"
 run_aot_tests () {
     local tests=("$@")
     for test_wasm in ${tests[@]}; do
+        local extra_stress_flags=""
+        if [[ "$test_wasm" =~ "stress" ]]; then
+            extra_stress_flags="--max-threads=8"
+        fi
+
         test_aot="${test_wasm%.wasm}.aot"
         test_json="${test_wasm%.wasm}.json"
 
@@ -35,12 +43,12 @@ run_aot_tests () {
 
         echo "Running $test_aot"
         expected=0
-        if [ -f ${test_json} ]; then 
+        if [ -f ${test_json} ]; then
             expected=$(jq .exit_code ${test_json})
         fi
-        
-        ${IWASM_CMD} $test_aot
-        
+
+        ${IWASM_CMD} $extra_stress_flags $test_aot
+
         ret=${PIPESTATUS[0]}
 
         echo "expected=$expected, actual=$ret"
@@ -48,20 +56,36 @@ run_aot_tests () {
             exit_code=1
         fi
     done
-} 
+}
 
 if [[ $MODE != "aot" ]];then
     python3 -m venv wasi-env && source wasi-env/bin/activate
     python3 -m pip install -r test-runner/requirements.txt
+
+    # Stress test requires max-threads=8 so it's run separately
+    if [[ -e "${THREAD_INTERNAL_TESTS}spawn_stress_test.wasm" ]]; then 
+        ${IWASM_CMD_STRESS} ${THREAD_INTERNAL_TESTS}spawn_stress_test.wasm
+        ret=${PIPESTATUS[0]}
+        if [ "${ret}" -ne 0 ]; then
+            echo "Stress test spawn_stress_test FAILED with code " ${ret}
+            exit_code=${ret}
+        fi
+    fi
+
     TEST_RUNTIME_EXE="${IWASM_CMD}" python3 test-runner/wasi_test_runner.py \
-                -r adapters/wasm-micro-runtime.py \
-                -t \
-                    ${C_TESTS} \
-                    ${ASSEMBLYSCRIPT_TESTS} \
-                    ${THREAD_PROPOSAL_TESTS} \
-                    ${THREAD_INTERNAL_TESTS} \
-                    ${LIB_SOCKET_TESTS} \
-    exit_code=${PIPESTATUS[0]}
+            -r adapters/wasm-micro-runtime.py \
+            -t \
+                ${C_TESTS} \
+                ${ASSEMBLYSCRIPT_TESTS} \
+                ${THREAD_PROPOSAL_TESTS} \
+                ${THREAD_INTERNAL_TESTS} \
+                ${LIB_SOCKET_TESTS} \
+            --exclude-filter "${THREAD_INTERNAL_TESTS}skip.json"
+
+    ret=${PIPESTATUS[0]}
+    if [ "${ret}" -ne 0 ]; then
+        exit_code=${ret}
+    fi
     deactivate
 else
     target_option=""