瀏覽代碼

Merge branch main into dev/gc_refactor

Wenyong Huang 2 年之前
父節點
當前提交
9c71ca6c46
共有 100 個文件被更改,包括 4720 次插入2469 次删除
  1. 6 0
      .github/workflows/compilation_on_android_ubuntu.yml
  2. 6 0
      .github/workflows/compilation_on_macos.yml
  3. 2 2
      .github/workflows/compilation_on_nuttx.yml
  4. 60 1
      .github/workflows/compilation_on_windows.yml
  5. 6 0
      .github/workflows/nightly_run.yml
  6. 3 3
      .github/workflows/release_process.yml
  7. 95 41
      .github/workflows/spec_test_on_nuttx.yml
  8. 4 4
      build-scripts/build_llvm.py
  9. 5 1
      build-scripts/runtime_lib.cmake
  10. 2 2
      core/app-mgr/README.md
  11. 1 1
      core/app-mgr/app-manager/module_wasm_app.c
  12. 6 1
      core/config.h
  13. 10 7
      core/iwasm/aot/aot_loader.c
  14. 90 30
      core/iwasm/aot/aot_runtime.c
  15. 4 0
      core/iwasm/aot/arch/aot_reloc_riscv.c
  16. 17 2
      core/iwasm/common/wasm_application.c
  17. 47 1
      core/iwasm/common/wasm_exec_env.c
  18. 4 0
      core/iwasm/common/wasm_exec_env.h
  19. 1 1
      core/iwasm/common/wasm_memory.c
  20. 54 34
      core/iwasm/common/wasm_runtime_common.c
  21. 6 5
      core/iwasm/common/wasm_runtime_common.h
  22. 0 1
      core/iwasm/compilation/aot.c
  23. 0 1
      core/iwasm/compilation/aot.h
  24. 3 1
      core/iwasm/compilation/aot_emit_aot_file.c
  25. 4 3
      core/iwasm/compilation/aot_emit_function.c
  26. 90 9
      core/iwasm/compilation/aot_llvm.c
  27. 3 0
      core/iwasm/compilation/aot_llvm.h
  28. 10 1
      core/iwasm/compilation/aot_orc_extra.cpp
  29. 3 0
      core/iwasm/compilation/aot_orc_extra.h
  30. 32 2
      core/iwasm/fast-jit/fe/jit_emit_function.c
  31. 22 14
      core/iwasm/fast-jit/fe/jit_emit_memory.c
  32. 17 10
      core/iwasm/fast-jit/fe/jit_emit_table.c
  33. 2 2
      core/iwasm/fast-jit/jit_codecache.c
  34. 1 0
      core/iwasm/fast-jit/jit_compiler.h
  35. 0 19
      core/iwasm/fast-jit/jit_utils.c
  36. 0 94
      core/iwasm/fast-jit/jit_utils.h
  37. 1 0
      core/iwasm/include/aot_comp_option.h
  38. 26 13
      core/iwasm/include/wasm_export.h
  39. 1 2
      core/iwasm/interpreter/wasm.h
  40. 22 19
      core/iwasm/interpreter/wasm_interp_classic.c
  41. 24 23
      core/iwasm/interpreter/wasm_interp_fast.c
  42. 7 2
      core/iwasm/interpreter/wasm_loader.c
  43. 1 0
      core/iwasm/interpreter/wasm_mini_loader.c
  44. 80 31
      core/iwasm/interpreter/wasm_runtime.c
  45. 16 4
      core/iwasm/interpreter/wasm_runtime.h
  46. 13 3
      core/iwasm/libraries/lib-rats/lib_rats_wrapper.c
  47. 3 0
      core/iwasm/libraries/lib-rats/lib_rats_wrapper.h
  48. 3 0
      core/iwasm/libraries/lib-socket/test/manifest.json
  49. 10 1
      core/iwasm/libraries/libc-uvwasi/libc_uvwasi_wrapper.c
  50. 3 2
      core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c
  51. 10 2
      core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.h
  52. 554 1312
      core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h
  53. 41 70
      core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/blocking_op.c
  54. 24 23
      core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/blocking_op.h
  55. 31 23
      core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/locking.h
  56. 200 527
      core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c
  57. 2 1
      core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.h
  58. 59 20
      core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/random.c
  59. 6 2
      core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/random.h
  60. 1 63
      core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/ssp_config.h
  61. 16 0
      core/iwasm/libraries/thread-mgr/thread_manager.c
  62. 6 0
      core/iwasm/libraries/thread-mgr/thread_manager.h
  63. 54 2
      core/shared/mem-alloc/ems/ems_alloc.c
  64. 2 0
      core/shared/mem-alloc/ems/ems_gc_internal.h
  65. 2 0
      core/shared/mem-alloc/ems/ems_hmu.c
  66. 17 2
      core/shared/mem-alloc/ems/ems_kfc.c
  67. 8 0
      core/shared/mem-alloc/mem_alloc.cmake
  68. 1 1
      core/shared/platform/alios/alios_platform.c
  69. 18 0
      core/shared/platform/alios/platform_internal.h
  70. 11 0
      core/shared/platform/android/platform_internal.h
  71. 256 0
      core/shared/platform/common/libc-util/libc_errno.c
  72. 15 0
      core/shared/platform/common/libc-util/libc_errno.h
  73. 8 0
      core/shared/platform/common/libc-util/platform_common_libc_util.cmake
  74. 12 1
      core/shared/platform/common/posix/platform_api_posix.cmake
  75. 86 0
      core/shared/platform/common/posix/posix_clock.c
  76. 1007 0
      core/shared/platform/common/posix/posix_file.c
  77. 4 4
      core/shared/platform/common/posix/posix_memmap.c
  78. 6 3
      core/shared/platform/common/posix/posix_socket.c
  79. 56 1
      core/shared/platform/common/posix/posix_thread.c
  80. 4 0
      core/shared/platform/cosmopolitan/platform_internal.h
  81. 11 0
      core/shared/platform/darwin/platform_internal.h
  82. 1 1
      core/shared/platform/esp-idf/espidf_memmap.c
  83. 6 3
      core/shared/platform/esp-idf/espidf_socket.c
  84. 11 0
      core/shared/platform/esp-idf/platform_internal.h
  85. 13 0
      core/shared/platform/freebsd/platform_internal.h
  86. 573 2
      core/shared/platform/include/platform_api_extension.h
  87. 1 1
      core/shared/platform/include/platform_api_vmcore.h
  88. 610 0
      core/shared/platform/include/platform_wasi_types.h
  89. 11 0
      core/shared/platform/linux-sgx/platform_internal.h
  90. 0 1
      core/shared/platform/linux-sgx/sgx_ipfs.h
  91. 9 2
      core/shared/platform/linux-sgx/sgx_platform.c
  92. 6 2
      core/shared/platform/linux-sgx/sgx_socket.c
  93. 66 1
      core/shared/platform/linux-sgx/sgx_thread.c
  94. 11 4
      core/shared/platform/linux-sgx/shared_platform.cmake
  95. 11 0
      core/shared/platform/linux/platform_internal.h
  96. 1 1
      core/shared/platform/nuttx/nuttx_platform.c
  97. 11 0
      core/shared/platform/nuttx/platform_internal.h
  98. 6 0
      core/shared/platform/nuttx/shared_platform.cmake
  99. 18 0
      core/shared/platform/riot/platform_internal.h
  100. 1 1
      core/shared/platform/riot/riot_platform.c

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

@@ -445,6 +445,12 @@ jobs:
           cmake --build . --config Release --parallel 4
           ./iwasm wasm-apps/no_pthread.wasm
 
+      - name: Build Sample [shared-module]
+        run: |
+          cd samples/shared-module
+          ./build.sh
+          ./run.sh
+
   test:
     needs:
       [

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

@@ -327,3 +327,9 @@ jobs:
           cmake ..
           cmake --build . --config Release --parallel 4
           ./iwasm wasm-apps/no_pthread.wasm
+
+      - name: Build Sample [shared-module]
+        run: |
+          cd samples/shared-module
+          ./build.sh
+          ./run.sh

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

@@ -94,9 +94,9 @@ jobs:
       - name: Install RISC-V Compilers
         if: contains(matrix.nuttx_board_config, 'risc-v')
         run: |
-          curl -L -k https://static.dev.sifive.com/dev-tools/freedom-tools/v2020.12/riscv64-unknown-elf-toolchain-10.2.0-2020.12.8-x86_64-linux-ubuntu14.tar.gz > riscv.tar.gz
+          curl -L https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack/releases/download/v12.3.0-1/xpack-riscv-none-elf-gcc-12.3.0-1-linux-x64.tar.gz > riscv.tar.gz
           tar xvf riscv.tar.gz
-          echo "$PWD/riscv64-unknown-elf-toolchain-10.2.0-2020.12.8-x86_64-linux-ubuntu14/bin" >> $GITHUB_PATH
+          echo "$PWD/xpack-riscv-none-elf-gcc-12.3.0-1/bin" >> $GITHUB_PATH
 
       - name: Install WASI-SDK
         run: |

+ 60 - 1
.github/workflows/compilation_on_windows.yml

@@ -39,6 +39,16 @@ on:
   # allow to be triggered manually
   workflow_dispatch:
 
+env:
+  # For Spec Test
+  DEFAULT_TEST_OPTIONS: "-s spec -b"
+  MULTI_MODULES_TEST_OPTIONS: "-s spec -b -M"
+  THREADS_TEST_OPTIONS: "-s spec -b -p"
+  WASI_TEST_OPTIONS: "-s wasi_certification -w"
+  WASI_TEST_FILTER: ${{ github.workspace }}/product-mini/platforms/windows/wasi_filtered_tests.json
+  # Used when building the WASI socket and thread tests
+  CC: ${{ github.workspace }}/wasi-sdk/bin/clang
+
 # Cancel any in-flight jobs for the same PR/branch so there's only one active
 # at a time
 concurrency:
@@ -60,12 +70,14 @@ jobs:
           "-DWAMR_BUILD_SIMD=1",
           "-DWAMR_BUILD_DEBUG_INTERP=1",
           "-DWAMR_BUILD_LIB_PTHREAD=1",
-          "-DWAMR_BUILD_LIB_WASI_THREADS=1"
+          "-DWAMR_BUILD_LIB_WASI_THREADS=1",
+          "-DWAMR_BUILD_LIBC_UVWASI=0 -DWAMR_BUILD_LIBC_WASI=1"
         ]
     steps:
       - uses: actions/checkout@v3
 
       - name: clone uvwasi library
+        if: ${{ !contains(matrix.build_options, '-DWAMR_BUILD_LIBC_UVWASI=0') }}
         run: |
           cd core/deps
           git clone https://github.com/nodejs/uvwasi.git
@@ -75,3 +87,50 @@ jobs:
           mkdir build && cd build
           cmake .. ${{ matrix.build_options }}
           cmake --build . --config Release --parallel 4
+
+  test:
+    runs-on: windows-latest
+    needs: [build]
+    strategy:
+      fail-fast: false
+      matrix:
+        running_mode:
+          [
+            "classic-interp",
+            "fast-interp",
+          ]
+        test_option:
+          [
+            $DEFAULT_TEST_OPTIONS,
+            $MULTI_MODULES_TEST_OPTIONS,
+            $THREADS_TEST_OPTIONS,
+            $WASI_TEST_OPTIONS,
+          ]
+    steps:
+      - name: checkout
+        uses: actions/checkout@v3
+
+      - name: download and install wasi-sdk
+        if: matrix.test_option == '$WASI_TEST_OPTIONS'
+        run: |
+          curl "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-20/wasi-sdk-20.0.m-mingw.tar.gz" -o wasi-sdk.tar.gz -L
+          mkdir wasi-sdk
+          tar -xzf wasi-sdk.tar.gz -C wasi-sdk --strip-components 1
+
+      - name: build socket api tests
+        shell: bash
+        if: matrix.test_option == '$WASI_TEST_OPTIONS'
+        run: ./build.sh
+        working-directory: ./core/iwasm/libraries/lib-socket/test/
+
+      - name: Build WASI thread tests
+        shell: bash
+        if: matrix.test_option == '$WASI_TEST_OPTIONS'
+        run: ./build.sh
+        working-directory: ./core/iwasm/libraries/lib-wasi-threads/test/
+
+      - name: run tests
+        shell: bash
+        timeout-minutes: 20
+        run: ./test_wamr.sh ${{ matrix.test_option }} -t ${{ matrix.running_mode }}
+        working-directory: ./tests/wamr-test-suites

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

@@ -501,6 +501,12 @@ jobs:
           cmake ..
           cmake --build . --config Release --parallel 4
           ./iwasm wasm-apps/no_pthread.wasm
+
+      - name: Build Sample [shared-module]
+        run: |
+          cd samples/shared-module
+          ./build.sh
+          ./run.sh
   test:
     needs:
       [

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

@@ -56,21 +56,21 @@ jobs:
     uses: ./.github/workflows/build_llvm_libraries.yml
     with:
       os: "ubuntu-20.04"
-      arch: "X86"
+      arch: "AArch64 ARM Mips RISCV X86"
 
   build_llvm_libraries_on_ubuntu_2204:
     needs: [create_tag, create_release]
     uses: ./.github/workflows/build_llvm_libraries.yml
     with:
       os: "ubuntu-22.04"
-      arch: "X86"
+      arch: "AArch64 ARM Mips RISCV X86"
 
   build_llvm_libraries_on_macos:
     needs: [create_tag, create_release]
     uses: ./.github/workflows/build_llvm_libraries.yml
     with:
       os: "macos-latest"
-      arch: "X86"
+      arch: "AArch64 ARM Mips RISCV X86"
 
   #
   # WAMRC

+ 95 - 41
.github/workflows/spec_test_on_nuttx.yml

@@ -4,6 +4,12 @@
 name: spec test on nuttx
 
 on:
+  pull_request:
+    types:
+      - closed
+    branches:
+      - main
+
   schedule:
     - cron:  '0 0 * * *'
 
@@ -12,6 +18,8 @@ on:
 env:
   LLVM_CACHE_SUFFIX: "build-llvm_libraries_ex"
   WASI_SDK_PATH: "/opt/wasi-sdk"
+  WAMR_COMMON_OPTION:
+    "CONFIG_INTERPRETERS_WAMR=y\\nCONFIG_INTERPRETERS_WAMR_STACKSIZE=32768\\nCONFIG_INTERPRETERS_WAMR_LOG=y\\nCONFIG_INTERPRETERS_WAMR_LIBC_BUILTIN=y\\nCONFIG_INTERPRETERS_WAMR_REF_TYPES=y\\nCONFIG_INTERPRETERS_WAMR_ENABLE_SPEC_TEST=y\\nCONFIG_INTERPRETERS_WAMR_SHARED_MEMORY=y\\nCONFIG_INTERPRETERS_WAMR_BULK_MEMORY=y\\nCONFIG_EOL_IS_LF=y\\nCONFIG_ARM_SEMIHOSTING_HOSTFS=y\\nCONFIG_ARM_SEMIHOSTING_HOSTFS_CACHE_COHERENCE=y\\nCONFIG_RISCV_SEMIHOSTING_HOSTFS=y\\nCONFIG_FS_HOSTFS=y\\nCONFIG_LIBC_FLOATINGPOINT=y\\n"
 
 jobs:
   build_llvm_libraries:
@@ -21,40 +29,82 @@ jobs:
       arch: "ARM RISCV AArch64"
 
   spec_test_on_qemu:
-    runs-on: ${{ matrix.os }}
+    runs-on: ubuntu-22.04
     needs: [build_llvm_libraries]
     strategy:
       matrix:
-        os: [ubuntu-22.04]
-        nuttx_board_config: [
-          # cortex-a9
-          "boards/arm/imx6/sabre-6quad/configs/nsh",
-          # riscv32imac
-          "boards/risc-v/qemu-rv/rv-virt/configs/nsh",
-          # riscv64imac
-          # "boards/risc-v/qemu-rv/rv-virt/configs/nsh64",
+        target_config: [
+          # {
+          #   config: "boards/arm64/qemu/qemu-armv8a/configs/nsh",
+          #   target: "aarch64_vfp",
+          #   use_fpu: true
+          # },
+          # {
+          #   config: "boards/arm/imx6/sabre-6quad/configs/nsh",
+          #   target: "thumbv7",
+          #   use_fpu: false
+          # },
+          {
+            config: "boards/arm/imx6/sabre-6quad/configs/nsh",
+            target: "thumbv7_vfp",
+            use_fpu: true
+          },
+          {
+            config: "boards/risc-v/qemu-rv/rv-virt/configs/nsh",
+            target: "riscv32",
+            use_fpu: false
+          },
+          # {
+          #   config: "boards/risc-v/qemu-rv/rv-virt/configs/nsh",
+          #   target: "riscv32_ilp32d",
+          #   use_fpu: true
+          # },
+          # {
+          #   config: "boards/risc-v/qemu-rv/rv-virt/configs/nsh64",
+          #   target: "riscv64",
+          #   use_fpu: false
+          # },
         ]
+
         wamr_test_option: [
-          # "-t fast-interp",
-          "-t aot",
-          "-t aot -X"
+          {
+            mode: "-t aot",
+            option: "CONFIG_INTERPRETERS_WAMR_AOT=y\\n"
+          },
+          {
+            mode: "-t aot -X",
+            option: "CONFIG_INTERPRETERS_WAMR_AOT=y\\n"
+          },
+          {
+            mode: "-t classic-interp",
+            option: "CONFIG_INTERPRETERS_WAMR_CLASSIC=y\\n"
+          },
+          {
+            mode: "-t fast-interp",
+            option: "CONFIG_INTERPRETERS_WAMR_FAST=y\\n"
+          },
         ]
-        llvm_cache_key: [ "${{ needs.build_llvm_libraries.outputs.cache_key }}" ]
+
     steps:
       - name: Install Utilities
         run: |
           sudo apt install -y kconfig-frontends-nox genromfs
 
       - name: Install ARM Compilers
-        if: contains(matrix.nuttx_board_config, 'arm')
-        run: sudo apt install -y gcc-arm-none-eabi
+        if: startsWith(matrix.target_config.config, 'boards/arm')
+        run: |
+          sudo apt install -y gcc-arm-none-eabi
+          wget --quiet https://developer.arm.com/-/media/Files/downloads/gnu/11.2-2022.02/binrel/gcc-arm-11.2-2022.02-x86_64-aarch64-none-elf.tar.xz
+          xz -d gcc-arm-11.2-2022.02-x86_64-aarch64-none-elf.tar.xz
+          tar xf gcc-arm-11.2-2022.02-x86_64-aarch64-none-elf.tar
+          echo "$PWD/gcc-arm-11.2-2022.02-x86_64-aarch64-none-elf/bin" >> $GITHUB_PATH
 
       - name: Install RISC-V Compilers
-        if: contains(matrix.nuttx_board_config, 'risc-v')
+        if: startsWith(matrix.target_config.config, 'boards/risc-v')
         run: |
-          curl -L -k https://static.dev.sifive.com/dev-tools/freedom-tools/v2020.12/riscv64-unknown-elf-toolchain-10.2.0-2020.12.8-x86_64-linux-ubuntu14.tar.gz > riscv.tar.gz
+          curl -L https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack/releases/download/v12.3.0-1/xpack-riscv-none-elf-gcc-12.3.0-1-linux-x64.tar.gz > riscv.tar.gz
           tar xvf riscv.tar.gz
-          echo "$PWD/riscv64-unknown-elf-toolchain-10.2.0-2020.12.8-x86_64-linux-ubuntu14/bin" >> $GITHUB_PATH
+          echo "$PWD/xpack-riscv-none-elf-gcc-12.3.0-1/bin" >> $GITHUB_PATH
 
       - name: Install WASI-SDK
         run: |
@@ -81,6 +131,7 @@ jobs:
           path: apps/interpreters/wamr/wamr
 
       - name: Get LLVM libraries
+        if: contains(matrix.wamr_test_option.mode, 'aot')
         id: retrieve_llvm_libs
         uses: actions/cache@v3
         with:
@@ -90,56 +141,59 @@ jobs:
             ./core/deps/llvm/build/lib
             ./core/deps/llvm/build/libexec
             ./core/deps/llvm/build/share
-          key: ${{ matrix.llvm_cache_key }}
+          key: ${{ needs.build_llvm_libraries.outputs.cache_key }}
 
       - name: Quit if cache miss
-        if: steps.retrieve_llvm_libs.outputs.cache-hit != 'true'
+        if: contains(matrix.wamr_test_option.mode, 'aot') && steps.retrieve_llvm_libs.outputs.cache-hit != 'true'
         run: echo "::error::can not get prebuilt llvm libraries" && exit 1
 
       - name: Copy LLVM
+        if: contains(matrix.wamr_test_option.mode, 'aot')
         run: cp -r core/deps/llvm apps/interpreters/wamr/wamr/core/deps/llvm
 
       - name: Enable WAMR for NuttX
         run: |
-          find nuttx/boards -name defconfig | xargs sed -i '$a\CONFIG_INTERPRETERS_WAMR=y\nCONFIG_INTERPRETERS_WAMR_STACKSIZE=32768\nCONFIG_INTERPRETERS_WAMR_AOT=y\nCONFIG_INTERPRETERS_WAMR_FAST=y\nCONFIG_INTERPRETERS_WAMR_LOG=y\nCONFIG_INTERPRETERS_WAMR_LIBC_BUILTIN=y\nCONFIG_INTERPRETERS_WAMR_REF_TYPES=y\nCONFIG_INTERPRETERS_WAMR_ENABLE_SPEC_TEST=y\nCONFIG_INTERPRETERS_WAMR_SHARED_MEMORY=y\nCONFIG_INTERPRETERS_WAMR_BULK_MEMORY=y\n'
-          find nuttx/boards -name defconfig | xargs sed -i '$a\CONFIG_EOL_IS_LF=y\nCONFIG_ARM_SEMIHOSTING_HOSTFS=y\nCONFIG_ARM_SEMIHOSTING_HOSTFS_CACHE_COHERENCE=y\nCONFIG_RISCV_SEMIHOSTING_HOSTFS=y\nCONFIG_FS_HOSTFS=y\nCONFIG_LIBC_FLOATINGPOINT=y\n'
+          find nuttx/boards -name defconfig | xargs sed -i '$a\${{ env.WAMR_COMMON_OPTION }}'
+      
+      - name: Enable WAMR Interpreter for NuttX
+        run: |
+          find nuttx/boards -name defconfig | xargs sed -i '$a\${{ matrix.wamr_test_option.option }}'
+
+      - name: Disable FPU for NuttX
+        if: matrix.target_config.use_fpu== false
+        run: |
+          find nuttx/boards -name defconfig | xargs sed -i '$a\# CONFIG_ARCH_FPU is not set\n'
 
       - name: Build wamrc
+        if: contains(matrix.wamr_test_option.mode, 'aot')
         working-directory: apps/interpreters/wamr/wamr/wamr-compiler
         run: |
           cmake -Bbuild .
           cmake --build build
 
       - name: Build
+        id: build_firmware
         run: |
           cd nuttx
-          tools/configure.sh ${{ matrix.nuttx_board_config }}
+          tools/configure.sh ${{ matrix.target_config.config }}
           make -j$(nproc)
-          echo "firmware=$PWD/nuttx" >> $GITHUB_ENV
+          echo "firmware=$PWD/nuttx" >> $GITHUB_OUTPUT
 
-      - name: Test on ARM
-        if: endsWith(matrix.nuttx_board_config, 'sabre-6quad/configs/nsh')
+      - name: Install QEMU for ARM
+        if: startsWith(matrix.target_config.config, 'boards/arm')
         run: |
           curl -L https://github.com/xpack-dev-tools/qemu-arm-xpack/releases/download/v7.1.0-1/xpack-qemu-arm-7.1.0-1-linux-x64.tar.gz > xpack-qemu-arm.tar.gz
           tar xvf xpack-qemu-arm.tar.gz
-          export PATH=$PATH:$PWD/xpack-qemu-arm-7.1.0-1/bin
-          cd apps/interpreters/wamr/wamr/tests/wamr-test-suites
-          ./test_wamr.sh -s spec ${{ matrix.wamr_test_option }} -m thumbv7_vfp -b -Q -P -F ${{ env.firmware }}
+          echo $PWD/xpack-qemu-arm-7.1.0-1/bin >> $GITHUB_PATH
 
-      - name: Test on RISCV32
-        if: endsWith(matrix.nuttx_board_config, 'rv-virt/configs/nsh')
+      - name: Install QEMU for RISC-V
+        if: startsWith(matrix.target_config.config, 'boards/risc-v')
         run: |
           curl -L https://github.com/xpack-dev-tools/qemu-riscv-xpack/releases/download/v7.1.0-1/xpack-qemu-riscv-7.1.0-1-linux-x64.tar.gz > xpack-qemu-riscv.tar.gz
           tar xvf xpack-qemu-riscv.tar.gz
-          export PATH=$PATH:$PWD/xpack-qemu-riscv-7.1.0-1/bin
-          cd apps/interpreters/wamr/wamr/tests/wamr-test-suites
-          ./test_wamr.sh -s spec ${{ matrix.wamr_test_option }} -m RISCV32 -b -Q -P -F ${{ env.firmware }}
-
-      - name: Test on RISCV64
-        if: endsWith(matrix.nuttx_board_config, 'rv-virt/configs/nsh64')
+          echo PATH=$PATH:$PWD/xpack-qemu-riscv-7.1.0-1/bin >> $GITHUB_PATH
+      
+      - name: Test
         run: |
-          curl -L https://github.com/xpack-dev-tools/qemu-riscv-xpack/releases/download/v7.1.0-1/xpack-qemu-riscv-7.1.0-1-linux-x64.tar.gz > xpack-qemu-riscv.tar.gz
-          tar xvf xpack-qemu-riscv.tar.gz
-          export PATH=$PATH:$PWD/xpack-qemu-riscv-7.1.0-1/bin
           cd apps/interpreters/wamr/wamr/tests/wamr-test-suites
-          ./test_wamr.sh -s spec ${{ matrix.wamr_test_option }} -m riscv64 -b -Q -P -F ${{ env.firmware }}
+          ./test_wamr.sh -s spec ${{ matrix.wamr_test_option.mode }} -m ${{ matrix.target_config.target }} -b -Q -P -F ${{ steps.build_firmware.outputs.firmware }}

+ 4 - 4
build-scripts/build_llvm.py

@@ -67,8 +67,8 @@ def build_llvm(llvm_dir, platform, backends, projects, use_clang=False, extra_fl
         "-DLLVM_INCLUDE_EXAMPLES:BOOL=OFF",
         "-DLLVM_INCLUDE_UTILS:BOOL=OFF",
         "-DLLVM_INCLUDE_TESTS:BOOL=OFF",
-        "-DLLVM_BUILD_TESTS:BOOL=OFF",
         "-DLLVM_OPTIMIZED_TABLEGEN:BOOL=ON",
+        "-DLLVM_USE_PERF:BOOL=ON",
     ]
 
     # use clang/clang++/lld. but macos doesn't support lld
@@ -255,7 +255,7 @@ def main():
             "branch": "release/15.x",
         },
         "xtensa": {
-            "repo": "https://github.com/espressif/llvm-project.git", 
+            "repo": "https://github.com/espressif/llvm-project.git",
             "repo_ssh": "git@github.com:espressif/llvm-project.git",
             "branch": "xtensa_release_15.x",
         },
@@ -281,13 +281,13 @@ def main():
             commit_hash = query_llvm_version(llvm_info)
             print(commit_hash)
             return commit_hash is not None
-        
+
         repo_addr = llvm_info["repo"]
         if os.environ.get('USE_GIT_SSH') == "true":
             repo_addr = llvm_info["repo_ssh"]
         else:
             print("To use ssh for git clone, run: export USE_GIT_SSH=true")
-        
+
         llvm_dir = clone_llvm(deps_dir, repo_addr, llvm_info["branch"])
         if (
             build_llvm(

+ 5 - 1
build-scripts/runtime_lib.cmake

@@ -179,7 +179,11 @@ file (GLOB header
 )
 LIST (APPEND RUNTIME_LIB_HEADER_LIST ${header})
 
-enable_language (ASM)
+if (WAMR_BUILD_PLATFORM STREQUAL "windows")
+    enable_language (ASM_MASM)
+else()
+    enable_language (ASM)
+endif()
 
 include (${SHARED_PLATFORM_CONFIG})
 include (${SHARED_DIR}/mem-alloc/mem_alloc.cmake)

+ 2 - 2
core/app-mgr/README.md

@@ -1,8 +1,8 @@
 # Remote application management
 
-The WAMR application manager supports [remote application management](../core/app-mgr) from the host environment or the cloud through any physical communications such as TCP, UPD, UART, BLE, etc. Its modular design makes it able to support application management for different managed runtimes.
+The WAMR application manager supports [remote application management](../../core/app-mgr) from the host environment or the cloud through any physical communications such as TCP, UPD, UART, BLE, etc. Its modular design makes it able to support application management for different managed runtimes.
 
-The tool [host_tool](../test-tools/host-tool) communicates to the WAMR app manager for installing/uninstalling the WASM applications on companion chip from the host system. And the [IoT App Store Demo](../test-tools/IoT-APP-Store-Demo/) shows the conception of remotely managing the device applications from the cloud.
+The tool [host_tool](../../test-tools/host-tool) communicates to the WAMR app manager for installing/uninstalling the WASM applications on companion chip from the host system. And the [IoT App Store Demo](../../test-tools/IoT-APP-Store-Demo/) shows the conception of remotely managing the device applications from the cloud.
 
 
 <img src="../../doc/pics/wamr-arch.JPG" width="80%">

+ 1 - 1
core/app-mgr/app-manager/module_wasm_app.c

@@ -1467,7 +1467,7 @@ wasm_app_module_on_install_request_byte_arrive(uint8 ch, int request_total_size,
                     if (total_size >= UINT32_MAX
                         || !(section->section_body =
                                  os_mmap(NULL, (uint32)total_size, map_prot,
-                                         map_flags))) {
+                                         map_flags, os_get_invalid_handle()))) {
                         app_manager_printf(
                             "Allocate executable memory failed!\n");
                         SEND_ERR_RESPONSE(recv_ctx.message.request_mid,

+ 6 - 1
core/config.h

@@ -330,6 +330,11 @@
 #define BH_ENABLE_GC_VERIFY 0
 #endif
 
+/* Heap corruption check, enabled by default */
+#ifndef BH_ENABLE_GC_CORRUPTION_CHECK
+#define BH_ENABLE_GC_CORRUPTION_CHECK 1
+#endif
+
 /* Enable global heap pool if heap verification is enabled */
 #if BH_ENABLE_GC_VERIFY != 0
 #define WASM_ENABLE_GLOBAL_HEAP_POOL 1
@@ -515,7 +520,7 @@
 /* Some chip cannot support external ram with rwx attr at the same time,
    it has to map it into 2 spaces of idbus and dbus, code in dbus can be
    read/written and read/executed in ibus. so there are 2 steps to execute
-   the code, first, copy&do relocaiton in dbus space, and second execute
+   the code, first, copy & do relocation in dbus space, and second execute
    it in ibus space, since in the 2 spaces the contents are the same,
    so we call it bus mirror.
  */

+ 10 - 7
core/iwasm/aot/aot_loader.c

@@ -1286,7 +1286,6 @@ load_table_init_data_list(const uint8 **p_buf, const uint8 *buf_end,
 
         data_list[i]->mode = mode;
         data_list[i]->elem_type = elem_type;
-        data_list[i]->is_dropped = false;
         data_list[i]->table_index = table_index;
 #if WASM_ENABLE_GC != 0
         if (wasm_is_type_multi_byte_type(elem_type)) {
@@ -2098,8 +2097,9 @@ load_object_data_sections(const uint8 **p_buf, const uint8 *buf_end,
 
         /* 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))) {
+            && !(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");
             return false;
         }
@@ -3022,7 +3022,8 @@ load_relocation_section(const uint8 *buf, const uint8 *buf_end,
 
         if (size > UINT32_MAX
             || !(module->extra_plt_data =
-                     os_mmap(NULL, (uint32)size, map_prot, map_flags))) {
+                     os_mmap(NULL, (uint32)size, map_prot, map_flags,
+                             os_get_invalid_handle()))) {
             set_error_buf(error_buf, error_buf_size, "mmap memory failed");
             goto fail;
         }
@@ -3145,7 +3146,8 @@ load_relocation_section(const uint8 *buf, const uint8 *buf_end,
         size = (uint64)sizeof(void *) * got_item_count;
         if (size > UINT32_MAX
             || !(module->got_func_ptrs =
-                     os_mmap(NULL, (uint32)size, map_prot, map_flags))) {
+                     os_mmap(NULL, (uint32)size, map_prot, map_flags,
+                             os_get_invalid_handle()))) {
             set_error_buf(error_buf, error_buf_size, "mmap memory failed");
             goto fail;
         }
@@ -3679,8 +3681,9 @@ create_sections(AOTModule *module, const uint8 *buf, uint32 size,
                         (uint64)section_size + aot_get_plt_table_size();
                     total_size = (total_size + 3) & ~((uint64)3);
                     if (total_size >= UINT32_MAX
-                        || !(aot_text = os_mmap(NULL, (uint32)total_size,
-                                                map_prot, map_flags))) {
+                        || !(aot_text =
+                                 os_mmap(NULL, (uint32)total_size, map_prot,
+                                         map_flags, os_get_invalid_handle()))) {
                         wasm_runtime_free(section);
                         set_error_buf(error_buf, error_buf_size,
                                       "mmap memory failed");

+ 90 - 30
core/iwasm/aot/aot_runtime.c

@@ -605,6 +605,12 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModuleInstance *parent,
         if (max_page_count > DEFAULT_MAX_PAGES)
             max_page_count = DEFAULT_MAX_PAGES;
     }
+    else { /* heap_size == 0 */
+        if (init_page_count == DEFAULT_MAX_PAGES) {
+            num_bytes_per_page = UINT32_MAX;
+            init_page_count = max_page_count = 1;
+        }
+    }
 
     LOG_VERBOSE("Memory instantiate:");
     LOG_VERBOSE("  page bytes: %u, init pages: %u, max pages: %u",
@@ -647,8 +653,8 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModuleInstance *parent,
      * both i and memarg.offset are u32 in range 0 to 4G
      * so the range of ea is 0 to 8G
      */
-    if (!(p = mapped_mem =
-              os_mmap(NULL, map_size, MMAP_PROT_NONE, MMAP_MAP_NONE))) {
+    if (!(p = mapped_mem = os_mmap(NULL, map_size, MMAP_PROT_NONE,
+                                   MMAP_MAP_NONE, os_get_invalid_handle()))) {
         set_error_buf(error_buf, error_buf_size, "mmap memory failed");
         return NULL;
     }
@@ -715,7 +721,7 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModuleInstance *parent,
 
 #if WASM_ENABLE_SHARED_MEMORY != 0
     if (is_shared_memory) {
-        memory_inst->is_shared_memory = true;
+        memory_inst->is_shared_memory = 1;
         memory_inst->ref_count = 1;
     }
 #endif
@@ -1092,7 +1098,8 @@ execute_post_instantiate_functions(AOTModuleInstance *module_inst,
            wasm functions, and ensure that the exec_env's module inst
            is the correct one. */
         module_inst_main = exec_env_main->module_inst;
-        exec_env->module_inst = (WASMModuleInstanceCommon *)module_inst;
+        wasm_exec_env_set_module_inst(exec_env,
+                                      (WASMModuleInstanceCommon *)module_inst);
     }
     else {
         /* Try using the existing exec_env */
@@ -1117,7 +1124,8 @@ execute_post_instantiate_functions(AOTModuleInstance *module_inst,
                module inst to ensure that the exec_env's module inst
                is the correct one. */
             module_inst_main = exec_env->module_inst;
-            exec_env->module_inst = (WASMModuleInstanceCommon *)module_inst;
+            wasm_exec_env_set_module_inst(
+                exec_env, (WASMModuleInstanceCommon *)module_inst);
         }
     }
 
@@ -1168,12 +1176,12 @@ execute_post_instantiate_functions(AOTModuleInstance *module_inst,
 fail:
     if (is_sub_inst) {
         /* Restore the parent exec_env's module inst */
-        exec_env_main->module_inst = module_inst_main;
+        wasm_exec_env_restore_module_inst(exec_env_main, module_inst_main);
     }
     else {
         if (module_inst_main)
             /* Restore the existing exec_env's module inst */
-            exec_env->module_inst = module_inst_main;
+            wasm_exec_env_restore_module_inst(exec_env, module_inst_main);
         if (exec_env_created)
             wasm_exec_env_destroy(exec_env_created);
     }
@@ -1207,6 +1215,9 @@ aot_instantiate(AOTModule *module, AOTModuleInstance *parent,
                 char *error_buf, uint32 error_buf_size)
 {
     AOTModuleInstance *module_inst;
+#if WASM_ENABLE_BULK_MEMORY != 0 || WASM_ENABLE_REF_TYPES != 0
+    WASMModuleInstanceExtraCommon *common;
+#endif
     const uint32 module_inst_struct_size =
         offsetof(AOTModuleInstance, global_table_data.bytes);
     const uint64 module_inst_mem_inst_size =
@@ -1303,6 +1314,32 @@ aot_instantiate(AOTModule *module, AOTModuleInstance *parent,
     if (!init_func_type_indexes(module_inst, module, error_buf, error_buf_size))
         goto fail;
 
+#if WASM_ENABLE_BULK_MEMORY != 0 || WASM_ENABLE_REF_TYPES != 0
+    common = &((AOTModuleInstanceExtra *)module_inst->e)->common;
+#endif
+#if WASM_ENABLE_BULK_MEMORY != 0
+    if (module->mem_init_data_count > 0) {
+        common->data_dropped = bh_bitmap_new(0, module->mem_init_data_count);
+        if (common->data_dropped == NULL) {
+            LOG_DEBUG("failed to allocate bitmaps");
+            set_error_buf(error_buf, error_buf_size,
+                          "failed to allocate bitmaps");
+            goto fail;
+        }
+    }
+#endif
+#if WASM_ENABLE_REF_TYPES != 0
+    if (module->table_init_data_count > 0) {
+        common->elem_dropped = bh_bitmap_new(0, module->table_init_data_count);
+        if (common->elem_dropped == NULL) {
+            LOG_DEBUG("failed to allocate bitmaps");
+            set_error_buf(error_buf, error_buf_size,
+                          "failed to allocate bitmaps");
+            goto fail;
+        }
+    }
+#endif
+
     /* Initialize global info */
     p = (uint8 *)module_inst + module_inst_struct_size
         + module_inst_mem_inst_size;
@@ -1522,6 +1559,8 @@ destroy_c_api_frames(Vector *frames)
 void
 aot_deinstantiate(AOTModuleInstance *module_inst, bool is_sub_inst)
 {
+    WASMModuleInstanceExtraCommon *common =
+        &((AOTModuleInstanceExtra *)module_inst->e)->common;
     if (module_inst->exec_env_singleton) {
         /* wasm_exec_env_destroy will call
            wasm_cluster_wait_for_all_except_self to wait for other
@@ -1564,7 +1603,7 @@ aot_deinstantiate(AOTModuleInstance *module_inst, bool is_sub_inst)
     if (module_inst->func_type_indexes)
         wasm_runtime_free(module_inst->func_type_indexes);
 
-    if (((AOTModuleInstanceExtra *)module_inst->e)->common.c_api_func_imports)
+    if (common->c_api_func_imports)
         wasm_runtime_free(((AOTModuleInstanceExtra *)module_inst->e)
                               ->common.c_api_func_imports);
 
@@ -1586,6 +1625,13 @@ aot_deinstantiate(AOTModuleInstance *module_inst, bool is_sub_inst)
         wasm_native_call_context_dtors((WASMModuleInstanceCommon *)module_inst);
     }
 
+#if WASM_ENABLE_BULK_MEMORY != 0
+    bh_bitmap_delete(common->data_dropped);
+#endif
+#if WASM_ENABLE_REF_TYPES != 0
+    bh_bitmap_delete(common->elem_dropped);
+#endif
+
     wasm_runtime_free(module_inst);
 }
 
@@ -2019,7 +2065,8 @@ execute_malloc_function(AOTModuleInstance *module_inst, WASMExecEnv *exec_env,
                module inst to ensure that the exec_env's module inst
                is the correct one. */
             module_inst_old = exec_env->module_inst;
-            exec_env->module_inst = (WASMModuleInstanceCommon *)module_inst;
+            wasm_exec_env_set_module_inst(
+                exec_env, (WASMModuleInstanceCommon *)module_inst);
         }
     }
 
@@ -2030,7 +2077,7 @@ execute_malloc_function(AOTModuleInstance *module_inst, WASMExecEnv *exec_env,
 
     if (module_inst_old)
         /* Restore the existing exec_env's module inst */
-        exec_env->module_inst = module_inst_old;
+        wasm_exec_env_restore_module_inst(exec_env, module_inst_old);
 
     if (exec_env_created)
         wasm_exec_env_destroy(exec_env_created);
@@ -2086,7 +2133,8 @@ execute_free_function(AOTModuleInstance *module_inst, WASMExecEnv *exec_env,
                module inst to ensure that the exec_env's module inst
                is the correct one. */
             module_inst_old = exec_env->module_inst;
-            exec_env->module_inst = (WASMModuleInstanceCommon *)module_inst;
+            wasm_exec_env_set_module_inst(
+                exec_env, (WASMModuleInstanceCommon *)module_inst);
         }
     }
 
@@ -2094,7 +2142,7 @@ execute_free_function(AOTModuleInstance *module_inst, WASMExecEnv *exec_env,
 
     if (module_inst_old)
         /* Restore the existing exec_env's module inst */
-        exec_env->module_inst = module_inst_old;
+        wasm_exec_env_restore_module_inst(exec_env, module_inst_old);
 
     if (exec_env_created)
         wasm_exec_env_destroy(exec_env_created);
@@ -2612,13 +2660,21 @@ aot_memory_init(AOTModuleInstance *module_inst, uint32 seg_index, uint32 offset,
 {
     AOTMemoryInstance *memory_inst = aot_get_default_memory(module_inst);
     AOTModule *aot_module;
-    uint8 *data = NULL;
+    uint8 *data;
     uint8 *maddr;
-    uint64 seg_len = 0;
+    uint64 seg_len;
 
-    aot_module = (AOTModule *)module_inst->module;
-    seg_len = aot_module->mem_init_data_list[seg_index]->byte_count;
-    data = aot_module->mem_init_data_list[seg_index]->bytes;
+    if (bh_bitmap_get_bit(
+            ((AOTModuleInstanceExtra *)module_inst->e)->common.data_dropped,
+            seg_index)) {
+        seg_len = 0;
+        data = NULL;
+    }
+    else {
+        aot_module = (AOTModule *)module_inst->module;
+        seg_len = aot_module->mem_init_data_list[seg_index]->byte_count;
+        data = aot_module->mem_init_data_list[seg_index]->bytes;
+    }
 
     if (!wasm_runtime_validate_app_addr((WASMModuleInstanceCommon *)module_inst,
                                         dst, len))
@@ -2641,9 +2697,9 @@ aot_memory_init(AOTModuleInstance *module_inst, uint32 seg_index, uint32 offset,
 bool
 aot_data_drop(AOTModuleInstance *module_inst, uint32 seg_index)
 {
-    AOTModule *aot_module = (AOTModule *)module_inst->module;
-
-    aot_module->mem_init_data_list[seg_index]->byte_count = 0;
+    bh_bitmap_set_bit(
+        ((AOTModuleInstanceExtra *)module_inst->e)->common.data_dropped,
+        seg_index);
     /* Currently we can't free the dropped data segment
        as the mem_init_data_count is a continuous array */
     return true;
@@ -2856,9 +2912,9 @@ aot_get_module_inst_mem_consumption(const AOTModuleInstance *module_inst,
 void
 aot_drop_table_seg(AOTModuleInstance *module_inst, uint32 tbl_seg_idx)
 {
-    AOTModule *module = (AOTModule *)module_inst->module;
-    AOTTableInitData *tbl_seg = module->table_init_data_list[tbl_seg_idx];
-    tbl_seg->is_dropped = true;
+    bh_bitmap_set_bit(
+        ((AOTModuleInstanceExtra *)module_inst->e)->common.elem_dropped,
+        tbl_seg_idx);
 }
 
 void
@@ -2892,7 +2948,9 @@ aot_table_init(AOTModuleInstance *module_inst, uint32 tbl_idx,
         return;
     }
 
-    if (tbl_seg->is_dropped) {
+    if (bh_bitmap_get_bit(
+            ((AOTModuleInstanceExtra *)module_inst->e)->common.elem_dropped,
+            tbl_seg_idx)) {
         aot_set_exception_with_id(module_inst, EXCE_OUT_OF_BOUNDS_TABLE_ACCESS);
         return;
     }
@@ -3352,13 +3410,15 @@ aot_dump_perf_profiling(const AOTModuleInstance *module_inst)
         func_name = get_func_name_from_index(module_inst, i);
 
         if (func_name)
-            os_printf("  func %s, execution time: %.3f ms, execution count: %d "
-                      "times\n",
-                      func_name, perf_prof->total_exec_time / 1000.0f,
-                      perf_prof->total_exec_cnt);
+            os_printf(
+                "  func %s, execution time: %.3f ms, execution count: %" PRIu32
+                " times\n",
+                func_name, perf_prof->total_exec_time / 1000.0f,
+                perf_prof->total_exec_cnt);
         else
-            os_printf("  func %d, execution time: %.3f ms, execution count: %d "
-                      "times\n",
+            os_printf("  func %" PRIu32
+                      ", execution time: %.3f ms, execution count: %" PRIu32
+                      " times\n",
                       i, perf_prof->total_exec_time / 1000.0f,
                       perf_prof->total_exec_cnt);
     }

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

@@ -177,7 +177,11 @@ rv_set_val(uint16 *addr, uint32 val)
     *addr = (val & 0xffff);
     *(addr + 1) = (val >> 16);
 
+#ifdef __riscv_zifencei
     __asm__ volatile("fence.i");
+#else
+    __asm__ volatile("fence");
+#endif
 }
 
 /* Add a val to given address */

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

@@ -417,6 +417,18 @@ execute_func(WASMModuleInstanceCommon *module_inst, const char *name,
             {
                 float32 f32 = strtof(argv[i], &endptr);
                 if (isnan(f32)) {
+#ifdef _MSC_VER
+                    /*
+                     * Spec tests require the binary representation of NaN to be
+                     * 0x7fc00000 for float and 0x7ff8000000000000 for float;
+                     * however, in MSVC compiler, strtof doesn't return this
+                     * exact value, causing some of the spec test failures. We
+                     * use the value returned by nan/nanf as it is the one
+                     * expected by spec tests.
+                     *
+                     */
+                    f32 = nanf("");
+#endif
                     if (argv[i][0] == '-') {
                         union ieee754_float u;
                         u.f = f32;
@@ -451,6 +463,9 @@ execute_func(WASMModuleInstanceCommon *module_inst, const char *name,
                 } u;
                 u.val = strtod(argv[i], &endptr);
                 if (isnan(u.val)) {
+#ifdef _MSC_VER
+                    u.val = nan("");
+#endif
                     if (argv[i][0] == '-') {
                         union ieee754_double ud;
                         ud.d = u.val;
@@ -657,7 +672,7 @@ execute_func(WASMModuleInstanceCommon *module_inst, const char *name,
             {
 #if UINTPTR_MAX == UINT32_MAX
                 if (argv1[k] != 0 && argv1[k] != (uint32)-1)
-                    os_printf("%p:ref.extern", (void *)argv1[k]);
+                    os_printf("0x%" PRIxPTR ":ref.extern", (uintptr_t)argv1[k]);
                 else
                     os_printf("extern:ref.null");
                 k++;
@@ -670,7 +685,7 @@ execute_func(WASMModuleInstanceCommon *module_inst, const char *name,
                 u.parts[1] = argv1[k + 1];
                 k += 2;
                 if (u.val && u.val != (uintptr_t)-1LL)
-                    os_printf("%p:ref.extern", (void *)u.val);
+                    os_printf("0x%" PRIxPTR ":ref.extern", u.val);
                 else
                     os_printf("extern:ref.null");
 #endif

+ 47 - 1
core/iwasm/common/wasm_exec_env.c

@@ -61,7 +61,8 @@ wasm_exec_env_create_internal(struct WASMModuleInstanceCommon *module_inst,
 
 #ifdef OS_ENABLE_HW_BOUND_CHECK
     if (!(exec_env->exce_check_guard_page =
-              os_mmap(NULL, os_getpagesize(), MMAP_PROT_NONE, MMAP_MAP_NONE)))
+              os_mmap(NULL, os_getpagesize(), MMAP_PROT_NONE, MMAP_MAP_NONE,
+                      os_get_invalid_handle())))
         goto fail5;
 #endif
 
@@ -223,7 +224,52 @@ void
 wasm_exec_env_set_module_inst(WASMExecEnv *exec_env,
                               WASMModuleInstanceCommon *const module_inst)
 {
+#if WASM_ENABLE_THREAD_MGR != 0
+    wasm_cluster_traverse_lock(exec_env);
+#endif
     exec_env->module_inst = module_inst;
+#if WASM_ENABLE_THREAD_MGR != 0
+    wasm_cluster_traverse_unlock(exec_env);
+#endif
+}
+
+void
+wasm_exec_env_restore_module_inst(
+    WASMExecEnv *exec_env, WASMModuleInstanceCommon *const module_inst_common)
+{
+    WASMModuleInstanceCommon *old_module_inst_common = exec_env->module_inst;
+    WASMModuleInstance *old_module_inst =
+        (WASMModuleInstance *)old_module_inst_common;
+    WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_common;
+    char cur_exception[EXCEPTION_BUF_LEN];
+
+#if WASM_ENABLE_THREAD_MGR != 0
+    wasm_cluster_traverse_lock(exec_env);
+#endif
+    exec_env->module_inst = module_inst_common;
+    /*
+     * propagate an exception if any.
+     */
+    exception_lock(old_module_inst);
+    if (old_module_inst->cur_exception[0] != '\0') {
+        bh_memcpy_s(cur_exception, sizeof(cur_exception),
+                    old_module_inst->cur_exception,
+                    sizeof(old_module_inst->cur_exception));
+    }
+    else {
+        cur_exception[0] = '\0';
+    }
+    exception_unlock(old_module_inst);
+#if WASM_ENABLE_THREAD_MGR != 0
+    wasm_cluster_traverse_unlock(exec_env);
+#endif
+    if (cur_exception[0] != '\0') {
+        exception_lock(module_inst);
+        bh_memcpy_s(module_inst->cur_exception,
+                    sizeof(module_inst->cur_exception), cur_exception,
+                    sizeof(cur_exception));
+        exception_unlock(module_inst);
+    }
 }
 
 void

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

@@ -293,6 +293,10 @@ void
 wasm_exec_env_set_module_inst(
     WASMExecEnv *exec_env, struct WASMModuleInstanceCommon *const module_inst);
 
+void
+wasm_exec_env_restore_module_inst(
+    WASMExecEnv *exec_env, struct WASMModuleInstanceCommon *const module_inst);
+
 void
 wasm_exec_env_set_thread_info(WASMExecEnv *exec_env);
 

+ 1 - 1
core/iwasm/common/wasm_memory.c

@@ -95,7 +95,7 @@ wasm_memory_init_with_allocator(void *_malloc_func, void *_realloc_func,
 static inline bool
 is_bounds_checks_enabled(WASMModuleInstanceCommon *module_inst)
 {
-#if WASM_CONFIGUABLE_BOUNDS_CHECKS != 0
+#if WASM_CONFIGURABLE_BOUNDS_CHECKS != 0
     return wasm_runtime_is_bounds_checks_enabled(module_inst);
 #else
     return true;

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

@@ -161,7 +161,7 @@ static JitCompOptions jit_options = { 0 };
 #endif
 
 #if WASM_ENABLE_JIT != 0
-static LLVMJITOptions llvm_jit_options = { 3, 3, 0 };
+static LLVMJITOptions llvm_jit_options = { 3, 3, 0, false };
 #endif
 
 #if WASM_ENABLE_GC != 0
@@ -681,9 +681,14 @@ wasm_runtime_full_init(RuntimeInitArgs *init_args)
 #endif
 
 #if WASM_ENABLE_JIT != 0
+    LOG_DEBUG("Start LLVM_JIT, opt_sz=%u, opt_lvl=%u, segue=%s, linux_perf=%s",
+              init_args->llvm_jit_size_level, init_args->llvm_jit_opt_level,
+              init_args->segue_flags ? "Yes" : "No",
+              init_args->linux_perf_support ? "Yes" : "No");
     llvm_jit_options.size_level = init_args->llvm_jit_size_level;
     llvm_jit_options.opt_level = init_args->llvm_jit_opt_level;
     llvm_jit_options.segue_flags = init_args->segue_flags;
+    llvm_jit_options.linux_perf_support = init_args->linux_perf_support;
 #endif
 
     if (!wasm_runtime_env_init()) {
@@ -2637,7 +2642,7 @@ wasm_runtime_get_custom_data(WASMModuleInstanceCommon *module_inst_comm)
     return module_inst->custom_data;
 }
 
-#if WASM_CONFIGUABLE_BOUNDS_CHECKS != 0
+#if WASM_CONFIGURABLE_BOUNDS_CHECKS != 0
 void
 wasm_runtime_set_bounds_checks(WASMModuleInstanceCommon *module_inst,
                                bool enable)
@@ -2834,7 +2839,7 @@ wasm_runtime_set_wasi_args_ex(WASMModuleCommon *module, const char *dir_list[],
                               uint32 dir_count, const char *map_dir_list[],
                               uint32 map_dir_count, const char *env_list[],
                               uint32 env_count, char *argv[], int argc,
-                              int stdinfd, int stdoutfd, int stderrfd)
+                              int64 stdinfd, int64 stdoutfd, int64 stderrfd)
 {
     WASIArguments *wasi_args = get_wasi_args_from_module(module);
 
@@ -2848,9 +2853,9 @@ wasm_runtime_set_wasi_args_ex(WASMModuleCommon *module, const char *dir_list[],
     wasi_args->env_count = env_count;
     wasi_args->argv = argv;
     wasi_args->argc = (uint32)argc;
-    wasi_args->stdio[0] = stdinfd;
-    wasi_args->stdio[1] = stdoutfd;
-    wasi_args->stdio[2] = stderrfd;
+    wasi_args->stdio[0] = (os_raw_file_handle)stdinfd;
+    wasi_args->stdio[1] = (os_raw_file_handle)stdoutfd;
+    wasi_args->stdio[2] = (os_raw_file_handle)stderrfd;
 
 #if WASM_ENABLE_MULTI_MODULE != 0
 #if WASM_ENABLE_INTERP != 0
@@ -2945,8 +2950,9 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst,
                        const char *env[], uint32 env_count,
                        const char *addr_pool[], uint32 addr_pool_size,
                        const char *ns_lookup_pool[], uint32 ns_lookup_pool_size,
-                       char *argv[], uint32 argc, int stdinfd, int stdoutfd,
-                       int stderrfd, char *error_buf, uint32 error_buf_size)
+                       char *argv[], uint32 argc, os_raw_file_handle stdinfd,
+                       os_raw_file_handle stdoutfd, os_raw_file_handle stderrfd,
+                       char *error_buf, uint32 error_buf_size)
 {
     WASIContext *wasi_ctx;
     char *argv_buf = NULL;
@@ -2964,7 +2970,7 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst,
     bool argv_environ_inited = false;
     bool addr_pool_inited = false;
     __wasi_fd_t wasm_fd = 3;
-    int32 raw_fd;
+    os_file_handle file_handle;
     char *path, resolved_path[PATH_MAX];
     uint32 i;
 
@@ -3034,15 +3040,19 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst,
     }
     addr_pool_inited = true;
 
-    /* Prepopulate curfds with stdin, stdout, and stderr file descriptors.
-     *
-     * If -1 is given, use STDIN_FILENO (0), STDOUT_FILENO (1),
-     * STDERR_FILENO (2) respectively.
-     */
-    if (!fd_table_insert_existing(curfds, 0, (stdinfd != -1) ? stdinfd : 0)
-        || !fd_table_insert_existing(curfds, 1, (stdoutfd != -1) ? stdoutfd : 1)
-        || !fd_table_insert_existing(curfds, 2,
-                                     (stderrfd != -1) ? stderrfd : 2)) {
+    os_file_handle stdin_file_handle = os_convert_stdin_handle(stdinfd);
+    os_file_handle stdout_file_handle = os_convert_stdout_handle(stdoutfd);
+    os_file_handle stderr_file_handle = os_convert_stderr_handle(stderrfd);
+
+    if (!os_is_handle_valid(&stdin_file_handle)
+        || !os_is_handle_valid(&stdout_file_handle)
+        || !os_is_handle_valid(&stderr_file_handle))
+        goto fail;
+
+    /* Prepopulate curfds with stdin, stdout, and stderr file descriptors. */
+    if (!fd_table_insert_existing(curfds, 0, stdin_file_handle, true)
+        || !fd_table_insert_existing(curfds, 1, stdout_file_handle, true)
+        || !fd_table_insert_existing(curfds, 2, stderr_file_handle, true)) {
         set_error_buf(error_buf, error_buf_size,
                       "Init wasi environment failed: init fd table failed");
         goto fail;
@@ -3050,7 +3060,7 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst,
 
     wasm_fd = 3;
     for (i = 0; i < dir_count; i++, wasm_fd++) {
-        path = realpath(dir_list[i], resolved_path);
+        path = os_realpath(dir_list[i], resolved_path);
         if (!path) {
             if (error_buf)
                 snprintf(error_buf, error_buf_size,
@@ -3059,22 +3069,31 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst,
             goto fail;
         }
 
-        raw_fd = open(path, O_RDONLY | O_DIRECTORY, 0);
-        if (raw_fd == -1) {
+        __wasi_errno_t error = os_open_preopendir(path, &file_handle);
+
+        if (error != __WASI_ESUCCESS) {
             if (error_buf)
                 snprintf(error_buf, error_buf_size,
                          "error while pre-opening directory %s: %d\n",
-                         dir_list[i], errno);
+                         dir_list[i], error);
             goto fail;
         }
 
-        if (!fd_table_insert_existing(curfds, wasm_fd, raw_fd)
-            || !fd_prestats_insert(prestats, dir_list[i], wasm_fd)) {
+        if (!fd_table_insert_existing(curfds, wasm_fd, file_handle, false)) {
             if (error_buf)
-                snprintf(
-                    error_buf, error_buf_size,
-                    "error while pre-opening directory %s: insertion failed\n",
-                    dir_list[i]);
+                snprintf(error_buf, error_buf_size,
+                         "error inserting preopen fd %u (directory %s) into fd "
+                         "table",
+                         (unsigned int)wasm_fd, dir_list[i]);
+            goto fail;
+        }
+
+        if (!fd_prestats_insert(prestats, dir_list[i], wasm_fd)) {
+            if (error_buf)
+                snprintf(error_buf, error_buf_size,
+                         "error inserting preopen fd %u (directory %s) into "
+                         "prestats table",
+                         (unsigned int)wasm_fd, dir_list[i]);
             goto fail;
         }
     }
@@ -3109,7 +3128,7 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst,
             goto fail;
         }
 
-        path = realpath(map_host, resolved_path);
+        path = os_realpath(map_host, resolved_path);
         if (!path) {
             if (error_buf)
                 snprintf(error_buf, error_buf_size,
@@ -3120,8 +3139,8 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst,
             goto fail;
         }
 
-        raw_fd = open(path, O_RDONLY | O_DIRECTORY, 0);
-        if (raw_fd == -1) {
+        __wasi_errno_t error = os_open_preopendir(path, &file_handle);
+        if (error != __WASI_ESUCCESS) {
             if (error_buf)
                 snprintf(error_buf, error_buf_size,
                          "error while pre-opening mapped directory %s: %d\n",
@@ -3131,7 +3150,7 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst,
             goto fail;
         }
 
-        if (!fd_table_insert_existing(curfds, wasm_fd, raw_fd)
+        if (!fd_table_insert_existing(curfds, wasm_fd, file_handle, false)
             || !fd_prestats_insert(prestats, map_mapped, wasm_fd)) {
             if (error_buf)
                 snprintf(error_buf, error_buf_size,
@@ -3272,8 +3291,9 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst,
                        const char *env[], uint32 env_count,
                        const char *addr_pool[], uint32 addr_pool_size,
                        const char *ns_lookup_pool[], uint32 ns_lookup_pool_size,
-                       char *argv[], uint32 argc, int stdinfd, int stdoutfd,
-                       int stderrfd, char *error_buf, uint32 error_buf_size)
+                       char *argv[], uint32 argc, os_raw_file_handle stdinfd,
+                       os_raw_file_handle stdoutfd, os_raw_file_handle stderrfd,
+                       char *error_buf, uint32 error_buf_size)
 {
     WASIContext *ctx;
     uvwasi_t *uvwasi;

+ 6 - 5
core/iwasm/common/wasm_runtime_common.h

@@ -18,7 +18,6 @@
 
 #if WASM_ENABLE_LIBC_WASI != 0
 #if WASM_ENABLE_UVWASI == 0
-#include "wasmtime_ssp.h"
 #include "posix.h"
 #else
 #include "uvwasi.h"
@@ -477,6 +476,7 @@ typedef struct LLVMJITOptions {
     uint32 opt_level;
     uint32 size_level;
     uint32 segue_flags;
+    bool linux_perf_support;
 } LLVMJITOptions;
 #endif
 
@@ -656,7 +656,7 @@ wasm_runtime_set_user_data(WASMExecEnv *exec_env, void *user_data);
 WASM_RUNTIME_API_EXTERN void *
 wasm_runtime_get_user_data(WASMExecEnv *exec_env);
 
-#if WASM_CONFIGUABLE_BOUNDS_CHECKS != 0
+#if WASM_CONFIGURABLE_BOUNDS_CHECKS != 0
 /* See wasm_export.h for description */
 WASM_RUNTIME_API_EXTERN void
 wasm_runtime_set_bounds_checks(WASMModuleInstanceCommon *module_inst,
@@ -915,7 +915,7 @@ wasm_runtime_set_wasi_args_ex(WASMModuleCommon *module, const char *dir_list[],
                               uint32 dir_count, const char *map_dir_list[],
                               uint32 map_dir_count, const char *env_list[],
                               uint32 env_count, char *argv[], int argc,
-                              int stdinfd, int stdoutfd, int stderrfd);
+                              int64 stdinfd, int64 stdoutfd, int64 stderrfd);
 
 /* See wasm_export.h for description */
 WASM_RUNTIME_API_EXTERN void
@@ -943,8 +943,9 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst,
                        const char *env[], uint32 env_count,
                        const char *addr_pool[], uint32 addr_pool_size,
                        const char *ns_lookup_pool[], uint32 ns_lookup_pool_size,
-                       char *argv[], uint32 argc, int stdinfd, int stdoutfd,
-                       int stderrfd, char *error_buf, uint32 error_buf_size);
+                       char *argv[], uint32 argc, os_raw_file_handle stdinfd,
+                       os_raw_file_handle stdoutfd, os_raw_file_handle stderrfd,
+                       char *error_buf, uint32 error_buf_size);
 
 void
 wasm_runtime_destroy_wasi(WASMModuleInstanceCommon *module_inst);

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

@@ -129,7 +129,6 @@ aot_create_table_init_data_list(const WASMModule *module)
         data_list[i]->mode = module->table_segments[i].mode;
         data_list[i]->elem_type = module->table_segments[i].elem_type;
         /* runtime control it */
-        data_list[i]->is_dropped = false;
         data_list[i]->table_index = module->table_segments[i].table_index;
         bh_memcpy_s(&data_list[i]->offset, sizeof(AOTInitExpr),
                     &module->table_segments[i].base_offset,

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

@@ -157,7 +157,6 @@ typedef struct AOTTableInitData {
 #if WASM_ENABLE_GC != 0
     WASMRefType *elem_ref_type;
 #endif
-    bool is_dropped;
     /* optional, only for active */
     uint32 table_index;
     /* Start address of init data */

+ 3 - 1
core/iwasm/compilation/aot_emit_aot_file.c

@@ -268,7 +268,7 @@ get_table_init_data_size(AOTCompContext *comp_ctx,
                          AOTTableInitData *table_init_data)
 {
     /*
-     * mode (4 bytes), elem_type (4 bytes), do not need is_dropped field
+     * mode (4 bytes), elem_type (4 bytes)
      *
      * table_index(4 bytes) + init expr type (4 bytes) + init expr value (8
      * bytes) + sizeof(WASMRefType)
@@ -1059,9 +1059,11 @@ get_native_symbol_list_size(AOTCompContext *comp_ctx)
 static uint32
 get_name_section_size(AOTCompData *comp_data);
 
+#if WASM_ENABLE_STRINGREF != 0
 static uint32
 get_string_literal_section_size(AOTCompContext *comp_ctx,
                                 AOTCompData *comp_data);
+#endif
 
 static uint32
 get_custom_sections_size(AOTCompContext *comp_ctx, AOTCompData *comp_data);

+ 4 - 3
core/iwasm/compilation/aot_emit_function.c

@@ -24,13 +24,14 @@
 static bool
 is_win_platform(AOTCompContext *comp_ctx)
 {
-    bool ret = false;
     char *triple = LLVMGetTargetMachineTriple(comp_ctx->target_machine);
+    bool ret;
 
     bh_assert(triple);
-    if (strstr(triple, "win32") || strstr(triple, "win"))
-        ret = true;
+    ret = (strstr(triple, "win32") || strstr(triple, "win")) ? true : false;
+
     LLVMDisposeMessage(triple);
+
     return ret;
 }
 

+ 90 - 9
core/iwasm/compilation/aot_llvm.c

@@ -182,6 +182,13 @@ aot_target_precheck_can_use_musttail(const AOTCompContext *comp_ctx)
          */
         return false;
     }
+    if (strstr(comp_ctx->target_arch, "thumb")) {
+        /*
+         * cf.
+         * https://github.com/bytecodealliance/wasm-micro-runtime/issues/2412
+         */
+        return false;
+    }
     /*
      * x86-64/i386: true
      *
@@ -727,6 +734,19 @@ aot_add_llvm_func(AOTCompContext *comp_ctx, LLVMModuleRef module,
                                 attr_no_jump_tables);
     }
 
+    /* spread fp.all to every function */
+    if (comp_ctx->emit_frame_pointer) {
+        const char *key = "frame-pointer";
+        const char *val = "all";
+        LLVMAttributeRef no_omit_fp = LLVMCreateStringAttribute(
+            comp_ctx->context, key, strlen(key), val, strlen(val));
+        if (!no_omit_fp) {
+            aot_set_last_error("create LLVM attribute (frame-pointer) failed.");
+            goto fail;
+        }
+        LLVMAddAttributeAtIndex(func, LLVMAttributeFunctionIndex, no_omit_fp);
+    }
+
     if (need_precheck) {
         if (!comp_ctx->is_jit_mode)
             LLVMSetLinkage(func, LLVMInternalLinkage);
@@ -2073,6 +2093,7 @@ static ArchItem valid_archs[] = {
 static const char *valid_abis[] = {
     "gnu",
     "eabi",
+    "eabihf",
     "gnueabihf",
     "msvc",
     "ilp32",
@@ -2088,13 +2109,33 @@ static void
 print_supported_targets()
 {
     uint32 i;
+    const char *target_name;
+
     os_printf("Supported targets:\n");
-    for (i = 0; i < sizeof(valid_archs) / sizeof(ArchItem); i++) {
-        os_printf("%s ", valid_archs[i].arch);
-        if (valid_archs[i].support_eb)
-            os_printf("%seb ", valid_archs[i].arch);
+    /* over the list of all available targets */
+    for (LLVMTargetRef target = LLVMGetFirstTarget(); target != NULL;
+         target = LLVMGetNextTarget(target)) {
+        target_name = LLVMGetTargetName(target);
+        /* Skip mipsel, aarch64_be since prefix mips, aarch64 will cover them */
+        if (strcmp(target_name, "mipsel") == 0)
+            continue;
+        else if (strcmp(target_name, "aarch64_be") == 0)
+            continue;
+
+        if (strcmp(target_name, "x86-64") == 0)
+            os_printf("  x86_64\n");
+        else if (strcmp(target_name, "x86") == 0)
+            os_printf("  i386\n");
+        else {
+            for (i = 0; i < sizeof(valid_archs) / sizeof(ArchItem); i++) {
+                /* If target_name is prefix for valid_archs[i].arch */
+                if ((strncmp(target_name, valid_archs[i].arch,
+                             strlen(target_name))
+                     == 0))
+                    os_printf("  %s\n", valid_archs[i].arch);
+            }
+        }
     }
-    os_printf("\n");
 }
 
 static void
@@ -2150,6 +2191,18 @@ get_target_arch_from_triple(const char *triple, char *arch_buf, uint32 buf_size)
     bh_assert(*triple == '-' || *triple == '\0');
 }
 
+static bool
+is_baremetal_target(const char *target, const char *cpu, const char *abi)
+{
+    /* TODO: support more baremetal targets */
+    if (target) {
+        /* If target is thumbxxx, then it is baremetal target */
+        if (!strncmp(target, "thumb", strlen("thumb")))
+            return true;
+    }
+    return false;
+}
+
 void
 aot_handle_llvm_errmsg(const char *string, LLVMErrorRef err)
 {
@@ -2278,7 +2331,7 @@ jit_stack_size_callback(void *user_data, const char *name, size_t namelen,
 }
 
 static bool
-orc_jit_create(AOTCompContext *comp_ctx)
+orc_jit_create(AOTCompContext *comp_ctx, bool linux_perf_support)
 {
     LLVMErrorRef err;
     LLVMOrcLLLazyJITRef orc_jit = NULL;
@@ -2318,6 +2371,14 @@ orc_jit_create(AOTCompContext *comp_ctx)
     /* Ownership transfer: LLVMOrcLLJITBuilderRef -> LLVMOrcLLJITRef */
     builder = NULL;
 
+    if (linux_perf_support) {
+        LOG_DEBUG("Enable linux perf support");
+        LLVMOrcObjectLayerRef obj_linking_layer =
+            (LLVMOrcObjectLayerRef)LLVMOrcLLLazyJITGetObjLinkingLayer(orc_jit);
+        LLVMOrcRTDyldObjectLinkingLayerRegisterJITEventListener(
+            obj_linking_layer, LLVMCreatePerfJITEventListener());
+    }
+
     /* Ownership transfer: local -> AOTCompContext */
     comp_ctx->orc_jit = orc_jit;
     orc_jit = NULL;
@@ -2372,7 +2433,7 @@ aot_create_comp_context(const AOTCompData *comp_data, aot_comp_option_t option)
     char *triple_norm_new = NULL, *cpu_new = NULL;
     char *err = NULL, *fp_round = "round.tonearest",
          *fp_exce = "fpexcept.strict";
-    char triple_buf[32] = { 0 }, features_buf[128] = { 0 };
+    char triple_buf[128] = { 0 }, features_buf[128] = { 0 };
     uint32 opt_level, size_level, i;
     LLVMCodeModel code_model;
     LLVMTargetDataRef target_data_ref;
@@ -2416,6 +2477,17 @@ aot_create_comp_context(const AOTCompData *comp_data, aot_comp_option_t option)
         goto fail;
     }
 
+    if (option->linux_perf_support) {
+        /* FramePointerKind.All */
+        LLVMMetadataRef val =
+            LLVMValueAsMetadata(LLVMConstInt(LLVMInt32Type(), 2, false));
+        const char *key = "frame-pointer";
+        LLVMAddModuleFlag(comp_ctx->module, LLVMModuleFlagBehaviorWarning, key,
+                          strlen(key), val);
+
+        comp_ctx->emit_frame_pointer = true;
+    }
+
     if (BH_LIST_ERROR == bh_list_init(&comp_ctx->native_symbols)) {
         goto fail;
     }
@@ -2524,7 +2596,7 @@ aot_create_comp_context(const AOTCompData *comp_data, aot_comp_option_t option)
             goto fail;
 
         /* Create LLJIT Instance */
-        if (!orc_jit_create(comp_ctx))
+        if (!orc_jit_create(comp_ctx, option->linux_perf_support))
             goto fail;
     }
     else {
@@ -2673,6 +2745,7 @@ aot_create_comp_context(const AOTCompData *comp_data, aot_comp_option_t option)
              * for Windows/MacOS under Linux host, or generating AOT file for
              * Linux/MacOS under Windows host.
              */
+
             if (!strcmp(abi, "msvc")) {
                 if (!strcmp(arch1, "i386"))
                     vendor_sys = "-pc-win32-";
@@ -2680,7 +2753,10 @@ aot_create_comp_context(const AOTCompData *comp_data, aot_comp_option_t option)
                     vendor_sys = "-pc-windows-";
             }
             else {
-                vendor_sys = "-pc-linux-";
+                if (is_baremetal_target(arch, cpu, abi))
+                    vendor_sys = "-unknown-none-";
+                else
+                    vendor_sys = "-pc-linux-";
             }
 
             bh_assert(strlen(arch1) + strlen(vendor_sys) + strlen(abi)
@@ -2716,6 +2792,11 @@ aot_create_comp_context(const AOTCompData *comp_data, aot_comp_option_t option)
                 if (!abi)
                     abi = "msvc";
             }
+            else if (is_baremetal_target(arch, cpu, abi)) {
+                vendor_sys = "-unknown-none-";
+                if (!abi)
+                    abi = "gnu";
+            }
             else {
                 vendor_sys = "-pc-linux-";
                 if (!abi)

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

@@ -12,6 +12,7 @@
 #include "llvm-c/Target.h"
 #include "llvm-c/Core.h"
 #include "llvm-c/Object.h"
+#include "llvm-c/OrcEE.h"
 #include "llvm-c/ExecutionEngine.h"
 #include "llvm-c/Analysis.h"
 #include "llvm-c/BitWriter.h"
@@ -436,6 +437,8 @@ typedef struct AOTCompContext {
     /* Whether optimize the JITed code */
     bool optimize;
 
+    bool emit_frame_pointer;
+
     /* Enable GC */
     bool enable_gc;
 

+ 10 - 1
core/iwasm/compilation/aot_orc_extra.cpp

@@ -12,11 +12,13 @@
 #include "llvm/ADT/None.h"
 #include "llvm/ADT/Optional.h"
 #endif
+#include "llvm/ExecutionEngine/JITEventListener.h"
+#include "llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h"
 #include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h"
 #include "llvm/ExecutionEngine/Orc/LLJIT.h"
+#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
 #include "llvm/ExecutionEngine/Orc/ObjectTransformLayer.h"
 #include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h"
-#include "llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h"
 #include "llvm/ExecutionEngine/SectionMemoryManager.h"
 #include "llvm/Support/CBindingWrapping.h"
 
@@ -108,6 +110,7 @@ DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ObjectTransformLayer,
                                    LLVMOrcObjectTransformLayerRef)
 DEFINE_SIMPLE_CONVERSION_FUNCTIONS(OrcV2CAPIHelper::PoolEntry,
                                    LLVMOrcSymbolStringPoolEntryRef)
+DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ObjectLayer, LLVMOrcObjectLayerRef)
 DEFINE_SIMPLE_CONVERSION_FUNCTIONS(SymbolStringPool, LLVMOrcSymbolStringPoolRef)
 DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ThreadSafeModule, LLVMOrcThreadSafeModuleRef)
 
@@ -322,3 +325,9 @@ LLVMOrcLLLazyJITGetObjTransformLayer(LLVMOrcLLLazyJITRef J)
 {
     return wrap(&unwrap(J)->getObjTransformLayer());
 }
+
+LLVMOrcObjectLayerRef
+LLVMOrcLLLazyJITGetObjLinkingLayer(LLVMOrcLLLazyJITRef J)
+{
+    return wrap(&unwrap(J)->getObjLinkingLayer());
+}

+ 3 - 0
core/iwasm/compilation/aot_orc_extra.h

@@ -76,5 +76,8 @@ LLVMOrcLLJITBuilderSetCompileFuncitonCreatorWithStackSizesCallback(
     LLVMOrcLLLazyJITBuilderRef Builder,
     void (*cb)(void *, const char *, size_t, size_t), void *cb_data);
 
+LLVMOrcObjectLayerRef
+LLVMOrcLLLazyJITGetObjLinkingLayer(LLVMOrcLLLazyJITRef J);
+
 LLVM_C_EXTERN_C_END
 #endif

+ 32 - 2
core/iwasm/fast-jit/fe/jit_emit_function.c

@@ -829,23 +829,45 @@ emit_callnative(JitCompContext *cc, JitReg native_func_reg, JitReg res,
                 JitReg *params, uint32 param_count)
 {
     JitInsn *insn;
+    char *i32_arg_names[] = { "edi", "esi", "edx", "ecx" };
     char *i64_arg_names[] = { "rdi", "rsi", "rdx", "rcx", "r8", "r9" };
     char *f32_arg_names[] = { "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" };
     char *f64_arg_names[] = { "xmm0_f64", "xmm1_f64", "xmm2_f64",
                               "xmm3_f64", "xmm4_f64", "xmm5_f64" };
-    JitReg i64_arg_regs[6], f32_arg_regs[6], f64_arg_regs[6], res_reg = 0;
+    JitReg i32_arg_regs[4], i64_arg_regs[6];
+    JitReg f32_arg_regs[6], f64_arg_regs[6], res_reg = 0;
     JitReg eax_hreg = jit_codegen_get_hreg_by_name("eax");
     JitReg xmm0_hreg = jit_codegen_get_hreg_by_name("xmm0");
-    uint32 i, i64_reg_idx, float_reg_idx;
+    uint32 i, i64_reg_idx, float_reg_idx, lock_i32_reg_num;
 
     bh_assert(param_count <= 6);
 
+    for (i = 0; i < 4; i++) {
+        i32_arg_regs[i] = jit_codegen_get_hreg_by_name(i32_arg_names[i]);
+    }
+
     for (i = 0; i < 6; i++) {
         i64_arg_regs[i] = jit_codegen_get_hreg_by_name(i64_arg_names[i]);
         f32_arg_regs[i] = jit_codegen_get_hreg_by_name(f32_arg_names[i]);
         f64_arg_regs[i] = jit_codegen_get_hreg_by_name(f64_arg_names[i]);
     }
 
+    lock_i32_reg_num = param_count < 4 ? param_count : 4;
+
+    /*
+     * Lock i32 registers so that they won't be allocated for the operand
+     * of below I32TOI64 insn, which may have been overwritten in the
+     * previous MOV, for example, in the below insns:
+     *   MOV             I5, I15
+     *   I32TOI64        I6, i5
+     *   CALLNATIVE      VOID, native_func, I5, I6
+     * i5 is used in the second insn, but it has been overwritten in I5
+     * by the first insn
+     */
+    for (i = 0; i < lock_i32_reg_num; i++) {
+        GEN_INSN(MOV, i32_arg_regs[i], i32_arg_regs[i]);
+    }
+
     i64_reg_idx = float_reg_idx = 0;
     for (i = 0; i < param_count; i++) {
         switch (jit_reg_kind(params[i])) {
@@ -867,6 +889,14 @@ emit_callnative(JitCompContext *cc, JitReg native_func_reg, JitReg res,
         }
     }
 
+    /*
+     * Announce the locked i32 registers are being used, and do necessary
+     * spill ASAP
+     */
+    for (i = 0; i < lock_i32_reg_num; i++) {
+        GEN_INSN(MOV, i32_arg_regs[i], i32_arg_regs[i]);
+    }
+
     if (res) {
         switch (jit_reg_kind(res)) {
             case JIT_REG_KIND_I32:

+ 22 - 14
core/iwasm/fast-jit/fe/jit_emit_memory.c

@@ -650,6 +650,7 @@ wasm_init_memory(WASMModuleInstance *inst, uint32 mem_idx, uint32 seg_idx,
     WASMDataSeg *data_segment;
     uint32 mem_size;
     uint8 *mem_addr, *data_addr;
+    uint32 seg_len;
 
     /* if d + n > the length of mem.data */
     mem_inst = inst->memories[mem_idx];
@@ -659,13 +660,19 @@ wasm_init_memory(WASMModuleInstance *inst, uint32 mem_idx, uint32 seg_idx,
 
     /* if s + n > the length of data.data */
     bh_assert(seg_idx < inst->module->data_seg_count);
-    data_segment = inst->module->data_segments[seg_idx];
-    if (data_segment->data_length < data_offset
-        || data_segment->data_length - data_offset < len)
+    if (bh_bitmap_get_bit(inst->e->common.data_dropped, seg_idx)) {
+        seg_len = 0;
+        data_addr = NULL;
+    }
+    else {
+        data_segment = inst->module->data_segments[seg_idx];
+        seg_len = data_segment->data_length;
+        data_addr = data_segment->data + data_offset;
+    }
+    if (seg_len < data_offset || seg_len - data_offset < len)
         goto out_of_bounds;
 
     mem_addr = mem_inst->memory_data + mem_offset;
-    data_addr = data_segment->data + data_offset;
     bh_memcpy_s(mem_addr, mem_size - mem_offset, data_addr, len);
 
     return 0;
@@ -706,21 +713,22 @@ fail:
     return false;
 }
 
+static void
+wasm_data_drop(WASMModuleInstance *inst, uint32 seg_idx)
+{
+    bh_bitmap_set_bit(inst->e->common.data_dropped, seg_idx);
+}
+
 bool
 jit_compile_op_data_drop(JitCompContext *cc, uint32 seg_idx)
 {
-    JitReg module = get_module_reg(cc->jit_frame);
-    JitReg data_segments = jit_cc_new_reg_ptr(cc);
-    JitReg data_segment = jit_cc_new_reg_ptr(cc);
+    JitReg args[2] = { 0 };
 
-    GEN_INSN(LDPTR, data_segments, module,
-             NEW_CONST(I32, offsetof(WASMModule, data_segments)));
-    GEN_INSN(LDPTR, data_segment, data_segments,
-             NEW_CONST(I32, seg_idx * sizeof(WASMDataSeg *)));
-    GEN_INSN(STI32, NEW_CONST(I32, 0), data_segment,
-             NEW_CONST(I32, offsetof(WASMDataSeg, data_length)));
+    args[0] = get_module_inst_reg(cc->jit_frame);
+    args[1] = NEW_CONST(I32, seg_idx);
 
-    return true;
+    return jit_emit_callnative(cc, wasm_data_drop, 0, args,
+                               sizeof(args) / sizeof(args[0]));
 }
 
 static int

+ 17 - 10
core/iwasm/fast-jit/fe/jit_emit_table.c

@@ -10,21 +10,22 @@
 #include "../jit_frontend.h"
 
 #if WASM_ENABLE_REF_TYPES != 0
+static void
+wasm_elem_drop(WASMModuleInstance *inst, uint32 tbl_seg_idx)
+{
+    bh_bitmap_set_bit(inst->e->common.elem_dropped, tbl_seg_idx);
+}
+
 bool
 jit_compile_op_elem_drop(JitCompContext *cc, uint32 tbl_seg_idx)
 {
-    JitReg module, tbl_segs;
+    JitReg args[2] = { 0 };
 
-    module = get_module_reg(cc->jit_frame);
-
-    tbl_segs = jit_cc_new_reg_ptr(cc);
-    GEN_INSN(LDPTR, tbl_segs, module,
-             NEW_CONST(I32, offsetof(WASMModule, table_segments)));
+    args[0] = get_module_inst_reg(cc->jit_frame);
+    args[1] = NEW_CONST(I32, tbl_seg_idx);
 
-    GEN_INSN(STI32, NEW_CONST(I32, true), tbl_segs,
-             NEW_CONST(I32, tbl_seg_idx * sizeof(WASMTableSeg)
-                                + offsetof(WASMTableSeg, is_dropped)));
-    return true;
+    return jit_emit_callnative(cc, wasm_elem_drop, 0, args,
+                               sizeof(args) / sizeof(args[0]));
 }
 
 bool
@@ -107,6 +108,12 @@ wasm_init_table(WASMModuleInstance *inst, uint32 tbl_idx, uint32 elem_idx,
     if (offset_len_out_of_bounds(dst_offset, len, tbl_sz))
         goto out_of_bounds;
 
+    if (!len)
+        return 0;
+
+    if (bh_bitmap_get_bit(inst->e->common.elem_dropped, elem_idx))
+        goto out_of_bounds;
+
     bh_memcpy_s((uint8 *)tbl + offsetof(WASMTableInstance, elems)
                     + dst_offset * sizeof(table_elem_type_t),
                 (uint32)((tbl_sz - dst_offset) * sizeof(table_elem_type_t)),

+ 2 - 2
core/iwasm/fast-jit/jit_codecache.c

@@ -17,8 +17,8 @@ jit_code_cache_init(uint32 code_cache_size)
     int map_prot = MMAP_PROT_READ | MMAP_PROT_WRITE | MMAP_PROT_EXEC;
     int map_flags = MMAP_MAP_NONE;
 
-    if (!(code_cache_pool =
-              os_mmap(NULL, code_cache_size, map_prot, map_flags))) {
+    if (!(code_cache_pool = os_mmap(NULL, code_cache_size, map_prot, map_flags,
+                                    os_get_invalid_handle()))) {
         return false;
     }
 

+ 1 - 0
core/iwasm/fast-jit/jit_compiler.h

@@ -70,6 +70,7 @@ typedef struct JitInterpSwitchInfo {
 typedef struct JitCompOptions {
     uint32 code_cache_size;
     uint32 opt_level;
+    bool linux_perf_support;
 } JitCompOptions;
 
 bool

+ 0 - 19
core/iwasm/fast-jit/jit_utils.c

@@ -1,19 +0,0 @@
-/*
- * Copyright (C) 2021 Intel Corporation.  All rights reserved.
- * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- */
-
-#include "jit_utils.h"
-
-JitBitmap *
-jit_bitmap_new(uintptr_t begin_index, unsigned bitnum)
-{
-    JitBitmap *bitmap;
-
-    if ((bitmap = jit_calloc(offsetof(JitBitmap, map) + (bitnum + 7) / 8))) {
-        bitmap->begin_index = begin_index;
-        bitmap->end_index = begin_index + bitnum;
-    }
-
-    return bitmap;
-}

+ 0 - 94
core/iwasm/fast-jit/jit_utils.h

@@ -12,20 +12,6 @@
 extern "C" {
 #endif
 
-/**
- * A simple fixed size bitmap.
- */
-typedef struct JitBitmap {
-    /* The first valid bit index.  */
-    uintptr_t begin_index;
-
-    /* The last valid bit index plus one.  */
-    uintptr_t end_index;
-
-    /* The bitmap.  */
-    uint8 map[1];
-} JitBitmap;
-
 static inline void *
 jit_malloc(unsigned int size)
 {
@@ -49,86 +35,6 @@ jit_free(void *ptr)
         wasm_runtime_free(ptr);
 }
 
-/**
- * Create a new bitmap.
- *
- * @param begin_index the first valid bit index
- * @param bitnum maximal bit number of the bitmap.
- *
- * @return the new bitmap if succeeds, NULL otherwise.
- */
-JitBitmap *
-jit_bitmap_new(uintptr_t begin_index, unsigned bitnum);
-
-/**
- * Delete a bitmap.
- *
- * @param bitmap the bitmap to be deleted
- */
-static inline void
-jit_bitmap_delete(JitBitmap *bitmap)
-{
-    jit_free(bitmap);
-}
-
-/**
- * Check whether the given index is in the range of the bitmap.
- *
- * @param bitmap the bitmap
- * @param n the bit index
- *
- * @return true if the index is in range, false otherwise
- */
-static inline bool
-jit_bitmap_is_in_range(JitBitmap *bitmap, unsigned n)
-{
-    return n >= bitmap->begin_index && n < bitmap->end_index;
-}
-
-/**
- * Get a bit in the bitmap
- *
- * @param bitmap the bitmap
- * @param n the n-th bit to be get
- *
- * @return value of the bit
- */
-static inline int
-jit_bitmap_get_bit(JitBitmap *bitmap, unsigned n)
-{
-    unsigned idx = n - bitmap->begin_index;
-    bh_assert(n >= bitmap->begin_index && n < bitmap->end_index);
-    return (bitmap->map[idx / 8] >> (idx % 8)) & 1;
-}
-
-/**
- * Set a bit in the bitmap.
- *
- * @param bitmap the bitmap
- * @param n the n-th bit to be set
- */
-static inline void
-jit_bitmap_set_bit(JitBitmap *bitmap, unsigned n)
-{
-    unsigned idx = n - bitmap->begin_index;
-    bh_assert(n >= bitmap->begin_index && n < bitmap->end_index);
-    bitmap->map[idx / 8] |= 1 << (idx % 8);
-}
-
-/**
- * Clear a bit in the bitmap.
- *
- * @param bitmap the bitmap
- * @param n the n-th bit to be cleared
- */
-static inline void
-jit_bitmap_clear_bit(JitBitmap *bitmap, unsigned n)
-{
-    unsigned idx = n - bitmap->begin_index;
-    bh_assert(n >= bitmap->begin_index && n < bitmap->end_index);
-    bitmap->map[idx / 8] &= ~(1 << (idx % 8));
-}
-
 #ifdef __cplusplus
 }
 #endif

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

@@ -26,6 +26,7 @@ typedef struct AOTCompOption {
     bool enable_llvm_pgo;
     bool enable_stack_estimation;
     bool enable_gc;
+    bool linux_perf_support;
     char *use_prof_file;
     uint32_t opt_level;
     uint32_t size_level;

+ 26 - 13
core/iwasm/include/wasm_export.h

@@ -172,6 +172,15 @@ typedef struct RuntimeInitArgs {
     uint32_t llvm_jit_size_level;
     /* Segue optimization flags for LLVM JIT */
     uint32_t segue_flags;
+    /**
+     * If enabled
+     * - llvm-jit will output a jitdump file for `perf inject`
+     * - aot. TBD
+     * - fast-jit. TBD
+     * - multi-tier-jit. TBD
+     * - interpreter. TBD
+     */
+    bool linux_perf_support;
 } RuntimeInitArgs;
 
 #ifndef WASM_VALKIND_T_DEFINED
@@ -435,26 +444,31 @@ wasm_runtime_get_module_hash(wasm_module_t module);
  * @param env_count     The number of elements in env.
  * @param argv          The list of command line arguments.
  * @param argc          The number of elements in argv.
- * @param stdinfd       The host file descriptor to back WASI STDIN_FILENO.
- *                      If -1 is specified, STDIN_FILENO is used.
- * @param stdoutfd      The host file descriptor to back WASI STDOUT_FILENO.
- *                      If -1 is specified, STDOUT_FILENO is used.
- * @param stderrfd      The host file descriptor to back WASI STDERR_FILENO.
- *                      If -1 is specified, STDERR_FILENO is used.
+ * @param stdin_handle  The raw host handle to back WASI STDIN_FILENO.
+ *                      If an invalid handle is specified (e.g. -1 on POSIX,
+ *                      INVALID_HANDLE_VALUE on Windows), the platform default
+ *                      for STDIN is used.
+ * @param stdoutfd      The raw host handle to back WASI STDOUT_FILENO.
+ *                      If an invalid handle is specified (e.g. -1 on POSIX,
+ *                      INVALID_HANDLE_VALUE on Windows), the platform default
+ *                      for STDOUT is used.
+ * @param stderrfd      The raw host handle to back WASI STDERR_FILENO.
+ *                      If an invalid handle is specified (e.g. -1 on POSIX,
+ *                      INVALID_HANDLE_VALUE on Windows), the platform default
+ *                      for STDERR is used.
  */
 WASM_RUNTIME_API_EXTERN void
 wasm_runtime_set_wasi_args_ex(wasm_module_t module,
                            const char *dir_list[], uint32_t dir_count,
                            const char *map_dir_list[], uint32_t map_dir_count,
                            const char *env[], uint32_t env_count,
-                           char *argv[], int argc,
-                           int stdinfd, int stdoutfd, int stderrfd);
+                           char *argv[], int argc, int64_t stdinfd,
+                           int64_t stdoutfd, int64_t stderrfd);
 
 /**
  * Set WASI parameters.
  *
- * Same as wasm_runtime_set_wasi_args_ex with stdinfd = -1, stdoutfd = -1,
- * stderrfd = -1.
+ * Same as wasm_runtime_set_wasi_args_ex but with default stdio handles
  */
 WASM_RUNTIME_API_EXTERN void
 wasm_runtime_set_wasi_args(wasm_module_t module,
@@ -943,7 +957,7 @@ wasm_runtime_get_custom_data(wasm_module_inst_t module_inst);
 
 /**
  * Set the memory bounds checks flag of a WASM module instance.
- * 
+ *
  * @param module_inst the WASM module instance
  * @param enable the flag to enable/disable the memory bounds checks
  */
@@ -952,9 +966,8 @@ wasm_runtime_set_bounds_checks(wasm_module_inst_t module_inst,
                                bool enable);
 /**
  * Check if the memory bounds checks flag is enabled for a WASM module instance.
- * 
- * @param module_inst the WASM module instance
  *
+ * @param module_inst the WASM module instance
  * @return true if the memory bounds checks flag is enabled, false otherwise
  */
 WASM_RUNTIME_API_EXTERN bool

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

@@ -627,7 +627,6 @@ typedef struct WASMTableSeg {
 #if WASM_ENABLE_GC != 0
     WASMRefType *elem_ref_type;
 #endif
-    bool is_dropped;
     /* optional, only for active */
     uint32 table_index;
     InitializerExpression base_offset;
@@ -666,7 +665,7 @@ typedef struct WASIArguments {
     uint32 ns_lookup_count;
     char **argv;
     uint32 argc;
-    int stdio[3];
+    os_raw_file_handle stdio[3];
 } WASIArguments;
 #endif
 

+ 22 - 19
core/iwasm/interpreter/wasm_interp_classic.c

@@ -1204,7 +1204,8 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst,
     }
 
     /* - module_inst */
-    exec_env->module_inst = (WASMModuleInstanceCommon *)sub_module_inst;
+    wasm_exec_env_set_module_inst(exec_env,
+                                  (WASMModuleInstanceCommon *)sub_module_inst);
     /* - aux_stack_boundary */
     aux_stack_origin_boundary = exec_env->aux_stack_boundary.boundary;
     exec_env->aux_stack_boundary.boundary =
@@ -1226,15 +1227,8 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst,
     prev_frame->ip = ip;
     exec_env->aux_stack_boundary.boundary = aux_stack_origin_boundary;
     exec_env->aux_stack_bottom.bottom = aux_stack_origin_bottom;
-    exec_env->module_inst = (WASMModuleInstanceCommon *)module_inst;
-
-    /* transfer exception if it is thrown */
-    if (wasm_copy_exception(sub_module_inst, NULL)) {
-        bh_memcpy_s(module_inst->cur_exception,
-                    sizeof(module_inst->cur_exception),
-                    sub_module_inst->cur_exception,
-                    sizeof(sub_module_inst->cur_exception));
-    }
+    wasm_exec_env_restore_module_inst(exec_env,
+                                      (WASMModuleInstanceCommon *)module_inst);
 }
 #endif
 
@@ -1382,7 +1376,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
     uint8 value_type;
 #if !defined(OS_ENABLE_HW_BOUND_CHECK) \
     || WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0
-#if WASM_CONFIGUABLE_BOUNDS_CHECKS != 0
+#if WASM_CONFIGURABLE_BOUNDS_CHECKS != 0
     bool disable_bounds_checks = !wasm_runtime_is_bounds_checks_enabled(
         (WASMModuleInstanceCommon *)module);
 #else
@@ -4960,9 +4954,17 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                         maddr = memory->memory_data + (uint32)addr;
 #endif
 
-                        seg_len = (uint64)module->module->data_segments[segment]
-                                      ->data_length;
-                        data = module->module->data_segments[segment]->data;
+                        if (bh_bitmap_get_bit(module->e->common.data_dropped,
+                                              segment)) {
+                            seg_len = 0;
+                            data = NULL;
+                        }
+                        else {
+                            seg_len =
+                                (uint64)module->module->data_segments[segment]
+                                    ->data_length;
+                            data = module->module->data_segments[segment]->data;
+                        }
                         if (offset + bytes > seg_len)
                             goto out_of_bounds;
 
@@ -4975,7 +4977,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                         uint32 segment;
 
                         read_leb_uint32(frame_ip, frame_ip_end, segment);
-                        module->module->data_segments[segment]->data_length = 0;
+                        bh_bitmap_set_bit(module->e->common.data_dropped,
+                                          segment);
                         break;
                     }
                     case WASM_OP_MEMORY_COPY:
@@ -5074,8 +5077,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                             break;
                         }
 
-                        if (module->module->table_segments[elem_idx]
-                                .is_dropped) {
+                        if (bh_bitmap_get_bit(module->e->common.elem_dropped,
+                                              elem_idx)) {
                             wasm_set_exception(module,
                                                "out of bounds table access");
                             goto got_exception;
@@ -5128,8 +5131,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                         read_leb_uint32(frame_ip, frame_ip_end, elem_idx);
                         bh_assert(elem_idx < module->module->table_seg_count);
 
-                        module->module->table_segments[elem_idx].is_dropped =
-                            true;
+                        bh_bitmap_set_bit(module->e->common.elem_dropped,
+                                          elem_idx);
                         break;
                     }
                     case WASM_OP_TABLE_COPY:

+ 24 - 23
core/iwasm/interpreter/wasm_interp_fast.c

@@ -1289,7 +1289,8 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst,
     }
 
     /* - module_inst */
-    exec_env->module_inst = (WASMModuleInstanceCommon *)sub_module_inst;
+    wasm_exec_env_set_module_inst(exec_env,
+                                  (WASMModuleInstanceCommon *)sub_module_inst);
     /* - aux_stack_boundary */
     aux_stack_origin_boundary = exec_env->aux_stack_boundary.boundary;
     exec_env->aux_stack_boundary.boundary =
@@ -1311,15 +1312,8 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst,
     prev_frame->ip = ip;
     exec_env->aux_stack_boundary.boundary = aux_stack_origin_boundary;
     exec_env->aux_stack_bottom.bottom = aux_stack_origin_bottom;
-    exec_env->module_inst = (WASMModuleInstanceCommon *)module_inst;
-
-    /* transfer exception if it is thrown */
-    if (wasm_copy_exception(sub_module_inst, NULL)) {
-        bh_memcpy_s(module_inst->cur_exception,
-                    sizeof(module_inst->cur_exception),
-                    sub_module_inst->cur_exception,
-                    sizeof(sub_module_inst->cur_exception));
-    }
+    wasm_exec_env_restore_module_inst(exec_env,
+                                      (WASMModuleInstanceCommon *)module_inst);
 }
 #endif
 
@@ -1476,7 +1470,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
     uint8 opcode = 0, local_type, *global_addr;
 #if !defined(OS_ENABLE_HW_BOUND_CHECK) \
     || WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0
-#if WASM_CONFIGUABLE_BOUNDS_CHECKS != 0
+#if WASM_CONFIGURABLE_BOUNDS_CHECKS != 0
     bool disable_bounds_checks = !wasm_runtime_is_bounds_checks_enabled(
         (WASMModuleInstanceCommon *)module);
 #else
@@ -4878,8 +4872,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
 
                         segment = read_uint32(frame_ip);
 
-                        bytes = (uint64)POP_I32();
-                        offset = (uint64)POP_I32();
+                        bytes = (uint64)(uint32)POP_I32();
+                        offset = (uint64)(uint32)POP_I32();
                         addr = POP_I32();
 
 #if WASM_ENABLE_THREAD_MGR
@@ -4894,10 +4888,18 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                             goto out_of_bounds;
                         maddr = memory->memory_data + (uint32)addr;
 #endif
+                        if (bh_bitmap_get_bit(module->e->common.data_dropped,
+                                              segment)) {
+                            seg_len = 0;
+                            data = NULL;
+                        }
+                        else {
 
-                        seg_len = (uint64)module->module->data_segments[segment]
-                                      ->data_length;
-                        data = module->module->data_segments[segment]->data;
+                            seg_len =
+                                (uint64)module->module->data_segments[segment]
+                                    ->data_length;
+                            data = module->module->data_segments[segment]->data;
+                        }
                         if (offset + bytes > seg_len)
                             goto out_of_bounds;
 
@@ -4910,8 +4912,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                         uint32 segment;
 
                         segment = read_uint32(frame_ip);
-
-                        module->module->data_segments[segment]->data_length = 0;
+                        bh_bitmap_set_bit(module->e->common.data_dropped,
+                                          segment);
                         break;
                     }
                     case WASM_OP_MEMORY_COPY:
@@ -5008,8 +5010,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                             break;
                         }
 
-                        if (module->module->table_segments[elem_idx]
-                                .is_dropped) {
+                        if (bh_bitmap_get_bit(module->e->common.elem_dropped,
+                                              elem_idx)) {
                             wasm_set_exception(module,
                                                "out of bounds table access");
                             goto got_exception;
@@ -5060,9 +5062,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                     {
                         uint32 elem_idx = read_uint32(frame_ip);
                         bh_assert(elem_idx < module->module->table_seg_count);
-
-                        module->module->table_segments[elem_idx].is_dropped =
-                            true;
+                        bh_bitmap_set_bit(module->e->common.elem_dropped,
+                                          elem_idx);
                         break;
                     }
                     case WASM_OP_TABLE_COPY:

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

@@ -181,7 +181,6 @@ fail:
 
 #define read_uint8(p) TEMPLATE_READ_VALUE(uint8, p)
 #define read_uint32(p) TEMPLATE_READ_VALUE(uint32, p)
-#define read_bool(p) TEMPLATE_READ_VALUE(bool, p)
 
 #define read_leb_int64(p, p_end, res)                                   \
     do {                                                                \
@@ -574,6 +573,7 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end,
             if (type != VALUE_TYPE_V128)
                 goto fail_type_mismatch;
 
+            CHECK_BUF(p, p_end, 1);
             flag = read_uint8(p);
             (void)flag;
 
@@ -624,6 +624,7 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end,
 #else
             WASMRefType ref_type1 = { 0 };
 
+            CHECK_BUF(p, p_end, 1);
             type1 = read_uint8(p);
             if (!is_byte_a_type(type1)) {
                 p--;
@@ -1183,6 +1184,7 @@ resolve_struct_type(const uint8 **p_buf, const uint8 *buf_end,
             }
         }
 
+        CHECK_BUF(p, p_end, 1);
         type->fields[i].field_flags = read_uint8(p);
         type->fields[i].field_size =
             (uint8)wasm_reftype_size(ref_type.ref_type);
@@ -4067,6 +4069,7 @@ init_llvm_jit_functions_stage1(WASMModule *module, char *error_buf,
     option.opt_level = llvm_jit_options.opt_level;
     option.size_level = llvm_jit_options.size_level;
     option.segue_flags = llvm_jit_options.segue_flags;
+    option.linux_perf_support = llvm_jit_options.linux_perf_support;
 
 #if WASM_ENABLE_BULK_MEMORY != 0
     option.enable_bulk_memory = true;
@@ -9184,7 +9187,7 @@ wasm_loader_get_custom_section(WASMModule *module, const char *name,
         section = section->next;
     }
 
-    return false;
+    return NULL;
 }
 #endif
 
@@ -12741,6 +12744,7 @@ re_scan:
             {
                 uint32 opcode1;
 
+                CHECK_BUF(p, p_end, 1);
                 opcode1 = read_uint8(p);
                 /* follow the order of enum WASMSimdEXTOpcode in wasm_opcode.h
                  */
@@ -13402,6 +13406,7 @@ re_scan:
             {
                 uint32 opcode1;
 
+                CHECK_BUF(p, p_end, 1);
                 opcode1 = read_uint8(p);
 #if WASM_ENABLE_FAST_INTERP != 0
                 emit_byte(loader_ctx, opcode1);

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

@@ -1879,6 +1879,7 @@ init_llvm_jit_functions_stage1(WASMModule *module, char *error_buf,
     option.opt_level = llvm_jit_options.opt_level;
     option.size_level = llvm_jit_options.size_level;
     option.segue_flags = llvm_jit_options.segue_flags;
+    option.linux_perf_support = llvm_jit_options.linux_perf_support;
 
 #if WASM_ENABLE_BULK_MEMORY != 0
     option.enable_bulk_memory = true;

+ 80 - 31
core/iwasm/interpreter/wasm_runtime.c

@@ -279,6 +279,12 @@ memory_instantiate(WASMModuleInstance *module_inst, WASMModuleInstance *parent,
         if (max_page_count > DEFAULT_MAX_PAGES)
             max_page_count = DEFAULT_MAX_PAGES;
     }
+    else { /* heap_size == 0 */
+        if (init_page_count == DEFAULT_MAX_PAGES) {
+            num_bytes_per_page = UINT32_MAX;
+            init_page_count = max_page_count = 1;
+        }
+    }
 
     LOG_VERBOSE("Memory instantiate:");
     LOG_VERBOSE("  page bytes: %u, init pages: %u, max pages: %u",
@@ -321,14 +327,16 @@ memory_instantiate(WASMModuleInstance *module_inst, WASMModuleInstance *parent,
      * so the range of ea is 0 to 8G
      */
     if (!(memory->memory_data = mapped_mem =
-              os_mmap(NULL, map_size, MMAP_PROT_NONE, MMAP_MAP_NONE))) {
+              os_mmap(NULL, map_size, MMAP_PROT_NONE, MMAP_MAP_NONE,
+                      os_get_invalid_handle()))) {
         set_error_buf(error_buf, error_buf_size, "mmap memory failed");
         goto fail1;
     }
 
 #ifdef BH_PLATFORM_WINDOWS
-    if (!os_mem_commit(mapped_mem, memory_data_size,
-                       MMAP_PROT_READ | MMAP_PROT_WRITE)) {
+    if (memory_data_size > 0
+        && !os_mem_commit(mapped_mem, memory_data_size,
+                          MMAP_PROT_READ | MMAP_PROT_WRITE)) {
         set_error_buf(error_buf, error_buf_size, "commit memory failed");
         os_munmap(mapped_mem, map_size);
         goto fail1;
@@ -381,7 +389,7 @@ memory_instantiate(WASMModuleInstance *module_inst, WASMModuleInstance *parent,
 
 #if WASM_ENABLE_SHARED_MEMORY != 0
     if (is_shared_memory) {
-        memory->is_shared_memory = true;
+        memory->is_shared_memory = 1;
         memory->ref_count = 1;
     }
 #endif
@@ -1127,7 +1135,8 @@ execute_post_instantiate_functions(WASMModuleInstance *module_inst,
            wasm functions, and ensure that the exec_env's module inst
            is the correct one. */
         module_inst_main = exec_env_main->module_inst;
-        exec_env->module_inst = (WASMModuleInstanceCommon *)module_inst;
+        wasm_exec_env_set_module_inst(exec_env,
+                                      (WASMModuleInstanceCommon *)module_inst);
     }
     else {
         /* Try using the existing exec_env */
@@ -1152,7 +1161,8 @@ execute_post_instantiate_functions(WASMModuleInstance *module_inst,
                module inst to ensure that the exec_env's module inst
                is the correct one. */
             module_inst_main = exec_env->module_inst;
-            exec_env->module_inst = (WASMModuleInstanceCommon *)module_inst;
+            wasm_exec_env_set_module_inst(
+                exec_env, (WASMModuleInstanceCommon *)module_inst);
         }
     }
 
@@ -1185,12 +1195,12 @@ execute_post_instantiate_functions(WASMModuleInstance *module_inst,
 fail:
     if (is_sub_inst) {
         /* Restore the parent exec_env's module inst */
-        exec_env_main->module_inst = module_inst_main;
+        wasm_exec_env_restore_module_inst(exec_env_main, module_inst_main);
     }
     else {
         if (module_inst_main)
             /* Restore the existing exec_env's module inst */
-            exec_env->module_inst = module_inst_main;
+            wasm_exec_env_restore_module_inst(exec_env, module_inst_main);
         if (exec_env_created)
             wasm_exec_env_destroy(exec_env_created);
     }
@@ -1259,7 +1269,8 @@ execute_malloc_function(WASMModuleInstance *module_inst, WASMExecEnv *exec_env,
                module inst to ensure that the exec_env's module inst
                is the correct one. */
             module_inst_old = exec_env->module_inst;
-            exec_env->module_inst = (WASMModuleInstanceCommon *)module_inst;
+            wasm_exec_env_set_module_inst(
+                exec_env, (WASMModuleInstanceCommon *)module_inst);
         }
     }
 
@@ -1270,7 +1281,7 @@ execute_malloc_function(WASMModuleInstance *module_inst, WASMExecEnv *exec_env,
 
     if (module_inst_old)
         /* Restore the existing exec_env's module inst */
-        exec_env->module_inst = module_inst_old;
+        wasm_exec_env_restore_module_inst(exec_env, module_inst_old);
 
     if (exec_env_created)
         wasm_exec_env_destroy(exec_env_created);
@@ -1326,7 +1337,8 @@ execute_free_function(WASMModuleInstance *module_inst, WASMExecEnv *exec_env,
                module inst to ensure that the exec_env's module inst
                is the correct one. */
             module_inst_old = exec_env->module_inst;
-            exec_env->module_inst = (WASMModuleInstanceCommon *)module_inst;
+            wasm_exec_env_set_module_inst(
+                exec_env, (WASMModuleInstanceCommon *)module_inst);
         }
     }
 
@@ -1334,7 +1346,7 @@ execute_free_function(WASMModuleInstance *module_inst, WASMExecEnv *exec_env,
 
     if (module_inst_old)
         /* Restore the existing exec_env's module inst */
-        exec_env->module_inst = module_inst_old;
+        wasm_exec_env_restore_module_inst(exec_env, module_inst_old);
 
     if (exec_env_created)
         wasm_exec_env_destroy(exec_env_created);
@@ -1856,6 +1868,31 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent,
     }
 #endif
 
+#if WASM_ENABLE_BULK_MEMORY != 0
+    if (module->data_seg_count > 0) {
+        module_inst->e->common.data_dropped =
+            bh_bitmap_new(0, module->data_seg_count);
+        if (module_inst->e->common.data_dropped == NULL) {
+            LOG_DEBUG("failed to allocate bitmaps");
+            set_error_buf(error_buf, error_buf_size,
+                          "failed to allocate bitmaps");
+            goto fail;
+        }
+    }
+#endif
+#if WASM_ENABLE_REF_TYPES != 0
+    if (module->table_seg_count > 0) {
+        module_inst->e->common.elem_dropped =
+            bh_bitmap_new(0, module->table_seg_count);
+        if (module_inst->e->common.elem_dropped == NULL) {
+            LOG_DEBUG("failed to allocate bitmaps");
+            set_error_buf(error_buf, error_buf_size,
+                          "failed to allocate bitmaps");
+            goto fail;
+        }
+    }
+#endif
+
 #if WASM_ENABLE_GC != 0
     if (!is_sub_inst) {
         uint32 gc_heap_size = wasm_runtime_get_gc_heap_size_default();
@@ -2516,6 +2553,13 @@ wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst)
         wasm_native_call_context_dtors((WASMModuleInstanceCommon *)module_inst);
     }
 
+#if WASM_ENABLE_BULK_MEMORY != 0
+    bh_bitmap_delete(module_inst->e->common.data_dropped);
+#endif
+#if WASM_ENABLE_REF_TYPES != 0
+    bh_bitmap_delete(module_inst->e->common.elem_dropped);
+#endif
+
     wasm_runtime_free(module_inst);
 }
 
@@ -2714,14 +2758,16 @@ wasm_dump_perf_profiling(const WASMModuleInstance *module_inst)
         }
 
         if (func_name)
-            os_printf("  func %s, execution time: %.3f ms, execution count: %d "
-                      "times\n",
-                      func_name,
-                      module_inst->e->functions[i].total_exec_time / 1000.0f,
-                      module_inst->e->functions[i].total_exec_cnt);
+            os_printf(
+                "  func %s, execution time: %.3f ms, execution count: %" PRIu32
+                " times\n",
+                func_name,
+                module_inst->e->functions[i].total_exec_time / 1000.0f,
+                module_inst->e->functions[i].total_exec_cnt);
         else
-            os_printf("  func %d, execution time: %.3f ms, execution count: %d "
-                      "times\n",
+            os_printf("  func %" PRIu32
+                      ", execution time: %.3f ms, execution count: %" PRIu32
+                      " times\n",
                       i, module_inst->e->functions[i].total_exec_time / 1000.0f,
                       module_inst->e->functions[i].total_exec_cnt);
     }
@@ -3535,16 +3581,23 @@ llvm_jit_memory_init(WASMModuleInstance *module_inst, uint32 seg_index,
 {
     WASMMemoryInstance *memory_inst;
     WASMModule *module;
-    uint8 *data = NULL;
+    uint8 *data;
     uint8 *maddr;
-    uint64 seg_len = 0;
+    uint64 seg_len;
 
     bh_assert(module_inst->module_type == Wasm_Module_Bytecode);
 
     memory_inst = wasm_get_default_memory(module_inst);
-    module = module_inst->module;
-    seg_len = module->data_segments[seg_index]->data_length;
-    data = module->data_segments[seg_index]->data;
+
+    if (bh_bitmap_get_bit(module_inst->e->common.data_dropped, seg_index)) {
+        seg_len = 0;
+        data = NULL;
+    }
+    else {
+        module = module_inst->module;
+        seg_len = module->data_segments[seg_index]->data_length;
+        data = module->data_segments[seg_index]->data;
+    }
 
     if (!wasm_runtime_validate_app_addr((WASMModuleInstanceCommon *)module_inst,
                                         dst, len))
@@ -3569,7 +3622,7 @@ llvm_jit_data_drop(WASMModuleInstance *module_inst, uint32 seg_index)
 {
     bh_assert(module_inst->module_type == Wasm_Module_Bytecode);
 
-    module_inst->module->data_segments[seg_index]->data_length = 0;
+    bh_bitmap_set_bit(module_inst->e->common.data_dropped, seg_index);
     /* Currently we can't free the dropped data segment
        as they are stored in wasm bytecode */
     return true;
@@ -3580,12 +3633,8 @@ llvm_jit_data_drop(WASMModuleInstance *module_inst, uint32 seg_index)
 void
 llvm_jit_drop_table_seg(WASMModuleInstance *module_inst, uint32 tbl_seg_idx)
 {
-    WASMTableSeg *tbl_segs;
-
     bh_assert(module_inst->module_type == Wasm_Module_Bytecode);
-
-    tbl_segs = module_inst->module->table_segments;
-    tbl_segs[tbl_seg_idx].is_dropped = true;
+    bh_bitmap_set_bit(module_inst->e->common.elem_dropped, tbl_seg_idx);
 }
 
 void
@@ -3620,7 +3669,7 @@ llvm_jit_table_init(WASMModuleInstance *module_inst, uint32 tbl_idx,
         return;
     }
 
-    if (tbl_seg->is_dropped) {
+    if (bh_bitmap_get_bit(module_inst->e->common.elem_dropped, tbl_seg_idx)) {
         jit_set_exception_with_id(module_inst, EXCE_OUT_OF_BOUNDS_TABLE_ACCESS);
         return;
     }

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

@@ -8,6 +8,7 @@
 
 #include "wasm.h"
 #include "bh_atomic.h"
+#include "bh_bitmap.h"
 #include "bh_hashmap.h"
 #include "../common/wasm_runtime_common.h"
 #include "../common/wasm_exec_env.h"
@@ -96,10 +97,15 @@ struct WASMMemoryInstance {
     /* Module type */
     uint32 module_type;
 
-    bool is_shared_memory;
+    /* Whether the memory is shared */
+    uint8 is_shared_memory;
 
-    /* Shared memory flag */
-    bh_atomic_16_t ref_count; /* 0: non-shared, > 0: reference count */
+    /* One byte padding */
+    uint8 __padding__;
+
+    /* Reference count of the memory instance:
+         0: non-shared memory, > 0: shared memory */
+    bh_atomic_16_t ref_count;
 
     /* Number bytes per page */
     uint32 num_bytes_per_page;
@@ -254,10 +260,16 @@ typedef struct WASMModuleInstanceExtraCommon {
     CApiFuncImport *c_api_func_imports;
     /* pointer to the exec env currently used */
     WASMExecEnv *cur_exec_env;
-#if WASM_CONFIGUABLE_BOUNDS_CHECKS != 0
+#if WASM_CONFIGURABLE_BOUNDS_CHECKS != 0
     /* Disable bounds checks or not */
     bool disable_bounds_checks;
 #endif
+#if WASM_ENABLE_BULK_MEMORY != 0
+    bh_bitmap *data_dropped;
+#endif
+#if WASM_ENABLE_REF_TYPES != 0
+    bh_bitmap *elem_dropped;
+#endif
 
 #if WASM_ENABLE_GC != 0
     /* The gc heap memory pool */

+ 13 - 3
core/iwasm/libraries/lib-rats/lib_rats_wrapper.c

@@ -17,7 +17,7 @@
 #include "lib_rats_common.h"
 
 static int
-librats_collect_wrapper(wasm_exec_env_t exec_env, char **evidence_json,
+librats_collect_wrapper(wasm_exec_env_t exec_env, uint32_t *evidence_json,
                         const char *buffer, uint32_t buffer_size)
 {
     wasm_module_inst_t module_inst = get_module_inst(exec_env);
@@ -47,7 +47,7 @@ librats_collect_wrapper(wasm_exec_env_t exec_env, char **evidence_json,
         return (int)RATS_ATTESTER_ERR_NO_MEM;
     }
     bh_memcpy_s(str_ret, json_size, json, json_size);
-    *((int *)evidence_json) = str_ret_offset;
+    *evidence_json = str_ret_offset;
     free(json);
 
     return 0;
@@ -96,6 +96,15 @@ librats_parse_evidence_wrapper(wasm_exec_env_t exec_env,
     return 0;
 }
 
+static void
+librats_dispose_evidence_json_wrapper(wasm_exec_env_t exec_env,
+                                      uint32_t evidence_json)
+{
+    wasm_module_inst_t module_inst = get_module_inst(exec_env);
+
+    module_free(evidence_json);
+}
+
 /* clang-format off */
 #define REG_NATIVE_FUNC(func_name, signature) \
     { #func_name, func_name##_wrapper, signature, NULL }
@@ -104,7 +113,8 @@ librats_parse_evidence_wrapper(wasm_exec_env_t exec_env,
 static NativeSymbol native_symbols_lib_rats[] = {
     REG_NATIVE_FUNC(librats_collect, "(**~)i"),
     REG_NATIVE_FUNC(librats_verify, "(*~*~)i"),
-    REG_NATIVE_FUNC(librats_parse_evidence, "(*~*~)i")
+    REG_NATIVE_FUNC(librats_parse_evidence, "(*~*~)i"),
+    REG_NATIVE_FUNC(librats_dispose_evidence_json, "(i)")
 };
 
 uint32_t

+ 3 - 0
core/iwasm/libraries/lib-rats/lib_rats_wrapper.h

@@ -41,6 +41,9 @@ librats_parse_evidence(const char *evidence_json, uint32_t json_size,
                            evidence_json ? strlen(evidence_json) + 1 : 0, \
                            evidence, sizeof(rats_sgx_evidence_t))
 
+void
+librats_dispose_evidence_json(char *evidence_json);
+
 #ifdef __cplusplus
 }
 #endif

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

@@ -0,0 +1,3 @@
+{
+    "name": "WAMR lib-socket tests"
+}

+ 10 - 1
core/iwasm/libraries/libc-uvwasi/libc_uvwasi_wrapper.c

@@ -30,7 +30,16 @@
     wasm_runtime_module_free(module_inst, offset)
 /* clang-format on */
 
-#define wasi_errno_t uvwasi_errno_t
+// uvwasi_errno_t is typedef'd to uint16 which is correct according to the ABI
+// specification. However, in WASM, the smallest integer type is int32. If we
+// return uint16, we would rely on language SDKs to implement the correct
+// behaviour of casting to uint16 before checking the value or using it any way.
+// Failure to do so can cause tricky bugs as the upper 16 bits of the error
+// result are not guaranteed to be zero'ed by us so the result essentially
+// contains garbage from the WASM app perspective. To prevent this, we return
+// uint32 directly instead so as not to be reliant on the correct behaviour of
+// any current/future SDK implementations.
+#define wasi_errno_t uint32_t
 #define wasi_fd_t uvwasi_fd_t
 #define wasi_clockid_t uvwasi_clockid_t
 #define wasi_timestamp_t uvwasi_timestamp_t

+ 3 - 2
core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c

@@ -7,6 +7,7 @@
 #include "bh_platform.h"
 #include "wasm_export.h"
 #include "wasm_runtime_common.h"
+#include "wasmtime_ssp.h"
 
 #if WASM_ENABLE_THREAD_MGR != 0
 #include "../../../thread-mgr/thread_manager.h"
@@ -192,7 +193,7 @@ wasi_clock_res_get(wasm_exec_env_t exec_env,
     if (!validate_native_addr(resolution, sizeof(wasi_timestamp_t)))
         return (wasi_errno_t)-1;
 
-    return wasmtime_ssp_clock_res_get(clock_id, resolution);
+    return os_clock_res_get(clock_id, resolution);
 }
 
 static wasi_errno_t
@@ -206,7 +207,7 @@ wasi_clock_time_get(wasm_exec_env_t exec_env,
     if (!validate_native_addr(time, sizeof(wasi_timestamp_t)))
         return (wasi_errno_t)-1;
 
-    return wasmtime_ssp_clock_time_get(clock_id, precision, time);
+    return os_clock_time_get(clock_id, precision, time);
 }
 
 static wasi_errno_t

+ 10 - 2
core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.h

@@ -6,7 +6,6 @@
 #ifndef _LIBC_WASI_WRAPPER_H
 #define _LIBC_WASI_WRAPPER_H
 
-#include "wasmtime_ssp.h"
 #include "posix.h"
 
 #ifdef __cplusplus
@@ -19,7 +18,16 @@ typedef __wasi_advice_t wasi_advice_t;
 typedef __wasi_ciovec_t wasi_ciovec_t;
 typedef __wasi_clockid_t wasi_clockid_t;
 typedef __wasi_dircookie_t wasi_dircookie_t;
-typedef __wasi_errno_t wasi_errno_t;
+// __wasi_errno_t is typedef'd to uint16 which is correct according to the ABI
+// specification. However, in WASM, the smallest integer type is int32. If we
+// return uint16, we would rely on language SDKs to implement the correct
+// behaviour of casting to uint16 before checking the value or using it any way.
+// Failure to do so can cause tricky bugs as the upper 16 bits of the error
+// result are not guaranteed to be zero'ed by us so the result essentially
+// contains garbage from the WASM app perspective. To prevent this, we return
+// uint32 directly instead so as not to be reliant on the correct behaviour of
+// any current/future WASI SDK implemenations.
+typedef uint32_t wasi_errno_t;
 typedef __wasi_event_t wasi_event_t;
 typedef __wasi_exitcode_t wasi_exitcode_t;
 typedef __wasi_fdflags_t wasi_fdflags_t;

文件差異過大導致無法顯示
+ 554 - 1312
core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h


+ 41 - 70
core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/blocking_op.c

@@ -8,99 +8,68 @@
 #include "ssp_config.h"
 #include "blocking_op.h"
 
-int
-blocking_op_close(wasm_exec_env_t exec_env, int fd)
+__wasi_errno_t
+blocking_op_close(wasm_exec_env_t exec_env, os_file_handle handle,
+                  bool is_stdio)
 {
     if (!wasm_runtime_begin_blocking_op(exec_env)) {
-        errno = EINTR;
-        return -1;
+        return __WASI_EINTR;
     }
-    int ret = close(fd);
+    __wasi_errno_t error = os_close(handle, is_stdio);
     wasm_runtime_end_blocking_op(exec_env);
-    return ret;
+    return error;
 }
 
-ssize_t
-blocking_op_readv(wasm_exec_env_t exec_env, int fd, const struct iovec *iov,
-                  int iovcnt)
+__wasi_errno_t
+blocking_op_readv(wasm_exec_env_t exec_env, os_file_handle handle,
+                  const struct __wasi_iovec_t *iov, int iovcnt, size_t *nread)
 {
     if (!wasm_runtime_begin_blocking_op(exec_env)) {
-        errno = EINTR;
-        return -1;
+        return __WASI_EINTR;
     }
-    ssize_t ret = readv(fd, iov, iovcnt);
+    __wasi_errno_t error = os_readv(handle, iov, iovcnt, nread);
     wasm_runtime_end_blocking_op(exec_env);
-    return ret;
+    return error;
 }
 
-#if CONFIG_HAS_PREADV
-ssize_t
-blocking_op_preadv(wasm_exec_env_t exec_env, int fd, const struct iovec *iov,
-                   int iovcnt, off_t offset)
-{
-    if (!wasm_runtime_begin_blocking_op(exec_env)) {
-        errno = EINTR;
-        return -1;
-    }
-    ssize_t ret = preadv(fd, iov, iovcnt, offset);
-    wasm_runtime_end_blocking_op(exec_env);
-    return ret;
-}
-#else  /* CONFIG_HAS_PREADV */
-ssize_t
-blocking_op_pread(wasm_exec_env_t exec_env, int fd, void *p, size_t nb,
-                  off_t offset)
+__wasi_errno_t
+blocking_op_preadv(wasm_exec_env_t exec_env, os_file_handle handle,
+                   const struct __wasi_iovec_t *iov, int iovcnt,
+                   __wasi_filesize_t offset, size_t *nread)
 {
     if (!wasm_runtime_begin_blocking_op(exec_env)) {
-        errno = EINTR;
-        return -1;
+        return __WASI_EINTR;
     }
-    ssize_t ret = pread(fd, p, nb, offset);
+    __wasi_errno_t ret = os_preadv(handle, iov, iovcnt, offset, nread);
     wasm_runtime_end_blocking_op(exec_env);
     return ret;
 }
-#endif /* CONFIG_HAS_PREADV */
 
-ssize_t
-blocking_op_writev(wasm_exec_env_t exec_env, int fd, const struct iovec *iov,
-                   int iovcnt)
+__wasi_errno_t
+blocking_op_writev(wasm_exec_env_t exec_env, os_file_handle handle,
+                   const struct __wasi_ciovec_t *iov, int iovcnt,
+                   size_t *nwritten)
 {
     if (!wasm_runtime_begin_blocking_op(exec_env)) {
-        errno = EINTR;
-        return -1;
+        return __WASI_EINTR;
     }
-    ssize_t ret = writev(fd, iov, iovcnt);
+    __wasi_errno_t error = os_writev(handle, iov, iovcnt, nwritten);
     wasm_runtime_end_blocking_op(exec_env);
-    return ret;
+    return error;
 }
 
-#if CONFIG_HAS_PWRITEV
-ssize_t
-blocking_op_pwritev(wasm_exec_env_t exec_env, int fd, const struct iovec *iov,
-                    int iovcnt, off_t offset)
+__wasi_errno_t
+blocking_op_pwritev(wasm_exec_env_t exec_env, os_file_handle handle,
+                    const struct __wasi_ciovec_t *iov, int iovcnt,
+                    __wasi_filesize_t offset, size_t *nwritten)
 {
     if (!wasm_runtime_begin_blocking_op(exec_env)) {
-        errno = EINTR;
-        return -1;
+        return __WASI_EINTR;
     }
-    ssize_t ret = pwritev(fd, iov, iovcnt, offset);
+    __wasi_errno_t error = os_pwritev(handle, iov, iovcnt, offset, nwritten);
     wasm_runtime_end_blocking_op(exec_env);
-    return ret;
+    return error;
 }
-#else  /* CONFIG_HAS_PWRITEV */
-ssize_t
-blocking_op_pwrite(wasm_exec_env_t exec_env, int fd, const void *p, size_t nb,
-                   off_t offset)
-{
-    if (!wasm_runtime_begin_blocking_op(exec_env)) {
-        errno = EINTR;
-        return -1;
-    }
-    ssize_t ret = pwrite(fd, p, nb, offset);
-    wasm_runtime_end_blocking_op(exec_env);
-    return ret;
-}
-#endif /* CONFIG_HAS_PWRITEV */
 
 int
 blocking_op_socket_accept(wasm_exec_env_t exec_env, bh_socket_t server_sock,
@@ -187,15 +156,17 @@ blocking_op_socket_addr_resolve(wasm_exec_env_t exec_env, const char *host,
     return ret;
 }
 
-int
-blocking_op_openat(wasm_exec_env_t exec_env, int fd, const char *path,
-                   int oflags, mode_t mode)
+__wasi_errno_t
+blocking_op_openat(wasm_exec_env_t exec_env, os_file_handle handle,
+                   const char *path, __wasi_oflags_t oflags,
+                   __wasi_fdflags_t fd_flags, __wasi_lookupflags_t lookup_flags,
+                   wasi_libc_file_access_mode access_mode, os_file_handle *out)
 {
     if (!wasm_runtime_begin_blocking_op(exec_env)) {
-        errno = EINTR;
-        return -1;
+        return __WASI_EINTR;
     }
-    int ret = openat(fd, path, oflags, mode);
+    __wasi_errno_t error = os_openat(handle, path, oflags, fd_flags,
+                                     lookup_flags, access_mode, out);
     wasm_runtime_end_blocking_op(exec_env);
-    return ret;
+    return error;
 }

+ 24 - 23
core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/blocking_op.h

@@ -6,26 +6,24 @@
 #include "bh_platform.h"
 #include "wasm_export.h"
 
-int
-blocking_op_close(wasm_exec_env_t exec_env, int fd);
-ssize_t
-blocking_op_readv(wasm_exec_env_t exec_env, int fd, const struct iovec *iov,
-                  int iovcnt);
-ssize_t
-blocking_op_preadv(wasm_exec_env_t exec_env, int fd, const struct iovec *iov,
-                   int iovcnt, off_t offset);
-ssize_t
-blocking_op_pread(wasm_exec_env_t exec_env, int fd, void *p, size_t nb,
-                  off_t offset);
-ssize_t
-blocking_op_writev(wasm_exec_env_t exec_env, int fd, const struct iovec *iov,
-                   int iovcnt);
-ssize_t
-blocking_op_pwritev(wasm_exec_env_t exec_env, int fd, const struct iovec *iov,
-                    int iovcnt, off_t offset);
-ssize_t
-blocking_op_pwrite(wasm_exec_env_t exec_env, int fd, const void *p, size_t nb,
-                   off_t offset);
+__wasi_errno_t
+blocking_op_close(wasm_exec_env_t exec_env, os_file_handle handle,
+                  bool is_stdio);
+__wasi_errno_t
+blocking_op_readv(wasm_exec_env_t exec_env, os_file_handle handle,
+                  const struct __wasi_iovec_t *iov, int iovcnt, size_t *nread);
+__wasi_errno_t
+blocking_op_preadv(wasm_exec_env_t exec_env, os_file_handle handle,
+                   const struct __wasi_iovec_t *iov, int iovcnt,
+                   __wasi_filesize_t offset, size_t *nread);
+__wasi_errno_t
+blocking_op_writev(wasm_exec_env_t exec_env, os_file_handle handle,
+                   const struct __wasi_ciovec_t *iov, int iovcnt,
+                   size_t *nwritten);
+__wasi_errno_t
+blocking_op_pwritev(wasm_exec_env_t exec_env, os_file_handle handle,
+                    const struct __wasi_ciovec_t *iov, int iovcnt,
+                    __wasi_filesize_t offset, size_t *nwritten);
 int
 blocking_op_socket_accept(wasm_exec_env_t exec_env, bh_socket_t server_sock,
                           bh_socket_t *sockp, void *addr,
@@ -47,6 +45,9 @@ blocking_op_socket_addr_resolve(wasm_exec_env_t exec_env, const char *host,
                                 uint8_t *hint_is_ipv4,
                                 bh_addr_info_t *addr_info,
                                 size_t addr_info_size, size_t *max_info_size);
-int
-blocking_op_openat(wasm_exec_env_t exec_env, int fd, const char *path,
-                   int oflags, mode_t mode);
+
+__wasi_errno_t
+blocking_op_openat(wasm_exec_env_t exec_env, os_file_handle handle,
+                   const char *path, __wasi_oflags_t oflags,
+                   __wasi_fdflags_t fd_flags, __wasi_lookupflags_t lookup_flags,
+                   wasi_libc_file_access_mode access_mode, os_file_handle *out);

+ 31 - 23
core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/locking.h

@@ -49,7 +49,7 @@
 /* Mutex that uses the lock annotations. */
 
 struct LOCKABLE mutex {
-    pthread_mutex_t object;
+    korp_mutex object;
 };
 
 /* clang-format off */
@@ -60,69 +60,71 @@ struct LOCKABLE mutex {
 static inline bool
 mutex_init(struct mutex *lock) REQUIRES_UNLOCKED(*lock)
 {
-    return pthread_mutex_init(&lock->object, NULL) == 0 ? true : false;
+    return os_mutex_init(&lock->object) == BHT_OK ? true : false;
 }
 
 static inline void
 mutex_destroy(struct mutex *lock) REQUIRES_UNLOCKED(*lock)
 {
-    pthread_mutex_destroy(&lock->object);
+    os_mutex_destroy(&lock->object);
 }
 
 static inline void
 mutex_lock(struct mutex *lock) LOCKS_EXCLUSIVE(*lock) NO_LOCK_ANALYSIS
 {
-    pthread_mutex_lock(&lock->object);
+    os_mutex_lock(&lock->object);
 }
 
 static inline void
 mutex_unlock(struct mutex *lock) UNLOCKS(*lock) NO_LOCK_ANALYSIS
 {
-    pthread_mutex_unlock(&lock->object);
+    os_mutex_unlock(&lock->object);
 }
 
 /* Read-write lock that uses the lock annotations. */
 
 struct LOCKABLE rwlock {
-    pthread_rwlock_t object;
+    korp_rwlock object;
 };
 
 static inline bool
 rwlock_init(struct rwlock *lock) REQUIRES_UNLOCKED(*lock)
 {
-    return pthread_rwlock_init(&lock->object, NULL) == 0 ? true : false;
+    return os_rwlock_init(&lock->object) == 0 ? true : false;
 }
 
 static inline void
 rwlock_rdlock(struct rwlock *lock) LOCKS_SHARED(*lock) NO_LOCK_ANALYSIS
 {
-    pthread_rwlock_rdlock(&lock->object);
+    os_rwlock_rdlock(&lock->object);
 }
 
 static inline void
 rwlock_wrlock(struct rwlock *lock) LOCKS_EXCLUSIVE(*lock) NO_LOCK_ANALYSIS
 {
-    pthread_rwlock_wrlock(&lock->object);
+    os_rwlock_wrlock(&lock->object);
 }
 
 static inline void
 rwlock_unlock(struct rwlock *lock) UNLOCKS(*lock) NO_LOCK_ANALYSIS
 {
-    pthread_rwlock_unlock(&lock->object);
+    os_rwlock_unlock(&lock->object);
 }
 
 static inline void
 rwlock_destroy(struct rwlock *lock) UNLOCKS(*lock) NO_LOCK_ANALYSIS
 {
-    pthread_rwlock_destroy(&lock->object);
+    os_rwlock_destroy(&lock->object);
 }
 
 /* Condition variable that uses the lock annotations. */
 
 struct LOCKABLE cond {
-    pthread_cond_t object;
-#if !CONFIG_HAS_PTHREAD_CONDATTR_SETCLOCK \
-    || !CONFIG_HAS_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP
+    korp_cond object;
+
+#if !CONFIG_HAS_CLOCK_NANOSLEEP               \
+    && (!CONFIG_HAS_PTHREAD_CONDATTR_SETCLOCK \
+        || !CONFIG_HAS_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP)
     clockid_t clock;
 #endif
 };
@@ -147,43 +149,49 @@ cond_init_monotonic(struct cond *cond)
 fail:
     pthread_condattr_destroy(&attr);
 #else
-    if (pthread_cond_init(&cond->object, NULL) != 0)
+    if (os_cond_init(&cond->object) != 0)
         return false;
     ret = true;
 #endif
 
-#if !CONFIG_HAS_PTHREAD_CONDATTR_SETCLOCK \
-    || !CONFIG_HAS_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP
+#if !CONFIG_HAS_CLOCK_NANOSLEEP               \
+    && (!CONFIG_HAS_PTHREAD_CONDATTR_SETCLOCK \
+        || !CONFIG_HAS_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP)
     cond->clock = CLOCK_MONOTONIC;
 #endif
+
     return ret;
 }
 
 static inline bool
 cond_init_realtime(struct cond *cond)
 {
-    if (pthread_cond_init(&cond->object, NULL) != 0)
+    if (os_cond_init(&cond->object) != 0)
         return false;
-#if !CONFIG_HAS_PTHREAD_CONDATTR_SETCLOCK \
-    || !CONFIG_HAS_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP
+
+#if !CONFIG_HAS_CLOCK_NANOSLEEP               \
+    && (!CONFIG_HAS_PTHREAD_CONDATTR_SETCLOCK \
+        || !CONFIG_HAS_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP)
     cond->clock = CLOCK_REALTIME;
 #endif
+
     return true;
 }
 
 static inline void
 cond_destroy(struct cond *cond)
 {
-    pthread_cond_destroy(&cond->object);
+    os_cond_destroy(&cond->object);
 }
 
 static inline void
 cond_signal(struct cond *cond)
 {
-    pthread_cond_signal(&cond->object);
+    os_cond_signal(&cond->object);
 }
 
 #if !CONFIG_HAS_CLOCK_NANOSLEEP
+
 static inline bool
 cond_timedwait(struct cond *cond, struct mutex *lock, uint64_t timeout,
                bool abstime) REQUIRES_EXCLUSIVE(*lock) NO_LOCK_ANALYSIS
@@ -259,7 +267,7 @@ static inline void
 cond_wait(struct cond *cond, struct mutex *lock)
     REQUIRES_EXCLUSIVE(*lock) NO_LOCK_ANALYSIS
 {
-    pthread_cond_wait(&cond->object, &lock->object);
+    os_cond_wait(&cond->object, &lock->object);
 }
 
 #endif

文件差異過大導致無法顯示
+ 200 - 527
core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c


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

@@ -60,7 +60,8 @@ struct addr_pool {
 bool
 fd_table_init(struct fd_table *);
 bool
-fd_table_insert_existing(struct fd_table *, __wasi_fd_t, int);
+fd_table_insert_existing(struct fd_table *, __wasi_fd_t, os_file_handle,
+                         bool is_stdio);
 bool
 fd_prestats_init(struct fd_prestats *);
 bool

+ 59 - 20
core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/random.c

@@ -13,14 +13,16 @@
 
 #include "ssp_config.h"
 #include "bh_platform.h"
+#include "libc_errno.h"
 #include "random.h"
 
 #if CONFIG_HAS_ARC4RANDOM_BUF
 
-void
+__wasi_errno_t
 random_buf(void *buf, size_t len)
 {
     arc4random_buf(buf, len);
+    return __WASI_ESUCCESS;
 }
 
 #elif CONFIG_HAS_GETRANDOM
@@ -29,7 +31,7 @@ random_buf(void *buf, size_t len)
 #include <sys/random.h>
 #endif
 
-void
+__wasi_errno_t
 random_buf(void *buf, size_t len)
 {
     for (;;) {
@@ -37,40 +39,71 @@ random_buf(void *buf, size_t len)
         if (x < 0) {
             if (errno == EINTR)
                 continue;
-            os_printf("getrandom failed: %s", strerror(errno));
-            abort();
+            return convert_errno(errno);
         }
         if ((size_t)x == len)
-            return;
+            break;
         buf = (void *)((unsigned char *)buf + x);
         len -= (size_t)x;
     }
+    return __WASI_ESUCCESS;
+}
+
+#elif defined(BH_PLATFORM_WINDOWS)
+
+#include <bcrypt.h>
+#pragma comment(lib, "Bcrypt.lib")
+
+__wasi_errno_t
+random_buf(void *buf, size_t len)
+{
+    NTSTATUS ret =
+        BCryptGenRandom(NULL, buf, (ULONG)len, BCRYPT_USE_SYSTEM_PREFERRED_RNG);
+
+    // Since we pass NULL for the algorithm handle, the only way BCryptGenRandom
+    // can fail is if one of the parameters is invalid
+    // (STATUS_INVALID_PARAMETER).
+    return ret ? __WASI_EINVAL : __WASI_ESUCCESS;
 }
 
 #else
 
-static int urandom;
+static int urandom = -1;
+static __wasi_errno_t urandom_error = __WASI_ESUCCESS;
 
 static void
 open_urandom(void)
 {
     urandom = open("/dev/urandom", O_RDONLY);
-    if (urandom < 0) {
-        os_printf("Failed to open /dev/urandom\n");
-        abort();
-    }
+    if (urandom < 0)
+        urandom_error = convert_errno(errno);
 }
 
-void
+__wasi_errno_t
 random_buf(void *buf, size_t len)
 {
     static pthread_once_t open_once = PTHREAD_ONCE_INIT;
-    pthread_once(&open_once, open_urandom);
+    int pthread_ret = pthread_once(&open_once, open_urandom);
+
+    if (pthread_ret != 0)
+        return convert_errno(pthread_ret);
 
-    if ((size_t)read(urandom, buf, len) != len) {
-        os_printf("Short read on /dev/urandom\n");
-        abort();
+    if (urandom < 0)
+        return urandom_error;
+
+    size_t bytes_read = 0;
+
+    while (bytes_read < len) {
+        ssize_t bytes_read_now =
+            read(urandom, buf + bytes_read, len - bytes_read);
+
+        if (bytes_read_now < 0)
+            return convert_errno(errno);
+
+        bytes_read += (size_t)bytes_read_now;
     }
+
+    return __WASI_ESUCCESS;
 }
 
 #endif
@@ -82,8 +115,8 @@ random_buf(void *buf, size_t len)
 // arc4random() until it lies within the range [2^k % upper, 2^k). As
 // this range has length k * upper, we can safely obtain a number
 // without any modulo bias.
-uintmax_t
-random_uniform(uintmax_t upper)
+__wasi_errno_t
+random_uniform(uintmax_t upper, uintmax_t *out)
 {
     // Compute 2^k % upper
     //      == (2^k - upper) % upper
@@ -91,8 +124,14 @@ random_uniform(uintmax_t upper)
     uintmax_t lower = -upper % upper;
     for (;;) {
         uintmax_t value;
-        random_buf(&value, sizeof(value));
-        if (value >= lower)
-            return value % upper;
+        __wasi_errno_t error = random_buf(&value, sizeof(value));
+
+        if (error != __WASI_ESUCCESS)
+            return error;
+
+        if (value >= lower) {
+            *out = value % upper;
+            return error;
+        }
     }
 }

+ 6 - 2
core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/random.h

@@ -14,8 +14,12 @@
 #ifndef RANDOM_H
 #define RANDOM_H
 
-void
+#include "bh_platform.h"
+
+__wasi_errno_t
 random_buf(void *, size_t);
-uintmax_t random_uniform(uintmax_t);
+
+__wasi_errno_t
+random_uniform(uintmax_t upper, uintmax_t *out);
 
 #endif

+ 1 - 63
core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/ssp_config.h

@@ -47,75 +47,19 @@
 #define CONFIG_HAS_CLOCK_NANOSLEEP 0
 #endif
 
-#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(ESP_PLATFORM)
-#define CONFIG_HAS_FDATASYNC 1
-#else
-#define CONFIG_HAS_FDATASYNC 0
-#endif
-
-/*
- * For NuttX, CONFIG_HAS_ISATTY is provided by its platform header.
- * (platform_internal.h)
- */
-#ifndef __NuttX__
-#ifndef __CloudABI__
-#define CONFIG_HAS_ISATTY 1
-#else
-#define CONFIG_HAS_ISATTY 0
-#endif
-#endif
-
-#if !defined(__APPLE__) && !defined(ESP_PLATFORM) && !defined(__COSMOPOLITAN__)
-#define CONFIG_HAS_POSIX_FALLOCATE 1
-#else
-#define CONFIG_HAS_POSIX_FALLOCATE 0
-#endif
-
-#if !defined(__APPLE__) && !defined(ESP_PLATFORM)
-#define CONFIG_HAS_PREADV 1
-#else
-#define CONFIG_HAS_PREADV 0
-#endif
-
 #if defined(__APPLE__) || defined(__CloudABI__)
 #define CONFIG_HAS_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP 1
 #else
 #define CONFIG_HAS_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP 0
 #endif
 
-#if !defined(__APPLE__) && !defined(BH_PLATFORM_LINUX_SGX) \
+#if !defined(__APPLE__) && !defined(BH_PLATFORM_LINUX_SGX) && !defined(_WIN32) \
     && !defined(__COSMOPOLITAN__)
 #define CONFIG_HAS_PTHREAD_CONDATTR_SETCLOCK 1
 #else
 #define CONFIG_HAS_PTHREAD_CONDATTR_SETCLOCK 0
 #endif
 
-#if !defined(__APPLE__) && !defined(ESP_PLATFORM)
-#define CONFIG_HAS_PWRITEV 1
-#else
-#define CONFIG_HAS_PWRITEV 0
-#endif
-
-#ifdef __APPLE__
-#define st_atim st_atimespec
-#define st_ctim st_ctimespec
-#define st_mtim st_mtimespec
-#endif
-
-#if defined(O_DSYNC)
-#define CONFIG_HAS_O_DSYNC
-#endif
-
-// POSIX requires O_RSYNC to be defined, but Linux explicitly doesn't support
-// it.
-#if defined(O_RSYNC) && !defined(__linux__)
-#define CONFIG_HAS_O_RSYNC
-#endif
-
-#if defined(O_SYNC)
-#define CONFIG_HAS_O_SYNC
-#endif
-
 #if !defined(BH_PLATFORM_LINUX_SGX)
 /* Clang's __GNUC_PREREQ macro has a different meaning than GCC one,
 so we have to handle this case specially */
@@ -143,10 +87,4 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58016 */
 #define CONFIG_HAS_STD_ATOMIC 0
 #endif /* end of !defined(BH_PLATFORM_LINUX_SGX) */
 
-#if !defined(__NuttX__)
-#define CONFIG_HAS_D_INO 1
-#else
-#define CONFIG_HAS_D_INO 0
-#endif
-
 #endif

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

@@ -1406,3 +1406,19 @@ exception_unlock(WASMModuleInstance *module_inst)
 {
     os_mutex_unlock(&_exception_lock);
 }
+
+void
+wasm_cluster_traverse_lock(WASMExecEnv *exec_env)
+{
+    WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env);
+    bh_assert(cluster);
+    os_mutex_lock(&cluster->lock);
+}
+
+void
+wasm_cluster_traverse_unlock(WASMExecEnv *exec_env)
+{
+    WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env);
+    bh_assert(cluster);
+    os_mutex_unlock(&cluster->lock);
+}

+ 6 - 0
core/iwasm/libraries/thread-mgr/thread_manager.h

@@ -215,6 +215,12 @@ wasm_cluster_set_debug_inst(WASMCluster *cluster, WASMDebugInstance *inst);
 
 #endif /* end of WASM_ENABLE_DEBUG_INTERP != 0 */
 
+void
+wasm_cluster_traverse_lock(WASMExecEnv *exec_env);
+
+void
+wasm_cluster_traverse_unlock(WASMExecEnv *exec_env);
+
 #ifdef __cplusplus
 }
 #endif

+ 54 - 2
core/shared/mem-alloc/ems/ems_alloc.c

@@ -45,19 +45,23 @@ hmu_is_in_heap(void *hmu, gc_uint8 *heap_base_addr, gc_uint8 *heap_end_addr)
 static bool
 remove_tree_node(gc_heap_t *heap, hmu_tree_node_t *p)
 {
-    hmu_tree_node_t *q = NULL, **slot = NULL, *parent;
-    hmu_tree_node_t *root = heap->kfc_tree_root;
+    hmu_tree_node_t *q = NULL, **slot = NULL;
+#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
+    hmu_tree_node_t *root = heap->kfc_tree_root, *parent;
     gc_uint8 *base_addr = heap->base_addr;
     gc_uint8 *end_addr = base_addr + heap->current_size;
+#endif
 
     bh_assert(p);
 
+#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
     parent = p->parent;
     if (!parent || p == root /* p can not be the ROOT node */
         || !hmu_is_in_heap(p, base_addr, end_addr)
         || (parent != root && !hmu_is_in_heap(parent, base_addr, end_addr))) {
         goto fail;
     }
+#endif
 
     /* get the slot which holds pointer to node p */
     if (p == p->parent->right) {
@@ -88,9 +92,11 @@ remove_tree_node(gc_heap_t *heap, hmu_tree_node_t *p)
         /* move right child up*/
         *slot = p->right;
         if (p->right) {
+#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
             if (!hmu_is_in_heap(p->right, base_addr, end_addr)) {
                 goto fail;
             }
+#endif
             p->right->parent = p->parent;
         }
 
@@ -101,9 +107,11 @@ remove_tree_node(gc_heap_t *heap, hmu_tree_node_t *p)
     if (!p->right) {
         /* move left child up*/
         *slot = p->left;
+#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
         if (!hmu_is_in_heap(p->left, base_addr, end_addr)) {
             goto fail;
         }
+#endif
         /* p->left can never be NULL unless it is corrupted. */
         p->left->parent = p->parent;
 
@@ -113,14 +121,18 @@ remove_tree_node(gc_heap_t *heap, hmu_tree_node_t *p)
 
     /* both left & right exist, find p's predecessor at first*/
     q = p->left;
+#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
     if (!hmu_is_in_heap(q, base_addr, end_addr)) {
         goto fail;
     }
+#endif
     while (q->right) {
         q = q->right;
+#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
         if (!hmu_is_in_heap(q, base_addr, end_addr)) {
             goto fail;
         }
+#endif
     }
 
     /* remove from the tree*/
@@ -132,15 +144,19 @@ remove_tree_node(gc_heap_t *heap, hmu_tree_node_t *p)
     q->left = p->left;
     q->right = p->right;
     if (q->left) {
+#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
         if (!hmu_is_in_heap(q->left, base_addr, end_addr)) {
             goto fail;
         }
+#endif
         q->left->parent = q;
     }
     if (q->right) {
+#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
         if (!hmu_is_in_heap(q->right, base_addr, end_addr)) {
             goto fail;
         }
+#endif
         q->right->parent = q;
     }
 
@@ -148,27 +164,35 @@ remove_tree_node(gc_heap_t *heap, hmu_tree_node_t *p)
 
     return true;
 fail:
+#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
     heap->is_heap_corrupted = true;
+#endif
     return false;
 }
 
 static bool
 unlink_hmu(gc_heap_t *heap, hmu_t *hmu)
 {
+#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
     gc_uint8 *base_addr, *end_addr;
+#endif
     gc_size_t size;
 
     bh_assert(gci_is_heap_valid(heap));
     bh_assert(hmu && (gc_uint8 *)hmu >= heap->base_addr
               && (gc_uint8 *)hmu < heap->base_addr + heap->current_size);
 
+#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
     if (hmu_get_ut(hmu) != HMU_FC) {
         heap->is_heap_corrupted = true;
         return false;
     }
+#endif
 
+#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
     base_addr = heap->base_addr;
     end_addr = base_addr + heap->current_size;
+#endif
     size = hmu_get_size(hmu);
 
     if (HMU_IS_FC_NORMAL(size)) {
@@ -177,10 +201,12 @@ unlink_hmu(gc_heap_t *heap, hmu_t *hmu)
         hmu_normal_node_t *node = heap->kfc_normal_list[node_idx].next;
 
         while (node) {
+#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
             if (!hmu_is_in_heap(node, base_addr, end_addr)) {
                 heap->is_heap_corrupted = true;
                 return false;
             }
+#endif
             node_next = get_hmu_normal_node_next(node);
             if ((hmu_t *)node == hmu) {
                 if (!node_prev) /* list head */
@@ -226,7 +252,9 @@ hmu_set_free_size(hmu_t *hmu)
 bool
 gci_add_fc(gc_heap_t *heap, hmu_t *hmu, gc_size_t size)
 {
+#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
     gc_uint8 *base_addr, *end_addr;
+#endif
     hmu_normal_node_t *np = NULL;
     hmu_tree_node_t *root = NULL, *tp = NULL, *node = NULL;
     uint32 node_idx;
@@ -240,8 +268,10 @@ gci_add_fc(gc_heap_t *heap, hmu_t *hmu, gc_size_t size)
                      <= heap->base_addr + heap->current_size);
     bh_assert(!(size & 7));
 
+#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
     base_addr = heap->base_addr;
     end_addr = base_addr + heap->current_size;
+#endif
 
     hmu_set_ut(hmu, HMU_FC);
     hmu_set_size(hmu, size);
@@ -249,10 +279,12 @@ gci_add_fc(gc_heap_t *heap, hmu_t *hmu, gc_size_t size)
 
     if (HMU_IS_FC_NORMAL(size)) {
         np = (hmu_normal_node_t *)hmu;
+#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
         if (!hmu_is_in_heap(np, base_addr, end_addr)) {
             heap->is_heap_corrupted = true;
             return false;
         }
+#endif
 
         node_idx = size >> 3;
         set_hmu_normal_node_next(np, heap->kfc_normal_list[node_idx].next);
@@ -286,10 +318,12 @@ gci_add_fc(gc_heap_t *heap, hmu_t *hmu, gc_size_t size)
             }
             tp = tp->left;
         }
+#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
         if (!hmu_is_in_heap(tp, base_addr, end_addr)) {
             heap->is_heap_corrupted = true;
             return false;
         }
+#endif
     }
     return true;
 }
@@ -347,15 +381,19 @@ alloc_hmu(gc_heap_t *heap, gc_size_t size)
             bh_assert(node_idx >= init_node_idx);
 
             p = normal_head->next;
+#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
             if (!hmu_is_in_heap(p, base_addr, end_addr)) {
                 heap->is_heap_corrupted = true;
                 return NULL;
             }
+#endif
             normal_head->next = get_hmu_normal_node_next(p);
+#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
             if (((gc_int32)(uintptr_t)hmu_to_obj(p) & 7) != 0) {
                 heap->is_heap_corrupted = true;
                 return NULL;
             }
+#endif
 
             if ((gc_size_t)node_idx != (uint32)init_node_idx
                 /* with bigger size*/
@@ -391,10 +429,12 @@ alloc_hmu(gc_heap_t *heap, gc_size_t size)
     bh_assert(root);
     tp = root->right;
     while (tp) {
+#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
         if (!hmu_is_in_heap(tp, base_addr, end_addr)) {
             heap->is_heap_corrupted = true;
             return NULL;
         }
+#endif
 
         if (tp->size < size) {
             tp = tp->right;
@@ -533,10 +573,12 @@ gc_alloc_vo_internal(void *vheap, gc_size_t size, const char *file, int line)
         /* integer overflow */
         return NULL;
 
+#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
     if (heap->is_heap_corrupted) {
         os_printf("[GC_ERROR]Heap is corrupted, allocate memory failed.\n");
         return NULL;
     }
+#endif
 
     LOCK_HEAP(heap);
 
@@ -595,10 +637,12 @@ gc_realloc_vo_internal(void *vheap, void *ptr, gc_size_t size, const char *file,
         /* integer overflow */
         return NULL;
 
+#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
     if (heap->is_heap_corrupted) {
         os_printf("[GC_ERROR]Heap is corrupted, allocate memory failed.\n");
         return NULL;
     }
+#endif
 
     if (obj_old) {
         hmu_old = obj_to_hmu(obj_old);
@@ -808,10 +852,12 @@ gc_free_vo_internal(void *vheap, gc_object_t obj, const char *file, int line)
         return GC_SUCCESS;
     }
 
+#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
     if (heap->is_heap_corrupted) {
         os_printf("[GC_ERROR]Heap is corrupted, free memory failed.\n");
         return GC_ERROR;
     }
+#endif
 
     hmu = obj_to_hmu(obj);
 
@@ -934,11 +980,13 @@ gci_dump(gc_heap_t *heap)
         else if (ut == HMU_FC)
             inuse = 'F';
 
+#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
         if (size == 0 || size > (uint32)((uint8 *)end - (uint8 *)cur)) {
             os_printf("[GC_ERROR]Heap is corrupted, heap dump failed.\n");
             heap->is_heap_corrupted = true;
             return;
         }
+#endif
 
         os_printf("#%d %08" PRIx32 " %" PRIx32 " %d %d"
                   " %c %" PRId32 "\n",
@@ -955,10 +1003,14 @@ gci_dump(gc_heap_t *heap)
         i++;
     }
 
+#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
     if (cur != end) {
         os_printf("[GC_ERROR]Heap is corrupted, heap dump failed.\n");
         heap->is_heap_corrupted = true;
     }
+#else
+    bh_assert(cur == end);
+#endif
 }
 
 #if WASM_ENABLE_GC != 0

+ 2 - 0
core/shared/mem-alloc/ems/ems_gc_internal.h

@@ -298,9 +298,11 @@ typedef struct gc_heap_struct {
     unsigned is_reclaim_enabled : 1;
 #endif
 
+#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
     /* whether heap is corrupted, e.g. the hmu nodes are modified
        by user */
     bool is_heap_corrupted;
+#endif
 
     gc_size_t init_size;
     gc_size_t highmark_size;

+ 2 - 0
core/shared/mem-alloc/ems/ems_hmu.c

@@ -83,7 +83,9 @@ hmu_verify(void *vheap, hmu_t *hmu)
             os_printf("Invalid padding for object created at %s:%d\n",
                       (prefix->file_name ? prefix->file_name : ""),
                       prefix->line_no);
+#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
             heap->is_heap_corrupted = true;
+#endif
         }
     }
 }

+ 17 - 2
core/shared/mem-alloc/ems/ems_kfc.c

@@ -160,8 +160,11 @@ gc_destroy_with_pool(gc_handle_t handle)
     hmu_t *cur = (hmu_t *)heap->base_addr;
     hmu_t *end = (hmu_t *)((char *)heap->base_addr + heap->current_size);
 
-    if (!heap->is_heap_corrupted
-        && (hmu_t *)((char *)cur + hmu_get_size(cur)) != end) {
+    if (
+#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
+        !heap->is_heap_corrupted &&
+#endif
+        (hmu_t *)((char *)cur + hmu_get_size(cur)) != end) {
         os_printf("Memory leak detected:\n");
         gci_dump(heap);
         ret = GC_ERROR;
@@ -236,10 +239,12 @@ gc_migrate(gc_handle_t handle, char *pool_buf_new, gc_size_t pool_buf_size)
     if (offset == 0)
         return 0;
 
+#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
     if (heap->is_heap_corrupted) {
         os_printf("[GC_ERROR]Heap is corrupted, heap migrate failed.\n");
         return GC_ERROR;
     }
+#endif
 
     heap->base_addr = (uint8 *)base_addr_new;
 
@@ -261,11 +266,13 @@ gc_migrate(gc_handle_t handle, char *pool_buf_new, gc_size_t pool_buf_size)
     while (cur < end) {
         size = hmu_get_size(cur);
 
+#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
         if (size <= 0 || size > (uint32)((uint8 *)end - (uint8 *)cur)) {
             os_printf("[GC_ERROR]Heap is corrupted, heap migrate failed.\n");
             heap->is_heap_corrupted = true;
             return GC_ERROR;
         }
+#endif
 
         if (hmu_get_ut(cur) == HMU_FC && !HMU_IS_FC_NORMAL(size)) {
             tree_node = (hmu_tree_node_t *)cur;
@@ -288,11 +295,15 @@ gc_migrate(gc_handle_t handle, char *pool_buf_new, gc_size_t pool_buf_size)
         cur = (hmu_t *)((char *)cur + size);
     }
 
+#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
     if (cur != end) {
         os_printf("[GC_ERROR]Heap is corrupted, heap migrate failed.\n");
         heap->is_heap_corrupted = true;
         return GC_ERROR;
     }
+#else
+    bh_assert(cur == end);
+#endif
 
     return 0;
 }
@@ -300,9 +311,13 @@ gc_migrate(gc_handle_t handle, char *pool_buf_new, gc_size_t pool_buf_size)
 bool
 gc_is_heap_corrupted(gc_handle_t handle)
 {
+#if BH_ENABLE_GC_CORRUPTION_CHECK != 0
     gc_heap_t *heap = (gc_heap_t *)handle;
 
     return heap->is_heap_corrupted ? true : false;
+#else
+    return false;
+#endif
 }
 
 #if BH_ENABLE_GC_VERIFY != 0

+ 8 - 0
core/shared/mem-alloc/mem_alloc.cmake

@@ -10,6 +10,14 @@ if (WAMR_BUILD_GC_VERIFY EQUAL 1)
     add_definitions (-DBH_ENABLE_GC_VERIFY=1)
 endif ()
 
+if (NOT DEFINED WAMR_BUILD_GC_CORRUPTION_CHECK)
+    set (WAMR_BUILD_GC_CORRUPTION_CHECK 1)
+endif ()
+
+if (WAMR_BUILD_GC_CORRUPTION_CHECK EQUAL 0)
+    add_definitions (-DBH_ENABLE_GC_CORRUPTION_CHECK=0)
+endif ()
+
 file (GLOB_RECURSE source_all
       ${MEM_ALLOC_DIR}/ems/*.c
       ${MEM_ALLOC_DIR}/tlsf/*.c

+ 1 - 1
core/shared/platform/alios/alios_platform.c

@@ -47,7 +47,7 @@ os_dumps_proc_mem_info(char *out, unsigned int size)
 }
 
 void *
-os_mmap(void *hint, size_t size, int prot, int flags)
+os_mmap(void *hint, size_t size, int prot, int flags, os_file_handle file)
 {
     if ((uint64)size >= UINT32_MAX)
         return NULL;

+ 18 - 0
core/shared/platform/alios/platform_internal.h

@@ -32,6 +32,12 @@ typedef aos_task_t *aos_tid_t;
 typedef aos_mutex_t korp_mutex;
 typedef aos_sem_t korp_sem;
 
+/* korp_rwlock is used in platform_api_extension.h,
+   we just define the type to make the compiler happy */
+typedef struct {
+    int dummy;
+} korp_rwlock;
+
 struct os_thread_wait_node;
 typedef struct os_thread_wait_node *os_thread_wait_list;
 typedef struct korp_cond {
@@ -64,4 +70,16 @@ int signbit(double x);
 int isnan(double x);
 /* clang-format on */
 
+/* The below types are used in platform_api_extension.h,
+   we just define them to make the compiler happy */
+typedef int os_file_handle;
+typedef void *os_dir_stream;
+typedef int os_raw_file_handle;
+
+static inline os_file_handle
+os_get_invalid_handle()
+{
+    return -1;
+}
+
 #endif /* end of _BH_PLATFORM_H */

+ 11 - 0
core/shared/platform/android/platform_internal.h

@@ -56,6 +56,7 @@ typedef pthread_t korp_tid;
 typedef pthread_mutex_t korp_mutex;
 typedef pthread_cond_t korp_cond;
 typedef pthread_t korp_thread;
+typedef pthread_rwlock_t korp_rwlock;
 typedef sem_t korp_sem;
 
 #define OS_THREAD_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
@@ -145,6 +146,16 @@ preadv(int __fd, const struct iovec *__iov, int __count, off_t __offset);
 ssize_t
 pwritev(int __fd, const struct iovec *__iov, int __count, off_t __offset);
 
+typedef int os_file_handle;
+typedef DIR *os_dir_stream;
+typedef int os_raw_file_handle;
+
+static inline os_file_handle
+os_get_invalid_handle()
+{
+    return -1;
+}
+
 #ifdef __cplusplus
 }
 #endif

+ 256 - 0
core/shared/platform/common/libc-util/libc_errno.c

@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2023 Intel Corporation. All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#include "errno.h"
+#include "libc_errno.h"
+
+__wasi_errno_t
+convert_errno(int error)
+{
+    // The C standard library only requires EDOM, EILSEQ and ERANGE to be
+    // defined. Other error codes are POSIX-specific and hence may or may
+    // not be available on non-POSIX platforms.
+    __wasi_errno_t code = __WASI_ENOSYS;
+#define X(v)               \
+    case v:                \
+        code = __WASI_##v; \
+        break;
+    switch (error) {
+        X(EDOM)
+        X(EILSEQ)
+        X(ERANGE)
+#ifdef E2BIG
+        X(E2BIG)
+#endif
+#ifdef EACCES
+        X(EACCES)
+#endif
+#ifdef EADDRINUSE
+        X(EADDRINUSE)
+#endif
+#ifdef EADDRNOTAVAIL
+        X(EADDRNOTAVAIL)
+#endif
+#ifdef EAFNOSUPPORT
+        X(EAFNOSUPPORT)
+#endif
+#ifdef EAGAIN
+        X(EAGAIN)
+#endif
+#ifdef EALREADY
+        X(EALREADY)
+#endif
+#ifdef EBADF
+        X(EBADF)
+#endif
+#ifdef EBADMSG
+        X(EBADMSG)
+#endif
+#ifdef EBUSY
+        X(EBUSY)
+#endif
+#ifdef ECANCELED
+        X(ECANCELED)
+#endif
+#ifdef ECHILD
+        X(ECHILD)
+#endif
+#ifdef ECONNABORTED
+        X(ECONNABORTED)
+#endif
+#ifdef ECONNREFUSED
+        X(ECONNREFUSED)
+#endif
+#ifdef ECONNRESET
+        X(ECONNRESET)
+#endif
+#ifdef EDEADLK
+        X(EDEADLK)
+#endif
+#ifdef EDESTADDRREQ
+        X(EDESTADDRREQ)
+#endif
+#ifdef EDQUOT
+        X(EDQUOT)
+#endif
+#ifdef EEXIST
+        X(EEXIST)
+#endif
+#ifdef EFAULT
+        X(EFAULT)
+#endif
+#ifdef EFBIG
+        X(EFBIG)
+#endif
+#ifdef EHOSTUNREACH
+        X(EHOSTUNREACH)
+#endif
+#ifdef EIDRM
+        X(EIDRM)
+#endif
+#ifdef EINPROGRESS
+        X(EINPROGRESS)
+#endif
+#ifdef EINTR
+        X(EINTR)
+#endif
+#ifdef EINVAL
+        X(EINVAL)
+#endif
+#ifdef EIO
+        X(EIO)
+#endif
+#ifdef EISCONN
+        X(EISCONN)
+#endif
+#ifdef EISDIR
+        X(EISDIR)
+#endif
+#ifdef ELOOP
+        X(ELOOP)
+#endif
+#ifdef EMFILE
+        X(EMFILE)
+#endif
+#ifdef EMLINK
+        X(EMLINK)
+#endif
+#ifdef EMSGSIZE
+        X(EMSGSIZE)
+#endif
+#ifdef EMULTIHOP
+        X(EMULTIHOP)
+#endif
+#ifdef ENAMETOOLONG
+        X(ENAMETOOLONG)
+#endif
+#ifdef ENETDOWN
+        X(ENETDOWN)
+#endif
+#ifdef ENETRESET
+        X(ENETRESET)
+#endif
+#ifdef ENETUNREACH
+        X(ENETUNREACH)
+#endif
+#ifdef ENFILE
+        X(ENFILE)
+#endif
+#ifdef ENOBUFS
+        X(ENOBUFS)
+#endif
+#ifdef ENODEV
+        X(ENODEV)
+#endif
+#ifdef ENOENT
+        X(ENOENT)
+#endif
+#ifdef ENOEXEC
+        X(ENOEXEC)
+#endif
+#ifdef ENOLCK
+        X(ENOLCK)
+#endif
+#ifdef ENOLINK
+        X(ENOLINK)
+#endif
+#ifdef ENOMEM
+        X(ENOMEM)
+#endif
+#ifdef ENOMSG
+        X(ENOMSG)
+#endif
+#ifdef ENOPROTOOPT
+        X(ENOPROTOOPT)
+#endif
+#ifdef ENOSPC
+        X(ENOSPC)
+#endif
+#ifdef ENOSYS
+        X(ENOSYS)
+#endif
+#ifdef ENOTCAPABLE
+        X(ENOTCAPABLE)
+#endif
+#ifdef ENOTCONN
+        X(ENOTCONN)
+#endif
+#ifdef ENOTDIR
+        X(ENOTDIR)
+#endif
+#ifdef ENOTEMPTY
+        X(ENOTEMPTY)
+#endif
+#ifdef ENOTRECOVERABLE
+        X(ENOTRECOVERABLE)
+#endif
+#ifdef ENOTSOCK
+        X(ENOTSOCK)
+#endif
+#ifdef ENOTSUP
+        X(ENOTSUP)
+#endif
+#ifdef ENOTTY
+        X(ENOTTY)
+#endif
+#ifdef ENXIO
+        X(ENXIO)
+#endif
+#ifdef EOVERFLOW
+        X(EOVERFLOW)
+#endif
+#ifdef EOWNERDEAD
+        X(EOWNERDEAD)
+#endif
+#ifdef EPERM
+        X(EPERM)
+#endif
+#ifdef EPIPE
+        X(EPIPE)
+#endif
+#ifdef EPROTO
+        X(EPROTO)
+#endif
+#ifdef EPROTONOSUPPORT
+        X(EPROTONOSUPPORT)
+#endif
+#ifdef EPROTOTYPE
+        X(EPROTOTYPE)
+#endif
+#ifdef EROFS
+        X(EROFS)
+#endif
+#ifdef ESPIPE
+        X(ESPIPE)
+#endif
+#ifdef ESRCH
+        X(ESRCH)
+#endif
+#ifdef ESTALE
+        X(ESTALE)
+#endif
+#ifdef ETIMEDOUT
+        X(ETIMEDOUT)
+#endif
+#ifdef ETXTBSY
+        X(ETXTBSY)
+#endif
+#ifdef EXDEV
+        X(EXDEV)
+#endif
+        default:
+#ifdef EOPNOTSUPP
+            if (error == EOPNOTSUPP)
+                code = __WASI_ENOTSUP;
+#endif
+#ifdef EWOULDBLOCK
+            if (error == EWOULDBLOCK)
+                code = __WASI_EAGAIN;
+#endif
+            break;
+    }
+#undef X
+    return code;
+}

+ 15 - 0
core/shared/platform/common/libc-util/libc_errno.h

@@ -0,0 +1,15 @@
+/*
+ * Copyright (C) 2023 Intel Corporation. All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#ifndef WASI_ERRNO_H
+#define WASI_ERRNO_H
+
+#include "platform_wasi_types.h"
+
+// Converts an errno error code to a WASI error code.
+__wasi_errno_t
+convert_errno(int error);
+
+#endif /* end of WASI_ERRNO_H */

+ 8 - 0
core/shared/platform/common/libc-util/platform_common_libc_util.cmake

@@ -0,0 +1,8 @@
+# Copyright (C) 2019 Intel Corporation.  All rights reserved.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ 
+set (PLATFORM_COMMON_LIBC_UTIL_DIR ${CMAKE_CURRENT_LIST_DIR})
+
+include_directories(${PLATFORM_COMMON_LIBC_UTIL_DIR})
+
+file (GLOB_RECURSE PLATFORM_COMMON_LIBC_UTIL_SOURCE ${PLATFORM_COMMON_LIBC_UTIL_DIR}/*.c)

+ 12 - 1
core/shared/platform/common/posix/platform_api_posix.cmake

@@ -1,8 +1,19 @@
 # Copyright (C) 2019 Intel Corporation.  All rights reserved.
 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- 
+
 set (PLATFORM_COMMON_POSIX_DIR ${CMAKE_CURRENT_LIST_DIR})
 
 file (GLOB_RECURSE source_all ${PLATFORM_COMMON_POSIX_DIR}/*.c)
 
+if (NOT WAMR_BUILD_LIBC_WASI EQUAL 1)
+    list(REMOVE_ITEM source_all
+        ${PLATFORM_COMMON_POSIX_DIR}/posix_file.c
+        ${PLATFORM_COMMON_POSIX_DIR}/posix_clock.c
+        ${PLATFORM_COMMON_POSIX_DIR}/posix_socket.c
+    )
+else()
+    include (${CMAKE_CURRENT_LIST_DIR}/../libc-util/platform_common_libc_util.cmake)
+    set(source_all ${source_all} ${PLATFORM_COMMON_LIBC_UTIL_SOURCE})
+endif()
+
 set (PLATFORM_COMMON_POSIX_SOURCE ${source_all} )

+ 86 - 0
core/shared/platform/common/posix/posix_clock.c

@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2023 Amazon Inc.  All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#include "libc_errno.h"
+#include "platform_api_extension.h"
+
+#define NANOSECONDS_PER_SECOND 1000000000ULL
+
+static __wasi_errno_t
+wasi_clockid_to_clockid(__wasi_clockid_t in, clockid_t *out)
+{
+    switch (in) {
+        case __WASI_CLOCK_MONOTONIC:
+            *out = CLOCK_MONOTONIC;
+            return __WASI_ESUCCESS;
+        case __WASI_CLOCK_REALTIME:
+            *out = CLOCK_REALTIME;
+            return __WASI_ESUCCESS;
+        case __WASI_CLOCK_PROCESS_CPUTIME_ID:
+#if defined(CLOCK_PROCESS_CPUTIME_ID)
+            *out = CLOCK_PROCESS_CPUTIME_ID;
+            return __WASI_ESUCCESS;
+#else
+            return __WASI_ENOTSUP;
+#endif
+        case __WASI_CLOCK_THREAD_CPUTIME_ID:
+#if defined(CLOCK_THREAD_CPUTIME_ID)
+            *out = CLOCK_THREAD_CPUTIME_ID;
+            return __WASI_ESUCCESS;
+#else
+            return __WASI_ENOTSUP;
+#endif
+        default:
+            return __WASI_EINVAL;
+    }
+}
+
+static __wasi_timestamp_t
+timespec_to_nanoseconds(const struct timespec *ts)
+{
+    if (ts->tv_sec < 0)
+        return 0;
+    if ((__wasi_timestamp_t)ts->tv_sec >= UINT64_MAX / NANOSECONDS_PER_SECOND)
+        return UINT64_MAX;
+    return (__wasi_timestamp_t)ts->tv_sec * NANOSECONDS_PER_SECOND
+           + (__wasi_timestamp_t)ts->tv_nsec;
+}
+
+__wasi_errno_t
+os_clock_res_get(__wasi_clockid_t clock_id, __wasi_timestamp_t *resolution)
+{
+    clockid_t nclock_id;
+    __wasi_errno_t error = wasi_clockid_to_clockid(clock_id, &nclock_id);
+
+    if (error != __WASI_ESUCCESS)
+        return error;
+
+    struct timespec ts;
+    if (clock_getres(nclock_id, &ts) < 0)
+        return convert_errno(errno);
+
+    *resolution = timespec_to_nanoseconds(&ts);
+
+    return error;
+}
+
+__wasi_errno_t
+os_clock_time_get(__wasi_clockid_t clock_id, __wasi_timestamp_t precision,
+                  __wasi_timestamp_t *time)
+{
+    clockid_t nclock_id;
+    __wasi_errno_t error = wasi_clockid_to_clockid(clock_id, &nclock_id);
+
+    if (error != __WASI_ESUCCESS)
+        return error;
+
+    struct timespec ts;
+    if (clock_gettime(nclock_id, &ts) < 0)
+        return convert_errno(errno);
+
+    *time = timespec_to_nanoseconds(&ts);
+
+    return error;
+}

+ 1007 - 0
core/shared/platform/common/posix/posix_file.c

@@ -0,0 +1,1007 @@
+/*
+ * Copyright (C) 2023 Intel Corporation. All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#include "platform_api_extension.h"
+#include "libc_errno.h"
+#include <unistd.h>
+
+#if !defined(__APPLE__) && !defined(ESP_PLATFORM)
+#define CONFIG_HAS_PWRITEV 1
+#define CONFIG_HAS_PREADV 1
+#else
+#define CONFIG_HAS_PWRITEV 0
+#define CONFIG_HAS_PREADV 0
+#endif
+
+#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(ESP_PLATFORM)
+#define CONFIG_HAS_FDATASYNC 1
+#else
+#define CONFIG_HAS_FDATASYNC 0
+#endif
+
+/*
+ * For NuttX, CONFIG_HAS_ISATTY is provided by its platform header.
+ * (platform_internal.h)
+ */
+#if !defined(__NuttX__)
+#define CONFIG_HAS_D_INO 1
+#define CONFIG_HAS_ISATTY 1
+#else
+#define CONFIG_HAS_D_INO 0
+#endif
+
+#if !defined(__APPLE__) && !defined(ESP_PLATFORM) && !defined(__COSMOPOLITAN__)
+#define CONFIG_HAS_POSIX_FALLOCATE 1
+#else
+#define CONFIG_HAS_POSIX_FALLOCATE 0
+#endif
+
+#if defined(O_DSYNC)
+#define CONFIG_HAS_O_DSYNC
+#endif
+
+// POSIX requires O_RSYNC to be defined, but Linux explicitly doesn't support
+// it.
+#if defined(O_RSYNC) && !defined(__linux__)
+#define CONFIG_HAS_O_RSYNC
+#endif
+
+#if defined(O_SYNC)
+#define CONFIG_HAS_O_SYNC
+#endif
+
+// Converts a POSIX timespec to a WASI timestamp.
+static __wasi_timestamp_t
+convert_timespec(const struct timespec *ts)
+{
+    if (ts->tv_sec < 0)
+        return 0;
+    if ((__wasi_timestamp_t)ts->tv_sec >= UINT64_MAX / 1000000000)
+        return UINT64_MAX;
+    return (__wasi_timestamp_t)ts->tv_sec * 1000000000
+           + (__wasi_timestamp_t)ts->tv_nsec;
+}
+
+// Converts a POSIX stat structure to a WASI filestat structure
+static void
+convert_stat(os_file_handle handle, const struct stat *in,
+             __wasi_filestat_t *out)
+{
+    out->st_dev = in->st_dev;
+    out->st_ino = in->st_ino;
+    out->st_nlink = (__wasi_linkcount_t)in->st_nlink;
+    out->st_size = (__wasi_filesize_t)in->st_size;
+#ifdef __APPLE__
+    out->st_atim = convert_timespec(&in->st_atimespec);
+    out->st_mtim = convert_timespec(&in->st_mtimespec);
+    out->st_ctim = convert_timespec(&in->st_ctimespec);
+#else
+    out->st_atim = convert_timespec(&in->st_atim);
+    out->st_mtim = convert_timespec(&in->st_mtim);
+    out->st_ctim = convert_timespec(&in->st_ctim);
+#endif
+
+    // Convert the file type. In the case of sockets there is no way we
+    // can easily determine the exact socket type.
+    if (S_ISBLK(in->st_mode)) {
+        out->st_filetype = __WASI_FILETYPE_BLOCK_DEVICE;
+    }
+    else if (S_ISCHR(in->st_mode)) {
+        out->st_filetype = __WASI_FILETYPE_CHARACTER_DEVICE;
+    }
+    else if (S_ISDIR(in->st_mode)) {
+        out->st_filetype = __WASI_FILETYPE_DIRECTORY;
+    }
+    else if (S_ISFIFO(in->st_mode)) {
+        out->st_filetype = __WASI_FILETYPE_SOCKET_STREAM;
+    }
+    else if (S_ISLNK(in->st_mode)) {
+        out->st_filetype = __WASI_FILETYPE_SYMBOLIC_LINK;
+    }
+    else if (S_ISREG(in->st_mode)) {
+        out->st_filetype = __WASI_FILETYPE_REGULAR_FILE;
+    }
+    else if (S_ISSOCK(in->st_mode)) {
+        int socktype;
+        socklen_t socktypelen = sizeof(socktype);
+
+        if (getsockopt(handle, SOL_SOCKET, SO_TYPE, &socktype, &socktypelen)
+            < 0) {
+            out->st_filetype = __WASI_FILETYPE_UNKNOWN;
+            return;
+        }
+
+        switch (socktype) {
+            case SOCK_DGRAM:
+                out->st_filetype = __WASI_FILETYPE_SOCKET_DGRAM;
+                break;
+            case SOCK_STREAM:
+                out->st_filetype = __WASI_FILETYPE_SOCKET_STREAM;
+                break;
+            default:
+                out->st_filetype = __WASI_FILETYPE_UNKNOWN;
+                return;
+        }
+    }
+    else {
+        out->st_filetype = __WASI_FILETYPE_UNKNOWN;
+    }
+}
+
+static void
+convert_timestamp(__wasi_timestamp_t in, struct timespec *out)
+{
+    // Store sub-second remainder.
+#if defined(__SYSCALL_SLONG_TYPE)
+    out->tv_nsec = (__SYSCALL_SLONG_TYPE)(in % 1000000000);
+#else
+    out->tv_nsec = (long)(in % 1000000000);
+#endif
+    in /= 1000000000;
+
+    // Clamp to the maximum in case it would overflow our system's time_t.
+    out->tv_sec = (time_t)in < BH_TIME_T_MAX ? (time_t)in : BH_TIME_T_MAX;
+}
+
+// Converts the provided timestamps and flags to a set of arguments for
+// futimens() and utimensat().
+static void
+convert_utimens_arguments(__wasi_timestamp_t st_atim,
+                          __wasi_timestamp_t st_mtim,
+                          __wasi_fstflags_t fstflags, struct timespec *ts)
+{
+    if ((fstflags & __WASI_FILESTAT_SET_ATIM_NOW) != 0) {
+        ts[0].tv_nsec = UTIME_NOW;
+    }
+    else if ((fstflags & __WASI_FILESTAT_SET_ATIM) != 0) {
+        convert_timestamp(st_atim, &ts[0]);
+    }
+    else {
+        ts[0].tv_nsec = UTIME_OMIT;
+    }
+
+    if ((fstflags & __WASI_FILESTAT_SET_MTIM_NOW) != 0) {
+        ts[1].tv_nsec = UTIME_NOW;
+    }
+    else if ((fstflags & __WASI_FILESTAT_SET_MTIM) != 0) {
+        convert_timestamp(st_mtim, &ts[1]);
+    }
+    else {
+        ts[1].tv_nsec = UTIME_OMIT;
+    }
+}
+
+__wasi_errno_t
+os_fstat(os_file_handle handle, struct __wasi_filestat_t *buf)
+{
+    struct stat stat_buf;
+    int ret = fstat(handle, &stat_buf);
+
+    if (ret < 0)
+        return convert_errno(errno);
+
+    convert_stat(handle, &stat_buf, buf);
+
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+os_fstatat(os_file_handle handle, const char *path,
+           struct __wasi_filestat_t *buf, __wasi_lookupflags_t lookup_flags)
+{
+    struct stat stat_buf;
+    int ret = fstatat(handle, path, &stat_buf,
+                      (lookup_flags & __WASI_LOOKUP_SYMLINK_FOLLOW)
+                          ? AT_SYMLINK_FOLLOW
+                          : AT_SYMLINK_NOFOLLOW);
+
+    if (ret < 0)
+        return convert_errno(errno);
+
+    convert_stat(handle, &stat_buf, buf);
+
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+os_file_get_fdflags(os_file_handle handle, __wasi_fdflags_t *flags)
+{
+    int ret = fcntl(handle, F_GETFL);
+
+    if (ret < 0)
+        return convert_errno(errno);
+
+    *flags = 0;
+
+    if ((ret & O_APPEND) != 0)
+        *flags |= __WASI_FDFLAG_APPEND;
+#ifdef CONFIG_HAS_O_DSYNC
+    if ((ret & O_DSYNC) != 0)
+        *flags |= __WASI_FDFLAG_DSYNC;
+#endif
+    if ((ret & O_NONBLOCK) != 0)
+        *flags |= __WASI_FDFLAG_NONBLOCK;
+#ifdef CONFIG_HAS_O_RSYNC
+    if ((ret & O_RSYNC) != 0)
+        *flags |= __WASI_FDFLAG_RSYNC;
+#endif
+#ifdef CONFIG_HAS_O_SYNC
+    if ((ret & O_SYNC) != 0)
+        *flags |= __WASI_FDFLAG_SYNC;
+#endif
+
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+os_file_set_fdflags(os_file_handle handle, __wasi_fdflags_t flags)
+{
+    int fcntl_flags = 0;
+
+    if ((flags & __WASI_FDFLAG_APPEND) != 0)
+        fcntl_flags |= O_APPEND;
+    if ((flags & __WASI_FDFLAG_DSYNC) != 0)
+#ifdef CONFIG_HAS_O_DSYNC
+        fcntl_flags |= O_DSYNC;
+#else
+        return __WASI_ENOTSUP;
+#endif
+    if ((flags & __WASI_FDFLAG_NONBLOCK) != 0)
+        fcntl_flags |= O_NONBLOCK;
+    if ((flags & __WASI_FDFLAG_RSYNC) != 0)
+#ifdef CONFIG_HAS_O_RSYNC
+        fcntl_flags |= O_RSYNC;
+#else
+        return __WASI_ENOTSUP;
+#endif
+    if ((flags & __WASI_FDFLAG_SYNC) != 0)
+#ifdef CONFIG_HAS_O_SYNC
+        fcntl_flags |= O_SYNC;
+#else
+        return __WASI_ENOTSUP;
+#endif
+
+    int ret = fcntl(handle, F_SETFL, fcntl_flags);
+
+    if (ret < 0)
+        return convert_errno(errno);
+
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+os_fdatasync(os_file_handle handle)
+{
+#if CONFIG_HAS_FDATASYNC
+    int ret = fdatasync(handle);
+#else
+    int ret = fsync(handle);
+#endif
+
+    if (ret < 0)
+        return convert_errno(errno);
+
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+os_fsync(os_file_handle handle)
+{
+    int ret = fsync(handle);
+
+    if (ret < 0)
+        return convert_errno(errno);
+
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+os_open_preopendir(const char *path, os_file_handle *out)
+{
+
+    int fd = open(path, O_RDONLY | O_DIRECTORY, 0);
+
+    if (fd < 0)
+        return convert_errno(errno);
+
+    *out = fd;
+
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+os_openat(os_file_handle handle, const char *path, __wasi_oflags_t oflags,
+          __wasi_fdflags_t fs_flags, __wasi_lookupflags_t lookup_flags,
+          wasi_libc_file_access_mode read_write_mode, os_file_handle *out)
+{
+    int open_flags = 0;
+
+    // Convert open flags.
+    if ((oflags & __WASI_O_CREAT) != 0) {
+        open_flags |= O_CREAT;
+    }
+    if ((oflags & __WASI_O_DIRECTORY) != 0)
+        open_flags |= O_DIRECTORY;
+    if ((oflags & __WASI_O_EXCL) != 0)
+        open_flags |= O_EXCL;
+    if ((oflags & __WASI_O_TRUNC) != 0) {
+        open_flags |= O_TRUNC;
+    }
+
+    // Convert file descriptor flags.
+    if ((fs_flags & __WASI_FDFLAG_APPEND) != 0)
+        open_flags |= O_APPEND;
+    if ((fs_flags & __WASI_FDFLAG_DSYNC) != 0) {
+#ifdef CONFIG_HAS_O_DSYNC
+        open_flags |= O_DSYNC;
+#else
+        return __WASI_ENOTSUP;
+#endif
+    }
+    if ((fs_flags & __WASI_FDFLAG_NONBLOCK) != 0)
+        open_flags |= O_NONBLOCK;
+    if ((fs_flags & __WASI_FDFLAG_RSYNC) != 0) {
+#ifdef CONFIG_HAS_O_RSYNC
+        open_flags |= O_RSYNC;
+#else
+        return __WASI_ENOTSUP;
+#endif
+    }
+    if ((fs_flags & __WASI_FDFLAG_SYNC) != 0) {
+#ifdef CONFIG_HAS_O_SYNC
+        open_flags |= O_SYNC;
+#else
+        return __WASI_ENOTSUP;
+#endif
+    }
+
+    if ((lookup_flags & __WASI_LOOKUP_SYMLINK_FOLLOW) == 0) {
+        open_flags |= O_NOFOLLOW;
+    }
+
+    switch (read_write_mode) {
+        case WASI_LIBC_ACCESS_MODE_READ_WRITE:
+            open_flags |= O_RDWR;
+            break;
+        case WASI_LIBC_ACCESS_MODE_READ_ONLY:
+            open_flags |= O_RDONLY;
+            break;
+        case WASI_LIBC_ACCESS_MODE_WRITE_ONLY:
+            open_flags |= O_WRONLY;
+            break;
+        default:
+            return __WASI_EINVAL;
+    }
+
+    int fd = openat(handle, path, open_flags, 0666);
+
+    if (fd < 0) {
+        int openat_errno = errno;
+        // Linux returns ENXIO instead of EOPNOTSUPP when opening a socket.
+        if (openat_errno == ENXIO) {
+            struct stat sb;
+            int ret = fstatat(fd, path, &sb,
+                              (lookup_flags & __WASI_LOOKUP_SYMLINK_FOLLOW)
+                                  ? 0
+                                  : AT_SYMLINK_NOFOLLOW);
+            return ret == 0 && S_ISSOCK(sb.st_mode) ? __WASI_ENOTSUP
+                                                    : __WASI_ENXIO;
+        }
+        // Linux returns ENOTDIR instead of ELOOP when using
+        // O_NOFOLLOW|O_DIRECTORY on a symlink.
+        if (openat_errno == ENOTDIR
+            && (open_flags & (O_NOFOLLOW | O_DIRECTORY)) != 0) {
+            struct stat sb;
+            int ret = fstatat(fd, path, &sb, AT_SYMLINK_NOFOLLOW);
+            if (S_ISLNK(sb.st_mode)) {
+                return __WASI_ELOOP;
+            }
+            (void)ret;
+        }
+        // FreeBSD returns EMLINK instead of ELOOP when using O_NOFOLLOW on
+        // a symlink.
+        if ((lookup_flags & __WASI_LOOKUP_SYMLINK_FOLLOW) == 0
+            && openat_errno == EMLINK)
+            return __WASI_ELOOP;
+
+        return convert_errno(openat_errno);
+    }
+
+    *out = fd;
+
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+os_file_get_access_mode(os_file_handle handle,
+                        wasi_libc_file_access_mode *access_mode)
+{
+    int ret = fcntl(handle, F_GETFL, 0);
+
+    if (ret < 0)
+        return convert_errno(errno);
+
+    switch (ret & O_ACCMODE) {
+        case O_RDONLY:
+            *access_mode = WASI_LIBC_ACCESS_MODE_READ_ONLY;
+            break;
+        case O_WRONLY:
+            *access_mode = WASI_LIBC_ACCESS_MODE_WRITE_ONLY;
+            break;
+        case O_RDWR:
+            *access_mode = WASI_LIBC_ACCESS_MODE_READ_WRITE;
+            break;
+        default:
+            return __WASI_EINVAL;
+    }
+
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+os_close(os_file_handle handle, bool is_stdio)
+{
+    if (is_stdio)
+        return __WASI_ESUCCESS;
+
+    int ret = close(handle);
+
+    if (ret < 0)
+        return convert_errno(errno);
+
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+os_preadv(os_file_handle handle, const struct __wasi_iovec_t *iov, int iovcnt,
+          __wasi_filesize_t offset, size_t *nread)
+{
+#if CONFIG_HAS_PREADV
+    ssize_t len =
+        preadv(handle, (const struct iovec *)iov, (int)iovcnt, (off_t)offset);
+    if (len < 0)
+        return convert_errno(errno);
+
+    *nread = (size_t)len;
+    return __WASI_ESUCCESS;
+#else
+    if (iovcnt == 1) {
+        ssize_t len = pread(handle, iov->buf, iov->buf_len, offset);
+
+        if (len < 0)
+            return convert_errno(errno);
+
+        *nread = len;
+        return __WASI_ESUCCESS;
+    }
+
+    // Allocate a single buffer to fit all data.
+    size_t totalsize = 0;
+    for (size_t i = 0; i < iovcnt; ++i)
+        totalsize += iov[i].buf_len;
+
+    char *buf = BH_MALLOC(totalsize);
+
+    if (buf == NULL) {
+        return __WASI_ENOMEM;
+    }
+
+    // Perform a single read operation.
+    ssize_t len = pread(handle, buf, totalsize, offset);
+
+    if (len < 0) {
+        BH_FREE(buf);
+        return convert_errno(errno);
+    }
+
+    // Copy data back to vectors.
+    size_t bufoff = 0;
+    for (size_t i = 0; i < iovcnt; ++i) {
+        if (bufoff + iov[i].buf_len < (size_t)len) {
+            memcpy(iov[i].buf, buf + bufoff, iov[i].buf_len);
+            bufoff += iov[i].buf_len;
+        }
+        else {
+            memcpy(iov[i].buf, buf + bufoff, len - bufoff);
+            break;
+        }
+    }
+    BH_FREE(buf);
+    *nread = len;
+
+    return __WASI_ESUCCESS;
+#endif
+}
+
+__wasi_errno_t
+os_pwritev(os_file_handle handle, const struct __wasi_ciovec_t *iov, int iovcnt,
+           __wasi_filesize_t offset, size_t *nwritten)
+{
+    if (iovcnt == 0)
+        return __WASI_EINVAL;
+
+    ssize_t len = 0;
+#if CONFIG_HAS_PWRITEV
+    len =
+        pwritev(handle, (const struct iovec *)iov, (int)iovcnt, (off_t)offset);
+#else
+    if (iovcnt == 1) {
+        len = pwrite(handle, iov->buf, iov->buf_len, offset);
+    }
+    else {
+        // Allocate a single buffer to fit all data.
+        size_t totalsize = 0;
+        for (size_t i = 0; i < iovcnt; ++i)
+            totalsize += iov[i].buf_len;
+        char *buf = BH_MALLOC(totalsize);
+        if (buf == NULL) {
+            return __WASI_ENOMEM;
+        }
+        size_t bufoff = 0;
+        for (size_t i = 0; i < iovcnt; ++i) {
+            memcpy(buf + bufoff, iov[i].buf, iov[i].buf_len);
+            bufoff += iov[i].buf_len;
+        }
+
+        // Perform a single write operation.
+        len = pwrite(handle, buf, totalsize, offset);
+        BH_FREE(buf);
+    }
+#endif
+    if (len < 0)
+        return convert_errno(errno);
+
+    *nwritten = (size_t)len;
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+os_readv(os_file_handle handle, const struct __wasi_iovec_t *iov, int iovcnt,
+         size_t *nread)
+{
+    ssize_t len = readv(handle, (const struct iovec *)iov, (int)iovcnt);
+
+    if (len < 0)
+        return convert_errno(errno);
+
+    *nread = (size_t)len;
+
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+os_writev(os_file_handle handle, const struct __wasi_ciovec_t *iov, int iovcnt,
+          size_t *nwritten)
+{
+    ssize_t len = writev(handle, (const struct iovec *)iov, (int)iovcnt);
+
+    if (len < 0)
+        return convert_errno(errno);
+
+    *nwritten = (size_t)len;
+
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+os_fallocate(os_file_handle handle, __wasi_filesize_t offset,
+             __wasi_filesize_t length)
+{
+#if CONFIG_HAS_POSIX_FALLOCATE
+    int ret = posix_fallocate(handle, (off_t)offset, (off_t)length);
+#else
+    // At least ensure that the file is grown to the right size.
+    // TODO(ed): See if this can somehow be implemented without any race
+    // conditions. We may end up shrinking the file right now.
+    struct stat sb;
+    int ret = fstat(handle, &sb);
+    off_t newsize = (off_t)(offset + length);
+
+    if (ret == 0 && sb.st_size < newsize)
+        ret = ftruncate(handle, newsize);
+#endif
+
+    if (ret != 0)
+        return convert_errno(ret);
+
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+os_ftruncate(os_file_handle handle, __wasi_filesize_t size)
+{
+    int ret = ftruncate(handle, (off_t)size);
+
+    if (ret < 0)
+        return convert_errno(errno);
+
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+os_futimens(os_file_handle handle, __wasi_timestamp_t access_time,
+            __wasi_timestamp_t modification_time, __wasi_fstflags_t fstflags)
+{
+    struct timespec ts[2];
+    convert_utimens_arguments(access_time, modification_time, fstflags, ts);
+
+    int ret = futimens(handle, ts);
+
+    if (ret < 0)
+        return convert_errno(errno);
+
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+os_utimensat(os_file_handle handle, const char *path,
+             __wasi_timestamp_t access_time,
+             __wasi_timestamp_t modification_time, __wasi_fstflags_t fstflags,
+             __wasi_lookupflags_t lookup_flags)
+{
+    struct timespec ts[2];
+    convert_utimens_arguments(access_time, modification_time, fstflags, ts);
+
+    int ret = utimensat(handle, path, ts,
+                        (lookup_flags & __WASI_LOOKUP_SYMLINK_FOLLOW)
+                            ? 0
+                            : AT_SYMLINK_NOFOLLOW);
+
+    if (ret < 0)
+        return convert_errno(errno);
+
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+os_readlinkat(os_file_handle handle, const char *path, char *buf,
+              size_t bufsize, size_t *nread)
+{
+    // Linux requires that the buffer size is positive. whereas POSIX does
+    // not. Use a fake buffer to store the results if the size is zero.
+    char fakebuf[1];
+    ssize_t len = readlinkat(handle, path, bufsize == 0 ? fakebuf : buf,
+                             bufsize == 0 ? sizeof(fakebuf) : bufsize);
+
+    if (len < 0)
+        return convert_errno(errno);
+
+    *nread = (size_t)len < bufsize ? (size_t)len : bufsize;
+
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+os_linkat(os_file_handle from_handle, const char *from_path,
+          os_file_handle to_handle, const char *to_path,
+          __wasi_lookupflags_t lookup_flags)
+{
+    int ret = linkat(
+        from_handle, from_path, to_handle, to_path,
+        (lookup_flags & __WASI_LOOKUP_SYMLINK_FOLLOW) ? AT_SYMLINK_FOLLOW : 0);
+
+    if (ret < 0)
+        return convert_errno(errno);
+
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+os_symlinkat(const char *old_path, os_file_handle handle, const char *new_path)
+{
+    int ret = symlinkat(old_path, handle, new_path);
+
+    if (ret < 0)
+        return convert_errno(errno);
+
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+os_mkdirat(os_file_handle handle, const char *path)
+{
+    int ret = mkdirat(handle, path, 0777);
+
+    if (ret < 0)
+        return convert_errno(errno);
+
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+os_renameat(os_file_handle old_handle, const char *old_path,
+            os_file_handle new_handle, const char *new_path)
+{
+
+    int ret = renameat(old_handle, old_path, new_handle, new_path);
+
+    if (ret < 0)
+        return convert_errno(errno);
+
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+os_unlinkat(os_file_handle handle, const char *path, bool is_dir)
+{
+    int ret = unlinkat(handle, path, is_dir ? AT_REMOVEDIR : 0);
+
+#ifndef __linux__
+    if (ret < 0) {
+        // Non-Linux implementations may return EPERM when attempting to remove
+        // a directory without REMOVEDIR. While that's what POSIX specifies,
+        // it's less useful. Adjust this to EISDIR. It doesn't matter that this
+        // is not atomic with the unlinkat, because if the file is removed and a
+        // directory is created before fstatat sees it, we're racing with that
+        // change anyway and unlinkat could have legitimately seen the directory
+        // if the race had turned out differently.
+        if (errno == EPERM) {
+            struct stat statbuf;
+            if (fstatat(handle, path, &statbuf, AT_SYMLINK_NOFOLLOW) == 0
+                && S_ISDIR(statbuf.st_mode)) {
+                errno = EISDIR;
+            }
+        }
+        // POSIX permits either EEXIST or ENOTEMPTY when the directory is not
+        // empty. Map it to ENOTEMPTY.
+        else if (errno == EEXIST) {
+            errno = ENOTEMPTY;
+        }
+
+        return convert_errno(errno);
+    }
+#endif
+
+    if (ret < 0)
+        return convert_errno(errno);
+
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+os_lseek(os_file_handle handle, __wasi_filedelta_t offset,
+         __wasi_whence_t whence, __wasi_filesize_t *new_offset)
+{
+    int nwhence;
+
+    switch (whence) {
+        case __WASI_WHENCE_CUR:
+            nwhence = SEEK_CUR;
+            break;
+        case __WASI_WHENCE_END:
+            nwhence = SEEK_END;
+            break;
+        case __WASI_WHENCE_SET:
+            nwhence = SEEK_SET;
+            break;
+        default:
+            return __WASI_EINVAL;
+    }
+
+    off_t ret = lseek(handle, offset, nwhence);
+
+    if (ret < 0)
+        return convert_errno(errno);
+
+    *new_offset = (__wasi_filesize_t)ret;
+
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+os_fadvise(os_file_handle handle, __wasi_filesize_t offset,
+           __wasi_filesize_t length, __wasi_advice_t advice)
+{
+#ifdef POSIX_FADV_NORMAL
+    int nadvice;
+    switch (advice) {
+        case __WASI_ADVICE_DONTNEED:
+            nadvice = POSIX_FADV_DONTNEED;
+            break;
+        case __WASI_ADVICE_NOREUSE:
+            nadvice = POSIX_FADV_NOREUSE;
+            break;
+        case __WASI_ADVICE_NORMAL:
+            nadvice = POSIX_FADV_NORMAL;
+            break;
+        case __WASI_ADVICE_RANDOM:
+            nadvice = POSIX_FADV_RANDOM;
+            break;
+        case __WASI_ADVICE_SEQUENTIAL:
+            nadvice = POSIX_FADV_SEQUENTIAL;
+            break;
+        case __WASI_ADVICE_WILLNEED:
+            nadvice = POSIX_FADV_WILLNEED;
+            break;
+        default:
+            return __WASI_EINVAL;
+    }
+
+    int ret = posix_fadvise(handle, (off_t)offset, (off_t)length, nadvice);
+
+    if (ret < 0)
+        return convert_errno(ret);
+
+    return __WASI_ESUCCESS;
+#else
+    // Advisory information can be safely ignored if not supported
+    switch (advice) {
+        case __WASI_ADVICE_DONTNEED:
+        case __WASI_ADVICE_NOREUSE:
+        case __WASI_ADVICE_NORMAL:
+        case __WASI_ADVICE_RANDOM:
+        case __WASI_ADVICE_SEQUENTIAL:
+        case __WASI_ADVICE_WILLNEED:
+            return __WASI_ESUCCESS;
+        default:
+            return __WASI_EINVAL;
+    }
+#endif
+}
+
+__wasi_errno_t
+os_isatty(os_file_handle handle)
+{
+#if CONFIG_HAS_ISATTY
+    int ret = isatty(handle);
+
+    if (ret == 1)
+        return __WASI_ESUCCESS;
+
+    return __WASI_ENOTTY;
+#else
+    return __WASI_ENOTSUP;
+#endif
+}
+
+os_file_handle
+os_convert_stdin_handle(os_raw_file_handle raw_stdin)
+{
+#ifndef STDIN_FILENO
+#define STDIN_FILENO 0
+#endif
+    return raw_stdin >= 0 ? raw_stdin : STDIN_FILENO;
+}
+
+os_file_handle
+os_convert_stdout_handle(os_raw_file_handle raw_stdout)
+{
+#ifndef STDOUT_FILENO
+#define STDOUT_FILENO 1
+#endif
+    return raw_stdout >= 0 ? raw_stdout : STDOUT_FILENO;
+}
+
+os_file_handle
+os_convert_stderr_handle(os_raw_file_handle raw_stderr)
+{
+#ifndef STDERR_FILENO
+#define STDERR_FILENO 2
+#endif
+    return raw_stderr >= 0 ? raw_stderr : STDERR_FILENO;
+}
+
+__wasi_errno_t
+os_fdopendir(os_file_handle handle, os_dir_stream *dir_stream)
+{
+    *dir_stream = fdopendir(handle);
+
+    if (*dir_stream == NULL)
+        return convert_errno(errno);
+
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+os_rewinddir(os_dir_stream dir_stream)
+{
+    rewinddir(dir_stream);
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+os_seekdir(os_dir_stream dir_stream, __wasi_dircookie_t position)
+{
+    seekdir(dir_stream, (long)position);
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+os_readdir(os_dir_stream dir_stream, __wasi_dirent_t *entry,
+           const char **d_name)
+{
+    errno = 0;
+
+    struct dirent *dent = readdir(dir_stream);
+
+    if (dent == NULL) {
+        *d_name = NULL;
+        return convert_errno(errno);
+    }
+
+    long offset = (__wasi_dircookie_t)telldir(dir_stream);
+
+    size_t namlen = strlen(dent->d_name);
+
+    *d_name = dent->d_name;
+    entry->d_next = offset;
+    entry->d_namlen = (__wasi_dirnamlen_t)namlen;
+#if CONFIG_HAS_D_INO
+    entry->d_ino = dent->d_ino;
+#else
+    entry->d_ino = 0;
+#endif
+
+    switch (dent->d_type) {
+        case DT_BLK:
+            entry->d_type = __WASI_FILETYPE_BLOCK_DEVICE;
+            break;
+        case DT_CHR:
+            entry->d_type = __WASI_FILETYPE_CHARACTER_DEVICE;
+            break;
+        case DT_DIR:
+            entry->d_type = __WASI_FILETYPE_DIRECTORY;
+            break;
+        case DT_FIFO:
+            entry->d_type = __WASI_FILETYPE_SOCKET_STREAM;
+            break;
+        case DT_LNK:
+            entry->d_type = __WASI_FILETYPE_SYMBOLIC_LINK;
+            break;
+        case DT_REG:
+            entry->d_type = __WASI_FILETYPE_REGULAR_FILE;
+            break;
+#ifdef DT_SOCK
+        case DT_SOCK:
+            // Technically not correct, but good enough.
+            entry->d_type = __WASI_FILETYPE_SOCKET_STREAM;
+            break;
+#endif
+        default:
+            entry->d_type = __WASI_FILETYPE_UNKNOWN;
+            break;
+    }
+
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+os_closedir(os_dir_stream dir_stream)
+{
+    int ret = closedir(dir_stream);
+
+    if (ret < 0)
+        return convert_errno(errno);
+
+    return __WASI_ESUCCESS;
+}
+
+os_dir_stream
+os_get_invalid_dir_stream()
+{
+    return NULL;
+}
+
+bool
+os_is_dir_stream_valid(os_dir_stream *dir_stream)
+{
+    assert(dir_stream != NULL);
+
+    return *dir_stream != NULL;
+}
+
+bool
+os_is_handle_valid(os_file_handle *handle)
+{
+    assert(handle != NULL);
+
+    return *handle > -1;
+}
+
+char *
+os_realpath(const char *path, char *resolved_path)
+{
+    return realpath(path, resolved_path);
+}

+ 4 - 4
core/shared/platform/common/posix/posix_memmap.c

@@ -37,7 +37,7 @@ round_down(uintptr_t v, uintptr_t b)
 #endif
 
 void *
-os_mmap(void *hint, size_t size, int prot, int flags)
+os_mmap(void *hint, size_t size, int prot, int flags, os_file_handle file)
 {
     int map_prot = PROT_NONE;
 #if (defined(__APPLE__) || defined(__MACH__)) && defined(__arm64__)
@@ -114,7 +114,7 @@ os_mmap(void *hint, size_t size, int prot, int flags)
         /* try 10 times, step with 1MB each time */
         for (i = 0; i < 10 && hint_addr < (uint8 *)(uintptr_t)(2ULL * BH_GB);
              i++) {
-            addr = mmap(hint_addr, request_size, map_prot, map_flags, -1, 0);
+            addr = mmap(hint_addr, request_size, map_prot, map_flags, file, 0);
             if (addr != MAP_FAILED) {
                 if (addr > (uint8 *)(uintptr_t)(2ULL * BH_GB)) {
                     /* unmap and try again if the mapped address doesn't
@@ -136,7 +136,7 @@ os_mmap(void *hint, size_t size, int prot, int flags)
     if (addr == MAP_FAILED) {
         /* try 5 times */
         for (i = 0; i < 5; i++) {
-            addr = mmap(hint, request_size, map_prot, map_flags, -1, 0);
+            addr = mmap(hint, request_size, map_prot, map_flags, file, 0);
             if (addr != MAP_FAILED)
                 break;
         }
@@ -266,4 +266,4 @@ os_icache_flush(void *start, size_t len)
 #if (defined(__APPLE__) || defined(__MACH__)) && defined(__arm64__)
     sys_icache_invalidate(start, len);
 #endif
-}
+}

+ 6 - 3
core/shared/platform/common/posix/posix_socket.c

@@ -5,6 +5,7 @@
 
 #include "platform_api_vmcore.h"
 #include "platform_api_extension.h"
+#include "libc_errno.h"
 
 #include <arpa/inet.h>
 #include <netdb.h>
@@ -308,11 +309,13 @@ os_socket_close(bh_socket_t socket)
     return BHT_OK;
 }
 
-int
+__wasi_errno_t
 os_socket_shutdown(bh_socket_t socket)
 {
-    shutdown(socket, O_RDWR);
-    return BHT_OK;
+    if (shutdown(socket, O_RDWR) != 0) {
+        return convert_errno(errno);
+    }
+    return __WASI_ESUCCESS;
 }
 
 int

+ 56 - 1
core/shared/platform/common/posix/posix_thread.c

@@ -329,6 +329,61 @@ os_cond_broadcast(korp_cond *cond)
     return BHT_OK;
 }
 
+int
+os_rwlock_init(korp_rwlock *lock)
+{
+    assert(lock);
+
+    if (pthread_rwlock_init(lock, NULL) != BHT_OK)
+        return BHT_ERROR;
+
+    return BHT_OK;
+}
+
+int
+os_rwlock_rdlock(korp_rwlock *lock)
+{
+    assert(lock);
+
+    if (pthread_rwlock_rdlock(lock) != BHT_OK)
+        return BHT_ERROR;
+
+    return BHT_OK;
+}
+
+int
+os_rwlock_wrlock(korp_rwlock *lock)
+{
+    assert(lock);
+
+    if (pthread_rwlock_wrlock(lock) != BHT_OK)
+        return BHT_ERROR;
+
+    return BHT_OK;
+}
+
+int
+os_rwlock_unlock(korp_rwlock *lock)
+{
+    assert(lock);
+
+    if (pthread_rwlock_unlock(lock) != BHT_OK)
+        return BHT_ERROR;
+
+    return BHT_OK;
+}
+
+int
+os_rwlock_destroy(korp_rwlock *lock)
+{
+    assert(lock);
+
+    if (pthread_rwlock_destroy(lock) != BHT_OK)
+        return BHT_ERROR;
+
+    return BHT_OK;
+}
+
 int
 os_thread_join(korp_tid thread, void **value_ptr)
 {
@@ -609,7 +664,7 @@ os_thread_signal_init(os_signal_handler handler)
 
     /* Initialize memory for signal alternate stack of current thread */
     if (!(map_addr = os_mmap(NULL, map_size, MMAP_PROT_READ | MMAP_PROT_WRITE,
-                             MMAP_MAP_NONE))) {
+                             MMAP_MAP_NONE, os_get_invalid_handle()))) {
         os_printf("Failed to mmap memory for alternate stack\n");
         goto fail1;
     }

+ 4 - 0
core/shared/platform/cosmopolitan/platform_internal.h

@@ -63,6 +63,10 @@ typedef sem_t korp_sem;
 
 #define bh_socket_t int
 
+typedef int os_file_handle;
+typedef DIR *os_dir_stream;
+typedef int os_raw_file_handle;
+
 #if WASM_DISABLE_WRITE_GS_BASE == 0
 #if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64)
 #define os_writegsbase(base_addr)                                 \

+ 11 - 0
core/shared/platform/darwin/platform_internal.h

@@ -58,6 +58,7 @@ typedef pthread_t korp_tid;
 typedef pthread_mutex_t korp_mutex;
 typedef pthread_cond_t korp_cond;
 typedef pthread_t korp_thread;
+typedef pthread_rwlock_t korp_rwlock;
 typedef sem_t korp_sem;
 
 #define OS_THREAD_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
@@ -108,6 +109,16 @@ os_sigreturn();
 void
 os_set_signal_number_for_blocking_op(int signo);
 
+typedef int os_file_handle;
+typedef DIR *os_dir_stream;
+typedef int os_raw_file_handle;
+
+static inline os_file_handle
+os_get_invalid_handle()
+{
+    return -1;
+}
+
 #ifdef __cplusplus
 }
 #endif

+ 1 - 1
core/shared/platform/esp-idf/espidf_memmap.c

@@ -19,7 +19,7 @@ static portMUX_TYPE s_spinlock = portMUX_INITIALIZER_UNLOCKED;
 #endif
 
 void *
-os_mmap(void *hint, size_t size, int prot, int flags)
+os_mmap(void *hint, size_t size, int prot, int flags, os_file_handle file)
 {
     if (prot & MMAP_PROT_EXEC) {
 #if (WASM_MEM_DUAL_BUS_MIRROR != 0)

+ 6 - 3
core/shared/platform/esp-idf/espidf_socket.c

@@ -5,6 +5,7 @@
 
 #include "platform_api_vmcore.h"
 #include "platform_api_extension.h"
+#include "libc_errno.h"
 
 #include <arpa/inet.h>
 
@@ -167,11 +168,13 @@ os_socket_close(bh_socket_t socket)
     return BHT_OK;
 }
 
-int
+__wasi_errno_t
 os_socket_shutdown(bh_socket_t socket)
 {
-    shutdown(socket, O_RDWR);
-    return BHT_OK;
+    if (shutdown(socket, O_RDWR) != 0) {
+        return convert_errno(errno);
+    }
+    return __WASI_ESUCCESS;
 }
 
 int

+ 11 - 0
core/shared/platform/esp-idf/platform_internal.h

@@ -39,6 +39,7 @@ typedef pthread_t korp_tid;
 typedef pthread_mutex_t korp_mutex;
 typedef pthread_cond_t korp_cond;
 typedef pthread_t korp_thread;
+typedef pthread_rwlock_t korp_rwlock;
 typedef unsigned int korp_sem;
 
 #define OS_THREAD_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
@@ -108,6 +109,16 @@ typedef unsigned int korp_sem;
 #define DT_LNK DTYPE_LINK
 #define DT_SOCK DTYPE_SOCK
 
+typedef int os_file_handle;
+typedef DIR *os_dir_stream;
+typedef int os_raw_file_handle;
+
+static inline os_file_handle
+os_get_invalid_handle()
+{
+    return -1;
+}
+
 #ifdef __cplusplus
 }
 #endif

+ 13 - 0
core/shared/platform/freebsd/platform_internal.h

@@ -57,6 +57,7 @@ typedef pthread_t korp_tid;
 typedef pthread_mutex_t korp_mutex;
 typedef pthread_cond_t korp_cond;
 typedef pthread_t korp_thread;
+typedef pthread_rwlock_t korp_rwlock;
 typedef sem_t korp_sem;
 
 #define OS_THREAD_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
@@ -65,6 +66,10 @@ typedef sem_t korp_sem;
 
 #define bh_socket_t int
 
+typedef int os_file_handle;
+typedef DIR *os_dir_stream;
+typedef int os_raw_file_handle;
+
 #if WASM_DISABLE_HW_BOUND_CHECK == 0
 #if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64)            \
     || defined(BUILD_TARGET_AARCH64) || defined(BUILD_TARGET_RISCV64_LP64D) \
@@ -107,6 +112,14 @@ os_sigreturn();
 void
 os_set_signal_number_for_blocking_op(int signo);
 
+typedef int os_file_handle;
+
+static inline os_file_handle
+os_get_invalid_handle()
+{
+    return -1;
+}
+
 #ifdef __cplusplus
 }
 #endif

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

@@ -7,6 +7,7 @@
 #define PLATFORM_API_EXTENSION_H
 
 #include "platform_common.h"
+#include "platform_wasi_types.h"
 /**
  * The related data structures should be defined
  * in platform_internal.h
@@ -238,6 +239,56 @@ os_cond_signal(korp_cond *cond);
 int
 os_cond_broadcast(korp_cond *cond);
 
+/**
+ * Initialize readwrite lock object
+ *
+ * @param cond [OUTPUT] pointer to a lock object variable
+ *
+ * @return 0 if success
+ */
+int
+os_rwlock_init(korp_rwlock *lock);
+
+/**
+ * Acquire the read lock
+ *
+ * @param lock lock variable
+ *
+ * @return 0 if success
+ */
+int
+os_rwlock_rdlock(korp_rwlock *lock);
+
+/**
+ * Acquire the write lock
+ *
+ * @param lock lock variable
+ *
+ * @return 0 if success
+ */
+int
+os_rwlock_wrlock(korp_rwlock *lock);
+
+/**
+ * Unlocks the lock object
+ *
+ * @param lock lock variable
+ *
+ * @return 0 if success
+ */
+int
+os_rwlock_unlock(korp_rwlock *lock);
+
+/**
+ * Destroy a lock object
+ *
+ * @param lock lock variable
+ *
+ * @return 0 if success
+ */
+int
+os_rwlock_destroy(korp_rwlock *lock);
+
 /**
  * Creates a new POSIX-like semaphore or opens an existing
  * semaphore.  The semaphore is identified by name.  For details of
@@ -522,9 +573,9 @@ os_socket_close(bh_socket_t socket);
  *
  * @param socket the socket to be shutdown
  *
- * @return always return 0
+ * @return returns corresponding error code
  */
-int
+__wasi_errno_t
 os_socket_shutdown(bh_socket_t socket);
 
 /**
@@ -1061,6 +1112,526 @@ os_socket_get_broadcast(bh_socket_t socket, bool *is_enabled);
 int
 os_dumps_proc_mem_info(char *out, unsigned int size);
 
+/****************************************************
+ *                     Section 3                    *
+ *                 Filesystem support               *
+ ****************************************************/
+
+/**
+ * NOTES:
+ * Fileystem APIs are required for WASI libc support. If you don't need to
+ * support WASI libc, there is no need to implement these APIs. With a
+ * few exceptions, each filesystem function has been named after the equivalent
+ * POSIX filesystem function with an os_ prefix.
+ *
+ * Filesystem types
+ *
+ * os_raw_file_handle: the underlying OS file handle type e.g. int on POSIX
+ * systems and HANDLE on Windows. This type exists to allow embedders to provide
+ * custom file handles for stdout/stdin/stderr.
+ *
+ * os_file_handle: the file handle type used in the WASI libc fd
+ * table. Filesystem implementations can use it as a means to store any
+ * necessary platform-specific information which may not be directly available
+ * through the raw OS file handle. Similiar to POSIX file descriptors, file
+ * handles may also refer to sockets, directories, symbolic links or character
+ * devices and any of the filesystem operations which make sense for these
+ * resource types should be supported as far as possible.
+ *
+ * os_dir_stream: a directory stream type in which fileystem implementations
+ * can store any necessary state to iterate over the entries in a directory.
+ */
+
+/**
+ * Obtain information about an open file associated with the given handle.
+ *
+ * @param handle the handle for which to obtain file information
+ * @param buf a buffer in which to store the information
+ */
+__wasi_errno_t
+os_fstat(os_file_handle handle, struct __wasi_filestat_t *buf);
+
+/**
+ * Obtain information about an open file or directory.
+ * @param handle the directory handle from which to resolve the file/directory
+ * path
+ * @param path the relative path of the file or directory for which to obtain
+ * information
+ * @param buf a buffer in which to store the information
+ * @param follow_symlink whether to follow symlinks when resolving the path
+ */
+__wasi_errno_t
+os_fstatat(os_file_handle handle, const char *path,
+           struct __wasi_filestat_t *buf, __wasi_lookupflags_t lookup_flags);
+
+/**
+ * Obtain the file status flags for the provided handle. This is similiar to the
+ * POSIX function fcntl called with the F_GETFL command.
+ *
+ * @param handle the handle for which to obtain the file status flags
+ * @param flags a pointer in which to store the output
+ */
+__wasi_errno_t
+os_file_get_fdflags(os_file_handle handle, __wasi_fdflags_t *flags);
+
+/**
+ * Set the file status flags for the provided handle. This is similiar to the
+ * POSIX function fcntl called with the F_SETFL command.
+ *
+ * @param handle the handle for which to set the file status flags
+ * @param flags the flags to set
+ */
+__wasi_errno_t
+os_file_set_fdflags(os_file_handle handle, __wasi_fdflags_t flags);
+
+/**
+ * Synchronize the data of a file to disk.
+ *
+ * @param handle
+ */
+__wasi_errno_t
+os_fdatasync(os_file_handle handle);
+
+/**
+ * Synchronize the data and metadata of a file to disk.
+ *
+ * @param handle
+ */
+__wasi_errno_t
+os_fsync(os_file_handle handle);
+
+/**
+ * Open a preopen directory. The path provided must refer to a directory and the
+ * returned handle will allow only readonly operations.
+ *
+ * @param path the path of the preopen directory to open
+ * @param out a pointer in which to store the newly opened handle
+ */
+__wasi_errno_t
+os_open_preopendir(const char *path, os_file_handle *out);
+
+typedef uint8 wasi_libc_file_access_mode;
+#define WASI_LIBC_ACCESS_MODE_READ_ONLY 0
+#define WASI_LIBC_ACCESS_MODE_WRITE_ONLY 1
+#define WASI_LIBC_ACCESS_MODE_READ_WRITE 2
+
+/**
+ * Open a file or directory at the given path.
+ *
+ * @param handle a handle to the directory in which to open the new file or
+ * directory
+ * @param path the relative path of the file or directory to open
+ * @param oflags the flags to determine how the file or directory is opened
+ * @param fd_flags the flags to set on the returned handle
+ * @param lookup_flags whether to follow symlinks when resolving the path
+ * @param access_mode whether the file is opened as read only, write only or
+ * both
+ * @param out a pointer in which to store the newly opened handle
+ */
+__wasi_errno_t
+os_openat(os_file_handle handle, const char *path, __wasi_oflags_t oflags,
+          __wasi_fdflags_t fd_flags, __wasi_lookupflags_t lookup_flags,
+          wasi_libc_file_access_mode access_mode, os_file_handle *out);
+
+/**
+ * Obtain the file access mode for the provided handle. This is similiar to the
+ * POSIX function fcntl called with the F_GETFL command combined with the
+ * O_ACCMODE mask.
+ *
+ * @param handle the handle for which to obtain the access mode
+ * @param access_mode a pointer in which to store the access mode
+ */
+__wasi_errno_t
+os_file_get_access_mode(os_file_handle handle,
+                        wasi_libc_file_access_mode *access_mode);
+
+/**
+ * Close the provided handle. If is_stdio is true, the raw file handle
+ * associated with the given file handle will not be closed.
+ *
+ * @param handle the handle to close
+ * @param is_stdio whether the provided handle refers to a stdio device
+ */
+__wasi_errno_t
+os_close(os_file_handle handle, bool is_stdio);
+
+/**
+ * Read data from the provided handle at the given offset into multiple buffers.
+ *
+ * @param handle the handle to read from
+ * @param iov the buffers to read into
+ * @param iovcnt the number of buffers to read into
+ * @param offset the offset to read from
+ * @param nread a pointer in which to store the number of bytes read
+ */
+__wasi_errno_t
+os_preadv(os_file_handle handle, const struct __wasi_iovec_t *iov, int iovcnt,
+          __wasi_filesize_t offset, size_t *nread);
+
+/**
+ * Write data from multiple buffers at the given offset to the provided handle.
+ *
+ * @param handle the handle to write to
+ * @param iov the buffers to write from
+ * @param iovcnt the number of buffers to write from
+ * @param offset the offset to write from
+ * @param nwritten a pointer in which to store the number of bytes written
+ */
+__wasi_errno_t
+os_pwritev(os_file_handle handle, const struct __wasi_ciovec_t *iov, int iovcnt,
+           __wasi_filesize_t offset, size_t *nwritten);
+
+/**
+ * Read data from the provided handle into multiple buffers.
+ *
+ * @param handle the handle to read from
+ * @param iov the buffers to read into
+ * @param iovcnt the number of buffers to read into
+ * @param nread a pointer in which to store the number of bytes read
+ */
+__wasi_errno_t
+os_readv(os_file_handle handle, const struct __wasi_iovec_t *iov, int iovcnt,
+         size_t *nread);
+
+/**
+ * Write data from multiple buffers to the provided handle.
+ *
+ * @param handle the handle to write to
+ * @param iov the buffers to write from
+ * @param iovcnt the number of buffers to write from
+ * @param nwritten a pointer in which to store the number of bytes written
+ */
+__wasi_errno_t
+os_writev(os_file_handle handle, const struct __wasi_ciovec_t *iov, int iovcnt,
+          size_t *nwritten);
+
+/**
+ * Allocate storage space for the file associated with the provided handle. This
+ * is similar to the POSIX function posix_fallocate.
+ *
+ * @param handle the handle to allocate space for
+ * @param offset the offset to allocate space at
+ * @param length the amount of space to allocate
+ */
+__wasi_errno_t
+os_fallocate(os_file_handle handle, __wasi_filesize_t offset,
+             __wasi_filesize_t length);
+
+/**
+ * Adjust the size of an open file.
+ *
+ * @param handle the associated file handle for which to adjust the size
+ * @param size the new size of the file
+ */
+__wasi_errno_t
+os_ftruncate(os_file_handle handle, __wasi_filesize_t size);
+
+/**
+ * Set file access and modification times on an open file or directory.
+ *
+ * @param handle the associated file handle for which to adjust the
+ * access/modification times
+ * @param access_time the timestamp for the new access time
+ * @param modification_time the timestamp for the new modification time
+ * @param fstflags a bitmask to indicate which timestamps to adjust
+ */
+__wasi_errno_t
+os_futimens(os_file_handle handle, __wasi_timestamp_t access_time,
+            __wasi_timestamp_t modification_time, __wasi_fstflags_t fstflags);
+
+/**
+ * Set file access and modification times on an open file or directory.
+ *
+ * @param handle the directory handle from which to resolve the path
+ * @param path the relative path of the file or directory for which to adjust
+ * the access/modification times
+ * @param access_time the timestamp for the new access time
+ * @param modification_time the timestamp for the new modification time
+ * @param fstflags a bitmask to indicate which timestamps to adjust
+ * @param lookup_flags whether to follow symlinks when resolving the path
+ */
+__wasi_errno_t
+os_utimensat(os_file_handle handle, const char *path,
+             __wasi_timestamp_t access_time,
+             __wasi_timestamp_t modification_time, __wasi_fstflags_t fstflags,
+             __wasi_lookupflags_t lookup_flags);
+
+/**
+ * Read the contents of a symbolic link relative to the provided directory
+ * handle.
+ *
+ * @param handle the directory handle
+ * @param path the relative path of the symbolic link from which to read
+ * @param buf the buffer to read the link contents into
+ * @param bufsize the size of the provided buffer
+ * @param nread a pointer in which to store the number of bytes read into the
+ * buffer
+ */
+__wasi_errno_t
+os_readlinkat(os_file_handle handle, const char *path, char *buf,
+              size_t bufsize, size_t *nread);
+
+/**
+ * Create a link from one path to another path.
+ *
+ * @param from_handle the directory handle from which to resolve the origin path
+ * @param from_path the origin path to link from
+ * @param to_handle the directory handle from which to resolve the destination
+ * path
+ * @param to_path the destination path at which to create the link
+ * @param lookup_flags whether to follow symlinks when resolving the origin path
+ */
+__wasi_errno_t
+os_linkat(os_file_handle from_handle, const char *from_path,
+          os_file_handle to_handle, const char *to_path,
+          __wasi_lookupflags_t lookup_flags);
+
+/**
+ * Create a symbolic link from one path to another path.
+ *
+ * @param old_path the symbolic link contents
+ * @param handle the directory handle from which to resolve the destination path
+ * @param new_path the destination path at which to create the symbolic link
+ */
+__wasi_errno_t
+os_symlinkat(const char *old_path, os_file_handle handle, const char *new_path);
+
+/**
+ * Create a directory relative to the provided directory handle.
+ *
+ * @param handle the directory handle
+ * @param path the relative path of the directory to create
+ */
+__wasi_errno_t
+os_mkdirat(os_file_handle handle, const char *path);
+
+/**
+ * Rename a file or directory.
+ *
+ * @param old_handle the directory handle from which to resolve the old path
+ * @param old_path the source path to rename
+ * @param new_handle the directory handle from which to resolve the destination
+ * path
+ * @param new_path the destination path to which to rename the file or directory
+ */
+__wasi_errno_t
+os_renameat(os_file_handle old_handle, const char *old_path,
+            os_file_handle new_handle, const char *new_path);
+
+/**
+ * Unlink a file or directory.
+ *
+ * @param handle the directory handle from which to resolve the path
+ * @param path the relative path of the file or directory to unlink
+ * @param is_dir whether the provided handle refers to a directory or file
+ */
+__wasi_errno_t
+os_unlinkat(os_file_handle handle, const char *path, bool is_dir);
+
+/**
+ * Move the read/write offset of an open file.
+ *
+ * @param handle the associated file handle for which to adjust the offset
+ * @param offset the number of bytes to adjust the offset by
+ * @param whence the position whence to adjust the offset
+ * @param new_offset a pointer in which to store the new offset
+ */
+__wasi_errno_t
+os_lseek(os_file_handle handle, __wasi_filedelta_t offset,
+         __wasi_whence_t whence, __wasi_filesize_t *new_offset);
+
+/**
+ * Provide file advisory information for the given handle. This is similar to
+ * the POSIX function posix_fadvise.
+ *
+ * @param handle the associated file handle for which to provide advisory
+ * information
+ * @param offset the offset within the file to which the advisory
+ * information applies
+ * @param length the length of the region for which the advisory information
+ * applies
+ * @param advice the advice to provide
+ */
+__wasi_errno_t
+os_fadvise(os_file_handle handle, __wasi_filesize_t offset,
+           __wasi_filesize_t length, __wasi_advice_t advice);
+
+/**
+ * Determine if the given handle refers to a terminal device. __WASI_ESUCCESS
+ * will be returned if the handle is associated with a terminal device,
+ * otherwise an appropriate error code will be returned.
+ *
+ * @param handle
+ */
+__wasi_errno_t
+os_isatty(os_file_handle handle);
+
+/**
+ * Converts a raw file handle to STDIN to a corresponding file handle to STDIN.
+ * If the provided raw file handle is invalid, the platform-default raw handle
+ * for STDIN will be used.
+ *
+ * @param raw_stdin a raw file handle to STDIN
+ *
+ * @return a handle to STDIN
+ */
+os_file_handle
+os_convert_stdin_handle(os_raw_file_handle raw_stdin);
+
+/**
+ * Converts a raw file handle to STDOUT to a correponding file handle to STDOUT.
+ * If the provided raw file handle is invalid, the platform-default raw handle
+ * for STDOUT will be used.
+ *
+ * @param raw_stdout a raw file handle to STDOUT
+ *
+ * @return a handle to STDOUT
+ */
+os_file_handle
+os_convert_stdout_handle(os_raw_file_handle raw_stdout);
+
+/**
+ * Converts a raw file handle to STDERR to a correponding file handle to STDERR.
+ * If the provided raw file handle is invalid, the platform-default raw handle
+ * for STDERR will be used.
+ *
+ * @param raw_stderr a raw file handle to STDERR
+ *
+ * @return a handle to STDERR
+ */
+os_file_handle
+os_convert_stderr_handle(os_raw_file_handle raw_stderr);
+
+/**
+ * Open a directory stream for the provided directory handle. The returned
+ * directory stream will be positioned at the first entry in the directory.
+ *
+ * @param handle the directory handle
+ * @param dir_stream a pointer in which to store the new directory stream
+ */
+__wasi_errno_t
+os_fdopendir(os_file_handle handle, os_dir_stream *dir_stream);
+
+/**
+ * Reset the position of a directory stream to the beginning of the directory.
+ *
+ * @param dir_stream the directory stream for which to reset the position
+ */
+__wasi_errno_t
+os_rewinddir(os_dir_stream dir_stream);
+
+/**
+ * Set the position of the given directory stream.
+ *
+ * @param dir_stream the directory stream for which to set the position
+ * @param position the position to set
+ */
+__wasi_errno_t
+os_seekdir(os_dir_stream dir_stream, __wasi_dircookie_t position);
+
+/**
+ * Read a directory entry from the given directory stream. The directory name
+ * will be NULL if the end of the directory is reached or an error is
+ * encountered.
+ *
+ * @param dir_stream the directory stream from which to read the entry
+ * @param entry a pointer in which to store the directory entry
+ * @param d_name a pointer in which to store the directory entry name
+ */
+__wasi_errno_t
+os_readdir(os_dir_stream dir_stream, __wasi_dirent_t *entry,
+           const char **d_name);
+
+/**
+ * Close the given directory stream. The handle associated with the directory
+ * stream will also be closed.
+ *
+ * @param dir_stream the directory stream to close
+ */
+__wasi_errno_t
+os_closedir(os_dir_stream dir_stream);
+
+/**
+ * Returns an invalid directory stream that is guaranteed to cause failure when
+ * called with any directory filesystem operation.
+ *
+ * @return the invalid directory stream
+ */
+os_dir_stream
+os_get_invalid_dir_stream();
+
+/**
+ * Checks whether the given directory stream is valid. An invalid directory
+ * stream is guaranteed to cause failure when called with any directory
+ * filesystem operation.
+ *
+ * @param dir_stream a pointer to a directory stream
+ */
+bool
+os_is_dir_stream_valid(os_dir_stream *dir_stream);
+
+/**
+ * Returns an invalid handle that is guaranteed to cause failure when
+ * called with any filesystem operation.
+ *
+ * @return the invalid handle
+ */
+os_file_handle
+os_get_invalid_handle();
+
+/**
+ * Checks whether the given file handle is valid. An invalid handle is
+ * guaranteed to cause failure when called with any filesystem operation.
+ *
+ * @param handle a pointer to a file handle
+ */
+bool
+os_is_handle_valid(os_file_handle *handle);
+
+/**
+ * Resolve a pathname. The generated pathname will be stored as a
+ * null-terminated string, with a maximum length of PATH_MAX bytes.
+ *
+ * @param path the path to resolve
+ * @param resolved_path the buffer to store the resolved path in
+ *
+ * @return the resolved path if success, NULL otherwise
+ */
+char *
+os_realpath(const char *path, char *resolved_path);
+
+/****************************************************
+ *                     Section 4                    *
+ *                  Clock functions                 *
+ ****************************************************/
+
+/**
+ * NOTES:
+ * Clock functions are required for WASI libc support. If you don't need to
+ * support WASI libc, there is no need to implement these APIs.
+ */
+
+/**
+ * Get the resolution of the specified clock.
+ *
+ * @param clock_id clock identifier
+ * @param resolution output variable to store the clock resolution
+ */
+__wasi_errno_t
+os_clock_res_get(__wasi_clockid_t clock_id, __wasi_timestamp_t *resolution);
+
+/**
+ * Get the current time of the specified clock.
+ *
+ * @param clock_id clock identifier
+ * @param precision the maximum lag that the returned time value may have,
+ * compared to its actual value.
+ * @param time output variable to store the clock time
+ */
+__wasi_errno_t
+os_clock_time_get(__wasi_clockid_t clock_id, __wasi_timestamp_t precision,
+                  __wasi_timestamp_t *time);
+
 #ifdef __cplusplus
 }
 #endif

+ 1 - 1
core/shared/platform/include/platform_api_vmcore.h

@@ -130,7 +130,7 @@ enum {
 };
 
 void *
-os_mmap(void *hint, size_t size, int prot, int flags);
+os_mmap(void *hint, size_t size, int prot, int flags, os_file_handle file);
 void
 os_munmap(void *addr, size_t size);
 int

+ 610 - 0
core/shared/platform/include/platform_wasi_types.h

@@ -0,0 +1,610 @@
+/*
+ * Copyright (C) 2023 Intel Corporation.  All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+/*
+ * This file declares the WASI interface. The definitions of types, macros and
+ * structures in this file should be consistent with those in wasi-libc:
+ * https://github.com/WebAssembly/wasi-libc/blob/main/libc-bottom-half/headers/public/wasi/api.h
+ */
+
+#ifndef _PLATFORM_WASI_TYPES_H
+#define _PLATFORM_WASI_TYPES_H
+
+#include "../../../config.h"
+
+#include <stdint.h>
+#include <stddef.h>
+
+/* clang-format off */
+
+#ifdef __cplusplus
+#ifndef _Static_assert
+#define _Static_assert static_assert
+#endif /* _Static_assert */
+
+#ifndef _Alignof
+#define _Alignof alignof
+#endif /* _Alignof */
+
+extern "C" {
+#endif
+
+/* There is no need to check the WASI layout if we're using uvwasi or libc-wasi
+ * is not enabled at all. */
+#if WASM_ENABLE_UVWASI != 0 || WASM_ENABLE_LIBC_WASI == 0
+#define assert_wasi_layout(expr, message) /* nothing */
+#else
+#define assert_wasi_layout(expr, message) _Static_assert(expr, message)
+#endif
+
+assert_wasi_layout(_Alignof(int8_t) == 1, "non-wasi data layout");
+assert_wasi_layout(_Alignof(uint8_t) == 1, "non-wasi data layout");
+assert_wasi_layout(_Alignof(int16_t) == 2, "non-wasi data layout");
+assert_wasi_layout(_Alignof(uint16_t) == 2, "non-wasi data layout");
+assert_wasi_layout(_Alignof(int32_t) == 4, "non-wasi data layout");
+assert_wasi_layout(_Alignof(uint32_t) == 4, "non-wasi data layout");
+#if 0
+assert_wasi_layout(_Alignof(int64_t) == 8, "non-wasi data layout");
+assert_wasi_layout(_Alignof(uint64_t) == 8, "non-wasi data layout");
+#endif
+
+typedef uint32_t __wasi_size_t;
+assert_wasi_layout(_Alignof(__wasi_size_t) == 4, "non-wasi data layout");
+
+typedef uint8_t __wasi_advice_t;
+#define __WASI_ADVICE_NORMAL     (0)
+#define __WASI_ADVICE_SEQUENTIAL (1)
+#define __WASI_ADVICE_RANDOM     (2)
+#define __WASI_ADVICE_WILLNEED   (3)
+#define __WASI_ADVICE_DONTNEED   (4)
+#define __WASI_ADVICE_NOREUSE    (5)
+
+typedef uint32_t __wasi_clockid_t;
+#define __WASI_CLOCK_REALTIME           (0)
+#define __WASI_CLOCK_MONOTONIC          (1)
+#define __WASI_CLOCK_PROCESS_CPUTIME_ID (2)
+#define __WASI_CLOCK_THREAD_CPUTIME_ID  (3)
+
+typedef uint64_t __wasi_device_t;
+
+typedef uint64_t __wasi_dircookie_t;
+#define __WASI_DIRCOOKIE_START (0)
+
+typedef uint32_t __wasi_dirnamlen_t;
+
+typedef uint16_t __wasi_errno_t;
+#define __WASI_ESUCCESS        (0)
+#define __WASI_E2BIG           (1)
+#define __WASI_EACCES          (2)
+#define __WASI_EADDRINUSE      (3)
+#define __WASI_EADDRNOTAVAIL   (4)
+#define __WASI_EAFNOSUPPORT    (5)
+#define __WASI_EAGAIN          (6)
+#define __WASI_EALREADY        (7)
+#define __WASI_EBADF           (8)
+#define __WASI_EBADMSG         (9)
+#define __WASI_EBUSY           (10)
+#define __WASI_ECANCELED       (11)
+#define __WASI_ECHILD          (12)
+#define __WASI_ECONNABORTED    (13)
+#define __WASI_ECONNREFUSED    (14)
+#define __WASI_ECONNRESET      (15)
+#define __WASI_EDEADLK         (16)
+#define __WASI_EDESTADDRREQ    (17)
+#define __WASI_EDOM            (18)
+#define __WASI_EDQUOT          (19)
+#define __WASI_EEXIST          (20)
+#define __WASI_EFAULT          (21)
+#define __WASI_EFBIG           (22)
+#define __WASI_EHOSTUNREACH    (23)
+#define __WASI_EIDRM           (24)
+#define __WASI_EILSEQ          (25)
+#define __WASI_EINPROGRESS     (26)
+#define __WASI_EINTR           (27)
+#define __WASI_EINVAL          (28)
+#define __WASI_EIO             (29)
+#define __WASI_EISCONN         (30)
+#define __WASI_EISDIR          (31)
+#define __WASI_ELOOP           (32)
+#define __WASI_EMFILE          (33)
+#define __WASI_EMLINK          (34)
+#define __WASI_EMSGSIZE        (35)
+#define __WASI_EMULTIHOP       (36)
+#define __WASI_ENAMETOOLONG    (37)
+#define __WASI_ENETDOWN        (38)
+#define __WASI_ENETRESET       (39)
+#define __WASI_ENETUNREACH     (40)
+#define __WASI_ENFILE          (41)
+#define __WASI_ENOBUFS         (42)
+#define __WASI_ENODEV          (43)
+#define __WASI_ENOENT          (44)
+#define __WASI_ENOEXEC         (45)
+#define __WASI_ENOLCK          (46)
+#define __WASI_ENOLINK         (47)
+#define __WASI_ENOMEM          (48)
+#define __WASI_ENOMSG          (49)
+#define __WASI_ENOPROTOOPT     (50)
+#define __WASI_ENOSPC          (51)
+#define __WASI_ENOSYS          (52)
+#define __WASI_ENOTCONN        (53)
+#define __WASI_ENOTDIR         (54)
+#define __WASI_ENOTEMPTY       (55)
+#define __WASI_ENOTRECOVERABLE (56)
+#define __WASI_ENOTSOCK        (57)
+#define __WASI_ENOTSUP         (58)
+#define __WASI_ENOTTY          (59)
+#define __WASI_ENXIO           (60)
+#define __WASI_EOVERFLOW       (61)
+#define __WASI_EOWNERDEAD      (62)
+#define __WASI_EPERM           (63)
+#define __WASI_EPIPE           (64)
+#define __WASI_EPROTO          (65)
+#define __WASI_EPROTONOSUPPORT (66)
+#define __WASI_EPROTOTYPE      (67)
+#define __WASI_ERANGE          (68)
+#define __WASI_EROFS           (69)
+#define __WASI_ESPIPE          (70)
+#define __WASI_ESRCH           (71)
+#define __WASI_ESTALE          (72)
+#define __WASI_ETIMEDOUT       (73)
+#define __WASI_ETXTBSY         (74)
+#define __WASI_EXDEV           (75)
+#define __WASI_ENOTCAPABLE     (76)
+
+#if defined(_MSC_VER)
+#define ALIGNED_(x) __declspec(align(x))
+#define WARN_UNUSED _Check_return_
+#elif defined(__GNUC__)
+#define ALIGNED_(x) __attribute__ ((aligned(x)))
+#define WARN_UNUSED __attribute__((__warn_unused_result__))
+#endif
+
+#define ALIGNED_TYPE(t,x) typedef t ALIGNED_(x)
+
+typedef uint16_t __wasi_eventrwflags_t;
+#define __WASI_EVENT_FD_READWRITE_HANGUP (0x0001)
+
+typedef uint8_t __wasi_eventtype_t;
+#define __WASI_EVENTTYPE_CLOCK          (0)
+#define __WASI_EVENTTYPE_FD_READ        (1)
+#define __WASI_EVENTTYPE_FD_WRITE       (2)
+
+typedef uint32_t __wasi_exitcode_t;
+
+typedef uint32_t __wasi_fd_t;
+
+typedef uint16_t __wasi_fdflags_t;
+#define __WASI_FDFLAG_APPEND   (0x0001)
+#define __WASI_FDFLAG_DSYNC    (0x0002)
+#define __WASI_FDFLAG_NONBLOCK (0x0004)
+#define __WASI_FDFLAG_RSYNC    (0x0008)
+#define __WASI_FDFLAG_SYNC     (0x0010)
+
+typedef int64_t __wasi_filedelta_t;
+
+typedef uint64_t __wasi_filesize_t;
+
+typedef uint8_t __wasi_filetype_t;
+#define __WASI_FILETYPE_UNKNOWN          (0)
+#define __WASI_FILETYPE_BLOCK_DEVICE     (1)
+#define __WASI_FILETYPE_CHARACTER_DEVICE (2)
+#define __WASI_FILETYPE_DIRECTORY        (3)
+#define __WASI_FILETYPE_REGULAR_FILE     (4)
+#define __WASI_FILETYPE_SOCKET_DGRAM     (5)
+#define __WASI_FILETYPE_SOCKET_STREAM    (6)
+#define __WASI_FILETYPE_SYMBOLIC_LINK    (7)
+
+typedef uint16_t __wasi_fstflags_t;
+#define __WASI_FILESTAT_SET_ATIM     (0x0001)
+#define __WASI_FILESTAT_SET_ATIM_NOW (0x0002)
+#define __WASI_FILESTAT_SET_MTIM     (0x0004)
+#define __WASI_FILESTAT_SET_MTIM_NOW (0x0008)
+
+typedef uint64_t __wasi_inode_t;
+
+ALIGNED_TYPE(uint64_t, 8) __wasi_linkcount_t;
+
+typedef uint32_t __wasi_lookupflags_t;
+#define __WASI_LOOKUP_SYMLINK_FOLLOW (0x00000001)
+
+typedef uint16_t __wasi_oflags_t;
+#define __WASI_O_CREAT     (0x0001)
+#define __WASI_O_DIRECTORY (0x0002)
+#define __WASI_O_EXCL      (0x0004)
+#define __WASI_O_TRUNC     (0x0008)
+
+typedef uint16_t __wasi_riflags_t;
+#define __WASI_SOCK_RECV_PEEK    (0x0001)
+#define __WASI_SOCK_RECV_WAITALL (0x0002)
+
+typedef uint64_t __wasi_rights_t;
+
+/**
+ * Observe that WASI defines rights in the plural form
+ * TODO: refactor to use RIGHTS instead of RIGHT
+ */
+#define __WASI_RIGHT_FD_DATASYNC ((__wasi_rights_t)(UINT64_C(1) << 0))
+#define __WASI_RIGHT_FD_READ ((__wasi_rights_t)(UINT64_C(1) << 1))
+#define __WASI_RIGHT_FD_SEEK ((__wasi_rights_t)(UINT64_C(1) << 2))
+#define __WASI_RIGHT_FD_FDSTAT_SET_FLAGS ((__wasi_rights_t)(UINT64_C(1) << 3))
+#define __WASI_RIGHT_FD_SYNC ((__wasi_rights_t)(UINT64_C(1) << 4))
+#define __WASI_RIGHT_FD_TELL ((__wasi_rights_t)(UINT64_C(1) << 5))
+#define __WASI_RIGHT_FD_WRITE ((__wasi_rights_t)(UINT64_C(1) << 6))
+#define __WASI_RIGHT_FD_ADVISE ((__wasi_rights_t)(UINT64_C(1) << 7))
+#define __WASI_RIGHT_FD_ALLOCATE ((__wasi_rights_t)(UINT64_C(1) << 8))
+#define __WASI_RIGHT_PATH_CREATE_DIRECTORY ((__wasi_rights_t)(UINT64_C(1) << 9))
+#define __WASI_RIGHT_PATH_CREATE_FILE ((__wasi_rights_t)(UINT64_C(1) << 10))
+#define __WASI_RIGHT_PATH_LINK_SOURCE ((__wasi_rights_t)(UINT64_C(1) << 11))
+#define __WASI_RIGHT_PATH_LINK_TARGET ((__wasi_rights_t)(UINT64_C(1) << 12))
+#define __WASI_RIGHT_PATH_OPEN ((__wasi_rights_t)(UINT64_C(1) << 13))
+#define __WASI_RIGHT_FD_READDIR ((__wasi_rights_t)(UINT64_C(1) << 14))
+#define __WASI_RIGHT_PATH_READLINK ((__wasi_rights_t)(UINT64_C(1) << 15))
+#define __WASI_RIGHT_PATH_RENAME_SOURCE ((__wasi_rights_t)(UINT64_C(1) << 16))
+#define __WASI_RIGHT_PATH_RENAME_TARGET ((__wasi_rights_t)(UINT64_C(1) << 17))
+#define __WASI_RIGHT_PATH_FILESTAT_GET ((__wasi_rights_t)(UINT64_C(1) << 18))
+#define __WASI_RIGHT_PATH_FILESTAT_SET_SIZE ((__wasi_rights_t)(UINT64_C(1) << 19))
+#define __WASI_RIGHT_PATH_FILESTAT_SET_TIMES ((__wasi_rights_t)(UINT64_C(1) << 20))
+#define __WASI_RIGHT_FD_FILESTAT_GET ((__wasi_rights_t)(UINT64_C(1) << 21))
+#define __WASI_RIGHT_FD_FILESTAT_SET_SIZE ((__wasi_rights_t)(UINT64_C(1) << 22))
+#define __WASI_RIGHT_FD_FILESTAT_SET_TIMES ((__wasi_rights_t)(UINT64_C(1) << 23))
+#define __WASI_RIGHT_PATH_SYMLINK ((__wasi_rights_t)(UINT64_C(1) << 24))
+#define __WASI_RIGHT_PATH_REMOVE_DIRECTORY ((__wasi_rights_t)(UINT64_C(1) << 25))
+#define __WASI_RIGHT_PATH_UNLINK_FILE ((__wasi_rights_t)(UINT64_C(1) << 26))
+#define __WASI_RIGHT_POLL_FD_READWRITE ((__wasi_rights_t)(UINT64_C(1) << 27))
+#define __WASI_RIGHT_SOCK_CONNECT ((__wasi_rights_t)(UINT64_C(1) << 28))
+#define __WASI_RIGHT_SOCK_LISTEN ((__wasi_rights_t)(UINT64_C(1) << 29))
+#define __WASI_RIGHT_SOCK_BIND ((__wasi_rights_t)(UINT64_C(1) << 30))
+#define __WASI_RIGHT_SOCK_ACCEPT ((__wasi_rights_t)(UINT64_C(1) << 31))
+#define __WASI_RIGHT_SOCK_RECV ((__wasi_rights_t)(UINT64_C(1) << 32))
+#define __WASI_RIGHT_SOCK_SEND ((__wasi_rights_t)(UINT64_C(1) << 33))
+#define __WASI_RIGHT_SOCK_ADDR_LOCAL ((__wasi_rights_t)(UINT64_C(1) << 34))
+#define __WASI_RIGHT_SOCK_ADDR_REMOTE ((__wasi_rights_t)(UINT64_C(1) << 35))
+#define __WASI_RIGHT_SOCK_RECV_FROM ((__wasi_rights_t)(UINT64_C(1) << 36))
+#define __WASI_RIGHT_SOCK_SEND_TO ((__wasi_rights_t)(UINT64_C(1) << 37))
+
+typedef uint16_t __wasi_roflags_t;
+#define __WASI_SOCK_RECV_DATA_TRUNCATED (0x0001)
+
+typedef uint8_t __wasi_sdflags_t;
+#define __WASI_SHUT_RD (0x01)
+#define __WASI_SHUT_WR (0x02)
+
+typedef uint16_t __wasi_siflags_t;
+
+typedef uint8_t __wasi_signal_t;
+
+typedef uint16_t __wasi_subclockflags_t;
+#define __WASI_SUBSCRIPTION_CLOCK_ABSTIME (0x0001)
+
+typedef uint64_t __wasi_timestamp_t;
+
+typedef uint64_t __wasi_userdata_t;
+
+typedef uint8_t __wasi_whence_t;
+#define __WASI_WHENCE_SET (0)
+#define __WASI_WHENCE_CUR (1)
+#define __WASI_WHENCE_END (2)
+
+typedef uint8_t __wasi_preopentype_t;
+#define __WASI_PREOPENTYPE_DIR              (0)
+
+struct fd_table;
+struct fd_prestats;
+struct argv_environ_values;
+struct addr_pool;
+
+typedef struct ALIGNED_(8) __wasi_dirent_t {
+    __wasi_dircookie_t d_next;
+    __wasi_inode_t d_ino;
+    __wasi_dirnamlen_t d_namlen;
+    __wasi_filetype_t d_type;
+} __wasi_dirent_t;
+assert_wasi_layout(offsetof(__wasi_dirent_t, d_next) == 0, "non-wasi data layout");
+assert_wasi_layout(offsetof(__wasi_dirent_t, d_ino) == 8, "non-wasi data layout");
+assert_wasi_layout(offsetof(__wasi_dirent_t, d_namlen) == 16, "non-wasi data layout");
+assert_wasi_layout(offsetof(__wasi_dirent_t, d_type) == 20, "non-wasi data layout");
+assert_wasi_layout(sizeof(__wasi_dirent_t) == 24, "non-wasi data layout");
+assert_wasi_layout(_Alignof(__wasi_dirent_t) == 8, "non-wasi data layout");
+
+typedef struct ALIGNED_(8) __wasi_event_t {
+    __wasi_userdata_t userdata;
+    __wasi_errno_t error;
+    __wasi_eventtype_t type;
+    uint8_t __paddings[5];
+    union __wasi_event_u {
+        struct __wasi_event_u_fd_readwrite_t {
+            __wasi_filesize_t nbytes;
+            __wasi_eventrwflags_t flags;
+            uint8_t __paddings[6];
+        } fd_readwrite;
+    } u;
+} __wasi_event_t;
+assert_wasi_layout(offsetof(__wasi_event_t, userdata) == 0, "non-wasi data layout");
+assert_wasi_layout(offsetof(__wasi_event_t, error) == 8, "non-wasi data layout");
+assert_wasi_layout(offsetof(__wasi_event_t, type) == 10, "non-wasi data layout");
+assert_wasi_layout(
+    offsetof(__wasi_event_t, u.fd_readwrite.nbytes) == 16, "non-wasi data layout");
+assert_wasi_layout(
+    offsetof(__wasi_event_t, u.fd_readwrite.flags) == 24, "non-wasi data layout");
+assert_wasi_layout(sizeof(__wasi_event_t) == 32, "non-wasi data layout");
+assert_wasi_layout(_Alignof(__wasi_event_t) == 8, "non-wasi data layout");
+
+typedef struct __wasi_prestat_t {
+    __wasi_preopentype_t pr_type;
+    union __wasi_prestat_u {
+        struct __wasi_prestat_u_dir_t {
+            size_t pr_name_len;
+        } dir;
+    } u;
+} __wasi_prestat_t;
+assert_wasi_layout(offsetof(__wasi_prestat_t, pr_type) == 0, "non-wasi data layout");
+assert_wasi_layout(sizeof(void *) != 4 ||
+    offsetof(__wasi_prestat_t, u.dir.pr_name_len) == 4, "non-wasi data layout");
+assert_wasi_layout(sizeof(void *) != 8 ||
+    offsetof(__wasi_prestat_t, u.dir.pr_name_len) == 8, "non-wasi data layout");
+assert_wasi_layout(sizeof(void *) != 4 ||
+    sizeof(__wasi_prestat_t) == 8, "non-wasi data layout");
+assert_wasi_layout(sizeof(void *) != 8 ||
+    sizeof(__wasi_prestat_t) == 16, "non-wasi data layout");
+assert_wasi_layout(sizeof(void *) != 4 ||
+    _Alignof(__wasi_prestat_t) == 4, "non-wasi data layout");
+assert_wasi_layout(sizeof(void *) != 8 ||
+    _Alignof(__wasi_prestat_t) == 8, "non-wasi data layout");
+
+typedef struct ALIGNED_(8) __wasi_fdstat_t {
+    __wasi_filetype_t fs_filetype;
+    __wasi_fdflags_t fs_flags;
+    uint8_t __paddings[4];
+    __wasi_rights_t fs_rights_base;
+    __wasi_rights_t fs_rights_inheriting;
+} __wasi_fdstat_t;
+assert_wasi_layout(
+    offsetof(__wasi_fdstat_t, fs_filetype) == 0, "non-wasi data layout");
+assert_wasi_layout(offsetof(__wasi_fdstat_t, fs_flags) == 2, "non-wasi data layout");
+assert_wasi_layout(
+    offsetof(__wasi_fdstat_t, fs_rights_base) == 8, "non-wasi data layout");
+assert_wasi_layout(
+    offsetof(__wasi_fdstat_t, fs_rights_inheriting) == 16,
+    "non-wasi data layout");
+assert_wasi_layout(sizeof(__wasi_fdstat_t) == 24, "non-wasi data layout");
+assert_wasi_layout(_Alignof(__wasi_fdstat_t) == 8, "non-wasi data layout");
+
+typedef struct ALIGNED_(8) __wasi_filestat_t {
+    __wasi_device_t st_dev;
+    __wasi_inode_t st_ino;
+    __wasi_filetype_t st_filetype;
+    __wasi_linkcount_t st_nlink;
+    __wasi_filesize_t st_size;
+    __wasi_timestamp_t st_atim;
+    __wasi_timestamp_t st_mtim;
+    __wasi_timestamp_t st_ctim;
+} __wasi_filestat_t;
+assert_wasi_layout(offsetof(__wasi_filestat_t, st_dev) == 0, "non-wasi data layout");
+assert_wasi_layout(offsetof(__wasi_filestat_t, st_ino) == 8, "non-wasi data layout");
+assert_wasi_layout(
+    offsetof(__wasi_filestat_t, st_filetype) == 16, "non-wasi data layout");
+assert_wasi_layout(
+    offsetof(__wasi_filestat_t, st_nlink) == 24, "non-wasi data layout");
+assert_wasi_layout(
+    offsetof(__wasi_filestat_t, st_size) == 32, "non-wasi data layout");
+assert_wasi_layout(
+    offsetof(__wasi_filestat_t, st_atim) == 40, "non-wasi data layout");
+assert_wasi_layout(
+    offsetof(__wasi_filestat_t, st_mtim) == 48, "non-wasi data layout");
+assert_wasi_layout(
+    offsetof(__wasi_filestat_t, st_ctim) == 56, "non-wasi data layout");
+assert_wasi_layout(sizeof(__wasi_filestat_t) == 64, "non-wasi data layout");
+assert_wasi_layout(_Alignof(__wasi_filestat_t) == 8, "non-wasi data layout");
+
+typedef struct __wasi_ciovec_t {
+    const void *buf;
+    size_t buf_len;
+} __wasi_ciovec_t;
+assert_wasi_layout(offsetof(__wasi_ciovec_t, buf) == 0, "non-wasi data layout");
+assert_wasi_layout(sizeof(void *) != 4 ||
+    offsetof(__wasi_ciovec_t, buf_len) == 4, "non-wasi data layout");
+assert_wasi_layout(sizeof(void *) != 8 ||
+    offsetof(__wasi_ciovec_t, buf_len) == 8, "non-wasi data layout");
+assert_wasi_layout(sizeof(void *) != 4 ||
+    sizeof(__wasi_ciovec_t) == 8, "non-wasi data layout");
+assert_wasi_layout(sizeof(void *) != 8 ||
+    sizeof(__wasi_ciovec_t) == 16, "non-wasi data layout");
+assert_wasi_layout(sizeof(void *) != 4 ||
+    _Alignof(__wasi_ciovec_t) == 4, "non-wasi data layout");
+assert_wasi_layout(sizeof(void *) != 8 ||
+    _Alignof(__wasi_ciovec_t) == 8, "non-wasi data layout");
+
+typedef struct __wasi_iovec_t {
+    void *buf;
+    size_t buf_len;
+} __wasi_iovec_t;
+assert_wasi_layout(offsetof(__wasi_iovec_t, buf) == 0, "non-wasi data layout");
+assert_wasi_layout(sizeof(void *) != 4 ||
+    offsetof(__wasi_iovec_t, buf_len) == 4, "non-wasi data layout");
+assert_wasi_layout(sizeof(void *) != 8 ||
+    offsetof(__wasi_iovec_t, buf_len) == 8, "non-wasi data layout");
+assert_wasi_layout(sizeof(void *) != 4 ||
+    sizeof(__wasi_iovec_t) == 8, "non-wasi data layout");
+assert_wasi_layout(sizeof(void *) != 8 ||
+    sizeof(__wasi_iovec_t) == 16, "non-wasi data layout");
+assert_wasi_layout(sizeof(void *) != 4 ||
+    _Alignof(__wasi_iovec_t) == 4, "non-wasi data layout");
+assert_wasi_layout(sizeof(void *) != 8 ||
+    _Alignof(__wasi_iovec_t) == 8, "non-wasi data layout");
+
+/**
+ * The contents of a `subscription` when type is `eventtype::clock`.
+ */
+typedef struct ALIGNED_(8) __wasi_subscription_clock_t {
+    /**
+     * The clock against which to compare the timestamp.
+     */
+    __wasi_clockid_t clock_id;
+
+    uint8_t __paddings1[4];
+
+    /**
+     * The absolute or relative timestamp.
+     */
+    __wasi_timestamp_t timeout;
+
+    /**
+     * The amount of time that the implementation may wait additionally
+     * to coalesce with other events.
+     */
+    __wasi_timestamp_t precision;
+
+    /**
+     * Flags specifying whether the timeout is absolute or relative
+     */
+    __wasi_subclockflags_t flags;
+
+    uint8_t __paddings2[4];
+
+} __wasi_subscription_clock_t;
+
+assert_wasi_layout(sizeof(__wasi_subscription_clock_t) == 32, "witx calculated size");
+assert_wasi_layout(_Alignof(__wasi_subscription_clock_t) == 8, "witx calculated align");
+assert_wasi_layout(offsetof(__wasi_subscription_clock_t, clock_id) == 0, "witx calculated offset");
+assert_wasi_layout(offsetof(__wasi_subscription_clock_t, timeout) == 8, "witx calculated offset");
+assert_wasi_layout(offsetof(__wasi_subscription_clock_t, precision) == 16, "witx calculated offset");
+assert_wasi_layout(offsetof(__wasi_subscription_clock_t, flags) == 24, "witx calculated offset");
+
+/**
+ * The contents of a `subscription` when type is type is
+ * `eventtype::fd_read` or `eventtype::fd_write`.
+ */
+typedef struct __wasi_subscription_fd_readwrite_t {
+    /**
+     * The file descriptor on which to wait for it to become ready for reading or writing.
+     */
+    __wasi_fd_t fd;
+
+} __wasi_subscription_fd_readwrite_t;
+
+assert_wasi_layout(sizeof(__wasi_subscription_fd_readwrite_t) == 4, "witx calculated size");
+assert_wasi_layout(_Alignof(__wasi_subscription_fd_readwrite_t) == 4, "witx calculated align");
+assert_wasi_layout(offsetof(__wasi_subscription_fd_readwrite_t, fd) == 0, "witx calculated offset");
+
+/**
+ * The contents of a `subscription`.
+ */
+typedef union __wasi_subscription_u_u_t {
+    __wasi_subscription_clock_t clock;
+    __wasi_subscription_fd_readwrite_t fd_readwrite;
+} __wasi_subscription_u_u_t ;
+
+typedef struct ALIGNED_(8) __wasi_subscription_u_t {
+    __wasi_eventtype_t type;
+    __wasi_subscription_u_u_t u;
+} __wasi_subscription_u_t;
+
+assert_wasi_layout(sizeof(__wasi_subscription_u_t) == 40, "witx calculated size");
+assert_wasi_layout(_Alignof(__wasi_subscription_u_t) == 8, "witx calculated align");
+assert_wasi_layout(offsetof(__wasi_subscription_u_t, u) == 8, "witx calculated union offset");
+assert_wasi_layout(sizeof(__wasi_subscription_u_u_t) == 32, "witx calculated union size");
+assert_wasi_layout(_Alignof(__wasi_subscription_u_u_t) == 8, "witx calculated union align");
+
+/**
+ * Subscription to an event.
+ */
+typedef struct __wasi_subscription_t {
+    /**
+     * User-provided value that is attached to the subscription in the
+     * implementation and returned through `event::userdata`.
+     */
+    __wasi_userdata_t userdata;
+
+    /**
+     * The type of the event to which to subscribe, and its contents
+     */
+    __wasi_subscription_u_t u;
+
+} __wasi_subscription_t;
+
+assert_wasi_layout(sizeof(__wasi_subscription_t) == 48, "witx calculated size");
+assert_wasi_layout(_Alignof(__wasi_subscription_t) == 8, "witx calculated align");
+assert_wasi_layout(offsetof(__wasi_subscription_t, userdata) == 0, "witx calculated offset");
+assert_wasi_layout(offsetof(__wasi_subscription_t, u) == 8, "witx calculated offset");
+
+/* keep syncing with wasi_socket_ext.h */
+typedef enum {
+    /* Used only for sock_addr_resolve hints */
+    SOCKET_ANY = -1,
+    SOCKET_DGRAM = 0,
+    SOCKET_STREAM,
+} __wasi_sock_type_t;
+
+typedef uint16_t __wasi_ip_port_t;
+
+typedef enum { IPv4 = 0, IPv6 } __wasi_addr_type_t;
+
+/* n0.n1.n2.n3 */
+typedef struct __wasi_addr_ip4_t {
+    uint8_t n0;
+    uint8_t n1;
+    uint8_t n2;
+    uint8_t n3;
+} __wasi_addr_ip4_t;
+
+typedef struct __wasi_addr_ip4_port_t {
+    __wasi_addr_ip4_t addr;
+    __wasi_ip_port_t port;
+} __wasi_addr_ip4_port_t;
+
+typedef struct __wasi_addr_ip6_t {
+    uint16_t n0;
+    uint16_t n1;
+    uint16_t n2;
+    uint16_t n3;
+    uint16_t h0;
+    uint16_t h1;
+    uint16_t h2;
+    uint16_t h3;
+} __wasi_addr_ip6_t;
+
+typedef struct __wasi_addr_ip6_port_t {
+    __wasi_addr_ip6_t addr;
+    __wasi_ip_port_t port;
+} __wasi_addr_ip6_port_t;
+
+typedef struct __wasi_addr_ip_t {
+    __wasi_addr_type_t kind;
+    union {
+        __wasi_addr_ip4_t ip4;
+        __wasi_addr_ip6_t ip6;
+    } addr;
+} __wasi_addr_ip_t;
+
+typedef struct __wasi_addr_t {
+    __wasi_addr_type_t kind;
+    union {
+        __wasi_addr_ip4_port_t ip4;
+        __wasi_addr_ip6_port_t ip6;
+    } addr;
+} __wasi_addr_t;
+
+typedef enum { INET4 = 0, INET6, INET_UNSPEC } __wasi_address_family_t;
+
+typedef struct __wasi_addr_info_t {
+    __wasi_addr_t addr;
+    __wasi_sock_type_t type;
+} __wasi_addr_info_t;
+
+typedef struct __wasi_addr_info_hints_t {
+   __wasi_sock_type_t type;
+   __wasi_address_family_t family;
+   // this is to workaround lack of optional parameters
+   uint8_t hints_enabled;
+} __wasi_addr_info_hints_t;
+
+#undef assert_wasi_layout
+
+/* clang-format on */
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* end of _PLATFORM_WASI_TYPES_H */

+ 11 - 0
core/shared/platform/linux-sgx/platform_internal.h

@@ -50,6 +50,7 @@ typedef pthread_t korp_thread;
 typedef pthread_t korp_tid;
 typedef pthread_mutex_t korp_mutex;
 typedef pthread_cond_t korp_cond;
+typedef pthread_rwlock_t korp_rwlock;
 typedef unsigned int korp_sem;
 
 #ifndef SGX_DISABLE_PTHREAD
@@ -68,6 +69,16 @@ strcpy(char *dest, const char *src);
 #define os_memory_order_seq_cst __ATOMIC_SEQ_CST
 #define os_atomic_thread_fence __atomic_thread_fence
 
+typedef int os_file_handle;
+typedef DIR *os_dir_stream;
+typedef int os_raw_file_handle;
+
+static inline os_file_handle
+os_get_invalid_handle()
+{
+    return -1;
+}
+
 #ifdef __cplusplus
 }
 #endif

+ 0 - 1
core/shared/platform/linux-sgx/sgx_ipfs.h

@@ -7,7 +7,6 @@
 #define _LIBC_WASI_SGX_PFS_H
 
 #include "bh_hashmap.h"
-#include "wasmtime_ssp.h"
 
 #ifdef __cplusplus
 extern "C" {

+ 9 - 2
core/shared/platform/linux-sgx/sgx_platform.c

@@ -120,13 +120,20 @@ strcpy(char *dest, const char *src)
 }
 
 void *
-os_mmap(void *hint, size_t size, int prot, int flags)
+os_mmap(void *hint, size_t size, int prot, int flags, os_file_handle file)
 {
     int mprot = 0;
     uint64 aligned_size, page_size;
     void *ret = NULL;
     sgx_status_t st = 0;
 
+    if (os_is_handle_valid(&file)) {
+        os_printf("os_mmap(size=%u, prot=0x%x, file=%x) failed: file is not "
+                  "supported.\n",
+                  size, prot, file);
+        return NULL;
+    }
+
     page_size = getpagesize();
     aligned_size = (size + page_size - 1) & ~(page_size - 1);
 
@@ -198,4 +205,4 @@ os_dcache_flush(void)
 
 void
 os_icache_flush(void *start, size_t len)
-{}
+{}

+ 6 - 2
core/shared/platform/linux-sgx/sgx_socket.c

@@ -5,6 +5,7 @@
 
 #include "platform_api_vmcore.h"
 #include "platform_api_extension.h"
+#include "libc_errno.h"
 
 #ifndef SGX_DISABLE_WASI
 
@@ -855,10 +856,13 @@ os_socket_send_to(bh_socket_t socket, const void *buf, unsigned int len,
     return ret;
 }
 
-int
+__wasi_errno_t
 os_socket_shutdown(bh_socket_t socket)
 {
-    return shutdown(socket, O_RDWR);
+    if (shutdown(socket, O_RDWR) != 0) {
+        return convert_errno(errno);
+    }
+    return __WASI_ESUCCESS;
 }
 
 int

+ 66 - 1
core/shared/platform/linux-sgx/sgx_thread.c

@@ -213,4 +213,69 @@ os_thread_get_stack_boundary()
 
 void
 os_thread_jit_write_protect_np(bool enabled)
-{}
+{}
+
+int
+os_rwlock_init(korp_rwlock *lock)
+{
+#ifndef SGX_DISABLE_PTHREAD
+    assert(lock);
+
+    if (pthread_rwlock_init(lock, NULL) != BHT_OK)
+        return BHT_ERROR;
+#endif
+
+    return BHT_OK;
+}
+
+int
+os_rwlock_rdlock(korp_rwlock *lock)
+{
+#ifndef SGX_DISABLE_PTHREAD
+    assert(lock);
+
+    if (pthread_rwlock_rdlock(lock) != BHT_OK)
+        return BHT_ERROR;
+#endif
+
+    return BHT_OK;
+}
+
+int
+os_rwlock_wrlock(korp_rwlock *lock)
+{
+#ifndef SGX_DISABLE_PTHREAD
+    assert(lock);
+
+    if (pthread_rwlock_wrlock(lock) != BHT_OK)
+        return BHT_ERROR;
+#endif
+
+    return BHT_OK;
+}
+
+int
+os_rwlock_unlock(korp_rwlock *lock)
+{
+#ifndef SGX_DISABLE_PTHREAD
+    assert(lock);
+
+    if (pthread_rwlock_unlock(lock) != BHT_OK)
+        return BHT_ERROR;
+#endif
+
+    return BHT_OK;
+}
+
+int
+os_rwlock_destroy(korp_rwlock *lock)
+{
+#ifndef SGX_DISABLE_PTHREAD
+    assert(lock);
+
+    if (pthread_rwlock_destroy(lock) != BHT_OK)
+        return BHT_ERROR;
+#endif
+
+    return BHT_OK;
+}

+ 11 - 4
core/shared/platform/linux-sgx/shared_platform.cmake

@@ -20,16 +20,23 @@ if (NOT BUILD_UNTRUST_PART EQUAL 1)
                        ${SGX_SDK_DIR}/include/libcxx)
 endif ()
 
-if (NOT WAMR_BUILD_LIBC_WASI EQUAL 1)
-  add_definitions(-DSGX_DISABLE_WASI)
-endif ()
-
 if (NOT WAMR_BUILD_THREAD_MGR EQUAL 1)
   add_definitions(-DSGX_DISABLE_PTHREAD)
 endif ()
 
 file (GLOB source_all ${PLATFORM_SHARED_DIR}/*.c)
 
+if (NOT WAMR_BUILD_LIBC_WASI EQUAL 1)
+  add_definitions(-DSGX_DISABLE_WASI)
+else()
+  list(APPEND source_all
+      ${PLATFORM_SHARED_DIR}/../common/posix/posix_file.c
+      ${PLATFORM_SHARED_DIR}/../common/posix/posix_clock.c
+  )
+  include (${CMAKE_CURRENT_LIST_DIR}/../common/libc-util/platform_common_libc_util.cmake)
+  set(source_all ${source_all} ${PLATFORM_COMMON_LIBC_UTIL_SOURCE})
+endif()
+
 file (GLOB source_all_untrusted ${PLATFORM_SHARED_DIR}/untrusted/*.c)
 
 set (PLATFORM_SHARED_SOURCE ${source_all})

+ 11 - 0
core/shared/platform/linux/platform_internal.h

@@ -55,6 +55,7 @@ typedef pthread_t korp_tid;
 typedef pthread_mutex_t korp_mutex;
 typedef pthread_cond_t korp_cond;
 typedef pthread_t korp_thread;
+typedef pthread_rwlock_t korp_rwlock;
 typedef sem_t korp_sem;
 
 #define OS_THREAD_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
@@ -121,6 +122,16 @@ os_sigreturn();
 void
 os_set_signal_number_for_blocking_op(int signo);
 
+typedef int os_file_handle;
+typedef DIR *os_dir_stream;
+typedef int os_raw_file_handle;
+
+static inline os_file_handle
+os_get_invalid_handle()
+{
+    return -1;
+}
+
 #ifdef __cplusplus
 }
 #endif

+ 1 - 1
core/shared/platform/nuttx/nuttx_platform.c

@@ -85,7 +85,7 @@ os_dumps_proc_mem_info(char *out, unsigned int size)
 }
 
 void *
-os_mmap(void *hint, size_t size, int prot, int flags)
+os_mmap(void *hint, size_t size, int prot, int flags, os_file_handle file)
 {
 #if (WASM_MEM_DUAL_BUS_MIRROR != 0)
     void *i_addr, *d_addr;

+ 11 - 0
core/shared/platform/nuttx/platform_internal.h

@@ -41,6 +41,7 @@ typedef pthread_t korp_tid;
 typedef pthread_mutex_t korp_mutex;
 typedef pthread_cond_t korp_cond;
 typedef pthread_t korp_thread;
+typedef pthread_rwlock_t korp_rwlock;
 typedef sem_t korp_sem;
 
 #define OS_THREAD_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
@@ -129,6 +130,16 @@ fdopendir(int fd);
 void
 os_set_signal_number_for_blocking_op(int signo);
 
+typedef int os_file_handle;
+typedef DIR *os_dir_stream;
+typedef int os_raw_file_handle;
+
+static inline os_file_handle
+os_get_invalid_handle()
+{
+    return -1;
+}
+
 #ifdef __cplusplus
 }
 #endif

+ 6 - 0
core/shared/platform/nuttx/shared_platform.cmake

@@ -10,5 +10,11 @@ include_directories(${PLATFORM_SHARED_DIR}/../include)
 
 file (GLOB_RECURSE source_all ${PLATFORM_SHARED_DIR}/*.c)
 
+if (WAMR_BUILD_LIBC_WASI EQUAL 1)
+  list(APPEND source_all ${PLATFORM_SHARED_DIR}/../common/posix/posix_file.c)
+  include (${CMAKE_CURRENT_LIST_DIR}/../common/libc-util/platform_common_libc_util.cmake)
+  set(source_all ${source_all} ${PLATFORM_COMMON_LIBC_UTIL_SOURCE})
+endif ()
+
 set (PLATFORM_SHARED_SOURCE ${source_all} ${PLATFORM_COMMON_MATH_SOURCE})
 

+ 18 - 0
core/shared/platform/riot/platform_internal.h

@@ -40,6 +40,12 @@ typedef kernel_pid_t korp_tid;
 typedef mutex_t korp_mutex;
 typedef unsigned int korp_sem;
 
+/* korp_rwlock is used in platform_api_extension.h,
+   we just define the type to make the compiler happy */
+typedef struct {
+    int dummy;
+} korp_rwlock;
+
 /* typedef sema_t korp_sem; */
 
 struct os_thread_wait_node;
@@ -52,6 +58,12 @@ typedef struct korp_cond {
 #define os_printf printf
 #define os_vprintf vprintf
 
+/* The below types are used in platform_api_extension.h,
+   we just define them to make the compiler happy */
+typedef int os_file_handle;
+typedef void *os_dir_stream;
+typedef int os_raw_file_handle;
+
 #if WA_MATH
 /* clang-format off */
 /* math functions which are not provided by os*/
@@ -76,4 +88,10 @@ int isnan(double x);
 /* clang-format on */
 #endif
 
+static inline os_file_handle
+os_get_invalid_handle()
+{
+    return -1;
+}
+
 #endif /* end of _BH_PLATFORM_H */

+ 1 - 1
core/shared/platform/riot/riot_platform.c

@@ -50,7 +50,7 @@ os_dumps_proc_mem_info(char *out, unsigned int size)
 }
 
 void *
-os_mmap(void *hint, size_t size, int prot, int flags)
+os_mmap(void *hint, size_t size, int prot, int flags, os_file_handle file)
 {
     if (size > ((unsigned)~0))
         return NULL;

部分文件因文件數量過多而無法顯示