Эх сурвалжийг харах

Merge pull request #3740 from bytecodealliance/main

Merge branch main into dev/dynamic_linking
Wenyong Huang 1 жил өмнө
parent
commit
cfc6f4ba55
34 өөрчлөгдсөн 2066 нэмэгдсэн , 420 устгасан
  1. 3 3
      .github/workflows/build_wamr_vscode_ext.yml
  2. 36 8
      .github/workflows/compilation_on_android_ubuntu.yml
  3. 24 19
      .github/workflows/compilation_on_nuttx.yml
  4. 23 3
      .github/workflows/nightly_run.yml
  5. 0 4
      .github/workflows/spec_test_on_nuttx.yml
  6. 74 0
      RELEASE_NOTES.md
  7. 5 0
      build-scripts/config_common.cmake
  8. 5 0
      core/config.h
  9. 171 72
      core/iwasm/aot/aot_loader.c
  10. 7 0
      core/iwasm/aot/aot_runtime.c
  11. 11 0
      core/iwasm/aot/aot_runtime.h
  12. 2 0
      core/iwasm/aot/arch/aot_reloc_riscv.c
  13. 36 2
      core/iwasm/common/wasm_memory.c
  14. 56 35
      core/iwasm/common/wasm_runtime_common.c
  15. 1 0
      core/iwasm/compilation/aot.c
  16. 28 32
      core/iwasm/compilation/aot_emit_const.c
  17. 1 0
      core/iwasm/compilation/aot_emit_memory.c
  18. 21 2
      core/iwasm/compilation/aot_llvm.c
  19. 6 0
      core/iwasm/compilation/aot_llvm_extra.cpp
  20. 1 0
      core/iwasm/fast-jit/fe/jit_emit_memory.c
  21. 8 0
      core/iwasm/interpreter/wasm.h
  22. 112 51
      core/iwasm/interpreter/wasm_interp_classic.c
  23. 1 0
      core/iwasm/interpreter/wasm_interp_fast.c
  24. 84 39
      core/iwasm/interpreter/wasm_loader.c
  25. 72 36
      core/iwasm/interpreter/wasm_mini_loader.c
  26. 159 100
      core/iwasm/interpreter/wasm_runtime.c
  27. 7 0
      core/iwasm/interpreter/wasm_runtime.h
  28. 3 2
      core/shared/platform/include/platform_api_extension.h
  29. 1 0
      core/shared/utils/bh_atomic.h
  30. 1 1
      core/version.h
  31. 24 2
      tests/wamr-test-suites/spec-test-script/all.py
  32. 1022 0
      tests/wamr-test-suites/spec-test-script/multi_memory_ignore_cases.patch
  33. 18 8
      tests/wamr-test-suites/spec-test-script/runtest.py
  34. 43 1
      tests/wamr-test-suites/test_wamr.sh

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

@@ -20,10 +20,10 @@ jobs:
     steps:
     steps:
       - uses: actions/checkout@v4
       - uses: actions/checkout@v4
 
 
-      - name: Use Node.js 16.x
+      - name: Use Node.js 18.x
         uses: actions/setup-node@v4
         uses: actions/setup-node@v4
         with:
         with:
-          node-version: 16.x
+          node-version: 18.x
 
 
       - name: set vscode extension to correct version
       - name: set vscode extension to correct version
         run: |
         run: |
@@ -33,7 +33,7 @@ jobs:
 
 
       - name: generate wamr ide vscode extension
       - name: generate wamr ide vscode extension
         run: |
         run: |
-          npm install -g vsce
+          npm install -g @vscode/vsce
           rm -rf node_modules
           rm -rf node_modules
           npm install
           npm install
           vsce package
           vsce package

+ 36 - 8
.github/workflows/compilation_on_android_ubuntu.yml

@@ -68,6 +68,7 @@ env:
   WAMR_COMPILER_TEST_OPTIONS: "-s wamr_compiler -S -b -P"
   WAMR_COMPILER_TEST_OPTIONS: "-s wamr_compiler -S -b -P"
   GC_TEST_OPTIONS: "-s spec -G -b -P"
   GC_TEST_OPTIONS: "-s spec -G -b -P"
   MEMORY64_TEST_OPTIONS: "-s spec -W -b -P"
   MEMORY64_TEST_OPTIONS: "-s spec -W -b -P"
+  MULTI_MEMORY_TEST_OPTIONS: "-s spec -E -b -P"
 
 
 jobs:
 jobs:
   build_llvm_libraries_on_ubuntu_2204:
   build_llvm_libraries_on_ubuntu_2204:
@@ -148,6 +149,7 @@ jobs:
             "-DWAMR_BUILD_TAIL_CALL=1",
             "-DWAMR_BUILD_TAIL_CALL=1",
             "-DWAMR_DISABLE_HW_BOUND_CHECK=1",
             "-DWAMR_DISABLE_HW_BOUND_CHECK=1",
             "-DWAMR_BUILD_MEMORY64=1",
             "-DWAMR_BUILD_MEMORY64=1",
+            "-DWAMR_BUILD_MULTI_MEMORY=1",
           ]
           ]
         os: [ubuntu-22.04]
         os: [ubuntu-22.04]
         platform: [android, linux]
         platform: [android, linux]
@@ -206,11 +208,9 @@ jobs:
             make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1"
             make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1"
           - make_options_run_mode: $MULTI_TIER_JIT_BUILD_OPTIONS
           - make_options_run_mode: $MULTI_TIER_JIT_BUILD_OPTIONS
             make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1"
             make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1"
-          # Memory64 only on CLASSIC INTERP mode, and only on 64-bit platform
+          # Memory64 only on CLASSIC INTERP and AOT mode, and only on 64-bit platform
           - make_options_feature: "-DWAMR_BUILD_MEMORY64=1"
           - make_options_feature: "-DWAMR_BUILD_MEMORY64=1"
             platform: android
             platform: android
-          - make_options_run_mode: $AOT_BUILD_OPTIONS
-            make_options_feature: "-DWAMR_BUILD_MEMORY64=1"
           - make_options_run_mode: $FAST_INTERP_BUILD_OPTIONS
           - make_options_run_mode: $FAST_INTERP_BUILD_OPTIONS
             make_options_feature: "-DWAMR_BUILD_MEMORY64=1"
             make_options_feature: "-DWAMR_BUILD_MEMORY64=1"
           - make_options_run_mode: $FAST_JIT_BUILD_OPTIONS
           - make_options_run_mode: $FAST_JIT_BUILD_OPTIONS
@@ -221,6 +221,21 @@ jobs:
             make_options_feature: "-DWAMR_BUILD_MEMORY64=1"
             make_options_feature: "-DWAMR_BUILD_MEMORY64=1"
           - make_options_run_mode: $MULTI_TIER_JIT_BUILD_OPTIONS
           - make_options_run_mode: $MULTI_TIER_JIT_BUILD_OPTIONS
             make_options_feature: "-DWAMR_BUILD_MEMORY64=1"
             make_options_feature: "-DWAMR_BUILD_MEMORY64=1"
+          # Multi memory only on CLASSIC INTERP mode, and only on 64-bit platform
+          - make_options_feature: "-DWAMR_BUILD_MEMORY64=1"
+            platform: android
+          - make_options_run_mode: $AOT_BUILD_OPTIONS
+            make_options_feature: "-DWAMR_BUILD_MULTI_MEMORY=1"
+          - make_options_run_mode: $FAST_INTERP_BUILD_OPTIONS
+            make_options_feature: "-DWAMR_BUILD_MULTI_MEMORY=1"
+          - make_options_run_mode: $FAST_JIT_BUILD_OPTIONS
+            make_options_feature: "-DWAMR_BUILD_MULTI_MEMORY=1"
+          - make_options_run_mode: $LLVM_LAZY_JIT_BUILD_OPTIONS
+            make_options_feature: "-DWAMR_BUILD_MULTI_MEMORY=1"
+          - make_options_run_mode: $LLVM_EAGER_JIT_BUILD_OPTIONS
+            make_options_feature: "-DWAMR_BUILD_MULTI_MEMORY=1"
+          - make_options_run_mode: $MULTI_TIER_JIT_BUILD_OPTIONS
+            make_options_feature: "-DWAMR_BUILD_MULTI_MEMORY=1"
           # Fast-JIT and Multi-Tier-JIT mode don't support android
           # Fast-JIT and Multi-Tier-JIT mode don't support android
           - make_options_run_mode: $FAST_JIT_BUILD_OPTIONS
           - make_options_run_mode: $FAST_JIT_BUILD_OPTIONS
             platform: android
             platform: android
@@ -593,6 +608,7 @@ jobs:
             $WASI_TEST_OPTIONS,
             $WASI_TEST_OPTIONS,
             $GC_TEST_OPTIONS,
             $GC_TEST_OPTIONS,
             $MEMORY64_TEST_OPTIONS,
             $MEMORY64_TEST_OPTIONS,
+            $MULTI_MEMORY_TEST_OPTIONS,
           ]
           ]
         wasi_sdk_release:
         wasi_sdk_release:
           [
           [
@@ -640,18 +656,30 @@ jobs:
             test_option: $MEMORY64_TEST_OPTIONS
             test_option: $MEMORY64_TEST_OPTIONS
           - running_mode: "multi-tier-jit"
           - running_mode: "multi-tier-jit"
             test_option: $MEMORY64_TEST_OPTIONS
             test_option: $MEMORY64_TEST_OPTIONS
+          # aot, fast-interp, fast-jit, llvm-jit, multi-tier-jit don't support Multi Memory 
+          - running_mode: "aot"
+            test_option: $MULTI_MEMORY_TEST_OPTIONS
+          - running_mode: "fast-interp"
+            test_option: $MULTI_MEMORY_TEST_OPTIONS
+          - running_mode: "fast-jit"
+            test_option: $MULTI_MEMORY_TEST_OPTIONS
+          - running_mode: "jit"
+            test_option: $MULTI_MEMORY_TEST_OPTIONS
+          - running_mode: "multi-tier-jit"
+            test_option: $MULTI_MEMORY_TEST_OPTIONS
+
     steps:
     steps:
       - name: checkout
       - name: checkout
         uses: actions/checkout@v4
         uses: actions/checkout@v4
 
 
       - name: Set-up OCaml
       - name: Set-up OCaml
         uses: ocaml/setup-ocaml@v3
         uses: ocaml/setup-ocaml@v3
-        if: matrix.test_option == '$GC_TEST_OPTIONS' || matrix.test_option == '$MEMORY64_TEST_OPTIONS'
+        if: matrix.test_option == '$GC_TEST_OPTIONS'
         with:
         with:
           ocaml-compiler: 4.13
           ocaml-compiler: 4.13
 
 
       - name: Set-up Ocamlbuild
       - name: Set-up Ocamlbuild
-        if: matrix.test_option == '$GC_TEST_OPTIONS' || matrix.test_option == '$MEMORY64_TEST_OPTIONS'
+        if: matrix.test_option == '$GC_TEST_OPTIONS'
         run: opam install ocamlbuild dune menhir
         run: opam install ocamlbuild dune menhir
 
 
       - name: download and install wasi-sdk
       - name: download and install wasi-sdk
@@ -717,13 +745,13 @@ jobs:
 
 
       - name: run tests
       - name: run tests
         timeout-minutes: 30
         timeout-minutes: 30
-        if: matrix.test_option != '$GC_TEST_OPTIONS' && matrix.test_option != '$MEMORY64_TEST_OPTIONS'
+        if: matrix.test_option != '$GC_TEST_OPTIONS'
         run: ./test_wamr.sh ${{ matrix.test_option }} -t ${{ matrix.running_mode }}
         run: ./test_wamr.sh ${{ matrix.test_option }} -t ${{ matrix.running_mode }}
         working-directory: ./tests/wamr-test-suites
         working-directory: ./tests/wamr-test-suites
 
 
-      - name: run gc or memory64 tests
+      - name: run gc tests
         timeout-minutes: 20
         timeout-minutes: 20
-        if: matrix.test_option == '$GC_TEST_OPTIONS' || matrix.test_option == '$MEMORY64_TEST_OPTIONS'
+        if: matrix.test_option == '$GC_TEST_OPTIONS'
         run: |
         run: |
           eval $(opam env)
           eval $(opam env)
           ./test_wamr.sh ${{ matrix.test_option }} -t ${{ matrix.running_mode }}
           ./test_wamr.sh ${{ matrix.test_option }} -t ${{ matrix.running_mode }}

+ 24 - 19
.github/workflows/compilation_on_nuttx.yml

@@ -68,18 +68,17 @@ jobs:
           # arm64
           # arm64
           "boards/arm64/qemu/qemu-armv8a/configs/nsh",
           "boards/arm64/qemu/qemu-armv8a/configs/nsh",
         ]
         ]
-        wamr_config_option: [
-          "CONFIG_INTERPRETERS_WAMR=y\\nCONFIG_INTERPRETERS_WAMR_AOT=y\\nCONFIG_INTERPRETERS_WAMR_FAST=y\\n",
-          "CONFIG_INTERPRETERS_WAMR=y\\nCONFIG_INTERPRETERS_WAMR_AOT=y\\nCONFIG_INTERPRETERS_WAMR_FAST=y\\nCONFIG_INTERPRETERS_WAMR_LIBC_WASI=y\\n",
-          "CONFIG_INTERPRETERS_WAMR=y\\nCONFIG_INTERPRETERS_WAMR_AOT=y\\nCONFIG_INTERPRETERS_WAMR_FAST=y\\nCONFIG_INTERPRETERS_WAMR_LIBC_BUILTIN=y\\n",
-          "CONFIG_INTERPRETERS_WAMR=y\\nCONFIG_INTERPRETERS_WAMR_AOT=y\\nCONFIG_INTERPRETERS_WAMR_CLASSIC=y\\n",
-          "CONFIG_INTERPRETERS_WAMR=y\\nCONFIG_INTERPRETERS_WAMR_AOT=y\\nCONFIG_INTERPRETERS_WAMR_CLASSIC=y\\nCONFIG_INTERPRETERS_WAMR_LIBC_WASI=y\\n",
-          "CONFIG_INTERPRETERS_WAMR=y\\nCONFIG_INTERPRETERS_WAMR_AOT=y\\nCONFIG_INTERPRETERS_WAMR_CLASSIC=y\\nCONFIG_INTERPRETERS_WAMR_LIBC_BUILTIN=y\\n",
-          "CONFIG_INTERPRETERS_WAMR=y\\nCONFIG_INTERPRETERS_WAMR_AOT=y\\nCONFIG_INTERPRETERS_WAMR_LIBC_BUILTIN=y\\n",
-          "CONFIG_INTERPRETERS_WAMR=y\\nCONFIG_INTERPRETERS_WAMR_AOT=y\\n",
-          "CONFIG_INTERPRETERS_WAMR=y\\nCONFIG_INTERPRETERS_WAMR_FAST=y\\n",
-          "CONFIG_INTERPRETERS_WAMR=y\\nCONFIG_INTERPRETERS_WAMR_CLASSIC=y\\n",
-        ]
+
+        wamr_config_option:
+          - "CONFIG_INTERPRETERS_WAMR_AOT"
+          - "CONFIG_INTERPRETERS_WAMR_FAST"
+          - "CONFIG_INTERPRETERS_WAMR_CLASSIC"
+          - "CONFIG_INTERPRETERS_WAMR_AOT CONFIG_INTERPRETERS_WAMR_FAST"
+          - "CONFIG_INTERPRETERS_WAMR_AOT CONFIG_INTERPRETERS_WAMR_FAST CONFIG_INTERPRETERS_WAMR_LIBC_WASI"
+          - "CONFIG_INTERPRETERS_WAMR_AOT CONFIG_INTERPRETERS_WAMR_FAST CONFIG_INTERPRETERS_WAMR_LIBC_BUILTIN"
+          - "CONFIG_INTERPRETERS_WAMR_AOT CONFIG_INTERPRETERS_WAMR_CLASSIC"
+          - "CONFIG_INTERPRETERS_WAMR_AOT CONFIG_INTERPRETERS_WAMR_CLASSIC CONFIG_INTERPRETERS_WAMR_LIBC_WASI"
+          - "CONFIG_INTERPRETERS_WAMR_AOT CONFIG_INTERPRETERS_WAMR_CLASSIC CONFIG_INTERPRETERS_WAMR_LIBC_WASI"
 
 
     steps:
     steps:
       - name: Checkout NuttX
       - name: Checkout NuttX
@@ -102,16 +101,22 @@ jobs:
           repository: ${{ github.repository }}
           repository: ${{ github.repository }}
           path: apps/interpreters/wamr/wamr
           path: apps/interpreters/wamr/wamr
 
 
-      - name: Enable WAMR for NuttX
+      - name: Configure WAMR
+        working-directory: nuttx
         run: |
         run: |
-          find nuttx/boards -name defconfig | xargs sed -i '$a\CONFIG_EOL_IS_LF=y\n${{ matrix.wamr_config_option }}'
-          find nuttx/boards/sim -name defconfig | xargs sed -i '$a\CONFIG_LIBM=y\n'
+          tools/configure.sh ${{ matrix.nuttx_board_config }}
+          kconfig-tweak --enable CONFIG_PSEUDOFS_SOFTLINKS
+          kconfig-tweak --enable CONFIG_INTERPRETERS_WAMR
+          kconfig-tweak --enable CONFIG_INTERPRETERS_IWASM_TASK
+          kconfig-tweak --set-val CONFIG_INTERPRETERS_WAMR_PRIORITY 100
+          kconfig-tweak --set-val CONFIG_INTERPRETERS_WAMR_STACKSIZE 8192
+          for x in ${{ matrix.wamr_config_option }}; do
+            kconfig-tweak --enable $x
+          done
 
 
       - name: Build
       - name: Build
-        run: |
-          cd nuttx
-          tools/configure.sh ${{ matrix.nuttx_board_config }}
-          make -j$(nproc) EXTRAFLAGS=-Werror
+        working-directory: nuttx
+        run: make -j$(nproc) EXTRAFLAGS=-Werror
 
 
       - name: Checkout Bloaty
       - name: Checkout Bloaty
         uses: actions/checkout@v3
         uses: actions/checkout@v3

+ 23 - 3
.github/workflows/nightly_run.yml

@@ -132,6 +132,7 @@ jobs:
             "-DWAMR_BUILD_TAIL_CALL=1",
             "-DWAMR_BUILD_TAIL_CALL=1",
             "-DWAMR_DISABLE_HW_BOUND_CHECK=1",
             "-DWAMR_DISABLE_HW_BOUND_CHECK=1",
             "-DWAMR_BUILD_MEMORY64=1",
             "-DWAMR_BUILD_MEMORY64=1",
+            "-DWAMR_BUILD_MULTI_MEMORY=1",
           ]
           ]
         os: [ubuntu-20.04]
         os: [ubuntu-20.04]
         platform: [android, linux]
         platform: [android, linux]
@@ -190,11 +191,9 @@ jobs:
             make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1"
             make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1"
           - make_options_run_mode: $MULTI_TIER_JIT_BUILD_OPTIONS
           - make_options_run_mode: $MULTI_TIER_JIT_BUILD_OPTIONS
             make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1"
             make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1"
-          # Memory64 only on CLASSIC INTERP mode, and only on 64-bit platform
+          # Memory64 only on CLASSIC INTERP and AOT mode, and only on 64-bit platform
           - make_options_feature: "-DWAMR_BUILD_MEMORY64=1"
           - make_options_feature: "-DWAMR_BUILD_MEMORY64=1"
             platform: android
             platform: android
-          - make_options_run_mode: $AOT_BUILD_OPTIONS
-            make_options_feature: "-DWAMR_BUILD_MEMORY64=1"
           - make_options_run_mode: $FAST_INTERP_BUILD_OPTIONS
           - make_options_run_mode: $FAST_INTERP_BUILD_OPTIONS
             make_options_feature: "-DWAMR_BUILD_MEMORY64=1"
             make_options_feature: "-DWAMR_BUILD_MEMORY64=1"
           - make_options_run_mode: $FAST_JIT_BUILD_OPTIONS
           - make_options_run_mode: $FAST_JIT_BUILD_OPTIONS
@@ -205,6 +204,21 @@ jobs:
             make_options_feature: "-DWAMR_BUILD_MEMORY64=1"
             make_options_feature: "-DWAMR_BUILD_MEMORY64=1"
           - make_options_run_mode: $MULTI_TIER_JIT_BUILD_OPTIONS
           - make_options_run_mode: $MULTI_TIER_JIT_BUILD_OPTIONS
             make_options_feature: "-DWAMR_BUILD_MEMORY64=1"
             make_options_feature: "-DWAMR_BUILD_MEMORY64=1"
+          # Multi memory only on CLASSIC INTERP mode, and only on 64-bit platform
+          - make_options_feature: "-DWAMR_BUILD_MEMORY64=1"
+            platform: android
+          - make_options_run_mode: $AOT_BUILD_OPTIONS
+            make_options_feature: "-DWAMR_BUILD_MULTI_MEMORY=1"
+          - make_options_run_mode: $FAST_INTERP_BUILD_OPTIONS
+            make_options_feature: "-DWAMR_BUILD_MULTI_MEMORY=1"
+          - make_options_run_mode: $FAST_JIT_BUILD_OPTIONS
+            make_options_feature: "-DWAMR_BUILD_MULTI_MEMORY=1"
+          - make_options_run_mode: $LLVM_LAZY_JIT_BUILD_OPTIONS
+            make_options_feature: "-DWAMR_BUILD_MULTI_MEMORY=1"
+          - make_options_run_mode: $LLVM_EAGER_JIT_BUILD_OPTIONS
+            make_options_feature: "-DWAMR_BUILD_MULTI_MEMORY=1"
+          - make_options_run_mode: $MULTI_TIER_JIT_BUILD_OPTIONS
+            make_options_feature: "-DWAMR_BUILD_MULTI_MEMORY=1"
           # Fast-JIT and Multi-Tier-JIT mode don't support android
           # Fast-JIT and Multi-Tier-JIT mode don't support android
           - make_options_run_mode: $FAST_JIT_BUILD_OPTIONS
           - make_options_run_mode: $FAST_JIT_BUILD_OPTIONS
             platform: android
             platform: android
@@ -289,6 +303,7 @@ jobs:
             "-DWAMR_BUILD_TAIL_CALL=1",
             "-DWAMR_BUILD_TAIL_CALL=1",
             "-DWAMR_DISABLE_HW_BOUND_CHECK=1",
             "-DWAMR_DISABLE_HW_BOUND_CHECK=1",
             "-DWAMR_BUILD_MEMORY64=1",
             "-DWAMR_BUILD_MEMORY64=1",
+            "-DWAMR_BUILD_MULTI_MEMORY=1",
           ]
           ]
         exclude:
         exclude:
           # incompatible feature and platform
           # incompatible feature and platform
@@ -322,6 +337,11 @@ jobs:
             make_options_feature: "-DWAMR_BUILD_MEMORY64=1"
             make_options_feature: "-DWAMR_BUILD_MEMORY64=1"
           - make_options_run_mode: $FAST_JIT_BUILD_OPTIONS
           - make_options_run_mode: $FAST_JIT_BUILD_OPTIONS
             make_options_feature: "-DWAMR_BUILD_MEMORY64=1"
             make_options_feature: "-DWAMR_BUILD_MEMORY64=1"
+          # Memory64 only on CLASSIC INTERP mode
+          - make_options_run_mode: $FAST_INTERP_BUILD_OPTIONS
+            make_options_feature: "-DWAMR_BUILD_MULTI_MEMORY=1"
+          - make_options_run_mode: $FAST_JIT_BUILD_OPTIONS
+            make_options_feature: "-DWAMR_BUILD_MULTI_MEMORY=1"
     steps:
     steps:
       - name: Install dependencies
       - name: Install dependencies
         run: |
         run: |

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

@@ -125,10 +125,6 @@ jobs:
           - target_config: { config: "boards/risc-v/qemu-rv/rv-virt/configs/nsh64" }
           - target_config: { config: "boards/risc-v/qemu-rv/rv-virt/configs/nsh64" }
             wamr_test_option: { mode: "-t aot -X" }
             wamr_test_option: { mode: "-t aot -X" }
 
 
-          # XIP is not fully supported yet on RISCV32 ILP32F, some relocations can not be resolved
-          - target_config: { config: "boards/risc-v/qemu-rv/rv-virt/configs/nsh", fpu_type: "fp" }
-            wamr_test_option:  { mode: "-t aot -X" }
-
           # Our xtensa environment doesn't have enough memory
           # Our xtensa environment doesn't have enough memory
           - target_config: { target: "xtensa" }
           - target_config: { target: "xtensa" }
             wamr_feature_option: { mode: "-G" }
             wamr_feature_option: { mode: "-G" }

+ 74 - 0
RELEASE_NOTES.md

@@ -1,3 +1,77 @@
+## WAMR-2.1.2
+
+### Breaking Changes
+ - wasi-nn: Apply new architecture (#3692)
+
+### New Features
+ - [wasi-nn] Add a new wasi-nn backend openvino (#3603)
+ - Add APIs into wasm_c_api.h to summary wasm function execution duration (#3639)
+ - Add support for RISCV32 ILP32F (#3708)
+
+### Bug Fixes
+ - libc-builtin: Fix function prototype for wasm_runtime_module_realloc (#3702)
+ - Fix potential memory leak in insert_native_symbol (#3712)
+ - aot compiler: Fix NaN handling for opcode f32/f64.const in XIP mode (#3721)
+ - Fix table idx resolving in op call_indirect/return_call_indirect (#3726)
+
+### Enhancements
+ - Remove a few hardcoded spec test knowledge from the core library (#3648)
+ - Change log of import function to be consistent (#3656)
+ - libc-builtin: Fix a printf format (#3652)
+ - Set compile symbol visibility to hidden in cmake (#3655)
+ - wamrc: Add --mllvm= option (#3658)
+ - wamr-compiler: Avoid size-level tweak if target is specified (#3659)
+ - aot runtime: Add missing arm/thumb relocations (#3660)
+ - aot compiler: Enlarge AOTNativeSymbol->symbol (#3662)
+ - aot compiler: Bail out on too long native symbol names (#3663)
+ - Support more features for rt-thread (#3661)
+ - Zephyr User Mode Support (#3650)
+ - Set posix thread name for debug build (#3657)
+ - Add emscripten_sleep() wrapper to libc-emcc (#3669)
+ - Fix a compilation warning (#3682)
+ - wamrc: Add some help text for --size-level (#3689)
+ - Restore linux iwasm default visibility (#3691)
+ - posix_thread.c: Restore old signal alternate stack before thread exit (#3693)
+ - libc-wasi: Make rights of STDIN/STDOUT/STDERR fixed and overlook their access modes (#3694)
+ - [refactoring] Extract read leb to a separate file, share the code between loader and mini loader (#3701)
+ - debug-interp: Only add lock when signal_flag is SIG_SINGSTEP (#3704)
+ - Fix compilation warnings (#3707)
+ - Add missing headers in bh_atomic.h and aot_llvm_extra.cpp (#3715)
+ - Update std atomic check and simd compatibility check for arc compiler (#3716)
+ - aot compiler: Track non-0x00 tableindex as ref types use (#3695)
+ - compilation: Use the dedicated stack-sizes section only for AOT (#3732)
+ - riscv: Add missing relocation intrinsics for __fixdfsi/__ltdf2 (#3733)
+
+### Others
+ - Fix night run CI (#3640)
+ - spec-test-script/runtest.py: Don't assume the tmp dir path (#3632)
+ - wamr-test-suites: Remove dead code (wasi_test) (#3634)
+ - wamr-test-suites/test_wamr.sh: Add an option to specify wamrc binary (#3635)
+ - CI: Build llvm for xtensa (#3637)
+ - spec-test-script/runtest.py: Avoid specifying -v=0 unnecessarily (#3642)
+ - spec-test-script: Add xtensa case (#3643)
+ - spec-test-script/runtest.py: Move "--size-level=1" to common place for RISCV64 (#3644)
+ - spec-test-script/runtest.py: Use a shorter timeout when expected to fail (#3647)
+ - spec-test-script: Make case_last_words larger (#3651)
+ - spec-test-script/runtest.py: Reduce stack size for aot w/o gc (#3653)
+ - spec-test-script: Skip a few tests for xtensa qemu (#3664)
+ - spec-test-script: Use -mtext-section-literals for xtensa xip (#3666)
+ - spec_test_on_nuttx.yml: Add xtensa (#3665)
+ - spec_test_on_nuttx.yml: Enable xip (#3671)
+ - spec_test_on_nuttx.yml: Record more logs (#3670)
+ - spec_test_on_nuttx.yml: Replace sed with kconfig-tweak (#3672)
+ - spec_test_on_nuttx.yml: Retire CONFIG_EOL_IS_LF (#3676)
+ - spec-test-script/runtest.py: Use wamrc --xip option for xip (#3683)
+ - CI: Bump NuttX version to 12.6 (#3684)
+ - wamr-test-suites: Clean up generated tmp files after spec test (#3700)
+ - test_wamr.sh: Fix build wabt tool (#3703)
+ - NuttX: Retire CONFIG_ARCH_RV32IM and CONFIG_ARCH_RV64GC (#3717)
+ - runtest.py: Normallize option handling for XIP mode (#3722)
+ - CI: Enable XIP spectest for RISCV32 ILP32F (#3727)
+ - CI: Unify configuration stage for NuttX (#3725)
+
+---
+
 ## WAMR-2.1.1
 ## WAMR-2.1.1
 
 
 ### Breaking Changes
 ### Breaking Changes

+ 5 - 0
build-scripts/config_common.cmake

@@ -265,6 +265,11 @@ if (WAMR_BUILD_MEMORY64 EQUAL 1)
   set (WAMR_DISABLE_HW_BOUND_CHECK 1)
   set (WAMR_DISABLE_HW_BOUND_CHECK 1)
   message ("     Memory64 memory enabled")
   message ("     Memory64 memory enabled")
 endif ()
 endif ()
+if (WAMR_BUILD_MULTI_MEMORY EQUAL 1)
+  add_definitions (-DWASM_ENABLE_MULTI_MEMORY=1)
+  message ("     Multi memory enabled")
+  set (WAMR_BUILD_DEBUG_INTERP 0)
+endif ()
 if (WAMR_BUILD_THREAD_MGR EQUAL 1)
 if (WAMR_BUILD_THREAD_MGR EQUAL 1)
   message ("     Thread manager enabled")
   message ("     Thread manager enabled")
 endif ()
 endif ()

+ 5 - 0
core/config.h

@@ -664,6 +664,11 @@
 #define WASM_ENABLE_MEMORY64 0
 #define WASM_ENABLE_MEMORY64 0
 #endif
 #endif
 
 
+/* Disable multi-memory by default */
+#ifndef WASM_ENABLE_MULTI_MEMORY
+#define WASM_ENABLE_MULTI_MEMORY 0
+#endif
+
 #ifndef WASM_TABLE_MAX_SIZE
 #ifndef WASM_TABLE_MAX_SIZE
 #define WASM_TABLE_MAX_SIZE 1024
 #define WASM_TABLE_MAX_SIZE 1024
 #endif
 #endif

+ 171 - 72
core/iwasm/aot/aot_loader.c

@@ -294,6 +294,39 @@ loader_malloc(uint64 size, char *error_buf, uint32 error_buf_size)
     return mem;
     return mem;
 }
 }
 
 
+static void *
+loader_mmap(uint32 size, bool prot_exec, char *error_buf, uint32 error_buf_size)
+{
+    int map_prot =
+        MMAP_PROT_READ | MMAP_PROT_WRITE | (prot_exec ? MMAP_PROT_EXEC : 0);
+    int map_flags;
+    void *mem;
+
+#if UINTPTR_MAX == UINT64_MAX
+    /* 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.
+       We try to mmap with MMAP_MAP_32BIT flag first, and if fails, mmap
+       again without the flag. */
+    map_flags = MMAP_MAP_32BIT;
+    if ((mem = os_mmap(NULL, size, map_prot, map_flags,
+                       os_get_invalid_handle()))) {
+        /* The mmapped memory must be in the first 2 Gigabytes of the
+           process address space */
+        bh_assert((uintptr_t)mem < INT32_MAX);
+        return mem;
+    }
+#endif
+
+    map_flags = MMAP_MAP_NONE;
+    if (!(mem = os_mmap(NULL, size, map_prot, map_flags,
+                        os_get_invalid_handle()))) {
+        set_error_buf(error_buf, error_buf_size, "allocate memory failed");
+        return NULL;
+    }
+    return mem;
+}
+
 static char *
 static char *
 load_string(uint8 **p_buf, const uint8 *buf_end, AOTModule *module,
 load_string(uint8 **p_buf, const uint8 *buf_end, AOTModule *module,
             bool is_load_from_file_buf,
             bool is_load_from_file_buf,
@@ -2378,7 +2411,6 @@ destroy_object_data_sections(AOTObjectDataSection *data_sections,
                 }
                 }
             }
             }
 #endif
 #endif
-            os_munmap(data_section->data, data_section->size);
         }
         }
     wasm_runtime_free(data_sections);
     wasm_runtime_free(data_sections);
 }
 }
@@ -2392,6 +2424,9 @@ load_object_data_sections(const uint8 **p_buf, const uint8 *buf_end,
     AOTObjectDataSection *data_sections;
     AOTObjectDataSection *data_sections;
     uint64 size;
     uint64 size;
     uint32 i;
     uint32 i;
+    uint64 total_size = 0;
+    uint32 page_size = os_getpagesize();
+    uint8 *merged_sections = NULL;
 
 
     /* Allocate memory */
     /* Allocate memory */
     size = sizeof(AOTObjectDataSection) * (uint64)module->data_section_count;
     size = sizeof(AOTObjectDataSection) * (uint64)module->data_section_count;
@@ -2400,41 +2435,40 @@ load_object_data_sections(const uint8 **p_buf, const uint8 *buf_end,
         return false;
         return false;
     }
     }
 
 
-    /* Create each data section */
+    /* First iteration: read data from buf, and calculate total memory needed */
     for (i = 0; i < module->data_section_count; i++) {
     for (i = 0; i < module->data_section_count; i++) {
-        int map_prot = MMAP_PROT_READ | MMAP_PROT_WRITE;
-#if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64) \
-    || defined(BUILD_TARGET_RISCV64_LP64D)                       \
-    || defined(BUILD_TARGET_RISCV64_LP64)
-        /* aot code and data in x86_64 must be in range 0 to 2G due to
-           relocation for R_X86_64_32/32S/PC32 */
-        int map_flags = MMAP_MAP_32BIT;
-#else
-        int map_flags = MMAP_MAP_NONE;
-#endif
-
         read_string(buf, buf_end, data_sections[i].name);
         read_string(buf, buf_end, data_sections[i].name);
         read_uint32(buf, buf_end, data_sections[i].size);
         read_uint32(buf, buf_end, data_sections[i].size);
-
+        CHECK_BUF(buf, buf_end, data_sections[i].size);
+        /* Temporary record data ptr for merge, will be replaced after the
+           merged_data_sections is mmapped */
+        if (data_sections[i].size > 0)
+            data_sections[i].data = (uint8 *)buf;
+        buf += data_sections[i].size;
+        total_size += align_uint64((uint64)data_sections[i].size, page_size);
+    }
+    if (total_size > UINT32_MAX) {
+        set_error_buf(error_buf, error_buf_size, "data sections too large");
+        return false;
+    }
+    if (total_size > 0) {
         /* Allocate memory for data */
         /* Allocate memory for data */
-        if (data_sections[i].size > 0
-            && !(data_sections[i].data =
-                     os_mmap(NULL, data_sections[i].size, map_prot, map_flags,
-                             os_get_invalid_handle()))) {
-            set_error_buf(error_buf, error_buf_size, "allocate memory failed");
+        merged_sections = module->merged_data_sections =
+            loader_mmap((uint32)total_size, false, error_buf, error_buf_size);
+        if (!merged_sections) {
             return false;
             return false;
         }
         }
-#if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64)
-#if !defined(BH_PLATFORM_LINUX_SGX) && !defined(BH_PLATFORM_WINDOWS) \
-    && !defined(BH_PLATFORM_DARWIN)
-        /* address must be in the first 2 Gigabytes of
-           the process address space */
-        bh_assert((uintptr_t)data_sections[i].data < INT32_MAX);
-#endif
-#endif
+        module->merged_data_sections_size = (uint32)total_size;
+    }
 
 
-        read_byte_array(buf, buf_end, data_sections[i].data,
-                        data_sections[i].size);
+    /* Second iteration: Create each data section */
+    for (i = 0; i < module->data_section_count; i++) {
+        if (data_sections[i].size > 0) {
+            bh_memcpy_s(merged_sections, data_sections[i].size,
+                        data_sections[i].data, data_sections[i].size);
+            data_sections[i].data = merged_sections;
+            merged_sections += align_uint(data_sections[i].size, page_size);
+        }
     }
     }
 
 
     *p_buf = buf;
     *p_buf = buf;
@@ -2532,6 +2566,82 @@ fail:
     return false;
     return false;
 }
 }
 
 
+#if !defined(BH_PLATFORM_NUTTX) && !defined(BH_PLATFORM_ESP_IDF)
+static bool
+try_merge_data_and_text(const uint8 **buf, const uint8 **buf_end,
+                        AOTModule *module, char *error_buf,
+                        uint32 error_buf_size)
+{
+    uint8 *old_buf = (uint8 *)*buf;
+    uint8 *old_end = (uint8 *)*buf_end;
+    size_t code_size = (size_t)(old_end - old_buf);
+    uint32 page_size = os_getpagesize();
+    uint64 total_size = 0;
+    uint32 i;
+    uint8 *sections;
+
+    if (code_size == 0) {
+        return true;
+    }
+
+    /* calculate the total memory needed */
+    total_size += align_uint64((uint64)code_size, page_size);
+    for (i = 0; i < module->data_section_count; ++i) {
+        total_size +=
+            align_uint64((uint64)module->data_sections[i].size, page_size);
+    }
+    /* distance between .data and .text should not be greater than 4GB
+       for some targets (e.g. arm64 reloc need < 4G distance) */
+    if (total_size > UINT32_MAX) {
+        return false;
+    }
+    /* code_size was checked and must be larger than 0 here */
+    bh_assert(total_size > 0);
+
+    sections = loader_mmap((uint32)total_size, false, NULL, 0);
+    if (!sections) {
+        /* merge failed but may be not critical for some targets */
+        return false;
+    }
+    /* change the code part to be executable */
+    if (os_mprotect(sections, code_size,
+                    MMAP_PROT_READ | MMAP_PROT_WRITE | MMAP_PROT_EXEC)
+        != 0) {
+        os_munmap(sections, (uint32)total_size);
+        return false;
+    }
+
+    module->merged_data_text_sections = sections;
+    module->merged_data_text_sections_size = (uint32)total_size;
+
+    /* 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);
+    os_munmap(old_buf, code_size);
+    sections += align_uint((uint32)code_size, page_size);
+
+    /* then migrate .data sections */
+    for (i = 0; i < module->data_section_count; ++i) {
+        AOTObjectDataSection *data_section = module->data_sections + i;
+        uint8 *old_data = data_section->data;
+        data_section->data = sections;
+        bh_memcpy_s(data_section->data, data_section->size, old_data,
+                    data_section->size);
+        sections += align_uint(data_section->size, page_size);
+    }
+    /* free the original data sections */
+    if (module->merged_data_sections) {
+        os_munmap(module->merged_data_sections,
+                  module->merged_data_sections_size);
+        module->merged_data_sections = NULL;
+        module->merged_data_sections_size = 0;
+    }
+
+    return true;
+}
+#endif /* ! defined(BH_PLATFORM_NUTTX) && !defined(BH_PLATFORM_ESP_IDF) */
+
 static bool
 static bool
 load_text_section(const uint8 *buf, const uint8 *buf_end, AOTModule *module,
 load_text_section(const uint8 *buf, const uint8 *buf_end, AOTModule *module,
                   char *error_buf, uint32 error_buf_size)
                   char *error_buf, uint32 error_buf_size)
@@ -3391,16 +3501,9 @@ load_relocation_section(const uint8 *buf, const uint8 *buf_end,
            + sizeof(uint64) * module->real_plt_count
            + sizeof(uint64) * module->real_plt_count
            + sizeof(uint32) * module->float_plt_count;
            + sizeof(uint32) * module->float_plt_count;
     if (size > 0) {
     if (size > 0) {
-        map_prot = MMAP_PROT_READ | MMAP_PROT_WRITE | MMAP_PROT_EXEC;
-        /* aot code and data in x86_64 must be in range 0 to 2G due to
-           relocation for R_X86_64_32/32S/PC32 */
-        map_flags = MMAP_MAP_32BIT;
-
         if (size > UINT32_MAX
         if (size > UINT32_MAX
-            || !(module->extra_plt_data =
-                     os_mmap(NULL, (uint32)size, map_prot, map_flags,
-                             os_get_invalid_handle()))) {
-            set_error_buf(error_buf, error_buf_size, "mmap memory failed");
+            || !(module->extra_plt_data = loader_mmap(
+                     (uint32)size, true, error_buf, error_buf_size))) {
             goto fail;
             goto fail;
         }
         }
         module->extra_plt_data_size = (uint32)size;
         module->extra_plt_data_size = (uint32)size;
@@ -3512,19 +3615,12 @@ load_relocation_section(const uint8 *buf, const uint8 *buf_end,
         GOTItem *got_item = module->got_item_list;
         GOTItem *got_item = module->got_item_list;
         uint32 got_item_idx = 0;
         uint32 got_item_idx = 0;
 
 
-        map_prot = MMAP_PROT_READ | MMAP_PROT_WRITE;
-        /* aot code and data in x86_64 must be in range 0 to 2G due to
-           relocation for R_X86_64_32/32S/PC32 */
-        map_flags = MMAP_MAP_32BIT;
-
         /* Create the GOT for func_ptrs, note that it is different from
         /* Create the GOT for func_ptrs, note that it is different from
            the .got section of a dynamic object file */
            the .got section of a dynamic object file */
         size = (uint64)sizeof(void *) * got_item_count;
         size = (uint64)sizeof(void *) * got_item_count;
         if (size > UINT32_MAX
         if (size > UINT32_MAX
-            || !(module->got_func_ptrs =
-                     os_mmap(NULL, (uint32)size, map_prot, map_flags,
-                             os_get_invalid_handle()))) {
-            set_error_buf(error_buf, error_buf_size, "mmap memory failed");
+            || !(module->got_func_ptrs = loader_mmap(
+                     (uint32)size, false, error_buf, error_buf_size))) {
             goto fail;
             goto fail;
         }
         }
 
 
@@ -3749,6 +3845,17 @@ load_from_sections(AOTModule *module, AOTSection *sections,
                     return false;
                     return false;
                 break;
                 break;
             case AOT_SECTION_TYPE_TEXT:
             case AOT_SECTION_TYPE_TEXT:
+#if !defined(BH_PLATFORM_NUTTX) && !defined(BH_PLATFORM_ESP_IDF)
+                /* try to merge .data and .text, with exceptions:
+                 * 1. XIP mode
+                 * 2. pre-mmapped module load from aot_load_from_sections()
+                 * 3. nuttx & esp-idf: have separate region for MMAP_PROT_EXEC
+                 */
+                if (!module->is_indirect_mode && is_load_from_file_buf)
+                    if (!try_merge_data_and_text(&buf, &buf_end, module,
+                                                 error_buf, error_buf_size))
+                        LOG_WARNING("merge .data and .text sections failed");
+#endif /* ! defined(BH_PLATFORM_NUTTX) && !defined(BH_PLATFORM_ESP_IDF) */
                 if (!load_text_section(buf, buf_end, module, error_buf,
                 if (!load_text_section(buf, buf_end, module, error_buf,
                                        error_buf_size))
                                        error_buf_size))
                     return false;
                     return false;
@@ -4065,37 +4172,16 @@ create_sections(AOTModule *module, const uint8 *buf, uint32 size,
 
 
             if (section_type == AOT_SECTION_TYPE_TEXT) {
             if (section_type == AOT_SECTION_TYPE_TEXT) {
                 if ((section_size > 0) && !module->is_indirect_mode) {
                 if ((section_size > 0) && !module->is_indirect_mode) {
-                    int map_prot =
-                        MMAP_PROT_READ | MMAP_PROT_WRITE | MMAP_PROT_EXEC;
-#if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64) \
-    || defined(BUILD_TARGET_RISCV64_LP64D)                       \
-    || defined(BUILD_TARGET_RISCV64_LP64)
-                    /* aot code and data in x86_64 must be in range 0 to 2G due
-                       to relocation for R_X86_64_32/32S/PC32 */
-                    int map_flags = MMAP_MAP_32BIT;
-#else
-                    int map_flags = MMAP_MAP_NONE;
-#endif
                     total_size =
                     total_size =
                         (uint64)section_size + aot_get_plt_table_size();
                         (uint64)section_size + aot_get_plt_table_size();
                     total_size = (total_size + 3) & ~((uint64)3);
                     total_size = (total_size + 3) & ~((uint64)3);
                     if (total_size >= UINT32_MAX
                     if (total_size >= UINT32_MAX
                         || !(aot_text =
                         || !(aot_text =
-                                 os_mmap(NULL, (uint32)total_size, map_prot,
-                                         map_flags, os_get_invalid_handle()))) {
+                                 loader_mmap((uint32)total_size, true,
+                                             error_buf, error_buf_size))) {
                         wasm_runtime_free(section);
                         wasm_runtime_free(section);
-                        set_error_buf(error_buf, error_buf_size,
-                                      "mmap memory failed");
                         goto fail;
                         goto fail;
                     }
                     }
-#if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64)
-#if !defined(BH_PLATFORM_LINUX_SGX) && !defined(BH_PLATFORM_WINDOWS) \
-    && !defined(BH_PLATFORM_DARWIN)
-                    /* address must be in the first 2 Gigabytes of
-                       the process address space */
-                    bh_assert((uintptr_t)aot_text < INT32_MAX);
-#endif
-#endif
 
 
 #if (WASM_MEM_DUAL_BUS_MIRROR != 0)
 #if (WASM_MEM_DUAL_BUS_MIRROR != 0)
                     mirrored_text = os_get_dbus_mirror(aot_text);
                     mirrored_text = os_get_dbus_mirror(aot_text);
@@ -4179,7 +4265,11 @@ load(const uint8 *buf, uint32 size, AOTModule *module,
     if (!ret) {
     if (!ret) {
         /* If load_from_sections() fails, then aot text is destroyed
         /* If load_from_sections() fails, then aot text is destroyed
            in destroy_sections() */
            in destroy_sections() */
-        destroy_sections(section_list, module->is_indirect_mode ? false : true);
+        destroy_sections(section_list,
+                         module->is_indirect_mode
+                                 || module->merged_data_text_sections
+                             ? false
+                             : true);
         /* aot_unload() won't destroy aot text again */
         /* aot_unload() won't destroy aot text again */
         module->code = NULL;
         module->code = NULL;
     }
     }
@@ -4329,7 +4419,8 @@ aot_unload(AOTModule *module)
     }
     }
 #endif
 #endif
 
 
-    if (module->code && !module->is_indirect_mode) {
+    if (module->code && !module->is_indirect_mode
+        && !module->merged_data_text_sections) {
         /* The layout is: literal size + literal + code (with plt table) */
         /* The layout is: literal size + literal + code (with plt table) */
         uint8 *mmap_addr = module->literal - sizeof(uint32);
         uint8 *mmap_addr = module->literal - sizeof(uint32);
         uint32 total_size =
         uint32 total_size =
@@ -4364,6 +4455,14 @@ aot_unload(AOTModule *module)
         destroy_object_data_sections(module->data_sections,
         destroy_object_data_sections(module->data_sections,
                                      module->data_section_count);
                                      module->data_section_count);
 
 
+    if (module->merged_data_sections)
+        os_munmap(module->merged_data_sections,
+                  module->merged_data_sections_size);
+
+    if (module->merged_data_text_sections)
+        os_munmap(module->merged_data_text_sections,
+                  module->merged_data_text_sections_size);
+
 #if WASM_ENABLE_DEBUG_AOT != 0
 #if WASM_ENABLE_DEBUG_AOT != 0
     jit_code_entry_destroy(module->elf_hdr);
     jit_code_entry_destroy(module->elf_hdr);
 #endif
 #endif

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

@@ -2817,6 +2817,13 @@ aot_enlarge_memory(AOTModuleInstance *module_inst, uint32 inc_page_count)
     return wasm_enlarge_memory(module_inst, inc_page_count);
     return wasm_enlarge_memory(module_inst, inc_page_count);
 }
 }
 
 
+bool
+aot_enlarge_memory_with_idx(AOTModuleInstance *module_inst,
+                            uint32 inc_page_count, uint32 memidx)
+{
+    return wasm_enlarge_memory_with_idx(module_inst, inc_page_count, memidx);
+}
+
 bool
 bool
 aot_invoke_native(WASMExecEnv *exec_env, uint32 func_idx, uint32 argc,
 aot_invoke_native(WASMExecEnv *exec_env, uint32 func_idx, uint32 argc,
                   uint32 *argv)
                   uint32 *argv)

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

@@ -315,6 +315,13 @@ typedef struct AOTModule {
 
 
     /* Whether the underlying wasm binary buffer can be freed */
     /* Whether the underlying wasm binary buffer can be freed */
     bool is_binary_freeable;
     bool is_binary_freeable;
+
+    /* `.data` sections merged into one mmaped to reduce the tlb cache miss */
+    uint8 *merged_data_sections;
+    uint32 merged_data_sections_size;
+    /* `.data` and `.text` sections merged into one large mmaped section */
+    uint8 *merged_data_text_sections;
+    uint32 merged_data_text_sections_size;
 } AOTModule;
 } AOTModule;
 
 
 #define AOTMemoryInstance WASMMemoryInstance
 #define AOTMemoryInstance WASMMemoryInstance
@@ -605,6 +612,10 @@ aot_module_dup_data(AOTModuleInstance *module_inst, const char *src,
 bool
 bool
 aot_enlarge_memory(AOTModuleInstance *module_inst, uint32 inc_page_count);
 aot_enlarge_memory(AOTModuleInstance *module_inst, uint32 inc_page_count);
 
 
+bool
+aot_enlarge_memory_with_idx(AOTModuleInstance *module_inst,
+                            uint32 inc_page_count, uint32 memidx);
+
 /**
 /**
  * Invoke native function from aot code
  * Invoke native function from aot code
  */
  */

+ 2 - 0
core/iwasm/aot/arch/aot_reloc_riscv.c

@@ -134,6 +134,7 @@ static SymbolMap target_sym_map[] = {
     REG_SYM(__eqdf2),
     REG_SYM(__eqdf2),
     REG_SYM(__extendsfdf2),
     REG_SYM(__extendsfdf2),
     REG_SYM(__fixdfdi),
     REG_SYM(__fixdfdi),
+    REG_SYM(__fixdfsi),
     REG_SYM(__fixunsdfdi),
     REG_SYM(__fixunsdfdi),
     REG_SYM(__fixunsdfsi),
     REG_SYM(__fixunsdfsi),
     REG_SYM(__floatdidf),
     REG_SYM(__floatdidf),
@@ -143,6 +144,7 @@ static SymbolMap target_sym_map[] = {
     REG_SYM(__gedf2),
     REG_SYM(__gedf2),
     REG_SYM(__gtdf2),
     REG_SYM(__gtdf2),
     REG_SYM(__ledf2),
     REG_SYM(__ledf2),
+    REG_SYM(__ltdf2),
     REG_SYM(__muldf3),
     REG_SYM(__muldf3),
     REG_SYM(__nedf2),
     REG_SYM(__nedf2),
     REG_SYM(__negdf2),
     REG_SYM(__negdf2),

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

@@ -670,6 +670,16 @@ wasm_get_default_memory(WASMModuleInstance *module_inst)
         return NULL;
         return NULL;
 }
 }
 
 
+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
+        return NULL;
+}
+
 void
 void
 wasm_runtime_set_mem_bound_check_bytes(WASMMemoryInstance *memory,
 wasm_runtime_set_mem_bound_check_bytes(WASMMemoryInstance *memory,
                                        uint64 memory_data_size)
                                        uint64 memory_data_size)
@@ -747,9 +757,14 @@ wasm_mmap_linear_memory(uint64_t map_size, uint64 commit_size)
 }
 }
 
 
 bool
 bool
-wasm_enlarge_memory_internal(WASMModuleInstance *module, uint32 inc_page_count)
+wasm_enlarge_memory_internal(WASMModuleInstance *module, uint32 inc_page_count,
+                             uint32 memidx)
 {
 {
+#if WASM_ENABLE_MULTI_MEMORY != 0
+    WASMMemoryInstance *memory = wasm_get_memory_with_idx(module, memidx);
+#else
     WASMMemoryInstance *memory = wasm_get_default_memory(module);
     WASMMemoryInstance *memory = wasm_get_default_memory(module);
+#endif
     uint8 *memory_data_old, *memory_data_new, *heap_data_old;
     uint8 *memory_data_old, *memory_data_new, *heap_data_old;
     uint32 num_bytes_per_page, heap_size;
     uint32 num_bytes_per_page, heap_size;
     uint32 cur_page_count, max_page_count, total_page_count;
     uint32 cur_page_count, max_page_count, total_page_count;
@@ -960,7 +975,7 @@ wasm_enlarge_memory(WASMModuleInstance *module, uint32 inc_page_count)
     if (module->memory_count > 0)
     if (module->memory_count > 0)
         shared_memory_lock(module->memories[0]);
         shared_memory_lock(module->memories[0]);
 #endif
 #endif
-    ret = wasm_enlarge_memory_internal(module, inc_page_count);
+    ret = wasm_enlarge_memory_internal(module, inc_page_count, 0);
 #if WASM_ENABLE_SHARED_MEMORY != 0
 #if WASM_ENABLE_SHARED_MEMORY != 0
     if (module->memory_count > 0)
     if (module->memory_count > 0)
         shared_memory_unlock(module->memories[0]);
         shared_memory_unlock(module->memories[0]);
@@ -969,6 +984,25 @@ wasm_enlarge_memory(WASMModuleInstance *module, uint32 inc_page_count)
     return ret;
     return ret;
 }
 }
 
 
+bool
+wasm_enlarge_memory_with_idx(WASMModuleInstance *module, uint32 inc_page_count,
+                             uint32 memidx)
+{
+    bool ret = false;
+
+#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);
+#if WASM_ENABLE_SHARED_MEMORY != 0
+    if (memidx < module->memory_count)
+        shared_memory_unlock(module->memories[memidx]);
+#endif
+
+    return ret;
+}
+
 void
 void
 wasm_deallocate_linear_memory(WASMMemoryInstance *memory_inst)
 wasm_deallocate_linear_memory(WASMMemoryInstance *memory_inst)
 {
 {

+ 56 - 35
core/iwasm/common/wasm_runtime_common.c

@@ -181,15 +181,36 @@ static RunningMode runtime_running_mode = Mode_Default;
    of signal handler */
    of signal handler */
 static os_thread_local_attribute WASMExecEnv *exec_env_tls = NULL;
 static os_thread_local_attribute WASMExecEnv *exec_env_tls = NULL;
 
 
+static bool
+is_sig_addr_in_guard_pages(void *sig_addr, WASMModuleInstance *module_inst)
+{
+    WASMMemoryInstance *memory_inst;
+    uint8 *mapped_mem_start_addr = NULL;
+    uint8 *mapped_mem_end_addr = NULL;
+    uint32 i;
+
+    for (i = 0; i < module_inst->memory_count; ++i) {
+        /* To be compatible with multi memory, get the ith memory instance */
+        memory_inst = wasm_get_memory_with_idx(module_inst, i);
+        mapped_mem_start_addr = memory_inst->memory_data;
+        mapped_mem_end_addr = memory_inst->memory_data + 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 memory instance's guard regions */
+            return true;
+        }
+    }
+
+    return false;
+}
+
 #ifndef BH_PLATFORM_WINDOWS
 #ifndef BH_PLATFORM_WINDOWS
 static void
 static void
 runtime_signal_handler(void *sig_addr)
 runtime_signal_handler(void *sig_addr)
 {
 {
     WASMModuleInstance *module_inst;
     WASMModuleInstance *module_inst;
-    WASMMemoryInstance *memory_inst;
     WASMJmpBuf *jmpbuf_node;
     WASMJmpBuf *jmpbuf_node;
-    uint8 *mapped_mem_start_addr = NULL;
-    uint8 *mapped_mem_end_addr = NULL;
     uint32 page_size = os_getpagesize();
     uint32 page_size = os_getpagesize();
 #if WASM_DISABLE_STACK_HW_BOUND_CHECK == 0
 #if WASM_DISABLE_STACK_HW_BOUND_CHECK == 0
     uint8 *stack_min_addr;
     uint8 *stack_min_addr;
@@ -201,23 +222,13 @@ runtime_signal_handler(void *sig_addr)
         && (jmpbuf_node = exec_env_tls->jmpbuf_stack_top)) {
         && (jmpbuf_node = exec_env_tls->jmpbuf_stack_top)) {
         /* Get mapped mem info of current instance */
         /* Get mapped mem info of current instance */
         module_inst = (WASMModuleInstance *)exec_env_tls->module_inst;
         module_inst = (WASMModuleInstance *)exec_env_tls->module_inst;
-        /* Get the default memory instance */
-        memory_inst = wasm_get_default_memory(module_inst);
-        if (memory_inst) {
-            mapped_mem_start_addr = memory_inst->memory_data;
-            mapped_mem_end_addr = memory_inst->memory_data + 8 * (uint64)BH_GB;
-        }
 
 
 #if WASM_DISABLE_STACK_HW_BOUND_CHECK == 0
 #if WASM_DISABLE_STACK_HW_BOUND_CHECK == 0
         /* Get stack info of current thread */
         /* Get stack info of current thread */
         stack_min_addr = os_thread_get_stack_boundary();
         stack_min_addr = os_thread_get_stack_boundary();
 #endif
 #endif
 
 
-        if (memory_inst
-            && (mapped_mem_start_addr <= (uint8 *)sig_addr
-                && (uint8 *)sig_addr < mapped_mem_end_addr)) {
-            /* The address which causes segmentation fault is inside
-               the memory instance's guard regions */
+        if (is_sig_addr_in_guard_pages(sig_addr, module_inst)) {
             wasm_set_exception(module_inst, "out of bounds memory access");
             wasm_set_exception(module_inst, "out of bounds memory access");
             os_longjmp(jmpbuf_node->jmpbuf, 1);
             os_longjmp(jmpbuf_node->jmpbuf, 1);
         }
         }
@@ -340,16 +351,7 @@ runtime_exception_handler(EXCEPTION_POINTERS *exce_info)
         && (jmpbuf_node = exec_env_tls->jmpbuf_stack_top)) {
         && (jmpbuf_node = exec_env_tls->jmpbuf_stack_top)) {
         module_inst = (WASMModuleInstance *)exec_env_tls->module_inst;
         module_inst = (WASMModuleInstance *)exec_env_tls->module_inst;
         if (ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) {
         if (ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) {
-            /* Get the default memory instance */
-            memory_inst = wasm_get_default_memory(module_inst);
-            if (memory_inst) {
-                mapped_mem_start_addr = memory_inst->memory_data;
-                mapped_mem_end_addr =
-                    memory_inst->memory_data + 8 * (uint64)BH_GB;
-            }
-
-            if (memory_inst && mapped_mem_start_addr <= (uint8 *)sig_addr
-                && (uint8 *)sig_addr < mapped_mem_end_addr) {
+            if (is_sig_addr_in_guard_pages(sig_addr, module_inst)) {
                 /* The address which causes segmentation fault is inside
                 /* The address which causes segmentation fault is inside
                    the memory instance's guard regions.
                    the memory instance's guard regions.
                    Set exception and let the wasm func continue to run, when
                    Set exception and let the wasm func continue to run, when
@@ -1417,12 +1419,39 @@ wasm_runtime_load_ex(uint8 *buf, uint32 size, const LoadArgs *args,
                      char *error_buf, uint32 error_buf_size)
                      char *error_buf, uint32 error_buf_size)
 {
 {
     WASMModuleCommon *module_common = NULL;
     WASMModuleCommon *module_common = NULL;
+    uint32 package_type;
+    bool magic_header_detected = false;
 
 
     if (!args) {
     if (!args) {
+        set_error_buf(error_buf, error_buf_size,
+                      "WASM module load failed: null load arguments");
+        return NULL;
+    }
+
+    if (size < 4) {
+        set_error_buf(error_buf, error_buf_size,
+                      "WASM module load failed: unexpected end");
         return NULL;
         return NULL;
     }
     }
 
 
-    if (get_package_type(buf, size) == Wasm_Module_Bytecode) {
+    package_type = get_package_type(buf, size);
+    if (package_type == Wasm_Module_Bytecode) {
+#if WASM_ENABLE_INTERP != 0
+        magic_header_detected = true;
+#endif
+    }
+    else if (package_type == Wasm_Module_AoT) {
+#if WASM_ENABLE_AOT != 0
+        magic_header_detected = true;
+#endif
+    }
+    if (!magic_header_detected) {
+        set_error_buf(error_buf, error_buf_size,
+                      "WASM module load failed: magic header not detected");
+        return NULL;
+    }
+
+    if (package_type == Wasm_Module_Bytecode) {
 #if WASM_ENABLE_INTERP != 0
 #if WASM_ENABLE_INTERP != 0
         module_common =
         module_common =
             (WASMModuleCommon *)wasm_load(buf, size,
             (WASMModuleCommon *)wasm_load(buf, size,
@@ -1435,7 +1464,7 @@ wasm_runtime_load_ex(uint8 *buf, uint32 size, const LoadArgs *args,
                 args->wasm_binary_freeable;
                 args->wasm_binary_freeable;
 #endif
 #endif
     }
     }
-    else if (get_package_type(buf, size) == Wasm_Module_AoT) {
+    else if (package_type == Wasm_Module_AoT) {
 #if WASM_ENABLE_AOT != 0
 #if WASM_ENABLE_AOT != 0
         module_common = (WASMModuleCommon *)aot_load_from_aot_file(
         module_common = (WASMModuleCommon *)aot_load_from_aot_file(
             buf, size, args, error_buf, error_buf_size);
             buf, size, args, error_buf, error_buf_size);
@@ -1444,15 +1473,7 @@ wasm_runtime_load_ex(uint8 *buf, uint32 size, const LoadArgs *args,
                 args->wasm_binary_freeable;
                 args->wasm_binary_freeable;
 #endif
 #endif
     }
     }
-    else {
-        if (size < 4)
-            set_error_buf(error_buf, error_buf_size,
-                          "WASM module load failed: unexpected end");
-        else
-            set_error_buf(error_buf, error_buf_size,
-                          "WASM module load failed: magic header not detected");
-        return NULL;
-    }
+
     if (!module_common) {
     if (!module_common) {
         LOG_DEBUG("WASM module load failed");
         LOG_DEBUG("WASM module load failed");
         return NULL;
         return NULL;

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

@@ -540,6 +540,7 @@ aot_create_comp_data(WASMModule *module, const char *target_arch,
     /* TODO: create import memories */
     /* TODO: create import memories */
 
 
     /* Allocate memory for memory array, reserve one AOTMemory space at least */
     /* Allocate memory for memory array, reserve one AOTMemory space at least */
+    /* TODO: multi-memory */
     if (!comp_data->memory_count)
     if (!comp_data->memory_count)
         comp_data->memory_count = 1;
         comp_data->memory_count = 1;
 
 

+ 28 - 32
core/iwasm/compilation/aot_emit_const.c

@@ -68,23 +68,21 @@ aot_compile_op_f32_const(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
 {
 {
     LLVMValueRef alloca, value;
     LLVMValueRef alloca, value;
 
 
-    if (!isnan(f32_const)) {
-        if (comp_ctx->is_indirect_mode
-            && aot_intrinsic_check_capability(comp_ctx, "f32.const")) {
-            WASMValue wasm_value;
-            memcpy(&wasm_value.f32, &f32_const, sizeof(float32));
-            value = aot_load_const_from_table(comp_ctx, func_ctx->native_symbol,
-                                              &wasm_value, VALUE_TYPE_F32);
-            if (!value) {
-                return false;
-            }
-            PUSH_F32(value);
-        }
-        else {
-            value = F32_CONST(f32_const);
-            CHECK_LLVM_CONST(value);
-            PUSH_F32(value);
+    if (comp_ctx->is_indirect_mode
+        && aot_intrinsic_check_capability(comp_ctx, "f32.const")) {
+        WASMValue wasm_value;
+        memcpy(&wasm_value.f32, &f32_const, sizeof(float32));
+        value = aot_load_const_from_table(comp_ctx, func_ctx->native_symbol,
+                                          &wasm_value, VALUE_TYPE_F32);
+        if (!value) {
+            return false;
         }
         }
+        PUSH_F32(value);
+    }
+    else if (!isnan(f32_const)) {
+        value = F32_CONST(f32_const);
+        CHECK_LLVM_CONST(value);
+        PUSH_F32(value);
     }
     }
     else {
     else {
         int32 i32_const;
         int32 i32_const;
@@ -123,23 +121,21 @@ aot_compile_op_f64_const(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
 {
 {
     LLVMValueRef alloca, value;
     LLVMValueRef alloca, value;
 
 
-    if (!isnan(f64_const)) {
-        if (comp_ctx->is_indirect_mode
-            && aot_intrinsic_check_capability(comp_ctx, "f64.const")) {
-            WASMValue wasm_value;
-            memcpy(&wasm_value.f64, &f64_const, sizeof(float64));
-            value = aot_load_const_from_table(comp_ctx, func_ctx->native_symbol,
-                                              &wasm_value, VALUE_TYPE_F64);
-            if (!value) {
-                return false;
-            }
-            PUSH_F64(value);
-        }
-        else {
-            value = F64_CONST(f64_const);
-            CHECK_LLVM_CONST(value);
-            PUSH_F64(value);
+    if (comp_ctx->is_indirect_mode
+        && aot_intrinsic_check_capability(comp_ctx, "f64.const")) {
+        WASMValue wasm_value;
+        memcpy(&wasm_value.f64, &f64_const, sizeof(float64));
+        value = aot_load_const_from_table(comp_ctx, func_ctx->native_symbol,
+                                          &wasm_value, VALUE_TYPE_F64);
+        if (!value) {
+            return false;
         }
         }
+        PUSH_F64(value);
+    }
+    else if (!isnan(f64_const)) {
+        value = F64_CONST(f64_const);
+        CHECK_LLVM_CONST(value);
+        PUSH_F64(value);
     }
     }
     else {
     else {
         int64 i64_const;
         int64 i64_const;

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

@@ -895,6 +895,7 @@ aot_compile_op_memory_grow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
 
 
     POP_PAGE_COUNT(delta);
     POP_PAGE_COUNT(delta);
 
 
+    /* TODO: multi-memory aot_enlarge_memory_with_idx() */
     /* Function type of aot_enlarge_memory() */
     /* Function type of aot_enlarge_memory() */
     param_types[0] = INT8_PTR_TYPE;
     param_types[0] = INT8_PTR_TYPE;
     param_types[1] = I32_TYPE;
     param_types[1] = I32_TYPE;

+ 21 - 2
core/iwasm/compilation/aot_llvm.c

@@ -1690,7 +1690,15 @@ aot_create_stack_sizes(const AOTCompData *comp_data, AOTCompContext *comp_ctx)
      * avoid creating extra relocations in the precheck functions.
      * avoid creating extra relocations in the precheck functions.
      */
      */
     LLVMSetLinkage(stack_sizes, LLVMInternalLinkage);
     LLVMSetLinkage(stack_sizes, LLVMInternalLinkage);
-    LLVMSetSection(stack_sizes, aot_stack_sizes_section_name);
+    /*
+     * for AOT, place it into a dedicated section for the convenience
+     * of the AOT file generation and symbol resolutions.
+     *
+     * for JIT, it doesn't matter.
+     */
+    if (!comp_ctx->is_jit_mode) {
+        LLVMSetSection(stack_sizes, aot_stack_sizes_section_name);
+    }
     comp_ctx->stack_sizes_type = stack_sizes_type;
     comp_ctx->stack_sizes_type = stack_sizes_type;
     comp_ctx->stack_sizes = stack_sizes;
     comp_ctx->stack_sizes = stack_sizes;
     return true;
     return true;
@@ -3108,6 +3116,16 @@ aot_create_comp_context(const AOTCompData *comp_data, aot_comp_option_t option)
         goto fail;
         goto fail;
     }
     }
 
 
+    /* Return error if ref-types and GC are disabled by command line but
+       ref-types instructions are used */
+    if (!option->enable_ref_types && !option->enable_gc
+        && wasm_module->is_ref_types_used) {
+        aot_set_last_error("ref-types instruction was found, "
+                           "try removing --disable-ref-types option "
+                           "or adding --enable-gc option.");
+        goto fail;
+    }
+
     /* Disable features when they are not actually used */
     /* Disable features when they are not actually used */
     if (!wasm_module->is_simd_used) {
     if (!wasm_module->is_simd_used) {
         option->enable_simd = comp_ctx->enable_simd = false;
         option->enable_simd = comp_ctx->enable_simd = false;
@@ -3121,7 +3139,8 @@ aot_create_comp_context(const AOTCompData *comp_data, aot_comp_option_t option)
 #endif
 #endif
 
 
     if (option->enable_simd && strcmp(comp_ctx->target_arch, "x86_64") != 0
     if (option->enable_simd && strcmp(comp_ctx->target_arch, "x86_64") != 0
-        && strncmp(comp_ctx->target_arch, "aarch64", 7) != 0) {
+        && strncmp(comp_ctx->target_arch, "aarch64", 7) != 0
+        && strcmp(comp_ctx->target_arch, "arc") != 0) {
         /* Disable simd if it isn't supported by target arch */
         /* Disable simd if it isn't supported by target arch */
         option->enable_simd = false;
         option->enable_simd = false;
     }
     }

+ 6 - 0
core/iwasm/compilation/aot_llvm_extra.cpp

@@ -41,6 +41,9 @@
 #include <llvm/Target/CodeGenCWrappers.h>
 #include <llvm/Target/CodeGenCWrappers.h>
 #include <llvm/Target/TargetMachine.h>
 #include <llvm/Target/TargetMachine.h>
 #include <llvm/Target/TargetOptions.h>
 #include <llvm/Target/TargetOptions.h>
+#if LLVM_VERSION_MAJOR >= 17
+#include <llvm/TargetParser/Triple.h>
+#endif
 #include <llvm/Transforms/Utils/LowerMemIntrinsics.h>
 #include <llvm/Transforms/Utils/LowerMemIntrinsics.h>
 #include <llvm/Transforms/Vectorize/LoopVectorize.h>
 #include <llvm/Transforms/Vectorize/LoopVectorize.h>
 #include <llvm/Transforms/Vectorize/LoadStoreVectorizer.h>
 #include <llvm/Transforms/Vectorize/LoadStoreVectorizer.h>
@@ -173,6 +176,9 @@ aot_check_simd_compatibility(const char *arch_c_str, const char *cpu_c_str)
     else if (targetArch == llvm::Triple::aarch64) {
     else if (targetArch == llvm::Triple::aarch64) {
         return subTargetInfo->checkFeatures("+neon");
         return subTargetInfo->checkFeatures("+neon");
     }
     }
+    else if (targetArch == llvm::Triple::arc) {
+        return true;
+    }
     else {
     else {
         return false;
         return false;
     }
     }

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

@@ -602,6 +602,7 @@ jit_compile_op_memory_grow(JitCompContext *cc, uint32 mem_idx)
     args[0] = get_module_inst_reg(cc->jit_frame);
     args[0] = get_module_inst_reg(cc->jit_frame);
     args[1] = inc_page_count;
     args[1] = inc_page_count;
 
 
+    /* TODO: multi-memory wasm_enlarge_memory_with_idx() */
     if (!jit_emit_callnative(cc, wasm_enlarge_memory, grow_res, args, 2)) {
     if (!jit_emit_callnative(cc, wasm_enlarge_memory, grow_res, args, 2)) {
         goto fail;
         goto fail;
     }
     }

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

@@ -94,6 +94,14 @@ extern "C" {
 #define SHARED_MEMORY_FLAG 0x02
 #define SHARED_MEMORY_FLAG 0x02
 #define MEMORY64_FLAG 0x04
 #define MEMORY64_FLAG 0x04
 
 
+/**
+ * In the multi-memory proposal, the memarg in loads and stores are
+ * reinterpreted as a bitfield, bit 6 serves as a flag indicating the presence
+ * of the optional memory index, if it is set, then an i32 memory index follows
+ * after the alignment bitfield
+ */
+#define OPT_MEMIDX_FLAG 0x40
+
 #define DEFAULT_NUM_BYTES_PER_PAGE 65536
 #define DEFAULT_NUM_BYTES_PER_PAGE 65536
 #define DEFAULT_MAX_PAGES 65536
 #define DEFAULT_MAX_PAGES 65536
 #define DEFAULT_MEM64_MAX_PAGES UINT32_MAX
 #define DEFAULT_MEM64_MAX_PAGES UINT32_MAX

+ 112 - 51
core/iwasm/interpreter/wasm_interp_classic.c

@@ -697,6 +697,44 @@ wasm_interp_get_frame_ref(WASMInterpFrame *frame)
 #define read_leb_mem_offset(p, p_end, res) read_leb_uint32(p, p_end, res)
 #define read_leb_mem_offset(p, p_end, res) read_leb_uint32(p, p_end, res)
 #endif
 #endif
 
 
+#if WASM_ENABLE_MULTI_MEMORY != 0
+/* If the current memidx differs than the last cached one,
+ * update memory related information */
+#define read_leb_memidx(p, p_end, res)                        \
+    do {                                                      \
+        read_leb_uint32(p, p_end, res);                       \
+        if (res != memidx_cached) {                           \
+            memory = wasm_get_memory_with_idx(module, res);   \
+            linear_mem_size = GET_LINEAR_MEMORY_SIZE(memory); \
+            memidx_cached = res;                              \
+        }                                                     \
+    } while (0)
+/* First read the alignment, then if it has flag indicating following memidx,
+ * read and update memory related information, if it differs than the
+ * last(cached) one. If it doesn't have flag reset the
+ * memory instance to the default memories[0] */
+#define read_leb_memarg(p, p_end, res)                         \
+    do {                                                       \
+        read_leb_uint32(p, p_end, res);                        \
+        if (!(res & OPT_MEMIDX_FLAG))                          \
+            memidx = 0;                                        \
+        else                                                   \
+            read_leb_uint32(p, p_end, memidx);                 \
+        if (memidx != memidx_cached) {                         \
+            memory = wasm_get_memory_with_idx(module, memidx); \
+            linear_mem_size = GET_LINEAR_MEMORY_SIZE(memory);  \
+            memidx_cached = memidx;                            \
+        }                                                      \
+    } while (0)
+#else
+#define read_leb_memarg(p, p_end, res)  \
+    do {                                \
+        read_leb_uint32(p, p_end, res); \
+        (void)res;                      \
+    } while (0)
+#define read_leb_memidx(p, p_end, res) read_leb_memarg(p, p_end, res)
+#endif
+
 #if WASM_ENABLE_LABELS_AS_VALUES == 0
 #if WASM_ENABLE_LABELS_AS_VALUES == 0
 #define RECOVER_FRAME_IP_END() frame_ip_end = wasm_get_func_code_end(cur_func)
 #define RECOVER_FRAME_IP_END() frame_ip_end = wasm_get_func_code_end(cur_func)
 #else
 #else
@@ -1567,6 +1605,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
     if (memory)
     if (memory)
         is_memory64 = memory->is_memory64;
         is_memory64 = memory->is_memory64;
 #endif
 #endif
+#if WASM_ENABLE_MULTI_MEMORY != 0
+    uint32 memidx = 0;
+    uint32 memidx_cached = (uint32)-1;
+#endif
 
 
 #if WASM_ENABLE_DEBUG_INTERP != 0
 #if WASM_ENABLE_DEBUG_INTERP != 0
     uint8 *frame_ip_orig = NULL;
     uint8 *frame_ip_orig = NULL;
@@ -2281,8 +2323,15 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                 bh_assert(tidx < module->module->type_count);
                 bh_assert(tidx < module->module->type_count);
                 cur_type = wasm_types[tidx];
                 cur_type = wasm_types[tidx];
 
 
+                /* clang-format off */
+#if WASM_ENABLE_REF_TYPES != 0 || WASM_ENABLE_GC != 0
                 read_leb_uint32(frame_ip, frame_ip_end, tbl_idx);
                 read_leb_uint32(frame_ip, frame_ip_end, tbl_idx);
+#else
+                frame_ip++;
+                tbl_idx = 0;
+#endif
                 bh_assert(tbl_idx < module->table_count);
                 bh_assert(tbl_idx < module->table_count);
+                /* clang-format on */
 
 
                 tbl_inst = wasm_get_table_inst(module, tbl_idx);
                 tbl_inst = wasm_get_table_inst(module, tbl_idx);
 
 
@@ -4285,13 +4334,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                 uint32 flags;
                 uint32 flags;
                 mem_offset_t offset, addr;
                 mem_offset_t offset, addr;
 
 
-                read_leb_uint32(frame_ip, frame_ip_end, flags);
+                read_leb_memarg(frame_ip, frame_ip_end, flags);
                 read_leb_mem_offset(frame_ip, frame_ip_end, offset);
                 read_leb_mem_offset(frame_ip, frame_ip_end, offset);
                 addr = POP_MEM_OFFSET();
                 addr = POP_MEM_OFFSET();
                 CHECK_MEMORY_OVERFLOW(4);
                 CHECK_MEMORY_OVERFLOW(4);
                 PUSH_I32(LOAD_I32(maddr));
                 PUSH_I32(LOAD_I32(maddr));
                 CHECK_READ_WATCHPOINT(addr, offset);
                 CHECK_READ_WATCHPOINT(addr, offset);
-                (void)flags;
                 HANDLE_OP_END();
                 HANDLE_OP_END();
             }
             }
 
 
@@ -4301,13 +4349,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                 uint32 flags;
                 uint32 flags;
                 mem_offset_t offset, addr;
                 mem_offset_t offset, addr;
 
 
-                read_leb_uint32(frame_ip, frame_ip_end, flags);
+                read_leb_memarg(frame_ip, frame_ip_end, flags);
                 read_leb_mem_offset(frame_ip, frame_ip_end, offset);
                 read_leb_mem_offset(frame_ip, frame_ip_end, offset);
                 addr = POP_MEM_OFFSET();
                 addr = POP_MEM_OFFSET();
                 CHECK_MEMORY_OVERFLOW(8);
                 CHECK_MEMORY_OVERFLOW(8);
                 PUSH_I64(LOAD_I64(maddr));
                 PUSH_I64(LOAD_I64(maddr));
                 CHECK_READ_WATCHPOINT(addr, offset);
                 CHECK_READ_WATCHPOINT(addr, offset);
-                (void)flags;
                 HANDLE_OP_END();
                 HANDLE_OP_END();
             }
             }
 
 
@@ -4316,13 +4363,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                 uint32 flags;
                 uint32 flags;
                 mem_offset_t offset, addr;
                 mem_offset_t offset, addr;
 
 
-                read_leb_uint32(frame_ip, frame_ip_end, flags);
+                read_leb_memarg(frame_ip, frame_ip_end, flags);
                 read_leb_mem_offset(frame_ip, frame_ip_end, offset);
                 read_leb_mem_offset(frame_ip, frame_ip_end, offset);
                 addr = POP_MEM_OFFSET();
                 addr = POP_MEM_OFFSET();
                 CHECK_MEMORY_OVERFLOW(1);
                 CHECK_MEMORY_OVERFLOW(1);
                 PUSH_I32(sign_ext_8_32(*(int8 *)maddr));
                 PUSH_I32(sign_ext_8_32(*(int8 *)maddr));
                 CHECK_READ_WATCHPOINT(addr, offset);
                 CHECK_READ_WATCHPOINT(addr, offset);
-                (void)flags;
                 HANDLE_OP_END();
                 HANDLE_OP_END();
             }
             }
 
 
@@ -4331,13 +4377,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                 uint32 flags;
                 uint32 flags;
                 mem_offset_t offset, addr;
                 mem_offset_t offset, addr;
 
 
-                read_leb_uint32(frame_ip, frame_ip_end, flags);
+                read_leb_memarg(frame_ip, frame_ip_end, flags);
                 read_leb_mem_offset(frame_ip, frame_ip_end, offset);
                 read_leb_mem_offset(frame_ip, frame_ip_end, offset);
                 addr = POP_MEM_OFFSET();
                 addr = POP_MEM_OFFSET();
                 CHECK_MEMORY_OVERFLOW(1);
                 CHECK_MEMORY_OVERFLOW(1);
                 PUSH_I32((uint32)(*(uint8 *)maddr));
                 PUSH_I32((uint32)(*(uint8 *)maddr));
                 CHECK_READ_WATCHPOINT(addr, offset);
                 CHECK_READ_WATCHPOINT(addr, offset);
-                (void)flags;
                 HANDLE_OP_END();
                 HANDLE_OP_END();
             }
             }
 
 
@@ -4346,13 +4391,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                 uint32 flags;
                 uint32 flags;
                 mem_offset_t offset, addr;
                 mem_offset_t offset, addr;
 
 
-                read_leb_uint32(frame_ip, frame_ip_end, flags);
+                read_leb_memarg(frame_ip, frame_ip_end, flags);
                 read_leb_mem_offset(frame_ip, frame_ip_end, offset);
                 read_leb_mem_offset(frame_ip, frame_ip_end, offset);
                 addr = POP_MEM_OFFSET();
                 addr = POP_MEM_OFFSET();
                 CHECK_MEMORY_OVERFLOW(2);
                 CHECK_MEMORY_OVERFLOW(2);
                 PUSH_I32(sign_ext_16_32(LOAD_I16(maddr)));
                 PUSH_I32(sign_ext_16_32(LOAD_I16(maddr)));
                 CHECK_READ_WATCHPOINT(addr, offset);
                 CHECK_READ_WATCHPOINT(addr, offset);
-                (void)flags;
                 HANDLE_OP_END();
                 HANDLE_OP_END();
             }
             }
 
 
@@ -4361,13 +4405,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                 uint32 flags;
                 uint32 flags;
                 mem_offset_t offset, addr;
                 mem_offset_t offset, addr;
 
 
-                read_leb_uint32(frame_ip, frame_ip_end, flags);
+                read_leb_memarg(frame_ip, frame_ip_end, flags);
                 read_leb_mem_offset(frame_ip, frame_ip_end, offset);
                 read_leb_mem_offset(frame_ip, frame_ip_end, offset);
                 addr = POP_MEM_OFFSET();
                 addr = POP_MEM_OFFSET();
                 CHECK_MEMORY_OVERFLOW(2);
                 CHECK_MEMORY_OVERFLOW(2);
                 PUSH_I32((uint32)(LOAD_U16(maddr)));
                 PUSH_I32((uint32)(LOAD_U16(maddr)));
                 CHECK_READ_WATCHPOINT(addr, offset);
                 CHECK_READ_WATCHPOINT(addr, offset);
-                (void)flags;
                 HANDLE_OP_END();
                 HANDLE_OP_END();
             }
             }
 
 
@@ -4376,13 +4419,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                 uint32 flags;
                 uint32 flags;
                 mem_offset_t offset, addr;
                 mem_offset_t offset, addr;
 
 
-                read_leb_uint32(frame_ip, frame_ip_end, flags);
+                read_leb_memarg(frame_ip, frame_ip_end, flags);
                 read_leb_mem_offset(frame_ip, frame_ip_end, offset);
                 read_leb_mem_offset(frame_ip, frame_ip_end, offset);
                 addr = POP_MEM_OFFSET();
                 addr = POP_MEM_OFFSET();
                 CHECK_MEMORY_OVERFLOW(1);
                 CHECK_MEMORY_OVERFLOW(1);
                 PUSH_I64(sign_ext_8_64(*(int8 *)maddr));
                 PUSH_I64(sign_ext_8_64(*(int8 *)maddr));
                 CHECK_READ_WATCHPOINT(addr, offset);
                 CHECK_READ_WATCHPOINT(addr, offset);
-                (void)flags;
                 HANDLE_OP_END();
                 HANDLE_OP_END();
             }
             }
 
 
@@ -4391,13 +4433,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                 uint32 flags;
                 uint32 flags;
                 mem_offset_t offset, addr;
                 mem_offset_t offset, addr;
 
 
-                read_leb_uint32(frame_ip, frame_ip_end, flags);
+                read_leb_memarg(frame_ip, frame_ip_end, flags);
                 read_leb_mem_offset(frame_ip, frame_ip_end, offset);
                 read_leb_mem_offset(frame_ip, frame_ip_end, offset);
                 addr = POP_MEM_OFFSET();
                 addr = POP_MEM_OFFSET();
                 CHECK_MEMORY_OVERFLOW(1);
                 CHECK_MEMORY_OVERFLOW(1);
                 PUSH_I64((uint64)(*(uint8 *)maddr));
                 PUSH_I64((uint64)(*(uint8 *)maddr));
                 CHECK_READ_WATCHPOINT(addr, offset);
                 CHECK_READ_WATCHPOINT(addr, offset);
-                (void)flags;
                 HANDLE_OP_END();
                 HANDLE_OP_END();
             }
             }
 
 
@@ -4406,13 +4447,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                 uint32 flags;
                 uint32 flags;
                 mem_offset_t offset, addr;
                 mem_offset_t offset, addr;
 
 
-                read_leb_uint32(frame_ip, frame_ip_end, flags);
+                read_leb_memarg(frame_ip, frame_ip_end, flags);
                 read_leb_mem_offset(frame_ip, frame_ip_end, offset);
                 read_leb_mem_offset(frame_ip, frame_ip_end, offset);
                 addr = POP_MEM_OFFSET();
                 addr = POP_MEM_OFFSET();
                 CHECK_MEMORY_OVERFLOW(2);
                 CHECK_MEMORY_OVERFLOW(2);
                 PUSH_I64(sign_ext_16_64(LOAD_I16(maddr)));
                 PUSH_I64(sign_ext_16_64(LOAD_I16(maddr)));
                 CHECK_READ_WATCHPOINT(addr, offset);
                 CHECK_READ_WATCHPOINT(addr, offset);
-                (void)flags;
                 HANDLE_OP_END();
                 HANDLE_OP_END();
             }
             }
 
 
@@ -4421,13 +4461,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                 uint32 flags;
                 uint32 flags;
                 mem_offset_t offset, addr;
                 mem_offset_t offset, addr;
 
 
-                read_leb_uint32(frame_ip, frame_ip_end, flags);
+                read_leb_memarg(frame_ip, frame_ip_end, flags);
                 read_leb_mem_offset(frame_ip, frame_ip_end, offset);
                 read_leb_mem_offset(frame_ip, frame_ip_end, offset);
                 addr = POP_MEM_OFFSET();
                 addr = POP_MEM_OFFSET();
                 CHECK_MEMORY_OVERFLOW(2);
                 CHECK_MEMORY_OVERFLOW(2);
                 PUSH_I64((uint64)(LOAD_U16(maddr)));
                 PUSH_I64((uint64)(LOAD_U16(maddr)));
                 CHECK_READ_WATCHPOINT(addr, offset);
                 CHECK_READ_WATCHPOINT(addr, offset);
-                (void)flags;
                 HANDLE_OP_END();
                 HANDLE_OP_END();
             }
             }
 
 
@@ -4436,14 +4475,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                 uint32 flags;
                 uint32 flags;
                 mem_offset_t offset, addr;
                 mem_offset_t offset, addr;
 
 
-                opcode = *(frame_ip - 1);
-                read_leb_uint32(frame_ip, frame_ip_end, flags);
+                read_leb_memarg(frame_ip, frame_ip_end, flags);
                 read_leb_mem_offset(frame_ip, frame_ip_end, offset);
                 read_leb_mem_offset(frame_ip, frame_ip_end, offset);
                 addr = POP_MEM_OFFSET();
                 addr = POP_MEM_OFFSET();
                 CHECK_MEMORY_OVERFLOW(4);
                 CHECK_MEMORY_OVERFLOW(4);
                 PUSH_I64(sign_ext_32_64(LOAD_I32(maddr)));
                 PUSH_I64(sign_ext_32_64(LOAD_I32(maddr)));
                 CHECK_READ_WATCHPOINT(addr, offset);
                 CHECK_READ_WATCHPOINT(addr, offset);
-                (void)flags;
                 HANDLE_OP_END();
                 HANDLE_OP_END();
             }
             }
 
 
@@ -4452,13 +4489,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                 uint32 flags;
                 uint32 flags;
                 mem_offset_t offset, addr;
                 mem_offset_t offset, addr;
 
 
-                read_leb_uint32(frame_ip, frame_ip_end, flags);
+                read_leb_memarg(frame_ip, frame_ip_end, flags);
                 read_leb_mem_offset(frame_ip, frame_ip_end, offset);
                 read_leb_mem_offset(frame_ip, frame_ip_end, offset);
                 addr = POP_MEM_OFFSET();
                 addr = POP_MEM_OFFSET();
                 CHECK_MEMORY_OVERFLOW(4);
                 CHECK_MEMORY_OVERFLOW(4);
                 PUSH_I64((uint64)(LOAD_U32(maddr)));
                 PUSH_I64((uint64)(LOAD_U32(maddr)));
                 CHECK_READ_WATCHPOINT(addr, offset);
                 CHECK_READ_WATCHPOINT(addr, offset);
-                (void)flags;
                 HANDLE_OP_END();
                 HANDLE_OP_END();
             }
             }
 
 
@@ -4469,7 +4505,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                 uint32 flags;
                 uint32 flags;
                 mem_offset_t offset, addr;
                 mem_offset_t offset, addr;
 
 
-                read_leb_uint32(frame_ip, frame_ip_end, flags);
+                read_leb_memarg(frame_ip, frame_ip_end, flags);
                 read_leb_mem_offset(frame_ip, frame_ip_end, offset);
                 read_leb_mem_offset(frame_ip, frame_ip_end, offset);
                 frame_sp--;
                 frame_sp--;
                 addr = POP_MEM_OFFSET();
                 addr = POP_MEM_OFFSET();
@@ -4484,7 +4520,6 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                     STORE_U32(maddr, frame_sp[1]);
                     STORE_U32(maddr, frame_sp[1]);
                 }
                 }
                 CHECK_WRITE_WATCHPOINT(addr, offset);
                 CHECK_WRITE_WATCHPOINT(addr, offset);
-                (void)flags;
                 HANDLE_OP_END();
                 HANDLE_OP_END();
             }
             }
 
 
@@ -4494,7 +4529,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                 uint32 flags;
                 uint32 flags;
                 mem_offset_t offset, addr;
                 mem_offset_t offset, addr;
 
 
-                read_leb_uint32(frame_ip, frame_ip_end, flags);
+                read_leb_memarg(frame_ip, frame_ip_end, flags);
                 read_leb_mem_offset(frame_ip, frame_ip_end, offset);
                 read_leb_mem_offset(frame_ip, frame_ip_end, offset);
                 frame_sp -= 2;
                 frame_sp -= 2;
                 addr = POP_MEM_OFFSET();
                 addr = POP_MEM_OFFSET();
@@ -4512,7 +4547,6 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                                     GET_I64_FROM_ADDR(frame_sp + 1));
                                     GET_I64_FROM_ADDR(frame_sp + 1));
                 }
                 }
                 CHECK_WRITE_WATCHPOINT(addr, offset);
                 CHECK_WRITE_WATCHPOINT(addr, offset);
-                (void)flags;
                 HANDLE_OP_END();
                 HANDLE_OP_END();
             }
             }
 
 
@@ -4524,7 +4558,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                 uint32 sval;
                 uint32 sval;
 
 
                 opcode = *(frame_ip - 1);
                 opcode = *(frame_ip - 1);
-                read_leb_uint32(frame_ip, frame_ip_end, flags);
+                read_leb_memarg(frame_ip, frame_ip_end, flags);
                 read_leb_mem_offset(frame_ip, frame_ip_end, offset);
                 read_leb_mem_offset(frame_ip, frame_ip_end, offset);
                 sval = (uint32)POP_I32();
                 sval = (uint32)POP_I32();
                 addr = POP_MEM_OFFSET();
                 addr = POP_MEM_OFFSET();
@@ -4538,7 +4572,6 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                     STORE_U16(maddr, (uint16)sval);
                     STORE_U16(maddr, (uint16)sval);
                 }
                 }
                 CHECK_WRITE_WATCHPOINT(addr, offset);
                 CHECK_WRITE_WATCHPOINT(addr, offset);
-                (void)flags;
                 HANDLE_OP_END();
                 HANDLE_OP_END();
             }
             }
 
 
@@ -4551,7 +4584,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                 uint64 sval;
                 uint64 sval;
 
 
                 opcode = *(frame_ip - 1);
                 opcode = *(frame_ip - 1);
-                read_leb_uint32(frame_ip, frame_ip_end, flags);
+                read_leb_memarg(frame_ip, frame_ip_end, flags);
                 read_leb_mem_offset(frame_ip, frame_ip_end, offset);
                 read_leb_mem_offset(frame_ip, frame_ip_end, offset);
                 sval = (uint64)POP_I64();
                 sval = (uint64)POP_I64();
                 addr = POP_MEM_OFFSET();
                 addr = POP_MEM_OFFSET();
@@ -4569,29 +4602,27 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                     STORE_U32(maddr, (uint32)sval);
                     STORE_U32(maddr, (uint32)sval);
                 }
                 }
                 CHECK_WRITE_WATCHPOINT(addr, offset);
                 CHECK_WRITE_WATCHPOINT(addr, offset);
-                (void)flags;
                 HANDLE_OP_END();
                 HANDLE_OP_END();
             }
             }
 
 
             /* memory size and memory grow instructions */
             /* memory size and memory grow instructions */
             HANDLE_OP(WASM_OP_MEMORY_SIZE)
             HANDLE_OP(WASM_OP_MEMORY_SIZE)
             {
             {
-                uint32 reserved;
-                read_leb_uint32(frame_ip, frame_ip_end, reserved);
+                uint32 mem_idx;
+                read_leb_memidx(frame_ip, frame_ip_end, mem_idx);
                 PUSH_PAGE_COUNT(memory->cur_page_count);
                 PUSH_PAGE_COUNT(memory->cur_page_count);
-                (void)reserved;
                 HANDLE_OP_END();
                 HANDLE_OP_END();
             }
             }
 
 
             HANDLE_OP(WASM_OP_MEMORY_GROW)
             HANDLE_OP(WASM_OP_MEMORY_GROW)
             {
             {
-                uint32 reserved, delta,
-                    prev_page_count = memory->cur_page_count;
+                uint32 mem_idx, delta, prev_page_count;
 
 
-                read_leb_uint32(frame_ip, frame_ip_end, reserved);
+                read_leb_memidx(frame_ip, frame_ip_end, mem_idx);
+                prev_page_count = memory->cur_page_count;
                 delta = (uint32)POP_PAGE_COUNT();
                 delta = (uint32)POP_PAGE_COUNT();
 
 
-                if (!wasm_enlarge_memory(module, delta)) {
+                if (!wasm_enlarge_memory_with_idx(module, delta, mem_idx)) {
                     /* failed to memory.grow, return -1 */
                     /* failed to memory.grow, return -1 */
                     PUSH_PAGE_COUNT(-1);
                     PUSH_PAGE_COUNT(-1);
                 }
                 }
@@ -4607,7 +4638,6 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
 #endif
 #endif
                 }
                 }
 
 
-                (void)reserved;
                 HANDLE_OP_END();
                 HANDLE_OP_END();
             }
             }
 
 
@@ -5603,8 +5633,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                         uint8 *data;
                         uint8 *data;
 
 
                         read_leb_uint32(frame_ip, frame_ip_end, segment);
                         read_leb_uint32(frame_ip, frame_ip_end, segment);
+#if WASM_ENABLE_MULTI_MEMORY != 0
+                        read_leb_memidx(frame_ip, frame_ip_end, memidx);
+#else
                         /* skip memory index */
                         /* skip memory index */
                         frame_ip++;
                         frame_ip++;
+#endif
 
 
                         bytes = (uint64)(uint32)POP_I32();
                         bytes = (uint64)(uint32)POP_I32();
                         offset = (uint64)(uint32)POP_I32();
                         offset = (uint64)(uint32)POP_I32();
@@ -5653,33 +5687,54 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                     {
                     {
                         mem_offset_t dst, src, len;
                         mem_offset_t dst, src, len;
                         uint8 *mdst, *msrc;
                         uint8 *mdst, *msrc;
+                        uint64 dlen;
 
 
-                        frame_ip += 2;
                         len = POP_MEM_OFFSET();
                         len = POP_MEM_OFFSET();
                         src = POP_MEM_OFFSET();
                         src = POP_MEM_OFFSET();
                         dst = POP_MEM_OFFSET();
                         dst = POP_MEM_OFFSET();
 
 
+#if WASM_ENABLE_MULTI_MEMORY != 0
+                        /* dst memidx */
+                        read_leb_memidx(frame_ip, frame_ip_end, memidx);
+#else
+                        /* skip dst memidx */
+                        frame_ip += 1;
+#endif
 #if WASM_ENABLE_THREAD_MGR != 0
 #if WASM_ENABLE_THREAD_MGR != 0
                         linear_mem_size = get_linear_mem_size();
                         linear_mem_size = get_linear_mem_size();
 #endif
 #endif
-
+                        /* dst boundary check */
 #ifndef OS_ENABLE_HW_BOUND_CHECK
 #ifndef OS_ENABLE_HW_BOUND_CHECK
-                        CHECK_BULK_MEMORY_OVERFLOW(src, len, msrc);
                         CHECK_BULK_MEMORY_OVERFLOW(dst, len, mdst);
                         CHECK_BULK_MEMORY_OVERFLOW(dst, len, mdst);
 #else
 #else
-                        if ((uint64)(uint32)src + len > linear_mem_size)
+                        if ((uint64)dst + len > linear_mem_size)
                             goto out_of_bounds;
                             goto out_of_bounds;
-                        msrc = memory->memory_data + (uint32)src;
+                        mdst = memory->memory_data + dst;
+#endif
+                        dlen = linear_mem_size - dst;
 
 
-                        if ((uint64)(uint32)dst + len > linear_mem_size)
+#if WASM_ENABLE_MULTI_MEMORY != 0
+                        /* src memidx */
+                        read_leb_memidx(frame_ip, frame_ip_end, memidx);
+#else
+                        /* skip src memidx */
+                        frame_ip += 1;
+#endif
+#if WASM_ENABLE_THREAD_MGR != 0
+                        linear_mem_size = get_linear_mem_size();
+#endif
+                        /* src boundary check */
+#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;
                             goto out_of_bounds;
-                        mdst = memory->memory_data + (uint32)dst;
+                        msrc = memory->memory_data + src;
 #endif
 #endif
 
 
-                        /* allowing the destination and source to overlap */
 #if WASM_ENABLE_MEMORY64 == 0
 #if WASM_ENABLE_MEMORY64 == 0
-                        bh_memmove_s(mdst, (uint32)(linear_mem_size - dst),
-                                     msrc, (uint32)len);
+                        /* allowing the destination and source to overlap */
+                        bh_memmove_s(mdst, (uint32)dlen, msrc, (uint32)len);
 #else
 #else
                         /* use memmove when memory64 is enabled since len
                         /* use memmove when memory64 is enabled since len
                            may be larger than UINT32_MAX */
                            may be larger than UINT32_MAX */
@@ -5691,7 +5746,13 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                     {
                     {
                         mem_offset_t dst, len;
                         mem_offset_t dst, len;
                         uint8 fill_val, *mdst;
                         uint8 fill_val, *mdst;
+
+#if WASM_ENABLE_MULTI_MEMORY != 0
+                        read_leb_memidx(frame_ip, frame_ip_end, memidx);
+#else
+                        /* skip memory index */
                         frame_ip++;
                         frame_ip++;
+#endif
 
 
                         len = POP_MEM_OFFSET();
                         len = POP_MEM_OFFSET();
                         fill_val = POP_I32();
                         fill_val = POP_I32();

+ 1 - 0
core/iwasm/interpreter/wasm_interp_fast.c

@@ -3837,6 +3837,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                 addr_ret = GET_OFFSET();
                 addr_ret = GET_OFFSET();
                 delta = (uint32)frame_lp[addr1];
                 delta = (uint32)frame_lp[addr1];
 
 
+                /* TODO: multi-memory wasm_enlarge_memory_with_idx() */
                 if (!wasm_enlarge_memory(module, delta)) {
                 if (!wasm_enlarge_memory(module, delta)) {
                     /* failed to memory.grow, return -1 */
                     /* failed to memory.grow, return -1 */
                     frame_lp[addr_ret] = -1;
                     frame_lp[addr_ret] = -1;

+ 84 - 39
core/iwasm/interpreter/wasm_loader.c

@@ -127,6 +127,17 @@ check_buf1(const uint8 *buf, const uint8 *buf_end, uint32 length,
 #define skip_leb_uint32(p, p_end) skip_leb(p)
 #define skip_leb_uint32(p, p_end) skip_leb(p)
 #define skip_leb_int32(p, p_end) skip_leb(p)
 #define skip_leb_int32(p, p_end) skip_leb(p)
 #define skip_leb_mem_offset(p, p_end) skip_leb(p)
 #define skip_leb_mem_offset(p, p_end) skip_leb(p)
+#define skip_leb_memidx(p, p_end) skip_leb(p)
+#if WASM_ENABLE_MULTI_MEMORY == 0
+#define skip_leb_align(p, p_end) skip_leb(p)
+#else
+/* Skip the following memidx if applicable */
+#define skip_leb_align(p, p_end)       \
+    do {                               \
+        if (*p++ & OPT_MEMIDX_FLAG)    \
+            skip_leb_uint32(p, p_end); \
+    } while (0)
+#endif
 
 
 #define read_uint8(p) TEMPLATE_READ_VALUE(uint8, p)
 #define read_uint8(p) TEMPLATE_READ_VALUE(uint8, p)
 #define read_uint32(p) TEMPLATE_READ_VALUE(uint32, p)
 #define read_uint32(p) TEMPLATE_READ_VALUE(uint32, p)
@@ -173,6 +184,40 @@ check_buf1(const uint8 *buf, const uint8 *buf_end, uint32 length,
         res = (int32)res64;                                             \
         res = (int32)res64;                                             \
     } while (0)
     } while (0)
 
 
+#define read_leb_memidx(p, p_end, res) read_leb_uint32(p, p_end, res)
+#if WASM_ENABLE_MULTI_MEMORY != 0
+#define check_memidx(module, memidx)                                        \
+    do {                                                                    \
+        if (memidx >= module->import_memory_count + module->memory_count) { \
+            set_error_buf_v(error_buf, error_buf_size, "unknown memory %d", \
+                            memidx);                                        \
+            goto fail;                                                      \
+        }                                                                   \
+    } while (0)
+/* Bit 6(0x40) indicating the optional memidx, and reset bit 6 for
+ * alignment check */
+#define read_leb_memarg(p, p_end, res)                      \
+    do {                                                    \
+        read_leb_uint32(p, p_end, res);                     \
+        if (res & OPT_MEMIDX_FLAG) {                        \
+            res &= ~OPT_MEMIDX_FLAG;                        \
+            read_leb_uint32(p, p_end, memidx); /* memidx */ \
+            check_memidx(module, memidx);                   \
+        }                                                   \
+    } while (0)
+#else
+/* reserved byte 0x00 */
+#define check_memidx(module, memidx)                                        \
+    do {                                                                    \
+        (void)module;                                                       \
+        if (memidx != 0) {                                                  \
+            set_error_buf(error_buf, error_buf_size, "zero byte expected"); \
+            goto fail;                                                      \
+        }                                                                   \
+    } while (0)
+#define read_leb_memarg(p, p_end, res) read_leb_uint32(p, p_end, res)
+#endif
+
 static char *
 static char *
 type2str(uint8 type)
 type2str(uint8 type)
 {
 {
@@ -3288,11 +3333,13 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
                     if (flags & 1)
                     if (flags & 1)
                         read_leb_uint32(p, p_end, u32);
                         read_leb_uint32(p, p_end, u32);
                     module->import_memory_count++;
                     module->import_memory_count++;
+#if WASM_ENABLE_MULTI_MEMORY == 0
                     if (module->import_memory_count > 1) {
                     if (module->import_memory_count > 1) {
                         set_error_buf(error_buf, error_buf_size,
                         set_error_buf(error_buf, error_buf_size,
                                       "multiple memories");
                                       "multiple memories");
                         return false;
                         return false;
                     }
                     }
+#endif
                     break;
                     break;
 
 
 #if WASM_ENABLE_TAGS != 0
 #if WASM_ENABLE_TAGS != 0
@@ -3903,11 +3950,14 @@ load_memory_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
     WASMMemory *memory;
     WASMMemory *memory;
 
 
     read_leb_uint32(p, p_end, memory_count);
     read_leb_uint32(p, p_end, memory_count);
+
+#if WASM_ENABLE_MULTI_MEMORY == 0
     /* a total of one memory is allowed */
     /* a total of one memory is allowed */
     if (module->import_memory_count + memory_count > 1) {
     if (module->import_memory_count + memory_count > 1) {
         set_error_buf(error_buf, error_buf_size, "multiple memories");
         set_error_buf(error_buf, error_buf_size, "multiple memories");
         return false;
         return false;
     }
     }
+#endif
 
 
     if (memory_count) {
     if (memory_count) {
         module->memory_count = memory_count;
         module->memory_count = memory_count;
@@ -7149,10 +7199,10 @@ wasm_loader_find_block_addr(WASMExecEnv *exec_env, BlockAddr *block_addr_cache,
             case WASM_OP_RETURN_CALL_INDIRECT:
             case WASM_OP_RETURN_CALL_INDIRECT:
 #endif
 #endif
                 skip_leb_uint32(p, p_end); /* typeidx */
                 skip_leb_uint32(p, p_end); /* typeidx */
-#if WASM_ENABLE_REF_TYPES == 0 && WASM_ENABLE_GC == 0
-                u8 = read_uint8(p); /* 0x00 */
-#else
+#if WASM_ENABLE_REF_TYPES != 0 || WASM_ENABLE_GC != 0
                 skip_leb_uint32(p, p_end); /* tableidx */
                 skip_leb_uint32(p, p_end); /* tableidx */
+#else
+                u8 = read_uint8(p); /* 0x00 */
 #endif
 #endif
                 break;
                 break;
 
 
@@ -7258,13 +7308,13 @@ wasm_loader_find_block_addr(WASMExecEnv *exec_env, BlockAddr *block_addr_cache,
             case WASM_OP_I64_STORE8:
             case WASM_OP_I64_STORE8:
             case WASM_OP_I64_STORE16:
             case WASM_OP_I64_STORE16:
             case WASM_OP_I64_STORE32:
             case WASM_OP_I64_STORE32:
-                skip_leb_uint32(p, p_end);     /* align */
+                skip_leb_align(p, p_end);      /* align */
                 skip_leb_mem_offset(p, p_end); /* offset */
                 skip_leb_mem_offset(p, p_end); /* offset */
                 break;
                 break;
 
 
             case WASM_OP_MEMORY_SIZE:
             case WASM_OP_MEMORY_SIZE:
             case WASM_OP_MEMORY_GROW:
             case WASM_OP_MEMORY_GROW:
-                skip_leb_uint32(p, p_end); /* 0x00 */
+                skip_leb_memidx(p, p_end); /* memidx */
                 break;
                 break;
 
 
             case WASM_OP_I32_CONST:
             case WASM_OP_I32_CONST:
@@ -7562,19 +7612,17 @@ wasm_loader_find_block_addr(WASMExecEnv *exec_env, BlockAddr *block_addr_cache,
 #if WASM_ENABLE_BULK_MEMORY != 0
 #if WASM_ENABLE_BULK_MEMORY != 0
                     case WASM_OP_MEMORY_INIT:
                     case WASM_OP_MEMORY_INIT:
                         skip_leb_uint32(p, p_end);
                         skip_leb_uint32(p, p_end);
-                        /* skip memory idx */
-                        p++;
+                        skip_leb_memidx(p, p_end);
                         break;
                         break;
                     case WASM_OP_DATA_DROP:
                     case WASM_OP_DATA_DROP:
                         skip_leb_uint32(p, p_end);
                         skip_leb_uint32(p, p_end);
                         break;
                         break;
                     case WASM_OP_MEMORY_COPY:
                     case WASM_OP_MEMORY_COPY:
-                        /* skip two memory idx */
-                        p += 2;
+                        skip_leb_memidx(p, p_end);
+                        skip_leb_memidx(p, p_end);
                         break;
                         break;
                     case WASM_OP_MEMORY_FILL:
                     case WASM_OP_MEMORY_FILL:
-                        /* skip memory idx */
-                        p++;
+                        skip_leb_memidx(p, p_end);
                         break;
                         break;
 #endif /* WASM_ENABLE_BULK_MEMORY */
 #endif /* WASM_ENABLE_BULK_MEMORY */
 #if WASM_ENABLE_REF_TYPES != 0
 #if WASM_ENABLE_REF_TYPES != 0
@@ -7701,7 +7749,6 @@ wasm_loader_find_block_addr(WASMExecEnv *exec_env, BlockAddr *block_addr_cache,
 #if WASM_ENABLE_SHARED_MEMORY != 0
 #if WASM_ENABLE_SHARED_MEMORY != 0
             case WASM_OP_ATOMIC_PREFIX:
             case WASM_OP_ATOMIC_PREFIX:
             {
             {
-                /* TODO: memory64 offset type changes */
                 uint32 opcode1;
                 uint32 opcode1;
 
 
                 /* atomic_op (u32_leb) + memarg (2 u32_leb) */
                 /* atomic_op (u32_leb) + memarg (2 u32_leb) */
@@ -10876,6 +10923,7 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func,
 #else
 #else
     mem_offset_type = VALUE_TYPE_I32;
     mem_offset_type = VALUE_TYPE_I32;
 #endif
 #endif
+    uint32 memidx;
 
 
     global_count = module->import_global_count + module->global_count;
     global_count = module->import_global_count + module->global_count;
 
 
@@ -12004,6 +12052,16 @@ re_scan:
 
 
                 read_leb_uint32(p, p_end, type_idx);
                 read_leb_uint32(p, p_end, type_idx);
 #if WASM_ENABLE_REF_TYPES != 0 || WASM_ENABLE_GC != 0
 #if WASM_ENABLE_REF_TYPES != 0 || WASM_ENABLE_GC != 0
+#if WASM_ENABLE_WAMR_COMPILER != 0
+                if (p + 1 < p_end && *p != 0x00) {
+                    /*
+                     * Any non-0x00 byte requires the ref types proposal.
+                     * This is different from checking the table_idx value
+                     * since `0x80 0x00` etc. are all valid encodings of zero.
+                     */
+                    module->is_ref_types_used = true;
+                }
+#endif
                 read_leb_uint32(p, p_end, table_idx);
                 read_leb_uint32(p, p_end, table_idx);
 #else
 #else
                 CHECK_BUF(p, p_end, 1);
                 CHECK_BUF(p, p_end, 1);
@@ -13145,7 +13203,7 @@ re_scan:
                 }
                 }
 #endif
 #endif
                 CHECK_MEMORY();
                 CHECK_MEMORY();
-                read_leb_uint32(p, p_end, align);          /* align */
+                read_leb_memarg(p, p_end, align);          /* align */
                 read_leb_mem_offset(p, p_end, mem_offset); /* offset */
                 read_leb_mem_offset(p, p_end, mem_offset); /* offset */
                 if (!check_memory_access_align(opcode, align, error_buf,
                 if (!check_memory_access_align(opcode, align, error_buf,
                                                error_buf_size)) {
                                                error_buf_size)) {
@@ -13211,12 +13269,8 @@ re_scan:
 
 
             case WASM_OP_MEMORY_SIZE:
             case WASM_OP_MEMORY_SIZE:
                 CHECK_MEMORY();
                 CHECK_MEMORY();
-                /* reserved byte 0x00 */
-                if (*p++ != 0x00) {
-                    set_error_buf(error_buf, error_buf_size,
-                                  "zero byte expected");
-                    goto fail;
-                }
+                read_leb_uint32(p, p_end, memidx);
+                check_memidx(module, memidx);
                 PUSH_PAGE_COUNT();
                 PUSH_PAGE_COUNT();
 
 
                 module->possible_memory_grow = true;
                 module->possible_memory_grow = true;
@@ -13227,12 +13281,8 @@ re_scan:
 
 
             case WASM_OP_MEMORY_GROW:
             case WASM_OP_MEMORY_GROW:
                 CHECK_MEMORY();
                 CHECK_MEMORY();
-                /* reserved byte 0x00 */
-                if (*p++ != 0x00) {
-                    set_error_buf(error_buf, error_buf_size,
-                                  "zero byte expected");
-                    goto fail;
-                }
+                read_leb_uint32(p, p_end, memidx);
+                check_memidx(module, memidx);
                 POP_AND_PUSH(mem_offset_type, mem_offset_type);
                 POP_AND_PUSH(mem_offset_type, mem_offset_type);
 
 
                 module->possible_memory_grow = true;
                 module->possible_memory_grow = true;
@@ -14584,8 +14634,8 @@ re_scan:
                             && module->memory_count == 0)
                             && module->memory_count == 0)
                             goto fail_unknown_memory;
                             goto fail_unknown_memory;
 
 
-                        if (*p++ != 0x00)
-                            goto fail_zero_byte_expected;
+                        read_leb_uint32(p, p_end, memidx);
+                        check_memidx(module, memidx);
 
 
                         if (data_seg_idx >= module->data_seg_count) {
                         if (data_seg_idx >= module->data_seg_count) {
                             set_error_buf_v(error_buf, error_buf_size,
                             set_error_buf_v(error_buf, error_buf_size,
@@ -14634,10 +14684,11 @@ re_scan:
                     case WASM_OP_MEMORY_COPY:
                     case WASM_OP_MEMORY_COPY:
                     {
                     {
                         CHECK_BUF(p, p_end, sizeof(int16));
                         CHECK_BUF(p, p_end, sizeof(int16));
-                        /* both src and dst memory index should be 0 */
-                        if (*(int16 *)p != 0x0000)
-                            goto fail_zero_byte_expected;
-                        p += 2;
+                        /* check both src and dst memory index */
+                        read_leb_uint32(p, p_end, memidx);
+                        check_memidx(module, memidx);
+                        read_leb_uint32(p, p_end, memidx);
+                        check_memidx(module, memidx);
 
 
                         if (module->import_memory_count == 0
                         if (module->import_memory_count == 0
                             && module->memory_count == 0)
                             && module->memory_count == 0)
@@ -14656,9 +14707,8 @@ re_scan:
                     }
                     }
                     case WASM_OP_MEMORY_FILL:
                     case WASM_OP_MEMORY_FILL:
                     {
                     {
-                        if (*p++ != 0x00) {
-                            goto fail_zero_byte_expected;
-                        }
+                        read_leb_uint32(p, p_end, memidx);
+                        check_memidx(module, memidx);
                         if (module->import_memory_count == 0
                         if (module->import_memory_count == 0
                             && module->memory_count == 0) {
                             && module->memory_count == 0) {
                             goto fail_unknown_memory;
                             goto fail_unknown_memory;
@@ -14674,10 +14724,6 @@ re_scan:
 #endif
 #endif
                         break;
                         break;
                     }
                     }
-                    fail_zero_byte_expected:
-                        set_error_buf(error_buf, error_buf_size,
-                                      "zero byte expected");
-                        goto fail;
 
 
                     fail_unknown_memory:
                     fail_unknown_memory:
                         set_error_buf(error_buf, error_buf_size,
                         set_error_buf(error_buf, error_buf_size,
@@ -14911,7 +14957,6 @@ re_scan:
 #if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0)
 #if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0)
             case WASM_OP_SIMD_PREFIX:
             case WASM_OP_SIMD_PREFIX:
             {
             {
-                /* TODO: memory64 offset type changes */
                 uint32 opcode1;
                 uint32 opcode1;
 
 
 #if WASM_ENABLE_WAMR_COMPILER != 0
 #if WASM_ENABLE_WAMR_COMPILER != 0

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

@@ -62,6 +62,17 @@ set_error_buf(char *error_buf, uint32 error_buf_size, const char *string)
 #define skip_leb_uint32(p, p_end) skip_leb(p)
 #define skip_leb_uint32(p, p_end) skip_leb(p)
 #define skip_leb_int32(p, p_end) skip_leb(p)
 #define skip_leb_int32(p, p_end) skip_leb(p)
 #define skip_leb_mem_offset(p, p_end) skip_leb(p)
 #define skip_leb_mem_offset(p, p_end) skip_leb(p)
+#define skip_leb_memidx(p, p_end) skip_leb(p)
+#if WASM_ENABLE_MULTI_MEMORY == 0
+#define skip_leb_align(p, p_end) skip_leb(p)
+#else
+/* Skip the following memidx if applicable */
+#define skip_leb_align(p, p_end)       \
+    do {                               \
+        if (*p++ & OPT_MEMIDX_FLAG)    \
+            skip_leb_uint32(p, p_end); \
+    } while (0)
+#endif
 
 
 static bool
 static bool
 is_32bit_type(uint8 type)
 is_32bit_type(uint8 type)
@@ -132,6 +143,35 @@ is_byte_a_type(uint8 type)
 #else
 #else
 #define read_leb_mem_offset(p, p_end, res) read_leb_uint32(p, p_end, res)
 #define read_leb_mem_offset(p, p_end, res) read_leb_uint32(p, p_end, res)
 #endif
 #endif
+#define read_leb_memidx(p, p_end, res) read_leb_uint32(p, p_end, res)
+#if WASM_ENABLE_MULTI_MEMORY != 0
+#define check_memidx(module, memidx)                                     \
+    do {                                                                 \
+        bh_assert(memidx                                                 \
+                  < module->import_memory_count + module->memory_count); \
+        (void)memidx;                                                    \
+    } while (0)
+/* Bit 6 indicating the optional memidx, and reset bit 6 for
+ * alignment check */
+#define read_leb_memarg(p, p_end, res)                      \
+    do {                                                    \
+        read_leb_uint32(p, p_end, res);                     \
+        if (res & OPT_MEMIDX_FLAG) {                        \
+            res &= ~OPT_MEMIDX_FLAG;                        \
+            read_leb_uint32(p, p_end, memidx); /* memidx */ \
+            check_memidx(module, memidx);                   \
+        }                                                   \
+    } while (0)
+#else
+/* reserved byte 0x00 */
+#define check_memidx(module, memidx) \
+    do {                             \
+        (void)module;                \
+        bh_assert(memidx == 0);      \
+        (void)memidx;                \
+    } while (0)
+#define read_leb_memarg(p, p_end, res) read_leb_uint32(p, p_end, res)
+#endif
 
 
 static void *
 static void *
 loader_malloc(uint64 size, char *error_buf, uint32 error_buf_size)
 loader_malloc(uint64 size, char *error_buf, uint32 error_buf_size)
@@ -882,7 +922,9 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
                     if (flags & 1)
                     if (flags & 1)
                         read_leb_uint32(p, p_end, u32);
                         read_leb_uint32(p, p_end, u32);
                     module->import_memory_count++;
                     module->import_memory_count++;
+#if WASM_ENABLE_MULTI_MEMORY != 0
                     bh_assert(module->import_memory_count <= 1);
                     bh_assert(module->import_memory_count <= 1);
+#endif
                     break;
                     break;
 
 
                 case IMPORT_KIND_GLOBAL: /* import global */
                 case IMPORT_KIND_GLOBAL: /* import global */
@@ -1223,7 +1265,9 @@ load_memory_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
     WASMMemory *memory;
     WASMMemory *memory;
 
 
     read_leb_uint32(p, p_end, memory_count);
     read_leb_uint32(p, p_end, memory_count);
+#if WASM_ENABLE_MULTI_MEMORY != 0
     bh_assert(module->import_memory_count + memory_count <= 1);
     bh_assert(module->import_memory_count + memory_count <= 1);
+#endif
 
 
     if (memory_count) {
     if (memory_count) {
         module->memory_count = memory_count;
         module->memory_count = memory_count;
@@ -3501,8 +3545,11 @@ wasm_loader_find_block_addr(WASMExecEnv *exec_env, BlockAddr *block_addr_cache,
             case WASM_OP_RETURN_CALL_INDIRECT:
             case WASM_OP_RETURN_CALL_INDIRECT:
 #endif
 #endif
                 skip_leb_uint32(p, p_end); /* typeidx */
                 skip_leb_uint32(p, p_end); /* typeidx */
-                CHECK_BUF(p, p_end, 1);
+#if WASM_ENABLE_REF_TYPES != 0
+                skip_leb_uint32(p, p_end); /* tableidx */
+#else
                 u8 = read_uint8(p); /* 0x00 */
                 u8 = read_uint8(p); /* 0x00 */
+#endif
                 break;
                 break;
 
 
 #if WASM_ENABLE_EXCE_HANDLING != 0
 #if WASM_ENABLE_EXCE_HANDLING != 0
@@ -3582,13 +3629,13 @@ wasm_loader_find_block_addr(WASMExecEnv *exec_env, BlockAddr *block_addr_cache,
             case WASM_OP_I64_STORE8:
             case WASM_OP_I64_STORE8:
             case WASM_OP_I64_STORE16:
             case WASM_OP_I64_STORE16:
             case WASM_OP_I64_STORE32:
             case WASM_OP_I64_STORE32:
-                skip_leb_uint32(p, p_end);     /* align */
+                skip_leb_align(p, p_end);      /* align */
                 skip_leb_mem_offset(p, p_end); /* offset */
                 skip_leb_mem_offset(p, p_end); /* offset */
                 break;
                 break;
 
 
             case WASM_OP_MEMORY_SIZE:
             case WASM_OP_MEMORY_SIZE:
             case WASM_OP_MEMORY_GROW:
             case WASM_OP_MEMORY_GROW:
-                skip_leb_uint32(p, p_end); /* 0x00 */
+                skip_leb_memidx(p, p_end); /* memidx */
                 break;
                 break;
 
 
             case WASM_OP_I32_CONST:
             case WASM_OP_I32_CONST:
@@ -3755,19 +3802,17 @@ wasm_loader_find_block_addr(WASMExecEnv *exec_env, BlockAddr *block_addr_cache,
 #if WASM_ENABLE_BULK_MEMORY != 0
 #if WASM_ENABLE_BULK_MEMORY != 0
                     case WASM_OP_MEMORY_INIT:
                     case WASM_OP_MEMORY_INIT:
                         skip_leb_uint32(p, p_end);
                         skip_leb_uint32(p, p_end);
-                        /* skip memory idx */
-                        p++;
+                        skip_leb_memidx(p, p_end);
                         break;
                         break;
                     case WASM_OP_DATA_DROP:
                     case WASM_OP_DATA_DROP:
                         skip_leb_uint32(p, p_end);
                         skip_leb_uint32(p, p_end);
                         break;
                         break;
                     case WASM_OP_MEMORY_COPY:
                     case WASM_OP_MEMORY_COPY:
-                        /* skip two memory idx */
-                        p += 2;
+                        skip_leb_memidx(p, p_end);
+                        skip_leb_memidx(p, p_end);
                         break;
                         break;
                     case WASM_OP_MEMORY_FILL:
                     case WASM_OP_MEMORY_FILL:
-                        /* skip memory idx */
-                        p++;
+                        skip_leb_memidx(p, p_end);
                         break;
                         break;
 #endif
 #endif
 #if WASM_ENABLE_REF_TYPES != 0
 #if WASM_ENABLE_REF_TYPES != 0
@@ -5902,7 +5947,7 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func,
     uint8 *param_types, *local_types, local_type, global_type, mem_offset_type;
     uint8 *param_types, *local_types, local_type, global_type, mem_offset_type;
     BlockType func_block_type;
     BlockType func_block_type;
     uint16 *local_offsets, local_offset;
     uint16 *local_offsets, local_offset;
-    uint32 count, local_idx, global_idx, u32, align, i;
+    uint32 count, local_idx, global_idx, u32, align, i, memidx;
     mem_offset_t mem_offset;
     mem_offset_t mem_offset;
     int32 i32, i32_const = 0;
     int32 i32, i32_const = 0;
     int64 i64_const;
     int64 i64_const;
@@ -7264,7 +7309,7 @@ re_scan:
                 }
                 }
 #endif
 #endif
                 CHECK_MEMORY();
                 CHECK_MEMORY();
-                read_leb_uint32(p, p_end, align);          /* align */
+                read_leb_memarg(p, p_end, align);          /* align */
                 read_leb_mem_offset(p, p_end, mem_offset); /* offset */
                 read_leb_mem_offset(p, p_end, mem_offset); /* offset */
 #if WASM_ENABLE_FAST_INTERP != 0
 #if WASM_ENABLE_FAST_INTERP != 0
                 emit_uint32(loader_ctx, mem_offset);
                 emit_uint32(loader_ctx, mem_offset);
@@ -7326,9 +7371,8 @@ re_scan:
 
 
             case WASM_OP_MEMORY_SIZE:
             case WASM_OP_MEMORY_SIZE:
                 CHECK_MEMORY();
                 CHECK_MEMORY();
-                /* reserved byte 0x00 */
-                bh_assert(*p == 0x00);
-                p++;
+                read_leb_memidx(p, p_end, memidx);
+                check_memidx(module, memidx);
                 PUSH_PAGE_COUNT();
                 PUSH_PAGE_COUNT();
 
 
                 module->possible_memory_grow = true;
                 module->possible_memory_grow = true;
@@ -7339,9 +7383,8 @@ re_scan:
 
 
             case WASM_OP_MEMORY_GROW:
             case WASM_OP_MEMORY_GROW:
                 CHECK_MEMORY();
                 CHECK_MEMORY();
-                /* reserved byte 0x00 */
-                bh_assert(*p == 0x00);
-                p++;
+                read_leb_memidx(p, p_end, memidx);
+                check_memidx(module, memidx);
                 POP_AND_PUSH(mem_offset_type, mem_offset_type);
                 POP_AND_PUSH(mem_offset_type, mem_offset_type);
 
 
                 module->possible_memory_grow = true;
                 module->possible_memory_grow = true;
@@ -7679,16 +7722,13 @@ re_scan:
 #if WASM_ENABLE_BULK_MEMORY != 0
 #if WASM_ENABLE_BULK_MEMORY != 0
                     case WASM_OP_MEMORY_INIT:
                     case WASM_OP_MEMORY_INIT:
                     {
                     {
+                        CHECK_MEMORY();
                         read_leb_uint32(p, p_end, segment_index);
                         read_leb_uint32(p, p_end, segment_index);
 #if WASM_ENABLE_FAST_INTERP != 0
 #if WASM_ENABLE_FAST_INTERP != 0
                         emit_uint32(loader_ctx, segment_index);
                         emit_uint32(loader_ctx, segment_index);
 #endif
 #endif
-                        bh_assert(module->import_memory_count
-                                      + module->memory_count
-                                  > 0);
-
-                        bh_assert(*p == 0x00);
-                        p++;
+                        read_leb_memidx(p, p_end, memidx);
+                        check_memidx(module, memidx);
 
 
                         bh_assert(segment_index < module->data_seg_count);
                         bh_assert(segment_index < module->data_seg_count);
                         bh_assert(module->data_seg_count1 > 0);
                         bh_assert(module->data_seg_count1 > 0);
@@ -7716,14 +7756,13 @@ re_scan:
                     }
                     }
                     case WASM_OP_MEMORY_COPY:
                     case WASM_OP_MEMORY_COPY:
                     {
                     {
+                        CHECK_MEMORY();
                         CHECK_BUF(p, p_end, sizeof(int16));
                         CHECK_BUF(p, p_end, sizeof(int16));
-                        /* both src and dst memory index should be 0 */
-                        bh_assert(*(int16 *)p == 0x0000);
-                        p += 2;
-
-                        bh_assert(module->import_memory_count
-                                      + module->memory_count
-                                  > 0);
+                        /* check both src and dst memory index */
+                        read_leb_memidx(p, p_end, memidx);
+                        check_memidx(module, memidx);
+                        read_leb_memidx(p, p_end, memidx);
+                        check_memidx(module, memidx);
 
 
                         POP_MEM_OFFSET();
                         POP_MEM_OFFSET();
                         POP_MEM_OFFSET();
                         POP_MEM_OFFSET();
@@ -7735,12 +7774,9 @@ re_scan:
                     }
                     }
                     case WASM_OP_MEMORY_FILL:
                     case WASM_OP_MEMORY_FILL:
                     {
                     {
-                        bh_assert(*p == 0);
-                        p++;
-
-                        bh_assert(module->import_memory_count
-                                      + module->memory_count
-                                  > 0);
+                        CHECK_MEMORY();
+                        read_leb_memidx(p, p_end, memidx);
+                        check_memidx(module, memidx);
 
 
                         POP_MEM_OFFSET();
                         POP_MEM_OFFSET();
                         POP_I32();
                         POP_I32();

+ 159 - 100
core/iwasm/interpreter/wasm_runtime.c

@@ -194,114 +194,119 @@ memory_instantiate(WASMModuleInstance *module_inst, WASMModuleInstance *parent,
     default_max_page =
     default_max_page =
         memory->is_memory64 ? DEFAULT_MEM64_MAX_PAGES : DEFAULT_MAX_PAGES;
         memory->is_memory64 ? DEFAULT_MEM64_MAX_PAGES : DEFAULT_MAX_PAGES;
 
 
-    if (heap_size > 0 && module_inst->module->malloc_function != (uint32)-1
-        && module_inst->module->free_function != (uint32)-1) {
-        /* Disable app heap, use malloc/free function exported
-           by wasm app to allocate/free memory instead */
-        heap_size = 0;
-    }
-
-    /* If initial memory is the largest size allowed, disallowing insert host
-     * managed heap */
-    if (heap_size > 0
-        && heap_offset == GET_MAX_LINEAR_MEMORY_SIZE(memory->is_memory64)) {
-        set_error_buf(error_buf, error_buf_size,
-                      "failed to insert app heap into linear memory, "
-                      "try using `--heap-size=0` option");
-        return NULL;
-    }
+    /* The app heap should be in the default memory */
+    if (memory_idx == 0) {
+        if (heap_size > 0 && module_inst->module->malloc_function != (uint32)-1
+            && module_inst->module->free_function != (uint32)-1) {
+            /* Disable app heap, use malloc/free function exported
+               by wasm app to allocate/free memory instead */
+            heap_size = 0;
+        }
 
 
-    if (init_page_count == max_page_count && init_page_count == 1) {
-        /* If only one page and at most one page, we just append
-           the app heap to the end of linear memory, enlarge the
-           num_bytes_per_page, and don't change the page count */
-        heap_offset = num_bytes_per_page;
-        num_bytes_per_page += heap_size;
-        if (num_bytes_per_page < heap_size) {
+        /* If initial memory is the largest size allowed, disallowing insert
+         * host managed heap */
+        if (heap_size > 0
+            && heap_offset == GET_MAX_LINEAR_MEMORY_SIZE(memory->is_memory64)) {
             set_error_buf(error_buf, error_buf_size,
             set_error_buf(error_buf, error_buf_size,
                           "failed to insert app heap into linear memory, "
                           "failed to insert app heap into linear memory, "
                           "try using `--heap-size=0` option");
                           "try using `--heap-size=0` option");
             return NULL;
             return NULL;
         }
         }
-    }
-    else if (heap_size > 0) {
-        if (init_page_count == max_page_count && init_page_count == 0) {
-            /* If the memory data size is always 0, we resize it to
-               one page for app heap */
-            num_bytes_per_page = heap_size;
-            heap_offset = 0;
-            inc_page_count = 1;
+
+        if (init_page_count == max_page_count && init_page_count == 1) {
+            /* If only one page and at most one page, we just append
+               the app heap to the end of linear memory, enlarge the
+               num_bytes_per_page, and don't change the page count */
+            heap_offset = num_bytes_per_page;
+            num_bytes_per_page += heap_size;
+            if (num_bytes_per_page < heap_size) {
+                set_error_buf(error_buf, error_buf_size,
+                              "failed to insert app heap into linear memory, "
+                              "try using `--heap-size=0` option");
+                return NULL;
+            }
         }
         }
-        else if (module->aux_heap_base_global_index != (uint32)-1
-                 && module->aux_heap_base
-                        < (uint64)num_bytes_per_page * init_page_count) {
-            /* Insert app heap before __heap_base */
-            aux_heap_base = module->aux_heap_base;
-            bytes_of_last_page = aux_heap_base % num_bytes_per_page;
-            if (bytes_of_last_page == 0)
-                bytes_of_last_page = num_bytes_per_page;
-            bytes_to_page_end = num_bytes_per_page - bytes_of_last_page;
-            inc_page_count =
-                (heap_size - bytes_to_page_end + num_bytes_per_page - 1)
-                / num_bytes_per_page;
-            heap_offset = aux_heap_base;
-            aux_heap_base += heap_size;
-
-            bytes_of_last_page = aux_heap_base % num_bytes_per_page;
-            if (bytes_of_last_page == 0)
-                bytes_of_last_page = num_bytes_per_page;
-            bytes_to_page_end = num_bytes_per_page - bytes_of_last_page;
-            if (bytes_to_page_end < 1 * BH_KB) {
-                aux_heap_base += 1 * BH_KB;
-                inc_page_count++;
+        else if (heap_size > 0) {
+            if (init_page_count == max_page_count && init_page_count == 0) {
+                /* If the memory data size is always 0, we resize it to
+                   one page for app heap */
+                num_bytes_per_page = heap_size;
+                heap_offset = 0;
+                inc_page_count = 1;
             }
             }
+            else if (module->aux_heap_base_global_index != (uint32)-1
+                     && module->aux_heap_base
+                            < (uint64)num_bytes_per_page * init_page_count) {
+                /* Insert app heap before __heap_base */
+                aux_heap_base = module->aux_heap_base;
+                bytes_of_last_page = aux_heap_base % num_bytes_per_page;
+                if (bytes_of_last_page == 0)
+                    bytes_of_last_page = num_bytes_per_page;
+                bytes_to_page_end = num_bytes_per_page - bytes_of_last_page;
+                inc_page_count =
+                    (heap_size - bytes_to_page_end + num_bytes_per_page - 1)
+                    / num_bytes_per_page;
+                heap_offset = aux_heap_base;
+                aux_heap_base += heap_size;
+
+                bytes_of_last_page = aux_heap_base % num_bytes_per_page;
+                if (bytes_of_last_page == 0)
+                    bytes_of_last_page = num_bytes_per_page;
+                bytes_to_page_end = num_bytes_per_page - bytes_of_last_page;
+                if (bytes_to_page_end < 1 * BH_KB) {
+                    aux_heap_base += 1 * BH_KB;
+                    inc_page_count++;
+                }
 
 
-            /* Adjust __heap_base global value */
-            global_idx = module->aux_heap_base_global_index;
-            bh_assert(module_inst->e->globals
-                      && global_idx < module_inst->e->global_count);
-            global_addr = module_inst->global_data
-                          + module_inst->e->globals[global_idx].data_offset;
+                /* Adjust __heap_base global value */
+                global_idx = module->aux_heap_base_global_index;
+                bh_assert(module_inst->e->globals
+                          && global_idx < module_inst->e->global_count);
+                global_addr = module_inst->global_data
+                              + module_inst->e->globals[global_idx].data_offset;
 #if WASM_ENABLE_MEMORY64 != 0
 #if WASM_ENABLE_MEMORY64 != 0
-            if (memory->is_memory64) {
-                /* For memory64, the global value should be i64 */
-                *(uint64 *)global_addr = aux_heap_base;
-            }
-            else
+                if (memory->is_memory64) {
+                    /* For memory64, the global value should be i64 */
+                    *(uint64 *)global_addr = aux_heap_base;
+                }
+                else
 #endif
 #endif
-            {
-                /* For memory32, the global value should be i32 */
-                *(uint32 *)global_addr = (uint32)aux_heap_base;
+                {
+                    /* For memory32, the global value should be i32 */
+                    *(uint32 *)global_addr = (uint32)aux_heap_base;
+                }
+                LOG_VERBOSE("Reset __heap_base global to %" PRIu64,
+                            aux_heap_base);
+            }
+            else {
+                /* Insert app heap before new page */
+                inc_page_count =
+                    (heap_size + num_bytes_per_page - 1) / num_bytes_per_page;
+                heap_offset = (uint64)num_bytes_per_page * init_page_count;
+                heap_size = (uint64)num_bytes_per_page * inc_page_count;
+                if (heap_size > 0)
+                    heap_size -= 1 * BH_KB;
+            }
+            init_page_count += inc_page_count;
+            max_page_count += inc_page_count;
+            if (init_page_count > default_max_page) {
+                set_error_buf(error_buf, error_buf_size,
+                              "failed to insert app heap into linear memory, "
+                              "try using `--heap-size=0` option");
+                return NULL;
             }
             }
-            LOG_VERBOSE("Reset __heap_base global to %" PRIu64, aux_heap_base);
-        }
-        else {
-            /* Insert app heap before new page */
-            inc_page_count =
-                (heap_size + num_bytes_per_page - 1) / num_bytes_per_page;
-            heap_offset = (uint64)num_bytes_per_page * init_page_count;
-            heap_size = (uint64)num_bytes_per_page * inc_page_count;
-            if (heap_size > 0)
-                heap_size -= 1 * BH_KB;
-        }
-        init_page_count += inc_page_count;
-        max_page_count += inc_page_count;
-        if (init_page_count > default_max_page) {
-            set_error_buf(error_buf, error_buf_size,
-                          "failed to insert app heap into linear memory, "
-                          "try using `--heap-size=0` option");
-            return NULL;
-        }
 
 
-        if (max_page_count > default_max_page)
-            max_page_count = default_max_page;
+            if (max_page_count > default_max_page)
+                max_page_count = default_max_page;
+        }
     }
     }
 
 
     LOG_VERBOSE("Memory instantiate:");
     LOG_VERBOSE("Memory instantiate:");
     LOG_VERBOSE("  page bytes: %u, init pages: %u, max pages: %u",
     LOG_VERBOSE("  page bytes: %u, init pages: %u, max pages: %u",
                 num_bytes_per_page, init_page_count, max_page_count);
                 num_bytes_per_page, init_page_count, max_page_count);
-    LOG_VERBOSE("  heap offset: %" PRIu64 ", heap size: %u\n", heap_offset,
-                heap_size);
+    if (memory_idx == 0)
+        LOG_VERBOSE("  heap offset: %" PRIu64 ", heap size: %u\n", heap_offset,
+                    heap_size);
 
 
     max_memory_data_size = (uint64)num_bytes_per_page * max_page_count;
     max_memory_data_size = (uint64)num_bytes_per_page * max_page_count;
     bh_assert(max_memory_data_size
     bh_assert(max_memory_data_size
@@ -326,12 +331,14 @@ memory_instantiate(WASMModuleInstance *module_inst, WASMModuleInstance *parent,
     memory->max_page_count = max_page_count;
     memory->max_page_count = max_page_count;
     memory->memory_data_size = memory_data_size;
     memory->memory_data_size = memory_data_size;
 
 
-    memory->heap_data = memory->memory_data + heap_offset;
-    memory->heap_data_end = memory->heap_data + heap_size;
-    memory->memory_data_end = memory->memory_data + memory_data_size;
+    if (memory_idx == 0) {
+        memory->heap_data = memory->memory_data + heap_offset;
+        memory->heap_data_end = memory->heap_data + heap_size;
+        memory->memory_data_end = memory->memory_data + memory_data_size;
+    }
 
 
     /* Initialize heap */
     /* Initialize heap */
-    if (heap_size > 0) {
+    if (memory_idx == 0 && heap_size > 0) {
         uint32 heap_struct_size = mem_allocator_get_heap_struct_size();
         uint32 heap_struct_size = mem_allocator_get_heap_struct_size();
 
 
         if (!(memory->heap_handle = runtime_malloc(
         if (!(memory->heap_handle = runtime_malloc(
@@ -361,7 +368,7 @@ memory_instantiate(WASMModuleInstance *module_inst, WASMModuleInstance *parent,
     return memory;
     return memory;
 
 
 fail2:
 fail2:
-    if (heap_size > 0)
+    if (memory_idx == 0 && heap_size > 0)
         wasm_runtime_free(memory->heap_handle);
         wasm_runtime_free(memory->heap_handle);
 fail1:
 fail1:
     if (memory->memory_data)
     if (memory->memory_data)
@@ -1351,7 +1358,45 @@ export_globals_instantiate(const WASMModule *module,
     bh_assert((uint32)(export_global - export_globals) == export_glob_count);
     bh_assert((uint32)(export_global - export_globals) == export_glob_count);
     return export_globals;
     return export_globals;
 }
 }
-#endif
+
+#if WASM_ENABLE_MULTI_MEMORY != 0
+static void
+export_memories_deinstantiate(WASMExportMemInstance *memories)
+{
+    if (memories)
+        wasm_runtime_free(memories);
+}
+
+static WASMExportMemInstance *
+export_memories_instantiate(const WASMModule *module,
+                            WASMModuleInstance *module_inst,
+                            uint32 export_mem_count, char *error_buf,
+                            uint32 error_buf_size)
+{
+    WASMExportMemInstance *export_memories, *export_memory;
+    WASMExport *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 */
+
+#endif /* end of if WASM_ENABLE_MULTI_MODULE != 0 */
 
 
 static WASMFunctionInstance *
 static WASMFunctionInstance *
 lookup_post_instantiate_func(WASMModuleInstance *module_inst,
 lookup_post_instantiate_func(WASMModuleInstance *module_inst,
@@ -2387,6 +2432,12 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent,
                      module, module_inst, module_inst->export_global_count,
                      module, module_inst, module_inst->export_global_count,
                      error_buf, error_buf_size)))
                      error_buf, error_buf_size)))
 #endif
 #endif
+#if WASM_ENABLE_MULTI_MODULE != 0 && 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,
+                     error_buf, error_buf_size)))
+#endif
 #if WASM_ENABLE_JIT != 0
 #if WASM_ENABLE_JIT != 0
         || (module_inst->e->function_count > 0
         || (module_inst->e->function_count > 0
             && !init_func_ptrs(module_inst, module, error_buf, error_buf_size))
             && !init_func_ptrs(module_inst, module, error_buf, error_buf_size))
@@ -3189,6 +3240,10 @@ wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst)
     export_globals_deinstantiate(module_inst->export_globals);
     export_globals_deinstantiate(module_inst->export_globals);
 #endif
 #endif
 
 
+#if WASM_ENABLE_MULTI_MODULE != 0 && WASM_ENABLE_MULTI_MEMORY != 0
+    export_memories_deinstantiate(module_inst->export_memories);
+#endif
+
 #if WASM_ENABLE_GC == 0 && WASM_ENABLE_REF_TYPES != 0
 #if WASM_ENABLE_GC == 0 && WASM_ENABLE_REF_TYPES != 0
     wasm_externref_cleanup((WASMModuleInstanceCommon *)module_inst);
     wasm_externref_cleanup((WASMModuleInstanceCommon *)module_inst);
 #endif
 #endif
@@ -3251,12 +3306,16 @@ wasm_lookup_global(const WASMModuleInstance *module_inst, const char *name)
 WASMMemoryInstance *
 WASMMemoryInstance *
 wasm_lookup_memory(const WASMModuleInstance *module_inst, const char *name)
 wasm_lookup_memory(const WASMModuleInstance *module_inst, const char *name)
 {
 {
-    /**
-     * using a strong assumption that one module instance only has
-     * one memory instance
-     */
+#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;
     (void)module_inst->export_memories;
     return module_inst->memories[0];
     return module_inst->memories[0];
+#endif
 }
 }
 
 
 WASMTableInstance *
 WASMTableInstance *

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

@@ -620,9 +620,16 @@ wasm_check_app_addr_and_convert(WASMModuleInstance *module_inst, bool is_str,
 WASMMemoryInstance *
 WASMMemoryInstance *
 wasm_get_default_memory(WASMModuleInstance *module_inst);
 wasm_get_default_memory(WASMModuleInstance *module_inst);
 
 
+WASMMemoryInstance *
+wasm_get_memory_with_idx(WASMModuleInstance *module_inst, uint32 index);
+
 bool
 bool
 wasm_enlarge_memory(WASMModuleInstance *module_inst, uint32 inc_page_count);
 wasm_enlarge_memory(WASMModuleInstance *module_inst, uint32 inc_page_count);
 
 
+bool
+wasm_enlarge_memory_with_idx(WASMModuleInstance *module_inst,
+                             uint32 inc_page_count, uint32 memidx);
+
 bool
 bool
 wasm_call_indirect(WASMExecEnv *exec_env, uint32 tbl_idx, uint32 elem_idx,
 wasm_call_indirect(WASMExecEnv *exec_env, uint32 tbl_idx, uint32 elem_idx,
                    uint32 argc, uint32 argv[]);
                    uint32 argc, uint32 argv[]);

+ 3 - 2
core/shared/platform/include/platform_api_extension.h

@@ -104,8 +104,9 @@ os_thread_exit(void *retval);
 #endif
 #endif
 
 
 /* Clang's __GNUC_PREREQ macro has a different meaning than GCC one,
 /* Clang's __GNUC_PREREQ macro has a different meaning than GCC one,
-   so we have to handle this case specially */
-#if defined(__clang__)
+   so we have to handle this case specially(except the CCAC compiler
+   provided by MetaWare, which doesn't support atomic operations) */
+#if defined(__clang__) && !defined(__CCAC__)
 /* Clang provides stdatomic.h since 3.6.0
 /* Clang provides stdatomic.h since 3.6.0
    See https://releases.llvm.org/3.6.0/tools/clang/docs/ReleaseNotes.html */
    See https://releases.llvm.org/3.6.0/tools/clang/docs/ReleaseNotes.html */
 #if __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 6)
 #if __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 6)

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

@@ -6,6 +6,7 @@
 #ifndef _BH_ATOMIC_H
 #ifndef _BH_ATOMIC_H
 #define _BH_ATOMIC_H
 #define _BH_ATOMIC_H
 
 
+#include "bh_platform.h"
 #include "gnuc.h"
 #include "gnuc.h"
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus

+ 1 - 1
core/version.h

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

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

@@ -14,7 +14,7 @@ import time
 
 
 """
 """
 The script itself has to be put under the same directory with the "spec".
 The script itself has to be put under the same directory with the "spec".
-To run a single non-GC and non-memory64 case with interpreter mode:
+To run a single non-GC case with interpreter mode:
   cd workspace
   cd workspace
   python3 runtest.py --wast2wasm wabt/bin/wat2wasm --interpreter iwasm \
   python3 runtest.py --wast2wasm wabt/bin/wat2wasm --interpreter iwasm \
     spec/test/core/xxx.wast
     spec/test/core/xxx.wast
@@ -22,7 +22,7 @@ To run a single non-GC case with aot mode:
   cd workspace
   cd workspace
   python3 runtest.py --aot --wast2wasm wabt/bin/wat2wasm --interpreter iwasm \
   python3 runtest.py --aot --wast2wasm wabt/bin/wat2wasm --interpreter iwasm \
     --aot-compiler wamrc spec/test/core/xxx.wast
     --aot-compiler wamrc spec/test/core/xxx.wast
-To run a single GC case or single memory64 case:
+To run a single GC case case:
   cd workspace
   cd workspace
   python3 runtest.py --wast2wasm spec/interpreter/wasm --interpreter iwasm \
   python3 runtest.py --wast2wasm spec/interpreter/wasm --interpreter iwasm \
     --aot-compiler wamrc --gc spec/test/core/xxx.wast
     --aot-compiler wamrc --gc spec/test/core/xxx.wast
@@ -79,6 +79,7 @@ def ignore_the_case(
     simd_flag=False,
     simd_flag=False,
     gc_flag=False,
     gc_flag=False,
     memory64_flag=False,
     memory64_flag=False,
+    multi_memory_flag=False,
     xip_flag=False,
     xip_flag=False,
     eh_flag=False,
     eh_flag=False,
     qemu_flag=False,
     qemu_flag=False,
@@ -165,6 +166,7 @@ def test_case(
     verbose_flag=True,
     verbose_flag=True,
     gc_flag=False,
     gc_flag=False,
     memory64_flag=False,
     memory64_flag=False,
+    multi_memory_flag=False,
     qemu_flag=False,
     qemu_flag=False,
     qemu_firmware="",
     qemu_firmware="",
     log="",
     log="",
@@ -223,6 +225,9 @@ def test_case(
     if memory64_flag:
     if memory64_flag:
         CMD.append("--memory64")
         CMD.append("--memory64")
 
 
+    if multi_memory_flag:
+        CMD.append("--multi-memory")
+
     if log != "":
     if log != "":
         CMD.append("--log-dir")
         CMD.append("--log-dir")
         CMD.append(log)
         CMD.append(log)
@@ -291,6 +296,7 @@ def test_suite(
     verbose_flag=True,
     verbose_flag=True,
     gc_flag=False,
     gc_flag=False,
     memory64_flag=False,
     memory64_flag=False,
+    multi_memory_flag=False,
     parl_flag=False,
     parl_flag=False,
     qemu_flag=False,
     qemu_flag=False,
     qemu_firmware="",
     qemu_firmware="",
@@ -316,6 +322,10 @@ def test_suite(
         eh_case_list_include = [test for test in eh_case_list if test.stem in ["throw", "tag", "try_catch", "rethrow", "try_delegate"]]
         eh_case_list_include = [test for test in eh_case_list if test.stem in ["throw", "tag", "try_catch", "rethrow", "try_delegate"]]
         case_list.extend(eh_case_list_include)
         case_list.extend(eh_case_list_include)
 
 
+    if multi_memory_flag:
+        multi_memory_list = sorted(suite_path.glob("multi-memory/*.wast"))
+        case_list.extend(multi_memory_list)
+
     # ignore based on command line options
     # ignore based on command line options
     filtered_case_list = []
     filtered_case_list = []
     for case_path in case_list:
     for case_path in case_list:
@@ -330,6 +340,7 @@ def test_suite(
             simd_flag,
             simd_flag,
             gc_flag,
             gc_flag,
             memory64_flag,
             memory64_flag,
+            multi_memory_flag,
             xip_flag,
             xip_flag,
             eh_flag,
             eh_flag,
             qemu_flag,
             qemu_flag,
@@ -366,6 +377,7 @@ def test_suite(
                         verbose_flag,
                         verbose_flag,
                         gc_flag,
                         gc_flag,
                         memory64_flag,
                         memory64_flag,
+                        multi_memory_flag,
                         qemu_flag,
                         qemu_flag,
                         qemu_firmware,
                         qemu_firmware,
                         log,
                         log,
@@ -408,6 +420,7 @@ def test_suite(
                     verbose_flag,
                     verbose_flag,
                     gc_flag,
                     gc_flag,
                     memory64_flag,
                     memory64_flag,
+                    multi_memory_flag,
                     qemu_flag,
                     qemu_flag,
                     qemu_firmware,
                     qemu_firmware,
                     log,
                     log,
@@ -546,6 +559,13 @@ def main():
         dest="memory64_flag",
         dest="memory64_flag",
         help="Running with memory64 feature",
         help="Running with memory64 feature",
     )
     )
+    parser.add_argument(
+        "--multi-memory",
+        action="store_true",
+        default=False,
+        dest="multi_memory_flag",
+        help="Running with multi-memory feature",
+    )
     parser.add_argument(
     parser.add_argument(
         "cases",
         "cases",
         metavar="path_to__case",
         metavar="path_to__case",
@@ -591,6 +611,7 @@ def main():
             options.verbose_flag,
             options.verbose_flag,
             options.gc_flag,
             options.gc_flag,
             options.memory64_flag,
             options.memory64_flag,
+            options.multi_memory_flag,
             options.parl_flag,
             options.parl_flag,
             options.qemu_flag,
             options.qemu_flag,
             options.qemu_firmware,
             options.qemu_firmware,
@@ -619,6 +640,7 @@ def main():
                     options.verbose_flag,
                     options.verbose_flag,
                     options.gc_flag,
                     options.gc_flag,
                     options.memory64_flag,
                     options.memory64_flag,
+                    options.multi_memory_flag,
                     options.qemu_flag,
                     options.qemu_flag,
                     options.qemu_firmware,
                     options.qemu_firmware,
                     options.log,
                     options.log,

+ 1022 - 0
tests/wamr-test-suites/spec-test-script/multi_memory_ignore_cases.patch

@@ -0,0 +1,1022 @@
+diff --git a/test/core/elem.wast b/test/core/elem.wast
+index 575ecef8..6eecab93 100644
+--- a/test/core/elem.wast
++++ b/test/core/elem.wast
+@@ -571,9 +571,11 @@
+   (func $const-i32-d (type $out-i32) (i32.const 68))
+ )
+ 
++(;
+ (assert_return (invoke $module1 "call-7") (i32.const 67))
+ (assert_return (invoke $module1 "call-8") (i32.const 68))
+ (assert_return (invoke $module1 "call-9") (i32.const 66))
++;)
+ 
+ (module $module3
+   (type $out-i32 (func (result i32)))
+@@ -584,6 +586,8 @@
+   (func $const-i32-f (type $out-i32) (i32.const 70))
+ )
+ 
++(;
+ (assert_return (invoke $module1 "call-7") (i32.const 67))
+ (assert_return (invoke $module1 "call-8") (i32.const 69))
+ (assert_return (invoke $module1 "call-9") (i32.const 70))
++;)
+diff --git a/test/core/imports.wast b/test/core/imports.wast
+index 94c1af5c..bb1704fc 100644
+--- a/test/core/imports.wast
++++ b/test/core/imports.wast
+@@ -86,7 +86,7 @@
+ (assert_return (invoke "print64" (i64.const 24)))
+ 
+ (assert_invalid
+-  (module 
++  (module
+     (type (func (result i32)))
+     (import "test" "func" (func (type 1)))
+   )
+@@ -559,6 +559,7 @@
+ (assert_return (invoke "grow" (i32.const 1)) (i32.const -1))
+ (assert_return (invoke "grow" (i32.const 0)) (i32.const 2))
+ 
++(;
+ (module $Mgm
+   (memory (export "memory") 1) ;; initial size is 1
+   (func (export "grow") (result i32) (memory.grow (i32.const 1)))
+@@ -567,7 +568,7 @@
+ (assert_return (invoke $Mgm "grow") (i32.const 1)) ;; now size is 2
+ (module $Mgim1
+   ;; imported memory limits should match, because external memory size is 2 now
+-  (memory (export "memory") (import "grown-memory" "memory") 2) 
++  (memory (export "memory") (import "grown-memory" "memory") 2)
+   (func (export "grow") (result i32) (memory.grow (i32.const 1)))
+ )
+ (register "grown-imported-memory" $Mgim1)
+@@ -578,7 +579,7 @@
+   (func (export "size") (result i32) (memory.size))
+ )
+ (assert_return (invoke $Mgim2 "size") (i32.const 3))
+-
++;)
+ 
+ ;; Syntax errors
+ 
+@@ -650,6 +651,7 @@
+   "import after memory"
+ )
+ 
++(;
+ ;; This module is required to validate, regardless of whether it can be
+ ;; linked. Overloading is not possible in wasm itself, but it is possible
+ ;; in modules from which wasm can import.
+@@ -676,3 +678,4 @@
+   )
+   "unknown import"
+ )
++;)
+\ No newline at end of file
+diff --git a/test/core/linking.wast b/test/core/linking.wast
+index 994e0f49..8fbcc021 100644
+--- a/test/core/linking.wast
++++ b/test/core/linking.wast
+@@ -19,11 +19,11 @@
+ (assert_return (invoke $Nf "call") (i32.const 3))
+ (assert_return (invoke $Nf "call Mf.call") (i32.const 2))
+ 
+-(module
++(module $M1
+   (import "spectest" "print_i32" (func $f (param i32)))
+   (export "print" (func $f))
+ )
+-(register "reexport_f")
++(register "reexport_f" $M1)
+ (assert_unlinkable
+   (module (import "reexport_f" "print" (func (param i64))))
+   "incompatible import type"
+@@ -35,7 +35,6 @@
+ 
+ 
+ ;; Globals
+-
+ (module $Mg
+   (global $glob (export "glob") i32 (i32.const 42))
+   (func (export "get") (result i32) (global.get $glob))
+@@ -47,6 +46,7 @@
+ )
+ (register "Mg" $Mg)
+ 
++(; only sharing initial values
+ (module $Ng
+   (global $x (import "Mg" "glob") i32)
+   (global $mut_glob (import "Mg" "mut_glob") (mut i32))
+@@ -81,7 +81,7 @@
+ (assert_return (get $Ng "Mg.mut_glob") (i32.const 241))
+ (assert_return (invoke $Mg "get_mut") (i32.const 241))
+ (assert_return (invoke $Ng "Mg.get_mut") (i32.const 241))
+-
++;)
+ 
+ (assert_unlinkable
+   (module (import "Mg" "mut_glob" (global i32)))
+@@ -130,7 +130,7 @@
+ 
+ 
+ ;; Tables
+-
++(; no such support
+ (module $Mt
+   (type (func (result i32)))
+   (type (func))
+@@ -307,10 +307,11 @@
+   (module (table (import "Mtable_ex" "t-extern") 1 funcref))
+   "incompatible import type"
+ )
++;)
+ 
+ 
+ ;; Memories
+-
++(; no such support
+ (module $Mm
+   (memory (export "mem") 1 5)
+   (data (i32.const 10) "\00\01\02\03\04\05\06\07\08\09")
+@@ -451,3 +452,4 @@
+ 
+ (assert_return (invoke $Ms "get memory[0]") (i32.const 104))  ;; 'h'
+ (assert_return (invoke $Ms "get table[0]") (i32.const 0xdead))
++;)
+\ No newline at end of file
+diff --git a/test/core/load.wast b/test/core/load.wast
+index 9fe48e2b..3e9c2f8c 100644
+--- a/test/core/load.wast
++++ b/test/core/load.wast
+@@ -29,6 +29,8 @@
+ (register "M")
+ 
+ (module
++  (func $readM1 (import "M" "read") (param i32) (result i32))
++  (export "readM1" (func $readM1))
+   (memory $mem1 (import "M" "mem") 2)
+   (memory $mem2 3)
+ 
+@@ -43,11 +45,12 @@
+   )
+ )
+ 
+-(assert_return (invoke $M "read" (i32.const 20)) (i32.const 1))
+-(assert_return (invoke $M "read" (i32.const 21)) (i32.const 2))
+-(assert_return (invoke $M "read" (i32.const 22)) (i32.const 3))
+-(assert_return (invoke $M "read" (i32.const 23)) (i32.const 4))
+-(assert_return (invoke $M "read" (i32.const 24)) (i32.const 5))
++;; To invoke the function in M as a submodule, not as an independent module
++(assert_return (invoke "readM1" (i32.const 20)) (i32.const 1))
++(assert_return (invoke "readM1" (i32.const 21)) (i32.const 2))
++(assert_return (invoke "readM1" (i32.const 22)) (i32.const 3))
++(assert_return (invoke "readM1" (i32.const 23)) (i32.const 4))
++(assert_return (invoke "readM1" (i32.const 24)) (i32.const 5))
+ 
+ (assert_return (invoke "read1" (i32.const 20)) (i32.const 1))
+ (assert_return (invoke "read1" (i32.const 21)) (i32.const 2))
+diff --git a/test/core/memory_grow.wast b/test/core/memory_grow.wast
+index 4b6dbc83..dc46c029 100644
+--- a/test/core/memory_grow.wast
++++ b/test/core/memory_grow.wast
+@@ -106,15 +106,15 @@
+ 
+ ;; Multiple memories
+ 
+-(module
++(module $MemroygrowM
+   (memory (export "mem1") 2 5)
+   (memory (export "mem2") 0)
+ )
+-(register "M")
++(register "MemroygrowM" $MemorygrowM)
+ 
+ (module
+-  (memory $mem1 (import "M" "mem1") 1 6)
+-  (memory $mem2 (import "M" "mem2") 0)
++  (memory $mem1 (import "MemroygrowM" "mem1") 1 6)
++  (memory $mem2 (import "MemroygrowM" "mem2") 0)
+   (memory $mem3 3)
+   (memory $mem4 4 5)
+ 
+diff --git a/test/core/memory_size.wast b/test/core/memory_size.wast
+index a1d6ea2d..b58c75d0 100644
+--- a/test/core/memory_size.wast
++++ b/test/core/memory_size.wast
+@@ -65,15 +65,15 @@
+ 
+ ;; Multiple memories
+ 
+-(module
++(module $MemmorysizeM
+   (memory (export "mem1") 2 4)
+   (memory (export "mem2") 0)
+ )
+-(register "M")
++(register "MemmorysizeM" $MemmorysizeM)
+ 
+ (module
+-  (memory $mem1 (import "M" "mem1") 1 5)
+-  (memory $mem2 (import "M" "mem2") 0)
++  (memory $mem1 (import "MemmorysizeM" "mem1") 1 5)
++  (memory $mem2 (import "MemmorysizeM" "mem2") 0)
+   (memory $mem3 3)
+   (memory $mem4 4 5)
+ 
+diff --git a/test/core/multi-memory/imports2.wast b/test/core/multi-memory/imports2.wast
+index 314bc131..e1060599 100644
+--- a/test/core/multi-memory/imports2.wast
++++ b/test/core/multi-memory/imports2.wast
+@@ -1,13 +1,13 @@
+-(module
++(module $imports2test
+   (memory (export "z") 0 0)
+   (memory (export "memory-2-inf") 2)
+   (memory (export "memory-2-4") 2 4)
+ )
+ 
+-(register "test")
++(register "imports2test" $imports2test)
+ 
+ (module
+-  (import "test" "z" (memory 0))
++  (import "imports2test" "z" (memory 0))
+   (memory $m (import "spectest" "memory") 1 2)
+   (data (memory 1) (i32.const 10) "\10")
+ 
+@@ -31,9 +31,9 @@
+ (assert_trap (invoke "load" (i32.const 1000000)) "out of bounds memory access")
+ 
+ (module
+-  (import "test" "memory-2-inf" (memory 2))
+-  (import "test" "memory-2-inf" (memory 1))
+-  (import "test" "memory-2-inf" (memory 0))
++  (import "imports2test" "memory-2-inf" (memory 2))
++  (import "imports2test" "memory-2-inf" (memory 1))
++  (import "imports2test" "memory-2-inf" (memory 0))
+ )
+ 
+ (module
+@@ -46,7 +46,7 @@
+ )
+ 
+ (assert_unlinkable
+-  (module (import "test" "unknown" (memory 1)))
++  (module (import "imports2test" "unknown" (memory 1)))
+   "unknown import"
+ )
+ (assert_unlinkable
+@@ -55,11 +55,11 @@
+ )
+ 
+ (assert_unlinkable
+-  (module (import "test" "memory-2-inf" (memory 3)))
++  (module (import "imports2test" "memory-2-inf" (memory 3)))
+   "incompatible import type"
+ )
+ (assert_unlinkable
+-  (module (import "test" "memory-2-inf" (memory 2 3)))
++  (module (import "imports2test" "memory-2-inf" (memory 2 3)))
+   "incompatible import type"
+ )
+ (assert_unlinkable
+diff --git a/test/core/multi-memory/imports4.wast b/test/core/multi-memory/imports4.wast
+index 411b1c0f..0a819454 100644
+--- a/test/core/multi-memory/imports4.wast
++++ b/test/core/multi-memory/imports4.wast
+@@ -1,12 +1,12 @@
+-(module
++(module $imports4test
+   (memory (export "memory-2-inf") 2)
+   (memory (export "memory-2-4") 2 4)
+ )
+ 
+-(register "test")
++(register "imports4test")
+ 
+ (module
+-  (import "test" "memory-2-4" (memory 1))
++  (import "imports4test" "memory-2-4" (memory 1))
+   (memory $m (import "spectest" "memory") 0 3)  ;; actual has max size 2
+   (func (export "grow") (param i32) (result i32) (memory.grow $m (local.get 0)))
+ )
+@@ -16,6 +16,8 @@
+ (assert_return (invoke "grow" (i32.const 1)) (i32.const -1))
+ (assert_return (invoke "grow" (i32.const 0)) (i32.const 2))
+ 
++;; TODO: Current implementation call grow on one submodule instance can't really change its definition
++(;
+ (module $Mgm
+   (memory 0)
+   (memory 0)
+@@ -45,3 +47,4 @@
+   (func (export "size") (result i32) (memory.size $m))
+ )
+ (assert_return (invoke $Mgim2 "size") (i32.const 3))
++;)
+\ No newline at end of file
+diff --git a/test/core/multi-memory/linking0.wast b/test/core/multi-memory/linking0.wast
+index b09c69f6..d57d484e 100644
+--- a/test/core/multi-memory/linking0.wast
++++ b/test/core/multi-memory/linking0.wast
+@@ -24,8 +24,8 @@
+   )
+   "unknown import"
+ )
+-(assert_trap (invoke $Mt "call" (i32.const 7)) "uninitialized element")
+-
++;; can't call function in submodule when module can't be instantiated
++;; (assert_trap (invoke "call" (i32.const 7)) "uninitialized element")
+ 
+ (assert_trap
+   (module
+@@ -39,4 +39,5 @@
+   )
+   "out of bounds memory access"
+ )
+-(assert_return (invoke $Mt "call" (i32.const 7)) (i32.const 0))
++;; can't call function in submodule when module can't be instantiated
++;; (assert_return (invoke "call" (i32.const 7)) (i32.const 0))
+diff --git a/test/core/multi-memory/linking1.wast b/test/core/multi-memory/linking1.wast
+index 39eabb00..49c87ce8 100644
+--- a/test/core/multi-memory/linking1.wast
++++ b/test/core/multi-memory/linking1.wast
+@@ -1,4 +1,4 @@
+-(module $Mm
++(module $linking1Mm
+   (memory $mem0 (export "mem0") 0 0)
+   (memory $mem1 (export "mem1") 1 5)
+   (memory $mem2 (export "mem2") 0 0)
+@@ -9,11 +9,11 @@
+     (i32.load8_u $mem1 (local.get 0))
+   )
+ )
+-(register "Mm" $Mm)
++(register "linking1Mm" $linking1Mm)
+ 
+-(module $Nm
+-  (func $loadM (import "Mm" "load") (param i32) (result i32))
+-  (memory (import "Mm" "mem0") 0)
++(module $linking1Nm
++  (func $loadM (import "linking1Mm" "load") (param i32) (result i32))
++  (memory (import "linking1Mm" "mem0") 0)
+ 
+   (memory $m 1)
+   (data (memory 1) (i32.const 10) "\f0\f1\f2\f3\f4\f5")
+@@ -24,12 +24,14 @@
+   )
+ )
+ 
+-(assert_return (invoke $Mm "load" (i32.const 12)) (i32.const 2))
+-(assert_return (invoke $Nm "Mm.load" (i32.const 12)) (i32.const 2))
+-(assert_return (invoke $Nm "load" (i32.const 12)) (i32.const 0xf2))
++(assert_return (invoke $linking1Mm "load" (i32.const 12)) (i32.const 2))
++(assert_return (invoke $linking1Nm "Mm.load" (i32.const 12)) (i32.const 2))
++(assert_return (invoke $linking1Nm "load" (i32.const 12)) (i32.const 0xf2))
+ 
+-(module $Om
+-  (memory (import "Mm" "mem1") 1)
++(module $linking1Om
++  (func $loadM (import "linking1Mm" "load") (param i32) (result i32))
++  (export "Mm.load" (func $loadM))
++  (memory (import "linking1Mm" "mem1") 1)
+   (data (i32.const 5) "\a0\a1\a2\a3\a4\a5\a6\a7")
+ 
+   (func (export "load") (param $a i32) (result i32)
+@@ -37,19 +39,20 @@
+   )
+ )
+ 
+-(assert_return (invoke $Mm "load" (i32.const 12)) (i32.const 0xa7))
+-(assert_return (invoke $Nm "Mm.load" (i32.const 12)) (i32.const 0xa7))
+-(assert_return (invoke $Nm "load" (i32.const 12)) (i32.const 0xf2))
+-(assert_return (invoke $Om "load" (i32.const 12)) (i32.const 0xa7))
++;; To invoke the function in Mm as a submodule, not as an independent module
++(assert_return (invoke $linking1Om "Mm.load" (i32.const 12)) (i32.const 0xa7))
++;; (assert_return (invoke $Nm "Mm.load" (i32.const 12)) (i32.const 0xa7))
++;; (assert_return (invoke $Nm "load" (i32.const 12)) (i32.const 0xf2))
++(assert_return (invoke $linking1Om "load" (i32.const 12)) (i32.const 0xa7))
+ 
+ (module
+-  (memory (import "Mm" "mem1") 0)
++  (memory (import "linking1Mm" "mem1") 0)
+   (data (i32.const 0xffff) "a")
+ )
+ 
+ (assert_trap
+   (module
+-    (memory (import "Mm" "mem0") 0)
++    (memory (import "linking1Mm" "mem0") 0)
+     (data (i32.const 0xffff) "a")
+   )
+   "out of bounds memory access"
+@@ -57,7 +60,7 @@
+ 
+ (assert_trap
+   (module
+-    (memory (import "Mm" "mem1") 0)
++    (memory (import "linking1Mm" "mem1") 0)
+     (data (i32.const 0x10000) "a")
+   )
+   "out of bounds memory access"
+diff --git a/test/core/multi-memory/linking2.wast b/test/core/multi-memory/linking2.wast
+index 26bf3cca..5eae4643 100644
+--- a/test/core/multi-memory/linking2.wast
++++ b/test/core/multi-memory/linking2.wast
+@@ -1,4 +1,4 @@
+-(module $Mm
++(module $linking2Mm
+   (memory $mem0 (export "mem0") 0 0)
+   (memory $mem1 (export "mem1") 1 5)
+   (memory $mem2 (export "mem2") 0 0)
+@@ -9,22 +9,22 @@
+     (i32.load8_u $mem1 (local.get 0))
+   )
+ )
+-(register "Mm" $Mm)
++(register "linking2Mm" $linking2Mm)
+ 
+-(module $Pm
+-  (memory (import "Mm" "mem1") 1 8)
++(module
++  (memory (import "linking2Mm" "mem1") 1 8)
+ 
+   (func (export "grow") (param $a i32) (result i32)
+     (memory.grow (local.get 0))
+   )
+ )
+ 
+-(assert_return (invoke $Pm "grow" (i32.const 0)) (i32.const 1))
+-(assert_return (invoke $Pm "grow" (i32.const 2)) (i32.const 1))
+-(assert_return (invoke $Pm "grow" (i32.const 0)) (i32.const 3))
+-(assert_return (invoke $Pm "grow" (i32.const 1)) (i32.const 3))
+-(assert_return (invoke $Pm "grow" (i32.const 1)) (i32.const 4))
+-(assert_return (invoke $Pm "grow" (i32.const 0)) (i32.const 5))
+-(assert_return (invoke $Pm "grow" (i32.const 1)) (i32.const -1))
+-(assert_return (invoke $Pm "grow" (i32.const 0)) (i32.const 5))
++(assert_return (invoke "grow" (i32.const 0)) (i32.const 1))
++(assert_return (invoke "grow" (i32.const 2)) (i32.const 1))
++(assert_return (invoke "grow" (i32.const 0)) (i32.const 3))
++(assert_return (invoke "grow" (i32.const 1)) (i32.const 3))
++(assert_return (invoke "grow" (i32.const 1)) (i32.const 4))
++(assert_return (invoke "grow" (i32.const 0)) (i32.const 5))
++(assert_return (invoke "grow" (i32.const 1)) (i32.const -1))
++(assert_return (invoke "grow" (i32.const 0)) (i32.const 5))
+ 
+diff --git a/test/core/multi-memory/linking3.wast b/test/core/multi-memory/linking3.wast
+index e23fbe4e..d3efe95a 100644
+--- a/test/core/multi-memory/linking3.wast
++++ b/test/core/multi-memory/linking3.wast
+@@ -33,8 +33,9 @@
+   )
+   "out of bounds memory access"
+ )
+-(assert_return (invoke $Mm "load" (i32.const 0)) (i32.const 97))
+-(assert_return (invoke $Mm "load" (i32.const 327670)) (i32.const 0))
++;; can't call function in submodule when module can't be instantiated
++;; (assert_return (invoke $Mm "load" (i32.const 0)) (i32.const 97))
++;; (assert_return (invoke $Mm "load" (i32.const 327670)) (i32.const 0))
+ 
+ (assert_trap
+   (module
+@@ -46,7 +47,8 @@
+   )
+   "out of bounds table access"
+ )
+-(assert_return (invoke $Mm "load" (i32.const 0)) (i32.const 97))
++;; can't call function in submodule when module can't be instantiated
++;; (assert_return (invoke $Mm "load" (i32.const 0)) (i32.const 97))
+ 
+ ;; Store is modified if the start function traps.
+ (module $Ms
+@@ -79,5 +81,6 @@
+   "unreachable"
+ )
+ 
+-(assert_return (invoke $Ms "get memory[0]") (i32.const 104))  ;; 'h'
+-(assert_return (invoke $Ms "get table[0]") (i32.const 0xdead))
++;; can't call function in submodule when module can't be instantiated
++;; (assert_return (invoke $Ms "get memory[0]") (i32.const 104))  ;; 'h'
++;; (assert_return (invoke $Ms "get table[0]") (i32.const 0xdead))
+diff --git a/test/core/multi-memory/load1.wast b/test/core/multi-memory/load1.wast
+index be309c39..6a0faf0d 100644
+--- a/test/core/multi-memory/load1.wast
++++ b/test/core/multi-memory/load1.wast
+@@ -8,6 +8,8 @@
+ (register "M")
+ 
+ (module
++  (func $readM1 (import "M" "read") (param i32) (result i32))
++  (export "readM1" (func $readM1))
+   (memory $mem1 (import "M" "mem") 2)
+   (memory $mem2 3)
+ 
+@@ -22,11 +24,12 @@
+   )
+ )
+ 
+-(assert_return (invoke $M "read" (i32.const 20)) (i32.const 1))
+-(assert_return (invoke $M "read" (i32.const 21)) (i32.const 2))
+-(assert_return (invoke $M "read" (i32.const 22)) (i32.const 3))
+-(assert_return (invoke $M "read" (i32.const 23)) (i32.const 4))
+-(assert_return (invoke $M "read" (i32.const 24)) (i32.const 5))
++;; To invoke the function in M as a submodule, not as an independent module
++(assert_return (invoke "readM1" (i32.const 20)) (i32.const 1))
++(assert_return (invoke "readM1" (i32.const 21)) (i32.const 2))
++(assert_return (invoke "readM1" (i32.const 22)) (i32.const 3))
++(assert_return (invoke "readM1" (i32.const 23)) (i32.const 4))
++(assert_return (invoke "readM1" (i32.const 24)) (i32.const 5))
+ 
+ (assert_return (invoke "read1" (i32.const 20)) (i32.const 1))
+ (assert_return (invoke "read1" (i32.const 21)) (i32.const 2))
+diff --git a/test/core/multi-memory/store1.wast b/test/core/multi-memory/store1.wast
+index 10cf2c42..eafe6cc9 100644
+--- a/test/core/multi-memory/store1.wast
++++ b/test/core/multi-memory/store1.wast
+@@ -10,6 +10,9 @@
+ )
+ (register "M1")
+ 
++(invoke "store" (i32.const 0) (i64.const 1))
++(assert_return (invoke "load" (i32.const 0)) (i64.const 1))
++
+ (module $M2
+   (memory (export "mem") 1)
+ 
+@@ -22,10 +25,8 @@
+ )
+ (register "M2")
+ 
+-(invoke $M1 "store" (i32.const 0) (i64.const 1))
+-(invoke $M2 "store" (i32.const 0) (i64.const 2))
+-(assert_return (invoke $M1 "load" (i32.const 0)) (i64.const 1))
+-(assert_return (invoke $M2 "load" (i32.const 0)) (i64.const 2))
++(invoke "store" (i32.const 0) (i64.const 2))
++(assert_return (invoke "load" (i32.const 0)) (i64.const 2))
+ 
+ (module
+   (memory $mem1 (import "M1" "mem") 1)
+diff --git a/test/core/ref_func.wast b/test/core/ref_func.wast
+index adb5cb78..6396013b 100644
+--- a/test/core/ref_func.wast
++++ b/test/core/ref_func.wast
+@@ -4,7 +4,7 @@
+ (register "M")
+ 
+ (module
+-  (func $f (import "M" "f") (param i32) (result i32))
++  (func $f (param $x i32) (result i32) (local.get $x))
+   (func $g (param $x i32) (result i32)
+     (i32.add (local.get $x) (i32.const 1))
+   )
+diff --git a/test/core/store.wast b/test/core/store.wast
+index 86f6263a..65a0d4ee 100644
+--- a/test/core/store.wast
++++ b/test/core/store.wast
+@@ -35,7 +35,10 @@
+     (i64.store (local.get 0) (local.get 1))
+   )
+ )
+-(register "M1")
++(register "M1" $M1)
++
++(invoke "store" (i32.const 0) (i64.const 1))
++(assert_return (invoke "load" (i32.const 0)) (i64.const 1))
+ 
+ (module $M2
+   (memory (export "mem") 1)
+@@ -47,12 +50,10 @@
+     (i64.store (local.get 0) (local.get 1))
+   )
+ )
+-(register "M2")
++(register "M2" $M2)
+ 
+-(invoke $M1 "store" (i32.const 0) (i64.const 1))
+-(invoke $M2 "store" (i32.const 0) (i64.const 2))
+-(assert_return (invoke $M1 "load" (i32.const 0)) (i64.const 1))
+-(assert_return (invoke $M2 "load" (i32.const 0)) (i64.const 2))
++(invoke "store" (i32.const 0) (i64.const 2))
++(assert_return (invoke "load" (i32.const 0)) (i64.const 2))
+ 
+ (module
+   (memory $mem1 (import "M1" "mem") 1)
+diff --git a/test/core/table_copy.wast b/test/core/table_copy.wast
+index 380e84ee..59230cfb 100644
+--- a/test/core/table_copy.wast
++++ b/test/core/table_copy.wast
+@@ -14,11 +14,11 @@
+ 
+ (module
+   (type (func (result i32)))  ;; type #0
+-  (import "a" "ef0" (func (result i32)))    ;; index 0
+-  (import "a" "ef1" (func (result i32)))
+-  (import "a" "ef2" (func (result i32)))
+-  (import "a" "ef3" (func (result i32)))
+-  (import "a" "ef4" (func (result i32)))    ;; index 4
++  (func (result i32) (i32.const 0))    ;; index 0
++  (func (result i32) (i32.const 1))
++  (func (result i32) (i32.const 2))
++  (func (result i32) (i32.const 3))
++  (func (result i32) (i32.const 4))    ;; index 4
+   (table $t0 30 30 funcref)
+   (table $t1 30 30 funcref)
+   (elem (table $t0) (i32.const 2) func 3 1 4 1)
+@@ -106,11 +106,11 @@
+ 
+ (module
+   (type (func (result i32)))  ;; type #0
+-  (import "a" "ef0" (func (result i32)))    ;; index 0
+-  (import "a" "ef1" (func (result i32)))
+-  (import "a" "ef2" (func (result i32)))
+-  (import "a" "ef3" (func (result i32)))
+-  (import "a" "ef4" (func (result i32)))    ;; index 4
++  (func (result i32) (i32.const 0))    ;; index 0
++  (func (result i32) (i32.const 1))
++  (func (result i32) (i32.const 2))
++  (func (result i32) (i32.const 3))
++  (func (result i32) (i32.const 4))    ;; index 4
+   (table $t0 30 30 funcref)
+   (table $t1 30 30 funcref)
+   (elem (table $t0) (i32.const 2) func 3 1 4 1)
+@@ -198,11 +198,11 @@
+ 
+ (module
+   (type (func (result i32)))  ;; type #0
+-  (import "a" "ef0" (func (result i32)))    ;; index 0
+-  (import "a" "ef1" (func (result i32)))
+-  (import "a" "ef2" (func (result i32)))
+-  (import "a" "ef3" (func (result i32)))
+-  (import "a" "ef4" (func (result i32)))    ;; index 4
++  (func (result i32) (i32.const 0))    ;; index 0
++  (func (result i32) (i32.const 1))
++  (func (result i32) (i32.const 2))
++  (func (result i32) (i32.const 3))
++  (func (result i32) (i32.const 4))    ;; index 4
+   (table $t0 30 30 funcref)
+   (table $t1 30 30 funcref)
+   (elem (table $t0) (i32.const 2) func 3 1 4 1)
+@@ -290,11 +290,11 @@
+ 
+ (module
+   (type (func (result i32)))  ;; type #0
+-  (import "a" "ef0" (func (result i32)))    ;; index 0
+-  (import "a" "ef1" (func (result i32)))
+-  (import "a" "ef2" (func (result i32)))
+-  (import "a" "ef3" (func (result i32)))
+-  (import "a" "ef4" (func (result i32)))    ;; index 4
++  (func (result i32) (i32.const 0))    ;; index 0
++  (func (result i32) (i32.const 1))
++  (func (result i32) (i32.const 2))
++  (func (result i32) (i32.const 3))
++  (func (result i32) (i32.const 4))    ;; index 4
+   (table $t0 30 30 funcref)
+   (table $t1 30 30 funcref)
+   (elem (table $t0) (i32.const 2) func 3 1 4 1)
+@@ -382,11 +382,11 @@
+ 
+ (module
+   (type (func (result i32)))  ;; type #0
+-  (import "a" "ef0" (func (result i32)))    ;; index 0
+-  (import "a" "ef1" (func (result i32)))
+-  (import "a" "ef2" (func (result i32)))
+-  (import "a" "ef3" (func (result i32)))
+-  (import "a" "ef4" (func (result i32)))    ;; index 4
++  (func (result i32) (i32.const 0))    ;; index 0
++  (func (result i32) (i32.const 1))
++  (func (result i32) (i32.const 2))
++  (func (result i32) (i32.const 3))
++  (func (result i32) (i32.const 4))    ;; index 4
+   (table $t0 30 30 funcref)
+   (table $t1 30 30 funcref)
+   (elem (table $t0) (i32.const 2) func 3 1 4 1)
+@@ -474,11 +474,11 @@
+ 
+ (module
+   (type (func (result i32)))  ;; type #0
+-  (import "a" "ef0" (func (result i32)))    ;; index 0
+-  (import "a" "ef1" (func (result i32)))
+-  (import "a" "ef2" (func (result i32)))
+-  (import "a" "ef3" (func (result i32)))
+-  (import "a" "ef4" (func (result i32)))    ;; index 4
++  (func (result i32) (i32.const 0))    ;; index 0
++  (func (result i32) (i32.const 1))
++  (func (result i32) (i32.const 2))
++  (func (result i32) (i32.const 3))
++  (func (result i32) (i32.const 4))    ;; index 4
+   (table $t0 30 30 funcref)
+   (table $t1 30 30 funcref)
+   (elem (table $t0) (i32.const 2) func 3 1 4 1)
+@@ -566,11 +566,11 @@
+ 
+ (module
+   (type (func (result i32)))  ;; type #0
+-  (import "a" "ef0" (func (result i32)))    ;; index 0
+-  (import "a" "ef1" (func (result i32)))
+-  (import "a" "ef2" (func (result i32)))
+-  (import "a" "ef3" (func (result i32)))
+-  (import "a" "ef4" (func (result i32)))    ;; index 4
++  (func (result i32) (i32.const 0))    ;; index 0
++  (func (result i32) (i32.const 1))
++  (func (result i32) (i32.const 2))
++  (func (result i32) (i32.const 3))
++  (func (result i32) (i32.const 4))    ;; index 4
+   (table $t0 30 30 funcref)
+   (table $t1 30 30 funcref)
+   (elem (table $t0) (i32.const 2) func 3 1 4 1)
+@@ -658,11 +658,11 @@
+ 
+ (module
+   (type (func (result i32)))  ;; type #0
+-  (import "a" "ef0" (func (result i32)))    ;; index 0
+-  (import "a" "ef1" (func (result i32)))
+-  (import "a" "ef2" (func (result i32)))
+-  (import "a" "ef3" (func (result i32)))
+-  (import "a" "ef4" (func (result i32)))    ;; index 4
++  (func (result i32) (i32.const 0))    ;; index 0
++  (func (result i32) (i32.const 1))
++  (func (result i32) (i32.const 2))
++  (func (result i32) (i32.const 3))
++  (func (result i32) (i32.const 4))    ;; index 4
+   (table $t0 30 30 funcref)
+   (table $t1 30 30 funcref)
+   (elem (table $t0) (i32.const 2) func 3 1 4 1)
+@@ -750,11 +750,11 @@
+ 
+ (module
+   (type (func (result i32)))  ;; type #0
+-  (import "a" "ef0" (func (result i32)))    ;; index 0
+-  (import "a" "ef1" (func (result i32)))
+-  (import "a" "ef2" (func (result i32)))
+-  (import "a" "ef3" (func (result i32)))
+-  (import "a" "ef4" (func (result i32)))    ;; index 4
++  (func (result i32) (i32.const 0))    ;; index 0
++  (func (result i32) (i32.const 1))
++  (func (result i32) (i32.const 2))
++  (func (result i32) (i32.const 3))
++  (func (result i32) (i32.const 4))    ;; index 4
+   (table $t0 30 30 funcref)
+   (table $t1 30 30 funcref)
+   (elem (table $t0) (i32.const 2) func 3 1 4 1)
+@@ -842,11 +842,11 @@
+ 
+ (module
+   (type (func (result i32)))  ;; type #0
+-  (import "a" "ef0" (func (result i32)))    ;; index 0
+-  (import "a" "ef1" (func (result i32)))
+-  (import "a" "ef2" (func (result i32)))
+-  (import "a" "ef3" (func (result i32)))
+-  (import "a" "ef4" (func (result i32)))    ;; index 4
++  (func (result i32) (i32.const 0))    ;; index 0
++  (func (result i32) (i32.const 1))
++  (func (result i32) (i32.const 2))
++  (func (result i32) (i32.const 3))
++  (func (result i32) (i32.const 4))    ;; index 4
+   (table $t0 30 30 funcref)
+   (table $t1 30 30 funcref)
+   (elem (table $t1) (i32.const 2) func 3 1 4 1)
+@@ -934,11 +934,11 @@
+ 
+ (module
+   (type (func (result i32)))  ;; type #0
+-  (import "a" "ef0" (func (result i32)))    ;; index 0
+-  (import "a" "ef1" (func (result i32)))
+-  (import "a" "ef2" (func (result i32)))
+-  (import "a" "ef3" (func (result i32)))
+-  (import "a" "ef4" (func (result i32)))    ;; index 4
++  (func (result i32) (i32.const 0))    ;; index 0
++  (func (result i32) (i32.const 1))
++  (func (result i32) (i32.const 2))
++  (func (result i32) (i32.const 3))
++  (func (result i32) (i32.const 4))    ;; index 4
+   (table $t0 30 30 funcref)
+   (table $t1 30 30 funcref)
+   (elem (table $t1) (i32.const 2) func 3 1 4 1)
+@@ -1026,11 +1026,11 @@
+ 
+ (module
+   (type (func (result i32)))  ;; type #0
+-  (import "a" "ef0" (func (result i32)))    ;; index 0
+-  (import "a" "ef1" (func (result i32)))
+-  (import "a" "ef2" (func (result i32)))
+-  (import "a" "ef3" (func (result i32)))
+-  (import "a" "ef4" (func (result i32)))    ;; index 4
++  (func (result i32) (i32.const 0))    ;; index 0
++  (func (result i32) (i32.const 1))
++  (func (result i32) (i32.const 2))
++  (func (result i32) (i32.const 3))
++  (func (result i32) (i32.const 4))    ;; index 4
+   (table $t0 30 30 funcref)
+   (table $t1 30 30 funcref)
+   (elem (table $t1) (i32.const 2) func 3 1 4 1)
+@@ -1118,11 +1118,11 @@
+ 
+ (module
+   (type (func (result i32)))  ;; type #0
+-  (import "a" "ef0" (func (result i32)))    ;; index 0
+-  (import "a" "ef1" (func (result i32)))
+-  (import "a" "ef2" (func (result i32)))
+-  (import "a" "ef3" (func (result i32)))
+-  (import "a" "ef4" (func (result i32)))    ;; index 4
++  (func (result i32) (i32.const 0))    ;; index 0
++  (func (result i32) (i32.const 1))
++  (func (result i32) (i32.const 2))
++  (func (result i32) (i32.const 3))
++  (func (result i32) (i32.const 4))    ;; index 4
+   (table $t0 30 30 funcref)
+   (table $t1 30 30 funcref)
+   (elem (table $t1) (i32.const 2) func 3 1 4 1)
+@@ -1210,11 +1210,11 @@
+ 
+ (module
+   (type (func (result i32)))  ;; type #0
+-  (import "a" "ef0" (func (result i32)))    ;; index 0
+-  (import "a" "ef1" (func (result i32)))
+-  (import "a" "ef2" (func (result i32)))
+-  (import "a" "ef3" (func (result i32)))
+-  (import "a" "ef4" (func (result i32)))    ;; index 4
++  (func (result i32) (i32.const 0))    ;; index 0
++  (func (result i32) (i32.const 1))
++  (func (result i32) (i32.const 2))
++  (func (result i32) (i32.const 3))
++  (func (result i32) (i32.const 4))    ;; index 4
+   (table $t0 30 30 funcref)
+   (table $t1 30 30 funcref)
+   (elem (table $t1) (i32.const 2) func 3 1 4 1)
+@@ -1302,11 +1302,11 @@
+ 
+ (module
+   (type (func (result i32)))  ;; type #0
+-  (import "a" "ef0" (func (result i32)))    ;; index 0
+-  (import "a" "ef1" (func (result i32)))
+-  (import "a" "ef2" (func (result i32)))
+-  (import "a" "ef3" (func (result i32)))
+-  (import "a" "ef4" (func (result i32)))    ;; index 4
++  (func (result i32) (i32.const 0))    ;; index 0
++  (func (result i32) (i32.const 1))
++  (func (result i32) (i32.const 2))
++  (func (result i32) (i32.const 3))
++  (func (result i32) (i32.const 4))    ;; index 4
+   (table $t0 30 30 funcref)
+   (table $t1 30 30 funcref)
+   (elem (table $t1) (i32.const 2) func 3 1 4 1)
+@@ -1394,11 +1394,11 @@
+ 
+ (module
+   (type (func (result i32)))  ;; type #0
+-  (import "a" "ef0" (func (result i32)))    ;; index 0
+-  (import "a" "ef1" (func (result i32)))
+-  (import "a" "ef2" (func (result i32)))
+-  (import "a" "ef3" (func (result i32)))
+-  (import "a" "ef4" (func (result i32)))    ;; index 4
++  (func (result i32) (i32.const 0))    ;; index 0
++  (func (result i32) (i32.const 1))
++  (func (result i32) (i32.const 2))
++  (func (result i32) (i32.const 3))
++  (func (result i32) (i32.const 4))    ;; index 4
+   (table $t0 30 30 funcref)
+   (table $t1 30 30 funcref)
+   (elem (table $t1) (i32.const 2) func 3 1 4 1)
+@@ -1486,11 +1486,11 @@
+ 
+ (module
+   (type (func (result i32)))  ;; type #0
+-  (import "a" "ef0" (func (result i32)))    ;; index 0
+-  (import "a" "ef1" (func (result i32)))
+-  (import "a" "ef2" (func (result i32)))
+-  (import "a" "ef3" (func (result i32)))
+-  (import "a" "ef4" (func (result i32)))    ;; index 4
++  (func (result i32) (i32.const 0))    ;; index 0
++  (func (result i32) (i32.const 1))
++  (func (result i32) (i32.const 2))
++  (func (result i32) (i32.const 3))
++  (func (result i32) (i32.const 4))    ;; index 4
+   (table $t0 30 30 funcref)
+   (table $t1 30 30 funcref)
+   (elem (table $t1) (i32.const 2) func 3 1 4 1)
+@@ -1578,11 +1578,11 @@
+ 
+ (module
+   (type (func (result i32)))  ;; type #0
+-  (import "a" "ef0" (func (result i32)))    ;; index 0
+-  (import "a" "ef1" (func (result i32)))
+-  (import "a" "ef2" (func (result i32)))
+-  (import "a" "ef3" (func (result i32)))
+-  (import "a" "ef4" (func (result i32)))    ;; index 4
++  (func (result i32) (i32.const 0))    ;; index 0
++  (func (result i32) (i32.const 1))
++  (func (result i32) (i32.const 2))
++  (func (result i32) (i32.const 3))
++  (func (result i32) (i32.const 4))    ;; index 4
+   (table $t0 30 30 funcref)
+   (table $t1 30 30 funcref)
+   (elem (table $t1) (i32.const 2) func 3 1 4 1)
+diff --git a/test/core/table_init.wast b/test/core/table_init.wast
+index 0b2d26f7..3c595e5b 100644
+--- a/test/core/table_init.wast
++++ b/test/core/table_init.wast
+@@ -14,11 +14,11 @@
+ 
+ (module
+   (type (func (result i32)))  ;; type #0
+-  (import "a" "ef0" (func (result i32)))    ;; index 0
+-  (import "a" "ef1" (func (result i32)))
+-  (import "a" "ef2" (func (result i32)))
+-  (import "a" "ef3" (func (result i32)))
+-  (import "a" "ef4" (func (result i32)))    ;; index 4
++  (func (result i32) (i32.const 0))    ;; index 0
++  (func (result i32) (i32.const 1))
++  (func (result i32) (i32.const 2))
++  (func (result i32) (i32.const 3))
++  (func (result i32) (i32.const 4))    ;; index 4
+   (table $t0 30 30 funcref)
+   (table $t1 30 30 funcref)
+   (elem (table $t0) (i32.const 2) func 3 1 4 1)
+@@ -72,11 +72,11 @@
+ 
+ (module
+   (type (func (result i32)))  ;; type #0
+-  (import "a" "ef0" (func (result i32)))    ;; index 0
+-  (import "a" "ef1" (func (result i32)))
+-  (import "a" "ef2" (func (result i32)))
+-  (import "a" "ef3" (func (result i32)))
+-  (import "a" "ef4" (func (result i32)))    ;; index 4
++  (func (result i32) (i32.const 0))    ;; index 0
++  (func (result i32) (i32.const 1))
++  (func (result i32) (i32.const 2))
++  (func (result i32) (i32.const 3))
++  (func (result i32) (i32.const 4))    ;; index 4
+   (table $t0 30 30 funcref)
+   (table $t1 30 30 funcref)
+   (elem (table $t0) (i32.const 2) func 3 1 4 1)
+@@ -130,11 +130,11 @@
+ 
+ (module
+   (type (func (result i32)))  ;; type #0
+-  (import "a" "ef0" (func (result i32)))    ;; index 0
+-  (import "a" "ef1" (func (result i32)))
+-  (import "a" "ef2" (func (result i32)))
+-  (import "a" "ef3" (func (result i32)))
+-  (import "a" "ef4" (func (result i32)))    ;; index 4
++  (func (result i32) (i32.const 0))    ;; index 0
++  (func (result i32) (i32.const 1))
++  (func (result i32) (i32.const 2))
++  (func (result i32) (i32.const 3))
++  (func (result i32) (i32.const 4))    ;; index 4
+   (table $t0 30 30 funcref)
+   (table $t1 30 30 funcref)
+   (elem (table $t0) (i32.const 2) func 3 1 4 1)
+@@ -196,11 +196,11 @@
+ 
+ (module
+   (type (func (result i32)))  ;; type #0
+-  (import "a" "ef0" (func (result i32)))    ;; index 0
+-  (import "a" "ef1" (func (result i32)))
+-  (import "a" "ef2" (func (result i32)))
+-  (import "a" "ef3" (func (result i32)))
+-  (import "a" "ef4" (func (result i32)))    ;; index 4
++  (func (result i32) (i32.const 0))    ;; index 0
++  (func (result i32) (i32.const 1))
++  (func (result i32) (i32.const 2))
++  (func (result i32) (i32.const 3))
++  (func (result i32) (i32.const 4))    ;; index 4
+   (table $t0 30 30 funcref)
+   (table $t1 30 30 funcref)
+   (elem (table $t1) (i32.const 2) func 3 1 4 1)
+@@ -254,11 +254,11 @@
+ 
+ (module
+   (type (func (result i32)))  ;; type #0
+-  (import "a" "ef0" (func (result i32)))    ;; index 0
+-  (import "a" "ef1" (func (result i32)))
+-  (import "a" "ef2" (func (result i32)))
+-  (import "a" "ef3" (func (result i32)))
+-  (import "a" "ef4" (func (result i32)))    ;; index 4
++  (func (result i32) (i32.const 0))    ;; index 0
++  (func (result i32) (i32.const 1))
++  (func (result i32) (i32.const 2))
++  (func (result i32) (i32.const 3))
++  (func (result i32) (i32.const 4))    ;; index 4
+   (table $t0 30 30 funcref)
+   (table $t1 30 30 funcref)
+   (elem (table $t1) (i32.const 2) func 3 1 4 1)
+@@ -312,11 +312,11 @@
+ 
+ (module
+   (type (func (result i32)))  ;; type #0
+-  (import "a" "ef0" (func (result i32)))    ;; index 0
+-  (import "a" "ef1" (func (result i32)))
+-  (import "a" "ef2" (func (result i32)))
+-  (import "a" "ef3" (func (result i32)))
+-  (import "a" "ef4" (func (result i32)))    ;; index 4
++  (func (result i32) (i32.const 0))    ;; index 0
++  (func (result i32) (i32.const 1))
++  (func (result i32) (i32.const 2))
++  (func (result i32) (i32.const 3))
++  (func (result i32) (i32.const 4))    ;; index 4
+   (table $t0 30 30 funcref)
+   (table $t1 30 30 funcref)
+   (elem (table $t1) (i32.const 2) func 3 1 4 1)

+ 18 - 8
tests/wamr-test-suites/spec-test-script/runtest.py

@@ -62,6 +62,13 @@ aot_target_options_map = {
     "xtensa": ["--target=xtensa"],
     "xtensa": ["--target=xtensa"],
 }
 }
 
 
+# AOT compilation options mapping for XIP mode
+aot_target_options_map_xip = {
+    # avoid l32r relocations for xtensa
+    "xtensa": ["--mllvm=-mtext-section-literals"],
+    "riscv32_ilp32f": ["--enable-builtin-intrinsics=i64.common,f64.common,f32.const,f64.const,f64xi32,f64xi64,f64_promote_f32,f32_demote_f64"],
+}
+
 def debug(data):
 def debug(data):
     if debug_file:
     if debug_file:
         debug_file.write(data)
         debug_file.write(data)
@@ -320,6 +327,9 @@ parser.add_argument('--gc', default=False, action='store_true',
 parser.add_argument('--memory64', default=False, action='store_true',
 parser.add_argument('--memory64', default=False, action='store_true',
         help='Test with Memory64')
         help='Test with Memory64')
 
 
+parser.add_argument('--multi-memory', default=False, action='store_true',
+        help='Test with multi-memory(with multi-module auto enabled)')
+
 parser.add_argument('--qemu', default=False, action='store_true',
 parser.add_argument('--qemu', default=False, action='store_true',
         help="Enable QEMU")
         help="Enable QEMU")
 
 
@@ -1090,6 +1100,8 @@ def compile_wast_to_wasm(form, wast_tempfile, wasm_tempfile, opts):
         cmd = [opts.wast2wasm, "--enable-threads", "--no-check", "--enable-exceptions", "--enable-tail-call", wast_tempfile, "-o", wasm_tempfile ]
         cmd = [opts.wast2wasm, "--enable-threads", "--no-check", "--enable-exceptions", "--enable-tail-call", wast_tempfile, "-o", wasm_tempfile ]
     elif opts.memory64:
     elif opts.memory64:
         cmd = [opts.wast2wasm, "--enable-memory64", "--no-check", wast_tempfile, "-o", wasm_tempfile ]
         cmd = [opts.wast2wasm, "--enable-memory64", "--no-check", wast_tempfile, "-o", wasm_tempfile ]
+    elif opts.multi_memory:
+        cmd = [opts.wast2wasm, "--enable-multi-memory", "--no-check", wast_tempfile, "-o", wasm_tempfile ]
     else:
     else:
         cmd = [opts.wast2wasm, "--enable-threads", "--no-check",
         cmd = [opts.wast2wasm, "--enable-threads", "--no-check",
                wast_tempfile, "-o", wasm_tempfile ]
                wast_tempfile, "-o", wasm_tempfile ]
@@ -1122,10 +1134,8 @@ def compile_wasm_to_aot(wasm_tempfile, aot_tempfile, runner, opts, r, output = '
 
 
     if opts.xip:
     if opts.xip:
         cmd.append("--xip")
         cmd.append("--xip")
-
-        # avoid l32r relocations for xtensa
-        if opts.target == "xtensa":
-            cmd.append("--mllvm=-mtext-section-literals")
+        if test_target in aot_target_options_map_xip:
+            cmd += aot_target_options_map_xip[test_target]
 
 
     if opts.multi_thread:
     if opts.multi_thread:
         cmd.append("--enable-multi-thread")
         cmd.append("--enable-multi-thread")
@@ -1308,8 +1318,8 @@ if __name__ == "__main__":
     if test_aot:
     if test_aot:
         aot_tempfile = create_tmp_file(".aot")
         aot_tempfile = create_tmp_file(".aot")
         # could be potientially compiled to aot
         # could be potientially compiled to aot
-        # with the future following call test_assert_xxx, 
-        # add them to temp_file_repo now even if no actual following file, 
+        # with the future following call test_assert_xxx,
+        # add them to temp_file_repo now even if no actual following file,
         # it will be simple ignore during final deletion if not exist
         # it will be simple ignore during final deletion if not exist
         prefix = wasm_tempfile.split(".wasm")[0]
         prefix = wasm_tempfile.split(".wasm")[0]
         temp_file_repo.append(prefix + ".aot")
         temp_file_repo.append(prefix + ".aot")
@@ -1436,8 +1446,8 @@ if __name__ == "__main__":
                         if test_aot:
                         if test_aot:
                             r = compile_wasm_to_aot(temp_files[1], temp_files[2], True, opts, r)
                             r = compile_wasm_to_aot(temp_files[1], temp_files[2], True, opts, r)
                             # could be potientially compiled to aot
                             # could be potientially compiled to aot
-                            # with the future following call test_assert_xxx, 
-                            # add them to temp_file_repo now even if no actual following file, 
+                            # with the future following call test_assert_xxx,
+                            # add them to temp_file_repo now even if no actual following file,
                             # it will be simple ignore during final deletion if not exist
                             # it will be simple ignore during final deletion if not exist
                             prefix = temp_files[1].split(".wasm")[0]
                             prefix = temp_files[1].split(".wasm")[0]
                             temp_file_repo.append(prefix + ".aot")
                             temp_file_repo.append(prefix + ".aot")

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

@@ -25,6 +25,7 @@ function help()
     echo "-S enable SIMD feature"
     echo "-S enable SIMD feature"
     echo "-G enable GC feature"
     echo "-G enable GC feature"
     echo "-W enable memory64 feature"
     echo "-W enable memory64 feature"
+    echo "-E enable multi memory feature"
     echo "-X enable XIP feature"
     echo "-X enable XIP feature"
     echo "-e enable exception handling"
     echo "-e enable exception handling"
     echo "-x test SGX"
     echo "-x test SGX"
@@ -59,6 +60,7 @@ COLLECT_CODE_COVERAGE=0
 ENABLE_SIMD=0
 ENABLE_SIMD=0
 ENABLE_GC=0
 ENABLE_GC=0
 ENABLE_MEMORY64=0
 ENABLE_MEMORY64=0
+ENABLE_MULTI_MEMORY=0
 ENABLE_XIP=0
 ENABLE_XIP=0
 ENABLE_EH=0
 ENABLE_EH=0
 ENABLE_DEBUG_VERSION=0
 ENABLE_DEBUG_VERSION=0
@@ -85,7 +87,7 @@ REQUIREMENT_NAME=""
 # Initialize an empty array for subrequirement IDs
 # Initialize an empty array for subrequirement IDs
 SUBREQUIREMENT_IDS=()
 SUBREQUIREMENT_IDS=()
 
 
-while getopts ":s:cabgvt:m:MCpSXexwWPGQF:j:T:r:A:" opt
+while getopts ":s:cabgvt:m:MCpSXexwWEPGQF:j:T:r:A:" opt
 do
 do
     OPT_PARSED="TRUE"
     OPT_PARSED="TRUE"
     case $opt in
     case $opt in
@@ -148,6 +150,11 @@ do
         echo "enable wasm64(memory64) feature"
         echo "enable wasm64(memory64) feature"
         ENABLE_MEMORY64=1
         ENABLE_MEMORY64=1
         ;;
         ;;
+        E)
+        echo "enable multi memory feature(auto enable multi module)"
+        ENABLE_MULTI_MEMORY=1
+        ENABLE_MULTI_MODULE=1
+        ;;
         C)
         C)
         echo "enable code coverage"
         echo "enable code coverage"
         COLLECT_CODE_COVERAGE=1
         COLLECT_CODE_COVERAGE=1
@@ -496,6 +503,20 @@ function spec_test()
         git reset --hard 48e69f394869c55b7bbe14ac963c09f4605490b6
         git reset --hard 48e69f394869c55b7bbe14ac963c09f4605490b6
         git checkout 044d0d2e77bdcbe891f7e0b9dd2ac01d56435f0b -- test/core/elem.wast test/core/data.wast
         git checkout 044d0d2e77bdcbe891f7e0b9dd2ac01d56435f0b -- test/core/elem.wast test/core/data.wast
         git apply ../../spec-test-script/memory64_ignore_cases.patch || exit 1
         git apply ../../spec-test-script/memory64_ignore_cases.patch || exit 1
+    elif [[ ${ENABLE_MULTI_MEMORY} == 1 ]]; then
+        echo "checkout spec for multi memory proposal"
+
+        # check spec test cases for multi memory
+        git clone -b main --single-branch https://github.com/WebAssembly/multi-memory.git spec
+        pushd spec
+
+        # Reset to commit: "Merge pull request #48 from backes/specify-memcpy-immediate-order"
+        git reset --hard 48e69f394869c55b7bbe14ac963c09f4605490b6
+        git checkout 044d0d2e77bdcbe891f7e0b9dd2ac01d56435f0b -- test/core/elem.wast
+        git apply ../../spec-test-script/multi_memory_ignore_cases.patch || exit 1
+        if [[ ${RUNNING_MODE} == "aot" ]]; then
+            git apply ../../spec-test-script/multi_module_aot_ignore_cases.patch || exit 1
+        fi
     else
     else
         echo "checkout spec for default proposal"
         echo "checkout spec for default proposal"
 
 
@@ -572,6 +593,13 @@ function spec_test()
         ARGS_FOR_SPEC_TEST+="--memory64 "
         ARGS_FOR_SPEC_TEST+="--memory64 "
     fi
     fi
 
 
+    # multi memory is only enabled in interp and aot mode
+    if [[ 1 == ${ENABLE_MULTI_MEMORY} ]]; then
+        if [[ $1 == 'classic-interp' || $1 == 'aot' ]]; then
+            ARGS_FOR_SPEC_TEST+="--multi-memory "
+        fi
+    fi
+
     if [[ ${ENABLE_QEMU} == 1 ]]; then
     if [[ ${ENABLE_QEMU} == 1 ]]; then
         ARGS_FOR_SPEC_TEST+="--qemu "
         ARGS_FOR_SPEC_TEST+="--qemu "
         ARGS_FOR_SPEC_TEST+="--qemu-firmware ${QEMU_FIRMWARE} "
         ARGS_FOR_SPEC_TEST+="--qemu-firmware ${QEMU_FIRMWARE} "
@@ -852,6 +880,14 @@ function do_execute_in_running_mode()
 {
 {
     local RUNNING_MODE="$1"
     local RUNNING_MODE="$1"
 
 
+    if [[ ${ENABLE_MULTI_MEMORY} -eq 1 ]]; then
+        if [[ "${RUNNING_MODE}" != "classic-interp" \
+                && "${RUNNING_MODE}" != "aot" ]]; then
+            echo "support multi-memory in classic-interp mode and aot mode"
+            return 0
+        fi
+    fi
+
     if [[ ${ENABLE_MEMORY64} -eq 1 ]]; then
     if [[ ${ENABLE_MEMORY64} -eq 1 ]]; then
         if [[ "${RUNNING_MODE}" != "classic-interp" \
         if [[ "${RUNNING_MODE}" != "classic-interp" \
                 && "${RUNNING_MODE}" != "aot" ]]; then
                 && "${RUNNING_MODE}" != "aot" ]]; then
@@ -941,6 +977,12 @@ function trigger()
         EXTRA_COMPILE_FLAGS+=" -DWAMR_BUILD_MEMORY64=0"
         EXTRA_COMPILE_FLAGS+=" -DWAMR_BUILD_MEMORY64=0"
     fi
     fi
 
 
+    if [[ ${ENABLE_MULTI_MEMORY} == 1 ]];then
+        EXTRA_COMPILE_FLAGS+=" -DWAMR_BUILD_MULTI_MEMORY=1"
+    else
+        EXTRA_COMPILE_FLAGS+=" -DWAMR_BUILD_MULTI_MEMORY=0"
+    fi
+
     if [[ ${ENABLE_MULTI_THREAD} == 1 ]];then
     if [[ ${ENABLE_MULTI_THREAD} == 1 ]];then
         EXTRA_COMPILE_FLAGS+=" -DWAMR_BUILD_LIB_PTHREAD=1"
         EXTRA_COMPILE_FLAGS+=" -DWAMR_BUILD_LIB_PTHREAD=1"
     fi
     fi