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

Merge pull request #3874 from bytecodealliance/main

Merge branch main into dev/checkpoint_and_restore
Wenyong Huang 1 год назад
Родитель
Сommit
21d71def73
100 измененных файлов с 5337 добавлено и 1388 удалено
  1. 30 0
      .github/scripts/codeql_buildscript.sh
  2. 5 0
      .github/workflows/build_docker_images.yml
  3. 87 33
      .github/workflows/build_iwasm_release.yml
  4. 29 4
      .github/workflows/build_llvm_libraries.yml
  5. 8 0
      .github/workflows/build_wamr_lldb.yml
  6. 6 0
      .github/workflows/build_wamr_sdk.yml
  7. 6 0
      .github/workflows/build_wamr_vscode_ext.yml
  8. 16 2
      .github/workflows/build_wamrc.yml
  9. 12 8
      .github/workflows/codeql.yml
  10. 3 0
      .github/workflows/coding_guidelines.yml
  11. 15 0
      .github/workflows/compilation_on_android_ubuntu.yml
  12. 18 0
      .github/workflows/compilation_on_macos.yml
  13. 5 1
      .github/workflows/compilation_on_nuttx.yml
  14. 6 0
      .github/workflows/compilation_on_sgx.yml
  15. 3 0
      .github/workflows/compilation_on_windows.yml
  16. 5 0
      .github/workflows/create_tag.yml
  17. 3 0
      .github/workflows/hadolint_dockerfiles.yml
  18. 18 0
      .github/workflows/nightly_run.yml
  19. 78 0
      .github/workflows/release_process.yml
  20. 6 0
      .github/workflows/reuse_latest_release_binaries.yml
  21. 15 19
      .github/workflows/spec_test_on_nuttx.yml
  22. 65 0
      .github/workflows/supply_chain.yml
  23. 1 0
      .gitignore
  24. 1 1
      ATTRIBUTIONS.md
  25. 27 5
      CMakeLists.txt
  26. 29 0
      CODEOWNERS
  27. 82 0
      RELEASE_NOTES.md
  28. 32 4
      build-scripts/build_llvm.py
  29. 17 5
      build-scripts/config_common.cmake
  30. 15 1
      build-scripts/runtime_lib.cmake
  31. 1 0
      ci/coding_guidelines_check.py
  32. 11 1
      core/config.h
  33. 143 139
      core/iwasm/aot/aot_loader.c
  34. 1 1
      core/iwasm/aot/aot_reloc.h
  35. 452 85
      core/iwasm/aot/aot_runtime.c
  36. 47 2
      core/iwasm/aot/aot_runtime.h
  37. 3 10
      core/iwasm/aot/arch/aot_reloc_aarch64.c
  38. 97 97
      core/iwasm/aot/arch/aot_reloc_arm.c
  39. 1 1
      core/iwasm/aot/arch/aot_reloc_mips.c
  40. 66 53
      core/iwasm/aot/arch/aot_reloc_riscv.c
  41. 97 97
      core/iwasm/aot/arch/aot_reloc_thumb.c
  42. 1 1
      core/iwasm/aot/arch/aot_reloc_x86_64.c
  43. 37 37
      core/iwasm/aot/arch/aot_reloc_xtensa.c
  44. 5 5
      core/iwasm/aot/debug/jit_debug.c
  45. 2 2
      core/iwasm/aot/debug/jit_debug.h
  46. 1 2
      core/iwasm/common/wasm_c_api.c
  47. 7 2
      core/iwasm/common/wasm_exec_env.c
  48. 4 0
      core/iwasm/common/wasm_exec_env.h
  49. 62 0
      core/iwasm/common/wasm_loader_common.c
  50. 12 0
      core/iwasm/common/wasm_loader_common.h
  51. 673 41
      core/iwasm/common/wasm_memory.c
  52. 31 2
      core/iwasm/common/wasm_memory.h
  53. 15 2
      core/iwasm/common/wasm_native.c
  54. 2 2
      core/iwasm/common/wasm_native.h
  55. 93 54
      core/iwasm/common/wasm_runtime_common.c
  56. 9 4
      core/iwasm/common/wasm_runtime_common.h
  57. 44 3
      core/iwasm/common/wasm_shared_memory.c
  58. 2 2
      core/iwasm/common/wasm_shared_memory.h
  59. 1 1
      core/iwasm/compilation/aot.h
  60. 105 34
      core/iwasm/compilation/aot_compiler.c
  61. 29 0
      core/iwasm/compilation/aot_compiler.h
  62. 9 0
      core/iwasm/compilation/aot_emit_aot_file.c
  63. 44 8
      core/iwasm/compilation/aot_emit_control.c
  64. 5 44
      core/iwasm/compilation/aot_emit_exception.c
  65. 149 51
      core/iwasm/compilation/aot_emit_function.c
  66. 267 11
      core/iwasm/compilation/aot_emit_memory.c
  67. 141 12
      core/iwasm/compilation/aot_emit_table.c
  68. 100 13
      core/iwasm/compilation/aot_llvm.c
  69. 9 1
      core/iwasm/compilation/aot_llvm.h
  70. 27 0
      core/iwasm/compilation/aot_stack_frame.h
  71. 150 0
      core/iwasm/compilation/aot_stack_frame_comp.c
  72. 33 0
      core/iwasm/compilation/aot_stack_frame_comp.h
  73. 46 1
      core/iwasm/include/aot_comp_option.h
  74. 4 0
      core/iwasm/include/wasm_c_api.h
  75. 192 2
      core/iwasm/include/wasm_export.h
  76. 12 2
      core/iwasm/interpreter/wasm.h
  77. 235 62
      core/iwasm/interpreter/wasm_interp_classic.c
  78. 120 28
      core/iwasm/interpreter/wasm_interp_fast.c
  79. 250 188
      core/iwasm/interpreter/wasm_loader.c
  80. 182 36
      core/iwasm/interpreter/wasm_mini_loader.c
  81. 217 57
      core/iwasm/interpreter/wasm_runtime.c
  82. 34 4
      core/iwasm/interpreter/wasm_runtime.h
  83. 1 1
      core/iwasm/libraries/lib-pthread/lib_pthread.cmake
  84. 1 1
      core/iwasm/libraries/lib-wasi-threads/lib_wasi_threads_wrapper.c
  85. 19 5
      core/iwasm/libraries/libc-emcc/libc_emcc_wrapper.c
  86. 5 4
      core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c
  87. 1 1
      core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c
  88. 29 0
      core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/refcount.h
  89. 18 4
      core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/ssp_config.h
  90. 8 0
      core/iwasm/libraries/shared-heap/shared_heap.cmake
  91. 57 0
      core/iwasm/libraries/shared-heap/shared_heap_wrapper.c
  92. 76 0
      core/iwasm/libraries/thread-mgr/thread_manager.c
  93. 16 4
      core/iwasm/libraries/thread-mgr/thread_manager.h
  94. 24 24
      core/iwasm/libraries/wasi-nn/README.md
  95. 25 0
      core/iwasm/libraries/wasi-nn/cmake/Findcjson.cmake
  96. 26 0
      core/iwasm/libraries/wasi-nn/cmake/Findllamacpp.cmake
  97. 29 39
      core/iwasm/libraries/wasi-nn/cmake/Findtensorflow_lite.cmake
  98. 12 0
      core/iwasm/libraries/wasi-nn/cmake/add_telemetry.patch
  99. 58 22
      core/iwasm/libraries/wasi-nn/cmake/wasi_nn.cmake
  100. 9 0
      core/iwasm/libraries/wasi-nn/include/wasi_nn_types.h

+ 30 - 0
.github/scripts/codeql_buildscript.sh

@@ -126,6 +126,16 @@ if [[ $? != 0 ]]; then
     exit 1;
 fi
 
+# build iwasm with multi-memory enabled
+cd ${WAMR_DIR}/product-mini/platforms/linux
+rm -rf build && mkdir build && cd build
+cmake .. -DCMAKE_BUILD_TYPE=Debug -DWAMR_BUILD_MULTI_MEMORY=1
+make -j
+if [[ $? != 0 ]]; then
+    echo "Failed to build iwasm with multi-memory enabled!"
+    exit 1;
+fi
+
 # build iwasm with hardware boundary check disabled
 cd ${WAMR_DIR}/product-mini/platforms/linux
 rm -rf build && mkdir build && cd build
@@ -280,3 +290,23 @@ if [[ $? != 0 ]]; then
     echo "Failed to build iwasm with linux perf support enabled!"
     exit 1;
 fi
+
+# build iwasm with shared heap enabled
+cd ${WAMR_DIR}/product-mini/platforms/linux
+rm -rf build && mkdir build && cd build
+cmake .. -DCMAKE_BUILD_TYPE=Debug -DWAMR_BUILD_SHARED_HEAP=1
+make -j
+if [[ $? != 0 ]]; then
+    echo "Failed to build iwasm with shared heap enabled!"
+    exit 1;
+fi
+
+# build iwasm with dynamic aot debug enabled
+cd ${WAMR_DIR}/product-mini/platforms/linux
+rm -rf build && mkdir build && cd build
+cmake .. -DCMAKE_BUILD_TYPE=Debug -DWAMR_BUILD_DYNAMIC_AOT_DEBUG=1
+make -j
+if [[ $? != 0 ]]; then
+    echo "Failed to build iwasm dynamic aot debug enabled!"
+    exit 1;
+fi

+ 5 - 0
.github/workflows/build_docker_images.yml

@@ -15,9 +15,14 @@ on:
         type: string
         required: true
 
+permissions:
+  contents: read
+
 jobs:
   build-and-push-images:
     runs-on: ubuntu-22.04
+    permissions:
+      contents: write # for uploading release artifacts
 
     steps:
       - name: Checkout repository

+ 87 - 33
.github/workflows/build_iwasm_release.yml

@@ -31,9 +31,78 @@ on:
         type: string
         required: false
 
+env:
+  DEFAULT_BUILD_OPTIONS: 
+    "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_FAST_JIT=1 -DWAMR_BUILD_JIT=1 \
+     -DWAMR_BUILD_CUSTOM_NAME_SECTION=0 \
+     -DWAMR_BUILD_DEBUG_INTERP=0 \
+     -DWAMR_BUILD_DEBUG_AOT=0 \
+     -DWAMR_BUILD_DUMP_CALL_STACK=0 \
+     -DWAMR_BUILD_LIBC_UVWASI=0 \
+     -DWAMR_BUILD_LIBC_EMCC=0 \
+     -DWAMR_BUILD_LIB_RATS=0 \
+     -DWAMR_BUILD_LOAD_CUSTOM_SECTION=0 \
+     -DWAMR_BUILD_MEMORY_PROFILING=0 \
+     -DWAMR_BUILD_MINI_LOADER=0 \
+     -DWAMR_BUILD_MULTI_MODULE=0 \
+     -DWAMR_BUILD_PERF_PROFILING=0 \
+     -DWAMR_BUILD_SPEC_TEST=0 \
+     -DWAMR_BUILD_BULK_MEMORY=1 \
+     -DWAMR_BUILD_LIB_PTHREAD=1 \
+     -DWAMR_BUILD_LIB_PTHREAD_SEMAPHORE=1 \
+     -DWAMR_BUILD_LIB_WASI_THREADS=1 \
+     -DWAMR_BUILD_LIBC_BUILTIN=1 \
+     -DWAMR_BUILD_LIBC_WASI=1 \
+     -DWAMR_BUILD_REF_TYPES=1 \
+     -DWAMR_BUILD_SIMD=1 \
+     -DWAMR_BUILD_SHARED_MEMORY=1 \
+     -DWAMR_BUILD_TAIL_CALL=1 \
+     -DWAMR_BUILD_THREAD_MGR=1"
+  GC_EH_BUILD_OPTIONS:
+    "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_FAST_JIT=0 -DWAMR_BUILD_JIT=0 \
+     -DWAMR_BUILD_CUSTOM_NAME_SECTION=0 \
+     -DWAMR_BUILD_DEBUG_INTERP=0 \
+     -DWAMR_BUILD_DEBUG_AOT=0 \
+     -DWAMR_BUILD_DUMP_CALL_STACK=0 \
+     -DWAMR_BUILD_LIBC_UVWASI=0 \
+     -DWAMR_BUILD_LIBC_EMCC=0 \
+     -DWAMR_BUILD_LIB_RATS=0 \
+     -DWAMR_BUILD_LOAD_CUSTOM_SECTION=0 \
+     -DWAMR_BUILD_MEMORY_PROFILING=0 \
+     -DWAMR_BUILD_MINI_LOADER=0 \
+     -DWAMR_BUILD_MULTI_MODULE=0 \
+     -DWAMR_BUILD_PERF_PROFILING=0 \
+     -DWAMR_BUILD_SPEC_TEST=0 \
+     -DWAMR_BUILD_BULK_MEMORY=1 \
+     -DWAMR_BUILD_LIB_PTHREAD=1 \
+     -DWAMR_BUILD_LIB_PTHREAD_SEMAPHORE=1 \
+     -DWAMR_BUILD_LIB_WASI_THREADS=1 \
+     -DWAMR_BUILD_LIBC_BUILTIN=1 \
+     -DWAMR_BUILD_LIBC_WASI=1 \
+     -DWAMR_BUILD_REF_TYPES=1 \
+     -DWAMR_BUILD_SIMD=1 \
+     -DWAMR_BUILD_SHARED_MEMORY=1 \
+     -DWAMR_BUILD_TAIL_CALL=1 \
+     -DWAMR_BUILD_THREAD_MGR=1 \
+     -DWAMR_BUILD_EXCE_HANDLING=1 \
+     -DWAMR_BUILD_GC=1"
+
+permissions:
+  contents: read
+
 jobs:
   build:
     runs-on: ${{ inputs.runner }}
+    strategy:
+      matrix:
+        include:
+          - build_options: $DEFAULT_BUILD_OPTIONS
+            suffix: ''
+          - build_options: $GC_EH_BUILD_OPTIONS
+            suffix: '-gc-eh'
+    permissions:
+      contents: write # for uploading release artifacts
+
     steps:
       - uses: actions/checkout@v4
 
@@ -51,40 +120,25 @@ jobs:
           fail-on-cache-miss: true
 
       - name: generate iwasm binary release
+        shell: bash
         run: |
-          cmake -S . -B build \
-            -DWAMR_BUILD_AOT=1 -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_FAST_JIT=1 -DWAMR_BUILD_JIT=1 \
-            -DWAMR_BUILD_CUSTOM_NAME_SECTION=0 \
-            -DWAMR_BUILD_DEBUG_INTERP=0 \
-            -DWAMR_BUILD_DEBUG_AOT=0 \
-            -DWAMR_BUILD_DUMP_CALL_STACK=0 \
-            -DWAMR_BUILD_LIBC_UVWASI=0 \
-            -DWAMR_BUILD_LIBC_EMCC=0 \
-            -DWAMR_BUILD_LIB_RATS=0 \
-            -DWAMR_BUILD_LOAD_CUSTOM_SECTION=0 \
-            -DWAMR_BUILD_MEMORY_PROFILING=0 \
-            -DWAMR_BUILD_MINI_LOADER=0 \
-            -DWAMR_BUILD_MULTI_MODULE=0 \
-            -DWAMR_BUILD_PERF_PROFILING=0 \
-            -DWAMR_BUILD_SPEC_TEST=0 \
-            -DWAMR_BUILD_BULK_MEMORY=1 \
-            -DWAMR_BUILD_LIB_PTHREAD=1 \
-            -DWAMR_BUILD_LIB_PTHREAD_SEMAPHORE=1 \
-            -DWAMR_BUILD_LIB_WASI_THREADS=1 \
-            -DWAMR_BUILD_LIBC_BUILTIN=1 \
-            -DWAMR_BUILD_LIBC_WASI=1 \
-            -DWAMR_BUILD_REF_TYPES=1 \
-            -DWAMR_BUILD_SIMD=1 \
-            -DWAMR_BUILD_SHARED_MEMORY=1 \
-            -DWAMR_BUILD_TAIL_CALL=1 \
-            -DWAMR_BUILD_THREAD_MGR=1
+          cmake -S . -B build ${{ matrix.build_options }}
           cmake --build build --config Release --parallel 4
         working-directory: ${{ inputs.cwd }}
 
-      - name: compress the binary
+      - name: Compress the binary on Windows
+        if: inputs.runner == 'windows-latest'
+        run: |
+          tar -czf iwasm${{ matrix.suffix }}-${{ inputs.ver_num }}-${{ inputs.runner }}.tar.gz iwasm.exe
+          Compress-Archive -Path iwasm.exe -DestinationPath iwasm${{ matrix.suffix }}-${{ inputs.ver_num }}-${{ inputs.runner }}.zip
+          mv iwasm${{ matrix.suffix }}-${{ inputs.ver_num }}-${{ inputs.runner }}.* ../
+        working-directory: ${{ inputs.cwd }}/build/Release
+
+      - name: compress the binary on non-Windows
+        if: inputs.runner != 'windows-latest'
         run: |
-          tar czf iwasm-${{ inputs.ver_num }}-${{ inputs.runner }}.tar.gz iwasm
-          zip iwasm-${{ inputs.ver_num }}-${{ inputs.runner }}.zip iwasm
+          tar czf iwasm${{ matrix.suffix }}-${{ inputs.ver_num }}-${{ inputs.runner }}.tar.gz iwasm
+          zip iwasm${{ matrix.suffix }}-${{ inputs.ver_num }}-${{ inputs.runner }}.zip iwasm
         working-directory: ${{ inputs.cwd }}/build
 
       - name: upload release tar.gz
@@ -93,8 +147,8 @@ jobs:
           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
         with:
           upload_url: ${{ inputs.upload_url }}
-          asset_path: ${{ inputs.cwd }}/build/iwasm-${{ inputs.ver_num }}-${{ inputs.runner }}.tar.gz
-          asset_name: iwasm-${{ inputs.ver_num }}-${{ inputs.arch }}-${{ inputs.runner }}.tar.gz
+          asset_path: ${{ inputs.cwd }}/build/iwasm${{ matrix.suffix }}-${{ inputs.ver_num }}-${{ inputs.runner }}.tar.gz
+          asset_name: iwasm${{ matrix.suffix }}-${{ inputs.ver_num }}-${{ inputs.arch }}-${{ inputs.runner }}.tar.gz
           asset_content_type: application/x-gzip
 
       - name: upload release zip
@@ -103,6 +157,6 @@ jobs:
           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
         with:
           upload_url: ${{ inputs.upload_url }}
-          asset_path: ${{ inputs.cwd }}/build/iwasm-${{ inputs.ver_num }}-${{ inputs.runner }}.zip
-          asset_name: iwasm-${{ inputs.ver_num }}-${{ inputs.arch }}-${{ inputs.runner }}.zip
+          asset_path: ${{ inputs.cwd }}/build/iwasm${{ matrix.suffix }}-${{ inputs.ver_num }}-${{ inputs.runner }}.zip
+          asset_name: iwasm${{ matrix.suffix }}-${{ inputs.ver_num }}-${{ inputs.arch }}-${{ inputs.runner }}.zip
           asset_content_type: application/zip

+ 29 - 4
.github/workflows/build_llvm_libraries.yml

@@ -27,6 +27,9 @@ on:
         description: "A cached key of LLVM libraries"
         value: ${{ jobs.build_llvm_libraries.outputs.key}}
 
+permissions:
+  contents: read
+
 jobs:
   build_llvm_libraries:
     runs-on: ${{ inputs.os }}
@@ -36,6 +39,9 @@ jobs:
       image: ${{ inputs.container_image }}
     outputs:
       key: ${{ steps.create_lib_cache_key.outputs.key}}
+    permissions:
+      contents: read
+      actions: write # for uploading cached artifact
 
     steps:
       - name: checkout
@@ -43,6 +49,7 @@ jobs:
 
       - name: install dependencies for non macos-14
         if: inputs.os != 'macos-14'
+        shell: bash
         run: /usr/bin/env python3 -m pip install -r requirements.txt
         working-directory: build-scripts
 
@@ -51,10 +58,13 @@ jobs:
         run: /usr/bin/env python3 -m pip install -r requirements.txt --break-system-packages
         working-directory: build-scripts
 
-      - name: retrieve the last commit ID
+      - name: Retrieve the last commit ID
         id: get_last_commit
-        run: echo "last_commit=$(GH_TOKEN=${{ secrets.GITHUB_TOKEN }} /usr/bin/env python3 ./build_llvm.py ${{ inputs.extra_build_llvm_options }} --llvm-ver)" >> $GITHUB_OUTPUT
-        working-directory: build-scripts
+        env:
+          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+        shell: bash
+        run: |
+          echo "last_commit=$(GH_TOKEN=${{ secrets.GITHUB_TOKEN }} /usr/bin/env python3 ./build_llvm.py ${{ inputs.extra_build_llvm_options }} --llvm-ver)" >> $GITHUB_OUTPUT
 
       # Bump the prefix number to evict all previous caches and
       # enforce a clean build, in the unlikely case that some
@@ -62,7 +72,9 @@ jobs:
       # suspect.
       - name: form the cache key of libraries
         id: create_lib_cache_key
-        run: echo "key=0-llvm-libraries-${{ inputs.os }}-${{ inputs.arch }}-${{ steps.get_last_commit.outputs.last_commit }}${{ inputs.cache_key_suffix }}" >> $GITHUB_OUTPUT
+        shell: bash
+        run: |
+          echo "key=0-llvm-libraries-${{ inputs.os }}-${{ inputs.arch }}-${{ steps.get_last_commit.outputs.last_commit }}${{ inputs.cache_key_suffix }}" >> $GITHUB_OUTPUT
 
       - name: Cache LLVM libraries
         id: retrieve_llvm_libs
@@ -107,7 +119,20 @@ jobs:
       - run: brew install ccache ninja
         if: steps.retrieve_llvm_libs.outputs.cache-hit != 'true' && startsWith(inputs.os, 'macos')
 
+      - uses: actions/cache@v4
+        with:
+          path: ~/.cache/ccache
+          key: 0-ccache-${{ inputs.os }}-${{ steps.get_last_commit.outputs.last_commit }}
+          restore-keys: |
+            0-ccache-${{ inputs.os }}
+        if: steps.retrieve_llvm_libs.outputs.cache-hit != 'true' && inputs.os == 'windows-latest'
+
+      # Install tools on Windows
+      - run: choco install -y ccache ninja
+        if: steps.retrieve_llvm_libs.outputs.cache-hit != 'true' && inputs.os == 'windows-latest'
+
       - name: Build LLVM libraries
         if: steps.retrieve_llvm_libs.outputs.cache-hit != 'true'
+        shell: bash
         run: /usr/bin/env python3 ./build_llvm.py ${{ inputs.extra_build_llvm_options }} --arch ${{ inputs.arch }}
         working-directory: build-scripts

+ 8 - 0
.github/workflows/build_wamr_lldb.yml

@@ -28,8 +28,13 @@ on:
         required: false
         default: "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-20/wasi-sdk-20.0-linux.tar.gz"
 
+permissions:
+  contents: read
+
 jobs:
   try_reuse:
+    permissions:
+      contents: write # for uploading release artifacts
     uses: ./.github/workflows/reuse_latest_release_binaries.yml
     with:
       binary_name_stem: "wamr-lldb-${{ inputs.ver_num }}-${{ inputs.arch }}-${{ inputs.runner }}"
@@ -46,6 +51,9 @@ jobs:
       PYTHON_VERSION: '3.10'
       PYTHON_UBUNTU_STANDALONE_BUILD: https://github.com/indygreg/python-build-standalone/releases/download/20230507/cpython-3.10.11+20230507-x86_64-unknown-linux-gnu-install_only.tar.gz
       PYTHON_MACOS_STANDALONE_BUILD: https://github.com/indygreg/python-build-standalone/releases/download/20230507/cpython-3.10.11+20230507-x86_64-apple-darwin-install_only.tar.gz
+    permissions:
+      contents: write # for uploading release artifacts
+
     steps:
       - uses: actions/checkout@v4
 

+ 6 - 0
.github/workflows/build_wamr_sdk.yml

@@ -35,9 +35,15 @@ on:
         type: string
         required: true
 
+permissions:
+  contents: read
+
 jobs:
   build:
     runs-on: ${{ inputs.runner }}
+    permissions:
+      contents: write # for uploading release artifacts
+
     steps:
       - uses: actions/checkout@v4
 

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

@@ -14,9 +14,15 @@ on:
         type: string
         required: true
 
+permissions:
+  contents: read
+
 jobs:
   build:
     runs-on: ubuntu-22.04
+    permissions:
+      contents: write # for uploading release artifacts
+
     steps:
       - uses: actions/checkout@v4
 

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

@@ -31,9 +31,15 @@ on:
         type: string
         required: false
 
+permissions:
+  contents: read
+
 jobs:
   build:
     runs-on: ${{ inputs.runner }}
+    permissions:
+      contents: write # for uploading release artifacts
+
     steps:
       - uses: actions/checkout@v4
 
@@ -56,8 +62,16 @@ jobs:
           cmake --build build --config Release --parallel 4
         working-directory: wamr-compiler
 
-      - name: compress the binary
-        if: inputs.release
+      - name: Compress the binary on Windows
+        if: inputs.runner == 'windows-latest' && inputs.release
+        run: |
+          tar -czf wamrc-${{ inputs.ver_num }}-${{ inputs.runner }}.tar.gz wamrc.exe
+          Compress-Archive -Path wamrc.exe -DestinationPath wamrc-${{ inputs.ver_num }}-${{ inputs.runner }}.zip
+          mv wamrc-${{ inputs.ver_num }}-${{ inputs.runner }}.* ../
+        working-directory: wamr-compiler/build/Release
+
+      - name: compress the binary on non-Windows
+        if: inputs.runner != 'windows-latest' && inputs.release
         run: |
           tar czf wamrc-${{ inputs.ver_num }}-${{ inputs.runner }}.tar.gz wamrc
           zip wamrc-${{ inputs.ver_num }}-${{ inputs.runner }}.zip wamrc

+ 12 - 8
.github/workflows/codeql.yml

@@ -19,6 +19,9 @@ on:
   # allow to be triggered manually
   workflow_dispatch:
 
+permissions:
+  contents: read
+
 jobs:
   analyze:
     if: github.repository == 'bytecodealliance/wasm-micro-runtime'
@@ -30,10 +33,6 @@ jobs:
     # Consider using larger runners for possible analysis time improvements.
     runs-on: ${{ (matrix.language == 'swift' && 'macos-13') || 'ubuntu-22.04' }}
     timeout-minutes: ${{ (matrix.language == 'swift' && 120) || 360 }}
-    permissions:
-      actions: read
-      contents: read
-      security-events: write
 
     strategy:
       fail-fast: false
@@ -41,6 +40,11 @@ jobs:
         language: [ 'cpp' ]
         # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby', 'swift' ]
 
+    permissions:
+      contents: read
+      actions: read
+      security-events: write
+
     steps:
     - name: Checkout repository
       uses: actions/checkout@v3
@@ -49,7 +53,7 @@ jobs:
 
     # Initializes the CodeQL tools for scanning.
     - name: Initialize CodeQL
-      uses: github/codeql-action/init@v3
+      uses: github/codeql-action/init@v3.26.13
       with:
         languages: ${{ matrix.language }}
 
@@ -66,7 +70,7 @@ jobs:
     - run: |
         ./.github/scripts/codeql_buildscript.sh
     - name: Perform CodeQL Analysis
-      uses: github/codeql-action/analyze@v3
+      uses: github/codeql-action/analyze@v3.26.13
       with:
         category: "/language:${{matrix.language}}"
         upload: false
@@ -95,14 +99,14 @@ jobs:
         output: ${{ steps.step1.outputs.sarif-output }}/cpp.sarif
 
     - name: Upload CodeQL results to code scanning
-      uses: github/codeql-action/upload-sarif@v3
+      uses: github/codeql-action/upload-sarif@v3.26.13
       with:
         sarif_file: ${{ steps.step1.outputs.sarif-output }}
         category: "/language:${{matrix.language}}"
 
     - name: Upload CodeQL results as an artifact
       if: success() || failure()
-      uses: actions/upload-artifact@v4
+      uses: actions/upload-artifact@v4.4.3
       with:
         name: codeql-results
         path: ${{ steps.step1.outputs.sarif-output }}

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

@@ -14,6 +14,9 @@ concurrency:
   group: ${{ github.workflow }}-${{ github.ref }}
   cancel-in-progress: true
 
+permissions:
+  contents: read
+
 jobs:
   compliance_job:
     runs-on: ubuntu-20.04

+ 15 - 0
.github/workflows/compilation_on_android_ubuntu.yml

@@ -70,8 +70,14 @@ env:
   MEMORY64_TEST_OPTIONS: "-s spec -W -b -P"
   MULTI_MEMORY_TEST_OPTIONS: "-s spec -E -b -P"
 
+permissions:
+  contents: read
+
 jobs:
   build_llvm_libraries_on_ubuntu_2204:
+    permissions:
+      contents: read
+      actions: write
     uses: ./.github/workflows/build_llvm_libraries.yml
     with:
       os: "ubuntu-22.04"
@@ -578,6 +584,15 @@ jobs:
           ./run.sh test1
           ./run.sh test2
 
+      - name: Build Sample [shared-heap]
+        run: |
+          cd samples/shared-heap
+          mkdir build && cd build
+          cmake ..
+          cmake --build . --config Debug --parallel 4
+          ./shared_heap_test
+          ./shared_heap_test --aot
+
   test:
     needs:
       [

+ 18 - 0
.github/workflows/compilation_on_macos.yml

@@ -52,13 +52,22 @@ env:
   LLVM_LAZY_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=1"
   LLVM_EAGER_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=0"
 
+permissions:
+  contents: read
+
 jobs:
   build_llvm_libraries_on_intel_macos:
+    permissions:
+      contents: read
+      actions: write
     uses: ./.github/workflows/build_llvm_libraries.yml
     with:
       os: "macos-13"
       arch: "X86"
   build_llvm_libraries_on_arm_macos:
+    permissions:
+      contents: read
+      actions: write
     uses: ./.github/workflows/build_llvm_libraries.yml
     with:
       os: "macos-14"
@@ -386,3 +395,12 @@ jobs:
           ./build.sh
           ./run.sh test1
           ./run.sh test2
+
+      - name: Build Sample [shared-heap]
+        run: |
+          cd samples/shared-heap
+          mkdir build && cd build
+          cmake ..
+          cmake --build . --config Debug --parallel 4
+          ./shared_heap_test
+          ./shared_heap_test --aot

+ 5 - 1
.github/workflows/compilation_on_nuttx.yml

@@ -46,6 +46,9 @@ concurrency:
 env:
   WASI_SDK_PATH: "/opt/wasi-sdk"
 
+permissions:
+  contents: read
+
 jobs:
   build_iwasm_on_nuttx:
     runs-on: ubuntu-latest
@@ -119,11 +122,12 @@ jobs:
         run: make -j$(nproc) EXTRAFLAGS=-Werror
 
       - name: Checkout Bloaty
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
         with:
           repository: google/bloaty
           submodules: recursive
           path: bloaty
+          ref: 34f4a66559ad4938c1e629e9b5f54630b2b4d7b0
 
       - name: Build Bloaty
         run: |

+ 6 - 0
.github/workflows/compilation_on_sgx.yml

@@ -54,8 +54,14 @@ env:
   LLVM_LAZY_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=1"
   LLVM_EAGER_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=0"
 
+permissions:
+  contents: read
+
 jobs:
   build_llvm_libraries:
+    permissions:
+      contents: read
+      actions: write
     uses: ./.github/workflows/build_llvm_libraries.yml
     with:
       os: "ubuntu-20.04"

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

@@ -53,6 +53,9 @@ concurrency:
   group: ${{ github.workflow }}-${{ github.ref }}
   cancel-in-progress: true
 
+permissions:
+  contents: read
+
 jobs:
   build:
     runs-on: windows-latest

+ 5 - 0
.github/workflows/create_tag.yml

@@ -15,6 +15,9 @@ on:
         description: "the new tag just created"
         value: ${{ jobs.create_tag.outputs.new_tag}}
 
+permissions:
+  contents: read
+
 jobs:
   create_tag:
     runs-on: ubuntu-latest
@@ -22,6 +25,8 @@ jobs:
       minor_version: ${{ steps.preparation.outputs.minor_version }}
       new_ver: ${{ steps.preparation.outputs.new_ver }}
       new_tag: ${{ steps.preparation.outputs.new_tag }}
+    permissions:
+      contents: write # create and push tags
 
     steps:
       - uses: actions/checkout@v4

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

@@ -28,6 +28,9 @@ concurrency:
   group: ${{ github.workflow }}-${{ github.ref }}
   cancel-in-progress: true
 
+permissions:
+  contents: read
+
 jobs:
   run-hadolint-on-dockerfiles:
     runs-on: ubuntu-22.04

+ 18 - 0
.github/workflows/nightly_run.yml

@@ -44,13 +44,22 @@ env:
   X86_32_TARGET_TEST_OPTIONS: "-m x86_32 -P"
   WASI_TEST_OPTIONS: "-s wasi_certification -w"
 
+permissions:
+  contents: read
+
 jobs:
   build_llvm_libraries_on_ubuntu_2004:
+    permissions:
+      contents: read
+      actions: write
     uses: ./.github/workflows/build_llvm_libraries.yml
     with:
       os: "ubuntu-20.04"
       arch: "X86"
   build_llvm_libraries_on_ubuntu_2204:
+    permissions:
+      contents: read
+      actions: write
     uses: ./.github/workflows/build_llvm_libraries.yml
     with:
       os: "ubuntu-22.04"
@@ -593,6 +602,15 @@ jobs:
           exit $?
         working-directory: ./wamr-app-framework/samples/simple
 
+      - name: Build Sample [shared-heap]
+        run: |
+          cd samples/shared-heap
+          mkdir build && cd build
+          cmake ..
+          cmake --build . --config Debug --parallel 4
+          ./shared_heap_test
+          ./shared_heap_test --aot
+
   test:
     needs:
       [

+ 78 - 0
.github/workflows/release_process.yml

@@ -18,11 +18,18 @@ concurrency:
   group: ${{ github.workflow }}-${{ github.ref }}
   cancel-in-progress: true
 
+permissions:
+  contents: read
+
 jobs:
   create_tag:
+    permissions:
+      contents: write # create and push tags
     uses: ./.github/workflows/create_tag.yml
 
   create_release:
+    permissions:
+      contents: write # create release
     needs: [create_tag]
     runs-on: ubuntu-latest
     outputs:
@@ -52,6 +59,9 @@ jobs:
   #
   # LLVM_LIBRARIES
   build_llvm_libraries_on_ubuntu_2004:
+    permissions:
+      contents: read
+      actions: write
     needs: [create_tag, create_release]
     uses: ./.github/workflows/build_llvm_libraries.yml
     with:
@@ -59,6 +69,9 @@ jobs:
       arch: "AArch64 ARM Mips RISCV X86"
 
   build_llvm_libraries_on_ubuntu_2204:
+    permissions:
+      contents: read
+      actions: write
     needs: [create_tag, create_release]
     uses: ./.github/workflows/build_llvm_libraries.yml
     with:
@@ -66,15 +79,30 @@ jobs:
       arch: "AArch64 ARM Mips RISCV X86"
 
   build_llvm_libraries_on_macos:
+    permissions:
+      contents: read
+      actions: write
     needs: [create_tag, create_release]
     uses: ./.github/workflows/build_llvm_libraries.yml
     with:
       os: "macos-13"
       arch: "AArch64 ARM Mips RISCV X86"
 
+  build_llvm_libraries_on_windows:
+    permissions:
+      contents: read
+      actions: write
+    needs: [create_tag, create_release]
+    uses: ./.github/workflows/build_llvm_libraries.yml
+    with:
+      os: "windows-latest"
+      arch: "AArch64 ARM Mips RISCV X86"
+
   #
   # WAMRC
   release_wamrc_on_ubuntu_2004:
+    permissions:
+      contents: write # upload release artifact
     needs: [create_tag, create_release, build_llvm_libraries_on_ubuntu_2004]
     uses: ./.github/workflows/build_wamrc.yml
     with:
@@ -85,6 +113,8 @@ jobs:
       ver_num: ${{ needs.create_tag.outputs.new_ver}}
 
   release_wamrc_on_ubuntu_2204:
+    permissions:
+      contents: write # upload release artifact
     needs: [create_tag, create_release, build_llvm_libraries_on_ubuntu_2204 ]
     uses: ./.github/workflows/build_wamrc.yml
     with:
@@ -95,6 +125,8 @@ jobs:
       ver_num: ${{ needs.create_tag.outputs.new_ver }}
 
   release_wamrc_on_ubuntu_macos:
+    permissions:
+      contents: write # upload release artifact
     needs: [create_tag, create_release, build_llvm_libraries_on_macos]
     uses: ./.github/workflows/build_wamrc.yml
     with:
@@ -103,10 +135,24 @@ jobs:
       runner: macos-13
       upload_url: ${{ needs.create_release.outputs.upload_url }}
       ver_num: ${{ needs.create_tag.outputs.new_ver }}
+  
+  release_wamrc_on_windows:
+    permissions:
+      contents: write # upload release artifact
+    needs: [create_tag, create_release, build_llvm_libraries_on_windows]
+    uses: ./.github/workflows/build_wamrc.yml
+    with:
+      llvm_cache_key: ${{ needs.build_llvm_libraries_on_windows.outputs.cache_key }}
+      release: true
+      runner: windows-latest
+      upload_url: ${{ needs.create_release.outputs.upload_url }}
+      ver_num: ${{ needs.create_tag.outputs.new_ver }}
 
   #
   # IWASM
   release_iwasm_on_ubuntu_2004:
+    permissions:
+      contents: write # upload release artifact
     needs: [create_tag, create_release, build_llvm_libraries_on_ubuntu_2004]
     uses: ./.github/workflows/build_iwasm_release.yml
     with:
@@ -117,6 +163,8 @@ jobs:
       ver_num: ${{ needs.create_tag.outputs.new_ver}}
 
   release_iwasm_on_ubuntu_2204:
+    permissions:
+      contents: write # upload release artifact
     needs: [create_tag, create_release, build_llvm_libraries_on_ubuntu_2204]
     uses: ./.github/workflows/build_iwasm_release.yml
     with:
@@ -127,6 +175,8 @@ jobs:
       ver_num: ${{ needs.create_tag.outputs.new_ver}}
 
   release_iwasm_on_macos:
+    permissions:
+      contents: write # upload release artifact
     needs: [create_tag, create_release, build_llvm_libraries_on_macos]
     uses: ./.github/workflows/build_iwasm_release.yml
     with:
@@ -136,9 +186,23 @@ jobs:
       upload_url: ${{ needs.create_release.outputs.upload_url }}
       ver_num: ${{ needs.create_tag.outputs.new_ver}}
 
+  release_iwasm_on_windows:
+    permissions:
+      contents: write # upload release artifact
+    needs: [create_tag, create_release, build_llvm_libraries_on_windows]
+    uses: ./.github/workflows/build_iwasm_release.yml
+    with:
+      cwd: product-mini/platforms/windows
+      llvm_cache_key: ${{ needs.build_llvm_libraries_on_windows.outputs.cache_key }}
+      runner: windows-latest
+      upload_url: ${{ needs.create_release.outputs.upload_url }}
+      ver_num: ${{ needs.create_tag.outputs.new_ver}}
+
   #
   # WAMR_SDK
   release_wamr_sdk_on_ubuntu_2004:
+    permissions:
+      contents: write # upload release artifact
     needs: [create_tag, create_release]
     uses: ./.github/workflows/build_wamr_sdk.yml
     with:
@@ -150,6 +214,8 @@ jobs:
       wamr_app_framework_url: https://github.com/bytecodealliance/wamr-app-framework.git
 
   release_wamr_sdk_on_ubuntu_2204:
+    permissions:
+      contents: write # upload release artifact
     needs: [create_tag, create_release]
     uses: ./.github/workflows/build_wamr_sdk.yml
     with:
@@ -161,6 +227,8 @@ jobs:
       wamr_app_framework_url: https://github.com/bytecodealliance/wamr-app-framework.git
 
   release_wamr_sdk_on_macos:
+    permissions:
+      contents: write # upload release artifact
     needs: [create_tag, create_release]
     uses: ./.github/workflows/build_wamr_sdk.yml
     with:
@@ -174,6 +242,8 @@ jobs:
   #
   # vscode extension cross-platform
   release_wamr_ide_vscode_ext:
+    permissions:
+      contents: write # upload release artifact
     needs: [create_tag, create_release]
     uses: ./.github/workflows/build_wamr_vscode_ext.yml
     secrets: inherit
@@ -184,6 +254,8 @@ jobs:
   #
   # vscode extension docker images package
   release_wamr_ide_docker_images_package:
+    permissions:
+      contents: write # upload release artifact
     needs: [create_tag, create_release]
     uses: ./.github/workflows/build_docker_images.yml
     with:
@@ -193,6 +265,8 @@ jobs:
   #
   # WAMR_LLDB
   release_wamr_lldb_on_ubuntu_2004:
+    permissions:
+      contents: write # upload release artifact
     needs: [create_tag, create_release]
     uses: ./.github/workflows/build_wamr_lldb.yml
     with:
@@ -201,6 +275,8 @@ jobs:
       ver_num: ${{ needs.create_tag.outputs.new_ver}}
 
   release_wamr_lldb_on_ubuntu_2204:
+    permissions:
+      contents: write # upload release artifact
     needs: [create_tag, create_release]
     uses: ./.github/workflows/build_wamr_lldb.yml
     with:
@@ -209,6 +285,8 @@ jobs:
       ver_num: ${{ needs.create_tag.outputs.new_ver}}
 
   release_wamr_lldb_on_macos_universal:
+    permissions:
+      contents: write # upload release artifact
     needs: [create_tag, create_release]
     uses: ./.github/workflows/build_wamr_lldb.yml
     with:

+ 6 - 0
.github/workflows/reuse_latest_release_binaries.yml

@@ -22,11 +22,17 @@ on:
       result:
         value: ${{ jobs.build.outputs.result }}
 
+permissions:
+  contents: read
+
 jobs:
   reuse:
     runs-on: ubuntu-latest
     outputs:
       result: ${{ steps.try_reuse.outputs.result }}
+    permissions:
+      contents: write # for creating realease and uploading release artifacts
+
     steps:
       - uses: actions/checkout@v4
         # Full git history is needed to get a proper list of commits and tags

+ 15 - 19
.github/workflows/spec_test_on_nuttx.yml

@@ -29,8 +29,14 @@ env:
   LLVM_CACHE_SUFFIX: "build-llvm_libraries_ex"
   WASI_SDK_PATH: "/opt/wasi-sdk"
 
+permissions:
+  contents: read
+
 jobs:
   build_llvm_libraries:
+    permissions:
+      contents: read
+      actions: write
     uses: ./.github/workflows/build_llvm_libraries.yml
     with:
       os: "ubuntu-22.04"
@@ -38,6 +44,9 @@ jobs:
       container_image: ghcr.io/no1wudi/nuttx/apache-nuttx-ci-linux@sha256:8c4e00b607d4d6d66ba8f51c4544819a616eac69d3a2ac669e2af2150e2eb0f9
 
   build_llvm_libraries_xtensa:
+    permissions:
+      contents: read
+      actions: write
     uses: ./.github/workflows/build_llvm_libraries.yml
     with:
       os: "ubuntu-22.04"
@@ -74,11 +83,11 @@ jobs:
             target: "riscv32",
             fpu_type: "none"
           },
-          {
-            config: "boards/risc-v/qemu-rv/rv-virt/configs/nsh",
-            target: "riscv32_ilp32f",
-            fpu_type: "fp"
-          },
+          #{
+          #  config: "boards/risc-v/qemu-rv/rv-virt/configs/nsh",
+          #  target: "riscv32_ilp32f",
+          #  fpu_type: "fp"
+          #},
           # {
           #   config: "boards/risc-v/qemu-rv/rv-virt/configs/nsh",
           #   target: "riscv32_ilp32d",
@@ -327,19 +336,6 @@ jobs:
         working-directory: apps/interpreters/wamr/wamr
 
       - name: Test
-        if: matrix.target_config.target != 'xtensa'
-        run: |
-          cd apps/interpreters/wamr/wamr/tests/wamr-test-suites
-          ./test_wamr.sh -s spec ${{ matrix.wamr_test_option.mode }} -m ${{ matrix.target_config.target }} -b -Q -P -F ${{ steps.build_firmware_path.outputs.firmware }} ${{ matrix.wamr_feature_option.mode}}
-
-      # for xtensa, for some reasons, when running the tests
-      # with test_wamr.sh -P, nuttx occasionally hangs after
-      # "total segments stored 6" on the CI.
-      # i (yamamoto) couldn't reproduce it locally (macOS) even
-      # with the identical flash image.
-      # for now, run the tests without -P.
-      - name: Test
-        if: matrix.target_config.target == 'xtensa'
         run: |
           cd apps/interpreters/wamr/wamr/tests/wamr-test-suites
           ./test_wamr.sh -s spec ${{ matrix.wamr_test_option.mode }} -m ${{ matrix.target_config.target }} -b -Q -F ${{ steps.build_firmware_path.outputs.firmware }} ${{ matrix.wamr_feature_option.mode}}
@@ -354,7 +350,7 @@ jobs:
 
       - name: upload the log
         if: always()
-        uses: actions/upload-artifact@v4
+        uses: actions/upload-artifact@v4.4.3
         with:
           name: spec-test-log-${{ github.run_id }}-${{ strategy.job-index }}-${{ matrix.target_config.target }}
           path: log

+ 65 - 0
.github/workflows/supply_chain.yml

@@ -0,0 +1,65 @@
+# This workflow uses actions that are not certified by GitHub. They are provided
+# by a third-party and are governed by separate terms of service, privacy
+# policy, and support documentation.
+
+# Check current WASM Micro Runtime results here: https://securityscorecards.dev/viewer/?uri=github.com/bytecodealliance/wasm-micro-runtime
+
+name: Scorecard supply-chain security
+on:
+  # For Branch-Protection check. Only the default branch is supported. See
+  # https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection
+  branch_protection_rule:
+  # To guarantee Maintained check is occasionally updated. See
+  # https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained
+  # midnight UTC
+  schedule:
+    - cron: "0 0 * * *"
+  # allow to be triggered manually
+  workflow_dispatch:
+
+# Declare default permissions as read only.
+permissions:
+  contents: read
+
+jobs:
+  analysis:
+    name: Scorecard analysis
+    runs-on: ubuntu-latest
+    if: github.repository == 'bytecodealliance/wasm-micro-runtime'
+    permissions:
+      # Needed to upload the results to code-scanning dashboard.
+      security-events: write
+      # Needed to publish results and get a badge (see publish_results below).
+      id-token: write      
+
+    steps:
+      - name: "Checkout code"
+        uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0
+        with:
+          persist-credentials: false
+
+      - name: "Run analysis"
+        uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.0
+        with:
+          results_file: results.sarif
+          results_format: sarif
+
+          #   - Publish results to OpenSSF REST API for easy access by consumers
+          #   - Allows the repository to include the Scorecard badge.
+          #   - See https://github.com/ossf/scorecard-action#publishing-results.      
+          publish_results: true
+
+      # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
+      # format to the repository Actions tab.
+      - name: "Upload artifact"
+        uses: actions/upload-artifact@184d73b71b93c222403b2e7f1ffebe4508014249 # v3.1.0
+        with:
+          name: SARIF file
+          path: results.sarif
+          retention-days: 5
+
+      # Upload the results to GitHub's code scanning dashboard.
+      - name: "Upload to code-scanning"
+        uses: github/codeql-action/upload-sarif@af56b044b5d41c317aef5d19920b3183cb4fbbec # v2.2.4
+        with:
+          sarif_file: results.sarif

+ 1 - 0
.gitignore

@@ -13,6 +13,7 @@
 .clangd
 .DS_Store
 *.o
+.aider*
 
 core/deps/**
 core/shared/mem-alloc/tlsf

+ 1 - 1
ATTRIBUTIONS.md

@@ -60,7 +60,7 @@ The WAMR fast interpreter is a clean room development. We would acknowledge the
 
 ### llvm
 
-[LICENSE](./LICENCE.txt)
+[LICENSE](./LICENSE)
 
 ### wasm-c-api
 

+ 27 - 5
CMakeLists.txt

@@ -121,10 +121,15 @@ set (WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR})
 
 include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake)
 
-set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat -Wformat-security -Wshadow -Wno-unused-parameter -fvisibility=hidden")
-# set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wconversion -Wsign-conversion")
-
-set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wformat -Wformat-security -Wno-unused")
+if (NOT WIN32)
+  set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat -Wformat-security \
+                                       -ffunction-sections -fdata-sections \
+                                       -Wno-unused-parameter -Wno-pedantic \
+                                       -fvisibility=hidden")
+  # Remove the extra spaces for better make log
+  string (REGEX REPLACE "  *" " " CMAKE_C_FLAGS ${CMAKE_C_FLAGS})
+  set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wformat -Wformat-security -Wno-unused")
+endif()
 
 if (WAMR_BUILD_TARGET MATCHES "X86_.*" OR WAMR_BUILD_TARGET STREQUAL "AMD_64")
   if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang"))
@@ -145,6 +150,10 @@ include (${SHARED_DIR}/utils/uncommon/shared_uncommon.cmake)
 set (THREADS_PREFER_PTHREAD_FLAG ON)
 find_package(Threads REQUIRED)
 
+if (MSVC)
+  add_definitions(-DCOMPILING_WASM_RUNTIME_API=1)
+endif ()
+
 # STATIC LIBRARY
 if (WAMR_BUILD_STATIC)
     add_library(iwasm_static STATIC ${WAMR_RUNTIME_LIB_SOURCE})
@@ -155,6 +164,14 @@ if (WAMR_BUILD_STATIC)
       target_link_libraries(iwasm_static INTERFACE boringssl_crypto)
     endif ()
 
+    if (MINGW)
+      target_link_libraries (iwasm_static PRIVATE ws2_32)
+    endif ()
+
+    if (WIN32)
+      target_link_libraries(iwasm_static PRIVATE ntdll)
+    endif()
+
     install (TARGETS iwasm_static ARCHIVE DESTINATION lib)
 endif ()
 
@@ -169,9 +186,14 @@ if (WAMR_BUILD_SHARED)
     endif ()
 
     if (MINGW)
-      target_link_libraries (iwasm_shared INTERFACE -lWs2_32 -lwsock32)
+      target_link_libraries(iwasm_shared INTERFACE -lWs2_32 -lwsock32)
+      target_link_libraries(iwasm_shared PRIVATE ws2_32)
     endif ()
 
+    if (WIN32)
+      target_link_libraries(iwasm_shared PRIVATE ntdll)
+    endif()
+
     install (TARGETS iwasm_shared LIBRARY DESTINATION lib)
 endif ()
 

+ 29 - 0
CODEOWNERS

@@ -0,0 +1,29 @@
+# In this project, we use CODEOWNERS to identify people who are likely to know
+# who should review a pull request.
+#
+# People listed in this file are committing to respond in a timely fashion to
+# PRs in the selected areas. However, that response doesn't have to be a full
+# code review; it could also take any of these forms:
+#
+# - "I intend to review this but I can't yet. Please leave me a message if I
+#   haven't responded by (a specific date in the near future)."
+#
+# - "I think (a specific other contributor) should review this." (Note that the
+#   best reviewer for a PR may not necessarily be listed in this file.)
+#
+# People must only be added to this file if they've agreed to provide one of
+# the above responses in a reasonable amount of time for every PR to which
+# they're assigned.
+#
+# We only ask for this commitment from people who are employed full-time to
+# work on this project. We gratefully welcome reviews from other contributors,
+# but we don't believe it's fair to ask volunteers to respond quickly.
+
+# If none of the later patterns match, assign to anyone. This team is the
+# parent of all the other teams and automatically includes everyone on those
+# teams.
+* @loganek @lum1n0us @no1wudi @wenyongh @xujuntwt95329 @yamt
+
+# Some parts of the project require more specialized knowledge. In those areas
+# we designate smaller groups who are more likely to be aware of who's working
+# in specific areas.

+ 82 - 0
RELEASE_NOTES.md

@@ -1,3 +1,85 @@
+## WAMR-2.2.0
+
+### Breaking changes 
+
+### New features 
+- Add support for multi-memory proposal in classic interpreter (#3742) 
+- wasi-nn: Add a new target for llama.cpp as a wasi-nn backend (#3709)
+- Add memory instance support apis (#3786) 
+- Implement a first version of shared heap feature (#3789) 
+- Support dynamic aot debug (#3788) 
+- Implement shared heap for AOT (#3815)
+- Support table64 extension in classic-interp and AOT running modes (#3811)
+  
+
+### Bug fixes
+- Enable merged os_mmap for aot data sections (#3681) 
+- Fix arm64 issues on mac (#3688) 
+- aot loader: Call os_mmap with MMAP_MAP_32BIT only when target is x86-64 or riscv64 (#3755)
+- Fix building iwasm_shared and iwasm_static libs on win32 (#3762) 
+- Fix compile error when multi-module and tags are enabled (#3781)
+- Fix aot multi export memory support (#3791)
+- Fix Windows compile error when uvwasi is enabled (#3810)
+- Fix missing symbols when using aot mode on riscv platforms (#3812)
+- Fix mac build of libc_emcc_wrapper.c (#3836)
+- aot_comp_option.h: Add missing stdint.h header (#3834)
+- Fix compilation error found in tflite test (#3820) 
+- Fix exec_env_tls assertion in module instantiation (#3844) 
+- Fix issues of destroy_shared_heaps (#3847)
+
+### Enhancements
+- aot loader: Refine os_mmap related code (#3711)
+- Enable merged os_mmap for aot data sections and aot text (#3743)
+- Improve posix mmap retry logic (#3714)
+- Remove unnecessary code duplication in aot runtime (#3767)
+- Add wamrc parameter to configure stack frame features (#3763) 
+- refactoring: Re-use commit IP functionality between exception handling and other cases (#3768)
+- AOT call stack optimizations (#3773) 
+- Appease GCC strict prototypes warning (#3775)
+- Appease GCC -Wformat (#3783)
+- Fix compiler warnings (#3784)
+- Implement option for skipping function index in the callstack (#3785)
+- Fix a compile warning in aot_emit_function.c (#3793) 
+- Restore cmake hidden compile symbol visibility (#3796)
+- Refactor shared heap feature for interpreter mode (#3794)
+- Add no_resolve to LoadArgs and wasm_runtime_resolve_symbols (#3790)
+- shared heap: Fix some issues and add basic unit test case (#3801)
+- Add shared heap sample (#3806)
+- Fix unused param warning when GC is enabled (#3814)
+- Add scoreboard CI for supply-chain security (#3819)
+- Emit load_addr and load_size if WAMR_ENABLE_COMPILER is set (#3835)
+- libc-emcc: Use alternate method to check getrandom support (#3848)
+- Enable libc-wasi for windows msvc build (#3852) 
+- Remove unused folder samples/gui and samples/littlevgl (#3853) 
+- Fix some compile warnings and typos (#3854)
+- Allow to set native stack boundary to exec_env (#3862)
+- Refine wasm/aot function instance lookup (#3865)
+- Fix quadratic runtime for duplicate export name detection (#3861)
+
+  
+### Others
+- Add a comment on AOT_SECTION_TYPE_SIGNATURE (#3746) 
+- CI: Freeze version of bloaty for NuttX compilation (#3756)
+- aot compiler: Allow to control stack boundary check when boundary check is enabled (#3754)
+- Update ref to the multi-memory tests (#3764)
+- compilation_on_nuttx.yml: Update checkout action to suppress warnings (#3765)
+- CI: Disable parallel test in spectest for NuttX (#3780)
+- spec_test_on_nuttx.yml: Disable riscv32_ilp32f for now (#3777) 
+- Ignore temporary file from aider (#3787)
+- Add CODEOWNERS (#3822)
+- build(deps): bump github/codeql-action from 2.2.4 to 3.26.9 (#3826)
+- build(deps): bump actions/upload-artifact from 3.1.0 to 4.4.0 (#3827)
+- build(deps): bump ossf/scorecard-action from 2.3.1 to 2.4.0 (#3828)
+- build(deps): bump github/codeql-action from 3.26.9 to 3.26.11 (#3843) 
+- build(deps): bump actions/upload-artifact from 4.4.0 to 4.4.3 (#3855)
+- build(deps): bump github/codeql-action from 3.26.11 to 3.26.12 (#3856)
+- Add Windows wamrc and iwasm build in release CI (#3857)
+- Fix syntax error in codeql_buildscript.sh (#3864)
+- release CI: Add another iwasm binary that supports Garbage Collection and Exception Handling (#3866)
+- Fix lookup function issue reported in nightly run (#3868)
+ 
+---
+
 ## WAMR-2.1.2
 
 ### Breaking Changes

+ 32 - 4
build-scripts/build_llvm.py

@@ -125,9 +125,7 @@ def build_llvm(llvm_dir, platform, backends, projects, use_clang=False, extra_fl
     if not llvm_dir.exists():
         raise Exception(f"{llvm_dir} doesn't exist")
 
-    build_dir = llvm_dir.joinpath(
-        "win32build" if "windows" == platform else "build"
-    ).resolve()
+    build_dir = llvm_dir.joinpath("build").resolve()
     build_dir.mkdir(exist_ok=True)
 
     lib_llvm_core_library = build_dir.joinpath("lib/libLLVMCore.a").resolve()
@@ -178,6 +176,7 @@ def repackage_llvm(llvm_dir):
         raise Exception("Find more than one LLVM-*.tar.gz")
 
     if not packs:
+        raise Exception("Didn't find any LLVM-* package")
         return
 
     llvm_package = packs[0].name
@@ -193,6 +192,31 @@ def repackage_llvm(llvm_dir):
     # rm ./LLVM-1*.gz
     os.remove(llvm_dir.joinpath(llvm_package).resolve())
 
+def repackage_llvm_windows(llvm_dir):
+    build_dir = llvm_dir.joinpath("./build").resolve()
+
+    packs_path = [f for f in build_dir.glob("./_CPack_Packages/win64/NSIS/LLVM-*-win64")]
+    if len(packs_path) > 1:
+        raise Exception("Find more than one LLVM-* package")
+
+    if not packs_path:
+        raise Exception("Didn't find any LLVM-* package")
+        return
+    
+    llvm_package_path = f"_CPack_Packages/win64/NSIS/{packs_path[0].name}"
+    windows_package_dir = build_dir.joinpath(llvm_package_path).resolve()
+
+    # mv package dir outside of build 
+    shutil.move(str(windows_package_dir), str(llvm_dir))
+    # rm -r build
+    shutil.rmtree(str(build_dir))
+    # mkdir build
+    build_dir.mkdir()
+    # move back all the subdiretories under cpack directory(bin/include/lib) to build dir
+    moved_package_dir = llvm_dir.joinpath(packs_path[0].name)
+    for sub_dir in moved_package_dir.iterdir():
+        shutil.move(str(sub_dir), str(build_dir))
+    moved_package_dir.rmdir()  
 
 def main():
     parser = argparse.ArgumentParser(description="build necessary LLVM libraries")
@@ -304,7 +328,11 @@ def main():
             )
             is not None
         ):
-            repackage_llvm(llvm_dir)
+            # TODO: repackage process may change in the future, this work for LLVM 15.x
+            if "windows" == platform:
+                repackage_llvm_windows(llvm_dir)
+            else:
+                repackage_llvm(llvm_dir)
 
         return True
     except subprocess.CalledProcessError:

+ 17 - 5
build-scripts/config_common.cmake

@@ -102,9 +102,6 @@ if (WAMR_BUILD_JIT EQUAL 1)
   if (NOT DEFINED LLVM_DIR)
     set (LLVM_SRC_ROOT "${WAMR_ROOT_DIR}/core/deps/llvm")
     set (LLVM_BUILD_ROOT "${LLVM_SRC_ROOT}/build")
-    if (WAMR_BUILD_PLATFORM STREQUAL "windows")
-      set (LLVM_BUILD_ROOT "${LLVM_SRC_ROOT}/win32build")
-    endif ()
     if (NOT EXISTS "${LLVM_BUILD_ROOT}")
         message (FATAL_ERROR "Cannot find LLVM dir: ${LLVM_BUILD_ROOT}")
     endif ()
@@ -256,6 +253,11 @@ if (WAMR_BUILD_SHARED_MEMORY EQUAL 1)
 else ()
   add_definitions (-DWASM_ENABLE_SHARED_MEMORY=0)
 endif ()
+if (WAMR_BUILD_SHARED_HEAP EQUAL 1)
+  add_definitions (-DWASM_ENABLE_SHARED_HEAP=1)
+  message ("     Shared heap enabled")
+endif()
+
 if (WAMR_BUILD_MEMORY64 EQUAL 1)
   # if native is 32-bit or cross-compiled to 32-bit
   if (NOT WAMR_BUILD_TARGET MATCHES ".*64.*")
@@ -404,6 +406,10 @@ endif ()
 if (WAMR_BUILD_DEBUG_AOT EQUAL 1)
     message ("     Debug AOT enabled")
 endif ()
+if (WAMR_BUILD_DYNAMIC_AOT_DEBUG EQUAL 1)
+    add_definitions (-DWASM_ENABLE_DYNAMIC_AOT_DEBUG=1)
+    message ("     Dynamic AOT debug enabled")
+endif ()
 if (WAMR_BUILD_LOAD_CUSTOM_SECTION EQUAL 1)
     add_definitions (-DWASM_ENABLE_LOAD_CUSTOM_SECTION=1)
     message ("     Load custom section enabled")
@@ -442,7 +448,9 @@ if (WAMR_BUILD_WASI_NN EQUAL 1)
   message ("     WASI-NN enabled")
   add_definitions (-DWASM_ENABLE_WASI_NN=1)
   # Variant backends
-  if (NOT WAMR_BUILD_WASI_NN_TFLITE EQUAL 1 AND NOT WAMR_BUILD_WASI_NN_OPENVINO EQUAL 1)
+  if (NOT WAMR_BUILD_WASI_NN_TFLITE EQUAL 1 AND
+      NOT WAMR_BUILD_WASI_NN_OPENVINO EQUAL 1 AND
+      NOT WAMR_BUILD_WASI_NN_LLAMACPP EQUAL 1)
     message (FATAL_ERROR "   Need to select a backend for WASI-NN")
   endif ()
 
@@ -454,6 +462,10 @@ if (WAMR_BUILD_WASI_NN EQUAL 1)
     message ("     WASI-NN: backend openvino enabled")
     add_definitions (-DWASM_ENABLE_WASI_NN_OPENVINO)
   endif ()
+  if (WAMR_BUILD_WASI_NN_LLAMACPP EQUAL 1)
+    message ("     WASI-NN: backend llamacpp enabled")
+    add_definitions (-DWASM_ENABLE_WASI_NN_LLAMACPP)
+  endif ()
   # Variant devices
   if (WAMR_BUILD_WASI_NN_ENABLE_GPU EQUAL 1)
       message ("     WASI-NN: GPU enabled")
@@ -483,7 +495,7 @@ if (WAMR_BUILD_MODULE_INST_CONTEXT EQUAL 1)
   message ("     Module instance context enabled")
 endif ()
 if (WAMR_BUILD_GC_HEAP_VERIFY EQUAL 1)
-  add_definitions (-DWASM_ENABLE_GC_VERIFY=1)
+  add_definitions (-DBH_ENABLE_GC_VERIFY=1)
   message ("     GC heap verification enabled")
 endif ()
 if ("$ENV{COLLECT_CODE_COVERAGE}" STREQUAL "1" OR COLLECT_CODE_COVERAGE EQUAL 1)

+ 15 - 1
build-scripts/runtime_lib.cmake

@@ -59,7 +59,12 @@ if (WAMR_BUILD_INTERP EQUAL 1)
 endif ()
 
 if (WAMR_BUILD_FAST_JIT EQUAL 1)
-    include (${IWASM_DIR}/fast-jit/iwasm_fast_jit.cmake)
+    if (WAMR_BUILD_PLATFORM STREQUAL "windows")
+        message ("Fast JIT currently not supported on Windows")
+        set (WAMR_BUILD_FAST_JIT 0)
+    else ()
+        include (${IWASM_DIR}/fast-jit/iwasm_fast_jit.cmake)
+    endif ()
 endif ()
 
 if (WAMR_BUILD_JIT EQUAL 1)
@@ -104,6 +109,10 @@ if (WAMR_BUILD_WASI_NN EQUAL 1)
 endif ()
 
 if (WAMR_BUILD_LIB_PTHREAD EQUAL 1)
+    if (WAMR_BUILD_PLATFORM STREQUAL "windows")
+        set (WAMR_BUILD_LIB_PTHREAD_SEMAPHORE 0)
+        message ("Lib pthread semaphore currently not supported on Windows")
+    endif ()
     include (${IWASM_DIR}/libraries/lib-pthread/lib_pthread.cmake)
     # Enable the dependent feature if lib pthread is enabled
     set (WAMR_BUILD_THREAD_MGR 1)
@@ -119,6 +128,10 @@ if (WAMR_BUILD_LIB_WASI_THREADS EQUAL 1)
     set (WAMR_BUILD_SHARED_MEMORY 1)
 endif ()
 
+if (WAMR_BUILD_SHARED_HEAP EQUAL 1)
+    include (${IWASM_DIR}/libraries/shared-heap/shared_heap.cmake)
+endif ()
+
 if (WAMR_BUILD_DEBUG_INTERP EQUAL 1)
     set (WAMR_BUILD_THREAD_MGR 1)
     include (${IWASM_DIR}/libraries/debug-engine/debug_engine.cmake)
@@ -193,6 +206,7 @@ set (source_all
     ${LIBC_EMCC_SOURCE}
     ${LIB_RATS_SOURCE}
     ${DEBUG_ENGINE_SOURCE}
+    ${LIB_SHARED_HEAP_SOURCE}
 )
 
 set (WAMR_RUNTIME_LIB_SOURCE ${source_all})

+ 1 - 0
ci/coding_guidelines_check.py

@@ -180,6 +180,7 @@ def check_file_name(path: Path) -> bool:
         "docker-compose",
         "package-lock",
         "vite-env.d",
+        "osv-scanner",
     ]:
         return True
 

+ 11 - 1
core/config.h

@@ -75,6 +75,10 @@
 #define WASM_ENABLE_AOT 0
 #endif
 
+#ifndef WASM_ENABLE_DYNAMIC_AOT_DEBUG
+#define WASM_ENABLE_DYNAMIC_AOT_DEBUG 0
+#endif
+
 #ifndef WASM_ENABLE_WORD_ALIGN_READ
 #define WASM_ENABLE_WORD_ALIGN_READ 0
 #endif
@@ -392,7 +396,9 @@
 #define APP_HEAP_SIZE_DEFAULT (8 * 1024)
 #endif
 #define APP_HEAP_SIZE_MIN (256)
-#define APP_HEAP_SIZE_MAX (512 * 1024 * 1024)
+/* The ems memory allocator supports maximal heap size 1GB,
+   see ems_gc_internal.h */
+#define APP_HEAP_SIZE_MAX (1024 * 1024 * 1024)
 
 /* Default min/max gc heap size of each app */
 #ifndef GC_HEAP_SIZE_DEFAULT
@@ -688,4 +694,8 @@
 #endif
 #endif /* WASM_ENABLE_FUZZ_TEST != 0 */
 
+#ifndef WASM_ENABLE_SHARED_HEAP
+#define WASM_ENABLE_SHARED_HEAP 0
+#endif
+
 #endif /* end of _CONFIG_H_ */

+ 143 - 139
core/iwasm/aot/aot_loader.c

@@ -4,9 +4,8 @@
  */
 
 #include "aot_runtime.h"
-#include "bh_common.h"
-#include "bh_log.h"
 #include "aot_reloc.h"
+#include "bh_platform.h"
 #include "../common/wasm_runtime_common.h"
 #include "../common/wasm_native.h"
 #include "../common/wasm_loader_common.h"
@@ -302,7 +301,10 @@ loader_mmap(uint32 size, bool prot_exec, char *error_buf, uint32 error_buf_size)
     int map_flags;
     void *mem;
 
-#if UINTPTR_MAX == UINT64_MAX
+#if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64) \
+    || defined(BUILD_TARGET_RISCV64_LP64D)                       \
+    || defined(BUILD_TARGET_RISCV64_LP64)
+#ifndef __APPLE__
     /* The mmapped AOT data and code in 64-bit targets had better be in
        range 0 to 2G, or aot loader may fail to apply some relocations,
        e.g., R_X86_64_32/R_X86_64_32S/R_X86_64_PC32/R_RISCV_32.
@@ -316,6 +318,7 @@ loader_mmap(uint32 size, bool prot_exec, char *error_buf, uint32 error_buf_size)
         bh_assert((uintptr_t)mem < INT32_MAX);
         return mem;
     }
+#endif
 #endif
 
     map_flags = MMAP_MAP_NONE;
@@ -579,6 +582,10 @@ load_target_info_section(const uint8 *buf, const uint8 *buf_end,
         return false;
     }
 
+    /* for backwards compatibility with previous wamrc aot files */
+    if (!strcmp(target_info.arch, "arm64"))
+        bh_strcpy_s(target_info.arch, sizeof(target_info.arch), "aarch64v8");
+
     /* Check machine info */
     if (!check_machine_info(&target_info, error_buf, error_buf_size)) {
         return false;
@@ -589,6 +596,10 @@ load_target_info_section(const uint8 *buf, const uint8 *buf_end,
         return false;
     }
 
+#if WASM_ENABLE_DUMP_CALL_STACK != 0
+    module->feature_flags = target_info.feature_flags;
+#endif
+
     /* Finally, check feature flags */
     return check_feature_flags(error_buf, error_buf_size,
                                target_info.feature_flags);
@@ -622,73 +633,6 @@ str2uint32(const char *buf, uint32 *p_res);
 static bool
 str2uint64(const char *buf, uint64 *p_res);
 
-#if WASM_ENABLE_MULTI_MODULE != 0
-static void *
-aot_loader_resolve_function(const AOTModule *module, const char *function_name,
-                            const AOTFuncType *expected_function_type,
-                            char *error_buf, uint32 error_buf_size);
-
-static void *
-aot_loader_resolve_function_ex(const char *module_name,
-                               const char *function_name,
-                               const AOTFuncType *expected_function_type,
-                               char *error_buf, uint32 error_buf_size)
-{
-    WASMModuleCommon *module_reg;
-
-    module_reg = wasm_runtime_find_module_registered(module_name);
-    if (!module_reg || module_reg->module_type != Wasm_Module_AoT) {
-        LOG_DEBUG("can not find a module named %s for function %s", module_name,
-                  function_name);
-        set_error_buf(error_buf, error_buf_size, "unknown import");
-        return NULL;
-    }
-    return aot_loader_resolve_function((AOTModule *)module_reg, function_name,
-                                       expected_function_type, error_buf,
-                                       error_buf_size);
-}
-
-static void *
-aot_loader_resolve_function(const AOTModule *module, const char *function_name,
-                            const AOTFuncType *expected_function_type,
-                            char *error_buf, uint32 error_buf_size)
-{
-    void *function = NULL;
-    AOTExport *export = NULL;
-    AOTFuncType *target_function_type = NULL;
-
-    export = loader_find_export((WASMModuleCommon *)module, module->name,
-                                function_name, EXPORT_KIND_FUNC, error_buf,
-                                error_buf_size);
-    if (!export) {
-        return NULL;
-    }
-
-    /* resolve function type and function */
-    if (export->index < module->import_func_count) {
-        target_function_type = module->import_funcs[export->index].func_type;
-        function = module->import_funcs[export->index].func_ptr_linked;
-    }
-    else {
-        target_function_type =
-            (AOTFuncType *)module
-                ->types[module->func_type_indexes[export->index
-                                                  - module->import_func_count]];
-        function =
-            (module->func_ptrs[export->index - module->import_func_count]);
-    }
-    /* check function type */
-    if (!wasm_type_equal((WASMType *)expected_function_type,
-                         (WASMType *)target_function_type, module->types,
-                         module->type_count)) {
-        LOG_DEBUG("%s.%s failed the type check", module->name, function_name);
-        set_error_buf(error_buf, error_buf_size, "incompatible import type");
-        return NULL;
-    }
-    return function;
-}
-#endif /* end of WASM_ENABLE_MULTI_MODULE */
-
 static bool
 load_native_symbol_section(const uint8 *buf, const uint8 *buf_end,
                            AOTModule *module, bool is_load_from_file_buf,
@@ -1437,6 +1381,12 @@ load_table_list(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module,
     for (i = 0; i < module->table_count; i++, table++) {
         read_uint8(buf, buf_end, table->table_type.elem_type);
         read_uint8(buf, buf_end, table->table_type.flags);
+
+        if (!wasm_table_check_flags(table->table_type.flags, error_buf,
+                                    error_buf_size, true)) {
+            return false;
+        }
+
         read_uint8(buf, buf_end, table->table_type.possible_grow);
 #if WASM_ENABLE_GC != 0
         if (wasm_is_type_multi_byte_type(table->table_type.elem_type)) {
@@ -2273,19 +2223,13 @@ destroy_import_funcs(AOTImportFunc *import_funcs)
 
 static bool
 load_import_funcs(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module,
-                  bool is_load_from_file_buf, char *error_buf,
+                  bool is_load_from_file_buf, bool no_resolve, char *error_buf,
                   uint32 error_buf_size)
 {
-    char *module_name, *field_name;
     const uint8 *buf = *p_buf;
     AOTImportFunc *import_funcs;
     uint64 size;
     uint32 i;
-#if WASM_ENABLE_MULTI_MODULE != 0
-    AOTModule *sub_module = NULL;
-    AOTFunc *linked_func = NULL;
-    AOTFuncType *declare_func_type = NULL;
-#endif
 
     /* Allocate memory */
     size = sizeof(AOTImportFunc) * (uint64)module->import_func_count;
@@ -2302,53 +2246,17 @@ load_import_funcs(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module,
             return false;
         }
 
-#if WASM_ENABLE_MULTI_MODULE != 0
-        declare_func_type =
-            (AOTFuncType *)module->types[import_funcs[i].func_type_index];
-        read_string(buf, buf_end, module_name);
-        read_string(buf, buf_end, field_name);
-
-        import_funcs[i].module_name = module_name;
-        import_funcs[i].func_name = field_name;
-        linked_func = wasm_native_resolve_symbol(
-            module_name, field_name, declare_func_type,
-            &import_funcs[i].signature, &import_funcs[i].attachment,
-            &import_funcs[i].call_conv_raw);
-        if (!linked_func) {
-            sub_module = NULL;
-            if (!wasm_runtime_is_built_in_module(module_name)) {
-                sub_module = (AOTModule *)wasm_runtime_load_depended_module(
-                    (WASMModuleCommon *)module, module_name, error_buf,
-                    error_buf_size);
-                if (!sub_module) {
-                    LOG_ERROR("failed to load sub module: %s", error_buf);
-                    return false;
-                }
-            }
-            if (!sub_module)
-                linked_func = aot_loader_resolve_function_ex(
-                    module_name, field_name, declare_func_type, error_buf,
-                    error_buf_size);
-            else
-                linked_func = aot_loader_resolve_function(
-                    sub_module, field_name, declare_func_type, error_buf,
-                    error_buf_size);
-        }
-        import_funcs[i].func_ptr_linked = linked_func;
-        import_funcs[i].func_type = declare_func_type;
-
-#else
         import_funcs[i].func_type =
             (AOTFuncType *)module->types[import_funcs[i].func_type_index];
         read_string(buf, buf_end, import_funcs[i].module_name);
         read_string(buf, buf_end, import_funcs[i].func_name);
-        module_name = import_funcs[i].module_name;
-        field_name = import_funcs[i].func_name;
-        import_funcs[i].func_ptr_linked = wasm_native_resolve_symbol(
-            module_name, field_name, import_funcs[i].func_type,
-            &import_funcs[i].signature, &import_funcs[i].attachment,
-            &import_funcs[i].call_conv_raw);
-#endif
+        import_funcs[i].attachment = NULL;
+        import_funcs[i].signature = NULL;
+        import_funcs[i].call_conv_raw = false;
+
+        if (!no_resolve) {
+            aot_resolve_import_func(module, &import_funcs[i]);
+        }
 
 #if WASM_ENABLE_LIBC_WASI != 0
         if (!strcmp(import_funcs[i].module_name, "wasi_unstable")
@@ -2366,7 +2274,7 @@ fail:
 static bool
 load_import_func_info(const uint8 **p_buf, const uint8 *buf_end,
                       AOTModule *module, bool is_load_from_file_buf,
-                      char *error_buf, uint32 error_buf_size)
+                      bool no_resolve, char *error_buf, uint32 error_buf_size)
 {
     const uint8 *buf = *p_buf;
 
@@ -2375,7 +2283,7 @@ load_import_func_info(const uint8 **p_buf, const uint8 *buf_end,
     /* load import funcs */
     if (module->import_func_count > 0
         && !load_import_funcs(&buf, buf_end, module, is_load_from_file_buf,
-                              error_buf, error_buf_size))
+                              no_resolve, error_buf, error_buf_size))
         return false;
 
     *p_buf = buf;
@@ -2502,7 +2410,7 @@ fail:
 static bool
 load_init_data_section(const uint8 *buf, const uint8 *buf_end,
                        AOTModule *module, bool is_load_from_file_buf,
-                       char *error_buf, uint32 error_buf_size)
+                       bool no_resolve, char *error_buf, uint32 error_buf_size)
 {
     const uint8 *p = buf, *p_end = buf_end;
 
@@ -2513,7 +2421,7 @@ load_init_data_section(const uint8 *buf, const uint8 *buf_end,
                                     error_buf, error_buf_size)
         || !load_global_info(&p, p_end, module, error_buf, error_buf_size)
         || !load_import_func_info(&p, p_end, module, is_load_from_file_buf,
-                                  error_buf, error_buf_size))
+                                  no_resolve, error_buf, error_buf_size))
         return false;
 
     /* load function count and start function index */
@@ -2603,6 +2511,15 @@ try_merge_data_and_text(const uint8 **buf, const uint8 **buf_end,
         /* merge failed but may be not critical for some targets */
         return false;
     }
+
+#ifdef BH_PLATFORM_WINDOWS
+    if (!os_mem_commit(sections, code_size,
+                       MMAP_PROT_READ | MMAP_PROT_WRITE | MMAP_PROT_EXEC)) {
+        os_munmap(sections, (uint32)total_size);
+        return false;
+    }
+#endif
+
     /* change the code part to be executable */
     if (os_mprotect(sections, code_size,
                     MMAP_PROT_READ | MMAP_PROT_WRITE | MMAP_PROT_EXEC)
@@ -2617,7 +2534,7 @@ try_merge_data_and_text(const uint8 **buf, const uint8 **buf_end,
     /* order not essential just as compiler does: .text section first */
     *buf = sections;
     *buf_end = sections + code_size;
-    bh_memcpy_s(sections, code_size, old_buf, code_size);
+    bh_memcpy_s(sections, (uint32)code_size, old_buf, (uint32)code_size);
     os_munmap(old_buf, code_size);
     sections += align_uint((uint32)code_size, page_size);
 
@@ -2835,6 +2752,48 @@ destroy_exports(AOTExport *exports)
     wasm_runtime_free(exports);
 }
 
+static int
+cmp_export_name(const void *a, const void *b)
+{
+    return strcmp(*(char **)a, *(char **)b);
+}
+
+static bool
+check_duplicate_exports(AOTModule *module, char *error_buf,
+                        uint32 error_buf_size)
+{
+    uint32 i;
+    bool result = false;
+    char *names_buf[32], **names = names_buf;
+    if (module->export_count > 32) {
+        names = loader_malloc(module->export_count * sizeof(char *), error_buf,
+                              error_buf_size);
+        if (!names) {
+            return result;
+        }
+    }
+
+    for (i = 0; i < module->export_count; i++) {
+        names[i] = module->exports[i].name;
+    }
+
+    qsort(names, module->export_count, sizeof(char *), cmp_export_name);
+
+    for (i = 1; i < module->export_count; i++) {
+        if (!strcmp(names[i], names[i - 1])) {
+            set_error_buf(error_buf, error_buf_size, "duplicate export name");
+            goto cleanup;
+        }
+    }
+
+    result = true;
+cleanup:
+    if (module->export_count > 32) {
+        wasm_runtime_free(names);
+    }
+    return result;
+}
+
 static bool
 load_exports(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module,
              bool is_load_from_file_buf, char *error_buf, uint32 error_buf_size)
@@ -2856,14 +2815,58 @@ load_exports(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module,
         read_uint32(buf, buf_end, exports[i].index);
         read_uint8(buf, buf_end, exports[i].kind);
         read_string(buf, buf_end, exports[i].name);
-#if 0 /* TODO: check kind and index */
-        if (export_funcs[i].index >=
-              module->func_count + module->import_func_count) {
-            set_error_buf(error_buf, error_buf_size,
-                          "function index is out of range");
+
+        /* Check export kind and index */
+        switch (exports[i].kind) {
+            case EXPORT_KIND_FUNC:
+                if (exports[i].index
+                    >= module->import_func_count + module->func_count) {
+                    set_error_buf(error_buf, error_buf_size,
+                                  "unknown function");
+                    return false;
+                }
+                break;
+            case EXPORT_KIND_TABLE:
+                if (exports[i].index
+                    >= module->import_table_count + module->table_count) {
+                    set_error_buf(error_buf, error_buf_size, "unknown table");
+                    return false;
+                }
+                break;
+            case EXPORT_KIND_MEMORY:
+                if (exports[i].index
+                    >= module->import_memory_count + module->memory_count) {
+                    set_error_buf(error_buf, error_buf_size, "unknown memory");
+                    return false;
+                }
+                break;
+            case EXPORT_KIND_GLOBAL:
+                if (exports[i].index
+                    >= module->import_global_count + module->global_count) {
+                    set_error_buf(error_buf, error_buf_size, "unknown global");
+                    return false;
+                }
+                break;
+#if WASM_ENABLE_TAGS != 0
+                /* TODO
+                case EXPORT_KIND_TAG:
+                    if (index >= module->import_tag_count + module->tag_count) {
+                        set_error_buf(error_buf, error_buf_size, "unknown tag");
+                        return false;
+                    }
+                    break;
+                */
+#endif
+            default:
+                set_error_buf(error_buf, error_buf_size, "invalid export kind");
+                return false;
+        }
+    }
+
+    if (module->export_count > 0) {
+        if (!check_duplicate_exports(module, error_buf, error_buf_size)) {
             return false;
         }
-#endif
     }
 
     *p_buf = buf;
@@ -3807,7 +3810,7 @@ has_module_memory64(AOTModule *module)
 
 static bool
 load_from_sections(AOTModule *module, AOTSection *sections,
-                   bool is_load_from_file_buf, char *error_buf,
+                   bool is_load_from_file_buf, bool no_resolve, char *error_buf,
                    uint32 error_buf_size)
 {
     AOTSection *section = sections;
@@ -3840,8 +3843,8 @@ load_from_sections(AOTModule *module, AOTSection *sections,
                 break;
             case AOT_SECTION_TYPE_INIT_DATA:
                 if (!load_init_data_section(buf, buf_end, module,
-                                            is_load_from_file_buf, error_buf,
-                                            error_buf_size))
+                                            is_load_from_file_buf, no_resolve,
+                                            error_buf, error_buf_size))
                     return false;
                 break;
             case AOT_SECTION_TYPE_TEXT:
@@ -4064,7 +4067,7 @@ aot_load_from_sections(AOTSection *section_list, char *error_buf,
     if (!module)
         return NULL;
 
-    if (!load_from_sections(module, section_list, false, error_buf,
+    if (!load_from_sections(module, section_list, false, false, error_buf,
                             error_buf_size)) {
         aot_unload(module);
         return NULL;
@@ -4234,7 +4237,8 @@ fail:
 
 static bool
 load(const uint8 *buf, uint32 size, AOTModule *module,
-     bool wasm_binary_freeable, char *error_buf, uint32 error_buf_size)
+     bool wasm_binary_freeable, bool no_resolve, char *error_buf,
+     uint32 error_buf_size)
 {
     const uint8 *buf_end = buf + size;
     const uint8 *p = buf, *p_end = buf_end;
@@ -4261,7 +4265,7 @@ load(const uint8 *buf, uint32 size, AOTModule *module,
         return false;
 
     ret = load_from_sections(module, section_list, !wasm_binary_freeable,
-                             error_buf, error_buf_size);
+                             no_resolve, error_buf, error_buf_size);
     if (!ret) {
         /* If load_from_sections() fails, then aot text is destroyed
            in destroy_sections() */
@@ -4309,8 +4313,8 @@ aot_load_from_aot_file(const uint8 *buf, uint32 size, const LoadArgs *args,
         return NULL;
 
     os_thread_jit_write_protect_np(false); /* Make memory writable */
-    if (!load(buf, size, module, args->wasm_binary_freeable, error_buf,
-              error_buf_size)) {
+    if (!load(buf, size, module, args->wasm_binary_freeable, args->no_resolve,
+              error_buf, error_buf_size)) {
         aot_unload(module);
         return NULL;
     }

+ 1 - 1
core/iwasm/aot/aot_reloc.h

@@ -226,7 +226,7 @@ SymbolMap *
 get_target_symbol_map(uint32 *sym_num);
 
 uint32
-get_plt_table_size();
+get_plt_table_size(void);
 
 void
 init_plt_table(uint8 *plt);

+ 452 - 85
core/iwasm/aot/aot_runtime.c

@@ -4,6 +4,7 @@
  */
 
 #include "aot_runtime.h"
+#include "../compilation/aot_stack_frame.h"
 #include "bh_log.h"
 #include "mem_alloc.h"
 #include "../common/wasm_runtime_common.h"
@@ -56,6 +57,9 @@ bh_static_assert(sizeof(AOTMemoryInstance) == 120);
 bh_static_assert(offsetof(AOTTableInstance, elems) == 24);
 
 bh_static_assert(offsetof(AOTModuleInstanceExtra, stack_sizes) == 0);
+bh_static_assert(offsetof(AOTModuleInstanceExtra, shared_heap_base_addr_adj)
+                 == 8);
+bh_static_assert(offsetof(AOTModuleInstanceExtra, shared_heap_start_off) == 16);
 
 bh_static_assert(sizeof(CApiFuncImport) == sizeof(uintptr_t) * 3);
 
@@ -72,6 +76,10 @@ bh_static_assert(offsetof(AOTFrame, sp) == sizeof(uintptr_t) * 5);
 bh_static_assert(offsetof(AOTFrame, frame_ref) == sizeof(uintptr_t) * 6);
 bh_static_assert(offsetof(AOTFrame, lp) == sizeof(uintptr_t) * 7);
 
+bh_static_assert(offsetof(AOTTinyFrame, func_index) == sizeof(uint32) * 0);
+bh_static_assert(offsetof(AOTTinyFrame, ip_offset) == sizeof(uint32) * 1);
+bh_static_assert(sizeof(AOTTinyFrame) == sizeof(uint32) * 2);
+
 static void
 set_error_buf(char *error_buf, uint32 error_buf_size, const char *string)
 {
@@ -110,6 +118,66 @@ runtime_malloc(uint64 size, char *error_buf, uint32 error_buf_size)
     return mem;
 }
 
+#if WASM_ENABLE_AOT_STACK_FRAME != 0
+static bool
+is_tiny_frame(WASMExecEnv *exec_env)
+{
+    AOTModule *module =
+        (AOTModule *)((AOTModuleInstance *)exec_env->module_inst)->module;
+
+    return module->feature_flags & WASM_FEATURE_TINY_STACK_FRAME;
+}
+
+static bool
+is_frame_per_function(WASMExecEnv *exec_env)
+{
+    AOTModule *module =
+        (AOTModule *)((AOTModuleInstance *)exec_env->module_inst)->module;
+
+    return module->feature_flags & WASM_FEATURE_FRAME_PER_FUNCTION;
+}
+
+#if WASM_ENABLE_DUMP_CALL_STACK != 0
+static bool
+is_frame_func_idx_disabled(WASMExecEnv *exec_env)
+{
+    AOTModule *module =
+        (AOTModule *)((AOTModuleInstance *)exec_env->module_inst)->module;
+
+    return module->feature_flags & WASM_FEATURE_FRAME_NO_FUNC_IDX;
+}
+#endif
+
+static void *
+get_top_frame(WASMExecEnv *exec_env)
+{
+    if (is_tiny_frame(exec_env)) {
+        return exec_env->wasm_stack.top > exec_env->wasm_stack.bottom
+                   ? exec_env->wasm_stack.top - sizeof(AOTTinyFrame)
+                   : NULL;
+    }
+    else {
+        return exec_env->cur_frame;
+    }
+}
+
+static void *
+get_prev_frame(WASMExecEnv *exec_env, void *cur_frame)
+{
+    bh_assert(cur_frame);
+
+    if (is_tiny_frame(exec_env)) {
+        if ((uint8 *)cur_frame == exec_env->wasm_stack.bottom) {
+            return NULL;
+        }
+        return ((AOTTinyFrame *)cur_frame) - 1;
+    }
+    else {
+        return ((AOTFrame *)cur_frame)->prev_frame;
+    }
+}
+#endif
+
 static bool
 check_global_init_expr(const AOTModule *module, uint32 global_index,
                        char *error_buf, uint32 error_buf_size)
@@ -674,18 +742,24 @@ tables_instantiate(AOTModuleInstance *module_inst, AOTModule *module,
 
 #if WASM_ENABLE_REF_TYPES != 0
         bh_assert(
-            table_seg->offset.init_expr_type == INIT_EXPR_TYPE_I32_CONST
+            table_seg->offset.init_expr_type
+                == (tbl_inst->is_table64 ? INIT_EXPR_TYPE_I64_CONST
+                                         : INIT_EXPR_TYPE_I32_CONST)
             || table_seg->offset.init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL
             || table_seg->offset.init_expr_type == INIT_EXPR_TYPE_FUNCREF_CONST
             || table_seg->offset.init_expr_type
                    == INIT_EXPR_TYPE_REFNULL_CONST);
 #else
-        bh_assert(table_seg->offset.init_expr_type == INIT_EXPR_TYPE_I32_CONST
+        bh_assert(table_seg->offset.init_expr_type
+                      == (tbl_inst->is_table64 ? INIT_EXPR_TYPE_I64_CONST
+                                               : INIT_EXPR_TYPE_I32_CONST)
                   || table_seg->offset.init_expr_type
                          == INIT_EXPR_TYPE_GET_GLOBAL);
 #endif
 
         /* Resolve table data base offset */
+        /* TODO: The table64 current implementation assumes table max size
+         * UINT32_MAX, so the offset conversion here is safe */
         if (table_seg->offset.init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL) {
             global_index = table_seg->offset.u.global_index;
 
@@ -995,7 +1069,24 @@ fail1:
     return NULL;
 }
 
-static AOTMemoryInstance *
+AOTMemoryInstance *
+aot_lookup_memory(AOTModuleInstance *module_inst, char const *name)
+{
+#if WASM_ENABLE_MULTI_MEMORY != 0
+    uint32 i;
+    for (i = 0; i < module_inst->export_memory_count; i++)
+        if (!strcmp(module_inst->export_memories[i].name, name))
+            return module_inst->export_memories[i].memory;
+    return NULL;
+#else
+    (void)module_inst->export_memories;
+    if (!module_inst->memories)
+        return NULL;
+    return module_inst->memories[0];
+#endif
+}
+
+AOTMemoryInstance *
 aot_get_default_memory(AOTModuleInstance *module_inst)
 {
     if (module_inst->memories)
@@ -1004,6 +1095,14 @@ aot_get_default_memory(AOTModuleInstance *module_inst)
         return NULL;
 }
 
+AOTMemoryInstance *
+aot_get_memory_with_index(AOTModuleInstance *module_inst, uint32 index)
+{
+    if ((index >= module_inst->memory_count) || !module_inst->memories)
+        return NULL;
+    return module_inst->memories[index];
+}
+
 static bool
 memories_instantiate(AOTModuleInstance *module_inst, AOTModuleInstance *parent,
                      AOTModule *module, uint32 heap_size,
@@ -1280,6 +1379,15 @@ init_func_type_indexes(AOTModuleInstance *module_inst, AOTModule *module,
     return true;
 }
 
+static int
+cmp_func_inst(const void *a, const void *b)
+{
+    const AOTFunctionInstance *func_inst1 = (const AOTFunctionInstance *)a;
+    const AOTFunctionInstance *func_inst2 = (const AOTFunctionInstance *)b;
+
+    return strcmp(func_inst1->func_name, func_inst2->func_name);
+}
+
 static bool
 create_export_funcs(AOTModuleInstance *module_inst, AOTModule *module,
                     char *error_buf, uint32 error_buf_size)
@@ -1320,11 +1428,44 @@ create_export_funcs(AOTModuleInstance *module_inst, AOTModule *module,
                 export_func++;
             }
         }
+
+        qsort(module_inst->export_functions, module_inst->export_func_count,
+              sizeof(AOTFunctionInstance), cmp_func_inst);
     }
 
     return true;
 }
 
+#if WASM_ENABLE_MULTI_MEMORY != 0
+static WASMExportMemInstance *
+export_memories_instantiate(const AOTModule *module,
+                            AOTModuleInstance *module_inst,
+                            uint32 export_mem_count, char *error_buf,
+                            uint32 error_buf_size)
+{
+    WASMExportMemInstance *export_memories, *export_memory;
+    AOTExport *export = module->exports;
+    uint32 i;
+    uint64 total_size =
+        sizeof(WASMExportMemInstance) * (uint64)export_mem_count;
+
+    if (!(export_memory = export_memories =
+              runtime_malloc(total_size, error_buf, error_buf_size))) {
+        return NULL;
+    }
+
+    for (i = 0; i < module->export_count; i++, export ++)
+        if (export->kind == EXPORT_KIND_MEMORY) {
+            export_memory->name = export->name;
+            export_memory->memory = module_inst->memories[export->index];
+            export_memory++;
+        }
+
+    bh_assert((uint32)(export_memory - export_memories) == export_mem_count);
+    return export_memories;
+}
+#endif /* end of if WASM_ENABLE_MULTI_MEMORY != 0 */
+
 static bool
 create_exports(AOTModuleInstance *module_inst, AOTModule *module,
                char *error_buf, uint32 error_buf_size)
@@ -1351,6 +1492,17 @@ create_exports(AOTModuleInstance *module_inst, AOTModule *module,
         }
     }
 
+#if WASM_ENABLE_MULTI_MEMORY != 0
+    if (module_inst->export_memory_count) {
+        module_inst->export_memories = export_memories_instantiate(
+            module, module_inst, module_inst->export_memory_count, error_buf,
+            error_buf_size);
+        if (!module_inst->export_memories) {
+            return false;
+        }
+    }
+#endif
+
     return create_export_funcs(module_inst, module, error_buf, error_buf_size);
 }
 
@@ -1429,8 +1581,12 @@ execute_post_instantiate_functions(AOTModuleInstance *module_inst,
     if (is_sub_inst) {
         bh_assert(exec_env_main);
 #ifdef OS_ENABLE_HW_BOUND_CHECK
-        bh_assert(exec_env_tls == exec_env_main);
-        (void)exec_env_tls;
+        /* May come from pthread_create_wrapper, thread_spawn_wrapper and
+           wasm_cluster_spawn_exec_env. If it comes from the former two,
+           the exec_env_tls must be not NULL and equal to exec_env_main,
+           else if it comes from the last one, it may be NULL. */
+        if (exec_env_tls)
+            bh_assert(exec_env_tls == exec_env_main);
 #endif
         exec_env = exec_env_main;
 
@@ -1754,6 +1910,24 @@ aot_instantiate(AOTModule *module, AOTModuleInstance *parent,
     extra->stack_sizes =
         aot_get_data_section_addr(module, AOT_STACK_SIZES_SECTION_NAME, NULL);
 
+    /*
+     * The AOT code checks whether the n bytes to access are in shared heap
+     * by checking whether the beginning address meets:
+     *   addr >= start_off && addr <= end_off - n-bytes + 1
+     * where n is 1/2/4/8/16 and `end_off - n-bytes + 1` is constant, e.g.,
+     *   UINT32_MAX, UINT32_MAX-1, UINT32_MAX-3 for n = 1, 2 or 4 in 32-bit
+     * target. To simplify the check, when shared heap is disabled, we set
+     * the start off to UINT64_MAX in 64-bit target and UINT32_MAX in 32-bit
+     * target, so in the checking, the above formula will be false, we don't
+     * need to check whether the shared heap is enabled or not in the AOT
+     * code.
+     */
+#if UINTPTR_MAX == UINT64_MAX
+    extra->shared_heap_start_off.u64 = UINT64_MAX;
+#else
+    extra->shared_heap_start_off.u32[0] = UINT32_MAX;
+#endif
+
 #if WASM_ENABLE_PERF_PROFILING != 0
     total_size = sizeof(AOTFuncPerfProfInfo)
                  * ((uint64)module->import_func_count + module->func_count);
@@ -1994,6 +2168,11 @@ aot_deinstantiate(AOTModuleInstance *module_inst, bool is_sub_inst)
     if (module_inst->export_functions)
         wasm_runtime_free(module_inst->export_functions);
 
+#if WASM_ENABLE_MULTI_MEMORY != 0
+    if (module_inst->export_memories)
+        wasm_runtime_free(module_inst->export_memories);
+#endif
+
     if (extra->functions) {
         uint32 func_idx;
         for (func_idx = 0; func_idx < extra->function_count; ++func_idx) {
@@ -2039,14 +2218,15 @@ aot_deinstantiate(AOTModuleInstance *module_inst, bool is_sub_inst)
 AOTFunctionInstance *
 aot_lookup_function(const AOTModuleInstance *module_inst, const char *name)
 {
-    uint32 i;
     AOTFunctionInstance *export_funcs =
         (AOTFunctionInstance *)module_inst->export_functions;
+    AOTFunctionInstance key = { .func_name = (char *)name };
 
-    for (i = 0; i < module_inst->export_func_count; i++)
-        if (!strcmp(export_funcs[i].func_name, name))
-            return &export_funcs[i];
-    return NULL;
+    if (!export_funcs)
+        return NULL;
+
+    return bsearch(&key, export_funcs, module_inst->export_func_count,
+                   sizeof(AOTFunctionInstance), cmp_func_inst);
 }
 
 #ifdef OS_ENABLE_HW_BOUND_CHECK
@@ -2265,7 +2445,7 @@ aot_call_function(WASMExecEnv *exec_env, AOTFunctionInstance *function,
         uint32 ext_ret_cell = wasm_get_cell_num(ext_ret_types, ext_ret_count);
         uint64 size;
 #if WASM_ENABLE_AOT_STACK_FRAME != 0
-        struct WASMInterpFrame *prev_frame = exec_env->cur_frame;
+        void *prev_frame = get_top_frame(exec_env);
 #endif
 
         /* Allocate memory all arguments */
@@ -2296,7 +2476,8 @@ aot_call_function(WASMExecEnv *exec_env, AOTFunctionInstance *function,
         }
 
 #if WASM_ENABLE_AOT_STACK_FRAME != 0
-        if (!aot_alloc_frame(exec_env, function->func_index)) {
+        if (!is_frame_per_function(exec_env)
+            && !aot_alloc_frame(exec_env, function->func_index)) {
             if (argv1 != argv1_buf)
                 wasm_runtime_free(argv1);
             return false;
@@ -2324,7 +2505,7 @@ aot_call_function(WASMExecEnv *exec_env, AOTFunctionInstance *function,
         /* Free all frames allocated, note that some frames
            may be allocated in AOT code and haven't been
            freed if exception occurred */
-        while (exec_env->cur_frame != prev_frame)
+        while (get_top_frame(exec_env) != prev_frame)
             aot_free_frame(exec_env);
 #endif
         if (!ret) {
@@ -2367,9 +2548,12 @@ aot_call_function(WASMExecEnv *exec_env, AOTFunctionInstance *function,
     }
     else {
 #if WASM_ENABLE_AOT_STACK_FRAME != 0
-        struct WASMInterpFrame *prev_frame = exec_env->cur_frame;
-
-        if (!aot_alloc_frame(exec_env, function->func_index)) {
+        void *prev_frame = get_top_frame(exec_env);
+        /* Only allocate frame for frame-per-call mode; in the
+           frame-per-function mode the frame is allocated at the
+           beginning of the function. */
+        if (!is_frame_per_function(exec_env)
+            && !aot_alloc_frame(exec_env, function->func_index)) {
             return false;
         }
 #endif
@@ -2394,7 +2578,7 @@ aot_call_function(WASMExecEnv *exec_env, AOTFunctionInstance *function,
         /* Free all frames allocated, note that some frames
            may be allocated in AOT code and haven't been
            freed if exception occurred */
-        while (exec_env->cur_frame != prev_frame)
+        while (get_top_frame(exec_env) != prev_frame)
             aot_free_frame(exec_env);
 #endif
 
@@ -2880,7 +3064,7 @@ aot_invoke_native(WASMExecEnv *exec_env, uint32 func_idx, uint32 argc,
             goto fail;
         }
 #if WASM_ENABLE_AOT_STACK_FRAME != 0
-        struct WASMInterpFrame *prev_frame = exec_env->cur_frame;
+        void *prev_frame = get_top_frame(exec_env);
 
         if (!aot_alloc_frame(exec_env, func_idx)) {
             goto fail;
@@ -2894,7 +3078,7 @@ aot_invoke_native(WASMExecEnv *exec_env, uint32 func_idx, uint32 argc,
         /* Free all frames allocated, note that some frames
            may be allocated in AOT code and haven't been
            freed if exception occurred */
-        while (exec_env->cur_frame != prev_frame)
+        while (get_top_frame(exec_env) != prev_frame)
             aot_free_frame(exec_env);
 #endif
     }
@@ -3622,8 +3806,8 @@ get_func_name_from_index(const AOTModuleInstance *module_inst,
           WASM_ENABLE_PERF_PROFILING != 0 */
 
 #if WASM_ENABLE_GC == 0
-bool
-aot_alloc_frame(WASMExecEnv *exec_env, uint32 func_index)
+static bool
+aot_alloc_standard_frame(WASMExecEnv *exec_env, uint32 func_index)
 {
     AOTModuleInstance *module_inst = (AOTModuleInstance *)exec_env->module_inst;
 #if WASM_ENABLE_PERF_PROFILING != 0
@@ -3668,37 +3852,10 @@ aot_alloc_frame(WASMExecEnv *exec_env, uint32 func_index)
     return true;
 }
 
-static inline void
-aot_free_frame_internal(WASMExecEnv *exec_env)
-{
-    AOTFrame *cur_frame = (AOTFrame *)exec_env->cur_frame;
-    AOTFrame *prev_frame = cur_frame->prev_frame;
-
-#if WASM_ENABLE_PERF_PROFILING != 0
-    uint64 time_elapsed =
-        (uintptr_t)os_time_thread_cputime_us() - cur_frame->time_started;
-
-    cur_frame->func_perf_prof_info->total_exec_time += time_elapsed;
-    cur_frame->func_perf_prof_info->total_exec_cnt++;
-
-    /* parent function */
-    if (prev_frame)
-        prev_frame->func_perf_prof_info->children_exec_time += time_elapsed;
-#endif
-
-    exec_env->cur_frame = (struct WASMInterpFrame *)prev_frame;
-}
-
-void
-aot_free_frame(WASMExecEnv *exec_env)
-{
-    aot_free_frame_internal(exec_env);
-}
-
 #else /* else of WASM_ENABLE_GC == 0 */
 
-bool
-aot_alloc_frame(WASMExecEnv *exec_env, uint32 func_index)
+static bool
+aot_alloc_standard_frame(WASMExecEnv *exec_env, uint32 func_index)
 {
     AOTModuleInstance *module_inst = (AOTModuleInstance *)exec_env->module_inst;
     AOTModule *module = (AOTModule *)module_inst->module;
@@ -3752,12 +3909,50 @@ aot_alloc_frame(WASMExecEnv *exec_env, uint32 func_index)
     frame->func_index = func_index;
     return true;
 }
+#endif /* end of WASM_ENABLE_GC == 0 */
+
+static bool
+aot_alloc_tiny_frame(WASMExecEnv *exec_env, uint32 func_index)
+{
+    AOTTinyFrame *new_frame = (AOTTinyFrame *)exec_env->wasm_stack.top;
+
+    if ((uint8 *)new_frame > exec_env->wasm_stack.top_boundary) {
+        aot_set_exception((WASMModuleInstance *)exec_env->module_inst,
+                          "wasm operand stack overflow");
+        return false;
+    }
+
+    new_frame->func_index = func_index;
+    exec_env->wasm_stack.top += sizeof(AOTTinyFrame);
+    return true;
+}
+
+bool
+aot_alloc_frame(WASMExecEnv *exec_env, uint32 func_index)
+{
+    AOTModule *module =
+        (AOTModule *)((AOTModuleInstance *)exec_env->module_inst)->module;
+
+    if (is_frame_per_function(exec_env)
+        && func_index >= module->import_func_count) {
+        /* in frame per function mode the frame is allocated at
+        the beginning of each frame, so we only need to allocate
+        the frame for imported functions */
+        return true;
+    }
+    if (is_tiny_frame(exec_env)) {
+        return aot_alloc_tiny_frame(exec_env, func_index);
+    }
+    else {
+        return aot_alloc_standard_frame(exec_env, func_index);
+    }
+}
 
 static inline void
-aot_free_frame_internal(WASMExecEnv *exec_env)
+aot_free_standard_frame(WASMExecEnv *exec_env)
 {
     AOTFrame *cur_frame = (AOTFrame *)exec_env->cur_frame;
-    AOTFrame *prev_frame = cur_frame->prev_frame;
+    AOTFrame *prev_frame = (AOTFrame *)cur_frame->prev_frame;
 
 #if WASM_ENABLE_PERF_PROFILING != 0
     uint64 time_elapsed =
@@ -3771,18 +3966,30 @@ aot_free_frame_internal(WASMExecEnv *exec_env)
         prev_frame->func_perf_prof_info->children_exec_time += time_elapsed;
 #endif
 
+#if WASM_ENABLE_GC != 0
     wasm_exec_env_free_wasm_frame(exec_env, cur_frame);
+#endif
     exec_env->cur_frame = (struct WASMInterpFrame *)prev_frame;
 }
 
+static inline void
+aot_free_tiny_frame(WASMExecEnv *exec_env)
+{
+    exec_env->wasm_stack.top =
+        get_prev_frame(exec_env, exec_env->wasm_stack.top);
+}
+
 void
 aot_free_frame(WASMExecEnv *exec_env)
 {
-    aot_free_frame_internal(exec_env);
+    if (is_tiny_frame(exec_env)) {
+        aot_free_tiny_frame(exec_env);
+    }
+    else {
+        aot_free_standard_frame(exec_env);
+    }
 }
 
-#endif /* end of WASM_ENABLE_GC == 0 */
-
 void
 aot_frame_update_profile_info(WASMExecEnv *exec_env, bool alloc_frame)
 {
@@ -3831,14 +4038,13 @@ aot_frame_update_profile_info(WASMExecEnv *exec_env, bool alloc_frame)
 bool
 aot_create_call_stack(struct WASMExecEnv *exec_env)
 {
-    AOTFrame *cur_frame = (AOTFrame *)exec_env->cur_frame,
-             *first_frame = cur_frame;
     AOTModuleInstance *module_inst = (AOTModuleInstance *)exec_env->module_inst;
     AOTModule *module = (AOTModule *)module_inst->module;
     uint32 n = 0;
 
-    while (cur_frame) {
-        cur_frame = cur_frame->prev_frame;
+    void *top_frame = get_top_frame(exec_env);
+    while (top_frame) {
+        top_frame = get_prev_frame(exec_env, top_frame);
         n++;
     }
 
@@ -3848,31 +4054,53 @@ aot_create_call_stack(struct WASMExecEnv *exec_env)
         return false;
     }
 
-    cur_frame = first_frame;
-    while (cur_frame) {
+    top_frame = get_top_frame(exec_env);
+    while (n-- > 0) {
+        uint32 func_index, ip_offset;
+        uint32 *lp = NULL;
+#if WASM_ENABLE_GC != 0
+        uint32 *sp = NULL;
+        uint8 *frame_ref = NULL;
+#endif
+        if (is_tiny_frame(exec_env)) {
+            AOTTinyFrame *frame = (AOTTinyFrame *)top_frame;
+            func_index = (uint32)frame->func_index;
+            ip_offset = (uint32)frame->ip_offset;
+        }
+        else {
+            AOTFrame *frame = (AOTFrame *)top_frame;
+            func_index = (uint32)frame->func_index;
+            ip_offset = (uint32)frame->ip_offset;
+            lp = frame->lp;
+#if WASM_ENABLE_GC != 0
+            sp = frame->sp;
+            frame_ref = frame->frame_ref;
+#endif
+        }
         WASMCApiFrame frame = { 0 };
-        uint32 max_local_cell_num, max_stack_cell_num;
+        uint32 max_local_cell_num = 0, max_stack_cell_num = 0;
         uint32 all_cell_num, lp_size;
 
         frame.instance = module_inst;
         frame.module_offset = 0;
-        frame.func_index = (uint32)cur_frame->func_index;
-        frame.func_offset = (uint32)cur_frame->ip_offset;
-        frame.func_name_wp = get_func_name_from_index(
-            module_inst, (uint32)cur_frame->func_index);
-
-        if (cur_frame->func_index >= module->import_func_count) {
-            uint32 aot_func_idx =
-                (uint32)(cur_frame->func_index - module->import_func_count);
-            max_local_cell_num = module->max_local_cell_nums[aot_func_idx];
-            max_stack_cell_num = module->max_stack_cell_nums[aot_func_idx];
-        }
-        else {
-            AOTFuncType *func_type =
-                module->import_funcs[cur_frame->func_index].func_type;
-            max_local_cell_num =
-                func_type->param_cell_num > 2 ? func_type->param_cell_num : 2;
-            max_stack_cell_num = 0;
+        frame.func_index = func_index;
+        frame.func_offset = ip_offset;
+        frame.func_name_wp = get_func_name_from_index(module_inst, func_index);
+
+        if (!is_frame_func_idx_disabled(exec_env)) {
+            if (func_index >= module->import_func_count) {
+                uint32 aot_func_idx = func_index - module->import_func_count;
+                max_local_cell_num = module->max_local_cell_nums[aot_func_idx];
+                max_stack_cell_num = module->max_stack_cell_nums[aot_func_idx];
+            }
+            else {
+                AOTFuncType *func_type =
+                    module->import_funcs[func_index].func_type;
+                max_local_cell_num = func_type->param_cell_num > 2
+                                         ? func_type->param_cell_num
+                                         : 2;
+                max_stack_cell_num = 0;
+            }
         }
 
         all_cell_num = max_local_cell_num + max_stack_cell_num;
@@ -3881,12 +4109,12 @@ aot_create_call_stack(struct WASMExecEnv *exec_env)
 #else
         lp_size = align_uint(all_cell_num * 5, 4);
 #endif
-        if (lp_size > 0) {
+        if (lp_size > 0 && !is_tiny_frame(exec_env)) {
             if (!(frame.lp = wasm_runtime_malloc(lp_size))) {
                 destroy_c_api_frames(module_inst->frames);
                 return false;
             }
-            bh_memcpy_s(frame.lp, lp_size, cur_frame->lp, lp_size);
+            bh_memcpy_s(frame.lp, lp_size, lp, lp_size);
 
 #if WASM_ENABLE_GC != 0
             uint32 local_ref_flags_cell_num =
@@ -3894,9 +4122,8 @@ aot_create_call_stack(struct WASMExecEnv *exec_env)
                     .local_ref_flag_cell_num;
             uint8 *local_ref_flags =
                 module->func_local_ref_flags[frame.func_index].local_ref_flags;
-            frame.sp = frame.lp + (cur_frame->sp - cur_frame->lp);
-            frame.frame_ref = (uint8 *)frame.lp
-                              + (cur_frame->frame_ref - (uint8 *)cur_frame->lp);
+            frame.sp = frame.lp + (sp - lp);
+            frame.frame_ref = (uint8 *)frame.lp + (frame_ref - (uint8 *)lp);
             /* copy local ref flags from AOT module */
             bh_memcpy_s(frame.frame_ref, local_ref_flags_cell_num,
                         local_ref_flags, lp_size);
@@ -3910,7 +4137,7 @@ aot_create_call_stack(struct WASMExecEnv *exec_env)
             return false;
         }
 
-        cur_frame = cur_frame->prev_frame;
+        top_frame = get_prev_frame(exec_env, top_frame);
     }
 
     return true;
@@ -4889,6 +5116,18 @@ aot_const_str_set_insert(const uint8 *str, int32 len, AOTModule *module,
     return c_str;
 }
 
+#if WASM_ENABLE_DYNAMIC_AOT_DEBUG != 0
+AOTModule *g_dynamic_aot_module = NULL;
+
+void __attribute__((noinline)) __enable_dynamic_aot_debug(void)
+{
+    /* empty implementation. */
+}
+
+void (*__enable_dynamic_aot_debug_ptr)(void)
+    __attribute__((visibility("default"))) = __enable_dynamic_aot_debug;
+#endif
+
 bool
 aot_set_module_name(AOTModule *module, const char *name, char *error_buf,
                     uint32_t error_buf_size)
@@ -4902,6 +5141,12 @@ aot_set_module_name(AOTModule *module, const char *name, char *error_buf,
                                             false,
 #endif
                                             error_buf, error_buf_size);
+#if WASM_ENABLE_DYNAMIC_AOT_DEBUG != 0
+    /* export g_dynamic_aot_module for dynamic aot debug */
+    g_dynamic_aot_module = module;
+    /* trigger breakpoint __enable_dynamic_aot_debug */
+    (*__enable_dynamic_aot_debug_ptr)();
+#endif
     return module->name != NULL;
 }
 
@@ -4910,3 +5155,125 @@ aot_get_module_name(AOTModule *module)
 {
     return module->name;
 }
+
+bool
+aot_resolve_symbols(AOTModule *module)
+{
+    bool ret = true;
+    uint32 idx;
+    for (idx = 0; idx < module->import_func_count; ++idx) {
+        AOTImportFunc *aot_import_func = &module->import_funcs[idx];
+        if (!aot_import_func->func_ptr_linked) {
+            if (!aot_resolve_import_func(module, aot_import_func)) {
+                LOG_WARNING("Failed to link function (%s, %s)",
+                            aot_import_func->module_name,
+                            aot_import_func->func_name);
+                ret = false;
+            }
+        }
+    }
+    return ret;
+}
+
+#if WASM_ENABLE_MULTI_MODULE != 0
+static void *
+aot_resolve_function(const AOTModule *module, const char *function_name,
+                     const AOTFuncType *expected_function_type, char *error_buf,
+                     uint32 error_buf_size);
+
+static void *
+aot_resolve_function_ex(const char *module_name, const char *function_name,
+                        const AOTFuncType *expected_function_type,
+                        char *error_buf, uint32 error_buf_size)
+{
+    WASMModuleCommon *module_reg;
+
+    module_reg = wasm_runtime_find_module_registered(module_name);
+    if (!module_reg || module_reg->module_type != Wasm_Module_AoT) {
+        LOG_DEBUG("can not find a module named %s for function %s", module_name,
+                  function_name);
+        set_error_buf(error_buf, error_buf_size, "unknown import");
+        return NULL;
+    }
+    return aot_resolve_function((AOTModule *)module_reg, function_name,
+                                expected_function_type, error_buf,
+                                error_buf_size);
+}
+
+static void *
+aot_resolve_function(const AOTModule *module, const char *function_name,
+                     const AOTFuncType *expected_function_type, char *error_buf,
+                     uint32 error_buf_size)
+{
+    void *function = NULL;
+    AOTExport *export = NULL;
+    AOTFuncType *target_function_type = NULL;
+
+    export = loader_find_export((WASMModuleCommon *)module, module->name,
+                                function_name, EXPORT_KIND_FUNC, error_buf,
+                                error_buf_size);
+    if (!export) {
+        return NULL;
+    }
+
+    /* resolve function type and function */
+    if (export->index < module->import_func_count) {
+        target_function_type = module->import_funcs[export->index].func_type;
+        function = module->import_funcs[export->index].func_ptr_linked;
+    }
+    else {
+        target_function_type =
+            (AOTFuncType *)module
+                ->types[module->func_type_indexes[export->index
+                                                  - module->import_func_count]];
+        function =
+            (module->func_ptrs[export->index - module->import_func_count]);
+    }
+    /* check function type */
+    if (!wasm_type_equal((WASMType *)expected_function_type,
+                         (WASMType *)target_function_type, module->types,
+                         module->type_count)) {
+        LOG_DEBUG("%s.%s failed the type check", module->name, function_name);
+        set_error_buf(error_buf, error_buf_size, "incompatible import type");
+        return NULL;
+    }
+    return function;
+}
+#endif /* end of WASM_ENABLE_MULTI_MODULE */
+
+bool
+aot_resolve_import_func(AOTModule *module, AOTImportFunc *import_func)
+{
+#if WASM_ENABLE_MULTI_MODULE != 0
+    char error_buf[128];
+    AOTModule *sub_module = NULL;
+#endif
+    import_func->func_ptr_linked = wasm_native_resolve_symbol(
+        import_func->module_name, import_func->func_name,
+        import_func->func_type, &import_func->signature,
+        &import_func->attachment, &import_func->call_conv_raw);
+#if WASM_ENABLE_MULTI_MODULE != 0
+    if (!import_func->func_ptr_linked) {
+        if (!wasm_runtime_is_built_in_module(import_func->module_name)) {
+            sub_module = (AOTModule *)wasm_runtime_load_depended_module(
+                (WASMModuleCommon *)module, import_func->module_name, error_buf,
+                sizeof(error_buf));
+            if (!sub_module) {
+                LOG_WARNING("Failed to load sub module: %s", error_buf);
+            }
+            if (!sub_module)
+                import_func->func_ptr_linked = aot_resolve_function_ex(
+                    import_func->module_name, import_func->func_name,
+                    import_func->func_type, error_buf, sizeof(error_buf));
+            else
+                import_func->func_ptr_linked = aot_resolve_function(
+                    sub_module, import_func->func_name, import_func->func_type,
+                    error_buf, sizeof(error_buf));
+            if (!import_func->func_ptr_linked) {
+                LOG_WARNING("Failed to link function: %s", error_buf);
+            }
+        }
+    }
+#endif
+    return import_func->func_ptr_linked != NULL;
+}

+ 47 - 2
core/iwasm/aot/aot_runtime.h

@@ -25,12 +25,16 @@ extern "C" {
 #define WASM_FEATURE_REF_TYPES (1 << 3)
 #define WASM_FEATURE_GARBAGE_COLLECTION (1 << 4)
 #define WASM_FEATURE_EXCEPTION_HANDLING (1 << 5)
-#define WASM_FEATURE_MEMORY64 (1 << 6)
+#define WASM_FEATURE_TINY_STACK_FRAME (1 << 6)
 #define WASM_FEATURE_MULTI_MEMORY (1 << 7)
 #define WASM_FEATURE_DYNAMIC_LINKING (1 << 8)
 #define WASM_FEATURE_COMPONENT_MODEL (1 << 9)
 #define WASM_FEATURE_RELAXED_SIMD (1 << 10)
 #define WASM_FEATURE_FLEXIBLE_VECTORS (1 << 11)
+/* Stack frame is created at the beginning of the function,
+ * and not at the beginning of each function call */
+#define WASM_FEATURE_FRAME_PER_FUNCTION (1 << 12)
+#define WASM_FEATURE_FRAME_NO_FUNC_IDX (1 << 13)
 
 typedef enum AOTSectionType {
     AOT_SECTION_TYPE_TARGET_INFO = 0,
@@ -39,6 +43,10 @@ typedef enum AOTSectionType {
     AOT_SECTION_TYPE_FUNCTION = 3,
     AOT_SECTION_TYPE_EXPORT = 4,
     AOT_SECTION_TYPE_RELOCATION = 5,
+    /*
+     * Note: We haven't had anything to use AOT_SECTION_TYPE_SIGNATURE.
+     * It's just reserved for possible module signing features.
+     */
     AOT_SECTION_TYPE_SIGNATURE = 6,
     AOT_SECTION_TYPE_CUSTOM = 100,
 } AOTSectionType;
@@ -103,6 +111,14 @@ typedef struct AOTFunctionInstance {
 
 typedef struct AOTModuleInstanceExtra {
     DefPointer(const uint32 *, stack_sizes);
+    /*
+     * Adjusted shared heap based addr to simple the calculation
+     * in the aot code. The value is:
+     *   shared_heap->base_addr - shared_heap->start_off
+     */
+    DefPointer(uint8 *, shared_heap_base_addr_adj);
+    MemBound shared_heap_start_off;
+
     WASMModuleInstanceExtraCommon common;
     AOTFunctionInstance **functions;
     uint32 function_count;
@@ -111,6 +127,10 @@ typedef struct AOTModuleInstanceExtra {
     bh_list *sub_module_inst_list;
     WASMModuleInstanceCommon **import_func_module_insts;
 #endif
+
+#if WASM_ENABLE_SHARED_HEAP != 0
+    WASMSharedHeap *shared_heap;
+#endif
 } AOTModuleInstanceExtra;
 
 #if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64)
@@ -322,6 +342,10 @@ typedef struct AOTModule {
     /* `.data` and `.text` sections merged into one large mmaped section */
     uint8 *merged_data_text_sections;
     uint32 merged_data_text_sections_size;
+
+#if WASM_ENABLE_AOT_STACK_FRAME != 0
+    uint32 feature_flags;
+#endif
 } AOTModule;
 
 #define AOTMemoryInstance WASMMemoryInstance
@@ -480,6 +504,18 @@ aot_load_from_sections(AOTSection *section_list, char *error_buf,
 void
 aot_unload(AOTModule *module);
 
+/**
+ * Resolve symbols for an AOT module
+ */
+bool
+aot_resolve_symbols(AOTModule *module);
+
+/**
+ * Helper function to resolve a single function
+ */
+bool
+aot_resolve_import_func(AOTModule *module, AOTImportFunc *import_func);
+
 /**
  * Instantiate a AOT module.
  *
@@ -520,6 +556,15 @@ aot_deinstantiate(AOTModuleInstance *module_inst, bool is_sub_inst);
 AOTFunctionInstance *
 aot_lookup_function(const AOTModuleInstance *module_inst, const char *name);
 
+AOTMemoryInstance *
+aot_lookup_memory(AOTModuleInstance *module_inst, char const *name);
+
+AOTMemoryInstance *
+aot_get_default_memory(AOTModuleInstance *module_inst);
+
+AOTMemoryInstance *
+aot_get_memory_with_index(AOTModuleInstance *module_inst, uint32 index);
+
 /**
  * Get a function in the AOT module instance.
  *
@@ -637,7 +682,7 @@ aot_check_app_addr_and_convert(AOTModuleInstance *module_inst, bool is_str,
                                void **p_native_addr);
 
 uint32
-aot_get_plt_table_size();
+aot_get_plt_table_size(void);
 
 void *
 aot_memmove(void *dest, const void *src, size_t n);

+ 3 - 10
core/iwasm/aot/arch/aot_reloc_aarch64.c

@@ -53,12 +53,6 @@ get_target_symbol_map(uint32 *sym_num)
     return target_sym_map;
 }
 
-#if (defined(__APPLE__) || defined(__MACH__)) && defined(__arm64__)
-#define BUILD_TARGET_AARCH64_DEFAULT "arm64"
-#else
-#define BUILD_TARGET_AARCH64_DEFAULT "aarch64v8"
-#endif
-
 void
 get_current_target(char *target_buf, uint32 target_buf_size)
 {
@@ -68,8 +62,8 @@ get_current_target(char *target_buf, uint32 target_buf_size)
 
     /* Set to "aarch64v8" by default if sub version isn't specified */
     if (strcmp(s, "AARCH64") == 0) {
-        s = BUILD_TARGET_AARCH64_DEFAULT;
-        s_size = sizeof(BUILD_TARGET_AARCH64_DEFAULT);
+        s = "aarch64v8";
+        s_size = 9; /* strlen("aarch64v8"); */
     }
     if (target_buf_size < s_size) {
         s_size = target_buf_size;
@@ -83,10 +77,9 @@ get_current_target(char *target_buf, uint32 target_buf_size)
     /* Ensure the string is null byte ('\0') terminated */
     *d = '\0';
 }
-#undef BUILD_TARGET_AARCH64_DEFAULT
 
 static uint32
-get_plt_item_size()
+get_plt_item_size(void)
 {
     /* 6*4 bytes instructions and 8 bytes symbol address */
     return 32;

+ 97 - 97
core/iwasm/aot/arch/aot_reloc_arm.c

@@ -12,102 +12,102 @@
 #define R_ARM_MOVT_ABS 44
 
 /* clang-format off */
-void __adddf3();
-void __addsf3();
-void __aeabi_d2f();
-void __aeabi_d2iz();
-void __aeabi_d2lz();
-void __aeabi_d2uiz();
-void __aeabi_d2ulz();
-void __aeabi_dadd();
-void __aeabi_dcmpeq();
-void __aeabi_dcmpge();
-void __aeabi_dcmpgt();
-void __aeabi_dcmple();
-void __aeabi_dcmplt();
-void __aeabi_dcmpun();
-void __aeabi_ddiv();
-void __aeabi_dmul();
-void __aeabi_dsub();
-void __aeabi_f2d();
-void __aeabi_f2iz();
-void __aeabi_f2lz();
-void __aeabi_f2ulz();
-void __aeabi_fadd();
-void __aeabi_fcmpeq();
-void __aeabi_fcmpge();
-void __aeabi_fcmpgt();
-void __aeabi_fcmple();
-void __aeabi_fcmplt();
-void __aeabi_fcmpun();
-void __aeabi_fdiv();
-void __aeabi_fmul();
-void __aeabi_fsub();
-void __aeabi_i2d();
-void __aeabi_i2f();
-void __aeabi_idiv();
-void __aeabi_idivmod();
-void __aeabi_l2d();
-void __aeabi_l2f();
-void __aeabi_ldivmod();
-void __aeabi_memclr();
-void __aeabi_memcpy();
-void __aeabi_memmove();
-void __aeabi_memset();
-void __aeabi_ui2d();
-void __aeabi_ui2f();
-void __aeabi_uidiv();
-void __aeabi_uidivmod();
-void __aeabi_ul2d();
-void __aeabi_ul2f();
-void __aeabi_uldivmod();
-void __clzsi2();
-void __divdf3();
-void __divdi3();
-void __divsf3();
-void __divsi3();
-void __eqdf2();
-void __eqsf2();
-void __extendsfdf2();
-void __fixdfdi();
-void __fixdfsi();
-void __fixsfdi();
-void __fixsfsi();
-void __fixunsdfdi();
-void __fixunsdfsi();
-void __fixunssfdi();
-void __floatdidf();
-void __floatdisf();
-void __floatsidf();
-void __floatsisf();
-void __floatundidf();
-void __floatundisf();
-void __floatunsidf();
-void __floatunsisf();
-void __gedf2();
-void __gesf2();
-void __gtdf2();
-void __gtsf2();
-void __ledf2();
-void __lesf2();
-void __ltdf2();
-void __ltsf2();
-void __moddi3();
-void __modsi3();
-void __muldf3();
-void __mulsf3();
-void __nedf2();
-void __nesf2();
-void __subdf3();
-void __subsf3();
-void __truncdfsf2();
-void __udivdi3();
-void __udivmoddi4();
-void __udivsi3();
-void __umoddi3();
-void __umodsi3();
-void __unorddf2();
-void __unordsf2();
+void __adddf3(void);
+void __addsf3(void);
+void __aeabi_d2f(void);
+void __aeabi_d2iz(void);
+void __aeabi_d2lz(void);
+void __aeabi_d2uiz(void);
+void __aeabi_d2ulz(void);
+void __aeabi_dadd(void);
+void __aeabi_dcmpeq(void);
+void __aeabi_dcmpge(void);
+void __aeabi_dcmpgt(void);
+void __aeabi_dcmple(void);
+void __aeabi_dcmplt(void);
+void __aeabi_dcmpun(void);
+void __aeabi_ddiv(void);
+void __aeabi_dmul(void);
+void __aeabi_dsub(void);
+void __aeabi_f2d(void);
+void __aeabi_f2iz(void);
+void __aeabi_f2lz(void);
+void __aeabi_f2ulz(void);
+void __aeabi_fadd(void);
+void __aeabi_fcmpeq(void);
+void __aeabi_fcmpge(void);
+void __aeabi_fcmpgt(void);
+void __aeabi_fcmple(void);
+void __aeabi_fcmplt(void);
+void __aeabi_fcmpun(void);
+void __aeabi_fdiv(void);
+void __aeabi_fmul(void);
+void __aeabi_fsub(void);
+void __aeabi_i2d(void);
+void __aeabi_i2f(void);
+void __aeabi_idiv(void);
+void __aeabi_idivmod(void);
+void __aeabi_l2d(void);
+void __aeabi_l2f(void);
+void __aeabi_ldivmod(void);
+void __aeabi_memclr(void);
+void __aeabi_memcpy(void);
+void __aeabi_memmove(void);
+void __aeabi_memset(void);
+void __aeabi_ui2d(void);
+void __aeabi_ui2f(void);
+void __aeabi_uidiv(void);
+void __aeabi_uidivmod(void);
+void __aeabi_ul2d(void);
+void __aeabi_ul2f(void);
+void __aeabi_uldivmod(void);
+void __clzsi2(void);
+void __divdf3(void);
+void __divdi3(void);
+void __divsf3(void);
+void __divsi3(void);
+void __eqdf2(void);
+void __eqsf2(void);
+void __extendsfdf2(void);
+void __fixdfdi(void);
+void __fixdfsi(void);
+void __fixsfdi(void);
+void __fixsfsi(void);
+void __fixunsdfdi(void);
+void __fixunsdfsi(void);
+void __fixunssfdi(void);
+void __floatdidf(void);
+void __floatdisf(void);
+void __floatsidf(void);
+void __floatsisf(void);
+void __floatundidf(void);
+void __floatundisf(void);
+void __floatunsidf(void);
+void __floatunsisf(void);
+void __gedf2(void);
+void __gesf2(void);
+void __gtdf2(void);
+void __gtsf2(void);
+void __ledf2(void);
+void __lesf2(void);
+void __ltdf2(void);
+void __ltsf2(void);
+void __moddi3(void);
+void __modsi3(void);
+void __muldf3(void);
+void __mulsf3(void);
+void __nedf2(void);
+void __nesf2(void);
+void __subdf3(void);
+void __subsf3(void);
+void __truncdfsf2(void);
+void __udivdi3(void);
+void __udivmoddi4(void);
+void __udivsi3(void);
+void __umoddi3(void);
+void __umodsi3(void);
+void __unorddf2(void);
+void __unordsf2(void);
 /* clang-format on */
 
 static SymbolMap target_sym_map[] = {
@@ -255,7 +255,7 @@ get_current_target(char *target_buf, uint32 target_buf_size)
 #undef BUILD_TARGET_ARM_DEFAULT
 
 uint32
-get_plt_item_size()
+get_plt_item_size(void)
 {
     /* 8 bytes instructions and 4 bytes symbol address */
     return 12;

+ 1 - 1
core/iwasm/aot/arch/aot_reloc_mips.c

@@ -28,7 +28,7 @@ get_current_target(char *target_buf, uint32 target_buf_size)
 }
 
 static uint32
-get_plt_item_size()
+get_plt_item_size(void)
 {
     return 0;
 }

+ 66 - 53
core/iwasm/aot/arch/aot_reloc_riscv.c

@@ -24,6 +24,7 @@
 #undef NEED_SOFT_I32_DIV
 #undef NEED_SOFT_I64_MUL
 #undef NEED_SOFT_I64_DIV
+#undef NEED_SOFT_ATOMIC
 
 #ifdef __riscv_flen
 #if __riscv_flen == 32
@@ -48,59 +49,66 @@
 #define NEED_SOFT_I64_DIV
 #endif
 
+#ifndef __riscv_atomic
+#define NEED_SOFT_ATOMIC
+#endif
+
 /* clang-format off */
-void __adddf3();
-void __addsf3();
-void __divdf3();
-void __divdi3();
-void __divsf3();
-void __divsi3();
-void __eqdf2();
-void __eqsf2();
-void __extendsfdf2();
-void __fixdfdi();
-void __fixdfsi();
-void __fixsfdi();
-void __fixsfsi();
-void __fixunsdfdi();
-void __fixunsdfsi();
-void __fixunssfdi();
-void __fixunssfsi();
-void __floatdidf();
-void __floatdisf();
-void __floatsidf();
-void __floatsisf();
-void __floatundidf();
-void __floatundisf();
-void __floatunsidf();
-void __floatunsisf();
-void __gedf2();
-void __gesf2();
-void __gtdf2();
-void __gtsf2();
-void __ledf2();
-void __lesf2();
-void __ltdf2();
-void __ltsf2();
-void __moddi3();
-void __modsi3();
-void __muldf3();
-void __muldi3();
-void __mulsf3();
-void __mulsi3();
-void __nedf2();
-void __negdf2();
-void __negsf2();
-void __nesf2();
-void __subdf3();
-void __subsf3();
-void __truncdfsf2();
-void __udivdi3();
-void __udivsi3();
-void __umoddi3();
-void __umodsi3();
-void __unorddf2();
-void __unordsf2();
+void __adddf3(void);
+void __addsf3(void);
+void __divdf3(void);
+void __divdi3(void);
+void __divsf3(void);
+void __divsi3(void);
+void __eqdf2(void);
+void __eqsf2(void);
+void __extendsfdf2(void);
+void __fixdfdi(void);
+void __fixdfsi(void);
+void __fixsfdi(void);
+void __fixsfsi(void);
+void __fixunsdfdi(void);
+void __fixunsdfsi(void);
+void __fixunssfdi(void);
+void __fixunssfsi(void);
+void __floatdidf(void);
+void __floatdisf(void);
+void __floatsidf(void);
+void __floatsisf(void);
+void __floatundidf(void);
+void __floatundisf(void);
+void __floatunsidf(void);
+void __floatunsisf(void);
+void __gedf2(void);
+void __gesf2(void);
+void __gtdf2(void);
+void __gtsf2(void);
+void __ledf2(void);
+void __lesf2(void);
+void __ltdf2(void);
+void __ltsf2(void);
+void __moddi3(void);
+void __modsi3(void);
+void __muldf3(void);
+void __muldi3(void);
+void __mulsf3(void);
+void __mulsi3(void);
+void __nedf2(void);
+void __negdf2(void);
+void __negsf2(void);
+void __nesf2(void);
+void __subdf3(void);
+void __subsf3(void);
+void __truncdfsf2(void);
+void __udivdi3(void);
+void __udivsi3(void);
+void __umoddi3(void);
+void __umodsi3(void);
+void __unorddf2(void);
+void __unordsf2(void);
+bool __atomic_compare_exchange_4(volatile void *, void *, unsigned int,
+                                 bool, int, int);
+void __atomic_store_4(volatile void *, unsigned int, int);
 /* clang-format on */
 
 static SymbolMap target_sym_map[] = {
@@ -127,6 +135,7 @@ static SymbolMap target_sym_map[] = {
      * to convert float and long long
      */
     REG_SYM(__floatundisf),
+    REG_SYM(__floatdisf),
 #endif
 #ifdef NEED_SOFT_DP
     REG_SYM(__adddf3),
@@ -175,6 +184,10 @@ static SymbolMap target_sym_map[] = {
     REG_SYM(__moddi3),
     REG_SYM(__udivdi3),
     REG_SYM(__umoddi3),
+#endif
+#ifdef NEED_SOFT_ATOMIC
+    REG_SYM(__atomic_compare_exchange_4),
+    REG_SYM(__atomic_store_4),
 #endif
     /* clang-format on */
 };
@@ -193,7 +206,7 @@ get_current_target(char *target_buf, uint32 target_buf_size)
 }
 
 uint32
-get_plt_item_size()
+get_plt_item_size(void)
 {
 #if __riscv_xlen == 64
     /* auipc + ld + jalr + nop + addr */

+ 97 - 97
core/iwasm/aot/arch/aot_reloc_thumb.c

@@ -14,102 +14,102 @@
 #define R_ARM_THM_MOVT_PREL 50
 
 /* clang-format off */
-void __adddf3();
-void __addsf3();
-void __aeabi_d2f();
-void __aeabi_d2iz();
-void __aeabi_d2lz();
-void __aeabi_d2uiz();
-void __aeabi_d2ulz();
-void __aeabi_dadd();
-void __aeabi_dcmpeq();
-void __aeabi_dcmpge();
-void __aeabi_dcmpgt();
-void __aeabi_dcmple();
-void __aeabi_dcmplt();
-void __aeabi_dcmpun();
-void __aeabi_ddiv();
-void __aeabi_dmul();
-void __aeabi_dsub();
-void __aeabi_f2d();
-void __aeabi_f2iz();
-void __aeabi_f2lz();
-void __aeabi_f2ulz();
-void __aeabi_fadd();
-void __aeabi_fcmpeq();
-void __aeabi_fcmpge();
-void __aeabi_fcmpgt();
-void __aeabi_fcmple();
-void __aeabi_fcmplt();
-void __aeabi_fcmpun();
-void __aeabi_fdiv();
-void __aeabi_fmul();
-void __aeabi_fsub();
-void __aeabi_i2d();
-void __aeabi_i2f();
-void __aeabi_idiv();
-void __aeabi_idivmod();
-void __aeabi_l2d();
-void __aeabi_l2f();
-void __aeabi_ldivmod();
-void __aeabi_llsl();
-void __aeabi_llsr();
-void __aeabi_lmul();
-void __aeabi_ui2d();
-void __aeabi_ui2f();
-void __aeabi_uidiv();
-void __aeabi_uidivmod();
-void __aeabi_ul2d();
-void __aeabi_ul2f();
-void __aeabi_uldivmod();
-void __ashldi3();
-void __clzsi2();
-void __divdf3();
-void __divdi3();
-void __divsi3();
-void __eqdf2();
-void __eqsf2();
-void __extendsfdf2();
-void __fixdfdi();
-void __fixdfsi();
-void __fixsfdi();
-void __fixunsdfdi();
-void __fixunsdfsi();
-void __fixunssfdi();
-void __floatdidf();
-void __floatdisf();
-void __floatsidf();
-void __floatsisf();
-void __floatundidf();
-void __floatundisf();
-void __floatunsidf();
-void __floatunsisf();
-void __gedf2();
-void __gesf2();
-void __gtdf2();
-void __gtsf2();
-void __ledf2();
-void __lesf2();
-void __lshrdi3();
-void __ltdf2();
-void __ltsf2();
-void __moddi3();
-void __modsi3();
-void __muldf3();
-void __muldi3();
-void __mulsf3();
-void __nedf2();
-void __nesf2();
-void __subdf3();
-void __subsf3();
-void __truncdfsf2();
-void __udivdi3();
-void __udivmoddi4();
-void __udivsi3();
-void __umoddi3();
-void __umodsi3();
-void __unorddf2();
-void __unordsf2();
+void __adddf3(void);
+void __addsf3(void);
+void __aeabi_d2f(void);
+void __aeabi_d2iz(void);
+void __aeabi_d2lz(void);
+void __aeabi_d2uiz(void);
+void __aeabi_d2ulz(void);
+void __aeabi_dadd(void);
+void __aeabi_dcmpeq(void);
+void __aeabi_dcmpge(void);
+void __aeabi_dcmpgt(void);
+void __aeabi_dcmple(void);
+void __aeabi_dcmplt(void);
+void __aeabi_dcmpun(void);
+void __aeabi_ddiv(void);
+void __aeabi_dmul(void);
+void __aeabi_dsub(void);
+void __aeabi_f2d(void);
+void __aeabi_f2iz(void);
+void __aeabi_f2lz(void);
+void __aeabi_f2ulz(void);
+void __aeabi_fadd(void);
+void __aeabi_fcmpeq(void);
+void __aeabi_fcmpge(void);
+void __aeabi_fcmpgt(void);
+void __aeabi_fcmple(void);
+void __aeabi_fcmplt(void);
+void __aeabi_fcmpun(void);
+void __aeabi_fdiv(void);
+void __aeabi_fmul(void);
+void __aeabi_fsub(void);
+void __aeabi_i2d(void);
+void __aeabi_i2f(void);
+void __aeabi_idiv(void);
+void __aeabi_idivmod(void);
+void __aeabi_l2d(void);
+void __aeabi_l2f(void);
+void __aeabi_ldivmod(void);
+void __aeabi_llsl(void);
+void __aeabi_llsr(void);
+void __aeabi_lmul(void);
+void __aeabi_ui2d(void);
+void __aeabi_ui2f(void);
+void __aeabi_uidiv(void);
+void __aeabi_uidivmod(void);
+void __aeabi_ul2d(void);
+void __aeabi_ul2f(void);
+void __aeabi_uldivmod(void);
+void __ashldi3(void);
+void __clzsi2(void);
+void __divdf3(void);
+void __divdi3(void);
+void __divsi3(void);
+void __eqdf2(void);
+void __eqsf2(void);
+void __extendsfdf2(void);
+void __fixdfdi(void);
+void __fixdfsi(void);
+void __fixsfdi(void);
+void __fixunsdfdi(void);
+void __fixunsdfsi(void);
+void __fixunssfdi(void);
+void __floatdidf(void);
+void __floatdisf(void);
+void __floatsidf(void);
+void __floatsisf(void);
+void __floatundidf(void);
+void __floatundisf(void);
+void __floatunsidf(void);
+void __floatunsisf(void);
+void __gedf2(void);
+void __gesf2(void);
+void __gtdf2(void);
+void __gtsf2(void);
+void __ledf2(void);
+void __lesf2(void);
+void __lshrdi3(void);
+void __ltdf2(void);
+void __ltsf2(void);
+void __moddi3(void);
+void __modsi3(void);
+void __muldf3(void);
+void __muldi3(void);
+void __mulsf3(void);
+void __nedf2(void);
+void __nesf2(void);
+void __subdf3(void);
+void __subsf3(void);
+void __truncdfsf2(void);
+void __udivdi3(void);
+void __udivmoddi4(void);
+void __udivsi3(void);
+void __umoddi3(void);
+void __umodsi3(void);
+void __unorddf2(void);
+void __unordsf2(void);
 /* clang-format on */
 
 static SymbolMap target_sym_map[] = {
@@ -259,7 +259,7 @@ get_current_target(char *target_buf, uint32 target_buf_size)
 #undef BUILD_TARGET_THUMB_V4T
 
 uint32
-get_plt_item_size()
+get_plt_item_size(void)
 {
     /* 16 bytes instructions and 4 bytes symbol address */
     return 20;

+ 1 - 1
core/iwasm/aot/arch/aot_reloc_x86_64.c

@@ -58,7 +58,7 @@ get_current_target(char *target_buf, uint32 target_buf_size)
 }
 
 static uint32
-get_plt_item_size()
+get_plt_item_size(void)
 {
     /* size of mov instruction and jmp instruction */
     return 12;

+ 37 - 37
core/iwasm/aot/arch/aot_reloc_xtensa.c

@@ -10,44 +10,44 @@
 
 /* clang-format off */
 /* for soft-float */
-void __floatsidf();
-void __divdf3();
-void __ltdf2();
+void __floatsidf(void);
+void __divdf3(void);
+void __ltdf2(void);
 
 /* for mul32 */
-void __mulsi3();
-void __muldi3();
-
-void __modsi3();
-
-void __divdi3();
-
-void __udivdi3();
-void __unorddf2();
-void __adddf3();
-void __eqdf2();
-void __muldf3();
-void __gedf2();
-void __ledf2();
-void __fixunsdfsi();
-void __floatunsidf();
-void __subdf3();
-void __nedf2();
-void __fixdfsi();
-void __moddi3();
-void __extendsfdf2();
-void __truncdfsf2();
-void __gtdf2();
-void __umoddi3();
-void __floatdidf();
-void __divsf3();
-void __fixdfdi();
-void __floatundidf();
-void __fixsfdi();
-void __fixunssfdi();
-void __fixunsdfdi();
-void __floatdisf();
-void __floatundisf();
+void __mulsi3(void);
+void __muldi3(void);
+
+void __modsi3(void);
+
+void __divdi3(void);
+
+void __udivdi3(void);
+void __unorddf2(void);
+void __adddf3(void);
+void __eqdf2(void);
+void __muldf3(void);
+void __gedf2(void);
+void __ledf2(void);
+void __fixunsdfsi(void);
+void __floatunsidf(void);
+void __subdf3(void);
+void __nedf2(void);
+void __fixdfsi(void);
+void __moddi3(void);
+void __extendsfdf2(void);
+void __truncdfsf2(void);
+void __gtdf2(void);
+void __umoddi3(void);
+void __floatdidf(void);
+void __divsf3(void);
+void __fixdfdi(void);
+void __floatundidf(void);
+void __fixsfdi(void);
+void __fixunssfdi(void);
+void __fixunsdfdi(void);
+void __floatdisf(void);
+void __floatundisf(void);
 
 
 static SymbolMap target_sym_map[] = {
@@ -119,7 +119,7 @@ get_current_target(char *target_buf, uint32 target_buf_size)
 }
 
 static uint32
-get_plt_item_size()
+get_plt_item_size(void)
 {
     return 0;
 }

+ 5 - 5
core/iwasm/aot/debug/jit_debug.c

@@ -69,10 +69,10 @@ typedef struct JITDescriptor {
  * and inline assembler statement inside.
  */
 void attribute_noinline
-__jit_debug_register_code();
+__jit_debug_register_code(void);
 
 void attribute_noinline
-__jit_debug_register_code()
+__jit_debug_register_code(void)
 {
     int x;
     *(char *)&x = '\0';
@@ -96,7 +96,7 @@ extern JITDescriptor __jit_debug_descriptor;
  * This gives the debugger an easy way to inject custom code to
  * handle the events.
  */
-void (*__jit_debug_register_code_ptr)() = __jit_debug_register_code;
+void (*__jit_debug_register_code_ptr)(void) = __jit_debug_register_code;
 
 #ifdef __cplusplus
 }
@@ -171,7 +171,7 @@ DestroyJITCodeEntryInternal(JITCodeEntry *entry)
 }
 
 bool
-jit_debug_engine_init()
+jit_debug_engine_init(void)
 {
     if (jit_debug_engine) {
         return true;
@@ -194,7 +194,7 @@ jit_debug_engine_init()
 }
 
 void
-jit_debug_engine_destroy()
+jit_debug_engine_destroy(void)
 {
     if (jit_debug_engine) {
         WASMJITEntryNode *node, *node_next;

+ 2 - 2
core/iwasm/aot/debug/jit_debug.h

@@ -11,10 +11,10 @@ extern "C" {
 #endif
 
 bool
-jit_debug_engine_init();
+jit_debug_engine_init(void);
 
 void
-jit_debug_engine_destroy();
+jit_debug_engine_destroy(void);
 
 bool
 jit_code_entry_create(const uint8 *symfile_addr, uint64 symfile_size);

+ 1 - 2
core/iwasm/common/wasm_c_api.c

@@ -3391,8 +3391,7 @@ wasm_func_call(const wasm_func_t *func, const wasm_val_vec_t *params,
                 if (export->kind == EXPORT_KIND_FUNC) {
                     if (export->index == func->func_idx_rt) {
                         func_comm_rt =
-                            (AOTFunctionInstance *)inst_aot->export_functions
-                            + export_func_j;
+                            aot_lookup_function(inst_aot, export->name);
                         ((wasm_func_t *)func)->func_comm_rt = func_comm_rt;
                         break;
                     }

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

@@ -282,8 +282,13 @@ wasm_exec_env_set_thread_info(WASMExecEnv *exec_env)
     os_mutex_lock(&exec_env->wait_lock);
 #endif
     exec_env->handle = os_self_thread();
-    exec_env->native_stack_boundary =
-        stack_boundary ? stack_boundary + WASM_STACK_GUARD_SIZE : NULL;
+    if (exec_env->user_native_stack_boundary)
+        /* WASM_STACK_GUARD_SIZE isn't added for flexibility to developer,
+           he must ensure that enough guard bytes are kept. */
+        exec_env->native_stack_boundary = exec_env->user_native_stack_boundary;
+    else
+        exec_env->native_stack_boundary =
+            stack_boundary ? stack_boundary + WASM_STACK_GUARD_SIZE : NULL;
     exec_env->native_stack_top_min = (void *)UINTPTR_MAX;
 #if WASM_ENABLE_THREAD_MGR != 0
     os_mutex_unlock(&exec_env->wait_lock);

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

@@ -136,6 +136,10 @@ typedef struct WASMExecEnv {
 
     void *user_data;
 
+    /* The boundary of native stack set by host embedder. It is used
+       if it is not NULL when calling wasm functions. */
+    uint8 *user_native_stack_boundary;
+
     /* The native thread handle of current thread */
     korp_tid handle;
 

+ 62 - 0
core/iwasm/common/wasm_loader_common.c

@@ -19,6 +19,37 @@ wasm_loader_set_error_buf(char *error_buf, uint32 error_buf_size,
     }
 }
 
+#if WASM_ENABLE_MEMORY64 != 0
+bool
+check_memory64_flags_consistency(WASMModule *module, char *error_buf,
+                                 uint32 error_buf_size, bool is_aot)
+{
+    uint32 i;
+    bool wasm64_flag, all_wasm64 = true, none_wasm64 = true;
+
+    for (i = 0; i < module->import_memory_count; ++i) {
+        wasm64_flag =
+            module->import_memories[i].u.memory.mem_type.flags & MEMORY64_FLAG;
+        all_wasm64 &= wasm64_flag;
+        none_wasm64 &= !wasm64_flag;
+    }
+
+    for (i = 0; i < module->memory_count; ++i) {
+        wasm64_flag = module->memories[i].flags & MEMORY64_FLAG;
+        all_wasm64 &= wasm64_flag;
+        none_wasm64 &= !wasm64_flag;
+    }
+
+    if (!(all_wasm64 || none_wasm64)) {
+        wasm_loader_set_error_buf(
+            error_buf, error_buf_size,
+            "inconsistent limits wasm64 flags for memory sections", is_aot);
+        return false;
+    }
+    return true;
+}
+#endif
+
 bool
 wasm_memory_check_flags(const uint8 mem_flag, char *error_buf,
                         uint32 error_buf_size, bool is_aot)
@@ -60,6 +91,37 @@ wasm_memory_check_flags(const uint8 mem_flag, char *error_buf,
     return true;
 }
 
+bool
+wasm_table_check_flags(const uint8 table_flag, char *error_buf,
+                       uint32 error_buf_size, bool is_aot)
+{
+    /* Check whether certain features indicated by mem_flag are enabled in
+     * runtime */
+    if (table_flag > MAX_TABLE_SIZE_FLAG) {
+        if (table_flag & SHARED_TABLE_FLAG) {
+            wasm_loader_set_error_buf(error_buf, error_buf_size,
+                                      "tables cannot be shared", is_aot);
+        }
+#if WASM_ENABLE_MEMORY64 == 0
+        if (table_flag & TABLE64_FLAG) {
+            wasm_loader_set_error_buf(error_buf, error_buf_size,
+                                      "invalid limits flags(table64 flag was "
+                                      "found, please enable memory64)",
+                                      is_aot);
+            return false;
+        }
+#endif
+    }
+
+    if (table_flag > MAX_TABLE_SIZE_FLAG + TABLE64_FLAG) {
+        wasm_loader_set_error_buf(error_buf, error_buf_size,
+                                  "invalid limits flags", is_aot);
+        return false;
+    }
+
+    return true;
+}
+
 /*
  * compare with a bigger type set in `wasm_value_type_size_internal()`,
  * this function will only cover global value type, function's param

+ 12 - 0
core/iwasm/common/wasm_loader_common.h

@@ -13,10 +13,22 @@
 extern "C" {
 #endif
 
+#if WASM_ENABLE_MEMORY64 != 0
+/* check consistency of memory64 flags across all memories,
+ * they must be either all wasm64 or all wasm32 */
+bool
+check_memory64_flags_consistency(WASMModule *module, char *error_buf,
+                                 uint32 error_buf_size, bool is_aot);
+#endif
+
 bool
 wasm_memory_check_flags(const uint8 mem_flag, char *error_buf,
                         uint32 error_buf_size, bool is_aot);
 
+bool
+wasm_table_check_flags(const uint8 table_flag, char *error_buf,
+                       uint32 error_buf_size, bool is_aot);
+
 bool
 is_valid_value_type(uint8 value_tpye);
 

+ 673 - 41
core/iwasm/common/wasm_memory.c

@@ -13,6 +13,10 @@
 #include "../common/wasm_shared_memory.h"
 #endif
 
+#if WASM_ENABLE_THREAD_MGR != 0
+#include "../libraries/thread-mgr/thread_manager.h"
+#endif
+
 typedef enum Memory_Mode {
     MEMORY_MODE_UNKNOWN = 0,
     MEMORY_MODE_POOL,
@@ -24,6 +28,11 @@ static Memory_Mode memory_mode = MEMORY_MODE_UNKNOWN;
 
 static mem_allocator_t pool_allocator = NULL;
 
+#if WASM_ENABLE_SHARED_HEAP != 0
+static WASMSharedHeap *shared_heap_list = NULL;
+static korp_mutex shared_heap_list_lock;
+#endif
+
 static enlarge_memory_error_callback_t enlarge_memory_error_cb;
 static void *enlarge_memory_error_user_data;
 
@@ -132,16 +141,371 @@ is_bounds_checks_enabled(WASMModuleInstanceCommon *module_inst)
 #endif
 }
 
+#if WASM_ENABLE_SHARED_HEAP != 0
+static void *
+wasm_mmap_linear_memory(uint64_t map_size, uint64 commit_size);
+static void
+wasm_munmap_linear_memory(void *mapped_mem, uint64 commit_size,
+                          uint64 map_size);
+
+static void *
+runtime_malloc(uint64 size)
+{
+    void *mem;
+
+    if (size >= UINT32_MAX || !(mem = wasm_runtime_malloc((uint32)size))) {
+        LOG_WARNING("Allocate memory failed");
+        return NULL;
+    }
+
+    memset(mem, 0, (uint32)size);
+    return mem;
+}
+
+WASMSharedHeap *
+wasm_runtime_create_shared_heap(SharedHeapInitArgs *init_args)
+{
+    uint64 heap_struct_size = sizeof(WASMSharedHeap), map_size;
+    uint32 size = init_args->size;
+    WASMSharedHeap *heap;
+
+    if (size == 0) {
+        goto fail1;
+    }
+
+    if (!(heap = runtime_malloc(heap_struct_size))) {
+        goto fail1;
+    }
+
+    if (!(heap->heap_handle =
+              runtime_malloc(mem_allocator_get_heap_struct_size()))) {
+        goto fail2;
+    }
+
+    size = align_uint(size, os_getpagesize());
+    heap->size = size;
+    heap->start_off_mem64 = UINT64_MAX - heap->size + 1;
+    heap->start_off_mem32 = UINT32_MAX - heap->size + 1;
+
+    if (size > APP_HEAP_SIZE_MAX || size < APP_HEAP_SIZE_MIN) {
+        LOG_WARNING("Invalid size of shared heap");
+        goto fail3;
+    }
+
+#ifndef OS_ENABLE_HW_BOUND_CHECK
+    map_size = size;
+#else
+    /* Totally 8G is mapped, the opcode load/store address range is 0 to 8G:
+     *   ea = i + memarg.offset
+     * both i and memarg.offset are u32 in range 0 to 4G
+     * so the range of ea is 0 to 8G
+     */
+    map_size = 8 * (uint64)BH_GB;
+#endif
+
+    if (!(heap->base_addr = wasm_mmap_linear_memory(map_size, size))) {
+        goto fail3;
+    }
+    if (!mem_allocator_create_with_struct_and_pool(
+            heap->heap_handle, heap_struct_size, heap->base_addr, size)) {
+        LOG_WARNING("init share heap failed");
+        goto fail4;
+    }
+
+    os_mutex_lock(&shared_heap_list_lock);
+    if (shared_heap_list == NULL) {
+        shared_heap_list = heap;
+    }
+    else {
+        heap->next = shared_heap_list;
+        shared_heap_list = heap;
+    }
+    os_mutex_unlock(&shared_heap_list_lock);
+    return heap;
+
+fail4:
+    wasm_munmap_linear_memory(heap->base_addr, size, map_size);
+fail3:
+    wasm_runtime_free(heap->heap_handle);
+fail2:
+    wasm_runtime_free(heap);
+fail1:
+    return NULL;
+}
+
+bool
+wasm_runtime_attach_shared_heap_internal(WASMModuleInstanceCommon *module_inst,
+                                         WASMSharedHeap *shared_heap)
+{
+    WASMMemoryInstance *memory =
+        wasm_get_default_memory((WASMModuleInstance *)module_inst);
+    uint64 linear_mem_size;
+
+    if (!memory)
+        return false;
+
+    linear_mem_size = memory->memory_data_size;
+
+    /* check if linear memory and shared heap are overlapped */
+    if ((memory->is_memory64 && linear_mem_size > shared_heap->start_off_mem64)
+        || (!memory->is_memory64
+            && linear_mem_size > shared_heap->start_off_mem32)) {
+        LOG_WARNING("Linear memory address is overlapped with shared heap");
+        return false;
+    }
+
+#if WASM_ENABLE_INTERP != 0
+    if (module_inst->module_type == Wasm_Module_Bytecode) {
+        WASMModuleInstanceExtra *e =
+            (WASMModuleInstanceExtra *)((WASMModuleInstance *)module_inst)->e;
+        if (e->shared_heap) {
+            LOG_WARNING("A shared heap is already attached");
+            return false;
+        }
+        e->shared_heap = shared_heap;
+#if WASM_ENABLE_JIT != 0
+#if UINTPTR_MAX == UINT64_MAX
+        if (memory->is_memory64)
+            e->shared_heap_start_off.u64 = shared_heap->start_off_mem64;
+        else
+            e->shared_heap_start_off.u64 = shared_heap->start_off_mem32;
+        e->shared_heap_base_addr_adj =
+            shared_heap->base_addr - e->shared_heap_start_off.u64;
+#else
+        e->shared_heap_start_off.u32[0] = (uint32)shared_heap->start_off_mem32;
+        e->shared_heap_base_addr_adj =
+            shared_heap->base_addr - e->shared_heap_start_off.u32[0];
+#endif
+#endif /* end of WASM_ENABLE_JIT != 0 */
+    }
+#endif /* end of WASM_ENABLE_INTERP != 0 */
+#if WASM_ENABLE_AOT != 0
+    if (module_inst->module_type == Wasm_Module_AoT) {
+        AOTModuleInstanceExtra *e =
+            (AOTModuleInstanceExtra *)((AOTModuleInstance *)module_inst)->e;
+        if (e->shared_heap) {
+            LOG_WARNING("A shared heap is already attached");
+            return false;
+        }
+        e->shared_heap = shared_heap;
+#if UINTPTR_MAX == UINT64_MAX
+        if (memory->is_memory64)
+            e->shared_heap_start_off.u64 = shared_heap->start_off_mem64;
+        else
+            e->shared_heap_start_off.u64 = shared_heap->start_off_mem32;
+        e->shared_heap_base_addr_adj =
+            shared_heap->base_addr - e->shared_heap_start_off.u64;
+#else
+        e->shared_heap_start_off.u32[0] = (uint32)shared_heap->start_off_mem32;
+        e->shared_heap_base_addr_adj =
+            shared_heap->base_addr - e->shared_heap_start_off.u32[0];
+#endif
+    }
+#endif /* end of WASM_ENABLE_AOT != 0 */
+
+    return true;
+}
+
+bool
+wasm_runtime_attach_shared_heap(WASMModuleInstanceCommon *module_inst,
+                                WASMSharedHeap *shared_heap)
+{
+#if WASM_ENABLE_THREAD_MGR != 0
+    return wasm_cluster_attach_shared_heap(module_inst, shared_heap);
+#else
+    return wasm_runtime_attach_shared_heap_internal(module_inst, shared_heap);
+#endif
+}
+
+void
+wasm_runtime_detach_shared_heap_internal(WASMModuleInstanceCommon *module_inst)
+{
+#if WASM_ENABLE_INTERP != 0
+    if (module_inst->module_type == Wasm_Module_Bytecode) {
+        WASMModuleInstanceExtra *e =
+            (WASMModuleInstanceExtra *)((WASMModuleInstance *)module_inst)->e;
+        e->shared_heap = NULL;
+#if WASM_ENABLE_JIT != 0
+#if UINTPTR_MAX == UINT64_MAX
+        e->shared_heap_start_off.u64 = UINT64_MAX;
+#else
+        e->shared_heap_start_off.u32[0] = UINT32_MAX;
+#endif
+        e->shared_heap_base_addr_adj = NULL;
+#endif
+    }
+#endif /* end of WASM_ENABLE_INTERP != 0 */
+#if WASM_ENABLE_AOT != 0
+    if (module_inst->module_type == Wasm_Module_AoT) {
+        AOTModuleInstanceExtra *e =
+            (AOTModuleInstanceExtra *)((AOTModuleInstance *)module_inst)->e;
+        e->shared_heap = NULL;
+#if UINTPTR_MAX == UINT64_MAX
+        e->shared_heap_start_off.u64 = UINT64_MAX;
+#else
+        e->shared_heap_start_off.u32[0] = UINT32_MAX;
+#endif
+        e->shared_heap_base_addr_adj = NULL;
+    }
+#endif /* end of WASM_ENABLE_AOT != 0 */
+}
+
+void
+wasm_runtime_detach_shared_heap(WASMModuleInstanceCommon *module_inst)
+{
+#if WASM_ENABLE_THREAD_MGR != 0
+    wasm_cluster_detach_shared_heap(module_inst);
+#else
+    wasm_runtime_detach_shared_heap_internal(module_inst);
+#endif
+}
+
+static WASMSharedHeap *
+get_shared_heap(WASMModuleInstanceCommon *module_inst_comm)
+{
+#if WASM_ENABLE_INTERP != 0
+    if (module_inst_comm->module_type == Wasm_Module_Bytecode) {
+        return ((WASMModuleInstance *)module_inst_comm)->e->shared_heap;
+    }
+#endif
+#if WASM_ENABLE_AOT != 0
+    if (module_inst_comm->module_type == Wasm_Module_AoT) {
+        AOTModuleInstanceExtra *e =
+            (AOTModuleInstanceExtra *)((AOTModuleInstance *)module_inst_comm)
+                ->e;
+        return e->shared_heap;
+    }
+#endif
+    return NULL;
+}
+
+WASMSharedHeap *
+wasm_runtime_get_shared_heap(WASMModuleInstanceCommon *module_inst_comm)
+{
+    return get_shared_heap(module_inst_comm);
+}
+
+static bool
+is_app_addr_in_shared_heap(WASMModuleInstanceCommon *module_inst,
+                           bool is_memory64, uint64 app_offset, uint32 bytes)
+{
+    WASMSharedHeap *heap = get_shared_heap(module_inst);
+
+    if (!heap) {
+        return false;
+    }
+
+    if (bytes == 0) {
+        bytes = 1;
+    }
+
+    if (!is_memory64) {
+        if (app_offset >= heap->start_off_mem32
+            && app_offset <= UINT32_MAX - bytes + 1) {
+            return true;
+        }
+    }
+    else {
+        if (app_offset >= heap->start_off_mem64
+            && app_offset <= UINT64_MAX - bytes + 1) {
+            return true;
+        }
+    }
+
+    return false;
+}
+
+static bool
+is_native_addr_in_shared_heap(WASMModuleInstanceCommon *module_inst,
+                              uint8 *addr, uint32 bytes)
+{
+    WASMSharedHeap *heap = get_shared_heap(module_inst);
+
+    if (heap && addr >= heap->base_addr
+        && addr + bytes <= heap->base_addr + heap->size
+        && addr + bytes > addr) {
+        return true;
+    }
+    return false;
+}
+
+uint64
+wasm_runtime_shared_heap_malloc(WASMModuleInstanceCommon *module_inst,
+                                uint64_t size, void **p_native_addr)
+{
+    WASMMemoryInstance *memory =
+        wasm_get_default_memory((WASMModuleInstance *)module_inst);
+    WASMSharedHeap *shared_heap = get_shared_heap(module_inst);
+    void *native_addr = NULL;
+
+    if (!memory || !shared_heap)
+        return 0;
+
+    native_addr = mem_allocator_malloc(shared_heap->heap_handle, size);
+    if (!native_addr)
+        return 0;
+
+    if (p_native_addr) {
+        *p_native_addr = native_addr;
+    }
+
+    if (memory->is_memory64)
+        return shared_heap->start_off_mem64
+               + ((uint8 *)native_addr - shared_heap->base_addr);
+    else
+        return shared_heap->start_off_mem32
+               + ((uint8 *)native_addr - shared_heap->base_addr);
+}
+
+void
+wasm_runtime_shared_heap_free(WASMModuleInstanceCommon *module_inst, uint64 ptr)
+{
+    WASMMemoryInstance *memory =
+        wasm_get_default_memory((WASMModuleInstance *)module_inst);
+    WASMSharedHeap *shared_heap = get_shared_heap(module_inst);
+    uint8 *addr = NULL;
+
+    if (!memory || !shared_heap) {
+        return;
+    }
+
+    if (memory->is_memory64) {
+        if (ptr < shared_heap->start_off_mem64) { /* ptr can not > UINT64_MAX */
+            LOG_WARNING("The address to free isn't in shared heap");
+            return;
+        }
+        addr = shared_heap->base_addr + (ptr - shared_heap->start_off_mem64);
+    }
+    else {
+        if (ptr < shared_heap->start_off_mem32 || ptr > UINT32_MAX) {
+            LOG_WARNING("The address to free isn't in shared heap");
+            return;
+        }
+        addr = shared_heap->base_addr + (ptr - shared_heap->start_off_mem32);
+    }
+
+    mem_allocator_free(shared_heap->heap_handle, addr);
+}
+#endif /* end of WASM_ENABLE_SHARED_HEAP != 0 */
+
 bool
 wasm_runtime_memory_init(mem_alloc_type_t mem_alloc_type,
                          const MemAllocOption *alloc_option)
 {
+    bool ret = false;
+
+#if WASM_ENABLE_SHARED_HEAP != 0
+    if (os_mutex_init(&shared_heap_list_lock)) {
+        return false;
+    }
+#endif
+
     if (mem_alloc_type == Alloc_With_Pool) {
-        return wasm_memory_init_with_pool(alloc_option->pool.heap_buf,
-                                          alloc_option->pool.heap_size);
+        ret = wasm_memory_init_with_pool(alloc_option->pool.heap_buf,
+                                         alloc_option->pool.heap_size);
     }
     else if (mem_alloc_type == Alloc_With_Allocator) {
-        return wasm_memory_init_with_allocator(
+        ret = wasm_memory_init_with_allocator(
 #if WASM_MEM_ALLOC_WITH_USER_DATA != 0
             alloc_option->allocator.user_data,
 #endif
@@ -151,16 +515,58 @@ wasm_runtime_memory_init(mem_alloc_type_t mem_alloc_type,
     }
     else if (mem_alloc_type == Alloc_With_System_Allocator) {
         memory_mode = MEMORY_MODE_SYSTEM_ALLOCATOR;
-        return true;
+        ret = true;
     }
     else {
-        return false;
+        ret = false;
+    }
+
+#if WASM_ENABLE_SHARED_HEAP != 0
+    if (!ret) {
+        os_mutex_destroy(&shared_heap_list_lock);
     }
+#endif
+
+    return ret;
 }
 
+#if WASM_ENABLE_SHARED_HEAP != 0
+static void
+destroy_shared_heaps()
+{
+    WASMSharedHeap *heap;
+    WASMSharedHeap *cur;
+    uint64 map_size;
+
+    os_mutex_lock(&shared_heap_list_lock);
+    heap = shared_heap_list;
+    shared_heap_list = NULL;
+    os_mutex_unlock(&shared_heap_list_lock);
+
+    while (heap) {
+        cur = heap;
+        heap = heap->next;
+        mem_allocator_destroy(cur->heap_handle);
+        wasm_runtime_free(cur->heap_handle);
+#ifndef OS_ENABLE_HW_BOUND_CHECK
+        map_size = cur->size;
+#else
+        map_size = 8 * (uint64)BH_GB;
+#endif
+        wasm_munmap_linear_memory(cur->base_addr, cur->size, map_size);
+        wasm_runtime_free(cur);
+    }
+    os_mutex_destroy(&shared_heap_list_lock);
+}
+#endif
+
 void
-wasm_runtime_memory_destroy()
+wasm_runtime_memory_destroy(void)
 {
+#if WASM_ENABLE_SHARED_HEAP != 0
+    destroy_shared_heaps();
+#endif
+
     if (memory_mode == MEMORY_MODE_POOL) {
 #if BH_ENABLE_GC_VERIFY == 0
         (void)mem_allocator_destroy(pool_allocator);
@@ -176,7 +582,7 @@ wasm_runtime_memory_destroy()
 }
 
 unsigned
-wasm_runtime_memory_pool_size()
+wasm_runtime_memory_pool_size(void)
 {
     if (memory_mode == MEMORY_MODE_POOL)
         return global_pool_size;
@@ -335,6 +741,13 @@ wasm_runtime_validate_app_addr(WASMModuleInstanceCommon *module_inst_comm,
         goto fail;
     }
 
+#if WASM_ENABLE_SHARED_HEAP != 0
+    if (is_app_addr_in_shared_heap(module_inst_comm, memory_inst->is_memory64,
+                                   app_offset, size)) {
+        return true;
+    }
+#endif
+
 #if WASM_ENABLE_MEMORY64 != 0
     if (memory_inst->is_memory64)
         max_linear_memory_size = MAX_LINEAR_MEM64_MEMORY_SIZE;
@@ -364,6 +777,7 @@ wasm_runtime_validate_app_str_addr(WASMModuleInstanceCommon *module_inst_comm,
                                    uint64 app_str_offset)
 {
     WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm;
+    WASMMemoryInstance *memory_inst;
     uint64 app_end_offset, max_linear_memory_size = MAX_LINEAR_MEMORY_SIZE;
     char *str, *str_end;
 
@@ -374,22 +788,42 @@ wasm_runtime_validate_app_str_addr(WASMModuleInstanceCommon *module_inst_comm,
         return true;
     }
 
-    if (!wasm_runtime_get_app_addr_range(module_inst_comm, app_str_offset, NULL,
-                                         &app_end_offset))
+    memory_inst = wasm_get_default_memory(module_inst);
+    if (!memory_inst) {
         goto fail;
+    }
+
+#if WASM_ENABLE_SHARED_HEAP != 0
+    if (is_app_addr_in_shared_heap(module_inst_comm, memory_inst->is_memory64,
+                                   app_str_offset, 1)) {
+        WASMSharedHeap *shared_heap = get_shared_heap(module_inst_comm);
+        str = (char *)shared_heap->base_addr
+              + (memory_inst->is_memory64
+                     ? (app_str_offset - shared_heap->start_off_mem64)
+                     : (app_str_offset - shared_heap->start_off_mem32));
+        str_end = (char *)shared_heap->base_addr + shared_heap->size;
+    }
+    else
+#endif
+    {
+        if (!wasm_runtime_get_app_addr_range(module_inst_comm, app_str_offset,
+                                             NULL, &app_end_offset))
+            goto fail;
 
 #if WASM_ENABLE_MEMORY64 != 0
-    if (module_inst->memories[0]->is_memory64)
-        max_linear_memory_size = MAX_LINEAR_MEM64_MEMORY_SIZE;
+        if (memory_inst->is_memory64)
+            max_linear_memory_size = MAX_LINEAR_MEM64_MEMORY_SIZE;
 #endif
-    /* boundary overflow check, max start offset can only be size - 1, while end
-     * offset can be size */
-    if (app_str_offset >= max_linear_memory_size
-        || app_end_offset > max_linear_memory_size)
-        goto fail;
+        /* boundary overflow check, max start offset can be size - 1, while end
+           offset can be size */
+        if (app_str_offset >= max_linear_memory_size
+            || app_end_offset > max_linear_memory_size)
+            goto fail;
+
+        str = wasm_runtime_addr_app_to_native(module_inst_comm, app_str_offset);
+        str_end = str + (app_end_offset - app_str_offset);
+    }
 
-    str = wasm_runtime_addr_app_to_native(module_inst_comm, app_str_offset);
-    str_end = str + (app_end_offset - app_str_offset);
     while (str < str_end && *str != '\0')
         str++;
     if (str == str_end)
@@ -431,6 +865,12 @@ wasm_runtime_validate_native_addr(WASMModuleInstanceCommon *module_inst_comm,
         goto fail;
     }
 
+#if WASM_ENABLE_SHARED_HEAP != 0
+    if (is_native_addr_in_shared_heap(module_inst_comm, native_ptr, size)) {
+        return true;
+    }
+#endif
+
     SHARED_MEMORY_LOCK(memory_inst);
 
     if (memory_inst->memory_data <= addr
@@ -465,6 +905,23 @@ wasm_runtime_addr_app_to_native(WASMModuleInstanceCommon *module_inst_comm,
         return NULL;
     }
 
+#if WASM_ENABLE_SHARED_HEAP != 0
+    if (is_app_addr_in_shared_heap(module_inst_comm, memory_inst->is_memory64,
+                                   app_offset, 1)) {
+        WASMSharedHeap *shared_heap = get_shared_heap(module_inst_comm);
+        uint64 shared_heap_start = 0;
+
+        if (memory_inst && !memory_inst->is_memory64) {
+            shared_heap_start = shared_heap->start_off_mem32;
+        }
+        else if (memory_inst && memory_inst->is_memory64) {
+            shared_heap_start = shared_heap->start_off_mem64;
+        }
+
+        return shared_heap->base_addr + app_offset - shared_heap_start;
+    }
+#endif
+
     SHARED_MEMORY_LOCK(memory_inst);
 
     addr = memory_inst->memory_data + (uintptr_t)app_offset;
@@ -499,11 +956,32 @@ wasm_runtime_addr_native_to_app(WASMModuleInstanceCommon *module_inst_comm,
 
     bounds_checks = is_bounds_checks_enabled(module_inst_comm);
 
+#if WASM_ENABLE_SHARED_HEAP != 0
+    /* If shared heap is enabled, bounds check is always needed */
+    bounds_checks = true;
+#endif
+
     memory_inst = wasm_get_default_memory(module_inst);
     if (!memory_inst) {
         return 0;
     }
 
+#if WASM_ENABLE_SHARED_HEAP != 0
+    if (is_native_addr_in_shared_heap(module_inst_comm, addr, 1)) {
+        WASMSharedHeap *shared_heap = get_shared_heap(module_inst_comm);
+        uint64 shared_heap_start = 0;
+
+        if (memory_inst && !memory_inst->is_memory64) {
+            shared_heap_start = shared_heap->start_off_mem32;
+        }
+        else if (memory_inst && memory_inst->is_memory64) {
+            shared_heap_start = shared_heap->start_off_mem64;
+        }
+
+        return shared_heap_start + (addr - shared_heap->base_addr);
+    }
+#endif
+
     SHARED_MEMORY_LOCK(memory_inst);
 
     if (bounds_checks) {
@@ -601,6 +1079,10 @@ wasm_check_app_addr_and_convert(WASMModuleInstance *module_inst, bool is_str,
     WASMMemoryInstance *memory_inst = wasm_get_default_memory(module_inst);
     uint8 *native_addr;
     bool bounds_checks;
+#if WASM_ENABLE_SHARED_HEAP != 0
+    WASMSharedHeap *shared_heap;
+    bool is_in_shared_heap = false;
+#endif
 
     bh_assert(app_buf_addr <= UINTPTR_MAX && app_buf_size <= UINTPTR_MAX);
 
@@ -609,9 +1091,25 @@ wasm_check_app_addr_and_convert(WASMModuleInstance *module_inst, bool is_str,
         return false;
     }
 
-    native_addr = memory_inst->memory_data + (uintptr_t)app_buf_addr;
+#if WASM_ENABLE_SHARED_HEAP != 0
+    if (is_app_addr_in_shared_heap((WASMModuleInstanceCommon *)module_inst,
+                                   memory_inst->is_memory64, app_buf_addr,
+                                   app_buf_size)) {
+        shared_heap = get_shared_heap((WASMModuleInstanceCommon *)module_inst);
+        native_addr = shared_heap->base_addr
+                      + (memory_inst->is_memory64
+                             ? (app_buf_addr - shared_heap->start_off_mem64)
+                             : (app_buf_addr - shared_heap->start_off_mem32));
+        is_in_shared_heap = true;
+    }
+    else
+#endif
+    {
+        native_addr = memory_inst->memory_data + (uintptr_t)app_buf_addr;
+    }
 
-    bounds_checks = is_bounds_checks_enabled((wasm_module_inst_t)module_inst);
+    bounds_checks =
+        is_bounds_checks_enabled((WASMModuleInstanceCommon *)module_inst);
 
     if (!bounds_checks) {
         if (app_buf_addr == 0) {
@@ -620,6 +1118,24 @@ wasm_check_app_addr_and_convert(WASMModuleInstance *module_inst, bool is_str,
         goto success;
     }
 
+#if WASM_ENABLE_SHARED_HEAP != 0
+    if (is_in_shared_heap) {
+        const char *str, *str_end;
+
+        /* The whole string must be in the linear memory */
+        str = (const char *)native_addr;
+        str_end = (const char *)shared_heap->base_addr + shared_heap->size;
+        while (str < str_end && *str != '\0')
+            str++;
+        if (str == str_end) {
+            wasm_set_exception(module_inst, "out of bounds memory access");
+            return false;
+        }
+        else
+            goto success;
+    }
+#endif
+
     /* No need to check the app_offset and buf_size if memory access
        boundary check with hardware trap is enabled */
 #ifndef OS_ENABLE_HW_BOUND_CHECK
@@ -673,11 +1189,9 @@ wasm_get_default_memory(WASMModuleInstance *module_inst)
 WASMMemoryInstance *
 wasm_get_memory_with_idx(WASMModuleInstance *module_inst, uint32 index)
 {
-    bh_assert(index < module_inst->memory_count);
-    if (module_inst->memories)
-        return module_inst->memories[index];
-    else
+    if ((index >= module_inst->memory_count) || !module_inst->memories)
         return NULL;
+    return module_inst->memories[index];
 }
 
 void
@@ -751,19 +1265,17 @@ wasm_mremap_linear_memory(void *mapped_mem, uint64 old_size, uint64 new_size,
 }
 
 static void *
-wasm_mmap_linear_memory(uint64_t map_size, uint64 commit_size)
+wasm_mmap_linear_memory(uint64 map_size, uint64 commit_size)
 {
     return wasm_mremap_linear_memory(NULL, 0, map_size, commit_size);
 }
 
-bool
-wasm_enlarge_memory_internal(WASMModuleInstance *module, uint32 inc_page_count,
-                             uint32 memidx)
+static bool
+wasm_enlarge_memory_internal(WASMModuleInstanceCommon *module,
+                             WASMMemoryInstance *memory, uint32 inc_page_count)
 {
-#if WASM_ENABLE_MULTI_MEMORY != 0
-    WASMMemoryInstance *memory = wasm_get_memory_with_idx(module, memidx);
-#else
-    WASMMemoryInstance *memory = wasm_get_default_memory(module);
+#if WASM_ENABLE_SHARED_HEAP != 0
+    WASMSharedHeap *shared_heap;
 #endif
     uint8 *memory_data_old, *memory_data_new, *heap_data_old;
     uint32 num_bytes_per_page, heap_size;
@@ -812,6 +1324,24 @@ wasm_enlarge_memory_internal(WASMModuleInstance *module, uint32 inc_page_count,
         goto return_func;
     }
 
+#if WASM_ENABLE_SHARED_HEAP != 0
+    shared_heap = get_shared_heap(module);
+    if (shared_heap) {
+        if (memory->is_memory64
+            && total_size_new > shared_heap->start_off_mem64) {
+            LOG_WARNING("Linear memory address is overlapped with shared heap");
+            ret = false;
+            goto return_func;
+        }
+        else if (!memory->is_memory64
+                 && total_size_new > shared_heap->start_off_mem32) {
+            LOG_WARNING("Linear memory address is overlapped with shared heap");
+            ret = false;
+            goto return_func;
+        }
+    }
+#endif
+
     bh_assert(total_size_new
               <= GET_MAX_LINEAR_MEMORY_SIZE(memory->is_memory64));
 
@@ -913,7 +1443,7 @@ wasm_enlarge_memory_internal(WASMModuleInstance *module, uint32 inc_page_count,
     wasm_runtime_set_mem_bound_check_bytes(memory, total_size_new);
 
 return_func:
-    if (!ret && enlarge_memory_error_cb) {
+    if (!ret && module && enlarge_memory_error_cb) {
         WASMExecEnv *exec_env = NULL;
 
 #if WASM_ENABLE_INTERP != 0
@@ -926,8 +1456,7 @@ return_func:
 #endif
 
         enlarge_memory_error_cb(inc_page_count, total_size_old, 0,
-                                failure_reason,
-                                (WASMModuleInstanceCommon *)module, exec_env,
+                                failure_reason, module, exec_env,
                                 enlarge_memory_error_user_data);
     }
 
@@ -971,15 +1500,16 @@ wasm_enlarge_memory(WASMModuleInstance *module, uint32 inc_page_count)
 {
     bool ret = false;
 
+    if (module->memory_count > 0) {
 #if WASM_ENABLE_SHARED_MEMORY != 0
-    if (module->memory_count > 0)
         shared_memory_lock(module->memories[0]);
 #endif
-    ret = wasm_enlarge_memory_internal(module, inc_page_count, 0);
+        ret = wasm_enlarge_memory_internal((WASMModuleInstanceCommon *)module,
+                                           module->memories[0], inc_page_count);
 #if WASM_ENABLE_SHARED_MEMORY != 0
-    if (module->memory_count > 0)
         shared_memory_unlock(module->memories[0]);
 #endif
+    }
 
     return ret;
 }
@@ -990,15 +1520,117 @@ wasm_enlarge_memory_with_idx(WASMModuleInstance *module, uint32 inc_page_count,
 {
     bool ret = false;
 
+    if (memidx < module->memory_count) {
 #if WASM_ENABLE_SHARED_MEMORY != 0
-    if (memidx < module->memory_count)
         shared_memory_lock(module->memories[memidx]);
 #endif
-    ret = wasm_enlarge_memory_internal(module, inc_page_count, memidx);
+        ret = wasm_enlarge_memory_internal((WASMModuleInstanceCommon *)module,
+                                           module->memories[memidx],
+                                           inc_page_count);
 #if WASM_ENABLE_SHARED_MEMORY != 0
-    if (memidx < module->memory_count)
         shared_memory_unlock(module->memories[memidx]);
 #endif
+    }
+
+    return ret;
+}
+
+WASMMemoryInstance *
+wasm_runtime_lookup_memory(WASMModuleInstanceCommon *module_inst,
+                           const char *name)
+{
+#if WASM_ENABLE_INTERP != 0
+    if (module_inst->module_type == Wasm_Module_Bytecode)
+        return wasm_lookup_memory((WASMModuleInstance *)module_inst, name);
+#endif
+
+#if WASM_ENABLE_AOT != 0
+    if (module_inst->module_type == Wasm_Module_AoT)
+        return aot_lookup_memory((WASMModuleInstance *)module_inst, name);
+#endif
+
+    return NULL;
+}
+
+WASMMemoryInstance *
+wasm_runtime_get_default_memory(WASMModuleInstanceCommon *module_inst)
+{
+#if WASM_ENABLE_INTERP != 0
+    if (module_inst->module_type == Wasm_Module_Bytecode)
+        return wasm_get_default_memory((WASMModuleInstance *)module_inst);
+#endif
+
+#if WASM_ENABLE_AOT != 0
+    if (module_inst->module_type == Wasm_Module_AoT)
+        return aot_get_default_memory((AOTModuleInstance *)module_inst);
+#endif
+
+    return NULL;
+}
+
+WASMMemoryInstance *
+wasm_runtime_get_memory(WASMModuleInstanceCommon *module_inst, uint32 index)
+{
+#if WASM_ENABLE_INTERP != 0
+    if (module_inst->module_type == Wasm_Module_Bytecode)
+        return wasm_get_memory_with_idx((WASMModuleInstance *)module_inst,
+                                        index);
+#endif
+
+#if WASM_ENABLE_AOT != 0
+    if (module_inst->module_type == Wasm_Module_AoT)
+        return aot_get_memory_with_index((AOTModuleInstance *)module_inst,
+                                         index);
+#endif
+
+    return NULL;
+}
+
+uint64
+wasm_memory_get_cur_page_count(WASMMemoryInstance *memory)
+{
+    return memory->cur_page_count;
+}
+
+uint64
+wasm_memory_get_max_page_count(WASMMemoryInstance *memory)
+{
+    return memory->max_page_count;
+}
+
+uint64
+wasm_memory_get_bytes_per_page(WASMMemoryInstance *memory)
+{
+    return memory->num_bytes_per_page;
+}
+
+bool
+wasm_memory_get_shared(WASMMemoryInstance *memory)
+{
+    return memory->is_shared_memory;
+}
+
+void *
+wasm_memory_get_base_address(WASMMemoryInstance *memory)
+{
+    return memory->memory_data;
+}
+
+bool
+wasm_memory_enlarge(WASMMemoryInstance *memory, uint64 inc_page_count)
+{
+    bool ret = false;
+
+    if (memory) {
+#if WASM_ENABLE_SHARED_MEMORY != 0
+        shared_memory_lock(memory);
+#endif
+        ret =
+            wasm_enlarge_memory_internal(NULL, memory, (uint32)inc_page_count);
+#if WASM_ENABLE_SHARED_MEMORY != 0
+        shared_memory_unlock(memory);
+#endif
+    }
 
     return ret;
 }

+ 31 - 2
core/iwasm/common/wasm_memory.h

@@ -41,15 +41,44 @@ SET_LINEAR_MEMORY_SIZE(WASMMemoryInstance *memory, uint64 size)
 #define SET_LINEAR_MEMORY_SIZE(memory, size) memory->memory_data_size = size
 #endif
 
+#if WASM_ENABLE_SHARED_HEAP != 0
+WASMSharedHeap *
+wasm_runtime_create_shared_heap(SharedHeapInitArgs *init_args);
+
+bool
+wasm_runtime_attach_shared_heap(WASMModuleInstanceCommon *module_inst,
+                                WASMSharedHeap *shared_heap);
+bool
+wasm_runtime_attach_shared_heap_internal(WASMModuleInstanceCommon *module_inst,
+                                         WASMSharedHeap *shared_heap);
+
+void
+wasm_runtime_detach_shared_heap(WASMModuleInstanceCommon *module_inst);
+
+void
+wasm_runtime_detach_shared_heap_internal(WASMModuleInstanceCommon *module_inst);
+
+WASMSharedHeap *
+wasm_runtime_get_shared_heap(WASMModuleInstanceCommon *module_inst_comm);
+
+uint64
+wasm_runtime_shared_heap_malloc(WASMModuleInstanceCommon *module_inst,
+                                uint64 size, void **p_native_addr);
+
+void
+wasm_runtime_shared_heap_free(WASMModuleInstanceCommon *module_inst,
+                              uint64 ptr);
+#endif
+
 bool
 wasm_runtime_memory_init(mem_alloc_type_t mem_alloc_type,
                          const MemAllocOption *alloc_option);
 
 void
-wasm_runtime_memory_destroy();
+wasm_runtime_memory_destroy(void);
 
 unsigned
-wasm_runtime_memory_pool_size();
+wasm_runtime_memory_pool_size(void);
 
 void
 wasm_runtime_set_mem_bound_check_bytes(WASMMemoryInstance *memory,

+ 15 - 2
core/iwasm/common/wasm_native.c

@@ -33,6 +33,11 @@ uint32
 get_spectest_export_apis(NativeSymbol **p_libc_builtin_apis);
 #endif
 
+#if WASM_ENABLE_SHARED_HEAP != 0
+uint32
+get_lib_shared_heap_export_apis(NativeSymbol **p_shared_heap_apis);
+#endif
+
 uint32
 get_libc_wasi_export_apis(NativeSymbol **p_libc_wasi_apis);
 
@@ -469,7 +474,7 @@ wasi_context_dtor(WASMModuleInstanceCommon *inst, void *ctx)
 
 #if WASM_ENABLE_QUICK_AOT_ENTRY != 0
 static bool
-quick_aot_entry_init();
+quick_aot_entry_init(void);
 #endif
 
 bool
@@ -512,6 +517,14 @@ wasm_native_init()
         goto fail;
 #endif
 
+#if WASM_ENABLE_SHARED_HEAP != 0
+    n_native_symbols = get_lib_shared_heap_export_apis(&native_symbols);
+    if (n_native_symbols > 0
+        && !wasm_native_register_natives("env", native_symbols,
+                                         n_native_symbols))
+        goto fail;
+#endif
+
 #if WASM_ENABLE_BASE_LIB != 0
     n_native_symbols = get_base_lib_export_apis(&native_symbols);
     if (n_native_symbols > 0
@@ -1461,7 +1474,7 @@ quick_aot_entry_cmp(const void *quick_aot_entry1, const void *quick_aot_entry2)
 }
 
 static bool
-quick_aot_entry_init()
+quick_aot_entry_init(void)
 {
     qsort(quick_aot_entries, sizeof(quick_aot_entries) / sizeof(QuickAOTEntry),
           sizeof(QuickAOTEntry), quick_aot_entry_cmp);

+ 2 - 2
core/iwasm/common/wasm_native.h

@@ -100,10 +100,10 @@ wasm_native_inherit_contexts(struct WASMModuleInstanceCommon *child,
 #endif /* WASM_ENABLE_MODULE_INST_CONTEXT */
 
 bool
-wasm_native_init();
+wasm_native_init(void);
 
 void
-wasm_native_destroy();
+wasm_native_destroy(void);
 
 #if WASM_ENABLE_QUICK_AOT_ENTRY != 0
 void *

+ 93 - 54
core/iwasm/common/wasm_runtime_common.c

@@ -86,7 +86,7 @@ static bh_list registered_module_list_head;
 static bh_list *const registered_module_list = &registered_module_list_head;
 static korp_mutex registered_module_list_lock;
 static void
-wasm_runtime_destroy_registered_module_list();
+wasm_runtime_destroy_registered_module_list(void);
 #endif /* WASM_ENABLE_MULTI_MODULE */
 
 #define E_TYPE_XIP 4
@@ -97,11 +97,11 @@ val_type_to_val_kind(uint8 value_type);
 #if WASM_ENABLE_GC == 0 && WASM_ENABLE_REF_TYPES != 0
 /* Initialize externref hashmap */
 static bool
-wasm_externref_map_init();
+wasm_externref_map_init(void);
 
 /* Destroy externref hashmap */
 static void
-wasm_externref_map_destroy();
+wasm_externref_map_destroy(void);
 #endif /* end of WASM_ENABLE_GC == 0 && WASM_ENABLE_REF_TYPES != 0 */
 
 static void
@@ -185,6 +185,9 @@ static bool
 is_sig_addr_in_guard_pages(void *sig_addr, WASMModuleInstance *module_inst)
 {
     WASMMemoryInstance *memory_inst;
+#if WASM_ENABLE_SHARED_HEAP != 0
+    WASMSharedHeap *shared_heap;
+#endif
     uint8 *mapped_mem_start_addr = NULL;
     uint8 *mapped_mem_end_addr = NULL;
     uint32 i;
@@ -202,6 +205,21 @@ is_sig_addr_in_guard_pages(void *sig_addr, WASMModuleInstance *module_inst)
         }
     }
 
+#if WASM_ENABLE_SHARED_HEAP != 0
+    shared_heap =
+        wasm_runtime_get_shared_heap((WASMModuleInstanceCommon *)module_inst);
+    if (shared_heap) {
+        mapped_mem_start_addr = shared_heap->base_addr;
+        mapped_mem_end_addr = shared_heap->base_addr + 8 * (uint64)BH_GB;
+        if (mapped_mem_start_addr <= (uint8 *)sig_addr
+            && (uint8 *)sig_addr < mapped_mem_end_addr) {
+            /* The address which causes segmentation fault is inside
+               the shared heap's guard regions */
+            return true;
+        }
+    }
+#endif
+
     return false;
 }
 
@@ -340,7 +358,6 @@ runtime_exception_handler(EXCEPTION_POINTERS *exce_info)
     PEXCEPTION_RECORD ExceptionRecord = exce_info->ExceptionRecord;
     uint8 *sig_addr = (uint8 *)ExceptionRecord->ExceptionInformation[1];
     WASMModuleInstance *module_inst;
-    WASMMemoryInstance *memory_inst;
     WASMJmpBuf *jmpbuf_node;
     uint8 *mapped_mem_start_addr = NULL;
     uint8 *mapped_mem_end_addr = NULL;
@@ -438,7 +455,7 @@ wasm_runtime_get_exec_env_tls()
 #endif /* end of OS_ENABLE_HW_BOUND_CHECK */
 
 static bool
-wasm_runtime_env_init()
+wasm_runtime_env_init(void)
 {
     if (bh_platform_init() != 0)
         return false;
@@ -584,7 +601,7 @@ static korp_mutex runtime_lock = OS_THREAD_MUTEX_INITIALIZER;
 static int32 runtime_ref_count = 0;
 
 static bool
-wasm_runtime_init_internal()
+wasm_runtime_init_internal(void)
 {
     if (!wasm_runtime_memory_init(Alloc_With_System_Allocator, NULL))
         return false;
@@ -622,7 +639,7 @@ wasm_runtime_init()
 }
 
 static void
-wasm_runtime_destroy_internal()
+wasm_runtime_destroy_internal(void)
 {
 #if WASM_ENABLE_GC == 0 && WASM_ENABLE_REF_TYPES != 0
     wasm_externref_map_destroy();
@@ -1484,6 +1501,22 @@ wasm_runtime_load_ex(uint8 *buf, uint32 size, const LoadArgs *args,
                                           error_buf_size);
 }
 
+WASM_RUNTIME_API_EXTERN bool
+wasm_runtime_resolve_symbols(WASMModuleCommon *module)
+{
+#if WASM_ENABLE_INTERP != 0
+    if (module->module_type == Wasm_Module_Bytecode) {
+        return wasm_resolve_symbols((WASMModule *)module);
+    }
+#endif
+#if WASM_ENABLE_AOT != 0
+    if (module->module_type == Wasm_Module_AoT) {
+        return aot_resolve_symbols((AOTModule *)module);
+    }
+#endif
+    return false;
+}
+
 WASMModuleCommon *
 wasm_runtime_load(uint8 *buf, uint32 size, char *error_buf,
                   uint32 error_buf_size)
@@ -2192,6 +2225,13 @@ wasm_runtime_get_user_data(WASMExecEnv *exec_env)
     return exec_env->user_data;
 }
 
+void
+wasm_runtime_set_native_stack_boundary(WASMExecEnv *exec_env,
+                                       uint8 *native_stack_boundary)
+{
+    exec_env->user_native_stack_boundary = native_stack_boundary;
+}
+
 #ifdef OS_ENABLE_HW_BOUND_CHECK
 void
 wasm_runtime_access_exce_check_guard_page()
@@ -3577,7 +3617,8 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst,
         char mapping_copy_buf[256];
         char *mapping_copy = mapping_copy_buf;
         char *map_mapped = NULL, *map_host = NULL;
-        const unsigned long max_len = strlen(map_dir_list[i]) * 2 + 3;
+        const unsigned long max_len =
+            (unsigned long)strlen(map_dir_list[i]) * 2 + 3;
 
         /* Allocation limit for runtime environments with reduced stack size */
         if (max_len > 256) {
@@ -3867,23 +3908,18 @@ wasm_runtime_is_wasi_mode(WASMModuleInstanceCommon *module_inst)
 WASMFunctionInstanceCommon *
 wasm_runtime_lookup_wasi_start_function(WASMModuleInstanceCommon *module_inst)
 {
-    uint32 i;
-
 #if WASM_ENABLE_INTERP != 0
     if (module_inst->module_type == Wasm_Module_Bytecode) {
         WASMModuleInstance *wasm_inst = (WASMModuleInstance *)module_inst;
-        WASMFunctionInstance *func;
-        for (i = 0; i < wasm_inst->export_func_count; i++) {
-            if (!strcmp(wasm_inst->export_functions[i].name, "_start")) {
-                func = wasm_inst->export_functions[i].function;
-                if (func->u.func->func_type->param_count != 0
-                    || func->u.func->func_type->result_count != 0) {
-                    LOG_ERROR("Lookup wasi _start function failed: "
-                              "invalid function type.\n");
-                    return NULL;
-                }
-                return (WASMFunctionInstanceCommon *)func;
+        WASMFunctionInstance *func = wasm_lookup_function(wasm_inst, "_start");
+        if (func) {
+            if (func->u.func->func_type->param_count != 0
+                || func->u.func->func_type->result_count != 0) {
+                LOG_ERROR("Lookup wasi _start function failed: "
+                          "invalid function type.\n");
+                return NULL;
             }
+            return (WASMFunctionInstanceCommon *)func;
         }
         return NULL;
     }
@@ -3892,19 +3928,15 @@ wasm_runtime_lookup_wasi_start_function(WASMModuleInstanceCommon *module_inst)
 #if WASM_ENABLE_AOT != 0
     if (module_inst->module_type == Wasm_Module_AoT) {
         AOTModuleInstance *aot_inst = (AOTModuleInstance *)module_inst;
-        AOTFunctionInstance *export_funcs =
-            (AOTFunctionInstance *)aot_inst->export_functions;
-        for (i = 0; i < aot_inst->export_func_count; i++) {
-            if (!strcmp(export_funcs[i].func_name, "_start")) {
-                AOTFuncType *func_type = export_funcs[i].u.func.func_type;
-                if (func_type->param_count != 0
-                    || func_type->result_count != 0) {
-                    LOG_ERROR("Lookup wasi _start function failed: "
-                              "invalid function type.\n");
-                    return NULL;
-                }
-                return (WASMFunctionInstanceCommon *)&export_funcs[i];
+        AOTFunctionInstance *func = aot_lookup_function(aot_inst, "_start");
+        if (func) {
+            AOTFuncType *func_type = func->u.func.func_type;
+            if (func_type->param_count != 0 || func_type->result_count != 0) {
+                LOG_ERROR("Lookup wasi _start function failed: "
+                          "invalid function type.\n");
+                return NULL;
             }
+            return func;
         }
         return NULL;
     }
@@ -4498,9 +4530,14 @@ wasm_runtime_invoke_native_raw(WASMExecEnv *exec_env, void *func_ptr,
                                uint32 *argv, uint32 argc, uint32 *argv_ret)
 {
     WASMModuleInstanceCommon *module = wasm_runtime_get_module_inst(exec_env);
+#if WASM_ENABLE_MEMORY64 != 0
+    WASMMemoryInstance *memory =
+        wasm_get_default_memory((WASMModuleInstance *)module);
+    bool is_memory64 = memory ? memory->is_memory64 : false;
+#endif
     typedef void (*NativeRawFuncPtr)(WASMExecEnv *, uint64 *);
     NativeRawFuncPtr invoke_native_raw = (NativeRawFuncPtr)func_ptr;
-    uint64 argv_buf[16] = { 0 }, *argv1 = argv_buf, *argv_dst, size, arg_i64;
+    uint64 argv_buf[16] = { 0 }, *argv1 = argv_buf, *argv_dst, size;
     uint32 *argv_src = argv, i, argc1, ptr_len;
     uint32 arg_i32;
     bool ret = false;
@@ -4525,11 +4562,11 @@ wasm_runtime_invoke_native_raw(WASMExecEnv *exec_env, void *func_ptr,
 #endif
             {
                 *(uint32 *)argv_dst = arg_i32 = *argv_src++;
-                /* TODO: memory64 if future there is a way for supporting
-                 * wasm64 and wasm32 in libc at the same time, remove the
-                 * macro control */
-#if WASM_ENABLE_MEMORY64 == 0
-                if (signature) {
+                if (signature
+#if WASM_ENABLE_MEMORY64 != 0
+                    && !is_memory64
+#endif
+                ) {
                     if (signature[i + 1] == '*') {
                         /* param is a pointer */
                         if (signature[i + 2] == '~')
@@ -4558,17 +4595,18 @@ wasm_runtime_invoke_native_raw(WASMExecEnv *exec_env, void *func_ptr,
                                 module, (uint64)arg_i32);
                     }
                 }
-#endif
                 break;
             }
             case VALUE_TYPE_I64:
 #if WASM_ENABLE_MEMORY64 != 0
             {
+                uint64 arg_i64;
+
                 PUT_I64_TO_ADDR((uint32 *)argv_dst,
                                 GET_I64_FROM_ADDR(argv_src));
                 argv_src += 2;
                 arg_i64 = *argv_dst;
-                if (signature) {
+                if (signature && is_memory64) {
                     /* TODO: memory64 pointer with length need a new symbol
                      * to represent type i64, with '~' still represent i32
                      * length */
@@ -4729,9 +4767,6 @@ wasm_runtime_invoke_native_raw(WASMExecEnv *exec_env, void *func_ptr,
 fail:
     if (argv1 != argv_buf)
         wasm_runtime_free(argv1);
-#if WASM_ENABLE_MEMORY64 == 0
-    (void)arg_i64;
-#endif
     return ret;
 }
 
@@ -4747,7 +4782,7 @@ fail:
     || defined(BUILD_TARGET_RISCV32_ILP32D)                          \
     || defined(BUILD_TARGET_RISCV32_ILP32F)                          \
     || defined(BUILD_TARGET_RISCV32_ILP32) || defined(BUILD_TARGET_ARC)
-typedef void (*GenericFunctionPointer)();
+typedef void (*GenericFunctionPointer)(void);
 void
 invokeNative(GenericFunctionPointer f, uint32 *args, uint32 n_stacks);
 
@@ -5312,7 +5347,7 @@ fail:
 #if defined(BUILD_TARGET_X86_32) || defined(BUILD_TARGET_ARM)    \
     || defined(BUILD_TARGET_THUMB) || defined(BUILD_TARGET_MIPS) \
     || defined(BUILD_TARGET_XTENSA)
-typedef void (*GenericFunctionPointer)();
+typedef void (*GenericFunctionPointer)(void);
 void
 invokeNative(GenericFunctionPointer f, uint32 *args, uint32 sz);
 
@@ -5597,7 +5632,7 @@ typedef uint32x4_t __m128i;
 
 #endif /* end of WASM_ENABLE_SIMD != 0 */
 
-typedef void (*GenericFunctionPointer)();
+typedef void (*GenericFunctionPointer)(void);
 void
 invokeNative(GenericFunctionPointer f, uint64 *args, uint64 n_stacks);
 
@@ -5655,6 +5690,11 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr,
                            uint32 *argv_ret)
 {
     WASMModuleInstanceCommon *module = wasm_runtime_get_module_inst(exec_env);
+#if WASM_ENABLE_MEMORY64 != 0
+    WASMMemoryInstance *memory =
+        wasm_get_default_memory((WASMModuleInstance *)module);
+    bool is_memory64 = memory ? memory->is_memory64 : false;
+#endif
     uint64 argv_buf[32] = { 0 }, *argv1 = argv_buf, *ints, *stacks, size,
            arg_i64;
     uint32 *argv_src = argv, i, argc1, n_ints = 0, n_stacks = 0;
@@ -5720,11 +5760,11 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr,
             {
                 arg_i32 = *argv_src++;
                 arg_i64 = arg_i32;
-                /* TODO: memory64 if future there is a way for supporting
-                 * wasm64 and wasm32 in libc at the same time, remove the
-                 * macro control */
-#if WASM_ENABLE_MEMORY64 == 0
-                if (signature) {
+                if (signature
+#if WASM_ENABLE_MEMORY64 != 0
+                    && !is_memory64
+#endif
+                ) {
                     if (signature[i + 1] == '*') {
                         /* param is a pointer */
                         if (signature[i + 2] == '~')
@@ -5751,7 +5791,6 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr,
                             module, (uint64)arg_i32);
                     }
                 }
-#endif
                 if (n_ints < MAX_REG_INTS)
                     ints[n_ints++] = arg_i64;
                 else
@@ -5763,7 +5802,7 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr,
             {
                 arg_i64 = GET_I64_FROM_ADDR(argv_src);
                 argv_src += 2;
-                if (signature) {
+                if (signature && is_memory64) {
                     /* TODO: memory64 pointer with length need a new symbol
                      * to represent type i64, with '~' still represent i32
                      * length */

+ 9 - 4
core/iwasm/common/wasm_runtime_common.h

@@ -673,6 +673,11 @@ wasm_runtime_set_user_data(WASMExecEnv *exec_env, void *user_data);
 WASM_RUNTIME_API_EXTERN void *
 wasm_runtime_get_user_data(WASMExecEnv *exec_env);
 
+/* See wasm_export.h for description */
+WASM_RUNTIME_API_EXTERN void
+wasm_runtime_set_native_stack_boundary(WASMExecEnv *exec_env,
+                                       uint8 *native_stack_boundary);
+
 #if WASM_CONFIGURABLE_BOUNDS_CHECKS != 0
 /* See wasm_export.h for description */
 WASM_RUNTIME_API_EXTERN void
@@ -852,10 +857,10 @@ wasm_runtime_set_module_reader(const module_reader reader,
                                const module_destroyer destroyer);
 
 module_reader
-wasm_runtime_get_module_reader();
+wasm_runtime_get_module_reader(void);
 
 module_destroyer
-wasm_runtime_get_module_destroyer();
+wasm_runtime_get_module_destroyer(void);
 
 bool
 wasm_runtime_register_module_internal(const char *module_name,
@@ -881,7 +886,7 @@ bool
 wasm_runtime_is_loading_module(const char *module_name);
 
 void
-wasm_runtime_destroy_loading_module_list();
+wasm_runtime_destroy_loading_module_list(void);
 
 WASMModuleCommon *
 wasm_runtime_search_sub_module(const WASMModuleCommon *parent_module,
@@ -1168,7 +1173,7 @@ wasm_runtime_quick_invoke_c_api_native(WASMModuleInstanceCommon *module_inst,
                                        uint32 result_count);
 
 void
-wasm_runtime_show_app_heap_corrupted_prompt();
+wasm_runtime_show_app_heap_corrupted_prompt(void);
 
 #if WASM_ENABLE_LOAD_CUSTOM_SECTION != 0
 void

+ 44 - 3
core/iwasm/common/wasm_shared_memory.c

@@ -8,6 +8,9 @@
 #if WASM_ENABLE_THREAD_MGR != 0
 #include "../libraries/thread-mgr/thread_manager.h"
 #endif
+#if WASM_ENABLE_AOT != 0
+#include "../aot/aot_runtime.h"
+#endif
 
 /*
  * Note: this lock can be per memory.
@@ -243,6 +246,31 @@ map_try_release_wait_info(HashMap *wait_hash_map, AtomicWaitInfo *wait_info,
     destroy_wait_info(wait_info);
 }
 
+#if WASM_ENABLE_SHARED_HEAP != 0
+static bool
+is_native_addr_in_shared_heap(WASMModuleInstanceCommon *module_inst,
+                              uint8 *addr, uint32 bytes)
+{
+    WASMSharedHeap *shared_heap = NULL;
+
+#if WASM_ENABLE_INTERP != 0
+    if (module_inst->module_type == Wasm_Module_Bytecode) {
+        shared_heap = ((WASMModuleInstance *)module_inst)->e->shared_heap;
+    }
+#endif
+#if WASM_ENABLE_AOT != 0
+    if (module_inst->module_type == Wasm_Module_AoT) {
+        AOTModuleInstanceExtra *e =
+            (AOTModuleInstanceExtra *)((AOTModuleInstance *)module_inst)->e;
+        shared_heap = e->shared_heap;
+    }
+#endif
+
+    return shared_heap && addr >= shared_heap->base_addr
+           && addr + bytes <= shared_heap->base_addr + shared_heap->size;
+}
+#endif
+
 uint32
 wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address,
                          uint64 expect, int64 timeout, bool wait64)
@@ -271,9 +299,17 @@ wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address,
     }
 
     shared_memory_lock(module_inst->memories[0]);
-    if ((uint8 *)address < module_inst->memories[0]->memory_data
-        || (uint8 *)address + (wait64 ? 8 : 4)
-               > module_inst->memories[0]->memory_data_end) {
+    if (
+#if WASM_ENABLE_SHARED_HEAP != 0
+        /* not in shared heap */
+        !is_native_addr_in_shared_heap((WASMModuleInstanceCommon *)module_inst,
+                                       address, wait64 ? 8 : 4)
+        &&
+#endif
+        /* and not in linear memory */
+        ((uint8 *)address < module_inst->memories[0]->memory_data
+         || (uint8 *)address + (wait64 ? 8 : 4)
+                > module_inst->memories[0]->memory_data_end)) {
         shared_memory_unlock(module_inst->memories[0]);
         wasm_runtime_set_exception(module, "out of bounds memory access");
         return -1;
@@ -397,6 +433,11 @@ wasm_runtime_atomic_notify(WASMModuleInstanceCommon *module, void *address,
 
     shared_memory_lock(module_inst->memories[0]);
     out_of_bounds =
+#if WASM_ENABLE_SHARED_HEAP != 0
+        /* not in shared heap */
+        !is_native_addr_in_shared_heap(module, address, 4) &&
+#endif
+        /* and not in linear memory */
         ((uint8 *)address < module_inst->memories[0]->memory_data
          || (uint8 *)address + 4 > module_inst->memories[0]->memory_data_end);
     shared_memory_unlock(module_inst->memories[0]);

+ 2 - 2
core/iwasm/common/wasm_shared_memory.h

@@ -17,10 +17,10 @@ extern "C" {
 extern korp_mutex g_shared_memory_lock;
 
 bool
-wasm_shared_memory_init();
+wasm_shared_memory_init(void);
 
 void
-wasm_shared_memory_destroy();
+wasm_shared_memory_destroy(void);
 
 uint16
 shared_memory_inc_reference(WASMMemoryInstance *memory);

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

@@ -312,7 +312,7 @@ void
 aot_destroy_comp_data(AOTCompData *comp_data);
 
 char *
-aot_get_last_error();
+aot_get_last_error(void);
 
 void
 aot_set_last_error(const char *error);

+ 105 - 34
core/iwasm/compilation/aot_compiler.c

@@ -16,6 +16,7 @@
 #include "aot_emit_parametric.h"
 #include "aot_emit_table.h"
 #include "aot_emit_gc.h"
+#include "aot_stack_frame_comp.h"
 #include "simd/simd_access_lanes.h"
 #include "simd/simd_bitmask_extracts.h"
 #include "simd/simd_bit_shifts.h"
@@ -145,9 +146,20 @@ aot_validate_wasm(AOTCompContext *comp_ctx)
     }
 
 #if WASM_ENABLE_MEMORY64 != 0
-    if (comp_ctx->pointer_size < sizeof(uint64) && IS_MEMORY64) {
-        aot_set_last_error("Compiling wasm64 to 32bit platform is not allowed");
-        return false;
+    if (comp_ctx->pointer_size < sizeof(uint64)) {
+        if (IS_MEMORY64) {
+            aot_set_last_error("Compiling wasm64(contains i64 memory section) "
+                               "to 32bit platform is not allowed");
+            return false;
+        }
+
+        for (uint32 i = 0; i < comp_ctx->comp_data->table_count; ++i) {
+            if (IS_TABLE64(i)) {
+                aot_set_last_error("Compiling wasm64(contains i64 table "
+                                   "section) to 32bit platform is not allowed");
+                return false;
+            }
+        }
     }
 #endif
 
@@ -253,6 +265,13 @@ store_value(AOTCompContext *comp_ctx, LLVMValueRef value, uint8 value_type,
     return true;
 }
 
+void
+aot_call_stack_features_init_default(AOTCallStackFeatures *features)
+{
+    memset(features, 1, sizeof(AOTCallStackFeatures));
+    features->frame_per_function = false;
+}
+
 bool
 aot_frame_store_value(AOTCompContext *comp_ctx, LLVMValueRef value,
                       uint8 value_type, LLVMValueRef cur_frame, uint32 offset)
@@ -337,6 +356,10 @@ aot_gen_commit_values(AOTCompFrame *frame)
     LLVMValueRef value;
     uint32 n;
 
+    if (!frame->comp_ctx->call_stack_features.values) {
+        return true;
+    }
+
     /* First, commit reference flags
      * For LLVM JIT, iterate all local and stack ref flags
      * For AOT, ignore local(params + locals) ref flags */
@@ -569,6 +592,64 @@ aot_gen_commit_values(AOTCompFrame *frame)
     return true;
 }
 
+static bool
+aot_standard_frame_gen_commit_ip(AOTCompContext *comp_ctx,
+                                 AOTFuncContext *func_ctx,
+                                 LLVMValueRef ip_value, bool is_64bit)
+{
+    LLVMValueRef cur_frame = func_ctx->cur_frame;
+    LLVMValueRef value_offset, value_addr, value_ptr;
+    uint32 offset_ip;
+
+    if (!comp_ctx->is_jit_mode)
+        offset_ip = comp_ctx->pointer_size * 4;
+    else
+        offset_ip = offsetof(WASMInterpFrame, ip);
+
+    if (!(value_offset = I32_CONST(offset_ip))) {
+        aot_set_last_error("llvm build const failed");
+        return false;
+    }
+
+    if (!(value_addr =
+              LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE, cur_frame,
+                                    &value_offset, 1, "ip_addr"))) {
+        aot_set_last_error("llvm build in bounds gep failed");
+        return false;
+    }
+
+    if (!(value_ptr = LLVMBuildBitCast(
+              comp_ctx->builder, value_addr,
+              is_64bit ? INT64_PTR_TYPE : INT32_PTR_TYPE, "ip_ptr"))) {
+        aot_set_last_error("llvm build bit cast failed");
+        return false;
+    }
+
+    if (!LLVMBuildStore(comp_ctx->builder, ip_value, value_ptr)) {
+        aot_set_last_error("llvm build store failed");
+        return false;
+    }
+
+    return true;
+}
+
+bool
+aot_gen_commit_ip(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
+                  LLVMValueRef ip_value, bool is_64bit)
+{
+    switch (comp_ctx->aux_stack_frame_type) {
+        case AOT_STACK_FRAME_TYPE_STANDARD:
+            return aot_standard_frame_gen_commit_ip(comp_ctx, func_ctx,
+                                                    ip_value, is_64bit);
+        case AOT_STACK_FRAME_TYPE_TINY:
+            return aot_tiny_frame_gen_commit_ip(comp_ctx, func_ctx, ip_value);
+        default:
+            aot_set_last_error(
+                "unsupported mode when generating commit_ip code");
+            return false;
+    }
+}
+
 bool
 aot_gen_commit_sp_ip(AOTCompFrame *frame, bool commit_sp, bool commit_ip)
 {
@@ -577,40 +658,19 @@ aot_gen_commit_sp_ip(AOTCompFrame *frame, bool commit_sp, bool commit_ip)
     LLVMValueRef cur_frame = func_ctx->cur_frame;
     LLVMValueRef value_offset, value_addr, value_ptr, value;
     LLVMTypeRef int8_ptr_ptr_type;
-    uint32 offset_ip, offset_sp, n;
+    uint32 offset_sp, n;
     bool is_64bit = (comp_ctx->pointer_size == sizeof(uint64)) ? true : false;
     const AOTValueSlot *sp = frame->sp;
     const uint8 *ip = frame->frame_ip;
 
     if (!comp_ctx->is_jit_mode) {
-        offset_ip = frame->comp_ctx->pointer_size * 4;
         offset_sp = frame->comp_ctx->pointer_size * 5;
     }
     else {
-        offset_ip = offsetof(WASMInterpFrame, ip);
         offset_sp = offsetof(WASMInterpFrame, sp);
     }
 
-    if (commit_ip) {
-        if (!(value_offset = I32_CONST(offset_ip))) {
-            aot_set_last_error("llvm build const failed");
-            return false;
-        }
-
-        if (!(value_addr =
-                  LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE, cur_frame,
-                                        &value_offset, 1, "ip_addr"))) {
-            aot_set_last_error("llvm build in bounds gep failed");
-            return false;
-        }
-
-        if (!(value_ptr = LLVMBuildBitCast(
-                  comp_ctx->builder, value_addr,
-                  is_64bit ? INT64_PTR_TYPE : INT32_PTR_TYPE, "ip_ptr"))) {
-            aot_set_last_error("llvm build bit cast failed");
-            return false;
-        }
-
+    if (commit_ip && comp_ctx->call_stack_features.ip) {
         if (!comp_ctx->is_jit_mode) {
             WASMModule *module = comp_ctx->comp_data->wasm_module;
             if (is_64bit)
@@ -630,13 +690,12 @@ aot_gen_commit_sp_ip(AOTCompFrame *frame, bool commit_sp, bool commit_ip)
             return false;
         }
 
-        if (!LLVMBuildStore(comp_ctx->builder, value, value_ptr)) {
-            aot_set_last_error("llvm build store failed");
+        if (!aot_gen_commit_ip(comp_ctx, func_ctx, value, is_64bit)) {
             return false;
         }
     }
 
-    if (commit_sp) {
+    if (commit_sp && comp_ctx->call_stack_features.values) {
         n = (uint32)(sp - frame->lp);
         value = I32_CONST(offset_of_local(comp_ctx, n));
         if (!value) {
@@ -940,6 +999,7 @@ static bool
 aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
 {
     AOTFuncContext *func_ctx = comp_ctx->func_ctxes[func_index];
+    LLVMValueRef func_index_ref;
     uint8 *frame_ip = func_ctx->aot_func->code, opcode, *p_f32, *p_f64;
     uint8 *frame_ip_end = frame_ip + func_ctx->aot_func->code_size;
     uint8 *param_types = NULL;
@@ -962,16 +1022,27 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
     LLVMMetadataRef location;
 #endif
 
-    if (comp_ctx->enable_aux_stack_frame) {
+    /* Start to translate the opcodes */
+    LLVMPositionBuilderAtEnd(
+        comp_ctx->builder,
+        func_ctx->block_stack.block_list_head->llvm_entry_block);
+
+    if (comp_ctx->aux_stack_frame_type
+        && comp_ctx->call_stack_features.frame_per_function) {
+        INT_CONST(func_index_ref,
+                  func_index + comp_ctx->comp_data->import_func_count, I32_TYPE,
+                  true);
+        if (!aot_alloc_frame_per_function_frame_for_aot_func(comp_ctx, func_ctx,
+                                                             func_index_ref)) {
+            return false;
+        }
+    }
+    if (comp_ctx->aux_stack_frame_type) {
         if (!init_comp_frame(comp_ctx, func_ctx, func_index)) {
             return false;
         }
     }
 
-    /* Start to translate the opcodes */
-    LLVMPositionBuilderAtEnd(
-        comp_ctx->builder,
-        func_ctx->block_stack.block_list_head->llvm_entry_block);
     while (frame_ip < frame_ip_end) {
         opcode = *frame_ip++;
 

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

@@ -195,6 +195,15 @@ aot_gen_commit_values(AOTCompFrame *frame);
 bool
 aot_gen_commit_sp_ip(AOTCompFrame *frame, bool commit_sp, bool commit_ip);
 
+/**
+ * Generate instructions to commit IP pointer to the frame.
+ *
+ * @param frame the frame information
+ */
+bool
+aot_gen_commit_ip(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
+                  LLVMValueRef ip_value, bool is_64bit);
+
 bool
 aot_frame_store_value(AOTCompContext *comp_ctx, LLVMValueRef value,
                       uint8 value_type, LLVMValueRef cur_frame, uint32 offset);
@@ -523,8 +532,13 @@ set_local_gc_ref(AOTCompFrame *frame, int n, LLVMValueRef value, uint8 ref_type)
 #define IS_MEMORY64 (comp_ctx->comp_data->memories[0].flags & MEMORY64_FLAG)
 #define MEMORY64_COND_VALUE(VAL_IF_ENABLED, VAL_IF_DISABLED) \
     (IS_MEMORY64 ? VAL_IF_ENABLED : VAL_IF_DISABLED)
+#define IS_TABLE64(i) \
+    (comp_ctx->comp_data->tables[i].table_type.flags & TABLE64_FLAG)
+#define TABLE64_COND_VALUE(i, VAL_IF_ENABLED, VAL_IF_DISABLED) \
+    (IS_TABLE64(i) ? VAL_IF_ENABLED : VAL_IF_DISABLED)
 #else
 #define MEMORY64_COND_VALUE(VAL_IF_ENABLED, VAL_IF_DISABLED) (VAL_IF_DISABLED)
+#define TABLE64_COND_VALUE(i, VAL_IF_ENABLED, VAL_IF_DISABLED) (VAL_IF_DISABLED)
 #endif
 
 #define POP_I32(v) POP(v, VALUE_TYPE_I32)
@@ -539,6 +553,9 @@ set_local_gc_ref(AOTCompFrame *frame, int n, LLVMValueRef value, uint8 ref_type)
     POP(v, MEMORY64_COND_VALUE(VALUE_TYPE_I64, VALUE_TYPE_I32))
 #define POP_PAGE_COUNT(v) \
     POP(v, MEMORY64_COND_VALUE(VALUE_TYPE_I64, VALUE_TYPE_I32))
+#define POP_TBL_ELEM_IDX(v) \
+    POP(v, TABLE64_COND_VALUE(tbl_idx, VALUE_TYPE_I64, VALUE_TYPE_I32))
+#define POP_TBL_ELEM_LEN(v) POP_TBL_ELEM_IDX(v)
 
 #define POP_COND(llvm_value)                                                   \
     do {                                                                       \
@@ -604,6 +621,9 @@ set_local_gc_ref(AOTCompFrame *frame, int n, LLVMValueRef value, uint8 ref_type)
 #define PUSH_GC_REF(v) PUSH(v, VALUE_TYPE_GC_REF)
 #define PUSH_PAGE_COUNT(v) \
     PUSH(v, MEMORY64_COND_VALUE(VALUE_TYPE_I64, VALUE_TYPE_I32))
+#define PUSH_TBL_ELEM_IDX(v) \
+    PUSH(v, TABLE64_COND_VALUE(tbl_idx, VALUE_TYPE_I64, VALUE_TYPE_I32))
+#define PUSH_TBL_ELEM_LEN(v) PUSH_TBL_ELEM_IDX(v)
 
 #define SET_CONST(v)                                                          \
     do {                                                                      \
@@ -652,6 +672,15 @@ set_local_gc_ref(AOTCompFrame *frame, int n, LLVMValueRef value, uint8 ref_type)
 #define F64_CONST(v) LLVMConstReal(F64_TYPE, v)
 #define I8_CONST(v) LLVMConstInt(INT8_TYPE, v, true)
 
+#define INT_CONST(variable, value, type, is_signed)        \
+    do {                                                   \
+        variable = LLVMConstInt(type, value, is_signed);   \
+        if (!variable) {                                   \
+            aot_set_last_error("llvm build const failed"); \
+            return false;                                  \
+        }                                                  \
+    } while (0)
+
 #define LLVM_CONST(name) (comp_ctx->llvm_consts.name)
 #define I1_ZERO LLVM_CONST(i1_zero)
 #define I1_ONE LLVM_CONST(i1_one)

+ 9 - 0
core/iwasm/compilation/aot_emit_aot_file.c

@@ -4433,6 +4433,15 @@ aot_obj_data_create(AOTCompContext *comp_ctx)
     if (comp_ctx->enable_gc) {
         obj_data->target_info.feature_flags |= WASM_FEATURE_GARBAGE_COLLECTION;
     }
+    if (comp_ctx->aux_stack_frame_type == AOT_STACK_FRAME_TYPE_TINY) {
+        obj_data->target_info.feature_flags |= WASM_FEATURE_TINY_STACK_FRAME;
+    }
+    if (comp_ctx->call_stack_features.frame_per_function) {
+        obj_data->target_info.feature_flags |= WASM_FEATURE_FRAME_PER_FUNCTION;
+    }
+    if (!comp_ctx->call_stack_features.func_idx) {
+        obj_data->target_info.feature_flags |= WASM_FEATURE_FRAME_NO_FUNC_IDX;
+    }
 
     bh_print_time("Begin to resolve object file info");
 

+ 44 - 8
core/iwasm/compilation/aot_emit_control.c

@@ -6,6 +6,7 @@
 #include "aot_emit_control.h"
 #include "aot_compiler.h"
 #include "aot_emit_exception.h"
+#include "aot_stack_frame_comp.h"
 #if WASM_ENABLE_GC != 0
 #include "aot_emit_gc.h"
 #endif
@@ -38,13 +39,24 @@ format_block_name(char *name, uint32 name_size, uint32 block_index,
         snprintf(name, name_size, "%s", "func_end");
 }
 
-#define CREATE_BLOCK(new_llvm_block, name)                      \
-    do {                                                        \
-        if (!(new_llvm_block = LLVMAppendBasicBlockInContext(   \
-                  comp_ctx->context, func_ctx->func, name))) {  \
-            aot_set_last_error("add LLVM basic block failed."); \
-            goto fail;                                          \
-        }                                                       \
+#define CREATE_BLOCK(new_llvm_block, name)                                   \
+    do {                                                                     \
+        if (!(new_llvm_block = LLVMAppendBasicBlockInContext(                \
+                  comp_ctx->context, func_ctx->func, name))) {               \
+            aot_set_last_error("add LLVM basic block failed.");              \
+            goto fail;                                                       \
+        }                                                                    \
+        if (!strcmp(name, "func_end") && comp_ctx->aux_stack_frame_type      \
+            && comp_ctx->call_stack_features.frame_per_function) {           \
+            LLVMBasicBlockRef cur_block =                                    \
+                LLVMGetInsertBlock(comp_ctx->builder);                       \
+            SET_BUILDER_POS(new_llvm_block);                                 \
+            if (!aot_free_frame_per_function_frame_for_aot_func(comp_ctx,    \
+                                                                func_ctx)) { \
+                goto fail;                                                   \
+            }                                                                \
+            SET_BUILDER_POS(cur_block);                                      \
+        }                                                                    \
     } while (0)
 
 #define CURR_BLOCK() LLVMGetInsertBlock(comp_ctx->builder)
@@ -93,6 +105,11 @@ format_block_name(char *name, uint32 name_size, uint32 block_index,
                 goto fail;                                                  \
             }                                                               \
             SET_BUILDER_POS(block->llvm_end_block);                         \
+            LLVMValueRef first_instr =                                      \
+                get_first_non_phi(block->llvm_end_block);                   \
+            if (first_instr) {                                              \
+                LLVMPositionBuilderBefore(comp_ctx->builder, first_instr);  \
+            }                                                               \
             for (_i = 0; _i < block->result_count; _i++) {                  \
                 if (!(block->result_phis[_i] = LLVMBuildPhi(                \
                           comp_ctx->builder,                                \
@@ -158,6 +175,18 @@ get_target_block(AOTFuncContext *func_ctx, uint32 br_depth)
     return block;
 }
 
+LLVMValueRef
+get_first_non_phi(LLVMBasicBlockRef block)
+{
+    LLVMValueRef instr = LLVMGetFirstInstruction(block);
+
+    while (instr && LLVMIsAPHINode(instr)) {
+        instr = LLVMGetNextInstruction(instr);
+    }
+
+    return instr;
+}
+
 static void
 clear_frame_locals(AOTCompFrame *aot_frame)
 {
@@ -883,7 +912,7 @@ check_suspend_flags(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
         aot_set_last_error("llvm build LOAD failed");
         return false;
     }
-    /* Set terminate_flags memory accecc to volatile, so that the value
+    /* Set terminate_flags memory access to volatile, so that the value
         will always be loaded from memory rather than register */
     LLVMSetVolatile(terminate_flags, true);
 
@@ -1361,6 +1390,13 @@ aot_compile_op_return(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
         (*p_frame_ip - 1) - comp_ctx->comp_data->wasm_module->buf_code);
 #endif
 
+    if (comp_ctx->aux_stack_frame_type
+        && comp_ctx->call_stack_features.frame_per_function
+        && !aot_free_frame_per_function_frame_for_aot_func(comp_ctx,
+                                                           func_ctx)) {
+        return false;
+    }
+
     if (block_func->result_count) {
         /* Store extra result values to function parameters */
         for (i = 0; i < block_func->result_count - 1; i++) {

+ 5 - 44
core/iwasm/compilation/aot_emit_exception.c

@@ -4,49 +4,10 @@
  */
 
 #include "aot_emit_exception.h"
+#include "aot_compiler.h"
 #include "../interpreter/wasm_runtime.h"
 #include "../aot/aot_runtime.h"
 
-static bool
-commit_ip(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
-          LLVMValueRef exce_ip, bool is_64bit)
-{
-    LLVMValueRef cur_frame = func_ctx->cur_frame;
-    LLVMValueRef value_offset, value_addr, value_ptr;
-    uint32 offset_ip;
-
-    if (!comp_ctx->is_jit_mode)
-        offset_ip = comp_ctx->pointer_size * 4;
-    else
-        offset_ip = offsetof(WASMInterpFrame, ip);
-
-    if (!(value_offset = I32_CONST(offset_ip))) {
-        aot_set_last_error("llvm build const failed");
-        return false;
-    }
-
-    if (!(value_addr =
-              LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE, cur_frame,
-                                    &value_offset, 1, "ip_addr"))) {
-        aot_set_last_error("llvm build in bounds gep failed");
-        return false;
-    }
-
-    if (!(value_ptr = LLVMBuildBitCast(
-              comp_ctx->builder, value_addr,
-              is_64bit ? INT64_PTR_TYPE : INT32_PTR_TYPE, "ip_ptr"))) {
-        aot_set_last_error("llvm build bit cast failed");
-        return false;
-    }
-
-    if (!LLVMBuildStore(comp_ctx->builder, exce_ip, value_ptr)) {
-        aot_set_last_error("llvm build store failed");
-        return false;
-    }
-
-    return true;
-}
-
 bool
 aot_emit_exception(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
                    int32 exception_id, bool is_cond_br, LLVMValueRef cond_br_if,
@@ -80,7 +41,7 @@ aot_emit_exception(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
             return false;
         }
 
-        if (comp_ctx->aot_frame) {
+        if (comp_ctx->aot_frame && comp_ctx->call_stack_features.trap_ip) {
             /* Create exception ip phi */
             if (!(func_ctx->exception_ip_phi = LLVMBuildPhi(
                       comp_ctx->builder, is_64bit ? I64_TYPE : I32_TYPE,
@@ -90,8 +51,8 @@ aot_emit_exception(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
             }
 
             /* Commit ip to current frame */
-            if (!commit_ip(comp_ctx, func_ctx, func_ctx->exception_ip_phi,
-                           is_64bit)) {
+            if (!aot_gen_commit_ip(comp_ctx, func_ctx,
+                                   func_ctx->exception_ip_phi, is_64bit)) {
                 return false;
             }
         }
@@ -173,7 +134,7 @@ aot_emit_exception(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     /* Add phi incoming value to got_exception block */
     LLVMAddIncoming(func_ctx->exception_id_phi, &exce_id, &block_curr, 1);
 
-    if (comp_ctx->aot_frame) {
+    if (comp_ctx->aot_frame && comp_ctx->call_stack_features.trap_ip) {
         const uint8 *ip = comp_ctx->aot_frame->frame_ip;
         LLVMValueRef exce_ip = NULL;
 

+ 149 - 51
core/iwasm/compilation/aot_emit_function.c

@@ -7,6 +7,7 @@
 #include "aot_emit_exception.h"
 #include "aot_emit_control.h"
 #include "aot_emit_table.h"
+#include "aot_stack_frame_comp.h"
 #include "../aot/aot_runtime.h"
 #if WASM_ENABLE_GC != 0
 #include "aot_emit_gc.h"
@@ -682,24 +683,29 @@ alloc_frame_for_aot_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
 
     new_frame = wasm_stack_top;
 
-    if (!(check_wasm_stack_succ = LLVMAppendBasicBlockInContext(
-              comp_ctx->context, func_ctx->func, "check_wasm_stack_succ"))) {
-        aot_set_last_error("llvm add basic block failed.");
-        return false;
-    }
+    if (comp_ctx->call_stack_features.bounds_checks) {
+        if (!(check_wasm_stack_succ = LLVMAppendBasicBlockInContext(
+                  comp_ctx->context, func_ctx->func,
+                  "check_wasm_stack_succ"))) {
+            aot_set_last_error("llvm add basic block failed.");
+            return false;
+        }
 
-    LLVMMoveBasicBlockAfter(check_wasm_stack_succ,
-                            LLVMGetInsertBlock(comp_ctx->builder));
+        LLVMMoveBasicBlockAfter(check_wasm_stack_succ,
+                                LLVMGetInsertBlock(comp_ctx->builder));
 
-    if (!(cmp = LLVMBuildICmp(comp_ctx->builder, LLVMIntUGT, wasm_stack_top_max,
-                              wasm_stack_top_bound, "cmp"))) {
-        aot_set_last_error("llvm build icmp failed");
-        return false;
-    }
+        if (!(cmp = LLVMBuildICmp(comp_ctx->builder, LLVMIntUGT,
+                                  wasm_stack_top_max, wasm_stack_top_bound,
+                                  "cmp"))) {
+            aot_set_last_error("llvm build icmp failed");
+            return false;
+        }
 
-    if (!(aot_emit_exception(comp_ctx, func_ctx, EXCE_OPERAND_STACK_OVERFLOW,
-                             true, cmp, check_wasm_stack_succ))) {
-        return false;
+        if (!(aot_emit_exception(comp_ctx, func_ctx,
+                                 EXCE_OPERAND_STACK_OVERFLOW, true, cmp,
+                                 check_wasm_stack_succ))) {
+            return false;
+        }
     }
 
 #if WASM_ENABLE_GC != 0
@@ -879,25 +885,28 @@ alloc_frame_for_aot_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     }
 
     if (!comp_ctx->is_jit_mode) {
-        /* aot mode: new_frame->func_idx = func_idx */
-        func_idx_val = comp_ctx->pointer_size == sizeof(uint64)
-                           ? I64_CONST(func_idx)
-                           : I32_CONST(func_idx);
-        offset = I32_CONST(comp_ctx->pointer_size);
-        CHECK_LLVM_CONST(func_idx_val);
-        CHECK_LLVM_CONST(offset);
-        if (!(func_idx_ptr =
-                  LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE, new_frame,
-                                        &offset, 1, "func_idx_addr"))
-            || !(func_idx_ptr =
-                     LLVMBuildBitCast(comp_ctx->builder, func_idx_ptr,
-                                      INTPTR_T_PTR_TYPE, "func_idx_ptr"))) {
-            aot_set_last_error("llvm get func_idx_ptr failed");
-            return false;
-        }
-        if (!LLVMBuildStore(comp_ctx->builder, func_idx_val, func_idx_ptr)) {
-            aot_set_last_error("llvm build store failed");
-            return false;
+        if (comp_ctx->call_stack_features.func_idx) {
+            /* aot mode: new_frame->func_idx = func_idx */
+            func_idx_val = comp_ctx->pointer_size == sizeof(uint64)
+                               ? I64_CONST(func_idx)
+                               : I32_CONST(func_idx);
+            offset = I32_CONST(comp_ctx->pointer_size);
+            CHECK_LLVM_CONST(func_idx_val);
+            CHECK_LLVM_CONST(offset);
+            if (!(func_idx_ptr = LLVMBuildInBoundsGEP2(
+                      comp_ctx->builder, INT8_TYPE, new_frame, &offset, 1,
+                      "func_idx_addr"))
+                || !(func_idx_ptr =
+                         LLVMBuildBitCast(comp_ctx->builder, func_idx_ptr,
+                                          INTPTR_T_PTR_TYPE, "func_idx_ptr"))) {
+                aot_set_last_error("llvm get func_idx_ptr failed");
+                return false;
+            }
+            if (!LLVMBuildStore(comp_ctx->builder, func_idx_val,
+                                func_idx_ptr)) {
+                aot_set_last_error("llvm build store failed");
+                return false;
+            }
         }
     }
     else {
@@ -1285,6 +1294,10 @@ commit_params_to_frame_of_import_func(AOTCompContext *comp_ctx,
 {
     uint32 i, n;
 
+    if (!comp_ctx->call_stack_features.values) {
+        return true;
+    }
+
     for (i = 0, n = 0; i < func_type->param_count; i++, n++) {
         switch (func_type->types[i]) {
             case VALUE_TYPE_I32:
@@ -1394,6 +1407,9 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     LLVMValueRef *param_values = NULL, value_ret = NULL, func;
     LLVMValueRef import_func_idx, res;
     LLVMValueRef ext_ret, ext_ret_ptr, ext_ret_idx;
+#if WASM_ENABLE_AOT_STACK_FRAME != 0
+    LLVMValueRef func_idx_ref;
+#endif
     int32 i, j = 0, param_count, result_count, ext_ret_count;
     uint64 total_size;
     uint8 wasm_ret_type;
@@ -1438,12 +1454,28 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
             return false;
     }
 
-    if (comp_ctx->enable_aux_stack_frame) {
 #if WASM_ENABLE_AOT_STACK_FRAME != 0
-        if (!alloc_frame_for_aot_func(comp_ctx, func_ctx, func_idx))
-            return false;
-#endif
+    if (comp_ctx->aux_stack_frame_type) {
+        if (func_idx < import_func_count
+            && comp_ctx->call_stack_features.frame_per_function) {
+            INT_CONST(func_idx_ref, func_idx, I32_TYPE, true);
+            if (!aot_alloc_frame_per_function_frame_for_aot_func(
+                    comp_ctx, func_ctx, func_idx_ref)) {
+                return false;
+            }
+        }
+        else if (!comp_ctx->call_stack_features.frame_per_function) {
+            if (comp_ctx->aux_stack_frame_type
+                != AOT_STACK_FRAME_TYPE_STANDARD) {
+                aot_set_last_error("unsupported mode");
+                return false;
+            }
+            if (!alloc_frame_for_aot_func(comp_ctx, func_ctx, func_idx)) {
+                return false;
+            }
+        }
     }
+#endif
 
     /* Get param cell number */
     param_cell_num = func_type->param_cell_num;
@@ -1513,7 +1545,7 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     }
 
     if (func_idx < import_func_count) {
-        if (comp_ctx->enable_aux_stack_frame
+        if (comp_ctx->aux_stack_frame_type == AOT_STACK_FRAME_TYPE_STANDARD
             && !commit_params_to_frame_of_import_func(
                 comp_ctx, func_ctx, func_type, param_values + 1)) {
             goto fail;
@@ -1804,12 +1836,26 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
         }
     }
 
-    if (comp_ctx->enable_aux_stack_frame) {
 #if WASM_ENABLE_AOT_STACK_FRAME != 0
-        if (!free_frame_for_aot_func(comp_ctx, func_ctx))
-            goto fail;
-#endif
+    if (comp_ctx->aux_stack_frame_type) {
+        if (func_idx < import_func_count
+            && comp_ctx->call_stack_features.frame_per_function) {
+            if (!aot_free_frame_per_function_frame_for_aot_func(comp_ctx,
+                                                                func_ctx)) {
+                goto fail;
+            }
+        }
+        else if (!comp_ctx->call_stack_features.frame_per_function) {
+            if (comp_ctx->aux_stack_frame_type
+                != AOT_STACK_FRAME_TYPE_STANDARD) {
+                aot_set_last_error("unsupported mode");
+            }
+            if (!free_frame_for_aot_func(comp_ctx, func_ctx)) {
+                goto fail;
+            }
+        }
     }
+#endif
 
     /* Insert suspend check point */
     if (comp_ctx->enable_thread_mgr) {
@@ -2043,6 +2089,9 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     LLVMValueRef ext_ret_offset, ext_ret_ptr, ext_ret, res;
     LLVMValueRef *param_values = NULL, *value_rets = NULL;
     LLVMValueRef *result_phis = NULL, value_ret, import_func_count;
+#if WASM_ENABLE_MEMORY64 != 0
+    LLVMValueRef u32_max, u32_cmp_result = NULL;
+#endif
     LLVMTypeRef *param_types = NULL, ret_type;
     LLVMTypeRef llvm_func_type, llvm_func_ptr_type;
     LLVMTypeRef ext_ret_ptr_type;
@@ -2107,7 +2156,7 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     func_param_count = func_type->param_count;
     func_result_count = func_type->result_count;
 
-    POP_I32(elem_idx);
+    POP_TBL_ELEM_IDX(elem_idx);
 
     /* get the cur size of the table instance */
     if (!(offset = I32_CONST(get_tbl_inst_offset(comp_ctx, func_ctx, tbl_idx)
@@ -2136,6 +2185,27 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
         goto fail;
     }
 
+#if WASM_ENABLE_MEMORY64 != 0
+    /* Check if elem index >= UINT32_MAX */
+    if (IS_TABLE64(tbl_idx)) {
+        if (!(u32_max = I64_CONST(UINT32_MAX))) {
+            aot_set_last_error("llvm build const failed");
+            goto fail;
+        }
+        if (!(u32_cmp_result =
+                  LLVMBuildICmp(comp_ctx->builder, LLVMIntUGE, elem_idx,
+                                u32_max, "cmp_elem_idx_u32_max"))) {
+            aot_set_last_error("llvm build icmp failed.");
+            goto fail;
+        }
+        if (!(elem_idx = LLVMBuildTrunc(comp_ctx->builder, elem_idx, I32_TYPE,
+                                        "elem_idx_i32"))) {
+            aot_set_last_error("llvm build trunc failed.");
+            goto fail;
+        }
+    }
+#endif
+
     /* Check if (uint32)elem index >= table size */
     if (!(cmp_elem_idx = LLVMBuildICmp(comp_ctx->builder, LLVMIntUGE, elem_idx,
                                        table_size_const, "cmp_elem_idx"))) {
@@ -2143,7 +2213,19 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
         goto fail;
     }
 
-    /* Throw exception if elem index >= table size */
+#if WASM_ENABLE_MEMORY64 != 0
+    if (IS_TABLE64(tbl_idx)) {
+        if (!(cmp_elem_idx =
+                  LLVMBuildOr(comp_ctx->builder, cmp_elem_idx, u32_cmp_result,
+                              "larger_than_u32_max_or_cur_size"))) {
+            aot_set_last_error("llvm build or failed.");
+            goto fail;
+        }
+    }
+#endif
+
+    /* Throw exception if elem index >= table size or elem index >= UINT32_MAX
+     */
     if (!(check_elem_idx_succ = LLVMAppendBasicBlockInContext(
               comp_ctx->context, func_ctx->func, "check_elem_idx_succ"))) {
         aot_set_last_error("llvm add basic block failed.");
@@ -2430,7 +2512,8 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
         goto fail;
     }
 
-    if (comp_ctx->enable_aux_stack_frame) {
+    if (comp_ctx->aux_stack_frame_type
+        && !comp_ctx->call_stack_features.frame_per_function) {
 #if WASM_ENABLE_AOT_STACK_FRAME != 0
         /*  TODO: use current frame instead of allocating new frame
                   for WASM_OP_RETURN_CALL_INDIRECT */
@@ -2499,7 +2582,13 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     /* Translate call import block */
     LLVMPositionBuilderAtEnd(comp_ctx->builder, block_call_import);
 
-    if (comp_ctx->enable_aux_stack_frame
+    if (comp_ctx->aot_frame && comp_ctx->call_stack_features.frame_per_function
+        && !aot_alloc_frame_per_function_frame_for_aot_func(comp_ctx, func_ctx,
+                                                            func_idx)) {
+        goto fail;
+    }
+
+    if (comp_ctx->aux_stack_frame_type == AOT_STACK_FRAME_TYPE_STANDARD
         && !commit_params_to_frame_of_import_func(comp_ctx, func_ctx, func_type,
                                                   param_values + 1)) {
         goto fail;
@@ -2536,6 +2625,12 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
         && !check_call_return(comp_ctx, func_ctx, res))
         goto fail;
 
+    if (comp_ctx->aot_frame && comp_ctx->call_stack_features.frame_per_function
+        && !aot_free_frame_per_function_frame_for_aot_func(comp_ctx,
+                                                           func_ctx)) {
+        goto fail;
+    }
+
     block_curr = LLVMGetInsertBlock(comp_ctx->builder);
     for (i = 0; i < func_result_count; i++) {
         LLVMAddIncoming(result_phis[i], &value_rets[i], &block_curr, 1);
@@ -2620,7 +2715,8 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
         PUSH(result_phis[i], func_type->types[func_param_count + i]);
     }
 
-    if (comp_ctx->enable_aux_stack_frame) {
+    if (comp_ctx->aux_stack_frame_type
+        && !comp_ctx->call_stack_features.frame_per_function) {
 #if WASM_ENABLE_AOT_STACK_FRAME != 0
         if (!free_frame_for_aot_func(comp_ctx, func_ctx))
             goto fail;
@@ -2927,7 +3023,8 @@ aot_compile_op_call_ref(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
         goto fail;
     }
 
-    if (comp_ctx->enable_aux_stack_frame) {
+    if (comp_ctx->aux_stack_frame_type
+        && !comp_ctx->call_stack_features.frame_per_function) {
 #if WASM_ENABLE_AOT_STACK_FRAME != 0
         /*  TODO: use current frame instead of allocating new frame
                   for WASM_OP_RETURN_CALL_REF */
@@ -2996,7 +3093,7 @@ aot_compile_op_call_ref(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     /* Translate call import block */
     LLVMPositionBuilderAtEnd(comp_ctx->builder, block_call_import);
 
-    if (comp_ctx->enable_aux_stack_frame
+    if (comp_ctx->aux_stack_frame_type == AOT_STACK_FRAME_TYPE_STANDARD
         && !commit_params_to_frame_of_import_func(comp_ctx, func_ctx, func_type,
                                                   param_values + 1)) {
         goto fail;
@@ -3124,7 +3221,8 @@ aot_compile_op_call_ref(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
         PUSH(result_phis[i], func_type->types[func_param_count + i]);
     }
 
-    if (comp_ctx->enable_aux_stack_frame) {
+    if (comp_ctx->aux_stack_frame_type
+        && !comp_ctx->call_stack_features.frame_per_function) {
 #if WASM_ENABLE_AOT_STACK_FRAME != 0
         if (!free_frame_for_aot_func(comp_ctx, func_ctx))
             goto fail;

+ 267 - 11
core/iwasm/compilation/aot_emit_memory.c

@@ -118,10 +118,10 @@ aot_check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
 {
     LLVMValueRef offset_const =
         MEMORY64_COND_VALUE(I64_CONST(offset), I32_CONST(offset));
-    LLVMValueRef addr, maddr, offset1, cmp1, cmp2, cmp;
+    LLVMValueRef addr, maddr, maddr_phi = NULL, offset1, cmp1, cmp2, cmp;
     LLVMValueRef mem_base_addr, mem_check_bound;
     LLVMBasicBlockRef block_curr = LLVMGetInsertBlock(comp_ctx->builder);
-    LLVMBasicBlockRef check_succ;
+    LLVMBasicBlockRef check_succ, block_maddr_phi = NULL;
     AOTValue *aot_value_top;
     uint32 local_idx_of_aot_value = 0;
     uint64 const_value;
@@ -131,6 +131,11 @@ aot_check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     bool is_shared_memory =
         comp_ctx->comp_data->memories[0].flags & SHARED_MEMORY_FLAG;
 #endif
+#if WASM_ENABLE_MEMORY64 == 0
+    bool is_memory64 = false;
+#else
+    bool is_memory64 = IS_MEMORY64;
+#endif
 
     is_target_64bit = (comp_ctx->pointer_size == sizeof(uint64)) ? true : false;
 
@@ -268,8 +273,137 @@ aot_check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     }
 
     /* offset1 = offset + addr; */
+    /* TODO: check whether integer overflow occurs when memory is 64-bit
+             and boundary check is enabled */
     BUILD_OP(Add, offset_const, addr, offset1, "offset1");
 
+    if (comp_ctx->enable_shared_heap /* TODO: && mem_idx == 0 */) {
+        LLVMBasicBlockRef app_addr_in_shared_heap, app_addr_in_linear_mem;
+        LLVMValueRef is_in_shared_heap, shared_heap_check_bound = NULL;
+
+        /* Add basic blocks */
+        ADD_BASIC_BLOCK(app_addr_in_shared_heap, "app_addr_in_shared_heap");
+        ADD_BASIC_BLOCK(app_addr_in_linear_mem, "app_addr_in_linear_mem");
+        ADD_BASIC_BLOCK(block_maddr_phi, "maddr_phi");
+
+        LLVMMoveBasicBlockAfter(app_addr_in_shared_heap, block_curr);
+        LLVMMoveBasicBlockAfter(app_addr_in_linear_mem,
+                                app_addr_in_shared_heap);
+        LLVMMoveBasicBlockAfter(block_maddr_phi, app_addr_in_linear_mem);
+
+        LLVMPositionBuilderAtEnd(comp_ctx->builder, block_maddr_phi);
+        if (!(maddr_phi =
+                  LLVMBuildPhi(comp_ctx->builder,
+                               enable_segue ? INT8_PTR_TYPE_GS : INT8_PTR_TYPE,
+                               "maddr_phi"))) {
+            aot_set_last_error("llvm build phi failed");
+            goto fail;
+        }
+
+        LLVMPositionBuilderAtEnd(comp_ctx->builder, block_curr);
+
+        if (!is_target_64bit) {
+            /* Check whether interger overflow occurs in addr + offset */
+            LLVMBasicBlockRef check_integer_overflow_end;
+            ADD_BASIC_BLOCK(check_integer_overflow_end,
+                            "check_integer_overflow_end");
+            LLVMMoveBasicBlockAfter(check_integer_overflow_end, block_curr);
+
+            BUILD_ICMP(LLVMIntULT, offset1, addr, cmp1, "cmp1");
+            if (!aot_emit_exception(comp_ctx, func_ctx,
+                                    EXCE_OUT_OF_BOUNDS_MEMORY_ACCESS, true,
+                                    cmp1, check_integer_overflow_end)) {
+                goto fail;
+            }
+            SET_BUILD_POS(check_integer_overflow_end);
+        }
+
+        shared_heap_check_bound =
+            is_memory64 ? I64_CONST(UINT64_MAX - bytes + 1)
+                        : (comp_ctx->pointer_size == sizeof(uint64)
+                               ? I64_CONST(UINT32_MAX - bytes + 1)
+                               : I32_CONST(UINT32_MAX - bytes + 1));
+        CHECK_LLVM_CONST(shared_heap_check_bound);
+
+        /* Check whether the bytes to access are in shared heap */
+        if (!comp_ctx->enable_bound_check) {
+            /* Use IntUGT but not IntUGE to compare, since (1) in the ems
+               memory allocator, the hmu node includes hmu header and hmu
+               memory, only the latter is returned to the caller as the
+               allocated memory, the hmu header isn't returned so the
+               first byte of the shared heap won't be accesed, (2) using
+               IntUGT gets better performance than IntUGE in some cases */
+            BUILD_ICMP(LLVMIntUGT, offset1, func_ctx->shared_heap_start_off,
+                       is_in_shared_heap, "is_in_shared_heap");
+            /* We don't check the shared heap's upper boundary if boundary
+               check isn't enabled, the runtime may also use the guard pages
+               of shared heap to check the boundary if hardware boundary
+               check feature is enabled. */
+        }
+        else {
+            /* Use IntUGT but not IntUGE to compare, same as above */
+            BUILD_ICMP(LLVMIntUGT, offset1, func_ctx->shared_heap_start_off,
+                       cmp1, "cmp1");
+            /* Check the shared heap's upper boundary if boundary check is
+               enabled */
+            BUILD_ICMP(LLVMIntULE, offset1, shared_heap_check_bound, cmp2,
+                       "cmp2");
+            BUILD_OP(And, cmp1, cmp2, is_in_shared_heap, "is_in_shared_heap");
+        }
+
+        if (!LLVMBuildCondBr(comp_ctx->builder, is_in_shared_heap,
+                             app_addr_in_shared_heap, app_addr_in_linear_mem)) {
+            aot_set_last_error("llvm build cond br failed");
+            goto fail;
+        }
+
+        LLVMPositionBuilderAtEnd(comp_ctx->builder, app_addr_in_shared_heap);
+
+        /* Get native address inside shared heap */
+        if (!(maddr =
+                  LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE,
+                                        func_ctx->shared_heap_base_addr_adj,
+                                        &offset1, 1, "maddr_shared_heap"))) {
+            aot_set_last_error("llvm build inbounds gep failed");
+            goto fail;
+        }
+
+        if (enable_segue) {
+            LLVMValueRef mem_base_addr_u64, maddr_u64, offset_to_mem_base;
+
+            if (!(maddr_u64 = LLVMBuildPtrToInt(comp_ctx->builder, maddr,
+                                                I64_TYPE, "maddr_u64"))
+                || !(mem_base_addr_u64 =
+                         LLVMBuildPtrToInt(comp_ctx->builder, mem_base_addr,
+                                           I64_TYPE, "mem_base_addr_u64"))) {
+                aot_set_last_error("llvm build ptr to int failed");
+                goto fail;
+            }
+            if (!(offset_to_mem_base =
+                      LLVMBuildSub(comp_ctx->builder, maddr_u64,
+                                   mem_base_addr_u64, "offset_to_mem_base"))) {
+                aot_set_last_error("llvm build sub failed");
+                goto fail;
+            }
+            if (!(maddr = LLVMBuildIntToPtr(
+                      comp_ctx->builder, offset_to_mem_base, INT8_PTR_TYPE_GS,
+                      "maddr_shared_heap_segue"))) {
+                aot_set_last_error("llvm build int to ptr failed.");
+                goto fail;
+            }
+        }
+
+        LLVMAddIncoming(maddr_phi, &maddr, &app_addr_in_shared_heap, 1);
+
+        if (!LLVMBuildBr(comp_ctx->builder, block_maddr_phi)) {
+            aot_set_last_error("llvm build br failed");
+            goto fail;
+        }
+
+        LLVMPositionBuilderAtEnd(comp_ctx->builder, app_addr_in_linear_mem);
+        block_curr = LLVMGetInsertBlock(comp_ctx->builder);
+    }
+
     if (comp_ctx->enable_bound_check
         && !(is_local_of_aot_value
              && aot_checked_addr_list_find(func_ctx, local_idx_of_aot_value,
@@ -305,10 +439,16 @@ aot_check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
             BUILD_ICMP(LLVMIntUGT, offset1, mem_check_bound, cmp, "cmp");
         }
         else {
-            /* Check integer overflow */
-            BUILD_ICMP(LLVMIntULT, offset1, addr, cmp1, "cmp1");
-            BUILD_ICMP(LLVMIntUGT, offset1, mem_check_bound, cmp2, "cmp2");
-            BUILD_OP(Or, cmp1, cmp2, cmp, "cmp");
+            if (comp_ctx->enable_shared_heap /* TODO: && mem_idx == 0 */) {
+                /* Check integer overflow has been checked above */
+                BUILD_ICMP(LLVMIntUGT, offset1, mem_check_bound, cmp, "cmp");
+            }
+            else {
+                /* Check integer overflow */
+                BUILD_ICMP(LLVMIntULT, offset1, addr, cmp1, "cmp1");
+                BUILD_ICMP(LLVMIntUGT, offset1, mem_check_bound, cmp2, "cmp2");
+                BUILD_OP(Or, cmp1, cmp2, cmp, "cmp");
+            }
         }
 
         /* Add basic blocks */
@@ -354,7 +494,19 @@ aot_check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
             goto fail;
         }
     }
-    return maddr;
+
+    if (comp_ctx->enable_shared_heap /* TODO: && mem_idx == 0 */) {
+        block_curr = LLVMGetInsertBlock(comp_ctx->builder);
+        LLVMAddIncoming(maddr_phi, &maddr, &block_curr, 1);
+        if (!LLVMBuildBr(comp_ctx->builder, block_maddr_phi)) {
+            aot_set_last_error("llvm build br failed");
+            goto fail;
+        }
+        LLVMPositionBuilderAtEnd(comp_ctx->builder, block_maddr_phi);
+        return maddr_phi;
+    }
+    else
+        return maddr;
 fail:
     return NULL;
 }
@@ -985,10 +1137,15 @@ check_bulk_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
                            LLVMValueRef offset, LLVMValueRef bytes)
 {
     LLVMValueRef maddr, max_addr, cmp;
-    LLVMValueRef mem_base_addr;
+    LLVMValueRef mem_base_addr, maddr_phi = NULL;
     LLVMBasicBlockRef block_curr = LLVMGetInsertBlock(comp_ctx->builder);
-    LLVMBasicBlockRef check_succ;
+    LLVMBasicBlockRef check_succ, block_maddr_phi = NULL;
     LLVMValueRef mem_size;
+#if WASM_ENABLE_MEMORY64 == 0
+    bool is_memory64 = false;
+#else
+    bool is_memory64 = IS_MEMORY64;
+#endif
 
     /* Get memory base address and memory data size */
 #if WASM_ENABLE_SHARED_MEMORY != 0
@@ -1053,9 +1210,96 @@ check_bulk_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     offset =
         LLVMBuildZExt(comp_ctx->builder, offset, I64_TYPE, "extend_offset");
     bytes = LLVMBuildZExt(comp_ctx->builder, bytes, I64_TYPE, "extend_len");
+    if (!offset || !bytes) {
+        aot_set_last_error("llvm build zext failed.");
+        goto fail;
+    }
 
+    /* TODO: check whether integer overflow occurs when memory is 64-bit
+             and boundary check is enabled */
     BUILD_OP(Add, offset, bytes, max_addr, "max_addr");
+
+    if (comp_ctx->enable_shared_heap /* TODO: && mem_idx == 0 */) {
+        LLVMBasicBlockRef app_addr_in_shared_heap, app_addr_in_linear_mem;
+        LLVMValueRef shared_heap_start_off, shared_heap_check_bound;
+        LLVMValueRef max_offset, cmp1, cmp2, is_in_shared_heap;
+
+        /* Add basic blocks */
+        ADD_BASIC_BLOCK(app_addr_in_shared_heap, "app_addr_in_shared_heap");
+        ADD_BASIC_BLOCK(app_addr_in_linear_mem, "app_addr_in_linear_mem");
+        ADD_BASIC_BLOCK(block_maddr_phi, "maddr_phi");
+
+        LLVMMoveBasicBlockAfter(app_addr_in_shared_heap, block_curr);
+        LLVMMoveBasicBlockAfter(app_addr_in_linear_mem,
+                                app_addr_in_shared_heap);
+        LLVMMoveBasicBlockAfter(block_maddr_phi, check_succ);
+
+        LLVMPositionBuilderAtEnd(comp_ctx->builder, block_maddr_phi);
+        if (!(maddr_phi = LLVMBuildPhi(comp_ctx->builder, INT8_PTR_TYPE,
+                                       "maddr_phi"))) {
+            aot_set_last_error("llvm build phi failed");
+            goto fail;
+        }
+
+        LLVMPositionBuilderAtEnd(comp_ctx->builder, block_curr);
+
+        shared_heap_start_off = func_ctx->shared_heap_start_off;
+        if (comp_ctx->pointer_size == sizeof(uint32)) {
+            if (!(shared_heap_start_off =
+                      LLVMBuildZExt(comp_ctx->builder, shared_heap_start_off,
+                                    I64_TYPE, "shared_heap_start_off_u64"))) {
+                aot_set_last_error("llvm build zext failed");
+                goto fail;
+            }
+        }
+        shared_heap_check_bound =
+            is_memory64 ? I64_CONST(UINT64_MAX) : I64_CONST(UINT32_MAX);
+        CHECK_LLVM_CONST(shared_heap_check_bound);
+
+        /* Check whether the bytes to access are in shared heap */
+        if (!comp_ctx->enable_bound_check) {
+            /* Use IntUGT but not IntUGE to compare, same as the check
+               in aot_check_memory_overflow */
+            BUILD_ICMP(LLVMIntUGT, offset, func_ctx->shared_heap_start_off,
+                       is_in_shared_heap, "is_in_shared_heap");
+        }
+        else {
+            BUILD_ICMP(LLVMIntUGT, offset, func_ctx->shared_heap_start_off,
+                       cmp1, "cmp1");
+            BUILD_OP(Add, max_addr, I64_NEG_ONE, max_offset, "max_offset");
+            BUILD_ICMP(LLVMIntULE, max_offset, shared_heap_check_bound, cmp2,
+                       "cmp2");
+            BUILD_OP(And, cmp1, cmp2, is_in_shared_heap, "is_in_shared_heap");
+        }
+
+        if (!LLVMBuildCondBr(comp_ctx->builder, is_in_shared_heap,
+                             app_addr_in_shared_heap, app_addr_in_linear_mem)) {
+            aot_set_last_error("llvm build cond br failed");
+            goto fail;
+        }
+
+        LLVMPositionBuilderAtEnd(comp_ctx->builder, app_addr_in_shared_heap);
+
+        /* Get native address inside shared heap */
+        if (!(maddr = LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE,
+                                            func_ctx->shared_heap_base_addr_adj,
+                                            &offset, 1, "maddr_shared_heap"))) {
+            aot_set_last_error("llvm build inbounds gep failed");
+            goto fail;
+        }
+        LLVMAddIncoming(maddr_phi, &maddr, &app_addr_in_shared_heap, 1);
+
+        if (!LLVMBuildBr(comp_ctx->builder, block_maddr_phi)) {
+            aot_set_last_error("llvm build br failed");
+            goto fail;
+        }
+
+        LLVMPositionBuilderAtEnd(comp_ctx->builder, app_addr_in_linear_mem);
+        block_curr = LLVMGetInsertBlock(comp_ctx->builder);
+    }
+
     BUILD_ICMP(LLVMIntUGT, max_addr, mem_size, cmp, "cmp_max_mem_addr");
+
     if (!aot_emit_exception(comp_ctx, func_ctx,
                             EXCE_OUT_OF_BOUNDS_MEMORY_ACCESS, true, cmp,
                             check_succ)) {
@@ -1068,11 +1312,23 @@ check_bulk_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
         aot_set_last_error("llvm build add failed.");
         goto fail;
     }
-    return maddr;
+
+    if (comp_ctx->enable_shared_heap /* TODO: && mem_idx == 0 */) {
+        block_curr = LLVMGetInsertBlock(comp_ctx->builder);
+        LLVMAddIncoming(maddr_phi, &maddr, &block_curr, 1);
+        if (!LLVMBuildBr(comp_ctx->builder, block_maddr_phi)) {
+            aot_set_last_error("llvm build br failed");
+            goto fail;
+        }
+        LLVMPositionBuilderAtEnd(comp_ctx->builder, block_maddr_phi);
+        return maddr_phi;
+    }
+    else
+        return maddr;
 fail:
     return NULL;
 }
-#endif /* end of WASM_ENABLE_BULK_MEMORY != 0 or WASM_ENABLE_STRINGREF != 0 */
+#endif /* end of WASM_ENABLE_BULK_MEMORY != 0 || WASM_ENABLE_STRINGREF != 0 */
 
 #if WASM_ENABLE_BULK_MEMORY != 0
 bool

+ 141 - 12
core/iwasm/compilation/aot_emit_table.c

@@ -10,6 +10,78 @@
 #include "aot_emit_gc.h"
 #endif
 
+#if WASM_ENABLE_REF_TYPES != 0 || WASM_ENABLE_GC != 0
+#if WASM_ENABLE_MEMORY64 != 0
+static bool
+zero_extend_u64(AOTCompContext *comp_ctx, LLVMValueRef *value, const char *name)
+{
+    if (comp_ctx->pointer_size == sizeof(uint64)) {
+        /* zero extend to uint64 if the target is 64-bit */
+        *value = LLVMBuildZExt(comp_ctx->builder, *value, I64_TYPE, name);
+        if (!*value) {
+            aot_set_last_error("llvm build zero extend failed.");
+            return false;
+        }
+    }
+    return true;
+}
+#endif
+
+/* check whether a table64 elem idx is greater than UINT32_MAX, if so, throw
+ * exception, otherwise trunc it to uint32 */
+static bool
+check_tbl_elem_idx_and_trunc(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
+                             LLVMValueRef *elem_idx, uint32 tbl_idx)
+{
+#if WASM_ENABLE_MEMORY64 != 0
+    LLVMValueRef u32_max, u32_cmp_result;
+    LLVMBasicBlockRef check_elem_idx_succ;
+
+    if (!IS_TABLE64(tbl_idx)) {
+        return true;
+    }
+
+    /* Check if elem index >= UINT32_MAX */
+    if (!(u32_max = I64_CONST(UINT32_MAX))) {
+        aot_set_last_error("llvm build const failed");
+        goto fail;
+    }
+    if (!(u32_cmp_result =
+              LLVMBuildICmp(comp_ctx->builder, LLVMIntUGE, *elem_idx, u32_max,
+                            "cmp_elem_idx_u32_max"))) {
+        aot_set_last_error("llvm build icmp failed.");
+        goto fail;
+    }
+    if (!(*elem_idx = LLVMBuildTrunc(comp_ctx->builder, *elem_idx, I32_TYPE,
+                                     "elem_idx_i32"))) {
+        aot_set_last_error("llvm build trunc failed.");
+        goto fail;
+    }
+
+    /* Throw exception if elem index >= UINT32_MAX*/
+    if (!(check_elem_idx_succ = LLVMAppendBasicBlockInContext(
+              comp_ctx->context, func_ctx->func, "check_elem_idx_succ"))) {
+        aot_set_last_error("llvm add basic block failed.");
+        goto fail;
+    }
+
+    LLVMMoveBasicBlockAfter(check_elem_idx_succ,
+                            LLVMGetInsertBlock(comp_ctx->builder));
+
+    if (!(aot_emit_exception(comp_ctx, func_ctx,
+                             EXCE_OUT_OF_BOUNDS_TABLE_ACCESS, true,
+                             u32_cmp_result, check_elem_idx_succ)))
+        goto fail;
+
+    return true;
+fail:
+    return false;
+#else
+    return true;
+#endif
+}
+#endif /* WASM_ENABLE_REF_TYPES != 0 || WASM_ENABLE_GC !=0 */
+
 uint64
 get_tbl_inst_offset(const AOTCompContext *comp_ctx,
                     const AOTFuncContext *func_ctx, uint32 tbl_idx)
@@ -158,6 +230,10 @@ aot_check_table_access(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
         goto fail;
     }
 
+    if (!check_tbl_elem_idx_and_trunc(comp_ctx, func_ctx, &elem_idx, tbl_idx)) {
+        goto fail;
+    }
+
     /* Check if (uint32)elem index >= table size */
     if (!(cmp_elem_idx = LLVMBuildICmp(comp_ctx->builder, LLVMIntUGE, elem_idx,
                                        tbl_sz, "cmp_elem_idx"))) {
@@ -192,7 +268,7 @@ aot_compile_op_table_get(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     LLVMValueRef elem_idx, offset, func_idx;
     LLVMValueRef table_elem_base, table_elem_addr, table_elem;
 
-    POP_I32(elem_idx);
+    POP_TBL_ELEM_IDX(elem_idx);
 
     if (!aot_check_table_access(comp_ctx, func_ctx, tbl_idx, elem_idx)) {
         goto fail;
@@ -289,7 +365,7 @@ aot_compile_op_table_set(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
         }
     }
 
-    POP_I32(elem_idx);
+    POP_TBL_ELEM_IDX(elem_idx);
 
     if (!aot_check_table_access(comp_ctx, func_ctx, tbl_idx, elem_idx)) {
         goto fail;
@@ -388,7 +464,11 @@ aot_compile_op_table_init(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     /* s */
     POP_I32(param_values[4]);
     /* d */
-    POP_I32(param_values[5]);
+    POP_TBL_ELEM_IDX(param_values[5]);
+    if (!check_tbl_elem_idx_and_trunc(comp_ctx, func_ctx, &param_values[5],
+                                      tbl_idx)) {
+        goto fail;
+    }
 
     /* "" means return void */
     if (!(LLVMBuildCall2(comp_ctx->builder, func_type, func, param_values, 6,
@@ -408,6 +488,7 @@ aot_compile_op_table_copy(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
 {
     LLVMTypeRef param_types[6], ret_type, func_type, func_ptr_type;
     LLVMValueRef func, param_values[6], value;
+    uint32 tbl_idx;
 
     param_types[0] = INT8_PTR_TYPE;
     param_types[1] = I32_TYPE;
@@ -434,12 +515,34 @@ aot_compile_op_table_copy(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
         goto fail;
     }
 
+    /* In table64, the length should be i32 type if any one of src/dst table
+     * is i32 type, set the table index to the lesser-or-equal table when
+     * popping length n */
+    if (!(comp_ctx->comp_data->tables[src_tbl_idx].table_type.flags
+          & TABLE64_FLAG))
+        tbl_idx = src_tbl_idx;
+    else
+        tbl_idx = dst_tbl_idx;
     /* n */
-    POP_I32(param_values[3]);
+    POP_TBL_ELEM_LEN(param_values[3]);
+    if (!check_tbl_elem_idx_and_trunc(comp_ctx, func_ctx, &param_values[3],
+                                      tbl_idx)) {
+        goto fail;
+    }
     /* s */
-    POP_I32(param_values[4]);
+    tbl_idx = src_tbl_idx;
+    POP_TBL_ELEM_IDX(param_values[4]);
+    if (!check_tbl_elem_idx_and_trunc(comp_ctx, func_ctx, &param_values[4],
+                                      tbl_idx)) {
+        goto fail;
+    }
     /* d */
-    POP_I32(param_values[5]);
+    tbl_idx = dst_tbl_idx;
+    POP_TBL_ELEM_IDX(param_values[5]);
+    if (!check_tbl_elem_idx_and_trunc(comp_ctx, func_ctx, &param_values[5],
+                                      tbl_idx)) {
+        goto fail;
+    }
 
     /* "" means return void */
     if (!(LLVMBuildCall2(comp_ctx->builder, func_type, func, param_values, 6,
@@ -484,7 +587,14 @@ aot_compile_op_table_size(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
         goto fail;
     }
 
-    PUSH_I32(tbl_sz);
+#if WASM_ENABLE_MEMORY64 != 0
+    if (IS_TABLE64(tbl_idx)) {
+        if (!zero_extend_u64(comp_ctx, &tbl_sz, "length64")) {
+            goto fail;
+        }
+    }
+#endif
+    PUSH_TBL_ELEM_IDX(tbl_sz);
 
     return true;
 fail:
@@ -517,7 +627,11 @@ aot_compile_op_table_grow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     }
 
     /* n */
-    POP_I32(param_values[2]);
+    POP_TBL_ELEM_LEN(param_values[2]);
+    if (!check_tbl_elem_idx_and_trunc(comp_ctx, func_ctx, &param_values[2],
+                                      tbl_idx)) {
+        goto fail;
+    }
     /* v */
 
     if (comp_ctx->enable_gc) {
@@ -545,7 +659,14 @@ aot_compile_op_table_grow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
         goto fail;
     }
 
-    PUSH_I32(ret);
+#if WASM_ENABLE_MEMORY64 != 0
+    if (IS_TABLE64(tbl_idx)) {
+        if (!zero_extend_u64(comp_ctx, &ret, "table_size64")) {
+            goto fail;
+        }
+    }
+#endif
+    PUSH_TBL_ELEM_LEN(ret);
 
     return true;
 fail:
@@ -579,7 +700,11 @@ aot_compile_op_table_fill(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     }
 
     /* n */
-    POP_I32(param_values[2]);
+    POP_TBL_ELEM_LEN(param_values[2]);
+    if (!check_tbl_elem_idx_and_trunc(comp_ctx, func_ctx, &param_values[2],
+                                      tbl_idx)) {
+        goto fail;
+    }
     /* v */
 
     if (comp_ctx->enable_gc) {
@@ -601,7 +726,11 @@ aot_compile_op_table_fill(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
         }
     }
     /* i */
-    POP_I32(param_values[4]);
+    POP_TBL_ELEM_IDX(param_values[4]);
+    if (!check_tbl_elem_idx_and_trunc(comp_ctx, func_ctx, &param_values[4],
+                                      tbl_idx)) {
+        goto fail;
+    }
 
     /* "" means return void */
     if (!(LLVMBuildCall2(comp_ctx->builder, func_type, func, param_values, 5,
@@ -615,4 +744,4 @@ fail:
     return false;
 }
 
-#endif /*  WASM_ENABLE_REF_TYPES != 0 || WASM_ENABLE_GC !=0 */
+#endif /* WASM_ENABLE_REF_TYPES != 0 || WASM_ENABLE_GC !=0 */

+ 100 - 13
core/iwasm/compilation/aot_llvm.c

@@ -1518,6 +1518,75 @@ create_memory_info(const AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     return true;
 }
 
+static bool
+create_shared_heap_info(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
+{
+    LLVMValueRef offset, base_addr_p, start_off_p, cmp;
+    uint32 offset_u32;
+
+    /* Load aot_inst->e->shared_heap_base_addr_adj */
+    offset_u32 = get_module_inst_extra_offset(comp_ctx);
+#if WASM_ENABLE_JIT != 0 && WASM_ENABLE_SHARED_HEAP != 0
+    if (comp_ctx->is_jit_mode)
+        offset_u32 +=
+            offsetof(WASMModuleInstanceExtra, shared_heap_base_addr_adj);
+    else
+#endif
+        offset_u32 +=
+            offsetof(AOTModuleInstanceExtra, shared_heap_base_addr_adj);
+    offset = I32_CONST(offset_u32);
+    CHECK_LLVM_CONST(offset);
+
+    if (!(base_addr_p = LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE,
+                                              func_ctx->aot_inst, &offset, 1,
+                                              "shared_heap_base_addr_adj_p"))) {
+        aot_set_last_error("llvm build inbounds gep failed");
+        return false;
+    }
+    if (!(func_ctx->shared_heap_base_addr_adj =
+              LLVMBuildLoad2(comp_ctx->builder, INT8_PTR_TYPE, base_addr_p,
+                             "shared_heap_base_addr_adj"))) {
+        aot_set_last_error("llvm build load failed");
+        return false;
+    }
+
+    /* Load aot_inst->e->shared_heap_start_off */
+    offset_u32 = get_module_inst_extra_offset(comp_ctx);
+#if WASM_ENABLE_JIT != 0 && WASM_ENABLE_SHARED_HEAP != 0
+    if (comp_ctx->is_jit_mode)
+        offset_u32 += offsetof(WASMModuleInstanceExtra, shared_heap_start_off);
+    else
+#endif
+        offset_u32 += offsetof(AOTModuleInstanceExtra, shared_heap_start_off);
+    offset = I32_CONST(offset_u32);
+    CHECK_LLVM_CONST(offset);
+
+    if (!(start_off_p = LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE,
+                                              func_ctx->aot_inst, &offset, 1,
+                                              "shared_heap_start_off_p"))) {
+        aot_set_last_error("llvm build inbounds gep failed");
+        return false;
+    }
+    if (!(func_ctx->shared_heap_start_off = LLVMBuildLoad2(
+              comp_ctx->builder,
+              comp_ctx->pointer_size == sizeof(uint64) ? I64_TYPE : I32_TYPE,
+              start_off_p, "shared_heap_start_off"))) {
+        aot_set_last_error("llvm build load failed");
+        return false;
+    }
+
+    if (!(cmp = LLVMBuildIsNotNull(comp_ctx->builder,
+                                   func_ctx->shared_heap_base_addr_adj,
+                                   "has_shared_heap"))) {
+        aot_set_last_error("llvm build is not null failed");
+        return false;
+    }
+
+    return true;
+fail:
+    return false;
+}
+
 static bool
 create_cur_exception(const AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
 {
@@ -1771,7 +1840,7 @@ aot_create_func_context(const AOTCompData *comp_data, AOTCompContext *comp_ctx,
         goto fail;
     }
 
-    if (comp_ctx->enable_aux_stack_frame
+    if (comp_ctx->aux_stack_frame_type
         && !create_aux_stack_frame(comp_ctx, func_ctx)) {
         goto fail;
     }
@@ -1808,6 +1877,12 @@ aot_create_func_context(const AOTCompData *comp_data, AOTCompContext *comp_ctx,
         goto fail;
     }
 
+    /* Load shared heap, shared heap start off mem32 or mem64 */
+    if (comp_ctx->enable_shared_heap
+        && !create_shared_heap_info(comp_ctx, func_ctx)) {
+        goto fail;
+    }
+
     return func_ctx;
 
 fail:
@@ -2577,8 +2652,8 @@ aot_create_comp_context(const AOTCompData *comp_data, aot_comp_option_t option)
     if (option->enable_ref_types)
         comp_ctx->enable_ref_types = true;
 
-    if (option->enable_aux_stack_frame)
-        comp_ctx->enable_aux_stack_frame = true;
+    comp_ctx->aux_stack_frame_type = option->aux_stack_frame_type;
+    comp_ctx->call_stack_features = option->call_stack_features;
 
     if (option->enable_perf_profiling)
         comp_ctx->enable_perf_profiling = true;
@@ -2619,6 +2694,9 @@ aot_create_comp_context(const AOTCompData *comp_data, aot_comp_option_t option)
     if (option->enable_gc)
         comp_ctx->enable_gc = true;
 
+    if (option->enable_shared_heap)
+        comp_ctx->enable_shared_heap = true;
+
     comp_ctx->opt_level = option->opt_level;
     comp_ctx->size_level = option->size_level;
 
@@ -2790,6 +2868,15 @@ aot_create_comp_context(const AOTCompData *comp_data, aot_comp_option_t option)
                 bh_assert(vendor_sys);
                 bh_memcpy_s(default_arch, sizeof(default_arch), default_triple,
                             (uint32)(vendor_sys - default_triple));
+                /**
+                 * On Mac M[1-9]+ LLVM will report arm64 as the
+                 * architecture, for the purposes of wamr this is the
+                 * same as aarch64v8 so we'll normalize it here.
+                 */
+                if (!strcmp(default_arch, "arm64")) {
+                    bh_strcpy_s(default_arch, sizeof(default_arch),
+                                "aarch64v8");
+                }
                 arch1 = default_arch;
 
                 LLVMDisposeMessage(default_triple);
@@ -2960,12 +3047,12 @@ aot_create_comp_context(const AOTCompData *comp_data, aot_comp_option_t option)
                                     sizeof(comp_ctx->target_arch));
 
         if (option->bounds_checks == 1 || option->bounds_checks == 0) {
-            /* Set by user */
+            /* Set by the user */
             comp_ctx->enable_bound_check =
                 (option->bounds_checks == 1) ? true : false;
         }
         else {
-            /* Unset by user, use default value */
+            /* Unset by the user, use the default value */
             if (strstr(comp_ctx->target_arch, "64")
                 && !option->is_sgx_platform) {
                 comp_ctx->enable_bound_check = false;
@@ -2975,17 +3062,17 @@ aot_create_comp_context(const AOTCompData *comp_data, aot_comp_option_t option)
             }
         }
 
-        if (comp_ctx->enable_bound_check) {
-            /* Always enable stack boundary check if `bounds-checks`
-               is enabled */
-            comp_ctx->enable_stack_bound_check = true;
-        }
-        else {
-            /* When `bounds-checks` is disabled, we set stack boundary
-               check status according to the input option */
+        if (option->stack_bounds_checks == 1
+            || option->stack_bounds_checks == 0) {
+            /* Set by the user */
             comp_ctx->enable_stack_bound_check =
                 (option->stack_bounds_checks == 1) ? true : false;
         }
+        else {
+            /* Unset by the user, use the default value, it will be the same
+             * value as the bound check */
+            comp_ctx->enable_stack_bound_check = comp_ctx->enable_bound_check;
+        }
 
         if ((comp_ctx->enable_stack_bound_check
              || comp_ctx->enable_stack_estimation)

+ 9 - 1
core/iwasm/compilation/aot_llvm.h

@@ -242,6 +242,9 @@ typedef struct AOTFuncContext {
     bool mem_space_unchanged;
     AOTCheckedAddrList checked_addr_list;
 
+    LLVMValueRef shared_heap_base_addr_adj;
+    LLVMValueRef shared_heap_start_off;
+
     LLVMBasicBlockRef got_exception_block;
     LLVMBasicBlockRef func_return_block;
     LLVMValueRef exception_id_phi;
@@ -410,7 +413,10 @@ typedef struct AOTCompContext {
     bool enable_aux_stack_check;
 
     /* Generate auxiliary stack frame */
-    bool enable_aux_stack_frame;
+    AOTStackFrameType aux_stack_frame_type;
+
+    /* Auxiliary call stack features */
+    AOTCallStackFeatures call_stack_features;
 
     /* Function performance profiling */
     bool enable_perf_profiling;
@@ -464,6 +470,8 @@ typedef struct AOTCompContext {
     /* Enable GC */
     bool enable_gc;
 
+    bool enable_shared_heap;
+
     uint32 opt_level;
     uint32 size_level;
 

+ 27 - 0
core/iwasm/compilation/aot_stack_frame.h

@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 Amazon Inc.  All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#ifndef _AOT_STACK_FRAME_H_
+#define _AOT_STACK_FRAME_H_
+
+#include "platform_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+    /* The non-imported function index of current function */
+    uint32 func_index;
+
+    /* Instruction pointer: offset to the bytecode array */
+    uint32 ip_offset;
+} AOTTinyFrame;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 150 - 0
core/iwasm/compilation/aot_stack_frame_comp.c

@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2024 Amazon Inc.  All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+#include "aot_stack_frame_comp.h"
+#include "aot_emit_exception.h"
+
+#define ADD_IN_BOUNDS_GEP(variable, type, pointer, indices, num_indices)     \
+    do {                                                                     \
+        if (!(variable =                                                     \
+                  LLVMBuildInBoundsGEP2(comp_ctx->builder, type, pointer,    \
+                                        indices, num_indices, #variable))) { \
+            aot_set_last_error("llvm build in bounds gep failed");           \
+            return false;                                                    \
+        }                                                                    \
+    } while (0)
+
+#define ADD_STORE(value, pointer)                                 \
+    do {                                                          \
+        if (!LLVMBuildStore(comp_ctx->builder, value, pointer)) { \
+            aot_set_last_error("llvm build store failed");        \
+            return false;                                         \
+        }                                                         \
+    } while (0)
+
+#define ADD_LOAD(value, type, pointer)                                         \
+    do {                                                                       \
+        if (!(value =                                                          \
+                  LLVMBuildLoad2(comp_ctx->builder, type, pointer, #value))) { \
+            aot_set_last_error("llvm build load failed");                      \
+            return false;                                                      \
+        }                                                                      \
+    } while (0)
+
+static bool
+aot_alloc_tiny_frame_for_aot_func(AOTCompContext *comp_ctx,
+                                  AOTFuncContext *func_ctx,
+                                  LLVMValueRef func_index)
+{
+    LLVMValueRef wasm_stack_top_ptr = func_ctx->wasm_stack_top_ptr,
+                 wasm_stack_top_bound = func_ctx->wasm_stack_top_bound,
+                 wasm_stack_top, cmp;
+    LLVMBasicBlockRef check_wasm_stack_succ;
+    LLVMValueRef offset;
+
+    ADD_LOAD(wasm_stack_top, INT8_PTR_TYPE, wasm_stack_top_ptr);
+
+    if (comp_ctx->call_stack_features.bounds_checks) {
+        if (!(check_wasm_stack_succ = LLVMAppendBasicBlockInContext(
+                  comp_ctx->context, func_ctx->func,
+                  "check_wasm_stack_succ"))) {
+            aot_set_last_error("llvm add basic block failed.");
+            return false;
+        }
+
+        LLVMMoveBasicBlockAfter(check_wasm_stack_succ,
+                                LLVMGetInsertBlock(comp_ctx->builder));
+
+        if (!(cmp = LLVMBuildICmp(comp_ctx->builder, LLVMIntUGE, wasm_stack_top,
+                                  wasm_stack_top_bound, "cmp"))) {
+            aot_set_last_error("llvm build icmp failed");
+            return false;
+        }
+
+        if (!(aot_emit_exception(comp_ctx, func_ctx,
+                                 EXCE_OPERAND_STACK_OVERFLOW, true, cmp,
+                                 check_wasm_stack_succ))) {
+            return false;
+        }
+    }
+
+    /* Save the func_idx on the top of the stack */
+    if (comp_ctx->call_stack_features.func_idx) {
+        ADD_STORE(func_index, wasm_stack_top);
+    }
+
+    /* increment the stack pointer */
+    INT_CONST(offset, sizeof(AOTTinyFrame), I32_TYPE, true);
+    ADD_IN_BOUNDS_GEP(wasm_stack_top, INT8_TYPE, wasm_stack_top, &offset, 1);
+    ADD_STORE(wasm_stack_top, wasm_stack_top_ptr);
+
+    return true;
+}
+
+static bool
+aot_free_tiny_frame_for_aot_func(AOTCompContext *comp_ctx,
+                                 AOTFuncContext *func_ctx)
+{
+    LLVMValueRef wasm_stack_top_ptr = func_ctx->wasm_stack_top_ptr,
+                 wasm_stack_top;
+    LLVMValueRef offset;
+
+    ADD_LOAD(wasm_stack_top, INT8_PTR_TYPE, wasm_stack_top_ptr);
+
+    INT_CONST(offset, -sizeof(AOTTinyFrame),
+              comp_ctx->pointer_size == 8 ? I64_TYPE : I32_TYPE, true);
+    ADD_IN_BOUNDS_GEP(wasm_stack_top, INT8_TYPE, wasm_stack_top, &offset, 1);
+    ADD_STORE(wasm_stack_top, wasm_stack_top_ptr);
+
+    return true;
+}
+
+bool
+aot_tiny_frame_gen_commit_ip(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
+                             LLVMValueRef ip_value)
+{
+    LLVMValueRef wasm_stack_top_ptr = func_ctx->wasm_stack_top_ptr,
+                 wasm_stack_top;
+    LLVMValueRef offset, ip_addr;
+
+    bh_assert(ip_value);
+
+    ADD_LOAD(wasm_stack_top, INT8_PTR_TYPE, wasm_stack_top_ptr);
+
+    INT_CONST(offset, -4, comp_ctx->pointer_size == 8 ? I64_TYPE : I32_TYPE,
+              true);
+    ADD_IN_BOUNDS_GEP(ip_addr, INT8_TYPE, wasm_stack_top, &offset, 1);
+
+    ADD_STORE(ip_value, ip_addr);
+
+    return true;
+}
+
+bool
+aot_alloc_frame_per_function_frame_for_aot_func(AOTCompContext *comp_ctx,
+                                                AOTFuncContext *func_ctx,
+                                                LLVMValueRef func_index)
+{
+    switch (comp_ctx->aux_stack_frame_type) {
+        case AOT_STACK_FRAME_TYPE_TINY:
+            return aot_alloc_tiny_frame_for_aot_func(comp_ctx, func_ctx,
+                                                     func_index);
+        default:
+            aot_set_last_error("unsupported mode");
+            return false;
+    }
+}
+
+bool
+aot_free_frame_per_function_frame_for_aot_func(AOTCompContext *comp_ctx,
+                                               AOTFuncContext *func_ctx)
+{
+    switch (comp_ctx->aux_stack_frame_type) {
+        case AOT_STACK_FRAME_TYPE_TINY:
+            return aot_free_tiny_frame_for_aot_func(comp_ctx, func_ctx);
+        default:
+            aot_set_last_error("unsupported mode");
+            return false;
+    }
+}

+ 33 - 0
core/iwasm/compilation/aot_stack_frame_comp.h

@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2024 Amazon Inc.  All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#ifndef _AOT_STACK_FRAME_COMP_H_
+#define _AOT_STACK_FRAME_COMP_H_
+
+#include "aot_stack_frame.h"
+#include "aot_compiler.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+bool
+aot_alloc_frame_per_function_frame_for_aot_func(AOTCompContext *comp_ctx,
+                                                AOTFuncContext *func_ctx,
+                                                LLVMValueRef func_index);
+
+bool
+aot_free_frame_per_function_frame_for_aot_func(AOTCompContext *comp_ctx,
+                                               AOTFuncContext *func_ctx);
+
+bool
+aot_tiny_frame_gen_commit_ip(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
+                             LLVMValueRef ip_value);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 46 - 1
core/iwasm/include/aot_comp_option.h

@@ -6,6 +6,49 @@
 #ifndef __AOT_COMP_OPTION_H__
 #define __AOT_COMP_OPTION_H__
 
+#include <stdint.h>
+
+typedef struct {
+    /* Enables or disables bounds checks for stack frames. When enabled, the AOT
+     * compiler generates code to check if the stack pointer is within the
+     * bounds of the current stack frame (and if not, traps). */
+    bool bounds_checks;
+
+    /* Enables or disables instruction pointer (IP) tracking. */
+    bool ip;
+
+    /* Enables or disables function index in the stack trace. Please note that
+     * function index can be recovered from the instruction pointer using
+     * ip2function.py script, so enabling this feature along with `ip` might
+     * often be redundant.
+     * This option will automatically be enabled for GC and Perf Profiling mode.
+     */
+    bool func_idx;
+
+    /* Enables or disables tracking instruction pointer of a trap. Only takes
+     * effect when `ip` is enabled. */
+    bool trap_ip;
+
+    /* Enables or disables parameters, locals and stack operands. */
+    bool values;
+
+    /* If enabled, stack frame is generated at the beginning of each
+     * function (frame-per-function mode). Otherwise, stack frame is
+     * generated before each call of a function (frame-per-call mode). */
+    bool frame_per_function;
+} AOTCallStackFeatures;
+
+void
+aot_call_stack_features_init_default(AOTCallStackFeatures *features);
+
+typedef enum {
+    AOT_STACK_FRAME_OFF = 0,
+    /* Use a small stack frame data structure (AOTTinyFrame) */
+    AOT_STACK_FRAME_TYPE_TINY,
+    /* Use a regular stack frame data structure (AOTFrame) */
+    AOT_STACK_FRAME_TYPE_STANDARD,
+} AOTStackFrameType;
+
 typedef struct AOTCompOption {
     bool is_jit_mode;
     bool is_indirect_mode;
@@ -21,7 +64,8 @@ typedef struct AOTCompOption {
     bool enable_ref_types;
     bool enable_gc;
     bool enable_aux_stack_check;
-    bool enable_aux_stack_frame;
+    AOTStackFrameType aux_stack_frame_type;
+    AOTCallStackFeatures call_stack_features;
     bool enable_perf_profiling;
     bool enable_memory_profiling;
     bool disable_llvm_intrinsics;
@@ -29,6 +73,7 @@ typedef struct AOTCompOption {
     bool enable_llvm_pgo;
     bool enable_stack_estimation;
     bool quick_invoke_c_api_import;
+    bool enable_shared_heap;
     char *use_prof_file;
     uint32_t opt_level;
     uint32_t size_level;

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

@@ -534,6 +534,10 @@ typedef struct LoadArgs {
     bool clone_wasm_binary;
     /* This option is only used by the AOT/wasm loader (see wasm_export.h) */
     bool wasm_binary_freeable;
+    /* false by default, if true, don't resolve the symbols yet. The
+       wasm_runtime_load_ex has to be followed by a wasm_runtime_resolve_symbols
+       call */
+    bool no_resolve;
     /* TODO: more fields? */
 } LoadArgs;
 #endif /* LOAD_ARGS_OPTION_DEFINED */

+ 192 - 2
core/iwasm/include/wasm_export.h

@@ -120,6 +120,10 @@ typedef struct WASMModuleInstanceCommon *wasm_module_inst_t;
 typedef void WASMFunctionInstanceCommon;
 typedef WASMFunctionInstanceCommon *wasm_function_inst_t;
 
+/* Memory instance */
+struct WASMMemoryInstance;
+typedef struct WASMMemoryInstance *wasm_memory_inst_t;
+
 /* WASM section */
 typedef struct wasm_section_t {
     struct wasm_section_t *next;
@@ -135,6 +139,9 @@ typedef struct wasm_section_t {
 struct WASMExecEnv;
 typedef struct WASMExecEnv *wasm_exec_env_t;
 
+struct WASMSharedHeap;
+typedef struct WASMSharedHeap *wasm_shared_heap_t;
+
 /* Package Type */
 typedef enum {
     Wasm_Module_Bytecode = 0,
@@ -248,6 +255,11 @@ typedef struct LoadArgs {
     const strings), making it possible to free the wasm binary buffer after
     loading. */
     bool wasm_binary_freeable;
+
+    /* false by default, if true, don't resolve the symbols yet. The
+       wasm_runtime_load_ex has to be followed by a wasm_runtime_resolve_symbols
+       call */
+    bool no_resolve;
     /* TODO: more fields? */
 } LoadArgs;
 #endif /* LOAD_ARGS_OPTION_DEFINED */
@@ -320,6 +332,10 @@ typedef enum {
     WASM_LOG_LEVEL_VERBOSE = 4
 } log_level_t;
 
+typedef struct SharedHeapInitArgs {
+    uint32_t size;
+} SharedHeapInitArgs;
+
 /**
  * Initialize the WASM runtime environment, and also initialize
  * the memory allocator with system allocator, which calls os_malloc
@@ -565,6 +581,12 @@ WASM_RUNTIME_API_EXTERN wasm_module_t
 wasm_runtime_load_ex(uint8_t *buf, uint32_t size, const LoadArgs *args,
                      char *error_buf, uint32_t error_buf_size);
 
+/**
+ * Resolve symbols for a previously loaded WASM module. Only useful when the
+ * module was loaded with LoadArgs::no_resolve set to true
+ */
+WASM_RUNTIME_API_EXTERN bool
+wasm_runtime_resolve_symbols(wasm_module_t module);
 /**
  * Load a WASM module from a specified WASM or AOT section list.
  *
@@ -939,6 +961,100 @@ WASM_RUNTIME_API_EXTERN void
 wasm_runtime_set_module_inst(wasm_exec_env_t exec_env,
                              const wasm_module_inst_t module_inst);
 
+/**
+ * @brief Lookup a memory instance by name
+ *
+ * @param module_inst The module instance
+ * @param name The name of the memory instance
+ *
+ * @return The memory instance if found, NULL otherwise
+ */
+WASM_RUNTIME_API_EXTERN wasm_memory_inst_t
+wasm_runtime_lookup_memory(const wasm_module_inst_t module_inst,
+                           const char *name);
+
+/**
+ * @brief Get the default memory instance
+ *
+ * @param module_inst The module instance
+ *
+ * @return The memory instance if found, NULL otherwise
+ */
+WASM_RUNTIME_API_EXTERN wasm_memory_inst_t
+wasm_runtime_get_default_memory(const wasm_module_inst_t module_inst);
+
+/**
+ * @brief Get a memory instance by index
+ *
+ * @param module_inst The module instance
+ * @param index The index of the memory instance
+ *
+ * @return The memory instance if found, NULL otherwise
+ */
+WASM_RUNTIME_API_EXTERN wasm_memory_inst_t
+wasm_runtime_get_memory(const wasm_module_inst_t module_inst, uint32_t index);
+
+/**
+ * @brief Get the current number of pages for a memory instance
+ *
+ * @param memory_inst The memory instance
+ *
+ * @return The current number of pages
+ */
+WASM_RUNTIME_API_EXTERN uint64_t
+wasm_memory_get_cur_page_count(const wasm_memory_inst_t memory_inst);
+
+/**
+ * @brief Get the maximum number of pages for a memory instance
+ *
+ * @param memory_inst The memory instance
+ *
+ * @return The maximum number of pages
+ */
+WASM_RUNTIME_API_EXTERN uint64_t
+wasm_memory_get_max_page_count(const wasm_memory_inst_t memory_inst);
+
+/**
+ * @brief Get the number of bytes per page for a memory instance
+ *
+ * @param memory_inst The memory instance
+ *
+ * @return The number of bytes per page
+ */
+WASM_RUNTIME_API_EXTERN uint64_t
+wasm_memory_get_bytes_per_page(const wasm_memory_inst_t memory_inst);
+
+/**
+ * @brief Get the shared status for a memory instance
+ *
+ * @param memory_inst The memory instance
+ *
+ * @return True if shared, false otherwise
+ */
+WASM_RUNTIME_API_EXTERN bool
+wasm_memory_get_shared(const wasm_memory_inst_t memory_inst);
+
+/**
+ * @brief Get the base address for a memory instance
+ *
+ * @param memory_inst The memory instance
+ *
+ * @return The base address on success, false otherwise
+ */
+WASM_RUNTIME_API_EXTERN void *
+wasm_memory_get_base_address(const wasm_memory_inst_t memory_inst);
+
+/**
+ * @brief Enlarge a memory instance by a number of pages
+ *
+ * @param memory_inst The memory instance
+ * @param inc_page_count The number of pages to add
+ *
+ * @return True if successful, false otherwise
+ */
+WASM_RUNTIME_API_EXTERN bool
+wasm_memory_enlarge(wasm_memory_inst_t memory_inst, uint64_t inc_page_count);
+
 /**
  * Call the given WASM function of a WASM module instance with
  * arguments (bytecode and AoT).
@@ -1050,8 +1166,8 @@ wasm_application_execute_main(wasm_module_inst_t module_inst, int32_t argc,
                               char *argv[]);
 
 /**
- * Find the specified function in argv[0] from a WASM module instance
- * and execute that function.
+ * Find the specified function from a WASM module instance and execute
+ * that function.
  *
  * @param module_inst the WASM module instance
  * @param name the name of the function to execute.
@@ -1639,6 +1755,26 @@ wasm_runtime_set_user_data(wasm_exec_env_t exec_env, void *user_data);
 WASM_RUNTIME_API_EXTERN void *
 wasm_runtime_get_user_data(wasm_exec_env_t exec_env);
 
+/**
+ * Set native stack boundary to execution environment, if it is set,
+ * it will be used instead of getting the boundary with the platform
+ * layer API when calling wasm functions. This is useful for some
+ * fiber cases.
+ *
+ * Note: unlike setting the boundary by runtime, this API doesn't add
+ * the WASM_STACK_GUARD_SIZE(see comments in core/config.h) to the
+ * exec_env's native_stack_boundary to reserve bytes to the native
+ * thread stack boundary, which is used to throw native stack overflow
+ * exception if the guard boundary is reached. Developer should ensure
+ * that enough guard bytes are kept.
+ *
+ * @param exec_env the execution environment
+ * @param native_stack_boundary the user data to be set
+ */
+WASM_RUNTIME_API_EXTERN void
+wasm_runtime_set_native_stack_boundary(wasm_exec_env_t exec_env,
+                                       uint8_t *native_stack_boundary);
+
 /**
  * Dump runtime memory consumption, including:
  *     Exec env memory consumption
@@ -2110,6 +2246,60 @@ wasm_runtime_detect_native_stack_overflow_size(wasm_exec_env_t exec_env,
 WASM_RUNTIME_API_EXTERN bool
 wasm_runtime_is_underlying_binary_freeable(const wasm_module_t module);
 
+/**
+ * Create a shared heap
+ *
+ * @param init_args the initialization arguments
+ * @return the shared heap created
+ */
+WASM_RUNTIME_API_EXTERN wasm_shared_heap_t
+wasm_runtime_create_shared_heap(SharedHeapInitArgs *init_args);
+
+/**
+ * Attach a shared heap to a module instance
+ *
+ * @param module_inst the module instance
+ * @param shared_heap the shared heap
+ * @return true if success, false if failed
+ */
+WASM_RUNTIME_API_EXTERN bool
+wasm_runtime_attach_shared_heap(wasm_module_inst_t module_inst,
+                                wasm_shared_heap_t shared_heap);
+
+/**
+ * Detach a shared heap from a module instance
+ *
+ * @param module_inst the module instance
+ */
+WASM_RUNTIME_API_EXTERN void
+wasm_runtime_detach_shared_heap(wasm_module_inst_t module_inst);
+
+/**
+ * Allocate memory from a shared heap
+ *
+ * @param module_inst the module instance
+ * @param size required memory size
+ * @param p_native_addr native address of allocated memory
+ *
+ * @return return the allocated memory address, which re-uses part of the wasm
+ * address space and is in the range of [UINT32 - shared_heap_size + 1, UINT32]
+ * (when the wasm memory is 32-bit) or [UINT64 - shared_heap_size + 1, UINT64]
+ * (when the wasm memory is 64-bit). Note that it is not an absolute address.
+ *         Return non-zero if success, zero if failed.
+ */
+WASM_RUNTIME_API_EXTERN uint64_t
+wasm_runtime_shared_heap_malloc(wasm_module_inst_t module_inst, uint64_t size,
+                                void **p_native_addr);
+
+/**
+ * Free the memory allocated from shared heap
+ *
+ * @param module_inst the module instance
+ * @param ptr the offset in wasm app
+ */
+WASM_RUNTIME_API_EXTERN void
+wasm_runtime_shared_heap_free(wasm_module_inst_t module_inst, uint64_t ptr);
+
 #ifdef __cplusplus
 }
 #endif

+ 12 - 2
core/iwasm/interpreter/wasm.h

@@ -93,6 +93,10 @@ extern "C" {
 #define MAX_PAGE_COUNT_FLAG 0x01
 #define SHARED_MEMORY_FLAG 0x02
 #define MEMORY64_FLAG 0x04
+#define MAX_TABLE_SIZE_FLAG 0x01
+/* the shared flag for table is not actual used now */
+#define SHARED_TABLE_FLAG 0x02
+#define TABLE64_FLAG 0x04
 
 /**
  * In the multi-memory proposal, the memarg in loads and stores are
@@ -494,6 +498,7 @@ typedef struct WASMTableType {
      * 0: no max size and not shared
      * 1: has max size
      * 2: shared
+     * 4: table64
      */
     uint8 flags;
     bool possible_grow;
@@ -520,6 +525,7 @@ typedef uint64 mem_offset_t;
 typedef uint32 mem_offset_t;
 #define PR_MEM_OFFSET PRIu32
 #endif
+typedef mem_offset_t tbl_elem_idx_t;
 
 typedef struct WASMMemory {
     uint32 flags;
@@ -976,8 +982,9 @@ struct WASMModule {
     uint64 buf_code_size;
 #endif
 
-#if WASM_ENABLE_DEBUG_INTERP != 0 || WASM_ENABLE_FAST_JIT != 0 \
-    || WASM_ENABLE_DUMP_CALL_STACK != 0 || WASM_ENABLE_JIT != 0
+#if WASM_ENABLE_DEBUG_INTERP != 0 || WASM_ENABLE_FAST_JIT != 0  \
+    || WASM_ENABLE_DUMP_CALL_STACK != 0 || WASM_ENABLE_JIT != 0 \
+    || WASM_ENABLE_WAMR_COMPILER != 0
     uint8 *load_addr;
     uint64 load_size;
 #endif
@@ -1238,6 +1245,9 @@ wasm_value_type_size_internal(uint8 value_type, uint8 pointer_size)
     else {
         bh_assert(0);
     }
+#if WASM_ENABLE_GC == 0
+    (void)pointer_size;
+#endif
     return 0;
 }
 

+ 235 - 62
core/iwasm/interpreter/wasm_interp_classic.c

@@ -46,6 +46,28 @@ typedef float64 CellType_F64;
 #define get_linear_mem_size() GET_LINEAR_MEMORY_SIZE(memory)
 #endif
 
+#if WASM_ENABLE_SHARED_HEAP != 0
+#if WASM_ENABLE_MULTI_MEMORY != 0
+/* Only enable shared heap for the default memory */
+#define is_default_memory (memidx == 0)
+#else
+#define is_default_memory true
+#endif
+#define app_addr_in_shared_heap(app_addr, bytes)                             \
+    (shared_heap && is_default_memory && (app_addr) >= shared_heap_start_off \
+     && (app_addr) <= shared_heap_end_off - bytes + 1)
+
+#define shared_heap_addr_app_to_native(app_addr, native_addr) \
+    native_addr = shared_heap_base_addr + ((app_addr)-shared_heap_start_off)
+
+#define CHECK_SHARED_HEAP_OVERFLOW(app_addr, bytes, native_addr) \
+    if (app_addr_in_shared_heap(app_addr, bytes))                \
+        shared_heap_addr_app_to_native(app_addr, native_addr);   \
+    else
+#else
+#define CHECK_SHARED_HEAP_OVERFLOW(app_addr, bytes, native_addr)
+#endif
+
 #if WASM_ENABLE_MEMORY64 == 0
 
 #if (!defined(OS_ENABLE_HW_BOUND_CHECK) \
@@ -53,6 +75,7 @@ typedef float64 CellType_F64;
 #define CHECK_MEMORY_OVERFLOW(bytes)                                           \
     do {                                                                       \
         uint64 offset1 = (uint64)offset + (uint64)addr;                        \
+        CHECK_SHARED_HEAP_OVERFLOW(offset1, bytes, maddr)                      \
         if (disable_bounds_checks || offset1 + bytes <= get_linear_mem_size()) \
             /* If offset1 is in valid range, maddr must also                   \
                be in valid range, no need to check it again. */                \
@@ -64,6 +87,7 @@ typedef float64 CellType_F64;
 #define CHECK_BULK_MEMORY_OVERFLOW(start, bytes, maddr)                        \
     do {                                                                       \
         uint64 offset1 = (uint32)(start);                                      \
+        CHECK_SHARED_HEAP_OVERFLOW(offset1, bytes, maddr)                      \
         if (disable_bounds_checks || offset1 + bytes <= get_linear_mem_size()) \
             /* App heap space is not valid space for                           \
              bulk memory operation */                                          \
@@ -71,18 +95,24 @@ typedef float64 CellType_F64;
         else                                                                   \
             goto out_of_bounds;                                                \
     } while (0)
+
 #else /* else of !defined(OS_ENABLE_HW_BOUND_CHECK) || \
          WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 */
-#define CHECK_MEMORY_OVERFLOW(bytes)                    \
-    do {                                                \
-        uint64 offset1 = (uint64)offset + (uint64)addr; \
-        maddr = memory->memory_data + offset1;          \
+
+#define CHECK_MEMORY_OVERFLOW(bytes)                      \
+    do {                                                  \
+        uint64 offset1 = (uint64)offset + (uint64)addr;   \
+        CHECK_SHARED_HEAP_OVERFLOW(offset1, bytes, maddr) \
+        maddr = memory->memory_data + offset1;            \
     } while (0)
 
-#define CHECK_BULK_MEMORY_OVERFLOW(start, bytes, maddr) \
-    do {                                                \
-        maddr = memory->memory_data + (uint32)(start);  \
+#define CHECK_BULK_MEMORY_OVERFLOW(start, bytes, maddr)   \
+    do {                                                  \
+        uint64 offset1 = (uint32)(start);                 \
+        CHECK_SHARED_HEAP_OVERFLOW(offset1, bytes, maddr) \
+        maddr = memory->memory_data + offset1;            \
     } while (0)
+
 #endif /* end of !defined(OS_ENABLE_HW_BOUND_CHECK) || \
           WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 */
 
@@ -91,6 +121,7 @@ typedef float64 CellType_F64;
 #define CHECK_MEMORY_OVERFLOW(bytes)                                        \
     do {                                                                    \
         uint64 offset1 = (uint64)offset + (uint64)addr;                     \
+        CHECK_SHARED_HEAP_OVERFLOW(offset1, bytes, maddr)                   \
         /* If memory64 is enabled, offset1, offset1 + bytes can overflow */ \
         if (disable_bounds_checks                                           \
             || (offset1 >= offset && offset1 + bytes >= offset1             \
@@ -99,9 +130,11 @@ typedef float64 CellType_F64;
         else                                                                \
             goto out_of_bounds;                                             \
     } while (0)
+
 #define CHECK_BULK_MEMORY_OVERFLOW(start, bytes, maddr)            \
     do {                                                           \
         uint64 offset1 = (uint64)(start);                          \
+        CHECK_SHARED_HEAP_OVERFLOW(offset1, bytes, maddr)          \
         /* If memory64 is enabled, offset1 + bytes can overflow */ \
         if (disable_bounds_checks                                  \
             || (offset1 + bytes >= offset1                         \
@@ -511,9 +544,9 @@ wasm_interp_get_frame_ref(WASMInterpFrame *frame)
 #endif
 
 #if WASM_ENABLE_MEMORY64 != 0
-#define PUSH_MEM_OFFSET(value)                     \
+#define COND_PUSH_TEMPLATE(cond, value)            \
     do {                                           \
-        if (is_memory64) {                         \
+        if (cond) {                                \
             PUT_I64_TO_ADDR(frame_sp, value);      \
             frame_sp += 2;                         \
         }                                          \
@@ -521,8 +554,11 @@ wasm_interp_get_frame_ref(WASMInterpFrame *frame)
             *(int32 *)frame_sp++ = (int32)(value); \
         }                                          \
     } while (0)
+#define PUSH_MEM_OFFSET(value) COND_PUSH_TEMPLATE(is_memory64, value)
+#define PUSH_TBL_ELEM_IDX(value) COND_PUSH_TEMPLATE(is_table64, value)
 #else
 #define PUSH_MEM_OFFSET(value) PUSH_I32(value)
+#define PUSH_TBL_ELEM_IDX(value) PUSH_I32(value)
 #endif
 
 #define PUSH_PAGE_COUNT(value) PUSH_MEM_OFFSET(value)
@@ -558,8 +594,10 @@ wasm_interp_get_frame_ref(WASMInterpFrame *frame)
 
 #if WASM_ENABLE_MEMORY64 != 0
 #define POP_MEM_OFFSET() (is_memory64 ? POP_I64() : POP_I32())
+#define POP_TBL_ELEM_IDX() (is_table64 ? POP_I64() : POP_I32())
 #else
 #define POP_MEM_OFFSET() POP_I32()
+#define POP_TBL_ELEM_IDX() POP_I32()
 #endif
 
 #define POP_PAGE_COUNT() POP_MEM_OFFSET()
@@ -1562,7 +1600,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
     uint8 opcode;
     uint32 i, depth, cond, count, fidx, tidx, lidx, frame_size = 0;
     uint32 all_cell_num = 0;
-    int32 val;
+    tbl_elem_idx_t val;
     uint8 *else_addr, *end_addr, *maddr = NULL;
     uint32 local_idx, local_offset, global_idx;
     uint8 local_type, *global_addr;
@@ -1602,9 +1640,26 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
     /* TODO: multi-memories for now assuming the memory idx type is consistent
      * across multi-memories */
     bool is_memory64 = false;
+    bool is_table64 = false;
     if (memory)
         is_memory64 = memory->is_memory64;
 #endif
+#if WASM_ENABLE_SHARED_HEAP != 0
+    WASMSharedHeap *shared_heap = module->e->shared_heap;
+    uint8 *shared_heap_base_addr = shared_heap ? shared_heap->base_addr : NULL;
+#if WASM_ENABLE_MEMORY64 != 0
+    uint64 shared_heap_start_off =
+        shared_heap ? (is_memory64 ? shared_heap->start_off_mem64
+                                   : shared_heap->start_off_mem32)
+                    : 0;
+    uint64 shared_heap_end_off =
+        shared_heap ? (is_memory64 ? UINT64_MAX : UINT32_MAX) : 0;
+#else
+    uint64 shared_heap_start_off =
+        shared_heap ? shared_heap->start_off_mem32 : 0;
+    uint64 shared_heap_end_off = shared_heap ? UINT32_MAX : 0;
+#endif
+#endif /* end of WASM_ENABLE_SHARED_HEAP != 0 */
 #if WASM_ENABLE_MULTI_MEMORY != 0
     uint32 memidx = 0;
     uint32 memidx_cached = (uint32)-1;
@@ -2315,7 +2370,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
 
                 /**
                  * type check. compiler will make sure all like
-                 * (call_indirect (type $x) (i32.const 1))
+                 * (call_indirect (type $x) (it.const 1))
                  * the function type has to be defined in the module also
                  * no matter it is used or not
                  */
@@ -2334,9 +2389,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                 /* clang-format on */
 
                 tbl_inst = wasm_get_table_inst(module, tbl_idx);
+#if WASM_ENABLE_MEMORY64 != 0
+                is_table64 = tbl_inst->is_table64;
+#endif
 
-                val = POP_I32();
-                if ((uint32)val >= tbl_inst->cur_size) {
+                val = POP_TBL_ELEM_IDX();
+                if (val >= tbl_inst->cur_size) {
                     wasm_set_exception(module, "undefined element");
                     goto got_exception;
                 }
@@ -2482,15 +2540,19 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
 
             HANDLE_OP(WASM_OP_TABLE_GET)
             {
-                uint32 tbl_idx, elem_idx;
+                uint32 tbl_idx;
+                tbl_elem_idx_t elem_idx;
                 WASMTableInstance *tbl_inst;
 
                 read_leb_uint32(frame_ip, frame_ip_end, tbl_idx);
                 bh_assert(tbl_idx < module->table_count);
 
                 tbl_inst = wasm_get_table_inst(module, tbl_idx);
+#if WASM_ENABLE_MEMORY64 != 0
+                is_table64 = tbl_inst->is_table64;
+#endif
 
-                elem_idx = POP_I32();
+                elem_idx = POP_TBL_ELEM_IDX();
                 if (elem_idx >= tbl_inst->cur_size) {
                     wasm_set_exception(module, "out of bounds table access");
                     goto got_exception;
@@ -2507,20 +2569,24 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
             HANDLE_OP(WASM_OP_TABLE_SET)
             {
                 WASMTableInstance *tbl_inst;
-                uint32 tbl_idx, elem_idx;
+                uint32 tbl_idx;
+                tbl_elem_idx_t elem_idx;
                 table_elem_type_t elem_val;
 
                 read_leb_uint32(frame_ip, frame_ip_end, tbl_idx);
                 bh_assert(tbl_idx < module->table_count);
 
                 tbl_inst = wasm_get_table_inst(module, tbl_idx);
+#if WASM_ENABLE_MEMORY64 != 0
+                is_table64 = tbl_inst->is_table64;
+#endif
 
 #if WASM_ENABLE_GC == 0
                 elem_val = POP_I32();
 #else
                 elem_val = POP_REF();
 #endif
-                elem_idx = POP_I32();
+                elem_idx = POP_TBL_ELEM_IDX();
                 if (elem_idx >= tbl_inst->cur_size) {
                     wasm_set_exception(module, "out of bounds table access");
                     goto got_exception;
@@ -3455,8 +3521,15 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                         str_obj = (WASMString)wasm_stringref_obj_get_value(
                             stringref_obj);
 
-                        memory_inst = module->memories[mem_idx];
-                        maddr = memory_inst->memory_data + addr;
+#if WASM_ENABLE_SHARED_HEAP != 0
+                        if (app_addr_in_shared_heap((uint64)addr, 1))
+                            shared_heap_addr_app_to_native((uint64)addr, maddr);
+                        else
+#endif
+                        {
+                            memory_inst = module->memories[mem_idx];
+                            maddr = memory_inst->memory_data + addr;
+                        }
 
                         if (opcode == WASM_OP_STRING_ENCODE_WTF16) {
                             flag = WTF16;
@@ -3623,8 +3696,15 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                         addr = POP_I32();
                         stringview_wtf8_obj = POP_REF();
 
-                        memory_inst = module->memories[mem_idx];
-                        maddr = memory_inst->memory_data + addr;
+#if WASM_ENABLE_SHARED_HEAP != 0
+                        if (app_addr_in_shared_heap((uint64)addr, 1))
+                            shared_heap_addr_app_to_native((uint64)addr, maddr);
+                        else
+#endif
+                        {
+                            memory_inst = module->memories[mem_idx];
+                            maddr = memory_inst->memory_data + addr;
+                        }
 
                         bytes_written = wasm_string_encode(
                             (WASMString)wasm_stringview_wtf8_obj_get_value(
@@ -4616,13 +4696,19 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
 
             HANDLE_OP(WASM_OP_MEMORY_GROW)
             {
-                uint32 mem_idx, delta, prev_page_count;
+                uint32 mem_idx, prev_page_count;
+                mem_offset_t delta;
 
                 read_leb_memidx(frame_ip, frame_ip_end, mem_idx);
                 prev_page_count = memory->cur_page_count;
-                delta = (uint32)POP_PAGE_COUNT();
+                delta = POP_PAGE_COUNT();
 
-                if (!wasm_enlarge_memory_with_idx(module, delta, mem_idx)) {
+                if (
+#if WASM_ENABLE_MEMORY64 != 0
+                    delta > UINT32_MAX ||
+#endif
+                    !wasm_enlarge_memory_with_idx(module, (uint32)delta,
+                                                  mem_idx)) {
                     /* failed to memory.grow, return -1 */
                     PUSH_PAGE_COUNT(-1);
                 }
@@ -5651,9 +5737,18 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
 #ifndef OS_ENABLE_HW_BOUND_CHECK
                         CHECK_BULK_MEMORY_OVERFLOW(addr, bytes, maddr);
 #else
-                        if ((uint64)(uint32)addr + bytes > linear_mem_size)
-                            goto out_of_bounds;
-                        maddr = memory->memory_data + (uint32)addr;
+#if WASM_ENABLE_SHARED_HEAP != 0
+                        if (app_addr_in_shared_heap((uint64)(uint32)addr,
+                                                    bytes))
+                            shared_heap_addr_app_to_native((uint64)(uint32)addr,
+                                                           maddr);
+                        else
+#endif
+                        {
+                            if ((uint64)(uint32)addr + bytes > linear_mem_size)
+                                goto out_of_bounds;
+                            maddr = memory->memory_data + (uint32)addr;
+                        }
 #endif
 
                         if (bh_bitmap_get_bit(module->e->common.data_dropped,
@@ -5703,15 +5798,30 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
 #if WASM_ENABLE_THREAD_MGR != 0
                         linear_mem_size = get_linear_mem_size();
 #endif
+
+                        dlen = linear_mem_size - dst;
+
                         /* dst boundary check */
 #ifndef OS_ENABLE_HW_BOUND_CHECK
                         CHECK_BULK_MEMORY_OVERFLOW(dst, len, mdst);
-#else
-                        if ((uint64)dst + len > linear_mem_size)
-                            goto out_of_bounds;
-                        mdst = memory->memory_data + dst;
+#if WASM_ENABLE_SHARED_HEAP != 0
+                        if (app_addr_in_shared_heap((uint64)dst, len))
+                            dlen = shared_heap_end_off - dst + 1;
 #endif
-                        dlen = linear_mem_size - dst;
+#else /* else of OS_ENABLE_HW_BOUND_CHECK */
+#if WASM_ENABLE_SHARED_HEAP != 0
+                        if (app_addr_in_shared_heap((uint64)dst, len)) {
+                            shared_heap_addr_app_to_native((uint64)dst, mdst);
+                            dlen = shared_heap_end_off - dst + 1;
+                        }
+                        else
+#endif
+                        {
+                            if ((uint64)dst + len > linear_mem_size)
+                                goto out_of_bounds;
+                            mdst = memory->memory_data + dst;
+                        }
+#endif /* end of OS_ENABLE_HW_BOUND_CHECK */
 
 #if WASM_ENABLE_MULTI_MEMORY != 0
                         /* src memidx */
@@ -5727,9 +5837,16 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
 #ifndef OS_ENABLE_HW_BOUND_CHECK
                         CHECK_BULK_MEMORY_OVERFLOW(src, len, msrc);
 #else
-                        if ((uint64)src + len > linear_mem_size)
-                            goto out_of_bounds;
-                        msrc = memory->memory_data + src;
+#if WASM_ENABLE_SHARED_HEAP != 0
+                        if (app_addr_in_shared_heap((uint64)src, len))
+                            shared_heap_addr_app_to_native((uint64)src, msrc);
+                        else
+#endif
+                        {
+                            if ((uint64)src + len > linear_mem_size)
+                                goto out_of_bounds;
+                            msrc = memory->memory_data + src;
+                        }
 #endif
 
 #if WASM_ENABLE_MEMORY64 == 0
@@ -5739,6 +5856,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                         /* use memmove when memory64 is enabled since len
                            may be larger than UINT32_MAX */
                         memmove(mdst, msrc, len);
+                        (void)dlen;
 #endif
                         break;
                     }
@@ -5765,9 +5883,17 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
 #ifndef OS_ENABLE_HW_BOUND_CHECK
                         CHECK_BULK_MEMORY_OVERFLOW(dst, len, mdst);
 #else
-                        if ((uint64)(uint32)dst + len > linear_mem_size)
-                            goto out_of_bounds;
-                        mdst = memory->memory_data + (uint32)dst;
+#if WASM_ENABLE_SHARED_HEAP != 0
+                        if (app_addr_in_shared_heap((uint64)(uint32)dst, len))
+                            shared_heap_addr_app_to_native((uint64)(uint32)dst,
+                                                           mdst);
+                        else
+#endif
+                        {
+                            if ((uint64)(uint32)dst + len > linear_mem_size)
+                                goto out_of_bounds;
+                            mdst = memory->memory_data + (uint32)dst;
+                        }
 #endif
 
                         memset(mdst, fill_val, len);
@@ -5777,8 +5903,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
 #if WASM_ENABLE_REF_TYPES != 0 || WASM_ENABLE_GC != 0
                     case WASM_OP_TABLE_INIT:
                     {
-                        uint32 tbl_idx, elem_idx;
-                        uint32 n, s, d;
+                        uint32 tbl_idx;
+                        tbl_elem_idx_t elem_idx, d;
+                        uint32 n, s;
                         WASMTableInstance *tbl_inst;
                         table_elem_type_t *table_elems;
                         InitializerExpression *tbl_seg_init_values = NULL,
@@ -5792,10 +5919,13 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                         bh_assert(tbl_idx < module->module->table_count);
 
                         tbl_inst = wasm_get_table_inst(module, tbl_idx);
+#if WASM_ENABLE_MEMORY64 != 0
+                        is_table64 = tbl_inst->is_table64;
+#endif
 
                         n = (uint32)POP_I32();
                         s = (uint32)POP_I32();
-                        d = (uint32)POP_I32();
+                        d = (tbl_elem_idx_t)POP_TBL_ELEM_IDX();
 
                         if (!bh_bitmap_get_bit(module->e->common.elem_dropped,
                                                elem_idx)) {
@@ -5808,8 +5938,15 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                                     .value_count;
                         }
 
-                        if (offset_len_out_of_bounds(s, n, tbl_seg_len)
-                            || offset_len_out_of_bounds(d, n,
+                        /* TODO: memory64 current implementation of table64
+                         * still assumes the max table size UINT32_MAX
+                         */
+                        if (
+#if WASM_ENABLE_MEMORY64 != 0
+                            d > UINT32_MAX ||
+#endif
+                            offset_len_out_of_bounds(s, n, tbl_seg_len)
+                            || offset_len_out_of_bounds((uint32)d, n,
                                                         tbl_inst->cur_size)) {
                             wasm_set_exception(module,
                                                "out of bounds table access");
@@ -5863,7 +6000,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                     case WASM_OP_TABLE_COPY:
                     {
                         uint32 src_tbl_idx, dst_tbl_idx;
-                        uint32 n, s, d;
+                        tbl_elem_idx_t n, s, d;
                         WASMTableInstance *src_tbl_inst, *dst_tbl_inst;
 
                         read_leb_uint32(frame_ip, frame_ip_end, dst_tbl_idx);
@@ -5876,14 +6013,29 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
 
                         src_tbl_inst = wasm_get_table_inst(module, src_tbl_idx);
 
-                        n = (uint32)POP_I32();
-                        s = (uint32)POP_I32();
-                        d = (uint32)POP_I32();
+#if WASM_ENABLE_MEMORY64 != 0
+                        is_table64 = src_tbl_inst->is_table64
+                                     && dst_tbl_inst->is_table64;
+#endif
+                        n = (tbl_elem_idx_t)POP_TBL_ELEM_IDX();
+#if WASM_ENABLE_MEMORY64 != 0
+                        is_table64 = src_tbl_inst->is_table64;
+#endif
+                        s = (tbl_elem_idx_t)POP_TBL_ELEM_IDX();
+#if WASM_ENABLE_MEMORY64 != 0
+                        is_table64 = dst_tbl_inst->is_table64;
+#endif
+                        d = (tbl_elem_idx_t)POP_TBL_ELEM_IDX();
 
-                        if (offset_len_out_of_bounds(d, n,
+                        if (
+#if WASM_ENABLE_MEMORY64 != 0
+                            n > UINT32_MAX || s > UINT32_MAX || d > UINT32_MAX
+                            ||
+#endif
+                            offset_len_out_of_bounds((uint32)d, (uint32)n,
                                                      dst_tbl_inst->cur_size)
                             || offset_len_out_of_bounds(
-                                s, n, src_tbl_inst->cur_size)) {
+                                (uint32)s, (uint32)n, src_tbl_inst->cur_size)) {
                             wasm_set_exception(module,
                                                "out of bounds table access");
                             goto got_exception;
@@ -5906,28 +6058,37 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                     case WASM_OP_TABLE_GROW:
                     {
                         WASMTableInstance *tbl_inst;
-                        uint32 tbl_idx, n, orig_tbl_sz;
+                        uint32 tbl_idx, orig_tbl_sz;
+                        tbl_elem_idx_t n;
                         table_elem_type_t init_val;
 
                         read_leb_uint32(frame_ip, frame_ip_end, tbl_idx);
                         bh_assert(tbl_idx < module->table_count);
 
                         tbl_inst = wasm_get_table_inst(module, tbl_idx);
+#if WASM_ENABLE_MEMORY64 != 0
+                        is_table64 = tbl_inst->is_table64;
+#endif
 
                         orig_tbl_sz = tbl_inst->cur_size;
 
-                        n = POP_I32();
+                        n = POP_TBL_ELEM_IDX();
 #if WASM_ENABLE_GC == 0
                         init_val = POP_I32();
 #else
                         init_val = POP_REF();
 #endif
 
-                        if (!wasm_enlarge_table(module, tbl_idx, n, init_val)) {
-                            PUSH_I32(-1);
+                        if (
+#if WASM_ENABLE_MEMORY64 != 0
+                            n > UINT32_MAX ||
+#endif
+                            !wasm_enlarge_table(module, tbl_idx, (uint32)n,
+                                                init_val)) {
+                            PUSH_TBL_ELEM_IDX(-1);
                         }
                         else {
-                            PUSH_I32(orig_tbl_sz);
+                            PUSH_TBL_ELEM_IDX(orig_tbl_sz);
                         }
                         break;
                     }
@@ -5940,13 +6101,17 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                         bh_assert(tbl_idx < module->table_count);
 
                         tbl_inst = wasm_get_table_inst(module, tbl_idx);
+#if WASM_ENABLE_MEMORY64 != 0
+                        is_table64 = tbl_inst->is_table64;
+#endif
 
-                        PUSH_I32(tbl_inst->cur_size);
+                        PUSH_TBL_ELEM_IDX(tbl_inst->cur_size);
                         break;
                     }
                     case WASM_OP_TABLE_FILL:
                     {
-                        uint32 tbl_idx, n;
+                        uint32 tbl_idx;
+                        tbl_elem_idx_t n, elem_idx;
                         WASMTableInstance *tbl_inst;
                         table_elem_type_t fill_val;
 
@@ -5954,24 +6119,32 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                         bh_assert(tbl_idx < module->table_count);
 
                         tbl_inst = wasm_get_table_inst(module, tbl_idx);
+#if WASM_ENABLE_MEMORY64 != 0
+                        is_table64 = tbl_inst->is_table64;
+#endif
 
-                        n = POP_I32();
+                        n = POP_TBL_ELEM_IDX();
 #if WASM_ENABLE_GC == 0
                         fill_val = POP_I32();
 #else
                         fill_val = POP_REF();
 #endif
-                        i = POP_I32();
+                        elem_idx = POP_TBL_ELEM_IDX();
 
-                        if (offset_len_out_of_bounds(i, n,
+                        if (
+#if WASM_ENABLE_MEMORY64 != 0
+                            n > UINT32_MAX || elem_idx > UINT32_MAX ||
+#endif
+                            offset_len_out_of_bounds((uint32)elem_idx,
+                                                     (uint32)n,
                                                      tbl_inst->cur_size)) {
                             wasm_set_exception(module,
                                                "out of bounds table access");
                             goto got_exception;
                         }
 
-                        for (; n != 0; i++, n--) {
-                            tbl_inst->elems[i] = fill_val;
+                        for (; n != 0; elem_idx++, n--) {
+                            tbl_inst->elems[elem_idx] = fill_val;
                         }
                         break;
                     }
@@ -6554,7 +6727,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
     || WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \
     || WASM_ENABLE_BULK_MEMORY != 0
             if (memory)
-                linear_mem_size = get_linear_mem_size();
+                linear_mem_size = GET_LINEAR_MEMORY_SIZE(memory);
 #endif
             if (wasm_copy_exception(module, NULL)) {
 #if WASM_ENABLE_EXCE_HANDLING != 0

+ 120 - 28
core/iwasm/interpreter/wasm_interp_fast.c

@@ -37,11 +37,28 @@ typedef float64 CellType_F64;
 #define get_linear_mem_size() GET_LINEAR_MEMORY_SIZE(memory)
 #endif
 
+#if WASM_ENABLE_SHARED_HEAP != 0
+#define app_addr_in_shared_heap(app_addr, bytes)        \
+    (shared_heap && (app_addr) >= shared_heap_start_off \
+     && (app_addr) <= shared_heap_end_off - bytes + 1)
+
+#define shared_heap_addr_app_to_native(app_addr, native_addr) \
+    native_addr = shared_heap_base_addr + ((app_addr)-shared_heap_start_off)
+
+#define CHECK_SHARED_HEAP_OVERFLOW(app_addr, bytes, native_addr) \
+    if (app_addr_in_shared_heap(app_addr, bytes))                \
+        shared_heap_addr_app_to_native(app_addr, native_addr);   \
+    else
+#else
+#define CHECK_SHARED_HEAP_OVERFLOW(app_addr, bytes, native_addr)
+#endif
+
 #if !defined(OS_ENABLE_HW_BOUND_CHECK) \
     || WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0
 #define CHECK_MEMORY_OVERFLOW(bytes)                                           \
     do {                                                                       \
         uint64 offset1 = (uint64)offset + (uint64)addr;                        \
+        CHECK_SHARED_HEAP_OVERFLOW(offset1, bytes, maddr)                      \
         if (disable_bounds_checks || offset1 + bytes <= get_linear_mem_size()) \
             /* If offset1 is in valid range, maddr must also                   \
                 be in valid range, no need to check it again. */               \
@@ -53,6 +70,7 @@ typedef float64 CellType_F64;
 #define CHECK_BULK_MEMORY_OVERFLOW(start, bytes, maddr)                        \
     do {                                                                       \
         uint64 offset1 = (uint32)(start);                                      \
+        CHECK_SHARED_HEAP_OVERFLOW(offset1, bytes, maddr)                      \
         if (disable_bounds_checks || offset1 + bytes <= get_linear_mem_size()) \
             /* App heap space is not valid space for                           \
                bulk memory operation */                                        \
@@ -61,15 +79,18 @@ typedef float64 CellType_F64;
             goto out_of_bounds;                                                \
     } while (0)
 #else
-#define CHECK_MEMORY_OVERFLOW(bytes)                    \
-    do {                                                \
-        uint64 offset1 = (uint64)offset + (uint64)addr; \
-        maddr = memory->memory_data + offset1;          \
+#define CHECK_MEMORY_OVERFLOW(bytes)                      \
+    do {                                                  \
+        uint64 offset1 = (uint64)offset + (uint64)addr;   \
+        CHECK_SHARED_HEAP_OVERFLOW(offset1, bytes, maddr) \
+        maddr = memory->memory_data + offset1;            \
     } while (0)
 
-#define CHECK_BULK_MEMORY_OVERFLOW(start, bytes, maddr) \
-    do {                                                \
-        maddr = memory->memory_data + (uint32)(start);  \
+#define CHECK_BULK_MEMORY_OVERFLOW(start, bytes, maddr)   \
+    do {                                                  \
+        uint64 offset1 = (uint32)(start);                 \
+        CHECK_SHARED_HEAP_OVERFLOW(offset1, bytes, maddr) \
+        maddr = memory->memory_data + offset1;            \
     } while (0)
 #endif /* !defined(OS_ENABLE_HW_BOUND_CHECK) \
           || WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 */
@@ -1516,6 +1537,24 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
 #if WASM_ENABLE_TAIL_CALL != 0 || WASM_ENABLE_GC != 0
     bool is_return_call = false;
 #endif
+#if WASM_ENABLE_SHARED_HEAP != 0
+    WASMSharedHeap *shared_heap = module->e ? module->e->shared_heap : NULL;
+    uint8 *shared_heap_base_addr = shared_heap ? shared_heap->base_addr : NULL;
+    /*
+#if WASM_ENABLE_MEMORY64 != 0
+    uint64 shared_heap_start_off =
+        shared_heap ? (is_memory64 ? shared_heap->start_off_mem64
+                                   : shared_heap->start_off_mem32)
+                    : 0;
+    uint64 shared_heap_end_off =
+        shared_heap ? (is_memory64 ? UINT64_MAX : UINT32_MAX) : 0;
+#else
+    */ /* TODO: uncomment the code when memory64 is enabled for fast-interp */
+    uint64 shared_heap_start_off =
+        shared_heap ? shared_heap->start_off_mem32 : 0;
+    uint64 shared_heap_end_off = shared_heap ? UINT32_MAX : 0;
+/* #endif */
+#endif /* end of WASM_ENABLE_SHARED_HEAP != 0 */
 
 #if WASM_ENABLE_LABELS_AS_VALUES != 0
 #define HANDLE_OPCODE(op) &&HANDLE_##op
@@ -2831,8 +2870,15 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                         str_obj = (WASMString)wasm_stringref_obj_get_value(
                             stringref_obj);
 
-                        memory_inst = module->memories[mem_idx];
-                        maddr = memory_inst->memory_data + addr;
+#if WASM_ENABLE_SHARED_HEAP != 0
+                        if (app_addr_in_shared_heap((uint64)addr, 1))
+                            shared_heap_addr_app_to_native((uint64)addr, maddr);
+                        else
+#endif
+                        {
+                            memory_inst = module->memories[mem_idx];
+                            maddr = memory_inst->memory_data + addr;
+                        }
 
                         if (opcode == WASM_OP_STRING_ENCODE_WTF16) {
                             flag = WTF16;
@@ -2999,8 +3045,15 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                         addr = POP_I32();
                         stringview_wtf8_obj = POP_REF();
 
-                        memory_inst = module->memories[mem_idx];
-                        maddr = memory_inst->memory_data + addr;
+#if WASM_ENABLE_SHARED_HEAP != 0
+                        if (app_addr_in_shared_heap((uint64)addr, 1))
+                            shared_heap_addr_app_to_native((uint64)addr, maddr);
+                        else
+#endif
+                        {
+                            memory_inst = module->memories[mem_idx];
+                            maddr = memory_inst->memory_data + addr;
+                        }
 
                         bytes_written = wasm_string_encode(
                             (WASMString)wasm_stringview_wtf8_obj_get_value(
@@ -4985,9 +5038,18 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
 #ifndef OS_ENABLE_HW_BOUND_CHECK
                         CHECK_BULK_MEMORY_OVERFLOW(addr, bytes, maddr);
 #else
-                        if ((uint64)(uint32)addr + bytes > linear_mem_size)
-                            goto out_of_bounds;
-                        maddr = memory->memory_data + (uint32)addr;
+#if WASM_ENABLE_SHARED_HEAP != 0
+                        if (app_addr_in_shared_heap((uint64)(uint32)addr,
+                                                    bytes))
+                            shared_heap_addr_app_to_native((uint64)(uint32)addr,
+                                                           maddr);
+                        else
+#endif
+                        {
+                            if ((uint64)(uint32)addr + bytes > linear_mem_size)
+                                goto out_of_bounds;
+                            maddr = memory->memory_data + (uint32)addr;
+                        }
 #endif
                         if (bh_bitmap_get_bit(module->e->common.data_dropped,
                                               segment)) {
@@ -5020,6 +5082,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                     {
                         uint32 dst, src, len;
                         uint8 *mdst, *msrc;
+                        uint64 dlen;
 
                         len = POP_I32();
                         src = POP_I32();
@@ -5029,22 +5092,43 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                         linear_mem_size = get_linear_mem_size();
 #endif
 
+                        dlen = linear_mem_size - dst;
+
 #ifndef OS_ENABLE_HW_BOUND_CHECK
                         CHECK_BULK_MEMORY_OVERFLOW(src, len, msrc);
                         CHECK_BULK_MEMORY_OVERFLOW(dst, len, mdst);
-#else
-                        if ((uint64)(uint32)src + len > linear_mem_size)
-                            goto out_of_bounds;
-                        msrc = memory->memory_data + (uint32)src;
+#if WASM_ENABLE_SHARED_HEAP != 0
+                        if (app_addr_in_shared_heap((uint64)dst, len))
+                            dlen = shared_heap_end_off - dst + 1;
+#endif
+#else /* else of OS_ENABLE_HW_BOUND_CHECK */
+#if WASM_ENABLE_SHARED_HEAP != 0
+                        if (app_addr_in_shared_heap((uint64)src, len))
+                            shared_heap_addr_app_to_native((uint64)src, msrc);
+                        else
+#endif
+                        {
+                            if ((uint64)(uint32)src + len > linear_mem_size)
+                                goto out_of_bounds;
+                            msrc = memory->memory_data + (uint32)src;
+                        }
 
-                        if ((uint64)(uint32)dst + len > linear_mem_size)
-                            goto out_of_bounds;
-                        mdst = memory->memory_data + (uint32)dst;
+#if WASM_ENABLE_SHARED_HEAP != 0
+                        if (app_addr_in_shared_heap((uint64)dst, len)) {
+                            shared_heap_addr_app_to_native((uint64)dst, mdst);
+                            dlen = shared_heap_end_off - dst + 1;
+                        }
+                        else
 #endif
+                        {
+                            if ((uint64)(uint32)dst + len > linear_mem_size)
+                                goto out_of_bounds;
+                            mdst = memory->memory_data + (uint32)dst;
+                        }
+#endif /* end of OS_ENABLE_HW_BOUND_CHECK */
 
                         /* allowing the destination and source to overlap */
-                        bh_memmove_s(mdst, (uint32)(linear_mem_size - dst),
-                                     msrc, len);
+                        bh_memmove_s(mdst, (uint32)dlen, msrc, len);
                         break;
                     }
                     case WASM_OP_MEMORY_FILL:
@@ -5063,9 +5147,17 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
 #ifndef OS_ENABLE_HW_BOUND_CHECK
                         CHECK_BULK_MEMORY_OVERFLOW(dst, len, mdst);
 #else
-                        if ((uint64)(uint32)dst + len > linear_mem_size)
-                            goto out_of_bounds;
-                        mdst = memory->memory_data + (uint32)dst;
+#if WASM_ENABLE_SHARED_HEAP != 0
+                        if (app_addr_in_shared_heap((uint64)(uint32)dst, len))
+                            shared_heap_addr_app_to_native((uint64)(uint32)dst,
+                                                           mdst);
+                        else
+#endif
+                        {
+                            if ((uint64)(uint32)dst + len > linear_mem_size)
+                                goto out_of_bounds;
+                            mdst = memory->memory_data + (uint32)dst;
+                        }
 #endif
 
                         memset(mdst, fill_val, len);
@@ -5902,7 +5994,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
     || WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \
     || WASM_ENABLE_BULK_MEMORY != 0
             if (memory)
-                linear_mem_size = get_linear_mem_size();
+                linear_mem_size = GET_LINEAR_MEMORY_SIZE(memory);
 #endif
             if (wasm_copy_exception(module, NULL))
                 goto got_exception;
@@ -6030,7 +6122,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
 
 #if WASM_ENABLE_LABELS_AS_VALUES != 0
 void **
-wasm_interp_get_handle_table()
+wasm_interp_get_handle_table(void)
 {
     WASMModuleInstance module;
     memset(&module, 0, sizeof(WASMModuleInstance));

+ 250 - 188
core/iwasm/interpreter/wasm_loader.c

@@ -4,8 +4,7 @@
  */
 
 #include "wasm_loader.h"
-#include "bh_common.h"
-#include "bh_log.h"
+#include "bh_platform.h"
 #include "wasm.h"
 #include "wasm_opcode.h"
 #include "wasm_runtime.h"
@@ -51,6 +50,18 @@ has_module_memory64(WASMModule *module)
 
     return false;
 }
+
+static bool
+is_table_64bit(WASMModule *module, uint32 table_idx)
+{
+    if (table_idx < module->import_table_count)
+        return !!(module->import_tables[table_idx].u.table.table_type.flags
+                  & TABLE64_FLAG);
+    else
+        return !!(module->tables[table_idx].table_type.flags & TABLE64_FLAG);
+
+    return false;
+}
 #endif
 
 static void
@@ -2201,10 +2212,14 @@ fail:
 }
 
 static void
-adjust_table_max_size(uint32 init_size, uint32 max_size_flag, uint32 *max_size)
+adjust_table_max_size(bool is_table64, uint32 init_size, uint32 max_size_flag,
+                      uint32 *max_size)
 {
     uint32 default_max_size;
 
+    /* TODO: current still use UINT32_MAX as upper limit for table size to keep
+     * ABI unchanged */
+    (void)is_table64;
     if (UINT32_MAX / 2 > init_size)
         default_max_size = init_size * 2;
     else
@@ -2246,60 +2261,6 @@ wasm_loader_find_export(const WASMModule *module, const char *module_name,
 #endif
 
 #if WASM_ENABLE_MULTI_MODULE != 0
-static WASMFunction *
-wasm_loader_resolve_function(const char *module_name, const char *function_name,
-                             const WASMFuncType *expected_function_type,
-                             char *error_buf, uint32 error_buf_size)
-{
-    WASMModuleCommon *module_reg;
-    WASMFunction *function = NULL;
-    WASMExport *export = NULL;
-    WASMModule *module = NULL;
-    WASMFuncType *target_function_type = NULL;
-
-    module_reg = wasm_runtime_find_module_registered(module_name);
-    if (!module_reg || module_reg->module_type != Wasm_Module_Bytecode) {
-        LOG_DEBUG("can not find a module named %s for function %s", module_name,
-                  function_name);
-        set_error_buf(error_buf, error_buf_size, "unknown import");
-        return NULL;
-    }
-
-    module = (WASMModule *)module_reg;
-    export =
-        wasm_loader_find_export(module, module_name, function_name,
-                                EXPORT_KIND_FUNC, error_buf, error_buf_size);
-    if (!export) {
-        return NULL;
-    }
-
-    /* resolve function type and function */
-    if (export->index < module->import_function_count) {
-        target_function_type =
-            module->import_functions[export->index].u.function.func_type;
-        function = module->import_functions[export->index]
-                       .u.function.import_func_linked;
-    }
-    else {
-        target_function_type =
-            module->functions[export->index - module->import_function_count]
-                ->func_type;
-        function =
-            module->functions[export->index - module->import_function_count];
-    }
-
-    /* check function type */
-    if (!wasm_type_equal((WASMType *)expected_function_type,
-                         (WASMType *)target_function_type, module->types,
-                         module->type_count)) {
-        LOG_DEBUG("%s.%s failed the type check", module_name, function_name);
-        set_error_buf(error_buf, error_buf_size, "incompatible import type");
-        return NULL;
-    }
-
-    return function;
-}
-
 static WASMTable *
 wasm_loader_resolve_table(const char *module_name, const char *table_name,
                           uint32 init_size, uint32 max_size, char *error_buf,
@@ -2474,7 +2435,8 @@ wasm_loader_resolve_tag(const char *module_name, const char *tag_name,
     }
 
     /* check function type */
-    if (!wasm_type_equal(expected_tag_type, tag->tag_type)) {
+    if (!wasm_type_equal(expected_tag_type, tag->tag_type, module->types,
+                         module->type_count)) {
         LOG_DEBUG("%s.%s failed the type check", module_name, tag_name);
         set_error_buf(error_buf, error_buf_size, "incompatible import type");
         return NULL;
@@ -2493,21 +2455,11 @@ static bool
 load_function_import(const uint8 **p_buf, const uint8 *buf_end,
                      const WASMModule *parent_module,
                      const char *sub_module_name, const char *function_name,
-                     WASMFunctionImport *function, char *error_buf,
-                     uint32 error_buf_size)
+                     WASMFunctionImport *function, bool no_resolve,
+                     char *error_buf, uint32 error_buf_size)
 {
     const uint8 *p = *p_buf, *p_end = buf_end;
     uint32 declare_type_index = 0;
-    WASMFuncType *declare_func_type = NULL;
-    WASMFunction *linked_func = NULL;
-#if WASM_ENABLE_MULTI_MODULE != 0
-    WASMModule *sub_module = NULL;
-    bool is_built_in_module = false;
-#endif
-    const char *linked_signature = NULL;
-    void *linked_attachment = NULL;
-    bool linked_call_conv_raw = false;
-    bool is_native_symbol = false;
 
     read_leb_uint32(p, p_end, declare_type_index);
     *p_buf = p;
@@ -2526,43 +2478,19 @@ load_function_import(const uint8 **p_buf, const uint8 *buf_end,
         parent_module->types, parent_module->type_count, declare_type_index);
 #endif
 
-    declare_func_type =
+    function->func_type =
         (WASMFuncType *)parent_module->types[declare_type_index];
 
-    /* lookup registered native symbols first */
-    linked_func = wasm_native_resolve_symbol(
-        sub_module_name, function_name, declare_func_type, &linked_signature,
-        &linked_attachment, &linked_call_conv_raw);
-    if (linked_func) {
-        is_native_symbol = true;
-    }
-#if WASM_ENABLE_MULTI_MODULE != 0
-    else {
-        if (!(is_built_in_module =
-                  wasm_runtime_is_built_in_module(sub_module_name))) {
-            sub_module = (WASMModule *)wasm_runtime_load_depended_module(
-                (WASMModuleCommon *)parent_module, sub_module_name, error_buf,
-                error_buf_size);
-        }
-        if (is_built_in_module || sub_module)
-            linked_func = wasm_loader_resolve_function(
-                sub_module_name, function_name, declare_func_type, error_buf,
-                error_buf_size);
-    }
-#endif
-
     function->module_name = (char *)sub_module_name;
     function->field_name = (char *)function_name;
-    function->func_type = declare_func_type;
-    /* func_ptr_linked is for native registered symbol */
-    function->func_ptr_linked = is_native_symbol ? linked_func : NULL;
-    function->signature = linked_signature;
-    function->attachment = linked_attachment;
-    function->call_conv_raw = linked_call_conv_raw;
-#if WASM_ENABLE_MULTI_MODULE != 0
-    function->import_module = is_native_symbol ? NULL : sub_module;
-    function->import_func_linked = is_native_symbol ? NULL : linked_func;
-#endif
+    function->attachment = NULL;
+    function->signature = NULL;
+    function->call_conv_raw = false;
+
+    /* lookup registered native symbols first */
+    if (!no_resolve) {
+        wasm_resolve_import_func(parent_module, function);
+    }
     return true;
 fail:
     return false;
@@ -2586,9 +2514,9 @@ load_table_import(const uint8 **p_buf, const uint8 *buf_end,
                   const char *table_name, WASMTableImport *table,
                   char *error_buf, uint32 error_buf_size)
 {
-    const uint8 *p = *p_buf, *p_end = buf_end;
-    uint32 declare_elem_type = 0, declare_max_size_flag = 0,
-           declare_init_size = 0, declare_max_size = 0;
+    const uint8 *p = *p_buf, *p_end = buf_end, *p_org;
+    uint32 declare_elem_type = 0, table_flag = 0, declare_init_size = 0,
+           declare_max_size = 0;
 #if WASM_ENABLE_MULTI_MODULE != 0
     WASMModule *sub_module = NULL;
     WASMTable *linked_table = NULL;
@@ -2597,6 +2525,7 @@ load_table_import(const uint8 **p_buf, const uint8 *buf_end,
     WASMRefType ref_type;
     bool need_ref_type_map;
 #endif
+    bool is_table64 = false;
 
 #if WASM_ENABLE_GC == 0
     CHECK_BUF(p, p_end, 1);
@@ -2635,23 +2564,29 @@ load_table_import(const uint8 **p_buf, const uint8 *buf_end,
 #endif
 #endif /* end of WASM_ENABLE_GC == 0 */
 
-    read_leb_uint32(p, p_end, declare_max_size_flag);
-    if (declare_max_size_flag > 1) {
-        set_error_buf(error_buf, error_buf_size, "integer too large");
+    p_org = p;
+    read_leb_uint32(p, p_end, table_flag);
+    is_table64 = table_flag & TABLE64_FLAG;
+    if (p - p_org > 1) {
+        LOG_VERBOSE("integer representation too long(import table)");
+        set_error_buf(error_buf, error_buf_size, "invalid limits flags");
+        return false;
+    }
+
+    if (!wasm_table_check_flags(table_flag, error_buf, error_buf_size, false)) {
         return false;
     }
 
     read_leb_uint32(p, p_end, declare_init_size);
-
-    if (declare_max_size_flag) {
+    if (table_flag & MAX_TABLE_SIZE_FLAG) {
         read_leb_uint32(p, p_end, declare_max_size);
         if (!check_table_max_size(declare_init_size, declare_max_size,
                                   error_buf, error_buf_size))
             return false;
     }
 
-    adjust_table_max_size(declare_init_size, declare_max_size_flag,
-                          &declare_max_size);
+    adjust_table_max_size(is_table64, declare_init_size,
+                          table_flag & MAX_TABLE_SIZE_FLAG, &declare_max_size);
 
     *p_buf = p;
 
@@ -2669,7 +2604,7 @@ load_table_import(const uint8 **p_buf, const uint8 *buf_end,
                 declare_elem_type = linked_table->table_type.elem_type;
                 declare_init_size = linked_table->table_type.init_size;
                 declare_max_size = linked_table->table_type.max_size;
-                declare_max_size_flag = linked_table->table_type.flags;
+                table_flag = linked_table->table_type.flags;
                 table->import_table_linked = linked_table;
                 table->import_module = sub_module;
             }
@@ -2678,12 +2613,17 @@ load_table_import(const uint8 **p_buf, const uint8 *buf_end,
 #endif /* WASM_ENABLE_MULTI_MODULE != 0 */
 
     /* (table (export "table") 10 20 funcref) */
+    /* (table (export "table64") 10 20 funcref) */
     /* we need this section working in wamrc */
     if (!strcmp("spectest", sub_module_name)) {
         const uint32 spectest_table_init_size = 10;
         const uint32 spectest_table_max_size = 20;
 
-        if (strcmp("table", table_name)) {
+        if (strcmp("table", table_name)
+#if WASM_ENABLE_MEMORY64 != 0
+            && strcmp("table64", table_name)
+#endif
+        ) {
             set_error_buf(error_buf, error_buf_size,
                           "incompatible import type or unknown import");
             return false;
@@ -2703,7 +2643,7 @@ load_table_import(const uint8 **p_buf, const uint8 *buf_end,
     /* now we believe all declaration are ok */
     table->table_type.elem_type = declare_elem_type;
     table->table_type.init_size = declare_init_size;
-    table->table_type.flags = declare_max_size_flag;
+    table->table_type.flags = table_flag;
     table->table_type.max_size = declare_max_size;
 
 #if WASM_ENABLE_WAMR_COMPILER != 0
@@ -2796,7 +2736,7 @@ load_memory_import(const uint8 **p_buf, const uint8 *buf_end,
     read_leb_uint32(p, p_end, mem_flag);
     is_memory64 = mem_flag & MEMORY64_FLAG;
     if (p - p_org > 1) {
-        LOG_VERBOSE("integer representation too long");
+        LOG_VERBOSE("integer representation too long(import memory)");
         set_error_buf(error_buf, error_buf_size, "invalid limits flags");
         return false;
     }
@@ -3111,6 +3051,7 @@ load_table(const uint8 **p_buf, const uint8 *buf_end, WASMModule *module,
     WASMRefType ref_type;
     bool need_ref_type_map;
 #endif
+    bool is_table64 = false;
 
 #if WASM_ENABLE_GC == 0
     CHECK_BUF(p, p_end, 1);
@@ -3148,34 +3089,20 @@ load_table(const uint8 **p_buf, const uint8 *buf_end, WASMModule *module,
 
     p_org = p;
     read_leb_uint32(p, p_end, table->table_type.flags);
-#if WASM_ENABLE_SHARED_MEMORY == 0
-    if (p - p_org > 1) {
-        set_error_buf(error_buf, error_buf_size,
-                      "integer representation too long");
-        return false;
-    }
-    if (table->table_type.flags > 1) {
-        set_error_buf(error_buf, error_buf_size, "integer too large");
-        return false;
-    }
-#else
+    is_table64 = table->table_type.flags & TABLE64_FLAG;
     if (p - p_org > 1) {
+        LOG_VERBOSE("integer representation too long(table)");
         set_error_buf(error_buf, error_buf_size, "invalid limits flags");
         return false;
     }
-    if (table->table_type.flags == 2) {
-        set_error_buf(error_buf, error_buf_size, "tables cannot be shared");
-        return false;
-    }
-    if (table->table_type.flags > 1) {
-        set_error_buf(error_buf, error_buf_size, "invalid limits flags");
+
+    if (!wasm_table_check_flags(table->table_type.flags, error_buf,
+                                error_buf_size, false)) {
         return false;
     }
-#endif
 
     read_leb_uint32(p, p_end, table->table_type.init_size);
-
-    if (table->table_type.flags) {
+    if (table->table_type.flags & MAX_TABLE_SIZE_FLAG) {
         read_leb_uint32(p, p_end, table->table_type.max_size);
         if (!check_table_max_size(table->table_type.init_size,
                                   table->table_type.max_size, error_buf,
@@ -3183,7 +3110,8 @@ load_table(const uint8 **p_buf, const uint8 *buf_end, WASMModule *module,
             return false;
     }
 
-    adjust_table_max_size(table->table_type.init_size, table->table_type.flags,
+    adjust_table_max_size(is_table64, table->table_type.init_size,
+                          table->table_type.flags & MAX_TABLE_SIZE_FLAG,
                           &table->table_type.max_size);
 
 #if WASM_ENABLE_WAMR_COMPILER != 0
@@ -3215,7 +3143,7 @@ load_memory(const uint8 **p_buf, const uint8 *buf_end, WASMMemory *memory,
     read_leb_uint32(p, p_end, memory->flags);
     is_memory64 = memory->flags & MEMORY64_FLAG;
     if (p - p_org > 1) {
-        LOG_VERBOSE("integer representation too long");
+        LOG_VERBOSE("integer representation too long(memory)");
         set_error_buf(error_buf, error_buf_size, "invalid limits flags");
         return false;
     }
@@ -3255,10 +3183,16 @@ fail:
     return false;
 }
 
+static int
+cmp_export_name(const void *a, const void *b)
+{
+    return strcmp(*(char **)a, *(char **)b);
+}
+
 static bool
 load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
-                    bool is_load_from_file_buf, char *error_buf,
-                    uint32 error_buf_size)
+                    bool is_load_from_file_buf, bool no_resolve,
+                    char *error_buf, uint32 error_buf_size)
 {
     const uint8 *p = buf, *p_end = buf_end, *p_old;
     uint32 import_count, name_len, type_index, i, u32, flags;
@@ -3441,9 +3375,10 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
                 case IMPORT_KIND_FUNC: /* import function */
                     bh_assert(import_functions);
                     import = import_functions++;
-                    if (!load_function_import(
-                            &p, p_end, module, sub_module_name, field_name,
-                            &import->u.function, error_buf, error_buf_size)) {
+                    if (!load_function_import(&p, p_end, module,
+                                              sub_module_name, field_name,
+                                              &import->u.function, no_resolve,
+                                              error_buf, error_buf_size)) {
                         return false;
                     }
                     break;
@@ -4124,17 +4059,53 @@ fail:
     return false;
 }
 
+static bool
+check_duplicate_exports(WASMModule *module, char *error_buf,
+                        uint32 error_buf_size)
+{
+    uint32 i;
+    bool result = false;
+    char *names_buf[32], **names = names_buf;
+
+    if (module->export_count > 32) {
+        names = loader_malloc(module->export_count * sizeof(char *), error_buf,
+                              error_buf_size);
+        if (!names) {
+            return result;
+        }
+    }
+
+    for (i = 0; i < module->export_count; i++) {
+        names[i] = module->exports[i].name;
+    }
+
+    qsort(names, module->export_count, sizeof(char *), cmp_export_name);
+
+    for (i = 1; i < module->export_count; i++) {
+        if (!strcmp(names[i], names[i - 1])) {
+            set_error_buf(error_buf, error_buf_size, "duplicate export name");
+            goto cleanup;
+        }
+    }
+
+    result = true;
+cleanup:
+    if (module->export_count > 32) {
+        wasm_runtime_free(names);
+    }
+    return result;
+}
+
 static bool
 load_export_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
                     bool is_load_from_file_buf, char *error_buf,
                     uint32 error_buf_size)
 {
     const uint8 *p = buf, *p_end = buf_end;
-    uint32 export_count, i, j, index;
+    uint32 export_count, i, index;
     uint64 total_size;
     uint32 str_len;
     WASMExport *export;
-    const char *name;
 
     read_leb_uint32(p, p_end, export_count);
 
@@ -4160,15 +4131,6 @@ load_export_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
             read_leb_uint32(p, p_end, str_len);
             CHECK_BUF(p, p_end, str_len);
 
-            for (j = 0; j < i; j++) {
-                name = module->exports[j].name;
-                if (strlen(name) == str_len && memcmp(name, p, str_len) == 0) {
-                    set_error_buf(error_buf, error_buf_size,
-                                  "duplicate export name");
-                    return false;
-                }
-            }
-
             if (!(export->name = wasm_const_str_list_insert(
                       p, str_len, module, is_load_from_file_buf, error_buf,
                       error_buf_size))) {
@@ -4241,6 +4203,10 @@ load_export_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
                     return false;
             }
         }
+
+        if (!check_duplicate_exports(module, error_buf, error_buf_size)) {
+            return false;
+        }
     }
 
     if (p != p_end) {
@@ -4488,6 +4454,7 @@ load_table_segment_section(const uint8 *buf, const uint8 *buf_end,
                            uint32 error_buf_size)
 {
     const uint8 *p = buf, *p_end = buf_end;
+    uint8 table_elem_idx_type;
     uint32 table_segment_count, i;
     uint64 total_size;
     WASMTableSeg *table_segment;
@@ -4510,6 +4477,7 @@ load_table_segment_section(const uint8 *buf, const uint8 *buf_end,
                               "invalid elements segment kind");
                 return false;
             }
+            table_elem_idx_type = VALUE_TYPE_I32;
 
 #if WASM_ENABLE_REF_TYPES != 0 || WASM_ENABLE_GC != 0
             read_leb_uint32(p, p_end, table_segment->mode);
@@ -4545,9 +4513,17 @@ load_table_segment_section(const uint8 *buf, const uint8 *buf_end,
                     if (!check_table_index(module, table_segment->table_index,
                                            error_buf, error_buf_size))
                         return false;
-                    if (!load_init_expr(
-                            module, &p, p_end, &table_segment->base_offset,
-                            VALUE_TYPE_I32, NULL, error_buf, error_buf_size))
+
+#if WASM_ENABLE_MEMORY64 != 0
+                    table_elem_idx_type =
+                        is_table_64bit(module, table_segment->table_index)
+                            ? VALUE_TYPE_I64
+                            : VALUE_TYPE_I32;
+#endif
+                    if (!load_init_expr(module, &p, p_end,
+                                        &table_segment->base_offset,
+                                        table_elem_idx_type, NULL, error_buf,
+                                        error_buf_size))
                         return false;
 
                     if (table_segment->mode == 0) {
@@ -4595,9 +4571,16 @@ load_table_segment_section(const uint8 *buf, const uint8 *buf_end,
                                           &table_segment->table_index,
                                           error_buf, error_buf_size))
                         return false;
-                    if (!load_init_expr(
-                            module, &p, p_end, &table_segment->base_offset,
-                            VALUE_TYPE_I32, NULL, error_buf, error_buf_size))
+#if WASM_ENABLE_MEMORY64 != 0
+                    table_elem_idx_type =
+                        is_table_64bit(module, table_segment->table_index)
+                            ? VALUE_TYPE_I64
+                            : VALUE_TYPE_I32;
+#endif
+                    if (!load_init_expr(module, &p, p_end,
+                                        &table_segment->base_offset,
+                                        table_elem_idx_type, NULL, error_buf,
+                                        error_buf_size))
                         return false;
                     if (!load_elem_type(module, &p, p_end,
                                         &table_segment->elem_type,
@@ -4649,7 +4632,7 @@ load_table_segment_section(const uint8 *buf, const uint8 *buf_end,
                                   "unknown element segment kind");
                     return false;
             }
-#else  /* else of WASM_ENABLE_REF_TYPES != 0 || WASM_ENABLE_GC != 0 */
+#else /* else of WASM_ENABLE_REF_TYPES != 0 || WASM_ENABLE_GC != 0 */
             /*
              * like:      00  41 05 0b               04 00 01 00 01
              * for: (elem 0   (offset (i32.const 5)) $f1 $f2 $f1 $f2)
@@ -4658,8 +4641,14 @@ load_table_segment_section(const uint8 *buf, const uint8 *buf_end,
                                   &table_segment->table_index, error_buf,
                                   error_buf_size))
                 return false;
+#if WASM_ENABLE_MEMORY64 != 0
+            table_elem_idx_type =
+                is_table_64bit(module, table_segment->table_index)
+                    ? VALUE_TYPE_I64
+                    : VALUE_TYPE_I32;
+#endif
             if (!load_init_expr(module, &p, p_end, &table_segment->base_offset,
-                                VALUE_TYPE_I32, NULL, error_buf,
+                                table_elem_idx_type, NULL, error_buf,
                                 error_buf_size))
                 return false;
             if (!load_func_index_vec(&p, p_end, module, table_segment,
@@ -4674,6 +4663,16 @@ load_table_segment_section(const uint8 *buf, const uint8 *buf_end,
                 return false;
 #endif /* end of WASM_ENABLE_REF_TYPES != 0 || WASM_ENABLE_GC != 0 */
 
+#if WASM_ENABLE_MEMORY64 != 0
+            if (table_elem_idx_type == VALUE_TYPE_I64
+                && table_segment->base_offset.u.u64 > UINT32_MAX) {
+                set_error_buf(error_buf, error_buf_size,
+                              "In table64, table base offset can't be "
+                              "larger than UINT32_MAX");
+                return false;
+            }
+#endif
+
 #if WASM_ENABLE_WAMR_COMPILER != 0
             if (table_segment->elem_type == VALUE_TYPE_EXTERNREF)
                 module->is_ref_types_used = true;
@@ -5406,7 +5405,8 @@ init_llvm_jit_functions_stage1(WASMModule *module, char *error_buf,
     option.enable_aux_stack_check = true;
 #if WASM_ENABLE_PERF_PROFILING != 0 || WASM_ENABLE_DUMP_CALL_STACK != 0 \
     || WASM_ENABLE_AOT_STACK_FRAME != 0
-    option.enable_aux_stack_frame = true;
+    option.aux_stack_frame_type = AOT_STACK_FRAME_TYPE_STANDARD;
+    aot_call_stack_features_init_default(&option.call_stack_features);
 #endif
 #if WASM_ENABLE_PERF_PROFILING != 0
     option.enable_perf_profiling = true;
@@ -5415,6 +5415,9 @@ init_llvm_jit_functions_stage1(WASMModule *module, char *error_buf,
     option.enable_memory_profiling = true;
     option.enable_stack_estimation = true;
 #endif
+#if WASM_ENABLE_SHARED_HEAP != 0
+    option.enable_shared_heap = true;
+#endif
 
     module->comp_ctx = aot_create_comp_context(module->comp_data, &option);
     if (!module->comp_ctx) {
@@ -5750,7 +5753,7 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func,
 
 #if WASM_ENABLE_FAST_INTERP != 0 && WASM_ENABLE_LABELS_AS_VALUES != 0
 void **
-wasm_interp_get_handle_table();
+wasm_interp_get_handle_table(void);
 
 static void **handle_table;
 #endif
@@ -5758,7 +5761,7 @@ static void **handle_table;
 static bool
 load_from_sections(WASMModule *module, WASMSection *sections,
                    bool is_load_from_file_buf, bool wasm_binary_freeable,
-                   char *error_buf, uint32 error_buf_size)
+                   bool no_resolve, char *error_buf, uint32 error_buf_size)
 {
     WASMExport *export;
     WASMSection *section = sections;
@@ -5815,8 +5818,8 @@ load_from_sections(WASMModule *module, WASMSection *sections,
                 break;
             case SECTION_TYPE_IMPORT:
                 if (!load_import_section(buf, buf_end, module,
-                                         reuse_const_strings, error_buf,
-                                         error_buf_size))
+                                         reuse_const_strings, no_resolve,
+                                         error_buf, error_buf_size))
                     return false;
                 break;
             case SECTION_TYPE_FUNC:
@@ -6195,6 +6198,12 @@ load_from_sections(WASMModule *module, WASMSection *sections,
 #endif
     }
 
+#if WASM_ENABLE_MEMORY64 != 0
+    if (!check_memory64_flags_consistency(module, error_buf, error_buf_size,
+                                          false))
+        return false;
+#endif
+
     calculate_global_data_offset(module);
 
 #if WASM_ENABLE_FAST_JIT != 0
@@ -6341,7 +6350,7 @@ wasm_loader_load_from_sections(WASMSection *section_list, char *error_buf,
     if (!module)
         return NULL;
 
-    if (!load_from_sections(module, section_list, false, true, error_buf,
+    if (!load_from_sections(module, section_list, false, true, false, error_buf,
                             error_buf_size)) {
         wasm_loader_unload(module);
         return NULL;
@@ -6486,7 +6495,8 @@ static union {
 
 static bool
 load(const uint8 *buf, uint32 size, WASMModule *module,
-     bool wasm_binary_freeable, char *error_buf, uint32 error_buf_size)
+     bool wasm_binary_freeable, bool no_resolve, char *error_buf,
+     uint32 error_buf_size)
 {
     const uint8 *buf_end = buf + size;
     const uint8 *p = buf, *p_end = buf_end;
@@ -6517,7 +6527,7 @@ load(const uint8 *buf, uint32 size, WASMModule *module,
 
     if (!create_sections(buf, size, &section_list, error_buf, error_buf_size)
         || !load_from_sections(module, section_list, true, wasm_binary_freeable,
-                               error_buf, error_buf_size)) {
+                               no_resolve, error_buf, error_buf_size)) {
         destroy_sections(section_list);
         return false;
     }
@@ -6693,8 +6703,8 @@ wasm_loader_load(uint8 *buf, uint32 size,
     module->load_size = size;
 #endif
 
-    if (!load(buf, size, module, args->wasm_binary_freeable, error_buf,
-              error_buf_size)) {
+    if (!load(buf, size, module, args->wasm_binary_freeable, args->no_resolve,
+              error_buf, error_buf_size)) {
         goto fail;
     }
 
@@ -9692,6 +9702,7 @@ fail:
 #define POP_REF(Type) TEMPLATE_POP_REF(Type)
 #define PUSH_MEM_OFFSET() TEMPLATE_PUSH_REF(mem_offset_type)
 #define PUSH_PAGE_COUNT() PUSH_MEM_OFFSET()
+#define PUSH_TBL_ELEM_IDX() TEMPLATE_PUSH_REF(table_elem_idx_type)
 
 #define POP_I32() TEMPLATE_POP(I32)
 #define POP_F32() TEMPLATE_POP(F32)
@@ -9702,6 +9713,7 @@ fail:
 #define POP_EXTERNREF() TEMPLATE_POP(EXTERNREF)
 #define POP_STRINGREF() TEMPLATE_POP(STRINGREF)
 #define POP_MEM_OFFSET() TEMPLATE_POP_REF(mem_offset_type)
+#define POP_TBL_ELEM_IDX() TEMPLATE_POP_REF(table_elem_idx_type)
 
 #if WASM_ENABLE_FAST_INTERP != 0
 
@@ -10887,7 +10899,8 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func,
 {
     uint8 *p = func->code, *p_end = func->code + func->code_size, *p_org;
     uint32 param_count, local_count, global_count;
-    uint8 *param_types, *local_types, local_type, global_type, mem_offset_type;
+    uint8 *param_types, *local_types, local_type, global_type, mem_offset_type,
+        table_elem_idx_type;
     BlockType func_block_type;
     uint16 *local_offsets, local_offset;
     uint32 type_idx, func_idx, local_idx, global_idx, table_idx;
@@ -10922,6 +10935,7 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func,
     mem_offset_type = is_memory64 ? VALUE_TYPE_I64 : VALUE_TYPE_I32;
 #else
     mem_offset_type = VALUE_TYPE_I32;
+    table_elem_idx_type = VALUE_TYPE_I32;
 #endif
     uint32 memidx;
 
@@ -12081,8 +12095,13 @@ re_scan:
                 emit_uint32(loader_ctx, table_idx);
 #endif
 
+#if WASM_ENABLE_MEMORY64 != 0
+                table_elem_idx_type = is_table_64bit(module, table_idx)
+                                          ? VALUE_TYPE_I64
+                                          : VALUE_TYPE_I32;
+#endif
                 /* skip elem idx */
-                POP_I32();
+                POP_TBL_ELEM_IDX();
 
                 if (type_idx >= module->type_count) {
                     set_error_buf(error_buf, error_buf_size, "unknown type");
@@ -12459,8 +12478,8 @@ re_scan:
                 break;
             }
 
-            /* table.get x. tables[x]. [i32] -> [t] */
-            /* table.set x. tables[x]. [i32 t] -> [] */
+            /* table.get x. tables[x]. [it] -> [t] */
+            /* table.set x. tables[x]. [it t] -> [] */
             case WASM_OP_TABLE_GET:
             case WASM_OP_TABLE_SET:
             {
@@ -12491,8 +12510,13 @@ re_scan:
                 emit_uint32(loader_ctx, table_idx);
 #endif
 
+#if WASM_ENABLE_MEMORY64 != 0
+                table_elem_idx_type = is_table_64bit(module, table_idx)
+                                          ? VALUE_TYPE_I64
+                                          : VALUE_TYPE_I32;
+#endif
                 if (opcode == WASM_OP_TABLE_GET) {
-                    POP_I32();
+                    POP_TBL_ELEM_IDX();
 #if WASM_ENABLE_FAST_INTERP != 0
                     PUSH_OFFSET_TYPE(decl_ref_type);
 #endif
@@ -12503,7 +12527,7 @@ re_scan:
                     POP_OFFSET_TYPE(decl_ref_type);
 #endif
                     POP_TYPE(decl_ref_type);
-                    POP_I32();
+                    POP_TBL_ELEM_IDX();
                 }
 
 #if WASM_ENABLE_WAMR_COMPILER != 0
@@ -14786,7 +14810,12 @@ re_scan:
 #endif
                         POP_I32();
                         POP_I32();
-                        POP_I32();
+#if WASM_ENABLE_MEMORY64 != 0
+                        table_elem_idx_type = is_table_64bit(module, table_idx)
+                                                  ? VALUE_TYPE_I64
+                                                  : VALUE_TYPE_I32;
+#endif
+                        POP_TBL_ELEM_IDX();
 
 #if WASM_ENABLE_WAMR_COMPILER != 0
                         module->is_ref_types_used = true;
@@ -14811,7 +14840,8 @@ re_scan:
                     }
                     case WASM_OP_TABLE_COPY:
                     {
-                        uint8 src_type, dst_type;
+                        uint8 src_type, dst_type, src_tbl_idx_type,
+                            dst_tbl_idx_type, min_tbl_idx_type;
 #if WASM_ENABLE_GC != 0
                         WASMRefType *src_ref_type = NULL, *dst_ref_type = NULL;
 #endif
@@ -14857,9 +14887,31 @@ re_scan:
                         emit_uint32(loader_ctx, dst_tbl_idx);
                         emit_uint32(loader_ctx, src_tbl_idx);
 #endif
-                        POP_I32();
-                        POP_I32();
-                        POP_I32();
+
+#if WASM_ENABLE_MEMORY64 != 0
+                        src_tbl_idx_type = is_table_64bit(module, src_tbl_idx)
+                                               ? VALUE_TYPE_I64
+                                               : VALUE_TYPE_I32;
+                        dst_tbl_idx_type = is_table_64bit(module, dst_tbl_idx)
+                                               ? VALUE_TYPE_I64
+                                               : VALUE_TYPE_I32;
+                        min_tbl_idx_type =
+                            (src_tbl_idx_type == VALUE_TYPE_I32
+                             || dst_tbl_idx_type == VALUE_TYPE_I32)
+                                ? VALUE_TYPE_I32
+                                : VALUE_TYPE_I64;
+#else
+                        src_tbl_idx_type = VALUE_TYPE_I32;
+                        dst_tbl_idx_type = VALUE_TYPE_I32;
+                        min_tbl_idx_type = VALUE_TYPE_I32;
+#endif
+
+                        table_elem_idx_type = min_tbl_idx_type;
+                        POP_TBL_ELEM_IDX();
+                        table_elem_idx_type = src_tbl_idx_type;
+                        POP_TBL_ELEM_IDX();
+                        table_elem_idx_type = dst_tbl_idx_type;
+                        POP_TBL_ELEM_IDX();
 
 #if WASM_ENABLE_WAMR_COMPILER != 0
                         module->is_ref_types_used = true;
@@ -14879,7 +14931,12 @@ re_scan:
                         emit_uint32(loader_ctx, table_idx);
 #endif
 
-                        PUSH_I32();
+#if WASM_ENABLE_MEMORY64 != 0
+                        table_elem_idx_type = is_table_64bit(module, table_idx)
+                                                  ? VALUE_TYPE_I64
+                                                  : VALUE_TYPE_I32;
+#endif
+                        PUSH_TBL_ELEM_IDX();
 
 #if WASM_ENABLE_WAMR_COMPILER != 0
                         module->is_ref_types_used = true;
@@ -14928,15 +14985,20 @@ re_scan:
                         emit_uint32(loader_ctx, table_idx);
 #endif
 
-                        POP_I32();
+#if WASM_ENABLE_MEMORY64 != 0
+                        table_elem_idx_type = is_table_64bit(module, table_idx)
+                                                  ? VALUE_TYPE_I64
+                                                  : VALUE_TYPE_I32;
+#endif
+                        POP_TBL_ELEM_IDX();
 #if WASM_ENABLE_FAST_INTERP != 0
                         POP_OFFSET_TYPE(decl_type);
 #endif
                         POP_TYPE(decl_type);
                         if (opcode1 == WASM_OP_TABLE_GROW)
-                            PUSH_I32();
+                            PUSH_TBL_ELEM_IDX();
                         else
-                            POP_I32();
+                            POP_TBL_ELEM_IDX();
 
 #if WASM_ENABLE_WAMR_COMPILER != 0
                         module->is_ref_types_used = true;

+ 182 - 36
core/iwasm/interpreter/wasm_mini_loader.c

@@ -33,12 +33,25 @@ has_module_memory64(WASMModule *module)
     /* TODO: multi-memories for now assuming the memory idx type is consistent
      * across multi-memories */
     if (module->import_memory_count > 0)
-        return !!(module->import_memories[0].u.mem_type.flags & MEMORY64_FLAG);
+        return !!(module->import_memories[0].u.memory.mem_type.flags
+                  & MEMORY64_FLAG);
     else if (module->memory_count > 0)
         return !!(module->memories[0].flags & MEMORY64_FLAG);
 
     return false;
 }
+
+static bool
+is_table_64bit(WASMModule *module, uint32 table_idx)
+{
+    if (table_idx < module->import_table_count)
+        return !!(module->import_tables[table_idx].u.table.table_type.flags
+                  & TABLE64_FLAG);
+    else
+        return !!(module->tables[table_idx].table_type.flags & TABLE64_FLAG);
+
+    return false;
+}
 #endif
 
 static void
@@ -577,11 +590,15 @@ load_type_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
 }
 
 static void
-adjust_table_max_size(uint32 init_size, uint32 max_size_flag, uint32 *max_size)
+adjust_table_max_size(bool is_table64, uint32 init_size, uint32 max_size_flag,
+                      uint32 *max_size)
 {
     uint32 default_max_size = init_size * 2 > WASM_TABLE_MAX_SIZE
                                   ? init_size * 2
                                   : WASM_TABLE_MAX_SIZE;
+    /* TODO: current still use UINT32_MAX as upper limit for table size to keep
+     * ABI unchanged */
+    (void)is_table64;
 
     if (max_size_flag) {
         /* module defines the table limitation */
@@ -642,8 +659,8 @@ load_table_import(const uint8 **p_buf, const uint8 *buf_end,
                   char *error_buf, uint32 error_buf_size)
 {
     const uint8 *p = *p_buf, *p_end = buf_end;
-    uint32 declare_elem_type = 0, declare_max_size_flag = 0,
-           declare_init_size = 0, declare_max_size = 0;
+    uint32 declare_elem_type = 0, table_flag = 0, declare_init_size = 0,
+           declare_max_size = 0;
 
     CHECK_BUF(p, p_end, 1);
     /* 0x70 or 0x6F */
@@ -654,24 +671,29 @@ load_table_import(const uint8 **p_buf, const uint8 *buf_end,
 #endif
     );
 
-    read_leb_uint32(p, p_end, declare_max_size_flag);
+    read_leb_uint32(p, p_end, table_flag);
+
+    if (!wasm_table_check_flags(table_flag, error_buf, error_buf_size, false)) {
+        return false;
+    }
+
     read_leb_uint32(p, p_end, declare_init_size);
-    if (declare_max_size_flag & 1) {
+    if (table_flag & MAX_TABLE_SIZE_FLAG) {
         read_leb_uint32(p, p_end, declare_max_size);
         bh_assert(table->table_type.init_size <= table->table_type.max_size);
     }
 
-    adjust_table_max_size(declare_init_size, declare_max_size_flag,
-                          &declare_max_size);
+    adjust_table_max_size(table_flag & TABLE64_FLAG, declare_init_size,
+                          table_flag & MAX_TABLE_SIZE_FLAG, &declare_max_size);
     *p_buf = p;
 
-    bh_assert(
-        !((declare_max_size_flag & 1) && declare_init_size > declare_max_size));
+    bh_assert(!((table_flag & MAX_TABLE_SIZE_FLAG)
+                && declare_init_size > declare_max_size));
 
     /* now we believe all declaration are ok */
     table->table_type.elem_type = declare_elem_type;
     table->table_type.init_size = declare_init_size;
-    table->table_type.flags = declare_max_size_flag;
+    table->table_type.flags = table_flag;
     table->table_type.max_size = declare_max_size;
     return true;
 }
@@ -789,16 +811,22 @@ load_table(const uint8 **p_buf, const uint8 *buf_end, WASMTable *table,
     p_org = p;
     read_leb_uint32(p, p_end, table->table_type.flags);
     bh_assert(p - p_org <= 1);
-    bh_assert(table->table_type.flags <= 1);
     (void)p_org;
 
+    if (!wasm_table_check_flags(table->table_type.flags, error_buf,
+                                error_buf_size, false)) {
+        return false;
+    }
+
     read_leb_uint32(p, p_end, table->table_type.init_size);
-    if (table->table_type.flags == 1) {
+    if (table->table_type.flags == MAX_TABLE_SIZE_FLAG) {
         read_leb_uint32(p, p_end, table->table_type.max_size);
         bh_assert(table->table_type.init_size <= table->table_type.max_size);
     }
 
-    adjust_table_max_size(table->table_type.init_size, table->table_type.flags,
+    adjust_table_max_size(table->table_type.flags & TABLE64_FLAG,
+                          table->table_type.init_size,
+                          table->table_type.flags & MAX_TABLE_SIZE_FLAG,
                           &table->table_type.max_size);
 
     *p_buf = p;
@@ -1575,6 +1603,7 @@ load_table_segment_section(const uint8 *buf, const uint8 *buf_end,
                            uint32 error_buf_size)
 {
     const uint8 *p = buf, *p_end = buf_end;
+    uint8 table_elem_idx_type;
     uint32 table_segment_count, i, table_index, function_count;
     uint64 total_size;
     WASMTableSeg *table_segment;
@@ -1592,6 +1621,7 @@ load_table_segment_section(const uint8 *buf, const uint8 *buf_end,
         table_segment = module->table_segments;
         for (i = 0; i < table_segment_count; i++, table_segment++) {
             bh_assert(p < p_end);
+            table_elem_idx_type = VALUE_TYPE_I32;
 
 #if WASM_ENABLE_REF_TYPES != 0
             read_leb_uint32(p, p_end, table_segment->mode);
@@ -1608,9 +1638,15 @@ load_table_segment_section(const uint8 *buf, const uint8 *buf_end,
                                            error_buf, error_buf_size))
                         return false;
 
+#if WASM_ENABLE_MEMORY64 != 0
+                    table_elem_idx_type =
+                        is_table_64bit(module, table_segment->table_index)
+                            ? VALUE_TYPE_I64
+                            : VALUE_TYPE_I32;
+#endif
                     if (!load_init_expr(
                             module, &p, p_end, &table_segment->base_offset,
-                            VALUE_TYPE_I32, error_buf, error_buf_size))
+                            table_elem_idx_type, error_buf, error_buf_size))
                         return false;
 
                     if (table_segment->mode == 0) {
@@ -1646,9 +1682,15 @@ load_table_segment_section(const uint8 *buf, const uint8 *buf_end,
                                           &table_segment->table_index,
                                           error_buf, error_buf_size))
                         return false;
+#if WASM_ENABLE_MEMORY64 != 0
+                    table_elem_idx_type =
+                        is_table_64bit(module, table_segment->table_index)
+                            ? VALUE_TYPE_I64
+                            : VALUE_TYPE_I32;
+#endif
                     if (!load_init_expr(
                             module, &p, p_end, &table_segment->base_offset,
-                            VALUE_TYPE_I32, error_buf, error_buf_size))
+                            table_elem_idx_type, error_buf, error_buf_size))
                         return false;
                     if (!load_elem_type(&p, p_end, &table_segment->elem_type,
                                         table_segment->mode == 2 ? true : false,
@@ -1691,13 +1733,29 @@ load_table_segment_section(const uint8 *buf, const uint8 *buf_end,
                                   &table_segment->table_index, error_buf,
                                   error_buf_size))
                 return false;
+#if WASM_ENABLE_MEMORY64 != 0
+            table_elem_idx_type =
+                is_table_64bit(module, table_segment->table_index)
+                    ? VALUE_TYPE_I64
+                    : VALUE_TYPE_I32;
+#endif
             if (!load_init_expr(module, &p, p_end, &table_segment->base_offset,
-                                VALUE_TYPE_I32, error_buf, error_buf_size))
+                                table_elem_idx_type, error_buf, error_buf_size))
                 return false;
             if (!load_func_index_vec(&p, p_end, module, table_segment,
                                      error_buf, error_buf_size))
                 return false;
 #endif /* WASM_ENABLE_REF_TYPES != 0 */
+
+#if WASM_ENABLE_MEMORY64 != 0
+            if (table_elem_idx_type == VALUE_TYPE_I64
+                && table_segment->base_offset.u.u64 > UINT32_MAX) {
+                set_error_buf(error_buf, error_buf_size,
+                              "In table64, table base offset can't be "
+                              "larger than UINT32_MAX");
+                return false;
+            }
+#endif
         }
     }
 
@@ -1781,8 +1839,8 @@ load_data_segment_section(const uint8 *buf, const uint8 *buf_end,
                 /* This memory_flag is from memory instead of data segment */
                 uint8 memory_flag;
                 if (module->import_memory_count > 0) {
-                    memory_flag =
-                        module->import_memories[mem_index].u.mem_type.flags;
+                    memory_flag = module->import_memories[mem_index]
+                                      .u.memory.mem_type.flags;
                 }
                 else {
                     memory_flag =
@@ -2148,7 +2206,8 @@ init_llvm_jit_functions_stage1(WASMModule *module, char *error_buf,
     option.enable_aux_stack_check = true;
 #if WASM_ENABLE_PERF_PROFILING != 0 || WASM_ENABLE_DUMP_CALL_STACK != 0 \
     || WASM_ENABLE_AOT_STACK_FRAME != 0
-    option.enable_aux_stack_frame = true;
+    option.aux_stack_frame_type = AOT_STACK_FRAME_TYPE_STANDARD;
+    aot_call_stack_features_init_default(&option.call_stack_features);
 #endif
 #if WASM_ENABLE_PERF_PROFILING != 0
     option.enable_perf_profiling = true;
@@ -2157,6 +2216,9 @@ init_llvm_jit_functions_stage1(WASMModule *module, char *error_buf,
     option.enable_memory_profiling = true;
     option.enable_stack_estimation = true;
 #endif
+#if WASM_ENABLE_SHARED_HEAP != 0
+    option.enable_shared_heap = true;
+#endif
 
     module->comp_ctx = aot_create_comp_context(module->comp_data, &option);
     if (!module->comp_ctx) {
@@ -2531,7 +2593,7 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func,
 
 #if WASM_ENABLE_FAST_INTERP != 0 && WASM_ENABLE_LABELS_AS_VALUES != 0
 void **
-wasm_interp_get_handle_table();
+wasm_interp_get_handle_table(void);
 
 static void **handle_table;
 #endif
@@ -2947,6 +3009,12 @@ load_from_sections(WASMModule *module, WASMSection *sections,
         }
     }
 
+#if WASM_ENABLE_MEMORY64 != 0
+    if (!check_memory64_flags_consistency(module, error_buf, error_buf_size,
+                                          false))
+        return false;
+#endif
+
     calculate_global_data_offset(module);
 
 #if WASM_ENABLE_FAST_JIT != 0
@@ -5213,6 +5281,13 @@ fail:
     } while (0)
 #define PUSH_PAGE_COUNT() PUSH_MEM_OFFSET()
 
+#define PUSH_TBL_ELEM_IDX()                                               \
+    do {                                                                  \
+        if (!(wasm_loader_push_frame_ref(loader_ctx, table_elem_idx_type, \
+                                         error_buf, error_buf_size)))     \
+            goto fail;                                                    \
+    } while (0)
+
 #define POP_MEM_OFFSET()                                                   \
     do {                                                                   \
         if (!wasm_loader_pop_frame_ref_offset(loader_ctx, mem_offset_type, \
@@ -5220,6 +5295,13 @@ fail:
             goto fail;                                                     \
     } while (0)
 
+#define POP_TBL_ELEM_IDX()                                               \
+    do {                                                                 \
+        if (!(wasm_loader_pop_frame_ref(loader_ctx, table_elem_idx_type, \
+                                        error_buf, error_buf_size)))     \
+            goto fail;                                                   \
+    } while (0)
+
 #define POP_AND_PUSH(type_pop, type_push)                         \
     do {                                                          \
         if (!(wasm_loader_push_pop_frame_ref_offset(              \
@@ -5283,6 +5365,13 @@ fail:
 
 #define PUSH_PAGE_COUNT() PUSH_MEM_OFFSET()
 
+#define PUSH_TBL_ELEM_IDX()                                               \
+    do {                                                                  \
+        if (!(wasm_loader_push_frame_ref(loader_ctx, table_elem_idx_type, \
+                                         error_buf, error_buf_size)))     \
+            goto fail;                                                    \
+    } while (0)
+
 #define POP_I32()                                                              \
     do {                                                                       \
         if (!(wasm_loader_pop_frame_ref(loader_ctx, VALUE_TYPE_I32, error_buf, \
@@ -5325,6 +5414,13 @@ fail:
             goto fail;                                               \
     } while (0)
 
+#define POP_TBL_ELEM_IDX()                                               \
+    do {                                                                 \
+        if (!(wasm_loader_pop_frame_ref(loader_ctx, table_elem_idx_type, \
+                                        error_buf, error_buf_size)))     \
+            goto fail;                                                   \
+    } while (0)
+
 #define POP_AND_PUSH(type_pop, type_push)                              \
     do {                                                               \
         if (!(wasm_loader_push_pop_frame_ref(loader_ctx, 1, type_push, \
@@ -5944,7 +6040,8 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func,
 {
     uint8 *p = func->code, *p_end = func->code + func->code_size, *p_org;
     uint32 param_count, local_count, global_count;
-    uint8 *param_types, *local_types, local_type, global_type, mem_offset_type;
+    uint8 *param_types, *local_types, local_type, global_type, mem_offset_type,
+        table_elem_idx_type;
     BlockType func_block_type;
     uint16 *local_offsets, local_offset;
     uint32 count, local_idx, global_idx, u32, align, i, memidx;
@@ -5975,6 +6072,7 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func,
     mem_offset_type = is_memory64 ? VALUE_TYPE_I64 : VALUE_TYPE_I32;
 #else
     mem_offset_type = VALUE_TYPE_I32;
+    table_elem_idx_type = VALUE_TYPE_I32;
 #endif
 
     global_count = module->import_global_count + module->global_count;
@@ -6587,8 +6685,13 @@ re_scan:
                 emit_uint32(loader_ctx, table_idx);
 #endif
 
+#if WASM_ENABLE_MEMORY64 != 0
+                table_elem_idx_type = is_table_64bit(module, table_idx)
+                                          ? VALUE_TYPE_I64
+                                          : VALUE_TYPE_I32;
+#endif
                 /* skip elem idx */
-                POP_I32();
+                POP_TBL_ELEM_IDX();
 
                 bh_assert(type_idx < module->type_count);
 
@@ -6864,8 +6967,8 @@ re_scan:
                 break;
             }
 
-            /* table.get x. tables[x]. [i32] -> [t] */
-            /* table.set x. tables[x]. [i32 t] -> [] */
+            /* table.get x. tables[x]. [it] -> [t] */
+            /* table.set x. tables[x]. [it t] -> [] */
             case WASM_OP_TABLE_GET:
             case WASM_OP_TABLE_SET:
             {
@@ -6881,8 +6984,13 @@ re_scan:
                 emit_uint32(loader_ctx, table_idx);
 #endif
 
+#if WASM_ENABLE_MEMORY64 != 0
+                table_elem_idx_type = is_table_64bit(module, table_idx)
+                                          ? VALUE_TYPE_I64
+                                          : VALUE_TYPE_I32;
+#endif
                 if (opcode == WASM_OP_TABLE_GET) {
-                    POP_I32();
+                    POP_TBL_ELEM_IDX();
 #if WASM_ENABLE_FAST_INTERP != 0
                     PUSH_OFFSET_TYPE(decl_ref_type);
 #endif
@@ -6893,7 +7001,7 @@ re_scan:
                     POP_OFFSET_TYPE(decl_ref_type);
 #endif
                     POP_TYPE(decl_ref_type);
-                    POP_I32();
+                    POP_TBL_ELEM_IDX();
                 }
                 break;
             }
@@ -7818,7 +7926,12 @@ re_scan:
 #endif
                         POP_I32();
                         POP_I32();
-                        POP_I32();
+#if WASM_ENABLE_MEMORY64 != 0
+                        table_elem_idx_type = is_table_64bit(module, table_idx)
+                                                  ? VALUE_TYPE_I64
+                                                  : VALUE_TYPE_I32;
+#endif
+                        POP_TBL_ELEM_IDX();
                         break;
                     }
                     case WASM_OP_ELEM_DROP:
@@ -7837,7 +7950,8 @@ re_scan:
                     case WASM_OP_TABLE_COPY:
                     {
                         uint8 src_ref_type, dst_ref_type;
-                        uint32 src_tbl_idx, dst_tbl_idx;
+                        uint32 src_tbl_idx, dst_tbl_idx, src_tbl_idx_type,
+                            dst_tbl_idx_type, min_tbl_idx_type;
 
                         read_leb_uint32(p, p_end, src_tbl_idx);
                         if (!get_table_elem_type(module, src_tbl_idx,
@@ -7861,9 +7975,31 @@ re_scan:
                         emit_uint32(loader_ctx, src_tbl_idx);
                         emit_uint32(loader_ctx, dst_tbl_idx);
 #endif
-                        POP_I32();
-                        POP_I32();
-                        POP_I32();
+
+#if WASM_ENABLE_MEMORY64 != 0
+                        src_tbl_idx_type = is_table_64bit(module, src_tbl_idx)
+                                               ? VALUE_TYPE_I64
+                                               : VALUE_TYPE_I32;
+                        dst_tbl_idx_type = is_table_64bit(module, dst_tbl_idx)
+                                               ? VALUE_TYPE_I64
+                                               : VALUE_TYPE_I32;
+                        min_tbl_idx_type =
+                            (src_tbl_idx_type == VALUE_TYPE_I32
+                             || dst_tbl_idx_type == VALUE_TYPE_I32)
+                                ? VALUE_TYPE_I32
+                                : VALUE_TYPE_I64;
+#else
+                        src_tbl_idx_type = VALUE_TYPE_I32;
+                        dst_tbl_idx_type = VALUE_TYPE_I32;
+                        min_tbl_idx_type = VALUE_TYPE_I32;
+#endif
+
+                        table_elem_idx_type = min_tbl_idx_type;
+                        POP_TBL_ELEM_IDX();
+                        table_elem_idx_type = src_tbl_idx_type;
+                        POP_TBL_ELEM_IDX();
+                        table_elem_idx_type = dst_tbl_idx_type;
+                        POP_TBL_ELEM_IDX();
                         break;
                     }
                     case WASM_OP_TABLE_SIZE:
@@ -7881,7 +8017,12 @@ re_scan:
                         emit_uint32(loader_ctx, table_idx);
 #endif
 
-                        PUSH_I32();
+#if WASM_ENABLE_MEMORY64 != 0
+                        table_elem_idx_type = is_table_64bit(module, table_idx)
+                                                  ? VALUE_TYPE_I64
+                                                  : VALUE_TYPE_I32;
+#endif
+                        PUSH_TBL_ELEM_IDX();
                         break;
                     }
                     case WASM_OP_TABLE_GROW:
@@ -7913,15 +8054,20 @@ re_scan:
                         emit_uint32(loader_ctx, table_idx);
 #endif
 
-                        POP_I32();
+#if WASM_ENABLE_MEMORY64 != 0
+                        table_elem_idx_type = is_table_64bit(module, table_idx)
+                                                  ? VALUE_TYPE_I64
+                                                  : VALUE_TYPE_I32;
+#endif
+                        POP_TBL_ELEM_IDX();
 #if WASM_ENABLE_FAST_INTERP != 0
                         POP_OFFSET_TYPE(decl_ref_type);
 #endif
                         POP_TYPE(decl_ref_type);
                         if (opcode1 == WASM_OP_TABLE_GROW)
-                            PUSH_I32();
+                            PUSH_TBL_ELEM_IDX();
                         else
-                            POP_I32();
+                            PUSH_TBL_ELEM_IDX();
                         break;
                     }
 #endif /* WASM_ENABLE_REF_TYPES */

+ 217 - 57
core/iwasm/interpreter/wasm_runtime.c

@@ -83,6 +83,124 @@ wasm_unload(WASMModule *module)
     wasm_loader_unload(module);
 }
 
+bool
+wasm_resolve_symbols(WASMModule *module)
+{
+    bool ret = true;
+    uint32 idx;
+    for (idx = 0; idx < module->import_function_count; ++idx) {
+        WASMFunctionImport *import = &module->import_functions[idx].u.function;
+        bool linked = import->func_ptr_linked;
+#if WASM_ENABLE_MULTI_MODULE != 0
+        if (import->import_func_linked) {
+            linked = true;
+        }
+#endif
+        if (!linked && !wasm_resolve_import_func(module, import)) {
+            ret = false;
+        }
+    }
+    return ret;
+}
+
+#if WASM_ENABLE_MULTI_MODULE != 0
+static WASMFunction *
+wasm_resolve_function(const char *module_name, const char *function_name,
+                      const WASMFuncType *expected_function_type,
+                      char *error_buf, uint32 error_buf_size)
+{
+    WASMModuleCommon *module_reg;
+    WASMFunction *function = NULL;
+    WASMExport *export = NULL;
+    WASMModule *module = NULL;
+    WASMFuncType *target_function_type = NULL;
+
+    module_reg = wasm_runtime_find_module_registered(module_name);
+    if (!module_reg || module_reg->module_type != Wasm_Module_Bytecode) {
+        LOG_DEBUG("can not find a module named %s for function %s", module_name,
+                  function_name);
+        set_error_buf(error_buf, error_buf_size, "unknown import");
+        return NULL;
+    }
+
+    module = (WASMModule *)module_reg;
+    export = loader_find_export((WASMModuleCommon *)module, module_name,
+                                function_name, EXPORT_KIND_FUNC, error_buf,
+                                error_buf_size);
+    if (!export) {
+        return NULL;
+    }
+
+    /* resolve function type and function */
+    if (export->index < module->import_function_count) {
+        target_function_type =
+            module->import_functions[export->index].u.function.func_type;
+        function = module->import_functions[export->index]
+                       .u.function.import_func_linked;
+    }
+    else {
+        target_function_type =
+            module->functions[export->index - module->import_function_count]
+                ->func_type;
+        function =
+            module->functions[export->index - module->import_function_count];
+    }
+
+    /* check function type */
+    if (!wasm_type_equal((WASMType *)expected_function_type,
+                         (WASMType *)target_function_type, module->types,
+                         module->type_count)) {
+        LOG_DEBUG("%s.%s failed the type check", module_name, function_name);
+        set_error_buf(error_buf, error_buf_size, "incompatible import type");
+        return NULL;
+    }
+
+    return function;
+}
+#endif
+
+bool
+wasm_resolve_import_func(const WASMModule *module, WASMFunctionImport *function)
+{
+#if WASM_ENABLE_MULTI_MODULE != 0
+    char error_buf[128];
+    WASMModule *sub_module = NULL;
+#endif
+    function->func_ptr_linked = wasm_native_resolve_symbol(
+        function->module_name, function->field_name, function->func_type,
+        &function->signature, &function->attachment, &function->call_conv_raw);
+
+    if (function->func_ptr_linked) {
+        return true;
+    }
+
+#if WASM_ENABLE_MULTI_MODULE != 0
+    if (!wasm_runtime_is_built_in_module(function->module_name)) {
+        sub_module = (WASMModule *)wasm_runtime_load_depended_module(
+            (WASMModuleCommon *)module, function->module_name, error_buf,
+            sizeof(error_buf));
+        if (!sub_module) {
+            LOG_WARNING("failed to load sub module: %s", error_buf);
+            return false;
+        }
+    }
+    function->import_func_linked = wasm_resolve_function(
+        function->module_name, function->field_name, function->func_type,
+        error_buf, sizeof(error_buf));
+
+    if (function->import_func_linked) {
+        function->import_module = sub_module;
+        return true;
+    }
+    else {
+        LOG_WARNING("failed to link function (%s, %s): %s",
+                    function->module_name, function->field_name, error_buf);
+    }
+#endif
+
+    return false;
+}
+
 static void *
 runtime_malloc(uint64 size, char *error_buf, uint32 error_buf_size)
 {
@@ -560,6 +678,8 @@ tables_instantiate(const WASMModule *module, WASMModuleInstance *module_inst,
            uninitialized elements */
 #endif
 
+        table->is_table64 = import->u.table.table_type.flags & TABLE64_FLAG;
+
 #if WASM_ENABLE_MULTI_MODULE != 0
         *table_linked = table_inst_linked;
         if (table_inst_linked != NULL) {
@@ -618,6 +738,7 @@ tables_instantiate(const WASMModule *module, WASMModuleInstance *module_inst,
         /* For GC, all elements have already been set to NULL_REF (0) as
            uninitialized elements */
 #endif
+        table->is_table64 = module->tables[i].table_type.flags & TABLE64_FLAG;
         table->elem_type = module->tables[i].table_type.elem_type;
 #if WASM_ENABLE_GC != 0
         table->elem_ref_type.elem_ref_type =
@@ -1246,6 +1367,17 @@ export_functions_deinstantiate(WASMExportFuncInstance *functions)
         wasm_runtime_free(functions);
 }
 
+static int
+cmp_export_func_inst(const void *a, const void *b)
+{
+    const WASMExportFuncInstance *export_func1 =
+        (const WASMExportFuncInstance *)a;
+    const WASMExportFuncInstance *export_func2 =
+        (const WASMExportFuncInstance *)b;
+
+    return strcmp(export_func1->name, export_func2->name);
+}
+
 /**
  * Instantiate export functions in a module.
  */
@@ -1274,6 +1406,9 @@ export_functions_instantiate(const WASMModule *module,
         }
 
     bh_assert((uint32)(export_func - export_funcs) == export_func_count);
+
+    qsort(export_funcs, export_func_count, sizeof(WASMExportFuncInstance),
+          cmp_export_func_inst);
     return export_funcs;
 }
 
@@ -1323,42 +1458,6 @@ export_tags_instantiate(const WASMModule *module,
 }
 #endif /* end of WASM_ENABLE_TAGS != 0 */
 
-#if WASM_ENABLE_MULTI_MODULE != 0
-static void
-export_globals_deinstantiate(WASMExportGlobInstance *globals)
-{
-    if (globals)
-        wasm_runtime_free(globals);
-}
-
-static WASMExportGlobInstance *
-export_globals_instantiate(const WASMModule *module,
-                           WASMModuleInstance *module_inst,
-                           uint32 export_glob_count, char *error_buf,
-                           uint32 error_buf_size)
-{
-    WASMExportGlobInstance *export_globals, *export_global;
-    WASMExport *export = module->exports;
-    uint32 i;
-    uint64 total_size =
-        sizeof(WASMExportGlobInstance) * (uint64)export_glob_count;
-
-    if (!(export_global = export_globals =
-              runtime_malloc(total_size, error_buf, error_buf_size))) {
-        return NULL;
-    }
-
-    for (i = 0; i < module->export_count; i++, export ++)
-        if (export->kind == EXPORT_KIND_GLOBAL) {
-            export_global->name = export->name;
-            export_global->global = &module_inst->e->globals[export->index];
-            export_global++;
-        }
-
-    bh_assert((uint32)(export_global - export_globals) == export_glob_count);
-    return export_globals;
-}
-
 #if WASM_ENABLE_MULTI_MEMORY != 0
 static void
 export_memories_deinstantiate(WASMExportMemInstance *memories)
@@ -1396,6 +1495,42 @@ export_memories_instantiate(const WASMModule *module,
 }
 #endif /* end of if WASM_ENABLE_MULTI_MEMORY != 0 */
 
+#if WASM_ENABLE_MULTI_MODULE != 0
+static void
+export_globals_deinstantiate(WASMExportGlobInstance *globals)
+{
+    if (globals)
+        wasm_runtime_free(globals);
+}
+
+static WASMExportGlobInstance *
+export_globals_instantiate(const WASMModule *module,
+                           WASMModuleInstance *module_inst,
+                           uint32 export_glob_count, char *error_buf,
+                           uint32 error_buf_size)
+{
+    WASMExportGlobInstance *export_globals, *export_global;
+    WASMExport *export = module->exports;
+    uint32 i;
+    uint64 total_size =
+        sizeof(WASMExportGlobInstance) * (uint64)export_glob_count;
+
+    if (!(export_global = export_globals =
+              runtime_malloc(total_size, error_buf, error_buf_size))) {
+        return NULL;
+    }
+
+    for (i = 0; i < module->export_count; i++, export ++)
+        if (export->kind == EXPORT_KIND_GLOBAL) {
+            export_global->name = export->name;
+            export_global->global = &module_inst->e->globals[export->index];
+            export_global++;
+        }
+
+    bh_assert((uint32)(export_global - export_globals) == export_glob_count);
+    return export_globals;
+}
+
 #endif /* end of if WASM_ENABLE_MULTI_MODULE != 0 */
 
 static WASMFunctionInstance *
@@ -1476,8 +1611,12 @@ execute_post_instantiate_functions(WASMModuleInstance *module_inst,
     if (is_sub_inst) {
         bh_assert(exec_env_main);
 #ifdef OS_ENABLE_HW_BOUND_CHECK
-        bh_assert(exec_env_tls == exec_env_main);
-        (void)exec_env_tls;
+        /* May come from pthread_create_wrapper, thread_spawn_wrapper and
+           wasm_cluster_spawn_exec_env. If it comes from the former two,
+           the exec_env_tls must be not NULL and equal to exec_env_main,
+           else if it comes from the last one, it may be NULL. */
+        if (exec_env_tls)
+            bh_assert(exec_env_tls == exec_env_main);
 #endif
         exec_env = exec_env_main;
 
@@ -2388,11 +2527,13 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent,
 
     /* export */
     module_inst->export_func_count = get_export_count(module, EXPORT_KIND_FUNC);
+#if WASM_ENABLE_MULTI_MEMORY != 0
+    module_inst->export_memory_count =
+        get_export_count(module, EXPORT_KIND_MEMORY);
+#endif
 #if WASM_ENABLE_MULTI_MODULE != 0
     module_inst->export_table_count =
         get_export_count(module, EXPORT_KIND_TABLE);
-    module_inst->export_memory_count =
-        get_export_count(module, EXPORT_KIND_MEMORY);
 #if WASM_ENABLE_TAGS != 0
     module_inst->e->export_tag_count =
         get_export_count(module, EXPORT_KIND_TAG);
@@ -2432,7 +2573,7 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent,
                      module, module_inst, module_inst->export_global_count,
                      error_buf, error_buf_size)))
 #endif
-#if WASM_ENABLE_MULTI_MODULE != 0 && WASM_ENABLE_MULTI_MEMORY != 0
+#if WASM_ENABLE_MULTI_MEMORY != 0
         || (module_inst->export_memory_count > 0
             && !(module_inst->export_memories = export_memories_instantiate(
                      module, module_inst, module_inst->export_memory_count,
@@ -2671,6 +2812,14 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent,
         }
     }
 
+#if WASM_ENABLE_JIT != 0 && WASM_ENABLE_SHARED_HEAP != 0
+#if UINTPTR_MAX == UINT64_MAX
+    module_inst->e->shared_heap_start_off.u64 = UINT64_MAX;
+#else
+    module_inst->e->shared_heap_start_off.u32[0] = UINT32_MAX;
+#endif
+#endif
+
 #if WASM_ENABLE_GC != 0
     /* Initialize the table data with init expr */
     for (i = 0; i < module->table_count; i++) {
@@ -3240,7 +3389,7 @@ wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst)
     export_globals_deinstantiate(module_inst->export_globals);
 #endif
 
-#if WASM_ENABLE_MULTI_MODULE != 0 && WASM_ENABLE_MULTI_MEMORY != 0
+#if WASM_ENABLE_MULTI_MEMORY != 0
     export_memories_deinstantiate(module_inst->export_memories);
 #endif
 
@@ -3285,22 +3434,20 @@ wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst)
 WASMFunctionInstance *
 wasm_lookup_function(const WASMModuleInstance *module_inst, const char *name)
 {
-    uint32 i;
-    for (i = 0; i < module_inst->export_func_count; i++)
-        if (!strcmp(module_inst->export_functions[i].name, name))
-            return module_inst->export_functions[i].function;
-    return NULL;
-}
+    WASMExportFuncInstance key = { .name = (char *)name };
+    WASMExportFuncInstance *export_func_inst;
 
-#if WASM_ENABLE_MULTI_MODULE != 0
-WASMGlobalInstance *
-wasm_lookup_global(const WASMModuleInstance *module_inst, const char *name)
-{
-    uint32 i;
-    for (i = 0; i < module_inst->export_global_count; i++)
-        if (!strcmp(module_inst->export_globals[i].name, name))
-            return module_inst->export_globals[i].global;
-    return NULL;
+    if (!module_inst->export_functions)
+        return NULL;
+
+    export_func_inst = bsearch(
+        &key, module_inst->export_functions, module_inst->export_func_count,
+        sizeof(WASMExportFuncInstance), cmp_export_func_inst);
+
+    if (!export_func_inst)
+        return NULL;
+
+    return export_func_inst->function;
 }
 
 WASMMemoryInstance *
@@ -3314,10 +3461,23 @@ wasm_lookup_memory(const WASMModuleInstance *module_inst, const char *name)
     return NULL;
 #else
     (void)module_inst->export_memories;
+    if (!module_inst->memories)
+        return NULL;
     return module_inst->memories[0];
 #endif
 }
 
+#if WASM_ENABLE_MULTI_MODULE != 0
+WASMGlobalInstance *
+wasm_lookup_global(const WASMModuleInstance *module_inst, const char *name)
+{
+    uint32 i;
+    for (i = 0; i < module_inst->export_global_count; i++)
+        if (!strcmp(module_inst->export_globals[i].name, name))
+            return module_inst->export_globals[i].global;
+    return NULL;
+}
+
 WASMTableInstance *
 wasm_lookup_table(const WASMModuleInstance *module_inst, const char *name)
 {

+ 34 - 4
core/iwasm/interpreter/wasm_runtime.h

@@ -92,6 +92,15 @@ typedef union {
     uint32 u32[2];
 } MemBound;
 
+typedef struct WASMSharedHeap {
+    struct WASMSharedHeap *next;
+    void *heap_handle;
+    uint8 *base_addr;
+    uint64 size;
+    uint64 start_off_mem64;
+    uint64 start_off_mem32;
+} WASMSharedHeap;
+
 struct WASMMemoryInstance {
     /* Module type */
     uint32 module_type;
@@ -157,7 +166,8 @@ struct WASMMemoryInstance {
 struct WASMTableInstance {
     /* The element type */
     uint8 elem_type;
-    uint8 __padding__[7];
+    uint8 is_table64;
+    uint8 __padding__[6];
     union {
 #if WASM_ENABLE_GC != 0
         WASMRefType *elem_ref_type;
@@ -353,6 +363,19 @@ typedef struct WASMModuleInstanceExtra {
     uint32 max_aux_stack_used;
 #endif
 
+#if WASM_ENABLE_SHARED_HEAP != 0
+    WASMSharedHeap *shared_heap;
+#if WASM_ENABLE_JIT != 0
+    /*
+     * Adjusted shared heap based addr to simple the calculation
+     * in the aot code. The value is:
+     *   shared_heap->base_addr - shared_heap->start_off
+     */
+    uint8 *shared_heap_base_addr_adj;
+    MemBound shared_heap_start_off;
+#endif
+#endif
+
 #if WASM_ENABLE_DEBUG_INTERP != 0                         \
     || (WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \
         && WASM_ENABLE_LAZY_JIT != 0)
@@ -513,6 +536,13 @@ wasm_load_from_sections(WASMSection *section_list, char *error_buf,
 void
 wasm_unload(WASMModule *module);
 
+bool
+wasm_resolve_symbols(WASMModule *module);
+
+bool
+wasm_resolve_import_func(const WASMModule *module,
+                         WASMFunctionImport *function);
+
 WASMModuleInstance *
 wasm_instantiate(WASMModule *module, WASMModuleInstance *parent,
                  WASMExecEnv *exec_env_main, uint32 stack_size,
@@ -539,13 +569,13 @@ wasm_set_running_mode(WASMModuleInstance *module_inst,
 WASMFunctionInstance *
 wasm_lookup_function(const WASMModuleInstance *module_inst, const char *name);
 
+WASMMemoryInstance *
+wasm_lookup_memory(const WASMModuleInstance *module_inst, const char *name);
+
 #if WASM_ENABLE_MULTI_MODULE != 0
 WASMGlobalInstance *
 wasm_lookup_global(const WASMModuleInstance *module_inst, const char *name);
 
-WASMMemoryInstance *
-wasm_lookup_memory(const WASMModuleInstance *module_inst, const char *name);
-
 WASMTableInstance *
 wasm_lookup_table(const WASMModuleInstance *module_inst, const char *name);
 

+ 1 - 1
core/iwasm/libraries/lib-pthread/lib_pthread.cmake

@@ -6,7 +6,7 @@ set (LIB_PTHREAD_DIR ${CMAKE_CURRENT_LIST_DIR})
 add_definitions (-DWASM_ENABLE_LIB_PTHREAD=1)
 
 if (WAMR_BUILD_LIB_PTHREAD_SEMAPHORE EQUAL 1)
-add_definitions (-DWASM_ENABLE_LIB_PTHREAD_SEMAPHORE=1)
+    add_definitions (-DWASM_ENABLE_LIB_PTHREAD_SEMAPHORE=1)
 endif()
 
 include_directories(${LIB_PTHREAD_DIR})

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

@@ -29,7 +29,7 @@ typedef struct {
 } ThreadStartArg;
 
 static int32
-allocate_thread_id()
+allocate_thread_id(void)
 {
     os_mutex_lock(&thread_id_lock);
     int32 id = tid_allocator_get_tid(&tid_allocator);

+ 19 - 5
core/iwasm/libraries/libc-emcc/libc_emcc_wrapper.c

@@ -7,8 +7,13 @@
 #include "bh_log.h"
 #include "wasm_export.h"
 #include "../interpreter/wasm.h"
-#if !defined(_DEFAULT_SOURCE) && !defined(BH_PLATFORM_LINUX_SGX)
-#include "sys/syscall.h"
+
+#if defined(__linux__)
+#include <linux/version.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)
+#define HAVE_SYSCALL_GETRANDOM
+#include <sys/syscall.h>
+#endif
 #endif
 
 /* clang-format off */
@@ -168,12 +173,21 @@ statbuf_native2app(const struct stat *statbuf_native,
     statbuf_app->st_blksize = (unsigned)statbuf_native->st_blksize;
     statbuf_app->st_blocks = (unsigned)statbuf_native->st_blocks;
     statbuf_app->st_ino = (int64)statbuf_native->st_ino;
+#if defined(__APPLE__)
+    statbuf_app->st_atim.tv_sec = (int)statbuf_native->st_atimespec.tv_sec;
+    statbuf_app->st_atim.tv_nsec = (int)statbuf_native->st_atimespec.tv_nsec;
+    statbuf_app->st_mtim.tv_sec = (int)statbuf_native->st_mtimespec.tv_sec;
+    statbuf_app->st_mtim.tv_nsec = (int)statbuf_native->st_mtimespec.tv_nsec;
+    statbuf_app->st_ctim.tv_sec = (int)statbuf_native->st_ctimespec.tv_sec;
+    statbuf_app->st_ctim.tv_nsec = (int)statbuf_native->st_ctimespec.tv_nsec;
+#else
     statbuf_app->st_atim.tv_sec = (int)statbuf_native->st_atim.tv_sec;
     statbuf_app->st_atim.tv_nsec = (int)statbuf_native->st_atim.tv_nsec;
     statbuf_app->st_mtim.tv_sec = (int)statbuf_native->st_mtim.tv_sec;
     statbuf_app->st_mtim.tv_nsec = (int)statbuf_native->st_mtim.tv_nsec;
     statbuf_app->st_ctim.tv_sec = (int)statbuf_native->st_ctim.tv_sec;
     statbuf_app->st_ctim.tv_nsec = (int)statbuf_native->st_ctim.tv_nsec;
+#endif
 }
 
 static int
@@ -261,10 +275,10 @@ getentropy_wrapper(wasm_exec_env_t exec_env, void *buffer, uint32 length)
 {
     if (buffer == NULL)
         return -1;
-#if defined(_DEFAULT_SOURCE) || defined(BH_PLATFORM_LINUX_SGX)
-    return getentropy(buffer, length);
-#else
+#if defined(HAVE_SYSCALL_GETRANDOM)
     return syscall(SYS_getrandom, buffer, length, 0);
+#else
+    return getentropy(buffer, length);
 #endif
 }
 

+ 5 - 4
core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c

@@ -1022,8 +1022,8 @@ execute_interruptible_poll_oneoff(
     uint32 i;
 
     const __wasi_timestamp_t timeout = get_timeout_for_poll_oneoff(
-                                 in, nsubscriptions),
-                             time_quant = 1e9;
+                                 in, (uint32)nsubscriptions),
+                             time_quant = (__wasi_timestamp_t)1e9;
     const uint64 size_to_copy =
         nsubscriptions * (uint64)sizeof(wasi_subscription_t);
     __wasi_subscription_t *in_copy = NULL;
@@ -1034,12 +1034,13 @@ execute_interruptible_poll_oneoff(
         return __WASI_ENOMEM;
     }
 
-    bh_memcpy_s(in_copy, size_to_copy, in, size_to_copy);
+    bh_memcpy_s(in_copy, (uint32)size_to_copy, in, (uint32)size_to_copy);
 
     while (timeout == (__wasi_timestamp_t)-1 || elapsed <= timeout) {
         /* update timeout for clock subscription events */
         update_clock_subscription_data(
-            in_copy, nsubscriptions, min_uint64(time_quant, timeout - elapsed));
+            in_copy, (uint32)nsubscriptions,
+            min_uint64(time_quant, timeout - elapsed));
         err = wasmtime_ssp_poll_oneoff(exec_env, curfds, in_copy, out,
                                        nsubscriptions, nevents);
         elapsed += time_quant;

+ 1 - 1
core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c

@@ -3130,7 +3130,7 @@ compare_address(const struct addr_pool *addr_pool_entry,
         }
         addr_size = 16;
     }
-    max_addr_mask = addr_size * 8;
+    max_addr_mask = (uint8)(addr_size * 8);
 
     /* IPv4 0.0.0.0 or IPv6 :: means any address */
     if (basebuf[0] == 0 && !memcmp(basebuf, basebuf + 1, addr_size - 1)) {

+ 29 - 0
core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/refcount.h

@@ -132,6 +132,35 @@ refcount_release(struct refcount *r)
 #error "Reference counter isn't implemented"
 #endif /* end of __GNUC_PREREQ (4.7) */
 
+#elif defined(_MSC_VER)
+
+/* Simple reference counter. */
+struct LOCKABLE refcount {
+    LONG count;
+};
+
+/* Initialize the reference counter. */
+static inline void
+refcount_init(struct refcount *r, unsigned int count)
+{
+    InterlockedExchange(&r->count, (LONG)count);
+}
+
+/* Increment the reference counter. */
+static inline void
+refcount_acquire(struct refcount *r)
+{
+    InterlockedIncrement(&r->count);
+}
+
+/* Decrement the reference counter, returning whether the reference
+   dropped to zero. */
+static inline bool
+refcount_release(struct refcount *r)
+{
+    return InterlockedDecrement(&r->count) == 0 ? true : false;
+}
+
 #else /* else of CONFIG_HAS_STD_ATOMIC */
 #error "Reference counter isn't implemented"
 #endif /* end of CONFIG_HAS_STD_ATOMIC */

+ 18 - 4
core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/ssp_config.h

@@ -70,9 +70,11 @@
 #endif
 
 #if !defined(BH_PLATFORM_LINUX_SGX)
+
 /* Clang's __GNUC_PREREQ macro has a different meaning than GCC one,
 so we have to handle this case specially */
 #if defined(__clang__)
+
 /* Clang provides stdatomic.h since 3.6.0
 See https://releases.llvm.org/3.6.0/tools/clang/docs/ReleaseNotes.html */
 #if __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 6)
@@ -80,7 +82,9 @@ See https://releases.llvm.org/3.6.0/tools/clang/docs/ReleaseNotes.html */
 #else
 #define CONFIG_HAS_STD_ATOMIC 0
 #endif
+
 #elif defined(__GNUC_PREREQ)
+
 /* Even though older versions of GCC support C11, atomics were
 not implemented until 4.9. See
 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58016 */
@@ -89,11 +93,21 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58016 */
 #else /* else of __GNUC_PREREQ(4, 9) */
 #define CONFIG_HAS_STD_ATOMIC 0
 #endif /* end of __GNUC_PREREQ(4, 9) */
-#else  /* else of defined(__GNUC_PREREQ) */
+
+#elif defined(_MSC_VER)
+
+#define CONFIG_HAS_STD_ATOMIC 0
+
+#else
+
 #define CONFIG_HAS_STD_ATOMIC 1
-#endif /* end of defined(__GNUC_PREREQ) */
-#else  /* else of !defined(BH_PLATFORM_LINUX_SGX) */
+
+#endif /* end of defined(__clang__) */
+
+#else /* else of !defined(BH_PLATFORM_LINUX_SGX) */
+
 #define CONFIG_HAS_STD_ATOMIC 0
+
 #endif /* end of !defined(BH_PLATFORM_LINUX_SGX) */
 
-#endif
+#endif /* end of SSP_CONFIG_H */

+ 8 - 0
core/iwasm/libraries/shared-heap/shared_heap.cmake

@@ -0,0 +1,8 @@
+# Copyright (C) 2024 Xiaomi Corporation.  All rights reserved.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+set (LIB_SHARED_HEAP ${CMAKE_CURRENT_LIST_DIR})
+add_definitions (-DWASM_ENABLE_SHARED_HEAP=1)
+include_directories(${LIB_SHARED_HEAP_DIR})
+file (GLOB source_all ${LIB_SHARED_HEAP}/*.c)
+set (LIB_SHARED_HEAP_SOURCE ${source_all})

+ 57 - 0
core/iwasm/libraries/shared-heap/shared_heap_wrapper.c

@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2024 Xiaomi Corporation.  All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#include "bh_common.h"
+#include "bh_log.h"
+#include "wasm_export.h"
+#include "../interpreter/wasm.h"
+#include "../common/wasm_runtime_common.h"
+/* clang-format off */
+#define validate_native_addr(addr, size) \
+    wasm_runtime_validate_native_addr(module_inst, addr, size)
+
+#define module_shared_malloc(size, p_native_addr) \
+    wasm_runtime_shared_heap_malloc(module_inst, size, p_native_addr)
+
+#define module_shared_free(offset) \
+    wasm_runtime_shared_heap_free(module_inst, offset)
+/* clang-format on */
+
+static uint32
+shared_heap_malloc_wrapper(wasm_exec_env_t exec_env, uint32 size)
+{
+    wasm_module_inst_t module_inst = get_module_inst(exec_env);
+    return (uint32)module_shared_malloc((uint64)size, NULL);
+}
+
+static void
+shared_heap_free_wrapper(wasm_exec_env_t exec_env, void *ptr)
+{
+    wasm_module_inst_t module_inst = get_module_inst(exec_env);
+
+    if (!validate_native_addr(ptr, (uint64)sizeof(uintptr_t))) {
+        LOG_WARNING("Invalid app address");
+        return;
+    }
+
+    module_shared_free(addr_native_to_app(ptr));
+}
+
+/* clang-format off */
+#define REG_NATIVE_FUNC(func_name, signature) \
+    { #func_name, func_name##_wrapper, signature, NULL }
+/* clang-format on */
+
+static NativeSymbol native_symbols_shared_heap[] = {
+    REG_NATIVE_FUNC(shared_heap_malloc, "(i)i"),
+    REG_NATIVE_FUNC(shared_heap_free, "(*)"),
+};
+
+uint32
+get_lib_shared_heap_export_apis(NativeSymbol **p_shared_heap_apis)
+{
+    *p_shared_heap_apis = native_symbols_shared_heap;
+    return sizeof(native_symbols_shared_heap) / sizeof(NativeSymbol);
+}

+ 76 - 0
core/iwasm/libraries/thread-mgr/thread_manager.c

@@ -1402,6 +1402,82 @@ wasm_cluster_spread_custom_data(WASMModuleInstanceCommon *module_inst,
     }
 }
 
+#if WASM_ENABLE_SHARED_HEAP != 0
+static void
+attach_shared_heap_visitor(void *node, void *heap)
+{
+    WASMExecEnv *curr_exec_env = (WASMExecEnv *)node;
+    WASMModuleInstanceCommon *module_inst = get_module_inst(curr_exec_env);
+
+    wasm_runtime_attach_shared_heap_internal(module_inst, heap);
+}
+
+static void
+detach_shared_heap_visitor(void *node, void *heap)
+{
+    WASMExecEnv *curr_exec_env = (WASMExecEnv *)node;
+    WASMModuleInstanceCommon *module_inst = get_module_inst(curr_exec_env);
+
+    (void)heap;
+    wasm_runtime_detach_shared_heap_internal(module_inst);
+}
+
+bool
+wasm_cluster_attach_shared_heap(WASMModuleInstanceCommon *module_inst,
+                                WASMSharedHeap *heap)
+{
+    WASMExecEnv *exec_env = wasm_clusters_search_exec_env(module_inst);
+
+    if (exec_env == NULL) {
+        /* Maybe threads have not been started yet. */
+        return wasm_runtime_attach_shared_heap_internal(module_inst, heap);
+    }
+    else {
+        WASMCluster *cluster;
+
+        cluster = wasm_exec_env_get_cluster(exec_env);
+        bh_assert(cluster);
+
+        os_mutex_lock(&cluster->lock);
+        /* Try attaching shared heap to this module instance first
+           to ensure that we can attach it to all other instances. */
+        if (!wasm_runtime_attach_shared_heap_internal(module_inst, heap)) {
+            os_mutex_unlock(&cluster->lock);
+            return false;
+        }
+        /* Detach the shared heap so it can be attached again. */
+        wasm_runtime_detach_shared_heap_internal(module_inst);
+        traverse_list(&cluster->exec_env_list, attach_shared_heap_visitor,
+                      heap);
+        os_mutex_unlock(&cluster->lock);
+    }
+
+    return true;
+}
+
+void
+wasm_cluster_detach_shared_heap(WASMModuleInstanceCommon *module_inst)
+{
+    WASMExecEnv *exec_env = wasm_clusters_search_exec_env(module_inst);
+
+    if (exec_env == NULL) {
+        /* Maybe threads have not been started yet. */
+        wasm_runtime_detach_shared_heap_internal(module_inst);
+    }
+    else {
+        WASMCluster *cluster;
+
+        cluster = wasm_exec_env_get_cluster(exec_env);
+        bh_assert(cluster);
+
+        os_mutex_lock(&cluster->lock);
+        traverse_list(&cluster->exec_env_list, detach_shared_heap_visitor,
+                      NULL);
+        os_mutex_unlock(&cluster->lock);
+    }
+}
+#endif
+
 #if WASM_ENABLE_MODULE_INST_CONTEXT != 0
 struct inst_set_context_data {
     void *key;

+ 16 - 4
core/iwasm/libraries/thread-mgr/thread_manager.h

@@ -11,6 +11,9 @@
 #include "wasm_export.h"
 #include "../interpreter/wasm.h"
 #include "../common/wasm_runtime_common.h"
+#if WASM_ENABLE_SHARED_HEAP != 0
+#include "../common/wasm_memory.h"
+#endif
 
 #ifdef __cplusplus
 extern "C" {
@@ -64,10 +67,10 @@ void
 wasm_cluster_set_max_thread_num(uint32 num);
 
 bool
-thread_manager_init();
+thread_manager_init(void);
 
 void
-thread_manager_destroy();
+thread_manager_destroy(void);
 
 /* Create cluster */
 WASMCluster *
@@ -109,7 +112,7 @@ bool
 wasm_cluster_register_destroy_callback(void (*callback)(WASMCluster *));
 
 void
-wasm_cluster_cancel_all_callbacks();
+wasm_cluster_cancel_all_callbacks(void);
 
 void
 wasm_cluster_suspend_all(WASMCluster *cluster);
@@ -167,6 +170,15 @@ wasm_cluster_set_context(WASMModuleInstanceCommon *module_inst, void *key,
 bool
 wasm_cluster_is_thread_terminated(WASMExecEnv *exec_env);
 
+#if WASM_ENABLE_SHARED_HEAP != 0
+bool
+wasm_cluster_attach_shared_heap(WASMModuleInstanceCommon *module_inst,
+                                WASMSharedHeap *heap);
+
+void
+wasm_cluster_detach_shared_heap(WASMModuleInstanceCommon *module_inst);
+#endif
+
 #if WASM_ENABLE_DEBUG_INTERP != 0
 #define WAMR_SIG_TRAP (5)
 #define WAMR_SIG_STOP (19)
@@ -190,7 +202,7 @@ struct WASMCurrentEnvStatus {
 };
 
 WASMCurrentEnvStatus *
-wasm_cluster_create_exenv_status();
+wasm_cluster_create_exenv_status(void);
 
 void
 wasm_cluster_destroy_exenv_status(WASMCurrentEnvStatus *status);

+ 24 - 24
core/iwasm/libraries/wasi-nn/README.md

@@ -4,7 +4,7 @@
 
 ### Host
 
-Enable WASI-NN in the WAMR by spefiying it in the cmake building configuration as follows,
+Enable WASI-NN in the WAMR by specifying it in the cmake building configuration as follows,
 
 ```cmake
 set (WAMR_BUILD_WASI_NN  1)
@@ -17,14 +17,15 @@ $ cmake -DWAMR_BUILD_WASI_NN=1 <other options> ...
 ```
 
 > ![Caution]
-> If enable `WAMR_BUID_WASI_NN`, iwasm will link a shared WAMR library instead of a static one. Wasi-nn backends will be loaded dynamically at runtime. Users shall specify the path of the backend library and register it to the iwasm runtime with `--native-lib=<path of backend library>`. All shared libraries should be placed in the `LD_LIBRARY_PATH`.
+> Enabling WAMR_BUILD_WASI_NN will cause the IWASM to link to a shared WAMR library instead of a static one. The WASI-NN backends will then be loaded dynamically when the program is run. You must ensure that all shared libraries are included in the `LD_LIBRARY_PATH`.
 
 #### Compilation options
 
-- `WAMR_BUILD_WASI_NN`. enable wasi-nn support. can't work alone. need to identify a backend. Match legacy wasi-nn spec naming convention. use `wasi_nn` as import module names.
-- `WAMR_BUILD_WASI_EPHEMERAL_NN`. Match latest wasi-nn spec naming convention. use `wasi_ephemeral_nn` as import module names.
-- `WAMR_BUILD_WASI_NN_TFLITE`. identify the backend as TensorFlow Lite.
-- `WAMR_BUILD_WASI_NN_OPENVINO`. identify the backend as OpenVINO.
+- `WAMR_BUILD_WASI_NN`. This option enables support for WASI-NN. It cannot function independently and requires specifying a backend. It follows the original WASI-NN specification for naming conventions and uses wasi_nn for import module names.
+- `WAMR_BUILD_WASI_EPHEMERAL_NN`. This option adheres to the most recent WASI-NN specification for naming conventions and uses wasi_ephemeral_nn for import module names.
+- `WAMR_BUILD_WASI_NN_TFLITE`. This option designates TensorFlow Lite as the backend.
+- `WAMR_BUILD_WASI_NN_OPENVINO`. This option designates OpenVINO as the backend.
+- `WAMR_BUILD_WASI_NN_LLAMACPP`. This option designates Llama.cpp as the backend.
 
 ### Wasm
 
@@ -44,7 +45,7 @@ typedef enum { fp16 = 0, fp32, up8, ip32 } tensor_type;
 
 It is required to recompile the Wasm application if you want to switch between the two sets of functions.
 
-#### Openvino
+#### Openvino installation
 
 If you're planning to use OpenVINO backends, the first step is to install OpenVINO on your computer. To do this correctly, please follow the official installation guide which you can find at this link: https://docs.openvino.ai/2024/get-started/install-openvino/install-openvino-archive-linux.html.
 
@@ -102,7 +103,6 @@ docker run \
     wasi-nn-cpu \
     --dir=/ \
     --env="TARGET=cpu" \
-    --native-lib=/lib/libwasi-nn-tflite.so \
     /assets/test_tensorflow.wasm
 ```
 
@@ -118,7 +118,6 @@ docker run \
     wasi-nn-nvidia-gpu \
     --dir=/ \
     --env="TARGET=gpu" \
-    --native-lib=/lib/libwasi-nn-tflite.so \
     /assets/test_tensorflow.wasm
 ```
 
@@ -130,7 +129,6 @@ docker run \
     wasi-nn-vx-delegate \
     --dir=/ \
     --env="TARGET=gpu" \
-    --native-lib=/lib/libwasi-nn-tflite.so \
     /assets/test_tensorflow_quantized.wasm
 ```
 
@@ -146,7 +144,6 @@ docker run \
     wasi-nn-tpu \
     --dir=/ \
     --env="TARGET=tpu" \
-    --native-lib=/lib/libwasi-nn-tflite.so \
     /assets/test_tensorflow_quantized.wasm
 ```
 
@@ -154,25 +151,17 @@ docker run \
 
 Supported:
 
-- Graph encoding: `tensorflowlite`.
-- Execution target: `cpu`, `gpu` and `tpu`.
+- Graph encoding: `tensorflowlite`, `openvino` and `ggml`
+- Execution target: `cpu` for all. `gpu` and `tpu` for `tensorflowlite`.
 - Tensor type: `fp32`.
 
 ## Smoke test
 
 ### Testing with WasmEdge-WASINN Examples
 
-To ensure everything is set up correctly, use the examples from [WasmEdge-WASINN-examples](https://github.com/second-state/WasmEdge-WASINN-examples/tree/master). These examples help verify that WASI-NN support in WAMR is functioning as expected.
+To make sure everything is configured properly, refer to the examples provided at [WasmEdge-WASINN-examples](https://github.com/second-state/WasmEdge-WASINN-examples/tree/master). These examples are useful for confirming that the WASI-NN support in WAMR is working correctly.
 
-> Note: The repository contains two types of examples. Some use the [standard wasi-nn](https://github.com/WebAssembly/wasi-nn), while others use [WasmEdge's version of wasi-nn](https://github.com/second-state/wasmedge-wasi-nn), which is enhanced to meet specific customer needs.
-
-The examples test the following machine learning backends:
-
-- OpenVINO
-- PyTorch
-- TensorFlow Lite
-
-Due to the different requirements of each backend, we'll use a Docker container for a hassle-free testing environment.
+Because each backend has its own set of requirements, we recommend using a Docker container to create a straightforward testing environment without complications.
 
 #### Prepare the execution environment
 
@@ -186,9 +175,20 @@ $ docker build -t wasi-nn-smoke:v1.0 -f ./core/iwasm/libraries/wasi-nn/test/Dock
 #### Execute
 
 ```bash
+$ pwd
+/workspaces/wasm-micro-runtime/
 $ docker run --rm wasi-nn-smoke:v1.0
 ```
 
-### Testing with bytecodealliance wasi-nn
+It should be noted that the qwen example is selected as the default one about the Llama.cpp backend because it uses a small model and is easy to run.
+
+```bash
+- openvino_mobile_image. PASS
+- openvino_mobile_raw. PASS
+- openvino_road_segmentation_adas. PASS
+- wasmedge_ggml_qwen. PASS
+```
+
+### Testing with bytecodealliance WASI-NN
 
 For another example, check out [classification-example](https://github.com/bytecodealliance/wasi-nn/tree/main/rust/examples/classification-example), which focuses on OpenVINO. You can run it using the same Docker container mentioned above.

+ 25 - 0
core/iwasm/libraries/wasi-nn/cmake/Findcjson.cmake

@@ -0,0 +1,25 @@
+# Copyright (C) 2019 Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+include(FetchContent)
+
+set(CJSON_SOURCE_DIR "${WAMR_ROOT_DIR}/core/deps/cjson")
+if(EXISTS ${CJSON_SOURCE_DIR})
+  message("Use existed source code under ${CJSON_SOURCE_DIR}")
+  FetchContent_Declare(
+    cjson
+    SOURCE_DIR     ${CJSON_SOURCE_DIR}
+  )
+else()
+  message("download source code and store it at ${CJSON_SOURCE_DIR}")
+  FetchContent_Declare(
+    cjson
+    GIT_REPOSITORY https://github.com/DaveGamble/cJSON.git
+    GIT_TAG        v1.7.18
+    SOURCE_DIR     ${CJSON_SOURCE_DIR}
+  )
+endif()
+
+set(ENABLE_CJSON_TEST OFF CACHE INTERNAL "Turn off tests")
+set(ENABLE_CJSON_UNINSTALL OFF CACHE INTERNAL "Turn off uninstall to avoid targets conflict")
+FetchContent_MakeAvailable(cjson)

+ 26 - 0
core/iwasm/libraries/wasi-nn/cmake/Findllamacpp.cmake

@@ -0,0 +1,26 @@
+# Copyright (C) 2019 Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+include(FetchContent)
+
+set(LLAMA_SOURCE_DIR "${WAMR_ROOT_DIR}/core/deps/llama.cpp")
+if(EXISTS ${LLAMA_SOURCE_DIR})
+  message("Use existed source code under ${LLAMA_SOURCE_DIR}")
+  FetchContent_Declare(
+    llamacpp
+    SOURCE_DIR     ${LLAMA_SOURCE_DIR}
+  )
+else()
+  message("download source code and store it at ${LLAMA_SOURCE_DIR}")
+  FetchContent_Declare(
+    llamacpp
+    GIT_REPOSITORY https://github.com/ggerganov/llama.cpp.git
+    GIT_TAG        b3573
+    SOURCE_DIR     ${LLAMA_SOURCE_DIR}
+  )
+endif()
+
+set(LLAMA_BUILD_TESTS OFF)
+set(LLAMA_BUILD_EXAMPLES OFF)
+set(LLAMA_BUILD_SERVER OFF)
+FetchContent_MakeAvailable(llamacpp)

+ 29 - 39
core/iwasm/libraries/wasi-nn/cmake/Findtensorflow_lite.cmake

@@ -1,47 +1,37 @@
 # Copyright (C) 2019 Intel Corporation. All rights reserved.
 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 
-find_library(TENSORFLOW_LITE
-  NAMES tensorflow-lite
-  HINTS ${CMAKE_CURRENT_BINARY_DIR}/tensorflow-lite
-  NO_DEFAULT_PATHS
-)
-
-if(NOT TENSORFLOW_LITE)
-  if(NOT EXISTS "${WAMR_ROOT_DIR}/core/deps/tensorflow-src")
-    execute_process(
-      COMMAND "${WAMR_ROOT_DIR}/core/deps/install_tensorflow.sh"
-      RESULT_VARIABLE TENSORFLOW_RESULT
-    )
-  else()
-    message("Tensorflow is already downloaded.")
-  endif()
-
-  set(TENSORFLOW_SOURCE_DIR "${WAMR_ROOT_DIR}/core/deps/tensorflow-src")
-
-  if(WAMR_BUILD_WASI_NN_ENABLE_GPU EQUAL 1)
-    # Tensorflow specific:
-    # * https://www.tensorflow.org/lite/guide/build_cmake#available_options_to_build_tensorflow_lite
-    set (TFLITE_ENABLE_GPU ON)
-  endif()
+include(FetchContent)
+
+set(TFLITE_SOURCE_DIR "${WAMR_ROOT_DIR}/core/deps/tensorflow-src")
+if(EXISTS ${TFLITE_SOURCE_DIR})
+  message("Use existed source code under ${TFLITE_SOURCE_DIR}")
+  FetchContent_Declare(
+    tensorflow_lite
+    SOURCE_DIR     ${TFLITE_SOURCE_DIR}
+    SOURCE_SUBDIR  tensorflow/lite
+  )
+else()
+  message("download source code and store it at ${TFLITE_SOURCE_DIR}")
+  FetchContent_Declare(
+    tensorflow_lite
+    GIT_REPOSITORY https://github.com/tensorflow/tensorflow.git
+    GIT_TAG        v2.12.0
+    GIT_SHALLOW    ON
+    GIT_PROGRESS   ON
+    SOURCE_DIR     ${TFLITE_SOURCE_DIR}
+    SOURCE_SUBDIR  tensorflow/lite
+    PATCH_COMMAND  git apply ${CMAKE_CURRENT_LIST_DIR}/add_telemetry.patch
+  )
+endif()
 
-  if (CMAKE_SIZEOF_VOID_P EQUAL 4)
-    set (TFLITE_ENABLE_XNNPACK OFF)
-  endif()
 
-  add_subdirectory(
-    "${TENSORFLOW_SOURCE_DIR}/tensorflow/lite"
-    "${CMAKE_CURRENT_BINARY_DIR}/tensorflow-lite"
-    EXCLUDE_FROM_ALL
-  )
-else ()
-  message(STATUS "TensorFlow Lite library found: ${TENSORFLOW_LITE}")
-  set(TENSORFLOW_SOURCE_DIR "${WAMR_ROOT_DIR}/core/deps/tensorflow-src")
+if(WAMR_BUILD_WASI_NN_ENABLE_GPU EQUAL 1)
+  set(TFLITE_ENABLE_GPU ON)
 endif()
 
-set(TENSORFLOW_LITE_INCLUDE_DIR "${TENSORFLOW_SOURCE_DIR}/tensorflow/lite")
-set(FLATBUFFER_INCLUDE_DIR "${CMAKE_CURRENT_BINARY_DIR}/flatbuffers/include")
+if (CMAKE_SIZEOF_VOID_P EQUAL 4)
+  set(TFLITE_ENABLE_XNNPACK OFF)
+endif()
 
-include_directories(${TENSORFLOW_SOURCE_DIR})
-include_directories(${FLATBUFFER_INCLUDE_DIR})
-link_directories(${CMAKE_CURRENT_BINARY_DIR}/tensorflow-lite)
+FetchContent_MakeAvailable(tensorflow_lite)

+ 12 - 0
core/iwasm/libraries/wasi-nn/cmake/add_telemetry.patch

@@ -0,0 +1,12 @@
+diff --git a/tensorflow/lite/CMakeLists.txt b/tensorflow/lite/CMakeLists.txt
+index c71a3925ac..39591a3bd7 100644
+--- a/tensorflow/lite/CMakeLists.txt
++++ b/tensorflow/lite/CMakeLists.txt
+@@ -493,6 +493,7 @@ set(TFLITE_PROFILER_SRCS
+   ${TFLITE_SOURCE_DIR}/profiling/root_profiler.h
+   ${TFLITE_SOURCE_DIR}/profiling/root_profiler.cc
+   ${TFLITE_SOURCE_DIR}/profiling/telemetry/profiler.cc
++  ${TFLITE_SOURCE_DIR}/profiling/telemetry/telemetry.cc
+ )
+ if(CMAKE_SYSTEM_NAME MATCHES "Android")
+   list(APPEND TFLITE_PROFILER_SRCS

+ 58 - 22
core/iwasm/libraries/wasi-nn/cmake/wasi_nn.cmake

@@ -3,27 +3,6 @@
 
 list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR})
 
-if(WAMR_BUILD_WASI_NN_TFLITE EQUAL 1)
-  # Find tensorflow-lite
-  find_package(tensorflow_lite REQUIRED)
-endif()
-
-if(WAMR_BUILD_WASI_NN_OPENVINO EQUAL 1)
-  if(NOT DEFINED ENV{OpenVINO_DIR})
-    message(FATAL_ERROR
-        "OpenVINO_DIR is not defined. "
-        "Please follow https://docs.openvino.ai/2024/get-started/install-openvino.html,"
-        "install openvino, and set environment variable OpenVINO_DIR."
-        "Like OpenVINO_DIR=/usr/lib/openvino-2023.2/ cmake ..."
-        "Or OpenVINO_DIR=/opt/intel/openvino/ cmake ..."
-    )
-  endif()
-
-  list(APPEND CMAKE_MODULE_PATH $ENV{OpenVINO_DIR})
-  # Find OpenVINO
-  find_package(OpenVINO REQUIRED COMPONENTS Runtime)
-endif()
-
 #
 # wasi-nn general
 set(WASI_NN_ROOT ${CMAKE_CURRENT_LIST_DIR}/..)
@@ -42,22 +21,46 @@ add_compile_definitions(
 #
 # - tflite
 if(WAMR_BUILD_WASI_NN_TFLITE EQUAL 1)
+  find_package(tensorflow_lite REQUIRED)
+
   add_library(
     wasi_nn_tflite
     SHARED
       ${WASI_NN_ROOT}/src/wasi_nn_tensorflowlite.cpp
   )
 
+  target_include_directories(
+    wasi_nn_tflite
+    PUBLIC
+      ${tensorflow_lite_SOURCE_DIR}
+  )
+
   target_link_libraries(
     wasi_nn_tflite
     PUBLIC
       libiwasm
       tensorflow-lite
   )
+
+  install(TARGETS wasi_nn_tflite DESTINATION lib)
 endif()
 
 # - openvino
 if(WAMR_BUILD_WASI_NN_OPENVINO EQUAL 1)
+  if(NOT DEFINED ENV{OpenVINO_DIR})
+    message(FATAL_ERROR
+        "OpenVINO_DIR is not defined. "
+        "Please follow https://docs.openvino.ai/2024/get-started/install-openvino.html,"
+        "install openvino, and set environment variable OpenVINO_DIR."
+        "Like OpenVINO_DIR=/usr/lib/openvino-2023.2/ cmake ..."
+        "Or OpenVINO_DIR=/opt/intel/openvino/ cmake ..."
+    )
+  endif()
+
+  list(APPEND CMAKE_MODULE_PATH $ENV{OpenVINO_DIR})
+  # Find OpenVINO
+  find_package(OpenVINO REQUIRED COMPONENTS Runtime)
+
   add_library(
     wasi_nn_openvino
     SHARED
@@ -71,4 +74,37 @@ if(WAMR_BUILD_WASI_NN_OPENVINO EQUAL 1)
       openvino::runtime
       openvino::runtime::c
   )
-endif()
+
+  install(TARGETS wasi_nn_openvino DESTINATION lib)
+endif()
+
+# - llamacpp
+
+if(WAMR_BUILD_WASI_NN_LLAMACPP EQUAL 1)
+  find_package(cjson REQUIRED)
+  find_package(llamacpp REQUIRED)
+
+  add_library(
+    wasi_nn_llamacpp
+    SHARED
+      ${WASI_NN_ROOT}/src/wasi_nn_llamacpp.c
+  )
+
+  target_include_directories(
+    wasi_nn_llamacpp
+    PUBLIC
+      ${cjson_SOURCE_DIR}
+  )
+
+  target_link_libraries(
+    wasi_nn_llamacpp
+    PUBLIC
+      libiwasm
+      cjson
+      common
+      ggml
+      llama
+  )
+
+  install(TARGETS wasi_nn_llamacpp DESTINATION lib)
+endif()

+ 9 - 0
core/iwasm/libraries/wasi-nn/include/wasi_nn_types.h

@@ -43,6 +43,11 @@ typedef enum {
     security,
     // The operation failed for an unspecified reason.
     unknown,
+    // for WasmEdge-wasi-nn
+    end_of_sequence = 100,  // End of Sequence Found.
+    context_full = 101,     // Context Full.
+    prompt_tool_long = 102, // Prompt Too Long.
+    model_not_found = 103,  // Model Not Found.
 } wasi_nn_error;
 
 /**
@@ -140,6 +145,9 @@ typedef uint32_t graph_execution_context;
 typedef wasi_nn_error (*LOAD)(void *, graph_builder_array *, graph_encoding,
                               execution_target, graph *);
 typedef wasi_nn_error (*LOAD_BY_NAME)(void *, const char *, uint32_t, graph *);
+typedef wasi_nn_error (*LOAD_BY_NAME_WITH_CONFIG)(void *, const char *,
+                                                  uint32_t, void *, uint32_t,
+                                                  graph *);
 typedef wasi_nn_error (*INIT_EXECUTION_CONTEXT)(void *, graph,
                                                 graph_execution_context *);
 typedef wasi_nn_error (*SET_INPUT)(void *, graph_execution_context, uint32_t,
@@ -154,6 +162,7 @@ typedef wasi_nn_error (*BACKEND_DEINITIALIZE)(void *);
 typedef struct {
     LOAD load;
     LOAD_BY_NAME load_by_name;
+    LOAD_BY_NAME_WITH_CONFIG load_by_name_with_config;
     INIT_EXECUTION_CONTEXT init_execution_context;
     SET_INPUT set_input;
     COMPUTE compute;

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